gsl_multimin__linear_minimize.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include "gsl_math.h"
  2. #include "gsl_errno.h"
  3. #include "gsl_poly.h"
  4. /* Find a minimum in x=[0,1] of the interpolating quadratic through
  5. * (0,f0) (1,f1) with derivative fp0 at x=0. The interpolating
  6. * polynomial is q(x) = f0 + fp0 * z + (f1-f0-fp0) * z^2
  7. */
  8. static double
  9. interp_quad (double f0, double fp0, double f1, double zl, double zh)
  10. {
  11. double fl = f0 + zl*(fp0 + zl*(f1 - f0 -fp0));
  12. double fh = f0 + zh*(fp0 + zh*(f1 - f0 -fp0));
  13. double c = 2 * (f1 - f0 - fp0); /* curvature */
  14. double zmin = zl, fmin = fl;
  15. if (fh < fmin) { zmin = zh; fmin = fh; }
  16. if (c > 0) /* positive curvature required for a minimum */
  17. {
  18. double z = -fp0 / c; /* location of minimum */
  19. if (z > zl && z < zh) {
  20. double f = f0 + z*(fp0 + z*(f1 - f0 -fp0));
  21. if (f < fmin) { zmin = z; fmin = f; };
  22. }
  23. }
  24. return zmin;
  25. }
  26. /* Find a minimum in x=[0,1] of the interpolating cubic through
  27. * (0,f0) (1,f1) with derivatives fp0 at x=0 and fp1 at x=1.
  28. *
  29. * The interpolating polynomial is:
  30. *
  31. * c(x) = f0 + fp0 * z + eta * z^2 + xi * z^3
  32. *
  33. * where eta=3*(f1-f0)-2*fp0-fp1, xi=fp0+fp1-2*(f1-f0).
  34. */
  35. static double
  36. cubic (double c0, double c1, double c2, double c3, double z)
  37. {
  38. return c0 + z * (c1 + z * (c2 + z * c3));
  39. }
  40. static void
  41. check_extremum (double c0, double c1, double c2, double c3, double z,
  42. double *zmin, double *fmin)
  43. {
  44. /* could make an early return by testing curvature >0 for minimum */
  45. double y = cubic (c0, c1, c2, c3, z);
  46. if (y < *fmin)
  47. {
  48. *zmin = z; /* accepted new point*/
  49. *fmin = y;
  50. }
  51. }
  52. static double
  53. interp_cubic (double f0, double fp0, double f1, double fp1, double zl, double zh)
  54. {
  55. double eta = 3 * (f1 - f0) - 2 * fp0 - fp1;
  56. double xi = fp0 + fp1 - 2 * (f1 - f0);
  57. double c0 = f0, c1 = fp0, c2 = eta, c3 = xi;
  58. double zmin, fmin;
  59. double z0, z1;
  60. zmin = zl; fmin = cubic(c0, c1, c2, c3, zl);
  61. check_extremum (c0, c1, c2, c3, zh, &zmin, &fmin);
  62. {
  63. int n = gsl_poly_solve_quadratic (3 * c3, 2 * c2, c1, &z0, &z1);
  64. if (n == 2) /* found 2 roots */
  65. {
  66. if (z0 > zl && z0 < zh)
  67. check_extremum (c0, c1, c2, c3, z0, &zmin, &fmin);
  68. if (z1 > zl && z1 < zh)
  69. check_extremum (c0, c1, c2, c3, z1, &zmin, &fmin);
  70. }
  71. else if (n == 1) /* found 1 root */
  72. {
  73. if (z0 > zl && z0 < zh)
  74. check_extremum (c0, c1, c2, c3, z0, &zmin, &fmin);
  75. }
  76. }
  77. return zmin;
  78. }
  79. static double
  80. interpolate (double a, double fa, double fpa,
  81. double b, double fb, double fpb, double xmin, double xmax,
  82. int order)
  83. {
  84. /* Map [a,b] to [0,1] */
  85. double z, alpha, zmin, zmax;
  86. zmin = (xmin - a) / (b - a);
  87. zmax = (xmax - a) / (b - a);
  88. if (zmin > zmax)
  89. {
  90. double tmp = zmin;
  91. zmin = zmax;
  92. zmax = tmp;
  93. };
  94. if (order > 2 && GSL_IS_REAL(fpb)) {
  95. z = interp_cubic (fa, fpa * (b - a), fb, fpb * (b - a), zmin, zmax);
  96. } else {
  97. z = interp_quad (fa, fpa * (b - a), fb, zmin, zmax);
  98. }
  99. alpha = a + z * (b - a);
  100. return alpha;
  101. }
  102. /* recommended values from Fletcher are
  103. rho = 0.01, sigma = 0.1, tau1 = 9, tau2 = 0.05, tau3 = 0.5 */
  104. static int
  105. minimize (gsl_function_fdf * fn, double rho, double sigma,
  106. double tau1, double tau2, double tau3,
  107. int order, double alpha1, double *alpha_new)
  108. {
  109. double f0, fp0, falpha, falpha_prev, fpalpha, fpalpha_prev, delta,
  110. alpha_next;
  111. double alpha = alpha1, alpha_prev = 0.0;
  112. double a, b, fa, fb, fpa, fpb;
  113. const size_t bracket_iters = 100, section_iters = 100;
  114. size_t i = 0;
  115. GSL_FN_FDF_EVAL_F_DF (fn, 0.0, &f0, &fp0);
  116. falpha_prev = f0;
  117. fpalpha_prev = fp0;
  118. /* Avoid uninitialized variables morning */
  119. a = 0.0; b = alpha;
  120. fa = f0; fb = 0.0;
  121. fpa = fp0; fpb = 0.0;
  122. /* Begin bracketing */
  123. while (i++ < bracket_iters)
  124. {
  125. falpha = GSL_FN_FDF_EVAL_F (fn, alpha);
  126. /* Fletcher's rho test */
  127. if (falpha > f0 + alpha * rho * fp0 || falpha >= falpha_prev)
  128. {
  129. a = alpha_prev; fa = falpha_prev; fpa = fpalpha_prev;
  130. b = alpha; fb = falpha; fpb = GSL_NAN;
  131. break; /* goto sectioning */
  132. }
  133. fpalpha = GSL_FN_FDF_EVAL_DF (fn, alpha);
  134. /* Fletcher's sigma test */
  135. if (fabs (fpalpha) <= -sigma * fp0)
  136. {
  137. *alpha_new = alpha;
  138. return GSL_SUCCESS;
  139. }
  140. if (fpalpha >= 0)
  141. {
  142. a = alpha; fa = falpha; fpa = fpalpha;
  143. b = alpha_prev; fb = falpha_prev; fpb = fpalpha_prev;
  144. break; /* goto sectioning */
  145. }
  146. delta = alpha - alpha_prev;
  147. {
  148. double lower = alpha + delta;
  149. double upper = alpha + tau1 * delta;
  150. alpha_next = interpolate (alpha_prev, falpha_prev, fpalpha_prev,
  151. alpha, falpha, fpalpha, lower, upper, order);
  152. }
  153. alpha_prev = alpha;
  154. falpha_prev = falpha;
  155. fpalpha_prev = fpalpha;
  156. alpha = alpha_next;
  157. }
  158. /* Sectioning of bracket [a,b] */
  159. while (i++ < section_iters)
  160. {
  161. delta = b - a;
  162. {
  163. double lower = a + tau2 * delta;
  164. double upper = b - tau3 * delta;
  165. alpha = interpolate (a, fa, fpa, b, fb, fpb, lower, upper, order);
  166. }
  167. falpha = GSL_FN_FDF_EVAL_F (fn, alpha);
  168. if ((a-alpha)*fpa <= GSL_DBL_EPSILON) {
  169. /* roundoff prevents progress */
  170. return GSL_ENOPROG;
  171. };
  172. if (falpha > f0 + rho * alpha * fp0 || falpha >= fa)
  173. {
  174. /* a_next = a; */
  175. b = alpha; fb = falpha; fpb = GSL_NAN;
  176. }
  177. else
  178. {
  179. fpalpha = GSL_FN_FDF_EVAL_DF (fn, alpha);
  180. if (fabs(fpalpha) <= -sigma * fp0)
  181. {
  182. *alpha_new = alpha;
  183. return GSL_SUCCESS; /* terminate */
  184. }
  185. if ( ((b-a) >= 0 && fpalpha >= 0) || ((b-a) <=0 && fpalpha <= 0))
  186. {
  187. b = a; fb = fa; fpb = fpa;
  188. a = alpha; fa = falpha; fpa = fpalpha;
  189. }
  190. else
  191. {
  192. a = alpha; fa = falpha; fpa = fpalpha;
  193. }
  194. }
  195. }
  196. return GSL_SUCCESS;
  197. }