105 "pfqn_dnc needs logarithms and is not available in exact arithmetic");
112 for (std::size_t i = 0; i < L.size(); ++i)
113 if (L[i] > zero) Lp.push_back(L[i]);
115 throw InputError(
"pfqn_dnc requires at least one station with positive demand");
116 if (N < zero)
throw InputError(
"pfqn_dnc requires a nonnegative population");
118 const std::size_t M = Lp.size();
120 for (std::size_t i = 1; i < M; ++i)
121 if (Lp[i] > xmax) xmax = Lp[i];
123 for (std::size_t i = 0; i < M; ++i) y[i] = T(Lp[i] / xmax);
128 std::vector<T> ys = y;
129 std::sort(ys.begin(), ys.end(), [](
const T& a,
const T& b) { return b < a; });
132 std::vector<long> mult;
135 for (std::size_t i = 1; i < M; ++i) {
136 if (ys[i] > T(u.back() * near)) {
143 const std::size_t Gd = u.size();
146 std::vector<std::size_t> node;
148 bool all_simple =
true;
149 for (std::size_t g = 0; g < Gd; ++g)
150 if (mult[g] != 1) all_simple =
false;
156 for (std::size_t g = 0; g < Gd; ++g) {
159 for (std::size_t l = 0; l < Gd; ++l) {
160 if (l == g)
continue;
161 const T den = T(u[g] - u[l]);
162 if (den == zero)
throw NumericError(
"pfqn_dnc: coincident loads in the simple branch");
163 prod *= T(u[g] / den);
170 std::vector<T> gint(M, zero);
173 for (std::size_t i = 0; i < M; ++i) {
174 std::vector<T> gi(M);
176 for (std::size_t k = 1; k < M; ++k) gi[k] = T(gi[k - 1] * y[i]);
177 std::vector<T> out(M, zero);
178 const std::size_t newlen = std::min(M, len + M - 1);
179 for (std::size_t a = 0; a < len; ++a)
180 for (std::size_t b = 0; b + a < M; ++b) out[a + b] += gint[a] * gi[b];
187 for (std::size_t g = 0; g < Gd; ++g)
188 for (
long jj = 1; jj <= mult[g]; ++jj) {
194 for (std::size_t n = 0; n < M; ++n) {
196 for (std::size_t k = 0; k < M; ++k) {
198 F(n, k) = exp(T(detail::num_lgamma<T>(T(nT + jT)) - detail::num_lgamma<T>(jT) -
199 detail::num_lgamma<T>(T(nT + one)) + nT * log(u[node[k]])));
206 const T GN = detail::dnc_eval<T>(N, A, u, node, j);
207 const T GN1 = detail::dnc_eval<T>(T(N - one), A, u, node, j);
208 res.
lG = T(log(GN) + N * log(xmax));
210 const bool gn1_nan = !(GN1 == GN1);
211 if (N <= zero || GN <= zero || gn1_nan) {
212 res.
X = std::numeric_limits<T>::quiet_NaN();
214 res.
X = T(T(GN1 / GN) / xmax);
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.