Zulip Chat Archive
Stream: general
Topic: tactic
orlando (Apr 07 2020 at 07:14):
Hello,
in this post : here Kevin & Patrick show how to create a tactic.
The example of the post is :
meta def AGL_ring : tactic unit := `[simp only [one_a, one_b, a_comp, b_comp], ring] run_cmd add_interactive [`AGL_ring]
In the same post " make a group " there is also a question of tag : @ext
and @simp
!
So my question : is it possible to create a tactic (my_tactic) and a new tag and add gradually new lemma in my tactic ?
For example : add a new tag AGL_ring
and gradualy add new lemma to my tactic !
Thx,
Patrick Massot (Apr 07 2020 at 07:41):
In this case you could use the builtin simp set feature.
Rob Lewis (Apr 07 2020 at 07:41):
The easiest way to do this would be with a custom simp attribute. https://leanprover-community.github.io/mathlib_docs/commands.html#mk_simp_attribute
Patrick Massot (Apr 07 2020 at 07:42):
Oh nice, I was searching for this link and Rob posted it.
Rob Lewis (Apr 07 2020 at 07:42):
You write run_cmd mk_simp_attribute AGL
.
orlando (Apr 07 2020 at 07:42):
Perhaps my question is not clear :innocent:
I give my example :
import tactic variables (R : Type)[comm_ring R] structure R_exp := (a_0 : R) (a_e : R) namespace R_exp @[ext] lemma ext : ∀ {g1 g2 : R_exp R}, g1.a_0 = g2.a_0 → g1.a_e = g2.a_e → g1 = g2 := λ g1 g2, begin intros h1, intros h2, cases g1, cases g2, congr ; try { assumption }, --- end local notation R`[ε]` := R_exp R def mod_ε (a : R[ε]) : R := a.a_0 instance has_coe : has_coe(R[ε]) R := ⟨mod_ε(R)⟩ -- ? bof /- a ↦ a+ 0 ε -/ def of(r : R) : R[ε] := {a_0 := r, a_e := 0} lemma of_ext_0 (r : R) : ((of R r).a_0 = r) := rfl lemma of_ext_e (r : R) : ((of R r).a_e = 0) := rfl lemma coe_of (r : R) : ((of R r) : R) = r := rfl /- element : ε qui va vérifier : ε^2 = 0 -/ def ε : R[ε] := {a_0 := (0 : R), a_e := (1 : R)} lemma ε_ext_0 : (ε R).a_0 = 0 := rfl lemma ε_ext_e : (ε R).a_e = 1 := rfl /- Element : one ! -/ def one : R[ε] := of R (1 : R) instance : has_one (R[ε] ) := ⟨one R⟩ lemma one_ext_0 : (1 : R[ε]).a_0 = 1 := rfl lemma one_ext_e : (1 : R[ε]).a_e = 0 := rfl /- Element !: 0 -/ def zero : R[ε] := of R (0 : R) instance : has_zero (R[ε] ) := ⟨zero R⟩ lemma zero_ext_0 : (0 : R[ε]).a_0 = 0 := rfl lemma zero_ext_e : (0 : R[ε]).a_e = 0 := rfl /- Addition : -/ def add' : (R[ε]) → (R[ε]) → (R[ε]) := λ a b, {a_0 := a.a_0+b.a_0, a_e := a.a_e +b.a_e} instance : has_add (R[ε]) := ⟨add' R⟩ lemma add_ext_0 (a b : R[ε]) : (a+b).a_0 = a.a_0+ b.a_0 := rfl lemma add_ext_e (a b : R[ε]) : (a+b).a_e = a.a_e+ b.a_e := rfl /- We want to show that add' give to R[ε] abelian group structure we print the axiom ! -/ #print add_group /- There is a lot of axiom -/ def neg' : (R[ε]) → (R[ε]) := λ a, {a_0 := - a.a_0, a_e := -a.a_e} instance : has_neg(R[ε]) := ⟨neg' R⟩ lemma neg_ext_0 (a : R[ε]) : (-a).a_0 = -a.a_0 := rfl lemma neg_ext_e (a : R[ε]) : (-a).a_e = -a.a_e := rfl meta def add_ring : tactic unit := `[simp only [neg_ext_0, neg_ext_e, add_ext_0,of_ext_0,of_ext_e, add_ext_e,zero_ext_0,zero_ext_e,one_ext_0,one_ext_e], ring] run_cmd add_interactive [`add_ring] lemma add_assoc' (a b c : R[ε]) : a + b + c = a+(b+c) := begin ext, add_ring, add_ring, end
The problem is : i want next to define multiplication and there is new lemma to add to my tatic !
Rob Lewis (Apr 07 2020 at 07:42):
Then you can tag lemmas with @[AGL] lemma foo ...
orlando (Apr 07 2020 at 07:43):
Ah i don't see the answers ! Thx i read !
Rob Lewis (Apr 07 2020 at 07:43):
and your tactic can say simp only with AGL
Patrick Massot (Apr 07 2020 at 07:44):
He also wanted to tack ring
at the end, hence the Kevin-style tactic.
Rob Lewis (Apr 07 2020 at 07:47):
Note, I misread my own documentation. You should write mk_simp_attribute AGL "describe what these rules are here"
orlando (Apr 07 2020 at 07:53):
Rob : i thinck i understand i add ring as Patrick mention !
import tactic variables (R : Type)[comm_ring R] structure R_exp := (a_0 : R) (a_e : R) namespace R_exp run_cmd mk_simp_attr `AGL meta def AGL_ring : tactic unit := `[simp only with AGL, ring] run_cmd add_interactive [`AGL_ring] @[ext] lemma ext : ∀ {g1 g2 : R_exp R}, g1.a_0 = g2.a_0 → g1.a_e = g2.a_e → g1 = g2 := λ g1 g2, begin intros h1, intros h2, cases g1, cases g2, congr ; try { assumption }, --- end local notation R`[ε]` := R_exp R def mod_ε (a : R[ε]) : R := a.a_0 instance has_coe : has_coe(R[ε]) R := ⟨mod_ε(R)⟩ -- ? bof /- a ↦ a+ 0 ε -/ def of(r : R) : R[ε] := {a_0 := r, a_e := 0} @[AGL]lemma of_ext_0 (r : R) : ((of R r).a_0 = r) := rfl @[AGL]lemma of_ext_e (r : R) : ((of R r).a_e = 0) := rfl @[AGL]lemma coe_of (r : R) : ((of R r) : R) = r := rfl /- element : ε qui va vérifier : ε^2 = 0 -/ def ε : R[ε] := {a_0 := (0 : R), a_e := (1 : R)} @[AGL]lemma ε_ext_0 : (ε R).a_0 = 0 := rfl @[AGL]lemma ε_ext_e : (ε R).a_e = 1 := rfl /- Element : one ! -/ def one : R[ε] := of R (1 : R) instance : has_one (R[ε] ) := ⟨one R⟩ @[AGL]lemma one_ext_0 : (1 : R[ε]).a_0 = 1 := rfl @[AGL]lemma one_ext_e : (1 : R[ε]).a_e = 0 := rfl /- Element !: 0 -/ def zero : R[ε] := of R (0 : R) instance : has_zero (R[ε] ) := ⟨zero R⟩ @[AGL]lemma zero_ext_0 : (0 : R[ε]).a_0 = 0 := rfl @[AGL]lemma zero_ext_e : (0 : R[ε]).a_e = 0 := rfl /- Addition : -/ def add' : (R[ε]) → (R[ε]) → (R[ε]) := λ a b, {a_0 := a.a_0+b.a_0, a_e := a.a_e +b.a_e} instance : has_add (R[ε]) := ⟨add' R⟩ @[AGL]lemma add_ext_0 (a b : R[ε]) : (a+b).a_0 = a.a_0+ b.a_0 := rfl @[AGL]lemma add_ext_e (a b : R[ε]) : (a+b).a_e = a.a_e+ b.a_e := rfl /- We want to show that add' give to R[ε] abelian group structure we print the axiom ! -/ #print add_group /- There is a lot of axiom -/ def neg' : (R[ε]) → (R[ε]) := λ a, {a_0 := - a.a_0, a_e := -a.a_e} instance : has_neg(R[ε]) := ⟨neg' R⟩ @[AGL]lemma neg_ext_0 (a : R[ε]) : (-a).a_0 = -a.a_0 := rfl @[AGL]lemma neg_ext_e (a : R[ε]) : (-a).a_e = -a.a_e := rfl lemma add_assoc' (a b c : R[ε]) : a + b + c = a+(b+c) := begin ext, AGL_ring, AGL_ring, end instance has_repr [has_repr R] : has_repr(R[ε]) := begin sorry, end end R_exp
Rob Lewis (Apr 07 2020 at 07:57):
Looks good! But it's better style if you replace the line
run_cmd mk_simp_attr `AGL
with
mk_simp_attribute AGL "description"
where you describe what the set of AGL rules are supposed to do.
Rob Lewis (Apr 07 2020 at 07:57):
This isn't very important though. :)
orlando (Apr 07 2020 at 08:06):
Hum little change ! Thx Rob ! That's very good !
mk_simp_attribute R_exp_ "trivial simplification" meta def R_exp__ring : tactic unit := `[iterate 2 { simp only with R_exp_, ring}]
orlando (Apr 07 2020 at 08:46):
Another little question : it's possible to simplify all this stuff ! I mean all the axiom result from the same command begin ext, R_exp__ring, end
Is it possible to " factorise " all ?
import tactic variables (R : Type)[comm_ring R] structure R_exp := (a_0 : R) (a_e : R) namespace R_exp mk_simp_attribute R_exp_ "trivial simplification" meta def R_exp__ring : tactic unit := `[iterate 2 { simp only with R_exp_, ring}] run_cmd add_interactive [`R_exp__ring] @[ext] lemma ext : ∀ {g1 g2 : R_exp R}, g1.a_0 = g2.a_0 → g1.a_e = g2.a_e → g1 = g2 := λ g1 g2, begin intros h1, intros h2, cases g1, cases g2, congr ; try { assumption }, --- end local notation R`[ε]` := R_exp R def mod_ε (a : R[ε]) : R := a.a_0 instance has_coe : has_coe(R[ε]) R := ⟨mod_ε(R)⟩ -- ? bof /- a ↦ a+ 0 ε -/ def of(r : R) : R[ε] := {a_0 := r, a_e := 0} @[R_exp_]lemma of_ext_0 (r : R) : ((of R r).a_0 = r) := rfl @[R_exp_]lemma of_ext_e (r : R) : ((of R r).a_e = 0) := rfl @[R_exp_]lemma coe_of (r : R) : ((of R r) : R) = r := rfl /- element : ε qui va vérifier : ε^2 = 0 -/ def ε : R[ε] := {a_0 := (0 : R), a_e := (1 : R)} @[R_exp_]lemma ε_ext_0 : (ε R).a_0 = 0 := rfl @[R_exp_]lemma ε_ext_e : (ε R).a_e = 1 := rfl /- Element !: 0 -/ def zero : R[ε] := of R (0 : R) instance : has_zero (R[ε] ) := ⟨zero R⟩ @[R_exp_]lemma zero_ext_0 : (0 : R[ε]).a_0 = 0 := rfl @[R_exp_]lemma zero_ext_e : (0 : R[ε]).a_e = 0 := rfl /- Addition : -/ def add' : (R[ε]) → (R[ε]) → (R[ε]) := λ a b, {a_0 := a.a_0+b.a_0, a_e := a.a_e +b.a_e} instance : has_add (R[ε]) := ⟨add' R⟩ @[R_exp_]lemma add_ext_0 (a b : R[ε]) : (a+b).a_0 = a.a_0+ b.a_0 := rfl @[R_exp_]lemma add_ext_e (a b : R[ε]) : (a+b).a_e = a.a_e+ b.a_e := rfl /- We want to show that add' give to R[ε] abelian group structure we print the axiom ! -/ #print add_comm_group /- There is a lot of axiom add_comm_group.add : Π {α : Type u} [c : add_comm_group α], α → α → α add_comm_group.add_assoc : ∀ {α : Type u} [c : add_comm_group α] (a b c_1 : α), a + b + c_1 = a + (b + c_1) add_comm_group.zero : Π (α : Type u) [c : add_comm_group α], α add_comm_group.zero_add : ∀ {α : Type u} [c : add_comm_group α] (a : α), 0 + a = a add_comm_group.add_zero : ∀ {α : Type u} [c : add_comm_group α] (a : α), a + 0 = a add_comm_group.neg : Π {α : Type u} [c : add_comm_group α], α → α add_comm_group.add_left_neg : ∀ {α : Type u} [c : add_comm_group α] (a : α), -a + a = 0 add_comm_group.add_comm : ∀ {α : Type u} [c : add_comm_group α] (a b : α), a + b = b + a -/ def neg' : (R[ε]) → (R[ε]) := λ a, {a_0 := - a.a_0, a_e := -a.a_e} instance : has_neg(R[ε]) := ⟨neg' R⟩ @[R_exp_]lemma neg_ext_0 (a : R[ε]) : (-a).a_0 = -a.a_0 := rfl @[R_exp_]lemma neg_ext_e (a : R[ε]) : (-a).a_e = -a.a_e := rfl lemma add_assoc' (a b c : R[ε]) : a + b + c = a+(b+c) := begin ext, R_exp__ring, end lemma zero_add' (a : R[ε]) : 0 + a = a:= begin ext, R_exp__ring, end lemma add_zero' (a : R[ε]) : a+ 0 = a:= begin ext, R_exp__ring, end lemma add_left_neg' (a : R[ε]) : -a + a = 0 := begin ext,R_exp__ring, end lemma add_comm' (a b : R[ε]) : a + b = b + a :=begin ext,R_exp__ring,end #print comm_ring /- structure comm_ring : Type u → Type u fields: comm_ring.add : Π {α : Type u} [c : comm_ring α], α → α → α comm_ring.add_assoc : ∀ {α : Type u} [c : comm_ring α] (a b c_1 : α), a + b + c_1 = a + (b + c_1) comm_ring.zero : Π (α : Type u) [c : comm_ring α], α comm_ring.zero_add : ∀ {α : Type u} [c : comm_ring α] (a : α), 0 + a = a comm_ring.add_zero : ∀ {α : Type u} [c : comm_ring α] (a : α), a + 0 = a comm_ring.neg : Π {α : Type u} [c : comm_ring α], α → α comm_ring.add_left_neg : ∀ {α : Type u} [c : comm_ring α] (a : α), -a + a = 0 comm_ring.add_comm : ∀ {α : Type u} [c : comm_ring α] (a b : α), a + b = b + a comm_ring.mul : Π {α : Type u} [c : comm_ring α], α → α → α comm_ring.mul_assoc : ∀ {α : Type u} [c : comm_ring α] (a b c_1 : α), a * b * c_1 = a * (b * c_1) comm_ring.one : Π (α : Type u) [c : comm_ring α], α comm_ring.one_mul : ∀ {α : Type u} [c : comm_ring α] (a : α), 1 * a = a comm_ring.mul_one : ∀ {α : Type u} [c : comm_ring α] (a : α), a * 1 = a comm_ring.left_distrib : ∀ {α : Type u} [c : comm_ring α] (a b c_1 : α), a * (b + c_1) = a * b + a * c_1 comm_ring.right_distrib : ∀ {α : Type u} [c : comm_ring α] (a b c_1 : α), (a + b) * c_1 = a * c_1 + b * c_1 comm_ring.mul_comm : ∀ {α : Type u} [c : comm_ring α] (a b : α), a * b = b * a -/ def mul' : (R[ε]) → (R[ε]) → (R[ε]) := λ a b,begin exact {a_0 := a.a_0 * b.a_0, a_e := a.a_0 * b.a_e+ a.a_e * b.a_0} end instance : has_mul (R[ε]) := ⟨mul' R⟩ @[R_exp_]lemma mul_ext_0 (a b : R[ε]) : (a * b).a_0 = a.a_0 * b.a_0 := rfl @[R_exp_]lemma mul_ext_e (a b : R[ε]) : (a*b).a_e =a.a_0 * b.a_e+ a.a_e * b.a_0 := rfl lemma mul_assoc' ( a b c : R[ε]) : a * b * c = a * (b * c) := begin ext, R_exp__ring, end def one : R[ε] := of R (1 : R) instance : has_one (R[ε] ) := ⟨one R⟩ @[R_exp_]lemma one_ext_0 : (1 : R[ε]).a_0 = 1 := rfl @[R_exp_]lemma one_ext_e : (1 : R[ε]).a_e = 0 := rfl lemma one_mul' (a : R[ε]) : 1 * a = a := begin ext, R_exp__ring,end lemma mul_one' (a : R[ε]) : a * 1 = a := begin ext, R_exp__ring,end lemma left_distrib' (a b c : R[ε]) : a * (b + c) = a * b + a * c := begin ext, R_exp__ring,end lemma right_distrib' (a b c : R[ε]) : (a + b) *c = a * c + b * c := begin ext, R_exp__ring,end lemma mul_comm' (a b : R[ε]) : a * b = b * a := begin ext, R_exp__ring, end instance : comm_ring (R[ε]) := { add := add' R, add_assoc := add_assoc' R, zero := 0, zero_add := zero_add' R, add_zero := add_zero' R, neg := neg' R, add_left_neg := add_left_neg' R, add_comm := add_comm' R, mul := mul' R, mul_assoc := mul_assoc' R, one := 1, one_mul := one_mul' R, mul_one := mul_one' R, left_distrib := left_distrib' R, right_distrib := right_distrib' R, mul_comm := mul_comm' R, } instance has_repr [has_repr R] : has_repr(R[ε]) := begin sorry, end end R_exp
Kevin Buzzard (Apr 07 2020 at 08:49):
These proofs look fine, but probably in mathlib you would not see it done like this; they would make the comm_ring
structure by something like refine_struct (something); by ext; R_exp__ring
and it would try this proof on all of the fields at once
orlando (Apr 07 2020 at 08:50):
i mean i would write
instance : comm_ring (R[ε]) := by ext, R_exp__ring,
Or something like that, without writing all the lemma just defining mul add one zero
:yum:
Kevin Buzzard (Apr 07 2020 at 08:51):
For example see
instance to_complex.is_ring_hom : is_ring_hom to_complex := by refine_struct {..}; intros; apply complex.ext; simp [sub_eq_add_neg, to_complex]
in data.zsqrtd.gaussian_int
orlando (Apr 07 2020 at 08:51):
ok Kevin !!! thx i take a look :wink:
Kevin Buzzard (Apr 07 2020 at 08:51):
It is the same as your situation: they need to check 10 things, but it's always the same proof -- "ext, then automation"
Kevin Buzzard (Apr 07 2020 at 08:52):
so they do not even name the lemmas, they use this semicolon ;
trick
Patrick Massot (Apr 07 2020 at 09:15):
Why don't you use a quotient ring?
orlando (Apr 07 2020 at 09:19):
hum good question Patrick, because i don't understand how to deal with 'mathlib quotient ring', i try to use but i think i loose all the control ! Probably i miss-understand something :confused:
Patrick Massot (Apr 07 2020 at 09:19):
In the long run I think you'll be much better with mathlib quotient rings.
Kevin Buzzard (Apr 07 2020 at 09:22):
I think it's a good exercise to do it like this, but of course quotient rings would be a much quicker way. But quotients are quite intimidating for beginners.
Yury G. Kudryashov (Apr 07 2020 at 09:23):
Also quotient ring won't give you a nice structure with two fields.
orlando (Apr 07 2020 at 09:28):
I explain my problem with mathlib tool : For example the next step with my is to create a functor sendind , with my construction if , the action on is . If i use, quotient, the problem is that i spent hours dealing with 'mathlib construction' quotient map etc , tensor product etc !
Is that i mean by : i loose control. But i thinck i don't use mathlib in a good maner for the moment :confused:
Kevin Buzzard (Apr 07 2020 at 09:37):
If you don't define it as a quotient, then you will probably at some stage have to prove that given such that , there is an induced map .
Kevin Buzzard (Apr 07 2020 at 09:37):
With the quotient definition you get this for free. But I agree, your approach has the advantage of being more concrete.
orlando (Apr 07 2020 at 09:59):
Yes Kevin ! The good stuff is to use the concret description and the mathlib construction via quotient ! Also, it's a good exercice for beginner, as you tell :grinning:
orlando (Apr 07 2020 at 10:10):
I add i little thing :
instance has_repr [has_repr R] : has_repr(R[ε]) := ⟨λ x, repr x.a_0 ++ "+" ++ repr x.a_e ++ "ε"⟩ #eval (8+ε ℤ)^7 -- result : 2097152+1835008ε
Is It possible to do the calculus with 'mathlib quotient' ?
Kenny Lau (Apr 07 2020 at 10:12):
no
Kenny Lau (Apr 07 2020 at 10:12):
Mario would say don't use quotient
Kenny Lau (Apr 07 2020 at 10:13):
Kevin would say use pari/gp for computations not Lean
orlando (Apr 07 2020 at 10:13):
yes !
Last updated: Dec 20 2023 at 11:08 UTC