49 std::vector<gate_t> &out)
59 if (!collectProductLeaves(gc, c, out))
return false;
67 std::vector<gate_t> &out)
70 if (!collectProductLeaves(gc, k, out))
74 std::sort(out.begin(), out.end());
75 if (std::adjacent_find(out.begin(), out.end()) != out.end())
99 const std::vector<unsigned> &ref)
101 std::map<gate_t, unsigned> internalRef;
102 std::set<gate_t> visited;
103 std::vector<gate_t> stk{agg};
105 while (!stk.empty()) {
106 gate_t g = stk.back(); stk.pop_back();
109 if (visited.insert(c).second) stk.push_back(c);
112 for (
gate_t g : visited) {
113 if (g == agg)
continue;
120 if (ref[
static_cast<std::size_t
>(g)] != internalRef[g])
127constexpr unsigned kMaxContributorLeaves = 20;
148 const std::vector<unsigned> &ref,
152 std::map<gate_t, unsigned> internalRef;
153 std::set<gate_t> seen;
154 std::vector<gate_t> order;
155 std::vector<std::pair<gate_t, bool>> stk{{g,
false}};
156 while (!stk.empty()) {
157 auto top = stk.back(); stk.pop_back();
163 if (top.second) { order.push_back(x);
continue; }
164 if (!seen.insert(x).second)
continue;
165 stk.push_back({x,
true});
169 stk.push_back({c,
false});
175 if (x == g)
continue;
180 if (ref[
static_cast<std::size_t
>(x)] != internalRef[x])
return false;
184 const int N =
static_cast<int>(order.size());
185 std::map<gate_t, int> pos;
186 for (
int i = 0; i < N; ++i) pos[order[i]] = i;
187 std::vector<gate_type> typ(N);
188 std::vector<std::vector<int>> childIdx(N);
189 std::vector<int> leafbit(N, -1);
190 std::vector<double> leafProb;
191 for (
int i = 0; i < N; ++i) {
194 leafbit[i] =
static_cast<int>(leafProb.size());
195 leafProb.push_back(gc.
getProb(order[i]));
197 for (
gate_t c : gc.
getWires(order[i])) childIdx[i].push_back(pos[c]);
200 const unsigned m =
static_cast<unsigned>(leafProb.size());
201 if (m > kMaxContributorLeaves)
return false;
204 std::vector<char> val(N);
206 for (uint32_t mask = 0; mask < (1u << m); ++mask) {
207 for (
int i = 0; i < N; ++i) {
211 case gate_input: val[i] = (mask >> leafbit[i]) & 1u;
break;
212 case gate_times: {
char v = 1;
for (
int c : childIdx[i]) v = v && val[c]; val[i] = v;
break; }
213 case gate_plus: {
char v = 0;
for (
int c : childIdx[i]) v = v || val[c]; val[i] = v;
break; }
214 case gate_monus: val[i] = val[childIdx[i][0]] && !val[childIdx[i][1]];
break;
215 default:
return false;
220 for (
unsigned b = 0; b < m; ++b)
221 pr *= (mask >> b) & 1u ? leafProb[b] : 1.0 - leafProb[b];
231 std::vector<int> parent;
232 explicit UnionFind(
int n) : parent(n) {
233 std::iota(parent.begin(), parent.end(), 0);
236 while (parent[x] != x) { parent[x] = parent[parent[x]]; x = parent[x]; }
239 void unite(
int a,
int b) { parent[find(a)] = find(b); }
246static std::vector<std::vector<int>> independenceBlocks(
247 const std::vector<std::vector<gate_t>> &contribs)
249 const std::size_t n = contribs.size();
250 UnionFind uf(
static_cast<int>(n));
251 std::map<gate_t, int> first_owner;
252 for (std::size_t i = 0; i < n; ++i)
253 for (
gate_t l : contribs[i]) {
254 auto it = first_owner.find(l);
255 if (it == first_owner.end()) first_owner[l] =
static_cast<int>(i);
256 else uf.unite(
static_cast<int>(i), it->second);
258 std::map<int, std::vector<int>> bmap;
259 for (std::size_t i = 0; i < n; ++i)
260 bmap[uf.find(
static_cast<int>(i))].push_back(
static_cast<int>(i));
261 std::vector<std::vector<int>> blocks;
262 blocks.reserve(bmap.size());
263 for (
auto &kv : bmap) blocks.push_back(std::move(kv.second));
270static std::vector<gate_t> commonLeaves(
271 const std::vector<std::vector<gate_t>> &contribs,
272 const std::vector<int> &members)
274 std::vector<gate_t> common = contribs[members[0]];
275 for (std::size_t mi = 1; mi < members.size() && !common.empty(); ++mi) {
276 std::vector<gate_t> tmp;
277 std::set_intersection(common.begin(), common.end(),
278 contribs[members[mi]].begin(),
279 contribs[members[mi]].end(),
280 std::back_inserter(tmp));
288static std::vector<std::vector<gate_t>> residualsOf(
289 const std::vector<std::vector<gate_t>> &contribs,
290 const std::vector<int> &members,
const std::vector<gate_t> &common)
292 std::vector<std::vector<gate_t>> residuals;
293 residuals.reserve(members.size());
294 for (
int m : members) {
295 std::vector<gate_t> r;
296 std::set_difference(contribs[m].begin(), contribs[m].end(),
297 common.begin(), common.end(), std::back_inserter(r));
298 residuals.push_back(std::move(r));
304static std::vector<double> convolve(
const std::vector<double> &a,
305 const std::vector<double> &b)
307 if (a.empty())
return b;
308 if (b.empty())
return a;
309 std::vector<double> r(a.size() + b.size() - 1, 0.0);
310 for (std::size_t i = 0; i < a.size(); ++i) {
311 if (a[i] == 0.0)
continue;
312 for (std::size_t j = 0; j < b.size(); ++j)
313 r[i + j] += a[i] * b[j];
321static std::vector<double> productConvolve(
const std::vector<double> &a,
322 const std::vector<double> &b)
324 if (a.empty() || b.empty())
return {};
325 const std::size_t amax = a.size() - 1, bmax = b.size() - 1;
326 std::vector<double> r(amax * bmax + 1, 0.0);
327 for (std::size_t i = 0; i <= amax; ++i) {
328 if (a[i] == 0.0)
continue;
329 for (std::size_t j = 0; j <= bmax; ++j)
330 r[i * j] += a[i] * b[j];
336struct ProductDecomp {
338 std::map<gate_t, int> leafFactor;
339 std::vector<std::vector<std::vector<gate_t>>> parts;
362static ProductDecomp decomposeProduct(
363 const std::vector<std::vector<gate_t>> &contribs,
364 const std::vector<int> &members)
369 std::vector<gate_t> L;
370 for (
int m : members)
for (
gate_t l : contribs[m]) L.push_back(l);
371 std::sort(L.begin(), L.end());
372 L.erase(std::unique(L.begin(), L.end()), L.end());
373 std::map<gate_t, int> idx;
374 for (std::size_t i = 0; i < L.size(); ++i) idx[L[i]] =
static_cast<int>(i);
375 const int nl =
static_cast<int>(L.size());
378 std::vector<std::vector<char>> cooc(nl, std::vector<char>(nl, 0));
379 for (
int m : members) {
380 const auto &cl = contribs[m];
381 for (std::size_t i = 0; i < cl.size(); ++i)
382 for (std::size_t j = i + 1; j < cl.size(); ++j) {
383 int a = idx[cl[i]], b = idx[cl[j]];
384 cooc[a][b] = cooc[b][a] = 1;
390 for (
int u = 0; u < nl; ++u)
391 for (
int v = u + 1; v < nl; ++v)
392 if (!cooc[u][v]) uf.unite(u, v);
393 std::map<int, int> factorId;
394 for (
int u = 0; u < nl; ++u)
395 factorId.emplace(uf.find(u),
static_cast<int>(factorId.size()));
396 const int nf =
static_cast<int>(factorId.size());
397 if (nf < 2)
return out;
399 for (
gate_t l : L) out.leafFactor[l] = factorId[uf.find(idx[l])];
403 std::vector<std::set<std::vector<gate_t>>> parts(nf);
404 for (
int m : members) {
405 std::vector<std::vector<gate_t>> proj(nf);
406 for (
gate_t l : contribs[m])
407 proj[out.leafFactor[l]].push_back(l);
408 for (
int f = 0; f < nf; ++f) {
409 if (proj[f].empty())
return out;
410 parts[f].insert(std::move(proj[f]));
417 std::size_t prod = 1;
418 for (
int f = 0; f < nf; ++f) prod *= parts[f].size();
419 if (prod != members.size())
return out;
421 out.parts.resize(nf);
422 for (
int f = 0; f < nf; ++f)
423 out.parts[f].assign(parts[f].begin(), parts[f].end());
455 std::vector<std::vector<gate_t>> contribs,
458 const std::size_t n = contribs.size();
459 if (n == 0)
return std::vector<double>{1.0};
462 UnionFind uf(
static_cast<int>(n));
464 std::map<gate_t, int> first_owner;
465 for (std::size_t i = 0; i < n; ++i)
466 for (
gate_t l : contribs[i]) {
467 auto it = first_owner.find(l);
468 if (it == first_owner.end()) first_owner[l] =
static_cast<int>(i);
469 else uf.unite(
static_cast<int>(i), it->second);
472 std::map<int, std::vector<int>> blocks;
473 for (std::size_t i = 0; i < n; ++i)
474 blocks[uf.find(
static_cast<int>(i))].push_back(
static_cast<int>(i));
476 std::vector<double> total{1.0};
477 for (
const auto &be : blocks) {
478 const std::vector<int> &members = be.second;
479 std::vector<double> blockPMF;
481 if (members.size() == 1) {
486 blockPMF = std::vector<double>{1.0 - q, q};
488 std::vector<gate_t> common = commonLeaves(contribs, members);
489 if (!common.empty()) {
494 std::vector<double> inner =
495 countPMF(gc, residualsOf(contribs, members, common), ok);
497 blockPMF = std::move(inner);
498 for (
double &x : blockPMF) x *= p_root;
499 blockPMF[0] += (1.0 - p_root);
505 ProductDecomp pd = decomposeProduct(contribs, members);
506 if (!pd.ok) { ok =
false;
return {}; }
507 std::vector<double> acc;
508 for (std::size_t f = 0; f < pd.parts.size(); ++f) {
509 std::vector<double> fp = countPMF(gc, std::move(pd.parts[f]), ok);
511 acc = (f == 0) ? std::move(fp) : productConvolve(acc, fp);
513 blockPMF = std::move(acc);
516 total = convolve(total, blockPMF);
529static double prFromPMF(
const std::vector<double> &pmf,
533 for (
int c = is_scalar ? 0 : 1; c < static_cast<int>(pmf.size()); ++c) {
543 if (sat) pr += pmf[c];
561 std::vector<std::vector<gate_t>> contribs,
bool &ok)
563 if (contribs.empty())
return 1.0;
565 for (
const auto &members : independenceBlocks(contribs)) {
567 if (members.size() == 1) {
570 block_absent = 1.0 - q;
572 std::vector<gate_t> common = commonLeaves(contribs, members);
573 if (!common.empty()) {
576 double inner = pAllAbsent(gc, residualsOf(contribs, members, common), ok);
578 block_absent = (1.0 - p_root) + p_root * inner;
586 ProductDecomp pd = decomposeProduct(contribs, members);
587 if (!pd.ok) { ok =
false;
return 0.0; }
588 double prodPresent = 1.0;
589 for (
auto &fparts : pd.parts) {
590 double fa = pAllAbsent(gc, fparts, ok);
592 prodPresent *= (1.0 - fa);
594 block_absent = 1.0 - prodPresent;
597 result *= block_absent;
609 const std::vector<std::vector<gate_t>> &leaves,
610 const std::vector<long> &vals,
611 const std::vector<std::vector<std::pair<long, double>>> &blocks,
621 auto pAbsentWhere = [&](
auto pred) ->
double {
622 std::vector<std::vector<gate_t>> sub;
623 for (std::size_t i = 0; i < leaves.size(); ++i)
624 if (pred(vals[i])) sub.push_back(leaves[i]);
625 double r = pAllAbsent(gc, std::move(sub), ok);
626 for (
const auto &blk : blocks) {
628 for (
const auto &alt : blk)
if (pred(alt.first)) s += alt.second;
629 r *= 1.0 - (s > 1.0 ? 1.0 : s);
634 const double allAbsent = pAbsentWhere([](
int) {
return true; });
644 - pAbsentWhere([&](
long v){
return v >= C;});
break;
646 - (pAbsentWhere([&](
long v){
return v > C;})
647 - pAbsentWhere([&](
long v){
return v >= C;}));
break;
656 - pAbsentWhere([&](
long v){
return v <= C;});
break;
658 - (pAbsentWhere([&](
long v){
return v < C;})
659 - pAbsentWhere([&](
long v){
return v <= C;}));
break;
671constexpr std::size_t kMaxSumSupport = 1u << 20;
696using JointPMF = std::map<std::pair<long, long>,
double>;
706static bool recoverAdditiveSeparation(
707 const std::vector<std::vector<gate_t>> &contribs,
708 const std::vector<int> &members,
const std::vector<long> &weights,
709 const ProductDecomp &pd, std::vector<std::vector<long>> &partVals)
711 const int nf =
static_cast<int>(pd.parts.size());
713 auto partOf = [&](
int m,
int f) {
714 std::vector<gate_t> p;
715 for (
gate_t l : contribs[m])
716 if (pd.leafFactor.at(l) == f) p.push_back(l);
721 std::map<std::vector<std::vector<gate_t>>,
long> grid;
722 for (
int m : members) {
723 std::vector<std::vector<gate_t>> key(nf);
724 for (
int f = 0; f < nf; ++f) key[f] = partOf(m, f);
725 grid[key] = weights[m];
728 const int m0 = members[0];
729 const long W0 = weights[m0];
730 std::vector<std::vector<gate_t>> ref(nf);
731 for (
int f = 0; f < nf; ++f) ref[f] = partOf(m0, f);
734 std::vector<std::map<std::vector<gate_t>,
long>> h(nf);
735 for (
int f = 0; f < nf; ++f)
736 for (
const auto &p : pd.parts[f]) {
737 std::vector<std::vector<gate_t>> key = ref;
739 auto it = grid.find(key);
740 if (it == grid.end())
return false;
741 h[f][p] = it->second - W0;
745 for (
int m : members) {
747 for (
int f = 0; f < nf; ++f) acc += h[f].at(partOf(m, f));
748 if (acc != weights[m])
return false;
751 partVals.assign(nf, {});
752 for (
int f = 0; f < nf; ++f) {
753 partVals[f].reserve(pd.parts[f].size());
754 for (
const auto &p : pd.parts[f])
755 partVals[f].push_back(h[f].at(p) + (f == 0 ? W0 : 0));
761 std::vector<std::vector<gate_t>> contribs,
762 std::vector<long> weights,
bool &ok)
766 if (contribs.empty())
return total;
768 for (
const auto &members : independenceBlocks(contribs)) {
770 if (members.size() == 1) {
773 blockPMF[{0, 0}] += 1.0 - q;
774 blockPMF[{weights[members[0]], 1}] += q;
776 std::vector<gate_t> common = commonLeaves(contribs, members);
777 if (!common.empty()) {
781 std::vector<long> rweights;
782 rweights.reserve(members.size());
783 for (
int m : members) rweights.push_back(weights[m]);
784 JointPMF inner = sumCountPMF(
785 gc, residualsOf(contribs, members, common), std::move(rweights), ok);
787 for (
const auto &kv : inner) blockPMF[kv.first] += p_root * kv.second;
788 blockPMF[{0, 0}] += 1.0 - p_root;
795 ProductDecomp pd = decomposeProduct(contribs, members);
796 if (!pd.ok) { ok =
false;
return {}; }
797 std::vector<std::vector<long>> partVals;
798 if (!recoverAdditiveSeparation(contribs, members, weights, pd,
800 ok =
false;
return {};
804 for (std::size_t f = 0; f < pd.parts.size(); ++f) {
805 JointPMF Jf = sumCountPMF(gc, pd.parts[f], partVals[f], ok);
808 for (
const auto &a : acc)
809 for (
const auto &b : Jf)
810 nacc[{a.first.first * b.first.second
811 + b.first.first * a.first.second,
812 a.first.second * b.first.second}] += a.second * b.second;
813 if (nacc.size() > kMaxSumSupport) { ok =
false;
return {}; }
816 blockPMF = std::move(acc);
821 for (
const auto &a : total)
822 for (
const auto &b : blockPMF)
823 ntotal[{a.first.first + b.first.first,
824 a.first.second + b.first.second}] += a.second * b.second;
825 if (ntotal.size() > kMaxSumSupport) { ok =
false;
return {}; }
832 std::vector<std::vector<gate_t>> contribs,
833 std::vector<long> weights,
bool &ok);
839static bool i128_mul(__int128 a, __int128 b, __int128 &out)
841 constexpr __int128 LIM =
static_cast<__int128
>(1) << 120;
842 if (a == 0 || b == 0) { out = 0;
return true; }
844 if (r / b != a)
return false;
845 __int128 ar = r < 0 ? -r : r;
846 if (ar > LIM)
return false;
865static std::map<long, double> mulSeparableSumPMF(
867 const std::vector<std::vector<gate_t>> &contribs,
868 const std::vector<int> &members,
const std::vector<long> &weights,
869 const ProductDecomp &pd,
bool &ok)
871 const int nf =
static_cast<int>(pd.parts.size());
873 auto partOf = [&](
int m,
int f) {
874 std::vector<gate_t> p;
875 for (
gate_t l : contribs[m])
876 if (pd.leafFactor.at(l) == f) p.push_back(l);
880 std::map<std::vector<std::vector<gate_t>>,
long> grid;
881 for (
int m : members) {
882 std::vector<std::vector<gate_t>> key(nf);
883 for (
int f = 0; f < nf; ++f) key[f] = partOf(m, f);
884 grid[key] = weights[m];
888 for (
int m : members)
if (weights[m] != 0) { piv = m;
break; }
889 if (piv < 0) { ok =
false;
return {}; }
890 const long D = weights[piv];
891 std::vector<std::vector<gate_t>> ref(nf);
892 for (
int f = 0; f < nf; ++f) ref[f] = partOf(piv, f);
895 std::vector<std::vector<long>> A(nf);
896 std::vector<std::map<std::vector<gate_t>,
int>> partIdx(nf);
897 for (
int f = 0; f < nf; ++f)
898 for (
const auto &p : pd.parts[f]) {
899 partIdx[f][p] =
static_cast<int>(A[f].size());
900 std::vector<std::vector<gate_t>> key = ref;
902 auto it = grid.find(key);
903 if (it == grid.end()) { ok =
false;
return {}; }
904 A[f].push_back(it->second);
909 for (
int t = 0; t < nf - 1; ++t)
910 if (!i128_mul(Dk1,
static_cast<__int128
>(D), Dk1)) { ok =
false;
return {}; }
913 for (
int m : members) {
915 for (
int f = 0; f < nf; ++f) {
916 long a = A[f][partIdx[f].at(partOf(m, f))];
917 if (!i128_mul(prod,
static_cast<__int128
>(a), prod)) { ok =
false;
return {}; }
920 if (!i128_mul(
static_cast<__int128
>(weights[m]), Dk1, rhs)) { ok =
false;
return {}; }
921 if (prod != rhs) { ok =
false;
return {}; }
925 std::map<__int128, double> run;
927 for (
int f = 0; f < nf; ++f) {
928 std::map<long, double> Pf = sumPMF(gc, pd.parts[f], A[f], ok);
930 std::map<__int128, double> nxt;
931 for (
const auto &rk : run)
932 for (
const auto &sk : Pf) {
934 if (!i128_mul(rk.first,
static_cast<__int128
>(sk.first), prod)) {
935 ok =
false;
return {};
937 nxt[prod] += rk.second * sk.second;
939 if (nxt.size() > kMaxSumSupport) { ok =
false;
return {}; }
944 std::map<long, double> out;
945 for (
const auto &kv : run) {
946 if (kv.first % Dk1 != 0) { ok =
false;
return {}; }
947 __int128 bs = kv.first / Dk1;
948 if (bs >
static_cast<__int128
>(LONG_MAX) ||
949 bs <
static_cast<__int128
>(LONG_MIN)) { ok =
false;
return {}; }
950 out[
static_cast<long>(bs)] += kv.second;
963 std::vector<std::vector<gate_t>> contribs,
964 std::vector<long> weights,
bool &ok)
966 std::map<long, double> total;
968 if (contribs.empty())
return total;
970 for (
const auto &members : independenceBlocks(contribs)) {
971 std::map<long, double> blockPMF;
972 if (members.size() == 1) {
975 blockPMF[0] += 1.0 - q;
976 blockPMF[weights[members[0]]] += q;
978 std::vector<gate_t> common = commonLeaves(contribs, members);
979 if (!common.empty()) {
983 std::vector<std::vector<gate_t>> residuals =
984 residualsOf(contribs, members, common);
985 std::vector<long> rweights;
986 rweights.reserve(members.size());
987 for (
int m : members) rweights.push_back(weights[m]);
989 std::map<long, double> inner =
990 sumPMF(gc, std::move(residuals), std::move(rweights), ok);
992 for (
const auto &kv : inner) blockPMF[kv.first] += p_root * kv.second;
993 blockPMF[0] += (1.0 - p_root);
1005 ProductDecomp pd = decomposeProduct(contribs, members);
1006 if (!pd.ok) { ok =
false;
return {}; }
1007 const int nf =
static_cast<int>(pd.parts.size());
1010 std::map<std::vector<gate_t>,
long> partVal;
1011 for (
int f = 0; f < nf && chosen < 0; ++f) {
1012 std::map<std::vector<gate_t>,
long> pv;
1013 bool consistent =
true;
1014 for (
int m : members) {
1015 std::vector<gate_t> partf;
1016 for (
gate_t l : contribs[m])
1017 if (pd.leafFactor[l] == f) partf.push_back(l);
1018 auto it = pv.find(partf);
1019 if (it == pv.end()) pv[partf] = weights[m];
1020 else if (it->second != weights[m]) { consistent =
false;
break; }
1022 if (consistent) { chosen = f; partVal = std::move(pv); }
1029 std::vector<long> partValues;
1030 partValues.reserve(pd.parts[chosen].size());
1031 for (
const auto &part : pd.parts[chosen])
1032 partValues.push_back(partVal[part]);
1033 std::map<long, double> Sf =
1034 sumPMF(gc, pd.parts[chosen], std::move(partValues), ok);
1038 std::vector<double> M;
1039 for (
int f = 0; f < nf; ++f) {
1040 if (f == chosen)
continue;
1041 std::vector<double> cf = countPMF(gc, pd.parts[f], ok);
1043 M = M.empty() ? std::move(cf) : productConvolve(M, cf);
1047 for (
const auto &skv : Sf)
1048 for (std::size_t mm = 0; mm < M.size(); ++mm)
1050 blockPMF[skv.first *
static_cast<long>(mm)] += skv.second * M[mm];
1051 if (blockPMF.size() > kMaxSumSupport) { ok =
false;
return {}; }
1060 std::vector<std::vector<long>> sep;
1061 if (recoverAdditiveSeparation(contribs, members, weights, pd, sep)) {
1062 std::vector<std::vector<gate_t>> bc;
1063 std::vector<long> bw;
1064 bc.reserve(members.size());
1065 bw.reserve(members.size());
1066 for (
int m : members) {
1067 bc.push_back(contribs[m]);
1068 bw.push_back(weights[m]);
1070 JointPMF j = sumCountPMF(gc, std::move(bc), std::move(bw), ok);
1072 for (
const auto &kv : j) blockPMF[kv.first.first] += kv.second;
1074 blockPMF = mulSeparableSumPMF(gc, contribs, members, weights, pd, ok);
1077 if (blockPMF.size() > kMaxSumSupport) { ok =
false;
return {}; }
1081 std::map<long, double> ntotal;
1082 for (
const auto &a : total)
1083 for (
const auto &b : blockPMF)
1084 ntotal[a.first + b.first] += a.second * b.second;
1085 if (ntotal.size() > kMaxSumSupport) { ok =
false;
return {}; }
1095 unsigned resolved = 0;
1098 std::vector<gate_t> cmps;
1099 for (std::size_t i = 0; i < nb; ++i) {
1100 auto g =
static_cast<gate_t>(i);
1104 if (cmps.empty())
return 0;
1108 for (
gate_t cmp : cmps) {
1123 const auto &ks = match.
ks;
1124 const std::size_t n = ks.size();
1128 if (ref[
static_cast<std::size_t
>(agg)] != 1)
continue;
1137 std::vector<std::vector<gate_t>> leaves;
1138 std::vector<long> tid_vals;
1141 std::map<gate_t, std::vector<std::pair<double, long>>> blocks;
1142 for (std::size_t i = 0; i < n && ok; ++i) {
1144 const auto &ch = gc.
getWires(ks[i]);
1145 if (ch.size() != 1) { ok =
false;
break; }
1146 blocks[ch[0]].push_back({gc.
getProb(ks[i]),
1147 static_cast<long>(match.
ms[i])});
1149 std::vector<gate_t> ls;
1150 if (parseProductContributor(gc, ks[i], ls)) {
1151 leaves.push_back(std::move(ls));
1152 tid_vals.push_back(
static_cast<long>(match.
ms[i]));
1159 if (!contributorExactMarginal(gc, ks[i], ref, pi)) { ok =
false;
break; }
1160 blocks[ks[i]].push_back({pi,
static_cast<long>(match.
ms[i])});
1171 std::set<gate_t> tidset;
1172 for (
const auto &ls : leaves) tidset.insert(ls.begin(), ls.end());
1174 for (
const auto &b : blocks)
1175 if (tidset.count(b.first)) { clash =
true;
break; }
1176 if (clash)
continue;
1184 if (!aggSubtreePrivate(gc, agg, ref))
continue;
1187 auto blockMass = [](
const std::vector<std::pair<double, long>> &alts) {
1189 for (
const auto &alt : alts) psum += alt.first;
1190 return psum > 1.0 ? 1.0 : psum;
1204 bool all_one =
true;
1205 for (
int m : match.
ms)
if (m != 1) { all_one =
false;
break; }
1206 if (!all_one)
continue;
1207 std::vector<double> total = countPMF(gc, leaves, ok);
1211 for (
const auto &b : blocks) {
1212 double psum = blockMass(b.second);
1213 total = convolve(total, std::vector<double>{1.0 - psum, psum});
1215 const bool is_scalar =
1217 pr = prFromPMF(total, match.
op, match.
C, is_scalar);
1228 auto shift = [&](
long m) {
return is_avg ? m - match.
C : m; };
1229 std::vector<long> weights;
1230 weights.reserve(tid_vals.size());
1231 long lo = 0, hi = 0;
1232 for (
long m : tid_vals) {
1234 weights.push_back(w);
1235 if (w < 0) lo += w;
else hi += w;
1237 for (
const auto &b : blocks)
1238 for (
const auto &alt : b.second) {
1239 long w = shift(alt.second);
1240 if (w < 0) lo += w;
else hi += w;
1243 if (hi - lo + 1 >
static_cast<long>(kMaxSumSupport))
continue;
1244 const long thr = is_avg ? 0 : match.
C;
1246 std::map<long, double> dist = sumPMF(gc, leaves, std::move(weights), ok);
1249 for (
const auto &b : blocks) {
1250 std::map<long, double> bpmf;
1251 for (
const auto &alt : b.second) bpmf[shift(alt.second)] += alt.first;
1252 bpmf[0] += 1.0 - blockMass(b.second);
1253 std::map<long, double> nd;
1254 for (
const auto &a : dist)
1255 for (
const auto &c : bpmf)
1256 nd[a.first + c.first] += a.second * c.second;
1257 if (nd.size() > kMaxSumSupport) { ok =
false;
break; }
1262 for (
const auto &kv : dist)
1263 if (sumSatisfies(kv.first, match.
op, thr)) pr += kv.second;
1268 if (sumSatisfies(0, match.
op, thr)) {
1269 double emptyMass = pAllAbsent(gc, leaves, ok);
1271 for (
const auto &b : blocks) emptyMass *= 1.0 - blockMass(b.second);
1278 std::vector<std::vector<std::pair<long, double>>> blockvec;
1279 blockvec.reserve(blocks.size());
1280 for (
const auto &b : blocks) {
1281 std::vector<std::pair<long, double>> alts;
1282 alts.reserve(b.second.size());
1283 for (
const auto &alt : b.second) alts.push_back({alt.second, alt.first});
1284 blockvec.push_back(std::move(alts));
1286 pr = minMaxProb(gc, leaves, tid_vals, blockvec, agg_kind, match.
op,
1291 if (pr < 0.0) pr = 0.0;
1292 if (pr > 1.0) pr = 1.0;