65 if (
sn.nstations != 2)
return false;
66 bool anyPositive =
false;
71 if (!anyPositive)
return false;
73 std::size_t iInf =
sn.nstations, iDps =
sn.nstations;
74 for (std::size_t i = 0; i <
sn.nstations; ++i) {
76 if (s == SchedStrategy::INF) {
77 if (iInf !=
sn.nstations)
return false;
79 }
else if (s == SchedStrategy::DPS) {
80 if (iDps !=
sn.nstations)
return false;
86 if (iInf ==
sn.nstations || iDps ==
sn.nstations)
return false;
87 const double c =
sn.stations[iDps].nservers;
88 if (std::isfinite(c) && c != 1.0)
return false;
89 if (
sn.nchains !=
sn.nclasses)
return false;
90 for (std::size_t ch = 0; ch <
sn.nchains; ++ch)
91 if (
sn.inchain[ch].size() > 1)
return false;
93 for (std::size_t r = 0; r <
sn.nclasses; ++r) {
94 if (!(
sn.classes[r].population > 0))
return false;
95 const std::size_t sts[2] = {iInf, iDps};
96 for (std::size_t k = 0; k < 2; ++k) {
98 if (!std::isfinite(rate) || rate <= 0)
return false;
100 if (std::isfinite(scv) && std::fabs(scv - 1.0) > 1e-6)
return false;
102 if (
sn.stations[iDps].schedparam.size() !=
sn.nclasses)
return false;
104 if (!std::isfinite(wgt) || wgt <= 0)
return false;
108 for (std::size_t r = 0; r <
sn.nclasses; ++r) {
111 if (std::fabs(vi - vd) > 1e-9 * std::max(1.0, vi))
return false;
130 "solver_nc_dps_analyzer: Morrison's W_m are erfc integrals; this backend has no "
131 "transcendental arithmetic");
140 "solver_nc_dps_analyzer: applies only to a CLOSED network of exactly two stations, "
141 "one infinite-server (think) station and one single-server DPS station with "
142 "exponential service and one visit each per cycle (see nc_is_dps_model).");
144 const std::size_t M =
sn.nstations, K =
sn.nclasses;
145 std::size_t iInf = M, iDps = M;
146 for (std::size_t i = 0; i < M; ++i) {
147 if (
sn.stations[i].sched == SchedStrategy::INF) iInf = i;
148 if (
sn.stations[i].sched == SchedStrategy::DPS) iDps = i;
150 if (iInf == M || iDps == M)
151 throw InputError(
"solver_nc_dps_analyzer: requires one INF and one DPS station");
153 std::vector<T> Npop(K, zero), Z(K, zero), S(K, zero), w(K, zero);
154 for (std::size_t r = 0; r < K; ++r) {
158 w[r] =
sn.stations[iDps].schedparam[r];
164 Matrix<T> Q(M, K, zero), U(M, K, zero), R(M, K, zero), Tp(M, K, zero);
165 std::vector<T> X(K, zero), C(K, zero);
167 const double cd =
sn.stations[iDps].nservers;
170 for (std::size_t r = 0; r < K; ++r) {
172 if (!(q >= zero)) q = zero;
173 if (q > Npop[r]) q = Npop[r];
174 const T x = T((Npop[r] - q) / Z[r]);
176 Q(iInf, r) = T(Npop[r] - q);
178 for (std::size_t i = 0; i < M; ++i) Tp(i, r) = T(x * V(i, r));
179 U(iInf, r) = Q(iInf, r);
180 U(iDps, r) = T(x * V(iDps, r) * S[r] / c);
181 if (x > zero) C[r] = T(Npop[r] / x);
183 for (std::size_t i = 0; i < M; ++i)
184 for (std::size_t r = 0; r < K; ++r)
185 if (Tp(i, r) > zero) R(i, r) = T(Q(i, r) / Tp(i, r));
194 out.
sol.lG = std::numeric_limits<double>::quiet_NaN();
195 out.
sol.method =
"morrison";
DpsMorrisonResult< T > npfqn_dps_morrison(const std::vector< T > &N, const std::vector< T > &Z, const std::vector< T > &S, const std::vector< T > &w)
Evaluates Morrison's two-term approximation.
The [Q,U,R,T,C,X,lG] of the reference, plus the algorithm that ran.