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

module Categories.Adjoint.Alternatives where

open import Level

open import Categories.Adjoint
open import Categories.Category
open import Categories.Functor renaming (id to idF)
open import Categories.NaturalTransformation

import Categories.Morphism.Reasoning as MR

private
  variable
    o ℓ e : Level
    C D   : Category o ℓ e

  module _ (L : Functor C D) (R : Functor D C) where
    private
      module C = Category C
      module D = Category D
      module L = Functor L
      module R = Functor R

    record FromUnit : Set (levelOfTerm L ⊔ levelOfTerm R) where

      field
        unit : NaturalTransformation idF (R ∘F L)

      module unit = NaturalTransformation unit

      field
        θ       : ∀ {X Y} → C [ X , R.₀ Y ] → D [ L.₀ X , Y ]
        commute : ∀ {X Y} (g : C [ X , R.₀ Y ]) → g C.≈ R.₁ (θ g) C.∘ unit.η X
        unique  : ∀ {X Y} {f : D [ L.₀ X , Y ]} {g : C [ X , R.₀ Y ]} →
                    g C.≈ R.₁ f C.∘ unit.η X → θ g D.≈ f

      module _ where
        open C.HomReasoning
        open MR C

        θ-natural : ∀ {X Y Z} (f : D [ Y , Z ]) (g : C [ X , R.₀ Y ]) → θ (R.₁ f C.∘ g) D.≈ θ (R.₁ f) D.∘ L.₁ g
        θ-natural {X} {Y} f g = unique eq
          where eq : R.₁ f C.∘ g C.≈ R.₁ (θ (R.₁ f) D.∘ L.₁ g) C.∘ unit.η X
                eq = begin
                  R.₁ f C.∘ g                                      ≈⟨ commute (R.₁ f) ⟩∘⟨refl ⟩
                  (R.₁ (θ (R.₁ f)) C.∘ unit.η (R.F₀ Y)) C.∘ g    ≈⟨ C.assoc ⟩
                  R.₁ (θ (R.₁ f)) C.∘ unit.η (R.₀ Y) C.∘ g       ≈⟨ pushʳ (unit.commute g) ⟩
                  (R.₁ (θ (R.₁ f)) C.∘ R.₁ (L.₁ g)) C.∘ unit.η X ≈˘⟨ R.homomorphism ⟩∘⟨refl ⟩
                  R.₁ (θ (R.₁ f) D.∘ L.₁ g) C.∘ unit.η X         ∎

        θ-cong : ∀ {X Y} {f g : C [ X , R.₀ Y ]} → f C.≈ g → θ f D.≈ θ g
        θ-cong eq = unique (eq ○ commute _)

      θ-natural′ : ∀ {X Y} (g : C [ X , R.₀ Y ]) → θ g D.≈ θ C.id D.∘ L.₁ g
      θ-natural′ g = θ-cong (introˡ R.identity) ○ θ-natural D.id g ○ D.∘-resp-≈ˡ (θ-cong R.identity)
        where open D.HomReasoning
              open MR C

      counit : NaturalTransformation (L ∘F R) idF
      counit = ntHelper record
        { η       = λ d → θ C.id
        ; commute = λ f → begin
          θ C.id D.∘ L.₁ (R.₁ f) ≈˘⟨ θ-natural′ (R.₁ f) ⟩
          θ (R.₁ f)              ≈⟨ unique (CH.⟺ (MR.cancelʳ C (CH.⟺ (commute C.id))) CH.○ CH.⟺ (C.∘-resp-≈ˡ R.homomorphism)) ⟩
          f D.∘ θ C.id           ∎
        }
        where open D.HomReasoning
              module CH = C.HomReasoning

      unique′ : ∀ {X Y} {f g : D [ L.₀ X , Y ]} (h : C [ X , R.₀ Y ]) →
                  h C.≈ R.₁ f C.∘ unit.η X →
                  h C.≈ R.₁ g C.∘ unit.η X → f D.≈ g
      unique′ _ eq₁ eq₂ = ⟺ (unique eq₁) ○ unique eq₂
        where open D.HomReasoning

      zig : ∀ {A} → θ C.id D.∘ L.F₁ (unit.η A) D.≈ D.id
      zig {A} = unique′ (unit.η A)
                        (commute (unit.η A) ○ (C.∘-resp-≈ˡ (R.F-resp-≈ (θ-natural′ (unit.η A)))))
                        (introˡ R.identity)
        where open C.HomReasoning
              open MR C

      L⊣R : L ⊣ R
      L⊣R = record
        { unit   = unit
        ; counit = counit
        ; zig    = zig
        ; zag    = C.Equiv.sym (commute C.id)
        }

    record FromCounit : Set (levelOfTerm L ⊔ levelOfTerm R) where

      field
        counit : NaturalTransformation (L ∘F R) idF

      module counit = NaturalTransformation counit

      field
        θ       : ∀ {X Y} → D [ L.₀ X , Y ] → C [ X , R.₀ Y ]
        commute : ∀ {X Y} (g : D [ L.₀ X , Y ]) → g D.≈ counit.η Y D.∘ L.₁ (θ g)
        unique  : ∀ {X Y} {f : C [ X , R.₀ Y ]} {g : D [ L.₀ X , Y ]} →
                    g D.≈ counit.η Y D.∘ L.₁ f → θ g C.≈ f

      module _ where
        open D.HomReasoning
        open MR D

        θ-natural : ∀ {X Y Z} (f : C [ X , Y ]) (g : D [ L.₀ Y , Z ]) → θ (g D.∘ L.₁ f) C.≈ R.₁ g C.∘ θ (L.₁ f)
        θ-natural {X} {Y} {Z} f g = unique eq
          where eq : g D.∘ L.₁ f D.≈ counit.η Z D.∘ L.₁ (R.₁ g C.∘ θ (L.₁ f))
                eq = begin
                  g D.∘ L.₁ f                                     ≈⟨ pushʳ (commute (L.₁ f)) ⟩
                  (g D.∘ counit.η (L.F₀ Y)) D.∘ L.F₁ (θ (L.F₁ f)) ≈⟨ pushˡ (counit.sym-commute g) ⟩
                  counit.η Z D.∘ L.₁ (R.₁ g) D.∘ L.₁ (θ (L.₁ f))  ≈˘⟨ refl⟩∘⟨ L.homomorphism ⟩
                  counit.η Z D.∘ L.₁ (R.₁ g C.∘ θ (L.₁ f))        ∎

        θ-cong : ∀ {X Y} {f g : D [ L.₀ X , Y ]} → f D.≈ g → θ f C.≈ θ g
        θ-cong eq = unique (eq ○ commute _)

      θ-natural′ : ∀ {X Y} (g : D [ L.₀ X , Y ]) → θ g C.≈ R.₁ g C.∘ θ D.id
      θ-natural′ g = θ-cong (introʳ L.identity) ○ θ-natural C.id g ○ C.∘-resp-≈ʳ (θ-cong L.identity)
        where open C.HomReasoning
              open MR D

      unit : NaturalTransformation idF (R ∘F L)
      unit = ntHelper record
        { η       = λ _ → θ D.id
        ; commute = λ f → begin
          θ D.id C.∘ f           ≈˘⟨ unique (DH.⟺ (cancelˡ (DH.⟺ (commute D.id))) DH.○ D.∘-resp-≈ʳ (DH.⟺ L.homomorphism)) ⟩
          θ (L.₁ f)              ≈⟨ θ-natural′ (L.₁ f) ⟩
          R.₁ (L.₁ f) C.∘ θ D.id ∎
        }
        where open C.HomReasoning
              module DH = D.HomReasoning
              open MR D

      unique′ : ∀ {X Y} {f g : C [ X , R.₀ Y ]} (h : D [ L.₀ X , Y ]) →
                  h D.≈ counit.η Y D.∘ L.₁ f →
                  h D.≈ counit.η Y D.∘ L.₁ g →
                  f C.≈ g
      unique′ _ eq₁ eq₂ = ⟺ (unique eq₁) ○ unique eq₂
        where open C.HomReasoning

      zag : ∀ {B} → R.F₁ (counit.η B) C.∘ θ D.id C.≈ C.id
      zag {B} = unique′ (counit.η B)
                        (⟺ (cancelʳ (⟺ (commute D.id))) ○ pushˡ (counit.sym-commute (counit.η B)) ○ D.∘-resp-≈ʳ (⟺ L.homomorphism))
                        (introʳ L.identity)
        where open D.HomReasoning
              open MR D

      L⊣R : L ⊣ R
      L⊣R = record
        { unit   = unit
        ; counit = counit
        ; zig    = D.Equiv.sym (commute D.id)
        ; zag    = zag
        }

module _ {L : Functor C D} {R : Functor D C} where

  fromUnit : FromUnit L R → L ⊣ R
  fromUnit = FromUnit.L⊣R

  fromCounit : FromCounit L R → L ⊣ R
  fromCounit = FromCounit.L⊣R


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

open import Base
open import Integers
open import Homotopy.Truncation
open import Spaces.Spheres
open import Spaces.Suspension
open import Homotopy.Connected
open import Homotopy.ConnectedSuspension
open import Homotopy.Pointed
open import Homotopy.HomotopyGroups

module Spaces.PikSn where

abstract
  Sⁿ-S-is-connected : (n : ℕ) → is-connected ⟨ n ⟩ (Sⁿ (S n))
  Sⁿ-S-is-connected n =
    suspension-is-connected-S (Sⁿ n) ind-hyp (proj (⋆Sⁿ n)) where
      ind-hyp : is-connected (n -1) (Sⁿ n)
      ind-hyp with n
      ind-hyp | O = inhab-prop-is-contr (proj true) (τ-is-truncated _ _)
      ind-hyp | S n = Sⁿ-S-is-connected n

Sⁿ⋆ : (n : ℕ) → pType₀
Sⁿ⋆ n = ⋆[ Sⁿ n , ⋆Sⁿ n ]

abstract
  πk-Sⁿ-is-contr : (k n : ℕ) (lt : k < n)
    → is-contr⋆ (πⁿ k (Sⁿ⋆ n))
  πk-Sⁿ-is-contr k O ()
  πk-Sⁿ-is-contr k (S n) lt = connected-πⁿ k n lt _ (Sⁿ-S-is-connected n)


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

{-
  Ribbon is an explicit covering space construction.

  This construction is given by Daniel Grayson, Favonia
  and Guillaume Brunerie together.
-}

open import HoTT

-- A is the pointed base space.
-- El is intended to be a (group-)set,
module homotopy.RibbonCover {i : ULevel} where

  -- The HIT ribbon---reconstructed covering space

  module _ (X : Ptd i) {j} (gs : GroupSet (πS 0 X) j) (a₂ : de⊙ X) where
    private
      A = de⊙ X
      a₁ = pt X
      El = GroupSet.El gs
      El-level = GroupSet.El-level gs
      infix 80 _⊙_
      _⊙_ = GroupSet.act gs

    RibbonSet : Type (lmax i j)
    RibbonSet = El × (a₁ =₀ a₂)

    data RibbonRel : RibbonSet → RibbonSet → Type (lmax i j) where
      ribbon-rel : ∀ el loop (p : a₁ =₀ a₂)
        → RibbonRel (el ⊙ loop , p) (el , loop ∙₀ p)

    Ribbon : Type (lmax i j)
    Ribbon = SetQuot RibbonRel

  module _ {X : Ptd i} {j} {gs : GroupSet (πS 0 X) j} {a₂ : de⊙ X} where
    private
      A = de⊙ X
      a = pt X
      El = GroupSet.El gs
      El-level = GroupSet.El-level gs
      infix 80 _⊙_
      _⊙_ = GroupSet.act gs

    -- A point in the fiber [a₂].
    {-
      [e] is a point in the [fiber a], and
      [p] is a path to transport [y] to fiber [a₂].
    -}
    trace : El → a =₀ a₂ → Ribbon X gs a₂
    trace el p = q[ el , p ]

    {-
      A loop based at [a] can used as a group action
      or for concatination.  Both should be equivalent.
    -}
    paste : ∀ el loop (p : a =₀ a₂) → trace (el ⊙ loop) p == trace el (loop ∙₀ p)
    paste el loop p = quot-rel (ribbon-rel el loop p)

    {-
      Make each fiber a set and cancel all higher structures
      due to [paste].
    -}
    Ribbon-level : is-set (Ribbon X gs a₂)
    Ribbon-level = SetQuot-level

    Ribbon-is-set = Ribbon-level

    -- Elimination rules.
    module RibbonElim {j} {P : Ribbon X gs a₂ → Type j}
      (P-level : ∀ r → is-set (P r))
      (trace* : ∀ el p → P (trace el p))
      (paste* : ∀ el loop p
                → trace* (el ⊙ loop) p == trace* el (loop ∙₀ p)
                  [ P ↓ paste el loop p ]) where

      private
        q[_]* : (α : RibbonSet X gs a₂) → P q[ α ]
        q[ el , p ]* = trace* el p

        rel* : ∀ {α₁ α₂} (r : RibbonRel X gs a₂ α₁ α₂) → q[ α₁ ]* == q[ α₂ ]* [ P ↓ quot-rel r ]
        rel* (ribbon-rel el loop p) = paste* el loop p

        module M = SetQuotElim P-level q[_]* rel*

      f : Π (Ribbon X gs a₂) P
      f = M.f

    open RibbonElim public using () renaming (f to Ribbon-elim)

    module RibbonRec {j} {P : Type j}
      (P-level : is-set P)
      (trace* : ∀ el p → P)
      (paste* : ∀ el loop p
                → trace* (el ⊙ loop) p == trace* el (loop ∙₀ p)) where

      private
        module M = RibbonElim (λ _ → P-level) trace*
          (λ el loop p → ↓-cst-in (paste* el loop p))

      f : Ribbon X gs a₂ → P
      f = M.f

    open RibbonRec public using () renaming (f to Ribbon-rec)

  -- This data structure gives a cover.
  Ribbon-cover : ∀ (X : Ptd i) {j} (gs : GroupSet (πS 0 X) j)
    → Cover (de⊙ X) (lmax i j)
  Ribbon-cover X gs = record
    { Fiber = Ribbon X gs
    ; Fiber-level = λ a → Ribbon-level
    }

  transp-trace : ∀ {A : Type i} {a₁} {j}
    {gs : GroupSet (πS 0 ⊙[ A , a₁ ]) j}
    {a₂} (q : a₁ == a₂) y p
    → transport (Ribbon ⊙[ A , a₁ ] gs) q (trace y p) == trace y (p ∙₀ [ q ])
  transp-trace idp y p = ap (trace y) $ ! $ ∙₀-unit-r p


open import SOAS.Common
open import SOAS.Families.Core

-- Algebras for a signature endofunctor
module SOAS.Metatheory.Algebra {T : Set} (⅀F : Functor (𝔽amiliesₛ {T}) (𝔽amiliesₛ {T})) where

module ⅀ = Functor ⅀F

⅀ : Familyₛ → Familyₛ
⅀ = ⅀.₀

⅀₁ : {𝒳 𝒴 : Familyₛ} → 𝒳 ⇾̣ 𝒴 → ⅀ 𝒳 ⇾̣ ⅀ 𝒴
⅀₁ = Functor.₁ ⅀F


module Section3 where

open import Section1 public

-- 3. The calculus of proof trees
-- ==============================
--
-- We define the set of proof trees of implicational logic in the ordinary style à la Church,
-- except that we use explicit substitutions.

-- 3.1. Definition of types
-- ------------------------
--
-- The types we have are base type and function types.  The set of types `𝒯 : Set` is introduced
-- by:

infixr 7 _⊃_
data 𝒯 : Set where
  •   : 𝒯
  _⊃_ : 𝒯 → 𝒯 → 𝒯

-- Types are denoted by `A`, `B`.  (…)
--
-- We write `•` for the base type and `A ⊃ B` for the function type.

module _ where
  inj₁⊃ : ∀ {A A′ B B′} → A ⊃ B ≡ A′ ⊃ B′ → A ≡ A′
  inj₁⊃ refl = refl

  inj₂⊃ : ∀ {A A′ B B′} → A ⊃ B ≡ A′ ⊃ B′ → B ≡ B′
  inj₂⊃ refl = refl

  _≟𝒯_ : (A A′ : 𝒯) → Dec (A ≡ A′)
  •       ≟𝒯 •         = yes refl
  •       ≟𝒯 (A′ ⊃ B′) = no λ ()
  (A ⊃ B) ≟𝒯 •         = no λ ()
  (A ⊃ B) ≟𝒯 (A′ ⊃ B′) with A ≟𝒯 A′ | B ≟𝒯 B′
  …                   | yes refl | yes refl = yes refl
  …                   | yes refl | no B≢B′  = no (λ p → inj₂⊃ p ↯ B≢B′)
  …                   | no A≢A′  | _        = no (λ p → inj₁⊃ p ↯ A≢A′)

-- 3.2. Definition of contexts
-- ---------------------------
--
-- Suppose a countably infinite set, `Name`, with names together with a decidable equality on it.
-- The set of contexts `𝒞` is mutually defined with a boolean-valued function `fresh` which describes
-- when a name is fresh in a context.  (…)
--
-- Ordinarily, the freshness condition is written as a side-condition, but since we are to
-- formalise the proof trees, this information must be represented, too.
--
-- We write `[]` for the empty context and `[ Γ , x ∷ A ]` for adding an element to a context,
-- hence when we write `[ Γ , x ∷ A ]`
-- it is implicit that we also have a proof that `x` is fresh in `Γ` (when `[ Γ , x ∷ A ]` occurs in the
-- conclusion of a statement, then it is implicit that `T (fresh x Γ)` is an assumption.)  The
-- function `fresh` is defined by induction on the context as:

mutual
  data 𝒞 : Set where
    []      : 𝒞
    [_,_∷_] : (Γ : 𝒞) (x : Name) {{_ : T (fresh x Γ)}} → 𝒯 → 𝒞

  fresh : Name → 𝒞 → Bool
  fresh x []            = true
  fresh x [ Γ , y ∷ A ] = and (x ≠ y) (fresh x Γ)

-- We use `Γ`, `Δ` and `Θ` for contexts.
--
-- The predicate `Γ ∋ x ∷ A` is true when a name with its type occurs in a context.
--
-- The introduction rules are:

data _∋_∷_ : 𝒞 → Name → 𝒯 → Set where
  zero : ∀ {Γ A x} {{_ : T (fresh x Γ)}} →
           [ Γ , x ∷ A ] ∋ x ∷ A
  suc  : ∀ {Γ A B x y} {{_ : T (fresh y Γ)}} →
           Γ ∋ x ∷ A →
           [ Γ , y ∷ B ] ∋ x ∷ A

module _ where
  injsuc : ∀ {Γ A B x y} {{_ : T (fresh y Γ)}} {i i′ : Γ ∋ x ∷ A} →
             suc {B = B} {y = y} i ≡ suc i′ → i ≡ i′
  injsuc refl = refl

  _≟∋_ : ∀ {Γ A x} → (i i′ : Γ ∋ x ∷ A) → Dec (i ≡ i′)
  zero  ≟∋ zero   = yes refl
  zero  ≟∋ suc i′ = no (λ ())
  suc i ≟∋ zero   = no (λ ())
  suc i ≟∋ suc i′ with i ≟∋ i′
  …              | yes refl = yes refl
  …              | no i≢i′  = no (λ p → injsuc p ↯ i≢i′)

module _ where
  _∌_∷_ : 𝒞 → Name → 𝒯 → Set
  Γ ∌ x ∷ A = ¬ (Γ ∋ x ∷ A)

  fresh→∌ : ∀ {x Γ A} {{_ : T (fresh x Γ)}} → Γ ∌ x ∷ A
  fresh→∌ {x} {{φ}}  zero             with x ≟ x
  fresh→∌ {x} {{()}} zero             | yes refl
  fresh→∌ {x} {{φ}}  zero             | no x≢x   = refl ↯ x≢x
  fresh→∌ {x} {{φ}}  (suc {y = y}  i) with x ≟ y
  fresh→∌ {x} {{()}} (suc {y = .x} i) | yes refl
  fresh→∌ {x} {{φ}}  (suc {y = y}  i) | no x≢y   = i ↯ fresh→∌

  freshlem₁ : ∀ {b′} → (x : Name) → ¬ (T (and (x ≠ x) b′))
  freshlem₁ x p with x ≟ x
  …            | yes refl = p
  …            | no x≢x   = refl ↯ x≢x

  freshlem₂ : ∀ {b′} → (x {y} : Name) → T (and (x ≠ y) b′) → T b′
  freshlem₂ x {y} p with x ≟ y
  …              | yes refl = elim⊥ p
  …              | no x≢y   = p

-- We also define the relation that describes when a context contains another.
--
-- We use the notational convention `Γ ⊇ Δ` for `Γ` being greater than `Δ`.
-- The set `_⊇_` has the constructors:

infix 3 _⊇_
data _⊇_ : 𝒞 → 𝒞 → Set where
  done : ∀ {Γ} →
           Γ ⊇ []
  step : ∀ {Γ Δ A x} {{_ : T (fresh x Δ)}} →
           Γ ⊇ Δ → Γ ∋ x ∷ A →
           Γ ⊇ [ Δ , x ∷ A ]

module _ where
  inj₁step : ∀ {Γ Δ A x} {{_ : T (fresh x Δ)}} {c c′ : Γ ⊇ Δ} {i i′ : Γ ∋ x ∷ A} →
               step c i ≡ step c′ i′ → c ≡ c′
  inj₁step refl = refl

  inj₂step : ∀ {Γ Δ A x} {{_ : T (fresh x Δ)}} {c c′ : Γ ⊇ Δ} {i i′ : Γ ∋ x ∷ A} →
               step c i ≡ step c′ i′ → i ≡ i′
  inj₂step refl = refl

  _≟⊇_ : ∀ {Γ Δ} → (c c′ : Γ ⊇ Δ) → Dec (c ≡ c′)
  done     ≟⊇ done       = yes refl
  step c i ≟⊇ step c′ i′ with c ≟⊇ c′ | i ≟∋ i′
  …                     | yes refl | yes refl = yes refl
  …                     | yes refl | no i≢i′  = no (λ p → inj₂step p ↯ i≢i′)
  …                     | no c≢c′  | _        = no (λ p → inj₁step p ↯ c≢c′)

-- The following lemmas are easy to prove:

-- Lemma 1.
ext⊇ : ∀ {Δ Γ} → (∀ {A x} → Δ ∋ x ∷ A → Γ ∋ x ∷ A) → Γ ⊇ Δ
ext⊇ {[]}            f = done
ext⊇ {[ Δ , x ∷ A ]} f = step (ext⊇ (λ i → f (suc i))) (f zero)

-- Lemma 2.
module _ where
  ↑⟨_⟩∋ : ∀ {Γ Δ A x} → Δ ⊇ Γ → Γ ∋ x ∷ A → Δ ∋ x ∷ A
  ↑⟨ done ⟩∋     ()
  ↑⟨ step c i ⟩∋ zero    = i
  ↑⟨ step c i ⟩∋ (suc j) = ↑⟨ c ⟩∋ j

  instance
    raise∋ : ∀ {A x} → Raiseable (_∋ x ∷ A)
    raise∋ = record { ↑⟨_⟩ = ↑⟨_⟩∋ }

-- Lemma 3.
refl⊇ : ∀ {Γ} → Γ ⊇ Γ
refl⊇ = ext⊇ id

-- Lemma 4.
module _ where
  _○_ : ∀ {Γ Δ Θ} → Γ ⊇ Δ → Θ ⊇ Γ → Θ ⊇ Δ
  c ○ c′ = ext⊇ (λ i → ↑⟨ c′ ⟩ (↑⟨ c ⟩ i))

  trans⊇ : ∀ {Γ Δ Θ} → Θ ⊇ Γ → Γ ⊇ Δ → Θ ⊇ Δ
  trans⊇ = flip _○_

-- Lemma 5.
weak⊇ : ∀ {Γ A x} {{_ : T (fresh x Γ)}} → [ Γ , x ∷ A ] ⊇ Γ
weak⊇ = ext⊇ suc

-- Lemma 6.
uniq∋ : ∀ {Γ A x} → (i i′ : Γ ∋ x ∷ A) → i ≡ i′
uniq∋ zero    zero     = refl
uniq∋ zero    (suc i′) = i′ ↯ fresh→∌
uniq∋ (suc i) zero     = i ↯ fresh→∌
uniq∋ (suc i) (suc i′) = cong suc (uniq∋ i i′)

-- Lemma 7.
uniq⊇ : ∀ {Γ Δ} → (c c′ : Γ ⊇ Δ) → c ≡ c′
uniq⊇ done       done         = refl
uniq⊇ (step c i) (step c′ i′) = cong² step (uniq⊇ c c′) (uniq∋ i i′)

-- `ext⊇`, `↑⟨_⟩∋` and `uniq⊇` are proven by induction on `Δ` and `uniq∋` is proven by
-- induction on `Γ`.  `refl⊇` and `weak⊇` are direct consequences of `ext⊇` and for `trans⊇`
-- we also use `↑⟨_⟩∋`.  (…)
--
-- The last two lemmas may seem slightly strange: they are used for guaranteeing independence
-- of the proofs of `_∋_∷_` and `_⊇_`.  For example, `uniq∋` says that if it can be shown that
-- `x ∷ A` occurs in a context `Γ`, then there is a unique proof of this fact.  The need to prove
-- independence of proofs might point to a problem in using type theory for formalising proofs.  On
-- the other hand, as we shall see, proof objects can also be useful: the present formalisation
-- heavily uses the possibilities to perform case analysis on proof objects, which reduces the
-- number of cases to consider.

module _ where
  id₁○ : ∀ {Γ Δ} → (c : Γ ⊇ Γ) (c′ : Δ ⊇ Γ) → c ○ c′ ≡ c′
  id₁○ c c′ = uniq⊇ (c ○ c′) c′

  id₂○ : ∀ {Γ Δ} → (c : Δ ⊇ Γ) (c′ : Δ ⊇ Δ) → c ○ c′ ≡ c
  id₂○ c c′ = uniq⊇ (c ○ c′) c

  assoc○ : ∀ {Γ Δ Θ Ω} → (c : Δ ⊇ Γ) (c′ : Θ ⊇ Δ) (c″ : Ω ⊇ Θ) →
             c ○ (c′ ○ c″) ≡ (c ○ c′) ○ c″
  assoc○ c c′ c″ = uniq⊇ (c ○ (c′ ○ c″)) ((c ○ c′) ○ c″)

  comp○ : ∀ {Γ Δ Θ} → (c : Δ ⊇ Γ) (c′ : Θ ⊇ Δ) (c″ : Θ ⊇ Γ) →
            c ○ c′ ≡ c″
  comp○ c c′ c″ = uniq⊇ (c ○ c′) c″

-- 3.3. Definition of proof trees
-- ------------------------------
--
-- Proof trees and substitutions are mutually inductively defined.  (…)
--
-- We use the notational convention `Γ ⊢ A` and `Δ ⋙ Γ` for a proof of `A` in context `Γ` and
-- a substitution of `Γ` by `Δ`, respectively.
--
-- A substitution of type `Δ ⋙ Γ` intuitively is a list that associates to each `x ∷ A` in `Γ` a unique
-- proof tree of type `Δ ⊢ A`.
--
-- The proof trees are defined by the following rules.
--
-- We recall that hidden assumptions in the definition above are implicitly universally defined
-- and that the notation `[ Γ , x ∷ A ]` implies that `x` is fresh in `Γ`.  (…)
--
-- In the definition of variables we can see that a proof of occurrence is part of the proof
-- tree.  The advantage is that we can do case-analysis on this proof to find out where in the
-- context `x ∷ A` occurs.  The disadvantage is that we need to prove that two variables are the
-- same even if they have two possibly different proofs of occurrence of `x ∷ A` (by Lemma 6 we
-- know that the proofs are the same).

mutual
  infix 3 _⊢_
  data _⊢_ : 𝒞 → 𝒯 → Set where
    ν   : ∀ {Γ A} →
            (x : Name) → Γ ∋ x ∷ A →
            Γ ⊢ A
    ƛ   : ∀ {Γ A B} →
            (x : Name) {{_ : T (fresh x Γ)}} → [ Γ , x ∷ A ] ⊢ B →
            Γ ⊢ A ⊃ B
    _∙_ : ∀ {Γ A B} →
            Γ ⊢ A ⊃ B → Γ ⊢ A →
            Γ ⊢ B
    _▶_ : ∀ {Γ Δ A} →
            Γ ⊢ A → Δ ⋙ Γ →
            Δ ⊢ A

  infix 3 _⋙_
  data _⋙_ : 𝒞 → 𝒞 → Set where
    π⟨_⟩    : ∀ {Γ Δ} →
                Δ ⊇ Γ →
                Δ ⋙ Γ
    _●_     : ∀ {Γ Δ Θ} →
                Γ ⋙ Δ → Θ ⋙ Γ →
                Θ ⋙ Δ
    [_,_≔_] : ∀ {Γ Δ A} →
                Δ ⋙ Γ → (x : Name) {{_ : T (fresh x Γ)}} → Δ ⊢ A →
                Δ ⋙ [ Γ , x ∷ A ]

-- Explicit substitutions are built from a projection map, update and composition (see below
-- for a discussion on the projection map).
--
-- We use the following notational conventions:
--
-- -   `ν x`           for referencing the occurrence `x`, where `x : Γ ∋ x ∷ A`
-- -   `M ▶ γ`         for applying the substitution `γ` to the term `M`
-- -   `ƛ x M`         for abstracting the occurrence `x` from the term `M`, where `M : [ Γ , x ∷ A ] ⊢ B`
-- -   `M ∙ N`         for applying the term `M` to the term `N`
-- -   `π⟨ c ⟩`        for projecting the inclusion `c` as a substitution
-- -   `[ γ , x ≔ M ]` for updating the substitution `γ` with the term `M` for the occurrence `x`
-- -   `γ ● δ`         for composing the substitution `δ` with the substitution `γ`
--
-- Proof trees and substitutions are named `M, N` and `γ, δ, θ` respectively.
--
-- The substitution `π⟨_⟩` is not a standard primitive for explicit substitutions.  Often one rather
-- has an identity substitution (in `Γ ⋙ Γ`) [1, 13] or the empty substitution (in `Γ ⋙ []`) [5].
-- Instead we have taken `π⟨_⟩` as primitive.  If `c : Γ ⊇ Γ`, then `π⟨ c ⟩` is the identity substitution and
-- if `c : Γ ⊇ []`, then `π⟨ c ⟩` is the empty substitution.  Abadi et al. [1] use a substitution `↑` that
-- corresponds to a shift on substitutions; the same substitution is here defined as `π⟨ c ⟩` where
-- `c : [ Γ , x ∷ A ] ⊇ Γ`.  In Martin-Löf’s substitution calculus [13, 20] we have as primitives also
-- thinning rules (i.e., if a term is well-typed in a given context, then it is also well-typed in a
-- larger context and likewise for substitutions.)  Here, thinning is achieved using `π⟨_⟩`, since if,
-- for example, `M : Γ ⊢ A` and `c : Δ ⊇ Γ`, then `M ▶ π⟨ c ⟩ : Δ ⊢ A`.
--
-- The first version of our work used combinators for the thinning rules, since we wanted it to
-- be a start for a complete mechanical analysis of Martin-Löf’s substitution calculus [13, 20].
-- The set of conversion rules we obtained using these combinators suggested the use of `π⟨_⟩`,
-- which gives fewer conversion rules.  There might be other advantages in using `π⟨_⟩`: if a proof
-- tree is of the form `M ▶ π⟨_⟩` we know which are the possible free variables of the term `M`,
-- information that might be used in a computation.

module _ where
  ↑⟨_⟩⊢ : ∀ {Γ Δ A} → Δ ⊇ Γ → Γ ⊢ A → Δ ⊢ A
  ↑⟨ c ⟩⊢ M = M ▶ π⟨ c ⟩

  ↑⟨_⟩⋙ : ∀ {Γ Δ Θ} → Δ ⊇ Γ → Γ ⋙ Θ → Δ ⋙ Θ
  ↑⟨ c ⟩⋙ δ = δ ● π⟨ c ⟩

  ↓⟨_⟩⋙ : ∀ {Γ Δ Θ} → Δ ⊇ Γ → Θ ⋙ Δ → Θ ⋙ Γ
  ↓⟨ c ⟩⋙ δ = π⟨ c ⟩ ● δ

  refl⋙ : ∀ {Γ} → Γ ⋙ Γ
  refl⋙ = π⟨ refl⊇ ⟩

  trans⋙ : ∀ {Γ Δ Θ} → Θ ⋙ Γ → Γ ⋙ Δ → Θ ⋙ Δ
  trans⋙ = flip _●_

  weak⋙ : ∀ {Γ A x} {{_ : T (fresh x Γ)}} → [ Γ , x ∷ A ] ⋙ Γ
  weak⋙ = π⟨ weak⊇ ⟩

  instance
    raise⊢ : ∀ {A} → Raiseable (_⊢ A)
    raise⊢ = record { ↑⟨_⟩ = ↑⟨_⟩⊢ }

    raise⋙ : ∀ {Γ} → Raiseable (_⋙ Γ)
    raise⋙ = record { ↑⟨_⟩ = ↑⟨_⟩⋙ }

    lower⋙ : ∀ {Δ} → Lowerable (Δ ⋙_)
    lower⋙ = record { ↓⟨_⟩ = ↓⟨_⟩⋙ }

-- 3.4. Convertibility of proof trees
-- ----------------------------------
--
-- The rules for conversion between proof trees and substitutions are inductively defined.
--
-- We use the notational convention `M ≅ N` and `γ ≅ₛ δ` for convertibility on proof trees and
-- on substitutions respectively.  (…)
--
-- The conversion rules for proof trees are the reflexivity, symmetry, transitivity, congruence
-- rules and the following rules:

mutual
  infix 3 _≅_
  data _≅_ : ∀ {Γ A} → Γ ⊢ A → Γ ⊢ A → Set where
    refl≅  : ∀ {Γ A} {M : Γ ⊢ A} →
               M ≅ M
    sym≅   : ∀ {Γ A} {M M′ : Γ ⊢ A} →
               M ≅ M′ →
               M′ ≅ M
    trans≅ : ∀ {Γ A} {M M′ M″ : Γ ⊢ A} →
               M ≅ M′ → M′ ≅ M″ →
               M ≅ M″

    congƛ≅ : ∀ {Γ A B x} {{_ : T (fresh x Γ)}} {M M′ : [ Γ , x ∷ A ] ⊢ B} →
               M ≅ M′ →
               ƛ x M ≅ ƛ x M′
    cong∙≅ : ∀ {Γ A B} {M M′ : Γ ⊢ A ⊃ B} {N N′ : Γ ⊢ A} →
               M ≅ M′ → N ≅ N′ →
               M ∙ N ≅ M′ ∙ N′
    cong▶≅ : ∀ {Γ Δ A} {M M′ : Γ ⊢ A} {γ γ′ : Δ ⋙ Γ} →
               M ≅ M′ → γ ≅ₛ γ′ →
               M ▶ γ ≅ M′ ▶ γ′

    conv₁≅ : ∀ {Γ Δ A B x} {{_ : T (fresh x Γ)}} →
               (M : [ Γ , x ∷ A ] ⊢ B) (N : Δ ⊢ A) (γ : Δ ⋙ Γ) →
               (ƛ x M ▶ γ) ∙ N ≅ M ▶ [ γ , x ≔ N ]
    conv₂≅ : ∀ {Γ A B x} {{_ : T (fresh x Γ)}} →
               (c : [ Γ , x ∷ A ] ⊇ Γ) (M : Γ ⊢ A ⊃ B) →
               M ≅ ƛ x ((M ▶ π⟨ c ⟩) ∙ ν x zero)
    conv₃≅ : ∀ {Γ Δ A x} {{_ : T (fresh x Γ)}} →
               (M : Δ ⊢ A) (γ : Δ ⋙ Γ) →
               ν x zero ▶ [ γ , x ≔ M ] ≅ M
    conv₄≅ : ∀ {Γ Δ A x} →
               (c : Δ ⊇ Γ) (i : Γ ∋ x ∷ A) (j : Δ ∋ x ∷ A) →
               ν x i ▶ π⟨ c ⟩ ≅ ν x j
    conv₅≅ : ∀ {Γ A} →
               (c : Γ ⊇ Γ) (M : Γ ⊢ A) →
               M ▶ π⟨ c ⟩ ≅ M
    conv₆≅ : ∀ {Γ Δ A B} →
               (M : Γ ⊢ A ⊃ B) (N : Γ ⊢ A) (γ : Δ ⋙ Γ) →
               (M ∙ N) ▶ γ ≅ (M ▶ γ) ∙ (N ▶ γ)
    conv₇≅ : ∀ {Γ Δ Θ A} →
               (M : Γ ⊢ A) (γ : Δ ⋙ Γ) (δ : Θ ⋙ Δ) →
               (M ▶ γ) ▶ δ ≅ M ▶ (γ ● δ)

  infix 3 _≅ₛ_
  data _≅ₛ_ : ∀ {Γ Δ} → Δ ⋙ Γ → Δ ⋙ Γ → Set where
    refl≅ₛ  : ∀ {Γ Δ} {γ : Δ ⋙ Γ} →
                γ ≅ₛ γ
    sym≅ₛ   : ∀ {Γ Δ} {γ γ′ : Δ ⋙ Γ} →
                γ ≅ₛ γ′ →
                γ′ ≅ₛ γ
    trans≅ₛ : ∀ {Γ Δ} {γ γ′ γ″ : Δ ⋙ Γ} →
                γ ≅ₛ γ′ → γ′ ≅ₛ γ″ →
                γ ≅ₛ γ″

    cong●≅ₛ : ∀ {Γ Δ Θ} {γ γ′ : Δ ⋙ Γ} {δ δ′ : Θ ⋙ Δ} →
                γ ≅ₛ γ′ → δ ≅ₛ δ′ →
                γ ● δ ≅ₛ γ′ ● δ′
    cong≔≅ₛ : ∀ {Γ Δ A x} {{_ : T (fresh x Γ)}} {γ γ′ : Δ ⋙ Γ} {M M′ : Δ ⊢ A} →
                γ ≅ₛ γ′ → M ≅ M′ →
                [ γ , x ≔ M ] ≅ₛ [ γ′ , x ≔ M′ ]

    conv₁≅ₛ : ∀ {Γ Δ Θ Ω} →
                (γ : Δ ⋙ Γ) (δ : Θ ⋙ Δ) (θ : Ω ⋙ Θ) →
                (γ ● δ) ● θ ≅ₛ γ ● (δ ● θ)
    conv₂≅ₛ : ∀ {Γ Δ Θ A x} {{_ : T (fresh x Γ)}} →
                (M : Δ ⊢ A) (γ : Δ ⋙ Γ) (δ : Θ ⋙ Δ) →
                [ γ , x ≔ M ] ● δ ≅ₛ [ γ ● δ , x ≔ M ▶ δ ]
    conv₃≅ₛ : ∀ {Γ Δ A x} {{_ : T (fresh x Γ)}} →
                (c : [ Γ , x ∷ A ] ⊇ Γ) (M : Δ ⊢ A) (γ : Δ ⋙ Γ) →
                π⟨ c ⟩ ● [ γ , x ≔ M ] ≅ₛ γ
    conv₄≅ₛ : ∀ {Γ Δ Θ} →
                (c : Θ ⊇ Γ) (c′ : Δ ⊇ Γ) (c″ : Θ ⊇ Δ) →
                π⟨ c′ ⟩ ● π⟨ c″ ⟩ ≅ₛ π⟨ c ⟩
    conv₅≅ₛ : ∀ {Γ Δ} →
                (c : Δ ⊇ Δ) (γ : Δ ⋙ Γ) →
                γ ● π⟨ c ⟩ ≅ₛ γ
    conv₆≅ₛ : ∀ {Γ} →
                (c : Γ ⊇ []) (γ : Γ ⋙ []) →
                γ ≅ₛ π⟨ c ⟩
    conv₇≅ₛ : ∀ {Γ Δ A x} {{_ : T (fresh x Γ)}} →
                (c : [ Γ , x ∷ A ] ⊇ Γ) (γ : Δ ⋙ [ Γ , x ∷ A ]) (i : [ Γ , x ∷ A ] ∋ x ∷ A) →
                γ ≅ₛ [ π⟨ c ⟩ ● γ , x ≔ ν x i ▶ γ ]

-- The first two `conv≅` rules correspond to the ordinary β- and η-rules, the next three define the effect
-- of substitutions and the last two rules can be seen as the correspondence of the η-rule for
-- substitutions.  The remaining `conv≅ₛ` rules define how the substitutions distribute.

module _ where
  ≡→≅ : ∀ {Γ A} {M M′ : Γ ⊢ A} → M ≡ M′ → M ≅ M′
  ≡→≅ refl = refl≅

  module ≅-Reasoning where
    infix 1 begin_
    begin_ : ∀ {Γ A} {M M′ : Γ ⊢ A} → M ≅ M′ → M ≅ M′
    begin p = p

    infixr 2 _≅⟨⟩_
    _≅⟨⟩_ : ∀ {Γ A} (M {M′} : Γ ⊢ A) → M ≅ M′ → M ≅ M′
    M ≅⟨⟩ p = p

    infixr 2 _≅⟨_⟩_
    _≅⟨_⟩_ : ∀ {Γ A} (M {M′ M″} : Γ ⊢ A) → M ≅ M′ → M′ ≅ M″ → M ≅ M″
    M ≅⟨ p ⟩ p′ = trans≅ p p′

    infixr 2 _≡⟨⟩_
    _≡⟨⟩_ : ∀ {Γ A} (M {M′} : Γ ⊢ A) → M ≅ M′ → M ≅ M′
    M ≡⟨⟩ p = p

    infixr 2 _≡⟨_⟩_
    _≡⟨_⟩_ : ∀ {Γ A} (M {M′ M″} : Γ ⊢ A) → M ≡ M′ → M′ ≅ M″ → M ≅ M″
    M ≡⟨ p ⟩ p′ = trans≅ (≡→≅ p) p′

    infix 3 _∎
    _∎ : ∀ {Γ A} (M : Γ ⊢ A) → M ≅ M
    M ∎ = refl≅

  ≡→≅ₛ : ∀ {Γ Δ} {γ γ′ : Δ ⋙ Γ} → γ ≡ γ′ → γ ≅ₛ γ′
  ≡→≅ₛ refl = refl≅ₛ

  module ≅ₛ-Reasoning where
    infix 1 begin_
    begin_ : ∀ {Γ Δ} {γ γ′ : Δ ⋙ Γ} → γ ≅ₛ γ′ → γ ≅ₛ γ′
    begin p = p

    infixr 2 _≅ₛ⟨⟩_
    _≅ₛ⟨⟩_ : ∀ {Γ Δ} (γ {γ′} : Δ ⋙ Γ) → γ ≅ₛ γ′ → γ ≅ₛ γ′
    γ ≅ₛ⟨⟩ p = p

    infixr 2 _≅ₛ⟨_⟩_
    _≅ₛ⟨_⟩_ : ∀ {Γ Δ} (γ {γ′ γ″} : Δ ⋙ Γ) → γ ≅ₛ γ′ → γ′ ≅ₛ γ″ → γ ≅ₛ γ″
    γ ≅ₛ⟨ p ⟩ p′ = trans≅ₛ p p′

    infixr 2 _≡⟨⟩_
    _≡⟨⟩_ : ∀ {Γ Δ} (γ {γ′} : Δ ⋙ Γ) → γ ≅ₛ γ′ → γ ≅ₛ γ′
    γ ≡⟨⟩ p = p

    infixr 2 _≡⟨_⟩_
    _≡⟨_⟩_ : ∀ {Γ Δ} (γ {γ′ γ″} : Δ ⋙ Γ) → γ ≡ γ′ → γ′ ≅ₛ γ″ → γ ≅ₛ γ″
    γ ≡⟨ p ⟩ p′ = trans≅ₛ (≡→≅ₛ p) p′

    infix 3 _∎
    _∎ : ∀ {Γ Δ} (γ : Δ ⋙ Γ) → γ ≅ₛ γ
    γ ∎ = refl≅ₛ


open import MJ.Types as Types
import MJ.Classtable.Core as Core

module MJ.Semantics.Values {c}(Ct : Core.Classtable c) where

open import Prelude

open import Level renaming (suc to lsuc; zero to lzero)
open import Data.List hiding (null)
open import Data.List.Membership.Propositional
open import Data.List.Prefix

open Core c
open Classtable Ct
open import MJ.Classtable.Membership Ct
open import MJ.LexicalScope c
open import Common.Weakening

{-
MJ inherits the values of STLC+Ref. In contrast to STCL+Ref, MJ also has
null-pointers; which we add as a constructor to our value type Val. The value
constructed by null is typed with an arbitrary reference type as it can be used
in place of any proper reference.
-}
data Val (W : World c) : Ty c → Set where
  num  : ℕ → Val W int
  unit : Val W void
  null : ∀ {C} → Val W (ref C)
  ref  : ∀ {C P} → (obj C) ∈ W → Σ ⊢ C <: P → Val W (ref P)

{-
We can construct default values out of thin air for every type
-}
default : ∀ {W} → (a : Ty c) → Val W a
default void = unit
default int = num 0
default (ref x) = null

{-
Value weakening
-}
weaken-val : ∀ {a}{W W' : World c} → W ⊒ W' → Val W' a → Val W a
weaken-val ext (num n) = num n
weaken-val ext unit = unit
weaken-val ext null = null
weaken-val ext (ref x sub) = ref (∈-⊒ x ext) sub

instance
  val-weakenable : ∀ {a} → Weakenable (λ W → Val W a)
  val-weakenable = record { wk = weaken-val }


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

-- There are really all 'private' sub-pieces of
-- Categories.Category.Monoidal.Closed.IsClosed, but that is taking
-- forever to typecheck, so the idea is to split things into pieces and
-- hope that that will help.

open import Categories.Category using (Category)
open import Categories.Category.Monoidal
open import Categories.Category.Monoidal.Closed using (Closed)

module Categories.Category.Monoidal.Closed.IsClosed.Identity
  {o ℓ e} {C : Category o ℓ e} {M : Monoidal C} (Cl : Closed M) where

open import Function using (_$_) renaming (_∘_ to _∙_)

open import Categories.Category.Monoidal.Utilities M
open import Categories.Morphism C using (Iso)
open import Categories.Morphism.Properties C using (Iso-resp-≈)
open import Categories.Morphism.Reasoning C using (pullʳ; pullˡ; pushˡ; cancelʳ)
open import Categories.Functor using (Functor) renaming (id to idF)
open import Categories.Functor.Bifunctor
open import Categories.Functor.Bifunctor.Properties
open import Categories.NaturalTransformation hiding (id)
open import Categories.NaturalTransformation.Dinatural
  using (Extranaturalʳ; extranaturalʳ; DinaturalTransformation)
open import Categories.NaturalTransformation.NaturalIsomorphism
  using (NaturalIsomorphism)
import Categories.Category.Closed as Cls

open Closed Cl
open Category C       -- most of it is used

open HomReasoning
open adjoint renaming (unit to η; counit to ε; Ladjunct to 𝕃)

private
  λ⇒ = unitorˡ.from
  λ⇐ = unitorˡ.to
  ρ⇒ = unitorʳ.from
  ρ⇐ = unitorʳ.to

identity : NaturalIsomorphism idF [ unit ,-]
identity = record
  { F⇒G = F∘id⇒F ∘ᵥ ([ unit ,-] ∘ˡ (unitorʳ-natural.F⇒G)) ∘ᵥ η
  ; F⇐G = ε ∘ᵥ (unitorʳ-natural.F⇐G ∘ʳ [ unit ,-]) ∘ᵥ F⇒id∘F
  ; iso = λ X → Iso-resp-≈ (iso X) (⟺ identityˡ) (⟺ (∘-resp-≈ʳ identityʳ))
  }
  where
  open Functor
  iso : ∀ X → Iso (𝕃 unitorʳ.from) (ε.η X ∘ unitorʳ.to)
  iso X = record
    { isoˡ = begin
      (ε.η X ∘ ρ⇐) ∘ 𝕃 ρ⇒      ≈⟨ pullʳ unitorʳ-commute-to ⟩
      ε.η X ∘ 𝕃 ρ⇒ ⊗₁ id ∘ ρ⇐  ≈˘⟨ assoc ⟩
      Radjunct (𝕃 ρ⇒) ∘ ρ⇐     ≈⟨ RLadjunct≈id ⟩∘⟨refl ⟩
      ρ⇒ ∘ ρ⇐                  ≈⟨ unitorʳ.isoʳ ⟩
      id                       ∎
    ; isoʳ = begin
      𝕃 ρ⇒ ∘ ε.η X ∘ ρ⇐                      ≈⟨ pullʳ (η.commute _) ⟩
      [ id , ρ⇒ ]₁ ∘ 𝕃 ((ε.η X ∘ ρ⇐) ⊗₁ id) ≈˘⟨ pushˡ (homomorphism [ unit ,-]) ⟩
      𝕃 (ρ⇒ ∘ (ε.η X ∘ ρ⇐) ⊗₁ id)           ≈⟨ F-resp-≈ [ unit ,-] unitorʳ-commute-from ⟩∘⟨refl ⟩
      𝕃 ((ε.η X ∘ ρ⇐) ∘ ρ⇒)                 ≈⟨ F-resp-≈ [ unit ,-] (cancelʳ unitorʳ.isoˡ) ⟩∘⟨refl ⟩
      𝕃 (ε.η X)                              ≈⟨ zag ⟩
      id                                     ∎
    }

module identity = NaturalIsomorphism identity

diagonal : Extranaturalʳ unit [-,-]
diagonal = extranaturalʳ (λ X → 𝕃 λ⇒)
  $ λ {X Y f} → begin
    [ id , f ]₁ ∘ 𝕃 λ⇒                             ≈˘⟨ pushˡ (homomorphism [ X ,-]) ⟩
    [ id , f ∘ λ⇒ ]₁ ∘ η.η unit                    ≈˘⟨ F-resp-≈ [ X ,-] unitorˡ-commute-from ⟩∘⟨refl ⟩
    [ id , λ⇒ ∘ id ⊗₁ f ]₁ ∘ η.η unit              ≈⟨ homomorphism [ X ,-] ⟩∘⟨refl ⟩
    ([ id , λ⇒ ]₁ ∘ [ id , id ⊗₁ f ]₁) ∘ η.η unit  ≈⟨ pullʳ (mate.commute₁ f) ⟩
    [ id , λ⇒ ]₁ ∘ [ f , id ]₁ ∘ η.η unit          ≈⟨ pullˡ [ [-,-] ]-commute ⟩
    ([ f , id ]₁ ∘ [ id , λ⇒ ]₁) ∘ η.η unit        ≈⟨ assoc ⟩
    [ f , id ]₁ ∘ 𝕃 λ⇒                             ∎
  where open Functor

module diagonal = DinaturalTransformation diagonal


module Section8 where

open import Section7 public

-- 8. Correctness of conversion between terms
-- ==========================================
--
-- The conversion rules for terms are sound:

-- Theorem 9.
postulate
  thm₉ : ∀ {Γ A t₀ t₁} →
           (M N : Γ ⊢ A) → t₀ 𝒟 M → t₁ 𝒟 N → Γ ⊢ t₀ ≊ t₁ ∷ A →
           M ≅ N

-- Proof: The proof is by induction on the proof of `Γ ⊢ t₀ ≊ t₁ ∷ A`.  We illustrate the proof
-- with the reflexivity case.  In this case we have that `t₀` and `t₁` are the same, hence by Corollary 3
-- we get `M ≅ N`.
--
-- To prove that the conversion rules are complete
-- is straightforward by induction on the proof of `M ≅ N`.

-- Theorem 10.
postulate
  thm₁₀ : ∀ {Γ A} →
            (M N : Γ ⊢ A) → M ≅ N →
            Γ ⊢ M ⁻ ≊ N ⁻ ∷ A


{-# OPTIONS --without-K --safe #-}
module Util.HoTT.Equiv.Core where

open import Util.Prelude
open import Util.HoTT.HLevel.Core

infix 4 _≅_ _≃_

private
  variable
    α β γ : Level
    A B C : Set α

Injective : (f : A → B) → Set _
Injective f = ∀ {x y} → f x ≡ f y → x ≡ y

record IsIso {A : Set α} {B : Set β} (forth : A → B) : Set (α ⊔ℓ β)
  where
  field
    back : B → A
    back∘forth : ∀ x → back (forth x) ≡ x
    forth∘back : ∀ x → forth (back x) ≡ x

record _≅_ (A : Set α) (B : Set β) : Set (α ⊔ℓ β) where
  field
    forth : A → B
    isIso : IsIso forth

  open IsIso isIso public

open _≅_ public

IsEquiv : {A : Set α} {B : Set β} (forth : A → B)
  → Set (α ⊔ℓ β)
IsEquiv {A = A} {B} forth
  = ∀ b → IsContr (Σ[ a ∈ A ] forth a ≡ b)

record _≃_ (A : Set α) (B : Set β) : Set (α ⊔ℓ β) where
  field
    forth : A → B
    isEquiv : IsEquiv forth

open _≃_ public


------------------------------------------------------------------------
-- The semantics is deterministic
------------------------------------------------------------------------

open import Atom

module Deterministic (atoms : χ-atoms) where

open import Equality.Propositional
open import Prelude hiding (const)
open import Tactic.By.Propositional

open import Chi atoms

open χ-atoms atoms

Lookup-deterministic :
  ∀ {c₁ c₂ bs xs₁ xs₂ e₁ e₂} →
  Lookup c₁ bs xs₁ e₁ → Lookup c₂ bs xs₂ e₂ →
  c₁ ≡ c₂ → xs₁ ≡ xs₂ × e₁ ≡ e₂
Lookup-deterministic here          here          _    = refl , refl
Lookup-deterministic here          (there q _)   refl = ⊥-elim (q refl)
Lookup-deterministic (there p _)   here          refl = ⊥-elim (p refl)
Lookup-deterministic (there p₁ p₂) (there q₁ q₂) refl =
  Lookup-deterministic p₂ q₂ refl

↦-deterministic :
  ∀ {e xs es e₁ e₂} →
  e [ xs ← es ]↦ e₁ → e [ xs ← es ]↦ e₂ → e₁ ≡ e₂
↦-deterministic []    []    = refl
↦-deterministic (∷ p) (∷ q) = by (↦-deterministic p q)

mutual

  ⇓-deterministic : ∀ {e v₁ v₂} → e ⇓ v₁ → e ⇓ v₂ → v₁ ≡ v₂
  ⇓-deterministic (apply p₁ p₂ p₃) (apply q₁ q₂ q₃)
    with ⇓-deterministic p₁ q₁ | ⇓-deterministic p₂ q₂
  ... | refl | refl = ⇓-deterministic p₃ q₃

  ⇓-deterministic (case p₁ p₂ p₃ p₄) (case q₁ q₂ q₃ q₄)
    with ⇓-deterministic p₁ q₁
  ... | refl with Lookup-deterministic p₂ q₂ refl
  ...   | refl , refl rewrite ↦-deterministic p₃ q₃ =
    ⇓-deterministic p₄ q₄

  ⇓-deterministic (rec p)    (rec q)    = ⇓-deterministic p q
  ⇓-deterministic lambda     lambda     = refl
  ⇓-deterministic (const ps) (const qs) = by (⇓⋆-deterministic ps qs)

  ⇓⋆-deterministic : ∀ {es vs₁ vs₂} → es ⇓⋆ vs₁ → es ⇓⋆ vs₂ → vs₁ ≡ vs₂
  ⇓⋆-deterministic []       []       = refl
  ⇓⋆-deterministic (p ∷ ps) (q ∷ qs) =
    cong₂ _∷_ (⇓-deterministic p q) (⇓⋆-deterministic ps qs)


open import Agda.Primitive using (lzero; lsuc; _⊔_; Level)
open import Relation.Binary.PropositionalEquality using (_≡_; refl; subst)
open import Relation.Binary using (Setoid)

-- A formalization of raw syntax

module Syntax where

  -- Syntactic classes

  data ObjectClass : Set where
    Ty Tm : ObjectClass

  data Class : Set where
    obj : ObjectClass → Class
    EqTy EqTm : Class

  -- Variable context shape

  infixl 6 _⊕_

  data VShape : Set where
    𝟘 : VShape
    𝟙 : VShape
    _⊕_ : VShape → VShape → VShape

  data var : VShape → Set where
    var-here : var 𝟙
    var-left : ∀ {γ δ} → var γ → var (γ ⊕ δ)
    var-right : ∀ {γ δ} → var δ → var (γ ⊕ δ)

  -- Metavariable context shapes

  infixl 9 _⊕ᵐᵛ_

  data MShape : Set where
    𝟘ᵐᵛ : MShape
    𝟙ᵐᵛ : ∀ (cl : Class) (γ : VShape) → MShape
    _⊕ᵐᵛ_ : MShape → MShape → MShape

  infix 8 [_,_]∈_

  data [_,_]∈_ : Class → VShape → MShape → Set where
    mv-here : ∀ cl γ → [ cl , γ ]∈ 𝟙ᵐᵛ cl γ
    mv-left : ∀ {𝕂 𝕄} cl γ → [ cl , γ ]∈ 𝕂 → [ cl , γ ]∈ 𝕂 ⊕ᵐᵛ 𝕄
    mv-right : ∀ {𝕂 𝕄} cl γ → [ cl , γ ]∈ 𝕄 → [ cl , γ ]∈ 𝕂 ⊕ᵐᵛ 𝕄

  -- Symbol signature

  record Signature : Set₁ where
    field
      symb : ObjectClass → Set -- a set of symbol names, one for each class
      symb-arg : ∀ {cl} → symb cl → MShape

  -- Expressions

  module Expression (𝕊 : Signature) where
    open Signature 𝕊

    data Expr : Class → (𝕄 : MShape) → (γ : VShape) → Set

    Arg : ∀ (cl : Class) (𝕄 : MShape) (γ : VShape) (δ : VShape) → Set
    Arg cl 𝕄 γ δ = Expr cl 𝕄 (γ ⊕ δ)

    ExprObj : ∀ (cl : ObjectClass) (𝕄 : MShape) (γ : VShape) → Set
    ExprObj cl = Expr (obj cl)

    ExprTm = ExprObj Tm
    ExprTy = ExprObj Ty

    data Expr where
      expr-var : ∀ {𝕄} {γ} (x : var γ) → ExprTm 𝕄 γ
      expr-symb : ∀ {cl 𝕄 γ} (S : symb cl) →
                    (es : ∀ {clⁱ γⁱ} (i : [ clⁱ , γⁱ ]∈ symb-arg S) → Arg clⁱ 𝕄 γ γⁱ) →
                    ExprObj cl 𝕄 γ
      expr-meta : ∀ {cl 𝕄 γ} {γᴹ} (M : [ obj cl , γᴹ ]∈ 𝕄) → (ts : ∀ (i : var γᴹ) → ExprTm 𝕄 γ) → ExprObj cl 𝕄 γ
      expr-eqty : ∀ {γ} {𝕄} → Expr EqTy 𝕄 γ
      expr-eqtm : ∀ {γ} {𝕄} → Expr EqTm 𝕄 γ

    expr-meta-generic : ∀ {𝕄} {cl} {γ γᴹ} (M : [ cl , γᴹ ]∈ 𝕄) → Arg cl 𝕄 γ γᴹ
    expr-meta-generic {cl = obj _} M = expr-meta M (λ i → expr-var (var-right i))
    expr-meta-generic {cl = EqTy} M = expr-eqty
    expr-meta-generic {cl = EqTm} M = expr-eqtm

  -- Syntactic equality

  module Equality {𝕊 : Signature} where

    open Signature 𝕊
    open Expression 𝕊

    infix 4 _≈_

    data _≈_ : ∀ {cl 𝕄 γ} → Expr cl 𝕄 γ → Expr cl 𝕄 γ → Set where
      ≈-≡ : ∀ {cl 𝕄 γ} {t u : Expr cl 𝕄 γ} (ξ : t ≡ u) → t ≈ u
      ≈-symb : ∀ {cl 𝕄 γ} {S : symb cl} →
                {ds es : ∀ {cⁱ γⁱ} (i : [ cⁱ , γⁱ ]∈ symb-arg S) → Arg cⁱ 𝕄 γ γⁱ}
                (ξ : ∀ {cⁱ γⁱ} (i : [ cⁱ , γⁱ ]∈ symb-arg S) → ds i ≈ es i) → expr-symb S ds ≈ expr-symb S es
      ≈-meta : ∀ {cl 𝕄 γ} {γᴹ} {M : [ obj cl , γᴹ ]∈ 𝕄} → {ts us : ∀ (i : var γᴹ) → ExprTm 𝕄 γ}
                (ξ : ∀ i → ts i ≈ us i) → expr-meta M ts ≈ expr-meta M us

    ≈-refl : ∀ {cl 𝕄 γ} {t : Expr cl 𝕄 γ} → t ≈ t
    ≈-refl = ≈-≡ refl

    ≈-eqty : ∀ {𝕄 γ} {s t : Expr EqTy 𝕄  γ} → s ≈ t
    ≈-eqty {s = expr-eqty} {t = expr-eqty} = ≈-refl

    ≈-eqtm : ∀ {𝕄 γ} {s t : Expr EqTm 𝕄 γ} → s ≈ t
    ≈-eqtm {s = expr-eqtm} {t = expr-eqtm} = ≈-refl

    ≈-sym : ∀ {cl 𝕄 γ} {t u : Expr cl 𝕄 γ} → t ≈ u → u ≈ t
    ≈-sym (≈-≡ refl) = ≈-≡ refl
    ≈-sym (≈-symb ε) = ≈-symb (λ i → ≈-sym (ε i))
    ≈-sym (≈-meta ε) = ≈-meta (λ i → ≈-sym (ε i))

    ≈-trans : ∀ {cl 𝕄 γ} {t u v : Expr cl 𝕄 γ} → t ≈ u → u ≈ v → t ≈ v
    ≈-trans (≈-≡ refl) ξ = ξ
    ≈-trans (≈-symb ζ) (≈-≡ refl) = ≈-symb ζ
    ≈-trans (≈-symb ζ) (≈-symb ξ) = ≈-symb (λ i → ≈-trans (ζ i) (ξ i))
    ≈-trans (≈-meta ζ) (≈-≡ refl) = ≈-meta ζ
    ≈-trans (≈-meta ζ) (≈-meta ξ) = ≈-meta (λ i → ≈-trans (ζ i) (ξ i))

    -- the setoid of expressions

    Expr-setoid : ∀ (cl : Class) (𝕄 : MShape) (γ : VShape) →  Setoid lzero lzero
    Expr-setoid cl 𝕄 γ =
      record
        { Carrier =  Expr cl 𝕄 γ
        ; _≈_ = _≈_
        ; isEquivalence = record { refl = ≈-refl ; sym = ≈-sym ; trans = ≈-trans }
        }

  infix 4 _%_≈_

  _%_≈_ : ∀ (𝕊 : Signature) {cl 𝕄 γ} → (t u : Expression.Expr 𝕊 cl 𝕄 γ) → Set
  _%_≈_ 𝕊 = Equality._≈_ {𝕊 = 𝕊}


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

open import HoTT
open import homotopy.elims.Lemmas
open import homotopy.elims.CofPushoutSection

module homotopy.elims.SuspSmash {i j k} {X : Ptd i} {Y : Ptd j}
  {P : Suspension (X ∧ Y) → Type k}
  (north* : P north) (south* : P south)
  (cod* : (s : fst X × fst Y) → north* == south* [ P ↓ merid (cfcod s) ])
  where

private
  base* = transport (λ κ → north* == south* [ P ↓ merid κ ])
    (! (cfglue (winl (snd X))))
    (cod* (snd X , snd Y))

  coh* : (s : X ∧ Y) → north* == south* [ P ↓ merid s ]
  coh* = CofPushoutSection.elim (λ _ → tt) (λ _ → idp)
    base*
    (λ {(x , y) →
      (fst (fillX x) ∙ fst (fillY y)) ◃ fst fill0 ◃ cod* (x , y)})
    (↓↓-from-squareover ∘ λ x →
      snd (fillX x) ↓⊡h∙
      ap (λ p → p ◃ fst fill0 ◃ cod* (x , snd Y))
         (! (ap (λ q → fst (fillX x) ∙ q) fillY-lemma ∙ ∙-unit-r _)))
    (↓↓-from-squareover ∘ λ y →
      snd (fillY y) ↓⊡h∙
      ap (λ p → p ◃ fst fill0 ◃ cod* (snd X , y))
         (! (ap (λ q → q ∙ fst (fillY y)) fillX-lemma)))
    where
    fill-lemma : (w : X ∨ Y)
      (α : north* == south* [ P ↓ merid (cfcod (∨-in-× X Y w)) ])
      → Σ (north* == north*)
          (λ p → SquareOver P (natural-square merid (cfglue w))
                   base*
                   (↓-ap-in _ _ (apd (λ _ → north*) (cfglue w)))
                   (↓-ap-in _ _ (apd (λ _ → south*) (cfglue w)))
                   (p ◃ α))
    fill-lemma w α = fill-upper-right _ _ _ _ _

    fill0 = fill-lemma (winl (snd X)) (cod* (snd X , snd Y))
    fillX = λ x → fill-lemma (winl x) (fst fill0 ◃ cod* (x , snd Y))
    fillY = λ y → fill-lemma (winr y) (fst fill0 ◃ cod* (snd X , y))

    fillX-lemma : fst (fillX (snd X)) == idp
    fillX-lemma = ! $
      fill-upper-right-unique _ _ _ _ _ idp (snd fill0 ↓⊡h∙ ! (idp◃ _))

    fillY-lemma : fst (fillY (snd Y)) == idp
    fillY-lemma = ! $
      fill-upper-right-unique _ _ _ _ _ idp (snd fill0 ↓⊡h∙ ! (idp◃ _))
      ∙ ap (λ w → fst (fill-lemma w (fst fill0 ◃ cod* (∨-in-× X Y w))))
           wglue

susp-smash-elim : Π (Suspension (X ∧ Y)) P
susp-smash-elim = Suspension-elim north* south* coh*


------------------------------------------------------------------------
-- The Agda standard library
--
-- Decidable setoid membership over lists
------------------------------------------------------------------------

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

open import Relation.Binary using (Decidable; DecSetoid)

module Data.List.Membership.DecSetoid {a ℓ} (DS : DecSetoid a ℓ) where

open import Data.List.Relation.Unary.Any using (any)
open DecSetoid DS

------------------------------------------------------------------------
-- Re-export contents of propositional membership

open import Data.List.Membership.Setoid (DecSetoid.setoid DS) public

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

infix 4 _∈?_

_∈?_ : Decidable _∈_
x ∈? xs = any (x ≟_) xs


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

open import HoTT

module groups.Image where

module _ {i j k} {G : Group i} {H : Group j}
  {K : Group k} (φ : H →ᴳ K) (ψ : G →ᴳ H) where

  abstract
    im-sub-im-∘ : is-surjᴳ ψ → im-propᴳ φ ⊆ᴳ im-propᴳ (φ ∘ᴳ ψ)
    im-sub-im-∘ ψ-is-surj k = Trunc-rec Trunc-level
      (λ{(h , φh=k) → Trunc-rec Trunc-level
        (λ{(g , ψg=h) → [ g , ap (GroupHom.f φ) ψg=h ∙ φh=k ]})
        (ψ-is-surj h)})

    im-∘-sub-im : im-propᴳ (φ ∘ᴳ ψ) ⊆ᴳ im-propᴳ φ
    im-∘-sub-im k = Trunc-rec Trunc-level
      (λ{(g , φψg=k) → [ GroupHom.f ψ g , φψg=k ]})

  im-iso-im-pre∘ : is-surjᴳ ψ → Im φ ≃ᴳ Im (φ ∘ᴳ ψ)
  im-iso-im-pre∘ ψ-is-surj = Subgroup-emap-r
    (im-propᴳ φ) (im-propᴳ (φ ∘ᴳ ψ))
    (im-sub-im-∘ ψ-is-surj) im-∘-sub-im


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

-- A Monad in a Bicategory.
-- For the more elementary version of Monads, see 'Categories.Monad'.
module Categories.Bicategory.Monad where

open import Level
open import Data.Product using (_,_)

open import Categories.Bicategory
import Categories.Bicategory.Extras as Bicat
open import Categories.NaturalTransformation.NaturalIsomorphism using (NaturalIsomorphism)

record Monad {o ℓ e t} (𝒞 : Bicategory o ℓ e t) : Set (o ⊔ ℓ ⊔ e ⊔ t) where
  open Bicat 𝒞

  field
    C : Obj
    T : C ⇒₁ C
    η : id₁ ⇒₂ T
    μ : (T ⊚₀ T) ⇒₂ T

    assoc     : μ ∘ᵥ (T ▷ μ) ∘ᵥ associator.from ≈ (μ ∘ᵥ (μ ◁ T))
    sym-assoc : μ ∘ᵥ (μ ◁ T) ∘ᵥ associator.to ≈ (μ ∘ᵥ (T ▷ μ))
    identityˡ : μ ∘ᵥ (T ▷ η) ∘ᵥ unitorʳ.to ≈ id₂
    identityʳ : μ ∘ᵥ (η ◁ T) ∘ᵥ unitorˡ.to ≈ id₂


-- Forced constructor arguments don't count towards the size of the datatype
-- (only if not --withoutK).

data _≡_ {a} {A : Set a} : A → A → Set where
  refl : ∀ x → x ≡ x

data Singleton {a} {A : Set a} : A → Set where
  [_] : ∀ x → Singleton x


module Implicits.Syntax.Type.Constructors where

open import Prelude
open import Implicits.Syntax.Type
open import Implicits.Substitutions
open TypeSubst

-- polymorphic identity
tid : ∀ {n} → Type n
tid = ∀' (simpl ((TVar zero) →' (TVar zero)))

-- type of bools encoding
tbool : Type 0
tbool = ∀' (simpl ((TVar zero) →' (simpl ((TVar zero) →' (TVar zero)))))

-- church numerals
tnat : Type 0
tnat = ∀' (simpl ((simpl ((TVar zero) →' (TVar zero))) →' (simpl ((TVar zero) →' (TVar zero)))))

-- existential quantification
∃' : ∀ {n} → (Type (suc n)) → Type n
∃' a = ∀' (∀' (simpl ((a tp/tp (wk ↑)) →' (simpl ((TVar (suc zero)) →' (TVar zero))))))

-- unit type
⊤' : ∀ {n} → Type n
⊤' = tid

-- zero type
⊥' : ∀ {n} → Type n
⊥' = ∀' (TVar zero)

-- n-ary function type
infixr 7 _→ⁿ_
_→ⁿ_ : ∀ {n k} → Vec (Type n) k → Type n → Type n
[]       →ⁿ z = z
(a ∷ as) →ⁿ z = as →ⁿ (simpl (a →' z))

-- Record/finite tuple
rec : ∀ {n k} → Vec (Type n) k → Type n
rec []       = ⊤'
rec (a ∷ as) = ∀' (simpl ((map tp-weaken (a ∷ as) →ⁿ TVar zero) →' TVar zero))

-- tuple
_×'_ : ∀ {n} → Type n → Type n → Type n
a ×' b = rec (a ∷ b ∷ [])


------------------------------------------------------------------------
-- The Agda standard library
--
-- Sublist-related properties
------------------------------------------------------------------------

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

module Data.List.Relation.Binary.Sublist.Propositional.Properties {a} {A : Set a} where

open import Data.List using (map)
open import Data.List.Relation.Unary.Any using (Any; here; there)
open import Data.List.Relation.Unary.Any.Properties using (here-injective; there-injective)
open import Data.List.Relation.Binary.Sublist.Propositional
  hiding (map)
import Data.List.Relation.Binary.Sublist.Setoid.Properties
  as SetoidProperties
open import Function
open import Relation.Binary.PropositionalEquality as P hiding ([_])
open import Relation.Unary as U using (Pred)

------------------------------------------------------------------------
-- Re-exporting setoid properties

open SetoidProperties (P.setoid A) public
  hiding (map⁺)

------------------------------------------------------------------------
-- map

module _ {b} {B : Set b} where

  map⁺ : ∀ {as bs} (f : A → B) → as ⊆ bs → map f as ⊆ map f bs
  map⁺ f = SetoidProperties.map⁺ (setoid A) (setoid B) (cong f)

------------------------------------------------------------------------
-- The `lookup` function induced by a proof that `xs ⊆ ys` is injective

module _ {p} {P : Pred A p} where

  lookup-injective : ∀ {xs ys} {p : xs ⊆ ys} {v w : Any P xs} →
                     lookup p v ≡ lookup p w → v ≡ w
  lookup-injective {p = []}       {}
  lookup-injective {p = _   ∷ʳ _} {v}       {w}       =
    lookup-injective ∘′ there-injective
  lookup-injective {p = x≡y ∷ _}  {here pv} {here pw} =
    cong here ∘′ subst-injective x≡y ∘′ here-injective
  lookup-injective {p = _ ∷ _}    {there v} {there w} =
    cong there ∘′ lookup-injective ∘′ there-injective
  lookup-injective {p = _ ∷ _}    {here  _} {there _} ()
  lookup-injective {p = _ ∷ _}    {there _} {here  _} ()


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

module Cubical.Algebra.Group.Action where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Structure
open import Cubical.Algebra.Group.Base
open import Cubical.Algebra.Group.Morphism
open import Cubical.Algebra.Group.Properties
open import Cubical.Algebra.Group.Notation
open import Cubical.Algebra.Group.MorphismProperties
open import Cubical.Structures.LeftAction
open import Cubical.Structures.Axioms
open import Cubical.Structures.Macro
open import Cubical.Structures.Auto
open import Cubical.Data.Sigma

private
  variable
    ℓ ℓ' : Level

record IsGroupAction (G : Group {ℓ = ℓ})
                     (H : Group {ℓ = ℓ'})
                     (_α_ : LeftActionStructure ⟨ G ⟩ ⟨ H ⟩) : Type (ℓ-max ℓ ℓ') where

  constructor isgroupaction

  open GroupNotationG G

  field
    isHom : (g : ⟨ G ⟩) → isGroupHom H H (g α_)
    identity : (h : ⟨ H ⟩) → 0ᴳ α h ≡ h
    assoc : (g g' : ⟨ G ⟩) → (h : ⟨ H ⟩) → (g +ᴳ g') α h ≡ g α (g' α h)

record GroupAction (G : Group {ℓ}) (H : Group {ℓ'}): Type (ℓ-suc (ℓ-max ℓ ℓ')) where

  constructor groupaction

  field
    _α_ : LeftActionStructure ⟨ G ⟩ ⟨ H ⟩
    isGroupAction : IsGroupAction G H _α_

module ActionΣTheory {ℓ ℓ' : Level} where

  module _ (G : Group {ℓ}) (H : Group {ℓ'}) (_α_ : LeftActionStructure ⟨ G ⟩ ⟨ H ⟩) where

    open GroupNotationG G

    IsGroupActionΣ : Type (ℓ-max ℓ ℓ')
    IsGroupActionΣ = ((g : ⟨ G ⟩) → isGroupHom H H (g α_))
                         × ((h : ⟨ H ⟩) → 0ᴳ α h ≡ h)
                         × ((g g' : ⟨ G ⟩) → (h : ⟨ H ⟩) → (g +ᴳ g') α h ≡ g α (g' α h))

    isPropIsGroupActionΣ : isProp IsGroupActionΣ
    isPropIsGroupActionΣ = isPropΣ isPropIsHom λ _ → isPropΣ isPropIdentity λ _ → isPropAssoc
      where
        isPropIsHom = isPropΠ (λ g → isPropIsGroupHom H H)
        isPropIdentity = isPropΠ (λ h → GroupStr.is-set (snd H) (0ᴳ α h) h)
        isPropAssoc = isPropΠ3 (λ g g' h → GroupStr.is-set (snd H) ((g +ᴳ g') α h) (g α (g' α h)))

    IsGroupAction→IsGroupActionΣ : IsGroupAction G H _α_ → IsGroupActionΣ
    IsGroupAction→IsGroupActionΣ (isgroupaction isHom identity assoc) = isHom , identity , assoc

    IsGroupActionΣ→IsGroupAction : IsGroupActionΣ → IsGroupAction G H _α_
    IsGroupActionΣ→IsGroupAction (isHom , identity , assoc) = isgroupaction isHom identity assoc

    IsGroupActionΣIso : Iso (IsGroupAction G H _α_) IsGroupActionΣ
    Iso.fun IsGroupActionΣIso = IsGroupAction→IsGroupActionΣ
    Iso.inv IsGroupActionΣIso = IsGroupActionΣ→IsGroupAction
    Iso.rightInv IsGroupActionΣIso = λ _ → refl
    Iso.leftInv IsGroupActionΣIso = λ _ → refl

open ActionΣTheory

isPropIsGroupAction : {ℓ ℓ' : Level }
                      (G : Group {ℓ}) (H : Group {ℓ'})
                      (_α_ : LeftActionStructure ⟨ G ⟩ ⟨ H ⟩)
                      → isProp (IsGroupAction G H _α_)
isPropIsGroupAction G H _α_ = isOfHLevelRespectEquiv 1
                                                     (invEquiv (isoToEquiv (IsGroupActionΣIso G H _α_)))
                                                     (isPropIsGroupActionΣ G H _α_)

module ActionNotationα {N : Group {ℓ}} {H : Group {ℓ'}} (Act : GroupAction H N) where
  _α_ = GroupAction._α_ Act
  private
    isGroupAction = GroupAction.isGroupAction Act
  α-id = IsGroupAction.identity isGroupAction
  α-hom = IsGroupAction.isHom isGroupAction
  α-assoc = IsGroupAction.assoc isGroupAction

module ActionLemmas {G : Group {ℓ}} {H : Group {ℓ'}} (Act : GroupAction G H) where
  open ActionNotationα {N = H} {H = G} Act
  open GroupNotationᴴ H
  open GroupNotationG G
  open MorphismLemmas {G = H} {H = H}
  open GroupLemmas

  abstract
    actOnUnit : (g : ⟨ G ⟩) → g α 0ᴴ ≡ 0ᴴ
    actOnUnit g = mapId (grouphom (g α_) (α-hom g))

    actOn-Unit : (g : ⟨ G ⟩) → g α (-ᴴ 0ᴴ) ≡ 0ᴴ
    actOn-Unit g = (cong (g α_) (invId H)) ∙ actOnUnit g

    actOn- : (g : ⟨ G ⟩) (h : ⟨ H ⟩) → g α (-ᴴ h) ≡ -ᴴ (g α h)
    actOn- g h = mapInv (grouphom (g α_) (α-hom g)) h

    -idAct : (h : ⟨ H ⟩) → (-ᴳ 0ᴳ) α h ≡ h
    -idAct h = (cong (_α h) (invId G)) ∙ (α-id h)

-- Examples
-- left adjoint action of a group on a normal subgroup


-- Andreas, 2015-07-18
-- Postpone checking of record expressions when type is blocked.
-- Guess type of record expressions when type is blocked.

open import Common.Product
open import Common.Prelude
open import Common.Equality

T : Bool → Set
T true  = Bool × Nat
T false = ⊥

works : (P : ∀{b} → b ≡ true → T b → Set) → Set
works P = P refl record{ proj₁ = true; proj₂ = 0 }

-- Guess or postpone.
test : (P : ∀{b} → T b → b ≡ true → Set) → Set
test P = P record{ proj₁ = true; proj₂ = 0 } refl

guess : (P : ∀{b} → T b → Set) → Set
guess P = P record{ proj₁ = true; proj₂ = 0 }

record R : Set where
  field
    f : Bool

record S : Set where
  field
    f : Bool

U : Bool → Set
U true = R
U false = S

postpone : (P : ∀{b} → U b → b ≡ true → Set) → Set
postpone P = P record{ f = false } refl

-- ambiguous : (P : ∀{b} → U b → Set) → Set
-- ambiguous P = P record{ f = false }


-- Andreas, 2015-06-11
-- testing with in copattern matching with dependent record

-- {-# OPTIONS -v tc.with:20 #-}

open import Common.Prelude
open import Common.Equality

data Dec P : Set where
  yes : (p : P) → Dec P
  no  : (¬p : P → ⊥) → Dec P

postulate
  _≟_ : (n m : Nat) → Dec (n ≡ m)
  boring : {A : Set} → A

record R : Set₁ where
  field
    Car  : Set
    el   : Car
    same : (x : Car) → Dec (x ≡ el)

test : (n : Nat) → R
R.Car  (test n) = Nat
R.el   (test n) = n
R.same (test zero) zero = yes refl
R.same (test zero) (suc x) = no λ()
R.same (test (suc n)) zero = no λ()
R.same (test (suc n)) (suc x) with n ≟ x
R.same (test (suc n)) (suc .n) | yes refl = yes refl
R.same (test (suc n)) (suc x) | no ¬p = no boring


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties for Conats
------------------------------------------------------------------------

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

module Codata.Conat.Properties where

open import Size
open import Data.Nat.Base using (ℕ; zero; suc)
open import Codata.Thunk
open import Codata.Conat
open import Codata.Conat.Bisimilarity
open import Function
open import Relation.Nullary
open import Relation.Nullary.Decidable using (map′)
open import Relation.Binary

private
  variable
    i : Size

0∸m≈0 : ∀ m → i ⊢ zero ∸ m ≈ zero
0∸m≈0 zero    = refl
0∸m≈0 (suc m) = 0∸m≈0 m

sℕ≤s⁻¹ : ∀ {m n} → suc m ℕ≤ suc n → m ℕ≤ n .force
sℕ≤s⁻¹ (sℕ≤s p) = p

_ℕ≤?_ : Decidable _ℕ≤_
zero  ℕ≤? n     = yes zℕ≤n
suc m ℕ≤? zero  = no (λ ())
suc m ℕ≤? suc n = map′ sℕ≤s sℕ≤s⁻¹ (m ℕ≤? n .force)

0ℕ+-identity : ∀ {n} → i ⊢ 0 ℕ+ n ≈ n
0ℕ+-identity = refl

+ℕ0-identity : ∀ {n} → i ⊢ n +ℕ 0 ≈ n
+ℕ0-identity {n = zero}  = zero
+ℕ0-identity {n = suc n} = suc λ where .force → +ℕ0-identity


{-# OPTIONS --safe #-}
module Cubical.Algebra.CommAlgebra.Instances.Initial where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism

open import Cubical.Data.Unit
open import Cubical.Data.Sigma.Properties using (Σ≡Prop)

open import Cubical.Algebra.CommRing
open import Cubical.Algebra.Ring
open import Cubical.Algebra.Algebra.Base using (IsAlgebraHom)
open import Cubical.Algebra.CommAlgebra.Base

private
  variable
    ℓ : Level

module _ ((R , str) : CommRing ℓ) where

  initialCAlg : CommAlgebra (R , str) ℓ
  initialCAlg =
    let open CommRingStr str
    in  (R , commalgebrastr _ _ _ _ _ (λ r x → r · x)
                    (makeIsCommAlgebra (isSetRing (CommRing→Ring (R , str)))
                       +Assoc +Rid +Rinv +Comm
                       ·Assoc ·Lid
                       ·Ldist+ ·Comm
                        (λ x y z → sym (·Assoc x y z)) ·Ldist+ ·Rdist+ ·Lid
                         λ x y z → sym (·Assoc x y z)))

  module _ (A : CommAlgebra (R , str) ℓ) where
    open CommAlgebraStr ⦃... ⦄
    private
      instance
        _ : CommAlgebraStr (R , str) (fst A)
        _ = snd A
        _ : CommAlgebraStr (R , str) R
        _ = snd initialCAlg

    _*_ : R → (fst A) → (fst A)
    r * a = CommAlgebraStr._⋆_ (snd A) r a

    initialMap : CommAlgebraHom initialCAlg A
    initialMap =
      makeCommAlgebraHom {M = initialCAlg} {N = A}
        (λ r → r * 1a)
        (⋆-lid _)
        (λ x y → ⋆-ldist x y 1a)
        (λ x y →  (x · y) * 1a ≡⟨ ⋆-assoc _ _ _ ⟩
                           x * (y * 1a)                   ≡[ i ]⟨ x * (·Lid (y * 1a) (~ i)) ⟩
                           x * (1a · (y * 1a))            ≡⟨ sym (⋆-lassoc _ _ _) ⟩
                           (x * 1a) · (y * 1a) ∎)
        (λ r x → (r · x) * 1a   ≡⟨ ⋆-assoc _ _ _ ⟩
                         (r * (x * 1a)) ∎)

    initialMapEq : (f : CommAlgebraHom initialCAlg A)
                   → f ≡ initialMap
    initialMapEq f =
      let open IsAlgebraHom (snd f)
      in Σ≡Prop
           (isPropIsCommAlgebraHom {M = initialCAlg} {N = A})
             λ i x →
               ((fst f) x                              ≡⟨ cong (fst f) (sym (·Rid _)) ⟩
               fst f (x · 1a)                          ≡⟨ pres⋆ x 1a ⟩
               CommAlgebraStr._⋆_ (snd A) x (fst f 1a) ≡⟨ cong
                                                           (λ u → (snd A CommAlgebraStr.⋆ x) u)
                                                           pres1 ⟩
               (CommAlgebraStr._⋆_ (snd A) x 1a) ∎) i

    initialityIso : Iso (CommAlgebraHom initialCAlg A) (Unit* {ℓ = ℓ})
    initialityIso = iso (λ _ → tt*)
                        (λ _ → initialMap)
                        (λ {tt*x → refl})
                        λ f → sym (initialMapEq f)

    initialityPath : CommAlgebraHom initialCAlg A ≡ Unit*
    initialityPath = isoToPath initialityIso


{-# OPTIONS --universe-polymorphism #-}
module Categories.Morphism.Cartesian where

open import Level

open import Categories.Category
open import Categories.Functor hiding (_≡_; _∘_)

record CartesianProperties {o₀ ℓ₀ e₀} {o₁ ℓ₁ e₁}
                           {E : Category o₀ ℓ₀ e₀} {B : Category o₁ ℓ₁ e₁}
                           {p : Functor E B} {e′ e} {φ : E [ e′ , e ]}
                           {e′′ : Category.Obj E} {ψ : E [ e′′ , e ]}
                           {g : B [ Functor.F₀ p e′′ , Functor.F₀ p e′ ]}
                           (pf : Category._≡_ B (Category._∘_ B (Functor.F₁ p φ) g) (Functor.F₁ p ψ)) : Set (o₀ ⊔ ℓ₀ ⊔ e₀ ⊔ ℓ₁ ⊔ e₁) where
  private module E = Category E
  private module B = Category B
  open B using (_∘_; _≡_)
  open E using () renaming (_∘_ to _∘E_; _≡_ to _≡E_)
  open Functor p renaming (F₀ to p₀; F₁ to p₁)

  field
    χ        : E [ e′′ , e′ ]
    ψ≡φ∘χ    : ψ ≡E φ ∘E χ
    p₁[χ]≡g  : p₁ χ ≡ g

    χ-unique : (f : E [ e′′ , e′ ]) → ψ ≡E φ ∘E f → p₁ f ≡ g → f ≡E χ

record Cartesian {o₀ ℓ₀ e₀} {o₁ ℓ₁ e₁} {E : Category o₀ ℓ₀ e₀} {B : Category o₁ ℓ₁ e₁} (p : Functor E B) {e′ e} (φ : E [ e′ , e ]) : Set (o₀ ⊔ ℓ₀ ⊔ e₀ ⊔ ℓ₁ ⊔ e₁) where
  private module E = Category E
  private module B = Category B
  open B using (_∘_; _≡_)
  open E using () renaming (_∘_ to _∘E_; _≡_ to _≡E_)
  open Functor p renaming (F₀ to p₀; F₁ to p₁)

  field
    properties : ∀ {e′′} (ψ : E [ e′′ , e ]) (g : B [ p₀ e′′ , p₀ e′ ]) (pf : p₁ φ ∘ g ≡ p₁ ψ) → CartesianProperties {p = p} pf


module Structure.Operator.Field.VectorSpace where

import      Lvl
open import Structure.Setoid
open import Structure.Operator.Field
open import Structure.Operator.Properties using (associativity ; identityₗ ; distributivityᵣ)
open import Structure.Operator.Vector
open import Structure.Operator
open import Type

private variable ℓ ℓₑ ℓₗ ℓₗₑ : Lvl.Level
private variable T : Type{ℓ}
private variable _+_ _⋅_ : T → T → T

module _
  ⦃ equiv : Equiv{ℓₑ}(T) ⦄
  ⦃ [+]-oper : BinaryOperator(_+_) ⦄
  ⦃ [⋅]-oper : BinaryOperator(_⋅_) ⦄
  (field-structure : Field{T = T}(_+_)(_⋅_))
  where
  open Field(field-structure)

  fieldVectorSpace : VectorSpace(_+_)(_⋅_)(_+_)(_⋅_)
  VectorSpace.scalarField                   fieldVectorSpace = field-structure
  VectorSpace.[⋅ₛᵥ]-binaryOperator          fieldVectorSpace = [⋅]-oper
  VectorSpace.[⋅ₛ][⋅ₛᵥ]-compatibility       fieldVectorSpace = associativity(_⋅_)
  VectorSpace.[⋅ₛᵥ][+ᵥ]-distributivityₗ     fieldVectorSpace = [⋅][+]-distributivityₗ
  VectorSpace.[⋅ₛᵥ][+ₛ][+ᵥ]-distributivityᵣ fieldVectorSpace = distributivityᵣ(_⋅_)(_+_)


module Simple where

open import Data.Nat renaming (_≟_ to _≟ℕ_)
open import Data.Fin hiding (_+_; inject)
open import Data.String hiding (_++_) renaming (_≟_ to _≟S_)
open import Relation.Nullary using (¬_; yes; no)
open import Relation.Binary.PropositionalEquality using (refl; _≡_)

open import Data.List

open import Data.Sum using (_⊎_; inj₁; inj₂)

FName : Set
FName = String

FNames : Set
FNames = List FName

data Expr : ℕ → Set where
   num : ∀ {n} → ℕ → Expr n
   bv  : ∀ {n} → (i : Fin n) → Expr n
   fv  : ∀ {n} → (x : FName) → Expr n
   ƛ   : ∀ {n} → (e : Expr (suc n)) → Expr n
   _·_ : ∀ {n} → (f : Expr n) → (e : Expr n) → Expr n

-- This idx indicates the amount of existence of lambda
-- out of current express

Expr0 : Set
Expr0 = Expr zero

↓ℕ≠ℕ : ∀ {n m} {i : Fin m}
     → ¬ (suc n ≡ toℕ (suc i))
     → ¬ (n ≡ toℕ i)
↓ℕ≠ℕ {n} {m} {i} sn≠si n≡i rewrite n≡i = sn≠si refl
-- ↓ℕ≠ℕ {n} {m} {i} sn≠si n≡i with n≡i
-- ↓ℕ≠ℕ sn≠si n≡i | refl = sn≠si refl

↓fin : ∀ {n} → (i : Fin (suc n)) → ¬ (n ≡ toℕ i) → Fin n
↓fin {zero} zero 0≠0 with 0≠0 refl
↓fin {zero} zero 0≠0 | ()
↓fin {zero} (suc ()) 0≠n
↓fin {suc n} zero i≠0 = zero
↓fin {suc n} (suc i) sn≠si = suc (↓fin i (↓ℕ≠ℕ sn≠si))

↑expr : ∀ {n} → Expr n → Expr (suc n)
↑expr (num i) = num i
↑expr (bv i)   = bv (inject₁ i)
-- inject₁ : ∀ {m} → Fin m → Fin (suc m)
↑expr (fv x)   = fv x
↑expr (ƛ e)    = ƛ (↑expr e)
↑expr (e · e₁) = ↑expr e · ↑expr e₁

{- substitution for bounded and free variable-}

[_↦_] : ∀ n → Expr n → Expr (suc n) → Expr n
[ m ↦ t ] (num i) = num i
[ m ↦ t ] (bv i) with m ≟ℕ toℕ i
... | yes m=i = t
... | no  m≠i = bv (↓fin i m≠i)
[ m ↦ t ] (fv x) = fv x
[ m ↦ t ] (ƛ e) = ƛ ([ suc m ↦ ↑expr t ] e)
[ m ↦ t ] (e · e₁) = [ m ↦ t ] e · [ m ↦ t ] e₁

[_↤_] : ∀ n → FName → Expr n → Expr (suc n)
[ m ↤ name ] (num x)  = num x
[ m ↤ name ] (bv i)   = ↑expr (bv i)
[ m ↤ name ] (fv x)   with x ≟S name
[ m ↤ name ] (fv x) | yes p = bv (fromℕ m)
[ m ↤ name ] (fv x) | no ¬p = fv x
[ m ↤ name ] (ƛ t)    = ƛ ([ suc m ↤ name ] t)
[ m ↤ name ] (t · t₁) = [ m ↤ name ] t · [ m ↤ name ] t₁

[_↝_] : ∀ {n} → FName → Expr n → Expr n → Expr n
[ n ↝ t ] (num i) = num i
[ n ↝ t ] (bv i) = bv i
[ n ↝ t ] (fv x) with n ≟S x
[ n ↝ t ] (fv x) | yes p = t
[ n ↝ t ] (fv x) | no ¬p = fv x
[ n ↝ t ] (ƛ x) = ƛ ([ n ↝ ↑expr t ] x)
[ n ↝ t ] (x · y) = [ n ↝ t ] x · [ n ↝ t ] y

_₀↦_ : Expr 1 → Expr 0 → Expr 0
m ₀↦ t = [ 0 ↦ t ] m

_↦₀_ : FName → Expr 0 → Expr 1
name ↦₀ t = [ 0 ↤ name ] t

_₀↤_ : Expr 0 → FName → Expr 1
t ₀↤ x = [ 0 ↤ x ] t

_₀↝_ : Expr 1 → FName → Expr 0
x ₀↝ s = x ₀↦ (fv s)

fvars : ∀ {n} → Expr n → FNames
fvars (num x) = []
fvars (bv i)  = []
fvars (fv x)  = x ∷ []
fvars (ƛ f)   = fvars f
fvars (f · x) = fvars f ++ fvars x

-- ############################## --
{-         locally closed         -}
-- ############################## --

open import Data.List.Any as Any
open Any.Membership-≡ using (_∈_; _∉_)
open import Data.Product

data LC : ∀ {n} → Expr n → Set where
   numᶜ : ∀ {n} → (i : ℕ) → LC {n} (num i)
   fvᶜ  : ∀ {n}
       → (x : FName)
       → LC {n} (fv x)
   _·ᶜ_ : ∀ {n} {f x}
       → LC {n} f
       → LC {n} x
       → LC {n} (f · x)
   ƛᶜ   : ∀ {e}
       → (ns : FNames)
       → ( ∀ {x} → x ∉ ns → LC {0} (e ₀↦ fv x) )
       → LC {0} (ƛ e)

postulate fresh-gen      : FNames → FName
postulate fresh-gen-spec : ∀ ns → fresh-gen ns ∉ ns

genName : (ns : FNames) → ∃ (λ x → x ∉ ns)
genName ns = fresh-gen ns , fresh-gen-spec ns

orz : ∀ {e} {nn} → nn ↦₀ (e ₀↦ fv nn) ≡ e
orz = {!   !}

foo : ∀ {nn} → (e : Expr 1) → LC {0} (e ₀↦ fv nn) → LC {1} e
foo (num i) lcp = {!   !}
foo (bv i)  lcp = {!   !}
foo (fv y)  lcp = {!   !}
foo (ƛ e)   lcp = {!   !}
foo (f · x) lcp = {!   !}

absᶜ  : ∀ {e} → LC {0} (ƛ e) → LC {1} e
absᶜ (ƛᶜ ns lcex) = {!   !}
   where nn    = proj₁ (genName ns)
         nn∉ns = proj₂ (genName ns)
         x     = lcex {nn} nn∉ns

appᶜ₁ : ∀ {n} {f x} → LC {n} (f · x) → LC {n} f
appᶜ₁ (lcf ·ᶜ lcx) = lcf

appᶜ₂ : ∀ {n} {f x} → LC {n} (f · x) → LC {n} x
appᶜ₂ (lcf ·ᶜ lcx) = lcx

lc? : ∀ {n} → (e : Expr n) → (LC {n} e ⊎ ¬ LC {n} e)
lc? (num x) = inj₁ (numᶜ x)
lc? (bv i)  = inj₂ (λ ())
lc? (fv x)  = inj₁ (fvᶜ x)
lc? (ƛ e)   with lc? e
lc? (ƛ e) | inj₁ x = inj₁ {!   !}
lc? (ƛ e) | inj₂ y = inj₂ {!   !}
lc? (f · x) with lc? f | lc? x
lc? (f · x) | inj₁ f' | inj₁ x' = inj₁ (f' ·ᶜ x')
lc? (f · x) | inj₁ f' | inj₂ x' = inj₂ (λ p → x' (appᶜ₂ p))
lc? (f · x) | inj₂ f' | _       = inj₂ (λ p → f' (appᶜ₁ p))

-- ############################## --
{-       value and semantics      -}
-- ############################## --

data Val : Expr0 → Set where
   num⁰ : ∀ n → Val (num n)
   ƛ⁰   : ∀ e → Val (ƛ e)

var? : (e : Expr0) → (Val e ⊎ ¬ (Val e))
var? (num i) = inj₁ (num⁰ i)
var? (bv i) = inj₂ (λ ())
var? (fv x) = inj₂ (λ ())
var? (ƛ x) = inj₁ (ƛ⁰ x)
var? (x · y) = inj₂ (λ ())

-- don't know what the hell this shit is
data _⟼_ : Expr 0 → Expr 0 → Set where
   app : ∀ {body para}
       → ((ƛ body) · para) ⟼ (body ₀↦ para)


-- Very simple facts about natural numbers
module NatSimple where

import Data.Fin as F

open import Data.Empty
open import Data.Unit
open import Data.Unit.Core
open import Data.Nat renaming (_⊔_ to _⊔ℕ_)
open import Data.Sum renaming (map to _⊎→_)
open import Data.Product renaming (map to _×→_)
open import Function renaming (_∘_ to _○_)
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

open import FT

------------------------------------------------------------------------------
-- Equivalences (not used)

data Dec (A : Set) : Set where
  yes : A → Dec A
  no : (A → ⊥) → Dec A

sucEq : {n : ℕ} → (i j : F.Fin n) → (F.suc i) ≡ (F.suc j) → i ≡ j
sucEq i .i refl = refl

_=F=_ : {n : ℕ} → (i j : F.Fin n) → Dec (i ≡ j)
F.zero    =F= F.zero                     = yes refl
(F.suc i) =F= F.zero                     = no (λ ())
F.zero    =F= (F.suc j)                  = no (λ ())
(F.suc i) =F= (F.suc j) with i =F= j
(F.suc i) =F= (F.suc .i) | yes refl      = yes refl
(F.suc i) =F= (F.suc j) | no p           = no (λ q → p (sucEq i j q))

------------------------------------------------------------------
-- Finite Types and the natural numbers are intimately related.

toℕ : FT → ℕ
toℕ ZERO = zero
toℕ ONE = suc zero
toℕ (PLUS b₀ b₁) = (toℕ b₀) + (toℕ b₁)
toℕ (TIMES b₀ b₁) = (toℕ b₀) * (toℕ b₁)

fromℕ : ℕ → FT
fromℕ zero    = ZERO
fromℕ (suc n) = PLUS ONE (fromℕ n)

normalize : FT → FT
normalize = fromℕ ○ toℕ

assocr : {m : ℕ} (n : ℕ) → (PLUS (fromℕ n) (fromℕ m)) ⇛ fromℕ (n + m)
assocr zero = unite₊⇛
assocr (suc n) = assocr₊⇛ ◎ (id⇛ ⊕ (assocr n))

distr : (n₀ : ℕ) {n₁ : ℕ} → TIMES (fromℕ n₀) (fromℕ n₁) ⇛ fromℕ (n₀ * n₁)
distr zero = distz⇛
distr (suc n) {m} = dist⇛ ◎ (unite⋆⇛ ⊕ distr n) ◎ assocr m

normal : (b : FT) → b ⇛ normalize b
normal ZERO = id⇛
normal ONE = uniti₊⇛ ◎ swap₊⇛
normal (PLUS b₀ b₁) = (normal b₀ ⊕ normal b₁) ◎ assocr (toℕ b₀)
normal (TIMES b₀ b₁) = (normal b₀ ⊗ normal b₁) ◎ distr (toℕ b₀)

-- normalize a finite type to (1 + (1 + (1 + ... + (1 + 0) ... )))
-- a bunch of ones ending with zero with left biased + in between

⟦_⟧ℕ : ℕ → Set
⟦ zero ⟧ℕ  = ⊥
⟦ suc n ⟧ℕ = ⊤ ⊎ ⟦ n ⟧ℕ

-- Take a natural number n, and a value of the type represented by that n,
-- and return the canonical finite set of size n.
fromNormalNat : (n : ℕ) → ⟦ n ⟧ℕ → F.Fin n
fromNormalNat zero     ()
fromNormalNat (suc n) (inj₁ tt) = F.zero
fromNormalNat (suc n) (inj₂ x) = F.suc (fromNormalNat n x)

-- Take a natural number n, a finite set of size n, and return a
-- (canonical) value of the type represented by n
toNormalNat : (n : ℕ) → F.Fin n → ⟦ n ⟧ℕ
toNormalNat zero     ()
toNormalNat (suc n) F.zero = inj₁ tt
toNormalNat (suc n) (F.suc f) = inj₂ (toNormalNat n f)

-- BEGIN CODE COPIED (AND SOMEWHAT MODIFIED) FROM Nat.Properties
-- (for some reason +-comm is a private field so I can't get to it without
-- importing superfluous files and going through a bunch of administrative
-- garbage that isn't worth my time)

m+1+n≡1+m+n : ∀ m n → m + suc n ≡ suc (m + n)
m+1+n≡1+m+n zero    n = refl
m+1+n≡1+m+n (suc m) n = cong suc (m+1+n≡1+m+n m n)

+-identity : {n : ℕ} → n + zero ≡ n
+-identity = n+0≡n _
  where
  n+0≡n : (n : ℕ) → n + zero ≡ n
  n+0≡n zero    = refl
  n+0≡n (suc n) = cong suc (n+0≡n n)

+-comm : (m n : ℕ) → m + n ≡ n + m
+-comm zero    n = sym +-identity
+-comm (suc m) n = begin
    suc m + n
  ≡⟨ refl ⟩
    suc (m + n)
  ≡⟨ cong suc (+-comm m n) ⟩
    suc (n + m)
  ≡⟨ sym (m+1+n≡1+m+n n m) ⟩
    n + suc m
  ∎

-- END CODE COPIED FROM Nat.Properties

--
add1modn : ℕ → ℕ → ℕ → ℕ
add1modn zero zero acc = zero
add1modn zero (suc n) acc = (suc n) + acc
add1modn (suc max) zero acc = suc acc
add1modn (suc max) (suc n) acc = add1modn max n (suc acc)

-- Useful for testing
one : ℕ
one = suc (zero)

two : ℕ
two = suc one

three : ℕ
three = suc two

four : ℕ
four = suc three

five : ℕ
five = suc four

six : ℕ
six = suc five


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

open import LogicalFormulae
open import Semirings.Definition
open import Numbers.Naturals.Definition
open import Numbers.Naturals.Semiring
open import Orders.Total.Definition
open import Orders.Partial.Definition

module Numbers.Naturals.Order where
open Semiring ℕSemiring
open import Decidable.Lemmas ℕDecideEquality

private
  infix 5 _<NLogical_
  _<NLogical_ : ℕ → ℕ → Set
  zero <NLogical zero = False
  zero <NLogical (succ n) = True
  (succ n) <NLogical zero = False
  (succ n) <NLogical (succ m) = n <NLogical m

infix 5 _<N_
record _<N_ (a : ℕ) (b : ℕ) : Set where
  constructor le
  field
    x : ℕ
    proof : (succ x) +N a ≡ b

infix 5 _<N'_
record _<N'_ (a : ℕ) (b : ℕ) : Set where
  constructor le'
  field
    x : ℕ
    .proof : (succ x) +N a ≡ b

infix 5 _≤N_
_≤N_ : ℕ → ℕ → Set
a ≤N b = (a <N b) || (a ≡ b)

succIsPositive : (a : ℕ) → zero <N succ a
succIsPositive a = le a (applyEquality succ (Semiring.commutative ℕSemiring a 0))

aLessSucc : (a : ℕ) → (a <NLogical succ a)
aLessSucc zero = record {}
aLessSucc (succ a) = aLessSucc a

private
  succPreservesInequalityLogical : {a b : ℕ} → (a <NLogical b) → (succ a <NLogical succ b)
  succPreservesInequalityLogical {a} {b} prAB = prAB

  lessTransitiveLogical : {a b c : ℕ} → (a <NLogical b) → (b <NLogical c) → (a <NLogical c)
  lessTransitiveLogical {a} {zero} {zero} prAB prBC = prAB
  lessTransitiveLogical {a} {(succ b)} {zero} prAB ()
  lessTransitiveLogical {zero} {zero} {(succ c)} prAB prBC = record {}
  lessTransitiveLogical {(succ a)} {zero} {(succ c)} () prBC
  lessTransitiveLogical {zero} {(succ b)} {(succ c)} prAB prBC = record {}
  lessTransitiveLogical {(succ a)} {(succ b)} {(succ c)} prAB prBC = lessTransitiveLogical {a} {b} {c} prAB prBC

  aLessXPlusSuccA : (a x : ℕ) → (a <NLogical x +N succ a)
  aLessXPlusSuccA a zero = aLessSucc a
  aLessXPlusSuccA zero (succ x) = record {}
  aLessXPlusSuccA (succ a) (succ x) = lessTransitiveLogical {a} {succ a} {x +N succ (succ a)} (aLessXPlusSuccA a zero) (aLessXPlusSuccA (succ a) x)

  leImpliesLogical<N : {a b : ℕ} → (a <N b) → (a <NLogical b)
  leImpliesLogical<N {zero} {zero} (le x ())
  leImpliesLogical<N {zero} {(succ b)} (le x proof) = record {}
  leImpliesLogical<N {(succ a)} {zero} (le x ())
  leImpliesLogical<N {(succ a)} {(succ .(succ a))} (le zero refl) = aLessSucc a
  leImpliesLogical<N {(succ a)} {(succ .(succ (x +N succ a)))} (le (succ x) refl) = succPreservesInequalityLogical {a} {succ (x +N succ a)} (lessTransitiveLogical {a} {succ a} {succ (x +N succ a)} (aLessSucc a) (aLessXPlusSuccA a x))

  logical<NImpliesLe : {a b : ℕ} → (a <NLogical b) → (a <N b)
  logical<NImpliesLe {zero} {zero} ()
  _<N_.x (logical<NImpliesLe {zero} {succ b} prAB) = b
  _<N_.proof (logical<NImpliesLe {zero} {succ b} prAB) = applyEquality succ (sumZeroRight b)
  logical<NImpliesLe {(succ a)} {zero} ()
  logical<NImpliesLe {(succ a)} {(succ b)} prAB with logical<NImpliesLe {a} prAB
  logical<NImpliesLe {(succ a)} {(succ .(succ (x +N a)))} prAB | le x refl = le x (applyEquality succ (transitivity (commutative x _) (applyEquality succ (commutative a _))))

lessTransitive : {a b c : ℕ} → (a <N b) → (b <N c) → (a <N c)
lessTransitive {a} {b} {c} prab prbc = logical<NImpliesLe (lessTransitiveLogical {a} {b} {c} (leImpliesLogical<N prab) (leImpliesLogical<N prbc))

lessIrreflexive : {a : ℕ} → (a <N a) → False
lessIrreflexive {zero} pr = leImpliesLogical<N pr
lessIrreflexive {succ a} pr = lessIrreflexive {a} (logical<NImpliesLe {a} {a} (leImpliesLogical<N {succ a} {succ a} pr))

succPreservesInequality : {a b : ℕ} → (a <N b) → (succ a <N succ b)
succPreservesInequality {a} {b} prAB = logical<NImpliesLe (succPreservesInequalityLogical {a} {b} (leImpliesLogical<N prAB))

canRemoveSuccFrom<N : {a b : ℕ} → (succ a <N succ b) → (a <N b)
canRemoveSuccFrom<N {a} {b} (le x proof) rewrite commutative x (succ a) | commutative a x = le x (succInjective proof)

a<SuccA : (a : ℕ) → a <N succ a
a<SuccA a = le zero refl

<NWellDefined : {a b : ℕ} → (p1 : a <N b) → (p2 : a <N b) → _<N_.x p1 ≡ _<N_.x p2
<NWellDefined {a} {b} (le x proof) (le y proof1) = equalityCommutative r
  where
    q : y +N a ≡ x +N a
    q = succInjective {y +N a} {x +N a} (transitivity proof1 (equalityCommutative proof))
    r : y ≡ x
    r = canSubtractFromEqualityRight q

canAddToOneSideOfInequality : {a b : ℕ} (c : ℕ) → a <N b → a <N (b +N c)
canAddToOneSideOfInequality {a} {b} c (le x proof) = le (x +N c) (transitivity (applyEquality succ (equalityCommutative (+Associative x c a))) (transitivity (applyEquality (λ i → (succ x) +N i) (commutative c a)) (transitivity (applyEquality succ (+Associative x a c)) (applyEquality (_+N c) proof))))

canAddToOneSideOfInequality' : {a b : ℕ} (c : ℕ) → a <N b → a <N (c +N b)
canAddToOneSideOfInequality' {a} {b} c (le x proof) = le (x +N c) ans
  where
    ans : succ ((x +N c) +N a) ≡ c +N b
    ans rewrite (equalityCommutative (+Associative x c a)) | commutative c a | (+Associative x a c) = transitivity (applyEquality (_+N c) proof) (commutative b c)

addingIncreases : (a b : ℕ) → a <N a +N succ b
addingIncreases zero b = succIsPositive b
addingIncreases (succ a) b = succPreservesInequality (addingIncreases a b)

zeroNeverGreater : {a : ℕ} → (a <N zero) → False
zeroNeverGreater {a} (le x ())

noIntegersBetweenXAndSuccX : {a : ℕ} (x : ℕ) → (x <N a) → (a <N succ x) → False
noIntegersBetweenXAndSuccX {zero} x x<a a<sx = zeroNeverGreater x<a
noIntegersBetweenXAndSuccX {succ a} x (le y proof) (le z proof1) with succInjective proof1
... | ah rewrite (equalityCommutative proof) | (succExtracts z (y +N x)) | +Associative (succ z) y x | commutative (succ (z +N y)) x = lessIrreflexive {x} (le (z +N y) (transitivity (commutative _ x) ah))

private
  orderIsTotal : (a b : ℕ) → ((a <N b) || (b <N a)) || (a ≡ b)
  orderIsTotal zero zero = inr refl
  orderIsTotal zero (succ b) = inl (inl (logical<NImpliesLe (record {})))
  orderIsTotal (succ a) zero = inl (inr (logical<NImpliesLe (record {})))
  orderIsTotal (succ a) (succ b) with orderIsTotal a b
  orderIsTotal (succ a) (succ b) | inl (inl x) = inl (inl (logical<NImpliesLe (leImpliesLogical<N x)))
  orderIsTotal (succ a) (succ b) | inl (inr x) = inl (inr (logical<NImpliesLe (leImpliesLogical<N x)))
  orderIsTotal (succ a) (succ b) | inr x = inr (applyEquality succ x)

  orderIsIrreflexive : {a b : ℕ} → (a <N b) → (b <N a) → False
  orderIsIrreflexive {zero} {b} prAB (le x ())
  orderIsIrreflexive {(succ a)} {zero} (le x ()) prBA
  orderIsIrreflexive {(succ a)} {(succ b)} prAB prBA = orderIsIrreflexive {a} {b} (logical<NImpliesLe (leImpliesLogical<N prAB)) (logical<NImpliesLe (leImpliesLogical<N prBA))

  orderIsTransitive : {a b c : ℕ} → (a <N b) → (b <N c) → (a <N c)
  orderIsTransitive {a} {.(succ (x +N a))} {.(succ (y +N succ (x +N a)))} (le x refl) (le y refl) = le (y +N succ x) (applyEquality succ (equalityCommutative (+Associative y (succ x) a)))

ℕTotalOrder : TotalOrder ℕ
PartialOrder._<_ (TotalOrder.order ℕTotalOrder) = _<N_
PartialOrder.irreflexive (TotalOrder.order ℕTotalOrder) = lessIrreflexive
PartialOrder.<Transitive (TotalOrder.order ℕTotalOrder) = orderIsTransitive
TotalOrder.totality ℕTotalOrder = orderIsTotal

cannotAddAndEnlarge : (a b : ℕ) → a <N succ (a +N b)
cannotAddAndEnlarge a b = le b (applyEquality succ (commutative b a))

cannotAddAndEnlarge' : {a b : ℕ} → a +N b <N a → False
cannotAddAndEnlarge' {a} {zero} pr rewrite sumZeroRight a = lessIrreflexive pr
cannotAddAndEnlarge' {a} {succ b} pr rewrite (succExtracts a b) = lessIrreflexive {a} (lessTransitive {a} {succ (a +N b)} {a} (cannotAddAndEnlarge a b) pr)

cannotAddAndEnlarge'' : {a b : ℕ} → a +N succ b ≡ a → False
cannotAddAndEnlarge'' {a} {b} pr = naughtE (equalityCommutative inter)
  where
    inter : succ b ≡ 0
    inter rewrite commutative a (succ b) = canSubtractFromEqualityRight pr

naturalsAreNonnegative : (a : ℕ) → (a <N zero) → False
naturalsAreNonnegative zero ()
naturalsAreNonnegative (succ x) ()

lessRespectsAddition : {a b : ℕ} (c : ℕ) → (a <N b) → ((a +N c) <N (b +N c))
lessRespectsAddition {a} {b} zero prAB rewrite commutative a 0 | commutative b 0 = prAB
lessRespectsAddition {a} {b} (succ c) prAB rewrite commutative a (succ c) | commutative b (succ c) | commutative c a | commutative c b = succPreservesInequality (lessRespectsAddition c prAB)

lessRespectsMultiplicationLeft : (a b c : ℕ) → (a <N b) → (zero <N c) → (c *N a <N c *N b)
lessRespectsMultiplicationLeft zero zero c (le x ()) cPos
lessRespectsMultiplicationLeft zero (succ b) zero prAB (le x ())
lessRespectsMultiplicationLeft zero (succ b) (succ c) prAB cPos = i
  where
    productNonzeroIsNonzero : {a b : ℕ} → zero <N a → zero <N b → zero <N a *N b
    productNonzeroIsNonzero {zero} {b} prA prB = prA
    productNonzeroIsNonzero {succ a} {zero} prA ()
    productNonzeroIsNonzero {succ a} {succ b} prA prB = le (b +N a *N succ b) (applyEquality succ (Semiring.sumZeroRight ℕSemiring _))

    j : zero <N succ c *N succ b
    j = productNonzeroIsNonzero cPos prAB
    i : succ c *N zero <N succ c *N succ b
    i = identityOfIndiscernablesLeft _<N_ j (equalityCommutative (productZeroRight c))
lessRespectsMultiplicationLeft (succ a) zero c (le x ()) cPos
lessRespectsMultiplicationLeft (succ a) (succ b) c prAB cPos = m
  where
    h : c *N a <N c *N b
    h = lessRespectsMultiplicationLeft a b c (canRemoveSuccFrom<N prAB) cPos
    j : c *N a +N c <N c *N b +N c
    j = lessRespectsAddition c h
    i : c *N succ a <N c *N b +N c
    i = identityOfIndiscernablesLeft _<N_ j (equalityCommutative (transitivity (multiplicationNIsCommutative c _) (transitivity (applyEquality (c +N_) (multiplicationNIsCommutative a _)) (commutative c _))))
    m : c *N succ a <N c *N succ b
    m = identityOfIndiscernablesRight _<N_ i (equalityCommutative (transitivity (multiplicationNIsCommutative c _) (transitivity (commutative c _) (applyEquality (_+N c) (multiplicationNIsCommutative b _)))))

canFlipMultiplicationsInIneq : {a b c d : ℕ} → (a *N b <N c *N d) → b *N a <N d *N c
canFlipMultiplicationsInIneq {a} {b} {c} {d} pr = identityOfIndiscernablesRight _<N_ (identityOfIndiscernablesLeft _<N_ pr (multiplicationNIsCommutative a b)) (multiplicationNIsCommutative c d)

lessRespectsMultiplication : (a b c : ℕ) → (a <N b) → (zero <N c) → (a *N c <N b *N c)
lessRespectsMultiplication a b c prAB cPos = canFlipMultiplicationsInIneq {c} {a} {c} {b} (lessRespectsMultiplicationLeft a b c prAB cPos)

squash<N : {a b : ℕ} → .(a <N b) → a <N b
squash<N {a} {b} a<b with orderIsTotal a b
... | inl (inl x) = x
... | inl (inr x) = exFalso (lessIrreflexive (orderIsTransitive x a<b))
squash<N {a} {b} a<b | inr refl = exFalso (lessIrreflexive a<b)

<NTo<N' : {a b : ℕ} → a <N b → a <N' b
<NTo<N' (le x proof) = le' x proof

<N'To<N : {a b : ℕ} → a <N' b → a <N b
<N'To<N {a} {b} (le' x proof) = le x (squash proof)

<N'Refl : {a b : ℕ} → (p1 p2 : a <N' b) → p1 ≡ p2
<N'Refl p1 p2 with <NWellDefined (<N'To<N p1) (<N'To<N p2)
... | refl = refl


{-# OPTIONS --safe #-}
module Cubical.Algebra.NatSolver.HornerForms where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Nat hiding (isZero)
open import Cubical.Data.FinData
open import Cubical.Data.Vec
open import Cubical.Data.Bool using (Bool; true; false; if_then_else_)

private
  variable
    ℓ : Level

{-
  This defines the type of multivariate Polynomials over ℕ.
  The construction is based on the algebraic fact

    ℕ[X₀][X₁]⋯[Xₙ] ≅ ℕ[X₀,⋯,Xₙ]

  BUT: Contrary to algebraic convetions, we will give 'Xₙ' the lowest index
  in the definition of 'Variable' below. So if 'Variable n k' is identified
  with 'Xₖ', what we construct should rather be denoted with

    ℕ[Xₙ][Xₙ₋₁]⋯[X₀]

  or, to be precise about the evaluation order:

    (⋯((ℕ[Xₙ])[Xₙ₋₁])⋯)[X₀]

-}

data IteratedHornerForms : ℕ → Type ℓ-zero where
  const : ℕ → IteratedHornerForms ℕ.zero
  0H : {n : ℕ} → IteratedHornerForms (ℕ.suc n)
  _·X+_ : {n : ℕ} → IteratedHornerForms (ℕ.suc n) → IteratedHornerForms n
                  → IteratedHornerForms (ℕ.suc n)

eval : {n : ℕ} (P : IteratedHornerForms n)
       → Vec ℕ n → ℕ
eval (const r) [] = r
eval 0H (_ ∷ _) = 0
eval (P ·X+ Q) (x ∷ xs) =
  (eval P (x ∷ xs)) · x + eval Q xs

module IteratedHornerOperations where

  private
    1H' : (n : ℕ) → IteratedHornerForms n
    1H' ℕ.zero = const 1
    1H' (ℕ.suc n) = 0H ·X+ 1H' n

    0H' : (n : ℕ) → IteratedHornerForms n
    0H' ℕ.zero = const 0
    0H' (ℕ.suc n) = 0H

  1ₕ : {n : ℕ} → IteratedHornerForms n
  1ₕ {n = n} = 1H' n

  0ₕ : {n : ℕ} → IteratedHornerForms n
  0ₕ {n = n} = 0H' n

  X : (n : ℕ) (k : Fin n) → IteratedHornerForms n
  X (ℕ.suc m) zero = 1ₕ ·X+ 0ₕ
  X (ℕ.suc m) (suc k) = 0ₕ ·X+ X m k

  _+ₕ_ : {n : ℕ} → IteratedHornerForms n → IteratedHornerForms n
               → IteratedHornerForms n
  (const r) +ₕ (const s) = const (r + s)
  0H +ₕ Q = Q
  (P ·X+ r) +ₕ 0H = P ·X+ r
  (P ·X+ r) +ₕ (Q ·X+ s) = (P +ₕ Q) ·X+ (r +ₕ s)

  isZero : {n : ℕ} → IteratedHornerForms (ℕ.suc n)
                   → Bool
  isZero 0H = true
  isZero (P ·X+ P₁) = false

  _⋆_ : {n : ℕ} → IteratedHornerForms n → IteratedHornerForms (ℕ.suc n)
                → IteratedHornerForms (ℕ.suc n)
  _·ₕ_ : {n : ℕ} → IteratedHornerForms n → IteratedHornerForms n
                → IteratedHornerForms n
  r ⋆ 0H = 0H
  r ⋆ (P ·X+ Q) = (r ⋆ P) ·X+ (r ·ₕ Q)

  const x ·ₕ const y = const (x · y)
  0H ·ₕ Q = 0H
  (P ·X+ Q) ·ₕ S =
     let
        z = (P ·ₕ S)
     in if (isZero z)
        then (Q ⋆ S)
        else (z ·X+ 0ₕ) +ₕ (Q ⋆ S)

Variable : (n : ℕ) (k : Fin n) → IteratedHornerForms n
Variable n k = IteratedHornerOperations.X n k

Constant : (n : ℕ) (r : ℕ) → IteratedHornerForms n
Constant ℕ.zero r = const r
Constant (ℕ.suc n) r = IteratedHornerOperations.0ₕ ·X+ Constant n r


import      Lvl
open import Structure.Setoid
open import Type

module Automaton.TuringMachine where

open import Data.Boolean
import      Data.Boolean.Operators
open        Data.Boolean.Operators.Programming
open import Data.Either as Either using (_‖_)
open import Data.Either.Setoid
open import Data.Option as Option
open import Data.Option.Functions as Option
open import Data.Option.Setoid
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Data.Tuple.Equivalence
open import Data.List renaming (∅ to ε ; _⊰_ to _·_)
open import Data.List.Setoid
open import Functional
open import Logic
open import Relator.Equals.Proofs.Equivalence
open import Structure.Operator
open import Structure.Relator
open import Structure.Relator.Properties
open import Syntax.Transitivity
open import Type.Size.Finite

private variable ℓₚ ℓₛ ℓₐ ℓₑₛ ℓₑₐ : Lvl.Level
private variable Alphabet : Type{ℓₐ}

data Direction : Type{Lvl.𝟎} where
  Backward : Direction
  Stay     : Direction
  Forward  : Direction
private instance _ = [≡]-equiv {T = Direction}

record Tape (Alphabet : Type{ℓₐ}) : Type{ℓₐ} where
  coinductive
  field
    back    : Tape(Alphabet)
    current : Alphabet
    front   : Tape(Alphabet)

  update : (Alphabet → Alphabet) → Tape(Alphabet)
  back   (update _) = back
  current(update f) = f(current)
  front  (update _) = front

stepBackward : Tape(Alphabet) → Tape(Alphabet)
Tape.back   (stepBackward t) = Tape.back(Tape.back t)
Tape.current(stepBackward t) = Tape.current(Tape.back t)
Tape.front  (stepBackward t) = t

stepForward : Tape(Alphabet) → Tape(Alphabet)
Tape.back   (stepForward t) = t
Tape.current(stepForward t) = Tape.current(Tape.front t)
Tape.front  (stepForward t) = Tape.front(Tape.front t)

stepInDirection : Direction → Tape(Alphabet) → Tape(Alphabet)
stepInDirection Backward = stepBackward
stepInDirection Stay     = id
stepInDirection Forward  = stepForward

module _ ⦃ equiv-alphabet : Equiv{ℓₑₐ}(Alphabet) ⦄ where
  step-inverseₗᵣ : ∀{t : Tape(Alphabet)} → (Tape.current(stepBackward(stepForward(t))) ≡ Tape.current(t))
  step-inverseₗᵣ = reflexivity(_≡_ ⦃ equiv-alphabet ⦄)

  step-inverseᵣₗ : ∀{t : Tape(Alphabet)} → (Tape.current(stepBackward(stepForward(t))) ≡ Tape.current(t))
  step-inverseᵣₗ = reflexivity(_≡_ ⦃ equiv-alphabet ⦄)

module _
  (State : Type{ℓₛ})    ⦃ equiv-state : Equiv{ℓₑₛ}(State) ⦄
  (Alphabet : Type{ℓₐ}) ⦃ equiv-alphabet : Equiv{ℓₑₐ}(Alphabet) ⦄
  where

  private instance _ = [≡]-equiv {T = Bool}

  -- Turing machine
  -- `State`      (Q)  is the set of states.
  -- `Alphabet`   (Σ)  is the set of symbols/the alphabet.
  -- `transition` (δ)  is the transition function.
  -- `start`      (q₀) is the start state.
  -- `Final`      (F)  is the subset of State which are the final/accepting states.
  record TuringMachine : Type{ℓₛ Lvl.⊔ ℓₑₐ Lvl.⊔ ℓₑₛ Lvl.⊔ ℓₐ Lvl.⊔ Lvl.𝐒(ℓₚ)} where
    constructor turingMachine
    field
      ⦃ State-finite ⦄              : Finite(State)
      ⦃ Alphabet-finite ⦄           : Finite(Alphabet)
      transition                    : State → Option(Alphabet) → Option(State ⨯ Alphabet ⨯ Direction)
      ⦃ transition-binaryOperator ⦄ : BinaryOperator(transition)
      start                         : State
      Final                         : State → Type{ℓₚ}
      ⦃ Final-unaryRelator ⦄        : UnaryRelator(Final)

    -- isFinal : State → Bool

  -- TODO: Not sure what the best (most easy to use) formalization of a TM would be or if this is correct
  Configuration = State ⨯ Tape(Option(Alphabet))
  module Configuration where
    step : TuringMachine{ℓₚ} → (Configuration → Option(Configuration))
    step tm (s , t) = Option.map (\(ns , nx , dir) → (ns , stepInDirection dir (Tape.update t (Some ∘ const nx)))) (TuringMachine.transition tm s (Tape.current t))


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

module ConcretePermutationProperties where

open import Relation.Binary.PropositionalEquality
  using (_≡_; refl; sym; trans; cong; module ≡-Reasoning; proof-irrelevance)

--

-- open import FinVecProperties using (∘̂-assoc; ∘̂-lid; ∘̂-rid)
open import ConcretePermutation
------------------------------------------------------------------------------
-- Properties of vectors where are only used to prove some properties
-- of concrete permutations -> do not export them.
private
  open import Data.Nat using (ℕ)
  open import Data.Fin using (Fin)
  open import Data.Vec using (Vec)
  open import Data.Vec.Properties using (lookup-allFin)
  open import Proofs using (finext; lookupassoc; _!!_)

  ∘̂-assoc : {m₁ m₂ m₃ m₄ : ℕ} →
           (a : Vec (Fin m₂) m₁) (b : Vec (Fin m₃) m₂) (c : Vec (Fin m₄) m₃) →
           a ∘̂ (b ∘̂ c) ≡ (a ∘̂ b) ∘̂ c
  ∘̂-assoc a b c = finext (lookupassoc a b c)

  ∘̂-rid : {m n : ℕ} → (π : Vec (Fin m) n) → π ∘̂ 1C ≡ π
  ∘̂-rid π = trans (finext (λ i → lookup-allFin (π !! i))) (cauchyext π)

  ∘̂-lid : {m n : ℕ} → (π : Vec (Fin m) n) → 1C ∘̂ π ≡ π
  ∘̂-lid π = trans (finext (λ i → cong (_!!_ π) (lookup-allFin i))) (cauchyext π)

------------------------------------------------------------------------------
-- Properties of concrete permutations that are needed to show that
-- this is also a symmetric rig groupoid

-- If the forward components are equal, then so are the backward ones

πᵒ≡ : ∀ {m n} → (π₁ π₂ : CPerm m n) → (CPerm.π π₁ ≡ CPerm.π π₂) →
      (CPerm.πᵒ π₁ ≡ CPerm.πᵒ π₂)
πᵒ≡ {n} (cp π πᵒ αp βp) (cp .π πᵒ₁ αp₁ βp₁) refl =
  begin (
    πᵒ                  ≡⟨ sym (∘̂-rid πᵒ) ⟩
    πᵒ ∘̂ 1C          ≡⟨  cong (_∘̂_ πᵒ) (sym αp₁)  ⟩
    πᵒ ∘̂ (π ∘̂ πᵒ₁)      ≡⟨ ∘̂-assoc πᵒ π πᵒ₁ ⟩
    (πᵒ ∘̂ π) ∘̂ πᵒ₁      ≡⟨ cong (λ x → x ∘̂ πᵒ₁) βp ⟩
    1C ∘̂ πᵒ₁            ≡⟨ ∘̂-lid πᵒ₁ ⟩
    πᵒ₁ ∎)
  where open ≡-Reasoning

-- If the forward components are equal, then so are the entire
-- concrete permutations

p≡ : ∀ {m n} → {π₁ π₂ : CPerm m n} → (CPerm.π π₁ ≡ CPerm.π π₂) → π₁ ≡ π₂
p≡ {m} {n} {cp π πᵒ αp βp} {cp .π πᵒ₁ αp₁ βp₁} refl with
  πᵒ≡ (cp π πᵒ αp βp) (cp π πᵒ₁ αp₁ βp₁) refl
p≡ {m} {n} {cp π πᵒ αp βp} {cp .π .πᵒ αp₁ βp₁} refl | refl
  with proof-irrelevance αp αp₁ | proof-irrelevance βp βp₁
p≡ {m} {n} {cp π πᵒ αp βp} {cp .π .πᵒ .αp .βp} refl | refl | refl | refl = refl

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


{-# OPTIONS --cubical #-}
module Cubical.Foundations.Equiv.Fiberwise where

open import Cubical.Core.Everything

open import Cubical.Foundations.Everything

module _ {a p q} {A : Type a} (P : A → Type p) (Q : A → Type q)
         (f : ∀ x → P x → Q x)
         where
  private
    total : (Σ A P) → (Σ A Q)
    total = (\ p → p .fst , f (p .fst) (p .snd))

  -- Thm 4.7.6
  fibers-total : ∀ {xv} → Iso (fiber total (xv)) (fiber (f (xv .fst)) (xv .snd))
  fibers-total {xv} = iso h g h-g g-h
   where
    h : ∀ {xv} → fiber total xv → fiber (f (xv .fst)) (xv .snd)
    h {xv} (p , eq) = J (\ xv eq → fiber (f (xv .fst)) (xv .snd)) ((p .snd) , refl) eq
    g : ∀ {xv} → fiber (f (xv .fst)) (xv .snd) → fiber total xv
    g {xv} (p , eq) = (xv .fst , p) , (\ i → _ , eq i)
    h-g : ∀ {xv} y → h {xv} (g {xv} y) ≡ y
    h-g {x , v} (p , eq) = J (λ _ eq₁ → h (g (p , eq₁)) ≡ (p , eq₁)) (JRefl (λ xv₁ eq₁ → fiber (f (xv₁ .fst)) (xv₁ .snd)) ((p , refl))) (eq)
    g-h : ∀ {xv} y → g {xv} (h {xv} y) ≡ y
    g-h {xv} ((a , p) , eq) = J (λ _ eq₁ → g (h ((a , p) , eq₁)) ≡ ((a , p) , eq₁))
                                (cong g (JRefl (λ xv₁ eq₁ → fiber (f (xv₁ .fst)) (xv₁ .snd)) (p , refl)))
                                eq
  -- half of Thm 4.7.7 (fiberwise equivalences)
  fiberEquiv : ([tf] : isEquiv total)
               → ∀ x → isEquiv (f x)
  fiberEquiv [tf] x .equiv-proof y = retractIsContr (fibers-total .Iso.inv) (fibers-total .Iso.fun) (fibers-total .Iso.rightInv)
                                                    ([tf] .equiv-proof (x , y))

module _ {ℓ : Level} {U : Type ℓ} {ℓr} (_~_ : U → U → Type ℓr)
         (idTo~ : ∀ {A B} → A ≡ B → A ~ B)
         (c : ∀ A → isContr (Σ U \ X → A ~ X))
       where

  isContrToUniv : ∀ {A B} → isEquiv (idTo~ {A} {B})
  isContrToUniv {A} {B}
    = fiberEquiv (λ z → A ≡ z) (λ z → A ~ z) (\ B → idTo~ {A} {B})
                 (λ { .equiv-proof y
                    → isContrSigma ((_ , refl) , (\ z → contrSingl (z .snd)))
                                   \ a → isContrPath (c A) _ _
                    })
                 B


module Numeral.Natural.UnclosedOper where

import Lvl
open import Data
open import Data.Boolean.Stmt
open import Data.Option as Option using (Option)
open import Data.Option.Functions as Option
open import Logic.Propositional
open import Numeral.Finite as 𝕟
  using (𝕟)
import      Numeral.Finite.Bound as 𝕟bound
open import Numeral.Integer as ℤ
  using (ℤ)
open import Numeral.Natural
open import Numeral.Natural.Oper
open import Numeral.Natural.Oper.Comparisons
open import Numeral.Natural.Oper.Modulo
open import Numeral.Natural.Oper.Modulo.Proofs
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Decidable
open import Numeral.Natural.Relation.Order.Proofs
import      Numeral.Sign as Sign
open import Type.Properties.Decidable.Proofs

infix  10010 _−_

-- TODO _/_ : ℕ → ℕ → ℚ

-- Unclosed total subtraction from natural numbers to an optional natural number.
-- When the subtraction gives a negative number semantically, this operation gives Option.None.
_−?_ : ℕ → ℕ → Option(ℕ)
a    −? 𝟎    = Option.Some(a)
𝟎    −? 𝐒(b) = Option.None
𝐒(a) −? 𝐒(b) = a −? b

-- Unclosed total floored division
{-# TERMINATING #-}
_⌊/₀⌋_ : ℕ → ℕ → ℕ
𝐒(x) ⌊/₀⌋ 𝐒(y) with (𝐒(x) −? 𝐒(y))
... | Option.Some(𝐒x𝐒y) = 𝐒(𝐒x𝐒y ⌊/₀⌋ 𝐒(y))
... | Option.None       = 𝟎
{-# CATCHALL #-}
_    ⌊/₀⌋ _    = 𝟎

-- Unclosed total subtraction from natural numbers to an optional natural number.
-- When dividing by 0, this operation gives Option.None.
{-# TERMINATING #-}
_⌊/⌋?_ : ℕ → ℕ → Option(ℕ)
_    ⌊/⌋? 𝟎    = Option.None
𝟎    ⌊/⌋? 𝐒(_) = Option.Some(𝟎)
𝐒(x) ⌊/⌋? 𝐒(y) with (𝐒(x) −? 𝐒(y))
... | Option.Some(𝐒x𝐒y) = Option.map 𝐒(𝐒x𝐒y ⌊/⌋? 𝐒(y))
... | Option.None       = Option.Some(𝟎)

-- Unclosed total subtraction from natural numbers to an optional natural number.
-- When dividing by 0 or the division gives a rational number semantically, this operation gives Option.None.
{-# TERMINATING #-}
_/?_ : ℕ → ℕ → Option(ℕ)
_    /? 𝟎    = Option.None
𝟎    /? 𝐒(_) = Option.Some(𝟎)
𝐒(x) /? 𝐒(y) with (𝐒(x) −? 𝐒(y))
... | Option.Some(𝐒x𝐒y) = Option.map 𝐒(𝐒x𝐒y /? 𝐒(y))
... | Option.None       = Option.None

-- Unclosed total subtraction from natural numbers to finite natural numbers
_−₀fin_ : (x : ℕ) → ℕ → 𝕟(𝐒(x))
𝟎    −₀fin _    = 𝕟.𝟎
𝐒(x) −₀fin 𝟎    = 𝕟.𝐒(x −₀fin 𝟎)
𝐒(x) −₀fin 𝐒(y) = 𝕟bound.bound-𝐒 (x −₀fin y)

-- Unclosed total subtraction from a natural number and a finite natural number to a finite natural number
_−fin_ : (x : ℕ) → 𝕟(𝐒(x)) → 𝕟(𝐒(x))
𝟎    −fin 𝕟.𝟎    = 𝕟.𝟎
𝐒(x) −fin 𝕟.𝟎    = 𝕟.𝐒(x −fin 𝕟.𝟎)
𝐒(x) −fin 𝕟.𝐒(y) = 𝕟bound.bound-𝐒 (x −fin y)

-- Modulo operation to upper bounded natural numbers.
_modfin_ : ℕ → (b : ℕ) → ⦃ _ : IsTrue(b ≢? 𝟎) ⦄ → 𝕟(b)
a modfin 𝐒 b = 𝕟.ℕ-to-𝕟 (a mod 𝐒(b)) ⦃ [↔]-to-[→] decider-true (mod-maxᵣ{a}{𝐒 b}) ⦄


------------------------------------------------------------------------
-- The Agda standard library
--
-- Half adjoint equivalences
------------------------------------------------------------------------

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

module Function.HalfAdjointEquivalence where

open import Function
open import Function.Equality using (_⟨$⟩_)
open import Function.Inverse as Inv using (_↔_; module Inverse)
open import Level
open import Relation.Binary.PropositionalEquality

-- Half adjoint equivalences (see the HoTT book).

record _≃_ {a b} (A : Set a) (B : Set b) : Set (a ⊔ b) where
  field
    to               : A → B
    from             : B → A
    left-inverse-of  : ∀ x → from (to x) ≡ x
    right-inverse-of : ∀ x → to (from x) ≡ x
    left-right       :
      ∀ x → cong to (left-inverse-of x) ≡ right-inverse-of (to x)

  -- Half adjoint equivalences can be turned into inverses.

  inverse : A ↔ B
  inverse = Inv.inverse to from left-inverse-of right-inverse-of

  -- The forward direction of a half adjoint equivalence is injective.

  injective : ∀ {x y} → to x ≡ to y → x ≡ y
  injective {x} {y} to-x≡to-y =
    x            ≡⟨ sym (left-inverse-of _) ⟩
    from (to x)  ≡⟨ cong from to-x≡to-y ⟩
    from (to y)  ≡⟨ left-inverse-of _ ⟩
    y            ∎
    where
    open ≡-Reasoning

-- Inverses can be turned into half adjoint equivalences.
--
-- (This proof is based on one in the HoTT book.)

↔→≃ : ∀ {a b} {A : Set a} {B : Set b} → A ↔ B → A ≃ B
↔→≃ A↔B = record
  { to               = to   ⟨$⟩_
  ; from             = from ⟨$⟩_
  ; left-inverse-of  = left-inverse-of
  ; right-inverse-of = right-inverse-of
  ; left-right       = left-right
  }
  where
  open ≡-Reasoning
  open module A↔B = Inverse A↔B using (to; from; left-inverse-of)

  right-inverse-of : ∀ x → to ⟨$⟩ (from ⟨$⟩ x) ≡ x
  right-inverse-of x =
    to ⟨$⟩ (from ⟨$⟩ x)                      ≡⟨ sym (A↔B.right-inverse-of _) ⟩
    to ⟨$⟩ (from ⟨$⟩ (to ⟨$⟩ (from ⟨$⟩ x)))  ≡⟨ cong (to ⟨$⟩_) (left-inverse-of _) ⟩
    to ⟨$⟩ (from ⟨$⟩ x)                      ≡⟨ A↔B.right-inverse-of _ ⟩
    x                                        ∎

  left-right :
    ∀ x →
    cong (to ⟨$⟩_) (left-inverse-of x) ≡ right-inverse-of (to ⟨$⟩ x)
  left-right x =
    cong (to ⟨$⟩_) (left-inverse-of x)               ≡⟨⟩

    trans refl (cong (to ⟨$⟩_) (left-inverse-of _))  ≡⟨ cong (λ p → trans p (cong (to ⟨$⟩_) _))
                                                          (sym (trans-symˡ (A↔B.right-inverse-of _))) ⟩
    trans (trans (sym (A↔B.right-inverse-of _))
               (A↔B.right-inverse-of _))
      (cong (to ⟨$⟩_) (left-inverse-of _))           ≡⟨ trans-assoc (sym (A↔B.right-inverse-of _)) ⟩

    trans (sym (A↔B.right-inverse-of _))
      (trans (A↔B.right-inverse-of _)
         (cong (to ⟨$⟩_) (left-inverse-of _)))       ≡⟨ cong (trans (sym (A↔B.right-inverse-of _))) lemma ⟩

    trans (sym (A↔B.right-inverse-of _))
      (trans (cong (to ⟨$⟩_) (left-inverse-of _))
         (trans (A↔B.right-inverse-of _) refl))      ≡⟨⟩

    right-inverse-of (to ⟨$⟩ x)                      ∎
    where
    lemma =
      trans (A↔B.right-inverse-of _)
        (cong (to ⟨$⟩_) (left-inverse-of _))             ≡⟨ cong (trans (A↔B.right-inverse-of _)) (sym (cong-id _)) ⟩

      trans (A↔B.right-inverse-of _)
        (cong id (cong (to ⟨$⟩_) (left-inverse-of _)))   ≡⟨ sym (naturality A↔B.right-inverse-of) ⟩

      trans (cong ((to ⟨$⟩_) ∘ (from ⟨$⟩_))
                 (cong (to ⟨$⟩_) (left-inverse-of _)))
        (A↔B.right-inverse-of _)                         ≡⟨ cong (λ p → trans p (A↔B.right-inverse-of _))
                                                              (sym (cong-∘ _)) ⟩
      trans (cong ((to ⟨$⟩_) ∘ (from ⟨$⟩_) ∘ (to ⟨$⟩_))
                      (left-inverse-of _))
        (A↔B.right-inverse-of _)                         ≡⟨ cong (λ p → trans p (A↔B.right-inverse-of _))
                                                              (cong-∘ _) ⟩
      trans (cong (to ⟨$⟩_)
                 (cong ((from ⟨$⟩_) ∘ (to ⟨$⟩_))
                    (left-inverse-of _)))
        (A↔B.right-inverse-of _)                         ≡⟨ cong (λ p → trans (cong (to ⟨$⟩_) p) _)
                                                              (cong-≡id left-inverse-of) ⟩
      trans (cong (to ⟨$⟩_) (left-inverse-of _))
        (A↔B.right-inverse-of _)                         ≡⟨ cong (trans (cong (to ⟨$⟩_) (left-inverse-of _)))
                                                              (sym (trans-reflʳ _)) ⟩
      trans (cong (to ⟨$⟩_) (left-inverse-of _))
        (trans (A↔B.right-inverse-of _) refl)            ∎