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::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::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,

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.

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