78 const std::size_t M = L.
empty() ? 0 : L.
rows();
79 const std::size_t R = N.size();
81 throw InputError(
"pfqn_conv: L and N disagree on the class count");
82 if (!cdscaling.empty() && cdscaling.size() != M)
83 throw InputError(
"pfqn_conv: the scaling vector has the wrong station count");
85 if (v < 0)
throw InputError(
"pfqn_conv: the convolution algorithm requires finite, "
86 "nonnegative (closed) populations");
91 std::vector<T> Zsum(R, zero);
93 if (Z.
cols() != R)
throw InputError(
"pfqn_conv: Z and N disagree on the class count");
94 for (std::size_t k = 0; k < Z.
rows(); ++k)
95 for (std::size_t r = 0; r < R; ++r) Zsum[r] += Z(k, r);
98 const std::vector<std::size_t> prods =
plane_sizes(N);
102 std::vector<T> G(total, zero);
104 std::vector<int> n(R, 0);
107 G[
pop_index(n, prods)] = detail::pff_delay(Zsum, n);
113 for (std::size_t ist = 0; ist < M; ++ist) {
114 const bool isCd = !cdscaling.empty() &&
static_cast<bool>(cdscaling[ist]);
118 std::vector<int> n(R, 0);
121 const std::size_t idx =
pop_index(n, prods);
123 for (std::size_t r = 0; r < R; ++r)
124 if (n[r] >= 1) acc += L(ist, r) * G[idx - prods[r]];
132 std::vector<T> Xm(total, zero);
135 std::vector<int> n(R, 0);
138 const std::size_t idx =
pop_index(n, prods);
140 while (r < R && n[r] == 0) ++r;
142 std::vector<T> row(R);
143 for (std::size_t s = 0; s < R; ++s)
145 const std::vector<T> bval = cdscaling[ist](row);
147 throw InputError(
"pfqn_conv: a class-dependence callable returned nothing");
148 const T beta = bval.size() > 1 ? bval.at(r) : bval[0];
151 for (
int v : n) tot += v;
153 Xm[idx] = fac * (L(ist, r) / beta) * Xm[idx - prods[r]];
161 std::vector<T> Gold(G);
162 std::vector<int> n(R, 0);
165 const std::size_t idxn =
pop_index(n, prods);
168 std::vector<int> i(R, 0);
171 std::size_t idx_i = 0, idx_nmi = 0;
172 for (std::size_t r = 0; r < R; ++r) {
173 idx_i += prods[r] *
static_cast<std::size_t
>(i[r]);
174 idx_nmi += prods[r] *
static_cast<std::size_t
>(n[r] - i[r]);
176 acc += Xm[idx_i] * Gold[idx_nmi];
184 const T Gn = G[total - 1];
NcResult< T > pfqn_conv(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< CdScaling< T > > &cdscaling)
Multichain convolution algorithm with class-dependent service rates (Sauer 1983, "Computational Algor...
bool next_pop(std::vector< int > &n, const std::vector< int > &N)
Advance n to the next population vector in the lattice 0 <= n <= N, odometer order with the last clas...
std::size_t pop_index(const std::vector< int > &n, const std::vector< std::size_t > &prods)
Index of n in the lattice, 0-based (MATLAB hashpop is 1-based).