• 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
      • Events
      • Encapsulate

      Partial-encapsulate

      Introduce functions with some constraints unspecified

      See encapsulate for relevant background. Partial-encapsulate is a variant of encapsulate for which some of the constraints are implicit. This is an advanced capability that is useful when one installs special-purpose code, possibly in raw Lisp, using a trust tag (see defttag).

      Introduction

      The syntax for partial-encapsulate is the same as the syntax of encapsulate, except for the addition of an argument, supporters, which is described below.

      General Form:
      (partial-encapsulate (signature ... signature)
        (f1 ... fk) ; supporters
        ev1
        ...
        evn)

      where, as for encapsulate: each signature is a well-formed signature, each describing a different function symbol, and each evi is an embedded event form (see embedded-event-form). The additional argument (shown above) is a true-list of function symbols, the supporters: it is an error if any such symbol, fi, is not a known function symbol at the time the partial-encapsulate call is evaluated, the exception being that fi may be introduced in one of the signatures. A partial-encapsulate form must satisfy the following three requirements in addition to those of the corresponding encapsulate form: it must have at least one signature, it must not occur within any other encapsulate or partial-encapsulate form that has at least one signature, and every function symbol that it introduces must be specified in one of the signatures.

      A call of partial-encapsulate introduces its signature functions together with its exported theorems, exactly as though it had been the call of encapsulate with the same signatures and events, however with one difference: the partial-encapsulate logically incorporates additional constraints that are not mentioned. This is discussed further below, but for now let us note that because of this difference, a successful evaluation of a partial-encapsulate form results in a special ``unknown-constraints'' designation for the functions introduced by the signatures. Any attempt to access the constraints for those functions will thus fail. Consider the following example, which introduces f as a constrained function symbol that is constrained not only by the property that f returns a boolean, but also by additional, unspecified (implicit) constraints.

      (partial-encapsulate
       ((f (x) t))
       nil
       (local (defun f (x) (declare (xargs :guard t)) (consp x)))
       (defthm booleanp-f
         (booleanp (f x))
         :rule-classes :type-prescription))
      
      (defthm symbolp-f
        (symbolp (f y)))
      
      (encapsulate
       ((g (x) t))
       (local (defun g (x) (consp x)))
       (defthm booleanp-g (booleanp (g x))))

      Then the following fails, even though it would succeed if we replace partial-encapsulate by encapsulate above. The reason is that the partial-encapsulate form allows for constraints beyond just the property that f is boolean. Imagine that special code had been inserted (using a trust tag) for reasoning about f when proving a theorem like symbolp-f that we were now trying to functionally instantiate.

      ; Functional instantiation FAILS because of unknown-constraints on f
      (defthm symbolp-g
        (symbolp (g y))
        :hints (("Goal" :by (:functional-instance symbolp-f (f g)))))

      Supporters and corresponding encapsulate

      A partial-encapsulate represents any encapsulate form that introduces the same function symbols, has the same signatures, and extends the constraints introduced such that every function symbol occurring in at least one of the additional constraints must either be mentioned in one of the evi or be among the list of supporters, (f1 ... fk). We may refer to such an encapsulate form as a ``corresponding encapsulate''. The user of partial-encapsulate should keep in mind such a set of additional constraints. The supporters should thus include all function symbols in the theorems exported from the intended corresponding encapsulate, except that signature functions are always included among the supporters whether specified or not, and hence their inclusion is optional.

      The list of supporters is used for generating proof obligations for a :functional-instance lemma-instance. Specifically, the supporters serve as the ``ancestors'' of the partial encapsulate's signature functions, in the constraint-generation algorithm described in the documentation for constraint. Thus, if supporters are missing that occur in the intended corresponding encapsulate, then functional instantiation may be unsound because some proof obligations fail to be generated. Note that in the typical application described next, where the implicit constraints all specify evaluation results for calls of signature functions as discussed below, the specified list of supporters can simply be nil.

      Applications

      A trust tag (see defttag) is not needed for evaluation of a partial-encapsulate form. However, for a typical application of partial-encapsulate — redefinition of a constrained function in raw Lisp — a trust tag is of course necessary (see defttag). In such a case, the corresponding encapsulate may be viewed as extending the original partial-encapsulate with all theorems of the form (equal (f a1 ... ak) val), ranging over all computations (f a1 ... ak) ever to be evaluated (a finite but potentially huge set) where val is the value returned for (f a1 ... ak). It is the responsibility of the creator of such an application to ensure that all evaluations satisfy the original constraints of the partial-encapsulate.

      Note that in this sort of application — that is, where the implicit constraints all arise from function evaluations — the supporters argument may soundly be nil, since only the signature functions are involved in the implicit constraints (and those functions are automatically included among the supporters, even when not specified by the user).

      For examples of such an application, including explanatory comments, see community-books and books/demos/partial-encapsulate.lisp and books/demos/include-raw-examples/mem-access-sound/mem.lisp.

      Partial-encapsulates are, in essence, also used in the implementation of dependent clause-processors, where the list of supporters might well be non-nil. See define-trusted-clause-processor.

      Implementation

      This section is provided as a reference for those interested, but can probably be safely skipped by most readers.

      Consider the following example.

      ACL2 !>:trans1 (partial-encapsulate
                      ((f0 (x) t))
                      (g0)
                      (local (defun f0 (x) x))
                      (defthm f0-prop
                        (implies (integerp x)
                                 (integerp (f0 x)))))
       (ENCAPSULATE ((F0 (X) T))
                    (LOCAL (DEFUN F0 (X) X))
                    (DEFTHM F0-PROP
                            (IMPLIES (INTEGERP X)
                                     (INTEGERP (F0 X))))
                    (SET-UNKNOWN-CONSTRAINTS-SUPPORTERS G0))
      ACL2 !>

      This example illustrates that a partial-encapsulate call expands to a call of encapsulate obtained by removing the supporters argument, but with the following extra event inserted after given list of events, where (f1 ... fk) is the specified list of supporters.

      (set-unknown-constraints-supporters f1 ... fk)

      The macro, set-unknown-constraints-supporters, extends a table, unknown-constraints-table. As evaluation of the partial-encapsulate concludes, the world is extended so that each signature function has a 'constraint-lst property indicating that its constraints are unknown, but with supporters (``ancestors'', as discussed above) according to that table. This macro call can thus be inserted non-locally within an encapsulate, anywhere after the local function definitions, to make an encapsulate behave like a partial-encapsulate.