39#define CHECK_FOR_INTERRUPTS() ((void)0)
55 for(
bag_t i{0}; i<
td.bags.size(); ++i) {
56 const auto &b =
td.getBag(i);
57 if(
td.getChildren(i).empty() && b.size()==1 &&
c.getGateType(*b.begin()) ==
BooleanGate::IN)
70 for(
auto g:
c.inputs) {
72 if(
c.getUUID(g).empty())
77 d.addWire(not_gate, gate);
86 for(
const auto &p: result_gates) {
87 if(p.suspicious.empty() && p.valuation.find(
root_id)->second) {
88 d.addWire(
d.root, p.id);
130 for(
const auto &g: suspicious) {
142 if(
td.getBag(bag).size()==0)
147 auto single_gate = *
td.getBag(bag).begin();
156 {std::make_pair(single_gate,
true)},
160 {std::make_pair(single_gate,
false)},
163 return { std::move(pos), std::move(neg) };
168 for(
auto v: {
true,
false}) {
175 if(
isStrong(
c.getGateType(single_gate), v))
176 suspicious.
insert(single_gate);
178 result_gates.emplace_back(
181 std::move(suspicious)
192 for(
const auto &p1: valuation) {
193 for(
const auto &p2: valuation) {
194 if(p1.first==p2.first)
196 if(!
isStrong(
c.getGateType(p1.first),p2.second))
200 switch(
c.getGateType(p1.first)) {
203 if(p1.second!=p2.second)
207 if(p1.second==p2.second)
226 for(
const auto &[g1,val]: valuation) {
227 if(innocent.
find(g1)!=innocent.
end())
231 if(!
isStrong(
c.getGateType(g1), valuation.
find(g1)->second)) {
239 for(
const auto &[g2, value]: valuation) {
263 for(
auto &[valuation, m]: gates_to_or) {
266 for(
auto &[var, val]: valuation) {
269 o <<
"(" << var <<
"," << val <<
")";
274 for(
auto &[innocent, gates]: m) {
277 for(
auto &x: innocent) {
286 for(
auto &x: gates) {
308 for(
auto g: children_gates) {
314 CHECK_FOR_INTERRUPTS();
321 auto compatibleValuation = [&g](
const auto &p) {
322 for(
const auto &[var, val]: p.first) {
323 auto it = g.valuation.find(var);
324 if(it != g.valuation.end() && it->second != val)
330 for (
auto it = std::find_if(partial.begin(), partial.end(), compatibleValuation);
332 it = std::find_if(std::next(it), partial.end(), compatibleValuation)) {
333 auto &[matching_valuation, m] = *it;
337 for(
auto &[var, val]: g.valuation) {
338 if(
td.getBag(bag).find(var)!=
td.getBag(bag).end()) {
339 if(matching_valuation.find(var)==matching_valuation.end())
342 if(g.suspicious.find(var)==g.suspicious.end()) {
343 extra_innocent.
insert(var);
352 for(
auto &[innocent, gates]: m) {
355 for(
auto s: innocent)
358 new_innocent =
getInnocent(valuation, new_innocent);
361 gates_to_or[valuation][new_innocent].push_back(g.id);
363 for(
auto g2: gates) {
372 d.getWires(g.id).empty()))
373 gates_children[nb++]=g.id;
376 d.getWires(g2).empty()))
377 gates_children[nb++]=g2;
390 and_gate = gates_children[0];
393 for(
auto x: gates_children) {
394 d.addWire(and_gate, x);
398 gates_to_or[valuation][new_innocent].push_back(and_gate);
413 struct RecursionParams
416 size_t children_processed;
420 bag(b), children_processed(
c), gates_to_or(std::move(g)) {
423 RecursionParams(
bag_t b) :
424 bag(b), children_processed(0) {
425 gates_to_or_t::mapped_type m;
433 std::stack<std::variant<RecursionParams,RecursionResult> > stack;
434 stack.emplace(RecursionParams{
td.root});
436 while(!stack.empty()) {
443 CHECK_FOR_INTERRUPTS();
444 RecursionResult result;
446 if(stack.top().index()==1) {
447 result = std::move(std::get<1>(stack.top()));
453 auto [bag, children_processed, gates_to_or] = std::move(std::get<0>(stack.top()));
456 if(
td.getChildren(bag).empty()) {
460 if(children_processed>0) {
464 if(children_processed==
td.getChildren(bag).size()) {
467 for(
auto &[valuation, m]: gates_to_or) {
468 for(
auto &[innocent, gates]: m) {
471 assert(gates.size()!=0);
474 for(
auto &[var, val]: valuation)
475 if(innocent.find(var)==innocent.end())
483 std::sort(gates.begin(), gates.end());
484 gates.erase(std::unique(gates.begin(), gates.end()), gates.end());
487 result_gate = *gates.begin();
490 for(
auto &g: gates) {
491 d.addWire(result_gate, g);
495 result_gates.emplace_back(result_gate, std::move(valuation), std::move(suspicious));
499 stack.emplace(std::move(result_gates));
501 stack.emplace(RecursionParams{bag, children_processed+1, std::move(gates_to_or)});
502 stack.emplace(RecursionParams{
td.getChildren(bag)[children_processed]});
520 o <<
"(" << p.first <<
"," << p.second <<
")";
BooleanGate
Gate types for a Boolean provenance circuit.
@ NOT
Logical negation of a single child gate.
@ OR
Logical disjunction of child gates.
@ AND
Logical conjunction of child gates.
@ IN
Input (variable) gate representing a base tuple.
gate_t
Strongly-typed gate identifier.
Out-of-line template method implementations for Circuit<gateType>.
bag_t
Strongly-typed bag identifier for a tree decomposition.
flat_set< gate_t, small_vector > Bag
The type of a bag: a small flat set of gate IDs.
std::unordered_map< gate_t, bag_t > responsible_bag
Maps each gate to its "responsible" bag.
bool circuitHasWire(gate_t u, gate_t v) const
Return true if there is a wire from gate u to gate v.
std::vector< T > gate_vector_t
Generic bounded-capacity vector for intermediate d-DNNF gates.
gate_vector_t< dDNNFGate > builddDNNF()
Main recursive procedure: build the d-DNNF bottom-up.
std::set< std::pair< gate_t, gate_t > > wiresSet
Set of all wires in the source circuit.
flat_map< gate_t, bool, small_vector > valuation_t
Partial assignment of truth values to the gates of a bag.
std::unordered_map< gate_t, gate_t > negated_input_gate
Maps original IN gates to their negations.
dDNNF && build() &&
Execute the compilation and return the resulting d-DNNF.
flat_set< gate_t, small_vector > suspicious_t
Set of gates whose truth-value assignments are not yet confirmed.
std::unordered_map< gate_t, gate_t > input_gate
Maps original IN gates to d-DNNF IN gates.
gates_to_or_t collectGatesToOr(bag_t bag, const gate_vector_t< dDNNFGate > &gates, const gates_to_or_t &partial)
Group a list of dDNNFGate entries by (valuation, suspicious) pairs.
gate_t root_id
Root gate of the source circuit.
dDNNF d
The d-DNNF being constructed.
const BooleanCircuit & c
Source circuit.
std::unordered_map< valuation_t, std::map< suspicious_t, gate_vector_t< gate_t > > > gates_to_or_t
Dynamic-programming table: (valuation, suspicious) → list of children.
TreeDecomposition & td
Tree decomposition of the circuit's primal graph.
bool isAlmostValuation(const valuation_t &valuation) const
Return true if valuation is a "almost valuation".
suspicious_t getInnocent(const valuation_t &valuation, const suspicious_t &innocent) const
Compute the subset of innocent that remains innocent.
gate_vector_t< dDNNFGate > builddDNNFLeaf(bag_t bag)
Build the d-DNNF contributions for a leaf bag.
A d-DNNF circuit supporting exact probabilistic and game-theoretic evaluation.
static bool isConnectible(const dDNNFTreeDecompositionBuilder::suspicious_t &suspicious, const TreeDecomposition::Bag &b)
Check whether all suspicious gates in suspicious appear in bag b.
constexpr bool isStrong(BooleanGate type, bool value)
Return true if assigning value to a gate of type type is a "strong" assignment.
std::ostream & operator<<(std::ostream &o, const dDNNFTreeDecompositionBuilder::gates_to_or_t &gates_to_or)
Write a gates_to_or_t DP table to an output stream for debugging.
Constructs a d-DNNF from a Boolean circuit and its tree decomposition.
Intermediate representation of a partially built d-DNNF gate.
suspicious_t suspicious
Gates whose assignments are unconfirmed.
valuation_t valuation
Current bag's truth-value assignment.
gate_t id
Gate ID in the target d-DNNF.
iterator find(K &&k)
Find the element with key k.
iterator end()
Return iterator past the last element.
void insert(const K &value)
Insert value if not already present (const-ref overload).
iterator find(K &&k)
Find an element equal to k.