; ACL2 books using the bdd hints
; Copyright (C) 1997  Computational Logic, Inc.
; License: A 3-clause BSD license.  See the LICENSE file distributed with ACL2.

; Written by:  Matt Kaufmann
; email:       Matt_Kaufmann@aus.edsr.eds.com
; Computational Logic, Inc.
; 1717 West Sixth Street, Suite 290
; Austin, TX 78703-4776 U.S.A.

(in-package "ACL2")

(set-verify-guards-eagerness 2)

(encapsulate
 ()

; This macro is really just implies, as shown by the local theorem below, but
; it is handy for bdd processing when we want to avoid building bdds for the
; hypotheses of an implies, but rather only want to use those hypotheses in
; order to guarantee that certain variables are Boolean.

(defmacro implies* (x y)
  `(if ,y t (not ,x)))

(local (defthm implies*-is-implies
         (equal (implies a b) (implies* a b))))
)

(defun firstn (n l)
  "The sublist of L consisting of its first N elements."
  (declare (xargs :guard (and (true-listp l)
                              (integerp n)
                              (<= 0 n))))
  (cond ((endp l) nil)
        ((zp n) nil)
        (t (cons (car l)
                 (firstn (1- n) (cdr l))))))

(defthm firstn-0
  (equal (firstn 0 rest)
         nil))

(defthm firstn-cons
  (equal (firstn n (cons a rest))
         (if (zp n) nil (cons a (firstn (1- n) rest)))))

(defun restn (n l)
  (declare (xargs :guard (and (true-listp l)
                              (integerp n)
                              (<= 0 n))))
  (if (endp l)
      l
    (if (zp n)
        l
      (restn (1- n) (cdr l)))))

(defthm restn-0
  (equal (restn 0 rest)
         rest))

(defthm restn-cons
  (equal (restn n (cons a rest))
         (if (zp n) (cons a rest) (restn (1- n) rest))))

(defun tree-size (tree)
  (if (atom tree)
      1
    (+ (tree-size (car tree))
       (tree-size (cdr tree)))))

(defthm tree-size-step
  (equal (tree-size (cons a b))
         (+ (tree-size a)
            (tree-size b))))

(defthm tree-size-base
  (equal (tree-size 0)
         1))

(defun tfirstn (list tree)
  (declare (xargs :guard (and (consp tree)
                              (true-listp list))))
  (firstn (tree-size (car tree)) list))

(defun trestn (list tree)
  (declare (xargs :guard (and (consp tree)
                              (true-listp list))))
  (restn (tree-size (car tree)) list))

(defun t-carry (c prop gen)
  (or (and c prop) gen))

(defthm append-cons
  (equal (append (cons a x) y)
         (cons a (append x y))))

(defthm append-nil
  (equal (append nil y)
         y))

; The following macros are handy for reducing the amount of editing necessary
; for translating Nqthm forms into ACL2.

(progn

(defmacro sub1 (x)
  `(1- ,x))

(defmacro nlistp (x)
  `(atom ,x))

(defmacro caddddr (x)
  `(car (cddddr ,x)))

(defmacro cdddddr (x)
  `(cdr (cddddr ,x)))

(defmacro cadddddr (x)
  `(car (cdddddr ,x)))

(defmacro cddddddr (x)
  `(cdr (cdddddr ,x)))

(defmacro caddddddr (x)
  `(car (cddddddr ,x)))

(defmacro cdddddddr (x)
  `(cdr (cddddddr ,x)))

(defmacro quotient (x y)
  `(nonnegative-integer-quotient ,x ,y))

(defmacro remainder (x y)
  `(rem ,x ,y))

(defmacro boolp (x)
  `(booleanp ,x))

(defmacro bvp (x)
  `(boolean-listp ,x))
)

(defun b-buf (x)                 (if x t nil))
(defun b-not (x)                 (not x))
(defun b-nand  (a b)             (not (and a b)))
(defun b-nand3 (a b c)           (not (and a b c)))
(defun b-nand4 (a b c d)         (not (and a b c d)))
(defun b-xor  (a b)              (if a (if b nil t) (if b t nil)))
(defun b-xor3 (a b c)            (b-xor (b-xor a b) c))
(defun b-equv (x y)              (if x (if y t nil) (if y nil t)))
(defun b-equv3 (a b c)           (b-equv a (b-xor b c)))
(defun b-and  (a b)              (and a b))
(defun b-and3 (a b c)            (and a b c))
(defun b-or   (a b)              (or a b))
(defun b-or3  (a b c)            (or a b c))
(defun b-nor  (a b)              (not (or a b)))
(defun b-nor3 (a b c)            (not (or a b c)))
(defun b-if (c a b)              (if c (if a t nil) (if b t nil)))

#| Unfortunately, b-and is not commutative the way it is defined above.
(defthm b-and-comm
  (equal (b-and a b) (b-and b a)))
|#

(defthm b-nand-comm
  (equal (b-nand a b) (b-nand b a)))

(defthm b-xor-comm
  (equal (b-xor a b) (b-xor b a)))

(defthm b-equv-comm
  (equal (b-equv a b) (b-equv b a)))

(defthm b-nor-comm
  (equal (b-nor a b) (b-nor b a)))

(defun v-if (c a b)
  (declare (xargs :guard (true-listp b)))
  (if (nlistp a)
      nil
    (cons (if (if c (car a) (car b)) t nil)
          (v-if c (cdr a) (cdr b)))))

(defthm v-if-base
  (equal (v-if c nil nil)
         nil))

(defthm v-if-step
  (let ((a (cons a0 a1))
        (b (cons b0 b1)))
    (equal (v-if c a b)
           (cons (if c
                     (if a0 t nil)
                   (if b0 t nil))
                 (v-if c a1 b1)))))

(defun v-buf (x)
  (if (nlistp x)
      nil
    (cons (b-buf (car x))
          (v-buf (cdr x)))))

(defthm v-buf-base
  (equal (v-buf nil)
         nil))

(defthm v-buf-step
  (let ((a (cons a0 a1)))
    (equal (v-buf a)
           (cons (b-buf a0)
                 (v-buf a1)))))

(defun boolfix (x)
  (if x t nil))

(defun v-nzerop (x)
  (if (nlistp x)
      nil
      (or (car x)
          (v-nzerop (cdr x)))))

(defthm v-nzerop-base
  (equal (v-nzerop nil)
         nil))

(defthm v-nzerop-step
  (let ((a (cons a0 a1)))
    (equal (v-nzerop a)
           (or a0 (v-nzerop a1)))))

(defun v-zerop (x)
  (not (v-nzerop x)))

(defun nat-to-v (x n)

#|
  (declare (xargs :guard (and (integerp n)
                              (not (< n 0))
                              (rationalp x))))
|#

; Too much trouble at this point.

  (declare (xargs :verify-guards nil))
  (if (zp n)
      nil
    (cons (not (zp (remainder x 2)))
          (nat-to-v (quotient x 2) (sub1 n)))))

(defun make-nils (n)
  (declare (xargs :guard (and (integerp n)
                              (not (< n 0)))))
  (if (zp n)
      nil
    (cons nil (make-nils (1- n)))))

(defthm nat-to-v-0
  (equal (nat-to-v 0 n)
         (make-nils n)))

(defthm fold-plus
  (implies (and (syntaxp (quotep i))
                (syntaxp (quotep j)))
           (equal (+ i j x)
                  (+ (+ i j) x))))

#| We don't really need this any more.
(defthm make-nils-add1
  (equal (make-nils (+ 1 n))
         (if* (zp (+ 1 n))
              nil
              (cons nil (make-nils n))))
  :hints (("Goal" :expand (make-nils (+ 1 n)))))
|#

(defun v-not (x)
  (if (nlistp x)
      nil
    (cons (b-not (car x))
          (v-not (cdr x)))))

(defthm v-not-base
  (equal (v-not nil) nil))

(defthm v-not-step
  (let ((a (cons a0 a1)))
    (equal (v-not a)
           (cons (b-not a0)
                 (v-not a1)))))

(defun v-xor (x y)
  (declare (xargs :guard (true-listp y)))
  (if (nlistp x)
      nil
    (cons (b-xor (car x) (car y))
          (v-xor (cdr x) (cdr y)))))

(defthm v-xor-base
  (equal (v-xor nil x)
         nil))

(defthm v-xor-step
  (let ((a (cons a0 a1))
        (b (cons b0 b1)))
    (equal (v-xor a b)
           (cons (b-xor a0 b0)
                 (v-xor a1 b1)))))

(defun v-or (x y)
  (declare (xargs :guard (true-listp y)))
  (if (nlistp x)
      nil
    (cons (b-or (car x) (car y))
          (v-or (cdr x) (cdr y)))))

(defthm v-or-base
  (equal (v-or nil x)
         nil))

(defthm v-or-step
  (let ((a (cons a0 a1))
        (b (cons b0 b1)))
    (equal (v-or a b)
           (cons (b-or a0 b0)
                 (v-or a1 b1)))))

(defun v-and (x y)
  (declare (xargs :guard (true-listp y)))
  (if (nlistp x)
      nil
    (cons (b-and (car x) (car y))
          (v-and (cdr x) (cdr y)))))

(defthm v-and-base
  (equal (v-and nil x)
         nil))

(defthm v-and-step
  (let ((a (cons a0 a1))
        (b (cons b0 b1)))
    (equal (v-and a b)
           (cons (b-and a0 b0)
                 (v-and a1 b1)))))

(defthm consp-cons
  (equal (consp (cons x y)) t))

(defthm nth-cons
  (equal (nth n (cons a x))
         (if* (zp n)
              a
              (nth (- n 1) x))))

(defthm len-cons
  (equal (len (cons a x))
         (+ 1 (len x))))

(defthm len-nil
  (equal (len nil) 0))

(defthm if*-hide
  (implies (equal x y)
           (equal x (if* test y (hide x))))
  :hints (("Goal" :expand (hide x)))
  :rule-classes nil)

(defun v-equal (x y)
  (if (nlistp x)
      (and (equal x nil) (equal y nil))
    (and (consp y)
         (equal (car x) (car y))
         (v-equal (cdr x) (cdr y)))))

(defthm v-equal-base
  (equal (v-equal nil x)
         (equal x nil)))

(defthm v-equal-step
  (let ((a (cons a0 a1))
        (b (cons b0 b1)))
    (equal (v-equal a b)
           (and (equal a0 b0)
                (v-equal a1 b1)))))

(defun vcond-macro (clauses)

; From ACL2 cond-macro.

  (declare (xargs :guard (cond-clausesp clauses)))
  (if (consp clauses)
      (if (and (eq (car (car clauses)) t)
               (eq (cdr clauses) nil))
          (if (cdr (car clauses))
              (car (cdr (car clauses)))
              (car (car clauses)))
          (list 'v-if (car (car clauses))
                (if (cdr (car clauses))
                    (car (cdr (car clauses)))
                    (car (car clauses)))
                (vcond-macro (cdr clauses))))
      nil))

(defmacro vcond (&rest clauses)
  (declare (xargs :guard (cond-clausesp clauses)))
  (vcond-macro clauses))

(defun bv2p (a b)
  (and (bvp a)
       (bvp b)
       (equal (len a) (len b))))

(defun v-trunc (x n)
  (declare (xargs :guard (and (bvp x)
                              (integerp n)
                              (not (< n 0)))))
  (if (zp n)
      nil
    (cons (boolfix (car x))
          (v-trunc (cdr x) (1- n)))))

(defthm v-trunc-0
  (equal (v-trunc x 0)
         nil))

(defthm v-trunc-cons
  (equal (v-trunc (cons a x) n)
         (if (zp n)
             nil
           (cons (boolfix a)
                 (v-trunc x (1- n))))))

(defthm len-v-trunc
  (equal (len (v-trunc x y))
         (nfix y)))

(defthm nfix-len
  (equal (nfix (len x))
         (len x)))

(defthm v-trunc-v-buf
  (implies (equal n (len a))
           (equal (v-trunc (v-buf a) n)
                  (v-buf a))))

(defthm len-nat-to-v
  (equal (len (nat-to-v i n))
         (nfix n)))

(defthm len-v-not
  (equal (len (v-not v))
         (len v)))

(defun v-shift-right (a si)
  (if (nlistp a)
      nil
    (append (v-buf (cdr a))
            (cons (boolfix si) nil))))

(encapsulate
 ()

 (local
  (defthm v-trunc-v-shift-right-lemma
    (equal (v-trunc (v-shift-right a c) (len a))
           (v-shift-right a c))))

 (defthm v-trunc-v-shift-right
   (implies (equal n (len a))
            (equal (v-trunc (v-shift-right a c) n)
                   (v-shift-right a c)))
   :hints (("Goal" :in-theory (disable v-shift-right))))
 )

(defthm v-trunc-v-xor
  (implies (equal n (len a))
           (equal (v-trunc (v-xor a b) n)
                  (v-xor a b))))

(encapsulate
 ()

 (local
  (defthm v-trunc-v-or-lemma
    (implies (bv2p a b)
             (equal (v-trunc (v-or a b) (len a))
                    (v-or a b)))))

 (defthm v-trunc-v-or
   (implies (and (bv2p a b)
                 (equal n (len a)))
            (equal (v-trunc (v-or a b) n)
                   (v-or a b)))))

(defthm v-trunc-v-not
  (implies (equal n (len a))
           (equal (v-trunc (v-not a) n)
                  (v-not a))))

(defthm len-v-buf
  (equal (len (v-buf v))
         (len v)))

(defthm len-v-xor
  (equal (len (v-xor a b))
         (len a)))

(defthm len-v-and
  (equal (len (v-and a b))
         (len a)))

(defthm len-v-or
  (equal (len (v-or a b))
         (len a)))

; We probably don't need to prove any lemmas about make-tree; we expect to use
; it applied to specific n.

(defun make-tree (n)
  (declare (xargs :guard (and (integerp n)
                              (not (< n 0)))))
  (if (zp n)
      0
    (if (= n 1)
        0
      (cons (make-tree (quotient n 2))
            (make-tree (- n (quotient n 2)))))))

