-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trusted Binary Decision Diagrams (Proof Generation) #435
Comments
tbdd
: Generating Extended Resolution Proofs within Adiar
Variable Sharing → Proof CompressionThe implementation described above makes no use of node sharing in any way at all. In parts, the proof has to retraverse the entire output anyway, since it has to create the correctness clauses (all the way from the bottom). Yet, if we can share proof variables between TBDDs, then we can mitigate some heavy blowup in the proof size. Yet, solving this seems quite difficult. Since we cannot know anything about the lifetimes of a TBDD, we cannot merely transfer the ownership from one TBDD to another, since the latter may be destructed before the former. |
tbdd
: Generating Extended Resolution Proofs within Adiar
While reading [FMCAD 22] on the TBuDDy implementation, it does not seem like the memory demands of the
References
|
A problem in SAT solving is trusting the solver when it claims a formula to be unsatisfiable. To this end, the solver can create an LRAT (or just a DRAT) proof. But, doing so is not a trivial task. Yet, BDDs naturally give rise to these very proofs, as is shown in [TACAS 21, arXiv 21] . The underlying idea is to store within each node the associated extension variable u and the four proof steps that encode the formula 'u <-> ITE(x,u1,u0)'.
This was added to a fork of the BuDDy BDD library, called TBuDDy. We want to add the same features to Adiar. The files tbdd.h and tbdd.cpp of TBuDDy might be useful reference material.
API
Proof Output
In TBuDDy, the user specifies the desired proof format and output file as part of a
tbdd_init
function (which also initialises BuDDy itself). We can do the same. But, I would prefer if we somehow could support multiple output files at once (thinking of later concurrent/thread-safe usages of Adiar). For thread-safety we might want to take a note or two from theexec_policy
design (#548)tbdd_ostream
class to handle outputting the proof steps (LRAT or DRAT), create fresh variables, and create the clause identifiers.tbdd_clause
andtbdd_validate
below) has the output stream as its last argument (default: global proof_writer).tbdd_ostream
in question needs to have a write-lock (using RAII).TBDD Operations
The TBDD u for the input CNF clause with the given id.
This is similar to
bdd_or
( with Extendbdd_and
andbdd_or
with negation flags #556 ) and adds the associated proof of Cid |= u. In TBuDDy this is thetbdd_create(bdd f, clause_id i)
function. That is, we may consider to just usebdd_and(xs)
and then convert it into atbdd
afterwards.This may need an (optional?) last argument for a shared
proof_writer
.The TBDD w for u∧v with the associated proof that u∧v → w.
tbdd tbdd_and(tbdd u, tbdd v);
Also add
&
and&=
overloadsUpgrades f to a TBDD u' by proving that u → u'.
tbdd tbdd_validate(tbdd u, bdd f);
This may need an (optional?) last argument for a shared
proof_writer
.TBDD Information
Next to
tbdd_clause(xs, id)
to create a clause, we may also want the following basic building blocks:The tautological clause (reuse
bdd_top
)This may need an (optional?) last argument for a shared
proof_writer
.We should also bring over the following predicates and accessors from
bdd
( together with #536 ).Whether a TBDD is a tautology (reuse
bdd_istrue
)Whether a TBDD is a contradiction (reuse
bdd_isfalse
)Whether a TBDD is a single literal (reuse
bdd_isvar
)Whether a TBDD is a positive literal (reuse
bdd_isithvar
)Whether a TBDD is a negative literal (reuse
bdd_isnithvar
)Finally, for debugging and statistics we also need
The number of BDD nodes in the TBDD (reuse
bdd_nodecount
)The number of Literals (i.e. the number of levels) present in the TBDD (reuse
bdd_varcount
)Print the underlying BDD to a file (reuse
bdd_printdot
but maybe the output should also include the proof variables? If so, then this may not be trivial)Other TBDD Operations (not mandatory)
In [CADE 2021], more operations are described. Here, they use the proof system to both proof a formula to be true and to be false (since that is necessary for QBF problems). What we have noted above for
tbdd_and(u, v)
is only the truth preserving version. See [CADE 21] for more details.The TBDD w for u∨v with the associated (thruth preserving) proof that u → w and v → w.
tbdd tbdd_or(tbdd u, tbdd v);
Also add
|
and|=
overloadsThe TBDD w for u∧l where l is a single literal. This creates the associated (truth preserving) proof of w∧l → u.
The TBDD w for ∃x : u.
In [CADE 21] this is just the combination of
tbdd_restrict
andtbdd_or
. Yet, one should be able to (1) combine it into a single quantification sweep for each literal and then maybe (2) incorporate multiple literals at once.The TBDD w for ∀x : u.
Use
tbdd_restrict
andtbdd_and
together. Similar totbdd_exists
, future work would be to improve performance with a dedicated quantification algorithm.tbdd_and
(Manipulation Algorithms)I'll focus on
tbdd_and
for now...Since the proof steps are built bottom-up most of the work happens in the Reduce Sweep - the preceding top-down sweep only needs to be extended such that it also stores the relevant association between nodes and proof variables.
Top-Down Sweeps
During the top-down sweep, forward a mapping between the nodes of the unreduced intermediate output and the original nodes (and/or their variables).
Algorithmic Extension
nested_sweep
).Reduce Sweep
Preliminaries
The end-goal is to describe each BDD node u = (x, u[0], u[1]) as the following four clauses that collectively encode u↔(x ? u[1] : u[0]).
Here, the L and H respectively are abbreviations for Low and High edges. The U is Up and D is Down (with respect to the direction of the implication). Notice, this perfectly fits with the information flow of the Reduce algorithm.
After having defined the BDD node in the proof, we also want to prove that it is the correct result. To this end, we need to combine the defining clauses of original BDD nodes u, v, and the resulting BDD node w.
Next to these six clauses we also need the following clauses that claim they correspond to the and of u and v.
Knowing the clause id of all eight of these, we can combine them into two RUP resolution chains that can be combined to proof -u -v w, i.e. u∧v→w.
Algorithmic Extension
Again, we should be able to implement the above by the addition of hooks to a stateful reduce_policy. Alternatively, if this becomes too messy/expensive, then we may want to just implement a separate
tbdd_reduce
. The four places the algorithm needs to be extended is:Node w is suppressed:
Store this down together, similar to the
red1_mapping
.Outputting new node w as w':
Push LD(w'), LU(w'), HD(w'), and HU(w') to the proof and push their ids to the clause id file. Furthermore, push the clause id into a
red2_mapping
sorter that puts it back in order with w. Here, weOutputting duplicate node w as w':
Also place this mapping in the
red2_mapping
clause sorter.With all of the defining clauses of w' available, we now only need to combine them with the input's clauses. Yet, to do so it needs to back in the order of the unreduced product graph. Hence, we need the clause variants of
red1_mapping
andred2_mapping
. Finally, knowing all of the relevant clauses and having identified the proof case in question, we can output the proofs during the last hook:Here, we need to provide the identifiers for the defining and correctness proving clauses of w'. These then need to be forwarded to their parents.
For all of this, the priority queue needs to be extended with w[_] and the clause proving their correctness (this is akin to #412).
tbdd_validate
(Validation Algorithm)This follows the above described idea for
tbdd_and
To make this faster, we would want the proof to relate to the BDD nodes of f rather than to new TBDD nodes of u' (since we then can reuse the node file for f). To do so, we should create a custom
tbdd_reduce
which does not output any new nodes and skips all of the computations to apply reduction rules. Instead, it traverses the transposed version of f, declares new variables for u', and proves it correct with the clauses of u.Architecture
tbdd
classtbdd
tobdd
should be trivial (since we may want to do some BDD operations, e.g.bdd_exists
, and then get back to TBDDs withtbdd_validate
). That is, it should merely be forgetting the associated variables. Hence, extension variables should not be included in thenode
orlevelized_file<node>
class but be placed in a separate file with the associated proof steps. In fact, we would wanttbdd
to inherit from thebdd
class.tbdd
destructor output a delete of all its extension variables. Hence, eachtbdd
needs to carry around a reference to their proof writer (assuming there is not only one).__tbdd
class (at least in the public API). To safe a little bit of disk space, we can also move the clause file(s) from the input into__tbdd
.tbdd_reduce
Add the hooks and logic described above.
tbdd_and
Add the hooks and logic described above.
tbdd_validate
Implement
tbdd_validate__down
andtbdd_validate__up
as described above.References
[TACAS 21] Randal E. Bryant and Marijn J. H. Heule. “Generating extended resolution proofs with a BDD-based SAT solver”. In: Tools and Algorithms for the Construction and Analysis of Systems (2021)
[arXiv 21] Randal E. Bryant and Marijn J. H. Heule. “Generating extended resolution proofs with a BDD-based SAT solver (extended version)”. In: arXiv Preprint (2021)
[CADE 21] Randal E. Bryant and Marijn J. H. Heule. “Dual Proof Generation for Quantified Boolean Formulas with a BDD-based Solver”. In: International Conference on Automated Deduction (2021)
The text was updated successfully, but these errors were encountered: