Filtering...

remove-duplicates

books/std/lists/remove-duplicates

Included Books

other
(in-package "ACL2")
include-book
(include-book "xdoc/top" :dir :system)
include-book
(include-book "list-defuns")
local
(local (include-book "equiv"))
local
(local (include-book "sets"))
local
(local (include-book "duplicity"))
local
(local (include-book "no-duplicatesp"))
other
(defsection std/lists/remove-duplicates-equal
  :parents (std/lists remove-duplicates)
  :short "Lemmas about @(see remove-duplicates-equal) available in the @(see
std/lists) library."
  (defthm remove-duplicates-equal-when-atom
    (implies (atom x) (equal (remove-duplicates-equal x) nil)))
  (defthm remove-duplicates-equal-of-cons
    (equal (remove-duplicates-equal (cons a x))
      (if (member a x)
        (remove-duplicates-equal x)
        (cons a (remove-duplicates-equal x)))))
  (defthm consp-of-remove-duplicates-equal
    (equal (consp (remove-duplicates-equal x)) (consp x)))
  (defthm len-of-remove-duplicates-equal
    (<= (len (remove-duplicates-equal x)) (len x))
    :rule-classes ((:rewrite) (:linear)))
  (defthm remove-duplicates-equal-of-list-fix
    (equal (remove-duplicates-equal (list-fix x))
      (remove-duplicates-equal x)))
  (defcong list-equiv
    equal
    (remove-duplicates-equal x)
    1
    :hints (("Goal" :in-theory (e/d (list-equiv) (remove-duplicates-equal-of-list-fix))
       :use ((:instance remove-duplicates-equal-of-list-fix) (:instance remove-duplicates-equal-of-list-fix (x x-equiv))))))
  (defthm member-of-remove-duplicates-equal
    (iff (member a (remove-duplicates-equal x)) (member a x)))
  (defthm remove-duplicates-equal-under-set-equiv
    (set-equiv (remove-duplicates-equal x) x)
    :hints (("Goal" :in-theory (enable set-equiv))))
  (defcong set-equiv set-equiv (remove-duplicates-equal x) 1)
  (defthm no-duplicatesp-equal-of-remove-duplicates-equal
    (no-duplicatesp-equal (remove-duplicates-equal x)))
  (defthm duplicity-in-of-remove-duplicates-equal
    (equal (duplicity a (remove-duplicates-equal x))
      (if (member a x)
        1
        0)))
  (defthm remove-duplicates-equal-of-remove
    (equal (remove-duplicates-equal (remove a x))
      (remove a (remove-duplicates-equal x)))))
other
(defsection hons-remove-duplicates
  :parents (std/lists remove-duplicates)
  :short "@(call hons-remove-duplicates) removes duplicate elements from a
list, and is implemented using @(see fast-alists)."
  :long "<p>This operation is similar to the built-in ACL2 function @(see
remove-duplicates-equal), but it has different performance characteristics and
the answer it produces is in an oddly different order.</p>

<p>ACL2's @(see remove-duplicates) function preserves the order of
non-duplicated elements but has a rather inefficient @('O(n^2)')
implementation: it walks down the list, checking for each element whether there
are any more occurrences of the element in the tail of the list.</p>

<p>In contrast, @('hons-remove-duplicates') is a tail-recursive function that
uses a fast alist to record the elements that have been seen so far.  This is
effectively @('O(n)') if we assume that hashing is constant time.  Note,
however.  that this approach requires us to @(see hons) the elements in the
list, which may be quite expensive if the list contains large structures.</p>

<p>Another reasonably efficient way to remove duplicate elements from a list
include sorting the elements, e.g., via @(see set::mergesort).</p>

<p>In the special case of removing duplicates from lists of natural numbers,
@(see nat-list-remove-duplicates) may be offer superior performance.</p>

<p>Even though @('hons-remove-duplicates') has a reasonably nice logical
definition that is merely in terms of @(see remove-duplicates-equal) and @(see
rev), we leave it disabled by default and go ahead and prove various theorems
about it.  These theorems are perhaps best regarded as a back-up plan.  In
general, you may often be able to avoid reasoning about
@('hons-remove-duplicates') via the following, strong @(see set-equiv)
rule:</p>

@(def hons-remove-duplicates-under-set-equiv)"
  (defund hons-remove-duplicates1
    (l tab)
    (declare (xargs :guard t))
    (cond ((atom l) (progn$ (fast-alist-free tab) nil))
      ((hons-get (car l) tab) (hons-remove-duplicates1 (cdr l) tab))
      (t (cons (car l)
          (hons-remove-duplicates1 (cdr l) (hons-acons (car l) t tab))))))
  (defund hons-remove-duplicates
    (l)
    (declare (xargs :guard t :verify-guards nil))
    (mbe :logic (rev (remove-duplicates-equal (rev l)))
      :exec (hons-remove-duplicates1 l (len l))))
  (local (in-theory (enable hons-remove-duplicates1 hons-remove-duplicates)))
  (defthm hons-remove-duplicates-when-atom
    (implies (atom x) (equal (hons-remove-duplicates x) nil)))
  (defthm hons-remove-duplicates-of-list-fix
    (equal (hons-remove-duplicates (list-fix x))
      (hons-remove-duplicates x)))
  (defcong list-equiv
    equal
    (hons-remove-duplicates x)
    1
    :hints (("Goal" :in-theory (e/d (list-equiv)
         (hons-remove-duplicates hons-remove-duplicates-of-list-fix))
       :use ((:instance hons-remove-duplicates-of-list-fix) (:instance hons-remove-duplicates-of-list-fix (x x-equiv))))))
  (defcong set-equiv set-equiv (hons-remove-duplicates x) 1)
  (defthm hons-remove-duplicates-under-set-equiv
    (set-equiv (hons-remove-duplicates x)
      (remove-duplicates-equal x)))
  (defthm no-duplicatesp-equal-of-hons-remove-duplicates
    (no-duplicatesp-equal (hons-remove-duplicates x)))
  (defthm duplicity-in-of-hons-remove-duplicates
    (equal (duplicity a (hons-remove-duplicates x))
      (if (member a x)
        1
        0)))
  (encapsulate nil
    (local (include-book "remove"))
    (local (include-book "../alists/alist-keys"))
    (local (defthm set-difference-equal-of-cons-right
        (equal (set-difference-equal x (cons a y))
          (remove a (set-difference-equal x y)))))
    (local (defthm set-difference-equal-of-list-fix-left
        (equal (set-difference-equal (list-fix x) y)
          (set-difference-equal x y))))
    (local (defthm set-difference-equal-of-append-left
        (equal (set-difference-equal (append a b) c)
          (append (set-difference-equal a c)
            (set-difference-equal b c)))))
    (local (defthm set-difference-equal-of-remove-left
        (equal (set-difference-equal (remove a x) y)
          (remove a (set-difference-equal x y)))))
    (local (defthm rev-of-remove-equal
        (equal (rev (remove-equal a x)) (remove-equal a (rev x)))))
    (local (in-theory (disable remove-of-rev remove-of-set-difference-equal)))
    (local (defthm l0
        (implies (not (hons-assoc-equal x1 tab))
          (equal (cons x1
              (remove-equal x1 (rev (remove-duplicates-equal x2))))
            (rev (remove-duplicates-equal (append x2 (list x1))))))))
    (local (defthm hons-remove-duplicates1-redef
        (equal (hons-remove-duplicates1 x tab)
          (rev (remove-duplicates-equal (set-difference-equal (rev x) (alist-keys tab)))))
        :hints (("Goal" :induct (hons-remove-duplicates1 x tab)))))
    (local (defthm set-difference-equal-of-nil-right
        (equal (set-difference-equal a nil) (list-fix a))))
    (defthmd hons-remove-duplicates1-of-nil
      (equal (hons-remove-duplicates1 x nil)
        (hons-remove-duplicates x)))
    (verify-guards hons-remove-duplicates))
  (local (defthm hons-remove-duplicates1-acl2-count
      (<= (acl2-count (hons-remove-duplicates1 x y))
        (acl2-count x))
      :hints (("Goal" :in-theory (e/d (hons-remove-duplicates1 acl2-count))))
      :rule-classes :linear))
  (defthm acl2-count-of-hons-remove-duplicates
    (<= (acl2-count (hons-remove-duplicates x)) (acl2-count x))
    :hints (("Goal" :in-theory (disable hons-remove-duplicates1 hons-remove-duplicates)
       :use ((:instance hons-remove-duplicates1-of-nil))))
    :rule-classes ((:rewrite) (:linear))))