Major Section: SWITCHES-PARAMETERS-AND-MODES
Examples: (set-case-split-limitations '(500 100)) (set-case-split-limitations 'nil) (set-case-split-limitations '(500 nil))The first of these prevents
clausify
from trying the
subsumption/replacement (see below) loop if more than 500 clauses are
involved. It also discourages the clause simplifier from splitting into more
than 100 cases at once.Note: This is an event! It does not print the usual event summary but
nevertheless changes the ACL2 logical world and is so recorded.
Moreover, its effect is to set the acl2-defaults-table
, and hence its
effect is local
to the book or encapsulate
form containing it;
see acl2-defaults-table.
See hints for discussion of a related hint, :case-split-limitations
.
Also see splitter for information about reports on rules that may be
responsible for case splits.
General Form: (set-case-split-limitations lst)where
lst
is either nil
(denoting a list of two nil
s), or a list
of length two, each element of which is either nil
or a natural number.
When nil
is used as an element, it is treated as positive infinity. The
default setting is (500 100)
.The first number specifies the maximum number of clauses that may participate in the ``subsumption/replacement'' loop. Because of the expensive nature of that loop (which compares every clause to every other in a way that is quadratic in the number of literals in the clauses), when the number of clauses exceeds about 1000, the system tends to ``go into a black hole,'' printing nothing and not even doing many garbage collections (because the subsumption/replacement loop does not create new clauses so much as it just tries to delete old ones). The initial setting is lower than the threshold at which we see noticeably bad performance, so you probably will not see this behavior unless you have raised or disabled the limit.
Why raise the subsumption/replacement limit? The subsumption/replacement loop cleans up the set of subgoals produced by the simplifier. For example, if one subgoal is
(implies (and p q r) s) [1]and another is
(implies (and p (not q) r) s) [2]then the subsumption/replacement loop would produce the single subgoal
(implies (and p r) s) [3]instead. This cleanup process is simply skipped when the number of subgoals exceeds the subsumption/replacement limit. But each subgoal must nonetheless be proved. The proofs of [1] and [2] are likely to duplicate much work, which is only done once in proving [3]. So with a low limit, you may find the system quickly produces a set of subgoals but then takes a long time to prove that set. With a higher limit, you may find the set of subgoals to be ``cleaner'' and faster to prove.
Why lower the subsumption/replacement limit? If you see the system go into a ``black hole'' of the sort described above (no output, and few garbage collections), it could due to the subsumption/replacement loop working on a large set of large subgoals. You might temporarily lower the limit so that it begins to print the uncleaned set of subgoals. Perhaps by looking at the output you will realize that some function can be disabled so as to prevent the case explosion. Then raise or disable the limit again!
The second number in the case-split-limitations specifies how many case
splits the simplifier will allow before it begins to shut down case
splitting. In normal operation, when a literal rewrites to a nest of
IF
s, the system simplifies all subsequent literals in all the contexts
generated by walking through the nest in all possible ways. This can also
cause the system to ``go into a black hole'' printing nothing except garbage
collection messages. This ``black hole'' behavior is different from than
mentioned above because space is typically being consumed at a prodigious
rate, since the system is rewriting the literals over and over in many
different contexts.
As the simplifier sweeps across the clause, it keeps track of the number of
cases that have been generated. When that number exceeds the second number
in case-split-limitations, the simplifier stops rewriting literals. The
remaining, unrewritten, literals are copied over into the output clauses.
IF
s in those literals are split out, but the literals themselves are not
rewritten. Each output clause is then attacked again, by subsequent
simplification, and eventually the unrewritten literals in the tail of the
clause will be rewritten because the earlier literals will stabilize and stop
producing case splits.
The default setting of 100 is fairly low. We have seen successful proofs in which thousands of subgoals were created by a simplification. By setting the second number to small values, you can force the system to case split slowly. For example, a setting of 5 will cause it to generate ``about 5'' subgoals per simplification.
You can read about how the simplifier works in the book Computer-Aided Reasoning: An Approach (Kaufmann, Manolios, Moore); also see introduction-to-the-theorem-prover for a detailed tutorial on using the ACL2 prover. If you think about it, you will see that with a low case limit, the initial literals of a goal are repeatedly simplified, because each time a subgoal is simplified we start at the left-most subterm. So when case splitting prevents the later subterms from being fully split out, we revisit the earlier terms before getting to the later ones. This can be good. Perhaps it takes several rounds of rewriting before the earlier terms are in normal form and then the later terms rewrite quickly. But it could happen that the earlier terms are expensive to rewrite and do not change, making the strategy of delayed case splits less efficient. It is up to you.
Sometimes the simplifier produces more clauses than you might expect, even
with case-split-limitations in effect. As noted above, once the limit has
been exceeded, the simplifier does not rewrite subsequent literals. But
IF
s in those literals are split out nonetheless. Furthermore, the
enforcement of the limit is -- as described above -- all or nothing: if the
limit allows us to rewrite a literal then we rewrite the literal fully,
without regard for limitations, and get as many cases as ``naturally'' are
produced. It quite often happens that a single literal, when expanded, may
grossly exceed the specified limits.
If the second ``number'' is nil
and the simplifier is going to produce
more than 1000 clauses, a ``helpful little message'' to this effect is
printed out. This output is printed to the system's ``comment window'' not
the standard proofs output.