Zulip Chat Archive
Stream: mathlib4
Topic: Autogenerate "forall" and "exists" lemmas
Yury G. Kudryashov (Jul 05 2023 at 00:55):
It would be nice to have a tactic that autogenerates lemmas like docs#Sigma.forall and docs#Sigma.exists
Yury G. Kudryashov (Jul 05 2023 at 02:35):
If someone is ready to teach me how to write meta code, I can try to write this.
Yury G. Kudryashov (Jul 05 2023 at 02:35):
E.g., what should I read first?
Patrick Massot (Jul 05 2023 at 06:59):
If you want to learn in a systematic way then you need to read Functional programming in Lean and then the meta-programming book. The indirect way is to try to read meta-code and try to imitate it.
Kyle Miller (Jul 05 2023 at 08:22):
Here's a general plan for a way to generate these lemmas sketched out inside a tactic proof:
import Mathlib.Tactic.ProxyType
import Mathlib.Data.ULift
inductive Foo
| A (n : Nat) (h : n < 5)
| B (b : Bool)
theorem mk_Foo_forall_exists (p : Foo → Prop) : false := by
-- The `proxy_equiv%` machinery also has a direct metaprogramming interface.
-- In the simps I'm making use of the name of the global definition it generates.
let eqv := proxy_equiv% Foo
have forall_lemma := Equiv.forall_congr_left' (p := p) eqv.symm
simp [Foo.proxyTypeEquiv] at forall_lemma
dsimp at forall_lemma
/-
forall_lemma :
(∀ (x : Foo), p x) ↔
(∀ (a : ℕ) (x : a < 5), p (Foo.A a x)) ∧ p (Foo.B false) ∧ p (Foo.B true)
-/
have exists_lemma := Equiv.exists_congr_left (p := p) eqv.symm
simp [Foo.proxyTypeEquiv] at exists_lemma
dsimp at exists_lemma
/-
exists_lemma :
(∃ a, p a) ↔
(∃ a x, p (Foo.A a x)) ∨ p (Foo.B false) ∨ p (Foo.B true)
-/
(Though it's probably better and more general to generate the lemmas more directly from the recursor.)
Kyle Miller (Jul 05 2023 at 08:23):
You could check out how reassoc and elementwise work as a partial model, though it's going to be different since these don't start with a theorem to transform
Kyle Miller (Jul 06 2023 at 00:49):
Here's a rough implementation to generate forall lemmas by analyzing the recursor. It works at least for the examples I've thrown at it.
code
Here are some examples:
@[mk_quantifier_iffs]
inductive Foo (α : Type u)
| A (n : Nat) (h : n < 5)
| B (b : Bool)
| C (x : α)
#check Foo.forall_iff
/-
Foo.forall_iff.{u_1} {α : Type u_1} {P : Foo α → Prop} :
(∀ (t : Foo α), P t) ↔ (∀ (n : ℕ) (h : n < 5), P (Foo.A n h))
∧ (∀ (b : Bool), P (Foo.B b)) ∧ ∀ (x : α), P (Foo.C x)
-/
@[mk_quantifier_iffs]
inductive Primaries
| Red | Green | Blue
#check Primaries.forall_iff
/-
Primaries.forall_iff {P : Primaries → Prop} :
(∀ (t : Primaries), P t) ↔ P Primaries.Red ∧ P Primaries.Green ∧ P Primaries.Blue
-/
attribute [mk_quantifier_iffs] Fin
#check Fin.forall_iff
/-
Fin.forall_iff {n : ℕ} {P : Fin n → Prop} :
(∀ (t : Fin n), P t) ↔ ∀ (val : ℕ) (isLt : val < n), P { val := val, isLt := isLt }
-/
attribute [mk_quantifier_iffs] Eq
#check Eq.forall_iff
/-
Eq.forall_iff.{u_1} {α : Sort u_1} {a✝ : α} {P : (a : α) → a✝ = a → Prop} :
(∀ (a : α) (t : a✝ = a), P a t) ↔ P a✝ (_ : a✝ = a✝)
-/
attribute [mk_quantifier_iffs] List
#check List.forall_iff
/-
List.forall_iff.{u_1} {α : Type u_1} {P : List α → Prop} :
(∀ (t : List α), P t) ↔ P [] ∧ ∀ (head : α) (tail : List α), P tail → P (head :: tail)
-/
Yury G. Kudryashov (Jul 06 2023 at 01:01):
Thanks! Will you PR it? BTW, should we use .forall
/.exists
or .forall_iff
/.exists_iff
?
Kyle Miller (Jul 06 2023 at 01:03):
It doesn't have exists lemmas yet, and it would be nice to more accurately generate the proof of the forall lemma rather than hope solve_by_elim
works (I found that it doesn't work for Acc
). But, yeah, I can PR it once it's ready
Kyle Miller (Jul 06 2023 at 01:05):
For names of the generated lemmas, both options seem fine, except forall
is still a reserved keyword, which is a little awkward
Yury G. Kudryashov (Jul 06 2023 at 01:17):
We have lots of *.forall
lemmas. All of them need to be protected anyway.
Yury G. Kudryashov (Jul 06 2023 at 01:17):
(you don't want many forall_iff
lemmas available after open
either)
Last updated: Dec 20 2023 at 11:08 UTC