LifeV
NonLinearBrent.hpp
Go to the documentation of this file.
1 //@HEADER
2 /*
3 *******************************************************************************
4 
5  Copyright (C) 2004, 2005, 2007 EPFL, Politecnico di Milano, INRIA
6  Copyright (C) 2010 EPFL, Politecnico di Milano, Emory University
7 
8  This file is part of LifeV.
9 
10  LifeV is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  LifeV is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with LifeV. If not, see <http://www.gnu.org/licenses/>.
22 
23 *******************************************************************************
24 */
25 //@HEADER
26 
27 /*!
28  @file
29  @brief Implementation of Brent's method for root finding.
30 
31  @author Alessio Fumagalli <alessio.fumagalli@mail.polimi.it>
32  @date
33 
34  @contributor Alessandro Melani <alessandro.melani@mail.polimi.it>
35  @mantainer Alessandro Melani <alessandro.melani@mail.polimi.it>
36 
37  Brent's method is a root-finding algorithm combining the bisection method, the secant method
38  and inverse quadratic interpolation. It has the reliability of bisection but it can be as quick
39  as some of the less reliable methods. The idea is to use the secant method or inverse quadratic
40  interpolation if possible, because they converge faster, but to fall back to the more robust bisection
41  method if necessary.
42 
43  @see Chapter 4 of R.P. Brent, "Algorithms for Minimization without Derivatives", Prentice-Hall, Englewood Cliffs, NJ. 1973
44  */
45 #ifndef _NonLinearBrent_H
46 #define _NonLinearBrent_H 1
47 
48 #include <limits>
49 
50 #include <lifev/core/LifeV.hpp>
51 
52 namespace LifeV
53 {
54 //! Implementation of Brent's method for root finding.
55 /*!
56  @author Alessio Fumagalli <alessio.fumagalli@mail.polimi.it>
57  @date
58 
59  Brent's method is a root-finding algorithm combining the bisection method, the secant method and inverse quadratic interpolation.
60  It has the reliability of bisection but it can be as quick as some of the less reliable methods.
61  The idea is to use the secant method or inverse quadratic interpolation if possible, because they converge faster, but to fall back
62  to the more robust bisection method if necessary.
63 
64  See Chapter 4 of R.P. Brent, "Algorithms for Minimization without Derivatives", Prentice-Hall, Englewood Cliffs, NJ. 1973
65 
66  @param f Function
67  @param leftExtremeBase Left extreme of the interval
68  @param rightExtremeBase Right extreme of the interval
69  @param toll Tollerance
70  @param maxIter Maximum number of iterations
71 */
72 
73 template <class Function>
74 Real NonLinearBrent ( const Function& f, const Real& leftExtremeBase, const Real& rightExtremeBase, const Real& toll, const UInt& maxIter )
75 {
76 
77  // Trivial case
78  if ( leftExtremeBase == rightExtremeBase )
79  {
80  return leftExtremeBase;
81  }
82 
83  // Current left and right extreme of the interval
84  Real leftExtreme ( leftExtremeBase ), rightExtreme ( rightExtremeBase );
85 
86  if ( leftExtreme > rightExtreme )
87  {
88  std::swap ( leftExtreme, rightExtreme );
89  }
90 
91  // Current iteration
92  UInt numIter ( static_cast<UInt> (0) );
93 
94  // Medium point of the current interval
95  Real midpoint ( ( leftExtreme + rightExtreme ) / static_cast<Real> (2.) );
96 
97  // Gold
98  Real gold ( static_cast<Real> ( (3. - std::sqrt (5.) ) / 2. ) );
99 
100  // Ausiliar variables
101  Real p (0), q (0), r (0);
102  Real x ( leftExtreme + gold * ( rightExtreme - leftExtreme ) );
103  Real u (0), e (0), w (0), v (0), d (0);
104  Real fx ( f (x) ), fv ( fx ), fw ( fx ), fu (0);
105 
106  // Relative tollerance
107  Real tollRelative ( std::numeric_limits<Real>::epsilon() * std::fabs ( x ) + toll );
108 
109 
110  while ( std::fabs ( x - midpoint) > ( static_cast<Real> (2.) * tollRelative - ( rightExtreme - leftExtreme ) / static_cast<Real> (2.) ) && numIter < maxIter )
111  {
112 
113  // Clear some ausiliar variables
114  p = q = r = static_cast<Real> (0);
115 
116  if ( std::fabs ( e ) > tollRelative )
117  {
118  r = ( x - w ) * ( fx - fv );
119  q = ( x - v ) * ( fx - fw );
120  p = ( x - v ) * q - ( x - w ) * r;
121  q = static_cast<Real> (2.) * ( q - r );
122 
123  if ( q > static_cast<Real> (0.) )
124  {
125  p = - p;
126  }
127  else
128  {
129  q = - q;
130  }
131 
132  r = e;
133  e = d;
134  }
135 
136 
137  if ( std::fabs ( p ) < std::fabs ( q * r / static_cast<Real> (2.) ) && p > q * ( leftExtreme - x ) && p < q * ( rightExtreme - x ) )
138  {
139  d = p / q;
140  u = x + d;
141 
142  if ( ( u - leftExtreme) < static_cast<Real> (2.) * tollRelative || ( rightExtreme - u ) < static_cast<Real> (2.) * tollRelative )
143  {
144  if ( x < midpoint )
145  {
146  d = tollRelative;
147  }
148  else
149  {
150  d = -tollRelative;
151  }
152  }
153  }
154  else
155  {
156  if ( x < midpoint )
157  {
158  e = rightExtreme - x;
159  }
160  else
161  {
162  e = leftExtreme - x;
163  }
164 
165  d = gold * e;
166  }
167 
168  if ( std::fabs ( d ) >= tollRelative )
169  {
170  u = x + d;
171  }
172  else
173  {
174  if ( d > static_cast<Real> (0.) )
175  {
176  u = x + tollRelative;
177  }
178  else
179  {
180  u = x - tollRelative;
181  }
182  }
183 
184  // Compute the value of f in the point u
185  fu = f (u);
186 
187  if ( fu <= fx )
188  {
189  if ( u < x )
190  {
191  rightExtreme = x;
192  }
193  else
194  {
195  leftExtreme = x;
196  }
197 
198  v = w;
199  fv = fw;
200  w = x;
201  fw = fx;
202  x = u;
203  fx = fu;
204  }
205  else
206  {
207  if ( u < x )
208  {
209  leftExtreme = u;
210  }
211  else
212  {
213  rightExtreme = u;
214  }
215 
216  if ( fu <= fw || x == w )
217  {
218  v = w;
219  fv = fw;
220  w = u;
221  fw = fu;
222  }
223  else
224  {
225  if ( fu <= fv || v == x || v == w )
226  {
227  v = u;
228  fv = fu;
229  }
230  }
231  }
232 
233  // Compute the midpoint of the interval
234  midpoint = ( leftExtreme + rightExtreme ) / static_cast<Real> (2.);
235 
236  // Compute the relative tollerance
237  tollRelative = std::numeric_limits<Real>::epsilon() * std::fabs ( x ) + toll;
238 
239  // Increase the iterations number
240  ++numIter;
241 
242  }
243  std::ostringstream os;
244  os << "Attention the brent scheme does not reach the convergence in "
245  << numIter << ", with tollerance "
246  << tollRelative << std::endl;
247 
248  // Check if the method reach the tollerance.
249  ASSERT ( maxIter > numIter, os.str().c_str() );
250 
251  return x;
252 
253 }
254 
255 } // Namespace LifeV
256 
257 #endif /* _NonLinearBrent_ */
Real NonLinearBrent(const Function &f, const Real &leftExtremeBase, const Real &rightExtremeBase, const Real &toll, const UInt &maxIter)
Implementation of Brent&#39;s method for root finding.
#define ASSERT(X, A)
Definition: LifeAssert.hpp:90
double Real
Generic real data.
Definition: LifeV.hpp:175
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191