Zulip Chat Archive
Stream: mathlib4
Topic: Style for long proofs in instances
Christian K (Feb 05 2025 at 10:42):
Hello,
I want to prove that the Nucleus in Mathlib is a CompleteSemilatticeInf
. I implemented it like this:
variable {s : Set (Nucleus X)}
def sInf_fun (s : Set (Nucleus X)) (x : X) := sInf {j x | j ∈ s}
def sInf_fun_increasing : ∀ (x : X), x ≤ sInf_fun s x := by
simp [sInf_fun, le_apply]
def sInf_fun_idempotent : ∀ (x : X), sInf_fun s (sInf_fun s x) ≤ sInf_fun s x := by
intro x
simp only [sInf_fun, le_sInf_iff, Set.mem_setOf_eq, forall_exists_index, and_imp,
forall_apply_eq_imp_iff₂, sInf_le_iff, lowerBounds]
intro a ha b h
rw [← idempotent]
apply le_trans (h a ha)
refine OrderHomClass.GCongr.mono a ?_
simp_all [sInf_le_iff, lowerBounds]
def sInf_preserves_inf : ∀ (x y : X), sInf_fun s (x ⊓ y) = sInf_fun s x ⊓ sInf_fun s y := by
simp only [sInf_fun, InfHomClass.map_inf]
intro x y
apply le_antisymm
· simp_all only [le_inf_iff, le_sInf_iff, Set.mem_setOf_eq, sInf_le_iff, lowerBounds,
forall_exists_index, and_imp, forall_apply_eq_imp_iff₂, implies_true, and_self]
· simp [le_sInf_iff]
intro a ha
apply And.intro
· apply inf_le_of_left_le
simp_all [sInf_le_iff, lowerBounds]
· apply inf_le_of_right_le
simp_all [sInf_le_iff, lowerBounds]
instance : InfSet (Nucleus X) where
sInf s := ⟨⟨sInf_fun s, sInf_preserves_inf⟩, sInf_fun_idempotent, sInf_fun_increasing⟩
This seems rather ugly to me, but I'm not sure how to do this differently. I separted the proofs into their own lemmas, because they are to big to be done inline at the sInf instance. Can these proofs be golfed considerably and(are there any helpful resources for me to learn how to shorten these? proofs)?. In general, what is the idiomatic way to handle such a case where the proofs are to big to fit in the instance definition?
Michael Rothgang (Feb 05 2025 at 11:11):
I noticed a few details which might be helpful (even thought they may not fully answer your question):
- side comment: I suspect most of your
def
s should belemma
s. (If you run #lint after your code, adefLemma
linter should complain.) - are all these
simp_all
s necessary, or doessimp
also work? - if the latter; simp and exact can usually be combined into
simpa
orsimpa using
: for examplesimp [foo]; exact bar
can usually becomesimpa [foo] using bar
Michael Rothgang (Feb 05 2025 at 11:12):
Since you're asking about idiomatic code, let me also mention the mathlib convention "hypotheses left of colon": instead of having a conclusion "\forall x, ... and starting your proofs with
intro x, it's shorter to make
x` part of the hypotheses.
Michael Rothgang (Feb 05 2025 at 11:15):
A few more comments:
- can
refine OrderHomClass.GCongr.mono a ?_
just becomegcongr
? - the first subgoal in
sInf_preserves_inf
is a terminal simp: unless it's slow, you don't need to squeeze it (i.e. writingsimp
orsimp_all
is just fine) - if you just want shorter code:
apply And.intro
should be equivalent toconstructor
orrefine \<?_, ?_\>
(these should be the correct angular brackets; cannot type them into zulip right now); if one proof is short you can also "inline" it (i.e. writerefine \<by simp, ?_\>
)
Michael Rothgang (Feb 05 2025 at 11:17):
Finally: writing out lemmas needed for these instances seems useful (particularly if you want to use those results separately, at some point in the future, or anticipate somebody wanting to do so).
I have a number of comments now. Let me emphasize that all these are about style: your code works already; these are just things I'd do to make it more mathlib-ready.
Christian K (Feb 06 2025 at 16:35):
Thank you very much for your detailed comments, they are very helpful to me! I implemented them and created a PR.
Last updated: May 02 2025 at 03:31 UTC