• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
      • Break-rewrite
        • Monitor
          • Brr
          • Brr-commands
          • Dmr
          • With-brr-data
          • Geneqv
          • Refinement-failure
          • Break-lemma
          • Why-brr
          • Brr@
          • Cw-gstack
          • Ok-if
          • Windows-installation
          • Brr-near-missp
          • Monitored-runes
          • Unmonitor
          • Monitor!
        • Proof-builder
        • Accumulated-persistence
        • Cgen
        • Forward-chaining-reports
        • Proof-tree
        • Print-gv
        • Dmr
        • With-brr-data
        • Splitter
        • Guard-debug
        • Set-debugger-enable
        • Redo-flat
        • Time-tracker
        • Set-check-invariant-risk
        • Removable-runes
        • Efficiency
        • Explain-near-miss
        • Tail-biting
        • Failed-forcing
        • Sneaky
        • Invariant-risk
        • Failure
        • Measure-debug
        • Dead-events
        • Compare-objects
        • Prettygoals
        • Remove-hyps
        • Type-prescription-debugging
        • Pstack
        • Trace
        • Set-register-invariant-risk
        • Walkabout
        • Disassemble$
        • Nil-goal
        • Cw-gstack
        • Set-guard-msg
        • Find-lemmas
        • Watch
        • Quick-and-dirty-subsumption-replacement-step
        • Profile-all
        • Profile-ACL2
        • Set-print-gv-defaults
        • Minimal-runes
        • Spacewalk
        • Try-gl-concls
        • Near-misses
      • Std
      • Proof-automation
      • Macro-libraries
      • ACL2
        • Theories
        • Rule-classes
        • Proof-builder
        • Recursion-and-induction
        • Hons-and-memoization
        • Events
        • Parallelism
        • History
        • Programming
        • Operational-semantics
        • Real
        • Start-here
        • Debugging
          • Break-rewrite
            • Monitor
              • Brr
              • Brr-commands
              • Dmr
              • With-brr-data
              • Geneqv
              • Refinement-failure
              • Break-lemma
              • Why-brr
              • Brr@
              • Cw-gstack
              • Ok-if
              • Windows-installation
              • Brr-near-missp
              • Monitored-runes
              • Unmonitor
              • Monitor!
            • Proof-builder
            • Accumulated-persistence
            • Cgen
            • Forward-chaining-reports
            • Proof-tree
            • Print-gv
            • Dmr
            • With-brr-data
            • Splitter
            • Guard-debug
            • Set-debugger-enable
            • Redo-flat
            • Time-tracker
            • Set-check-invariant-risk
            • Removable-runes
            • Efficiency
            • Explain-near-miss
            • Tail-biting
            • Failed-forcing
            • Sneaky
            • Invariant-risk
            • Failure
            • Measure-debug
            • Dead-events
            • Compare-objects
            • Prettygoals
            • Remove-hyps
            • Type-prescription-debugging
            • Pstack
            • Trace
            • Set-register-invariant-risk
            • Walkabout
            • Disassemble$
            • Nil-goal
            • Cw-gstack
            • Set-guard-msg
            • Find-lemmas
            • Watch
            • Quick-and-dirty-subsumption-replacement-step
            • Profile-all
            • Profile-ACL2
            • Set-print-gv-defaults
            • Minimal-runes
            • Spacewalk
            • Try-gl-concls
            • Near-misses
          • Miscellaneous
          • Output-controls
          • Macros
          • Interfacing-tools
        • Interfacing-tools
        • Hardware-verification
        • Software-verification
        • Math
        • Testing-utilities
      • Break-rewrite

      Monitor

      To monitor attempted applications of certain rules by the rewriter

      This function stores information about which runes should be monitored during rewriting and what criteria are used to invoke an interactive break when those runes are tried by the rewriter during a subsequent proof attempt.

      Outline

      • Protocol for Using Monitors
      • Example and General Forms
      • Background on Rewriting
      • Criteria for Breaks
      • Example Break Conditions
      • What If No Break Occurs?

      Protocol for Using Monitors

      When a proof fails and you expected it to succeed by applying rules you've proved, it can be helpful to see what happens when (if) the rewriter attempts to use your rules. The break-rewrite utility allows you to monitor each attempt by the rewriter to use specific rules (runes). The basic protocol is that you turn on the break-rewrite utility with brr and then you use this facility, monitor, to specify the rules you want to monitor and the criteria for entering an interactive break. (The variant monitor! is like monitor but also makes sure the break rewrite utility is turned on.) Then you attempt the failed proof again. When a monitored rule is tried and the criteria for that rule are satisfied, the rewriter triggers an interactive break allowing you to query the environment and watch what happens. The break is a read-eval-print loop (in fact it is managed by ld, the same function that provides ACL2's top-level interactive loop). However, it is inside a wormhole, allowing you to see what happening in rewrite. But any changes you make while in this break disappear when the break exits and the wormhole evaporates. See brr-commands for a list of the commands that specifically give you access to parts of the rewriter's state. Such breaks do not allow you to change the course of the rewriter or otherwise guide the proof attempt! Breaks do allow you to abort a proof attempt, which you typically do when you've understood why your rule failed to apply. If you're seeking an interactive proof checker see proof-builder. To learn about the interactive breaks triggered when monitored runes are tried, see break-rewrite.

      The current topic deals with how to install a monitor on a rule.

      Example and General Forms

      Examples:
      (monitor '(:rewrite assoc-of-app) 't)
      (monitor '(:r assoc-of-app) t)
      (monitor 'assoc-of-app t)
      (monitor '(rewrite assoc-of-app) '(:condition t :depth 2))
      (monitor '(rewrite assoc-of-app) '(:condition t :rf t :depth 2))
      
      Keyword Command Examples:
      :monitor assoc-of-app t
      :monitor lemma42 (:condition (equal (brr@ :target) '(F A (G A (H B))))
                        :rf t
                        :depth 2
                        :abstraction (F x (G x y))
                        :lambda t))
      
      General Forms:
      (monitor x criteria)
      (monitor x criteria t) ; a quiet version
      (monitor! x criteria)  ; like quiet monitor but turns on brr first

      where (the value of) x is a rune or more generally a runic designator (see theories) designating one or more runes of classes :rewrite, :definition, :rewrite-quoted-constant, or :linear and (the value of) criteria is a “keyword value list” — a list of alternating keywords and values. If no :condition key is supplied, :condition t is used. If criteria is some term, y, it is treated as the keyword value list (:condition y). The following keywords and values are supported but the details are discussed below.

      • :rf — value must be T or NIL, defaults to NIL
      • :depth — value must be a natural number
      • :abstraction — value must be a term and it is most often an abstraction of the pattern that triggers x obtained by replacing some subterms of that pattern by new variables
      • :lambda — value must be t or nil
      • :condition — value must be a term, called the “break condition” which contains at most one free variable and that variable must be state. An interactive break is initiated only if the :condition term evaluates to non-nil. If not provided, the :condition value defaults to 'T.

      The keys :depth, :abstraction, and :lambda are only relevant when the rule named by x rewrites with an equivalence relation that is a refinement of the equivalence relation the rewriter is obligated to maintain on the current target (see geneqv) and the rule's “pattern” does not match the target. They specify criteria under which a failed match is to be considered a “near miss.” Details are given below.

      The key :rf with value T indicates that breaks are to also occur (if the :condition evaluates to non-nil and) the rune's equivalence relation has failed to be a refinement of the equivalence relation the rewriter is obligated to maintain on the current target. See refinement-failure. If :rf is nil or not provided, refinement failures do not trigger breaks but the other kinds of breaks may occur.

      Keywords other than :condition, :rf, :depth, :abstraction, and :lambda are allowed with no constraints on their values. The purpose of this allowance is so that the user who wants to attach his or her own function to ACL2's brr-near-missp predicate can pass information to that function.

      When successful, monitor arranges for the rewriter to trigger an interactive break when any rule named by x and of the above classes is tried, provided the break-rewrite utility has been turned on — using :brr t, :monitor!, or with-brr-data — and the circumstances of the attempt to apply the rule satisfy the criteria as checked by the function brr-near-missp. Monitor prints to the comment window a list of all the currently-monitored runes and their criteria and returns the error-triple (value :invisible). The so-called “quiet” versions above do no printing.

      Some :rewrite rules are considered ``simple abbreviations''; see simple. These can be be monitored, but are only tried at certain times during the proof. Monitoring is carried out by code inside the rewriter but abbreviation rules may be applied by a special purpose simplifier inside the so-called preprocess phase of a proof. If you desire to monitor an abbreviation rule, a warning will be printed suggesting that you may want to supply the hint :DO-NOT '(PREPROCESS); see hints. Without such a hint, an abbreviation rule can be applied during the preprocess phase of a proof, and no such application will cause an interactive break.

      To remove a rune from the list of monitored runes, use unmonitor. To see which runes are monitored and what their break criteria are, evaluate (monitored-runes).

      Monitor, unmonitor and monitored-runes are macros that expand into expressions involving state. While these macros appear to return the list of monitored runes this is an illusion. They all print monitored rune information to the comment window and then return error-triples instructing ld to print nothing. It is impossible to return the list of monitored runes because it exists only in the wormhole state with which you interact when a break occurs. This allows you to change the monitored runes and their conditions during the course of a proof attempt without changing the state in which the proof is being constructed.

      Note: This list of monitored runes is maintained as a locally bound variable by break-rewrite. For example, suppose that at the top-level of ACL2 the list of monitored runes and their criteria is x. Suppose you then start a proof attempt, a break-rewrite break occurs and in that break you use monitor or unmonitor to change the list of monitored runes to y. Now suppose that you release or abort from the break and ACL2 returns to the top-level. You might think the list of monitored runes is y but in fact it is x. The list is locally bound to value in the caller's environment each time break-rewrite is entered and thus restored to the value in the caller's environment when break-rewrite returns.

      Background on Rewriting

      Before we explain the criteria for triggering breaks we establish some basic terminology about the rewriter. We start with how it applies :rewrite rules. The rewriter walks through a term (typically left-to-right, innermost first) maintaining a list of known assumptions represented as a type-alist. It rewrites each subterm under those assumptions. The subterm the rewriter is currently considering is called the “target”. Each :rewrite rule is derived from some theorem essentially of the form (implies (and hyp1 ... hypn) (equiv lhs rhs)), where the hypi, lhs, and rhs are terms and equiv is known equivalence relation. The lhs is always a function application and the rule derived from the theorem is stored in the ACL2 logical world under the topmost function symbol of the lhs.

      Each time the rewriter steps to a new target it retrieves all the rules stored under the topmost function symbol of the target and tries each rule in turn (provided the rule is enabled and its equiv is a congruence relation in the current context). To try a :rewrite rule the rewriter first attempts to match the lhs to the target. By “match” we mean the rewriter tries to find a substitution for the variables of lhs (consistent with the restrict hints governing the target) such that applying the substitution to the lhs produces the target. If the lhs matches the target, the rewriter then attempts to establish the hypi by rewriting each of them in turn, instantiating each hypi with the substitution. If the instance of each hypi rewrites to true, we know — by the theorem justifying this rule — that that the instance of lhs is equivalent to the corresponding instance of rhs, but the instance of lhs is the target. So the rewriter is logically justified in replacing the occurrence of the target by the instance of rhs and recursively rewrites that. Heuristic considerations may prevent such a replacement, e.g., the instantiated rhs is considered ``too complicated,'' a loop might be detected, etc.

      We can generalize and summarize this description just by saying that each rule has a pattern, some hypotheses, and a result. We say the rule is “about” the topmost function symbol in the pattern. If the pattern matches the target, the hypotheses are true, and heuristic considerations allow, we use the result. :Definition and :rewrite-quoted-constant rules fit easily within this scheme. But :linear rules are a little different. The conclusion of a :linear rule an arithmetic inequality relating subterms, the pattern is one of those subterms, and the result is the entire inequality conclusion. If the hypotheses are all rewritten to true, the result is instantiated and added to the context, telling the rewriter possibly useful information about the target.

      Criteria for Breaks

      If matching fails it is sometimes useful to see why. How did the pattern and the target differ? But since a rule about a given function symbol is tried every time the target has that same topmost function symbol, most rules fail to match much more often than they match. Triggering a break on every failed match is counterproductive. Instead, we introduce the notion of a “near miss” and allow you to set criteria that trigger breaks when a failed match is a near miss. There are three built-in near miss criteria, :depth, :abstraction, and :lambda. We expect any given monitored command will probably specify only one of these three criteria, depending on the pattern in the rule and your judgment of what might be going wrong, but there is nothing preventing you from specifying multiple criteria. If any one of them is satisfied by a failed match a break will occur.

      • :depth n causes a break if the pattern of the rune fails to match the target but the pattern does match down to depth n. For example, the pattern (F X (G X (H Y (I Z)))) fails to match the target (F A (G B C)), but it does match to depth 2. To check this criterion the break utility abstracts the pattern by copying it and replacing every subterm at n by a new variable symbol. The depth n abstractions of (F X (G (H Y (I Z)))) for n=1, 2, and 3 are shown below.
        • n = 1: (F GENSYM0 GENSYM1)
        • n = 2: (F X (G GENSYM0 GENSYM1))
        • n = 3: (F X (G X (H GENSYM0 GENSYM1)))
      • :abstraction apat causes a break if the pattern of the rune fails to match the target but the translation of apat does match the target. This is useful when you want more control over the abstraction of the pattern than :depth gives you. For example, the depth 2 abstraction of (F X (G X (H Y (I Z)))) is (F X (G GENSYM0 GENSYM1)) but you may be interested only in breaks when (F X (G X GENSYM1)) matches the target, i.e., where the first arguments of F and G are the same. If so you could specify the criterion :abstraction (F X (G X Y)) or, equivalently, :abstraction (F X (G X GENSYM1)).
        • :lambda t causes a break if the pattern of the rune fails to match the target but does match everywhere except on quoted lambda constants. This is checked by replacing each quoted lambda object in the pattern by a new variable. This is particularly useful when your rule contains a lambda$ expression, which translates to a quoted lambda constant, but the occurrence of that constant in the target has been rewritten (see rewrite-lambda-object). See also the discussion of “Normal Forms in Loop$ Bodies” in stating-and-proving-lemmas-about-loop$s.

        When a near miss break is caused it prints a message like this

        (1 Breaking (:REWRITE LEMMA) on (F (G A B) A '(A B C D ...)):
        
        The pattern in this rule failed to match the target.  However, this
        is considered a NEAR MISS under the break criteria,
        (:CONDITION 'T :ABSTRACTION (F X1 X2 X3)), specified when this rule
        was monitored.

        The message then displays all of the near miss break criteria that were satisfied and then prompts you for input. This allows you to inspect the pattern (via the brr-commands :lhs or :max-term depending on whether the monitored lemma is a :rewrite rule or a :linear rule. You can inspect the target term with the command :target. The ``+'' versions of those commands, e.g., :lhs+, will print the terms without evisceration. If you want more information about why the pattern of the rule failed to match the target, use the command :explain-near-miss or its ``+'' version. You may exit the break with any of the usual commands, e.g., :ok to continue the proof attempt (because perhaps you determined that the lemma was never supposed to match this particular target) or :a! to abort back to the top-level to fix the problem (because you figured out why the lemma, as written, will not match the intended target).

        On the other hand, suppose the pattern of the rune matches the target. Then the break condition term, i.e., the :condition criterion, is evaluated. The only variable allowed in the break condition term is state, which in the context of the break-rewrite utility is a wormhole state. Suppose the break condition term evaluates to ans. If ans is nil, no break occurs. If ans is t, an interactive break occurs and the user is prompted for commands. Otherwise, ans is expected to be a true list of commands to be fed to the break, i.e., to be appended to standard-oi. Those commands are then executed just as though the user typed them. If they exit the break, the user is not prompted for further commands. If they don't exit the break, the user is prompted for more commands.

        Example Break Conditions

        In order to develop effective break conditions it must be possible to access context sensitive information, i.e., information about the context in which the monitored rune is being tried. The brr@ macro may be used in break conditions to access such information as the term being rewritten and the current governing assumptions. This information is not stored in the proof state but is transferred into the wormhole state when breaks occur. The macro form is (brr@ :sym) where :sym is one of several keyword symbols, including :target (the term being rewritten), :unify-subst (the substitution that instantiates the left-hand side of the conclusion of the rule so that it is the target term), and :type-alist (the governing assumptions). See brr@.

        For example,

        ACL2 !>:monitor (:rewrite assoc-of-app)
                        (equal (brr@ :target) '(app (app a b) c))

        will monitor (:rewrite assoc-of-app) but will cause an interactive break only when the target term is literally (APP (APP A B) C).

        Because break conditions are evaluated in the interaction environment, the user developing a break condition for a given rune can test candidate break conditions before installing them. For example, suppose an unconditional break has been installed on a rune, that an interactive break has occurred and that the user has determined both that this particular application is uninteresting and that many more such applications will likely occur. An appropriate response would be to develop an expression that recognizes such applications and returns nil. Of course, the hard task is figuring out what makes the current application uninteresting. But once a candidate expression is developed, the user can evaluate it in the current context simply to confirm that it returns nil.

        Recall that when a break condition returns a non-nil true list that list is appended to the front of standard-oi. For example,

        ACL2 !>:monitor (:rewrite assoc-of-app) '(:go)

        will cause (:rewrite assoc-of-app) to be monitored and will make the break condition be '(:go). This break condition always evaluates to the non-nil true list (:go). Thus, an interactive break will occur every time (:rewrite assoc-of-app) is tried. The break is fed the command :go. Now the command :go causes break-rewrite to (a) evaluate the attempt to apply the lemma, (b) print the result of that attempt, and (c) exit from the interactive break and let the proof attempt continue. Thus, in effect, the above :monitor merely “traces” the attempted applications of the rune but never causes an interactive break requiring input from the user.

        It is possible to use this feature to cause a conditional break where the effective break condition is tested after the lemma has been tried. For example:

        ACL2 !>:monitor (:rewrite lemma12)
                        '(:unify-subst
                          :eval!
                          :ok-if (or (not (brr@ :wonp))
                                     (not (equal (brr@ :rewritten-rhs) '(foo a))))
                          :rewritten-rhs)

        causes the following behavior when (:rewrite lemma12) is tried. A break always occurs, but it is fed the commands above. The first, :unify-subst, causes break-rewrite to print out the unifying substitution. Then in response to :eval! the lemma is tried but with all runes temporarily unmonitored. Thus no breaks will occur during the rewriting of the hypotheses of the lemma. When the attempt has been made, control returns to break-rewrite (which will print the results of the attempt, i.e., whether the lemma was applied, if so what the result is, if not why it failed). The next command, the :ok-if with its following expression, is a conditional exit command. It means exit break-rewrite if either the attempt was unsuccessful, (not (brr@ :wonp)), or if the result of the rewrite is any term other than (foo a). If this condition is met, the break is exited and the remaining break commands are irrelevant. If this condition is not met then the next command, :rewritten-rhs, prints the result of the application (which in this contrived example is known to be (foo a)). Finally, the list of supplied commands is exhausted but break-rewrite expects more input. Therefore, it begins prompting the user for input. The end result of the above :monitor command is that the rune in question is elaborately traced and interactive breaks occur whenever it rewrites its target to (foo a).

        We recognize that the above break condition is fairly arcane. We suspect that with experience we will develop some useful idioms. For example, it is straightforward now to define macros that monitor runes in the ways suggested by the following names: trace-rune, break-if-target-is, and break-if-result-is. For example, the last could be defined as

        (defmacro break-if-result-is (rune term)
          `(monitor ',rune
                    '(quote (:eval :ok-if
                                   (not (equal (brr@ :rewritten-rhs) ',term))))))

        (Note however that the submitted term must be in translated form.)

        Since we don't have any experience with this kind of control on lemmas we thought it best to provide a general (if arcane) mechanism and hope that the ACL2 community will develop the special cases that we find most convenient.

        Note: The combination of a non-trivial :condition and some near-miss criteria can result in confusing behavior. To get a near-miss break a target has to fail to match the rule's pattern but succeed in matching the near-miss criteria. So the near-miss criteria is irrelevant if the target matches the rule. But to get a break the target must match the rule in such a way that the :condition is satisfied. Failure to get any breaks when you have a non-trivial :condition and a very general near-miss criteria may mean targets matching the near-miss criteria also matched the rule's pattern but failed to satisfy your :condition. Our personal preference when monitoring for near-misses is to use the default :condition of t, at least until we see what kind of matches are arising.

        What If No Break Occurs?

        Suppose rune is a rune that names a rule about some function symbol fn. What does it mean if you've installed a monitor on rune with (:condition t :depth 1) and no break ever occurs? Then one of the following is probably true.

        • the break-rewrite utility is not turned on — you should evaluate (brr t),
        • rune is disabled in the theory used for subgoals mentioning fn — you should enable it either with a global in-theory command or a subgoal-specific :in-theory hint (see hints),
        • rune names an abbreviation rule as discussed above — you should add the hint :DO-NOT '(PREPROCESS) (see hints),
        • the :hints supplied includes a :hands-off list that includes fn — perhaps you should disable other rules about fn (since that is presumably why you put fn on the :hands-off list in the first place) and remove fn from the :hands-off list,
        • the only terms that the rewriter ever encountered with the topmost function fn were within a HIDE,
        • no target with the topmost function symbol fn was ever seen by rewrite — perhaps fn was involved in the conjecture or introduced into the proof attempt but was eliminated by another rewrite.

        The rewriter is complicated. There may be other ways this could happen!