42#define CHECK_FOR_INTERRUPTS() provsql_tdkc_poll()
58 for(
bag_t i{0}; i<
td.bags.size(); ++i) {
59 const auto &b =
td.getBag(i);
60 if(
td.getChildren(i).empty() && b.size()==1 &&
c.getGateType(*b.begin()) ==
BooleanGate::IN)
73 for(
auto g:
c.inputs) {
75 if(
c.getUUID(g).empty())
80 d.addWire(not_gate, gate);
89 for(
const auto &p: result_gates) {
90 if(p.suspicious.empty() && p.valuation.find(
root_id)->second) {
91 d.addWire(
d.root, p.id);
133 for(
const auto &g: suspicious) {
145 if(
td.getBag(bag).size()==0)
150 auto single_gate = *
td.getBag(bag).begin();
159 {std::make_pair(single_gate,
true)},
163 {std::make_pair(single_gate,
false)},
166 return { std::move(pos), std::move(neg) };
171 for(
auto v: {
true,
false}) {
178 if(
isStrong(
c.getGateType(single_gate), v))
179 suspicious.
insert(single_gate);
181 result_gates.emplace_back(
184 std::move(suspicious)
195 for(
const auto &p1: valuation) {
196 for(
const auto &p2: valuation) {
197 if(p1.first==p2.first)
199 if(!
isStrong(
c.getGateType(p1.first),p2.second))
203 switch(
c.getGateType(p1.first)) {
206 if(p1.second!=p2.second)
210 if(p1.second==p2.second)
229 for(
const auto &[g1,val]: valuation) {
230 if(innocent.
find(g1)!=innocent.
end())
234 if(!
isStrong(
c.getGateType(g1), valuation.
find(g1)->second)) {
242 for(
const auto &[g2, value]: valuation) {
266 for(
auto &[valuation, m]: gates_to_or) {
269 for(
auto &[var, val]: valuation) {
272 o <<
"(" << var <<
"," << val <<
")";
277 for(
auto &[innocent, gates]: m) {
280 for(
auto &x: innocent) {
289 for(
auto &x: gates) {
311 for(
auto g: children_gates) {
317 CHECK_FOR_INTERRUPTS();
324 auto compatibleValuation = [&g](
const auto &p) {
325 for(
const auto &[var, val]: p.first) {
326 auto it = g.valuation.find(var);
327 if(it != g.valuation.end() && it->second != val)
333 for (
auto it = std::find_if(partial.begin(), partial.end(), compatibleValuation);
335 it = std::find_if(std::next(it), partial.end(), compatibleValuation)) {
336 auto &[matching_valuation, m] = *it;
340 for(
auto &[var, val]: g.valuation) {
341 if(
td.getBag(bag).find(var)!=
td.getBag(bag).end()) {
342 if(matching_valuation.find(var)==matching_valuation.end())
345 if(g.suspicious.find(var)==g.suspicious.end()) {
346 extra_innocent.
insert(var);
355 for(
auto &[innocent, gates]: m) {
358 for(
auto s: innocent)
361 new_innocent =
getInnocent(valuation, new_innocent);
364 gates_to_or[valuation][new_innocent].push_back(g.id);
366 for(
auto g2: gates) {
375 d.getWires(g.id).empty()))
376 gates_children[nb++]=g.id;
379 d.getWires(g2).empty()))
380 gates_children[nb++]=g2;
393 and_gate = gates_children[0];
396 for(
auto x: gates_children) {
397 d.addWire(and_gate, x);
401 gates_to_or[valuation][new_innocent].push_back(and_gate);
416 struct RecursionParams
419 size_t children_processed;
423 bag(b), children_processed(
c), gates_to_or(std::move(g)) {
426 RecursionParams(
bag_t b) :
427 bag(b), children_processed(0) {
428 gates_to_or_t::mapped_type m;
436 std::stack<std::variant<RecursionParams,RecursionResult> > stack;
437 stack.emplace(RecursionParams{
td.root});
439 while(!stack.empty()) {
446 CHECK_FOR_INTERRUPTS();
447 RecursionResult result;
449 if(stack.top().index()==1) {
450 result = std::move(std::get<1>(stack.top()));
456 auto [bag, children_processed, gates_to_or] = std::move(std::get<0>(stack.top()));
459 if(
td.getChildren(bag).empty()) {
463 if(children_processed>0) {
467 if(children_processed==
td.getChildren(bag).size()) {
470 for(
auto &[valuation, m]: gates_to_or) {
471 for(
auto &[innocent, gates]: m) {
474 assert(gates.size()!=0);
477 for(
auto &[var, val]: valuation)
478 if(innocent.find(var)==innocent.end())
486 std::sort(gates.begin(), gates.end());
487 gates.erase(std::unique(gates.begin(), gates.end()), gates.end());
490 result_gate = *gates.begin();
493 for(
auto &g: gates) {
494 d.addWire(result_gate, g);
498 result_gates.emplace_back(result_gate, std::move(valuation), std::move(suspicious));
502 stack.emplace(std::move(result_gates));
504 stack.emplace(RecursionParams{bag, children_processed+1, std::move(gates_to_or)});
505 stack.emplace(RecursionParams{
td.getChildren(bag)[children_processed]});
523 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.
Build-loop interrupt hook for the standalone tdkc binary.