minima.qbk 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. [section:brent_minima Locating Function Minima using Brent's algorithm]
  2. [import ../../example/brent_minimise_example.cpp]
  3. [h4 Synopsis]
  4. ``
  5. #include <boost/math/tools/minima.hpp>
  6. ``
  7. template <class F, class T>
  8. std::pair<T, T> brent_find_minima(F f, T min, T max, int bits);
  9. template <class F, class T>
  10. std::pair<T, T> brent_find_minima(F f, T min, T max, int bits, boost::uintmax_t& max_iter);
  11. [h4 Description]
  12. These two functions locate the minima of the continuous function ['f] using
  13. [@http://en.wikipedia.org/wiki/Brent%27s_method Brent's method]: specifically it
  14. uses quadratic interpolation to locate the minima, or if that fails, falls back to
  15. a [@http://en.wikipedia.org/wiki/Golden_section_search golden-section search].
  16. [*Parameters]
  17. [variablelist
  18. [[f] [The function to minimise: a function object (or C++ lambda) that should be smooth over the
  19. range ['\[min, max\]], with no maxima occurring in that interval.]]
  20. [[min] [The lower endpoint of the range in which to search for the minima.]]
  21. [[max] [The upper endpoint of the range in which to search for the minima.]]
  22. [[bits] [The number of bits precision to which the minima should be found.[br]
  23. Note that in principle, the minima can not be located to greater
  24. accuracy than the square root of machine epsilon (for 64-bit double, sqrt(1e-16)[cong]1e-8),
  25. therefore the value of ['bits] will be ignored if it's greater than half the number of bits
  26. in the mantissa of T.]]
  27. [[max_iter] [The maximum number of iterations to use
  28. in the algorithm, if not provided the algorithm will just
  29. keep on going until the minima is found.]]
  30. ] [/variablelist]
  31. [*Returns:]
  32. A `std::pair` of type T containing the value of the abscissa (x) at the minima and the value
  33. of ['f(x)] at the minima.
  34. [tip Defining BOOST_MATH_INSTRUMENT will show some parameters, for example:
  35. ``
  36. Type T is double
  37. bits = 24, maximum 26
  38. tolerance = 1.19209289550781e-007
  39. seeking minimum in range min-4 to 1.33333333333333
  40. maximum iterations 18446744073709551615
  41. 10 iterations.
  42. ``
  43. ]
  44. [h4:example Brent Minimisation Example]
  45. As a demonstration, we replicate this [@http://en.wikipedia.org/wiki/Brent%27s_method#Example Wikipedia example]
  46. minimising the function ['y= (x+3)(x-1)[super 2]].
  47. It is obvious from the equation and the plot that there is a
  48. minimum at exactly unity (x = 1) and the value of the function at one is exactly zero (y = 0).
  49. [tip This observation shows that an analytical or
  50. [@http://en.wikipedia.org/wiki/Closed-form_expression Closed-form expression]
  51. solution always beats brute-force hands-down for both speed and precision.]
  52. [graph brent_test_function_1]
  53. First an include is needed:
  54. [brent_minimise_include_1]
  55. This function is encoded in C++ as function object (functor) using `double` precision thus:
  56. [brent_minimise_double_functor]
  57. The Brent function is conveniently accessed through a `using` statement (noting sub-namespace `::tools`).
  58. using boost::math::tools::brent_find_minima;
  59. The search minimum and maximum are chosen as -4 to 4/3 (as in the Wikipedia example).
  60. [tip S A Stage (reference 6) reports that the Brent algorithm is ['slow to start, but fast to converge],
  61. so choosing a tight min-max range is good.]
  62. For simplicity, we set the precision parameter `bits` to `std::numeric_limits<double>::digits`,
  63. which is effectively the maximum possible `std::numeric_limits<double>::digits/2`.
  64. Nor do we provide a value for maximum iterations parameter `max_iter`,
  65. (probably unwisely), so the function will iterate until it finds a minimum.
  66. [brent_minimise_double_1]
  67. The resulting [@http://en.cppreference.com/w/cpp/utility/pair std::pair]
  68. contains the minimum close to one, and the minimum value close to zero.
  69. x at minimum = 1.00000000112345,
  70. f(1.00000000112345) = 5.04852568272458e-018
  71. The differences from the expected ['one] and ['zero] are less than the
  72. uncertainty, for `double` 1.5e-008, calculated from
  73. `sqrt(std::numeric_limits<double>::epsilon())`.
  74. We can use this uncertainty to check that the two values are close-enough to those expected,
  75. [brent_minimise_double_1a]
  76. that outputs
  77. x == 1 (compared to uncertainty 1.49011611938477e-08) is true
  78. f(x) == 0 (compared to uncertainty 1.49011611938477e-08) is true
  79. [note The function `close_at_tolerance` is ineffective for testing if a value is small or zero
  80. (because it may divide by small or zero and cause overflow).
  81. Function `is_small` does this job.]
  82. It is possible to make this comparison more generally with a templated function,
  83. `is_close`, first checking `is_small` before checking `close_at_tolerance`,
  84. returning `true` when small or close, for example:
  85. [brent_minimise_close]
  86. In practical applications, we might want to know how many iterations,
  87. and maybe to limit iterations (in case the function proves ill-behaved),
  88. and/or perhaps to trade some loss of precision for speed, for example:
  89. [brent_minimise_double_2]
  90. limits to a maximum of 20 iterations
  91. (a reasonable estimate for this example function, even for much higher precision shown later).
  92. The parameter `it` is updated to return the actual number of iterations
  93. (so it may be useful to also keep a record of the limit set in `const maxit`).
  94. It is neat to avoid showing insignificant digits by computing the number of decimal digits to display.
  95. [brent_minimise_double_3]
  96. Showing 53 bits precision with 9 decimal digits from tolerance 1.49011611938477e-008
  97. x at minimum = 1, f(1) = 5.04852568e-018
  98. We can also half the number of precision bits from 52 to 26:
  99. [brent_minimise_double_4]
  100. showing no change in the result and no change in the number of iterations, as expected.
  101. It is only if we reduce the precision to a quarter, specifying only 13 precision bits
  102. [brent_minimise_double_5]
  103. that we reduce the number of iterations from 10 to 7 that the result slightly differs from ['one] and ['zero].
  104. Showing 13 bits precision with 9 decimal digits from tolerance 0.015625
  105. x at minimum = 0.9999776, f(0.9999776) = 2.0069572e-009 after 7 iterations.
  106. [h5:template Templating on floating-point type]
  107. If we want to switch the floating-point type, then the functor must be revised.
  108. Since the functor is stateless, the easiest option is to simply make
  109. `operator()` a template member function:
  110. [brent_minimise_T_functor]
  111. The `brent_find_minima` function can now be used in template form, for example using `long double`:
  112. [brent_minimise_template_1]
  113. The form shown uses the floating-point type `long double` by deduction,
  114. but it is also possible to be more explicit, for example:
  115. std::pair<long double, long double> r = brent_find_minima<func, long double>
  116. (func(), bracket_min, bracket_max, bits, it);
  117. In order to show the use of multiprecision below (or other user-defined types),
  118. it may be convenient to write a templated function to use this:
  119. [brent_minimise_T_show]
  120. [note the prudent addition of `try'n'catch` blocks within the function.
  121. This ensures that any malfunction will provide a Boost.Math error message
  122. rather than uncommunicatively calling `std::abort`.]
  123. We can use this with all built-in floating-point types, for example
  124. [brent_minimise_template_fd]
  125. [h5:quad_precision Quad 128-bit precision]
  126. On platforms that provide it, a
  127. [@http://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format 128-bit quad] type can be used.
  128. (See [@boost:libs/multiprecision/doc/html/boost_multiprecision/tut/floats/float128.html float128]).
  129. If this type is available, the build should define the macro BOOST_HAVE_QUADMATH:
  130. [brent_minimise_mp_include_1]
  131. and can be (conditionally) used this:
  132. [brent_minimise_template_quad]
  133. [h5:multiprecision Multiprecision]
  134. If a higher precision than `double` (or `long double` if that is more precise) is required,
  135. then this is easily achieved using __multiprecision with some includes, for example:
  136. [brent_minimise_mp_include_0]
  137. and some `typdef`s.
  138. [brent_minimise_mp_typedefs]
  139. Used thus
  140. [brent_minimise_mp_1]
  141. and with our `show_minima` function
  142. [brent_minimise_mp_2]
  143. [brent_minimise_mp_output_1]
  144. [brent_minimise_mp_output_2]
  145. [tip One can usually rely on template argument deduction
  146. to avoid specifying the verbose multiprecision types,
  147. but great care in needed with the ['type of the values] provided
  148. to avoid confusing the compiler.
  149. ]
  150. [tip Using `std::cout.precision(std::numeric_limits<T>::digits10);`
  151. or `std::cout.precision(std::numeric_limits<T>::max_digits10);`
  152. during debugging may be wise because it gives some warning if construction of multiprecision values
  153. involves unintended conversion from `double` by showing trailing zero or random digits after
  154. [@http://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10 max_digits10],
  155. that is 17 for `double`, digit 18... may be just noise.]
  156. The complete example code is at [@../../example/brent_minimise_example.cpp brent_minimise_example.cpp].
  157. [h4 Implementation]
  158. This is a reasonably faithful implementation of Brent's algorithm.
  159. [h4 References]
  160. # Brent, R.P. 1973, Algorithms for Minimization without Derivatives,
  161. (Englewood Cliffs, NJ: Prentice-Hall), Chapter 5.
  162. # Numerical Recipes in C, The Art of Scientific Computing,
  163. Second Edition, William H. Press, Saul A. Teukolsky,
  164. William T. Vetterling, and Brian P. Flannery.
  165. Cambridge University Press. 1988, 1992.
  166. # An algorithm with guaranteed convergence for finding a zero
  167. of a function, R. P. Brent, The Computer Journal, Vol 44, 1971.
  168. # [@http://en.wikipedia.org/wiki/Brent%27s_method Brent's method in Wikipedia.]
  169. # Z. Zhang, An Improvement to the Brent's Method, IJEA, vol. 2, pp. 2 to 26, May 31, 2011.
  170. [@http://www.cscjournals.org/manuscript/Journals/IJEA/volume2/Issue1/IJEA-7.pdf ]
  171. # Steven A. Stage, Comments on An Improvement to the Brent's Method
  172. (and comparison of various algorithms)
  173. [@http://www.cscjournals.org/manuscript/Journals/IJEA/volume4/Issue1/IJEA-33.pdf]
  174. Stage concludes that Brent's algorithm is slow to start, but fast to finish convergence, and has good accuracy.
  175. [endsect] [/section:rebt_minima Locating Function Minima]
  176. [/
  177. Copyright 2006, 2015, 2018 John Maddock and Paul A. Bristow.
  178. Distributed under the Boost Software License, Version 1.0.
  179. (See accompanying file LICENSE_1_0.txt or copy at
  180. http://www.boost.org/LICENSE_1_0.txt).
  181. ]