------------------------------------------------------------------------
-- A variant of Induction for Set₁
------------------------------------------------------------------------

-- I want universe polymorphism.

module Induction1 where

open import Relation.Unary1

-- A RecStruct describes the allowed structure of recursion. The
-- examples in Induction.Nat should explain what this is all about.

RecStruct : Set → Set₂
RecStruct a = Pred a → Pred a

-- A recursor builder constructs an instance of a recursion structure
-- for a given input.

RecursorBuilder : ∀ {a} → RecStruct a → Set₂
RecursorBuilder {a} Rec = (P : Pred a) → Rec P ⊆′ P → Universal (Rec P)

-- A recursor can be used to actually compute/prove something useful.

Recursor : ∀ {a} → RecStruct a → Set₂
Recursor {a} Rec = (P : Pred a) → Rec P ⊆′ P → Universal P

-- And recursors can be constructed from recursor builders.

build : ∀ {a} {Rec : RecStruct a} →
        RecursorBuilder Rec →
        Recursor Rec
build builder P f x = f x (builder P f x)

-- We can repeat the exercise above for subsets of the type we are
-- recursing over.

SubsetRecursorBuilder : ∀ {a} → Pred a → RecStruct a → Set₂
SubsetRecursorBuilder {a} Q Rec = (P : Pred a) → Rec P ⊆′ P → Q ⊆′ Rec P

SubsetRecursor : ∀ {a} → Pred a → RecStruct a → Set₂
SubsetRecursor {a} Q Rec = (P : Pred a) → Rec P ⊆′ P → Q ⊆′ P

subsetBuild : ∀ {a} {Q : Pred a} {Rec : RecStruct a} →
              SubsetRecursorBuilder Q Rec →
              SubsetRecursor Q Rec
subsetBuild builder P f x q = f x (builder P f x q)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Left inverses
------------------------------------------------------------------------

module Function.LeftInverse where

open import Data.Product
open import Level
import Relation.Binary.EqReasoning as EqReasoning
open import Relation.Binary
open import Function.Equality as Eq
  using (_⟶_; _⟨$⟩_) renaming (_∘_ to _⟪∘⟫_)
open import Function.Equivalence using (Equivalence)
open import Function.Injection using (Injective; Injection)
import Relation.Binary.PropositionalEquality as P

-- Left and right inverses.

_LeftInverseOf_ :
  ∀ {f₁ f₂ t₁ t₂} {From : Setoid f₁ f₂} {To : Setoid t₁ t₂} →
  To ⟶ From → From ⟶ To → Set _
_LeftInverseOf_ {From = From} f g = ∀ x → f ⟨$⟩ (g ⟨$⟩ x) ≈ x
  where open Setoid From

_RightInverseOf_ :
  ∀ {f₁ f₂ t₁ t₂} {From : Setoid f₁ f₂} {To : Setoid t₁ t₂} →
  To ⟶ From → From ⟶ To → Set _
f RightInverseOf g = g LeftInverseOf f

-- The set of all left inverses between two setoids.

record LeftInverse {f₁ f₂ t₁ t₂}
                   (From : Setoid f₁ f₂) (To : Setoid t₁ t₂) :
                   Set (f₁ ⊔ f₂ ⊔ t₁ ⊔ t₂) where
  field
    to              : From ⟶ To
    from            : To ⟶ From
    left-inverse-of : from LeftInverseOf to

  private
    open module F = Setoid From
    open module T = Setoid To
  open EqReasoning From

  injective : Injective to
  injective {x} {y} eq = begin
    x                    ≈⟨ F.sym (left-inverse-of x) ⟩
    from ⟨$⟩ (to ⟨$⟩ x)  ≈⟨ Eq.cong from eq ⟩
    from ⟨$⟩ (to ⟨$⟩ y)  ≈⟨ left-inverse-of y ⟩
    y                    ∎

  injection : Injection From To
  injection = record { to = to; injective = injective }

  equivalence : Equivalence From To
  equivalence = record
    { to   = to
    ; from = from
    }

  to-from : ∀ {x y} → to ⟨$⟩ x T.≈ y → from ⟨$⟩ y F.≈ x
  to-from {x} {y} to-x≈y = begin
    from ⟨$⟩ y           ≈⟨ Eq.cong from (T.sym to-x≈y) ⟩
    from ⟨$⟩ (to ⟨$⟩ x)  ≈⟨ left-inverse-of x ⟩
    x                    ∎

-- The set of all right inverses between two setoids.

RightInverse : ∀ {f₁ f₂ t₁ t₂}
               (From : Setoid f₁ f₂) (To : Setoid t₁ t₂) → Set _
RightInverse From To = LeftInverse To From

-- The set of all left inverses from one set to another. (Read A ↞ B
-- as "surjection from B to A".)

infix 3 _↞_

_↞_ : ∀ {f t} → Set f → Set t → Set _
From ↞ To = LeftInverse (P.setoid From) (P.setoid To)

-- Identity and composition.

id : ∀ {s₁ s₂} {S : Setoid s₁ s₂} → LeftInverse S S
id {S = S} = record
  { to              = Eq.id
  ; from            = Eq.id
  ; left-inverse-of = λ _ → Setoid.refl S
  }

infixr 9 _∘_

_∘_ : ∀ {f₁ f₂ m₁ m₂ t₁ t₂}
        {F : Setoid f₁ f₂} {M : Setoid m₁ m₂} {T : Setoid t₁ t₂} →
      LeftInverse M T → LeftInverse F M → LeftInverse F T
_∘_ {F = F} f g = record
  { to              = to   f ⟪∘⟫ to   g
  ; from            = from g ⟪∘⟫ from f
  ; left-inverse-of = λ x → begin
      from g ⟨$⟩ (from f ⟨$⟩ (to f ⟨$⟩ (to g ⟨$⟩ x)))  ≈⟨ Eq.cong (from g) (left-inverse-of f (to g ⟨$⟩ x)) ⟩
      from g ⟨$⟩ (to g ⟨$⟩ x)                          ≈⟨ left-inverse-of g x ⟩
      x                                                ∎
  }
  where
  open LeftInverse
  open EqReasoning F


{-# OPTIONS --without-K --rewriting #-}

open import HoTT
open import homotopy.PtdMapSequence
open import homotopy.CofiberSequence
open import groups.Exactness
open import groups.ExactSequence
open import groups.HomSequence
open import cohomology.Theory

module cohomology.Sigma {i} (CT : CohomologyTheory i)
  (n : ℤ) (X : Ptd i) (Y : de⊙ X → Ptd i) where

open CohomologyTheory CT
open import cohomology.PtdMapSequence CT

{- Cⁿ(Σx:X.Y) = Cⁿ(⋁x:X.Y) × Cⁿ(X). The proof is by constructing a
 - splitting exact sequence

       0 → Cⁿ(⋁x:X.Y) → Cⁿ(Σx:X.Y) → Cⁿ(X)

 - by observing that the map [select : x ↦ (x, pt Yₓ)] has a left inverse
 - and satisfies [Cofiber select == ⋁x:X.Y. -}

⊙select : X ⊙→ ⊙Σ X Y
⊙select = (bigwedge-f Y , idp)

⊙Σbwin : ⊙Σ X Y ⊙→ ⊙BigWedge Y
⊙Σbwin = ⊙cfcod' ⊙select

private
  abstract
    cst-C-Σbwin-is-exact : is-exact (cst-hom {G = C n (⊙Susp X)}) (C-fmap n ⊙Σbwin)
    cst-C-Σbwin-is-exact = equiv-preserves-exact
      {φ₁ = cst-hom {G = C n (⊙Susp X)}}
      {ξG = C-fmap n (⊙Susp-to-⊙Cof² ⊙select)} {ξH = idhom _} {ξK = idhom _}
      (comm-sqrᴳ λ x →
        CEl-fmap n (⊙cfcod²' ⊙select) x
          =⟨ ! $ CEl-fmap-idf n $ CEl-fmap n (⊙cfcod²' ⊙select) x ⟩
        CEl-fmap n (⊙idf _) (CEl-fmap n (⊙cfcod²' ⊙select) x)
          =⟨ C-comm-square n (extract-glue-cod²-comm-sqr ⊙select) □$ᴳ x ⟩
        CEl-fmap n ⊙extract-glue (CEl-fmap n (⊙Susp-to-⊙Cof² ⊙select) x)
          =⟨ CEl-fmap-const n (extract-glue-from-BigWedge-is-const Y) _ ⟩
        Cident n _
          =∎)
      (comm-sqrᴳ λ _ → idp)
      (C-isemap n (⊙Susp-to-⊙Cof² ⊙select) (snd (Cof²-equiv-Susp ⊙select ⁻¹)))
      (idf-is-equiv _)
      (idf-is-equiv _)
      (C-exact n ⊙Σbwin)

  χ : C n X →ᴳ C n (⊙Σ X Y)
  χ = C-fmap n (⊙fstᵈ Y)

  abstract
    select-χ-is-idf : ∀ s → CEl-fmap n ⊙select (GroupHom.f χ s) == s
    select-χ-is-idf = CEl-fmap-inverse n ⊙select (⊙fstᵈ Y) λ _ → idp

C-Σ : C n (⊙Σ X Y) ≃ᴳ C n (⊙BigWedge Y) ×ᴳ C n X
C-Σ = Exact.φ-inj-and-ψ-has-rinv-split
  (C-exact n ⊙select) (C-is-abelian n _)
  (Exact.φ-const-implies-ψ-is-inj cst-C-Σbwin-is-exact (λ _ → idp))
  χ select-χ-is-idf

{-
  ⊙Σbwin-over : CF-hom n ⊙Σbwin == ×ᴳ-inl
                [ (λ G → GroupHom (C n (⊙BigWedge Y)) G) ↓ path ]
  ⊙Σbwin-over = SER.φ-over-iso

  ⊙select-over : CF-hom n ⊙select == ×ᴳ-snd {G = C n (⊙BigWedge Y)}
                 [ (λ G → GroupHom G (C n X)) ↓ path ]
  ⊙select-over = SER.ψ-over-iso

  open CofSelect public using (select; ⊙select; ⊙Σbwin)
-}


{-# OPTIONS --without-K #-}

open import HoTT

module homotopy.AnyUniversalCoverIsPathSet {i} (A : Type i)
  -- (A-conn : is-connected 0 A)
  where

  open Cover

  module _
    (a₁ : A)
    -- A universal covering (defined as being simply connected).
    {j} (univ-cov : Cover A j)
    (univ-cov-univ : is-universal univ-cov)
    (a⇑₁ : Fiber univ-cov a₁)
    where

    private
      -- One-to-one mapping between the universal cover
      -- and the truncated path spaces from one point.

      [path] : ∀ (a⇑₁ a⇑₂ : TotalSpace univ-cov) → a⇑₁ =₀ a⇑₂
      [path] a⇑₁ a⇑₂ = –> (Trunc=-equiv [ a⇑₁ ] [ a⇑₂ ])
        (contr-has-all-paths univ-cov-univ [ a⇑₁ ] [ a⇑₂ ])

      [path]-has-all-paths :
        ∀ {a⇑₁ a⇑₂ : TotalSpace univ-cov}
        → has-all-paths (a⇑₁ =₀ a⇑₂)
      [path]-has-all-paths {a⇑₁} {a⇑₂} =
        coe (ap has-all-paths $ ua (Trunc=-equiv [ a⇑₁ ] [ a⇑₂ ]))
        $ contr-has-all-paths (raise-level -2 univ-cov-univ [ a⇑₁ ] [ a⇑₂ ])

      to : ∀ {a₂} → Fiber univ-cov a₂ → a₁ =₀ a₂
      to {a₂} a⇑₂ = ap₀ fst ([path] (a₁ , a⇑₁) (a₂ , a⇑₂))

      from : ∀ {a₂} → a₁ =₀ a₂ → Fiber univ-cov a₂
      from p = cover-trace univ-cov a⇑₁ p

      to-from : ∀ {a₂} (p : a₁ =₀ a₂) → to (from p) == p
      to-from = Trunc-elim
        (λ _ → =-preserves-set Trunc-level)
        (λ p → lemma p)
        where
          lemma : ∀ {a₂} (p : a₁ == a₂) → to (from [ p ]) == [ p ]
          lemma idp =
            ap₀ fst ([path] (a₁ , a⇑₁) (a₁ , a⇑₁))
              =⟨ ap (ap₀ fst)
                    $ [path]-has-all-paths
                      ([path] (a₁ , a⇑₁) (a₁ , a⇑₁))
                      (idp₀ :> ((a₁ , a⇑₁) =₀ (a₁ , a⇑₁))) ⟩
            (idp₀ :> (a₁ =₀ a₁))
              ∎

      from-to : ∀ {a₂} (a⇑₂ : Fiber univ-cov a₂) → from (to a⇑₂) == a⇑₂
      from-to {a₂} a⇑₂ = Trunc-elim
        (λ p → =-preserves-set
                {x = from (ap₀ fst p)}
                {y = a⇑₂}
                (Fiber-level univ-cov a₂))
        (λ p → to-transp $ snd= p)
        ([path] (a₁ , a⇑₁) (a₂ , a⇑₂))

    theorem : ∀ a₂ → Fiber univ-cov a₂ ≃ (a₁ =₀ a₂)
    theorem a₂ = to , is-eq _ from to-from from-to


------------------------------------------------------------------------
-- The Agda standard library
--
-- Lists where all elements satisfy a given property
------------------------------------------------------------------------

module Data.List.All where

open import Data.List as List hiding (map; all)
open import Data.List.Any as Any using (here; there)
open Any.Membership-≡ using (_∈_; _⊆_)
open import Function
open import Level
open import Relation.Nullary
import Relation.Nullary.Decidable as Dec
open import Relation.Unary using (Decidable) renaming (_⊆_ to _⋐_)
open import Relation.Binary.PropositionalEquality

-- All P xs means that all elements in xs satisfy P.

infixr 5 _∷_

data All {a p} {A : Set a}
         (P : A → Set p) : List A → Set (p ⊔ a) where
  []  : All P []
  _∷_ : ∀ {x xs} (px : P x) (pxs : All P xs) → All P (x ∷ xs)

head : ∀ {a p} {A : Set a} {P : A → Set p} {x xs} →
       All P (x ∷ xs) → P x
head (px ∷ pxs) = px

tail : ∀ {a p} {A : Set a} {P : A → Set p} {x xs} →
       All P (x ∷ xs) → All P xs
tail (px ∷ pxs) = pxs

lookup : ∀ {a p} {A : Set a} {P : A → Set p} {xs : List A} →
         All P xs → (∀ {x : A} → x ∈ xs → P x)
lookup []         ()
lookup (px ∷ pxs) (here refl)  = px
lookup (px ∷ pxs) (there x∈xs) = lookup pxs x∈xs

tabulate : ∀ {a p} {A : Set a} {P : A → Set p} {xs} →
           (∀ {x} → x ∈ xs → P x) → All P xs
tabulate {xs = []}     hyp = []
tabulate {xs = x ∷ xs} hyp = hyp (here refl) ∷ tabulate (hyp ∘ there)

map : ∀ {a p q} {A : Set a} {P : A → Set p} {Q : A → Set q} →
      P ⋐ Q → All P ⋐ All Q
map g []         = []
map g (px ∷ pxs) = g px ∷ map g pxs

all : ∀ {a p} {A : Set a} {P : A → Set p} →
      Decidable P → Decidable (All P)
all p []       = yes []
all p (x ∷ xs) with p x
all p (x ∷ xs) | yes px = Dec.map′ (_∷_ px) tail (all p xs)
all p (x ∷ xs) | no ¬px = no (¬px ∘ head)


module Issue180 where

module Example₁ where

  data C : Set where
    c : C → C

  data Indexed : (C → C) → Set where
    i : Indexed c

  foo : Indexed c → Set
  foo i = C

module Example₂ where

  data List (A : Set) : Set where
    nil  : List A
    cons : A → List A → List A

  postulate
    A : Set
    x : A

  T : Set
  T = List A → List A

  data P : List T → Set where
    p : (f : T) → P (cons f nil)

  data S : (xs : List T) → P xs → Set where
    s : (f : T) → S (cons f nil) (p f)

  foo : S (cons (cons x) nil) (p (cons x)) → A
  foo (s ._) = x


------------------------------------------------------------------------
-- The Agda standard library
--
-- Decidable equality over lists parameterised by some setoid
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

open import Relation.Binary

module Data.List.Relation.Binary.Equality.DecSetoid
  {a ℓ} (DS : DecSetoid a ℓ) where

import Data.List.Relation.Binary.Equality.Setoid as SetoidEquality
import Data.List.Relation.Binary.Pointwise as PW
open import Level
open import Relation.Binary using (Decidable)
open DecSetoid DS

------------------------------------------------------------------------
-- Make all definitions from setoid equality available

open SetoidEquality setoid public

------------------------------------------------------------------------
-- Additional properties

infix 4 _≋?_

_≋?_ : Decidable _≋_
_≋?_ = PW.decidable _≟_

≋-isDecEquivalence : IsDecEquivalence _≋_
≋-isDecEquivalence = PW.isDecEquivalence isDecEquivalence

≋-decSetoid : DecSetoid a (a ⊔ ℓ)
≋-decSetoid = PW.decSetoid DS


{-

This file contains:

- Definition of set coequalizers as performed in https://1lab.dev/Data.Set.Coequaliser.html

-}
{-# OPTIONS --safe #-}
module Cubical.HITs.SetCoequalizer.Base where

open import Cubical.Core.Primitives

private
  variable
    ℓ ℓ' ℓ'' : Level
    A : Type ℓ
    B : Type ℓ'

-- Set coequalizers as a higher inductive type
data SetCoequalizer {A : Type ℓ} {B : Type ℓ'} (f g : A → B) : Type (ℓ-max ℓ ℓ') where
  inc    : B → SetCoequalizer f g
  coeq   : (a : A) → inc (f a) ≡ inc (g a)
  squash : (x y : SetCoequalizer f g) → (p q : x ≡ y) → p ≡ q


------------------------------------------------------------------------
-- The Agda standard library
--
-- Injections
------------------------------------------------------------------------

module Function.Injection where

open import Function as Fun using () renaming (_∘_ to _⟨∘⟩_)
open import Level
open import Relation.Binary
open import Function.Equality as F
  using (_⟶_; _⟨$⟩_) renaming (_∘_ to _⟪∘⟫_)
import Relation.Binary.PropositionalEquality as P

-- Injective functions.

Injective : ∀ {a₁ a₂ b₁ b₂} {A : Setoid a₁ a₂} {B : Setoid b₁ b₂} →
            A ⟶ B → Set _
Injective {A = A} {B} f = ∀ {x y} → f ⟨$⟩ x ≈₂ f ⟨$⟩ y → x ≈₁ y
  where
  open Setoid A renaming (_≈_ to _≈₁_)
  open Setoid B renaming (_≈_ to _≈₂_)

-- The set of all injections between two setoids.

record Injection {f₁ f₂ t₁ t₂}
                 (From : Setoid f₁ f₂) (To : Setoid t₁ t₂) :
                 Set (f₁ ⊔ f₂ ⊔ t₁ ⊔ t₂) where
  field
    to        : From ⟶ To
    injective : Injective to

-- The set of all injections from one set to another.

infix 3 _↣_

_↣_ : ∀ {f t} → Set f → Set t → Set _
From ↣ To = Injection (P.setoid From) (P.setoid To)

-- Identity and composition.

infixr 9 _∘_

id : ∀ {s₁ s₂} {S : Setoid s₁ s₂} → Injection S S
id = record { to = F.id; injective = Fun.id }

_∘_ : ∀ {f₁ f₂ m₁ m₂ t₁ t₂}
        {F : Setoid f₁ f₂} {M : Setoid m₁ m₂} {T : Setoid t₁ t₂} →
      Injection M T → Injection F M → Injection F T
f ∘ g = record
  { to        =          to        f  ⟪∘⟫ to        g
  ; injective = (λ {_} → injective g) ⟨∘⟩ injective f
  } where open Injection


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Data.List.Base where

open import Agda.Builtin.List        public
open import Cubical.Core.Everything
open import Cubical.Data.Maybe.Base
open import Cubical.Data.Nat.Base

module _ {ℓ} {A : Type ℓ} where

  infixr 5 _++_
  infixl 5 _∷ʳ_

  [_] : A → List A
  [ a ] = a ∷ []

  _++_ : List A → List A → List A
  [] ++ ys = ys
  (x ∷ xs) ++ ys = x ∷ xs ++ ys

  rev : List A → List A
  rev [] = []
  rev (x ∷ xs) = rev xs ++ [ x ]

  _∷ʳ_ : List A → A → List A
  xs ∷ʳ x = xs ++ x ∷ []

  length : List A → ℕ
  length [] = 0
  length (x ∷ l) = 1 + length l

  map : ∀ {ℓ'} {B : Type ℓ'} → (A → B) → List A → List B
  map f [] = []
  map f (x ∷ xs) = f x ∷ map f xs

  map2 : ∀ {ℓ' ℓ''} {B : Type ℓ'} {C : Type ℓ''}
    → (A → B → C) → List A → List B → List C
  map2 f [] _ = []
  map2 f _ [] = []
  map2 f (x ∷ xs) (y ∷ ys) = f x y ∷ map2 f xs ys

  foldr : ∀ {ℓ'} {B : Type ℓ'} → (A → B → B) → B → List A → B
  foldr f b [] = b
  foldr f b (x ∷ xs) = f x (foldr f b xs)

  foldl : ∀ {ℓ'} {B : Type ℓ'} → (B → A → B) → B → List A → B
  foldl f b [] = b
  foldl f b (x ∷ xs) = foldl f (f b x) xs


------------------------------------------------------------------------
-- Binary trees
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

open import Equality

module Tree {c⁺} (eq : ∀ {a p} → Equality-with-J a p c⁺) where

open Derived-definitions-and-properties eq

open import Prelude hiding (id)

open import Bag-equivalence eq
open import Bijection eq using (_↔_)
open import Function-universe eq
open import List eq

------------------------------------------------------------------------
-- Binary trees

data Tree (A : Type) : Type where
  leaf : Tree A
  node : (l : Tree A) (x : A) (r : Tree A) → Tree A

-- Any.

AnyT : ∀ {A} → (A → Type) → (Tree A → Type)
AnyT P leaf         = ⊥
AnyT P (node l x r) = AnyT P l ⊎ P x ⊎ AnyT P r

-- Membership.

infix 4 _∈T_

_∈T_ : ∀ {A} → A → Tree A → Type
x ∈T t = AnyT (_≡_ x) t

-- Bag equivalence.

_≈-bagT_ : ∀ {A} → Tree A → Tree A → Type
t₁ ≈-bagT t₂ = ∀ x → x ∈T t₁ ↔ x ∈T t₂

------------------------------------------------------------------------
-- Singleton

-- Singleton trees.

singleton : {A : Type} → A → Tree A
singleton x = node leaf x leaf

-- Any lemma for singleton.

Any-singleton : ∀ {A : Type} (P : A → Type) {x} →
                AnyT P (singleton x) ↔ P x
Any-singleton P {x} =
  AnyT P (singleton x)  ↔⟨⟩
  ⊥ ⊎ P x ⊎ ⊥           ↔⟨ ⊎-left-identity ⟩
  P x ⊎ ⊥               ↔⟨ ⊎-right-identity ⟩
  P x                   □

------------------------------------------------------------------------
-- Flatten

-- Inorder flattening of a tree.

flatten : {A : Type} → Tree A → List A
flatten leaf         = []
flatten (node l x r) = flatten l ++ x ∷ flatten r

-- Flatten does not add or remove any elements.

flatten-lemma : {A : Type} (t : Tree A) → ∀ z → z ∈ flatten t ↔ z ∈T t
flatten-lemma leaf         = λ z → ⊥ □
flatten-lemma (node l x r) = λ z →
  z ∈ flatten l ++ x ∷ flatten r         ↔⟨ Any-++ (_≡_ z) _ _ ⟩
  z ∈ flatten l ⊎ z ≡ x ⊎ z ∈ flatten r  ↔⟨ flatten-lemma l z ⊎-cong (z ≡ x □) ⊎-cong flatten-lemma r z ⟩
  z ∈T l        ⊎ z ≡ x ⊎ z ∈T r         □

------------------------------------------------------------------------
-- Bags can (perhaps) be defined as binary trees quotiented by bag
-- equivalence

-- Agda doesn't support quotients, so the following type is used to
-- state that two quotients are isomorphic.
--
-- Note that this definition may not actually make sense if the
-- relations _≈A_ and _≈B_ are not /proof-irrelevant/ equivalence
-- relations.

record _/_↔_/_ (A : Type) (_≈A_ : A → A → Type)
               (B : Type) (_≈B_ : B → B → Type) : Type where
  field
    to        : A → B
    to-resp   : ∀ x y → x ≈A y → to x ≈B to y
    from      : B → A
    from-resp : ∀ x y → x ≈B y → from x ≈A from y
    to∘from   : ∀ x → to (from x) ≈B x
    from∘to   : ∀ x → from (to x) ≈A x

-- Lists quotiented by bag equivalence are isomorphic to binary trees
-- quotiented by bag equivalence (assuming that one can actually
-- quotient by bag equivalence, and that the definition of _/_↔_/_
-- makes sense in this case).

list-bags↔tree-bags : {A : Type} → List A / _≈-bag_ ↔ Tree A / _≈-bagT_
list-bags↔tree-bags {A} = record
  { to        = to-tree
  ; to-resp   = λ xs ys xs≈ys z →
                  z ∈T to-tree xs  ↔⟨ to-tree-lemma xs z ⟩
                  z ∈ xs           ↔⟨ xs≈ys z ⟩
                  z ∈ ys           ↔⟨ inverse $ to-tree-lemma ys z ⟩
                  z ∈T to-tree ys  □
  ; from      = flatten
  ; from-resp = λ t₁ t₂ t₁≈t₂ z →
                  z ∈ flatten t₁  ↔⟨ flatten-lemma t₁ z ⟩
                  z ∈T t₁         ↔⟨ t₁≈t₂ z ⟩
                  z ∈T t₂         ↔⟨ inverse $ flatten-lemma t₂ z ⟩
                  z ∈ flatten t₂  □
  ; to∘from   = to∘from
  ; from∘to   = from∘to
  }
  where
  to-tree : List A → Tree A
  to-tree = foldr (node leaf) leaf

  to-tree-lemma : ∀ xs z → z ∈T to-tree xs ↔ z ∈ xs
  to-tree-lemma []       = λ z → ⊥ □
  to-tree-lemma (x ∷ xs) = λ z →
    ⊥ ⊎ z ≡ x   ⊎ z ∈T to-tree xs  ↔⟨ id ⊎-cong id ⊎-cong to-tree-lemma xs z ⟩
    ⊥ ⊎ z ≡ x   ⊎ z ∈ xs           ↔⟨ ⊎-assoc ⟩
    (⊥ ⊎ z ≡ x) ⊎ z ∈ xs           ↔⟨ ⊎-left-identity ⊎-cong id ⟩
    z ≡ x       ⊎ z ∈ xs           □

  to-tree-++ : ∀ {P : A → Type} xs {ys} →
               AnyT P (to-tree (xs ++ ys)) ↔
               AnyT P (to-tree xs) ⊎ AnyT P (to-tree ys)
  to-tree-++ {P} [] {ys} =
    AnyT P (to-tree ys)      ↔⟨ inverse ⊎-left-identity ⟩
    ⊥ ⊎ AnyT P (to-tree ys)  □
  to-tree-++ {P} (x ∷ xs) {ys} =
    ⊥ ⊎ P x ⊎ AnyT P (to-tree (xs ++ ys))                  ↔⟨ id ⊎-cong id ⊎-cong to-tree-++ xs ⟩
    ⊥ ⊎ P x ⊎ AnyT P (to-tree xs) ⊎ AnyT P (to-tree ys)    ↔⟨ lemma _ _ _ _ ⟩
    (⊥ ⊎ P x ⊎ AnyT P (to-tree xs)) ⊎ AnyT P (to-tree ys)  □
    where
    lemma : (A B C D : Type) → A ⊎ B ⊎ C ⊎ D ↔ (A ⊎ B ⊎ C) ⊎ D
    lemma A B C D =
      A ⊎ B ⊎ C ⊎ D      ↔⟨ ⊎-assoc ⟩
      (A ⊎ B) ⊎ C ⊎ D    ↔⟨ ⊎-assoc ⟩
      ((A ⊎ B) ⊎ C) ⊎ D  ↔⟨ inverse ⊎-assoc ⊎-cong id ⟩
      (A ⊎ B ⊎ C) ⊎ D    □

  to∘from : ∀ t → to-tree (flatten t) ≈-bagT t
  to∘from leaf         = λ z → ⊥ □
  to∘from (node l x r) = λ z →
    z ∈T to-tree (flatten l ++ x ∷ flatten r)                        ↔⟨ to-tree-++ (flatten l) ⟩
    z ∈T to-tree (flatten l) ⊎ ⊥ ⊎ z ≡ x ⊎ z ∈T to-tree (flatten r)  ↔⟨ to∘from l z ⊎-cong id ⊎-cong id ⊎-cong to∘from r z ⟩
    z ∈T l                   ⊎ ⊥ ⊎ z ≡ x ⊎ z ∈T r                    ↔⟨ id ⊎-cong ⊎-left-identity ⟩
    z ∈T l                   ⊎     z ≡ x ⊎ z ∈T r                    □

  from∘to : ∀ xs → flatten (to-tree xs) ≈-bag xs
  from∘to []       = λ z → ⊥ □
  from∘to (x ∷ xs) = λ z →
    z ≡ x ⊎ z ∈ flatten (to-tree xs)  ↔⟨ id ⊎-cong from∘to xs z ⟩
    z ≡ x ⊎ z ∈ xs                    □


import      Lvl
open import Structure.Operator.Vector
open import Structure.Setoid
open import Type

module Structure.Operator.Vector.FiniteDimensional
  {ℓᵥ ℓₛ ℓᵥₑ ℓₛₑ}
  {V : Type{ℓᵥ}} ⦃ equiv-V : Equiv{ℓᵥₑ}(V) ⦄
  {S : Type{ℓₛ}} ⦃ equiv-S : Equiv{ℓₛₑ}(S) ⦄
  {_+ᵥ_ : V → V → V}
  {_⋅ₛᵥ_ : S → V → V}
  {_+ₛ_ _⋅ₛ_ : S → S → S}
  ⦃ vectorSpace : VectorSpace(_+ᵥ_)(_⋅ₛᵥ_)(_+ₛ_)(_⋅ₛ_) ⦄
  where

open VectorSpace(vectorSpace)

open import Data.Tuple using (_⨯_ ; _,_)
open import Functional using (id ; _∘_ ; _∘₂_ ; _$_ ; swap ; _on₂_)
open import Function.Equals
open import Logic
open import Logic.Predicate
open import Numeral.CoordinateVector as Vec using () renaming (Vector to Vec)
open import Numeral.Finite
open import Numeral.Natural
open import Sets.ExtensionalPredicateSet as PredSet using (PredSet ; _∈_ ; [∋]-binaryRelator)
open import Structure.Function.Domain
open import Structure.Operator.Vector.LinearCombination ⦃ vectorSpace = vectorSpace ⦄
open import Syntax.Function

private variable n : ℕ

-- A sequence of vectors is linearly independent when there is no vector that can be represented as a linear combination by the others.
-- Note: Equivalent to: `∀{sf} → (linearCombination(vf)(sf) ≡ 𝟎ᵥ) → (sf ⊜ Vec.fill(𝟎ₛ))`.
LinearlyIndependent : Vec(n)(V) → Stmt
LinearlyIndependent = Injective ∘ linearCombination

-- A sequence of vectors is spanning the vector space when every vector in the vector space can be represented as a linear combination of the set of vectors.
Spanning : Vec(n)(V) → Stmt
Spanning = Surjective ∘ linearCombination

-- A sequence of vectors is a basis when every vector in the vector space can be represented as a unique linear combination of the set of vectors.
-- A sequence of vectors is a basis when they span the vector space and is linearly independent.
Basis : Vec(n)(V) → Stmt
Basis = Bijective ∘ linearCombination

-- A finite dimensional vector space is when there are a finite number of vectors that spans the whole space.
FiniteDimensional : Stmt
FiniteDimensional = ∃(n ↦ ∃(vf ↦ Spanning{n}(vf)))


{-# OPTIONS --without-K --safe #-}

-- Defines Restriction Category
--   https://ncatlab.org/nlab/show/restriction+category
-- but see also
--   https://github.com/jmchapman/restriction-categories

-- Notation choice: one of the interpretations is that the
-- restriction structure captures the "domain of definedness"
-- of a morphism, as a (partial) identity. As this is positive
-- information, we will use f ↓ (as a postfix operation) to
-- denote this. Note that computability theory uses the same
-- notation to mean definedness.

-- Note, as we're working in Setoid-Enriched Categories, we need
-- to add an explicit axiom, that ↓ preserves ≈
module Categories.Category.Restriction where

open import Level using (Level; _⊔_)

open import Categories.Category.Core using (Category)

private
  variable
    o ℓ e : Level

record Restriction (C : Category o ℓ e) : Set (o ⊔ ℓ ⊔ e) where
  open Category C using (Obj; _⇒_; _∘_; _≈_; id)

  field
    _↓ :  {A B : Obj} → A ⇒ B → A ⇒ A
    -- partial identity on the right
    pidʳ : {A B : Obj} {f : A ⇒ B} → f ∘ f ↓ ≈ f
    -- the domain-of-definition arrows commute
    ↓-comm : {A B C : Obj} {f : A ⇒ B} {g : A ⇒ C} → f ↓ ∘ g ↓ ≈ g ↓ ∘ f ↓
    -- domain-of-definition denests (on the right)
    ↓-denestʳ : {A B C : Obj} {f : A ⇒ B} {g : A ⇒ C} → (g ∘ f ↓) ↓ ≈ g ↓ ∘ f ↓
    -- domain-of-definition has a skew-commutative law
    ↓-skew-comm : {A B C : Obj} {g : A ⇒ B} {f : C ⇒ A} → g ↓ ∘ f ≈ f ∘ (g ∘ f) ↓
    -- and the new axiom, ↓ is a congruence
    ↓-cong : {A B : Obj} {f g : A ⇒ B} → f ≈ g → f ↓ ≈ g ↓

  -- it is convenient to define the total predicate in this context
  total : {A B : Obj} (f : A ⇒ B) → Set e
  total f = f ↓ ≈ id


{-

This file proves the higher groupoid structure of types
for homogeneous and heterogeneous paths

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Foundations.GroupoidLaws where

open import Cubical.Foundations.Prelude

private
  variable
    ℓ : Level
    A : Type ℓ
    x y z w v : A

_⁻¹ : (x ≡ y) → (y ≡ x)
x≡y ⁻¹ = sym x≡y

infix 40 _⁻¹

-- homogeneous groupoid laws

symInvo : (p : x ≡ y) → p ≡ p ⁻¹ ⁻¹
symInvo p = refl

rUnit : (p : x ≡ y) → p ≡ p ∙ refl
rUnit p j i = compPath-filler p refl j i

-- The filler of left unit: lUnit-filler p =
-- PathP (λ i → PathP (λ j → PathP (λ k → A) x (p (~ j ∨ i)))
-- (refl i) (λ j → compPath-filler refl p i j)) (λ k i → (p (~ k ∧ i ))) (lUnit p)

lUnit-filler : {x y : A} (p : x ≡ y) → I → I → I → A
lUnit-filler {x = x} p j k i =
  hfill (λ j → λ { (i = i0) → x
                  ; (i = i1) → p (~ k ∨ j )
                  ; (k = i0) → p i
               -- ; (k = i1) → compPath-filler refl p j i
                  }) (inS (p (~ k ∧ i ))) j

lUnit : (p : x ≡ y) → p ≡ refl ∙ p
lUnit p j i = lUnit-filler p i1 j i

symRefl : refl {x = x} ≡ refl ⁻¹
symRefl i = refl

compPathRefl : refl {x = x} ≡ refl ∙ refl
compPathRefl = rUnit refl

-- The filler of right cancellation: rCancel-filler p =
-- PathP (λ i → PathP (λ j → PathP (λ k → A) x (p (~ j ∧ ~ i)))
-- (λ j → compPath-filler p (p ⁻¹) i j) (refl i)) (λ j i → (p (i ∧ ~ j))) (rCancel p)

rCancel-filler : ∀ {x y : A} (p : x ≡ y) → (k j i : I) → A
rCancel-filler {x = x} p k j i =
  hfill (λ k → λ { (i = i0) → x
                  ; (i = i1) → p (~ k ∧ ~ j)
               -- ; (j = i0) → compPath-filler p (p ⁻¹) k i
                  ; (j = i1) → x
                  }) (inS (p (i ∧ ~ j))) k

rCancel : (p : x ≡ y) → p ∙ p ⁻¹ ≡ refl
rCancel {x = x} p j i = rCancel-filler p i1 j i

rCancel-filler' : ∀ {ℓ} {A : Type ℓ} {x y : A} (p : x ≡ y) → (i j k : I) → A
rCancel-filler' {x = x} {y} p i j k =
  hfill
    (λ i → λ
      { (j = i1) → p (~ i ∧ k)
      ; (k = i0) → x
      ; (k = i1) → p (~ i)
      })
    (inS (p k))
    (~ i)

rCancel' : ∀ {ℓ} {A : Type ℓ} {x y : A} (p : x ≡ y) → p ∙ p ⁻¹ ≡ refl
rCancel' p j k = rCancel-filler' p i0 j k

lCancel : (p : x ≡ y) → p ⁻¹ ∙ p ≡ refl
lCancel p = rCancel (p ⁻¹)

assoc : (p : x ≡ y) (q : y ≡ z) (r : z ≡ w) →
  p ∙ q ∙ r ≡ (p ∙ q) ∙ r
assoc p q r k = (compPath-filler p q k) ∙ compPath-filler' q r (~ k)

-- heterogeneous groupoid laws

symInvoP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
     PathP (λ j → PathP (λ i → symInvo (λ i → A i) j i) x y) p (symP (symP p))
symInvoP p = refl

rUnitP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
  PathP (λ j → PathP (λ i → rUnit (λ i → A i) j i) x y) p (compPathP p refl)
rUnitP p j i = compPathP-filler p refl j i

lUnitP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
  PathP (λ j → PathP (λ i → lUnit (λ i → A i) j i) x y) p (compPathP refl p)
lUnitP {A = A} {x = x} p k i =
  comp (λ j → lUnit-filler (λ i → A i) j k i)
       (λ j → λ { (i = i0) → x
                ; (i = i1) → p (~ k ∨ j )
                ; (k = i0) → p i
                }) (p (~ k ∧ i ))

rCancelP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
   PathP (λ j → PathP (λ i → rCancel (λ i → A i) j i) x x) (compPathP p (symP p)) refl
rCancelP {A = A} {x = x} p j i =
  comp (λ k → rCancel-filler (λ i → A i) k j i)
       (λ k → λ { (i = i0) → x
                ; (i = i1) → p (~ k ∧ ~ j)
                ; (j = i1) → x
                }) (p (i ∧ ~ j))

lCancelP : {A : I → Type ℓ} → {x : A i0} → {y : A i1} → (p : PathP A x y) →
   PathP (λ j → PathP (λ i → lCancel (λ i → A i) j i) y y) (compPathP (symP p) p) refl
lCancelP p = rCancelP (symP p)

assocP : {A : I → Type ℓ} {x : A i0} {y : A i1} {B_i1 : Type ℓ} {B : (A i1) ≡ B_i1} {z : B i1}
  {C_i1 : Type ℓ} {C : (B i1) ≡ C_i1} {w : C i1} (p : PathP A x y) (q : PathP (λ i → B i) y z) (r : PathP (λ i → C i) z w) →
  PathP (λ j → PathP (λ i → assoc (λ i → A i) B C j i) x w) (compPathP p (compPathP q r)) (compPathP (compPathP p q) r)
assocP {A = A} {B = B} {C = C} p q r k i =
    comp (\ j' → hfill  (λ j → λ {
                     (i = i0) → A i0
                   ; (i = i1) → compPath-filler' (λ i₁ → B i₁) (λ i₁ → C i₁) (~ k) j })
                     (inS (compPath-filler (λ i₁ → A i₁) (λ i₁ → B i₁) k i)) j')
     (λ j → λ
      { (i = i0) → p i0
      ; (i = i1) →
        comp (\ j' → hfill ((λ l → λ
            { (j = i0) → B k
            ; (j = i1) → C l
            ; (k = i1) → C (j ∧ l)
            })) (inS (B ( j ∨ k)) ) j')
          (λ l → λ
            { (j = i0) → q k
            ; (j = i1) → r l
            ; (k = i1) → r (j ∧ l)
            })
          (q (j ∨ k))
      })
    (compPathP-filler p q k i)

-- Loic's code below

-- some exchange law for doubleCompPath and refl

invSides-filler : {x y z : A} (p : x ≡ y) (q : x ≡ z) → Square p (sym q) q (sym p)
invSides-filler {x = x} p q i j =
  hcomp (λ k → λ { (i = i0) → p (k ∧ j)
                 ; (i = i1) → q (~ j ∧ k)
                 ; (j = i0) → q (i ∧ k)
                 ; (j = i1) → p (~ i ∧ k)})
        x

leftright : {ℓ : Level} {A : Type ℓ} {x y z : A} (p : x ≡ y) (q : y ≡ z) →
            (refl ∙∙ p ∙∙ q) ≡ (p ∙∙ q ∙∙ refl)
leftright p q i j =
  hcomp (λ t → λ { (j = i0) → p (i ∧ (~ t))
                 ; (j = i1) → q (t ∨ i) })
        (invSides-filler q (sym p) (~ i) j)

-- equating doubleCompPath and a succession of two compPath

split-leftright : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y) (r : y ≡ z) →
                  (p ∙∙ q ∙∙ r) ≡ (refl ∙∙ (p ∙∙ q ∙∙ refl) ∙∙ r)
split-leftright p q r j i =
  hcomp (λ t → λ { (i = i0) → p (~ j ∧ ~ t)
                 ; (i = i1) → r t })
        (doubleCompPath-filler p q refl j i)

split-leftright' : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y) (r : y ≡ z) →
                  (p ∙∙ q ∙∙ r) ≡ (p ∙∙ (refl ∙∙ q ∙∙ r) ∙∙ refl)
split-leftright' p q r j i =
  hcomp (λ t → λ { (i = i0) → p (~ t)
                 ; (i = i1) → r (j ∨ t) })
        (doubleCompPath-filler refl q r j i)

doubleCompPath-elim : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y)
                      (r : y ≡ z) → (p ∙∙ q ∙∙ r) ≡ (p ∙ q) ∙ r
doubleCompPath-elim p q r = (split-leftright p q r) ∙ (λ i → (leftright p q (~ i)) ∙ r)

doubleCompPath-elim' : {ℓ : Level} {A : Type ℓ} {w x y z : A} (p : w ≡ x) (q : x ≡ y)
                       (r : y ≡ z) → (p ∙∙ q ∙∙ r) ≡ p ∙ (q ∙ r)
doubleCompPath-elim' p q r = (split-leftright' p q r) ∙ (sym (leftright p (q ∙ r)))

cong-∙ : ∀ {B : Type ℓ} (f : A → B) (p : x ≡ y) (q : y ≡ z)
         → cong f (p ∙ q) ≡ (cong f p) ∙ (cong f q)
cong-∙ f p q j i = hcomp (λ k → λ { (j = i0) → f (compPath-filler p q k i)
                                  ; (i = i0) → f (p i0)
                                  ; (i = i1) → f (q k) })
                         (f (p i))

cong-∙∙ : ∀ {B : Type ℓ} (f : A → B) (p : w ≡ x) (q : x ≡ y) (r : y ≡ z)
          → cong f (p ∙∙ q ∙∙ r) ≡ (cong f p) ∙∙ (cong f q) ∙∙ (cong f r)
cong-∙∙ f p q r j i = hcomp (λ k → λ { (j = i0) → f (doubleCompPath-filler p q r k i)
                                     ; (i = i0) → f (p (~ k))
                                     ; (i = i1) → f (r k) })
                            (f (q i))

hcomp-unique : ∀ {ℓ} {A : Type ℓ} {φ} → (u : I → Partial φ A) → (u0 : A [ φ ↦ u i0 ]) →
               (h2 : ∀ i → A [ (φ ∨ ~ i) ↦ (\ { (φ = i1) → u i 1=1; (i = i0) → outS u0}) ])
               → (hcomp u (outS u0) ≡ outS (h2 i1)) [ φ ↦ (\ { (φ = i1) → (\ i → u i1 1=1)}) ]
hcomp-unique {φ = φ} u u0 h2 = inS (\ i → hcomp (\ k → \ { (φ = i1) → u k 1=1
                                                            ; (i = i1) → outS (h2 k) })
                                                   (outS u0))

lid-unique : ∀ {ℓ} {A : Type ℓ} {φ} → (u : I → Partial φ A) → (u0 : A [ φ ↦ u i0 ]) →
               (h1 h2 : ∀ i → A [ (φ ∨ ~ i) ↦ (\ { (φ = i1) → u i 1=1; (i = i0) → outS u0}) ])
               → (outS (h1 i1) ≡ outS (h2 i1)) [ φ ↦ (\ { (φ = i1) → (\ i → u i1 1=1)}) ]
lid-unique {φ = φ} u u0 h1 h2 = inS (\ i → hcomp (\ k → \ { (φ = i1) → u k 1=1
                                                            ; (i = i0) → outS (h1 k)
                                                            ; (i = i1) → outS (h2 k) })
                                                   (outS u0))

transp-hcomp : ∀ {ℓ} (φ : I) {A' : Type ℓ}
                     (A : (i : I) → Type ℓ [ φ ↦ (λ _ → A') ]) (let B = \ (i : I) → outS (A i))
                 → ∀ {ψ} (u : I → Partial ψ (B i0)) → (u0 : B i0 [ ψ ↦ u i0 ]) →
                 (transp (\ i → B i) φ (hcomp u (outS u0)) ≡ hcomp (\ i o → transp (\ i → B i) φ (u i o)) (transp (\ i → B i) φ (outS u0)))
                   [ ψ ↦ (\ { (ψ = i1) → (\ i → transp (\ i → B i) φ (u i1 1=1))}) ]
transp-hcomp φ A u u0 = inS (sym (outS (hcomp-unique
               ((\ i o → transp (\ i → B i) φ (u i o))) (inS (transp (\ i → B i) φ (outS u0)))
                 \ i → inS (transp (\ i → B i) φ (hfill u u0 i)))))
  where
    B = \ (i : I) → outS (A i)

hcomp-cong : ∀ {ℓ} {A : Type ℓ} {φ} → (u : I → Partial φ A) → (u0 : A [ φ ↦ u i0 ]) →
                                     (u' : I → Partial φ A) → (u0' : A [ φ ↦ u' i0 ]) →
             (ueq : ∀ i → PartialP φ (\ o → u i o ≡ u' i o)) → (outS u0 ≡ outS u0') [ φ ↦ (\ { (φ = i1) → ueq i0 1=1}) ]
             → (hcomp u (outS u0) ≡ hcomp u' (outS u0')) [ φ ↦ (\ { (φ = i1) → ueq i1 1=1 }) ]
hcomp-cong u u0 u' u0' ueq 0eq = inS (\ j → hcomp (\ i o → ueq i o j) (outS 0eq j))

congFunct-filler : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} {x y z : A} (f : A → B) (p : x ≡ y) (q : y ≡ z)
                → I → I → I → B
congFunct-filler {x = x} f p q i j z =
  hfill (λ k → λ { (i = i0) → f x
                  ; (i = i1) → f (q k)
                  ; (j = i0) → f (compPath-filler p q k i)})
        (inS (f (p i)))
        z

congFunct : ∀ {ℓ} {B : Type ℓ} (f : A → B) (p : x ≡ y) (q : y ≡ z) → cong f (p ∙ q) ≡ cong f p ∙ cong f q
congFunct f p q j i = congFunct-filler f p q i j i1

-- congFunct for dependent types
congFunct-dep : ∀ {ℓ ℓ'} {A : Type ℓ} {B : A → Type ℓ'} {x y z : A} (f : (a : A) → B a) (p : x ≡ y) (q : y ≡ z)
         → PathP (λ i → PathP (λ j → B (compPath-filler p q i j)) (f x) (f (q i))) (cong f p) (cong f (p ∙ q))
congFunct-dep {B = B} {x = x} f p q i j = f (compPath-filler p q i j)

cong₂Funct : ∀ {ℓ ℓ'} {A : Type ℓ} {x y : A} {B : Type ℓ'} (f : A → A → B) →
        (p : x ≡ y) →
        {u v : A} (q : u ≡ v) →
        cong₂ f p q ≡ cong (λ x → f x u) p ∙ cong (f y) q
cong₂Funct {x = x} {y = y} f p {u = u} {v = v} q j i =
  hcomp (λ k → λ { (i = i0) → f x u
                  ; (i = i1) → f y (q k)
                  ; (j = i0) → f (p i) (q (i ∧ k))})
       (f (p i) u)

symDistr-filler : ∀ {ℓ} {A : Type ℓ} {x y z : A} (p : x ≡ y) (q : y ≡ z) → I → I → I → A
symDistr-filler {A = A} {z = z} p q i j k =
  hfill (λ k → λ { (i = i0) → q (k ∨ j)
                  ; (i = i1) → p (~ k ∧ j) })
        (inS (invSides-filler q (sym p) i j))
        k

symDistr : ∀ {ℓ} {A : Type ℓ} {x y z : A} (p : x ≡ y) (q : y ≡ z) → sym (p ∙ q) ≡ sym q ∙ sym p
symDistr p q i j = symDistr-filler p q j i i1

-- we can not write hcomp-isEquiv : {ϕ : I} → (p : I → Partial ϕ A) → isEquiv (λ (a : A [ ϕ ↦ p i0 ]) → hcomp p a)
-- due to size issues. But what we can write (compare to hfill) is:
hcomp-equivFillerSub : {ϕ : I} → (p : I → Partial ϕ A) → (a : A [ ϕ ↦ p i0 ])
                     → (i : I)
                     → A [ ϕ ∨ i ∨ ~ i ↦ (λ { (i = i0) → outS a
                                            ; (i = i1) → hcomp (λ i → p (~ i)) (hcomp p (outS a))
                                            ; (ϕ = i1) → p i0 1=1 }) ]
hcomp-equivFillerSub {ϕ = ϕ} p a i =
  inS (hcomp (λ k → λ { (i = i1) → hfill (λ j → p (~ j)) (inS (hcomp p (outS a))) k
                      ; (i = i0) → outS a
                      ; (ϕ = i1) → p (~ k ∧ i) 1=1 })
             (hfill p a i))

hcomp-equivFiller : {ϕ : I} → (p : I → Partial ϕ A) → (a : A [ ϕ ↦ p i0 ])
                  → (i : I) → A
hcomp-equivFiller p a i = outS (hcomp-equivFillerSub p a i)

pentagonIdentity : (p : x ≡ y) → (q : y ≡ z) → (r : z ≡ w) → (s : w ≡ v)
                      →
            (assoc p q (r ∙ s) ∙ assoc (p ∙ q) r s)
                              ≡
   cong (p ∙_) (assoc q r s) ∙∙ assoc p (q ∙ r) s ∙∙ cong (_∙ s) (assoc p q r)

pentagonIdentity {x = x} {y} p q r s =
        (λ i →
              (λ j → cong (p ∙_) (assoc q r s) (i ∧ j))
           ∙∙ (λ j → lemma₀₀ i j ∙ lemma₀₁ i j)
           ∙∙ (λ j → lemma₁₀ i j ∙ lemma₁₁ i j)
        )
   where

    lemma₀₀ : ( i j : I) → _ ≡ _
    lemma₀₀ i j i₁ =
         hcomp
        (λ k → λ { (j = i0) → p i₁
                 ; (i₁ = i0) → x
                 ; (i₁ = i1) → hcomp
                                 (λ k₁ → λ { (i = i0) → (q (j ∧ k))
                                           ; (k = i0) → y
                                           ; (j = i0) → y
                                           ; (j = i1)(k = i1) → r (k₁ ∧ i)})
                                 (q (j ∧ k))
        }) (p i₁)

    lemma₀₁ : ( i j : I) → hcomp
                       (λ k → λ {(i = i0) → q j
                               ; (j = i0) → y
                               ; (j = i1) → r (k ∧ i)
                          })
                       (q j) ≡ _
    lemma₀₁ i j i₁ = (hcomp
                        (λ k → λ { (j = i1) → hcomp
                                                (λ k₁ → λ { (i₁ = i0) → r i
                                                          ; (k = i0) → r i
                                                          ; (i = i1) → s (k₁ ∧  k ∧  i₁)
                                                          ; (i₁ = i1)(k = i1) → s k₁ })
                                                (r ((i₁ ∧ k) ∨ i))
                                  ; (i₁ = i0) → compPath-filler q r i j
                                  ; (i₁ = i1) → hcomp
                                                  (λ k₁ → λ { (k = i0) → r i
                                                            ; (k = i1) → s k₁
                                                            ; (i = i1) → s (k ∧ k₁)})
                                                  (r (i ∨ k))})
                         (hfill
                             (λ k → λ { (j = i1) → r k
                                      ; (i₁ = i1) → r k
                                      ; (i₁ = i0)(j = i0) → y })
                             (inS (q (i₁ ∨ j))) i))

    lemma₁₁ : ( i j : I) → (r (i ∨ j)) ≡ _
    lemma₁₁ i j i₁ =
           hcomp
             (λ k → λ { (i = i1) → s (i₁ ∧ k)
                      ; (j = i1) → s (i₁ ∧ k)
                      ; (i₁ = i0) → r (i ∨ j)
                      ; (i₁ = i1) → s k
              }) (r (i ∨ j ∨ i₁))

    lemma₁₀-back :  I → I → I → _
    lemma₁₀-back i j i₁ =
        hcomp
         (λ k → λ {
           (i₁ = i0) → x
         ; (i₁ = i1) → hcomp
                         (λ k₁ → λ { (k = i0) → q (j ∨ ~ i)
                                   ; (k = i1) → r (k₁ ∧ j)
                                   ; (j = i0) → q (k ∨ ~ i)
                                   ; (j = i1) → r (k₁ ∧ k)
                                   ; (i = i0) → r (k ∧ j ∧ k₁)
                         })
                         (q (k ∨ j ∨ ~ i))
         ; (i = i0)(j = i0) → (p ∙ q) i₁
         })
        (hcomp
           (λ k → λ { (i₁ = i0) → x
                    ; (i₁ = i1) → q ((j ∨ ~ i ) ∧ k)
                    ; (j = i0)(i = i1) → p i₁
            })
            (p i₁))

    lemma₁₀-front : I → I → I → _
    lemma₁₀-front i j i₁ =
       (((λ _ → x) ∙∙ compPath-filler p q j ∙∙
         (λ i₁ →
             hcomp
                (λ k → λ { (i₁ = i0) → q j
                         ; (i₁ = i1) → r (k ∧ (j ∨ i))
                         ; (j = i0)(i = i0) → q i₁
                         ; (j = i1) → r (i₁ ∧ k)
               })
            (q (j ∨ i₁))
         )) i₁)

    compPath-filler-in-filler :
                (p : _ ≡ y) → (q : _ ≡ _ )
              → _≡_ {A = Square (p ∙ q) (p ∙ q) (λ _ → x) (λ _ → z)}
               (λ i j → hcomp
                          (λ i₂ →
                           λ { (j = i0) → x
                             ; (j = i1) → q (i₂ ∨ ~ i)
                             ; (i = i0) → (p ∙ q) j
                            })
                          (compPath-filler p q (~ i) j))
               (λ _ → p ∙ q)
    compPath-filler-in-filler p q z i j =
       hcomp
         (λ k → λ {
            (j = i0) → p i0
          ; (j = i1) → q (k ∨ ~ i ∧ ~ z)
          ; (i = i0) → hcomp
                       (λ i₂ → λ {
                         (j = i0) → p i0
                        ;(j = i1) → q ((k ∨  ~ z) ∧ i₂)
                        ;(z = i1) (k = i0) → p j
                       })
                      (p j)
          ; (i = i1) →  compPath-filler p (λ i₁ → q (k ∧ i₁)) k j
          ; (z = i0) → hfill
                         ((λ i₂ → λ { (j = i0) → p i0
                             ; (j = i1) → q (i₂ ∨ ~ i)
                             ; (i = i0) → (p ∙ q) j
                            }))
                         (inS ((compPath-filler p q (~ i) j))) k
          ; (z = i1) → compPath-filler p q k j
         })
         (compPath-filler p q (~ i ∧ ~ z) j)

    cube-comp₋₀₋ :
        (c : I → I → I → A)
      → {a' : Square _ _ _ _}
      → (λ i i₁ → c i i0 i₁) ≡ a'
      → (I → I → I → A)
    cube-comp₋₀₋ c p i j k =
       hcomp
         (λ l → λ {
            (i = i0) → c i0 j k
           ;(i = i1) → c i1 j k
           ;(j = i0) → p l i k
           ;(j = i1) → c i i1 k
           ;(k = i0) → c i j i0
           ;(k = i1) → c i j i1
          })
        (c i j k)

    cube-comp₀₋₋ :
        (c : I → I → I → A)
      → {a' : Square _ _ _ _}
      → (λ i i₁ → c i0 i i₁) ≡ a'
      → (I → I → I → A)
    cube-comp₀₋₋ c p i j k =
       hcomp
         (λ l → λ {
            (i = i0) → p l j k
           ;(i = i1) → c i1 j k
           ;(j = i0) → c i i0 k
           ;(j = i1) → c i i1 k
           ;(k = i0) → c i j i0
           ;(k = i1) → c i j i1
          })
        (c i j k)

    lemma₁₀-back' : _
    lemma₁₀-back' k j i₁ =
       (cube-comp₋₀₋ (lemma₁₀-back)
         (compPath-filler-in-filler p q)) k j i₁

    lemma₁₀ : ( i j : I) → _ ≡ _
    lemma₁₀ i j i₁ =
        (cube-comp₀₋₋ lemma₁₀-front (sym lemma₁₀-back')) i j i₁


{-# OPTIONS --without-K #-}
module HoTT.Identity.Coproduct where

open import HoTT.Base
open import HoTT.Equivalence

open variables
private variable x y : A + B

_=+_ : {A : 𝒰 i} {B : 𝒰 j} (x y : A + B) → 𝒰 (i ⊔ j)
_=+_ {j = j} (inl a₁) (inl a₂) = Lift {j} (a₁ == a₂)
_=+_ (inl _) (inr _) = 𝟎
_=+_ (inr _) (inl _) = 𝟎
_=+_ {i} (inr b₁) (inr b₂) = Lift {i} (b₁ == b₂)

=+-equiv : (x == y) ≃ x =+ y
=+-equiv = f , qinv→isequiv (g , η , ε)
  where
  f : x == y → x =+ y
  f {x = inl a} refl = lift refl
  f {x = inr a} refl = lift refl

  g : x =+ y → x == y
  g {x = inl _} {inl _} (lift refl) = refl
  g {x = inl _} {inr _} ()
  g {x = inr _} {inl _} ()
  g {x = inr _} {inr _} (lift refl) = refl

  η : {x y : A + B} → g {x = x} {y} ∘ f ~ id
  η {y = inl _} refl = refl
  η {y = inr _} refl = refl

  ε : f {x = x} {y} ∘ g ~ id
  ε {x = inl _} {inl _} (lift refl) = refl
  ε {x = inl _} {inr _} ()
  ε {x = inr _} {inl _} ()
  ε {x = inr _} {inr _} (lift refl) = refl

=+-elim : x == y → x =+ y
=+-elim = pr₁ =+-equiv

=+-intro : x =+ y → x == y
=+-intro = Iso.g (eqv→iso =+-equiv)


------------------------------------------------------------------------
-- The Agda standard library
--
-- The type for booleans and some operations
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

module Data.Bool.Base where

open import Data.Unit.Base using (⊤)
open import Data.Empty
open import Level using (Level)

private
  variable
    a : Level
    A : Set a

------------------------------------------------------------------------
-- The boolean type

open import Agda.Builtin.Bool public

------------------------------------------------------------------------
-- Relations

infix 4 _≤_ _<_

data _≤_ : Bool → Bool → Set where
  f≤t : false ≤ true
  b≤b : ∀ {b} → b ≤ b

data _<_ : Bool → Bool → Set where
  f<t : false < true

------------------------------------------------------------------------
-- Boolean operations

infixr 6 _∧_
infixr 5 _∨_ _xor_

not : Bool → Bool
not true  = false
not false = true

_∧_ : Bool → Bool → Bool
true  ∧ b = b
false ∧ b = false

_∨_ : Bool → Bool → Bool
true  ∨ b = true
false ∨ b = b

_xor_ : Bool → Bool → Bool
true  xor b = not b
false xor b = b

------------------------------------------------------------------------
-- Other operations

infix  0 if_then_else_

if_then_else_ : Bool → A → A → A
if true  then t else f = t
if false then t else f = f

-- A function mapping true to an inhabited type and false to an empty
-- type.

T : Bool → Set
T true  = ⊤
T false = ⊥


open import TypeTheory.Nat.Mono.Structure

module TypeTheory.Nat.Mono.Properties (nat : Nat) where

open import Level renaming (zero to lzero; suc to lsuc)
open import Data.Empty using (⊥)
open import Data.Product using (Σ; _×_; _,_)
open import Data.Sum
open import Relation.Binary using (Rel)
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary using (¬_)
open import Function.Base

open Nat nat

+-suc : ∀ m n → suc m + n ≡ suc (m + n)
+-suc m n = rec-suc _ _ _

+-identityˡ : ∀ n → zero + n ≡ n
+-identityˡ n = rec-zero _ _

+-identityʳ : ∀ n → n + zero ≡ n
+-identityʳ n = ind (λ k → k + zero ≡ k) (+-identityˡ zero)
                    (λ k k+z≡k → trans (+-suc k zero) (cong suc k+z≡k) )
                    n

1N+n≡sn : ∀ n → 1N + n ≡ suc n
1N+n≡sn n = begin
  suc zero + n   ≡⟨ +-suc zero n ⟩
  suc (zero + n) ≡⟨ cong suc (+-identityˡ n) ⟩
  suc n          ∎
  where open ≡-Reasoning

+-suc-comm : ∀ m n → suc m + n ≡ m + suc n
+-suc-comm m n =
  ind
    (λ o → suc o + n ≡ o + suc n)
    (begin
      suc zero + n ≡⟨ 1N+n≡sn n ⟩
      suc n        ≡⟨ sym $ +-identityˡ (suc n) ⟩
      zero + suc n ∎)
    (λ o so+n≡o+sn → begin
      suc (suc o) + n ≡⟨ +-suc (suc o) n ⟩
      suc (suc o + n) ≡⟨ cong suc so+n≡o+sn ⟩
      suc (o + suc n) ≡⟨ sym $ +-suc o (suc n) ⟩
      suc o + suc n   ∎)
    m
  where open ≡-Reasoning

z≤n : ∀ n → zero ≤ n
z≤n n = n , +-identityˡ n

≤-step : ∀ {m n} → m ≤ n → m ≤ suc n
≤-step {m} {n} (o , m+o≡n) = suc o , (begin
  m + suc o   ≡⟨ sym $ +-suc-comm m o ⟩
  suc m + o   ≡⟨ +-suc m o ⟩
  suc (m + o) ≡⟨ cong suc m+o≡n ⟩
  suc n       ∎)
  where open ≡-Reasoning

≤-refl : ∀ {n} → n ≤ n
≤-refl {n} = zero , +-identityʳ n

s≤s : ∀ {m n} → m ≤ n → suc m ≤ suc n
s≤s {m} {n} (o , m+o≡n) = o , trans (+-suc m o) (cong suc m+o≡n)

s<s : ∀ {m n} → m < n → suc m < suc n
s<s = s≤s

z<s : ∀ n → zero < suc n
z<s n = s≤s (z≤n n)

n<sn : ∀ n → n < suc n
n<sn n = ≤-refl {suc n}

≤⇒<∨≡ : ∀ {m n} → m ≤ n → m < n ⊎ m ≡ n
≤⇒<∨≡ {m} {n} (o , m+o≡n) =
  ind (λ k → m + k ≡ n → m < n ⊎ m ≡ n)
      (λ m+z≡n → inj₂ (trans (sym $ +-identityʳ m) m+z≡n))
      (λ k _ m+sk≡n → inj₁ (k , (trans (+-suc-comm m k) m+sk≡n)))
      o
      m+o≡n

data Order (m n : N) : Set where
  less    : (m<n : m < n) → Order m n
  equal   : (m≡n : m ≡ n) → Order m n
  greater : (m>n : m > n) → Order m n

order? : ∀ m n → Order m n
order? m₀ n₀ = ind (λ m → Order m n₀) order?-zero order?-suc m₀
  where
  order?-zero : Order zero n₀
  order?-zero = ind (Order zero) (equal refl) (λ _ _ → less (z<s _)) n₀

  order?-suc : ∀ m → Order m n₀ → Order (suc m) n₀
  order?-suc m (less sm≤n) with ≤⇒<∨≡ sm≤n
  ... | inj₁ sm<n = less sm<n
  ... | inj₂ sm≡n = equal sm≡n
  order?-suc m (equal refl)  = greater (n<sn _)
  order?-suc m (greater m>n) = greater (≤-step m>n)

-- indΔ :
module _ (P : N → N → Set) where
  indΔ : P zero zero →
         (∀ n → P zero (suc n)) →
         (∀ m → P (suc m) zero) →
         (∀ m n → P m n → P (suc m) (suc n)) →
         ∀ m n → P m n
  indΔ Pzz Pzs Psz Pss m n with order? m n
  ... | less    m<n = {!   !}
  ... | equal   m≡n = {!   !}
  ... | greater m>n = {!   !}


module fold-Tree where

open import map-Tree using (Tree; leaf; node)

fold-Tree : ∀ {A B C : Set} → (A → C) → (C → B → C → C) → Tree A B → C
fold-Tree f _ (leaf a)             = f a
fold-Tree f g (node treeˡ b treeʳ) = g (fold-Tree f g treeˡ) b (fold-Tree f g treeʳ)


------------------------------------------------------------------------
-- The Agda standard library
--
-- A generalisation of the arithmetic operations
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

module Data.Nat.GeneralisedArithmetic where

open import Data.Nat
open import Data.Nat.Properties
open import Function using (_∘′_; _∘_; id)
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

module _ {a} {A : Set a} where

  fold : A → (A → A) → ℕ → A
  fold z s zero    = z
  fold z s (suc n) = s (fold z s n)

  add : (0# : A) (1+ : A → A) → ℕ → A → A
  add 0# 1+ n z = fold z 1+ n

  mul : (0# : A) (1+ : A → A) → (+ : A → A → A) → (ℕ → A → A)
  mul 0# 1+ _+_ n x = fold 0# (λ s → x + s) n

-- Properties

module _ {a} {A : Set a} where

  fold-+ : ∀ {s : A → A} {z : A} →
           ∀ m {n} → fold z s (m + n) ≡ fold (fold z s n) s m
  fold-+ zero    = refl
  fold-+ {s = s} (suc m) = cong s (fold-+ m)

  fold-k : ∀ {s : A → A} {z : A} {k} m →
           fold k (s ∘′_) m z ≡ fold (k z) s m
  fold-k zero    = refl
  fold-k {s = s} (suc m) = cong s (fold-k m)

  fold-* : ∀ {s : A → A} {z : A} m {n} →
           fold z s (m * n) ≡ fold z (fold id (s ∘_) n) m
  fold-*  zero        = refl
  fold-* {s = s} {z} (suc m) {n} = let +n = fold id (s ∘′_) n in begin
    fold z s (n + m * n)        ≡⟨ fold-+ n ⟩
    fold (fold z s (m * n)) s n ≡⟨ cong (λ z → fold z s n) (fold-* m) ⟩
    fold (fold z +n m) s n      ≡⟨ sym (fold-k n) ⟩
    fold z +n (suc m)           ∎

  fold-pull : ∀ {s : A → A} {z : A} (g : A → A → A) (p : A)
              (eqz : g z p ≡ p)
              (eqs : ∀ l → s (g l p) ≡ g (s l) p) →
              ∀ m → fold p s m ≡ g (fold z s m) p
  fold-pull _ _ eqz _ zero    = sym eqz
  fold-pull {s = s} {z} g p eqz eqs (suc m) = begin
    s (fold p s m)       ≡⟨ cong s (fold-pull g p eqz eqs m) ⟩
    s (g (fold z s m) p) ≡⟨ eqs (fold z s m) ⟩
    g (s (fold z s m)) p ∎

id-is-fold : ∀ m → fold zero suc m ≡ m
id-is-fold zero    = refl
id-is-fold (suc m) = cong suc (id-is-fold m)

+-is-fold : ∀ m {n} → fold n suc m ≡ m + n
+-is-fold zero    = refl
+-is-fold (suc m) = cong suc (+-is-fold m)

*-is-fold : ∀ m {n} → fold zero (n +_) m ≡ m * n
*-is-fold zero        = refl
*-is-fold (suc m) {n} = cong (n +_) (*-is-fold m)

^-is-fold : ∀ {m} n → fold 1 (m *_) n ≡ m ^ n
^-is-fold     zero    = refl
^-is-fold {m} (suc n) = cong (m *_) (^-is-fold n)

*+-is-fold : ∀ m n {p} → fold p (n +_) m ≡ m * n + p
*+-is-fold m n {p} = begin
  fold p (n +_) m     ≡⟨ fold-pull _+_ p refl
                         (λ l → sym (+-assoc n l p)) m ⟩
  fold 0 (n +_) m + p ≡⟨ cong (_+ p) (*-is-fold m) ⟩
  m * n + p           ∎

^*-is-fold : ∀ m n {p} → fold p (m *_) n ≡ m ^ n * p
^*-is-fold m n {p} = begin
  fold p (m *_) n     ≡⟨ fold-pull _*_ p (*-identityˡ p)
                         (λ l → sym (*-assoc m l p)) n ⟩
  fold 1 (m *_) n * p ≡⟨ cong (_* p) (^-is-fold n) ⟩
  m ^ n * p           ∎


{-# OPTIONS --safe --warning=error --without-K #-}

open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import LogicalFormulae
open import Sets.EquivalenceRelations
open import Setoids.Setoids

module Setoids.DirectSum {m n o p : _} {A : Set m} {B : Set n} (R : Setoid {m} {o} A) (S : Setoid {n} {p} B) where

directSumSetoid : Setoid {m ⊔ n} (A || B)
Setoid._∼_ directSumSetoid (inl x) (inl y) = embedLevel {o} {p} (Setoid._∼_ R x y)
Setoid._∼_ directSumSetoid (inl x) (inr y) = False'
Setoid._∼_ directSumSetoid (inr x) (inl y) = False'
Setoid._∼_ directSumSetoid (inr x) (inr y) = embedLevel {p} {o} (Setoid._∼_ S x y)
Equivalence.reflexive (Setoid.eq directSumSetoid) {inl x} = Equivalence.reflexive (Setoid.eq R) {x} ,, record {}
Equivalence.reflexive (Setoid.eq directSumSetoid) {inr x} = Equivalence.reflexive (Setoid.eq S) {x} ,, record {}
Equivalence.symmetric (Setoid.eq directSumSetoid) {inl x} {inl y} (x=y ,, _) = (Equivalence.symmetric (Setoid.eq R) x=y) ,, record {}
Equivalence.symmetric (Setoid.eq directSumSetoid) {inr x} {inr y} (x=y ,, _) = (Equivalence.symmetric (Setoid.eq S) x=y) ,, record {}
Equivalence.transitive (Setoid.eq directSumSetoid) {inl x} {inl y} {inl z} (x=y ,, _) (y=z ,, _) = Equivalence.transitive (Setoid.eq R) x=y y=z ,, record {}
Equivalence.transitive (Setoid.eq directSumSetoid) {inr x} {inr y} {inr z} (x=y ,, _) (y=z ,, _) = Equivalence.transitive (Setoid.eq S) x=y y=z ,, record {}


{-# OPTIONS --cubical --safe #-}
module Cubical.Structures.AbGroup where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma
open import Cubical.Foundations.SIP renaming (SNS-PathP to SNS)

open import Cubical.Structures.NAryOp
open import Cubical.Structures.Group hiding (⟨_⟩)

private
  variable
    ℓ : Level

abelian-group-axioms : (X : Type ℓ) → raw-group-structure X → Type ℓ
abelian-group-axioms X _·_ = group-axioms X _·_ ×
                             ((x y : X) → x · y ≡ y · x)

abelian-group-structure : Type ℓ → Type ℓ
abelian-group-structure = add-to-structure raw-group-structure abelian-group-axioms

AbGroup : Type (ℓ-suc ℓ)
AbGroup {ℓ} = TypeWithStr ℓ abelian-group-structure

abelian-group-iso : StrIso abelian-group-structure ℓ
abelian-group-iso = add-to-iso (nAryFunIso 2) abelian-group-axioms

abelian-group-axioms-isProp : (X : Type ℓ)
                           → (s : raw-group-structure X)
                           → isProp (abelian-group-axioms X s)
abelian-group-axioms-isProp X _·_ = isPropΣ (group-axioms-isProp X _·_)
                                    λ { ((isSetX , _) , _) → isPropΠ2 λ _ _ → isSetX _ _}

abelian-group-is-SNS : SNS {ℓ} abelian-group-structure abelian-group-iso
abelian-group-is-SNS = add-axioms-SNS _ abelian-group-axioms-isProp raw-group-is-SNS

AbGroupPath : (M N : AbGroup {ℓ}) → (M ≃[ abelian-group-iso ] N) ≃ (M ≡ N)
AbGroupPath = SIP abelian-group-is-SNS

-- Abelian group is group

AbGroup→Group : AbGroup {ℓ} → Group
AbGroup→Group (G , _·_ , isGroup , ·comm) = G , _·_ , isGroup

-- Abelian group extractors

⟨_⟩ : AbGroup {ℓ} → Type ℓ
⟨ G , _ ⟩ = G

module _ (G : AbGroup {ℓ}) where

  abgroup-operation = group-operation (AbGroup→Group G)

  abgroup-is-set = group-is-set (AbGroup→Group G)

  abgroup-assoc = group-assoc (AbGroup→Group G)

  abgroup-id = group-id (AbGroup→Group G)

  abgroup-rid = group-rid (AbGroup→Group G)

  abgroup-lid = group-lid (AbGroup→Group G)

  abgroup-inv = group-inv (AbGroup→Group G)

  abgroup-rinv = group-rinv (AbGroup→Group G)

  abgroup-linv = group-linv (AbGroup→Group G)

module abgroup-operation-syntax where

  abgroup-operation-syntax : (G : AbGroup {ℓ}) → ⟨ G ⟩ → ⟨ G ⟩ → ⟨ G ⟩
  abgroup-operation-syntax G = abgroup-operation G
  infixr 20 abgroup-operation-syntax
  syntax abgroup-operation-syntax G x y = x ·⟨ G ⟩ y

open abgroup-operation-syntax

abgroup-comm : (G : AbGroup {ℓ}) (x y : ⟨ G ⟩) → x ·⟨ G ⟩ y ≡ y ·⟨ G ⟩ x
abgroup-comm (_ , _ , _ , P) = P

-- AbGroup ·syntax

module abgroup-·syntax (G : AbGroup {ℓ}) where
  open group-·syntax (AbGroup→Group G) public


{-
  Definition of various kinds of categories.

  This library follows the UniMath terminology, that is:

  Concept              Ob C   Hom C  Univalence

  Precategory          Type   Type   No
  Category             Type   Set    No
  Univalent Category   Type   Set    Yes

  This file also contains
    - pathToIso : Turns a path between two objects into an isomorphism between them
    - opposite categories

-}

{-# OPTIONS --cubical --no-import-sorts --safe #-}

module Cubical.Categories.Category where

open import Cubical.Core.Glue
open import Cubical.Foundations.Prelude

private
  variable
    ℓ ℓ' : Level

-- Precategories

record Precategory ℓ ℓ' : Type (ℓ-suc (ℓ-max ℓ ℓ')) where
  -- no-eta-equality ; NOTE: need eta equality for `opop`
  field
    ob : Type ℓ
    Hom[_,_] : ob → ob → Type ℓ'
    id : ∀ x → Hom[ x , x ]
    _⋆_ : ∀ {x y z} (f : Hom[ x , y ]) (g : Hom[ y , z ]) → Hom[ x , z ]
    ⋆IdL : ∀ {x y : ob} (f : Hom[ x , y ]) → (id x) ⋆ f ≡ f
    ⋆IdR : ∀ {x y} (f : Hom[ x , y ]) → f ⋆ (id y) ≡ f
    ⋆Assoc : ∀ {u v w x} (f : Hom[ u , v ]) (g : Hom[ v , w ]) (h : Hom[ w , x ]) → (f ⋆ g) ⋆ h ≡ f ⋆ (g ⋆ h)

  -- composition: alternative to diagramatic order
  _∘_ : ∀ {x y z} (g : Hom[ y , z ]) (f : Hom[ x , y ]) → Hom[ x , z ]
  g ∘ f = f ⋆ g

open Precategory

-- Helpful syntax/notation

_[_,_] : (C : Precategory ℓ ℓ') → (x y : C .ob) → Type ℓ'
_[_,_] = Hom[_,_]

-- needed to define this in order to be able to make the subsequence syntax declaration
seq' : ∀ (C : Precategory ℓ ℓ') {x y z} (f : C [ x , y ]) (g : C [ y , z ]) → C [ x , z ]
seq' = _⋆_

infix 15 seq'
syntax seq' C f g = f ⋆⟨ C ⟩ g

-- composition
comp' : ∀ (C : Precategory ℓ ℓ') {x y z} (g : C [ y , z ]) (f : C [ x , y ]) → C [ x , z ]
comp' = _∘_

infix 16 comp'
syntax comp' C g f = g ∘⟨ C ⟩ f

-- Categories

record isCategory (C : Precategory ℓ ℓ') : Type (ℓ-max ℓ ℓ') where
  field
    isSetHom : ∀ {x y} → isSet (C [ x , y ])

-- Isomorphisms and paths in precategories

record CatIso {C : Precategory ℓ ℓ'} (x y : C .Precategory.ob) : Type ℓ' where
  constructor catiso
  field
    mor : C [ x , y ]
    inv : C [ y , x ]
    sec : inv ⋆⟨ C ⟩ mor ≡ C .id y
    ret : mor ⋆⟨ C ⟩ inv ≡ C .id x

pathToIso : {C : Precategory ℓ ℓ'} (x y : C .ob) (p : x ≡ y) → CatIso {C = C} x y
pathToIso {C = C} x y p = J (λ z _ → CatIso x z) (catiso (C .id x) idx (C .⋆IdL idx) (C .⋆IdL idx)) p
  where
    idx = C .id x

-- Univalent Categories

record isUnivalent (C : Precategory ℓ ℓ') : Type (ℓ-max ℓ ℓ') where
  field
    univ : (x y : C .ob) → isEquiv (pathToIso {C = C} x y)

open isUnivalent public

-- Opposite Categories

_^op : Precategory ℓ ℓ' → Precategory ℓ ℓ'
(C ^op) .ob = C .ob
(C ^op) .Hom[_,_] x y = C .Hom[_,_] y x
(C ^op) .id = C .id
(C ^op) ._⋆_ f g = C ._⋆_ g f
(C ^op) .⋆IdL = C .⋆IdR
(C ^op) .⋆IdR = C .⋆IdL
(C ^op) .⋆Assoc f g h = sym (C .⋆Assoc _ _ _)

open isCategory public

-- opposite of opposite is definitionally equal to itself
involutiveOp : ∀ {C : Precategory ℓ ℓ'} → (C ^op) ^op ≡ C
involutiveOp = refl

-- Other useful operations on categories

-- whisker the parallel morphisms g and g' with f
lPrecatWhisker : {C : Precategory ℓ ℓ'} {x y z : C .ob} (f : C [ x , y ]) (g g' : C [ y , z ]) (p : g ≡ g') → f ⋆⟨ C ⟩ g ≡ f ⋆⟨ C ⟩ g'
lPrecatWhisker {C = C} f _ _ p = cong (_⋆_ C f) p


-- Sums and cocartesian categories
module CategoryTheory.BCCCs.Cocartesian where

open import CategoryTheory.Categories

open import Relation.Binary using (IsEquivalence)

module _ {n} (ℂ : Category n) where

    open Category ℂ

    -- Initial object in a category
    record InitialObj : Set (lsuc n) where
        field
            -- | Data
            -- The initial object
            ⊥ : obj
            -- Canonical morphism
            ¡ : {A : obj} -> (⊥ ~> A)

            -- | Laws
            -- Need to show that the canonical morphism ! is unique
            ¡-unique : {A : obj} -> (m : ⊥ ~> A)
                  -> m ≈ ¡

    -- Sum of two objects
    -- Based on github.com/copumpkin/categories
    record Sum (A B : obj) : Set (lsuc n) where
        infix 10 [_⁏_]
        field
            -- | Data
            -- Sum of A and B
            A⊕B : obj
            -- First injection
            ι₁ : A ~> A⊕B
            -- Second injection
            ι₂ : B ~> A⊕B
            -- Canonical mediator
            [_⁏_] : ∀{S} -> (A ~> S) -> (B ~> S) -> (A⊕B ~> S)

            -- | Laws
            -- [_⁏_] expresses that given another candidate sum S
            -- and candidate injections to A and B there is a morphism
            -- from A⊕B to S. We need to check that this mediator makes
            -- the sum diagram commute and is unique.

            ι₁-comm : ∀{S} -> {i₁ : A ~> S} {i₂ : B ~> S}
                   -> [ i₁ ⁏ i₂ ] ∘ ι₁ ≈ i₁
            ι₂-comm : ∀{S} -> {i₁ : A ~> S} {i₂ : B ~> S}
                   -> [ i₁ ⁏ i₂ ] ∘ ι₂ ≈ i₂
            ⊕-unique  : ∀{S} -> {i₁ : A ~> S} {i₂ : B ~> S} {m : A⊕B ~> S}
                   -> m ∘ ι₁ ≈ i₁ -> m ∘ ι₂ ≈ i₂ -> [ i₁ ⁏ i₂ ] ≈ m

        -- η-expansion of function sums (via morphisms)
        ⊕-η-exp : ∀{S} -> {m : A⊕B ~> S}
               -> [ m ∘ ι₁ ⁏ m ∘ ι₂ ] ≈ m
        ⊕-η-exp = ⊕-unique r≈ r≈

        -- Summing of injection functions is the identity
        ⊕-η-id : [ ι₁ ⁏ ι₂ ] ≈ id
        ⊕-η-id = ⊕-unique id-left id-left

        -- Congruence over function summing
        [⁏]-cong : ∀{S} -> {i₁ j₁ : A ~> S} {i₂ j₂ : B ~> S}
               -> i₁ ≈ j₁ -> i₂ ≈ j₂
               -> [ i₁ ⁏ i₂ ] ≈ [ j₁ ⁏ j₂ ]
        [⁏]-cong pr1 pr2 = ⊕-unique (ι₁-comm ≈> pr1 [sym]) (ι₂-comm ≈> pr2 [sym])

-- Type class for cocartesian categories
record Cocartesian {n} (ℂ : Category n) : Set (lsuc n) where
    open Category ℂ
    field
        -- | Data
        -- Initial object
        init : InitialObj ℂ
        -- Binary sums for all pairs of objects
        sum : ∀(A B : obj) -> Sum ℂ A B

    open InitialObj init public
    open module S {A} {B} = Sum (sum A B) public

    -- Shorthand for sum object
    infixl 22 _⊕_
    _⊕_ : (A B : obj) -> obj
    A ⊕ B = A⊕B {A} {B}

    -- Parallel sum of morphisms
    infixl 65 _⊹_
    _⊹_ : {A B P Q : obj} -> (A ~> P) -> (B ~> Q)
       -> (A ⊕ B ~> P ⊕ Q)
    _⊹_ {A} {B} {P} {Q} f g = [ ι₁ ∘ f ⁏ ι₂ ∘ g ]

    -- Sum of three morphisms
    [_⁏_⁏_] : ∀{S A B C : obj} -> (A ~> S) -> (B ~> S) -> (C ~> S) -> (A ⊕ B ⊕ C ~> S)
    [ f ⁏ g ⁏ h ] = [ [ f ⁏ g ] ⁏ h ]


{-# OPTIONS --without-K #-}

module VectorLemmas where

open import Level using (Level)

open import Data.Vec
  using (Vec; tabulate; []; _∷_; lookup; allFin)
  renaming (_++_ to _++V_; map to mapV; concat to concatV)
open import  Data.Vec.Properties
  using (lookup-++-≥; lookup∘tabulate; tabulate-∘; tabulate∘lookup;
     tabulate-allFin)
open import Function using (id;_∘_;flip)
open import Relation.Binary.PropositionalEquality
  using (_≡_; refl; sym; cong; cong₂; subst; trans; proof-irrelevance; module ≡-Reasoning)
open import Data.Nat using (ℕ; zero; suc; _+_; z≤n; _*_)
open import Data.Nat.Properties.Simple using (+-comm; +-right-identity)
open import Data.Fin using (Fin; zero; suc; inject+; raise; reduce≥)
open import Data.Fin.Properties using (toℕ-injective)

open import Data.Sum using (_⊎_; [_,_]′; inj₁; inj₂) renaming (map to map⊎)

open import SubstLemmas
open import FinNatLemmas
open import FiniteFunctions

------------------------------------------------------------------------------
-- Lemmas about map and tabulate

-- to make things look nicer
_!!_ : ∀ {m} {A : Set} → Vec A m → Fin m → A
v !! i = lookup i v

-- this is actually in Data.Vec.Properties, but over an arbitrary
-- Setoid.  Specialize

map-id : ∀ {a n} {A : Set a} (xs : Vec A n) → mapV id xs ≡ xs
map-id [] = refl
map-id (x ∷ xs) = cong (_∷_ x) (map-id xs)

map-++-commute : ∀ {a b m n} {A : Set a} {B : Set b}
                 (f : B → A) (xs : Vec B m) {ys : Vec B n} →
                 mapV f (xs ++V ys) ≡ mapV f xs ++V mapV f ys
map-++-commute f []       = refl
map-++-commute f (x ∷ xs) = cong (λ z → f x ∷ z) (map-++-commute f  xs)

-- this is too, but is done "point free", this version is more convenient

map-∘ : ∀ {a b c n} {A : Set a} {B : Set b} {C : Set c}
        (f : B → C) (g : A → B) → (xs : Vec A n) →
        mapV (f ∘ g) xs ≡ (mapV f ∘ mapV g) xs
map-∘ f g [] = refl
map-∘ f g (x ∷ xs) = cong (_∷_ (f (g x))) (map-∘ f g xs)

-- this looks trivial, why can't I find it?

lookup-map : ∀ {a b} {n : ℕ} {A : Set a} {B : Set b} →
  (i : Fin n) → (f : A → B) →
  (v : Vec A n) → lookup i (mapV f v) ≡ f (lookup i v)
lookup-map {n = 0} () _ _
lookup-map {n = suc n} zero f (x ∷ v) = refl
lookup-map {n = suc n} (suc i) f (x ∷ v) = lookup-map i f v

-- These are 'generalized' lookup into left/right parts of a Vector which
-- does not depend on the values in the Vector at all.

look-left : ∀ {m n} {a b c : Level} {A : Set a} {B : Set b} {C : Set c} →
  (i : Fin m) → (f : A → C) → (g : B → C) → (vm : Vec A m) → (vn : Vec B n) →
  lookup (inject+ n i) (mapV f vm ++V mapV g vn) ≡ f (lookup i vm)
look-left {0} () _ _ _ _
look-left {suc _} zero f g (x ∷ vm) vn = refl
look-left {suc _} (suc i) f g (x ∷ vm) vn = look-left i f g vm vn

look-right : ∀ {m n} {a b c : Level} {A : Set a} {B : Set b} {C : Set c} →
  (i : Fin n) → (f : A → C) → (g : B → C) → (vm : Vec A m) → (vn : Vec B n) →
  lookup (raise m i) (mapV f vm ++V mapV g vn) ≡ g (lookup i vn)
look-right {0} i f g vn vm = lookup-map i g vm
look-right {suc m} {0} () _ _ _ _
look-right {suc m} {suc n} i f g (x ∷ vn) vm = look-right i f g vn vm

-- variant
left!! : ∀ {m n} {C : Set} →
  (i : Fin m) → (f : Fin m → C) → {g : Fin n → C} →
  (tabulate f ++V tabulate g) !! (inject+ n i) ≡ f i
left!! {zero} () _
left!! {suc _} zero f = refl
left!! {suc _} (suc i) f = left!! i (f ∘ suc)

right!! : ∀ {m n} {C : Set} →
  (i : Fin n) → {f : Fin m → C} → (g : Fin n → C) →
  (tabulate f ++V tabulate g) !! (raise m i) ≡ g i
right!! {zero} i g = lookup∘tabulate g i
right!! {suc _} {0} () _
right!! {suc m} {suc _} i g = right!! {m} i g

-- similar to lookup-++-inject+ from library

lookup-++-raise : ∀ {m n} {a : Level} {A : Set a} →
  (vm : Vec A m) (vn : Vec A n) (i : Fin n) →
  lookup (raise m i) (vm ++V vn) ≡ lookup i vn
lookup-++-raise {0} vn vm i =
  begin (lookup i (vn ++V vm)
           ≡⟨ lookup-++-≥ vn vm i z≤n ⟩
         lookup (reduce≥ i z≤n) vm
            ≡⟨ refl ⟩
         lookup i vm ∎)
  where open ≡-Reasoning --
lookup-++-raise {suc m} {0} _ _ ()
lookup-++-raise {suc m} {suc n} (x ∷ vn) vm i = lookup-++-raise vn vm i

-- concat (map (map f) xs) = map f (concat xs)
concat-map : ∀ {a b m n} {A : Set a} {B : Set b} →
  (xs : Vec (Vec A n) m) → (f : A → B) →
  concatV (mapV (mapV f) xs) ≡ mapV f (concatV xs)
concat-map [] f = refl
concat-map (xs ∷ xss) f =
  begin (concatV (mapV (mapV f) (xs ∷ xss))
           ≡⟨ refl ⟩
         concatV (mapV f xs ∷ mapV (mapV f) xss)
           ≡⟨  refl ⟩
         mapV f xs ++V concatV (mapV (mapV f) xss)
           ≡⟨ cong (_++V_ (mapV f xs)) (concat-map xss f) ⟩
         mapV f xs ++V mapV f (concatV xss)
           ≡⟨ sym (map-++-commute f xs) ⟩
         mapV f (xs ++V concatV xss)
           ≡⟨ refl ⟩
         mapV f (concatV (xs ∷ xss)) ∎)
  where open ≡-Reasoning

map-map-map : ∀ {a b c m n} {A : Set a} {B : Set b} {C : Set c} →
  (f  : B → C) → (g : A → Vec B n) → (xs : Vec A m) →
  mapV (mapV f) (mapV g xs) ≡ mapV (mapV f ∘ g) xs
map-map-map f g xss = sym (map-∘ (mapV f) g xss)

splitV+ : ∀ {m n} {a : Level} {A : Set a} {f : Fin (m + n) → A} → Vec A (m + n)
splitV+ {m} {n} {f = f} = tabulate {m} (f ∘ inject+ n) ++V tabulate {n} (f ∘ raise m)

splitVOp+ : ∀ {m} {n} {a : Level} {A : Set a} {f : Fin (n + m) → A} → Vec A (m + n)
splitVOp+ {m} {n} {f = f} = tabulate {m} (f ∘ raise n) ++V tabulate {n} (f ∘ inject+ m)

-- f can be implicit since this is mostly used in equational reasoning, where it can be inferred!
tabulate-split : ∀ {m n} {a : Level} {A : Set a} → {f : Fin (m + n) → A} →
  tabulate {m + n} f ≡ splitV+ {m} {n} {f = f}
tabulate-split {0} = refl
tabulate-split {suc m} {f = f} = cong (_∷_ (f zero)) (tabulate-split {m} {f = f ∘ suc})

lookup-subst : ∀ {m m' n}
  (i : Fin n) (xs : Vec (Fin m) n) (eq : m ≡ m') →
  lookup i (subst (λ s → Vec (Fin s) n) eq xs) ≡
  subst Fin eq (lookup i xs)
lookup-subst i xs refl = refl

-- lookup is associative on Fin vectors
lookupassoc : ∀ {m₁ m₂ m₃ m₄} → (π₁ : Vec (Fin m₂) m₁)
  (π₂ : Vec (Fin m₃) m₂) (π₃ : Vec (Fin m₄) m₃) → (i : Fin m₁) →
  lookup (lookup i π₁) (tabulate (λ j → lookup (lookup j π₂) π₃)) ≡
  lookup (lookup i (tabulate (λ j → lookup (lookup j π₁) π₂))) π₃
lookupassoc π₁ π₂ π₃ i =
  begin (lookup (lookup i π₁) (tabulate (λ j → lookup (lookup j π₂) π₃))
           ≡⟨ lookup∘tabulate (λ j → lookup (lookup j π₂) π₃) (lookup i π₁) ⟩
         lookup (lookup (lookup i π₁) π₂) π₃
           ≡⟨ cong
                (λ x → lookup x π₃)
                (sym (lookup∘tabulate (λ j → lookup (lookup j π₁) π₂) i)) ⟩
         lookup (lookup i (tabulate (λ j → lookup (lookup j π₁) π₂))) π₃ ∎)
  where open ≡-Reasoning

-- This should generalize a lot, but that can be done later
subst-lookup-tabulate-raise : ∀ {m n : ℕ} → (z : Fin n) →
  subst Fin (+-comm n m) (lookup z (tabulate (λ i → subst Fin (+-comm m n) (raise m i)))) ≡
  raise m z
subst-lookup-tabulate-raise {m} {n} z =
 begin (subst Fin (+-comm n m) (lookup z (tabulate (λ i → subst Fin (+-comm m n) (raise m i))))
      ≡⟨ cong (subst Fin (+-comm n m))
             (lookup∘tabulate (λ i → subst Fin (+-comm m n) (raise m i)) z) ⟩
    subst Fin (+-comm n m) (subst Fin (+-comm m n) (raise m z))
      ≡⟨ subst-subst (+-comm n m) (+-comm m n)
                 (proof-irrelevance (sym (+-comm n m)) (+-comm m n)) (raise m z) ⟩
    raise m z
     ∎)
  where open ≡-Reasoning

subst-lookup-tabulate-inject+ : ∀ {m n : ℕ} → (z : Fin m) →
  subst Fin (+-comm n m) (lookup z (tabulate (λ i → subst Fin (+-comm m n) (inject+ n i)))) ≡
  inject+ n z
subst-lookup-tabulate-inject+ {m} {n} z =
 begin (subst Fin (+-comm n m) (lookup z (tabulate (λ i → subst Fin (+-comm m n) (inject+ n i))))
      ≡⟨ cong (subst Fin (+-comm n m))
             (lookup∘tabulate (λ i → subst Fin (+-comm m n) (inject+ n i)) z) ⟩
    subst Fin (+-comm n m) (subst Fin (+-comm m n) (inject+ n z))
      ≡⟨ subst-subst (+-comm n m) (+-comm m n)
                 (proof-irrelevance (sym (+-comm n m)) (+-comm m n)) (inject+ n z) ⟩
    inject+ n z
     ∎)
  where open ≡-Reasoning

-- a kind of inverse for splitAt
unSplit : {m n : ℕ} {A : Set} → (f : Fin (m + n) → A) →
  tabulate {m} (f ∘ (inject+ n)) ++V tabulate {n} (f ∘ (raise m)) ≡ tabulate f
unSplit {0} {n} f = refl
unSplit {suc m} f = cong (λ x → (f zero) ∷ x) (unSplit {m} (f ∘ suc))

-- nested tabulate-lookup
denest-tab-!! : {A B C : Set} {k : ℕ} → (f : B → C) → (g : A → B) → (v : Vec A k) →
    tabulate (λ i → f (tabulate (λ j → g (v !! j)) !! i)) ≡ mapV (f ∘ g) v
denest-tab-!! f g v =
  begin (
    tabulate (λ i → f (tabulate (λ j → g (v !! j)) !! i))
        ≡⟨ tabulate-∘ f (λ i → tabulate (λ j → g (v !! j)) !! i) ⟩
    mapV f (tabulate  (λ i → tabulate (λ j → g (v !! j)) !! i) )
        ≡⟨ cong (mapV f) (tabulate∘lookup (tabulate (λ j → g (v !! j)))) ⟩
    mapV f (tabulate (λ j → g (v !! j)))
        ≡⟨ cong (mapV f) (tabulate-∘ g (flip lookup v)) ⟩
    mapV f (mapV g (tabulate (flip lookup v)))
        ≡⟨ sym (map-∘ f g _) ⟩
    mapV (f ∘ g) (tabulate (flip lookup v))
        ≡⟨ cong (mapV (f ∘ g)) (tabulate∘lookup v) ⟩
    mapV (f ∘ g) v ∎)
  where open ≡-Reasoning

tab++[]≡tab∘̂unite+ : ∀ {m} {A : Set} (f : Fin m → A) (eq : m + 0 ≡ m) →
  tabulate f ++V [] ≡ tabulate (λ j → f (subst Fin eq j))
tab++[]≡tab∘̂unite+ {zero} f eq = refl
tab++[]≡tab∘̂unite+ {suc m} f eq = cong₂ _∷_ (cong f pf₁) pf₂
  where
    pf₁ : zero ≡ subst Fin eq zero
    pf₁ = toℕ-injective (sym (toℕ-invariance zero eq))
    pf₃ : ∀ j → suc (subst Fin (+-right-identity m) j) ≡ subst Fin eq (suc j)
    pf₃ j = toℕ-injective (trans (cong suc (toℕ-invariance j (+-right-identity m)))
                                 (sym (toℕ-invariance (suc j) eq)))
    pf₂ : tabulate (f ∘ suc) ++V [] ≡ tabulate (λ j → f (subst Fin eq (suc j)))
    pf₂ = trans (tab++[]≡tab∘̂unite+ (f ∘ suc) (+-right-identity m))
                (finext (λ j → cong f (pf₃ j)))

-- Move to its own spot later
merge-[,] : {A B C D E : Set} → {h : A → C} → {i : B → D} → {f : C → E}
  → {g : D → E} → (x : A ⊎ B) →
    [ f , g ]′ ( map⊎ h i x ) ≡ [ (f ∘ h) , (g ∘ i) ]′ x
merge-[,] (inj₁ x) = refl
merge-[,] (inj₂ y) = refl


open import Common.Prelude

instance
  tti : ⊤
  tti = record{}

NonZero : Nat → Set
NonZero zero    = ⊥
NonZero (suc _) = ⊤

pred′ : (n : Nat) .{{_ : NonZero n}} → Nat
pred′ zero {{}}
pred′ (suc n) = n

test : (n : Nat) {{x y : NonZero n}} → Nat
test n = pred′ n

_<_ : Nat → Nat → Set
m < zero = ⊥
zero < suc n = ⊤
suc m < suc n = m < n

instance
  <-suc : ∀ {m n} → .(m < n) → m < suc n
  <-suc {zero} _ = tt
  <-suc {suc m} {zero} ()
  <-suc {suc m} {suc n} = <-suc {m} {n}


{-# OPTIONS --safe #-}
module Cubical.Algebra.AbGroup.Instances.NProd where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Nat using (ℕ)

open import Cubical.Algebra.Group
open import Cubical.Algebra.Group.Instances.NProd
open import Cubical.Algebra.AbGroup

private variable
  ℓ : Level

open AbGroupStr

NProd-AbGroup : (G : (n : ℕ) → Type ℓ) → (Gstr : (n : ℕ) → AbGroupStr (G n)) → AbGroup ℓ
NProd-AbGroup G Gstr = Group→AbGroup (NProd-Group G (λ n → AbGroupStr→GroupStr (Gstr n)))
                                      λ f g → funExt λ n → +Comm (Gstr n) _ _


module #1 where

open import Level
open import Relation.Binary.PropositionalEquality

{-
Exercise 1.1. Given functions f : A → B and g : B → C, define their composite g ◦ f : A → C.
Show that we have h ◦ (g ◦ f ) ≡ (h ◦ g) ◦ f .
-}

-- Function composition
_∘_ : ∀ {a b c}{A : Set a}{B : Set b}{C : Set c} → (B → C) → (A → B) → A → C
f ∘ g = λ x → f (g x)

-- Proof of associativity of composition
∘-assoc : ∀ {a b c d}{A : Set a}{B : Set b}{C : Set c}{D : Set d} →
            (h : C → D) → (g : B → C) → (f : A → B) →
            h ∘ (g ∘ f) ≡ (h ∘ g) ∘ f
∘-assoc _ _ _ = refl


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.RingSolver.IntAsRawRing where

open import Cubical.Data.Nat hiding (_+_; _·_)
open import Cubical.Data.Int
open import Cubical.Data.Int.Base renaming (Int to ℤ) public

open import Cubical.Foundations.Prelude
open import Cubical.Algebra.RingSolver.RawRing

ℤAsRawRing : RawRing {ℓ-zero}
ℤAsRawRing = rawring ℤ (pos zero) (pos (suc zero)) _+_ _·_ (λ k → - k)

+Ridℤ : (k : ℤ) → (pos zero) + k ≡ k
+Ridℤ k = sym (pos0+ k)


module Lectures.Three where

open import Lectures.One
open import Lectures.Two

-- Introduce propositional equality

data _≡_ {A : Set} (x : A) : A → Set where
  refl : x ≡ x

{-# BUILTIN EQUALITY _≡_ #-}

-- Comment on precendences
infix 10 _≡_

record Equivalence (_~_ : ∀ {A : Set} → A → A → Set) : Set₁ where
  field
    reflexive  : ∀ {A} {a : A} → a ~ a
    symmetric  : ∀ {A} {a b : A} → a ~ b → b ~ a
    transitive : ∀ {A} {a b c : A} → a ~ b → b ~ c → a ~ c

open Equivalence

sym : ∀ {A} {a b : A} → a ≡ b → b ≡ a
sym refl = refl

trans : ∀ {A} {a b c : A} → a ≡ b → b ≡ c → a ≡ c
trans refl refl = refl

-- Comment on copatterns
≡-Equivalence : Equivalence _≡_
reflexive ≡-Equivalence = refl
symmetric ≡-Equivalence = sym
transitive ≡-Equivalence = trans

cong : ∀ {A B} {a b : A} → (f : A → B) → a ≡ b → f a ≡ f b
cong f refl = refl

-- Leibniz equality?
subst : ∀ {A} {x y : A} {P : A → Set} → P x → x ≡ y → P y
subst p refl = p

_ : _+_ ≡ _+_
_ = refl

-- _ : _+_ ≡ λ x y → y + x
-- _ = {!refl!}

-- Comment on postulates
postulate
  extensionality : {A B : Set} {f g : A → B} → (∀ x → f x ≡ g x) → f ≡ g

+-idʳ : ∀ x → x ≡ x + 0
+-idʳ zero = refl
+-idʳ (suc x) = cong suc (+-idʳ _)

+-suc : ∀ x y → suc (x + y) ≡ x + suc y
+-suc zero y = refl
+-suc (suc x) y = cong suc (+-suc _ _)

+-comm : ∀ x y → x + y ≡ y + x
+-comm zero y = +-idʳ _
+-comm (suc x) y = trans (cong suc (+-comm x y)) (+-suc _ _)

+-assoc : ∀ x y z → x + (y + z) ≡ (x + y) + z
+-assoc zero y z = refl
+-assoc (suc x) y z = cong suc (+-assoc x y z)


{-# OPTIONS --without-K #-}

module LeqLemmas where

open import Data.Nat
  using (ℕ; suc; _+_; _*_; _<_; _≤_; _≤?_; z≤n; s≤s; module ≤-Reasoning)
open import Data.Nat.Properties.Simple using (+-comm)
open import Data.Nat.Properties using (n≤m+n)
open import Relation.Binary using (Decidable)

------------------------------------------------------------------------------
-- Proofs and definitions about ≤ on natural numbers

_<?_ : Decidable _<_
i <? j = suc i ≤? j

cong+r≤ : ∀ {i j} → i ≤ j → (k : ℕ) → i + k ≤ j + k
cong+r≤ {0}     {j}     z≤n       k = n≤m+n j k
cong+r≤ {suc i} {0}     ()        k -- absurd
cong+r≤ {suc i} {suc j} (s≤s i≤j) k = s≤s (cong+r≤ {i} {j} i≤j k)

cong+l≤ : ∀ {i j} → i ≤ j → (k : ℕ) → k + i ≤ k + j
cong+l≤ {i} {j} i≤j k =
  begin (k + i
           ≡⟨ +-comm k i ⟩
         i + k
           ≤⟨ cong+r≤ i≤j k ⟩
         j + k
           ≡⟨ +-comm j k ⟩
         k + j ∎)
  where open ≤-Reasoning

cong*r≤ : ∀ {i j} → i ≤ j → (k : ℕ) → i * k ≤ j * k
cong*r≤ {0}     {j}     z≤n       k = z≤n
cong*r≤ {suc i} {0}     ()        k -- absurd
cong*r≤ {suc i} {suc j} (s≤s i≤j) k = cong+l≤ (cong*r≤ i≤j k) k

------------------------------------------------------------------------------


{-# OPTIONS --exact-split              #-}
{-# OPTIONS --no-sized-types           #-}
{-# OPTIONS --no-universe-polymorphism #-}
{-# OPTIONS --without-K                #-}

-- From: Hancock (2008). (Ordinal-theoretic) proof theory.

module Ordinals where

data ℕ : Set where
  zero : ℕ
  succ : ℕ → ℕ

data Ω : Set where
  zero : Ω
  succ : Ω → Ω
  limN : (ℕ → Ω) → Ω

inj : ℕ → Ω
inj zero     = zero
inj (succ n) = succ (inj n)

ω : Ω
ω = limN (λ n → inj n)

ω+1 : Ω
ω+1 = succ ω

data Ω₂ : Set where
  zero : Ω₂
  succ : Ω₂ → Ω₂
  limN : (ℕ → Ω₂) → Ω₂
  limΩ : (Ω → Ω₂) → Ω₂

inj₁ : Ω → Ω₂
inj₁ zero     = zero
inj₁ (succ o) = succ (inj₁ o)
inj₁ (limN f) = limN (λ n → inj₁ (f n))

ω₁ : Ω₂
ω₁ = limΩ (λ o → inj₁ o)


module Structure.Operator.Algebra where

open import Lang.Instance
open import Logic.Predicate
import      Lvl
open import Structure.Function.Domain
open import Structure.Operator.Field
open import Structure.Operator.Monoid
open import Structure.Operator.Properties
open import Structure.Operator.Ring
open import Structure.Operator.Ring.Homomorphism
open import Structure.Operator.Vector
open import Structure.Operator.Vector.LinearMap
open import Structure.Setoid
open import Type

module _
  {ℓᵥ ℓₛ ℓᵥₑ ℓₛₑ}
  {V : Type{ℓᵥ}} ⦃ _ : Equiv{ℓᵥₑ}(V) ⦄
  {S : Type{ℓₛ}} ⦃ _ : Equiv{ℓₛₑ}(S) ⦄
  (_+ᵥ_ : V → V → V)
  (_⋅ᵥ_ : V → V → V)
  (_⋅ₛᵥ_ : S → V → V)
  (_+ₛ_ : S → S → S)
  (_⋅ₛ_ : S → S → S)
  where

  record Algebra : Type{ℓₛₑ Lvl.⊔ ℓₛ Lvl.⊔ ℓᵥₑ Lvl.⊔ ℓᵥ} where
    constructor intro
    field
      ⦃ vectorSpace ⦄      : VectorSpace(_+ᵥ_)(_⋅ₛᵥ_)(_+ₛ_)(_⋅ₛ_)
      ⦃ [⋅ᵥ]-bilinearity ⦄ : BilinearOperator vectorSpace (_⋅ᵥ_)
    open VectorSpace(vectorSpace)
      renaming (ring to ringₛ)
      public

    ringᵥ : ⦃ Associativity(_⋅ᵥ_) ⦄ → ⦃ ∃(Identity(_⋅ᵥ_)) ⦄ → Ring(_+ᵥ_)(_⋅ᵥ_)
    Rng.[+]-commutative-group    (Ring.rng   ringᵥ) = vectorCommutativeGroup
    Rng.[⋅]-binary-operator      (Ring.rng   ringᵥ) = BilinearMap.binaryOperator [⋅ᵥ]-bilinearity
    Rng.[⋅]-associativity        (Ring.rng   ringᵥ) = infer
    Rng.[⋅][+]-distributivityₗ   (Ring.rng   ringᵥ) = BilinearOperator.[+ᵥ]-distributivityₗ vectorSpace (_⋅ᵥ_) [⋅ᵥ]-bilinearity
    Rng.[⋅][+]-distributivityᵣ   (Ring.rng   ringᵥ) = BilinearOperator.[+ᵥ]-distributivityᵣ vectorSpace (_⋅ᵥ_) [⋅ᵥ]-bilinearity
    Unity.[⋅]-identity-existence (Ring.unity ringᵥ) = infer

  -- TODO: I found some conflicting definitions for a star algebra from different sources. What is a reasonable definition?
  record ⋆-algebra (_⋆ᵥ : V → V) (_⋆ₛ : S → S) : Type{ℓₛₑ Lvl.⊔ ℓₛ Lvl.⊔ ℓᵥₑ Lvl.⊔ ℓᵥ} where
    constructor intro
    field
      ⦃ algebra ⦄ : Algebra
    open Algebra(algebra) public

    field
      ⦃ [⋅ᵥ]-commutativity ⦄             : Commutativity(_⋅ᵥ_)
      ⦃ [⋅ᵥ]-associativity ⦄             : Associativity(_⋅ᵥ_)
      ⦃ [⋅ᵥ]-identity ⦄                  : ∃(Identity(_⋅ᵥ_))
      ⦃ [⋆ₛ]-involution ⦄                : Involution(_⋆ᵥ)
      ⦃ [⋆ᵥ]-involution ⦄                : Involution(_⋆ᵥ)
      [⋆ᵥ]-distribute-over-[⋅ₛᵥ]-to-[⋆ₛ] : ∀{s}{v} → ((s ⋅ₛᵥ v)⋆ᵥ ≡ (s ⋆ₛ) ⋅ₛᵥ (v ⋆ᵥ))
      ⦃ [⋆ₛ]-antihomomorphism ⦄          : Antihomomorphism ringₛ ringₛ (_⋆ₛ)
      ⦃ [⋆ᵥ]-antihomomorphism ⦄          : Antihomomorphism ringᵥ ringᵥ (_⋆ᵥ)


{-# OPTIONS --safe --warning=error --without-K #-}

open import Setoids.Setoids
open import Rings.Definition
open import Rings.IntegralDomains.Definition

open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)

module Rings.PrincipalIdealDomains.Definition {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ _*_ : A → A → A} {R : Ring S _+_ _*_} (intDom : IntegralDomain R) where

open import Rings.Ideals.Principal.Definition R
open import Rings.Ideals.Definition R

PrincipalIdealDomain : {c : _} → Set (a ⊔ b ⊔ lsuc c)
PrincipalIdealDomain {c} = {pred : A → Set c} → (ideal : Ideal pred) → PrincipalIdeal ideal


module Structure.Category.Functor where

open import Functional using (_on₂_)
open import Lang.Instance
import      Lvl
open import Logic.Predicate
open import Structure.Category
open import Structure.Function
open import Structure.Function.Multi
import      Structure.Relator.Names as Names
open import Structure.Setoid
open import Syntax.Function
open import Type

private variable ℓ ℓₒ ℓₘ ℓₗₒ ℓₗₘ ℓᵣₒ ℓᵣₘ ℓₑ ℓₗₑ ℓᵣₑ : Lvl.Level
private variable Obj Objₗ Objᵣ : Type{ℓ}
private variable Morphism Morphismₗ Morphismᵣ : Objₗ → Objᵣ → Type{ℓ}

module _
  ⦃ morphism-equivₗ : ∀{x y : Objₗ} → Equiv{ℓₗₑ}(Morphismₗ x y) ⦄
  ⦃ morphism-equivᵣ : ∀{x y : Objᵣ} → Equiv{ℓᵣₑ}(Morphismᵣ x y) ⦄
  (Categoryₗ : Category(Morphismₗ))
  (Categoryᵣ : Category(Morphismᵣ))
  where

  -- A covariant functor.
  -- A mapping which transforms objects and morphisms from one category to another while "preserving" the categorical structure.
  -- A homomorphism between categories.
  -- In the context of equivalence relations instead of categories, this is the "function"/"congruence" property of the function `F`.
  record Functor (F : Objₗ → Objᵣ) : Type{Lvl.of(Type.of(Categoryₗ)) Lvl.⊔ Lvl.of(Type.of(Categoryᵣ))} where
    constructor intro
    open Category ⦃ … ⦄
    open Category.ArrowNotation ⦃ … ⦄
    private instance _ = Categoryₗ
    private instance _ = Categoryᵣ

    field
      -- Morphs/Transforms morphisms from the left category to the right category.
      -- ∀{x y : Objₗ} → (x ⟶ y) → (F(x) ⟶ F(y))
      map : Names.Subrelation(_⟶_) ((_⟶_) on₂ F)

    field
      ⦃ map-function ⦄     : ∀{x y} → Function(map{x}{y})
      ⦃ op-preserving ⦄    : ∀{x y z : Objₗ}{f : y ⟶ z}{g : x ⟶ y} → (map(f ∘ g) ≡ map(f) ∘ map(g))
      ⦃ id-preserving ⦄    : ∀{x : Objₗ} → Names.Preserving₀(map{x})(id)(id) --(map(id {x = x}) ≡ id)

    open import Structure.Categorical.Properties
    open import Structure.Function.Domain

    Faithful      = ∀{x y} → Injective (map{x}{y}) -- TODO: F also? Not sure
    Full          = ∀{x y} → Surjective(map{x}{y})
    FullyFaithful = ∀{x y} → Bijective (map{x}{y})
    -- TODO: Conservative  = ∀{x y : Objₗ}{f : x ⟶ y} → Morphism.Isomorphism(\{x} → _∘_ {x = x})(\{x} → id{x = x})(map f) → Morphism.Isomorphism(\{x} → _∘_ {x = x})(id)(f)

module _
  ⦃ morphism-equiv : ∀{x y : Obj} → Equiv{ℓₑ}(Morphism x y) ⦄
  (Category : Category(Morphism))
  where

  Endofunctor = Functor(Category)(Category)
  module Endofunctor = Functor{Categoryₗ = Category}{Categoryᵣ = Category}

_→ᶠᵘⁿᶜᵗᵒʳ_ : CategoryObject{ℓₗₒ}{ℓₗₘ}{ℓₗₑ} → CategoryObject{ℓᵣₒ}{ℓᵣₘ}{ℓᵣₑ} → Type
catₗ →ᶠᵘⁿᶜᵗᵒʳ catᵣ = ∃(Functor (CategoryObject.category(catₗ)) ((CategoryObject.category(catᵣ))))

⟲ᶠᵘⁿᶜᵗᵒʳ_ : CategoryObject{ℓₒ}{ℓₘ}{ℓₑ} → Type
⟲ᶠᵘⁿᶜᵗᵒʳ cat = cat →ᶠᵘⁿᶜᵗᵒʳ cat


module Cats.Category.Preorder where

open import Data.Unit using (⊤ ; tt)
open import Level
open import Relation.Binary as Rel
  using (Rel ; IsEquivalence ; _Preserves₂_⟶_⟶_ ; Setoid)

open import Cats.Category
open import Cats.Category.Setoids using (Setoids ; ≈-intro)
open import Cats.Util.Conv
open import Cats.Util.Function as Fun using (_on_)

module _ (lc l≈ l≤ : Level) where

  infixr 9 _∘_
  infixr 4 _≈_

  private
    module Setoids = Category (Setoids lc l≈)

  Obj : Set (suc (lc ⊔ l≈ ⊔ l≤))
  Obj = Rel.Preorder lc l≈ l≤

  Universe : Obj → Setoid lc l≈
  Universe A = record
      { Carrier = Rel.Preorder.Carrier A
      ; _≈_ = Rel.Preorder._≈_ A
      ; isEquivalence = Rel.Preorder.isEquivalence A
      }

  record _⇒_ (A B : Obj) : Set (lc ⊔ l≈ ⊔ l≤) where
    private
      module A = Rel.Preorder A
      module B = Rel.Preorder B

    field
      arr : Universe A Setoids.⇒ Universe B
      monotone : ∀ {x y} → x A.∼ y → (arr ⃗) x B.∼ (arr ⃗) y

    open Cats.Category.Setoids._⇒_ arr public using (resp)

  open _⇒_ using (monotone ; resp)

  instance
    HasArrow-⇒ : ∀ A B → HasArrow (A ⇒ B) _ _ _
    HasArrow-⇒ A B = record { Cat = Setoids lc l≈ ; _⃗ = _⇒_.arr }

  id : ∀ {A} → A ⇒ A
  id = record { arr = Setoids.id ; monotone = Fun.id }

  _∘_ : ∀ {A B C} → B ⇒ C → A ⇒ B → A ⇒ C
  g ∘ f = record
      { arr = g ⃗ Setoids.∘ f ⃗
      ; monotone = monotone g Fun.∘ monotone f
      }

  _≈_ : {A B : Obj} → Rel (A ⇒ B) (lc ⊔ l≈)
  _≈_ = Setoids._≈_ on _⃗

  instance Preorder : Category (suc (lc ⊔ l≈ ⊔ l≤)) (lc ⊔ l≈ ⊔ l≤) (lc ⊔ l≈)
  Preorder = record
      { Obj = Obj
      ; _⇒_ = _⇒_
      ; _≈_ = _≈_
      ; id = id
      ; _∘_ = _∘_
      ; equiv = Fun.on-isEquivalence _⃗ Setoids.equiv
      ; ∘-resp = Setoids.∘-resp
      ; id-r = Setoids.id-r
      ; id-l = Setoids.id-l
      ; assoc = λ { {f = f} {g} {h} → Setoids.assoc {f = f ⃗} {g ⃗} {h ⃗} }
      }

preorderAsCategory : ∀ {lc l≈ l≤} → Rel.Preorder lc l≈ l≤ → Category lc l≤ zero
preorderAsCategory P = record
    { Obj = P.Carrier
    ; _⇒_ = P._∼_
    ; _≈_ = λ _ _ → ⊤
    ; id = P.refl
    ; _∘_ = λ B≤C A≤B → P.trans A≤B B≤C
    ; equiv = record { refl = tt ; sym = λ _ → tt ; trans = λ _ _ → tt }
    ; ∘-resp = λ _ _ → tt
    ; id-r = tt
    ; id-l = tt
    ; assoc = tt
    }
  where
    module P = Rel.Preorder P


------------------------------------------------------------------------
-- The Agda standard library
--
-- Membership predicate for fresh lists
------------------------------------------------------------------------

{-# OPTIONS --without-K --safe #-}

open import Relation.Binary

module Data.List.Fresh.Membership.Setoid {c ℓ} (S : Setoid c ℓ) where

open import Level using (Level; _⊔_)
open import Data.List.Fresh
open import Data.List.Fresh.Relation.Unary.Any as Any using (Any)
open import Relation.Nullary

open Setoid S renaming (Carrier to A)

private
  variable
    r : Level

_∈_ : {R : Rel A r} → A → List# A R → Set _
x ∈ xs = Any (x ≈_) xs

_∉_ : {R : Rel A r} → A → List# A R → Set _
x ∉ xs = ¬ (x ∈ xs)


module Prelude.Ord.Reasoning where

open import Prelude.Equality
open import Prelude.Ord
open import Prelude.Function

module _ {a} {A : Set a} {{OrdA : Ord/Laws A}} where

  private
    lt/leq-trans : ∀ {x y z : A} → x < y → y ≤ z → x < z
    lt/leq-trans x<y y≤z =
      case leq-to-lteq {A = A} y≤z of λ where
        (less  y<z)  → less-trans {A = A} x<y y<z
        (equal refl) → x<y

    leq/lt-trans : ∀ {x y z : A} → x ≤ y → y < z → x < z
    leq/lt-trans x≤y y<z =
      case leq-to-lteq {A = A} x≤y of λ where
        (less  x<y)  → less-trans {A = A} x<y y<z
        (equal refl) → y<z

  data _≲_ (x y : A) : Set a where
    strict    : x < y → x ≲ y
    nonstrict : x ≤ y → x ≲ y

  module _ {x y : A} where
    OrdProof : x ≲ y → Set a
    OrdProof (strict    _) = x < y
    OrdProof (nonstrict _) = x ≤ y

    infix -1 ordProof_
    ordProof_ : (p : x ≲ y) → OrdProof p
    ordProof strict    p = p
    ordProof nonstrict p = p

  infixr 0 eqOrdStep ltOrdStep leqOrdStep
  infix  1 _∎Ord

  syntax eqOrdStep x q p = x ≡[ p ] q
  eqOrdStep : ∀ (x : A) {y z} → y ≲ z → x ≡ y → x ≲ z
  x ≡[ x=y ] strict    y<z = strict    (case x=y of λ where refl → y<z)
  x ≡[ x=y ] nonstrict y≤z = nonstrict (case x=y of λ where refl → y≤z)
    -- ^ Note: don't match on the proof here, we need to decide strict vs nonstrict for neutral proofs

  syntax eqOrdStepʳ x q p = x ≡[ p ]ʳ q
  eqOrdStepʳ : ∀ (x : A) {y z} → y ≲ z → y ≡ x → x ≲ z
  x ≡[ y=x ]ʳ strict    y<z = strict    (case y=x of λ where refl → y<z)
  x ≡[ y=x ]ʳ nonstrict y≤z = nonstrict (case y=x of λ where refl → y≤z)

  syntax ltOrdStep x q p = x <[ p ] q
  ltOrdStep : ∀ (x : A) {y z} → y ≲ z → x < y → x ≲ z
  x <[ x<y ] strict    y<z = strict (less-trans {A = A} x<y y<z)
  x <[ x<y ] nonstrict y≤z = strict (lt/leq-trans x<y y≤z)

  syntax leqOrdStep x q p = x ≤[ p ] q
  leqOrdStep : ∀ (x : A) {y z} → y ≲ z → x ≤ y → x ≲ z
  x ≤[ x≤y ] strict    y<z = strict    (leq/lt-trans x≤y y<z)
  x ≤[ x≤y ] nonstrict y≤z = nonstrict (leq-trans {A = A} x≤y y≤z)

  _∎Ord : ∀ (x : A) → x ≲ x
  x ∎Ord = nonstrict (eq-to-leq {A = A} refl)


{-# OPTIONS --without-K #-}
module NTypes.HedbergsTheorem where

open import GroupoidStructure
open import NTypes
open import NTypes.Negation
open import PathOperations
open import Transport
open import Types

stable : ∀ {a} → Set a → Set a
stable A = ¬ ¬ A → A

dec : ∀ {a} → Set a → Set a
dec A = A ⊎ ¬ A

dec→stable : ∀ {a} {A : Set a} → dec A → stable A
dec→stable {A = A} = case (λ _ → stable A)
  (λ  a   _ → a)
  (λ ¬a ¬¬a → 0-elim (¬¬a ¬a))

dec-eq : ∀ {a} → Set a → Set a
dec-eq A = (x y : A) → dec (x ≡ y)

stable-eq : ∀ {a} → Set a → Set a
stable-eq A = (x y : A) → stable (x ≡ y)

dec-eq→stable-eq : ∀ {a} {A : Set a} → dec-eq A → stable-eq A
dec-eq→stable-eq dec x y = dec→stable (dec x y)

-- Lemma 2.9.6 from HoTT book.
lemma : ∀ {a b c} {A : Set a} {B : A → Set b} {C : A → Set c}
  {x y : A} (p : x ≡ y) (f : B x → C x) (g : B y → C y) →
  tr _ p f ≡ g → (b : B x) → tr _ p (f b) ≡ g (tr _ p b)
lemma {B = B} {C = C} = J
  (λ x y p → (f : B x → C x) (g : B y → C y) →
    tr _ p f ≡ g → (b : B x) → tr _ p (f b) ≡ g (tr _ p b))
  (λ _ _ _ → happly) _ _

stable-eq→set : ∀ {a} {A : Set a} → stable-eq A → isSet A
stable-eq→set {A = A} h _ _ p q = J
  (λ x y p → (q : x ≡ y) → q ≡ p)
  K _ _ q p
  where
  K : (x : A) (p : x ≡ x) → p ≡ refl
  K x p
    = id·p _ ⁻¹
    · ap (λ z → z · p)
      (p⁻¹·p (h x x r)) ⁻¹
    · p·q·r (h x x r ⁻¹) (h x x r) p ⁻¹
    · ap (λ z → h x x r ⁻¹ · z)
      ( tr-post x p (h x x r) ⁻¹
      · lemma p (h x x) (h x x) (apd (h x) p) r
      · ap (h x x)
        (¬-isProp (tr (λ v → ¬ ¬ (x ≡ v)) p r) r)
      )
    · p⁻¹·p (h x x r)
    where
    -- Choice of r doesn't matter.
    r : ¬ ¬ (x ≡ x)
    r c = c refl


module Prelude.List where

open import Prelude.Bool
open import Prelude.Nat
open import Prelude.Fin

infixr 40 _::_

data List (A : Set) : Set where
  []   : List A
  _::_ : A -> List A -> List A

{-# BUILTIN LIST List #-}
{-# BUILTIN NIL [] #-}
{-# BUILTIN CONS _::_ #-}

infixr 30 _++_

_++_ : {A : Set} -> List A -> List A -> List A
[]        ++ ys = ys
(x :: xs) ++ ys = x :: (xs ++ ys)

snoc : {A : Set} -> List A -> A -> List A
snoc []        e = e :: []
snoc (x :: xs) e = x :: snoc xs e

length : {A : Set} -> List A -> Nat
length [] = 0
length (x :: xs) = 1 + length xs

zipWith : ∀ {A B C} -> (A -> B -> C) -> List A -> List B -> List C
zipWith f (x :: xs) (y :: ys) = f x y :: zipWith f xs ys
zipWith _ _ _ = []

map : ∀ {A B} -> (A -> B) -> List A -> List B
map _ []        = []
map f (x :: xs) = f x :: map f xs

mapIgen : ∀ {A B} -> (A -> B) -> List A -> List B
mapIgen = map

_!_ : ∀ {A} -> (xs : List A) -> Fin (length {A} xs) -> A
_!_ {A} (x :: xs) (fz .{length xs})   = x
_!_ {A} (x :: xs) (fs .{length xs} n) = _!_ {A} xs n
_!_ {A} [] ()

_[_]=_ : {A : Set} -> (xs : List A) -> Fin (length xs) -> A -> List A
(a :: as) [ fz ]= e = e :: as
(a :: as) [ fs n ]= e = a :: (as [ n ]= e)
[] [ () ]= e

listEq : {A : Set} -> (A -> A -> Bool) -> List A -> List A -> Bool
listEq _    []        [] = true
listEq _==_ (a :: as) (b :: bs) with a == b
... | true  = listEq _==_ as bs
... | false = false
listEq _ _ _ = false

tail : {A : Set} -> List A -> List A
tail [] = []
tail (x :: xs) = xs

reverse : {A : Set} -> List A -> List A
reverse [] = []
reverse (x :: xs) = reverse xs ++ (x :: [])

init : {A : Set} -> List A -> List A
init xs = reverse (tail (reverse xs))

filter : {A : Set} -> (A -> Bool) -> List A -> List A
filter p [] = []
filter p (a :: as) with p a
... | true  = a :: filter p as
... | false = filter p as


------------------------------------------------------------------------
-- The Agda standard library
--
-- Natural numbers
------------------------------------------------------------------------

module Data.Nat where

open import Function
open import Function.Equality as F using (_⟨$⟩_)
open import Function.Injection using (_↣_)
open import Data.Sum
open import Data.Empty
import Level
open import Relation.Nullary
import Relation.Nullary.Decidable as Dec
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as PropEq
  using (_≡_; refl)

------------------------------------------------------------------------
-- The types

data ℕ : Set where
  zero : ℕ
  suc  : (n : ℕ) → ℕ

{-# BUILTIN NATURAL ℕ #-}

infix 4 _≤_ _<_ _≥_ _>_ _≰_ _≮_ _≱_ _≯_

data _≤_ : Rel ℕ Level.zero where
  z≤n : ∀ {n}                 → zero  ≤ n
  s≤s : ∀ {m n} (m≤n : m ≤ n) → suc m ≤ suc n

_<_ : Rel ℕ Level.zero
m < n = suc m ≤ n

_≥_ : Rel ℕ Level.zero
m ≥ n = n ≤ m

_>_ : Rel ℕ Level.zero
m > n = n < m

_≰_ : Rel ℕ Level.zero
a ≰ b = ¬ a ≤ b

_≮_ : Rel ℕ Level.zero
a ≮ b = ¬ a < b

_≱_ : Rel ℕ Level.zero
a ≱ b = ¬ a ≥ b

_≯_ : Rel ℕ Level.zero
a ≯ b = ¬ a > b

-- The following, alternative definition of _≤_ is more suitable for
-- well-founded induction (see Induction.Nat).

infix 4 _≤′_ _<′_ _≥′_ _>′_

data _≤′_ (m : ℕ) : ℕ → Set where
  ≤′-refl :                         m ≤′ m
  ≤′-step : ∀ {n} (m≤′n : m ≤′ n) → m ≤′ suc n

_<′_ : Rel ℕ Level.zero
m <′ n = suc m ≤′ n

_≥′_ : Rel ℕ Level.zero
m ≥′ n = n ≤′ m

_>′_ : Rel ℕ Level.zero
m >′ n = n <′ m

------------------------------------------------------------------------
-- A generalisation of the arithmetic operations

fold : {a : Set} → a → (a → a) → ℕ → a
fold z s zero    = z
fold z s (suc n) = s (fold z s n)

module GeneralisedArithmetic {a : Set} (0# : a) (1+ : a → a) where

  add : ℕ → a → a
  add n z = fold z 1+ n

  mul : (+ : a → a → a) → (ℕ → a → a)
  mul _+_ n x = fold 0# (λ s → x + s) n

------------------------------------------------------------------------
-- Arithmetic

pred : ℕ → ℕ
pred zero    = zero
pred (suc n) = n

infixl 7 _*_ _⊓_
infixl 6 _+_ _+⋎_ _∸_ _⊔_

_+_ : ℕ → ℕ → ℕ
zero  + n = n
suc m + n = suc (m + n)

{-# BUILTIN NATPLUS _+_ #-}

-- Argument-swapping addition. Used by Data.Vec._⋎_.

_+⋎_ : ℕ → ℕ → ℕ
zero  +⋎ n = n
suc m +⋎ n = suc (n +⋎ m)

_∸_ : ℕ → ℕ → ℕ
m     ∸ zero  = m
zero  ∸ suc n = zero
suc m ∸ suc n = m ∸ n

{-# BUILTIN NATMINUS _∸_ #-}

_*_ : ℕ → ℕ → ℕ
zero  * n = zero
suc m * n = n + m * n

{-# BUILTIN NATTIMES _*_ #-}

-- Max.

_⊔_ : ℕ → ℕ → ℕ
zero  ⊔ n     = n
suc m ⊔ zero  = suc m
suc m ⊔ suc n = suc (m ⊔ n)

-- Min.

_⊓_ : ℕ → ℕ → ℕ
zero  ⊓ n     = zero
suc m ⊓ zero  = zero
suc m ⊓ suc n = suc (m ⊓ n)

-- Division by 2, rounded downwards.

⌊_/2⌋ : ℕ → ℕ
⌊ 0 /2⌋           = 0
⌊ 1 /2⌋           = 0
⌊ suc (suc n) /2⌋ = suc ⌊ n /2⌋

-- Division by 2, rounded upwards.

⌈_/2⌉ : ℕ → ℕ
⌈ n /2⌉ = ⌊ suc n /2⌋

------------------------------------------------------------------------
-- Queries

infix 4 _≟_

_≟_ : Decidable {A = ℕ} _≡_
zero  ≟ zero   = yes refl
suc m ≟ suc n  with m ≟ n
suc m ≟ suc .m | yes refl = yes refl
suc m ≟ suc n  | no prf   = no (prf ∘ PropEq.cong pred)
zero  ≟ suc n  = no λ()
suc m ≟ zero   = no λ()

≤-pred : ∀ {m n} → suc m ≤ suc n → m ≤ n
≤-pred (s≤s m≤n) = m≤n

_≤?_ : Decidable _≤_
zero  ≤? _     = yes z≤n
suc m ≤? zero  = no λ()
suc m ≤? suc n with m ≤? n
...            | yes m≤n = yes (s≤s m≤n)
...            | no  m≰n = no  (m≰n ∘ ≤-pred)

-- A comparison view. Taken from "View from the left"
-- (McBride/McKinna); details may differ.

data Ordering : Rel ℕ Level.zero where
  less    : ∀ m k → Ordering m (suc (m + k))
  equal   : ∀ m   → Ordering m m
  greater : ∀ m k → Ordering (suc (m + k)) m

compare : ∀ m n → Ordering m n
compare zero    zero    = equal   zero
compare (suc m) zero    = greater zero m
compare zero    (suc n) = less    zero n
compare (suc m) (suc n) with compare m n
compare (suc .m)           (suc .(suc m + k)) | less    m k = less    (suc m) k
compare (suc .m)           (suc .m)           | equal   m   = equal   (suc m)
compare (suc .(suc m + k)) (suc .m)           | greater m k = greater (suc m) k

-- If there is an injection from a type to ℕ, then the type has
-- decidable equality.

eq? : ∀ {a} {A : Set a} → A ↣ ℕ → Decidable {A = A} _≡_
eq? inj = Dec.via-injection inj _≟_

------------------------------------------------------------------------
-- Some properties

decTotalOrder : DecTotalOrder _ _ _
decTotalOrder = record
  { Carrier         = ℕ
  ; _≈_             = _≡_
  ; _≤_             = _≤_
  ; isDecTotalOrder = record
      { isTotalOrder = record
          { isPartialOrder = record
              { isPreorder = record
                  { isEquivalence = PropEq.isEquivalence
                  ; reflexive     = refl′
                  ; trans         = trans
                  }
              ; antisym  = antisym
              }
          ; total = total
          }
      ; _≟_  = _≟_
      ; _≤?_ = _≤?_
      }
  }
  where
  refl′ : _≡_ ⇒ _≤_
  refl′ {zero}  refl = z≤n
  refl′ {suc m} refl = s≤s (refl′ refl)

  antisym : Antisymmetric _≡_ _≤_
  antisym z≤n       z≤n       = refl
  antisym (s≤s m≤n) (s≤s n≤m) with antisym m≤n n≤m
  ...                         | refl = refl

  trans : Transitive _≤_
  trans z≤n       _         = z≤n
  trans (s≤s m≤n) (s≤s n≤o) = s≤s (trans m≤n n≤o)

  total : Total _≤_
  total zero    _       = inj₁ z≤n
  total _       zero    = inj₂ z≤n
  total (suc m) (suc n) with total m n
  ...                   | inj₁ m≤n = inj₁ (s≤s m≤n)
  ...                   | inj₂ n≤m = inj₂ (s≤s n≤m)

import Relation.Binary.PartialOrderReasoning as POR
module ≤-Reasoning where
  open POR (DecTotalOrder.poset decTotalOrder) public
    renaming (_≈⟨_⟩_ to _≡⟨_⟩_)

  infixr 2 _<⟨_⟩_

  _<⟨_⟩_ : ∀ x {y z} → x < y → y IsRelatedTo z → suc x IsRelatedTo z
  x <⟨ x<y ⟩ y≤z = suc x ≤⟨ x<y ⟩ y≤z