Zulip Chat Archive
Stream: lean4
Topic: Defining algebraic structures
Tomáš Pecl (Oct 27 2023 at 13:04):
Hello. I am trying to define Linear algebra. I have several problems and questions about it. Currently I got this:
class Inv (F : Type u) where
inv : F -> F
postfix:max "⁻¹" => Inv.inv
class Zero (F : Type u) where
zero : F
instance Zero.toOfNat0 {α} [Zero α] : OfNat α (nat_lit 0) where
ofNat := ‹Zero α›.1
class One (F : Type u) where
one : F
instance One.toOfNat1 {α} [One α] : OfNat α (nat_lit 1) where
ofNat := ‹One α›.1
class Monoid (F : Type u) (op : F -> F -> F) (ide : F) where
--I would like to use a custom notation here so instead "op ide a = a"
--I would like to use 1 * a = a but only inside here
--so that it would not interfere with the Field definition
--which instanciates two Group structures each with a different operator (+ and *)
id_op: ∀ a : F, op ide a = a
assoc: ∀ a b c : F, op a (op b c) = op (op a b) c
--why can I not put class here?
--what is the difference between class and structure?
structure CommutMonoid (F : Type u) (op : F -> F -> F) (ide : F) extends Monoid F op ide where
comm: ∀ a b : F, op a b = op b a
theorem op_id (m : CommutMonoid F op ide) : ∀ a : F, op a ide = a := by {
intro a
rw [m.comm,m.id_op]
}
class Group (F : Type u) (op : F -> F -> F) (ide : F) (inv : F -> F) extends CommutMonoid F op ide where
a_op_inv_a: ∀ a : F, op a (inv a) = ide
--I can use the proof from the CommutMonoid in here
theorem op_id2 (g : Group F op ide inv) : ∀ a : F, op a ide = a := op_id g.toCommutMonoid
--I use this for saying that multiplication is "ConditionalGroup f (.*.) 1 (.⁻¹) (. ≠ 0)"
class ConditionalGroup (F : Type u) (op : F -> F -> F) (ide : F) (inv : F -> F) (inv_cond : F -> Prop) extends CommutMonoid F op ide where
a_op_inv_a: ∀ a : F, inv_cond a -> op a (inv a) = ide
class Field (F : Type u) extends Zero F, Add F, Neg F, One F, Mul F, Inv F where
plus: Group F (.+.) 0 (-.) --the Group structure of +
mult: ConditionalGroup F (.*.) 1 (.⁻¹) (. ≠ 0) --the Group structure of *
ldistr: ∀ a b c : F, a * (b + c) = a*b + a*c --left distrubutivity
--I can use the more general proof for CommutMonoid here for both + and * to define these "shortcuts"
theorem plus_zero (f : Field F) : ∀ a : F, a + 0 = a := op_id f.plus.toCommutMonoid
theorem mult_one (f : Field F) : ∀ a : F, a * 1 = a := op_id f.mult.toCommutMonoid
--proof of right distributivity
theorem rdistr (f : Field F) : ∀ a b c : F, (b + c)*a = b*a + c*a := by {
intro a b c
rw [f.mult.comm,f.ldistr,f.mult.comm b a,f.mult.comm a c]
}
--I can use multiple Fields here and prove things about them, not sure if I ever need this
--(this example is quite stupid)
theorem x (f1 : Field F1) (f2 : Field F2) : (∀ a : F1, a + 0 = a) ∧ (∀ a : F2, a + 0 = a) := by {
exact And.intro (op_id f1.plus.toCommutMonoid) (op_id f2.plus.toCommutMonoid)
}
--why can I not use class here?
structure LinearSpace (f: Field F) (L : Type u) extends Zero L, Add L, Neg L, HMul F L L where
plus: Group L (.+.) 0 (-.)
--scalar multiplication axioms -> maybe I could replace these by something like a Monoid?
--mult: Monoid ???
one_mult: ∀ a : L, (1 : F) * a = a
mult_assoc: ∀ a b : F, ∀ x : L, a * (b * x) = (a * b) * x
--distrubutivity axioms
ldistr: ∀ a : F, ∀ x y : L, a * (x + y) = a*x + a*y
rdistr: ∀ a b : F, ∀ x : L, (a + b) * x = a*x + b*x
--this does not work if LinearSpace is not class -> + and 0 are unknown
theorem unique_zero_vector (f : Field F) (l : LinearSpace f L) : ∀ zero : L, ((∀ a : L, zero + a = a) -> zero = 0) := by {
intro zero2
intro is_zero
have zero2_plus_zero := is_zero 0
rw [l.plus.comm zero2 0] at zero2_plus_zero
rw [l.plus.id_op] at zero2_plus_zero
exact zero2_plus_zero
}
Eric Wieser (Oct 27 2023 at 13:42):
Here's an answer to the local *
notation:
section
variable (F : Type u) (op : F -> F -> F) (ide : F)
local infix:65 "*" => op
local notation "𝟙" => ide
class Monoid where
id_op: ∀ a : F, 𝟙 * a = a
assoc: ∀ a b c : F, a * (b * c) = (a * b) * c
end
Tomáš Pecl (Oct 27 2023 at 14:02):
But wouldnt that mean that Monoid would be private in the section? Like then I would have to open that section if I wanted to use that Monoid somewhere else, or am I wrong?
Tomáš Pecl (Oct 27 2023 at 14:03):
But I am gonna try it
Eric Wieser (Oct 27 2023 at 14:14):
The only thing that is "private" in the section are the local
commands
Eric Wieser (Oct 27 2023 at 14:14):
The Monoid
type is not private
Tomáš Pecl (Oct 27 2023 at 14:18):
Ok so I made it work:
section MonoidsDefs
variable (F : Type u) (op : F -> F -> F) (id : F)
local infix:65 "*" => op
local notation "𝟙" => id
class Monoid where
id_op: ∀ a : F, 𝟙 * a = a
assoc: ∀ a b c : F, a * (b * c) = (a * b) * c
structure CommutMonoid extends Monoid F op id where
comm: ∀ a b : F, a*b = b*a
end MonoidsDefs
section MonoidsProofs
variable {F : Type u} {op : F -> F -> F} {id : F}
local infix:65 "*" => op
local notation "𝟙" => id
theorem op_id (m : CommutMonoid F op id) : ∀ a : F, a*id = a := by {
intro a
rw [m.comm,m.id_op]
}
end MonoidsProofs
Eric Wieser (Oct 27 2023 at 14:19):
structure CommutMonoid extends Monoid
should be class CommutMonoid extends Monoid
Tomáš Pecl (Oct 27 2023 at 14:19):
I used curly braces {} in the section MonoidsProofs for the variables to make sure that I do not have to supply the F, op and id whenever I use the theorems
Eric Wieser (Oct 27 2023 at 14:20):
That choice will come to bite you when you have an expression like a*1 + 0
, and need to pick between the two different op_id
s with +0
vs *1
Tomáš Pecl (Oct 27 2023 at 14:21):
Eric Wieser said:
structure CommutMonoid extends Monoid
should beclass CommutMonoid extends Monoid
But then my code for Group breaks because:
cannot find synthesization order for instance @Group.toCommutMonoid with type
{F : Type u} → {op : F → F → F} → {ide : F} → (inv : F → F) → [self : Group F op ide inv] → CommutMonoid F op ide
all remaining arguments have metavariables:
Group F op ide ?invLean 4
T5.Group.a_op_inv_a.{u} {F : Type u} {op : F → F → F} {ide : F} {inv : F → F} [self : Group F op ide inv] (a : F) :
op a (inv a) = ide
Eric Wieser (Oct 27 2023 at 14:22):
You should use
class Group (F : Type u) (op : F -> F -> F) (ide : F) (inv : outParam <| F -> F) extends CommutMonoid F op ide where
a_op_inv_a: ∀ a : F, op a (inv a) = ide
Eric Wieser (Oct 27 2023 at 14:22):
Which tells Lean "if you know op
and ide
already, then there is only one possible inv
"
Tomáš Pecl (Oct 27 2023 at 14:24):
Eric Wieser said:
That choice will come to bite you when you have an expression like
a*1 + 0
, and need to pick between the two differentop_id
s with+0
vs*1
hey it works:
theorem identities (f : Field F) : ∀ a : F, a*1 + 0 = a := by {
intro a
rw [f.plus.comm,f.plus.id_op,f.mult.comm,f.mult.id_op]
}
Ruben Van de Velde (Oct 27 2023 at 14:25):
Please use #backticks
Tomáš Pecl (Oct 27 2023 at 14:26):
yea, sorry, I fixed it
Eric Wieser (Oct 27 2023 at 14:27):
Just to check, I assume you're aware that mathlib already has docs#Field and docs#Module etc, and you're doing this as an exercise?
Tomáš Pecl (Oct 27 2023 at 14:28):
Yes. I am trying to write it from scratch
Tomáš Pecl (Oct 27 2023 at 14:30):
Eric Wieser said:
You should use
class Group (F : Type u) (op : F -> F -> F) (ide : F) (inv : outParam <| F -> F) extends CommutMonoid F op ide where a_op_inv_a: ∀ a : F, op a (inv a) = ide
why should it mean that "once you know op and ide, you know inv"?
Tomáš Pecl (Oct 27 2023 at 14:33):
can you explain why it makes it work?
Eric Wieser (Oct 27 2023 at 15:03):
docs#outParam has some explanation, but perhaps not enough
Last updated: Dec 20 2023 at 11:08 UTC