LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
mamap22_fit_fs.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_MAM_MAMAP22_FIT_FS_H
6#define LINE_API_MAM_MAMAP22_FIT_FS_H
7
8/**
9 * @file
10 * @ingroup api_mam
11 * Fit a MAMAP(2,2) matching the FORWARD moment and the class TRANSITION
12 * probability sigma.
13 *
14 * Templated port of matlab/lib/m3a/m3a/mamap22/mamap22_fit_fs_multiclass.m, the
15 * twin of `mamap22_fit_bs.h`. The structure is the same -- a closed-form inverse
16 * over the coefficient tables of `mamap2m_coefficients.h`, with five degenerate
17 * branches ahead of it -- and only the inverse itself differs, reading the
18 * FORWARD block of the tables (U(1..6), G(13..15), Y(2)) where the backward
19 * fitter reads U(7..12), G(10..12) and Y(3).
20 *
21 * TWO CLASSES ONLY, as in the backward twin, and for the same reason.
22 *
23 * ONE BRANCH DIFFERS SUBSTANTIVELY from the backward fitter and is worth
24 * naming: the CANONICAL PHASE-TYPE case (form 1, r2 = 0). The reference falls
25 * back to `maph2m_fit_multiclass`, which fits BACKWARD moments, and it has no
26 * forward targets to give it -- so it sets both backward targets to the ordinary
27 * mean and WARNS that the caller should have used B+S instead. That warning is
28 * reproduced as a named diagnostic on the result rather than dropped, because a
29 * caller who asked for a forward fit and silently got a mean-matched backward
30 * one has no other way to find out. It also re-fits the timing as an APH(2) when
31 * the SCV has fallen to one, which is the hypoexponential boundary where the
32 * canonical form stops being informative.
33 *
34 * WHAT IS NOT PORTED, refused by name: the same nonconvex repair as the backward
35 * twin -- YALMIP `bmibnb`, a spatial branch-and-bound returning a GLOBAL optimum
36 * of a bilinear program. `line/util/auglag.h` finds a local KKT point, which on a
37 * nonconvex set is a different answer; substituting it would report a fit the
38 * reference would not have chosen. The gamma < 0 degeneracy's sigma arm IS
39 * ported: the reference states it as a YALMIP program, but its feasible set is
40 * an interval and its objective is (x - S11)^2, so the projection is its exact
41 * global optimum.
42 *
43 * ARITHMETIC: transcendental.
44 */
45
46#include <cmath>
47#include <cstddef>
48#include <string>
49#include <vector>
50
67#include "line/num/number.h"
68#include "line/util/error.h"
69#include "line/util/matrix.h"
70
71namespace line {
72namespace mam {
73
74/** The forward-plus-sigma result; `warning` carries the reference's diagnostic. */
75template <class T>
78 std::vector<T> fF; ///< achieved per-class forward moments
79 Matrix<T> fS; ///< achieved class transition probabilities
80 bool exact = false;
81 std::string warning; ///< empty unless a branch substituted its targets
82};
83
84namespace fsdetail {
85
86/** The closed-form F+S inverse of the first canonical form. */
87template <class T>
88void fit_can1(const Mamap2mCoefficients<T>& c, const T& p1, const T& vF1, const T& vS11,
89 double denumtol, T* q1, T* q2, T* q3) {
90 const T den = T(p1 * (c.U[4] * vF1 + c.U[5]));
91 if (std::fabs(num_traits<T>::to_double(den)) < denumtol) {
92 *q1 = *q2 = *q3 = p1;
93 return;
94 }
95 *q2 = T((c.U[0] * vF1 * vF1 * p1 * p1 + c.U[1] * vF1 * p1 * p1 + c.U[2] * vS11 +
96 c.U[3] * p1 * p1) /
97 den);
98 *q1 = T(-(c.G[14] * p1 - vF1 * c.G[2] * p1 +
99 (c.G[2] * c.G[13] - c.G[1] * c.G[14]) * (*q2)) /
100 c.Y[1]);
101 *q3 = T((c.G[12] * p1 - vF1 * c.G[0] * p1 +
102 (c.G[0] * c.G[13] - c.G[1] * c.G[12]) * (*q2)) /
103 c.Y[1]);
104}
105
106/** The closed-form F+S inverse of the second canonical form. */
107template <class T>
108void fit_can2(const Mamap2mCoefficients<T>& c, const T& p1, const T& vF1, const T& vS11,
109 double denumtol, T* q1, T* q2, T* q3) {
110 const T den = T(c.U[4] * vF1 * p1 + c.U[5] * p1);
111 if (std::fabs(num_traits<T>::to_double(den)) < denumtol) {
112 *q1 = *q2 = *q3 = p1;
113 return;
114 }
115 *q3 = T((c.U[0] * vF1 * vF1 * p1 * p1 + c.U[1] * vF1 * p1 * p1 + c.U[2] * p1 * p1 +
116 c.U[3] * vS11) /
117 den);
118 *q1 = T(-(c.G[12] * p1 - vF1 * c.G[1] * p1 +
119 (c.G[1] * c.G[13] - c.G[2] * c.G[12]) * (*q3)) /
120 c.Y[1]);
121 *q2 = T((c.G[11] * p1 - vF1 * c.G[0] * p1 +
122 (c.G[0] * c.G[13] - c.G[2] * c.G[11]) * (*q3)) /
123 c.Y[1]);
124}
125
126} // namespace fsdetail
127
128/**
129 * @param map the AMAP(2), in one of the two canonical acyclic forms
130 * @param p the two class probabilities
131 * @param F the two target forward moments
132 * @param S the target class transition matrix; only S(0,0) is used
133 * @param classWeights per-class weights; empty means uniform
134 * @param fsWeights the (forward, sigma) weights; empty means (1, 1)
135 * @param adjust repair an infeasible closed form; the repair is unported
136 */
137template <class T>
139 const Map<T>& map, const std::vector<T>& p, const std::vector<T>& F, const Matrix<T>& S,
140 const std::vector<T>& classWeights = std::vector<T>(),
141 const std::vector<T>& fsWeights = std::vector<T>(), bool adjust = true) {
143 "mamap22_fit_fs_multiclass inverts a moment system");
144 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
145 const T two = num_traits<T>::from_int(2);
146 if (map.D0.rows() != 2)
147 throw InputError("mamap22_fit_fs_multiclass: the underlying MAP must be second order");
148 if (!(num_abs(T(map.D0(1, 0))) <= zero))
149 throw InputError("mamap22_fit_fs_multiclass: the underlying MAP must be acyclic");
150 int form;
151 if (map.D1(0, 1) == zero) form = 1;
152 else if (map.D1(0, 0) == zero) form = 2;
153 else
154 throw InputError(
155 "mamap22_fit_fs_multiclass: the underlying MAP must be in canonical acyclic form");
156 if (p.size() != 2)
157 throw InputError(
158 "mamap22_fit_fs_multiclass: fitting the forward moment and the transition "
159 "probabilities supports two classes only");
160 if (F.size() != 2)
161 throw InputError("mamap22_fit_fs_multiclass: one forward moment per class is required");
162 if (S.rows() < 1 || S.cols() < 1)
163 throw InputError("mamap22_fit_fs_multiclass: the transition matrix is empty");
164
165 std::vector<T> cw = classWeights;
166 if (cw.empty()) cw.assign(2, one);
167 std::vector<T> fw = fsWeights;
168 if (fw.empty()) fw.assign(2, one);
169
170 // feastol is 1e-3 here and 1e-4 in the backward twin; that is the
171 // reference's own asymmetry, not a transcription slip.
172 const double degentol = 1e-6, feastol = 1e-3, denumtol = 1e-12;
173 Map<T> mp = map;
174 T h1 = T(-one / mp.D0(0, 0)), h2 = T(-one / mp.D0(1, 1));
175 T r1 = T(mp.D0(0, 1) * h1), r2 = T(mp.D1(1, 1) * h2);
176 auto dv = [](const T& v) { return num_traits<T>::to_double(v); };
177
179 out.mmap.D0 = mp.D0;
180 out.mmap.D1 = mp.D1;
181 out.mmap.Dc.assign(2, Matrix<T>(2, 2, zero));
182
183 auto finish = [&](T q1, T q2, T q3) {
184 auto fix = [&](const T& q) {
185 T v = q;
186 if (v < zero) v = zero;
187 if (v > one) v = one;
188 return v;
189 };
190 q1 = fix(q1);
191 q2 = fix(q2);
192 q3 = fix(q3);
193 if (form == 1) {
194 out.mmap.Dc[0](0, 0) = T(out.mmap.D1(0, 0) * q1);
195 out.mmap.Dc[1](0, 0) = T(out.mmap.D1(0, 0) * (one - q1));
196 } else {
197 out.mmap.Dc[0](0, 1) = T(out.mmap.D1(0, 1) * q1);
198 out.mmap.Dc[1](0, 1) = T(out.mmap.D1(0, 1) * (one - q1));
199 }
200 out.mmap.Dc[0](1, 0) = T(out.mmap.D1(1, 0) * q2);
201 out.mmap.Dc[1](1, 0) = T(out.mmap.D1(1, 0) * (one - q2));
202 out.mmap.Dc[0](1, 1) = T(out.mmap.D1(1, 1) * q3);
203 out.mmap.Dc[1](1, 1) = T(out.mmap.D1(1, 1) * (one - q3));
204 const std::vector<unsigned> ord(1, 1u);
205 const Matrix<T> fm = mmap_forward_moment(out.mmap, ord, true);
206 out.fF.assign(2, zero);
207 for (std::size_t c = 0; c < 2; ++c) out.fF[c] = fm(c, 0);
208 out.fS = mmap_sigma(out.mmap);
209 };
210 auto feasible = [&](const T& q) { return dv(q) >= -feastol && dv(q) <= 1.0 + feastol; };
211 auto adopt = [&](const Mmap<T>& m) {
212 out.mmap = m;
213 const std::vector<unsigned> ord(1, 1u);
214 const Matrix<T> fm = mmap_forward_moment(out.mmap, ord, true);
215 out.fF.assign(2, zero);
216 for (std::size_t c = 0; c < 2; ++c) out.fF[c] = fm(c, 0);
217 out.fS = mmap_sigma(out.mmap);
218 };
219
220 // ---- the Poisson perturbation ---------------------------------------
221 // The forward fitter's degeneracy is h1 - h2 + h2*r1 in BOTH forms, and it
222 // perturbs h1, not h2. The backward twin's is a different expression and
223 // perturbs a different parameter; do not share this block with it.
224 const bool degen1 = form == 1 && (dv(r1) < degentol || dv(r2) > 1.0 - degentol ||
225 std::fabs(dv(h1) - dv(h2) + dv(h2) * dv(r1)) < degentol);
226 const bool degen2 =
227 form == 2 && (dv(r2) > 1.0 - degentol ||
228 std::fabs(dv(h1) - dv(h2) + dv(h2) * dv(r1)) < degentol);
229 if (degen1 || degen2) {
230 if (dv(r1) < degentol) r1 = num_traits<T>::from_double(degentol);
231 if (dv(r2) > 1.0 - degentol) r2 = num_traits<T>::from_double(1.0 - degentol);
232 if (std::fabs(dv(h1) - dv(h2) + dv(h2) * dv(r1)) < degentol)
233 h1 = T(h2 * (one - r1) + num_traits<T>::from_double(degentol));
234 mp.D0 = Matrix<T>(2, 2, zero);
235 mp.D1 = Matrix<T>(2, 2, zero);
236 mp.D0(0, 0) = T(-one / h1);
237 mp.D0(0, 1) = T(r1 / h1);
238 mp.D0(1, 1) = T(-one / h2);
239 if (form == 1) {
240 mp.D1(0, 0) = T((one - r1) / h1);
241 mp.D1(1, 0) = T(r2 / h2);
242 mp.D1(1, 1) = T((one - r2) / h2);
243 } else {
244 mp.D1(0, 1) = T((one - r1) / h1);
245 mp.D1(1, 0) = T(r2 / h2);
246 mp.D1(1, 1) = T((one - r2) / h2);
247 }
248 mp = map_normalize(mp);
249 out.mmap.D0 = mp.D0;
250 out.mmap.D1 = mp.D1;
251 }
252
253 // ---- the degenerate ladder ------------------------------------------
254 if (form == 2 && dv(r2) < degentol && std::fabs(1.0 - dv(r1)) < degentol) {
255 finish(p[0], p[0], p[0]);
256 return out;
257 }
258 if (form == 1 && dv(r2) < degentol) {
259 // The reference has no forward targets for the MAPH fitter, so it uses
260 // the ordinary mean as both backward targets and WARNS; the warning is
261 // carried out rather than dropped.
262 Map<T> aph = mp;
263 aph.D1(1, 1) = zero;
264 aph = map_normalize(aph);
265 if (dv(map_scv(aph)) < 1.0 + degentol) aph = aph2_fit_map(mp).aph;
266 const T mean = map_mean(aph);
267 const std::vector<T> Bsub(2, mean);
268 const Maph2mFitResult<T> r = maph2m_fit_multiclass(aph, p, Bsub, cw);
269 adopt(r.maph);
270 out.warning =
271 "mamap22_fit_fs_multiclass: the canonical phase-type branch fits BACKWARD moments and "
272 "had no forward targets to use, so both were set to the ordinary mean; fit with "
273 "mamap22_fit_bs_multiclass instead if the forward moments matter";
274 return out;
275 }
276 if (std::fabs(1.0 - dv(r1)) < degentol) {
277 // Non-canonical: only the forward moment is identifiable, through a
278 // one-variable inverse whose feasible set is an interval.
279 auto degen_forward = [&](const T& vF1, T* q1, T* q2, T* q3) {
280 *q1 = p[0]; // meaningless when the form is truly degenerate
281 *q2 = T(p[0] * (h2 - vF1) / (h1 * (r2 - one)));
282 *q3 = T(p[0] * (h1 + h2 - vF1) / (h1 * r2));
283 };
284 T q1 = zero, q2 = zero, q3 = zero;
285 degen_forward(F[0], &q1, &q2, &q3);
286 if (!(feasible(q1) && feasible(q2) && feasible(q3))) {
287 const T q2F = T(-p[0] / (h1 * (r2 - one)));
288 const T q2_0 = T(p[0] * h2 / (h1 * (r2 - one)));
289 const T q3F = T(-p[0] / (h1 * r2));
290 const T q3_0 = T(p[0] * (h1 + h2) / (h1 * r2));
291 double lo = 1e-6, hi = 1e6;
292 const double coefs[2] = {dv(q2F), dv(q3F)};
293 const double offs[2] = {dv(q2_0), dv(q3_0)};
294 for (int i = 0; i < 2; ++i) {
295 if (std::fabs(coefs[i]) < denumtol) continue;
296 const double a = -offs[i] / coefs[i], b = (1.0 - offs[i]) / coefs[i];
297 lo = std::max(lo, std::min(a, b));
298 hi = std::min(hi, std::max(a, b));
299 }
300 if (!(lo <= hi))
301 throw NumericError(
302 "mamap22_fit_fs_multiclass: the non-canonical forward fit has an empty "
303 "feasible interval for this (p, F)");
304 double x = dv(F[0]);
305 if (x < lo) x = lo;
306 if (x > hi) x = hi;
307 degen_forward(num_traits<T>::from_double(x), &q1, &q2, &q3);
308 }
309 finish(q1, q2, q3);
310 return out;
311 }
312 if (form == 2 && dv(r2) < degentol) {
313 auto degen_forward2 = [&](const T& vF1, T* q1, T* q2, T* q3) {
314 *q1 = T(p[0] * (r1 - two) * (h1 + h2 * r1 - vF1) / ((r1 - one) * (h1 - h2 + h2 * r1)));
315 *q2 = T(-p[0] * (vF1 - h2) * (r1 - two) / (h1 - h2 + h2 * r1));
316 *q3 = p[0];
317 };
318 T q1 = zero, q2 = zero, q3 = zero;
319 if (dv(fw[0]) > dv(fw[1])) {
320 degen_forward2(F[0], &q1, &q2, &q3);
321 if (!(feasible(q1) && feasible(q2) && feasible(q3))) {
322 const T q1F = T(-p[0] * (r1 - two) / ((r1 - one) * (h1 - h2 + h2 * r1)));
323 const T q1_0 =
324 T(p[0] * (r1 - two) * (h1 + h2 * r1) / ((r1 - one) * (h1 - h2 + h2 * r1)));
325 const T q2F = T(-p[0] * (r1 - two) / (h1 - h2 + h2 * r1));
326 const T q2_0 = T(p[0] * (r1 - two) * h2 / (h1 - h2 + h2 * r1));
327 double lo = 1e-6, hi = 1e6;
328 const double coefs[2] = {dv(q1F), dv(q2F)};
329 const double offs[2] = {dv(q1_0), dv(q2_0)};
330 for (int i = 0; i < 2; ++i) {
331 if (std::fabs(coefs[i]) < denumtol) continue;
332 const double a = -offs[i] / coefs[i], b = (1.0 - offs[i]) / coefs[i];
333 lo = std::max(lo, std::min(a, b));
334 hi = std::min(hi, std::max(a, b));
335 }
336 if (!(lo <= hi))
337 throw NumericError(
338 "mamap22_fit_fs_multiclass: the degenerate forward fit has an empty "
339 "feasible interval for this (p, F)");
340 double x = dv(F[0]);
341 if (x < lo) x = lo;
342 if (x > hi) x = hi;
343 degen_forward2(num_traits<T>::from_double(x), &q1, &q2, &q3);
344 }
345 finish(q1, q2, q3);
346 return out;
347 }
348 // The sigma-weighted arm. The reference states this repair as a YALMIP
349 // program, but it is a ONE-VARIABLE CONVEX QP -- minimize (x - S11)^2
350 // over {0 <= x <= p1^2, x >= p1^2(1-(1-r1)^2), x >= p1^2-(1-p1)^2} --
351 // so the projection below IS its global optimum, not a local stand-in.
352 // sqrt(p1^2 - S11) is COMPLEX above p1^2, where the reference's own
353 // feasibility test then fails on the real part and sends it to the
354 // repair. Report that as "not feasible" instead of raising, so the
355 // repair below is reachable from the same inputs.
356 auto degen_transition = [&](const T& vS11, T* a, T* b, T* c2) {
357 const double root = dv(T(p[0] * p[0] - vS11));
358 const T s = num_traits<T>::from_double(std::sqrt(std::max(root, 0.0)));
359 *a = T(p[0] + s / (r1 - one));
360 *b = T(p[0] + s);
361 *c2 = p[0];
362 return root >= 0.0;
363 };
364 const bool real = degen_transition(S(0, 0), &q1, &q2, &q3);
365 if (!real || !(feasible(q1) && feasible(q2) && feasible(q3))) {
366 const double p1 = dv(p[0]), rr1 = dv(r1);
367 double lo = std::max(0.0, std::max(p1 * p1 * (1.0 - (1.0 - rr1) * (1.0 - rr1)),
368 p1 * p1 - (1.0 - p1) * (1.0 - p1)));
369 const double hi = p1 * p1;
370 if (lo > hi)
371 throw NumericError(
372 "mamap22_fit_fs_multiclass: the sigma repair of the gamma < 0 degeneracy is "
373 "infeasible for this (p, r1)");
374 double s11 = dv(S(0, 0));
375 if (s11 < lo) s11 = lo;
376 if (s11 > hi) s11 = hi;
377 degen_transition(num_traits<T>::from_double(s11), &q1, &q2, &q3);
378 }
379 finish(q1, q2, q3);
380 return out;
381 }
382
383 // ---- the full form ---------------------------------------------------
384 const Mamap2mCoefficients<T> c = form == 1
385 ? mamap2m_can1_coefficients(h1, h2, r1, r2)
386 : mamap2m_can2_coefficients(h1, h2, r1, r2);
387 T q1 = zero, q2 = zero, q3 = zero;
388 if (form == 1)
389 fsdetail::fit_can1(c, p[0], F[0], S(0, 0), denumtol, &q1, &q2, &q3);
390 else
391 fsdetail::fit_can2(c, p[0], F[0], S(0, 0), denumtol, &q1, &q2, &q3);
392
393 if (feasible(q1) && feasible(q2) && feasible(q3)) {
394 out.exact = true;
395 finish(q1, q2, q3);
396 return out;
397 }
398 if (!adjust) {
399 finish(q1, q2, q3);
400 return out;
401 }
402 throw UnsupportedError(
403 "mamap22_fit_fs_multiclass: the closed-form forward-plus-sigma inverse is infeasible for "
404 "these targets, and the reference's repair solves a NONCONVEX bilinear program with "
405 "YALMIP's bmibnb, a spatial branch-and-bound returning a GLOBAL optimum. That solver is "
406 "not ported; a local method would report a different fit under the same name. Pass "
407 "adjust = false to take the clamped closed form, or use mamap2m_fit_fb_multiclass");
408}
409
410
411/**
412 * `mamap22_fit_gamma_fs`: fit over every AMAP(2) form and keep the closest.
413 *
414 * Port of matlab/lib/m3a/m3a/mamap22/mamap22_fit_gamma_fs.m. When the moment
415 * set admits only a one-state process, the reference perturbs the second and
416 * third moments slightly above the exponential to recover a two-state form, and
417 * falls back to a marked Poisson only if that also fails; both steps are here.
418 */
419template <class T>
420Mmap<T> mamap22_fit_gamma_fs(const T& M1, const T& M2, const T& M3, const T& GAMMA,
421 const std::vector<T>& p, const std::vector<T>& F,
422 const Matrix<T>& S) {
423 const T one = num_traits<T>::from_int(1);
424 Amap2FitGammaResult<T> a = amap2_fit_gamma(M1, M2, M3, GAMMA);
425 if (a.amaps.size() == 1 && a.amaps[0].order() == 1) {
426 // Perturb just above the exponential to recover a second-order form.
427 const T M2a = T(M2 * (one + num_traits<T>::from_double(1e-4)));
428 const T ratio = T(M2a / M2);
429 const T M3a = T(M3 * num_traits<T>::from_double(
430 std::pow(num_traits<T>::to_double(ratio), 1.5)));
431 const std::vector<Map<T>> alt = amap2_fitall_gamma(M1, M2a, M3a, GAMMA);
432 if (!alt.empty()) {
433 a.amaps.clear();
434 for (std::size_t j = 0; j < alt.size(); ++j) a.amaps.push_back(map_normalize(alt[j]));
435 } else {
436 return mamapdetail::marked_poisson(M1, p);
437 }
438 }
439
440 Mmap<T> best;
441 double bestErr = 0.0;
442 bool have = false;
443 for (std::size_t j = 0; j < a.amaps.size(); ++j) {
445 try {
446 r = mamap22_fit_fs_multiclass(a.amaps[j], p, F, S);
447 } catch (const Error&) {
448 continue;
449 }
450 // the reference scores on the FIRST class alone: fF(1) and fS(1,1)
451 const double df = num_traits<T>::to_double(T(F[0] / r.fF[0])) - 1.0;
452 const double ds = num_traits<T>::to_double(T(S(0, 0) / r.fS(0, 0))) - 1.0;
453 const double err = df * df + ds * ds;
454 if (!have || err < bestErr) {
455 bestErr = err;
456 best = r.mmap;
457 have = true;
458 }
459 }
460 if (!have)
461 throw NumericError(
462 "mamap22_fit_gamma_fs: no AMAP(2) form admits a feasible forward-plus-sigma marking "
463 "for these targets");
464 return best;
465}
466
467/** `mamap22_fit_gamma_fs` driven from a marked trace. */
468template <class T>
469Mmap<T> mamap22_fit_gamma_fs_trace(const std::vector<T>& Tv, const std::vector<int>& A) {
470 if (Tv.empty() || Tv.size() != A.size())
471 throw InputError(
472 "mamap22_fit_gamma_fs_trace: the trace and its labels must agree in length");
473 const T zero = num_traits<T>::from_int(0);
474 T m1 = zero, m2 = zero, m3 = zero;
475 for (std::size_t i = 0; i < Tv.size(); ++i) {
476 const T x = Tv[i];
477 m1 += x;
478 m2 += x * x;
479 m3 += x * x * x;
480 }
481 const T n = num_traits<T>::from_int(static_cast<long>(Tv.size()));
482 const std::vector<unsigned> ord(1, 1u);
483 const std::vector<T> p = trace::mtrace_pc<T>(A);
484 const Matrix<T> fm = trace::mtrace_forward_moment(Tv, A, ord);
485 std::vector<T> F(p.size(), zero);
486 for (std::size_t c = 0; c < p.size(); ++c) F[c] = fm(c, 0);
488 return mamap22_fit_gamma_fs(T(m1 / n), T(m2 / n), T(m3 / n),
489 line::trace::trace_gamma(Tv).gamma, p, F, S);
490}
491
492} // namespace mam
493} // namespace line
494
495#endif // LINE_API_MAM_MAMAP22_FIT_FS_H
AMAP(2) fit of three moments and the autocorrelation decay rate (matlab/lib/m3a/m3a/amap2/amap2_fit_g...
All AMAP(2) representations matching three moments and the autocorrelation decay rate (matlab/lib/m3a...
Base error for the multiprecision C++ port.
Definition error.h:31
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
NumericError(const std::string &what)
Definition error.h:45
UnsupportedError(const std::string &what)
Definition error.h:51
The exception types the port throws.
The m3a fitters driven from a process or from a trace rather than from moments.
Fit a MAMAP(2,2) matching the BACKWARD moment and the class TRANSITION probability sigma.
The marking coefficients of a canonical AMAP(2), for the sigma fitters.
The marked Poisson process every MAMAP fitter falls back to.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
MAP constructors and structural transformations.
Fit a MAPH(2,m): a second-order acyclic phase-type marked with m classes.
Dense matrix and non-owning view.
Compression of a marked MAP into a smaller representation, and the two M3A primitives it is built fro...
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
Marked MAP statistics: embedded chains, class-transition probabilities, forward and cross moments,...
Forward moments of a marked trace: the moments of the inter-arrival time that FOLLOWS an event of eac...
Class probabilities of a marked trace, p_c = count_c / N.
One-step class transition frequencies of a marked trace,.
Mamap2mCoefficients< T > mamap2m_can1_coefficients(const T &h1, const T &h2, const T &r1, const T &r2)
First canonical form, a positive autocorrelation decay.
Amap2FitGammaResult< T > amap2_fit_gamma(const T &M1, const T &M2, const T &M3, const T &GAMMA, const T &cvtol)
Fit an AMAP(2) to (M1, M2, M3, GAMMA).
Matrix< T > mmap_forward_moment(const Mmap< T > &mm, const std::vector< unsigned > &orders, bool normalize)
Forward moments: MOMENTS(a,h) is the order-orders[h] moment of the interval ENDING with a class-a arr...
Definition mmap_stats.h:290
Mmap< T > mamap22_fit_gamma_fs(const T &M1, const T &M2, const T &M3, const T &GAMMA, const std::vector< T > &p, const std::vector< T > &F, const Matrix< T > &S)
mamap22_fit_gamma_fs: fit over every AMAP(2) form and keep the closest.
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
Definition map_moment.h:101
Mamap2mCoefficients< T > mamap2m_can2_coefficients(const T &h1, const T &h2, const T &r1, const T &r2)
Second canonical form, a negative autocorrelation decay (E, V, Z).
Aph2FitResult< T > aph2_fit_map(const Map< T > &m)
Fit an APH(2) to the first three moments of a MAP.
Mamap22FsFitResult< T > mamap22_fit_fs_multiclass(const Map< T > &map, const std::vector< T > &p, const std::vector< T > &F, const Matrix< T > &S, const std::vector< T > &classWeights=std::vector< T >(), const std::vector< T > &fsWeights=std::vector< T >(), bool adjust=true)
Matrix< T > mmap_sigma(const Mmap< T > &mm)
sigma(i,j) = pie E_i E_j 1, the probability that two consecutive marks are (i,j).
Definition mmap_stats.h:140
T map_scv(const Map< T > &m)
Squared coefficient of variation.
Definition map_moment.h:140
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...
std::vector< Map< T > > amap2_fitall_gamma(const T &M1, const T &M2, const T &M3, const T &GAMMA, const T &degentol, const T &r12tol)
Every AMAP(2) matching (M1, M2, M3, GAMMA).
Mmap< T > mamap22_fit_gamma_fs_trace(const std::vector< T > &Tv, const std::vector< int > &A)
mamap22_fit_gamma_fs driven from a marked trace.
Maph2mFitResult< T > maph2m_fit_multiclass(const Map< T > &aph, const std::vector< T > &p, const std::vector< T > &B, const std::vector< T > &classWeights=std::vector< T >())
Mark a canonical acyclic APH(2) with m classes.
Definition maph2m_fit.h:89
Matrix< T > mtrace_forward_moment(const std::vector< T > &Tv, const std::vector< int > &A, const std::vector< unsigned > &orders, bool norm=true)
Forward moments of a marked trace: the moments of the inter-arrival time that FOLLOWS an event of eac...
TraceGammaResult< T > trace_gamma(const std::vector< T > &S, long limit=1000, const std::vector< T > &grid=std::vector< T >())
Autocorrelation decay rate of a trace: the gamma of the geometric model rho(k) = rho0 * gamma^k,...
Definition trace_gamma.h:73
std::vector< T > mtrace_pc(const std::vector< int > &A)
Class probabilities of a marked trace, p_c = count_c / N.
Definition mtrace_pc.h:42
Matrix< T > mtrace_sigma(const std::vector< int > &L)
One-step class transition frequencies of a marked trace, sigma(i,j) = #{t : A_t = i,...
T num_abs(const T &v)
Definition number.h:172
Number-type abstraction for the templated API port.
Result of amap2_fit_gamma.
std::vector< Map< T > > amaps
every exact solution found
The forward-plus-sigma result; warning carries the reference's diagnostic.
std::string warning
empty unless a branch substituted its targets
std::vector< T > fF
achieved per-class forward moments
Matrix< T > fS
achieved class transition probabilities
The three coefficient tables of one canonical form.
std::vector< T > G
15 entries for form 1, 14 for form 2 (there called E)
std::vector< T > Y
3 determinants (Z for form 2)
std::vector< T > U
12 entries (V for form 2)
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53
Matrix< T > D1
Definition map_moment.h:55
Matrix< T > D0
Definition map_moment.h:54
The fitted MAPH and the backward moments it actually achieved.
Definition maph2m_fit.h:75
An MMAP: the underlying MAP plus the per-class arrival matrices.
Definition mmap_lambda.h:45
Autocorrelation decay rate of a trace: the gamma of the geometric model rho(k) = rho0 * gamma^k,...