Zulip Chat Archive

Stream: lean4

Topic: groups


learnerofmaths (May 19 2021 at 23:04):

Hello, I am trying to define groups in lean4 to get a sense of what it would mean to use a theorem prover for work. Here is how far I have gotten:

section groupdefs

class One (α : Type u) where
  one : α

class Inv (α : Type u) where
  inv : α  α

class Mul (G : Type u) where
  mul : G  G

-- Set up notation typeclass using `extends`.
class has_group_notation (G : Type u) extends Mul G, One G, Inv G

-- definition of the group structure
class group (G : Type u) extends has_group_notation G where
  mul_assoc (a b c : G) : a * b * c = a * (b * c)

But I am having issues here since I keep getting an error "(kernel) declaration has metavariables 'mygroup.group.mk'Lean 4" . Does anyone know what's happening? Is this the right way to start defining one's own definition of a group?
Best!

Mario Carneiro (May 19 2021 at 23:12):

I get an error on class Mul saying that Mul is already declared. What version of lean 4 are you using?

Mario Carneiro (May 19 2021 at 23:15):

You need to use the Mul declared in the core library if you want to get the * notation, or declare your own * notation in terms of your Mul

Mario Carneiro (May 19 2021 at 23:15):

Here's a version using the classes from core:

class abbrev One (α : Type u) := OfNat α 1

class Inv (α : Type u) where
  inv : α  α

-- Set up notation typeclass using `extends`.
class has_group_notation (G : Type u) extends Mul G, One G, Inv G

-- definition of the group structure
class group (G : Type u) extends has_group_notation G where
  mul_assoc (a b c : G) : a * b * c = a * (b * c)

learnerofmaths (May 19 2021 at 23:15):

Sorry about that you need a custom namespace. I missed that

namespace mygroup

-- definitions of the group classes

section groupdefs

class One (α : Type u) where
  one : α

class Inv (α : Type u) where
  inv : α  α

class Mul (G : Type u) where
  mul : G  G

-- Set up notation typeclass using `extends`.
class has_group_notation (G : Type u) extends Mul G, One G, Inv G

-- definition of the group structure
class group (G : Type u) extends has_group_notation G where
  mul_assoc (a b c : G) : a * b * c = a * (b * c)

The version of lean is "leanprover/lean4:4.0.0"

learnerofmaths (May 19 2021 at 23:17):

I see thank you!

learnerofmaths (May 19 2021 at 23:18):

Mario Carneiro said:

You need to use the Mul declared in the core library if you want to get the * notation, or declare your own * notation in terms of your Mul

Thank you!

learnerofmaths (May 19 2021 at 23:21):

section groupdefs

class abbrev One (α : Type u) := OfNat α 1

class Inv (α : Type u) where
  inv : α  α

-- Set up notation typeclass using `extends`.
class has_group_notation (G : Type u) extends Mul G, One G, Inv G

-- definition of the group structure
class group (G : Type u) extends has_group_notation G where
  mul_assoc (a b c : G) : a * b * c = a * (b * c)
  one_mul (a : G) : 1 * a = a
  mul_left_inv (a : G) : a⁻¹ * a = 1

Now almost works. But I get a strange error with using \^-1. "expected termLean 4" Screen-Shot-2021-05-19-at-7.20.50-PM.png

Mario Carneiro (May 19 2021 at 23:22):

Just like Mul, Inv doesn't itself come with any notation, especially since it was just defined

Mario Carneiro (May 19 2021 at 23:23):

notation a "⁻¹" => Inv.inv a

learnerofmaths (May 19 2021 at 23:23):

ah! Ok, starting to get the hang of that.

learnerofmaths (May 19 2021 at 23:23):

makes sense.

Mario Carneiro (May 19 2021 at 23:24):

One does work because it is abbreviating the class OfNat A 1 that is used to resolve the meaning of 1 : A

learnerofmaths (May 19 2021 at 23:25):

I see. But why is 1 not considered a type of "notation" but rather a class?

Mario Carneiro (May 19 2021 at 23:26):

Just like inv and mul, there is a notation that says that number literals are defined to be OfNat.ofNat A n where OfNat is a class

Mario Carneiro (May 19 2021 at 23:26):

it's defined somewhere in the core library and it's a bit more complicated because it has to match on number literals

learnerofmaths (May 19 2021 at 23:27):

So something like notation "1" => OfNat.ofNat 1 (This is wrong, but something like this?) ? But my 1 has nothing to do with natural numbers, right? It's just notation?

Mario Carneiro (May 19 2021 at 23:29):

Conceptually that's what it is doing, yes

Mario Carneiro (May 19 2021 at 23:29):

there are an infinite number of such notations that have to be declared though so it is written in a more complicated way

Mario Carneiro (May 19 2021 at 23:30):

the actual code is here. It is using the more low level interface that notation desugars into

Mario Carneiro (May 19 2021 at 23:31):

it's probably unreadable but you can see OfNat.ofNat getting referenced

learnerofmaths (May 19 2021 at 23:31):

Alright. Sometimes the easiest things are so fundamental they are complicated. Off to prove some theorems and excited to learn lean : )

learnerofmaths (May 23 2021 at 22:27):

Hello again, I am trying to prove some properties of groups. But I am getting hung up on various syntax issues. Here is my initial definition

-- We're overwriting inbuilt group theory here so we always work in
-- a namespace
namespace mygroup

-- definitions of the group classes
section groupdefs

-- Notation for One done in an odd way
class abbrev One (α : Type u) := OfNat α 1

-- define inverse class and notation
class Inv (α : Type u) where
  inv : α  α

notation a "⁻¹" => Inv.inv a

-- Set up notation typeclass using `extends` for define classes
class has_group_notation (G : Type u) extends Mul G, One G, Inv G

-- definition of the group structure
class group (G : Type u) extends has_group_notation G where
  mul_assoc (a b c : G) : a * b * c = a * (b * c)
  one_mul (a : G) : 1 * a = a
  mul_left_inv (a : G) : a⁻¹ * a = 1


export group (mul_assoc one_mul mul_left_inv )

-- example of abelian group
class comm_group (G : Type u) extends group G where
  mul_comm (a b : G) : a * b = b * a
end groupdefs

namespace group


theorem inv_mul_cancel_left [group G] (a b : G) : a⁻¹ * (a * b) = b := by
  have a⁻¹ * (a * b) = (a⁻¹ * a) * b := by rw [mul_assoc]
  have (a⁻¹ * a) = 1 := by rw [mul_left_inv]
  have 1 * b = b := by rw [one_mul]

end group

end mygroup
  1. the first issue is that [group G ] (a b : G) is not valid while [group α ] (a b : α ) why this statement sensitive to Unicode greek letters? I get an "unknown identifier 'G'".

  2. My next issue is that I am not sure how to tell lean to complete a proof when I replace G with α:

theorem inv_mul_cancel_left [group α ] (a b : α ) : a⁻¹ * (a * b) = b := by
  have a⁻¹ * (a * b) = (a⁻¹ * a) * b := by rw [mul_assoc]
  have (a⁻¹ * a) = 1 := by rw [mul_left_inv]
  have 1 * b = b := by rw [one_mul]

Gives a bunch of errors that I attached.

Thank your help. Screen-Shot-2021-05-23-at-6.25.54-PM.png

Alex J. Best (May 23 2021 at 22:54):

Mac said:

Kevin Buzzard said:

I'm on today's nightly.

example :  (x : Prop), x  x  x := sorry -- compiles
example :  (A : Prop), A  A  A := sorry -- fails on third A
example :  (A : Prop), a  a  a := sorry -- compiles?!

This is because it is being parsed as Mario Carneiro showed and then the unbound lowercase latin letters are being auto bound as specified in https://leanprover.github.io/lean4/doc/autobound.html

I'm guessing you are seeing this behaviour and you need to add {G : Type u} to have it work

learnerofmaths (May 24 2021 at 03:18):

I checked it out. I tried that change and a different error happened. I attached it. Screen-Shot-2021-05-23-at-11.17.43-PM.png

Scott Morrison (May 24 2021 at 03:27):

Please post code blocks (ideally as #mwe), rather than screenshots! You'll get much more help. :-)

Yakov Pechersky (May 24 2021 at 03:57):

You need {G : Type u} [group G] (a b : G)

Yakov Pechersky (May 24 2021 at 03:59):

We first postulate an arbitrary type G, then postulate that it has a group structure, then say "let a and b be terms of G"

learnerofmaths (May 24 2021 at 04:40):

ahhh! I see that. Makes total sense @Yakov Pechersky . Now I get some of others with

-- We're overwriting inbuilt group theory here so we always work in
-- a namespace
namespace mygroup

-- definitions of the group classes
section groupdefs

-- Notation for One done in an odd way
class abbrev One (α : Type u) := OfNat α 1

-- define inverse class and notation
class Inv (α : Type u) where
  inv : α  α

notation a "⁻¹" => Inv.inv a

-- Set up notation typeclass using `extends` for define classes
class has_group_notation (G : Type u) extends Mul G, One G, Inv G

-- definition of the group structure
class group (G : Type u) extends has_group_notation G where
  mul_assoc (a b c : G) : a * b * c = a * (b * c)
  one_mul (a : G) : 1 * a = a
  mul_left_inv (a : G) : a⁻¹ * a = 1


export group (mul_assoc one_mul mul_left_inv )

-- example of abelian group
class comm_group (G : Type u) extends group G where
  mul_comm (a b : G) : a * b = b * a
end groupdefs

namespace group


theorem inv_mul_cancel_left {G : Type u} [group G] (a b : G) : a⁻¹ * (a * b) = b := by
  have a⁻¹ * (a * b) = (a⁻¹ * a) * b := by rw [mul_assoc]
  have (a⁻¹ * a) = 1 := by rw [mul_left_inv]
  have 1 * b = b := by rw [one_mul]

end group

end mygroup

I get two instances of "failed to synthesize instance OfNat G 1" and I can't seem to tell lean that I have proved the theorem.

Thanks for the tip @Scott Morrison ! : )

Eric Wieser (May 24 2021 at 04:50):

You haven't proved the theorem, you've proved three intermediate results without joining them together

Eric Wieser (May 24 2021 at 04:51):

Adding rw this after each have probably resolves that

Kevin Buzzard (May 24 2021 at 06:38):

Your first comment in the code is not correct. Lean 4 does not have inbuilt groups

learnerofmaths (May 24 2021 at 13:03):

Hi, @Kevin Buzzard I was referring to https://github.com/leanprover/lean4/blob/master/tests/lean/run/alg.lean and https://github.com/leanprover/lean4/blob/master/tests/lean/run/alg.lean . But these appear as tests, so I will remove that comment.

Kevin Buzzard (May 24 2021 at 13:04):

If you import Mathlib.Algebra.Group.Defs from mathlib4 you can have groups :-)

learnerofmaths (May 24 2021 at 13:15):

@Eric Wieser , awesome. But I still get "failed to synthesize instance OfNat G 1" and red squiggly lines under the ones ('1'). Have you seen that before?

Do you happen to know what "rw this" means? Is there another way without rw this? My understanding was that for lean3 there was something called 'calc' and you could write proofs using chains of implications that looked like:

calc a⁻¹ * (a * b) = (a⁻¹ * a) * b : by rw mul_assoc
...  (a⁻¹ * a) * b : by  rw mul_left_inv
...  1 * b = b :  by rw one_mul

Here's the current code so far. Thank you for getting me on board.

-- 'If you import Mathlib.Algebra.Group.Defs from mathlib4 you can have groups :-)' ~ Kevin Buzzard
-- To get the swing of things built everything here
namespace mygroup

-- definitions of the group classes
section groupdefs

-- Notation for One done in an odd way
class abbrev One (α : Type u) := OfNat α 1

-- define inverse class and notation
class Inv (α : Type u) where
  inv : α  α

notation a "⁻¹" => Inv.inv a

-- Set up notation typeclass using `extends` for define classes
class has_group_notation (G : Type u) extends Mul G, One G, Inv G

-- definition of the group structure
class group (G : Type u) extends has_group_notation G where
  mul_assoc (a b c : G) : a * b * c = a * (b * c)
  one_mul (a : G) : 1 * a = a
  mul_left_inv (a : G) : a⁻¹ * a = 1


export group (mul_assoc one_mul mul_left_inv )

-- example of abelian group
class comm_group (G : Type u) extends group G where
  mul_comm (a b : G) : a * b = b * a
end groupdefs

namespace group


theorem inv_mul_cancel_left {G : Type u} [group G] (a b : G) : a⁻¹ * (a * b) = b := by
  have a⁻¹ * (a * b) = (a⁻¹ * a) * b := by rw [mul_assoc]
  rw this
  have (a⁻¹ * a) = 1 := by rw [mul_left_inv]
  rw this
  have 1 * b = b := by rw [one_mul]
  rw this

end group

end mygroup

Screen-Shot-2021-05-24-at-9.14.17-AM.png

Eric Wieser (May 24 2021 at 13:19):

have some_statement := sorry is short for have this : some_statement := sorry, meaning "prove some_statement and put the proof in a hypothesis called this" (at least, it is in lean3 and I assume it hasn't changed in lean 4).

Eric Wieser (May 24 2021 at 13:20):

Someone else who actually knows lean4 will have to help you with your ofNat problem

Eric Wieser (May 24 2021 at 13:23):

The calc proof you show there doesn't work in lean3 either though - an= is in the wrong place

Kevin Buzzard (May 24 2021 at 13:27):

Check out Mathlib.Algebra.Group.Defs for how to do 1 in Lean 4.

learnerofmaths (May 24 2021 at 13:29):

I see @Eric Wieser . I am very new to lean. I saw that notation used elsewhere. I have also seen

theorem inv_mul_cancel_left (a b : G) : a⁻¹ * (a * b) = b :=
by rw [ mul_assoc, mul_left_inv, one_mul]

Is the above version with the "have" and "rw this" the same? What is "← " doing here? I am happy to look at documentation just not sure what to search for. Are there names for these different styles?

Ruben Van de Velde (May 24 2021 at 13:31):

rw mul_assoc rewrites a * b * c to a * (b * c); rw ←mul_assoc rewrites a * (b * c) to a * b * c

learnerofmaths (May 24 2021 at 13:33):

@Kevin Buzzard I tried your suggestion. But I get unknown identifier 'nat_lit'Lean 4

-- 'If you import Mathlib.Algebra.Group.Defs from mathlib4 you can have groups :-)' ~ Kevin Buzzard
-- To get the swing of things built everything here

namespace mygroup

-- definitions of the group classes
section groupdefs

-- -- Notation for One done in an odd way
-- class abbrev One (α : Type u) := OfNat α 1
class One (α : Type u) where
  one : α

instance [One α] : OfNat α (nat_lit 1) where
  ofNat := One.one


-- define inverse class and notation
class Inv (α : Type u) where
  inv : α  α

notation a "⁻¹" => Inv.inv a

-- Set up notation typeclass using `extends` for define classes
class has_group_notation (G : Type u) extends Mul G, One G, Inv G

-- definition of the group structure
class group (G : Type u) extends has_group_notation G where
  mul_assoc (a b c : G) : a * b * c = a * (b * c)
  one_mul (a : G) : 1 * a = a
  mul_left_inv (a : G) : a⁻¹ * a = 1


export group (mul_assoc one_mul mul_left_inv )

-- example of abelian group
class comm_group (G : Type u) extends group G where
  mul_comm (a b : G) : a * b = b * a
end groupdefs

namespace group


theorem inv_mul_cancel_left {G : Type u} [group G] (a b : G) : a⁻¹ * (a * b) = b := by
  have intial_assumption : a⁻¹ * (a * b) = (a⁻¹ * a) * b := by rw [mul_assoc]
  rw intial_assumption
  have (a⁻¹ * a) = 1 := by rw [mul_left_inv]
  rw this
  have 1 * b = b := by rw [one_mul]
  rw this

end group

end mygroup

Julian Berman (May 24 2021 at 14:20):

I think that'll mean your lean4 is too old -- what does lean --version say? (Or just update to a more recent one). nat_lit used to be called natLit!.

learnerofmaths (May 24 2021 at 14:24):

Hi @Julian Berman . My current version of lean is

group_theory$ lean --version
Lean (version 4.0.0-m2, commit 26dda3f63d88, Release)

Julian Berman (May 24 2021 at 14:25):

Hello -- yeah natLit! got renamed about 10 days after that -- you should probably stick to the version of Lean that mathlib4 itself uses if you're going to use things from it

Julian Berman (May 24 2021 at 14:26):

which according to https://github.com/leanprover-community/mathlib4/blob/master/leanpkg.toml#L4 is leanprover/lean4:nightly-2021-05-18

learnerofmaths (May 24 2021 at 14:26):

Ah, cool! Changing to natLit! fixed it. But I will see about updating, too!

learnerofmaths (May 24 2021 at 14:26):

Thank you all!! Off to prove more theorems. Your help is really appreciated. Have a good day everyone.

Jakob von Raumer (May 24 2021 at 18:48):

To add what the others were saying: At some point we will surely have a calc and conv environment in Lean 4, they're not implemented yet, though.

Alex J. Best (May 24 2021 at 19:37):

Sebastian wrote a version of calc in a thread here: (maybe there was another one in a thread too)
Sebastian Ullrich said:

Here's one solution for a heterogeneous calc based on a Trans typeclass and ... as a term notation:

class Trans (r : α  β  Prop) (s : β  γ  Prop) (t : outParam (α  γ  Prop)) where
  trans {a b c} : r a b  s b c  t a c

export Trans (trans)

instance (r : α  γ  Prop) : Trans Eq r r where
  trans heq h' := heq  h'

instance (r : α  β  Prop) : Trans r Eq r where
  trans h' heq := heq  h'

notation "..." => _
-- enforce indentation of calc steps so we know when to stop parsing them
syntax calcStep := colGe term " := " term
syntax "calc " withPosition(calcStep+) : term

macro_rules
  | `(calc $p:term := $h:term) => `(($h : $p))
  | `(calc $p:term := $h:term $rest:calcStep*) => `(trans _ _ _ ($h : $p) (calc $rest:calcStep*))

variable (t1 t2 t3 t4 : Nat)
variable (pf12 : t1 = t2) (pf23 : t2 = t3) (pf34 : t3 = t4)

theorem foo : t1 = t4 :=
 calc
   t1 = t2 := pf12
   ... = t3 := pf23
   ... = t4 := pf34

variable (t5 : Nat)
variable (pf23' : t2 < t3) (pf45' : t4 < t5)

instance [HasLess α] : Trans (α := α) Less Less Less where
  trans := sorry

theorem foo' : t1 < t5 :=
 calc
   t1 = t2 := pf12
   ... < t3 := pf23'
   ... = t4 := pf34
   ... < t5 := pf45'


Last updated: Dec 20 2023 at 11:08 UTC