module Structure.Real where

import      Lvl
open import Data.Boolean
open import Data.Boolean.Proofs
import      Data.Either as Either
open import Functional
open import Logic
open import Logic.Classical
open import Logic.Propositional
open import Logic.Predicate
open import Numeral.Natural using (ℕ)
import      Numeral.Natural.Relation.Order as ℕ
open import Relator.Ordering
open import Structure.Setoid
open import Structure.Function.Ordering
open import Structure.Operator.Field
open import Structure.Operator.Monoid
open import Structure.Operator.Group
open import Structure.Operator.Proofs
open import Structure.Operator.Properties
open import Structure.Relator.Ordering
open        Structure.Relator.Ordering.Weak.Properties
open import Structure.Relator.Properties
open import Structure.OrderedField
import      Structure.OrderedField.AbsoluteValue
open import Syntax.Transitivity
open import Type

private variable ℓ ℓ₁ ℓ₂ ℓₑ : Lvl.Level

-- Theory defining the axioms of ℝ in classical logic.
-- The axioms are the following:
-- • An ordered field.
-- • Monotone convergence.
record RealTheory {R : Type{ℓ₁}} ⦃ equiv-R : Equiv{ℓₑ}(R) ⦄ (_+_ _⋅_ : R → R → R) (_≤_ : R → R → Stmt{ℓ₂}) ⦃ classical : ∀{ℓ}{P : Stmt{ℓ}} → Classical(P) ⦄ : Type{ℓ₁ Lvl.⊔ ℓ₂ Lvl.⊔ ℓₑ} where
  field
    ⦃ orderedField ⦄ : OrderedField(_+_)(_⋅_)(_≤_)

  open OrderedField(orderedField) public
  open Structure.OrderedField.AbsoluteValue(_+_)(_⋅_)(_≤_)

  field
    sup-fn : (f : ℕ → R) → ⦃ Increasing(ℕ._≤_)(_≤_)(f) ⦄ → ⦃ UpperBounded(ℕ._≤_)(_≤_)(f) ⦄ → R
    monotone-convergence : ∀{f} → ⦃ inc : Increasing(ℕ._≤_)(_≤_)(f) ⦄ → ⦃ bound : UpperBounded(ℕ._≤_)(_≤_)(f) ⦄ → ∃{Obj = R → ℕ}(N ↦ ∀{ε} → (ε > 𝟎) → ∀{n} → (n ℕ.> N(ε)) → (‖ f(n) − sup-fn (f) ⦃ inc ⦄ ⦃ bound ⦄ ‖ < ε))

  -- TODO: Consider adding something that relates addition and multiplication so that it conform to the axioms of arithmetic and their definitions of addition and multiplication. This is so that one should be able to prove (x + x ≡ 𝐒(𝐒(𝟎)) ⋅ x) or (2.5 ⋅ x = x + x + x/2) (when 𝐒, the successor function is defined as (1 +_)) for easier to write statements. In other words: add ((1 + x) ⋅ y = x + (x ⋅ y)) as an axiom. (20201210 Is this TODO outdated?)


{-# OPTIONS --without-K --safe #-}
module Categories.Functor.Instance.Discrete where

-- Discrete Functor
--   from Sets to Cats. This works, unlike in the previous version of the library,
--   because the equality in Cats is properly NaturalIsomorphism instead of something stricter,
--   no need for that pesky Heterogeneous anything.

open import Categories.Category
open import Categories.Functor
open import Categories.Category.Instance.Sets
open import Categories.Category.Instance.Cats
open import Categories.NaturalTransformation using (ntHelper)
open import Categories.NaturalTransformation.NaturalIsomorphism
import Categories.Category.Discrete as D

import Relation.Binary.PropositionalEquality as ≡
open import Function renaming (id to idf; _∘_ to _●_)

Discrete : ∀ {o} → Functor (Sets o) (Cats o o o)
Discrete {o} = record
   { F₀ = D.Discrete
   ; F₁ = DiscreteFunctor
   ; identity = DiscreteId
   ; homomorphism = PointwiseHom
   ; F-resp-≈ = ExtensionalityNI
   }
   where
     DiscreteFunctor : {A B : Set o} → (A → B) → Cats o o o [ D.Discrete A , D.Discrete B ]
     DiscreteFunctor f = record
       { F₀ = f
       ; F₁ = ≡.cong f
       ; identity = ≡.refl
       ; homomorphism = λ { {_} {_} {_} {≡.refl} {≡.refl} → ≡.refl}
       ; F-resp-≈ = λ g≡h → ≡.cong (≡.cong f) g≡h -- marvel at the weirdness involved
       }
     DiscreteId : {A : Set o} → NaturalIsomorphism (DiscreteFunctor {A} idf) id
     DiscreteId = record
       { F⇒G = record { η = λ X → ≡.refl ; commute = λ { ≡.refl → ≡.refl } ; sym-commute = λ { ≡.refl → ≡.refl} }
       ; F⇐G = record { η = λ _ → ≡.refl ; commute = λ { ≡.refl → ≡.refl } ; sym-commute = λ { ≡.refl → ≡.refl} }
       ; iso = λ X → record { isoˡ = ≡.refl ; isoʳ = ≡.refl }
       }
     PointwiseHom : {X Y Z : Set o} {g : X → Y} {h : Y → Z} →
       NaturalIsomorphism (DiscreteFunctor (h ● g)) (DiscreteFunctor h ∘F DiscreteFunctor g)
     PointwiseHom = record
       { F⇒G = record { η = λ _ → ≡.refl ; commute = λ { ≡.refl → ≡.refl} ; sym-commute = λ { ≡.refl → ≡.refl} }
       ; F⇐G = record { η = λ _ → ≡.refl ; commute = λ { ≡.refl → ≡.refl} ; sym-commute = λ { ≡.refl → ≡.refl} }
       ; iso = λ X → record { isoˡ = ≡.refl ; isoʳ = ≡.refl }
       }
     ExtensionalityNI : {A B : Set o} {g h : A → B} →
      ({x : A} → g x ≡.≡ h x) → NaturalIsomorphism (DiscreteFunctor g) (DiscreteFunctor h)
     ExtensionalityNI g≡h = record
       { F⇒G = ntHelper record { η = λ X → g≡h {X} ; commute = λ { ≡.refl → ≡.sym (≡.trans-reflʳ g≡h)} }
       ; F⇐G = ntHelper record { η = λ X → ≡.sym (g≡h {X}) ; commute = λ { ≡.refl → ≡.sym (≡.trans-reflʳ _)} }
       ; iso = λ X → record { isoˡ = ≡.trans-symʳ g≡h ; isoʳ = ≡.trans-symˡ g≡h }
       }


module Structure.Relator.Equivalence where

import      Lvl
open import Logic
open import Logic.Propositional
open import Structure.Relator.Properties
  hiding (reflexivity ; symmetry ; transitivity)
open import Type

private variable ℓ₁ ℓ₂ : Lvl.Level

-- An equivalence relation is a reflexive, symmetric and transitive relation.
record Equivalence {T : Type{ℓ₁}} (_≡_ : T → T → Stmt{ℓ₂}) : Stmt{ℓ₁ Lvl.⊔ ℓ₂} where
  instance constructor intro
  field
    instance ⦃ reflexivity ⦄  : Reflexivity  (_≡_)
    instance ⦃ symmetry ⦄     : Symmetry     (_≡_)
    instance ⦃ transitivity ⦄ : Transitivity (_≡_)


module Tuple where

import Level
import Data.List as List
open import Data.List hiding (_++_; [_]; _∷ʳ_)
open import Data.Fin

open import Relation.Binary.PropositionalEquality hiding ([_])

infixr 5 _∷_

data Tuple {a} : List (Set a) → Set a where
  [] : Tuple []
  _∷_ : ∀ {A As} → A → Tuple As → Tuple (A ∷ As)

[_] : ∀ {a} {A : Set a} → A → Tuple (A ∷ [])
[ x ] = x ∷ []

_++_ : ∀ {a} {xs ys : List (Set a)}
     → Tuple xs → Tuple ys → Tuple (xs List.++ ys)
_++_ {xs = []} [] ys = ys
_++_ {xs = _ ∷ _} (x ∷ xs) ys = x ∷ (xs ++ ys)

_∷ʳ_ : ∀ {a} {x : Set a} {xs : List (Set a)}
     → Tuple xs → x → Tuple (xs List.∷ʳ x)
_∷ʳ_ xs x = xs ++ [ x ]

private
  listLookup : ∀ {a} {A : Set a} (xs : List A) → (n : Fin (length xs)) → A
  listLookup [] ()
  listLookup (x ∷ xs) zero = x
  listLookup (x ∷ xs) (suc n) = listLookup xs n

lookup : ∀ {a} {xs : List (Set a)}
       → (n : Fin (length xs)) → Tuple xs → listLookup xs n
lookup {xs = []} () []
lookup {xs = _ ∷ _} zero (x ∷ xs) = x
lookup {xs = _ ∷ _} (suc n) (x ∷ xs) = lookup n xs

unfoldToFunc : ∀ {a} → List (Set a) → Set a → Set a
unfoldToFunc [] B = B
unfoldToFunc (A ∷ As) B = A → unfoldToFunc As B

apply : {Xs : List Set} {A : Set} → unfoldToFunc Xs A → Tuple Xs → A
apply {[]} f [] = f
apply {_ ∷ _} f (x ∷ xs) = apply (f x) xs

list-proof : ∀ {a} {A : Set a} (xs : List A) → xs ≡ (xs List.++ [])
list-proof [] = refl
list-proof (x ∷ xs) = cong (_∷_ x) (list-proof xs)

list-proof₁ : ∀ {a} {A : Set a} (xs ys zs : List A)
            → (xs List.++ ys) List.++ zs ≡ xs List.++ (ys List.++ zs)
list-proof₁ [] ys zs = refl
list-proof₁ (x ∷ xs) ys zs = cong (_∷_ x) (list-proof₁ xs ys zs)

curry : ∀ {a} (xs : List (Set a)) → unfoldToFunc xs (Tuple xs)
curry xs = curry' [] xs []
  where curry' : ∀ {a} (xs ys : List (Set a)) → Tuple xs
               → unfoldToFunc ys (Tuple (xs List.++ ys))
        curry' xs [] tpl = subst Tuple (list-proof xs) tpl
        curry' xs (y ∷ ys) tpl x₁ =
          subst (λ x → unfoldToFunc ys (Tuple x))
                (list-proof₁ xs List.[ y ] ys)
                (curry' (xs List.∷ʳ y) ys (tpl ∷ʳ x₁))

proof₁ : ∀ {a} (As : List (Set a)) {B : Set a}
       → (Tuple As → B) → unfoldToFunc As B
proof₁ [] f = f []
proof₁ (A ∷ As) f x = proof₁ As (λ xs → f (x ∷ xs))

proof₂ : ∀ {a} (As : List (Set a)) {B : Set a}
       → unfoldToFunc As B → Tuple As → B
proof₂ [] f [] = f
proof₂ (A ∷ As) f (x ∷ xs) = proof₂ As (f x) xs


module Numeral.Natural.Prime.Proofs.Product where

import      Lvl
open import Data.Either as Either using ()
open import Functional
open import Lang.Instance
open import Logic.Propositional
open import Numeral.Natural
open import Numeral.Natural.Relation.Divisibility.Proofs
open import Numeral.Natural.Oper
open import Numeral.Natural.Prime
open import Numeral.Natural.Relation.Divisibility.Proofs.Product
open import Sets.PredicateSet renaming (_≡_ to _≡ₛ_)
open import Type

private variable a b : ℕ

-- The prime factors of a product is the prime factors of its factors.
product-primeFactors : PrimeFactor(a ⋅ b) ≡ₛ (PrimeFactor(a) ∪ PrimeFactor(b))
product-primeFactors = [↔]-intro l r where
  l : PrimeFactor(a ⋅ b) ⊇ (PrimeFactor(a) ∪ PrimeFactor(b))
  l{a}{b}{x} (Either.Left  intro) = intro ⦃ factor = divides-with-[⋅] {x}{a}{b} ([∨]-introₗ infer) ⦄
  l{a}{b}{x} (Either.Right intro) = intro ⦃ factor = divides-with-[⋅] {x}{a}{b} ([∨]-introᵣ infer) ⦄

  r : PrimeFactor(a ⋅ b) ⊆ (PrimeFactor(a) ∪ PrimeFactor(b))
  r{a}{b}{x} intro = Either.map (p ↦ intro ⦃ factor = p ⦄) (p ↦ intro ⦃ factor = p ⦄) (prime-divides-of-[⋅] {x}{a}{b} infer infer)


module RecursiveInstanceSearch where

open import Common.Prelude
open import Common.Product

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

record Eq (A : Set) : Set where
  constructor eq
  field
    _==_ : A → A → Bool
open Eq {{...}} public

instance
  eq-Bool : Eq Bool
  eq-Bool = eq aux  where

    aux : Bool → Bool → Bool
    aux true true = true
    aux false false = true
    aux _ _ = false

  eq-Nat : Eq Nat
  eq-Nat = eq aux  where

    aux : Nat → Nat → Bool
    aux zero zero = true
    aux (suc n) (suc m) = aux n m
    aux _ _ = false

  eq-Maybe : {A : Set} {{_ : Eq A}} → Eq (Maybe A)
  eq-Maybe {A} = eq aux  where

    aux : Maybe A → Maybe A → Bool
    aux nothing nothing = true
    aux (just y) (just z) = (y == z)
    aux _ _ = false

  eq-List : {A : Set} {{_ : Eq A}} → Eq (List A)
  eq-List {A} = eq aux  where

    aux : List A → List A → Bool
    aux [] [] = true
    aux (x ∷ l) (y ∷ l') = (x == y) && (aux l l')
    aux _ _ = false

  eq-× : {A B : Set} {{_ : Eq A}} {{_ : Eq B}} → Eq (A × B)
  eq-× {A} {B} = eq (λ x y → (proj₁ x == proj₁ y) && (proj₂ x == proj₂ y))

test₂ : Bool
test₂ = (3 == 4)

test₃ : Bool
test₃ = ((just 9) == nothing)

test₃' : Bool
test₃' = (nothing == just 6)

test₄ : Bool
test₄ = (true ∷ []) == (false ∷ [])

test₅ : Bool
test₅ = (just ((true ,′ (1 ,′ just 0)) ∷ []) == just ((true , (1 , just 0)) ∷ []))


-- Testing parameterised records in parameterised modules
module Exist (X : Set) where

data [_] (a : Set) : Set where
  []  : [ a ]
  _∷_ : a -> [ a ] -> [ a ]

map : forall {a b} -> (a -> b) -> [ a ] -> [ b ]
map f []       = []
map f (x ∷ xs) = f x ∷ map f xs

record ∃ (a : Set) (P : a -> Set) : Set where
  field
    witness : a
    proof   : P witness

ListP : (a : Set) -> (a -> Set) -> Set
ListP a P = [ ∃ a P ]

mapP : forall {a b P Q}
  -> (f : a -> b) -> (forall {x} -> P x -> Q (f x))
  -> ListP a P -> ListP b Q
mapP {a} {b} {P} {Q} f pres xs = map helper xs
  where
  helper : ∃ a P -> ∃ b Q
  helper r = record { witness = f (∃.witness r)
                    ; proof   = pres (∃.proof r)
                    }


module trees where

  data Tree (A : Set) : Set where
    empty : Tree A
    node : Tree A -> A -> Tree A -> Tree A

  open import Data.Nat

  #nodes : {A : Set} -> Tree A -> ℕ
  #nodes empty = 0
  #nodes (node t x t₁) = (#nodes t) + (1 + (#nodes t₁))

  #leafs : {A : Set} -> Tree A -> ℕ
  #leafs empty = zero
  -- #leafs (node empty x empty) = 1
  #leafs (node t x t₁) with t | t₁
  ...                     | empty | empty = 1
  ...                     | _     | _ = (#leafs t) + (#leafs t₁)


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

open import Categories.Category

module Categories.Category.Cocomplete.Properties {o ℓ e} (C : Category o ℓ e) where

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

open import Categories.Adjoint.Properties
open import Categories.Category.Complete
open import Categories.Category.Complete.Properties
open import Categories.Category.Cocomplete
open import Categories.Category.Cocomplete.Finitely
open import Categories.Category.Duality
open import Categories.Category.Construction.Functors
open import Categories.Functor
open import Categories.Functor.Cocontinuous
open import Categories.Functor.Duality
open import Categories.NaturalTransformation as N
open import Categories.NaturalTransformation.NaturalIsomorphism using (_≃_)
open import Categories.Diagram.Limit
open import Categories.Diagram.Limit.Properties
open import Categories.Diagram.Colimit
open import Categories.Diagram.Duality

import Categories.Morphism.Reasoning as MR

private
  variable
    o′ ℓ′ e′ o″ ℓ″ e″ : Level
  module C = Category C

Cocomplete⇒FinitelyCocomplete : Cocomplete o′ ℓ′ e′ C → FinitelyCocomplete C
Cocomplete⇒FinitelyCocomplete Coc =
  coFinitelyComplete⇒FinitelyCocomplete C (Complete⇒FinitelyComplete C.op (Cocomplete⇒coComplete C Coc))

module _ {D : Category o′ ℓ′ e′} (Coc : Cocomplete o″ ℓ″ e″ D) where
  private
    module D = Category D

  Functors-Cocomplete : Cocomplete o″ ℓ″ e″ (Functors C D)
  Functors-Cocomplete {J} F = coLimit⇒Colimit (Functors C D) LFop
    where module J = Category J
          module F = Functor F
          open Functor F
          F′ : Functor J.op (Functors C.op D.op)
          F′ = opF⇒ ∘F F.op

          L : (H : Functor J.op (Functors C.op D.op)) → Limit H
          L = Functors-Complete C.op {D = D.op} (λ G → Colimit⇒coLimit D (Coc (Functor.op G)))

          LF′ : Limit F′
          LF′ = L F′

          LF″ : Limit (opF⇐ ∘F F′)
          LF″ = rapl (Functorsᵒᵖ-equiv.L⊣R C.op D.op) F′ LF′

          iso : opF⇐ ∘F F′ ≃ F.op
          iso = record
            { F⇒G = ntHelper record
              { η       = λ _ → N.id
              ; commute = λ f → id-comm
              }
            ; F⇐G = ntHelper record
              { η       = λ _ → N.id
              ; commute = λ f → id-comm
              }
            ; iso = λ j → record
              { isoˡ = D.identity²
              ; isoʳ = D.identity²
              }
            }
            where open MR D

          LFop : Limit op
          LFop = ≃-resp-lim iso LF″

  -- TODO: need to refactor the where block above to show cocontinuous. there is no need to do it now.
  --
  -- evalF-Cocontinuous : ∀ X → Cocontinuous o″ ℓ″ e″ (evalF C D X)
  -- evalF-Cocontinuous X {J} {F} L = Coc (evalF C D X ∘F F) , {!!}
  --   where


module Data.Boolean.Numeral where

open import Data
open import Data.Boolean
open import Data.Boolean.Stmt
import      Lvl
open import Numeral.Natural
open import Numeral.Natural.Oper.Comparisons
open import Syntax.Number
open import Type

Bool-to-ℕ : Bool → ℕ
Bool-to-ℕ 𝐹 = 0
Bool-to-ℕ 𝑇 = 1

ℕ-to-Bool : (n : ℕ) → . ⦃ _ : IsTrue(n <? 2) ⦄ → Bool
ℕ-to-Bool 0 = 𝐹
ℕ-to-Bool 1 = 𝑇

instance
  Bool-from-ℕ : Numeral(Bool)
  Numeral.restriction-ℓ Bool-from-ℕ     = Lvl.𝟎
  Numeral.restriction   Bool-from-ℕ   n = IsTrue(n <? 2)
  num                 ⦃ Bool-from-ℕ ⦄ n = ℕ-to-Bool n


{- This file describes properties of computable relations. -}

open import bool
open import level
open import eq
open import product
open import product-thms

module bool-relations {ℓ : level}{A : Set ℓ} (_≤A_ : A → A → 𝔹) where

reflexive : Set (ℓ)
reflexive = ∀ {a : A} → a ≤A a ≡ tt

transitive : Set (ℓ)
transitive = ∀ {a b c : A} → a ≤A b ≡ tt → b ≤A c ≡ tt → a ≤A c ≡ tt

total : Set ℓ
total = ∀ {a b : A} → a ≤A b ≡ ff → b ≤A a ≡ tt

total-reflexive : total → reflexive
total-reflexive tot {a} with keep (a ≤A a)
total-reflexive tot {a} | tt , p = p
total-reflexive tot {a} | ff , p = tot p

_iso𝔹_ : A → A → 𝔹
d iso𝔹 d' = d ≤A d' && d' ≤A d

iso𝔹-intro : ∀{x y : A} → x ≤A y ≡ tt → y ≤A x ≡ tt → x iso𝔹 y ≡ tt
iso𝔹-intro p1 p2 rewrite p1 | p2 = refl


module Ag12 where

import Relation.Binary.PropositionalEquality as Eq
open Eq
open import Data.Nat using (ℕ; zero; suc; _+_; _*_)
open import Relation.Nullary using (¬_)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Function
open import Ag09 hiding (_∘_)
-- open import Data.Product using (Σ; _,_; ∃; Σ-syntax; ∃-syntax)
open import Level using (Level; _⊔_) renaming (zero to lzero; suc to lsuc)
open ≡-Reasoning
open ≃-Reasoning

postulate
  funExt : ∀ {m n : Level} {A : Set m} {B : Set n} {f g : A → B}
           → (∀ (x : A) → f x ≡ g x)
           → f ≡ g

lemma₀ : ∀ {A B : Set} → (a : A × B) → ⟨ proj₁ a , proj₂ a ⟩ ≡ a
lemma₀ ⟨ fst , snd ⟩ = refl

lemma₁ : ∀ {A : Set} {B C : A → Set}
         → (f : (x : A) → B x × C x)
         → (λ a → ⟨ proj₁ (f a) , proj₂ (f a) ⟩) ≡ f
lemma₁ f = refl

∀-distrib-× : ∀ {A : Set} {B C : A → Set} →
  (∀ (x : A) → B x × C x) ≃ (∀ (x : A) → B x) × (∀ (x : A) → C x)
∀-distrib-× {A} {B} {C} =
  record
  { to      = λ bc → ⟨ proj₁ ∘ bc , proj₂ ∘ bc ⟩
  ; from    = λ bc a → ⟨ proj₁ bc a , proj₂ bc a ⟩
  ; from∘to = λ f → refl
  ; to∘from = λ f → refl
  }
⊎∀-implies-∀⊎ : ∀ {A : Set} {B C : A → Set} →
  (∀ (x : A) → B x) ⊎ (∀ (x : A) → C x)  →  ∀ (x : A) → B x ⊎ C x
⊎∀-implies-∀⊎ (_⊎_.inj₁ x₁) x = _⊎_.inj₁ (x₁ x)
⊎∀-implies-∀⊎ (_⊎_.inj₂ y) x = _⊎_.inj₂ (y x)

data Σ (A : Set) (B : A → Set) : Set where
  ⟨_,_⟩ : (x : A) → B x → Σ A B

Σ-syntax = Σ
infix 2 Σ-syntax
syntax Σ-syntax A (λ x → B) = Σ[ x ∈ A ] B

∃ : ∀ {A : Set} (B : A → Set) → Set
∃ {A} B = Σ A B

∃-syntax = ∃
syntax ∃-syntax (λ x → B) = ∃[ x ] B

∃-distrib-⊎ : ∀ {A : Set} {B C : A → Set} →
  ∃[ x ] (B x ⊎ C x) ≃ (∃[ x ] B x) ⊎ (∃[ x ] C x)
∃-distrib-⊎ =
  record
  { to = λ x → {!!}
  ; from = λ{ (inj₁ x) → ⟨ {!!} , {!!} ⟩ ; (inj₂ x) → {!!} }
  ; from∘to = {!!}
  ; to∘from = {!!}
  }


------------------------------------------------------------------------------
-- Totality properties for Forest
------------------------------------------------------------------------------

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

module FOTC.Program.Mirror.Forest.TotalityI where

open import FOTC.Base
open import FOTC.Data.List
open import FOTC.Program.Mirror.Type

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

++-Forest : ∀ {xs ys} → Forest xs → Forest ys → Forest (xs ++ ys)
++-Forest {ys = ys} fnil Fys = subst Forest (sym (++-[] ys)) Fys
++-Forest {ys = ys} (fcons {x} {xs} Tx Fxs) Fys =
  subst Forest (sym (++-∷ x xs ys)) (fcons Tx (++-Forest Fxs Fys))

map-Forest : ∀ {xs} f → (∀ {x} → Tree x → Tree (f · x)) →
             Forest xs → Forest (map f xs)
map-Forest f fTree fnil = subst Forest (sym (map-[] f)) fnil
map-Forest f fTree (fcons {x} {xs} Tx Fxs) =
  subst Forest
        (sym (map-∷ f x xs))
        (fcons (fTree Tx) (map-Forest f fTree Fxs))

rev-Forest : ∀ {xs ys} → Forest xs → Forest ys → Forest (rev xs ys)
rev-Forest {ys = ys} fnil Fys = subst Forest (sym (rev-[] ys)) Fys
rev-Forest {ys = ys} (fcons {x} {xs} Tx Fxs) Fys =
  subst Forest (sym (rev-∷ x xs ys)) (rev-Forest Fxs (fcons Tx Fys))

reverse-Forest : ∀ {xs} → Forest xs → Forest (reverse xs)
reverse-Forest Fxs = rev-Forest Fxs fnil


------------------------------------------------------------------------------
-- In the Agda standard library, gcd 0 0 = 0.
------------------------------------------------------------------------------

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

module FOT.FOTC.Program.GCD.GCD00-SL where

open import Data.Nat.GCD
open import Data.Product
open import Relation.Binary.PropositionalEquality

open GCD hiding ( refl )

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

gcd00 : proj₁ (gcd 0 0) ≡ 0
gcd00 = refl

-- A different proof.
gcd00' : GCD 0 0 0
gcd00' = base


--
-- Created by Dependently-Typed Lambda Calculus on 2020-09-24
-- Equal
-- Author: dplaindoux
--

module Equal where

open import Data.Nat using (ℕ; zero; suc)
open import Data.Bool using (Bool; true; false)

infix 30 _=?_

data Type : Set where
    nat  : Type

▲_ : Type → Set
▲ nat  = ℕ

_=?_ : { a : Type } → ▲ a → ▲ a → Bool

_=?_ {nat} zero zero       = true
_=?_ {nat} (suc m) (suc n) = m =? n
_=?_ {nat} _ _             = false

Nat :
  ∀self(P : Nat → Set) →
  ∀(zero : P(λz. λs. z)) →
  ∀(succ : ∀(n : Nat) → P (λz. λs. s n)) →
  P self


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

open import Categories.Category

module Categories.Category.Complete.Finitely {o ℓ e} (C : Category o ℓ e) where

open import Level

open import Categories.Category.Cartesian C
open import Categories.Diagram.Equalizer C
open import Categories.Diagram.Pullback C

open Category C

record FinitelyComplete : Set (levelOfTerm C) where
  field
    cartesian : Cartesian
    equalizer : ∀ {A B} (f g : A ⇒ B) → Equalizer f g

  module cartesian = Cartesian cartesian
  module equalizer {A B} (f g : A ⇒ B) = Equalizer (equalizer f g)
  open cartesian public

  pullback : ∀ {X Y Z} (f : X ⇒ Z) (g : Y ⇒ Z) → Pullback f g
  pullback f g = Product×Equalizer⇒Pullback product (equalizer _ _)

  module pullback {X Y Z} (f : X ⇒ Z) (g : Y ⇒ Z) = Pullback (pullback f g)


{-
This second-order equational theory was created from the following second-order syntax description:

syntax Inception | IA

type
  L : 0-ary
  P : 0-ary
  A : 0-ary

term
  rec : L  P  ->  A
  inc : L.A  P.A  ->  A

theory
  (S) p : P   a : P.A |> inc (l. rec (l, p[]), x. a[x]) = a[p[]]
  (E) a : L.A  |> k : L |- inc (l. a[l], x. rec(k, x)) = a[k]
  (W) m : A  a : P.A  |> inc (l. m[], x. a[x]) = m[]
  (A) p : (L,L).A  a : (L,P).A  b : P.A |>         inc (l. inc (k. p[l, k], x. a[l,x]), y. b[y])       = inc (k. inc(l. p[l,k], y.b[y]), x. inc(l. a[l,x], y.b[y]))
-}

module Inception.Equality where

open import SOAS.Common
open import SOAS.Context
open import SOAS.Variable
open import SOAS.Families.Core
open import SOAS.Families.Build
open import SOAS.ContextMaps.Inductive

open import Inception.Signature
open import Inception.Syntax

open import SOAS.Metatheory.SecondOrder.Metasubstitution IA:Syn
open import SOAS.Metatheory.SecondOrder.Equality IA:Syn

private
  variable
    α β γ τ : IAT
    Γ Δ Π : Ctx

infix 1 _▹_⊢_≋ₐ_

-- Axioms of equality
data _▹_⊢_≋ₐ_ : ∀ 𝔐 Γ {α} → (𝔐 ▷ IA) α Γ → (𝔐 ▷ IA) α Γ → Set where
  S : ⁅ P ⁆ ⁅ P ⊩ A ⁆̣ ▹   ∅   ⊢  inc (rec x₀ 𝔞) (𝔟⟨ x₀ ⟩) ≋ₐ 𝔟⟨ 𝔞 ⟩
  E : ⁅ L ⊩ A ⁆̣       ▹ ⌊ L ⌋ ⊢ inc (𝔞⟨ x₀ ⟩) (rec x₁ x₀) ≋ₐ 𝔞⟨ x₀ ⟩
  W : ⁅ A ⁆ ⁅ P ⊩ A ⁆̣ ▹   ∅   ⊢           inc 𝔞 (𝔟⟨ x₀ ⟩) ≋ₐ 𝔞
  A : ⁅ L · L ⊩ A ⁆ ⁅ L · P ⊩ A ⁆ ⁅ P ⊩ A ⁆̣ ▹ ∅
    ⊢ inc (inc (𝔞⟨ x₁ ◂ x₀ ⟩) (𝔟⟨ x₁ ◂ x₀ ⟩)) (𝔠⟨ x₀ ⟩)
   ≋ₐ inc (inc (𝔞⟨ x₀ ◂ x₁ ⟩) (𝔠⟨ x₀ ⟩)) (inc (𝔟⟨ x₀ ◂ x₁ ⟩) (𝔠⟨ x₀ ⟩))

open EqLogic _▹_⊢_≋ₐ_
open ≋-Reasoning


module Sort where
  open import Sec4
  import Sec2
  postulate _≤_ : {A : Set} →  A → A → Prop
  postulate tot-list : {A : Set} → (a b : A) → (a ≤ b) ∨ (b ≤ a)
  postulate trans-list :  {A : Set} → (a b c : A) → (a ≤ b) → (b ≤ c) → (a ≤ c)

-- XXX: Definition of a list
  data List (A : Set) : Set where
    Nil : List A
    _∷_ : A → List A → List A

-- XXX: definition of an ordered list
  all-ordered-list : {A : Set} → (a : A)
                     → (l : List A)
                     → Prop
  all-ordered-list a Nil = ⊤
  all-ordered-list a (x ∷ l) = (a ≤ x) ∧ all-ordered-list a l

  ordered-list : {A : Set} → List A → Prop
  ordered-list Nil = ⊤
  ordered-list (x ∷ l) = all-ordered-list x l ∧ (ordered-list l)

-- XXX: Inserting elements in the list
  insert-list : {A : Set} → (a : A) → (l : List A) → List A
  insert-list a Nil = a ∷ Nil
  insert-list a (x ∷ l) with (tot-list a x)
  insert-list a (x ∷ l) | ora h = a ∷ (x ∷ l)
  insert-list a (x ∷ l) | orb h = x ∷ (insert-list a l)

  lem1 : {A : Set}
         → (a x : A)
         → (l : List A)
         → (p : all-ordered-list x l)
         → (p1 : a ≤ x)
         → (all-ordered-list a l)
  lem1 a x Nil p p1 = ⋆
  lem1 a x (x₁ ∷ l) (and x₂ x₃) p1 = and (trans-list a x x₁ p1 x₂) (lem1 a x l x₃ p1)

  lem2 : {A : Set} → (x a : A) → (l : List A) → (h : x ≤ a)
         → (p1 : all-ordered-list x l) → (p2 : ordered-list l)
         → (v : ordered-list (insert-list a l))
         → all-ordered-list x (insert-list a l)
  lem2 x a Nil h p1 p3 v = and h ⋆
  lem2 x a (x₁ ∷ l) h p1 p3 v with (tot-list a x₁)
  lem2 x₂ a (x₁ ∷ l) h p1 p3 v | ora x = and h p1
  lem2 x₂ a (x₁ ∷ l) h (and x₃ x₄) (and x₅ x₆) (and x₇ x₈) | orb x = and x₃ (lem2 x₂ a l h x₄ x₆ x₈)

  thm2 : {A : Set}
         → ∀ (a : A)
         → ∀ (l : List A)
         → (p : ordered-list l)
         → (ordered-list (insert-list a l))
  thm2 a Nil p = and ⋆ ⋆
  thm2 a (x ∷ l) p with (tot-list a x)
  thm2 a (x ∷ l) (and x₁ x₂) | ora h = and (and h (lem1 a x l x₁ h)) (and x₁ x₂)
  thm2 a (x ∷ l) (and x₁ x₂) | orb h =
                                   let v = (thm2 a l x₂)
                                   in
                                   and (lem2 x a l h x₁ x₂ v) v

-- XXX: append lists
  _++_ : {A : Set} → (l : List A) → (m : List A) → List A
  Nil ++ m = m
  (x ∷ l) ++ m = x ∷ (l ++ m)

-- XXX: Length of a list
  length : {A : Set} → (l : List A) → Sec2.ℕ
  length Nil = Sec2.Z
  length (x ∷ l) = Sec2.S (length l)

-- XXX: reverse of a list
  rev : {A : Set} → (List A) → (List A)
  rev Nil = Nil
  rev (x ∷ l) = (rev l) ++ (x ∷ Nil)

-- XXX: Theorem on length of lists
  thm : {A : Set} → (l : List A) → (m : List A) → ((length l) Sec2.+ (length m) Sec2.≡ length (l ++ m))
  thm Nil m = Sec2.refl
  thm (x ∷ l) m =
                let
                  xx = thm l m
                in
                Sec2.cong xx

  cong : {A : Set} → (x : A) → (l m : List A) → (l Sec2.≡ m)
         → (x ∷ l) Sec2.≡ (x ∷ m)
  cong x l .l Sec2.refl = Sec2.refl

  cong2 : {A : Set} → (l m q : List A) → (l Sec2.≡ m)
          → (l ++ q) Sec2.≡ (m ++ q)
  cong2 l .l q Sec2.refl = Sec2.refl

  ++-lem : {A : Set} → (l : List A) → ((l ++ Nil) Sec2.≡ l)
  ++-lem Nil = Sec2.refl
  ++-lem (x ∷ l) = cong x (l ++ Nil) l (++-lem l)

  assoc : {A : Set} → (l m q : List A)
          → l ++ (m ++ q) Sec2.≡ (l ++ m) ++ q
  assoc Nil m q = Sec2.refl
  assoc (x ∷ l) m q = cong x (l ++ (m ++ q)) ((l ++ m) ++ q) (assoc l m q)

  rev-lem : {A : Set} → ∀ (l m : List A)
            → rev (l ++ m) Sec2.≡ (rev m) ++ (rev l)
  rev-lem Nil m rewrite
                ++-lem (rev m) = Sec2.refl
  rev-lem (x ∷ l) m rewrite
                    assoc (rev m) (rev l) (x ∷ Nil)
                    = let p = rev-lem l m in
                      cong2 (rev (l ++ m)) (rev m ++ rev l) (x ∷ Nil) p

-- XXX: Involution of reversal of lists
  rev-involute : {A : Set} → (l : List A) → l Sec2.≡ (rev (rev l))
  rev-involute Nil = Sec2.refl
  rev-involute (x ∷ l) rewrite
                       rev-lem (rev l) (x ∷ Nil)
                       = cong x l (rev (rev l)) (rev-involute l)


module Forcing4 where

open import Common.Nat renaming (zero to Z; suc to S)
open import Lib.Fin
open import Common.Equality
open import Common.String
open import Common.IO
open import Common.Unit

{-
toNat : {n : Nat} → Fin n → Nat
toNat (zero _)    = 0
toNat (suc _ i) = suc (toNat i)
-}

Rel : (X : Set) -> Set1
Rel X = X -> X -> Set

data _<=_ : Rel Nat where
  z<=n : ∀ n                 → Z  <= n
  s<=s : ∀ m n (m<=n : m <= n) → S m <= S n

_ℕ<_ : Rel Nat
m ℕ< n = S m <= n

fromℕ≤ : ∀ {m n} → m ℕ< n → Fin n
fromℕ≤ (s<=s .0 n (z<=n .n)) = fz {n}
fromℕ≤ (s<=s .(S m) .(S n) (s<=s m n m<=n)) = fs {S n} (fromℕ≤ (s<=s m n m<=n))

fromℕ≤-toℕ : ∀ m (i : Fin m) (i<m : forget i ℕ< m) → fromℕ≤ i<m ≡ i
fromℕ≤-toℕ .(S n) (fz {n}) (s<=s .0 .n (z<=n .n)) = refl
fromℕ≤-toℕ .(S (S n)) (fs .{S n} y) (s<=s .(S (forget y)) .(S n) (s<=s .(forget y) n m≤n)) = cong (\ n -> fs n) (fromℕ≤-toℕ (S n) y (s<=s (forget y) n m≤n))

[_/2] : Nat -> Nat
[ 0 /2] = 0
[ 1 /2] = 0
[ S (S n) /2] = S [ n /2]

[1/2]-mono : (m n : Nat) -> m <= n -> [ m /2] <= [ n /2]
[1/2]-mono .0 .n (z<=n n) = z<=n [ n /2]
[1/2]-mono .1 .(S n) (s<=s .0 .n (z<=n n)) = z<=n [ S n /2]
[1/2]-mono .(S (S m)) .(S (S n)) (s<=s .(S m) .(S n) (s<=s m n m<=n)) = s<=s [ m /2] [ n /2] ([1/2]-mono m n m<=n)

showEq : {X : Set}{A : X}  -> A ≡ A -> String
showEq refl = "refl"

show<= : {m n : Nat} -> m <= n -> String
show<= (z<=n n) = "0 <= " +S+ natToString n
show<= (s<=s m n m<=n) = natToString (S m) +S+ " <= " +S+ natToString (S n)

data Bot : Set where
-- Only to check that it compiles..
foo : (n : Nat) -> S n <= n -> Bot
foo .(S n) (s<=s .(S n) n le) = foo n le

main : IO Unit
main = putStrLn (showEq (fromℕ≤-toℕ 3 (inc (inject 1)) le)) ,,
       putStrLn (show<= ([1/2]-mono 4 6 le'))
  where
    le : 2 <= 3
    le = s<=s _ _ (s<=s _ _ (z<=n _))
    le' : 4 <= 6
    le' = s<=s _ _ (s<=s _ _ (s<=s _ _ (s<=s _ _ (z<=n _))))


-- Proof: insertion sort computes a permutation of the input list

module sortnat where

open import bool
open import eq
open import nat
open import list
open import nondet
open import nondet-thms

-- non-deterministic insert.
--This takes a nondeterministic list because I need to be able to call it with the result of perm
--
--implementation in curry:
-- ndinsert x [] = []
-- ndinsert x (y:ys) = (x : y : xs) ? (y : insert x ys)
ndinsert : {A : Set} → A → 𝕃 A → ND (𝕃 A)
ndinsert x []        = Val ( x :: [])
ndinsert x (y :: ys) = (Val ( x :: y :: ys ))
                    ?? ((_::_ y) $* (ndinsert x ys))

--non-deterministic permutation
--this is identical to the curry code (except for the Val constructor)
perm : {A : Set} → (𝕃 A) → ND (𝕃 A)
perm []        = Val []
perm (x :: xs) = (ndinsert x) *$* (perm xs)

--insert a value into a sorted list.
--this is identical to curry or haskell code.
--
--note that the structure here is identical to ndinsert
insert : ℕ → 𝕃 ℕ → 𝕃 ℕ
insert x []        = x :: []
insert x (y :: ys) = if x < y then (x :: y :: ys)
                              else (y :: insert x ys)

--simple insertion sort
--again this is identical to curry or haskell
--also, note that the structure is identical to perm
sort : 𝕃 ℕ → 𝕃 ℕ
sort []     = []
sort (x :: xs) = insert x (sort xs)

--If introduction rule for non-deterministic values.
--if x and y are both possible values in z then
--∀ c. if c then x else y will give us either x or y, so it must be a possible value of z.
--
ifIntro : {A : Set} → (x : A) → (y : A) → (nx : ND A)
       → x ∈ nx → y ∈ nx → (c : 𝔹) → (if c then x else y) ∈ nx
ifIntro x y nx p q tt = p
ifIntro x y nx p q ff = q

---------------------------------------------------------------------------
--
-- this should prove that if xs ∈ nxs then, insert x xs ∈ ndinsert x nxs
-- parameters:
-- x         : the value we are inserting into the list
-- xs        : the list
--
--returns: insert x xs ∈ ndinsert x xs
--  a proof that inserting a value in a list is ok with non-deterministic lists

insert=ndinsert : (y : ℕ) → (xs : 𝕃 ℕ) → (insert y xs) ∈ (ndinsert y xs)

-- the first case is simple: inserting into an empty list is trivial
insert=ndinsert y [] = ndrefl

--The recursive case is the interesting one.
--The list to insert an element has the form (x :: xs)
--At this point we have two possible cases.
--Either y is smaller then every element in (x :: xs), in which case it's inserted at the front,
--or y is larger than x, in which case it's inserted somewhere in xs.
--Since both of these cases are covered by ndinsert we can invoke the ifIntro lemma, to say that we don't care which case it is.
--
--variables:
-- step    : one step of insert
-- l       : the left hand side of insert y xs (the then branch)
-- r       : the right hand side of insert y xs (the else branch)
-- nr      : a non-deterministic r
-- (Val l) : a non-deterministic l (but since ndinsert only has a deterministic value on the left it's not very interesting)
-- rec     : The recursive call.  If y isn't inserted into the front, then we need to find it.
-- l∈step : a proof that l is a possible value for step
-- r∈step : a proof that r is a possible value for step
insert=ndinsert y (x :: xs) = ifIntro l r step l∈step r∈step (y < x)
  where step   = ndinsert y (x :: xs)
        l      = (y :: x :: xs)
        r      = x :: insert y xs
        nl     = Val l
        nr     = (_::_ x) $* (ndinsert y xs)
        rec    = ∈-$* (_::_ x) (insert y xs) (ndinsert y xs)
                      (insert=ndinsert y xs)
        l∈step = left  nl nr ndrefl
        r∈step = right nl nr rec

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

-- Main theorem: Sorting a list preserves permutations
-- all of the work is really done by insert=ndinsert
sortPerm : (xs : 𝕃 ℕ) → sort xs ∈ perm xs
sortPerm []        = ndrefl
sortPerm (x :: xs) = ∈-*$* (sort xs) (perm xs) (insert x) (ndinsert x)
                           (sortPerm xs) (insert=ndinsert x (sort xs))


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

open import Boolean.Definition
open import LogicalFormulae
open import Decidable.Lemmas

module Numbers.Naturals.Definition where

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

infix 100 succ

{-# BUILTIN NATURAL ℕ #-}

succInjective : {a b : ℕ} → (succ a ≡ succ b) → a ≡ b
succInjective {a} {.a} refl = refl

naughtE : {a : ℕ} → zero ≡ succ a → False
naughtE ()

aIsNotSuccA : (a : ℕ) → (a ≡ succ a) → False
aIsNotSuccA zero pr = naughtE pr
aIsNotSuccA (succ a) pr = aIsNotSuccA a (succInjective pr)

ℕDecideEquality : (a b : ℕ) → ((a ≡ b) || ((a ≡ b) → False))
ℕDecideEquality zero zero = inl refl
ℕDecideEquality zero (succ b) = inr (λ ())
ℕDecideEquality (succ a) zero = inr (λ ())
ℕDecideEquality (succ a) (succ b) with ℕDecideEquality a b
ℕDecideEquality (succ a) (succ b) | inl x = inl (applyEquality succ x)
ℕDecideEquality (succ a) (succ b) | inr x = inr λ pr → x (succInjective pr)

ℕDecideEquality' : (a b : ℕ) → Bool
ℕDecideEquality' a b with ℕDecideEquality a b
ℕDecideEquality' a b | inl x = BoolTrue
ℕDecideEquality' a b | inr x = BoolFalse

record _=N'_ (a b : ℕ) : Set where
  field
    .eq : a ≡ b

squashN : {a b : ℕ} → a =N' b → a ≡ b
squashN record { eq = eq } = squash ℕDecideEquality eq

collapseN : {a b : ℕ} → a ≡ b → a =N' b
collapseN refl = record { eq = refl }

=N'Refl : {a b : ℕ} → (p1 p2 : a =N' b) → p1 ≡ p2
=N'Refl p1 p2 = refl


-- This module closely follows a section of Martín Escardó's HoTT lecture notes:
-- https://www.cs.bham.ac.uk/~mhe/HoTT-UF-in-Agda-Lecture-Notes/HoTT-UF-Agda.html#unicharac
{-# OPTIONS --without-K #-}
module Util.HoTT.Univalence.ContrFormulation where

open import Util.Data.Product using (map₂)
open import Util.Prelude
open import Util.HoTT.Equiv
open import Util.HoTT.HLevel.Core
open import Util.HoTT.Singleton
open import Util.HoTT.Univalence.Axiom
open import Util.HoTT.Univalence.Statement

private
  variable
    α β γ : Level

UnivalenceContr : ∀ α → Set (lsuc α)
UnivalenceContr α = (A : Set α) → IsContr (Σ[ B ∈ Set α ] (A ≃ B))

UnivalenceProp : ∀ α → Set (lsuc α)
UnivalenceProp α = (A : Set α) → IsProp (Σ[ B ∈ Set α ] (A ≃ B))

abstract
  IsEquiv→Σ-IsContr : {A : Set α} {B : A → Set β} (x : A)
    → (f : ∀ y → x ≡ y → B y)
    → (∀ y → IsEquiv (f y))
    → IsContr (Σ A B)
  IsEquiv→Σ-IsContr {A = A} {B = B} x f f-equiv
    = ≃-pres-IsContr Singleton≃ΣB IsContr-Singleton′
    where
      ≡≃B : ∀ y → (x ≡ y) ≃ B y
      ≡≃B y .forth = f y
      ≡≃B y .isEquiv = f-equiv y

      Singleton≃ΣB : Singleton′ x ≃ Σ A B
      Singleton≃ΣB = Σ-≃⁺ ≡≃B

  Σ-IsContr→IsEquiv : {A : Set α} {B : A → Set β} (x : A)
    → (f : ∀ y → x ≡ y → B y)
    → IsContr (Σ A B)
    → ∀ y → IsEquiv (f y)
  Σ-IsContr→IsEquiv {A = A} {B = B} x f Σ-contr
    = IsEquiv-map₂-f→IsEquiv-f f f-equiv
    where
      f-equiv : IsEquiv (map₂ f)
      f-equiv = IsContr→IsEquiv IsContr-Singleton′ Σ-contr (map₂ f)

  Univalence→UnivalenceContr : Univalence α → UnivalenceContr α
  Univalence→UnivalenceContr ua A = IsEquiv→Σ-IsContr A (λ B → ≡→≃) (λ B → ua)

  UnivalenceContr→Univalence : UnivalenceContr α → Univalence α
  UnivalenceContr→Univalence ua {A} {B}
    = Σ-IsContr→IsEquiv A (λ B → ≡→≃) (ua A) B

  univalenceContr : (A : Set α) → IsContr (Σ[ B ∈ Set α ] (A ≃ B))
  univalenceContr = Univalence→UnivalenceContr univalence

  UnivalenceContr→UnivalenceProp : UnivalenceContr α → UnivalenceProp α
  UnivalenceContr→UnivalenceProp ua = IsContr→IsProp ∘ ua

  UnivalenceProp→UnivalenceContr : UnivalenceProp α → UnivalenceContr α
  UnivalenceProp→UnivalenceContr ua A
    = IsProp∧Pointed→IsContr (ua A) (A , ≃-refl)

  Univalence→UnivalenceProp : Univalence α → UnivalenceProp α
  Univalence→UnivalenceProp
    = UnivalenceContr→UnivalenceProp ∘ Univalence→UnivalenceContr

  UnivalenceProp→Univalence : UnivalenceProp α → Univalence α
  UnivalenceProp→Univalence
    = UnivalenceContr→Univalence ∘ UnivalenceProp→UnivalenceContr

  univalenceProp : ∀ {α} → UnivalenceProp α
  univalenceProp = Univalence→UnivalenceProp univalence


module ListThms where
open import Sec4
import Sec2

{-
  Definition of a list
-}
data List (A : Set) : Set where
  []  : List A                  -- Empty list
  _∷_ : A → List A → List A     -- Cons

infixr 4 _∷_

-- Proposition stating what is a non empty list
nelist : {A : Set} → (List A) → Prop
nelist [] = ⊥
nelist (x ∷ x₁) = ⊤

-- Head function that only works on non empty list
head : {A : Set} → (l : List A) → (p : nelist l) → A
head [] ()                      -- This can never happen
head (x ∷ _) ⋆ = x              -- This is the head of the list

-- The tail of the list only works on non empty list
tail : {A : Set} → (l : List A) → (p : nelist l) → (List A)
tail [] ()
tail (_ ∷ l) ⋆ = l

-- definition of a map
map : {A B : Set} → (A → B) → (List A) → List B
map f [] = []
map f (x ∷ l) = (f x) ∷ map f l

-- definition of fold left
fold : {A B : Set} → (A → B → B) → B → (List A) → B
fold f x [] = x
fold f x (x₁ ∷ l) = fold f (f x₁ x) l

-- reduce only works on lists of length > 0
reduce : {A : Set} → (l : List A) → (p : nelist l) → (A → A → A) → A
reduce [] ()
reduce (x ∷ l) _ f = fold f x l

-- length of a list
length : {A : Set} → (List A) → Sec2.ℕ
length [] = Sec2.Z
length (x ∷ l) = (Sec2.S Sec2.Z) Sec2.+ (length l)

-- Proposition on ≤
_<=_ : Sec2.ℕ  → Sec2.ℕ → Prop
Sec2.Z <= Sec2.Z = ⊤
Sec2.Z <= Sec2.S y = ⊤
Sec2.S x <= y = x <= y

_>=_ : Sec2.ℕ  → Sec2.ℕ → Prop
Sec2.Z >= Sec2.Z = ⊤
Sec2.Z >= Sec2.S y = ⊥
Sec2.S x >= y = x >= y

-- Indexing into the list
_!!_ : {A : Set} → ∀ (l : List A) → ∀ (i : Sec2.ℕ) → (nelist l)
                 → Exists A (λ _  → ((i >= Sec2.Z) ∧ (i <= (length l))))
([] !! i) ()
((x ∷ l) !! i) ⋆ = [ x , (and (lem1 i) (lem (x ∷ l) i))]
  where
  cong-<= : (x y : Sec2.ℕ) → (x <= y) → (x <= Sec2.S y)
  cong-<= Sec2.Z y p = ⋆
  cong-<= (Sec2.S x) Sec2.Z p = cong-<= x Sec2.Z p
  cong-<= (Sec2.S x) (Sec2.S y) p = cong-<= x (Sec2.S y) p

  lem1 : (i : Sec2.ℕ) → (i >= Sec2.Z)
  lem1 Sec2.Z = ⋆
  lem1 (Sec2.S i) = lem1 i

  lem2 : (i : Sec2.ℕ) → (i <= Sec2.Z)
  lem2 Sec2.Z = ⋆
  lem2 (Sec2.S i₁) = lem2 i₁

  lem : {A : Set} →  (l : List A) → (i : Sec2.ℕ) → (i <= (length l))
  lem [] Sec2.Z = ⋆
  lem [] (Sec2.S i) = lem2 i
  lem (x₁ ∷ l₁) i = cong-<= i (length l₁) (lem l₁ i)

data Maybe (A : Set) : Set where
  Nothing : Maybe A
  Just : A → Maybe A

index : {A : Set} → ∀ (l : List A)
                  → (nelist l)
                  → ∀ (i : Sec2.ℕ)
                  → Sec2.So ((i Sec2.≥ Sec2.Z) Sec2.& (i Sec2.< (length l)))
                  → Maybe A
index l _ i _ = index' l i (Sec2.Z)
  where
  index' : {A : Set} → ∀ (l : List A) → ∀(i : Sec2.ℕ)
                     → (c : Sec2.ℕ) → Maybe A
  index' [] i₁ c = Nothing
  index' (x₁ ∷ l₁) i₁ c with (i₁ Sec2.== c)
  index' (x₁ ∷ l₁) i₁ c | Sec2.T = Just x₁
  index' (x₁ ∷ l₁) i₁ c | Sec2.F = index' l₁ i₁ (Sec2.S c)

exx1 : Maybe Sec2.ℕ
exx1 = index (1 ∷ []) ⋆ 0 Sec2.ok

index'' : {A : Set} → ∀ (l : List A)
                  → ∀ (i : Sec2.ℕ)
                  → Sec2.So (i Sec2.< (length l))
                  → A
index'' [] Sec2.Z ()
index'' [] (Sec2.S i) ()
index'' (x ∷ l) Sec2.Z Sec2.ok = x
index'' (x ∷ l) (Sec2.S i) p = index'' l i p

-- append two lists
_++_ : {A : Set} → (l : List A) → (l' : List A) → (List A)
[] ++ l' = l'
(x ∷ l) ++ l' = (x ∷ (l ++ l'))

-- composition of two functions
_∘_ : {A B C : Set} → (A → B) → (B → C) → (A → C)
f ∘ g = λ x → (g (f x))

cong : {A : Set} → (x : A) → (l m : List A) → (l Sec2.≡ m) → (x ∷ l) Sec2.≡ (x ∷ m)
cong x l .l Sec2.refl = Sec2.refl

cong2 : {A : Set} → (l m q : List A) → (l Sec2.≡ m) → (l ++ q) Sec2.≡ (m ++ q)
cong2 l .l q Sec2.refl = Sec2.refl

thm1-map : {A B : Set} → (f : A → B) → (l : List A) → (m : List A) → (map f (l ++ m)) Sec2.≡ (map f l) ++ (map f m)
thm1-map f [] m = Sec2.refl
thm1-map f (x ∷ l) m with (f x)
thm1-map f (x ∷ l) m | p  = cong p (map f (l ++ m)) (map f l ++ map f m) (thm1-map f l m)

-- map ∘
thm2-map : {A B C : Set} → (f : A → B) → (g : B → C) → (l : List A) → (map (f ∘ g) l Sec2.≡ ((map f) ∘ (map g)) l)
thm2-map f₁ g₁ [] = Sec2.refl
thm2-map f₁ g₁ (x ∷ l) with (thm2-map f₁ g₁ l)
thm2-map f₁ g₁ (x ∷ l) | p = cong (g₁ (f₁ x)) (map (λ z → g₁ (f₁ z)) l) (map g₁ (map f₁ l)) p

-- Non empty list by construction
data NeList (A : Set) : Set where
  ^_^ : A → NeList A
  _∶_ : A → NeList A → NeList A

infixr 60 ^_^
infixr 60 _∶_

-- XXX: Prove these in Coq along with the other theorem from Mike Naha's
-- tutorial in Agda.


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

open import LogicalFormulae
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Functions.Definition
open import Setoids.Setoids
open import Setoids.Subset
open import Graphs.Definition
open import Sets.FinSet.Definition
open import Numbers.Naturals.Semiring
open import Sets.EquivalenceRelations

module Graphs.CompleteGraph where

CompleteGraph : {a b : _} {V' : Set a} (V : Setoid {a} {b} V') → Graph b V
Graph._<->_ (CompleteGraph V) x y = ((Setoid._∼_ V x y) → False)
Graph.noSelfRelation (CompleteGraph V) x x!=x = x!=x (Equivalence.reflexive (Setoid.eq V))
Graph.symmetric (CompleteGraph V) x!=y y=x = x!=y ((Equivalence.symmetric (Setoid.eq V)) y=x)
Graph.wellDefined (CompleteGraph V) {x} {y} {r} {s} x=y r=s x!=r y=s = x!=r (transitive x=y (transitive y=s (symmetric r=s)))
  where
    open Setoid V
    open Equivalence eq

Kn : (n : ℕ) → Graph _ (reflSetoid (FinSet n))
Kn n = CompleteGraph (reflSetoid (FinSet n))

triangle : Graph _ (reflSetoid (FinSet 3))
triangle = Kn 3


module Category where

open import Logic.Equivalence
open import Logic.Relations

open Equivalence using () renaming (_==_ to eq)

record Cat : Set2 where
  field
    Obj     : Set1
    _─→_    : Obj -> Obj -> Set
    id      : {A : Obj} -> A ─→ A
    _∘_     : {A B C : Obj} -> B ─→ C -> A ─→ B -> A ─→ C
    Eq      : {A B : Obj} -> Equivalence (A ─→ B)
    cong    : {A B C : Obj}{f₁ f₂ : B ─→ C}{g₁ g₂ : A ─→ B} ->
              eq Eq f₁ f₂ -> eq Eq g₁ g₂ -> eq Eq (f₁ ∘ g₁) (f₂ ∘ g₂)
    idLeft  : {A B : Obj}{f : A ─→ B} -> eq Eq (id ∘ f) f
    idRight : {A B : Obj}{f : A ─→ B} -> eq Eq (f ∘ id) f
    assoc   : {A B C D : Obj}{f : C ─→ D}{g : B ─→ C}{h : A ─→ B} ->
              eq Eq ((f ∘ g) ∘ h) (f ∘ (g ∘ h))

module Category (ℂ : Cat) where

  private module CC = Cat ℂ
  open CC public hiding (_─→_; _∘_)

  private module Eq {A B : Obj} = Equivalence (Eq {A}{B})
  open Eq public hiding (_==_)

  infix	 20 _==_
  infixr 30 _─→_
  infixr 90 _∘_

  _─→_ = CC._─→_

  _==_ : {A B : Obj} -> Rel (A ─→ B)
  _==_ = Eq._==_

  _∘_ : {A B C : Obj} -> B ─→ C -> A ─→ B -> A ─→ C
  _∘_ = CC._∘_

  congL : {A B C : Obj}{f₁ f₂ : B ─→ C}{g : A ─→ B} ->
	  f₁ == f₂ -> f₁ ∘ g == f₂ ∘ g
  congL p = cong p refl

  congR : {A B C : Obj}{f : B ─→ C}{g₁ g₂ : A ─→ B} ->
	  g₁ == g₂ -> f ∘ g₁ == f ∘ g₂
  congR p = cong refl p


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

open import Data.Product

open import Categories.Category
open import Categories.Functor
open import Categories.Product
open import Categories.FunctorCategory
open import Categories.Functor.Constant

import Categories.Power as Power

Δ : ∀ {o ℓ e} → (C : Category o ℓ e) → Functor C (Product C C)
Δ C = record
  { F₀ = λ x → x , x
  ; F₁ = λ f → f , f
  ; identity = refl , refl
  ; homomorphism = refl , refl
  ; F-resp-≡ = λ x → x , x
  }
  where
  open Category C
  open Equiv

Δ′ : ∀ {o ℓ e} → (I : Set) → (C : Category o ℓ e) → Functor C (Power.Exp C I)
Δ′ I C = record
  { F₀ = λ x _ → x
  ; F₁ = λ f _ → f
  ; identity = λ _ → refl
  ; homomorphism = λ _ → refl
  ; F-resp-≡ = λ x _ → x
  }
  where
  open Power C
  open Category C
  open Equiv

ΔF : ∀ {o ℓ e o₁ ℓ₁ e₁} {C : Category o ℓ e} (I : Category o₁ ℓ₁ e₁) → Functor C (Functors I C)
ΔF {C = C} I = record
  { F₀ = λ c → Constant c
  ; F₁ = λ f → record { η = λ X → f; commute = λ g → trans C.identityʳ (sym C.identityˡ) }
  ; identity = refl
  ; homomorphism = refl
  ; F-resp-≡ = λ x → x
  }
 where
   module C = Category C
   open C.Equiv
   module I = Category I


{-# OPTIONS --without-K #-}
module sets.vec.properties where

open import equality.core
open import function.core
open import function.extensionality
open import function.isomorphism
open import sets.nat.core using (ℕ; zero; suc)
open import sets.fin using (Fin; zero; suc)
open import sets.vec.core

tabulate-lookup : ∀ {i}{A : Set i}{n : ℕ}
                → (xs : Vec A n)
                → tabulate (lookup xs) ≡ xs
tabulate-lookup [] = refl
tabulate-lookup (x ∷ xs) = ap (_∷_ x) (tabulate-lookup xs)

lookup-tabulate-funext : ∀ {i}{A : Set i}{n : ℕ}
                    → (f : Fin n → A)(i : Fin n)
                    → lookup (tabulate f) i ≡ f i
lookup-tabulate-funext {n = zero} f ()
lookup-tabulate-funext {n = suc m} f zero = refl
lookup-tabulate-funext {n = suc m} f (suc i) =
  lookup-tabulate-funext (f ∘ suc) i

lookup-tabulate : ∀ {i}{A : Set i}{n : ℕ}
                → (f : Fin n → A)
                → lookup (tabulate f) ≡ f
lookup-tabulate f = funext (lookup-tabulate-funext f)

lookup-iso : ∀ {i}{A : Set i}{n : ℕ}
           → Vec A n ≅ (Fin n → A)
lookup-iso = iso lookup tabulate tabulate-lookup lookup-tabulate


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

open import Groups.Definition
open import Setoids.Orders.Partial.Definition
open import Setoids.Orders.Total.Definition
open import Setoids.Setoids
open import Functions.Definition
open import Rings.Definition
open import Rings.Orders.Partial.Definition

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

module Rings.Orders.Total.Definition {n m : _} {A : Set n} {S : Setoid {n} {m} A} {_+_ : A → A → A} {_*_ : A → A → A} {R : Ring S _+_ _*_} where

open Ring R
open Group additiveGroup
open Setoid S

record TotallyOrderedRing {p : _} {_<_ : Rel {_} {p} A} {pOrder : SetoidPartialOrder S _<_} (pRing : PartiallyOrderedRing R pOrder) : Set (lsuc n ⊔ m ⊔ p) where
  field
    total : SetoidTotalOrder pOrder
  open SetoidPartialOrder pOrder


{-# OPTIONS --cubical --no-exact-split --safe #-}
module Multidimensional.Data.Extra.Nat.Properties where

open import Cubical.Core.Everything

open import Cubical.Foundations.Prelude

open import Cubical.Data.Nat
open import Cubical.Data.Empty

open import Cubical.Relation.Nullary

open import Multidimensional.Data.Extra.Nat.Base

sucnsuc : (n m : ℕ) → sucn n (suc m) ≡ suc (sucn n m)
sucnsuc zero m = refl
sucnsuc (suc n) m =
    sucn (suc n) (suc m) ≡⟨ refl ⟩
    suc (sucn n (suc m)) ≡⟨ cong suc (sucnsuc n m) ⟩
    suc (suc (sucn n m)) ∎

doublePred : (n : ℕ) → doubleℕ (predℕ n) ≡ predℕ (predℕ (doubleℕ n))
doublePred zero = refl
doublePred (suc n) = refl

sucPred : (n : ℕ) → ¬ (n ≡ zero) → suc (predℕ n) ≡ n
sucPred zero 0≠0 = ⊥-elim (0≠0 refl)
sucPred (suc n) sucn≠0 = refl

doubleDoubles : (n m : ℕ) → doubleℕ (doublesℕ n m) ≡ doublesℕ (suc n) m
doubleDoubles zero m = refl
doubleDoubles (suc n) m = doubleDoubles n (doubleℕ m)

doublePos : (n : ℕ) → ¬ (n ≡ 0) → ¬ (doubleℕ n ≡ 0)
doublePos zero 0≠0 = ⊥-elim (0≠0 refl)
doublePos (suc n) sn≠0 = snotz

doublesPos : (n m : ℕ) → ¬ (m ≡ 0) → ¬ (doublesℕ n m ≡ 0)
doublesPos zero m m≠0 = m≠0
doublesPos (suc n) m m≠0 = doublesPos n (doubleℕ m) (doublePos m (m≠0))

predDoublePos : (n : ℕ) → ¬ (n ≡ 0) → ¬ (predℕ (doubleℕ n)) ≡ 0
predDoublePos zero n≠0 = ⊥-elim (n≠0 refl)
predDoublePos (suc n) sn≠0 = snotz

doubleDoublesOne≠0 : (n : ℕ) → ¬ (doubleℕ (doublesℕ n (suc zero)) ≡ 0)
doubleDoublesOne≠0 zero = snotz
doubleDoublesOne≠0 (suc n) = doublePos (doublesℕ n 2) (doublesPos n 2 (snotz))

predDoubleDoublesOne≠0 : (n : ℕ) → ¬ (predℕ (doubleℕ (doublesℕ n (suc zero))) ≡ 0)
predDoubleDoublesOne≠0 zero = snotz
predDoubleDoublesOne≠0 (suc n) = predDoublePos (doublesℕ n 2) (doublesPos n 2 snotz)

doublesZero : (n : ℕ) → doublesℕ n zero ≡ zero
doublesZero zero = refl
doublesZero (suc n) = doublesZero n

doubleSucn : (i n : ℕ) →  doubleℕ (sucn i n) ≡ sucn (doubleℕ i) (doubleℕ n)
doubleSucn zero n = refl
doubleSucn (suc i) n =
    suc (suc (doubleℕ (sucn i n)))
  ≡⟨ cong (λ z → suc (suc z)) (doubleSucn i n) ⟩
    suc (suc (sucn (doubleℕ i) (doubleℕ n)))
  ≡⟨ refl ⟩
    suc (sucn (suc (doubleℕ i)) (doubleℕ n))
  ≡⟨ cong suc refl ⟩
    sucn (suc (suc (doubleℕ i))) (doubleℕ n)
  ∎

doublesSucn : (i n m : ℕ) → doublesℕ n (sucn i m) ≡ sucn (doublesℕ n i) (doublesℕ n m)
doublesSucn i zero m = refl
doublesSucn i (suc n) m =
    doublesℕ n (doubleℕ (sucn i m))
  ≡⟨  cong (doublesℕ n) (doubleSucn i m) ⟩
    doublesℕ n (sucn (doubleℕ i) (doubleℕ m))
  ≡⟨ doublesSucn (doubleℕ i) n (doubleℕ m) ⟩
     sucn (doublesℕ n (doubleℕ i)) (doublesℕ n (doubleℕ m))
  ∎

-- 2^n * (m + 2) =
doublesSucSuc : (n m : ℕ) → doublesℕ n (suc (suc m)) ≡ sucn (doublesℕ (suc n) 1) (doublesℕ n m)
doublesSucSuc zero m = refl
doublesSucSuc (suc n) m =
    doublesℕ (suc n) (suc (suc m))
  ≡⟨ refl ⟩
    doublesℕ n (sucn 4 (doubleℕ m))
  ≡⟨ doublesSucn 4 n (doubleℕ m) ⟩
    sucn (doublesℕ n 4) (doublesℕ n (doubleℕ m))
  ∎

n+n≡2n : (n : ℕ) → sucn n n ≡ doubleℕ n
n+n≡2n zero = refl
n+n≡2n (suc n) =
    sucn (suc n) (suc n)
  ≡⟨ sucnsuc (suc n) n ⟩
    suc (sucn (suc n) n)
  ≡⟨ refl ⟩
   suc (suc (sucn n n))
  ≡⟨ cong (λ z → suc (suc z)) (n+n≡2n n) ⟩
   suc (suc (doubleℕ n))
  ∎


module Mutual2 where

data Bool
  : Set
  where

  false
    : Bool

  true
    : Bool

data ℕ
  : Set
  where

  zero
    : ℕ

  suc
    : ℕ
    → ℕ

is-even
  : ℕ
  → Bool

is-odd
  : ℕ
  → Bool

is-even zero
  = true
is-even (suc n)
  = is-odd n

is-odd zero
  = false
is-odd (suc n)
  = is-even n

is-even'
  : ℕ
  → Bool
is-even'
  = is-even


module IIDg where

open import LF

-- Codes for indexed inductive types
data OPg (I : Set) : Set1 where
  ι : I -> OPg I
  σ : (A : Set)(γ : A -> OPg I) -> OPg I
  δ : (H : Set)(i : H -> I)(γ : OPg I) -> OPg I

-- The top-level structure of values in an IIDg
Args : {I : Set}(γ : OPg I)(U : I -> Set) -> Set
Args (ι _)     U = One
Args (σ A γ)   U = A × \a -> Args (γ a) U
Args (δ H i γ) U = ((x : H) -> U (i x)) × \_ -> Args γ U

-- The index of a value in an IIDg
Index : {I : Set}(γ : OPg I)(U : I -> Set) -> Args γ U -> I
Index (ι i)	U _	    = i
Index (σ A γ)	U < a | b > = Index (γ a) U b
Index (δ _ _ γ) U < _ | b > = Index γ U b

-- The assumptions of a particular inductive occurrence.
IndArg : {I : Set}(γ : OPg I)(U : I -> Set) -> Args γ U -> Set
IndArg (ι _)     U _	     = Zero
IndArg (σ A γ)	 U < a | b > = IndArg (γ a) U b
IndArg (δ H i γ) U < _ | b > = H + IndArg γ U b

-- The index of an inductive occurrence.
IndIndex : {I : Set}(γ : OPg I)(U : I -> Set)(a : Args γ U) -> IndArg γ U a -> I
IndIndex (ι _)	   U _	     ()
IndIndex (σ A γ)   U < a | b > h       = IndIndex (γ a) U b h
IndIndex (δ A i γ) U < g | b > (inl h) = i h
IndIndex (δ A i γ) U < g | b > (inr h) = IndIndex γ U b h

-- An inductive occurrence.
Ind : {I : Set}(γ : OPg I)(U : I -> Set)(a : Args γ U)(h : IndArg γ U a) -> U (IndIndex γ U a h)
Ind (ι _)     U _	  ()
Ind (σ A γ)   U < a | b > h	  = Ind (γ a) U b h
Ind (δ H i γ) U < g | b > (inl h) = g h
Ind (δ H i γ) U < _ | b > (inr h) = Ind γ U b h

-- The type of induction hypotheses.
IndHyp : {I : Set}(γ : OPg I)(U : I -> Set)(C : (i : I) -> U i -> Set)(a : Args γ U) -> Set
IndHyp γ U C a = (hyp : IndArg γ U a) -> C (IndIndex γ U a hyp) (Ind γ U a hyp)

-- Large induction hypostheses.
IndHyp₁ : {I : Set}(γ : OPg I)(U : I -> Set)(C : (i : I) -> U i -> Set1)(a : Args γ U) -> Set1
IndHyp₁ γ U C a = (hyp : IndArg γ U a) -> C (IndIndex γ U a hyp) (Ind γ U a hyp)


-- {-# OPTIONS -v tc.meta:100 #-}
-- Andreas, 2011-04-20
-- see Abel Pientka TLCA 2011
module PruningNonMillerPattern where

data _≡_ {A : Set}(a : A) : A -> Set where
  refl : a ≡ a

data Nat : Set where
  zero : Nat
  suc  : Nat -> Nat

test : let X : Nat -> Nat -> Nat
           X = _
           Y : Nat -> Nat -> Nat
           Y = _
       in  (C : Set) ->
           (({x y : Nat} -> X x x ≡ suc (Y x y)) ->
            ({x y : Nat} -> Y x x ≡ x)           ->
            ({x y : Nat} -> X (Y x y) y ≡ X x x) -> C) -> C
test C k = k refl refl refl
{- none of these equations is immediately solvable.  However,
   from 1. we deduce that Y does not depend on its second argument, thus
   from 2. we solve Y x y = x, and then
   eqn. 3. simplifies to X x y = X x x, thus, X does not depend on its second arg,
   we can then solve using 1.  X x y = suc x
-}

-- a variant, where pruning is even triggered from a non-pattern
test' : let X : Nat -> Nat -> Nat
            X = _
            Y : Nat -> Nat -> Nat
            Y = _
        in  (C : Set) ->
            (({x y : Nat} -> X x (suc x) ≡ suc (Y x y)) ->  -- non-pattern lhs
             ({x y : Nat} -> Y x x ≡ x)           ->
             ({x y : Nat} -> X (Y x y) y ≡ X x x) -> C) -> C
test' C k = k refl refl refl


import      Lvl
open import Data.Boolean
open import Type

module Data.List.Sorting.InsertionSort {ℓ} {T : Type{ℓ}} (_≤?_ : T → T → Bool) where

open import Data.List
import      Data.List.Functions as List
open import Data.List.Sorting.Functions(_≤?_)

insertion-sort : List(T) → List(T)
insertion-sort = List.foldᵣ insert ∅

module Proofs where
  open import Data.Boolean.Stmt
  open import Data.List.Relation.Permutation
  open import Data.List.Sorting(_≤?_)
  open import Data.List.Sorting.Proofs(_≤?_)
  open import Functional using (_∘₂_)
  open import Logic.Propositional
  open import Relator.Equals
  open import Structure.Relator.Properties
  open import Syntax.Transitivity

  module _ (asym : ∀{x y} → (x ≤? y ≡ not(y ≤? x))) where -- TODO: Use Structure.Relator.Properties.Asymmetry by the relation (IsTrue ∘₂ (_≤?_))
    instance
      insertion-sort-sorted-proof : ∀{l} → Sorted(insertion-sort l)
      insertion-sort-sorted-proof {∅}     = empty
      insertion-sort-sorted-proof {x ⊰ l} = insert-sorted-proof asym (insertion-sort-sorted-proof {l})

    insert-permutation-proof : ∀{x}{l} → ((insert x l) permutes (x ⊰ l))
    insert-permutation-proof {x} {∅} = prepend _permutes_.empty
    insert-permutation-proof {x} {a ⊰ l} with (x ≤? a)
    ... | 𝑇 = reflexivity(_permutes_)
    ... | 𝐹 =
      a ⊰ insert x l 🝖-[ _permutes_.prepend (insert-permutation-proof {x} {l}) ]
      a ⊰ x ⊰ l      🝖-[ _permutes_.swap ]
      x ⊰ a ⊰ l      🝖-end

    instance
      insertion-sort-permutation-proof : ∀{l} → ((insertion-sort l) permutes l)
      insertion-sort-permutation-proof {∅} = _permutes_.empty
      insertion-sort-permutation-proof {x ⊰ l} =
        insertion-sort (x ⊰ l) 🝖-[ insert-permutation-proof ]
        x ⊰ (insertion-sort l) 🝖-[ prepend (insertion-sort-permutation-proof {l}) ]
        x ⊰ l                  🝖-end

    instance
      insertion-sort-sorting-algorithm : SortingAlgorithm(insertion-sort)
      SortingAlgorithm.sorts    insertion-sort-sorting-algorithm {l} = insertion-sort-sorted-proof {l}
      SortingAlgorithm.permutes insertion-sort-sorting-algorithm     = insertion-sort-permutation-proof


import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Data.Nat using (ℕ; zero; suc)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Relation.Nullary using (¬_)
open import Relation.Nullary.Negation using (contraposition)
open import Data.Unit using (⊤; tt)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.List using (List; []; _∷_; foldr; map)
open import Function using (_∘_)

double-negation : ∀ {A : Set} → A → ¬ ¬ A
double-negation x ¬x = ¬x x

triple-negation : ∀ {A : Set} → ¬ ¬ ¬ A → ¬ A
triple-negation ¬¬¬x x = ¬¬¬x (double-negation x)

Stable : Set → Set
Stable A = ¬ ¬ A → A

¬-stable : ∀ {A : Set} → Stable (¬ A)
¬-stable = triple-negation

×-stable : ∀ {A B : Set} → Stable A → Stable B → Stable (A × B)
×-stable ¬¬x→x ¬¬y→y ¬¬xy =
  ⟨ ¬¬x→x (contraposition (contraposition proj₁) ¬¬xy)
  , ¬¬y→y (contraposition (contraposition proj₂) ¬¬xy)
  ⟩

∀-stable : ∀ {A : Set} {B : A → Set} → (∀ (x : A) → Stable (B x)) → Stable (∀ (x : A) → B x)
∀-stable ∀x→¬¬y→y ¬¬∀x→y x =
  ∀x→¬¬y→y x (contraposition (contraposition λ{∀x→y → ∀x→y x}) ¬¬∀x→y)

-- Gödel-Gentzen translation

{--
data Var : ℕ → Set where
  zero : ∀ (n : ℕ) → Var (suc n)
  suc : ∀ (n : ℕ) → Var n → Var (suc n)

data Formula : ℕ → Set where
  _`≡_ : ∀ (n : ℕ) → Var n → Var n → Formula n
  _`×_ : ∀ (n : ℕ) → Formula n → Formula n → Formula n
  _`⊎_ : ∀ (n : ℕ) → Formula n → Formula n → Formula n
  `¬_ : ∀ (n : ℕ) → Formula n → Formula n
--}

data Formula : Set₁ where
  atomic : ∀ (A : Set) → Formula
  _`×_ : Formula → Formula → Formula
  _`⊎_ : Formula → Formula → Formula
  `¬_ : Formula → Formula

interp : Formula → Set
interp (atomic A) =  A
interp (`A `× `B) = interp `A × interp `B
interp (`A `⊎ `B) = interp `A ⊎ interp `B
interp (`¬ `A) = ¬ interp `A

g : Formula → Formula
g (atomic A) =  `¬ `¬ (atomic A)
g (`A `× `B) = g `A `× g `B
g (`A `⊎ `B) = `¬ ((`¬ g `A) `× (`¬ g `B))
g (`¬ `A) = `¬ g `A

stable-g : ∀ (`A : Formula) → Stable (interp (g `A))
stable-g (atomic A) =  ¬-stable
stable-g (`A `× `B) =  ×-stable (stable-g `A) (stable-g `B)
stable-g (`A `⊎ `B) =  ¬-stable
stable-g (`¬ `A) = ¬-stable


-- Classical propositional logic, PHOAS approach, initial encoding

module Pi.Cp where

-- Types

infixl 2 _&&_
infixl 1 _||_
infixr 0 _=>_
data Ty : Set where
  UNIT  :             Ty
  _=>_  : Ty -> Ty -> Ty
  _&&_  : Ty -> Ty -> Ty
  _||_  : Ty -> Ty -> Ty
  FALSE :             Ty

infixr 0 _<=>_
_<=>_ : Ty -> Ty -> Ty
a <=> b = (a => b) && (b => a)

NOT : Ty -> Ty
NOT a = a => FALSE

TRUE : Ty
TRUE = FALSE => FALSE

-- Context and truth judgement

Cx : Set1
Cx = Ty -> Set

isTrue : Ty -> Cx -> Set
isTrue a tc = tc a

-- Terms

module Cp where
  infixl 1 _$_
  data Tm (tc : Cx) : Ty -> Set where
    var    : forall {a}     -> isTrue a tc               -> Tm tc a
    lam'   : forall {a b}   -> (isTrue a tc -> Tm tc b)  -> Tm tc (a => b)
    _$_    : forall {a b}   -> Tm tc (a => b) -> Tm tc a -> Tm tc b
    pair'  : forall {a b}   -> Tm tc a        -> Tm tc b -> Tm tc (a && b)
    fst    : forall {a b}   -> Tm tc (a && b)            -> Tm tc a
    snd    : forall {a b}   -> Tm tc (a && b)            -> Tm tc b
    left   : forall {a b}   -> Tm tc a                   -> Tm tc (a || b)
    right  : forall {a b}   -> Tm tc b                   -> Tm tc (a || b)
    case'  : forall {a b c} -> Tm tc (a || b) -> (isTrue a tc -> Tm tc c) -> (isTrue b tc -> Tm tc c) -> Tm tc c
    abort' : forall {a}    -> (isTrue (NOT a) tc -> Tm tc FALSE) -> Tm tc a

  lam'' : forall {tc a b} -> (Tm tc a -> Tm tc b) -> Tm tc (a => b)
  lam'' f = lam' \x -> f (var x)

  case'' : forall {tc a b c} -> Tm tc (a || b) -> (Tm tc a -> Tm tc c) -> (Tm tc b -> Tm tc c) -> Tm tc c
  case'' xy f g = case' xy (\x -> f (var x)) (\y -> g (var y))

  abort'' : forall {tc a} -> (Tm tc (NOT a) -> Tm tc FALSE) -> Tm tc a
  abort'' f = abort' \na -> f (var na)

  syntax lam''   (\a -> b) = lam a => b
  syntax pair'   x y       = [ x , y ]
  syntax case''  xy (\x -> z1) (\y -> z2) = case xy of x => z1 or y => z2
  syntax abort'' (\x -> y) = abort x => y

  Thm : Ty -> Set1
  Thm a = forall {tc} -> Tm tc a
open Cp public


-- 2011-10-01 Andreas
module EtaContractIrrelevant where

import Common.Level

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

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

postulate
  Val : Set

Pred = Val → Set

fam : Pred → Set1
fam A = {a : Val} → .(A a) → Pred

postulate
  π : (A : Pred)(F : fam A) → Pred

πCong : {A A' : Pred}(A≡A' : A ≡ A') →
  {F  : fam A }
  {F' : fam A'}
  (F≡F' : (λ {a} Aa → F {a = a} Aa)
        ≡ (λ {a} Aa → F' {a = a} (subst (λ A → A a) A≡A' Aa))) →
  π A F ≡ π A' F'
πCong refl refl = refl
-- needs eta-contraction for irrelevant functions F F'


------------------------------------------------------------------------
-- The Agda standard library
--
-- Definitions of algebraic structures defined over some other
-- structure, like modules and vector spaces
--
-- Terminology of bundles:
-- * There are both *semimodules* and *modules*.
--   - For M an R-semimodule, R is a semiring, and M forms a commutative
--     monoid.
--   - For M an R-module, R is a ring, and M forms an Abelian group.
-- * There are all four of *left modules*, *right modules*, *bimodules*,
--   and *modules*.
--   - Left modules have a left-scaling operation.
--   - Right modules have a right-scaling operation.
--   - Bimodules have two sorts of scalars. Left-scaling handles one and
--     right-scaling handles the other. Left-scaling and right-scaling
--     are furthermore compatible.
--   - Modules are bimodules with a single sort of scalars and scalar
--     multiplication must also be commutative. Left-scaling and
--     right-scaling coincide.
------------------------------------------------------------------------

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

module Algebra.Module.Bundles where

open import Algebra.Bundles
open import Algebra.Core
open import Algebra.Module.Structures
open import Algebra.Module.Definitions
open import Function.Base
open import Level
open import Relation.Binary
import Relation.Binary.Reasoning.Setoid as SetR

private
  variable
    r ℓr s ℓs : Level

------------------------------------------------------------------------
-- Left modules
------------------------------------------------------------------------

record LeftSemimodule (semiring : Semiring r ℓr) m ℓm
                      : Set (r ⊔ ℓr ⊔ suc (m ⊔ ℓm)) where
  open Semiring semiring

  infixr 7 _*ₗ_
  infixl 6 _+ᴹ_
  infix 4 _≈ᴹ_

  field
    Carrierᴹ : Set m
    _≈ᴹ_ : Rel Carrierᴹ ℓm
    _+ᴹ_ : Op₂ Carrierᴹ
    _*ₗ_ : Opₗ Carrier Carrierᴹ
    0ᴹ : Carrierᴹ
    isLeftSemimodule : IsLeftSemimodule semiring _≈ᴹ_ _+ᴹ_ 0ᴹ _*ₗ_

  open IsLeftSemimodule isLeftSemimodule public

  +ᴹ-commutativeMonoid : CommutativeMonoid m ℓm
  +ᴹ-commutativeMonoid = record
    { isCommutativeMonoid = +ᴹ-isCommutativeMonoid
    }

  open CommutativeMonoid +ᴹ-commutativeMonoid public
    using () renaming
    ( monoid    to +ᴹ-monoid
    ; semigroup to +ᴹ-semigroup
    ; magma     to +ᴹ-magma
    ; rawMagma  to +ᴹ-rawMagma
    ; rawMonoid to +ᴹ-rawMonoid
    )

record LeftModule (ring : Ring r ℓr) m ℓm : Set (r ⊔ ℓr ⊔ suc (m ⊔ ℓm)) where
  open Ring ring

  infixr 8 -ᴹ_
  infixr 7 _*ₗ_
  infixl 6 _+ᴹ_
  infix 4 _≈ᴹ_

  field
    Carrierᴹ : Set m
    _≈ᴹ_ : Rel Carrierᴹ ℓm
    _+ᴹ_ : Op₂ Carrierᴹ
    _*ₗ_ : Opₗ Carrier Carrierᴹ
    0ᴹ : Carrierᴹ
    -ᴹ_ : Op₁ Carrierᴹ
    isLeftModule : IsLeftModule ring _≈ᴹ_ _+ᴹ_ 0ᴹ -ᴹ_ _*ₗ_

  open IsLeftModule isLeftModule public

  leftSemimodule : LeftSemimodule semiring m ℓm
  leftSemimodule = record { isLeftSemimodule = isLeftSemimodule }

  open LeftSemimodule leftSemimodule public
    using ( +ᴹ-commutativeMonoid; +ᴹ-monoid; +ᴹ-semigroup; +ᴹ-magma
          ; +ᴹ-rawMagma; +ᴹ-rawMonoid)

  +ᴹ-abelianGroup : AbelianGroup m ℓm
  +ᴹ-abelianGroup = record { isAbelianGroup = +ᴹ-isAbelianGroup }

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

------------------------------------------------------------------------
-- Right modules
------------------------------------------------------------------------

record RightSemimodule (semiring : Semiring r ℓr) m ℓm
                       : Set (r ⊔ ℓr ⊔ suc (m ⊔ ℓm)) where
  open Semiring semiring

  infixl 7 _*ᵣ_
  infixl 6 _+ᴹ_
  infix 4 _≈ᴹ_

  field
    Carrierᴹ : Set m
    _≈ᴹ_ : Rel Carrierᴹ ℓm
    _+ᴹ_ : Op₂ Carrierᴹ
    _*ᵣ_ : Opᵣ Carrier Carrierᴹ
    0ᴹ : Carrierᴹ
    isRightSemimodule : IsRightSemimodule semiring _≈ᴹ_ _+ᴹ_ 0ᴹ _*ᵣ_

  open IsRightSemimodule isRightSemimodule public

  +ᴹ-commutativeMonoid : CommutativeMonoid m ℓm
  +ᴹ-commutativeMonoid = record
    { isCommutativeMonoid = +ᴹ-isCommutativeMonoid
    }

  open CommutativeMonoid +ᴹ-commutativeMonoid public
    using () renaming
    ( monoid    to +ᴹ-monoid
    ; semigroup to +ᴹ-semigroup
    ; magma     to +ᴹ-magma
    ; rawMagma  to +ᴹ-rawMagma
    ; rawMonoid to +ᴹ-rawMonoid
    )

record RightModule (ring : Ring r ℓr) m ℓm : Set (r ⊔ ℓr ⊔ suc (m ⊔ ℓm)) where
  open Ring ring

  infixr 8 -ᴹ_
  infixl 7 _*ᵣ_
  infixl 6 _+ᴹ_
  infix 4 _≈ᴹ_

  field
    Carrierᴹ : Set m
    _≈ᴹ_ : Rel Carrierᴹ ℓm
    _+ᴹ_ : Op₂ Carrierᴹ
    _*ᵣ_ : Opᵣ Carrier Carrierᴹ
    0ᴹ : Carrierᴹ
    -ᴹ_ : Op₁ Carrierᴹ
    isRightModule : IsRightModule ring _≈ᴹ_ _+ᴹ_ 0ᴹ -ᴹ_ _*ᵣ_

  open IsRightModule isRightModule public

  rightSemimodule : RightSemimodule semiring m ℓm
  rightSemimodule = record { isRightSemimodule = isRightSemimodule }

  open RightSemimodule rightSemimodule public
    using ( +ᴹ-commutativeMonoid; +ᴹ-monoid; +ᴹ-semigroup; +ᴹ-magma
          ; +ᴹ-rawMagma; +ᴹ-rawMonoid)

  +ᴹ-abelianGroup : AbelianGroup m ℓm
  +ᴹ-abelianGroup = record { isAbelianGroup = +ᴹ-isAbelianGroup }

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

------------------------------------------------------------------------
-- Bimodules
------------------------------------------------------------------------

record Bisemimodule (R-semiring : Semiring r ℓr) (S-semiring : Semiring s ℓs)
                    m ℓm : Set (r ⊔ s ⊔ ℓr ⊔ ℓs ⊔ suc (m ⊔ ℓm)) where
  private
    module R = Semiring R-semiring
    module S = Semiring S-semiring

  infixr 7 _*ₗ_
  infixl 6 _+ᴹ_
  infix 4 _≈ᴹ_

  field
    Carrierᴹ : Set m
    _≈ᴹ_ : Rel Carrierᴹ ℓm
    _+ᴹ_ : Op₂ Carrierᴹ
    _*ₗ_ : Opₗ R.Carrier Carrierᴹ
    _*ᵣ_ : Opᵣ S.Carrier Carrierᴹ
    0ᴹ : Carrierᴹ
    isBisemimodule : IsBisemimodule R-semiring S-semiring _≈ᴹ_ _+ᴹ_ 0ᴹ _*ₗ_ _*ᵣ_

  open IsBisemimodule isBisemimodule public

  leftSemimodule : LeftSemimodule R-semiring m ℓm
  leftSemimodule = record { isLeftSemimodule = isLeftSemimodule }

  rightSemimodule : RightSemimodule S-semiring m ℓm
  rightSemimodule = record { isRightSemimodule = isRightSemimodule }

  open LeftSemimodule leftSemimodule public
    using ( +ᴹ-commutativeMonoid; +ᴹ-monoid; +ᴹ-semigroup; +ᴹ-magma; +ᴹ-rawMagma
          ; +ᴹ-rawMonoid)

record Bimodule (R-ring : Ring r ℓr) (S-ring : Ring s ℓs) m ℓm
                : Set (r ⊔ s ⊔ ℓr ⊔ ℓs ⊔ suc (m ⊔ ℓm)) where
  private
    module R = Ring R-ring
    module S = Ring S-ring

  infixr 7 _*ₗ_
  infixl 6 _+ᴹ_
  infix 4 _≈ᴹ_

  field
    Carrierᴹ : Set m
    _≈ᴹ_ : Rel Carrierᴹ ℓm
    _+ᴹ_ : Op₂ Carrierᴹ
    _*ₗ_ : Opₗ R.Carrier Carrierᴹ
    _*ᵣ_ : Opᵣ S.Carrier Carrierᴹ
    0ᴹ : Carrierᴹ
    -ᴹ_ : Op₁ Carrierᴹ
    isBimodule : IsBimodule R-ring S-ring _≈ᴹ_ _+ᴹ_ 0ᴹ -ᴹ_ _*ₗ_ _*ᵣ_

  open IsBimodule isBimodule public

  leftModule : LeftModule R-ring m ℓm
  leftModule = record { isLeftModule = isLeftModule }

  rightModule : RightModule S-ring m ℓm
  rightModule = record { isRightModule = isRightModule }

  open LeftModule leftModule public
    using ( +ᴹ-abelianGroup; +ᴹ-commutativeMonoid; +ᴹ-group; +ᴹ-monoid
          ; +ᴹ-semigroup; +ᴹ-magma; +ᴹ-rawMagma; +ᴹ-rawMonoid)

  bisemimodule : Bisemimodule R.semiring S.semiring m ℓm
  bisemimodule = record { isBisemimodule = isBisemimodule }

  open Bisemimodule bisemimodule public
    using (leftSemimodule; rightSemimodule)

------------------------------------------------------------------------
-- Modules over commutative structures
------------------------------------------------------------------------

record Semimodule (commutativeSemiring : CommutativeSemiring r ℓr) m ℓm
                  : Set (r ⊔ ℓr ⊔ suc (m ⊔ ℓm)) where
  open CommutativeSemiring commutativeSemiring

  infixr 7 _*ₗ_
  infixl 7 _*ᵣ_
  infixl 6 _+ᴹ_
  infix 4 _≈ᴹ_

  field
    Carrierᴹ : Set m
    _≈ᴹ_ : Rel Carrierᴹ ℓm
    _+ᴹ_ : Op₂ Carrierᴹ
    _*ₗ_ : Opₗ Carrier Carrierᴹ
    _*ᵣ_ : Opᵣ Carrier Carrierᴹ
    0ᴹ : Carrierᴹ
    isSemimodule : IsSemimodule commutativeSemiring _≈ᴹ_ _+ᴹ_ 0ᴹ _*ₗ_ _*ᵣ_

  open IsSemimodule isSemimodule public

  private
    module L = LeftDefs Carrier _≈ᴹ_
    module R = RightDefs Carrier _≈ᴹ_

  bisemimodule : Bisemimodule semiring semiring m ℓm
  bisemimodule = record { isBisemimodule = isBisemimodule }

  open Bisemimodule bisemimodule public
    using ( leftSemimodule; rightSemimodule
          ; +ᴹ-commutativeMonoid; +ᴹ-monoid; +ᴹ-semigroup; +ᴹ-magma
          ; +ᴹ-rawMagma; +ᴹ-rawMonoid)

  open SetR ≈ᴹ-setoid

  *ₗ-comm : L.Commutative _*ₗ_
  *ₗ-comm x y m = begin
    x *ₗ y *ₗ m   ≈⟨ ≈ᴹ-sym (*ₗ-assoc x y m) ⟩
    (x * y) *ₗ m  ≈⟨ *ₗ-cong (*-comm _ _) ≈ᴹ-refl ⟩
    (y * x) *ₗ m  ≈⟨ *ₗ-assoc y x m ⟩
    y *ₗ x *ₗ m   ∎

  *ᵣ-comm : R.Commutative _*ᵣ_
  *ᵣ-comm m x y = begin
    m *ᵣ x *ᵣ y   ≈⟨ *ᵣ-assoc m x y ⟩
    m *ᵣ (x * y)  ≈⟨ *ᵣ-cong ≈ᴹ-refl (*-comm _ _) ⟩
    m *ᵣ (y * x)  ≈⟨ ≈ᴹ-sym (*ᵣ-assoc m y x) ⟩
    m *ᵣ y *ᵣ x   ∎

record Module (commutativeRing : CommutativeRing r ℓr) m ℓm
              : Set (r ⊔ ℓr ⊔ suc (m ⊔ ℓm)) where
  open CommutativeRing commutativeRing

  infixr 8 -ᴹ_
  infixr 7 _*ₗ_
  infixl 6 _+ᴹ_
  infix 4 _≈ᴹ_

  field
    Carrierᴹ : Set m
    _≈ᴹ_ : Rel Carrierᴹ ℓm
    _+ᴹ_ : Op₂ Carrierᴹ
    _*ₗ_ : Opₗ Carrier Carrierᴹ
    _*ᵣ_ : Opᵣ Carrier Carrierᴹ
    0ᴹ : Carrierᴹ
    -ᴹ_ : Op₁ Carrierᴹ
    isModule : IsModule commutativeRing _≈ᴹ_ _+ᴹ_ 0ᴹ -ᴹ_ _*ₗ_ _*ᵣ_

  open IsModule isModule public

  bimodule : Bimodule ring ring m ℓm
  bimodule = record { isBimodule = isBimodule }

  open Bimodule bimodule public
    using ( leftModule; rightModule; leftSemimodule; rightSemimodule
          ; +ᴹ-abelianGroup; +ᴹ-group; +ᴹ-commutativeMonoid; +ᴹ-monoid
          ; +ᴹ-semigroup; +ᴹ-magma ; +ᴹ-rawMonoid; +ᴹ-rawMagma)

  semimodule : Semimodule commutativeSemiring m ℓm
  semimodule = record { isSemimodule = isSemimodule }

  open Semimodule semimodule public using (*ₗ-comm; *ᵣ-comm)


module Cats.Category.Preorder.Facts.PreorderAsCategory where

open import Data.Bool using (true ; false)
open import Relation.Binary using (Preorder)

import Level

open import Cats.Category
open import Cats.Category.Preorder using (preorderAsCategory)
open import Cats.Util.Logic.Constructive

module _ {lc l≈ l≤} (P : Preorder lc l≈ l≤) where

  C : Category _ _ _
  C = preorderAsCategory P

  open module P = Preorder P using (_∼_) renaming (_≈_ to _≋_)
  open Category C

  _≈_⊔_ : Obj → Obj → Obj → Set l≤
  lub ≈ x ⊔ y = x ∼ lub ∧ y ∼ lub ∧ (lub ∼ x ∨ lub ∼ y)

  _≈_⊓_ : Obj → Obj → Obj → Set l≤
  glb ≈ x ⊓ y = glb ∼ x ∧ glb ∼ y ∧ (x ∼ glb ∨ y ∼ glb)

  IsMinimum : Obj → Set (lc Level.⊔ l≤)
  IsMinimum m = ∀ x → m ∼ x

  IsMaximum : Obj → Set (lc Level.⊔ l≤)
  IsMaximum m = ∀ x → x ∼ m

  initial : ∀ {x} → IsMinimum x → IsInitial x
  initial min y = ∃!-intro (min y) _ _

  terminal : ∀ {x} → IsMaximum x → IsTerminal x
  terminal max y = ∃!-intro (max y) _ _

  ⊓-isBinaryProduct : ∀ {glb x y}
    → (pl : glb ∼ x)
    → (pr : glb ∼ y)
    → (x ∼ glb ∨ y ∼ glb)
    → IsBinaryProduct glb pl pr
  ⊓-isBinaryProduct pl pr (∨-introl x∼glb) xl xr = ∃!-intro (x∼glb ∘ xl) _ _
  ⊓-isBinaryProduct pl pr (∨-intror y∼glb) xl xr = ∃!-intro (y∼glb ∘ xr) _ _

  ⊓-to-BinaryProduct : ∀ {glb x y} → glb ≈ x ⊓ y → BinaryProduct x y
  ⊓-to-BinaryProduct {glb} (pl , pr , maximal)
      = mkBinaryProduct pl pr (⊓-isBinaryProduct pl pr maximal)

  mono : ∀ {x y} (f : x ⇒ y) → IsMono f
  mono = _

  epi : ∀ {x y} (f : x ⇒ y) → IsEpi f
  epi = _

  unique : ∀ {x y} (f : x ⇒ y) → IsUnique f
  unique = _


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Relation.Unary where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Univalence
open import Cubical.Classes
import Cubical.Foundations.Logic as L

open import Cubical.Data.Sigma
open import Cubical.Data.Empty using (⊥)
open import Cubical.Data.Sum.Base using (_⊎_; rec)
open import Cubical.Foundations.Function

open import Cubical.Relation.Nullary
open import Cubical.Relation.Nullary.Decidable using (IsYes)

private
  variable
    a b c ℓ ℓ₁ ℓ₂ : Level
    A : Type a
    B : Type b
    C : Type c

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

-- Unary relations are known as predicates and `Pred A ℓ` can be viewed
-- as some property that elements of type A might satisfy.

-- Consequently `P : Pred A ℓ` can also be seen as a subset of A
-- containing all the elements of A that satisfy property P. This view
-- informs much of the notation used below.

RawPred : Type a → (ℓ : Level) → Type _
RawPred A ℓ = A → Type ℓ

Pred : Type a → (ℓ : Level) → Type _
Pred A ℓ = A → hProp ℓ

isPropValued : RawPred A ℓ → Type _
isPropValued P = ∀ x → isProp (P x)

instance
  PredCast : Cast (Pred A ℓ) (RawPred A ℓ)
  PredCast = record { [_] = λ P x → P x .fst }

isProp[_] : (P : Pred A ℓ) → isPropValued [ P ]
isProp[ P ] x = P x .snd

fromRaw : (P : RawPred A ℓ) → isPropValued P → Pred A ℓ
fromRaw P isPropP x .fst = P x
fromRaw P isPropP x .snd = isPropP x

------------------------------------------------------------------------
-- Special sets

-- The empty set.

∅ : Pred A _
∅ _ = L.⊥

-- The singleton set.

｛_｝ : A → Pred A _
｛ x ｝ = L._≡ₚ x

-- The universal set.

U : Pred A _
U _ = L.⊤

open import Cubical.Data.Unit public using (tt)

------------------------------------------------------------------------
-- Membership

infix 6 _∈_ _∉_

_∈_ : A → Pred A ℓ → Type _
x ∈ P = ⟨ P x ⟩

_∉_ : A → Pred A ℓ → Type _
x ∉ P = ¬ x ∈ P

------------------------------------------------------------------------
-- Subset relations

infix 6 _⊆_ _⊇_ _⊈_ _⊉_ _⊂_ _⊃_ _⊄_ _⊅_

_⊆_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⊆ Q = ∀ {x} → x ∈ P → x ∈ Q

_⊇_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⊇ Q = Q ⊆ P

_⊈_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⊈ Q = ¬ (P ⊆ Q)

_⊉_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⊉ Q = ¬ (P ⊇ Q)

_⊂_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⊂ Q = P ⊆ Q × Q ⊈ P

_⊃_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⊃ Q = Q ⊂ P

_⊄_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⊄ Q = ¬ (P ⊂ Q)

_⊅_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⊅ Q = ¬ (P ⊃ Q)

------------------------------------------------------------------------
-- Properties of sets

infix 10 Satisfiable Universal IUniversal

-- Emptiness - no element satisfies P.

Empty : Pred A ℓ → Type _
Empty P = ∀ x → x ∉ P

-- Satisfiable - at least one element satisfies P.

Satisfiable : Pred A ℓ → Type _
Satisfiable {A = A} P = ∃[ x ∈ A ] x ∈ P

syntax Satisfiable P = ∃⟨ P ⟩

-- Universality - all elements satisfy P.

Universal : Pred A ℓ → Type _
Universal P = ∀ x → x ∈ P

syntax Universal P = Π[ P ]

-- Implicit universality - all elements satisfy P.

IUniversal : Pred A ℓ → Type _
IUniversal P = ∀ {x} → x ∈ P

syntax IUniversal P = ∀[ P ]

-- Decidability - it is possible to determine if an arbitrary element
-- satisfies P.

Decidable : Pred A ℓ → Type _
Decidable P = ∀ x → Dec (x ∈ P)

-- Disjointness - Any element satifsying both P and Q is contradictory.

_⊃⊂_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
_⊃⊂_ P Q = ∀ {x} → x ∈ P → x ∈ Q → ⊥

-- Positive version of non-disjointness, dual to inclusion.

_≬_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
_≬_ {A = A} P Q = ∃[ x ∈ A ] x ∈ P × x ∈ Q

------------------------------------------------------------------------
-- Operations on sets

infix 10 ⋃ ⋂
infixr 9 _⊢_ _⊣_
infixr 8 _⇒_
infixr 7 _∩_
infixr 6 _∪_
infix 5 _≬_

-- Complement.

∁ : Pred A ℓ → Pred A ℓ
∁ P = λ x → L.¬ P x

-- Implication.

_⇒_ : Pred A ℓ₁ → Pred A ℓ₂ → Pred A _
P ⇒ Q = λ x → P x L.⇒ Q x

-- Union.

_∪_ : Pred A ℓ₁ → Pred A ℓ₂ → Pred A _
P ∪ Q = λ x → P x L.⊔ Q x

-- Intersection.

_∩_ : Pred A ℓ₁ → Pred A ℓ₂ → Pred A _
P ∩ Q = λ x → P x L.⊓ Q x

-- Infinitary union.

⋃ : ∀ {i} (I : Type i) → (I → Pred A ℓ) → Pred A _
⋃ I P = λ x → L.∃[ i ∶ I ] P i x

syntax ⋃ I (λ i → P) = ⋃[ i ∶ I ] P

-- Infinitary intersection.
⋂ : ∀ {i} (I : Type i) → (I → Pred A ℓ) → Pred A _
⋂ I P = λ x → ((i : I) → x ∈ P i) , isPropΠ λ i → isProp[ P i ] x

syntax ⋂ I (λ i → P) = ⋂[ i ∶ I ] P

-- Preimage.

_⊢_ : (A → B) → Pred B ℓ → Pred A ℓ
f ⊢ P = λ x → P (f x)

-- Image.

_⊣_ : (A → B) → Pred A ℓ → Pred B _
f ⊣ P = λ x → L.∥ Σ[ (y , _) ∈ Σ _ (_∈ P) ] (f y ≡ x) ∥ₚ

------------------------------------------------------------------------
-- Preservation under operations

_Preserves_⟶_ : (A → B) → Pred A ℓ₁ → Pred B ℓ₂ → Type _
f Preserves P ⟶ Q = P ⊆ f ⊢ Q

_Preserves_ : (A → A) → Pred A ℓ → Type _
f Preserves P = f Preserves P ⟶ P

-- A binary variant of _Preserves_⟶_.

_Preserves₂_⟶_⟶_ : (A → B → C) → Pred A ℓ₁ → Pred B ℓ₂ → Pred C ℓ → Type _
_∙_ Preserves₂ P ⟶ Q ⟶ R = ∀ {x y} → x ∈ P → y ∈ Q → x ∙ y ∈ R

_Preserves₂_ : (A → A → A) → Pred A ℓ → Type _
_∙_ Preserves₂ P = _∙_ Preserves₂ P ⟶ P ⟶ P

------------------------------------------------------------------------
-- Logical equivalence

infix 8 _⇔_ _⇚⇛_

_⇔_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⇔ Q = P ⊆ Q × P ⊇ Q

-- Direct logical equivalence (more useful for proofs)

_⇚⇛_ : Pred A ℓ₁ → Pred A ℓ₂ → Type _
P ⇚⇛ Q = ∀ x → x ∈ P ≃ x ∈ Q

module _ (P : Pred A ℓ₁) (Q : Pred A ℓ₂) where

  ⇔-⇚⇛ : P ⇔ Q → P ⇚⇛ Q
  ⇔-⇚⇛ (P⊆Q , Q⊆P) x = isPropEquiv→Equiv (P x .snd) (Q x .snd) P⊆Q Q⊆P

  ⇚⇛-⇔ : P ⇚⇛ Q → P ⇔ Q
  ⇚⇛-⇔ P⇚⇛Q = equivFun (P⇚⇛Q _) , invEq (P⇚⇛Q _)

  equiv≃ : P ⇔ Q ≃ P ⇚⇛ Q
  equiv≃ = isPropEquiv→Equiv (isProp× (isPropImplicitΠ λ _ → isPropΠ λ _ → (Q _ .snd)) (isPropImplicitΠ λ _ → isPropΠ λ _ → (P _ .snd)))
                              (isPropΠ λ _ → isPropΣ (isPropΠ λ _ → Q _ .snd) (λ _ → isPropIsEquiv _)) ⇔-⇚⇛ ⇚⇛-⇔

equiv≡ : _⇔_ ≡ _⇚⇛_ {ℓ₁} {A} {ℓ₂} {ℓ}
equiv≡ = funExt (λ P → funExt (λ Q → ua (equiv≃ P Q)))

module _ (P Q : Pred A ℓ) where

  ⇚⇛toPath : P ⇚⇛ Q → P ≡ Q
  ⇚⇛toPath P⇚⇛Q = funExt (λ x → L.hProp≡ (ua (P⇚⇛Q x)))

  ⇔toPath : P ⇔ Q → P ≡ Q
  ⇔toPath P⇔Q = ⇚⇛toPath (⇔-⇚⇛ P Q P⇔Q)

------------------------------------------------------------------------
-- Predicate combinators

-- These differ from the set operations above, as the carrier set of the
-- resulting predicates are not the same as the carrier set of the
-- component predicates.

infixr  2 _⟨×⟩_
infixr  2 _⟨⊙⟩_
infixr  1 _⟨⊎⟩_
infixr  0 _⟨→⟩_
infixl  9 _⟨·⟩_
infix  10 _~
infixr  9 _⟨∘⟩_
infixr  2 _//_ _\\_

-- Product.

_⟨×⟩_ : Pred A ℓ₁ → Pred B ℓ₂ → Pred (A × B) _
(P ⟨×⟩ Q) (x , y) = P x L.⊓ Q y

-- Sum over one element.

_⟨⊎⟩_ : Pred A ℓ → Pred B ℓ → Pred (A ⊎ B) _
P ⟨⊎⟩ Q = rec P Q

-- Sum over two elements.

_⟨⊙⟩_ : Pred A ℓ₁ → Pred B ℓ₂ → Pred (A × B) _
(P ⟨⊙⟩ Q) (x , y) = P x L.⊔ Q y

-- Implication.

_⟨→⟩_ : Pred A ℓ₁ → Pred B ℓ₂ → Pred (A → B) _
(P ⟨→⟩ Q) f = (∀ {x} → x ∈ P → f x ∈ Q) , isPropImplicitΠ λ _ → isPropΠ
                                                          λ _ → isProp[ Q ] _

-- Product.

_⟨·⟩_ : (P : Pred A ℓ₁) (Q : Pred B ℓ₂) →
        (P ⟨×⟩ (P ⟨→⟩ Q)) ⊆ uncurry (flip _$_) ⊢ Q
(P ⟨·⟩ Q) (p , f) = f p

-- Converse.

_~ : Pred (A × B) ℓ → Pred (B × A) ℓ
P ~ = P ∘ λ { (x , y) → y , x }

-- Composition.

_⟨∘⟩_ : Pred (A × B) ℓ₁ → Pred (B × C) ℓ₂ → Pred (A × C) _
_⟨∘⟩_ {B = B} P Q (x , z) = L.∃[ y ∶ B ] P (x , y) L.⊓ Q (y , z)

-- Post-division.

_//_ : Pred (A × C) ℓ₁ → Pred (B × C) ℓ₂ → Pred (A × B) _
(P // Q) (x , y) = (∀ {z} → (y , z) ∈ Q → (x , z) ∈ P) ,
                      isPropImplicitΠ λ _ → isPropΠ
                                      λ _ → isProp[ P ] _

-- Pre-division.

_\\_ : Pred (A × C) ℓ₁ → Pred (A × B) ℓ₂ → Pred (B × C) _
P \\ Q = (P ~ // Q ~) ~


------------------------------------------------------------------------
-- An example showing how Container.Tree-sort can be used
------------------------------------------------------------------------

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

open import Equality

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

open Derived-definitions-and-properties eq

open import Prelude using (ℕ; zero; suc; Bool; true; false)

open import Container eq
open import Container.List eq

-- Comparison function for natural numbers.

_≤_ : ℕ → ℕ → Bool
zero  ≤ _     = true
suc _ ≤ zero  = false
suc m ≤ suc n = m ≤ n

open import Container.Tree-sort eq _≤_

-- The sort function seems to return an ordered list.

ordered : sort (3 ∷ 1 ∷ 2 ∷ []) ≡ 1 ∷ 2 ∷ 3 ∷ []
ordered = refl _

-- The sort function definitely returns a list which is bag equivalent
-- to the input. This property can be used to establish bag
-- equivalences between concrete lists.

a-bag-equivalence : 1 ∷ 2 ∷ 3 ∷ [] ≈-bag 3 ∷ 1 ∷ 2 ∷ []
a-bag-equivalence = sort≈ (3 ∷ 1 ∷ 2 ∷ [])


-- Inductively constructed substitution maps
module SOAS.ContextMaps.Inductive {T : Set} where

open import SOAS.Common
open import SOAS.Context
open import SOAS.Sorting
open import SOAS.Families.Core {T}
open import SOAS.Variable

private
  variable
    α : T
    Γ Δ : Ctx
    𝒳 𝒴 : Familyₛ

-- A list of terms in context Δ for every variable in context Γ
data Sub (𝒳 : Familyₛ) : Ctx → Ctx → Set where
  •   : Sub 𝒳 ∅ Δ
  _◂_ : 𝒳 α Δ → Sub 𝒳 Γ Δ → Sub 𝒳 (α ∙ Γ) Δ

infixl 120 _◂_

infix 150 _⟩
pattern _⟩ t  = t ◂ •

-- Functorial mapping
Sub₁ : (f : 𝒳 ⇾̣ 𝒴) → Sub 𝒳 Γ Δ → Sub 𝒴 Γ Δ
Sub₁ f • = •
Sub₁ f (x ◂ σ) = f x ◂ Sub₁ f σ

-- Conversion between inductive substitutions and context maps
module _ {𝒳 : Familyₛ} where
  index : Sub 𝒳 Γ Δ → Γ ~[ 𝒳 ]↝ Δ
  index • ()
  index (t ◂ σ) new = t
  index (t ◂ σ) (old v) = index σ v

  tabulate : Γ ~[ 𝒳 ]↝ Δ → Sub 𝒳 Γ Δ
  tabulate {Γ = ∅} σ = •
  tabulate {Γ = α ∙ Γ} σ = σ new ◂ tabulate (σ ∘ old)

  ix∘tab≈id : (σ : Γ ~[ 𝒳 ]↝ Δ) (v : ℐ α Γ)
         → index (tabulate σ) v ≡ σ v
  ix∘tab≈id {Γ = α ∙ Γ} σ new = refl
  ix∘tab≈id {Γ = α ∙ Γ} σ (old v) = ix∘tab≈id (σ ∘ old) v

  tab∘ix≈id : (σ : Sub 𝒳 Γ Δ) → tabulate (index σ) ≡ σ
  tab∘ix≈id • = refl
  tab∘ix≈id (x ◂ σ) rewrite tab∘ix≈id σ = refl

-- Naturality conditions
tabulate-nat : (f : 𝒳 ⇾̣ 𝒴)(σ : Γ ~[ 𝒳 ]↝ Δ)
          → tabulate {𝒴} (f ∘ σ) ≡ Sub₁ f (tabulate {𝒳} σ)
tabulate-nat {Γ = ∅} f σ = refl
tabulate-nat {Γ = α ∙ Γ} f σ = cong (f (σ new) ◂_) (tabulate-nat f (σ ∘ old))

index-nat : (f : 𝒳 ⇾̣ 𝒴)(σ : Sub 𝒳 Γ Δ)(v : ℐ α Γ)
          → index (Sub₁ f σ) v ≡ f (index σ v)
index-nat f (x ◂ σ) new     = refl
index-nat f (x ◂ σ) (old v) = index-nat f σ v


------------------------------------------------------------------------
-- The Agda standard library
--
-- Component functions of permutations found in `Data.Fin.Permutation`
------------------------------------------------------------------------

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

module Data.Fin.Permutation.Components where

open import Data.Bool.Base using (Bool; true; false)
open import Data.Fin.Base
open import Data.Fin.Properties
open import Data.Nat.Base as ℕ using (zero; suc; _∸_)
import Data.Nat.Properties as ℕₚ
open import Data.Product using (proj₂)
open import Function.Base using (_∘_)
open import Relation.Nullary.Reflects using (invert)
open import Relation.Nullary using (does; _because_; yes; no)
open import Relation.Nullary.Decidable using (dec-true; dec-false)
open import Relation.Binary.PropositionalEquality
open import Algebra.Definitions using (Involutive)
open ≡-Reasoning

--------------------------------------------------------------------------------
--  Functions
--------------------------------------------------------------------------------

-- 'tranpose i j' swaps the places of 'i' and 'j'.

transpose : ∀ {n} → Fin n → Fin n → Fin n → Fin n
transpose i j k with does (k ≟ i)
... | true  = j
... | false with does (k ≟ j)
...   | true  = i
...   | false = k

-- reverse i = n ∸ 1 ∸ i

reverse : ∀ {n} → Fin n → Fin n
reverse {suc n} i  = inject≤ (n ℕ- i) (ℕₚ.m∸n≤m (suc n) (toℕ i))

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

transpose-inverse : ∀ {n} (i j : Fin n) {k} →
                    transpose i j (transpose j i k) ≡ k
transpose-inverse i j {k} with k ≟ j
... | true  because [k≡j] rewrite dec-true (i ≟ i) refl = sym (invert [k≡j])
... | false because [k≢j] with k ≟ i
...   | true  because [k≡i]
        rewrite dec-false (j ≟ i) (invert [k≢j] ∘ trans (invert [k≡i]) ∘ sym)
                | dec-true (j ≟ j) refl
                = sym (invert [k≡i])
...   | false because [k≢i] rewrite dec-false (k ≟ i) (invert [k≢i])
                                  | dec-false (k ≟ j) (invert [k≢j]) = refl

reverse-prop : ∀ {n} → (i : Fin n) → toℕ (reverse i) ≡ n ∸ suc (toℕ i)
reverse-prop {suc n} i = begin
  toℕ (inject≤ (n ℕ- i) _)  ≡⟨ toℕ-inject≤ _ (ℕₚ.m∸n≤m (suc n) (toℕ i)) ⟩
  toℕ (n ℕ- i)              ≡⟨ toℕ‿ℕ- n i ⟩
  n ∸ toℕ i                 ∎

reverse-involutive : ∀ {n} → Involutive _≡_ (reverse {n})
reverse-involutive {suc n} i = toℕ-injective (begin
  toℕ (reverse (reverse i)) ≡⟨ reverse-prop (reverse i) ⟩
  n ∸ (toℕ (reverse i))     ≡⟨ cong (n ∸_) (reverse-prop i) ⟩
  n ∸ (n ∸ (toℕ i))         ≡⟨ ℕₚ.m∸[m∸n]≡n (ℕₚ.≤-pred (toℕ<n i)) ⟩
  toℕ i                     ∎)

reverse-suc : ∀ {n} {i : Fin n} → toℕ (reverse (suc i)) ≡ toℕ (reverse i)
reverse-suc {n} {i} = begin
  toℕ (reverse (suc i))      ≡⟨ reverse-prop (suc i) ⟩
  suc n ∸ suc (toℕ (suc i))  ≡⟨⟩
  n ∸ toℕ (suc i)            ≡⟨⟩
  n ∸ suc (toℕ i)            ≡⟨ sym (reverse-prop i) ⟩
  toℕ (reverse i)            ∎


module Numeral.Natural.Function.Coprimalize where

open import Data.Tuple
open import Numeral.Natural
open import Numeral.Natural.Function.GreatestCommonDivisor
open import Numeral.Natural.Oper.FlooredDivision

coprimalize : (ℕ ⨯ ℕ) → (ℕ ⨯ ℕ)
coprimalize(x , y) = ((x ⌊/⌋₀ gcd(x)(y)) , (y ⌊/⌋₀ gcd(x)(y)))

{- TODO: Maybe prove something like (b ∣ a) → ((d ∣ (a / b)) ↔ ((d ∣ a) ∧ (d ∤ b))) if it holds?
open import Numeral.Natural.Coprime
open import Relator.Equals

Coprime-coprimalize : ∀{xy} → uncurry Coprime(coprimalize xy)
Coprime.proof Coprime-coprimalize nx ny = {!!} where

n ∣ (x ⌊/⌋₀ gcd(x)(y))
(n ∣ x) ∧ (n ∤ gcd(x)(y))
-}


module Prelude.List.Relations.Any where

open import Agda.Primitive

open import Prelude.Nat
open import Prelude.List.Base
open import Prelude.Equality

open import Prelude.List.Relations.All

data Any {a b} {A : Set a} (P : A → Set b) : List A → Set (a ⊔ b) where
  zero : ∀ {x xs} (p : P x) → Any P (x ∷ xs)
  suc  : ∀ {x xs} (i : Any P xs) → Any P (x ∷ xs)

pattern zero! = zero refl

infix 3 _∈_
_∈_ : ∀ {a} {A : Set a} → A → List A → Set a
x ∈ xs = Any (_≡_ x) xs

module _ {a b} {A : Set a} {P : A → Set b} where
  -- Delete

  deleteIx : ∀ xs → Any P xs → List A
  deleteIx (_ ∷ xs) (zero _) = xs
  deleteIx (x ∷ xs) (suc  i) = x ∷ deleteIx xs i

  deleteAllIx : ∀ {c} {Q : A → Set c} {xs} → All Q xs → (i : Any P xs) → All Q (deleteIx xs i)
  deleteAllIx (q ∷ qs) (zero _) = qs
  deleteAllIx (q ∷ qs) (suc i)  = q ∷ deleteAllIx qs i

forgetAny : ∀ {a p} {A : Set a} {P : A → Set p} {xs : List A} → Any P xs → Nat
forgetAny (zero _) = zero
forgetAny (suc  i) = suc (forgetAny i)


module Functor where

import Logic.Identity as Id
import Category
import Logic.ChainReasoning

open Category
open Poly-Cat

private
 module Fun where

  data Functor (ℂ ⅅ : Cat) : Set1 where
    functor : (F     : Obj ℂ -> Obj ⅅ)
	      (map   : {A B : Obj ℂ} -> A ─→ B -> F A ─→ F B)
	      (mapId : {A : Obj ℂ} -> map (id {A = A}) == id)
	      (mapCompose : {A B C : Obj ℂ}{f : B ─→ C}{g : A ─→ B} ->
			    map (f ∘ g) == map f ∘ map g
	      ) -> Functor ℂ ⅅ

open Fun public

module Projections where

  Map : {ℂ ⅅ : Cat} -> Functor ℂ ⅅ -> Obj ℂ -> Obj ⅅ
  Map (functor F _ _ _) = F

  map : {ℂ ⅅ : Cat}(F : Functor ℂ ⅅ)
	{A B : Obj ℂ} -> A ─→ B -> Map F A ─→ Map F B
  map (functor _ m _ _) = m

  mapId : {ℂ ⅅ : Cat}(F : Functor ℂ ⅅ)
	  {A : Obj ℂ} -> map F id == id {A = Map F A}
  mapId (functor _ _ i _) = i

  mapCompose : {ℂ ⅅ : Cat}(F : Functor ℂ ⅅ)
	       {A B C : Obj ℂ}{f : B ─→ C}{g : A ─→ B} ->
	       map F (f ∘ g) == map F f ∘ map F g
  mapCompose (functor _ _ _ c) = c

module Functor {ℂ ⅅ : Cat}(F : Functor ℂ ⅅ) where

  module P = Projections

  Map : Obj ℂ -> Obj ⅅ
  Map = P.Map F

  map : {A B : Obj ℂ} -> A ─→ B -> Map A ─→ Map B
  map = P.map F

  mapId : {A : Obj ℂ} -> map id == id {A = Map A}
  mapId = P.mapId F

  mapCompose : {A B C : Obj ℂ}{f : B ─→ C}{g : A ─→ B} ->
	       map (f ∘ g) == map f ∘ map g
  mapCompose = P.mapCompose F

module Functors where

  Id : {ℂ : Cat} -> Functor ℂ ℂ
  Id = functor (\A -> A) (\f -> f) (\{A} -> refl) (\{A}{B}{C}{f}{g} -> refl)

  _○_ : {ℂ ℚ ℝ : Cat} -> Functor ℚ ℝ -> Functor ℂ ℚ -> Functor ℂ ℝ
  _○_ {ℂ}{ℚ}{ℝ} F G = functor FG m mid mcomp
    where

      module F = Functor F
      module G = Functor G

      FG : Obj ℂ -> Obj ℝ
      FG A = F.Map (G.Map A)

      m : {A B : Obj ℂ} -> A ─→ B -> FG A ─→ FG B
      m f = F.map (G.map f)

      mid : {A : Obj ℂ} -> m (id {A = A}) == id
      mid = chain> F.map (G.map id)
	       === F.map id   by ? -- cong F.map G.mapId
	       === id	      by F.mapId
	where
	  open module Chain = Logic.ChainReasoning.Mono.Homogenous _==_
			      (\f -> refl)
			      (\f g h -> trans)

      mcomp : {A B C : Obj ℂ}{f : B ─→ C}{g : A ─→ B} ->
	      m (f ∘ g) == m f ∘ m g
      mcomp {f = f}{g = g} =
	chain> F.map (G.map (f ∘ g))
	   === F.map (G.map f ∘ G.map g)
	       by ? -- cong F.map G.mapCompose
	   === F.map (G.map f) ∘ F.map (G.map g)
	       by F.mapCompose
	where
	  open module Chain = Logic.ChainReasoning.Mono.Homogenous _==_
			      (\f -> refl)
			      (\f g h -> trans)


module Adjunctions.Adj2Mon where

open import Library
open import Categories
open import Functors
open import Monads
open import Adjunctions

open Cat
open Fun

Adj2Mon : ∀{a b}{C D : Cat {a}{b}} → Adj C D → Monad C
Adj2Mon {C = C}{D} A = record{
  T    = OMap R ∘ OMap L;
  η    = left (iden D);
  bind = HMap R ∘ right;
  law1 =
    proof
    HMap R (right (left (iden D)))
    ≅⟨ cong (HMap R) (lawa (iden D)) ⟩
    HMap R (iden D)
    ≅⟨ fid R ⟩
    iden C ∎;
  law2 = λ{_}{_}{f} →
    proof
    comp C (HMap R (right f)) (left (iden D))
    ≅⟨ cong (comp C (HMap R (right f))) (sym (idr C)) ⟩
    comp C (HMap R (right f)) (comp C (left (iden D)) (iden C))
    ≅⟨ natleft (iden C) (right f) (iden D) ⟩
    left (comp D (right f) (comp D (iden D) (HMap L (iden C))))
    ≅⟨ cong (left ∘ comp D (right f)) (idl D) ⟩
    left (comp D (right f) (HMap L (iden C)))
    ≅⟨ cong (left ∘ comp D (right f)) (fid L) ⟩
    left (comp D (right f) (iden D))
    ≅⟨ cong (left) (idr D) ⟩
    left (right f)
    ≅⟨ lawb f ⟩
    f ∎;
  law3 = λ{_}{_}{_}{f}{g} →
    proof
    HMap R (right (comp C (HMap R (right g)) f))
    ≅⟨ cong (HMap R ∘ right ∘ comp C (HMap R (right g)))
            (sym (idr C)) ⟩
    HMap R (right (comp C (HMap R (right g)) (comp C f (iden C))))
    ≅⟨ cong (HMap R) (natright (iden C) (right g) f) ⟩
    HMap R (comp D (right g) (comp D (right f) (HMap L (iden C))))
    ≅⟨ cong (HMap R ∘ comp D (right g) ∘ comp D (right f)) (fid L)⟩
    HMap R (comp D (right g) (comp D (right f) (iden D)))
    ≅⟨ cong (HMap R ∘ comp D (right g)) (idr D) ⟩
    HMap R (comp D (right g) (right f))
    ≅⟨ fcomp R ⟩
    comp C (HMap R (right g)) (HMap R (right f))
    ∎}
  where open Adj A


module Operator.Equals {ℓ ℓₑ} where

open import Data.Boolean
open import Logic
open import Structure.Setoid
open import Type.Properties.Decidable
open import Type

DecidableEquiv : (T : Type{ℓ}) ⦃ equiv : Equiv{ℓₑ}(T) ⦄ → Stmt
DecidableEquiv(T) = Decidable(2)(_≡_)

_==_ : ∀{T : Type{ℓ}} ⦃ equiv : Equiv{ℓₑ}(T) ⦄ ⦃ _ : DecidableEquiv(T) ⦄ → (T → T → Bool)
_==_ = decide(2)(_≡_)


{-# OPTIONS --safe --experimental-lossy-unification #-}
module Cubical.Algebra.CommRing.Instances.MultivariatePoly where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Nat renaming(_+_ to _+n_; _·_ to _·n_)
open import Cubical.Data.Vec

open import Cubical.Algebra.Ring
open import Cubical.Algebra.CommRing

open import Cubical.Algebra.Polynomials.Multivariate.Base
open import Cubical.Algebra.Polynomials.Multivariate.Properties

private variable
  ℓ ℓ' : Level

module _ (A' : CommRing ℓ) (n : ℕ) where

  private
    A = fst A'
    Ar = CommRing→Ring A'

  open CommRingStr
  open RingTheory Ar
  open Nth-Poly-structure A' n

  PolyCommRing : CommRing ℓ
  fst PolyCommRing = Poly A' n
  0r (snd PolyCommRing) = 0P
  1r (snd PolyCommRing) = 1P
  _+_ (snd PolyCommRing) = _Poly+_
  _·_ (snd PolyCommRing) = _Poly*_
  - snd PolyCommRing = Poly-inv
  isCommRing (snd PolyCommRing) = makeIsCommRing
                                  trunc
                                  Poly+-assoc
                                  Poly+-Rid
                                  Poly+-rinv
                                  Poly+-comm
                                  Poly*-assoc
                                  Poly*-Rid
                                  Poly*-Rdist
                                  Poly*-comm


{-# OPTIONS --without-K #-}
open import Data.Nat
open import Data.Two
open import Data.Zero
open import Data.Fin.NP
open import Type
open import Function
open import Relation.Binary.PropositionalEquality.NP

import Explore.Universe.Base
open import Explore.Core
open import Explore.Zero
open import Explore.One
open import Explore.Two
open import Explore.Universe.Type

-- Exploring Fin comes in two flavors Regular & Custom
-- We recommend Regular if you want to work for arbitrary values of n.
-- We recommend Custom if you want to work for particular values of n (2, 6...).
module Explore.Fin where

module Regular n = Explore.Universe.Base (≃ᵁ (Finᵁ n) (Fin n) (Finᵁ≃Fin n))

module Custom where
  module _ n where
    open Explore.Universe.Base (≃ᵁ (Finᵁ' n) (Fin n) (Finᵁ'≃Fin n))
      public

  Finᵉ0-𝟘ᵉ : (λ {M : ★₀} (ε : M) op f → explore 0 ε op (f ∘ Fin▹𝟘)) ≡ 𝟘ᵉ
  Finᵉ0-𝟘ᵉ = refl

  Finᵉ1-𝟙ᵉ : (λ {M : ★₀} (ε : M) op f → explore 1 ε op (f ∘ Fin▹𝟙)) ≡ 𝟙ᵉ
  Finᵉ1-𝟙ᵉ = refl

  Finᵉ2-𝟚ᵉ : (λ {M : ★₀} (ε : M) op f → explore 2 ε op (f ∘ Fin▹𝟚)) ≡ 𝟚ᵉ
  Finᵉ2-𝟚ᵉ = refl

module ByHand {ℓ} where
  Finᵉ' : ∀ n → Explore ℓ (Fin n)
  Finᵉ' zero    z _⊕_ f = z
  Finᵉ' (suc n) z _⊕_ f = f zero ⊕ Finᵉ' n z _⊕_ (f ∘ suc)

  -- Finᵉ and Finᵉ' are extensionally equal.
  -- Moreover the simplicity of the proof shows that the two functions are computing
  -- in the same way.
  Finᵉ-Finᵉ' : ∀ n {M} (ε : M) (_⊕_ : M → M → M) (f : Fin n → M) → Regular.explore n ε _⊕_ f ≡ Finᵉ' n ε _⊕_ f
  Finᵉ-Finᵉ' zero    ε _⊕_ f = idp
  Finᵉ-Finᵉ' (suc n) ε _⊕_ f = ap (_⊕_ (f zero))
                                  (Finᵉ-Finᵉ' n ε _⊕_ (f ∘ suc))


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

open import Cubical.Core.Primitives
open import Cubical.Data.Nat
open import Cubical.Data.Empty

record ℕ₋₁ : Type₀ where
  constructor -1+_
  field
    n : ℕ

pattern neg1 = -1+ zero
pattern ℕ→ℕ₋₁ n = -1+ (suc n)

1+_ : ℕ₋₁ → ℕ
1+_ (-1+ n) = n

suc₋₁ : ℕ₋₁ → ℕ₋₁
suc₋₁ (-1+ n) = -1+ (suc n)

-- Natural number and negative integer literals for ℕ₋₁

open import Cubical.Data.Nat.Literals public

instance
  fromNatℕ₋₁ : HasFromNat ℕ₋₁
  fromNatℕ₋₁ = record { Constraint = λ _ → Unit ; fromNat = ℕ→ℕ₋₁ }

instance
  fromNegℕ₋₁ : HasFromNeg ℕ₋₁
  fromNegℕ₋₁ = record { Constraint = λ { (suc (suc _)) → ⊥ ; _ → Unit }
                       ; fromNeg = λ { zero → 0 ; (suc zero) → neg1 } }


module Data.Tuple.Function where

open import Data
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Functional
open import Type

module _ {ℓ₁ ℓ₂ ℓ₃} {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} {T₃ : Type{ℓ₃}} where
  _,⃝_ : (T₁ → T₂) → (T₁ → T₃) → (T₁ → (T₂ ⨯ T₃))
  _,⃝_ f g x = (f(x) , g(x))

  left : (T₁ → (T₂ ⨯ T₃)) → (T₁ → T₂)
  left =  Tuple.left ∘_

  right : (T₁ → (T₂ ⨯ T₃)) → (T₁ → T₃)
  right =  Tuple.right ∘_


module Oscar.Property.Extensionality where

open import Oscar.Level

record Extensionality
  {a} {A : Set a} {b} {B : A → Set b} {ℓ₁}
    (_≤₁_ : (x : A) → B x → Set ℓ₁)
  {c} {C : A → Set c} {d} {D : ∀ {x} → B x → Set d} {ℓ₂}
    (_≤₂_ : ∀ {x} → C x → ∀ {y : B x} → D y → Set ℓ₂)
    (μ₁ : (x : A) → C x)
    (μ₂ : ∀ {x} → (y : B x) → D y)
  : Set (a ⊔ ℓ₁ ⊔ b ⊔ ℓ₂) where
  field
    extensionality : ∀ {x} {y : B x} → x ≤₁ y → μ₁ x ≤₂ μ₂ y

open Extensionality ⦃ … ⦄ public

extension : ∀
    {a} {A : Set a}
    {b} {B : A → Set b}
    {ℓ₁} {_≤₁_ : (x : A) → B x → Set ℓ₁}
    {c} {C : A → Set c} {d} {D : ∀ {x} → B x → Set d} {ℓ₂}
  (_≤₂_ : ∀ {x} → C x → ∀ {y : B x} → D y → Set ℓ₂)
    {μ₁ : (x : A) → C x}
    {μ₂ : ∀ {x} → (y : B x) → D y}
  ⦃ _ : Extensionality _≤₁_ _≤₂_ μ₁ μ₂ ⦄
    {x} {y : B x}
  → x ≤₁ y → μ₁ x ≤₂ μ₂ y
extension _≤₂_ = extensionality {_≤₂_ = _≤₂_}