• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
    • Macro-libraries
    • ACL2
      • Theories
      • Rule-classes
      • Proof-builder
      • Recursion-and-induction
      • Hons-and-memoization
      • Events
        • Defun
        • Verify-guards
        • Table
        • Mutual-recursion
        • Memoize
        • Make-event
        • Include-book
        • Encapsulate
          • Signature
          • Constraint
          • Partial-encapsulate
          • Redundant-encapsulate
            • Infected-constraints
            • Functional-instantiation
          • Defun-sk
          • Defttag
          • Defstobj
          • Defpkg
          • Defattach
          • Defabsstobj
          • Defchoose
          • Progn
          • Verify-termination
          • Redundant-events
          • Defmacro
          • Defconst
          • Skip-proofs
          • In-theory
          • Embedded-event-form
          • Value-triple
          • Comp
          • Local
          • Defthm
          • Progn!
          • Defevaluator
          • Theory-invariant
          • Assert-event
          • Defun-inline
          • Project-dir-alist
          • Partial-encapsulate
          • Define-trusted-clause-processor
          • Defproxy
          • Defexec
          • Defun-nx
          • Defthmg
          • Defpun
          • Defabbrev
          • Set-table-guard
          • Name
          • Defrec
          • Add-custom-keyword-hint
          • Regenerate-tau-database
          • Defcong
          • Deftheory
          • Defaxiom
          • Deftheory-static
          • Defund
          • Evisc-table
          • Verify-guards+
          • Logical-name
          • Profile
          • Defequiv
          • Defmacro-untouchable
          • Add-global-stobj
          • Defthmr
          • Defstub
          • Defrefinement
          • Deflabel
          • In-arithmetic-theory
          • Unmemoize
          • Defabsstobj-missing-events
          • Defthmd
          • Fake-event
          • Set-body
          • Defun-notinline
          • Functions-after
          • Macros-after
          • Dump-events
          • Defund-nx
          • Defun$
          • Remove-global-stobj
          • Remove-custom-keyword-hint
          • Dft
          • Defthy
          • Defund-notinline
          • Defnd
          • Defn
          • Defund-inline
          • Defmacro-last
        • Parallelism
        • History
        • Programming
        • Operational-semantics
        • Real
        • Start-here
        • Debugging
        • Miscellaneous
        • Output-controls
        • Macros
        • Interfacing-tools
      • Interfacing-tools
      • Hardware-verification
      • Software-verification
      • Math
      • Testing-utilities
    • Encapsulate

    Redundant-encapsulate

    Redundancy of encapsulate events

    For this documentation topic we assume familiarity with encapsulate events and the notion of redundancy for events; see encapsulate and see redundant-events. Until the final remark, we also assume that redefinition is off (see ld-redefinition-action).

    The typical way for an encapsulate event to be redundant is when a syntactically identical encapsulate has already been executed under the same default-defun-mode, default-ruler-extenders, and default-verify-guards-eagerness. But more generally, the encapsulate events need not be syntactically identical; for example, it suffices that they agree when the contents of local sub-events are ignored. Detailed criteria for redundancy are given below, but let us first look at a consequence of the point just made about ignoring the contents of local sub-events. Consider the following sequence of two events.

    (encapsulate
     ()
     (defun f (x) x)
     (local (defthm f-identity
              (equal (f x) x))))
    
    (encapsulate
     ()
     (defun f (x) x)
     (local (defthm false-claim
              (equal (f x) (not x)))))

    You might be surprised to learn that the second is actually redundant, even though false-claim is clearly not a theorem; indeed, its negation is a theorem! The following two points may soften the blow. First, this behavior is as specified above (and is specified more precisely below): the contents of local events are ignored when checking redundancy of encapsulate events. Second, this behavior is sound, because the logical meaning of an encapsulate event is taken from the events that it exports, which do not include events that are local to the encapsulate event.

    Some users, however, want to use encapsulate events for testing in a way that is thwarted by this ignoring of local sub-events. Consider the following sort of example.

    (encapsulate ()
                 (local (defthm test1 ...)))
    
    (encapsulate ()
                 (local (defthm test2 ...)))

    Fortunately, in this case both test1 and test2 will be evaluated. To see why, first note that when a completed encapsulate event with empty signature has introduced no sub-events, then it has no effect at all on the logical world. Thus, the first encapsulate event is not stored in the world; so, the second encapsulate event is not redundant, since it is executed in a world that contains no trace of the first encapsulate event.

    Also see community books std/testing/eval.lisp, make-event/eval-check.lisp, and make-event/eval-tests.lisp for more ways to test in books.

    Here are detailed criteria for redundancy of encapsulate events. First, based on a heuristic (but rather thorough) check, the proposed (new) encapsulate event must be seen as possibly introducing a new name, for example because one of its sub-events, perhaps after some macroexpansion, is an invocation of defun, of defthm, or of certain other events that might introduce a name, including make-event. Second, the two worlds in which each encapsulate event is evaluated must have the same default-defun-modes, the same default-ruler-extenders, and the same default-verify-guards-eagerness. Third, the existing and proposed encapsulate events must contain the same signatures and the same number of top-level sub-events; let k be that number. Finally: for each i < k, the ith top-level events E1 and E2 from the earlier and proposed encapsulates must be related in one of the following ways.

    • E1 and E2 are equal; or
    • E1 is of the form (record-expansion E2 ...), with the exception noted below; or else
    • E1 and E2 are equal after replacing each sub-event of E1 with its make-event expansion and replacing each local sub-event of E1 or E2 by (local (value-triple :elided)). Here, a sub-event of an event E is defined to be either E itself, or a sub-event of a constituent event of E in the case that E is a call of skip-proofs, with-output, with-prover-time-limit, with-prover-step-limit, record-expansion, time$, progn, progn!, or encapsulate itself.

    The second condition has the following exception: it does not apply when the new encapsulate event takes place within an include-book event. (Allowing that would be unsound, as explained in a comment in ACL2 source function corresponding-encaps.)

    Remark. We conclude with some discussion of redundancy of encapsulate events in the presence of redefinition (see ld-redefinition-action). Consider the following sequence of events.

    (encapsulate () (defun foo (x) x))
    
    (redef!) ; Turn on redefinition.
    
    ; not redundant
    (encapsulate () (defun foo (x) (cons x x)))
    
    ; not redundant
    (encapsulate () (defun foo (x) x))

    Note that the last encapsulate call is identical to an earlier event, namely the first one. However, ACL2 never sees that first event when determining whether the last event is redundant. The reason is that when ACL2 searches the world for a corresponding encapsulate event, it does not look back past the most recent definition of foo.

    By contrast, consider what happens when, in a fresh ACL2 session, we evaluate the following sequence instead, obtained by wrapping a make-event call around each defun event.

    (encapsulate () (make-event '(defun foo (x) x)))
    
    (redef!) ; Turn on redefinition.
    
    ; not redundant
    (encapsulate () (make-event '(defun foo (x) (cons x x))))
    
    ; redundant!
    (encapsulate () (make-event '(defun foo (x) x)))

    It may be surprising that the last encapsulate call is redundant. The reason is that it is identical to an earlier encapsulate event. Because of the use of make-event in the final event, ACL2 does not determine that the last event is attempting to define foo, so ACL2 does not limit its search backward through the world as it did in the previous example (where there were no uses of make-event). The moral of the story: when redefinition is involved, it may be best not to rely on one's intuition about redundancy for encapsulate events.