5#ifndef LINE_API_MAM_MAP_ANFIT_H
6#define LINE_API_MAM_MAP_ANFIT_H
62namespace anfitdetail {
66Map<T> super2(
const Map<T>& a,
const Map<T>& b) {
68 m.D0 =
krons(a.D0, b.D0);
69 m.D1 =
krons(a.D1, b.D1);
75Map<T> ipp(
const T& c1,
const T& c2,
const T& l) {
76 const T zero = num_traits<T>::from_int(0);
88std::vector<double> phi_ladder(
double beta,
double n, std::size_t ds, std::size_t* dOut,
91 for (std::size_t guard = 0; guard < 64; ++guard) {
92 const double a = std::pow(10.0, n /
static_cast<double>(d - 1));
93 std::vector<double> phi(d + 1, 0.0);
96 for (std::size_t i = 1; i < d; ++i) {
98 for (std::size_t j = 0; j < i; ++j)
99 S += phi[d - j] * phi[d - j] *
100 std::exp(1.0 - std::pow(a,
static_cast<double>(i - j)));
101 const double D = std::pow(a,
static_cast<double>(i) * beta) - S;
111 phi[d - i] = std::sqrt(D);
117 std::vector<double> out(d + 1, 0.0);
118 for (std::size_t i = 1; i <= d; ++i) out[i] = phi[i];
121 throw NumericError(
"map_anfit: the phi ladder did not terminate");
149 if (ds < 2)
throw InputError(
"map_anfit: at least two IPPs are required");
151 if (!(lsd > 0.0))
throw InputError(
"map_anfit: the arrival rate must be positive");
156 const std::vector<double> phi = anfitdetail::phi_ladder<T>(beta, n, ds, &d, &a);
158 const double k21 = 0.8;
159 std::vector<double> k2(d + 1, 0.0);
160 for (std::size_t i = 1; i <= d; ++i) k2[i] = std::pow(a, 1.0 -
static_cast<double>(i)) * k21;
162 double S = 0.0, phisum = 0.0;
163 for (std::size_t i = 1; i <= d; ++i) {
164 const double kappa = k2[i], e = std::exp(-kappa);
165 S += phi[i] * phi[i] / (kappa * kappa) *
166 ((1.0 - e) * (1.0 - e) - 2.0 * rhod * (kappa - (1.0 - e)));
171 "map_anfit: the ladder carries no variance at this (rho, H, n); the construction has "
172 "no interrupted-Poisson superposition for these targets");
173 const double eta = std::sqrt(4.0 * rhod * lsd) / std::sqrt(S);
174 const double L = eta * phisum / 2.0;
176 std::vector<double> c1(d + 1, 0.0), c2v(d + 1, 0.0), l(d + 1, 0.0);
179 for (std::size_t i = 1; i <= d; ++i) {
180 c1[i] = L * L / (lsd * lsd + L * L) * k2[i];
181 c2v[i] = k2[i] - c1[i];
182 l[i] = phi[i] * (lsd * lsd + L * L) / (lsd * phisum);
186 for (std::size_t i = 1; i <= d; ++i) {
187 c2v[i] = 0.5 * k2[i];
198 for (std::size_t i = 1; i <= d; ++i)
207 for (std::size_t i = 1; i <= d; ++i) {
223 const std::vector<T>& SA,
const std::vector<unsigned>& SAlags,
224 unsigned iter_max = 100) {
226 if (SA.size() != SAlags.size())
227 throw InputError(
"map_anfit_lsq: the autocorrelation values and lags must agree in length");
228 if (SA.empty())
throw InputError(
"map_anfit_lsq: no autocorrelation targets given");
231 const std::size_t d = base.
d;
235 std::vector<double> k1(d, 0.0), k2(d, 0.0), lsi(d, 0.0);
236 for (std::size_t i = 0; i < d; ++i) {
240 const double c1 = 0.5 * kk, c2 = 0.5 * kk;
241 k1[i] = li * li * (c1 * c2) / std::pow(c1 + c2, 3.0);
243 lsi[i] = (c2 * li) / (c1 + c2);
246 auto build = [&](
const std::vector<T>& r) {
250 for (std::size_t i = 0; i < d; ++i) {
252 if (!(ri > 0.0))
throw NumericError(
"map_anfit_lsq: a ratio left the feasible region");
265 auto fobj = [&](
const std::vector<T>& r) {
268 const std::vector<T> acf =
map_acf(build(r), SAlags);
269 for (std::size_t i = 0; i < SA.size(); ++i) {
270 const T diff = T(acf[i] - SA[i]);
273 }
catch (
const Error&) {
278 auto heq = [&](
const std::vector<T>&) {
return std::vector<T>(); };
279 auto gineq = [&](
const std::vector<T>& r) {
280 std::vector<T> g(d, zero);
281 for (std::size_t i = 0; i < d; ++i) {
283 const double lim = ri > 0.0 ? std::sqrt(k1[i] * k2[i] / ri) : 1e30;
289 std::vector<T> r0(d, one), bestx;
290 std::vector<Bound<T>> bounds(d);
291 for (std::size_t i = 0; i < d; ++i) {
293 1.0 + (lsi[i] > 0.0 ? k1[i] * k2[i] / (lsi[i] * lsi[i]) : 1.0));
298 opt.max_outer = iter_max;
302 out.
map = build(res.
x);
Augmented Lagrangian method for equality- and inequality-constrained minimization,...
Base error for the multiprecision C++ port.
NumericError(const std::string &what)
The exception types the port throws.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
std::vector< T > map_acf(const Map< T > &m, const std::vector< unsigned > &lags)
Autocorrelation coefficients of the inter-arrival times at the given lags,.
Matrix< T > krons(const Matrix< T > &A, const Matrix< T > &B)
Kronecker sum, MATLAB's krons: kron(A, I_nb) + kron(I_na, B).
MapAnfitResult< T > map_anfit_lsq(const T &ls, const T &rho, const T &H, double n, std::size_t ds, const std::vector< T > &SA, const std::vector< unsigned > &SAlags, unsigned iter_max=100)
The least-squares variant: after the deterministic construction, the per-IPP ratios are tuned so the ...
MapAnfitResult< T > map_anfit(const T &ls, const T &rho, const T &H, double n, std::size_t ds)
Fit a superposition of interrupted Poisson processes to a Hurst parameter.
Map< T > map_normalize(const Map< T > &in)
Clamp negative off-diagonal entries of D0 and negative entries of D1 to zero, then rebuild the diagon...
AugLagResult< T > auglag(F f, H h, G g, const std::vector< T > &x0, const std::vector< Bound< T > > &bounds, const AugLagOptions< T > &opt)
Augmented Lagrangian with a scalar objective and a simplex inner solver.
AugLagOptions< T > auglag_defaults()
Defaults: rho0 = 10, growth 10, feasibility 1e-10, 50 outer iterations.
Number-type abstraction for the templated API port.
Tuning of the outer multiplier iteration.
Outcome of a constrained solve.
std::vector< T > x
best point found
What map_anfit returns: the fitted MAP and the ladder it was built on.
T poisson_rate
lP, the Poisson remainder
std::vector< T > switching
k(2,i), the switching-rate ladder
std::size_t d
number of IPPs actually used
std::vector< T > rates
l(i), the on-state arrival rates
A MAP as the pair of matrices (D0, D1).