Zulip Chat Archive
Stream: new members
Topic: add_group, has_neg, and subtypes defined as sums
Eric Wieser (Jun 27 2020 at 20:51):
Here's my MVE:
import algebra.group.hom
universe u
section
-- these sorry's I have, but aren't relevant
parameters {G : Type u} [add_group G]
def Bᵣ (r : ℕ) : Type u := {g : G // sorry}
instance Bᵣ_has_neg (r : ℕ) : has_neg (Bᵣ r) := sorry
/- an r-vector must be decomposable into r blades-/
def is_rvector (r : nat) (v : G) : Prop :=
∃ (bs : list (Bᵣ r)),
v = (bs.map subtype.val).sum
/- the algebra of a single grade -/
def Gᵣ (r : ℕ) := {g : G // is_rvector r g}
-- I don't know how to obtain this without tediously expanding `list.sum` for every case.
instance g (r : ℕ) : add_group (Gᵣ r) := sorry
end
Is there a trivial way to create an instance
add_group (Gᵣ r)
? I can prove the properties one by one, but I get the feeling that mathlib already has what I need if I define is_rvector
in a clever way.
Eric Wieser (Jun 27 2020 at 21:14):
To help ward off accidental XY problems here, my actual problem is
given a subtype
Br
ofG
where[has_neg Br]
and[add_group G]
, how do I form the subtypeGr
which is the smallest subgroup ofG
which contains all ofBr
?
Kenny Lau (Jun 27 2020 at 21:19):
it might be better to work with sets instead of subtypes
Eric Wieser (Jun 27 2020 at 21:23):
Is there any way to convert back an forth between the two?
Eric Wieser (Jun 27 2020 at 21:32):
I think you've set me on the right track, thanks
Jalex Stark (Jun 28 2020 at 06:35):
I think you're looking for this? https://leanprover-community.github.io/mathlib_docs/algebra/pointwise.html
Jalex Stark (Jun 28 2020 at 06:35):
or maybe this https://leanprover-community.github.io/mathlib_docs/algebra/pi_instances.html
Eric Wieser (Jun 28 2020 at 07:52):
I ended up trying to use add_subgroup.closure (set_of (Bᵣ r).property)
Kenny Lau (Jun 28 2020 at 07:56):
@Eric Wieser I'm saying, in the first place don't have B_r be a subtype to begin with
Eric Wieser (Jun 28 2020 at 07:56):
I think I want it to be a subtype because I want to define functions over the objects in the set
Kenny Lau (Jun 28 2020 at 07:57):
and having it be a set allows for this flexibility, because you can coerce a set into a subtype but not the other way round
Kenny Lau (Jun 28 2020 at 07:57):
at least idiomatically
Eric Wieser (Jun 28 2020 at 07:57):
In that ↥
will be invoked automatically?
Mario Carneiro (Jun 28 2020 at 07:57):
yes
Kenny Lau (Jun 28 2020 at 07:58):
and you can have additive closure of a set but not of a subtype
Kenny Lau (Jun 28 2020 at 07:59):
at least idiomatically
Kenny Lau (Jun 28 2020 at 07:59):
and you can perform set operations (intersections, unions, insertions, etc) on a set but not on a subtype
Kenny Lau (Jun 28 2020 at 07:59):
at least idiomatically
Eric Wieser (Jun 28 2020 at 07:59):
Thanks for the tips
I actually had both Gᵣ_subgroup
and Gᵣ (r : ℕ) := ↥(Gᵣ_subgroup r)
.
Sounds like there is no need for the separate definitions
Kenny Lau (Jun 28 2020 at 08:00):
and you don't need the second one
Kenny Lau (Jun 28 2020 at 08:01):
aliases are not idiomatic because rw
and simp
and etc cannot see through it
Eric Wieser (Jun 28 2020 at 08:01):
A follow-up question - if I have P := set_of p
, and can prove ∀ x : α, p x
, can I show P = \alpha
?
Kenny Lau (Jun 28 2020 at 08:01):
which I sometimes find annoying as well -- why can't I just make aliases that everything can see through?
Kenny Lau (Jun 28 2020 at 08:01):
set_of
is also not idiomatic: use { x | P x }
instead
Kenny Lau (Jun 28 2020 at 08:02):
\alpha
is not a set; you mean set.univ
Kenny Lau (Jun 28 2020 at 08:02):
and you can prove that using lemmas about set.univ
Eric Wieser (Jun 28 2020 at 08:02):
I think I was hoping to show type equality
Mario Carneiro (Jun 28 2020 at 08:02):
set equality is what you want
Mario Carneiro (Jun 28 2020 at 08:02):
type equality is not meaningful
Eric Wieser (Jun 28 2020 at 08:03):
Perhaps I was misdirected by the codewars kata asking me to prove bool != nat into thinking that such a proof was common :)
Mario Carneiro (Jun 28 2020 at 08:03):
heh
Kenny Lau (Jun 28 2020 at 08:03):
aha
Kenny Lau (Jun 28 2020 at 08:03):
yeah we don't use type equalities
Kenny Lau (Jun 28 2020 at 08:04):
we don't ask whether two types are equal
Kenny Lau (Jun 28 2020 at 08:04):
just like in ZFC you don't ask whether 37 is an element of the real number pi
Eric Wieser (Jun 28 2020 at 08:05):
Alright, so lets's say I use ∀ x : α, p x
to prove set_of p = set.univ
. Can I get a free coe
from \alpha
to P
?
Mario Carneiro (Jun 28 2020 at 08:05):
Not a coe but I believe there is an equiv for this
Eric Wieser (Jun 28 2020 at 08:06):
equiv is a bijective coe?
Mario Carneiro (Jun 28 2020 at 08:06):
It's a bijection with computable inverse
Mario Carneiro (Jun 28 2020 at 08:06):
it is a function you have to apply
Mario Carneiro (Jun 28 2020 at 08:07):
The relevant function is usually called cod_restrict
Kenny Lau (Jun 28 2020 at 08:08):
it might be more helpful if you un #xy this further
Mario Carneiro (Jun 28 2020 at 08:08):
ah yes, src#set.cod_restrict in data.set.function
Eric Wieser (Jun 28 2020 at 08:14):
@Kenny Lau: Not sure how to un-XY further without giving my full file... If you're willing to skim ~200 lines, then I'll give you a github link. If not, I'll keep exploring myself :)
Eric Wieser (Jun 28 2020 at 08:17):
The line that feels awkward to me is: https://github.com/eric-wieser/lean-ga/blob/sets-of-blades/src/geometric_algebra/nursery/chisolm.lean#L209 (edit: fixed sorry, I must have just had a typo or something)
Jalex Stark (Jun 28 2020 at 08:17):
I won't speak for kenny, but if I'm following a conversation and there's a link to a github file, I usually follow the link rather than unfollow the conversation
Eric Wieser (Jun 28 2020 at 08:26):
Simplified my issue a little bit - its really just a case of working out what's idiomatic and gets me the most for free - I was able to complete my proof
Jalex Stark (Jun 28 2020 at 08:29):
i find the file kind of hard to read. is there a reason you don't write something more like
lemma vec_sym_prod_scalar:
∀ (a b : G₁), ∃ k : G₀, a *₊ᵥ b = fₛ k :=
begin
intros a b,
have h1 : (a + b)²ᵥ = a²ᵥ + b²ᵥ + a *₊ᵥ b,
{ unfold square_vec sym_prod_vec prod_vec,
rw add_monoid_hom.map_add fᵥ a b,
rw left_distrib,
repeat {rw right_distrib},
abel },
have vec_sq_scalar : ∀ v : G₁, ∃ k : G₀, v²ᵥ = fₛ k,
apply geometric_algebra.vec_sq_scalar,
use vec_sq_scalar (a + b),
..
end
Jalex Stark (Jun 28 2020 at 08:30):
in my local copy of the master branch, typeclass inference can't find has_add G₁
Eric Wieser (Jun 28 2020 at 08:30):
master branch of mathlib? Of that repo?
Jalex Stark (Jun 28 2020 at 08:31):
of that repo
Jalex Stark (Jun 28 2020 at 08:31):
you linked to a branch called sets-of-blades, maybe it's fixed there. for some reason git checkout origin/sets-of-blades
doesn't work for me
Eric Wieser (Jun 28 2020 at 08:31):
Master branch is not super relevant to my question, since all the stuff I added is on another branch
Eric Wieser (Jun 28 2020 at 08:32):
I think has_add G₁
is implied by [vector_space G₀ G₁]
?
Jalex Stark (Jun 28 2020 at 08:32):
even earlier, by [add_comm_group G₁]
Eric Wieser (Jun 28 2020 at 08:33):
I didn't write that lemma (@Utensil Song did), so don't want to think too much about its style right now.
Jalex Stark (Jun 28 2020 at 08:35):
ok i figured out my branch issues (i just nuked my local copy and did leanproject get eric-wieser/lean-ga:sets-of-blades
)
Eric Wieser (Jun 28 2020 at 08:36):
Thanks for (offering to start) helping out!
Jalex Stark (Jun 28 2020 at 08:37):
well i haven't offered anything useful yet :P
Jalex Stark (Jun 28 2020 at 08:44):
there's something I don't understand about the difference between tactic mode and term mode. The first lemma throws an error and the second one doesn't
lemma vec_sym_prod_scalar2 (a b : G₁) : is_scalar (a *₊ᵥ b) :=
begin
have h1 : (a + b)²ᵥ = a²ᵥ + b²ᵥ + a *₊ᵥ b,
sorry
end
lemma vec_sym_prod_scalar (a b : G₁) : is_scalar (a *₊ᵥ b) :=
have h1 : (a + b)²ᵥ = a²ᵥ + b²ᵥ + a *₊ᵥ b, from begin
sorry
end, sorry
Eric Wieser (Jun 28 2020 at 08:45):
I ran into this too - it can't seem to infer the operators
Eric Wieser (Jun 28 2020 at 08:45):
Putting ( ... : G)
around their use seemed to fix it for me
Kenny Lau (Jun 28 2020 at 08:48):
def neg (b : Bᵣ r) : Bᵣ r := ⟨-b.val, begin
cases b with b' hb,
exact exists.elim hb begin
intros a ha,
use -a,
simp [ha],
end
end⟩
instance has_neg (r : ℕ) : has_neg (Bᵣ r) := { neg := neg}
Kenny Lau (Jun 28 2020 at 08:48):
this isn't idiomatic: you should instead show that is_rblade r b
implies is_rblade r (-b)
Eric Wieser (Jun 28 2020 at 08:49):
And then derive neg
from that proof?
Jalex Stark (Jun 28 2020 at 08:50):
do you know where the floating end
on line 216 of https://github.com/eric-wieser/lean-ga/blob/sets-of-blades/src/geometric_algebra/nursery/chisolm.lean#L209 comes from?
Eric Wieser (Jun 28 2020 at 08:51):
section
Jalex Stark (Jun 28 2020 at 08:52):
thanks (anonymous sections seem obviously bad to me, but I guess you're trying not to think about that sort of thing right now)
Kenny Lau (Jun 28 2020 at 08:52):
also, your file has a lot of aliases, and I mean a whole lot. It is a shame that Lean cannot deal with aliases optimally, so the idiomatic thing to do is to stick with one way to write a certain thing and prove 37 lemmas about that way
Kenny Lau (Jun 28 2020 at 08:53):
for example, we have 3700 lemmas about multiplication and 0 about your sym_prod
so maybe you shouldn't use sym_prod
Eric Wieser (Jun 28 2020 at 08:54):
Regarding neg
, is this closer to idiomatic?
lemma neg_is_rblade {b : G} (hb : is_rblade r b) : (is_rblade r (-b)) := begin
exact exists.elim hb begin
intros a ha,
use -a,
simp [ha],
end
end
def neg (b : Bᵣ r) : Bᵣ r := ⟨-b.val, neg_is_rblade b.property⟩
Kenny Lau (Jun 28 2020 at 08:54):
yeah
Jalex Stark (Jun 28 2020 at 08:55):
I'm confused, what do you suggest they do instead of use sym_prod
?
Kenny Lau (Jun 28 2020 at 08:55):
@[simp] def sym_prod (a b : G) := a * b + b * a
Kenny Lau (Jun 28 2020 at 08:55):
I suggest they forget about this definition
Kenny Lau (Jun 28 2020 at 08:56):
oops I added @[simp]
in my local version
Jalex Stark (Jun 28 2020 at 08:56):
what do you mean by "forget about"?
Jalex Stark (Jun 28 2020 at 08:56):
do you mean add @[simp]
?
Kenny Lau (Jun 28 2020 at 08:57):
I actually mean delete this definition, but maybe we could ask @Mario Carneiro about how that file could become more idiomatic
Kenny Lau (Jun 28 2020 at 08:57):
that file = https://github.com/eric-wieser/lean-ga/blob/sets-of-blades/src/geometric_algebra/nursery/chisolm.lean
Jalex Stark (Jun 28 2020 at 08:58):
is giving it @[reducible] similar to deleting it? or making it a notation?
I imagine the point is just that it's a pain to type out a * b + b * a
when a
and b
are many characters long
Kenny Lau (Jun 28 2020 at 09:00):
hence "it's a shame Lean can't handle aliases optimally"
Kenny Lau (Jun 28 2020 at 09:00):
in my ideal world I would be able to write sym_prod
in theorems and have it automatically convert to the long version when they store the theorem
Kenny Lau (Jun 28 2020 at 09:00):
so people won't complain about my LHS not being in "simp-normal" form
Eric Wieser (Jun 28 2020 at 09:00):
My suspicion is that we will not need sym_prod
in its current form, only sym_prod_vec
. The true symmetric product over G is much more complex, I think
Eric Wieser (Jun 28 2020 at 09:03):
Another question about that file - I have:
-- r-vectors
def Gᵣ (r : ℕ) := add_subgroup.closure (Bᵣ r)
namespace Gᵣ
variables {r : ℕ}
instance addgroup : add_comm_group (Gᵣ r) := (Gᵣ r).to_add_comm_group
end Gᵣ
Is the add_comm_group
instance actually needed, or does lean already provide it? If the latter, can I write an assertion that I satisfy the type class?
Kenny Lau (Jun 28 2020 at 09:04):
if you tag the definition with @[reducible]
then you will automatically have the instance
Kenny Lau (Jun 28 2020 at 09:05):
@Jalex Stark @Mario Carneiro in my ideal world, writing sym_prod a b
would be the same as writing a * b + b * a
in all circumstances
Eric Wieser (Jun 28 2020 at 09:05):
@Kenny Lau, for the second part of the question, how can I check if I have the instance?
Kenny Lau (Jun 28 2020 at 09:06):
#check \la r, (by instance : add_comm_group G\_r r)
(be sure not to put this after a line that starts with by
)
Eric Wieser (Jun 28 2020 at 09:06):
Is it idiomatic to leave checks in files as proof that the instances you intend to satisfy are satified?
Jalex Stark (Jun 28 2020 at 09:07):
no
Kenny Lau (Jun 28 2020 at 09:07):
it isn't a proof
Kenny Lau (Jun 28 2020 at 09:07):
you don't need that line there to use the file
Eric Wieser (Jun 28 2020 at 09:07):
Right, but it acts as a unit test for the file
Jalex Stark (Jun 28 2020 at 09:08):
if you "intend to satisfy the instance" then there should be theorems that make use of it
Kenny Lau (Jun 28 2020 at 09:08):
we don't do unit tests
Eric Wieser (Jun 28 2020 at 09:08):
@Jalex Stark: what about situations where I don't need it to satisfy any of my theorems, but users building upon my theorems do?
Kenny Lau (Jun 28 2020 at 09:09):
you don't need the #check
line to have the instance
Kenny Lau (Jun 28 2020 at 09:09):
it's just there literally for you to check that the instance is there
Eric Wieser (Jun 28 2020 at 09:09):
No, but if I remove the instance by accident, how would I know?
Kenny Lau (Jun 28 2020 at 09:09):
then the theorems depending on that instance will complain to you
Eric Wieser (Jun 28 2020 at 09:10):
But they won't, they'd complain at someone else who wrote those theorems on a different machine. Who would then complain to me
Kenny Lau (Jun 28 2020 at 09:10):
"All repo not PR'd into mathlib is lost" -- Ancient Chinese Proverb
Jalex Stark (Jun 28 2020 at 09:11):
you can declare the instance by instance : add_comm_group G\0 := by apply_instance
, is that what you want?
Mario Carneiro (Jun 28 2020 at 09:11):
If you want sym_prod a b
to be turned into a * b + b * a
immediately, you can use a notation
Eric Wieser (Jun 28 2020 at 09:12):
Yes, I think that's a nice compromise @Jalex Stark , thanks. @Kenny Lau, thanks for the advice.
Bryan Gin-ge Chen (Jun 28 2020 at 09:14):
Jalex Stark said:
you can declare the instance by
instance : add_comm_group G\0 := by apply_instance
, is that what you want?
Won't this result in two add_comm_group
instances? If so, maybe for a test you should use example
here instead.
Eric Wieser (Jun 28 2020 at 09:14):
@Jalex Stark , that doesn't work, it seems to declare it with a name of add_comm_group
.
Eric Wieser (Jun 28 2020 at 09:14):
example (r : ℕ) : add_comm_group (Gᵣ r) := by apply_instance
is what I was after!
Eric Wieser (Jun 28 2020 at 09:16):
It seems I don't need @[reducible]
?
Jalex Stark (Jun 28 2020 at 09:16):
you don't need reducible where?
Eric Wieser (Jun 28 2020 at 09:17):
Kenny Lau said:
if you tag the definition with
@[reducible]
then you will automatically have the instance
On G\_r
Mario Carneiro (Jun 28 2020 at 09:18):
If the instance gets a bad name, you should give it a name manually
Mario Carneiro (Jun 28 2020 at 09:18):
instance G0.add_comm_group : add_comm_group G\0 := by apply_instance
Eric Wieser (Jun 28 2020 at 09:19):
My hope was that instance
without a name would result in no name at all. But it sounds like if you need no name at all, example
is the right keyword.
Bryan Gin-ge Chen (Jun 28 2020 at 09:19):
Including this instance explicitly can speed up type class search, right?
Mario Carneiro (Jun 28 2020 at 09:19):
no name just means it uses an automatic naming scheme which is wrong surprisingly often
Bryan Gin-ge Chen (Jun 28 2020 at 09:19):
example
just throws away the declaration once it's been checked.
Jalex Stark (Jun 28 2020 at 09:23):
(deleted)
Jalex Stark (Jun 28 2020 at 09:27):
one example of bad aliasing in this file is left_distrib
. everywhere it's used it can (and should) be replaced with the general mul_add
Eric Wieser (Jun 28 2020 at 09:35):
Yeah, I noticed that too, just didn't want to do too much cleanup to start with.
Jalex Stark (Jun 28 2020 at 09:37):
( @Utensil Song should probably look at this thread at some point )
Kenny Lau (Jun 28 2020 at 13:50):
Mario Carneiro said:
If you want
sym_prod a b
to be turned intoa * b + b * a
immediately, you can use a notation
@Kevin Buzzard and I are trying out this new approach and it's working fine
Kenny Lau (Jun 28 2020 at 13:50):
and I'm left here wondering why don't we use this all over mathlib
Kenny Lau (Jun 28 2020 at 13:52):
-- make all the tactics work
import tactic
import algebra.pi_instances
-- Let's just use Lean's definition of the naturals and not worry
-- about what they are or how to make them.
import data.nat.basic
-- Let's now experiment
namespace experiment
/-
An experiment where we try different definitions of the integers.
-/
namespace int3
notation `ℕ²` := ℕ × ℕ
namespace natsquared
notation `first` := prod.fst
notation `second` := prod.snd
def r (a b : ℕ²) := first a + second b = second a + first b
instance : has_equiv ℕ² := ⟨r⟩
namespace r
theorem refl (a : ℕ²) : a ≈ a :=
begin
-- unfold it in your head
change first a + second a = second a + first a,
-- if you delete the line above, the line below still works
apply add_comm,
end
theorem symm (a b : ℕ²) : a ≈ b → b ≈ a :=
begin
intro hab,
unfold has_equiv.equiv at *,
rw [r] at *,
omega,
end
theorem trans (a b c : ℕ²) : a ≈ b → b ≈ c → a ≈ c :=
begin
intro hab,
intro hbc,
unfold has_equiv.equiv at *,
rw [r] at *,
omega,
end
theorem equiv : equivalence r :=
⟨refl, symm, trans⟩
end r
instance : setoid ℕ² :=
{ r := r,
iseqv := r.equiv }
end natsquared
-- definition of int as quotient type
notation `ℤ3` := quotient natsquared.setoid
-- theorem! It's a ring!
def zero : ℤ3 := ⟦0⟧
def one : ℤ3 := ⟦1⟧
open natsquared
@[simp] lemma thing (a b : ℕ²) : a ≈ b ↔ first a + second b = second a + first b := iff.rfl
def add (a b : ℤ3) : ℤ3 := quotient.lift_on₂ a b (λ z w, ⟦(z+w)⟧) begin
intros,
simp at *,
omega,
end
end int3
end experiment
Kenny Lau (Jun 28 2020 at 13:53):
here, no definition, only notation, and everything works fine
Kenny Lau (Jun 28 2020 at 13:53):
@Mario Carneiro we should use this all over mathlib
Kenny Lau (Jun 28 2020 at 13:54):
oh except for one thing: zero and one and add are all definitions
Mario Carneiro (Jun 28 2020 at 13:57):
I don't think we want int3
to be a notation
Mario Carneiro (Jun 28 2020 at 13:58):
or rather, ℤ3
should be a notation for def int3 := quotient natsquared.setoid
Mario Carneiro (Jun 28 2020 at 13:58):
I don't see any problems with ℕ²
being a (local) notation though
Mario Carneiro (Jun 28 2020 at 13:58):
actually these should all probably be local notations
Mario Carneiro (Jun 28 2020 at 13:59):
But notations are not a substitute for defs. They are like macros, they expand on the spot
Mario Carneiro (Jun 28 2020 at 13:59):
that's usually not what you want
Kenny Lau (Jun 28 2020 at 14:05):
but that's what I'm complaining about
Kenny Lau (Jun 28 2020 at 14:05):
I want them to behave completely the same
Kenny Lau (Jun 28 2020 at 14:06):
I guess I'm being unreasonable
Kenny Lau (Jun 28 2020 at 14:06):
if everything were expanded every term would be huge right
Kenny Lau (Jun 28 2020 at 14:06):
like internally, even though pp gives a short term
Mario Carneiro (Jun 28 2020 at 14:27):
even pp
won't be able to provide small terms in most cases, I think
Mario Carneiro (Jun 28 2020 at 14:28):
But you've got the idea there - the whole point of definitions is so that term sizes don't grow exponentially as you move up in abstraction
Mario Carneiro (Jun 28 2020 at 14:28):
if you intend to give something an "API" then it should probably be a definition
Utensil Song (Jun 30 2020 at 12:05):
Just discovered this topic through @. Thanks for the code review and suggestions!
The file is mostly a messy battlefield when I was fighting with how to proceed to the next line. There're many cleanups in order, and not cleaning them up is simply because of some historical reasons and random feelings about them:
- The proof would become much more readable if it's rewritten into what @Jalex Stark suggested here, I was just piecing the scalars together so I used elim to give the scalars names from the exists prop;
- anonymous sections are indeed bad, but if I have a lemma
c
in namespacea
and sectionb
, I can't help to think it asa.b.c
so I leftb
empty ; - the abuse of alias is partly an experiment to see how can I see through these noises when I prove things;
- partly because I need them in the process of writing some deleted code, take
sym_prod
for an example, initially, there was nosym_prod_vec
and onlysym_prod
since I used coe instead of homes, and I can't just use notation because I need to specify the types to give Lean the hint to automatically add coes for me, see https://github.com/pygae/lean-ga/blob/cf736df9e327ba6822f3b95e996406ec2e87f470/src/geometric_algebra/nursery/basic.lean#L89 - the existence of
left_distrib
etc. is because I need to prove this trivial thing locally to verify the local environment, like parameters/variables are working, and I left them there because I wanted to present them locally, the same place they appear in the literature(showing that they are already included in the definition, without explicit appearances in the definition) and felt annoying to have to remember from which algebraic structureleft_distrib
came from.
Jalex Stark (Jun 30 2020 at 12:11):
You don't need to remember the name of an algebraic structure to use rw mul_add
Last updated: Dec 20 2023 at 11:08 UTC