32 template<
class F,
size_t Derivatives,
class Real>
34 Real& x, Real new_x, Real& low_bound, Real& high_bound, Real x_precision) {
39 if ((new_x >= high_bound) || (new_x <= low_bound)) {
46 auto new_state = f(new_x);
49 Real delta = new_x - x;
51 if ((
std::abs(delta) <
std::abs(x_precision * new_x)) || (new_state[0] == Real(0))) {
55 curr_state = new_state;
73 curr_state = new_state;
84 template<
class F,
size_t Derivatives,
class Real>
86 Real& x, Real& low_bound, Real& high_bound, Real x_precision) {
87 static_assert(Derivatives >= 1,
"Can only perform newton raphson if at least 1 derivative is available");
90 if (curr_state[1] == 0) {
101 template<
class F,
size_t Derivatives,
class Real>
102 inline int halley_step(
const F& f, std::array<Real, Derivatives>& curr_state,
103 Real& x, Real& low_bound, Real& high_bound, Real x_precision) {
104 static_assert(Derivatives >= 2,
"Can only perform Halley iteration if at least 1 derivative is available");
107 Real numerator = 2 * curr_state[0] * curr_state[1];
108 Real denominator = 2 * curr_state[1] * curr_state[1] - curr_state[0] * curr_state[2];
110 if ((denominator == 0) || !std::isfinite(denominator)) {
117 Real delta = - numerator / denominator;
118 Real deltaNR = - curr_state[0] / curr_state[1];
121 if (std::signbit(delta) != std::signbit(deltaNR)) {
135 template<
class F,
size_t Derivatives,
class Real>
136 inline int schroeder_step(
const F& f, std::array<Real, Derivatives>& curr_state, Real& x, Real& low_bound, Real& high_bound, Real x_precision) {
137 static_assert(Derivatives >= 2,
"Can only perform Halley iteration if at least 1 derivative is available");
139 if (curr_state[1] == 0)
143 return detail::process_iterative_step(f, curr_state, x, x - 2 * curr_state[0] * curr_state[1] - curr_state[2] * curr_state[0] * curr_state[0] / (2 * curr_state[1] * curr_state[1] * curr_state[1]), low_bound, high_bound, x_precision);
148 template<
class F,
size_t Derivatives,
class Real>
149 inline int bisection_step(
const F& f, std::array<Real, Derivatives>& curr_state, Real& x, Real& low_bound, Real& high_bound, Real x_precision) {
150 if ((low_bound >= high_bound) || std::isinf(low_bound) || std::isinf(high_bound))
155 auto f_low = f(low_bound);
156 auto f_high = f(high_bound);
158 if (std::signbit(f_low[0]) == std::signbit(f_high[0])) {
164 Real x_mid = (low_bound + high_bound) / 2;
165 auto new_state = f(x_mid);
169 Real delta = x_mid - x;
174 || (new_state[0] == Real(0))
176 || (x_mid == low_bound)
177 || (x_mid == high_bound)
183 curr_state = new_state;
188 if (std::signbit(new_state[0]) == std::signbit(f_high[0])) {
196 curr_state = new_state;
206 template<
class F,
class Real>
207 bool newton_raphson(
const F& f, Real& x, Real low_bound = -HUGE_VAL, Real high_bound = +HUGE_VAL,
208 size_t iterations = 0,
int digits = std::numeric_limits<Real>::digits / 2)
211 iterations = std::numeric_limits<size_t>::max();
213 auto last_state = f(x);
214 static_assert(last_state.size() > 1,
"Require one derivative of the objective function for Newton-Raphson method");
216 Real x_precision =
static_cast<Real
>(ldexp(1.0, 1 - digits));
218 if (last_state[0] == 0)
222 while ((--iterations) && (status != 2)) {
225 status =
bisection_step(f, last_state, x, low_bound, high_bound, x_precision);
231 return (status == 2);
239 template<
class F,
class Real>
241 Real high_bound = +HUGE_VAL,
size_t iterations = 0,
int digits = std::numeric_limits<Real>::digits / 2)
244 iterations = std::numeric_limits<size_t>::max();
246 auto last_state = f(x);
248 static_assert(last_state.size() > 2,
"Require two derivatives of the objective function for Halley's method");
250 Real x_precision =
static_cast<Real
>(ldexp(1.0, 1 - digits));
252 if (last_state[0] == 0)
257 while ((--iterations) && (status != 2)) {
258 status =
halley_step(f, last_state, x, low_bound, high_bound, x_precision);
262 status =
bisection_step(f, last_state, x, low_bound, high_bound, x_precision);
268 return (status == 2);
271 template<
class F,
class Real>
273 Real high_bound,
size_t iterations = 0,
int digits = std::numeric_limits<Real>::digits / 2)
276 if ((low_bound >= high_bound) || std::isinf(low_bound) || std::isinf(high_bound))
280 iterations = std::numeric_limits<size_t>::max();
282 Real x_precision =
static_cast<Real
>(ldexp(1.0, 1 - digits));
284 auto f_low = f(low_bound);
285 auto f_high = f(high_bound);
287 if (std::signbit(f_low) == std::signbit(f_high)) {
297 while (--iterations) {
298 Real x_mid = (low_bound + high_bound) / 2;
299 auto new_state = f(x_mid);
300 Real delta = x_mid - x;
305 || (new_state == Real(0))
307 || (x_mid == low_bound)
308 || (x_mid == high_bound)
316 if (std::signbit(new_state) == std::signbit(f_high)) {
int bisection_step(const F &f, std::array< Real, Derivatives > &curr_state, Real &x, Real &low_bound, Real &high_bound, Real x_precision)
A single bisection step.
int newton_raphson_step(const F &f, std::array< Real, Derivatives > &curr_state, Real &x, Real &low_bound, Real &high_bound, Real x_precision)
A single step of the Newton-Raphson method for finding roots.
int process_iterative_step(const F &f, std::array< Real, Derivatives > &curr_state, Real &x, Real new_x, Real &low_bound, Real &high_bound, Real x_precision)
Update and checking of safeguards, called after an iterative step is taken towards a root...
int halley_step(const F &f, std::array< Real, Derivatives > &curr_state, Real &x, Real &low_bound, Real &high_bound, Real x_precision)
A single step of Halley's method for finding roots.
bool bisection(const F &f, Real &x, Real low_bound, Real high_bound, size_t iterations=0, int digits=std::numeric_limits< Real >::digits/2)
bool halleys_method(const F &f, Real &x, Real low_bound=-HUGE_VAL, Real high_bound=+HUGE_VAL, size_t iterations=0, int digits=std::numeric_limits< Real >::digits/2)
Safeguarded Halley's method for detecting a root.
bool newton_raphson(const F &f, Real &x, Real low_bound=-HUGE_VAL, Real high_bound=+HUGE_VAL, size_t iterations=0, int digits=std::numeric_limits< Real >::digits/2)
Safeguarded newton_raphson method for detecting a root.
int schroeder_step(const F &f, std::array< Real, Derivatives > &curr_state, Real &x, Real &low_bound, Real &high_bound, Real x_precision)
A single step of Schroeder's method for finding roots.
constexpr C<(1 - 2 *(num< 0)) *num,(1 - 2 *(den< 0)) *den > abs(const C< num, den > &a)
The stator library namespace.