197 const std::vector<T>& S,
const std::vector<T>& w) {
199 "npfqn_dps_morrison requires transcendental arithmetic");
200 const std::size_t p = N.size();
201 if (Z.size() != p || S.size() != p || w.size() != p) {
202 throw InputError(
"npfqn_dps_morrison: N, Z, S and w must have the same number of classes.");
209 for (std::size_t i = 0; i < p; ++i) {
210 if (!detail::num_isfinite(N[i]) || !(N[i] > zero)) {
211 throw InputError(
"npfqn_dps_morrison: the approximation requires finite positive class "
214 if (!detail::num_isfinite(Z[i]) || !(Z[i] > zero) || !detail::num_isfinite(S[i]) ||
216 throw InputError(
"npfqn_dps_morrison: think times Z and DPS service times S must be "
217 "finite and positive.");
219 if (!detail::num_isfinite(w[i]) || !(w[i] > zero)) {
220 throw InputError(
"npfqn_dps_morrison: DPS weights must be finite and positive.");
225 std::vector<T> b(N), r(p, zero), g(p, zero);
227 for (std::size_t i = 0; i < p; ++i) {
232 const T a = one - rho;
235 T cB = zero, cC = zero, cD = zero, cH = zero, cI = zero, cJ = zero;
236 T cK = zero, cL = zero, cM = zero, cQ = zero;
237 for (std::size_t i = 0; i < p; ++i) {
238 const T g2 = g[i] * g[i], g3 = g2 * g[i], w2 = w[i] * w[i], r2 = r[i] * r[i];
239 cB += b[i] / (r[i] * g2 * w[i]);
240 cC += b[i] / (g2 * w[i]);
241 cD += b[i] / (r[i] * g2);
242 cH += b[i] / (r2 * g3 * w[i]);
243 cI += b[i] / (r2 * g3 * w2);
244 cJ += b[i] / (r[i] * g3 * w2);
245 cK += b[i] / (g3 * w2);
246 cL += b[i] / (r[i] * g3 * w[i]);
247 cM += b[i] / (r2 * g3);
254 std::vector<std::vector<T> > A(p, std::vector<T>(p, zero));
255 std::vector<T> rhs(p, zero);
256 for (std::size_t i = 0; i < p; ++i) {
258 for (std::size_t j = 0; j < p; ++j) {
259 const T den = r[i] * g[i] * w[i] + r[j] * g[j] * w[j];
260 A[i][i] -= w[j] * b[j] * r[j] / den;
261 A[i][j] -= w[j] * b[i] * r[i] / den;
263 rhs[i] = rho * (b[i] / g[i]) * (cD / (cB * w[i]) - one);
265 for (std::size_t j = 0; j < p; ++j) A[p - 1][j] = one / (r[j] * g[j]);
267 const std::vector<T> sigma = detail::dps_solve_square(A, rhs);
271 for (std::size_t i = 0; i < p; ++i) {
272 const T alpha_i = sigma[i] - (b[i] / g[i]) * (cD / (cB * w[i]) - one);
273 delta += alpha_i / g[i];
277 const T cR = three * (cB * cL - cD * cJ) / (cB * cD);
278 const T cS = (two * cB * (cD * cH - cB * cM) - cD * (cD * cI - cB * cH)) / (two * cB * cB * cD * cD);
279 const T cU = (cQ - cC * cD / cB - delta) / rho - cD * cR / cB + (a * a - cC * cD / cB) * cS;
280 const T cA = cS * cC * cC + cR * cC - cK;
281 const T cV = cR + two * cS * cC;
283 const std::vector<T> W = detail::dps_W(cB, cC, cD, a);
288 const T eps = cB / cD;
289 const T num = W[1] - eps * (cA / three * W[4] + a / two * cV * W[3] + cU * W[2]);
290 const T den = W[0] - eps * (cA / three * W[3] + a / two * cV * W[2] + cU * W[1] + cS);
291 if (!detail::num_isfinite(den) || den == zero) {
292 throw InputError(
"npfqn_dps_morrison: the expansion is degenerate for this model (vanishing "
293 "denominator); the usage is too far from the moderately-heavy regime.");
297 res.
Q.resize(p); res.
R.resize(p); res.
X.resize(p);
299 for (std::size_t j = 0; j < p; ++j) {
300 const T gw = g[j] * w[j];
301 res.
Qlead[j] = b[j] * W[1] / (gw * W[0]);
302 res.
Q[j] = b[j] * num / (gw * den) - b[j] * W[2] / (g[j] * g[j] * w[j] * w[j] * W[0]) -
304 res.
Rlead[j] = W[1] / (r[j] * gw * W[0]);
305 res.
R[j] = num / (r[j] * gw * den) +
306 ((W[1] / W[0]) * (W[1] / W[0]) - W[2] / W[0]) /
307 (r[j] * g[j] * g[j] * w[j] * w[j]) -
308 sigma[j] / (rho * r[j] * b[j]);
309 res.
X[j] = r[j] * (b[j] - res.
Q[j]);
311 res.
rho = rho; res.
a = a;
312 res.
cB = cB; res.
cC = cC; res.
cD = cD; res.
cH = cH; res.
cI = cI; res.
cJ = cJ;
313 res.
cK = cK; res.
cL = cL; res.
cM = cM; res.
cQ = cQ; res.
delta = delta;
314 res.
cR = cR; res.
cS = cS; res.
cU = cU; res.
cA = cA; res.
cV = cV;