14#include <dune/common/float_cmp.hh>
15#include <dune/functions/common/signature.hh>
17#include <spdlog/spdlog.h>
19#include <Eigen/Sparse>
46 double maxtime = std::numeric_limits<double>::infinity();
55 double Delta_bar = std::numeric_limits<double>::infinity();
64template <PreConditioner preConditioner = PreConditioner::IncompleteCholesky,
typename UF = utils::UpdateDefault>
67 static_assert(std::copy_constructible<UF>,
68 " The update function should be copy constructable. If it is a lambda wrap it in a std::function");
75 template <
typename UF2>
84 typename UF = utils::UpdateDefault>
95template <
typename F,
typename TRConfig>
96requires traits::isSpecializationNonTypeAndTypes<TrustRegionConfig, std::remove_cvref_t<TRConfig>>::value
98 static constexpr PreConditioner preConditioner = std::remove_cvref_t<TRConfig>::preConditionerType;
99 using UF = std::remove_cvref_t<TRConfig>::UpdateFunction;
100 static_assert(std::remove_cvref_t<F>::nDerivatives == 2,
101 "The number of derivatives in the DifferentiableFunction have to be exactly 2.");
102 auto solver = std::make_shared<TrustRegion<F, preConditioner, UF>>(f, std::forward<TRConfig>(config).updateFunction);
104 solver->setup(config.parameters);
169template <
typename F, PreConditioner preConditioner,
typename UF>
192 template <
typename UF2 = UF>
194 : energyFunction_{f},
195 updateFunction_{std::forward<UF2>(updateFunction)} {}
202 settings_ = settings;
203 assert(settings_.
rho_prime < 0.25 &&
"options.rho_prime must be strictly smaller than 1/4.");
204 assert(settings_.
Delta_bar > 0 &&
"options.Delta_bar must be positive.");
206 "options.Delta0 must be positive and smaller than Delta_bar.");
224 auto& energyF = energyFunction_;
225 auto gradientF = derivative(energyF);
226 auto hessianF = derivative(gradientF);
227 decltype(
auto) e = energyF(x);
228 decltype(
auto) g = gradientF(x);
229 decltype(
auto) h = hessianF(x);
233 truncatedConjugateGradient_.analyzePattern(h);
236 truncatedConjugateGradient_.analyzePattern(h);
240 " | iter | inner_i | rho | energy | energy_p | energy_inc | norm(g) | Delta | norm(corr) | "
242 spdlog::info(
"{:-^143}",
"-");
243 while (not stoppingCriterion(e)) {
248 while (eta_.dot(h * eta_) > innerInfo_.
Delta * innerInfo_.
Delta)
255 solveInnerProblem(g, h);
266 const Eigen::VectorXd Hg = h * g;
267 const auto g_Hg = g.dot(Hg);
271 tauC = std::min(Dune::power(stats_.
gradNorm, 3) / (innerInfo_.
Delta * g_Hg), 1.0);
274 const Eigen::VectorXd etaC = -tauC * innerInfo_.
Delta / stats_.
gradNorm * g;
275 const Eigen::VectorXd HetaC = -tauC * innerInfo_.
Delta / stats_.
gradNorm * Hg;
277 const double mdle = stats_.
energy + g.dot(eta_) + .5 * Heta_.dot(eta_);
278 const double mdlec = stats_.
energy + g.dot(etaC) + .5 * HetaC.dot(etaC);
279 if (mdlec < mdle && stats_.
outerIter == 0) {
291 updateFunction_(x, eta_);
300 auto rhoden = -eta_.dot(g + 0.5 * Heta_);
305 const auto rhoReg = std::max(1.0, abs(stats_.
energy)) * eps_ * settings_.
rho_reg;
306 rhonum = rhonum + rhoReg;
307 rhoden = rhoden + rhoReg;
309 const bool modelDecreased = rhoden > 0.0;
314 stats_.
rho = rhonum / rhoden;
315 stats_.
rho = stats_.
rho < 0.0 ? -1.0 : stats_.
rho;
323 if (stats_.
rho < 1e-4 || not modelDecreased || std::isnan(stats_.
rho) || not energyDecreased) {
325 innerInfo_.
Delta /= 4.0;
330 spdlog::info(
" +++ Detected many consecutive TR- (radius decreases).");
331 spdlog::info(
" +++ Consider decreasing options.Delta_bar by an order of magnitude.");
342 spdlog::info(
" +++ Detected many consecutive TR+ (radius increases)");
343 spdlog::info(
" +++ Consider increasing options.Delta_bar by an order of magnitude");
351 if (modelDecreased && stats_.
rho > settings_.
rho_prime && energyDecreased) {
354 "Energy function increased by {} (step size: {}). Since this is small we accept the step and hope for "
355 "convergence of the gradient norm.",
366 innerInfo_.
Delta /= 2;
389 updateFunction_(x, -eta_);
408 return solverInformation;
414 auto&
energy() {
return energyFunction_; }
420 auto residual() {
return derivative(energyFunction_); }
424 constexpr auto make_optional_reference(T& value) {
425 return std::make_optional<std::reference_wrapper<const T>>(std::cref(value));
429 requires(not std::is_lvalue_reference_v<T>)
430 constexpr T make_optional_reference(T&& value) {
434 void logState()
const {
436 "{:>3s} {:>3s} {:>6d} {:>9d} {:>6.2f} {:>9.2e} {:>9.2e} {:>11.2e} {:>9.2e} {:>9.2e} {:>11.2e} "
443 void logFinalState() {
444 spdlog::info(
"{:>3s} {:>3s} {:>6d} {:>9d} {: ^6} {: ^9} {: ^9} {: ^11} {:>9.2e} {: ^9} {: ^11} {:<73}",
449 bool stoppingCriterion(
const auto&
energy) {
450 std::ostringstream stream;
454 spdlog::info(
"CONVERGENCE: Energy: {:1.16e} norm(gradient): {:1.16e}",
energy, stats_.
gradNorm);
455 stream <<
"Gradient norm tolerance reached; options.tolerance = " << settings_.
grad_tol;
463 spdlog::info(
"CONVERGENCE: Energy: {:1.16e} norm(correction): {:1.16e}",
energy, stats_.
etaNorm);
464 stream <<
"Displacement norm tolerance reached; = " << settings_.
corr_tol <<
"." << std::endl;
474 stream <<
"Max time exceeded; options.maxtime = " << settings_.
maxtime <<
".";
483 stream <<
"Max iteration count reached; options.maxiter = " << settings_.
maxIter <<
".";
491 void solveInnerProblem(
const auto& g,
const auto& h) {
492 truncatedConjugateGradient_.
setInfo(innerInfo_);
494 truncatedConjugateGradient_.factorize(h);
499 while (truncatedConjugateGradient_.info() != Eigen::Success) {
500 choleskyInitialShift_ *= 5;
501 truncatedConjugateGradient_.preconditioner().setInitialShift(choleskyInitialShift_);
502 truncatedConjugateGradient_.factorize(h);
504 DUNE_THROW(Dune::MathError,
"Factorization of preconditioner failed!");
507 if (truncatedConjugateGradient_.info() == Eigen::Success)
508 choleskyInitialShift_ = 1e-3;
510 eta_ = truncatedConjugateGradient_.solveWithGuess(-g, eta_);
511 innerInfo_ = truncatedConjugateGradient_.
getInfo();
517 std::remove_cvref_t<CorrectionType> eta_;
518 std::remove_cvref_t<CorrectionType> Heta_;
521 double choleskyInitialShift_ = 1e-3;
524 static constexpr double eps_ = 0.0001220703125;
525 std::array<std::string, 6> tcg_stop_reason_{
526 {
"negative curvature",
"exceeded trust region",
"reached target residual-kappa (linear)",
527 "reached target residual-theta (superlinear)",
"maximum inner iterations",
"model increased"}
530 using PreConditionerType =
533 typename Eigen::DiagonalPreconditioner<std::decay_t<EnergyType>>,
534 typename Eigen::IncompleteCholesky<std::decay_t<EnergyType>>>>;
536 truncatedConjugateGradient_;
550 typename UF = utils::UpdateDefault>
552 return std::make_shared<TrustRegion<F, preConditioner, UF>>(f, updateFunction);
556 typename UF2 = utils::UpdateDefault>
Contains stl-like type traits.
Collection of fallback default functions.
Helper for the autodiff library.
Implementation of the solver information returned by the nonlinear solvers.
Base for all nonlinear solvers.
Definition of TruncatedConjugateGradient class for solving linear systems using truncated conjugate g...
Implementation of the observer design pattern with broadcasters.
Enums for observer messages.
auto norm(const Eigen::MatrixBase< Derived > &v)
Adding free norm function to Eigen types.
Definition: linearalgebrahelper.hh:259
Definition: assemblermanipulatorbuildingblocks.hh:22
TrustRegion(const F &f, UF2 &&updateFunction={}) -> TrustRegion< F, preConditioner, std::remove_cvref_t< UF2 > >
::value auto createNonlinearSolver(NRConfig &&config, F &&f)
Function to create a NewtonRaphson solver instance.
Definition: newtonraphson.hh:82
auto makeTrustRegion(const F &f, UF &&updateFunction={})
Creates an instance of the TrustRegion solver.
Definition: trustregion.hh:551
NonLinearSolverMessages
Enum class defining non-linear solver-related messages.
Definition: broadcastermessages.hh:22
StopReason
Enumeration of reasons for stopping the TrustRegion solver.
Definition: trustregion.hh:113
@ maximumIterationsReached
@ correctionNormTolReached
PreConditioner
Enumeration of available preconditioners for the trust region solver.
Definition: trustregion.hh:37
Scalar Delta
Definition: truncatedconjugategradient.hh:38
TCGStopReason stop_tCG
Definition: truncatedconjugategradient.hh:37
Eigen::Index numInnerIter
Definition: truncatedconjugategradient.hh:43
Iterative solver for solving linear systems using the truncated conjugate gradient method.
Definition: truncatedconjugategradient.hh:196
TCGInfo< typename MatrixType::RealScalar > getInfo()
Get information about the truncated conjugate gradient algorithm.
Definition: truncatedconjugategradient.hh:227
void setInfo(TCGInfo< typename MatrixType::RealScalar > alginfo)
Set information about the truncated conjugate gradient algorithm.
Definition: truncatedconjugategradient.hh:233
Base for all nonlinear solvers. Defines the message interface that can be broadcasted to listeners.
Definition: nonlinearsolverbase.hh:24
State for nonlinear solvers.
Definition: nonlinearsolverstate.hh:24
const Domain & domain
Definition: nonlinearsolverstate.hh:28
Information about the result of a non-linear solver.
Definition: solverinfos.hh:21
double correctionNorm
Definition: solverinfos.hh:30
int iterations
Definition: solverinfos.hh:31
double residualNorm
Definition: solverinfos.hh:29
bool success
Definition: solverinfos.hh:28
Definition: trustregion.hh:44
double grad_tol
Gradient tolerance.
Definition: trustregion.hh:50
double Delta_bar
Maximum trust region radius.
Definition: trustregion.hh:55
double rho_reg
Regularization value for rho.
Definition: trustregion.hh:54
double Delta0
Initial trust region radius.
Definition: trustregion.hh:56
bool useRand
Flag for using random correction predictor.
Definition: trustregion.hh:53
int verbosity
Verbosity level.
Definition: trustregion.hh:45
int debug
Debugging flag.
Definition: trustregion.hh:49
int minIter
Minimum number of iterations.
Definition: trustregion.hh:47
double maxtime
Maximum allowable time for solving.
Definition: trustregion.hh:46
double corr_tol
Correction tolerance.
Definition: trustregion.hh:51
int maxIter
Maximum number of iterations.
Definition: trustregion.hh:48
double rho_prime
Rho prime value.
Definition: trustregion.hh:52
Definition: trustregion.hh:66
static constexpr PreConditioner preConditionerType
Definition: trustregion.hh:73
TRSettings parameters
Definition: trustregion.hh:72
UF UpdateFunction
Definition: trustregion.hh:70
UF updateFunction
Definition: trustregion.hh:74
auto rebindUpdateFunction(UF2 &&updateFunction) const
Definition: trustregion.hh:76
Trust Region solver for non-linear optimization problems.
Definition: trustregion.hh:173
UF UpdateFunction
Type of the update function.
Definition: trustregion.hh:180
typename FTraits::template Range< 0 > EnergyType
Type of the scalar cost.
Definition: trustregion.hh:183
auto residual()
Access the residual.
Definition: trustregion.hh:420
TrustRegion(const F &f, UF2 &&updateFunction={})
Constructs a TrustRegion solver instance.
Definition: trustregion.hh:193
typename FTraits::template Range< 2 > HessianType
Type of the Hessian matrix.
Definition: trustregion.hh:185
typename FTraits::template Range< 1 > GradientType
Type of the gradient vector.
Definition: trustregion.hh:184
F DifferentiableFunction
Type of function to minimize.
Definition: trustregion.hh:181
typename FTraits::Domain Domain
Type of the parameter vector of.
Definition: trustregion.hh:178
typename FTraits::template Range< 1 > CorrectionType
Type of the correction of x += deltaX.
Definition: trustregion.hh:179
TRSettings Settings
Type of the settings for the TrustRegion solver.
Definition: trustregion.hh:175
void setup(const Settings &settings)
Sets up the TrustRegion solver with the provided settings and checks feasibility.
Definition: trustregion.hh:201
NonLinearSolverInformation solve(Domain &x)
Solves the nonlinear optimization problem using the TrustRegion algorithm.
Definition: trustregion.hh:214
typename F::Traits FTraits
Definition: trustregion.hh:177
auto & energy()
Access the energy function.
Definition: trustregion.hh:414
Additional information about the TrustRegion algorithm.
Definition: trustregion.hh:126
std::string cauchystr
Used Cauchy step string.
Definition: trustregion.hh:134
StopReason stop
Stopping reason.
Definition: trustregion.hh:137
std::string randomPredictionString
Random prediction string.
Definition: trustregion.hh:133
bool acceptProposal
Flag indicating whether the proposal is accepted.
Definition: trustregion.hh:135
std::string reasonString
String describing the stopping reason.
Definition: trustregion.hh:138
int consecutive_TRminus
Consecutive trust region decreases.
Definition: trustregion.hh:128
bool used_cauchy
Flag indicating whether Cauchy point was used.
Definition: trustregion.hh:136
int consecutive_Rejected
Consecutive rejected proposals.
Definition: trustregion.hh:129
std::string trstr
Trust region change string (TR+, TR-).
Definition: trustregion.hh:131
std::string stopReasonString
String describing the stopping reason.
Definition: trustregion.hh:130
std::string accstr
Acceptance string (REJ, acc).
Definition: trustregion.hh:132
int consecutive_TRplus
Consecutive trust region increases.
Definition: trustregion.hh:127
Information about the TrustRegion solver.
Definition: trustregion.hh:146
double rho
Definition: trustregion.hh:152
double etaNorm
Definition: trustregion.hh:148
double energyProposal
Definition: trustregion.hh:151
double energy
Definition: trustregion.hh:150
double gradNorm
Definition: trustregion.hh:147
int outerIter
Definition: trustregion.hh:153
double time
Definition: trustregion.hh:149
int innerIterSum
Definition: trustregion.hh:154
void notify(NonLinearSolverMessages message, const State &data)
This calls all the registered functions.
Definition: broadcaster.hh:61