gsl_multimin__linear_wrapper.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. typedef struct
  2. {
  3. gsl_function_fdf fdf_linear;
  4. gsl_multimin_function_fdf *fdf;
  5. /* fixed values */
  6. const gsl_vector *x;
  7. const gsl_vector *g;
  8. const gsl_vector *p;
  9. /* cached values, for x(alpha) = x + alpha * p */
  10. double f_alpha;
  11. double df_alpha;
  12. gsl_vector *x_alpha;
  13. gsl_vector *g_alpha;
  14. /* cache "keys" */
  15. double f_cache_key;
  16. double df_cache_key;
  17. double x_cache_key;
  18. double g_cache_key;
  19. }
  20. wrapper_t;
  21. static void
  22. moveto (double alpha, wrapper_t * w)
  23. {
  24. if (alpha == w->x_cache_key) /* using previously cached position */
  25. {
  26. return;
  27. }
  28. /* set x_alpha = x + alpha * p */
  29. gsl_vector_memcpy (w->x_alpha, w->x);
  30. gsl_blas_daxpy (alpha, w->p, w->x_alpha);
  31. w->x_cache_key = alpha;
  32. }
  33. static double
  34. slope (wrapper_t * w) /* compute gradient . direction */
  35. {
  36. double df;
  37. gsl_blas_ddot (w->g_alpha, w->p, &df);
  38. return df;
  39. }
  40. static double
  41. wrap_f (double alpha, void *params)
  42. {
  43. wrapper_t *w = (wrapper_t *) params;
  44. if (alpha == w->f_cache_key) /* using previously cached f(alpha) */
  45. {
  46. return w->f_alpha;
  47. }
  48. moveto (alpha, w);
  49. w->f_alpha = GSL_MULTIMIN_FN_EVAL_F (w->fdf, w->x_alpha);
  50. w->f_cache_key = alpha;
  51. return w->f_alpha;
  52. }
  53. static double
  54. wrap_df (double alpha, void *params)
  55. {
  56. wrapper_t *w = (wrapper_t *) params;
  57. if (alpha == w->df_cache_key) /* using previously cached df(alpha) */
  58. {
  59. return w->df_alpha;
  60. }
  61. moveto (alpha, w);
  62. if (alpha != w->g_cache_key)
  63. {
  64. GSL_MULTIMIN_FN_EVAL_DF (w->fdf, w->x_alpha, w->g_alpha);
  65. w->g_cache_key = alpha;
  66. }
  67. w->df_alpha = slope (w);
  68. w->df_cache_key = alpha;
  69. return w->df_alpha;
  70. }
  71. static void
  72. wrap_fdf (double alpha, void *params, double *f, double *df)
  73. {
  74. wrapper_t *w = (wrapper_t *) params;
  75. /* Check for previously cached values */
  76. if (alpha == w->f_cache_key && alpha == w->df_cache_key)
  77. {
  78. *f = w->f_alpha;
  79. *df = w->df_alpha;
  80. return;
  81. }
  82. if (alpha == w->f_cache_key || alpha == w->df_cache_key)
  83. {
  84. *f = wrap_f (alpha, params);
  85. *df = wrap_df (alpha, params);
  86. return;
  87. }
  88. moveto (alpha, w);
  89. GSL_MULTIMIN_FN_EVAL_F_DF (w->fdf, w->x_alpha, &w->f_alpha, w->g_alpha);
  90. w->f_cache_key = alpha;
  91. w->g_cache_key = alpha;
  92. w->df_alpha = slope (w);
  93. w->df_cache_key = alpha;
  94. *f = w->f_alpha;
  95. *df = w->df_alpha;
  96. }
  97. static void
  98. prepare_wrapper (wrapper_t * w, gsl_multimin_function_fdf * fdf,
  99. const gsl_vector * x, double f, const gsl_vector *g,
  100. const gsl_vector * p,
  101. gsl_vector * x_alpha, gsl_vector *g_alpha)
  102. {
  103. w->fdf_linear.f = &wrap_f;
  104. w->fdf_linear.df = &wrap_df;
  105. w->fdf_linear.fdf = &wrap_fdf;
  106. w->fdf_linear.params = (void *)w; /* pointer to "self" */
  107. w->fdf = fdf;
  108. w->x = x;
  109. w->g = g;
  110. w->p = p;
  111. w->x_alpha = x_alpha;
  112. w->g_alpha = g_alpha;
  113. gsl_vector_memcpy(w->x_alpha, w->x);
  114. w->x_cache_key = 0.0;
  115. w->f_alpha = f;
  116. w->f_cache_key = 0.0;
  117. gsl_vector_memcpy(w->g_alpha, w->g);
  118. w->g_cache_key = 0.0;
  119. w->df_alpha = slope(w);
  120. w->df_cache_key = 0.0;
  121. }
  122. static void
  123. update_position (wrapper_t * w, double alpha, gsl_vector *x, double *f, gsl_vector *g)
  124. {
  125. /* ensure that everything is fully cached */
  126. { double f_alpha, df_alpha; wrap_fdf (alpha, w, &f_alpha, &df_alpha); } ;
  127. *f = w->f_alpha;
  128. gsl_vector_memcpy(x, w->x_alpha);
  129. gsl_vector_memcpy(g, w->g_alpha);
  130. }
  131. static void
  132. change_direction (wrapper_t * w)
  133. {
  134. /* Convert the cache values from the end of the current minimisation
  135. to those needed for the start of the next minimisation, alpha=0 */
  136. /* The new x_alpha for alpha=0 is the current position */
  137. gsl_vector_memcpy (w->x_alpha, w->x);
  138. w->x_cache_key = 0.0;
  139. /* The function value does not change */
  140. w->f_cache_key = 0.0;
  141. /* The new g_alpha for alpha=0 is the current gradient at the endpoint */
  142. gsl_vector_memcpy (w->g_alpha, w->g);
  143. w->g_cache_key = 0.0;
  144. /* Calculate the slope along the new direction vector, p */
  145. w->df_alpha = slope (w);
  146. w->df_cache_key = 0.0;
  147. }