=begin
= Multidimensional Root-Finding

== Initializing the Solver
Two types of solvers are available. The solver itself depends only on the 
dimension of the problem and the algorithm and can be reused for different problems.
The (({FdfSolver})) requires derivatives of the function to solve.

--- GSL::MultiRoot::FSolver.new(T, n)
--- GSL::MultiRoot::FSolver.alloc(T, n)
    This creates an instance of the (({FSolver})) class of type ((|T|)) 
    for a system of ((|n|)) dimensions. The type is given by a constant or a string,
      * GSL::MultiRoot:FSolver::HYBRIDS, or "hybrids"
      * GSL::MultiRoot:FSolver::HYBRID, or "hybrid"
      * GSL::MultiRoot:FSolver::DNEWTON, or "dnewton"
      * GSL::MultiRoot:FSolver::BROYDEN, or "broyden"

--- GSL::MultiRoot::FdfSolver.new(T, n)
--- GSL::MultiRoot::FdfSolver.alloc(T, n)
    This creates an instance of the (({FdfSolver})) class of type ((|T|)) 
    for a system of ((|n|)) dimensions. The type is given by a constant,
      * GSL::MultiRoot:FdfSolver::HYBRIDSJ, or "hybridsj"
      * GSL::MultiRoot:FdfSolver::HYBRIDJ, or "hybridj",
      * GSL::MultiRoot:FdfSolver::NEWTON, or "newton",
      * GSL::MultiRoot:FdfSolver::GNEWTON, or "gnewton

--- GSL::MultiRoot::FSolver#set(func, x)
    This method sets, or resets, an existing solver ((|self|)) 
    to use the function ((|func|)) and the initial guess ((|x|)).
    Here ((|x|)) is a (({Vector})), and ((|func|)) 
    is a (({MultiRoot:Function})) object.
--- GSL::MultiRoot::FdfSolver#set(func_fdf, x)
    This method sets, or resets, an existing solver ((|self|)) 
    to use the function ((|func_fdf|)) and the initial guess ((|x|)).
    Here ((|x|)) is a (({Vector})), and ((|func_fdf|)) 
    is a (({MultiRoot:Function_fdf})) object.

--- GSL::MultiRoot::FSolver#name
--- GSL::MultiRoot::FdfSolver#name

== Providing the function to solve
--- GSL::MultiRoot:Function.new(proc, dim, params)
    See example below:

      # x: vector, current guess
      # params: a scalar or an array
      # f: vector, function value
      proc = Proc.new { |x, params, f|
        a = params[0]; b = params[1]
        x0 = x[0]; x1 = x[1]
        f[0] = a*(1 - x0)
        f[1] = b*(x1 - x0*x0)
      }

      params = [1.0, 10.0]
      func = MultiRoot::Function.new(proc, 2, params)
      fsolver = MultiRoot::FSolver.new("broyden", 2)
      x = [-10, -5]    # initial guess
      fsolver.set(func, x)

--- GSL::MultiRoot:Function_fdf.new(proc, dim, params)
    See the example below:
    
      procf = Proc.new { |x, params, f|
        a = params[0]; b = params[1]
        x0 = x[0]; x1 = x[1]
        f[0] = a*(1 - x0)
        f[1] = b*(x1 - x0*x0)
      }

      procdf = Proc.new { |x, params, jac|
        a = params[0]; b = params[1]
        jac.set(0, 0, -a)
        jac.set(0, 1, 0)
        jac.set(1, 0, -2*b*x[0])
        jac.set(1, 1, b)
      }

      params = [1.0, 10.0]
      func_fdf = MultiRoot::Function_fdf.new(procf, procdf, n, params)

      fdfsolver = MultiRoot::FdfSolver.new("gnewton", n)
      x = [-10.0, -5.0]
      fdfsolver.set(func_fdf, x)

== Iteration
--- GSL::MultiRoot::FSolver#interate
--- GSL::MultiRoot::FdfSolver#interate
    These methods perform a single iteration of the solver ((|self|)). 
    If the iteration encounters an unexpected problem then an error code will 
    be returned,
    * GSL_EBADFUNC: the iteration encountered a singular point where the function 
      or its derivative evaluated to Inf or NaN.
    * GSL_ENOPROG: the iteration is not making any progress, preventing the 
      algorithm from continuing.
    The solver maintains a current best estimate of the root at all times. 
    This information can be accessed with the following auxiliary methods.

--- GSL::MultiRoot::FSolver#root
--- GSL::MultiRoot::FdfSolver#root
    These methods return the current estimate of the root (Vector) for the solver ((|self|)).

--- GSL::MultiRoot::FSolver#f
--- GSL::MultiRoot::FdfSolver#f
    These methds return the function value (({f(x)})) (Vector) at the current estimate 
    of the root for the solver ((|self|)).

--- GSL::MultiRoot::FSolver#dx
--- GSL::MultiRoot::FdfSolver#dx
    These method return the last step ((|dx|)) (Vector) taken by the solver ((|self|)).

== Search Stopping Parameters
--- GSL::MultiRoot::FSolver#test_delta(epsabs, epsrel)
--- GSL::MultiRoot::FdfSolver#test_delta(epsabs, epsrel)
    This method tests for the convergence of the sequence by comparing the last step 
    (({dx})) with the absolute error ((|epsabs|)) and relative error ((|epsrel|)) 
    to the current position (({x})). 
    The test returns (({GSL::SUCCESS})) if the following condition is achieved,
      |dx_i| < epsabs + epsrel |x_i|
    for each component of (({x})) and returns (({GSL::CONTINUE})) otherwise.

--- GSL::MultiRoot::FSolver#test_residual(epsabs)
--- GSL::MultiRoot::FdfSolver#test_residual(epsabs)
    This method tests the residual value (({f})) against the absolute error 
    bound ((|epsabs|)). The test returns (({GSL::SUCCESS})) if the following 
    condition is achieved,
       sum_i |f_i| < epsabs
    and returns (({GSL::CONTINUE})) otherwise. This criterion is suitable for 
    situations where the precise location of the root, (({x})), is unimportant 
    provided a value can be found where the residual is small enough.

== Higher Level Interface
--- GSL::MultiRoot::FSolver#fsolve(max_iter = 1000, eps = 1e-7)
--- GSL::MultiRoot::FSolver#solve(max_iter = 1000, eps = 1e-7)
--- GSL::MultiRoot::FSolver.fsolve(fsolver, max_iter = 1000, eps = 1e-7)
--- GSL::MultiRoot::FSolver.solve(fsolver, max_iter = 1000, eps = 1e-7)
See sample script (({samples/multiroot/fsolver3.rb})).

== Example

=== FSolver

     proc = Proc.new { |x, params, f|
       a = params[0];  b = params[1]
       x0 = x[0];  x1 = x[1]
       f[0] = a*(1 - x0)
       f[1] = b*(x1 - x0*x0)
     }

     params = [1.0, 10.0]
     func = MultiRoot::Function.new(proc, 2, params)

     fsolver = MultiRoot::FSolver.new("hybrid", 2)
     x = [-10, -5]
     fsolver.set(func, x)

     iter = 0
     begin
       iter += 1
       status = fsolver.iterate
       root = fsolver.root
       f = fsolver.f
       printf("iter = %3u x = % .3f % .3f f(x) = % .3e % .3e\n",
               iter, root[0], root[1], f[0], f[1])
       status = fsolver.test_residual(1e-7)
     end while status == GSL::CONTINUE and iter < 1000

=== FdfSolver
     n = 2

     procf = Proc.new { |x, params, f|
       a = params[0]; b = params[1]
       x0 = x[0]; x1 = x[1]
       f[0] = a*(1 - x0)
       f[1] = b*(x1 - x0*x0)
     }

     procdf = Proc.new { |x, params, jac|
       a = params[0]; b = params[1]
       jac.set(0, 0, -a)
       jac.set(0, 1, 0)
       jac.set(1, 0, -2*b*x[0])
       jac.set(1, 1, b)
     }

     params = [1.0, 10.0]
     f = MultiRoot::Function_fdf.new(procf, procdf, n, params)

     fdfsolver = MultiRoot::FdfSolver.new("gnewton", n)

     x = [-10.0, -5.0]

     fdfsolver.set(f, x)

     iter = 0
     begin
       iter += 1
       status = fdfsolver.iterate
       root = fdfsolver.root
       f = fdfsolver.f
       printf("iter = %3u x = % .3f % .3f f(x) = % .3e % .3e\n",
               iter, root[0], root[1], f[0], f[1])
       status = fdfsolver.test_residual(1e-7)
     end while status == GSL::CONTINUE and iter < 1000

((<back|URL:index.html>))
=end
