PageRenderTime 30ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/math/minimizer_low.c

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