Optimist  0.0.0
A C++ library for optimization
Loading...
Searching...
No Matches
Chandrupatla.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * Copyright (c) 2025, Davide Stocco and Enrico Bertolazzi. *
3 * *
4 * The Optimist project is distributed under the BSD 2-Clause License. *
5 * *
6 * Davide Stocco Enrico Bertolazzi *
7 * University of Trento University of Trento *
8 * davide.stocco@unitn.it enrico.bertolazzi@unitn.it *
9\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10
11#pragma once
12
13#ifndef OPTIMIST_ROOTFINDER_CHANDRUPATLA_HH
14#define OPTIMIST_ROOTFINDER_CHANDRUPATLA_HH
15
17
18namespace Optimist {
19 namespace RootFinder {
20
21 /*\
22 | ____ _ _ _ _
23 | / ___| |__ __ _ _ __ __| |_ __ _ _ _ __ __ _| |_| | __ _
24 | | | | '_ \ / _` | '_ \ / _` | '__| | | | '_ \ / _` | __| |/ _` |
25 | | |___| | | | (_| | | | | (_| | | | |_| | |_) | (_| | |_| | (_| |
26 | \____|_| |_|\__,_|_| |_|\__,_|_| \__,_| .__/ \__,_|\__|_|\__,_|
27 | |_|
28 \*/
29
40 template <typename Scalar>
41 class Chandrupatla : public Bracketing<Scalar, Chandrupatla<Scalar>> {
42 public:
43 static constexpr bool RequiresFunction{true};
44 static constexpr bool RequiresFirstDerivative{false};
45 static constexpr bool RequiresSecondDerivative{false};
46
48
49
53
58 constexpr std::string name_impl() const {
59 return "Chandrupatla";
60 }
61
70 template <typename FunctionLambda>
71 Scalar find_root_impl(FunctionLambda &&function) {
72#define CMD "Optimist::RootFinder::Chandrupatla::find_root_impl(...): "
73
74 bool success;
75 Scalar tolerance_step{this->m_tolerance_bracketing};
76 Scalar tolerance_function{this->m_tolerance_bracketing};
77
78 // Check for trivial solution
79 this->m_converged = this->m_fa == 0;
80 if (this->m_verbose) {
81 this->info(std::abs(this->m_fa));
82 }
83 if (this->m_converged) {
84 return this->m_a;
85 }
86 this->m_converged = this->m_fb == 0;
87 if (this->m_verbose) {
88 this->info(std::abs(this->m_fb));
89 }
90 if (this->m_converged) {
91 return this->m_b;
92 }
93
94 // Initialize to dumb values
95 this->m_e = QUIET_NAN;
96 this->m_fe = QUIET_NAN;
97
98 // While f(left) or f(right) are infinite perform bisection
99 while (!(std::isfinite(this->m_fa) && std::isfinite(this->m_fb))) {
100 ++this->m_iterations;
101 this->m_c = (this->m_a + this->m_b) / 2.0;
102 success =
103 this->evaluate_function(std::forward<FunctionLambda>(function),
104 this->m_c,
105 this->m_fc);
106 OPTIMIST_ASSERT(success,
107 CMD "function evaluation failed at iteration "
108 << this->m_iterations << ".");
109 this->m_converged = this->m_fc == 0;
110 if (this->m_verbose) {
111 this->info(std::abs(this->m_fc));
112 }
113 if (this->m_converged) {
114 return this->m_c;
115 }
116 if (this->m_fa * this->m_fc < 0) {
117 // -> [a, c]
118 this->m_b = this->m_c;
119 this->m_fb = this->m_fc;
120 } else {
121 // -> [c, b]
122 this->m_a = this->m_c;
123 this->m_fa = this->m_fc;
124 }
125
126 // Check for convergence
127 Scalar abs_fa{std::abs(this->m_fa)};
128 Scalar abs_fb{std::abs(this->m_fb)};
129 if (this->m_verbose) {
130 this->info(abs_fa < abs_fb ? abs_fa : abs_fb);
131 }
132 this->m_converged = (this->m_b - this->m_a) < tolerance_step ||
133 abs_fa < tolerance_function ||
134 abs_fb < tolerance_function;
135 if (this->m_converged) {
136 return abs_fb < abs_fa ? this->m_b : this->m_a;
137 }
138 }
139
140 Scalar t{0.5};
141
143 Scalar direction{this->m_b - this->m_a};
144 Scalar tolerance{tolerance_step /
145 (static_cast<Scalar>(2.0) * std::abs(direction))};
146 this->m_converged = tolerance >= 0.5;
147 if (this->m_converged) {
148 break;
149 }
150
151 Scalar abs_fa{std::abs(this->m_fa)};
152 Scalar abs_fb{std::abs(this->m_fb)};
153 if (this->m_verbose) {
154 this->info(abs_fa < abs_fb ? abs_fa : abs_fb);
155 }
156 this->m_converged =
157 abs_fa < tolerance_function || abs_fb < tolerance_function;
158 if (this->m_converged) {
159 break;
160 }
161
162 if (t < tolerance) {
163 t = tolerance;
164 } else if (t > 1.0 - tolerance) {
165 t = 1.0 - tolerance;
166 }
167
168 Scalar c{this->m_a + t * direction};
169 Scalar fc;
170 success =
171 this->evaluate_function(std::forward<FunctionLambda>(function),
172 c,
173 fc);
174 OPTIMIST_ASSERT(success,
175 CMD "function evaluation failed at iteration "
176 << this->m_iterations << ".");
177 if (this->m_verbose) {
178 this->info(fc);
179 }
180
181 OPTIMIST_ASSERT(std::isfinite(fc), CMD "function is not finite.");
182
183 this->m_converged = fc == 0;
184 if (this->m_converged) {
185 this->m_a = this->m_b = c;
186 this->m_fa = this->m_fb = 0;
187 break;
188 }
189
190 // Arrange 2-1-3: 2-1 interval, 1 middle, 3 discarded point
191 Scalar d, fd;
192 if ((0.0 < fc) == (0.0 < this->m_fa)) {
193 // a -> d --> [d,a,b] = [a,c,b]
194 d = this->m_a;
195 fd = this->m_fa;
196 } else {
197 // b -> d, a -> b --> [b,a,d] = [a,c,b]
198 d = this->m_b;
199 fd = this->m_fb;
200 this->m_b = this->m_a;
201 this->m_fb = this->m_fa;
202 }
203 // c => a
204 this->m_a = c;
205 this->m_fa = fc;
206
207 // If inverse quadratic interpolation holds use it
208 Scalar ba{this->m_b - this->m_a};
209 Scalar fba{this->m_fb - this->m_fa};
210 Scalar bd{this->m_b - d};
211 Scalar fbd{this->m_fb - fd};
212
213 Scalar xi{ba / bd};
214 Scalar ph{fba / fbd};
215 Scalar fl{static_cast<Scalar>(1.0) -
216 std::sqrt(static_cast<Scalar>(1.0) - xi)};
217 Scalar fh{std::sqrt(xi)};
218
219 if (fl < ph && ph < fh) {
220 Scalar da{d - this->m_a};
221 Scalar fda{fd - this->m_fa};
222 t = (this->m_fa / fba) * (fd / fbd) -
223 (this->m_fa / fda) * (this->m_fb / fbd) * (da / ba);
224 } else {
225 t = 0.5;
226 }
227 }
228 if (this->m_a > this->m_b) {
229 std::swap(this->m_a, this->m_b);
230 std::swap(this->m_fa, this->m_fb);
231 }
232 return std::abs(this->m_fa) < std::abs(this->m_fb) ? this->m_a
233 : this->m_b;
234 ;
235
236#undef CMD
237 }
238
239 }; // class Chandrupatla
240
241 } // namespace RootFinder
242
243} // namespace Optimist
244
245#endif // OPTIMIST_ROOTFINDER_CHANDRUPATLA_HH
#define OPTIMIST_BASIC_CONSTANTS(Scalar)
Definition Optimist.hh:70
#define OPTIMIST_ASSERT(COND, MSG)
Definition Optimist.hh:48
#define CMD
static constexpr bool RequiresFirstDerivative
Definition Chandrupatla.hh:44
static constexpr bool RequiresSecondDerivative
Definition Chandrupatla.hh:45
Chandrupatla()
Definition Chandrupatla.hh:52
static constexpr bool RequiresFunction
Definition Chandrupatla.hh:43
constexpr std::string name_impl() const
Definition Chandrupatla.hh:58
Scalar find_root_impl(FunctionLambda &&function)
Definition Chandrupatla.hh:71
typename TypeTrait< Scalar >::Scalar Scalar
Definition RootFinder.hh:53
void info(Scalar residuals, const std::string &notes="-")
Definition SolverBase.hh:1232
bool evaluate_function(FunctionLambda &&function, const Scalar &x, Scalar &out)
Definition SolverBase.hh:1040
Scalar tolerance() const
Definition SolverBase.hh:513
Namespace for the Optimist library.
Definition Optimist.hh:90