Zulip Chat Archive
Stream: mathlib4
Topic: Nonconfluent simp for `↑{x | True}`
Jovan Gerbscheid (Dec 19 2024 at 22:33):
Although there is Set.coe_setOf {α : Type u} (p : α → Prop) : ↑{x | p x} = { x // p x }
, the following fails:
example : ↑{x : α | True} = {x : α // True} := by
/-
unsolved goals
α : Type u_1
⊢ ↑Set.univ = { x // True }
-/
simp
I ran into this when trying to show that Nat.card {x : Fin n // True} = n
.
Should there be a simp lemma for rewriting { x // True }
into ↑Set.univ
?
Kevin Buzzard (Dec 19 2024 at 23:19):
This is equality of types so it makes me feel a bit queezy.
Ruben Van de Velde (Dec 19 2024 at 23:21):
Me too, though apparently this case is supported? It seems to be a simp confluence issue; simp [-Set.setOf_true]
solves the original goal
Jovan Gerbscheid (Dec 19 2024 at 23:45):
Here's what I was looking at:
example : {s : Fin 19 → Fin 2 | ∀ n : Fin 19, 10 ≤ n.val → s n = 0}.ncard = 2 ^ 10 := by
rw [← Set.Nat.card_coe_set_eq, Set.coe_setOf,
Nat.card_congr <| @Equiv.subtypePiEquivPi (Fin 19) _ fun n i => 10 ≤ n.val → i = 0]
rw [Nat.card_pi, Fin.prod_univ_add (a := 10) (b := 9)]
simp
rfl
This proof works, but it breaks down when replacing 2 by 200, because the rfl
at the end can't expand that much.
And the only reason for working with types instead of sets was that there seems to be no equivalent to Equiv.subtypePiEquivPi
that works with sets. Unfortunately I can't manage to rewrite back to the setOf
representation, because I can't rewrite under a binder, and simp_rw [← Set.coe_setOf]
gets stuck in a loop.
Eric Wieser (Dec 19 2024 at 23:49):
I would guess the answer is to add a Set
version of Equiv.subtypePiEquivPi
Jovan Gerbscheid (Dec 19 2024 at 23:57):
Another point about Equiv.subtypePiEquivPi is that, similar to Classical.skolem
, it contains a term that usually can't be figured out by unifiication, namely the p a (f a)
in { f : (a : α) → β a // ∀ (a : α), p a (f a) }
. Should the p
be made an explicit parameter? (in Classical.skolem
, it is not so bad because the lemma is the other way around, with the bad term on the rhs)
Jovan Gerbscheid (Dec 19 2024 at 23:59):
Or even better could there be some hint to the unification algorithm for how to deal with such unifications? The difficulty is that the term f a
is not a single free variable, so it can't be abstracted as easily.
Daniel Weber (Dec 20 2024 at 16:05):
Kevin Buzzard said:
This is equality of types so it makes me feel a bit queezy.
As long as it stays defeq it's fine, I think
Jovan Gerbscheid (Dec 20 2024 at 16:10):
The way you would usually encounter {x // True}
in simp is by running simp on {x // some complicated expression}
. So simp would already do some non-defeq rewrites of this type. At that point the defeq rewrite into ↑Set.univ
is not much to worry about.
Daniel Weber (Dec 20 2024 at 16:11):
Does simp
do non-defeq rewrites in types?
Jovan Gerbscheid (Dec 20 2024 at 16:12):
Yes:
example : {x:Nat // n = n} = {x:Nat // True} := by
simp
Daniel Weber (Dec 20 2024 at 16:16):
That's not a type here, it's only a term. For example:
example : Function.const {x:Nat // n = n} 1 ⟨1,rfl⟩ = Function.const {x:Nat // True} 1 ⟨1,.intro⟩ := by
fail_if_success simp [-Function.const_apply]
sorry
Jovan Gerbscheid (Dec 20 2024 at 16:18):
Wait, I thought a term x
is a type if and only if x : Type _
holds.
Daniel Weber (Dec 20 2024 at 16:19):
It is a type, I meant "in contexts where it's a type of some other term"
Jovan Gerbscheid (Dec 20 2024 at 16:24):
But if I add this simp lemma, it does (defeq) simp the type:
import Mathlib
@[simp]
theorem subtype_true (α : Type) : {_x : α // True} = ↑(@Set.univ α) := rfl
example : Function.const {x:Nat // n = n} 1 ⟨1,rfl⟩ = Function.const {x:Nat // True} 1 ⟨1,.intro⟩ := by
simp [-Function.const_apply]
Daniel Weber (Dec 20 2024 at 16:25):
(it's using Function.const_one
since you imported Mathlib)
Jovan Gerbscheid (Dec 20 2024 at 16:25):
Oh oops, it doesn't
Daniel Weber (Dec 20 2024 at 16:25):
it does use it
import Mathlib
@[simp]
theorem subtype_true (α : Type) : {_x : α // True} = ↑(@Set.univ α) := rfl
example : Function.const {x:Nat // n = n} 1 ⟨1,rfl⟩ = Function.const {x:Nat // True} 1 ⟨1,.intro⟩ := by
simp? [-Function.const_apply, -Function.const_one] says simp only [subtype_true]
Daniel Weber (Dec 20 2024 at 16:26):
in any case, that's my point - it only does dsimp
on types, I think
Jovan Gerbscheid (Dec 20 2024 at 16:28):
Hmm, then would it make sense to tag this lemma as a non-dsimp lemma? And is that even possible?
Daniel Weber (Dec 20 2024 at 17:00):
I think that happens if the proof isn't literally rfl
Jovan Gerbscheid (Dec 20 2024 at 18:21):
Then should this lemma be added with the proof id rfl
?
Kyle Miller (Dec 20 2024 at 18:34):
Daniel Weber said:
Does
simp
do non-defeq rewrites in types?
It's not about types vs terms, but which arguments are dependent on what. In Jovan's rewriting types in an equality example, there's no dependence in @Eq X a b
for a
and b
, but X
is depended upon. Types are commonly depended upon, but there are plenty of examples where terms are depended upon. In general, simp
falls back to dsimp
for arguments that are depended upon, with some exceptions (for example, if it's a proof or a Decidable instance that's the dependent, simp
has a procedure to use the full simp
procedure anyway).
Kyle Miller (Dec 20 2024 at 18:49):
For what it's worth, I've found simp lemmas that go between subtypes and coerced sets to cause issues. In the past, it made me think that they should not be simp lemmas at all, and they should be opt-in.
The alternative is to commit to choosing, for example, coerced sets to be the simp normal form for subtypes in general, and to never use subtypes directly.
Jovan Gerbscheid (Dec 20 2024 at 20:23):
Would there be any disadvantage to comitting to coerced set notation as the default, and banishing any occurrences of {x // _} from Mathlib?
Kyle Miller (Dec 20 2024 at 20:35):
Not sure. I floated this idea once awhile back, but I don't remember much agreement, and it seems like a lot of work. (Assuming no complications, I would think this would be a big improvement to normalize!)
Jovan Gerbscheid (Dec 20 2024 at 20:38):
The only thing that worried me a bit is that the definitional equality of the types doesn't hold in reducible transparency, but I don't think this is a problem.
Jovan Gerbscheid (Dec 20 2024 at 20:39):
I also noticed a discrepancy in the pretty printer: it shows {a | True}
, but { a // True }
has extra spaces
Last updated: May 02 2025 at 03:31 UTC