17.7. Case Analysis
17.7.1. Selection heuristics
grind
decides which sub‑term to split on by combining three sources of signal:
-
Structural flags — quick booleans that enable whole syntactic classes:
-
splitIte
(default true) → split everyif … then … else …
term. -
splitMatch
(default true)→ split on allmatch
expressions (thegrind
analogue of Lean’ssplit
tactic, just likesplitIte
). -
splitImp
(default false) → whentrue
splits on any hypothesisA → B
whose antecedentA
is propositional. Arithmetic antecedents are special‑cased: ifA
is an arithmetic literal (≤
,=
,¬
,Dvd
, …)grind
will split even whensplitImp := false
so the integer solver can propagate facts.
-
👉 Shorthand toggles: by grind -splitIte +splitImp
expands to by grind (splitIte := false) (splitImp := true)
.
-
Global limit —
splits := n
caps the depth of the search tree. Once a branch performsn
splitsgrind
stops splitting further in that branch; if the branch cannot be closed it reports that the split threshold has been reached. -
Manual annotations — you may mark any inductive predicate or structure with
attribute [grind cases] Even Sorted
and grind
will treat every instance of that predicate as a split candidate.
17.7.2. Examples
example (c : Bool) (x y : Nat)
(h : (if c then x else y) = 0) :
x = 0 ∨ y = 0 := c:Boolx:Naty:Nath:(if c = true then x else y) = 0⊢ x = 0 ∨ y = 0
All goals completed! 🐙
example (c : Bool) (x y : Nat)
(h : (if c then x else y) = 0) :
x = 0 ∨ y = 0 := c:Boolx:Naty:Nath:(if c = true then x else y) = 0⊢ x = 0 ∨ y = 0
-- The following fails because we need one case split
fail_if_success c:Boolx:Naty:Nath:(if c = true then x else y) = 0⊢ x = 0 ∨ y = 0
All goals completed! 🐙
-- User‑defined predicate with [grind cases]
inductive Even : Nat → Prop
| zero : Even 0
| step : Even n → Even (n+2)
attribute [grind cases] Even
example (h : Even 5) : False := h:Even 5⊢ False
-- With the attribute,
-- grind immediately splits on the Even hypothesis
All goals completed! 🐙
example (h : Even (n + 2)) : Even n := n:Nath:Even (n + 2)⊢ Even n
All goals completed! 🐙
example (h : y = match x with | 0 => 1 | _ => 2) :
y > 0 := y:Natx:Nath:y =
match x with
| 0 => 1
| x => 2⊢ y > 0
-- `grind` fails if we disable `splitMatch`
fail_if_success y:Natx:Nath:y =
match x with
| 0 => 1
| x => 2⊢ y > 0
All goals completed! 🐙
17.7.3. Tips
-
Increase
splits
only when the goal genuinely needs deeper branching; each extra level multiplies the search space. -
Disable
splitMatch
when large pattern‑matching definitions explode the tree. -
You can combine flags:
by grind -splitMatch (splits := 10) +splitImp
. -
The
[grind cases]
attribute is scoped; you can use the modifierslocal
/scoped
if you only want extra splits inside a section or namespace.
