64
The ACL2 Proof Assistant Formal Methods Jeremy Johnson

The ACL2 Proof Assistant Formal Methods Jeremy Johnson

Embed Size (px)

Citation preview

The ACL2 Proof Assistant

Formal MethodsJeremy Johnson

Topics ACL2 as a specification language Reasoning about ACL2 programs

Equational reasoning Induction and recursion

ACL2 as a logic ACL2 axioms Definitional axioms and input contracts Induction principle

ACL2 as a theorem prover

Sorting

Given a list L = (L1 … Ln) of elements from a totally ordered set (e.g. rationals with ≤) return a list M = (M1 … Mn) such that

(sorted M), i.e. M1 ≤ M2 ≤ ≤ Mn

M = (permutation L), i.e. Mi = L(i) where is a bijection from {1,…,n} to {1,…,n}

sortedp

Predicate to test to see if a list is sortedShould check to see that L is a list of rationals

(x1 x2 … xn) with x1 ≤ x2 ≤ ≤ xn

xi ≤ xi+1 for 1 ≤ i < n

i xi ≤ xi+1 1 ≤ i i < n

(defun sortedp (L) (cond ((equal L nil) t) ((equal (length L) 1) t) ((and (<= (first L) (second L)) (sortedp (rest L))))))

Correctness of sortedp

L = (x1 x2 … xn)

By induction on len(L)Base cases L nil or of length 1

Show xi ≤ xi+1 for 1 ≤ i < n

x1 ≤ x2 and by induction xi ≤ xi+1 for 2 ≤ i < n

Insertion Sort

; input. L is a list of integers; output is a sorted list of integers whose elements are the same as in L.

(defun insertionsort (L)

(if (equal L nil)

nil

(insert (first L) (insertionsort (rest L)))))

; inputs x is an integer and L is a list of rationals that is sorted; output is a sorted list of integers.(defun insert (x L) (cond ((equal L nil) (list x)) ((<= x (first L)) (cons x L)) ((cons (first L) (insert x (rest L))))))

Testing of Insertion Sort

(check= (insert 1 nil) '(1))(check= (insert 4 '(1 2 3)) '(1 2 3 4))(check= (insert 0 '(1 2 3)) '(0 1 2 3))(check= (insert 2 '(1 3)) '(1 2 3))(check= (sortedp (insert 2 '(1 3))) t)

(check= (insertionsort '(3 2 1)) '(1 2 3))(check= (sortedp (insertionsort '(3 4 2 1))) t)

Correctness of insertionsort

L = (L1 … Ln)

1. (insertionsort L) terminates and returns a list

2. (insertionsort L) is sorted

3. (insertionsort L) is a permutation of L

Proof by induction on n

1. For n 0, recursive call with smaller n

2. Recursive call produces a sorted list of (rest L) by induction and (insert (first L) (insertionsort (rest L))) returns a sorted list (by induction)

3. Recursive call returns a permutation of (rest L) and insert returns a list containing (first L) and elements of (rest L)

Formal Correctness Proof

(defthm insert-sortedp (implies (sortedp L) (sortedp (insert x L))))

(defthm insertion-sort-is-sorted (sortedp (insertion-sort L)))

(defthm insert-perm-cons (implies (perm L P) (perm (insert x L) (cons x P))))

(thm (perm (insertion-sort L) L))

Insertion Sort

(defunc insertion-sort (L) :input-contract (list-rationalp L) :output-contract (and (list-rationalp (insertion-sort L)) (sortedp (insertion-sort L)) (perm (insertion-sort L) L)) (if (equal L nil) nil (insert (first L) (insertion-sort (rest L)))))

insert

(defunc insert (x L) :input-contract (and (rationalp x) (list-rationalp L) (sortedp L)) :output-contract (and (list-rationalp (insert x L)) (sortedp (insert x L)) (perm (insert x L) (cons x L))) (cond ( (equal L nil) (list x) ) ( (<= x (first L)) (cons x L) ) ( (cons (first L) (insert x (rest L))) ) ) )

sortedp

(defunc sortedp (x) :input-contract (list-rationalp x) :output-contract (booleanp (sortedp x)) (cond ( (equal x nil) t ) ( (equal (len x) 1) t ) ( t (and (<= (first x) (second x)) (sortedp (rest x))) ) ))

list-rationalp

(defunc list-rationalp (x) :input-contract t :output-contract (booleanp (list-rationalp x)) (cond ( (equal x nil) t) ( (consp x) (and (rationalp (first x)) (list-rationalp (rest

x))) ) ( t nil) ))

list-rationalp

(defunc sortedp (x) :input-contract (list-rationalp x) :output-contract (booleanp (sortedp x)) (cond ( (equal x nil) t ) ( (equal (len x) 1) t ) ( t (and (<= (first x) (second x)) (sortedp (rest x))) ) ))

perm

(defunc perm (L P) :input-contract (and (list-rationalp L) (list-rationalp P)) :output-contract (booleanp (perm L P)) (cond ( (equal L nil) (equal P nil) ) ( t (and (in (first L) P) (perm (rest L) (del (first L) P))) ) ))

in

(defunc in (x L) :input-contract (and (rationalp x) (list-rationalp L)) :output-contract (booleanp (in x L)) (cond ( (equal L nil) nil ) ( (equal x (first L)) t ) ( t (in x (rest L)) ) ))

del

(defunc del (x L) :input-contract (and (rationalp x) (list-rationalp L)) :output-contract (list-rationalp (del x L)) (cond ( (equal L nil) nil ) ( (equal x (first L)) (rest L) ) ( t (cons (first L) (del x (rest L))) ) ))

How was ACL2 able to do this?

Proofs use formal reasoning Axioms for built-in functions (consp, if, equal) Every time we define a function that ACL2s

admits, we also get a definitional axiom an axiom stating that the function is equal to its body.

I.E. Replace a function call by its body substituting the formal parameters with the arguments

Reason using properties of first order logic Equational reasoning Well founded induction

Example

Reason about the following functions

(defunc len (x)

:input-contract t

:output-contract (natp (len x))

(if (atom x)

0

(+ 1 (len (rest x)))))

Example

(defunc atom (x)

:input-contract t

:output-contract (booleanp (atom x))

(not (consp x)))

(defunc not (a)

:input-contract (booleanp a)

:output-contract (booleanp (not a))

(if a nil t))

Example

Theorem: (equal (len (cons x (list z))) 2) (len (cons x (list z))) (if (atom (cons x (list z))) 0 (+ 1 (len (rest (cons

x (list z)))))) {def of len} (if (atom (cons x (list z))) 0 (+ 1 (len (list z))))

{first-rest axiom} (if (not (consp (cons x (list z)))) 0 (+ 1 (len (list

z)))) {def of atom}

Example Continued (if (if (consp (cons x (list z))) nil t) 0 (+ 1 (len (list

z)))) {def of not} (if (if t nil t) 0 (+ 1 (len (list z)))) {consp axiom} (if nil 0 (+ 1 (len (list z)))) {if axiom} (+ 1 (len (list z))) {if axiom} (+ 1 (len (cons z nil))) {expand list macro} … (+ 1 1) = 2 (equal 2 2) = t

Example Proof

Conjecture: (equal (len (cons x (list z)))(len (cons y (list z))))

The previous theorem showed (len (cons x (list z))) = 2

Similar reasoning shows (len (cons y (list z))) = 2

Alternatively we can substitute x=y in the theorem to obtain (len (cons y (list z))) = 2

Counter Example

Same type of reasoning can be use to prove conjectures false

Conjecture: (equal (len (list x)) (len x))(equal (len (list nil)) (len nil))

Compute (len nil) and (len (list nil)) and compare

Counter Example(len nil) (if (atom nil) 0 (+ 1 (len (rest nil))))) [def of len](if t 0 (+ 1 (len (rest nil))))) [def of atom]0 [if axiom](len (list nil))(if (atom (list nil)) 0 (+ 1 (len (rest (list nil))))))

[def of len](if nil 0 (+ 1 (len (rest nil))))) [def of atom](+ 1 (len (rest nil)))) [if axiom]

Counter Example

(len (list nil))(if (atom (list nil)) 0 (+ 1 (len (rest (list

nil)))))) [def of len](if nil 0 (+ 1 (len (rest (list nil))))) [def of

atom](+ 1 (len (rest (list nil))))) [if axiom](+ 1 (len nil)) [first-rest axiom](+ 1 0) [previous calculation]1 0

List ProcessingRecursive Definition

List := nil | (cons All List)List<Type> := nil (cons Type List<Type>)Process lists using these two cases and use

recursion to recursively process lists in consUse first and rest to access components of cons

Size is the number of conses (generally number of constructors)Prove properties by inducting on size – assume

property holds for smaller size objects and show that this implies it holds for object at hand27

Append

(defun append (x y)

(if (equal x nil)

y

(cons (first x) (append (rest x) y))))

Properties1. (append x nil) = x

2. (length (append x y)) = (+ (length x) (length y))

3. (append x (append y z)) = (append (append x y) z)

28

Structural Induction

When using induction on recursively defined data structures like lists you can induct on the size of the data structure = to the number of calls to the constructors.

When trying to show a property for a data structure of a given size, you can assume that the property holds when making a recursive call on a smaller data structure. You must make sure that the property holds for all constructors including base cases.

With lists (rest …) will return a smaller data structure (at least one fewer cons)

Structural induction allows you to induct on the recursive data structure without being explicit about the size provided the IH is applied to smaller objects.

Proof of Property 1

Show (append x nil) = x using structural induction

Base case. x = nil. In this case, (append nil nil) returns nil = x.

By induction assume recursive call satisfies the property [note (rest x) is smaller than x]I.E. (append (rest x) nil) = (rest x)

Thus (append x nil) returns (cons (first x) (rest x)) = x

Proof of Property 2

Show (length (append x y) = (+ (length x) (length y)) using structural induction on xBase case. x = nil. (append nil y) = y and

(length y) = (+ (length nil) (length y))By induction assume recursive call satisfies the

property (length (append (rest x) y) = (+ (length (rest x))

(length y))

Thus (length (append x y)) = (length (cons (first x) (append (rest x) y)) = (+ 1 (length (rest x)) + (length y)) = (+ (length x) (length y))

Proof of Property 3

Show (append x (append y z)) = (append (append x y) z)Base case. x = nil. (append nil (append y z)) =

(append y z) = (append (append nil y) z) Assume property holds for (rest x)

(append (append x y) z) =(append (cons (first x) (append (rest x) y)) z) [by def]=(cons (first x) (append (append (rest x) y) z)) [by def]=(cons (first x) (append (rest x) (append y z))) [by IH]=(append (cons (first x) (rest x)) (append y z)) [by def]=(append x (append y z)) [by property of cons]

Logical Axioms

Propositional Axiom Schema: ( ) Expansion: derive (1 2) from 2

Contraction: derive from ( ) Associativity: derive (1 2) 3 from 1

(2 3)

Cut: derive (2 3) from (1 2) (1 3) -Introduction: If x not free in B then derive

x A B from A B

Instantiation

Derive | from . That is, if is a theorem and is a substitution, then by instantiation, | is a theorem. Substitution ((var1 term1) . . . (varn termn))

Example. From the theorem (equal (first (cons x y)) x)

We can derive (equal (first (cons (foo x) (bar z))) (foo x))

Equality

Reflexivity Axiom: x=x Equality Axiom: [(x1 = y1 x∧ 2 = y2)] [(x1 = x2)

(y1 = y2)] Implies = is an equivalence relation

Reflexive x = x Symmetric x = y y = x Transitive x = y y = z x = z

Equality Axiom Schema for Functions (x1 = y1 ∧ x∧ n = yn) (f x⇒ 1 xn) = (f y1 yn)

Sound and Complete

Allows use of classic results (derived rules) from logic Propositional tautology Case analysis

Derive from (1 n) and i

Substitution of equals for equals If 1 = 2 then in any formula we may replace 1 by 2

in Deduction law

May assume hypotheses of formula as givens while trying to prove conclusion

Proof of Soundness and Completeness

Show equivalent to natural deductionDerive 2 from 1 and 1 2

1. 1 Given

2. 1 2 Given

3. 2 1 Expansion 1

4. 1 2 Commutativity of [must show]

5. 2 2 Cut 4,2

6. 2 Contraction 5

Axioms of ACL2

x = nil (if x y z) = z⇒ x nil (if x y z) = y⇒ x = y (⇒ equal x y) = t x y (equal x y) = nil⇒ (equal (first (rest x y)) x) nil

t nil (equal x y) = t x = y (equal x y) = nil x y (first (cons x y)) = x

Propositional Functions

(not p) = (if p nil t) (or p q) = (if p t (if q t nil)) (and p q) = (if p (if q t nil) nil) (implies p q) = (if p (if q t nil) t) (iff p q) = (if p (if q t nil) (if q nil t))

(not p) (p nil) (or p q) (p nil) (q nil) (and p q) (p nil) (q nil) (implies p q) (p nil) (q nil)

Remaining Axioms

(rest (cons x y)) = y (consp (cons x y)) = t

Axiomatize other data types symbol, number, characters, strings (implies (consp x) (not (symbolp x)) [disjoint] Derive (consp nil) = nil Axioms from arithmetic – rationals are an

ordered field for constants 0, 1 and +,-,*,/, and <

Definition of Append

(defunc app (a b)

:input-contract (and (listp a) (listp b))

:output-contract (and (listp (app a b))

(equal (len (app a b))

(+ (len a) (len b))))

(if (endp a)

b

(cons (first a) (app (rest a) b))))

Necessary Functions

(defunc listp (l)

:input-contract t

:output-contract (booleanp (listp l))

(if (consp l)

(listp (rest l))

(equal l ())))

(defunc endp (a)

:input-contract (listp a)

:output-contract (booleanp (endp a))

(equal a nil))

Proving Properties

Associativity of app (app x (app y z)) = (app (app x y) z) Definitional axiom Input contracts and context Formal reasoning needed for induction Base Case when x = nil

(endp x) (listp x) (listp y) (listp z) ⇒(app (app x y) z) = (app x (app y z))

General case assuming inductive hypothesis (listp (rest x)) (listp y) (listp z) ∧ ∧ ⇒

(app (app (rest x) y) z) = (app (rest x) (app y z))

Definitional Axiom

(listp a) (listp b)∧

⇒ (app a b)

=

(if (endp a)

b

(cons (first a) (app (rest a) b)))

Can’t expand body unless (listp a) and (listp b)

In general every time we “successfully admit a function” we get an axiom: ic (f x⇒ 1 ... xn) = body

Can’t expand body unless ic is satisfied.

Application of Append

Theorem [CA]: (listp y) (listp z) (app (cons x y) z) = (cons x (app y z)) (app (cons x y) z) (if (endp (cons x y)) z (cons (first (cons x y))

(app (rest (cons x y)) z))) [def of app and inst] (if nil z (cons (first (cons x y)) (app (rest (cons x

y)) z))) [def of endp and consp axiom] (cons (first (cons x y)) (app (rest (cons x y)) z))

[if axiom] (cons x (app y z)) [axioms for first and rest]

Base Case

Theorem: (endp x) (listp x) (listp y) (listp z) ⇒(app (app x y) z) = (app x (app y z))

Conjecture Contract Checking

Make sure all hypotheses are present in your conjectures

Conjecture: (endp x) ⇒ (app (app x y) z) = (app x (app y z))

Taking into account all input contracts Conjecture: (endp x) (listp x) (listp y)

(listp z) ⇒ (app (app x y) z) = (app x (app y z))

Context

Conjecture: (endp x) (listp x) (listp y) (listp z) ⇒ (app (app x y) z) = (app x (app y z)) (implies (and (endp x) (listp x) (listp y) (listp z))

(iff (app (app x y) z) (app x (app y z))

hyp1 hyp∧ 2 ∧ hyp∧ n conc⇒ Context = {hyp1, hyp2,…, hypn}

Context of conjecture = {(endp x), (listp x), (listp y), (listp z)}

Implications of Context

Conjecture: (endp x) (listp x) (listp y) (listp z) ⇒ (app (app x y) z) = (app x (app y z))

C1. (endp x)C2. (listp x)C3. (listp y)C4. (listp z)C5. x = nil {C1, C2}

Testing Conjecture(let ((x nil)

(y nil)

(z nil))

(implies (and (endp x)

(listp x)

(listp y)

(listp z))

(equal (app (app x y) z)

(app x (app y z)))))

Testing Conjecture(test?

(implies (and (endp x)

(listp x)

(listp y)

(listp z))

(equal (app (app x y) z)

(app x (app y z)))))

Proof of Conjecture

Theorem: (endp x) (listp x) (listp y) (listp z) ⇒ (app (app x y) z) = (app x (app y z))

C1. (endp x)C2. (listp x)C3. (listp y)C4. (listp z)C5. x = nil {C1, C2}

(app (app x y) z)(app y z) [def of app, def of endp, C5, if axiom] (app x (app y z) ) [def of app, def of endp, C5, if axiom]

General Case

Theorem. [(consp x) (listp x) (listp y) ∧ ∧(listp z)

[(listp (rest x)) (listp y) (listp z)∧ ∧ ⇒ (app (app (rest x) y) z) = (app (rest

x) (app y z))]] ⇒ (app (app x y) z) = (app x (app y z))

Rearranging Contexts(consp x)

[[(listp (rest x)) (listp y) (listp z)∧ ∧

⇒ (app (app (rest x) y) z) = (app (rest x) (app y z))]

⇒ [(listp x) (listp y) (listp z)∧ ∧

⇒ (app (app x y) z) = (app x (app y z))]]

[(consp x) [(listp (rest x)) (listp y) (listp z)∧ ∧

⇒ (app (app (rest x) y) z) = (app (rest x) (app y z))]

⇒ [(listp x) (listp y) (listp z)∧ ∧

⇒ (app (app x y) z) = (app x (app y z))]]

Rearranging Contexts

[(consp x) [(listp (rest x)) (listp y) (listp z)∧ ∧

⇒ (app (app (rest x) y) z) = (app (rest x) (app y z))]

⇒ [(listp x) (listp y) (listp z)∧ ∧

⇒ (app (app x y) z) = (app x (app y z))]]

[(consp x) (listp x) (listp y) (listp z) ∧ ∧ [(listp (rest x)) (listp y) (listp z)∧ ∧

⇒ (app (app (rest x) y) z) = (app (rest x) (app y z))]]

⇒ (app (app x y) z) = (app x (app y z))

Context of Conjecture

Conjecture: (app (app x y) z) = (app x (app y z))

C1. (consp x)C2. (listp x)C3. (listp y)C4. (listp z)

C5. [(listp (rest x)) (listp y) (listp z)∧ ∧

⇒ (app (app (rest x) y) z) = (app (rest x) (app y z))]

Extending Context

C1. (consp x)C2. (listp x)C3. (listp y)C4. (listp z)

C5. [(listp (rest x)) (listp y) (listp z)∧ ∧

⇒ (app (app (rest x) y) z) = (app (rest x) (app y z))]

C6. (listp (rest x)) [C1, C2, def of listp]C7. (app (app (rest x) y) z) = (app (rest x) (app y z))

[C6, C3, C4, C5, MP]

Proof of Theorem Theorem. [(consp x) (listp x) (listp y) (listp z) ∧ ∧ [(listp (rest x)) (listp y) (listp z)∧ ∧

⇒ (app (app (rest x) y) z) = (app (rest x) (app y z))]]

⇒ (app (app x y) z) = (app x (app y z))

Proof (app (app x y) z) (app (cons (first x) (app (rest x) y)) z) [def app, C1, C2, C3] (cons (first x) (app (app (rest x) y) z)) [Thm CA,C3,C4,C6] (cons (first x) (app (rest x) (app y z))) [C7] (app x (app y z))) [def app, C1, C2, C3, C4]

Induction Scheme Base Case

(endp x) (listp x) (listp y) (listp z) ⇒ (app (app x y) z) = (app x (app y z))

Induction Step [(consp x) (listp x) (listp y) (listp z) ∧ ∧

[(listp (rest x)) (listp y) (listp z)∧ ∧

⇒ (app (app (rest x) y) z) = (app (rest x) (app y z))]] ⇒ (app (app x y) z) = (app x (app y z))

Conclude (assuming termination) (app (app x y) z) = (app x (app y z))

Induction in ACL2ACL2 >QUERY (thm (implies (and (true-listp x) (true-listp y) (true-listp z)) (equal (app (app x y) z) (app x (app y z)))))

<< Starting proof tree logging >>^^^ Checkpoint Goal ^^^

*1 (the initial Goal, a key checkpoint) is pushed for proof by induction.

Perhaps we can prove *1 by induction. Five induction schemes are suggested

by this conjecture. These merge into three derived induction schemes.However, two of these are flawed and so we are left with one viablecandidate.

We will induct according to a scheme suggested by (APP X Y). Thissuggestion was produced using the :induction rules APP-INDUCTION-

SCHEME,APP-INDUCTION-SCHEME-FROM-DEFINITION and TRUE-LISTP. If we let

(:P X Y Z)denote *1 above then the induction scheme we'll use is(AND (IMPLIES (NOT (AND (TRUE-LISTP X) (TRUE-LISTP Y))) (:P X Y Z)) (IMPLIES (AND (AND (TRUE-LISTP X) (TRUE-LISTP Y)) (NOT (ENDP X)) (:P (CDR X) Y Z)) (:P X Y Z)) (IMPLIES (AND (AND (TRUE-LISTP X) (TRUE-LISTP Y)) (ENDP X)) (:P X Y Z))).This induction is justified by the same argument used to admit APP.When applied to the goal at hand the above induction scheme producesthree nontautological subgoals.^^^ Checkpoint *1 ^^^Subgoal *1/3Subgoal *1/3'Subgoal *1/2Subgoal *1/1Subgoal *1/1'

*1 is COMPLETED!Thus key checkpoint Goal is COMPLETED!

Q.E.D.

SummaryForm: ( THM ...)Rules: ((:DEFINITION APP-DEFINITION-RULE) (:DEFINITION ENDP) (:DEFINITION NOT) (:DEFINITION TRUE-LISTP) (:EXECUTABLE-COUNTERPART CONSP) (:FAKE-RUNE-FOR-TYPE-SET NIL) (:INDUCTION APP-INDUCTION-SCHEME) (:INDUCTION APP-INDUCTION-SCHEME-FROM-DEFINITION) (:INDUCTION TRUE-LISTP) (:REWRITE APP-CONTRACT) (:REWRITE CAR-CONS) (:REWRITE CDR-CONS) (:REWRITE LIST::TRUE-LISTP-OF-CONS) (:REWRITE LIST::TRUE-LISTP-OF-NON-CONSP))Time: 0.37 seconds (prove: 0.19, print: 0.00, proof tree: 0.03, other:

0.16)Prover steps counted: 10932

Proof succeeded.

Induction in ACL2We will induct according to a scheme suggested by (APP X Y). Thissuggestion was produced using the :induction rules APP-INDUCTION-

SCHEME,APP-INDUCTION-SCHEME-FROM-DEFINITION and TRUE-LISTP. If we let

(:P X Y Z)denote *1 above then the induction scheme we'll use is(AND (IMPLIES (NOT (AND (TRUE-LISTP X) (TRUE-LISTP Y))) (:P X Y Z)) (IMPLIES (AND (AND (TRUE-LISTP X) (TRUE-LISTP Y)) (NOT (ENDP X)) (:P (CDR X) Y Z)) (:P X Y Z)) (IMPLIES (AND (AND (TRUE-LISTP X) (TRUE-LISTP Y)) (ENDP X)) (:P X Y Z))).

Induction in ACL2This induction is justified by the same argument used to admit APP.When applied to the goal at hand the above induction scheme producesthree nontautological subgoals.^^^ Checkpoint *1 ^^^Subgoal *1/3Subgoal *1/3'Subgoal *1/2Subgoal *1/1Subgoal *1/1'

*1 is COMPLETED!Thus key checkpoint Goal is COMPLETED!

Q.E.D.

Induction in ACL2SummaryForm: ( THM ...)Rules: ((:DEFINITION APP-DEFINITION-RULE) (:DEFINITION ENDP) (:DEFINITION NOT) (:DEFINITION TRUE-LISTP) (:EXECUTABLE-COUNTERPART CONSP) (:FAKE-RUNE-FOR-TYPE-SET NIL) (:INDUCTION APP-INDUCTION-SCHEME) (:INDUCTION APP-INDUCTION-SCHEME-FROM-DEFINITION) (:INDUCTION TRUE-LISTP) (:REWRITE APP-CONTRACT) (:REWRITE CAR-CONS) (:REWRITE CDR-CONS) (:REWRITE LIST::TRUE-LISTP-OF-CONS) (:REWRITE LIST::TRUE-LISTP-OF-NON-CONSP))Time: 0.37 seconds (prove: 0.19, print: 0.00, proof tree: 0.03, other: 0.16)Prover steps counted: 10932Proof succeeded.

Exercise

(defun reverse (l)

(if (equal l nil)

nil

(append (reverse (rest l)) (cons (first l) nil))))

Prove the following properties using induction (length (reverse x)) = (length x) (reverse (append x y)) = (append (reverse y) (reverse x)) (reverse (reverse x)) = x

Prove these properties using ACL2

64