forked from polyfem/polysolve
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Criteria.cpp
118 lines (110 loc) · 3.64 KB
/
Criteria.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Source: https://github.com/PatWie/CppNumericalSolvers/blob/7eddf28fa5a8872a956d3c8666055cac2f5a535d/include/cppoptlib/meta.h
// License: MIT
#include "Criteria.hpp"
#include <spdlog/fmt/fmt.h>
namespace polysolve::nonlinear
{
bool is_converged_status(const Status s)
{
return s == Status::XDeltaTolerance || s == Status::FDeltaTolerance || s == Status::GradNormTolerance;
}
Criteria::Criteria()
{
reset();
}
void Criteria::reset()
{
iterations = 0;
xDelta = 0;
fDelta = 0;
gradNorm = 0;
firstGradNorm = 0;
fDeltaCount = 0;
xDeltaDotGrad = 0;
firstStepGradNorm = 0;
}
void Criteria::print(std::ostream &os) const
{
os << fmt::format(
"iters={:d} Δf={:g} ‖∇f‖={:g} ‖Δx‖={:g} Δx⋅∇f(x)={:g} ‖∇f_1‖={:g}",
iterations, fDelta, gradNorm, xDelta, xDeltaDotGrad, firstStepGradNorm);
}
Status checkConvergence(const Criteria &stop, const Criteria ¤t)
{
if (stop.iterations > 0 && current.iterations > stop.iterations)
{
return Status::IterationLimit;
}
const double stopGradNorm = current.iterations == 0 ? stop.firstGradNorm : stop.gradNorm;
//if (stopGradNorm > 0 && current.gradNorm < stopGradNorm)
//{
// return Status::GradNormTolerance;
//}
if (stopGradNorm > 0 && stop.firstStepGradNorm != 0 && current.gradNorm < stopGradNorm * stop.firstStepGradNorm)
{
return Status::GradNormTolerance;
}
if (stop.xDelta > 0 && current.xDelta < stop.xDelta)
{
return Status::XDeltaTolerance;
}
if (stop.fDelta > 0 && current.fDelta < stop.fDelta && current.fDeltaCount >= stop.fDeltaCount)
{
return Status::FDeltaTolerance;
}
// Δx⋅∇f ≥ 0 means that the search direction is not a descent direction
if (stop.xDeltaDotGrad < 0 && current.xDeltaDotGrad > stop.xDeltaDotGrad)
{
return Status::NotDescentDirection;
}
return Status::Continue;
}
std::ostream &operator<<(std::ostream &os, const Status &s)
{
switch (s)
{
case Status::NotStarted:
os << "Solver not started";
break;
case Status::Continue:
os << "Convergence criteria not reached";
break;
case Status::IterationLimit:
os << "Iteration limit reached";
break;
case Status::XDeltaTolerance:
os << "Change in parameter vector too small";
break;
case Status::FDeltaTolerance:
os << "Change in cost function value too small";
break;
case Status::GradNormTolerance:
os << "Gradient vector norm too small";
break;
case Status::ObjectiveCustomStop:
os << "Objective function specified to stop";
break;
case Status::NanEncountered:
os << "Objective or gradient function returned NaN";
break;
case Status::NotDescentDirection:
os << "Search direction not a descent direction";
break;
case Status::LineSearchFailed:
os << "Line search failed";
break;
case Status::UpdateDirectionFailed:
os << "Update direction could not be computed";
break;
default:
os << "Unknown status";
break;
}
return os;
}
std::ostream &operator<<(std::ostream &os, const Criteria &c)
{
c.print(os);
return os;
}
} // namespace polysolve::nonlinear