lib/mopti/scaled_conjugate_gradient.rb in mopti-0.1.0 vs lib/mopti/scaled_conjugate_gradient.rb in mopti-0.2.0
- old
+ new
@@ -40,11 +40,11 @@
# # :n_iter=>9,
# # :fnc=>1.6170212789006122,
# # :jcb=>1.8698188678645777e-07}
#
# *Reference*
- # 1. M F. Moller, "A Scaled Conjugate Gradient Algorithm for Fast Supervised Learning," Neural Networks, Vol. 6, pp. 525--533, 1993.
+ # 1. Moller, M F., "A Scaled Conjugate Gradient Algorithm for Fast Supervised Learning," Neural Networks, Vol. 6, pp. 525--533, 1993.
class ScaledConjugateGradient
include Enumerable
# Create a new optimizer with scaled conjugate gradient.
#
@@ -54,11 +54,11 @@
# @param x_init [Numo::NArray] Initial point.
# @param max_iter [Integer] Maximum number of iterations.
# @param xtol [Float] Tolerance for termination for the optimal vector norm.
# @param ftol [Float] Tolerance for termination for the objective function value.
# @param jtol [Float] Tolerance for termination for the gradient norm.
- def initialize(fnc:, jcb:, args: nil, x_init:, max_iter: 200, xtol: 1e-6, ftol: 1e-8, jtol: 1e-7)
+ def initialize(fnc:, jcb:, x_init:, args: nil, max_iter: 200, xtol: 1e-6, ftol: 1e-8, jtol: 1e-7)
@fnc = fnc
@jcb = jcb
@x_init = x_init
@args = args
@max_iter = max_iter
@@ -80,14 +80,14 @@
# @return [Enumerator] If block is not given, this method returns Enumerator.
def each
return to_enum(__method__) unless block_given?
x = @x_init
- f_prev = func(x)
+ f_prev = func(x, @args)
n_fev = 1
f_curr = f_prev
- j_next = jacb(x)
+ j_next = jacb(x, @args)
n_jev = 1
j_curr = j_next.dot(j_next)
j_prev = j_next.dup
d = -j_next
@@ -107,24 +107,27 @@
kappa = d.dot(d)
break if kappa < 1e-16
sigma = SIGMA_INIT / Math.sqrt(kappa)
x_plus = x + sigma * d
- j_plus = jacb(x_plus)
+ j_plus = jacb(x_plus, @args)
n_jev += 1
theta = d.dot(j_plus - j_next) / sigma
end
delta = theta + beta * kappa
if delta <= 0
delta = beta * kappa
- beta -= theta / kappa
+ # TODO: Investigate the cause of the type error.
+ # Cannot assign a value of type `::Complex` to a variable of type `::Float`
+ # beta -= theta / kappa
+ beta = (beta - (theta / kappa)).to_f
end
alpha = -mu / delta
x_next = x + alpha * d
- f_next = func(x_next)
+ f_next = func(x_next, @args)
n_fev += 1
delta = 2 * (f_next - f_prev) / (alpha * mu)
if delta >= 0
success = true
@@ -144,19 +147,19 @@
break if (alpha * d).abs.max < @xtol
f_prev = f_next
j_prev = j_next
- j_next = jacb(x)
+ j_next = jacb(x, @args)
n_jev += 1
j_curr = j_next.dot(j_next)
break if j_curr <= @jtol
end
- beta = [beta * 4, BETA_MAX].min if delta < 0.25
- beta = [beta / 4, BETA_MIN].max if delta > 0.75
+ beta = beta * 4 < BETA_MAX ? beta * 4 : BETA_MAX if delta < 0.25
+ beta = beta / 4 > BETA_MIN ? beta / 4 : BETA_MIN if delta > 0.75
if n_successes == x.size
d = -j_next
beta = 1.0
n_successes = 0
@@ -173,30 +176,30 @@
private_constant :SIGMA_INIT, :BETA_MIN, :BETA_MAX
private
- def func(x)
- if @args.is_a?(Hash)
- @fnc.call(x, **@args)
- elsif @args.is_a?(Array)
- @fnc.call(x, *@args)
- elsif @args.nil?
+ def func(x, args)
+ if args.is_a?(Hash)
+ @fnc.call(x, **args)
+ elsif args.is_a?(Array)
+ @fnc.call(x, *args)
+ elsif args.nil?
@fnc.call(x)
else
- @fnc.call(x, @args)
+ @fnc.call(x, args)
end
end
- def jacb(x)
- if @args.is_a?(Hash)
- @jcb.call(x, **@args)
- elsif @args.is_a?(Array)
- @jcb.call(x, *@args)
- elsif @args.nil?
+ def jacb(x, args)
+ if args.is_a?(Hash)
+ @jcb.call(x, **args)
+ elsif args.is_a?(Array)
+ @jcb.call(x, *args)
+ elsif args.nil?
@jcb.call(x)
else
- @jcb.call(x, @args)
+ @jcb.call(x, args)
end
end
end
end