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

module Categories.Functor.Duality where

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

open import Categories.Category
open import Categories.Category.Construction.Cones as Con
open import Categories.Category.Construction.Cocones as Coc
open import Categories.Functor
open import Categories.Functor.Continuous
open import Categories.Functor.Cocontinuous
open import Categories.Diagram.Limit as Lim
open import Categories.Diagram.Colimit as Col
open import Categories.Diagram.Duality
open import Categories.Morphism.Duality as MorD

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

module _ (G : Functor C D) {J : Category o ℓ e} where
  private
    module C = Category C
    module D = Category D
    module G = Functor G
    module J = Category J

  coLimitPreserving⇒ColimitPreserving : ∀ {F : Functor J C} (L : Limit (Functor.op F)) →
                                          LimitPreserving G.op L →
                                          ColimitPreserving G (coLimit⇒Colimit C L)
  coLimitPreserving⇒ColimitPreserving L (L′ , iso) = coLimit⇒Colimit D L′ , op-≅⇒≅ D iso

  ColimitPreserving⇒coLimitPreserving : ∀ {F : Functor J C} (L : Colimit F) →
                                          ColimitPreserving G L →
                                          LimitPreserving G.op (Colimit⇒coLimit C L)
  ColimitPreserving⇒coLimitPreserving L (L′ , iso) = Colimit⇒coLimit D L′ , op-≅⇒≅ D.op iso

module _ {o ℓ e} (G : Functor C D) where
  private
    module G = Functor G

  coContinuous⇒Cocontinuous : Continuous o ℓ e G.op → Cocontinuous o ℓ e G
  coContinuous⇒Cocontinuous Con L =
    coLimitPreserving⇒ColimitPreserving G (Colimit⇒coLimit C L) (Con (Colimit⇒coLimit C L))

  Cocontinuous⇒coContinuous : Cocontinuous o ℓ e G → Continuous o ℓ e G.op
  Cocontinuous⇒coContinuous Coc L =
    ColimitPreserving⇒coLimitPreserving G (coLimit⇒Colimit C L) (Coc (coLimit⇒Colimit C L))


------------------------------------------------------------------------
-- INCREMENTAL λ-CALCULUS
--
-- Bags of integers, for Nehemiah plugin.
--
-- This module imports postulates about bags of integers
-- with negative multiplicities as a group under additive union.
------------------------------------------------------------------------

module Structure.Bag.Nehemiah where

open import Postulate.Bag-Nehemiah public

open import Relation.Binary.PropositionalEquality
open import Algebra using (CommutativeRing)
open import Algebra.Structures
open import Data.Integer
open import Data.Integer.Properties
  using ()
  renaming (+-*-commutativeRing to ℤ-is-commutativeRing)
open import Data.Product

infixl 9 _\\_ -- same as Data.Map.(\\)
_\\_ : Bag → Bag → Bag
d \\ b = d ++ (negateBag b)

-- Useful properties of abelian groups
commutative : ∀ {A : Set} {f : A → A → A} {z} →
  IsCommutativeMonoid _≡_ f z → (m n : A) → f m n ≡ f n m
commutative = IsCommutativeMonoid.comm

associative : ∀ {A : Set} {f : A → A → A} {z} →
  IsCommutativeMonoid _≡_ f z → (k m n : A) → f (f k m) n ≡ f k (f m n)
associative abelian = IsCommutativeMonoid.assoc abelian

left-inverse : ∀ {A : Set} {f : A → A → A} {z neg} →
  IsAbelianGroup _≡_ f z neg → (n : A) → f (neg n) n ≡ z
left-inverse abelian = proj₁ (IsAbelianGroup.inverse abelian)
right-inverse : ∀ {A : Set} {f : A → A → A} {z neg} →
  IsAbelianGroup _≡_ f z neg → (n : A) → f n (neg n) ≡ z
right-inverse abelian = proj₂ (IsAbelianGroup.inverse abelian)

left-identity : ∀ {A : Set} {f : A → A → A} {z neg} →
  IsAbelianGroup _≡_ f z neg → (n : A) → f z n ≡ n
left-identity abelian = proj₁ (IsMonoid.identity
  (IsGroup.isMonoid (IsAbelianGroup.isGroup abelian)))
right-identity : ∀ {A : Set} {f : A → A → A} {z neg} →
  IsAbelianGroup _≡_ f z neg → (n : A) → f n z ≡ n
right-identity abelian = proj₂ (IsMonoid.identity
  (IsGroup.isMonoid (IsAbelianGroup.isGroup abelian)))

instance
  abelian-int : IsAbelianGroup _≡_ _+_ (+ 0) (-_)
  abelian-int =
    CommutativeRing.+-isAbelianGroup ℤ-is-commutativeRing

  abelian→comm-monoid :
   ∀ {A : Set} {f : A → A → A} {z neg} →
   {{abel : IsAbelianGroup _≡_ f z neg}} → IsCommutativeMonoid _≡_ f z
  abelian→comm-monoid {{abel}} = IsAbelianGroup.isCommutativeMonoid abel

  comm-monoid-int : IsCommutativeMonoid _≡_ _+_ (+ 0)
  comm-monoid-int = IsAbelianGroup.isCommutativeMonoid abelian-int
  comm-monoid-bag : IsCommutativeMonoid _≡_ _++_ emptyBag
  comm-monoid-bag = IsAbelianGroup.isCommutativeMonoid abelian-bag

  import Data.Nat as N
  import Data.Nat.Properties as NP
  comm-monoid-nat : IsCommutativeMonoid _≡_ N._+_ 0
  comm-monoid-nat = IsCommutativeSemiring.+-isCommutativeMonoid NP.isCommutativeSemiring

commutative-int : (m n : ℤ) → m + n ≡ n + m
commutative-int = commutative comm-monoid-int
associative-int : (k m n : ℤ) → (k + m) + n ≡ k + (m + n)
associative-int = associative comm-monoid-int
right-inv-int : (n : ℤ) → n - n ≡ + 0
right-inv-int = right-inverse abelian-int
left-id-int : (n : ℤ) → (+ 0) + n ≡ n
left-id-int = left-identity abelian-int
right-id-int : (n : ℤ) → n + (+ 0) ≡ n
right-id-int = right-identity abelian-int

commutative-bag : (a b : Bag) → a ++ b ≡ b ++ a
commutative-bag = commutative comm-monoid-bag
associative-bag : (a b c : Bag) → (a ++ b) ++ c ≡ a ++ (b ++ c)
associative-bag = associative comm-monoid-bag
right-inv-bag : (b : Bag) → b \\ b ≡ emptyBag
right-inv-bag = right-inverse abelian-bag
left-id-bag : (b : Bag) → emptyBag ++ b ≡ b
left-id-bag = left-identity abelian-bag
right-id-bag : (b : Bag) → b ++ emptyBag ≡ b
right-id-bag = right-identity abelian-bag


postulate
  A : Set

data B (a : A) : Set where
  conB : B a → B a

data C (a : A) : B a → Set where
  conC : (b : B a) → C a (conB b)

goo : (a1 a2 a3 : A) (c : C a1 _) → Set
goo a1 a2 a3 (conC b) = {!!}


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

open import lib.Basics
open import lib.NType2
open import lib.types.Group
open import lib.types.Sigma
open import lib.types.Truncation
open import lib.groups.Homomorphisms

module lib.groups.PropSubgroup where

module _ {i} (G : Group i) where

  private
    module G = Group G

  module PropSubgroup {j} (P : G.El → Type j)
    (P-level : ∀ g → has-level -1 (P g))
    (P-ident : P G.ident) (P-inv : ∀ {g} → P g → P (G.inv g))
    (P-comp : ∀ {g₁ g₂} → P g₁ → P g₂ → P (G.comp g₁ g₂)) where

    struct : GroupStructure (Σ G.El P)
    struct = record {
      ident = (G.ident , P-ident);
      inv = λ {(g , p) → (G.inv g , P-inv p)};
      comp = λ {(g₁ , p₁) (g₂ , p₂) → (G.comp g₁ g₂ , P-comp p₁ p₂)};
      unitl = λ {(g , _) →
        pair= (G.unitl g) (prop-has-all-paths-↓ (P-level _))};
      unitr = λ {(g , _) →
        pair= (G.unitr g) (prop-has-all-paths-↓ (P-level _))};
      assoc = λ {(g₁ , _) (g₂ , _) (g₃ , _) →
        pair= (G.assoc g₁ g₂ g₃) (prop-has-all-paths-↓ (P-level _))};
      invl = λ {(g , _) →
        pair= (G.invl g) (prop-has-all-paths-↓ (P-level _))};
      invr = λ {(g , _) →
        pair= (G.invr g) (prop-has-all-paths-↓ (P-level _))}}

    Subgroup : Group (lmax i j)
    Subgroup = group _ (Σ-level G.El-level (raise-level _ ∘ P-level)) struct

    inj : Subgroup →ᴳ G
    inj = record {
      f = λ {(g , _) → g};
      pres-comp = λ _ _ → idp}

    module _ {j} {H : Group j} (φ : H →ᴳ G) where

      private
        module H = Group H
        module φ = GroupHom φ

      prop-hom : Π H.El (P ∘ φ.f) → (H →ᴳ Subgroup)
      prop-hom p = record {
        f = λ g → (φ.f g , p g);
        pres-comp = λ g₁ g₂ →
          pair= (φ.pres-comp g₁ g₂) (prop-has-all-paths-↓ (P-level _))}

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

  private
    module G = Group G
    module H = Group H
    module φ = GroupHom φ

    module Ker = PropSubgroup G (λ g → φ.f g == H.ident)
      (λ g → H.El-level _ _) φ.pres-ident
      (λ p → φ.pres-inv _ ∙ ap H.inv p ∙ group-inv-ident H)
      (λ p₁ p₂ → φ.pres-comp _ _ ∙ ap2 H.comp p₁ p₂ ∙ H.unitl _)

    module Im = PropSubgroup H (λ h → Trunc -1 (Σ G.El (λ g → φ.f g == h)))
      (λ h → Trunc-level) ([ G.ident , φ.pres-ident ])
      (Trunc-fmap (λ {(g , p) →
        (G.inv g , φ.pres-inv g ∙ ap H.inv p)}))
      (Trunc-fmap2 (λ {(g₁ , p₁) (g₂ , p₂) →
        (G.comp g₁ g₂ , φ.pres-comp g₁ g₂ ∙ ap2 H.comp p₁ p₂)}))

  open Ker public renaming
    (struct to ker-struct; Subgroup to Ker;
     inj to ker-inj; prop-hom to ker-hom)

  open Im public renaming
    (struct to im-struct; Subgroup to Im;
     inj to im-inj; prop-hom to im-out-hom)

  im-in-hom : G →ᴳ Im
  im-in-hom = record {
    f = λ g → (φ.f g , [ g , idp ]);
    pres-comp = λ g₁ g₂ →
      pair= (φ.pres-comp g₁ g₂) (prop-has-all-paths-↓ Trunc-level)}

  im-in-surj : (h : Group.El Im)
    → Trunc -1 (Σ G.El (λ g → GroupHom.f im-in-hom g == h))
  im-in-surj (_ , s) = Trunc-fmap (λ {(g , p) →
    (g , pair= p (prop-has-all-paths-↓ Trunc-level))}) s


-- Intuitionistic propositional logic, de Bruijn approach, final encoding

module Bf.Ip where

open import Lib using (List; _,_; LMem; lzero; lsuc)

-- 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 : Set
Cx = List Ty

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

-- Terms

TmRepr : Set1
TmRepr = Cx -> Ty -> Set

module ArrMp where
  record Tm (tr : TmRepr) : Set1 where
    infixl 1 _$_
    infixr 0 lam=>_
    field
      var    : forall {tc a}   -> isTrue a tc               -> tr tc a
      lam=>_ : forall {tc a b} -> tr (tc , a) b             -> tr tc (a => b)
      _$_    : forall {tc a b} -> tr tc (a => b) -> tr tc a -> tr tc b

    v0 : forall {tc a} -> tr (tc , a) a
    v0 = var lzero

    v1 : forall {tc a b} -> tr (tc , a , b) a
    v1 = var (lsuc lzero)

    v2 : forall {tc a b c} -> tr (tc , a , b , c) a
    v2 = var (lsuc (lsuc lzero))
  open Tm {{...}} public

module Mp where
  record Tm (tr : TmRepr) : Set1 where
    field
      pair' : forall {tc a b}   -> tr tc a        -> tr tc b -> tr tc (a && b)
      fst   : forall {tc a b}   -> tr tc (a && b)            -> tr tc a
      snd   : forall {tc a b}   -> tr tc (a && b)            -> tr tc b
      left  : forall {tc a b}   -> tr tc a                   -> tr tc (a || b)
      right : forall {tc a b}   -> tr tc b                   -> tr tc (a || b)
      case' : forall {tc a b c} -> tr tc (a || b) -> tr (tc , a) c -> tr (tc , b) c -> tr tc c

      isArrMp : ArrMp.Tm tr
    open ArrMp.Tm isArrMp public

    syntax pair' x y    = [ x , y ]
    syntax case' xy x y = case xy => x => y
  open Tm {{...}} public

module Ip where
  record Tm (tr : TmRepr) : Set1 where
    field
      abort : forall {tc a} -> tr tc FALSE -> tr tc a

      isMp : Mp.Tm tr
    open Mp.Tm isMp public
  open Tm {{...}} public

  Thm : Ty -> Set1
  Thm a = forall {tr tc} {{_ : Tm tr}} -> tr tc a
open Ip public

-- Example theorems

t1 : forall {a b} -> Thm (a => NOT a => b)
t1 =
  lam=>
    lam=> abort (v0 $ v1)

t2 : forall {a b} -> Thm (NOT a => a => b)
t2 =
  lam=>
    lam=> abort (v1 $ v0)

t3 : forall {a} -> Thm (a => NOT (NOT a))
t3 =
  lam=>
    lam=> v0 $ v1

t4 : forall {a} -> Thm (NOT a <=> NOT (NOT (NOT a)))
t4 =
  [ lam=>
      lam=> v0 $ v1
  , lam=>
      lam=> v1 $ (lam=> v0 $ v1)
  ]


{-# OPTIONS --enable-prop #-}

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

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


module _ where

id : {A : Set} → A → A
id x = x

const : {A : Set₁} {B : Set} → A → (B → A)
const x = λ _ → x

{-# DISPLAY const x y = x #-}

infixr 4 _,_
infixr 2 _×_

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

open Σ public

_×_ : (A B : Set) → Set
A × B = Σ A (const B)

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

foo : {A B : Set} → A × B → A × B
foo = Σ-map id {!!}


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

module Dodo.Binary.Disjoint where

-- Stdlib imports
open import Level using (Level; _⊔_) renaming (suc to ℓsuc)
open import Data.Empty using (⊥)
open import Data.Product using (_,_)
open import Relation.Unary using (Pred)
open import Relation.Binary using (REL)
open import Data.List using (List; _∷_; []; all; map)
open import Data.List.Relation.Unary.Any using (Any; here; there)
open import Relation.Nullary using (¬_)
-- Local imports
open import Dodo.Binary.Empty
open import Dodo.Binary.Equality
open import Dodo.Binary.Intersection

-- # Definitions

-- | Predicate stating two binary relations are never inhabited for the same elements.
Disjoint₂ : ∀ {a b ℓ₁ ℓ₂ : Level} {A : Set a} {B : Set b}
  → REL A B ℓ₁ → REL A B ℓ₂ → Set _
Disjoint₂ P Q = Empty₂ (P ∩₂ Q)

-- | Given a predicate `P`, `Any₂ P xs` states that /at least two/ elements in
-- `xs` satisfy `P`.
data Any₂ {a ℓ : Level} {A : Set a} (P : Pred A ℓ) : Pred (List A) (a ⊔ ℓ) where
  here  : ∀ {x xs} (px : P x) → Any P xs → Any₂ P (x ∷ xs)
  there : ∀ {x xs} (pxs : Any₂ P xs) → Any₂ P (x ∷ xs)

-- | A predicate stating any two predicates in the list cannot be inhabitated for the same elements.
PairwiseDisjoint₁ : {a ℓ : Level} {A : Set a} → List (Pred A ℓ) → Set (a ⊔ ℓsuc ℓ)
PairwiseDisjoint₁ Ps = ∀ {x} → Any₂ (λ{P → P x}) Ps → ⊥

-- | A predicate stating any two binary relations in the list cannot be inhabitated for the same elements.
PairwiseDisjoint₂ : {a b ℓ : Level} {A : Set a} {B : Set b} → List (REL A B ℓ) → Set (a ⊔ b ⊔ ℓsuc ℓ)
PairwiseDisjoint₂ Rs = ∀ {x y} → Any₂ (λ{R → R x y}) Rs → ⊥

-- # Properties

module _ {a b ℓ₁ ℓ₂ : Level} {A : Set a} {B : Set b} {P : REL A B ℓ₁} {Q : REL A B ℓ₂} where

  -- | If P is disjoint with Q, then Q is surely also disjoint with P.
  disjoint₂-sym : Disjoint₂ P Q → Disjoint₂ Q P
  disjoint₂-sym disjointPQ x y [Q∩P]xy =
    let [P∩Q]xy = ⇔₂-apply-⊆₂ (∩₂-comm {P = Q} {Q = P}) [Q∩P]xy
    in disjointPQ x y [P∩Q]xy

module _ {a b ℓ : Level} {A : Set a} {B : Set b} {P : REL A B ℓ} where

  -- | Every relation is disjoint with its negation.
  disjoint₂-neg : Disjoint₂ P (¬₂ P)
  disjoint₂-neg x y (Pxy , ¬Pxy) = ¬Pxy Pxy

module _ {a b ℓ₁ ℓ₂ ℓ₃ : Level} {A : Set a} {B : Set b} {P : REL A B ℓ₁} {Q : REL A B ℓ₂} {R : REL A B ℓ₃} where

  -- | If two relations P and Q are disjoint, then any subset R of P is also disjoint with Q.
  disjoint₂-⊆ˡ : R ⊆₂ P → Disjoint₂ P Q → Disjoint₂ R Q
  disjoint₂-⊆ˡ R⊆P disjointPQ x y [R∩Q]xy = disjointPQ x y (⊆₂-apply (∩₂-substˡ-⊆₂ {R = Q} R⊆P) [R∩Q]xy)

  -- | If two relations P and Q are disjoint, then any subset R of Q is also disjoint with P.
  disjoint₂-⊆ʳ : R ⊆₂ Q → Disjoint₂ P Q → Disjoint₂ P R
  disjoint₂-⊆ʳ R⊆Q disjointPQ x y [P∩R]xy = disjointPQ x y (⊆₂-apply (∩₂-substʳ-⊆₂ {R = P} R⊆Q) [P∩R]xy)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Rose trees
------------------------------------------------------------------------

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

module Data.Tree.Rose where

open import Level using (Level)
open import Size
open import Data.List.Base as List using (List; []; _∷_)
open import Data.Nat.Base as ℕ using (ℕ; zero; suc)
import Data.Nat.Properties as ℕₚ
open import Data.List.Extrema.Nat
open import Function.Base using (_∘_)

private
  variable
    a b : Level
    A : Set a
    B : Set b
    i : Size

------------------------------------------------------------------------
-- Type and basic constructions

data Rose (A : Set a) : Size → Set a where
  node : (a : A) (ts : List (Rose A i)) → Rose A (↑ i)

leaf : A → Rose A ∞
leaf a = node a []

------------------------------------------------------------------------
-- Transforming rose trees

map : (A → B) → Rose A i → Rose B i
map f (node a ts) = node (f a) (List.map (map f) ts)

------------------------------------------------------------------------
-- Reducing rose trees

foldr : (A → List B → B) → Rose A i → B
foldr n (node a ts) = n a (List.map (foldr n) ts)

depth : Rose A i → ℕ
depth (node a ts) = suc (max 0 (List.map depth ts))


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

module Cubical.Algebra.Group.Semidirect where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Structure
open import Cubical.Algebra.Group.Base
open import Cubical.Algebra.Group.Morphism
open import Cubical.Algebra.Group.Notation
open import Cubical.Algebra.Group.MorphismProperties
open import Cubical.Algebra.Group.Action
open import Cubical.Data.Sigma

private
  variable
    ℓ ℓ' : Level

module _  where

  semidirectProd : (G : Group {ℓ}) (H : Group {ℓ'}) (Act : GroupAction H G) → Group {ℓ-max ℓ ℓ'}
  semidirectProd G H Act = makeGroup-left {A = sd-carrier} sd-0 _+sd_ -sd_ sd-set sd-assoc sd-lId sd-lCancel
    where
      open ActionNotationα Act
      open ActionLemmas Act
      open GroupNotationG G
      open GroupNotationᴴ H
      -- sd stands for semidirect
      sd-carrier = ⟨ G ⟩ × ⟨ H ⟩
      sd-0 = 0ᴳ , 0ᴴ

      module _ ((g , h) : sd-carrier) where
        -sd_ = (-ᴴ h) α (-ᴳ g) , -ᴴ h

        _+sd_ = λ (g' , h') → g +ᴳ (h α g') , h +ᴴ h'

      abstract
        sd-set = isSetΣ setᴳ (λ _ → setᴴ)
        sd-lId = λ ((g , h) : sd-carrier) → ΣPathP (lIdᴳ (0ᴴ α g) ∙ (α-id g) , lIdᴴ h)
        sd-lCancel = λ ((g , h) : sd-carrier) → ΣPathP ((sym (α-hom (-ᴴ h) (-ᴳ g) g) ∙∙ cong ((-ᴴ h) α_) (lCancelᴳ g) ∙∙ actOnUnit (-ᴴ h)) , lCancelᴴ h)

        sd-assoc = λ (a , x) (b , y) (c , z) → ΣPathP ((a +ᴳ (x α (b  +ᴳ (y α c)))
                                    ≡⟨ cong (a +ᴳ_) (α-hom x b (y α c)) ⟩
                                a +ᴳ ((x α b) +ᴳ (x α (y α c)))
                                    ≡⟨ assocᴳ a (x α b) (x α (y α c)) ⟩
                                (a +ᴳ (x α b)) +ᴳ (x α (y α c))
                                    ≡⟨ cong ((a +ᴳ (x α b)) +ᴳ_) (sym (α-assoc x y c)) ⟩
                                (a +ᴳ (x α b)) +ᴳ ((x +ᴴ y) α c) ∎) , assocᴴ x y z)

  -- this syntax declaration is the reason we can't unify semidirectProd with
  -- the projections module
  syntax semidirectProd G H α = G ⋊⟨ α ⟩ H

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

  π₁ : ⟨ G ⋊⟨ Act ⟩ H ⟩ → ⟨ G ⟩
  π₁ = fst

  ι₁ : GroupHom G (G ⋊⟨ Act ⟩ H)
  ι₁ = grouphom (λ g → g , 0ᴴ) λ g g' → ΣPathP (cong (g +ᴳ_) (sym (α-id g')), sym (lIdᴴ 0ᴴ))

  π₂ : GroupHom (G ⋊⟨ Act ⟩ H) H
  -- π₂ = grouphom snd λ _ _ → refl
  π₂ = grouphom snd λ (g , h) (g' , h') → refl {x = h +ᴴ h'}

  ι₂ : GroupHom H (G ⋊⟨ Act ⟩ H)
  ι₂ = grouphom (λ h → 0ᴳ , h) λ h h' → ΣPathP (sym (actOnUnit h) ∙ sym (lIdᴳ (h α 0ᴳ)) , refl)

  π₂-hasSec : isGroupSplitEpi ι₂ π₂
  π₂-hasSec = GroupMorphismExt (λ _ → refl)


{-
  Copyright 2019 Lisandra Silva

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-}

open import Prelude
open import Relation.Binary.HeterogeneousEquality
            using (_≅_)
            renaming (cong to ≅-cong; refl to ≅-refl)

open import StateMachineModel

module Examples.SMCounter where

  data MyEvent : Set where
    inc  : MyEvent
    inc2 : MyEvent

  data MyEnabled : MyEvent → ℕ → Set where
    tt : ∀ {e} {n} → MyEnabled e n

  MyEventSet : EventSet {Event = MyEvent}
  MyEventSet inc  = ⊤
  MyEventSet inc2 = ⊤

  MyAction : {preSt : ℕ} {ev : MyEvent} → MyEnabled ev preSt → ℕ
  MyAction {preSt} {inc} enEv = suc preSt
  MyAction {preSt} {inc2} enEv = suc (suc preSt)

  data MyWeakFairness : EventSet → Set where
    w0 : MyWeakFairness MyEventSet

  -- Another way of modelling the WeakFairness
  MyWeakFairness2 : EventSet {Event = MyEvent} → Set
  MyWeakFairness2 MyEventSet = ⊤

  MyStateMachine : StateMachine ℕ MyEvent
  MyStateMachine = record { initial = 2 ≡_
                          ; enabled = MyEnabled
                          ; action  = MyAction }

  mySystem : System ℕ MyEvent
  mySystem = record { stateMachine = MyStateMachine
                    ; weakFairness = MyWeakFairness }

  myInvariant : Invariant MyStateMachine (2 ≤_)
  myInvariant (init x) = ≤-reflexive x
  myInvariant (step {ps} {inc} rs enEv) = ≤-stepsˡ 1 (myInvariant rs)
  myInvariant (step {ps} {inc2} rs enEv) = ≤-stepsˡ 2 (myInvariant rs)

  open LeadsTo ℕ MyEvent mySystem

  -- A state equals to n leads to a state equals to (1 + n) or equals to (2 + n)
  progressDumb : ∀ {n : ℕ} → (n ≡_) l-t ((1 + n ≡_) ∪ (2 + n ≡_))
  progressDumb = viaEvSet MyEventSet w0
                           ( λ { inc  ⊤ → hoare λ { refl enEv → inj₁ refl}
                               ; inc2 ⊤ → hoare λ { refl enEv → inj₂ refl} })
                           ( λ { inc  ⊥ → ⊥-elim (⊥ tt)
                               ; inc2 ⊥ → ⊥-elim (⊥ tt)} )
                           λ rs n≡s → inc , tt , tt

  n<m+n : ∀ {n m} → 0 < m → n < m + n
  n<m+n {zero}  {suc m} x = s≤s z≤n
  n<m+n {suc n} {suc m} x = s≤s (m≤n+m (suc n) m)

  progress-< : ∀ n → (n ≡_) l-t (n <_)
  progress-< n = viaTrans
                   progressDumb
                   (viaInv (λ { rs (inj₁ refl) → s≤s ≤-refl
                              ; rs (inj₂ refl) → s≤s (m≤n+m n 1)}))

  {- A predicate on states, parameterized by m (target). The d parameter is the
     "distance" from the target m from state s.

     QUESTION : We are generalizing Z to be of a given type, however in myWFR
     we are using it knowing that is ℕ because we apply _≡_ and _+_
  -}
  F : ∀ {m} → ℕ → Z → Set
  F {m} d s = m ≡ d + s

  wfr-1 : ∀ {m} → (s : Z) → (m ≤ s) ⊎ ∃[ x ] F {m} x s
  wfr-1 {m} s with m ≤? s
  ... | yes yy  = inj₁ yy
  ... | no  s<m = inj₂ (m ∸ s , sym (m∸n+n≡m (≰⇒≥ s<m)) )

  progress-1st : ∀ {n m} → (n ≡_) l-t ( (m ≤_) ∪ [∃ x ∶ F {m} x ] )
  progress-1st {n} {m} = viaInv (λ {s} rs n≡s → wfr-1 s)

  -- A state which distance to m is 0 (if we are in the state m)
  -- leads to a state greater than m
  progress-d0 : ∀ {m} → F {m} 0 l-t ( (m ≤_) ∪ [∃ x ⇒ _< 0 ∶ F {m} x ] )
  progress-d0 {m} = viaInv (λ { {s} rs refl → inj₁ ≤-refl })

  progress-d1 : ∀ {m} → F {m} 1 l-t ((m ≤_) ∪ [∃ x ⇒ _< 1 ∶ F {m} x ] )
  progress-d1 {m} =
    viaEvSet
      MyEventSet
      w0
      (λ { inc  ⊤ → hoare (λ { refl _ → inj₁ ≤-refl })
         ; inc2 ⊤ → hoare (λ { refl _ → inj₁ (≤-step ≤-refl) })
         })
      (λ { inc  ⊥ → ⊥-elim (⊥ tt)
         ; inc2 ⊥ → ⊥-elim (⊥ tt)
         })
      λ _ _ → inc , tt , tt

  progress-d2 : ∀ {m w} → F {m} (2 + w) l-t ( (m ≤_) ∪ [∃ x ⇒ _< (2 + w) ∶ F {m} x ] )
  progress-d2 {m} {w} =
    viaEvSet
      MyEventSet
      w0
      (λ { inc ⊤ → hoare λ { {ps} refl _
                     → inj₂ (suc w , ≤-refl , cong suc (sym (+-suc w ps)) )}
         ; inc2 ⊤ → hoare λ { {ps} refl _
                     → inj₂ (w , ≤-step ≤-refl , sym (trans (+-suc w (suc ps))
                                                     (cong suc (+-suc w ps)))) }
         })
      (λ { inc  ⊥ → ⊥-elim (⊥ tt)
         ; inc2 ⊥ → ⊥-elim (⊥ tt) })
      λ _ _ → inc , tt , tt

  progress-2nd : ∀ {m w}
              → F {m} w
                l-t
                ((m ≤_) ∪ [∃ x ⇒ _< w ∶ F {m} x ] )
  progress-2nd {m} {zero}        = progress-d0
  progress-2nd {m} {suc zero}    = progress-d1
  progress-2nd {m} {suc (suc w)} = progress-d2

  -- A state equals to n leads to a state greater or equal to m, ∀ m.
  -- In other words, from n we can go to every possible state m steps
  -- away from n
  progress : ∀ {n m : ℕ} → (n ≡_) l-t (m ≤_)
  progress {n} {m} = viaWFR (F {m})
                             progress-1st
                             λ w → progress-2nd


import      Lvl
open import Type

module Type.Functions {ℓₗ : Lvl.Level}{ℓₒ₁}{ℓₒ₂} {X : Type{ℓₒ₁}} {Y : Type{ℓₒ₂}} where

open import Function.Domains
open import Type.Properties.Empty
open import Type.Properties.Singleton

record Bijective (f : X → Y) : Type{ℓₗ Lvl.⊔ ℓₒ₁ Lvl.⊔ ℓₒ₂} where
  constructor intro
  field
    proof : ∀{y} → IsUnit{ℓₗ Lvl.⊔ ℓₒ₁} (Unapply {ℓₗ}{X = X}{Y = Y} f(y))

record Injective (f : X → Y) : Type{ℓₗ Lvl.⊔ ℓₒ₁ Lvl.⊔ ℓₒ₂} where
  constructor intro
  field
    proof : ∀{y} → MereProposition{ℓₗ Lvl.⊔ ℓₒ₁} (Unapply {ℓₗ}{X = X}{Y = Y} f(y))

record Surjective (f : X → Y) : Type{ℓₗ Lvl.⊔ ℓₒ₁ Lvl.⊔ ℓₒ₂} where
  constructor intro
  field
    proof : ∀{y} → ◊(Unapply {ℓₗ}{X = X}{Y = Y} f(y))


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

module Function.Surjective.Base where

open import Path
open import Function.Fiber
open import Level
open import HITs.PropositionalTruncation
open import Data.Sigma

Surjective : (A → B) → Type _
Surjective f = ∀ y → ∥ fiber f y ∥

SplitSurjective : (A → B) → Type _
SplitSurjective f = ∀ y → fiber f y

infixr 0 _↠!_ _↠_

_↠!_ : Type a → Type b → Type (a ℓ⊔ b)
A ↠! B = Σ (A → B) SplitSurjective

_↠_ : Type a → Type b → Type (a ℓ⊔ b)
A ↠ B = Σ (A → B) Surjective


module container.w.core where

open import level
open import sum
open import equality
open import function.extensionality
open import function.isomorphism
open import function.isomorphism.properties
open import function.overloading
open import sets.empty
open import sets.nat.core using (suc)
open import sets.unit
open import hott.level
open import container.core
open import container.fixpoint
open import container.equality

private
  module Definition {li la lb} (c : Container li la lb) where
    open Container c

    -- definition of indexed W-types using a type family
    data W (i : I) : Set (la ⊔ lb) where
      sup : (a : A i) → ((b : B a) → W (r b)) → W i

    -- initial F-algebra
    inW : F W →ⁱ W
    inW i (a , f) = sup a f

    module Elim {lx} {X : I → Set lx}
                (α : F X →ⁱ X) where
      -- catamorphisms
      fold : W →ⁱ X
      fold i (sup a f) = α i (a , λ b → fold _ (f b))

      -- computational rule for catamorphisms
      -- this holds definitionally
      fold-β : ∀ {i} (x : F W i) → fold i (inW i x) ≡ α i (imap fold i x)
      fold-β x = refl

      -- η-rule, this is only propositional
      fold-η : (h : W →ⁱ X)
             → (∀ {i} (x : F W i) → h i (inW i x) ≡ α i (imap h i x))
             → ∀ {i} (x : W i) → h i x ≡ fold i x
      fold-η h p {i} (sup a f) = p (a , λ b → f b) · lem
        where
          lem : α i (a , (λ b → h _ (f b)))
              ≡ α i (a , (λ b → fold _ (f b)))
          lem = ap (λ z → α i (a , z))
                     (funext λ b → fold-η h p (f b))
    open Elim public

    head : ∀ {i} → W i → A i
    head (sup a f) = a

    tail : ∀ {i} (x : W i)(b : B (head x)) → W (r b)
    tail (sup a f) = f

    fixpoint : (i : I) → W i ≅ F W i
    fixpoint _ = iso f g H K
      where
        f : {i : I} → W i → F W i
        f (sup a f) = a , f

        g : {i : I} → F W i → W i
        g (a , f) = sup a f

        H : {i : I}(w : W i) → g (f w) ≡ w
        H (sup a f) = refl

        K : {i : I}(w : F W i) → f (g w) ≡ w
        K (a , f) = refl

private
  module Properties {li la lb}{c : Container li la lb} where
    open Container c
    open Definition c

    open Equality c (fix W fixpoint)
    open Container equality
      using ()
      renaming (F to F-≡')
    open Definition equality
      using ()
      renaming ( W to W-≡
               ; fixpoint to fixpoint-≡ )

    F-≡ : ∀ {lx}
        → (∀ {i} → W i → W i → Set lx)
        → (∀ {i} → W i → W i → Set _)
    F-≡ X  u v = F-≡' (λ {(i , u , v) → X {i} u v}) (_ , u , v)

    _≡W_ : ∀ {i} → W i → W i → Set _
    _≡W_ {i} u v = W-≡ (i , u , v)

    fixpoint-W : ∀ {i}{u v : W i} → (u ≡ v) ≅ F-≡ _≡_ u v
    fixpoint-W {i}{sup a f}{sup a' f'} = begin
        (sup a f ≡ sup a' f')
      ≅⟨ iso≡ (fixpoint i) ⟩
        (apply (fixpoint i) (sup a f) ≡ apply (fixpoint i) (sup a' f'))
      ≅⟨ sym≅ Σ-split-iso ⟩
        (Σ (a ≡ a') λ p → subst (λ a → (b : B a) → W (r b)) p f ≡ f')
      ≅⟨ Σ-ap-iso refl≅ (substX-β f f') ⟩
        (Σ (a ≡ a') λ p → ∀ b → f b ≡ substX p b (f' (subst B p b)))
      ∎
      where open ≅-Reasoning

    str-iso : ∀ {i}{u v : W i} → (u ≡ v) ≅ (u ≡W v)
    str-iso {i}{sup a f}{sup a' f'} = begin
        (sup a f ≡ sup a' f')
      ≅⟨ fixpoint-W ⟩
        (Σ (a ≡ a') λ p → ∀ b → f b ≡ substX p b (f' (subst B p b)))
      ≅⟨ Σ-ap-iso refl≅ (λ a → Π-ap-iso refl≅ λ b → str-iso) ⟩
        (Σ (a ≡ a') λ p → ∀ b → f b ≡W substX p b (f' (subst B p b)))
      ≅⟨ sym≅ (fixpoint-≡ _) ⟩
        (sup a f ≡W sup a' f')
      ∎
      where open ≅-Reasoning

--    w-level : ∀ {n} → ((i : I) → h (suc n) (A i)) → (i : I) → h (suc n) (W i)
--    w-level hA i (sup a f) (sup a' f') = iso-level (sym≅ lem)
--      (Σ-level (hA i a a') (λ p → Π-level λ b → w-level hA _ _ _))
--      where
--        lem : ∀ {i}{a a' : A i}
--              {f : (b : B a) → W (r b)}
--              {f' : (b : B a') → W (r b)}
--            → (sup a f ≡ sup a' f')
--            ≅ Σ (a ≡ a') λ p → ∀ b → f b ≡ substX p b (f' (subst B p b))
--        lem = fixpoint-W

open Definition public
-- open Properties public using (w-level)


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

module Ch2-2 where

open import Ch2-1

open import Level

-- Lemma 2.2.1 (ap)
ap : ∀ {a b} {A : Set a} {B : Set b} {x y : A}
  → (f : A → B)
  → (p : x ≡ y)
  → f x ≡ f y
ap {a} {b} {A} {B} {x} {y} f p = J {a} {a ⊔ b} A D d x y p f
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set (a ⊔ b)
    D x y p = (f : A → B) → f x ≡ f y

    -- base case
    d : (x : A) → D x x refl
    d x f = refl

-- ap2 : {a b c : Level} {A : Set a} {B : Set b} {C : Set c} {x y : A} {z w : B}
--   → (f : A → B → C) (p : x ≡ y) (q : z ≡ w)
--   → f x z ≡ f y w
-- ap2 {a} {b} {c} {A} {B} {C} {x} {y} {z} {w} f p q = J A D d x y p z w q f
--   where
--     -- the predicate
--     D : (x y : A) (p : x ≡ y) → Set _
--     D x y p = (a b : B) (q : z ≡ w) (f : A → B → C) → f x z ≡ f y w
--
--     -- base case
--     d : (x : A) → D x x refl
--     d x z w q f = ap (f x) q

[_]∙ : ∀ {a} {A : Set a} {x y z : A}
  → (p : x ≡ y) (q : y ≡ z)
  → x ≡ z
[ p ]∙ q = p ∙ q

∙[_] : ∀ {a} {A : Set a} {x y z : A}
  → (q : y ≡ z) (p : x ≡ y)
  → x ≡ z
∙[ p ] q = q ∙ p

-- -- -- cong₂ ::
-- [_]∙[_] : ∀ {a} {A : Set a} {x y z : A}
--   → (p q : x ≡ y) (r s : y ≡ z)
--   → p ∙ r ≡ q ∙ s
-- [_]∙[_] {a} {A} {x} {y} {z} p q r s = {! ap2  !}

ap-refl : ∀ {a b} {A : Set a} {B : Set b} {x : A}
  → (f : A → B)
  → ap {a} {b} {A} {B} {x} f refl ≡ refl
ap-refl f = refl

-- Lemma 2.2.2.i (ap respects _∙_)
ap-∙ : ∀ {a b} {A : Set a} {B : Set b} {x y z : A}
  → (f : A → B)
  → (p : x ≡ y) (q : y ≡ z)
  → ap f (p ∙ q) ≡ ap f p ∙ ap f q
ap-∙ {a} {b} {A} {B} {x} {y} {z} f p q = J A D d x y p f z q
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set _
    D x y p = (f : A → B) (z : A) (q : y ≡ z) → ap f (p ∙ q) ≡ ap f p ∙ ap f q

    -- base case
    d : (x : A) → D x x refl
    d x f z q = J A E e x z q
      where
      -- the predicate
      E : (x z : A) (q : x ≡ z) → Set _
      E x z q = ap f (refl ∙ q) ≡ ap f refl ∙ ap f q
      -- base case
      e : (x : A) → E x x refl
      e x = refl

-- Lemma 2.2.2.ii (ap respects ¬_)
ap-¬ : ∀ {a b} {A : Set a} {B : Set b} {x y : A}
  → (f : A → B)
  → (p : x ≡ y)
  → ap f (¬ p) ≡ ¬ ap f p
ap-¬ {a} {b} {A} {B} {x} {y} f p = J A D d x y p f
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set _
    D x y p = (f : A → B) → ap f (¬ p) ≡ ¬ ap f p

    -- base case
    d : (x : A) → D x x refl
    d x f = refl

open import Function using (_∘_; id)

-- Lemma 2.2.2.iii (ap respects function compos)
ap-∘ : ∀ {a b c} {A : Set a} {B : Set b} {C : Set c} {x y : A}
  → (f : A → B) (g : B → C)
  → (p : x ≡ y)
  → ap g (ap f p) ≡ ap (g ∘ f) p
ap-∘ {_} {_} {_} {A} {B} {C} {x} {y} f g p = J A D d x y p f g
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set _
    D x y p = (f : A → B) → (g : B → C) → ap g (ap f p) ≡ ap (g ∘ f) p

    -- base case
    d : (x : A) → D x x refl
    d x f g = refl

-- Lemma 2.2.2.iv (ap respects identity function)
ap-id : ∀ {a} {A : Set a} {x y : A}
  → (p : x ≡ y)
  → ap id p ≡ p
ap-id {a} {A} {x} {y} p = J A D d x y p
  where
    -- the predicate
    D : (x y : A) (p : x ≡ y) → Set a
    D x y p = ap id p ≡ p

    -- base case
    d : (x : A) → D x x refl
    d x = refl


module Prelude.List.Relations.Properties where

open import Agda.Primitive

open import Prelude.Equality
open import Prelude.Nat
open import Prelude.Empty
open import Prelude.Unit
open import Prelude.Product
open import Prelude.Number
open import Prelude.Decidable
open import Prelude.List.Base

open import Prelude.List.Relations.All
open import Prelude.List.Relations.Any

open import Prelude.Nat.Properties
open import Prelude.Variables

open import Prelude.Applicative

-- All --

module _ {a b} {A : Set a} {P Q : A → Set b} (f : ∀ {x} → P x → Q x) where
  mapAll : ∀ {xs} → All P xs → All Q xs
  mapAll [] = []
  mapAll (x ∷ xs) = f x ∷ mapAll xs

traverseAll : ∀ {a b} {A : Set a} {B : A → Set a} {F : Set a → Set b}
                {{AppF : Applicative F}} →
                (∀ x → F (B x)) → (xs : List A) → F (All B xs)
traverseAll f []       = pure []
traverseAll f (x ∷ xs) = ⦇ f x ∷ traverseAll f xs ⦈

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

  -- Append

  infixr 5 _++All_
  _++All_ : ∀ {xs ys} → All P xs → All P ys → All P (xs ++ ys)
  []       ++All qs = qs
  (p ∷ ps) ++All qs = p ∷ ps ++All qs

-- Any --

module _ {a b} {A : Set a} {P Q : A → Set b} (f : ∀ {x} → P x → Q x) where
  mapAny : ∀ {xs} → Any P xs → Any Q xs
  mapAny (zero x) = zero (f x)
  mapAny (suc i)  = suc (mapAny i)

-- Literal overloading for Any
module _ {a b} {A : Set a} {P : A → Set b} where
  private
    AnyConstraint : List A → Nat → Set (a ⊔ b)
    AnyConstraint []        _      = ⊥′
    AnyConstraint (x ∷  _)  zero   = ⊤′ {a} × P x   -- hack to line up levels
    AnyConstraint (_ ∷ xs) (suc i) = AnyConstraint xs i

    natToIx : ∀ (xs : List A) n → {{_ : AnyConstraint xs n}} → Any P xs
    natToIx [] n {{}}
    natToIx (x ∷ xs)  zero {{_ , px}} = zero px
    natToIx (x ∷ xs) (suc n) = suc (natToIx xs n)

  instance
    NumberAny : ∀ {xs} → Number (Any P xs)
    Number.Constraint (NumberAny {xs}) = AnyConstraint xs
    fromNat {{NumberAny {xs}}} = natToIx xs

lookupAny : ∀ {a b} {A : Set a} {P Q : A → Set b} {xs} → All P xs → Any Q xs → Σ A (λ x → P x × Q x)
lookupAny (p ∷ ps) (zero q) = _ , p , q
lookupAny (p ∷ ps) (suc  i) = lookupAny ps i

lookup∈ : ∀ {a b} {A : Set a} {P : A → Set b} {xs x} → All P xs → x ∈ xs → P x
lookup∈ (p ∷ ps) (zero refl) = p
lookup∈ (p ∷ ps) (suc i)     = lookup∈ ps i

module _ {a b} {A : Set a} {P : A → Set b} {{EqP : ∀ {x} → Eq (P x)}} where

  private
    z' : ∀ {x xs} → P x → Any P (x ∷ xs)
    z' = zero

    zero-inj : ∀ {x} {xs : List A} {p q : P x} → Any.zero {xs = xs} p ≡ z' q → p ≡ q
    zero-inj refl = refl

    sucAny-inj : ∀ {x xs} {i j : Any P xs} → Any.suc {x = x} i ≡ Any.suc {x = x} j → i ≡ j
    sucAny-inj refl = refl

    cons-inj₁ : ∀ {x xs} {p q : P x} {ps qs : All P xs} → p All.∷ ps ≡ q ∷ qs → p ≡ q
    cons-inj₁ refl = refl

    cons-inj₂ : ∀ {x xs} {p q : P x} {ps qs : All P xs} → p All.∷ ps ≡ q ∷ qs → ps ≡ qs
    cons-inj₂ refl = refl

  instance
    EqAny : ∀ {xs} → Eq (Any P xs)
    _==_ {{EqAny}} (zero p) (zero q) = decEq₁ zero-inj   (p == q)
    _==_ {{EqAny}} (suc i)  (suc j)  = decEq₁ sucAny-inj (i == j)
    _==_ {{EqAny}} (zero _) (suc _)  = no λ ()
    _==_ {{EqAny}} (suc _)  (zero _) = no λ ()

    EqAll : ∀ {xs} → Eq (All P xs)
    _==_ {{EqAll}} []       []       = yes refl
    _==_ {{EqAll}} (x ∷ xs) (y ∷ ys) = decEq₂ cons-inj₁ cons-inj₂ (x == y) (xs == ys)


------------------------------------------------------------------------
-- The Agda standard library
--
-- A pointwise lifting of a relation to incorporate new extrema.
-------------------------------------------------------------------------

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

-- This module is designed to be used with
-- Relation.Nullary.Construct.Add.Extrema

open import Relation.Binary

module Relation.Binary.Construct.Add.Extrema.Equality
  {a ℓ} {A : Set a} (_≈_ : Rel A ℓ) where

open import Function using (_∘′_)
import Relation.Binary.Construct.Add.Infimum.Equality as AddInfimum
import Relation.Binary.Construct.Add.Supremum.Equality as AddSupremum
open import Relation.Nullary.Construct.Add.Extrema

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

private
  module Inf = AddInfimum _≈_
  module Sup = AddSupremum (Inf._≈₋_)

open Sup using () renaming (_≈⁺_ to _≈±_) public

-------------------------------------------------------------------------
-- Useful pattern synonyms

pattern ⊥±≈⊥± = Sup.[ Inf.⊥₋≈⊥₋ ]
pattern [_] p = Sup.[ Inf.[ p ] ]
pattern ⊤±≈⊤± = Sup.⊤⁺≈⊤⁺

-------------------------------------------------------------------------
-- Relational properties

[≈]-injective : ∀ {k l} → [ k ] ≈± [ l ] → k ≈ l
[≈]-injective = Inf.[≈]-injective ∘′ Sup.[≈]-injective

≈±-refl : Reflexive _≈_ → Reflexive _≈±_
≈±-refl = Sup.≈⁺-refl ∘′ Inf.≈₋-refl

≈±-sym : Symmetric _≈_ → Symmetric _≈±_
≈±-sym = Sup.≈⁺-sym ∘′ Inf.≈₋-sym

≈±-trans : Transitive _≈_ → Transitive _≈±_
≈±-trans = Sup.≈⁺-trans ∘′ Inf.≈₋-trans

≈±-dec : Decidable _≈_ → Decidable _≈±_
≈±-dec = Sup.≈⁺-dec ∘′ Inf.≈₋-dec

≈±-irrelevant : Irrelevant _≈_ → Irrelevant _≈±_
≈±-irrelevant = Sup.≈⁺-irrelevant ∘′ Inf.≈₋-irrelevant

≈±-substitutive : ∀ {ℓ} → Substitutive _≈_ ℓ → Substitutive _≈±_ ℓ
≈±-substitutive = Sup.≈⁺-substitutive ∘′ Inf.≈₋-substitutive

-------------------------------------------------------------------------
-- Structures

≈±-isEquivalence : IsEquivalence _≈_ → IsEquivalence _≈±_
≈±-isEquivalence = Sup.≈⁺-isEquivalence ∘′ Inf.≈₋-isEquivalence

≈±-isDecEquivalence : IsDecEquivalence _≈_ → IsDecEquivalence _≈±_
≈±-isDecEquivalence = Sup.≈⁺-isDecEquivalence ∘′ Inf.≈₋-isDecEquivalence


------------------------------------------------------------------------
-- The Agda standard library
--
-- Convenient syntax for "equational reasoning" using a partial order
------------------------------------------------------------------------

-- Example uses:
--
--    u≤x : u ≤ x
--    u≤x = begin
--      u  ≈⟨ u≈v ⟩
--      v  ≡⟨ v≡w ⟩
--      w  <⟨ w≤x ⟩
--      x  ∎
--
--    u<x : u < x
--    u<x = begin-strict
--      u  ≈⟨ u≈v ⟩
--      v  ≡⟨ v≡w ⟩
--      w  <⟨ w≤x ⟩
--      x  ∎
--
--    u<e : u < e
--    u<e = begin-strict
--      u  ≈⟨ u≈v ⟩
--      v  ≡⟨ v≡w ⟩
--      w  <⟨ w<x ⟩
--      x  ≤⟨ x≤y ⟩
--      y  <⟨ y<z ⟩
--      z  ≡˘⟨ d≡z ⟩
--      d  ≈˘⟨ e≈d ⟩
--      e  ∎
--
--    u≈w : u ≈ w
--    u≈w = begin-equality
--      u  ≈⟨ u≈v ⟩
--      v  ≡⟨ v≡w ⟩
--      w  ∎

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

open import Relation.Binary

module Relation.Binary.Reasoning.PartialOrder
  {p₁ p₂ p₃} (P : Poset p₁ p₂ p₃) where

open Poset P
import Relation.Binary.Construct.NonStrictToStrict _≈_ _≤_ as Strict

------------------------------------------------------------------------
-- Re-export contents of base module

open import Relation.Binary.Reasoning.Base.Triple
  isPreorder
  (Strict.trans isPartialOrder)
  (Strict.<-resp-≈ isEquivalence ≤-resp-≈)
  Strict.<⇒≤
  (Strict.<-≤-trans Eq.sym trans antisym ≤-respʳ-≈)
  (Strict.≤-<-trans trans antisym ≤-respˡ-≈)
  public

------------------------------------------------------------------------
-- DEPRECATED NAMES
------------------------------------------------------------------------
-- Please use the new names as continuing support for the old names is
-- not guaranteed.

-- Version 1.0

infixr 2 _≈⟨⟩_

_≈⟨⟩_ = _≡⟨⟩_
{-# WARNING_ON_USAGE _≈⟨⟩_
"Warning: _≈⟨⟩_ was deprecated in v1.0.
Please use _≡⟨⟩_ instead."
#-}


module Vecs.Reverse where

open import Vecs
open import Nats
open import Equality
open import Function

------------------------------------------------------------------------
-- internal stuffs

private

  -- rev$v:a=a:rev$v : ∀ {n m} {A : Set n} (a : A) (v : Vec A m) →
  --                 rev (v ∷ʳ a) ≡ a ∷ rev v
  -- rev$v:a=a:rev$v _ [] = refl
  -- rev$v:a=a:rev$v a (_ ∷ xs) with rev (xs ∷ʳ a) | rev$v:a=a:rev$v a xs
  -- ...                            | .(a ∷ rev xs) | refl = refl

  rev$v:a=a:rev$v : ∀ {n m} {A : Set n} (a : A) (v : Vec A m) →
                  reverse (v ∷ʳ a) ≡ a ∷ reverse v
  rev$v:a=a:rev$v _ [] = refl
  rev$v:a=a:rev$v a (_ ∷ xs)
    rewrite rev$v:a=a:rev$v a xs
            = refl

  rev∘rev=id : ∀ {n m} {A : Set n} (v : Vec A m) → reverse (reverse v) ≡ v
  rev∘rev=id [] = refl
  rev∘rev=id (x ∷ xs)
    rewrite rev$v:a=a:rev$v x $ reverse xs
          | rev∘rev=id xs
            = refl

------------------------------------------------------------------------
-- public aliases

vec-rev-rev-id : ∀ {n m} {A : Set n} (v : Vec A m) → reverse (reverse v) ≡ v
vec-rev-rev-id = rev∘rev=id


module Bools where

open import Agda.Builtin.Bool public
  renaming (Bool to 𝔹)

not : 𝔹 → 𝔹
not true  = false
not false = true

-- T : 𝔹 → Set
-- T true  = ⊤
-- T false = ⊥

if_then_else_ : ∀ {a} {A : Set a} → 𝔹 → A → A → A
if true  then t else _ = t
if false then _ else f = f

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

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

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


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

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

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

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


module comb where

infixr 50 _⟶_

data Ty : Set where
  ι : Ty
  _⟶_ : Ty -> Ty -> Ty

data Tm : Ty -> Set where
  K : {σ τ : Ty} -> Tm (σ ⟶ τ ⟶ σ)
  S : {σ τ ρ : Ty} -> Tm ((σ ⟶ τ ⟶ ρ) ⟶ (σ ⟶ τ) ⟶ σ ⟶ ρ)
  _$_ : {σ τ : Ty} -> Tm (σ ⟶ τ) -> Tm σ -> Tm τ

data Nf : Ty -> Set where
  Kⁿ : {σ τ : Ty} -> Nf (σ ⟶ τ ⟶ σ)
  Kⁿ¹ : {σ τ : Ty} -> Nf σ -> Nf (τ ⟶ σ)
  Sⁿ : {σ τ ρ : Ty} -> Nf ((σ ⟶ τ ⟶ ρ) ⟶ (σ ⟶ τ) ⟶ σ ⟶ ρ)
  Sⁿ¹ : {σ τ ρ : Ty} -> Nf (σ ⟶ τ ⟶ ρ) -> Nf ((σ ⟶ τ) ⟶ σ ⟶ ρ)
  Sⁿ² : {σ τ ρ : Ty} -> Nf (σ ⟶ τ ⟶ ρ) -> Nf (σ ⟶ τ) -> Nf (σ ⟶ ρ)

_$$_ : {σ τ : Ty} -> Nf (σ ⟶ τ) -> Nf σ -> Nf τ
Kⁿ      $$ x = Kⁿ¹ x
Kⁿ¹ x   $$ y = x
Sⁿ      $$ x = Sⁿ¹ x
Sⁿ¹ x   $$ y = Sⁿ² x y
Sⁿ² x y $$ z = (x $$ z) $$ (y $$ z)

nf : {σ : Ty} -> Tm σ -> Nf σ
nf K = Kⁿ
nf S = Sⁿ
nf (t $ u) = nf t $$ nf u

data _$ⁿ_⇓_ : {σ τ : Ty} -> Nf (σ ⟶ τ) -> Nf σ -> Nf τ -> Set where
  rKⁿ  : {σ τ : Ty} -> {x : Nf σ} -> Kⁿ {σ} {τ} $ⁿ x ⇓ Kⁿ¹ x
  rKⁿ¹ : {σ τ : Ty} -> {x : Nf σ} -> {y : Nf τ} -> Kⁿ¹ x $ⁿ y ⇓ x
  rSⁿ  : {σ τ ρ : Ty} -> {x : Nf (σ ⟶ τ ⟶ ρ)} -> Sⁿ $ⁿ x ⇓ Sⁿ¹ x
  rSⁿ¹ : {σ τ ρ : Ty} -> {x : Nf (σ ⟶ τ ⟶ ρ)} -> {y : Nf (σ ⟶ τ)} ->
    Sⁿ¹ x $ⁿ y ⇓ Sⁿ² x y
  rSⁿ² : {σ τ ρ : Ty} -> {x : Nf (σ ⟶ τ ⟶ ρ)} -> {y : Nf (σ ⟶ τ)} ->
    {z : Nf σ} -> {u : Nf (τ ⟶ ρ)} -> x $ⁿ z ⇓ u -> {v : Nf τ} ->
    y $ⁿ z ⇓ v -> {w : Nf ρ} -> u $ⁿ v ⇓ w -> Sⁿ² x y $ⁿ z ⇓ w

data _⇓_ : {σ : Ty} -> Tm σ -> Nf σ -> Set where
  rK : {σ τ : Ty} -> K {σ} {τ} ⇓ Kⁿ
  rS : {σ τ ρ : Ty} -> S {σ} {τ} {ρ} ⇓ Sⁿ
  r$ : {σ τ : Ty} -> {t : Tm (σ ⟶ τ)} -> {f : Nf (σ ⟶ τ)} -> t ⇓ f ->
    {u : Tm σ} -> {a : Nf σ} -> u ⇓ a -> {v : Nf τ} -> f $ⁿ a ⇓ v  ->
    t $ u ⇓ v

data _==_ {A : Set}(a : A) : {B : Set} -> (b : B) -> Set where
  refl : a == a

data Σ {A : Set}(B : A -> Set) : Set where
  sig : (a : A) -> (b : B a) -> Σ B

σ₀ : {A : Set} -> {B : A -> Set} -> Σ B -> A
σ₀ (sig x _) = x

σ₁ : {A : Set} -> {B : A -> Set} -> (s : Σ B) -> B (σ₀ s)
σ₁ (sig _ y) = y

_$$⁼_&_ : {σ τ : Ty} -> (f : Nf (σ ⟶ τ)) -> (a : Nf σ) -> {n : Nf τ} ->
  f $ⁿ a ⇓ n ->     Σ \(n' : Nf τ) -> n' == n
Kⁿ      $$⁼ x & rKⁿ  = sig (Kⁿ¹ x) refl
Kⁿ¹ x   $$⁼ y & rKⁿ¹ = sig x refl
Sⁿ      $$⁼ x & rSⁿ  = sig (Sⁿ¹ x) refl
Sⁿ¹ x   $$⁼ y & rSⁿ¹ = sig (Sⁿ² x y) refl
Sⁿ² x y $$⁼ z & (rSⁿ² p q r) with x $$⁼ z & p | y $$⁼ z & q
Sⁿ² x y $$⁼ z & (rSⁿ² p q r)  |   sig u refl  | sig v refl with u $$⁼ v & r
Sⁿ² x y $$⁼ z & (rSⁿ² p q r)  |   sig u refl  | sig v refl  |   sig w refl =
  sig w refl

nf⁼ : {σ : Ty} -> (t : Tm σ) -> {n : Nf σ} -> t ⇓ n ->
  Σ \(n' : Nf σ) -> n' == n
nf⁼ K rK = sig Kⁿ refl
nf⁼ S rS = sig Sⁿ refl
nf⁼ (t $ u) (r$ p q r) with nf⁼ t p    | nf⁼ u q
nf⁼ (t $ u) (r$ p q r)  |   sig f refl | sig a refl with f $$⁼ a & r
nf⁼ (t $ u) (r$ p q r)  |   sig f refl | sig a refl  |   sig v refl =
  sig v refl

proof : {σ : Ty} -> (t : Tm σ) -> Σ \(n : Nf σ) -> t ⇓ n
proof = {! !}

nf⇓ :  {σ : Ty} -> Tm σ -> Nf σ
nf⇓ t = σ₀ (nf⁼ t (σ₁ (proof t)))


module DecidableOrder where

open import Logic.Relations
open import Logic.Identity using (_≡_)

open module Antisym = PolyEq _≡_ using (Antisymmetric)

record DecidableOrder (A : Set) : Set1 where
  field
    _≤_     : Rel A
    refl    : Reflexive _≤_
    antisym : Antisymmetric _≤_
    trans   : Transitive _≤_
    total   : Total _≤_
    decide  : forall x y -> Decidable (x ≤ y)

  infix 80 _≤_ _≥_

  _≥_ = \(x y : A) -> y ≤ x


module plfa-code.Isomorphism where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong; cong-app)
open Eq.≡-Reasoning
open import Data.Nat using (ℕ; zero; suc; _+_)
open import Data.Nat.Properties using (+-comm)

_∘_ : ∀ {A B C : Set} → (B → C) → (A → B) → (A → C)
(g ∘ f) x  =  g (f x)

_∘′_ : ∀ {A B C : Set} → (B → C) → (A → B) → (A → C)
g ∘′ f = λ x → g (f x)

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

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

same-app : ∀ (m n : ℕ) → m +′ n ≡ m + n
same-app m n rewrite +-comm m n = helper m n
  where
  helper : ∀ (m n : ℕ) → m +′ n ≡ n + m
  helper m zero    = refl
  helper m (suc n) = cong suc (helper m n)

same : _+′_ ≡ _+_
same = extensionality (λ m → extensionality (λ n → same-app m n))

infix 0 _≃_
record _≃_ (A B : Set) : Set where
  field
    to   : A → B
    from : B → A
    from∘to : ∀ (x : A) → from (to x) ≡ x
    to∘from : ∀ (y : B) → to (from y) ≡ y
open _≃_

-- equal to
data _≃′_ (A B : Set): Set where
  mk-≃′ : ∀ (to : A → B) →
          ∀ (from : B → A) →
          ∀ (from∘to : (∀ (x : A) → from (to x) ≡ x)) →
          ∀ (to∘from : (∀ (y : B) → to (from y) ≡ y)) →
          A ≃′ B

to′ : ∀ {A B : Set} → (A ≃′ B) → (A → B)
to′ (mk-≃′ f g g∘f f∘g) = f

from′ : ∀ {A B : Set} → (A ≃′ B) → (B → A)
from′ (mk-≃′ f g g∘f f∘g) = g

from∘to′ : ∀ {A B : Set} → (A≃B : A ≃′ B) → (∀ (x : A) → from′ A≃B (to′ A≃B x) ≡ x)
from∘to′ (mk-≃′ f g g∘f f∘g) = g∘f

to∘from′ : ∀ {A B : Set} → (A≃B : A ≃′ B) → (∀ (y : B) → to′ A≃B (from′ A≃B y) ≡ y)
to∘from′ (mk-≃′ f g g∘f f∘g) = f∘g
-- which means `field record` will take the field

≃-refl : ∀ {A : Set}
    -----
  → A ≃ A
≃-refl =
  record
    { to = λ{x → x}
    ; from = λ{y → y}
    ; from∘to = λ{x → refl}
    ; to∘from = λ{y → refl}
    }

≃-sym : ∀ {A B : Set}
  → A ≃ B
    -----
  → B ≃ A
≃-sym A≃B =
  record
    { to = from A≃B
    ; from = to A≃B
    ; from∘to = to∘from A≃B
    ; to∘from = from∘to A≃B
    }

≃-trans : ∀ {A B C : Set}
  → A ≃ B
  → B ≃ C
    -----
  → A ≃ C
≃-trans A≃B B≃C =
  record
    { to      =   to   B≃C ∘ to   A≃B
    ; from    =   from A≃B ∘ from B≃C
    ; from∘to = λ{x →
      begin
        (from A≃B ∘ from B≃C) ((to B≃C ∘ to A≃B) x)
      ≡⟨⟩
        from A≃B (from B≃C (to B≃C (to A≃B x)))
      ≡⟨ cong (from A≃B) (from∘to B≃C (to A≃B x)) ⟩
        from A≃B (to A≃B x)
      ≡⟨ from∘to A≃B x ⟩
        x
      ∎
      }
    ; to∘from = λ{y →
        begin
          (to B≃C ∘ to A≃B) ((from A≃B ∘ from B≃C) y)
        ≡⟨⟩
          to B≃C (to A≃B (from A≃B (from B≃C y)))
        ≡⟨ cong (to B≃C) (to∘from A≃B (from B≃C y)) ⟩
          to B≃C (from B≃C y)
        ≡⟨ to∘from B≃C y ⟩
          y
        ∎}
    }

module ≃-Reasoning where

  infix  1 ≃-begin_
  infixr 2 _≃⟨_⟩_
  infix  3 _≃-∎

  ≃-begin_ : ∀ {A B : Set}
    → A ≃ B
      -----
    → A ≃ B
  ≃-begin A≃B = A≃B

  _≃⟨_⟩_ : ∀ (A : Set) {B C : Set}
    → A ≃ B
    → B ≃ C
      -----
    → A ≃ C
  A ≃⟨ A≃B ⟩ B≃C = ≃-trans A≃B B≃C

  _≃-∎ : ∀ (A : Set)
      -----
    → A ≃ A
  A ≃-∎ = ≃-refl

open ≃-Reasoning

infix 0 _≲_
record _≲_ (A B : Set) : Set where
  field
    to      : A → B
    from    : B → A
    from∘to : ∀ (x : A) → from (to x) ≡ x
open _≲_

≲-refl : ∀ {A : Set} → A ≲ A
≲-refl =
  record
    { to      = λ{x → x}
    ; from    = λ{y → y}
    ; from∘to = λ{x → refl}
    }

≲-trans : ∀ {A B C : Set} → A ≲ B → B ≲ C → A ≲ C
≲-trans A≲B B≲C =
  record
    { to      = λ{x → to   B≲C (to   A≲B x)}
    ; from    = λ{y → from A≲B (from B≲C y)}
    ; from∘to = λ{x →
        begin
          from A≲B (from B≲C (to B≲C (to A≲B x)))
        ≡⟨ cong (from A≲B) (from∘to B≲C (to A≲B x)) ⟩
          from A≲B (to A≲B x)
        ≡⟨ from∘to A≲B x ⟩
          x
        ∎}
     }

≲-antisym : ∀ {A B : Set}
  → (A≲B : A ≲ B)
  → (B≲A : B ≲ A)
  → (to A≲B ≡ from B≲A)
  → (from A≲B ≡ to B≲A)
    -------------------
  → A ≃ B
≲-antisym A≲B B≲A to≡from from≡to =
  record
  { to      = to A≲B
  ; from    = from A≲B
  ; from∘to = from∘to A≲B
  ; to∘from = λ{y →
      begin
        to A≲B (from A≲B y)
      ≡⟨ cong (to A≲B) (cong-app from≡to y) ⟩
        to A≲B (to B≲A y)
      ≡⟨ cong-app to≡from (to B≲A y) ⟩
        from B≲A (to B≲A y)
      ≡⟨ from∘to B≲A y ⟩
        y
      ∎
    }
  }

module ≲-Reasoning where

  infix  1 ≲-begin_
  infixr 2 _≲⟨_⟩_
  infix  3 _≲-∎

  ≲-begin_ : ∀ {A B : Set}
    → A ≲ B
      -----
    → A ≲ B
  ≲-begin A≲B = A≲B

  _≲⟨_⟩_ : ∀ (A : Set) {B C : Set}
    → A ≲ B
    → B ≲ C
      -----
    → A ≲ C
  A ≲⟨ A≲B ⟩ B≲C = ≲-trans A≲B B≲C

  _≲-∎ : ∀ (A : Set)
      -----
    → A ≲ A
  A ≲-∎ = ≲-refl

open ≲-Reasoning

---------- practice ----------

≃-implies-≲ : ∀ {A B : Set}
  → A ≃ B
    -----
  → A ≲ B

≃-implies-≲ A≃B =
  record
  { to = to A≃B
  ; from = from A≃B
  ; from∘to = from∘to A≃B
  }

record _⇔_ (A B : Set) : Set where
  field
    to   : A → B
    from : B → A

open _⇔_

⇔-refl : ∀ {A : Set} → A ⇔ A
⇔-refl = record { to = λ z → z ; from = λ z → z }

⇔-sym : ∀ {A B : Set} → A ⇔ B → B ⇔ A
⇔-sym A⇔B = record { to = from A⇔B ; from = to A⇔B }

⇔-trans : ∀ {A B C : Set} → A ⇔ B → B ⇔ C → A ⇔ C
⇔-trans A⇔B B⇔C =
  record
    { to   = to B⇔C ∘ to A⇔B
    ; from = from A⇔B ∘ from B⇔C
    }

data Bin : Set where
  nil : Bin
  x0_ : Bin → Bin
  x1_ : Bin → Bin

postulate
  toB : ℕ → Bin
  fromB : Bin → ℕ
  from-to-const : ∀ (n : ℕ) → fromB (toB n) ≡ n

ℕ-embedding-Bin : ℕ ≲ Bin
ℕ-embedding-Bin =
  record
    { to      = toB
    ; from    = fromB
    ; from∘to = from-to-const
    }


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

open import Level
open import Relation.Binary using (IsEquivalence)
open import Relation.Binary.PropositionalEquality
  using ()
  renaming (_≡_ to _≣_)
open import Relation.Nullary using (¬_)
open import Data.Product using (Σ; _×_; ∃; proj₁)
open import Categories.Category
open import Categories.Functor.Core public
import Categories.Morphisms as Morphisms

infix  4 _≡_

_≡_ : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} → (F G : Functor C D) → Set (e′ ⊔ ℓ′ ⊔ ℓ ⊔ o)
_≡_ {C = C} {D} F G = ∀ {A B} → (f : C [ A , B ]) → Functor.F₁ F f ∼ Functor.F₁ G f
  where open Heterogeneous D

≡⇒≣ : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′}
  → (F G : Functor C D)
  → F ≡ G
  → (∀ x → Functor.F₀ F x ≣ Functor.F₀ G x)
≡⇒≣ {C = C} {D} F G F≡G x = domain-≣ (F≡G (Category.id C {x}))
  where
    open Heterogeneous D

.assoc : ∀ {o₀ ℓ₀ e₀ o₁ ℓ₁ e₁ o₂ ℓ₂ e₂ o₃ ℓ₃ e₃}
           {C₀ : Category o₀ ℓ₀ e₀} {C₁ : Category o₁ ℓ₁ e₁} {C₂ : Category o₂ ℓ₂ e₂} {C₃ : Category o₃ ℓ₃ e₃}
           {F : Functor C₀ C₁} {G : Functor C₁ C₂} {H : Functor C₂ C₃}
       → (H ∘ G) ∘ F ≡ H ∘ (G ∘ F)
assoc {C₃ = C₃} f = refl
  where open Heterogeneous C₃

.identityˡ : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} {F : Functor C D} → id ∘ F ≡ F
identityˡ {C = C} {D} {F} f = refl
  where open Heterogeneous D

.identityʳ : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} {F : Functor C D} → F ∘ id ≡ F
identityʳ {C = C} {D} {F} f = refl
  where open Heterogeneous D

.equiv : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} → IsEquivalence (_≡_ {C = C} {D = D})
equiv {C = C} {D} = record
  { refl = λ f → refl
  ; sym = λ F∼G f → sym (F∼G f)
  ; trans = λ F∼G G∼H f → trans (F∼G f) (G∼H f)
  }
  where open Heterogeneous D

.∘-resp-≡  : ∀ {o₀ ℓ₀ e₀ o₁ ℓ₁ e₁ o₂ ℓ₂ e₂}
               {A : Category o₀ ℓ₀ e₀} {B : Category o₁ ℓ₁ e₁} {C : Category o₂ ℓ₂ e₂}
               {F H : Functor B C} {G I : Functor A B}
           → F ≡ H → G ≡ I → F ∘ G ≡ H ∘ I
∘-resp-≡ {B = B} {C} {F} {I = I} F≡H G≡I q = helper (G≡I q) (F≡H (Functor.F₁ I q))
  where
  open Heterogeneous C
  module C = Category C
  helper : ∀ {a b c d} {z w} {f : B [ a , b ]} {h : B [ c , d ]} {i : C [ z , w ]}
         → B [ f ∼ h ] → C [ Functor.F₁ F h ∼ i ] → C [ Functor.F₁ F f ∼ i ]
  helper (≡⇒∼ f≡h) (≡⇒∼ g≡i) = ≡⇒∼ (C.Equiv.trans (Functor.F-resp-≡ F f≡h) g≡i)

Faithful : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} → Functor C D → Set (o ⊔ ℓ ⊔ e ⊔ e′)
Faithful {C = C} {D} F = ∀ {X Y} → (f g : C [ X , Y ]) → D [ F₁ f ≡ F₁ g ] → C [ f ≡ g ]
  where
  module C = Category C
  module D = Category D
  open Functor F

-- Is this convoluted double-negated definition really necessary? A naive constructive definition of surjectivity
-- requires a right inverse, which would probably restrict the things we can provide proofs for
Full : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} → Functor C D → Set (o ⊔ ℓ ⊔ ℓ′ ⊔ e′)
Full {C = C} {D} F = ∀ {X Y} → ¬ Σ (D [ F₀ X , F₀ Y ]) (λ f → ¬ Σ (C [ X , Y ]) (λ g → D [ F₁ g ≡ f ]))
  where
  module C = Category C
  module D = Category D
  open Functor F

FullyFaithful : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} → Functor C D → Set (o ⊔ ℓ ⊔ e ⊔ ℓ′ ⊔ e′)
FullyFaithful F = Full F × Faithful F

{-
[02:22:21 AM] <ddarius> copumpkin: So I think the normal statement is fine.  You should be requiring F_1 to be a setoid function, i.e. forall x ~ x'. f(x) ~ f(x').  The function that would be required by the forall y.exists x. ... is not a setoid function and thus doesn't necessarily produce an inverse.  That is, you'll have a function g such that f(g(y)) ~ y but not necessarily f(g(y)) = y and it is not necessary that for y ~ y' that
[02:22:22 AM] <ddarius> g(y) ~ g(y'), they could be different w.r.t. the domain setoid as long as f still maps them to equivalent elements in the codomain.
[02:27:53 AM] <ddarius> For example, let f : 2/= -> 2/~ (where True ~ False).  Then, we need g(True) and g(False) and we could use g = not, even though True /= False and f(g(y)) /= y (assuming say f is id on the carrier), because it is still the case that f(g(y)) ~ y.
[02:28:55 AM] <ddarius> So g isn't an inverse on the carrier sets, and g isn't a setoid function inverse because it's not even a setoid function.
-}

EssentiallySurjective : ∀ {o ℓ e} {o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′} → Functor C D → Set _
EssentiallySurjective {D = D} F = ∀ d → ∃ (λ c → F₀ c ≅ d)
  where
  open Functor F
  open Morphisms D


{-# OPTIONS --universe-polymorphism #-}

module Categories.Free where

open import Categories.Category
open import Categories.Free.Core
open import Categories.Free.Functor
open import Categories.Graphs.Underlying
open import Categories.Functor
  using (Functor)
open import Graphs.Graph
open import Graphs.GraphMorphism
  using (GraphMorphism; module GraphMorphism)
open import Data.Star

-- Exports from other modules:
--    Free₀, Free₁ and Free
open Categories.Free.Core public
  using (Free₀)
open Categories.Free.Functor public
  using (Free)

-- TODO:
--  Prove Free⊣Underlying : Adjunction Free Underlying
--  Define Adjunction.left and Adjunction.right as conveniences
--    (or whatever other names make sense for the hom-set maps
--    C [ F _ , _ ] → D [ _ , G _ ] and inverse, respectively)
--  Let Cata = Adjunction.left Free⊣Underlying
Cata : ∀{o₁ ℓ₁ e₁}{G : Graph    o₁ ℓ₁ e₁}
        {o₂ ℓ₂ e₂}{C : Category o₂ ℓ₂ e₂}
  → (F : GraphMorphism G (Underlying₀ C))
  → Functor (Free₀ G) C
Cata {G = G} {C = C} F = record
  { F₀            = F₀
  ; F₁            = F₁*
  ; identity      = refl
  ; homomorphism  = λ{X}{Y}{Z}{f}{g} → homomorphism {X}{Y}{Z}{f}{g}
  ; F-resp-≡      = F₁*-resp-≡
  }
  where
    open Category C
    open GraphMorphism F
    open Equiv
    open HomReasoning
    open PathEquality using (ε-cong; _◅-cong_)

    F₁* : ∀ {A B} → Free₀ G [ A , B ] → C [ F₀ A , F₀ B ]
    F₁* ε = id
    F₁* (f ◅ fs) = F₁* fs ∘ F₁ f

    .homomorphism : ∀ {X Y Z} {f : Free₀ G [ X , Y ]} {g : Free₀ G [ Y , Z ]}
                  → C [ F₁* (Free₀ G [ g ∘ f ]) ≡ C [ F₁* g ∘ F₁* f ] ]
    homomorphism {f = ε} = sym identityʳ
    homomorphism {f = f ◅ fs}{gs} =
      begin
        F₁* (fs ◅◅ gs) ∘ F₁ f
      ↓⟨ homomorphism {f = fs}{gs} ⟩∘⟨ refl ⟩
        (F₁* gs ∘ F₁* fs) ∘ F₁ f
      ↓⟨ assoc ⟩
        F₁* gs ∘ F₁* fs ∘ F₁ f
      ∎

    .F₁*-resp-≡ : ∀ {A B} {f g : Free₀ G [ A , B ]} → Free₀ G [ f ≡ g ] → C [ F₁* f ≡ F₁* g ]
    F₁*-resp-≡ {f = ε}{.ε} ε-cong = refl
    F₁*-resp-≡ {f = f ◅ fs}{g ◅ gs} (f≈g ◅-cong fs≈gs) =
      begin
        F₁* fs ∘ F₁ f
      ↓⟨ F₁*-resp-≡ fs≈gs ⟩∘⟨ F-resp-≈ f≈g ⟩
        F₁* gs ∘ F₁ g
      ∎
    F₁*-resp-≡ {f = f ◅ fs}{ε} ()


module Pi.AuxLemmas where
open import Data.Empty
open import Data.Unit
open import Data.Sum
open import Data.Product
open import Relation.Binary.PropositionalEquality
open import Pi.Syntax
open import Pi.Opsem

Lemma₁ : ∀ {A B C D v v' κ κ'} {c : A ↔ B} {c' : C ↔ D}
           → ⟨ c ∣ v ∣ κ ⟩ ↦ ［ c' ∣ v' ∣ κ' ］
           → A ≡ C × B ≡ D
Lemma₁ ↦₁ = refl , refl
Lemma₁ ↦₂ = refl , refl

Lemma₂ : ∀ {A B v v' κ κ'} {c c' : A ↔ B}
           → ⟨ c ∣ v ∣ κ ⟩ ↦ ［ c' ∣ v' ∣ κ' ］
           → c ≡ c' × κ ≡ κ'
Lemma₂ ↦₁ = refl , refl
Lemma₂ ↦₂ = refl , refl

Lemma₃ : ∀ {A B v v' κ} {c : A ↔ B}
           → (r : ⟨ c ∣ v ∣ κ ⟩ ↦ ［ c ∣ v' ∣ κ ］)
           → base c ⊎ A ≡ B
Lemma₃ (↦₁ {b = b}) = inj₁ b
Lemma₃ ↦₂ = inj₂ refl

Lemma₄ : ∀ {A v v' κ} {c : A ↔ A}
           → (r : ⟨ c ∣ v ∣ κ ⟩ ↦ ［ c ∣ v' ∣ κ ］)
           → base c ⊎ c ≡ id↔
Lemma₄ {c = swap₊} ↦₁ = inj₁ tt
Lemma₄ {c = swap⋆} ↦₁ = inj₁ tt
Lemma₄ ↦₂ = inj₂ refl


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

module Cubical.Data.Fin.Recursive.Base where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Empty as Empty hiding (rec; elim)
open import Cubical.Data.Nat hiding (elim)

data FinF (X : Type₀) : Type₀ where
  zero : FinF X
  suc : X → FinF X

Fin : ℕ → Type₀
Fin zero = ⊥
Fin (suc k) = FinF (Fin k)

private
  variable
    ℓ : Level
    k : ℕ
    R : Type ℓ

rec : R → (R → R) → Fin k → R
rec {k = suc k} z _ zero = z
rec {k = suc k} z s (suc x) = s (rec z s x)

elim
  : ∀(P : ∀{k} → Fin k → Type ℓ)
  → (∀{k} → P {suc k} zero)
  → (∀{k} (fn : Fin k) → P fn → P {suc k} (suc fn))
  → (fn : Fin k) → P fn
elim {k = suc k} P fz fs zero = fz
elim {k = suc k} P fz fs (suc x) = fs x (elim P fz fs x)


------------------------------------------------------------------------
-- The Agda standard library
--
-- The binary relation defined by a constant
------------------------------------------------------------------------

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

module Relation.Binary.Construct.Constant where

open import Relation.Binary

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

Const : ∀ {a b c} {A : Set a} {B : Set b} → Set c → REL A B c
Const I = λ _ _ → I

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

module _ {a c} (A : Set a) {C : Set c} where

  refl : C → Reflexive {A = A} (Const C)
  refl c = c

  sym : Symmetric {A = A} (Const C)
  sym c = c

  trans : Transitive {A = A} (Const C)
  trans c d = c

  isEquivalence : C → IsEquivalence {A = A} (Const C)
  isEquivalence c = record
    { refl  = λ {x} → refl c {x}
    ; sym   = λ {x} {y} → sym {x} {y}
    ; trans = λ {x} {y} {z} → trans {x} {y} {z}
    }

  setoid : C → Setoid a c
  setoid x = record { isEquivalence = isEquivalence x }


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

open import Prelude
open import Categories

module Categories.Coequalizer {ℓ₁ ℓ₂} (C : Category ℓ₁ ℓ₂) where

open Category C

private
  variable
    h i : X ⟶ Y

record Coequalizer (f g : X ⟶ Y) : Type (ℓ₁ ℓ⊔ ℓ₂) where
  field
    {obj} : Ob
    arr   : Y ⟶ obj

    equality   : arr · f ≡ arr · g
    coequalize : ∀ {H} {h : Y ⟶ H} → h · f ≡ h · g → obj ⟶ H
    universal  : ∀ {H} {h : Y ⟶ H} {eq : h · f ≡ h · g} → h ≡ coequalize eq · arr
    unique     : ∀ {H} {h : Y ⟶ H} {i : obj ⟶ H} {eq : h · f ≡ h · g} → h ≡ i · arr → i ≡ coequalize eq


module API.Theorems where

open import Algebra
open import Algebra.Theorems
open import API
open import Prelude
open import Reasoning

-- vertices [x] == vertex x
vertices-vertex : ∀ {A} {x : A} -> vertices [ x ] ≡ vertex x
vertices-vertex = +identity >> reflexivity

-- edge x y == clique [x, y]
edge-clique : ∀ {A} {x y : A} -> edge x y ≡ clique (x :: [ y ])
edge-clique = symmetry (R *right-identity)

-- vertices xs ⊆ clique xs
vertices-clique : ∀ {A} {xs : List A} -> vertices xs ⊆ clique xs
vertices-clique {_} {[]}     = ⊆reflexivity
vertices-clique {a} {_ :: t} = ⊆transitivity (⊆right-monotony (vertices-clique {a} {t})) ⊆connect

-- clique (xs ++ ys) == connect (clique xs) (clique ys)
connect-clique : ∀ {A} {xs ys : List A} -> clique (xs ++ ys) ≡ connect (clique xs) (clique ys)
connect-clique {_} {[]}     = symmetry *left-identity
connect-clique {a} {_ :: t} = R (connect-clique {a} {t}) >> *associativity


import Relation.Binary.EqReasoning as EqReasoning
open import SemiNearRingRecords
module ZeroLemmas (snr : SemiNearRing) where
  open SemiNearRing snr -- public
  open import CommAssocLemmas s _≃s_ _+s_ zers isCommMon hiding (_<+>_) renaming (SA to Ss)

  zeroˡLemma : ∀ x y → zers *s x +s zers *s y ≃s zers
  zeroˡLemma x y = begin
         zers *s x +s zers *s y
       ≈⟨ zeroˡ x <+> zeroˡ y ⟩
         zers +s zers
       ≈⟨ identityˡs zers ⟩
         zers
       ∎
    where open EqReasoning Ss

  zeroʳLemma : ∀ x y →  x *s zers  +s  y *s zers   ≃s  zers
  zeroʳLemma x y =
       begin
           x *s zers  +s   y *s zers
       ≈⟨  zeroʳ x    <+>  zeroʳ y ⟩
         zers         +s   zers
       ≈⟨ identityˡs zers ⟩
         zers
       ∎
    where open EqReasoning Ss

  zeroˡʳLemma : ∀ w x y → w +s (zers *s x +s  y *s zers)  ≃s  w
  zeroˡʳLemma w x y = begin
        w +s (zers *s x  +s  y *s zers)
     ≈⟨ refls <+> (zeroˡ x <+> zeroʳ y) ⟩
        w +s (zers +s zers)
     ≈⟨ refls <+> identityˡs zers ⟩
        w +s zers
     ≈⟨ identityʳs w ⟩
        w
     ∎
     where open EqReasoning Ss

  -- Some lemmas are needed to eliminate the zers and massage the terms.
  zeroLemma01 = lemmaCommAssoc01

  zeroLemma10 : ∀ {a b c d e} →   a +s ( ((zers *s b) +s c) +s (d +s (e *s zers)))
                              ≃s  a +s                 ( c  +s  d )
  zeroLemma10 {a} {b} {c} {d} {e} = refls <+>
    (begin
       ((zers *s b) +s c)      +s (d      +s (e *s zers))
     ≈⟨ (zeroˡ   b <+> refls) <+> (refls <+>  zeroʳ e) ⟩
       ( zers       +s c)      +s (d      +s zers)
     ≈⟨ identityˡs c <+> identityʳs d ⟩
        c +s d
     ∎)
      where open EqReasoning Ss

  zeroLemma00 : ∀ {a b c d e} →   a +s ((c +s b) +s (d +s (e *s zers)) )
                             ≃s  (a +s b) +s (c  +s  d)
  zeroLemma00 {a} {b} {c} {d} {e} =
    (begin
       a       +s ((c +s b)   +s (d      +s (e *s zers)) )
     ≈⟨ refls <+> (comms c b <+> (refls <+> zeroʳ e)) ⟩
       a       +s ((b +s c)   +s (d      +s zers) )
     ≈⟨ refls <+> (refls <+> identityʳs d) ⟩
       a       +s ((b +s c)   +s d)
     ≈⟨ refls <+> assocs b c d ⟩
       a +s (b +s (c +s d))
     ≈⟨ syms (assocs a b _) ⟩
       (a +s b) +s (c +s d)
     ∎)
      where open EqReasoning Ss

  zeroLemma11 : ∀ {a b c d e} →   a +s (((zers *s e)  +s  c) +s (b +s d))
                             ≃s  (a +s b) +s (c +s  d)
  zeroLemma11 {a} {b} {c} {d} {e} =
    (begin
       a       +s (((zers *s e)  +s  c)     +s (b +s d))
     ≈⟨ refls <+> ((zeroˡ e     <+> refls) <+> refls) ⟩
       a       +s ((zers        +s  c)      +s (b +s d))
     ≈⟨ refls <+> (identityˡs c            <+> refls) ⟩
       a       +s (                 c       +s (b +s d))
     ≈⟨ refls <+> syms (assocs c b d) ⟩
       a       +s ((c +s b) +s d)
     ≈⟨ refls <+> (comms c b <+> refls) ⟩
       a       +s ((b +s c) +s d)
     ≈⟨ refls <+> (assocs _ _ _) ⟩
       a       +s (b +s (c +s d))
     ≈⟨ syms (assocs _ _ _) ⟩
       (a +s b) +s (c +s d)
     ∎)
      where open EqReasoning Ss


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

open import LogicalFormulae
open import Orders.Total.Definition
open import Orders.Partial.Definition
open import Setoids.Setoids
open import Setoids.Orders.Partial.Definition
open import Setoids.Orders.Total.Definition
open import Functions.Definition
open import Sets.EquivalenceRelations

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

module Setoids.Orders.Total.Lemmas {a b : _} {A : Set a} {S : Setoid {a} {b} A} {c : _} {_<_ : A → A → Set c} {P : SetoidPartialOrder S _<_} (T : SetoidTotalOrder P) where

open SetoidTotalOrder T
open SetoidPartialOrder P
open Setoid S
open Equivalence eq

maxInequalitiesR : {a b c : A} → (a < b) → (a < c) → (a < max b c)
maxInequalitiesR {a} {b} {c} a<b a<c with totality b c
... | inl (inl x) = a<c
... | inl (inr x) = a<b
... | inr x = a<c

minInequalitiesR : {a b c : A} → (a < b) → (a < c) → (a < min b c)
minInequalitiesR {a} {b} {c} a<b a<c with totality b c
... | inl (inl x) = a<b
... | inl (inr x) = a<c
... | inr x = a<b

maxInequalitiesL : {a b c : A} → (a < c) → (b < c) → (max a b < c)
maxInequalitiesL {a} {b} {c} a<b a<c with totality a b
... | inl (inl x) = a<c
... | inl (inr x) = a<b
... | inr x = a<c

minInequalitiesL : {a b c : A} → (a < c) → (b < c) → (min a b < c)
minInequalitiesL {a} {b} {c} a<b a<c with totality a b
... | inl (inl x) = a<b
... | inl (inr x) = a<c
... | inr x = a<b

minLessL : (a b : A) → min a b <= a
minLessL a b with totality a b
... | inl (inl x) = inr reflexive
... | inl (inr x) = inl x
... | inr x = inr reflexive

minLessR : (a b : A) → min a b <= b
minLessR a b with totality a b
... | inl (inl x) = inl x
... | inl (inr x) = inr reflexive
... | inr x = inr x

maxGreaterL : (a b : A) → a <= max a b
maxGreaterL a b with totality a b
... | inl (inl x) = inl x
... | inl (inr x) = inr reflexive
... | inr x = inr x

maxGreaterR : (a b : A) → b <= max a b
maxGreaterR a b with totality a b
... | inl (inl x) = inr reflexive
... | inl (inr x) = inl x
... | inr x = inr reflexive


{-

This file contains:

- Properties of 2-groupoid truncations

-}
{-# OPTIONS --cubical --safe #-}
module Cubical.HITs.2GroupoidTruncation.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.HITs.2GroupoidTruncation.Base

rec : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} (gB : is2Groupoid B) → (A → B) → (∥ A ∥₂ → B)
rec gB f ∣ x ∣₂ = f x
rec gB f (squash₂ _ _ _ _ _ _ t u i j k l) =
  gB _ _ _ _ _ _
    (λ m n o → rec gB f (t m n o))
    (λ m n o → rec gB f (u m n o))
    i j k l

elim : ∀ {ℓ ℓ'} {A : Type ℓ} {B : ∥ A ∥₂ → Type ℓ'}
  (bG : (x : ∥ A ∥₂) → is2Groupoid (B x))
  (f : (x : A) → B ∣ x ∣₂) (x : ∥ A ∥₂) → B x
elim bG f ∣ x ∣₂ = f x
elim bG f (squash₂ x y p q r s u v i j k l) =
  isOfHLevel→isOfHLevelDep 4 bG _ _ _ _ _ _
    (λ j k l → elim bG f (u j k l)) (λ j k l → elim bG f (v j k l))
    (squash₂ x y p q r s u v)
    i j k l


module #15 where

{-
  Show that indiscernability of identicals follows from path induction
-}

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

id : ∀{x}{A : Set x} → A → A
id x = x

ind₌ : ∀{a}{A : Set a} → (C : (x y : A) → (x ≡ y) → Set) → ((x : A) → C x x refl) → (x y : A) → (p : x ≡ y) → C x y p
ind₌ C c x y p rewrite p =  c y

based-ind₌ : ∀{x}{A : Set x} → (a : A) → (C : (x : A) → (a ≡ x) → Set) → C a refl → (x : A) → (p : a ≡ x) → C x p
based-ind₌ a C c b p rewrite p = c

indiscernability-of-identicals : {A : Set}{C : A → Set} → Σ[ f ∈ ((x y : A) → (x ≡ y) → C x → C y) ]((x : A) → f x x refl ≡ id {A = C x})
indiscernability-of-identicals {A} {C} = transport , (λ _ → refl)
  where
    transport : (x y : A) → (p : x ≡ y) → C x → C y
    transport = ind₌ (λ x y _ → C x → C y) (λ x z → z)


module Equality where

open import Agda.Builtin.Equality public
open import Relation.Nullary

infix 4 _≅_ _≢_
infixr 2 _≡⟨_⟩_
infix  3 _QED

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

≡→≅ : ∀ {ℓ} {A : Set ℓ} {a b : A} → a ≡ b → a ≅ b
≡→≅ refl = refl

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

sym′ : ∀ {ℓ} {A B : Set ℓ} {a : A} {b : B} → a ≅ b → b ≅ a
sym′ refl = refl

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

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

cong-app : ∀ {a b} {A : Set a} {B : A → Set b} {f g : (x : A) → B x} →
           f ≡ g → (x : A) → f x ≡ g x
cong-app refl x = refl

cong₂ : ∀ {a b c} {A : Set a} {B : Set b} {C : Set c}
        (f : A → B → C) {x y u v} → x ≡ y → u ≡ v → f x u ≡ f y v
cong₂ f refl refl = refl

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

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

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


------------------------------------------------------------------------
-- Possibly infinite binary trees
------------------------------------------------------------------------

module Tree where

open import Codata.Musical.Notation
import Relation.Binary.PropositionalEquality as PropEq
open PropEq using (_≡_)

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

map : ∀ {A B} → (A → B) → Tree A → Tree B
map f leaf         = leaf
map f (node l x r) = node (♯ map f (♭ l)) (f x) (♯ map f (♭ r))

data _≈_ {A : Set} : (t₁ t₂ : Tree A) → Set where
  leaf : leaf ≈ leaf
  node : ∀ {l₁ l₂ x₁ x₂ r₁ r₂}
         (l≈ : ∞ (♭ l₁ ≈ ♭ l₂)) (x≡ : x₁ ≡ x₂) (r≈ : ∞ (♭ r₁ ≈ ♭ r₂)) →
         node l₁ x₁ r₁ ≈ node l₂ x₂ r₂

refl : ∀ {A} (t : Tree A) → t ≈ t
refl leaf         = leaf
refl (node l x r) = node (♯ refl (♭ l)) PropEq.refl (♯ refl (♭ r))

trans : ∀ {A} {t₁ t₂ t₃ : Tree A} →
        t₁ ≈ t₂ → t₂ ≈ t₃ → t₁ ≈ t₃
trans leaf            leaf               = leaf
trans (node l≈ x≡ r≈) (node l≈′ x≡′ r≈′) =
  node (♯ trans (♭ l≈) (♭ l≈′)) (PropEq.trans x≡ x≡′)
       (♯ trans (♭ r≈) (♭ r≈′))

map-cong : ∀ {A B} (f : A → B) {t₁ t₂ : Tree A} →
           t₁ ≈ t₂ → map f t₁ ≈ map f t₂
map-cong f leaf            = leaf
map-cong f (node l≈ x≡ r≈) =
  node (♯ map-cong f (♭ l≈)) (PropEq.cong f x≡) (♯ map-cong f (♭ r≈))


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

open import Algebra.Structures.Bundles.Field

module Algebra.Linear.Structures.VectorSpace
  {k ℓᵏ} (K : Field k ℓᵏ)
  where

open import Algebra.FunctionProperties
open import Relation.Binary using (Rel)
open import Level using (_⊔_)
open import Data.Nat using (ℕ)

module VectorSpaceField where
    open Field K public
      using ()
      renaming
      ( Carrier       to K'
      ; _≈_           to _≈ᵏ_
      ; refl          to ≈ᵏ-refl
      ; sym           to ≈ᵏ-sym
      ; trans         to ≈ᵏ-trans
      ; reflexive     to ≈ᵏ-reflexive
      ; isEquivalence to ≈ᵏ-isEquiv
      ; setoid        to K-setoid
      ; _+_           to _+ᵏ_
      ; _*_           to _*ᵏ_
      ; _-_           to _-ᵏ_
      ; 0#            to 0ᵏ
      ; 1#            to 1ᵏ
      ; -_            to -ᵏ_
      ; _⁻¹            to _⁻¹ᵏ
      ; +-cong        to +ᵏ-cong
      ; +-identity    to +ᵏ-identity
      ; +-identityˡ    to +ᵏ-identityˡ
      ; +-identityʳ    to +ᵏ-identityʳ
      ; +-assoc       to +ᵏ-assoc
      ; +-comm        to +ᵏ-comm
      ; *-cong        to *ᵏ-cong
      ; *-identity    to *ᵏ-identity
      ; *-identityˡ    to *ᵏ-identityˡ
      ; *-identityʳ    to *ᵏ-identityʳ
      ; *-assoc       to *ᵏ-assoc
      ; *-comm        to *ᵏ-comm
      ; zero          to *ᵏ-zero
      ; zeroˡ          to *ᵏ-zeroˡ
      ; zeroʳ          to *ᵏ-zeroʳ
      ; distrib       to *ᵏ-+ᵏ-distrib
      ; distribˡ      to *ᵏ-+ᵏ-distribˡ
      ; distribʳ      to *ᵏ-+ᵏ-distribʳ
      ; -‿distribˡ-*  to -ᵏ‿distribˡ-*ᵏ
      ; -‿distribʳ-*  to -ᵏ‿distribʳ-*ᵏ
      ; -‿cong       to -ᵏ‿cong
      ; -‿inverse    to -ᵏ‿inverse
      ; -‿inverseˡ    to -ᵏ‿inverseˡ
      ; -‿inverseʳ    to -ᵏ‿inverseʳ
      ; uniqueˡ-⁻¹     to uniqueˡ-⁻¹ᵏ
      ; uniqueʳ-⁻¹     to uniqueʳ-⁻¹ᵏ
      ; _⁻¹-inverse    to _⁻¹ᵏ-inverse
      ; _⁻¹-involutive to _⁻¹ᵏ-involutive
      ; 0#-not-1#     to 0ᵏ-not-1ᵏ
      )

module _
  {v ℓ} {V : Set v}
  (_≈_ : Rel V ℓ)
  where

  open VectorSpaceField

  open import Algebra.Structures _≈_

  record IsVectorSpace (_+_ : Op₂ V) (_∙_ : K' → V → V) (-_ : Op₁ V) (0# : V) : Set (v ⊔ k ⊔ ℓ ⊔ ℓᵏ) where
    field
      isAbelianGroup : IsAbelianGroup _+_ 0# -_
      *ᵏ-∙-compat    : ∀ (a b : K') (u : V) -> ((a *ᵏ b) ∙ u) ≈ (a ∙ (b ∙ u))
      ∙-+-distrib    : ∀ (a : K') (u v : V) -> (a ∙ (u + v)) ≈ ((a ∙ u) + (a ∙ v))
      ∙-+ᵏ-distrib   : ∀ (a b : K') (u : V) -> ((a +ᵏ b) ∙ u) ≈ ((a ∙ u) + (b ∙ u))
      ∙-cong         : ∀ {a b : K'} {u v : V} -> a ≈ᵏ b -> u ≈ v -> (a ∙ u) ≈ (b ∙ v)
      ∙-identity     : ∀ (x : V) → (1ᵏ ∙ x) ≈ x
      ∙-absorbˡ       : ∀ (x : V) → (0ᵏ ∙ x) ≈ 0#

    open IsAbelianGroup isAbelianGroup public
      renaming
      ( assoc     to +-assoc
      ; ∙-cong    to +-cong
      ; identity  to +-identity
      ; identityˡ  to +-identityˡ
      ; identityʳ  to +-identityʳ
      ; comm      to +-comm
      ; inverse   to -‿inverse
      ; inverseˡ   to -‿inverseˡ
      ; inverseʳ   to -‿inverseʳ
      ; ⁻¹-cong    to -‿cong
      )

    open import Algebra.Properties.AbelianGroup (record { isAbelianGroup = isAbelianGroup }) public
      renaming
      ( ε⁻¹≈ε            to -0≈0
      ; ∙-cancelˡ        to +-cancelˡ
      ; ∙-cancelʳ        to +-cancelʳ
      ; ∙-cancel        to +-cancel
      ; identityˡ-unique to +-identityˡ-unique
      ; identityʳ-unique to +-identityʳ-unique
      ; identity-unique to +-identity-unique
      ; inverseˡ-unique  to +-inverseˡ-unique
      ; inverseʳ-unique  to +-inverseʳ-unique
      ; xyx⁻¹≈y          to x+y-x≈y
      ; ⁻¹-∙-comm        to -‿+-comm
      )

    open import Relation.Binary.EqReasoning setoid

    ∙-absorbʳ : ∀ (a : K') -> (a ∙ 0#) ≈ 0#
    ∙-absorbʳ a =
      begin
        a ∙ 0#
      ≈⟨ trans (∙-cong ≈ᵏ-refl (sym (∙-absorbˡ 0#))) (sym (*ᵏ-∙-compat a 0ᵏ 0#))  ⟩
        (a *ᵏ 0ᵏ) ∙ 0#
      ≈⟨ ∙-cong (*ᵏ-zeroʳ a) refl ⟩
        0ᵏ ∙ 0#
      ≈⟨ ∙-absorbˡ 0# ⟩
        0#
      ∎

    ∙-∙-comm : ∀ (a b : K') (u : V) -> (a ∙ (b ∙ u)) ≈ (b ∙ (a ∙ u))
    ∙-∙-comm a b u =
      begin
        a ∙ (b ∙ u)
      ≈⟨ sym (*ᵏ-∙-compat a b u) ⟩
        (a *ᵏ b) ∙ u
      ≈⟨ ∙-cong (*ᵏ-comm a b) refl ⟩
        (b *ᵏ a) ∙ u
      ≈⟨ *ᵏ-∙-compat b a u ⟩
        b ∙ (a ∙ u)
      ∎

    private
      lemma-inverseʳ : ∀ (u : V) -> (u + ((-ᵏ 1ᵏ) ∙ u)) ≈ 0#
      lemma-inverseʳ u =
        begin
          u + ((-ᵏ 1ᵏ) ∙ u)
        ≈⟨ +-cong (sym (∙-identity u)) refl ⟩
          (1ᵏ ∙ u) + ((-ᵏ 1ᵏ) ∙ u)
        ≈⟨ sym (∙-+ᵏ-distrib 1ᵏ (-ᵏ 1ᵏ) u) ⟩
          (1ᵏ +ᵏ (-ᵏ 1ᵏ)) ∙ u
        ≈⟨ ∙-cong (-ᵏ‿inverseʳ 1ᵏ) refl ⟩
          0ᵏ ∙ u
        ≈⟨ ∙-absorbˡ u ⟩
          0#
        ∎

    -1∙u≈-u : ∀ (u : V) -> ((-ᵏ 1ᵏ) ∙ u) ≈ (- u)
    -1∙u≈-u u =
      begin
        ((-ᵏ 1ᵏ) ∙ u)
      ≈⟨ +-inverseʳ-unique u ((-ᵏ 1ᵏ) ∙ u) (lemma-inverseʳ u) ⟩
        - u
      ∎


------------------------------------------------------------------------
-- The Agda standard library
--
-- Well-founded induction
------------------------------------------------------------------------

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

open import Relation.Binary

module Induction.WellFounded where

open import Data.Product
open import Function
open import Induction
open import Level
open import Relation.Binary.PropositionalEquality hiding (trans)
open import Relation.Unary

private
  variable
    a b ℓ ℓ₁ ℓ₂ r : Level
    A : Set a
    B : Set b

------------------------------------------------------------------------
-- Definitions

-- When using well-founded recursion you can recurse arbitrarily, as
-- long as the arguments become smaller, and "smaller" is
-- well-founded.

WfRec : Rel A r → ∀ {ℓ} → RecStruct A ℓ _
WfRec _<_ P x = ∀ y → y < x → P y

-- The accessibility predicate: x is accessible if everything which is
-- smaller than x is also accessible (inductively).

data Acc {A : Set a} (_<_ : Rel A ℓ) (x : A) : Set (a ⊔ ℓ) where
  acc : (rs : WfRec _<_ (Acc _<_) x) → Acc _<_ x

acc-inverse : ∀ {_<_ : Rel A ℓ} {x : A} (q : Acc _<_ x) →
              (y : A) → y < x → Acc _<_ y
acc-inverse (acc rs) y y<x = rs y y<x

-- The accessibility predicate encodes what it means to be
-- well-founded; if all elements are accessible, then _<_ is
-- well-founded.

WellFounded : Rel A ℓ → Set _
WellFounded _<_ = ∀ x → Acc _<_ x

Well-founded = WellFounded
{-# WARNING_ON_USAGE Well-founded
"Warning: Well-founded was deprecated in v0.15.
Please use WellFounded instead."
#-}

------------------------------------------------------------------------
-- Basic properties

Acc-resp-≈ : {_≈_ : Rel A ℓ₁} {_<_ : Rel A ℓ₂} → Symmetric _≈_ →
             _<_ Respectsʳ _≈_ → (Acc _<_) Respects _≈_
Acc-resp-≈ sym respʳ x≈y (acc rec) =
  acc (λ z z<y → rec z (respʳ (sym x≈y) z<y))

------------------------------------------------------------------------
-- Well-founded induction for the subset of accessible elements:

module Some {_<_ : Rel A r} {ℓ} where

  wfRecBuilder : SubsetRecursorBuilder (Acc _<_) (WfRec _<_ {ℓ = ℓ})
  wfRecBuilder P f x (acc rs) = λ y y<x →
    f y (wfRecBuilder P f y (rs y y<x))

  wfRec : SubsetRecursor (Acc _<_) (WfRec _<_)
  wfRec = subsetBuild wfRecBuilder

  unfold-wfRec : (P : Pred A ℓ) (f : WfRec _<_ P ⊆′ P) {x : A} (q : Acc _<_ x) →
                 wfRec P f x q ≡ f x (λ y y<x → wfRec P f y (acc-inverse q y y<x))
  unfold-wfRec P f (acc rs) = refl

  wfRec-builder = wfRecBuilder
  {-# WARNING_ON_USAGE wfRec-builder
  "Warning: wfRec-builder was deprecated in v0.15.
\ \Please use wfRecBuilder instead."
  #-}

------------------------------------------------------------------------
-- Well-founded induction for all elements, assuming they are all
-- accessible:

module All {_<_ : Rel A r} (wf : WellFounded _<_) ℓ where

  wfRecBuilder : RecursorBuilder (WfRec _<_ {ℓ = ℓ})
  wfRecBuilder P f x = Some.wfRecBuilder P f x (wf x)

  wfRec : Recursor (WfRec _<_)
  wfRec = build wfRecBuilder

  wfRec-builder = wfRecBuilder
  {-# WARNING_ON_USAGE wfRec-builder
  "Warning: wfRec-builder was deprecated in v0.15.
\ \Please use wfRecBuilder instead."
  #-}

module FixPoint
  {_<_ : Rel A ℓ} (wf : WellFounded _<_)
  (P : Pred A ℓ) (f : WfRec _<_ P ⊆′ P)
  (f-ext : (x : A) {IH IH' : WfRec _<_ P x} → (∀ {y} y<x → IH y y<x ≡ IH' y y<x) → f x IH ≡ f x IH')
  where

  some-wfRec-irrelevant : ∀ x → (q q' : Acc _<_ x) → Some.wfRec P f x q ≡ Some.wfRec P f x q'
  some-wfRec-irrelevant = All.wfRec wf _
                                   (λ x → (q q' : Acc _<_ x) → Some.wfRec P f x q ≡ Some.wfRec P f x q')
                                   (λ { x IH (acc rs) (acc rs') → f-ext x (λ y<x → IH _ y<x (rs _ y<x) (rs' _ y<x)) })

  open All wf ℓ
  wfRecBuilder-wfRec : ∀ {x y} y<x → wfRecBuilder P f x y y<x ≡ wfRec P f y
  wfRecBuilder-wfRec {x} {y} y<x with wf x
  ... | acc rs = some-wfRec-irrelevant y (rs y y<x) (wf y)

  unfold-wfRec : ∀ {x} → wfRec P f x ≡ f x (λ y _ → wfRec P f y)
  unfold-wfRec {x} = f-ext x wfRecBuilder-wfRec

------------------------------------------------------------------------
-- It might be useful to establish proofs of Acc or Well-founded using
-- combinators such as the ones below (see, for instance,
-- "Constructing Recursion Operators in Intuitionistic Type Theory" by
-- Lawrence C Paulson).

module Subrelation {_<₁_ : Rel A ℓ₁} {_<₂_ : Rel A ℓ₂}
                   (<₁⇒<₂ : ∀ {x y} → x <₁ y → x <₂ y) where

  accessible : Acc _<₂_ ⊆ Acc _<₁_
  accessible (acc rs) = acc (λ y y<x → accessible (rs y (<₁⇒<₂ y<x)))

  wellFounded : WellFounded _<₂_ → WellFounded _<₁_
  wellFounded wf = λ x → accessible (wf x)

  well-founded = wellFounded
  {-# WARNING_ON_USAGE well-founded
  "Warning: well-founded was deprecated in v0.15.
\ \Please use wellFounded instead."
  #-}

module InverseImage {_<_ : Rel B ℓ} (f : A → B) where

  accessible : ∀ {x} → Acc _<_ (f x) → Acc (_<_ on f) x
  accessible (acc rs) = acc (λ y fy<fx → accessible (rs (f y) fy<fx))

  wellFounded : WellFounded _<_ → WellFounded (_<_ on f)
  wellFounded wf = λ x → accessible (wf (f x))

  well-founded = wellFounded
  {-# WARNING_ON_USAGE well-founded
  "Warning: well-founded was deprecated in v0.15.
\ \Please use wellFounded instead."
  #-}

module TransitiveClosure {A : Set a} (_<_ : Rel A ℓ) where

  infix 4 _<⁺_

  data _<⁺_ : Rel A (a ⊔ ℓ) where
    [_]   : ∀ {x y} (x<y : x < y) → x <⁺ y
    trans : ∀ {x y z} (x<y : x <⁺ y) (y<z : y <⁺ z) → x <⁺ z

  downwardsClosed : ∀ {x y} → Acc _<⁺_ y → x <⁺ y → Acc _<⁺_ x
  downwardsClosed (acc rs) x<y = acc (λ z z<x → rs z (trans z<x x<y))

  mutual

    accessible : ∀ {x} → Acc _<_ x → Acc _<⁺_ x
    accessible acc-x = acc (accessible′ acc-x)

    accessible′ : ∀ {x} → Acc _<_ x → WfRec _<⁺_ (Acc _<⁺_) x
    accessible′ (acc rs) y [ y<x ]         = accessible (rs y y<x)
    accessible′ acc-x    y (trans y<z z<x) =
      downwardsClosed (accessible′ acc-x _ z<x) y<z

  wellFounded : WellFounded _<_ → WellFounded _<⁺_
  wellFounded wf = λ x → accessible (wf x)

  downwards-closed = downwardsClosed
  {-# WARNING_ON_USAGE downwards-closed
  "Warning: downwards-closed was deprecated in v0.15.
\ \Please use downwardsClosed instead."
  #-}
  well-founded     = wellFounded
  {-# WARNING_ON_USAGE well-founded
  "Warning: well-founded was deprecated in v0.15.
\ \Please use wellFounded instead."
  #-}

-- DEPRECATED in v1.3.
-- Please use `×-Lex` from `Data.Product.Relation.Binary.Lex.Strict` instead.
module Lexicographic {A : Set a} {B : A → Set b}
                     (RelA : Rel A ℓ₁)
                     (RelB : ∀ x → Rel (B x) ℓ₂) where

  data _<_ : Rel (Σ A B) (a ⊔ b ⊔ ℓ₁ ⊔ ℓ₂) where
    left  : ∀ {x₁ y₁ x₂ y₂} (x₁<x₂ : RelA   x₁ x₂) → (x₁ , y₁) < (x₂ , y₂)
    right : ∀ {x y₁ y₂}     (y₁<y₂ : RelB x y₁ y₂) → (x  , y₁) < (x  , y₂)

  mutual

    accessible : ∀ {x y} →
                 Acc RelA x → (∀ {x} → WellFounded (RelB x)) →
                 Acc _<_ (x , y)
    accessible accA wfB = acc (accessible′ accA (wfB _) wfB)

    accessible′ :
      ∀ {x y} →
      Acc RelA x → Acc (RelB x) y → (∀ {x} → WellFounded (RelB x)) →
      WfRec _<_ (Acc _<_) (x , y)
    accessible′ (acc rsA) _    wfB ._ (left  x′<x) = accessible (rsA _ x′<x) wfB
    accessible′ accA (acc rsB) wfB ._ (right y′<y) =
      acc (accessible′ accA (rsB _ y′<y) wfB)

  wellFounded : WellFounded RelA → (∀ {x} → WellFounded (RelB x)) →
                WellFounded _<_
  wellFounded wfA wfB p = accessible (wfA (proj₁ p)) wfB

  well-founded = wellFounded

  {-# WARNING_ON_USAGE _<_
  "Warning: _<_ was deprecated in v1.3.
\ \Please use `×-Lex` from `Data.Product.Relation.Binary.Lex.Strict` instead."
  #-}
  {-# WARNING_ON_USAGE accessible
  "Warning: accessible was deprecated in v1.3."
  #-}
  {-# WARNING_ON_USAGE accessible′
  "Warning: accessible′ was deprecated in v1.3."
  #-}
  {-# WARNING_ON_USAGE wellFounded
  "Warning: wellFounded was deprecated in v1.3.
\ \Please use `×-wellFounded` from `Data.Product.Relation.Binary.Lex.Strict` instead."
  #-}
  {-# WARNING_ON_USAGE well-founded
  "Warning: well-founded was deprecated in v0.15.
\ \Please use wellFounded instead."
  #-}

------------------------------------------------------------------------
-- DEPRECATED NAMES
------------------------------------------------------------------------
-- Please use the new names as continuing support for the old names is
-- not guaranteed.

-- Version 1.0

module Inverse-image = InverseImage
module Transitive-closure = TransitiveClosure


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

open import HoTT
open import homotopy.elims.Lemmas

{- Given a span [A ←f– C –g→ B] and a map [h : A ⊔_C B → D] where
 - [g] has a left inverse:

 - To define a fundction  [Π (Cof h) P], one can give only the [cfbase],
 - [cfcod], [cfglue∘left], and [cfglue∘right] cases, and construct a map
 - which has the right behavior on [cfbase], [cfcod], [cfglue∘left],
 - with [cfglue∘right] edited to achieve the highest coherence.

 - This is useful for for proving equivalences where (at least) one side
 - involves one of these iterated pushouts. It could be generalized
 - further by loosening from cofiber to some more general class of pushouts,
 - but this is sufficient for the current applications. -}

module homotopy.elims.CofPushoutSection where

module _ {i j k l} {s : Span {i} {j} {k}} {D : Type l}
  {h : Pushout s → D} where

  open Span s

  module CofPushoutSection (r : B → C) (inv : ∀ c → r (g c) == c) where

    elim : ∀ {m} {P : Cofiber h → Type m}
      (cfbase* : P cfbase) (cfcod* : (d : D) → P (cfcod d))
      (cfglue-left* : (a : A) →
        cfbase* == cfcod* (h (left a)) [ P ↓ cfglue (left a) ])
      (cfglue-right* : (b : B) →
        cfbase* == cfcod* (h (right b)) [ P ↓ cfglue (right b) ])
      → Π (Cofiber h) P
    elim {P = P} cfbase* cfcod* cfglue-left* cfglue-right* =
      Cofiber-elim
        cfbase*
        cfcod*
        (Pushout-elim
          cfglue-left*
          (λ b → (fst (fill (r b))) ◃ cfglue-right* b)
          (λ c → ↓↓-from-squareover $
            transport
              (λ c' → SquareOver P (natural-square cfglue (glue c))
                  (cfglue-left* (f c))
                  (↓-ap-in P (λ _ → cfbase) (apd (λ _ → cfbase*) (glue c)))
                  (↓-ap-in P (cfcod ∘ h) (apd (cfcod* ∘ h) (glue c)))
                  (fst (fill c') ◃ cfglue-right* (g c)))
              (! (inv c))
              (snd (fill c))))
      where
      fill : (c : C)
        → Σ (cfbase* == cfbase*)
            (λ q → SquareOver P (natural-square cfglue (glue c))
                     (cfglue-left* (f c)) _ _ (q ◃ cfglue-right* (g c)))
      fill c = fill-upper-right _ _ _ _ _

    rec : ∀ {m} {E : Type m}
      (cfbase* : E) (cfcod* : D → E)
      (cfglue-left* : (a : A) → cfbase* == cfcod* (h (left a)))
      (cfglue-right* : (b : B) → cfbase* == cfcod* (h (right b)))
      → (Cofiber h → E)
    rec cfbase* cfcod* cfglue-left* cfglue-right* =
      elim cfbase* cfcod* (↓-cst-in ∘ cfglue-left*) (↓-cst-in ∘ cfglue-right*)


module list where

open import level
open import bool
open import eq
open import maybe
open import nat
open import unit
open import product
open import empty
open import sum

----------------------------------------------------------------------
-- datatypes
----------------------------------------------------------------------

data 𝕃 {ℓ} (A : Set ℓ) : Set ℓ where
  [] : 𝕃 A
  _::_ : (x : A) (xs : 𝕃 A) → 𝕃 A

{-# BUILTIN LIST 𝕃 #-}
{-# COMPILE GHC 𝕃 = data [] ([] | (:)) #-}

list = 𝕃

----------------------------------------------------------------------
-- syntax
----------------------------------------------------------------------

infixr 6 _::_ _++_
infixr 5 _shorter_ _longer_

----------------------------------------------------------------------
-- operations
----------------------------------------------------------------------

[_] : ∀ {ℓ} {A : Set ℓ} → A → 𝕃 A
[ x ] = x :: []

is-empty : ∀{ℓ}{A : Set ℓ} → 𝕃 A → 𝔹
is-empty [] = tt
is-empty (_ :: _) = ff

tail : ∀ {ℓ} {A : Set ℓ} → 𝕃 A → 𝕃 A
tail [] = []
tail (x :: xs) = xs

head : ∀{ℓ}{A : Set ℓ} → (l : 𝕃 A) → is-empty l ≡ ff → A
head [] ()
head (x :: xs) _ = x

head2 : ∀{ℓ}{A : Set ℓ} → (l : 𝕃 A) → maybe A
head2 [] = nothing
head2 (a :: _) = just a

last : ∀{ℓ}{A : Set ℓ} → (l : 𝕃 A) → is-empty l ≡ ff → A
last [] ()
last (x :: []) _ = x
last (x :: (y :: xs)) _ = last (y :: xs) refl

_++_ : ∀ {ℓ} {A : Set ℓ} → 𝕃 A → 𝕃 A → 𝕃 A
[]        ++ ys = ys
(x :: xs) ++ ys = x :: (xs ++ ys)

concat : ∀{ℓ}{A : Set ℓ} → 𝕃 (𝕃 A) → 𝕃 A
concat [] = []
concat (l :: ls) = l ++ concat ls

repeat : ∀{ℓ}{A : Set ℓ} → ℕ → A → 𝕃 A
repeat 0 a = []
repeat (suc n) a = a :: (repeat n a)

map : ∀ {ℓ ℓ'} {A : Set ℓ} {B : Set ℓ'} → (A → B) → 𝕃 A → 𝕃 B
map f []        = []
map f (x :: xs) = f x :: map f xs

-- The hom part of the list functor.
list-funct : {ℓ : Level}{A B : Set ℓ} → (A → B) → (𝕃 A → 𝕃 B)
list-funct f l = map f l

{- (maybe-map f xs) returns (just ys) if f returns (just y_i) for each
   x_i in the list xs.  Otherwise, (maybe-map f xs) returns nothing. -}
𝕃maybe-map : ∀ {ℓ ℓ'} {A : Set ℓ} {B : Set ℓ'} → (A → maybe B) → 𝕃 A → maybe (𝕃 B)
𝕃maybe-map f []       = just []
𝕃maybe-map f (x :: xs) with f x
𝕃maybe-map f (x :: xs) | nothing = nothing
𝕃maybe-map f (x :: xs) | just y with 𝕃maybe-map f xs
𝕃maybe-map f (x :: xs) | just y | nothing = nothing
𝕃maybe-map f (x :: xs) | just y | just ys = just (y :: ys)

foldr : ∀{ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'} → (A → B → B) → B → 𝕃 A → B
foldr f b [] = b
foldr f b (a :: as) = f a (foldr f b as)

length : ∀{ℓ}{A : Set ℓ} → 𝕃 A → ℕ
length [] = 0
length (x :: xs) = suc (length xs)

reverse-helper : ∀ {ℓ}{A : Set ℓ} → 𝕃 A → 𝕃 A → 𝕃 A
reverse-helper h [] = h
reverse-helper h (x :: xs) = reverse-helper (x :: h) xs

reverse : ∀ {ℓ}{A : Set ℓ} → 𝕃 A → 𝕃 A
reverse l = reverse-helper [] l

reverse-bad : ∀ {ℓ}{A : Set ℓ} → 𝕃 A → 𝕃 A
reverse-bad [] = []
reverse-bad (x :: l) = reverse-bad l ++ [ x ]

list-member : ∀{ℓ}{A : Set ℓ}(eq : A → A → 𝔹)(a : A)(l : 𝕃 A) → 𝔹
list-member eq a [] = ff
list-member eq a (x :: xs) with eq a x
... | tt = tt
... | ff = list-member eq a xs

list-member-prop : ∀{ℓ}{A : Set ℓ}(eq : A → A → 𝔹)(a : A)(l : 𝕃 A) → Set
list-member-prop eq a [] = ⊥
list-member-prop eq a (x :: xs) with eq a x
... | tt = ⊤
... | ff = list-member-prop eq a xs

list-minus : ∀{ℓ}{A : Set ℓ}(eq : A → A → 𝔹)(l1 l2 : 𝕃 A) → 𝕃 A
list-minus eq [] l2 = []
list-minus eq (x :: xs) l2 =
  let r = list-minus eq xs l2 in
    if list-member eq x l2 then r else x :: r

_longer_ : ∀{ℓ}{A : Set ℓ}(l1 l2 : 𝕃 A) → 𝔹
[] longer y = ff
(x :: xs) longer [] = tt
(x :: xs) longer (y :: ys) = xs longer ys

_shorter_ : ∀{ℓ}{A : Set ℓ}(l1 l2 : 𝕃 A) → 𝔹
x shorter y = y longer x

-- return tt iff all elements in the list satisfy the given predicate pred.
list-all : ∀{ℓ}{A : Set ℓ}(pred : A → 𝔹)(l : 𝕃 A) → 𝔹
list-all pred [] = tt
list-all pred (x :: xs) = pred x && list-all pred xs

all-pred : {ℓ : Level}{X : Set ℓ} → (X → Set ℓ) → 𝕃 X → Set ℓ
all-pred f [] = ⊤
all-pred f (x₁ :: xs) = (f x₁) ∧ (all-pred f xs)

-- return tt iff at least one element in the list satisfies the given predicate pred.
list-any : ∀{ℓ}{A : Set ℓ}(pred : A → 𝔹)(l : 𝕃 A) → 𝔹
list-any pred [] = ff
list-any pred (x :: xs) = pred x || list-any pred xs

list-and : (l : 𝕃 𝔹) → 𝔹
list-and [] = tt
list-and (x :: xs) = x && (list-and xs)

list-or : (l : 𝕃 𝔹) → 𝔹
list-or [] = ff
list-or (x :: l) = x || list-or l

list-max : ∀{ℓ}{A : Set ℓ} (lt : A → A → 𝔹) → 𝕃 A → A → A
list-max lt [] x = x
list-max lt (y :: ys) x = list-max lt ys (if lt y x then x else y)

isSublist : ∀{ℓ}{A : Set ℓ} → 𝕃 A → 𝕃 A → (A → A → 𝔹) → 𝔹
isSublist l1 l2 eq = list-all (λ a → list-member eq a l2) l1

=𝕃 : ∀{ℓ}{A : Set ℓ} → (A → A → 𝔹) → (l1 : 𝕃 A) → (l2 : 𝕃 A) → 𝔹
=𝕃 eq (a :: as) (b :: bs) = eq a b && =𝕃 eq as bs
=𝕃 eq [] [] = tt
=𝕃 eq _ _ = ff

filter : ∀{ℓ}{A : Set ℓ} → (A → 𝔹) → 𝕃 A → 𝕃 A
filter p [] = []
filter p (x :: xs) = let r = filter p xs in
                     if p x then x :: r else r

-- remove all elements equal to the given one
remove : ∀{ℓ}{A : Set ℓ}(eq : A → A → 𝔹)(a : A)(l : 𝕃 A) → 𝕃 A
remove eq a l = filter (λ x → ~ (eq a x)) l

{- nthTail n l returns the part of the list after the first n elements,
   or [] if the list has fewer than n elements -}
nthTail : ∀{ℓ}{A : Set ℓ} → ℕ → 𝕃 A → 𝕃 A
nthTail 0 l = l
nthTail n [] = []
nthTail (suc n) (x :: l) = nthTail n l

nth : ∀{ℓ}{A : Set ℓ} → ℕ → 𝕃 A → maybe A
nth _ [] = nothing
nth 0 (x :: xs) = just x
nth (suc n) (x :: xs) = nth n xs

-- nats-down N returns N :: (N-1) :: ... :: 0 :: []
nats-down : ℕ → 𝕃 ℕ
nats-down 0 = [ 0 ]
nats-down (suc x) = suc x :: nats-down x

zip : ∀{ℓ₁ ℓ₂}{A : Set ℓ₁}{B : Set ℓ₂} → 𝕃 A → 𝕃 B → 𝕃 (A × B)
zip [] [] = []
zip [] (x :: l₂) = []
zip (x :: l₁) [] = []
zip (x :: l₁) (y :: l₂) = (x , y) :: zip l₁ l₂

unzip : ∀{ℓ₁ ℓ₂}{A : Set ℓ₁}{B : Set ℓ₂} → 𝕃 (A × B) → (𝕃 A × 𝕃 B)
unzip [] = ([] , [])
unzip ((x , y) :: ps) with unzip ps
... | (xs , ys) = x :: xs , y :: ys

inPairListFst : {A B : Set} → (A → A → 𝔹) → A → 𝕃 (A ∧ B) → Set
inPairListFst _ w [] = ⊥
inPairListFst _=A_ w ((a , b) :: c) with w =A a
... | tt = ⊤
... | ff = inPairListFst _=A_ w c

map-⊎ : {ℓ₁ ℓ₂ ℓ₃ : Level} → {A : Set ℓ₁}{B : Set ℓ₂}{C : Set ℓ₃} → (A → C) → (B → C) → 𝕃 (A ⊎ B) → 𝕃 C
map-⊎ f g [] = []
map-⊎ f g (inj₁ x :: l) = f x :: map-⊎ f g l
map-⊎ f g (inj₂ y :: l) = g y :: map-⊎ f g l

proj-⊎₁ : {ℓ ℓ' : Level}{A : Set ℓ}{B : Set ℓ'} → 𝕃 (A ⊎ B) → (𝕃 A)
proj-⊎₁ [] = []
proj-⊎₁ (inj₁ x :: l) = x :: proj-⊎₁ l
proj-⊎₁ (inj₂ y :: l) = proj-⊎₁ l

proj-⊎₂ : {ℓ ℓ' : Level}{A : Set ℓ}{B : Set ℓ'} → 𝕃 (A ⊎ B) → (𝕃 B)
proj-⊎₂ [] = []
proj-⊎₂ (inj₁ x :: l) = proj-⊎₂ l
proj-⊎₂ (inj₂ y :: l) = y :: proj-⊎₂ l

drop-nothing : ∀{ℓ}{A : Set ℓ} → 𝕃 (maybe A) → 𝕃 A
drop-nothing [] = []
drop-nothing (nothing :: aa) = drop-nothing aa
drop-nothing (just a :: aa) = a :: drop-nothing aa

index : ∀{ℓ}{A : Set ℓ} → A → (A → A → 𝔹) → ℕ → 𝕃 A → maybe ℕ
index x _ c [] = nothing
index x _eq_ c (y :: l) with x eq y
... | tt = just c
... | ff = index x _eq_ (suc c) l


-- Some extra properties of integers.

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

module Integer.Properties where

-- imports from stdlib.
open import Relation.Nullary using (¬_)
open import Relation.Binary.PropositionalEquality as PE
  using (_≡_ ; refl ; sym ; cong ; trans ; cong₂)

open import Data.Sum using (_⊎_ ; inj₁ ; inj₂)
open import Data.Product as P using (_×_ ; _,_ ; ∃ ; proj₁ ; proj₂)
open import Data.Nat as Nat using (ℕ ; suc ; zero ; z≤n)
import Data.Nat.Solver as NS
open import Data.Integer as Int
  using (ℤ ; ∣_∣ ; +_ ; +[1+_] ; -[1+_] ; 1ℤ ; +<+ ; -<- ; -≤- ; -<+ ; -≤+ ; +≤+ ; 0ℤ ; NonNegative ; +0)
import Data.Integer.Properties as IntP
open import Function

-- imports from local.
open import Instances

-- Triangle equality.
tri-eq : ∀ (a b : ℤ) .{{_ : NonNegative a}} .{{_ : NonNegative b}} -> ∣ a + b ∣ ≡ ∣ a ∣ + ∣ b ∣
tri-eq (+_ a) (+_ b) = begin
  ∣ + a + + b ∣ ≡⟨ refl ⟩
  ∣ + (a + b) ∣ ≡⟨ refl ⟩
  a + b        ≡⟨ refl ⟩
  ∣ + a ∣ + ∣ + b ∣ ∎
    where
      open PE.≡-Reasoning

-- For all a, a * a is always non-negative.
a*a=+b : ∀ a -> ∃ λ b → a * a ≡ + b
a*a=+b (+_ a) = (a * a) , IntP.pos-distrib-* a a
a*a=+b (-[1+_] a) = suc a * suc a , refl

0≤a*a : ∀ {a} → 0ℤ ≤ a * a
0≤a*a {a} rewrite proj₂ $ a*a=+b a = +≤+ Nat.z≤n

-- For non-zero natrual number a, a * a is always positive.
a*a-pos : ∀ (a : ℕ) .{{_ : Nat.NonZero a}} -> ∃ λ n → a * a ≡ suc n
a*a-pos (suc b) = b * b + 2 * b , claim
  where
    claim : suc b * suc b ≡ suc (b * b + 2 * b)
    claim =
      begin
          suc b * suc b   ≡⟨ refl ⟩
      (1 + b) * (1 + b)   ≡⟨ solve 1 (λ b → (con 1 :+ b) :* (con 1 :+ b) := con 1 :+ (b :* b :+ con 2 :* b)) refl b ⟩
      1 + (b * b + 2 * b)  ≡⟨ refl ⟩
      suc (b * b + 2 * b) ∎
        where
          open NS.+-*-Solver
          open PE.≡-Reasoning

a*a-pos' : ∀ (a : ℤ) .{{_ : NonZero a}} -> ∃ λ n → a * a ≡ + (suc n)
a*a-pos' +[1+ n ] rewrite proj₂ $ a*a-pos (suc n) = (proj₁ $ a*a-pos (suc n)) , refl
a*a-pos' -[1+ n ] rewrite proj₂ $ a*a-pos (suc n) = (proj₁ $ a*a-pos (suc n)) , refl

-- For an non-zero integer a, ∣ a * a ∣ is always positive.
∣a*a∣-pos : ∀ (a : ℤ) .{{_ : NonZero a}} -> ∃ λ n → ∣ a * a ∣ ≡ suc n
∣a*a∣-pos (+ (suc b)) = b * b + 2 * b , claim
  where
    claim : suc b * suc b ≡ suc (b * b + 2 * b)
    claim = proj₂ $ a*a-pos (suc b)
∣a*a∣-pos (-[1+_] b) = b * b + 2 * b , claim
  where
    claim : suc b * suc b ≡ suc (b * b + 2 * b)
    claim = proj₂ $ a*a-pos (suc b)

+∣a*a∣=a*a : ∀ (a : ℤ) -> + ∣ a * a ∣ ≡ a * a
+∣a*a∣=a*a a = IntP.0≤i⇒+∣i∣≡i (0≤a*a {a})

pos : ∀ {a : ℤ} -> ¬ a ≡ 0ℤ -> 0ℤ < a * a
pos {+_ zero} n0 with n0 refl
... | ()
pos {a@(+[1+ n ])} n0 rewrite proj₂ $ a*a-pos' a = +<+ (Nat.s≤s Nat.z≤n)
pos {a@(-[1+ n ])} n0 rewrite proj₂ $ a*a-pos' a = +<+ (Nat.s≤s Nat.z≤n)

pos' : ∀ {a} -> 0ℤ < a -> Nat.NonZero ∣ a ∣
pos' {(+_ zero)} (+<+ ())
pos' {+[1+ n ]} l = record { nonZero = _ }

-- ∣ a * a + b * b ∣ is not zero if one of a and b is.
∣aa+bb∣-nonzero : ∀ a b -> ¬ a ≡ 0ℤ ⊎ ¬ b ≡ 0ℤ -> Nat.NonZero ∣ a * a + b * b ∣
∣aa+bb∣-nonzero a b (inj₁ x) = pos' (IntP.+-mono-<-≤ (pos x) (0≤a*a {b}))
∣aa+bb∣-nonzero a b (inj₂ y) = pos' (IntP.+-mono-≤-< (0≤a*a {a}) (pos y))

-- ----------------------------------------------------------------------
-- Properties of aa + bb

-- A special case of tri-eq.
tri-eq' : ∀ a b -> ∣ a * a + b * b ∣ ≡ ∣ a * a ∣ + ∣ b * b ∣
tri-eq' a b = begin
      let (sa , sae) = (a*a=+b a) in let (sb , sbe) = a*a=+b b in
       ∣ a * a + b * b ∣  ≡⟨ cong (λ x → ∣ x ∣) (cong₂ _+_ sae sbe) ⟩
       ∣ + sa + + sb ∣  ≡⟨ (tri-eq (+ sa) (+ sb)) ⟩
       ∣ + sa ∣ + ∣ + sb ∣  ≡⟨ cong₂ _+_ (cong ∣_∣ (sym sae)) (cong ∣_∣ (sym sbe)) ⟩
       ∣ a * a ∣ + ∣ b * b ∣ ∎
        where
          open PE.≡-Reasoning

-- A property of a pair of integers.
a=0×b=0⇒aa+bb=0 : ∀ {a b : ℤ} -> a ≡ 0ℤ × b ≡ 0ℤ -> a * a + b * b ≡ 0ℤ
a=0×b=0⇒aa+bb=0 {.0ℤ} {.0ℤ} (refl , refl) = refl

aa+bb=0⇒a=0×b=0 : ∀ {a b : ℤ} -> a * a + b * b ≡ 0ℤ -> a ≡ 0ℤ × b ≡ 0ℤ
aa+bb=0⇒a=0×b=0 {a} {b} eq = P.map x^2=0⇒x=0 x^2=0⇒x=0 $ z+z (0≤a*a {a}) (0≤a*a {b}) eq
  where
    z+z : ∀ {x y} -> 0ℤ ≤ x -> 0ℤ ≤ y -> x + y ≡ 0ℤ -> x ≡ 0ℤ × y ≡ 0ℤ
    z+z {.+0} {.(+ _)} (+≤+ {n = zero} z≤n) (+≤+ z≤n) x+y=0 = (refl , x+y=0)
    z+z {.(+[1+ n ])} {.+0} (+≤+ {n = ℕ.suc n} z≤n) (+≤+ {n = zero} m≤n) ()
    z+z {.(+[1+ n ])} {.(+[1+ n₁ ])} (+≤+ {n = ℕ.suc n} z≤n) (+≤+ {n = ℕ.suc n₁} m≤n) ()

    x^2=0⇒x=0 : ∀ {x} -> x * x ≡ 0ℤ -> x ≡ 0ℤ
    x^2=0⇒x=0 {+_ zero} eq = refl