Zulip Chat Archive

Stream: Analysis I

Topic: Regression with simps?


Dan Abramov (Jul 31 2025 at 22:14):

I've noticed https://github.com/teorth/analysis/pull/251 broke one of my proofs:

theorem SetTheory.Set.image_preimage_f_3_4_2' :
    image f_3_4_2 (preimage f_3_4_2 {1,2,3})  {1,2,3} := by
  intro h
  have : 1  image f_3_4_2 (preimage f_3_4_2 {1, 2, 3}) := by
    simp [mem_image] -- This simp no longer works
  simp_all

Before the change, it worked and unrolled into

    simp only [mem_image, Object.ofnat_eq, nat_coe_eq_iff, mul_eq_one, OfNat.ofNat_ne_one,
      false_and, and_false, exists_const, not_false_eq_true]

After the change, it doesn't work and unrolls to

    simp only [pair_comm, replacement_axiom, Object.ofnat_eq, specification_axiom'',
      Subtype.coe_eta, mem_triple, nat_coe_eq_iff, mul_eq_one, OfNat.ofNat_ne_one, false_and, ne_eq,
      OfNat.ofNat_ne_zero, not_false_eq_true, mul_eq_left₀, false_or, exists_prop, Subtype.exists,
      not_exists, not_and, not_or]
  /-
  ⊢ ∀ (x : Object) (x_1 : x ∈ nat), 1 = ↑(2 * nat_equiv.symm ⟨x, ⋯⟩) → x ∈ nat → ¬2 * nat_equiv.symm ⟨x, ⋯⟩ = 3 ∧ ¬nat_equiv.symm ⟨x, ⋯⟩ = 1
  -/

I don't mind the change per se (easily fixable by changing my code to simp; aesop) but I was wondering whether this could indicate a legit regression? Like maybe some of the ones from https://github.com/teorth/analysis/pull/251 were unsafe to mark as simp for whatever reason. I don't have a mental model for which theorems are OK to mark with simp.

Dan Abramov (Jul 31 2025 at 22:31):

It seems to narrow down to having @[simp] on replacement_axiom.

If that simp is present, it seems like it gets unfolded first, and turns

 1  image f_3_4_2 (preimage f_3_4_2 {1, 2, 3})

into

 ¬∃ x, 1 = (f_3_4_2 x)  x  preimage f_3_4_2 {1, 2, 3}

which for some reason leads into corner.

But if I exclude replacement_axiom and instead let mem_image simplify first with simp [mem_image], I get

 ¬∃ x, x  preimage f_3_4_2 {1, 2, 3}  (f_3_4_2 x) = 1

And then it's able to continue.

I wonder if somehow 1 = ↑(f_3_4_2 x) is easier to unroll than ↑(f_3_4_2 x) = 1 later?

Dan Abramov (Jul 31 2025 at 22:33):

An alternative fix that seems to work is to change SetTheory.Set.image to say fun x y ↦ f x = y rather than fun x y ↦ y = f x in its definition. Which I guess matches mem_image.

Kyle Miller (Jul 31 2025 at 22:34):

SetTheory.Set.pair_comm looks like it shouldn't be a simp lemma

Lemmas like SetTheory.Set.subset_inter_iff and SetTheory.Set.union_subset_iff can be problematic since they're "nonlinear" (there are more occurrences of a variable after the rewrite)

Kyle Miller (Jul 31 2025 at 22:34):

Dan Abramov said:

I wonder if somehow 1 = ↑(f_3_4_2 x) is easier to unroll than ↑(f_3_4_2 x) = 1 later?

That seems worth looking into. Have you used simp? to see which lemmas are applying?

Dan Abramov (Jul 31 2025 at 22:35):

Yup, that's the simp only lists above in the first message

Dan Abramov (Jul 31 2025 at 22:36):

This is the list I get if I change y = f x to f x = y:

    simp only [pair_comm, replacement_axiom, Object.ofnat_eq, nat_coe_eq_iff, mul_eq_one,
      OfNat.ofNat_ne_one, false_and, specification_axiom'', Subtype.coe_eta, mem_triple, ne_eq,
      OfNat.ofNat_ne_zero, not_false_eq_true, mul_eq_left₀, false_or, exists_prop, exists_const]

It works.

And this is the list that doesn't work (without that change):

    simp only [pair_comm, replacement_axiom, Object.ofnat_eq, specification_axiom'',
      Subtype.coe_eta, mem_triple, nat_coe_eq_iff, mul_eq_one, OfNat.ofNat_ne_one, false_and, ne_eq,
      OfNat.ofNat_ne_zero, not_false_eq_true, mul_eq_left₀, false_or, exists_prop, Subtype.exists,
      not_exists, not_and, not_or]

Dan Abramov (Jul 31 2025 at 22:43):

Narrowing it down a bit.

On main, this:

simp only [replacement_axiom, Object.ofnat_eq, nat_coe_eq_iff, mul_eq_one, OfNat.ofNat_ne_one, false_and]

leads to ¬∃ x, 1 = ↑(2 * nat_equiv.symm x) ∧ ↑x ∈ preimage f_3_4_2 {1, 2, 3}.

But if I edit SetTheory.Set.image to f x = y, then the same list leads to

 ¬∃ x, False

Dan Abramov (Jul 31 2025 at 22:50):

Ok I think this is because mul_eq_one doesn't simplify 1 = ↑(2 * nat_equiv.symm x) but it does simplify ↑(2 * nat_equiv.symm x) = 1. This is why unfolding it as f x = y works but y = f x doesn't. And before replacement_axiom was marked as a simp, it wouldn't get unfolded at all and was being unfolded by mem_image which does have f x = y.

I guess this is a case of me relying on fragile impl details?

Dan Abramov (Jul 31 2025 at 22:52):

Probably not a bad idea to align the order between y and f x between definitions to make it more consistent

Dan Abramov (Jul 31 2025 at 22:53):

And yea I agree pair_comm probably shouldn't be @[simp] although not the issue in this case

Terence Tao (Jul 31 2025 at 22:56):

Marking SetTheory.Set.pair_comm as @[simp] was definitely a mistake, I will revert that now, as well as swap the equality in SetTheory.Set.image (at first I thought this was due to the way it was written in the book, but actually the book doesn't state either form).

On the other hand, Mathlib marks docs#Set.subset_inter_iff and docs#Set.union_subset_iff as @[simp] so I assume these particular types of simp lemmas are "battle-tested"?

Dan Abramov (Jul 31 2025 at 22:59):

Thanks, confirmed it works after a rebase

Kyle Miller (Jul 31 2025 at 23:43):

Terence Tao said:

I assume these particular types of simp lemmas are "battle-tested"?

I'm not really sure. Distributivity lemmas sometimes are and sometimes aren't simp lemmas, and it's not clear why or why not.

Those subset lemmas are simp lemmas, docs#map_mul is a simp lemma, yet docs#mul_add is not a simp lemma.

(Sometimes I've thought it would be nice if we had an expand simp set that contained all the distribution lemmas.)

Kyle Miller (Jul 31 2025 at 23:45):

Dan Abramov said:

mul_eq_one

Interesting, mul_eq_one is a simp lemma, but there's no one_eq_mul... That seems like a little bit of an oversight in the simp set.

Possibly the answer is that there needs to be a 1 = x <-> x = 1 simp lemma, if _ = 1 is decided to be the simp normal form.


Last updated: Dec 20 2025 at 21:32 UTC