minima.hpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // (C) Copyright John Maddock 2006.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_TOOLS_MINIMA_HPP
  6. #define BOOST_MATH_TOOLS_MINIMA_HPP
  7. #ifdef _MSC_VER
  8. #pragma once
  9. #endif
  10. #include <utility>
  11. #include <boost/config/no_tr1/cmath.hpp>
  12. #include <boost/math/tools/precision.hpp>
  13. #include <boost/math/policies/policy.hpp>
  14. #include <boost/cstdint.hpp>
  15. namespace boost{ namespace math{ namespace tools{
  16. template <class F, class T>
  17. std::pair<T, T> brent_find_minima(F f, T min, T max, int bits, boost::uintmax_t& max_iter)
  18. {
  19. BOOST_MATH_STD_USING
  20. bits = (std::min)(policies::digits<T, policies::policy<> >() / 2, bits);
  21. T tolerance = static_cast<T>(ldexp(1.0, 1-bits));
  22. T x; // minima so far
  23. T w; // second best point
  24. T v; // previous value of w
  25. T u; // most recent evaluation point
  26. T delta; // The distance moved in the last step
  27. T delta2; // The distance moved in the step before last
  28. T fu, fv, fw, fx; // function evaluations at u, v, w, x
  29. T mid; // midpoint of min and max
  30. T fract1, fract2; // minimal relative movement in x
  31. static const T golden = 0.3819660f; // golden ratio, don't need too much precision here!
  32. x = w = v = max;
  33. fw = fv = fx = f(x);
  34. delta2 = delta = 0;
  35. uintmax_t count = max_iter;
  36. do{
  37. // get midpoint
  38. mid = (min + max) / 2;
  39. // work out if we're done already:
  40. fract1 = tolerance * fabs(x) + tolerance / 4;
  41. fract2 = 2 * fract1;
  42. if(fabs(x - mid) <= (fract2 - (max - min) / 2))
  43. break;
  44. if(fabs(delta2) > fract1)
  45. {
  46. // try and construct a parabolic fit:
  47. T r = (x - w) * (fx - fv);
  48. T q = (x - v) * (fx - fw);
  49. T p = (x - v) * q - (x - w) * r;
  50. q = 2 * (q - r);
  51. if(q > 0)
  52. p = -p;
  53. q = fabs(q);
  54. T td = delta2;
  55. delta2 = delta;
  56. // determine whether a parabolic step is acceptible or not:
  57. if((fabs(p) >= fabs(q * td / 2)) || (p <= q * (min - x)) || (p >= q * (max - x)))
  58. {
  59. // nope, try golden section instead
  60. delta2 = (x >= mid) ? min - x : max - x;
  61. delta = golden * delta2;
  62. }
  63. else
  64. {
  65. // whew, parabolic fit:
  66. delta = p / q;
  67. u = x + delta;
  68. if(((u - min) < fract2) || ((max- u) < fract2))
  69. delta = (mid - x) < 0 ? (T)-fabs(fract1) : (T)fabs(fract1);
  70. }
  71. }
  72. else
  73. {
  74. // golden section:
  75. delta2 = (x >= mid) ? min - x : max - x;
  76. delta = golden * delta2;
  77. }
  78. // update current position:
  79. u = (fabs(delta) >= fract1) ? T(x + delta) : (delta > 0 ? T(x + fabs(fract1)) : T(x - fabs(fract1)));
  80. fu = f(u);
  81. if(fu <= fx)
  82. {
  83. // good new point is an improvement!
  84. // update brackets:
  85. if(u >= x)
  86. min = x;
  87. else
  88. max = x;
  89. // update control points:
  90. v = w;
  91. w = x;
  92. x = u;
  93. fv = fw;
  94. fw = fx;
  95. fx = fu;
  96. }
  97. else
  98. {
  99. // Oh dear, point u is worse than what we have already,
  100. // even so it *must* be better than one of our endpoints:
  101. if(u < x)
  102. min = u;
  103. else
  104. max = u;
  105. if((fu <= fw) || (w == x))
  106. {
  107. // however it is at least second best:
  108. v = w;
  109. w = u;
  110. fv = fw;
  111. fw = fu;
  112. }
  113. else if((fu <= fv) || (v == x) || (v == w))
  114. {
  115. // third best:
  116. v = u;
  117. fv = fu;
  118. }
  119. }
  120. }while(--count);
  121. max_iter -= count;
  122. return std::make_pair(x, fx);
  123. }
  124. template <class F, class T>
  125. inline std::pair<T, T> brent_find_minima(F f, T min, T max, int digits)
  126. {
  127. boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
  128. return brent_find_minima(f, min, max, digits, m);
  129. }
  130. }}} // namespaces
  131. #endif