LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
da_fpi.h
Go to the documentation of this file.
1
/*
2
* Copyright (c) 2012-2026, QORE Lab, Imperial College London
3
* All rights reserved.
4
*/
5
#ifndef LINE_API_DA_DA_FPI_H
6
#define LINE_API_DA_DA_FPI_H
7
8
/**
9
* @file
10
* @ingroup api_da
11
* Damped fixed-point iteration, the shared driver of the decomposition
12
* algorithms.
13
*
14
* Templated port of matlab/src/api/da/da_fpi.m. The iteration is
15
* x_{k+1} = (1 - omega) x_ref + omega f(x_k, k)
16
* stopping when the configured norm of the increment falls below iter_tol, or
17
* after iter_max steps. MATLAB passes the iteration function as a handle
18
* returning both the new iterate and the reference point it should be damped
19
* against; the port takes a std::function with the same contract, so a caller
20
* whose reference differs from its input (as in the Erlang fixed point) is
21
* expressible without special-casing.
22
*
23
* THE INCREMENT NORM FOLLOWS MATLAB'S max(), which OMITS NaN and answers NaN
24
* only when every entry is one. The first form of this port skipped NaN entries
25
* but left `delta` at its initial 0, so an all-NaN increment -- a diverged
26
* iterate -- reported CONVERGENCE, where MATLAB's `NaN < iter_tol` is false and
27
* the loop continues to iter_max. Corrected here; a caller that wants to stop on
28
* a divergence asks for it with `nanstop`.
29
*
30
* A tolerance-driven loop is inexact by construction, whatever the arithmetic:
31
* the answer is the fixed point only to within iter_tol. The static_assert
32
* records that, so nobody instantiates it at exact arithmetic expecting an
33
* exact fixed point.
34
*/
35
36
#include <cmath>
37
#include <cstddef>
38
#include <functional>
39
#include <limits>
40
#include <utility>
41
#include <vector>
42
43
#include "
line/num/number.h
"
44
#include "
line/util/error.h
"
45
46
namespace
line
{
47
namespace
da
{
48
49
/** Options mirroring the fields MATLAB reads off the options struct. */
50
struct
FpiOptions
{
51
std::size_t
iter_max
= 10000;
52
double
iter_tol
= 1e-8;
53
double
damping
= 1.0;
///< omega; 1 means no damping
54
std::size_t
miniter
= 1;
///< iterations before the stopping test applies
55
bool
nanstop
=
false
;
///< stop when the increment norm is not finite
56
/**
57
* `config.da_norm`, the increment norm. MATLAB passes a function handle;
58
* the two handles the reference actually installs are both RELATIVE --
59
* `max(|xn-xr|./xr)` in solver_mam.m and `max(|xn-xr|./(xr+FineTol))` in
60
* solver_mam_basic_mmap_inner.m -- so they are expressed here as a flag and
61
* the denominator's offset rather than as a std::function, which would have
62
* to be templated on T and would change the type of every existing caller's
63
* options object.
64
*
65
* FALSE keeps the default absolute max-norm. TRUE with `relative_eps = 0`
66
* reproduces the first handle, including its division by a zero reference
67
* (the reference divides by `xr` unguarded, and an all-zero start therefore
68
* yields NaN on the first sweep; `miniter` is what keeps that from stopping
69
* the loop, exactly as in MATLAB).
70
*/
71
bool
relative_norm
=
false
;
72
double
relative_eps
= 0.0;
73
};
74
75
template
<
class
T>
76
struct
FpiResult
{
77
std::vector<T>
x
;
78
std::size_t
iterations
= 0;
79
bool
converged
=
false
;
80
};
81
82
/**
83
* @brief Damped fixed-point iteration, the shared driver of the decomposition
84
* algorithms.
85
*
86
* @param iterfun (x, iteration) -> (xnew, xref); xref is the point the damping
87
* and the increment norm are taken against
88
* @param x0 initial iterate
89
* @param options fixed-point options (tolerance, iteration cap, damping)
90
*/
91
template
<
class
T>
92
FpiResult<T>
da_fpi
(
93
const
std::function<std::pair<std::vector<T>, std::vector<T>>(
const
std::vector<T>&, std::size_t)>&
94
iterfun,
95
const
std::vector<T>& x0,
const
FpiOptions
& options =
FpiOptions
()) {
96
static_assert
(
num_traits<T>::has_transcendental
,
97
"da_fpi requires transcendental arithmetic: it stops on a tolerance, so its "
98
"result is the fixed point only to within iter_tol whatever the arithmetic"
);
99
if
(x0.empty())
throw
InputError
(
"da_fpi: empty initial iterate"
);
100
const
T omega =
num_traits<T>::from_double
(options.damping);
101
const
T one =
num_traits<T>::from_int
(1);
102
103
FpiResult<T>
r;
104
r.
x
= x0;
105
for
(std::size_t it = 1; it <= options.iter_max; ++it) {
106
r.
iterations
= it;
107
std::pair<std::vector<T>, std::vector<T>> step = iterfun(r.
x
, it);
108
std::vector<T>& xnew = step.first;
109
const
std::vector<T>& xref = step.second;
110
if
(xnew.size() != r.
x
.size() || xref.size() != r.
x
.size())
111
throw
InputError
(
"da_fpi: the iteration function changed the vector length"
);
112
113
if
(options.damping != 1.0)
114
for
(std::size_t i = 0; i < xnew.size(); ++i)
115
xnew[i] = (one - omega) * xref[i] + omega * xnew[i];
116
117
// MATLAB's max() OMITS NaN and answers NaN only when every entry is one,
118
// which is what lets the relative norm survive a zero reference entry on
119
// the first sweep instead of stopping the loop there.
120
double
delta = 0.0;
121
bool
anynum =
false
;
122
for
(std::size_t i = 0; i < xnew.size(); ++i) {
123
double
d = std::fabs(
num_traits<T>::to_double
(T(xnew[i] - xref[i])));
124
if
(options.relative_norm)
125
d /=
num_traits<T>::to_double
(xref[i]) + options.relative_eps;
126
if
(std::isnan(d))
continue
;
127
if
(!anynum || d > delta) delta = d;
128
anynum =
true
;
129
}
130
if
(!anynum && !xnew.empty()) delta = std::numeric_limits<double>::quiet_NaN();
131
r.
x
= xnew;
132
133
if
(it >= options.miniter) {
134
if
(delta < options.iter_tol) {
135
r.
converged
=
true
;
136
break
;
137
}
138
if
(options.nanstop && !std::isfinite(delta))
break
;
139
}
140
}
141
return
r;
142
}
143
144
}
// namespace da
145
}
// namespace line
146
147
#endif
// LINE_API_DA_DA_FPI_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
error.h
The exception types the port throws.
line::da
Definition
da_cache_isolate.h:45
line::da::da_fpi
FpiResult< T > da_fpi(const std::function< std::pair< std::vector< T >, std::vector< T > >(const std::vector< T > &, std::size_t)> &iterfun, const std::vector< T > &x0, const FpiOptions &options=FpiOptions())
Damped fixed-point iteration, the shared driver of the decomposition algorithms.
Definition
da_fpi.h:92
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
line::da::FpiOptions
Options mirroring the fields MATLAB reads off the options struct.
Definition
da_fpi.h:50
line::da::FpiOptions::iter_max
std::size_t iter_max
Definition
da_fpi.h:51
line::da::FpiOptions::miniter
std::size_t miniter
iterations before the stopping test applies
Definition
da_fpi.h:54
line::da::FpiOptions::damping
double damping
omega; 1 means no damping
Definition
da_fpi.h:53
line::da::FpiOptions::relative_eps
double relative_eps
Definition
da_fpi.h:72
line::da::FpiOptions::iter_tol
double iter_tol
Definition
da_fpi.h:52
line::da::FpiOptions::relative_norm
bool relative_norm
config.da_norm, the increment norm.
Definition
da_fpi.h:71
line::da::FpiOptions::nanstop
bool nanstop
stop when the increment norm is not finite
Definition
da_fpi.h:55
line::da::FpiResult
Definition
da_fpi.h:76
line::da::FpiResult::iterations
std::size_t iterations
Definition
da_fpi.h:78
line::da::FpiResult::x
std::vector< T > x
Definition
da_fpi.h:77
line::da::FpiResult::converged
bool converged
Definition
da_fpi.h:79
line::num_traits
Definition
number.h:111
include
line
api
da
da_fpi.h
Generated by
1.18.0