------------------------------------------------------------------------
-- The Agda standard library
--
-- Some properties about integers
------------------------------------------------------------------------

module Data.Integer.Properties where

open import Algebra
import Algebra.FunctionProperties
import Algebra.Morphism as Morphism
import Algebra.Properties.AbelianGroup
open import Algebra.Structures
open import Data.Integer hiding (suc; _≤?_)
import Data.Integer.Addition.Properties as Add
import Data.Integer.Multiplication.Properties as Mul
open import Data.Nat
  using (ℕ; suc; zero; _∸_; _≤?_; _<_; _≥_; _≱_; s≤s; z≤n; ≤-pred)
  renaming (_+_ to _ℕ+_; _*_ to _ℕ*_)
open import Data.Nat.Properties as ℕ using (_*-mono_)
open import Data.Product using (proj₁; proj₂; _,_)
open import Data.Sign as Sign using () renaming (_*_ to _S*_)
import Data.Sign.Properties as SignProp
open import Function using (_∘_; _$_)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
open import Relation.Nullary using (yes; no)
open import Relation.Nullary.Negation using (contradiction)

open Algebra.FunctionProperties (_≡_ {A = ℤ})
open CommutativeMonoid Add.commutativeMonoid
  using ()
  renaming ( assoc to +-assoc; comm to +-comm; identity to +-identity
           ; isCommutativeMonoid to +-isCommutativeMonoid
           ; isMonoid to +-isMonoid
           )
open CommutativeMonoid Mul.commutativeMonoid
  using ()
  renaming ( assoc to *-assoc; comm to *-comm; identity to *-identity
           ; isCommutativeMonoid to *-isCommutativeMonoid
           ; isMonoid to *-isMonoid
           )
open CommutativeSemiring ℕ.commutativeSemiring
  using () renaming (zero to *-zero; distrib to *-distrib)
open DecTotalOrder Data.Nat.decTotalOrder
  using () renaming (refl to ≤-refl)
open Morphism.Definitions ℤ ℕ _≡_
open ℕ.SemiringSolver
open ≡-Reasoning

------------------------------------------------------------------------
-- Miscellaneous properties

-- Some properties relating sign and ∣_∣ to _◃_.

sign-◃ : ∀ s n → sign (s ◃ suc n) ≡ s
sign-◃ Sign.- _ = refl
sign-◃ Sign.+ _ = refl

sign-cong : ∀ {s₁ s₂ n₁ n₂} →
            s₁ ◃ suc n₁ ≡ s₂ ◃ suc n₂ → s₁ ≡ s₂
sign-cong {s₁} {s₂} {n₁} {n₂} eq = begin
  s₁                  ≡⟨ sym $ sign-◃ s₁ n₁ ⟩
  sign (s₁ ◃ suc n₁)  ≡⟨ cong sign eq ⟩
  sign (s₂ ◃ suc n₂)  ≡⟨ sign-◃ s₂ n₂ ⟩
  s₂                  ∎

abs-◃ : ∀ s n → ∣ s ◃ n ∣ ≡ n
abs-◃ _      zero    = refl
abs-◃ Sign.- (suc n) = refl
abs-◃ Sign.+ (suc n) = refl

abs-cong : ∀ {s₁ s₂ n₁ n₂} →
           s₁ ◃ n₁ ≡ s₂ ◃ n₂ → n₁ ≡ n₂
abs-cong {s₁} {s₂} {n₁} {n₂} eq = begin
  n₁           ≡⟨ sym $ abs-◃ s₁ n₁ ⟩
  ∣ s₁ ◃ n₁ ∣  ≡⟨ cong ∣_∣ eq ⟩
  ∣ s₂ ◃ n₂ ∣  ≡⟨ abs-◃ s₂ n₂ ⟩
  n₂           ∎

-- ∣_∣ commutes with multiplication.

abs-*-commute : Homomorphic₂ ∣_∣ _*_ _ℕ*_
abs-*-commute i j = abs-◃ _ _

-- If you subtract a natural from itself, then you get zero.

n⊖n≡0 : ∀ n → n ⊖ n ≡ + 0
n⊖n≡0 zero    = refl
n⊖n≡0 (suc n) = n⊖n≡0 n

------------------------------------------------------------------------
-- The integers form a commutative ring

private

  ----------------------------------------------------------------------
  -- Additive abelian group.

  inverseˡ : LeftInverse (+ 0) -_ _+_
  inverseˡ -[1+ n ]  = n⊖n≡0 n
  inverseˡ (+ zero)  = refl
  inverseˡ (+ suc n) = n⊖n≡0 n

  inverseʳ : RightInverse (+ 0) -_ _+_
  inverseʳ i = begin
    i + - i  ≡⟨ +-comm i (- i) ⟩
    - i + i  ≡⟨ inverseˡ i ⟩
    + 0      ∎

  +-isAbelianGroup : IsAbelianGroup _≡_ _+_ (+ 0) -_
  +-isAbelianGroup = record
    { isGroup = record
      { isMonoid = +-isMonoid
      ; inverse  = inverseˡ , inverseʳ
      ; ⁻¹-cong  = cong -_
      }
    ; comm = +-comm
    }

  open Algebra.Properties.AbelianGroup
         (record { isAbelianGroup = +-isAbelianGroup })
    using () renaming (⁻¹-involutive to -‿involutive)

  ----------------------------------------------------------------------
  -- Distributivity

  -- Various lemmas used to prove distributivity.

  sign-⊖-< : ∀ {m n} → m < n → sign (m ⊖ n) ≡ Sign.-
  sign-⊖-< {zero}  (s≤s z≤n) = refl
  sign-⊖-< {suc n} (s≤s m<n) = sign-⊖-< m<n

  sign-⊖-≱ : ∀ {m n} → m ≱ n → sign (m ⊖ n) ≡ Sign.-
  sign-⊖-≱ = sign-⊖-< ∘ ℕ.≰⇒>

  +-⊖-left-cancel : ∀ a b c → (a ℕ+ b) ⊖ (a ℕ+ c) ≡ b ⊖ c
  +-⊖-left-cancel zero    b c = refl
  +-⊖-left-cancel (suc a) b c = +-⊖-left-cancel a b c

  ⊖-swap : ∀ a b → a ⊖ b ≡ - (b ⊖ a)
  ⊖-swap zero    zero    = refl
  ⊖-swap (suc _) zero    = refl
  ⊖-swap zero    (suc _) = refl
  ⊖-swap (suc a) (suc b) = ⊖-swap a b

  -- Lemmas relating _⊖_ and _∸_.

  ∣⊖∣-< : ∀ {m n} → m < n → ∣ m ⊖ n ∣ ≡ n ∸ m
  ∣⊖∣-< {zero}  (s≤s z≤n) = refl
  ∣⊖∣-< {suc n} (s≤s m<n) = ∣⊖∣-< m<n

  ∣⊖∣-≱ : ∀ {m n} → m ≱ n → ∣ m ⊖ n ∣ ≡ n ∸ m
  ∣⊖∣-≱ = ∣⊖∣-< ∘ ℕ.≰⇒>

  ⊖-≥ : ∀ {m n} → m ≥ n → m ⊖ n ≡ + (m ∸ n)
  ⊖-≥ z≤n       = refl
  ⊖-≥ (s≤s n≤m) = ⊖-≥ n≤m

  ⊖-< : ∀ {m n} → m < n → m ⊖ n ≡ - + (n ∸ m)
  ⊖-< {zero}  (s≤s z≤n) = refl
  ⊖-< {suc m} (s≤s m<n) = ⊖-< m<n

  ⊖-≱ : ∀ {m n} → m ≱ n → m ⊖ n ≡ - + (n ∸ m)
  ⊖-≱ = ⊖-< ∘ ℕ.≰⇒>

  -- Lemmas working around the fact that _◃_ pattern matches on its
  -- second argument before its first.

  +‿◃ : ∀ n → Sign.+ ◃ n ≡ + n
  +‿◃ zero    = refl
  +‿◃ (suc _) = refl

  -‿◃ : ∀ n → Sign.- ◃ n ≡ - + n
  -‿◃ zero    = refl
  -‿◃ (suc _) = refl

  -- The main distributivity proof.

  distrib-lemma :
    ∀ a b c → (c ⊖ b) * -[1+ a ] ≡ a ℕ+ b ℕ* suc a ⊖ (a ℕ+ c ℕ* suc a)
  distrib-lemma a b c
    rewrite +-⊖-left-cancel a (b ℕ* suc a) (c ℕ* suc a)
          | ⊖-swap (b ℕ* suc a) (c ℕ* suc a)
    with b ≤? c
  ... | yes b≤c
    rewrite ⊖-≥ b≤c
          | ⊖-≥ (b≤c *-mono (≤-refl {x = suc a}))
          | -‿◃ ((c ∸ b) ℕ* suc a)
          | ℕ.*-distrib-∸ʳ (suc a) c b
          = refl
  ... | no b≰c
    rewrite sign-⊖-≱ b≰c
          | ∣⊖∣-≱ b≰c
          | +‿◃ ((b ∸ c) ℕ* suc a)
          | ⊖-≱ (b≰c ∘ ℕ.cancel-*-right-≤ b c a)
          | -‿involutive (+ (b ℕ* suc a ∸ c ℕ* suc a))
          | ℕ.*-distrib-∸ʳ (suc a) b c
          = refl

  distribʳ : _*_ DistributesOverʳ _+_

  distribʳ (+ zero) y z
    rewrite proj₂ *-zero ∣ y ∣
          | proj₂ *-zero ∣ z ∣
          | proj₂ *-zero ∣ y + z ∣
          = refl

  distribʳ x (+ zero) z
    rewrite proj₁ +-identity z
          | proj₁ +-identity (sign z S* sign x ◃ ∣ z ∣ ℕ* ∣ x ∣)
          = refl

  distribʳ x y (+ zero)
    rewrite proj₂ +-identity y
          | proj₂ +-identity (sign y S* sign x ◃ ∣ y ∣ ℕ* ∣ x ∣)
          = refl

  distribʳ -[1+ a ] -[1+ b ] -[1+ c ] = cong +_ $
    solve 3 (λ a b c → (con 2 :+ b :+ c) :* (con 1 :+ a)
                    := (con 1 :+ b) :* (con 1 :+ a) :+
                       (con 1 :+ c) :* (con 1 :+ a))
            refl a b c

  distribʳ (+ suc a) (+ suc b) (+ suc c) = cong +_ $
    solve 3 (λ a b c → (con 1 :+ b :+ (con 1 :+ c)) :* (con 1 :+ a)
                    := (con 1 :+ b) :* (con 1 :+ a) :+
                       (con 1 :+ c) :* (con 1 :+ a))
          refl a b c

  distribʳ -[1+ a ] (+ suc b) (+ suc c) = cong -[1+_] $
    solve 3 (λ a b c → a :+ (b :+ (con 1 :+ c)) :* (con 1 :+ a)
                     := (con 1 :+ b) :* (con 1 :+ a) :+
                        (a :+ c :* (con 1 :+ a)))
           refl a b c

  distribʳ (+ suc a) -[1+ b ] -[1+ c ] = cong -[1+_] $
    solve 3 (λ a b c → a :+ (con 1 :+ a :+ (b :+ c) :* (con 1 :+ a))
                    := (con 1 :+ b) :* (con 1 :+ a) :+
                       (a :+ c :* (con 1 :+ a)))
           refl a b c

  distribʳ -[1+ a ] -[1+ b ] (+ suc c) = distrib-lemma a b c

  distribʳ -[1+ a ] (+ suc b) -[1+ c ] = distrib-lemma a c b

  distribʳ (+ suc a) -[1+ b ] (+ suc c)
    rewrite +-⊖-left-cancel a (c ℕ* suc a) (b ℕ* suc a)
    with b ≤? c
  ... | yes b≤c
    rewrite ⊖-≥ b≤c
          | +-comm (- (+ (a ℕ+ b ℕ* suc a))) (+ (a ℕ+ c ℕ* suc a))
          | ⊖-≥ (b≤c *-mono ≤-refl {x = suc a})
          | ℕ.*-distrib-∸ʳ (suc a) c b
          | +‿◃ (c ℕ* suc a ∸ b ℕ* suc a)
          = refl
  ... | no b≰c
    rewrite sign-⊖-≱ b≰c
          | ∣⊖∣-≱ b≰c
          | -‿◃ ((b ∸ c) ℕ* suc a)
          | ⊖-≱ (b≰c ∘ ℕ.cancel-*-right-≤ b c a)
          | ℕ.*-distrib-∸ʳ (suc a) b c
          = refl

  distribʳ (+ suc c) (+ suc a) -[1+ b ]
    rewrite +-⊖-left-cancel c (a ℕ* suc c) (b ℕ* suc c)
    with b ≤? a
  ... | yes b≤a
    rewrite ⊖-≥ b≤a
          | ⊖-≥ (b≤a *-mono ≤-refl {x = suc c})
          | +‿◃ ((a ∸ b) ℕ* suc c)
          | ℕ.*-distrib-∸ʳ (suc c) a b
          = refl
  ... | no b≰a
    rewrite sign-⊖-≱ b≰a
          | ∣⊖∣-≱ b≰a
          | ⊖-≱ (b≰a ∘ ℕ.cancel-*-right-≤ b a c)
          | -‿◃ ((b ∸ a) ℕ* suc c)
          | ℕ.*-distrib-∸ʳ (suc c) b a
          = refl

  -- The IsCommutativeSemiring module contains a proof of
  -- distributivity which is used below.

  isCommutativeSemiring : IsCommutativeSemiring _≡_ _+_ _*_ (+ 0) (+ 1)
  isCommutativeSemiring = record
    { +-isCommutativeMonoid = +-isCommutativeMonoid
    ; *-isCommutativeMonoid = *-isCommutativeMonoid
    ; distribʳ              = distribʳ
    ; zeroˡ                 = λ _ → refl
    }

commutativeRing : CommutativeRing _ _
commutativeRing = record
  { Carrier           = ℤ
  ; _≈_               = _≡_
  ; _+_               = _+_
  ; _*_               = _*_
  ; -_                = -_
  ; 0#                = + 0
  ; 1#                = + 1
  ; isCommutativeRing = record
    { isRing = record
      { +-isAbelianGroup = +-isAbelianGroup
      ; *-isMonoid       = *-isMonoid
      ; distrib          = IsCommutativeSemiring.distrib
                             isCommutativeSemiring
      }
    ; *-comm = *-comm
    }
  }

import Algebra.RingSolver.Simple as Solver
import Algebra.RingSolver.AlmostCommutativeRing as ACR
module RingSolver =
  Solver (ACR.fromCommutativeRing commutativeRing) _≟_

------------------------------------------------------------------------
-- More properties

-- Multiplication is right cancellative for non-zero integers.

cancel-*-right : ∀ i j k →
                 k ≢ + 0 → i * k ≡ j * k → i ≡ j
cancel-*-right i j k            ≢0 eq with signAbs k
cancel-*-right i j .(+ 0)       ≢0 eq | s ◂ zero  = contradiction refl ≢0
cancel-*-right i j .(s ◃ suc n) ≢0 eq | s ◂ suc n
  with ∣ s ◃ suc n ∣ | abs-◃ s (suc n) | sign (s ◃ suc n) | sign-◃ s n
...  | .(suc n)      | refl            | .s               | refl =
  ◃-cong (sign-i≡sign-j i j eq) $
         ℕ.cancel-*-right ∣ i ∣ ∣ j ∣ $ abs-cong eq
  where
  sign-i≡sign-j : ∀ i j →
                  sign i S* s ◃ ∣ i ∣ ℕ* suc n ≡
                  sign j S* s ◃ ∣ j ∣ ℕ* suc n →
                  sign i ≡ sign j
  sign-i≡sign-j i              j              eq with signAbs i | signAbs j
  sign-i≡sign-j .(+ 0)         .(+ 0)         eq | s₁ ◂ zero   | s₂ ◂ zero   = refl
  sign-i≡sign-j .(+ 0)         .(s₂ ◃ suc n₂) eq | s₁ ◂ zero   | s₂ ◂ suc n₂
    with ∣ s₂ ◃ suc n₂ ∣ | abs-◃ s₂ (suc n₂)
  ... | .(suc n₂) | refl
    with abs-cong {s₁} {sign (s₂ ◃ suc n₂) S* s} {0} {suc n₂ ℕ* suc n} eq
  ...   | ()
  sign-i≡sign-j .(s₁ ◃ suc n₁) .(+ 0)         eq | s₁ ◂ suc n₁ | s₂ ◂ zero
    with ∣ s₁ ◃ suc n₁ ∣ | abs-◃ s₁ (suc n₁)
  ... | .(suc n₁) | refl
    with abs-cong {sign (s₁ ◃ suc n₁) S* s} {s₁} {suc n₁ ℕ* suc n} {0} eq
  ...   | ()
  sign-i≡sign-j .(s₁ ◃ suc n₁) .(s₂ ◃ suc n₂) eq | s₁ ◂ suc n₁ | s₂ ◂ suc n₂
    with ∣ s₁ ◃ suc n₁ ∣ | abs-◃ s₁ (suc n₁)
       | sign (s₁ ◃ suc n₁) | sign-◃ s₁ n₁
       | ∣ s₂ ◃ suc n₂ ∣ | abs-◃ s₂ (suc n₂)
       | sign (s₂ ◃ suc n₂) | sign-◃ s₂ n₂
  ... | .(suc n₁) | refl | .s₁ | refl | .(suc n₂) | refl | .s₂ | refl =
    SignProp.cancel-*-right s₁ s₂ (sign-cong eq)

-- Multiplication with a positive number is right cancellative (for
-- _≤_).

cancel-*-+-right-≤ : ∀ m n o → m * + suc o ≤ n * + suc o → m ≤ n
cancel-*-+-right-≤ (-[1+ m ]) (-[1+ n ]) o (-≤- n≤m) =
  -≤- (≤-pred (ℕ.cancel-*-right-≤ (suc n) (suc m) o (s≤s n≤m)))
cancel-*-+-right-≤ ℤ.-[1+ _ ] (+ _)      _ _         = -≤+
cancel-*-+-right-≤ (+ 0)      ℤ.-[1+ _ ] _ ()
cancel-*-+-right-≤ (+ suc _)  ℤ.-[1+ _ ] _ ()
cancel-*-+-right-≤ (+ 0)      (+ 0)      _ _         = +≤+ z≤n
cancel-*-+-right-≤ (+ 0)      (+ suc _)  _ _         = +≤+ z≤n
cancel-*-+-right-≤ (+ suc _)  (+ 0)      _ (+≤+ ())
cancel-*-+-right-≤ (+ suc m)  (+ suc n)  o (+≤+ m≤n) =
  +≤+ (ℕ.cancel-*-right-≤ (suc m) (suc n) o m≤n)

-- Multiplication with a positive number is monotone.

*-+-right-mono : ∀ n → (λ x → x * + suc n) Preserves _≤_ ⟶ _≤_
*-+-right-mono _ (-≤+             {n = 0})         = -≤+
*-+-right-mono _ (-≤+             {n = suc _})     = -≤+
*-+-right-mono x (-≤-                         n≤m) =
  -≤- (≤-pred (s≤s n≤m *-mono ≤-refl {x = suc x}))
*-+-right-mono _ (+≤+ {m = 0}     {n = 0}     m≤n) = +≤+ m≤n
*-+-right-mono _ (+≤+ {m = 0}     {n = suc _} m≤n) = +≤+ z≤n
*-+-right-mono _ (+≤+ {m = suc _} {n = 0}     ())
*-+-right-mono x (+≤+ {m = suc _} {n = suc _} m≤n) =
  +≤+ (m≤n *-mono ≤-refl {x = suc x})


{-# OPTIONS --without-K #-}
open import HoTT.Base
open import HoTT.Equivalence
open import HoTT.Identity.Product

module HoTT.Equivalence.Product where

private
  variable
    i : Level
    A A' B B' : 𝒰 i

×-swap : A × B → B × A
×-swap x = pr₂ x , pr₁ x

×-comm : A × B ≃ B × A
×-comm = ×-swap , qinv→isequiv (×-swap , ×-uniq , ×-uniq)

×-equiv₁ : A ≃ A' → A × B ≃ A' × B
×-equiv₁ {A = A} {A' = A'} {B = B} (f₁ , e₁) = f , qinv→isequiv (g , η , ε)
  where
  open qinv (isequiv→qinv e₁) renaming (g to g₁ ; η to η₁ ; ε to ε₁)
  f : A × B → A' × B
  f (a , b) = f₁ a , b
  g : A' × B → A × B
  g (a' , b) = g₁ a' , b
  η : g ∘ f ~ id
  η (a , b) = ×-pair⁼ (η₁ a , refl)
  ε : f ∘ g ~ id
  ε (a' , b) = ×-pair⁼ (ε₁ a' , refl)

×-equiv₂ : B ≃ B' → A × B ≃ A × B'
×-equiv₂ {B = B} {B' = B'} {A = A} (f₂ , e₂) = f , qinv→isequiv (g , η , ε)
  where
  open qinv (isequiv→qinv e₂) renaming (g to g₂ ; η to η₂ ; ε to ε₂)
  f : A × B → A × B'
  f (a , b) = a , f₂ b
  g : A × B' → A × B
  g (a , b') = a , g₂ b'
  η : g ∘ f ~ id
  η (a , b) = ×-pair⁼ (refl , η₂ b)
  ε : f ∘ g ~ id
  ε (a , b') = ×-pair⁼ (refl , ε₂ b')


{-
This second-order equational theory was created from the following second-order syntax description:

syntax Sum | S

type
  _⊕_ : 2-ary | l30

term
  inl  : α  ->  α ⊕ β
  inr  : β  ->  α ⊕ β
  case : α ⊕ β  α.γ  β.γ  ->  γ

theory
  (lβ) a : α   f : α.γ  g : β.γ |> case (inl(a), x.f[x], y.g[y])      = f[a]
  (rβ) b : β   f : α.γ  g : β.γ |> case (inr(b), x.f[x], y.g[y])      = g[b]
  (cη) s : α ⊕ β  c : (α ⊕ β).γ |> case (s, x.c[inl(x)], y.c[inr(y)]) = c[s]
-}

module Sum.Equality where

open import SOAS.Common
open import SOAS.Context
open import SOAS.Variable
open import SOAS.Families.Core
open import SOAS.Families.Build
open import SOAS.ContextMaps.Inductive

open import Sum.Signature
open import Sum.Syntax

open import SOAS.Metatheory.SecondOrder.Metasubstitution S:Syn
open import SOAS.Metatheory.SecondOrder.Equality S:Syn

private
  variable
    α β γ τ : ST
    Γ Δ Π : Ctx

infix 1 _▹_⊢_≋ₐ_

-- Axioms of equality
data _▹_⊢_≋ₐ_ : ∀ 𝔐 Γ {α} → (𝔐 ▷ S) α Γ → (𝔐 ▷ S) α Γ → Set where
  lβ : ⁅ α ⁆ ⁅ α ⊩ γ ⁆ ⁅ β ⊩ γ ⁆̣ ▹ ∅ ⊢   case (inl 𝔞) (𝔟⟨ x₀ ⟩) (𝔠⟨ x₀ ⟩) ≋ₐ 𝔟⟨ 𝔞 ⟩
  rβ : ⁅ β ⁆ ⁅ α ⊩ γ ⁆ ⁅ β ⊩ γ ⁆̣ ▹ ∅ ⊢   case (inr 𝔞) (𝔟⟨ x₀ ⟩) (𝔠⟨ x₀ ⟩) ≋ₐ 𝔠⟨ 𝔞 ⟩
  cη : ⁅ α ⊕ β ⁆ ⁅ (α ⊕ β) ⊩ γ ⁆̣ ▹ ∅ ⊢ case 𝔞 (𝔟⟨ inl x₀ ⟩) (𝔟⟨ inr x₀ ⟩) ≋ₐ 𝔟⟨ 𝔞 ⟩

open EqLogic _▹_⊢_≋ₐ_
open ≋-Reasoning


{-
  Copyright 2019 Lisandra Silva

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

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

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

open import Prelude

module StateMachineModel where

   -----------------------------------------------------------------------------
   -- State Machine
   -----------------------------------------------------------------------------
  record StateMachine (State : Set) (Event : Set) : Set₁ where
    field
      initial : Pred State 0ℓ
      enabled : Event → State → Set
      action  : ∀ {preState} {event} → enabled event preState → State
  open StateMachine

  data Reachable {State Event} {sm : StateMachine State Event} : State → Set where
    init : ∀ {s₀} → initial sm s₀
           → Reachable s₀
    step : ∀ {st event} → Reachable {sm = sm} st → (enEv : enabled sm event st)
           → Reachable (action sm enEv)

  Invariant : ∀ {State Event} (sm : StateMachine State Event) (P : Pred State 0ℓ) → Set
  Invariant sm P = ∀ {state} (rs : Reachable {sm = sm} state) → P state

  Stable : ∀ {State Event} (sm : StateMachine State Event) (P : Pred State 0ℓ) → Set
  Stable sm P = ∀ {st ev} (enEv : enabled sm ev st)
                → P st
                → P (action sm enEv)

  EventSet : ∀ {Event : Set} → Set₁
  EventSet {Event} = Pred Event 0ℓ

  record System State Event : Set₁ where
    field
      stateMachine : StateMachine State Event
      weakFairness : Pred (EventSet {Event}) 0ℓ
  open System

  enabledSet : ∀ {State Event} → StateMachine State Event
               → EventSet {Event} → State → Set
  enabledSet sm evSet state = ∃[ event ] (event ∈ evSet × enabled sm event state)

  module LeadsTo
    (State : Set) (Event : Set) (sys : System State Event)
    where

   -----------------------------------------------------------------------------
   -- HOARE Triple
   -----------------------------------------------------------------------------
   data [_]_[_] (P : Pred State 0ℓ) (event : Event) (Q : Pred State 0ℓ) : Set where
      hoare : (∀ {st} → P st
                      → (enEv : enabled (stateMachine sys) event st)
                      → Q (action (stateMachine sys) enEv ))
               → [ P ] event [ Q ]

   Z : Set
   Z = ℕ

   -- Auxiliary properties with syntax renaming for better compliance with paper
   -- TODO : Try to make this more generic
   ⋃₁ : ∀ {ℓ ℓ'} {A : Set ℓ'} → (A → Pred State ℓ) → Pred State (ℓ ⊔ ℓ')
   ⋃₁ {A = A} P = λ x → Σ[ i ∈ A ] P i x

   syntax ⋃₁ (λ i → P) = [∃ i ∶ P ]

   ⋃₂ : ∀ {ℓ₁ ℓ₂ ℓ'} {A : Set ℓ'} → (C : Pred A ℓ₁) → (F : A → Pred State ℓ₂) → Pred State _
   ⋃₂ {A = A} C F = λ s → Σ[ i ∈ A ] ( C i × F i s )

   syntax ⋃₂ C (λ x → P) = [∃ x ⇒ C ∶ P ]

   -----------------------------------------------------------------------------
   -- PROOF RULES for liveness
   -----------------------------------------------------------------------------
   infix 1 _l-t_

   data _l-t_ (P : Pred State 0ℓ) (Q : Pred State 0ℓ) : Set₁ where
     viaEvSet  :   (evSet : EventSet) → (weakFairness sys evSet)
                 → (∀ (e : Event) → e ∈ evSet → [ P ] e [ Q ])
                 → (∀ (e : Event) → ¬ (e ∈ evSet) → [ P ] e [ P ∪ Q ])
                 → Invariant (stateMachine sys)
                             (P ⇒ enabledSet (stateMachine sys) evSet)
               → P l-t Q

     viaInv    : Invariant (stateMachine sys) (P ⇒ Q)
                 → P l-t Q

     viaTrans  : ∀ {R} → P l-t R → R l-t Q
                 → P l-t Q

     viaTrans2 : ∀ {R} → P l-t (Q ∪ R) → R l-t Q
                 → P l-t Q

     viaDisj   : ∀ {P₁ P₂} → P ⊆ (P₁ ∪ P₂) → P₁ l-t Q → P₂ l-t Q
                 → P  l-t Q

     viaUseInv : ∀ {R} → Invariant (stateMachine sys) R → (P ∩ R) l-t (R ⇒ Q)
                 → P l-t Q

     viaWFR    : ∀ (F : Z → Pred State 0ℓ)
                 → P l-t (Q ∪ [∃ x ∶ F x ])
                 → (∀ (w : Z) → F w l-t (Q ∪ [∃ x ⇒ _< w ∶ F x ]))
                 → P l-t Q

     viaAllVal : ∀ {A : Set} → {R : A → Pred State 0ℓ}
                 → Invariant (stateMachine sys) [∃ x ∶ R x ]
                 → (∀ (a : A) → (P ∩ R a) l-t Q )
                 → P l-t Q

     viaStable : ∀ {P' Q' S} → Stable (stateMachine sys) S
                 → P l-t P' ∩ S → P' l-t Q' → Q' ∩ S l-t Q
                 → P l-t Q

   P⊆QQ→Inv[P⇒Q] : ∀ {P Q} {sm : StateMachine State Event}
                   → P ⊆ Q
                   → Invariant sm (P ⇒ Q)
   P⊆QQ→Inv[P⇒Q] p⊆q rs pS
     with p⊆q pS
   ... | qS = qS

   invR⇒P-l-t-P∧R : ∀ {P R} {sm : StateMachine State Event}
                    → Invariant (stateMachine sys) R
                    → P l-t P ∩ R
   invR⇒P-l-t-P∧R invR = viaInv (λ rs ps → ps , (invR rs))


module BTree {A : Set} where

open import Data.List

data BTree : Set where
  leaf : BTree
  node : A → BTree → BTree → BTree

flatten : BTree → List A
flatten leaf = []
flatten (node x l r) = (flatten l) ++ (x ∷ flatten r)


module Main where

import Automaton.DeterministicFinite
import Automaton.NonDeterministicFinite
import Automaton.Pushdown
import Automaton.TuringMachine
import Cardinal
import Cardinal.Finite.Count
import Cardinal.Proofs
import Data
import Data.Any
import Data.Boolean
import Data.Boolean.Stmt
import Data.Boolean.Operators
import Data.Boolean.Proofs
import Data.Either
import Data.List
import Data.List.Computability
import Data.List.Proofs
import Data.List.Relation.Membership.Proofs
import Data.List.Relation.Sublist.Proofs
import Data.List.Relation
import Data.List.Relation.Membership
import Data.List.Relation.Sublist
import Data.ListNonEmpty
import Data.Option
import Data.Proofs
import Data.Tuple
import Data.Tuple.Function
import Data.Tuple.List
import Data.Tuple.Proofs
import Data.Tuple.Raise
import Data.Tuple.Raiseᵣ
import Data.Tuple.Raiseₗ
import FFI.IO   as FFI
import FormalLanguage
import FormalLanguage.ContextFreeGrammar
import FormalLanguage.Proofs
import FormalLanguage.RegularExpression
import Functional
import Function.DomainRaise
import Function.Domains
import Function.Domains.Proofs
import Function.Equals
import Function.Names
import Function.PrimitiveRecursion
import Function.Proofs
import Function.Iteration
import Function.Iteration.Proofs
-- import Geometry.Test
-- import Geometry.Test2
import Geometry.Test3
import Graph
import Lang.Instance
import Lang.Irrelevance
import Logic.Classical
import Logic.Classical.DoubleNegated
import Logic.Classical.Mere
import Logic.Computability
import Logic.Computability.Binary
import Logic.Convenience
import Logic.DiagonalProof
import Logic.LambdaCalculus
import Logic.Predicate
import Logic.Predicate.Theorems
import Logic.Propositional
import Logic.Propositional.Names
import Logic.Propositional.Theorems
import Lvl
import Metalogic.Classical.Propositional.ProofSystem
import Metalogic.Classical.Propositional.Syntax
import Metalogic.Classical.Propositional.TruthSemanticsModel
import Metalogic.Constructive.NaturalDeduction.TreeModel
-- import Metalogic.Constructive.Provability
import Metalogic.Linear.SequentCalculus
import Metalogic.Linear.Syntax
import Numeral.CoordinateVector
import Numeral.FiniteInclusive
import Numeral.Finite
import Numeral.Finite.Bound
import Numeral.Finite.Functions
import Numeral.Finite.Oper
import Numeral.Finite.Oper.Comparisons
import Numeral.Finite.Proofs
import Numeral.Integer
import Numeral.Integer.Function
import Numeral.Integer.Oper
import Numeral.Integer.Proofs
import Numeral.Integer.Relation
import Numeral.Integer.Sign
import Numeral.Matrix
import Numeral.Natural
import Numeral.Natural.Coprime
import Numeral.Natural.Function
import Numeral.Natural.Function.Proofs
-- import Numeral.Natural.GreatestCommonDivisor
import Numeral.Natural.Induction
import Numeral.Natural.Inductions
import Numeral.Natural.Oper
import Numeral.Natural.Oper.Comparisons
import Numeral.Natural.Oper.Comparisons.Proofs
import Numeral.Natural.Oper.Divisibility
import Numeral.Natural.Oper.Modulo
import Numeral.Natural.Oper.Modulo.Proofs
import Numeral.Natural.Oper.Proofs
import Numeral.Natural.Order
import Numeral.Natural.Prime
import Numeral.Natural.Relation
import Numeral.Natural.Relation.Computability
import Numeral.Natural.Relation.Countable
import Numeral.Natural.Relation.Divisibility
import Numeral.Natural.Relation.Order
import Numeral.Natural.Relation.Order.Computability
import Numeral.Natural.Relation.Order.Existence
import Numeral.Natural.Relation.Order.Existence.Proofs
import Numeral.Natural.Relation.Order.Proofs
import Numeral.Natural.Relation.Properties
import Numeral.Natural.TotalOper
import Numeral.Natural.UnclosedOper
import Numeral.PositiveInteger
import Numeral.PositiveInteger.Oper
import Numeral.Rational.AlterAdd
-- import Numeral.Rational.SternBrocot
import Numeral.Real
import Numeral.Real.Properties
import Numeral.Sign
import Numeral.Sign.Oper
import Numeral.Sign.Oper0
import Operator.Equals
import Relator.Bijection
import Relator.Congruence
import Relator.Congruence.Proofs
import Relator.Countable
import Relator.Equals
import Relator.Equals.Proofs
import Relator.Equals.Proofs.Uniqueness
import Structure.Setoid.Uniqueness
import Relator.Finite
import Sets.BoolSet
import Sets.BoolSet.Proofs
import Sets.ETCS
import Sets.IZF
import Sets.PredicateSet
import Sets.PredicateSet.Filter
import Sets.PredicateSet.Finite
import Sets.PredicateSet.Proofs
import Sets.PredicateSet.Relations
import Structure.Setoid
import Structure.Setoid.Proofs
import Stream
import String
import Structure.Arithmetic
-- import Structure.Category
import Structure.Function.Domain
import Structure.Function.Linear
import Structure.Function.Ordering
import Structure.LinearAlgebra
import Structure.Logic.Classical.PredicateBoundedQuantification
import Structure.Logic.Classical.NaturalDeduction
import Structure.Logic.Classical.NaturalDeduction.Proofs
import Structure.Logic.Classical.SetTheory
import Structure.Logic.Classical.SetTheory.SetBoundedQuantification
import Structure.Logic.Classical.SetTheory.Function
import Structure.Logic.Classical.SetTheory.Relation
import Structure.Logic.Classical.SetTheory.ZFC
import Structure.Logic.Classical.SetTheory.ZFC.BinaryRelatorSet
-- import Structure.Logic.Classical.SetTheory.ZFC.Finite
import Structure.Logic.Classical.SetTheory.ZFC.FunctionSet
import Structure.Logic.Classical.SetTheory.ZFC.Proofs
import Structure.Logic.Constructive.Functions.Properties
import Structure.Logic.Constructive.NaturalDeduction
import Structure.Operator.Field
import Structure.Operator.Functions
import Structure.Operator.Group
import Structure.Operator.Group.Proofs
import Structure.Operator.Monoid
import Structure.Operator.Proofs
import Structure.Operator.Properties
import Structure.Operator.SetAlgebra
import Structure.Operator.Vector
import Structure.Real
import Structure.Relator.Equivalence as Eq
import Structure.Relator.Function
import Structure.Relator.Ordering
import Structure.Relator.Ordering.Subsets
import Structure.Relator.Properties
import Structure.Relator.Properties.Proofs
import Syntax.Function
import Syntax.Method
import Syntax.Number
import Type
import Type.Cardinality
import Type.Cardinality.Proofs
import Type.Dependent
import Type.Properties.Empty
import Type.Properties.Empty.Proofs
import Type.Functions
import Type.Functions.Inverse
import Type.Functions.Inverse.Proofs
import Type.Functions.Proofs
import Type.Singleton
import Type.Singleton.Proofs
import Type.Properties.Singleton
import Type.Properties.Singleton.Proofs
import Type.Univalence

main : FFI.IO Data.Unit
main = FFI.printStrLn("Okay")


open import Everything

{-
open import Oscar.Prelude
open import Oscar.Class.HasEquivalence
open import Oscar.Class.Symmetrical
open import Oscar.Data.Term
open import Oscar.Data.Substitunction
open import Oscar.Data.Surjcollation
open import Oscar.Data.Surjextenscollation
open import Oscar.Data.Proposequality
import Oscar.Class.HasEquivalence.ExtensionṖroperty
import Oscar.Class.HasEquivalence.Ṗroperty
import Oscar.Class.Symmetrical.ExtensionalUnifies
import Oscar.Class.Symmetrical.Unifies
import Oscar.Property.Setoid.Proposequality -- FIXME see _∼⁰_ below; comment this out to observe confusing error messages
import Oscar.Property.Functor.SubstitunctionExtensionTerm
import Oscar.Class.Surjection.⋆
-}

module Test.SymmetricalSubstitunction {𝔭} (𝔓 : Ø 𝔭) (ℓ : Ł) where
  open Term 𝔓 using () renaming (
    Term to 𝑩;
    Terms to 𝑩')
  open Substitunction 𝔓 using () renaming (
    Substitunction to 𝑪)

  infix 18 _∼⁰_
  _∼⁰_ = ≡-surjcollation⟦ 𝑪 ⟧ --  ≡-Unifies₀⟦ 𝑪 ⟧ -- FIXME gives a confusing error message
  -- _∼⁰_ = ≡-SymUnifies₀⟦ 𝑪 ⟧ -- FIXME gives a more useful error message

  open Surjextenscollation 𝑪 _≡̇_ renaming (_⟹_ to _∼¹_)

  fact1⋆ : ∀ {𝓃} (𝓈 𝓉 : 𝑩 𝓃) → 𝓈 ∼⁰ 𝓉 ≈ 𝓉 ∼⁰ 𝓈
  fact1⋆ 𝓈 𝓉 = symmetrical 𝓈 𝓉
  -- fact1⋆ 𝓈 𝓉 = symmetrical ⦃ r = Oscar.Class.Symmetrical.Unifies.𝓢ymmetricalUnifies₀ ⦃ ! ⦄ ⦃ ! ⦄ ⦃ Oscar.Property.Setoid.Proposequality.𝓢ymmetryProposequality ⦄ ⦄ 𝓈 𝓉 -- FIXME I wish Agda would tell us that this is how the instances were resolved

  fact1⋆s : ∀ {N 𝓃} (𝓈 𝓉 : 𝑩' N 𝓃) → 𝓈 ∼⁰ 𝓉 ≈ 𝓉 ∼⁰ 𝓈
  fact1⋆s 𝓈 𝓉 = symmetrical 𝓈 𝓉

  fact1 : ∀ {𝓃} (𝓈 𝓉 : 𝑩 𝓃) → 𝓈 ∼¹ 𝓉 ≈ 𝓉 ∼¹ 𝓈
  fact1 𝓈 𝓉 = symmetrical 𝓈 𝓉

  fact1s : ∀ {N 𝓃} (𝓈 𝓉 : 𝑩' N 𝓃) → 𝓈 ∼¹ 𝓉 ≈ 𝓉 ∼¹ 𝓈
  fact1s 𝓈 𝓉 = symmetrical 𝓈 𝓉


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

open import Categories.Category
open import Categories.Object.Zero

module Categories.Object.Kernel.Properties {o ℓ e} {𝒞 : Category o ℓ e} (𝒞-Zero : Zero 𝒞) where

open import Function using (_$_)

open import Categories.Diagram.Equalizer 𝒞
open import Categories.Diagram.Pullback 𝒞 renaming (glue to glue-pullback; up-to-iso to pullback-up-to-iso)
open import Categories.Diagram.Pullback.Properties 𝒞
open import Categories.Object.Kernel 𝒞-Zero
open import Categories.Object.Terminal 𝒞

open import Categories.Morphism 𝒞
open import Categories.Morphism.Reasoning 𝒞

open Category 𝒞
open HomReasoning
open Equiv

open Zero 𝒞-Zero

private
  variable
    A B : Obj
    f : A ⇒ B

-- We can express kernels as pullbacks along the morphism '! : ⊥ ⇒ A'.
Kernel⇒Pullback : Kernel f → Pullback f !
Kernel⇒Pullback {f = f} kernel = record
  { p₁ = kernel⇒
  ; p₂ = ¡
  ; isPullback = record
    { commute = commute
    ; universal = λ {C} {h₁} {h₂} eq → universal {h = h₁} $ begin
      f ∘ h₁ ≈⟨ eq ⟩
      ! ∘ h₂ ≈˘⟨ refl⟩∘⟨ ¡-unique h₂ ⟩
      zero⇒ ∎
    ; unique = λ {C} {h₁} {h₂} {i} k-eq h-eq → unique $ begin
      h₁ ≈˘⟨ k-eq ⟩
      kernel⇒ ∘ i ∎
    ; p₁∘universal≈h₁ = ⟺ factors
    ; p₂∘universal≈h₂ = ¡-unique₂ _ _
    }
  }
  where
    open Kernel kernel

-- All pullbacks along the morphism '! : ⊥ ⇒ A' are also kernels.
Pullback⇒Kernel : Pullback f ! → Kernel f
Pullback⇒Kernel {f = f} pullback = record
  { kernel⇒ = p₁
  ; isKernel = record
    { commute = begin
      f ∘ p₁ ≈⟨ commute ⟩
      ! ∘ p₂ ≈˘⟨ refl⟩∘⟨ ¡-unique p₂ ⟩
      zero⇒ ∎
    ; universal = λ eq → universal eq
    ; factors = ⟺ p₁∘universal≈h₁
    ; unique = λ eq → unique (⟺ eq) (⟺ (¡-unique _))
    }
  }
  where
    open Pullback pullback

-- We can also express kernels as the equalizer of 'f' and the zero morphism.
Kernel⇒Equalizer : Kernel f → Equalizer f zero⇒
Kernel⇒Equalizer {f = f} kernel = record
  { arr = kernel⇒
  ; isEqualizer = record
    { equality = begin
      f ∘ kernel⇒ ≈⟨ commute ⟩
      zero⇒       ≈⟨ pushʳ (¡-unique (¡ ∘ kernel⇒)) ⟩
      zero⇒ ∘ kernel⇒ ∎
    ; equalize = λ {_} {h} eq → universal (eq ○ pullʳ (⟺ (¡-unique (¡ ∘ h))))
    ; universal = factors
    ; unique = unique
    }
  }
  where
    open Kernel kernel

-- Furthermore, all equalizers of 'f' and the zero morphism are equalizers
Equalizer⇒Kernel : Equalizer f zero⇒ → Kernel f
Equalizer⇒Kernel {f = f} equalizer = record
  { kernel⇒ = arr
  ; isKernel = record
    { commute = begin
      f ∘ arr      ≈⟨ equality ⟩
      zero⇒ ∘ arr ≈⟨ pullʳ (⟺ (¡-unique (¡ ∘ arr))) ⟩
      zero⇒ ∎
    ; universal = λ {_} {h} eq → equalize (eq ○ pushʳ (¡-unique (¡ ∘ h)))
    ; factors = universal
    ; unique = unique
    }
  }
  where
    open Equalizer equalizer

module _ (K : Kernel f) where
  open Kernel K

  Kernel-Mono : Mono kernel⇒
  Kernel-Mono g₁ g₂ eq = begin
    g₁ ≈⟨ unique refl ⟩
    universal universal-∘ ≈˘⟨ unique eq ⟩
    g₂ ∎

module _ (has-kernels : ∀ {A B} → (f : A ⇒ B) → Kernel f) where

  -- The kernel of a kernel is isomorphic to the zero object.
  kernel²-zero : ∀ {A B} {f : A ⇒ B} → Kernel.kernel (has-kernels (Kernel.kernel⇒ (has-kernels f))) ≅ zero
  kernel²-zero {B = B} {f = f} = pullback-up-to-iso kernel-pullback (pullback-mono-mono !-Mono)
    where
      K : Kernel f
      K = has-kernels f

      module K = Kernel K

      K′ : Kernel K.kernel⇒
      K′ = has-kernels K.kernel⇒

      kernel-pullback : Pullback ! !
      kernel-pullback = Pullback-resp-≈ (glue-pullback (Kernel⇒Pullback K) (swap (Kernel⇒Pullback K′))) (!-unique (f ∘ !)) refl

      pullback-mono-mono : ∀ {A B} {f : A ⇒ B} → Mono f → Pullback f f
      pullback-mono-mono mono = record
        { p₁ = id
        ; p₂ = id
        ; isPullback = pullback-self-mono mono
        }


{-

Mayer-Vietoris cofiber sequence:

  Let X be a pointed type, and let a span B ←[f]- X -[g]→ C be given.
  Then the mapping cone of the canonical map (B ⋁ C) → B ⊔_X C is equivalent to Susp X.

The sequence Susp X → (B ⋁ C) → B ⊔_X C therefore induces a long exact sequence in cohomology.
Proof is adapted from Evan Cavallo's master's thesis.

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Homotopy.MayerVietorisCofiber where

open import Cubical.Core.Everything
open import Cubical.Foundations.Everything
open import Cubical.Foundations.Pointed
open import Cubical.Data.Unit
open import Cubical.HITs.MappingCones
open import Cubical.HITs.Pushout
open import Cubical.HITs.Susp
open import Cubical.HITs.Wedge

module _ {ℓX ℓB ℓC} {X : Pointed ℓX} {B : Type ℓB} {C : Type ℓC} (f : X .fst → B) (g : X .fst → C)
  where

  private
    Y : Pointed _
    Y = (B , f (X .snd))

    Z : Pointed _
    Z = (C , g (X .snd))

  wedgeToPushout : Y ⋁ Z → Pushout f g
  wedgeToPushout (inl y) = inl y
  wedgeToPushout (inr z) = inr z
  wedgeToPushout (push _ i) = push (pt X) i

  pushoutToSusp : Pushout f g → Susp (X .fst)
  pushoutToSusp (inl y) = north
  pushoutToSusp (inr z) = south
  pushoutToSusp (push x i) = merid x i

  {-
    Coherence lemma:
    To construct a function f : (c : Cone wedgeToPushout) → D c, we can always
    adjust the definition of (f (spoke (inr z) i)) so that there is a canonical
    choice for (f (spoke (push tt j) i))
  -}
  module Helper {ℓD} {D : Cone wedgeToPushout → Type ℓD}
    (inj* : ∀ w → D (inj w))
    (hub* : D hub)
    (inl* : ∀ y → PathP (λ i → D (spoke (inl y) i)) hub* (inj* (inl y)))
    (inr* : ∀ z → PathP (λ i → D (spoke (inr z) i)) hub* (inj* (inr z)))
    where

    cap : (i j : I) → D (spoke (push tt j) i)
    cap i j =
      fill
        (λ i → D (spoke (push tt j) (~ i)))
        (λ i → λ
          { (j = i0) → inl* (Y .snd) (~ i)
          ; (j = i1) → inr* (Z .snd) (~ i)
          })
        (inS (inj* (push (X .snd) j)))
        (~ i)

    cap0 : (j : I) → D hub
    cap0 = cap i0

    face-i≡0 : (k j : I) → D hub
    face-i≡0 k j =
      hfill
        (λ j → λ
          { (k = i0) → cap0 j
          ; (k = i1) → hub*
          })
        (inS hub*)
        j

    inrFiller : ∀ z → (k i : I) → D (spoke (inr z) i)
    inrFiller z k i =
     hfill
       (λ k → λ
         { (i = i0) → face-i≡0 k i1
         ; (i = i1) → inj* (inr z)
         })
       (inS (inr* z i))
       k

    fun : ∀ c → D c
    fun (inj w) = inj* w
    fun hub = hub*
    fun (spoke (inl y) i) = inl* y i
    fun (spoke (inr z) i) = inrFiller z i1 i
    fun (spoke (push tt j) i) =
      hcomp
        (λ k → λ
          { (i = i0) → face-i≡0 k j
          ; (i = i1) → inj* (push (X .snd) j)
          ; (j = i0) → inl* (Y .snd) i
          })
        (cap i j)

  equiv : Cone wedgeToPushout ≃ Susp (X .fst)
  equiv = isoToEquiv (iso fwd bwd fwdBwd bwdFwd)
    where
    fwd : Cone wedgeToPushout → Susp (X .fst)
    fwd (inj w) = pushoutToSusp w
    fwd hub = north
    fwd (spoke (inl y) i) = north
    fwd (spoke (inr z) i) = merid (X .snd) i
    fwd (spoke (push tt j) i) = merid (X .snd) (i ∧ j)

    bwd : Susp (X .fst) → Cone wedgeToPushout
    bwd north = hub
    bwd south = hub
    bwd (merid x i) =
      hcomp
        (λ k → λ
          { (i = i0) → spoke (inl (f x)) (~ k)
          ; (i = i1) → spoke (inr (g x)) (~ k)
          })
        (inj (push x i))

    bwdPushout : (w : Pushout f g) → bwd (pushoutToSusp w) ≡ inj w
    bwdPushout (inl y) = spoke (inl y)
    bwdPushout (inr z) = spoke (inr z)
    bwdPushout (push x i) k =
      hfill
        (λ k → λ
          { (i = i0) → spoke (inl (f x)) (~ k)
          ; (i = i1) → spoke (inr (g x)) (~ k)
          })
        (inS (inj (push x i)))
        (~ k)

    bwdMeridPt : refl ≡ cong bwd (merid (X .snd))
    bwdMeridPt j i =
      hcomp
        (λ k → λ
          { (i = i0) → spoke (inl (Y .snd)) (~ k)
          ; (i = i1) → spoke (inr (Z .snd)) (~ k)
          ; (j = i0) → spoke (push _ i) (~ k)
          })
        (inj (push (X .snd) i))

    bwdFwd : (c : Cone wedgeToPushout) → bwd (fwd c) ≡ c
    bwdFwd =
      Helper.fun
        bwdPushout
        refl
        (λ y i k → spoke (inl y) (i ∧ k))
        (λ z i k →
          hcomp
            (λ l → λ
              { (i = i0) → hub
              ; (i = i1) → spoke (inr z) k
              ; (k = i0) → bwdMeridPt l i
              ; (k = i1) → spoke (inr z) i
              })
            (spoke (inr z) (i ∧ k)))

    fwdBwd : (s : Susp (X .fst)) → fwd (bwd s) ≡ s
    fwdBwd north = refl
    fwdBwd south = merid (X .snd)
    fwdBwd (merid a i) j =
      fill
        (λ _ → Susp (X .fst))
        (λ j → λ
          { (i = i0) → north
          ; (i = i1) → merid (X .snd) (~ j)
          })
        (inS (merid a i))
        (~ j)


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

module Fragment.Examples.CSemigroup.Arith.Functions where

open import Fragment.Examples.CSemigroup.Arith.Base

-- Fully dynamic associativity

+-dyn-assoc₁ : ∀ {f : ℕ → ℕ} {m n o} → (f m + n) + o ≡ f m + (n + o)
+-dyn-assoc₁ = fragment CSemigroupFrex +-csemigroup

+-dyn-assoc₂ : ∀ {f g : ℕ → ℕ} {m n o p} → ((f m + n) + o) + g p ≡ f m + (n + (o + g p))
+-dyn-assoc₂ = fragment CSemigroupFrex +-csemigroup

+-dyn-assoc₃ : ∀ {f g h : ℕ → ℕ} {m n o p q} → (f m + n) + g o + (p + h q) ≡ f m + (n + g o + p) + h q
+-dyn-assoc₃ = fragment CSemigroupFrex +-csemigroup

*-dyn-assoc₁ : ∀ {f : ℕ → ℕ} {m n o} → (f m * n) * o ≡ f m * (n * o)
*-dyn-assoc₁ = fragment CSemigroupFrex *-csemigroup

*-dyn-assoc₂ : ∀ {f g : ℕ → ℕ} {m n o p} → ((f m * n) * o) * g p ≡ f m * (n * (o * g p))
*-dyn-assoc₂ = fragment CSemigroupFrex *-csemigroup

*-dyn-assoc₃ : ∀ {f g h : ℕ → ℕ} {m n o p q} → (f m * n) * g o * (p * h q) ≡ f m * (n * g o * p) * h q
*-dyn-assoc₃ = fragment CSemigroupFrex *-csemigroup

-- Fully dynamic commutativity

+-dyn-comm₁ : ∀ {f : ℕ → ℕ} {m} → f m + m ≡ m + f m
+-dyn-comm₁ = fragment CSemigroupFrex +-csemigroup

+-dyn-comm₂ : ∀ {f g : ℕ → ℕ} {m n o} → f m + (n + g o) ≡ (g o + n) + f m
+-dyn-comm₂ = fragment CSemigroupFrex +-csemigroup

+-dyn-comm₃ : ∀ {f g h : ℕ → ℕ} {m n o p} → (f m + g n) + (h o + p) ≡ (p + h o) + (g n + f m)
+-dyn-comm₃ = fragment CSemigroupFrex +-csemigroup

*-dyn-comm₁ : ∀ {f : ℕ → ℕ} {m} → f m * m ≡ m * f m
*-dyn-comm₁ = fragment CSemigroupFrex *-csemigroup

*-dyn-comm₂ : ∀ {f g : ℕ → ℕ} {m n o} → f m * (n * g o) ≡ (g o * n) * f m
*-dyn-comm₂ = fragment CSemigroupFrex *-csemigroup

*-dyn-comm₃ : ∀ {f g h : ℕ → ℕ} {m n o p} → (f m * g n) * (h o * p) ≡ (p * h o) * (g n * f m)
*-dyn-comm₃ = fragment CSemigroupFrex *-csemigroup

-- Fully dynamic associavity and commutativity

+-dyn-comm-assoc₁ : ∀ {f : ℕ → ℕ} {m} → (f m + f (f m)) + f (f (f m)) ≡ f (f (f m)) + (f (f m) + f m)
+-dyn-comm-assoc₁ = fragment CSemigroupFrex +-csemigroup

+-dyn-comm-assoc₂ : ∀ {f g : ℕ → ℕ} {m n} → ((f m + f n) + g m) + g n ≡ g m + (f n + (g n + f m))
+-dyn-comm-assoc₂ = fragment CSemigroupFrex +-csemigroup

+-dyn-comm-assoc₃ : ∀ {f : ℕ → ℕ} {m n o p q} → f (m + n) + o + (p + q) ≡ f (m + n) + q + (p + o)
+-dyn-comm-assoc₃ = fragment CSemigroupFrex +-csemigroup

*-dyn-comm-assoc₁ : ∀ {f : ℕ → ℕ} {m} → (f m * f (f m)) * f (f (f m)) ≡ f (f (f m)) * (f (f m) * f m)
*-dyn-comm-assoc₁ = fragment CSemigroupFrex *-csemigroup

*-dyn-comm-assoc₂ : ∀ {f g : ℕ → ℕ} {m n} → ((f m * f n) * g m) * g n ≡ g m * (f n * (g n * f m))
*-dyn-comm-assoc₂ = fragment CSemigroupFrex *-csemigroup

*-dyn-comm-assoc₃ : ∀ {f : ℕ → ℕ} {m n o p q} → f (m + n) * o * (p * q) ≡ f (m + n) * q * (p * o)
*-dyn-comm-assoc₃ = fragment CSemigroupFrex *-csemigroup

-- Partially static associativity

+-sta-assoc₁ : ∀ {f : ℕ → ℕ} {m} → (m + 2) + (3 + f 0) ≡ m + (5 + f 0)
+-sta-assoc₁ = fragment CSemigroupFrex +-csemigroup

+-sta-assoc₂ : ∀ {f g : ℕ → ℕ} {m n o p} → (((f m + g n) + 5) + o) + p ≡ f m + (g n + (2 + (3 + (o + p))))
+-sta-assoc₂ = fragment CSemigroupFrex +-csemigroup

+-sta-assoc₃ : ∀ {f : ℕ → ℕ} {m n o p} → f (n + m) + (n + 2) + (3 + (o + p)) ≡ (((n + 1) + (4 + o)) + p) + f (n + m)
+-sta-assoc₃ = fragment CSemigroupFrex +-csemigroup

*-sta-assoc₁ : ∀ {f : ℕ → ℕ} {m} → (m * 2) * (3 * f 0) ≡ m * (6 * f 0)
*-sta-assoc₁ = fragment CSemigroupFrex *-csemigroup

*-sta-assoc₂ : ∀ {f g : ℕ → ℕ} {m n o p} → (((f m * g n) * 6) * o) * p ≡ f m * (g n * (2 * (3 * (o * p))))
*-sta-assoc₂ = fragment CSemigroupFrex *-csemigroup

*-sta-assoc₃ : ∀ {f : ℕ → ℕ} {m n o p} → f (n + m) * (n * 4) * (3 * (o * p)) ≡ (((n * 2) * (6 * o)) * p) * f (n + m)
*-sta-assoc₃ = fragment CSemigroupFrex *-csemigroup

-- Partially static commutativity

+-sta-comm₁ : ∀ {f g : ℕ → ℕ} {m} → f m + g 1 ≡ g 1 + f m
+-sta-comm₁ = fragment CSemigroupFrex +-csemigroup

+-sta-comm₂ : ∀ {f g : ℕ → ℕ} {m n} → f m + (2 + g n) ≡ (g n + 2) + f m
+-sta-comm₂ = fragment CSemigroupFrex +-csemigroup

+-sta-comm₃ : ∀ {f g h : ℕ → ℕ} {m n o p} → (1 + (f m + g n)) + ((o + p) + h 2) ≡ ((p + o) + h 2) + (1 + (g n + f m))
+-sta-comm₃ = fragment CSemigroupFrex +-csemigroup

*-sta-comm₁ : ∀ {f g : ℕ → ℕ} {m} → f m * g 1 ≡ g 1 * f m
*-sta-comm₁ = fragment CSemigroupFrex *-csemigroup

*-sta-comm₂ : ∀ {f g : ℕ → ℕ} {m n} → f m * (2 * g n) ≡ (g n * 2) * f m
*-sta-comm₂ = fragment CSemigroupFrex *-csemigroup

*-sta-comm₃ : ∀ {f g h : ℕ → ℕ} {m n o p} → (3 * (f m * g n)) * ((o * p) * h 2) ≡ ((p * o) * h 2) * (3 * (g n * f m))
*-sta-comm₃ = fragment CSemigroupFrex *-csemigroup

-- Partially static associavity and commutativity

+-sta-comm-assoc₁ : ∀ {f : ℕ → ℕ} {m n o} → 1 + (f m + n) + f o + 4 ≡ 5 + n + (f m + f o)
+-sta-comm-assoc₁ = fragment CSemigroupFrex +-csemigroup

+-sta-comm-assoc₂ : ∀ {f g : ℕ → ℕ} {m n o p} → 5 + ((f m + n) + o) + g p ≡ g p + ((o + 1) + (n + f m)) + 4
+-sta-comm-assoc₂ = fragment CSemigroupFrex +-csemigroup

+-sta-comm-assoc₃ : ∀ {f g h : ℕ → ℕ} {m n o p q} → (f m + g n + 1) + o + (p + h q + 4) ≡ (2 + h q) + (p + o + g n) + (f m + 3)
+-sta-comm-assoc₃ = fragment CSemigroupFrex +-csemigroup

*-sta-comm-assoc₁ : ∀ {f : ℕ → ℕ} {m n o} → 2 * (f m * n) * f o * 6 ≡ 12 * n * (f m * f o)
*-sta-comm-assoc₁ = fragment CSemigroupFrex *-csemigroup

*-sta-comm-assoc₂ : ∀ {f g : ℕ → ℕ} {m n o p} → 12 * ((f m * n) * o) * g p ≡ g p * ((o * 2) * (n * f m)) * 6
*-sta-comm-assoc₂ = fragment CSemigroupFrex *-csemigroup

*-sta-comm-assoc₃ : ∀ {f g h : ℕ → ℕ} {m n o p q} → (f m * g n * 2) * o * (p * h q * 6) ≡ (4 * h q) * (p * o * g n) * (f m * 3)
*-sta-comm-assoc₃ = fragment CSemigroupFrex *-csemigroup


------------------------------------------------------------------------
-- Some properties related to the const function
------------------------------------------------------------------------

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

open import Equality

module Const
  {reflexive} (eq : ∀ {a p} → Equality-with-J a p reflexive) where

open import Logical-equivalence using (_⇔_)
open import Prelude

import Bijection eq as Bijection
open Derived-definitions-and-properties eq
open import Embedding eq
open import Equivalence eq as Eq using (_≃_)
open import Fin eq
open import Function-universe eq
open import H-level eq
open import H-level.Closure eq
open import Injection eq using (Injective)
import Nat eq as Nat
open import Univalence-axiom eq

-- If A is inhabited, then the function const : B → (A → B) is
-- injective.

const-is-injective :
  ∀ {a b} →
  {A : Type a} {B : Type b} →
  A → Injective {B = A → B} const
const-is-injective x {y} {z} =
  const y ≡ const z  ↝⟨ cong (_$ x) ⟩□
  y ≡ z              □

-- Thus, if B is a set, then const is also an embedding (assuming
-- extensionality).

const-is-embedding :
  ∀ {a b} →
  Extensionality (a ⊔ b) (a ⊔ b) →
  {A : Type a} {B : Type b} →
  Is-set B →
  A → Is-embedding {B = A → B} const
const-is-embedding {a} {b} ext B-set x =
  _≃_.to (Injective≃Is-embedding
            ext B-set
            (Π-closure (lower-extensionality b a ext) 2 λ _ →
             B-set)
            const)
    (const-is-injective x)

-- However, if B is not a set, then one can construct a counterexample
-- (assuming extensionality and univalence).
--
-- This example is due to Thierry Coquand. (His proof was not
-- identical to the one below.)

const-is-not-embedding :
  ∀ {a b} →
  Extensionality (a ⊔ b) (lsuc b) →
  Univalence b →
  Univalence (# 0) →
  ¬ ({A : Type a} {B : Type (lsuc b)} →
     A → Is-embedding {B = A → B} const)
const-is-not-embedding {a} {b} ext univ univ₀ hyp =
  from-⊎ (2 Nat.≟ 4) 2≡4
  where
  ext-b : Extensionality b b
  ext-b = lower-extensionality a (lsuc b) ext

  ext-ab₊ : Extensionality a (lsuc b)
  ext-ab₊ = lower-extensionality b lzero ext

  ext₁ : Extensionality (# 0) (# 1)
  ext₁ = lower-extensionality _ (lsuc b) ext

  ext₀ : Extensionality (# 0) (# 0)
  ext₀ = lower-extensionality _ _ ext

  emb : Is-embedding {B = ↑ a (Fin 2) → Type b} const
  emb = hyp (lift true)

  2≡4 : 2 ≡ 4
  2≡4 = _⇔_.to isomorphic-same-size (
    Fin 2                                      ↝⟨ inverse $ [Fin≡Fin]↔Fin! ext₀ univ₀ 2 ⟩
    Fin 2 ≡ Fin 2                              ↔⟨ inverse $ ≡-preserves-≃ ext-b univ univ₀ (Eq.↔⇒≃ Bijection.↑↔) (Eq.↔⇒≃ Bijection.↑↔) ⟩
    ↑ b (Fin 2) ≡ ↑ b (Fin 2)                  ↔⟨ Eq.⟨ _ , emb (↑ b (Fin 2)) (↑ b (Fin 2)) ⟩ ⟩
    const (↑ b (Fin 2)) ≡ const (↑ b (Fin 2))  ↔⟨ inverse $ Eq.extensionality-isomorphism ext-ab₊ ⟩
    (↑ a (Fin 2) → ↑ b (Fin 2) ≡ ↑ b (Fin 2))  ↔⟨ →-cong ext-ab₊ (Eq.↔⇒≃ Bijection.↑↔)
                                                    (≡-preserves-≃ ext-b univ univ₀ (Eq.↔⇒≃ Bijection.↑↔) (Eq.↔⇒≃ Bijection.↑↔)) ⟩
    (Fin 2 → Fin 2 ≡ Fin 2)                    ↝⟨ ∀-cong ext₁ (λ _ → [Fin≡Fin]↔Fin! ext₀ univ₀ 2) ⟩
    (Fin 2 → Fin 2)                            ↝⟨ [Fin→Fin]↔Fin^ ext₀ 2 2 ⟩□
    Fin 4                                      □)


module Data.List.Proofs.Length where

import Lvl
open import Functional
open import Function.Names as Names using (_⊜_)
open import Data.Boolean
open import Data.List as List
open import Data.List.Functions
open import Logic
open import Logic.Propositional
open import Numeral.Finite
open import Numeral.Natural
open import Numeral.Natural.Oper
open import Numeral.Natural.Oper.Proofs
open import Relator.Equals
open import Relator.Equals.Proofs
open import Structure.Function.Multi
open import Structure.Operator.Properties
open import Structure.Operator
open import Structure.Relator.Properties
open import Syntax.Transitivity
open import Type

private variable ℓ ℓₑ : Lvl.Level
private variable T A B : Type{ℓ}
private variable l l₁ l₂ : List(T)
private variable a b x : T
private variable n : ℕ
private variable f : A → B
private variable P : List(T) → Stmt{ℓ}

-- TODO: Almost all of these can use Preserving instead

length-[∅] : (length(∅ {T = T}) ≡ 0)
length-[∅] = [≡]-intro

length-singleton : (length{T = T}(singleton(a)) ≡ 1)
length-singleton = [≡]-intro

instance
  length-preserves-prepend : Preserving₁(length)(a ⊰_)(𝐒)
  Preserving.proof (length-preserves-prepend {a = a}) {x} = [≡]-intro

length-postpend : ((length ∘ postpend a) ⊜ (𝐒 ∘ length))
length-postpend {x = l} = List.elim [≡]-intro (\x l → [≡]-with(𝐒) {length(postpend _ l)}{𝐒(length l)}) l

instance
  length-preserves-postpend : Preserving₁(length)(postpend a)(𝐒)
  Preserving.proof (length-preserves-postpend {a = a}) {x} = length-postpend {a = a}{x = x}

length-[++] : (length{T = T}(l₁ ++ l₂) ≡ length(l₁) + length(l₂))
length-[++] {T = T} {l₁ = l₁} {l₂} = List.elim base next l₁ where
  base : length(∅ ++ l₂) ≡ length{T = T}(∅) + length(l₂)
  base = symmetry(_≡_) (identityₗ(_+_)(0))

  next : ∀(x)(l) → (length(l ++ l₂) ≡ length(l) + length(l₂)) → (length((x ⊰ l) ++ l₂) ≡ length(x ⊰ l) + length(l₂))
  next x l stmt =
    length((x ⊰ l) ++ l₂)      🝖[ _≡_ ]-[]
    length(x ⊰ (l ++ l₂))      🝖[ _≡_ ]-[]
    𝐒(length(l ++ l₂))         🝖[ _≡_ ]-[ [≡]-with(𝐒) stmt ]
    𝐒(length(l) + length(l₂))  🝖[ _≡_ ]-[ [+]-stepₗ {length(l)} {length(l₂)} ]
    𝐒(length(l)) + length(l₂)  🝖[ _≡_ ]-[]
    length(x ⊰ l) + length(l₂) 🝖-end

instance
  length-preserves-[++] : Preserving₂(length{T = T})(_++_)(_+_)
  Preserving.proof length-preserves-[++] {l₁} {l₂} = length-[++] {l₁ = l₁} {l₂ = l₂}

length-reverse : ((length{T = T} ∘ reverse) ⊜ length)
length-reverse {x = ∅}     = [≡]-intro
length-reverse {x = x ⊰ l} = length-postpend{a = x}{x = reverse l} 🝖 [≡]-with(𝐒) (length-reverse {x = l})

instance
  length-preserves-reverse : Preserving₁(length{T = T})(reverse)(id)
  Preserving.proof length-preserves-reverse {l} = length-reverse {x = l}

length-repeat : ((length{T = T} ∘ repeat(a)) ⊜ id)
length-repeat{T = T}{x = 𝟎}    = [≡]-intro
length-repeat{T = T}{x = 𝐒(n)} = [≡]-with(𝐒) (length-repeat{T = T}{x = n})

length-tail : ((length{T = T} ∘ tail) ⊜ (𝐏 ∘ length))
length-tail{x = ∅}     = [≡]-intro
length-tail{x = _ ⊰ l} = [≡]-intro

instance
  length-preserves-tail : Preserving₁(length{T = T})(tail)(𝐏)
  Preserving.proof length-preserves-tail {l} = length-tail {x = l}

length-map : ∀{f : A → B} → ((length ∘ map f) ⊜ length)
length-map {f = f}{x = ∅}     = [≡]-intro
length-map {f = f}{x = x ⊰ l} = [≡]-with(𝐒) (length-map {f = f}{x = l})

instance
  length-preserves-map : Preserving₁(length{T = T})(map f)(id)
  Preserving.proof (length-preserves-map {f = f}) {l} = length-map {f = f}{x = l}

length-foldᵣ : ∀{init}{f}{g} → (∀{x}{l} → (length(f x l) ≡ g x (length l))) → (length{T = T}(foldᵣ f init l) ≡ foldᵣ g (length init) l)
length-foldᵣ {l = ∅}                    _ = [≡]-intro
length-foldᵣ {l = x ⊰ l} {init} {f} {g} p =
  length(foldᵣ f init (x ⊰ l))    🝖[ _≡_ ]-[]
  length(f(x) (foldᵣ f init l))   🝖[ _≡_ ]-[ p ]
  g(x) (length(foldᵣ f init l))   🝖[ _≡_ ]-[ [≡]-with(g(x)) (length-foldᵣ {l = l} {init} {f} {g} p) ]
  g(x) (foldᵣ g (length init) l)  🝖[ _≡_ ]-[]
  foldᵣ g (length init) (x ⊰ l)   🝖-end

length-concatMap : ∀{f} → (length{T = T}(concatMap f l) ≡ foldᵣ((_+_) ∘ length ∘ f) 𝟎 l)
length-concatMap {l = l} {f} = length-foldᵣ{l = l}{init = ∅}{f = (_++_) ∘ f} \{x l} → length-[++] {l₁ = f(x)}{l₂ = l}

length-accumulateIterate₀ : ∀{n}{f}{init : T} → (length(accumulateIterate₀ n f init) ≡ n)
length-accumulateIterate₀ {n = 𝟎}      = [≡]-intro
length-accumulateIterate₀ {n = 𝐒 n}{f} = [≡]-with(𝐒) (length-accumulateIterate₀ {n = n}{f})

length-[++^] : (length(l ++^ n) ≡ length(l) ⋅ n)
length-[++^] {l = l}{𝟎}    = [≡]-intro
length-[++^] {l = l}{𝐒(n)} =
  length-[++] {l₁ = l}{l ++^ n}
  🝖 [≡]-with(expr ↦ length(l) + expr) (length-[++^] {l = l}{n})

length-isEmpty : (length(l) ≡ 0) ↔ (isEmpty(l) ≡ 𝑇)
length-isEmpty {l = ∅}     = [↔]-intro (const [≡]-intro) (const [≡]-intro)
length-isEmpty {l = x ⊰ L} = [↔]-intro (\()) (\())

instance
  length-preserves-insert : Preserving₁(length)(insert n x)(𝐒)
  Preserving.proof (length-preserves-insert {n = n}) = proof{n = n} where
    proof : ∀{n} → (length(insert n x l) ≡ 𝐒(length l))
    proof         {l = _}     {n = 𝟎}   = [≡]-intro
    proof         {l = ∅}     {n = 𝐒 n} = [≡]-intro
    proof {x = x} {l = y ⊰ l} {n = 𝐒 n} rewrite proof {x = x} {l = l} {n = n} = [≡]-intro

length-insertIn : ∀{n} → (length(insertIn x l n) ≡ 𝐒(length l))
length-insertIn         {l = _}     {n = 𝟎}   = [≡]-intro
length-insertIn         {l = ∅}     {n = 𝐒 n} = [≡]-intro
length-insertIn {x = x} {l = y ⊰ l} {n = 𝐒 n} rewrite length-insertIn {x = x} {l = l} {n = n} = [≡]-intro


open import Type

module Graph.Walk.Functions {ℓ₁ ℓ₂} {V : Type{ℓ₁}} where

import      Lvl
open import Graph{ℓ₁}{ℓ₂}(V)
open import Graph.Properties
open import Graph.Walk{ℓ₁}{ℓ₂}{V}
open import Numeral.Natural
open import Syntax.Function
open import Type.Dependent
open import Type.Dependent.Functions

module _ {_⟶_ : Graph} where
  edge : ∀{a b} → (a ⟶ b) → (Walk(_⟶_) a b)
  edge e = prepend e at

  join : ∀{a b c} → (a ⟶ b) → (b ⟶ c) → (Walk(_⟶_) a c)
  join e₁ e₂ = prepend e₁ (edge e₂)

  _++_ : ∀{a b c} → Walk(_⟶_) a b → Walk(_⟶_) b c → Walk(_⟶_) a c
  at            ++ w₂ = w₂
  prepend e₁ w₁ ++ w₂ = prepend e₁ (w₁ ++ w₂)

  postpend : ∀{a b c} → (Walk(_⟶_) a b) → (b ⟶ c) → (Walk(_⟶_) a c)
  postpend at             e₂ = edge e₂
  postpend (prepend e₁ w) e₂ = prepend e₁ (postpend w e₂)

  reverse : ⦃ Undirected(_⟶_) ⦄ → ∀{a b} → Walk(_⟶_) a b → Walk(_⟶_) b a
  reverse at            = at
  reverse (prepend e w) = postpend (reverse w) (undirected-reverse(_⟶_) e)

  prelop : ∀{a c} → (Walk(_⟶_) a c) → Σ(_)(b ↦ Walk(_⟶_) b c)
  prelop at            = intro _ at
  prelop (prepend e w) = intro _ w

  postlop : ∀{a c} → (Walk(_⟶_) a c) → Σ(_)(b ↦ Walk(_⟶_) a b)
  postlop at                          = intro _ at
  postlop (prepend e  at)             = intro _ at
  postlop (prepend e₁ (prepend e₂ w)) = [Σ]-applyᵣ (postlop(prepend e₂ w)) (prepend e₁)

  length : ∀{a b} → (Walk(_⟶_) a b) → ℕ
  length at            = 𝟎
  length (prepend _ w) = 𝐒(length w)


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.DStructures.Structures.Action where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Structure
open import Cubical.Functions.FunExtEquiv

open import Cubical.Data.Sigma

open import Cubical.Algebra.Group
open import Cubical.Structures.LeftAction

open import Cubical.DStructures.Base
open import Cubical.DStructures.Meta.Properties

open import Cubical.DStructures.Structures.Constant
open import Cubical.DStructures.Structures.Type
open import Cubical.DStructures.Structures.Group

private
  module _ {ℓ ℓ' : Level} where
    Las : ((G , H) : Group {ℓ} × Group {ℓ'}) → Type (ℓ-max ℓ ℓ')
    Las (G , H) = LeftActionStructure ⟨ G ⟩ ⟨ H ⟩

module _ (ℓ ℓ' : Level) where
  G²Las = Σ[ GH ∈ G² ℓ ℓ' ] Las GH
  GGLas = Σ[ G ∈ Group {ℓ} ] Σ[ H ∈ Group {ℓ'} ] Las (G , H)
  Action = Σ[ ((G , H) , _α_) ∈ G²Las ] (IsGroupAction G H _α_)
  G²LasAct = Σ[ (G , H) ∈ G² ℓ ℓ' ] Σ[ α ∈ Las (G , H) ] IsGroupAction G H α
  GGLasAct = Σ[ G ∈ Group {ℓ} ] Σ[ H ∈ Group {ℓ'} ] Σ[ α ∈ Las (G , H) ] IsGroupAction G H α

  IsoAction : Iso Action GGLasAct
  IsoAction = compIso Σ-assoc-Iso Σ-assoc-Iso

  -- two groups with an action structure, i.e. a map ⟨ G ⟩ → ⟨ H ⟩ → ⟨ H ⟩
  𝒮ᴰ-G²\Las : URGStrᴰ (𝒮-group ℓ ×𝒮 𝒮-group ℓ')
                      (λ GH → Las GH)
                      (ℓ-max ℓ ℓ')
  𝒮ᴰ-G²\Las =
    make-𝒮ᴰ (λ {(G , H)} _α_ (eG , eH) _β_
                   → (g : ⟨ G ⟩) (h : ⟨ H ⟩)
                     → GroupEquiv.eq eH .fst (g α h) ≡ (GroupEquiv.eq eG .fst g) β (GroupEquiv.eq eH .fst h))
                (λ _ _ _ → refl)
                λ (G , H) _α_ → isContrRespectEquiv
                                                       -- (Σ[ _β_ ∈ Las (G , H) ] (_α_ ≡ _β_)
                                                       (Σ-cong-equiv-snd (λ _β_ → invEquiv funExt₂Equiv))
                                                       (isContrSingl _α_)

  𝒮-G²Las : URGStr G²Las (ℓ-max ℓ ℓ')
  𝒮-G²Las = ∫⟨ 𝒮-group ℓ ×𝒮 𝒮-group ℓ' ⟩ 𝒮ᴰ-G²\Las

  open ActionΣTheory

  𝒮ᴰ-G²Las\Action : URGStrᴰ 𝒮-G²Las
                     (λ ((G , H) , _α_) → IsGroupAction G H _α_)
                     ℓ-zero
  𝒮ᴰ-G²Las\Action = Subtype→Sub-𝒮ᴰ (λ ((G , H) , _α_) → IsGroupAction G H _α_ , isPropIsGroupAction G H _α_)
                             𝒮-G²Las

  𝒮-G²LasAction : URGStr Action (ℓ-max ℓ ℓ')
  𝒮-G²LasAction = ∫⟨ 𝒮-G²Las ⟩ 𝒮ᴰ-G²Las\Action

  𝒮-Action = 𝒮-G²LasAction

  𝒮ᴰ-G\GLasAction : URGStrᴰ (𝒮-group ℓ)
                            (λ G → Σ[ H ∈ Group {ℓ'} ] Σ[ α ∈ Las (G , H) ] IsGroupAction G H α)
                            (ℓ-max ℓ ℓ')
  𝒮ᴰ-G\GLasAction =
    splitTotal-𝒮ᴰ (𝒮-group ℓ)
                  (𝒮ᴰ-const (𝒮-group ℓ) (𝒮-group ℓ'))
                  (splitTotal-𝒮ᴰ (𝒮-group ℓ ×𝒮 𝒮-group ℓ')
                                 𝒮ᴰ-G²\Las
                                 𝒮ᴰ-G²Las\Action)


-- Record declarations can now contain arbitrary declarations.
-- These are included in the projection module.
module FancyRecordModule where

data Nat : Set where
  zero : Nat
  suc  : Nat -> Nat

record Exist {A : Set}(P : A -> Set) : Set where
  field witness : A
  x = witness
  field proof   : P x
  silly : Nat -> Nat
  silly zero = zero
  silly (suc n) = silly n

postulate
  P : Nat -> Set
  e : Exist P

data _==_ {A : Set}(x : A) : A -> Set where
  refl : x == x

test : Exist.silly e (suc zero) == zero
test = refl


-- Andreas, 2012-01-10
-- {-# OPTIONS -v tc.constr.findInScope:50 #-}
module InstanceGuessesMeta2 where

open import Common.Level

data ℕ : Set where
  zero : ℕ
  suc  : (n : ℕ) → ℕ

record takeClass {a}
  (F : Set a → Set a)
  (G : Set a → ℕ → Set a) : Set (lsuc a) where
  field
    take : {A : Set a} → (n : ℕ) → F A → G A n

take : ∀ {a} {A : Set a} {F : Set a → Set a} {G : Set a → ℕ → Set a}
   {{takeA : takeClass F G}} →
   (n : ℕ) → F A → G A n
take {{takeA}} = takeClass.take takeA

postulate
  List : ∀ {a} → Set a → Set a
  BVec : ∀ {a} → Set a → ℕ → Set a
  toList : ∀ {a}{A : Set a}{n : ℕ} → BVec A n → List A
  -- universe polymorphic instance
  takeInstanceList : {a : Level} → takeClass (List {a = a}) BVec

take0 : {A : Set} → List A → BVec A zero
take0 l = take zero l

take1 : {A : Set} → List A → List A
take1 l = toList (take (suc zero) l)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Notation for freely adding extrema to any set
------------------------------------------------------------------------

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

module Relation.Nullary.Construct.Add.Extrema where

open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Relation.Nullary.Construct.Add.Infimum  as Infimum  using (_₋)
open import Relation.Nullary.Construct.Add.Supremum as Supremum using (_⁺)

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

_± : ∀ {a} → Set a → Set a
A ± = A ₋ ⁺

pattern ⊥±    = Supremum.[ Infimum.⊥₋ ]
pattern [_] k = Supremum.[ Infimum.[ k ] ]
pattern ⊤±    = Supremum.⊤⁺

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

[_]-injective : ∀ {a} {A : Set a} {k l : A} → [ k ] ≡ [ l ] → k ≡ l
[_]-injective refl = refl


module Structure.Category.NaturalTransformation.Equiv where

import      Function.Equals
open        Function.Equals.Dependent
import      Lvl
open import Logic
open import Logic.Predicate
open import Structure.Category
open import Structure.Category.Functor
open import Structure.Category.NaturalTransformation
open import Structure.Setoid
open import Structure.Relator.Equivalence
open import Structure.Relator.Properties
open import Type

module _
  {ℓₗₒ ℓₗₘ ℓₗₑ ℓᵣₒ ℓᵣₘ ℓᵣₑ}
  {catₗ : CategoryObject{ℓₗₒ}{ℓₗₘ}{ℓₗₑ}}
  {catᵣ : CategoryObject{ℓᵣₒ}{ℓᵣₘ}{ℓᵣₑ}}
  {F₁ : catₗ →ᶠᵘⁿᶜᵗᵒʳ catᵣ}
  {F₂ : catₗ →ᶠᵘⁿᶜᵗᵒʳ catᵣ}
  where

  _≡ᴺᵀ_ : (F₁ →ᴺᵀ F₂) → (F₁ →ᴺᵀ F₂) → Stmt
  [∃]-intro N₁ ≡ᴺᵀ [∃]-intro N₂ = N₁ ⊜ N₂

  instance
    [≡ᴺᵀ]-reflexivity : Reflexivity(_≡ᴺᵀ_)
    Reflexivity.proof [≡ᴺᵀ]-reflexivity = reflexivity(_⊜_)

  instance
    [≡ᴺᵀ]-symmetry : Symmetry(_≡ᴺᵀ_)
    Symmetry.proof [≡ᴺᵀ]-symmetry = symmetry(_⊜_)

  instance
    [≡ᴺᵀ]-transitivity : Transitivity(_≡ᴺᵀ_)
    Transitivity.proof [≡ᴺᵀ]-transitivity = transitivity(_⊜_)

  instance
    [≡ᴺᵀ]-equivalence : Equivalence(_≡ᴺᵀ_)
    [≡ᴺᵀ]-equivalence = intro

  instance
    [→ᴺᵀ]-equiv : Equiv(F₁ →ᴺᵀ F₂)
    [→ᴺᵀ]-equiv = intro(_≡ᴺᵀ_) ⦃ [≡ᴺᵀ]-equivalence ⦄


open import Common.Prelude

infixr 9 _∘_

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

test : Nat → Nat
test = _* 5 ∘ 6 +_ ∘ 2 ∸_


open import SOAS.Common
open import SOAS.Families.Core
import SOAS.Metatheory.MetaAlgebra

-- Shorthands for de Bruijn indices
module SOAS.Syntax.Shorthands {T : Set}
  {⅀F : Functor 𝔽amiliesₛ 𝔽amiliesₛ}
  (open SOAS.Metatheory.MetaAlgebra ⅀F)
  {𝒜 : Familyₛ → Familyₛ}(𝒜ᵃ : (𝔛 : Familyₛ) → MetaAlg 𝔛 (𝒜 𝔛))
  where

open import SOAS.Context
open import SOAS.Families.Build
open import SOAS.ContextMaps.Inductive
open import SOAS.Variable
open import Data.Nat

open import Relation.Nullary.Decidable using (True; toWitness)

private
  variable
    α β γ δ υ : T
    Γ Δ : Ctx

module _ {𝔛 : Familyₛ} where
  open MetaAlg 𝔛 (𝒜ᵃ 𝔛)

  -- Refer to variables via de Bruijn numerals: e.g. ` 2 = 𝑣𝑎𝑟 (old (old new))
  len : Ctx {T} → ℕ
  len ∅        =  ℕ.zero
  len (α ∙ Γ)  =  suc (len Γ)

  ix : {Γ : Ctx} → {n : ℕ} → (p : n < len Γ) → T
  ix {(α ∙ _)} {zero}    (s≤s z≤n)  =  α
  ix {(_ ∙ Γ)} {(suc n)} (s≤s p)    =  ix p

  deBruijn : ∀ {Γ} → {n : ℕ} → (p : n < len Γ) → ℐ (ix p) Γ
  deBruijn {_ ∙ _} {zero}    (s≤s z≤n)  =  new
  deBruijn {_ ∙ Γ} {(suc n)} (s≤s p)    =  old (deBruijn p)

  ′ : {Γ : Ctx}(n : ℕ){n∈Γ : True (suc n ≤? len Γ)} → 𝒜 𝔛 (ix (toWitness n∈Γ)) Γ
  ′ n {n∈Γ} = 𝑣𝑎𝑟 (deBruijn (toWitness n∈Γ))

  -- Explicit abbreviations for de Bruijn indices 0-4
  x₀ : 𝒜 𝔛 α (α ∙ Γ)
  x₀ = 𝑣𝑎𝑟 new
  x₁ : 𝒜 𝔛 β (α ∙ β ∙ Γ)
  x₁ = 𝑣𝑎𝑟 (old new)
  x₂ : 𝒜 𝔛 γ (α ∙ β ∙ γ ∙ Γ)
  x₂ = 𝑣𝑎𝑟 (old (old new))
  x₃ : 𝒜 𝔛 δ (α ∙ β ∙ γ ∙ δ ∙ Γ)
  x₃ = 𝑣𝑎𝑟 (old (old (old new)))
  x₄ : 𝒜 𝔛 υ (α ∙ β ∙ γ ∙ δ ∙ υ ∙ Γ)
  x₄ = 𝑣𝑎𝑟 (old (old (old (old new))))


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

module Relation.Nullary.Decidable.Properties where

open import Relation.Nullary.Decidable
open import Level
open import Relation.Nullary.Stable
open import Data.Empty
open import HLevels
open import Data.Empty.Properties using (isProp¬)
open import Data.Unit
open import Data.Empty

Dec→Stable : ∀ {ℓ} (A : Type ℓ) → Dec A → Stable A
Dec→Stable A (yes x) = λ _ → x
Dec→Stable A (no x) = λ f → ⊥-elim (f x)

isPropDec : (Aprop : isProp A) → isProp (Dec A)
isPropDec Aprop (yes a) (yes a') i = yes (Aprop a a' i)
isPropDec Aprop (yes a) (no ¬a) = ⊥-elim (¬a a)
isPropDec Aprop (no ¬a) (yes a) = ⊥-elim (¬a a)
isPropDec {A = A} Aprop (no ¬a) (no ¬a') i = no (isProp¬ A ¬a ¬a' i)

True : Dec A → Type
True (yes _) = ⊤
True (no  _) = ⊥

toWitness : {x : Dec A} → True x → A
toWitness {x = yes p} _ = p

open import Path
open import Data.Bool.Base

from-reflects : ∀ b → (d : Dec A) → Reflects A b → does d ≡ b
from-reflects false (no  y) r = refl
from-reflects false (yes y) r = ⊥-elim (r y)
from-reflects true  (no  y) r = ⊥-elim (y r)
from-reflects true  (yes y) r = refl


module Relator.Congruence.Proofs where

import      Lvl
open import Functional
open import Logic.Propositional
open import Logic.Predicate
-- TODO: open import Structure.Function.Domain
open import Structure.Relator.Equivalence
open import Structure.Relator.Properties
open import Relator.Congruence
open import Relator.Equals
open import Relator.Equals.Proofs
open import Structure.Function.Names
open import Syntax.Transitivity
open import Type

module _ {ℓ₁ ℓ₂} {X : Type{ℓ₁}}{Y : Type{ℓ₂}} {f : X → Y} where
  instance
    [≅]-reflexivity : Reflexivity (_≅_of f)
    Reflexivity.proof([≅]-reflexivity) = [≅]-intro [≡]-intro

  instance
    [≅]-symmetry : Symmetry (_≅_of f)
    Symmetry.proof([≅]-symmetry) = ([≅]-intro ∘ symmetry(_≡_) ∘ [≅]-elim)

  instance
    [≅]-transitivity : Transitivity (_≅_of f)
    Transitivity.proof([≅]-transitivity) (eq1) (eq2) = [≅]-intro(([≅]-elim eq1) 🝖 ([≅]-elim eq2))

  instance
    [≅]-equivalence : Equivalence (_≅_of f)
    [≅]-equivalence = record {
        reflexivity  = [≅]-reflexivity ;
        symmetry     = [≅]-symmetry    ;
        transitivity = [≅]-transitivity
      }

  [≅]-to-[≡] : Injective(f) ↔ (∀{x₁ x₂ : X} → (x₁ ≅ x₂ of f) → (x₁ ≡ x₂))
  [≅]-to-[≡] = [↔]-intro (_∘ [≅]-intro) (_∘ [≅]-elim)

module _ {ℓ₁ ℓ₂ ℓ₃} {X₁ : Type{ℓ₁}}{X₂ : Type{ℓ₂}}{Y : Type{ℓ₃}} where
  [≅]-composition : ∀{x₁ x₂ : X₁}{g : X₁ → X₂} → (x₁ ≅ x₂ of g) → ∀{f : X₂ → Y} → (g(x₁) ≅ g(x₂) of f)
  [≅]-composition ([≅]-intro (fx₁≡fx₂)) {f} = [≅]-intro ([≡]-with(f) (fx₁≡fx₂))
    -- x₁ ≅ x₂
    -- ⇔ g(x₁) = g(x₂)
    -- ⇒ f(g(x₁)) = f(g(x₂))


------------------------------------------------------------------------
-- INCREMENTAL λ-CALCULUS
--
-- Terms that operate on changes (Fig. 3).
------------------------------------------------------------------------

import Parametric.Syntax.Type as Type
import Parametric.Syntax.Term as Term
import Parametric.Change.Type as ChangeType

module Parametric.Change.Term
    {Base : Set}
    (Const : Term.Structure Base)
    (ΔBase : ChangeType.Structure Base)
  where

-- Terms that operate on changes

open Type.Structure Base
open Term.Structure Base Const
open ChangeType.Structure Base ΔBase

open import Data.Product

-- Extension point 1: A term for ⊝ on base types.
DiffStructure : Set
DiffStructure = ∀ {ι Γ} → Term Γ (base ι ⇒ base ι ⇒ ΔBase ι)

-- Extension point 2: A term for ⊕ on base types.
ApplyStructure : Set
ApplyStructure = ∀ {ι Γ} → Term Γ (ΔType (base ι) ⇒ base ι ⇒ base ι)

-- Extension point 3: A term for 0 on base types.
NilStructure : Set
NilStructure = ∀ {ι Γ} → Term Γ (base ι ⇒ ΔBase ι)

module Structure
    (apply-base : ApplyStructure)
    (diff-base  : DiffStructure)
    (nil-base   : NilStructure)
  where

  -- g ⊝ f  = λ x . λ Δx . g (x ⊕ Δx) ⊝ f x
  -- f ⊕ Δf = λ x . f x ⊕ Δf x (x ⊝ x)

  -- We provide: terms for ⊕ and ⊝ on arbitrary types.
  apply-term : ∀ {τ Γ} → Term Γ (ΔType τ ⇒ τ ⇒ τ)
  diff-term : ∀ {τ Γ} → Term Γ (τ ⇒ τ ⇒ ΔType τ)
  nil-term : ∀ {τ Γ} → Term Γ (τ ⇒ ΔType τ)

  apply-term {base ι} = apply-base
  apply-term {σ ⇒ τ} =
    let
       _⊕τ_ = λ {Γ} t Δt → app₂ (apply-term {τ} {Γ}) Δt t
       nil-σ = λ {Γ} t → app (nil-term {σ} {Γ}) t
     in
       absV 3 (λ Δh h y → app h y ⊕τ app (app Δh y) (nil-σ y))

  diff-term {base ι} = diff-base
  diff-term {σ ⇒ τ} =
    let
       _⊝τ_ = λ {Γ} s t  → app₂ (diff-term {τ} {Γ}) s t
       _⊕σ_ = λ {Γ} t Δt → app₂ (apply-term {σ} {Γ}) Δt t
     in
       absV 4 (λ g f x Δx → app g (x ⊕σ Δx) ⊝τ app f x)

  nil-term {base ι} = nil-base
  nil-term {σ ⇒ τ} =
    -- What I'd usually write:
    --absV 1 (λ f → app₂ diff-term f f)
    -- What I wrote in fact:
    let
       _⊝τ_ = λ {Γ} s t  → app₂ (diff-term {τ} {Γ}) s t
       _⊕σ_ = λ {Γ} t Δt → app₂ (apply-term {σ} {Γ}) Δt t
     in
       absV 1 (λ ff → app (absV 3 (λ f x Δx → app f (x ⊕σ Δx) ⊝τ app f x)) ff)
    -- This simplified a lot proving meaning-onil by reusing meaning-⊝.
    --
    -- The reason is that the extra lambda-abstraction ensures that f is pushed
    -- twice in the environment.

  apply : ∀ τ {Γ} →
    Term Γ (ΔType τ) → Term Γ τ →
    Term Γ τ
  apply _ = app₂ apply-term

  diff : ∀ τ {Γ} →
    Term Γ τ → Term Γ τ →
    Term Γ (ΔType τ)
  diff _ = app₂ diff-term

  onil₍_₎ : ∀ τ {Γ} →
    Term Γ τ →
    Term Γ (ΔType τ)
  onil₍ _ ₎ = app nil-term

  infixl 6 apply diff

  syntax apply τ x Δx = Δx ⊕₍ τ ₎ x
  syntax diff τ x y = x ⊝₍ τ ₎ y

  infixl 6 _⊕_ _⊝_

  _⊕_ : ∀ {τ Γ} →
    Term Γ (ΔType τ) → Term Γ τ →
    Term Γ τ
  _⊕_ {τ} = apply τ

  _⊝_ : ∀ {τ Γ} →
    Term Γ τ → Term Γ τ →
    Term Γ (ΔType τ)
  _⊝_ {τ} = diff τ

  onil : ∀ {τ Γ} →
    Term Γ τ →
    Term Γ (ΔType τ)
  onil {τ} = onil₍ τ ₎


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

module FOT.PA.Inductive.CanonicalTerm where

-- We cannot extract a canonical term from a non-intuitionistic proof.

open import PA.Inductive.Base
open import PA.Inductive.PropertiesI

------------------------------------------------------------------------------
-- The existential projections

∃-proj₁ : ∀ {A} → ∃ A → ℕ
∃-proj₁ (x , _) = x

∃-proj₂ : ∀ {A} → (h : ∃ A) → A (∃-proj₁ h)
∃-proj₂ (_ , Ax) = Ax

------------------------------------------------------------------------------
-- Non-intuitionistic logic theorems

-- The principle of the excluded middle.
postulate pem : ∀ {A} → A ∨ ¬ A

-- The principle of indirect proof (proof by contradiction).
¬-elim : ∀ {A} → (¬ A → ⊥) → A
¬-elim h = case (λ a → a) (λ ¬a → ⊥-elim (h ¬a)) pem

-- ∃ in terms of ∀ and ¬.
¬∃¬→∀ : {A : ℕ → Set} → ¬ (∃[ x ] ¬ A x) → ∀ {x} → A x
¬∃¬→∀ h {x} = ¬-elim (λ h₁ → h (x , h₁))

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

-- Intuitionistic proof.
proof₁ : ∃[ x ] x ≢ succ x
proof₁ = succ zero , x≢Sx

-- Non-intuitionistic proof.
proof₂ : ∃[ x ] x ≢ succ x
proof₂ = ¬-elim (λ h → x≢Sx {succ zero} (¬∃¬→∀ h))

-- We can extract a canonical term from an intuitionistic proof.
canonicalTerm₁ : ∃-proj₁ proof₁ ≡ succ zero
canonicalTerm₁ = refl

-- We cannot extract a canonical term from a non-intuitionistic proof.
-- canonicalTerm₂ : ∃-proj₁ proof₂ ≡ succ zero
-- canonicalTerm₂ = {!refl!}

-- Agda error:
--
-- ∃-proj₁ ([ (λ a → a) , (λ ¬a → ⊥-elim (x≢Sx (¬∃¬→∀ ¬a))) ] pem) !=
-- succ zero of type M
-- when checking that the expression refl has type
-- ∃-proj₁ proof₂ ≡ succ zero


module Dave.Equality where
  data _≡_ {A : Set} (x : A) : A → Set where
    refl : x ≡ x

  infix 4 _≡_

  {-# BUILTIN EQUALITY _≡_ #-}

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

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

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

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

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

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

  infix  1 begin_
  infixr 2 _≡⟨⟩_ _≡⟨_⟩_
  infix  3 _∎

  begin_ : ∀ {A : Set} {x y : A}
    → x ≡ y
      -----
    → x ≡ y
  begin x≡y  =  x≡y

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

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

  _∎ : ∀ {A : Set} (x : A)
     -----
     → x ≡ x
  x ∎  =  refl


------------------------------------------------------------------------
-- A coinductive definition of (strong) similarity
------------------------------------------------------------------------

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

open import Labelled-transition-system

module Similarity {ℓ} (lts : LTS ℓ) where

open import Equality.Propositional
open import Prelude
open import Prelude.Size

open import Bisimilarity lts as SB using ([_]_∼_; [_]_∼′_)
open import Indexed-container hiding (⟨_⟩)
open import Relation
import Similarity.General

open LTS lts

private
  module General = Similarity.General lts _[_]⟶_ id

open General public
  using (module StepC; ⟨_⟩; challenge; force;
         reflexive-≤; reflexive-≤′; ≡⇒≤; ≤:_; ≤′:_;
         [_]_≡_; [_]_≡′_; []≡↔; Extensionality; extensionality)

-- StepC is given in the following way, rather than via open public,
-- to make hyperlinks to it more informative.

StepC : Container (Proc × Proc) (Proc × Proc)
StepC = General.StepC

-- The following definitions are given explicitly, in order to make
-- the code easier to follow.

Similarity : Size → Rel₂ ℓ Proc
Similarity = ν StepC

Similarity′ : Size → Rel₂ ℓ Proc
Similarity′ = ν′ StepC

infix 4 [_]_≤_ [_]_≤′_ _≤_ _≤′_

[_]_≤_ : Size → Proc → Proc → Type ℓ
[ i ] p ≤ q = ν StepC i (p , q)

[_]_≤′_ : Size → Proc → Proc → Type ℓ
[ i ] p ≤′ q = ν′ StepC i (p , q)

_≤_ : Proc → Proc → Type ℓ
_≤_ = [ ∞ ]_≤_

_≤′_ : Proc → Proc → Type ℓ
_≤′_ = [ ∞ ]_≤′_

private

  -- However, these definitions are definitionally equivalent to
  -- corresponding definitions in General.

  indirect-Similarity : Similarity ≡ General.Similarity
  indirect-Similarity = refl

  indirect-Similarity′ : Similarity′ ≡ General.Similarity′
  indirect-Similarity′ = refl

  indirect-[]≤ : [_]_≤_ ≡ General.[_]_≤_
  indirect-[]≤ = refl

  indirect-[]≤′ : [_]_≤′_ ≡ General.[_]_≤′_
  indirect-[]≤′ = refl

  indirect-≤ : _≤_ ≡ General._≤_
  indirect-≤ = refl

  indirect-≤′ : _≤′_ ≡ General._≤′_
  indirect-≤′ = refl

mutual

  -- Bisimilarity is contained in similarity.

  ∼⇒≤ : ∀ {i p q} → [ i ] p ∼ q → [ i ] p ≤ q
  ∼⇒≤ = λ p∼q →
    ⟨ (λ q⟶q′ →
         let p′ , p⟶p′ , p′∼′q′ = SB.left-to-right p∼q q⟶q′
         in p′ , p⟶p′ , ∼⇒≤′ p′∼′q′)
    ⟩

  ∼⇒≤′ : ∀ {i p q} → [ i ] p ∼′ q → [ i ] p ≤′ q
  force (∼⇒≤′ p≳′q) = ∼⇒≤ (SB.force p≳′q)

mutual

  -- Similarity is transitive.

  transitive-≤ : ∀ {i p q r} → [ i ] p ≤ q → [ i ] q ≤ r → [ i ] p ≤ r
  transitive-≤ p≤q q≤r =
    ⟨ (λ p⟶p′ →
         let q′ , q⟶q′ , p′≤q′ = challenge p≤q p⟶p′
             r′ , r⟶r′ , q′≤r′ = challenge q≤r q⟶q′
         in r′ , r⟶r′ , transitive-≤′ p′≤q′ q′≤r′)
    ⟩

  transitive-≤′ :
    ∀ {i p q r} → [ i ] p ≤′ q → [ i ] q ≤′ r → [ i ] p ≤′ r
  force (transitive-≤′ p≤q q≤r) = transitive-≤ (force p≤q) (force q≤r)


{-# OPTIONS --without-K --safe #-}
module Cats.Category.Constructions.Exponential where

open import Level

open import Cats.Category.Base
open import Cats.Category.Constructions.Product as Product using
  (HasBinaryProducts)
open import Cats.Util.Conv

import Cats.Category.Constructions.Iso as Iso
import Cats.Category.Constructions.Unique as Unique

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

  open Category Cat
  open ≈-Reasoning
  open Unique.Build Cat
  open Iso.Build Cat
  open HasBinaryProducts hasBinaryProducts
  open _≅_

  record Exp (B C : Obj) : Set (lo ⊔ la ⊔ l≈) where
    field
      Cᴮ : Obj
      eval : Cᴮ × B ⇒ C
      curry′ : ∀ {A} (f : A × B ⇒ C)
        → ∃![ f̃ ∈ A ⇒ Cᴮ ] (eval ∘ ⟨ f̃ × id ⟩ ≈ f)

    curry : ∀ {A} → A × B ⇒ C → A ⇒ Cᴮ
    curry f = curry′ f ⃗

    eval-curry : ∀ {A} {f : A × B ⇒ C}
      → eval ∘ ⟨ curry f × id ⟩ ≈ f
    eval-curry {f = f} = ∃!′.prop (curry′ f)

    curry-unique : ∀ {A} {f : A × B ⇒ C} {g}
      → eval ∘ ⟨ g × id ⟩ ≈ f
      → curry f ≈ g
    curry-unique {f = f} = ∃!′.unique (curry′ f)

    uncurry : ∀ {A} → A ⇒ Cᴮ → A × B ⇒ C
    uncurry f = eval ∘ ⟨ f × id ⟩

    curry∘uncurry : ∀ {A} {f : A ⇒ Cᴮ}
      → curry (uncurry f) ≈ f
    curry∘uncurry = curry-unique ≈.refl

    uncurry∘curry : ∀ {A} {f : A × B ⇒ C}
      → uncurry (curry f) ≈ f
    uncurry∘curry = eval-curry

  instance HasObj-Exp : ∀ {B C} → HasObj (Exp B C) lo la l≈
  HasObj-Exp = record { Cat = Cat ; _ᴼ = Exp.Cᴮ }

  open Exp public

  curry∘curry : ∀ {A B C Y Z} (Cᴮ : Exp B C) (Yᶻ : Exp Y Z)
    → {f : Cᴮ ᴼ × Y ⇒ Z} {g : A × B ⇒ C}
    → curry Yᶻ f ∘ curry Cᴮ g ≈ curry Yᶻ (f ∘ ⟨ curry Cᴮ g × id ⟩)
  curry∘curry Cᴮ Yᶻ {f} {g} = ≈.sym (curry-unique Yᶻ (
      begin
        eval Yᶻ ∘ ⟨ curry Yᶻ f ∘ curry Cᴮ g × id ⟩
      ≈⟨ ∘-resp-r (⟨×⟩-resp ≈.refl (≈.sym id-l)) ⟩
        eval Yᶻ ∘ ⟨ curry Yᶻ f ∘ curry Cᴮ g × id ∘ id ⟩
      ≈⟨ ∘-resp-r (≈.sym ⟨×⟩-∘) ⟩
        eval Yᶻ ∘ ⟨ curry Yᶻ f × id ⟩ ∘ ⟨ curry Cᴮ g × id ⟩
      ≈⟨ unassoc ⟩
        (eval Yᶻ ∘ ⟨ curry Yᶻ f × id ⟩) ∘ ⟨ curry Cᴮ g × id ⟩
      ≈⟨ ∘-resp-l (eval-curry Yᶻ) ⟩
        f ∘ ⟨ curry Cᴮ g × id ⟩
      ∎
    ))

  Exp-resp-≅ : ∀ {A A′ B B′}
    → A ≅ A′
    → B ≅ B′
    → (E : Exp A B) (E′ : Exp A′ B′)
    → E ᴼ ≅ E′ ᴼ
  Exp-resp-≅ A≅A′ B≅B′ E E′ = record
    { forth = curry E′ (B≅B′ .forth ∘ eval E ∘ ⟨ id × A≅A′ .back ⟩)
    ; back = curry E (B≅B′ .back ∘ eval E′ ∘ ⟨ id × A≅A′ .forth ⟩)
    -- Today in our series on 'trivial' properties (also copy-and-paste
    -- programming).
    ; back-forth = ≈.trans (curry∘curry E′ E)
        (curry-unique E (≈.trans (∘-resp-r ⟨×⟩-id) (≈.trans id-r
        (≈.sym (≈.trans assoc (≈.trans (∘-resp-r (≈.trans assoc (≈.trans
        (∘-resp-r (≈.trans ⟨×⟩-∘
        (≈.trans (⟨×⟩-resp (≈.trans id-l (≈.sym id-r)) (≈.trans id-r (≈.sym id-l)))
        (≈.sym ⟨×⟩-∘)))) (≈.trans unassoc (∘-resp-l (eval-curry E′))))))
        (≈.trans unassoc (≈.trans (∘-resp-l (≈.trans unassoc
        (≈.trans (∘-resp-l (B≅B′ .back-forth)) id-l)))
        (≈.trans assoc (≈.trans (∘-resp-r (≈.trans ⟨×⟩-∘
        (≈.trans (⟨×⟩-resp id-l (A≅A′ .back-forth)) ⟨×⟩-id))) id-r))))))))))
    ; forth-back = ≈.trans (curry∘curry E E′)
        (curry-unique E′ (≈.trans (∘-resp-r ⟨×⟩-id) (≈.trans id-r
        (≈.sym (≈.trans assoc (≈.trans (∘-resp-r (≈.trans assoc (≈.trans
        (∘-resp-r (≈.trans ⟨×⟩-∘
        (≈.trans (⟨×⟩-resp (≈.trans id-l (≈.sym id-r)) (≈.trans id-r (≈.sym id-l)))
        (≈.sym ⟨×⟩-∘)))) (≈.trans unassoc (∘-resp-l (eval-curry E))))))
        (≈.trans unassoc (≈.trans (∘-resp-l (≈.trans unassoc
        (≈.trans (∘-resp-l (B≅B′ .forth-back)) id-l)))
        (≈.trans assoc (≈.trans (∘-resp-r (≈.trans ⟨×⟩-∘
        (≈.trans (⟨×⟩-resp id-l (A≅A′ .forth-back)) ⟨×⟩-id))) id-r))))))))))
    }

record HasExponentials {lo la l≈}
  (Cat : Category lo la l≈)
  : Set (lo ⊔ la ⊔ l≈)
  where
  private open module Bld = Build Cat using (Exp)
  open Category Cat
  open Unique.Build Cat
  open Iso.Build Cat

  infixr 1 _↝′_ _↝_

  field
    {{hasBinaryProducts}} : HasBinaryProducts Cat
    _↝′_ : ∀ B C → Exp B C

  open HasBinaryProducts hasBinaryProducts

  _↝_ : Obj → Obj → Obj
  B ↝ C = (B ↝′ C) ᴼ

  eval : ∀ {B C} → (B ↝ C) × B ⇒ C
  eval {B} {C} = Bld.eval (B ↝′ C)

  curry : ∀ {A B C} → A × B ⇒ C → A ⇒ B ↝ C
  curry {B = B} {C} f = Bld.curry (B ↝′ C) f

  uncurry : ∀ {A B C} → A ⇒ B ↝ C → A × B ⇒ C
  uncurry {B = B} {C} = Bld.uncurry (B ↝′ C)

  eval-curry : ∀ {A B C} {f : A × B ⇒ C}
    → eval ∘ ⟨ curry f × id ⟩ ≈ f
  eval-curry {B = B} {C} = Bld.eval-curry (B ↝′ C)

  curry-unique : ∀ {A B C} {f : A × B ⇒ C} {g}
    → eval ∘ ⟨ g × id ⟩ ≈ f
    → curry f ≈ g
  curry-unique {B = B} {C} = Bld.curry-unique (B ↝′ C)

  curry∘uncurry : ∀ {A B C} {f : A ⇒ B ↝ C}
    → curry (uncurry f) ≈ f
  curry∘uncurry {B = B} {C} = Bld.curry∘uncurry (B ↝′ C)

  uncurry∘curry : ∀ {A B C} {f : A × B ⇒ C}
    → uncurry (curry f) ≈ f
  uncurry∘curry {B = B} {C} = Bld.uncurry∘curry (B ↝′ C)

  curry∘curry : ∀ {A B C Y Z}
    → {f : (B ↝ C) × Y ⇒ Z} {g : A × B ⇒ C}
    → curry f ∘ curry g ≈ curry (f ∘ ⟨ curry g × id ⟩)
  curry∘curry {B = B} {C} {Y} {Z} = Bld.curry∘curry (B ↝′ C) (Y ↝′ Z)

  ↝-resp-≅ : ∀ {A A′ B B′}
    → A ≅ A′
    → B ≅ B′
    → (A ↝ B) ≅ (A′ ↝ B′)
  ↝-resp-≅ {A} {A′} {B} {B′} A≅A′ B≅B′
    = Bld.Exp-resp-≅ A≅A′ B≅B′ (A ↝′ B) (A′ ↝′ B′)

open Build public


{-# OPTIONS --type-in-type #-}
-- {-# OPTIONS --guardedness-preserving-type-constructors #-}

module PatternSynonymsErrorLocation where

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

infixr 2 _,_

record Unit : Set where

data Sigma (A : Set)(B : A -> Set) : Set where
  _,_ : (fst : A) -> B fst -> Sigma A B

-- Prod does not communicate guardedness
Prod : (A B : Set) -> Set
Prod A B = Sigma A \ _ -> B

data Empty : Set where

data ListTag : Set where nil cons : ListTag

{-# TERMINATING #-}
List : (A : Set) -> Set
List A = Sigma ListTag T where
  T : ListTag -> Set
  T nil  = Unit
  T cons = Sigma A \ _ -> List A

infix 5 _∷_

pattern []       = nil , _
pattern _∷_ x xs = cons , x , xs
-- FAILS: pattern x ∷ xs = cons , x , xs

data TyTag : Set where base arr : TyTag

{-# TERMINATING #-}
Ty : Set
Ty = Sigma TyTag T where
  T : TyTag -> Set
  T base = Unit
  T arr  = Sigma Ty \ _ -> Ty  -- Prod Ty Ty

infix 10 _⇒_

pattern ★       = base , _
pattern _⇒_ A B = arr , A , B

Context = List Ty

data NatTag : Set where zero succ : NatTag

Var : (Gamma : Context)(C : Ty) -> Set
Var []           C = Empty
Var (cons , A , Gamma) C =  Sigma NatTag T
  where T : NatTag -> Set
        T zero = A ≡ C
        T succ = Var Gamma C

pattern vz   = zero , refl
pattern vs x = succ , x

idVar : (Gamma : Context)(C : Ty)(x : Var Gamma C) -> Var Gamma C
idVar [] _ ()
-- CORRECT: idVar (A ∷ Gamma) C (zero , proof) = zero , proof
idVar (A ∷ Gamma) C vz         = vz
idVar (A ∷ Gamma) C (vs x)     = vs (idVar Gamma C x)


module Nat where

open import Eq

data ℕ : Set where
  Z : ℕ
  S : ℕ → ℕ

{-# BUILTIN NATURAL ℕ #-}

infixl 6 _+_
infixl 7 _×_

_+_ : ℕ → ℕ → ℕ
Z + n     = n
(S k) + n = S(k + n)

{-# BUILTIN NATPLUS _+_ #-}

_×_ : ℕ → ℕ → ℕ
Z  × n = Z
S m × n = n + m × n

{-# BUILTIN NATTIMES _×_ #-}

*-right-zero : ∀ (n : ℕ) → n × Z ≡ Z
*-right-zero Z = Refl
*-right-zero (S n) = *-right-zero n

testEq : (x : ℕ) → (y : ℕ) → (p : x ≡ y) → ℕ
testEq x _ Refl = x


module eq-reasoning {A : Set} where

  open import eq

  infix  1 begin_
  infixr 2 _≡⟨⟩_ _≡⟨_⟩_
  infix  3 _∎

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

  _≡⟨⟩_ : ∀ (x : A) {y : A}
    → x ≡ y
      -----
    → x ≡ y
  x ≡⟨⟩ x≡y  =  x≡y

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

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


{-# OPTIONS --without-K #-}
module hott.univalence where

open import level using (lsuc)
open import sum using (_,_ ; proj₁)
open import equality.core
open import equality.calculus
open import equality.reasoning
open import function.core
open import function.isomorphism.core using (_≅_ ; module _≅_)
open import hott.equivalence.core

-- mapping from equality to function
coerce : ∀ {i} {X Y : Set i} → X ≡ Y → X → Y
coerce refl = id

coerce-equiv : ∀ {i} {X Y : Set i} → (p : X ≡ Y) → weak-equiv (coerce p)
coerce-equiv refl x = (x , refl) , λ { (.x , refl) → refl }

coerce-hom : ∀ {i} {X Y Z : Set i}
           → (p : X ≡ Y)(q : Y ≡ Z)
           → coerce (p · q) ≡ coerce q ∘ coerce p
coerce-hom refl q = refl

-- mapping from propositional equality to weak equivalence
≡⇒≈ : ∀ {i} {X Y : Set i} → X ≡ Y → X ≈ Y
≡⇒≈ p = coerce p , coerce-equiv p

Univalence : ∀ i → Set (lsuc i)
Univalence i = {X Y : Set i} → weak-equiv $ ≡⇒≈ {X = X} {Y = Y}

postulate univalence : ∀ {i} → Univalence i

private
  module Properties {i} {X Y : Set i} where
    uni-equiv : (X ≡ Y) ≈ (X ≈ Y)
    uni-equiv = ≡⇒≈ , univalence

    uni-iso : (X ≡ Y) ≅ (X ≈ Y)
    uni-iso = ≈⇒≅ uni-equiv
    open _≅_ uni-iso public using ()
      renaming (from to ≈⇒≡)

    uni-coherence : (f : X ≈ Y) → coerce (≈⇒≡ f) ≡ proj₁ f
    uni-coherence f = begin
        coerce (≈⇒≡ f)
      ≡⟨ refl ⟩
        proj₁ (≡⇒≈ (≈⇒≡ f))
      ≡⟨ ap proj₁ (iso₂ f) ⟩
        proj₁ f
      ∎
      where
        open ≡-Reasoning
        open _≅_ uni-iso using (iso₂)

open Properties public


--------------------------------------------------------------------------------
-- This is part of Agda Inference Systems

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

open import Codata.Colist
open import Codata.Thunk
open import Size
open import Data.Empty
open import Relation.Binary.PropositionalEquality

module Examples.Colists.Auxiliary.Colist_member {A : Set} where

  data _∈_ : A → Colist A ∞ → Set where
    here : ∀ {x xs} → x ∈ (x ∷ xs)
    there : ∀{x y xs} → x ∈ xs .force → x ∈ (y ∷ xs)

  mem-abs : ∀{x xs} → x ∈ xs → xs ≡ [] → ⊥
  mem-abs {_} {.[]} () refl


-- The Berry majority function.

module Berry where

  data Bool : Set where
    F : Bool
    T : Bool

  maj : Bool -> Bool -> Bool -> Bool
  maj T T T = T
  maj T F x = x
  maj F x T = x
  maj x T F = x   -- doesn't hold definitionally
  maj F F F = F

  postulate
    z : Bool


-- {-# OPTIONS --show-implicit --show-irrelevant #-}
module Data.QuadTree.LensProofs.Valid-LensAtLocation where

open import Haskell.Prelude renaming (zero to Z; suc to S)
open import Data.Lens.Lens
open import Data.Logic
open import Data.QuadTree.InternalAgda
open import Agda.Primitive
open import Data.Lens.Proofs.LensLaws
open import Data.Lens.Proofs.LensPostulates
open import Data.Lens.Proofs.LensComposition
open import Data.QuadTree.LensProofs.Valid-LensLeaf
open import Data.QuadTree.LensProofs.Valid-LensWrappedTree
open import Data.QuadTree.LensProofs.Valid-LensA
open import Data.QuadTree.LensProofs.Valid-LensBCD
open import Data.QuadTree.LensProofs.Valid-LensGo
open import Data.QuadTree.Implementation.QuadrantLenses
open import Data.QuadTree.Implementation.Definition
open import Data.QuadTree.Implementation.ValidTypes
open import Data.QuadTree.Implementation.SafeFunctions
open import Data.QuadTree.Implementation.PublicFunctions
open import Data.QuadTree.Implementation.DataLenses

---- Lens laws for go

ValidLens-AtLocation-ViewSet :
    {t : Set} {{eqT : Eq t}}
    -> (loc : Nat × Nat) -> (dep : Nat)
    -> {ins : IsTrue (isInsidePow loc dep)}
    -> ViewSet (atLocation {t} loc dep {ins})
ValidLens-AtLocation-ViewSet (x , y) dep {ins} v s = trans refl (prop-Composition-ViewSet (ValidLens-WrappedTree) (ValidLens-go (x , y) dep {ins}) v s)

ValidLens-AtLocation-SetView :
    {t : Set} {{eqT : Eq t}}
    -> (loc : Nat × Nat) -> (dep : Nat)
    -> {ins : IsTrue (isInsidePow loc dep)}
    -> SetView (atLocation {t} loc dep {ins})
ValidLens-AtLocation-SetView (x , y) dep {ins} s = trans refl (prop-Composition-SetView (ValidLens-WrappedTree) (ValidLens-go (x , y) dep {ins}) s)

ValidLens-AtLocation-SetSet :
    {t : Set} {{eqT : Eq t}}
    -> (loc : Nat × Nat) -> (dep : Nat)
    -> {ins : IsTrue (isInsidePow loc dep)}
    -> SetSet (atLocation {t} loc dep {ins})
ValidLens-AtLocation-SetSet (x , y) dep {ins} v1 v2 s = trans refl (prop-Composition-SetSet (ValidLens-WrappedTree) (ValidLens-go (x , y) dep {ins}) v1 v2 s)

ValidLens-AtLocation : {t : Set} {{eqT : Eq t}}
    -> (loc : Nat × Nat) -> (dep : Nat)
    -> {ins : IsTrue (isInsidePow loc dep)}
    -> ValidLens (VQuadTree t {dep}) t
ValidLens-AtLocation {t} {{eqT}} (x , y) dep {ins} = CValidLens (atLocation (x , y) dep {ins}) (ValidLens-AtLocation-ViewSet (x , y) dep {ins}) (ValidLens-AtLocation-SetView (x , y) dep {ins}) (ValidLens-AtLocation-SetSet (x , y) dep {ins})


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

module Cubical.Categories.Equivalence.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Data.Sigma
open import Cubical.Categories.Category
open import Cubical.Categories.Functor
open import Cubical.Categories.NaturalTransformation
open import Cubical.Categories.Morphism
open import Cubical.Categories.Equivalence.Base
open import Cubical.HITs.PropositionalTruncation.Base

open Precategory
open Functor
open NatIso
open CatIso
open NatTrans
open isEquivalence

private
  variable
    ℓC ℓC' ℓD ℓD' : Level

-- Equivalence implies Full, Faithul, and Essentially Surjective

module _ {C : Precategory ℓC ℓC'} {D : Precategory ℓD ℓD'} where
  symEquiv : ∀ {F : Functor C D} → (e : isEquivalence F) → isEquivalence (e .invFunc)
  symEquiv {F} record { invFunc = G ; η = η ; ε = ε } = record { invFunc = F ; η = symNatIso ε ; ε = symNatIso η }

  isEquiv→Faithful : ∀ {F : Functor C D} → isEquivalence F → isFaithful F
  isEquiv→Faithful {F} record { invFunc = G
                              ; η = η
                              ; ε = _ }
                   c c' f g p = f
                              ≡⟨ sqRL η ⟩
                                cIso .mor ⋆⟨ C ⟩ G ⟪ F ⟪ f ⟫ ⟫ ⋆⟨ C ⟩ c'Iso .inv
                              ≡⟨ cong (λ v → cIso .mor ⋆⟨ C ⟩ (G ⟪ v ⟫) ⋆⟨ C ⟩ c'Iso .inv) p ⟩
                                cIso .mor ⋆⟨ C ⟩ G ⟪ F ⟪ g ⟫ ⟫ ⋆⟨ C ⟩ c'Iso .inv
                              ≡⟨ sym (sqRL η) ⟩
                                g
                              ∎
    where

      -- isomorphism between c and GFc
      cIso = isIso→CatIso (η .nIso c)
      -- isomorphism between c' and GFc'
      c'Iso = isIso→CatIso (η .nIso c')

module _ {C : Precategory ℓC ℓC'} {D : Precategory ℓD ℓD'} where
  isEquiv→Full : ∀ {F : Functor C D} → isEquivalence F → isFull F
  isEquiv→Full {F} eq@record { invFunc = G
                             ; η = η
                             ; ε = _ }
               c c' g = ∣ h , isEquiv→Faithful (symEquiv eq) _ _ _ _ GFh≡Gg ∣ -- apply faithfulness of G
    where
      -- isomorphism between c and GFc
      cIso = isIso→CatIso (η .nIso c)
      -- isomorphism between c' and GFc'
      c'Iso = isIso→CatIso (η .nIso c')

      -- reverses
      cIso⁻ = symCatIso cIso
      c'Iso⁻ = symCatIso c'Iso

      h = cIso .mor ⋆⟨ C ⟩ G ⟪ g ⟫ ⋆⟨ C ⟩ c'Iso .inv

      -- we show that both `G ⟪ g ⟫` and `G ⟪ F ⟪ h ⟫ ⟫`
      -- are equal to the same thing
      -- namely : cIso .inv ⋆⟨ C ⟩ h ⋆⟨ C ⟩ c'Iso .mor
      Gg≡ηhη : G ⟪ g ⟫ ≡ cIso .inv ⋆⟨ C ⟩ h ⋆⟨ C ⟩ c'Iso .mor
      Gg≡ηhη = invMoveL cAreInv move-c' ∙ sym (C .⋆Assoc _ _ _)
        where
          cAreInv : areInv (cIso .mor) (cIso .inv)
          cAreInv = CatIso→areInv cIso

          c'AreInv : areInv (c'Iso .mor) (c'Iso .inv)
          c'AreInv = CatIso→areInv c'Iso

          move-c' : cIso .mor ⋆⟨ C ⟩ G ⟪ g ⟫ ≡ h ⋆⟨ C ⟩ c'Iso .mor
          move-c' = invMoveR (symAreInv c'AreInv) refl

      GFh≡Gg : G ⟪ F ⟪ h ⟫ ⟫ ≡ G ⟪ g ⟫
      GFh≡Gg = G ⟪ F ⟪ h ⟫ ⟫
             ≡⟨ sqLR η ⟩
               cIso .inv ⋆⟨ C ⟩ h ⋆⟨ C ⟩ c'Iso .mor
             ≡⟨ sym Gg≡ηhη ⟩
               G ⟪ g ⟫
             ∎

  isEquiv→Surj : ∀ {F : Functor C D} → isEquivalence F → isEssentiallySurj F
  isEquiv→Surj isE d = (isE .invFunc ⟅ d ⟆) , isIso→CatIso ((isE .ε .nIso) d)


module Category.Instance where

open import Level
open import Category.Core

𝟙 : Category _ _
𝟙 = record
    { Objects = record
        { Carrier = ⊤
        ; _≈_ = λ _ _ → ⊤
        ; isEquivalence = _
        }
    ; Morphisms = record
        { Carrier = λ x → ⊤
        ; _≈_ = λ _ _ → ⊤
        ; isEquivalence = _
        ; _∘_ = λ _ _ → tt
        ; id = λ a → tt
        ; isMorphism = _
        }
    }
    where
        open import Data.Unit

-- "pointing" an element with a functor from 𝟙
point : ∀ {𝒸 ℓ} → {C : Category 𝒸 ℓ} → Category.Object C → Functor 𝟙 C
point {_} {_} {C} c = record
    { mapObject = λ _ → c
    ; mapMorphism = λ _ → id c
    ; isFunctor = record
        { preserve-id = λ a → MorphEq.refl
        ; preserve-∘ = λ _ _ → MorphEq.sym (left-identity (id c))
        }
    }
    where
        open Category C
        open import Relation.Binary.Indexed
        module MorphEq = IsEquivalence (MorphismStructure.isEquivalence Morphisms)

        open IsMorphism isMorphism

-- the identity functo
identity : ∀ {𝒸 ℓ} → (C : Category 𝒸 ℓ) → Functor C C
identity C = record
    { mapObject = λ x → x
    ; mapMorphism = λ x → x
    ; isFunctor = record
        { preserve-id = λ a → MorphEq.refl
        ; preserve-∘ = λ f g → MorphEq.refl
        }
    }
    where
        open Category C
        open import Relation.Binary.Indexed
        module MorphEq = IsEquivalence (MorphismStructure.isEquivalence Morphisms)

        open IsMorphism isMorphism


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

open import Data.Empty
open import Data.Sum.Base using (_⊎_; inj₁; inj₂)
open import Function.Base using (_∘_; id)
open import Relation.Nullary using (¬_)
open import Relation.Binary.PropositionalEquality.Core using (_≡_; refl; subst; cong; sym)

record _◁_ {ℓ} (A B : Set ℓ) : Set ℓ where
  constructor _,_,_
  field
    ϕ : A → B
    ψ : B → A
    retract : ψ ∘ ϕ ≡ id
open _◁_

record _◁′_ {ℓ} (A B : Set ℓ) : Set ℓ where
  constructor _,_,_
  field
    ϕ : A → B
    ψ : B → A
    retract : A ◁ B → ψ ∘ ϕ ≡ id
open _◁′_

postulate
  EM : ∀ {ℓ} (A : Set ℓ) → A ⊎ (¬ A)

℘ : ∀ {ℓ} → Set ℓ → Set _
℘ X = X → Set

t : ∀ {ℓ} (A B : Set ℓ) → ℘ A ◁′ ℘ B
t A B with EM (℘ A ◁ ℘ B)
... | inj₁  ℘A◁℘B =
      let ϕ , ψ , retract = ℘A◁℘B
      in ϕ , ψ , λ _ → retract
... | inj₂ ¬℘A◁℘B =
      (λ _ _ → ⊥) , (λ _ _ → ⊥) , λ ℘A◁℘B → ⊥-elim (¬℘A◁℘B ℘A◁℘B)

-- type-in-type allows U to be put into Set...
U : Set
U = ∀ X → ℘ X

-- ...so that u: U can be applied to U itself
projᵤ : U → ℘ U
projᵤ u = u U

injᵤ : ℘ U → U
injᵤ f X =
  let _ , ψ , _ = t X U
      ϕ , _ , _ = t U U
  in ψ (ϕ f)

projᵤ∘injᵤ : projᵤ ∘ injᵤ ≡ id
projᵤ∘injᵤ = retract (t U U) (id , id , refl)

_∈_ : U → U → Set
u ∈ v = projᵤ u v

Russell : ℘ U
Russell u = ¬ u ∈ u

r : U
r = injᵤ Russell

-- up to here EM + impredicativity is enough,
-- as long as _≡_ itself is in the impredicative universe,
-- but to go further, large elimination (via subst) is required
r∈r≡r∉r : r ∈ r ≡ (¬ r ∈ r)
r∈r≡r∉r = cong (λ f → f Russell r) projᵤ∘injᵤ

r∉r : ¬ r ∈ r
r∉r r∈r =
  let r∈r→r∉r = subst id r∈r≡r∉r
  in r∈r→r∉r r∈r r∈r

false : ⊥
false =
  let r∉r→r∈r = subst id (sym r∈r≡r∉r)
  in r∉r (r∉r→r∈r r∉r)


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

module Categories.Minus2-Category.Properties where

-- All -2-Categories are equivalent to One

open import Level
open import Data.Product using (Σ; _,_; proj₁; proj₂)
open import Data.Unit using (⊤; tt)

open import Categories.Minus2-Category
open import Categories.Category
import Categories.Morphism as M
open import Categories.Category.Monoidal
open import Categories.Category.Instance.One
open import Categories.Category.Equivalence hiding (refl)
open import Categories.NaturalTransformation using (ntHelper)

private
  variable
    o ℓ e : Level

shrink-them-all : (X : -2-Category {o} {ℓ} {e}) → StrongEquivalence (-2-Category.cat X) (One {o} {ℓ} {e})
shrink-them-all X = record
  { F = record
    { F₀ = λ _ → lift tt
    ; F₁ = λ _ → lift tt
    }
  ; G = record
    { F₀ = λ _ → proj₁ Obj-Contr
    ; F₁ = λ _ → M._≅_.from (proj₂ Obj-Contr (proj₁ Obj-Contr))
    ; identity = Hom-Conn
    ; homomorphism = Hom-Conn
    ; F-resp-≈ = λ _ → Hom-Conn
    }
  ; weak-inverse = record
    { F∘G≈id = _
    ; G∘F≈id = record
      { F⇒G = ntHelper (record
        { η = λ y → M._≅_.from (proj₂ Obj-Contr y)
        ; commute = λ _ → Hom-Conn
        })
      ; F⇐G = ntHelper (record
        { η = λ y → M._≅_.to (proj₂ Obj-Contr y)
        ; commute = λ _ → Hom-Conn
        })
      ; iso = λ Z → record
        { isoˡ = M._≅_.isoˡ (proj₂ Obj-Contr Z)
        ; isoʳ = M._≅_.isoʳ (proj₂ Obj-Contr Z)
        }
      }
    }
  }
  where
    open -2-Category X
    open Category cat