2014-12-12 04:14:53 +00:00
|
|
|
/-
|
|
|
|
Copyright (c) 2014 Jeremy Avigad. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
Authors: Jeremy Avigad, Leonardo de Moura
|
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
Various multiplicative and additive structures.
|
|
|
|
Ported from the standard library
|
2014-12-12 04:14:53 +00:00
|
|
|
-/
|
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
import algebra.binary
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
open eq is_trunc binary -- note: ⁻¹ will be overloaded
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
namespace algebra
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
variable {A : Type}
|
|
|
|
|
|
|
|
/- overloaded symbols -/
|
|
|
|
structure has_mul [class] (A : Type) :=
|
|
|
|
(mul : A → A → A)
|
|
|
|
|
|
|
|
structure has_inv [class] (A : Type) :=
|
|
|
|
(inv : A → A)
|
|
|
|
|
|
|
|
structure has_neg [class] (A : Type) :=
|
|
|
|
(neg : A → A)
|
|
|
|
|
2015-10-01 19:52:28 +00:00
|
|
|
infixl * := has_mul.mul
|
|
|
|
infixl + := has_add.add
|
|
|
|
postfix ⁻¹ := has_inv.inv
|
|
|
|
prefix - := has_neg.neg
|
|
|
|
notation 1 := !has_one.one
|
|
|
|
notation 0 := !has_zero.zero
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-28 00:02:18 +00:00
|
|
|
--a second notation for the inverse, which is not overloaded
|
2015-10-09 20:21:03 +00:00
|
|
|
postfix [parsing_only] `⁻¹ᵍ`:std.prec.max_plus := has_inv.inv
|
2015-02-28 00:02:18 +00:00
|
|
|
|
2014-12-12 04:14:53 +00:00
|
|
|
/- semigroup -/
|
|
|
|
|
|
|
|
structure semigroup [class] (A : Type) extends has_mul A :=
|
2015-05-05 21:25:35 +00:00
|
|
|
(is_hset_carrier : is_hset A)
|
2014-12-12 19:19:06 +00:00
|
|
|
(mul_assoc : ∀a b c, mul (mul a b) c = mul a (mul b c))
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
attribute semigroup.is_hset_carrier [instance]
|
2015-03-19 14:21:54 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul.assoc [s : semigroup A] (a b c : A) : a * b * c = a * (b * c) :=
|
2014-12-12 04:14:53 +00:00
|
|
|
!semigroup.mul_assoc
|
|
|
|
|
|
|
|
structure comm_semigroup [class] (A : Type) extends semigroup A :=
|
2014-12-12 19:19:06 +00:00
|
|
|
(mul_comm : ∀a b, mul a b = mul b a)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul.comm [s : comm_semigroup A] (a b : A) : a * b = b * a :=
|
2014-12-12 04:14:53 +00:00
|
|
|
!comm_semigroup.mul_comm
|
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul.left_comm [s : comm_semigroup A] (a b c : A) : a * (b * c) = b * (a * c) :=
|
2015-11-11 19:32:05 +00:00
|
|
|
binary.left_comm (@mul.comm A _) (@mul.assoc A _) a b c
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul.right_comm [s : comm_semigroup A] (a b c : A) : (a * b) * c = (a * c) * b :=
|
2015-11-11 19:32:05 +00:00
|
|
|
binary.right_comm (@mul.comm A _) (@mul.assoc A _) a b c
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure left_cancel_semigroup [class] (A : Type) extends semigroup A :=
|
2014-12-12 19:19:06 +00:00
|
|
|
(mul_left_cancel : ∀a b c, mul a b = mul a c → b = c)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul.left_cancel [s : left_cancel_semigroup A] {a b c : A} :
|
2014-12-12 19:19:06 +00:00
|
|
|
a * b = a * c → b = c :=
|
2014-12-12 04:14:53 +00:00
|
|
|
!left_cancel_semigroup.mul_left_cancel
|
|
|
|
|
2015-06-15 11:16:30 +00:00
|
|
|
abbreviation eq_of_mul_eq_mul_left' := @mul.left_cancel
|
|
|
|
|
2014-12-12 04:14:53 +00:00
|
|
|
structure right_cancel_semigroup [class] (A : Type) extends semigroup A :=
|
2014-12-12 19:19:06 +00:00
|
|
|
(mul_right_cancel : ∀a b c, mul a b = mul c b → a = c)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul.right_cancel [s : right_cancel_semigroup A] {a b c : A} :
|
2014-12-12 19:19:06 +00:00
|
|
|
a * b = c * b → a = c :=
|
2014-12-12 04:14:53 +00:00
|
|
|
!right_cancel_semigroup.mul_right_cancel
|
|
|
|
|
2015-06-15 11:16:30 +00:00
|
|
|
abbreviation eq_of_mul_eq_mul_right' := @mul.right_cancel
|
|
|
|
|
2014-12-12 04:14:53 +00:00
|
|
|
/- additive semigroup -/
|
|
|
|
|
|
|
|
structure add_semigroup [class] (A : Type) extends has_add A :=
|
2015-05-14 02:01:48 +00:00
|
|
|
(is_hset_carrier : is_hset A)
|
2014-12-12 19:19:06 +00:00
|
|
|
(add_assoc : ∀a b c, add (add a b) c = add a (add b c))
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-14 02:01:48 +00:00
|
|
|
attribute add_semigroup.is_hset_carrier [instance]
|
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add.assoc [s : add_semigroup A] (a b c : A) : a + b + c = a + (b + c) :=
|
2014-12-12 04:14:53 +00:00
|
|
|
!add_semigroup.add_assoc
|
|
|
|
|
|
|
|
structure add_comm_semigroup [class] (A : Type) extends add_semigroup A :=
|
2014-12-12 19:19:06 +00:00
|
|
|
(add_comm : ∀a b, add a b = add b a)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add.comm [s : add_comm_semigroup A] (a b : A) : a + b = b + a :=
|
2014-12-12 04:14:53 +00:00
|
|
|
!add_comm_semigroup.add_comm
|
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add.left_comm [s : add_comm_semigroup A] (a b c : A) :
|
2014-12-12 19:19:06 +00:00
|
|
|
a + (b + c) = b + (a + c) :=
|
2015-11-11 19:32:05 +00:00
|
|
|
binary.left_comm (@add.comm A _) (@add.assoc A _) a b c
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add.right_comm [s : add_comm_semigroup A] (a b c : A) : (a + b) + c = (a + c) + b :=
|
2015-11-11 19:32:05 +00:00
|
|
|
binary.right_comm (@add.comm A _) (@add.assoc A _) a b c
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure add_left_cancel_semigroup [class] (A : Type) extends add_semigroup A :=
|
2014-12-12 19:19:06 +00:00
|
|
|
(add_left_cancel : ∀a b c, add a b = add a c → b = c)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add.left_cancel [s : add_left_cancel_semigroup A] {a b c : A} :
|
2014-12-12 19:19:06 +00:00
|
|
|
a + b = a + c → b = c :=
|
2014-12-12 04:14:53 +00:00
|
|
|
!add_left_cancel_semigroup.add_left_cancel
|
|
|
|
|
2015-06-15 11:16:30 +00:00
|
|
|
abbreviation eq_of_add_eq_add_left := @add.left_cancel
|
|
|
|
|
2014-12-12 04:14:53 +00:00
|
|
|
structure add_right_cancel_semigroup [class] (A : Type) extends add_semigroup A :=
|
2014-12-12 19:19:06 +00:00
|
|
|
(add_right_cancel : ∀a b c, add a b = add c b → a = c)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add.right_cancel [s : add_right_cancel_semigroup A] {a b c : A} :
|
2014-12-12 19:19:06 +00:00
|
|
|
a + b = c + b → a = c :=
|
2014-12-12 04:14:53 +00:00
|
|
|
!add_right_cancel_semigroup.add_right_cancel
|
|
|
|
|
2015-06-15 11:16:30 +00:00
|
|
|
abbreviation eq_of_add_eq_add_right := @add.right_cancel
|
|
|
|
|
2014-12-12 04:14:53 +00:00
|
|
|
/- monoid -/
|
|
|
|
|
|
|
|
structure monoid [class] (A : Type) extends semigroup A, has_one A :=
|
2015-02-21 00:30:32 +00:00
|
|
|
(one_mul : ∀a, mul one a = a) (mul_one : ∀a, mul a one = a)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem one_mul [s : monoid A] (a : A) : 1 * a = a := !monoid.one_mul
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem mul_one [s : monoid A] (a : A) : a * 1 = a := !monoid.mul_one
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure comm_monoid [class] (A : Type) extends monoid A, comm_semigroup A
|
|
|
|
|
|
|
|
/- additive monoid -/
|
|
|
|
|
|
|
|
structure add_monoid [class] (A : Type) extends add_semigroup A, has_zero A :=
|
2015-02-21 00:30:32 +00:00
|
|
|
(zero_add : ∀a, add zero a = a) (add_zero : ∀a, add a zero = a)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem zero_add [s : add_monoid A] (a : A) : 0 + a = a := !add_monoid.zero_add
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem add_zero [s : add_monoid A] (a : A) : a + 0 = a := !add_monoid.add_zero
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure add_comm_monoid [class] (A : Type) extends add_monoid A, add_comm_semigroup A
|
|
|
|
|
|
|
|
/- group -/
|
|
|
|
|
|
|
|
structure group [class] (A : Type) extends monoid A, has_inv A :=
|
2014-12-12 19:19:06 +00:00
|
|
|
(mul_left_inv : ∀a, mul (inv a) a = one)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
-- Note: with more work, we could derive the axiom one_mul
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
section group
|
|
|
|
|
|
|
|
variable [s : group A]
|
|
|
|
include s
|
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul.left_inv (a : A) : a⁻¹ * a = 1 := !group.mul_left_inv
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
theorem inv_mul_cancel_left (a b : A) : a⁻¹ * (a * b) = b :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [-mul.assoc, mul.left_inv, one_mul]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
theorem inv_mul_cancel_right (a b : A) : a * b⁻¹ * b = a :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [mul.assoc, mul.left_inv, mul_one]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem inv_eq_of_mul_eq_one {a b : A} (H : a * b = 1) : a⁻¹ = b :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [-mul_one a⁻¹, -H, inv_mul_cancel_left]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-23 04:05:06 +00:00
|
|
|
theorem one_inv : 1⁻¹ = (1:A) := inv_eq_of_mul_eq_one (one_mul 1)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem inv_inv (a : A) : (a⁻¹)⁻¹ = a := inv_eq_of_mul_eq_one (mul.left_inv a)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem inv.inj {a b : A} (H : a⁻¹ = b⁻¹) : a = b :=
|
|
|
|
by rewrite [-inv_inv, H, inv_inv]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem inv_eq_inv_iff_eq (a b : A) : a⁻¹ = b⁻¹ ↔ a = b :=
|
|
|
|
iff.intro (assume H, inv.inj H) (assume H, ap _ H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem inv_eq_one_iff_eq_one (a b : A) : a⁻¹ = 1 ↔ a = 1 :=
|
2015-05-23 04:05:06 +00:00
|
|
|
one_inv ▸ inv_eq_inv_iff_eq a 1
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_inv_of_eq_inv {a b : A} (H : a = b⁻¹) : b = a⁻¹ :=
|
|
|
|
by rewrite [H, inv_inv]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_inv_iff_eq_inv (a b : A) : a = b⁻¹ ↔ b = a⁻¹ :=
|
|
|
|
iff.intro !eq_inv_of_eq_inv !eq_inv_of_eq_inv
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul.right_inv (a : A) : a * a⁻¹ = 1 :=
|
2014-12-12 04:14:53 +00:00
|
|
|
calc
|
2014-12-12 19:19:06 +00:00
|
|
|
a * a⁻¹ = (a⁻¹)⁻¹ * a⁻¹ : inv_inv
|
2015-05-05 21:25:35 +00:00
|
|
|
... = 1 : mul.left_inv
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
theorem mul_inv_cancel_left (a b : A) : a * (a⁻¹ * b) = b :=
|
2014-12-12 04:14:53 +00:00
|
|
|
calc
|
2015-05-05 21:25:35 +00:00
|
|
|
a * (a⁻¹ * b) = a * a⁻¹ * b : by rewrite mul.assoc
|
|
|
|
... = 1 * b : mul.right_inv
|
|
|
|
... = b : one_mul
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
theorem mul_inv_cancel_right (a b : A) : a * b * b⁻¹ = a :=
|
2014-12-12 04:14:53 +00:00
|
|
|
calc
|
2015-05-05 21:25:35 +00:00
|
|
|
a * b * b⁻¹ = a * (b * b⁻¹) : mul.assoc
|
|
|
|
... = a * 1 : mul.right_inv
|
2015-02-21 00:30:32 +00:00
|
|
|
... = a : mul_one
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-23 04:05:06 +00:00
|
|
|
theorem mul_inv (a b : A) : (a * b)⁻¹ = b⁻¹ * a⁻¹ :=
|
2015-02-21 00:30:32 +00:00
|
|
|
inv_eq_of_mul_eq_one
|
2014-12-12 04:14:53 +00:00
|
|
|
(calc
|
2015-05-05 21:25:35 +00:00
|
|
|
a * b * (b⁻¹ * a⁻¹) = a * (b * (b⁻¹ * a⁻¹)) : mul.assoc
|
|
|
|
... = a * a⁻¹ : mul_inv_cancel_left
|
|
|
|
... = 1 : mul.right_inv)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem eq_of_mul_inv_eq_one {a b : A} (H : a * b⁻¹ = 1) : a = b :=
|
2014-12-12 04:14:53 +00:00
|
|
|
calc
|
2015-05-05 21:25:35 +00:00
|
|
|
a = a * b⁻¹ * b : by rewrite inv_mul_cancel_right
|
|
|
|
... = 1 * b : H
|
|
|
|
... = b : one_mul
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_mul_inv_of_mul_eq {a b c : A} (H : a * c = b) : a = b * c⁻¹ :=
|
|
|
|
by rewrite [-H, mul_inv_cancel_right]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_inv_mul_of_mul_eq {a b c : A} (H : b * a = c) : a = b⁻¹ * c :=
|
|
|
|
by rewrite [-H, inv_mul_cancel_left]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem inv_mul_eq_of_eq_mul {a b c : A} (H : b = a * c) : a⁻¹ * b = c :=
|
|
|
|
by rewrite [H, inv_mul_cancel_left]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul_inv_eq_of_eq_mul {a b c : A} (H : a = c * b) : a * b⁻¹ = c :=
|
|
|
|
by rewrite [H, mul_inv_cancel_right]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_mul_of_mul_inv_eq {a b c : A} (H : a * c⁻¹ = b) : a = b * c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
!inv_inv ▸ (eq_mul_inv_of_mul_eq H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_mul_of_inv_mul_eq {a b c : A} (H : b⁻¹ * a = c) : a = b * c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
!inv_inv ▸ (eq_inv_mul_of_mul_eq H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul_eq_of_eq_inv_mul {a b c : A} (H : b = a⁻¹ * c) : a * b = c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
!inv_inv ▸ (inv_mul_eq_of_eq_mul H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul_eq_of_eq_mul_inv {a b c : A} (H : a = c * b⁻¹) : a * b = c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
!inv_inv ▸ (mul_inv_eq_of_eq_mul H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem mul_eq_iff_eq_inv_mul (a b c : A) : a * b = c ↔ b = a⁻¹ * c :=
|
|
|
|
iff.intro eq_inv_mul_of_mul_eq mul_eq_of_eq_inv_mul
|
|
|
|
|
|
|
|
theorem mul_eq_iff_eq_mul_inv (a b c : A) : a * b = c ↔ a = c * b⁻¹ :=
|
|
|
|
iff.intro eq_mul_inv_of_mul_eq mul_eq_of_eq_mul_inv
|
|
|
|
|
|
|
|
theorem mul_left_cancel {a b c : A} (H : a * b = a * c) : b = c :=
|
|
|
|
by rewrite [-inv_mul_cancel_left a b, H, inv_mul_cancel_left]
|
|
|
|
|
|
|
|
theorem mul_right_cancel {a b c : A} (H : a * b = c * b) : a = c :=
|
|
|
|
by rewrite [-mul_inv_cancel_right a b, H, mul_inv_cancel_right]
|
|
|
|
|
2015-11-11 19:32:05 +00:00
|
|
|
definition group.to_left_cancel_semigroup [instance] [reducible] : left_cancel_semigroup A :=
|
2015-05-05 21:25:35 +00:00
|
|
|
⦃ left_cancel_semigroup, s,
|
|
|
|
mul_left_cancel := @mul_left_cancel A s ⦄
|
|
|
|
|
2015-11-11 19:32:05 +00:00
|
|
|
definition group.to_right_cancel_semigroup [instance] [reducible] : right_cancel_semigroup A :=
|
2015-05-05 21:25:35 +00:00
|
|
|
⦃ right_cancel_semigroup, s,
|
|
|
|
mul_right_cancel := @mul_right_cancel A s ⦄
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
end group
|
|
|
|
|
|
|
|
structure comm_group [class] (A : Type) extends group A, comm_monoid A
|
|
|
|
|
|
|
|
/- additive group -/
|
|
|
|
|
|
|
|
structure add_group [class] (A : Type) extends add_monoid A, has_neg A :=
|
2014-12-12 19:19:06 +00:00
|
|
|
(add_left_inv : ∀a, add (neg a) a = zero)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
section add_group
|
|
|
|
|
|
|
|
variables [s : add_group A]
|
|
|
|
include s
|
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add.left_inv (a : A) : -a + a = 0 := !add_group.add_left_inv
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
theorem neg_add_cancel_left (a b : A) : -a + (a + b) = b :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [-add.assoc, add.left_inv, zero_add]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
theorem neg_add_cancel_right (a b : A) : a + -b + b = a :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [add.assoc, add.left_inv, add_zero]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg_eq_of_add_eq_zero {a b : A} (H : a + b = 0) : -a = b :=
|
|
|
|
by rewrite [-add_zero, -H, neg_add_cancel_left]
|
|
|
|
|
2015-05-18 22:45:23 +00:00
|
|
|
theorem neg_zero : -0 = (0:A) := neg_eq_of_add_eq_zero (zero_add 0)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg_neg (a : A) : -(-a) = a := neg_eq_of_add_eq_zero (add.left_inv a)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_neg_of_add_eq_zero {a b : A} (H : a + b = 0) : a = -b :=
|
|
|
|
by rewrite [-neg_eq_of_add_eq_zero H, neg_neg]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg.inj {a b : A} (H : -a = -b) : a = b :=
|
2014-12-12 04:14:53 +00:00
|
|
|
calc
|
2014-12-12 19:19:06 +00:00
|
|
|
a = -(-a) : neg_neg
|
2015-05-05 21:25:35 +00:00
|
|
|
... = b : neg_eq_of_add_eq_zero (H⁻¹ ▸ (add.left_inv _))
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg_eq_neg_iff_eq (a b : A) : -a = -b ↔ a = b :=
|
|
|
|
iff.intro (assume H, neg.inj H) (assume H, ap _ H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg_eq_zero_iff_eq_zero (a : A) : -a = 0 ↔ a = 0 :=
|
|
|
|
neg_zero ▸ !neg_eq_neg_iff_eq
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_neg_of_eq_neg {a b : A} (H : a = -b) : b = -a :=
|
2015-05-01 03:23:12 +00:00
|
|
|
H⁻¹ ▸ (neg_neg b)⁻¹
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_neg_iff_eq_neg (a b : A) : a = -b ↔ b = -a :=
|
|
|
|
iff.intro !eq_neg_of_eq_neg !eq_neg_of_eq_neg
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add.right_inv (a : A) : a + -a = 0 :=
|
2014-12-12 04:14:53 +00:00
|
|
|
calc
|
2014-12-12 19:19:06 +00:00
|
|
|
a + -a = -(-a) + -a : neg_neg
|
2015-05-05 21:25:35 +00:00
|
|
|
... = 0 : add.left_inv
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
theorem add_neg_cancel_left (a b : A) : a + (-a + b) = b :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [-add.assoc, add.right_inv, zero_add]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2014-12-12 19:19:06 +00:00
|
|
|
theorem add_neg_cancel_right (a b : A) : a + b + -b = a :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [add.assoc, add.right_inv, add_zero]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg_add_rev (a b : A) : -(a + b) = -b + -a :=
|
|
|
|
neg_eq_of_add_eq_zero
|
|
|
|
begin
|
|
|
|
rewrite [add.assoc, add_neg_cancel_left, add.right_inv]
|
|
|
|
end
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
-- TODO: delete these in favor of sub rules?
|
|
|
|
theorem eq_add_neg_of_add_eq {a b c : A} (H : a + c = b) : a = b + -c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
H ▸ !add_neg_cancel_right⁻¹
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_neg_add_of_add_eq {a b c : A} (H : b + a = c) : a = -b + c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
H ▸ !neg_add_cancel_left⁻¹
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg_add_eq_of_eq_add {a b c : A} (H : b = a + c) : -a + b = c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
H⁻¹ ▸ !neg_add_cancel_left
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add_neg_eq_of_eq_add {a b c : A} (H : a = c + b) : a + -b = c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
H⁻¹ ▸ !add_neg_cancel_right
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_add_of_add_neg_eq {a b c : A} (H : a + -c = b) : a = b + c :=
|
|
|
|
!neg_neg ▸ (eq_add_neg_of_add_eq H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_add_of_neg_add_eq {a b c : A} (H : -b + a = c) : a = b + c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
!neg_neg ▸ (eq_neg_add_of_add_eq H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add_eq_of_eq_neg_add {a b c : A} (H : b = -a + c) : a + b = c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
!neg_neg ▸ (neg_add_eq_of_eq_add H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add_eq_of_eq_add_neg {a b c : A} (H : a = c + -b) : a + b = c :=
|
2015-05-01 03:23:12 +00:00
|
|
|
!neg_neg ▸ (add_neg_eq_of_eq_add H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add_eq_iff_eq_neg_add (a b c : A) : a + b = c ↔ b = -a + c :=
|
|
|
|
iff.intro eq_neg_add_of_add_eq add_eq_of_eq_neg_add
|
|
|
|
|
|
|
|
theorem add_eq_iff_eq_add_neg (a b c : A) : a + b = c ↔ a = c + -b :=
|
|
|
|
iff.intro eq_add_neg_of_add_eq add_eq_of_eq_add_neg
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add_left_cancel {a b c : A} (H : a + b = a + c) : b = c :=
|
|
|
|
calc b = -a + (a + b) : !neg_add_cancel_left⁻¹
|
|
|
|
... = -a + (a + c) : H
|
|
|
|
... = c : neg_add_cancel_left
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add_right_cancel {a b c : A} (H : a + b = c + b) : a = c :=
|
|
|
|
calc a = (a + b) + -b : !add_neg_cancel_right⁻¹
|
|
|
|
... = (c + b) + -b : H
|
|
|
|
... = c : add_neg_cancel_right
|
|
|
|
|
2015-11-11 19:32:05 +00:00
|
|
|
definition add_group.to_left_cancel_semigroup [instance] [reducible] :
|
2014-12-12 04:14:53 +00:00
|
|
|
add_left_cancel_semigroup A :=
|
2015-05-05 21:25:35 +00:00
|
|
|
⦃ add_left_cancel_semigroup, s,
|
|
|
|
add_left_cancel := @add_left_cancel A s ⦄
|
|
|
|
|
2015-11-11 19:32:05 +00:00
|
|
|
definition add_group.to_add_right_cancel_semigroup [instance][reducible] :
|
2014-12-12 04:14:53 +00:00
|
|
|
add_right_cancel_semigroup A :=
|
2015-05-05 21:25:35 +00:00
|
|
|
⦃ add_right_cancel_semigroup, s,
|
|
|
|
add_right_cancel := @add_right_cancel A s ⦄
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
/- sub -/
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
-- TODO: derive corresponding facts for div in a field
|
2015-02-21 00:30:32 +00:00
|
|
|
definition sub [reducible] (a b : A) : A := a + -b
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-10-01 19:52:28 +00:00
|
|
|
infix - := sub
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem sub_eq_add_neg (a b : A) : a - b = a + -b := rfl
|
|
|
|
|
|
|
|
theorem sub_self (a : A) : a - a = 0 := !add.right_inv
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem sub_add_cancel (a b : A) : a - b + b = a := !neg_add_cancel_right
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem add_sub_cancel (a b : A) : a + b - b = a := !add_neg_cancel_right
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem eq_of_sub_eq_zero {a b : A} (H : a - b = 0) : a = b :=
|
2014-12-12 04:14:53 +00:00
|
|
|
calc
|
2015-05-05 21:25:35 +00:00
|
|
|
a = (a - b) + b : !sub_add_cancel⁻¹
|
2014-12-12 19:19:06 +00:00
|
|
|
... = 0 + b : H
|
2015-02-21 00:30:32 +00:00
|
|
|
... = b : zero_add
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_iff_sub_eq_zero (a b : A) : a = b ↔ a - b = 0 :=
|
|
|
|
iff.intro (assume H, H ▸ !sub_self) (assume H, eq_of_sub_eq_zero H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem zero_sub (a : A) : 0 - a = -a := !zero_add
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem sub_zero (a : A) : a - 0 = a := subst (eq.symm neg_zero) !add_zero
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-06-22 19:22:11 +00:00
|
|
|
theorem sub_neg_eq_add (a b : A) : a - (-b) = a + b :=
|
|
|
|
by change a + -(-b) = a + b; rewrite neg_neg
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem neg_sub (a b : A) : -(a - b) = b - a :=
|
2015-05-05 21:25:35 +00:00
|
|
|
neg_eq_of_add_eq_zero
|
2014-12-12 04:14:53 +00:00
|
|
|
(calc
|
2015-05-05 21:25:35 +00:00
|
|
|
a - b + (b - a) = a - b + b - a : by rewrite -add.assoc
|
|
|
|
... = a - a : sub_add_cancel
|
|
|
|
... = 0 : sub_self)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem add_sub (a b c : A) : a + (b - c) = a + b - c := !add.assoc⁻¹
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem sub_add_eq_sub_sub_swap (a b c : A) : a - (b + c) = a - c - b :=
|
2014-12-12 04:14:53 +00:00
|
|
|
calc
|
2015-05-05 21:25:35 +00:00
|
|
|
a - (b + c) = a + (-c - b) : neg_add_rev
|
|
|
|
... = a - c - b : by rewrite add.assoc
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem sub_eq_iff_eq_add (a b c : A) : a - b = c ↔ a = c + b :=
|
|
|
|
iff.intro (assume H, eq_add_of_add_neg_eq H) (assume H, add_neg_eq_of_eq_add H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_sub_iff_add_eq (a b c : A) : a = b - c ↔ a + c = b :=
|
|
|
|
iff.intro (assume H, add_eq_of_eq_add_neg H) (assume H, eq_add_neg_of_add_eq H)
|
|
|
|
|
|
|
|
theorem eq_iff_eq_of_sub_eq_sub {a b c d : A} (H : a - b = c - d) : a = b ↔ c = d :=
|
|
|
|
calc
|
|
|
|
a = b ↔ a - b = 0 : eq_iff_sub_eq_zero
|
|
|
|
... = (c - d = 0) : H
|
|
|
|
... ↔ c = d : iff.symm (eq_iff_sub_eq_zero c d)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_sub_of_add_eq {a b c : A} (H : a + c = b) : a = b - c :=
|
|
|
|
!eq_add_neg_of_add_eq H
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem sub_eq_of_eq_add {a b c : A} (H : a = c + b) : a - b = c :=
|
|
|
|
!add_neg_eq_of_eq_add H
|
|
|
|
|
|
|
|
theorem eq_add_of_sub_eq {a b c : A} (H : a - c = b) : a = b + c :=
|
|
|
|
eq_add_of_add_neg_eq H
|
|
|
|
|
|
|
|
theorem add_eq_of_eq_sub {a b c : A} (H : a = c - b) : a + b = c :=
|
|
|
|
add_eq_of_eq_add_neg H
|
2014-12-12 04:14:53 +00:00
|
|
|
end add_group
|
|
|
|
|
|
|
|
structure add_comm_group [class] (A : Type) extends add_group A, add_comm_monoid A
|
|
|
|
|
|
|
|
section add_comm_group
|
2015-05-05 21:25:35 +00:00
|
|
|
variable [s : add_comm_group A]
|
|
|
|
include s
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem sub_add_eq_sub_sub (a b c : A) : a - (b + c) = a - b - c :=
|
2015-05-05 21:25:35 +00:00
|
|
|
!add.comm ▸ !sub_add_eq_sub_sub_swap
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg_add_eq_sub (a b : A) : -a + b = b - a := !add.comm
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem neg_add (a b : A) : -(a + b) = -a + -b := add.comm (-b) (-a) ▸ neg_add_rev a b
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem sub_add_eq_add_sub (a b c : A) : a - b + c = a + c - b := !add.right_comm
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem sub_sub (a b c : A) : a - b - c = a - (b + c) :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [▸ a + -b + -c = _, add.assoc, -neg_add]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-02-21 00:30:32 +00:00
|
|
|
theorem add_sub_add_left_eq_sub (a b c : A) : (c + a) - (c + b) = a - b :=
|
2015-05-05 21:25:35 +00:00
|
|
|
by rewrite [sub_add_eq_sub_sub, (add.comm c a), add_sub_cancel]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_sub_of_add_eq' {a b c : A} (H : c + a = b) : a = b - c :=
|
|
|
|
!eq_sub_of_add_eq (!add.comm ▸ H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem sub_eq_of_eq_add' {a b c : A} (H : a = b + c) : a - b = c :=
|
|
|
|
!sub_eq_of_eq_add (!add.comm ▸ H)
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
theorem eq_add_of_sub_eq' {a b c : A} (H : a - b = c) : a = b + c :=
|
|
|
|
!add.comm ▸ eq_add_of_sub_eq H
|
|
|
|
|
|
|
|
theorem add_eq_of_eq_sub' {a b c : A} (H : b = c - a) : a + b = c :=
|
|
|
|
!add.comm ▸ add_eq_of_eq_sub H
|
|
|
|
end add_comm_group
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-14 02:01:48 +00:00
|
|
|
definition group_of_add_group (A : Type) [G : add_group A] : group A :=
|
|
|
|
⦃group,
|
|
|
|
mul := has_add.add,
|
|
|
|
mul_assoc := add.assoc,
|
|
|
|
one := !has_zero.zero,
|
|
|
|
one_mul := zero_add,
|
|
|
|
mul_one := add_zero,
|
|
|
|
inv := has_neg.neg,
|
|
|
|
mul_left_inv := add.left_inv,
|
|
|
|
is_hset_carrier := !add_group.is_hset_carrier⦄
|
|
|
|
|
2014-12-12 04:14:53 +00:00
|
|
|
/- bundled structures -/
|
|
|
|
structure Semigroup :=
|
|
|
|
(carrier : Type) (struct : semigroup carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute Semigroup.carrier [coercion]
|
|
|
|
attribute Semigroup.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure CommSemigroup :=
|
|
|
|
(carrier : Type) (struct : comm_semigroup carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute CommSemigroup.carrier [coercion]
|
|
|
|
attribute CommSemigroup.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure Monoid :=
|
|
|
|
(carrier : Type) (struct : monoid carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute Monoid.carrier [coercion]
|
|
|
|
attribute Monoid.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure CommMonoid :=
|
|
|
|
(carrier : Type) (struct : comm_monoid carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute CommMonoid.carrier [coercion]
|
|
|
|
attribute CommMonoid.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure Group :=
|
|
|
|
(carrier : Type) (struct : group carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute Group.carrier [coercion]
|
|
|
|
attribute Group.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure CommGroup :=
|
|
|
|
(carrier : Type) (struct : comm_group carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute CommGroup.carrier [coercion]
|
|
|
|
attribute CommGroup.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure AddSemigroup :=
|
|
|
|
(carrier : Type) (struct : add_semigroup carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute AddSemigroup.carrier [coercion]
|
|
|
|
attribute AddSemigroup.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure AddCommSemigroup :=
|
|
|
|
(carrier : Type) (struct : add_comm_semigroup carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute AddCommSemigroup.carrier [coercion]
|
|
|
|
attribute AddCommSemigroup.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure AddMonoid :=
|
|
|
|
(carrier : Type) (struct : add_monoid carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute AddMonoid.carrier [coercion]
|
|
|
|
attribute AddMonoid.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure AddCommMonoid :=
|
|
|
|
(carrier : Type) (struct : add_comm_monoid carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute AddCommMonoid.carrier [coercion]
|
|
|
|
attribute AddCommMonoid.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure AddGroup :=
|
|
|
|
(carrier : Type) (struct : add_group carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute AddGroup.carrier [coercion]
|
|
|
|
attribute AddGroup.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
|
|
|
structure AddCommGroup :=
|
|
|
|
(carrier : Type) (struct : add_comm_group carrier)
|
|
|
|
|
2015-01-26 19:31:12 +00:00
|
|
|
attribute AddCommGroup.carrier [coercion]
|
|
|
|
attribute AddCommGroup.struct [instance]
|
2014-12-12 04:14:53 +00:00
|
|
|
|
2015-05-05 21:25:35 +00:00
|
|
|
end algebra
|