{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Data.DiffInt.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Univalence
open import Cubical.Data.DiffInt.Base
open import Cubical.Data.Nat as ℕ using (suc; zero; isSetℕ; discreteℕ; ℕ) renaming (_+_ to _+ⁿ_; _·_ to _·ⁿ_)
open import Cubical.Data.Sigma
open import Cubical.Data.Bool

open import Cubical.Data.Int as Int using (Int; sucInt)
open import Cubical.Foundations.Path
open import Cubical.Foundations.Isomorphism

open import Cubical.Relation.Binary.Base
open import Cubical.Relation.Nullary

open import Cubical.HITs.SetQuotients

open BinaryRelation

relIsEquiv : isEquivRel rel
relIsEquiv = equivRel {A = ℕ × ℕ} relIsRefl relIsSym relIsTrans
  where
    open import Cubical.Data.Nat
    relIsRefl : isRefl rel
    relIsRefl (a0 , a1) = refl

    relIsSym : isSym rel
    relIsSym (a0 , a1) (b0 , b1) p = sym p

    relIsTrans : isTrans rel
    relIsTrans (a0 , a1) (b0 , b1) (c0 , c1) p0 p1 =
      inj-m+ {m = (b0 + b1)} ((b0 + b1) + (a0 + c1) ≡⟨ +-assoc (b0 + b1) a0 c1  ⟩
            ((b0 + b1) + a0) + c1 ≡[ i ]⟨ +-comm b0 b1 i + a0   + c1 ⟩
            ((b1 + b0) + a0) + c1 ≡[ i ]⟨ +-comm (b1 + b0) a0 i + c1 ⟩
            (a0 + (b1 + b0)) + c1 ≡[ i ]⟨ +-assoc a0 b1 b0 i    + c1 ⟩
            (a0 + b1) + b0 + c1 ≡⟨ sym (+-assoc (a0 + b1) b0 c1) ⟩
            (a0 + b1) + (b0 + c1) ≡⟨ cong (λ p → p . fst + p .snd) (transport ΣPath≡PathΣ (p0 , p1))⟩
            (b0 + a1) + (c0 + b1) ≡⟨ sym (+-assoc b0 a1 (c0 + b1))⟩
            b0 + (a1 + (c0 + b1)) ≡[ i ]⟨ b0 + (a1 + +-comm c0 b1 i) ⟩
            b0 + (a1 + (b1 + c0)) ≡[ i ]⟨ b0 + +-comm a1 (b1 + c0) i ⟩
            b0 + ((b1 + c0) + a1) ≡[ i ]⟨ b0 + +-assoc b1 c0 a1 (~ i) ⟩
            b0 + (b1 + (c0 + a1)) ≡⟨ +-assoc b0 b1 (c0 + a1)⟩
            (b0 + b1) + (c0 + a1) ∎ )

relIsProp : BinaryRelation.isPropValued rel
relIsProp a b x y = isSetℕ _ _ _ _

discreteℤ : Discrete ℤ
discreteℤ = discreteSetQuotients (discreteΣ discreteℕ λ _ → discreteℕ) relIsProp relIsEquiv (λ _ _ → discreteℕ _ _)

isSetℤ : isSet ℤ
isSetℤ = Discrete→isSet discreteℤ

sucℤ' : ℕ × ℕ -> ℤ
sucℤ' (a⁺ , a⁻) = [ suc a⁺ , a⁻ ]

sucℤ'-respects-rel : (a b : ℕ × ℕ) → rel a b → sucℤ' a ≡ sucℤ' b
sucℤ'-respects-rel a@(a⁺ , a⁻) b@(b⁺ , b⁻) a~b = eq/ (suc a⁺ , a⁻) (suc b⁺ , b⁻) λ i → suc (a~b i)

sucℤ : ℤ -> ℤ
sucℤ = elim {R = rel} {B = λ _ → ℤ} (λ _ → isSetℤ) sucℤ' sucℤ'-respects-rel

predℤ' : ℕ × ℕ -> ℤ
predℤ' (a⁺ , a⁻) = [ a⁺ , suc a⁻ ]

⟦_⟧ : Int -> ℤ
⟦_⟧ (Int.pos n) = [ n , 0 ]
⟦_⟧ (Int.negsuc n) = [ 0 , suc n ]

fwd = ⟦_⟧

bwd' : ℕ × ℕ -> Int
bwd' (zero   , a⁻) = Int.neg a⁻
bwd' (suc a⁺ , a⁻) = sucInt (bwd' (a⁺ , a⁻))

rel-suc : ∀ a⁺ a⁻ → rel (a⁺ , a⁻) (suc a⁺ , suc a⁻)
rel-suc a⁺ a⁻ = ℕ.+-suc a⁺ a⁻

bwd'-suc : ∀ a⁺ a⁻ → bwd' (a⁺ , a⁻) ≡ bwd' (suc a⁺ , suc a⁻)
bwd'-suc zero zero = refl
bwd'-suc zero (suc a⁻) = refl
bwd'-suc (suc a⁺) a⁻ i = sucInt (bwd'-suc a⁺ a⁻ i)

bwd'+ : ∀ m n → bwd' (m , m +ⁿ n) ≡ bwd' (0 , n)
bwd'+ zero n = refl
bwd'+ (suc m) n = sym (bwd'-suc m (m +ⁿ n)) ∙ bwd'+ m n

bwd'-respects-rel : (a b : ℕ × ℕ) → rel a b → bwd' a ≡ bwd' b
bwd'-respects-rel (zero   , a⁻) (    b⁺ , b⁻) a~b = sym (bwd'+ b⁺ a⁻) ∙ (λ i → bwd' (b⁺ , a~b (~ i)))
bwd'-respects-rel (suc a⁺ , a⁻) (zero   , b⁻) a~b = (λ i → bwd' (suc a⁺ , a~b (~ i))) ∙ sym (bwd'-suc a⁺ (a⁺ +ⁿ b⁻)) ∙ bwd'+ a⁺ b⁻
bwd'-respects-rel (suc a⁺ , a⁻) (suc b⁺ , b⁻) a~b i = sucInt (bwd'-respects-rel (a⁺ , a⁻) (b⁺ , b⁻) (ℕ.inj-m+ {1} {a⁺ +ⁿ b⁻} {b⁺ +ⁿ a⁻} a~b) i)

bwd : ℤ -> Int
bwd = elim {R = rel} {B = λ _ → Int} (λ _ → Int.isSetInt) bwd' bwd'-respects-rel

bwd-fwd : ∀ (x : Int) -> bwd (fwd x) ≡ x
bwd-fwd (Int.pos zero) = refl
bwd-fwd (Int.pos (suc n)) i = sucInt (bwd-fwd (Int.pos n) i)
bwd-fwd (Int.negsuc n) = refl

suc-⟦⟧ : ∀ x → sucℤ ⟦ x ⟧ ≡ ⟦ sucInt x ⟧
suc-⟦⟧ (Int.pos n) = refl
suc-⟦⟧ (Int.negsuc zero) = eq/ {R = rel} (1 , 1) (0 , 0) refl
suc-⟦⟧ (Int.negsuc (suc n)) = eq/ {R = rel} (1 , 2 +ⁿ n) (0 , 1 +ⁿ n) refl

fwd-bwd' : (a : ℕ × ℕ) → fwd (bwd [ a ]) ≡ [ a ]
fwd-bwd' a@(zero , zero) = refl
fwd-bwd' a@(zero , suc a⁻) = refl
fwd-bwd' a@(suc a⁺ , a⁻) = sym (suc-⟦⟧ (bwd [ a⁺ , a⁻ ])) ∙ (λ i → sucℤ (fwd-bwd' (a⁺ , a⁻) i))

fwd-bwd : ∀ (z : ℤ) -> fwd (bwd z) ≡ z
fwd-bwd = elimProp {R = rel} (λ _  → isSetℤ _ _) fwd-bwd'

Int≡ℤ : Int ≡ ℤ
Int≡ℤ = isoToPath (iso fwd bwd fwd-bwd bwd-fwd)

infix  8 -_
infixl 7 _·_
infixl 6 _+_

_+'_ : (a b : ℕ × ℕ) → ℤ
(a⁺ , a⁻) +' (b⁺ , b⁻) = [ a⁺ +ⁿ b⁺ , a⁻ +ⁿ b⁻ ]

private
  commˡⁿ : ∀ a b c → a +ⁿ b +ⁿ c ≡ a +ⁿ c +ⁿ b
  commˡⁿ a b c = sym (ℕ.+-assoc a b c) ∙ (λ i → a +ⁿ ℕ.+-comm b c i) ∙ ℕ.+-assoc a c b

  lem0 : ∀ a b c d → (a +ⁿ b) +ⁿ (c +ⁿ d) ≡ (a +ⁿ c) +ⁿ (b +ⁿ d)
  lem0 a b c d = ℕ.+-assoc (a +ⁿ b) c d ∙ (λ i → commˡⁿ a b c i +ⁿ d) ∙ sym (ℕ.+-assoc (a +ⁿ c) b d)

+ⁿ-creates-rel-≡ : ∀ a⁺ a⁻ x → _≡_ {A = ℤ} [ a⁺ , a⁻ ] [ a⁺ +ⁿ x , a⁻ +ⁿ x ]
+ⁿ-creates-rel-≡ a⁺ a⁻ x = eq/ (a⁺ , a⁻) (a⁺ +ⁿ x , a⁻ +ⁿ x) ((λ i → a⁺ +ⁿ ℕ.+-comm a⁻ x i) ∙ ℕ.+-assoc a⁺ x a⁻)

+-respects-relʳ : (a b c : ℕ × ℕ) → rel a b → (a +' c) ≡ (b +' c)
+-respects-relʳ a@(a⁺ , a⁻) b@(b⁺ , b⁻) c@(c⁺ , c⁻) p = eq/ {R = rel} (a⁺ +ⁿ c⁺ , a⁻ +ⁿ c⁻) (b⁺ +ⁿ c⁺ , b⁻ +ⁿ c⁻) (
  (a⁺ +ⁿ c⁺) +ⁿ (b⁻ +ⁿ c⁻) ≡⟨ lem0 a⁺ c⁺ b⁻ c⁻ ⟩
  (a⁺ +ⁿ b⁻) +ⁿ (c⁺ +ⁿ c⁻) ≡[ i ]⟨ p i +ⁿ (c⁺ +ⁿ c⁻) ⟩
  (b⁺ +ⁿ a⁻) +ⁿ (c⁺ +ⁿ c⁻) ≡⟨ sym (lem0 b⁺ c⁺ a⁻ c⁻) ⟩
  (b⁺ +ⁿ c⁺) +ⁿ (a⁻ +ⁿ c⁻) ∎)

+-respects-relˡ : (a b c : ℕ × ℕ) → rel b c → (a +' b) ≡ (a +' c)
+-respects-relˡ a@(a⁺ , a⁻) b@(b⁺ , b⁻) c@(c⁺ , c⁻) p = eq/ {R = rel} (a⁺ +ⁿ b⁺ , a⁻ +ⁿ b⁻) (a⁺ +ⁿ c⁺ , a⁻ +ⁿ c⁻) (
  (a⁺ +ⁿ b⁺) +ⁿ (a⁻ +ⁿ c⁻) ≡⟨ lem0 a⁺ b⁺ a⁻ c⁻ ⟩
  (a⁺ +ⁿ a⁻) +ⁿ (b⁺ +ⁿ c⁻) ≡[ i ]⟨ (a⁺ +ⁿ a⁻) +ⁿ p i ⟩
  (a⁺ +ⁿ a⁻) +ⁿ (c⁺ +ⁿ b⁻) ≡⟨ sym (lem0 a⁺ c⁺ a⁻ b⁻) ⟩
  (a⁺ +ⁿ c⁺) +ⁿ (a⁻ +ⁿ b⁻) ∎)

_+''_ : ℤ → ℤ → ℤ
_+''_ = rec2 {R = rel} {B = ℤ} φ _+'_ +-respects-relʳ +-respects-relˡ
  where abstract φ = isSetℤ

-- normalization of isSetℤ explodes. Therefore we wrap this with expanded cases
_+_ : ℤ → ℤ → ℤ
x@([ _ ])               + y@([ _ ])               = x +'' y
x@([ _ ])               + y@(eq/ _ _ _ _)         = x +'' y
x@(eq/ _ _ _ _)         + y@([ _ ])               = x +'' y
x@(eq/ _ _ _ _)         + y@(eq/ _ _ _ _)         = x +'' y
x@(eq/ _ _ _ _)         + y@(squash/ a b p q i j) = isSetℤ _ _ (cong (x +_) p) (cong (x +_) q) i j
x@([ _ ])               + y@(squash/ a b p q i j) = isSetℤ _ _ (cong (x +_) p) (cong (x +_) q) i j
x@(squash/ a b p q i j) + y                       = isSetℤ _ _ (cong (_+ y) p) (cong (_+ y) q) i j

-'_ : ℕ × ℕ → ℤ
-' (a⁺ , a⁻) = [ a⁻ , a⁺ ]

neg-respects-rel'-≡ : (a b : ℕ × ℕ) → rel a b → (-' a) ≡ (-' b)
neg-respects-rel'-≡ a@(a⁺ , a⁻) b@(b⁺ , b⁻) p = eq/ {R = rel} (a⁻ , a⁺) (b⁻ , b⁺) (ℕ.+-comm a⁻ b⁺ ∙ sym p ∙ ℕ.+-comm a⁺ b⁻)

-_ : ℤ → ℤ
-_ = rec {R = rel} {B = ℤ} isSetℤ -'_ neg-respects-rel'-≡

_·'_ : (a b : ℕ × ℕ) → ℤ
(a⁺ , a⁻) ·' (b⁺ , b⁻) = [ a⁺ ·ⁿ b⁺ +ⁿ a⁻ ·ⁿ b⁻ , a⁺ ·ⁿ b⁻ +ⁿ a⁻ ·ⁿ b⁺ ]

private
  lem1 : ∀ a b c d → (a +ⁿ b) +ⁿ (c +ⁿ d) ≡ (a +ⁿ d) +ⁿ (b +ⁿ c)
  lem1 a b c d = (λ i → (a +ⁿ b) +ⁿ ℕ.+-comm c d i) ∙ ℕ.+-assoc (a +ⁿ b) d c ∙ (λ i → commˡⁿ a b d i +ⁿ c) ∙ sym (ℕ.+-assoc (a +ⁿ d) b c)

·-respects-relʳ : (a b c : ℕ × ℕ) → rel a b → (a ·' c) ≡ (b ·' c)
·-respects-relʳ a@(a⁺ , a⁻) b@(b⁺ , b⁻) c@(c⁺ , c⁻) p = eq/ {R = rel} (a⁺ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ c⁻ , a⁺ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ c⁺) (b⁺ ·ⁿ c⁺ +ⁿ b⁻ ·ⁿ c⁻ , b⁺ ·ⁿ c⁻ +ⁿ b⁻ ·ⁿ c⁺) (
  (a⁺ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ c⁻) +ⁿ (b⁺ ·ⁿ c⁻ +ⁿ b⁻ ·ⁿ c⁺) ≡⟨ lem1 (a⁺ ·ⁿ c⁺) (a⁻ ·ⁿ c⁻) (b⁺ ·ⁿ c⁻) (b⁻ ·ⁿ c⁺) ⟩
  (a⁺ ·ⁿ c⁺ +ⁿ b⁻ ·ⁿ c⁺) +ⁿ (a⁻ ·ⁿ c⁻ +ⁿ b⁺ ·ⁿ c⁻) ≡[ i ]⟨ ℕ.·-distribʳ a⁺ b⁻ c⁺ i +ⁿ ℕ.·-distribʳ a⁻ b⁺ c⁻ i ⟩
  ((a⁺ +ⁿ b⁻) ·ⁿ c⁺) +ⁿ ((a⁻ +ⁿ b⁺) ·ⁿ c⁻)         ≡[ i ]⟨ p i ·ⁿ c⁺ +ⁿ (ℕ.+-comm a⁻ b⁺ ∙ sym p ∙ ℕ.+-comm a⁺ b⁻) i ·ⁿ c⁻ ⟩
  ((b⁺ +ⁿ a⁻) ·ⁿ c⁺) +ⁿ ((b⁻ +ⁿ a⁺) ·ⁿ c⁻)         ≡[ i ]⟨ ℕ.·-distribʳ b⁺ a⁻ c⁺ (~ i) +ⁿ ℕ.·-distribʳ b⁻ a⁺ c⁻ (~ i) ⟩
  (b⁺ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ c⁺) +ⁿ (b⁻ ·ⁿ c⁻ +ⁿ a⁺ ·ⁿ c⁻) ≡⟨ sym (lem1 (b⁺ ·ⁿ c⁺) (b⁻ ·ⁿ c⁻) (a⁺ ·ⁿ c⁻) (a⁻ ·ⁿ c⁺)) ⟩
  (b⁺ ·ⁿ c⁺ +ⁿ b⁻ ·ⁿ c⁻) +ⁿ (a⁺ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ c⁺) ∎)

·-respects-relˡ : (a b c : ℕ × ℕ) → rel b c → (a ·' b) ≡ (a ·' c)
·-respects-relˡ a@(a⁺ , a⁻) b@(b⁺ , b⁻) c@(c⁺ , c⁻) p = eq/ {R = rel} (a⁺ ·ⁿ b⁺ +ⁿ a⁻ ·ⁿ b⁻ , a⁺ ·ⁿ b⁻ +ⁿ a⁻ ·ⁿ b⁺) (a⁺ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ c⁻ , a⁺ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ c⁺) (
  (a⁺ ·ⁿ b⁺ +ⁿ a⁻ ·ⁿ b⁻) +ⁿ (a⁺ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ c⁺) ≡⟨ lem0 (a⁺ ·ⁿ b⁺) (a⁻ ·ⁿ b⁻) (a⁺ ·ⁿ c⁻) (a⁻ ·ⁿ c⁺) ⟩
  (a⁺ ·ⁿ b⁺ +ⁿ a⁺ ·ⁿ c⁻) +ⁿ (a⁻ ·ⁿ b⁻ +ⁿ a⁻ ·ⁿ c⁺) ≡[ i ]⟨ ℕ.·-distribˡ a⁺ b⁺ c⁻ i +ⁿ ℕ.·-distribˡ a⁻ b⁻ c⁺ i ⟩
  (a⁺ ·ⁿ (b⁺ +ⁿ c⁻)) +ⁿ (a⁻ ·ⁿ (b⁻ +ⁿ c⁺))         ≡[ i ]⟨ a⁺ ·ⁿ p i +ⁿ a⁻ ·ⁿ (ℕ.+-comm b⁻ c⁺ ∙ sym p ∙ ℕ.+-comm b⁺ c⁻) i ⟩
  (a⁺ ·ⁿ (c⁺ +ⁿ b⁻)) +ⁿ (a⁻ ·ⁿ (c⁻ +ⁿ b⁺))         ≡[ i ]⟨ ℕ.·-distribˡ a⁺ c⁺ b⁻ (~ i) +ⁿ ℕ.·-distribˡ a⁻ c⁻ b⁺ (~ i) ⟩
  (a⁺ ·ⁿ c⁺ +ⁿ a⁺ ·ⁿ b⁻) +ⁿ (a⁻ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ b⁺) ≡⟨ sym (lem0 (a⁺ ·ⁿ c⁺) (a⁻ ·ⁿ c⁻) (a⁺ ·ⁿ b⁻) (a⁻ ·ⁿ b⁺)) ⟩
  (a⁺ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ c⁻) +ⁿ (a⁺ ·ⁿ b⁻ +ⁿ a⁻ ·ⁿ b⁺) ∎)

_·''_ : ℤ → ℤ → ℤ
_·''_ = rec2 {R = rel} {B = ℤ} isSetℤ _·'_ ·-respects-relʳ ·-respects-relˡ

-- normalization of isSetℤ explodes. Therefore we wrap this with expanded cases
_·_ : ℤ → ℤ → ℤ
x@([ _ ])               · y@([ _ ])               = x ·'' y
x@([ _ ])               · y@(eq/ _ _ _ _)         = x ·'' y
x@(eq/ _ _ _ _)         · y@([ _ ])               = x ·'' y
x@(eq/ _ _ _ _)         · y@(eq/ _ _ _ _)         = x ·'' y
x@(eq/ _ _ _ _)         · y@(squash/ a b p q i j) = isSetℤ _ _ (cong (x ·_) p) (cong (x ·_) q) i j
x@([ _ ])               · y@(squash/ a b p q i j) = isSetℤ _ _ (cong (x ·_) p) (cong (x ·_) q) i j
x@(squash/ a b p q i j) · y                       = isSetℤ _ _ (cong (_· y) p) (cong (_· y) q) i j

+-identityʳ : (x : ℤ) → x + 0 ≡ x
+-identityʳ = elimProp {R = rel} (λ _ → isSetℤ _ _)
  λ{ (a⁺ , a⁻) i → [ ℕ.+-comm a⁺ 0 i , ℕ.+-comm a⁻ 0 i ] }

+-comm : (x y : ℤ) → x + y ≡ y + x
+-comm = elimProp2 {R = rel} (λ _ _ → isSetℤ _ _)
  λ{ (a⁺ , a⁻) (b⁺ , b⁻) i → [ ℕ.+-comm a⁺ b⁺ i , ℕ.+-comm a⁻ b⁻ i ] }

+-inverseʳ : (x : ℤ) → x + (- x) ≡ 0
+-inverseʳ = elimProp {R = rel} (λ _ → isSetℤ _ _)
  λ{ (a⁺ , a⁻) → eq/ {R = rel} (a⁺ +ⁿ a⁻ , a⁻ +ⁿ a⁺) (0 , 0) (ℕ.+-zero (a⁺ +ⁿ a⁻) ∙ ℕ.+-comm a⁺ a⁻) }

+-assoc : (x y z : ℤ) → x + (y + z) ≡ x + y + z
+-assoc = elimProp3 {R = rel} (λ _ _ _ → isSetℤ _ _)
  λ{ (a⁺ , a⁻) (b⁺ , b⁻) (c⁺ , c⁻) i → [ ℕ.+-assoc a⁺ b⁺ c⁺ i , ℕ.+-assoc a⁻ b⁻ c⁻ i ] }

·-identityʳ : (x : ℤ) → x · 1 ≡ x
·-identityʳ = elimProp {R = rel} (λ _ → isSetℤ _ _) γ
  where
  γ : (a : ℕ × ℕ) → _
  γ (a⁺ , a⁻) i = [ p i , q i ]
    where
    p : a⁺ ·ⁿ 1 +ⁿ a⁻ ·ⁿ 0 ≡ a⁺
    p i = ℕ.+-comm (ℕ.·-identityʳ a⁺ i) (ℕ.0≡m·0 a⁻ (~ i)) i
    q : a⁺ ·ⁿ 0 +ⁿ a⁻ ·ⁿ 1 ≡ a⁻
    q i = ℕ.0≡m·0 a⁺ (~ i) +ⁿ ℕ.·-identityʳ a⁻ i

·-comm : (x y : ℤ) → x · y ≡ y · x
·-comm = elimProp2 {R = rel} (λ _ _ → isSetℤ _ _)
  λ{ (a⁺ , a⁻) (b⁺ , b⁻) i → [ ℕ.·-comm a⁺ b⁺ i +ⁿ ℕ.·-comm a⁻ b⁻ i , ℕ.+-comm (ℕ.·-comm a⁺ b⁻ i) (ℕ.·-comm a⁻ b⁺ i) i ] }

·-distribˡ : (x y z : ℤ) → x · (y + z) ≡ x · y + x · z
·-distribˡ = elimProp3 {R = rel} (λ _ _ _ → isSetℤ _ _)
  λ{ (a⁺ , a⁻) (b⁺ , b⁻) (c⁺ , c⁻) →
    [ a⁺ ·ⁿ (b⁺ +ⁿ c⁺) +ⁿ a⁻ ·ⁿ (b⁻ +ⁿ c⁻)
    , a⁺ ·ⁿ (b⁻ +ⁿ c⁻) +ⁿ a⁻ ·ⁿ (b⁺ +ⁿ c⁺)
    ] ≡[ i ]⟨ [ ℕ.·-distribˡ a⁺ b⁺ c⁺ (~ i) +ⁿ ℕ.·-distribˡ a⁻ b⁻ c⁻ (~ i) , ℕ.·-distribˡ a⁺ b⁻ c⁻ (~ i) +ⁿ ℕ.·-distribˡ a⁻ b⁺ c⁺ (~ i) ] ⟩
    [ (a⁺ ·ⁿ b⁺ +ⁿ a⁺ ·ⁿ c⁺) +ⁿ (a⁻ ·ⁿ b⁻ +ⁿ a⁻ ·ⁿ c⁻)
    , (a⁺ ·ⁿ b⁻ +ⁿ a⁺ ·ⁿ c⁻) +ⁿ (a⁻ ·ⁿ b⁺ +ⁿ a⁻ ·ⁿ c⁺)
    ] ≡[ i ]⟨ [ lem0 (a⁺ ·ⁿ b⁺) (a⁻ ·ⁿ b⁻) (a⁺ ·ⁿ c⁺) (a⁻ ·ⁿ c⁻) (~ i), lem0 (a⁺ ·ⁿ b⁻) (a⁺ ·ⁿ c⁻) (a⁻ ·ⁿ b⁺) (a⁻ ·ⁿ c⁺) i ] ⟩
    [ a⁺ ·ⁿ b⁺ +ⁿ a⁻ ·ⁿ b⁻ +ⁿ (a⁺ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ c⁻)
    , a⁺ ·ⁿ b⁻ +ⁿ a⁻ ·ⁿ b⁺ +ⁿ (a⁺ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ c⁺)
    ] ∎
   }

·-assoc : (x y z : ℤ) → x · (y · z) ≡ x · y · z
·-assoc = elimProp3 {R = rel} (λ _ _ _ → isSetℤ _ _)
  λ{ (a⁺ , a⁻) (b⁺ , b⁻) (c⁺ , c⁻) →
    [ a⁺ ·ⁿ (b⁺ ·ⁿ c⁺ +ⁿ b⁻ ·ⁿ c⁻) +ⁿ a⁻ ·ⁿ (b⁺ ·ⁿ c⁻ +ⁿ b⁻ ·ⁿ c⁺)
    , a⁺ ·ⁿ (b⁺ ·ⁿ c⁻ +ⁿ b⁻ ·ⁿ c⁺) +ⁿ a⁻ ·ⁿ (b⁺ ·ⁿ c⁺ +ⁿ b⁻ ·ⁿ c⁻)
    ] ≡[ i ]⟨ [ ℕ.·-distribˡ a⁺ (b⁺ ·ⁿ c⁺) (b⁻ ·ⁿ c⁻) (~ i) +ⁿ ℕ.·-distribˡ a⁻ (b⁺ ·ⁿ c⁻) (b⁻ ·ⁿ c⁺) (~ i)
              , ℕ.·-distribˡ a⁺ (b⁺ ·ⁿ c⁻) (b⁻ ·ⁿ c⁺) (~ i) +ⁿ ℕ.·-distribˡ a⁻ (b⁺ ·ⁿ c⁺) (b⁻ ·ⁿ c⁻) (~ i) ] ⟩
    [ (a⁺ ·ⁿ (b⁺ ·ⁿ c⁺) +ⁿ a⁺ ·ⁿ (b⁻ ·ⁿ c⁻)) +ⁿ (a⁻ ·ⁿ (b⁺ ·ⁿ c⁻) +ⁿ a⁻ ·ⁿ (b⁻ ·ⁿ c⁺))
    , (a⁺ ·ⁿ (b⁺ ·ⁿ c⁻) +ⁿ a⁺ ·ⁿ (b⁻ ·ⁿ c⁺)) +ⁿ (a⁻ ·ⁿ (b⁺ ·ⁿ c⁺) +ⁿ a⁻ ·ⁿ (b⁻ ·ⁿ c⁻))
    ] ≡[ i ]⟨ [ (ℕ.·-assoc a⁺ b⁺ c⁺ i +ⁿ ℕ.·-assoc a⁺ b⁻ c⁻ i) +ⁿ (ℕ.·-assoc a⁻ b⁺ c⁻ i +ⁿ ℕ.·-assoc a⁻ b⁻ c⁺ i)
              , (ℕ.·-assoc a⁺ b⁺ c⁻ i +ⁿ ℕ.·-assoc a⁺ b⁻ c⁺ i) +ⁿ (ℕ.·-assoc a⁻ b⁺ c⁺ i +ⁿ ℕ.·-assoc a⁻ b⁻ c⁻ i) ] ⟩
    [ (a⁺ ·ⁿ b⁺ ·ⁿ c⁺ +ⁿ a⁺ ·ⁿ b⁻ ·ⁿ c⁻) +ⁿ (a⁻ ·ⁿ b⁺ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ b⁻ ·ⁿ c⁺)
    , (a⁺ ·ⁿ b⁺ ·ⁿ c⁻ +ⁿ a⁺ ·ⁿ b⁻ ·ⁿ c⁺) +ⁿ (a⁻ ·ⁿ b⁺ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ b⁻ ·ⁿ c⁻)
    ] ≡[ i ]⟨ [ lem1 (a⁺ ·ⁿ b⁺ ·ⁿ c⁺) (a⁺ ·ⁿ b⁻ ·ⁿ c⁻) (a⁻ ·ⁿ b⁺ ·ⁿ c⁻) (a⁻ ·ⁿ b⁻ ·ⁿ c⁺) i
              , lem1 (a⁺ ·ⁿ b⁺ ·ⁿ c⁻) (a⁺ ·ⁿ b⁻ ·ⁿ c⁺) (a⁻ ·ⁿ b⁺ ·ⁿ c⁺) (a⁻ ·ⁿ b⁻ ·ⁿ c⁻) i ] ⟩
    [ (a⁺ ·ⁿ b⁺ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ b⁻ ·ⁿ c⁺) +ⁿ (a⁺ ·ⁿ b⁻ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ b⁺ ·ⁿ c⁻)
    , (a⁺ ·ⁿ b⁺ ·ⁿ c⁻ +ⁿ a⁻ ·ⁿ b⁻ ·ⁿ c⁻) +ⁿ (a⁺ ·ⁿ b⁻ ·ⁿ c⁺ +ⁿ a⁻ ·ⁿ b⁺ ·ⁿ c⁺)
    ] ≡[ i ]⟨ [ ℕ.·-distribʳ (a⁺ ·ⁿ b⁺) (a⁻ ·ⁿ b⁻) c⁺ i +ⁿ ℕ.·-distribʳ (a⁺ ·ⁿ b⁻) (a⁻ ·ⁿ b⁺) c⁻ i
              , ℕ.·-distribʳ (a⁺ ·ⁿ b⁺) (a⁻ ·ⁿ b⁻) c⁻ i +ⁿ ℕ.·-distribʳ (a⁺ ·ⁿ b⁻) (a⁻ ·ⁿ b⁺) c⁺ i ] ⟩
    [ (a⁺ ·ⁿ b⁺ +ⁿ a⁻ ·ⁿ b⁻) ·ⁿ c⁺ +ⁿ (a⁺ ·ⁿ b⁻ +ⁿ a⁻ ·ⁿ b⁺) ·ⁿ c⁻
    , (a⁺ ·ⁿ b⁺ +ⁿ a⁻ ·ⁿ b⁻) ·ⁿ c⁻ +ⁿ (a⁺ ·ⁿ b⁻ +ⁿ a⁻ ·ⁿ b⁺) ·ⁿ c⁺
    ] ∎
   }

private
  _ : Dec→Bool (discreteℤ [ (3 , 5) ] [ (4 , 6) ]) ≡ true
  _ = refl

  _ : Dec→Bool (discreteℤ [ (3 , 5) ] [ (4 , 7) ]) ≡ false
  _ = refl


module x08-747Quantifiers-hc where

-- Library

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong; sym)
open import Data.Nat using (ℕ; zero; suc; _+_; _*_; _≤_; z≤n; s≤s) -- added ≤
-- open import Data.Nat.Properties using (≤-refl)
open import Relation.Nullary using (¬_)
open import Data.Product using (_×_; proj₁; proj₂) renaming (_,_ to ⟨_,_⟩) -- added proj₂
open import Data.Sum using (_⊎_; inj₁; inj₂ ) -- added inj₁, inj₂
open import Function using (_∘_) -- added

-- BEGIN: Copied from 747Isomorphism.
postulate
  extensionality : ∀ {A B : Set} {f g : A → B}
    → (∀ (x : A) → f x ≡ g x)
      -----------------------
    → f ≡ g

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

record _⇔_ (A B : Set) : Set where
  field
    to   : A → B
    from : B → A
open _⇔_
-- END: Copied from 747Isomorphism.

-- Logical forall is ∀.
-- Forall elimination is function application.
∀-elim : ∀ {A : Set} {B : A → Set}
  → (L : ∀ (x : A) → B x)
  → (M : A)
    -----------------
  → B M
∀-elim L M = L M

-- A → B is nicer syntax for ∀ (_ : A) → B.

-- 747/PLFA exercise: ForAllDistProd (1 point)
-- ∀ distributes over ×
-- (note: → distributes over × was shown in Connectives)

∀-distrib-× : ∀ {A : Set} {B C : A → Set} →
  (∀ (a : A) → B a × C a) ≃ (∀ (a : A) → B a) × (∀ (a : A) → C a)
to      ∀-distrib-× a→Ba×Ca         = ⟨ proj₁ ∘ a→Ba×Ca , proj₂ ∘ a→Ba×Ca ⟩
from    ∀-distrib-× ⟨ a→ba , a→ca ⟩ = λ a → ⟨ a→ba a , a→ca a ⟩
from∘to ∀-distrib-× a→Ba×Ca         = refl
to∘from ∀-distrib-× ⟨ a→ba , a→ca ⟩ = refl

-- 747/PLFA exercise: SumForAllImpForAllSum (1 point)
-- disjunction of foralls implies a forall of disjunctions
⊎∀-implies-∀⊎ : ∀ {A : Set} {B C : A → Set} →
  (∀ (a : A) → B a) ⊎ (∀ (a : A) → C a)  →  ∀ (a : A) → B a ⊎ C a
⊎∀-implies-∀⊎ (inj₁ a→ba) = inj₁ ∘ a→ba
⊎∀-implies-∀⊎ (inj₂ a→ca) = inj₂ ∘ a→ca

-- Existential quantification
-- a pair:
-- - a witness and
-- - a proof that the witness satisfies the property
data Σ (A : Set) (B : A → Set) : Set where
  ⟨_,_⟩ : (a : A) → B a → Σ A B

-- convenient syntax

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

-- can use the RHS syntax in code,
-- but LHS will show up in displays of goal and context.
-- This syntax is equivalent to defining a dependent record type.

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

-- convention : library uses ∃ when domain of bound variable is implicit

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

-- syntax

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

-- eliminate existential with a function
-- that consumes the witness and proof
-- and reaches a conclusion C
∃-elim : ∀ {A : Set} {B : A → Set} {C : Set}
  → (∀ a → B a → C)
  → ∃[ a ] B a
    ---------------
  → C
∃-elim a→Ba→C ⟨ a , Ba ⟩ = a→Ba→C a Ba

-- generalization of currying (from Connectives)
-- currying : ∀ {A B C : Set} → (A → B → C) ≃ (A × B → C)
∀∃-currying : ∀ {A : Set} {B : A → Set} {C : Set}
  → (∀ a → B a → C) ≃ (∃[ a ] B a → C)
_≃_.to      ∀∃-currying a→Ba→C ⟨ a , Ba ⟩ = a→Ba→C a Ba
_≃_.from    ∀∃-currying ∃xB a Ba          = ∃xB ⟨ a , Ba ⟩
_≃_.from∘to ∀∃-currying a→Ba→C            = refl
_≃_.to∘from ∀∃-currying ∃xB               = extensionality λ { ⟨ a , Ba ⟩ → refl}

-- 747/PLFA exercise: ExistsDistSum (2 points)
-- existentials distribute over disjunction
∃-distrib-⊎ : ∀ {A : Set} {B C : A → Set} →
  ∃[ a ] (B a ⊎ C a) ≃ (∃[ a ] B a) ⊎ (∃[ a ] C a)
to      ∃-distrib-⊎       ⟨ a , inj₁ Ba ⟩  = inj₁ ⟨ a ,      Ba ⟩
to      ∃-distrib-⊎       ⟨ a , inj₂ Ca ⟩  = inj₂ ⟨ a ,      Ca ⟩
from    ∃-distrib-⊎ (inj₁ ⟨ a ,      Ba ⟩) =      ⟨ a , inj₁ Ba ⟩
from    ∃-distrib-⊎ (inj₂ ⟨ a ,      Ca ⟩) =      ⟨ a , inj₂ Ca ⟩
from∘to ∃-distrib-⊎       ⟨ a , inj₁ Ba ⟩  = refl
from∘to ∃-distrib-⊎       ⟨ a , inj₂ Ca ⟩  = refl
to∘from ∃-distrib-⊎ (inj₁ ⟨ a ,      Ba ⟩) = refl
to∘from ∃-distrib-⊎ (inj₂ ⟨ a ,      Ca ⟩) = refl

-- 747/PLFA exercise: ExistsProdImpProdExists (1 point)
-- existentials distribute over ×
∃×-implies-×∃ : ∀ {A : Set} {B C : A → Set} →
  ∃[ a ] (B a × C a) → (∃[ a ] B a) × (∃[ a ] C a)
∃×-implies-×∃ ⟨ a , ⟨ Ba , Ca ⟩ ⟩ = ⟨ ⟨ a , Ba ⟩ , ⟨ a , Ca ⟩ ⟩

-- existential example: revisiting even/odd.
-- mutually-recursive definitions of even and odd.
data even : ℕ → Set
data odd  : ℕ → Set

data even where

  even-zero : even zero

  even-suc : ∀ {n : ℕ}
    → odd n
      ------------
    → even (suc n)

data odd where
  odd-suc : ∀ {n : ℕ}
    → even n
      -----------
    → odd (suc n)

-- number is even iff it is          double some other number
even-∃ : ∀ {n : ℕ} → even n → ∃[ m ] (    m * 2 ≡ n)
-- number is odd  iff it is one plus double some other number
odd-∃  : ∀ {n : ℕ} →  odd n → ∃[ m ] (1 + m * 2 ≡ n)

even-∃  even-zero = ⟨ zero , refl ⟩
even-∃ (even-suc odd-suc-x*2)
    with odd-∃ odd-suc-x*2
... | ⟨ x , refl ⟩ = ⟨ suc x , refl ⟩
odd-∃  (odd-suc  even-x*2)
    with even-∃ even-x*2
... | ⟨ x , refl ⟩ = ⟨     x , refl ⟩

∃-even : ∀ {n : ℕ} → ∃[ m ] (    m * 2 ≡ n) → even n
∃-odd  : ∀ {n : ℕ} → ∃[ m ] (1 + m * 2 ≡ n) →  odd n

∃-even ⟨ zero  , refl ⟩ = even-zero
∃-even ⟨ suc x , refl ⟩ = even-suc (∃-odd  ⟨ x , refl ⟩)
∃-odd  ⟨     x , refl ⟩ = odd-suc  (∃-even ⟨ x , refl ⟩)

-- PLFA exercise: what if we write the arithmetic more "naturally"?
-- (Proof gets harder but is still doable).

-- 747/PLFA exercise: AltLE (3 points)
-- alternate definition of y ≤ z
-- (Optional exercise: Is this an isomorphism?)
+0 : ∀ (m : ℕ) → m + zero ≡ m
+0  zero   = refl
+0 (suc m) = cong suc (+0 m)

open import x03-842Relations-hc-2 using (s≤s)

xxx : ∀ {m n : ℕ} → m ≤ n → suc (m + zero) ≤ suc n
xxx {m} {n} p rewrite +0 m = s≤s p

≤-refl : ∀ {n : ℕ}
    -----
  → n ≤ n
≤-refl {zero}  = z≤n
≤-refl {suc n} = s≤s (≤-refl {n})

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

aaa : ∀ {x y z : ℕ} → y + suc x ≡ z → y ≤ y + suc x
--aaa {x} {y} y+sucx≡z rewrite sym y+sucx≡z {- | +-suc y x -} = {!!}
aaa {zero}  {zero}  refl = z≤n
aaa {suc x} {zero}  refl = z≤n
aaa {zero}  {suc y} refl = s≤s {!!}
aaa {suc x} {suc y} refl = s≤s {!!}

zzz : ∀ {y z : ℕ} → y + zero ≡ z → y ≤ z
zzz {y} y+x≡z rewrite +0 y | y+x≡z | sym y+x≡z = ≤-refl {y}

∃-≤ : ∀ {y z : ℕ} → ( (y ≤ z) ⇔ ( ∃[ x ] (y + x ≡ z) ) )
{-
∃-≤ {y} {z} = record { to = λ { z≤n → ⟨ zero , {!!} ⟩ ; (s≤s y≤z) → {!!} }; from = {!!} }
-}
to   ∃-≤           z≤n        = ⟨          zero  , {!!} ⟩
to   ∃-≤      (s≤s z≤n)       = ⟨      suc zero  , {!!} ⟩
to   ∃-≤ (s≤s (s≤s m≤n))      = ⟨ suc (suc zero) , {!!} ⟩
from ∃-≤ ⟨ zero  , y+zero≡z ⟩ = zzz y+zero≡z
from ∃-≤ ⟨ suc x , y+sucx≡z ⟩ rewrite sym y+sucx≡z = {!!}

-- The negation of an existential is isomorphic to a universal of a negation.
¬∃≃∀¬ : ∀ {A : Set} {B : A → Set}
  → (¬ ∃[ a ] B a) ≃ ∀ a → ¬ B a
to      ¬∃≃∀¬ = λ { ¬∃B     a → λ Ba   → ¬∃B ⟨ a , Ba ⟩ }
from    ¬∃≃∀¬ = λ { a→¬Ba ⟨ a ,   Ba ⟩ → a→¬Ba a   Ba }
from∘to ¬∃≃∀¬ = λ   ¬∃B                → {!!} -- TODO
to∘from ¬∃≃∀¬ = λ   a→¬Ba              → refl

-- 747/PLFA exercise: ExistsNegImpNegForAll (1 point)
-- Existence of negation implies negation of universal.

∃¬-implies-¬∀ : ∀ {A : Set} {B : A → Set}
  → ∃[ a ] (¬ B a)
    --------------
  → ¬ (∀ a → B a)
∃¬-implies-¬∀ ⟨ a , ¬Ba ⟩ = λ a→Ba → ¬Ba (a→Ba a)

-- The converse cannot be proved in intuitionistic logic.

-- PLFA exercise: isomorphism between naturals and existence of canonical binary.
-- This is essentially what we did at the end of 747Isomorphism.


-- Issue498: Underapplied projection-like functions did not evaluate correctly.
module Issue498 where

data ⊤ : Set where
  tt : ⊤

data C : ⊤ → Set where
  c : C tt

data C₂ : ⊤ → ⊤ → Set where
  c : C₂ tt tt

module NoParams where

  f₁ : ∀ a → C a → ⊤
  f₁ a x = tt

  f₁′ : ∀ a → C a → ⊤
  f₁′ = f₁

  check₁ : ∀ a x → C (f₁′ a x)
  check₁ s x = c

  f₂ : ∀ a b → C₂ a b → ⊤
  f₂ a b x = tt

  f₂′ : ∀ a b → C₂ a b → ⊤
  f₂′ a = f₂ a

  check₂ : ∀ a b x → C (f₂′ a b x)
  check₂ a b x = c

  f₃ : ∀ a {b} → C₂ a b → ⊤
  f₃ a x = tt

  f₃′ : ∀ a {b} → C₂ a b → ⊤
  f₃′ = f₃

  data Is-f₃ : (∀ a {b} → C₂ a b → ⊤) → Set where
    is-f₃ : Is-f₃ (λ a {b} x → tt)

  check₃ : Is-f₃ f₃′
  check₃ = is-f₃

module SomeParams (X Y : Set) where

  f₁ : ∀ a → C a → ⊤
  f₁ a x = tt

  f₁′ : ∀ a → C a → ⊤
  f₁′ = f₁

  check₁ : ∀ a x → C (f₁′ a x)
  check₁ s x = c

  f₂ : ∀ a b → C₂ a b → ⊤
  f₂ a b x = tt

  f₂′ : ∀ a b → C₂ a b → ⊤
  f₂′ a = f₂ a

  check₂ : ∀ a b x → C (f₂′ a b x)
  check₂ a b x = c

check₃ : ∀ {X Y} a x → C (SomeParams.f₁′ X Y a x)
check₃ a x = c

check₄ : ∀ {X Y} a b x → C (SomeParams.f₂′ X Y a b x)
check₄ a b x = c


-- Verify that issue 3415 has been fixed by checking that the
-- computation rule for univalence holds up to a trivial transport (it
-- used to only hold up to a more complicated argument).
{-# OPTIONS --cubical #-}
module Issue3415 where

open import Agda.Primitive.Cubical public
open import Agda.Builtin.Cubical.Path public
open import Agda.Builtin.Cubical.Glue public
open import Agda.Builtin.Sigma public

idIsEquiv : ∀ {ℓ} (A : Set ℓ) → isEquiv (λ (x : A) → x)
equiv-proof (idIsEquiv A) y =
  ((y , λ _ → y) , λ z i → z .snd (primINeg i)
  , λ j → z .snd (primIMax (primINeg i) j))

idEquiv : ∀ {ℓ} (A : Set ℓ) → A ≃ A
idEquiv A = ((λ x → x) , idIsEquiv A)

ua : ∀ {ℓ} {A B : Set ℓ} → A ≃ B → A ≡ B
ua {A = A} {B = B} e i =
  primGlue B (λ { (i = i0) → A ; (i = i1) → B })
             (λ { (i = i0) → e ; (i = i1) → (idEquiv B) })

transport : ∀ {ℓ} {A B : Set ℓ} → A ≡ B → A → B
transport p a = primTransp (λ i → p i) i0 a

transportRefl : ∀ {ℓ}  {A : Set ℓ} → (x : A) → transport (λ _ → A) x ≡ x
transportRefl {A = A} x i = primTransp (λ _ → A) i x

uaβ : ∀ {ℓ} {A B : Set ℓ} (e : A ≃ B) (x : A) → transport (ua e) x ≡ e .fst x
uaβ e x = transportRefl (e .fst x)


{-# OPTIONS --type-in-type #-}

-- Yeah, that's type-in-type. I'm a sissy, I want to use the stdlib, I
-- don't want to reimplement ℕ, ⊤, etc. in Set1.

module ILabel where

open import Data.String

open import Data.Empty
open import Data.Unit

open import Data.Product

open import Data.Maybe
open import Data.Nat

open import Relation.Binary.PropositionalEquality

--****************************************************************
-- A universe of labels
--****************************************************************

infixr 5 _∷_

data AllowedBy : Set -> Set where
  ε    : forall {T} ->
         AllowedBy T
  _∷_  : {S : Set}{T : S -> Set} ->
         (s : S)(ts : AllowedBy (T s)) -> AllowedBy ((x : S) -> T x)

UId = String

-- The universe (that's a tiny one):

data Label : Set where
  label : (u : UId)(T : Set)(ts : AllowedBy T) -> Label

--****************************************************************
-- IDesc & co.
--****************************************************************

data IDesc (I : Set1) : Set1 where
  var    : I -> IDesc I
  const  : Set -> IDesc I
  prod   : IDesc I -> IDesc I -> IDesc I
  sigma  : (S : Set) -> (S -> IDesc I) -> IDesc I
  pi     : (S : Set) -> (S -> IDesc I) -> IDesc I

desc : {I : Set1} -> IDesc I -> (I -> Set) -> Set
desc (var i) P = P i
desc (const X) P = X
desc (prod D D') P = desc D P × desc D' P
desc (sigma S T) P = Σ S (\s -> desc (T s) P)
desc (pi S T) P = (s : S) -> desc (T s) P

-- We (may) stuck a label on the fix-point:

data IMu {I : Set1}(L : Maybe (I -> Label))(R : I -> IDesc I)(i : I) : Set where
  con : desc (R i) (\j -> IMu L R j) -> IMu L R i

--****************************************************************
-- Example: Nat
--****************************************************************

data NatConst : Set where
  Ze : NatConst
  Su : NatConst

natCases : NatConst -> IDesc ⊤
natCases Ze = const ⊤
natCases Suc = var _

NatD : ⊤ → IDesc ⊤
NatD _ = sigma NatConst natCases

Nat : Set
Nat = IMu (just (\ _ -> label "Nat" Set ε)) NatD _

--****************************************************************
-- Example: Vector
--****************************************************************

data VecConst : ℕ -> Set where
  Vnil : VecConst 0
  Vcons : {n : ℕ} -> VecConst (1 + n)

vecDChoice : Set -> (n : ℕ) -> VecConst n -> IDesc ℕ
vecDChoice X 0 Vnil = const ⊤
vecDChoice X (suc n) Vcons = prod (const X) (var n)

vecD : Set -> ℕ -> IDesc ℕ
vecD X n = sigma (VecConst n) (vecDChoice X n)

vec : Set -> ℕ -> Set
vec X n = IMu (just (\n -> label "Vec" (ℕ -> Set) (n ∷ ε))) (vecD X) n

--****************
-- Example: Fin
--****************

data FinConst : ℕ -> Set where
  Fz : {n : ℕ} -> FinConst (1 + n)
  Fs : {n : ℕ} -> FinConst (1 + n)

finDChoice : (n : ℕ) -> FinConst n -> IDesc ℕ
finDChoice 0 ()
finDChoice (suc n) Fz = const ⊤
finDChoice (suc n) Fs = var n

finD : ℕ -> IDesc ℕ
finD n = sigma (FinConst n) (finDChoice n)

fin : ℕ -> Set
fin n = IMu (just (\ n -> label "Fin" (ℕ -> Set) (n ∷ ε))) finD n

--****************
-- Example: Identity type
--****************

-- data Id (A : Set) (a : A) : A -> Set := (refl : Id A a a)

data IdConst : Set where
  Refl : IdConst

idD : (A : Set)(a : A)(b : A) -> IDesc A
idD A a b = sigma IdConst (\ _ -> const (a ≡ b))

id : (A : Set)(a : A)(b : A) -> Set
id A a b = IMu (just (\ b -> label "Id" ((A : Set)(a : A)(b : A) -> Set) (A ∷ a ∷ b ∷ ε))) (idD A a) b


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

module Data.Nat.Base where

open import Agda.Builtin.Nat public
  using (_+_; _*_; zero; suc)
  renaming (Nat to ℕ; _-_ to _∸_)
import Agda.Builtin.Nat as Nat

open import Level
open import Data.Bool

data Ordering : ℕ → ℕ → Type₀ where
  less    : ∀ m k → Ordering m (suc (m + k))
  equal   : ∀ m   → Ordering m m
  greater : ∀ m k → Ordering (suc (m + k)) m

compare : ∀ m n → Ordering m n
compare zero    zero    = equal   zero
compare (suc m) zero    = greater zero m
compare zero    (suc n) = less    zero n
compare (suc m) (suc n) with compare m n
... | less    m k = less (suc m) k
... | equal   m   = equal (suc m)
... | greater n k = greater (suc n) k

nonZero : ℕ → Bool
nonZero (suc _) = true
nonZero zero    = false

_÷_ : (n m : ℕ) → { m≢0 : T (nonZero m) } → ℕ
_÷_ n (suc m) = Nat.div-helper 0 m n m

rem : (n m : ℕ) → { m≢0 : T (nonZero m) } → ℕ
rem n (suc m) = Nat.mod-helper 0 m n m


open import Oscar.Prelude
open import Oscar.Class.IsPrecategory
open import Oscar.Class.Surjection
open import Oscar.Class.Smap
open import Oscar.Class.Surjtranscommutativity
open import Oscar.Class.Surjextensionality
open import Oscar.Class.Transitivity

module Oscar.Class.IsPrefunctor where

module _
  {𝔬₁} {𝔒₁ : Ø 𝔬₁}
  {𝔯₁} (_∼₁_ : 𝔒₁ → 𝔒₁ → Ø 𝔯₁)
  {ℓ₁} (_∼̇₁_ : ∀ {x y} → x ∼₁ y → x ∼₁ y → Ø ℓ₁)
  (_↦₁_ : Transitivity.type _∼₁_)
  {𝔬₂} {𝔒₂ : Ø 𝔬₂}
  {𝔯₂} (_∼₂_ : 𝔒₂ → 𝔒₂ → Ø 𝔯₂)
  {ℓ₂} (_∼̇₂_ : ∀ {x y} → x ∼₂ y → x ∼₂ y → Ø ℓ₂)
  (_↦₂_ : Transitivity.type _∼₂_)
  {surjection : Surjection.type 𝔒₁ 𝔒₂}
  (smap : Smap.type _∼₁_ _∼₂_ surjection surjection)
  where
  record IsPrefunctor : Ø 𝔬₁ ∙̂ 𝔯₁ ∙̂ ℓ₁ ∙̂ 𝔬₂ ∙̂ 𝔯₂ ∙̂ ℓ₂ where
    constructor ∁
    field
      overlap ⦃ `IsPrecategory₁ ⦄ : IsPrecategory _∼₁_ _∼̇₁_ _↦₁_
      overlap ⦃ `IsPrecategory₂ ⦄ : IsPrecategory _∼₂_ _∼̇₂_ _↦₂_
      overlap ⦃ `𝓢urjtranscommutativity ⦄ : Surjtranscommutativity.class _∼₁_ _∼₂_ _∼̇₂_ smap _↦₁_ _↦₂_
      ⦃ `𝓢urjextensionality ⦄ : Surjextensionality.class _∼₁_ _∼̇₁_ _∼₂_ _∼̇₂_ surjection smap


open import Relation.Nullary.Decidable using (False; map)
open import Relation.Nullary.Negation using (contradiction)
open import Relation.Binary using (Decidable)
open import Relation.Binary.PropositionalEquality using (_≡_; _≢_; refl; sym; cong; module ≡-Reasoning)
open ≡-Reasoning
open import Function.Equivalence as FE using ()

open import Data.Unit using (⊤; tt)
open import Agda.Builtin.FromNat using (Number)

module AKS.Modular.Quotient.Base where

open import AKS.Nat using (ℕ; zero; suc; _<_; _∸_) renaming (_+_ to _+ℕ_; _*_ to _*ℕ_; _≟_ to _≟ℕ_)
open import AKS.Nat using (≢⇒¬≟; ∸-mono-<ʳ; 0<1+n; <⇒≤; <-irrelevant; 0≢⇒0<)
open import AKS.Nat.Divisibility using (_%_; n%m<m; 0%m≡0; 1%m≡1; [m+kn]%n≡m%n; m%n%n≡m%n; %-distribˡ-+; %-distribˡ-*)
open import AKS.Nat.GCD using (+ʳ; +ˡ)
open import AKS.Primality using (IsPrime; Prime; prime≢0; bézout-prime)
open Prime

record ℤ/[_] (P : Prime) : Set where
  constructor ℤ✓
  field
    mod : ℕ
    mod<p : mod < prime P
open ℤ/[_] public

module Operations {P : Prime} where
  open Prime P using () renaming (prime to p; isPrime to p-isPrime)
  open IsPrime p-isPrime using (1<p)

  p≢0 : False (p ≟ℕ 0)
  p≢0 = ≢⇒¬≟ (prime≢0 p-isPrime)

  [_] : ℕ → ℤ/[ P ]
  [ n ] = ℤ✓ ((n % p) {p≢0}) (n%m<m n p)

  instance
    ℤ/[]-number : Number (ℤ/[ P ])
    ℤ/[]-number = record
      { Constraint = λ _ → ⊤
      ; fromNat = λ n → [ n ]
      }

  infixl 6 _+_
  _+_ : ℤ/[ P ] → ℤ/[ P ] → ℤ/[ P ]
  n + m = [ mod n +ℕ mod m ]

  infix 8 -_
  -_ : ℤ/[ P ] → ℤ/[ P ]
  - (ℤ✓ zero    0<p) = ℤ✓ zero  0<p
  - (ℤ✓ (suc n) 1+n<p) = ℤ✓ (p ∸ suc n) (∸-mono-<ʳ (<⇒≤ 1+n<p) 0<1+n)

  infixl 7 _*_
  _*_ : ℤ/[ P ] → ℤ/[ P ] → ℤ/[ P ]
  n * m = [ mod n *ℕ mod m ]

  ℤ/[]-irrelevance : ∀ {x y : ℤ/[ P ]} → mod x ≡ mod y → x ≡ y
  ℤ/[]-irrelevance {ℤ✓ mod[x] mod[x]<p} {ℤ✓ .mod[x] mod[y]<p} refl = cong (λ z<p → ℤ✓ mod[x] z<p) (<-irrelevant mod[x]<p mod[y]<p)

  n≢0⇒mod[n]≢0 : ∀ {n} → n ≢ 0 → mod n ≢ 0
  n≢0⇒mod[n]≢0 {ℤ✓ zero _} n≢0 = contradiction (ℤ/[]-irrelevance (sym (0%m≡0 p))) n≢0
  n≢0⇒mod[n]≢0 {ℤ✓ (suc n) _} n≢0 = λ ()

  bézout-x∤p : ∀ n x y → 1 +ℕ x *ℕ n ≡ y *ℕ p → 0 ≢ (x % p) {p≢0}
  bézout-x∤p n x y 1+x*n≡y*p 0≡x%p = contradiction 1≡0 (λ ())
    where
    1≡0 : 1 ≡ zero
    1≡0 = begin
      1 ≡⟨ sym (1%m≡1 1<p) ⟩
      (1 +ℕ 0 *ℕ n) % p ≡⟨ cong (λ t → ((1 +ℕ t *ℕ n) % p) {p≢0}) 0≡x%p ⟩
      (1 +ℕ (x % p) *ℕ n) % p ≡⟨ %-distribˡ-+ 1 ((x % p) *ℕ n) p ⟩
      (1 % p +ℕ ((x % p) *ℕ n) % p) % p ≡⟨ cong (λ t → ((1 % p +ℕ t) % p) {p≢0}) (%-distribˡ-* (x % p) n p) ⟩
      (1 % p +ℕ ((x % p % p) *ℕ (n % p)) % p) % p ≡⟨ cong (λ t → (1 % p +ℕ (t *ℕ (n % p)) % p) % p) (m%n%n≡m%n x p) ⟩
      (1 % p +ℕ ((x % p) *ℕ (n % p)) % p) % p ≡⟨ cong (λ t → (1 % p +ℕ t) % p) (sym (%-distribˡ-* x n p)) ⟩
      (1 % p +ℕ (x *ℕ n) % p) % p ≡⟨ sym (%-distribˡ-+ 1 (x *ℕ n) p) ⟩
      (1 +ℕ x *ℕ n) % p ≡⟨ cong (λ t → (t % p) {p≢0}) 1+x*n≡y*p ⟩
      (y *ℕ p) % p ≡⟨ [m+kn]%n≡m%n 0 y p {p≢0} ⟩
      0 % p ≡⟨ 0%m≡0 p ⟩
      0 ∎

  -- x⁻¹ * x - 1 ≡ z * p
  infix 8 _⁻¹
  _⁻¹ : ∀ (n : ℤ/[ P ]) {n≢0 : n ≢ 0} → ℤ/[ P ]
  (n ⁻¹) {n≢0} with bézout-prime (mod n) p (n≢0⇒mod[n]≢0 n≢0) (mod<p n) p-isPrime
  ... | +ʳ x y 1+x*n≡y*p = ℤ✓ (p ∸ (x % p) {p≢0}) (∸-mono-<ʳ (<⇒≤ (n%m<m x p)) (0≢⇒0< (bézout-x∤p (mod n) x y 1+x*n≡y*p)))
  ... | +ˡ x y 1+y*p≡x*n = [ x ]

  infixl 7 _/_
  _/_ : ∀ (n m : ℤ/[ P ]) {m≢0 : m ≢ 0} → ℤ/[ P ]
  (n / m) {m≢0} = n * (m ⁻¹) {m≢0}

  _≟_ : Decidable {A = ℤ/[ P ]} _≡_
  ℤ✓ x x<p ≟ ℤ✓ y y<p = map (FE.equivalence ℤ/[]-irrelevance (λ { refl → refl })) (x ≟ℕ y)

open Operations public


{-# OPTIONS --safe --experimental-lossy-unification #-}
module Cubical.ZCohomology.RingStructure.CohomologyRingFun where

{-
   There is two definitionof the Cohomology Ring.
   We recommend to use the HIT definition (the other one)
   as the ring product is eaiser to handle.
   Nevertheless the equality is harder to handle so
   this definition can interessting too.
-}

open import Cubical.Foundations.Prelude

open import Cubical.Relation.Nullary

open import Cubical.Data.Empty as ⊥
open import Cubical.Data.Nat renaming (_+_ to _+ℕ_)
open import Cubical.Data.Nat.Order
open import Cubical.Data.Sigma

open import Cubical.Algebra.Monoid
open import Cubical.Algebra.Ring
open import Cubical.Algebra.GradedRing.DirectSumFun

open import Cubical.ZCohomology.Base
open import Cubical.ZCohomology.GroupStructure
open import Cubical.ZCohomology.RingStructure.CupProduct
open import Cubical.ZCohomology.RingStructure.RingLaws
open import Cubical.ZCohomology.RingStructure.GradedCommutativity

private variable
  ℓ ℓ' : Level

open PlusBis

module _ (A : Type ℓ) where

  H*FunR : Ring ℓ
  H*FunR = ⊕FunGradedRing-Ring
           _+'_ (makeIsMonoid isSetℕ +'-assoc +'-rid +'-lid)
           +'≡+
           (λ k → coHom k A)
           (λ k → snd (coHomGroup k A))
           1⌣
           _⌣_
           (λ {k} {l} → 0ₕ-⌣ k l)
           (λ {k} {l} → ⌣-0ₕ k l)
           (λ _ _ _ → sym (ΣPathTransport→PathΣ _ _ ((sym (+'-assoc _ _ _)) , (sym (assoc-⌣ _ _ _ _ _ _)))))
           (λ _ → sym (ΣPathTransport→PathΣ _ _ (sym (+'-rid _) , sym (lUnit⌣ _ _))))
           (λ _ → ΣPathTransport→PathΣ _ _ (refl , transportRefl _ ∙ rUnit⌣ _ _))
           (λ _ _ _ → leftDistr-⌣ _ _ _ _ _)
           λ _ _ _ → rightDistr-⌣ _ _ _ _ _

  H*Fun : Type ℓ
  H*Fun = fst H*FunR


open import Prelude
open import Nat
open import core
open import contexts

module lemmas-env where
  env-ctx-same-1 : ∀{Δ Σ' Γ E x} →
                     Δ , Σ' , Γ ⊢ E →
                     x # E →
                     x # Γ
  env-ctx-same-1 EnvId h = x#∅
  env-ctx-same-1 {x = x} (EnvInd {E = E} {x = x'} ctxcons _) x#E+
    with natEQ x x'
  ... | Inl refl = abort (x#E+ (_ , x,a∈Γ,,x,a {Γ = E}))
  ... | Inr x≠x'
    with env-ctx-same-1 ctxcons (x#Γ+→x#Γ {Γ = E} x#E+)
  ... | x#Γ = x#Γ→x#Γ+ x≠x' x#Γ

  env-ctx-same-2 : ∀{Δ Σ' Γ E x} →
                     Δ , Σ' , Γ ⊢ E →
                     x # Γ →
                     x # E
  env-ctx-same-2 EnvId h = x#∅
  env-ctx-same-2 {x = x} (EnvInd {Γ = Γ} {x = x'} ctxcons _) x#Γ+
    with natEQ x x'
  ... | Inl refl = abort (x#Γ+ (_ , x,a∈Γ,,x,a {Γ = Γ}))
  ... | Inr x≠x'
    with env-ctx-same-2 ctxcons (x#Γ+→x#Γ {Γ = Γ} x#Γ+)
  ... | x#E = x#Γ→x#Γ+ x≠x' x#E

  env-all-Γ : ∀{Δ Σ' Γ E x τ} →
                Δ , Σ' , Γ ⊢ E →
                (x , τ) ∈ Γ →
                Σ[ r ∈ result ] ((x , r) ∈ E ∧ Δ , Σ' ⊢ r ·: τ)
  env-all-Γ EnvId x∈Γ = abort (x#∅ (_ , x∈Γ))
  env-all-Γ {x = x} (EnvInd {Γ = Γ} {E} {x'} ctxcons ta) x∈Γ
    with natEQ x x'
  ... | Inl refl
          rewrite ctxunicity x∈Γ (x,a∈Γ,,x,a {Γ = Γ})
            = _ , x,a∈Γ,,x,a {Γ = E} , ta
  ... | Inr x≠x'
    with env-all-Γ ctxcons (x∈Γ+→x∈Γ {Γ = Γ} x≠x' x∈Γ)
  ... | _ , x∈E , ta-rec = _ , x∈Γ→x∈Γ+ x≠x' x∈E , ta-rec

  env-all-E : ∀{Δ Σ' Γ E x r} →
                Δ , Σ' , Γ ⊢ E →
                (x , r) ∈ E →
                Σ[ τ ∈ typ ] ((x , τ) ∈ Γ ∧ Δ , Σ' ⊢ r ·: τ)
  env-all-E EnvId x∈E = abort (x#∅ (_ , x∈E))
  env-all-E {x = x} (EnvInd {Γ = Γ} {E} {x'} ctxcons ta) x∈E
    with natEQ x x'
  ... | Inl refl
          rewrite ctxunicity x∈E (x,a∈Γ,,x,a {Γ = E})
            = _ , x,a∈Γ,,x,a {Γ = Γ} , ta
  ... | Inr x≠x'
    with env-all-E ctxcons (x∈Γ+→x∈Γ {Γ = E} x≠x' x∈E)
  ... | _ , x∈Γ , ta-rec = _ , x∈Γ→x∈Γ+ x≠x' x∈Γ , ta-rec


{-# OPTIONS --copatterns --sized-types #-}

open import Function
open import Data.Unit as Unit renaming (tt to ∗)
open import Data.List as List

TyCtx = List ⊤

data TyVar : (Γ : TyCtx) → Set where
  zero : ∀{Γ}                          → TyVar (∗ ∷ Γ)
  succ : ∀{Γ} → (x : TyVar Γ) → TyVar (∗ ∷ Γ)

data Type (Γ : TyCtx) : Set where
  unit :                                     Type Γ
  var  : (x : TyVar Γ)                     → Type Γ
  _⊕_  : (t₁ : Type Γ)       (t₂ : Type Γ) → Type Γ
  μ    : (t : Type (_ ∷ Γ))                → Type Γ
  _⊗_  : (t₁ : Type Γ)       (t₂ : Type Γ) → Type Γ
  _⇒_  : (t₁ : Type [])      (t₂ : Type Γ) → Type Γ
  ν    : (t : Type (_ ∷ Γ))                → Type Γ

-- | Variable renaming in types
_▹_ : (Γ Δ : TyCtx) → Set
Γ ▹ Δ = TyVar Γ → TyVar Δ

{-
rename : {Γ Δ : TyCtx} → (ρ : Γ ▹ Δ) → Type Γ → Type Δ
rename         ρ unit      = unit
rename         ρ (var x)   = var (ρ ∗ x)
rename         ρ (t₁ ⊕ t₂) = rename ρ t₁ ⊕ rename ρ t₂
rename {Γ} {Δ} ρ (μ t)     = μ (rename ρ' t)
  where
    ρ' : (∗ ∷ Γ) ▹ (∗ ∷ Δ)
    ρ' = ?
    -- ρ' = id {[ ∗ ]} ⧻ ρ
rename         ρ (t₁ ⊗ t₂) = rename ρ t₁ ⊗ rename ρ t₂
rename         ρ (t₁ ⇒ t₂) = t₁ ⇒ rename ρ t₂
rename {Γ} {Δ} ρ (ν t)     = ν (rename ρ' t)
  where
    ρ' : (∗ ∷ Γ) ▹ (∗ ∷ Δ)
    ρ' = ?
--    ρ' = ctx-id {[ ∗ ]} ⧻ ρ

-------------------------
---- Generating structure on contexts (derived from renaming)

weaken : {Γ : TyCtx} (Δ : TyCtx) → Type Γ -> Type (Δ ++ Γ)
weaken {Γ} Δ = rename {Γ} {Δ ++ Γ} ?

exchange : (Γ Δ : TyCtx) → Type (Γ ++ Δ) -> Type (Δ ++ Γ)
exchange Γ Δ = rename [ i₂ {Δ} {Γ} , i₁ {Δ} {Γ} ]

contract : {Γ : TyCtx} → Type (Γ ∐ Γ) -> Type Γ
contract = rename [ ctx-id , ctx-id ]

-}

Subst : TyCtx → TyCtx → Set
Subst Γ Δ = TyVar Γ → Type Δ

update : ∀{Γ Δ : TyCtx} → Subst Γ Δ → Type Δ → (Subst (∗ ∷ Γ) Δ)
update σ a zero        = a
update σ _ (succ x) = σ x

lift : ∀{Γ Δ} → Subst Γ Δ → Subst (∗ ∷ Γ) (∗ ∷ Δ)
lift σ zero = {!!}
lift σ (succ x) = {!!}

-- | Simultaneous substitution
subst : {Γ Δ : TyCtx} → (σ : Subst Γ Δ) → Type Γ → Type Δ
subst         σ unit      = unit
subst         σ (var x)   = σ x
subst         σ (t₁ ⊕ t₂) = subst σ t₁ ⊕ subst σ t₂
subst {Γ} {Δ} σ (μ t)     = μ (subst (lift σ) t)
subst         σ (t₁ ⊗ t₂) = subst σ t₁ ⊗ subst σ t₂
subst         σ (t₁ ⇒ t₂) = t₁ ⇒ subst σ t₂
subst {Γ} {Δ} σ (ν t)     = ν (subst (lift σ) t)

data Term : Set where


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

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

module Graphs.UnionGraph where

unionGraph : {a b c d e f : _} {V' : Set a} {V : Setoid {a} {b} V'} (G : Graph c V) {W' : Set d} {W : Setoid {d} {e} W'} (H : Graph f W) → Graph (c ⊔ f) (directSumSetoid V W)
Graph._<->_ (unionGraph {c = c} {f = f} G H) (inl v) (inl v2) = embedLevel {c} {f} (Graph._<->_ G v v2)
Graph._<->_ (unionGraph G H) (inl v) (inr w) = False'
Graph._<->_ (unionGraph G H) (inr w) (inl v) = False'
Graph._<->_ (unionGraph {c = c} {f = f} G H) (inr w) (inr w2) = embedLevel {f} {c} (Graph._<->_ H w w2)
Graph.noSelfRelation (unionGraph G H) (inl v) (v=v ,, _) = Graph.noSelfRelation G v v=v
Graph.noSelfRelation (unionGraph G H) (inr w) (w=w ,, _) = Graph.noSelfRelation H w w=w
Graph.symmetric (unionGraph G H) {inl x} {inl y} (x=y ,, _) = Graph.symmetric G x=y ,, record {}
Graph.symmetric (unionGraph G H) {inr x} {inr y} (x=y ,, _) = Graph.symmetric H x=y ,, record {}
Graph.wellDefined (unionGraph G H) {inl x} {inl y} {inl z} {inl w} (x=y ,, _) (y=z ,, _) (z=w ,, _) = Graph.wellDefined G x=y y=z z=w ,, record {}
Graph.wellDefined (unionGraph G H) {inr x} {inr y} {inr z} {inr w} (x=y ,, _) (y=z ,, _) (z=w ,, _) = Graph.wellDefined H x=y y=z z=w ,, record {}


{-# OPTIONS --prop #-}

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

postulate
  A : Set
  P : Prop
  p : P
  u : P → A

f : {x : A} (q : u p ≡ x) → P
f refl = p   -- works in 2.6.0.1


{-# OPTIONS --safe --without-K #-}
module Categories.Examples.Monad.Duration where

-- Monad induced by pairing a Monoid and a Setoid
open import Level

open import Function.Base using (_-⟪_⟫-_; _on_; _∘_) renaming (id to id→)
open import Function.Equality using (Π; _⟨$⟩_; cong)

open import Relation.Binary
open import Relation.Binary.Indexed.Heterogeneous.Construct.Trivial

open import Data.Product using (Σ; _,_; _×_; proj₁; proj₂; dmap′; zip; map₁; map₂)
open import Algebra using (Monoid)

open import Categories.Category
open import Categories.Category.Instance.Setoids
open import Categories.Functor renaming (id to idF)
open import Categories.NaturalTransformation using (NaturalTransformation; ntHelper)
open import Categories.Monad using (Monad)

open import Data.Nat.Properties renaming (+-0-monoid to +-0-nat-monoid)
open import Data.Integer.Properties renaming (+-0-monoid to +-0-integer-monoid)
open import Data.Rational.Properties renaming (+-0-monoid to +-0-rational-monoid)

open Monoid public

monoid×-₀ : ∀ {l₁ l₂ e₁ e₂} → Monoid l₁ e₁ → Setoid l₂ e₂ → Setoid _ _
monoid×-₀ m s = record
  { Carrier = m.Carrier × s.Carrier
  ; _≈_ = m._≈_ on proj₁ -⟪ _×_ ⟫- s._≈_ on proj₂
  ; isEquivalence = record
      { refl = m.refl , s.refl
      ; sym = dmap′ m.sym s.sym
      ; trans = zip m.trans s.trans
      }
  }
  where
    module m = Monoid m
    module s = Setoid s

monoid×-₁ : ∀ {l₁ l₂ e₁ e₂} {A B : Setoid l₂ e₂} → (m : Monoid l₁ e₁) → (f : Setoids l₂ e₂ [ A , B ]) → Setoids _ _ [ monoid×-₀ m A , monoid×-₀ m B ]
monoid×-₁ _ f = record
  { _⟨$⟩_ = map₂ (_⟨$⟩_ f)
  ; cong = map₂ (cong f)
  }

-- levels have to be the same because everything gets put into the same stop
monoid×-endo : ∀ {l₁ e₁} → Monoid l₁ e₁ → Endofunctor (Setoids l₁ e₁)
monoid×-endo m =  record
  { F₀ = monoid×-₀ m
  ; F₁ = monoid×-₁ m
  ; identity = id→
  ; homomorphism = λ {_} {_} {_} {f} {g} p → map₂ (cong g ∘ cong f) p
  ; F-resp-≈ = λ f → map₂ f
  }

monoid×-η : ∀ {l e} → (m : Monoid l e) → NaturalTransformation idF (monoid×-endo m)
monoid×-η m = ntHelper record
  { η = λ _ → record { _⟨$⟩_ = m.ε ,_ ; cong = m.refl ,_ }
  ; commute = λ f x → m.refl , cong f x
  }
  where module m = Monoid m

monoid×-μ : ∀ {l} → (m : Monoid l l) → NaturalTransformation (monoid×-endo m ∘F monoid×-endo m) (monoid×-endo m)
monoid×-μ m = ntHelper record
  { η = λ X → record
    { _⟨$⟩_ =  λ { (d , d₁ , value) → ( d m.∙ d₁) , value }
    ; cong = λ { (d , d₁ , v) → m.∙-cong d d₁ , v }
    }
  ; commute = λ { f (d , d₁ , v) → m.∙-cong d d₁ , cong f v }
  }
  where
    module m = Monoid m

monoid×-monad : ∀ {l} → Monoid l l → Monad (Setoids l l)
monoid×-monad m = record
  { F = monoid×-endo m
  ; η = monoid×-η m
  ; μ = monoid×-μ m
  ; assoc     = λ (p₀ , p₁ , p₂ , p₃) → m.trans (m.∙-cong p₀ (m.∙-cong p₁ p₂)) (m.sym (m.assoc _ _ _)) , p₃
  ; sym-assoc = λ (p₀ , p₁ , p₂ , p₃) → m.trans (m.∙-cong (m.∙-cong p₀ p₁) p₂) (      (m.assoc _ _ _)) , p₃
  ; identityˡ  = λ p → map₁ (m.trans (m.identityʳ _)) p
  ; identityʳ  = λ p → map₁ (m.trans (m.identityˡ _)) p
  }
  where module m = Monoid m

natDuration : Monad (Setoids 0ℓ 0ℓ)
natDuration = monoid×-monad +-0-nat-monoid

integerDuration : Monad (Setoids 0ℓ 0ℓ)
integerDuration = monoid×-monad +-0-integer-monoid

rationalDuration : Monad (Setoids 0ℓ 0ℓ)
rationalDuration = monoid×-monad +-0-rational-monoid


module Categories.Products where

open import Library renaming (_×_ to Pair) hiding ([_])
open import Categories

_×_ : ∀{l l' m m'}(C : Cat {l}{m})(D : Cat {l'}{m'}) -> Cat
C × D = record
          { Obj  = Pair (Obj C) (Obj D)
          ; Hom  = λ {(X , X') (Y , Y') -> Pair (Hom C X Y) (Hom D X' Y')}
          ; iden = iden C , iden D
          ; comp = λ {(f , f') (g , g') -> comp C f g , comp D f' g'}
          ; idl  = cong₂ _,_ (idl C) (idl D)
          ; idr  = cong₂ _,_ (idr C) (idr D)
          ; ass  = cong₂ _,_ (ass C) (ass D)
          } where open Cat

infixr 50 _×_

record Prod {l}{m}(C : Cat {l}{m})(A : Cat.Obj C)(B : Cat.Obj C) : Set (l ⊔ m)
  where
  constructor prod
  open Cat C
  field Pr : Obj
        π₁ : Hom Pr A
        π₂ : Hom Pr B
        [_,_] : ∀{C} → Hom C A → Hom C B → Hom C Pr
        law1 : ∀{C}{f : Hom C A}{g} → comp π₁ [ f , g ] ≅ f
        law2 : ∀{C}{f : Hom C A}{g} → comp π₂ [ f , g ] ≅ g
        law3 : ∀{C}{f : Hom C A}{g : Hom C B}{h : Hom C Pr} →
               comp π₁ h ≅ f → comp π₂ h ≅ g → h ≅ [ f , g ]


module Dipsy.Example.CLL where

open import Data.Nat using (ℕ)
open import Data.Vec using (Vec; _∷_; [])
open import Dipsy.Polarity using (Polarity; flip) renaming (pos to +; neg to -)

mutual
  Op₀ : (r : Polarity) → Set
  Op₀ r = Op [] r
  Op₁ : (a r : Polarity) → Set
  Op₁ a r = Op (a ∷ []) r
  Op₂ : (a₁ a₂ r : Polarity) → Set
  Op₂ a₁ a₂ r = Op (a₁ ∷ a₂ ∷ []) r

  data Op : {n : ℕ} → Vec Polarity n → Polarity → Set where
    ″⊥″ : Op₀ -
    ″𝟏″ : Op₀ +
    ″⊤″ : Op₀ -
    ″𝟎″ : Op₀ +
    ″¬″ : {p : Polarity} → Op₁ (flip p) p
    ″⅋″ : Op₂ - - -
    ″⊗″ : Op₂ + + +
    ″&″ : Op₂ - - -
    ″⊕″ : Op₂ + + +

open import Dipsy.Base Op Op

pattern ⊥ = op ″⊥″ []
pattern 𝟏 = op ″𝟏″ []
pattern ⊤ = op ″⊤″ []
pattern 𝟎 = op ″𝟎″ []
pattern ¬_ A = op ″¬″ (A ∷ [])
pattern _⅋_ A B = op ″⅋″ (A ∷ B ∷ [])
pattern _⊗_ A B = op ″⊗″ (A ∷ B ∷ [])
pattern _&_ A B = op ″&″ (A ∷ B ∷ [])
pattern _⊕_ A B = op ″⊕″ (A ∷ B ∷ [])


module Syntax.Implication.Dependent where

open import Functional using (id)
open import Functional.Dependent
import      Lvl
open import Type

private variable ℓ₁ ℓ₂ ℓ₃ ℓ₄ : Lvl.Level

_⇒-[_]_ : ∀(X : Type{ℓ₁}){Y : ∀{_ : X} → Type{ℓ₂}}{Z : ∀{x : X}{_ : Y{x}} → Type{ℓ₃}} → (P : (x : X) → Y{x}) → (∀{x : X} → (y : Y{x}) → Z{x}{y}) → ((x : X) → Z{x}{P(x)})
_⇒-[_]_ = const(swap(_∘_))
infixr 0.98 _⇒-[_]_
{-# INLINE _⇒-[_]_ #-}

_⇒-[]_ : ∀(X : Type{ℓ₁}){Y : ∀{_ : X} → Type{ℓ₂}} → ((x : X) → Y{x}) → ((x : X) → Y{x})
_⇒-[]_ = const id
infixr 0.98 _⇒-[]_
{-# INLINE _⇒-[]_ #-}

_⇒-end : ∀(X : Type{ℓ₁}) → (X → X)
_⇒-end = const id
infixr 0.99 _⇒-end
{-# INLINE _⇒-end #-}

_⇒_ = apply
infixl 0.97 _⇒_
{-# INLINE _⇒_ #-}

-- TODO: Change these to be similar to the ones in Syntax.Implication
•_⇒₁_ = apply
infixl 0.97 •_⇒₁_
{-# INLINE •_⇒₁_ #-}

•_•_⇒₂_ : ∀{X : Type{ℓ₁}}{Y : ∀{_ : X} → Type{ℓ₂}}{Z : ∀{x : X}{_ : Y{x}} → Type{ℓ₃}} → (x : X) → (y : Y{x}) → ((x : X) → (y : Y{x}) → Z{x}{y}) → Z{x}{y}
• a • b ⇒₂ P = P ⇒ apply a ⇒ apply b
infixl 0.97 •_•_⇒₂_
{-# INLINE •_•_⇒₂_ #-}

•_•_•_⇒₃_ : ∀{X : Type{ℓ₁}}{Y : ∀{_ : X} → Type{ℓ₂}}{Z : ∀{x : X}{_ : Y{x}} → Type{ℓ₃}}{W : ∀{x : X}{y : Y{x}}{_ : Z{x}{y}} → Type{ℓ₄}} → (x : X) → (y : Y{x}) → (z : Z{x}{y}) → ((x : X) → (y : Y{x}) → (z : Z{x}{y}) → W{x}{y}{z}) → W{x}{y}{z}
• a • b • c ⇒₃ P = P ⇒ apply a ⇒ apply b ⇒ apply c
infixl 0.97 •_•_•_⇒₃_
{-# INLINE •_•_•_⇒₃_ #-}


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

open import Level

open import Relation.Binary using (Rel; IsEquivalence)
open import Data.Sum
open import Data.Product
open import Function using (flip)

open import Categories.Category
open import Categories.Functor hiding (equiv; assoc; identityˡ; identityʳ; ∘-resp-≡) renaming (id to idF; _≡_ to _≡F_; _∘_ to _∘F_)
open import Categories.NaturalTransformation hiding (equiv; setoid) renaming (id to idT; _≡_ to _≡T_)
open import Categories.Monad
open import Categories.Support.Equivalence

record Adjunction {o ℓ e} {o₁ ℓ₁ e₁} {C : Category o ℓ e} {D : Category o₁ ℓ₁ e₁} (F : Functor D C) (G : Functor C D) : Set (o ⊔ ℓ ⊔ e ⊔ o₁ ⊔ ℓ₁ ⊔ e₁) where
  field
    unit   : NaturalTransformation idF (G ∘F F)
    counit : NaturalTransformation (F ∘F G) idF

    .zig : idT ≡T (counit ∘ʳ F) ∘₁ (F ∘ˡ unit)
    .zag : idT ≡T (G ∘ˡ counit) ∘₁ (unit ∘ʳ G)

  private module C = Category C
  private module D = Category D

  private module F = Functor F
  private module G = Functor G renaming (F₀ to G₀; F₁ to G₁; F-resp-≡ to G-resp-≡)
  open F hiding (op)
  open G hiding (op)

  private module unit   = NaturalTransformation unit
  private module counit = NaturalTransformation counit

  monad : Monad D
  monad = record
    { F = G ∘F F
    ; η = unit
    ; μ = G ∘ˡ (counit ∘ʳ F)
    ; assoc = assoc′
    ; identityˡ = identityˡ′
    ; identityʳ = identityʳ′
    }
    where

    .assoc′ : ∀ {x}
           → G₁ (counit.η (F₀ x)) D.∘ G₁ (F₁ (G₁ (counit.η (F₀ x)))) D.≡ G₁ (counit.η (F₀ x)) D.∘ G₁ (counit.η (F₀ (G₀ (F₀ x))))
    assoc′ {x} =
        begin
          G₁ (counit.η (F₀ x)) D.∘ G₁ (F₁ (G₁ (counit.η (F₀ x))))
        ↑⟨ G.homomorphism ⟩
          G₁ ((counit.η (F₀ x)) C.∘ (F₁ (G₁ (counit.η (F₀ x)))))
        ↓⟨ G-resp-≡ (NaturalTransformation.commute counit (counit.η (F₀ x))) ⟩
          G₁ (counit.η (F₀ x) C.∘ counit.η (F₀ (G₀ (F₀ x))))
        ↓⟨ G.homomorphism ⟩
          G₁ (counit.η (F₀ x)) D.∘ G₁ (counit.η (F₀ (G₀ (F₀ x))))
        ∎
      where
      open D.HomReasoning

    .identityˡ′ : ∀ {x} → G₁ (counit.η (F₀ x)) D.∘ G₁ (F₁ (unit.η x)) D.≡ D.id
    identityˡ′ {x} =
        begin
          G₁ (counit.η (F₀ x)) D.∘ G₁ (F₁ (unit.η x))
        ↑⟨ G.homomorphism ⟩
          G₁ ((counit.η (F₀ x)) C.∘ (F₁ (unit.η x)))
        ↑⟨ G-resp-≡ zig ⟩
          G₁ C.id
        ↓⟨ G.identity ⟩
          D.id
        ∎
      where
      open D.HomReasoning

    .identityʳ′ : ∀ {x} → G₁ (counit.η (F₀ x)) D.∘ unit.η (G₀ (F₀ x)) D.≡ D.id
    identityʳ′ = D.Equiv.sym zag

  op : Adjunction {C = D.op} {D = C.op} G.op F.op
  op = record { unit = counit.op; counit = unit.op; zig = zag; zag = zig }

infixr 5 _⊣_
_⊣_ = Adjunction

id : ∀ {o ℓ e} {C : Category o ℓ e} → Adjunction (idF {C = C}) (idF {C = C})
id {C = C} = record
   { unit = idT
   ; counit = idT
   ; zig = Equiv.sym C.identityˡ
   ; zag = Equiv.sym C.identityˡ
   }
  where
    module C = Category C
    open C

infix  4 _≡_

_≡_ : ∀ {o ℓ e} {o₁ ℓ₁ e₁} {C : Category o ℓ e} {D : Category o₁ ℓ₁ e₁} {F : Functor D C} {G : Functor C D} →  Rel (F ⊣ G) (o ⊔ e ⊔ o₁ ⊔ e₁)
_≡_ {C = C} {D} {F} {G} X Y = Adjunction.unit X ≡T Adjunction.unit Y ×
                                Adjunction.counit X ≡T Adjunction.counit Y

.equiv : ∀ {o ℓ e} {o₁ ℓ₁ e₁} {C : Category o ℓ e} {D : Category o₁ ℓ₁ e₁} {F : Functor D C} {G : Functor C D} → IsEquivalence (_≡_ {F = F} {G})
equiv {C = C} {D} {F} {G} = record
         { refl = (D.Equiv.refl), (C.Equiv.refl)
         ; sym = λ {T U : F ⊣ G} → sym' {T = T} {U = U}
         ; trans = λ {T U V : F ⊣ G} → trans' {T = T} {U = U} {V = V}
         }
      where
        module C = Category C
        module D = Category D

        sym' : {T U : F ⊣ G} → (H : T ≡ U) → flip _≡_ T U
        sym' {T} {U} (H₁ , H₂) = (λ {x} → D.Equiv.sym H₁) , (λ {x} → C.Equiv.sym H₂)

        trans' : {T U V : F ⊣ G} → T ≡ U → U ≡ V → T ≡ V
        trans' {T} {U} {V} (H₁ , H₂) (H₃ , H₄) = (λ {x} → D.Equiv.trans H₁ H₃) , (C.Equiv.trans H₂ H₄)

setoid : ∀ {o ℓ e} {o₁ ℓ₁ e₁} {C : Category o ℓ e} {D : Category o₁ ℓ₁ e₁} {F : Functor D C} {G : Functor C D}
         → Setoid (o ⊔ ℓ ⊔ e ⊔ o₁ ⊔ ℓ₁ ⊔ e₁) (o ⊔ e ⊔ o₁ ⊔ e₁)
setoid {C = C} {D} {F} {G} = record
       { Carrier = Adjunction F G
       ; _≈_ = _≡_
       ; isEquivalence = equiv {F = F} {G = G}
       }


module Dave.Algebra.Naturals.Ordering where
    open import Dave.Algebra.Naturals.Definition public
    open import Dave.Algebra.Naturals.Addition public
    open import Dave.Algebra.Naturals.Multiplication public

    -- TO-DO: define relation
    data _≤_ : ℕ → ℕ → Set where
        z≤n : ∀ {n : ℕ} → zero ≤ n
        s≤s : ∀ {m n : ℕ} → m ≤ n → suc m ≤ suc n

    infix 4 _≤_

    inv-s≤s : ∀ {m n : ℕ} → suc m ≤ suc n → m ≤ n
    inv-s≤s (s≤s m≤n) = m≤n

    inv-z≤n : ∀ {m : ℕ} → m ≤ zero → m ≡ zero
    inv-z≤n z≤n = refl

    -- TO-DO: define relation properties in general
    ≤-refl : ∀ {n : ℕ} → n ≤ n
    ≤-refl {zero} = z≤n
    ≤-refl {suc n} = s≤s ≤-refl

    ≤-trans : ∀ {m n p : ℕ} → m ≤ n → n ≤ p → m ≤ p
    ≤-trans z≤n n≤p = z≤n
    ≤-trans (s≤s m≤n) (s≤s n≤p) = s≤s (≤-trans m≤n n≤p)

    ≤-trans´ : ∀ (m n p : ℕ) → m ≤ n → n ≤ p → m ≤ p
    ≤-trans´ zero n p z≤n n≤p = z≤n
    ≤-trans´ (suc m) (suc n) (suc p) (s≤s m≤n) (s≤s n≤p) = s≤s (≤-trans´ m n p m≤n n≤p)

    ≤-antisym : ∀ {m n : ℕ} → m ≤ n → n ≤ m → m ≡ n
    ≤-antisym z≤n z≤n = refl
    ≤-antisym (s≤s m≤n) (s≤s n≤m) = cong suc (≤-antisym m≤n n≤m)

    data Total (m n : ℕ) : Set where
        forward : m ≤ n → Total m n
        flipped : n ≤ m → Total m n

    data Total´ : ℕ → ℕ → Set where
        forward´ : ∀ {m n : ℕ} → m ≤ n → Total´ m n
        flipped´ : ∀ {m n : ℕ} → n ≤ m → Total´ m n

    ≤-total : ∀ (m n : ℕ) → Total m n
    ≤-total zero n = forward z≤n
    ≤-total (suc m) zero = flipped z≤n
    ≤-total (suc m) (suc n) with ≤-total m n
    ...                         | forward m≤n = forward (s≤s m≤n)
    ...                         | flipped n≤m = flipped (s≤s n≤m)

    ≤-total´ : ∀ (m n : ℕ) → Total m n
    ≤-total´ zero n = forward z≤n
    ≤-total´ (suc m) zero = flipped z≤n
    ≤-total´ (suc m) (suc n) = helper (≤-total´ m n)
        where
        helper : Total m n → Total (suc m) (suc n)
        helper (forward m≤n) = forward (s≤s m≤n)
        helper (flipped n≤m) = flipped (s≤s n≤m)

    +-monoᵣ-≤ : ∀ (n p q : ℕ) → p ≤ q → n + p ≤ n + q
    +-monoᵣ-≤ zero p q p≤q = p≤q
    +-monoᵣ-≤ (suc n) p q p≤q = s≤s (+-monoᵣ-≤ n p q p≤q)

    +-monoₗ-≤ : ∀ (m n p : ℕ) → m ≤ n → m + p ≤ n + p
    +-monoₗ-≤ m n p m≤n  rewrite +-comm m p | +-comm n p = +-monoᵣ-≤ p m n m≤n

    +-mono-≤ : ∀ (m n p q : ℕ) → m ≤ n → p ≤ q → m + p ≤ n + q
    +-mono-≤ m n p q m≤n p≤q = ≤-trans (+-monoₗ-≤ m n p m≤n) (+-monoᵣ-≤ n p q p≤q)

    *-monoᵣ-≤ : ∀ (n p q : ℕ) → p ≤ q → n * p ≤ n * q
    *-monoᵣ-≤ zero p q p≤q = z≤n
    *-monoᵣ-≤ (suc n) p q p≤q = +-mono-≤ (n * p) (n * q) p q (*-monoᵣ-≤ n p q p≤q) p≤q

    *-monoₗ-≤ : ∀ (m n p : ℕ) → m ≤ n → m * p ≤ n * p
    *-monoₗ-≤ m n p m≤n  rewrite ℕ-*-comm m p | ℕ-*-comm n p = *-monoᵣ-≤ p m n m≤n

    *-mono-≤ : ∀ (m n p q : ℕ) → m ≤ n → p ≤ q → m * p ≤ n * q
    *-mono-≤ m n p q m≤n p≤q = ≤-trans (*-monoₗ-≤ m n p m≤n) (*-monoᵣ-≤ n p q p≤q)

    {- Strict inequality -}
    infix 4 _<_ _>_

    data _<_ : ℕ → ℕ → Set where
        z<s : ∀ {n : ℕ} → zero < suc n
        s<s : ∀ {m n : ℕ} → m < n → suc m < suc n

    <-trans : ∀ {m n p : ℕ} → m < n → n < p → m < p
    <-trans z<s (s<s n<p) = z<s
    <-trans (s<s m<n) (s<s n<p) = s<s (<-trans m<n n<p)

    +-monoᵣ-< : ∀ (n p q : ℕ) → p < q → n + p < n + q
    +-monoᵣ-< zero p q p<q = p<q
    +-monoᵣ-< (suc n) p q p<q = s<s (+-monoᵣ-< n p q p<q)

    +-monoₗ-< : ∀ (m n p : ℕ) → m < n → m + p < n + p
    +-monoₗ-< m n p m<n rewrite +-comm m p | +-comm n p = +-monoᵣ-< p m n m<n

    +-mono-< : ∀ (m n p q : ℕ) → m < n → p < q → m + p < n + q
    +-mono-< m n p q m<n p<q = <-trans (+-monoₗ-< m n p m<n) (+-monoᵣ-< n p q p<q)

    suc-≤→< : ∀ (m n : ℕ) → suc m ≤ n → m < n
    suc-≤→< zero (suc n) leq = z<s
    suc-≤→< (suc m) (suc n) (s≤s leq) = s<s (suc-≤→< m n leq)

    <→suc-≤ : ∀ (m n : ℕ) → m < n → suc m ≤ n
    <→suc-≤ zero (suc n) le = s≤s z≤n
    <→suc-≤ (suc m) (suc n) (s<s le) = s≤s (<→suc-≤ m n le)

    data _>_ : ℕ → ℕ → Set where
        co-m>n : ∀ {m n : ℕ} → n < m → m > n

    ℕ-suc-> : ∀ {m n : ℕ} → m > n → suc m > suc n
    ℕ-suc-> (co-m>n x) = co-m>n (s<s x)

    {- Trichotomy -}
    data Trichotomy (m n : ℕ) : Set where
        t-m>n : m > n → Trichotomy m n
        t-m≡n : m ≡ n → Trichotomy m n
        t-m<n : m < n → Trichotomy m n

    ℕ-suc-Trichotomy : ∀ {m n : ℕ} → Trichotomy m n → Trichotomy (suc m) (suc n)
    ℕ-suc-Trichotomy (t-m>n x) = t-m>n (ℕ-suc-> x)
    ℕ-suc-Trichotomy (t-m≡n refl) = t-m≡n refl
    ℕ-suc-Trichotomy (t-m<n x) = t-m<n (s<s x)

    ℕ-is-Trichotomy : ∀ (m n : ℕ) → Trichotomy m n
    ℕ-is-Trichotomy zero zero = t-m≡n refl
    ℕ-is-Trichotomy zero (suc n) = t-m<n z<s
    ℕ-is-Trichotomy (suc m) zero = t-m>n (co-m>n z<s)
    ℕ-is-Trichotomy (suc m) (suc n) = ℕ-suc-Trichotomy (ℕ-is-Trichotomy m n)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Solver for equations in commutative monoids
--
-- Adapted from Algebra.Solver.Monoid
------------------------------------------------------------------------

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

open import Algebra

module Algebra.Solver.CommutativeMonoid {m₁ m₂} (M : CommutativeMonoid m₁ m₂) where

open import Data.Fin using (Fin; zero; suc)
open import Data.Maybe as Maybe
  using (Maybe; decToMaybe; From-just; from-just)
open import Data.Nat as ℕ using (ℕ; zero; suc; _+_)
open import Data.Nat.GeneralisedArithmetic using (fold)
open import Data.Product using (_×_; uncurry)
open import Data.Vec using (Vec; []; _∷_; lookup; replicate)

open import Function using (_∘_)

import Relation.Binary.Reasoning.Setoid as EqReasoning
import Relation.Binary.Reflection as Reflection
import Relation.Nullary.Decidable as Dec
import Data.Vec.Relation.Binary.Pointwise.Inductive as Pointwise

open import Relation.Binary.PropositionalEquality as P using (_≡_; decSetoid)
open import Relation.Nullary using (Dec)

open CommutativeMonoid M
open EqReasoning setoid

------------------------------------------------------------------------
-- Monoid expressions

-- There is one constructor for every operation, plus one for
-- variables; there may be at most n variables.

infixr 5 _⊕_
infixr 10 _•_

data Expr (n : ℕ) : Set where
  var : Fin n → Expr n
  id  : Expr n
  _⊕_ : Expr n → Expr n → Expr n

-- An environment contains one value for every variable.

Env : ℕ → Set _
Env n = Vec Carrier n

-- The semantics of an expression is a function from an environment to
-- a value.

⟦_⟧ : ∀ {n} → Expr n → Env n → Carrier
⟦ var x   ⟧ ρ = lookup ρ x
⟦ id      ⟧ ρ = ε
⟦ e₁ ⊕ e₂ ⟧ ρ = ⟦ e₁ ⟧ ρ ∙ ⟦ e₂ ⟧ ρ

------------------------------------------------------------------------
-- Normal forms

-- A normal form is a vector of multiplicities (a bag).

Normal : ℕ → Set
Normal n = Vec ℕ n

-- The semantics of a normal form.

⟦_⟧⇓ : ∀ {n} → Normal n → Env n → Carrier
⟦ []    ⟧⇓ _ = ε
⟦ n ∷ v ⟧⇓ (a ∷ ρ) = fold (⟦ v ⟧⇓ ρ) (λ b → a ∙ b) n

------------------------------------------------------------------------
-- Constructions on normal forms

-- The empty bag.

empty : ∀{n} → Normal n
empty = replicate 0

-- A singleton bag.

sg : ∀{n} (i : Fin n) → Normal n
sg zero    = 1 ∷ empty
sg (suc i) = 0 ∷ sg i

-- The composition of normal forms.

_•_  : ∀{n} (v w : Normal n) → Normal n
[]      • []      = []
(l ∷ v) • (m ∷ w) = l + m ∷ v • w

------------------------------------------------------------------------
-- Correctness of the constructions on normal forms

-- The empty bag stands for the unit ε.

empty-correct : ∀{n} (ρ : Env n) → ⟦ empty ⟧⇓ ρ ≈ ε
empty-correct [] = refl
empty-correct (a ∷ ρ) = empty-correct ρ

-- The singleton bag stands for a single variable.

sg-correct : ∀{n} (x : Fin n) (ρ : Env n) →  ⟦ sg x ⟧⇓ ρ ≈ lookup ρ x
sg-correct zero (x ∷ ρ) = begin
    x ∙ ⟦ empty ⟧⇓ ρ   ≈⟨ ∙-congˡ (empty-correct ρ) ⟩
    x ∙ ε              ≈⟨ identityʳ _ ⟩
    x                  ∎
sg-correct (suc x) (m ∷ ρ) = sg-correct x ρ

-- Normal form composition corresponds to the composition of the monoid.

comp-correct : ∀ {n} (v w : Normal n) (ρ : Env n) →
              ⟦ v • w ⟧⇓ ρ ≈ (⟦ v ⟧⇓ ρ ∙ ⟦ w ⟧⇓ ρ)
comp-correct [] [] ρ =  sym (identityˡ _)
comp-correct (l ∷ v) (m ∷ w) (a ∷ ρ) = lemma l m (comp-correct v w ρ)
  where
    flip12 : ∀ a b c → a ∙ (b ∙ c) ≈ b ∙ (a ∙ c)
    flip12 a b c = begin
        a ∙ (b ∙ c)  ≈⟨ sym (assoc _ _ _) ⟩
        (a ∙ b) ∙ c  ≈⟨ ∙-congʳ (comm _ _) ⟩
        (b ∙ a) ∙ c  ≈⟨ assoc _ _ _ ⟩
        b ∙ (a ∙ c)  ∎
    lemma : ∀ l m {d b c} (p : d ≈ b ∙ c) →
      fold d (a ∙_) (l + m) ≈ fold b (a ∙_) l ∙ fold c (a ∙_) m
    lemma zero zero p = p
    lemma zero (suc m) p = trans (∙-congˡ (lemma zero m p)) (flip12 _ _ _)
    lemma (suc l) m p = trans (∙-congˡ (lemma l m p)) (sym (assoc a _ _))

------------------------------------------------------------------------
-- Normalization

-- A normaliser.

normalise : ∀ {n} → Expr n → Normal n
normalise (var x)   = sg x
normalise id        = empty
normalise (e₁ ⊕ e₂) = normalise e₁ • normalise e₂

-- The normaliser preserves the semantics of the expression.

normalise-correct : ∀ {n} (e : Expr n) (ρ : Env n) →
    ⟦ normalise e ⟧⇓ ρ ≈ ⟦ e ⟧ ρ
normalise-correct (var x)   ρ = sg-correct x ρ
normalise-correct id        ρ = empty-correct ρ
normalise-correct (e₁ ⊕ e₂) ρ =  begin

    ⟦ normalise e₁ • normalise e₂ ⟧⇓ ρ

  ≈⟨ comp-correct (normalise e₁) (normalise e₂) ρ ⟩

    ⟦ normalise e₁ ⟧⇓ ρ ∙ ⟦ normalise e₂ ⟧⇓ ρ

  ≈⟨ ∙-cong (normalise-correct e₁ ρ) (normalise-correct e₂ ρ) ⟩

    ⟦ e₁ ⟧ ρ ∙ ⟦ e₂ ⟧ ρ
  ∎

------------------------------------------------------------------------
-- "Tactics"

open module R = Reflection
                  setoid var ⟦_⟧ (⟦_⟧⇓ ∘ normalise) normalise-correct
  public using (solve; _⊜_)

-- We can decide if two normal forms are /syntactically/ equal.

infix 5 _≟_

_≟_ : ∀ {n} (nf₁ nf₂ : Normal n) → Dec (nf₁ ≡ nf₂)
nf₁ ≟ nf₂ = Dec.map Pointwise-≡↔≡ (decidable ℕ._≟_ nf₁ nf₂)
  where open Pointwise

-- We can also give a sound, but not necessarily complete, procedure
-- for determining if two expressions have the same semantics.

prove′ : ∀ {n} (e₁ e₂ : Expr n) → Maybe (∀ ρ → ⟦ e₁ ⟧ ρ ≈ ⟦ e₂ ⟧ ρ)
prove′ e₁ e₂ =
  Maybe.map lemma (decToMaybe (normalise e₁ ≟ normalise e₂))
  where
  lemma : normalise e₁ ≡ normalise e₂ → ∀ ρ → ⟦ e₁ ⟧ ρ ≈ ⟦ e₂ ⟧ ρ
  lemma eq ρ =
    R.prove ρ e₁ e₂ (begin
      ⟦ normalise e₁ ⟧⇓ ρ  ≡⟨ P.cong (λ e → ⟦ e ⟧⇓ ρ) eq ⟩
      ⟦ normalise e₂ ⟧⇓ ρ  ∎)

-- This procedure can be combined with from-just.

prove : ∀ n (e₁ e₂ : Expr n) → From-just (prove′ e₁ e₂)
prove _ e₁ e₂ = from-just (prove′ e₁ e₂)

-- prove : ∀ n (es : Expr n × Expr n) →
--         From-just (uncurry prove′ es)
-- prove _ = from-just ∘ uncurry prove′


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.HITs.Susp.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Equiv

open import Cubical.Data.Bool
open import Cubical.HITs.Join
open import Cubical.HITs.Susp.Base

open Iso

Susp-iso-joinBool : ∀ {ℓ} {A : Type ℓ} → Iso (Susp A) (join A Bool)
fun Susp-iso-joinBool north = inr true
fun Susp-iso-joinBool south = inr false
fun Susp-iso-joinBool (merid a i) = (sym (push a true) ∙ push a false) i
inv Susp-iso-joinBool (inr true ) = north
inv Susp-iso-joinBool (inr false) = south
inv Susp-iso-joinBool (inl _) = north
inv Susp-iso-joinBool (push a true  i) = north
inv Susp-iso-joinBool (push a false i) = merid a i
rightInv Susp-iso-joinBool (inr true ) = refl
rightInv Susp-iso-joinBool (inr false) = refl
rightInv Susp-iso-joinBool (inl a) = sym (push a true)
rightInv Susp-iso-joinBool (push a true  i) j = push a true (i ∨ ~ j)
rightInv Susp-iso-joinBool (push a false i) j
  = hcomp (λ k → λ { (i = i0) → push a true (~ j)
                   ; (i = i1) → push a false k
                   ; (j = i1) → push a false (i ∧ k) })
          (push a true (~ i ∧ ~ j))
leftInv Susp-iso-joinBool north = refl
leftInv Susp-iso-joinBool south = refl
leftInv (Susp-iso-joinBool {A = A}) (merid a i) j
  = hcomp (λ k → λ { (i = i0) → transp (λ _ → Susp A) (k ∨ j) north
                   ; (i = i1) → transp (λ _ → Susp A) (k ∨ j) (merid a k)
                   ; (j = i1) → merid a (i ∧ k) })
          (transp (λ _ → Susp A) j north)

Susp≃joinBool : ∀ {ℓ} {A : Type ℓ} → Susp A ≃ join A Bool
Susp≃joinBool = isoToEquiv Susp-iso-joinBool

Susp≡joinBool : ∀ {ℓ} {A : Type ℓ} → Susp A ≡ join A Bool
Susp≡joinBool = isoToPath Susp-iso-joinBool

congSuspEquiv : ∀ {ℓ} {A B : Type ℓ} → A ≃ B → Susp A ≃ Susp B
congSuspEquiv {ℓ} {A} {B} h = isoToEquiv isom
  where isom : Iso (Susp A) (Susp B)
        Iso.fun isom north = north
        Iso.fun isom south = south
        Iso.fun isom (merid a i) = merid (fst h a) i
        Iso.inv isom north = north
        Iso.inv isom south = south
        Iso.inv isom (merid a i) = merid (invEq h a) i
        Iso.rightInv isom north = refl
        Iso.rightInv isom south = refl
        Iso.rightInv isom (merid a i) j = merid (retEq h a j) i
        Iso.leftInv isom north = refl
        Iso.leftInv isom south = refl
        Iso.leftInv isom (merid a i) j = merid (secEq h a j) i

suspToPropRec : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Susp A → Type ℓ'} (a : A)
                 → ((x : Susp A) → isProp (B x))
                 → B north
                 → (x : Susp A) → B x
suspToPropRec a isProp Bnorth north = Bnorth
suspToPropRec {B = B} a isProp Bnorth south = subst B (merid a) Bnorth
suspToPropRec {B = B} a isProp Bnorth (merid a₁ i) =
  isOfHLevel→isOfHLevelDep 1 isProp Bnorth (subst B (merid a) Bnorth) (merid a₁) i

suspToPropRec2 : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Susp A → Susp A → Type ℓ'} (a : A)
                 → ((x y : Susp A) → isProp (B x y))
                 → B north north
                 → (x y : Susp A) → B x y
suspToPropRec2 a isProp Bnorth =
  suspToPropRec a (λ x → isOfHLevelΠ 1 λ y → isProp x y)
                      (suspToPropRec a (λ x → isProp north x) Bnorth)


open import Relation.Binary using (Decidable; Setoid; DecSetoid)
open import Level

module CP.Session3 {a} {b} (ChanDecSetoid : DecSetoid zero a) (TypeDecSetoid : DecSetoid zero b) where

module TS = DecSetoid TypeDecSetoid

Type : Set
Type = DecSetoid.Carrier TypeDecSetoid

open DecSetoid ChanDecSetoid

Chan : Set
Chan = Carrier

module _ where
  -- type of
  infix 6 _∶_
  data TypeOf : Set a where
    _∶_ : (x : Chan) → (A : Type) → TypeOf

  chanOf : TypeOf → Chan
  chanOf (x ∶ _) = x

  import Relation.Binary.Construct.On as On

  decSetoid : DecSetoid _ _
  decSetoid = On.decSetoid ChanDecSetoid chanOf

open import Data.List.Relation.Binary.Subset.DecSetoid decSetoid
open import Data.List

Session : Set a
Session = List TypeOf

open import Relation.Nullary
open import Relation.Nullary.Decidable

open import Data.Product
open import Data.Maybe

seperate : (Γ : Session) → (x : Chan) → Maybe (∃[ Δ ] ∃[ A ] (Γ ≋ x ∶ A ∷ Δ))
seperate []          x = nothing
seperate (y ∶ A ∷ Γ) x with y ≟ x
... | yes P = just (Γ , A , ∷-cong P ≋-refl)
... | no ¬P with seperate Γ x
... | just (Δ , B , eq) = just (y ∶ A ∷ Δ , B , reasoning)
  where
    open EqReasoning
    reasoning : y ∶ A ∷ Γ ≋ x ∶ B ∷ y ∶ A ∷ Δ
    reasoning =
      begin
        y ∶ A ∷ Γ
      ≈⟨ ∷-cong refl eq ⟩
        y ∶ A ∷ x ∶ B ∷ Δ
      ≈⟨ ≋-swap ⟩
        x ∶ B ∷ y ∶ A ∷ Δ
      ∎
... | nothing = nothing

-- insertion
infixl 5 _#_
_#_ : Session → TypeOf → Session
Γ # (x ∶ A) with seperate Γ x
... | nothing = x ∶ A ∷ Γ
... | just (Δ , _ , _) = x ∶ A ∷ Δ

insert-idempotent : ∀ Γ x A → Γ # x ∶ A # x ∶ A ≋ Γ # x ∶ A
insert-idempotent Γ x A with seperate Γ x
insert-idempotent Γ x A | nothing with seperate (x ∶ A ∷ Γ) x
... | nothing = {!   !}
... | just x₁ = {!   !}
insert-idempotent Γ x A | just x₁ = {!   !}


module Data.List.Proofs where

import Lvl
open import Functional
open import Data.Option using (Option ; Some ; None)
open import Data.List
open import Data.List.Equiv
open import Data.List.Functions
open import Logic
open import Numeral.Natural
open import Numeral.Natural.Oper
open import Numeral.Natural.Oper.Proofs
open import Relator.Equals renaming (_≡_ to _≡ₑ_ ; _≢_ to _≢ₑ_)
open import Structure.Function
open import Structure.Function.Domain
open import Structure.Function.Multi
import      Structure.Function.Names as Names
import      Structure.Operator.Names as Names
open import Structure.Operator.Proofs.Util
open import Structure.Operator.Properties
open import Structure.Operator
open import Structure.Relator.Properties
open import Structure.Setoid
open import Syntax.Transitivity
open import Type

private variable ℓ ℓₑ ℓₑₗ ℓₑₒ ℓₑ₁ ℓₑ₂ ℓₑₗ₁ ℓₑₗ₂ : Lvl.Level
private variable T A B : Type{ℓ}
private variable n : ℕ

module _ ⦃ equiv : Equiv{ℓₑ}(T) ⦄ ⦃ equiv-List : Equiv{ℓₑₗ}(List(T)) ⦄ ⦃ extensionality : Extensionality(equiv-List) ⦄ where
  private variable l l₁ l₂ : List(T)
  private variable a b x : T
  private variable P : List(T) → Stmt{ℓ}

  open Equiv(equiv-List) using () renaming (_≡_ to _≡ₗ_)

  instance
    tail-function : Function(tail)
    Function.congruence tail-function {∅}      {∅}      p = p
    Function.congruence tail-function {∅}      {x ⊰ y}  p with () ← [∅][⊰]-unequal p
    Function.congruence tail-function {x ⊰ xl} {∅}      p with () ← [∅][⊰]-unequal (symmetry(_≡_) p)
    Function.congruence tail-function {x ⊰ xl} {y ⊰ yl} p = [⊰]-generalized-cancellationₗ p

  instance
    first-function : ⦃ equiv-Option : Equiv{ℓₑₒ}(Option(T)) ⦄ ⦃ Some-function : Function(Some) ⦄ → Function(first)
    Function.congruence first-function {∅}      {∅}      p = reflexivity(_≡_)
    Function.congruence first-function {∅}      {y ⊰ yl} p with () ← [∅][⊰]-unequal p
    Function.congruence first-function {x ⊰ xl} {∅}      p with () ← [∅][⊰]-unequal (symmetry(_≡_) p)
    Function.congruence first-function {x ⊰ xl} {y ⊰ yl} p = congruence₁(Some) ([⊰]-generalized-cancellationᵣ p)

  instance
    [⊰]-cancellationₗ : Cancellationₗ(_⊰_)
    Cancellationₗ.proof([⊰]-cancellationₗ) = [⊰]-generalized-cancellationₗ

  instance
    [⊰]-cancellationᵣ : Cancellationᵣ(_⊰_)
    Cancellationᵣ.proof([⊰]-cancellationᵣ) = [⊰]-generalized-cancellationᵣ

  [⊰]-unequal : (x ⊰ l ≢ l)
  [⊰]-unequal {l = ∅} = [∅][⊰]-unequal ∘ symmetry(_≡_)
  [⊰]-unequal {l = x ⊰ l} = [⊰]-unequal {l = l} ∘ [⊰]-generalized-cancellationₗ

  postpend-of-prepend : (postpend a (b ⊰ l) ≡ b ⊰ postpend a l)
  postpend-of-prepend = reflexivity(_≡_)

  instance
    postpend-function : BinaryOperator(postpend)
    postpend-function = intro p where
      p : Names.Congruence₂(postpend)
      p {x₂ = ∅}        {y₂ = ∅}        px pl = congruence₂(_⊰_) px pl
      p {x₂ = ∅}        {y₂ = y₂ ⊰ yl₂} px pl with () ← [∅][⊰]-unequal pl
      p {x₂ = x₂ ⊰ xl₂} {y₂ = ∅}        px pl with () ← [∅][⊰]-unequal (symmetry(_≡_) pl)
      p {x₂ = x₂ ⊰ xl₂} {y₂ = y₂ ⊰ yl₂} px pl = congruence₂(_⊰_) ([⊰]-generalized-cancellationᵣ pl) (p{x₂ = xl₂} {y₂ = yl₂} px ([⊰]-generalized-cancellationₗ pl))

  instance
    reverse-function : Function(reverse)
    reverse-function = intro p where
      p : Names.Congruence₁(reverse)
      p {∅}      {∅}      pl = reflexivity(_≡_)
      p {∅}      {y ⊰ yl} pl with () ← [∅][⊰]-unequal pl
      p {x ⊰ xl} {∅}      pl with () ← [∅][⊰]-unequal (symmetry(_≡_) pl)
      p {x ⊰ xl} {y ⊰ yl} pl = congruence₂(postpend) ([⊰]-generalized-cancellationᵣ pl) (p([⊰]-generalized-cancellationₗ pl))

  instance
    [++]-identityₗ : Identityₗ(_++_) ∅
    Identityₗ.proof([++]-identityₗ) = reflexivity(_≡_)

  instance
    [++]-identityᵣ : Identityᵣ(_++_) ∅
    Identityᵣ.proof([++]-identityᵣ) {x = l} = elim (reflexivity(_≡_)) (\x l → congruence₂ᵣ(_⊰_)(x) {l ++ ∅}{l}) l

  instance
    [++]-associativity : Associativity(_++_)
    Associativity.proof([++]-associativity) {l₁}{l₂}{l₃} = elim (reflexivity(_≡_)) (\x l → congruence₂ᵣ(_⊰_)(x) {(l ++ l₂) ++ l₃}{l ++ (l₂ ++ l₃)}) l₁

  reverse-postpend : (reverse(postpend a l) ≡ a ⊰ reverse l)
  reverse-postpend {a = a}{l = l} = elim (reflexivity(_≡ₗ_)) (\x l p → congruence₂ᵣ(postpend) ⦃ postpend-function ⦄ (x) {reverse(postpend a l)}{a ⊰ reverse l} p) l

  prepend-[++] : (a ⊰ l ≡ singleton{T = T}(a) ++ l)
  prepend-[++] = reflexivity(_≡_)

  postpend-[++] : (postpend{T = T} a l ≡ l ++ singleton(a))
  postpend-[++] {a = a}{l = l} = elim (reflexivity(_≡_)) (\x l → congruence₂ᵣ(_⊰_)(x) {postpend a l}{l ++ (singleton a)}) l

  postpend-of-[++] : (postpend{T = T} a (l₁ ++ l₂) ≡ l₁ ++ postpend a l₂)
  postpend-of-[++] {a = a} {l₁}{l₂} = elim (reflexivity(_≡_)) (\x l → congruence₂ᵣ(_⊰_)(x) {postpend a (l ++ l₂)}{l ++ (postpend a l₂)}) l₁

  reverse-[++] : (reverse(l₁ ++ l₂) ≡ reverse(l₂) ++ reverse(l₁))
  reverse-[++] {l₁ = l₁} {l₂ = l₂} = elim
    (congruence₁(reverse) (identityₗ(_++_)(∅) {l₂}) 🝖 symmetry(_≡_) (identityᵣ(_++_)(∅) {reverse l₂}))
    (\x l₁ p → congruence₂ᵣ(postpend) ⦃ postpend-function ⦄ (x) {reverse (l₁ ++ l₂)}{reverse l₂ ++ reverse l₁} p 🝖 postpend-of-[++] {l₁ = reverse l₂} {l₂ = reverse l₁})
    l₁

  [∅]-postpend-unequal : (postpend x l ≢ ∅)
  [∅]-postpend-unequal {l = ∅}     = [∅][⊰]-unequal ∘ symmetry(_≡_)
  [∅]-postpend-unequal {l = _ ⊰ l} = [∅][⊰]-unequal ∘ symmetry(_≡_)

  postpend-unequal : (postpend x l ≢ l)
  postpend-unequal {l = ∅}     = [∅][⊰]-unequal ∘ symmetry(_≡_)
  postpend-unequal {l = y ⊰ l} = postpend-unequal {l = l} ∘ cancellationₗ(_⊰_)

  [++]-middle-prepend-postpend : postpend x l₁ ++ l₂ ≡ l₁ ++ (x ⊰ l₂)
  [++]-middle-prepend-postpend {l₁ = ∅}      {l₂ = ∅} = reflexivity(_≡_)
  [++]-middle-prepend-postpend {l₁ = ∅}      {l₂ = x ⊰ l₂} = reflexivity(_≡_)
  [++]-middle-prepend-postpend {l₁ = x ⊰ l₁} {l₂ = l₂} = congruence₂ᵣ(_⊰_)(x) ([++]-middle-prepend-postpend {l₁ = l₁} {l₂ = l₂})

  instance
    [++]-cancellationₗ : Cancellationₗ(_++_)
    Cancellationₗ.proof [++]-cancellationₗ {x}{y}{z} = proof {x}{y}{z} where
      proof : Names.Cancellationₗ (_++_)
      proof {∅}     p = p
      proof {x ⊰ l} p = proof {l} (cancellationₗ(_⊰_) p)

  instance
    [++]-cancellationᵣ : Cancellationᵣ(_++_)
    Cancellationᵣ.proof([++]-cancellationᵣ) {a}{b} = proof {a}{b} where
      proof : Names.Cancellationᵣ(_++_)
      proof {z}      {∅}      {∅}      p = reflexivity(_≡_)
      proof {z}      {x ⊰ xl} {y ⊰ yl} p = congruence₂(_⊰_) ([⊰]-generalized-cancellationᵣ p) (proof {z}{xl}{yl} ([⊰]-generalized-cancellationₗ p))
      proof {∅}      {∅}      {y ⊰ yl} p with () ← [∅][⊰]-unequal {l = yl} (p 🝖 identityᵣ(_++_)(∅))
      proof {z ⊰ zl} {∅}      {y ⊰ yl} p with () ← [∅]-postpend-unequal(symmetry(_≡_) (proof{zl}{∅}{postpend z yl} ([⊰]-generalized-cancellationₗ p 🝖 symmetry(_≡_) ([++]-middle-prepend-postpend {x = z}{l₁ = yl}{l₂ = zl}))))
      proof {∅}      {x ⊰ xl} {∅}      p with () ← [∅][⊰]-unequal {l = xl} (symmetry(_≡_) p 🝖 identityᵣ(_++_)(∅))
      proof {z ⊰ zl} {x ⊰ xl} {∅}      p with () ← [∅]-postpend-unequal(proof{zl}{postpend z xl}{∅} ([++]-middle-prepend-postpend {x = z}{l₁ = xl}{l₂ = zl} 🝖 [⊰]-generalized-cancellationₗ p))

  reverse-involution-raw : Names.Involution(reverse{T = T})
  reverse-involution-raw {x = ∅}     = reflexivity(_≡_)
  reverse-involution-raw {x = x ⊰ l} = reverse-postpend {a = x}{l = reverse l} 🝖 congruence₂ᵣ(_⊰_)(x) (reverse-involution-raw {x = l})

  instance
    reverse-involution : Involution(reverse{T = T})
    Involution.proof reverse-involution = reverse-involution-raw

  initial-of-∅ : (initial(n)(∅ {T = T}) ≡ ∅)
  initial-of-∅ {n = 𝟎}    = reflexivity(_≡_)
  initial-of-∅ {n = 𝐒(n)} = reflexivity(_≡_)

  module _ where
    open import Relator.Equals.Proofs.Equiv {T = ℕ}
    foldᵣ-constant-[+]ᵣ : ∀{init step} → (foldᵣ (const(_+ step)) init l ≡ₑ (step ⋅ length(l)) + init)
    foldᵣ-constant-[+]ᵣ {l = ∅} = reflexivity(_≡ₑ_)
    foldᵣ-constant-[+]ᵣ {l = x ⊰ l} {init}{step} =
      const(_+ step) x (foldᵣ (const(_+ step)) init l) 🝖[ _≡_ ]-[]
      (foldᵣ (const(_+ step)) init l) + step           🝖[ _≡_ ]-[ congruence₁(_+ step) (foldᵣ-constant-[+]ᵣ {l = l} {init}{step}) ]
      ((step ⋅ length(l)) + init) + step               🝖[ _≡_ ]-[ One.commuteᵣ-assocₗ {a = step ⋅ length(l)}{init}{step} ]
      ((step ⋅ length(l)) + step) + init               🝖[ _≡_ ]-[ congruence₁(_+ init) (commutativity(_+_) {step ⋅ length(l)}{step}) ]
      (step + (step ⋅ length(l))) + init               🝖-end

    foldᵣ-constant-[+]ₗ : ∀{init step} → (foldᵣ (const(step +_)) init l ≡ (length(l) ⋅ step) + init)
    foldᵣ-constant-[+]ₗ {l = ∅}                  = reflexivity(_≡_)
    foldᵣ-constant-[+]ₗ {l = x ⊰ l} {init}{step} =
      foldᵣ(const(step +_)) init (x ⊰ l)  🝖[ _≡_ ]-[]
      step + foldᵣ(const(step +_)) init l 🝖[ _≡_ ]-[ congruence₂ᵣ(_+_)(step) (foldᵣ-constant-[+]ₗ {l = l} {init}{step}) ]
      step + ((length(l) ⋅ step) + init)  🝖[ _≡_ ]-[ associativity(_+_) {step}{length(l) ⋅ step}{init} ]-sym
      (step + (length(l) ⋅ step)) + init  🝖[ _≡_ ]-[ congruence₂ₗ(_+_)(init) (commutativity(_+_) {step}{length(l) ⋅ step}) ]
      ((length(l) ⋅ step) + step) + init  🝖[ _≡_ ]-[ congruence₂ₗ(_+_)(init) ([⋅]-with-[𝐒]ₗ {length(l)}{step}) ]-sym
      (𝐒(length(l)) ⋅ step) + init        🝖[ _≡_ ]-[]
      (length(x ⊰ l) ⋅ step) + init       🝖-end

open import Structure.Setoid
module _
  ⦃ equiv-A : Equiv{ℓₑ₁}(A) ⦄ ⦃ equiv-List₁ : Equiv{ℓₑₗ₁}(List(A)) ⦄ ⦃ extensionality-A : Extensionality(equiv-List₁) ⦄
  ⦃ equiv-B : Equiv{ℓₑ₂}(B) ⦄ ⦃ equiv-List₂ : Equiv{ℓₑₗ₂}(List(B)) ⦄ ⦃ extensionality-B : Extensionality(equiv-List₂) ⦄
  where

  private variable l l₁ l₂ : List(T)
  private variable a b x : T
  private variable P : List(T) → Stmt{ℓ}

  private variable f : A → B

  map-postpend : (map f(postpend a l) ≡ postpend (f(a)) (map f(l)))
  map-postpend {f = f} {a = a}{l = l} = elim (reflexivity(_≡_)) (\x l → congruence₂ᵣ(_⊰_)(f(x)) {map f (postpend a l)}{postpend (f(a)) (map f l)}) l

  instance
    map-preserves-[++] : Preserving₂(map f)(_++_)(_++_)
    Preserving.proof (map-preserves-[++] {f = f}) {l₁} {l₂} = elim (reflexivity(_≡_)) (\x l₁ → congruence₂ᵣ(_⊰_)(f(x)) {map f(l₁ ++ l₂)}{(map f l₁) ++ (map f l₂)}) l₁


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

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

open import Categories.Category

open import Categories.Functor public
open import Categories.Product

Bifunctor : ∀ {o ℓ e} {o′ ℓ′ e′} {o′′ ℓ′′ e′′} → Category o ℓ e → Category o′ ℓ′ e′ → Category o′′ ℓ′′ e′′ → Set (o ⊔ ℓ ⊔ e ⊔ o′ ⊔ ℓ′ ⊔ e′ ⊔ o′′ ⊔ ℓ′′ ⊔ e′′)
Bifunctor C D E = Functor (Product C D) E

overlap-× : ∀ {o ℓ e} {o′₁ ℓ′₁ e′₁} {o′₂ ℓ′₂ e′₂} {C : Category o ℓ e} {D₁ : Category o′₁ ℓ′₁ e′₁} {D₂ : Category o′₂ ℓ′₂ e′₂} (H : Bifunctor D₁ D₂ C) {o″ ℓ″ e″} {E : Category o″ ℓ″ e″} (F : Functor E D₁) (G : Functor E D₂) → Functor E C
overlap-× H F G = H ∘ (F ※ G)

reduce-× : ∀ {o ℓ e} {o′₁ ℓ′₁ e′₁} {o′₂ ℓ′₂ e′₂} {C : Category o ℓ e} {D₁ : Category o′₁ ℓ′₁ e′₁} {D₂ : Category o′₂ ℓ′₂ e′₂} (H : Bifunctor D₁ D₂ C) {o″₁ ℓ″₁ e″₁} {E₁ : Category o″₁ ℓ″₁ e″₁} (F : Functor E₁ D₁) {o″₂ ℓ″₂ e″₂} {E₂ : Category o″₂ ℓ″₂ e″₂} (G : Functor E₂ D₂) → Bifunctor E₁ E₂ C
reduce-× H F G = H ∘ (F ⁂ G)

flip-bifunctor : ∀ {o ℓ e} {o′ ℓ′ e′} {o′′ ℓ′′ e′′} {C : Category o ℓ e} → {D : Category o′ ℓ′ e′} → {E : Category o′′ ℓ′′ e′′} → Bifunctor C D E → Bifunctor D C E
flip-bifunctor {C = C} {D = D} {E = E} b = _∘_ b (Swap {C = C} {D = D})


------------------------------------------------------------------------
-- Call-by-value (CBV) reduction in pure type systems (PTS)
------------------------------------------------------------------------

module Pts.Reduction.Cbv where

open import Data.Fin.Substitution
open import Data.Fin.Substitution.ExtraLemmas
open import Data.Star using (map; gmap)
import Relation.Binary.EquivalenceClosure as EqClos
import Relation.Binary.PropositionalEquality as PropEq
open import Relation.Binary.Reduction

open import Pts.Syntax
open import Pts.Reduction.Full as Full hiding (reduction)

-- All remaining submodules are parametrized by a given set of sorts.
module _ {Sort : Set} where

  open Syntax       Sort
  open Substitution Sort using (_[_])

  ----------------------------------------------------------------------
  -- Call-by-value (CBV) reduction and equivalence relations

  -- Untyped values with up to n free variables.
  data Val {n} : Term n → Set where
    sort : ∀ s   → Val (sort s)  -- sort
    Π    : ∀ a b → Val (Π a b)   -- dependent product
    ƛ    : ∀ a b → Val (ƛ a b)   -- abstraction

  infixl 9  _·₁_ _·₂_
  infix  5  _→v_

  -- One-step CBV reduction.
  data _→v_ {n} : Term n → Term n → Set where
    cont : ∀ a b {c} (v : Val c)              → (ƛ a b) · c →v b [ c ]
    _·₁_ : ∀ {a₁ a₂} → a₁ →v a₂ → ∀ b         →      a₁ · b →v a₂ · b
    _·₂_ : ∀ {a b₁ b₂} (v : Val a) → b₁ →v b₂ →      a · b₁ →v a · b₂

  reduction : Reduction Term
  reduction = record { _→1_ = _→v_ }

  -- CBV reduction and equivalence.
  open Reduction reduction public renaming (_→*_ to _→v*_; _↔_ to _≡v_)

  ----------------------------------------------------------------------
  -- Substitutions in CBV reductions/equivalence
  --
  -- The applications _/→v_, _/→v*_ and _/≡v_ below may be considered
  -- substitution lemmas, i.e. they establish the commutativity of the
  -- respective reductions/equivalence with substitutions.

  -- Application of generic substitutions to the
  -- reductions/equivalence.
  record CbvSubstApp {T} (l : Lift T Term) : Set where
    open Lift l
    open SubstApp Sort l
    open PropEq hiding ([_])

    -- Substitutions commute.
    field /-sub-↑ : ∀ {m n} a b (σ : Sub T m n) →
                    a [ b ] / σ ≡ (a / σ ↑) [ b / σ ]

    infixl 8 _/Val_ _/→v_

    -- Application of substitutions preserves values.
    _/Val_ : ∀ {m n a} → Val a → (σ : Sub T m n) → Val (a / σ)
    sort s /Val σ = sort s
    Π a b  /Val σ = Π (a / σ) (b / σ ↑)
    ƛ a b  /Val σ = ƛ (a / σ) (b / σ ↑)

    -- Substitution commutes with one-step reduction.
    _/→v_ : ∀ {m n a b} → a →v b → (σ : Sub T m n) → a / σ →v b / σ
    cont a b c /→v σ =
      subst (_→v_ _) (sym (/-sub-↑ b _ σ)) (cont (a / σ) (b / σ ↑) (c /Val σ))
    a₁→a₂ ·₁ b /→v σ = (a₁→a₂ /→v σ) ·₁ (b / σ)
    a ·₂ b₁→b₂ /→v σ = (a /Val σ) ·₂ (b₁→b₂ /→v σ)

    redSubstApp : RedSubstApp reduction (record { _/_ = _/_ })
    redSubstApp = record { _/→1_ = _/→v_ }

    open RedSubstApp redSubstApp public
      hiding (_/→1_) renaming (_/→*_ to _/→v*_; _/↔_ to _/≡v_)

  -- Term substitutions in reductions/equivalences.
  module CbvSubstitution where
    open Substitution Sort
      using (termSubst; weaken; sub-commutes; varLiftSubLemmas)

    -- Application of renamings to reductions/equivalences.
    varSubstApp : CbvSubstApp (TermSubst.varLift termSubst)
    varSubstApp = record { /-sub-↑ = /-sub-↑ }
      where open LiftSubLemmas varLiftSubLemmas
    private module V = CbvSubstApp varSubstApp

    -- Weakening of one-step CBV reductions.
    weaken-→v : ∀ {n} {a b : Term n} → a →v b → weaken a →v weaken b
    weaken-→v a→b = a→b V./→v VarSubst.wk

    -- Weakening of CBV reductions.
    weaken-→v* : ∀ {n} {a b : Term n} → a →v* b → weaken a →v* weaken b
    weaken-→v* = gmap weaken weaken-→v

    -- Weakening of equivalences.
    weaken-≡v : ∀ {n} {a b : Term n} → a ≡v b → weaken a ≡v weaken b
    weaken-≡v = EqClos.gmap weaken weaken-→v

    -- Application of term substitutions to reductions/equivalences.
    termSubstApp : CbvSubstApp (TermSubst.termLift termSubst)
    termSubstApp = record { /-sub-↑ = λ a _ _ → sub-commutes a }
    open CbvSubstApp termSubstApp public

  ----------------------------------------------------------------------
  -- Properties of the CBV reductions/equivalence

  -- Inclusions.
  →v⇒→v* = →1⇒→* reduction
  →v*⇒≡v = →*⇒↔  reduction
  →v⇒≡v  = →1⇒↔  reduction

  -- CBV reduction is a preorder.
  →v*-predorder = →*-predorder reduction

  -- Preorder reasoning for CBV reduction.
  module →v*-Reasoning = →*-Reasoning reduction

  -- Terms together with CBV equivalence form a setoid.
  ≡v-setoid = ↔-setoid reduction

  -- Equational reasoning for CBV equivalence.
  module ≡v-Reasoning = ↔-Reasoning reduction

  ----------------------------------------------------------------------
  -- Relationships between CBV reduction and full β-reduction

  -- One-step CBV reduction implies one-step β-reduction.
  →v⇒→β : ∀ {n} {a b : Term n} → a →v b → a →β b
  →v⇒→β (cont a b c) = cont a b _
  →v⇒→β (a₁→a₂ ·₁ b) = →v⇒→β a₁→a₂ ·₁ b
  →v⇒→β (a ·₂ b₁→b₂) = _ ·₂ →v⇒→β b₁→b₂

  -- CBV reduction implies parallel reduction.
  →v*⇒→β* : ∀ {n} {a b : Term n} → a →v* b → a →β* b
  →v*⇒→β* = map →v⇒→β

  -- CBV equivalence implies parallel equivalence.
  ≡v⇒≡p : ∀ {n} {a b : Term n} → a ≡v b → a ≡β b
  ≡v⇒≡p = EqClos.map →v⇒→β


------------------------------------------------------------------------
-- The Agda standard library
--
-- Property that elements are grouped
------------------------------------------------------------------------

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

module Data.List.Relation.Unary.Grouped where

open import Data.List using (List; []; _∷_; map)
open import Data.List.Relation.Unary.All as All using (All; []; _∷_; all)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Product using (_×_; _,_)
open import Relation.Binary as B using (REL; Rel)
open import Relation.Unary as U using (Pred)
open import Relation.Nullary using (¬_; yes)
open import Relation.Nullary.Decidable as Dec
open import Relation.Nullary.Sum using (_⊎-dec_)
open import Relation.Nullary.Product using (_×-dec_)
open import Relation.Nullary.Negation using (¬?)
open import Level using (_⊔_)

infixr 5 _∷≉_ _∷≈_

data Grouped {a ℓ} {A : Set a} (_≈_ : Rel A ℓ) : Pred (List A) (a ⊔ ℓ) where
  [] : Grouped _≈_ []
  _∷≉_ : ∀ {x xs} → All (λ y → ¬ (x ≈ y)) xs → Grouped _≈_ xs → Grouped _≈_ (x ∷ xs)
  _∷≈_ : ∀ {x y xs} → x ≈ y → Grouped _≈_ (y ∷ xs) → Grouped _≈_ (x ∷ y ∷ xs)

module _ {a ℓ} {A : Set a} {_≈_ : Rel A ℓ} where
  grouped? : B.Decidable _≈_ → U.Decidable (Grouped _≈_)
  grouped? _≟_ [] = yes []
  grouped? _≟_ (x ∷ []) = yes ([] ∷≉ [])
  grouped? _≟_ (x ∷ y ∷ xs) = map′ from to ((x ≟ y ⊎-dec all (λ z → ¬? (x ≟ z)) (y ∷ xs)) ×-dec (grouped? _≟_ (y ∷ xs))) where
    from : ((x ≈ y) ⊎ All (λ z → ¬ (x ≈ z)) (y ∷ xs)) × Grouped _≈_ (y ∷ xs) → Grouped _≈_ (x ∷ y ∷ xs)
    from (inj₁ x≈y          , grouped[y∷xs]) = x≈y          ∷≈ grouped[y∷xs]
    from (inj₂ all[x≉,y∷xs] , grouped[y∷xs]) = all[x≉,y∷xs] ∷≉ grouped[y∷xs]
    to : Grouped _≈_ (x ∷ y ∷ xs) → ((x ≈ y) ⊎ All (λ z → ¬ (x ≈ z)) (y ∷ xs)) × Grouped _≈_ (y ∷ xs)
    to (all[x≉,y∷xs] ∷≉ grouped[y∷xs]) = inj₂ all[x≉,y∷xs] , grouped[y∷xs]
    to (x≈y          ∷≈ grouped[y∷xs]) = inj₁ x≈y , grouped[y∷xs]