Cubical.Algebra.Group.Base

module Cubical.Algebra.Group.Base where
{-
  Defines groups and adds the smart constructors [makeGroup-right] and [makeGroup-left]
  for constructing groups from less data than the standard [makeGroup] constructor.
-}

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Structure
open import Cubical.Data.Sigma
open import Cubical.Data.Nat using (ℕ)
open import Cubical.Data.Fin.Inductive.Base
open import Cubical.Algebra.Monoid
open import Cubical.Algebra.Semigroup

open import Cubical.Reflection.RecordEquiv


private
  variable
    ℓ : Level

record IsGroup {G : Type ℓ}
               (1g : G) (_·_ : G → G → G) (inv : G → G) : Type ℓ where

  constructor isgroup

  field
    isMonoid  : IsMonoid 1g _·_
    ·InvR : (x : G) → x · inv x ≡ 1g
    ·InvL : (x : G) → inv x · x ≡ 1g

  open IsMonoid isMonoid public

unquoteDecl IsGroupIsoΣ = declareRecordIsoΣ IsGroupIsoΣ (quote IsGroup)

record GroupStr (G : Type ℓ) : Type ℓ where

  constructor groupstr

  field
    1g      : G
    _·_     : G → G → G
    inv     : G → G
    isGroup : IsGroup 1g _·_ inv

  infixr 7 _·_

  open IsGroup isGroup public

unquoteDecl GroupStrIsoΣ = declareRecordIsoΣ GroupStrIsoΣ (quote GroupStr)

Group : ∀ ℓ → Type (ℓ-suc ℓ)
Group ℓ = TypeWithStr ℓ GroupStr

Group₀ : Type₁
Group₀ = Group ℓ-zero

group : (G : Type ℓ) (1g : G) (_·_ : G → G → G) (inv : G → G) (h : IsGroup 1g _·_ inv) → Group ℓ
group G 1g _·_ inv h = G , groupstr 1g _·_ inv h

makeIsGroup : {G : Type ℓ} {e : G} {_·_ : G → G → G} { inv : G → G}
              (is-setG : isSet G)
              (·Assoc : (x y z : G) → x · (y · z) ≡ (x · y) · z)
              (·IdR : (x : G) → x · e ≡ x)
              (·IdL : (x : G) → e · x ≡ x)
              (·InvR : (x : G) → x · inv x ≡ e)
              (·InvL : (x : G) → inv x · x ≡ e)
            → IsGroup e _·_ inv
IsGroup.isMonoid (makeIsGroup is-setG ·Assoc ·IdR ·IdL ·InvR ·InvL) = makeIsMonoid is-setG ·Assoc ·IdR ·IdL
IsGroup.·InvR (makeIsGroup is-setG ·Assoc ·IdR ·IdL ·InvR ·InvL) = ·InvR
IsGroup.·InvL (makeIsGroup is-setG ·Assoc ·IdR ·IdL ·InvR ·InvL) = ·InvL

makeGroup : {G : Type ℓ} (1g : G) (_·_ : G → G → G) (inv : G → G)
            (is-setG : isSet G)
            (·Assoc : (x y z : G) → x · (y · z) ≡ (x · y) · z)
            (·IdR : (x : G) → x · 1g ≡ x)
            (·IdL : (x : G) → 1g · x ≡ x)
            (·InvR : (x : G) → x · inv x ≡ 1g)
            (·InvL : (x : G) → inv x · x ≡ 1g)
          → Group ℓ
makeGroup 1g _·_ inv is-setG ·Assoc ·IdR ·IdL ·InvR ·InvL = _ , helper
  where
  helper : GroupStr _
  GroupStr.1g helper = 1g
  GroupStr._·_ helper = _·_
  GroupStr.inv helper = inv
  GroupStr.isGroup helper = makeIsGroup is-setG ·Assoc ·IdR ·IdL ·InvR ·InvL

Group→Monoid : Group ℓ → Monoid ℓ
Group→Monoid (A , groupstr  _ _ _ G) = A , monoidstr _ _ (IsGroup.isMonoid G)

makeGroup-right : {A : Type ℓ}
  → (1g : A)
  → (_·_ : A → A → A)
  → (inv : A → A)
  → (set : isSet A)
  → (·Assoc : ∀ a b c → a · (b · c) ≡ (a · b) · c)
  → (·IdR : ∀ a → a · 1g ≡ a)
  → (·InvR : ∀ a → a · inv a ≡ 1g)
  → Group ℓ
makeGroup-right 1g _·_ inv set ·Assoc ·IdR ·InvR =
  makeGroup 1g _·_ inv set ·Assoc ·IdR ·IdL ·InvR ·InvL
  where
    abstract
      ·InvL : ∀ a → inv a · a ≡ 1g
      ·InvL a =
        inv a · a
          ≡⟨ sym (·IdR _)  ⟩
        (inv a · a) · 1g
          ≡⟨ cong (_·_ _) (sym (·InvR (inv a))) ⟩
        (inv a · a) · (inv a · (inv (inv a)))
          ≡⟨ ·Assoc _ _ _ ⟩
        ((inv a · a) · (inv a)) · (inv (inv a))
          ≡⟨ cong (λ □ → □ · _) (sym (·Assoc _ _ _)) ⟩
        (inv a · (a · inv a)) · (inv (inv a))
          ≡⟨ cong (λ □ → (inv a · □) · (inv (inv a))) (·InvR a) ⟩
        (inv a · 1g) · (inv (inv a))
          ≡⟨ cong (λ □ → □ · (inv (inv a))) (·IdR (inv a)) ⟩
        inv a · (inv (inv a))
          ≡⟨ ·InvR (inv a) ⟩
        1g
          ∎

      ·IdL : ∀ a → 1g · a ≡ a
      ·IdL a =
        1g · a
          ≡⟨ cong (λ b → b · a) (sym (·InvR a)) ⟩
        (a · inv a) · a
          ≡⟨ sym (·Assoc _ _ _) ⟩
        a · (inv a · a)
          ≡⟨ cong (a ·_) (·InvL a) ⟩
        a · 1g
          ≡⟨ ·IdR a ⟩
        a
          ∎

makeGroup-left : {A : Type ℓ}
  → (1g : A)
  → (_·_ : A → A → A)
  → (inv : A → A)
  → (set : isSet A)
  → (·Assoc : ∀ a b c → a · (b · c) ≡ (a · b) · c)
  → (·IdL : ∀ a → 1g · a ≡ a)
  → (·InvL : ∀ a → (inv a) · a ≡ 1g)
  → Group ℓ
makeGroup-left 1g _·_ inv set ·Assoc ·IdL ·InvL =
  makeGroup 1g _·_ inv set ·Assoc ·IdR ·IdL ·InvR ·InvL
  where
    abstract
      ·InvR : ∀ a → a · inv a ≡ 1g
      ·InvR a =
        a · inv a
          ≡⟨ sym (·IdL _)  ⟩
        1g · (a · inv a)
          ≡⟨ cong (λ b → b · (a · inv a)) (sym (·InvL (inv a))) ⟩
        (inv (inv a) · inv a) · (a · inv a)
          ≡⟨ sym (·Assoc (inv (inv a)) (inv a) _) ⟩
        inv (inv a) · (inv a · (a · inv a))
          ≡⟨ cong (inv (inv a) ·_) (·Assoc (inv a) a (inv a)) ⟩
        (inv (inv a)) · ((inv a · a) · (inv a))
          ≡⟨ cong (λ b → (inv (inv a)) · (b · (inv a))) (·InvL a) ⟩
        inv (inv a) · (1g · inv a)
          ≡⟨ cong (inv (inv a) ·_) (·IdL (inv a)) ⟩
        inv (inv a) · inv a
          ≡⟨ ·InvL (inv a) ⟩
        1g
          ∎

      ·IdR : ∀ a → a · 1g ≡ a
      ·IdR a =
        a · 1g
          ≡⟨ cong (a ·_) (sym (·InvL a)) ⟩
        a · (inv a · a)
          ≡⟨ ·Assoc a (inv a) a ⟩
        (a · inv a) · a
          ≡⟨ cong (λ b → b · a) (·InvR a) ⟩
        1g · a
          ≡⟨ ·IdL a ⟩
        a
          ∎

sumFinGroup : ∀ {ℓ} (G : Group ℓ) {n : ℕ} (f : Fin n → fst G) → fst G
sumFinGroup G {n = n} f = sumFinGen {n = n} (GroupStr._·_ (snd G)) (GroupStr.1g (snd G)) f