Zulip Chat Archive

Stream: lean4

Topic: 'simp'lifying 'match' expressions


Michael Stoll (Jun 10 2024 at 19:51):

Consider

import Mathlib.Data.ZMod.Defs

def foo (a : ZMod 4) : Nat :=
  match a with
  | 0 | 2 => 37
  | 1 => 389
  | 3 => 5077

example :  n : Nat, foo 2 = n := by
  simp only [foo]
  /- ⊢ ∃ n,
  (match 2 with
    | 0 => 37
    | 2 => 37
    | 1 => 389
    | 3 => 5077) =
    n
  -/
  sorry

How can I get the (match 2 with ...) simplified to 37? (They are defeq, so change ∃ n,37 = n would work, but I'd like to get this automatically.)

Note:

  • Replacing foo 2 by foo 0 or foo 1 works (i.e., simp only [foo] resolves the match).
  • Replacing ZMod 4 by Fin 4 in the definition of foo also works.
  • dsimp does not work.

Of course, one could add simp lemmas lemma foo_two : foo 2 = 37 := rfl etc., but when 4 is a bit larger, that gets tedious...

Michael Stoll (Jun 12 2024 at 12:50):

Any ideas?

Damiano Testa (Jun 12 2024 at 12:53):

On the webserver, simp only [foo, exists_eq'] works: is this not suitable?

Damiano Testa (Jun 12 2024 at 12:54):

Or do you want simp to stop before closing the goal?

Michael Stoll (Jun 12 2024 at 12:55):

This is cheating and an artifact of the MWE :smile:
Maybe this is better:

import Mathlib.Data.ZMod.Defs

def foo (a : ZMod 4) : Nat :=
  match a with
  | 0 | 2 => 37
  | 1 => 389
  | 3 => 5077

example : foo 2 = 95 := by
  simp [foo]
  sorry

The point is that simp does not resolve the match (when the argument is at least 2).

Damiano Testa (Jun 12 2024 at 12:57):

example [Nat.AtLeastTwo 2] : foo 2 = 95 := by
  simp [foo]

?

EDIT: this looked correct, but it was probably due to some cached state.

Michael Stoll (Jun 12 2024 at 12:58):

This still doesn't resolve the match.

Adam Topaz (Jun 12 2024 at 13:16):

Does split split the match?

Michael Stoll (Jun 12 2024 at 13:17):

example : foo 2 = 95 := by
  simp [foo]
  split
  all_goals try tauto
  sorry

works, but seems a bit clumsy. ( split leaves four goals.)

Adam Topaz (Jun 12 2024 at 13:18):

Yeah I agree. What if you tag foo with simp?

Damiano Testa (Jun 12 2024 at 13:18):

split is also what aesop uses.

Michael Stoll (Jun 12 2024 at 13:19):

Adam Topaz said:

Yeah I agree. What if you tag foo with simp?

That does not seem to change anything (except that I don't have to give foo explicitly to simp).

Michael Stoll (Jun 12 2024 at 13:34):

I would say resolving match expressions may look like something a simproc could do.

In any case, I find it a bit strange that simp only [foo] does work when foo is defined as Fin 4 → Nat.

Shreyas Srinivas (Jun 12 2024 at 13:50):

I know why. ZMod is a def

Shreyas Srinivas (Jun 12 2024 at 13:50):

See this. I just redefined ZMod as it is in mathlib except it is now reducible:

import Mathlib.Data.ZMod.Defs

namespace Play
abbrev ZMod :   Type
  | 0 => 
  | n + 1 => Fin (n + 1)
abbrev foo (a : ZMod 4) : Nat :=
  match a with
  | 0 | 2 => 37
  | 1 => 389
  | 3 => 5077

example :  n : Nat, foo 2 = n := by
  simp only [foo]
  done
  /- ⊢ ∃ n,37 =n
  -/


end Play

Michael Stoll (Jun 12 2024 at 13:56):

But simp [foo, ZMod] does not work either...

Adam Topaz (Jun 12 2024 at 13:57):

Does it work if you use Fin instead of Zmod?

Michael Stoll (Jun 12 2024 at 13:57):

Yes, as already mentioned.

Adam Topaz (Jun 12 2024 at 13:59):

Sorry, I’m on mobile so I missed it

Adam Topaz (Jun 12 2024 at 14:04):

You can also use change foo (a : Fin _) = _ before the simp and it should (hopefully!) work

Shreyas Srinivas (Jun 12 2024 at 14:04):

simp has no occurrences of ZMod to rewrite I suppose

Shreyas Srinivas (Jun 12 2024 at 14:04):

(deleted)

Shreyas Srinivas (Jun 12 2024 at 14:07):

That was not the case. Once the def of foo was unfolded, even if you had changed 2's type to Fin, it gets rewritten as ZMod.

Matthew Ballard (Jun 12 2024 at 15:47):

Add

instance ZMod.instOfNat:  n m : , OfNat (ZMod n) m
  | 0, m => inferInstanceAs (OfNat  m)
  | n + 1, m => inferInstanceAs (OfNat (Fin (n + 1)) m)

to L105 of file#Data/ZMod/Defs

Michael Stoll (Jun 12 2024 at 15:48):

OK, let me make a PR...

Matthew Ballard (Jun 12 2024 at 15:51):

I didn't check the resulting diamond though

Michael Stoll (Jun 12 2024 at 15:51):

I'll see how it goes.

Michael Stoll (Jun 12 2024 at 17:38):

This runs into problems:

import Mathlib.Data.ZMod.Defs

instance ZMod.instOfNat (n m : ) [Nat.AtLeastTwo m] : OfNat (ZMod n) m := inferInstance

shows that there is (of course) another OfNat instance on ZMod n, and having both makes (perhaps among other problems) ring/ring_nf stop working on ZMod n. (And of course it violates the principle that instances should be "morally unique".) But this other instance (which comes from docs#instOfNatAtLeastTwo) does not help with reducing the match.

Eric Wieser (Jun 13 2024 at 01:37):

Matthew Ballard said:

Add

instance ZMod.instOfNat:  n m : , OfNat (ZMod n) m
  | 0, m => inferInstanceAs (OfNat  m)
  | n + 1, m => inferInstanceAs (OfNat (Fin (n + 1)) m)

to L105 of file#Data/ZMod/Defs

m should not be part of the match here

Kevin Buzzard (Jun 14 2024 at 10:39):

0 should map to 11, right?


Last updated: May 02 2025 at 03:31 UTC