Filtering...

duplicity

books/std/lists/duplicity

Included Books

other
(in-package "ACL2")
include-book
(include-book "xdoc/top" :dir :system)
include-book
(include-book "equiv")
include-book
(include-book "rev")
include-book
(include-book "flatten")
other
(defsection duplicity
  :parents (std/lists count no-duplicatesp)
  :short "@(call duplicity) counts how many times the element @('a') occurs
within the list @('x')."
  :long "<p>This function is much nicer to reason about than ACL2's built-in
@(see count) function because it is much more limited:</p>

<ul>

<li>@('count') can operate on either strings or lists; @('duplicity') only
works on lists.</li>

<li>@('count') can consider only some particular sub-range of its input;
@('duplicity') always considers the whole list.</li>

</ul>

<p>Reasoning about duplicity is useful when trying to show two lists are
permutations of one another (sometimes called multiset- or bag-equivalence).  A
classic exercise for new ACL2 users is to prove that a permutation function is
symmetric.  Hint: a duplicity-based argument may compare quite favorably to
induction on the definition of permutation.</p>

<p>This function can also be useful when trying to establish @(see
no-duplicatesp), e.g., see @(see no-duplicatesp-equal-same-by-duplicity).</p>"
  (defund duplicity-exec
    (a x n)
    (declare (xargs :guard (natp n)))
    (if (atom x)
      n
      (duplicity-exec a
        (cdr x)
        (if (equal (car x) a)
          (+ 1 n)
          n))))
  (defund duplicity
    (a x)
    (declare (xargs :guard t :verify-guards nil))
    (mbe :logic (cond ((atom x) 0)
        ((equal (car x) a) (+ 1 (duplicity a (cdr x))))
        (t (duplicity a (cdr x))))
      :exec (duplicity-exec a x 0)))
  (defthm duplicity-exec-removal
    (implies (natp n)
      (equal (duplicity-exec a x n) (+ (duplicity a x) n)))
    :hints (("Goal" :in-theory (enable duplicity duplicity-exec))))
  (verify-guards duplicity
    :hints (("Goal" :in-theory (enable duplicity))))
  (defthm duplicity-when-not-consp
    (implies (not (consp x)) (equal (duplicity a x) 0))
    :hints (("Goal" :in-theory (enable duplicity))))
  (defthm duplicity-of-cons
    (equal (duplicity a (cons b x))
      (if (equal a b)
        (+ 1 (duplicity a x))
        (duplicity a x)))
    :hints (("Goal" :in-theory (enable duplicity))))
  (defthm duplicity-of-list-fix
    (equal (duplicity a (list-fix x)) (duplicity a x))
    :hints (("Goal" :induct (len x))))
  (defcong list-equiv
    equal
    (duplicity a x)
    2
    :hints (("Goal" :in-theory (e/d (list-equiv) (duplicity-of-list-fix))
       :use ((:instance duplicity-of-list-fix) (:instance duplicity-of-list-fix (x x-equiv))))))
  (defthm duplicity-of-append
    (equal (duplicity a (append x y))
      (+ (duplicity a x) (duplicity a y)))
    :hints (("Goal" :induct (len x))))
  (defthm duplicity-of-rev
    (equal (duplicity a (rev x)) (duplicity a x))
    :hints (("Goal" :induct (len x))))
  (defthm duplicity-of-revappend
    (equal (duplicity a (revappend x y))
      (+ (duplicity a x) (duplicity a y)))
    :hints (("Goal" :induct (revappend x y))))
  (defthm duplicity-of-reverse
    (equal (duplicity a (reverse x)) (duplicity a x)))
  (defthm duplicity-when-non-member-equal
    (implies (not (member-equal a x)) (equal (duplicity a x) 0)))
  (defthm duplicity-when-member-equal
    (implies (member-equal a x) (< 0 (duplicity a x)))
    :rule-classes ((:rewrite) (:linear)))
  (defthm duplicity-zero-to-member-equal
    (iff (equal 0 (duplicity a x)) (not (member-equal a x))))
  (defthm no-duplicatesp-equal-when-high-duplicity
    (implies (> (duplicity a x) 1)
      (not (no-duplicatesp-equal x))))
  (defthm duplicity-of-flatten-of-rev
    (equal (duplicity a (flatten (rev x)))
      (duplicity a (flatten x)))
    :hints (("Goal" :induct (len x)))))