KASKADE 7 development version
cgImplementation.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2002-2013 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef CG_IMPLEMENTATION_HH
14#define CG_IMPLEMENTATION_HH
15
16#include <iostream>
17#include <memory>
18
19#include "algorithm/opt_aux/src/include/Fmin.h"
20
21#include "boost/timer/timer.hpp"
22#include "utilities/scalar.hh"
24
25namespace Kaskade
26{
28
29 namespace CG_Detail
30 {
31 template <class X, class Xstar, class Derived>
33 {
35
36 Regularization(double eps_, int verbose_) : eps(eps_), verbose(verbose_)
37 {}
38
40 {
41 theta = 0;
42 }
43
44 void regularize(double& qAq, double qPq)
45 {
46 qAq += theta*qPq;
47 }
48
49 void updateRegularization(double qAq, double qPq)
50 {
51 double oldTheta = theta > 0 ? theta : eps;
52 theta += (1-qAq)/std::fabs(qPq);
53 if( verbose > 0 ) std::cout << "Regularization: Computed theta: " << theta << std::endl;
54 theta = std::min(std::max(2*oldTheta,theta),1e2*oldTheta);
55 if( verbose > 0 ) std::cout << "Regularization: Updating theta from " << oldTheta << " to " << theta << std::endl;
56 }
57
58 void adjustResidual(Xstar& r, double alpha, Xstar const& Pq)
59 {
60 r.axpy(-alpha*theta,Pq);
61 }
62
63 Real theta = 0, eps = 1e-16;
64 int verbose = 0;
65 };
66
67 template <class X, class Xstar, class>
69 {
70 NoRegularization(double,int) {}
71
73 void regularize(double&, double) {}
74 void updateRegularization(double,double) {}
75 void adjustResidual(Xstar&,double,Xstar const&) {}
76
77 };
78
79 template <class X, class Xstar, class Derived, CGImplementationType impl>
81 {
82 typedef typename std::conditional< (impl == CGImplementationType::STANDARD || impl == CGImplementationType::TRUNCATED ),
86 };
87 }
88
89
91 {
92 void resumeMVTimer() {}
93 void resumeDPTimer() {}
94 void resumeAPTimer() {}
95 void resumePRTimer() {}
96
97 void stopMVTimer() {}
98 void stopDPTimer() {}
99 void stopAPTimer() {}
100 void stopPRTimer() {}
101
102 void printTimers() {}
103 };
104
106 {
108 {
109 mvTimer.stop();
110 dpTimer.stop();
111 apTimer.stop();
112 prTimer.stop();
113 }
114
115 void resumeMVTimer() { mvTimer.resume(); }
116 void resumeDPTimer() { dpTimer.resume(); }
117 void resumeAPTimer() { apTimer.resume(); }
118 void resumePRTimer() { prTimer.resume(); }
119
120 void stopMVTimer() { mvTimer.stop(); }
121 void stopDPTimer() { dpTimer.stop(); }
122 void stopAPTimer() { apTimer.stop(); }
123 void stopPRTimer() { prTimer.stop(); }
124
126 {
127
128 std::cout << "Matrix-Vector time: " << mvTimer.format()
129 << "dual pairings : " << dpTimer.format()
130 << "vector ops : " << apTimer.format()
131 << "preconditioner : " << prTimer.format() << '\n';
132 }
133
134 private:
135 boost::timer::cpu_timer mvTimer;
136 boost::timer::cpu_timer dpTimer;
137 boost::timer::cpu_timer apTimer;
138 boost::timer::cpu_timer prTimer;
139 };
140
142 {
143 template <typename... Args>
144 void init(const Args&...){}
145
146 double operator()() { return 1; }
147 };
148
150 {
151 CGFminModel() = default;
152 CGFminModel(CGFminModel const&) = default;
154
155 CGFminModel(double quadraticPart_, double linearPart_, double omegaL_,
156 double dndn_, double dnd_, double dd_)
157 : linearPart(linearPart_), quadraticPart(quadraticPart_), omegaL(omegaL_),
158 dndn(dndn_), dnd(dnd_), dd(dd_)
159 {}
160
161 double operator()(double t)
162 {
163 double normSquared = dndn + t*dnd + t*t*dd;
164 return t*linearPart + 0.5*t*t*quadraticPart + pow(normSquared,1.5);
165 }
166
167 double linearPart = 0, quadraticPart = 0, omegaL = 0, dndn = 0, dnd = 0, dd = 0;
168 };
169
174 template <class POperator, class Vector>
176 {
177 AlwaysRegularizeWithThetaGuess(POperator const& P_, Vector const& dn_, double nu_, double omegaL_) : P(P_), dn(dn_), omegaL(omegaL_), nu(nu_)
178 {}
179
180 template <class Operator, class Rhs, class DualPairing>
181 void init(Operator const& A, Rhs const& rhs, Vector const& d, DualPairing const& dp)
182 {
183 Rhs Ad(rhs), Adn(rhs);
184 A.apply(d,Ad);
185 A.apply(dn,Adn);
186 double dAd = dp(d,Ad);
187 double lin = dp(d,rhs) + nu*dp(d,Adn);
188
189 Rhs Pd(rhs), Pdn(rhs);
190 P.apply(d,Pd);
191 P.apply(dn,Pdn);
192 double dndn = nu*nu*dp(dn,dn),
193 dnd = nu*dp(d,dn),
194 dd = dp(d,d);
195
196
197 model = CGFminModel(dAd,lin,omegaL,dndn,dnd,dd);
198 }
199
200 double operator()()
201 {
202 return Fmin(0.,1.,model,1e-3);
203 }
204
205 POperator const& P;
206 Vector const& dn;
207 double omegaL, nu;
209 };
210
221 template<class X, class Xstar, CGImplementationType impl = CGImplementationType::STANDARD, class TimerPolicy = DoNotMeasureTime, class Functor = DoNotAlwaysRegularize>
222 class CGBase
223 : public Dune::InverseOperator<X,Xstar>
224 , public TimerPolicy
225 , public CG_Detail::ChooseRegularization<X,Xstar,CGBase<X,Xstar,impl,TimerPolicy>,impl>::type
226 {
227 enum class Result { Converged, Failed, EncounteredNonConvexity, TruncatedAtNonConvexity };
228
229 public:
234
240 CGBase(Dune::LinearOperator<X,Xstar>& op_, Dune::Preconditioner<X,Xstar>& prec_, DualPairing<X,Xstar> const& dp_, PCGTerminationCriterion<Real>& terminate_, int verbose_ = 0, double eps_ = 1e-15)
241 : CG_Detail::ChooseRegularization<X,Xstar,CGBase<X,Xstar,impl,TimerPolicy>,impl>::type(eps_,verbose_),
242 op(op_), prec(prec_), dp(dp_), terminate(terminate_), verbose(verbose_), eps(eps_)
243 {}
244
245 CGBase(Dune::LinearOperator<X,Xstar>& op_, Dune::Preconditioner<X,Xstar>& prec_, DualPairing<X,Xstar> const& dp_, PCGTerminationCriterion<Real>& terminate_, Functor f_, int verbose_ = 0, double eps_ = 1e-15)
246 : CG_Detail::ChooseRegularization<X,Xstar,CGBase<X,Xstar,impl,TimerPolicy>,impl>::type(eps_,verbose_),
247 op(op_), prec(prec_), dp(dp_), terminate(terminate_), verbose(verbose_), eps(eps_), f(f_)
248 {}
249
250
251 void apply (X& u, Xstar& b)
252 {
253 Dune::InverseOperatorResult res;
254 apply(u,b,res);
255 }
256
263 virtual void apply(X& u, Xstar&b, Real tolerance, Dune::InverseOperatorResult& res)
264 {
265 terminate.setTolerance(tolerance);
266 apply(u,b,res);
267 }
268
269 virtual void apply(X& u, Xstar& b, Dune::InverseOperatorResult& res)
270 {
271 int step = 0;
272 if( impl == CGImplementationType::STANDARD || impl == CGImplementationType::TRUNCATED ) step = cgLoop(u,b,res);
273 else
274 {
275 X u0(u);
276 Xstar b0(b);
277 result = Result::Failed;
278 while( result != Result::Converged && result != Result::TruncatedAtNonConvexity )
279 {
280 u = u0;
281 b = b0;
282 step = cgLoop(u,b,res);
283 }
284 }
285
286 if (verbose>0) // final print
287 {
288 std::cout << "=== rate=" << res.conv_rate
289 << ", T=" << res.elapsed
290 << ", TIT=" << res.elapsed/step
291 << ", IT=" << step << std::endl;
292
293 this->printTimers();
294 }
295 }
296
297 int cgLoop (X& u, Xstar& b, Dune::InverseOperatorResult& res)
298 {
299 Dune::Timer watch;
300 terminate.clear(); // clear termination criterion
301
302 result = Result::Failed;
303 res.converged = false;
304 prec.pre(u,b);
305
306 int step = 0;
307 const int maxNoiterations=terminate.getMaxIterationSteps();
308
309 Xstar r(b);
310 op.applyscaleadd(-1,u,r); // r = b-Au
311 std::unique_ptr<X> rq(new X(u)); *rq = 0;
312
313 this->resumePRTimer();
314 prec.apply(*rq,r); // rq = B^{-1} r
315 this->stopPRTimer();
316 std::unique_ptr<X> q(new X(*rq));
317 X Aq(b);
318
319 Xstar Pq(r);
320
321 // some local variables
322 Real alpha = 0, beta = 0, energyNorm2 = 0;
323 Real sigma = std::abs(dp(*rq,r)); // preconditioned residual norm squared
324 double const sigma0 = sigma;
325
326 if (verbose>0) { // printing
327 std::cout << "=== Kaskade7 IterateType::CG" << std::endl;
328 if (verbose>0) {
329 this->printHeader(std::cout);
330 this->printOutput(std::cout,(double)0,sigma0);
331 }
332 }
333
334 // monitor proposal for initial theta
335 if(!std::is_same<Functor,DoNotAlwaysRegularize>::value)
336 {
337 f.init(op,b,*q,dp);
338 double tau = f();
339 Xstar Hd(b);
340 op.apply(*q,Hd);
341 double dHd = dp(*q,Hd);
342
343 double initialThetaGuess = 1./tau - dHd/sigma;
344 std::cout << "CG: TAU = " << tau << std::endl;
345 std::cout << "CG: INITIAL GUESS FOR THETA = " << initialThetaGuess << std::endl;
346 }
347 // (sigma/tau - dHd)/dPd;
348
349 // the loop
350 for ( step = 1; step<=maxNoiterations; step++ )
351 {
352 // minimize in given search direction p
353 this->resumeMVTimer();
354 op.apply(*q,Aq);
355 this->stopMVTimer();
356
357 this->resumeDPTimer();
358 Real qAq = dp(*q,Aq);
359 Real qPq = dp(*q,Pq);
360 this->stopDPTimer();
361 this->regularize(qAq,qPq);
362
363 alpha = sigma/qAq;
364 energyNorm2 += alpha*qAq;
365
366 // don't trust small numbers
367 if( std::fabs(qAq) < eps*eps )
368 {
369 if( verbose > 0 ) std::cout << pre << "Terminating due to numerically almost vanishing step." << std::endl;
370 result = Result::Converged;
371 res.converged = true;
372 break;
373 }
374
375 if( qAq < 0 )
376 {
378 {
379 std::cout << pre << "Direction of negative curvature encountered in standard IterateType::CG implementation!" << std::endl;
380 std::cout << pre << "Either something is wrong with your operator or you should use TCG, RCG or HCG. Terminating IterateType::CG!" << std::endl;
381// result = Result::EncounteredNonConvexity;
382// break;
383 }
384
386 {
387 // At least do something to retain a little chance to get out of the nonconvexity. In fact if a nonconvexity is encountered in the first step something probably went wrong
388 // elsewhere. Chances that a way out of the nonconvexity can be found are small in this case.
389 if( step == 1 ) u.axpy(1.0,*q);
390 if( verbose > 0 ) std::cout << pre << "Truncating at nonconvexity in iteration " << step << ": " << qAq << std::endl;
391 result = Result::TruncatedAtNonConvexity;
392 break;
393 }
394
396 {
397 this->updateRegularization(qAq,qPq);
398 if( verbose > 0 ) std::cout << pre << "Regularizing at nonconvexity in iteration " << step << "." << std::endl;
399 result = Result::EncounteredNonConvexity;
400 break;
401 }
402 }
403
404 terminate.addStepQuantities(alpha,qAq,qPq,sigma);
405
406 this->resumeAPTimer();
407 u.axpy(alpha,*q);
408 this->stopAPTimer();
409
410 // convergence test
411 if (terminate)
412 {
413 result = Result::Converged;
414 res.converged = true;
415 break;
416 }
417
418 this->resumeAPTimer();
419 r.axpy(-alpha,Aq); // r = r - alpha*A*q
420 this->adjustResidual(r,alpha,Pq);
421 this->stopAPTimer();
422
423 this->resumePRTimer();
424 prec.apply(*rq,r);
425 this->stopPRTimer();
426
427 // determine new search direction
428 this->resumeDPTimer();
429 double sigmaNew = std::abs(dp(*rq,r));
430 this->stopDPTimer();
431 if (verbose>1) this->printOutput(std::cout,(double)step,std::abs(sigmaNew),std::abs(sigma));
432
433 beta = sigmaNew/sigma;
434 sigma = sigmaNew;
435 this->resumeAPTimer();
436 rq->axpy(beta,*q); // compute q = rq + beta*q
437 this->stopAPTimer();
438 Pq *= beta;
439 Pq += r;
440 std::swap(rq,q);
441 }
442
443 prec.post(u);
444
445 if (verbose>0) this->printOutput(std::cout,(double)step,std::abs(sigma));
446 res.iterations = step; // fill statistics
447 res.reduction = std::sqrt(std::abs(sigma)/sigma0);
448 res.conv_rate = pow(res.reduction,1.0/step);
449 res.elapsed = watch.elapsed();
450
451 return step;
452 }
453
454 bool encounteredNonConvexity() const { return result==Result::EncounteredNonConvexity || result==Result::TruncatedAtNonConvexity; }
455
456 double getSolutionEnergyNormEstimate() { return sqrt(energyNorm2); }
457
463 virtual Dune::SolverCategory::Category category() const override
464 {
465 return Dune::SolverCategory::sequential;
466 }
467
468 private:
469 Dune::LinearOperator<X,Xstar>& op;
470 Dune::Preconditioner<X,Xstar>& prec;
471 DualPairing<X,Xstar> const& dp;
473 int verbose;
474 Result result;
475 double eps, energyNorm2;
476 std::string pre = std::string("KASKADE IterateType::PCG: ");
477 Functor f;
478 };
479} // namespace Kaskade
480#endif
regularized preconditioned conjugate gradient method
virtual void apply(X &u, Xstar &b, Real tolerance, Dune::InverseOperatorResult &res)
ScalarTraits< typenameGetScalar< X >::type >::Real Real
the real field type corresponding to X::field_type or X::Scalar
virtual Dune::SolverCategory::Category category() const override
returns the category of the operator
CGBase(Dune::LinearOperator< X, Xstar > &op_, Dune::Preconditioner< X, Xstar > &prec_, DualPairing< X, Xstar > const &dp_, PCGTerminationCriterion< Real > &terminate_, Functor f_, int verbose_=0, double eps_=1e-15)
bool encounteredNonConvexity() const
virtual void apply(X &u, Xstar &b, Dune::InverseOperatorResult &res)
void apply(X &u, Xstar &b)
CGBase(Dune::LinearOperator< X, Xstar > &op_, Dune::Preconditioner< X, Xstar > &prec_, DualPairing< X, Xstar > const &dp_, PCGTerminationCriterion< Real > &terminate_, int verbose_=0, double eps_=1e-15)
Set up conjugate gradient solver with termination criterion.
int cgLoop(X &u, Xstar &b, Dune::InverseOperatorResult &res)
double getSolutionEnergyNormEstimate()
Abstract base class for dual pairing of and its dual space .
virtual void setTolerance(Real tol)=0
set requested tolerance
virtual void clear()=0
re-initializes the termination criterion for a new IterateType::CG run
virtual int getMaxIterationSteps()=0
get the maximum number of allowed iteration steps
virtual void addStepQuantities(Real stepLength, Real qAq, Real qPq, Real rPINVr)=0
addStepQuantities supplies algorithmic quantities to the termination criterion
Helper class for working with (real or complex) scalar field types.
Definition: scalar.hh:36
Dune::FieldVector< T, n > max(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise maximum.
Definition: fixdune.hh:110
Dune::FieldVector< T, n > min(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise minimum.
Definition: fixdune.hh:122
Dune::FieldVector< Scalar, dim > Vector
void init(Operator const &A, Rhs const &rhs, Vector const &d, DualPairing const &dp)
AlwaysRegularizeWithThetaGuess(POperator const &P_, Vector const &dn_, double nu_, double omegaL_)
std::conditional<(impl==CGImplementationType::STANDARD||impl==CGImplementationType::TRUNCATED), NoRegularization< X, Xstar, Derived >, Regularization< X, Xstar, Derived > >::type type
void adjustResidual(Xstar &, double, Xstar const &)
ScalarTraits< typenameGetScalar< X >::type >::Real Real
void regularize(double &qAq, double qPq)
void updateRegularization(double qAq, double qPq)
void adjustResidual(Xstar &r, double alpha, Xstar const &Pq)
Regularization(double eps_, int verbose_)
CGFminModel & operator=(CGFminModel const &)=default
CGFminModel(double quadraticPart_, double linearPart_, double omegaL_, double dndn_, double dnd_, double dd_)
CGFminModel(CGFminModel const &)=default
double operator()(double t)