155 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| //  (C) Copyright John Maddock 2006.
 | |
| //  Use, modification and distribution are subject to the
 | |
| //  Boost Software License, Version 1.0. (See accompanying file
 | |
| //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | |
| 
 | |
| 
 | |
| #ifndef BOOST_MATH_TOOLS_MINIMA_HPP
 | |
| #define BOOST_MATH_TOOLS_MINIMA_HPP
 | |
| 
 | |
| #ifdef _MSC_VER
 | |
| #pragma once
 | |
| #endif
 | |
| 
 | |
| #include <utility>
 | |
| #include <boost/config/no_tr1/cmath.hpp>
 | |
| #include <boost/math/tools/precision.hpp>
 | |
| #include <boost/math/policies/policy.hpp>
 | |
| #include <boost/cstdint.hpp>
 | |
| 
 | |
| namespace boost{ namespace math{ namespace tools{
 | |
| 
 | |
| template <class F, class T>
 | |
| std::pair<T, T> brent_find_minima(F f, T min, T max, int bits, boost::uintmax_t& max_iter)
 | |
|    BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
 | |
| {
 | |
|    BOOST_MATH_STD_USING
 | |
|    bits = (std::min)(policies::digits<T, policies::policy<> >() / 2, bits);
 | |
|    T tolerance = static_cast<T>(ldexp(1.0, 1-bits));
 | |
|    T x;  // minima so far
 | |
|    T w;  // second best point
 | |
|    T v;  // previous value of w
 | |
|    T u;  // most recent evaluation point
 | |
|    T delta;  // The distance moved in the last step
 | |
|    T delta2; // The distance moved in the step before last
 | |
|    T fu, fv, fw, fx;  // function evaluations at u, v, w, x
 | |
|    T mid; // midpoint of min and max
 | |
|    T fract1, fract2;  // minimal relative movement in x
 | |
| 
 | |
|    static const T golden = 0.3819660f;  // golden ratio, don't need too much precision here!
 | |
| 
 | |
|    x = w = v = max;
 | |
|    fw = fv = fx = f(x);
 | |
|    delta2 = delta = 0;
 | |
| 
 | |
|    uintmax_t count = max_iter;
 | |
| 
 | |
|    do{
 | |
|       // get midpoint
 | |
|       mid = (min + max) / 2;
 | |
|       // work out if we're done already:
 | |
|       fract1 = tolerance * fabs(x) + tolerance / 4;
 | |
|       fract2 = 2 * fract1;
 | |
|       if(fabs(x - mid) <= (fract2 - (max - min) / 2))
 | |
|          break;
 | |
| 
 | |
|       if(fabs(delta2) > fract1)
 | |
|       {
 | |
|          // try and construct a parabolic fit:
 | |
|          T r = (x - w) * (fx - fv);
 | |
|          T q = (x - v) * (fx - fw);
 | |
|          T p = (x - v) * q - (x - w) * r;
 | |
|          q = 2 * (q - r);
 | |
|          if(q > 0)
 | |
|             p = -p;
 | |
|          q = fabs(q);
 | |
|          T td = delta2;
 | |
|          delta2 = delta;
 | |
|          // determine whether a parabolic step is acceptible or not:
 | |
|          if((fabs(p) >= fabs(q * td / 2)) || (p <= q * (min - x)) || (p >= q * (max - x)))
 | |
|          {
 | |
|             // nope, try golden section instead
 | |
|             delta2 = (x >= mid) ? min - x : max - x;
 | |
|             delta = golden * delta2;
 | |
|          }
 | |
|          else
 | |
|          {
 | |
|             // whew, parabolic fit:
 | |
|             delta = p / q;
 | |
|             u = x + delta;
 | |
|             if(((u - min) < fract2) || ((max- u) < fract2))
 | |
|                delta = (mid - x) < 0 ? (T)-fabs(fract1) : (T)fabs(fract1);
 | |
|          }
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|          // golden section:
 | |
|          delta2 = (x >= mid) ? min - x : max - x;
 | |
|          delta = golden * delta2;
 | |
|       }
 | |
|       // update current position:
 | |
|       u = (fabs(delta) >= fract1) ? T(x + delta) : (delta > 0 ? T(x + fabs(fract1)) : T(x - fabs(fract1)));
 | |
|       fu = f(u);
 | |
|       if(fu <= fx)
 | |
|       {
 | |
|          // good new point is an improvement!
 | |
|          // update brackets:
 | |
|          if(u >= x)
 | |
|             min = x;
 | |
|          else
 | |
|             max = x;
 | |
|          // update control points:
 | |
|          v = w;
 | |
|          w = x;
 | |
|          x = u;
 | |
|          fv = fw;
 | |
|          fw = fx;
 | |
|          fx = fu;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|          // Oh dear, point u is worse than what we have already,
 | |
|          // even so it *must* be better than one of our endpoints:
 | |
|          if(u < x)
 | |
|             min = u;
 | |
|          else
 | |
|             max = u;
 | |
|          if((fu <= fw) || (w == x))
 | |
|          {
 | |
|             // however it is at least second best:
 | |
|             v = w;
 | |
|             w = u;
 | |
|             fv = fw;
 | |
|             fw = fu;
 | |
|          }
 | |
|          else if((fu <= fv) || (v == x) || (v == w))
 | |
|          {
 | |
|             // third best:
 | |
|             v = u;
 | |
|             fv = fu;
 | |
|          }
 | |
|       }
 | |
| 
 | |
|    }while(--count);
 | |
| 
 | |
|    max_iter -= count;
 | |
| 
 | |
|    return std::make_pair(x, fx);
 | |
| }
 | |
| 
 | |
| template <class F, class T>
 | |
| inline std::pair<T, T> brent_find_minima(F f, T min, T max, int digits)
 | |
|    BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(T) && noexcept(std::declval<F>()(std::declval<T>())))
 | |
| {
 | |
|    boost::uintmax_t m = (std::numeric_limits<boost::uintmax_t>::max)();
 | |
|    return brent_find_minima(f, min, max, digits, m);
 | |
| }
 | |
| 
 | |
| }}} // namespaces
 | |
| 
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | 
