Octopus
minimizer_low.c
Go to the documentation of this file.
1/*
2 Copyright (C) 2002 M. Marques, A. Castro, A. Rubio, G. Bertsch, M. Oliveira
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18
19*/
20
21#include <config.h>
22#include <gsl/gsl_errno.h>
23#include <gsl/gsl_math.h>
24#include <gsl/gsl_min.h>
25#include <gsl/gsl_multimin.h>
26#include <math.h>
27#include <stdio.h>
28#include <stdlib.h>
29
30#include "string_f.h"
31
32/* A. First, the interface to the gsl function that calculates the minimum
33 of an N-dimensional function, with the knowledge of the function itself
34 and its gradient. */
35
36/* This is a type used to communicate with Fortran; func_d is the type of the
37 interface to a Fortran subroutine that calculates the function and its
38 gradient. */
39typedef void (*func_d)(const int *, const double *, double *, const int *,
40 double *);
41typedef struct {
42 func_d func;
43} param_fdf_t;
44
45/* Compute both f and df together. */
46static void my_fdf(const gsl_vector *v, void *params, double *f,
47 gsl_vector *df) {
48 double *x, *gradient, ff2;
49 int i, dim, getgrad;
50 param_fdf_t *p;
51
52 p = (param_fdf_t *)params;
53
54 dim = v->size;
55 x = (double *)malloc(dim * sizeof(double));
56 gradient = (double *)malloc(dim * sizeof(double));
57
58 for (i = 0; i < dim; i++)
59 x[i] = gsl_vector_get(v, i);
60 getgrad = (df == NULL) ? 0 : 1;
61
62 p->func(&dim, x, &ff2, &getgrad, gradient);
63
64 if (f != NULL)
65 *f = ff2;
66
67 if (df != NULL) {
68 for (i = 0; i < dim; i++)
69 gsl_vector_set(df, i, gradient[i]);
70 }
71
72 free(x);
73 free(gradient);
74}
75
76static double my_f(const gsl_vector *v, void *params) {
77 double val;
78
79 my_fdf(v, params, &val, NULL);
80 return val;
81}
82
83/* The gradient of f, df = (df/dx, df/dy). */
84static void my_df(const gsl_vector *v, void *params, gsl_vector *df) {
85 my_fdf(v, params, NULL, df);
86}
87
88typedef void (*print_f_ptr)(const int *, const int *, const double *,
89 const double *, const double *, const double *);
90
91int FC_FUNC_(oct_minimize,
92 OCT_MINIMIZE)(const int *method, const int *dim, double *point,
93 const double *step, const double *line_tol,
94 const double *tolgrad, const double *toldr,
95 const int *maxiter, func_d f,
96 const print_f_ptr write_info, double *minimum) {
97 int iter = 0;
98 int status;
99 double maxgrad, maxdr;
100 int i;
101 double *oldpoint;
102 double *grad;
103
104 const gsl_multimin_fdfminimizer_type *T = NULL;
105 gsl_multimin_fdfminimizer *s;
106 gsl_vector *x;
107 gsl_vector *absgrad, *absdr;
108 gsl_multimin_function_fdf my_func;
109
110 param_fdf_t p;
111
112 p.func = f;
113
114 oldpoint = (double *)malloc(*dim * sizeof(double));
115 grad = (double *)malloc(*dim * sizeof(double));
116
117 my_func.f = &my_f;
118 my_func.df = &my_df;
119 my_func.fdf = &my_fdf;
120 my_func.n = *dim;
121 my_func.params = (void *)&p;
122
123 /* Starting point */
124 x = gsl_vector_alloc(*dim);
125 for (i = 0; i < *dim; i++)
126 gsl_vector_set(x, i, point[i]);
127
128 /* Allocate space for the gradient */
129 absgrad = gsl_vector_alloc(*dim);
130 absdr = gsl_vector_alloc(*dim);
131
132 // GSL recommends line_tol = 0.1;
133 switch (*method) {
134 case 1:
135 T = gsl_multimin_fdfminimizer_steepest_descent;
136 break;
137 case 2:
138 T = gsl_multimin_fdfminimizer_conjugate_fr;
139 break;
140 case 3:
141 T = gsl_multimin_fdfminimizer_conjugate_pr;
142 break;
143 case 4:
144 T = gsl_multimin_fdfminimizer_vector_bfgs;
145 break;
146 case 5:
147 T = gsl_multimin_fdfminimizer_vector_bfgs2;
148 break;
149 }
150
151 s = gsl_multimin_fdfminimizer_alloc(T, *dim);
152
153 gsl_multimin_fdfminimizer_set(s, &my_func, x, *step, *line_tol);
154 do {
155 iter++;
156 for (i = 0; i < *dim; i++)
157 oldpoint[i] = point[i];
158
159 /* Iterate */
160 status = gsl_multimin_fdfminimizer_iterate(s);
161
162 /* Get current minimum, point and gradient */
163 *minimum = gsl_multimin_fdfminimizer_minimum(s);
164 for (i = 0; i < *dim; i++)
165 point[i] = gsl_vector_get(gsl_multimin_fdfminimizer_x(s), i);
166 for (i = 0; i < *dim; i++)
167 grad[i] = gsl_vector_get(gsl_multimin_fdfminimizer_gradient(s), i);
168
169 /* Compute convergence criteria */
170 for (i = 0; i < *dim; i++)
171 gsl_vector_set(absdr, i, fabs(point[i] - oldpoint[i]));
172 maxdr = gsl_vector_max(absdr);
173 for (i = 0; i < *dim; i++)
174 gsl_vector_set(absgrad, i, fabs(grad[i]));
175 maxgrad = gsl_vector_max(absgrad);
176
177 /* Print information */
178 write_info(&iter, dim, minimum, &maxdr, &maxgrad, point);
179
180 /* Store infomation for next iteration */
181 for (i = 0; i < *dim; i++)
182 oldpoint[i] = point[i];
183
184 if (status)
185 break;
186
187 if ((maxgrad <= *tolgrad) || (maxdr <= *toldr))
188 status = GSL_SUCCESS;
189 else
190 status = GSL_CONTINUE;
191 } while (status == GSL_CONTINUE && iter <= *maxiter);
192
193 if (status == GSL_CONTINUE)
194 status = 1025;
195
196 gsl_multimin_fdfminimizer_free(s);
197 gsl_vector_free(x);
198 gsl_vector_free(absgrad);
199 gsl_vector_free(absdr);
200
201 free(oldpoint);
202 free(grad);
203
204 return status;
205}
206
207/* B. Second, the interface to the gsl function that calculates the minimum
208 of a one-dimensional function, with the knowledge of the function itself,
209 but not its gradient. */
210
211/* This is a type used to communicate with Fortran; func1 is the type of the
212 interface to a Fortran subroutine that calculates the function and its
213 gradient. */
214typedef void (*func1)(const double *, double *);
215typedef struct {
216 func1 func;
217} param_f1_t;
218
219double fn1(double x, void *params) {
220 param_f1_t *p = (param_f1_t *)params;
221 double fx;
222 p->func(&x, &fx);
223 return fx;
224}
225
226void FC_FUNC_(oct_1dminimize, OCT_1DMINIMIZE)(double *a, double *b, double *m,
227 func1 f, int *status) {
228 int iter = 0;
229 int max_iter = 100;
230 const gsl_min_fminimizer_type *T;
231 gsl_min_fminimizer *s;
232 gsl_function F;
233 param_f1_t p;
234
235 p.func = f;
236
237 F.function = &fn1;
238 F.params = (void *)&p;
239
240 T = gsl_min_fminimizer_brent;
241 s = gsl_min_fminimizer_alloc(T);
242
243 *status = gsl_min_fminimizer_set(s, &F, *m, *a, *b);
244
245 gsl_set_error_handler_off();
246
247 do {
248 iter++;
249 *status = gsl_min_fminimizer_iterate(s);
250
251 *m = gsl_min_fminimizer_x_minimum(s);
252 *a = gsl_min_fminimizer_x_lower(s);
253 *b = gsl_min_fminimizer_x_upper(s);
254
255 *status = gsl_min_test_interval(*a, *b, 0.00001, 0.0);
256
257 /*if (*status == GSL_SUCCESS) printf ("Converged:\n");*/
258 /*printf ("%5d [%.7f, %.7f] %.7f \n", iter, *a, *b,*m);*/
259 } while (*status == GSL_CONTINUE && iter < max_iter);
260 gsl_min_fminimizer_free(s);
261}
262
263/* C. Third, the interface to the gsl function that calculates the minimum
264 of an N-dimensional function, with the knowledge of the function itself,
265 but not its gradient. */
266
267/* This is a type used to communicate with Fortran; funcn is the type of the
268 interface to a Fortran subroutine that calculates the function and its
269 gradient. */
270typedef void (*funcn)(int *, double *, double *);
271typedef struct {
272 funcn func;
273} param_fn_t;
274
275double fn(const gsl_vector *v, void *params) {
276 double val;
277 double *x;
278 int i, dim;
279 param_fn_t *p;
280
281 p = (param_fn_t *)params;
282 dim = v->size;
283 x = (double *)malloc(dim * sizeof(double));
284
285 for (i = 0; i < dim; i++)
286 x[i] = gsl_vector_get(v, i);
287 p->func(&dim, x, &val);
288
289 free(x);
290 return val;
291}
292
293typedef void (*print_f_fn_ptr)(const int *, const int *, const double *,
294 const double *, const double *);
295
296int FC_FUNC_(oct_minimize_direct,
297 OCT_MINIMIZE_DIRECT)(const int *method, const int *dim,
298 double *point, const double *step,
299 const double *toldr, const int *maxiter,
300 funcn f, const print_f_fn_ptr write_info,
301 double *minimum) {
302 int iter = 0, status, i;
303 double size;
304
305 const gsl_multimin_fminimizer_type *T = NULL;
306 gsl_multimin_fminimizer *s = NULL;
307 gsl_vector *x, *ss;
308 gsl_multimin_function my_func;
309
310 param_fn_t p;
311 p.func = f;
312
313 my_func.f = &fn;
314 my_func.n = *dim;
315 my_func.params = (void *)&p;
316
317 /* Set the initial vertex size vector */
318 ss = gsl_vector_alloc(*dim);
319 gsl_vector_set_all(ss, *step);
320
321 /* Starting point */
322 x = gsl_vector_alloc(*dim);
323 for (i = 0; i < *dim; i++)
324 gsl_vector_set(x, i, point[i]);
325
326 switch (*method) {
327 case 6:
328 T = gsl_multimin_fminimizer_nmsimplex;
329 break;
330 }
331
332 s = gsl_multimin_fminimizer_alloc(T, *dim);
333 gsl_multimin_fminimizer_set(s, &my_func, x, ss);
334
335 do {
336 iter++;
337 status = gsl_multimin_fminimizer_iterate(s);
338
339 if (status)
340 break;
341
342 *minimum = gsl_multimin_fminimizer_minimum(s);
343 for (i = 0; i < *dim; i++)
344 point[i] = gsl_vector_get(gsl_multimin_fminimizer_x(s), i);
345
346 size = gsl_multimin_fminimizer_size(s);
347 status = gsl_multimin_test_size(size, *toldr);
348
349 write_info(&iter, dim, minimum, &size, point);
350
351 } while (status == GSL_CONTINUE && iter < *maxiter);
352
353 if (status == GSL_CONTINUE)
354 status = 1025;
355
356 gsl_vector_free(x);
357 gsl_vector_free(ss);
358 gsl_multimin_fminimizer_free(s);
359 return status;
360}
double fabs(double __x) __attribute__((__nothrow__
real(real64) function func(r1, rn, n, a)
Definition: logrid.F90:355
integer, parameter, public minimum
integer, public maxiter
Definition: poisson_cg.F90:137
real(real64) function s()
ptrdiff_t i
Definition: operate_inc.c:12