LifeV
NonLinearLineSearch.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 Line-search algorithm with parabolic interpolation.
30 
31  @author
32  @date
33 
34  @contributor Alessandro Melani <alessandro.melani@mail.polimi.it>
35  @mantainer Alessandro Melani <alessandro.melani@mail.polimi.it>
36 
37  @see Chapter 8 of C.T. Kelley,
38  "Iterative methods for linear and nonlinear equations", SIAM 1995
39 
40  @see Chapter 6 of J.E. Dennis, R.B.Schnabel
41  "Numerical Methods for Unconstrained Optimization and Nonlinear Equations",
42  no. 16 in Classics in Applied Mathematics, SIAM, Philadelphia, 1996
43 
44 */
45 
46 #ifndef _NonLinearLineSearch_H_
47 #define _NonLinearLineSearch_H_ 1
48 
49 namespace LifeV
50 {
51 //! Implementation of Line Search method with parabolic interpolation
52 /*!
53 
54  @author
55  @date
56 
57  This line search algorithm comes from chapter 8 of C.T. Kelley,
58  "Iterative methods for linear and nonlinear equations", SIAM 1995
59 
60  (i) lambda given (usually 1 when Newton method is used)
61  (ii) solTest = sol + lambda stepTest
62  (iii) if residuTest < (1 - alpha lambda) residu
63  then sol = solTest
64  else choose lambda via a three point parabolic interpolation
65  (that does not net the derivative) and apply a safeguarding
66  step: if lambda < sigma0 lambdaCurrent then lambda = sigma0 lambdaCurrent
67  if lambda > sigma1 lambdaCurrent then lambda = sigma1 lambdaCurrent
68 
69  Constant parameters:
70 
71  sigma0, sigma1: safeguarding bounds (default values 0.1 and 0.5)
72  alpha: parameter to measure sufficient decrease (default 1e-4)
73  maxIterations: maximum number of steplength reductions before
74  failure is reported (default 50)
75 
76  @param f Function
77  @param residual Residual
78  @param sol Solution
79  @param step Step to update the solution
80  @param normRes Norm of the residual
81  @param lambda Length of the Step
82  @param iter Iterations
83  @param verboseLevel Option for detailed description
84 */
85 template <class Fct, class VectorType>
86 Int NonLinearLineSearchParabolic ( Fct& f, VectorType& residual, VectorType& sol, VectorType& step, Real& normRes,
87  Real& lambda, UInt iter, UInt const verboseLevel = 1)
88 {
89 
90  //----------------------------------------------------------------------
91  if ( verboseLevel > 0 )
92  {
93  std::cout << "Parabolic line search ..." << std::endl;
94  }
95  const Real sigma0 = 0.1;
96  const Real sigma1 = 0.5;
97  const Real alpha = 1.e-4;
98  const Int maxIterations = 50;
99  //----------------------------------------------------------------------
100  static VectorType S_solCurrent = sol; // static to avoid too many alloc/de-alloc
101  Int iterNonLinearLineSearch;
102  Real lambdaCurrent, lambdaOld, normResTest, res2, resTest2, resTestOld2, c1, c2;
103  //
104  res2 = normRes * normRes;
105  lambdaOld = lambda;
106  lambdaCurrent = lambda;
107  S_solCurrent = sol;
108  sol += lambda * step;
109  f.evalResidual ( residual, sol, iter );
110  normResTest = residual.normInf();
111  resTest2 = normResTest * normResTest;
112  resTestOld2 = resTest2;
113  iterNonLinearLineSearch = 0;
114  while ( normResTest >= ( 1 - alpha * lambda ) * normRes )
115  {
116  iterNonLinearLineSearch++;
117  // parabolic interpolation of lambda:
118  c2 = lambdaOld * ( resTest2 - res2 ) - lambdaCurrent * ( resTestOld2 - res2 );
119  if ( c2 >= 0 )
120  {
121  lambda = sigma1 * lambdaCurrent;
122  }
123  else
124  {
125  c1 = lambdaCurrent * lambdaCurrent * ( resTestOld2 - res2 )
126  - lambdaOld * lambdaOld * ( resTest2 - res2 );
127  lambda = -c1 * .5 / c2;
128  if ( lambda < sigma0 * lambdaCurrent )
129  {
130  lambda = sigma0 * lambdaCurrent;
131  }
132  if ( lambda > sigma1 * lambdaCurrent )
133  {
134  lambda = sigma1 * lambdaCurrent;
135  }
136  }
137  if ( verboseLevel > 0 )
138  std::cout << "--- line search " << iterNonLinearLineSearch << " : residual test = "
139  << normResTest << ", reduction = " << lambda << std::endl;
140  // update solTest
141  sol = S_solCurrent;
142  sol += lambda * step;
143  lambdaOld = lambdaCurrent;
144  lambdaCurrent = lambda;
145  // eval norms
146  f.evalResidual ( residual, sol, iter );
147  normResTest = residual.normInf();
148  resTestOld2 = resTest2;
149  resTest2 = normResTest * normResTest;
150  if ( iterNonLinearLineSearch > maxIterations )
151  {
152  if ( verboseLevel > 0 )
153  {
154  std::cout << "!!! Too many iterations in the line search algorithm" << std::endl;
155  }
156  return EXIT_FAILURE;
157  }
158  }
159  normRes = normResTest;
160  if ( verboseLevel > 0 )
161  {
162  std::cout << "Parabolic line search: final residual = " << normRes << std::endl;
163  }
164 
165  return EXIT_SUCCESS;
166 
167 }
168 
169 //! Implementation of Line Search method with cubic interpolation
170 /*!
171 
172  @author
173  @date
174 
175  This line search algorithm comes from chapter 6 of J.E. Dennis, R.B.Schnabel
176  "Numerical Methods for Unconstrained Optimization and Nonlinear Equations",
177  no. 16 in Classics in Applied Mathematics, SIAM, Philadelphia, 1996
178 
179  (i) lambda given (usually 1 when Newton method is used)
180  (ii) solTest = sol + lambda stepTest
181  (iii) Goldstein - Price + cubic interpolation
182 
183  sigma0, sigma1: safeguarding bounds (default values 0.1 and 0.5)
184  m1, m2 parameters in Goldstein conditions
185  maxIterations: maximum number of steplength reductions before
186  failure is reported (default 50)
187 
188  @param f Function
189  @param residual Residual
190  @param sol Solution
191  @param step Step to update the solution
192  @param normRes Norm of the residual
193  @param lambda Length of the Step
194  @param slope Slope value in linesearch algorithm
195  @param iter Iterations
196  @param verboseLevel Option for detailed description
197 */
198 
199 template <class Fct, class VectorType>
200 Int NonLinearLineSearchCubic ( Fct& f, VectorType& residual, VectorType& sol, VectorType& step,
201  Real& normRes, Real& lambda, Real& slope, UInt iter, UInt const verboseLevel = 1 )
202 {
203 
204  //----------------------------------------------------------------------
205  if ( verboseLevel > 0 )
206  {
207  std::cout << "Cubic line search ..." << std::endl;
208  }
209 
210  const Real sigma0 = 0.1;
211  const Real sigma1 = 0.5;
212  const Real m1 = 0.25;
213  const Real m2 = 0.75;
214  const Int maxIterations = 50;
215  //----------------------------------------------------------------------
216  static VectorType S_solCurrent = sol; // static to avoid too many alloc/de-alloc
217  Int iterLinesearch;
218  bool firstTime = true;
219  Real lambda2, lambdaOld, lambdaOld2, lambdaTemporary,
220  normResTest, f0, ftest, c, c11, c12, c21, c22, a, b, disc, g1, g2, gprev = 0;
221  //
222  f0 = 0.5 * normRes * normRes;
223  lambdaOld = lambda;
224  S_solCurrent = sol;
225  sol += lambda * step;
226  f.evalResidual ( residual, sol, iter );
227  normResTest = residual.normInf();
228  ftest = 0.5 * normResTest * normResTest;
229  iterLinesearch = 0;
230  while ( ftest < f0 + m2 * slope * lambda // lambda is too small: extrapolation
231  && iterLinesearch < maxIterations )
232  {
233  iterLinesearch++;
234  lambda *= 2;
235  sol = S_solCurrent;
236  sol += lambda * step;
237  if ( verboseLevel > 0 )
238  {
239  std::cout << "--- line search (extrapolation, Goldstein rule)" << std::endl;
240  }
241  f.evalResidual ( residual, sol, iter );
242 
243  if ( verboseLevel > 0 )
244  std::cout << " line search iter : " << iterLinesearch << " residual test = "
245  << normResTest << ", lambda = " << lambda << std::endl;
246  normResTest = residual.normInf();
247  ftest = 0.5 * normResTest * normResTest;
248  }
249  if ( iterLinesearch == maxIterations )
250  {
251  if ( verboseLevel > 0 )
252  {
253  std::cout << "line search: too many extrapolations" << std::endl;
254  }
255  return EXIT_FAILURE;
256  }
257  lambdaOld = lambda;
258  while ( ftest > f0 + m1 * slope * lambda // Armijo's rule: lambda is too large
259  && iterLinesearch < maxIterations )
260  {
261  iterLinesearch++;
262  //-- cubic interpolation of lambda:
263  lambda2 = lambda * lambda;
264  g1 = ftest - f0 - slope * lambda;
265  if ( firstTime )
266  {
267  lambdaTemporary = - slope * lambda2 / ( 2. * g1 );
268  firstTime = false;
269  }
270  else
271  {
272  lambdaOld2 = lambdaOld * lambdaOld;
273  g2 = gprev - f0 - lambdaOld * slope;
274  c = 1. / ( lambda - lambdaOld );
275  c11 = 1. / lambda2;
276  c12 = -1. / lambdaOld2;
277  c21 = - lambdaOld / lambda2;
278  c22 = lambda / lambdaOld2;
279  a = c * ( c11 * g1 + c12 * g2 );
280  b = c * ( c21 * g1 + c22 * g2 );
281  disc = b * b - 3. * a * slope;
282  if ( ( std::fabs ( a ) > std::numeric_limits<Real>::min() ) &&
283  ( disc > std::numeric_limits<Real>::min() )
284  )
285  {
286  lambdaTemporary = ( - b + std::sqrt ( disc ) ) / ( 3. * a );
287  }
288  else
289  {
290  lambdaTemporary = slope * lambda2 / ( 2. * g1 ) ;
291  }
292  if ( lambdaTemporary >= sigma1 * lambda )
293  {
294  lambdaTemporary = sigma1 * lambda;
295  }
296  }
297  lambdaOld = lambda;
298  gprev = ftest;
299  if ( lambdaTemporary < sigma0 * lambda )
300  {
301  lambda *= sigma0;
302  }
303  else
304  {
305  lambda = lambdaTemporary;
306  }
307  //--
308  sol = S_solCurrent;
309  sol += lambda * step;
310  if ( verboseLevel > 0 )
311  {
312  std::cout << "--- line search (cubic interpolation, Armijo rule)" << std::endl;
313  }
314  f.evalResidual ( residual, sol, iter );
315  normResTest = residual.normInf();
316  if ( verboseLevel > 0 )
317  std::cout << " line search iter : " << iterLinesearch << " residual test = "
318  << normResTest << ", lambda = " << lambda << std::endl;
319  ftest = 0.5 * normResTest * normResTest;
320  }
321  if ( iterLinesearch == maxIterations )
322  {
323  if ( verboseLevel > 0 )
324  {
325  std::cout << "line search: too many interpolations" << std::endl;
326  }
327  return EXIT_FAILURE;
328  }
329  normRes = normResTest;
330  if ( verboseLevel > 0 )
331  {
332  std::cout << "Parabolic line search: final residual = " << normRes << std::endl;
333  }
334  return EXIT_SUCCESS;
335 }
336 
337 } // Namespace LifeV
338 
339 #endif /* _NonLinearLineSearch_H_ */
Int NonLinearLineSearchCubic(Fct &f, VectorType &residual, VectorType &sol, VectorType &step, Real &normRes, Real &lambda, Real &slope, UInt iter, UInt const verboseLevel=1)
Implementation of Line Search method with cubic interpolation.
int32_type Int
Generic integer data.
Definition: LifeV.hpp:188
double Real
Generic real data.
Definition: LifeV.hpp:175
Int NonLinearLineSearchParabolic(Fct &f, VectorType &residual, VectorType &sol, VectorType &step, Real &normRes, Real &lambda, UInt iter, UInt const verboseLevel=1)
Implementation of Line Search method with parabolic interpolation.
uint32_type UInt
generic unsigned integer (used mainly for addressing)
Definition: LifeV.hpp:191