Major Section: EVENTS

Example: (theory-invariant (not (and (member-equal '(:rewrite left-to-right) theory) (member-equal '(:rewrite right-to-left) theory))) :key my-invariant :error nil)where:General Form: (theory-invariant term &key key error)

o

`term`

is a term that uses no variables other than`theory`

and`world`

;o

`key`

is an arbitrary ``name'' for this invariant (if omitted, an integer is generated and used); ando

`:error`

specifies the action to be taken when an invariant is violated -- either`nil`

if a warning is to be printed, else`t`

(the default) if an error is to be caused.

`Theory-invariant`

is an event that adds to or modifies the table
of user-supplied theory invariants that are checked each time a theory
expression is evaluated.
The theory invariant mechanism is provided via a table
(see table) named `theory-invariant-table`

. In fact, the
`theory-invariant`

``event'' is just a macro that expands into a use of the
`table`

event. More general access to the `theory-invariant`

table is provided by `table`

itself. For example, the table
can be inspected or cleared with `table`

; you can clear an individual
theory invariant by setting the invariant to `t`

, or eliminate all theory
invariants with the command `(table theory-invariant-table nil nil :clear)`

.

`Theory-invariant-table`

maps arbitrary keys to terms mentioning, at
most, the variables `theory`

and `world`

. Every time an alleged theory
expression is evaluated, e.g., in the `in-theory`

event or `:`

`in-theory`

hint, each of the terms in `theory-invariant-table`

is evaluated with
`theory`

bound to the runic theory (see theories) obtained from
the theory expression and `world`

bound to the current ACL2 world
(see world). If the result is `nil`

, a message is printed and an error
occurs (except, only a warning occurs if `:error nil`

is specified). Thus,
the table can be thought of as a list of conjuncts. Each `term`

in
the table has a ``name,'' which is just the key under which the term is
stored. When a theory violates the restrictions specified by some term, both
the name and the term are printed. By calling `theory-invariant`

with a
new term but the same name, you can overwrite that conjunct of the theory
invariant; but see the Local Redefinition Caveat at the end of this note.
You may want to avoid using explicit names, since otherwise the subsequent
inclusion of another book that defines a theory invariant with the same name
will override your theory invariant.

Theory invariants are particularly useful in the context of large rule sets intended for re-use. Such sets often contain conflicting rules, e.g., rules that are to be enabled when certain function symbols are disabled, rules that rewrite in opposite directions and thus loop if simultaneously enabled, groups of rules which should be enabled in concert, etc. The developer of such rule sets understands these restrictions and probably documents them. The theory invariant mechanism allows the developer to codify his restrictions so that the user is alerted when they are violated.

Since theory invariants are arbitrary terms, macros may be used to express commonly used restrictions. For example, executing the event

(theory-invariant (incompatible (:rewrite left-to-right) (:rewrite right-to-left)))would subsequently cause an error any time the current theory contained both of the two runes shown. Of course, incompatible is just defined as a macro. Its definition may be inspected with

`:pe incompatible`

.
In order for a `theory-invariant`

event to be accepted, the proposed theory
invariant must be satisfied by the current theory (see current-theory). The
value returned upon successful execution of the event is the key (whether
user-supplied or generated).

Note: If the table event is used directly to `:put`

a term into the
theory invariant table, be aware that the term must be in translated
form. This is enforced by the `value`

invariant for
`theory-invariant-table`

. But the upshot of this is that you will be
unable to use macros in theory invariants stored directly with the
`:put`

table event.

Local Redefinition Caveat. Care needs to be taken when redefining a theory invariant in a local context. Consider the following example.

(theory-invariant (member-equal '(:definition binary-append) theory) :key app-inv)The second pass of the(encapsulate () (local (theory-invariant t :key app-inv)) (in-theory (disable binary-append)) (defthm ...))

`encapsulate`

will fail, because the
`in-theory`

event violates the original `theory-invariant`

and the
`local`

`theory-invariant`

is skipped in the second pass of the
`encapsulate`

. Of course, `local`

`theory-invariant`

s in
books can cause the analogous problem in the second (`include-book`

)
pass of a `certify-book`

. In both cases, though, the theory invariants
are only checked at the conclusion of the (`include-book`

or
`encapsulate`

) event. Indeed, theory invariants are checked at the end of
every event related to theories, including `defun`

, `defthm`

,
`in-theory`

, `encapsulate`

, and `include-book`

, except for events
executed on behalf of an `include-book`

or the second pass of an
`encapsulate`

.