69 const std::size_t M = mu.
rows();
70 const std::size_t Nt = mu.
cols();
71 if (M == 0 || Nt == 0)
throw InputError(
"pfqn_sens_ldmx_ec: the rate lattice is empty");
73 throw InputError(
"pfqn_sens_ldmx_ec: D and mu disagree on the station count");
74 if (lambda.size() != D.
cols())
75 throw InputError(
"pfqn_sens_ldmx_ec: lambda and D disagree on the class count");
81 res.
Lo.assign(M, zero);
82 for (std::size_t i = 0; i < M; ++i)
83 for (std::size_t r = 0; r < lambda.size(); ++r) res.
Lo[i] += lambda[r] * D(i, r);
85 std::vector<std::size_t> b(M, 1);
86 for (std::size_t i = 0; i < M; ++i) {
87 const T& last = mu(i, Nt - 1);
89 while (k < Nt && mu(i, k - 1) != last) ++k;
94 const std::size_t Cw = 2 * Nt + 2;
96 for (std::size_t i = 0; i < M; ++i)
97 for (std::size_t k = 0; k < Cw; ++k) {
98 const T& rate = k < Nt ? mu(i, k) : mu(i, Nt - 1);
99 if (rate == zero)
throw NumericError(
"pfqn_sens_ldmx_ec: a load-dependent rate is zero");
100 C(i, k) = one / rate;
103 const auto Cq = [&](std::size_t i, std::size_t k) ->
const T& {
return C(i, k - 1); };
112 for (std::size_t i = 0; i < M; ++i) {
113 const std::size_t bi = b[i];
114 const T Cb = Cq(i, bi);
115 const T den = one - res.
Lo[i] * Cb;
118 "pfqn_sens_ldmx_ec: the station is saturated by the open classes (Lo * C(b) = 1)");
119 const std::size_t nhead = bi >= 2 ? bi - 1 : 0;
121 std::vector<T> E1(Nt + 1, zero), dE1(Nt + 1, zero);
122 std::vector<T> E2(Nt + 1, zero), dE2(Nt + 1, zero);
123 std::vector<T> E3(Nt + 1, zero), dE3(Nt + 1, zero);
124 std::vector<T> E2p(Nt + 1, zero), dE2p(Nt + 1, zero);
125 Matrix<T> F2(Nt + 1, nhead + 1, zero), dF2(Nt + 1, nhead + 1, zero);
126 Matrix<T> F3(Nt + 1, nhead + 1, zero), dF3(Nt + 1, nhead + 1, zero);
127 Matrix<T> F2p(Nt + 1, nhead + 1, zero), dF2p(Nt + 1, nhead + 1, zero);
129 for (std::size_t n = 0; n <= Nt; ++n) {
132 res.
E(i, n) = one /
num_pow_int(den,
static_cast<unsigned>(n + 1));
135 res.
Eprime(i, n) = Cb * res.
E(i, n);
142 dE1[0] = Cb / (den * den);
143 for (std::size_t j = 1; j + 1 <= bi; ++j) {
144 E1[0] *= Cq(i, j) / Cb;
145 dE1[0] *= Cq(i, j) / Cb;
148 const T fac = Cb / Cq(i, n);
149 E1[n] = one / den * fac * E1[n - 1];
150 dE1[n] = Cb / (den * den) * fac * E1[n - 1] + one / den * fac * dE1[n - 1];
154 for (std::size_t n0 = 0; n0 <= nhead; ++n0) {
161 F2(n, n0) = coef * res.
Lo[i] * F2(n, n0 - 1);
162 dF2(n, n0) = coef * (F2(n, n0 - 1) + res.
Lo[i] * dF2(n, n0 - 1));
167 for (std::size_t n0 = 0; n0 < nhead; ++n0) {
169 dE2[n] += dF2(n, n0);
173 for (std::size_t n0 = 0; n0 <= nhead; ++n0) {
174 if (n == 0 && n0 == 0) {
176 for (std::size_t j = 1; j + 1 <= bi; ++j) F3(0, 0) *= Cq(i, j) / Cb;
178 }
else if (n > 0 && n0 == 0) {
179 const T fac = Cb / Cq(i, n);
180 F3(n, 0) = fac * F3(n - 1, 0);
181 dF3(n, 0) = fac * dF3(n - 1, 0);
185 F3(n, n0) = coef * res.
Lo[i] * F3(n, n0 - 1);
186 dF3(n, n0) = coef * (F3(n, n0 - 1) + res.
Lo[i] * dF3(n, n0 - 1));
191 for (std::size_t n0 = 0; n0 < nhead; ++n0) {
193 dE3[n] += dF3(n, n0);
197 for (std::size_t n0 = 0; n0 <= nhead; ++n0) {
199 F2p(n, 0) = Cq(i, n + 1);
205 F2p(n, n0) = coef * res.
Lo[i] * F2p(n, n0 - 1);
206 dF2p(n, n0) = coef * (F2p(n, n0 - 1) + res.
Lo[i] * dF2p(n, n0 - 1));
211 for (std::size_t n0 = 0; n0 < nhead; ++n0) {
212 E2p[n] += F2p(n, n0);
213 dE2p[n] += dF2p(n, n0);
217 res.
E(i, n) = E1[n] + E2[n] - E3[n];
218 res.
dE(i, n) = dE1[n] + dE2[n] - dE3[n];
220 res.
Eprime(i, n) = Cb * E1[n] + E2p[n] - Cb * E3[n];
221 res.
dEprime(i, n) = Cb * dE1[n] + dE2p[n] - Cb * dE3[n];
223 res.
Eprime(i, n) = Cb * res.
E(i, n);
229 for (std::size_t n = 1; n <= Nt; ++n) {
230 if (res.
E(i, n - 1) == zero)
throw NumericError(
"pfqn_sens_ldmx_ec: E vanishes");
231 res.
EC(i, n - 1) = Cq(i, n) * res.
E(i, n) / res.
E(i, n - 1);
232 res.
dEC(i, n - 1) = Cq(i, n) *
233 (res.
dE(i, n) * res.
E(i, n - 1) - res.
E(i, n) * res.
dE(i, n - 1)) /
234 (res.
E(i, n - 1) * res.
E(i, n - 1));