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
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 |