• Top
    • Documentation
    • Books
    • Recursion-and-induction
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
      • Std/lists
      • Std/alists
      • Obags
      • Std/util
      • Std/strings
      • Std/io
      • Std/osets
        • Omaps
        • All-by-membership
        • In
          • Defset
          • Primitives
          • Subset
          • Mergesort
          • Intersect
          • Union
          • Pick-a-point-subset-strategy
          • Delete
          • Difference
          • Cardinality
          • Set
          • Double-containment
          • Intersectp
        • Std/system
        • Std/basic
        • Std/typed-lists
        • Std/bitsets
        • Std/testing
        • Std/typed-alists
        • Std/stobjs
        • Std-extensions
      • Proof-automation
      • Macro-libraries
      • ACL2
      • Interfacing-tools
      • Hardware-verification
      • Software-verification
      • Testing-utilities
      • Math
    • Std/osets

    In

    (in a x) determines if a is a member of the set X.

    The logical definition of in makes no mention of the set order, except implicitly by the use of the set primitives like head and tail.

    The :exec version just inlines the set primitives and does one level of loop unrolling. On CCL, it seems to run about 2.6x faster on the following loop:

    ;; 4.703 sec logic, 1.811 sec exec
    (let ((big-set (loop for i from 1 to 100000 collect i)))
      (gc$)
      (time (loop for i fixnum from 1 to 30000 do (set::in i big-set))))

    There are other ways we could optimize in. Since the set is ordered, we could try to use the set order << to stop early when we ran into an element that is larger than the one we are looking for. For instance, when looking for 1 in the set '(2 3 4), we know that since 1 << 2 that 1 cannot be a member of this set.

    The simplest way to do this is to use << at every element. But set order comparisons can be very expensive, especially when sets contain large cons structures. So while it is easy to contrive situations where exploiting the order would be advantageous, like

    (in 1 '(2 3 4 .... 100000))

    where we could return instantly, there are also times where it would be slower. For instance, on

    (in 100001 '(1 2 3 4 ... 100000))

    we would incur the extra cost of 100,000 calls to <<.

    For this reason, we do not currently implement any short-circuiting. The reasoning is:

    • it is not clear which would be faster in all cases,
    • it is not clear what the typical usage behavior of in is, so even if we wanted to benchmark alternate implementations, it may be hard to come up with the right benchmarking suite
    • both solutions are O(n) anyway, and in isn't a function that should probably be used in any kind of loop so its performance shouldn't be especially critical to anything
    • the current method is arguably no less efficient than an unordered implementation.

    Future note. In principle membership in an ordered list might be done in O(log_2 n). We are considering using a galloping membership check in the future to obtain something along these lines.

    Definitions and Theorems

    Function: in

    (defun in (a x)
           (declare (xargs :guard (setp x)))
           (mbe :logic (and (not (empty x))
                            (or (equal a (head x)) (in a (tail x))))
                :exec (and x
                           (or (equal a (car x))
                               (and (cdr x)
                                    (or (equal a (cadr x))
                                        (in a (cddr x))))))))

    Theorem: in-type

    (defthm in-type
            (or (equal (in a x) t)
                (equal (in a x) nil))
            :rule-classes :type-prescription)

    Theorem: not-in-self

    (defthm not-in-self (not (in x x)))

    Theorem: in-sfix-cancel

    (defthm in-sfix-cancel
            (equal (in a (sfix x)) (in a x)))

    Theorem: never-in-empty

    (defthm never-in-empty
            (implies (empty x) (not (in a x))))

    Theorem: in-set

    (defthm in-set (implies (in a x) (setp x)))

    Theorem: in-tail

    (defthm in-tail
            (implies (in a (tail x)) (in a x)))

    Theorem: in-tail-or-head

    (defthm in-tail-or-head
            (implies (and (in a x) (not (in a (tail x))))
                     (equal (head x) a)))

    Theorem: in-head

    (defthm in-head
            (equal (in (head x) x) (not (empty x))))