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