module Prelude.Int.Properties where

open import Prelude.Unit
open import Prelude.Nat
open import Prelude.Nat.Properties
open import Prelude.Number
open import Prelude.Equality
open import Prelude.Int.Core
open import Prelude.Smashed
open import Prelude.Ord
open import Prelude.Semiring
open import Prelude.Function

--- Specification functions ---
---   sucInt   a   =  1 + a
---   predInt  a   = -1 + a
---   sucsInt  n a = pos n + a
---   predsInt n a = neg n + a
---   diffNat  a b = a -NZ b

sucInt : Int → Int
sucInt (pos n)          = pos (suc n)
sucInt (negsuc zero)    = pos zero
sucInt (negsuc (suc n)) = negsuc n

predInt : Int → Int
predInt (pos zero)    = negsuc zero
predInt (pos (suc n)) = pos n
predInt (negsuc n)    = negsuc (suc n)

sucsInt : Nat → Int → Int
sucsInt zero    b = b
sucsInt (suc a) b = sucInt (sucsInt a b)

predsInt : Nat → Int → Int
predsInt zero    b = b
predsInt (suc a) b = predInt (predsInt a b)

diffNat : Nat → Nat → Int
diffNat a       zero    = pos a
diffNat zero    (suc b) = negsuc b
diffNat (suc a) (suc b) = diffNat a b

--- Injectivity proofs ---

pos-inj : ∀ {a b} → pos a ≡ pos b → a ≡ b
pos-inj refl = refl

negsuc-inj : ∀ {a b} → negsuc a ≡ negsuc b → a ≡ b
negsuc-inj refl = refl

neg-inj : ∀ {a b} → neg a ≡ neg b → a ≡ b
neg-inj {zero}  {zero}  eq = refl
neg-inj {zero}  {suc b} ()
neg-inj {suc a} {zero}  ()
neg-inj {suc a} {suc b} eq = suc $≡ negsuc-inj eq

negate-inj : {a b : Int} → negate a ≡ negate b → a ≡ b
negate-inj {pos    a}    {pos    b}    eq = pos $≡ neg-inj eq
negate-inj {pos  zero}   {negsuc b}    ()
negate-inj {pos (suc a)} {negsuc b}    ()
negate-inj {negsuc a}    {pos zero}    ()
negate-inj {negsuc a}    {pos (suc _)} ()
negate-inj {negsuc a}    {negsuc b}    eq = negsuc $≡ suc-inj (pos-inj eq)

sucInt-inj : ∀ a b → sucInt a ≡ sucInt b → a ≡ b
sucInt-inj (pos a)          (pos a)          refl = refl
sucInt-inj (pos a)          (negsuc zero)    ()
sucInt-inj (pos a)          (negsuc (suc b)) ()
sucInt-inj (negsuc zero)    (pos b) ()
sucInt-inj (negsuc (suc a)) (pos b) ()
sucInt-inj (negsuc zero)    (negsuc zero)    eq = refl
sucInt-inj (negsuc zero)    (negsuc (suc b)) ()
sucInt-inj (negsuc (suc a)) (negsuc zero)    ()
sucInt-inj (negsuc (suc a)) (negsuc (suc a)) refl = refl

predInt-inj : ∀ a b → predInt a ≡ predInt b → a ≡ b
predInt-inj (pos zero)    (pos zero)    eq = refl
predInt-inj (pos zero)    (pos (suc b)) ()
predInt-inj (pos (suc a)) (pos zero)    ()
predInt-inj (pos (suc a)) (pos (suc a)) refl = refl
predInt-inj (pos zero)    (negsuc b)    ()
predInt-inj (pos (suc a)) (negsuc b)    ()
predInt-inj (negsuc a)    (pos zero)    ()
predInt-inj (negsuc a)    (pos (suc b)) ()
predInt-inj (negsuc a)    (negsuc a)    refl = refl

--- sucInt and predInt are inverses --

sucInt-predInt : ∀ a → sucInt (predInt a) ≡ a
sucInt-predInt (pos zero)    = refl
sucInt-predInt (pos (suc n)) = refl
sucInt-predInt (negsuc n)    = refl

predInt-sucInt : ∀ a → predInt (sucInt a) ≡ a
predInt-sucInt (pos n)          = refl
predInt-sucInt (negsuc zero)    = refl
predInt-sucInt (negsuc (suc n)) = refl

--- Commutativity of _+_ is easy

addInt-commute : (a b : Int) → a + b ≡ b + a
addInt-commute (pos    a) (pos    b) = pos $≡ add-commute a b
addInt-commute (pos    a) (negsuc b) = refl
addInt-commute (negsuc a) (pos    b) = refl
addInt-commute (negsuc a) (negsuc b) = negsuc ∘ suc $≡ add-commute a b

--- Proving _-NZ_ == diffNat

-NZ-suc : ∀ a b → suc a -NZ suc b ≡ a -NZ b
-NZ-suc a b rewrite smashed {x = compare (suc a) (suc b)} {suc-comparison (compare a b)}
            with    compare a b
... | less    (diff! k) = refl
... | equal   eq        = refl
... | greater (diff! k) = refl

-NZ-spec : ∀ a b → a -NZ b ≡ diffNat a b
-NZ-spec zero    zero    = refl
-NZ-spec (suc a) zero    = refl
-NZ-spec zero    (suc b) = refl
-NZ-spec (suc a) (suc b) = -NZ-suc a b ⟨≡⟩ -NZ-spec a b

--- diffNat distributes over suc in both arguments...

diffNat-suc-l : ∀ a b → diffNat (suc a) b ≡ sucInt (diffNat a b)
diffNat-suc-l a       0             = refl
diffNat-suc-l 0       1             = refl
diffNat-suc-l 0       (suc (suc b)) = refl
diffNat-suc-l (suc a) (suc b)       = diffNat-suc-l a b

diffNat-suc-r : ∀ a b → diffNat a (suc b) ≡ predInt (diffNat a b)
diffNat-suc-r zero    zero    = refl
diffNat-suc-r zero    (suc b) = refl
diffNat-suc-r (suc a) zero    = refl
diffNat-suc-r (suc a) (suc b) = diffNat-suc-r a b

--- ...and thus so does _-NZ_

-NZ-suc-l : ∀ a b → suc a -NZ b ≡ sucInt (a -NZ b)
-NZ-suc-l a b = -NZ-spec (suc a) b ⟨≡⟩ diffNat-suc-l a b ⟨≡⟩ʳ sucInt $≡ -NZ-spec a b

-NZ-suc-r : ∀ a b → a -NZ suc b ≡ predInt (a -NZ b)
-NZ-suc-r a b = -NZ-spec a (suc b) ⟨≡⟩ diffNat-suc-r a b ⟨≡⟩ʳ predInt $≡ -NZ-spec a b

--- We need some lemmas about how sucInt and predInt relates to _+_.
--- These are special cases of the computation rules below, so we make them private.

private
  sucInt-spec : ∀ a → 1 + a ≡ sucInt a
  sucInt-spec (pos n)          = refl
  sucInt-spec (negsuc zero)    = refl
  sucInt-spec (negsuc (suc n)) = refl

  predInt-spec : ∀ a → -1 + a ≡ predInt a
  predInt-spec (pos zero)    = refl
  predInt-spec (pos (suc n)) = -NZ-spec (suc n) 1
  predInt-spec (negsuc n)    = refl

  addInt-suc : ∀ a b → pos (suc a) + b ≡ sucInt (pos a + b)
  addInt-suc a (pos    b) = refl
  addInt-suc a (negsuc b) = -NZ-suc-l a (suc b)

  addInt-negsuc : ∀ a b → negsuc (suc a) + b ≡ predInt (negsuc a + b)
  addInt-negsuc a (pos b)    = -NZ-suc-r b (suc a)
  addInt-negsuc a (negsuc b) = refl

--- Now we can prove some "computation" rules for _+_

addInt-zero-l : (a : Int) → 0 + a ≡ a
addInt-zero-l (pos a)    = refl
addInt-zero-l (negsuc a) = -NZ-spec 0 (suc a)

addInt-zero-r : (a : Int) → a + 0 ≡ a
addInt-zero-r (pos a)    = pos $≡ add-zero-r a
addInt-zero-r (negsuc a) = -NZ-spec 0 (suc a)

addInt-sucInt-l : ∀ a b → sucInt a + b ≡ sucInt (a + b)
addInt-sucInt-l (pos a)          b = addInt-suc a b
addInt-sucInt-l (negsuc zero)    b = addInt-zero-l b ⟨≡⟩ʳ sucInt $≡ predInt-spec b ⟨≡⟩ sucInt-predInt b
addInt-sucInt-l (negsuc (suc a)) b = sucInt-predInt (negsuc a + b) ʳ⟨≡⟩ʳ sucInt $≡ addInt-negsuc a b

addInt-predInt-l : ∀ a b → predInt a + b ≡ predInt (a + b)
addInt-predInt-l (pos zero)    b = predInt-spec b ⟨≡⟩ʳ predInt $≡ addInt-zero-l b
addInt-predInt-l (pos (suc a)) b = predInt-sucInt (pos a + b) ʳ⟨≡⟩ʳ predInt $≡ addInt-suc a b
addInt-predInt-l (negsuc a)    b = addInt-negsuc a b

--- Adding a non-negative number is equivalent to sucsInt and adding a negative number
--- to predsInt.

addInt-pos : ∀ a b → pos a + b ≡ sucsInt a b
addInt-pos zero    b = addInt-zero-l b
addInt-pos (suc a) b = addInt-suc a b ⟨≡⟩ sucInt $≡ addInt-pos a b

addInt-neg : ∀ a b → neg a + b ≡ predsInt a b
addInt-neg zero          b = addInt-zero-l b
addInt-neg (suc zero)    b = addInt-predInt-l 0 b ⟨≡⟩ predInt $≡ addInt-zero-l b -- predInt-spec b
addInt-neg (suc (suc a)) b = addInt-predInt-l (negsuc a) b ⟨≡⟩ predInt $≡ addInt-neg (suc a) b

--- sucsInt and predsInt have the appropriate associativity properties

private
  sucsInt-assoc : ∀ a b c → sucsInt a (b + c) ≡ sucsInt a b + c
  sucsInt-assoc zero    b c = refl
  sucsInt-assoc (suc a) b c = sucInt $≡ sucsInt-assoc a b c ⟨≡⟩ʳ
                              addInt-sucInt-l (sucsInt a b) c

  predsInt-assoc : ∀ a b c → predsInt a (b + c) ≡ predsInt a b + c
  predsInt-assoc zero    b c = refl
  predsInt-assoc (suc a) b c = predInt $≡ predsInt-assoc a b c ⟨≡⟩ʳ
                               addInt-predInt-l (predsInt a b) c

--- Finally we can prove associativity of _+_

addInt-assoc : (a b c : Int) → a + (b + c) ≡ (a + b) + c
addInt-assoc (pos    a) b c = addInt-pos a (b + c)       ⟨≡⟩ sucsInt-assoc a b c        ⟨≡⟩ʳ _+ c $≡ addInt-pos a b
addInt-assoc (negsuc a) b c = addInt-neg (suc a) (b + c) ⟨≡⟩ predsInt-assoc (suc a) b c ⟨≡⟩ʳ _+ c $≡ addInt-neg (suc a) b

--- Injectivity of _+_

private
  sucsInt-inj : ∀ a b c → sucsInt a b ≡ sucsInt a c → b ≡ c
  sucsInt-inj zero    b c eq = eq
  sucsInt-inj (suc a) b c eq = sucsInt-inj a b c (sucInt-inj _ _ eq)

  predsInt-inj : ∀ a b c → predsInt a b ≡ predsInt a c → b ≡ c
  predsInt-inj zero    b c eq = eq
  predsInt-inj (suc a) b c eq = predsInt-inj a b c (predInt-inj _ _ eq)

addInt-inj₂ : (a b c : Int) → a + b ≡ a + c → b ≡ c
addInt-inj₂ (pos a)    b c eq = sucsInt-inj  a b c                  (addInt-pos a b       ʳ⟨≡⟩ eq ⟨≡⟩ addInt-pos a c)
addInt-inj₂ (negsuc a) b c eq = predsInt-inj a b c (predInt-inj _ _ (addInt-neg (suc a) b ʳ⟨≡⟩ eq ⟨≡⟩ addInt-neg (suc a) c))

addInt-inj₁ : (a b c : Int) → a + c ≡ b + c → a ≡ b
addInt-inj₁ a b c eq = addInt-inj₂ c a b (addInt-commute c a ⟨≡⟩ eq ⟨≡⟩ addInt-commute b c)

--- Properties of negate ---

negate-idempotent : (a : Int) → negate (negate a) ≡ a
negate-idempotent (pos zero)    = refl
negate-idempotent (pos (suc n)) = refl
negate-idempotent (negsuc n)    = refl

private
  neg-add : ∀ a b → neg (a + b) ≡ neg a + neg b
  neg-add zero    b       = sym (addInt-zero-l (neg b))
  neg-add (suc a) zero    = negsuc $≡ add-zero-r a ⟨≡⟩ʳ -NZ-spec 0 (suc a)
  neg-add (suc a) (suc b) = negsuc $≡ add-suc-r a b

  negate-diffNat : ∀ a b → negate (diffNat a b) ≡ diffNat b a
  negate-diffNat zero    zero    = refl
  negate-diffNat zero    (suc b) = refl
  negate-diffNat (suc a) zero    = refl
  negate-diffNat (suc a) (suc b) = negate-diffNat a b

negate-NZ : ∀ a b → negate (a -NZ b) ≡ b -NZ a
negate-NZ a b = negate $≡ -NZ-spec a b ⟨≡⟩ negate-diffNat a b ⟨≡⟩ʳ -NZ-spec b a

negate-addInt : (a b : Int) → negate (a + b) ≡ negate a + negate b
negate-addInt (pos a)       (pos b)       = neg-add a b
negate-addInt (pos zero)    (negsuc b)    = refl
negate-addInt (pos (suc a)) (negsuc b)    = negate-NZ (suc a) (suc b)
negate-addInt (negsuc a)    (pos zero)    = pos ∘ suc $≡ sym (add-zero-r a)
negate-addInt (negsuc a)    (pos (suc b)) = negate-NZ (suc b) (suc a)
negate-addInt (negsuc a)    (negsuc b)    = pos $≡ sym (add-suc-r (suc a) b)

negate-subInt : (a b : Int) → negate (a - b) ≡ b - a
negate-subInt a b = negate-addInt a (negate b) ⟨≡⟩
                    negate a +_ $≡ negate-idempotent b ⟨≡⟩
                    addInt-commute (negate a) b

--- Properties of subtraction ---

private
  diffNat-equal : ∀ a → diffNat a a ≡ 0
  diffNat-equal zero = refl
  diffNat-equal (suc a) = diffNat-equal a

subInt-equal : (a b : Int) → a ≡ b → a - b ≡ 0
subInt-equal (pos zero)    _ refl = refl
subInt-equal (pos (suc n)) _ refl = -NZ-spec (suc n) (suc n) ⟨≡⟩ diffNat-equal n
subInt-equal (negsuc n)    _ refl = -NZ-spec (suc n) (suc n) ⟨≡⟩ diffNat-equal n


{-# OPTIONS --without-K --safe #-}
module Categories.Category.Helper where

open import Level
open import Relation.Binary using (Rel; IsEquivalence)

open import Categories.Category.Core using (Category)

-- Since we add extra proofs in the definition of `Category` (i.e. `sym-assoc` and
-- `identity²`), we might still want to construct a `Category` in its originally
-- easier manner. Thus, this redundant definition is here to ease the construction.
record CategoryHelper (o ℓ e : Level) : Set (suc (o ⊔ ℓ ⊔ e)) where
  infix  4 _≈_ _⇒_
  infixr 9 _∘_

  field
    Obj : Set o
    _⇒_ : Rel Obj ℓ
    _≈_ : ∀ {A B} → Rel (A ⇒ B) e

    id  : ∀ {A} → (A ⇒ A)
    _∘_ : ∀ {A B C} → (B ⇒ C) → (A ⇒ B) → (A ⇒ C)

  field
    assoc     : ∀ {A B C D} {f : A ⇒ B} {g : B ⇒ C} {h : C ⇒ D} → (h ∘ g) ∘ f ≈ h ∘ (g ∘ f)
    identityˡ : ∀ {A B} {f : A ⇒ B} → id ∘ f ≈ f
    identityʳ : ∀ {A B} {f : A ⇒ B} → f ∘ id ≈ f
    equiv     : ∀ {A B} → IsEquivalence (_≈_ {A} {B})
    ∘-resp-≈  : ∀ {A B C} {f h : B ⇒ C} {g i : A ⇒ B} → f ≈ h → g ≈ i → f ∘ g ≈ h ∘ i

categoryHelper : ∀ {o ℓ e} → CategoryHelper o ℓ e → Category o ℓ e
categoryHelper C = record
  { Obj       = Obj
  ; _⇒_       = _⇒_
  ; _≈_       = _≈_
  ; id        = id
  ; _∘_       = _∘_
  ; assoc     = assoc
  ; sym-assoc = sym assoc
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; identity² = identityˡ
  ; equiv     = equiv
  ; ∘-resp-≈  = ∘-resp-≈
  }
  where open CategoryHelper C
        module _ {A B} where
          open IsEquivalence (equiv {A} {B}) public


------------------------------------------------------------------------
-- INCREMENTAL λ-CALCULUS
--
-- Variables and contexts
--
-- This module defines the syntax of contexts and subcontexts,
-- together with variables and properties of these notions.
--
-- This module is parametric in the syntax of types, so it
-- can be reused for different calculi.
------------------------------------------------------------------------

module Base.Syntax.Context
    (Type : Set)
  where

open import Relation.Binary
open import Relation.Binary.PropositionalEquality

-- Typing Contexts
-- ===============

import Data.List as List
open import Base.Data.ContextList public

Context : Set
Context = List.List Type

-- Variables
-- =========
--
-- Here it is clear that we are using de Bruijn indices,
-- encoded as natural numbers, more or less.
data Var : Context → Type → Set where
  this : ∀ {Γ τ} → Var (τ • Γ) τ
  that : ∀ {Γ σ τ} → (x : Var Γ τ) → Var (σ • Γ) τ

-- Weakening
-- =========
--
-- We define weakening based on subcontext relationship.

-- Subcontexts
-- -----------
--
-- Useful as a reified weakening operation,
-- and for making theorems strong enough to prove by induction.
--
-- The contents of this module are currently exported at the end
-- of this file.

-- This handling of contexts is recommended by [this
-- email](https://lists.chalmers.se/pipermail/agda/2011/003423.html) and
-- attributed to Conor McBride.
--
-- The associated thread discusses a few alternatives solutions, including one
-- where beta-reduction can handle associativity of ++.

module Subcontexts where
  infix 4 _≼_

  data _≼_ : (Γ₁ Γ₂ : Context) → Set where
    ∅ : ∅ ≼ ∅
    keep_•_ : ∀ {Γ₁ Γ₂} →
      (τ : Type) →
      Γ₁ ≼ Γ₂ →
      τ • Γ₁ ≼ τ • Γ₂
    drop_•_ : ∀ {Γ₁ Γ₂} →
      (τ : Type) →
      Γ₁ ≼ Γ₂ →
      Γ₁ ≼ τ • Γ₂

  -- Properties

  ∅≼Γ : ∀ {Γ} → ∅ ≼ Γ
  ∅≼Γ {∅} = ∅
  ∅≼Γ {τ • Γ} = drop τ • ∅≼Γ

  ≼-refl : Reflexive _≼_
  ≼-refl {∅} = ∅
  ≼-refl {τ • Γ} = keep τ • ≼-refl

  ≼-reflexive : ∀ {Γ₁ Γ₂} → Γ₁ ≡ Γ₂ → Γ₁ ≼ Γ₂
  ≼-reflexive refl = ≼-refl

  ≼-trans : Transitive _≼_
  ≼-trans ≼₁ ∅ = ≼₁
  ≼-trans (keep .τ • ≼₁) (keep τ • ≼₂) = keep τ • ≼-trans ≼₁ ≼₂
  ≼-trans (drop .τ • ≼₁) (keep τ • ≼₂) = drop τ • ≼-trans ≼₁ ≼₂
  ≼-trans ≼₁ (drop τ • ≼₂) = drop τ • ≼-trans ≼₁ ≼₂

  ≼-isPreorder : IsPreorder _≡_ _≼_
  ≼-isPreorder = record
    { isEquivalence = isEquivalence
    ; reflexive = ≼-reflexive
    ; trans = ≼-trans
    }

  ≼-preorder : Preorder _ _ _
  ≼-preorder = record
    { Carrier = Context
    ; _≈_ = _≡_
    ; _∼_ = _≼_
    ; isPreorder = ≼-isPreorder
    }

  module ≼-Reasoning where
    open import Relation.Binary.PreorderReasoning ≼-preorder public
      renaming
        ( _≈⟨_⟩_ to _≡⟨_⟩_
        ; _∼⟨_⟩_ to _≼⟨_⟩_
        ; _≈⟨⟩_ to _≡⟨⟩_
        )

  -- Lift a variable to a super context

  weaken-var : ∀ {Γ₁ Γ₂ τ} → Γ₁ ≼ Γ₂ → Var Γ₁ τ → Var Γ₂ τ
  weaken-var (keep τ • ≼₁) this = this
  weaken-var (keep τ • ≼₁) (that x) = that (weaken-var ≼₁ x)
  weaken-var (drop τ • ≼₁) x = that (weaken-var ≼₁ x)

-- Currently, we export the subcontext relation.

open Subcontexts public


-- Andreas, 2015-06-24

open import Common.Equality
open import Common.Product

Sing : {A : Set} (a : A) → Set
Sing a = ∃ λ b → a ≡ b

works : {A : Set} (f : ∀{a : A} → Sing a) (a : A) → Sing a
works f a = let b , p = f {_} in b , p

test : {A : Set} (f : ∀{a : A} → Sing a) (a : A) → Sing a
test f a = let b , p = f in b , p

-- ERROR WAS:
-- Type mismatch
-- when checking that the pattern b , p has type
-- {a = a₁ : .A} → Sing a₁

-- should work now


{-# OPTIONS --without-K #-}
module Wow-It-is-FV where

open import Agda.Builtin.Nat
open import Agda.Builtin.Equality
open import Agda.Primitive

levelEq : lzero ≡ lzero
levelEq = refl

levelEq′ : lsuc lzero ≡ lsuc lzero
levelEq′ = refl

trans : {l : Level} {Q : Set l} {a b c : Q}
      → a ≡ b → b ≡ c → a ≡ c
trans refl refl = refl

J : {A : Set} (P : (x y : A) → x ≡ y → Set)
  → ((x : A) → P x x refl)
  → (x y : A) (xy : x ≡ y) → P x y xy
J P p x .x refl = p x

cong : {A B : Set} (f : A → B)
     → {m n : A} → m ≡ n → f m ≡ f n
cong f refl = refl

sym : {A : Set} {m n : A} → m ≡ n → n ≡ m
sym refl = refl

theorem : suc zero + suc zero ≡ _
theorem = refl

theorem′ : 1 + 1 ≡ 2
theorem′ = refl

trivialEq : {a : _} {A : Set a} → A ≡ A
trivialEq = refl

trivialEq′ : ∀ {a} {A : Set a} → A ≡ A
trivialEq′ = refl

trivialEq′′ : ∀ a b → a + b ≡ a + b
trivialEq′′ a b = refl

trans′ : ∀ {a} {A : Set a} (a b c : A)
       → a ≡ b → b ≡ c → a ≡ c
trans′ a .a c refl bc = bc

data _<=_ : (a b : Nat) → Set where
  0ltn : ∀ {n}   → 0 <= n
  nltm : ∀ {n m} → n <= m → suc n <= suc m

7lt13 : 7 <= 13
7lt13 = nltm (nltm (nltm (nltm (nltm (nltm (nltm 0ltn))))))

abc : ∀ {a b c} → a <= b → b <= c → a <= c
abc 0ltn bc = 0ltn
abc (nltm ab) (nltm bc) = nltm (abc ab bc)

data ⊥ : Set where

ridiculous : ⊥ → ⊥
ridiculous a = a

ridiculous′ : 1 ≡ 0 → ⊥
ridiculous′ ()

⊥-elim : ∀ {a} {A : Set a} → ⊥ → A
⊥-elim ()

4lt3 : 4 <= 3 → ⊥
4lt3 (nltm (nltm (nltm ())))

infix 3 ¬_
¬_ : ∀ {a} → Set a → Set a
¬ P = P → ⊥

_!=_ : ∀ {a} {A : Set a} → A → A → Set a
x != y = ¬ x ≡ y

_≡⟨_⟩_ : ∀ {A : Set} (x : A) {y z : A} → x ≡ y → y ≡ z → x ≡ z
_ ≡⟨ refl ⟩ c = c

_QED : ∀ {A : Set} (x : A) → x ≡ x
_ QED = refl

lemma₀ : ∀ n → n + 0 ≡ n
lemma₀ zero = refl
lemma₀ (suc n) = cong suc (lemma₀ n)

lemma₁ : ∀ n m → suc (n + m) ≡ n + suc m
lemma₁ zero _ = refl
lemma₁ (suc n) m = cong suc (lemma₁ n m)

comm : ∀ n m → n + m ≡ m + n
comm zero n = sym (lemma₀ n)
comm (suc n) m = suc n + m
  ≡⟨ refl ⟩ suc (n + m)
  ≡⟨ cong suc (comm n m) ⟩ suc (m + n)
  ≡⟨ lemma₁ m n ⟩ m + suc n QED

infixr 2 _≡⟨_⟩_
infix 3 _QED


module Data.Finitude.Exponent where
open import Data.Finitude
open import Data.Fin as Fin using (Fin; toℕ)
open import Data.Nat
open import Data.Vec as Vec
open import Relation.Binary.PropositionalEquality as P
open import Data.Nat.DivMod
open import Relation.Nullary.Decidable
open import Function
open import Function.Equality as F using (_⟶_; _⟨$⟩_; _⇨_)
open import Function.Inverse as Inv using (module Inverse; Inverse)
open import Data.Product
open import Data.Sum
open import Data.Empty
open import Relation.Binary

exponent : ∀ {m} {n} → Finitude (P.setoid (Vec (Fin m) n)) (m ^ n)
exponent {m} {n} = record {
    to = P.→-to-⟶ to
  ; from = P.→-to-⟶ from
  ; inverse-of = record {
      left-inverse-of = from∘to
    ; right-inverse-of = to∘from {m}{n}
    }
  }
  where
    open import Data.Nat.Properties
    open import Data.Fin.Properties hiding (≤-refl; _≟_; <-cmp)
    open import Relation.Nullary.Negation
    shift : ∀ {m n} (i : Fin m)(j : Fin n) → toℕ j + (toℕ i) * n < m * n
    shift {m}{n} i j =
              begin suc (toℕ j) + toℕ i * n
                ≤⟨ +-mono-≤ (toℕ<n j) (≤-refl {(toℕ i) * n}) ⟩
                  n + toℕ i * n
                ≤⟨ *-mono-≤ (toℕ<n i) ≤-refl ⟩ m * n ∎
          where
            open ≤-Reasoning
    to : ∀ {m n} → Vec (Fin m) n → Fin (m ^ n)
    to [] = Fin.zero
    to {m}{n = suc n} (i ∷ is) = Fin.fromℕ≤ (shift i (to is))

    suci^j≢0  : ∀ i j → suc i ^ j ≢ 0
    suci^j≢0 i j eq with i^j≡0⇒i≡0 _ j eq
    ... | ()

    from : ∀ {m n} → Fin (m ^ n) → Vec (Fin m) n
    from {m} {zero} i = []
    from {zero} {suc n} ()
    from {suc m} {suc n} i with ((toℕ i) divMod (suc m ^ n))
      {≢0 = fromWitnessFalse (suci^j≢0 _ n)}
    from {suc m} {suc n} i | result quotient remainder property
      = Fin.fromℕ≤ q<sm  ∷ from remainder
      where
        q<sm : quotient < suc m
        q<sm = ≰⇒> (λ sm≤q → <⇒≱ (toℕ<n i)
                (begin (suc m) * (suc m ^ n)
                   ≤⟨ *-mono-≤ sm≤q ≤-refl ⟩ quotient * (suc m ^ n)
                   ≤⟨ +-mono-≤ (z≤n {toℕ remainder}) ≤-refl ⟩ toℕ remainder + quotient * (suc m ^ n)
                   ≡⟨ P.sym property ⟩ toℕ i ∎))
              where
                open ≤-Reasoning
    ≢→<⊎> : ∀ {m n} → m ≢ n → m < n ⊎ n < m
    ≢→<⊎> {m}{n} m≢n  with <-cmp m n
    ≢→<⊎> {m} {n} m≢n | tri<  m<n _ _ = inj₁ m<n
    ≢→<⊎> {m} {n} m≢n | tri≈ _ m≡n _ = ⊥-elim (m≢n m≡n)
    ≢→<⊎> {m} {n} m≢n | tri> _ _ n<m = inj₂ n<m

    chn : ∀ m → ∀ {k₀ k₁} {r₀ r₁ : Fin m} → toℕ r₀ + k₀ * m  ≡ toℕ r₁ + k₁ * m → k₀ ≡ k₁ × r₀ ≡ r₁
    chn zero {k₀} {k₁} {()} {r₁} _
    chn (suc m) {k₀} {k₁} {r₀} {r₁} eq = k₀≡k₁ , r₀≡r₁
      where
        open ≤-Reasoning
        contra : k₀ ≢ k₁ → ⊥
        contra k₀≢k₁ with ≢→<⊎> k₀≢k₁
        ... | inj₁ k₀<k₁ = <⇒≱  (toℕ<n r₀) (+-cancelʳ-≤ (suc m) (toℕ r₀)
                                 (begin suc m + k₀ * suc m
                                   ≡⟨ refl ⟩ suc k₀ * suc m
                                   ≤⟨ *-mono-≤ (m≤m+n (suc k₀) (k₁ ∸ suc k₀)) (≤-refl {suc m}) ⟩
                                          (suc k₀ + (k₁ ∸ suc k₀)) * suc m
                                   ≡⟨ P.cong₂ _*_ (m+n∸m≡n k₀<k₁) refl ⟩ k₁ * suc m
                                   ≤⟨ n≤m+n (toℕ r₁) (k₁ * suc m)  ⟩ toℕ r₁ + k₁ * suc m
                                   ≡⟨ P.sym eq ⟩ toℕ r₀ + k₀ * suc m ∎))
        ... | inj₂ k₁<k₀ = <⇒≱  (toℕ<n r₁) (+-cancelʳ-≤  (suc m) (toℕ r₁)
                  (begin suc k₁ * suc m
                         ≤⟨ *-mono-≤ (m≤m+n (suc k₁) (k₀ ∸ suc k₁)) (≤-refl {suc m}) ⟩
                         (suc k₁ + (k₀ ∸ suc k₁)) * suc m
                         ≡⟨ P.cong₂ _*_ (m+n∸m≡n k₁<k₀) refl ⟩ k₀ * suc m
                         ≤⟨ n≤m+n  (toℕ r₀) (k₀ * suc m) ⟩ toℕ r₀ + k₀ * suc m
                         ≡⟨ eq ⟩ toℕ r₁ + k₁ * suc m  ∎ ))
        k₀≡k₁ : k₀ ≡ k₁
        k₀≡k₁ = decidable-stable (k₀ ≟ k₁) contra

        r₀≡r₁ : r₀ ≡ r₁
        r₀≡r₁ = toℕ-injective (+-cancelʳ-≡ (toℕ r₀) (toℕ r₁)
          (P.subst (λ k → toℕ r₀ + k * (suc m)  ≡ toℕ r₁ + k₁ * (suc m)) k₀≡k₁ eq))

    from∘to : ∀ {m n}(is : Vec (Fin m) n) → from (to is) ≡ is
    from∘to {m} {.0} [] = P.refl
    from∘to {zero} {.(suc _)} (() ∷ is)
    from∘to {suc m} {suc n} (i ∷ is) with to (i ∷ is) | P.inspect to (i ∷ is)
    from∘to {suc m} {suc n} (i ∷ is) | j | Reveal_·_is_.[ eq ] with P.cong toℕ eq
    ... | eq2 rewrite toℕ-fromℕ≤ (shift i (to is)) with ((toℕ j) divMod (suc m ^ n))
      {≢0 = fromWitnessFalse (suci^j≢0 _ n)}
    ... | result quotient remainder property with chn (suc m ^ n) {toℕ i}{quotient}
          {to is}{remainder} (trans eq2 property)
    ... | k₀≡k₁ , r₀≡r₁ rewrite P.sym r₀≡r₁ | from∘to is =
        P.cong (_∷ is) (toℕ-injective (begin toℕ (Fin.fromℕ≤ _)
                                               ≡⟨ toℕ-fromℕ≤ _ ⟩ quotient
                                               ≡⟨ P.sym k₀≡k₁ ⟩ toℕ i ∎))
        where
          open ≡-Reasoning

    to∘from : ∀ {m n}(i : Fin (m ^ n)) → to (from{m}{n} i) ≡ i
    to∘from {m} {zero} Fin.zero = refl
    to∘from {m} {zero} (Fin.suc ())
    to∘from {zero} {suc n} ()
    to∘from {suc m} {suc n} i with ((toℕ i) divMod (suc m ^ n))
      {≢0 = fromWitnessFalse (suci^j≢0 _ n)}
    to∘from {suc m} {suc n} i | result quotient remainder property = goal
      where
        q<sm : quotient < suc m
        q<sm = ≰⇒> (λ sm≤q → <⇒≱ (toℕ<n i)
                (begin (suc m) * (suc m ^ n)
                   ≤⟨ *-mono-≤ sm≤q ≤-refl ⟩ quotient * (suc m ^ n)
                   ≤⟨ +-mono-≤ (z≤n {toℕ remainder}) ≤-refl ⟩ toℕ remainder + quotient * (suc m ^ n)
                   ≡⟨ P.sym property ⟩ toℕ i ∎))
              where
                open ≤-Reasoning

        goal : to (Fin.fromℕ≤ q<sm  ∷ from {suc m}{n} remainder) ≡ i
        goal = toℕ-injective
              (begin _ ≡⟨ toℕ-fromℕ≤ _ ⟩
                         toℕ (to (from {suc m} {n} remainder)) + toℕ (Fin.fromℕ≤ q<sm ) * (suc m ^ n)
                       ≡⟨ P.cong₂ (λ r k → toℕ r + k * (suc m ^ n))
                            (to∘from {suc m} {n} remainder) (toℕ-fromℕ≤ q<sm)
                          ⟩  toℕ remainder + quotient * (suc m ^ n)
                       ≡⟨ P.sym property ⟩ toℕ i ∎)
          where
            open ≡-Reasoning

⟶-finitude-toVec : ∀{m n a b p q}{A : Setoid a p}{B : Setoid b q} → Finitude A m → Finitude B n
             → A ⟶ B → Vec (Fin n) m
⟶-finitude-toVec finA finB f = Vec.tabulate
                                   (λ i → (Inverse.to finB  F.∘ f F.∘ Inverse.from finA) ⟨$⟩ i )

⟶-finitude-fromVec : ∀{m n a b p q}{A : Setoid a p}{B : Setoid b q} → Finitude A m → Finitude B n
             → Vec (Fin n) m → A ⟶ B
⟶-finitude-fromVec {A = SA}{B = SB} finA finB vec =
  record {   _⟨$⟩_ = f
          ;  cong  = f-cong   }
  where
    open module SA = Setoid SA renaming (Carrier to A) using ()
    open module SB = Setoid SB renaming (Carrier to B) using ()
    f : A → B
    f x = Inverse.from finB ⟨$⟩ Vec.lookup (Inverse.to finA ⟨$⟩ x) vec

    f-cong : ∀ {x y} → x SA.≈ y → f x SB.≈ f y
    f-cong {x}{y} x≈y = F.cong (Inverse.from finB)
                           (P.cong (flip Vec.lookup vec) (F.cong (Inverse.to finA) x≈y))

⟶-finitude↔Vec : ∀{m n a b p q}{A : Setoid a p}{B : Setoid b q} → Finitude A n → Finitude B m
                 → Inverse (A ⇨ B) (P.setoid (Vec (Fin m) n))
Inverse.to (⟶-finitude↔Vec {m} {n} {A = S₁} {S₂} finA finB) ._⟨$⟩_ = ⟶-finitude-toVec finA finB
Inverse.to (⟶-finitude↔Vec {m} {n} {A = S₁} {S₂} finA finB) .F.cong {f} {g} eq = tabulate-cong ( λ i →
  F.cong (Inverse.to finB) (eq ≈₁-refl) )
  where
    open import Data.Vec.Properties
    open Setoid S₁ renaming (isEquivalence to isEquivalence₁)
    open IsEquivalence isEquivalence₁ renaming (refl to ≈₁-refl)

Inverse.from (⟶-finitude↔Vec finA finB) = P.→-to-⟶ (⟶-finitude-fromVec finA finB)
Inv._InverseOf_.left-inverse-of (Inverse.inverse-of (⟶-finitude↔Vec {m = m}{n}{A = S₁} {S₂} finA finB)) f {x}{y} x≈y =
  begin ⟶-finitude-fromVec finA finB (⟶-finitude-toVec finA finB f) ⟨$⟩ x
         ≈⟨ F.cong (Inverse.from finB) lemma  ⟩ _
         ≈⟨ linv₂ _  ⟩ _
         ≈⟨ F.cong f (linv₁ x) ⟩ _
         ≈⟨ F.cong f x≈y ⟩ f ⟨$⟩ y ∎
  where
    open import Data.Vec.Properties
    open import Relation.Binary.Reasoning.Setoid (S₂)
    open Setoid S₁ renaming (isEquivalence to isEquivalence₁)
    open IsEquivalence isEquivalence₁ renaming (refl to ≈₁-refl; trans to ≈₁-trans)
    open Setoid S₂ renaming (isEquivalence to isEquivalence₂)
    open IsEquivalence isEquivalence₂ renaming (refl to ≈₂-refl; trans to ≈₂-trans)
    F = (Inverse.to finB  F.∘ f F.∘ Inverse.from finA) ⟨$⟩_
    lemma = lookup∘tabulate F (Inverse.to finA ⟨$⟩ x)
    linv₁ = finA .Inverse.inverse-of .Inv._InverseOf_.left-inverse-of
    linv₂ = finB .Inverse.inverse-of .Inv._InverseOf_.left-inverse-of
Inv._InverseOf_.right-inverse-of (Inverse.inverse-of (⟶-finitude↔Vec finA finB)) vec =
  begin _  ≡⟨ tabulate-cong lemma ⟩ _
           ≡⟨ tabulate∘lookup vec ⟩ vec ∎
  where
    open import Data.Vec.Properties
    open P.≡-Reasoning
    rinv₁ = finA .Inverse.inverse-of .Inv._InverseOf_.right-inverse-of
    rinv₂ = finB .Inverse.inverse-of .Inv._InverseOf_.right-inverse-of
    lemma : Inverse.to finB F.∘ (⟶-finitude-fromVec finA finB vec) F.∘ Inverse.from finA ⟨$⟩_ ≗ flip lookup vec
    lemma i = begin _ ≡⟨ rinv₂ _ ⟩ _
                      ≡⟨ P.cong (flip lookup vec) (rinv₁ i)  ⟩ lookup i vec ∎

⟶-finitude : ∀{m n a b p q}{A : Setoid a p}{B : Setoid b q} → Finitude A n → Finitude B m
                 → Finitude (A ⇨ B) (m ^ n)
⟶-finitude finA finB = exponent  Inv.∘ (⟶-finitude↔Vec finA finB)


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

open import HoTT
open import homotopy.HSpace

module homotopy.CircleHSpace where

S¹-hSpace : HSpaceStructure S¹
S¹-hSpace = hSpaceStructure base μ μ-e-l μ-e-r μ-coh where

  turn-around : (x : S¹) → x == x
  turn-around = S¹-elim loop (↓-idf=idf-in (∙=∙' loop loop))

  module Mu = S¹Rec (idf S¹) (λ= turn-around)

  μ : S¹ → S¹ → S¹
  μ = Mu.f

  μ-e-l : (x : S¹) → μ base x == x
  μ-e-l x = idp

  μ-e-r : (x : S¹) → μ x base == x
  μ-e-r = S¹-elim idp (↓-app=idf-in
    (idp ∙' loop                          =⟨ ∙'-unit-l loop ⟩
     loop                                 =⟨ idp ⟩
     turn-around base                     =⟨ ! (app=-β turn-around base) ⟩
     ap (λ z → z base) (λ= turn-around)   =⟨ ! (Mu.loop-β |in-ctx (ap (λ z → z base))) ⟩
     ap (λ z → z base) (ap μ loop)        =⟨ ! (ap-∘ (λ z → z base) μ loop) ⟩
     ap (λ z → μ z base) loop             =⟨ ! (∙-unit-r _) ⟩
     ap (λ z → μ z base) loop ∙ idp ∎))

  μ-coh = idp


module Normalize where

open import Data.List
open import Data.Product

open import PiLevel0

-- We are going to use all the coherence as follows; make the right
-- hand side canonical and rewrite the left hand side to the right
-- hand side. Brute force below cannot work!

-- Use the same structure as
-- https://agda.github.io/agda-stdlib/Algebra.Monoid-solver.html ??

{-# NO_TERMINATION_CHECK #-}
normalize : {t₁ t₂ : U} → (t₁ ⟷ t₂) → (t₁ ⟷ t₂)
normalize unite₊ = {!!}
normalize uniti₊ = {!!}
normalize swap₊ = {!!}
normalize assocl₊ = {!!}
normalize assocr₊ = {!!}
normalize unite⋆ = {!!}
normalize uniti⋆ = {!!}
normalize swap⋆ = {!!}
normalize assocl⋆ = {!!}
normalize assocr⋆ = {!!}
normalize absorbr = {!!}
normalize absorbl = {!!}
normalize factorzr = {!!}
normalize factorzl = {!!}
normalize dist = {!!}
normalize factor = {!!}
normalize id⟷ = {!!}
normalize (c ◎ id⟷) = normalize c
normalize (unite₊ ◎ c₁) = {!!}
normalize (uniti₊ ◎ c₁) = {!!}
normalize (swap₊ ◎ c₁) = {!!}
normalize (assocl₊ ◎ c₁) = {!!}
normalize (assocr₊ ◎ c₁) = {!!}
normalize (unite⋆ ◎ c₁) = {!!}
normalize (uniti⋆ ◎ c₁) = {!!}
normalize (swap⋆ ◎ c₁) = {!!}
normalize (assocl⋆ ◎ c₁) = {!!}
normalize (assocr⋆ ◎ c₁) = {!!}
normalize (absorbr ◎ c₁) = {!!}
normalize (absorbl ◎ c₁) = {!!}
normalize (factorzr ◎ c₁) = {!!}
normalize (factorzl ◎ c₁) = {!!}
normalize (dist ◎ c₁) = {!!}
normalize (factor ◎ c₁) = {!!}
normalize (id⟷ ◎ c₁) = normalize c₁
normalize ((c ◎ c₁) ◎ c₂) = normalize (c ◎ (c₁ ◎ c₂))
normalize ((c ⊕ c₁) ◎ c₂) = {!!}
normalize ((c ⊗ c₁) ◎ c₂) = {!!}
normalize (c ⊕ unite₊) = {!!}
normalize (c ⊕ uniti₊) = {!!}
normalize (c ⊕ swap₊) = {!!}
normalize (c ⊕ assocl₊) = {!!}
normalize (c ⊕ assocr₊) = {!!}
normalize (c ⊕ unite⋆) = {!!}
normalize (c ⊕ uniti⋆) = {!!}
normalize (c ⊕ swap⋆) = {!!}
normalize (c ⊕ assocl⋆) = {!!}
normalize (c ⊕ assocr⋆) = {!!}
normalize (c ⊕ absorbr) = {!!}
normalize (c ⊕ absorbl) = {!!}
normalize (c ⊕ factorzr) = {!!}
normalize (c ⊕ factorzl) = {!!}
normalize (c ⊕ dist) = {!!}
normalize (c ⊕ factor) = {!!}
normalize (c ⊕ id⟷) = {!!}
normalize (c ⊕ c₁ ◎ c₂) = {!!}
normalize (c ⊕ (c₁ ⊕ c₂)) = {!!}
normalize (c ⊕ (c₁ ⊗ c₂)) = {!!}
normalize (c ⊗ c₁) = {!!}


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

module Math.NumberTheory.Summation.Generic.Properties.Lemma where

-- agda-stdlib
open import Data.Nat
open import Data.Nat.Properties
open import Data.Nat.Solver
open import Relation.Binary.PropositionalEquality
open import Function.Base

lemma₁ : ∀ m n → 2 + m + n ≡ suc m + suc n
lemma₁ = solve 2 (λ m n → con 2 :+ m :+ n := con 1 :+ m :+ (con 1 :+ n)) refl
  where open +-*-Solver


module Prelude where

-- Booleans
data Bool : Set where
  tt : Bool
  ff : Bool

_||_ : Bool -> Bool -> Bool
tt || y = tt
ff || y = y

_&&_ : Bool -> Bool -> Bool
tt && y = y
ff && y = ff

if_then_else : {A : Set} -> Bool -> A -> A -> A
if tt then x else _ = x
if ff then _ else y = y

-- Eq "type class"
record Eq (A : Set) : Set where
  field
    _==_   : A -> A ->  Bool

open Eq {{...}} public

-- Function composition
_∘_ : ∀ {x y z : Set} -> (y -> z) -> (x -> y) -> (x -> z)
(f ∘ g) x = f (g x)

-- Product type
data _×_ (A B : Set) : Set where
    _,_ : A -> B -> A × B

uncurry : ∀ {x y z : Set} -> (x -> y -> z) -> (x × y) -> z
uncurry f (a , b) = f a b

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

infixr 20 _::_
infixr 15 _++_

[_] : ∀ {A} -> A -> List A
[ x ] = x :: []

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

foldr : ∀ {A B : Set} -> (A -> B -> B) -> B -> List A -> B
foldr f b [] = b
foldr f b (x :: xs) = f x (foldr f b xs)

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

zip : ∀ {A B} -> List A -> List B -> List (A × B)
zip [] _                = []
zip _  []               = []
zip (x :: xs) (y :: ys) = (x , y) :: zip xs ys

-- Bottom type
-- data ⊥ : Set where

-- ¬ : Set -> Set
-- ¬ A = A -> ⊥

-- Decidable propositions and relations:
-- Rel : Set -> Set₁
-- Rel a = a -> a -> Set

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

-- Decidable : {a : Set} → Rel a → Set
-- Decidable _∼_ = forall x y → Dec (x ∼ y)

-- Natural numbers
data ℕ : Set where
  zero : ℕ
  suc  : ℕ -> ℕ


------------------------------------------------------------------------
-- The Agda standard library
--
-- Results concerning function extensionality for propositional equality
------------------------------------------------------------------------

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

module Axiom.Extensionality.Propositional where

open import Function
open import Level using (Level; _⊔_; suc; lift)
open import Relation.Binary.Core
open import Relation.Binary.PropositionalEquality.Core

------------------------------------------------------------------------
-- Function extensionality states that if two functions are
-- propositionally equal for every input, then the functions themselves
-- must be propositionally equal.

Extensionality : (a b : Level) → Set _
Extensionality a b =
  {A : Set a} {B : A → Set b} {f g : (x : A) → B x} →
  (∀ x → f x ≡ g x) → f ≡ g

------------------------------------------------------------------------
-- Properties

-- If extensionality holds for a given universe level, then it also
-- holds for lower ones.

lower-extensionality : ∀ {a₁ b₁} a₂ b₂ →
                       Extensionality (a₁ ⊔ a₂) (b₁ ⊔ b₂) →
                       Extensionality a₁ b₁
lower-extensionality a₂ b₂ ext f≡g = cong (λ h → Level.lower ∘ h ∘ lift) $
    ext (cong (lift {ℓ = b₂}) ∘ f≡g ∘ Level.lower {ℓ = a₂})

-- Functional extensionality implies a form of extensionality for
-- Π-types.

∀-extensionality : ∀ {a b} → Extensionality a (suc b) →
                   {A : Set a} (B₁ B₂ : A → Set b) →
                   (∀ x → B₁ x ≡ B₂ x) →
                   (∀ x → B₁ x) ≡ (∀ x → B₂ x)
∀-extensionality ext B₁ B₂ B₁≡B₂ with ext B₁≡B₂
∀-extensionality ext B .B  B₁≡B₂ | refl = refl


open import SingleSorted.AlgebraicTheory
open import Agda.Primitive using (lzero; lsuc; _⊔_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import SingleSorted.Substitution
open import Data.Nat using (ℕ; zero; suc; _+_; _*_)

module SingleSorted.Group where

data GroupOp : Set where
  e : GroupOp
  inv : GroupOp
  mul : GroupOp

_ : Context
_ = ctx-empty

_ : Context
_ = ctx-concat ctx-slot ctx-empty

_ : var ctx-slot
_ = var-var

_ : var (ctx-concat ctx-slot ctx-slot)
_ = var-inl var-var

_ : var (ctx-concat ctx-slot ctx-slot)
_ = var-inr var-var

ctx-1 : Context
ctx-1 = ctx-slot

ctx-2 : Context
ctx-2 = ctx-concat ctx-1 ctx-1

ctx : ∀ (n : ℕ) → Context
ctx zero = ctx-empty
ctx (suc n) = ctx-concat (ctx n) ctx-slot

-- the signature of the theory of groups
-- has one constant, one unary operation, one binary operation
Σ : Signature
Σ = record { oper = GroupOp ; oper-arity = λ{ e → ctx-empty ; inv → ctx 1 ; mul → ctx 2} }

open Signature Σ

-- some example terms
_ : Term ctx-1
_ = tm-var var-var

_ : Term ctx-2
_ = tm-var (var-inr var-var)

_ : Term ctx-2
_ = tm-var (var-inr var-var)

-- helper functions for creating terms
e' : ∀ {Γ : Context} → Term Γ
e' {Γ} = tm-oper e λ()

-- inv' : ∀ {Γ : Context} → Term Γ → Term Γ
-- inv' x = tm-oper inv λ{ _ → x}

-- mul' : ∀ {Γ : Context} → Term Γ → Term Γ → Term Γ
-- mul' x y = tm-oper mul λ{ (var-inl _) → x ; (var-inr _) → y}

concat-empty : var (ctx-concat ctx-empty ctx-slot) → (var ctx-slot)
concat-empty (var-inr x) = x

x*y : Term ctx-2
x*y = tm-oper mul λ{ (var-inl x) → tm-var (var-inl (concat-empty x)) ; (var-inr y) → tm-var (var-inr y)}

-- concat-empty-idʳ : ctx-concat ctx-empty ctx-slot ≡ ctx-slot
-- concat-empty-idʳ = {!!}

singleton-context : (var ctx-slot) → var (ctx-concat ctx-empty ctx-slot)
singleton-context (var-var) = var-inr var-var

σ : ∀ {Γ : Context} {t : Term Γ} →  Γ ⇒s (ctx 1)
σ {Γ} {t} = λ{ (var-inr var-var) → t}

δ : ∀ {Γ : Context} {t : Term Γ} {s : Term Γ} →   Γ ⇒s (ctx 2)
δ {Γ} {t} {s} = λ{ (var-inl x) → t ; (var-inr y) → s}

_∗_ : ∀ {Γ} → Term Γ → Term Γ → Term Γ
t ∗ s =  tm-oper mul λ{ xs → δ {t = t} {s = s} xs}

_ⁱ : ∀ {Γ : Context} →  Term Γ → Term Γ
t ⁱ =  tm-oper inv λ{ x → σ {t = t} x}

-- _∗_ : ∀ {Γ} → Term Γ → Term Γ → Term Γ
-- t ∗ s =  tm-oper mul λ{ (var-inl x) → t ; (var-inr args) → s}

-- _ⁱ : ∀ {Γ : Context} →  Term Γ → Term Γ
-- t ⁱ =  tm-oper inv λ{ x → t }

infixl 5 _∗_
infix 6 _ⁱ

_ : Term (ctx 2)
_ = tm-var (var-inl (var-inr var-var)) ∗ tm-var (var-inr var-var)

_ : Term (ctx 1)
_ = e' ∗ a
  where
  a : Term (ctx 1)
  a = tm-var (var-inr var-var)

-- group equations
data GroupEq : Set where
  mul-assoc e-left e-right inv-left inv-right : GroupEq

mul-assoc-ax : Equation
e-left-ax : Equation
e-right-ax : Equation
inv-left-ax : Equation
inv-right-ax : Equation

mul-assoc-ax = record { eq-ctx = ctx 3
                      ; eq-lhs = x ∗ y ∗ z
                      ; eq-rhs = x ∗ (y ∗ z)
                      }
             where
             x : Term (ctx 3)
             y : Term (ctx 3)
             z : Term (ctx 3)
             x = tm-var (var-inl (var-inl (var-inr var-var)))
             y = tm-var (var-inl (var-inr var-var))
             z = tm-var (var-inr var-var)

e-left-ax = record { eq-ctx = ctx 1 ; eq-lhs = e' ∗ x ; eq-rhs = x }
  where
  x : Term (ctx 1)
  x = tm-var (var-inr var-var)

e-right-ax = record { eq-ctx = ctx 1 ; eq-lhs = x ∗ e' ; eq-rhs = x }
  where
  x : Term (ctx 1)
  x = tm-var (var-inr var-var)

inv-left-ax = record { eq-ctx = ctx 1 ; eq-lhs = x ⁱ ∗ x ; eq-rhs = e' }
  where
  x : Term (ctx 1)
  x = tm-var (var-inr var-var)

inv-right-ax = record { eq-ctx = ctx 1 ; eq-lhs = x ∗ x ⁱ ; eq-rhs = e' }
  where
  x : Term (ctx 1)
  x = tm-var (var-inr var-var)

𝒢 : Theory lzero Σ
𝒢 = record { ax = GroupEq
            ; ax-eq = λ{ mul-assoc → mul-assoc-ax
                       ; e-left → e-left-ax
                       ; e-right → e-right-ax
                       ; inv-left → inv-left-ax
                       ; inv-right → inv-right-ax
                       }
            }


module Syntax where

open import Data.List using (List; []; _∷_; _++_; lookup; length)
open import Data.Product using (Σ; Σ-syntax; proj₁; proj₂)
open import Data.Unit renaming (⊤ to top)
open import Data.Empty renaming (⊥ to bot)

open import Level using (suc; _⊔_)

module PType {ℓ} (Gr : Set ℓ) where
  infixr 10 _*_
  infixr 9 _=>_

  data Type : Set ℓ where
    ⌊_⌋ : Gr -> Type
    Unit : Type
    _*_ : Type -> Type -> Type
    _=>_ : Type -> Type -> Type

  record Sorting : Set ℓ where
    field
      dom : Type
      cod : Type

  Context : Set ℓ
  Context = List Type

record Signature ℓ₁ ℓ₂ : Set (suc (ℓ₁ ⊔ ℓ₂)) where
  field
    Gr : Set ℓ₁
    Func : Set ℓ₂

  open PType Gr public

  field
    sorting : Func -> Sorting

  dom : Func -> Type
  dom f = Sorting.dom (sorting f)

  cod : Func -> Type
  cod f = Sorting.cod (sorting f)

module Term {ℓ₁ ℓ₂} (Sg : Signature ℓ₁ ℓ₂) where
  open Signature Sg

  infix 3 _⊨_
  infix 8 _∙_

  infix 3 _⊢_
  infixl 4 _[_]

  data _⊨_ : Context -> Context -> Set (ℓ₁ ⊔ ℓ₂)
  data _⊢_ : Context -> Type -> Set (ℓ₁ ⊔ ℓ₂)

  data _⊨_ where
    id : forall {Γ} -> Γ ⊨ Γ  -- identity morphism
    _∙_ : forall {Γ Γ′ Γ′′} -> Γ′ ⊨ Γ′′ -> Γ ⊨ Γ′ -> Γ ⊨ Γ′′ -- composition of morphisms
    weaken : forall {Γ A} -> A ∷ Γ ⊨ Γ -- the first projection
    ext : forall {Γ Γ′ A} -> Γ ⊨ Γ′ -> Γ ⊢ A -> Γ ⊨ A ∷ Γ′ -- the unique morphism into the product
    ! : forall {Γ} -> Γ ⊨ [] -- the unique morphism into the terminal object

  data _⊢_ where
    func : forall {Γ} (f : Func) -> Γ ⊢ dom f -> Γ ⊢ cod f

    var : forall {Γ A} -> A ∷ Γ ⊢ A

    unit : forall {Γ} -> Γ ⊢ Unit

    pair : forall {Γ A B} -> Γ ⊢ A -> Γ ⊢ B -> Γ ⊢ A * B
    fst : forall {Γ A B} -> Γ ⊢ A * B -> Γ ⊢ A
    snd : forall {Γ A B} -> Γ ⊢ A * B -> Γ ⊢ B

    abs : forall {Γ A B} -> A ∷ Γ ⊢ B -> Γ ⊢ A => B
    app : forall {Γ A B} -> Γ ⊢ A => B -> Γ ⊢ A -> Γ ⊢ B

    _[_] : forall {Γ Γ′ A} -> Γ′ ⊢ A -> Γ ⊨ Γ′ -> Γ ⊢ A

  infix 10 _×id′

  _×id′ : forall {Γ Γ′} {A} -> Γ ⊨ Γ′ -> A ∷ Γ ⊨ A ∷ Γ′
  γ ×id′ = ext (γ ∙ weaken) var


------------------------------------------------------------------------
-- H-levels
------------------------------------------------------------------------

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

-- Partly based on Voevodsky's work on so-called univalent
-- foundations.

open import Equality

module H-level
  {reflexive} (eq : ∀ {a p} → Equality-with-J a p reflexive) where

open Derived-definitions-and-properties eq
open import Logical-equivalence hiding (id; _∘_)
open import Nat eq
open import Prelude
open import Surjection eq hiding (id; _∘_)

private
  variable
    a ℓ : Level
    m n : ℕ
    A B : Type a

------------------------------------------------------------------------
-- H-levels

-- H-levels ("homotopy levels").

H-level : ℕ → Type ℓ → Type ℓ
H-level zero          A = Contractible A
H-level (suc zero)    A = Is-proposition A
H-level (suc (suc n)) A = {x y : A} → H-level (suc n) (x ≡ y)

private

  -- Note that H-level 2 is a synonym for Is-set.

  H-level-2≡Is-set : H-level 2 A ≡ Is-set A
  H-level-2≡Is-set = refl _

-- For-iterated-equality n P A means that P holds for (equalities
-- over)^n A.

For-iterated-equality : ℕ → (Type ℓ → Type ℓ) → (Type ℓ → Type ℓ)
For-iterated-equality zero    P A = P A
For-iterated-equality (suc n) P A =
  (x y : A) → For-iterated-equality n P (x ≡ y)

-- An alternative definition of h-levels.
--
-- In some cases this definition, with only two cases, is easier to
-- use. In other cases the definition above, which is less complicated
-- for positive h-levels, is easier to use.

H-level′ : ℕ → Type ℓ → Type ℓ
H-level′ = flip For-iterated-equality Contractible

-- Propositions are propositional types.

Proposition : (ℓ : Level) → Type (lsuc ℓ)
Proposition _ = ∃ Is-proposition

-- Types that are sets.

Set : (ℓ : Level) → Type (lsuc ℓ)
Set _ = ∃ Is-set

-- The underlying type.

⌞_⌟ : Set ℓ → Type ℓ
⌞ A ⌟ = proj₁ A

------------------------------------------------------------------------
-- General properties

-- H-level′ is upwards closed in its first argument.

mono₁′ : ∀ n → H-level′ n A → H-level′ (1 + n) A
mono₁′         (suc n) h x y = mono₁′ n (h x y)
mono₁′ {A = A} zero    h x y = trivial x y , irr
  where
  trivial : (x y : A) → x ≡ y
  trivial x y =
    x        ≡⟨ sym $ proj₂ h x ⟩
    proj₁ h  ≡⟨ proj₂ h y ⟩∎
    y        ∎

  irr : (x≡y : x ≡ y) → trivial x y ≡ x≡y
  irr = elim (λ {x y} x≡y → trivial x y ≡ x≡y)
             (λ x → trans-symˡ (proj₂ h x))

-- H-level and H-level′ are pointwise logically equivalent.

H-level⇔H-level′ : H-level n A ⇔ H-level′ n A
H-level⇔H-level′ = record { to = to _; from = from _ }
  where
  to : ∀ n → H-level n A → H-level′ n A
  to zero          h = h
  to (suc zero)    h = λ x → mono₁′ 0 (x , h x) x
  to (suc (suc n)) h = λ x y → to (suc n) h

  from : ∀ n → H-level′ n A → H-level n A
  from zero          h = h
  from (suc zero)    h x y = proj₁ (h x y)
  from (suc (suc n)) h {x = x} {y = y} = from (suc n) (h x y)

-- If A has h-level 1 + n, then the types of equality proofs between
-- elements of type A have h-level n.

+⇒≡ : {x y : A} → H-level (suc n) A → H-level n (x ≡ y)
+⇒≡ h = _⇔_.from H-level⇔H-level′ $ _⇔_.to H-level⇔H-level′ h _ _

-- H-level is upwards closed in its first argument.

mono₁ : ∀ n → H-level n A → H-level (1 + n) A
mono₁ n =
  _⇔_.from H-level⇔H-level′ ∘
  mono₁′ n ∘
  _⇔_.to H-level⇔H-level′

abstract

  mono : m ≤ n → H-level m A → H-level n A
  mono (≤-refl′ eq)     = subst (λ n → H-level n _) eq
  mono (≤-step′ m≤n eq) =
    subst (λ n → H-level n _) eq ∘
    mono₁ _ ∘
    mono m≤n

  -- If A has h-level n, then the types of equality proofs between
  -- elements of type A also have h-level n.

  ⇒≡ : {x y : A} → ∀ n → H-level n A → H-level n (x ≡ y)
  ⇒≡ _ = +⇒≡ ∘ mono₁ _

  -- If something is contractible given the assumption that it is
  -- inhabited, then it is propositional.

  [inhabited⇒contractible]⇒propositional :
    (A → Contractible A) → Is-proposition A
  [inhabited⇒contractible]⇒propositional h x = mono₁ 0 (h x) x

  -- If something has h-level (1 + n) given the assumption that it is
  -- inhabited, then it has h-level (1 + n).

  [inhabited⇒+]⇒+ : ∀ n → (A → H-level (1 + n) A) → H-level (1 + n) A
  [inhabited⇒+]⇒+ n h =
    _⇔_.from H-level⇔H-level′ λ x → _⇔_.to H-level⇔H-level′ (h x) x

  -- An alternative characterisation of sets and higher h-levels.
  --
  -- This is Theorem 7.2.7 from the HoTT book.

  2+⇔∀1+≡ :
    ∀ n → H-level (2 + n) A ⇔ ((x : A) → H-level (1 + n) (x ≡ x))
  2+⇔∀1+≡ n = record
    { to   = λ h _ → h
    ; from = λ h → [inhabited⇒+]⇒+ _
                     (elim (λ {x y} _ → H-level (1 + n) (x ≡ y)) h)
    }

-- If a propositional type is inhabited, then it is contractible.

propositional⇒inhabited⇒contractible :
  Is-proposition A → A → Contractible A
propositional⇒inhabited⇒contractible p x = (x , p x)

-- H-level′ n respects (split) surjections.

respects-surjection′ :
  A ↠ B → ∀ n → H-level′ n A → H-level′ n B
respects-surjection′ A↠B zero (x , irr) = (to x , irr′)
  where
  open _↠_ A↠B

  irr′ : ∀ y → to x ≡ y
  irr′ = λ y →
    to x         ≡⟨ cong to (irr (from y)) ⟩
    to (from y)  ≡⟨ right-inverse-of y ⟩∎
    y            ∎

respects-surjection′ A↠B (suc n) h = λ x y →
  respects-surjection′ (↠-≡ A↠B) n (h (from x) (from y))
  where open _↠_ A↠B

-- H-level n respects (split) surjections.

respects-surjection :
  A ↠ B → ∀ n → H-level n A → H-level n B
respects-surjection A↠B n =
  _⇔_.from H-level⇔H-level′ ∘
  respects-surjection′ A↠B n ∘
  _⇔_.to H-level⇔H-level′


{-

Definition of the torus as a HIT together with a proof that it is
equivalent to two circles

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

open import Cubical.Core.Glue

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism

open import Cubical.Data.Nat
open import Cubical.Data.Int
open import Cubical.Data.Prod hiding (_×_) renaming (_×Σ_ to _×_)

open import Cubical.HITs.S1

data Torus : Type₀ where
  point : Torus
  line1 : point ≡ point
  line2 : point ≡ point
  square : PathP (λ i → line1 i ≡ line1 i) line2 line2

t2c : Torus → S¹ × S¹
t2c point        = ( base , base )
t2c (line1 i)    = ( loop i , base )
t2c (line2 j)    = ( base , loop j )
t2c (square i j) = ( loop i , loop j )

c2t : S¹ × S¹ → Torus
c2t (base   , base)   = point
c2t (loop i , base)   = line1 i
c2t (base   , loop j) = line2 j
c2t (loop i , loop j) = square i j

c2t-t2c : ∀ (t : Torus) → c2t (t2c t) ≡ t
c2t-t2c point        = refl
c2t-t2c (line1 _)    = refl
c2t-t2c (line2 _)    = refl
c2t-t2c (square _ _) = refl

t2c-c2t : ∀ (p : S¹ × S¹) → t2c (c2t p) ≡ p
t2c-c2t (base   , base)   = refl
t2c-c2t (base   , loop _) = refl
t2c-c2t (loop _ , base)   = refl
t2c-c2t (loop _ , loop _) = refl

Torus≡S¹×S¹ : Torus ≡ S¹ × S¹
Torus≡S¹×S¹ = isoToPath (iso t2c c2t t2c-c2t c2t-t2c)

ΩTorus : Type₀
ΩTorus = point ≡ point

-- TODO: upstream
lemPathAnd : ∀ {ℓ} {A B : Type ℓ} (t u : A × B) →
  Path _ (t ≡ u) ((t .fst ≡ u .fst) × ((t .snd) ≡ (u .snd)))
lemPathAnd t u = isoToPath (iso (λ tu → (λ i → tu i .fst) , λ i → tu i .snd)
                                 (λ tu i → tu .fst i , tu .snd i)
                                 (λ y → refl)
                                 (λ x → refl))

funDep : ∀ {ℓ} {A B : Type ℓ} (p : A ≡ B) (u0 : A) (u1 : B) →
  (Path A u0 (transport (λ i → p (~ i)) u1)) ≡ (Path B (transport p u0) u1)
funDep p u0 u1 i = Path (p i) (transp (λ j → p (i ∧ j)) (~ i) u0) (transp (λ j → p (i ∨ ~ j)) i u1)

-- Can this proof be simplified?
ΩTorus≡Int×Int : ΩTorus ≡ Int × Int
ΩTorus≡Int×Int =
  ΩTorus
    ≡⟨ (λ i → Path Torus point (transp (\ j → Torus≡S¹×S¹ (~ j ∧ i)) (~ i)
                                       (glue (λ { (i = i0) → point
                                                ; (i = i1) → (base , base) }) (base , base)))) ⟩
  Path Torus point (transp (\ i → Torus≡S¹×S¹ (~ i)) i0 (base , base))
    ≡⟨ funDep (λ i → Torus≡S¹×S¹ i) point (base , base) ⟩
  Path (S¹ × S¹) (transp (\ i → Torus≡S¹×S¹ i) i0 point) (base , base)
    ≡⟨ (λ i → Path _ (transp (λ j → Torus≡S¹×S¹ (j ∨ i))  i
                             (glue (λ { (i = i0) → point
                                      ; (i = i1) → (base , base) }) (base , base))) (base , base)) ⟩
  Path (S¹ × S¹) (base , base) (base , base)
    ≡⟨ lemPathAnd (base , base) (base , base) ⟩
  ΩS¹ × ΩS¹
    ≡⟨ (λ i → ΩS¹≡Int i × ΩS¹≡Int i) ⟩
  Int × Int ∎

-- Computing the winding numbers on the torus
windingTorus : ΩTorus → Int × Int
windingTorus l = ( winding (λ i → t2c (l i) .fst)
                 , winding (λ i → t2c (l i) .snd))

module _ where
 private
  test1 : windingTorus (line1 ∙ line2) ≡ (pos 1 , pos 1)
  test1 = refl

  test2 : windingTorus (line1 ∙ line2 ∙ sym line1 ∙ sym line1) ≡ (negsuc 0 , pos 1)
  test2 = refl


{-# OPTIONS --type-in-type #-}

data ⊥ : Set where

℘ : ∀ {ℓ} → Set ℓ → Set _
℘ {ℓ} S = S → Set

U : Set
U = ∀ (X : Set) → (℘ (℘ X) → X) → ℘ (℘ X)

{- If using two impredicative universe layers instead of type-in-type:
U : Set₁
U = ∀ (X : Set₁) → (℘ (℘ X) → X) → ℘ (℘ X)
-}

τ : ℘ (℘ U) → U
τ t = λ X f p → t (λ x → p (f (x X f)))

σ : U → ℘ (℘ U)
σ s = s U τ

Δ : ℘ U
Δ y = (∀ p → σ y p → p (τ (σ y))) → ⊥

Ω : U
Ω = τ (λ p → (∀ x → σ x p → p x))

R : ∀ p → (∀ x → σ x p → p x) → p Ω
R _ 𝟙 = 𝟙 Ω (λ x → 𝟙 (τ (σ x)))

M : ∀ x → σ x Δ → Δ x
M _ 𝟚 𝟛 = 𝟛 Δ 𝟚 (λ p → 𝟛 (λ y → p (τ (σ y))))

L : (∀ p → (∀ x → σ x p → p x) → p Ω) → ⊥
L 𝟘 = 𝟘 Δ M (λ p → 𝟘 (λ y → p (τ (σ y))))

false : ⊥
false = L R


module Trans where

open import Prelude

Rel : Set -> Set1
Rel A = A -> A -> Set

data [_]* {A : Set}(R : Rel A)(x : A) : A -> Set where
  ref : [ R ]* x x
  _▹_ : {y z : A} -> R x y -> [ R ]* y z -> [ R ]* x z

infixr 40 _▹_ _▹◃_

length : {A : Set}{R : Rel A}{x y : A} -> [ R ]* x y -> Nat
length ref      = zero
length (x ▹ xs) = suc (length xs)

_=[_]=>_ : {A B : Set}(R : Rel A)(i : A -> B)(S : Rel B) -> Set
R =[ i ]=> S = forall {x y} -> R x y -> S (i x) (i y)

map : {A B : Set}{R : Rel A}{S : Rel B}(i : A -> B) ->
      (R =[ i ]=> S) ->
      {x y : A} -> [ R ]* x y -> [ S ]* (i x) (i y)
map i f ref      = ref
map i f (x ▹ xs) = f x ▹ map i f xs

lem-length-map :
      {A B : Set}{R : Rel A}{S : Rel B}(i : A -> B)
      (f : R =[ i ]=> S){x y : A}(xs : [ R ]* x y) ->
      length xs ≡ length (map {S = S} i f xs)
lem-length-map i f ref      = refl
lem-length-map i f (x ▹ xs) = cong suc (lem-length-map i f xs)

_▹◃_ : {A : Set}{R : Rel A}{x y z : A} ->
       [ R ]* x y -> [ R ]* y z -> [ R ]* x z
ref      ▹◃ ys = ys
(x ▹ xs) ▹◃ ys = x ▹ (xs ▹◃ ys)

lem-length▹◃ : {A : Set}{R : Rel A}{x y z : A}
               (r₁ : [ R ]* x y)(r₂ : [ R ]* y z) ->
               length r₁ + length r₂ ≡ length (r₁ ▹◃ r₂)
lem-length▹◃ ref      ys = refl
lem-length▹◃ (x ▹ xs) ys = cong suc (lem-length▹◃ xs ys)


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

module sets.int.utils where

open import sum
open import equality
open import function
open import sets.nat.core
open import sets.int.definition
open import hott.level

module _ {i}{X : Set i}(hX : h 2 X)
  (f : ℕ → ℕ → ℕ → ℕ → X)
  (u : ∀ n n' d m m' e → f n n' m m' ≡ f (d + n) (d + n') (e + m) (e + m')) where

  private
    g : ℕ → ℕ → ℤ → X
    g n n' = elim-ℤ hX (f n n' , u n n' 0)

    lem : (n n' d m m' : ℕ) → g n n' (m [-] m') ≡ g (d + n) (d + n') (m [-] m')
    lem n n' d m m' = u n n' d m m' 0

    v : (n n' d : ℕ) → g n n' ≡ g (d + n) (d + n')
    v n n' d = funext λ m → elim-prop-ℤ
      (λ m → hX (g n n' m) (g (d + n) (d + n') m))
      (lem n n' d) m

    hX' : h 2 (ℤ → X)
    hX' = Π-level λ _ → hX

  elim₂-ℤ : ℤ → ℤ → X
  elim₂-ℤ = elim-ℤ hX' (g , v)

elim₂-prop-ℤ : ∀ {i}{X : ℤ → ℤ → Set i} → (∀ n m → h 1 (X n m))
             → ((n n' m m' : ℕ) → X (n [-] n') (m [-] m'))
             → ∀ n m → X n m
elim₂-prop-ℤ {i}{X} hX f = elim-prop-ℤ hX' g
  where
    g : (n n' : ℕ) → ∀ m → X (n [-] n') m
    g n n' = elim-prop-ℤ (hX (n [-] n')) (f n n')

    hX' : ∀ n → h 1 (∀ m → X n m)
    hX' n = Π-level λ m → hX n m

elim₃-prop-ℤ : ∀ {i}{X : ℤ → ℤ → ℤ → Set i} → (∀ n m p → h 1 (X n m p))
             → ((n n' m m' p p' : ℕ) → X (n [-] n') (m [-] m') (p [-] p'))
             → ∀ n m p → X n m p
elim₃-prop-ℤ {i}{X} hX f = elim-prop-ℤ hX' g
  where
    g : (n n' : ℕ) → ∀ m p → X (n [-] n') m p
    g n n' = elim₂-prop-ℤ (hX (n [-] n')) (f n n')

    hX' : ∀ n → h 1 (∀ m p → X n m p)
    hX' n = Π-level λ m → Π-level λ p → hX n m p


------------------------------------------------------------------------
-- An ad-hoc but straightforward solution to the problem of showing
-- that elegant definitions of the Hamming numbers (see EWD 792) and
-- the Fibonacci sequence are productive
------------------------------------------------------------------------

module StreamProg where

open import Codata.Musical.Notation
open import Codata.Musical.Stream as S using (Stream; _∷_; _≈_)
open import Data.Nat
open import Relation.Binary
import Relation.Binary.PropositionalEquality as P

private
  module SS {A : Set} = Setoid (S.setoid A)

------------------------------------------------------------------------
-- Merging of streams

data Ord : Set where
  lt : Ord
  eq : Ord
  gt : Ord

merge : {A : Set} → (A → A → Ord) → Stream A → Stream A → Stream A
merge cmp (x ∷ xs) (y ∷ ys) with cmp x y
... | lt = x ∷ ♯ merge cmp (♭ xs)   (y ∷ ys)
... | eq = x ∷ ♯ merge cmp (♭ xs)   (♭ ys)
... | gt = y ∷ ♯ merge cmp (x ∷ xs) (♭ ys)

------------------------------------------------------------------------
-- Stream programs

infixr 5 _∷_

data StreamP (A : Set) : Set1 where
  _∷_     : (x : A) (xs : ∞ (StreamP A)) → StreamP A
  zipWith : ∀ {B C} (f : B → C → A)
            (xs : StreamP B) (ys : StreamP C) → StreamP A
  map     : ∀ {B} (f : B → A) (xs : StreamP B) → StreamP A
  mergeP  : (cmp : A → A → Ord)
            (xs : StreamP A) (ys : StreamP A) → StreamP A

data StreamW A : Set1 where
  _∷_ : (x : A) (xs : StreamP A) → StreamW A

zipWithW : {A B C : Set} →
           (A → B → C) → StreamW A → StreamW B → StreamW C
zipWithW f (x ∷ xs) (y ∷ ys) = f x y ∷ zipWith f xs ys

mapW : {A B : Set} → (A → B) → StreamW A → StreamW B
mapW f (x ∷ xs) = f x ∷ map f xs

mergeW : {A : Set} →
         (A → A → Ord) → StreamW A → StreamW A → StreamW A
mergeW cmp (x ∷ xs) (y ∷ ys) with cmp x y
... | lt = x ∷ mergeP cmp xs (y ∷ ♯ ys)
... | eq = x ∷ mergeP cmp xs ys
... | gt = y ∷ mergeP cmp (x ∷ ♯ xs) ys

whnf : ∀ {A} → StreamP A → StreamW A
whnf (x ∷ xs)           = x ∷ ♭ xs
whnf (zipWith f xs ys)  = zipWithW f (whnf xs) (whnf ys)
whnf (map f xs)         = mapW f (whnf xs)
whnf (mergeP cmp xs ys) = mergeW cmp (whnf xs) (whnf ys)

mutual

  ⟦_⟧W : ∀ {A} → StreamW A → Stream A
  ⟦ x ∷ xs ⟧W = x ∷ ♯ ⟦ xs ⟧P

  ⟦_⟧P : ∀ {A} → StreamP A → Stream A
  ⟦ xs ⟧P = ⟦ whnf xs ⟧W

------------------------------------------------------------------------
-- Examples

fib : StreamP ℕ
fib = 0 ∷ ♯ zipWith _+_ fib (1 ∷ ♯ fib)

-- Alternative definition showing that definitions do not need to
-- start with a cons constructor.

fib′ : StreamP ℕ
fib′ = zipWith _+_ (0 ∷ ♯ fib′) (0 ∷ ♯ (1 ∷ ♯ fib′))

cmp : ℕ → ℕ → Ord
cmp m n = toOrd (compare m n)
  where
  toOrd : ∀ {m n} → Ordering m n → Ord
  toOrd (less _ _)    = lt
  toOrd (equal _)     = eq
  toOrd (greater _ _) = gt

hamming : StreamP ℕ
hamming = 1 ∷ ♯ mergeP cmp (map (_*_ 2) hamming) (map (_*_ 3) hamming)

------------------------------------------------------------------------
-- The definition of fib is correct

-- ⟦_⟧P is homomorphic with respect to zipWith/S.zipWith.

zipWith-hom : ∀ {A B C} (_∙_ : A → B → C) xs ys →
              ⟦ zipWith _∙_ xs ys ⟧P ≈ S.zipWith _∙_ ⟦ xs ⟧P ⟦ ys ⟧P
zipWith-hom _∙_ xs ys with whnf xs | whnf ys
zipWith-hom _∙_ xs ys | x ∷ xs′ | y ∷ ys′ =
  P.refl ∷ ♯ zipWith-hom _∙_ xs′ ys′

-- Unfortunately Agda's definitional equality for coinductive
-- constructors is currently a little strange, so the result type
-- cannot be written out completely here:

fib-correct′ :
  ⟦ fib ⟧P ≈ 0 ∷ ♯ S.zipWith _+_ ⟦ fib ⟧P (1 ∷ _ {- ♯ ⟦ fib ⟧P -})
fib-correct′ = P.refl ∷ ♯ zipWith-hom _+_ fib (1 ∷ ♯ fib)

-- Fortunately there is a workaround.

fib-correct : ⟦ fib ⟧P ≈ 0 ∷ ♯ S.zipWith _+_ ⟦ fib ⟧P (1 ∷ ♯ ⟦ fib ⟧P)
fib-correct =
  P.refl ∷ ♯ SS.trans (zipWith-hom _+_ fib (1 ∷ ♯ fib))
                      (S.zipWith-cong _+_ (SS.refl {x = 0 ∷ _})
                                          (P.refl ∷ ♯ SS.refl))

-- For a proof showing that the given equation for fib has a unique
-- solution, see MapIterate.

------------------------------------------------------------------------
-- The definition of hamming is correct

-- ⟦_⟧P is homomorphic with respect to map/S.map.

map-hom : ∀ {A B} (f : A → B) xs →
          ⟦ map f xs ⟧P ≈ S.map f ⟦ xs ⟧P
map-hom f xs with whnf xs
... | x ∷ xs′ = P.refl ∷ ♯ map-hom f xs′

-- ⟦_⟧P is homomorphic with respect to mergeP/merge.

merge-hom : ∀ {A} (cmp : A → A → Ord) xs ys →
            ⟦ mergeP cmp xs ys ⟧P ≈ merge cmp ⟦ xs ⟧P ⟦ ys ⟧P
merge-hom cmp xs ys with whnf xs | whnf ys
... | x ∷ xs′ | y ∷ ys′ with cmp x y
...   | lt = P.refl ∷ ♯ merge-hom cmp xs′ (y ∷ ♯ ys′)
...   | eq = P.refl ∷ ♯ merge-hom cmp xs′ ys′
...   | gt = P.refl ∷ ♯ merge-hom cmp (x ∷ ♯ xs′) ys′

-- merge is a congruence.

merge-cong : ∀ {A} (cmp : A → A → Ord) {xs xs′ ys ys′} →
             xs ≈ xs′ → ys ≈ ys′ →
             merge cmp xs ys ≈ merge cmp xs′ ys′
merge-cong cmp (_∷_ {x = x} P.refl xs≈)
               (_∷_ {x = y} P.refl ys≈) with cmp x y
... | lt = P.refl ∷ ♯ merge-cong cmp (♭ xs≈) (P.refl ∷ ys≈)
... | eq = P.refl ∷ ♯ merge-cong cmp (♭ xs≈) (♭ ys≈)
... | gt = P.refl ∷ ♯ merge-cong cmp (P.refl ∷ xs≈) (♭ ys≈)

-- hamming is correct.

hamming-correct : ⟦ hamming ⟧P ≈
                  1 ∷ ♯ merge cmp (S.map (_*_ 2) ⟦ hamming ⟧P)
                                  (S.map (_*_ 3) ⟦ hamming ⟧P)
hamming-correct =
  P.refl ∷ ♯ SS.trans (merge-hom cmp (map (_*_ 2) hamming)
                                     (map (_*_ 3) hamming))
                      (merge-cong cmp (map-hom (_*_ 2) hamming)
                                      (map-hom (_*_ 3) hamming))


-- Copyright:  (c) 2016 Ertugrul Söylemez
-- License:    BSD3
-- Maintainer: Ertugrul Söylemez <esz@posteo.de>

module Data.Mod where

open import Core
open import Data.Int.Core hiding (module Props)
import Data.Int.Core as ℤ
open import Data.Nat.Core using (ℕ)
import Data.Nat.Core as ℕ

private module ℤP = ℤ.Props

ModEq : ℕ → Equiv ℤ
ModEq n =
  record {
    _≈_ = _≈_;
    refl = λ {x} → 0 , ℤP.+-right-inv x;
    sym = λ {x} {y} → sym' x y;
    trans = λ {x} {y} {z} → trans' x y z
  }

  where
  infix 4 _≈_

  _≈_ : ℤ → ℤ → Set
  x ≈ y = ∃ (λ k → x - y ≡ k * pos n)

  sym' : ∀ x y → x ≈ y → y ≈ x
  sym' x y (k , p) =
    neg k ,
    (begin
      y - x           || sym (ℤP.neg-flip x y) ::
      neg (x - y)     || cong neg p ::
      neg (k * pos n) || sym (ℤP.*-assoc -1 k (pos n)) ::
      neg k * pos n
    qed)

    where
    open Equiv (PropEq ℤ)

  trans' : ∀ x y z → x ≈ y → y ≈ z → x ≈ z
  trans' x y z (k1 , p1) (k2 , p2) =
    k1 + k2 ,
    (begin
      x - z                   || cong (x +_) (sym (ℤP.+-left-id (neg z))) ::
      x + (0 - z)             || cong (λ a → x + (a - z)) (sym (ℤP.+-left-inv y)) ::
      x + (neg y + y - z)     || cong (x +_) (ℤP.+-assoc (neg y) y (neg z)) ::
      x + (neg y + (y - z))   || sym (ℤP.+-assoc x (neg y) (y + neg z)) ::
      x + neg y + (y - z)     || cong2 _+_ p1 p2 ::
      k1 * pos n + k2 * pos n || sym (ℤP.*-+-right-dist k1 k2 (pos n)) ::
      (k1 + k2) * pos n
    qed)

    where
    open Equiv (PropEq ℤ)

module Props (n : ℕ) where
  open Equiv (ModEq n) using (_≈_)
  open Equiv (PropEq ℤ) hiding (_≈_)

  +-cong : ∀ {x1 x2 y1 y2} → x1 ≈ x2 → y1 ≈ y2 → x1 + y1 ≈ x2 + y2
  +-cong {x1} {x2} {y1} {y2} (k1 , p1) (k2 , p2) =
    k1 + k2 ,
    (begin
      x1 + y1 - (x2 + y2)   || ℤP.+-assoc x1 y1 _ ::
      x1 + (y1 - (x2 + y2)) ||
      cong (x1 +_) (
        y1 - (x2 + y2)         || cong (y1 +_) (ℤP.*-+-left-dist -1 x2 y2) ::
        y1 + (neg x2 + neg y2) || sym (ℤP.+-assoc y1 (neg x2) (neg y2)) ::
        (y1 + neg x2 + neg y2) || cong (_+ neg y2) (ℤP.+-comm y1 (neg x2)) ::
        neg x2 + y1 + neg y2   || ℤP.+-assoc (neg x2) y1 _ ::
        neg x2 + (y1 + neg y2)
      qed) ::
      x1 + (neg x2 + (y1 + neg y2)) || sym (ℤP.+-assoc x1 (neg x2) _) ::
      x1 - x2 + (y1 - y2)           || cong2 _+_ p1 p2 ::
      k1 * pos n + k2 * pos n       || sym (ℤP.*-+-right-dist k1 k2 (pos n)) ::
      (k1 + k2) * pos n
    qed)


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

open import HoTT
open import homotopy.PushoutSplit

module cw.cohomology.CofiberGrid {i j k}
  {A : Type i} {B : Type j} {C : Type k}
  (f : A → B) (g : B → C) where

  {-
    A -------> B -----------> C
    |          |           _/|
    |          |         _/  |
    |          |     __.D_   |
    v          v .--'   | `-.v
    1 ------> B/A ------|-> C/A
               |        |    |
               |        v    |
               |     __.E_   |
               v .--'     `-.v
               1 ---------> C/B
  -}

  open import cw.cohomology.GridMap f g

  private
    B-to-B/A : B → B/A
    B-to-B/A = cfcod' f

    D-span : Span
    D-span = span B/A C B B-to-B/A g
    D : Type (lmax i (lmax j k))
    D = Pushout D-span

  private
    module VSplit = PushoutRSplit (λ _ → tt) f g
    module C/AToD = VSplit.Split
  C/A-to-D : C/A → D
  C/A-to-D = C/AToD.f

  B/A-to-D : B/A → D
  B/A-to-D = left

  private
    E : Type (lmax i (lmax j k))
    E = Cofiber B/A-to-D

  private
    module HSplit = PushoutLSplit B-to-B/A (λ _ → tt) g
    module C/BToE = HSplit.Split
  C/B-to-E : C/B → E
  C/B-to-E = C/BToE.f

  private
    module DToC/B = HSplit.Inner
    D-to-C/B : D → C/B
    D-to-C/B = DToC/B.f

    D-to-E : D → E
    D-to-E = cfcod

    C/A-to-D-to-C/B : ∀ c/a → D-to-C/B (C/A-to-D c/a) == C/A-to-C/B c/a
    C/A-to-D-to-C/B = Cofiber-elim
      idp
      (λ c → idp)
      (λ a → ↓-='-in' $ ! $
        ap (D-to-C/B ∘ C/A-to-D) (glue a)
          =⟨ ap-∘ D-to-C/B C/A-to-D (glue a) ⟩
        ap D-to-C/B (ap C/A-to-D (glue a))
          =⟨ C/AToD.glue-β a |in-ctx ap D-to-C/B ⟩
        ap D-to-C/B (ap left (glue a) ∙ glue (f a))
          =⟨ ap-∙ D-to-C/B (ap left (glue a)) (glue (f a)) ⟩
        ap D-to-C/B (ap left (glue a)) ∙ ap D-to-C/B (glue (f a))
          =⟨ ap2 _∙_ (∘-ap D-to-C/B left (glue a)) (DToC/B.glue-β (f a)) ⟩
        ap (λ _ → cfbase) (glue a) ∙ glue (f a)
          =⟨ ap-cst cfbase (glue a) |in-ctx _∙ glue (f a) ⟩
        glue (f a)
          =⟨ ! $ C/AToC/B.glue-β a ⟩
        ap C/A-to-C/B (glue a)
          =∎)

    D-to-C/B-to-E : ∀ d → C/B-to-E (D-to-C/B d) == D-to-E d
    D-to-C/B-to-E = HSplit.split-inner

  {- The public interface -}

  C/A-to-C/B-comm-square : CommSquare C/A-to-C/B D-to-E C/A-to-D C/B-to-E
  C/A-to-C/B-comm-square = comm-sqr λ c/a → ap C/B-to-E (! (C/A-to-D-to-C/B c/a))
                                     ∙ D-to-C/B-to-E (C/A-to-D c/a)

  B/A-to-C/A-comm-square : CommSquare B/A-to-C/A B/A-to-D (idf B/A) C/A-to-D
  B/A-to-C/A-comm-square = comm-sqr VSplit.split-inner

  C/A-to-D-is-equiv : is-equiv C/A-to-D
  C/A-to-D-is-equiv = snd VSplit.split-equiv

  C/B-to-E-is-equiv : is-equiv C/B-to-E
  C/B-to-E-is-equiv = snd HSplit.split-equiv


module proofs where

open import lambdasyntax
open import static
open import dynamic

open import Data.Empty
open import Data.Nat
open import Function
open import Data.Vec using (Vec; [])
open import Data.Bool using (Bool; true; false)
open import Relation.Nullary
open import Relation.Binary.PropositionalEquality

-- label precision
data _⊑ˡ_ : (ℓ₁ ℓ₂ : Label) → Set where
    ℓ⊑✭ : ∀ {ℓ} → ℓ ⊑ˡ ✭
    ℓ⊑ℓ : ∀ {ℓ} → ℓ ⊑ˡ ℓ

_⊑ˡ?_ : ∀ (ℓ₁ ℓ₂ : Label) → Dec (ℓ₁ ⊑ˡ ℓ₂)
⊤ ⊑ˡ? ⊤ = yes ℓ⊑ℓ
⊤ ⊑ˡ? ⊥ = no (λ ())
⊤ ⊑ˡ? ✭ = yes ℓ⊑✭
⊥ ⊑ˡ? ⊤ = no (λ ())
⊥ ⊑ˡ? ⊥ = yes ℓ⊑ℓ
⊥ ⊑ˡ? ✭ = yes ℓ⊑✭
✭ ⊑ˡ? ⊤ = no (λ ())
✭ ⊑ˡ? ⊥ = no (λ ())
✭ ⊑ˡ? ✭ = yes ℓ⊑✭

-- type precision
data _⊑_ : (t₁ t₂ : GType) → Set where
    b⊑b : ∀ {ℓ₁ ℓ₂} → ℓ₁ ⊑ˡ ℓ₂ → bool ℓ₁ ⊑ bool ℓ₂
    λ⊑λ : ∀ {s₁₁ s₂₁ s₁₂ s₂₂ ℓ₁ ℓ₂} → s₁₁ ⊑ s₂₁ → s₁₂ ⊑ s₂₂ → ℓ₁ ⊑ˡ ℓ₂ → ((s₁₁ ⇒ ℓ₁) s₁₂) ⊑ ((s₂₁ ⇒ ℓ₂) s₂₂)

lem₁ : ∀ {t₁ t₂ t₃ t₄ ℓ ℓ₁} → (x : (t₁ ⇒ ℓ) t₂ ⊑ (t₃ ⇒ ℓ₁) t₄) → t₃ ⊑ t₁
lem₁ (λ⊑λ x x₁ x₂) = {!  !}

_⊑?_ : ∀ (t₁ t₂ : GType) → Dec (t₁ ⊑ t₂)
bool x ⊑? bool x₁ with x ⊑ˡ? x₁
bool x ⊑? bool x₁ | yes p = yes (b⊑b p)
bool x ⊑? bool x₁ | no ¬p = no (¬p ∘ lem)
    where lem : ∀ {ℓ₁ ℓ₂ : Label} → (bool ℓ₁ ⊑ bool ℓ₂) → ℓ₁ ⊑ˡ ℓ₂
          lem (b⊑b x) = x
bool x ⊑? (t₂ ⇒ x₁) t₃      = no (λ ())
bool x ⊑? err               = no (λ ())
(t₁ ⇒ x) t₂ ⊑? bool x₁      = no (λ ())
(t₁ ⇒ ℓ) t₂ ⊑? (t₃ ⇒ ℓ₁) t₄ with t₃ ⊑? t₁ | t₂ ⊑? t₄
(t₁ ⇒ ℓ) t₂ ⊑? (t₃ ⇒ ℓ₁) t₄ | yes p | (yes p₁) = yes {!   !}
(t₁ ⇒ ℓ) t₂ ⊑? (t₃ ⇒ ℓ₁) t₄ | yes p | (no ¬p) = no (¬p ∘ lem)
    where lem : ∀ {t₁ t₂ t₃ t₄ ℓ ℓ₁} (x : (t₁ ⇒ ℓ) t₂ ⊑ (t₃ ⇒ ℓ₁) t₄) → t₂ ⊑ t₄
          lem (λ⊑λ x x₁ x₂) = x₁
(t₁ ⇒ ℓ) t₂ ⊑? (t₃ ⇒ ℓ₁) t₄ | no ¬p | (yes p) = no {!!}
(t₁ ⇒ ℓ) t₂ ⊑? (t₃ ⇒ ℓ₁) t₄ | no ¬p | (no ¬p₁) = no (¬p ∘ {!   !})
(t₁ ⇒ x) t₂ ⊑? err          = no (λ ())
err ⊑? bool x               = no (λ ())
err ⊑? (t₂ ⇒ x) t₃          = no (λ ())
err ⊑? err                  = no (λ ())


{-# OPTIONS --safe #-}
module Cubical.Algebra.Group.DirProd where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma
open import Cubical.Algebra.Group.Base
open import Cubical.Algebra.Monoid
open import Cubical.Algebra.Semigroup

open GroupStr
open IsGroup hiding (rid ; lid ; invr ; invl)
open IsMonoid hiding (rid ; lid)
open IsSemigroup

DirProd : ∀ {ℓ ℓ'} → Group ℓ → Group ℓ' → Group (ℓ-max ℓ ℓ')
fst (DirProd G H) = fst G × fst H
1g (snd (DirProd G H)) = (1g (snd G)) , (1g (snd H))
_·_ (snd (DirProd G H)) x y = _·_ (snd G) (fst x) (fst y)
                            , _·_ (snd H) (snd x) (snd y)
(inv (snd (DirProd G H))) x = (inv (snd G) (fst x)) , (inv (snd H) (snd x))
is-set (isSemigroup (isMonoid (isGroup (snd (DirProd G H))))) =
  isSet× (is-set (snd G)) (is-set (snd H))
assoc (isSemigroup (isMonoid (isGroup (snd (DirProd G H))))) x y z i =
  assoc (snd G) (fst x) (fst y) (fst z) i , assoc (snd H) (snd x) (snd y) (snd z) i
fst (identity (isMonoid (isGroup (snd (DirProd G H)))) x) i =
  rid (snd G) (fst x) i , rid (snd H) (snd x) i
snd (identity (isMonoid (isGroup (snd (DirProd G H)))) x) i =
  lid (snd G) (fst x) i , lid (snd H) (snd x) i
fst (inverse (isGroup (snd (DirProd G H))) x) i =
  (invr (snd G) (fst x) i) , invr (snd H) (snd x) i
snd (inverse (isGroup (snd (DirProd G H))) x) i =
  (invl (snd G) (fst x) i) , invl (snd H) (snd x) i


{-# OPTIONS --without-K #-}
open import Library
open import Basic

--------------------------------------------------------------------------------
-- Universes for a Functor
--------------------------------------------------------------------------------

record FntrLevel : Set where
  field
    C : CatLevel
    D : CatLevel

  module C = CatLevel C
  module D = CatLevel D

  Fntr : Level
  Fntr = ℓ-max C.Cat D.Cat

--------------------------------------------------------------------------------
-- Definition of a Functor
--------------------------------------------------------------------------------

module _ {ℓ : FntrLevel}    (let module ℓ = FntrLevel ℓ)
         (C : Category ℓ.C) (let module C = Category C)
           (open C using () renaming (_⇒_ to _⇒ᶜ_ ; _∘_ to _∘ᶜ_))
         (D : Category ℓ.D) (let module D = Category D)
           (open D using () renaming (_⇒_ to _⇒ᵈ_ ; _∘_ to _∘ᵈ_)) where

  record Functor : Set ℓ.Fntr where
    field
      map  : C.Obj → D.Obj
      fmap : ∀{X Y} → X ⇒ᶜ Y → (map X) ⇒ᵈ (map Y)

    field
      id   : ∀{X} → fmap (C.id X) ≡ D.id (map X)
      comp : ∀{X Y Z}{f : X ⇒ᶜ Y}{g : Y ⇒ᶜ Z}
               → fmap (g ∘ᶜ f) ≡ (fmap g) ∘ᵈ (fmap f)

--------------------------------------------------------------------------------
-- Definition of a Natural Transformation and a Natural Isomorphism
--------------------------------------------------------------------------------

module _ {ℓ : FntrLevel}     (let module ℓ = FntrLevel ℓ)
         {C : Category ℓ.C}  (let module C = Category C)
           (open C using () renaming (_⇒_ to _⇒ᶜ_ ; _∘_ to _∘ᶜ_))
         {D : Category ℓ.D}  (let module D = Category D)
           (open D using () renaming (_⇒_ to _⇒ᵈ_ ; _∘_ to _∘ᵈ_))
         (F G : Functor C D) (let module F = Functor F)
                                 (let module G = Functor G) where

  record NaturalTrans : Set ℓ.Fntr where
    field
      map    : (X : C.Obj) → (F.map X) ⇒ᵈ (G.map X)
      nat-sq : {X Y : C.Obj}{f : X ⇒ᶜ Y} →
                 (G.fmap f) ∘ᵈ (map X) ≡ (map Y) ∘ᵈ (F.fmap f)

    is-natrual-isomorphism : Set (ℓ-max ℓ.C.Obj ℓ.D.Hom)
    is-natrual-isomorphism = ∀(X : C.Obj) → D.is-isomorphism (map X)

  NaturalIso : Set ℓ.Fntr
  NaturalIso = Σ NaturalTrans NaturalTrans.is-natrual-isomorphism

--------------------------------------------------------------------------------
-- Category of Functors
--------------------------------------------------------------------------------

module _ {ℓ : FntrLevel}     (let module ℓ = FntrLevel ℓ)
         (C : Category ℓ.C) (let module C = Category C)
           (open C using () renaming (_⇒_ to _⇒ᶜ_ ; _∘_ to _∘ᶜ_))
         (D : Category ℓ.D) (let module D = Category D)
           (open D using () renaming (_⇒_ to _⇒ᵈ_ ; _∘_ to _∘ᵈ_)) where

  FntrCat : Category (record { Obj = ℓ.Fntr ; Hom = ℓ.Fntr })
  FntrCat = record { Obj   = Functor C D
                   ; _⇒_   = NaturalTrans
                   ; id    = natural-trans-id
                   ; _∘_   = vertical-comp
                   ; idl   = {!!}
                   ; idr   = {!!}
                   ; assoc = {!!} }
    where
      natural-trans-id : (F : Functor C D) → NaturalTrans F F
      natural-trans-id F = record
        { map    = λ (X : C.Obj) → D.id (F.map X)
        ; nat-sq = λ {X Y : C.Obj} {f : X ⇒ᶜ Y} →               ≡-proof
            (F.fmap f) ∘ᵈ D.id (F.map X)                        ≡⟨ D.idr       ⟩
            F.fmap f                                            ≡⟨ ≡-sym D.idl ⟩
            D.id (F.map Y) ∘ᵈ (F.fmap f)                        ≡-qed
        } where module F = Functor F

      vertical-comp : {F G H : Functor C D}
                        → NaturalTrans G H → NaturalTrans F G → NaturalTrans F H
      vertical-comp {F} {G} {H} β α = record
        { map    = λ (X : C.Obj) → (β.map X) ∘ᵈ (α.map X)
        ; nat-sq = λ {X Y : C.Obj} {f : X ⇒ᶜ Y} →           ≡-proof
            H.fmap f ∘ᵈ (β.map X ∘ᵈ α.map X)          ≡⟨ ≡-sym D.assoc ⟩
            (H.fmap f ∘ᵈ β.map X) ∘ᵈ α.map X          ≡⟨ {!!} ⟩
            (β.map Y ∘ᵈ G.fmap f) ∘ᵈ α.map X          ≡⟨ D.assoc ⟩
            β.map Y ∘ᵈ (G.fmap f ∘ᵈ α.map X)          ≡⟨ {!!} ⟩
            β.map Y ∘ᵈ (α.map Y ∘ᵈ F.fmap f)          ≡⟨ ≡-sym D.assoc ⟩
            (β.map Y ∘ᵈ α.map Y) ∘ᵈ F.fmap f            ≡-qed
        } where module F = Functor F
                module G = Functor G
                module H = Functor H
                module α = NaturalTrans α
                module β = NaturalTrans β

--------------------------------------------------------------------------------
-- Definition of Presheaf
--------------------------------------------------------------------------------

-- module _ {C : CatLevel} (open CatLevel C)
--          (C : Category C) (let module C = Category C) where
--   Presheaf : Category (record { Obj = ℓ-suc Obj ; Hom = ℓ-suc Hom })
--   Presheaf C = record { Obj = Functor C.op (Type Hom)
--                       ; _⇒_ = NaturalTrans
--                       ; id  = NaturalTrans-id
--                       ; __}


module Structure.Operator.Monoid.Invertible.Proofs where

import      Data.Tuple as Tuple
import      Lvl
open import Logic.Propositional
open import Logic.Predicate
open import Structure.Operator
open import Structure.Operator.Monoid
open import Structure.Operator.Monoid.Invertible
open import Structure.Operator.Properties hiding (InverseOperatorₗ ; InverseOperatorᵣ)
open import Structure.Relator.Properties
open import Structure.Setoid
open import Syntax.Transitivity
open import Type

private variable ℓ ℓₗ ℓₑ : Lvl.Level
private variable T : Type{ℓ}
private variable _▫_ : T → T → T
private variable _⨞_ : T → T → Type{ℓₗ}

module _ ⦃ equiv : Equiv{ℓₑ}(T) ⦄ ⦃ monoid : Monoid{T = T}(_▫_) ⦄ ⦃ invRel : InverseRelationᵣ(_▫_){ℓₗ}(_⨞_) ⦄ where
  open Monoid(monoid) using (id)

  instance
    inverseRelationᵣ-reflexivity : Reflexivity(_⨞_)
    Reflexivity.proof inverseRelationᵣ-reflexivity = [↔]-to-[←] (InverseRelationᵣ.proof invRel) ([∃]-intro id ⦃ identityᵣ(_▫_)(id) ⦄)

  instance
    inverseRelationᵣ-transitivity : Transitivity(_⨞_)
    Transitivity.proof inverseRelationᵣ-transitivity xy yz
      with [∃]-intro a ⦃ pa ⦄ ← [↔]-to-[→] (InverseRelationᵣ.proof invRel) xy
      with [∃]-intro b ⦃ pb ⦄ ← [↔]-to-[→] (InverseRelationᵣ.proof invRel) yz
      = [↔]-to-[←] (InverseRelationᵣ.proof invRel) ([∃]-intro (a ▫ b) ⦃ symmetry(_≡_) (associativity(_▫_)) 🝖 congruence₂ₗ(_▫_)(b) pa 🝖 pb ⦄)

  inverseRelationᵣ-with-opᵣ : ∀{a x y} → (x ⨞ y) → ((a ▫ x) ⨞ (a ▫ y))
  inverseRelationᵣ-with-opᵣ {a}{x}{y} xy
    with [∃]-intro z ⦃ xzy ⦄ ← [↔]-to-[→] (InverseRelationᵣ.proof invRel) xy
    = [↔]-to-[←] (InverseRelationᵣ.proof invRel) ([∃]-intro z ⦃ associativity(_▫_) 🝖 congruence₂ᵣ(_▫_)(a) xzy ⦄)

  inverseRelationᵣ-without-opᵣ : ⦃ cancₗ : Cancellationₗ(_▫_) ⦄ → ∀{a x y} → ((a ▫ x) ⨞ (a ▫ y)) → (x ⨞ y)
  inverseRelationᵣ-without-opᵣ {a}{x}{y} xy
    with [∃]-intro z ⦃ xzy ⦄ ← [↔]-to-[→] (InverseRelationᵣ.proof invRel) xy
    = [↔]-to-[←] (InverseRelationᵣ.proof invRel) ([∃]-intro z ⦃ cancellationₗ(_▫_) (symmetry(_≡_) (associativity(_▫_)) 🝖 xzy) ⦄)

  inverseRelationᵣ-of-idₗ : ∀{x} → (id ⨞ x)
  inverseRelationᵣ-of-idₗ {x} = [↔]-to-[←] (InverseRelationᵣ.proof invRel) ([∃]-intro x ⦃ identityₗ(_▫_)(id) ⦄)

  module _ {_⋄_ : (x : T) → (y : T) → . ⦃ inv : (y ⨞ x) ⦄ → T} ⦃ invOper : InverseOperatorᵣ(_▫_)(_⋄_) ⦄ where
    {-op-cancellationᵣ : ∀{a x y} → (a ⨞ x) → (a ⨞ y) → (a ▫ x ≡ a ▫ y) → (x ≡ y)
    op-cancellationᵣ {a}{x}{y} ax ay axay
      with [∃]-intro r ⦃ pr ⦄ ← [↔]-to-[→] (InverseRelationᵣ.proof invRel) ax
      with [∃]-intro s ⦃ ps ⦄ ← [↔]-to-[→] (InverseRelationᵣ.proof invRel) ay
      =
        x 🝖[ _≡_ ]-[ {!!} ]
        y 🝖-end-}

    inverseRelationᵣ-to-invertibleᵣ : ∀{x} → ⦃ x ⨞ id ⦄ → InvertibleElementᵣ(_▫_) ⦃ Monoid.identity-existenceᵣ(monoid) ⦄ (x)
    inverseRelationᵣ-to-invertibleᵣ {x} ⦃ xid ⦄ = [∃]-intro (id ⋄ x) ⦃ intro p ⦄ where
      p =
        (x ▫ (id ⋄ x))                                                    🝖[ _≡_ ]-[ congruence₂ᵣ(_▫_)(x) (InverseOperatorᵣ.proof invOper {id}{x}) ]
        (x ▫ [∃]-witness([↔]-to-[→] (InverseRelationᵣ.proof invRel) xid)) 🝖[ _≡_ ]-[ [∃]-proof([↔]-to-[→] (InverseRelationᵣ.proof invRel) xid) ]
        id                                                                🝖-end

    {- TODO: Should this not be possible without cancellation?
    inverseOperator-self : ∀{x} → let instance _ = reflexivity(_⨞_) in (x ⋄ x ≡ id)
    inverseOperator-self {x} = let instance _ = reflexivity(_⨞_) {x} in
      (x ⋄ x)                                                                        🝖[ _≡_ ]-[ InverseOperatorᵣ.proof invOper {x}{x} ]
      [∃]-witness([↔]-to-[→] (InverseRelationᵣ.proof invRel) (reflexivity(_⨞_) {x})) 🝖[ _≡_ ]-[]
      ∃.witness(Tuple.right(InverseRelationᵣ.proof invRel) (reflexivity(_⨞_)))       🝖[ _≡_ ]-[ {!!} ]
      id                                                                             🝖-end
    -}


module Data.Union.Relation.Binary.Subtype where

open import Data.List using (List)
open import Data.List.Relation.Unary.Any using (here; there)
open import Data.List.Relation.Binary.Subset.Propositional using (_⊆_)

open import Data.Union using (Union; here; there; inj)

open import Function using (_∘_; id)

open import Relation.Binary.PropositionalEquality using () renaming (refl to refl≡)

open import Level using (Level; _⊔_)

-- ----------------------------------------------------------------------
-- Subtyping

private
  variable
    a b c d f : Level
    A : Set a
    B : Set b
    C : Set c
    D : Set d

    F : A → Set f
    ts ts′ : List A

infix 4 _≼_ _,_⊢_≼_

_≼_ : Set a → Set b → Set (a ⊔ b)
A ≼ B = A → B

_,_⊢_≼_ : (A : Set a) → (F : A → Set b) → List A → List A → Set (a ⊔ b)
A , F ⊢ ts ≼ ts′ = Union A F ts ≼ Union A F ts′

refl : A ≼ A
refl = id

trans : A ≼ B → B ≼ C → A ≼ C
trans A≼B B≼C = B≼C ∘ A≼B

generalize : ts ⊆ ts′ → A , F ⊢ ts ≼ ts′
generalize ts⊆ts′ (here x) = inj (ts⊆ts′ (here refl≡)) x
generalize ts⊆ts′ (there x) = generalize (ts⊆ts′ ∘ there) x

function : C ≼ A → B ≼ D → (A → B) ≼ (C → D)
function C≼A B≼D f = B≼D ∘ f ∘ C≼A

coerce : A ≼ B → A → B
coerce = id


{-# OPTIONS --cubical --guardedness --safe #-}

module Data.PolyP.Universe where

open import Prelude hiding (_⟨_⟩_)
open import Data.Vec.Iterated
open import Data.Fin.Indexed

--------------------------------------------------------------------------------
--
--  The Universe of functors we're interested in.
--
--------------------------------------------------------------------------------
data Functor (n : ℕ) : Type where
  !     : Fin n → Functor n
  _⊕_   : (F G : Functor n) → Functor n
  _⊗_   : (F G : Functor n) → Functor n
  μ⟨_⟩  : Functor (suc n) → Functor n
  ⓪     : Functor n
  ①     : Functor n

infixl 6 _⊕_
infixl 7 _⊗_

Params : ℕ → Type₁
Params = Vec Type

variable
  n m k : ℕ
  F G : Functor n
  As Bs : Params n

---------------------------------------------------------------------------------
--
-- Interpretation
--
---------------------------------------------------------------------------------

mutual
  ⟦_⟧ : Functor n → Params n → Type
  ⟦ ! i     ⟧ xs = xs [ i ]
  ⟦ F ⊕  G  ⟧ xs = ⟦ F ⟧ xs ⊎  ⟦ G ⟧ xs
  ⟦ F ⊗  G  ⟧ xs = ⟦ F ⟧ xs ×  ⟦ G ⟧ xs
  ⟦ μ⟨ F ⟩  ⟧ xs = μ F xs
  ⟦ ⓪       ⟧ xs = ⊥
  ⟦ ①       ⟧ xs = ⊤

  record μ (F : Functor (suc n)) (As : Params n) : Type where
    pattern; inductive; constructor ⟨_⟩
    field unwrap : ⟦ F ⟧ (μ F As ∷ As)
open μ public


module lib.libraryDec where

-- old version of Dec
--

open import Data.Empty
open import Level
open import Relation.Nullary using ( ¬_ )

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


module Prelude.Equality.Inspect where

open import Prelude.Function using (id)
open import Prelude.Equality
open import Prelude.Product

module _ {a b} {A : Set a} {B : A → Set b} (f : ∀ x → B x) (x : A) where

  -- The Graph idiom is more powerful than the old Inspect idiom
  -- (defined in terms of Graph below), in that it lets you both
  -- abstract over a term and keep the equation that the old term
  -- equals the abstracted variable.

  -- Use as follows:
  --   example : Γ → T (f e)
  --   example xs with f e | graphAt f e
  --   ... | z | ingraph eq = ?  -- eq : f e ≡ z, goal : T z

  data Graph (y : B x) : Set b where
    ingraph : f x ≡ y → Graph y

  graphAt : Graph (f x)
  graphAt = ingraph refl
  {-# INLINE graphAt #-}

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

  Inspect : A → Set a
  Inspect x = Σ _ λ y → Graph id x y

  infix 4 _with≡_
  pattern _with≡_ x eq = x , ingraph eq

  inspect : ∀ x → Inspect x
  inspect x = x , ingraph refl
  {-# INLINE inspect #-}


module Numeral.FixedPositional where

import      Lvl
open import Data using (<>)
open import Data.List
open import Data.Boolean hiding (elim)
open import Data.Boolean.Stmt
open import Numeral.Finite
open import Numeral.Natural
open import Functional
open import Syntax.Number
open import Type

private variable ℓ : Lvl.Level
private variable z : Bool
private variable b n : ℕ

-- A formalization of the fixed positional radix numeral system for the notation of numbers.
-- Each number is represented by a list of digits.
-- Digits are a finite set of ordered objects starting with zero (0), and a finite number of its successors.
-- Examples using radix 10 (b = 10):
--   ∅                               represents 0
--   # 0                             represents 0
--   # 0 · 0                         represents 0
--   # 2                             represents 2
--   # 1 · 3                         represents 13
--   # 5 · 0 · 4 · 0 · 0             represents 50400
--   # 0 · 5 · 0 · 4 · 0 · 0         represents 50400
--   # 0 · 0 · 0 · 5 · 0 · 4 · 0 · 0 represents 50400
--   # 5 · 0 · 4 · 0 · 0 · 0         represents 504000
-- Example using radix 2 (b = 2):
--   # 1 · 1             represents 3
--   # 0 · 1 · 0 · 1 · 1 represents 11
-- Note: The radix is also called base.
-- Note: This representation is in little endian: The deepest digit in the list is the most significant digit (greatest), and the first position of the list is the least significant digit. Note that the (_·_) operator is a reversed list cons operator, so it constructs a list from right to left when written without parenthesis.
Positional = List ∘ 𝕟
pattern # n = n ⊰ ∅
pattern _·_ a b = b ⊰ a
infixl 100 _·_

private variable x y : Positional(b)
private variable d : 𝕟(n)

-- Two positionals are equal when the sequence of digits in the lists are the same.
-- But also, when there are zeroes at the most significant positions, they should be skipped.
-- Examples:
--   # 4 · 5         ≡ₚₒₛ # 4 · 5
--   # 0 · 0 · 4 · 5 ≡ₚₒₛ # 4 · 5
--   # 4 · 5         ≡ₚₒₛ # 0 · 0 · 4 · 5
--   # 0 · 0 · 4 · 5 ≡ₚₒₛ # 0 · 4 · 5
data _≡ₚₒₛ_ : Positional b → Positional b → Type{Lvl.𝟎} where
  empty : (_≡ₚₒₛ_ {b} ∅ ∅)
  skipₗ : (x ≡ₚₒₛ ∅) → (x · 𝟎 ≡ₚₒₛ ∅)
  skipᵣ : (∅ ≡ₚₒₛ y) → (∅ ≡ₚₒₛ y · 𝟎)
  step  : (x ≡ₚₒₛ y) → (x · d ≡ₚₒₛ y · d)

module _ where
  open import Numeral.Natural.Oper

  -- Converts a positional to a number by adding the first digit and multiplying the rest with the radix.
  -- Examples in radix 10 (b = 10):
  --   to-ℕ (# 1 · 2 · 3) = 10 ⋅ (10 ⋅ (10 ⋅ 0 + 1) + 2) + 3 = ((0 + 100) + 20) + 3 = 100 + 20 + 3 = 123
  --   to-ℕ (# a · b · c) = 10 ⋅ (10 ⋅ (10 ⋅ 0 + a) + b) + c = (10² ⋅ a) + (10¹ ⋅ b) + c = (10² ⋅ a) + (10¹ ⋅ b) + (10⁰ ⋅ c)
  to-ℕ : Positional b → ℕ
  to-ℕ     ∅       = 𝟎
  to-ℕ {b} (l · n) = (b ⋅ (to-ℕ l)) + (𝕟-to-ℕ n)

  import      Data.List.Functions as List
  open import Logic.Propositional
  open import Numeral.Finite.Proofs
  open import Numeral.Natural.Inductions
  open import Numeral.Natural.Oper.Comparisons
  open import Numeral.Natural.Oper.FlooredDivision
  open import Numeral.Natural.Oper.FlooredDivision.Proofs
  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
  open import Structure.Relator.Ordering
  import      Structure.Relator.Names as Names
  open import Structure.Relator.Equivalence
  open import Structure.Relator.Properties
  open import Syntax.Transitivity
  open import Type.Properties.Decidable
  open import Type.Properties.Decidable.Proofs

  -- Converts a number to its positional representation in the specified radix.
  -- This is done by extracting the next digit using modulo of the radix and then dividing the rest.
  -- This is the inverse of to-ℕ.
  from-ℕ-rec : ⦃ b-size : IsTrue(b >? 1) ⦄ → (x : ℕ) → ((prev : ℕ) ⦃ _ : prev < x ⦄ → Positional(b)) → Positional(b)
  from-ℕ-rec b@{𝐒(𝐒 _)} 𝟎       _    = ∅
  from-ℕ-rec b@{𝐒(𝐒 _)} n@(𝐒 _) prev = (prev(n ⌊/⌋ b) ⦃ [⌊/⌋]-ltₗ {n}{b} ⦄) · (ℕ-to-𝕟 (n mod b) ⦃ [↔]-to-[→] decider-true (mod-maxᵣ{n}{b}) ⦄)
  from-ℕ : ℕ → Positional(b)
  from-ℕ {0}        = const ∅
  from-ℕ {1}        = List.repeat 𝟎
  from-ℕ b@{𝐒(𝐒 _)} = Strict.Properties.wellfounded-recursion(_<_) from-ℕ-rec

  instance
    [≡ₚₒₛ]-reflexivity : Reflexivity(_≡ₚₒₛ_ {b})
    [≡ₚₒₛ]-reflexivity = intro p where
      p : Names.Reflexivity(_≡ₚₒₛ_ {b})
      p {x = ∅}     = empty
      p {x = _ ⊰ _} = _≡ₚₒₛ_.step p

  instance
    [≡ₚₒₛ]-symmetry : Symmetry(_≡ₚₒₛ_ {b})
    [≡ₚₒₛ]-symmetry = intro p where
      p : Names.Symmetry(_≡ₚₒₛ_ {b})
      p empty            = empty
      p (skipₗ eq)       = skipᵣ (p eq)
      p (skipᵣ eq)       = skipₗ (p eq)
      p (_≡ₚₒₛ_.step eq) = _≡ₚₒₛ_.step (p eq)

  instance
    [≡ₚₒₛ]-transitivity : Transitivity(_≡ₚₒₛ_ {b})
    [≡ₚₒₛ]-transitivity = intro p where
      p : Names.Transitivity(_≡ₚₒₛ_ {b})
      p empty           empty           = empty
      p empty           (skipᵣ b)       = skipᵣ b
      p (skipₗ a)       empty           = skipₗ a
      p (skipₗ a)       (skipᵣ b)       = _≡ₚₒₛ_.step (p a b)
      p (skipᵣ a)       (skipₗ b)       = p a b
      p (skipᵣ a)       (_≡ₚₒₛ_.step b) = skipᵣ (p a b)
      p (_≡ₚₒₛ_.step a) (skipₗ b)       = skipₗ (p a b)
      p (_≡ₚₒₛ_.step a) (_≡ₚₒₛ_.step b) = _≡ₚₒₛ_.step (p a b)

  instance
    [≡ₚₒₛ]-equivalence : Equivalence(_≡ₚₒₛ_ {b})
    [≡ₚₒₛ]-equivalence = intro

  open import Structure.Setoid using (Equiv ; intro)

  Positional-equiv : Equiv(Positional(b))
  Positional-equiv {b} = intro _ ⦃ [≡ₚₒₛ]-equivalence {b} ⦄

  open import Lang.Instance
  open import Numeral.Natural.Relation.Proofs
  open import Structure.Function
  open import Structure.Operator
  open import Relator.Equals
  open import Relator.Equals.Proofs

  from-ℕ-digit : ⦃ b-size : IsTrue(b >? 1) ⦄ → ⦃ _ : IsTrue(n <? b) ⦄ → (from-ℕ {b} n ≡ₚₒₛ ℕ-to-𝕟 n ⊰ ∅)
  from-ℕ-digit b@{𝐒(𝐒 bb)} {n} = Strict.Properties.wellfounded-recursion-intro(_<_) {rec = from-ℕ-rec} {φ = \{n} expr → ⦃ _ : IsTrue(n <? b) ⦄ → (expr ≡ₚₒₛ (ℕ-to-𝕟 n ⊰ ∅))} p {n} where
    p : (y : ℕ) → _ → _ → ⦃ _ : IsTrue(y <? b) ⦄ → (from-ℕ y ≡ₚₒₛ (ℕ-to-𝕟 y ⊰ ∅))
    p 𝟎 prev eq = skipᵣ empty
    p (𝐒 y) prev eq ⦃ ord ⦄ =
      from-ℕ (𝐒(y))                                                         🝖[ _≡ₚₒₛ_ ]-[ sub₂(_≡_)(_≡ₚₒₛ_) (eq{y} ⦃ reflexivity(_≤_) ⦄) ]
      from-ℕ (𝐒(y) ⌊/⌋ b) · ℕ-to-𝕟 (𝐒(y) mod b) ⦃ yb-ord? ⦄                 🝖[ _≡ₚₒₛ_ ]-[ _≡ₚₒₛ_.step (prev ⦃ [⌊/⌋]-ltₗ{𝐒 y}{b}  ⦄ ⦃ div-ord ⦄) ]
      ∅ · ℕ-to-𝕟 (𝐒(y) ⌊/⌋ b) ⦃ div-ord ⦄ · ℕ-to-𝕟 (𝐒(y) mod b) ⦃ yb-ord? ⦄ 🝖[ _≡ₚₒₛ_ ]-[ sub₂(_≡_)(_≡ₚₒₛ_) (congruence₂ᵣ(_·_)(_) (congruence-ℕ-to-𝕟 ⦃ infer ⦄ ⦃ yb-ord? ⦄ (mod-lesser-than-modulus {𝐒 y}{𝐒 bb} ⦃ yb-ord ⦄))) ]
      ∅ · ℕ-to-𝕟 (𝐒(y) ⌊/⌋ b) ⦃ div-ord ⦄ · ℕ-to-𝕟 (𝐒(y))                   🝖[ _≡ₚₒₛ_ ]-[ _≡ₚₒₛ_.step (sub₂(_≡_)(_≡ₚₒₛ_) (congruence₂ᵣ(_·_)(_) (congruence-ℕ-to-𝕟 ⦃ infer ⦄ ⦃ div-ord ⦄ ([⌊/⌋]-zero {𝐒 y}{b} yb-ord2)))) ]
      ∅ · 𝟎 · ℕ-to-𝕟 (𝐒(y))                                                 🝖[ _≡ₚₒₛ_ ]-[ _≡ₚₒₛ_.step (skipₗ empty) ]
      ∅ · ℕ-to-𝕟 (𝐒(y))                                                     🝖-end
      where
        yb-ord? = [↔]-to-[→] decider-true (mod-maxᵣ {𝐒(y)}{b} ⦃ infer ⦄)
        yb-ord = [↔]-to-[←] (decider-true ⦃ [<]-decider ⦄) ord
        yb-ord2 = [↔]-to-[←] (decider-true ⦃ [<]-decider ⦄) ord
        div-ord = [↔]-to-[→] decider-true ([⌊/⌋]-preserve-[<]ₗ {𝐒 y}{b}{b} yb-ord2)

  from-ℕ-step : ⦃ b-size : IsTrue(b >? 1) ⦄
              → let pos = [↔]-to-[←] Positive-greater-than-zero ([≤]-predecessor ([↔]-to-[←] (decider-true ⦃ [<]-decider {1}{b} ⦄) b-size))
                in (from-ℕ {b} n ≡ₚₒₛ (from-ℕ {b} ((n ⌊/⌋ b) ⦃ pos ⦄)) · (ℕ-to-𝕟 ((n mod b) ⦃ pos ⦄) ⦃ [↔]-to-[→] decider-true (mod-maxᵣ{n}{b} ⦃ pos ⦄) ⦄))
  from-ℕ-step b@{𝐒(𝐒 bb)} {n} = Strict.Properties.wellfounded-recursion-intro(_<_) {rec = from-ℕ-rec} {φ = \{n} expr → (expr ≡ₚₒₛ from-ℕ {b} (n ⌊/⌋ b) · (ℕ-to-𝕟 (n mod b) ⦃ ord n ⦄))} p {n} where
    ord = \n → [↔]-to-[→] decider-true (mod-maxᵣ{n}{b})
    p : (y : ℕ) → _ → _ → Strict.Properties.accessible-recursion(_<_) from-ℕ-rec y ≡ₚₒₛ from-ℕ (y ⌊/⌋ b) · ℕ-to-𝕟 (y mod b) ⦃ ord y ⦄
    p 𝟎     prev eq = skipᵣ empty
    p (𝐒 y) prev eq = (sub₂(_≡_)(_≡ₚₒₛ_) (eq {y} ⦃ reflexivity(_≤_) ⦄))

  open import Numeral.Natural.Oper.FlooredDivision.Proofs.Inverse
  open import Numeral.Natural.Oper.Proofs
  open import Structure.Operator.Properties
  from-ℕ-step-invs : ⦃ b-size : IsTrue(b >? 1) ⦄ → (from-ℕ {b} ((b ⋅ n) + (𝕟-to-ℕ d)) ≡ₚₒₛ (from-ℕ {b} n) · d)
  from-ℕ-step-invs b@{𝐒(𝐒 bb)} {n}{d} =
    from-ℕ (b ⋅ n + 𝕟-to-ℕ d)                                                     🝖[ _≡ₚₒₛ_ ]-[ from-ℕ-step {n = b ⋅ n + 𝕟-to-ℕ d} ]
    from-ℕ ((b ⋅ n + 𝕟-to-ℕ d) ⌊/⌋ b) · (ℕ-to-𝕟 ((b ⋅ n + 𝕟-to-ℕ d) mod b) ⦃ _ ⦄) 🝖[ _≡ₚₒₛ_ ]-[ sub₂(_≡_)(_≡ₚₒₛ_) (congruence₂(_·_) (congruence₁(from-ℕ) r) (congruence-ℕ-to-𝕟 ⦃ infer ⦄ ⦃ ord1 ⦄ ⦃ ord2 ⦄ q 🝖 ℕ-𝕟-inverse)) ]
    from-ℕ n · d                                                                  🝖-end where
      ord1 = [↔]-to-[→] decider-true (mod-maxᵣ{(b ⋅ n) + (𝕟-to-ℕ d)}{b})
      ord2 = [↔]-to-[→] decider-true ([<]-of-𝕟-to-ℕ {b}{d})
      q =
        ((b ⋅ n) + 𝕟-to-ℕ d) mod b 🝖[ _≡_ ]-[ congruence₁(_mod b) (commutativity(_+_) {b ⋅ n}{𝕟-to-ℕ d}) ]
        (𝕟-to-ℕ d + (b ⋅ n)) mod b 🝖[ _≡_ ]-[ mod-of-modulus-sum-multiple {𝕟-to-ℕ d}{b}{n} ]
        (𝕟-to-ℕ d) mod b           🝖[ _≡_ ]-[ mod-lesser-than-modulus ⦃ [≤]-without-[𝐒] [<]-of-𝕟-to-ℕ ⦄ ]
        𝕟-to-ℕ d                   🝖-end
      r =
        (b ⋅ n + 𝕟-to-ℕ d) ⌊/⌋ b             🝖[ _≡_ ]-[ [⌊/⌋][+]-distributivityᵣ {b ⋅ n}{𝕟-to-ℕ d}{b} ]
        ((b ⋅ n) ⌊/⌋ b) + ((𝕟-to-ℕ d) ⌊/⌋ b) 🝖[ _≡_ ]-[ congruence₂(_+_) ([⌊/⌋][swap⋅]-inverseOperatorᵣ {b}{n}) ([⌊/⌋]-zero ([<]-of-𝕟-to-ℕ {b}{d})) ]
        n + 𝟎                                🝖[ _≡_ ]-[]
        n                                    🝖-end

  open import Numeral.Natural.Oper.DivMod.Proofs
  open import Structure.Function.Domain
  import      Structure.Function.Names as Names

  instance
    from-to-inverse : ⦃ b-size : IsTrue(b >? 1) ⦄ → Inverseᵣ ⦃ Positional-equiv{b} ⦄ from-ℕ to-ℕ
    from-to-inverse b@{𝐒(𝐒 _)} = intro p where
      p : Names.Inverses ⦃ Positional-equiv{b} ⦄ from-ℕ to-ℕ
      p{x = ∅}     = empty
      p{x = x · n} = from-ℕ-step-invs{b}{to-ℕ x}{n} 🝖 _≡ₚₒₛ_.step (p{x = x})

  instance
    to-from-inverse : ⦃ b-size : IsTrue(b >? 1) ⦄ → Inverseᵣ(to-ℕ{b}) (from-ℕ{b})
    to-from-inverse {b@(𝐒(𝐒 bb))} = intro (\{n} → Strict.Properties.wellfounded-recursion-intro(_<_) {rec = from-ℕ-rec {b}} {φ = \{n} expr → (to-ℕ expr ≡ n)} p {n}) where
      p : (y : ℕ) → _ → _ → (to-ℕ {b} (from-ℕ {b} y) ≡ y)
      p 𝟎     _    _  = [≡]-intro
      p (𝐒 y) prev eq =
        to-ℕ {b} (from-ℕ (𝐒 y))                                                       🝖[ _≡_ ]-[ congruence₁(to-ℕ) (eq {𝐒(y) ⌊/⌋ b} ⦃ ord2 ⦄) ]
        to-ℕ {b} ((from-ℕ (𝐒(y) ⌊/⌋ b)) · (ℕ-to-𝕟 (𝐒(y) mod b) ⦃ _ ⦄))                🝖[ _≡_ ]-[]
        (b ⋅ to-ℕ {b} (from-ℕ {b} (𝐒(y) ⌊/⌋ b))) + 𝕟-to-ℕ (ℕ-to-𝕟 (𝐒(y) mod b) ⦃ _ ⦄) 🝖[ _≡_ ]-[ congruence₂(_+_) (congruence₂ᵣ(_⋅_)(b) (prev{𝐒(y) ⌊/⌋ b} ⦃ ord2 ⦄)) (𝕟-ℕ-inverse {b}{𝐒(y) mod b} ⦃ ord1 ⦄) ]
        (b ⋅ (𝐒(y) ⌊/⌋ b)) + (𝐒(y) mod b)                                             🝖[ _≡_ ]-[ [⌊/⌋][mod]-is-division-with-remainder-pred-commuted {𝐒 y}{b} ]
        𝐒(y)                                                                          🝖-end
        where
          ord1 = [↔]-to-[→] decider-true (mod-maxᵣ{𝐒(y)}{b})
          ord2 = [⌊/⌋]-ltₗ {𝐒 y}{b}

  instance
    to-ℕ-function : ⦃ b-size : IsTrue(b >? 1) ⦄ → Function ⦃ Positional-equiv ⦄ ⦃ [≡]-equiv ⦄ (to-ℕ {b})
    to-ℕ-function {b} = intro p where
      p : Names.Congruence₁ ⦃ Positional-equiv ⦄ ⦃ [≡]-equiv ⦄ (to-ℕ {b})
      p empty                          = reflexivity(_≡_)
      p (skipₗ xy) rewrite p xy        = reflexivity(_≡_)
      p (skipᵣ {y = ∅} xy)             = reflexivity(_≡_)
      p (skipᵣ {y = 𝟎 ⊰ y} (skipᵣ xy))
        rewrite symmetry(_≡_) (p xy)   = reflexivity(_≡_)
      p (_≡ₚₒₛ_.step xy)
        rewrite p xy = reflexivity(_≡_)

  open import Logic.Predicate
  open import Structure.Function.Domain.Proofs

  instance
    from-ℕ-bijective : ⦃ b-size : IsTrue(b >? 1) ⦄ → Bijective ⦃ [≡]-equiv ⦄ ⦃ Positional-equiv ⦄ (from-ℕ {b})
    from-ℕ-bijective = [↔]-to-[→] (invertible-when-bijective ⦃ _ ⦄ ⦃ _ ⦄) ([∃]-intro to-ℕ ⦃ [∧]-intro infer ([∧]-intro infer infer) ⦄)

  instance
    to-ℕ-bijective : ⦃ b-size : IsTrue(b >? 1) ⦄ → Bijective ⦃ Positional-equiv ⦄ ⦃ [≡]-equiv ⦄ (to-ℕ {b})
    to-ℕ-bijective = [↔]-to-[→] (invertible-when-bijective ⦃ _ ⦄ ⦃ _ ⦄) ([∃]-intro from-ℕ ⦃ [∧]-intro ([≡]-to-function ⦃ Positional-equiv ⦄) ([∧]-intro infer infer) ⦄)

  import      Data.Option.Functions as Option
  open import Function.Names
  open import Numeral.Natural.Relation.Order.Proofs

  -- TODO: Trying to define a bijection, but not really possible because not all functions
  PositionalSequence : List(𝕟(𝐒 b)) → (ℕ → 𝕟(𝐒 b))
  PositionalSequence l n = (List.index₀ n l) Option.or 𝟎

  sequencePositional : (f : ℕ → 𝕟(𝐒 b)) → ∃(N ↦ (f ∘ (_+ N) ⊜ const 𝟎)) → List(𝕟(𝐒 b))
  sequencePositional f ([∃]-intro 𝟎)           = ∅
  sequencePositional f ([∃]-intro (𝐒 N) ⦃ p ⦄) = f(𝟎) ⊰ sequencePositional (f ∘ 𝐒) ([∃]-intro N ⦃ \{n} → p{n} ⦄)


{-# OPTIONS --universe-polymorphism #-}
module Categories.Functor.Algebras where

open import Level hiding (lift)

open import Categories.Category
open import Categories.Functor hiding (_≡_; id; _∘_; equiv; assoc; identityˡ; identityʳ; ∘-resp-≡)
open import Categories.Functor.Algebra

record F-Algebra-Morphism {o ℓ e} {C : Category o ℓ e} {F : Endofunctor C} (X Y : F-Algebra F) : Set (ℓ ⊔ e) where
  constructor _,_
  open Category C
  module X = F-Algebra X
  module Y = F-Algebra Y
  open Functor F
  field
    f : X.A ⇒ Y.A
    .commutes : f ∘ X.α ≡ Y.α ∘ F₁ f

F-Algebras : ∀ {o ℓ e} {C : Category o ℓ e} → Endofunctor C → Category (ℓ ⊔ o) (e ⊔ ℓ) e
F-Algebras {C = C} F = record
  { Obj = Obj′
  ; _⇒_ = Hom′
  ; _≡_ = _≡′_
  ; _∘_ = _∘′_
  ; id = id′
  ; assoc = assoc
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; equiv = record
    { refl = refl
    ; sym = sym
    ; trans = trans
    }
  ; ∘-resp-≡ = ∘-resp-≡
  }
  where
  open Category C
  open Equiv
  open Functor F

  Obj′ = F-Algebra F

  Hom′ : (A B : Obj′) → Set _
  Hom′ = F-Algebra-Morphism

  _≡′_ : ∀ {A B} (f g : Hom′ A B) → Set _
  (f , _) ≡′ (g , _) = f ≡ g

  _∘′_ : ∀ {A B C} → Hom′ B C → Hom′ A B → Hom′ A C
  _∘′_ {A} {B} {C} (f , pf₁) (g , pf₂) = _,_ {X = A} {C} (f ∘ g) pf -- TODO: find out why the hell I need to provide these implicits
    where
    module A = F-Algebra A
    module B = F-Algebra B
    module C = F-Algebra C

    .pf : (f ∘ g) ∘ A.α ≡ C.α ∘ (F₁ (f ∘ g))
    pf = begin
           (f ∘ g) ∘ A.α
         ↓⟨ assoc ⟩
           f ∘ (g ∘ A.α)
         ↓⟨ ∘-resp-≡ʳ pf₂ ⟩
           f ∘ (B.α ∘ F₁ g)
         ↑⟨ assoc ⟩
           (f ∘ B.α) ∘ F₁ g
         ↓⟨ ∘-resp-≡ˡ pf₁ ⟩
           (C.α ∘ F₁ f) ∘ F₁ g
         ↓⟨ assoc ⟩
           C.α ∘ (F₁ f ∘ F₁ g)
         ↑⟨ ∘-resp-≡ʳ homomorphism ⟩
           C.α ∘ (F₁ (f ∘ g))
         ∎
      where
      open HomReasoning

  id′ : ∀ {A} → Hom′ A A
  id′ {A} = _,_ {X = A} {A} id pf
    where
    module A = F-Algebra A

    .pf : id ∘ A.α ≡ A.α ∘ F₁ id
    pf = begin
           id ∘ A.α
         ↓⟨ identityˡ ⟩
           A.α
         ↑⟨ identityʳ ⟩
           A.α ∘ id
         ↑⟨ ∘-resp-≡ʳ identity ⟩
           A.α ∘ F₁ id
         ∎
      where
      open HomReasoning

open import Categories.Object.Initial

module Lambek {o ℓ e} {C : Category o ℓ e} {F : Endofunctor C} (I : Initial (F-Algebras F)) where
  open Category C
  open Equiv
  module FA = Category (F-Algebras F) renaming (_∘_ to _∘FA_; _≡_ to _≡FA_)
  open Functor F
  import Categories.Morphisms as Morphisms
  open Morphisms C
  open Initial I
  open F-Algebra ⊥

  lambek : A ≅ F₀ A
  lambek = record
    { f = f′
    ; g = g′
    ; iso = iso′
    }
    where
    f′ : A ⇒ F₀ A
    f′ = F-Algebra-Morphism.f (! {lift ⊥})

    g′ : F₀ A ⇒ A
    g′ = α

    .iso′ : Iso f′ g′
    iso′ = record
      { isoˡ = isoˡ′
      ; isoʳ = begin
                 f′ ∘ g′
               ↓⟨ F-Algebra-Morphism.commutes (! {lift ⊥}) ⟩
                 F₁ g′ ∘ F₁ f′
               ↑⟨ homomorphism ⟩
                 F₁ (g′ ∘ f′)
               ↓⟨ F-resp-≡ isoˡ′ ⟩
                 F₁ id
               ↓⟨ identity ⟩
                 id
               ∎
      }
      where
      open FA hiding (id; module HomReasoning)
      open HomReasoning

      isoˡ′ = ⊥-id ((_,_ {C = C} {F} g′ refl) ∘FA !)

open Lambek public


-- Andreas, 2015-06-17
-- Postponing checkArguments dropped already inserted implicit arguments.

{-# OPTIONS --show-implicit #-}
-- {-# OPTIONS -v tc.def.alias:100 -v tc.decl:10 -v tc.term.expr:20 -v tc.data.con:20 #-}
-- {-# OPTIONS  -v tc.meta.assign:10 #-}
-- {-# OPTIONS  -v tc.term.expr.args:80 #-}
-- {-# OPTIONS  -v tc.term.args:30 #-}

postulate
  S : Set
  Cxt : Set
  N : (Γ : Cxt) → Set

  NeP  : ∀ (i : S) Δ (n : N Δ) → Set
  inhN : ∀ i Δ (v : N Δ) → NeP i Δ v

data Val (Δ : Cxt) : Set where
  ne : ∀ (n : N Δ) → Val Δ

-- BEGIN mutual

data ValP i Δ : (v : Val Δ) → Set
NeO : _

data ValP i Δ where
  cn  : ∀ (n : N Δ) → NeO n i  → ValP i Δ (ne n)
-- adding constructor cn : (n : N Δ) → _24 i Δ n → ValP i Δ (ne n)
-- LATER    : term _24 i Δ n := NeO n i
-- SHOULD BE: term _24 i Δ n := NeO {Δ} i n

-- must be last in mutual block for error
-- implicit argument needed for error
-- NeO_[_] : ∀ {Δ} (n : N Δ) (i : S) → Set  -- full type signature removes error
NeO = λ {Δ} n i → NeP i Δ n

-- END mutual

inhVal : ∀ i Δ (v : Val Δ) → ValP i Δ v
inhVal i Δ (ne n) = cn n (inhN i Δ n)

-- Checking inhN i Δ n : NeO n [ i ] -->  λ i₁ → NeP i₁ n i

-- ANALYSIS:
-- checked type signature NeO : _20
-- checking constructor cn : (n : N Δ) → NeO n i → ValP i Δ (ne n)
-- adding constructor cn : (n : N Δ) → _24 i Δ n → ValP i Δ (ne n)
-- postponed checking arguments [n, i] against _20
-- progress: checked [] remaining [n, i] : _20
-- term _20 :>= {Δ : _27} → _29 {Δ}
-- term _20 :>= {Δ : _27} → _29 {Δ}
-- solving _20 := {Δ : _27} → _29 {Δ}
-- postponed checking arguments [n, i] against _29 {_Δ_30 i Δ n}
-- progress: checked [] remaining [n, i] : _29 {_Δ_30 i Δ n}
-- Checking λ n i → NeP i Δ n : _29 {Δ}
-- solving _29 := λ {Δ} → (n : N Δ) (i : S) → Set
-- solving _24 := (λ i Δ n → NeO n i)