5#ifndef LINE_API_MAM_MAP_TRANSFORM_H
6#define LINE_API_MAM_MAP_TRANSFORM_H
56 const std::size_t n = m.
order();
57 if (m.
D1.rows() != n || m.
D0.cols() != n || m.
D1.cols() != n)
58 throw InputError(
"map_normalize: D0 and D1 must be square and of equal order");
59 for (std::size_t i = 0; i < n; ++i)
60 for (std::size_t j = 0; j < n; ++j) {
61 if (i != j && m.
D0(i, j) < zero) m.
D0(i, j) = zero;
62 if (m.
D1(i, j) < zero) m.
D1(i, j) = zero;
64 for (std::size_t i = 0; i < n; ++i) {
67 for (std::size_t j = 0; j < n; ++j) s += m.
D0(i, j) + m.
D1(i, j);
77 const T ratio =
map_mean(in) / new_mean;
79 for (std::size_t i = 0; i < m.
order(); ++i)
80 for (std::size_t j = 0; j < m.
order(); ++j) {
106 const T ratio =
map_mean(in) / new_mean;
108 for (std::size_t i = 0; i < m.
order(); ++i)
109 for (std::size_t j = 0; j < m.
order(); ++j) {
126 if (k == 0)
throw InputError(
"map_erlang: k must be positive");
133 for (
unsigned i = 0; i + 1 < k; ++i) m.
D0(i, i + 1) = mu;
152 "map_hyperexp requires transcendental arithmetic");
158 for (
unsigned attempt = 0; attempt < 8; ++attempt) {
159 const T E2 = T((one + scv) * mean * mean);
160 const T Delta = T(-four * p * mean * mean + four * p * p * mean * mean + two * E2 * p -
163 const T sD = T(sqrt(Delta));
164 const T den = T(E2 * p - two * mean * mean);
166 for (
int root = 0; root < 2; ++root) {
167 const T mu2 = T((root == 0 ? T(-two * mean + two * p * mean + sD)
168 : T(-two * mean + two * p * mean - sD)) /
170 const T dd = T(p - one + mean * mu2);
172 const T mu1 = T(mu2 * p / dd);
178 m.
D1(0, 0) = mu1 * p;
179 m.
D1(0, 1) = mu1 * (one - p);
180 m.
D1(1, 0) = mu2 * p;
181 m.
D1(1, 1) = mu2 * (one - p);
189 throw NumericError(
"map_hyperexp: no feasible two-phase fit for this (mean, scv)");
204 if (n == 0)
throw InputError(
"map_sum: n must be positive");
205 const std::size_t order = in.
order();
206 const std::size_t N = order * n;
212 for (
unsigned i = 0; i < n; ++i) {
213 for (std::size_t a = 0; a < order; ++a)
214 for (std::size_t b = 0; b < order; ++b) m.
D0(cur + a, cur + b) = in.
D0(a, b);
216 for (std::size_t a = 0; a < order; ++a)
217 for (std::size_t b = 0; b < order; ++b)
218 m.
D0(cur + a, cur + order + b) = in.
D1(a, b);
220 for (std::size_t a = 0; a < order; ++a)
221 for (std::size_t b = 0; b < order; ++b) m.
D1(cur + a, b) = in.
D1(a, b);
235 if (maps.empty())
throw InputError(
"map_sumind: empty list");
236 const std::size_t n = maps.size();
237 std::vector<std::size_t> order(n), off(n + 1, 0);
238 for (std::size_t i = 0; i < n; ++i) {
239 order[i] = maps[i].order();
240 off[i + 1] = off[i] + order[i];
242 const std::size_t N = off[n];
247 for (std::size_t i = 0; i < n; ++i) {
248 for (std::size_t a = 0; a < order[i]; ++a)
249 for (std::size_t b = 0; b < order[i]; ++b)
250 m.
D0(off[i] + a, off[i] + b) = maps[i].D0(a, b);
253 const std::size_t nxt = (i + 1 < n) ? i + 1 : 0;
254 const std::vector<T> pie =
map_pie(maps[nxt]);
255 std::vector<T> rowsum(order[i], zero);
256 for (std::size_t a = 0; a < order[i]; ++a)
257 for (std::size_t b = 0; b < order[i]; ++b) rowsum[a] += maps[i].D1(a, b);
258 for (std::size_t a = 0; a < order[i]; ++a)
259 for (std::size_t b = 0; b < order[nxt]; ++b) {
260 const T val = rowsum[a] * pie[b];
262 m.
D0(off[i] + a, off[nxt] + b) = val;
264 m.
D1(off[i] + a, off[nxt] + b) = val;
277 if (maps.empty())
throw InputError(
"map_mixture: empty list");
278 if (alpha.size() != maps.size())
throw InputError(
"map_mixture: weight/list size mismatch");
279 const std::size_t n = maps.size();
280 std::vector<std::size_t> order(n), off(n + 1, 0);
281 for (std::size_t i = 0; i < n; ++i) {
282 order[i] = maps[i].order();
283 off[i + 1] = off[i] + order[i];
285 const std::size_t N = off[n];
290 std::vector<std::vector<T>> pies(n);
291 for (std::size_t j = 0; j < n; ++j) pies[j] =
map_pie(maps[j]);
292 for (std::size_t i = 0; i < n; ++i) {
293 for (std::size_t a = 0; a < order[i]; ++a)
294 for (std::size_t b = 0; b < order[i]; ++b)
295 m.
D0(off[i] + a, off[i] + b) = maps[i].D0(a, b);
296 std::vector<T> rowsum(order[i], zero);
297 for (std::size_t a = 0; a < order[i]; ++a)
298 for (std::size_t b = 0; b < order[i]; ++b) rowsum[a] += maps[i].D1(a, b);
299 for (std::size_t j = 0; j < n; ++j)
300 for (std::size_t a = 0; a < order[i]; ++a)
301 for (std::size_t b = 0; b < order[j]; ++b)
302 m.
D1(off[i] + a, off[j] + b) = rowsum[a] * alpha[j] * pies[j][b];
314 const std::size_t n = in.
order();
316 const std::vector<T> pie =
map_pie(in);
320 for (std::size_t a = 0; a < n; ++a) {
322 for (std::size_t b = 0; b < n; ++b) rs += in.
D1(a, b);
323 for (std::size_t b = 0; b < n; ++b) m.
D1(a, b) = rs * pie[b];
347 const std::size_t n = ph.
subgen.rows();
348 if (ph.
alpha.size() != n)
throw InputError(
"ph2map: alpha and T have different orders");
353 for (std::size_t a = 0; a < n; ++a) {
355 for (std::size_t b = 0; b < n; ++b) rs += ph.
subgen(a, b);
356 for (std::size_t b = 0; b < n; ++b) m.
D1(a, b) = -rs * ph.
alpha[b];
368 const std::size_t n = in.
order();
369 std::vector<bool> keep(n,
false);
370 for (std::size_t r : retain) {
371 if (r >= n)
throw InputError(
"map_stochcomp: retained index out of range");
374 std::vector<std::size_t> elim;
375 for (std::size_t i = 0; i < n; ++i)
376 if (!keep[i]) elim.push_back(i);
377 const std::size_t nr = retain.size(), ne = elim.size();
378 if (nr == 0)
throw InputError(
"map_stochcomp: no phase retained");
384 for (std::size_t a = 0; a < nr; ++a)
385 for (std::size_t b = 0; b < nr; ++b) {
386 out.
D0(a, b) = in.
D0(retain[a], retain[b]);
387 out.
D1(a, b) = in.
D1(retain[a], retain[b]);
391 Matrix<T> Q_EE(ne, ne), Q_RE(nr, ne), Q_ER(ne, nr), D1_ER(ne, nr);
392 for (std::size_t a = 0; a < ne; ++a)
393 for (std::size_t b = 0; b < ne; ++b) Q_EE(a, b) = Q(elim[a], elim[b]);
394 for (std::size_t a = 0; a < nr; ++a)
395 for (std::size_t b = 0; b < ne; ++b) Q_RE(a, b) = Q(retain[a], elim[b]);
396 for (std::size_t a = 0; a < ne; ++a)
397 for (std::size_t b = 0; b < nr; ++b) {
398 Q_ER(a, b) = Q(elim[a], retain[b]);
399 D1_ER(a, b) = in.
D1(elim[a], retain[b]);
402 for (std::size_t a = 0; a < ne; ++a)
403 for (std::size_t b = 0; b < ne; ++b) negQEE(a, b) = -Q_EE(a, b);
407 for (std::size_t a = 0; a < nr; ++a)
408 for (std::size_t b = 0; b < nr; ++b) {
409 const T Qnew = Q(retain[a], retain[b]) + corrQ(a, b);
410 out.
D1(a, b) = in.
D1(retain[a], retain[b]) + corrD1(a, b);
411 out.
D0(a, b) = Qnew - out.
D1(a, b);
427 return num / (v * v);
444 const T s = T(sqrt(
map_scv(m)));
445 const T den = T(s * m1);
446 return M3 / (den * den * den);
455T
map_joint(
const Map<T>& m,
const std::vector<unsigned>& a,
const std::vector<unsigned>& i) {
456 if (a.size() != i.size() || a.empty())
throw InputError(
"map_joint: a and i size mismatch");
457 const std::size_t n = m.
order();
458 const std::size_t K = a.size();
459 std::vector<unsigned> ca(K);
461 for (std::size_t k = 0; k < K; ++k) {
466 for (std::size_t r = 0; r < n; ++r)
467 for (std::size_t c = 0; c < n; ++c) negD0(r, c) = -negD0(r, c);
471 for (std::size_t k = 0; k + 1 < K; ++k) {
474 for (std::size_t r = 0; r < n; ++r)
475 for (std::size_t c = 0; c < n; ++c) blk(r, c) *= f;
480 for (std::size_t r = 0; r < n; ++r)
481 for (std::size_t c = 0; c < n; ++c) last(r, c) *= fl;
485 for (
const T& x : v) s += x;
499 const std::size_t n = m.
order();
506 for (std::size_t i = 0; i < n; ++i)
507 for (std::size_t j = 0; j < n; ++j) {
510 if (std::isnan(a) || std::isnan(b) || std::isinf(a) || std::isinf(b))
return false;
512 for (std::size_t i = 0; i < n; ++i)
513 for (std::size_t j = 0; j < n; ++j) {
514 if (i != j && m.
D0(i, j) < -tol)
return false;
515 if (i == j && m.
D0(i, j) > tol)
return false;
516 if (m.
D1(i, j) < -tol)
return false;
519 for (std::size_t i = 0; i < n; ++i) {
521 for (std::size_t j = 0; j < n; ++j) {
522 if (i != j && Q(i, j) < -tol)
return false;
525 if (
num_abs(T(rs)) > ntol)
return false;
528 for (std::size_t i = 0; i < n; ++i)
529 for (std::size_t j = 0; j < n; ++j) negD0(i, j) = -negD0(i, j);
536 for (std::size_t i = 0; i < n; ++i) {
538 for (std::size_t j = 0; j < n; ++j) {
539 if (P(i, j) < -tol)
return false;
542 if (
num_abs(T(rs - one)) > ntol)
return false;
572 for (
int k = 15; k >= 1; --k) {
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.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
Matrix< T > map_infgen(const Map< T > &m)
Generator of the underlying phase process, D0 + D1.
T map_joint(const Map< T > &m, const std::vector< unsigned > &a, const std::vector< unsigned > &i)
Joint moment of K consecutive inter-arrival times observed at the cumulative lags a,...
Map< T > map_hyperexp(const T &mean, const T &scv, const T &p_in)
Two-phase hyperexponential renewal MAP matching a mean and an SCV >= 1, with branching probability p ...
T map_skew(const Map< T > &m)
Skewness of the inter-arrival time (map_skew.m).
T map_mean(const Map< T > &m)
Mean inter-arrival time, 1/lambda.
T map_var(const Map< T > &m)
Variance of the inter-arrival time.
int map_feastol()
Tolerance exponent shared by the KPC feasibility checks (map_feastol.m).
Map< T > map_renewal(const Map< T > &in)
Renewal process with the same inter-arrival distribution: D1 is replaced by (D1 e) pie,...
Map< T > map_exponential(const T &lambda)
Two-phase MAP constructor for a Poisson process of rate lambda.
Map< T > map_erlang(const T &mean, unsigned k)
Erlang-k renewal MAP with the given mean (map_erlang.m).
bool map_isfeasible(const Map< T > &m, const T &tol)
Structural feasibility of a MAP within a tolerance (map_isfeasible.m): off-diagonal D0 and all of D1 ...
Map< T > map_exponential_mean(const T &mean)
Poisson process with the given mean inter-arrival time (map_exponential.m).
Map< T > map_sumind(const std::vector< Map< T > > &maps)
Sum of independent, not necessarily identical MAPs: after each component completes,...
Map< T > map_mixture(const std::vector< T > &alpha, const std::vector< Map< T > > &maps)
Probabilistic mixture of MAPs with weights alpha: after an arrival from component i the process jumps...
Map< T > map_sum(const Map< T > &in, unsigned n)
n-fold convolution of a MAP with itself: the inter-arrival time of the result is the sum of n consecu...
Map< T > map_scale_rate(const Map< T > &in, const T &new_mean)
Rescale to a target mean WITHOUT the feasibility repair, for a matrix exponential.
Map< T > ph2map(const PhType< T > &ph)
MAP whose inter-arrival time is the PH (alpha, T): the renewal MAP with D1 = (-T e) alpha.
bool map_checkfeasible(const Map< T > &m, const T &tol)
The reference's map_checkfeasible, i.e.
Map< T > map_scale(const Map< T > &in, const T &new_mean)
Rescale time so that the mean inter-arrival time becomes new_mean.
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
Map< T > map_stochcomp(const Map< T > &in, const std::vector< std::size_t > &retain)
Stochastic complement of a MAP on the retained phases (map_stochcomp.m): the eliminated phases are ce...
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...
T map_moment(const Map< T > &m, unsigned k)
Raw moment of order k of the inter-arrival time: k!
T map_kurt(const Map< T > &m)
Kurtosis of the inter-arrival time (map_kurt.m); rational in the entries.
PhType< T > map2ph(const Map< T > &in)
(alpha, T) of the inter-arrival distribution: alpha = pie, T = D0 (map2ph.m).
T num_factorial(unsigned n)
Factorial as a value of T.
std::vector< T > vecmul(const std::vector< T > &v, const Matrix< T > &A)
Row vector times matrix, v A.
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.
Matrix< T > matpow(const Matrix< T > &A, unsigned k)
Integer matrix power, by repeated squaring.
Matrix< T > eye(std::size_t n)
Identity of order n.
Number-type abstraction for the templated API port.
A MAP as the pair of matrices (D0, D1).
std::size_t order() const
A phase-type representation (alpha, T) of a MAP's inter-arrival time.
std::vector< T > alpha
entry distribution, = pie
Matrix< T > subgen
sub-generator, = D0