Proving Theorems about
Proving theorems about
With these points in mind we will now work through a proof about a fancy
Sample Question: Define the function
Sample Solution (as a narrative of the discovery).
As usual, we make sure we're operating in a session where
(include-book "projects/apply/top" :dir :system)
We will construct our pairs with
(defun make-pair (i j) (declare (xargs :guard t)) (cons i j))
Here is our recursive definition. It involves two helper functions.
(defun all-pairs-helper2 (i j jmax) (declare (xargs :measure (nfix (- (+ (nfix jmax) 1) (nfix j))) :guard (and (natp i) (natp j) (natp jmax)))) (let ((j (nfix j)) (jmax (nfix jmax))) (cond ((> j jmax) nil) (t (cons (make-pair i j) (all-pairs-helper2 i (+ 1 j) jmax)))))) (defun all-pairs-helper1 (i imax jmax) (declare (xargs :measure (nfix (- (+ (nfix imax) 1) (nfix i))) :guard (and (natp i) (natp imax) (natp jmax)))) (let ((i (nfix i)) (imax (nfix imax))) (cond ((> i imax) nil) (t (append (all-pairs-helper2 i 1 jmax) (all-pairs-helper1 (+ 1 i) imax jmax)))))) (defun all-pairs (imax jmax) (declare (xargs :guard (and (natp imax) (natp jmax)))) (all-pairs-helper1 1 imax jmax))
Here is a simple test.
ACL2 !>(all-pairs 2 4) ((1 . 1) (1 . 2) (1 . 3) (1 . 4) (2 . 1) (2 . 2) (2 . 3) (2 . 4))
And here is our first attempt to define the
(defun all-pairs-loop$ (imax jmax) (declare (xargs :guard (and (natp imax) (natp jmax)))) (loop$ for i from 1 to imax append (loop$ for j from 1 to jmax collect (make-pair i j))))) ACL2 Error [Translate] in ( DEFUN ALL-PAIRS-LOOP$ ...): The body of a LAMBDA object, lambda$ term, or loop$ statement should be fully badged but MAKE-PAIR is used in ((LAMBDA (I J) (MAKE-PAIR I J)) (CAR LOOP$-GVARS) (CAR LOOP$-IVARS)) and has no badge. ... ... Note: this error occurred in the context (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (DECLARE (XARGS :GUARD (AND (TRUE-LISTP LOOP$-GVARS) (EQUAL # 1) (TRUE-LISTP LOOP$-IVARS) (EQUAL # 1)))) (LET ((I (CAR LOOP$-GVARS)) (J (CAR LOOP$-IVARS))) (DECLARE (IGNORABLE I J)) (MAKE-PAIR I J))).
The error message above includes some extraneous possible explanation of the error which we've omitted.
The error tells us we forgot to assign a badge to
(defwarrant make-pair)
(Had we just badged
Trying the
(defun all-pairs-loop$ (imax jmax) (declare (xargs :guard (and (natp imax) (natp jmax)))) (loop$ for i from 1 to imax append (loop$ for j from 1 to jmax collect (make-pair i j))))) *** Key checkpoint at the top level: *** Subgoal 1.2' (IMPLIES (AND (CONSP LOOP$-IVARS) (NOT (CDR LOOP$-IVARS)) (CONSP LOOP$-GVARS) (NOT (CDR LOOP$-GVARS))) (INTEGERP (CAR LOOP$-GVARS))) ACL2 Error [Failure] in ( DEFUN ALL-PAIRS-LOOP$ ...): The proof of the guard conjecture for ALL-PAIRS-LOOP$ has failed; see the discussion above about :VERIFY-GUARDS and :GUARD-DEBUG. See :DOC failure.
We need to prove, as part of the guard verification, that
We do not recommend using
(Note: We have manually inserted some comments to identify certain lines of the display below.)
ACL2 !>:tca (loop$ for i from 1 to imax append (loop$ for j from 1 to jmax collect (make-pair i j))) (PROG2$ '(LOOP$ FOR I FROM 1 TO IMAX APPEND (LOOP$ FOR J FROM 1 TO JMAX COLLECT (MAKE-PAIR I J))) (APPEND$+ ; [0] (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) ; [1] (DECLARE (XARGS :GUARD (AND (TRUE-LISTP LOOP$-GVARS) ; [2] (EQUAL (LEN LOOP$-GVARS) 1) (TRUE-LISTP LOOP$-IVARS) (EQUAL (LEN LOOP$-IVARS) 1)) :SPLIT-TYPES T)) (LET ((JMAX (CAR LOOP$-GVARS)) ; [3] (I (CAR LOOP$-IVARS))) (PROG2$ '(LOOP$ FOR J FROM 1 TO JMAX COLLECT (MAKE-PAIR I J)) (COLLECT$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (DECLARE (XARGS :GUARD (AND (TRUE-LISTP LOOP$-GVARS) (EQUAL (LEN LOOP$-GVARS) 1) (TRUE-LISTP LOOP$-IVARS) (EQUAL (LEN LOOP$-IVARS) 1)) :SPLIT-TYPES T)) (LET ((I (CAR LOOP$-GVARS)) (J (CAR LOOP$-IVARS))) (MAKE-PAIR I J))) (LIST I) (LOOP$-AS (LIST (FROM-TO-BY 1 JMAX 1))))))) ; [4] (LIST JMAX) ; [5] (LOOP$-AS (LIST (FROM-TO-BY 1 IMAX 1))))) ; [6]
We're trying to verify the guards all the functions in that expression,
and we have the
So what functions above require an argument to be an integer? Hint: There is only one such function but it occurs in two places.
The
So how do we change the
Using
ACL2 !>:tca (loop$ for i from 1 to imax append :guard (natp jmax) ; [new] (loop$ for j from 1 to jmax collect (make-pair i j))) (PROG2$ '(LOOP$ FOR I FROM 1 TO IMAX APPEND (LOOP$ FOR J FROM 1 TO JMAX COLLECT (MAKE-PAIR I J))) (APPEND$+ ; [0] (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) ; [1] (DECLARE (XARGS :GUARD (AND (TRUE-LISTP LOOP$-GVARS) ; [2'] (EQUAL (LEN LOOP$-GVARS) 1) (TRUE-LISTP LOOP$-IVARS) (EQUAL (LEN LOOP$-IVARS) 1) (NATP (CAR LOOP$-GVARS))) ; [new] :SPLIT-TYPES T)) (LET ((JMAX (CAR LOOP$-GVARS)) ; [3] (I (CAR LOOP$-IVARS))) (PROG2$ '(LOOP$ FOR J FROM 1 TO JMAX COLLECT (MAKE-PAIR I J)) (COLLECT$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (DECLARE (XARGS :GUARD (AND (TRUE-LISTP LOOP$-GVARS) (EQUAL (LEN LOOP$-GVARS) 1) (TRUE-LISTP LOOP$-IVARS) (EQUAL (LEN LOOP$-IVARS) 1)) :SPLIT-TYPES T)) (LET ((I (CAR LOOP$-GVARS)) (J (CAR LOOP$-IVARS))) (MAKE-PAIR I J))) (LIST I) (LOOP$-AS (LIST (FROM-TO-BY 1 JMAX 1))))))) ; [4] (LIST JMAX) ; [5] (LOOP$-AS (LIST (FROM-TO-BY 1 IMAX 1))))) ; [6]
Observe the difference between the
If we think in terms of scions, we're saying “Every time this
Finally, how do we know every application of the
So now we can admit and verify the guards of our
(defun all-pairs-loop$ (imax jmax) (declare (xargs :guard (and (natp imax) (natp jmax)))) (loop$ for i from 1 to imax append :guard (natp jmax) (loop$ for j from 1 to jmax collect (make-pair i j))))
Our goal is to prove the theorem below. We use The-Method, with which we assume you're familiar but which we narrate below.
First we try to prove our main goal. It fails with the checkpoint shown.
(defthm main (implies (and (natp imax) (natp jmax)) (equal (all-pairs-loop$ imax jmax) (all-pairs imax jmax))))) *** Key checkpoint at the top level: *** Goal'' (IMPLIES (AND (INTEGERP IMAX) (<= 0 IMAX) (INTEGERP JMAX) (<= 0 JMAX)) (EQUAL (APPEND$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (COLLECT$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (CONS (CAR LOOP$-GVARS) (CAR LOOP$-IVARS))) (LIST (CAR LOOP$-IVARS)) (LOOP$-AS (LIST (FROM-TO-BY 1 (CAR LOOP$-GVARS) 1))))) (LIST JMAX) (LOOP$-AS (LIST (FROM-TO-BY 1 IMAX 1)))) (ALL-PAIRS-HELPER1 1 IMAX JMAX)))
Looking at the conclusion we see need to prove that the
We submit the proposed generalization as
(defthm lemma1 (implies (and (natp imax) (natp jmax) (natp i0)) (equal (append$+ (lambda$ (loop$-gvars loop$-ivars) (collect$+ (lambda$ (loop$-gvars loop$-ivars) (cons (car loop$-gvars) (car loop$-ivars))) (list (car loop$-ivars)) (loop$-as (list (from-to-by 1 (car loop$-gvars) 1))))) (list jmax) (loop$-as (list (from-to-by i0 imax 1)))) (all-pairs-helper1 i0 imax jmax))))) *** Key checkpoint under a top-level induction: *** Subgoal *1/6'' (IMPLIES (AND (<= I0 IMAX) (EQUAL (APPEND$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (COLLECT$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (CONS (CAR LOOP$-GVARS) (CAR LOOP$-IVARS))) (LIST (CAR LOOP$-IVARS)) (LOOP$-AS (LIST (FROM-TO-BY 1 (CAR LOOP$-GVARS) 1))))) (LIST JMAX) (LOOP$-AS (LIST (FROM-TO-BY (+ 1 I0) IMAX 1)))) (ALL-PAIRS-HELPER1 (+ 1 I0) IMAX JMAX)) (INTEGERP IMAX) (<= 0 IMAX) (INTEGERP JMAX) (<= 0 JMAX) (INTEGERP I0) (<= 0 I0)) (EQUAL (APPEND (COLLECT$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (CONS (CAR LOOP$-GVARS) (CAR LOOP$-IVARS))) (LIST I0) (LOOP$-AS (LIST (FROM-TO-BY 1 JMAX 1)))) (ALL-PAIRS-HELPER1 (+ 1 I0) IMAX JMAX)) (APPEND (ALL-PAIRS-HELPER2 I0 1 JMAX) (ALL-PAIRS-HELPER1 (+ 1 I0) IMAX JMAX))))
Notice that we're trying to prove something of the form
(EQUAL (APPEND a1 b1) (APPEND a2 b2))
where
But again, this is inductive. The
(defthm lemma2 (implies (and (natp imax) (natp jmax) (natp i0) (natp j0)) (equal (collect$+ (lambda$ (loop$-gvars loop$-ivars) (cons (car loop$-gvars) (car loop$-ivars))) (list i0) (loop$-as (list (from-to-by j0 jmax 1)))) (all-pairs-helper2 i0 j0 jmax))))
So now we return to
(defthm lemma1 (implies (and (natp imax) (natp jmax) (natp i0)) (equal (append$+ (lambda$ (loop$-gvars loop$-ivars) (collect$+ (lambda$ (loop$-gvars loop$-ivars) (cons (car loop$-gvars) (car loop$-ivars))) (list (car loop$-ivars)) (loop$-as (list (from-to-by 1 (car loop$-gvars) 1))))) (list jmax) (loop$-as (list (from-to-by i0 imax 1)))) (all-pairs-helper1 i0 imax jmax))))) *** Key checkpoint at the top level: *** [1]Goal (APPLY$-WARRANT-COLLECT$+)
Note that this checkpoint comes from a forcing round (the clue is the
“
(defthm lemma1 (IMPLIES (AND (warrant collect$+) (natp imax) (natp jmax) (natp i0)) (equal (append$+ (lambda$ (loop$-gvars loop$-ivars) (collect$+ (lambda$ (loop$-gvars loop$-ivars) (cons (car loop$-gvars) (car loop$-ivars))) (list (car loop$-ivars)) (loop$-as (list (from-to-by 1 (car loop$-gvars) 1))))) (list jmax) (loop$-as (list (from-to-by i0 imax 1)))) (all-pairs-helper1 i0 imax jmax))))
This proof succeeds.
So now we return to
Unfortunately this attempt fails, but with two easy-to-fix checkpoints.
(defthm main (implies (and (natp imax) (natp jmax)) (equal (all-pairs-loop$ imax jmax) (all-pairs imax jmax))) :hints (("Goal" :do-not-induct t)))) *** Key checkpoints at the top level: *** [1]Subgoal 2 (APPLY$-WARRANT-MAKE-PAIR) [1]Subgoal 1 (APPLY$-WARRANT-COLLECT$+)
Note that the checkpoints are forcing round subgoals showing that we need
two warrants. So we add both warrants to
(defthm main (implies (and (warrant collect$+ make-pair) (natp imax) (natp jmax)) (equal (all-pairs-loop$ imax jmax) (all-pairs imax jmax))) :hints (("Goal" :do-not-induct t)))
Note: The
You might wonder why we need the warrant on
The first time we tried to prove
Goal'' (IMPLIES (AND (INTEGERP IMAX) (<= 0 IMAX) (INTEGERP JMAX) (<= 0 JMAX)) (EQUAL (APPEND$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (COLLECT$+ (LAMBDA$ (LOOP$-GVARS LOOP$-IVARS) (CONS (CAR LOOP$-GVARS) (CAR LOOP$-IVARS))) (LIST (CAR LOOP$-IVARS)) (LOOP$-AS (LIST (FROM-TO-BY 1 (CAR LOOP$-GVARS) 1))))) (LIST JMAX) (LOOP$-AS (LIST (FROM-TO-BY 1 IMAX 1)))) (ALL-PAIRS-HELPER1 1 IMAX JMAX)))
The innermost
Had that first proof attempt at
But forced subgoals are not reported if the proof fails for other reasons.
So we were left unaware that we were depending on the warrant for
The more experienced ACL2 user would have noticed (indeed, did notice!)
the expansion of
The final series of events to solve this problem is shown below.
; Include standard apply$ book. (include-book "projects/apply/top" :dir :system)} ; Define and verify the guards of the recursive all-pairs. (defun make-pair (i j) (declare (xargs :guard t)) (cons i j)) (defun all-pairs-helper2 (i j jmax) (declare (xargs :measure (nfix (- (+ (nfix jmax) 1) (nfix j))) :guard (and (natp i) (natp j) (natp jmax)))) (let ((j (nfix j)) (jmax (nfix jmax))) (cond ((> j jmax) nil) (t (cons (make-pair i j) (all-pairs-helper2 i (+ 1 j) jmax)))))) (defun all-pairs-helper1 (i imax jmax) (declare (xargs :measure (nfix (- (+ (nfix imax) 1) (nfix i))) :guard (and (natp i) (natp imax) (natp jmax)))) (let ((i (nfix i)) (imax (nfix imax))) (cond ((> i imax) nil) (t (append (all-pairs-helper2 i 1 jmax) (all-pairs-helper1 (+ 1 i) imax jmax)))))) (defun all-pairs (imax jmax) (declare (xargs :guard (and (natp imax) (natp jmax)))) (all-pairs-helper1 1 imax jmax)) ; Warrant make-pair so we can use it in a loop$. (defwarrant make-pair) ; Define and verify the guards of the loop$ version. (defun all-pairs-loop$ (imax jmax) (declare (xargs :guard (and (natp imax) (natp jmax)))) (loop$ for i from 1 to imax append :guard (natp jmax) (loop$ for j from 1 to jmax collect (make-pair i j)))) ; Prove that the generalized inner loop$ is all-pairs-helper2. (defthm lemma2 (implies (and (natp imax) (natp jmax) (natp i0) (natp j0)) (equal (collect$+ (lambda$ (loop$-gvars loop$-ivars) (cons (car loop$-gvars) (car loop$-ivars))) (list i0) (loop$-as (list (from-to-by j0 jmax 1)))) (all-pairs-helper2 i0 j0 jmax)))) ; Prove that the generalized outer loop$ is all-pairs-helper1. (defthm lemma1 (implies (and (warrant collect$+) (natp imax) (natp jmax) (natp i0)) (equal (append$+ (lambda$ (loop$-gvars loop$-ivars) (collect$+ (lambda$ (loop$-gvars loop$-ivars) (cons (car loop$-gvars) (car loop$-ivars))) (list (car loop$-ivars)) (loop$-as (list (from-to-by 1 (car loop$-gvars) 1))))) (list jmax) (loop$-as (list (from-to-by i0 imax 1)))) (all-pairs-helper1 i0 imax jmax)))) ; Main theorem (defthm main (implies (and (warrant collect$+ make-pair) (natp imax) (natp jmax)) (equal (all-pairs-loop$ imax jmax) (all-pairs imax jmax))))
Now go to lp-section-12 (or return to the