module Preliminaries where

infix 15 _≡_
data _≡_ {A : Set} (a : A) : A  Set where
  refl : a  a

open _≡_ public

data  : Set where

infixr 20 _+_
data _+_ (A : Set) (B : Set) : Set where
  inl : A  A + B
  inr : B  A + B

open _+_ public

record  : Set where
  constructor tt

open  public

infixr 20 _,_

record Σ (A : Set) (B : A  Set) : Set where
  constructor _,_
  field
    fst : A
    snd : B fst

open Σ public

infix 10 _≅_
record _≅_ (A B : Set) : Set where
  field
    fun : A  B
    inv : B  A
    inv-fun : (a : A)  inv (fun a)  a
    fun-inv : (b : B)  fun (inv b)  b

open _≅_ public

postulate
  funext : {A : Set} {B : A  Set} {f g : (a : A)  B a}  ((a : A)  f a  g a)  f  g

infixr 20 _•_
_•_ : {A : Set} {a b c : A}  a  b  b  c  a  c
refl  refl = refl

symm : {A : Set} {a b : A}  a  b  b  a
symm refl = refl

ap : {A B : Set} {a b : A} (f : A  B)  a  b  f a  f b
ap f refl = refl

transport : {A : Set} (P : A  Set) {x y : A}  P x  x  y  P y
transport P p refl = p

-- To avoid parentheses in long function applications.
infixr 5 _$_
_$_ : {A : Set} {B : A  Set} (f : (a : A)  B a) (a : A)  B a
f $ a = f a

_∘_ : {A B C : Set}  (B  C)  (A  B)  A  C
(g  f) a = g (f a)

infixr 20 _∘ₑ_
_∘ₑ_ : {A B C : Set}  B  C  A  B  A  C
(g ∘ₑ f) .fun a = g .fun (f .fun a)
(g ∘ₑ f) .inv c = f .inv (g .inv c)
(g ∘ₑ f) .inv-fun a = ap (f .inv) (g .inv-fun _)  f .inv-fun _
(g ∘ₑ f) .fun-inv c = ap (g .fun) (f .fun-inv _)  g .fun-inv _

+-ind : {A B : Set} {P : A + B  Set}  ((a : A)  P (inl a))  ((b : B)  P (inr b)) 
        (x : A + B)  P x
+-ind pa pb (inl a) = pa a
+-ind pa pb (inr b) = pb b

+-rec : {A B C : Set}  (A  C)  (B  C)  A + B  C
+-rec = +-ind

+-symm : {A B : Set}  A + B  B + A
+-symm .fun = +-rec inr inl
+-symm .inv = +-rec inr inl
+-symm .inv-fun = +-ind  a  refl)  b  refl)
+-symm .fun-inv = +-ind  b  refl)  a  refl)

+-assoc : {A B C : Set}  A + B + C  (A + B) + C
+-assoc .fun = +-rec (inl  inl) (+-rec (inl  inr) inr)
+-assoc .inv = +-rec (+-rec inl (inr  inl)) (inr  inr)
+-assoc .inv-fun = +-ind  a  refl) (+-ind  b  refl) λ c  refl)
+-assoc .fun-inv = +-ind (+-ind  a  refl)  b  refl)) λ c  refl

+-map : {A B X Y : Set}  (A  X)  (B  Y)  A + B  X + Y
+-map f g = +-rec (inl  f) (inr  g)

+-congr : {A B X Y : Set}  A  X  B  Y  A + B  X + Y
+-congr f g .fun = +-map (f .fun) (g .fun)
+-congr f g .inv = +-map (f .inv) (g .inv)
+-congr f g .inv-fun = +-ind  a  ap inl (f .inv-fun a))  b  ap inr (g .inv-fun b))
+-congr f g .fun-inv = +-ind  a  ap inl (f .fun-inv a))  b  ap inr (g .fun-inv b))

id-iso : {A : Set}  A  A
id-iso .fun a = a
id-iso .inv a = a
id-iso .inv-fun a = refl
id-iso .fun-inv a = refl

inv-iso : {A B : Set}  A  B  B  A
inv-iso f .fun = f .inv
inv-iso f .inv = f .fun
inv-iso f .inv-fun = f .fun-inv
inv-iso f .fun-inv = f .inv-fun

symm-iso : {A : Set} {x y : A}  x  y  y  x
symm-iso .fun = symm
symm-iso .inv = symm
symm-iso .inv-fun refl = refl
symm-iso .fun-inv refl = refl

transport-iso : {A : Set} (P : A  Set) {x y : A}  x  y  P x  P y
transport-iso _ refl = id-iso

eq-congr : {A : Set} {a b x y : A}  a  x  b  y  a  b  x  y
eq-congr refl refl = id-iso

eq-congr-refl : {A : Set} {a x : A} (p : a  x)  eq-congr p p .fun refl  refl
eq-congr-refl refl = refl

fib : {A B : Set} (f : A  B)  B  Set
fib {A = A} f b = Σ A  a  f a  b)

isContr : Set  Set
isContr A = Σ A  a  (b : A)  a  b)

refl-comp : {A : Set} {a b : A} (p : a  b)  refl  p  p
refl-comp refl = refl

comp-refl : {A : Set} {a b : A} (p : a  b)  p  refl  p
comp-refl refl = refl

ap-nat : {A B : Set} {f g : A  B} (h : (a : A)  f a  g a) {a b : A} (p : a  b) 
         ap f p  h b  h a  ap g p
ap-nat h refl = refl-comp _  symm (comp-refl _)

eq-symm-comp-of-comp-eq : {A : Set} {a b c : A}
                         (ab : a  b) (bc : b  c) (ac : a  c) 
                         ab  bc  ac  bc  symm ab  ac
eq-symm-comp-of-comp-eq  refl refl p h = h  symm (refl-comp _)

ap-id : {A : Set} {a b : A} (p : a  b)  ap  x  x) p  p
ap-id refl = refl

ap-circ : {A B C : Set} {f : A  B} {g : B  C} {a b : A} (p : a  b)  ap g (ap f p)  ap (g  f) p
ap-circ refl = refl

comp-congr : {A : Set} {a b c : A} {p p' : a  b} {q q' : b  c}  p  p'  q  q'  p  q  p'  q'
comp-congr refl refl = refl

postcomp-inj : {A : Set} {a b c : A} {p p' : a  b} (q : b  c) 
               p  q  p'  q  p  p'
postcomp-inj refl h = symm (comp-refl _ )  h  comp-refl _

endo-comm : {A : Set} {f : A  A} (h : (a : A)  f a  a) (a : A) 
            h (f a)  ap f (h a)
endo-comm h a = postcomp-inj (h a) (symm (ap-nat h (h a)  comp-congr refl (ap-id _)))

isProp : Set  Set
isProp A = (a b : A)  a  b

isProp-of-isContr : {A : Set}  isContr A  isProp A
isProp-of-isContr A-contr a b = symm (A-contr .snd _)  A-contr .snd _

contr-of-prop : {A : Set}  isProp A  A  isContr A
contr-of-prop A-prop a = (a , A-prop a)

transport-refl : {A : Set} {P : A  Set} {a : A} {q : a  a} {p : P a} 
                 q  refl  transport P p q  p
transport-refl refl = refl

module _ {A : Set} (A-contr : isContr A) (P : A  Set) (p : P (A-contr .fst)) where
  abstract
    contr-ind : (a : A)  P a
    contr-ind a = transport P p (isProp-of-isContr A-contr _ _)

    contr-ind-centre : contr-ind (A-contr .fst)  p
    contr-ind-centre = transport-refl {p = p} (symm (eq-symm-comp-of-comp-eq _ _ _ (comp-refl _)))

congrFun : {A : Set} {B : A  Set} {f g : (a : A)  B a}  f  g  (a : A)  f a  g a
congrFun refl _ = refl

Σ-congr-snd : {A : Set} {X Y : A  Set} (e : (a : A)  X a  Y a)  Σ A X  Σ A Y
Σ-congr-snd e .fun t = t .fst , e (t .fst) .fun (t .snd)
Σ-congr-snd e .inv t = t .fst , e (t .fst) .inv (t .snd)
Σ-congr-snd e .inv-fun t = ap (t .fst ,_) (e (t .fst) .inv-fun (t .snd))
Σ-congr-snd e .fun-inv t = ap (t .fst ,_) (e (t .fst) .fun-inv (t .snd))

uncurry : {A : Set} {B : A  Set} {C : Σ A B  Set}  (c : (a : A)  (b : B a)  C (a , b)) 
          (t : Σ A B)  C t
uncurry c t = c (t .fst) (t .snd)

⊥-prop : isProp 
⊥-prop ()

⊤-prop : isProp 
⊤-prop tt tt = refl

exfalso : {A : Set}    A
exfalso ()

+-prop : {A B : Set}  isProp A  isProp B  (A  B  )  isProp (A + B)
+-prop A-prop B-prop disj (inl a) (inl a') = ap inl (A-prop _ _)
+-prop A-prop B-prop disj (inl a) (inr b') = exfalso (disj a b')
+-prop A-prop B-prop disj (inr b) (inl a') = exfalso (disj a' b)
+-prop A-prop B-prop disj (inr b) (inr b') = ap inr (B-prop _ _)

prop-iso : {A B : Set}  isProp A  isProp B  (A  B)  (B  A)  A  B
prop-iso A-prop B-prop f g .fun = f
prop-iso A-prop B-prop f g .inv = g
prop-iso A-prop B-prop f g .inv-fun a = A-prop _ _
prop-iso A-prop B-prop f g .fun-inv b = B-prop _ _

+-distrib : {A : Set} {X Y : A  Set}  (Σ A X) + (Σ A Y)  Σ A  a  X a + Y a)
+-distrib .fun (inl t) = t .fst , inl (t .snd)
+-distrib .fun (inr t) = t .fst , inr (t .snd)
+-distrib .inv (a , inl x) = inl (a , x)
+-distrib .inv (a , inr y) = inr (a , y)
+-distrib .inv-fun (inl t) = refl
+-distrib .inv-fun (inr t) = refl
+-distrib .fun-inv (a , inl x) = refl
+-distrib .fun-inv (a , inr y) = refl

ap-inr-iso : {A B : Set} {x y : B}  x  y  inr {A = A} x  inr y
ap-inr-iso .fun = ap inr
ap-inr-iso .inv refl = refl
ap-inr-iso .inv-fun refl = refl
ap-inr-iso .fun-inv refl = refl 

Σ-contr : {A : Set} {X : A  Set}  ((a : A)  isContr (X a)) 
          Σ A X  A
Σ-contr X-contr .fun = fst
Σ-contr X-contr .inv a = a , X-contr a .fst 
Σ-contr X-contr .inv-fun = uncurry λ a  contr-ind (X-contr a) _ refl
Σ-contr X-contr .fun-inv a = refl

×-symm : {A B : Set}  Σ A  _  B)  Σ B  _  A)
×-symm .fun p = p .snd , p .fst
×-symm .inv p = p .snd , p .fst
×-symm .inv-fun p = refl
×-symm .fun-inv p = refl

contr-singleton : {A : Set} (a : A)  isContr (Σ A  a'  a'  a))
contr-singleton a .fst = (a , refl)
contr-singleton a .snd (_ , refl) = refl

contr-congr : {A B : Set} (f : A  B)  isContr A  isContr B
contr-congr f A-contr = contr-of-prop
   b b'  symm (f .fun-inv b) 
    ap (f .fun) (isProp-of-isContr A-contr _ _)  f .fun-inv b')
    (f .fun (A-contr .fst))