DOpE
reducednewtonalgorithm.h
Go to the documentation of this file.
1 
24 #ifndef REDUCEDNEWTON__ALGORITHM_H_
25 #define REDUCEDNEWTON__ALGORITHM_H_
26 
27 #include "reducedalgorithm.h"
28 #include "parameterreader.h"
29 
30 #include <iostream>
31 #include <assert.h>
32 #include <iomanip>
33 namespace DOpE
34 {
49  template <typename PROBLEM, typename VECTOR>
50  class ReducedNewtonAlgorithm : public ReducedAlgorithm<PROBLEM, VECTOR>
51  {
52  public:
66  ReducedNewtonAlgorithm(PROBLEM* OP,
68  ParameterReader &param_reader,
69  DOpEExceptionHandler<VECTOR>* Except=NULL,
70  DOpEOutputHandler<VECTOR>* Output=NULL,
71  int base_priority=0);
72  virtual ~ReducedNewtonAlgorithm();
73 
79  static void declare_params(ParameterReader &param_reader);
80 
90  virtual int Solve(ControlVector<VECTOR>& q,double global_tol=-1.);
97  double NewtonResidual(const ControlVector<VECTOR>& q);
98 
99  protected:
118  virtual int SolveReducedLinearSystem(const ControlVector<VECTOR>& q,
119  const ControlVector<VECTOR>& gradient,
120  const ControlVector<VECTOR>& gradient_transposed,
122 
136  virtual int ReducedNewtonLineSearch(const ControlVector<VECTOR>& dq,
137  const ControlVector<VECTOR>& gradient,
138  double& cost,
143  virtual double Residual(const ControlVector<VECTOR>& gradient,
144  const ControlVector<VECTOR>& gradient_transposed)
145  {return gradient*gradient_transposed;}
146  private:
147  unsigned int nonlinear_maxiter_, linear_maxiter_, line_maxiter_;
148  double nonlinear_tol_, nonlinear_global_tol_, linear_tol_, linear_global_tol_, lineasearch_rho_, linesearch_c_;
149  bool compute_functionals_in_every_step_;
150  std::string postindex_;
151  };
152 
153  /***************************************************************************************/
154  /****************************************IMPLEMENTATION*********************************/
155  /***************************************************************************************/
156  using namespace dealii;
157 
158  /******************************************************/
159 
160 template <typename PROBLEM, typename VECTOR>
162  {
163  param_reader.SetSubsection("reducednewtonalgorithm parameters");
164  param_reader.declare_entry("nonlinear_maxiter", "10",Patterns::Integer(0));
165  param_reader.declare_entry("nonlinear_tol", "1.e-7",Patterns::Double(0));
166  param_reader.declare_entry("nonlinear_global_tol", "1.e-11",Patterns::Double(0));
167 
168  param_reader.declare_entry("linear_maxiter", "40",Patterns::Integer(0));
169  param_reader.declare_entry("linear_tol", "1.e-10",Patterns::Double(0));
170  param_reader.declare_entry("linear_global_tol", "1.e-12",Patterns::Double(0));
171 
172  param_reader.declare_entry("line_maxiter", "4",Patterns::Integer(0));
173  param_reader.declare_entry("linesearch_rho", "0.9",Patterns::Double(0));
174  param_reader.declare_entry("linesearch_c", "0.1",Patterns::Double(0));
175 
176  param_reader.declare_entry("compute_functionals_in_every_step", "false",Patterns::Bool());
177 
179  }
180 /******************************************************/
181 
182 template <typename PROBLEM, typename VECTOR>
185  ParameterReader &param_reader,
188  int base_priority)
189  : ReducedAlgorithm<PROBLEM, VECTOR>(OP,S,param_reader,Except,Output,base_priority)
190  {
191 
192  param_reader.SetSubsection("reducednewtonalgorithm parameters");
193  nonlinear_maxiter_ = param_reader.get_integer ("nonlinear_maxiter");
194  nonlinear_tol_ = param_reader.get_double ("nonlinear_tol");
195  nonlinear_global_tol_ = param_reader.get_double ("nonlinear_global_tol");
196 
197  linear_maxiter_ = param_reader.get_integer ("linear_maxiter");
198  linear_tol_ = param_reader.get_double ("linear_tol");
199  linear_global_tol_ = param_reader.get_double ("linear_global_tol");
200 
201  line_maxiter_ = param_reader.get_integer ("line_maxiter");
202  lineasearch_rho_ = param_reader.get_double ("linesearch_rho");
203  linesearch_c_ = param_reader.get_double ("linesearch_c");
204 
205  compute_functionals_in_every_step_ = param_reader.get_bool ("compute_functionals_in_every_step");
206 
207  postindex_ = "_"+this->GetProblem()->GetName();
208  }
209 
210 /******************************************************/
211 
212 template <typename PROBLEM, typename VECTOR>
214  {
215 
216  }
217 
218 /******************************************************/
219 
220 template <typename PROBLEM, typename VECTOR>
222 {
223  //Solve j'(q) = 0
224  ControlVector<VECTOR> gradient(q), gradient_transposed(q);
225 
226  try
227  {
228  this->GetReducedProblem()->ComputeReducedCostFunctional(q);
229  }
230  catch(DOpEException& e)
231  {
232  this->GetExceptionHandler()->HandleCriticalException(e,"ReducedNewtonAlgorithm::NewtonResidual");
233  }
234 
235  try
236  {
237  this->GetReducedProblem()->ComputeReducedGradient(q,gradient,gradient_transposed);
238  }
239  catch(DOpEException& e)
240  {
241  this->GetExceptionHandler()->HandleCriticalException(e,"ReducedNewtonAlgorithm::NewtonResidual");
242  }
243 
244  return sqrt(Residual(gradient,gradient_transposed));
245 }
246 
247 /******************************************************/
248 
249 template <typename PROBLEM, typename VECTOR>
251 {
252 
253  q.ReInit();
254  //Solve j'(q) = 0
255  ControlVector<VECTOR> dq(q), gradient(q), gradient_transposed(q);
256 
257  unsigned int iter=0;
258  double cost=0.;
259  std::stringstream out;
260  this->GetOutputHandler()->InitNewtonOut(out);
261 
262  out << "**************************************************\n";
263  out << "* Starting Reduced Newton Algorithm *\n";
264  out << "* Solving : "<<this->GetProblem()->GetName()<<"\t*\n";
265  out << "* CDoFs : ";
266  q.PrintInfos(out);
267  out << "* SDoFs : ";
268  this->GetReducedProblem()->StateSizeInfo(out);
269  out << "**************************************************";
270  this->GetOutputHandler()->Write(out,1+this->GetBasePriority(),1,1);
271 
272  this->GetOutputHandler()->SetIterationNumber(iter,"OptNewton"+postindex_);
273 
274  this->GetOutputHandler()->Write(q,"Control"+postindex_,"control");
275 
276  try
277  {
278  cost = this->GetReducedProblem()->ComputeReducedCostFunctional(q);
279  }
280  catch(DOpEException& e)
281  {
282  this->GetExceptionHandler()->HandleCriticalException(e,"ReducedNewtonAlgorithm::Solve");
283  }
284 
285  out<< "CostFunctional: " << cost;
286  this->GetOutputHandler()->Write(out,2+this->GetBasePriority());
287 
288  if (compute_functionals_in_every_step_ == true)
289  {
290  try
291  {
292  this->GetReducedProblem()->ComputeReducedFunctionals(q);
293  }
294  catch(DOpEException& e)
295  {
296  this->GetExceptionHandler()->HandleCriticalException(e);
297  }
298  }
299 
300  try
301  {
302  this->GetReducedProblem()->ComputeReducedGradient(q,gradient,gradient_transposed);
303  }
304  catch(DOpEException& e)
305  {
306  this->GetExceptionHandler()->HandleCriticalException(e,"ReducedNewtonAlgorithm::Solve");
307  }
308 
309  double res = Residual(gradient,gradient_transposed);//gradient*gradient_transposed;
310  double firstres = res;
311 
312  assert(res >= 0);
313 
314  this->GetOutputHandler()->Write(gradient,"NewtonResidual"+postindex_,"control");
315  out<< "\t Newton step: " <<iter<<"\t Residual (abs.): "<<sqrt(res)<<"\n";
316  out<< "\t Newton step: " <<iter<<"\t Residual (rel.): "<<std::scientific<<sqrt(res)/sqrt(res)<<"\n";
317  this->GetOutputHandler()->Write(out,3+this->GetBasePriority());
318  int liniter = 0;
319  int lineiter =0;
320  unsigned int miniter = 0;
321  if(global_tol > 0.)
322  miniter = 1;
323 
324  global_tol = std::max(nonlinear_global_tol_,global_tol);
325  while(( (res >= global_tol*global_tol) && (res >= nonlinear_tol_*nonlinear_tol_*firstres) ) || iter < miniter )
326  {
327  iter++;
328  this->GetOutputHandler()->SetIterationNumber(iter,"OptNewton"+postindex_);
329 
330  if(iter > nonlinear_maxiter_)
331  {
332  throw DOpEIterationException("Iteration count exceeded bounds!","ReducedNewtonAlgorithm::Solve");
333  }
334 
335  //Compute a search direction
336  try
337  {
338  liniter = SolveReducedLinearSystem(q,gradient,gradient_transposed, dq);
339  }
340  catch(DOpEIterationException& e)
341  {
342  //Seems uncritical too many linear solves, it'll probably work
343  //So only write a warning, and continue.
344  this->GetExceptionHandler()->HandleException(e,"ReducedNewtonAlgorithm::Solve");
345  liniter = -1;
346  }
348  {
349  this->GetExceptionHandler()->HandleException(e,"ReducedNewtonAlgorithm::Solve");
350  lineiter = -2;
351  }
352  catch(DOpEException& e)
353  {
354  this->GetExceptionHandler()->HandleCriticalException(e,"ReducedNewtonAlgorithm::Solve");
355  }
356  //Linesearch
357  try
358  {
359  lineiter = ReducedNewtonLineSearch(dq,gradient,cost,q);
360  }
361  catch(DOpEIterationException& e)
362  {
363  //Seems uncritical too many line search steps, it'll probably work
364  //So only write a warning, and continue.
365  this->GetExceptionHandler()->HandleException(e,"ReducedNewtonAlgorithm::Solve");
366  lineiter = -1;
367  }
368  //catch(DOpEException& e)
369  //{
370  // this->GetExceptionHandler()->HandleCriticalException(e);
371  //}
372 
373  out<< "CostFunctional: " << cost;
374  this->GetOutputHandler()->Write(out,3+this->GetBasePriority());
375 
376  if (compute_functionals_in_every_step_ == true)
377  {
378  try
379  {
380  this->GetReducedProblem()->ComputeReducedFunctionals(q);
381  }
382  catch(DOpEException& e)
383  {
384  this->GetExceptionHandler()->HandleCriticalException(e);
385  }
386  }
387 
388 
389  //Prepare the next Iteration
390  try
391  {
392  this->GetReducedProblem()->ComputeReducedGradient(q,gradient,gradient_transposed);
393  }
394  catch(DOpEException& e)
395  {
396  this->GetExceptionHandler()->HandleCriticalException(e,"ReducedNewtonAlgorithm::Solve");
397  }
398 
399  this->GetOutputHandler()->Write(q,"Control"+postindex_,"control");
400  this->GetOutputHandler()->Write(gradient,"NewtonResidual"+postindex_,"control");
401 
402  res = Residual(gradient,gradient_transposed);//gradient*gradient_transposed;
403 
404  out<<"\t Newton step: " <<iter<<"\t Residual (rel.): "<<this->GetOutputHandler()->ZeroTolerance(sqrt(res)/sqrt(firstres),1.0)<< "\t LinearIters ["<<liniter<<"]\t LineSearch {"<<lineiter<<"} ";
405  this->GetOutputHandler()->Write(out,3+this->GetBasePriority());
406  }
407 
408  //We are done write total evaluation
409  out<< "CostFunctional: " << cost;
410  this->GetOutputHandler()->Write(out,2+this->GetBasePriority());
411  try
412  {
413  this->GetReducedProblem()->ComputeReducedFunctionals(q);
414  }
415  catch(DOpEException& e)
416  {
417  this->GetExceptionHandler()->HandleCriticalException(e,"ReducedNewtonAlgorithm::Solve");
418  }
419 
420  out << "**************************************************\n";
421  out << "* Stopping Reduced Newton Algorithm *\n";
422  out << "* after "<<std::setw(6)<<iter<<" Iterations *\n";
423  out.precision(4);
424  out << "* with rel. Residual "<<std::scientific << std::setw(11) << this->GetOutputHandler()->ZeroTolerance(sqrt(res)/sqrt(firstres),1.0)<<" *\n";
425  out.precision(10);
426  out << "**************************************************";
427  this->GetOutputHandler()->Write(out,1+this->GetBasePriority(),1,1);
428  return iter;
429 }
430 
431 /******************************************************/
432 
433 template <typename PROBLEM, typename VECTOR>
435  const ControlVector<VECTOR>& gradient,
436  const ControlVector<VECTOR>& gradient_transposed,
438 {
439  std::stringstream out;
440  dq = 0.;
441  ControlVector<VECTOR> r(q), r_transposed(q), d(q), Hd(q), Hd_transposed(q);
442 
443  r = gradient;
444  r_transposed = gradient_transposed;
445  d = gradient_transposed;
446 
447  double res = Residual(r,r_transposed);//r*r_transposed;
448  double firstres = res;
449 
450  assert(res >= 0.);
451 
452  out << "Starting Reduced Linear Solver with Residual: "<<sqrt(res);
453  this->GetOutputHandler()->Write(out,4+this->GetBasePriority());
454 
455  unsigned int iter = 0;
456  double cgalpha, cgbeta, oldres;
457 
458  this->GetOutputHandler()->SetIterationNumber(iter,"OptNewtonCg"+postindex_);
459 
460  //while(res>=linear_tol_*linear_tol_*firstres && res>=linear_global_tol_*linear_global_tol_)
461  //using Algorithm 6.1 from Nocedal Wright
462  while(res>= std::min(0.25,sqrt(firstres))*firstres && res>=linear_global_tol_*linear_global_tol_)
463  {
464  iter++;
465  this->GetOutputHandler()->SetIterationNumber(iter,"OptNewtonCg"+postindex_);
466  if(iter > linear_maxiter_)
467  {
468  throw DOpEIterationException("Iteration count exceeded bounds!","ReducedNewtonAlgorithm::SolveReducedLinearSystem");
469  }
470 
471  try
472  {
473  this->GetReducedProblem()->ComputeReducedHessianVector(q,d,Hd,Hd_transposed);
474  }
475  catch(DOpEException& e)
476  {
477  this->GetExceptionHandler()->HandleCriticalException(e,"ReducedNewtonAlgorithm::SolveReducedLinearSystem");
478  }
479 
480  cgalpha = res / (Hd*d);
481 
482  if(cgalpha < 0)
483  {
484  if(iter==1)
485  {
486  dq.add(cgalpha,d);
487  }
488  throw DOpENegativeCurvatureException("Negative curvature detected!","ReducedNewtonAlgorithm::SolveReducedLinearSystem");
489  }
490 
491  dq.add(cgalpha,d);
492  r.add(cgalpha,Hd);
493  r_transposed.add(cgalpha,Hd_transposed);
494 
495  oldres = res;
496  res = Residual(r,r_transposed);//r*r_transposed;
497  if(res < 0.)
498  {
499  //something is broken, maybe don't use update formula and
500  //calculate res from scratch.
501  try
502  {
503  this->GetReducedProblem()->ComputeReducedHessianVector(q,dq,Hd,Hd_transposed);
504  }
505  catch(DOpEException& e)
506  {
507  this->GetExceptionHandler()->HandleCriticalException(e);
508  }
509  r = gradient;
510  r_transposed = gradient_transposed;
511  r.add(1.,Hd);
512  r_transposed.add(1.,Hd_transposed);
513  res = Residual(r,r_transposed);
514  }
515  if(res < 0. && ( res > -1. *linear_global_tol_*linear_global_tol_ || res > -1.*std::min(0.25,sqrt(firstres))*firstres) )
516  {
517  //Ignore the wrong sign, it may be due to cancellations, and we would stop now.
518  //This is precisely what will happen if we just `correct' the sign of res
519  res = fabs(res);
520  out<<"\t There seem to be cancellation errors accumulating in the Residual,"<<std::endl;
521  out<<"\t and its norm gets negative. Since it is below the tolerance, we stop the iteration.";
522  this->GetOutputHandler()->Write(out,4+this->GetBasePriority());
523  }
524  assert(res >= 0.);
525  out<<"\t Cg step: " <<iter<<"\t Residual: "<<sqrt(res);
526  this->GetOutputHandler()->Write(out,4+this->GetBasePriority());
527 
528  cgbeta = res / oldres; //Fletcher-Reeves
529  d*= cgbeta;
530  d.equ(-1,r_transposed);
531  }
532  return iter;
533 }
534 
535 
536 /******************************************************/
537 
538 template <typename PROBLEM, typename VECTOR>
540  const ControlVector<VECTOR>& gradient,
541  double& cost,
543 {
544  double rho = lineasearch_rho_;
545  double c = linesearch_c_;
546 
547  double costnew = 0.;
548  bool force_linesearch = false;
549 
550  q+=dq;
551  try
552  {
553  costnew = this->GetReducedProblem()->ComputeReducedCostFunctional(q);
554  }
555  catch(DOpEException& e)
556  {
557 // this->GetExceptionHandler()->HandleException(e);
558  force_linesearch = true;
559  this->GetOutputHandler()->Write("Computing Cost Failed",4+this->GetBasePriority());
560  }
561 
562  double alpha=1;
563  unsigned int iter =0;
564 
565  double reduction = gradient*dq;
566  if(reduction > 0)
567  {
568  this->GetOutputHandler()->WriteError("Waring: computed direction doesn't seem to be a descend direction!");
569  reduction = 0;
570  }
571 
572  if(line_maxiter_ > 0)
573  {
574  if(fabs(reduction) < 1.e-10*cost)
575  reduction = 0.;
576  if(std::isinf(costnew) || std::isnan(costnew) || (costnew >= cost + c*alpha*reduction) || force_linesearch)
577  {
578  this->GetOutputHandler()->Write("\t linesearch ",4+this->GetBasePriority());
579  while(std::isinf(costnew) || std::isnan(costnew) || (costnew >= cost + c*alpha*reduction) || force_linesearch)
580  {
581  iter++;
582  if(iter > line_maxiter_)
583  {
584  if(force_linesearch)
585  {
586  throw DOpEException("Iteration count exceeded bounds while unable to compute the CostFunctional!","ReducedNewtonAlgorithm::ReducedNewtonLineSearch");
587  }
588  else
589  {
590  cost = costnew;
591  throw DOpEIterationException("Iteration count exceeded bounds!","ReducedNewtonAlgorithm::ReducedNewtonLineSearch");
592  }
593  }
594  force_linesearch = false;
595  q.add(alpha*(rho-1.),dq);
596  alpha *= rho;
597 
598  try
599  {
600  costnew = this->GetReducedProblem()->ComputeReducedCostFunctional(q);
601  }
602  catch(DOpEException& e)
603  {
604  //this->GetExceptionHandler()->HandleException(e);
605  force_linesearch = true;
606  this->GetOutputHandler()->Write("Computing Cost Failed",4+this->GetBasePriority());
607  }
608  }
609  }
610  cost = costnew;
611  }
612 
613  return iter;
614 
615 }
616 
617 
618 }
619 #endif
Definition: dopeexception.h:76
void PrintInfos(std::stringstream &out)
Definition: controlvector.cc:896
ReducedNewtonAlgorithm(PROBLEM *OP, ReducedProblemInterface< PROBLEM, VECTOR > *S, ParameterReader &param_reader, DOpEExceptionHandler< VECTOR > *Except=NULL, DOpEOutputHandler< VECTOR > *Output=NULL, int base_priority=0)
Definition: reducednewtonalgorithm.h:183
double get_double(const std::string &entry_name)
Definition: parameterreader.h:115
Definition: dopeexception.h:90
bool get_bool(const std::string &entry_name)
Definition: parameterreader.h:148
Definition: parameterreader.h:36
Definition: optproblemcontainer.h:70
virtual ~ReducedNewtonAlgorithm()
Definition: reducednewtonalgorithm.h:213
virtual double Residual(const ControlVector< VECTOR > &gradient, const ControlVector< VECTOR > &gradient_transposed)
Definition: reducednewtonalgorithm.h:143
void declare_entry(const std::string &entry, const std::string &default_value, const Patterns::PatternBase &pattern=Patterns::Anything(), const std::string &documentation=std::string())
Definition: parameterreader.h:98
Definition: controlvector.h:49
Definition: reducednewtonalgorithm.h:50
PROBLEM * GetProblem()
Definition: reducedalgorithm.h:187
virtual int Solve(ControlVector< VECTOR > &q, double global_tol=-1.)
Definition: reducednewtonalgorithm.h:250
virtual int SolveReducedLinearSystem(const ControlVector< VECTOR > &q, const ControlVector< VECTOR > &gradient, const ControlVector< VECTOR > &gradient_transposed, ControlVector< VECTOR > &dq)
Definition: reducednewtonalgorithm.h:434
Definition: reducedalgorithm.h:54
void add(double s, const ControlVector &dq)
Definition: controlvector.cc:629
void ReInit()
Definition: controlvector.cc:96
static void declare_params(ParameterReader &param_reader)
Definition: reducedalgorithm.h:241
virtual int ReducedNewtonLineSearch(const ControlVector< VECTOR > &dq, const ControlVector< VECTOR > &gradient, double &cost, ControlVector< VECTOR > &q)
Definition: reducednewtonalgorithm.h:539
int get_integer(const std::string &entry_name)
Definition: parameterreader.h:126
static void declare_params(ParameterReader &param_reader)
Definition: reducednewtonalgorithm.h:161
void SetSubsection(const std::string subsection)
Definition: parameterreader.h:93
Definition: reducedprobleminterface.h:335
Definition: dopeexception.h:35
double NewtonResidual(const ControlVector< VECTOR > &q)
Definition: reducednewtonalgorithm.h:221
Definition: optproblemcontainer.h:72