Zulip Chat Archive
Stream: mathlib4
Topic: Tactic state explosion
Patrick Massot (Oct 12 2023 at 18:33):
I am again facing tactic state explosion and I would really like to get an answer because this is a huge pain for teaching. Compare the following Lean 3 code:
import tactic.group
import group_theory.subgroup.basic
variables {G : Type*} [group G]
def conjugate (x : G) (H : subgroup G) : subgroup G :=
{ carrier := {a : G | ∃ h, h ∈ H ∧ a = x * h * x⁻¹},
one_mem' := begin
use 1,
split,
exact H.one_mem,
group
end,
inv_mem' := begin
rintro - ⟨h, h_in, rfl⟩,
use [h⁻¹, H.inv_mem h_in],
group
end,
mul_mem' := begin
rintro - - ⟨h, h_in, rfl⟩ ⟨k, k_in, rfl⟩,
use [h*k, H.mul_mem h_in k_in],
group
end }
lemma conjugate_one (H : subgroup G) : conjugate 1 H = H :=
begin
ext x,
unfold conjugate, -- State isn't great, but better than in Mathlib4
simp
end
with its Lean 4 analogue
import Mathlib.Tactic.Group
import Mathlib.GroupTheory.Subgroup.Basic
variable {G : Type*} [Group G]
def conjugate (x : G) (H : Subgroup G) : Subgroup G where
carrier := {a : G | ∃ h, h ∈ H ∧ a = x * h * x⁻¹}
one_mem' := by
-- Note crazy tactic state here
dsimp
use 1
constructor
exact H.one_mem
group
inv_mem' := by
-- Note crazy tactic state is becoming even crazier
dsimp
rintro - ⟨h, h_in, rfl⟩
use h⁻¹, H.inv_mem h_in
group
mul_mem' := by
-- But here it's getting better??
dsimp
rintro - - ⟨h, h_in, rfl⟩ ⟨k, k_in, rfl⟩
use h*k, H.mul_mem h_in k_in
group
lemma conjugate_one (H : Subgroup G) : conjugate 1 H = H := by
ext x
unfold conjugate -- crazy crazy tactic state
simp
Patrick Massot (Oct 12 2023 at 18:35):
For instance at the beginning of the first proof, you get in Lean 3:
1 ∈ {a : G | ∃ (h : G), h ∈ H ∧ a = x * h * x⁻¹}
which isn't what you would hope for, which is ∃ (h : G), h ∈ H ∧ 1 = x * h * x⁻¹
, but is much better than the Lean 4 version:
1 ∈
{ carrier := {a | ∃ h, h ∈ H ∧ a = x * h * x⁻¹},
mul_mem' :=
(_ :
∀ {a b : G},
a ∈ {a | ∃ h, h ∈ H ∧ a = x * h * x⁻¹} →
b ∈ {a | ∃ h, h ∈ H ∧ a = x * h * x⁻¹} → a * b ∈ {a | ∃ h, h ∈ H ∧ a = x * h * x⁻¹}) }.carrier
Patrick Massot (Oct 12 2023 at 18:36):
And in the last proof, after unfold conjugate
, the Lean 3 goal is displayed as
x ∈ {carrier := {a : G | ∃ (h : G), h ∈ H ∧ a = 1 * h * 1⁻¹}, mul_mem' := _, one_mem' := _, inv_mem' := _} ↔ x ∈ H
which again is not perfect, but the Lean 4 version is:
x ∈
{
toSubmonoid :=
{
toSubsemigroup :=
{ carrier := {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹},
mul_mem' :=
(_ :
∀ {a b : G},
a ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} → a * b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹}) },
one_mem' :=
(_ :
1 ∈
{ carrier := {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹},
mul_mem' :=
(_ :
∀ {a b : G},
a ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
a * b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹}) }.carrier) },
inv_mem' :=
(_ :
∀ {x : G},
x ∈
{
toSubsemigroup :=
{ carrier := {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹},
mul_mem' :=
(_ :
∀ {a b : G},
a ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
a * b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹}) },
one_mem' :=
(_ :
1 ∈
{ carrier := {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹},
mul_mem' :=
(_ :
∀ {a b : G},
a ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
a * b ∈
{a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹}) }.carrier) }.toSubsemigroup.carrier →
x⁻¹ ∈
{
toSubsemigroup :=
{ carrier := {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹},
mul_mem' :=
(_ :
∀ {a b : G},
a ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
a * b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹}) },
one_mem' :=
(_ :
1 ∈
{ carrier := {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹},
mul_mem' :=
(_ :
∀ {a b : G},
a ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
b ∈ {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹} →
a * b ∈
{a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹}) }.carrier) }.toSubsemigroup.carrier) } ↔
x ∈ H
Bhavik Mehta (Oct 12 2023 at 18:38):
I think part of this is because Lean 4 is printing the types of proof fields, which is exploding the state. For me that setting is turned off, and I wonder if for teaching it might be an unhelpful option. In particular, in your first example my goal looks like
1 ∈ { carrier := {a | ∃ h, h ∈ H ∧ a = x * h * x⁻¹}, mul_mem' := _ }.carrier
Patrick Massot (Oct 12 2023 at 18:38):
I don't know whether this is related to new structures vs flat structures or if we are missing a delaborator. But we need to do something. It makes Lean+Mathlib a lot less usable for teaching, and it will also be a problem for ambitious formalization projects.
Patrick Massot (Oct 12 2023 at 18:39):
Do you mean set_option pp.proofs.withType false
?
Bhavik Mehta (Oct 12 2023 at 18:39):
Yes
Patrick Massot (Oct 12 2023 at 18:40):
Indeed this already make things a little better.
Patrick Massot (Oct 12 2023 at 18:40):
Actually a lot better, but still the last tactic state is:
x ∈
{
toSubmonoid :=
{ toSubsemigroup := { carrier := {a | ∃ h, h ∈ H ∧ a = 1 * h * 1⁻¹}, mul_mem' := _ }, one_mem' := _ },
inv_mem' := _ } ↔
x ∈ H
which looks like nested classes are acting badly.
Jireh Loreaux (Oct 12 2023 at 18:41):
Is there a pp.etaReduce
? that seems like it would fix the extra .carrier
?
Patrick Massot (Oct 12 2023 at 18:44):
No there isn't.
Patrick Massot (Oct 12 2023 at 18:47):
And I also don't understand why dsimp
does nothing after unfold conjugate
.
Patrick Massot (Oct 12 2023 at 18:47):
It does in Lean 3.
Thomas Murrills (Oct 12 2023 at 20:14):
Would it be a good idea to have something like pp.flattenStructures
to handle the nested structures part of the issue? Do we have something like that already somewhere? (I couldn’t find it.)
Patrick Massot (Oct 12 2023 at 20:16):
Do you understand why dsimp
doesn't work?
Thomas Murrills (Oct 12 2023 at 20:47):
Hmm, no, I don't; I was thinking about how to clean up the appearance of toSubmonoid
and toSubSemigroup
.
Thomas Murrills (Oct 12 2023 at 21:19):
Ah, I think I (sort of) figured it out: mathlib3's dsimp
can rewrite using subgroup.mem_mk
(now docs#Subgroup.mem_mk), whereas mathlib4's dsimp
can't.
Thomas Murrills (Oct 12 2023 at 21:20):
Why this difference exists, I'm not sure yet.
Thomas Murrills (Oct 12 2023 at 21:37):
I think we're getting closer! It has to do with ↔
-theorems marked @[simp]
which consist of Iff.rfl
. These aren't recognized as dsimp
-worthy in Lean 4, but are in Lean 3. Compare:
Lean 4:
def w : Prop → Prop | p => p
example : w a := by dsimp -- dsimp made no progress
@[simp] theorem defthm : w a ↔ a := Iff.rfl
example : w a := by dsimp -- dsimp made no progress
@[simp] theorem defthm' : w a = a := rfl
example : w a := by dsimp -- unsolved goals `⊢ a`
Lean 3:
def w : Prop → Prop := fun p, p
example (a : Prop) : w a := by dsimp -- (no progress) unsolved goals `⊢ w a`
@[simp] theorem defthm (a : Prop) : w a ↔ a := iff.rfl
example (a : Prop) : w a := by dsimp -- unsolved goals `⊢ a`
Ruben Van de Velde (Oct 12 2023 at 21:38):
https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/dsimp.20and.20Iff.2Erfl
Thomas Murrills (Oct 12 2023 at 21:47):
I see! It doesn't look like an issue was ever filed...should one be?
Thomas Murrills (Oct 12 2023 at 22:23):
I looked around and I think it would be a minor change—we'd just want to mark these theorems as rfl
theorems to simp
internally, which (I think) amounts to just changing the condition
if proof.isAppOfArity ``Eq.refl 2 || proof.isAppOfArity ``rfl 2 then ...
to
if proof.isAppOfArity ``Eq.refl 2 || proof.isAppOfArity ``rfl 2 ||
proof.isAppOfArity ``Iff.refl 1 || proof.isAppOfArity ``Iff.rfl 1 then ...
in isRflProofCore
(in Lean.Meta.Tactic.Simp.SimpTheorems). (EDIT: actually a couple other small changes need to be made, but the gist is the same.) Though I haven't tested it out.
I'd be happy to make an issue + a draft PR to see if it really is this simple, if there's support. :)
Yaël Dillies (Oct 12 2023 at 22:25):
Yes please! It's an annoying regression.
Patrick Massot (Oct 12 2023 at 22:34):
Yes, please.
Thomas Murrills (Oct 12 2023 at 22:36):
On it. :)
Thomas Murrills (Oct 12 2023 at 22:59):
Issue: lean4#2678
Draft PR forthcoming...
Thomas Murrills (Oct 19 2023 at 21:30):
(Subsequent messages moved to #mathlib4 > using Iff
rfl proofs in dsimp
. Apparently I forgot to tick the box that automates this message... :) )
Last updated: Dec 20 2023 at 11:08 UTC