-- Pattern synonyms are now allowed in parameterised modules.
module _ where

module L (A : Set) where
  data List : Set where
    nil : List
    cons : A → List → List
  pattern unit x = cons x nil

data Bool : Set where
  true false : Bool

module LB = L Bool
open LB

init : List → List
init nil = nil
init (unit _) = nil
init (cons x xs) = cons x (init xs)

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

test : init (cons true (unit false)) ≡ unit true
test = refl


open import Formalization.PredicateLogic.Signature

module Formalization.PredicateLogic.Syntax (𝔏 : Signature) where
open Signature(𝔏)

open import Data.ListSized
import      Lvl
open import Functional using (_∘_ ; _∘₂_ ; swap)
open import Numeral.Finite
open import Numeral.Natural
open import Sets.PredicateSet using (PredSet)
open import Type

private variable ℓ : Lvl.Level
private variable args vars : ℕ

data Term (vars : ℕ) : Type{ℓₒ} where
  var  : 𝕟(vars) → Term(vars)                       -- Variables
  func : Obj(args) → List(Term(vars))(args) → Term(vars) -- Constants/functions

-- Formulas.
-- Inductive definition of the grammatical elements of the language of predicate logic.
data Formula : ℕ → Type{ℓₚ Lvl.⊔ ℓₒ} where
  _$_ : Prop(args) → List(Term(vars))(args) → Formula(vars) -- Relations

  ⊤ : Formula(vars) -- Tautology (Top / True)
  ⊥ : Formula(vars) -- Contradiction (Bottom / False)

  _∧_ : Formula(vars) → Formula(vars) → Formula(vars) -- Conjunction (And)
  _∨_ : Formula(vars) → Formula(vars) → Formula(vars) -- Disjunction (Or)
  _⟶_ : Formula(vars) → Formula(vars) → Formula(vars) -- Implication

  Ɐ : Formula(𝐒(vars)) → Formula(vars)
  ∃ : Formula(𝐒(vars)) → Formula(vars)

-- A sentence is a formula with no variables occurring.
Sentence = Formula(𝟎)

infix  1011 _$_
infixr 1005 _∧_
infixr 1004 _∨_
infixr 1000 _⟶_

-- Negation
¬_ : Formula(vars) → Formula(vars)
¬_ = _⟶ ⊥

-- Double negation
¬¬_ : Formula(vars) → Formula(vars)
¬¬_ = (¬_) ∘ (¬_)

-- Reverse implication
_⟵_ : Formula(vars) → Formula(vars) → Formula(vars)
_⟵_ = swap(_⟶_)

-- Equivalence
_⟷_ : Formula(vars) → Formula(vars) → Formula(vars)
p ⟷ q = (p ⟵ q) ∧ (p ⟶ q)

-- (Nor)
_⊽_ : Formula(vars) → Formula(vars) → Formula(vars)
_⊽_ = (¬_) ∘₂ (_∨_)

-- (Nand)
_⊼_ : Formula(vars) → Formula(vars) → Formula(vars)
_⊼_ = (¬_) ∘₂ (_∧_)

-- (Exclusive or / Xor)
_⊻_ : Formula(vars) → Formula(vars) → Formula(vars)
_⊻_ = (¬_) ∘₂ (_⟷_)

infix  1010 ¬_ ¬¬_
infixl 1000 _⟵_ _⟷_

Ɐ₊ : Formula(vars) → Sentence
Ɐ₊{𝟎}   φ = φ
Ɐ₊{𝐒 v} φ = Ɐ₊{v} (Ɐ φ)

∃₊ : Formula(vars) → Sentence
∃₊{𝟎}   φ = φ
∃₊{𝐒 v} φ = ∃₊{v} (∃ φ)


{-# OPTIONS --universe-polymorphism #-}
open import Level
open import Categories.Category
module Categories.Power.NaturalTransformation {o ℓ e : Level} (C : Category o ℓ e) where

open import Function using () renaming (_∘_ to _∙_)
open import Data.Fin using (Fin; inject+; raise)
open import Data.Sum using (_⊎_; [_,_]′; inj₁; inj₂)
open import Data.Product using (_,_)

import Categories.Power
module Pow = Categories.Power C
open Pow public
open import Categories.Bifunctor using (Bifunctor)

open import Categories.Bifunctor.NaturalTransformation renaming (id to idⁿ; _≡_ to _≡ⁿ_)
open import Categories.Functor using (module Functor) renaming (_∘_ to _∘F_)

flattenPⁿ : ∀ {D : Category o ℓ e} {n m} {F G : Powerfunctor′ D (Fin n ⊎ Fin m)} (η : NaturalTransformation F G) → NaturalTransformation (flattenP F) (flattenP G)
flattenPⁿ {n = n} {m} η = record
  { η = λ Xs → η.η (Xs ∙ pack)
  ; commute = λ fs → η.commute (fs ∙ pack)
  }
  where
  private module η = NaturalTransformation η
  pack = [ inject+ m , raise n ]′

reduceN′ : ∀ (H : Bifunctor C C C) {I} {F F′ : Powerendo′ I} (φ : NaturalTransformation F F′) {J} {G G′ : Powerendo′ J} (γ : NaturalTransformation G G′) → NaturalTransformation (reduce′ H F G) (reduce′ H F′ G′)
reduceN′ H {I} {F} {F′} φ {J} {G} {G′} γ = record
  { η = my-η
  ; commute = λ {Xs Ys} → my-commute Xs Ys
  }
  where
  module F = Functor F
  module F′ = Functor F′
  module G = Functor G
  module G′ = Functor G′
  module φ = NaturalTransformation φ
  module γ = NaturalTransformation γ
  module H = Functor H
  module L = Functor (reduce′ H F G)
  module R = Functor (reduce′ H F′ G′)
  my-η : ∀ Xs → C [ L.F₀ Xs , R.F₀ Xs ]
  my-η Xs = H.F₁ ((φ.η (Xs ∙ inj₁)) , (γ.η (Xs ∙ inj₂)))
  .my-commute : ∀ Xs Ys fs → C.CommutativeSquare (L.F₁ fs) (my-η Xs) (my-η Ys) (R.F₁ fs)
  my-commute Xs Ys fs = begin
      my-η Ys ∘ L.F₁ fs
    ↑⟨ H.homomorphism ⟩
      H.F₁ ((φ.η (Ys ∙ inj₁) ∘ F.F₁ (fs ∙ inj₁)) , (γ.η (Ys ∙ inj₂) ∘ G.F₁ (fs ∙ inj₂)))
    ↓⟨ H.F-resp-≡ ((φ.commute (fs ∙ inj₁)) , (γ.commute (fs ∙ inj₂))) ⟩
      H.F₁ ((F′.F₁ (fs ∙ inj₁) ∘ φ.η (Xs ∙ inj₁)) , (G′.F₁ (fs ∙ inj₂) ∘ γ.η (Xs ∙ inj₂)))
    ↓⟨ H.homomorphism ⟩
      R.F₁ fs ∘ my-η Xs
    ∎
    where
    open C using (_∘_; _≡_)
    open C.HomReasoning

reduceN : ∀ (H : Bifunctor C C C) {n} {F F′ : Powerendo n} (φ : NaturalTransformation F F′) {m} {G G′ : Powerendo m} (γ : NaturalTransformation G G′) → NaturalTransformation (reduce H F G) (reduce H F′ G′)
reduceN  H {n}  {F = f} {f′} F {m} {g} {g′} G = flattenPⁿ  {F = a} {G = b}  (reduceN′ H F G)
  where
    a : Categories.Bifunctor.Functor     (Categories.Power.Exp C (Fin n ⊎ Fin m)) C
    a = reduce′ H f g
    b : Categories.Bifunctor.Functor     (Categories.Power.Exp C (Fin n ⊎ Fin m)) C
    b = reduce′ H f′ g′

overlapN : ∀ (H : Bifunctor C C C) {n} {F F′ : Powerendo n} (φ : NaturalTransformation F F′) {G G′ : Powerendo n} (γ : NaturalTransformation G G′) → NaturalTransformation (overlaps {C} {C} H F G) (overlaps {C} {C} H F′ G′)
overlapN H F G = overlapN-× {D₁ = C} {D₂ = C} H F G


------------------------------------------------------------------------------
-- Exercises for Type Theory CM0859 (Prof. Andreas Abel).
-- http://www1.eafit.edu.co/asr/courses/type-theory-CM0859/exercises.pdf
------------------------------------------------------------------------------

open import Data.PropFormula 2 public

ex1 : ∀ {φ}
    → ∅ ⊢ φ ⊃ φ

ex1 {φ} = ⊃-intro (assume {Γ = ∅} φ)

ex2 : ∀ {φ ψ}
    → ∅ ⊢ (φ ∧ (φ ⊃ ψ)) ⊃ ψ

ex2 {φ}{ψ} =
  ⊃-intro $
    ⊃-elim
      (∧-proj₂ $ assume {Γ = ∅} (φ ∧ (φ ⊃ ψ)))
      (∧-proj₁ $ assume {Γ = ∅} (φ ∧ (φ ⊃ ψ)))

ex3 : ∀ {φ ψ γ}
    → ∅ ⊢ (φ ∧ (ψ ∨ γ)) ⊃ ((φ ∧ ψ) ∨ (φ ∧ γ))

ex3 {φ}{ψ}{γ} =
  ⊃-intro $
    ⊃-elim
      (⊃-intro $
        ∨-elim {Γ = ∅ , (φ ∧ (ψ ∨ γ))}
          (∨-intro₁ (φ ∧ γ) $
            ∧-intro
              (∧-proj₁ $ weaken ψ $ assume {Γ = ∅} (φ ∧ (ψ ∨ γ)))
              (assume {Γ = ∅ , (φ ∧ (ψ ∨ γ)) } ψ))
          (∨-intro₂ (φ ∧ ψ) $
            ∧-intro
              (∧-proj₁ $ weaken γ $ assume {Γ = ∅} (φ ∧ (ψ ∨ γ)))
              (assume {Γ = ∅ , (φ ∧ (ψ ∨ γ))} γ )))
    (∧-proj₂ $ assume {Γ = ∅} (φ ∧ (ψ ∨ γ)))

ex4 : ∀ {φ ψ}
    → ∅ ⊢ (¬ φ ∨ ψ) ⊃ (φ ⊃ ψ)

ex4 {φ}{ψ} =
  ⊃-intro $
    ∨-elim {Γ = ∅}
      (⊃-intro $
        ⊥-elim {Γ = ∅ , ¬ φ , φ} ψ
          (¬-elim
            (weaken φ $
              assume {Γ = ∅} (¬ φ))
            (assume {Γ = ∅ , ¬ φ} φ)))
      (⊃-intro $
        weaken φ $
          assume {Γ = ∅} ψ)

ex5 : ∀ {φ ψ}
    → ∅ ⊢ ¬ (φ ∨ ψ) ⊃ (¬ φ ∧ ¬ ψ)

ex5 {φ}{ψ} =
  ⊃-intro $
    ∧-intro
      (¬-intro $
        ¬-elim
          (weaken φ $
            assume {Γ = ∅} (¬ (φ ∨ ψ)))
          (∨-intro₁ ψ $
            assume {Γ = ∅ , ¬ (φ ∨ ψ)} φ))
      (¬-intro $
        ¬-elim
          (weaken ψ $
            assume {Γ = ∅} (¬ (φ ∨ ψ)))
          (∨-intro₂ φ $
            assume {Γ = ∅ , ¬ (φ ∨ ψ)} ψ))

¬¬EM : ∀ {Γ} {φ}
     → Γ ⊢ ¬ ¬ (φ ∨ ¬ φ)

¬¬EM {Γ}{φ} =
  ¬-intro $
    ¬-elim
      (assume {Γ = Γ} (¬ (φ ∨ ¬ φ)))
      PEM

RAA⊃EM
  : ∀ {Γ} {φ}
  → Γ ⊢ φ ∨ ¬ φ

RAA⊃EM {Γ}{φ} =
  RAA
    (¬-elim
      (¬¬EM {Γ = Γ , ¬ (φ ∨ ¬ φ)} )
      (assume {Γ = Γ} (¬ (φ ∨ ¬ φ))))

EM⊃Pierce
  : ∀ {Γ} {φ ψ}
  → Γ ⊢ ((φ ⊃ ψ) ⊃ φ) ⊃ φ

EM⊃Pierce {Γ}{φ}{ψ} =
  ⊃-elim
    (⊃-intro
      (∨-elim {Γ = Γ}
        (⊃-intro
          (weaken ((φ ⊃ ψ) ⊃ φ)
            (assume {Γ = Γ} φ)))
        (⊃-intro
          (⊃-elim
            (assume {Γ = Γ , ¬ φ} ((φ ⊃ ψ) ⊃ φ))
              (⊃-intro
                (⊥-elim
                  ψ
                  (¬-elim
                  (weaken φ
                    (weaken ((φ ⊃ ψ) ⊃ φ)
                      (assume {Γ = Γ} (¬ φ))))
                      (assume {Γ = Γ , ¬ φ , (φ ⊃ ψ) ⊃ φ} φ))))
            ))))
      PEM

postulate
  RAA'
    : ∀ {Γ} {φ}
    → Γ ⊢ ( ¬ φ ⊃ φ) ⊃ φ

RAA'⊃RAA : ∀ {Γ}{φ}
         → Γ ⊢ ¬ (¬ φ) ⊃ φ

RAA'⊃RAA {Γ}{φ} =
  ⊃-intro
    (⊃-elim
      RAA'
      (⊃-intro
        (⊥-elim
          φ
          (¬-elim
            (weaken (¬ φ) (assume  {Γ = Γ } ( ¬ (¬ φ))))
            (assume  {Γ = Γ , ¬ (¬ φ) } (¬ φ)))
         )))

postulate
  Pierce : ∀ {Γ} {φ} {ψ}
         → Γ ⊢ ((φ ⊃ ψ) ⊃ φ) ⊃ φ

Pierce⊃RAA' : ∀ {Γ}{φ}
            → Γ ⊢ ( ¬ φ ⊃ φ ) ⊃ φ

Pierce⊃RAA' {Γ}{φ} =
  ⊃-intro $
    ⊃-elim
      (Pierce {Γ = Γ , ¬ φ ⊃ φ} {φ = φ} {ψ = ⊥})
      (⊃-intro $
        ⊃-elim
          (weaken (φ ⊃ ⊥) $
            assume {Γ = Γ} ((¬ φ) ⊃ φ))
          (¬-equiv₂ $
            assume {Γ = Γ , (¬ φ) ⊃ φ}
              (φ ⊃ ⊥)
          )
      )


module Prelude where

-- 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


module Prelude where
  open import Agda.Primitive using (Level; lzero; lsuc) renaming (_⊔_ to lmax)

  -- empty type
  data ⊥ : Set where

  -- from false, derive whatever
  abort : ∀ {C : Set} → ⊥ → C
  abort ()

  -- unit
  data ⊤ : Set where
    <> : ⊤

  -- sums
  data _+_ (A B : Set) : Set where
    Inl : A → A + B
    Inr : B → A + B

  -- pairs
  infixr 1 _,_
  record Σ {l1 l2 : Level} (A : Set l1) (B : A → Set l2) : Set (lmax l1 l2) where
    constructor _,_
    field
      π1 : A
      π2 : B π1
  open Σ public

  syntax Σ A (\ x -> B) = Σ[ x ∈ A ] B

  _×_ : {l1 : Level} {l2 : Level} → (Set l1) → (Set l2) → Set (lmax l1 l2)
  A × B = Σ A λ _ → B

  infixr 1 _×_

  -- equality
  data _==_ {l : Level} {A : Set l} (M : A) : A → Set l where
    refl : M == M

  infixr 9 _==_

  {-# BUILTIN EQUALITY _==_ #-}
  {-# BUILTIN REFL refl #-}

  _·_ : {l : Level} {α : Set l} {x y z : α} → x == y → y == z → x == z
  refl · refl = refl

  -- β: ! (refl m)  == refl m
  ! : {l : Level} {α : Set l} {x y : α} → x == y → y == x
  ! refl = refl

  -- β: (ap f (refl m)) == refl (f m)
  ap1 : {l1 l2 : Level} {α : Set l1} {β : Set l2} {x y : α} (F : α → β)
          → x == y → F x == F y
  ap1 F refl = refl

  -- β? : tr β (refl x) y == y
  tr : {l1 l2 : Level} {α : Set l1} {x y : α}
                    (B : α → Set l2)
                    → x == y
                    → B x
                    → B y
  tr B refl x₁ = x₁

  ap2 : {l1 l2 l3 : Level}
        {A : Set l1} {B : Set l2} {C : Set l3}
        {M N : A} {M' N' : B}
        (f : A -> B -> C) -> M == N -> M' == N' -> (f M M') == (f N N')
  ap2 f refl refl = refl

  infix  2 _■
  infixr 2 _=<_>_

  _=<_>_ : {l : Level} {A : Set l} (x : A) {y z : A} → x == y → y == z → x == z
  _ =< p1 > p2 = p1 · p2

  _■ : {l : Level} {A : Set l} (x : A) → x == x
  _■ _ = refl

  -- options
  data Maybe (A : Set) : Set where
    Some : A → Maybe A
    None : Maybe A

  -- the some constructor is injective. perhaps unsurprisingly.
  someinj : {A : Set} {x y : A} → Some x == Some y → x == y
  someinj refl = refl

  -- order
  data Order : Set where
    Less : Order
    Equal : Order
    Greater : Order

  -- function extensionality
  postulate
     funext : {A : Set} {B : A → Set} {f g : (x : A) → (B x)} →
              ((x : A) → f x == g x) → f == g


------------------------------------------------------------------------
-- The Agda standard library
--
-- A definition for the permutation relation using setoid equality
------------------------------------------------------------------------

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

open import Relation.Binary

module Data.List.Relation.Binary.Permutation.Setoid
  {a ℓ} (S : Setoid a ℓ) where

open import Data.List.Base using (List; _∷_)
import Data.List.Relation.Binary.Permutation.Homogeneous as Homogeneous
import Data.List.Relation.Binary.Pointwise as Pointwise
open import Data.List.Relation.Binary.Equality.Setoid S
open import Data.Nat.Base using (ℕ; zero; suc; _+_)
open import Level using (_⊔_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
import Relation.Binary.Reasoning.Setoid as SetoidReasoning

private
  module Eq = Setoid S
open Eq using (_≈_) renaming (Carrier to A)

------------------------------------------------------------------------
-- Definition

open Homogeneous public
  using (refl; prep; swap; trans)

infix 3 _↭_

_↭_ : Rel (List A) (a ⊔ ℓ)
_↭_ = Homogeneous.Permutation _≈_

------------------------------------------------------------------------
-- Constructor aliases

-- These provide aliases for `swap` and `prep` when the elements being
-- swapped or prepended are propositionally equal

↭-prep : ∀ x {xs ys} → xs ↭ ys → x ∷ xs ↭ x ∷ ys
↭-prep x xs↭ys = prep Eq.refl xs↭ys

↭-swap : ∀ x y {xs ys} → xs ↭ ys → x ∷ y ∷ xs ↭ y ∷ x ∷ ys
↭-swap x y xs↭ys = swap Eq.refl Eq.refl xs↭ys

------------------------------------------------------------------------
-- Functions over permutations

steps : ∀ {xs ys} → xs ↭ ys → ℕ
steps (refl _)            = 1
steps (prep _ xs↭ys)      = suc (steps xs↭ys)
steps (swap _ _ xs↭ys)    = suc (steps xs↭ys)
steps (trans xs↭ys ys↭zs) = steps xs↭ys + steps ys↭zs

------------------------------------------------------------------------
-- _↭_ is an equivalence

↭-reflexive : _≡_ ⇒ _↭_
↭-reflexive refl = refl (Pointwise.refl Eq.refl)

↭-refl : Reflexive _↭_
↭-refl = ↭-reflexive refl

↭-sym : Symmetric _↭_
↭-sym = Homogeneous.sym Eq.sym

↭-trans : Transitive _↭_
↭-trans = trans

↭-isEquivalence : IsEquivalence _↭_
↭-isEquivalence = Homogeneous.isEquivalence Eq.refl Eq.sym

↭-setoid : Setoid _ _
↭-setoid = Homogeneous.setoid {R = _≈_} Eq.refl Eq.sym

------------------------------------------------------------------------
-- A reasoning API to chain permutation proofs

module PermutationReasoning where

  private
    module Base = SetoidReasoning ↭-setoid

  open SetoidReasoning ↭-setoid public
    hiding (step-≈; step-≈˘)

  infixr 2 step-↭  step-↭˘ step-≋ step-≋˘ step-swap step-prep

  step-↭  = Base.step-≈
  step-↭˘ = Base.step-≈˘

  -- Step with pointwise list equality
  step-≋ : ∀ x {y z} → y IsRelatedTo z → x ≋ y → x IsRelatedTo z
  step-≋ x (relTo y↔z) x≋y = relTo (trans (refl x≋y) y↔z)

  -- Step with flipped pointwise list equality
  step-≋˘ : ∀ x {y z} → y IsRelatedTo z → y ≋ x → x IsRelatedTo z
  step-≋˘ x y↭z y≋x = x ≋⟨ ≋-sym y≋x ⟩ y↭z

  -- Skip reasoning on the first element
  step-prep : ∀ x xs {ys zs : List A} → (x ∷ ys) IsRelatedTo zs →
              xs ↭ ys → (x ∷ xs) IsRelatedTo zs
  step-prep x xs rel xs↭ys = relTo (trans (prep Eq.refl xs↭ys) (begin rel))

  -- Skip reasoning about the first two elements
  step-swap : ∀ x y xs {ys zs : List A} → (y ∷ x ∷ ys) IsRelatedTo zs →
              xs ↭ ys → (x ∷ y ∷ xs) IsRelatedTo zs
  step-swap x y xs rel xs↭ys = relTo (trans (swap Eq.refl Eq.refl xs↭ys) (begin rel))

  syntax step-↭  x y↭z x↭y = x ↭⟨  x↭y ⟩ y↭z
  syntax step-↭˘ x y↭z y↭x = x ↭˘⟨  y↭x ⟩ y↭z
  syntax step-≋  x y↭z x≋y = x ≋⟨  x≋y ⟩ y↭z
  syntax step-≋˘ x y↭z y≋x = x ≋˘⟨  y≋x ⟩ y↭z
  syntax step-prep x xs y↭z x↭y = x ∷ xs <⟨ x↭y ⟩ y↭z
  syntax step-swap x y xs y↭z x↭y = x ∷ y ∷ xs <<⟨ x↭y ⟩ y↭z


-- Andreas, 2015-12-12, report by Ulf, 2015-12-09

{-# OPTIONS -v tc.with.40 #-}

open import Common.Equality
open import Common.Bool

T : Bool → Set
T true  = Bool
T false = true ≡ false

foo : (a b : Bool) → a ≡ b → T a → T b
foo a b eq x rewrite eq = x

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

-- Intended new rewrite
refl-rewrite : ∀ a (eq : a ≡ a) (t : T a) → foo a a eq t ≡ t
refl-rewrite a eq t with eq
refl-rewrite a eq t | refl = refl

test : ∀ a (eq : a ≡ a) (t : T a) → foo a a eq t ≡ t
test a eq t rewrite eq = refl  -- FAILS, this is the original issue report
-- Error:
-- foo a a eq t | a | eq != t of type T a
-- when checking that the expression refl has type foo a a eq t ≡ t
-- test a refl t = refl  -- WORKS, of course

-- Non-reflexive rewrite
works : ∀ a b (eq : a ≡ b) (t : T a) → foo a b eq t ≅ t
works a b eq t rewrite eq = refl

-- Manual desugaring of old-style rewrite works as well
old-rewrite : ∀ a (eq : a ≡ a) (t : T a) → foo a a eq t ≡ t
old-rewrite a eq t with a | eq
old-rewrite a eq t | _ | refl = refl


module Data.Finitude.Properties where
open import Data.Fin as Fin using (Fin; #_ )
open import Data.Fin.Properties hiding (decSetoid)
open import Relation.Nullary
open import Relation.Unary
open import Relation.Binary renaming (Decidable to Dec₂) hiding (Irrelevant)
open import Relation.Binary.PropositionalEquality as P hiding (decSetoid; isEquivalence)
open import Data.Finitude
open import Function.Equality as F using (_⟨$⟩_)
open import Function.Inverse as Inv using (Inverse)
open import Data.Nat as ℕ hiding (_≟_)
import Level

finitude→≡ : ∀ {n m} → Finitude (P.setoid (Fin n)) m → n ≡ m
finitude→≡ fin = ⇒Fin∼Fin fin
  where
    open import Data.Fin.PigeonHole

dec-≈ : ∀ {a ℓ n}{S : Setoid a ℓ} → Finitude S n → Dec₂ (Setoid._≈_ S)
dec-≈ {S = S} fin x y with (Inverse.to fin ⟨$⟩ x) ≟ (Inverse.to fin ⟨$⟩ y)
dec-≈ {S = S} fin x y | yes fx≡fy = yes (Inverse.injective fin fx≡fy)
dec-≈ {S = S} fin x y | no fx≢fy = no (λ x≈y → fx≢fy (F.cong (Inverse.to fin) x≈y))

decSetoid : ∀ {a ℓ n}{S : Setoid a ℓ} → Finitude S n → DecSetoid a ℓ
decSetoid {S = S} fin = record {
          isDecEquivalence = record {
            _≟_ = dec-≈ fin
          ; isEquivalence = isEquivalence
          }
          }
          where open Setoid S

same-size↔  : ∀ {n a₁ a₂ ℓ₁ ℓ₂}{A₁ : Setoid a₁ ℓ₁}{A₂ : Setoid a₂ ℓ₂} → Finitude A₁ n → Finitude A₂ n → Inverse A₁ A₂
same-size↔ fin₁ fin₂ = Inv.sym fin₂ Inv.∘  fin₁

size-unique : ∀ {a ℓ} {A : Setoid a ℓ} {n m} → Finitude A n → Finitude A m → n ≡ m
size-unique finN finM = finitude→≡ (finM Inv.∘ Inv.sym finN)

{-
open import Data.Empty
open import Data.Unit

Irr : ∀ {a ℓ}(S : Setoid a ℓ) → Set (a Level.⊔ ℓ)
Irr S = ∀ x y → x ≈ y
  where
    open Setoid S

⊥-Irr : Irrelevant ⊥
⊥-Irr = λ ()

⊤-Irr : Irrelevant ⊤
⊤-Irr = λ _ _ → P.refl

Irr-finitude : ∀ {a ℓ n}{S : Set a} → Irrelevant S → Finitude (P.setoid S) n → n ℕ.≤ 1
Irr-finitude {n = ℕ.zero} irr fin = z≤n
Irr-finitude {n = ℕ.suc ℕ.zero} irr fin = s≤s z≤n
Irr-finitude {n = ℕ.suc (ℕ.suc n)}{S} irr fin = ⊥-elim contra
   where
     open Setoid S
     x₀ = Inverse.from fin ⟨$⟩ # 0
     x₁ = Inverse.from fin ⟨$⟩ # 1

     contra : ⊥
     contra with Inverse.injective (Inv.sym fin) (irr x₀ x₁)
     ... | ()
-}


{-# OPTIONS --without-K #-}
module equality.calculus where

open import sum using (Σ ; _,_ ; proj₁; proj₂)
open import equality.core
open import equality.groupoid public
open import function.core

ap' : ∀ {i j} {X : Set i}{Y : X → Set j}
        {x x' : X}(f : (x : X) → Y x)(p : x ≡ x')
      → subst Y p (f x) ≡ f x'
ap' _ refl = refl

subst-naturality : ∀ {i i' j} {X : Set i} {Y : Set i'}
                   {x x' : X} (P : Y → Set j)
                   (f : X → Y)(p : x ≡ x')(u : P (f x))
                 → subst (P ∘ f) p u ≡ subst P (ap f p) u
subst-naturality _ _ refl _ = refl

subst-hom : ∀ {i j}{X : Set i}(P : X → Set j){x y z : X}
          → (p : x ≡ y)(q : y ≡ z)(u : P x)
          → subst P q (subst P p u) ≡ subst P (p · q) u
subst-hom _ refl q u = refl

subst-eq : ∀ {i} {X : Set i}{x y z : X}
         → (p : y ≡ x)(q : y ≡ z)
         → subst (λ y → y ≡ z) p q
         ≡ sym p · q
subst-eq refl _ = refl

subst-eq₂ : ∀ {i} {X : Set i}{x y : X}
          → (p : x ≡ y)
          → (q : x ≡ x)
          → subst (λ z → z ≡ z) p q ≡ sym p · q · p
subst-eq₂ refl q = sym (left-unit _)

subst-const : ∀ {i j} {A : Set i}{X : Set j}
            → {a a' : A}(p : a ≡ a')(x : X)
            → subst (λ _ → X) p x ≡ x
subst-const refl x = refl

subst-const-ap : ∀ {i j} {A : Set i}{X : Set j}
                 → {a a' : A}(f : A → X)(p : a ≡ a')
                 → ap' f p ≡ subst-const p (f a) · ap f p
subst-const-ap f refl = refl

apΣ : ∀ {i j}{A : Set i}{B : A → Set j}
        {x x' : Σ A B}
     → (p : x ≡ x')
     → Σ (proj₁ x ≡ proj₁ x') λ q
     → subst B q (proj₂ x) ≡ proj₂ x'
apΣ {B = B} p =
  J (λ x x' p → Σ (proj₁ x ≡ proj₁ x') λ q
              → subst B q (proj₂ x) ≡ proj₂ x')
    (λ x → refl , refl)
    _ _ p

unapΣ : ∀ {i j}{A : Set i}{B : A → Set j}
          {a a' : A}{b : B a}{b' : B a'}
        → (Σ (a ≡ a') λ q → subst B q b ≡ b')
        → (a , b) ≡ (a' , b')
unapΣ (refl , refl) = refl

pair≡ : ∀ {i j}{A : Set i}{B : Set j}
          {a a' : A}{b b' : B}
        → (a ≡ a') → (b ≡ b')
        → (a , b) ≡ (a' , b')
pair≡ refl refl = refl

apΣ-proj : ∀ {i j}{A : Set i}{B : A → Set j}
             {a a' : A}{b : B a}{b' : B a'}
             (p : (a , b) ≡ (a' , b'))
           → proj₁ (apΣ p)
           ≡ ap proj₁ p
apΣ-proj =
  J (λ _ _ p → proj₁ (apΣ p) ≡ ap proj₁ p)
    (λ x → refl) _ _

apΣ-sym : ∀ {i j}{A : Set i}{B : A → Set j}
            {a a' : A}{b : B a}{b' : B a'}
            (p : (a , b) ≡ (a' , b'))
          → proj₁ (apΣ (sym p))
          ≡ sym (proj₁ (apΣ p))
apΣ-sym =
  J (λ _ _ p → proj₁ (apΣ (sym p))
             ≡ sym (proj₁ (apΣ p)))
    (λ x → refl) _ _

subst-ap : ∀ {i j}{A : Set i}{B : Set j}{a a' : A}
           → (f : A → B)
           → (p : a ≡ a')
           → ap f (sym p)
           ≡ subst (λ x → f x ≡ f a) p refl
subst-ap f refl = refl

ap-map-id : ∀ {i j}{X : Set i}{Y : Set j}{x : X}
            → (f : X → Y)
            → ap f (refl {x = x}) ≡ refl {x = f x}
ap-map-id f = refl

ap-map-hom : ∀ {i j}{X : Set i}{Y : Set j}{x y z : X}
             → (f : X → Y)(p : x ≡ y)(q : y ≡ z)
             → ap f (p · q) ≡ ap f p · ap f q
ap-map-hom f refl _ = refl

ap-id : ∀ {l} {A : Set l}{x y : A}(p : x ≡ y)
        → ap id p ≡ p
ap-id refl = refl

ap-hom : ∀ {l m n} {A : Set l}{B : Set m}{C : Set n}
           {x y : A}(f : A → B)(g : B → C)(p : x ≡ y)
         → ap g (ap f p) ≡ ap (g ∘ f) p
ap-hom f g refl = refl

ap-inv : ∀ {i j} {X : Set i} {Y : Set j}
         → {x x' : X}
         → (f : X → Y)(p : x ≡ x')
         → ap f (sym p) ≡ sym (ap f p)
ap-inv f refl = refl

double-inverse : ∀ {i} {X : Set i} {x y : X}
               (p : x ≡ y) → sym (sym p) ≡ p
double-inverse refl = refl

inverse-comp : ∀ {i} {X : Set i} {x y z : X}
               (p : x ≡ y)(q : y ≡ z)
             → sym (p · q) ≡ sym q · sym p
inverse-comp refl q = sym (left-unit (sym q))

inverse-unique : ∀ {i} {X : Set i} {x y : X}
                 (p : x ≡ y)(q : y ≡ x)
               → p · q ≡ refl
               → sym p ≡ q
inverse-unique refl q t = sym t


{-#  OPTIONS --type-in-type #-}
module AgdaPrelude where

data Nat : Set where
  Zero : Nat
  Succ : Nat -> Nat

natElim : (m : Nat -> Set) -> (mz : m Zero) -> (ms : (l : Nat) -> m l -> m (Succ l)) -> (k : Nat) -> m k
natElim m mz ms Zero = mz
natElim m mz ms (Succ k) = ms k (natElim m mz ms k)

data Vec : Set -> Nat -> Set where
  Nil : (a : Set) -> Vec a Zero
  Cons : (a : Set) -> (n : Nat) -> (x : a) -> (xs : Vec a n) -> Vec a (Succ n)

data Eq : (a : Set) -> a -> a -> Set where
  Refl : (a : Set) -> (x : a) -> Eq a x x


module _ where

open import Common.Prelude renaming (_+_ to _+N_)
open import Common.Integer

diff : Nat → Nat → Integer
diff  a       zero   = pos a
diff  zero   (suc b) = negsuc b
diff (suc a) (suc b) = diff a b

_+_ : Integer → Integer → Integer
pos    a + pos    b = pos (a +N b)
pos    a + negsuc b = diff a (suc b)
negsuc a + pos    b = diff b (suc a)
negsuc a + negsuc b = negsuc (suc a +N b)

printInt : Integer → IO Unit
printInt n = putStrLn (intToString n)

main : IO Unit
main = printInt (pos 42 + pos 58)     ,,
       printInt (pos 42 + negsuc 141) ,,
       printInt (pos 42 + negsuc 31)  ,,
       printInt (negsuc 42 + pos 143) ,,
       printInt (negsuc 42 + pos 33)  ,,
       printInt (negsuc 42 + negsuc 56)


module Sandbox.IndRecIndexed where
-- Ornamental Algebras, Algebraic Ornaments, CONOR McBRIDE
-- https://personal.cis.strath.ac.uk/conor.mcbride/pub/OAAO/Ornament.pdf
-- A Finite Axiomtization of Inductive-Recursion definitions, Peter Dybjer, Anton Setzer
-- http://www.cse.chalmers.se/~peterd/papers/Finite_IR.pdf

open import Data.Product using (_×_; Σ; _,_; proj₁; proj₂)
open import Data.Bool
open import Data.Unit
open import Data.Empty
open import Function
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

data Desc (I : Set) : Set₁ where
    arg : (A : Set) → (A → Desc I) → Desc I
    rec : I → Desc I → Desc I
    ret : I → Desc I

⟦_⟧ : ∀ {I} → Desc I → (I → Set) → (I → Set)
⟦ arg A D ⟧ R i = Σ A (λ a → ⟦ D a ⟧ R i)
⟦ rec j D ⟧ R i = R j × ⟦ D ⟧ R i
⟦ ret j   ⟧ R i = j ≡ i

data Data {I} (D : Desc I) : I → Set where
    ⟨_⟩ : ∀ {i} → ⟦ D ⟧ (Data D) i → Data D i

-- an arrow that respects indices
_⇒_ : ∀ {I} → (I → Set) → (I → Set) → Set
_⇒_ {I} X Y = (i : I) → X i → Y i

map : ∀ {I} {A B : I → Set} → (D : Desc I) → (A ⇒ B) → ⟦ D ⟧ A ⇒ ⟦ D ⟧ B
map (arg T U) f i (t , u) = t     , map (U t) f i u
map (rec j D) f i (a , u) = f j a , map D     f i u
map (ret j)   f i i≡j     = i≡j

Alg : ∀ {I} (D : Desc I) → (A : I → Set) → Set
Alg D A = ⟦ D ⟧ A ⇒ A

-- fold D alg i ⟨ x ⟩ = alg i (map D (fold D alg) i x)
-- mapFold F G alg i x = map F (fold G alg) i x

mapFold : ∀ {I} {A : I → Set} (F G : Desc I) → Alg G A → ⟦ F ⟧ (Data G) ⇒ ⟦ F ⟧ A
mapFold (arg Tags decoder) G alg i (tag , subnode) = tag , (mapFold (decoder tag) G alg i subnode)
mapFold (rec j F)          G alg i (⟨ x ⟩ , xs) = alg j (mapFold G G alg j x) , mapFold F G alg i xs
mapFold (ret j)            G alg i x = x

fold : ∀ {I} {A : I → Set} (D : Desc I) → Alg D A → Data D ⇒ A
fold D alg i ⟨ x ⟩ = alg i (mapFold D D alg i x)

-- ℕ
ℕDesc : Desc ⊤
ℕDesc = arg Bool (λ { true → rec tt (ret tt) ; false → ret tt })

ℕ : Set
ℕ = Data ℕDesc tt

zero : ℕ
zero = ⟨ (false , refl) ⟩

suc : ℕ → ℕ
suc n = ⟨ (true , (n , refl)) ⟩

-- indℕ : (P : ℕ → Set)
--      → P zero
--      → ((n : ℕ) → P n → P (suc n))
--      → (x : ℕ)
--      → P x
-- indℕ P base step ⟨ true , n , refl ⟩ = step n (indℕ P base step n)
-- indℕ P base step ⟨ false , refl ⟩ = base
--
-- _+_ : ℕ → ℕ → ℕ
-- x + y = indℕ (λ _ → ℕ) y (λ n prf → suc prf) x

+alg : ℕ → Alg ℕDesc (λ _ → ℕ)
+alg y .tt (true , sum , refl) = suc sum
+alg y .tt (false , refl) = y

_+_ : ℕ → ℕ → ℕ
x + y = fold ℕDesc (+alg y) tt x

one : ℕ
one = suc zero

two : ℕ
two = suc one

+-suc-left : (m n : ℕ) → suc m + n ≡ suc (m + n)
+-suc-left ⟨ true , m , refl ⟩ n = refl
+-suc-left ⟨ false , refl ⟩ n = refl

-- Nat
NatDesc : Desc ℕ
NatDesc = arg Bool (
    λ { true → arg ℕ (λ { n → rec n (ret (suc n)) })
      ; false → ret zero
      })

Nat : ℕ → Set
Nat n = Data NatDesc n

zeroNat : Nat zero
zeroNat = ⟨ (false , refl) ⟩

sucNat : ∀ {n} → Nat n → Nat (suc n)
sucNat {n} x = ⟨ (true , (n , (x , refl))) ⟩

-- Maybe
MaybeDesc : Set → Desc ⊤
MaybeDesc A = arg Bool (λ { true → arg A (λ _ → ret tt) ; false → ret tt })

Maybe : Set → Set
Maybe A = Data (MaybeDesc A) tt

nothing : ∀ {A} → Maybe A
nothing = ⟨ (false , refl) ⟩

just : ∀ {A} → A → Maybe A
just n = ⟨ (true , (n , refl)) ⟩

-- List
ListDesc : Set → Desc ⊤
ListDesc A = arg Bool (
    λ { true  → arg A (λ _ → rec tt (ret tt))
      ; false → ret tt
      })

List : Set → Set
List A = Data (ListDesc A) tt

nil : ∀ {A} → List A
nil = ⟨ (false , refl) ⟩

cons : ∀ {A} → A → List A → List A
cons x xs = ⟨ (true , (x , (xs , refl))) ⟩

indList : ∀ {A} (P : List A → Set)
        → P nil
        → ((x : A) → (xs : List A) → P xs → P (cons x xs))
        → (xs : List A)
        → P xs
indList P base step ⟨ true , x , xs , refl ⟩ = step x xs (indList P base step xs)
indList P base step ⟨ false , refl ⟩ = base

-- Vec
VecDesc : Set → Desc ℕ
VecDesc A = arg Bool (
  λ { true → arg A (λ _ → arg ℕ (λ n → rec n (ret (suc n))))
    ; false → ret zero
    })

Vec : Set → ℕ → Set
Vec A n = Data (VecDesc A) n

nilV : ∀ {A} → Vec A zero
nilV = ⟨ false , refl ⟩

consV : ∀ {A n} → A → Vec A n → Vec A (suc n)
consV {A} {n} x xs = ⟨ true , x , n , xs , refl ⟩

++alg : ∀ {A n} → Vec A n → Alg (VecDesc A) (λ m → Vec A (m + n))
++alg {A} {n} ys .(suc o) (true , z , o , zs , refl) = ⟨ true , z , o + n , zs , sym (+-suc-left o n) ⟩
++alg ys .zero    (false , refl) = ys

_++_ : ∀ {A m n} → Vec A m → Vec A n → Vec A (m + n)
_++_ {A} {m} {n} xs ys = fold (VecDesc A) (++alg ys) m xs

-- inverse image of e : J → I
data Inv {J I : Set} (e : J → I) : I → Set where
    inv : (j : J) → Inv e (e j)

data Orn {J I : Set} (e : J → I) : Desc I → Set₁ where
    arg : (A : Set) → {D : A → Desc I} → ((a : A) → Orn e (D a)) → Orn e (Desc.arg A D)
    rec : ∀ {h D} → Inv e h → Orn e D → Orn e (rec h D)
    ret : ∀ {o} → Inv e o → Orn e (ret o)
    new : ∀ {D} → (A : Set) → ((a : A) → Orn e D) → Orn e D

ListOrn : Set → Orn (λ x → tt) ℕDesc
ListOrn A = arg Bool (λ { true → Orn.new A (λ a → rec (inv tt) (ret (inv tt)))
                        ; false → Orn.ret (inv tt)})

orn : ∀ {I J} {D : Desc I} {e : J → I} → Orn e D → Desc J
orn (arg A O)       = arg A (λ x → orn (O x))
orn (rec (inv j) O) = rec j (orn O)
orn (ret (inv j))   = ret j
orn (new A O)       = arg A (λ x → orn (O x))

ListDesc' : Set → Desc ⊤
ListDesc' A = orn (ListOrn A)

erase : ∀ {I J} {R : I → Set} {e : J → I} {D : Desc I} → (O : Orn e D) → ⟦ orn O ⟧ (R ∘ e) ⇒ (⟦ D ⟧ R ∘ e)
erase (arg A O) i (a , os) = a , (erase (O a) i os)
erase (rec (inv i) O) j (r , os) = r , erase O j os
erase (ret (inv j)) .j refl = refl
erase (new A O) j (a , os) = erase (O a) j os

ornament-algebra : ∀ {I J} {e : J → I} {D : Desc I} → (O : Orn e D) → Alg (orn O) (λ j → Data D (e j))
ornament-algebra O j x = ⟨ erase O j x ⟩

forget : ∀ {I J} {e : J → I} {D : Desc I} {O : Orn e D} {j : J} → Data (orn O) j → Data D (e j)
forget {I} {J} {e} {D} {O} {j} = fold (orn O) (ornament-algebra O) j

algo : ∀ {I A} → (D : Desc I) → Alg D A → Orn {Σ I {! A  !}} proj₁ D
algo (arg A x) alg = arg A (λ a → algo (x a) (λ j ds → alg j (a , ds)))
algo {I} {A} (rec i D) alg = new (A i) (λ a → rec (inv (i , a)) (algo D (λ j ds → alg i (a , {! ds  !}))))
algo (ret i) alg = ret (inv (i , alg i refl))


------------------------------------------------------------------------
-- The Agda standard library
--
-- Definitions of algebraic structures like monoids and rings
-- (packed in records together with sets, operations, etc.)
------------------------------------------------------------------------

module Algebra where

open import Relation.Binary
open import Algebra.FunctionProperties
open import Algebra.Structures
open import Function
open import Level

------------------------------------------------------------------------
-- Semigroups, (commutative) monoids and (abelian) groups

record Semigroup c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier     : Set c
    _≈_         : Rel Carrier ℓ
    _∙_         : Op₂ Carrier
    isSemigroup : IsSemigroup _≈_ _∙_

  open IsSemigroup isSemigroup public

  setoid : Setoid _ _
  setoid = record { isEquivalence = isEquivalence }

-- A raw monoid is a monoid without any laws.

record RawMonoid c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _∙_     : Op₂ Carrier
    ε       : Carrier

record Monoid c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier  : Set c
    _≈_      : Rel Carrier ℓ
    _∙_      : Op₂ Carrier
    ε        : Carrier
    isMonoid : IsMonoid _≈_ _∙_ ε

  open IsMonoid isMonoid public

  semigroup : Semigroup _ _
  semigroup = record { isSemigroup = isSemigroup }

  open Semigroup semigroup public using (setoid)

  rawMonoid : RawMonoid _ _
  rawMonoid = record
    { _≈_ = _≈_
    ; _∙_ = _∙_
    ; ε   = ε
    }

record CommutativeMonoid c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier             : Set c
    _≈_                 : Rel Carrier ℓ
    _∙_                 : Op₂ Carrier
    ε                   : Carrier
    isCommutativeMonoid : IsCommutativeMonoid _≈_ _∙_ ε

  open IsCommutativeMonoid isCommutativeMonoid public

  monoid : Monoid _ _
  monoid = record { isMonoid = isMonoid }

  open Monoid monoid public using (setoid; semigroup; rawMonoid)

record Group c ℓ : Set (suc (c ⊔ ℓ)) where
  infix  8 _⁻¹
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _∙_     : Op₂ Carrier
    ε       : Carrier
    _⁻¹     : Op₁ Carrier
    isGroup : IsGroup _≈_ _∙_ ε _⁻¹

  open IsGroup isGroup public

  monoid : Monoid _ _
  monoid = record { isMonoid = isMonoid }

  open Monoid monoid public using (setoid; semigroup; rawMonoid)

record AbelianGroup c ℓ : Set (suc (c ⊔ ℓ)) where
  infix  8 _⁻¹
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier        : Set c
    _≈_            : Rel Carrier ℓ
    _∙_            : Op₂ Carrier
    ε              : Carrier
    _⁻¹            : Op₁ Carrier
    isAbelianGroup : IsAbelianGroup _≈_ _∙_ ε _⁻¹

  open IsAbelianGroup isAbelianGroup public

  group : Group _ _
  group = record { isGroup = isGroup }

  open Group group public using (setoid; semigroup; monoid; rawMonoid)

  commutativeMonoid : CommutativeMonoid _ _
  commutativeMonoid =
    record { isCommutativeMonoid = isCommutativeMonoid }

------------------------------------------------------------------------
-- Various kinds of semirings

record NearSemiring c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier        : Set c
    _≈_            : Rel Carrier ℓ
    _+_            : Op₂ Carrier
    _*_            : Op₂ Carrier
    0#             : Carrier
    isNearSemiring : IsNearSemiring _≈_ _+_ _*_ 0#

  open IsNearSemiring isNearSemiring public

  +-monoid : Monoid _ _
  +-monoid = record { isMonoid = +-isMonoid }

  open Monoid +-monoid public
         using (setoid)
         renaming ( semigroup to +-semigroup
                  ; rawMonoid to +-rawMonoid)

  *-semigroup : Semigroup _ _
  *-semigroup = record { isSemigroup = *-isSemigroup }

record SemiringWithoutOne c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier              : Set c
    _≈_                  : Rel Carrier ℓ
    _+_                  : Op₂ Carrier
    _*_                  : Op₂ Carrier
    0#                   : Carrier
    isSemiringWithoutOne : IsSemiringWithoutOne _≈_ _+_ _*_ 0#

  open IsSemiringWithoutOne isSemiringWithoutOne public

  nearSemiring : NearSemiring _ _
  nearSemiring = record { isNearSemiring = isNearSemiring }

  open NearSemiring nearSemiring public
         using ( setoid
               ; +-semigroup; +-rawMonoid; +-monoid
               ; *-semigroup
               )

  +-commutativeMonoid : CommutativeMonoid _ _
  +-commutativeMonoid =
    record { isCommutativeMonoid = +-isCommutativeMonoid }

record SemiringWithoutAnnihilatingZero c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier                           : Set c
    _≈_                               : Rel Carrier ℓ
    _+_                               : Op₂ Carrier
    _*_                               : Op₂ Carrier
    0#                                : Carrier
    1#                                : Carrier
    isSemiringWithoutAnnihilatingZero :
      IsSemiringWithoutAnnihilatingZero _≈_ _+_ _*_ 0# 1#

  open IsSemiringWithoutAnnihilatingZero
         isSemiringWithoutAnnihilatingZero public

  +-commutativeMonoid : CommutativeMonoid _ _
  +-commutativeMonoid =
    record { isCommutativeMonoid = +-isCommutativeMonoid }

  open CommutativeMonoid +-commutativeMonoid public
         using (setoid)
         renaming ( semigroup to +-semigroup
                  ; rawMonoid to +-rawMonoid
                  ; monoid    to +-monoid
                  )

  *-monoid : Monoid _ _
  *-monoid = record { isMonoid = *-isMonoid }

  open Monoid *-monoid public
         using ()
         renaming ( semigroup to *-semigroup
                  ; rawMonoid to *-rawMonoid
                  )

record Semiring c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier    : Set c
    _≈_        : Rel Carrier ℓ
    _+_        : Op₂ Carrier
    _*_        : Op₂ Carrier
    0#         : Carrier
    1#         : Carrier
    isSemiring : IsSemiring _≈_ _+_ _*_ 0# 1#

  open IsSemiring isSemiring public

  semiringWithoutAnnihilatingZero : SemiringWithoutAnnihilatingZero _ _
  semiringWithoutAnnihilatingZero = record
    { isSemiringWithoutAnnihilatingZero =
        isSemiringWithoutAnnihilatingZero
    }

  open SemiringWithoutAnnihilatingZero
         semiringWithoutAnnihilatingZero public
         using ( setoid
               ; +-semigroup; +-rawMonoid; +-monoid
               ; +-commutativeMonoid
               ; *-semigroup; *-rawMonoid; *-monoid
               )

  semiringWithoutOne : SemiringWithoutOne _ _
  semiringWithoutOne =
    record { isSemiringWithoutOne = isSemiringWithoutOne }

  open SemiringWithoutOne semiringWithoutOne public
         using (nearSemiring)

record CommutativeSemiringWithoutOne c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier                         : Set c
    _≈_                             : Rel Carrier ℓ
    _+_                             : Op₂ Carrier
    _*_                             : Op₂ Carrier
    0#                              : Carrier
    isCommutativeSemiringWithoutOne :
      IsCommutativeSemiringWithoutOne _≈_ _+_ _*_ 0#

  open IsCommutativeSemiringWithoutOne
         isCommutativeSemiringWithoutOne public

  semiringWithoutOne : SemiringWithoutOne _ _
  semiringWithoutOne =
    record { isSemiringWithoutOne = isSemiringWithoutOne }

  open SemiringWithoutOne semiringWithoutOne public
         using ( setoid
               ; +-semigroup; +-rawMonoid; +-monoid
               ; +-commutativeMonoid
               ; *-semigroup
               ; nearSemiring
               )

record CommutativeSemiring c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier               : Set c
    _≈_                   : Rel Carrier ℓ
    _+_                   : Op₂ Carrier
    _*_                   : Op₂ Carrier
    0#                    : Carrier
    1#                    : Carrier
    isCommutativeSemiring : IsCommutativeSemiring _≈_ _+_ _*_ 0# 1#

  open IsCommutativeSemiring isCommutativeSemiring public

  semiring : Semiring _ _
  semiring = record { isSemiring = isSemiring }

  open Semiring semiring public
         using ( setoid
               ; +-semigroup; +-rawMonoid; +-monoid
               ; +-commutativeMonoid
               ; *-semigroup; *-rawMonoid; *-monoid
               ; nearSemiring; semiringWithoutOne
               ; semiringWithoutAnnihilatingZero
               )

  *-commutativeMonoid : CommutativeMonoid _ _
  *-commutativeMonoid =
    record { isCommutativeMonoid = *-isCommutativeMonoid }

  commutativeSemiringWithoutOne : CommutativeSemiringWithoutOne _ _
  commutativeSemiringWithoutOne = record
    { isCommutativeSemiringWithoutOne = isCommutativeSemiringWithoutOne
    }

------------------------------------------------------------------------
-- (Commutative) rings

-- A raw ring is a ring without any laws.

record RawRing c : Set (suc c) where
  infix  8 -_
  infixl 7 _*_
  infixl 6 _+_
  field
    Carrier : Set c
    _+_     : Op₂ Carrier
    _*_     : Op₂ Carrier
    -_      : Op₁ Carrier
    0#      : Carrier
    1#      : Carrier

record Ring c ℓ : Set (suc (c ⊔ ℓ)) where
  infix  8 -_
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _+_     : Op₂ Carrier
    _*_     : Op₂ Carrier
    -_      : Op₁ Carrier
    0#      : Carrier
    1#      : Carrier
    isRing  : IsRing _≈_ _+_ _*_ -_ 0# 1#

  open IsRing isRing public

  +-abelianGroup : AbelianGroup _ _
  +-abelianGroup = record { isAbelianGroup = +-isAbelianGroup }

  semiring : Semiring _ _
  semiring = record { isSemiring = isSemiring }

  open Semiring semiring public
         using ( setoid
               ; +-semigroup; +-rawMonoid; +-monoid
               ; +-commutativeMonoid
               ; *-semigroup; *-rawMonoid; *-monoid
               ; nearSemiring; semiringWithoutOne
               ; semiringWithoutAnnihilatingZero
               )

  open AbelianGroup +-abelianGroup public
         using () renaming (group to +-group)

  rawRing : RawRing _
  rawRing = record
    { _+_ = _+_
    ; _*_ = _*_
    ; -_  = -_
    ; 0#  = 0#
    ; 1#  = 1#
    }

record CommutativeRing c ℓ : Set (suc (c ⊔ ℓ)) where
  infix  8 -_
  infixl 7 _*_
  infixl 6 _+_
  infix  4 _≈_
  field
    Carrier           : Set c
    _≈_               : Rel Carrier ℓ
    _+_               : Op₂ Carrier
    _*_               : Op₂ Carrier
    -_                : Op₁ Carrier
    0#                : Carrier
    1#                : Carrier
    isCommutativeRing : IsCommutativeRing _≈_ _+_ _*_ -_ 0# 1#

  open IsCommutativeRing isCommutativeRing public

  ring : Ring _ _
  ring = record { isRing = isRing }

  commutativeSemiring : CommutativeSemiring _ _
  commutativeSemiring =
    record { isCommutativeSemiring = isCommutativeSemiring }

  open Ring ring public using (rawRing; +-group; +-abelianGroup)
  open CommutativeSemiring commutativeSemiring public
         using ( setoid
               ; +-semigroup; +-rawMonoid; +-monoid; +-commutativeMonoid
               ; *-semigroup; *-rawMonoid; *-monoid; *-commutativeMonoid
               ; nearSemiring; semiringWithoutOne
               ; semiringWithoutAnnihilatingZero; semiring
               ; commutativeSemiringWithoutOne
               )

------------------------------------------------------------------------
-- (Distributive) lattices and boolean algebras

record Lattice c ℓ : Set (suc (c ⊔ ℓ)) where
  infixr 7 _∧_
  infixr 6 _∨_
  infix  4 _≈_
  field
    Carrier   : Set c
    _≈_       : Rel Carrier ℓ
    _∨_       : Op₂ Carrier
    _∧_       : Op₂ Carrier
    isLattice : IsLattice _≈_ _∨_ _∧_

  open IsLattice isLattice public

  setoid : Setoid _ _
  setoid = record { isEquivalence = isEquivalence }

record DistributiveLattice c ℓ : Set (suc (c ⊔ ℓ)) where
  infixr 7 _∧_
  infixr 6 _∨_
  infix  4 _≈_
  field
    Carrier               : Set c
    _≈_                   : Rel Carrier ℓ
    _∨_                   : Op₂ Carrier
    _∧_                   : Op₂ Carrier
    isDistributiveLattice : IsDistributiveLattice _≈_ _∨_ _∧_

  open IsDistributiveLattice isDistributiveLattice public

  lattice : Lattice _ _
  lattice = record { isLattice = isLattice }

  open Lattice lattice public using (setoid)

record BooleanAlgebra c ℓ : Set (suc (c ⊔ ℓ)) where
  infix  8 ¬_
  infixr 7 _∧_
  infixr 6 _∨_
  infix  4 _≈_
  field
    Carrier          : Set c
    _≈_              : Rel Carrier ℓ
    _∨_              : Op₂ Carrier
    _∧_              : Op₂ Carrier
    ¬_               : Op₁ Carrier
    ⊤                : Carrier
    ⊥                : Carrier
    isBooleanAlgebra : IsBooleanAlgebra _≈_ _∨_ _∧_ ¬_ ⊤ ⊥

  open IsBooleanAlgebra isBooleanAlgebra public

  distributiveLattice : DistributiveLattice _ _
  distributiveLattice =
    record { isDistributiveLattice = isDistributiveLattice }

  open DistributiveLattice distributiveLattice public
         using (setoid; lattice)


-- Exercises for session 3
--
-- If unsure which exercises to do start with those marked with *
--
{-# OPTIONS --cubical --allow-unsolved-metas #-}
module ExerciseSession3 where

open import Part1
open import Part2
open import Part3
open import Part4
open import ExerciseSession1 hiding (B)

open import Cubical.Foundations.Isomorphism
open import Cubical.Data.Nat
open import Cubical.Data.Int hiding (neg)

-- Exercise* 1: prove associativity of _++_ for FMSet.
-- (hint: mimic the proof of unitr-++)

-- Exercise 2: define the integers as a HIT with a pos and neg
-- constructor each taking a natural number as well as a path
-- constructor equating pos 0 and neg 0.

-- Exercise 3 (a little longer, but not very hard): prove that the
-- above definition of the integers is equal to the ones in
-- Cubical.Data.Int. Deduce that they form a set.

-- Exercise* 4: we can define the notion of a surjection as:
isSurjection : (A → B) → Type _
isSurjection {A = A} {B = B} f = (b : B) → ∃ A (λ a → f a ≡ b)

-- The exercise is now to:
--
-- a) prove that being a surjection is a proposition
--
-- b) prove that the inclusion ∣_∣ : A → ∥ A ∥ is surjective
--    (hint: use rec for ∥_∥)

-- Exercise* 5: define

intLoop : Int → ΩS¹
intLoop = {!!}

-- which given +n return loop^n and given -n returns loop^-n. Then
-- prove that:

windingIntLoop : (n : Int) → winding (intLoop n) ≡ n
windingIntLoop = {!!}

-- (The other direction is much more difficult and relies on the
-- encode-decode method. See Egbert's course on Friday!)

-- Exercise 6 (harder): the suspension of a type can be defined as

data Susp (A : Type ℓ) : Type ℓ where
  north : Susp A
  south : Susp A
  merid : (a : A) → north ≡ south

-- Prove that the circle is equal to the suspension of Bool
S¹≡SuspBool : S¹ ≡ Susp Bool
S¹≡SuspBool = {!!}

-- Hint: define maps back and forth and prove that they cancel.


------------------------------------------------------------------------
-- The Agda standard library
--
-- Operations on and properties of decidable relations
------------------------------------------------------------------------

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

module Relation.Nullary.Decidable where

open import Data.Bool.Base using (Bool; false; true; not; T)
open import Data.Empty
open import Data.Product hiding (map)
open import Data.Unit
open import Function
open import Function.Equality using (_⟨$⟩_; module Π)
open import Function.Equivalence
  using (_⇔_; equivalence; module Equivalence)
open import Function.Injection using (Injection; module Injection)
open import Level using (Lift)
open import Relation.Binary using (Setoid; module Setoid; Decidable)
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary

⌊_⌋ : ∀ {p} {P : Set p} → Dec P → Bool
⌊ yes _ ⌋ = true
⌊ no  _ ⌋ = false

True : ∀ {p} {P : Set p} → Dec P → Set
True Q = T ⌊ Q ⌋

False : ∀ {p} {P : Set p} → Dec P → Set
False Q = T (not ⌊ Q ⌋)

-- Gives a witness to the "truth".

toWitness : ∀ {p} {P : Set p} {Q : Dec P} → True Q → P
toWitness {Q = yes p} _  = p
toWitness {Q = no  _} ()

-- Establishes a "truth", given a witness.

fromWitness : ∀ {p} {P : Set p} {Q : Dec P} → P → True Q
fromWitness {Q = yes p} = const _
fromWitness {Q = no ¬p} = ¬p

-- Variants for False.

toWitnessFalse : ∀ {p} {P : Set p} {Q : Dec P} → False Q → ¬ P
toWitnessFalse {Q = yes _}  ()
toWitnessFalse {Q = no  ¬p} _  = ¬p

fromWitnessFalse : ∀ {p} {P : Set p} {Q : Dec P} → ¬ P → False Q
fromWitnessFalse {Q = yes p} = flip _$_ p
fromWitnessFalse {Q = no ¬p} = const _

map : ∀ {p q} {P : Set p} {Q : Set q} → P ⇔ Q → Dec P → Dec Q
map P⇔Q (yes p) = yes (Equivalence.to P⇔Q ⟨$⟩ p)
map P⇔Q (no ¬p) = no (¬p ∘ _⟨$⟩_ (Equivalence.from P⇔Q))

map′ : ∀ {p q} {P : Set p} {Q : Set q} →
       (P → Q) → (Q → P) → Dec P → Dec Q
map′ P→Q Q→P = map (equivalence P→Q Q→P)

module _ {a₁ a₂ b₁ b₂} {A : Setoid a₁ a₂} {B : Setoid b₁ b₂} where

  open Injection
  open Setoid A using () renaming (_≈_ to _≈A_)
  open Setoid B using () renaming (_≈_ to _≈B_)

  -- If there is an injection from one setoid to another, and the
  -- latter's equivalence relation is decidable, then the former's
  -- equivalence relation is also decidable.

  via-injection : Injection A B → Decidable _≈B_ → Decidable _≈A_
  via-injection inj dec x y with dec (to inj ⟨$⟩ x) (to inj ⟨$⟩ y)
  ... | yes injx≈injy = yes (Injection.injective inj injx≈injy)
  ... | no  injx≉injy = no (λ x≈y → injx≉injy (Π.cong (to inj) x≈y))

-- If a decision procedure returns "yes", then we can extract the
-- proof using from-yes.

module _ {p} {P : Set p} where

  From-yes : Dec P → Set p
  From-yes (yes _) = P
  From-yes (no  _) = Lift p ⊤

  from-yes : (p : Dec P) → From-yes p
  from-yes (yes p) = p
  from-yes (no  _) = _

-- If a decision procedure returns "no", then we can extract the proof
-- using from-no.

  From-no : Dec P → Set p
  From-no (no  _) = ¬ P
  From-no (yes _) = Lift p ⊤

  from-no : (p : Dec P) → From-no p
  from-no (no ¬p) = ¬p
  from-no (yes _) = _


open import Type

module Graph.Walk.Properties {ℓ₁ ℓ₂} {V : Type{ℓ₁}} where

open import Lang.Instance
open import Logic
import      Lvl
open import Graph{ℓ₁}{ℓ₂}(V)
open import Graph.Walk{ℓ₁}{ℓ₂}{V}
open import Relator.Equals.Proofs.Equiv
open import Type.Properties.MereProposition

module _ (_⟶_ : Graph) where
  -- `Passes edge walk` states that the walk `walk` contains the edge `edge`.
  -- In other words, there is a step in the walk which is `edge`.
  -- Note: Passes is a generalized containment relation for paths instead of lists.
  data Passes {v₁ v₂ : V} (edge : v₁ ⟶ v₂) : ∀{a b : V} → Walk(_⟶_) a b → Type{ℓ₁ Lvl.⊔ ℓ₂} where
    current : ∀{c}{rest : Walk(_⟶_) v₂ c} → Passes edge (Walk.prepend edge rest)
    skip    : ∀{b c}{rest : Walk(_⟶_) b c} → Passes edge rest → ∀{a}{e : (a ⟶ b)} → Passes edge (Walk.prepend e rest)

  -- `Visits v walk` states that the walk `walk` visits the vertex `v`.
  -- In other words, one of the steps/edges in the walk mention the vertex v.
  data Visits (v : V) : ∀{a b : V} → Walk(_⟶_) a b → Type{ℓ₁ Lvl.⊔ ℓ₂} where
    current : ∀{b}{path : Walk(_⟶_) v b} → Visits v path
    skip    : ∀{a b c}{e : (a ⟶ b)}{rest : Walk(_⟶_) b c} → Visits v rest → Visits v (Walk.prepend e rest)

  module _ {a b : V} (walk₁ : Walk(_⟶_) a b) {c d : V} (walk₂ : Walk(_⟶_) c d) where
    record Subwalk : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
      constructor intro
      field proof : ∀{v₁ v₂ : V}{edge : v₁ ⟶ v₂} → Passes edge walk₁ → Passes edge walk₂

module _ {_⟶_ : Graph} {a b : V} (walk : Walk(_⟶_) a b) where
  -- A walk that never visits the same edge twice.
  -- Note: Equality on edges must respect uniqueness. In other words, one edge must not have multiple constructions.
  record Trail : Type{ℓ₁ Lvl.⊔ ℓ₂} where
    constructor intro
    field proof : ∀{v₁ v₂ : V}{edge : v₁ ⟶ v₂} → MereProposition(Passes(_⟶_) edge walk)

  -- A walk that never visits the same vertex twice.
  -- Also called "Simple path".
  -- Note: Equality on edges must respect uniqueness. In other words, one edge must not have multiple constructions.
  record Path : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
    constructor intro
    field proof : ∀{v : V} → MereProposition(Visits(_⟶_) v walk)
  path = inst-fn Path.proof

  -- A walk that visits every vertex in the graph.
  record Traceable : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
    constructor intro
    field proof : ∀{v : V} → Visits(_⟶_) v walk
  traceable = inst-fn Traceable.proof


module Common.Equality where

open import Common.Level

infix 4 _≡_

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

{-# BUILTIN EQUALITY _≡_  #-}
{-# BUILTIN REFL     refl #-}

subst : ∀ {a p}{A : Set a}(P : A → Set p){x y : A} → x ≡ y → P x → P y
subst P refl t = t


------------------------------------------------------------------------
-- The Agda standard library
--
-- Natural numbers with fast addition (for use together with
-- DifferenceVec)
------------------------------------------------------------------------

module Data.DifferenceNat where

open import Data.Nat as N using (ℕ)
open import Function

infixl 6 _+_

Diffℕ : Set
Diffℕ = ℕ → ℕ

0# : Diffℕ
0# = λ k → k

suc : Diffℕ → Diffℕ
suc n = λ k → N.suc (n k)

1# : Diffℕ
1# = suc 0#

_+_ : Diffℕ → Diffℕ → Diffℕ
m + n = λ k → m (n k)

toℕ : Diffℕ → ℕ
toℕ n = n 0

-- fromℕ n is linear in the size of n.

fromℕ : ℕ → Diffℕ
fromℕ n = λ k → n ⟨ N._+_ ⟩ k


open import Oscar.Prelude
open import Oscar.Data.𝟘

module Oscar.Data.Proposequality where

module _ where

  data Proposequality {𝔬} {𝔒 : Ø 𝔬} (𝓞 : 𝔒) : 𝔒 → Ø₀ where
    instance ∅ : Proposequality 𝓞 𝓞

  {-# BUILTIN EQUALITY Proposequality #-}

  Proposequality⟦_⟧ : ∀ {𝔬} (𝔒 : Ø 𝔬) → 𝔒 → 𝔒 → Ø₀
  Proposequality⟦ _ ⟧ = Proposequality

  [Proposequality] : ∀ {𝔬} {𝔒 : Ø 𝔬} → {x y : 𝔒} → Ø₀
  [Proposequality] {x = x} {y = y} = Proposequality x y

module _ where

  infix 4 _≡_
  _≡_ = Proposequality

-- transport : ∀ {a b} {A : Set a} (B : A → Set b) {x y} → x ≡ y → B x → B y
-- transport _ ∅ = ¡

-- transport₂ : ∀ {a b c} {A : Set a} {B : Set b} (C : A → B → Set c) {x₁ x₂ y₁ y₂} → x₁ ≡ x₂ → y₁ ≡ y₂ → C x₁ y₁ → C x₂ y₂
-- transport₂ _ ∅ ∅ = ¡

module _ where

  Proposantiequality : ∀ {𝔬} {𝔒 : Ø 𝔬} → 𝔒 → 𝔒 → Ø₀
  Proposantiequality x y = Proposequality x y → 𝟘

  Proposantiequality⟦_⟧ : ∀ {𝔬} (𝔒 : Ø 𝔬) → 𝔒 → 𝔒 → Ø₀
  Proposantiequality⟦ _ ⟧ = Proposantiequality

  infix 4 _≢_
  _≢_ = Proposantiequality

module _ where

  Proposextensequality : ∀ {𝔬} {𝔒 : Ø 𝔬} {𝔭} {𝔓 : 𝔒 → Ø 𝔭} → ((𝓞 : 𝔒) → 𝔓 𝓞) → ((𝓞 : 𝔒) → 𝔓 𝓞) → Ø 𝔬
  Proposextensequality 𝓟₁ 𝓟₂ = ∀ 𝓞 → Proposequality (𝓟₁ 𝓞) (𝓟₂ 𝓞)

  Proposextensequality⟦_⟧ : ∀ {𝔬} {𝔒 : Ø 𝔬} {𝔭} (𝔓 : 𝔒 → Ø 𝔭) → ((𝓞 : 𝔒) → 𝔓 𝓞) → ((𝓞 : 𝔒) → 𝔓 𝓞) → Ø 𝔬
  Proposextensequality⟦ _ ⟧ = Proposextensequality

  Proposextensequality[_/_] : ∀ {𝔬} (𝔒 : Ø 𝔬) {𝔭} (𝔓 : 𝔒 → Ø 𝔭) → ((𝓞 : 𝔒) → 𝔓 𝓞) → ((𝓞 : 𝔒) → 𝔓 𝓞) → Ø 𝔬
  Proposextensequality[ _ / _ ] = Proposextensequality

module _ where

  infix 4 _≡̇_
  _≡̇_ = Proposextensequality

  infix 4 ≡̇⟦⟧-syntax
  ≡̇⟦⟧-syntax = Proposextensequality⟦_⟧
  syntax ≡̇⟦⟧-syntax t x y = x ≡̇⟦ t ⟧ y


------------------------------------------------------------------------------
-- Reasoning about a function without a termination proof
------------------------------------------------------------------------------

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

module FOT.FOTC.Program.Collatz.CollatzSL where

open import Data.Bool.Base
open import Data.Empty
open import Data.Nat renaming ( suc to succ )
open import Data.Nat.Properties
open import Data.Product
open import Data.Sum
open import Relation.Binary.PropositionalEquality hiding ( [_] )
open import Relation.Nullary

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

isEven : ℕ → Bool
isEven 0               = true
isEven 1               = false
isEven (succ (succ n)) = isEven n

{-# TERMINATING #-}
collatz : ℕ → ℕ
collatz zero        = 1
collatz (succ zero) = 1
{-# CATCHALL #-}
collatz n with isEven n
... | true  = collatz ⌊ n /2⌋
... | false = collatz (3 * n + 1)

-- 25 April 2014: Failed with Andreas' --without-K.
xy≡0→x≡0∨y≡0 : (m n : ℕ) → m * n ≡ zero → m ≡ zero ⊎ n ≡ zero
xy≡0→x≡0∨y≡0 zero     n        h = inj₁ refl
xy≡0→x≡0∨y≡0 (succ m) zero     h = inj₂ refl
xy≡0→x≡0∨y≡0 (succ m) (succ n) ()

+∸2 : ∀ {n} → n ≢ zero → n ≢ 1 → n ≡ succ (succ (n ∸ 2))
+∸2 {zero}          0≢0 _   = ⊥-elim (0≢0 refl)
+∸2 {succ zero}     _   1≢1 = ⊥-elim (1≢1 refl)
+∸2 {succ (succ n)} _   _   = refl

2^x≢0 : (n : ℕ) → 2 ^ n ≢ zero
2^x≢0 zero ()
2^x≢0 (succ n) h = [ (λ ())
                   , (λ 2^n≡0 → ⊥-elim (2^x≢0 n 2^n≡0))
                   ]′ (xy≡0→x≡0∨y≡0 2 (2 ^ n) h)

2^[x+1]/2≡2^x : ∀ n → ⌊ 2 ^ succ n /2⌋ ≡ 2 ^ n
2^[x+1]/2≡2^x zero            = refl
2^[x+1]/2≡2^x (succ zero)     = refl
2^[x+1]/2≡2^x (succ (succ n)) = {!!}

collatz-2^x : ∀ n → Σ ℕ (λ k → n ≡ 2 ^ k) → collatz n ≡ 1
collatz-2^x zero     h                = refl
collatz-2^x (succ n) (zero , proj₂)   = subst (λ t → collatz t ≡ 1) (sym proj₂) refl
collatz-2^x (succ n) (succ k , proj₂) = subst (λ t → collatz t ≡ 1) (sym proj₂) {!!}

succInjective : ∀ {m n} → succ m ≡ succ n → m ≡ n
succInjective refl = refl

Sx≡x→⊥ : ∀ n → succ n ≢ n
Sx≡x→⊥ zero ()
Sx≡x→⊥ (succ n) h = ⊥-elim (Sx≡x→⊥ n (succInjective h))

2^[x+1]≢1 : ∀ n → 2 ^ (succ n) ≢ 1
2^[x+1]≢1 n h = Sx≡x→⊥ 1 (i*j≡1⇒i≡1 2 (2 ^ n) h)


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

module Ctt where

open import Cubical.Core.Everything
open import Agda.Primitive.Cubical
  using ( primComp )

-- Identity function.
id : ∀ {ℓ} {A : Set ℓ} (x : A) → A
id x = x

-- Funciton composition.
_∘_ : ∀ {ℓ} {A B C : Type ℓ} (g : B → C) (f : A → B) → A → C
g ∘ f = λ a → g (f a)

-- Equivalence is the path to `x` itself.
refl : ∀ {ℓ} {A : Type ℓ} {x : A} → Path A x x
refl {x = x} = λ i → x

-- A square in `A` is built out of 4 points and 4 lines.
square : ∀ {ℓ} {A : Type ℓ} {x0 x1 y0 y1 : A}
  → x0 ≡ x1 → y0 ≡ y1 → x0 ≡ y0 → x1 ≡ y1
  → Type ℓ
square p q r s = PathP (λ i → p i ≡ q i) r s

-- Symmetry.
sym : ∀ {ℓ} {A : Type ℓ} {x y : A} → x ≡ y → y ≡ x
sym p i = p (~ i)
-- sym p i = λ i → p (~ i)

-- Congruence.
cong : ∀ {ℓ} {A : Type ℓ} {x y : A} {B : A → Type ℓ}
  (f : (a : A) → B a) (p : x ≡ y)
  → PathP (λ i → B (p i)) (f x) (f y)
cong f p i = f (p i)

-- Symmetry inverse.
symInv : ∀ {ℓ} {A : Type ℓ} {x y : A} (p : x ≡ y) → sym (sym p) ≡ p
symInv p = refl

-- Congruence with identity function.
congId : ∀ {ℓ} {A : Type ℓ} {x y : A} (p : x ≡ y) → cong id p ≡ p
congId p = refl

-- Congruence with composition.
congComp : ∀ {ℓ} {A B C : Type ℓ}
  (f : A → B) (g : B → C)
  {x y : A} (p : x ≡ y)
  → cong (g ∘ f) p ≡ cong g (cong f p)
congComp f g p = refl

-- Function extensionality.
funExt : ∀ {ℓ} {A : Type ℓ} {B : A → Type ℓ} {f g : (x : A) → B x}
  → ((x : A) → f x ≡ g x) → f ≡ g
funExt p i x = p x i
-- `p` matches the 1st parameter,
-- `i` matches the dimension of the 1st parameter,
-- `x` matches `(x : A)`,
-- `funExt p i x = {!!}` the goal matches `B x`,
-- `(p x) i` is obvious.

-- Transitivity.
trans : ∀ {ℓ} {A : Type ℓ} {x y z : A}
  → x ≡ y → y ≡ z → x ≡ z
trans {y = y} p q i = primComp {!!} {!!} {!!}

-- Transport with composition.
transportComp : ∀ {ℓ} {A B C : Type ℓ}
  → A ≡ B → B ≡ C → A → C
transportComp p q a = {!!}


import Lvl

module Type.Functions.Proofs {ℓₗ : Lvl.Level} where

open import Functional
import      Function.Domains
import      Lang.Irrelevance
import      Logic.Predicate
import      Logic.Predicate.Theorems
import      Relator.Equals
import      Relator.Equals.Proofs
open import Type
open import Type.Properties.Empty
import      Type.Functions
import      Type.Singleton.Proofs
open import Type.Properties.Singleton
open import Type.Properties.Singleton.Proofs

module _ {ℓₒ₁}{ℓₒ₂} {X : Type{ℓₒ₁}} {Y : Type{ℓₒ₂}} {f : X → Y} where
  open Type.Functions {ℓₗ}{ℓₒ₁}{ℓₒ₂} {X}{Y}

  bijective-to-injective : ⦃ bij : Bijective(f) ⦄ → Injective(f)
  Injective.proof (bijective-to-injective ⦃ intro proof ⦄) {y} =
    unit-is-prop {ℓₒ₁} ⦃ proof{y} ⦄

  bijective-to-surjective : ⦃ bij : Bijective(f) ⦄ → Surjective(f)
  Surjective.proof (bijective-to-surjective ⦃ intro proof ⦄) {y} =
    unit-is-pos {ℓₗ Lvl.⊔ ℓₒ₁} ⦃ proof{y} ⦄

  injective-surjective-to-bijective : ⦃ inj : Injective(f) ⦄ → ⦃ surj : Surjective(f) ⦄ → Bijective(f)
  Bijective.proof(injective-surjective-to-bijective ⦃ intro inj ⦄ ⦃ intro surj ⦄) {y} =
    pos-prop-is-unit {ℓₗ Lvl.⊔ ℓₒ₁} ⦃ surj{y} ⦄ ⦃ inj{y} ⦄

module _ {ℓₒ₁}{ℓₒ₂} {X : Type{ℓₒ₁}} {Y : Type{ℓₒ₂}} {f : X → Y} where
  open Function.Domains
  open Type.Functions {ℓₗ}{ℓₒ₁}{ℓₒ₂} {X}{Y}
  open Relator.Equals

  private
    _≡₁_ = _≡_ {ℓₗ Lvl.⊔ ℓₒ₁}

  Injective-apply : ⦃ _ : Injective(f) ⦄ → ∀{x y} → (f(x) ≡₁ f(y)) → (x ≡₁ y)
  Injective-apply ⦃ Injective.intro proof ⦄ {x}{y} (fxfy) with proof{f(y)}
  ... | MereProposition.intro uniqueness with uniqueness{Unapply.intro x ⦃ fxfy ⦄} {Unapply.intro y ⦃ [≡]-intro ⦄}
  ...   | [≡]-intro = [≡]-intro

module _ {ℓₒ : Lvl.Level} {X : Type{ℓₒ}} where
  open Type.Functions {ℓₗ Lvl.⊔ ℓₒ}{ℓₒ}{ℓₒ} {X}{X}
  open Type.Singleton.Proofs {ℓₗ}{ℓₒ} {X}

  instance
    id-is-bijective : Bijective(id)
    id-is-bijective = intro Singleton-is-unit


-- Andreas, 2017-01-24, issue #2430, reported by nad

-- Regression introduced by updating module parameter substitution
-- when going underAbstraction (80794767db1aceaa78a72e06ad901cfa53f8346d).

record Σ (A : Set) (B : A → Set) : Set where
  field
    proj₁ : A
    proj₂ : B proj₁

open Σ public

Σ-map : {A : Set} {B : Set} {P : A → Set} {Q : B → Set} →
        (f : A → B) → (∀ {x} → P x → Q (f x)) →
        Σ A P → Σ B Q
Σ-map f g p = record { proj₁ = f (proj₁ p); proj₂ = g (proj₂ p) }

postulate

  _≡_        : {A : Set} → A → A → Set
  refl       : {A : Set} (x : A) → x ≡ x
  cong       : {A : Set} {B : Set} (f : A → B) {x y : A} →
               x ≡ y → f x ≡ f y
  cong-refl  : {A : Set} {B : Set} (f : A → B) {x : A} →
               refl (f x) ≡ cong f (refl x)
  subst      : {A : Set} (P : A → Set) {x y : A} →
               x ≡ y → P x → P y
  subst-refl : ∀ {A : Set} (P : A → Set) {x} (p : P x) →
               subst P (refl x) p ≡ p
  trans      : {A : Set} {x y z : A} → x ≡ y → y ≡ z → x ≡ z

module _ (_ : Set) where

  postulate

    Σ-≡,≡→≡ : {A : Set} {B : A → Set} {p₁ p₂ : Σ A B} →
              (p : proj₁ p₁ ≡ proj₁ p₂) →
              subst B p (proj₂ p₁) ≡ proj₂ p₂ →
              p₁ ≡ p₂

    Σ-≡,≡→≡-refl-subst-refl :
      ∀ {A : Set} {B : A → Set} {p} →
      Σ-≡,≡→≡ (refl (proj₁ p)) (subst-refl B (proj₂ p)) ≡ refl p

  rejected :
    {A₁ A₂ : Set} {B₁ : A₁ → Set} {B₂ : A₂ → Set}
    (f : A₁ → A₂) (g : ∀ x → B₁ x → B₂ (f x)) (x : Σ A₁ B₁) →
    Σ-≡,≡→≡ (refl _) (subst-refl B₂ _) ≡ cong (Σ-map f (g _)) (refl x)
  rejected {B₁ = B₁} {B₂} f g x =
    trans {x = Σ-≡,≡→≡ (refl _) (subst-refl B₂ _)}
          {z = cong (Σ-map f (g _)) (refl _)}
          Σ-≡,≡→≡-refl-subst-refl
          (cong-refl _)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Some examples of how to use non-trivial induction over the natural
-- numbers.
------------------------------------------------------------------------

module README.Data.Nat.Induction where

open import Data.Nat
open import Data.Nat.Induction
open import Data.Product using (_,_)
open import Function using (_∘_)
open import Induction.WellFounded
open import Relation.Binary.PropositionalEquality

-- Doubles its input.

twice : ℕ → ℕ
twice = rec _ λ
  { zero    _       → zero
  ; (suc n) twice-n → suc (suc twice-n)
  }

-- Halves its input (rounding downwards).
--
-- The step function is mentioned in a proof below, so it has been
-- given a name. (The mutual keyword is used to avoid having to give
-- a type signature for the step function.)

mutual

  half₁-step = λ
    { zero          _                → zero
    ; (suc zero)    _                → zero
    ; (suc (suc n)) (_ , half₁n , _) → suc half₁n
    }

  half₁ : ℕ → ℕ
  half₁ = cRec _ half₁-step

-- An alternative implementation of half₁.

mutual

  half₂-step = λ
    { zero          _   → zero
    ; (suc zero)    _   → zero
    ; (suc (suc n)) rec → suc (rec n (≤′-step ≤′-refl))
    }

  half₂ : ℕ → ℕ
  half₂ = <′-rec _ half₂-step

-- The application half₁ (2 + n) is definitionally equal to
-- 1 + half₁ n. Perhaps it is instructive to see why.

half₁-2+ : ∀ n → half₁ (2 + n) ≡ 1 + half₁ n
half₁-2+ n = begin

  half₁ (2 + n)                                                         ≡⟨⟩

  cRec _ half₁-step (2 + n)                                             ≡⟨⟩

  half₁-step (2 + n) (cRecBuilder _ half₁-step (2 + n))                 ≡⟨⟩

  half₁-step (2 + n)
    (let ih = cRecBuilder _ half₁-step (1 + n) in
     half₁-step (1 + n) ih , ih)                                        ≡⟨⟩

  half₁-step (2 + n)
    (let ih = cRecBuilder _ half₁-step n in
     half₁-step (1 + n) (half₁-step n ih , ih) , half₁-step n ih , ih)  ≡⟨⟩

  1 + half₁-step n (cRecBuilder _ half₁-step n)                         ≡⟨⟩

  1 + cRec _ half₁-step n                                               ≡⟨⟩

  1 + half₁ n                                                           ∎

  where open ≡-Reasoning

-- The application half₂ (2 + n) is definitionally equal to
-- 1 + half₂ n. Perhaps it is instructive to see why.

half₂-2+ : ∀ n → half₂ (2 + n) ≡ 1 + half₂ n
half₂-2+ n = begin

  half₂ (2 + n)                                               ≡⟨⟩

  <′-rec _ half₂-step (2 + n)                                 ≡⟨⟩

  half₂-step (2 + n) (<′-recBuilder _ half₂-step (2 + n))     ≡⟨⟩

  1 + <′-recBuilder _ half₂-step (2 + n) n (≤′-step ≤′-refl)  ≡⟨⟩

  1 + Some.wfRecBuilder _ half₂-step (2 + n)
        (<′-wellFounded (2 + n)) n (≤′-step ≤′-refl)          ≡⟨⟩

  1 + Some.wfRecBuilder _ half₂-step (2 + n)
        (acc (<′-wellFounded′ (2 + n))) n (≤′-step ≤′-refl)   ≡⟨⟩

  1 + half₂-step n
        (Some.wfRecBuilder _ half₂-step n
           (<′-wellFounded′ (2 + n) n (≤′-step ≤′-refl)))     ≡⟨⟩

  1 + half₂-step n
        (Some.wfRecBuilder _ half₂-step n
           (<′-wellFounded′ (1 + n) n ≤′-refl))               ≡⟨⟩

  1 + half₂-step n
        (Some.wfRecBuilder _ half₂-step n (<′-wellFounded n)) ≡⟨⟩

  1 + half₂-step n (<′-recBuilder _ half₂-step n)             ≡⟨⟩

  1 + <′-rec _ half₂-step n                                   ≡⟨⟩

  1 + half₂ n                                                 ∎

  where open ≡-Reasoning

-- Some properties that the functions above satisfy, proved using
-- cRec.

half₁-+₁ : ∀ n → half₁ (twice n) ≡ n
half₁-+₁ = cRec _ λ
  { zero          _                        → refl
  ; (suc zero)    _                        → refl
  ; (suc (suc n)) (_ , half₁twice-n≡n , _) →
      cong (suc ∘ suc) half₁twice-n≡n
  }

half₂-+₁ : ∀ n → half₂ (twice n) ≡ n
half₂-+₁ = cRec _ λ
  { zero          _                        → refl
  ; (suc zero)    _                        → refl
  ; (suc (suc n)) (_ , half₁twice-n≡n , _) →
      cong (suc ∘ suc) half₁twice-n≡n
  }

-- Some properties that the functions above satisfy, proved using
-- <′-rec.

half₁-+₂ : ∀ n → half₁ (twice n) ≡ n
half₁-+₂ = <′-rec _ λ
  { zero          _   → refl
  ; (suc zero)    _   → refl
  ; (suc (suc n)) rec →
      cong (suc ∘ suc) (rec n (≤′-step ≤′-refl))
  }

half₂-+₂ : ∀ n → half₂ (twice n) ≡ n
half₂-+₂ = <′-rec _ λ
  { zero          _   → refl
  ; (suc zero)    _   → refl
  ; (suc (suc n)) rec →
      cong (suc ∘ suc) (rec n (≤′-step ≤′-refl))
  }


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

open import Level using (Level; suc; _⊔_)

open import Categories.Category
open import Data.Product
import Categories.Morphism

record pseudo-iso {o ℓ e} (C : Category o ℓ e) : Set (o ⊔ ℓ ⊔ e) where
  open Category C
  open Definitions C
  open Categories.Morphism C

  infix 10 _⁻¹
  field
    _⁻¹ : ∀ {A B} → (f : A ⇒ B) → B ⇒ A
    pseudo-iso₁ : ∀ {A B} {f : A ⇒ B} → f ∘ f ⁻¹ ∘ f ≈ f
    pseudo-iso₂ : ∀ {A B} {f : A ⇒ B} → f ⁻¹ ∘ f ∘ f ⁻¹ ≈ f ⁻¹

record Inverse {o ℓ e} (C : Category o ℓ e) : Set (o ⊔ ℓ ⊔ e) where
  open Category C
  open Definitions C
  open Categories.Morphism C
  open pseudo-iso

  field
    piso : pseudo-iso C
    unique : ∀ {p : pseudo-iso C} {A B} → (f : A ⇒ B) → _⁻¹ piso f ≈ _⁻¹ p f


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

module Magma.Bundles where

open import Algebra.Bundles
open import Algebra.Core
open import Magma.Structures
open import Relation.Binary
open import Level

record IdempotentMagma c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _∙_     : Op₂ Carrier
    isIdempotentMagma  : IsIdempotentMagma _≈_ _∙_

  open IsIdempotentMagma isIdempotentMagma public

  magma : Magma c ℓ
  magma = record { isMagma = isMagma }

  open Magma magma public
    using (rawMagma)

record AlternateMagma c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _∙_     : Op₂ Carrier
    isAlternateMagma  : IsAlternateMagma _≈_ _∙_

  open IsAlternateMagma isAlternateMagma public

  magma : Magma c ℓ
  magma = record { isMagma = isMagma }

  open Magma magma public
    using (rawMagma)

record FlexibleMagma c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _∙_     : Op₂ Carrier
    isFlexibleMagma  : IsFlexibleMagma _≈_ _∙_

  open IsFlexibleMagma isFlexibleMagma public

  magma : Magma c ℓ
  magma = record { isMagma = isMagma }

  open Magma magma public
    using (rawMagma)

record MedialMagma c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _∙_     : Op₂ Carrier
    isMedialMagma  : IsMedialMagma _≈_ _∙_

  open IsMedialMagma isMedialMagma public

  magma : Magma c ℓ
  magma = record { isMagma = isMagma }

  open Magma magma public
    using (rawMagma)

record SemimedialMagma c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier : Set c
    _≈_     : Rel Carrier ℓ
    _∙_     : Op₂ Carrier
    isSemimedialMagma  : IsSemimedialMagma _≈_ _∙_

  open IsSemimedialMagma isSemimedialMagma public

  magma : Magma c ℓ
  magma = record { isMagma = isMagma }

  open Magma magma public
    using (rawMagma)

record LeftUnitalMagma c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier  : Set c
    _≈_      : Rel Carrier ℓ
    _∙_      : Op₂ Carrier
    ε        : Carrier
    isLeftUnitalMagma  : IsLeftUnitalMagma _≈_ _∙_ ε

  open IsLeftUnitalMagma isLeftUnitalMagma public

  magma : Magma c ℓ
  magma = record { isMagma = isMagma }

  open Magma magma public
    using (rawMagma)

record RightUnitalMagma c ℓ : Set (suc (c ⊔ ℓ)) where
  infixl 7 _∙_
  infix  4 _≈_
  field
    Carrier  : Set c
    _≈_      : Rel Carrier ℓ
    _∙_      : Op₂ Carrier
    ε        : Carrier
    isRightUnitalMagma  : IsRightUnitalMagma _≈_ _∙_ ε

  open IsRightUnitalMagma isRightUnitalMagma public

  magma : Magma c ℓ
  magma = record { isMagma = isMagma }

  open Magma magma public
    using (rawMagma)


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

module Data.Binary.Multiplication where

open import Data.Binary.Definition
open import Data.Binary.Addition

double : 𝔹 → 𝔹
double 0ᵇ = 0ᵇ
double (1ᵇ xs) = 2ᵇ double xs
double (2ᵇ xs) = 2ᵇ 1ᵇ xs

infixl 7 _*_
_*_ : 𝔹 → 𝔹 → 𝔹
0ᵇ    * ys = 0ᵇ
1ᵇ xs * ys = ys + double (ys * xs)
2ᵇ xs * ys = double (ys + ys * xs)


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

module Categories.Category.Monoidal.Structure where

open import Level

open import Categories.Category
open import Categories.Category.Monoidal.Core
open import Categories.Category.Monoidal.Braided
open import Categories.Category.Monoidal.Symmetric

record MonoidalCategory o ℓ e : Set (suc (o ⊔ ℓ ⊔ e)) where
  field
    U        : Category o ℓ e
    monoidal : Monoidal U

  module U        = Category U
  module monoidal = Monoidal monoidal

  open U public
  open monoidal public

record BraidedMonoidalCategory o ℓ e : Set (suc (o ⊔ ℓ ⊔ e)) where
  field
    U         : Category o ℓ e
    monoidal  : Monoidal U
    braided   : Braided monoidal

  module U        = Category U
  module monoidal = Monoidal monoidal
  module braided  = Braided braided

  monoidalCategory : MonoidalCategory o ℓ e
  monoidalCategory = record { U = U ; monoidal = monoidal }

  open U public
  open braided public

record SymmetricMonoidalCategory o ℓ e : Set (suc (o ⊔ ℓ ⊔ e)) where
  field
    U         : Category o ℓ e
    monoidal  : Monoidal U
    symmetric : Symmetric monoidal

  module U         = Category U
  module monoidal  = Monoidal monoidal
  module symmetric = Symmetric symmetric

  braidedMonoidalCategory : BraidedMonoidalCategory o ℓ e
  braidedMonoidalCategory = record
    { U        = U
    ; monoidal = monoidal
    ; braided  = symmetric.braided
    }

  open U public
  open symmetric public
  open BraidedMonoidalCategory braidedMonoidalCategory public
    using (monoidalCategory)


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

module Bundles where

open import Agda.Primitive renaming (_⊔_ to ℓ-max; lsuc to ℓ-suc; lzero to ℓ-zero)

private
  variable
    ℓ ℓ' ℓ'' : Level

open import Cubical.Foundations.Everything renaming (_⁻¹ to _⁻¹ᵖ; assoc to ∙-assoc)
open import Cubical.Structures.CommRing
open import Cubical.Relation.Nullary.Base -- ¬_
open import Cubical.Relation.Binary.Base
open import Cubical.Data.Sum.Base renaming (_⊎_ to infixr 4 _⊎_)
open import Cubical.Data.Sigma.Base renaming (_×_ to infixr 4 _×_)
open import Cubical.Data.Empty renaming (elim to ⊥-elim) -- `⊥` and `elim`
-- open import Cubical.Structures.Poset
open import Cubical.Foundations.Function
open import Cubical.Structures.Ring
open import Cubical.Foundations.Logic renaming (¬_ to ¬ᵖ_)

open import Function.Base using (_∋_)
-- open import Function.Reasoning using (∋-syntax)
open import Function.Base using (it) -- instance search

open import Utils
open import MoreLogic
open MoreLogic.Reasoning
open MoreLogic.Properties
open import MoreAlgebra
open MoreAlgebra.Definitions
open MoreAlgebra.Consequences

-- 4.1  Algebraic structure of numbers
--
-- Fields have the property that nonzero numbers have a multiplicative inverse, or more precisely, that
--   (∀ x : F) x ≠ 0 ⇒ (∃ y : F) x · y = 1.
--
-- Remark 4.1.1.
-- If we require the collection of numbers to form a set in the sense of Definition 2.5.4, and satisfy the ring axioms, then multiplicative inverses are unique, so that the above is equivalent to the proposition
--   (Π x : F) x ≠ 0 ⇒ (Σ y : F) x · y = 1.
--
-- Definition 4.1.2.
-- A classical field is a set F with points 0, 1 : F, operations +, · : F → F → F, which is a commutative ring with unit, such that
--   (∀ x : F) x ≠ 0 ⇒ (∃ y : F) x · y = 1.

module ClassicalFieldModule where
  record IsClassicalField {F : Type ℓ}
                          (0f : F) (1f : F) (_+_ : F → F → F) (_·_ : F → F → F) (-_ : F → F) (_⁻¹ᶠ : (x : F) → {{¬(x ≡ 0f)}} → F) : Type ℓ where
    constructor isclassicalfield

    field
      isCommRing : IsCommRing 0f 1f _+_ _·_ -_
      ·-rinv : (x : F) → (p : ¬(x ≡ 0f)) → x · (_⁻¹ᶠ x {{p}}) ≡ 1f
      ·-linv : (x : F) → (p : ¬(x ≡ 0f)) → (_⁻¹ᶠ x {{p}}) · x ≡ 1f

    open IsCommRing {0r = 0f} {1r = 1f} isCommRing public

  record ClassicalField : Type (ℓ-suc ℓ) where
    field
      Carrier : Type ℓ
      0f   : Carrier
      1f   : Carrier
      _+_  : Carrier → Carrier → Carrier
      _·_  : Carrier → Carrier → Carrier
      -_   : Carrier → Carrier
      _⁻¹ᶠ : (x : Carrier) → {{¬(x ≡ 0f)}} → Carrier
      isClassicalField : IsClassicalField 0f 1f _+_ _·_ -_ _⁻¹ᶠ

    infix  9 _⁻¹ᶠ
    infix  8 -_
    infixl 7 _·_
    infixl 6 _+_

    open IsClassicalField isClassicalField public

-- Remark 4.1.3.
-- As in the classical case, by proving that additive and multiplicative inverses are unique, we also obtain the negation and division operations.
--
-- For the reals, the assumption x ≠ 0 does not give us any information allowing us to bound x away from 0, which we would like in order to compute multiplicative inverses.
-- Hence, we give a variation on the denition of fields in which the underlying set comes equipped with an apartness relation #, which satises x # y ⇒ x ≠ y, although the converse implication may not hold.
-- This apartness relation allows us to make appropriate error bounds and compute multiplicative inverses based on the assumption x # 0.
--

-- NOTE: there is also PropRel in Cubical.Relation.Binary.Base which
-- NOTE: one needs these "all-lowercase constructors" to make use of copatterns
-- NOTE: see also Relation.Binary.Indexed.Homogeneous.Definitions.html
-- NOTE: see also Algebra.Definitions.html

-- Definition 4.1.5.
-- A constructive field is a set F with points 0, 1 : F, binary operations +, · : F → F → F, and a binary relation # such that
-- 1. (F, 0, 1, +, ·) is a commutative ring with unit;
-- 2. x : F has a multiplicative inverse iff x # 0;
-- 3. + is #-extensional, that is, for all w, x, y, z : F
--    w + x # y + z ⇒ w # y ∨ x # z.

record IsConstructiveField {F : Type ℓ}
                           (0f : F) (1f : F) (_+_ : F → F → F) (_·_ : F → F → F) (-_ : F → F) (_#_ : hPropRel F F ℓ') (_⁻¹ᶠ : (x : F) → {{[ x # 0f ]}} → F) : Type (ℓ-max ℓ ℓ') where
  constructor isconstructivefield

  field
    isCommRing : IsCommRing 0f 1f _+_ _·_ -_
    ·-rinv     : ∀ x → (p : [ x # 0f ]) → x · (_⁻¹ᶠ x {{p}}) ≡ 1f
    ·-linv     : ∀ x → (p : [ x # 0f ]) → (_⁻¹ᶠ x {{p}}) · x ≡ 1f
    ·-inv-back : ∀ x y → (x · y ≡ 1f) → [ x # 0f ] × [ y # 0f ]
    #-tight    : ∀ x y → ¬([ x # y ]) → x ≡ y
    -- NOTE: the following ⊎ caused trouble two times with resolving ℓ or ℓ'
    +-#-extensional : ∀ w x y z → [ (w + x) # (y + z) ] → [ (w # y) ⊔ (x # z) ]
    isApartnessRel  : IsApartnessRelᵖ _#_

  open IsCommRing {0r = 0f} {1r = 1f} isCommRing public
  open IsApartnessRelᵖ isApartnessRel public
    renaming
      ( isIrrefl  to #-irrefl
      ; isSym     to #-sym
      ; isCotrans to #-cotrans )

record ConstructiveField : Type (ℓ-suc (ℓ-max ℓ ℓ')) where
  constructor constructivefield
  field
    Carrier : Type ℓ
    0f   : Carrier
    1f   : Carrier
    _+_  : Carrier → Carrier → Carrier
    _·_  : Carrier → Carrier → Carrier
    -_   : Carrier → Carrier
    _#_  : hPropRel Carrier Carrier ℓ'
    _⁻¹ᶠ : (x : Carrier) → {{[ x # 0f ]}} → Carrier
    isConstructiveField : IsConstructiveField 0f 1f _+_ _·_ -_ _#_ _⁻¹ᶠ

  infix  9 _⁻¹ᶠ
  infixl 7 _·_
  infix  6 -_
  infixl 5 _+_
  infixl 4 _#_

  open IsConstructiveField isConstructiveField public

-- Definition 4.1.8.
-- Let (A, ≤) be a partial order, and let min, max : A → A → A be binary operators on A. We say that (A, ≤, min, max) is a lattice if min computes greatest lower bounds in the sense that for every x, y, z : A, we have
--   z ≤ min(x,y) ⇔ z ≤ x ∧ z ≤ y,
-- and max computes least upper bounds in the sense that for every x, y, z : A, we have
--   max(x,y) ≤ z ⇔ x ≤ z ∧ y ≤ z.

record IsLattice {A : Type ℓ}
                 (_≤_ : Rel A A ℓ') (min max : A → A → A) : Type (ℓ-max ℓ ℓ') where
  constructor islattice
  field
    isPartialOrder : IsPartialOrder _≤_
    glb      : ∀ x y z → z ≤ min x y → z ≤ x × z ≤ y
    glb-back : ∀ x y z → z ≤ x × z ≤ y → z ≤ min x y
    lub      : ∀ x y z → max x y ≤ z → x ≤ z × y ≤ z
    lub-back : ∀ x y z → x ≤ z × y ≤ z → max x y ≤ z

  open IsPartialOrder isPartialOrder public
    renaming
      ( isRefl    to ≤-refl
      ; isAntisym to ≤-antisym
      ; isTrans   to ≤-trans )

record Lattice : Type (ℓ-suc (ℓ-max ℓ ℓ')) where
  constructor lattice
  field
    Carrier : Type ℓ
    _≤_ : Rel Carrier Carrier ℓ'
    min max : Carrier → Carrier → Carrier
    isLattice : IsLattice _≤_ min max

  infixl 4 _≤_

  open IsLattice isLattice public

-- Remark 4.1.9.2
-- 1. From the fact that (A, ≤, min, max) is a lattice, it does not follow that for every x and y, min(x,y) = x ∨ min(x,y) = y. However, we can characterize min as
--   z < min(x,y) ⇔ z < x ∨ z < y
--   and similarly for max, see Lemma 6.7.1.
-- 2. In a partial order, for two fixed elements a and b, all joins and meets of a, b are equal, so that Lemma 2.6.20 the type of joins and the type of meets are propositions. Hence, providing the maps min and max as in the above definition is equivalent to the showing the existenceof all binary joins and meets.
--
-- The following definition is modified from on The Univalent Foundations Program [89, Definition 11.2.7].
--
-- Definition 4.1.10.
-- An ordered field is a set F together with constants 0, 1, operations +, ·, min, max, and a binary relation < such that:
-- 1. (F, 0, 1, +, ·) is a commutative ring with unit;
-- 2. < is a strict [partial] order;
-- 3. x : F has a multiplicative inverse iff x # 0, recalling that # is defined as in Lemma 4.1.7;
-- 4. ≤, as in Lemma 4.1.7, is antisymmetric, so that (F, ≤) is a partial order;
-- 5. (F, ≤, min, max) is a lattice.
-- 6. for all x, y, z, w : F:
--    x + y < z + w ⇒ x < z ∨ y < w, (†)
--    0 < z ∧ x < y ⇒ x z < y z.     (∗)
-- Our notion of ordered fields coincides with The Univalent Foundations Program [89, Definition 11.2.7].

-- NOTE: well, the HOTT book definition organizes things slightly different. Why prefer one approach over the other?

record IsAlmostOrderedField {F : Type ℓ}
                 (0f 1f : F) (_+_ : F → F → F) (-_ : F → F) (_·_ min max : F → F → F) (_<_ _#_ _≤_ : Rel F F ℓ') (_⁻¹ᶠ : (x : F) → {{x # 0f}} → F) : Type (ℓ-max ℓ ℓ') where
  field
    -- 1.
    isCommRing : IsCommRing 0f 1f _+_ _·_ -_
    -- 2.
    <-isStrictPartialOrder : IsStrictPartialOrder _<_
    -- 3.
    ·-rinv     : (x : F) → (p : x # 0f) → x · (_⁻¹ᶠ x {{p}}) ≡ 1f
    ·-linv     : (x : F) → (p : x # 0f) → (_⁻¹ᶠ x {{p}}) · x ≡ 1f
    ·-inv-back : (x y : F) → (x · y ≡ 1f) → x # 0f × y # 0f
    -- 4. NOTE: we already have ≤-isPartialOrder in <-isLattice
    -- ≤-isPartialOrder : IsPartialOrder _≤_
    -- 5.
    ≤-isLattice : IsLattice _≤_ min max

  open IsCommRing {0r = 0f} {1r = 1f} isCommRing public
  open IsStrictPartialOrder <-isStrictPartialOrder public
    renaming
      ( isIrrefl  to <-irrefl
      ; isTrans   to <-trans
      ; isCotrans to <-cotrans )
  open IsLattice ≤-isLattice public

record AlmostOrderedField : Type (ℓ-suc (ℓ-max ℓ ℓ')) where
  constructor orderedfield
  field
    Carrier : Type ℓ
    0f 1f   : Carrier
    _+_     : Carrier → Carrier → Carrier
    -_      : Carrier → Carrier
    _·_     : Carrier → Carrier → Carrier
    min max : Carrier → Carrier → Carrier
    _<_     : Rel Carrier Carrier ℓ'
    <-isProp : ∀ x y → isProp (x < y)

  _#_ = _#'_ {_<_ = _<_}
  _≤_ = _≤'_ {_<_ = _<_}

  field
    _⁻¹ᶠ    : (x : Carrier) → {{x # 0f}} → Carrier
    isAlmostOrderedField : IsAlmostOrderedField 0f 1f _+_ -_ _·_ min max _<_ _#_ _≤_ _⁻¹ᶠ

  infix  9 _⁻¹ᶠ
  infixl 7 _·_
  infix  6 -_
  infixl 5 _+_
  infixl 4 _#_
  infixl 4 _≤_
  infixl 4 _<_

  open IsAlmostOrderedField isAlmostOrderedField public

  #-isProp : ∀ x y → isProp (x # y)
  #-isProp = #-from-<-isProp _<_ <-isStrictPartialOrder <-isProp

record IsOrderedField {F : Type ℓ}
                 (0f 1f : F) (_+_ : F → F → F) (-_ : F → F) (_·_ min max : F → F → F) (_<_ _#_ _≤_ : Rel F F ℓ') (_⁻¹ᶠ : (x : F) → {{x # 0f}} → F) : Type (ℓ-max ℓ ℓ') where
  constructor isorderedfield
  field
    -- 1. 2. 3. 4. 5.
    isAlmostOrderedField : IsAlmostOrderedField 0f 1f _+_ -_ _·_ min max _<_ _#_ _≤_ _⁻¹ᶠ
    -- 6. (†)
    -- NOTE: this is 'shifted' from the pevious definition of #-extensionality for + .. does the name still fit?
    +-<-extensional : ∀ w x y z → (x + y) < (z + w) → (x < z) ⊎ (y < w)
    -- 6. (∗)
    ·-preserves-< : ∀ x y z → 0f < z → x < y → (x · z) < (y · z)
  open IsAlmostOrderedField isAlmostOrderedField public

record OrderedField : Type (ℓ-suc (ℓ-max ℓ ℓ')) where
  constructor orderedfield
  field
    Carrier : Type ℓ
    0f 1f   : Carrier
    _+_     : Carrier → Carrier → Carrier
    -_      : Carrier → Carrier
    _·_     : Carrier → Carrier → Carrier
    min max : Carrier → Carrier → Carrier
    _<_     : Rel Carrier Carrier ℓ'
    <-isProp : ∀ x y → isProp (x < y)

  _#_ = _#'_ {_<_ = _<_}
  _≤_ = _≤'_ {_<_ = _<_}

  field
    _⁻¹ᶠ    : (x : Carrier) → {{x # 0f}} → Carrier
    isOrderedField : IsOrderedField 0f 1f _+_ -_ _·_ min max _<_ _#_ _≤_ _⁻¹ᶠ

  infix  9 _⁻¹ᶠ
  infixl 7 _·_
  infix  6 -_
  infixl 5 _+_
  infixl 4 _#_
  infixl 4 _≤_
  infixl 4 _<_

  open IsOrderedField isOrderedField public

  abstract
    -- NOTE: there might be some reason not to "do" (or "open") all the theory of a record within that record
    +-preserves-< : ∀ a b x → a < b → a + x < b + x
    +-preserves-< a b x a<b = (
       a            <  b            ⇒⟨ transport (λ i → sym (fst (+-identity a)) i < sym (fst (+-identity b)) i) ⟩
       a +    0f    <  b +    0f    ⇒⟨ transport (λ i → a + sym (+-rinv x) i < b + sym (+-rinv x) i) ⟩
       a + (x  - x) <  b + (x  - x) ⇒⟨ transport (λ i → +-assoc a x (- x) i < +-assoc b x (- x) i) ⟩
      (a +  x) - x  < (b +  x) - x  ⇒⟨ +-<-extensional (- x) (a + x) (- x) (b + x) ⟩
      (a + x < b + x) ⊎ (- x < - x) ⇒⟨ (λ{ (inl a+x<b+x) → a+x<b+x -- somehow ⊥-elim needs a hint in the next line
                                         ; (inr  -x<-x ) → ⊥-elim {A = λ _ → (a + x < b + x)} (<-irrefl (- x) -x<-x) }) ⟩
       a + x < b + x ◼) a<b

    ≤-isPreorder : IsPreorder _≤_
    ≤-isPreorder = ≤-isPreorder' {_<_ = _<_} {<-isStrictPartialOrder}

-- Definition 4.3.1.
-- A morphism from an ordered field (F, 0F , 1F , +F , ·F , minF , maxF , <F )
--              to an ordered field (G, 0G , 1G , +G , ·G , minG , maxG , <G )
-- is a map f : F → G such that
-- 1. f is a morphism of rings,
-- 2. f reflects < in the sense that for every x, y : F
--    f (x) <G f (y) ⇒ x <F y.

-- NOTE: see Cubical.Structures.Group.Morphism
--       and Cubical.Structures.Group.MorphismProperties

-- open import Cubical.Structures.Group.Morphism

record IsRingMor
  {ℓ ℓ'}
  (F : Ring {ℓ}) (G : Ring {ℓ'})
  (f : (Ring.Carrier F) → (Ring.Carrier G)) : Type (ℓ-max ℓ ℓ')
  where
  module F = Ring F
  module G = Ring G
  field
    preserves-+ : ∀ a b → f (a F.+ b) ≡ f a G.+ f b
    preserves-· : ∀ a b → f (a F.· b) ≡ f a G.· f b
    perserves-1 : f F.1r ≡ G.1r

record IsOrderedFieldMor
  {ℓ ℓ' ℓₚ ℓₚ'} -- NOTE: this is a lot of levels. Can we get rid of some of these?
  (F : OrderedField {ℓ} {ℓₚ}) (G : OrderedField {ℓ'} {ℓₚ'})
  -- (let module F = OrderedField F) -- NOTE: `let` is not allowed in a telescope
  -- (let module G = OrderedField G)
  (f : (OrderedField.Carrier F) → (OrderedField.Carrier G)) : Type (ℓ-max (ℓ-max ℓ ℓ') (ℓ-max ℓₚ ℓₚ'))
  where
  module F = OrderedField F
  module G = OrderedField G
  field
    isRingMor : IsRingMor (record {F}) (record {G}) f
    reflects-< : ∀ x y → f x G.< f y → x F.< y
  -- NOTE: for more properties, see https://en.wikipedia.org/wiki/Ring_homomorphism#Properties

record OrderedFieldMor {ℓ ℓ' ℓₚ ℓₚ'} (F : OrderedField {ℓ} {ℓₚ}) (G : OrderedField {ℓ'} {ℓₚ'}) : Type (ℓ-max (ℓ-max ℓ ℓ') (ℓ-max ℓₚ ℓₚ')) where
  constructor orderedfieldmor
  module F = OrderedField F
  module G = OrderedField G
  field
    fun : F.Carrier → G.Carrier
    isOrderedFieldMor : IsOrderedFieldMor F G fun

-- NOTE: f preserves P: P A ⇒ P (f A)
--       f reflects  P: P (f A) ⇒ P A
-- Remark 4.3.2. The contrapositive of reflecting < means preserving ≤.


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

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

open import LogicalFormulae

module Functions.Definition where

Rel : {a b : _} → Set a → Set (a ⊔ lsuc b)
Rel {a} {b} A = A → A → Set b

_∘_ : {a b c : _} {A : Set a} {B : Set b} {C : Set c} → (f : B → C) → (g : A → B) → (A → C)
g ∘ f = λ a → g (f a)

Injection : {a b : _} {A : Set a} {B : Set b} (f : A → B) → Set (a ⊔ b)
Injection {A = A} f = {x y : A} → (f x ≡ f y) → x ≡ y

Surjection : {a b : _} {A : Set a} {B : Set b} (f : A → B) → Set (a ⊔ b)
Surjection {A = A} {B = B} f = (b : B) → Sg A (λ a → f a ≡ b)

record Bijection {a b : _} {A : Set a} {B : Set b} (f : A → B) : Set (a ⊔ b) where
  field
    inj : Injection f
    surj : Surjection f

record Invertible {a b : _} {A : Set a} {B : Set b} (f : A → B) : Set (a ⊔ b) where
  field
    inverse : B → A
    isLeft : (b : B) → f (inverse b) ≡ b
    isRight : (a : A) → inverse (f a) ≡ a

id : {a : _} {A : Set a} → (A → A)
id a = a

dom : {a b : _} {A : Set a} {B : Set b} (f : A → B) → Set a
dom {A = A} f = A

codom : {a b : _} {A : Set a} {B : Set b} (f : A → B) → Set b
codom {B = B} f = B


data N : Set = zero | suc (n:N)
data B : Set = true | false

data False : Set =
data True  : Set = tt

F : B -> Set
F true  = N
F false = B

G : (x:B) -> F x -> Set
G false _      = N
G true zero    = B
G true (suc n) = N

(==) : B -> B -> Set
true == true = True
false == false = True
_ == _ = False

data Equal (x,y:B) : Set where
  equal : x == y -> Equal x y

refl : (x:B) -> Equal x x
refl true = equal tt
refl false = equal tt

postulate
  f : (x:B) -> (y : F x) -> G x y -> N -- Equal x true -> N

h : N
h = f _ false zero --(refl true)


open import Agda.Builtin.Nat

interleaved mutual

  plus : Nat → Nat → Nat
  mult : Nat → Nat → Nat

  -- base case
  mult 0 n = 0
  plus 0 n = n

  -- inductive case. The fun clauses with an ellipsis belong to mult
  mult (suc m) n with mult m n
  ... | p with plus p n
  ... | q = q
  plus (suc m) n = suc (plus m n)

open import Agda.Builtin.Equality

proof : ∀ m n → mult (suc m) n ≡ plus (mult m n) n
proof m n with mult m n
... | p with plus p n
... | q = refl


{-# OPTIONS --without-K #-}
module sets.finite.level where

open import sum
open import function.isomorphism.core
open import hott.level.core
open import hott.level.closure
open import hott.level.sets
open import sets.finite.core

finite-h2 : ∀ {i}{A : Set i} → IsFinite A → h 2 A
finite-h2 (n , fA) = iso-level (sym≅ fA) (fin-set n)


------------------------------------------------------------------------
-- Order morphisms
------------------------------------------------------------------------

module Relation.Binary.OrderMorphism where

open import Relation.Binary
open Poset
import Data.Function as F

record _⇒-Poset_ (po₁ po₂ : Poset) : Set where
  field
    fun      : carrier po₁ → carrier po₂
    monotone : _≤_ po₁ =[ fun ]⇒ _≤_ po₂

_⇒-DTO_ : (dto₁ dto₂ : DecTotalOrder) → Set
dto₁ ⇒-DTO dto₂ = poset dto₁ ⇒-Poset poset dto₂
  where open DecTotalOrder

open _⇒-Poset_

id : ∀ {po} → po ⇒-Poset po
id = record
  { fun      = F.id
  ; monotone = F.id
  }

_∘_ : ∀ {po₁ po₂ po₃} →
      po₂ ⇒-Poset po₃ → po₁ ⇒-Poset po₂ → po₁ ⇒-Poset po₃
f ∘ g = record
  { fun      = F._∘_ (fun f)      (fun g)
  ; monotone = F._∘_ (monotone f) (monotone g)
  }

const : ∀ {po₁ po₂} → carrier po₂ → po₁ ⇒-Poset po₂
const {po₂ = po₂} x = record
  { fun      = F.const x
  ; monotone = F.const (refl po₂)
  }


{-# OPTIONS --without-K #-}
open import Type using (Type₀; Type₁)
open import Type.Identities
open import Data.Zero using (𝟘)
open import Data.One using (𝟙; 0₁)
open import Data.Two.Base using (𝟚; 0₂; 1₂)
open import Data.Product.NP using (Σ; _×_)
open import Data.Sum.NP using (_⊎_)
open import Data.Nat.Base using (ℕ; zero; suc)
open import Data.Fin using (Fin)
open import Data.Vec using (Vec)
open import HoTT using (ua; UA; module Equivalences)
open import Relation.Binary.PropositionalEquality.NP using (_≡_; !_; _∙_; idp)
open        Equivalences using (_≃_; ≃-!; ≃-refl; _≃-∙_)

module Explore.Universe.Type {X : Type₀} where

infixr 2 _×ᵁ_

data U : Type₁
El : U → Type₀

data U where
  𝟘ᵁ 𝟙ᵁ 𝟚ᵁ : U
  _×ᵁ_ _⊎ᵁ_ : U → U → U
  Σᵁ : (u : U) (f : El u → U) → U
  Xᵁ : U
  ≃ᵁ : (u : U) (A : Type₀) (e : El u ≃ A) → U

El 𝟘ᵁ = 𝟘
El 𝟙ᵁ = 𝟙
El 𝟚ᵁ = 𝟚
El (u₀ ×ᵁ u₁) = El u₀ × El u₁
El (u₀ ⊎ᵁ u₁) = El u₀ ⊎ El u₁
El (Σᵁ u f) = Σ (El u) λ x → El (f x)
El Xᵁ = X
El (≃ᵁ u A e) = A

infix  8 _^ᵁ_
_^ᵁ_ : U → ℕ → U
u ^ᵁ zero  = 𝟙ᵁ
u ^ᵁ suc n = u ×ᵁ u ^ᵁ n

^ᵁ≃Vec : ∀ u n → El (u ^ᵁ n) ≃ Vec (El u) n
^ᵁ≃Vec u zero = ≃-! Vec0≃𝟙
^ᵁ≃Vec u (suc n) = ×≃-second (El u) (^ᵁ≃Vec u n) ≃-∙ ≃-! Vec∘suc≃×

^ᵁ≡Vec : ∀ {{_ : UA}} u n → El (u ^ᵁ n) ≡ Vec (El u) n
^ᵁ≡Vec u n = ua (^ᵁ≃Vec u n)

Finᵁ : ℕ → U
Finᵁ zero    = 𝟘ᵁ
Finᵁ (suc n) = 𝟙ᵁ ⊎ᵁ Finᵁ n

Finᵁ' : ℕ → U
Finᵁ' zero          = 𝟘ᵁ
Finᵁ' (suc zero)    = 𝟙ᵁ
Finᵁ' (suc (suc n)) = 𝟙ᵁ ⊎ᵁ Finᵁ' (suc n)

Finᵁ≃Fin : ∀ n → El (Finᵁ n) ≃ Fin n
Finᵁ≃Fin zero    = ≃-! Fin0≃𝟘
Finᵁ≃Fin (suc n) = ⊎≃ ≃-refl (Finᵁ≃Fin n) ≃-∙ ≃-! Fin∘suc≃𝟙⊎Fin

Finᵁ'≃Fin : ∀ n → El (Finᵁ' n) ≃ Fin n
Finᵁ'≃Fin zero          = ≃-! Fin0≃𝟘
Finᵁ'≃Fin (suc zero)    = ≃-! Fin1≃𝟙
Finᵁ'≃Fin (suc (suc n)) = ⊎≃ ≃-refl (Finᵁ'≃Fin (suc n)) ≃-∙ ≃-! Fin∘suc≃𝟙⊎Fin


{-# OPTIONS --without-K --exact-split --rewriting --overlapping-instances #-}

open import lib.Basics
open import lib.NConnected
open import lib.NType2
open import lib.types.Truncation

open import Coequalizers.Definition
open import Coequalizers.Misc

open import Graphs.Definition

open import Util.Misc

module Groups.Definition where

{- BG has the structure of a type theoretic group if it is pointed, connected and
   1-truncated.
-}
record TTGroup {i : ULevel} (BG : Type i) : Type i where
  field
    base : BG
    ⦃ gp-conn ⦄ : is-connected 0 BG
    ⦃ gp-trunc ⦄ : is-gpd BG

open TTGroup ⦃...⦄ public

{- Some functions related to free higher groups (which we never define explicitly). -}
module _ {i : ULevel} {A : Type i} where
  instance -- Whenever we need a pair of maps A ⇉ 1 they are defined as follows
    gph-fhg : Graph A Unit
    gph-fhg = record { π₀ = λ _ → unit ; π₁ = λ _ → unit }

    conn-fhg : is-connected 0 (⊤ / A)
    conn-fhg = has-level-in ([ c[ unit ] ] , Trunc-elim (λ x → Trunc-rec (λ { (t , p) → ap [_] p}) (quotient-map-is-surj x)))

  fhg-base : ⊤ / A
  fhg-base = c[ unit ]

{- The definition of a free group. -}
FreeGroup : {i : ULevel} (A : Type i) → Type i
FreeGroup A = ∥ ⊤ / A ∥₁

instance -- free groups are groups
  free-gp-str : {i : ULevel} {A : Type i} → TTGroup (FreeGroup A)
  free-gp-str = record { base = [ fhg-base ] }


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

open import HoTT

module homotopy.HSpace where

-- This is just an approximation because
-- not all higher cells are killed.
record HSpaceStructure {i} (A : Type i) : Type i where
  constructor hSpaceStructure
  field
    e : A
    μ : A → A → A
    μ-e-l : (a : A) → μ e a == a
    μ-e-r : (a : A) → μ a e == a
    μ-coh : μ-e-l e == μ-e-r e

module ConnectedHSpace {i} (A : Type i) (c : is-connected 0 A)
  (hA : HSpaceStructure A) where

  open HSpaceStructure hA

  {-
  Given that [A] is 0-connected, to prove that each [μ a] is an equivalence we
  only need to prove that one of them is. But for [a] = [e], [μ a] is the
  identity so we’re done.
  -}

  μ-e-l-is-equiv : (a : A) → is-equiv (λ a' → μ a' a)
  μ-e-l-is-equiv = prop-over-connected {a = e} c
    (λ a → (is-equiv (λ a' → μ a' a) , is-equiv-is-prop (λ a' → μ a' a)))
    (transport! is-equiv (λ= μ-e-r) (idf-is-equiv A))

  μ-e-r-is-equiv : (a : A) → is-equiv (μ a)
  μ-e-r-is-equiv = prop-over-connected {a = e} c
    (λ a → (is-equiv (μ a) , is-equiv-is-prop (μ a)))
    (transport! is-equiv (λ= μ-e-l) (idf-is-equiv A))

  μ-e-l-equiv : A → A ≃ A
  μ-e-l-equiv a = _ , μ-e-l-is-equiv a

  μ-e-r-equiv : A → A ≃ A
  μ-e-r-equiv a = _ , μ-e-r-is-equiv a


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

open import Categories.Category using (Category; module Commutation)
open import Categories.Category.Monoidal.Core using (Monoidal)
open import Categories.Category.Monoidal.Symmetric using (Symmetric)

-- Extra identities that hold only for symmetric monoidal categories.

module Categories.Category.Monoidal.Interchange.Symmetric
  {o ℓ e} {C : Category o ℓ e} {M : Monoidal C} (S : Symmetric M) where

open import Data.Product using (_,_)

import Categories.Category.Construction.Core C as Core
import Categories.Category.Monoidal.Braided.Properties as BraidedProps
open import Categories.Category.Monoidal.Interchange using (HasInterchange)
import Categories.Category.Monoidal.Interchange.Braided as BraidedInterchange
  using (module swapInner; swapInner-braiding)
import Categories.Category.Monoidal.Reasoning M as MonoidalReasoning
import Categories.Category.Monoidal.Utilities M as MonoidalUtilities
open import Categories.Category.Product using (_⁂_; assocˡ)
open import Categories.Functor using (_∘F_)
open import Categories.NaturalTransformation.NaturalIsomorphism
  using (_≃_; niHelper)
open import Categories.Morphism.IsoEquiv C using (to-unique)
open import Categories.Morphism.Reasoning C
  using (elim-center; pushˡ; pullʳ; cancelInner; switch-fromtoˡ)

open Category C using (Obj; _⇒_; _∘_; id; sym-assoc; ∘-resp-≈ʳ; module Equiv)
open Commutation C
open MonoidalReasoning
open MonoidalUtilities using (_⊗ᵢ_)
open Symmetric S renaming (associator to α; braided to B)
open BraidedInterchange B
open Core.Shorthands               -- for idᵢ, _∘ᵢ_, ...
open MonoidalUtilities.Shorthands  -- for λ⇒, ρ⇒, α⇒, ...
open BraidedProps.Shorthands B     -- for σ⇒, ...

private
  variable
    W W₁ W₂ X X₁ X₂ Y Y₁ Y₂ Z Z₁ Z₂ : Obj
    f g h i : X ⇒ Y

private
  i⇒ = swapInner.from
  i⇐ = swapInner.to

swapInner-commutative : [ (X₁ ⊗₀ X₂) ⊗₀ (Y₁ ⊗₀ Y₂) ⇒
                          (X₁ ⊗₀ X₂) ⊗₀ (Y₁ ⊗₀ Y₂) ]⟨
                           i⇒    ⇒⟨ (X₁ ⊗₀ Y₁) ⊗₀ (X₂ ⊗₀ Y₂) ⟩
                           i⇒
                        ≈ id
                        ⟩
swapInner-commutative = begin
    i⇒ ∘ i⇒                                                               ≈⟨ pullʳ (cancelInner α.isoʳ) ⟩
    α⇐ ∘ id ⊗₁ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ id ⊗₁ (α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒  ≈˘⟨ refl⟩∘⟨ pushˡ split₂ˡ ⟩
    α⇐ ∘ id ⊗₁ ((α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒ ∘ σ⇒ ⊗₁ id ∘ α⇐) ∘ α⇒        ≈⟨ refl⟩∘⟨ refl⟩⊗⟨ (∘-resp-≈ʳ sym-assoc ○ α[σ⊗1]α⁻¹.isoʳ) ⟩∘⟨refl ⟩
    α⇐ ∘ id ⊗₁ id ∘ α⇒                                                    ≈⟨ elim-center ⊗.identity ○ α.isoˡ ⟩
    id                                                                     ∎
  where module α[σ⊗1]α⁻¹ = _≅_ (α ∘ᵢ braided-iso ⊗ᵢ idᵢ ∘ᵢ α ⁻¹) using (isoʳ)

swapInner-iso : (W ⊗₀ X) ⊗₀ (Y ⊗₀ Z) ≅ (W ⊗₀ Y) ⊗₀ (X ⊗₀ Z)
swapInner-iso = record
  { from = i⇒
  ; to   = i⇒
  ; iso  = record
    { isoˡ = swapInner-commutative
    ; isoʳ = swapInner-commutative
    }
  }

swapInner-selfInverse : [ (X₁ ⊗₀ X₂) ⊗₀ (Y₁ ⊗₀ Y₂) ⇒
                          (X₁ ⊗₀ Y₁) ⊗₀ (X₂ ⊗₀ Y₂) ]⟨
                          i⇒
                        ≈ i⇐
                        ⟩
swapInner-selfInverse =
  to-unique (iso swapInner-iso) swapInner.iso Equiv.refl

swapInner-braiding′ : [ (W ⊗₀ X) ⊗₀ (Y ⊗₀ Z) ⇒ (Y ⊗₀ W) ⊗₀ (Z ⊗₀ X) ]⟨
                        i⇒         ⇒⟨ (W ⊗₀ Y) ⊗₀ (X ⊗₀ Z) ⟩
                        σ⇒ ⊗₁ σ⇒
                      ≈ σ⇒         ⇒⟨ (Y ⊗₀ Z) ⊗₀ (W ⊗₀ X) ⟩
                        i⇒
                      ⟩
swapInner-braiding′ = switch-fromtoˡ swapInner-iso swapInner-braiding