5#ifndef LINE_API_PFQN_SENS_LINEARIZER_H
6#define LINE_API_PFQN_SENS_LINEARIZER_H
80 const std::vector<
Matrix<T>>& d2m,
const std::vector<int>& n,
82 const std::size_t M = m.
rows(), R = m.
cols(), MM = dm.size();
87 for (std::size_t l = 0; l < R; ++l) {
88 if (n[l] <= 0)
continue;
90 for (std::size_t i = 0; i < M; ++i) {
91 v(i, l) = m(i, l) / nT;
92 for (std::size_t h = 0; h < MM; ++h) {
93 dv[h](i, l) = dm[h](i, l) / nT;
94 d2v[h](i, l) = d2m[h](i, l) / nT;
106unsigned sens_lin_core2(
const Matrix<T>& L,
const std::vector<T>& Z,
const std::vector<int>& n,
108 const std::vector<std::vector<
Matrix<T>>>& ddelta,
111 std::vector<T>& lam,
Matrix<T>& w,
const T* tol,
unsigned maxiter) {
112 const std::size_t M = L.
rows(), R = L.
cols();
115 for (
int v : n)
nc += v;
116 const T tolm = tol ? *tol
123 std::vector<T> varprev(M, zero);
125 for (
unsigned iter = 1; iter <= maxiter; ++iter) {
131 std::vector<Matrix<T>> dv, d2v;
132 sens_lin_fractions(m, dm, d2m, n, v, dv, d2v);
134 std::vector<Matrix<T>> dmtot(M,
Matrix<T>(M, R, zero));
135 std::vector<Matrix<T>> d2mtot(M,
Matrix<T>(M, R, zero));
136 for (std::size_t l = 0; l < R; ++l) {
137 if (n[l] <= 0)
continue;
138 for (std::size_t i = 0; i < M; ++i) {
140 std::vector<T> dacc(M, zero), d2acc(M, zero);
141 for (std::size_t l2 = 0; l2 < R; ++l2) {
142 const int cnt = n[l2] - (l2 == l ? 1 : 0);
143 if (cnt <= 0)
continue;
145 acc += cT * (v(i, l2) + delta[i](l, l2));
146 for (std::size_t h = 0; h < M; ++h) {
147 dacc[h] += cT * (dv[h](i, l2) + ddelta[i][h](l, l2));
148 d2acc[h] += cT * (d2v[h](i, l2) + d2delta[i][h](l, l2));
152 for (std::size_t h = 0; h < M; ++h) {
153 dmtot[h](i, l) = dacc[h];
154 d2mtot[h](i, l) = d2acc[h];
161 std::vector<Matrix<T>> dw(M, Matrix<T>(M, R, zero)), d2w(M, Matrix<T>(M, R, zero));
162 const T one = num_traits<T>::from_int(1);
163 for (std::size_t l = 0; l < R; ++l) {
164 if (n[l] <= 0)
continue;
165 for (std::size_t i = 0; i < M; ++i) {
166 const T A = one + mtot(i, l);
167 w(i, l) = L(i, l) * A;
168 for (std::size_t h = 0; h < M; ++h) {
169 const T dA = dmtot[h](i, l);
170 const T d2A = d2mtot[h](i, l);
172 dw[h](i, l) = L(i, l) * (A + dA);
173 d2w[h](i, l) = L(i, l) * (num_traits<T>::from_int(2) * dA + d2A);
175 dw[h](i, l) = L(i, l) * dA;
176 d2w[h](i, l) = L(i, l) * d2A;
182 Matrix<T> dlam(R, M, zero), d2lam(R, M, zero);
183 for (std::size_t l = 0; l < R; ++l) {
184 if (n[l] <= 0)
continue;
186 for (std::size_t i = 0; i < M; ++i) sw += w(i, l);
187 const T den = (Z.empty() ? zero : Z[l]) + sw;
188 const T nT = num_traits<T>::from_int(n[l]);
190 const T den2 = den * den;
191 const T den3 = den2 * den;
192 for (std::size_t h = 0; h < M; ++h) {
193 T dden = zero, d2den = zero;
194 for (std::size_t i = 0; i < M; ++i) {
196 d2den += d2w[h](i, l);
198 dlam(l, h) = -nT * dden / den2;
199 d2lam(l, h) = -nT * d2den / den2 + num_traits<T>::from_int(2) * nT * dden * dden / den3;
203 dm.assign(M, Matrix<T>(M, R, zero));
204 d2m.assign(M, Matrix<T>(M, R, zero));
205 for (std::size_t l = 0; l < R; ++l) {
206 if (n[l] <= 0)
continue;
207 for (std::size_t i = 0; i < M; ++i) {
208 m(i, l) = lam[l] * w(i, l);
209 for (std::size_t h = 0; h < M; ++h) {
210 dm[h](i, l) = dlam(l, h) * w(i, l) + lam[l] * dw[h](i, l);
211 d2m[h](i, l) = d2lam(l, h) * w(i, l) +
212 num_traits<T>::from_int(2) * dlam(l, h) * dw[h](i, l) +
213 lam[l] * d2w[h](i, l);
220 for (std::size_t l = 0; l < R; ++l) {
221 if (n[l] <= 0)
continue;
222 const T nT = num_traits<T>::from_int(n[l]);
223 for (std::size_t i = 0; i < M; ++i) {
224 const T d =
num_abs(T(m(i, l) - mprev(i, l))) / nT;
225 if (d > dev) dev = d;
228 std::vector<T> varnow(M, zero);
230 for (std::size_t i = 0; i < M; ++i) {
232 for (std::size_t l = 0; l < R; ++l) acc += dm[i](i, l);
238 for (std::size_t i = 0; i < M; ++i) {
239 const T d =
num_abs(T(varnow[i] - varprev[i])) / sv;
240 if (d > vdev) vdev = d;
243 if (dev <= tolm && vdev <= tolv)
break;
265 const std::vector<T>& Z,
const T* tol,
268 "pfqn_sens_linearizer requires transcendental arithmetic: it is a fixed point "
269 "stopped on a tolerance, so its result is a property of the stopping test rather "
270 "than of the model, and exact arithmetic buys nothing");
272 const std::size_t M = L.
rows();
273 const std::size_t R = N.size();
275 throw InputError(
"pfqn_sens_linearizer: demand matrix and population vector disagree on the class count");
276 if (!Z.empty() && Z.size() != R)
277 throw InputError(
"pfqn_sens_linearizer: think-time vector has the wrong length");
282 res.
XN.assign(R, zero);
286 res.
m.assign(M, zero);
288 res.
d2m.assign(M, zero);
290 res.
Var.assign(M, zero);
291 res.
M2.assign(M, zero);
292 res.
M3.assign(M, zero);
293 res.
Skew.assign(M, 0.0);
297 bool anyPositive =
false;
299 if (v < 0)
throw InputError(
"pfqn_sens_linearizer: negative population");
300 if (v > 0) anyPositive =
true;
302 if (!anyPositive || M == 0 || R == 0)
return res;
305 const std::size_t npops = 1 + R;
306 std::vector<std::vector<int>> pv(npops, N);
307 for (std::size_t l = 0; l < R; ++l)
308 if (N[l] > 0) pv[1 + l][l] = N[l] - 1;
310 std::vector<Matrix<T>> mE(npops,
Matrix<T>(M, R, zero));
311 std::vector<std::vector<Matrix<T>>> dmE(npops, std::vector<
Matrix<T>>(M,
Matrix<T>(M, R, zero)));
312 std::vector<std::vector<Matrix<T>>> d2mE(npops, std::vector<
Matrix<T>>(M,
Matrix<T>(M, R, zero)));
313 for (std::size_t p = 0; p < npops; ++p)
314 for (std::size_t l = 0; l < R; ++l)
315 for (std::size_t i = 0; i < M; ++i)
318 std::vector<Matrix<T>> delta(M,
Matrix<T>(R, R, zero));
319 std::vector<std::vector<Matrix<T>>> ddelta(M, std::vector<
Matrix<T>>(M,
Matrix<T>(R, R, zero)));
320 std::vector<std::vector<Matrix<T>>> d2delta(M, std::vector<
Matrix<T>>(M,
Matrix<T>(R, R, zero)));
324 for (
int outer = 0; outer < 3; ++outer) {
325 res.
iter += detail::sens_lin_core2(L, Z, N, delta, ddelta, d2delta, mE[0], dmE[0], d2mE[0],
326 lam, wmat, tol, maxiter);
327 if (outer == 2)
break;
329 for (std::size_t l = 0; l < R; ++l) {
330 if (N[l] == 0)
continue;
333 res.
iter += detail::sens_lin_core2(L, Z, pv[1 + l], delta, ddelta, d2delta, mE[1 + l],
334 dmE[1 + l], d2mE[1 + l], lam2, w2, tol, maxiter);
339 std::vector<Matrix<T>> dvN, d2vN;
340 detail::sens_lin_fractions(mE[0], dmE[0], d2mE[0], N, vN, dvN, d2vN);
341 for (std::size_t
lp = 0;
lp < R; ++
lp) {
342 if (N[
lp] == 0)
continue;
344 std::vector<Matrix<T>> dvL, d2vL;
345 detail::sens_lin_fractions(mE[1 +
lp], dmE[1 +
lp], d2mE[1 +
lp], pv[1 +
lp], vL, dvL,
347 for (std::size_t i = 0; i < M; ++i)
348 for (std::size_t l = 0; l < R; ++l) {
349 delta[i](
lp, l) = vL(i, l) - vN(i, l);
350 for (std::size_t h = 0; h < M; ++h) {
351 ddelta[i][h](
lp, l) = dvL[h](i, l) - dvN[h](i, l);
352 d2delta[i][h](
lp, l) = d2vL[h](i, l) - d2vN[h](i, l);
361 for (std::size_t i = 0; i < M; ++i) {
363 for (std::size_t l = 0; l < R; ++l) acc += res.
QN(i, l);
365 for (std::size_t h = 0; h < M; ++h) {
367 for (std::size_t l = 0; l < R; ++l) d += dmE[0][h](i, l);
371 for (std::size_t l = 0; l < R; ++l) d2 += d2mE[0][i](i, l);
373 for (std::size_t r = 0; r < R; ++r) res.
UN(i, r) = res.
XN[r] * L(i, r);
376 for (std::size_t i = 0; i < M; ++i)
377 for (std::size_t j = 0; j < M; ++j) {
378 const T d =
num_abs(T(res.
dm(i, j) - res.
dm(j, i)));
381 for (std::size_t i = 0; i < M; ++i)
382 for (std::size_t j = 0; j < M; ++j)
385 for (std::size_t i = 0; i < M; ++i) {
386 const T d1 = res.
dm(i, i);
387 const T mi = res.
m[i];
389 res.
M2[i] = d1 + mi * mi;
390 res.
M3[i] = res.
d2m[i] +
403 const std::vector<T>& Z) {
The exception types the port throws.
Dense matrix and non-owning view.
SensLinearizerResult< T > pfqn_sens_linearizer(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const T *tol, unsigned maxiter)
Approximate moments E[Q_i], Var[Q_i], Cov[Q_i,Q_j], E[Q_i^2] and E[Q_i^3] of the per-station total qu...
Number-type abstraction for the templated API port.
unsigned iter
total CORE iterations performed
Matrix< T > dm
(M x M) dm(i,h) = x_h dm_i/dx_h
std::vector< T > M3
(M) E[Q^3]
Matrix< T > UN
(M x R) utilization
std::vector< T > m
(M) E[Q_i], the total queue at station i
std::vector< T > XN
(R) throughput
std::vector< T > M2
(M) E[Q^2]
std::vector< T > d2m
(M) x_i^2 d2m_i/dx_i^2
Matrix< T > Cov
(M x M) symmetrized dm
T CovAsym
raw asymmetry of Cov, an error indicator here
Matrix< T > QN
(M x R) queue length per class
std::vector< double > Skew
(M) skewness, NaN where the variance vanishes
Matrix< T > WN
(M x R) residence time