104 "pfqn_rd requires transcendental arithmetic: it is a heuristic reduction whose "
105 "correction series is truncated and reweighted, it locates the terminal rate by "
106 "a tolerance comparison, and it reports a logarithm");
108 const std::size_t M = L0.
rows();
109 const std::size_t R = N.size();
111 throw InputError(
"pfqn_rd: L and N disagree on the class count");
117 const auto is_nan = [](
const T& v) {
return !(v == v); };
118 const auto is_finite = [&](
const T& v) {
return !is_nan(v) && v < inf && v > T(-inf); };
121 for (
int n : N) Ntot += n;
126 res.
lGN = -std::numeric_limits<double>::infinity();
133 for (std::size_t i = 0; i < M; ++i) {
134 bool constant =
true;
135 for (std::size_t k = 1; k < mu.
cols(); ++k)
136 if (mu(i, k) != mu(i, 0)) constant =
false;
137 if (!constant)
continue;
138 for (std::size_t r = 0; r < R; ++r) L(i, r) = L(i, r) / mu(i, 0);
139 for (std::size_t k = 0; k < mu.
cols(); ++k) mu(i, k) = one;
145 const std::size_t Nt =
static_cast<std::size_t
>(Ntot);
146 if (mu.
rows() != M)
throw InputError(
"pfqn_rd: mu has the wrong station count");
147 if (mu.
cols() < Nt)
throw InputError(
"pfqn_rd: mu has fewer rate columns than the population");
151 for (std::size_t i = 0; i < M; ++i)
152 for (std::size_t k = 0; k < Nt; ++k) muT(i, k) = is_nan(mu(i, k)) ? inf : mu(i, k);
155 std::vector<std::size_t> s(M, Nt);
156 for (std::size_t i = 0; i < M; ++i) {
157 if (!is_finite(muT(i, Nt - 1))) {
161 std::size_t found = Nt;
162 for (std::size_t k = 0; k < Nt; ++k)
163 if (
num_abs(T(muT(i, k) - muT(i, Nt - 1))) < tolT) {
172 for (std::size_t i = 0; i < M; ++i) {
173 if (!is_finite(muT(i, s[i] - 1))) {
174 std::size_t lastfinite = 0;
175 for (std::size_t k = 0; k < Nt; ++k)
176 if (is_finite(muT(i, k))) lastfinite = k + 1;
178 throw NumericError(
"pfqn_rd: a station has no finite load-dependent rate");
181 for (std::size_t r = 0; r < R; ++r) y(i, r) = y(i, r) / muT(i, s[i] - 1);
186 for (std::size_t i = 0; i < M; ++i)
187 for (std::size_t k = 0; k < Nt; ++k) gamma(i, k) = muT(i, k) / muT(i, s[i] - 1);
190 for (std::size_t i = 0; i < M; ++i) {
191 beta(i, 0) = gamma(i, 0) / (one - gamma(i, 0));
192 for (std::size_t j = 1; j < Nt; ++j)
193 beta(i, j) = (one - gamma(i, j - 1)) * (gamma(i, j) / (one - gamma(i, j)));
196 for (std::size_t i = 0; i < M; ++i)
197 for (std::size_t j = 0; j < Nt; ++j) {
198 if (is_nan(beta(i, j))) beta(i, j) = inf;
199 if (beta(i, j) != inf) allInf =
false;
202 const std::vector<T> lambda;
205 res.
lGN =
pfqn_nc(lambda, L, N, Z, method, zero).lG;
211 for (std::size_t i = 0; i < M; ++i)
212 if (s[i] > 1) vmax_l +=
static_cast<long>(s[i]) - 1;
213 if (vmax_l > Ntot) vmax_l = Ntot;
214 const std::size_t vmax =
static_cast<std::size_t
>(vmax_l < 0 ? 0 : vmax_l);
218 for (std::size_t i = 0; i < M; ++i) {
220 for (std::size_t r = 0; r < R; ++r) acc += y(i, r) * Y.
XN[r];
226 std::vector<double> lEN(vmax + 1, 0.0);
227 for (std::size_t v = 1; v <= vmax; ++v) {
234 for (std::size_t v = 0; v <= vmax; ++v) {
236 const long shift = v >= 1 ?
static_cast<long>(v) - 1 : 0;
RdResult< T > pfqn_rd(const Matrix< T > &L0, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu0, double tol, NcMethod method)
Reduction heuristic (RD) for the normalizing constant of a closed LOAD-DEPENDENT product-form network...
NcDispatchResult< T > pfqn_nc(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, NcMethod method, const T &atol, const NcOptions &nopt)
Normalizing constant of a product-form queueing network: the dispatcher.