Blame doc/multiroots.rst

Packit 67cb25
.. index::
Packit 67cb25
   single: solving nonlinear systems of equations
Packit 67cb25
   single: nonlinear systems of equations, solution of
Packit 67cb25
   single: systems of equations, nonlinear
Packit 67cb25
Packit 67cb25
*****************************
Packit 67cb25
Multidimensional Root-Finding
Packit 67cb25
*****************************
Packit 67cb25
Packit 67cb25
.. include:: include.rst
Packit 67cb25
Packit 67cb25
This chapter describes functions for multidimensional root-finding
Packit 67cb25
(solving nonlinear systems with :math:`n` equations in :math:`n`
Packit 67cb25
unknowns).  The library provides low level components for a variety of
Packit 67cb25
iterative solvers and convergence tests.  These can be combined by the
Packit 67cb25
user to achieve the desired solution, with full access to the
Packit 67cb25
intermediate steps of the iteration.  Each class of methods uses the
Packit 67cb25
same framework, so that you can switch between solvers at runtime
Packit 67cb25
without needing to recompile your program.  Each instance of a solver
Packit 67cb25
keeps track of its own state, allowing the solvers to be used in
Packit 67cb25
multi-threaded programs.  The solvers are based on the original Fortran
Packit 67cb25
library |minpack|.
Packit 67cb25
Packit 67cb25
The header file :file:`gsl_multiroots.h` contains prototypes for the
Packit 67cb25
multidimensional root finding functions and related declarations.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: multidimensional root finding, overview
Packit 67cb25
Packit 67cb25
Overview
Packit 67cb25
========
Packit 67cb25
Packit 67cb25
The problem of multidimensional root finding requires the simultaneous
Packit 67cb25
solution of :math:`n` equations, :math:`f_i`, in :math:`n` variables,
Packit 67cb25
:math:`x_i`,
Packit 67cb25
Packit 67cb25
.. only:: not texinfo
Packit 67cb25
Packit 67cb25
   .. math:: f_i (x_1, \dots, x_n) = 0 \qquad\hbox{for}~i = 1 \dots n.
Packit 67cb25
Packit 67cb25
.. only:: texinfo
Packit 67cb25
Packit 67cb25
   ::
Packit 67cb25
Packit 67cb25
      f_i (x_1, ..., x_n) = 0    for i = 1 ... n.
Packit 67cb25
Packit 67cb25
In general there are no bracketing methods available for :math:`n`
Packit 67cb25
dimensional systems, and no way of knowing whether any solutions
Packit 67cb25
exist.  All algorithms proceed from an initial guess using a variant of
Packit 67cb25
the Newton iteration,
Packit 67cb25
Packit 67cb25
.. only:: not texinfo
Packit 67cb25
Packit 67cb25
   .. math:: x \to x' = x - J^{-1} f(x)
Packit 67cb25
Packit 67cb25
.. only:: texinfo
Packit 67cb25
Packit 67cb25
   ::
Packit 67cb25
Packit 67cb25
      x -> x' = x - J^{-1} f(x)
Packit 67cb25
Packit 67cb25
where :math:`x`, :math:`f` are vector quantities and :math:`J` is the
Packit 67cb25
Jacobian matrix :math:`J_{ij} = \partial f_i / \partial x_j`.
Packit 67cb25
Additional strategies can be used to enlarge the region of
Packit 67cb25
convergence.  These include requiring a decrease in the norm :math:`|f|` on
Packit 67cb25
each step proposed by Newton's method, or taking steepest-descent steps in
Packit 67cb25
the direction of the negative gradient of :math:`|f|`.
Packit 67cb25
Packit 67cb25
Several root-finding algorithms are available within a single framework.
Packit 67cb25
The user provides a high-level driver for the algorithms, and the
Packit 67cb25
library provides the individual functions necessary for each of the
Packit 67cb25
steps.  There are three main phases of the iteration.  The steps are,
Packit 67cb25
Packit 67cb25
* initialize solver state, :data:`s`, for algorithm :data:`T`
Packit 67cb25
* update :data:`s` using the iteration :data:`T`
Packit 67cb25
* test :data:`s` for convergence, and repeat iteration if necessary
Packit 67cb25
Packit 67cb25
The evaluation of the Jacobian matrix can be problematic, either because
Packit 67cb25
programming the derivatives is intractable or because computation of the
Packit 67cb25
:math:`n^2` terms of the matrix becomes too expensive.  For these reasons
Packit 67cb25
the algorithms provided by the library are divided into two classes according
Packit 67cb25
to whether the derivatives are available or not.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: Jacobian matrix, root finding
Packit 67cb25
Packit 67cb25
The state for solvers with an analytic Jacobian matrix is held in a
Packit 67cb25
:type:`gsl_multiroot_fdfsolver` struct.  The updating procedure requires
Packit 67cb25
both the function and its derivatives to be supplied by the user.
Packit 67cb25
Packit 67cb25
The state for solvers which do not use an analytic Jacobian matrix is
Packit 67cb25
held in a :type:`gsl_multiroot_fsolver` struct.  The updating procedure
Packit 67cb25
uses only function evaluations (not derivatives).  The algorithms
Packit 67cb25
estimate the matrix :math:`J` or :math:`J^{-1}`
Packit 67cb25
by approximate methods.
Packit 67cb25
Packit 67cb25
Initializing the Solver
Packit 67cb25
=======================
Packit 67cb25
Packit 67cb25
The following functions initialize a multidimensional solver, either
Packit 67cb25
with or without derivatives.  The solver itself depends only on the
Packit 67cb25
dimension of the problem and the algorithm and can be reused for
Packit 67cb25
different problems.
Packit 67cb25
Packit 67cb25
.. type:: gsl_multiroot_fsolver
Packit 67cb25
Packit 67cb25
   This is a workspace for multidimensional root-finding without derivatives.
Packit 67cb25
Packit 67cb25
.. type:: gsl_multiroot_fdfsolver
Packit 67cb25
Packit 67cb25
   This is a workspace for multidimensional root-finding with derivatives.
Packit 67cb25
Packit 67cb25
.. function:: gsl_multiroot_fsolver * gsl_multiroot_fsolver_alloc (const gsl_multiroot_fsolver_type * T, size_t n)
Packit 67cb25
Packit 67cb25
   This function returns a pointer to a newly allocated instance of a
Packit 67cb25
   solver of type :data:`T` for a system of :data:`n` dimensions.
Packit 67cb25
   For example, the following code creates an instance of a hybrid solver, 
Packit 67cb25
   to solve a 3-dimensional system of equations::
Packit 67cb25
Packit 67cb25
      const gsl_multiroot_fsolver_type * T = gsl_multiroot_fsolver_hybrid;
Packit 67cb25
      gsl_multiroot_fsolver * s = gsl_multiroot_fsolver_alloc (T, 3);
Packit 67cb25
Packit 67cb25
   If there is insufficient memory to create the solver then the function
Packit 67cb25
   returns a null pointer and the error handler is invoked with an error
Packit 67cb25
   code of :macro:`GSL_ENOMEM`.
Packit 67cb25
Packit 67cb25
.. function:: gsl_multiroot_fdfsolver * gsl_multiroot_fdfsolver_alloc (const gsl_multiroot_fdfsolver_type * T, size_t n)
Packit 67cb25
Packit 67cb25
   This function returns a pointer to a newly allocated instance of a
Packit 67cb25
   derivative solver of type :data:`T` for a system of :data:`n` dimensions.
Packit 67cb25
   For example, the following code creates an instance of a Newton-Raphson solver,
Packit 67cb25
   for a 2-dimensional system of equations::
Packit 67cb25
Packit 67cb25
      const gsl_multiroot_fdfsolver_type * T = gsl_multiroot_fdfsolver_newton;
Packit 67cb25
      gsl_multiroot_fdfsolver * s = gsl_multiroot_fdfsolver_alloc (T, 2);
Packit 67cb25
Packit 67cb25
   If there is insufficient memory to create the solver then the function
Packit 67cb25
   returns a null pointer and the error handler is invoked with an error
Packit 67cb25
   code of :macro:`GSL_ENOMEM`.
Packit 67cb25
Packit 67cb25
.. function:: int gsl_multiroot_fsolver_set (gsl_multiroot_fsolver * s, gsl_multiroot_function * f, const gsl_vector * x)
Packit 67cb25
              int gsl_multiroot_fdfsolver_set (gsl_multiroot_fdfsolver * s, gsl_multiroot_function_fdf * fdf, const gsl_vector * x)
Packit 67cb25
Packit 67cb25
   These functions set, or reset, an existing solver :data:`s` to use the
Packit 67cb25
   function :data:`f` or function and derivative :data:`fdf`, and the initial
Packit 67cb25
   guess :data:`x`.  Note that the initial position is copied from :data:`x`, this
Packit 67cb25
   argument is not modified by subsequent iterations.
Packit 67cb25
Packit 67cb25
.. function:: void gsl_multiroot_fsolver_free (gsl_multiroot_fsolver * s)
Packit 67cb25
              void gsl_multiroot_fdfsolver_free (gsl_multiroot_fdfsolver * s)
Packit 67cb25
Packit 67cb25
   These functions free all the memory associated with the solver :data:`s`.
Packit 67cb25
Packit 67cb25
.. function:: const char * gsl_multiroot_fsolver_name (const gsl_multiroot_fsolver * s)
Packit 67cb25
              const char * gsl_multiroot_fdfsolver_name (const gsl_multiroot_fdfsolver * s)
Packit 67cb25
Packit 67cb25
   These functions return a pointer to the name of the solver.  For example::
Packit 67cb25
Packit 67cb25
      printf ("s is a '%s' solver\n", gsl_multiroot_fdfsolver_name (s));
Packit 67cb25
Packit 67cb25
   would print something like :code:`s is a 'newton' solver`.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: multidimensional root finding, providing a function to solve
Packit 67cb25
Packit 67cb25
Providing the function to solve
Packit 67cb25
===============================
Packit 67cb25
Packit 67cb25
You must provide :math:`n` functions of :math:`n` variables for the root
Packit 67cb25
finders to operate on.  In order to allow for general parameters the
Packit 67cb25
functions are defined by the following data types:
Packit 67cb25
Packit 67cb25
.. type:: gsl_multiroot_function 
Packit 67cb25
Packit 67cb25
   This data type defines a general system of functions with parameters.
Packit 67cb25
Packit 67cb25
   :code:`int (* f) (const gsl_vector * x, void * params, gsl_vector * f)`
Packit 67cb25
Packit 67cb25
      this function should store the vector result
Packit 67cb25
      :math:`f(x,params)` in :data:`f` for argument :data:`x` and parameters :data:`params`,
Packit 67cb25
      returning an appropriate error code if the function cannot be computed.
Packit 67cb25
Packit 67cb25
   :code:`size_t n`
Packit 67cb25
Packit 67cb25
      the dimension of the system, i.e. the number of components of the
Packit 67cb25
      vectors :data:`x` and :data:`f`.
Packit 67cb25
Packit 67cb25
   :code:`void * params`
Packit 67cb25
Packit 67cb25
      a pointer to the parameters of the function.
Packit 67cb25
Packit 67cb25
Here is an example using Powell's test function,
Packit 67cb25
Packit 67cb25
.. only:: not texinfo
Packit 67cb25
Packit 67cb25
   .. math::
Packit 67cb25
Packit 67cb25
      f_1(x) &= A x_0 x_1 - 1 \\
Packit 67cb25
      f_2(x) &= \exp(-x_0) + \exp(-x_1) - (1 + 1/A)
Packit 67cb25
Packit 67cb25
.. only:: texinfo
Packit 67cb25
Packit 67cb25
   ::
Packit 67cb25
Packit 67cb25
      f_1(x) = A x_0 x_1 - 1,
Packit 67cb25
      f_2(x) = exp(-x_0) + exp(-x_1) - (1 + 1/A)
Packit 67cb25
Packit 67cb25
with :math:`A = 10^4`.  The following code defines a
Packit 67cb25
:type:`gsl_multiroot_function` system :code:`F` which you could pass to a
Packit 67cb25
solver::
Packit 67cb25
Packit 67cb25
  struct powell_params { double A; };
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  powell (gsl_vector * x, void * p, gsl_vector * f) {
Packit 67cb25
     struct powell_params * params 
Packit 67cb25
       = (struct powell_params *)p;
Packit 67cb25
     const double A = (params->A);
Packit 67cb25
     const double x0 = gsl_vector_get(x,0);
Packit 67cb25
     const double x1 = gsl_vector_get(x,1);
Packit 67cb25
Packit 67cb25
     gsl_vector_set (f, 0, A * x0 * x1 - 1);
Packit 67cb25
     gsl_vector_set (f, 1, (exp(-x0) + exp(-x1) 
Packit 67cb25
                            - (1.0 + 1.0/A)));
Packit 67cb25
     return GSL_SUCCESS
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  gsl_multiroot_function F;
Packit 67cb25
  struct powell_params params = { 10000.0 };
Packit 67cb25
Packit 67cb25
  F.f = &powell;
Packit 67cb25
  F.n = 2;
Packit 67cb25
  F.params = ¶m;;
Packit 67cb25
Packit 67cb25
.. type:: gsl_multiroot_function_fdf
Packit 67cb25
Packit 67cb25
   This data type defines a general system of functions with parameters and
Packit 67cb25
   the corresponding Jacobian matrix of derivatives,
Packit 67cb25
Packit 67cb25
   :code:`int (* f) (const gsl_vector * x, void * params, gsl_vector * f)`
Packit 67cb25
Packit 67cb25
      this function should store the vector result
Packit 67cb25
      :math:`f(x,params)` in :data:`f` for argument :data:`x` and parameters :data:`params`,
Packit 67cb25
      returning an appropriate error code if the function cannot be computed.
Packit 67cb25
Packit 67cb25
   :code:`int (* df) (const gsl_vector * x, void * params, gsl_matrix * J)`
Packit 67cb25
Packit 67cb25
      this function should store the :data:`n`-by-:data:`n` matrix result
Packit 67cb25
Packit 67cb25
      .. only:: not texinfo
Packit 67cb25
Packit 67cb25
         .. math:: J_{ij} = \partial f_i(x,\hbox{\it params}) / \partial x_j
Packit 67cb25
Packit 67cb25
      .. only:: texinfo
Packit 67cb25
Packit 67cb25
         ::
Packit 67cb25
Packit 67cb25
            J_ij = d f_i(x,params) / d x_j
Packit 67cb25
            
Packit 67cb25
      in :data:`J` for argument :data:`x` 
Packit 67cb25
      and parameters :data:`params`, returning an appropriate error code if the
Packit 67cb25
      function cannot be computed.
Packit 67cb25
Packit 67cb25
   :code:`int (* fdf) (const gsl_vector * x, void * params, gsl_vector * f, gsl_matrix * J)`
Packit 67cb25
Packit 67cb25
      This function should set the values of the :data:`f` and :data:`J` as above,
Packit 67cb25
      for arguments :data:`x` and parameters :data:`params`.  This function
Packit 67cb25
      provides an optimization of the separate functions for :math:`f(x)` and
Packit 67cb25
      :math:`J(x)`---it is always faster to compute the function and its
Packit 67cb25
      derivative at the same time.
Packit 67cb25
Packit 67cb25
   :code:`size_t n`
Packit 67cb25
Packit 67cb25
      the dimension of the system, i.e. the number of components of the
Packit 67cb25
      vectors :data:`x` and :data:`f`.
Packit 67cb25
Packit 67cb25
   :code:`void * params`
Packit 67cb25
Packit 67cb25
      a pointer to the parameters of the function.
Packit 67cb25
Packit 67cb25
The example of Powell's test function defined above can be extended to
Packit 67cb25
include analytic derivatives using the following code::
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  powell_df (gsl_vector * x, void * p, gsl_matrix * J) 
Packit 67cb25
  {
Packit 67cb25
     struct powell_params * params 
Packit 67cb25
       = (struct powell_params *)p;
Packit 67cb25
     const double A = (params->A);
Packit 67cb25
     const double x0 = gsl_vector_get(x,0);
Packit 67cb25
     const double x1 = gsl_vector_get(x,1);
Packit 67cb25
     gsl_matrix_set (J, 0, 0, A * x1);
Packit 67cb25
     gsl_matrix_set (J, 0, 1, A * x0);
Packit 67cb25
     gsl_matrix_set (J, 1, 0, -exp(-x0));
Packit 67cb25
     gsl_matrix_set (J, 1, 1, -exp(-x1));
Packit 67cb25
     return GSL_SUCCESS
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  powell_fdf (gsl_vector * x, void * p, 
Packit 67cb25
              gsl_matrix * f, gsl_matrix * J) {
Packit 67cb25
     struct powell_params * params 
Packit 67cb25
       = (struct powell_params *)p;
Packit 67cb25
     const double A = (params->A);
Packit 67cb25
     const double x0 = gsl_vector_get(x,0);
Packit 67cb25
     const double x1 = gsl_vector_get(x,1);
Packit 67cb25
Packit 67cb25
     const double u0 = exp(-x0);
Packit 67cb25
     const double u1 = exp(-x1);
Packit 67cb25
Packit 67cb25
     gsl_vector_set (f, 0, A * x0 * x1 - 1);
Packit 67cb25
     gsl_vector_set (f, 1, u0 + u1 - (1 + 1/A));
Packit 67cb25
Packit 67cb25
     gsl_matrix_set (J, 0, 0, A * x1);
Packit 67cb25
     gsl_matrix_set (J, 0, 1, A * x0);
Packit 67cb25
     gsl_matrix_set (J, 1, 0, -u0);
Packit 67cb25
     gsl_matrix_set (J, 1, 1, -u1);
Packit 67cb25
     return GSL_SUCCESS
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  gsl_multiroot_function_fdf FDF;
Packit 67cb25
Packit 67cb25
  FDF.f = &powell_f;
Packit 67cb25
  FDF.df = &powell_df;
Packit 67cb25
  FDF.fdf = &powell_fdf;
Packit 67cb25
  FDF.n = 2;
Packit 67cb25
  FDF.params = 0;
Packit 67cb25
Packit 67cb25
Note that the function :code:`powell_fdf` is able to reuse existing terms
Packit 67cb25
from the function when calculating the Jacobian, thus saving time.
Packit 67cb25
Packit 67cb25
Iteration
Packit 67cb25
=========
Packit 67cb25
Packit 67cb25
The following functions drive the iteration of each algorithm.  Each
Packit 67cb25
function performs one iteration to update the state of any solver of the
Packit 67cb25
corresponding type.  The same functions work for all solvers so that
Packit 67cb25
different methods can be substituted at runtime without modifications to
Packit 67cb25
the code.
Packit 67cb25
Packit 67cb25
.. function:: int gsl_multiroot_fsolver_iterate (gsl_multiroot_fsolver * s)
Packit 67cb25
              int gsl_multiroot_fdfsolver_iterate (gsl_multiroot_fdfsolver * s)
Packit 67cb25
Packit 67cb25
   These functions perform a single iteration of the solver :data:`s`.  If the
Packit 67cb25
   iteration encounters an unexpected problem then an error code will be
Packit 67cb25
   returned,
Packit 67cb25
Packit 67cb25
   :macro:`GSL_EBADFUNC`
Packit 67cb25
Packit 67cb25
      the iteration encountered a singular point where the function or its
Packit 67cb25
      derivative evaluated to :code:`Inf` or :code:`NaN`.
Packit 67cb25
Packit 67cb25
   :macro:`GSL_ENOPROG`
Packit 67cb25
Packit 67cb25
      the iteration is not making any progress, preventing the algorithm from
Packit 67cb25
      continuing.
Packit 67cb25
Packit 67cb25
The solver maintains a current best estimate of the root :code:`s->x`
Packit 67cb25
and its function value :code:`s->f` at all times.  This information can
Packit 67cb25
be accessed with the following auxiliary functions,
Packit 67cb25
Packit 67cb25
.. function:: gsl_vector * gsl_multiroot_fsolver_root (const gsl_multiroot_fsolver * s)
Packit 67cb25
              gsl_vector * gsl_multiroot_fdfsolver_root (const gsl_multiroot_fdfsolver * s)
Packit 67cb25
Packit 67cb25
   These functions return the current estimate of the root for the solver :data:`s`, given by :code:`s->x`.
Packit 67cb25
Packit 67cb25
.. function:: gsl_vector * gsl_multiroot_fsolver_f (const gsl_multiroot_fsolver * s)
Packit 67cb25
              gsl_vector * gsl_multiroot_fdfsolver_f (const gsl_multiroot_fdfsolver * s)
Packit 67cb25
Packit 67cb25
   These functions return the function value :math:`f(x)` at the current
Packit 67cb25
   estimate of the root for the solver :data:`s`, given by :code:`s->f`.
Packit 67cb25
Packit 67cb25
.. function:: gsl_vector * gsl_multiroot_fsolver_dx (const gsl_multiroot_fsolver * s)
Packit 67cb25
              gsl_vector * gsl_multiroot_fdfsolver_dx (const gsl_multiroot_fdfsolver * s)
Packit 67cb25
Packit 67cb25
   These functions return the last step :math:`dx` taken by the solver
Packit 67cb25
   :data:`s`, given by :code:`s->dx`.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: root finding, stopping parameters
Packit 67cb25
Packit 67cb25
Search Stopping Parameters
Packit 67cb25
==========================
Packit 67cb25
Packit 67cb25
A root finding procedure should stop when one of the following conditions is
Packit 67cb25
true:
Packit 67cb25
Packit 67cb25
* A multidimensional root has been found to within the user-specified precision.
Packit 67cb25
* A user-specified maximum number of iterations has been reached.
Packit 67cb25
* An error has occurred.
Packit 67cb25
Packit 67cb25
The handling of these conditions is under user control.  The functions
Packit 67cb25
below allow the user to test the precision of the current result in
Packit 67cb25
several standard ways.
Packit 67cb25
Packit 67cb25
.. function:: int gsl_multiroot_test_delta (const gsl_vector * dx, const gsl_vector * x, double epsabs, double epsrel)
Packit 67cb25
Packit 67cb25
   This function tests for the convergence of the sequence by comparing the
Packit 67cb25
   last step :data:`dx` with the absolute error :data:`epsabs` and relative
Packit 67cb25
   error :data:`epsrel` to the current position :data:`x`.  The test returns
Packit 67cb25
   :macro:`GSL_SUCCESS` if the following condition is achieved,
Packit 67cb25
Packit 67cb25
   .. only:: not texinfo
Packit 67cb25
Packit 67cb25
      .. math:: |dx_i| < \hbox{\it epsabs} + \hbox{\it epsrel\/}\, |x_i|
Packit 67cb25
Packit 67cb25
   .. only:: texinfo
Packit 67cb25
Packit 67cb25
      ::
Packit 67cb25
Packit 67cb25
         |dx_i| < epsabs + epsrel |x_i|
Packit 67cb25
Packit 67cb25
   for each component of :data:`x` and returns :macro:`GSL_CONTINUE` otherwise.
Packit 67cb25
Packit 67cb25
.. index::
Packit 67cb25
   single: residual, in nonlinear systems of equations
Packit 67cb25
Packit 67cb25
.. function:: int gsl_multiroot_test_residual (const gsl_vector * f, double epsabs)
Packit 67cb25
Packit 67cb25
   This function tests the residual value :data:`f` against the absolute
Packit 67cb25
   error bound :data:`epsabs`.  The test returns :macro:`GSL_SUCCESS` if the
Packit 67cb25
   following condition is achieved,
Packit 67cb25
Packit 67cb25
   .. only:: not texinfo
Packit 67cb25
Packit 67cb25
      .. math:: \sum_i |f_i| < \hbox{\it epsabs}
Packit 67cb25
Packit 67cb25
   .. only:: texinfo
Packit 67cb25
Packit 67cb25
      ::
Packit 67cb25
Packit 67cb25
         \sum_i |f_i| < epsabs
Packit 67cb25
Packit 67cb25
   and returns :macro:`GSL_CONTINUE` otherwise.  This criterion is suitable
Packit 67cb25
   for situations where the precise location of the root, :math:`x`, is
Packit 67cb25
   unimportant provided a value can be found where the residual is small
Packit 67cb25
   enough.
Packit 67cb25
Packit 67cb25
Algorithms using Derivatives
Packit 67cb25
============================
Packit 67cb25
Packit 67cb25
The root finding algorithms described in this section make use of both
Packit 67cb25
the function and its derivative.  They require an initial guess for the
Packit 67cb25
location of the root, but there is no absolute guarantee of
Packit 67cb25
convergence---the function must be suitable for this technique and the
Packit 67cb25
initial guess must be sufficiently close to the root for it to work.
Packit 67cb25
When the conditions are satisfied then convergence is quadratic.
Packit 67cb25
Packit 67cb25
.. type:: gsl_multiroot_fdfsolver_type
Packit 67cb25
Packit 67cb25
   The following are available algorithms for minimizing functions using
Packit 67cb25
   derivatives.
Packit 67cb25
Packit 67cb25
   .. index:: HYBRID algorithms for nonlinear systems
Packit 67cb25
Packit 67cb25
   .. index::
Packit 67cb25
      single: HYBRIDSJ algorithm
Packit 67cb25
      single: MINPACK, minimization algorithms
Packit 67cb25
Packit 67cb25
   .. var:: gsl_multiroot_fdfsolver_hybridsj
Packit 67cb25
Packit 67cb25
      This is a modified version of Powell's Hybrid method as implemented in
Packit 67cb25
      the HYBRJ algorithm in |minpack|.  Minpack was written by Jorge
Packit 67cb25
      J. |More|, Burton S. Garbow and Kenneth E. Hillstrom.  The Hybrid
Packit 67cb25
      algorithm retains the fast convergence of Newton's method but will also
Packit 67cb25
      reduce the residual when Newton's method is unreliable. 
Packit 67cb25
Packit 67cb25
      The algorithm uses a generalized trust region to keep each step under
Packit 67cb25
      control.  In order to be accepted a proposed new position :math:`x'` must
Packit 67cb25
      satisfy the condition :math:`|D (x' - x)| < \delta`, where :math:`D` is a
Packit 67cb25
      diagonal scaling matrix and :math:`\delta` is the size of the trust
Packit 67cb25
      region.  The components of :math:`D` are computed internally, using the
Packit 67cb25
      column norms of the Jacobian to estimate the sensitivity of the residual
Packit 67cb25
      to each component of :math:`x`.  This improves the behavior of the
Packit 67cb25
      algorithm for badly scaled functions.
Packit 67cb25
Packit 67cb25
      On each iteration the algorithm first determines the standard Newton
Packit 67cb25
      step by solving the system :math:`J dx = - f`.  If this step falls inside
Packit 67cb25
      the trust region it is used as a trial step in the next stage.  If not,
Packit 67cb25
      the algorithm uses the linear combination of the Newton and gradient
Packit 67cb25
      directions which is predicted to minimize the norm of the function while
Packit 67cb25
      staying inside the trust region,
Packit 67cb25
Packit 67cb25
      .. math:: dx = - \alpha J^{-1} f(x) - \beta \nabla |f(x)|^2
Packit 67cb25
Packit 67cb25
      This combination of Newton and gradient directions is referred to as a
Packit 67cb25
      *dogleg step*.
Packit 67cb25
Packit 67cb25
      The proposed step is now tested by evaluating the function at the
Packit 67cb25
      resulting point, :math:`x'`.  If the step reduces the norm of the function
Packit 67cb25
      sufficiently then it is accepted and size of the trust region is
Packit 67cb25
      increased.  If the proposed step fails to improve the solution then the
Packit 67cb25
      size of the trust region is decreased and another trial step is
Packit 67cb25
      computed.
Packit 67cb25
Packit 67cb25
      The speed of the algorithm is increased by computing the changes to the
Packit 67cb25
      Jacobian approximately, using a rank-1 update.  If two successive
Packit 67cb25
      attempts fail to reduce the residual then the full Jacobian is
Packit 67cb25
      recomputed.  The algorithm also monitors the progress of the solution
Packit 67cb25
      and returns an error if several steps fail to make any improvement,
Packit 67cb25
Packit 67cb25
      :macro:`GSL_ENOPROG`
Packit 67cb25
Packit 67cb25
         the iteration is not making any progress, preventing the algorithm from
Packit 67cb25
         continuing.
Packit 67cb25
Packit 67cb25
      :macro:`GSL_ENOPROGJ`
Packit 67cb25
Packit 67cb25
         re-evaluations of the Jacobian indicate that the iteration is not
Packit 67cb25
         making any progress, preventing the algorithm from continuing.
Packit 67cb25
Packit 67cb25
   .. index:: HYBRIDJ algorithm
Packit 67cb25
Packit 67cb25
   .. var:: gsl_multiroot_fdfsolver_hybridj
Packit 67cb25
Packit 67cb25
      This algorithm is an unscaled version of HYBRIDSJ.  The steps are
Packit 67cb25
      controlled by a spherical trust region :math:`|x' - x| < \delta`, instead
Packit 67cb25
      of a generalized region.  This can be useful if the generalized region
Packit 67cb25
      estimated by HYBRIDSJ is inappropriate.
Packit 67cb25
Packit 67cb25
   .. index:: Newton's method for systems of nonlinear equations
Packit 67cb25
Packit 67cb25
   .. var:: gsl_multiroot_fdfsolver_newton
Packit 67cb25
Packit 67cb25
      Newton's Method is the standard root-polishing algorithm.  The algorithm
Packit 67cb25
      begins with an initial guess for the location of the solution.  On each
Packit 67cb25
      iteration a linear approximation to the function :math:`F` is used to
Packit 67cb25
      estimate the step which will zero all the components of the residual.
Packit 67cb25
      The iteration is defined by the following sequence,
Packit 67cb25
Packit 67cb25
      .. only:: not texinfo
Packit 67cb25
Packit 67cb25
         .. math:: x \to x' = x - J^{-1} f(x)
Packit 67cb25
Packit 67cb25
      .. only:: texinfo
Packit 67cb25
Packit 67cb25
         ::
Packit 67cb25
Packit 67cb25
            x -> x' = x - J^{-1} f(x)
Packit 67cb25
Packit 67cb25
      where the Jacobian matrix :math:`J` is computed from the derivative
Packit 67cb25
      functions provided by :data:`f`.  The step :math:`dx` is obtained by solving
Packit 67cb25
      the linear system,
Packit 67cb25
Packit 67cb25
      .. math:: J dx = - f(x)
Packit 67cb25
Packit 67cb25
      using LU decomposition.  If the Jacobian matrix is singular, an error
Packit 67cb25
      code of :macro:`GSL_EDOM` is returned.
Packit 67cb25
Packit 67cb25
   .. index::
Packit 67cb25
      single: Modified Newton's method for nonlinear systems
Packit 67cb25
      single: Newton algorithm, globally convergent
Packit 67cb25
Packit 67cb25
   .. var:: gsl_multiroot_fdfsolver_gnewton
Packit 67cb25
Packit 67cb25
      This is a modified version of Newton's method which attempts to improve
Packit 67cb25
      global convergence by requiring every step to reduce the Euclidean norm
Packit 67cb25
      of the residual, :math:`|f(x)|`.  If the Newton step leads to an increase
Packit 67cb25
      in the norm then a reduced step of relative size,
Packit 67cb25
Packit 67cb25
      .. math:: t = (\sqrt{1 + 6 r} - 1) / (3 r)
Packit 67cb25
Packit 67cb25
      is proposed, with :math:`r` being the ratio of norms
Packit 67cb25
      :math:`|f(x')|^2/|f(x)|^2`.  This procedure is repeated until a suitable step
Packit 67cb25
      size is found. 
Packit 67cb25
Packit 67cb25
Algorithms without Derivatives
Packit 67cb25
==============================
Packit 67cb25
Packit 67cb25
The algorithms described in this section do not require any derivative
Packit 67cb25
information to be supplied by the user.  Any derivatives needed are
Packit 67cb25
approximated by finite differences.  Note that if the
Packit 67cb25
finite-differencing step size chosen by these routines is inappropriate,
Packit 67cb25
an explicit user-supplied numerical derivative can always be used with
Packit 67cb25
the algorithms described in the previous section.
Packit 67cb25
Packit 67cb25
.. type:: gsl_multiroot_fsolver_type
Packit 67cb25
Packit 67cb25
   The following are available algorithms for minimizing functions without
Packit 67cb25
   derivatives.
Packit 67cb25
Packit 67cb25
   .. index::
Packit 67cb25
      single: HYBRIDS algorithm, scaled without derivatives
Packit 67cb25
Packit 67cb25
   .. var:: gsl_multiroot_fsolver_hybrids
Packit 67cb25
Packit 67cb25
      This is a version of the Hybrid algorithm which replaces calls to the
Packit 67cb25
      Jacobian function by its finite difference approximation.  The finite
Packit 67cb25
      difference approximation is computed using :func:`gsl_multiroots_fdjac`
Packit 67cb25
      with a relative step size of :macro:`GSL_SQRT_DBL_EPSILON`.  Note that
Packit 67cb25
      this step size will not be suitable for all problems.
Packit 67cb25
Packit 67cb25
   .. index::
Packit 67cb25
      single: HYBRID algorithm, unscaled without derivatives
Packit 67cb25
Packit 67cb25
   .. var:: gsl_multiroot_fsolver_hybrid
Packit 67cb25
Packit 67cb25
      This is a finite difference version of the Hybrid algorithm without
Packit 67cb25
      internal scaling.
Packit 67cb25
Packit 67cb25
   .. index::
Packit 67cb25
      single: Discrete Newton algorithm for multidimensional roots
Packit 67cb25
      single: Newton algorithm, discrete
Packit 67cb25
Packit 67cb25
   .. var:: gsl_multiroot_fsolver_dnewton
Packit 67cb25
Packit 67cb25
      The *discrete Newton algorithm* is the simplest method of solving a
Packit 67cb25
      multidimensional system.  It uses the Newton iteration
Packit 67cb25
Packit 67cb25
      .. only:: not texinfo
Packit 67cb25
Packit 67cb25
         .. math:: x \to x - J^{-1} f(x)
Packit 67cb25
Packit 67cb25
      .. only:: texinfo
Packit 67cb25
Packit 67cb25
         ::
Packit 67cb25
Packit 67cb25
            x -> x - J^{-1} f(x)
Packit 67cb25
Packit 67cb25
      where the Jacobian matrix :math:`J` is approximated by taking finite
Packit 67cb25
      differences of the function :data:`f`.  The approximation scheme used by
Packit 67cb25
      this implementation is,
Packit 67cb25
Packit 67cb25
      .. math:: J_{ij} = (f_i(x + \delta_j) - f_i(x)) /  \delta_j
Packit 67cb25
Packit 67cb25
      where :math:`\delta_j` is a step of size :math:`\sqrt\epsilon |x_j|` with
Packit 67cb25
      :math:`\epsilon` being the machine precision 
Packit 67cb25
      (:math:`\epsilon \approx 2.22 \times 10^{-16}`).
Packit 67cb25
      The order of convergence of Newton's algorithm is quadratic, but the
Packit 67cb25
      finite differences require :math:`n^2` function evaluations on each
Packit 67cb25
      iteration.  The algorithm may become unstable if the finite differences
Packit 67cb25
      are not a good approximation to the true derivatives.
Packit 67cb25
Packit 67cb25
   .. index::
Packit 67cb25
      single: Broyden algorithm for multidimensional roots
Packit 67cb25
      single: multidimensional root finding, Broyden algorithm
Packit 67cb25
Packit 67cb25
   .. var:: gsl_multiroot_fsolver_broyden
Packit 67cb25
Packit 67cb25
      The *Broyden algorithm* is a version of the discrete Newton
Packit 67cb25
      algorithm which attempts to avoids the expensive update of the Jacobian
Packit 67cb25
      matrix on each iteration.  The changes to the Jacobian are also
Packit 67cb25
      approximated, using a rank-1 update,
Packit 67cb25
Packit 67cb25
      .. math:: J^{-1} \to J^{-1} - (J^{-1} df - dx) dx^T J^{-1} / dx^T J^{-1} df
Packit 67cb25
Packit 67cb25
      where the vectors :math:`dx` and :math:`df` are the changes in :math:`x`
Packit 67cb25
      and :math:`f`.  On the first iteration the inverse Jacobian is estimated
Packit 67cb25
      using finite differences, as in the discrete Newton algorithm.
Packit 67cb25
 
Packit 67cb25
      This approximation gives a fast update but is unreliable if the changes
Packit 67cb25
      are not small, and the estimate of the inverse Jacobian becomes worse as
Packit 67cb25
      time passes.  The algorithm has a tendency to become unstable unless it
Packit 67cb25
      starts close to the root.  The Jacobian is refreshed if this instability
Packit 67cb25
      is detected (consult the source for details).
Packit 67cb25
Packit 67cb25
      This algorithm is included only for demonstration purposes, and is not
Packit 67cb25
      recommended for serious use.
Packit 67cb25
Packit 67cb25
Examples
Packit 67cb25
========
Packit 67cb25
Packit 67cb25
The multidimensional solvers are used in a similar way to the
Packit 67cb25
one-dimensional root finding algorithms.  This first example
Packit 67cb25
demonstrates the HYBRIDS scaled-hybrid algorithm, which does not
Packit 67cb25
require derivatives. The program solves the Rosenbrock system of equations,
Packit 67cb25
Packit 67cb25
.. only:: not texinfo
Packit 67cb25
Packit 67cb25
   .. math::
Packit 67cb25
Packit 67cb25
      f_1 (x, y) &= a (1 - x) \\
Packit 67cb25
      f_2 (x, y) &= b (y - x^2)
Packit 67cb25
Packit 67cb25
.. only:: texinfo
Packit 67cb25
Packit 67cb25
   ::
Packit 67cb25
Packit 67cb25
      f_1 (x, y) = a (1 - x)
Packit 67cb25
      f_2 (x, y) = b (y - x^2)
Packit 67cb25
Packit 67cb25
with :math:`a = 1, b = 10`. The solution of this system lies at
Packit 67cb25
:math:`(x,y) = (1,1)` in a narrow valley.
Packit 67cb25
Packit 67cb25
The first stage of the program is to define the system of equations::
Packit 67cb25
Packit 67cb25
  #include <stdlib.h>
Packit 67cb25
  #include <stdio.h>
Packit 67cb25
  #include <gsl/gsl_vector.h>
Packit 67cb25
  #include <gsl/gsl_multiroots.h>
Packit 67cb25
Packit 67cb25
  struct rparams
Packit 67cb25
    {
Packit 67cb25
      double a;
Packit 67cb25
      double b;
Packit 67cb25
    };
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  rosenbrock_f (const gsl_vector * x, void *params, 
Packit 67cb25
                gsl_vector * f)
Packit 67cb25
  {
Packit 67cb25
    double a = ((struct rparams *) params)->a;
Packit 67cb25
    double b = ((struct rparams *) params)->b;
Packit 67cb25
Packit 67cb25
    const double x0 = gsl_vector_get (x, 0);
Packit 67cb25
    const double x1 = gsl_vector_get (x, 1);
Packit 67cb25
Packit 67cb25
    const double y0 = a * (1 - x0);
Packit 67cb25
    const double y1 = b * (x1 - x0 * x0);
Packit 67cb25
Packit 67cb25
    gsl_vector_set (f, 0, y0);
Packit 67cb25
    gsl_vector_set (f, 1, y1);
Packit 67cb25
Packit 67cb25
    return GSL_SUCCESS;
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
The main program begins by creating the function object :code:`f`, with
Packit 67cb25
the arguments :code:`(x,y)` and parameters :code:`(a,b)`. The solver
Packit 67cb25
:code:`s` is initialized to use this function, with the :data:`gsl_multiroot_fsolver_hybrids`
Packit 67cb25
method::
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  main (void)
Packit 67cb25
  {
Packit 67cb25
    const gsl_multiroot_fsolver_type *T;
Packit 67cb25
    gsl_multiroot_fsolver *s;
Packit 67cb25
Packit 67cb25
    int status;
Packit 67cb25
    size_t i, iter = 0;
Packit 67cb25
Packit 67cb25
    const size_t n = 2;
Packit 67cb25
    struct rparams p = {1.0, 10.0};
Packit 67cb25
    gsl_multiroot_function f = {&rosenbrock_f, n, &p};
Packit 67cb25
Packit 67cb25
    double x_init[2] = {-10.0, -5.0};
Packit 67cb25
    gsl_vector *x = gsl_vector_alloc (n);
Packit 67cb25
Packit 67cb25
    gsl_vector_set (x, 0, x_init[0]);
Packit 67cb25
    gsl_vector_set (x, 1, x_init[1]);
Packit 67cb25
Packit 67cb25
    T = gsl_multiroot_fsolver_hybrids;
Packit 67cb25
    s = gsl_multiroot_fsolver_alloc (T, 2);
Packit 67cb25
    gsl_multiroot_fsolver_set (s, &f, x);
Packit 67cb25
Packit 67cb25
    print_state (iter, s);
Packit 67cb25
Packit 67cb25
    do
Packit 67cb25
      {
Packit 67cb25
        iter++;
Packit 67cb25
        status = gsl_multiroot_fsolver_iterate (s);
Packit 67cb25
Packit 67cb25
        print_state (iter, s);
Packit 67cb25
Packit 67cb25
        if (status)   /* check if solver is stuck */
Packit 67cb25
          break;
Packit 67cb25
Packit 67cb25
        status = 
Packit 67cb25
          gsl_multiroot_test_residual (s->f, 1e-7);
Packit 67cb25
      }
Packit 67cb25
    while (status == GSL_CONTINUE && iter < 1000);
Packit 67cb25
Packit 67cb25
    printf ("status = %s\n", gsl_strerror (status));
Packit 67cb25
Packit 67cb25
    gsl_multiroot_fsolver_free (s);
Packit 67cb25
    gsl_vector_free (x);
Packit 67cb25
    return 0;
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
Note that it is important to check the return status of each solver
Packit 67cb25
step, in case the algorithm becomes stuck.  If an error condition is
Packit 67cb25
detected, indicating that the algorithm cannot proceed, then the error
Packit 67cb25
can be reported to the user, a new starting point chosen or a different
Packit 67cb25
algorithm used.
Packit 67cb25
Packit 67cb25
The intermediate state of the solution is displayed by the following
Packit 67cb25
function.  The solver state contains the vector :code:`s->x` which is the
Packit 67cb25
current position, and the vector :code:`s->f` with corresponding function
Packit 67cb25
values::
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  print_state (size_t iter, gsl_multiroot_fsolver * s)
Packit 67cb25
  {
Packit 67cb25
    printf ("iter = %3u x = % .3f % .3f "
Packit 67cb25
            "f(x) = % .3e % .3e\n",
Packit 67cb25
            iter,
Packit 67cb25
            gsl_vector_get (s->x, 0), 
Packit 67cb25
            gsl_vector_get (s->x, 1),
Packit 67cb25
            gsl_vector_get (s->f, 0), 
Packit 67cb25
            gsl_vector_get (s->f, 1));
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
Here are the results of running the program. The algorithm is started at
Packit 67cb25
:math:`(-10,-5)` far from the solution.  Since the solution is hidden in
Packit 67cb25
a narrow valley the earliest steps follow the gradient of the function
Packit 67cb25
downhill, in an attempt to reduce the large value of the residual. Once
Packit 67cb25
the root has been approximately located, on iteration 8, the Newton
Packit 67cb25
behavior takes over and convergence is very rapid::
Packit 67cb25
Packit 67cb25
  iter =  0 x = -10.000  -5.000  f(x) = 1.100e+01 -1.050e+03
Packit 67cb25
  iter =  1 x = -10.000  -5.000  f(x) = 1.100e+01 -1.050e+03
Packit 67cb25
  iter =  2 x =  -3.976  24.827  f(x) = 4.976e+00  9.020e+01
Packit 67cb25
  iter =  3 x =  -3.976  24.827  f(x) = 4.976e+00  9.020e+01
Packit 67cb25
  iter =  4 x =  -3.976  24.827  f(x) = 4.976e+00  9.020e+01
Packit 67cb25
  iter =  5 x =  -1.274  -5.680  f(x) = 2.274e+00 -7.302e+01
Packit 67cb25
  iter =  6 x =  -1.274  -5.680  f(x) = 2.274e+00 -7.302e+01
Packit 67cb25
  iter =  7 x =   0.249   0.298  f(x) = 7.511e-01  2.359e+00
Packit 67cb25
  iter =  8 x =   0.249   0.298  f(x) = 7.511e-01  2.359e+00
Packit 67cb25
  iter =  9 x =   1.000   0.878  f(x) = 1.268e-10 -1.218e+00
Packit 67cb25
  iter = 10 x =   1.000   0.989  f(x) = 1.124e-11 -1.080e-01
Packit 67cb25
  iter = 11 x =   1.000   1.000  f(x) = 0.000e+00  0.000e+00
Packit 67cb25
  status = success
Packit 67cb25
Packit 67cb25
Note that the algorithm does not update the location on every
Packit 67cb25
iteration. Some iterations are used to adjust the trust-region
Packit 67cb25
parameter, after trying a step which was found to be divergent, or to
Packit 67cb25
recompute the Jacobian, when poor convergence behavior is detected.
Packit 67cb25
Packit 67cb25
The next example program adds derivative information, in order to
Packit 67cb25
accelerate the solution. There are two derivative functions
Packit 67cb25
:code:`rosenbrock_df` and :code:`rosenbrock_fdf`. The latter computes both
Packit 67cb25
the function and its derivative simultaneously. This allows the
Packit 67cb25
optimization of any common terms.  For simplicity we substitute calls to
Packit 67cb25
the separate :code:`f` and :code:`df` functions at this point in the code
Packit 67cb25
below::
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  rosenbrock_df (const gsl_vector * x, void *params, 
Packit 67cb25
                 gsl_matrix * J)
Packit 67cb25
  {
Packit 67cb25
    const double a = ((struct rparams *) params)->a;
Packit 67cb25
    const double b = ((struct rparams *) params)->b;
Packit 67cb25
Packit 67cb25
    const double x0 = gsl_vector_get (x, 0);
Packit 67cb25
Packit 67cb25
    const double df00 = -a;
Packit 67cb25
    const double df01 = 0;
Packit 67cb25
    const double df10 = -2 * b  * x0;
Packit 67cb25
    const double df11 = b;
Packit 67cb25
Packit 67cb25
    gsl_matrix_set (J, 0, 0, df00);
Packit 67cb25
    gsl_matrix_set (J, 0, 1, df01);
Packit 67cb25
    gsl_matrix_set (J, 1, 0, df10);
Packit 67cb25
    gsl_matrix_set (J, 1, 1, df11);
Packit 67cb25
Packit 67cb25
    return GSL_SUCCESS;
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  rosenbrock_fdf (const gsl_vector * x, void *params,
Packit 67cb25
                  gsl_vector * f, gsl_matrix * J)
Packit 67cb25
  {
Packit 67cb25
    rosenbrock_f (x, params, f);
Packit 67cb25
    rosenbrock_df (x, params, J);
Packit 67cb25
Packit 67cb25
    return GSL_SUCCESS;
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
The main program now makes calls to the corresponding :code:`fdfsolver`
Packit 67cb25
versions of the functions::
Packit 67cb25
Packit 67cb25
  int
Packit 67cb25
  main (void)
Packit 67cb25
  {
Packit 67cb25
    const gsl_multiroot_fdfsolver_type *T;
Packit 67cb25
    gsl_multiroot_fdfsolver *s;
Packit 67cb25
Packit 67cb25
    int status;
Packit 67cb25
    size_t i, iter = 0;
Packit 67cb25
Packit 67cb25
    const size_t n = 2;
Packit 67cb25
    struct rparams p = {1.0, 10.0};
Packit 67cb25
    gsl_multiroot_function_fdf f = {&rosenbrock_f, 
Packit 67cb25
                                    &rosenbrock_df, 
Packit 67cb25
                                    &rosenbrock_fdf, 
Packit 67cb25
                                    n, &p};
Packit 67cb25
Packit 67cb25
    double x_init[2] = {-10.0, -5.0};
Packit 67cb25
    gsl_vector *x = gsl_vector_alloc (n);
Packit 67cb25
Packit 67cb25
    gsl_vector_set (x, 0, x_init[0]);
Packit 67cb25
    gsl_vector_set (x, 1, x_init[1]);
Packit 67cb25
Packit 67cb25
    T = gsl_multiroot_fdfsolver_gnewton;
Packit 67cb25
    s = gsl_multiroot_fdfsolver_alloc (T, n);
Packit 67cb25
    gsl_multiroot_fdfsolver_set (s, &f, x);
Packit 67cb25
Packit 67cb25
    print_state (iter, s);
Packit 67cb25
Packit 67cb25
    do
Packit 67cb25
      {
Packit 67cb25
        iter++;
Packit 67cb25
Packit 67cb25
        status = gsl_multiroot_fdfsolver_iterate (s);
Packit 67cb25
Packit 67cb25
        print_state (iter, s);
Packit 67cb25
Packit 67cb25
        if (status)
Packit 67cb25
          break;
Packit 67cb25
Packit 67cb25
        status = gsl_multiroot_test_residual (s->f, 1e-7);
Packit 67cb25
      }
Packit 67cb25
    while (status == GSL_CONTINUE && iter < 1000);
Packit 67cb25
Packit 67cb25
    printf ("status = %s\n", gsl_strerror (status));
Packit 67cb25
Packit 67cb25
    gsl_multiroot_fdfsolver_free (s);
Packit 67cb25
    gsl_vector_free (x);
Packit 67cb25
    return 0;
Packit 67cb25
  }
Packit 67cb25
Packit 67cb25
The addition of derivative information to the :data:`gsl_multiroot_fsolver_hybrids` solver does
Packit 67cb25
not make any significant difference to its behavior, since it able to
Packit 67cb25
approximate the Jacobian numerically with sufficient accuracy.  To
Packit 67cb25
illustrate the behavior of a different derivative solver we switch to
Packit 67cb25
:data:`gsl_multiroot_fdfsolver_gnewton`. This is a traditional Newton solver with the constraint
Packit 67cb25
that it scales back its step if the full step would lead "uphill". Here
Packit 67cb25
is the output for the :data:`gsl_multiroot_fdfsolver_gnewton` algorithm::
Packit 67cb25
Packit 67cb25
  iter = 0 x = -10.000  -5.000 f(x) =  1.100e+01 -1.050e+03
Packit 67cb25
  iter = 1 x =  -4.231 -65.317 f(x) =  5.231e+00 -8.321e+02
Packit 67cb25
  iter = 2 x =   1.000 -26.358 f(x) = -8.882e-16 -2.736e+02
Packit 67cb25
  iter = 3 x =   1.000   1.000 f(x) = -2.220e-16 -4.441e-15
Packit 67cb25
  status = success
Packit 67cb25
Packit 67cb25
The convergence is much more rapid, but takes a wide excursion out to
Packit 67cb25
the point :math:`(-4.23,-65.3)`. This could cause the algorithm to go
Packit 67cb25
astray in a realistic application.  The hybrid algorithm follows the
Packit 67cb25
downhill path to the solution more reliably.
Packit 67cb25
Packit 67cb25
References and Further Reading
Packit 67cb25
==============================
Packit 67cb25
Packit 67cb25
The original version of the Hybrid method is described in the following
Packit 67cb25
articles by Powell,
Packit 67cb25
Packit 67cb25
* M.J.D. Powell, "A Hybrid Method for Nonlinear Equations" (Chap 6, p
Packit 67cb25
  87--114) and "A Fortran Subroutine for Solving systems of Nonlinear
Packit 67cb25
  Algebraic Equations" (Chap 7, p 115--161), in *Numerical Methods for
Packit 67cb25
  Nonlinear Algebraic Equations*, P. Rabinowitz, editor.  Gordon and
Packit 67cb25
  Breach, 1970.
Packit 67cb25
Packit 67cb25
The following papers are also relevant to the algorithms described in
Packit 67cb25
this section,
Packit 67cb25
Packit 67cb25
* J.J. |More|, M.Y. Cosnard, "Numerical Solution of Nonlinear Equations",
Packit 67cb25
  *ACM Transactions on Mathematical Software*, Vol 5, No 1, (1979), p 64--85
Packit 67cb25
Packit 67cb25
* C.G. Broyden, "A Class of Methods for Solving Nonlinear
Packit 67cb25
  Simultaneous Equations", *Mathematics of Computation*, Vol 19 (1965),
Packit 67cb25
  p 577--593
Packit 67cb25
Packit 67cb25
* J.J. |More|, B.S. Garbow, K.E. Hillstrom, "Testing Unconstrained
Packit 67cb25
  Optimization Software", ACM Transactions on Mathematical Software, Vol
Packit 67cb25
  7, No 1 (1981), p 17--41