1 /* multiroots/broyden.c
3 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include <gsl/gsl_math.h>
29 #include <gsl/gsl_errno.h>
30 #include <gsl/gsl_multiroots.h>
31 #include <gsl/gsl_linalg.h>
35 /* Broyden's method. It is not an efficient or modern algorithm but
36 gives an example of a rank-1 update.
38 C.G. Broyden, "A Class of Methods for Solving Nonlinear
39 Simultaneous Equations", Mathematics of Computation, vol 19 (1965),
48 gsl_permutation *permutation;
59 static int broyden_alloc (void *vstate, size_t n);
60 static int broyden_set (void *vstate, gsl_multiroot_function * function, gsl_vector * x, gsl_vector * f, gsl_vector * dx);
61 static int broyden_iterate (void *vstate, gsl_multiroot_function * function, gsl_vector * x, gsl_vector * f, gsl_vector * dx);
62 static void broyden_free (void *vstate);
66 broyden_alloc (void *vstate, size_t n)
68 broyden_state_t *state = (broyden_state_t *) vstate;
69 gsl_vector *v, *w, *y, *fnew, *x_trial, *p;
70 gsl_permutation *perm;
73 m = gsl_matrix_calloc (n, n);
77 GSL_ERROR ("failed to allocate space for lu", GSL_ENOMEM);
82 perm = gsl_permutation_calloc (n);
88 GSL_ERROR ("failed to allocate space for permutation", GSL_ENOMEM);
91 state->permutation = perm;
93 H = gsl_matrix_calloc (n, n);
97 gsl_permutation_free (perm);
100 GSL_ERROR ("failed to allocate space for d", GSL_ENOMEM);
105 v = gsl_vector_calloc (n);
110 gsl_permutation_free (perm);
113 GSL_ERROR ("failed to allocate space for v", GSL_ENOMEM);
118 w = gsl_vector_calloc (n);
124 gsl_permutation_free (perm);
127 GSL_ERROR ("failed to allocate space for w", GSL_ENOMEM);
132 y = gsl_vector_calloc (n);
139 gsl_permutation_free (perm);
142 GSL_ERROR ("failed to allocate space for y", GSL_ENOMEM);
147 fnew = gsl_vector_calloc (n);
155 gsl_permutation_free (perm);
158 GSL_ERROR ("failed to allocate space for fnew", GSL_ENOMEM);
163 x_trial = gsl_vector_calloc (n);
167 gsl_vector_free (fnew);
172 gsl_permutation_free (perm);
175 GSL_ERROR ("failed to allocate space for x_trial", GSL_ENOMEM);
178 state->x_trial = x_trial;
180 p = gsl_vector_calloc (n);
184 gsl_vector_free (x_trial);
185 gsl_vector_free (fnew);
190 gsl_permutation_free (perm);
193 GSL_ERROR ("failed to allocate space for p", GSL_ENOMEM);
202 broyden_set (void *vstate, gsl_multiroot_function * function, gsl_vector * x, gsl_vector * f, gsl_vector * dx)
204 broyden_state_t *state = (broyden_state_t *) vstate;
205 size_t i, j, n = function->n;
208 GSL_MULTIROOT_FN_EVAL (function, x, f);
210 gsl_multiroot_fdjacobian (function, x, f, GSL_SQRT_DBL_EPSILON, state->lu);
211 gsl_linalg_LU_decomp (state->lu, state->permutation, &signum);
212 gsl_linalg_LU_invert (state->lu, state->permutation, state->H);
214 for (i = 0; i < n; i++)
215 for (j = 0; j < n; j++)
216 gsl_matrix_set(state->H,i,j,-gsl_matrix_get(state->H,i,j));
218 for (i = 0; i < n; i++)
220 gsl_vector_set (dx, i, 0.0);
223 state->phi = enorm (f);
229 broyden_iterate (void *vstate, gsl_multiroot_function * function, gsl_vector * x, gsl_vector * f, gsl_vector * dx)
231 broyden_state_t *state = (broyden_state_t *) vstate;
233 double phi0, phi1, t, lambda;
235 gsl_matrix *H = state->H;
236 gsl_vector *p = state->p;
237 gsl_vector *y = state->y;
238 gsl_vector *v = state->v;
239 gsl_vector *w = state->w;
240 gsl_vector *fnew = state->fnew;
241 gsl_vector *x_trial = state->x_trial;
242 gsl_matrix *lu = state->lu;
243 gsl_permutation *perm = state->permutation;
247 size_t n = function->n;
251 for (i = 0; i < n; i++)
255 for (j = 0; j < n; j++)
257 sum += gsl_matrix_get (H, i, j) * gsl_vector_get (f, j);
259 gsl_vector_set (p, i, sum);
269 for (i = 0; i < n; i++)
271 double pi = gsl_vector_get (p, i);
272 double xi = gsl_vector_get (x, i);
273 gsl_vector_set (x_trial, i, xi + t * pi);
277 int status = GSL_MULTIROOT_FN_EVAL (function, x_trial, fnew);
279 if (status != GSL_SUCCESS)
289 if (phi1 > phi0 && iter < 10 && t > 0.1)
291 /* full step goes uphill, take a reduced step instead */
293 double theta = phi1 / phi0;
294 t *= (sqrt (1.0 + 6.0 * theta) - 1.0) / (3.0 * theta);
300 /* need to recompute Jacobian */
303 gsl_multiroot_fdjacobian (function, x, f, GSL_SQRT_DBL_EPSILON, lu);
305 for (i = 0; i < n; i++)
306 for (j = 0; j < n; j++)
307 gsl_matrix_set(lu,i,j,-gsl_matrix_get(lu,i,j));
309 gsl_linalg_LU_decomp (lu, perm, &signum);
310 gsl_linalg_LU_invert (lu, perm, H);
312 gsl_linalg_LU_solve (lu, perm, f, p);
316 for (i = 0; i < n; i++)
318 double pi = gsl_vector_get (p, i);
319 double xi = gsl_vector_get (x, i);
320 gsl_vector_set (x_trial, i, xi + t * pi);
324 int status = GSL_MULTIROOT_FN_EVAL (function, x_trial, fnew);
326 if (status != GSL_SUCCESS)
337 for (i = 0; i < n; i++)
339 double yi = gsl_vector_get (fnew, i) - gsl_vector_get (f, i);
340 gsl_vector_set (y, i, yi);
345 for (i = 0; i < n; i++)
349 for (j = 0; j < n; j++)
351 sum += gsl_matrix_get (H, i, j) * gsl_vector_get (y, j);
354 gsl_vector_set (v, i, sum);
361 for (i = 0; i < n; i++)
363 lambda += gsl_vector_get (p, i) * gsl_vector_get (v, i);
368 GSL_ERROR ("approximation to Jacobian has collapsed", GSL_EZERODIV) ;
373 for (i = 0; i < n; i++)
375 double vi = gsl_vector_get (v, i) + t * gsl_vector_get (p, i);
376 gsl_vector_set (v, i, vi);
381 for (i = 0; i < n; i++)
385 for (j = 0; j < n; j++)
387 sum += gsl_matrix_get (H, j, i) * gsl_vector_get (p, j);
390 gsl_vector_set (w, i, sum);
393 /* Hij -> Hij - (vi wj / lambda) */
395 for (i = 0; i < n; i++)
397 double vi = gsl_vector_get (v, i);
399 for (j = 0; j < n; j++)
401 double wj = gsl_vector_get (w, j);
402 double Hij = gsl_matrix_get (H, i, j) - vi * wj / lambda;
403 gsl_matrix_set (H, i, j, Hij);
407 /* copy fnew into f */
409 gsl_vector_memcpy (f, fnew);
411 /* copy x_trial into x */
413 gsl_vector_memcpy (x, x_trial);
415 for (i = 0; i < n; i++)
417 double pi = gsl_vector_get (p, i);
418 gsl_vector_set (dx, i, t * pi);
428 broyden_free (void *vstate)
430 broyden_state_t *state = (broyden_state_t *) vstate;
432 gsl_matrix_free (state->H);
434 gsl_matrix_free (state->lu);
435 gsl_permutation_free (state->permutation);
437 gsl_vector_free (state->v);
438 gsl_vector_free (state->w);
439 gsl_vector_free (state->y);
440 gsl_vector_free (state->p);
442 gsl_vector_free (state->fnew);
443 gsl_vector_free (state->x_trial);
448 static const gsl_multiroot_fsolver_type broyden_type =
449 {"broyden", /* name */
450 sizeof (broyden_state_t),
456 const gsl_multiroot_fsolver_type *gsl_multiroot_fsolver_broyden = &broyden_type;