Included Books
other
(in-package "ACL2")
include-book
(include-book "xdoc/top" :dir :system)
other
(defxdoc non-case-splitting-logic :parents (boolean-reasoning) :short "Boolean connectives that avoid case splits." :long "<p>Perhaps the most common reason that ACL2 proofs take a long time is that they split into too many cases unnecessarily. The alternative Boolean operators @('iff*'), @('and*'), @('or*'), @('xor*'), and @('if*') can help to avoid such case splits.</p> <p>A small and abstract example: Suppose foo is a function that has the following shape:</p> @({ (defun foo (...) (cond (<exceptional-case1> ...) (<exceptional-case2> ...) ... (<exceptional-casen> ...) (t ...))) ;; default case }) <p>And suppose that each of the N exceptional cases is a conjunction of M subterms. How many cases will ACL2 typically split into in order to prove something about foo?</p> <p>The answer is on the order of @('M^N'). You can get the exact number via the following recurrence:</p> @({ (defun number-of-cases (n m) (if (zp n) 1 (+ 1 (* m (number-of-cases (- n 1) m))))) }) <p>This is because for each conjunction @('(and a b c') that may cause an exceptional case, ACL2 considers the cases:</p> @({ (not a) (and a (not b)) (and a b (not c)) (and a b c) }) <p>In the first three cases, the conjunction is not true (this is where the @('* m') in the recurrence comes from), and in the last case it is true (this is where the @('+ 1') in the recurrence comes from).</p> <p>This is where the alternative operators come in. If we replace the conjunctions above with @('and*') calls, then instead of splitting into @('M^N') cases, we split into @('N+1') cases! This usually works because when we are in case K, we care that the conjuncts of @('<exceptional-casek>') were true, but usually not which of the conjuncts of @('<exceptional-case0>') through @('exceptional-casek-1') were untrue.</p> ")
other
(defsection iff* :parents (non-case-splitting-logic) :short "Non-case-splitting version of IFF." (defund iff* (x y) (iff x y)) (local (in-theory (enable iff*))) (defequiv iff*) (defrefinement iff iff*) (defrefinement iff* iff) (defthm iff*-of-nonnils (implies (and x y) (equal (iff* x y) t)) :rule-classes ((:rewrite :backchain-limit-lst 0))) (defthm iff*-with-nil (and (equal (iff* x nil) (not x)) (equal (iff* nil x) (not x)))) (defthm iff*-when-other (implies y (and (iff (iff* x y) x) (iff (iff* y x) x)))))
other
(defsection xor* :parents (non-case-splitting-logic) :short "Non-case-splitting version of XOR." (defund xor* (x y) (xor x y)) (local (in-theory (enable xor*))) (defcong iff equal (xor* x y) 1) (defcong iff equal (xor* x y) 2) (defthm xor*-of-nonnils (implies (and x y) (equal (xor* x y) nil)) :rule-classes ((:rewrite :backchain-limit-lst 0))) (defthm xor*-with-nil (and (iff (xor* x nil) x) (iff (xor* nil x) x))) (defthm xor*-when-other (implies y (and (equal (xor* x y) (not x)) (equal (xor* y x) (not x))))))
other
(defsection and* :parents (non-case-splitting-logic) :short "Non-case-splitting version of AND." (defun binary-and* (a b) (declare (xargs :guard t)) (and a b)) (defun and*-macro (lst) (if (atom lst) t (if (atom (cdr lst)) (car lst) (list 'binary-and* (car lst) (and*-macro (cdr lst)))))) (defmacro and* (&rest lst) (and*-macro lst)) (add-binop and* binary-and*) (defcong iff equal (and* a b) 1) (defcong iff iff (and* a b) 2) (defthm and*-rem-first (implies a (equal (and* a b) b))) (defthm and*-rem-second (implies b (iff (and* a b) a))) (defthm and*-nil-first (equal (and* nil b) nil)) (defthm and*-nil-second (equal (and* a nil) nil)) (defthm and*-forward (implies (and* a b) (and a b)) :rule-classes :forward-chaining) (defmacro and** (&rest lst) `(mbe :logic (and* . ,LST) :exec (and . ,LST))) (in-theory (disable and*)))
other
(defsection or* :parents (non-case-splitting-logic) :short "Non-case-splitting version of OR." (defun binary-or* (a b) (declare (xargs :guard t)) (or a b)) (defun or*-macro (lst) (if (atom lst) nil (if (atom (cdr lst)) (car lst) (list 'binary-or* (car lst) (or*-macro (cdr lst)))))) (defmacro or* (&rest lst) (or*-macro lst)) (add-binop or* binary-or*) (defcong iff iff (or* a b) 1) (defcong iff iff (or* a b) 2) (defthm or*-true-first (implies a (equal (or* a b) a))) (defthm or*-true-second (implies b (or* a b))) (defthm or*-nil-first (equal (or* nil b) b)) (defthm or*-nil-second (equal (or* a nil) a)) (defthm or*-forward (implies (or* a b) (or a b)) :rule-classes :forward-chaining) (defmacro or** (&rest lst) `(mbe :logic (or* . ,LST) :exec (or . ,LST))) (in-theory (disable or*)))