184 "pfqn_clwoi requires transcendental arithmetic (contour integration of a "
185 "generating function)");
188 const std::size_t R = N.size();
189 const std::size_t M = mu.size();
190 if (!Z.empty() && Z.size() != R)
191 throw InputError(
"pfqn_clwoi: Z and N disagree on the chain count");
192 if (!visits.
empty() && (visits.
rows() != M || visits.
cols() != R))
193 throw InputError(
"pfqn_clwoi: visits must be M x R");
198 for (std::size_t r = 0; r < R; ++r) {
201 res.
lG = T(-std::numeric_limits<T>::infinity());
212 std::vector<int> lfull;
213 std::vector<double> gfull;
214 detail::clw_defaults(R,
opt, lfull, gfull);
218 std::vector<std::size_t> keep;
219 for (std::size_t r = 0; r < R; ++r)
220 if (N[r] > 0) keep.push_back(r);
221 const std::size_t p = keep.size();
222 std::vector<int> Nk(p, 0), l(p, 1);
223 std::vector<T> Zk(p, zero);
224 std::vector<double> gam(p, 0.0);
225 for (std::size_t j = 0; j < p; ++j) {
227 Zk[j] = Z.empty() ? zero : Z[keep[j]];
228 l[j] = lfull[keep[j]];
229 gam[j] = gfull[keep[j]];
231 const std::size_t nmask =
static_cast<std::size_t
>(1) << p;
235 for (std::size_t i = 0; i < M; ++i)
236 for (std::size_t mask = 1; mask < nmask; ++mask) {
237 std::vector<int> chi(R, 0);
238 for (std::size_t b = 0; b < p; ++b)
239 if (mask & (
static_cast<std::size_t
>(1) << b)) chi[keep[b]] = 1;
240 muS(i, mask) = detail::clwoi_support_rate<T>(mu[i], chi);
242 detail::clwoi_check_support<T>(mu, muS, keep, Nk, R);
245 std::vector<std::vector<std::size_t>> bits(nmask), subcol(nmask);
246 for (std::size_t mask = 1; mask < nmask; ++mask)
247 for (std::size_t b = 0; b < p; ++b)
248 if (mask & (
static_cast<std::size_t
>(1) << b)) {
249 bits[mask].push_back(b);
250 subcol[mask].push_back(mask & ~(
static_cast<std::size_t
>(1) << b));
255 for (std::size_t i = 0; i < M; ++i)
256 for (std::size_t b = 0; b < p; ++b) V(i, b) = visits.
empty() ? one : visits(i, keep[b]);
258 std::vector<T> r(p, one);
259 for (std::size_t j = 0; j < p; ++j)
260 r[j] = detail::clw_pow_real(
271 std::vector<std::vector<T>> rows;
272 for (std::size_t i = 0; i < M; ++i)
273 for (std::size_t mask = 1; mask < nmask; ++mask) {
274 bool dominated =
false;
275 for (std::size_t mask2 = 1; mask2 < nmask && !dominated; ++mask2)
276 if (mask2 != mask && (mask & mask2) == mask &&
279 if (dominated)
continue;
280 std::vector<T> row(p, zero);
281 for (std::size_t t = 0; t < bits[mask].size(); ++t)
282 row[bits[mask][t]] = V(i, bits[mask][t]) / muS(i, mask);
285 const std::size_t nrow = rows.size();
287 for (std::size_t i = 0; i < nrow; ++i)
288 for (std::size_t j = 0; j < p; ++j) Lt(i, j) = rows[i][j];
290 for (std::size_t j = 0; j < p; ++j) Lt(0, j) = zero;
292 const std::vector<long> mult(nrow ? nrow : 1, 1);
293 const std::vector<T> alpha = detail::clw_scaling(Lt, Lt, Nk, Zk, l, r, mult);
295 std::vector<T> arho0(p, zero);
297 for (std::size_t j = 0; j < p; ++j) {
298 arho0[j] = alpha[j] * Zk[j];
299 for (std::size_t i = 0; i < M; ++i) vs(i, j) = V(i, j) * alpha[j];
305 std::vector<detail::Cx<T>> FS(nmask, detail::Cx<T>(zero, zero));
306 const auto gbar = [&](
const std::vector<detail::Cx<T>>& w) {
307 detail::Cx<T> expo(zero, zero);
308 for (std::size_t j = 0; j < p; ++j)
309 expo = detail::cx_add(
310 expo, detail::cx_scale(detail::Cx<T>(T(w[j].re - one), w[j].im), arho0[j]));
311 detail::Cx<T> logF(zero, zero);
312 for (std::size_t i = 0; i < M; ++i) {
313 FS[0] = detail::Cx<T>(one, zero);
314 detail::Cx<T> tot(one, zero);
315 for (std::size_t mask = 1; mask < nmask; ++mask) {
316 detail::Cx<T> num(zero, zero);
317 detail::Cx<T> den(muS(i, mask), zero);
318 for (std::size_t t = 0; t < bits[mask].size(); ++t) {
319 const std::size_t b = bits[mask][t];
320 const detail::Cx<T> x = detail::cx_scale(w[b], vs(i, b));
321 num = detail::cx_add(num, detail::cx_mul(x, FS[subcol[mask][t]]));
322 den = detail::cx_sub(den, x);
324 FS[mask] = detail::cx_div(num, den);
325 tot = detail::cx_add(tot, FS[mask]);
327 logF = detail::cx_add(logF, detail::cx_log(tot));
329 return detail::cx_exp(detail::cx_add(expo, logF));
332 std::vector<detail::Cx<T>> w(p);
333 const detail::Cx<T> gv = detail::clw_invert(0, w, Nk, l, r, p, gbar);
335 throw NumericError(
"pfqn_clwoi: the inverted generating function is not positive");
338 for (std::size_t j = 0; j < p; ++j)