108 "solver_mam_ldqbd_transient: the transient law is a matrix exponential (finite "
109 "buffer) or a tolerance-truncated Taylor series with an incomplete-gamma error bound "
110 "(infinite buffer); rerun with --arith double or --arith real");
117 "solver_mam_ldqbd_transient: the transient QBD method requires a single-class model");
118 if (!std::isinf(L.
classes[0].population))
120 "solver_mam_ldqbd_transient: the transient QBD method requires an open model");
122 std::size_t src = 0, q = 0, nsrc = 0, nq = 0;
123 for (std::size_t i = 1; i <= M; ++i) {
124 if (L.
stations[i - 1].sched == SchedStrategy::EXT) { src = i; ++nsrc; }
125 else if (L.
stations[i - 1].sched == SchedStrategy::FCFS) { q = i; ++nq; }
127 if (nsrc != 1 || nq != 1)
129 "solver_mam_ldqbd_transient: the transient QBD method requires exactly one Source and "
132 const T lambda = L.
rates(src - 1, 0);
134 const double nServers = L.
stations[q - 1].nservers;
135 const double bufCap = L.
cap[q - 1];
136 const std::size_t nPhases = PHq.
D0.rows();
137 const bool isPH = nPhases > 1;
139 std::vector<T> alphaV;
142 mu = T(-PHq.
D0(0, 0));
146 for (std::size_t i = 0; i < nPhases; ++i) {
148 for (std::size_t j = 0; j < nPhases; ++j) s += PHq.
D0(i, j);
152 if (isPH && nServers > 1.0)
154 "solver_mam_ldqbd_transient: transient QBD with PH service supports single-server "
155 "queues only; the level phase would have to carry the multiset of in-service phases");
157 const double T_start =
opt.timespan_start;
158 const double T_end =
opt.timespan_end;
159 if (!(T_end > T_start) || !std::isfinite(T_end))
161 "solver_mam_ldqbd_transient: the timespan must be a finite interval with a positive "
163 const double T_duration = T_end - T_start;
164 const unsigned c =
static_cast<unsigned>(
165 std::isfinite(nServers) ? std::llround(nServers) : 1);
167 std::vector<double> times;
168 std::vector<T> qlen,
util, tput;
170 if (std::isfinite(bufCap)) {
172 const std::size_t Cap =
static_cast<std::size_t
>(std::llround(bufCap));
178 for (std::size_t n = 0; n <= Cap; ++n) {
180 std::min(
static_cast<double>(n),
static_cast<double>(c))) * mu;
181 const T arr = (n < Cap) ? lambda : zero;
182 if (n > 0) Q(n, n - 1) = dep;
183 if (n < Cap) Q(n, n + 1) = arr;
184 Q(n, n) = T(-(dep + arr));
187 dim = 1 + Cap * nPhases;
190 for (std::size_t j = 0; j < nPhases; ++j) Q(0, 1 + j) = T(lambda * alphaV[j]);
191 for (std::size_t n = 1; n <= Cap; ++n) {
192 const std::size_t r0 = 1 + (n - 1) * nPhases;
193 for (std::size_t i = 0; i < nPhases; ++i)
194 for (std::size_t j = 0; j < nPhases; ++j) {
195 Q(r0 + i, r0 + j) = PHq.
D0(i, j);
196 if (i == j && n < Cap) Q(r0 + i, r0 + j) -= lambda;
199 for (std::size_t i = 0; i < nPhases; ++i)
200 Q(r0 + i, r0 + nPhases + i) = lambda;
202 for (std::size_t i = 0; i < nPhases; ++i) Q(r0 + i, 0) = texit(i, 0);
204 const std::size_t p0 = r0 - nPhases;
205 for (std::size_t i = 0; i < nPhases; ++i)
206 for (std::size_t j = 0; j < nPhases; ++j) Q(r0 + i, p0 + j) = PHq.
D1(i, j);
210 const std::size_t nT =
static_cast<std::size_t
>(std::min<double>(
211 101.0, std::max<double>(11.0, std::round(T_duration * 10.0))));
212 const double dt = T_duration /
static_cast<double>(nT - 1);
215 std::vector<T> pi(dim, zero);
217 for (std::size_t t = 0; t < nT; ++t) {
218 times.push_back(T_start +
static_cast<double>(t) * dt);
219 T qv = zero, uv = zero, tv = zero;
220 for (std::size_t n = 0; n <= Cap; ++n) {
227 for (std::size_t i = 0; i < nPhases; ++i) pn += pi[1 + (n - 1) * nPhases + i];
232 std::min(
static_cast<double>(n),
static_cast<double>(c)) /
233 static_cast<double>(c)) * pn;
236 std::min(
static_cast<double>(n),
static_cast<double>(c))) * mu *
239 for (std::size_t i = 0; i < nPhases; ++i)
240 tv += pi[1 + (n - 1) * nPhases + i] * texit(i, 0);
247 if (t + 1 < nT) pi =
vecmul(pi, eQdt);
254 for (
unsigned n = 1; n + 1 <= c; ++n) {
263 for (std::size_t j = 0; j < nPhases; ++j) up0(0, j) = T(lambda * alphaV[j]);
265 Matrix<T> A10(nPhases, nPhases, zero), A1p(nPhases, nPhases, zero);
266 for (std::size_t i = 0; i < nPhases; ++i) {
267 for (std::size_t j = 0; j < nPhases; ++j) A10(i, j) = PHq.
D0(i, j);
274 std::vector<std::vector<T>> pi0(1, std::vector<T>(1, one));
277 for (std::size_t t = 0; t < ts.
times.size(); ++t) {
278 times.push_back(ts.
times[t] + T_start);
279 const std::vector<std::vector<T>>& d = ts.
dists[t];
280 T qv = zero, uv = zero, tv = zero;
281 for (std::size_t n = 1; n < d.size(); ++n) {
283 for (
const T& v : d[n]) pn += v;
286 std::min(
static_cast<double>(n),
static_cast<double>(c)) /
287 static_cast<double>(c)) * pn;
290 std::min(
static_cast<double>(n),
static_cast<double>(c))) * mu * pn;
292 for (std::size_t i = 0; i < d[n].size() && i < nPhases; ++i)
293 tv += d[n][i] * texit(i, 0);