36 td.makeFriendly(root_id);
39 for(
bag_t i{0}; i<td.bags.size(); ++i) {
40 const auto &b = td.getBag(i);
41 if(td.getChildren(i).empty() && b.size()==1 && c.getGateType(*b.begin()) ==
BooleanGate::IN)
42 responsible_bag[*b.begin()] = i;
47 assert(responsible_bag.size()==c.inputs.size());
50 for(
auto g: c.inputs) {
53 d.addWire(not_gate, gate);
55 negated_input_gate[g]=not_gate;
62 for(
const auto &p: result_gates) {
63 if(p.suspicious.empty() && p.valuation.find(root_id)->second) {
64 d.addWire(d.root, p.id);
106 for(
const auto &g: suspicious) {
132 {std::make_pair(single_gate,
true)},
136 {std::make_pair(single_gate,
false)},
139 return { std::move(pos), std::move(neg) };
144 for(
auto v: {
true,
false}) {
152 suspicious.
insert(single_gate);
154 result_gates.emplace_back(
157 std::move(suspicious)
168 for(
const auto &p1: valuation) {
169 for(
const auto &p2: valuation) {
170 if(p1.first==p2.first)
179 if(p1.second!=p2.second)
183 if(p1.second==p2.second)
202 for(
const auto &[g1,val]: valuation) {
203 if(innocent.
find(g1)!=innocent.
end())
215 for(
const auto &[g2, value]: valuation) {
239 for(
auto &[valuation, m]: gates_to_or) {
242 for(
auto &[var, val]: valuation) {
245 o <<
"(" << var <<
"," << val <<
")";
250 for(
auto &[innocent, gates]: m) {
253 for(
auto &x: innocent) {
262 for(
auto &x: gates) {
284 for(
auto g: children_gates) {
291 auto compatibleValuation = [&g](
const auto &p) {
292 for(
const auto &[var, val]: p.first) {
293 auto it = g.valuation.
find(var);
294 if(it != g.valuation.end() && it->second != val)
300 for (
auto it = std::find_if(partial.begin(), partial.end(), compatibleValuation);
302 it = std::find_if(std::next(it), partial.end(), compatibleValuation)) {
303 auto &[matching_valuation, m] = *it;
307 for(
auto &[var, val]: g.valuation) {
309 if(matching_valuation.find(var)==matching_valuation.end())
312 if(g.suspicious.find(var)==g.suspicious.end()) {
313 extra_innocent.
insert(var);
322 for(
auto &[innocent, gates]: m) {
325 for(
auto s: innocent)
328 new_innocent =
getInnocent(valuation, new_innocent);
331 gates_to_or[valuation][new_innocent].push_back(g.id);
333 for(
auto g2: gates) {
343 gates_children[nb++]=g.id;
347 gates_children[nb++]=g2;
360 and_gate = gates_children[0];
363 for(
auto x: gates_children) {
368 gates_to_or[valuation][new_innocent].push_back(and_gate);
383 struct RecursionParams
386 size_t children_processed;
390 bag(b), children_processed(c), gates_to_or(std::move(g)) {
393 RecursionParams(
bag_t b) :
394 bag(b), children_processed(0) {
395 gates_to_or_t::mapped_type m;
403 std::stack<std::variant<RecursionParams,RecursionResult> > stack;
404 stack.emplace(RecursionParams{
td.
root});
406 while(!stack.empty()) {
407 RecursionResult result;
409 if(stack.top().index()==1) {
410 result = std::move(std::get<1>(stack.top()));
416 auto [bag, children_processed, gates_to_or] = std::move(std::get<0>(stack.top()));
423 if(children_processed>0) {
430 for(
auto &[valuation, m]: gates_to_or) {
431 for(
auto &[innocent, gates]: m) {
434 assert(gates.size()!=0);
437 for(
auto &[var, val]: valuation)
438 if(innocent.
find(var)==innocent.
end())
442 result_gate = *gates.begin();
445 for(
auto &g: gates) {
450 result_gates.emplace_back(result_gate, std::move(valuation), std::move(suspicious));
454 stack.emplace(std::move(result_gates));
456 stack.emplace(RecursionParams{bag, children_processed+1, std::move(gates_to_or)});
457 stack.emplace(RecursionParams{
td.
getChildren(bag)[children_processed]});
475 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.
gate_t setGate(BooleanGate type) override
Allocate a new gate with type type and no UUID.
std::vector< gate_t > & getWires(gate_t g)
Return a mutable reference to the child-wire list of gate g.
gateType getGateType(gate_t g) const
Return the type of gate g.
void addWire(gate_t f, gate_t t)
Add a directed wire from gate f (parent) to gate t (child).
bag_t root
Identifier of the root bag.
Bag & getBag(bag_t b)
Mutable access to bag b.
std::vector< bag_t > & getChildren(bag_t b)
Mutable access to the children of bag b.
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.
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.
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.
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.
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.
void insert(P &&value)
Insert or update a key-value pair.
iterator begin()
Return iterator to the first element.
iterator end()
Return iterator past the last element.
size_t size() const
Return the number of elements in the set.
void insert(const K &value)
Insert value if not already present (const-ref overload).
iterator find(K &&k)
Find an element equal to k.