5#ifndef LINE_API_MAM_MAMAP22_FIT_FS_H
6#define LINE_API_MAM_MAMAP22_FIT_FS_H
89 double denumtol, T* q1, T* q2, T* q3) {
90 const T den = T(p1 * (c.
U[4] * vF1 + c.
U[5]));
95 *q2 = T((c.
U[0] * vF1 * vF1 * p1 * p1 + c.
U[1] * vF1 * p1 * p1 + c.
U[2] * vS11 +
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)) /
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)) /
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);
112 *q1 = *q2 = *q3 = p1;
115 *q3 = T((c.U[0] * vF1 * vF1 * p1 * p1 + c.U[1] * vF1 * p1 * p1 + c.U[2] * p1 * p1 +
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)) /
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)) /
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");
146 if (map.
D0.rows() != 2)
147 throw InputError(
"mamap22_fit_fs_multiclass: the underlying MAP must be second order");
149 throw InputError(
"mamap22_fit_fs_multiclass: the underlying MAP must be acyclic");
151 if (map.
D1(0, 1) == zero) form = 1;
152 else if (map.
D1(0, 0) == zero) form = 2;
155 "mamap22_fit_fs_multiclass: the underlying MAP must be in canonical acyclic form");
158 "mamap22_fit_fs_multiclass: fitting the forward moment and the transition "
159 "probabilities supports two classes only");
161 throw InputError(
"mamap22_fit_fs_multiclass: one forward moment per class is required");
163 throw InputError(
"mamap22_fit_fs_multiclass: the transition matrix is empty");
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);
172 const double degentol = 1e-6, feastol = 1e-3, denumtol = 1e-12;
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);
183 auto finish = [&](T q1, T q2, T q3) {
184 auto fix = [&](
const T& q) {
186 if (v < zero) v = zero;
187 if (v > one) v = one;
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));
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));
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);
206 out.
fF.assign(2, zero);
207 for (std::size_t c = 0; c < 2; ++c) out.
fF[c] = fm(c, 0);
210 auto feasible = [&](
const T& q) {
return dv(q) >= -feastol && dv(q) <= 1.0 + feastol; };
211 auto adopt = [&](
const Mmap<T>& m) {
213 const std::vector<unsigned> ord(1, 1u);
215 out.
fF.assign(2, zero);
216 for (std::size_t c = 0; c < 2; ++c) out.
fF[c] = fm(c, 0);
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);
227 form == 2 && (dv(r2) > 1.0 - degentol ||
228 std::fabs(dv(h1) - dv(h2) + dv(h2) * dv(r1)) < degentol);
229 if (degen1 || degen2) {
232 if (std::fabs(dv(h1) - dv(h2) + dv(h2) * dv(r1)) < degentol)
236 mp.
D0(0, 0) = T(-one / h1);
237 mp.
D0(0, 1) = T(r1 / h1);
238 mp.
D0(1, 1) = T(-one / h2);
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);
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);
254 if (form == 2 && dv(r2) < degentol && std::fabs(1.0 - dv(r1)) < degentol) {
255 finish(p[0], p[0], p[0]);
258 if (form == 1 && dv(r2) < degentol) {
267 const std::vector<T> Bsub(2, mean);
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";
276 if (std::fabs(1.0 - dv(r1)) < degentol) {
279 auto degen_forward = [&](
const T& vF1, T* q1, T* q2, T* q3) {
281 *q2 = T(p[0] * (h2 - vF1) / (h1 * (r2 - one)));
282 *q3 = T(p[0] * (h1 + h2 - vF1) / (h1 * r2));
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));
302 "mamap22_fit_fs_multiclass: the non-canonical forward fit has an empty "
303 "feasible interval for this (p, F)");
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));
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)));
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));
338 "mamap22_fit_fs_multiclass: the degenerate forward fit has an empty "
339 "feasible interval for this (p, F)");
356 auto degen_transition = [&](
const T& vS11, T* a, T* b, T* c2) {
357 const double root = dv(T(p[0] * p[0] - vS11));
359 *a = T(p[0] + s / (r1 - one));
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;
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;
387 T q1 = zero, q2 = zero, q3 = zero;
389 fsdetail::fit_can1(c, p[0], F[0], S(0, 0), denumtol, &q1, &q2, &q3);
391 fsdetail::fit_can2(c, p[0], F[0], S(0, 0), denumtol, &q1, &q2, &q3);
393 if (feasible(q1) && feasible(q2) && feasible(q3)) {
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");
421 const std::vector<T>& p,
const std::vector<T>& F,
425 if (a.
amaps.size() == 1 && a.
amaps[0].order() == 1) {
428 const T ratio = T(M2a / M2);
434 for (std::size_t j = 0; j < alt.size(); ++j) a.
amaps.push_back(
map_normalize(alt[j]));
436 return mamapdetail::marked_poisson(M1, p);
441 double bestErr = 0.0;
443 for (std::size_t j = 0; j < a.
amaps.size(); ++j) {
447 }
catch (
const Error&) {
453 const double err = df * df + ds * ds;
454 if (!have || err < bestErr) {
462 "mamap22_fit_gamma_fs: no AMAP(2) form admits a feasible forward-plus-sigma marking "
463 "for these targets");
470 if (Tv.empty() || Tv.size() != A.size())
472 "mamap22_fit_gamma_fs_trace: the trace and its labels must agree in length");
474 T m1 = zero, m2 = zero, m3 = zero;
475 for (std::size_t i = 0; i < Tv.size(); ++i) {
482 const std::vector<unsigned> ord(1, 1u);
485 std::vector<T> F(p.size(), zero);
486 for (std::size_t c = 0; c < p.size(); ++c) F[c] = fm(c, 0);
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.
NumericError(const std::string &what)
UnsupportedError(const std::string &what)
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...
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...
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.
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).
T map_scv(const Map< T > &m)
Squared coefficient of variation.
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 °entol, 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.
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,...
std::vector< T > mtrace_pc(const std::vector< int > &A)
Class probabilities of a marked trace, p_c = count_c / N.
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,...
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).
The fitted MAPH and the backward moments it actually achieved.
An MMAP: the underlying MAP plus the per-class arrival matrices.
Autocorrelation decay rate of a trace: the gamma of the geometric model rho(k) = rho0 * gamma^k,...