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