other
(in-package "SATLINK")
other
(include-book "varp")
other
(include-book "litp")
other
(include-book "std/stobjs/clone" :dir :system)
other
(include-book "std/stobjs/bitarr" :dir :system)
other
(local (include-book "data-structures/list-defthms" :dir :system))
other
(local (add-default-post-define-hook :fix))
other
(defsection env$ :parents (cnf) :short "A bit array that serves as the environment for @(see eval-formula)." (defstobj-clone env$ bitarr :exports (env$-length env$-get env$-set env$-resize)))
other
(defxdoc cnf :parents (satlink) :short "Our representation (syntax and semantics) for <a href='http://en.wikipedia.org/wiki/Conjunctive_normal_form'>conjunctive normal form</a> formulas." :long "<p>To express what it means to call a SAT solver, we need a representation and a semantics for Boolean formulas in conjunctive normal form. Our syntax is as follows:</p> <ul> <li>A <b>variable</b> is a natural number. To help keep variables separate from literals, we represent them @(see varp)s, instead of @(see natp)s.</li> <li>A <b>literal</b> represents either a variable or a negated variable. We represent these using a typical numeric encoding: the least significant bit is the negated bit, and the remaining bits are the variable. See @(see litp).</li> <li>A <b>clause</b> is a disjunction of literals. We represent these as ordinary lists of literals. See @(see lit-listp).</li> <li>A <b>formula</b> is a conjunction of clauses. We represent these using @(see lit-list-listp).</li> </ul> <p>The semantics of these formulas are given by @(see eval-formula).</p>")
other
(define eval-var ((var varp) env$) :returns (bit bitp) :inline t (mbe :logic (get-bit (var-fix var) env$) :exec (if (< (the (integer 0 *) var) (the (integer 0 *) (bits-length env$))) (get-bit var env$) 0)))
other
(define eval-lit ((lit litp) env$) :returns (bit bitp) (b-xor (lit->neg lit) (eval-var (lit->var lit) env$)))
other
(define eval-clause ((clause lit-listp) env$) :returns (bit bitp) (if (atom clause) 0 (mbe :logic (b-ior (eval-lit (car clause) env$) (eval-clause (cdr clause) env$)) :exec (if (bit->bool (eval-lit (car clause) env$)) 1 (eval-clause (cdr clause) env$)))))
other
(define eval-formula :parents (cnf) :short "Semantics of CNF formulas." ((formula lit-list-listp) env$) :returns (bit bitp) :long "<p>We define a simple evaluator for CNF formulas that uses an environment to assign values to the identifiers.</p> <p>The environment, @(see env$), is an abstract stobj that implements a simple bit array. Our evaluators produce a <b>BIT</b> (i.e., 0 or 1) instead of a BOOL (i.e., T or NIL) to make it directly compatible with the bitarr stobj.</p>" (if (atom formula) 1 (mbe :logic (b-and (eval-clause (car formula) env$) (eval-formula (cdr formula) env$)) :exec (if (bit->bool (eval-clause (car formula) env$)) (eval-formula (cdr formula) env$) 0))))
other
(define eval-cube ((cube lit-listp) env$) :returns (bit bitp) (if (atom cube) 1 (mbe :logic (b-and (eval-lit (car cube) env$) (eval-cube (cdr cube) env$)) :exec (if (bit->bool (eval-lit (car cube) env$)) (eval-cube (cdr cube) env$) 0))))
other
(define fast-max-index-clause ((clause lit-listp) (max natp)) :parents (max-index-clause) :short "Tail-recursive version of @(see max-index-clause)." (b* (((when (atom clause)) (lnfix max)) (id1 (lit->var (car clause))) (max (max (lnfix max) id1))) (fast-max-index-clause (cdr clause) max)))
other
(define max-index-clause ((clause lit-listp)) :returns (max natp :rule-classes :type-prescription) :parents (cnf) :short "Maximum index of any identifier used anywhere in a clause." :verify-guards nil (mbe :logic (if (atom clause) 0 (max (lit->var (car clause)) (max-index-clause (cdr clause)))) :exec (fast-max-index-clause clause 0)) /// (defthm fast-max-index-clause-removal (equal (fast-max-index-clause clause max) (max (nfix max) (max-index-clause clause))) :hints (("Goal" :in-theory (enable fast-max-index-clause)))) (verify-guards max-index-clause))
other
(define fast-max-index-formula ((formula lit-list-listp) (max natp)) :parents (max-index-formula) :short "Tail recursive version of @(see max-index-formula)." (b* (((when (atom formula)) (lnfix max)) (max (fast-max-index-clause (car formula) max))) (fast-max-index-formula (cdr formula) max)))
other
(define max-index-formula ((formula lit-list-listp)) :returns (max natp :rule-classes :type-prescription) :parents (cnf) :short "Maximum index of any identifier used anywhere in a formula." :verify-guards nil (mbe :logic (if (atom formula) 0 (max (max-index-clause (car formula)) (max-index-formula (cdr formula)))) :exec (fast-max-index-formula formula 0)) /// (defthm fast-max-index-formula-removal (equal (fast-max-index-formula formula max) (max (nfix max) (max-index-formula formula))) :hints (("Goal" :in-theory (enable fast-max-index-formula)))) (verify-guards max-index-formula))
other
(define clause-indices ((clause lit-listp)) :parents (cnf) :short "Collect indices of all identifiers used throughout a clause." (if (atom clause) nil (cons (lit->var (car clause)) (clause-indices (cdr clause)))) /// (defthm clause-indices-when-atom (implies (atom clause) (equal (clause-indices clause) nil))) (defthm clause-indices-of-cons (equal (clause-indices (cons lit clause)) (cons (lit->var lit) (clause-indices clause)))))
other
(define formula-indices ((formula lit-list-listp)) :parents (cnf) :short "Collect indices of all identifiers used throughout a formula." (if (atom formula) nil (append (clause-indices (car formula)) (formula-indices (cdr formula)))) /// (defthm formula-indices-when-atom (implies (atom formula) (equal (formula-indices formula) nil))) (defthm formula-indices-of-cons (equal (formula-indices (cons clause formula)) (append (clause-indices clause) (formula-indices formula)))))
other
(defstobj-clone assums$
bitarr
:exports (assums$-length assums$-get
assums$-set
assums$-resize))
other
(define lit-assumedp ((lit litp) assums$) :guard (< (+ 1 (* 2 (lit->var lit))) (bits-length assums$)) :guard-hints ('(:use ((:instance lit-fix-bound-by-lit->var (x lit)))) (and stable-under-simplificationp '(:in-theory (enable lit-val litp)))) (eql 1 (get-bit (lit-fix lit) assums$)))
other
(define lit-assume ((lit litp) assums$) :guard (< (+ 1 (* 2 (lit->var lit))) (bits-length assums$)) :guard-hints ('(:use ((:instance lit-fix-bound-by-lit->var (x lit)))) (and stable-under-simplificationp '(:in-theory (enable litp)))) (set-bit (mbe :logic (lit-fix lit) :exec lit) 1 assums$) /// (defthm lit-assumedp-of-lit-assume (equal (lit-assumedp lit1 (lit-assume lit assums$)) (if (lit-equiv lit1 lit) t (lit-assumedp lit1 assums$))) :hints (("Goal" :in-theory (enable lit-assumedp)))) (defthm len-of-lit-assume (<= (len assums$) (len (lit-assume lit assums$))) :rule-classes :linear))
other
(defun-sk env-satisfies-assums
(env$ assums$)
(forall var
(and (implies (lit-assumedp (make-lit var 0)
assums$)
(equal (eval-var var env$) 1))
(implies (lit-assumedp (make-lit var 1)
assums$)
(equal (eval-var var env$) 0))))
:rewrite :direct)
other
(in-theory (disable env-satisfies-assums))
other
(defthm env-satisfies-assums-implies-lit-eval (implies (and (env-satisfies-assums env$ assums$) (lit-assumedp lit assums$)) (equal (eval-lit lit env$) 1)) :hints (("goal" :use ((:instance env-satisfies-assums-necc (var (lit->var lit))) (:instance make-lit-identity)) :in-theory (e/d (eval-lit) (make-lit-identity equal-of-lit-fix-backchain)))))
other
(defthm env-satisfies-assums-implies-not-lit-eval (implies (and (env-satisfies-assums env$ assums$) (lit-assumedp (lit-negate lit) assums$)) (equal (eval-lit lit env$) 0)) :hints (("goal" :use ((:instance env-satisfies-assums-necc (var (lit->var lit))) (:instance make-lit-identity)) :in-theory (e/d (eval-lit lit-negate) (make-lit-identity equal-of-lit-fix-backchain equal-of-make-lit)))))
other
(defthm lit-assumedp-of-opposite-when-env-satisfies (implies (and (lit-assumedp (lit-negate lit) assums$) (env-satisfies-assums env$ assums$)) (not (lit-assumedp lit assums$))) :hints (("goal" :use ((:instance env-satisfies-assums-implies-lit-eval) (:instance env-satisfies-assums-implies-not-lit-eval)) :in-theory (disable env-satisfies-assums-implies-not-lit-eval env-satisfies-assums-implies-lit-eval))))
other
(defthm equal-var-fix-forward (implies (equal (var-fix x) y) (var-equiv x y)) :rule-classes :forward-chaining)
other
(defthm equal-var-fix-forward2 (implies (equal y (var-fix x)) (var-equiv x y)) :rule-classes :forward-chaining)
other
(defthm env-satisfies-assums-of-lit-assume (iff (env-satisfies-assums env$ (lit-assume lit assums$)) (and (equal 1 (eval-lit lit env$)) (env-satisfies-assums env$ assums$))) :hints ((and stable-under-simplificationp (b* ((lit (assoc 'env-satisfies-assums clause))) `(:expand (,SATLINK::LIT) :in-theory (enable eval-lit equal-of-make-lit)))) (and stable-under-simplificationp '(:use ((:instance lit-assumedp-of-opposite-when-env-satisfies (assums$ (lit-assume lit assums$)) (lit (make-lit (env-satisfies-assums-witness env$ assums$) 0)))) :in-theory (disable lit-assumedp-of-opposite-when-env-satisfies)))))
other
(defthm env-satisfies-assums-of-empty-assums (env-satisfies-assums env$ (resize-list nil size 0)) :hints (("Goal" :in-theory (e/d (env-satisfies-assums lit-assumedp nth-of-resize-list-split) (resize-list-when-empty)) :do-not-induct t)))
other
(define clause-unsat-under-assums ((clause lit-listp) (assums$)) :guard (< (+ 1 (* 2 (max-index-clause clause))) (bits-length assums$)) :guard-hints (("goal" :expand ((max-index-clause clause)))) :returns (unsatp) (b* (((when (atom clause)) t) (lit (car clause))) (and (lit-assumedp (lit-negate lit) assums$) (clause-unsat-under-assums (cdr clause) assums$))) /// (defthm clause-unsat-under-assums-not-true-when-satisfied (implies (and (env-satisfies-assums env$ assums$) (equal (eval-clause clause env$) 1)) (not (clause-unsat-under-assums clause assums$))) :hints (("Goal" :in-theory (enable eval-clause)))))
other
(define clause-unit-under-assums ((clause lit-listp) (assums$)) :returns (mv (final-possibles natp :rule-classes :type-prescription "0 for unsat, 1 for unit, 2 otherwise") (unit-lit (implies (equal 1 final-possibles) (litp unit-lit)))) :guard (< (+ 1 (* 2 (max-index-clause clause))) (bits-length assums$)) :guard-hints (("goal" :expand ((max-index-clause clause)))) (b* (((when (atom clause)) (mv 0 nil)) (lit (car clause)) (falsep (lit-assumedp (lit-negate lit) assums$)) ((when falsep) (clause-unit-under-assums (cdr clause) assums$)) ((when (clause-unsat-under-assums (cdr clause) assums$)) (mv 1 (lit-fix lit)))) (mv 2 nil)) /// (defret clause-unit-under-assums-0-implies-unsat (implies (and (env-satisfies-assums env$ assums$) (equal 1 (eval-clause clause env$))) (not (equal 0 final-possibles))) :hints (("Goal" :in-theory (enable eval-clause)))) (defret clause-unit-under-assums-1-implies-unit (implies (and (env-satisfies-assums env$ assums$) (equal 1 (eval-clause clause env$)) (equal 1 final-possibles)) (equal (eval-lit unit-lit env$) 1)) :hints (("Goal" :in-theory (enable eval-clause)))) (defret clause-unit-under-assums-unit-lit-implies-in-bounds (implies (equal final-possibles 1) (<= (lit->var unit-lit) (max-index-clause clause))) :hints (("Goal" :in-theory (enable max-index-clause))) :rule-classes :linear))
other
(define trivial-unsat-p1 ((formula lit-list-listp) (assums$)) :returns (mv unsat-p new-assums$) :guard (< (+ 1 (* 2 (max-index-formula formula))) (bits-length assums$)) :guard-hints (("goal" :expand ((max-index-formula formula)))) (b* (((when (atom formula)) (mv nil assums$)) ((mv status unit-lit) (clause-unit-under-assums (car formula) assums$)) ((when (eql status 0)) (mv t assums$)) ((unless (eql status 1)) (trivial-unsat-p1 (cdr formula) assums$)) (assums$ (lit-assume unit-lit assums$))) (trivial-unsat-p1 (cdr formula) assums$)) /// (defret trivial-unsat-p1-correct (implies (and (not (equal (eval-formula formula env$) 0)) (env-satisfies-assums env$ assums$)) (not unsat-p)) :hints (("Goal" :in-theory (enable eval-formula)))))
other
(define trivial-unsat-p ((formula lit-list-listp)) :returns unsat-p (b* (((local-stobjs assums$) (mv unsat-p assums$)) (max-index (max-index-formula formula)) (assums$ (resize-bits (+ 2 (* 2 max-index)) assums$))) (trivial-unsat-p1 formula assums$)) /// (defretd trivial-unsat-p-correct (implies unsat-p (equal (eval-formula formula env$) 0)) :hints (("Goal" :in-theory (disable resize-list-when-empty)))))