Zulip Chat Archive
Stream: general
Topic: Simp not collapsing simultaneous matching
l1mey (Sep 10 2025 at 07:42):
Consider this simple inductive type with the function iN.addNsw containing a simultaneous match on the inputs checking for poison. If either aren't poison, it calls iN.addNswBV which the implementation of isn't important here.
The theorem poison_left passes easily by simp, but poison_right doesn't pass by simp. I know this is due to how Lean represents simultaneous matching, but how can I circumvent it while keeping matching (or use if statements)?
Defining a simp lemma for poison_right not be the right way to go, as there are around 20 instructions each with their own variants.
Below is a MWE:
/--
LLVM-style integers with poison value.
-/
inductive iN (bits : Nat) : Type where
| bitvec : BitVec bits → iN bits
| poison : iN bits
export iN (poison bitvec)
protected def iN.addNswBV {n : Nat} (a b : BitVec n) : iN n :=
if BitVec.saddOverflow a b then
poison
else
bitvec (a + b)
protected def iN.addNsw {n} : iN n → iN n → iN n
| poison, _ => poison
| _, poison => poison
| bitvec a, bitvec b => iN.addNswBV a b
theorem poison_left {n} {x : iN n}
: iN.addNsw poison x = (poison : iN n) := by
unfold iN.addNsw
simp
theorem poison_right {n} {x : iN n}
: iN.addNsw x poison = (poison : iN n) := by
unfold iN.addNsw
simp
/-
n : Nat
x : iN n
⊢ (match x, poison with
| poison, x => poison
| x, poison => poison
| bitvec a, bitvec b => iN.addNswBV a b) =
poison
-/
sorry
Jakub Nowak (Sep 10 2025 at 10:02):
In match x, poison there are two possible cases poison, x or x, poison and simp generally can't do case by case analysis like that.
This works:
theorem poison_right {n} {x : iN n}
: iN.addNsw x poison = (poison : iN n) := by
unfold iN.addNsw
cases x <;> simp
After cases x there are two goals and simp can solve each one individually, because there's only one possible branch of the match.
l1mey (Sep 11 2025 at 07:44):
Could I use an if statment instead? I just don't know how to extract out a case without a match.
Jakub Nowak (Sep 11 2025 at 16:55):
Usually you wouldn't use if or match in tactic mode. cases is similar to match. cases x creates two subgoals. In one subgoal x is replaced with bitvec a, in the second subgoals it's replaced with poison.
Not sure if you know <;> syntax, maybe this would be simper to understand:
theorem poison_right {n} {x : iN n}
: iN.addNsw x poison = (poison : iN n) := by
unfold iN.addNsw
unfold iN.addNsw
cases x
· simp
· simp
You can put cursor right after cases x and inspect both subgoals it created.
Last updated: Dec 20 2025 at 21:32 UTC