5#ifndef LINE_API_MAM_MAP_DIST_H
6#define LINE_API_MAM_MAP_DIST_H
51Matrix<T> sylv_solve(
const Matrix<T>& A,
const Matrix<T>& B,
const Matrix<T>& C) {
52 const std::size_t m = A.rows(), n = B.cols();
53 if (A.cols() != m || B.rows() != n)
throw InputError(
"sylv_solve: A and B must be square");
54 if (C.rows() != m || C.cols() != n)
55 throw InputError(
"sylv_solve: the right-hand side is not conformable");
56 const std::size_t N = m * n;
57 Matrix<T> M(N, N, num_traits<T>::from_int(0));
59 for (std::size_t j = 0; j < n; ++j)
60 for (std::size_t ia = 0; ia < m; ++ia)
61 for (std::size_t ja = 0; ja < m; ++ja) M(j * m + ia, j * m + ja) += A(ia, ja);
62 for (std::size_t jb = 0; jb < n; ++jb)
63 for (std::size_t ib = 0; ib < n; ++ib)
64 for (std::size_t k = 0; k < m; ++k) M(jb * m + k, ib * m + k) += B(ib, jb);
65 std::vector<T> rhs = vec_colmajor(C);
66 for (std::size_t k = 0; k < N; ++k) rhs[k] = -rhs[k];
67 const std::vector<T> x =
solve(M, rhs);
68 Matrix<T> X(m, n, num_traits<T>::from_int(0));
69 for (std::size_t j = 0; j < n; ++j)
70 for (std::size_t i = 0; i < m; ++i) X(i, j) = x[j * m + i];
76Matrix<T> tr(
const Matrix<T>& A) {
77 Matrix<T> B(A.cols(), A.rows());
78 for (std::size_t i = 0; i < A.rows(); ++i)
79 for (std::size_t j = 0; j < A.cols(); ++j) B(j, i) = A(i, j);
85Matrix<T> negrowsum(
const Matrix<T>& D0) {
86 Matrix<T> v(D0.rows(), 1, num_traits<T>::from_int(0));
87 for (std::size_t i = 0; i < D0.rows(); ++i)
88 for (std::size_t j = 0; j < D0.cols(); ++j) v(i, 0) -= D0(i, j);
94Matrix<T> outer(
const std::vector<T>& u,
const std::vector<T>& v) {
95 Matrix<T> M(u.size(), v.size(), num_traits<T>::from_int(0));
96 for (std::size_t i = 0; i < u.size(); ++i)
97 for (std::size_t j = 0; j < v.size(); ++j) M(i, j) = u[i] * v[j];
108T quad_kron(
const Matrix<T>& A,
const Matrix<T>& X,
const Matrix<T>& Z,
const Matrix<T>& B) {
110 if (AXBt.rows() != Z.rows() || AXBt.cols() != Z.cols())
111 throw InputError(
"quad_kron: the two Sylvester solutions are not conformable");
112 T s = num_traits<T>::from_int(0);
113 for (std::size_t i = 0; i < Z.rows(); ++i)
114 for (std::size_t j = 0; j < Z.cols(); ++j) s += Z(i, j) * AXBt(i, j);
120T rcond1(
const Matrix<T>& M) {
121 const T zero = num_traits<T>::from_int(0);
123 for (std::size_t j = 0; j < M.cols(); ++j) {
125 for (std::size_t i = 0; i < M.rows(); ++i) c +=
num_abs(M(i, j));
128 if (nM == zero)
return zero;
129 const Matrix<T> Mi =
inverse(M);
131 for (std::size_t j = 0; j < Mi.cols(); ++j) {
133 for (std::size_t i = 0; i < Mi.rows(); ++i) c +=
num_abs(Mi(i, j));
136 if (nI == zero)
return zero;
137 return num_traits<T>::from_int(1) / (nM * nI);
150 const std::vector<T>& alB) {
151 if (L == 0)
throw InputError(
"map_exp_mul_int: the lag L must be positive");
152 const Matrix<T> B0t = detail::tr(b.
D0), B1t = detail::tr(b.
D1);
153 Matrix<T> Z = detail::sylv_solve(B0t, a.
D0, detail::outer(alB, alA));
154 for (
unsigned i = 1; i < L; ++i)
156 const Matrix<T> ea = detail::negrowsum(a.
D0), eb = detail::negrowsum(b.
D0);
158 for (std::size_t i = 0; i < eb.rows(); ++i)
159 for (std::size_t j = 0; j < ea.
rows(); ++j) d += eb(i, 0) * Z(i, j) * ea(j, 0);
179 const std::vector<T>& alB) {
180 const std::size_t NA = a.
order(), NB = b.
order();
182 Matrix<T> negA0(NA, NA, zero), negB0(NB, NB, zero);
183 for (std::size_t i = 0; i < NA; ++i)
184 for (std::size_t j = 0; j < NA; ++j) negA0(i, j) = -a.
D0(i, j);
185 for (std::size_t i = 0; i < NB; ++i)
186 for (std::size_t j = 0; j < NB; ++j) negB0(i, j) = -b.
D0(i, j);
189 for (std::size_t i = 0; i < NA; ++i)
190 for (std::size_t j = 0; j < NA; ++j) PAh(i, j) -= alA[j];
191 for (std::size_t i = 0; i < NB; ++i)
192 for (std::size_t j = 0; j < NB; ++j) PBh(i, j) -= alB[j];
195 for (std::size_t jb = 0; jb < NB; ++jb)
196 for (std::size_t ib = 0; ib < NB; ++ib)
197 for (std::size_t ia = 0; ia < NA; ++ia)
198 for (std::size_t ja = 0; ja < NA; ++ja)
199 M(jb * NA + ia, ib * NA + ja) = -PBh(ib, jb) * PAh(ia, ja);
200 for (std::size_t k = 0; k < NA * NB; ++k) M(k, k) += one;
201 const T rc = detail::rcond1(M);
202 if (rc == zero)
throw InputError(
"map_geo_mul_sum: the Stein operator is singular");
205 std::vector<T> ra(NA, zero);
206 for (std::size_t i = 0; i < NA; ++i)
207 for (std::size_t j = 0; j < NA; ++j) ra[i] += A0i(i, j);
208 const std::vector<T> cb =
vecmul(alB, B0i);
209 const Matrix<T> X = detail::stein_solve(PAh, PBh, detail::outer(ra, cb));
212 const std::vector<T> w =
vecmul(u, B0i);
214 for (std::size_t j = 0; j < NB; ++j) d += w[j];
227 const std::vector<T>& alB) {
242 const std::vector<T>& alB) {
246 const T varA = m2A - mA * mA, varB = m2B - mB * mB;
248 throw InputError(
"map_dist_acf: a deterministic MAP has no autocorrelation");
249 return (
map_geo_mul_sum(a, a, alA, alA) - m2A * m2A / four) / (varA * varA) -
250 two * (
map_geo_mul_sum(a, b, alA, alB) - m2A * m2B / four) / (varA * varB) +
269 const std::vector<T>& alB) {
270 const std::size_t NA = a.
order(), NB = b.
order();
271 const Matrix<T> A0t = detail::tr(a.
D0), B0t = detail::tr(b.
D0);
272 const Matrix<T> ea = detail::negrowsum(a.
D0), eb = detail::negrowsum(b.
D0);
273 std::vector<T> av(NA), bv(NB);
274 for (std::size_t i = 0; i < NA; ++i) av[i] = ea(i, 0);
275 for (std::size_t i = 0; i < NB; ++i) bv[i] = eb(i, 0);
276 const Matrix<T> Z_AB = detail::sylv_solve(A0t, b.
D0, detail::outer(alA, alB));
277 const Matrix<T> Z_AA = detail::sylv_solve(A0t, a.
D0, detail::outer(alA, alA));
278 const Matrix<T> Z_BB = detail::sylv_solve(B0t, b.
D0, detail::outer(alB, alB));
279 const Matrix<T> X_AB = detail::sylv_solve(a.
D0, B0t, detail::outer(av, bv));
280 const Matrix<T> X_AA = detail::sylv_solve(a.
D0, A0t, detail::outer(av, av));
281 const Matrix<T> X_BB = detail::sylv_solve(b.
D0, B0t, detail::outer(bv, bv));
283 return detail::quad_kron(b.
D1, X_BB, Z_BB, b.
D1) + detail::quad_kron(a.
D1, X_AA, Z_AA, a.
D1) -
284 two * detail::quad_kron(a.
D1, X_AB, Z_AB, b.
D1);
Discrete-time Markovian arrival processes (D-MAPs).
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.
T map_dist_acf(const Map< T > &a, const Map< T > &b, const std::vector< T > &alA, const std::vector< T > &alB)
Squared L2 distance between the two autocorrelation functions (map_dist_acf.m).
T map_dist_lag1(const Map< T > &a, const Map< T > &b, const std::vector< T > &alA, const std::vector< T > &alB)
Squared L2 distance between the two lag-one joint densities (map_dist_lag1.m).
T map_geo_mul_sum(const Map< T > &a, const Map< T > &b, const std::vector< T > &alA, const std::vector< T > &alB)
Geometrically weighted sum of the cross moments of the two embedded chains.
T map_dist(const Map< T > &a, const Map< T > &b, unsigned L, const std::vector< T > &alA, const std::vector< T > &alB)
Squared L2 distance between the two joint densities up to lag L (map_dist.m).
std::vector< T > map_pie(const Map< T > &m)
Phase distribution seen by an arriving job, pie = pi D1 / (pi D1 e).
T map_moment(const Map< T > &m, unsigned k)
Raw moment of order k of the inter-arrival time: k!
T map_exp_mul_int(const Map< T > &a, const Map< T > &b, unsigned L, const std::vector< T > &alA, const std::vector< T > &alB)
Integral of the product of the two interarrival densities up to lag L.
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.
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.
Number-type abstraction for the templated API port.
A MAP as the pair of matrices (D0, D1).
std::size_t order() const