Sound checking of the RUP fragment of LRAT certificates #
rupCheck checks reverse unit propagation along supplied clause indices.
checkStepsWith checks a sequence of such additions and requires an empty clause.
unsat_of_checkSteps proves that acceptance implies unsatisfiability of the input CNF.
External solvers supply certificates; their correctness is unnecessary for this theorem.
ClauseDB abstracts lookup, append and initialization together with the membership laws
consumed by soundness. Both the array and balanced-tree implementations prove those laws.
The theorem covers RUP additions, not general RAT additions. Concrete certificate data
and upstream performance experiments are outside this import.
A zero-based variable index and its polarity.
Equations
Instances For
A disjunction of literals.
Instances For
A conjunction of clauses.
Instances For
A total Boolean assignment.
Equations
Instances For
Literals asserted true by a partial assignment.
Instances For
A CNF is satisfied by an assignment.
Equations
- QECCertificates.LRAT.SatFormula σ F = ∀ (C : QECCertificates.LRAT.Clause), C ∈ F → QECCertificates.LRAT.SatClause σ C
Instances For
The CNF is satisfiable.
Equations
Instances For
The partial assignment a agrees with the total assignment σ.
Equations
- QECCertificates.LRAT.agrees σ a = ∀ (l : QECCertificates.LRAT.Lit), l ∈ a → σ l.fst = l.snd
Instances For
The literal is not known false: its negation is absent from the partial assignment.
Equations
Instances For
1. Scanning a clause #
Collect literals not known false, accumulating them in reverse order.
Equations
- QECCertificates.LRAT.scanAux a fr [] = fr
- QECCertificates.LRAT.scanAux a fr (l :: rest) = if QECCertificates.LRAT.litFree a l = true then QECCertificates.LRAT.scanAux a (l :: fr) rest else QECCertificates.LRAT.scanAux a fr rest
Instances For
Scan a clause: return the list of its literals not known false under the current assignment. Emptiness means "all false", a conflict, and a singleton means "exactly one free literal", a unit step.
Equations
Instances For
2. The clause database interface #
Kernel replay uses only four operations of the database, namely lookup, length,
append and build, and three laws. Changing the representation, from Array to a
balanced tree, is therefore an instantiation, not a re-proof of a load-bearing
module.
The representation matters for kernel reduction: array accesses and appends can repeatedly traverse prior entries, whereas balanced trees avoid that pattern. Both implementations below satisfy the same soundness interface. Concrete replay datasets and upstream benchmarks are outside this import.
The clause database interface: rupCheck and checkAux use only these four
operations and three laws.
Look up a clause at a zero-based index.
- size : Carrier → ℕ
The index at which the next clause is appended.
- push : Carrier → Clause → Carrier
Append a clause to the database.
Semantic membership of a clause in the database.
A clause that is looked up is certainly in the database.
After one append, every clause in the database is either the new one or was already there. Only the half that soundness needs is required:
checkAux_soundconsumes this direction only, while the missing converse,C' = C ∨ Mem d C' → Mem (push d C) C', is exactly where a balanced-tree instance needs the invariant "key < size". Stating the laws at the strength that is used keeps both instances clean.- ofCNF : CNF → Carrier
Build a database from a CNF.
Every clause of the initial database comes from that CNF, again only the half that is used.
Instances For
The clause database represented by an array.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Membership for the tree database: C is the value at some key.
Factored out into a separate def: writing Mem inside the structure literal would
resolve to the structure projection ClauseDB.Mem, which takes the structure itself as
its first argument, so Mem d C would expect a ClauseDB as its first argument.
Instances For
The balanced-tree version: each lookup and insertion is $O(\log n)$ in the
kernel, so the whole certificate accumulates logarithmically rather than quadratically as
with Array. The key is the clause number minus one, 0-based, and push appends at
size.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Unit propagation along the hint sequence. h is a 1-based clause number.
Equations
- One or more equations did not get rendered due to their size.
- QECCertificates.LRAT.rupAux D d a [] = false
Instances For
The clause C is RUP with respect to the database d: negating C and propagating
along hints reaches a conflict.
Equations
- QECCertificates.LRAT.rupCheck D d C hints = QECCertificates.LRAT.rupAux D d (List.map QECCertificates.LRAT.litNeg C) hints
Instances For
3. The certificate checking layer #
Checking with a given representation: build the database from the CNF via
D.ofCNF, then check the steps one by one.
Equations
- QECCertificates.LRAT.checkStepsWith D F steps = QECCertificates.LRAT.checkAux D (D.ofCNF F) steps
Instances For
The entry point, with the verbatim signature from before the interface was
opened: it uses the Array database, so the two downstream data modules are
unaffected.
Equations
Instances For
The main theorem, entry point: a successful kernel check implies that the CNF is unsatisfiable.
The entry point used by the generator: the same content as checkSteps_sound, as a
proof term.