Filtering...

nth

books/std/lists/nth

Included Books

other
(in-package "ACL2")
include-book
(include-book "list-defuns")
include-book
(include-book "abstract")
include-book
(include-book "std/util/bstar" :dir :system)
local
(local (include-book "rev"))
local
(local (include-book "append"))
local
(local (include-book "take"))
other
(defsection std/lists/nth
  :parents (std/lists nth)
  :short "Lemmas about @(see nth) available in the @(see std/lists) library."
  "<h4>Trivial reductions</h4>"
  (defthm nth-when-atom
    (implies (atom x) (equal (nth n x) nil)))
  (defthm nth-when-zp
    (implies (zp n) (equal (nth n x) (car x))))
  (defthm nth-of-nil (equal (nth n nil) nil))
  (defthm nth-of-list-fix
    (equal (nth n (list-fix x)) (nth n x)))
  (defthm nth-of-nfix (equal (nth (nfix n) x) (nth n x)))
  "<p>Note: Matt Kaufmann reported that the following lemma got expensive in
   one of his books, so we now disable it by default and instead leave enabled
   a -cheap rule with a backchain limit.</p>"
  (defthmd nth-when-too-large
    (implies (<= (len x) (nfix n)) (equal (nth n x) nil)))
  (defthm nth-when-too-large-cheap
    (implies (<= (len x) (nfix n)) (equal (nth n x) nil))
    :rule-classes ((:rewrite :backchain-limit-lst 1)))
  "<h4>Lemmas about @(see acl2-count) of nth</h4>"
  (defthm acl2-count-of-nth-linear
    (implies (consp x)
      (< (acl2-count (nth i x)) (acl2-count x)))
    :rule-classes :linear)
  (defthm acl2-count-of-nth-linear-weak
    (<= (acl2-count (nth i x)) (acl2-count x))
    :rule-classes :linear)
  (defthm acl2-count-of-nth-rewrite
    (equal (< (acl2-count (nth i x)) (acl2-count x))
      (or (consp x) (> (acl2-count x) 0))))
  "<h4>Nth with other basic list functions</h4>

   <p>Note that we don't prove a rule about @(see update-nth), because
   @('nth-update-nth') is an ACL2 builtin.</p>"
  (defthm member-of-nth
    (implies (< (nfix n) (len x)) (member (nth n x) x)))
  (defthm nth-of-append
    (equal (nth n (append x y))
      (if (< (nfix n) (len x))
        (nth n x)
        (nth (- n (len x)) y))))
  (defthm nth-of-revappend
    (equal (nth n (revappend x y))
      (if (< (nfix n) (len x))
        (nth (- (len x) (+ 1 (nfix n))) x)
        (nth (- n (len x)) y))))
  (defthm nth-of-rev
    (equal (nth n (rev x))
      (if (< (nfix n) (len x))
        (nth (- (len x) (+ 1 (nfix n))) x)
        nil)))
  (defthm nth-of-reverse
    (equal (nth n (reverse x))
      (if (< (nfix n) (len x))
        (nth (- (len x) (+ 1 (nfix n))) x)
        nil)))
  (defthm nth-of-take
    (equal (nth i (take n l))
      (if (< (nfix i) (nfix n))
        (nth i l)
        nil)))
  (defthm nth-of-make-list-ac
    (equal (nth n (make-list-ac m val acc))
      (if (< (nfix n) (nfix m))
        val
        (nth (- n (nfix m)) acc))))
  (encapsulate nil
    (local (defun my-induct
        (n m)
        (if (zp m)
          (list n m)
          (my-induct (- n 1) (- m 1)))))
    (defthm nth-of-repeat
      (equal (nth n (repeat m a))
        (if (< (nfix n) (nfix m))
          a
          nil))
      :hints (("Goal" :induct (my-induct n m) :in-theory (enable repeat)))))
  (defthm nth-of-nthcdr
    (equal (nth n (nthcdr m x)) (nth (+ (nfix n) (nfix m)) x)))
  (defthm nth-of-last
    (equal (nth n (last x))
      (if (zp n)
        (car (last x))
        nil)))
  (defthm nth-of-butlast
    (equal (nth n (butlast x m))
      (if (< (nfix n) (- (len x) (nfix m)))
        (nth n x)
        nil)))
  "<h4>Nth of element lists and projections</h4>

  <p>These are for use with @(see std::deflist) and @(see std::defprojection).</p>"
  (def-listp-rule element-p-of-nth-when-element-list-p-when-nil-element
    (implies (and (element-p nil) (element-list-p x))
      (element-p (nth n x)))
    :requirement (and element-p-of-nil simple)
    :name element-p-of-nth-when-element-list-p
    :body (implies (element-list-p x) (element-p (nth n x))))
  (def-listp-rule element-p-of-nth-when-element-list-p-when-nil-unknown
    (implies (and (element-list-p x) (< (nfix n) (len x)))
      (element-p (nth n x)))
    :requirement (and (not element-p-of-nil)
      simple
      (not not-element-p-of-nil))
    :name element-p-of-nth-when-element-list-p)
  (def-listp-rule element-p-of-nth-when-element-list-p-when-nil-not-element-non-negated
    (implies (and (not (element-p nil)) (element-list-p x))
      (iff (element-p (nth n x)) (< (nfix n) (len x))))
    :requirement (and not-element-p-of-nil simple (not negatedp))
    :name element-p-of-nth-when-element-list-p
    :body (implies (element-list-p x)
      (iff (element-p (nth n x)) (< (nfix n) (len x)))))
  (def-listp-rule element-p-of-nth-when-element-list-p-when-nil-not-element-negated
    (implies (and (not (element-p nil)) (element-list-p x))
      (iff (non-element-p (nth n x)) (<= (len x) (nfix n))))
    :requirement (and not-element-p-of-nil simple negatedp)
    :name element-p-of-nth-when-element-list-p
    :body (implies (element-list-p x)
      (iff (non-element-p (nth n x)) (<= (len x) (nfix n)))))
  (def-projection-rule nth-of-elementlist-projection-when-nil-preservingp
    (implies (equal (element-xformer nil) nil)
      (equal (nth n (elementlist-projection x))
        (element-xformer (nth n x))))
    :requirement nil-preservingp
    :name nth-of-elementlist-projection
    :body (equal (nth n (elementlist-projection x))
      (element-xformer (nth n x))))
  (def-projection-rule nth-of-elementlist-projection-when-not-nil-preservingp
    (equal (nth n (elementlist-projection x))
      (and (< (nfix n) (len x)) (element-xformer (nth n x))))
    :requirement (not nil-preservingp)
    :name nth-of-elementlist-projection)
  (def-listfix-rule nth-of-element-list-fix-when-nil-element
    (implies (element-p nil)
      (equal (nth n (element-list-fix x)) (element-fix (nth n x))))
    :requirement element-p-of-nil
    :name nth-of-element-list-fix
    :body (equal (nth n (element-list-fix x)) (element-fix (nth n x))))
  (def-listfix-rule nth-of-element-list-fix-unless-nil-element
    (equal (nth n (element-list-fix x))
      (and (< (nfix n) (len x)) (element-fix (nth n x))))
    :requirement (not element-p-of-nil)
    :name nth-of-element-list-fix))
other
(defsection equal-by-nths
  :parents (std/lists/nth nth)
  :short "Proof technique: show two lists are equal by showing that their
  @(see nth) elements are always the same."
  :long "<p>This is a powerful rule that can be functionally instantiated to
  prove that two lists are equal when their @('nth') elements are always the
  same.  The theorem to instantiate is:</p>

  @(thm equal-by-nths)

  <p>Where the @('hyp'), @('lhs'), and @('rhs') must satisfy the encapsulated
  constraint, essentially that the @('nth') element of @('lhs') is always the
  same as the @('nth') element of @('rhs') when the @('hyp') is satisfied:</p>

  @(def equal-by-nths-hyp)

  <p>For some bare-bones automation, see also @(see equal-by-nths-hint).</p>"
  :autodoc nil
  (encapsulate (((equal-by-nths-hyp) => *) ((equal-by-nths-lhs) => *)
      ((equal-by-nths-rhs) => *))
    (local (defun equal-by-nths-hyp nil nil))
    (local (defun equal-by-nths-lhs nil nil))
    (local (defun equal-by-nths-rhs nil nil))
    (defthmd equal-by-nths-constraint
      (implies (and (equal-by-nths-hyp)
          (natp n)
          (< n (len (equal-by-nths-lhs))))
        (equal (nth n (equal-by-nths-lhs))
          (nth n (equal-by-nths-rhs))))))
  (local (defun nth-badguy
      (x y)
      (cond ((or (not (consp x)) (not (consp y))) 0)
        ((equal (car x) (car y)) (+ 1 (nth-badguy (cdr x) (cdr y))))
        (t 0))))
  (local (defthm nth-badguy-bounded
      (<= (nth-badguy x y) (len x))
      :rule-classes :linear))
  (local (defthm nth-badguy-is-bad
      (implies (and (equal (len x) (len y))
          (not (equal (nth-badguy x y) (len x))))
        (not (equal (nth (nth-badguy x y) x) (nth (nth-badguy x y) y))))))
  (local (defthm nth-badguy-is-equality
      (implies (and (equal (len x) (len y)) (true-listp x) (true-listp y))
        (equal (equal (nth-badguy x y) (len x)) (equal x y)))))
  (local (in-theory (disable nth-badguy-is-equality
        nth-badguy-is-bad
        nth-badguy)))
  (defthm equal-by-nths
    (implies (and (equal-by-nths-hyp)
        (true-listp (equal-by-nths-lhs))
        (true-listp (equal-by-nths-rhs)))
      (equal (equal (equal-by-nths-lhs) (equal-by-nths-rhs))
        (equal (len (equal-by-nths-lhs)) (len (equal-by-nths-rhs)))))
    :hints (("Goal" :use ((:instance nth-badguy-is-equality
          (x (equal-by-nths-lhs))
          (y (equal-by-nths-rhs))) (:instance nth-badguy-is-bad
           (x (equal-by-nths-lhs))
           (y (equal-by-nths-rhs)))
         (:instance equal-by-nths-constraint
           (n (nth-badguy (equal-by-nths-lhs) (equal-by-nths-rhs)))))))))
other
(defsection equal-by-nths-hint
  :parents (equal-by-nths)
  :short "A @(see computed-hint) that automates basic applications of @(see equal-by-nths)."
  :long "<p>This is a computed hint that looks for goals of the form</p>

  @({
      (implies (and hyp1 ... hypN) (equal lhs rhs))
  })

  <p>If the goal has the right form, we functionally instantiate @(see
  equal-by-nths) with the @('hyp')s, @('lhs'), and @('rhs') above, which should
  effectively reduce the goal to showing that the @(see nth) element of
  @('lhs') and @('rhs') are always the same, and that their length is the
  same.</p>

  <p>Typical usage would be something like:</p>

  @({
      (defthm foo ... :hints((equal-by-nths-hint)))
  })

  <p>or perhaps:</p>

  @({
      (defthm foo ... :hints((and stable-under-simplificationp
                                  (equal-by-nths-hint))))
  })"
  (defun equal-by-nths-hint-fn
    (clause)
    (declare (xargs :mode :program))
    (b* ((lit (car (last clause))) ((unless (and (consp lit) (eq (car lit) 'equal))) nil)
        (hyps (dumb-negate-lit-lst (butlast clause 1)))
        ((list x y) (cdr lit)))
      `(:use ((:functional-instance equal-by-nths
           (equal-by-nths-lhs (lambda nil ,X))
           (equal-by-nths-rhs (lambda nil ,Y))
           (equal-by-nths-hyp (lambda nil (and . ,HYPS))))))))
  (defmacro equal-by-nths-hint
    nil
    '(equal-by-nths-hint-fn clause)))