5#ifndef LINE_API_MAM_MMAP_K_FIT_H
6#define LINE_API_MAM_MMAP_K_FIT_H
72bool marking_inverse(
int form,
const T& h1,
const T& h2,
const T& r1,
const T& r2,
const T& p,
73 const T& Fc,
const T& Bc,
double degentol, T* q1, T* q2, T* q3) {
78 const T d1 = T((r2 - one) * (r1 - one) * (h1 * r2 - h2));
79 const T d2 = T((r2 - one) * r1);
80 const T d3 = T(r1 * r2 * (h1 + h2 * r1 - h2));
81 const T e1 = T(h1 + h2 * r1 - h2), e2 = T(h1 * r2 - h2);
82 if (small(d1) || small(d2) || small(d3) || small(e1) || small(e2))
return false;
83 const T W = T(r1 * r2 - r2 + one);
84 *q1 = T(p * W * ((h1 * r2 - h1 - h2) + Bc) / d1);
86 ((h1 * h1 * (r2 - one) + h1 * h2 * r1 * (r2 - one) - h2 * h2 * r1) / (e1 * e2) -
89 *q3 = T(p * W * ((h1 + h2 * r1) - Fc) / d3);
91 const T U = T(h1 * r1 * r2 - h1 * r1 + h1 - h2);
92 const T d1 = T((r2 - one) * (r1 - one) * U);
93 const T e1 = T(h1 + h2 * r1 - h2);
94 const T d2 = T((r2 - one) * e1);
95 if (small(d1) || small(d2) || small(r2) || small(U) || small(e1))
return false;
96 const T V = T(r1 * r2 - r1 - r2 + two);
97 *q1 = T(p * V * ((h1 * r1 * r2 - h1 * r1 - h2) + Bc) / d1);
98 *q2 = T(p * V * (h2 - Fc) / d2);
100 ((h1 * h1 + h1 * h2 * r1 * r2 - h2 * h2) / (e1 * U) - Fc / e1 - Bc / U) / r2);
106inline std::vector<std::pair<unsigned, unsigned>> marking_orders(std::size_t n, std::size_t z) {
107 std::vector<std::pair<unsigned, unsigned>> o;
109 o.push_back(std::make_pair(1u, 0u));
110 o.push_back(std::make_pair(1u, 1u));
111 o.push_back(std::make_pair(2u, 0u));
113 o.push_back(std::make_pair(1u, 0u));
114 o.push_back(std::make_pair(1u, 1u));
115 o.push_back(std::make_pair(2u, 0u));
116 o.push_back(std::make_pair(3u, 0u));
118 o.push_back(std::make_pair(1u, 0u));
119 o.push_back(std::make_pair(1u, 1u));
121 while (o.size() < n + 1) o.push_back(std::make_pair(a++, 0u));
123 if (o.size() > z) o.resize(z);
138 const std::vector<T>& P,
const std::vector<T>& F,
139 const std::vector<T>& B) {
142 const std::size_t K = P.size();
143 if (K == 0)
throw InputError(
"mmap2k_fit: no classes given");
144 if (F.size() != K || B.size() != K)
145 throw InputError(
"mmap2k_fit: P, F and B must have the same length");
146 const double degentol = 1e-8, feastol = 1e-8;
149 bool haveBest =
false;
150 double bestViol = 0.0;
153 std::vector<std::vector<T>> bestQ;
155 for (std::size_t j = 0; j < a.
amaps.size(); ++j) {
157 if (mp.
order() != 2)
continue;
158 if (!(
num_abs(T(mp.
D0(1, 0))) <= zero))
continue;
160 if (mp.
D1(0, 1) == zero) form = 1;
161 else if (mp.
D1(0, 0) == zero) form = 2;
164 const T h1 = T(-one / mp.
D0(0, 0)), h2 = T(-one / mp.
D0(1, 1));
165 const T r1 = T(mp.
D0(0, 1) * h1), r2 = T(mp.
D1(1, 1) * h2);
167 std::vector<std::vector<T>> q(3, std::vector<T>(K, zero));
169 for (std::size_t c = 0; c < K && ok; ++c)
170 ok = kfitdetail::marking_inverse(form, h1, h2, r1, r2, P[c], F[c], B[c], degentol,
171 &q[0][c], &q[1][c], &q[2][c]);
176 for (std::size_t jj = 0; jj < 3; ++jj) {
178 for (std::size_t c = 0; c < K; ++c) {
180 viol = std::max(viol, std::max(0.0, -v));
181 viol = std::max(viol, std::max(0.0, v - 1.0));
186 if (!haveBest || viol < bestViol) {
196 if (haveBest && bestViol <= feastol) {
200 for (std::size_t c = 0; c < K; ++c) {
201 for (std::size_t jj = 0; jj < 3; ++jj) {
202 if (bestQ[jj][c] < zero) bestQ[jj][c] = zero;
203 if (bestQ[jj][c] > one) bestQ[jj][c] = one;
206 out.
mmap.Dc[c](0, 0) = T(bestMap.
D1(0, 0) * bestQ[0][c]);
207 out.
mmap.Dc[c](1, 0) = T(bestMap.
D1(1, 0) * bestQ[1][c]);
208 out.
mmap.Dc[c](1, 1) = T(bestMap.
D1(1, 1) * bestQ[2][c]);
210 out.
mmap.Dc[c](0, 1) = T(bestMap.
D1(0, 1) * bestQ[0][c]);
211 out.
mmap.Dc[c](1, 0) = T(bestMap.
D1(1, 0) * bestQ[1][c]);
212 out.
mmap.Dc[c](1, 1) = T(bestMap.
D1(1, 1) * bestQ[2][c]);
233 const std::vector<T>& F,
const std::vector<T>& B,
234 const std::vector<T>& B2 = std::vector<T>()) {
237 const std::size_t K = P.size(), n = D0.
rows();
238 if (K == 0)
throw InputError(
"mmap3k_fit: no classes given");
239 if (F.size() != K || B.size() != K)
240 throw InputError(
"mmap3k_fit: P, F and B must have the same length");
241 if (n == 0 || D1.
rows() != n)
throw InputError(
"mmap3k_fit: D0 and D1 disagree");
242 const double feastol = 1e-8;
245 std::vector<std::pair<std::size_t, std::size_t>> nz;
246 for (std::size_t i = 0; i < n; ++i)
247 for (std::size_t j = 0; j < n; ++j)
248 if (!(D1(i, j) == zero)) nz.push_back(std::make_pair(i, j));
249 const std::size_t z = nz.size();
250 if (z == 0)
throw InputError(
"mmap3k_fit: the MAP has no arrival transitions to mark");
252 const std::vector<std::pair<unsigned, unsigned>> orders = kfitdetail::marking_orders(n, z);
253 std::vector<T> b2 = B2;
255 for (std::size_t i = 0; i < orders.size(); ++i)
256 if (orders[i].first == 3)
258 "mmap3k_fit: this MAP's marking system includes the third-order backward "
259 "characteristic, so the second-order backward moments B2 are required");
264 for (std::size_t i = 0; i < n; ++i)
265 for (std::size_t j = 0; j < n; ++j) negD0(i, j) = -D0(i, j);
271 for (std::size_t i = 0; i < n; ++i)
272 for (std::size_t j = 0; j < n; ++j) Tm(i, j) = T(Pemb(j, i) - (i == j ? one : zero));
273 for (std::size_t j = 0; j < n; ++j) Tm(n - 1, j) = one;
274 std::vector<T> rhs(n, zero);
276 const std::vector<T> pie =
solve(Tm, rhs);
279 std::vector<Matrix<T>> Apow(1,
eye<T>(n));
280 std::size_t maxpow = 0;
281 for (std::size_t i = 0; i < orders.size(); ++i)
282 maxpow = std::max<std::size_t>(maxpow, std::max(orders[i].first, orders[i].second));
283 for (std::size_t k = 1; k <= maxpow; ++k) Apow.push_back(
matmul(Apow[k - 1], A));
286 for (std::size_t jj = 0; jj < z; ++jj) {
288 Dc(nz[jj].first, nz[jj].second) = D1(nz[jj].first, nz[jj].second);
289 for (std::size_t ii = 0; ii < orders.size(); ++ii) {
293 for (std::size_t a = 0; a < n; ++a)
294 for (std::size_t b = 0; b < n; ++b) acc += pie[a] * R(a, b);
302 std::vector<std::vector<T>> q(z, std::vector<T>(K, zero));
303 for (std::size_t c = 0; c < K; ++c) {
304 std::vector<T> y(z, zero);
305 for (std::size_t ii = 0; ii < orders.size(); ++ii) {
306 const unsigned a = orders[ii].first, b = orders[ii].second;
307 if (a == 1 && b == 0) y[ii] = P[c];
308 else if (a == 1 && b == 1) y[ii] = T(P[c] * F[c]);
309 else if (a == 2 && b == 0) y[ii] = T(P[c] * B[c]);
310 else if (a == 3 && b == 0) y[ii] = T(P[c] * b2[c]);
313 "mmap3k_fit: no target is supplied for one of the marking characteristics");
320 "mmap3k_fit: the underlying MAP is on the degenerate locus of the marking system, "
321 "where the characteristics do not determine the split");
323 for (std::size_t jj = 0; jj < z; ++jj) q[jj][c] = x[jj];
327 for (std::size_t jj = 0; jj < z; ++jj) {
329 for (std::size_t c = 0; c < K; ++c) {
331 viol = std::max(viol, std::max(0.0, -v));
332 viol = std::max(viol, std::max(0.0, v - 1.0));
339 out.
exact = viol <= feastol;
343 for (std::size_t c = 0; c < K; ++c)
344 for (std::size_t jj = 0; jj < z; ++jj) {
346 if (v < zero) v = zero;
347 if (v > one) v = one;
348 out.
mmap.Dc[c](nz[jj].first, nz[jj].second) =
349 T(D1(nz[jj].first, nz[jj].second) * v);
AMAP(2) fit of three moments and the autocorrelation decay rate (matlab/lib/m3a/m3a/amap2/amap2_fit_g...
The algorithm cannot proceed on this instance (singular matrix, ...).
NumericError(const std::string &what)
The exception types the port throws.
Dense linear algebra over the templated number type: products, identity, inverse, and powers.
LU factorization with partial pivoting, templated on the number type.
Fit a MAMAP(2,m): a second-order acyclic MAP marked with m classes, matching the forward and backward...
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...
MmapKFitResult< T > mmap2k_fit(const T &M1, const T &M2, const T &M3, const T &GAMMA, const std::vector< T > &P, const std::vector< T > &F, const std::vector< T > &B)
Exact marking of an AMAP(2) against per-class (p, F, B).
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).
MmapKFitResult< T > mmap3k_fit(const Matrix< T > &D0, const Matrix< T > &D1, const std::vector< T > &P, const std::vector< T > &F, const std::vector< T > &B, const std::vector< T > &B2=std::vector< T >())
Exact marking of an arbitrary MAP by solving the marking system directly.
Mmap< T > mamap2m_fit_gamma_fb(const T &M1, const T &M2, const T &M3, const T &GAMMA, const std::vector< T > &p, const std::vector< T > &F, const std::vector< T > &B)
Fit a MAMAP(2,m) to three moments, the decay rate, the class probabilities and the forward and backwa...
Matrix< T > inverse(const Matrix< T > &A)
Inverse by LU with one factorization and n back substitutions.
Matrix< T > matmul(const Matrix< T > &A, const Matrix< T > &B)
Matrix product A B.
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.
Matrix< T > eye(std::size_t n)
Identity of order n.
Number-type abstraction for the templated API port.
Result of amap2_fit_gamma.
std::vector< Map< T > > amaps
every exact solution found
A MAP as the pair of matrices (D0, D1).
std::size_t order() const
A marked MAP and whether the marking system was solved exactly.
An MMAP: the underlying MAP plus the per-class arrival matrices.