{- Name: Bowornmet (Ben) Hudson

--Preorders 2: Electric Boogaloo--

-}

open import Preliminaries

module Preorder-withmax where

  {- Doing the same thing as we did in Preorder.agda but this
     time we want to keep our end goal in mind and extend the
     notion of preorders to include information about maximums
     as well. This will make it easier to 'ensure' that functions
     on nats are monotone (because they sometimes aren't - e.g.
     sine, cosine, etc.) so we can give them a reasonable upper bound.
     If we don't monotonize functions on nats then that makes bounding
     more complicated. This also means we have to extend the idea of
     maximums to all our other types...
  -}
  record Preorder-max-str (A : Set) : Set1 where
    constructor preorder-max
    field
      ≤ : A → A → Set
      refl : ∀ x → ≤ x x
      trans : ∀ x y z → ≤ x y → ≤ y z → ≤ x z
      max : A → A → A
      max-l : ∀ l r → ≤ l (max l r)
      max-r : ∀ l r → ≤ r (max l r)
      max-lub : ∀ k l r → ≤ l k → ≤ r k → ≤ (max l r) k

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

  -- order on nats
  ≤nat : Nat → Nat → Set
  ≤nat Z Z = Unit
  ≤nat Z (S y) = Unit
  ≤nat (S x) Z = Void
  ≤nat (S x) (S y) = ≤nat x y

  -- proof that Nat is reflexive under ≤
  nat-refl : ∀ (x : Nat) → ≤nat x x
  nat-refl Z = <>
  nat-refl (S x) = nat-refl x

  -- proof that Nat is transitive under ≤
  nat-trans : ∀ (x y z : Nat) → ≤nat x y → ≤nat y z → ≤nat x z
  nat-trans Z Z Z p q = <>
  nat-trans Z Z (S z) p q = <>
  nat-trans Z (S y) Z p q = <>
  nat-trans Z (S y) (S z) p q = <>
  nat-trans (S x) Z Z p q = p
  nat-trans (S x) Z (S z) () q
  nat-trans (S x) (S y) Z p ()
  nat-trans (S x) (S y) (S z) p q = nat-trans x y z p q

  -- nat max
  nat-max : Nat → Nat → Nat
  nat-max Z n = n
  nat-max (S m) Z = S m
  nat-max (S m) (S n) = S (nat-max m n)

  -- left max
  nat-max-l : ∀ (l r : Nat) → ≤nat l (nat-max l r)
  nat-max-l Z Z = <>
  nat-max-l Z (S n) = <>
  nat-max-l (S m) Z = nat-refl m
  nat-max-l (S m) (S n) = nat-max-l m n

  -- right max
  nat-max-r : ∀ (l r : Nat) → ≤nat r (nat-max l r)
  nat-max-r Z Z = <>
  nat-max-r Z (S n) = nat-refl n
  nat-max-r (S m) Z = <>
  nat-max-r (S m) (S n) = nat-max-r m n

  -- rub a dub dub, Nats have a lub
  nat-max-lub : ∀ (k l r : Nat) → ≤nat l k → ≤nat r k → ≤nat (nat-max l r) k
  nat-max-lub Z Z Z p q = <>
  nat-max-lub Z Z (S r) p ()
  nat-max-lub Z (S l) Z () q
  nat-max-lub Z (S l) (S r) () q
  nat-max-lub (S k) Z Z p q = <>
  nat-max-lub (S k) Z (S r) p q = q
  nat-max-lub (S k) (S l) Z p q = p
  nat-max-lub (S k) (S l) (S r) p q = nat-max-lub k l r p q

  -- Nat is preorder with max
  nat-p : Preorder-max-str Nat
  nat-p = preorder-max ≤nat nat-refl nat-trans nat-max nat-max-l nat-max-r nat-max-lub

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

--same thing for products

  -- relation for products
  ≤axb : ∀ {A B : Set} → Preorder-max-str A → Preorder-max-str B → (A × B) → (A × B) → Set
  ≤axb PA PB (a1 , b1) (a2 , b2) = Preorder-max-str.≤ PA a1 a2 × Preorder-max-str.≤ PB b1 b2

  axb-refl : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (x : (A × B)) →  ≤axb PA PB x x
  axb-refl PA PB (a , b) = Preorder-max-str.refl PA a , Preorder-max-str.refl PB b

  axb-trans : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (x y z : (A × B)) → ≤axb PA PB x y → ≤axb PA PB y z → ≤axb PA PB x z
  axb-trans PA PB (a1 , b1) (a2 , b2) (a3 , b3) (a1<a2 , b1<b2) (a2<a3 , b2<b3) =
                          Preorder-max-str.trans PA a1 a2 a3 a1<a2 a2<a3 , Preorder-max-str.trans PB b1 b2 b3 b1<b2 b2<b3

  axb-max : ∀ {A B : Set} → Preorder-max-str A → Preorder-max-str B → (A × B) → (A × B) → (A × B)
  axb-max PA PB (a1 , b1) (a2 , b2) = Preorder-max-str.max PA a1 a2 , Preorder-max-str.max PB b1 b2

  axb-max-l : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (l r : (A × B)) → ≤axb PA PB l (axb-max PA PB l r)
  axb-max-l PA PB (a1 , b1) (a2 , b2) = Preorder-max-str.max-l PA a1 a2 , Preorder-max-str.max-l PB b1 b2

  axb-max-r : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (l r : (A × B)) → ≤axb PA PB r (axb-max PA PB l r)
  axb-max-r PA PB (a1 , b1) (a2 , b2) = Preorder-max-str.max-r PA a1 a2 , Preorder-max-str.max-r PB b1 b2

  axb-max-lub : ∀ {A B : Set}
                → (PA : Preorder-max-str A)
                → (PB : Preorder-max-str B)
                → (k l r : (A × B))
                → ≤axb PA PB l k → ≤axb PA PB r k → ≤axb PA PB (axb-max PA PB l r) k
  axb-max-lub PA PB (k1 , k2) (l1 , l2) (r1 , r2) (l1<k1 , l2<k2) (r1<k1 , r2<k2) =
                 Preorder-max-str.max-lub PA k1 l1 r1 l1<k1 r1<k1 , Preorder-max-str.max-lub PB k2 l2 r2 l2<k2 r2<k2

  axb-p : ∀ (A B : Set) → Preorder-max-str A → Preorder-max-str B → Preorder-max-str (A × B)
  axb-p A B PA PB = preorder-max (≤axb PA PB) (axb-refl PA PB) (axb-trans PA PB) (axb-max PA PB) (axb-max-l PA PB) (axb-max-r PA PB) (axb-max-lub PA PB)

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

  -- the type of monotone functions from A to B
  record Monotone (A : Set) (B : Set) (PA : Preorder-max-str A) (PB : Preorder-max-str B) : Set where
    constructor monotone
    field
      f : A → B
      is-monotone : ∀ (x y : A) → Preorder-max-str.≤ PA x y → Preorder-max-str.≤ PB (f x) (f y)

  ≤mono : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (Monotone A B PA PB) → (Monotone A B PA PB) → Set
  ≤mono {A} PA PB f g = (x : A) → Preorder-max-str.≤ PB (Monotone.f f x) (Monotone.f g x)

  mono-refl : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (x : (Monotone A B PA PB)) → ≤mono PA PB x x
  mono-refl PA PB f = λ x → Preorder-max-str.refl PB (Monotone.f f x)

  mono-trans : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (x y z : (Monotone A B PA PB)) → ≤mono PA PB x y → ≤mono PA PB y z → ≤mono PA PB x z
  mono-trans PA PB f g h p q = λ x → Preorder-max-str.trans PB (Monotone.f f x) (Monotone.f g x) (Monotone.f h x) (p x) (q x)

  mono-max : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (Monotone A B PA PB) → (Monotone A B PA PB) → (Monotone A B PA PB)
  mono-max PA PB (monotone f f-ismono) (monotone g g-ismono) =
             monotone (λ x → Preorder-max-str.max PB (f x) (g x)) (λ x y x₁ → Preorder-max-str.max-lub PB (Preorder-max-str.max PB (f y) (g y)) (f x) (g x)
               (Preorder-max-str.trans PB (f x) (f y) (Preorder-max-str.max PB (f y) (g y)) (f-ismono x y x₁) (Preorder-max-str.max-l PB (f y) (g y)))
                 (Preorder-max-str.trans PB (g x) (g y) (Preorder-max-str.max PB (f y) (g y)) (g-ismono x y x₁) (Preorder-max-str.max-r PB (f y) (g y))))

  mono-max-l : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (l r : Monotone A B PA PB) → ≤mono PA PB l (mono-max PA PB l r)
  mono-max-l PA PB f g = λ x → Preorder-max-str.max-l PB (Monotone.f f x) (Monotone.f g x)

  mono-max-r : ∀ {A B : Set} → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → (l r : Monotone A B PA PB) → ≤mono PA PB r (mono-max PA PB l r)
  mono-max-r PA PB f g = λ x → Preorder-max-str.max-r PB (Monotone.f f x) (Monotone.f g x)

  mono-max-lub : ∀ {A B : Set}
                → (PA : Preorder-max-str A)
                → (PB : Preorder-max-str B)
                → (k l r : Monotone A B PA PB)
                → ≤mono PA PB l k → ≤mono PA PB r k → ≤mono PA PB (mono-max PA PB l r) k
  mono-max-lub PA PB f g h p q = λ x → Preorder-max-str.max-lub PB (Monotone.f f x) (Monotone.f g x) (Monotone.f h x) (p x) (q x)

  mono-p : ∀ (A B : Set) → (PA : Preorder-max-str A) → (PB : Preorder-max-str B) → Preorder-max-str (Monotone A B PA PB)
  mono-p A B PA PB = preorder-max (≤mono PA PB) (mono-refl PA PB) (mono-trans PA PB) (mono-max PA PB) (mono-max-l PA PB) (mono-max-r PA PB) (mono-max-lub PA PB)

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

--"Hey, let's make things monotone!"

  -- another way to define the ≤ relation on Nat
  data _≤'_ : Nat → Nat → Set where
    x≤'x : {x : Nat} → x ≤' x
    x≤'y : {x y : Nat} → x ≤' y → x ≤' (S y)

  -- silly lemmas about silly nats
  nat-lemma : (x : Nat) → Z ≤' x
  nat-lemma Z = x≤'x
  nat-lemma (S x) = x≤'y (nat-lemma x)

  nat-lemma2 : (x y : Nat) → x ≤' y → (S x) ≤' (S y)
  nat-lemma2 .y y x≤'x = x≤'x
  nat-lemma2 x .(S y) (x≤'y {.x} {y} p) = x≤'y (nat-lemma2 x y p)

  nat-lemma3 : (x : Nat) → ≤nat x (S x)
  nat-lemma3 Z = <>
  nat-lemma3 (S x) = nat-lemma3 x

  -- maps to and from the old and new definitions of the ≤ relation
  ≤-map : (x y : Nat) → ≤nat x y → x ≤' y
  ≤-map Z Z f = x≤'x
  ≤-map Z (S y) f = nat-lemma (S y)
  ≤-map (S x) Z ()
  ≤-map (S x) (S y) f = nat-lemma2 x y (≤-map x y f)

  ≤-map2 : (x y : Nat) → x ≤' y → ≤nat x y
  ≤-map2 .y y x≤'x = nat-refl y
  ≤-map2 x .(S y) (x≤'y {.x} {y} f) = nat-trans x y (S y) (≤-map2 x y f) (nat-lemma3 y)

  -- a function to find the maximum of a whole set and not just a pair of values
  max' : ∀ {A : Set} → (PA : Preorder-max-str A) → Nat → (Nat → A) → A
  max' PA Z f = f Z
  max' PA (S n) f = Preorder-max-str.max PA (f (S n)) (max' PA n f)

  -- primitive recursion function corresponding to rec
  natrec : ∀{C : Set} → C → (Nat → C → C) → Nat → C
  natrec base step Z = base
  natrec base step (S n) = step n (natrec base step n)

  -- another lemma
  mono-f-lemma : ∀ {A : Set} → (x y : Nat) → x ≤' y → (PA : Preorder-max-str A) → (f : Nat → A) → Preorder-max-str.≤ PA (max' PA x f) (max' PA y f)
  mono-f-lemma .y y x≤'x PA f = Preorder-max-str.refl PA (max' PA y f)
  mono-f-lemma x .(S y) (x≤'y {.x} {y} p) PA f = Preorder-max-str.trans PA (max' PA x f) (max' PA y f) (max' PA (S y) f)
                                                                        (mono-f-lemma x y p PA f) (Preorder-max-str.max-r PA (f (S y)) (max' PA y f))

  -- make a function monotone by taking the max at every point
  mono-f : ∀ {A : Set} → (PA : Preorder-max-str A) → (f : Nat → A) → Monotone Nat A nat-p PA
  mono-f PA f = monotone (λ x → max' PA x f) (λ x y x₁ → mono-f-lemma x y (≤-map x y x₁) PA f)

  -- f ≤ (monotonization of f)
  mono-f-is-monotone : ∀ {A : Set} → (PA : Preorder-max-str A) → (x : Nat) → (f : Nat → A) → Preorder-max-str.≤ PA (f x) (Monotone.f (mono-f PA f) x)
  mono-f-is-monotone PA Z f = Preorder-max-str.refl PA (f Z)
  mono-f-is-monotone PA (S x) f = Preorder-max-str.max-l PA (f (S x)) (max' PA x f)

  -- if f is already monotone, then its monotonization is less than or equal to itself
  mono-f-≤-itself : ∀ {A : Set}
                    → (PA : Preorder-max-str A)
                    → (x : Nat)
                    → (f : Monotone Nat A nat-p PA)
                    →  Preorder-max-str.≤ PA (Monotone.f (mono-f PA (Monotone.f f)) x) (Monotone.f f x)
  mono-f-≤-itself PA Z f = Preorder-max-str.refl PA (Monotone.f (mono-f PA (Monotone.f f)) Z)
  mono-f-≤-itself PA (S x) f = Preorder-max-str.max-lub PA (Monotone.f f (S x)) (Monotone.f f (S x)) (max' PA x (Monotone.f f))
                                                        (Preorder-max-str.refl PA (Monotone.f f (S x)))
                                                          (Preorder-max-str.trans PA (max' PA x (Monotone.f f))
                                                            (Monotone.f f x) (Monotone.f f (S x)) (mono-f-≤-itself PA x f)
                                                              (Monotone.is-monotone f x (S x) (≤-map2 x (S x) (x≤'y x≤'x))))

  -- monotonize at the end
  mnatrec : ∀ {A : Set} → (PA : Preorder-max-str A) → A → (Nat → A → A) → Nat → A
  mnatrec PA zc sc e = max' PA e (natrec zc sc)

  -- still incorrect
  mono-natrec : ∀ {A : Set} → (PA : Preorder-max-str A) → A → (Nat → A → A) → Nat → A
  mono-natrec PA zc sc Z = zc
  mono-natrec PA zc sc (S y') = Preorder-max-str.max PA zc (sc y' (mono-natrec PA zc sc y'))

  data N' : Set where
    Z1 : N'
    Sa : N' → N'
    Sb : N' → N'

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

-- same thing as Preorder.agda but for this module

  PREORDER = Σ (λ (A : Set) → Preorder-max-str A)

  MONOTONE : (PΓ PA : PREORDER) → Set
  MONOTONE (Γ , PΓ) (A , PA) = Monotone Γ A PΓ PA

  -- some operations
  _×p_ : PREORDER → PREORDER → PREORDER
  (A , PA) ×p (B , PB) = A × B , axb-p A B PA PB

  _->p_ : PREORDER → PREORDER → PREORDER
  (A , PA) ->p (B , PB) = Monotone A B PA PB , mono-p A B PA PB

  -- Unit is a preorder
  unit-p : PREORDER
  unit-p = Unit , preorder-max (λ x x₁ → Unit) (λ x → <>) (λ x y z _ _ → <>) (λ _ _ → <>) (λ l r → <>) (λ l r → <>) (λ k l r _ _ → <>)

  -- identity preserves monotonicity
  id : ∀ {Γ} → MONOTONE Γ Γ
  id = λ {Γ} → monotone (λ x → x) (λ x y x₁ → x₁)

  -- composition preserves monotonicity
  comp : ∀ {PA PB PC} → MONOTONE PA PB → MONOTONE PB PC → MONOTONE PA PC
  comp (monotone f f-ismono) (monotone g g-ismono) = monotone (λ x → g (f x)) (λ x y x₁ → g-ismono (f x) (f y) (f-ismono x y x₁))

  -- proofs that types like pairs etc. with preorders are monotone
  pair' : ∀ {PΓ PA PB} → MONOTONE PΓ PA → MONOTONE PΓ PB → MONOTONE PΓ (PA ×p PB)
  pair' (monotone f f-ismono) (monotone g g-ismono) = monotone (λ x → (f x) , (g x)) (λ x y x₁ → f-ismono x y x₁ , g-ismono x y x₁)

  fst' : ∀ {PΓ PA PB} → MONOTONE PΓ (PA ×p PB) → MONOTONE PΓ PA
  fst' (monotone f f-ismono) =
          monotone (λ x → fst (f x)) (λ x y z → fst (f-ismono x y z))

  snd' : ∀ {PΓ PA PB} → MONOTONE PΓ (PA ×p PB) → MONOTONE PΓ PB
  snd' (monotone f f-ismono) =
          monotone (λ x → snd (f x)) (λ x y z → snd (f-ismono x y z))

  lam' : ∀ {PΓ PA PB} → MONOTONE (PΓ ×p PA) PB → MONOTONE PΓ (PA ->p PB)
  lam' {Γ , preorder-max _ reflΓ _ _ _ _ _} {A , preorder-max _ refla _ _ _ _ _} (monotone f f-ismono) =
          monotone (λ x → monotone (λ p → f (x , p)) (λ a b c → f-ismono (x , a) (x , b) ((reflΓ x) , c))) (λ x y z w → f-ismono (x , w) (y , w) (z , (refla w)))

  app' : ∀ {PΓ PA PB} → MONOTONE PΓ (PA ->p PB) → MONOTONE PΓ PA → MONOTONE PΓ PB
  app' {_} {_} {b , preorder-max _ _ transb _ _ _ _} (monotone f f-ismono) (monotone g g-ismono) =
          monotone (λ x → Monotone.f (f x) (g x)) (λ x y z → transb (Monotone.f (f x) (g x)) (Monotone.f (f y) (g x)) (Monotone.f (f y) (g y))
          (f-ismono x y z (g x)) (Monotone.is-monotone (f y) (g x) (g y) (g-ismono x y z)))


{-
      Agda file from the exercise session(s).
-}

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

open import Agda.Primitive

{-
  Two inductive implementations of the
    Martin-Löf identity type
  aka
    equality type
  aka
    identification type
  aka
    path type.
-}

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

infixr 10 _≡_

-- explcit
data _≡'_ {A : Set} : A → A → Set where
  refl : (a : A) → a ≡' a

-- variables can be used later and are understood as Pi-quantified.
variable
  A B C : Set

-- sym' for ≡'
sym' : {a b : A} → a ≡' b → b ≡' a
sym' {a = x} {.x} (refl .x) = refl x

-- sym for ≡
sym : {a b : A} → a ≡ b → b ≡ a
sym refl = refl

_⁻¹ = sym

symsym : {a b : A} → (p : a ≡ b) → sym (sym p) ≡ p
symsym refl = refl

ap : (f : A → B) → {a b : A} → a ≡ b → f a ≡ f b
ap f {a} {.a} refl = refl

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

infixl 26 _∘_

ap-g∘f : (f : A → B) (g : B → C) {a b : A} (p : a ≡ b)
         → ap (g ∘ f) p ≡ (ap g ∘ ap f) p
ap-g∘f f g refl = refl

trans : {a b c : A} → a ≡ b → b ≡ c → a ≡ c
trans refl q = q

_∙_ = trans
infixr 30 _∙_

sym-refl : {a b : A} → (p : a ≡ b) → (p ⁻¹) ∙ p ≡ refl
sym-refl refl = refl

trans2 : {a b c : A} -> a ≡ b -> b ≡ c -> a ≡ c
trans2 p refl = p

trans-trans2 : {a b c : A} -> (p : a ≡ b) -> (q : b ≡ c)
               -> trans p q ≡ trans2 p q
trans-trans2 {a = x} {b = .x} {c = .x} refl refl = refl

trans3 : {a b c : A} -> a ≡ b -> b ≡ c -> a ≡ c
trans3 refl refl = refl

trans-trans3 : {a b c : A} -> (p : a ≡ b) -> (q : b ≡ c)
               -> trans p q ≡ trans3 p q
trans-trans3 {a = x} {b = .x} {c = .x} refl refl = refl

test : {a c : A} → (q : a ≡ c) → trans refl q ≡ q
test q = refl

test2 : {a c : A} → (q : a ≡ c) → trans2 q refl ≡ q
test2 q = refl

test3 : {a c : A} → (q : a ≡ c) → trans3 refl q ≡ q
test3 refl = refl

{-
  In test3 above, we have to pattern match (path induct) on q!
  What if we cannot, as in
    test4 : {a : A} → (q : a ≡ a) → trans3 refl q ≡ q
  ?
-}

-- solution:
test4 : {a : A} → (q : a ≡ a) → trans3 refl q ≡ q
test4 q = test3 q

-- We can only pattern match on q if we remove the --without-K option:
uip : {a b : A} → (p q : a ≡ b) → p ≡ q
uip {a = x} {b = .x} refl q = {!q!}

-- implementation of the J eliminator (aka path induction)
module _ (C : (a b : A) → a ≡ b → Set) where

   J-elim : (d : (a : A) → C a a refl) → (a b : A) → (p : a ≡ b) → C a b p
   J-elim d a .a refl = d a

-- implementation of the Paulin-Mohring version of J (based bath induction)
module _ (a₀ : A) (C : (b : A) → a₀ ≡ b → Set) where

   J-elim-PM : (d : C a₀ refl) → (b : A) → (p : a₀ ≡ b) → C b p
   J-elim-PM d b refl = d

-- this is "Axiom K" (which is disabled in the options)
module _ (a₀ : A) (C : a₀ ≡ a₀ → Set) where

  K : (d : C refl) → (p : a₀ ≡ a₀) → C p
  K d p = {!p!}

-- Caveat:
-- judgmental equality in Agda: = but on paper: ≡
-- path type in Agda: ≡ but on paper: =

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

open Σ public
infixr 4 _,_

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

{-
  Exercise 5
  For a given function f : A -> B, a *pointwise left inverse* is a
  function g : B -> A such that (a : A) -> g (f a) = a.

  Show: If f has a pointwise left inverse then, for all a,b : A, the
  function ap_f {a} {b} has a pointwise left inverse. (Does the other
  direction hold as well?)

  Solution of the easy part:
-}

has-ptw-left-inv : {A B : Set} → (f : A → B) → Set
has-ptw-left-inv {A} {B} f = Σ (B → A) λ g → (a : A) → g (f a) ≡ a

ptw-left-inv-ap : {A B : Set} → (f : A → B) →
                  has-ptw-left-inv f →
                  {a₁ a₂ : A} → has-ptw-left-inv (ap f {a₁} {a₂})
ptw-left-inv-ap f (g , g∘f) {a₁} {a₂} =
                (λ q → (g∘f a₁ ⁻¹) ∙ ap g {f a₁} {f a₂} q ∙ g∘f a₂) ,
                λ {refl →  sym-refl (g∘f a₁) }

{-
  Exercise 6: a1 a2 : A, b1 b2 : B
  (a1 , b1) ≡ (a2 , b2) is equivalent to (a1 = a2) × (b1 = b2).

  Exercise 7:
  eqv2iso :   isEqv(f) -> isIso(f)   [easy]
  iso2eqv :  isIso(f) -> isEqv(f)   [hard]
-}

module _ (A B : Set) (g : B → A) (a b : B) where

  lemma : (pair1 pair2 : Σ A λ x → x ≡ g a) → pair1 ≡ pair2
  lemma (.(g a) , refl) (.(g a) , refl) = refl

  wrong : (pair1 pair2 : Σ A λ x → g a ≡ g b) → pair1 ≡ pair2
  wrong (x1 , p1) (x2 , p2) = {!p1!}

split-equality : {x y : A × B} → x ≡ y → (fst x ≡ fst y) × (snd x ≡ snd y)
split-equality = {!!}

combine-equalities : {x y : A × B} → (fst x ≡ fst y) × (snd x ≡ snd y) → x ≡ y
combine-equalities = {!!}


open import Data.Empty using ( ⊥ )
open import Data.Nat using ( ℕ ; zero ; suc ; _+_ ; _≤_ ; z≤n ; s≤s )
open import Relation.Binary.PropositionalEquality using ( _≡_ ; refl ; sym ; cong )
open import Relation.Binary.PropositionalEquality.TrustMe using ( trustMe )
open import Relation.Nullary using ( ¬_ )

module FRP.LTL.Util where

infixr 5 _trans_ _∋_

-- Irrelevant projections

postulate
  .irrelevant : ∀ {A : Set} → .A → A

-- Irrelevant ≡ can be promoted to relevant ≡

≡-relevant : ∀ {A : Set} {a b : A} → .(a ≡ b) → (a ≡ b)
≡-relevant a≡b = trustMe

-- A version of ⊥-elim which takes an irrelevant argument

⊥-elim : {A : Set} → .⊥ → A
⊥-elim ()

-- An infix variant of trans

_trans_ : ∀ {X : Set} {x y z : X} → (x ≡ y) → (y ≡ z) → (x ≡ z)
refl trans refl = refl

-- Help the type inference engine out by being explicit about X.

_∋_ : (X : Set) → X → X
X ∋ x = x

-- Lemmas about addition on ℕ
-- These are from Data.Nat.Properties,
-- included here to avoid having to load all of Data.Nat.Properties' dependencies.

m+1+n≡1+m+n : ∀ m n → m + suc n ≡ suc (m + n)
m+1+n≡1+m+n zero    n = refl
m+1+n≡1+m+n (suc m) n = cong suc (m+1+n≡1+m+n m n)

+-comm : ∀ m n → (m + n ≡ n + m)
+-comm zero    zero    = refl
+-comm zero    (suc n) = cong suc (+-comm zero n)
+-comm (suc m) n       = (cong suc (+-comm m n)) trans (sym (m+1+n≡1+m+n n m))

+-assoc : ∀ l m n → ((l + m) + n ≡ l + (m + n))
+-assoc zero    m n = refl
+-assoc (suc l) m n = cong suc (+-assoc l m n)

m+n≡0-impl-m≡0 : ∀ m n → (m + n ≡ 0) → (m ≡ 0)
m+n≡0-impl-m≡0 zero    n m+n≡0 = refl
m+n≡0-impl-m≡0 (suc m) n ()

1+n≰n : ∀ n → ¬(suc n ≤ n)
1+n≰n zero    ()
1+n≰n (suc n) (s≤s m≤n) = 1+n≰n n m≤n

≤0-impl-≡0 : ∀ {n} → (n ≤ 0) → (n ≡ 0)
≤0-impl-≡0 z≤n = refl


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

open import Categories.Category using (Category; module Commutation)

-- The "four middle interchange" for monoidal categories.
--
-- Aka the "interchange law" or "exchange law" (though those terms are
-- more comonly used in the more general context of composition in
-- 2-categories).

-- Section 5.3 of the PhD thesis of Geoff Cruttwell states most (all?)
-- the properties in the module, starting on p. 57 (starting with Prop. 5.3.4).
-- It also has nice string-diagrammatic proofs.
--    See also further comments in https://github.com/agda/agda-categories/pull/294#issuecomment-897697009

module Categories.Category.Monoidal.Interchange
  {o ℓ e} {C : Category o ℓ e} where

open import Level using (_⊔_)

import Categories.Category.Monoidal.Construction.Product as MonoidalProduct
open import Categories.Category.Monoidal.Core using (Monoidal)
import Categories.Category.Monoidal.Utilities as MonoidalUtilities
open import Categories.Category.Product using (_⁂_)
open import Categories.Functor using (_∘F_)
open import Categories.NaturalTransformation.NaturalIsomorphism using (_≃_; niHelper)
open import Categories.Morphism C using (_≅_; module ≅)

open Category C using (Obj; id; _⇒_; _∘_; _≈_)
open Commutation C

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

-- An abstract definition of an interchange map with the minimal set
-- of coherence laws required to make the tensor product ⊗ of C a
-- monoidal functor.  (See also Categories.Functor.Monoidal.Tensor.)

record HasInterchange (M : Monoidal C) : Set (o ⊔ ℓ ⊔ e) where
  open Monoidal M using (_⊗₀_; _⊗₁_; unit; ⊗)
  open MonoidalUtilities.Shorthands M using (α⇒; λ⇐; λ⇒; ρ⇒)

  -- The "four middle interchange" for tensor products.

  field swapInner : ∀ {W X Y Z} → (W ⊗₀ X) ⊗₀ (Y ⊗₀ Z) ≅ (W ⊗₀ Y) ⊗₀ (X ⊗₀ Z)

  module swapInner {W X Y Z} = _≅_ (swapInner {W} {X} {Y} {Z})
  private
    i⇒ = swapInner.from
    i⇐ = swapInner.to

  -- Naturality and coherence laws of the interchange.

  field
    natural : i⇒ ∘ (f ⊗₁ g) ⊗₁ (h ⊗₁ i) ≈ (f ⊗₁ h) ⊗₁ (g ⊗₁ i) ∘ i⇒

    assoc : [ ((X₁ ⊗₀ X₂) ⊗₀ (Y₁ ⊗₀ Y₂)) ⊗₀ (Z₁ ⊗₀ Z₂) ⇒
              (X₁ ⊗₀ (Y₁ ⊗₀ Z₁)) ⊗₀ (X₂ ⊗₀ (Y₂ ⊗₀ Z₂)) ]⟨
              i⇒ ⊗₁ id   ⇒⟨ ((X₁ ⊗₀ Y₁) ⊗₀ (X₂ ⊗₀ Y₂)) ⊗₀ (Z₁ ⊗₀ Z₂) ⟩
              i⇒         ⇒⟨ ((X₁ ⊗₀ Y₁) ⊗₀ Z₁) ⊗₀ ((X₂ ⊗₀ Y₂) ⊗₀ Z₂) ⟩
              α⇒ ⊗₁ α⇒
            ≈ α⇒         ⇒⟨ (X₁ ⊗₀ X₂) ⊗₀ ((Y₁ ⊗₀ Y₂) ⊗₀ (Z₁ ⊗₀ Z₂)) ⟩
              id ⊗₁ i⇒   ⇒⟨ (X₁ ⊗₀ X₂) ⊗₀ ((Y₁ ⊗₀ Z₁) ⊗₀ (Y₂ ⊗₀ Z₂)) ⟩
              i⇒
            ⟩

    unitˡ : [ unit ⊗₀ (X ⊗₀ Y) ⇒ (X ⊗₀ Y) ]⟨
              λ⇐ ⊗₁ id   ⇒⟨ (unit ⊗₀ unit) ⊗₀ (X ⊗₀ Y) ⟩
              i⇒         ⇒⟨ (unit ⊗₀ X) ⊗₀ (unit ⊗₀ Y) ⟩
              λ⇒ ⊗₁ λ⇒
            ≈ λ⇒
            ⟩

    unitʳ : [ (X ⊗₀ Y) ⊗₀ unit ⇒ (X ⊗₀ Y) ]⟨
              id ⊗₁ λ⇐   ⇒⟨ (X ⊗₀ Y) ⊗₀ (unit ⊗₀ unit) ⟩
              i⇒         ⇒⟨ (X ⊗₀ unit) ⊗₀ (Y ⊗₀ unit) ⟩
              ρ⇒ ⊗₁ ρ⇒
            ≈ ρ⇒
            ⟩

  -- The interchange is a natural isomorphism.

  naturalIso : ⊗ ∘F (⊗ ⁂ ⊗) ≃ ⊗ ∘F MonoidalProduct.⊗ M M
  naturalIso = niHelper (record
    { η       = λ _ → i⇒
    ; η⁻¹     = λ _ → i⇐
    ; commute = λ _ → natural
    ; iso     = λ _ → swapInner.iso
    })


-- Σ type (also used as existential) and
-- cartesian product (also used as conjunction).

{-# OPTIONS --safe #-}

import Tools.PropositionalEquality as PE

module Tools.Product where

infixr 4 _,_
infixr 2 _×_

-- Dependent pair type (aka dependent sum, Σ type).

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

open Σ public

-- Existential quantification.

∃ : {A : Set} → (A → Set) → Set
∃ = Σ _

∃₂ : {A : Set} {B : A → Set}
     (C : (x : A) → B x → Set) → Set
∃₂ C = ∃ λ a → ∃ λ b → C a b

-- Cartesian product.

_×_ : (A B : Set) → Set
A × B = Σ A (λ x → B)

×-eq : ∀ {A B : Set} {x x' : A} {y y' : B} → x PE.≡ x' × y PE.≡ y' → (x , y) PE.≡ ( x' , y' )
×-eq ( PE.refl , PE.refl ) = PE.refl


module SortedBinaryTree where
  infix 4 _≡_
  data _≡_ {a} {A : Set a} (x : A) : A → Set a where
    refl : x ≡ x
  {-# BUILTIN EQUALITY _≡_  #-}
  {-# BUILTIN REFL     refl #-}

  open import Sec4
  postulate A : Set -- XXX: E.g., Nat or Bool some base type

  -- XXX: Postulates for ≤
  postulate _≤_ : A → A → Prop
  postulate antisym-≤ : (a b : A) → (a ≤ b) → (b ≤ a) → (a ≡ b)
  postulate tot-≤ : (a b : A) → (a ≤ b) ∨ (b ≤ a)
  postulate refl-≤ : (a : A) → (a ≤ a)
  postulate trans-≤ : (a b c : A) → (a ≤ b) → (b ≤ a) → (a ≤ c)

  -- XXX: Postulates for ≥
  postulate _≥_ : A → A → Prop
  postulate antisym-≥ : (a b : A) → (a ≥ b) → (b ≥ a) → (a ≡ b)
  postulate tot-≥ : (a b : A) → (a ≥ b) ∨ (b ≥ a)
  postulate refl-≥ : (a : A) → (a ≥ a)
  postulate trans-≥ : (a b c : A) → (a ≥ b) → (b ≥ a) → (a ≥ c)

-- XXX: Definition of a binary tree.
  data SortedBinaryTree (A : Set) : Set where
    Leaf : SortedBinaryTree A
    Node : (a : A) → (l : SortedBinaryTree A) → (r : SortedBinaryTree A) → SortedBinaryTree A

  all-leq : (a : A) → (t : SortedBinaryTree A) → Prop
  all-leq a₁ Leaf = ⊤
  all-leq a₁ (Node a₂ l r) = (a₂ ≤ a₁) ∧ ((all-leq a₁ l) ∧ (all-leq a₁ r))

  all-geq : (a : A) → (t : SortedBinaryTree A) → Prop
  all-geq a₁ Leaf = ⊤
  all-geq a₁ (Node a₂ l r) = (a₂ ≥ a₁) ∧ ((all-geq a₁ l) ∧ (all-geq a₁ r))

-- XXX: What is a sorted tree. A BTree is sorted, if all elements in the
-- left substree are ≥ root and all elements in the right subtree are ≤
-- root.
  ordered : SortedBinaryTree A → Prop
  ordered Leaf = ⊤
  ordered (Node a l r) = ((all-leq a l) ∧ (all-geq a r)) ∧ ((ordered l) ∧ (ordered r))

-- XXX: Insert function for SortedBinaryTree
  insert : (a : A) → SortedBinaryTree A → SortedBinaryTree A
  insert x Leaf = Node x Leaf Leaf
  insert x (Node a t t₁) with (tot-≤ x a)
  insert x (Node a t t₁) | ora x₁ = insert x t
  insert x (Node a t t₁) | orb x₁ = insert x t₁

-- XXX: Prove that the tree obtained after insertion is sorted
  insert-sorted : (a : A)
                  → (t : SortedBinaryTree A)
                  → (p : ordered t)
                  → ordered (insert a t)
  insert-sorted a Leaf _ = and (and ⋆ ⋆) (and ⋆ ⋆)
  insert-sorted a (Node a₁ t t₁) (and (and x x1) (and x2 x3)) with (tot-≤ a a₁)
  insert-sorted a (Node a₁ t t₁) (and (and p1 p2) (and p3 p4)) | ora w = insert-sorted a t p3
  insert-sorted a (Node a₁ t t₁) (and (and p1 p2) (and p3 p4)) | orb w = insert-sorted a t₁ p4

-- XXX: Proof carrying code
  insert' : (a : A)
            → (t : SortedBinaryTree A)
            → (p : ordered t)
            → Exists (SortedBinaryTree A) (λ t' → ordered t')
  insert' a t p = [ insert a t , insert-sorted a t p ]

-- XXX: Write Proof that delete works.

-- XXX: Write a version with record and setoid carrying the ≤, etc


module nat-division-wf where

open import bool
open import bool-thms
open import eq
open import neq
open import nat
open import nat-thms
open import product
open import product-thms
open import sum
open import termination

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

infixl 10 _÷_!_

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

{- a div-result for dividend x and divisor d consists of the quotient q, remainder r,
   a proof that q * d + r = x, and a proof that the remainder is less than the divisor. -}
div-result : ℕ → ℕ → Set
div-result x d = Σ ℕ (λ q → Σ ℕ (λ r → q * d + r ≡ x ∧ r < d ≡ tt))

-- this uses well-founded recursion.  The approach in nat-division.agda is arguably simpler.
div-helper : ∀ (x : ℕ) → ↓𝔹 _>_ x → (d : ℕ) → d =ℕ 0 ≡ ff → div-result x d
div-helper x ↓x 0 ()
div-helper 0 (pf↓ fx) (suc d) _ = 0 , 0 , refl , refl
div-helper (suc x) (pf↓ fx) (suc d) _ with keep (x < d)
div-helper (suc x) (pf↓ fx) (suc d) _ | tt , p = 0 , suc x , refl , p
div-helper (suc x) (pf↓ fx) (suc d) _ | ff , p
  with div-helper (x ∸ d) (fx (∸<1 {x} {d})) (suc d) refl
div-helper (suc x) (pf↓ fx) (suc d) _ | ff , p | q , r , u , v =
  suc q , r , lem{q * suc d} (∸eq-swap{x}{d}{q * suc d + r} (<ff{x} p) u) , v
  where lem : ∀ {a b c : ℕ} → a + b + c ≡ x → suc (c + a + b) ≡ suc x
        lem{a}{b}{c} p' rewrite +comm c a | sym (+assoc a c b)
                              | +comm c b | +assoc a b c | p' = refl

_÷_!_ : (x : ℕ) → (d : ℕ) → d =ℕ 0 ≡ ff → div-result x d
x ÷ d ! p = div-helper x (↓-> x) d p

_÷_!!_ : ℕ → (d : ℕ) → d =ℕ 0 ≡ ff → ℕ × ℕ
x ÷ d !! p with x ÷ d ! p
... | q , r , p' = q , r

-- return quotient only
_÷_div_ : ℕ → (d : ℕ) → d =ℕ 0 ≡ ff → ℕ
x ÷ d div p with x ÷ d ! p
... | q , r , p' = q


------------------------------------------------------------------------------
-- Inductive PA properties using the induction principle
------------------------------------------------------------------------------

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

module PA.Inductive.PropertiesByInductionATP where

open import PA.Inductive.Base
open import PA.Inductive.PropertiesByInduction

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

+-comm : ∀ m n → m + n ≡ n + m
+-comm m n = ℕ-ind A A0 is m
  where
  A : ℕ → Set
  A i = i + n ≡ n + i
  {-# ATP definition A #-}

  A0 : A zero
  A0 = sym (+-rightIdentity n)

  postulate is : ∀ i → A i → A (succ i)
  -- TODO (21 November 2014). See Apia issue 16
  -- {-# ATP prove is x+Sy≡S[x+y] #-}


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

open import LogicalFormulae
open import Rings.Definition
open import Rings.IntegralDomains.Definition
open import Setoids.Setoids
open import Sets.EquivalenceRelations

module Fields.FieldOfFractions.Multiplication {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ : A → A → A} {_*_ : A → A → A} {R : Ring S _+_ _*_} (I : IntegralDomain R) where

open import Fields.FieldOfFractions.Setoid I

fieldOfFractionsTimes : fieldOfFractionsSet → fieldOfFractionsSet → fieldOfFractionsSet
fieldOfFractionsTimes (record { num = a ; denom = b ; denomNonzero = b!=0 }) (record { num = c ; denom = d ; denomNonzero = d!=0 }) = record { num = a * c ; denom = b * d ; denomNonzero = ans }
  where
    open Setoid S
    open Ring R
    ans : ((b * d) ∼ Ring.0R R) → False
    ans pr with IntegralDomain.intDom I pr
    ans pr | f = exFalso (d!=0 (f b!=0))

fieldOfFractionsTimesWellDefined : {a b c d : fieldOfFractionsSet} → (Setoid._∼_ fieldOfFractionsSetoid a c) → (Setoid._∼_ fieldOfFractionsSetoid b d) → (Setoid._∼_ fieldOfFractionsSetoid (fieldOfFractionsTimes a b) (fieldOfFractionsTimes c d))
fieldOfFractionsTimesWellDefined {record { num = a ; denom = b }} {record { num = c ; denom = d }} {record { num = e ; denom = f }} {record { num = g ; denom = h }} af=be ch=dg = need
  where
    open Setoid S
    open Equivalence eq
    need : ((a * c) * (f * h)) ∼ ((b * d) * (e * g))
    need = transitive (Ring.*WellDefined R reflexive (Ring.*Commutative R)) (transitive (Ring.*Associative R) (transitive (Ring.*WellDefined R (symmetric (Ring.*Associative R)) reflexive) (transitive (Ring.*WellDefined R (Ring.*WellDefined R reflexive ch=dg) reflexive) (transitive (Ring.*Commutative R) (transitive (Ring.*Associative R) (transitive (Ring.*WellDefined R (Ring.*Commutative R) reflexive) (transitive (Ring.*WellDefined R af=be reflexive) (transitive (Ring.*Associative R) (transitive (Ring.*WellDefined R (transitive (symmetric (Ring.*Associative R)) (transitive (Ring.*WellDefined R reflexive (Ring.*Commutative R)) (Ring.*Associative R))) reflexive) (symmetric (Ring.*Associative R)))))))))))


{-# OPTIONS --cubical #-}

open import Agda.Builtin.Cubical.Path
open import Agda.Primitive
open import Agda.Primitive.Cubical

variable
  a p         : Level
  A           : Set a
  P           : A → Set p
  eq₁ u v x y : A

refl : x ≡ x
refl {x = x} = λ _ → x

subst : (P : A → Set p) → x ≡ y → P x → P y
subst P x≡y p = primTransp (λ i → P (x≡y i)) i0 p

hcong :
  (f : (x : A) → P x) (x≡y : x ≡ y) →
  PathP (λ i → P (x≡y i)) (f x) (f y)
hcong f x≡y = λ i → f (x≡y i)

dcong :
  (f : (x : A) → P x) (x≡y : x ≡ y) →
  subst P x≡y (f x) ≡ f y
dcong {P = P} f x≡y = λ i →
  primTransp (λ j → P (x≡y (primIMax i j))) i (f (x≡y i))

-- This lemma is due to Anders Mörtberg.

lemma₁ :
  {P : I → Set p} {p : P i0} {q : P i1} →
  PathP P p q ≡ (primTransp P i0 p ≡ q)
lemma₁ {P = P} {p = p} {q = q} = λ i →
  PathP
    (λ j → P (primIMax i j))
    (primTransp (λ j → P (primIMin i j)) (primINeg i) p)
    q

data 𝕊¹ : Set where
  base : 𝕊¹
  loop : base ≡ base

postulate

  Q : 𝕊¹ → Set
  b : Q base
  ℓ : subst Q loop b ≡ b

lemma₂ :
  {eq : x ≡ y} →
  subst Q eq u ≡ v →
  PathP (λ i → Q (eq i)) u v
lemma₂ = subst (λ A → A → PathP _ _ _) lemma₁ (λ x → x)

lemma₃ : (x : 𝕊¹) → Q x
lemma₃ base     = b
lemma₃ (loop i) = lemma₂ ℓ i

postulate

  lemma₄ :
    (eq₂ : subst Q eq₁ (lemma₃ x) ≡ lemma₃ y) →
    hcong lemma₃ eq₁ ≡ lemma₂ eq₂ →
    dcong lemma₃ eq₁ ≡ eq₂

works : dcong lemma₃ loop ≡ ℓ
works = lemma₄ ℓ refl

-- "injectivity" of lemma₃ was the problem
should-work-too : dcong lemma₃ loop ≡ ℓ
should-work-too = lemma₄ _ refl


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

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

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

pattern one = 1+ zero
pattern 2+_ n = 1+ (suc n)

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

ℕ₊₁→ℕ : ℕ₊₁ → ℕ
ℕ₊₁→ℕ (1+ n) = suc n

suc₊₁ : ℕ₊₁ → ℕ₊₁
suc₊₁ (1+ n) = 1+ (suc n)

-- Natural number literals for ℕ₊₁

open import Cubical.Data.Nat.Literals public

instance
  fromNatℕ₊₁ : HasFromNat ℕ₊₁
  fromNatℕ₊₁ = record { Constraint = λ { zero → ⊥ ; _ → Unit }
                      ; fromNat = λ { (suc n) → 1+ n } }


{-# OPTIONS --safe --without-K #-}
open import Algebra.Bundles using (Group)

module Categories.Category.Construction.GroupAsCategory o {c ℓ} (G : Group c ℓ) where

open import Level

open import Categories.Category.Groupoid

open Group G

-- A group is a groupoid with a single object
open import Categories.Category.Construction.MonoidAsCategory o monoid
  renaming (MonoidAsCategory to GroupAsCategory) public

GroupIsGroupoid : IsGroupoid GroupAsCategory
GroupIsGroupoid = record
  { iso = record
    { isoˡ = inverseˡ _
    ; isoʳ = inverseʳ _
    }
  }

GroupAsGroupoid : Groupoid o c ℓ
GroupAsGroupoid = record { isGroupoid = GroupIsGroupoid }


------------------------------------------------------------------------
-- Equivalence relations
------------------------------------------------------------------------

module Eq where

infix 4 _≡_

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

record Equiv {a : Set} (_≈_ : a -> a -> Set) : Set where
  field
    refl      : forall x       -> x ≈ x
    sym       : forall {x y}   -> x ≈ y -> y ≈ x
    _`trans`_ : forall {x y z} -> x ≈ y -> y ≈ z -> x ≈ z

------------------------------------------------------------------------
-- Propositional equality

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

subst : forall {a x y} ->
  (P : a -> Set) -> x ≡ y -> P x -> P y
subst _ refl p = p

cong : forall {a b x y} ->
  (f : a -> b) -> x ≡ y -> f x ≡ f y
cong _ refl = refl

Equiv-≡ : forall {a} -> Equiv {a} _≡_
Equiv-≡ {a} =
  record { refl      = \_ -> refl
         ; sym       = sym
         ; _`trans`_ = _`trans`_
         }
  where
  sym : {x y : a} -> x ≡ y -> y ≡ x
  sym refl = refl

  _`trans`_ : {x y z : a} -> x ≡ y -> y ≡ z -> x ≡ z
  refl `trans` refl = refl


------------------------------------------------------------------------------
-- Definition of mutual inductive predicates
------------------------------------------------------------------------------

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

module FOTC.MutualInductivePredicates where

open import FOTC.Base

------------------------------------------------------------------------------
-- Using mutual inductive predicates

data Even : D → Set
data Odd  : D → Set

data Even where
  ezero : Even zero
  esucc : ∀ {n} → Odd n → Even (succ₁ n)

data Odd where
  osucc : ∀ {n} → Even n → Odd (succ₁ n)

-- Non-mutual induction principles

Even-ind : (A : D → Set) →
           A zero →
           (∀ {n} → Odd n → A (succ₁ n)) →
           ∀ {n} → Even n → A n
Even-ind A A0 h ezero      = A0
Even-ind A A0 h (esucc On) = h On

Odd-ind : (A : D → Set) →
          (∀ {n} → Even n → A (succ₁ n)) →
          ∀ {n} → Odd n → A n
Odd-ind A h (osucc En) = h En

-- Mutual induction principles (from Coq)
Even-mutual-ind :
  (A B : D → Set) →
  A zero →
  (∀ {n} → Odd n → B n → A (succ₁ n)) →
  (∀ {n} → Even n → A n → B (succ₁ n)) →
  ∀ {n} → Even n → A n

Odd-mutual-ind :
  (A B : D → Set) →
  A zero →
  (∀ {n} → Odd n → B n → A (succ₁ n)) →
  (∀ {n} → Even n → A n → B (succ₁ n)) →
  ∀ {n} → Odd n → B n

Even-mutual-ind A B A0 h₁ h₂ ezero      = A0
Even-mutual-ind A B A0 h₁ h₂ (esucc On) = h₁ On (Odd-mutual-ind A B A0 h₁ h₂ On)

Odd-mutual-ind A B A0 h₁ h₂ (osucc En) = h₂ En (Even-mutual-ind A B A0 h₁ h₂ En)

module DisjointSum where
  -- Using a single inductive predicate on D × D (see
  -- Blanchette (2013)).

  _+_ : Set → Set → Set
  _+_ = _∨_

  data EvenOdd : D + D → Set where
    eozero :                            EvenOdd (inj₁ zero)
    eoodd  : {n : D} → EvenOdd (inj₁ n) → EvenOdd (inj₂ (succ₁ n))
    eoeven : {n : D} → EvenOdd (inj₂ n) → EvenOdd (inj₁ (succ₁ n))

  -- Induction principle
  EvenOdd-ind : (A : D + D → Set) →
                A (inj₁ zero) →
                ({n : D} → A (inj₁ n) → A (inj₂ (succ₁ n))) →
                ({n : D} → A (inj₂ n) → A (inj₁ (succ₁ n))) →
                {n : D + D} → EvenOdd n → A n
  EvenOdd-ind A A0 h₁ h₂ eozero       = A0
  EvenOdd-ind A A0 h₁ h₂ (eoodd EOn)  = h₁ (EvenOdd-ind A A0 h₁ h₂ EOn)
  EvenOdd-ind A A0 h₁ h₂ (eoeven EOn) = h₂ (EvenOdd-ind A A0 h₁ h₂ EOn)

  -------------------------------------------------------------------------
  -- From the single inductive predicate to the mutual inductive predicates

  -- Even and Odd from EvenOdd.
  Even' : D → Set
  Even' n = EvenOdd (inj₁ n)

  Odd' : D → Set
  Odd' n = EvenOdd (inj₂ n)

  -- From Even/Odd to Even'/Odd'
  Even→Even' : ∀ {n} → Even n → Even' n
  Odd→Odd'   : ∀ {n} → Odd n → Odd' n

  Even→Even' ezero = eozero
  Even→Even' (esucc On) = eoeven (Odd→Odd' On)

  Odd→Odd' (osucc En) = eoodd (Even→Even' En)

  -- From Even'/Odd' to Even/Odd
  Even'→Even : ∀ {n} → Even' n → Even n
  Odd'→Odd : ∀ {n} → Odd' n → Odd n

  -- Requires K.
  Even'→Even eozero     = ezero
  Even'→Even (eoeven h) = esucc (Odd'→Odd h)

  Odd'→Odd (eoodd h) = osucc (Even'→Even h)

  -- TODO (03 December 2012). From EvenOdd-ind to Even-mutual-ind and
  -- Odd-mutual-ind.

module FunctionSpace where
-- Using a single inductive predicate on D → D

  data EvenOdd : D → D → Set where
    eozero :                         EvenOdd zero (succ₁ zero)
    eoodd  : ∀ {m n} → EvenOdd m n → EvenOdd m (succ₁ m)
    eoeven : ∀ {m n} → EvenOdd m n → EvenOdd (succ₁ n) n

  -- Even and Odd from EvenOdd.
  -- Even' : D → Set
  -- Even' n = EvenOdd zero (succ₁ zero) ∨ EvenOdd (succ₁ n) n

  -- Odd' : D → Set
  -- Odd' n = EvenOdd n (succ₁ n)

  -- -- From Even/Odd to Even'/Odd'
  -- Even→Even' : ∀ {n} → Even n → Even' n
  -- Odd→Odd'   : ∀ {n} → Odd n → Odd' n

  -- Even→Even' ezero      = inj₁ eozero
  -- Even→Even' (esucc On) = inj₂ (eoeven (Odd→Odd' On))

  -- Odd→Odd' (osucc En) = eoodd {!!}

  -- -- From Even'/Odd' to Even/Odd
  -- Even'→Even : ∀ {n} → Even' n → Even n
  -- Odd'→Odd : ∀ {n} → Odd' n → Odd n

  -- Even'→Even (inj₁ x) = {!!}
  -- Even'→Even (inj₂ x) = {!!}

  -- Odd'→Odd h = {!!}

------------------------------------------------------------------------------
-- References
--
-- Blanchette, Jasmin Christian (2013). Relational analysis of
-- (co)inductive predicates, (co)algebraic datatypes, and
-- (co)recursive functions. Software Quality Journal 21.1,
-- pp. 101–126.


module Common.Equality where

open import Common.Level

infix 4 _≡_

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

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

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

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

sym : ∀ {a}{A : Set a}{x y : A} → x ≡ y → y ≡ x
sym refl = refl

trans : ∀ {a}{A : Set a}{x y z : A} → x ≡ y → y ≡ z → x ≡ z
trans refl refl = refl


{-# OPTIONS --without-K #-}
module Model.Nat where

open import Model.Size as MS using
  ( Size ; Sizes ; _≤_ ; _<_ ; ≤-IsProp ; nat )
open import Model.Type.Core
open import Util.HoTT.HLevel
open import Util.Prelude
open import Util.Relation.Binary.PropositionalEquality using (Σ-≡⁺)

import Data.Nat.Properties as ℕ

open Size

ℕ≤ : Size → Set
ℕ≤ n = ∃[ m ] (nat m ≤ n)

ℕ≤-IsSet : ∀ {n} → IsSet (ℕ≤ n)
ℕ≤-IsSet = Σ-IsSet ℕ.≡-irrelevant λ m → IsOfHLevel-suc 1 ≤-IsProp

abstract
  ℕ≤-≡⁺ : ∀ {n} {m m′} (m≤n : nat m ≤ n) (m′≤n : nat m′ ≤ n)
    → m ≡ m′
    → (m , m≤n) ≡ (m′ , m′≤n)
  ℕ≤-≡⁺ _ _ m≡m′ = Σ-≡⁺ (m≡m′ , ≤-IsProp _ _)

Nat : ⟦Type⟧ Sizes
Nat = record
  { ObjHSet = λ n → HLevel⁺ (ℕ≤ n) ℕ≤-IsSet
  ; eqHProp = λ { _ (n , _) (m , _) → HLevel⁺ (n ≡ m) ℕ.≡-irrelevant }
  ; eq-refl = λ _ → refl
  }

castℕ≤ : ∀ {n m} → n ≤ m → ℕ≤ n → ℕ≤ m
castℕ≤ n≤m (k , k≤n) = k , go
  where abstract go = MS.≤-trans k≤n n≤m

zero≤ : ∀ n → ℕ≤ n
zero≤ n = 0 , MS.0≤n

suc≤ : ∀ n m → m < n → ℕ≤ m → ℕ≤ n
suc≤ n m m<n (x , x≤m) = suc x , MS.n<m→Sn≤m (MS.≤→<→< x≤m m<n)

caseℕ≤ : ∀ {α} {A : Set α} {n}
  → ℕ≤ n
  → A
  → (∀ m → m < n → ℕ≤ m → A)
  → A
caseℕ≤ (zero , _) z s = z
caseℕ≤ (suc x , Sx≤n) z s = s (nat x) (MS.Sn≤m→n<m Sx≤n) (x , MS.≤-refl)

caseℕ≤-pres : ∀ {α β γ} {A : Set α} {A′ : Set β} {n n′}
  → (R : A → A′ → Set γ)
  → (i : ℕ≤ n) (i′ : ℕ≤ n′)
  → (z : A) (z′ : A′)
  → (s : ∀ m → m < n → ℕ≤ m → A) (s′ : ∀ m → m < n′ → ℕ≤ m → A′)
  → proj₁ i ≡ proj₁ i′
  → R z z′
  → (∀ m m<n m′ m′<n′ j j′
      → proj₁ j ≡ proj₁ j′
      → R (s m m<n j) (s′ m′ m′<n′ j′))
  → R (caseℕ≤ i z s) (caseℕ≤ i′ z′ s′)
caseℕ≤-pres R (zero , _) (_ , _) z z′ s s′ refl zRz′ sRs′ = zRz′
caseℕ≤-pres R (suc i , _) (_ , _) z z′ s s′ refl zRz′ sRs′
  = sRs′ _ _ _ _ _ _ refl


module Oscar.Class.Congruity where

open import Oscar.Class.Extensionality
open import Oscar.Level

record Congruity {a} {A : Set a} {ℓ₁} (_≋₁_ : A → A → Set ℓ₁)
                 {b} {B : Set b} {ℓ₂} (_≋₂_ : B → B → Set ℓ₂)
       : Set (a ⊔ ℓ₁ ⊔ b ⊔ ℓ₂) where
  field
    congruity : ∀ (μ : A → B) {x y} → x ≋₁ y → μ x ≋₂ μ y

  instance ′extensionality : ∀ (μ : A → B) → Extensionality _≋₁_ (λ ⋆ → _≋₂_ ⋆) μ μ
  Extensionality.extensionality (′extensionality μ) = congruity μ

open Congruity ⦃ … ⦄ public -- hiding (′extensionality)


module Array.Repr where

open import Array.Base

open import Data.Nat
open import Data.Vec as V
open import Data.Fin using (Fin; zero; suc; raise)
open import Relation.Binary.PropositionalEquality
open import Function

-- This is a function that inductively generates a Vec-based type
-- for the given arguments of Ar.
repr-t : ∀ {a} → (X : Set a) → (n : ℕ) → (s : Vec ℕ n) → Set a
repr-t X zero s = X
repr-t X (suc n) (x ∷ s) = Vec (repr-t X n s) x

a→rt : ∀ {a}{X : Set a}{n s} → Ar X n s → repr-t X n s
a→rt {n = zero}  {s = []} (imap f) = f []
a→rt {n = suc n} {x ∷ s} (imap f) = tabulate λ i → a→rt (imap (λ iv → f (i ∷ iv)))

rt→a : ∀ {a}{X : Set a}{n s} → repr-t X n s → Ar X n s
rt→a {n = zero} {s} x = imap (λ _ → x)
rt→a {n = suc n} {s ∷ _} x = imap λ where
                                (i ∷ iv) → case rt→a (lookup x i) of λ where
                                              (imap f) → f iv

-- This is an inductive type for tensors
data Tensor {a} (X : Set a) : (n : ℕ) → (s : Vec ℕ n) → Set a where
  zz : (x : X) → Tensor X 0 []
  ss : ∀ {n m}{s : Vec ℕ n} → (v : Vec (Tensor X n s) m) → Tensor X (1 + n) (m ∷ s)

-- Ugh, well...  This is big because we have to formulate point-wise equality.
data EqTen {a} (X : Set a) : (n : ℕ) → ∀ {s s₁} → Tensor X n s → Tensor X n s₁ → Set a where
  zeq : ∀ {x} → EqTen X 0 (zz x) (zz x)
  s[] : ∀ {n}{s s₁ : Vec ℕ n}
        → (∀ i → lookup s i ≡ lookup s₁ i)
        → EqTen X (1 + n) (ss {s = s} []) (ss {s = s₁} [])
  s∷ : ∀ {n}{s s₁ : Vec ℕ n}{m}
        → (∀ i → lookup s i ≡ lookup s₁ i)
        → ∀ {x y xs ys}
        → EqTen X n {s = s} {s₁ = s₁} x y
        → EqTen X (1 + n) (ss {m = m} xs) (ss {m = m} ys)
        → EqTen X (1 + n) (ss (x ∷ xs)) (ss (y ∷ ys))

a→tensor : ∀ {a}{X : Set a}{n s} → Ar X n s → Tensor X n s
a→tensor {n = zero} {s = []} (imap f) = zz (f [])
a→tensor {n = suc n}{s = s ∷ _} (imap f) = ss $ tabulate λ i → a→tensor (imap (λ iv → f (i ∷ iv)))

tensor→a : ∀ {a}{X : Set a}{n s} → Tensor X n s → Ar X n s --(lookup s)
tensor→a {s = []} (zz x) = imap (λ _ → x)
tensor→a {s = a ∷ s} (ss v) = imap λ where
                                 (i ∷ iv) → case tensor→a (lookup v i) of λ where
                                               (imap f) → f iv

t→rt : ∀ {a}{X : Set a}{n s} → Tensor X n s → repr-t X n s
t→rt {s = []} (zz x) = x
t→rt {s = x₁ ∷ s} (ss v) = V.map t→rt v

rt→t : ∀ {a}{X : Set a}{n s} → repr-t X n s → Tensor X n s
rt→t {s = []}     x = zz x
rt→t {s = _ ∷ _} x = ss (V.map rt→t x)

module test-repr where
    a : Ar ℕ 2 (3 ∷ 3 ∷ [])
    a = cst 42

    at = (a→tensor a)
    aₜ = tensor→a at

    rt = a→rt a
    a₁ = rt→a {n = 2} {s = 3 ∷ 3 ∷ []} rt

    test₁ : t→rt at ≡ rt
    test₁ = refl

    -- This one is quite tricky to show
    --test₂ : ∀ iv → sel a₁ iv ≡ sel aₜ iv
    --test₂ iv = {!!}


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties of the extensional sublist relation over setoid equality.
------------------------------------------------------------------------

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

open import Relation.Binary hiding (Decidable)

module Data.List.Relation.Binary.Subset.Setoid.Properties where

open import Data.Bool.Base using (Bool; true; false)
open import Data.List.Base
open import Data.List.Relation.Unary.Any using (here; there)
import Data.List.Membership.Setoid as Membership
open import Data.List.Membership.Setoid.Properties
import Data.List.Relation.Binary.Subset.Setoid as Sublist
import Data.List.Relation.Binary.Equality.Setoid as Equality
open import Relation.Nullary using (¬_; does)
open import Relation.Unary using (Pred; Decidable)
import Relation.Binary.Reasoning.Preorder as PreorderReasoning

open Setoid using (Carrier)

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

module _ {a ℓ} (S : Setoid a ℓ) where

  open Equality S
  open Sublist S
  open Membership S

  ⊆-reflexive : _≋_ ⇒ _⊆_
  ⊆-reflexive xs≋ys = ∈-resp-≋ S xs≋ys

  ⊆-refl : Reflexive _⊆_
  ⊆-refl x∈xs = x∈xs

  ⊆-trans : Transitive _⊆_
  ⊆-trans xs⊆ys ys⊆zs x∈xs = ys⊆zs (xs⊆ys x∈xs)

  ⊆-isPreorder : IsPreorder _≋_ _⊆_
  ⊆-isPreorder = record
    { isEquivalence = ≋-isEquivalence
    ; reflexive     = ⊆-reflexive
    ; trans         = ⊆-trans
    }

  ⊆-preorder : Preorder _ _ _
  ⊆-preorder = record
    { isPreorder = ⊆-isPreorder
    }

  -- Reasoning over subsets
  module ⊆-Reasoning where
    private
      module Base = PreorderReasoning ⊆-preorder

    open Base public
      hiding (step-∼; step-≈; step-≈˘)
      renaming (_≈⟨⟩_ to _≋⟨⟩_)

    infix 2 step-⊆ step-≋ step-≋˘
    infix 1 step-∈

    step-∈ : ∀ x {xs ys} → xs IsRelatedTo ys → x ∈ xs → x ∈ ys
    step-∈ x xs⊆ys x∈xs = (begin xs⊆ys) x∈xs

    step-⊆  = Base.step-∼
    step-≋  = Base.step-≈
    step-≋˘ = Base.step-≈˘

    syntax step-∈  x  xs⊆ys x∈xs  = x  ∈⟨  x∈xs  ⟩ xs⊆ys
    syntax step-⊆  xs ys⊆zs xs⊆ys = xs ⊆⟨  xs⊆ys ⟩ ys⊆zs
    syntax step-≋  xs ys⊆zs xs≋ys = xs ≋⟨  xs≋ys ⟩ ys⊆zs
    syntax step-≋˘ xs ys⊆zs xs≋ys = xs ≋˘⟨ xs≋ys ⟩ ys⊆zs

------------------------------------------------------------------------
-- filter

module _ {a p ℓ} (S : Setoid a ℓ)
         {P : Pred (Carrier S) p} (P? : Decidable P) where

  open Setoid S renaming (Carrier to A)
  open Sublist S

  filter⁺ : ∀ xs → filter P? xs ⊆ xs
  filter⁺ (x ∷ xs) y∈f[x∷xs] with does (P? x)
  ... | false = there (filter⁺ xs y∈f[x∷xs])
  ... | true  with y∈f[x∷xs]
  ...   | here  y≈x     = here y≈x
  ...   | there y∈f[xs] = there (filter⁺ xs y∈f[xs])


module Cats.Category.Wedges where

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

open import Cats.Category
open import Cats.Category.Setoids using (Setoids)
open import Cats.Profunctor
open import Cats.Util.Function using (_on_ ; on-isEquivalence)

module _ {lo la l≈ lo′ la′ l≈′}
  {C : Category lo la l≈} {D : Category lo′ la′ l≈′}
  (F : Profunctor C C D)
  where

  private
    module C = Category C
    module D = Category D
    module F = Profunctor F

  record Wedge : Set (lo ⊔ la ⊔ lo′ ⊔ la′ ⊔ l≈′) where
    open D

    field
      Apex : Obj
      arr : ∀ x → Apex ⇒ pobj F x x
      commute : ∀ {a b} (f : a C.⇒ b)
        → pmap₂ F f ∘ arr a ≈ pmap₁ F f ∘ arr b

  Obj = Wedge

  record _⇒_ (A B : Obj) : Set (lo ⊔ la′ ⊔ l≈′) where
    open Wedge
    open D

    field
      θ : Apex A D.⇒ Apex B
      commute : ∀ x → arr B x ∘ θ ≈ arr A x

  _≈_ : ∀ {A B} → Rel (A ⇒ B) l≈′
  _≈_ = D._≈_ on _⇒_.θ

  equiv : ∀ {A B} → IsEquivalence (_≈_ {A} {B})
  equiv = on-isEquivalence _⇒_.θ D.equiv

  id : ∀ {A} → A ⇒ A
  id = record
    { θ = D.id
    ; commute = λ x → D.id-r
    }

  _∘_ : ∀ {A B C} → B ⇒ C → A ⇒ B → A ⇒ C
  _∘_ {A} {B} {C} f g = record
    { θ = θ f ∘S θ g
    ; commute = λ j →
        begin
          arr C j ∘S θ f ∘S θ g
        ≈⟨ D.unassoc ⟩
          (arr C j ∘S θ f) ∘S θ g
        ≈⟨ D.∘-resp-l (commute f j) ⟩
          arr B j ∘S θ g
        ≈⟨ commute g j ⟩
          arr A j
        ∎
    }
    where
      open Wedge using (arr)
      open _⇒_
      open D using () renaming (_∘_ to _∘S_)
      open D.≈-Reasoning

  Wedges : Category (lo ⊔ la ⊔ lo′ ⊔ la′ ⊔ l≈′) (lo ⊔ la′ ⊔ l≈′) l≈′
  Wedges = record
    { Obj = Obj
    ; _⇒_ = _⇒_
    ; _≈_ = _≈_
    ; id = id
    ; _∘_ = _∘_
    ; equiv = equiv
    ; ∘-resp = D.∘-resp
    ; id-r = D.id-r
    ; id-l = D.id-l
    ; assoc = D.assoc
    }


module Pi-.Dir where
open import Relation.Binary.PropositionalEquality

data Dir : Set where
  ◁ : Dir
  ▷ : Dir

-ᵈⁱʳ_ : Dir → Dir
-ᵈⁱʳ ▷ = ◁
-ᵈⁱʳ ◁ = ▷

_×ᵈⁱʳ_ : Dir → Dir → Dir
◁ ×ᵈⁱʳ ◁ = ▷
◁ ×ᵈⁱʳ ▷ = ◁
▷ ×ᵈⁱʳ ◁ = ◁
▷ ×ᵈⁱʳ ▷ = ▷

identˡᵈⁱʳ : ∀ d → ▷ ×ᵈⁱʳ d ≡ d
identˡᵈⁱʳ ◁ = refl
identˡᵈⁱʳ ▷ = refl

assoclᵈⁱʳ : ∀ d₁ d₂ d₃ → d₁ ×ᵈⁱʳ (d₂ ×ᵈⁱʳ d₃) ≡ (d₁ ×ᵈⁱʳ d₂) ×ᵈⁱʳ d₃
assoclᵈⁱʳ ◁ ◁ ◁ = refl
assoclᵈⁱʳ ◁ ◁ ▷ = refl
assoclᵈⁱʳ ◁ ▷ ◁ = refl
assoclᵈⁱʳ ◁ ▷ ▷ = refl
assoclᵈⁱʳ ▷ ◁ ◁ = refl
assoclᵈⁱʳ ▷ ◁ ▷ = refl
assoclᵈⁱʳ ▷ ▷ ◁ = refl
assoclᵈⁱʳ ▷ ▷ ▷ = refl

commᵈⁱʳ : ∀ d₁ d₂ → d₁ ×ᵈⁱʳ d₂ ≡ d₂ ×ᵈⁱʳ d₁
commᵈⁱʳ ◁ ◁ = refl
commᵈⁱʳ ◁ ▷ = refl
commᵈⁱʳ ▷ ◁ = refl
commᵈⁱʳ ▷ ▷ = refl

assocl-commᵈⁱʳ : ∀ d₁ d₂ d₃ → d₁ ×ᵈⁱʳ (d₂ ×ᵈⁱʳ d₃) ≡ (d₂ ×ᵈⁱʳ d₁) ×ᵈⁱʳ d₃
assocl-commᵈⁱʳ ◁ ◁ ◁ = refl
assocl-commᵈⁱʳ ◁ ◁ ▷ = refl
assocl-commᵈⁱʳ ◁ ▷ ◁ = refl
assocl-commᵈⁱʳ ◁ ▷ ▷ = refl
assocl-commᵈⁱʳ ▷ ◁ ◁ = refl
assocl-commᵈⁱʳ ▷ ◁ ▷ = refl
assocl-commᵈⁱʳ ▷ ▷ ◁ = refl
assocl-commᵈⁱʳ ▷ ▷ ▷ = refl

assoc-commᵈⁱʳ : ∀ d₁ d₂ d₃ → d₁ ×ᵈⁱʳ (d₂ ×ᵈⁱʳ d₃) ≡ d₂ ×ᵈⁱʳ (d₁ ×ᵈⁱʳ d₃)
assoc-commᵈⁱʳ ◁ ◁ ◁ = refl
assoc-commᵈⁱʳ ◁ ◁ ▷ = refl
assoc-commᵈⁱʳ ◁ ▷ ◁ = refl
assoc-commᵈⁱʳ ◁ ▷ ▷ = refl
assoc-commᵈⁱʳ ▷ ◁ ◁ = refl
assoc-commᵈⁱʳ ▷ ◁ ▷ = refl
assoc-commᵈⁱʳ ▷ ▷ ◁ = refl
assoc-commᵈⁱʳ ▷ ▷ ▷ = refl


-- Paths in a graph
{-# OPTIONS --safe #-}

module Cubical.Data.Graph.Path where

open import Cubical.Data.Graph.Base
open import Cubical.Data.List.Base hiding (_++_)
open import Cubical.Data.Nat.Base
open import Cubical.Data.Nat.Properties
open import Cubical.Data.Sigma.Base hiding (Path)
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Prelude hiding (Path)

module _ {ℓv ℓe : Level} where

  module _ (G : Graph ℓv ℓe) where
    data Path : (v w : Node G) → Type (ℓ-max ℓv ℓe) where
      pnil : ∀ {v} → Path v v
      pcons : ∀ {v w x} → Path v w → Edge G w x → Path v x

    -- Path concatenation
    ccat : ∀ {v w x} → Path v w → Path w x → Path v x
    ccat P pnil = P
    ccat P (pcons Q e) = pcons (ccat P Q) e

    private
      _++_ = ccat
      infixr 20 _++_

    -- Some properties
    pnil++ : ∀ {v w} (P : Path v w) → pnil ++ P ≡ P
    pnil++ pnil = refl
    pnil++ (pcons P e) = cong (λ P → pcons P e) (pnil++ _)

    ++assoc : ∀ {v w x y}
        (P : Path v w) (Q : Path w x) (R : Path x y)
      → (P ++ Q) ++ R ≡ P ++ (Q ++ R)
    ++assoc P Q pnil = refl
    ++assoc P Q (pcons R e) = cong (λ P → pcons P e) (++assoc P Q R)

    -- Paths as lists
    pathToList : ∀ {v w} → Path v w
        → List (Σ[ x ∈ Node G ] Σ[ y ∈ Node G ] Edge G x y)
    pathToList pnil = []
    pathToList (pcons P e) = (_ , _ , e) ∷ (pathToList P)

    -- Path v w is a set
    -- Lemma 4.2 of https://arxiv.org/abs/2112.06609
    module _ (isSetNode : isSet (Node G))
             (isSetEdge : ∀ v w → isSet (Edge G v w)) where

      -- This is called ̂W (W-hat) in the paper
      PathWithLen : ℕ → Node G → Node G → Type (ℓ-max ℓv ℓe)
      PathWithLen 0 v w = Lift {j = ℓe} (v ≡ w)
      PathWithLen (suc n) v w = Σ[ k ∈ Node G ] (PathWithLen n v k × Edge G k w)

      isSetPathWithLen : ∀ n v w → isSet (PathWithLen n v w)
      isSetPathWithLen 0 _ _ = isOfHLevelLift 2 (isProp→isSet (isSetNode _ _))
      isSetPathWithLen (suc n) _ _ = isSetΣ isSetNode λ _ →
          isSet× (isSetPathWithLen _ _ _) (isSetEdge _ _)

      isSet-ΣnPathWithLen : ∀ {v w} → isSet (Σ[ n ∈ ℕ ] PathWithLen n v w)
      isSet-ΣnPathWithLen = isSetΣ isSetℕ (λ _ → isSetPathWithLen _ _ _)

      Path→PathWithLen : ∀ {v w} → Path v w → Σ[ n ∈ ℕ ] PathWithLen n v w
      Path→PathWithLen pnil = 0 , lift refl
      Path→PathWithLen (pcons P e) = suc (Path→PathWithLen P .fst) ,
                                          _ , Path→PathWithLen P .snd , e

      PathWithLen→Path : ∀ {v w} → Σ[ n ∈ ℕ ] PathWithLen n v w → Path v w
      PathWithLen→Path (0 , q) = subst (Path _) (q .lower) pnil
      PathWithLen→Path (suc n , _ , pwl , e) = pcons (PathWithLen→Path (n , pwl)) e

      Path→PWL→Path : ∀ {v w} P → PathWithLen→Path {v} {w} (Path→PathWithLen P) ≡ P
      Path→PWL→Path {v} pnil = substRefl {B = Path v} pnil
      Path→PWL→Path (pcons P x) = cong₂ pcons (Path→PWL→Path _) refl

      isSetPath : ∀ v w → isSet (Path v w)
      isSetPath v w = isSetRetract Path→PathWithLen PathWithLen→Path
                                   Path→PWL→Path isSet-ΣnPathWithLen


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

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

open import Numbers.ClassicalReals.RealField
open import LogicalFormulae
open import Setoids.Subset
open import Setoids.Setoids
open import Setoids.Orders
open import Sets.EquivalenceRelations
open import Rings.Orders.Total.Definition
open import Rings.Orders.Partial.Definition
open import Rings.Definition
open import Fields.Fields
open import Groups.Definition
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Numbers.Naturals.Order.Lemmas
open import Sequences

module Numbers.ClassicalReals.Sequences (ℝ : RealField) where

open RealField ℝ
open Setoid S
open Equivalence eq
open Ring R
open Field F
open SetoidPartialOrder pOrder
open import Fields.Orders.LeastUpperBounds.Definition pOrder
open import Rings.Orders.Total.Lemmas orderedRing
open import Rings.Orders.Partial.Lemmas pOrderedRing
open Group additiveGroup
open PartiallyOrderedRing pOrderedRing
open SetoidTotalOrder (TotallyOrderedRing.total orderedRing)
open import Rings.InitialRing R
open import Fields.Orders.Lemmas oField
open import Rings.Lemmas R
open import Groups.Lemmas additiveGroup
open import Numbers.Intervals.Definition pOrderedRing
open import Numbers.Intervals.Arithmetic pOrderedRing
open import Fields.Lemmas F
open import Fields.Orders.Total.Definition F

orderedField : TotallyOrderedField pOrderedRing
orderedField = record { oRing = orderedRing }

open import Fields.Orders.Limits.Definition orderedField

StrictlyIncreasing : Sequence A → Set c
StrictlyIncreasing x = (n : ℕ) → (index x n) < (index x (succ n))

Increasing : Sequence A → Set (b ⊔ c)
Increasing x = (n : ℕ) → ((index x n) < (index x (succ n))) || ((index x n) ∼ (index x (succ n)))

sequencePredicate : (x : Sequence A) → A → Set b
sequencePredicate x a = Sg ℕ (λ n → index x n ∼ a)

sequenceSubset : (x : Sequence A) → subset S (sequencePredicate x)
sequenceSubset sequence {x} {y} x=y (n , sn=x) = n , transitive sn=x x=y

boundedSequenceBounds : (K : A) (x : Sequence A) → ((n : ℕ) → index x n < K) → UpperBound (sequenceSubset x) K
boundedSequenceBounds K x pr y (n , y=xn) = inl (<WellDefined y=xn reflexive (pr n))

increasingBoundedLimit : (x : Sequence A) → Increasing x → Bounded x → A
increasingBoundedLimit x increasing (K , kIsBound) with lub (sequenceSubset x) ((index x 0) , (0 , reflexive)) (K , boundedSequenceBounds K x kIsBound)
... | a , _ = a

increasingBoundedConverges : (x : Sequence A) → (increasing : Increasing x) → (bounded : Bounded x) → x ~> (increasingBoundedLimit x increasing bounded)
increasingBoundedConverges x increasing (K , prBound) with lub (sequenceSubset x) (Sequence.head x , (0 , reflexive)) (K , boundedSequenceBounds K x prBound)
... | lub , isLub = {!!}


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

module Categories.Category.Monoidal.Instance.Setoids where

open import Level
open import Data.Product
open import Data.Product.Relation.Binary.Pointwise.NonDependent
open import Data.Sum
open import Data.Sum.Relation.Binary.Pointwise
open import Function.Equality
open import Relation.Binary using (Setoid)

open import Categories.Category
open import Categories.Category.Instance.Setoids
open import Categories.Category.Cartesian
open import Categories.Category.Cocartesian
open import Categories.Category.Instance.SingletonSet
open import Categories.Category.Instance.EmptySet

module _ {o ℓ} where

  Setoids-Cartesian : Cartesian (Setoids o ℓ)
  Setoids-Cartesian = record
    { terminal = SingletonSetoid-⊤
    ; products = record
      { product = λ {A B} →
        let module A = Setoid A
            module B = Setoid B
         in record
          { A×B      = ×-setoid A B -- the stdlib doesn't provide projections!
          ; π₁       = record
            { _⟨$⟩_ = proj₁
            ; cong  = proj₁
            }
          ; π₂       = record
            { _⟨$⟩_ = proj₂
            ; cong  = proj₂
            }
          ; ⟨_,_⟩    = λ f g → record
            { _⟨$⟩_ = λ x → f ⟨$⟩ x , g ⟨$⟩ x
            ; cong  = λ eq → cong f eq , cong g eq
            }
          ; project₁ = λ {_ h i} eq → cong h eq
          ; project₂ = λ {_ h i} eq → cong i eq
          ; unique   = λ {W h i j} eq₁ eq₂ eq → A.sym (eq₁ (Setoid.sym W eq)) , B.sym (eq₂ (Setoid.sym W eq))
          }
      }
    }

  module Setoids-Cartesian = Cartesian Setoids-Cartesian
  open Setoids-Cartesian renaming (monoidal to Setoids-Monoidal) public

  Setoids-Cocartesian : Cocartesian (Setoids o (o ⊔ ℓ))
  Setoids-Cocartesian = record
    { initial = EmptySetoid-⊥
    ; coproducts = record
      { coproduct = λ {A} {B} → record
        { A+B = ⊎-setoid A B
        ; i₁ = record { _⟨$⟩_ = inj₁ ; cong = inj₁ }
        ; i₂ = record { _⟨$⟩_ = inj₂ ; cong = inj₂ }
        ; [_,_] = λ f g → record
          { _⟨$⟩_ = [ f ⟨$⟩_ , g ⟨$⟩_ ]
          ; cong = λ { (inj₁ x) → Π.cong f x ; (inj₂ x) → Π.cong g x }
          }
        ; inject₁ = λ {_} {f} → Π.cong f
        ; inject₂ = λ {_} {_} {g} → Π.cong g
        ; unique = λ { {C} h≈f h≈g (inj₁ x) → Setoid.sym C (h≈f (Setoid.sym A x))
                     ; {C} h≈f h≈g (inj₂ x) → Setoid.sym C (h≈g (Setoid.sym B x)) }
        }
      }
    }


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

module Cubical.Homotopy.Loopspace where

open import Cubical.Core.Everything

open import Cubical.Data.Nat

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Pointed
open import Cubical.Foundations.GroupoidLaws

{- loop space of a pointed type -}
Ω : {ℓ : Level} → Pointed ℓ → Pointed ℓ
Ω (_ , a) = ((a ≡ a) , refl)

{- n-fold loop space of a pointed type -}
Ω^_ : ∀ {ℓ} → ℕ → Pointed ℓ → Pointed ℓ
(Ω^ 0) p = p
(Ω^ (suc n)) p = Ω ((Ω^ n) p)

{- loop space map -}
Ω→ : ∀ {ℓA ℓB} {A : Pointed ℓA} {B : Pointed ℓB} (f : A →∙ B) → (Ω A →∙ Ω B)
Ω→ (f , f∙) = (λ p → (sym f∙ ∙ cong f p) ∙ f∙) , cong (λ q → q ∙ f∙) (sym (rUnit (sym f∙))) ∙ lCancel f∙


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

-- The Category of Presheaves over a Category C, i.e.
-- the Functor Category [ C.op , Setoids ]
-- Again, the levels are made explicit to show the generality and constraints.
open import Level

open import Categories.Category
open import Categories.Category.Construction.Functors
open import Categories.Category.Instance.Setoids using (Setoids)

Presheaves : ∀ {o ℓ e o′ ℓ′ : Level} → Category o ℓ e →
  Category (o ⊔ ℓ ⊔ e ⊔ suc (o′ ⊔ ℓ′)) (o ⊔ ℓ ⊔ o′ ⊔ ℓ′) (o ⊔ o′ ⊔ ℓ′)
Presheaves {o} {ℓ} {e} {o′} {ℓ′} C = Functors (Category.op C) (Setoids o′ ℓ′)


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

open import LogicalFormulae
open import Groups.Homomorphisms.Definition
open import Groups.Definition
open import Setoids.Setoids
open import Sets.EquivalenceRelations
open import Rings.Definition
open import Lists.Lists
open import Rings.Homomorphisms.Definition

module Rings.Polynomial.Evaluation {a b : _} {A : Set a} {S : Setoid {a} {b} A} {_+_ _*_ : A → A → A} (R : Ring S _+_ _*_) where

open Ring R
open Setoid S
open Equivalence eq
open Group additiveGroup
open import Groups.Polynomials.Definition additiveGroup
open import Groups.Polynomials.Addition additiveGroup
open import Rings.Polynomial.Ring R
open import Rings.Polynomial.Multiplication R

inducedFunction : NaivePoly → A → A
inducedFunction [] a = 0R
inducedFunction (x :: p) a = x + (a * inducedFunction p a)

inducedFunctionMult : (as : NaivePoly) (b c : A) → inducedFunction (map (_*_ b) as) c ∼ (inducedFunction as c) * b
inducedFunctionMult [] b c = symmetric (transitive *Commutative timesZero)
inducedFunctionMult (x :: as) b c = transitive (transitive (+WellDefined reflexive (transitive (transitive (*WellDefined reflexive (inducedFunctionMult as b c)) *Associative) *Commutative)) (symmetric *DistributesOver+)) *Commutative

inducedFunctionWellDefined : {a b : NaivePoly} → polysEqual a b → (c : A) → inducedFunction a c ∼ inducedFunction b c
inducedFunctionWellDefined {[]} {[]} a=b c = reflexive
inducedFunctionWellDefined {[]} {x :: b} (fst ,, snd) c = symmetric (transitive (+WellDefined fst (transitive (*WellDefined reflexive (symmetric (inducedFunctionWellDefined {[]} {b} snd c))) (timesZero {c}))) identRight)
inducedFunctionWellDefined {a :: as} {[]} (fst ,, snd) c = transitive (+WellDefined fst reflexive) (transitive identLeft (transitive (*WellDefined reflexive (inducedFunctionWellDefined {as} {[]} snd c)) (timesZero {c})))
inducedFunctionWellDefined {a :: as} {b :: bs} (fst ,, snd) c = +WellDefined fst (*WellDefined reflexive (inducedFunctionWellDefined {as} {bs} snd c))

inducedFunctionGroupHom : {x y : NaivePoly} → (a : A) → inducedFunction (x +P y) a ∼ (inducedFunction x a + inducedFunction y a)
inducedFunctionGroupHom {[]} {[]} a = symmetric identLeft
inducedFunctionGroupHom {[]} {x :: y} a rewrite mapId y = symmetric identLeft
inducedFunctionGroupHom {x :: xs} {[]} a rewrite mapId xs = symmetric identRight
inducedFunctionGroupHom {x :: xs} {y :: ys} a = transitive (symmetric +Associative) (transitive (+WellDefined reflexive (transitive (transitive (+WellDefined reflexive (transitive (*WellDefined reflexive (transitive (inducedFunctionGroupHom {xs} {ys} a) groupIsAbelian)) *DistributesOver+)) +Associative) groupIsAbelian)) +Associative)

inducedFunctionRingHom : (r s : NaivePoly) (a : A) → inducedFunction (r *P s) a ∼ (inducedFunction r a * inducedFunction s a)
inducedFunctionRingHom [] s a = symmetric (transitive *Commutative timesZero)
inducedFunctionRingHom (x :: xs) [] a = symmetric timesZero
inducedFunctionRingHom (b :: bs) (c :: cs) a = transitive (+WellDefined reflexive (*WellDefined reflexive (inducedFunctionGroupHom {map (_*_ b) cs +P map (_*_ c) bs} {0G :: (bs *P cs)} a))) (transitive (+WellDefined reflexive (*WellDefined reflexive (+WellDefined (inducedFunctionGroupHom {map (_*_ b) cs} {map (_*_ c) bs} a) identLeft))) (transitive (transitive (transitive (+WellDefined reflexive (transitive (transitive (transitive (*WellDefined reflexive (transitive (+WellDefined (transitive groupIsAbelian (+WellDefined (inducedFunctionMult bs c a) (inducedFunctionMult cs b a))) (transitive (transitive (*WellDefined reflexive (transitive (inducedFunctionRingHom bs cs a) *Commutative)) *Associative) *Commutative)) (symmetric +Associative))) *DistributesOver+) (+WellDefined reflexive *DistributesOver+)) (+WellDefined *Associative (+WellDefined (transitive *Associative *Commutative) *Associative)))) +Associative) (+WellDefined (symmetric *DistributesOver+') (symmetric *DistributesOver+'))) (symmetric *DistributesOver+)))

inducedFunctionIsHom : (a : A) → RingHom polyRing R (λ p → inducedFunction p a)
RingHom.preserves1 (inducedFunctionIsHom a) = transitive (+WellDefined reflexive (timesZero {a})) identRight
RingHom.ringHom (inducedFunctionIsHom a) {r} {s} = inducedFunctionRingHom r s a
GroupHom.groupHom (RingHom.groupHom (inducedFunctionIsHom a)) {x} {y} = inducedFunctionGroupHom {x} {y} a
GroupHom.wellDefined (RingHom.groupHom (inducedFunctionIsHom a)) x=y = inducedFunctionWellDefined x=y a


------------------------------------------------------------------------------
-- The map-iterate property: A property using co-induction
------------------------------------------------------------------------------

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

-- The map-iterate property (Gibbons and Hutton, 2005):
-- map f (iterate f x) = iterate f (f · x)

module FOTC.Program.MapIterate.MapIterateATP where

open import FOTC.Base
open import FOTC.Base.List
open import FOTC.Data.List
open import FOTC.Relation.Binary.Bisimilarity.Type

------------------------------------------------------------------------------
-- The map-iterate property.
≈-map-iterate : ∀ f x → map f (iterate f x) ≈ iterate f (f · x)
≈-map-iterate f x = ≈-coind B h₁ h₂
  where
  -- Based on the relation used by (Giménez and Castéran, 2007).
  B : D → D → Set
  B xs ys = ∃[ y ] xs ≡ map f (iterate f y) ∧ ys ≡ iterate f (f · y)
  {-# ATP definition B #-}

  postulate
    h₁ : ∀ {xs} {ys} → B xs ys →
         ∃[ x' ] ∃[ xs' ] ∃[ ys' ] xs ≡ x' ∷ xs' ∧ ys ≡ x' ∷ ys' ∧ B xs' ys'
  {-# ATP prove h₁ #-}

  postulate h₂ : B (map f (iterate f x)) (iterate f (f · x))
  {-# ATP prove h₂ #-}

------------------------------------------------------------------------------
-- References
--
-- Giménez, Eduardo and Casterán, Pierre (2007). A Tutorial on
-- [Co-]Inductive Types in Coq.
--
-- Gibbons, Jeremy and Hutton, Graham (2005). Proof Methods for
-- Corecursive Programs. Fundamenta Informaticae XX, pp. 1–14.


------------------------------------------------------------------------
-- Function setoids and related constructions
------------------------------------------------------------------------

module Relation.Binary.FunctionSetoid where

open import Data.Function
open import Relation.Binary

infixr 0 _↝_ _⟶_ _⇨_ _≡⇨_

-- A logical relation (i.e. a relation which relates functions which
-- map related things to related things).

_↝_ : ∀ {A B} → (∼₁ : Rel A) (∼₂ : Rel B) → Rel (A → B)
_∼₁_ ↝ _∼₂_ = λ f g → ∀ {x y} → x ∼₁ y → f x ∼₂ g y

-- Functions which preserve equality.

record _⟶_ (From To : Setoid) : Set where
  open Setoid
  infixl 5 _⟨$⟩_
  field
    _⟨$⟩_ : carrier From → carrier To
    pres  : _⟨$⟩_ Preserves _≈_ From ⟶ _≈_ To

open _⟶_ public

↝-isEquivalence : ∀ {A B C} {∼₁ : Rel A} {∼₂ : Rel B}
                  (fun : C → (A → B)) →
                  (∀ f → fun f Preserves ∼₁ ⟶ ∼₂) →
                  IsEquivalence ∼₁ → IsEquivalence ∼₂ →
                  IsEquivalence ((∼₁ ↝ ∼₂) on₁ fun)
↝-isEquivalence _ pres eq₁ eq₂ = record
  { refl  = λ {f} x∼₁y → pres f x∼₁y
  ; sym   = λ f∼g x∼y → sym eq₂ (f∼g (sym eq₁ x∼y))
  ; trans = λ f∼g g∼h x∼y → trans eq₂ (f∼g (refl eq₁)) (g∼h x∼y)
  } where open IsEquivalence

-- Function setoids.

_⇨_ : Setoid → Setoid → Setoid
S₁ ⇨ S₂ = record
  { carrier       = S₁ ⟶ S₂
  ; _≈_           = (_≈_ S₁ ↝ _≈_ S₂) on₁ _⟨$⟩_
  ; isEquivalence =
      ↝-isEquivalence _⟨$⟩_ pres (isEquivalence S₁) (isEquivalence S₂)
  } where open Setoid; open _⟶_

-- A generalised variant of (_↝_ _≡_).

≡↝ : ∀ {A} {B : A → Set} → (∀ x → Rel (B x)) → Rel ((x : A) → B x)
≡↝ R = λ f g → ∀ x → R x (f x) (g x)

≡↝-isEquivalence : {A : Set} {B : A → Set} {R : ∀ x → Rel (B x)} →
                   (∀ x → IsEquivalence (R x)) → IsEquivalence (≡↝ R)
≡↝-isEquivalence eq = record
  { refl  = λ _ → refl
  ; sym   = λ f∼g x → sym (f∼g x)
  ; trans = λ f∼g g∼h x → trans (f∼g x) (g∼h x)
  } where open module Eq {x} = IsEquivalence (eq x)

_≡⇨_ : (A : Set) → (A → Setoid) → Setoid
A ≡⇨ S = record
  { carrier       = (x : A) → carrier (S x)
  ; _≈_           = ≡↝ (λ x → _≈_ (S x))
  ; isEquivalence = ≡↝-isEquivalence (λ x → isEquivalence (S x))
  } where open Setoid


module Metalogic.Classical.Propositional.TruthSemanticsModel {ℓ} (Proposition : Set(ℓ)) where

import      Lvl
open import Data.Boolean
open import Data
open import Data.Tuple as Tuple using (_⨯_ ; _,_)
open import Functional
open import Metalogic.Classical.Propositional.Syntax{ℓ} (Proposition)
  renaming (
    ⊤   to ⊤ₗ ;
    ⊥   to ⊥ₗ ;
    ¬_  to ¬ₗ_ ;
    _∧_ to _∧ₗ_ ;
    _∨_ to _∨ₗ_ ;
    _⇒_ to _⇒ₗ_ )
open import Relator.Equals
open import Relator.Equals.Proofs
open import Sets.BoolSet

-- A model decides whether a proposition is true or false
-- Also known as Interpretation, Structure, Model
record Model : Set(ℓ) where
  field
    interpretProp : Proposition → Bool

-- TODO: Can this be called a "theory" of propositional logic? So that instances of the type Semantics is the "models" of logic?
-- TODO: Now, all the metalogic depends on booleans, which may not be satisfactory
module _ where
  import      Data.Boolean.Operators
  open        Data.Boolean.Operators.Logic

  satisfaction : Model → Formula → Bool
  satisfaction(𝔐)(• prop) = Model.interpretProp(𝔐) (prop)
  satisfaction(𝔐)(⊤ₗ) = 𝑇
  satisfaction(𝔐)(⊥ₗ) = 𝐹
  satisfaction(𝔐)(¬ₗ φ) = ¬(satisfaction(𝔐)(φ))
  satisfaction(𝔐)(φ₁ ∧ₗ φ₂) = (satisfaction(𝔐)(φ₁)) ∧ (satisfaction(𝔐)(φ₂))
  satisfaction(𝔐)(φ₁ ∨ₗ φ₂) = (satisfaction(𝔐)(φ₁)) ∨ (satisfaction(𝔐)(φ₂))
  satisfaction(𝔐)(φ₁ ⇒ₗ φ₂) = ¬(satisfaction(𝔐)(φ₁)) ∨ (satisfaction(𝔐)(φ₂))

  -- Syntactic details with the relation symbol
  record SatisfactionRelation {ℓ₁}{ℓ₂} (Obj : Set(ℓ) → Set(ℓ₁)) : Set(Lvl.𝐒(ℓ Lvl.⊔ ℓ₁ Lvl.⊔ ℓ₂)) where
    field
      _⊧_ : Model → Obj(Formula) → Set(ℓ₂)
  open SatisfactionRelation ⦃ ... ⦄ public

  instance
    -- Satisfaction for a single formula
    formula-satisfaction-relation : SatisfactionRelation(id)
    formula-satisfaction-relation = record{_⊧_ = \𝔐 φ → satisfaction(𝔐)(φ) ≡ 𝑇}

  instance
    -- Satisfaction for a list of formulas
    list-satisfaction-relation : SatisfactionRelation(BoolSet{ℓ})
    list-satisfaction-relation = record{_⊧_ = \𝔐 Γ → (∀{γ} → (γ ∈ Γ) → satisfaction(𝔐)(γ) ≡ 𝑇)}

  -- Entailment
  data _⊨_ (Γ : BoolSet{ℓ}(Formula)) (φ : Formula) : Set(ℓ) where
    [⊨]-intro : (∀{𝔐} → (𝔐 ⊧ Γ) → (𝔐 ⊧ φ)) → (Γ ⊨ φ)

  _⊭_ : BoolSet{ℓ}(Formula) → Formula → Set(ℓ)
  _⊭_ Γ φ = (_⊨_ Γ φ) → Empty{ℓ}

  -- Validity
  valid : Formula → Set(ℓ)
  valid = (∅ ⊨_)

  module Theorems where
    [⊤]-entailment : (∅ ⊨ ⊤ₗ)
    [⊤]-entailment = [⊨]-intro(const [≡]-intro)
    -- ∅ ⊨ ⊤ₗ
    -- ∀{𝔐} → (𝔐 ⊧ ∅) → (𝔐 ⊧ ⊤ₗ)
    -- ∀{𝔐} → (𝔐 ⊧ ∅) → (satisfaction(𝔐)(⊤ₗ) ≡ 𝑇)
    -- ∀{𝔐} → (∀{γ} → (γ ∈ ∅) → satisfaction(𝔐)(γ) ≡ 𝑇) → (satisfaction(𝔐)(⊤ₗ) ≡ 𝑇)

    -- [∧]-entailment : ∀{φ₁ φ₂} → ([ φ₁ ⊰ φ₂ ] ⊨ (φ₁ ∧ₗ φ₂))
    -- [∧]-entailment{φ₁}{φ₂} = [⊨]-intro ([∈]-proof ↦ congruence₁-op(_∧_) ([∈]-proof (use)) ([∈]-proof (skip use)))
    -- [ φ₁ ⊰ φ₂ ] ⊨ (φ₁ ∧ φ₂)
    -- ∀{𝔐} → (𝔐 ⊧ [ φ₁ ⊰ φ₂ ]) → (𝔐 ⊧ (φ₁ ∧ φ₂))
    -- ∀{𝔐} → (𝔐 ⊧ [ φ₁ ⊰ φ₂ ]) → (satisfaction(𝔐)(φ₁ ∧ₗ φ₂) ≡ 𝑇)
    -- ∀{𝔐} → (𝔐 ⊧ [ φ₁ ⊰ φ₂ ]) → (satisfaction(𝔐)(φ₁) ∧ satisfaction(𝔐)(φ₂) ≡ 𝑇)
    -- ∀{𝔐} → (∀{γ} → (γ ∈ [ φ₁ ⊰ φ₂ ]) → satisfaction(𝔐)(γ) ≡ 𝑇) → (satisfaction(𝔐)(φ₁) ∧ satisfaction(𝔐)(φ₂) ≡ 𝑇)


open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl)
open import Data.Fin using (Fin)
open import Data.Nat using (ℕ)
open import Data.Product using (_×_; _,_)
open import Data.Vec using (Vec; lookup; _[_]≔_)

open import Common

data Local (n : ℕ) : Set where
  endL : Local n
  sendSingle recvSingle : Fin n -> Label -> Local n -> Local n

private
  variable
    n : ℕ
    p p′ q : Fin n
    l l′ : Label
    lSub lSub′ : Local n

endL≢sendSingle : ∀ { lSub } -> endL {n} ≢ sendSingle q l lSub
endL≢sendSingle ()

endL≢recvSingle : ∀ { lSub } -> endL {n} ≢ recvSingle q l lSub
endL≢recvSingle ()

sendSingle-injective :
  sendSingle {n} p l lSub ≡ sendSingle p′ l′ lSub′
  -> p ≡ p′ × l ≡ l′ × lSub ≡ lSub′
sendSingle-injective refl = refl , refl , refl

recvSingle-injective :
  recvSingle {n} p l lSub ≡ recvSingle p′ l′ lSub′
  -> p ≡ p′ × l ≡ l′ × lSub ≡ lSub′
recvSingle-injective refl = refl , refl , refl

Configuration : ℕ -> Set
Configuration n = Vec (Local n) n

data _-_→l_ {n : ℕ} : (Fin n × Local n) -> Action n -> (Fin n × Local n) -> Set where
  →l-send :
    ∀ { lp lpSub }
    -> (p : Fin n)
    -> lp ≡ sendSingle q l lpSub
    -> (p≢q : p ≢ q)
    -> (p , lp) - (action p q p≢q l) →l (p , lpSub)
  →l-recv :
    ∀ { lp lpSub }
    -> (p : Fin n)
    -> lp ≡ recvSingle q l lpSub
    -> (q≢p : q ≢ p)
    -> (p , lp) - (action q p q≢p l) →l (p , lpSub)

data _-_→c_ {n : ℕ} : Configuration n -> Action n -> Configuration n -> Set where
  →c-comm :
    ∀ { lp lp′ lq lq′ c′ p≢q-p p≢q-q }
    -> (c : Configuration n)
    -> (p≢q : p ≢ q)
    -> lp ≡ lookup c p
    -> lq ≡ lookup c q
    -> c′ ≡ c [ p ]≔ lp′ [ q ]≔ lq′
    -> (p , lp) - (action p q p≢q-p l) →l (p , lp′)
    -> (q , lq) - (action p q p≢q-q l) →l (q , lq′)
    -> c - (action p q p≢q l) →c  c′


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

open import Prelude
open import Relation.Binary

module Relation.Binary.Construct.Decision
  {a ℓ₁ ℓ₂} {A : Type a}
  (ord : TotalOrder A ℓ₁ ℓ₂)
  where

open TotalOrder ord renaming (refl to ≤-refl)

_<′_ : A → A → Type
x <′ y = T (does (x <? y))

_≤′_ : A → A → Type
x ≤′ y = T (not (does (y <? x)))

witness-< : ∀ {x y} → x <′ y → x < y
witness-< {x} {y} p with x <? y
witness-< {x} {y} p | yes q = q

witness-≤ : ∀ {x y} → x ≤′ y → x ≤ y
witness-≤ {x} {y} p with y <? x
witness-≤ {x} {y} p | no q = ≮⇒≥ q

compute-< : ∀ {x y} → x < y → x <′ y
compute-< {x} {y} p with x <? y
compute-< {x} {y} p | yes q = tt
compute-< {x} {y} p | no ¬p = ⊥-elim (¬p p)

compute-≤ : ∀ {x y} → x ≤ y → x ≤′ y
compute-≤ {x} {y} ¬p with y <? x
compute-≤ {x} {y} ¬p | yes p = ⊥-elim (<⇒≱ p ¬p)
compute-≤ {x} {y} ¬p | no  _ = tt

≰⇒>′ : ∀ {x y} → ¬ (x ≤′ y) → y <′ x
≰⇒>′ {x} {y} p with y <? x
≰⇒>′ {x} {y} p | no  _ = p tt
≰⇒>′ {x} {y} p | yes _ = tt

≮⇒≥′ : ∀ {x y} → ¬ (x <′ y) → y ≤′ x
≮⇒≥′ {x} {y} p with x <? y
≮⇒≥′ {x} {y} p | no  _ = tt
≮⇒≥′ {x} {y} p | yes _ = p tt

dec-ord : TotalOrder A ℓzero ℓzero
StrictPreorder._<_    (StrictPartialOrder.strictPreorder (TotalOrder.strictPartialOrder dec-ord)) = _<′_
StrictPreorder.trans  (StrictPartialOrder.strictPreorder (TotalOrder.strictPartialOrder dec-ord)) p q = compute-< (<-trans (witness-< p) (witness-< q))
StrictPreorder.irrefl (StrictPartialOrder.strictPreorder (TotalOrder.strictPartialOrder dec-ord)) p = irrefl (witness-< p)
StrictPartialOrder.conn (TotalOrder.strictPartialOrder dec-ord) p q = conn (p ∘ compute-<) (q ∘ compute-<)
Preorder._≤_  (PartialOrder.preorder (TotalOrder.partialOrder dec-ord)) = _≤′_
Preorder.refl (PartialOrder.preorder (TotalOrder.partialOrder dec-ord)) = compute-≤ ≤-refl
PartialOrder.antisym (TotalOrder.partialOrder dec-ord) p q = antisym (witness-≤ p) (witness-≤ q)
Preorder.trans (PartialOrder.preorder (TotalOrder.partialOrder dec-ord)) p q = compute-≤ (≤-trans (witness-≤ p) (witness-≤ q))
TotalOrder._<?_ dec-ord x y = iff-dec (compute-< iff witness-<) (x <? y)
TotalOrder.≰⇒> dec-ord = ≰⇒>′
TotalOrder.≮⇒≥ dec-ord = ≮⇒≥′


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

-- The category of Cats is Monoidal

module Categories.Category.Monoidal.Instance.Cats where

open import Level

open import Categories.Category.BinaryProducts using (BinaryProducts)
open import Categories.Category.Cartesian using (Cartesian)
open import Categories.Category.Cartesian.Monoidal using (module CartesianMonoidal)
open import Categories.Category.Instance.Cats using (Cats)
open import Categories.Category.Instance.One using (One-⊤)
open import Categories.Category.Monoidal using (Monoidal)
open import Categories.Category.Product using (Product; πˡ; πʳ; _※_)
open import Categories.Category.Product.Properties using (project₁; project₂; unique)

-- Cats is a Monoidal Category with Product as Bifunctor
module Product {o ℓ e : Level} where
  private
    C = Cats o ℓ e

  Cats-has-all : BinaryProducts C
  Cats-has-all = record { product = λ {A} {B} → record
    { A×B = Product A B
    ; π₁ = πˡ
    ; π₂ = πʳ
    ; ⟨_,_⟩ = _※_
    ; project₁ = λ {_} {h} {i} → project₁ {i = h} {j = i}
    ; project₂ = λ {_} {h} {i} → project₂ {i = h} {j = i}
    ; unique = unique
    } }

  Cats-is : Cartesian C
  Cats-is = record { terminal = One-⊤ ; products = Cats-has-all }

  Cats-Monoidal : Monoidal C
  Cats-Monoidal = CartesianMonoidal.monoidal Cats-is


module List.Permutation.Base (A : Set) where

open import Data.List

data _/_⟶_ : List A → A → List A → Set where
  /head : {x : A}{xs : List A}
                   →  (x ∷ xs) / x ⟶ xs
  /tail : {x y : A}{xs ys : List A}
                   → xs / y ⟶ ys
                   → (x ∷ xs) / y ⟶ (x ∷ ys)

data _∼_ : List A → List A → Set where
  ∼[] : [] ∼ []
  ∼x : {x : A}{xs ys xs' ys' : List A}
                   → xs / x ⟶ xs'
                   → ys / x ⟶ ys'
                   → xs' ∼ ys'
                   → xs ∼ ys


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

open import LogicalFormulae
open import Numbers.Naturals.Semiring
open import Numbers.Integers.Definition

module Numbers.Integers.Multiplication where

infix 25 _*Z_
_*Z_ : ℤ → ℤ → ℤ
nonneg x *Z nonneg y = nonneg (x *N y)
nonneg zero *Z negSucc y = nonneg zero
nonneg (succ x) *Z negSucc y = negSucc ((succ x) *N y +N x)
negSucc x *Z nonneg zero = nonneg zero
negSucc x *Z nonneg (succ y) = negSucc ((succ y) *N x +N y)
negSucc x *Z negSucc y = nonneg ((succ x) *N (succ y))

*ZInherits : (a b : ℕ) → nonneg (a *N b) ≡ (nonneg a) *Z (nonneg b)
*ZInherits a b = refl


------------------------------------------------------------------------
-- The Agda standard library
--
-- Semi-heterogeneous vector equality over setoids
------------------------------------------------------------------------

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

open import Relation.Binary

module Data.Vec.Relation.Binary.Equality.Setoid
  {a ℓ} (S : Setoid a ℓ) where

open import Data.Nat.Base using (ℕ; zero; suc; _+_)
open import Data.Vec
open import Data.Vec.Relation.Binary.Pointwise.Inductive as PW
  using (Pointwise)
open import Function
open import Level using (_⊔_)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P using (_≡_)

open Setoid S renaming (Carrier to A)

------------------------------------------------------------------------
-- Definition of equality

infix 4 _≋_

_≋_ : ∀ {m n} → REL (Vec A m) (Vec A n) (a ⊔ ℓ)
_≋_ = Pointwise _≈_

open Pointwise public using ([]; _∷_)
open PW public using (length-equal)

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

≋-refl : ∀ {n} → Reflexive (_≋_ {n})
≋-refl = PW.refl refl

≋-sym : ∀ {n m} → Sym _≋_ (_≋_ {m} {n})
≋-sym = PW.sym sym

≋-trans : ∀ {n m o} → Trans (_≋_ {m}) (_≋_ {n} {o}) (_≋_)
≋-trans = PW.trans trans

≋-isEquivalence : ∀ n → IsEquivalence (_≋_ {n})
≋-isEquivalence = PW.isEquivalence isEquivalence

≋-setoid : ℕ → Setoid a (a ⊔ ℓ)
≋-setoid = PW.setoid S

------------------------------------------------------------------------
-- map

open PW public using ( map⁺)

------------------------------------------------------------------------
-- ++

open PW public using (++⁺ ; ++⁻ ; ++ˡ⁻; ++ʳ⁻)

++-identityˡ : ∀ {n} (xs : Vec A n) → [] ++ xs ≋ xs
++-identityˡ _ = ≋-refl

++-identityʳ : ∀ {n} (xs : Vec A n) → xs ++ [] ≋ xs
++-identityʳ []       = []
++-identityʳ (x ∷ xs) = refl ∷ ++-identityʳ xs

map-++-commute : ∀ {b m n} {B : Set b}
                   (f : B → A) (xs : Vec B m) {ys : Vec B n} →
                   map f (xs ++ ys) ≋ map f xs ++ map f ys
map-++-commute f []       = ≋-refl
map-++-commute f (x ∷ xs) = refl ∷ map-++-commute f xs

------------------------------------------------------------------------
-- concat

open PW public using (concat⁺; concat⁻)

------------------------------------------------------------------------
-- replicate

replicate-shiftʳ : ∀ {m} n x (xs : Vec A m) →
                  replicate {n = n}     x ++ (x ∷ xs) ≋
                  replicate {n = 1 + n} x ++      xs
replicate-shiftʳ zero    x xs = ≋-refl
replicate-shiftʳ (suc n) x xs = refl ∷ (replicate-shiftʳ n x xs)


{- Voevodsky's proof that univalence implies funext -}

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

module Cubical.Experiments.FunExtFromUA where

open import Cubical.Core.Everything
open import Cubical.Foundations.Everything

variable
 ℓ ℓ' : Level
_∼_ : {X : Type ℓ} {A : X → Type ℓ'} → (f g : (x : X) → A x) → Type (ℓ-max ℓ ℓ')
f ∼ g = ∀ x → f x ≡ g x

funext : ∀ ℓ ℓ' → Type (ℓ-suc(ℓ-max ℓ ℓ'))
funext ℓ ℓ' = {X : Type ℓ} {Y : Type ℓ'} {f g : X → Y} → f ∼ g → f ≡ g

elimEquivFun' : ∀ {ℓ} (P : (A B : Type ℓ) → (A → B) → Type ℓ)
              → (r : (B : Type ℓ) → P B B (λ x → x))
              → (A B : Type ℓ) → (e : A ≃ B) → P A B (e .fst)
elimEquivFun' P r A B = elimEquivFun B (λ A → P A B) (r B) A

pre-comp-is-equiv : (X Y : Type ℓ) (f : X → Y) (Z : Type ℓ)
                  → isEquiv f
                  → isEquiv (λ (g : Y → Z) → g ∘ f)
pre-comp-is-equiv {ℓ} X Y f Z e = elimEquivFun' P r X Y (f , e)
 where
  P : (X Y : Type ℓ) → (X → Y) → Type ℓ
  P X Y f = isEquiv (λ (g : Y → Z) → g ∘ f)
  r : (B : Type ℓ) → P B B (λ x → x)
  r B = idIsEquiv (B → Z)

leftCancellable : {X : Type ℓ} {Y : Type ℓ'} → (X → Y) → Type (ℓ-max ℓ ℓ')
leftCancellable f = ∀ {x x'} → f x ≡ f x' → x ≡ x'

equivLC : {X : Type ℓ} {Y : Type ℓ'} (f : X → Y) → isEquiv f → leftCancellable f
equivLC f e {x} {x'} p i = hcomp (λ j → \ {(i = i0) → secEq (f , e) x j ;
                                           (i = i1) → secEq (f , e) x' j})
                                 (invEq (f , e) (p i))

univalence-gives-funext : funext ℓ' ℓ
univalence-gives-funext {ℓ'} {ℓ} {X} {Y} {f₀} {f₁} = γ
 where
  Δ = Σ[ y₀ ∈ Y ] Σ[ y₁ ∈ Y ] y₀ ≡ y₁

  δ : Y → Δ
  δ y = (y , y , refl)

  π₀ π₁ : Δ → Y
  π₀ (y₀ , y₁ , p) = y₀
  π₁ (y₀ , y₁ , p) = y₁

  δ-is-equiv : isEquiv δ
  δ-is-equiv = isoToIsEquiv (iso δ π₀ ε η)
   where
    η : (y : Y) → π₀ (δ y) ≡ y
    η y = refl
    ε : (d : Δ) → δ (π₀ d) ≡ d
    ε (y₀ , y₁ , p) i = y₀ , p i , λ j → p (i ∧ j)

  φ : (Δ → Y) → (Y → Y)
  φ π = π ∘ δ

  e : isEquiv φ
  e = pre-comp-is-equiv Y Δ δ Y δ-is-equiv

  p : φ π₀ ≡ φ π₁
  p = refl

  q : π₀ ≡ π₁
  q = equivLC φ e p

  g : (h : f₀ ∼ f₁) (π : Δ → Y) (x : X) → Y
  g = λ h π x → π (f₀ x , f₁ x , h x)

  γ : f₀ ∼ f₁ → f₀ ≡ f₁
  γ h = cong (g h) q

  γ' : f₀ ∼ f₁ → f₀ ≡ f₁
  γ' h = f₀                              ≡⟨ refl ⟩
         (λ x → f₀ x)                    ≡⟨ refl ⟩
         (λ x → π₀ (f₀ x , f₁ x , h x))  ≡⟨ cong (g h) q ⟩
         (λ x → π₁ (f₀ x , f₁ x , h x))  ≡⟨ refl ⟩
         (λ x → f₁ x)                    ≡⟨ refl ⟩
         f₁                              ∎

{- Experiment testing univalence via funext -}

private

  data ℕ : Type₀ where
   zero : ℕ
   succ : ℕ → ℕ

  f g : ℕ → ℕ

  f n = n

  g zero = zero
  g (succ n) = succ (g n)

  h : (n : ℕ) → f n ≡ g n
  h zero = refl
  h (succ n) = cong succ (h n)

  p : f ≡ g
  p = univalence-gives-funext h

  five : ℕ
  five = succ (succ (succ (succ (succ zero))))

  a : Σ ℕ (λ n → f n ≡ five)
  a = five , refl

  b : Σ ℕ (λ n → g n ≡ five)
  b = subst (λ - → Σ ℕ (λ n → - n ≡ five)) p a

  c : fst b ≡ five
  c = refl

{- It works, fast. -}


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

module Data.Binary.Operations.Semantics where

open import Data.Nat as ℕ using (ℕ; suc; zero)
open import Data.Binary.Definitions
open import Data.Binary.Operations.Unary
import Data.List as List

2* : ℕ → ℕ
2* x = x ℕ.+ x
{-# INLINE 2* #-}

_∷⇓_ : Bit → ℕ → ℕ
O ∷⇓ xs = 2* xs
I ∷⇓ xs = suc (2* xs)
{-# INLINE _∷⇓_ #-}

⟦_⇓⟧⁺ : 𝔹⁺ → ℕ
⟦_⇓⟧⁺ = List.foldr _∷⇓_ 1
{-# INLINE ⟦_⇓⟧⁺ #-}

⟦_⇓⟧ : 𝔹 → ℕ
⟦ 0ᵇ ⇓⟧ = 0
⟦ 0< xs ⇓⟧ = ⟦ xs ⇓⟧⁺

⟦_⇑⟧ : ℕ → 𝔹
⟦ zero ⇑⟧ = 0ᵇ
⟦ suc n ⇑⟧ = inc ⟦ n ⇑⟧


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.CommRing.Integers where

open import Cubical.Foundations.Prelude

open import Cubical.Algebra.CommRing
open import Cubical.HITs.Ints.BiInvInt
  renaming (
    _+_ to _+ℤ_;
    -_ to _-ℤ_;
    +-assoc to +ℤ-assoc;
    +-comm to +ℤ-comm
  )

BiInvIntAsCommRing : CommRing {ℓ-zero}
BiInvIntAsCommRing =
  makeCommRing
    zero (suc zero) _+ℤ_ _·_ _-ℤ_
    isSetBiInvInt
    +ℤ-assoc +-zero +-invʳ +ℤ-comm
    ·-assoc ·-identityʳ
    (λ x y z → sym (·-distribˡ x y z))
    ·-comm


-- In Agda 2.5.3 the error was:

-- μ₂ is not strictly positive, because it occurs
-- in the third argument to ⟦_⟧
-- in the type of the constructor fix
-- in the definition of μ₂.

open import Data.Nat using (ℕ;zero;suc)
open import Data.Fin using (Fin;zero;suc)
open import Data.Vec
open import Data.Empty
open import Data.Product
open import Data.Sum
open import Data.Unit

Σ# : {n : ℕ} -> (Fin n -> Set) -> Set
Σ# {zero} f = ⊥
Σ# {suc zero} f = f zero
Σ# {suc n} f = f zero ⊎ Σ# {n} λ i -> f (suc i)

module Matrices {Ix : Set} {Σ : (Ix -> Set) -> Set} where

  Matrix : Set1
  Matrix = (i j : Ix) -> Set

  _<+>_ : Matrix -> Matrix -> Matrix
  m <+> n = λ i j -> m i j ⊎ n i j
  {-# INLINE _<+>_ #-}

  _<*>_ : Matrix -> Matrix -> Matrix
  m <*> n = λ i j -> Σ λ k -> m i k × n k j
  {-# INLINE _<*>_ #-}

data Poly {Coeffs : Set1} : Set1 where
  0p 1p : Poly
  X : Poly
  _+_ _*_ : (D1 D2 : Poly {Coeffs}) -> Poly {Coeffs}
  K : Coeffs -> Poly

module Dim {n : ℕ} where
  open Matrices {Fin n} {Σ#}

  ⟦_⟧ : Poly {Vec (Vec Set n) n} -> Matrix -> Matrix
  ⟦ 0p ⟧ x i j = ⊥
  ⟦ 1p ⟧ x i j = ⊤
  ⟦ X ⟧ x i j = x i j
  ⟦ D1 + D2 ⟧ x i j = (⟦ D1 ⟧ x <+> ⟦ D2 ⟧ x) i j
  ⟦ D1 * D2 ⟧ x i j = (⟦ D1 ⟧ x <*> ⟦ D2 ⟧ x) i j
  ⟦ K S ⟧ x i j = lookup (lookup S i) j

  ⟪_⟫ : Poly {Set} -> Set → Set
  ⟪ 0p ⟫ x = ⊥
  ⟪ 1p ⟫ x = ⊤
  ⟪ X ⟫ x = x
  ⟪ D1 + D2 ⟫ x = (⟪ D1 ⟫ x ⊎ ⟪ D2 ⟫ x)
  ⟪ D1 * D2 ⟫ x = (⟪ D1 ⟫ x × ⟪ D2 ⟫ x)
  ⟪ K S ⟫ x = S

  data μ₁ (p : Poly) : Set where
    fix : ⟪ p ⟫ (μ₁ p) -> μ₁ p

  data μ₂ (p : Poly) (i j : Fin n) : Set where
    fix : ⟦ p ⟧ (μ₂ p) i j -> μ₂ p i j


module Prelude.List.Relations.All where

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.List.Base

open import Prelude.Applicative

open import Agda.Primitive

infixr 5 _∷_
data All {a b} {A : Set a} (P : A → Set b) : List A → Set (a ⊔ b) where
  []  : All P []
  _∷_ : ∀ {x xs} (p : P x) (ps : All P xs) → All P (x ∷ xs)


------------------------------------------------------------------------------
-- The gcd program is correct
------------------------------------------------------------------------------

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

-- This module proves the correctness of the gcd program using
-- the Euclid's algorithm.

module LTC-PCF.Program.GCD.Total.CorrectnessProof where

open import LTC-PCF.Base
open import LTC-PCF.Data.Nat.Type
open import LTC-PCF.Program.GCD.Total.CommonDivisor using ( gcdCD )
open import LTC-PCF.Program.GCD.Total.Definitions using ( gcdSpec )
open import LTC-PCF.Program.GCD.Total.Divisible using ( gcdDivisible )
open import LTC-PCF.Program.GCD.Total.GCD using ( gcd )

------------------------------------------------------------------------------
-- The gcd is correct.
gcdCorrect : ∀ {m n} → N m → N n → gcdSpec m n (gcd m n)
gcdCorrect Nm Nn = gcdCD Nm Nn , gcdDivisible Nm Nn


module map-compose where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong)
open Eq.≡-Reasoning
open import Function using (_∘_)
open import lists using (List; []; _∷_; map)

postulate
  -- 外延性の公理
  extensionality : ∀ {A B : Set} {f g : A → B}
    → (∀ (x : A) → f x ≡ g x)
      -----------------------
    → f ≡ g

-- 外延性の公理を用いた証明のための補助定理
lemma : ∀ {A B C : Set} → (f : A → B) → (g : B → C) → (x : List A)
  → map (g ∘ f) x ≡ (map g ∘ map f) x
lemma f g []       = refl
lemma f g (x ∷ xs) =
  begin
    map (g ∘ f) (x ∷ xs)
  ≡⟨⟩
    (g ∘ f) x ∷ map (g ∘ f) xs
  ≡⟨ cong ((g ∘ f) x ∷_) (lemma f g xs) ⟩
    (g ∘ f) x ∷ (map g ∘ map f) xs
  ≡⟨⟩
    (map g ∘ map f) (x ∷ xs)
  ∎

-- mapの分配法則の証明
map-compose : ∀ {A B C : Set} → (f : A → B) → (g : B → C)
  → map (g ∘ f) ≡ map g ∘ map f
map-compose f g = extensionality (lemma f g)


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

open import HoTT

module cohomology.Choice where

unchoose : ∀ {i j} {n : ℕ₋₂} {A : Type i} {B : A → Type j}
  → Trunc n (Π A B) → Π A (Trunc n ∘ B)
unchoose = Trunc-rec (Π-level (λ _ → Trunc-level)) (λ f → [_] ∘ f)

has-choice : ∀ {i j} (n : ℕ₋₂) (A : Type i) (B : A → Type j) → Type (lmax i j)
has-choice {i} {j} n A B = is-equiv (unchoose {n = n} {A} {B})

{- Binary Choice -}
module _ {k} where

  pick-Bool : ∀ {j} {C : Lift {j = k} Bool → Type j}
    → (C (lift true)) → (C (lift false)) → Π (Lift Bool) C
  pick-Bool x y (lift true) = x
  pick-Bool x y (lift false) = y

  pick-Bool-η : ∀ {j} {C : Lift Bool → Type j} (f : Π (Lift Bool) C)
    → pick-Bool (f (lift true)) (f (lift false)) == f
  pick-Bool-η {C = C} f = λ= lemma
    where
    lemma : (b : Lift Bool) →
      pick-Bool {C = C} (f (lift true)) (f (lift false)) b == f b
    lemma (lift true) = idp
    lemma (lift false) = idp

  module _ {i} {n : ℕ₋₂} {A : Lift {j = k} Bool → Type i} where
    choose-Bool : Π (Lift Bool) (Trunc n ∘ A) → Trunc n (Π (Lift Bool) A)
    choose-Bool f = Trunc-rec Trunc-level
      (λ ft → Trunc-rec Trunc-level
        (λ ff → [ pick-Bool ft ff ] )
        (f (lift false)))
      (f (lift true))

    choose-Bool-squash : (f : Π (Lift Bool) A)
      → choose-Bool (λ b → [ f b ]) == [ f ]
    choose-Bool-squash f = ap [_] (pick-Bool-η f)

    private
      unc-c : ∀ f → unchoose (choose-Bool f) == f
      unc-c f = transport
        (λ h → unchoose (choose-Bool h) == h)
        (pick-Bool-η f)
        (Trunc-elim
           {P = λ tft →
             unchoose (choose-Bool (pick-Bool tft (f (lift false))))
             == pick-Bool tft (f (lift false))}
           (λ _ → =-preserves-level _ (Π-level (λ _ → Trunc-level)))
           (λ ft → Trunc-elim
             {P = λ tff →
               unchoose (choose-Bool (pick-Bool [ ft ] tff ))
               == pick-Bool [ ft ] tff}
             (λ _ → =-preserves-level _ (Π-level (λ _ → Trunc-level)))
             (λ ff → ! (pick-Bool-η _))
             (f (lift false)))
           (f (lift true)))

      c-unc : ∀ tg → choose-Bool (unchoose tg) == tg
      c-unc = Trunc-elim
        {P = λ tg → choose-Bool (unchoose tg) == tg}
        (λ _ → =-preserves-level _ Trunc-level)
        (λ g → ap [_] (pick-Bool-η g))

    Bool-has-choice : has-choice n (Lift Bool) A
    Bool-has-choice = is-eq unchoose choose-Bool unc-c c-unc


------------------------------------------------------------------------------
-- FOTC version of a nested recursive function
------------------------------------------------------------------------------

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

-- From: Ana Bove and Venanzio Capretta. Nested general recursion and
-- partiality in type theory. Vol. 2152 of LNCS. 2001.

module FOT.FOTC.Program.Nest.PropertiesI where

open import Common.FOL.Relation.Binary.EqReasoning

open import FOTC.Base
open import FOTC.Data.Nat.Type
open import FOTC.Program.Nest.Nest

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

nestCong : ∀ {m n} → m ≡ n → nest m ≡ nest n
nestCong refl = refl

nest-x≡0 : ∀ {n} → N n → nest n ≡ zero
nest-x≡0 nzero = nest-0
nest-x≡0 (nsucc {n} Nn) =
  nest (succ₁ n) ≡⟨ nest-S n ⟩
  nest (nest n)  ≡⟨ nestCong (nest-x≡0 Nn) ⟩
  nest zero      ≡⟨ nest-0 ⟩
  zero           ∎

nest-N : ∀ {n} → N n → N (nest n)
nest-N Nn = subst N (sym (nest-x≡0 Nn)) nzero


test.id : (A:Set) -> (x:A) -> A
test.id A x = x

nat.plus : (x:Nat) -> (y:Nat) -> Nat
nat.plus (nat.suc x) y = nat.suc (nat.plus x y)
nat.plus nat.zero y = y


import Either
open import Boolean

module Logic where

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

  Rel : Set → Set₁
  Rel X = X → X → Set

  Decidable : ∀ { X } → Rel X → Set
  Decidable R = ∀ x y → Either (R x y) (¬ (R x y))
    where open Either

  modusPonens : { P Q : Set } → ( P → Q ) → P → Q
  modusPonens = id