minima.hpp 4.5 KB

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