Zulip Chat Archive
Stream: new members
Topic: Proving something is a subfield
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 21:21):
I'm trying to prove that the intersection of two subfields is a subfield -- the problem with using subfield.mk
, or just using {...}
directly, is that subfield
is defined using extends
, so I need to prove that it's a subring -- and by extension that it is an additive subgroup and a submonoid. What's the notation for this?
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 21:21):
This is what I have:
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 21:21):
import algebra.field import field_theory.subfield theorem field_intersect (F1 F2 : set K) [h1 : is_subfield F1] [h2 : is_subfield F2] : is_subfield (F1 ∩ F2) := { --do I need to put something here? inv_mem := (λ x ⟨hx1, hx2⟩, and.intro (is_subfield.inv_mem hx1) (is_subfield.inv_mem hx2)) }
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 21:37):
Got it, it's to_is_subring
.
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:10):
Ok, I suppose one could do without that, too.
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:10):
theorem field_intersect (F1 F2 : set K) [h1 : is_subfield F1] [h2 : is_subfield F2] : is_subfield (F1 ∩ F2) := { zero_mem := and.intro h1.zero_mem h2.zero_mem, one_mem := and.intro h1.one_mem h2.one_mem, add_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (by {have k := h1.add_mem, exact @k a b ha1 hb1}) (by {have k := h2.add_mem, exact @k a b ha2 hb2}), mul_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (by {have k := h1.mul_mem, exact @k a b ha1 hb1}) (by {have k := h2.mul_mem, exact @k a b ha2 hb2}), neg_mem := λ a ⟨ha1, ha2⟩, and.intro (by {have k := h1.neg_mem, exact @k a ha1}) (by {have k := h2.neg_mem, exact @k a ha2}), inv_mem := (λ x ⟨hx1, hx2⟩, and.intro (is_subfield.inv_mem hx1) (is_subfield.inv_mem hx2)) }
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:11):
I got confused because Lean doesn't point out which fields are to be provided when something extends something.
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:14):
On a related note, why doesn't this work?
theorem field_intersect (F1 F2 : set K) [h1 : is_subfield F1] [h2 : is_subfield F2] : is_subfield (F1 ∩ F2) := { zero_mem := and.intro h1.zero_mem h2.zero_mem, one_mem := and.intro h1.one_mem h2.one_mem, add_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (h1.add_mem ha1 hb1) (h2.add_mem ha2 hb2), mul_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (h1.mul_mem ha1 hb1) (h2.mul_mem ha2 hb2), neg_mem := λ a ⟨ha1, ha2⟩, and.intro (h1.neg_mem ha1) (h2.neg_mem ha2), inv_mem := (λ x ⟨hx1, hx2⟩, and.intro (is_subfield.inv_mem hx1) (is_subfield.inv_mem hx2)) }
Or even this:
theorem field_intersect (F1 F2 : set K) [h1 : is_subfield F1] [h2 : is_subfield F2] : is_subfield (F1 ∩ F2) := { zero_mem := and.intro h1.zero_mem h2.zero_mem, one_mem := and.intro h1.one_mem h2.one_mem, add_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (@h1.add_mem a b ha1 hb1) (@h2.add_mem a b ha2 hb2), mul_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (@h1.mul_mem ha1 hb1) (@h2.mul_mem a b ha2 hb2), neg_mem := λ a ⟨ha1, ha2⟩, and.intro (@h1.neg_mem a ha1) (@h2.neg_mem a ha2), inv_mem := (λ x ⟨hx1, hx2⟩, and.intro (is_subfield.inv_mem hx1) (is_subfield.inv_mem hx2)) }
One has to do a have
statement and then construct the statement with the local instance of neg_mem
, etc. Why?
Reid Barton (Jan 10 2019 at 22:15):
What exactly did you write the first time? with to_is_subring
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:15):
Oh, I just nested them all in:
theorem field_intersect (F1 F2 : set K) [h1 : is_subfield F1] [h2 : is_subfield F2] : is_subfield (F1 ∩ F2) := { to_is_subring := { to_is_add_subgroup := { to_is_add_submonoid := { zero_mem := and.intro h1.zero_mem h2.zero_mem, add_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (by {have k := h1.add_mem, exact @k a b ha1 hb1}) (by {have k := h2.add_mem, exact @k a b ha2 hb2}), }, neg_mem := λ a ⟨ha1, ha2⟩, and.intro (by {have k := h1.neg_mem, exact @k a ha1}) (by {have k := h2.neg_mem, exact @k a ha2}), }, to_is_submonoid := { one_mem := and.intro h1.one_mem h2.one_mem, mul_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (by {have k := h1.mul_mem, exact @k a b ha1 hb1}) (by {have k := h2.mul_mem, exact @k a b ha2 hb2}), }, }, inv_mem := (λ x ⟨hx1, hx2⟩, and.intro (is_subfield.inv_mem hx1) (is_subfield.inv_mem hx2)) }
Mario Carneiro (Jan 10 2019 at 22:22):
@h1.neg_mem
doesn't work because you can't mix field notation and @
notation
Mario Carneiro (Jan 10 2019 at 22:22):
you have to write @neg_mem h1
Mario Carneiro (Jan 10 2019 at 22:24):
also you shouldn't project out of a typeclass argument, because it's implicit
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:24):
Re:(@,.) -- I thought so, but I tried that and it doesn't work either -- it just doesn't find is_subfield.neg_mem
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:25):
also you shouldn't project out of a typeclass argument, because it's implicit
What do you mean?
Mario Carneiro (Jan 10 2019 at 22:25):
what do you get when you try it?
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:26):
unknown identifier 'is_subfield.add_mem'
Mario Carneiro (Jan 10 2019 at 22:26):
that means it's not called that
Mario Carneiro (Jan 10 2019 at 22:27):
what is the def of is_subfield
?
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:27):
I tried with is_add_submonoid
too.
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:27):
type mismatch at application is_add_submonoid.add_mem term h1 has type is_subfield F1 : Type but is expected to have type Type ? : Type (?+1)
Mario Carneiro (Jan 10 2019 at 22:27):
you don't pass in h1
at all
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:28):
I did.
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:28):
This is what I'm trying:
theorem field_intersect (F1 F2 : set K) [h1 : is_subfield F1] [h2 : is_subfield F2] : is_subfield (F1 ∩ F2) := { zero_mem := and.intro h1.zero_mem h2.zero_mem, one_mem := and.intro h1.one_mem h2.one_mem, add_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro ((@is_add_submonoid.add_mem h1) a b ha1 hb1) (@h2.add_mem a b ha2 hb2), mul_mem := λ a b ⟨ha1, ha2⟩ ⟨hb1, hb2⟩, and.intro (@h1.mul_mem ha1 hb1) (@h2.mul_mem a b ha2 hb2), neg_mem := λ a ⟨ha1, ha2⟩, and.intro (@h1.neg_mem a ha1) (@h2.neg_mem a ha2), inv_mem := (λ x ⟨hx1, hx2⟩, and.intro (is_subfield.inv_mem hx1) (is_subfield.inv_mem hx2)) }
Mario Carneiro (Jan 10 2019 at 22:28):
i know, stop
Mario Carneiro (Jan 10 2019 at 22:28):
just call it without passing in h1
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:29):
Ah.
Mario Carneiro (Jan 10 2019 at 22:29):
like is_add_submonoid.add_mem ha1 hb1
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:30):
I see, yes this works.
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:30):
But why? What's wrong with trying to feed Lean the class?
Mario Carneiro (Jan 10 2019 at 22:31):
the class is implicit, you aren't supposed to give it, lean finds it by typeclass inference
Mario Carneiro (Jan 10 2019 at 22:31):
you can give it if you use @
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:32):
Yes, why wasn't that working?
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:32):
Using @
and feeding the class?
Mario Carneiro (Jan 10 2019 at 22:32):
that should work, you just need a few more arguments that way, like the types
Mario Carneiro (Jan 10 2019 at 22:33):
I guess it looks something like @is_add_submonoid.add_mem F1 h1 a b ha1 hb1
Mario Carneiro (Jan 10 2019 at 22:34):
oh wait, no it should be something more complicated than just h1
there
Mario Carneiro (Jan 10 2019 at 22:35):
because h1
is a is_subfield
and it needs a is_add_monoid
, it does some typeclass inference to fill the gap
Abhimanyu Pallavi Sudhir (Jan 10 2019 at 22:36):
Oh ok. I think I see why it's best to leave things to Lean's class inference.
Abhimanyu Pallavi Sudhir (Jan 16 2019 at 19:28):
I'm proving a similar theorem and having the same problem again, except this time just leaving Lean to do its type class inference doesn't work (only zero_mem
and one_mem
work):
variables {K L : Type} [discrete_field K] [discrete_field L] (f : K → L) theorem field_intersect' (PL : set (set L)) [H : ∀ J ∈ PL, is_subfield J] : is_subfield (set.sInter PL) := { zero_mem := by { simp, exact λ J HJ, (H J HJ).zero_mem }, one_mem := by { simp, exact λ J HJ, (H J HJ).one_mem }, add_mem := by { simp, exact λ a b ha hb J HJ, is_add_submonoid.add_mem (ha J HJ) (hb J HJ) }, mul_mem := by { simp, exact λ a b ha hb J HJ, is_submonoid.mul_mem (ha J HJ) (hb J HJ) }, neg_mem := by { simp, exact λ a h J HJ, is_add_subgroup.neg_mem (h J HJ) }, inv_mem := by { simp, exact λ a h J HJ, is_subfield.inv_mem (h J HJ) } }
It worked with set.Inter
:
theorem field_intersect (Fi : ι → set K) [hi : ∀ i, is_subfield (Fi i)] : is_subfield (set.Inter Fi) := { zero_mem := by { simp, exact λ i, (hi i).zero_mem }, one_mem := by { simp, exact λ i, (hi i).one_mem }, add_mem := by { simp, exact λ a b ha hb i, is_add_submonoid.add_mem (ha i) (hb i) }, mul_mem := by { simp, exact λ a b ha hb i, is_submonoid.mul_mem (ha i) (hb i) }, neg_mem := by { simp, exact λ a h i, is_add_subgroup.neg_mem (h i) }, inv_mem := by { simp, exact λ a h i, is_subfield.inv_mem (h i) } }
Kevin Buzzard (Jan 16 2019 at 19:46):
Can you post working code so I can cut and paste?
Kevin Buzzard (Jan 16 2019 at 19:46):
PS this "simp, ..." style is discouraged. There are always ways around it.
Abhimanyu Pallavi Sudhir (Jan 16 2019 at 19:53):
import algebra.field import field_theory.subfield import data.polynomial variables {K L : Type} [discrete_field K] [discrete_field L] (f : K → L) theorem field_intersect' (PL : set (set L)) [H : ∀ J ∈ PL, is_subfield J] : is_subfield (set.sInter PL) := { zero_mem := by { simp, exact λ J HJ, (H J HJ).zero_mem }, one_mem := by { simp, exact λ J HJ, (H J HJ).one_mem }, add_mem := by { simp, exact λ a b ha hb J HJ, is_add_submonoid.add_mem (ha J HJ) (hb J HJ) }, mul_mem := by { simp, exact λ a b ha hb J HJ, is_submonoid.mul_mem (ha J HJ) (hb J HJ) }, neg_mem := by { simp, exact λ a h J HJ, is_add_subgroup.neg_mem (h J HJ) }, inv_mem := by { simp, exact λ a h J HJ, is_subfield.inv_mem (h J HJ) } }
Abhimanyu Pallavi Sudhir (Jan 16 2019 at 19:53):
Doesn't that work (for copy-pasting, I mean)?
Kevin Buzzard (Jan 16 2019 at 20:04):
import field_theory.subfield variables {K L : Type} [discrete_field K] [discrete_field L] (f : K → L) theorem field_intersect' (PL : set (set L)) [H : ∀ J ∈ PL, is_subfield J] : is_subfield (set.sInter PL) := { zero_mem := λ J HJ, (H J HJ).zero_mem, one_mem := λ J HJ, (H J HJ).one_mem, add_mem := λ a b ha hb J HJ, let X := (H J HJ).add_mem in X (ha J HJ) (hb J HJ), mul_mem := sorry, neg_mem := sorry, inv_mem := sorry, }
You don't need simp
for stuff like this, you can just spell it out. Although I struggled with add_mem
and I don't know why, it's something to do with classes that I don't understand properly.
Abhimanyu Pallavi Sudhir (Jan 16 2019 at 20:07):
Yeah, the simp
was a legacy from my code for field_intersect
with indexed subsets.
Abhimanyu Pallavi Sudhir (Jan 16 2019 at 20:07):
Interesting that the let ... in
thing works, though -- I did notice that going have
the add_mem
statement (without feeding it any parameters) in tactic mode worked.
Patrick Massot (Jan 16 2019 at 20:30):
This is pretty weird. A more understandable solution would be λ a b ha hb J HJ, by haveI := H J HJ ; exact is_add_submonoid.add_mem (ha J HJ) (hb J HJ),
Patrick Massot (Jan 16 2019 at 20:33):
Of course you can also use the ugly direct term @is_add_submonoid.add_mem _ _ _ (H J HJ).to_is_add_submonoid _ _ (ha J HJ) (hb J HJ)
Last updated: Dec 20 2023 at 11:08 UTC