{-# OPTIONS --allow-unsolved-metas #-}

module fin where

open import Data.Fin hiding (_<_ ; _≤_ ; _>_ ; _+_ )
open import Data.Fin.Properties hiding (≤-trans ;  <-trans ;  ≤-refl  ) renaming ( <-cmp to <-fcmp )
open import Data.Nat
open import Data.Nat.Properties
open import logic
open import nat
open import Relation.Binary.PropositionalEquality

-- toℕ<n
fin<n : {n : ℕ} {f : Fin n} → toℕ f < n
fin<n {_} {zero} = s≤s z≤n
fin<n {suc n} {suc f} = s≤s (fin<n {n} {f})

-- toℕ≤n
fin≤n : {n : ℕ} (f : Fin (suc n)) → toℕ f ≤ n
fin≤n {_} zero = z≤n
fin≤n {suc n} (suc f) = s≤s (fin≤n {n} f)

pred<n : {n : ℕ} {f : Fin (suc n)} → n > 0  → Data.Nat.pred (toℕ f) < n
pred<n {suc n} {zero} (s≤s z≤n) = s≤s z≤n
pred<n {suc n} {suc f} (s≤s z≤n) = fin<n

fin<asa : {n : ℕ} → toℕ (fromℕ< {n} a<sa) ≡ n
fin<asa = toℕ-fromℕ< nat.a<sa

-- fromℕ<-toℕ
toℕ→from : {n : ℕ} {x : Fin (suc n)} → toℕ x ≡ n → fromℕ n ≡ x
toℕ→from {0} {zero} refl = refl
toℕ→from {suc n} {suc x} eq = cong (λ k → suc k ) ( toℕ→from {n} {x} (cong (λ k → Data.Nat.pred k ) eq ))

0≤fmax : {n : ℕ } → (# 0) Data.Fin.≤ fromℕ< {n} a<sa
0≤fmax  = subst (λ k → 0 ≤ k ) (sym (toℕ-fromℕ< a<sa)) z≤n

0<fmax : {n : ℕ } → (# 0) Data.Fin.< fromℕ< {suc n} a<sa
0<fmax = subst (λ k → 0 < k ) (sym (toℕ-fromℕ< a<sa)) (s≤s z≤n)

-- toℕ-injective
i=j : {n : ℕ} (i j : Fin n) → toℕ i ≡ toℕ j → i ≡ j
i=j {suc n} zero zero refl = refl
i=j {suc n} (suc i) (suc j) eq = cong ( λ k → suc k ) ( i=j i j (cong ( λ k → Data.Nat.pred k ) eq) )

-- raise 1
fin+1 :  { n : ℕ } → Fin n → Fin (suc n)
fin+1  zero = zero
fin+1  (suc x) = suc (fin+1 x)

open import Data.Nat.Properties as NatP  hiding ( _≟_ )

fin+1≤ : { i n : ℕ } → (a : i < n)  → fin+1 (fromℕ< a) ≡ fromℕ< (<-trans a a<sa)
fin+1≤ {0} {suc i} (s≤s z≤n) = refl
fin+1≤ {suc n} {suc (suc i)} (s≤s (s≤s a)) = cong (λ k → suc k ) ( fin+1≤ {n} {suc i} (s≤s a) )

fin+1-toℕ : { n : ℕ } → { x : Fin n} → toℕ (fin+1 x) ≡ toℕ x
fin+1-toℕ {suc n} {zero} = refl
fin+1-toℕ {suc n} {suc x} = cong (λ k → suc k ) (fin+1-toℕ {n} {x})

open import Relation.Nullary
open import Data.Empty

fin-1 :  { n : ℕ } → (x : Fin (suc n)) → ¬ (x ≡ zero )  → Fin n
fin-1 zero ne = ⊥-elim (ne refl )
fin-1 {n} (suc x) ne = x

fin-1-sx : { n : ℕ } → (x : Fin n) →  fin-1 (suc x) (λ ()) ≡ x
fin-1-sx zero = refl
fin-1-sx (suc x) = refl

fin-1-xs : { n : ℕ } → (x : Fin (suc n)) → (ne : ¬ (x ≡ zero ))  → suc (fin-1 x ne ) ≡ x
fin-1-xs zero ne = ⊥-elim ( ne refl )
fin-1-xs (suc x) ne = refl

-- suc-injective
-- suc-eq : {n : ℕ } {x y : Fin n} → Fin.suc x ≡ Fin.suc y  → x ≡ y
-- suc-eq {n} {x} {y} eq = subst₂ (λ j k → j ≡ k ) {!!} {!!} (cong (λ k → Data.Fin.pred k ) eq )

-- this is refl
lemma3 : {a b : ℕ } → (lt : a < b ) → fromℕ< (s≤s lt) ≡ suc (fromℕ< lt)
lemma3 (s≤s lt) = refl

-- fromℕ<-toℕ
lemma12 : {n m : ℕ } → (n<m : n < m ) → (f : Fin m )  → toℕ f ≡ n → f ≡ fromℕ< n<m
lemma12 {zero} {suc m} (s≤s z≤n) zero refl = refl
lemma12 {suc n} {suc m} (s≤s n<m) (suc f) refl =  cong suc ( lemma12 {n} {m} n<m f refl  )

open import Relation.Binary.HeterogeneousEquality as HE using (_≅_ )

-- <-irrelevant
<-nat=irr : {i j n : ℕ } → ( i ≡ j ) → {i<n : i < n } → {j<n : j < n } → i<n ≅ j<n
<-nat=irr {zero} {zero} {suc n} refl {s≤s z≤n} {s≤s z≤n} = HE.refl
<-nat=irr {suc i} {suc i} {suc n} refl {s≤s i<n} {s≤s j<n} = HE.cong (λ k → s≤s k ) ( <-nat=irr {i} {i} {n} refl  )

lemma8 : {i j n : ℕ } → ( i ≡ j ) → {i<n : i < n } → {j<n : j < n } → i<n ≅ j<n
lemma8 {zero} {zero} {suc n} refl {s≤s z≤n} {s≤s z≤n} = HE.refl
lemma8 {suc i} {suc i} {suc n} refl {s≤s i<n} {s≤s j<n} = HE.cong (λ k → s≤s k ) ( lemma8 {i} {i} {n} refl  )

-- fromℕ<-irrelevant
lemma10 : {n i j  : ℕ } → ( i ≡ j ) → {i<n : i < n } → {j<n : j < n }  → fromℕ< i<n ≡ fromℕ< j<n
lemma10 {n} refl  = HE.≅-to-≡ (HE.cong (λ k → fromℕ< k ) (lemma8 refl  ))

lemma31 : {a b c : ℕ } → { a<b : a < b } { b<c : b < c } { a<c : a < c } → NatP.<-trans a<b b<c ≡ a<c
lemma31 {a} {b} {c} {a<b} {b<c} {a<c} = HE.≅-to-≡ (lemma8 refl)

-- toℕ-fromℕ<
lemma11 : {n m : ℕ } {x : Fin n } → (n<m : n < m ) → toℕ (fromℕ< (NatP.<-trans (toℕ<n x) n<m)) ≡ toℕ x
lemma11 {n} {m} {x} n<m  = begin
              toℕ (fromℕ< (NatP.<-trans (toℕ<n x) n<m))
           ≡⟨ toℕ-fromℕ< _ ⟩
              toℕ x
           ∎  where
               open ≡-Reasoning

x<y→fin-1 : {n : ℕ } → { x y : Fin (suc n)} →  toℕ x < toℕ y  → Fin n
x<y→fin-1 {n} {x} {y} lt = fromℕ< (≤-trans lt (fin≤n _ ))

x<y→fin-1-eq : {n : ℕ } → { x y : Fin (suc n)} → (lt : toℕ x < toℕ y ) → toℕ x ≡ toℕ (x<y→fin-1 lt )
x<y→fin-1-eq {n} {x} {y} lt = sym ( begin
           toℕ (fromℕ< (≤-trans lt (fin≤n y)) ) ≡⟨ toℕ-fromℕ< _ ⟩
           toℕ x  ∎  ) where open ≡-Reasoning

f<→< : {n : ℕ } → { x y : Fin n} → x Data.Fin.< y  →  toℕ x < toℕ y
f<→< {_} {zero} {suc y} (s≤s lt) = s≤s z≤n
f<→< {_} {suc x} {suc y} (s≤s lt) = s≤s (f<→< {_} {x} {y} lt)

f≡→≡ : {n : ℕ } → { x y : Fin n} → x ≡ y  →  toℕ x ≡ toℕ y
f≡→≡ refl = refl

open import Data.List
open import Relation.Binary.Definitions

-- fin-count : { n : ℕ }  (q : Fin n) (qs : List (Fin n) ) → ℕ
-- fin-count q p[ = 0
-- fin-count q (q0 ∷ qs ) with <-fcmp q q0
-- ... | tri-e = suc (fin-count q qs)
-- ... | false = fin-count q qs

-- fin-not-dup-in-list : { n : ℕ}  (qs : List (Fin n) ) → Set
-- fin-not-dup-in-list {n} qs = (q : Fin n) → fin-count q ≤ 1

-- this is far easier
-- fin-not-dup-in-list→len<n : { n : ℕ}  (qs : List (Fin n) ) → ( (q : Fin n) → fin-not-dup-in-list qs q) → length qs ≤ n
-- fin-not-dup-in-list→len<n = ?

fin-phase2 : { n : ℕ }  (q : Fin n) (qs : List (Fin n) ) → Bool
fin-phase2 q [] = false
fin-phase2 q (x ∷ qs) with <-fcmp q x
... | tri< a ¬b ¬c = fin-phase2 q qs
... | tri≈ ¬a b ¬c = true
... | tri> ¬a ¬b c = fin-phase2 q qs
fin-phase1 : { n : ℕ }  (q : Fin n) (qs : List (Fin n) ) → Bool
fin-phase1 q [] = false
fin-phase1 q (x ∷ qs) with <-fcmp q x
... | tri< a ¬b ¬c = fin-phase1 q qs
... | tri≈ ¬a b ¬c = fin-phase2 q qs
... | tri> ¬a ¬b c = fin-phase1 q qs

fin-dup-in-list : { n : ℕ}  (q : Fin n) (qs : List (Fin n) ) → Bool
fin-dup-in-list {n} q qs = fin-phase1 q qs

record FDup-in-list (n : ℕ ) (qs : List (Fin n))  : Set where
   field
      dup : Fin n
      is-dup : fin-dup-in-list dup qs ≡ true

list-less : {n : ℕ } → List (Fin (suc n)) → List (Fin n)
list-less [] = []
list-less {n} (i ∷ ls) with <-fcmp (fromℕ< a<sa) i
... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ i < suc k ) (sym fin<asa) (fin≤n _ )))
... | tri≈ ¬a b ¬c = list-less ls
... | tri> ¬a ¬b c = x<y→fin-1 c ∷ list-less ls

fin010 : {n m : ℕ } {x : Fin n} (c : suc (toℕ x) ≤ toℕ (fromℕ< {m} a<sa) ) → toℕ (fromℕ< (≤-trans c (fin≤n (fromℕ< a<sa)))) ≡ toℕ x
fin010 {_} {_} {x} c = begin
           toℕ (fromℕ< (≤-trans c (fin≤n (fromℕ< a<sa))))  ≡⟨ toℕ-fromℕ< _ ⟩
           toℕ x  ∎   where open ≡-Reasoning

---
---  if List (Fin n) is longer than n, there is at most one duplication
---
fin-dup-in-list>n : {n : ℕ } → (qs : List (Fin n))  → (len> : length qs > n ) → FDup-in-list n qs
fin-dup-in-list>n {zero} [] ()
fin-dup-in-list>n {zero} (() ∷ qs) lt
fin-dup-in-list>n {suc n} qs lt = fdup-phase0 where
     open import Level using ( Level )
     --  make a dup from one level below
     fdup+1 : (qs : List (Fin (suc n))) (i : Fin n) →  fin-dup-in-list  (fromℕ< a<sa ) qs ≡ false
          → fin-dup-in-list i (list-less qs) ≡ true → FDup-in-list (suc n) qs
     fdup+1 qs i ne p = record { dup = fin+1 i ; is-dup = f1-phase1 qs p (case1 ne) } where
          -- we have two loops on the max element and the current level. The disjuction means the phases may differ.
          f1-phase2 : (qs : List (Fin (suc n)) ) → fin-phase2 i (list-less qs) ≡ true
              → (fin-phase1 (fromℕ< a<sa) qs ≡ false ) ∨ (fin-phase2 (fromℕ< a<sa) qs ≡ false)
              → fin-phase2 (fin+1 i) qs ≡ true
          f1-phase2 (x ∷ qs) p (case1 q1) with  <-fcmp (fromℕ< a<sa) x
          ... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ x < suc k ) (sym fin<asa) (fin≤n _ )))
          f1-phase2 (x ∷ qs) p (case1 q1) | tri≈ ¬a b ¬c with <-fcmp (fin+1 i) x
          ... | tri< a ¬b ¬c₁ = f1-phase2 qs p (case2 q1)
          ... | tri≈ ¬a₁ b₁ ¬c₁ = refl
          ... | tri> ¬a₁ ¬b c = f1-phase2 qs p (case2 q1)
          -- two fcmp is only different in the size of Fin, but to develop both f1-phase and list-less both fcmps are required
          f1-phase2 (x ∷ qs) p (case1 q1) | tri> ¬a ¬b c with <-fcmp i (fromℕ< (≤-trans c (fin≤n (fromℕ< a<sa)))) | <-fcmp (fin+1 i) x
          ... | tri< a ¬b₁ ¬c | tri< a₁ ¬b₂ ¬c₁ = f1-phase2 qs p (case1 q1)
          ... | tri< a ¬b₁ ¬c | tri≈ ¬a₁ b ¬c₁  = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) (sym fin+1-toℕ) (toℕ-fromℕ< _) a ))
          ... | tri< a ¬b₁ ¬c | tri> ¬a₁ ¬b₂ c₁ = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) (sym fin+1-toℕ) (toℕ-fromℕ< _) a ))
          ... | tri≈ ¬a₁ b ¬c | tri< a ¬b₁ ¬c₁  = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) fin+1-toℕ (sym (toℕ-fromℕ< _)) a ))
          ... | tri≈ ¬a₁ b ¬c | tri≈ ¬a₂ b₁ ¬c₁ = refl
          ... | tri≈ ¬a₁ b ¬c | tri> ¬a₂ ¬b₁ c₁ = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) fin+1-toℕ (sym (toℕ-fromℕ< _)) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri< a ¬b₂ ¬c = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) (sym fin+1-toℕ) (toℕ-fromℕ< _) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri≈ ¬a₂ b ¬c = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) (sym fin+1-toℕ) (toℕ-fromℕ< _) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri> ¬a₂ ¬b₂ c₂ = f1-phase2 qs p (case1 q1)
          f1-phase2 (x ∷ qs) p (case2 q1) with  <-fcmp (fromℕ< a<sa) x
          ... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ x < suc k ) (sym fin<asa) (fin≤n _ )))
          f1-phase2 (x ∷ qs) p (case2 q1) | tri≈ ¬a b ¬c with <-fcmp (fin+1 i) x
          ... | tri< a ¬b ¬c₁ = ⊥-elim ( ¬-bool q1 refl )
          ... | tri≈ ¬a₁ b₁ ¬c₁ = refl
          ... | tri> ¬a₁ ¬b c = ⊥-elim ( ¬-bool q1 refl )
          f1-phase2 (x ∷ qs) p (case2 q1) | tri> ¬a ¬b c with <-fcmp i (fromℕ< (≤-trans c (fin≤n (fromℕ< a<sa)))) | <-fcmp (fin+1 i) x
          ... | tri< a ¬b₁ ¬c | tri< a₁ ¬b₂ ¬c₁ = f1-phase2 qs p (case2 q1)
          ... | tri< a ¬b₁ ¬c | tri≈ ¬a₁ b ¬c₁  = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) (sym fin+1-toℕ) (toℕ-fromℕ< _) a ))
          ... | tri< a ¬b₁ ¬c | tri> ¬a₁ ¬b₂ c₁ = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) (sym fin+1-toℕ) (toℕ-fromℕ< _) a ))
          ... | tri≈ ¬a₁ b ¬c | tri< a ¬b₁ ¬c₁  = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) fin+1-toℕ (sym (toℕ-fromℕ< _)) a ))
          ... | tri≈ ¬a₁ b ¬c | tri≈ ¬a₂ b₁ ¬c₁ = refl
          ... | tri≈ ¬a₁ b ¬c | tri> ¬a₂ ¬b₁ c₁ = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) fin+1-toℕ (sym (toℕ-fromℕ< _)) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri< a ¬b₂ ¬c = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) (sym fin+1-toℕ) (toℕ-fromℕ< _) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri≈ ¬a₂ b ¬c = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) (sym fin+1-toℕ) (toℕ-fromℕ< _) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri> ¬a₂ ¬b₂ c₂ =  f1-phase2 qs p (case2 q1 )
          f1-phase1 : (qs : List (Fin (suc n)) ) → fin-phase1 i (list-less qs) ≡ true
              → (fin-phase1 (fromℕ< a<sa) qs ≡ false ) ∨ (fin-phase2 (fromℕ< a<sa) qs ≡ false)
              → fin-phase1 (fin+1 i) qs ≡ true
          f1-phase1 (x ∷ qs) p (case1 q1) with  <-fcmp (fromℕ< a<sa) x
          ... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ x < suc k ) (sym fin<asa) (fin≤n _ )))
          f1-phase1 (x ∷ qs) p (case1 q1) | tri≈ ¬a b ¬c with <-fcmp (fin+1 i) x
          ... | tri< a ¬b ¬c₁ = f1-phase1 qs p (case2 q1)
          ... | tri≈ ¬a₁ b₁ ¬c₁ = ⊥-elim (fdup-10 b b₁) where
               fdup-10 : fromℕ< a<sa ≡ x → fin+1 i ≡ x → ⊥
               fdup-10 eq eq1 = nat-≡< (cong toℕ (trans eq1 (sym eq))) (subst₂ (λ j k → j < k ) (sym fin+1-toℕ) (sym fin<asa) fin<n )
          ... | tri> ¬a₁ ¬b c = f1-phase1 qs p (case2 q1)
          f1-phase1 (x ∷ qs) p (case1 q1) | tri> ¬a ¬b c with <-fcmp i (fromℕ< (≤-trans c (fin≤n (fromℕ< a<sa)))) | <-fcmp (fin+1 i) x
          ... | tri< a ¬b₁ ¬c | tri< a₁ ¬b₂ ¬c₁ = f1-phase1 qs p (case1 q1)
          ... | tri< a ¬b₁ ¬c | tri≈ ¬a₁ b ¬c₁  = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) (sym fin+1-toℕ) (toℕ-fromℕ< _) a ))
          ... | tri< a ¬b₁ ¬c | tri> ¬a₁ ¬b₂ c₁ = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) (sym fin+1-toℕ) (toℕ-fromℕ< _) a ))
          ... | tri≈ ¬a₁ b ¬c | tri< a ¬b₁ ¬c₁  = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) fin+1-toℕ (sym (toℕ-fromℕ< _)) a ))
          ... | tri≈ ¬a₁ b ¬c | tri≈ ¬a₂ b₁ ¬c₁ = f1-phase2 qs p (case1 q1)
          ... | tri≈ ¬a₁ b ¬c | tri> ¬a₂ ¬b₁ c₁ = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) fin+1-toℕ (sym (toℕ-fromℕ< _)) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri< a ¬b₂ ¬c = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) (sym fin+1-toℕ) (toℕ-fromℕ< _) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri≈ ¬a₂ b ¬c = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) (sym fin+1-toℕ) (toℕ-fromℕ< _) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri> ¬a₂ ¬b₂ c₂ = f1-phase1 qs p (case1 q1)
          f1-phase1 (x ∷ qs) p (case2 q1) with  <-fcmp (fromℕ< a<sa) x
          ... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ x < suc k ) (sym fin<asa) (fin≤n _ )))
          f1-phase1 (x ∷ qs) p (case2 q1) | tri≈ ¬a b ¬c = ⊥-elim ( ¬-bool q1 refl )
          f1-phase1 (x ∷ qs) p (case2 q1) | tri> ¬a ¬b c with <-fcmp i (fromℕ< (≤-trans c (fin≤n (fromℕ< a<sa)))) | <-fcmp (fin+1 i) x
          ... | tri< a ¬b₁ ¬c | tri< a₁ ¬b₂ ¬c₁ = f1-phase1 qs p (case2 q1)
          ... | tri< a ¬b₁ ¬c | tri≈ ¬a₁ b ¬c₁  = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) (sym fin+1-toℕ) (toℕ-fromℕ< _) a ))
          ... | tri< a ¬b₁ ¬c | tri> ¬a₁ ¬b₂ c₁ = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) (sym fin+1-toℕ) (toℕ-fromℕ< _) a ))
          ... | tri≈ ¬a₁ b ¬c | tri< a ¬b₁ ¬c₁  = ⊥-elim ( ¬a₁ (subst₂ (λ j k → j < k) fin+1-toℕ (sym (toℕ-fromℕ< _)) a ))
          ... | tri≈ ¬a₁ b ¬c | tri≈ ¬a₂ b₁ ¬c₁ = f1-phase2 qs p (case2 q1)
          ... | tri≈ ¬a₁ b ¬c | tri> ¬a₂ ¬b₁ c₁ = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) fin+1-toℕ (sym (toℕ-fromℕ< _)) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri< a ¬b₂ ¬c = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) (sym fin+1-toℕ) (toℕ-fromℕ< _) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri≈ ¬a₂ b ¬c = ⊥-elim ( ¬c (subst₂ (λ j k → j > k) (sym fin+1-toℕ) (toℕ-fromℕ< _) c₁ ))
          ... | tri> ¬a₁ ¬b₁ c₁ | tri> ¬a₂ ¬b₂ c₂ = f1-phase1 qs p (case2 q1)
     fdup-phase0 : FDup-in-list (suc n) qs
     fdup-phase0 with fin-dup-in-list (fromℕ< a<sa) qs | inspect (fin-dup-in-list (fromℕ< a<sa)) qs
     ... | true  | record { eq = eq } = record { dup = fromℕ< a<sa ; is-dup = eq }
     ... | false | record { eq = ne } = fdup+1 qs (FDup-in-list.dup fdup) ne (FDup-in-list.is-dup fdup)  where
           -- if no dup in the max element, the list without the element is only one length shorter
           fless : (qs : List (Fin (suc n))) → length qs > suc n  → fin-dup-in-list (fromℕ< a<sa) qs ≡ false → n < length (list-less qs)
           fless qs lt p = fl-phase1 n qs lt p where
               fl-phase2 : (n1 : ℕ) (qs : List (Fin (suc n))) → length qs > n1  → fin-phase2 (fromℕ< a<sa) qs ≡ false → n1 < length (list-less qs)
               fl-phase2 zero (x ∷ qs) (s≤s lt) p with  <-fcmp (fromℕ< a<sa) x
               ... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ x < suc k ) (sym fin<asa) (fin≤n _ )))
               ... | tri> ¬a ¬b c =  s≤s z≤n
               fl-phase2 (suc n1) (x ∷ qs) (s≤s lt) p with  <-fcmp (fromℕ< a<sa) x
               ... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ x < suc k ) (sym fin<asa) (fin≤n _ )))
               ... | tri> ¬a ¬b c = s≤s ( fl-phase2 n1 qs lt p )
               fl-phase1 : (n1 : ℕ) (qs : List (Fin (suc n))) → length qs > suc n1  → fin-phase1 (fromℕ< a<sa) qs ≡ false → n1 < length (list-less qs)
               fl-phase1 zero (x ∷ qs) (s≤s lt) p  with <-fcmp (fromℕ< a<sa) x
               ... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ x < suc k ) (sym fin<asa) (fin≤n _ )))
               ... | tri≈ ¬a b ¬c = fl-phase2 0 qs lt p
               ... | tri> ¬a ¬b c = s≤s z≤n
               fl-phase1 (suc n1) (x ∷ qs) (s≤s lt) p with <-fcmp (fromℕ< a<sa) x
               ... | tri< a ¬b ¬c = ⊥-elim ( nat-≤> a (subst (λ k → toℕ x < suc k ) (sym fin<asa) (fin≤n _ )))
               ... | tri≈ ¬a b ¬c = fl-phase2 (suc n1) qs lt p
               ... | tri> ¬a ¬b c = s≤s ( fl-phase1 n1 qs lt p )
           -- if the list without the max element is only one length shorter, we can recurse
           fdup : FDup-in-list n (list-less qs)
           fdup = fin-dup-in-list>n (list-less qs) (fless qs lt ne)


{-

Finite Types

This file formalize the notion of Rijke finite type,
which is a direct generalization of Bishop finite set.
Basically, a type is (Rijke) n-finite if its i-th order
homotopy groups πᵢ are Bishop finite for i ≤ n.

Referrences:
  https://github.com/EgbertRijke/OEIS-A000001

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

module Cubical.Data.FinType.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Structure

open import Cubical.HITs.SetTruncation

open import Cubical.Data.Nat
open import Cubical.Data.Sigma
open import Cubical.Data.FinSet

private
  variable
    ℓ ℓ' : Level
    n : ℕ
    X : Type ℓ

-- the (Rijke) finite type

isFinType : (n : ℕ) → Type ℓ → Type ℓ
isFinType 0 X = isFinSet ∥ X ∥₂
isFinType (suc n) X = (isFinType 0 X) × ((a b : X) → isFinType n (a ≡ b))

isPropIsFinType : isProp (isFinType n X)
isPropIsFinType {n = 0} = isPropIsFinSet
isPropIsFinType {n = suc n} = isProp× isPropIsFinSet (isPropΠ2 (λ _ _ → isPropIsFinType {n = n}))

-- the type of finite types

FinType : (ℓ : Level)(n : ℕ) → Type (ℓ-suc ℓ)
FinType ℓ n = TypeWithStr ℓ (isFinType n)

-- basic numerical implications

isFinTypeSuc→isFinType : isFinType (suc n) X → isFinType n X
isFinTypeSuc→isFinType {n = 0} p = p .fst
isFinTypeSuc→isFinType {n = suc n} p .fst = p .fst
isFinTypeSuc→isFinType {n = suc n} p .snd a b = isFinTypeSuc→isFinType {n = n} (p .snd a b)

isFinType→isFinType0 : isFinType n X → isFinType 0 X
isFinType→isFinType0 {n = 0} p = p
isFinType→isFinType0 {n = suc n} p = p .fst

isFinTypeSuc→isFinType1 : isFinType (suc n) X → isFinType 1 X
isFinTypeSuc→isFinType1 {n = 0} p = p
isFinTypeSuc→isFinType1 {n = suc n} p .fst = p .fst
isFinTypeSuc→isFinType1 {n = suc n} p .snd a b = isFinType→isFinType0 {n = suc n} (p .snd a b)


module Structure.Operator.Names where

open import Functional.Dependent
open import Function.Names
import      Lvl
open import Logic
open import Logic.Propositional
open import Logic.Predicate
open import Structure.Function.Names
open import Structure.Setoid
open import Syntax.Function
open import Syntax.Transitivity
open import Type

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

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} ⦃ _ : Equiv{ℓₑ₂}(T₂) ⦄ where
  -- Definition of commutativity of specific elements.
  -- The binary operation swapped yields the same result.
  -- Example: For any x, (x ▫ x) always commutes.
  Commuting : (T₁ → T₁ → T₂) → T₁ → T₁ → Stmt
  Commuting(_▫_) = pointwise₂,₂(_≡_) (_▫_) (swap(_▫_))

  -- Definition of commutativity.
  -- Order of application for the operation does not matter for equality.
  -- Example: Addition of the natural numbers (_+_ : ℕ → ℕ → ℕ).
  Commutativity : (T₁ → T₁ → T₂) → Stmt
  Commutativity = ∀² ∘ Commuting

  -- Definition of an left identity element.
  -- Example: Top implies a proposition in boolean logic (⊤ →_).
  Identityₗ : (T₁ → T₂ → T₂) → T₁ → Stmt
  Identityₗ (_▫_) id = ∀{x : T₂} → (id ▫ x) ≡ x

  -- Definition of a right absorber element
  -- Also called "right neutral element" or "right annihilator"
  -- Applying the operation on this element to the right always yields itself.
  -- Example: A proposition implies top in boolean logic (_→ ⊤).
  Absorberᵣ : (T₁ → T₂ → T₂) → T₂ → Stmt
  Absorberᵣ (_▫_) null = ∀{x : T₁} → (x ▫ null) ≡ null

  ConverseAbsorberᵣ : (T₁ → T₂ → T₂) → T₂ → Stmt
  ConverseAbsorberᵣ (_▫_)(a) = ∀{x y} → (x ▫ y ≡ a) → (y ≡ a)

module _ {T₁ : Type{ℓ₁}} ⦃ _ : Equiv{ℓₑ₁}(T₁) ⦄ {T₂ : Type{ℓ₂}} where
  -- Definition of an right identity element
  -- Example: Subtracting 0 for integers (_− 0).
  Identityᵣ : (T₁ → T₂ → T₁) → T₂ → Stmt
  Identityᵣ(_▫_) id = Identityₗ(swap(_▫_)) id

  -- Definition of a left absorber element
  -- Also called "left neutral element" or "left annihilator"
  -- Example: Subtraction (monus) of 0 for natural numbers (0 − ).
  Absorberₗ : (T₁ → T₂ → T₁) → T₁ → Stmt
  Absorberₗ(_▫_) null = Absorberᵣ(swap(_▫_)) null

  ConverseAbsorberₗ : (T₁ → T₂ → T₁) → T₁ → Stmt
  ConverseAbsorberₗ (_▫_)(a) = ∀{x y} → (x ▫ y ≡ a) → (x ≡ a)

module _ {T : Type{ℓ}} ⦃ _ : Equiv{ℓₑ}(T) ⦄ where
  -- Definition of an identity element
  -- Example: 0 for addition of integers, 1 for multiplication of integers.
  Identity : (T → T → T) → T → Stmt
  Identity (_▫_) id = (Identityₗ (_▫_) id) ∧ (Identityᵣ (_▫_) id)

  -- Definition of idempotence.
  Idempotence : (T → T → T) → Stmt
  Idempotence (_▫_) = ∀{x : T} → (x ▫ x ≡ x)

  -- Example: 0 for addition of natural numbers, 1 for multiplication of natural numbers.
  ConverseAbsorber : (T → T → T) → T → Stmt
  ConverseAbsorber (_▫_)(a) = ∀{x y} → (x ▫ y ≡ a) → (x ≡ a)∧(y ≡ a)

  -- Example: 0 for multiplication of natural numbers.
  WeakConverseAbsorber : (T → T → T) → T → Stmt
  WeakConverseAbsorber (_▫_)(a) = ∀{x y} → (x ▫ y ≡ a) → (x ≡ a)∨(y ≡ a)

module _ {T₊ : Type{ℓ₁}} {T₋ : Type{ℓ₂}} {Tᵣ : Type{ℓ₃}} ⦃ _ : Equiv{ℓₑᵣ}(Tᵣ) ⦄ where
  -- Definition of a left inverse element.
  InverseElementₗ : (T₋ → T₊ → Tᵣ) → Tᵣ → T₊ → T₋ → Stmt
  InverseElementₗ (_▫_) id x x⁻¹ = ((x⁻¹ ▫ x) ≡ id)

  -- Definition of a right inverse element
  InverseElementᵣ : (T₊ → T₋ → Tᵣ) → Tᵣ → T₊ → T₋ → Stmt
  InverseElementᵣ (_▫_) id x x⁻¹ = ((x ▫ x⁻¹) ≡ id)

  -- Definition of a left inverse function
  InverseFunctionₗ : (T₋ → T₊ → Tᵣ) → Tᵣ → (T₊ → T₋) → Stmt
  InverseFunctionₗ (_▫_) id inv = ∀{x : T₊} → InverseElementₗ(_▫_) id x (inv x)

  -- Definition of a right inverse function
  InverseFunctionᵣ : (T₊ → T₋ → Tᵣ) → Tᵣ → (T₊ → T₋) → Stmt
  InverseFunctionᵣ (_▫_) id inv = ∀{x : T₊} → InverseElementᵣ(_▫_) id x (inv x)

module _ {T : Type{ℓ₁}} {Tᵣ : Type{ℓ₂}} ⦃ _ : Equiv{ℓₑᵣ}(Tᵣ) ⦄ where
  -- Definition of an invertible element
  InverseElement : (T → T → Tᵣ) → Tᵣ → T → T → Stmt
  InverseElement (_▫_) id x x⁻¹ = (InverseElementₗ(_▫_) id x x⁻¹) ∧ (InverseElementᵣ(_▫_) id x x⁻¹)

  -- Definition of a function which returns the inverse element of the other side of the operation
  InverseFunction : (T → T → Tᵣ) → Tᵣ → (T → T) → Stmt
  InverseFunction (_▫_) id inv = (InverseFunctionₗ (_▫_) id inv) ∧ (InverseFunctionᵣ (_▫_) id inv)

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} ⦃ _ : Equiv{ℓₑ₂}(T₂) ⦄ {T₃ : Type{ℓ₃}} ⦃ _ : Equiv{ℓₑ₃}(T₃) ⦄ where
  -- Definition of right cancellation of a specific object
  -- ∀{a b : T₂} → ((x ▫ a) ≡ (x ▫ b)) → (a ≡ b)
  CancellationOnₗ : (T₁ → T₂ → T₃) → T₁ → Stmt
  CancellationOnₗ (_▫_) (x) = Injective(x ▫_)

  -- Definition of left cancellation (Injectivity for the right param)
  -- ∀{x : T₁}{a b : T₂} → ((x ▫ a) ≡ (x ▫ b)) → (a ≡ b)
  Cancellationₗ : (T₁ → T₂ → T₃) → Stmt
  Cancellationₗ (_▫_) = (∀{x : T₁} → CancellationOnₗ(_▫_)(x))

module _ {T₁ : Type{ℓ₁}} ⦃ _ : Equiv{ℓₑ₁}(T₁) ⦄ {T₂ : Type{ℓ₂}} {T₃ : Type{ℓ₃}} ⦃ _ : Equiv{ℓₑ₃}(T₃) ⦄ where
  -- Definition of right cancellation of a specific object
  -- ∀{a b : T₁} → ((a ▫ x) ≡ (b ▫ x)) → (a ≡ b)
  CancellationOnᵣ : (T₁ → T₂ → T₃) → T₂ → Stmt
  CancellationOnᵣ (_▫_) (x) = Injective(_▫ x)

  -- Definition of right cancellation (Injectivity for the left param)
  -- ∀{x : T₂}{a b : T₁} → ((a ▫ x) ≡ (b ▫ x)) → (a ≡ b)
  Cancellationᵣ : (T₁ → T₂ → T₃) → Stmt
  Cancellationᵣ (_▫_) = (∀{x : T₂} → CancellationOnᵣ (_▫_)(x))

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} {T₃ : Type{ℓ₃}} ⦃ _ : Equiv{ℓₑ₂}(T₂) ⦄ where
  -- Definition of the left inverse property
  InverseOperatorOnₗ : (T₁ → T₂ → T₃) → (T₁ → T₃ → T₂) → T₁ → T₂ → Stmt
  InverseOperatorOnₗ (_▫₁_) (_▫₂_) x y = (x ▫₂ (x ▫₁ y) ≡ y)

  InverseOperatorₗ : (T₁ → T₂ → T₃) → (T₁ → T₃ → T₂) → Stmt
  InverseOperatorₗ (_▫₁_)(_▫₂_) = ∀{x y} → InverseOperatorOnₗ(_▫₁_)(_▫₂_) x y

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} {T₃ : Type{ℓ₃}} ⦃ _ : Equiv{ℓₑ₁}(T₁) ⦄ where
  -- Definition of the right inverse property
  InverseOperatorOnᵣ : (T₁ → T₂ → T₃) → (T₃ → T₂ → T₁) → T₁ → T₂ → Stmt
  InverseOperatorOnᵣ (_▫₁_) (_▫₂_) x y = ((x ▫₁ y) ▫₂ y ≡ x)

  InverseOperatorᵣ : (T₁ → T₂ → T₃) → (T₃ → T₂ → T₁) → Stmt
  InverseOperatorᵣ (_▫₁_)(_▫₂_) = ∀{x y} → InverseOperatorOnᵣ(_▫₁_)(_▫₂_) x y

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} ⦃ _ : Equiv{ℓₑ₂}(T₂) ⦄ where
  InversePropertyₗ : (T₁ → T₂ → T₂) → (T₁ → T₁) → Stmt
  InversePropertyₗ (_▫_) inv = InverseOperatorₗ(_▫_)(a ↦ b ↦ inv(a) ▫ b)

  InversePropertyᵣ : (T₂ → T₁ → T₂) → (T₁ → T₁) → Stmt
  InversePropertyᵣ (_▫_) inv = InverseOperatorᵣ(_▫_)(a ↦ b ↦ a ▫ inv(b))

---------------------------------------------------------
-- Patterns

module _ {T₁ : Type{ℓ₁}}{T₂ : Type{ℓ₂}}{T₃ : Type{ℓ₃}}{Tᵣ₂ : Type{ℓᵣ₂}}{Tᵣ₃ : Type{ℓᵣ₃}}{Tᵣ : Type{ℓᵣ}} ⦃ _ : Equiv{ℓₑᵣ}(Tᵣ) ⦄ where
  AssociativityPattern : (T₁ → T₂ → Tᵣ₃) → (Tᵣ₃ → T₃ → Tᵣ)  → (T₁ → Tᵣ₂ → Tᵣ) → (T₂ → T₃ → Tᵣ₂)→ Stmt
  AssociativityPattern (_▫₁_) (_▫₂_) (_▫₃_) (_▫₄_) =
    ∀{x : T₁}{y : T₂}{z : T₃} → ((x ▫₁ y) ▫₂ z) ≡ (x ▫₃ (y ▫₄ z))

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} {T₃ : Type{ℓ₃}} ⦃ _ : Equiv{ℓₑ₃}(T₃) ⦄ where
  DistributivityPatternₗ : (T₁ → T₂ → T₃) → (T₂ → T₂ → T₂) → (T₃ → T₃ → T₃) → Stmt
  DistributivityPatternₗ (_▫₁_) (_▫₂_) (_▫₃_) =
    ∀{x : T₁} {y z : T₂} → (x ▫₁ (y ▫₂ z)) ≡ ((x ▫₁ y) ▫₃ (x ▫₁ z))

  DistributivityPatternᵣ : (T₁ → T₂ → T₃) → (T₁ → T₁ → T₁) → (T₃ → T₃ → T₃) → Stmt
  DistributivityPatternᵣ (_▫₁_) (_▫₂_) (_▫₃_) =
    ∀{x y : T₁} {z : T₂} → ((x ▫₂ y) ▫₁ z) ≡ ((x ▫₁ z) ▫₃ (y ▫₁ z))

---------------------------------------------------------
-- Derived

module _ {T : Type{ℓ}} ⦃ _ : Equiv{ℓₑ}(T) ⦄ where
  -- Definition of associativity for a binary operation
  Associativity : (T → T → T) → Stmt
  Associativity (_▫_) = AssociativityPattern (_▫_) (_▫_) (_▫_) (_▫_)
  -- {x y z : T} → ((x ▫ y) ▫ z) ≡ (x ▫ (y ▫ z))

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} ⦃ _ : Equiv{ℓₑ₂}(T₂) ⦄ where
  -- Definition of compatibility for a binary operation
  Compatibility : (T₁ → T₁ → T₁) → (T₁ → T₂ → T₂) → Stmt -- TODO: https://en.wikipedia.org/wiki/Semigroup_action
  Compatibility (_▫₁_) (_▫₂_) = AssociativityPattern (_▫₁_) (_▫₂_) (_▫₂_) (_▫₂_)
  -- {x₁ x₂ : T₁}{y : T₂} → ((x₁ ▫₁ x₂) ▫₂ y) ≡ (x₁ ▫₂ (x₂ ▫₂ y))

  -- Definition of left distributivity for a binary operation
  Distributivityₗ : (T₁ → T₂ → T₂) → (T₂ → T₂ → T₂) → Stmt
  Distributivityₗ (_▫₁_) (_▫₂_) = DistributivityPatternₗ (_▫₁_) (_▫₂_) (_▫₂_)
  -- ∀{x : T₁} {y z : T₂} → (x ▫₁ (y ▫₂ z)) ≡ (x ▫₁ y) ▫₂ (x ▫₁ z)

  -- Definition of right distributivity for a binary operation
  Distributivityᵣ : (T₂ → T₁ → T₂) → (T₂ → T₂ → T₂) → Stmt
  Distributivityᵣ (_▫₁_) (_▫₂_) = DistributivityPatternᵣ (_▫₁_) (_▫₂_) (_▫₂_)
  -- ∀{x y : T₂} {z : T₁} → ((x ▫₂ y) ▫₁ z) ≡ (x ▫₁ z) ▫₂ (y ▫₁ z)

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} {T₃ : Type{ℓ₃}} ⦃ _ : Equiv{ℓₑ₁}(T₁) ⦄ where
  -- Definition of left absorption for two binary operators
  Absorptionₗ : (T₁ → T₃ → T₁) → (T₁ → T₂ → T₃) → Stmt
  Absorptionₗ (_▫₁_)(_▫₂_) = ∀{x : T₁}{y : T₂} → (x ▫₁ (x ▫₂ y) ≡ x)

module _ {T₁ : Type{ℓ₁}} {T₂ : Type{ℓ₂}} {T₃ : Type{ℓ₃}} ⦃ _ : Equiv{ℓₑ₂}(T₂) ⦄ where
  -- Definition of right absorption for two binary operators
  Absorptionᵣ : (T₃ → T₂ → T₂) → (T₁ → T₂ → T₃) → Stmt
  Absorptionᵣ (_▫₁_)(_▫₂_) = ∀{x : T₁}{y : T₂} → ((x ▫₂ y) ▫₁ y ≡ y)

---------------------------------------------------------
-- Functions (TODO: Move to Structure.Operator.Proofs)
{-
open import Relator.Equals{ℓ₁}{ℓ₂}
open import Relator.Equals.Proofs{ℓ₁}{ℓ₂}

-- Returns a commuted LHS of an equality
commuteₗ : ∀{T}{_▫_}{x y z} → ⦃ _ : Commutativity {T} {T} (_▫_) ⦄ → ((x ▫ y) ≡ z) → ((y ▫ x) ≡ z)
commuteₗ ⦃ comm ⦄ stmt = comm 🝖 stmt

-- Returns a commuted RHS of an equality
commuteᵣ : ∀{T}{_▫_}{x y z} → ⦃ _ : Commutativity {T} {T} (_▫_) ⦄ → (z ≡ (x ▫ y)) → (z ≡ (y ▫ x))
commuteᵣ ⦃ comm ⦄ stmt = stmt 🝖 comm

commuteBoth : ∀{T₁ T₂}{_▫_}{a₁ a₂ b₁ b₂} → Commutativity{T₁}{T₂}(_▫_) → (a₁ ▫ a₂ ≡ b₁ ▫ b₂) → (a₂ ▫ a₁ ≡ b₂ ▫ b₁)
commuteBoth {_}{_} {a₁} {a₂} {b₁} {b₂} commutativity (a₁▫a₂≡b₁▫b₂) =
    (symmetry ⦃ [≡]-symmetry ⦄ (commutativity {a₁} {a₂}))
    🝖' (a₁▫a₂≡b₁▫b₂)
    🝖' (commutativity {b₁} {b₂})
    where
      _🝖'_ = _🝖_ ⦃ [≡]-transitivity ⦄
      infixl 1000 _🝖'_
-}


-- Andreas, AIM XXIII 2016-04-21 Overloaded projections

-- Milestone 1: Check overloaded projections on rhs (without postponing).

module _ (A : Set) (a : A) where

module RecDefs where

  record R B : Set where
    field f : B
  open R public

  record S B : Set where
    field f : B
  open S public

  record T B : Set where
    field f : B → B
  open T public

open RecDefs public

r : R A
R.f r = a

s : S A
S.f s = f r

t : R A → S A
S.f (t r) = f r

u : _
u = f s

v = f s

w : ∀{A} → T A → A → A
w t x = f t x


open import prelude

-- Copied pretty much verbatim

data Term : Set where
  true : Term
  false : Term
  if_then_else_end : Term → Term → Term → Term
  zero : Term
  succ : Term → Term
  iszero : Term → Term

data NValue : Term → Set where
  zero : NValue zero
  succ : ∀ {t} → NValue(t) → NValue(succ t)

data Value : Term → Set where
  true : Value true
  false :  Value false
  nv : ∀ {t} → NValue(t) → Value(t)

data _⟶_ : Term → Term → Set where

  E─IfTrue : ∀ {t₂ t₃} →

    -----------------------------------
    if true then t₂ else t₃ end ⟶ t₂

  E─IfFalse : ∀ {t₂ t₃} →

    -----------------------------------
    if false then t₂ else t₃ end ⟶ t₃

  E─IfCong : ∀ {t₁ t₁′ t₂ t₃} →

    (t₁ ⟶ t₁′) →
    ----------------------------------------------------------
    (if t₁ then t₂ else t₃ end ⟶ if t₁′ then t₂ else t₃ end)

  E─SuccCong : ∀ {t₁ t₁′} →

    (t₁ ⟶ t₁′) →
    ----------------------
    (succ t₁ ⟶ succ t₁′)

  E─IsZero :

    ----------------------
    (iszero zero ⟶ true)

  E─IsSucc : ∀ {n} →

    --------------------------
    (iszero (succ n) ⟶ false)

  E─IsCong : ∀ {t₁ t₁′} →

    (t₁ ⟶ t₁′) →
    --------------------------
    (iszero t₁ ⟶ iszero t₁′)

data Redex  : Term → Set where

  redex : ∀ {t t′} →

    t ⟶ t′ →
    --------
    Redex(t)

-- Types

data Type : Set where
  bool : Type
  nat : Type

data _∈_ : Term → Type → Set where

  T-True :

    -----------
    true ∈ bool

  T-False :

    -----------
    false ∈ bool

  T-If : ∀ {t₁ t₂ t₃ T} →

    t₁ ∈ bool →
    t₂ ∈ T →
    t₃ ∈ T →
    -----------------------------
    if t₁ then t₂ else t₃ end ∈ T

  T-Zero :

    ----------
    zero ∈ nat

  T-Succ : ∀ {t₁} →

    t₁ ∈ nat →
    -------------
    succ t₁ ∈ nat

  T-IsZero : ∀ {t₁} →

    t₁ ∈ nat →
    -------------
    iszero t₁ ∈ bool

-- Proving that well-typed terms stay well-typed

preservation : ∀ {t t′ T} → (t ∈ T) → (t ⟶ t′) → (t′ ∈ T)
preservation (T-If p₁ p₂ p₃) E─IfTrue = p₂
preservation (T-If p₁ p₂ p₃) E─IfFalse = p₃
preservation (T-If p₁ p₂ p₃) (E─IfCong q) = T-If (preservation p₁ q) p₂ p₃
preservation (T-Succ p) (E─SuccCong q) = T-Succ (preservation p q)
preservation (T-IsZero p) E─IsZero = T-True
preservation (T-IsZero p) E─IsSucc = T-False
preservation (T-IsZero p) (E─IsCong q) = T-IsZero (preservation p q)

-- Proving that every term is a value or a redex

data ValueOrRedex : Term → Set where

  value : ∀ {t} →

    (Value(t)) →
    ---------------
    ValueOrRedex(t)

  redex : ∀ {t t′} →

    t ⟶ t′ →
    ---------------
    ValueOrRedex(t)

progress : ∀ {t T} → (t ∈ T) → ValueOrRedex(t)
progress T-True = value true
progress T-False = value false
progress (T-If p₁ p₂ p₃) = helper (progress p₁) p₁ where

  helper : ∀ {t₀ t₁ t₂} → ValueOrRedex(t₀) → t₀ ∈ bool → ValueOrRedex(if t₀ then t₁ else t₂ end)
  helper (value true) p = redex E─IfTrue
  helper (value false) p = redex E─IfFalse
  helper (redex r) p = redex (E─IfCong r)
  helper (value (nv ())) T-True
  helper (value (nv ())) T-False
  helper (value (nv ())) (T-If p p₁ p₂)

progress T-Zero = value (nv zero)
progress (T-Succ p) = helper (progress p) p where

  helper : ∀ {t₀} → ValueOrRedex(t₀) → t₀ ∈ nat → ValueOrRedex(succ t₀)
  helper (value (nv n)) p = value (nv (succ n))
  helper (redex r) p = redex (E─SuccCong r)

progress (T-IsZero p) = helper (progress p) p where

  helper : ∀ {t₀} → ValueOrRedex(t₀) → t₀ ∈ nat → ValueOrRedex(iszero t₀)
  helper (value (nv zero)) p = redex E─IsZero
  helper (value (nv (succ x))) p = redex E─IsSucc
  helper (redex r) p = redex (E─IsCong r)

-- Interpreter

data _⟶*_ : Term → Term → Set where

  done : ∀ {t} →

    --------
    t ⟶* t

  redex : ∀ {t t′ t″} →

    t ⟶ t′ →
    t′ ⟶* t″ →
    ----------
    t ⟶* t″

-- An interpreter result

data Result  : Term → Set where

  result : ∀ {t t′} →

    t ⟶* t′ →
    Value(t′) →
    ---------
    Result(t)

-- The interpreter just calls `progress` until it is a value.
-- This might bot terminate!

{-# NON_TERMINATING #-}
interp : ∀ {t T} → (t ∈ T) → Result(t)
interp p = helper₂ p (progress p) where

  helper₁ : ∀ {t t′} → (t ⟶ t′) → Result(t′) → Result(t)
  helper₁ r (result s v) = result (redex r s) v

  helper₂ : ∀ {t T} → (t ∈ T) → ValueOrRedex(t) → Result(t)
  helper₂ p (value v) = result done v
  helper₂ p (redex r) = helper₁ r (interp (preservation p r))

ex = if (iszero zero) then (succ zero) else (zero) end

exNat : (ex ∈ nat)
exNat = T-If (T-IsZero T-Zero) (T-Succ T-Zero) T-Zero

-- Normalize (C-N) interp exNat
-- result
--   (redex (E─IfCong E─IsZero)
--     (redex E─IfTrue
--       done))
--   (nv (succ zero))


------------------------------------------------------------------------
-- Unary relations (variant for Set₁)
------------------------------------------------------------------------

-- I want universe polymorphism.

module Relation.Unary1 where

------------------------------------------------------------------------
-- Unary relations

Pred : Set → Set₂
Pred a = a → Set₁

------------------------------------------------------------------------
-- Unary relations can be seen as sets

-- I.e., they can be seen as subsets of the universe of discourse.

private
 module Dummy {a : Set} -- The universe of discourse.
          where

  -- Set membership.

  infix 4 _∈_

  _∈_ : a → Pred a → Set₁
  x ∈ P = P x

  -- The property of being universal.

  Universal : Pred a → Set₁
  Universal P = ∀ x → x ∈ P

  -- P ⊆ Q means that P is a subset of Q. _⊆′_ is a variant of _⊆_.

  infix 4 _⊆_ _⊇_ _⊆′_ _⊇′_

  _⊆_ : Pred a → Pred a → Set₁
  P ⊆ Q = ∀ {x} → x ∈ P → x ∈ Q

  _⊆′_ : Pred a → Pred a → Set₁
  P ⊆′ Q = ∀ x → x ∈ P → x ∈ Q

  _⊇_ : Pred a → Pred a → Set₁
  Q ⊇ P = P ⊆ Q

  _⊇′_ : Pred a → Pred a → Set₁
  Q ⊇′ P = P ⊆′ Q

open Dummy public


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

open import Algebra
open import Relation.Unary
open import Relation.Binary hiding (Decidable)

module Data.FingerTree.Split
  {r m}
  (ℳ : Monoid r m)
  {s}
  {ℙ : Pred (Monoid.Carrier ℳ) s}
  (ℙ-resp : ℙ Respects (Monoid._≈_ ℳ))
  (ℙ? : Decidable ℙ)
  where

open import Relation.Nullary using (¬_; yes; no; Dec)
open import Level using (_⊔_)
open import Data.Product
open import Function
open import Data.List as List using (List; _∷_; [])

open import Data.FingerTree.Measures ℳ
open import Data.FingerTree.Structures ℳ
open import Data.FingerTree.Reasoning ℳ
open import Data.FingerTree.View ℳ using (deepₗ; deepᵣ)
open import Data.FingerTree.Cons ℳ using (listToTree)

open import Relation.Nullary using (Dec; yes; no)
open import Relation.Nullary.Decidable using (True; toWitness; False; toWitnessFalse)

open σ ⦃ ... ⦄

open Monoid ℳ renaming (Carrier to 𝓡)

open import Data.FingerTree.Relation.Binary.Reasoning.FasterInference.Setoid setoid

open import Data.FingerTree.Split.Point ℳ ℙ-resp ℙ?
open import Data.FingerTree.Split.StoredPredicate ℳ ℙ-resp ℙ?
open import Data.FingerTree.Split.Intermediate ℳ ℙ-resp ℙ?
open import Data.FingerTree.Split.Structures ℳ ℙ-resp ℙ?

record Split {a} (Σ : Set a) ⦃ _ : σ Σ ⦄ : Set (a ⊔ r ⊔ m ⊔ s) where
  constructor _∷⟨_⟩∷_[_]
  field
    left : Tree Σ
    focus : Σ
    right : Tree Σ
    is-split : μ left ∣ μ focus
open Split public

instance
  σ-Split : ∀  {a} {Σ : Set a} ⦃ _ : σ Σ ⦄ → σ (Split Σ)
  μ ⦃ σ-Split ⦄ (l ∷⟨ x ⟩∷ r [ _ ]) = μ l ∙ (μ x ∙ μ r)

split : ∀ {a} {Σ : Set a} ⦃ _ : σ Σ ⦄
      → {¬ℙ⟨ε⟩ : False (ℙ? ε)}
      → (xs : Tree Σ)
      → {ℙ⟨xs⟩ : True (ℙ? (μ xs))}
      → μ⟨ Split Σ ⟩≈ μ xs
split {¬ℙ⟨ε⟩ = ¬ℙ⟨ε⟩} xs {ℙ⟨xs⟩} with splitTree ε xs (init-ℙ ¬ℙ⟨ε⟩ ℙ⟨xs⟩) ≈[ identityˡ _ ]
... | xs′ ∷⟨ x ⟩∷ ys [ p ] ⇑[ p₂ ] = xs′ ∷⟨ x ⟩∷ ys [ Relation.Nullary.recompute (_ ∣? _) p ≈◄⟅ identityˡ _ ⟆ ] ⇑[  sym (identityˡ _) ⍮ p₂ ]


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

open import Categories.Category
open import Categories.Monad

module Categories.Category.Construction.EilenbergMoore {o ℓ e} {C : Category o ℓ e} (M : Monad C) where

open import Level

open import Categories.Morphism.Reasoning C

private
  module C = Category C
  module M = Monad M
  open C
  open M.F
  open HomReasoning

record Module : Set (o ⊔ ℓ ⊔ e) where
  field
    A        : Obj
    action   : F₀ A ⇒ A
    commute  : action ∘ F₁ action ≈ action ∘ M.μ.η A
    identity : action ∘ M.η.η A ≈ C.id

record Module⇒ (X Y : Module) : Set (ℓ ⊔ e) where
  private
    module X = Module X
    module Y = Module Y
  field
    arr     : X.A ⇒ Y.A
    commute : arr ∘ X.action ≈ Y.action ∘ F₁ arr

EilenbergMoore : Category (o ⊔ ℓ ⊔ e) (ℓ ⊔ e) e
EilenbergMoore = record
  { Obj       = Module
  ; _⇒_       = Module⇒
  ; _≈_       = λ f g → Module⇒.arr f ≈ Module⇒.arr g
  ; id        = record
    { arr     = C.id
    ; commute = id-comm-sym ○ ∘-resp-≈ʳ (⟺ identity)
    }
  ; _∘_       = compose
  ; assoc     = assoc
  ; sym-assoc = sym-assoc
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; identity² = identity²
  ; equiv     = record
    { refl  = refl
    ; sym   = sym
    ; trans = trans
    }
  ; ∘-resp-≈  = ∘-resp-≈
  }
  where compose : ∀ {X Y Z} → Module⇒ Y Z → Module⇒ X Y → Module⇒ X Z
        compose {X} {Y} {Z} f g = record
          { arr     = f.arr ∘ g.arr
          ; commute = begin
            (f.arr ∘ g.arr) ∘ Module.action X       ≈⟨ pullʳ g.commute ⟩
            f.arr ∘ Module.action Y ∘ F₁ g.arr      ≈⟨ pullˡ f.commute ⟩
            (Module.action Z ∘ F₁ f.arr) ∘ F₁ g.arr ≈˘⟨ pushʳ homomorphism ⟩
            Module.action Z ∘ F₁ (f.arr ∘ g.arr)    ∎
          }
          where module f = Module⇒ f
                module g = Module⇒ g


------------------------------------------------------------------------
-- The Agda standard library
--
-- Subsets of finite sets
------------------------------------------------------------------------

module Data.Fin.Subset where

open import Algebra
import Algebra.Properties.BooleanAlgebra as BoolAlgProp
import Algebra.Properties.BooleanAlgebra.Expression as BAExpr
import Data.Bool.Properties as BoolProp
open import Data.Fin
open import Data.List as List using (List)
open import Data.Nat
open import Data.Product
open import Data.Vec using (Vec; _∷_; _[_]=_)
import Relation.Binary.Vec.Pointwise as Pointwise
open import Relation.Nullary

infix 4 _∈_ _∉_ _⊆_ _⊈_

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

-- Sides.

open import Data.Bool public
  using () renaming (Bool to Side; true to inside; false to outside)

-- Partitions a finite set into two parts, the inside and the outside.

Subset : ℕ → Set
Subset = Vec Side

------------------------------------------------------------------------
-- Membership and subset predicates

_∈_ : ∀ {n} → Fin n → Subset n → Set
x ∈ p = p [ x ]= inside

_∉_ : ∀ {n} → Fin n → Subset n → Set
x ∉ p = ¬ (x ∈ p)

_⊆_ : ∀ {n} → Subset n → Subset n → Set
p₁ ⊆ p₂ = ∀ {x} → x ∈ p₁ → x ∈ p₂

_⊈_ : ∀ {n} → Subset n → Subset n → Set
p₁ ⊈ p₂ = ¬ (p₁ ⊆ p₂)

------------------------------------------------------------------------
-- Set operations

-- Pointwise lifting of the usual boolean algebra for booleans gives
-- us a boolean algebra for subsets.
--
-- The underlying equality of the returned boolean algebra is
-- propositional equality.

booleanAlgebra : ℕ → BooleanAlgebra _ _
booleanAlgebra n =
  BoolAlgProp.replace-equality
    (BAExpr.lift BoolProp.booleanAlgebra n)
    Pointwise.Pointwise-≡

private
  open module BA {n} = BooleanAlgebra (booleanAlgebra n) public
    using
      ( ⊥  -- The empty subset.
      ; ⊤  -- The subset containing all elements.
      )
    renaming
      ( _∨_ to _∪_  -- Binary union.
      ; _∧_ to _∩_  -- Binary intersection.
      ; ¬_  to ∁    -- Complement.
      )

-- A singleton subset, containing just the given element.

⁅_⁆ : ∀ {n} → Fin n → Subset n
⁅ zero  ⁆ = inside  ∷ ⊥
⁅ suc i ⁆ = outside ∷ ⁅ i ⁆

-- N-ary union.

⋃ : ∀ {n} → List (Subset n) → Subset n
⋃ = List.foldr _∪_ ⊥

-- N-ary intersection.

⋂ : ∀ {n} → List (Subset n) → Subset n
⋂ = List.foldr _∩_ ⊤

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

Nonempty : ∀ {n} (p : Subset n) → Set
Nonempty p = ∃ λ f → f ∈ p

Empty : ∀ {n} (p : Subset n) → Set
Empty p = ¬ Nonempty p

-- Point-wise lifting of properties.

Lift : ∀ {n} → (Fin n → Set) → (Subset n → Set)
Lift P p = ∀ {x} → x ∈ p → P x


module Category.Core where

open import Level
open import Data.Product
-- open import Relation.Binary as B using ()
open import Relation.Binary as B using ()
open import Relation.Binary.Indexed
open import Relation.Binary.PropositionalEquality as PropEq using (_≡_; refl)

record IsMorphism   {𝒸 ℓ : Level}
                    {Object : Set 𝒸}
                    {Carrier : (Object × Object) → Set 𝒸}
                    (_≈_ : Rel Carrier ℓ)
                    (_∘_ : ∀ {a b c} → Carrier (b , c) → Carrier (a , b) → Carrier (a , c))
                    (id : (a : Object) → Carrier (a , a))
                    : Set (suc (𝒸 ⊔ ℓ)) where
    _⇒_ = curry Carrier
    field
        assoc : ∀ {a b c d : Object}
            → (f : a ⇒ b) → (g : b ⇒ c) → (h : c ⇒ d)
            → ((h ∘ g) ∘ f) ≈ (h ∘ (g ∘ f))
        left-identity : ∀ {a b : Object}
            → (f : a ⇒ b)
            → (id b ∘ f) ≈ f
        right-identity : ∀ {a b : Object}
            → (f : a ⇒ b)
            → (f ∘ id a) ≈ f
        cong : ∀ {a b c a' b' c' : Object}
            {x : Carrier (b , c)} {y : Carrier (b' , c')}
            {u : Carrier (a , b)} {v : Carrier (a' , b')}
            → x ≈ y → u ≈ v → (x ∘ u) ≈ (y ∘ v)

record MorphismStructure (𝒸 ℓ : Level) (Object : Set 𝒸) : Set (suc (𝒸 ⊔ ℓ)) where
    infixr 9 _∘_
    infix 4 _≈_
    field
        Carrier : (Object × Object) → Set 𝒸
        _≈_ : Rel Carrier ℓ
        isEquivalence : IsEquivalence Carrier _≈_

    setoid : Setoid (Object × Object) _ _
    setoid = record { isEquivalence = isEquivalence }

    -- Arrows
    _⇒_ : Object → Object → Set 𝒸
    _⇒_ = curry Carrier

    field
        _∘_ : ∀ {a b c : Object}
            → b ⇒ c
            → a ⇒ b
            → a ⇒ c
        id : (a : Object) → a ⇒ a
        isMorphism : IsMorphism _≈_ _∘_ id

record Category (𝒸 ℓ : Level) : Set (suc (𝒸 ⊔ ℓ)) where

    field
        Objects : B.Setoid 𝒸 ℓ

    Object : Set 𝒸
    Object = B.Setoid.Carrier Objects

    _≈o_ : Object → Object → Set ℓ
    _≈o_ = B.Setoid._≈_ Objects

    field
        Morphisms : MorphismStructure 𝒸 ℓ Object

    open MorphismStructure Morphisms public

    hom[-,_] : Object → Set 𝒸
    hom[-, b ] = Σ[ a ∈ Object ] a ⇒ b

    -- hom[_,_] : Object → Object → Set 𝒸
    -- hom[ a , b ] = a ⇒ b

record IsFunctor {𝒸₀ ℓ₀ 𝒸₁ ℓ₁ : Level}
    {C : Category 𝒸₀ ℓ₀} {D : Category 𝒸₁ ℓ₁}
    (mapObject : Category.Object C → Category.Object D)
    (mapMorphism : ∀ {a b}
            → (Category._⇒_ C) a             b
            → (Category._⇒_ D) (mapObject a) (mapObject b))
    : Set (𝒸₀ ⊔ ℓ₀ ⊔ 𝒸₁ ⊔ ℓ₁) where

    module C = Category C
    open Category D

    field
        preserve-id : (a : C.Object)
            → mapMorphism (C.id a) ≈ id (mapObject a)
        preserve-∘ : {a b c : C.Object} (f : a C.⇒ b) (g : b C.⇒ c)
            → mapMorphism (C._∘_ g f) ≈ mapMorphism g ∘ mapMorphism f

record Functor {𝒸₀ ℓ₀ 𝒸₁ ℓ₁ : Level}
    (C : Category 𝒸₀ ℓ₀) (D : Category 𝒸₁ ℓ₁) : Set (𝒸₀ ⊔ ℓ₀ ⊔ 𝒸₁ ⊔ ℓ₁) where
    module C = Category C
    module D = Category D
    field
        mapObject : C.Object → D.Object
        mapMorphism : ∀ {a b} → a C.⇒ b → mapObject a D.⇒ mapObject b
        isFunctor : IsFunctor {𝒸₀} {ℓ₀} {𝒸₁} {ℓ₁} {C} {D} mapObject mapMorphism


------------------------------------------------------------------------
-- The Agda standard library
--
-- Data.List.Any.Membership instantiated with propositional equality,
-- along with some additional definitions.
------------------------------------------------------------------------

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

module Data.List.Membership.Propositional {a} {A : Set a} where

open import Data.List.Relation.Unary.Any using (Any)
open import Relation.Binary.PropositionalEquality using (setoid; subst)

import Data.List.Membership.Setoid as SetoidMembership

------------------------------------------------------------------------
-- Re-export contents of setoid membership

open SetoidMembership (setoid A) public hiding (lose)

------------------------------------------------------------------------
-- Other operations

lose : ∀ {p} {P : A → Set p} {x xs} → x ∈ xs → P x → Any P xs
lose = SetoidMembership.lose (setoid A) (subst _)


open import Data.Product using ( _×_ ; _,_ )
open import FRP.LTL.ISet.Core using ( ISet ; MSet ; [_] ; _⇛_ ; _,_ )
open import FRP.LTL.Time using ( _+_ ; +-resp-≤ ; +-resp-< )
open import FRP.LTL.Time.Bound using
  ( Time∞ ; +∞ ; fin ; _≼_ ; _≺_ ; +∞-top ; ≤-impl-≼ ; t≺+∞ ; ≺-impl-⋡ ; ≺-impl-< ; <-impl-≺ )
open import FRP.LTL.Time.Interval using ( Interval ; [_⟩ ; _⊑_ ; _~_ ; _⌢_∵_ ; _,_ )
open import FRP.LTL.Util using ( ⊥-elim )
open import Relation.Binary.PropositionalEquality using ( refl )

module FRP.LTL.ISet.Next where

-- ○ A is "A holds at the next point in time"

next : Time∞ → Time∞
next +∞      = +∞
next (fin t) = fin (t + 1)

next-resp-≼ : ∀ {t u} → (t ≼ u) → (next t ≼ next u)
next-resp-≼ +∞-top         = +∞-top
next-resp-≼ (≤-impl-≼ t≤u) = ≤-impl-≼ (+-resp-≤ t≤u 1)

next-resp-≺ : ∀ {t u} → (t ≺ u) → (next t ≺ next u)
next-resp-≺ {+∞}            t≺u = ⊥-elim (≺-impl-⋡ t≺u +∞-top)
next-resp-≺ {fin t} {+∞}    t≺u = t≺+∞
next-resp-≺ {fin t} {fin u} t≺u = <-impl-≺ (+-resp-< (≺-impl-< t≺u) 1)

Next : MSet → MSet
Next (A , split , subsum) = (○A , ○split , ○subsum) where

  ○A : Interval → Set
  ○A [ s≺t ⟩ = A [ next-resp-≺ s≺t ⟩

  ○split : ∀ i j i~j → ○A (i ⌢ j ∵ i~j) → (○A i × ○A j)
  ○split [ s≺t ⟩ [ t≺u ⟩ refl =
    split [ next-resp-≺ s≺t ⟩ [ next-resp-≺ t≺u ⟩ refl

  ○subsum : ∀ i j → (i ⊑ j) → ○A j → ○A i
  ○subsum [ s≺t ⟩ [ r≺u ⟩ (r≼s , t≼u) =
    subsum [ next-resp-≺ s≺t ⟩ [ next-resp-≺ r≺u ⟩ (next-resp-≼ r≼s , next-resp-≼ t≼u)

○ : ISet → ISet
○ ([ A ]) = [ Next A ]
○ (A ⇛ B) = Next A ⇛ ○ B


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

module Cubical.Categories.Type where

open import Cubical.Foundations.Prelude
open import Cubical.Categories.Category

open Precategory

module _ ℓ where
  TYPE : Precategory (ℓ-suc ℓ) ℓ
  TYPE .ob = Type ℓ
  TYPE .Hom[_,_] A B = A → B
  TYPE .id A  = λ x → x
  TYPE ._⋆_ f g = λ x → g (f x)
  TYPE .⋆IdL f = refl
  TYPE .⋆IdR f = refl
  TYPE .⋆Assoc f g h = refl


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

-- I think that the idea behind this library is originally Ulf
-- Norell's. I have adapted it to my tastes and mixfix operators,
-- though.

-- If you need to use several instances of this module in a given
-- file, then you can use the following approach:
--
--   import Relation.Binary.PreorderReasoning as Pre
--
--   f x y z = begin
--     ...
--       ∎
--     where open Pre preorder₁
--
--   g i j = begin
--     ...
--       ∎
--     where open Pre preorder₂

open import Relation.Binary

module Relation.Binary.PreorderReasoning
         {p₁ p₂ p₃} (P : Preorder p₁ p₂ p₃) where

open Preorder P

infix  4 _IsRelatedTo_
infix  2 _∎
infixr 2 _∼⟨_⟩_ _≈⟨_⟩_ _≈⟨⟩_
infix  1 begin_

-- This seemingly unnecessary type is used to make it possible to
-- infer arguments even if the underlying equality evaluates.

data _IsRelatedTo_ (x y : Carrier) : Set p₃ where
  relTo : (x∼y : x ∼ y) → x IsRelatedTo y

begin_ : ∀ {x y} → x IsRelatedTo y → x ∼ y
begin relTo x∼y = x∼y

_∼⟨_⟩_ : ∀ x {y z} → x ∼ y → y IsRelatedTo z → x IsRelatedTo z
_ ∼⟨ x∼y ⟩ relTo y∼z = relTo (trans x∼y y∼z)

_≈⟨_⟩_ : ∀ x {y z} → x ≈ y → y IsRelatedTo z → x IsRelatedTo z
_ ≈⟨ x≈y ⟩ relTo y∼z = relTo (trans (reflexive x≈y) y∼z)

_≈⟨⟩_ : ∀ x {y} → x IsRelatedTo y → x IsRelatedTo y
_ ≈⟨⟩ x∼y = x∼y

_∎ : ∀ x → x IsRelatedTo x
_∎ _ = relTo refl


{-# OPTIONS --allow-unsolved-metas #-}

open import Agda.Primitive using (Level)
module Tutorials.Monday where

-- Two dashes to comment out the rest of the line
{-
  Opening {-
  and closing -}
  for a multi-line comment
-}

-- In Agda all the tokens are tokenised using whitespace (with the exception of parentheses and some other symbols)
-- Agda offers unicode support
-- We can input unicode using the backslash \ and (most of the time) typing what one would type in LaTeX
-- If in emacs, we can put the cursor over a characted and use M-x describe-char to see how that character is inputted
-- ⊥ is written using \bot
data ⊥ : Set where
  -- AKA the empty set, bottom, falsehood, the absurd type, the empty type, the initial object
  -- ⊥ : Set means ⊥ is a Type (Set = Type, for historical reasons)
  -- The data keyword creates a data type where we list all the constructors of the types
  -- ⊥ has no constructors: there is no way of making something of type ⊥

record ⊤ : Set where
  -- AKA the singleton set, top, truth, the trivial type, the unit type, the terminal object
  -- The record keyword creates a record type
  -- Records have a single constructor
  -- To create a record you must populate all of its fields
  -- ⊤ has no fields: it is trivial to make one, and contains no information
  constructor tt

data Bool : Set where
  -- Bool has two constructors: one bit worth of information
  true : Bool
  false : Bool

--------
-- Simple composite types
--------

module Simple where
  record _×_ (A : Set) (B : Set) : Set where
    -- AKA logical and, product type

    -- Agda offers support for mixfix notation
    -- We use the underscores to specify where the arguments goal
    -- In this case the arguments are the type parameters A and B, so we can write A × B

    -- A × B models a type packing up *both* an A *and* a B
    -- A and B are type parameters, both of type Set, i.e. types
    -- A × B itself is of type Set, i.e. a type
    -- We use the single record constructor _,_ to make something of type A × B
    -- The constructor _,_ takes two parameters: the fields fst and snd, of type A and B, respectively
    -- If we have a of type A and b of type B, then (a , b) is of type A × B
    constructor _,_
    field
      fst : A
      snd : B

  -- Agda has a very expressive module system (more on modules later)
  -- Every record has a module automatically attached to it
  -- Opening a record exposes its constructor and it fields
  -- The fields are projection functions out of the record
  -- In the case of _×_, it exposes
  -- fst : A × B → A
  -- snd : A × B → B
  open _×_

  data _⊎_ (A B : Set) : Set where
    -- AKA logical or, sum type, disjoint union
    -- A ⊎ B models a type packing *either* an A *or* a B
    -- A and B are type parameters, both of type Set, i.e. types
    -- A ⊎ B itself is of type Set, i.e. a type
    -- A ⊎ B has two constructors: inl and inr
    -- The constructor inl takes something of type A as an argument and returns something of type A ⊎ B
    -- The constructor inr takes something of type B as an argument and returns something of type A ⊎ B
    -- We can make something of type A ⊎ B either by using inl and supplying an A, or by using inr and supplying a B
    inl : A → A ⊎ B
    inr : B → A ⊎ B

  --------
  -- Some simple proofs!
  --------

  -- In constructive mathematics logical implication is modelled as function types
  -- An object of type A → B shows that assuming an object of type A, we can construct an object of type B
  -- Below we want to show that assuming an object of type A × B, we can construct an object of type A
  -- We want to show that this is the case regardless of what A and B actually are
  -- We do this using a polymorphic function that is parametrised over A and B, both of type Set
  -- We use curly braces {} to make these function parameters implicit
  -- When we call this function we won't have to supply the arguments A and B unless we want to
  -- When we define this function we won't have to accept A and B as arguments unless we want to
  -- The first line below gives the type of the function get-fst
  -- The second line gives its definition
  get-fst : {A : Set} {B : Set} → A × B → A
  get-fst x = {!!}

  -- Agda is an *interactive* proof assistant
  -- We don't provide our proofs/programs all at once: we develop them iteratively
  -- We write ? where we don't yet have a program to provide, and we reload the file
  -- What we get back is a hole where we can place the cursor and have a conversation with Agda
  -- ctrl+c is the prefix that we use to communicate with Agda
  -- ctrl+c ctrl+l     reload the file
  -- ctrl+c ctrl+,     shows the goal and the context
  -- ctrl+c ctrl+.     shows the goal, the context, and what we have so far
  -- ctrl+c ctrl+c     pattern matches against a given arguments
  -- ctrl+c ctrl+space fill in hole
  -- ctrl+c ctrl+r     refines the goal: it will ask Agda to insert the first constructor we need
  -- ctrl+c ctrl+a     try to automatically fulfill the goal
  -- key bindings: https://agda.readthedocs.io/en/v2.6.1.3/getting-started/quick-guide.html
  get-snd : ∀ {A B} → A × B → B
  get-snd x = {!!}

  -- The variable keyword enables us to declare convention for notation
  -- Unless said otherwise, whenever we refer to A, B or C and these are not bound, we will refer to objects of type Set
  variable
    ℓ : Level
    A B C : Set ℓ

  -- Notice how we don't have to declare A, B and C anymore
  curry : (A → B → C) → (A × B → C)
  curry f = {!!}

  uncurry : (A × B → C) → (A → B → C)
  uncurry f = {!!}

  ×-comm : A × B → B × A
  ×-comm = {!!}

  ×-assoc : (A × B) × C → A × (B × C)
  ×-assoc = {!!}

  -- Pattern matching has to be exhaustive: all cases must be addressed
  ⊎-comm : A ⊎ B → B ⊎ A
  ⊎-comm = {!!}

  ⊎-assoc : (A ⊎ B) ⊎ C → A ⊎ (B ⊎ C)
  ⊎-assoc = {!!}

  -- If there are no cases to be addressed there is nothing for us left to do
  -- If you believe ⊥ exist you believe anything
  absurd : ⊥ → A
  absurd a = {!!}

  -- In constructive mathematics all proofs are constructions
  -- How do we show that an object of type A cannot possibly be constructed, while using a construction to show so?
  -- We take the cannonically impossible-to-construct object ⊥, and show that if we were to assume the existence of A, we could use it to construct ⊥
  ¬_ : Set ℓ → Set ℓ
  ¬ A = A → ⊥

  -- In classical logic double negation can be eliminated: ¬ ¬ A ⇒ A
  -- That is however not the case in constructive mathematics:
  -- The proof ¬ ¬ A is a function that takes (A → ⊥) into ⊥, and offers no witness for A
  -- The opposite direction is however constructive:
  ⇒¬¬ : A → ¬ ¬ A
  ⇒¬¬ = {!!}

  -- Moreover, double negation can be eliminated from non-witnesses
  ¬¬¬⇒¬ : ¬ ¬ ¬ A → ¬ A
  ¬¬¬⇒¬ = {!!}

  -- Here we have a choice of two programs to write
  ×-⇒-⊎₁ : A × B → A ⊎ B
  ×-⇒-⊎₁ = {!!}

  ×-⇒-⊎₂ : A × B → A ⊎ B
  ×-⇒-⊎₂ = {!!}

  -- A little more involved
  -- Show that the implication (A ⊎ B → A × B) is not always true for all A and Bs
  ⊎-⇏-× : ¬ (∀ {A B} → A ⊎ B → A × B)
  ⊎-⇏-× f = {!!}

variable
  ℓ : Level
  A B C : Set ℓ

--------
-- Inductive data types
--------

data ℕ : Set where
  -- The type of unary natural numbers
  -- The zero constructor takes no arguments; the base case
  -- The suc constructor takes one argument: an existing natural number; the inductive case
  -- We represent natural numbers by using ticks: ||| ≈ 3
  -- zero: no ticks
  -- suc: one more tick
  -- suc (suc (suc zero)) ≈ ||| ≈ 3
  zero : ℕ
  suc  : ℕ → ℕ

three : ℕ
three = suc (suc (suc zero))

-- Compiler pragmas allow us to give instructions to Agda
-- They are introduced with an opening {-# and a closing #-}
-- Here we the pragma BUILTIN to tell Agda to use ℕ as the builtin type for natural numbers
-- This allows us to say 3 instead of suc (suc (suc zero))
{-# BUILTIN NATURAL ℕ #-}
three' : ℕ
three' = 3

-- Whenever we say n or m and they haven't been bound, they refer to natural numbers
variable
  n m l : ℕ

-- Brief interlude: we declare the fixity of certain functions
-- By default, all definitions have precedence 20
-- The higher the precedence, the tighter they bind
-- Here we also declare that _+_ is left associative, i.e. 1 + 2 + 3 is parsed as (1 + 2) + 3
infixl 20 _+_

-- Define addition of natural numbers by structural recursion
_+_ : ℕ → ℕ → ℕ
x + y = {!!}

-- In functions recursion must always occur on structurally smaller values (otherwise the computation might never terminate)
-- In Agda *all computations must terminate*
-- We can tell Agda to ignore non-termination with this pragma
{-# TERMINATING #-}
non-terminating : ℕ → ℕ
non-terminating n = non-terminating n

-- However, doing so would allow us to define elements of the type ⊥
-- This is not considered safe: running Agda with the --safe option will make type-checking fail
{-# TERMINATING #-}
loop : ⊥
loop = loop

-- Use structural recursion to define multiplication
_*_ : ℕ → ℕ → ℕ
x * y = {!!}

-- The module keyword allows us to define modules (namespaces)
module List where
  infixr 15 _∷_ _++_
  data List (A : Set) : Set where
    -- Lists are another example of inductive types
    -- The type parameter A is the type of every element in the list
    -- They are like natural numbers, but the successor case contains an A
    []  : List A
    _∷_ : A → List A → List A

  -- List concatenation by structural recursion
  _++_ : List A → List A → List A
  [] ++ ys = ys
  (x ∷ xs) ++ ys = x ∷ (xs ++ ys)

  -- Apply a function (A → B) to every element of a list
  map : (A → B) → List A → List B
  map = {!!}

  -- A base case B and an inductive case A → B → B is all we need to take a List A and make a B
  foldr : (A → B → B) → B → List A → B
  foldr f b [] = b
  foldr f b (x ∷ xs) = f x (foldr f b xs)

--------
-- Dependent Types
--------

-- Dependent types are types that depend on values, objects of another type
-- Dependent types allow us to model predicates on types
-- A predicate P on a type A is a function taking elements of A into types
Pred : Set → Set₁
Pred A = A → Set

-- Let us define a predicate on ℕ that models the even numbers
-- Even numbers are taken to the type ⊤, which is trivial to satisfy
-- Odd numbers are taken to the type ⊥, which is impossible to satisfy
Even : Pred ℕ
Even x = {!!}

-- We can now use Even as a precondition on a previous arguments
-- Here we bind the first argument of type ℕ to the name n
-- We then use n as an argument to the type Even
-- As we expose the constructors of n, Even will compute
half : (n : ℕ) → Even n → ℕ
half n n-even = {!!}

-- There is an alternative way of definiting dependent types
-- EvenData is a data type indexed by elements of the type ℕ
-- That is, for every (n : ℕ), EvenData n is a type
-- The constructor zero constructs an element of the type EvenData zero
-- The constructor 2+_ takes an element of the type EvenData n and constructs one of type EvenData (suc (suc n))
-- Note that there is no constructors that constructs elements of the type Evendata (suc zero)
data EvenData : ℕ → Set where -- Pred ℕ
  zero : EvenData zero
  2+_  : EvenData n → EvenData (suc (suc n))

-- We can use EvenData as a precondition too
-- The difference is that while Even n computes automatically, we have to take EvenData n appart by pattern matching
-- It leaves a trace of *why* n is even
half-data : (n : ℕ) → EvenData n → ℕ
half-data n n-even = {!!}

-- Function composition: (f ∘ g) composes two functions f and g
-- The result takes the input, feeds it through g, then feeds the result through f
infixr 20 _∘_
_∘_ : (B → C) → (A → B) → (A → C)
(f ∘ g) x = f (g x)

--------
-- Example of common uses of dependent types
--------

module Fin where
  -- The type Fin n has n distinct inhabitants
  data Fin : ℕ → Set where
    zero : Fin (suc n)
    suc  : Fin n → Fin (suc n)

  -- Note that there is no constructor for Fin zero
  Fin0 : Fin zero → ⊥
  Fin0 x = {!!}

  -- We can erase the type level information to get a ℕ back
  to-ℕ : Fin n → ℕ
  to-ℕ zero = zero
  to-ℕ (suc x) = suc (to-ℕ x)

module Vec where
  open Fin

  -- Vectors are like lists, but they keep track of their length
  -- The type Vec A n is the type of lists of length n containing values of type A
  -- Notice that while A is a parameter (remains unchanged in all constructors), n is an index
  -- We can bind parameters to names (since they don't change) but we cannot bind indices
  data Vec (A : Set) : ℕ → Set where
    []  : Vec A zero
    _∷_ : A → Vec A n → Vec A (suc n)

  -- Now we can define concatenation, but giving more assurances about the resulting length
  _++_ : Vec A n → Vec A m → Vec A (n + m)
  xs ++ ys = {!!}

  map : (A → B) → Vec A n → Vec B n
  map = {!!}

  -- Given a vector and a fin, we can use the latter as a lookup index into the former
  -- Question: what happens if there vector is empty?
  _!_ : Vec A n → Fin n → A
  xs ! i = {!!}

  -- A vector Vec A n is just the inductive form of a function Fin n → A
  tabulate : ∀ {n} → (Fin n → A) → Vec A n
  tabulate {n = zero}  f = []
  tabulate {n = suc n} f = f zero ∷ tabulate (f ∘ suc)

  untabulate : Vec A n → (Fin n → A)
  untabulate [] ()
  untabulate (x ∷ xs) zero = x
  untabulate (x ∷ xs) (suc i) = untabulate xs i

-- Predicates need not be unary, they can be binary! (i.e. relations)
Rel : Set → Set₁
Rel A = A → A → Set

-- Question: how many proofs are there for any n ≤ m
data _≤_ : Rel ℕ where
  z≤n :         zero  ≤ n
  s≤s : n ≤ m → suc n ≤ suc m

_<_ : ℕ → ℕ → Set
n < m = suc n ≤ m

-- _≤_ is reflexive and transitive
≤-refl : ∀ n → n ≤ n
≤-refl n = {!!}

≤-trans : n ≤ m → m ≤ l → n ≤ l
≤-trans a b = {!!}

-----------
-- Propositional Equality
-----------

-- Things get interesting: we can use type indices to define propositional equality
-- For any (x y : A) the type x ≡ y is a proof showing that x and y are in fact definitionally equal
-- It has a single constructor refl which limits the ways of making something of type x ≡ y to those where x and y are in fact the same, i.e. x ≡ x
-- When we pattern match against something of type x ≡ y, the constructor refl will make x and y unify: Agda will internalise the equality
infix 10 _≡_
-- \== ≡
data _≡_ (x : A) : A → Set where
  refl : x ≡ x

{-# BUILTIN EQUALITY _≡_ #-}

-- Definitional equality holds when the two sides compute to the same symbols
2+2≡4 : 2 + 2 ≡ 4
2+2≡4 = {!!}

-- Because of the way in which defined _+_, zero + x ≡ x holds definitionally (the first case in the definition)
+-idˡ : ∀ x → (zero + x) ≡ x
+-idˡ x = {!!}

-- We show that equality respects congruence
cong : {x y : A} (f : A → B) → x ≡ y → f x ≡ f y
cong f p = {!!}

-- However this does not hold definitionally
-- We need to use proof by induction
-- We miss some pieces to prove this
+-idʳ : ∀ x → (x + zero) ≡ x
+-idʳ x = {!!}

-- Propositional equality is reflexive by construction, here we show it is also symmetric and transitive
sym : {x y : A} → x ≡ y → y ≡ x
sym p = {!!}

trans : {x y z : A} → x ≡ y → y ≡ z → x ≡ z
trans p q = {!!}

-- A binary version that will come in use later on
cong₂ : {x y : A} {w z : B} (f : A → B → C) → x ≡ y → w ≡ z → f x w ≡ f y z
cong₂ f refl refl = refl

-- Leibniz equality, transport
subst : {x y : A} {P : Pred A} → x ≡ y → P x → P y
subst eq p = {!!}

-- Now we can start proving slightly more interesting things!
+-assoc : ∀ x y z → (x + y) + z ≡ x + (y + z)
+-assoc x y z = {!!}

-- Introduce underscores on the RHS
+-comm : ∀ x y → x + y ≡ y + x
+-comm x zero = {!!}
+-comm x (suc y) = {!!}
  -- The keyword where allows us to introduce local definitions
  where
  +-suc : ∀ x y → x + suc y ≡ suc (x + y)
  +-suc x y = {!!}

-----------
-- Some tooling for equational reasoning
-----------

infix  3 _∎
infixr 2 step-≡
infix  1 begin_

begin_ : ∀{x y : A} → x ≡ y → x ≡ y
begin_ x≡y = x≡y

step-≡ : ∀ (x {y z} : A) → y ≡ z → x ≡ y → x ≡ z
step-≡ _ y≡z x≡y = trans x≡y y≡z

syntax step-≡  x y≡z x≡y = x ≡⟨  x≡y ⟩ y≡z

_∎ : ∀ (x : A) → x ≡ x
_∎ _ = refl

-- The equational resoning style allows us to explicitly write down the goals at each stage
-- This starts to look like what one would do on the whiteboard
+-comm′ : ∀ x y → x + y ≡ y + x
+-comm′ x zero = {!!}
+-comm′ x (suc y) = begin
  (x + suc y)  ≡⟨ {!!} ⟩
  suc (x + y)  ≡⟨ {!!} ⟩
  suc (y + x)  ∎


module Common where
  ∗ : Set₁
  ∗ = Set

  _∘_ : {A B C : ∗} → (B → C) → (A → B) → (A → C)
  f ∘ g = λ a → f (g a)

  infixr 2 _×_
  infixr 1 _⊎_

  data _×_ (A B : ∗) : ∗ where
    _,_ : A → B → A × B

  proj₁ : ∀ {A B} → A × B → A
  proj₁ (a , b) = a

  proj₂ : ∀ {A B} → A × B → B
  proj₂ (a , b) = b

  uncurry : {A B C : ∗} → (A → B → C) → (A × B → C)
  uncurry f (a , b) = f a b

  data _⊎_ (A B : ∗) : ∗ where
    inj₁ : (x : A) → A ⊎ B
    inj₂ : (y : B) → A ⊎ B


-- Integers modulo N
module Numeric.Nat.Modulo where

open import Prelude
open import Numeric.Nat.DivMod
open import Tactic.Nat

data IntMod (n : Nat) : Set where
  modn : ∀ k → k < n → IntMod n

{-# DISPLAY modn k (LessNat.diff _ refl) = k #-}

negIntMod : ∀ {n} → IntMod n → IntMod n
negIntMod (modn 0 lt) = modn 0 lt
negIntMod (modn (suc k) (diff j eq)) = modn (suc j) (by (sym eq))

{-# DISPLAY negIntMod a = negate a #-}

instance
  NumberIntMod : ∀ {n} → Number (IntMod (suc n))
  Number.Constraint NumberIntMod _ = ⊤
  fromNat {{NumberIntMod {n}}} k with k divmod suc n
  ... | qr _ r lt _ = modn r lt

  NegativeIntMod : ∀ {n} → Negative (IntMod (suc n))
  Negative.Constraint NegativeIntMod _ = ⊤
  fromNeg {{NegativeIntMod}} k = negIntMod (fromNat k)

addIntMod : ∀ {n} → IntMod (suc n) → IntMod (suc n) → IntMod (suc n)
addIntMod {n} (modn a _) (modn b _) = force (a + b) λ a+b → fromNat a+b ofType IntMod (suc n)

mulIntMod : ∀ {n} → IntMod (suc n) → IntMod (suc n) → IntMod (suc n)
mulIntMod {n} (modn a _) (modn b _) = force (a * b) λ a*b → fromNat a*b ofType IntMod (suc n)

subIntMod : ∀ {n} → IntMod (suc n) → IntMod (suc n) → IntMod (suc n)
subIntMod a b = addIntMod a (negIntMod b)

{-# DISPLAY addIntMod a b = a + b #-}
{-# DISPLAY mulIntMod a b = a * b #-}
{-# DISPLAY subIntMod a b = a - b #-}

instance
  SemiringIntMod : ∀ {n} → Semiring (IntMod (suc n))
  zro {{SemiringIntMod}} = 0
  one {{SemiringIntMod}} = 1
  _+_ {{SemiringIntMod}} = addIntMod
  _*_ {{SemiringIntMod}} = mulIntMod

  SubtractiveIntMod : ∀ {n} → Subtractive (IntMod (suc n))
  _-_    {{SubtractiveIntMod}} = subIntMod
  negate {{SubtractiveIntMod}} = negIntMod


{- Lemmas and operations involving rewriting and heterogeneous equality. -}
module TemporalOps.Common.Rewriting where

open import Relation.Binary.HeterogeneousEquality as ≅
open import Relation.Binary.PropositionalEquality as ≡

-- | Rewriting and heterogeneous equality

-- Substitution with identity predicate – explicit rewriting
rew : ∀{ℓ}{x y : Set ℓ} -> x ≡ y -> x -> y
rew refl x = x

-- Rewriting preserves heterogeneous equality
rew-to-≅ : ∀{ℓ}{A B : Set ℓ}{v : A} -> (p : A ≡ B) -> v ≅ rew p v
rew-to-≅ {A = A} {.A} {v} refl = ≅.refl

-- Heterogenous equality with differently typed arguments
-- can be converted to homogeneous equality via rewriting of the types
≅-to-rew-≡ : ∀ {P Q : Set} {x : P} {y : Q}
            -> (p : x ≅ y) -> (e : P ≡ Q)
            -> rew e x ≡ y
≅-to-rew-≡ ≅.refl refl = refl

-- Rewriting by p is cancelled out by rewriting by (sym p)
rew-cancel : ∀ {P Q : Set}
            -> (v : P) -> (p : P ≡ Q)
            -> rew (≡.sym p) (rew p v) ≡ v
rew-cancel v refl = refl

-- | Equality of equality proofs and functions
-- Two propositional equality proofs are propositionally (heterogeneously) equal
-- if given two heterogeneously equal values, rewriting each with
-- the respective proofs gives propositionally (heterogeneously) equal terms.

-- Propositional equality of equality proofs
Proof-≅ : ∀{p1 p2 q1 q2 : Set} -> p1 ≡ q1 -> p2 ≡ q2 -> Set
Proof-≅ {p1}{p2} pf1 pf2 =
        (v : p1) (v′ : p2) -> v ≅ v′ -> rew pf1 v ≅ rew pf2 v′

-- Propositional equality of equality proofs
Proof-≡ : ∀{p1 p2 q : Set} -> p1 ≡ q -> p2 ≡ q -> Set
Proof-≡ {p1}{p2} pf1 pf2 =
        (v : p1) (v′ : p2) -> v ≅ v′ -> rew pf1 v ≡ rew pf2 v′

-- Propositional equality of functions
Fun-≅ : ∀{a1 a2 b1 b2 : Set} -> (a1 -> b1) -> (a2 -> b2) -> Set
Fun-≅ {a1}{a2} f1 f2 =
        (v : a1) (v′ : a2) -> v ≅ v′ -> f1 v ≅ f2 v′

-- | Other lemmas

-- Heterogeneous congruence of three arguments
≅-cong₃ : ∀ {a b c d} {A : Set a} {B : A → Set b} {C : ∀ (x : A) → B x → Set c}
            {D : ∀ (x : A) -> (y : B x) -> C x y -> Set d} {x y z w u v}
       -> (f : (x : A) (y : B x) (z : C x y) → D x y z)
       -> x ≅ y -> z ≅ w -> u ≅ v -> f x z u ≅ f y w v
≅-cong₃ f ≅.refl ≅.refl ≅.refl = ≅.refl


module Cats.Category.Constructions.Mono where

open import Level

open import Cats.Category.Base

module Build {lo la l≈} (Cat : Category lo la l≈) where

  private open module Cat = Category Cat
  open Cat.≈-Reasoning

  IsMono : ∀ {A B} → A ⇒ B → Set (lo ⊔ la ⊔ l≈)
  IsMono {A} f = ∀ {C} {g h : C ⇒ A} → f ∘ g ≈ f ∘ h → g ≈ h


module Oscar.Property.Symmetry where

open import Oscar.Level

record Symmetry {𝔬} {⋆ : Set 𝔬} {𝔮} (_≒_ : ⋆ → ⋆ → Set 𝔮) : Set (𝔬 ⊔ 𝔮) where
  field
    symmetry : ∀ {x y} → x ≒ y → y ≒ x

open Symmetry ⦃ … ⦄ public


module List where

  data List (a : Set) : Set where
    nil  : List a
    _::_ : a -> List a -> List a

  nil2 : (\x -> x) ({a : Set} -> List a)
  nil2 = nil {_}

  tt : Set1 -> Set2
  tt _ = Set1

  map : {a b : Set} -> (a -> b) -> List a -> List b
  map f nil       = nil
  map f (x :: xs) = f x :: map f xs


{-# OPTIONS --without-K --safe #-}
module Categories.Category.Instance.StrictGroupoids where

-- The 'strict' category of groupoids.
-- The difference here is that _≈_ is not |NaturalIsomorphism| but |_≡F_|

open import Level
open import Relation.Binary.PropositionalEquality using (refl)

open import Categories.Category using (Category)
open import Categories.Category.Groupoid using (Groupoid)
open import Categories.Category.Instance.Groupoids using (F-resp-⁻¹)
open import Categories.Functor using (Functor; id; _∘F_)
open import Categories.Functor.Equivalence

private
  variable
    o ℓ e : Level

open Groupoid using (category)

Groupoids : ∀ o ℓ e → Category (suc (o ⊔ ℓ ⊔  e)) (o ⊔ ℓ ⊔ e) (o ⊔ ℓ ⊔ e)
Groupoids o ℓ e = record
  { Obj       = Groupoid o ℓ e
  ; _⇒_       = λ G H → Functor (category G) (category H)
  ; _≈_       = _≡F_
  ; id        = id
  ; _∘_       = _∘F_
  ; assoc     = λ {_ _ _ _ F G H} → ≡F-assoc     {F = F} {G} {H}
  ; sym-assoc = λ {_ _ _ _ F G H} → ≡F-sym-assoc {F = F} {G} {H}
  ; identityˡ = ≡F-identityˡ
  ; identityʳ = ≡F-identityʳ
  ; identity² = ≡F-identity²
  ; equiv     = ≡F-equiv
  ; ∘-resp-≈  = ∘F-resp-≡F
  }


module Ual.Either where

infix 10 _∨_
data _∨_ (A B : Set) : Set where
  orL : A → A ∨ B
  orR : B → A ∨ B


module Issue857 where

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

data ⊤ : Set where
  tt : ⊤

data ⊥ : Set where

⊥-elim : {A : Set} → ⊥ → A
⊥-elim = λ ()

bad : (x : ⊥) → ⊥-elim x ≡ tt
bad x = {!!}  -- Goal type: x ≡ tt, with x : ⊥.


------------------------------------------------------------------------------
-- Agda-Prop Library.
-- Theorems with different connectives.
------------------------------------------------------------------------------

open import Data.Nat using ( ℕ )

module Data.PropFormula.Theorems.Mixies ( n : ℕ ) where

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

open import Data.PropFormula.Syntax n
open import Data.PropFormula.Theorems.Classical n
open import Data.PropFormula.Theorems.Biimplication n
  using ( ⇔-¬-to-¬; ⊃-⇔-¬∨ )
open import Data.PropFormula.Theorems.Disjunction n
  using ( ∨-dmorgan; ∨-dmorgan₁ )
open import Data.PropFormula.Theorems.Implication n
  using ( vanDalen244e; ⊃-equiv )
open import Data.PropFormula.Theorems.Weakening n

open import Function using ( _$_ ; _∘_ )

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

-- Theorem.
e245b
  : ∀ {Γ Δ} {φ ψ}
  → Γ ⊢ φ → Δ , φ ⊢ ψ
  → Γ ⨆ Δ ⊢ ψ

-- Proof.
e245b {Γ}{Δ} Γ⊢φ Δ,φ⊢ψ =
  ⊃-elim
    (weaken-Δ₂ Γ $ ⊃-intro Δ,φ⊢ψ)
    (weaken-Δ₁ Δ Γ⊢φ)
-------------------------------------------------------------------------- ∎

-- Theorem.
¬⊃-to-∧¬
  : ∀ {Γ} {φ ψ}
  → Γ ⊢ ¬ (φ ⊃ ψ)
  → Γ ⊢ φ ∧ ¬ ψ

-- Proof.
¬⊃-to-∧¬ {Γ}{φ}{ψ} Γ⊢¬⟪φ⊃ψ⟫ =
  ∧-intro
    (⊃-elim vanDalen244e (∧-proj₁ p2))
    (∧-proj₂ p2)
  where
    p1 : Γ ⊢ ¬ (¬ φ ∨ ψ)
    p1 = ⇔-¬-to-¬ ⊃-⇔-¬∨ Γ⊢¬⟪φ⊃ψ⟫

    p2 : Γ ⊢ ¬ (¬ φ) ∧  ¬ ψ
    p2 = ∨-dmorgan₁ p1
-------------------------------------------------------------------------- ∎

-- Theorem.
⊃¬∧¬⊃-to-¬⇔
  : ∀ {Γ} {φ ψ}
  → Γ ⊢ (φ ⊃ ¬ ψ) ∧ (¬ ψ ⊃ φ)
  → Γ ⊢ ¬ (φ ⇔ ψ)

-- Proof.
⊃¬∧¬⊃-to-¬⇔ {Γ}{φ}{ψ} thm =
 ¬-intro
   (¬-elim
     (¬-intro
       (¬-elim
         (⊃-elim
           (weaken ψ (weaken (φ ⇔ ψ) (∧-proj₁ thm)))
           (⇔-elim₂
             (assume {Γ = Γ , φ ⇔ ψ} ψ)
             (weaken ψ (assume (φ ⇔ ψ)))))
         (assume {Γ = Γ , φ ⇔ ψ} ψ)))
    (RAA
      (¬-elim
         (¬-intro
           (¬-elim
             (⊃-elim
               (weaken φ (weaken (¬ ψ ) (weaken (φ ⇔ ψ) (∧-proj₁ thm))))
               (assume {Γ = Γ , φ ⇔ ψ , ¬ ψ} φ))
             (⇔-elim₁
               (assume {Γ = Γ , φ ⇔ ψ , ¬ ψ} φ)
               (weaken φ (weaken (¬ ψ) (assume (φ ⇔ ψ)))))))
         (⊃-elim
           (weaken (¬ ψ) (weaken (φ ⇔ ψ) (∧-proj₂ thm)))
           (assume {Γ = Γ , φ ⇔ ψ} (¬ ψ))))))
-------------------------------------------------------------------------- ∎


module Prelude.Decidable where

open import Prelude.Empty

data Dec {a} (P : Set a) : Set a where
  yes : P → Dec P
  no  : ¬ P → Dec P

infix 0 ifYes_then_else_ ifNo_then_else_
ifYes_then_else_ : ∀ {a b} {A : Set a} {B : Set b} → Dec A → B → B → B
ifYes yes _ then x else _ = x
ifYes no  _ then _ else y = y

ifNo_then_else_ : ∀ {a b} {A : Set a} {B : Set b} → Dec A → B → B → B
ifNo d then x else y = ifYes d then y else x

FromDec : ∀ {a} {P : Set a} → Dec P → Set a
FromDec {P = P} (yes _) = P
FromDec {P = P} (no  _) = ¬ P

fromDec : ∀ {a} {P : Set a} (d : Dec P) → FromDec d
fromDec (yes x) = x
fromDec (no  x) = x


open import Agda.Builtin.Nat

data D : Set where
  c : D → D

record R : Set where
  constructor mkR
  field f : Nat

f : D → R
f (c x) = mkR zero

f' : D → Nat → R
f' (c x) n = mkR n

postulate
  P  : (A : Set) → A → Set
  g  : (x : D) → P R (f x) → P D x
  g' : (n : Nat) (x : D) → P R (f' x n) → P D x

h : (x : D) → P R (mkR zero) → P D (c x)
h x = g _

h' : (n : Nat) (x : D) → P R (mkR n) → P D (c x)
h' n x = g' n _


{-

This file contains:
    - the abelianization of groups as a HIT as proposed in https://arxiv.org/abs/2007.05833

The definition of the abelianization is not as a set-quotient, since the relation of abelianization is cumbersome to work with.

-}
{-# OPTIONS --safe #-}
module Cubical.Algebra.Group.Abelianization.Base where

open import Cubical.Data.Sigma

open import Cubical.Algebra.Group.Base
open import Cubical.Algebra.Group.Properties

private
  variable
    ℓ : Level

module _ (G : Group ℓ) where
  open GroupStr {{...}}
  open GroupTheory G
  private
    instance
      _ = snd G

  {-
    The definition of the abelianization of a group as a higher inductive type.
    The generality of the comm relation will be needed to define the group structure on the abelianization.
  -}
  data Abelianization : Type ℓ where
    η : (g : fst G) → Abelianization
    comm : (a b c : fst G) → η (a · (b · c)) ≡ η (a · (c · b))
    isset : (x y : Abelianization) → (p q : x ≡ y) → p ≡ q


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

module Algebra.Construct.Free.Semilattice.Homomorphism where

open import Prelude
open import Algebra
open import Path.Reasoning

open import Algebra.Construct.Free.Semilattice.Definition
open import Algebra.Construct.Free.Semilattice.Eliminators
open import Algebra.Construct.Free.Semilattice.Union

module _ {b} (semilattice : Semilattice b) where
  open Semilattice semilattice
  module _ (sIsSet : isSet 𝑆) (h : A → 𝑆) where
    μ′ : A ↘ 𝑆
    [ μ′ ]-set = sIsSet
    [ μ′ ] x ∷ xs = h x ∙ xs
    [ μ′ ][] = ε
    [ μ′ ]-dup x xs =
      h x ∙ (h x ∙ xs) ≡˘⟨ assoc (h x) (h x) xs ⟩
      (h x ∙ h x) ∙ xs ≡⟨ cong (_∙ xs) (idem (h x)) ⟩
      h x ∙ xs ∎
    [ μ′ ]-com x y xs =
      h x ∙ (h y ∙ xs) ≡˘⟨ assoc (h x) (h y) xs ⟩
      (h x ∙ h y) ∙ xs ≡⟨ cong (_∙ xs) (comm (h x) (h y)) ⟩
      (h y ∙ h x) ∙ xs ≡⟨ assoc (h y) (h x) xs ⟩
      h y ∙ (h x ∙ xs) ∎

    μ : 𝒦 A → 𝑆
    μ = [ μ′ ]↓

    ∙-hom′ : ∀ ys → xs ∈𝒦 A ⇒∥ μ xs ∙ μ ys ≡ μ (xs ∪ ys) ∥
    ∥ ∙-hom′ ys ∥-prop = sIsSet _ _
    ∥ ∙-hom′ ys ∥[] = ε∙ _
    ∥ ∙-hom′ ys ∥ x ∷ xs ⟨ Pxs ⟩ =
      μ (x ∷ xs) ∙ μ ys ≡⟨⟩
      (h x ∙ μ xs) ∙ μ ys ≡⟨ assoc (h x) (μ xs) (μ ys) ⟩
      h x ∙ (μ xs ∙ μ ys) ≡⟨ cong (h x ∙_) Pxs ⟩
      h x ∙ μ (xs ∪ ys) ≡⟨⟩
      μ ((x ∷ xs) ∪ ys) ∎

    ∙-hom : ∀ xs ys → μ xs ∙ μ ys ≡ μ (xs ∪ ys)
    ∙-hom xs ys = ∥ ∙-hom′ ys ∥⇓ xs


------------------------------------------------------------------------
-- The Agda standard library
--
-- An inductive definition of the heterogeneous prefix relation
------------------------------------------------------------------------

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

module Data.List.Relation.Binary.Prefix.Heterogeneous where

open import Level
open import Data.List.Base as List using (List; []; _∷_)
open import Data.List.Relation.Binary.Pointwise
  using (Pointwise; []; _∷_)
open import Data.Product using (∃; _×_; _,_; uncurry)
open import Relation.Binary using (REL; _⇒_)

module _ {a b r} {A : Set a} {B : Set b} (R : REL A B r) where

  data Prefix : REL (List A) (List B) (a ⊔ b ⊔ r) where
    []  : ∀ {bs} → Prefix [] bs
    _∷_ : ∀ {a b as bs} → R a b → Prefix as bs → Prefix (a ∷ as) (b ∷ bs)

  data PrefixView (as : List A) : List B → Set (a ⊔ b ⊔ r) where
    _++_ : ∀ {cs} → Pointwise R as cs → ∀ ds → PrefixView as (cs List.++ ds)

module _ {a b r} {A : Set a} {B : Set b} {R : REL A B r} {a b as bs} where

  head : Prefix R (a ∷ as) (b ∷ bs) → R a b
  head (r ∷ rs) = r

  tail : Prefix R (a ∷ as) (b ∷ bs) → Prefix R as bs
  tail (r ∷ rs) = rs

  uncons : Prefix R (a ∷ as) (b ∷ bs) → R a b × Prefix R as bs
  uncons (r ∷ rs) = r , rs

module _ {a b r s} {A : Set a} {B : Set b} {R : REL A B r} {S : REL A B s} where

  map : R ⇒ S → Prefix R ⇒ Prefix S
  map R⇒S []       = []
  map R⇒S (r ∷ rs) = R⇒S r ∷ map R⇒S rs

module _ {a b r} {A : Set a} {B : Set b} {R : REL A B r} where

  toView : ∀ {as bs} → Prefix R as bs → PrefixView R as bs
  toView []       = [] ++ _
  toView (r ∷ rs) with toView rs
  ... | rs′ ++ ds = (r ∷ rs′) ++ ds

  fromView : ∀ {as bs} → PrefixView R as bs → Prefix R as bs
  fromView ([]       ++ ds) = []
  fromView ((r ∷ rs) ++ ds) = r ∷ fromView (rs ++ ds)


module plfa-code.Relations where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; cong; sym; trans)
open import Data.Nat using (ℕ; zero; suc; _+_; _*_)
open import Data.Nat.Properties using (+-comm)
open Eq.≡-Reasoning using (begin_; _≡⟨⟩_)

open import plfa-code.Reasoning-legacy
open import Function

data _≤_ : ℕ → ℕ → Set where
  z≤n : ∀ {n : ℕ}
      ---------
    → zero ≤ n

  s≤s : ∀ {m n : ℕ}
    → m ≤ n
      --------------
    → suc m ≤ suc n

infix 4 _≤_

_ : 2 ≤ 4
_ = s≤s (s≤s z≤n)

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

≤-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 _ = 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    _       _       z≤n       _          =  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)

-- when m is zero there is no instance for `n ≤ m`, the same as when n is zero

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

  flipped :
      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)

---------- practice ----------
*-mono-≤ : ∀ (m n p q : ℕ) → m ≤ n → p ≤ q → m * p ≤ n * q
*-mono-≤ zero n p q m≤n p≤q = z≤n
*-mono-≤ (suc m) (suc n) p q m≤n p≤q = +-mono-≤ p q (m * p) (n * q) p≤q (*-mono-≤ m n p q (inv-s≤s m≤n) p≤q)
------------------------------

infix 4 _<_

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

  s<s : ∀ {m n : ℕ}
    → m < n
      --------------
    → suc m < suc n

---------- practice ----------
inv-s<s : ∀ {m n : ℕ} → suc m < suc n → m < n
inv-s<s (s<s mLTn) = mLTn

<-trans : ∀ (m n p : ℕ) → m < n → n < p → m < p
<-trans zero (suc n) (suc p) zLTsn snLTsp = z<s
<-trans (suc m) (suc n) (suc p) smLTsn snLTsp = s<s (<-trans m n p (inv-s<s smLTsn) (inv-s<s snLTsp))

data Trichotomy (m n : ℕ) : Set where
  less    : m < n → Trichotomy m n
  equal   : m ≡ n → Trichotomy m n
  greater : n < m → Trichotomy m n

<-trichotomy : ∀ (m n : ℕ) → Trichotomy m n
<-trichotomy zero    zero     = equal refl
<-trichotomy zero    (suc n)  = less z<s
<-trichotomy (suc m) zero     = greater z<s
<-trichotomy (suc m) (suc n) with <-trichotomy m n
...                             | less    mLTn = less (s<s mLTn)
...                             | equal   refl = equal refl
...                             | greater nLTm = greater (s<s nLTm)

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

+-monoˡ-< : ∀ (m n p : ℕ) → m < n → m + p < n + p
+-monoˡ-< m n p mLTn rewrite +-comm m p | +-comm n p = +-monoʳ-< p m n mLTn

+-mono-< : ∀ (m n p q : ℕ) → m < n → p < q → m + p < n + q
+-mono-< m n p q mLTn pLTq = <-trans (m + p) (n + p) (n + q) (+-monoˡ-< m n p mLTn) (+-monoʳ-< n p q pLTq)

≤-iff-< : ∀ (m n : ℕ) → suc m ≤ n → m < n
≤-iff-< zero    (suc n) _       = z<s
≤-iff-< (suc m) (suc n) ssm≤sn = s<s (≤-iff-< m n sm≤n)
  where
  sm≤n = inv-s≤s ssm≤sn

<-iff-≤ : ∀ (m n : ℕ) → m < n → suc m ≤ n
<-iff-≤ zero (suc n) mLTn = s≤s z≤n
<-iff-≤ (suc m) (suc n) smLTn = s≤s (<-iff-≤ m n (inv-s<s smLTn))

<→≤ : ∀ (n p : ℕ) → n < p → n ≤ p
<→≤ zero p nLTp = z≤n
<→≤ (suc n) (suc p) nLTp = s≤s (<→≤ n p (inv-s<s nLTp))

<-trans-revisited : ∀ (m n p : ℕ) → m < n → n < p → m < p
<-trans-revisited m n p mLTn nLTp = ≤-iff-< m p (inv-s≤s ssm≤sp)
  where ssm≤sp = s≤s (≤-trans (<-iff-≤ m n mLTn) (<→≤ n p nLTp))
------------------------------

data even : ℕ → Set
data odd  : ℕ → Set

data even where

  zero :
      ---------
      even zero

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

data odd where

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

e+e≡e : ∀ {m n : ℕ}
  → even m
  → even n
    -------------
  → even (m + n)

o+e≡o : ∀ {m n : ℕ}
  → odd m
  → even n
    ------------
  → odd (m + n)

e+e≡e zero     en  =  en
e+e≡e (suc om) en  =  suc (o+e≡o om en)

o+e≡o (suc em) en  =  suc (e+e≡e em en)

---------- practice ----------
o+o≡e : ∀ {m n : ℕ} → odd m → odd n → even (m + n)
o+o≡e (suc zero)     on = suc on
o+o≡e (suc (suc ox)) on = suc (suc (o+o≡e ox on))

open import plfa-code.Induction using (Bin; nil; x0_; x1_; inc; from; to;
                                      +1≡suc; suc-from-inc; from-to-const)

data Can : Bin → Set
data One : Bin → Set

data One where
  one  : One (x1 nil)
  x0_ : ∀ {b : Bin} → One b → One(x0 b)
  x1_ : ∀ {b : Bin} → One b → One(x1 b)

data Can where
  zero     : Can (x0 nil)
  can-one  : ∀ {b : Bin} → One b → Can b

one-inc : ∀ {x : Bin} → One x → One (inc x)
one-inc one = x0 one
one-inc (x0 x) = x1 x
one-inc (x1 x) = x0 (one-inc x)

can-inc : ∀ {x : Bin} → Can x → Can (inc x)
can-inc zero        =  can-one one
can-inc (can-one x) =  can-one (one-inc x)

one-to-n : ∀ (n : ℕ) → One (to (suc n))
one-to-n zero = one
one-to-n (suc n) = one-inc (one-to-n n)

can-to-n : ∀ (n : ℕ) → Can (to n)
can-to-n zero = zero
can-to-n (suc n) = can-one (one-to-n n)

open Data.Nat.Properties using (+-identityʳ; +-suc)

l0 : ∀ (n) → to (suc n) ≡ inc (to n)
l0 zero    = refl
l0 (suc n) = refl

2n-eq-x0 : ∀ (n) → 1 ≤ n → to (n + n) ≡ x0 (to n)
2n-eq-x0 zero ()
2n-eq-x0 (suc zero) (s≤s z≤n) = refl
2n-eq-x0 (suc (suc n)) (s≤s z≤n) =
  begin to (suc (suc n) + suc (suc n))
  ≡⟨ cong (λ x → to x) (+-suc (suc (suc n)) (suc n)) ⟩  to (suc (suc (suc n + suc n)))
  ≡⟨⟩  inc (inc (to (suc n + suc n)))
  ≡⟨ cong (λ x → (inc (inc x))) (2n-eq-x0 (suc n) (s≤s z≤n)) ⟩  inc (inc (x0 (to (suc n))))
  ≡⟨⟩  x0 (inc (to (suc n)))
  ≡⟨⟩  x0 (to (suc (suc n)))
  ∎

one-b-iff-1≤b : ∀ (b) → One b → 1 ≤ from b
one-b-iff-1≤b (x0 b) (x0 ob)
              rewrite +-identityʳ (from b)
              = +-mono-≤ 1 n 0 n (one-b-iff-1≤b b ob) z≤n
                where n = from b
one-b-iff-1≤b (x1 .nil) one     = s≤s z≤n
one-b-iff-1≤b (x1 b)    (x1 ob) = s≤s z≤n

one-tf-eq : ∀ {b} → One b → to (from b) ≡ b
one-tf-eq {_}    one    = refl
one-tf-eq {x0 b} (x0 x) =
  begin
    to (from (x0 b))
  ≡⟨⟩
    to (from b + (from b + zero))
  ≡⟨ cong (λ n → to (from b + n)) (+-identityʳ (from b)) ⟩
    to (from b + from b)
  ≡⟨ 2n-eq-x0 (from b) (one-b-iff-1≤b b x) ⟩
    x0 (to (from b))
  ≡⟨ cong x0_ (one-tf-eq x) ⟩
    x0 b
  ∎
one-tf-eq {x1 b} (x1 x) =
  begin
    to (from (x1 b))
  ≡⟨⟩
    inc (to (from b + (from b + zero)))
  ≡⟨ cong (λ n → inc (to (from b + n))) (+-identityʳ (from b)) ⟩
    inc (to (from b + from b))
  ≡⟨ cong inc (2n-eq-x0 (from b) (one-b-iff-1≤b b x)) ⟩
    inc (x0 (to (from b)))
  ≡⟨⟩
    x1 (to (from b))
  ≡⟨ cong x1_ (one-tf-eq x) ⟩
    x1 b
  ∎

can-tf-eq : ∀ {x} → Can x → to (from x) ≡ x
can-tf-eq {_}  zero        = refl
can-tf-eq {b}  (can-one x) = one-tf-eq x

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


------------------------------------------------------------------------
-- Examples showing how Tree-sort can be used
------------------------------------------------------------------------

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

open import Equality

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

open Derived-definitions-and-properties eq

open import Prelude

open import Bag-equivalence eq
import Nat eq as Nat

-- Comparison functions for natural numbers.

_≤?_ : ℕ → ℕ → Bool
m ≤? n with Nat.total m n
... | inj₁ m≤n = true
... | inj₂ n<m = false

import Tree-sort.Partial eq _≤?_ as P
open import Tree-sort.Full eq Nat._≤_ Nat.total as F using (cons; nil)

-- The sort functions return ordered lists.

orderedP : P.tree-sort (3 ∷ 1 ∷ 2 ∷ []) ≡ 1 ∷ 2 ∷ 3 ∷ []
orderedP = refl _

orderedF : F.tree-sort (3 ∷ 1 ∷ 2 ∷ []) ≡
           cons 1 (cons 2 (cons 3 (nil _) _) _) _
orderedF = refl _

-- The sort functions return lists which are bag equivalent to the
-- input. This property can be used to establish bag equivalences
-- between concrete lists.

a-bag-equivalenceP : 1 ∷ 2 ∷ 3 ∷ [] ≈-bag 3 ∷ 1 ∷ 2 ∷ []
a-bag-equivalenceP = P.tree-sort-permutes (3 ∷ 1 ∷ 2 ∷ [])

a-bag-equivalenceF : 1 ∷ 2 ∷ 3 ∷ [] ≈-bag 3 ∷ 1 ∷ 2 ∷ []
a-bag-equivalenceF = F.tree-sort-permutes (3 ∷ 1 ∷ 2 ∷ [])


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

open import LogicalFormulae
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Numbers.Naturals.Naturals
open import Numbers.Naturals.Order
open import Vectors
open import Semirings.Definition
open import Categories.Definition
open import Groups.Definition
open import Setoids.Setoids
open import Groups.Homomorphisms.Definition
open import Groups.Homomorphisms.Examples
open import Groups.Homomorphisms.Lemmas
open import Functions

module Categories.Examples where

SET : {a : _} → Category {lsuc a} {a}
Category.objects (SET {a}) = Set a
Category.arrows (SET {a}) = λ a b → (a → b)
Category.id (SET {a}) = λ x → λ y → y
Category._∘_ (SET {a}) = λ f g → λ x → f (g x)
Category.rightId (SET {a}) = λ f → refl
Category.leftId (SET {a}) = λ f → refl
Category.compositionAssociative (SET {a}) = λ f g h → refl

GROUP : {a b : _} → Category {lsuc a ⊔ lsuc b} {a ⊔ b}
Category.objects (GROUP {a} {b}) = Sg (Set a) (λ A → Sg (A → A → A) (λ _+_ → Sg (Setoid {a} {b} A) (λ S → Group S _+_)))
Category.arrows (GROUP {a}) (A , (_+A_ , (S , G))) (B , (_+B_ , (T , H))) = Sg (A → B) (GroupHom G H)
Category.id (GROUP {a}) (A , (_+A_ , (S , G))) = (λ i → i) , identityHom G
Category._∘_ (GROUP {a}) {A , (_+A_ , (S , G))} {B , (_+B_ , (T , H))} {C , (_+C_ , (U , I))} (f , fHom) (g , gHom) = (f ∘ g) , groupHomsCompose gHom fHom
Category.rightId (GROUP {a}) {A , (_+A_ , (S , G))} {B , (_+B_ , (T , H))} (f , fHom) = {!!}
Category.leftId (GROUP {a}) {A , (_+A_ , (S , G))} {B , (_+B_ , (T , H))} (f , fHom) = {!!}
Category.compositionAssociative (GROUP {a}) = {!!}

DISCRETE : {a : _} (X : Set a) → Category {a} {a}
Category.objects (DISCRETE X) = X
Category.arrows (DISCRETE X) = λ a b → a ≡ b
Category.id (DISCRETE X) = λ x → refl
Category._∘_ (DISCRETE X) = λ y=z x=y → transitivity x=y y=z
Category.rightId (DISCRETE X) refl = refl
Category.leftId (DISCRETE X) refl = refl
Category.compositionAssociative (DISCRETE X) refl refl refl = refl


module Data.List.Relation.Quantification where

import      Lvl
open import Data.List
open import Logic
open import Type

private variable ℓ ℓₑ : Lvl.Level
private variable T A B : Type{ℓ}
private variable l l₁ l₂ : List(T)
private variable x y px py : T
private variable P : T → Stmt{ℓ}

-- TODO: How about this as an alternative definition?
-- module _ (P : T → Type{ℓ}) where
--   open import Type.Dependent
--   open Data.IndexedList(Σ T P){List(T)} using (IndexedList ; intro)
--
--   AllElements : List(T) → Stmt{Lvl.of(T) Lvl.⊔ ℓ}
--   AllElements = IndexedList(intro ∅ ((_⊰_) ∘ Σ.left))
data AllElements (P : T → Stmt{ℓ}) : List(T) → Stmt{Lvl.of(T) Lvl.⊔ ℓ} where
  ∅   : AllElements(P)(∅)
  _⊰_ : P(x) → AllElements(P)(l) → AllElements(P)(x ⊰ l)

data ExistsElement (P : T → Stmt{ℓ}) : List(T) → Stmt{Lvl.of(T) Lvl.⊔ ℓ} where
  •_ : P(x)                → ExistsElement(P)(x ⊰ l)
  ⊰_ : ExistsElement(P)(l) → ExistsElement(P)(x ⊰ l)

-- TODO: Maybe remove this and use AllElements with map₂ instead
data AllElements₂ (P : A → B → Stmt{ℓ}) : List(A) → List(B) → Stmt{Lvl.of(A) Lvl.⊔ Lvl.of(B) Lvl.⊔ ℓ} where
  ∅   : AllElements₂(P)(∅)(∅)
  _⊰_ : P(x)(y) → AllElements₂(P)(l₁)(l₂) → AllElements₂(P)(x ⊰ l₁)(y ⊰ l₂)

∀ₗᵢₛₜ : List(T) → (T → Stmt{ℓ}) → Stmt
∀ₗᵢₛₜ(l) P = AllElements P l

∃ₗᵢₛₜ : List(T) → (T → Stmt{ℓ}) → Stmt
∃ₗᵢₛₜ(l) P = ExistsElement P l

module _ {P : T → Type{ℓ}} where
  open import Logic.Propositional
  open import Structure.Relator.Equivalence
  import      Structure.Relator.Names as Names
  open import Structure.Relator.Properties
  open import Structure.Setoid

  data ExistsElementEquivalence : ExistsElement(P)(l) → ExistsElement(P)(l) → Stmt{Lvl.of(T) Lvl.⊔ ℓ} where
    use  : ExistsElementEquivalence{l = x ⊰ l}(• px)(• py)
    skip : ExistsElementEquivalence(px)(py) → ExistsElementEquivalence{l = x ⊰ l}(⊰ px)(⊰ py)

  instance
    ExistsElementEquivalence-equiv : Equiv(ExistsElement(P)(l))
    Equiv._≡_ ExistsElementEquivalence-equiv = ExistsElementEquivalence
    Equiv.equivalence ExistsElementEquivalence-equiv = intro ⦃ intro refl ⦄ ⦃ intro sym ⦄ ⦃ intro trans ⦄ where
      refl : Names.Reflexivity(ExistsElementEquivalence{l = l})
      refl{x = • _} = use
      refl{x = ⊰ p} = skip(refl{x = p})

      sym : Names.Symmetry(ExistsElementEquivalence{l = l})
      sym {x = • px} {y = • py} use      = use
      sym {x = ⊰ px} {y = ⊰ py} (skip p) = skip(sym{x = px}{y = py} p)

      trans : Names.Transitivity(ExistsElementEquivalence{l = l})
      trans {x = • px} {y = • py} {z = • pz} use      use      = use
      trans {x = ⊰ px} {y = ⊰ py} {z = ⊰ pz} (skip p) (skip q) = skip(trans {x = px} {y = py} {z = pz} p q)

module _ where
  open import Type.Properties.Singleton

  ExistsUniqueElement : (T → Stmt{ℓ}) → List(T) → Stmt
  ExistsUniqueElement P l = IsUnit(ExistsElement(P)(l)) ⦃ ExistsElementEquivalence-equiv ⦄

  ∃!ₗᵢₛₜ : List(T) → (T → Stmt{ℓ}) → Stmt
  ∃!ₗᵢₛₜ(l) P = ExistsUniqueElement P l


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties of interleaving using setoid equality
------------------------------------------------------------------------

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

open import Relation.Binary using (Setoid)

module Data.List.Relation.Ternary.Interleaving.Setoid.Properties
  {c ℓ} (S : Setoid c ℓ) where

open import Data.List.Base using (List; []; _∷_; filter; _++_)
open import Relation.Unary using (Decidable)
open import Relation.Nullary using (yes; no)
open import Relation.Nullary.Negation using (¬?)
open import Function

open import Data.List.Relation.Binary.Equality.Setoid S using (≋-refl)
open import Data.List.Relation.Ternary.Interleaving.Setoid S
open Setoid S renaming (Carrier to A)

------------------------------------------------------------------------
-- Re-exporting existing properties

open import Data.List.Relation.Ternary.Interleaving.Properties public

------------------------------------------------------------------------
-- _++_

++-linear : (xs ys : List A) → Interleaving xs ys (xs ++ ys)
++-linear xs ys = ++-disjoint (left ≋-refl) (right ≋-refl)

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

module _ {p} {P : A → Set p} (P? : Decidable P) where

  filter⁺ : ∀ xs → Interleaving (filter P? xs) (filter (¬? ∘ P?) xs) xs
  filter⁺ []       = []
  filter⁺ (x ∷ xs) with P? x
  ... | yes px = refl ∷ˡ filter⁺ xs
  ... | no ¬px = refl ∷ʳ filter⁺ xs