-- Andreas, 2015-07-20, record patterns

open import Common.Product
open import Common.Prelude
open import Common.Equality

swap : {A B : Set} (p : A × B) → B × A
swap record{ proj₁ = a; proj₂ = b } = record{ proj₁ = b; proj₂ = a }

fst : {A : Set}{B : A → Set} (p : Σ A B) → A
fst record{ proj₁ = a } = a

snd : {A : Set}{B : A → Set} (p : Σ A B) → B (fst p)
snd record{ proj₂ = b } = b

module _ (A : Set) (B : A → Set) (C : (a : A) → B a → Set) where

  Tr = Σ A (λ a → Σ (B a) (C a))

  fst3 : Tr → A
  fst3 record{ proj₁ = a } = a

  snd3 : (t : Tr) → B (fst3 t)
  snd3 record{ proj₂ = record { proj₁ = b }} = b

  thd3 : (t : Tr) → C (fst3 t) (snd3 t)
  thd3 record{ proj₂ = record { proj₂ = c }} = c

  thd32 : (t u : Tr) → C (fst3 t) (snd3 t)
  thd32 record{ proj₂ = record { proj₂ = c }}
        record{ proj₂ = record { proj₂ = _ }} = c

postulate A : Set

record R : Set where
  field f : A

T : Bool → Set
T true  = R
T false = A

-- Postponed record pattern
test : ∀{b} → T b → b ≡ true → A
test record{f = a} refl = a


module Algebra where

-- Core graph construction primitives
data Graph (A : Set) : Set where
    ε   : Graph A                       -- Empty graph
    v   : A -> Graph A                  -- Graph comprising a single vertex
    _+_ : Graph A -> Graph A -> Graph A -- Overlay two graphs
    _*_ : Graph A -> Graph A -> Graph A -- Connect two graphs

infixl 4  _≡_
infixl 8  _+_
infixl 9  _*_
infix  10 _⊆_

-- Equational theory of graphs
data _≡_ {A} : (x y : Graph A) -> Set where
    -- Equivalence relation
    reflexivity  : ∀ {x     : Graph A} ->                   x ≡ x
    symmetry     : ∀ {x y   : Graph A} -> x ≡ y ->          y ≡ x
    transitivity : ∀ {x y z : Graph A} -> x ≡ y -> y ≡ z -> x ≡ z

    -- Congruence
    +left-congruence  : ∀ {x y z : Graph A} -> x ≡ y -> x + z ≡ y + z
    +right-congruence : ∀ {x y z : Graph A} -> x ≡ y -> z + x ≡ z + y
    *left-congruence  : ∀ {x y z : Graph A} -> x ≡ y -> x * z ≡ y * z
    *right-congruence : ∀ {x y z : Graph A} -> x ≡ y -> z * x ≡ z * y

    -- Axioms of +
    +commutativity : ∀ {x y : Graph A}   -> x + y       ≡ y + x
    +associativity : ∀ {x y z : Graph A} -> x + (y + z) ≡ (x + y) + z

    -- Axioms of *
    *left-identity  : ∀ {x     : Graph A} -> ε * x       ≡ x
    *right-identity : ∀ {x     : Graph A} -> x * ε       ≡ x
    *associativity  : ∀ {x y z : Graph A} -> x * (y * z) ≡ (x * y) * z

    -- Other axioms
    left-distributivity  : ∀ {x y z : Graph A} -> x * (y + z) ≡ x * y + x * z
    right-distributivity : ∀ {x y z : Graph A} -> (x + y) * z ≡ x * z + y * z
    decomposition        : ∀ {x y z : Graph A} -> x * y * z   ≡ x * y + x * z + y * z

-- Subgraph relation
_⊆_ : ∀ {A} -> Graph A -> Graph A -> Set
x ⊆ y = x + y ≡ y


{-# OPTIONS --no-universe-polymorphism #-}
open import Induction.WellFounded as WF
open import Induction.Nat
open import Relation.Binary.Core hiding (Total)
open import Relation.Unary as U using (Decidable)
open import Relation.Nullary
open import Function using (_on_)
open import Data.Nat
import Level as L using (zero)
open import Data.List

open import BagEquality

module Lists where

infixr 8 _<l_

_<l_ : {A : Set} → Rel (List A) L.zero
_<l_ = Data.Nat._<′_ on length

<l-wellFounded : {A : Set} → Well-founded (_<l_ {A = A})
<l-wellFounded = newWf where
          module InverseOfProj = WF.Inverse-image length
          newWf = InverseOfProj.well-founded <′-well-founded

data Ordered  : {A : Set} → Rel A _ → List A → Set where
                 NilIsOrd : {A : Set} {LEQ : Rel A _} → Ordered LEQ []
                 SingleIsOrd : {A : Set} {LEQ : Rel A _} {x : A} → Ordered LEQ [ x ]
                 HeadTailOrd : {A : Set} {LEQ : Rel A _} {x y : A} {zs : List A} → LEQ x y → Ordered LEQ (y ∷ zs) → Ordered LEQ (x ∷ (y ∷ zs))

cons-Order-cong : {A : Set} → {LEQ : Rel A L.zero} → {x : A} → {ys : List A} → (∀ z → z ∈ ys → LEQ x z) → Ordered LEQ ys → Ordered LEQ (x ∷ ys)
cons-Order-cong {A} {LEQ} {y} {[]} _ _ = SingleIsOrd
cons-Order-cong {A} {LEQ} {x} {y ∷ ys} xLEQ ord-ys = HeadTailOrd (xLEQ y (inj₁ refl)) ord-ys

++-Order-cong : {A : Set} {LEQ : Rel A L.zero} → {xs ys : List A} {y : A} → (∀ z → z ∈ xs → LEQ z y) → Ordered LEQ xs → Ordered LEQ (y ∷ ys) → Ordered LEQ (xs ++ (y ∷ ys))
++-Order-cong {A} {LEQ} {[]}             {ys} {y} _        _                          ord-y∷ys = ord-y∷ys
++-Order-cong {A} {LEQ} {x ∷ []}         {ys} {y} yGEQ     _                          ord-y∷ys = HeadTailOrd (yGEQ x (inj₁ refl)) ord-y∷ys
++-Order-cong {A} {LEQ} {x₁ ∷ (x₂ ∷ xs)} {ys} {y} yGEQ (HeadTailOrd x₁LEQx₂ ord-x∷xs) ord-y∷ys = HeadTailOrd x₁LEQx₂ (++-Order-cong (λ z zIn → yGEQ z (inj₂ zIn)) ord-x∷xs ord-y∷ys)

Total : {A : Set} → Rel A L.zero → Set
Total {A} LEQ = (x y : A) → LEQ x y ⊕ LEQ y x

data ListPrimitive : {A : Set} → List A → Set where
            NilIsPrim : ∀{A} → ListPrimitive {A = A} []

consIsNotPrim : {A : Set} → {x : A} → {xs : List A} → ¬ ListPrimitive (x ∷ xs)
consIsNotPrim ()

primDec : {A : Set} → U.Decidable (ListPrimitive {A = A})
primDec []       = yes NilIsPrim
primDec (x ∷ xs) = no consIsNotPrim

data ListPrimitive2 : {A : Set} → List A → Set where
           NilIsPrim2 : ∀{A} → ListPrimitive2 {A = A} []
           SingleIsPrim2 : ∀{A} {x : A} → ListPrimitive2 (x ∷ [])

consConsIsNotPrim2 : {A : Set} → {x y : A} → {zs : List A} → ¬ ListPrimitive2 (x ∷ (y ∷ zs))
consConsIsNotPrim2 ()

prim2Dec : {A : Set} → U.Decidable (ListPrimitive2 {A = A})
prim2Dec [] = yes NilIsPrim2
prim2Dec (x ∷ []) = yes SingleIsPrim2
prim2Dec (x ∷ (y ∷ zs)) = no consConsIsNotPrim2


module Generic.Lib.Equality.Coerce where

open import Generic.Lib.Intro
open import Generic.Lib.Equality.Propositional
open import Generic.Lib.Decidable
open import Generic.Lib.Data.Product

Coerce′ : ∀ {α β} -> α ≡ β -> Set α -> Set β
Coerce′ refl = id

coerce′ : ∀ {α β} {A : Set α} -> (q : α ≡ β) -> A -> Coerce′ q A
coerce′ refl = id

uncoerce′ : ∀ {α β} {A : Set α} -> (q : α ≡ β) -> Coerce′ q A -> A
uncoerce′ refl = id

inspectUncoerce′ : ∀ {α β} {A : Set α}
                 -> (q : α ≡ β) -> (p : Coerce′ q A) -> ∃ λ x -> p ≡ coerce′ q x
inspectUncoerce′ refl x = x , refl

split : ∀ {α β γ δ} {A : Set α} {B : A -> Set β} {C : Set γ}
      -> (q : α ⊔ β ≡ δ) -> Coerce′ q (Σ A B) -> (∀ x -> B x -> C) -> C
split q p g = uncurry g (uncoerce′ q p)

decCoerce′ : ∀ {α β} {A : Set α} -> (q : α ≡ β) -> IsSet A -> IsSet (Coerce′ q A)
decCoerce′ refl = id

data Coerce {β} : ∀ {α} -> α ≡ β -> Set α -> Set β where
  coerce : ∀ {A} -> A -> Coerce refl A

qcoerce : ∀ {α β} {A : Set α} {q : α ≡ β} -> A -> Coerce q A
qcoerce {q = refl} = coerce


module FFI.Data.Either where

{-# FOREIGN GHC import qualified Data.Either #-}

data Either (A B : Set) : Set where
  Left : A → Either A B
  Right : B → Either A B
{-# COMPILE GHC Either = data Data.Either.Either (Data.Either.Left|Data.Either.Right) #-}

swapLR : ∀ {A B} → Either A B → Either B A
swapLR (Left x) = Right x
swapLR (Right x) = Left x

mapL : ∀ {A B C} → (A → B) → Either A C → Either B C
mapL f (Left x) = Left (f x)
mapL f (Right x) = Right x

mapR : ∀ {A B C} → (B → C) → Either A B → Either A C
mapR f (Left x) = Left x
mapR f (Right x) = Right (f x)

mapLR : ∀ {A B C D} → (A → B) → (C → D) → Either A C → Either B D
mapLR f g (Left x) = Left (f x)
mapLR f g (Right x) = Right (g x)

cond : ∀ {A B C : Set} → (A → C) → (B → C) → (Either A B) → C
cond f g (Left x) = f x
cond f g (Right x) = g x


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties related to addition of integers
------------------------------------------------------------------------

module Data.Integer.Addition.Properties where

open import Algebra
import Algebra.FunctionProperties
open import Algebra.Structures
open import Data.Integer hiding (suc)
open import Data.Nat using (suc; zero) renaming (_+_ to _ℕ+_)
import Data.Nat.Properties as ℕ
open import Relation.Binary.PropositionalEquality

open Algebra.FunctionProperties (_≡_ {A = ℤ})
open CommutativeSemiring ℕ.commutativeSemiring
  using (+-comm; +-assoc; +-identity)

------------------------------------------------------------------------
-- Addition and zero form a commutative monoid

private

  comm : Commutative _+_
  comm -[1+ a ] -[1+ b ] rewrite +-comm a b = refl
  comm (+   a ) (+   b ) rewrite +-comm a b = refl
  comm -[1+ _ ] (+   _ ) = refl
  comm (+   _ ) -[1+ _ ] = refl

  identityˡ : LeftIdentity (+ 0) _+_
  identityˡ -[1+ _ ] = refl
  identityˡ (+   _ ) = refl

  identityʳ : RightIdentity (+ 0) _+_
  identityʳ x rewrite comm x (+ 0) = identityˡ x

  distribˡ-⊖-+-neg : ∀ a b c → b ⊖ c + -[1+ a ] ≡ b ⊖ (suc c ℕ+ a)
  distribˡ-⊖-+-neg _ zero    zero    = refl
  distribˡ-⊖-+-neg _ zero    (suc _) = refl
  distribˡ-⊖-+-neg _ (suc _) zero    = refl
  distribˡ-⊖-+-neg a (suc b) (suc c) = distribˡ-⊖-+-neg a b c

  distribʳ-⊖-+-neg : ∀ a b c → -[1+ a ] + (b ⊖ c) ≡ b ⊖ (suc a ℕ+ c)
  distribʳ-⊖-+-neg a b c
    rewrite comm -[1+ a ] (b ⊖ c)
          | distribˡ-⊖-+-neg a b c
          | +-comm a c
          = refl

  distribˡ-⊖-+-pos : ∀ a b c → b ⊖ c + + a ≡ b ℕ+ a ⊖ c
  distribˡ-⊖-+-pos _ zero    zero    = refl
  distribˡ-⊖-+-pos _ zero    (suc _) = refl
  distribˡ-⊖-+-pos _ (suc _) zero    = refl
  distribˡ-⊖-+-pos a (suc b) (suc c) = distribˡ-⊖-+-pos a b c

  distribʳ-⊖-+-pos : ∀ a b c → + a + (b ⊖ c) ≡ a ℕ+ b ⊖ c
  distribʳ-⊖-+-pos a b c
    rewrite comm (+ a) (b ⊖ c)
          | distribˡ-⊖-+-pos a b c
          | +-comm a b
          = refl

  assoc : Associative _+_
  assoc (+ zero) y z rewrite identityˡ      y  | identityˡ (y + z) = refl
  assoc x (+ zero) z rewrite identityʳ  x      | identityˡ      z  = refl
  assoc x y (+ zero) rewrite identityʳ (x + y) | identityʳ  y      = refl
  assoc -[1+ a ]  -[1+ b ]  (+ suc c) = sym (distribʳ-⊖-+-neg a c b)
  assoc -[1+ a ]  (+ suc b) (+ suc c) = distribˡ-⊖-+-pos (suc c) b a
  assoc (+ suc a) -[1+ b ]  -[1+ c ]  = distribˡ-⊖-+-neg c a b
  assoc (+ suc a) -[1+ b ] (+ suc c)
    rewrite distribˡ-⊖-+-pos (suc c) a b
          | distribʳ-⊖-+-pos (suc a) c b
          | sym (+-assoc a 1 c)
          | +-comm a 1
          = refl
  assoc (+ suc a) (+ suc b) -[1+ c ]
    rewrite distribʳ-⊖-+-pos (suc a) b c
          | sym (+-assoc a 1 b)
          | +-comm a 1
          = refl
  assoc -[1+ a ] -[1+ b ] -[1+ c ]
    rewrite sym (+-assoc a 1 (b ℕ+ c))
          | +-comm a 1
          | +-assoc a b c
          = refl
  assoc -[1+ a ] (+ suc b) -[1+ c ]
    rewrite distribʳ-⊖-+-neg a b c
          | distribˡ-⊖-+-neg c b a
          = refl
  assoc (+ suc a) (+ suc b) (+ suc c)
    rewrite +-assoc (suc a) (suc b) (suc c)
          = refl

  isSemigroup : IsSemigroup _≡_ _+_
  isSemigroup = record
    { isEquivalence = isEquivalence
    ; assoc         = assoc
    ; ∙-cong        = cong₂ _+_
    }

  isCommutativeMonoid : IsCommutativeMonoid _≡_ _+_ (+ 0)
  isCommutativeMonoid = record
    { isSemigroup = isSemigroup
    ; identityˡ   = identityˡ
    ; comm        = comm
    }

commutativeMonoid : CommutativeMonoid _ _
commutativeMonoid = record
  { Carrier             = ℤ
  ; _≈_                 = _≡_
  ; _∙_                 = _+_
  ; ε                   = + 0
  ; isCommutativeMonoid = isCommutativeMonoid
  }


------------------------------------------------------------------------------
-- Properties of the divisibility relation
------------------------------------------------------------------------------

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

module LTC-PCF.Data.Nat.Divisibility.By0.Properties where

open import Common.FOL.Relation.Binary.EqReasoning

open import LTC-PCF.Base
open import LTC-PCF.Base.Properties
open import LTC-PCF.Data.Nat
open import LTC-PCF.Data.Nat.Properties
open import LTC-PCF.Data.Nat.Divisibility.By0
open import LTC-PCF.Data.Nat.Inequalities
open import LTC-PCF.Data.Nat.Inequalities.Properties
open import LTC-PCF.Data.Nat.Properties
open import LTC-PCF.Data.Nat.UnaryNumbers
open import LTC-PCF.Data.Nat.UnaryNumbers.Totality

------------------------------------------------------------------------------
-- Any positive number divides 0.
S∣0 : ∀ {n} → N n → succ₁ n ∣ zero
S∣0 {n} Nn = zero , nzero , sym (*-leftZero (succ₁ n))

-- 0 divides 0.
0∣0 : zero ∣ zero
0∣0 = zero , nzero , sym (*-leftZero zero)

-- The divisibility relation is reflexive.
∣-refl : ∀ {n} → N n → n ∣ n
∣-refl {n} Nn = [1] , 1-N , sym (*-leftIdentity Nn)

-- If x divides y and z then x divides y ∸ z.
x∣y→x∣z→x∣y∸z-helper : ∀ {m n o k k'} → N m → N k → N k' →
                       n ≡ k * m →
                       o ≡ k' * m →
                       n ∸ o ≡ (k ∸ k') * m
x∣y→x∣z→x∣y∸z-helper Nm Nk Nk' refl refl = sym (*∸-leftDistributive Nk Nk' Nm)

x∣y→x∣z→x∣y∸z : ∀ {m n o} → N m → N n → N o → m ∣ n → m ∣ o → m ∣ n ∸ o
x∣y→x∣z→x∣y∸z Nm Nn No (k , Nk , h₁) (k' , Nk' , h₂) =
  k ∸ k' , ∸-N Nk Nk' , x∣y→x∣z→x∣y∸z-helper Nm Nk Nk' h₁ h₂

-- If x divides y and z then x divides y + z.
x∣y→x∣z→x∣y+z-helper : ∀ {m n o k k'} → N m → N k → N k' →
                       n ≡ k * m →
                       o ≡ k' * m →
                       n + o ≡ (k + k') * m
x∣y→x∣z→x∣y+z-helper Nm Nk Nk' refl refl = sym (*+-leftDistributive Nk Nk' Nm)

x∣y→x∣z→x∣y+z : ∀ {m n o} → N m → N n → N o → m ∣ n → m ∣ o → m ∣ n + o
x∣y→x∣z→x∣y+z Nm Nn No (k , Nk , h₁) (k' , Nk' , h₂) =
  k + k' , +-N Nk Nk' , x∣y→x∣z→x∣y+z-helper Nm Nk Nk' h₁ h₂

-- If x divides y and y is positive, then x ≤ y.
x∣S→x≤S : ∀ {m n} → N m → N n → m ∣ (succ₁ n) → m ≤ succ₁ n
x∣S→x≤S {m} Nm Nn (.zero , nzero , Sn≡0*m) =
  ⊥-elim (0≢S (trans (sym (*-leftZero m)) (sym Sn≡0*m)))
x∣S→x≤S {m} Nm Nn (.(succ₁ k) , nsucc {k} Nk , Sn≡Sk*m) =
  subst (λ t₁ → m ≤ t₁)
        (sym Sn≡Sk*m)
        (subst (λ t₂ → m ≤ t₂)
               (sym (*-Sx k m))
               (x≤x+y Nm (*-N Nk Nm)))

0∣x→x≡0 : ∀ {m} → N m → zero ∣ m → m ≡ zero
0∣x→x≡0 nzero          _                 = refl
0∣x→x≡0 (nsucc {m} Nm) (k , Nk , Sm≡k*0) =
  ⊥-elim (0≢S (trans (sym (*-leftZero k))
                     (trans (*-comm nzero Nk) (sym Sm≡k*0))))


module Screen where

import Data.Nat
import Data.Bool
import Data.List
import Logic.Base

open Data.Bool
open Data.List
open Data.Nat
open Logic.Base

-- Ranges -----------------------------------------------------------------

data Range : Set where
  range : Nat -> Nat -> Range

inRange : Range -> Nat -> Bool
inRange (range lo hi) x = lo ≤ x && x ≤ hi

low : Range -> Nat
low (range lo _) = lo

high : Range -> Nat
high (range _ hi) = hi

size : Range -> Nat
size (range lo hi) = suc hi - lo

enumerate : Range -> List Nat
enumerate (range lo hi) = enum lo hi
  where
    list : Nat -> Nat -> List Nat
    list _ 0       = []
    list k (suc n) = k :: list (suc k) n

    enum : Nat -> Nat -> List Nat
    enum lo hi = map (_+_ lo) (list 0 (suc hi - lo))

-- The screen example -----------------------------------------------------

xRange : Range
xRange = range 0 79

yRange : Range
yRange = range 0 24

screenRange : Range
screenRange = range 0xb8000 0xb87ff

-- Converting (x,y) to addr

plot : Nat -> Nat -> Nat
plot x y = low screenRange + x + size xRange * y

-- The property

forAll : Range -> (Nat -> Bool) -> Bool
forAll r p = foldr (\n b -> p n && b) true (enumerate r)

prop : Bool
prop = forAll xRange \x ->
       forAll yRange \y ->
       inRange screenRange (plot x y)

proof : IsTrue prop
proof = tt


{-# OPTIONS --safe #-}

module Ferros.Prelude where

open import Relation.Binary.PropositionalEquality
open import Data.Nat
open import Data.Nat.Properties
open import Data.Bool hiding (_≤_)

ℕ-sub : (x y : ℕ) → (y ≤ x) → ℕ
ℕ-sub x .zero z≤n = x
ℕ-sub ._ ._ (s≤s p) = ℕ-sub _ _ p

invert-ℕ-sub : ∀ x y → (p : y ≤ x) → (ℕ-sub x y p) + y ≡ x
invert-ℕ-sub x .zero z≤n = +-identityʳ x
invert-ℕ-sub (suc x) (suc y) (s≤s p) = begin
  (ℕ-sub (suc x) (suc y) (s≤s p)) + suc y   ≡⟨ +-suc (ℕ-sub (suc x) (suc y) (s≤s p)) y ⟩
  suc ((ℕ-sub (suc x) (suc y) (s≤s p)) + y) ≡⟨ cong suc (invert-ℕ-sub x y p) ⟩
  suc x
  ∎ where open ≡-Reasoning


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

open import Agda.Primitive
open import Prelude
import GSeTT.Typed-Syntax
import Globular-TT.Syntax

{- Type theory for globular sets -}
module Globular-TT.Eqdec-syntax {l}
  (index : Set l) (eqdec-index : eqdec index) where

  open import Globular-TT.Syntax index

  eqdec-Ty : eqdec Pre-Ty
  eqdec-Tm : eqdec Pre-Tm
  eqdec-Sub : eqdec Pre-Sub

  eqdec-Ty ∗ ∗ = inl idp
  eqdec-Ty ∗ (⇒ _ _ _) = inr λ{()}
  eqdec-Ty (⇒ _ _ _ ) ∗ = inr λ{()}
  eqdec-Ty (⇒ A t u) (⇒ B t' u') with eqdec-Ty A B | eqdec-Tm t t' | eqdec-Tm u u'
  ...                            | inl idp | inl idp | inl idp = inl idp
  ...                            | inr A≠B | _ | _ = inr λ{idp → A≠B idp}
  ...                            | inl idp | inr t≠t' | _ = inr λ eq → t≠t' (snd (fst (=⇒ eq)))
  ...                            | inl idp | inl idp | inr u≠u' = inr λ eq → u≠u' (snd (=⇒ eq))
  eqdec-Tm (Var x) (Var y) with eqdecℕ x y
  ...                      | inl idp = inl idp
  ...                      | inr x≠y = inr λ {idp → x≠y idp}
  eqdec-Tm (Var _) (Tm-constructor _ _) = inr λ{()}
  eqdec-Tm (Tm-constructor _ _) (Var _) = inr λ{()}
  eqdec-Tm (Tm-constructor i γ) (Tm-constructor i' γ') with eqdec-index i i' | eqdec-Sub γ γ'
  ...                                                   | inl idp | inl idp = inl idp
  ...                                                   | inr i≠i' | _ = inr λ{idp → i≠i' idp}
  ...                                                   | inl idp | inr γ≠γ' = inr λ eq → γ≠γ' (snd (=Tm-constructor eq))
  eqdec-Sub <> <> = inl idp
  eqdec-Sub < _ , _ ↦ _ > <> = inr λ{()}
  eqdec-Sub <> < _ , _ ↦ _ > = inr λ{()}
  eqdec-Sub < γ , x ↦ t > < γ' , y ↦ t' > with eqdec-Sub γ γ' | eqdecℕ x y | eqdec-Tm t t'
  ...                                      | inl idp | inl idp | inl idp = inl idp
  ...                                      | inr γ≠γ' | _ | _ = inr λ{idp → γ≠γ' idp}
  ...                                      | inl idp | inr x≠y | _ = inr λ eq → x≠y (snd (fst (=<,> eq)))
  ...                                      | inl idp | inl idp | inr t≠t' = inr λ eq → t≠t' (snd (=<,> eq))


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

open import LogicalFormulae
open import Numbers.Naturals.Semiring
open import Numbers.Naturals.Order
open import Numbers.Integers.RingStructure.Ring
open import Semirings.Definition
open import Rings.Orders.Partial.Definition
open import Rings.Orders.Total.Definition
open import Orders.Total.Definition
open import Orders.Partial.Definition
open import Setoids.Orders.Total.Definition

module Numbers.Integers.Order where

infix 5 _<Z_
record _<Z_ (a : ℤ) (b : ℤ) : Set where
  constructor le
  field
    x : ℕ
    proof : (nonneg (succ x)) +Z a ≡ b

lessLemma : (a x : ℕ) → succ x +N a ≡ a → False
lessLemma zero x pr = naughtE (equalityCommutative pr)
lessLemma (succ a) x pr = lessLemma a x q
  where
    q : succ x +N a ≡ a
    q rewrite Semiring.commutative ℕSemiring a (succ x) | Semiring.commutative ℕSemiring x a | Semiring.commutative ℕSemiring (succ a) x = succInjective pr

irreflexive : (x : ℤ) → x <Z x → False
irreflexive (nonneg x) record { x = y ; proof = proof } = lessLemma x y (nonnegInjective proof)
irreflexive (negSucc a) record { x = x ; proof = proof } = naughtE (equalityCommutative q)
  where
    pr' : nonneg (succ x) +Z (negSucc a +Z nonneg (succ a)) ≡ negSucc a +Z nonneg (succ a)
    pr' rewrite +ZAssociative (nonneg (succ x)) (negSucc a) (nonneg (succ a)) = applyEquality (λ t → t +Z nonneg (succ a)) proof
    pr'' : nonneg (succ x) +Z nonneg 0 ≡ nonneg 0
    pr'' rewrite equalityCommutative (additiveInverseExists a) = identityOfIndiscernablesLeft _≡_ pr' q
      where
        q : nonneg (succ x) +Z (negSucc a +Z nonneg (succ a)) ≡ nonneg (succ (x +N 0))
        q rewrite Semiring.commutative ℕSemiring x 0 | additiveInverseExists a | Semiring.commutative ℕSemiring x 0 = refl
    pr''' : succ x +N 0 ≡ 0
    pr''' = nonnegInjective pr''
    q : succ x ≡ 0
    q rewrite Semiring.commutative ℕSemiring 0 (succ x) = pr'''

lessZTransitive : {a b c : ℤ} → (a <Z b) → (b <Z c) → (a <Z c)
lessZTransitive {a} {b} {c} (le d1 pr1) (le d2 pr2) rewrite equalityCommutative pr1 = le (d1 +N succ d2) pr
  where
    pr : nonneg (succ (d1 +N succ d2)) +Z a ≡ c
    pr rewrite +ZAssociative (nonneg (succ d2)) (nonneg (succ d1)) a | Semiring.commutative ℕSemiring (succ d2) (succ d1) = pr2

lessInherits : {a b : ℕ} → (a <N b) → ((nonneg a) <Z (nonneg b))
_<Z_.x (lessInherits {a} {b} (le x proof)) = x
_<Z_.proof (lessInherits {a} {.(succ (x +N a))} (le x refl)) = refl

lessInheritsNegsucc : {a b : ℕ} → (a <N b) → ((negSucc b) <Z negSucc a)
_<Z_.x (lessInheritsNegsucc {a} {b} (le x proof)) = x
_<Z_.proof (lessInheritsNegsucc {a} {b} (le x proof)) rewrite equalityCommutative proof = transitivity (transitivity (+ZCommutative (nonneg x) (negSucc (x +N a))) (applyEquality (λ i → negSucc i +Z nonneg x) (Semiring.commutative ℕSemiring x a))) (equalityCommutative (negSucc+Nonneg a x))

lessNegsuccNonneg : {a b : ℕ} → (negSucc a <Z nonneg b)
_<Z_.x (lessNegsuccNonneg {a} {b}) = a +N b
_<Z_.proof (lessNegsuccNonneg {zero} {b}) = refl
_<Z_.proof (lessNegsuccNonneg {succ a} {b}) = _<Z_.proof (lessNegsuccNonneg {a} {b})

lessThanTotalZ : {a b : ℤ} → ((a <Z b) || (b <Z a)) || (a ≡ b)
lessThanTotalZ {nonneg a} {nonneg b} with TotalOrder.totality ℕTotalOrder a b
lessThanTotalZ {nonneg a} {nonneg b} | inl (inl a<b) = inl (inl (lessInherits a<b))
lessThanTotalZ {nonneg a} {nonneg b} | inl (inr b<a) = inl (inr (lessInherits b<a))
lessThanTotalZ {nonneg a} {nonneg b} | inr a=b = inr (applyEquality nonneg a=b)
lessThanTotalZ {nonneg a} {negSucc b} = inl (inr (lessNegsuccNonneg {b} {a}))
lessThanTotalZ {negSucc a} {nonneg x} = inl (inl (lessNegsuccNonneg {a} {x}))
lessThanTotalZ {negSucc a} {negSucc b} with TotalOrder.totality ℕTotalOrder a b
... | inl (inl a<b) = inl (inr (lessInheritsNegsucc a<b))
... | inl (inr b<a) = inl (inl (lessInheritsNegsucc b<a))
lessThanTotalZ {negSucc a} {negSucc .a} | inr refl = inr refl

ℤOrder : TotalOrder ℤ
PartialOrder._<_ (TotalOrder.order ℤOrder) = _<Z_
PartialOrder.irreflexive (TotalOrder.order ℤOrder) {a} = irreflexive a
PartialOrder.<Transitive (TotalOrder.order ℤOrder) = lessZTransitive
TotalOrder.totality ℤOrder a b = lessThanTotalZ {a} {b}

orderRespectsAddition : (a b : ℤ) → a <Z b → (c : ℤ) → a +Z c <Z b +Z c
orderRespectsAddition (nonneg a) (nonneg b) (le x proof) (nonneg c) = le x (transitivity (+ZAssociative (nonneg (succ x)) (nonneg a) (nonneg c)) (applyEquality (_+Z nonneg c) proof))
orderRespectsAddition (nonneg a) (nonneg b) (le x proof) (negSucc c) = le x (transitivity (+ZAssociative (nonneg (succ x)) (nonneg a) (negSucc c)) (applyEquality (_+Z negSucc c) proof))
orderRespectsAddition (negSucc a) (nonneg b) (le x proof) (nonneg c) = le x (transitivity (+ZAssociative (nonneg (succ x)) (negSucc a) (nonneg c)) (applyEquality (_+Z nonneg c) proof))
orderRespectsAddition (negSucc a) (nonneg b) (le x proof) (negSucc c) = le x (transitivity (+ZAssociative (nonneg (succ x)) (negSucc a) (negSucc c)) (applyEquality (_+Z negSucc c) proof))
orderRespectsAddition (negSucc a) (negSucc b) (le x proof) (nonneg c) = le x (transitivity (+ZAssociative (nonneg (succ x)) (negSucc a) (nonneg c)) (applyEquality (_+Z nonneg c) proof))
orderRespectsAddition (negSucc a) (negSucc b) (le x proof) (negSucc c) = le x (transitivity (+ZAssociative (nonneg (succ x)) (negSucc a) (negSucc c)) (applyEquality (_+Z negSucc c) proof))

orderRespectsMultiplication : (a b : ℤ) → nonneg 0 <Z a → nonneg 0 <Z b → nonneg 0 <Z a *Z b
orderRespectsMultiplication (nonneg (succ a)) (nonneg (succ b)) 0<a 0<b = lessInherits (succIsPositive (b +N a *N succ b))

ℤPOrderedRing : PartiallyOrderedRing ℤRing (SetoidTotalOrder.partial (totalOrderToSetoidTotalOrder ℤOrder))
PartiallyOrderedRing.orderRespectsAddition ℤPOrderedRing {a} {b} = orderRespectsAddition a b
PartiallyOrderedRing.orderRespectsMultiplication ℤPOrderedRing {a} {b} = orderRespectsMultiplication a b

ℤOrderedRing : TotallyOrderedRing ℤPOrderedRing
TotallyOrderedRing.total ℤOrderedRing = totalOrderToSetoidTotalOrder ℤOrder


module examplesPaperJFP.StackBisim where

open import Data.Product
open import Function
open import Data.Nat.Base as N
open import Data.Vec as Vec using (Vec; []; _∷_; head; tail)

open import Relation.Binary.PropositionalEquality

open import examplesPaperJFP.StatefulObject

module _ {S : Set} {M : S → Set}  {R : (s : S)  →  (m : M s)  →  Set} {next : (s : S)  →  (m : M s)  →  R s m → S} (let

  I  = record { Stateˢ = S; Methodˢ = M; Resultˢ = R; nextˢ = next }
 ) (let
  O = Objectˢ I

    ) where
module Bisim (I : Interfaceˢ)
  (let S    = Stateˢ  I)
  (let M    = Methodˢ I)
  (let R    = Resultˢ I)
  (let next = nextˢ I)
  (let O    = Objectˢ I) where

  data  ΣR     {A : Set} {B : A → Set} (R : ∀{a} (b b′ : B a) → Set)
               :  (p p′ : Σ[ a ∈ A ] B a) → Set
        where
        eqΣ    :  ∀{a}{b b′ : B a} → R b b′ → ΣR R (a , b) (a , b′)

  record _≅_ {s : S} (o o′ : O s) : Set where
    coinductive
    field  bisimMethod  :  (m : M s) →
                           ΣR (_≅_) (objectMethod o m) (objectMethod o′ m)

  open _≅_ public

  refl≅ :  ∀{s} (o : O s) → o ≅ o
  bisimMethod (refl≅ o) m  =  let  (r , o′) =  objectMethod o m
                              in   eqΣ (refl≅ o′)

module _ {E : Set} where
  private
    I = StackInterfaceˢ E
    S = Stateˢ I
    O = Objectˢ I
  open Bisim I

  pop-after-push : ∀{n} {v : Vec E n} {e : E} →
    let  st          =  stack v
         (_ , st₁)   =  objectMethod  st   (push e)
         (e₂ , st₂)  =  objectMethod  st₁  pop

    in   (e ≡ e₂) × (st ≅ st₂)

  pop-after-push = refl , refl≅ _

  push-after-pop : ∀{n} {v : Vec E n} {e : E} →
    let  st            =  stack (e ∷ v)
         (e₁  ,  st₁)  =  objectMethod st   pop
         (_   ,  st₂)  =  objectMethod st₁  (push e₁)

    in   st ≅ st₂

  push-after-pop = refl≅ _

  tabulate  :  ∀ (n : ℕ) (f : ℕ → E) → Vec E n
  tabulate  0        f  =  []
  tabulate  (suc n)  f  =  f 0 ∷ tabulate n (f ∘ suc)

  stackF : ∀ (n : ℕ) (f : ℕ → E) → Objectˢ (StackInterfaceˢ E) n
  objectMethod  (stackF  n        f) (push e)  =  _    ,  stackF (suc n) λ
    {  0        →  e
    ;  (suc m)  →  f m    }
  objectMethod  (stackF  (suc n)  f) pop       =  f 0  ,  stackF n (f  ∘ suc)

  impl-bisim : ∀{n f} v (p : tabulate n f ≡ v) → stackF n f ≅ stack v

  bisimMethod (impl-bisim v        p) (push e) =
    eqΣ (impl-bisim (e ∷ v)  (cong (_∷_ e)  p))

  bisimMethod (impl-bisim (e ∷ v)  p) pop rewrite cong head p =
    eqΣ (impl-bisim v        (cong tail     p))


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

-- Category of Lawvere Theories

open import Level

open import Categories.Category.Core using (Category)
open import Categories.Functor.Cartesian using (CartesianF)
open import Categories.NaturalTransformation.NaturalIsomorphism
 using (_≃_; associator; sym-associator; unitorˡ; unitorʳ; unitor²; refl; sym; trans; _ⓘₕ_)
open import Categories.Theory.Lawvere using (LawvereTheory; LT-Hom; LT-id; LT-∘)

LawvereTheories : (ℓ e : Level) → Category (suc (ℓ ⊔ e)) (ℓ ⊔ e) (ℓ ⊔ e)
LawvereTheories ℓ e = record
  { Obj = LawvereTheory ℓ e
  ; _⇒_ = LT-Hom
  ; _≈_ = λ H₁ H₂ → cartF.F H₁ ≃ cartF.F H₂
  ; id = LT-id
  ; _∘_ = LT-∘
  ; assoc = λ { {f = f} {g} {h} → associator (cartF.F f) (cartF.F g) (cartF.F h) }
  ; sym-assoc = λ { {f = f} {g} {h} → sym-associator (cartF.F f) (cartF.F g) (cartF.F h) }
  ; identityˡ = unitorˡ
  ; identityʳ = unitorʳ
  ; identity² = unitor²
  ; equiv = record { refl = refl ; sym = sym ; trans = trans }
  ; ∘-resp-≈ = _ⓘₕ_
  }
  where open LT-Hom


------------------------------------------------------------------------------
-- Axiomatic Peano arithmetic base
------------------------------------------------------------------------------

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

module PA.Axiomatic.Standard.Base where

infixl 7 _*_
infixl 6 _+_

------------------------------------------------------------------------------
-- First-order logic with equality.
open import Common.FOL.FOL-Eq public renaming ( D to ℕ )

-- Common definitions.
open import Common.DefinitionsATP

-- Non-logical constants
postulate
  zero    : ℕ
  succ    : ℕ → ℕ
  _+_ _*_ : ℕ → ℕ → ℕ

-- Proper axioms
-- From (Machover 1996, p. 263) and (Hájek and Pudlák 1998, p. 28):
--
-- PA₁. 0 ≠ n'
-- PA₂. m' = n' → m = n
-- PA₃. 0 + n = n
-- PA₄. m' + n = (m + n)'
-- PA₅. 0 * n = 0
-- PA₆. m' * n = n + (m * n)
-- Axiom of induction:
-- φ(0) → (∀n.φ(n) → φ(succ n)) → ∀n.φ(n), for any formulae φ

postulate
  PA₁ : ∀ {n} → zero ≢ succ n
  PA₂ : ∀ {m n} → succ m ≡ succ n → m ≡ n
  PA₃ : ∀ n → zero + n ≡ n
  PA₄ : ∀ m n → succ m + n ≡ succ (m + n)
  PA₅ : ∀ n → zero * n ≡ zero
  PA₆ : ∀ m n → succ m * n ≡ n + m * n
{-# ATP axioms PA₁ PA₂ PA₃ PA₄ PA₅ PA₆ #-}

-- The axiom of induction is an axiom schema, therefore we do not
-- translate it to TPTP.
postulate
  ℕ-ind : (A : ℕ → Set) → A zero → (∀ n → A n → A (succ n)) → ∀ n → A n

------------------------------------------------------------------------------
-- References
--
-- Machover, Moshé (1996). Set theory, Logic and their
-- Limitations. Cambridge University Press.

-- Hájek, Petr and Pudlák, Pavel (1998). Metamathematics of
-- First-Order Arithmetic. 2nd printing. Springer.


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

module HoTT.Identity.Product where

open variables
private variable x y : A × B

_=×_ : A × B → A × B → 𝒰 _
x =× y = pr₁ x == pr₁ y × pr₂ x == pr₂ y

-- Theorem 2.6.2
=× : x == y ≃ x =× y
=× {x = _ , _} {_ , _} = let open Iso in iso→eqv λ where
  .f refl → refl , refl
  .g (refl , refl) → refl
  .η refl → refl
  .ε (refl , refl) → refl

module _ {x y : A × B} where
  open Iso (eqv→iso (=× {x = x} {y})) public
    renaming (f to =×-elim ; g to =×-intro ; η to =×-η ; ε to =×-β)

×-pair⁼ = =×-intro


------------------------------------------------------------------------------
-- Arithmetic properties used by the McCarthy 91 function
------------------------------------------------------------------------------

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

module FOTC.Program.McCarthy91.ArithmeticATP where

open import FOTC.Base
open import FOTC.Data.Nat
open import FOTC.Data.Nat.Inequalities
open import FOTC.Data.Nat.Inequalities.PropertiesATP
  using ( x≤y+x∸y
        ; x≤y→x≯y
        ; x≤y→x+k≤y+k
        )
open import FOTC.Data.Nat.PropertiesATP
  using ( +-N
        ; ∸-N
        ; +-comm
        ; [x+Sy]∸y≡Sx
        )
open import FOTC.Data.Nat.UnaryNumbers
open import FOTC.Data.Nat.UnaryNumbers.TotalityATP
  using ( 10-N
        ; 11-N
        ; 89-N
        ; 100-N
        )

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

postulate 91≡100+11∸10∸10 : 91' ≡ 100' + 11' ∸ 10' ∸ 10'
{-# ATP prove 91≡100+11∸10∸10 #-}

postulate
  100≡89+11  : 100' ≡ 89' + 11'
  101≡90+11  : 101' ≡ 90' + 11'
  102≡91+11  : 102' ≡ 91' + 11'
  103≡92+11  : 103' ≡ 92' + 11'
  104≡93+11  : 104' ≡ 93' + 11'
  105≡94+11  : 105' ≡ 94' + 11'
  106≡95+11  : 106' ≡ 95' + 11'
  107≡96+11  : 107' ≡ 96' + 11'
  108≡97+11  : 108' ≡ 97' + 11'
  109≡98+11  : 109' ≡ 98' + 11'
  110≡99+11  : 110' ≡ 99' + 11'
  111≡100+11 : 111' ≡ 100' + 11'
{-# ATP prove 100≡89+11 #-}
{-# ATP prove 101≡90+11 #-}
{-# ATP prove 102≡91+11 #-}
{-# ATP prove 103≡92+11 #-}
{-# ATP prove 104≡93+11 #-}
{-# ATP prove 105≡94+11 #-}
{-# ATP prove 106≡95+11 #-}
{-# ATP prove 107≡96+11 #-}
{-# ATP prove 108≡97+11 #-}
{-# ATP prove 109≡98+11 #-}
{-# ATP prove 110≡99+11 #-}
{-# ATP prove 111≡100+11 #-}

postulate 101≡100+11∸10 : 101' ≡ 100' + 11' ∸ 10'
{-# ATP prove 101≡100+11∸10 #-}

postulate
  100+11∸10>100 : 100' + 11' ∸ 10' > 100'
  100+11>100    : 100' + 11'       > 100'
{-# ATP prove 100+11∸10>100 101≡100+11∸10 #-}
{-# ATP prove 100+11>100 111≡100+11 #-}

postulate
  99+11>100 : 99' + 11' > 100'
  98+11>100 : 98' + 11' > 100'
  97+11>100 : 97' + 11' > 100'
  96+11>100 : 96' + 11' > 100'
  95+11>100 : 95' + 11' > 100'
  94+11>100 : 94' + 11' > 100'
  93+11>100 : 93' + 11' > 100'
  92+11>100 : 92' + 11' > 100'
  91+11>100 : 91' + 11' > 100'
  90+11>100 : 90' + 11' > 100'
{-# ATP prove 99+11>100 110≡99+11 #-}
{-# ATP prove 98+11>100 109≡98+11 #-}
{-# ATP prove 97+11>100 108≡97+11 #-}
{-# ATP prove 96+11>100 107≡96+11 #-}
{-# ATP prove 95+11>100 106≡95+11 #-}
{-# ATP prove 94+11>100 105≡94+11 #-}
{-# ATP prove 93+11>100 104≡93+11 #-}
{-# ATP prove 92+11>100 103≡92+11 #-}
{-# ATP prove 91+11>100 102≡91+11 #-}
{-# ATP prove 90+11>100 101≡90+11 #-}

x+11-N : ∀ {n} → N n → N (n + 11')
x+11-N Nn = +-N Nn 11-N

x+11∸10≡Sx : ∀ {n} → N n → n + 11' ∸ 10' ≡ succ₁ n
x+11∸10≡Sx Nn = [x+Sy]∸y≡Sx Nn 10-N

postulate x+1≤x∸10+11 : ∀ {n} → N n → n + 1' ≤ (n ∸ 10') + 11'
{-# ATP prove x+1≤x∸10+11 x≤y+x∸y 10-N 11-N +-N ∸-N +-comm #-}

postulate x≤89→x+11≯100 : ∀ {n} → N n → n ≤ 89' → n + 11' ≯ 100'
{-# ATP prove x≤89→x+11≯100 x≤y→x≯y x≤y→x+k≤y+k x+11-N 89-N 100-N 100≡89+11 #-}


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

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

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

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

open import Data.FingerTree.Measures ℳ
open import Data.FingerTree.Reasoning ℳ

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

open σ ⦃ ... ⦄

open Monoid ℳ renaming (Carrier to 𝓡)

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

infixr 5 _∣_
record _∣_ (left focus : 𝓡) : Set s where
  constructor ¬[_]ℙ[_]
  field
    ¬ℙ : ¬ ℙ left
    !ℙ : ℙ (left ∙ focus)
open _∣_ public

_∣?_ : ∀ x y → Dec (x ∣ y)
x ∣? y with ℙ? x
... | yes p = no λ c → ¬ℙ c p
... | no ¬p with ℙ? (x ∙ y)
... | no ¬c = no (¬c ∘ !ℙ)
... | yes p = yes ¬[ ¬p ]ℙ[ p ]

infixl 2 _≈◄⟅_⟆ _≈▻⟅_⟆ _≈⟅_∣_⟆ _◄_ _▻_
_◄_ : ∀ {l f₁ f₂} → l ∣ f₁ ∙ f₂ → ¬ ℙ (l ∙ f₁) → (l ∙ f₁) ∣ f₂
!ℙ (p ◄ ¬ℙf) = ℙ-resp (sym (assoc _ _ _)) (!ℙ p)
¬ℙ (p ◄ ¬ℙf) = ¬ℙf

_▻_ : ∀ {l f₁ f₂} → l ∣ f₁ ∙ f₂ → ℙ (l ∙ f₁) → l ∣ f₁
!ℙ (p ▻ ℙf) = ℙf
¬ℙ (p ▻ ℙf) = ¬ℙ p

_≈◄⟅_⟆ : ∀ {x y z} → x ∣ y → x ≈ z → z ∣ y
¬ℙ (x⟅y⟆ ≈◄⟅ x≈z ⟆) = ¬ℙ x⟅y⟆ ∘ ℙ-resp (sym x≈z)
!ℙ (x⟅y⟆ ≈◄⟅ x≈z ⟆) = ℙ-resp (≪∙ x≈z) (!ℙ x⟅y⟆)

_≈▻⟅_⟆ : ∀ {x y z} → x ∣ y → y ≈ z → x ∣ z
¬ℙ (x⟅y⟆ ≈▻⟅ y≈z ⟆) = ¬ℙ x⟅y⟆
!ℙ (x⟅y⟆ ≈▻⟅ y≈z ⟆) = ℙ-resp (∙≫ y≈z) (!ℙ x⟅y⟆)

_≈⟅_∣_⟆ : ∀ {x₁ y₁ x₂ y₂} → x₁ ∣ y₁ → x₁ ≈ x₂ → y₁ ≈ y₂ → x₂ ∣ y₂
¬ℙ (x⟅y⟆ ≈⟅ x≈ ∣ y≈ ⟆) = ¬ℙ x⟅y⟆ ∘ ℙ-resp (sym x≈)
!ℙ (x⟅y⟆ ≈⟅ x≈ ∣ y≈ ⟆) = ℙ-resp (∙-cong x≈ y≈) (!ℙ x⟅y⟆)

¬∄ℙ : ∀ {i} → ¬ (i ∣ ε)
¬∄ℙ i⟅ε⟆ = ¬ℙ i⟅ε⟆ (ℙ-resp (identityʳ _) (!ℙ i⟅ε⟆))


module Structure.Categorical.Names where

import      Lvl
open import Functional using (const ; swap)
open import Logic
open import Structure.Setoid
import      Structure.Operator.Names as Names
import      Structure.Relator.Names as Names
open import Type

private variable ℓₒ ℓₘ ℓₑ : Lvl.Level
private variable Obj : Type{ℓₒ}
private variable x y z w : Obj

-- Obj is the collection of objects.
-- _⟶_ is the collection of morphisms.
module _ (Morphism : Obj → Obj → Type{ℓₘ}) where
  -- A morphism is an endomorphism when the domain and the codomain are equal.
  -- Something which morphs itself (referring to the object).
  Endomorphism : Obj → Stmt{ℓₘ}
  Endomorphism a = Morphism a a

  module ArrowNotation where
    _⟶_ : Obj → Obj → Type{ℓₘ}
    _⟶_ = Morphism

    -- Reversed arrow
    _⟵_ : Obj → Obj → Type{ℓₘ}
    _⟵_ = swap(_⟶_)

    -- Self-pointing arrow
    ⟲_ : Obj → Type{ℓₘ}
    ⟲_ = Endomorphism

module Morphism where
  module _ (Morphism : Obj → Obj → Type{ℓₘ}) where
    open ArrowNotation(Morphism)

    -- The domain of a morphism
    dom : ∀{x y : Obj} → Morphism(x)(y) → Obj
    dom{x}{_} (_) = x

    -- The codomain of a morphism
    codom : ∀{x y : Obj} → Morphism(x)(y) → Obj
    codom{_}{y} (_) = y

  module _ {Morphism : Obj → Obj → Type{ℓₘ}} ⦃ equiv-morphism : ∀{x y} → Equiv{ℓₑ}(Morphism x y) ⦄ where
    open ArrowNotation(Morphism)

    module _ (_▫_ : Names.SwappedTransitivity(_⟶_)) where
      Associativity : Stmt
      Associativity = ∀{x y z w : Obj} → Names.AssociativityPattern {T₁ = z ⟶ w} {T₂ = y ⟶ z} {T₃ = x ⟶ y} (_▫_)(_▫_)(_▫_)(_▫_)

      Idempotent : (x ⟶ x) → Stmt
      Idempotent(f) = (f ▫ f ≡ f)

      module _ (id : Names.Reflexivity(_⟶_)) where
        Identityₗ : Stmt
        Identityₗ = ∀{x y}{f : x ⟶ y} → (id ▫ f ≡ f)

        Identityᵣ : Stmt
        Identityᵣ = ∀{x y}{f : x ⟶ y} → (f ▫ id ≡ f)

        Inverseₗ : (x ⟶ y) → (y ⟶ x) → Stmt
        Inverseₗ(f)(f⁻¹) = (f⁻¹ ▫ f ≡ id)

        Inverseᵣ : (x ⟶ y) → (y ⟶ x) → Stmt
        Inverseᵣ(f)(f⁻¹) = (f ▫ f⁻¹ ≡ id)

        Involution : (x ⟶ x) → Stmt
        Involution(f) = Inverseᵣ f f

module Polymorphism where
  module _ {Morphism : Obj → Obj → Type{ℓₘ}} ⦃ equiv-morphism : ∀{x y} → Equiv{ℓₑ}(Morphism x y) ⦄ where
    open ArrowNotation(Morphism)

    module _ (_▫_ : Names.SwappedTransitivity(_⟶_)) where
      IdempotentOn : Obj → Obj → (∀{x y} → (x ⟶ y)) → Stmt
      IdempotentOn(x)(z) (f) = ∀{y} → (f{y}{z} ▫ f{x}{y} ≡ f{x}{z})

      module _ (id : Names.Reflexivity(_⟶_)) where
        InvolutionOn : Obj → Obj → (∀{x y} → (x ⟶ y)) → Stmt
        InvolutionOn(x)(y) (f) = (f{x}{y} ▫ f{y}{x} ≡ id{y})

        Involution : (∀{x y} → (x ⟶ y)) → Stmt
        Involution(f) = ∀{x y} → InvolutionOn(x)(y)(f)


module Natural where

open import Equality
open import Cubical.Data.Nat.Properties public
open import Data.Empty
open import Data.Nat as ℕ public hiding (_+_; _*_; _^_)
open import Data.Nat.Properties public hiding (+-assoc; +-suc)
open import Data.Unit
open import Function
open import Syntax

instance
  ℕ-plus-syntax : plus-syntax-simple ℕ ℕ ℕ
  ℕ-plus-syntax = record { _+_ = ℕ._+_ }

  ℕ-times-syntax : times-syntax-simple ℕ ℕ ℕ
  ℕ-times-syntax = record { _*_ = ℕ._*_ }

  ℕ-raise-syntax : raise-syntax-simple ℕ ℕ ℕ
  ℕ-raise-syntax = record { _^_ = ℕ._^_ }

+-cross : (a b c d : ℕ) → (a + b) + (c + d) ≡ (a + c) + (b + d)
+-cross a b c d =
    (a + b) + (c + d)
  ≡⟨ sym (+-assoc a _ _) ⟩
    a + (b + (c + d))
  ≡⟨ cong (a +_) (+-assoc b _ _) ⟩
    a + ((b + c) + d)
  ≡⟨ cong (a +_) (cong (_+ d) ⟨ +-comm b c ⟩) ⟩
    a + ((c + b) + d)
  ≡⟨ cong (a +_) (sym (+-assoc c _ _)) ⟩
    a + (c + (b + d))
  ≡⟨ +-assoc a _ _ ⟩
    (a + c) + (b + d)
  ∎

instance
  ℕ-Number : Number ℕ
  ℕ-Number = record { Constraint = λ _ → ⊤ ; fromNat = λ x → x }


module QualifiedConstructors where

data Nat₁ : Set where
  zero : Nat₁
  suc  : Nat₁ → Nat₁

data Nat₂ : Set where
  zero : Nat₂
  suc  : Nat₂ → Nat₂

zero₁ = Nat₁.zero
one₂  = Nat₂.suc Nat₂.zero

record Suc : Set where
  constructor suc
  field n : Nat₁

one₃ = Suc.suc zero₁

pred : Suc → Nat₁
pred s = Suc.n s

conv : Nat₂ → Nat₁
conv Nat₂.zero    = Nat₁.zero
conv (Nat₂.suc n) = Nat₁.suc (conv n)

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

inj : (n m : Nat₁) → Nat₁.suc n ≡ suc m → n ≡ m
inj .m m refl = refl


module Formalization.LambdaCalculus.Semantics.CallByName where

import      Lvl
open import Data
open import Formalization.LambdaCalculus
open import Formalization.LambdaCalculus.Semantics
open import Formalization.LambdaCalculus.SyntaxTransformation
open import Logic.Predicate
open import Numeral.Natural
open import Syntax.Number
open import Type

private variable d db : ℕ
private variable f t x : Term(d)
private variable body : Term(db)
private variable v : ∃(Value)

data _⇓_ : Term(d) → ∃(Value) → Type{0} where
  value : ⦃ val : Value(t) ⦄ → (t ⇓ [∃]-intro t)
  apply : (f ⇓ [∃]-intro(Abstract body)) → (substituteVar0 x body ⇓ v) → (Apply f x ⇓ v)


{-# OPTIONS --allow-unsolved-metas #-}
module nat where

open import Data.Nat
open import Data.Nat.Properties
open import Data.Empty
open import Relation.Nullary
open import  Relation.Binary.PropositionalEquality
open import  Relation.Binary.Core
open import Relation.Binary.Definitions
open import  logic

nat-<> : { x y : ℕ } → x < y → y < x → ⊥
nat-<>  (s≤s x<y) (s≤s y<x) = nat-<> x<y y<x

nat-≤> : { x y : ℕ } → x ≤ y → y < x → ⊥
nat-≤>  (s≤s x<y) (s≤s y<x) = nat-≤> x<y y<x

nat-<≡ : { x : ℕ } → x < x → ⊥
nat-<≡  (s≤s lt) = nat-<≡ lt

nat-≡< : { x y : ℕ } → x ≡ y → x < y → ⊥
nat-≡< refl lt = nat-<≡ lt

¬a≤a : {la : ℕ} → suc la ≤ la → ⊥
¬a≤a  (s≤s lt) = ¬a≤a  lt

a<sa : {la : ℕ} → la < suc la
a<sa {zero} = s≤s z≤n
a<sa {suc la} = s≤s a<sa

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

a≤sa : {x : ℕ } → x ≤ suc x
a≤sa {zero} = z≤n
a≤sa {suc x} = s≤s (a≤sa {x})

=→¬< : {x : ℕ  } → ¬ ( x < x )
=→¬< {zero} ()
=→¬< {suc x} (s≤s lt) = =→¬< lt

>→¬< : {x y : ℕ  } → (x < y ) → ¬ ( y < x )
>→¬< (s≤s x<y) (s≤s y<x) = >→¬< x<y y<x

<-∨ : { x y : ℕ } → x < suc y → ( (x ≡ y ) ∨ (x < y) )
<-∨ {zero} {zero} (s≤s z≤n) = case1 refl
<-∨ {zero} {suc y} (s≤s lt) = case2 (s≤s z≤n)
<-∨ {suc x} {zero} (s≤s ())
<-∨ {suc x} {suc y} (s≤s lt) with <-∨ {x} {y} lt
<-∨ {suc x} {suc y} (s≤s lt) | case1 eq = case1 (cong (λ k → suc k ) eq)
<-∨ {suc x} {suc y} (s≤s lt) | case2 lt1 = case2 (s≤s lt1)

n≤n : (n : ℕ) →  n Data.Nat.≤ n
n≤n zero = z≤n
n≤n (suc n) = s≤s (n≤n n)

<→m≤n : {m n : ℕ} → m  < n →  m Data.Nat.≤ n
<→m≤n {zero} lt = z≤n
<→m≤n {suc m} {zero} ()
<→m≤n {suc m} {suc n} (s≤s lt) = s≤s (<→m≤n lt)

max : (x y : ℕ) → ℕ
max zero zero = zero
max zero (suc x) = (suc x)
max (suc x) zero = (suc x)
max (suc x) (suc y) = suc ( max x y )

-- _*_ : ℕ → ℕ → ℕ
-- _*_ zero _ = zero
-- _*_ (suc n) m = m + ( n * m )

exp : ℕ → ℕ → ℕ
exp _ zero = 1
exp n (suc m) = n * ( exp n m )

minus : (a b : ℕ ) →  ℕ
minus a zero = a
minus zero (suc b) = zero
minus (suc a) (suc b) = minus a b

_-_ = minus

m+= : {i j  m : ℕ } → m + i ≡ m + j → i ≡ j
m+= {i} {j} {zero} refl = refl
m+= {i} {j} {suc m} eq = m+= {i} {j} {m} ( cong (λ k → pred k ) eq )

+m= : {i j  m : ℕ } → i + m ≡ j + m → i ≡ j
+m= {i} {j} {m} eq = m+= ( subst₂ (λ j k → j ≡ k ) (+-comm i _ ) (+-comm j _ ) eq )

less-1 :  { n m : ℕ } → suc n < m → n < m
less-1 {zero} {suc (suc _)} (s≤s (s≤s z≤n)) = s≤s z≤n
less-1 {suc n} {suc m} (s≤s lt) = s≤s (less-1 {n} {m} lt)

sa=b→a<b :  { n m : ℕ } → suc n ≡ m → n < m
sa=b→a<b {0} {suc zero} refl = s≤s z≤n
sa=b→a<b {suc n} {suc (suc n)} refl = s≤s (sa=b→a<b refl)

minus+n : {x y : ℕ } → suc x > y  → minus x y + y ≡ x
minus+n {x} {zero} _ = trans (sym (+-comm zero  _ )) refl
minus+n {zero} {suc y} (s≤s ())
minus+n {suc x} {suc y} (s≤s lt) = begin
           minus (suc x) (suc y) + suc y
        ≡⟨ +-comm _ (suc y)    ⟩
           suc y + minus x y
        ≡⟨ cong ( λ k → suc k ) (
           begin
                 y + minus x y
              ≡⟨ +-comm y  _ ⟩
                 minus x y + y
              ≡⟨ minus+n {x} {y} lt ⟩
                 x
           ∎
           ) ⟩
           suc x
        ∎  where open ≡-Reasoning

sn-m=sn-m : {m n : ℕ } →  m ≤ n → suc n - m ≡ suc ( n - m )
sn-m=sn-m {0} {n} z≤n = refl
sn-m=sn-m {suc m} {suc n} (s≤s m<n) = sn-m=sn-m m<n

si-sn=i-n : {i n : ℕ } → n < i  → suc (i - suc n) ≡ (i - n)
si-sn=i-n {i} {n} n<i = begin
   suc (i - suc n) ≡⟨ sym (sn-m=sn-m n<i )  ⟩
   suc i - suc n ≡⟨⟩
   i - n
   ∎  where
      open ≡-Reasoning

n-m<n : (n m : ℕ ) →  n - m ≤ n
n-m<n zero zero = z≤n
n-m<n (suc n) zero = s≤s (n-m<n n zero)
n-m<n zero (suc m) = z≤n
n-m<n (suc n) (suc m) = ≤-trans (n-m<n n m ) refl-≤s

n-n-m=m : {m n : ℕ } → m ≤ n  → m ≡ (n - (n - m))
n-n-m=m {0} {zero} z≤n = refl
n-n-m=m {0} {suc n} z≤n = n-n-m=m {0} {n} z≤n
n-n-m=m {suc m} {suc n} (s≤s m≤n) = sym ( begin
   suc n - ( n - m )    ≡⟨ sn-m=sn-m (n-m<n  n m) ⟩
   suc (n - ( n - m ))  ≡⟨ cong (λ k → suc k ) (sym (n-n-m=m m≤n)) ⟩
   suc m
   ∎  ) where
      open ≡-Reasoning

0<s : {x : ℕ } → zero < suc x
0<s {_} = s≤s z≤n

<-minus-0 : {x y z : ℕ } → z + x < z + y → x < y
<-minus-0 {x} {suc _} {zero} lt = lt
<-minus-0 {x} {y} {suc z} (s≤s lt) = <-minus-0 {x} {y} {z} lt

<-minus : {x y z : ℕ } → x + z < y + z → x < y
<-minus {x} {y} {z} lt = <-minus-0 ( subst₂ ( λ j k → j < k ) (+-comm x _) (+-comm y _ ) lt )

x≤x+y : {z y : ℕ } → z ≤ z + y
x≤x+y {zero} {y} = z≤n
x≤x+y {suc z} {y} = s≤s  (x≤x+y {z} {y})

<-plus : {x y z : ℕ } → x < y → x + z < y + z
<-plus {zero} {suc y} {z} (s≤s z≤n) = s≤s (subst (λ k → z ≤ k ) (+-comm z _ ) x≤x+y  )
<-plus {suc x} {suc y} {z} (s≤s lt) = s≤s (<-plus {x} {y} {z} lt)

<-plus-0 : {x y z : ℕ } → x < y → z + x < z + y
<-plus-0 {x} {y} {z} lt = subst₂ (λ j k → j < k ) (+-comm _ z) (+-comm _ z) ( <-plus {x} {y} {z} lt )

≤-plus : {x y z : ℕ } → x ≤ y → x + z ≤ y + z
≤-plus {0} {y} {zero} z≤n = z≤n
≤-plus {0} {y} {suc z} z≤n = subst (λ k → z < k ) (+-comm _ y ) x≤x+y
≤-plus {suc x} {suc y} {z} (s≤s lt) = s≤s ( ≤-plus {x} {y} {z} lt )

≤-plus-0 : {x y z : ℕ } → x ≤ y → z + x ≤ z + y
≤-plus-0 {x} {y} {zero} lt = lt
≤-plus-0 {x} {y} {suc z} lt = s≤s ( ≤-plus-0 {x} {y} {z} lt )

x+y<z→x<z : {x y z : ℕ } → x + y < z → x < z
x+y<z→x<z {zero} {y} {suc z} (s≤s lt1) = s≤s z≤n
x+y<z→x<z {suc x} {y} {suc z} (s≤s lt1) = s≤s ( x+y<z→x<z {x} {y} {z} lt1 )

*≤ : {x y z : ℕ } → x ≤ y → x * z ≤ y * z
*≤ lt = *-mono-≤ lt ≤-refl

*< : {x y z : ℕ } → x < y → x * suc z < y * suc z
*< {zero} {suc y} lt = s≤s z≤n
*< {suc x} {suc y} (s≤s lt) = <-plus-0 (*< lt)

<to<s : {x y  : ℕ } → x < y → x < suc y
<to<s {zero} {suc y} (s≤s lt) = s≤s z≤n
<to<s {suc x} {suc y} (s≤s lt) = s≤s (<to<s {x} {y} lt)

<tos<s : {x y  : ℕ } → x < y → suc x < suc y
<tos<s {zero} {suc y} (s≤s z≤n) = s≤s (s≤s z≤n)
<tos<s {suc x} {suc y} (s≤s lt) = s≤s (<tos<s {x} {y} lt)

≤to< : {x y  : ℕ } → x < y → x ≤ y
≤to< {zero} {suc y} (s≤s z≤n) = z≤n
≤to< {suc x} {suc y} (s≤s lt) = s≤s (≤to< {x} {y}  lt)

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

open import Data.Product

minus<=0 : {x y : ℕ } → x ≤ y → minus x y ≡ 0
minus<=0 {0} {zero} z≤n = refl
minus<=0 {0} {suc y} z≤n = refl
minus<=0 {suc x} {suc y} (s≤s le) = minus<=0 {x} {y} le

minus>0 : {x y : ℕ } → x < y → 0 < minus y x
minus>0 {zero} {suc _} (s≤s z≤n) = s≤s z≤n
minus>0 {suc x} {suc y} (s≤s lt) = minus>0 {x} {y} lt

distr-minus-* : {x y z : ℕ } → (minus x y) * z ≡ minus (x * z) (y * z)
distr-minus-* {x} {zero} {z} = refl
distr-minus-* {x} {suc y} {z} with <-cmp x y
distr-minus-* {x} {suc y} {z} | tri< a ¬b ¬c = begin
          minus x (suc y) * z
        ≡⟨ cong (λ k → k * z ) (minus<=0 {x} {suc y} (x<y→≤ a)) ⟩
           0 * z
        ≡⟨ sym (minus<=0 {x * z} {z + y * z} le ) ⟩
          minus (x * z) (z + y * z)
        ∎  where
            open ≡-Reasoning
            le : x * z ≤ z + y * z
            le  = ≤-trans lemma (subst (λ k → y * z ≤ k ) (+-comm _ z ) (x≤x+y {y * z} {z} ) ) where
               lemma : x * z ≤ y * z
               lemma = *≤ {x} {y} {z} (≤to< a)
distr-minus-* {x} {suc y} {z} | tri≈ ¬a refl ¬c = begin
          minus x (suc y) * z
        ≡⟨ cong (λ k → k * z ) (minus<=0 {x} {suc y} refl-≤s ) ⟩
           0 * z
        ≡⟨ sym (minus<=0 {x * z} {z + y * z} (lt {x} {z} )) ⟩
          minus (x * z) (z + y * z)
        ∎  where
            open ≡-Reasoning
            lt : {x z : ℕ } →  x * z ≤ z + x * z
            lt {zero} {zero} = z≤n
            lt {suc x} {zero} = lt {x} {zero}
            lt {x} {suc z} = ≤-trans lemma refl-≤s where
               lemma : x * suc z ≤   z + x * suc z
               lemma = subst (λ k → x * suc z ≤ k ) (+-comm _ z) (x≤x+y {x * suc z} {z})
distr-minus-* {x} {suc y} {z} | tri> ¬a ¬b c = +m= {_} {_} {suc y * z} ( begin
           minus x (suc y) * z + suc y * z
        ≡⟨ sym (proj₂ *-distrib-+ z  (minus x (suc y) )  _) ⟩
           ( minus x (suc y) + suc y ) * z
        ≡⟨ cong (λ k → k * z) (minus+n {x} {suc y} (s≤s c))  ⟩
           x * z
        ≡⟨ sym (minus+n {x * z} {suc y * z} (s≤s (lt c))) ⟩
           minus (x * z) (suc y * z) + suc y * z
        ∎ ) where
            open ≡-Reasoning
            lt : {x y z : ℕ } → suc y ≤ x → z + y * z ≤ x * z
            lt {x} {y} {z} le = *≤ le

minus- : {x y z : ℕ } → suc x > z + y → minus (minus x y) z ≡ minus x (y + z)
minus- {x} {y} {z} gt = +m= {_} {_} {z} ( begin
           minus (minus x y) z + z
        ≡⟨ minus+n {_} {z} lemma ⟩
           minus x y
        ≡⟨ +m= {_} {_} {y} ( begin
              minus x y + y
           ≡⟨ minus+n {_} {y} lemma1 ⟩
              x
           ≡⟨ sym ( minus+n {_} {z + y} gt ) ⟩
              minus x (z + y) + (z + y)
           ≡⟨ sym ( +-assoc (minus x (z + y)) _  _ ) ⟩
              minus x (z + y) + z + y
           ∎ ) ⟩
           minus x (z + y) + z
        ≡⟨ cong (λ k → minus x k + z ) (+-comm _ y )  ⟩
           minus x (y + z) + z
        ∎  ) where
             open ≡-Reasoning
             lemma1 : suc x > y
             lemma1 = x+y<z→x<z (subst (λ k → k < suc x ) (+-comm z _ ) gt )
             lemma : suc (minus x y) > z
             lemma = <-minus {_} {_} {y} ( subst ( λ x → z + y < suc x ) (sym (minus+n {x} {y}  lemma1 ))  gt )

minus-* : {M k n : ℕ } → n < k  → minus k (suc n) * M ≡ minus (minus k n * M ) M
minus-* {zero} {k} {n} lt = begin
           minus k (suc n) * zero
        ≡⟨ *-comm (minus k (suc n)) zero ⟩
           zero * minus k (suc n)
        ≡⟨⟩
           0 * minus k n
        ≡⟨ *-comm 0 (minus k n) ⟩
           minus (minus k n * 0 ) 0
        ∎  where
        open ≡-Reasoning
minus-* {suc m} {k} {n} lt with <-cmp k 1
minus-* {suc m} {.0} {zero} lt | tri< (s≤s z≤n) ¬b ¬c = refl
minus-* {suc m} {.0} {suc n} lt | tri< (s≤s z≤n) ¬b ¬c = refl
minus-* {suc zero} {.1} {zero} lt | tri≈ ¬a refl ¬c = refl
minus-* {suc (suc m)} {.1} {zero} lt | tri≈ ¬a refl ¬c = minus-* {suc m} {1} {zero} lt
minus-* {suc m} {.1} {suc n} (s≤s ()) | tri≈ ¬a refl ¬c
minus-* {suc m} {k} {n} lt | tri> ¬a ¬b c = begin
           minus k (suc n) * M
        ≡⟨ distr-minus-* {k} {suc n} {M}  ⟩
           minus (k * M ) ((suc n) * M)
        ≡⟨⟩
           minus (k * M ) (M + n * M  )
        ≡⟨ cong (λ x → minus (k * M) x) (+-comm M _ ) ⟩
           minus (k * M ) ((n * M) + M )
        ≡⟨ sym ( minus- {k * M} {n * M} (lemma lt) ) ⟩
           minus (minus (k * M ) (n * M)) M
        ≡⟨ cong (λ x → minus x M ) ( sym ( distr-minus-* {k} {n} )) ⟩
           minus (minus k n * M ) M
        ∎  where
             M = suc m
             lemma : {n k m : ℕ } → n < k  → suc (k * suc m) > suc m + n * suc m
             lemma {zero} {suc k} {m} (s≤s lt) = s≤s (s≤s (subst (λ x → x ≤ m + k * suc m) (+-comm 0 _ ) x≤x+y ))
             lemma {suc n} {suc k} {m} lt = begin
                         suc (suc m + suc n * suc m)
                      ≡⟨⟩
                         suc ( suc (suc n) * suc m)
                      ≤⟨ ≤-plus-0 {_} {_} {1} (*≤ lt ) ⟩
                         suc (suc k * suc m)
                      ∎   where open ≤-Reasoning
             open ≡-Reasoning

open import Data.List

ℕL-inject : {h h1 : ℕ } {x y : List ℕ } → h ∷ x ≡ h1 ∷ y → h ≡ h1
ℕL-inject refl = refl

ℕL-inject-t : {h h1 : ℕ } {x y : List ℕ } → h ∷ x ≡ h1 ∷ y → x ≡ y
ℕL-inject-t refl = refl

ℕL-eq? : (x y : List ℕ ) → Dec (x ≡ y )
ℕL-eq? [] [] = yes refl
ℕL-eq? [] (x ∷ y) = no (λ ())
ℕL-eq? (x ∷ x₁) [] = no (λ ())
ℕL-eq? (h ∷ x) (h1 ∷ y) with h ≟ h1 | ℕL-eq? x y
... | yes y1 | yes y2 = yes ( cong₂ (λ j k → j ∷ k ) y1 y2 )
... | yes y1 | no n = no (λ e → n (ℕL-inject-t e))
... | no n  | t = no (λ e → n (ℕL-inject e))


{-# OPTIONS --cubical --safe #-}
module Cubical.HITs.Pushout.Base where

open import Cubical.Core.Glue

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

open import Cubical.Data.Unit

open import Cubical.HITs.Susp

data Pushout {ℓ ℓ' ℓ''} {A : Type ℓ} {B : Type ℓ'} {C : Type ℓ''}
             (f : A → B) (g : A → C) : Type (ℓ-max ℓ (ℓ-max ℓ' ℓ'')) where
  inl : B → Pushout f g
  inr : C → Pushout f g
  push : (a : A) → inl (f a) ≡ inr (g a)

-- Suspension defined as a pushout

PushoutSusp : ∀ {ℓ} (A : Type ℓ) → Type ℓ
PushoutSusp A = Pushout {A = A} {B = Unit} {C = Unit} (λ _ → tt) (λ _ → tt)

PushoutSusp→Susp : ∀ {ℓ} {A : Type ℓ} → PushoutSusp A → Susp A
PushoutSusp→Susp (inl _) = north
PushoutSusp→Susp (inr _) = south
PushoutSusp→Susp (push a i) = merid a i

Susp→PushoutSusp : ∀ {ℓ} {A : Type ℓ} → Susp A → PushoutSusp A
Susp→PushoutSusp north = inl tt
Susp→PushoutSusp south = inr tt
Susp→PushoutSusp (merid a i) = push a i

Susp→PushoutSusp→Susp : ∀ {ℓ} {A : Type ℓ} (x : Susp A) →
                        PushoutSusp→Susp (Susp→PushoutSusp x) ≡ x
Susp→PushoutSusp→Susp north = refl
Susp→PushoutSusp→Susp south = refl
Susp→PushoutSusp→Susp (merid _ _) = refl

PushoutSusp→Susp→PushoutSusp : ∀ {ℓ} {A : Type ℓ} (x : PushoutSusp A) →
                               Susp→PushoutSusp (PushoutSusp→Susp x) ≡ x
PushoutSusp→Susp→PushoutSusp (inl _) = refl
PushoutSusp→Susp→PushoutSusp (inr _) = refl
PushoutSusp→Susp→PushoutSusp (push _ _) = refl

PushoutSusp≃Susp : ∀ {ℓ} {A : Type ℓ} → PushoutSusp A ≃ Susp A
PushoutSusp≃Susp = isoToEquiv (iso PushoutSusp→Susp Susp→PushoutSusp Susp→PushoutSusp→Susp PushoutSusp→Susp→PushoutSusp)

PushoutSusp≡Susp : ∀ {ℓ} {A : Type ℓ} → PushoutSusp A ≡ Susp A
PushoutSusp≡Susp = isoToPath (iso PushoutSusp→Susp Susp→PushoutSusp Susp→PushoutSusp→Susp PushoutSusp→Susp→PushoutSusp)


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

open import HoTT
open import homotopy.Freudenthal

module homotopy.IterSuspensionStable where

{- π (S k) (Ptd-Susp^ (S n) X) == π k (Ptd-Susp^ n X), where k = S k'
   Susp^Stable below assumes k ≠ O instead of taking k' as the argument -}
module Susp^StableSucc {i} (k n : ℕ) (Skle : S k ≤ n *2)
  (X : Ptd i) {{_ : is-connected ⟨ n ⟩ (de⊙ X)}} where

  {- some numeric computations -}
  private
    Skle' : ⟨ S k ⟩ ≤T ⟨ n ⟩₋₁ +2+ ⟨ n ⟩₋₁
    Skle' = ≤T-trans (⟨⟩-monotone-≤ Skle) (inl (lemma n))
      where lemma : (n : ℕ) → ⟨ n *2 ⟩ == ⟨ n ⟩₋₁ +2+ ⟨ n ⟩₋₁
            lemma O = idp
            lemma (S n') = ap S (ap S (lemma n')
                                 ∙ ! (+2+-βr ⟨ S n' ⟩₋₂ ⟨ S n' ⟩₋₂))

  private
    module F = FreudenthalIso
      ⟨ n ⟩₋₂ k Skle' X

  stable : πS (S k) (⊙Susp X) ≃ᴳ πS k X
  stable =
    πS (S k) (⊙Susp X)
      ≃ᴳ⟨ πS-Ω-split-iso k (⊙Susp X) ⟩
    πS k (⊙Ω (⊙Susp X))
      ≃ᴳ⟨ Ω^S-group-Trunc-fuse-diag-iso k (⊙Ω (⊙Susp X)) ⁻¹ᴳ ⟩
    Ω^S-group k (⊙Trunc ⟨ S k ⟩ (⊙Ω (⊙Susp X)))
      ≃ᴳ⟨ F.iso ⁻¹ᴳ ⟩
    Ω^S-group k (⊙Trunc ⟨ S k ⟩ X)
      ≃ᴳ⟨ Ω^S-group-Trunc-fuse-diag-iso k X ⟩
    πS k X ≃ᴳ∎


open import Data.Product using ( _×_ )
open import Web.Semantic.DL.Signature using ( Signature ; CN ; RN )

module Web.Semantic.DL.FOL where

-- A fragment of first order logic with no existentials or disjunctions.

infixr 4 _∧_

data Formula (Σ : Signature) (Δ : Set) : Set where
  true : Formula Σ Δ
  false : Formula Σ Δ
  _∧_ : Formula Σ Δ → Formula Σ Δ → Formula Σ Δ
  _∈₁_ : Δ → CN Σ → Formula Σ Δ
  _∈₁_⇒_ : Δ → CN Σ → Formula Σ Δ → Formula Σ Δ
  _∈₂_ : (Δ × Δ) → RN Σ → Formula Σ Δ
  _∈₂_⇒_ : (Δ × Δ) → RN Σ → Formula Σ Δ → Formula Σ Δ
  _∼_ : Δ → Δ → Formula Σ Δ
  _∼_⇒_ : Δ → Δ → Formula Σ Δ → Formula Σ Δ
  ∀₁ : (Δ → Formula Σ Δ) → Formula Σ Δ


------------------------------------------------------------------------
-- The Agda standard library
--
-- Unsigned divisibility
------------------------------------------------------------------------
-- For signed divisibility see `Data.Integer.Divisibility.Signed`

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

module Data.Integer.Divisibility where

open import Function
open import Data.Integer
open import Data.Integer.Properties
import Data.Nat as ℕ
import Data.Nat.Properties as ℕᵖ
import Data.Nat.Divisibility as ℕᵈ
import Data.Nat.Coprimality as ℕᶜ
open import Level
open import Relation.Binary
open import Relation.Binary.PropositionalEquality

------------------------------------------------------------------------
-- Divisibility

infix 4 _∣_

_∣_ : Rel ℤ 0ℓ
_∣_ = ℕᵈ._∣_ on ∣_∣

open ℕᵈ public using (divides)

------------------------------------------------------------------------
-- Properties of divisibility

*-monoʳ-∣ : ∀ k → (k *_) Preserves _∣_ ⟶ _∣_
*-monoʳ-∣ k {i} {j} i∣j = begin
  ∣ k * i ∣       ≡⟨ abs-*-commute k i ⟩
  ∣ k ∣ ℕ.* ∣ i ∣ ∣⟨ ℕᵈ.*-cong ∣ k ∣ i∣j ⟩
  ∣ k ∣ ℕ.* ∣ j ∣ ≡⟨ sym (abs-*-commute k j) ⟩
  ∣ k * j ∣       ∎
  where open ℕᵈ.∣-Reasoning

*-monoˡ-∣ : ∀ k → (_* k) Preserves _∣_ ⟶ _∣_
*-monoˡ-∣ k {i} {j}
  rewrite *-comm i k
        | *-comm j k
        = *-monoʳ-∣ k

*-cancelˡ-∣ : ∀ k {i j} → k ≢ + 0 → k * i ∣ k * j → i ∣ j
*-cancelˡ-∣ k {i} {j} k≢0 k*i∣k*j = ℕᵈ./-cong (ℕ.pred ∣ k ∣) $ begin
  let ∣k∣-is-suc = ℕᵖ.m≢0⇒suc[pred[m]]≡m (k≢0 ∘ ∣n∣≡0⇒n≡0) in
  ℕ.suc (ℕ.pred ∣ k ∣) ℕ.* ∣ i ∣ ≡⟨ cong (ℕ._* ∣ i ∣) (∣k∣-is-suc) ⟩
  ∣ k ∣ ℕ.* ∣ i ∣                ≡⟨ sym (abs-*-commute k i) ⟩
  ∣ k * i ∣                      ∣⟨ k*i∣k*j ⟩
  ∣ k * j ∣                      ≡⟨ abs-*-commute k j ⟩
  ∣ k ∣ ℕ.* ∣ j ∣                ≡⟨ cong (ℕ._* ∣ j ∣) (sym ∣k∣-is-suc) ⟩
  ℕ.suc (ℕ.pred ∣ k ∣) ℕ.* ∣ j ∣ ∎
  where open ℕᵈ.∣-Reasoning

*-cancelʳ-∣ : ∀ k {i j} → k ≢ + 0 → i * k ∣ j * k → i ∣ j
*-cancelʳ-∣ k {i} {j} ≢0 = *-cancelˡ-∣ k ≢0 ∘
  subst₂ _∣_ (*-comm i k) (*-comm j k)


module product-thms where

open import eq
open import level
open import product
open import unit
open import functions

-- this is called the inspect idiom, in the Agda stdlib
keep : ∀{ℓ}{A : Set ℓ} → (x : A) → Σ A (λ y → x ≡ y)
keep x = ( x , refl )

,inj : ∀{ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'}{a a' : A}{b b' : B} →
        (a , b) ≡ (a' , b') → (a ≡ a') ∧ (b ≡ b')
,inj refl = refl , refl

eta-× : ∀{ℓ₁ ℓ₂ ℓ₃}{A : Set ℓ₁}{B : Set ℓ₂}{C : Set ℓ₃}{h : A × B → C}
  → (extensionality {ℓ₁ ⊔ ℓ₂}{ℓ₃})
  → (λ c → h (fst c , snd c)) ≡ h
eta-× {A = A}{B}{C}{h} ext = ext eta-×-aux
 where
   eta-×-aux : ∀{a : Σ A (λ x → B)} → h (fst a , snd a) ≡ h a
   eta-×-aux {(a , b)} = refl

eq-× : ∀{ℓ₁ ℓ₂}{A : Set ℓ₁}{B : Set ℓ₂}{a a' : A}{b b' : B}
  → a ≡ a'
  → b ≡ b'
  → (a , b) ≡ (a' , b')
eq-× refl refl = refl

twist-×-iso : ∀{ℓ : level}{U V : Set ℓ}{a : U × V} → (twist-× ∘ twist-×) a ≡ id a
twist-×-iso {a  = u , v} = refl

-- This module proves typical isomorphisms about ∧.
module ∧-Isos where
  postulate ext-set : ∀{l1 l2 : level} → extensionality {l1} {l2}

  ∧-unit-l : ∀{ℓ}{A : Set ℓ} → A → A ∧ (⊤ {ℓ})
  ∧-unit-l x = x , triv

  ∧-unit-r : ∀{ℓ}{A : Set ℓ} → A → ⊤ ∧ A
  ∧-unit-r x = twist-× (∧-unit-l x)

  ∧-unit-l-iso : ∀{ℓ}{A : Set ℓ} → Iso A (A ∧ ⊤)
  ∧-unit-l-iso {_}{A} = isIso ∧-unit-l fst refl (ext-set aux)
   where
    aux : {a : A ∧ ⊤} → (fst a , triv) ≡ a
    aux {x , triv} = refl

  ∧-unit-r-iso : ∀{ℓ}{A : Set ℓ} → Iso A (⊤ ∧ A)
  ∧-unit-r-iso {_}{A} = isIso ∧-unit-r snd refl (ext-set aux)
   where
    aux : {a : ⊤ ∧ A} → (triv , snd a) ≡ a
    aux {triv , x} = refl

  ∧-assoc₁ : ∀{ℓ}{A B C : Set ℓ} → (A ∧ (B ∧ C)) → ((A ∧ B) ∧ C)
  ∧-assoc₁ (a , b , c) = ((a , b) , c)

  ∧-assoc₂ : ∀{ℓ}{A B C : Set ℓ} → ((A ∧ B) ∧ C) → (A ∧ (B ∧ C))
  ∧-assoc₂ ((a , b) , c) = (a , b , c)

  ∧-assoc-iso : ∀{ℓ}{A B C : Set ℓ} → Iso (A ∧ (B ∧ C)) ((A ∧ B) ∧ C)
  ∧-assoc-iso {_}{A}{B}{C} = isIso ∧-assoc₁ ∧-assoc₂ (ext-set aux₁) (ext-set aux₂)
   where
    aux₁ : {a : A ∧ (B ∧ C)} → ∧-assoc₂ (∧-assoc₁ a) ≡ a
    aux₁ {a , (b , c)} = refl

    aux₂ : {a : (A ∧ B) ∧ C} → ∧-assoc₁ (∧-assoc₂ a) ≡ a
    aux₂ {(a , b) , c} = refl


data Nat : Set where
  zero : Nat
  suc : Nat → Nat

plus : Nat → Nat → Nat
plus zero b = b
plus (suc a) b = suc (plus a b)

infixl 6 _+_
_+_ = plus

{-# DISPLAY suc n = 1 + n #-}
{-# DISPLAY plus a b = a + b #-}

postulate
  T : {A : Set} → A → Set

test₁ : ∀ a b → T (plus (suc a) b)
test₁ a b = {!!}

data Vec (A : Set) : Nat → Set where
  []  : Vec A zero
  _∷_ : ∀ {n} → A → Vec A n → Vec A (suc n)

data List A : Set where
  []  : List A
  _∷_ : A → List A → List A

infixr 4 _∷_

[_] : ∀ {A} → A → Vec A (suc zero)
[ x ] = x ∷  []

{-# DISPLAY Vec._∷_ x Vec.[] = [ x ] #-}

test₂ : (n : Nat) → T (n Vec.∷ [])
test₂ n = {!!}

append : ∀ {A : Set} {n m} → Vec A n → Vec A m → Vec A (n + m)
append []       ys = ys
append (x ∷ xs) ys = x ∷ append xs ys

infixr 4 _++_
_++_ = append

{-# DISPLAY append xs ys = xs ++ ys #-}
{-# DISPLAY append xs (y Vec.∷ ys) = xs ++ [ y ] ++ ys #-}

test₃ : ∀ {n} (xs ys : Vec Nat n) → T (append xs (n ∷ ys))
test₃ {n} xs ys = {!!}


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

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism
open import Cubical.Data.Nat
open import Cubical.Data.NatPlusOne.Base

1+Path : ℕ ≡ ℕ₊₁
1+Path = isoToPath (iso 1+_ -1+_ (λ _ → refl) (λ _ → refl))


open import Category

module Iso (ℂ : Cat) where

private open module C = Cat (η-Cat ℂ)

data _≅_ (A B : Obj) : Set where
  iso : (i : A ─→ B)(j : B ─→ A) ->
	i ∘ j == id -> j ∘ i == id ->
	A ≅ B


open import Agda.Primitive
open import Agda.Builtin.Nat

-- Named implicit function types

postulate
  T : Set → Set → Set
  foo : {A = X : Set} {B : Set} → T X B
  bar : ∀ {A = X} {B} → T X B

foo₁ : (X : Set) → T X X
foo₁ X = foo {A = X} {B = X}

bar₁ : ∀ X → T X X
bar₁ X = bar {A = X} {B = X}

Id : {A = _ : Set} → Set
Id {A = X} = X

Id₁ : Set → Set
Id₁ X = Id {A = X}

-- With blanks

postulate
  namedUnused   : {A = _ : Set} → Set
  unnamedUsed   : {_ = X : Set} → X → X
  unnamedUnused : {_ = _ : Set} → Set

_ : Set
_ = namedUnused {A = Nat}

_ : Nat → Nat
_ = unnamedUsed {Nat} -- can't give by name

_ : Set
_ = unnamedUnused {Nat}

-- In left-hand sides

id : {A = X : Set} → X → X
id {A = Y} x = x

-- In with-functions

with-fun : ∀ {A} {B = X} → T A X → T A X
with-fun {A = A} {B = Z} x with T A Z
with-fun {B = Z} x | Goal = x

-- In datatypes

data List {ℓ = a} (A : Set a) : Set a where
  [] : List A
  _∷_ : A → List A → List A

List₁ = List {ℓ = lsuc lzero}

-- In module telescopes

module Named {A : Set} {B = X : Set} where
   postulate H : X → A

h : (A : Set) → A → A
h A = Named.H {A = A} {B = A}

postulate
  X : Set

open Named {A = X} {B = X}

hh : X → X
hh = H

-- Constructors

data Q (n : Nat) : Set where
  mkQ : Q n

data E {n = x} (q : Q x) : Set where
  mkE : E q

e₁ : (q : Q 1) → E q
e₁ q = mkE {n = 1} {q = q}

-- Generalized variables

variable
  m n : Nat

q₁ = mkQ {n = 1}

data D (x : Q n) : Q m → Set where
  refl : {y = z : Q m} → D x z

D₁  = D {n = 1}
D₁₂ = λ x → D {n = 1} x {m = 2}

refl′ = λ x → refl {n = 1} {x = x} {m = 2} {y = mkQ}


{-# OPTIONS --cubical --safe --postfix-projections #-}

-- This file contains an implementation of the stack-based compiler for Hutton's
-- razor, as from:
--
--   P. Bahr and G. Hutton, “Calculating correct compilers,” Journal of
--   Functional Programming, vol. 25, no. e14, Sep. 2015,
--   doi: 10.1017/S0956796815000180.
--
-- The compiler is total and the evaluator is stack-safe, and furthermore we have
-- proven a full isomorphism between the code representation and the AST.

module Data.Dyck.Prog where

open import Prelude
open import Data.Nat using (_+_)

private variable n : ℕ

--------------------------------------------------------------------------------
-- We have 2 forms that we want to convert between: an AST and a flat code.
--------------------------------------------------------------------------------

data Expr : Type where
  [_] : ℕ → Expr
  _⊕_ : Expr → Expr → Expr

--------------------------------------------------------------------------------
-- We do the conversion with cayley forms of the dyck monoids
--------------------------------------------------------------------------------

⟨_⟩_↝_ : (ℕ → Type) → ℕ → ℕ → Type
⟨ C ⟩ n ↝ m = ∀ {i} → C (n + i) → C (m + i)

--------------------------------------------------------------------------------
-- An encoding of an AST
--------------------------------------------------------------------------------

data Code : ℕ → Type where
  HALT : Code 1
  PUSH : ℕ → ⟨ Code ⟩ 1 ↝ 0
  ADD  :     ⟨ Code ⟩ 1 ↝ 2

--------------------------------------------------------------------------------
-- We will need a stack (a snoc-list)
--------------------------------------------------------------------------------

Stack : Type → ℕ → Type
Stack A zero    = ⊤
Stack A (suc n) = Stack A n × A

infixl 5 _∷_
pattern _∷_ xs x = xs , x

foldl : (P : ℕ → Type) → (A → ⟨ P ⟩ 1 ↝ 0) → Stack A n → P n → P zero
foldl {n = zero}  P f tt       = id
foldl {n = suc n} P f (xs ∷ x) = foldl P f xs ∘ f x

private variable st : Stack Expr n

--------------------------------------------------------------------------------
-- Conversion to and from code
--------------------------------------------------------------------------------

--            Code n → ⟨ Stack Expr ⟩ n ↝ 1
code→expr⊙ : Code n → Stack Expr n → Expr
code→expr⊙ HALT        (tt ∷ e)       = e
code→expr⊙ (PUSH v is) st             = code→expr⊙ is (st ∷ [ v ])
code→expr⊙ (ADD is)    (st ∷ xs ∷ ys) = code→expr⊙ is (st ∷ xs ⊕ ys)

code→expr : Code 0 → Expr
code→expr ds = code→expr⊙ ds tt

expr→code⊙ : Expr → ⟨ Code ⟩ 1 ↝ 0
expr→code⊙ [ x ]     = PUSH x
expr→code⊙ (xs ⊕ ys) = expr→code⊙ xs ∘ expr→code⊙ ys ∘ ADD

expr→code : Expr → Code 0
expr→code xs = expr→code⊙ xs HALT

--------------------------------------------------------------------------------
-- Proof of isomorphism
--------------------------------------------------------------------------------

expr→code→expr⊙ : {is : Code (1 + n)} (e : Expr) →
  code→expr⊙ (expr→code⊙ e is) st ≡ code→expr⊙ is (st ∷ e)
expr→code→expr⊙ [ x ]     = refl
expr→code→expr⊙ (xs ⊕ ys) = expr→code→expr⊙ xs ; expr→code→expr⊙ ys

code→expr→code⊙ : (is : Code n) →
 expr→code (code→expr⊙ is st) ≡ foldl Code expr→code⊙ st is
code→expr→code⊙  HALT       = refl
code→expr→code⊙ (PUSH i is) = code→expr→code⊙ is
code→expr→code⊙ (ADD    is) = code→expr→code⊙ is

prog-iso : Code 0 ⇔ Expr
prog-iso .fun = code→expr
prog-iso .inv = expr→code
prog-iso .rightInv = expr→code→expr⊙
prog-iso .leftInv  = code→expr→code⊙


{-
  Define finitely generated ideals of commutative rings and
  show that they are an ideal.
  Parts of this should be reusable for explicit constructions
  of free modules over a finite set.
-}
{-# OPTIONS --safe #-}
module Cubical.Algebra.CommRing.FGIdeal where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.Transport
open import Cubical.Foundations.HLevels

open import Cubical.Data.Sigma
open import Cubical.Data.FinData hiding (elim ; rec)
open import Cubical.Data.Nat renaming ( zero to ℕzero ; suc to ℕsuc
                                      ; _+_ to _+ℕ_ ; _·_ to _·ℕ_
                                      ; +-assoc to +ℕ-assoc ; +-comm to +ℕ-comm
                                      ; ·-assoc to ·ℕ-assoc ; ·-comm to ·ℕ-comm)
                             hiding (elim)
open import Cubical.HITs.PropositionalTruncation

open import Cubical.Algebra.CommRing
open import Cubical.Algebra.CommRing.Ideal
open import Cubical.Algebra.Ring.QuotientRing
open import Cubical.Algebra.Ring.Properties
open import Cubical.Algebra.Ring.BigOps
open import Cubical.Algebra.RingSolver.ReflectionSolving
open import Cubical.Algebra.Matrix

private
  variable
    ℓ : Level

module _ (Ring@(R , str) : CommRing ℓ) where
  infixr 5 _holds
  _holds : hProp ℓ → Type ℓ
  P holds = fst P
  open CommRingStr str
  open RingTheory (CommRing→Ring Ring)
  open Sum (CommRing→Ring Ring)

  linearCombination : {n : ℕ} → FinVec R n → FinVec R n → R
  linearCombination α V = ∑ (λ i → α i · V i)

  sumDist+ : ∀ {n : ℕ} (α β V : FinVec R n)
           → linearCombination (λ i → α i + β i) V ≡ linearCombination α V + linearCombination β V
  sumDist+ α β V = ∑Ext (λ i → ·Ldist+ (α i) (β i) (V i)) ∙ ∑Split (λ i → α i · V i) (λ i → β i · V i)

  dist- : ∀ {n : ℕ} (α V : FinVec R n)
        → linearCombination (λ i → - α i) V ≡ - linearCombination α V
  dist- α V = ∑Ext (λ i → -DistL· (α i) (V i)) ∙ ∑Dist- (λ i → α i · V i)

  dist0 : ∀ {n : ℕ} (V : FinVec R n)
        → linearCombination (replicateFinVec n 0r) V ≡ 0r
  dist0 {n = n} V = ∑Ext (λ i → 0LeftAnnihilates (V i)) ∙ ∑0r n

  isLinearCombination : {n : ℕ} → FinVec R n → R → Type ℓ
  isLinearCombination V x = ∃[ α ∈ FinVec R _ ] x ≡ linearCombination α V

  {- If x and y are linear combinations of l, then (x + y) is
     a linear combination. -}
  isLinearCombination+ : {n : ℕ} {x y : R} (V : FinVec R n)
                         → isLinearCombination V x
                         → isLinearCombination V y
                         → isLinearCombination V (x + y)
  isLinearCombination+ V = map2 λ α β → (λ i → α .fst i + β .fst i)
                                       , cong₂ (_+_) (α .snd) (β .snd) ∙ sym (sumDist+ _ _ V)

  {- If x is a linear combinations of l, then -x is
     a linear combination. -}
  isLinearCombination- : {n : ℕ} {x : R} (V : FinVec R n)
                       → isLinearCombination V x → isLinearCombination V (- x)
  isLinearCombination- V = map λ α → (λ i → - α .fst i) , cong (-_) (α .snd) ∙ sym (dist- _ V)

  {- 0r is the trivial linear Combination -}
  isLinearCombination0 : {n : ℕ} (V : FinVec R n)
                       → isLinearCombination V 0r
  isLinearCombination0 V = ∣ _ , sym (dist0 V) ∣

  {- Linear combinations are stable under left multiplication -}
  isLinearCombinationL· : {n : ℕ} (V : FinVec R n) (r : R) {x : R}
                        → isLinearCombination V x → isLinearCombination V (r · x)
  isLinearCombinationL· V r = map λ α → (λ i → r · α .fst i) , cong (r ·_) (α .snd)
                                                            ∙∙ ∑Mulrdist r (λ i → α .fst i · V i)
                                                            ∙∙ ∑Ext λ i → ·Assoc r (α .fst i) (V i)

  generatedIdeal : {n : ℕ} → FinVec R n → IdealsIn Ring
  generatedIdeal V = makeIdeal Ring
                               (λ x → isLinearCombination V x , isPropPropTrunc)
                               (isLinearCombination+ V)
                               (isLinearCombination0 V)
                               λ r → isLinearCombinationL· V r

open CommIdeal.isCommIdeal
genIdeal : {n : ℕ} (R : CommRing ℓ) → FinVec (fst R) n → CommIdeal.CommIdeal R
fst (genIdeal R V) x = isLinearCombination R V x , isPropPropTrunc
+Closed (snd (genIdeal R V)) = isLinearCombination+ R V
contains0 (snd (genIdeal R V)) = isLinearCombination0 R V
·Closed (snd (genIdeal R V)) r = isLinearCombinationL· R V r

syntax genIdeal R V = ⟨ V ⟩[ R ]

FGIdealIn : (R : CommRing ℓ) → Type (ℓ-suc ℓ)
FGIdealIn R = Σ[ I ∈ CommIdeal.CommIdeal R ]
                   ∃[ nV ∈ Σ[ n ∈ ℕ ] FinVec (fst R) n ] I ≡ ⟨ nV .snd ⟩[ R ]

-- The lattice laws
module _ (R' : CommRing ℓ) where
 open CommRingStr (snd R')
 open RingTheory (CommRing→Ring R')
 open CommIdeal R'
 open Sum (CommRing→Ring R')
 open KroneckerDelta (CommRing→Ring R')
 private
  R = fst R'
  ⟨_⟩ : {n : ℕ} → FinVec R n → CommIdeal
  ⟨ V ⟩ = ⟨ V ⟩[ R' ]

 inclOfFGIdeal : {n : ℕ} (V : FinVec R n) (I : CommIdeal)
     → (∀ i → V i ∈ I) → ⟨ V ⟩ ⊆ I
 inclOfFGIdeal V I ∀i→Vi∈I x = elim (λ _ → I .fst x .snd) inclOfFGIdealΣ
  where
  inclOfFGIdealΣ : Σ[ α ∈ FinVec R _ ] x ≡ linearCombination R' α V → x ∈ I
  inclOfFGIdealΣ (α , x≡α·V) = subst-∈ I (sym x≡α·V) (∑Closed I (λ i → α i · V i)
                             λ i → ·Closed (I .snd) _ (∀i→Vi∈I i))

 indInIdeal : ∀ {n : ℕ} (U : FinVec R n) (i : Fin n) → U i ∈ ⟨ U ⟩
 indInIdeal U i = ∣ (δ i) , sym (∑Mul1r _ U i) ∣

 sucIncl : ∀ {n : ℕ} (U : FinVec R (ℕsuc n)) → ⟨ U ∘ suc ⟩ ⊆ ⟨ U ⟩
 sucIncl U x = map λ (α , x≡∑αUsuc) → (λ { zero → 0r ; (suc i) → α i }) , x≡∑αUsuc ∙ path _ _
  where
  path : ∀ s u₀ → s ≡ 0r · u₀ + s
  path = solve R'

 emptyFGIdeal : ∀ (V : FinVec R 0) → ⟨ V ⟩ ≡ 0Ideal
 emptyFGIdeal V = CommIdeal≡Char (λ _ →  rec (is-set _ _) snd)
                                 (λ _ x≡0 → ∣ (λ ()) , x≡0 ∣)

 0FGIdealLIncl : {n : ℕ} → ⟨ replicateFinVec n 0r ⟩ ⊆ 0Ideal
 0FGIdealLIncl x = elim (λ _ → is-set _ _)
         λ (α , x≡∑α0) → subst-∈ 0Ideal (sym x≡∑α0) (∑Closed 0Ideal (λ i → α i · 0r)
         λ i → subst-∈ 0Ideal (sym (0RightAnnihilates _)) refl)

 0FGIdealRIncl : {n : ℕ} → 0Ideal ⊆ ⟨ replicateFinVec n 0r ⟩
 0FGIdealRIncl x x≡0 = subst-∈ ⟨ replicateFinVec _ 0r ⟩ (sym x≡0)
                        (⟨ replicateFinVec _ 0r ⟩ .snd .contains0)

 0FGIdeal : {n : ℕ} → ⟨ replicateFinVec n 0r ⟩ ≡ 0Ideal
 0FGIdeal = CommIdeal≡Char 0FGIdealLIncl 0FGIdealRIncl

 FGIdealAddLemmaLIncl : {n m : ℕ} (U : FinVec R n) (V : FinVec R m)
                      → ⟨ U ++Fin V ⟩ ⊆ (⟨ U ⟩ +i ⟨ V ⟩)
 FGIdealAddLemmaLIncl {n = ℕzero} U V x x∈⟨V⟩ =
                                  ∣ (0r , x) , ⟨ U ⟩ .snd .contains0 , x∈⟨V⟩ , sym (+Lid x) ∣
 FGIdealAddLemmaLIncl {n = ℕsuc n} U V x = rec isPropPropTrunc helperΣ
   where
   helperΣ : Σ[ α ∈ FinVec R _ ] (x ≡ ∑ λ i → α i · (U ++Fin V) i) → x ∈ (⟨ U ⟩ +i ⟨ V ⟩)
   helperΣ (α , p) = subst-∈ (⟨ U ⟩ +i ⟨ V ⟩) (sym p)
                              ((⟨ U ⟩ +i ⟨ V ⟩) .snd .+Closed zeroIncl sumIncl)
    where
    zeroIncl : (α zero · U zero) ∈ (⟨ U ⟩ +i ⟨ V ⟩)
    zeroIncl = +iLincl ⟨ U ⟩ ⟨ V ⟩ (α zero · U zero)
                 (⟨ U ⟩ .snd .·Closed (α zero) (indInIdeal U zero))

    sumIncl : (∑ λ i → (α ∘ suc) i · ((U ∘ suc) ++Fin V) i) ∈ (⟨ U ⟩ +i ⟨ V ⟩)
    sumIncl = let sum = ∑ λ i → (α ∘ suc) i · ((U ∘ suc) ++Fin V) i in
         +iRespLincl ⟨ U ∘ suc ⟩ ⟨ U ⟩ ⟨ V ⟩ (sucIncl U) sum
           (FGIdealAddLemmaLIncl (U ∘ suc) V _ ∣ (α ∘ suc) , refl ∣)

 FGIdealAddLemmaRIncl : {n m : ℕ} (U : FinVec R n) (V : FinVec R m)
                      → (⟨ U ⟩ +i ⟨ V ⟩) ⊆ ⟨ U ++Fin V ⟩
 FGIdealAddLemmaRIncl U V x = rec isPropPropTrunc (uncurry3 helper)
   where
   helperΣ : ((y , z) : R × R)
           → Σ[ α ∈ FinVec R _ ] (y ≡ ∑ λ i → α i · U i)
           → Σ[ β ∈ FinVec R _ ] (z ≡ ∑ λ i → β i · V i)
           → x ≡ y + z
           → x ∈ ⟨ U ++Fin V ⟩
   helperΣ (y , z) (α , y≡∑αU) (β , z≡∑βV) x≡y+z = ∣ (α ++Fin β) , path ∣
    where
    path : x ≡ ∑ λ i → (α ++Fin β) i · (U ++Fin V) i
    path = x                                               ≡⟨ x≡y+z ⟩
           y + z                                           ≡⟨ cong₂ (_+_) y≡∑αU z≡∑βV ⟩
           (∑ λ i → α i · U i) + (∑ λ i → β i · V i)       ≡⟨ sym (∑Split++ (λ i → α i · U i) _) ⟩
           (∑ ((λ i → α i · U i) ++Fin (λ i → β i · V i))) ≡⟨ ∑Ext (mul++dist α U β V) ⟩
           (∑ λ i → (α ++Fin β) i · (U ++Fin V) i)         ∎

   helper : ((y , z) : R × R)
          → ∃[ α ∈ FinVec R _ ] (y ≡ ∑ λ i → α i · U i)
          → ∃[ β ∈ FinVec R _ ] (z ≡ ∑ λ i → β i · V i)
          → x ≡ y + z
          → x ∈ ⟨ U ++Fin V ⟩
   helper _ = rec2 (isPropΠ (λ _ → isPropPropTrunc)) (helperΣ _)

 FGIdealAddLemma : {n m : ℕ} (U : FinVec R n) (V : FinVec R m)
                 → ⟨ U ++Fin V ⟩ ≡ ⟨ U ⟩ +i ⟨ V ⟩
 FGIdealAddLemma U V = CommIdeal≡Char (FGIdealAddLemmaLIncl U V) (FGIdealAddLemmaRIncl U V)

 IdealAddAssoc :  {n m k : ℕ} (U : FinVec R n) (V : FinVec R m) (W : FinVec R k)
               → ⟨ U ++Fin (V ++Fin W) ⟩ ≡  ⟨ (U ++Fin V) ++Fin W ⟩
 IdealAddAssoc {n = n} {m = m} {k = k} U V W =
   let genIdealExpl : (n : ℕ) → FinVec R n → CommIdeal
       genIdealExpl _ V = ⟨ V ⟩
   in  cong₂ genIdealExpl (+ℕ-assoc n m k) (++FinAssoc U V W)

 ++FinComm : ∀ {n m : ℕ} (V : FinVec R n) (W : FinVec R m)
           → ⟨ V ++Fin W ⟩ ≡ ⟨ W ++Fin V ⟩
 ++FinComm V W = FGIdealAddLemma V W ∙∙ +iComm ⟨ V ⟩ ⟨ W ⟩ ∙∙ sym (FGIdealAddLemma W V)

 open ProdFin R'
 prodIn··Ideal : {n m : ℕ} (U : FinVec R n) (V : FinVec R m) (x y : R)
          → (x ∈ ⟨ U ⟩) → (y ∈ ⟨ V ⟩) → (x · y) ∈ ⟨ U ··Fin V ⟩
 prodIn··Ideal {n = n} {m = m} U V x y = map2 Σhelper
  where
  Σhelper : Σ[ α ∈ FinVec R n ] x ≡ linearCombination R' α U
          → Σ[ β ∈ FinVec R m ] y ≡ linearCombination R' β V
          → Σ[ γ ∈ FinVec R (n ·ℕ m) ] (x · y) ≡ linearCombination R' γ (U ··Fin V)
  Σhelper (α , x≡∑αU) (β , y≡∑βV) = α ··Fin β , path
   where
   path : x · y ≡ ∑ λ i → (α ··Fin β) i · (U ··Fin V) i
   path = x · y ≡⟨ cong₂ (_·_) x≡∑αU y≡∑βV ⟩
          (∑ λ i → α i · U i) · (∑ λ i → β i · V i) ≡⟨ ∑Dist··Fin (λ i → α i · U i) _ ⟩
          (∑ λ j → ((λ i → α i · U i) ··Fin (λ i → β i · V i)) j) ≡⟨ ∑Ext (·Dist··Fin α U β V) ⟩
          (∑ λ i → (α ··Fin β) i · (U ··Fin V) i) ∎

 FGIdealMultLemmaLIncl : {n m : ℕ} (U : FinVec R n) (V : FinVec R m)
                       → ⟨ U ··Fin V ⟩ ⊆ (⟨ U ⟩ ·i ⟨ V ⟩)
 FGIdealMultLemmaLIncl U V x = elim (λ _ → isPropPropTrunc)
   λ (α , x≡∑αUV) → subst-∈ (⟨ U ⟩ ·i ⟨ V ⟩)  (sym x≡∑αUV) --replace x by ∑αᵢⱼUᵢVⱼ
     (∑Closed (⟨ U ⟩ ·i ⟨ V ⟩) (λ i → α i · (U ··Fin V) i) --show that each αᵢ(U··V)ᵢ is in product
       λ i → (⟨ U ⟩ ·i ⟨ V ⟩) .snd .·Closed (α i) --drop the α's
         (flattenElim {P = _∈ (⟨ U ⟩ ·i ⟨ V ⟩)} (toMatrix U V) --show theat UᵢVⱼ is in product
           (λ j k → prodInProd ⟨ U ⟩ ⟨ V ⟩ (U j) (V k) (indInIdeal U j) (indInIdeal V k)) i))

 FGIdealMultLemmaRIncl : {n m : ℕ} (U : FinVec R n) (V : FinVec R m)
                       → (⟨ U ⟩ ·i ⟨ V ⟩) ⊆ ⟨ U ··Fin V ⟩
 FGIdealMultLemmaRIncl U V x = elim (λ _ → isPropPropTrunc)
   λ (_ , (α , β) , ∀α∈⟨U⟩ , ∀β∈⟨V⟩ , x≡∑αβ) → subst-∈ ⟨ U ··Fin V ⟩ (sym x≡∑αβ)
     (∑Closed ⟨ U ··Fin V ⟩ _ (λ i → prodIn··Ideal U V (α i) (β i) (∀α∈⟨U⟩ i) (∀β∈⟨V⟩ i)))

 FGIdealMultLemma : {n m : ℕ} (U : FinVec R n) (V : FinVec R m)
                 → ⟨ U ··Fin V ⟩ ≡ ⟨ U ⟩ ·i ⟨ V ⟩
 FGIdealMultLemma U V = CommIdeal≡Char (FGIdealMultLemmaLIncl U V) (FGIdealMultLemmaRIncl U V)


module Automaton.NonDeterministic where

import      Lvl
open import Data.Boolean
import      Data.Boolean.Operators
open        Data.Boolean.Operators.Programming
open import Data.List using (List) renaming (∅ to ε ; _⊰_ to _·_)
open import Functional
open import Logic
open import Sets.ExtensionalPredicateSet
open import Structure.Setoid
open import Type

-- Non-deterministic Automata
-- `State`      (Q)  is the set of states.
-- `Alphabet`   (Σ)  is the set of symbols/the alphabet.
-- `transition` (δ)  is the transition function.
-- `start`      (q₀) is the start state.
-- `Final`      (F)  is the subset of State which are the final/accepting states.
record NonDeterministic {ℓₚ ℓₛ ℓₑ ℓₐ} (State : Type{ℓₛ}) ⦃ equiv-state : Equiv{ℓₑ}(State) ⦄ (Alphabet : Type{ℓₐ}) : Type{ℓₛ Lvl.⊔ ℓₑ Lvl.⊔ ℓₐ Lvl.⊔ Lvl.𝐒(ℓₚ)} where
  constructor nondeterministic
  field
    transition : State → Alphabet → PredSet{ℓₚ}(State)
    start      : State
    Final      : PredSet{ℓₚ}(State)

  Word = List(Alphabet)

  -- Chained transition using a word (list of characters).
  wordTransition : State → Word → PredSet{ℓₑ}(State)
  wordTransition initialState ε       = • initialState
  wordTransition initialState (a · l) = {!⋃ ?!} -- wordTransition (transition initialState a) l
{-
  module LetterNotation where
    Q  = State
    Σ  = Alphabet
    δ  = transition
    δ̂  = wordTransition
    q₀ = start
    F  = Final

  -- A word is accepted by the automaton when it can transition from the start state to a final state.
  AcceptsWord : Word → Stmt
  AcceptsWord = (_∈ Final) ∘ wordTransition start

  -- The subset of State which are the accessible states from the start state by chained transitions.
  Accessible : PredSet(State)
  Accessible = ⊶(wordTransition start)

  automatonTransition : Alphabet → NonDeterministic(State)(Alphabet)
  transition (automatonTransition _) = transition
  start      (automatonTransition c) = transition start c
  Final      (automatonTransition _) = Final

  automatonTransitionWord : Word → NonDeterministic(State)(Alphabet)
  transition (automatonTransitionWord _) = transition
  start      (automatonTransitionWord w) = wordTransition start w
  Final      (automatonTransitionWord _) = Final
-}


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

module Algebra.Construct.Free.Semilattice.Relation.Unary.All.Def where

open import Prelude hiding (⊥; ⊤)
open import Algebra.Construct.Free.Semilattice.Eliminators
open import Algebra.Construct.Free.Semilattice.Definition
open import Cubical.Foundations.HLevels
open import Data.Empty.UniversePolymorphic
open import HITs.PropositionalTruncation.Sugar
open import HITs.PropositionalTruncation.Properties
open import HITs.PropositionalTruncation
open import Data.Unit.UniversePolymorphic

private
  variable p : Level

dup-◻ : (P : A → Type p) → (x : A) (xs : Type p) → (∥ P x ∥ × ∥ P x ∥ × xs) ⇔ (∥ P x ∥ × xs)
dup-◻ P _ _ .fun = snd
dup-◻ P _ _ .inv (x , xs) = x , x , xs
dup-◻ P _ _ .rightInv (x , xs) = refl
dup-◻ P _ _ .leftInv  (x₁ , x₂ , xs) i .fst = squash x₂ x₁ i
dup-◻ P _ _ .leftInv  (x₁ , x₂ , xs) i .snd = (x₂ , xs)

com-◻ : (P : A → Type p) → (x y : A) (xs : Type p) → (∥ P x ∥ × ∥ P y ∥ × xs) ⇔ (∥ P y ∥ × ∥ P x ∥ × xs)
com-◻ P _ _ _ .fun (x , y , xs) = y , x , xs
com-◻ P _ _ _ .inv (y , x , xs) = x , y , xs
com-◻ P _ _ _ .leftInv  (x , y , xs) = refl
com-◻ P _ _ _ .rightInv (x , y , xs) = refl

◻′ : (P : A → Type p) → A ↘ hProp p
[ ◻′ P ]-set = isSetHProp
([ ◻′ P ] x ∷ (xs , hxs)) .fst = ∥ P x ∥ × xs
([ ◻′ P ] x ∷ (xs , hxs)) .snd y z = ΣProp≡ (λ _  → hxs) (squash (fst y) (fst z))
[ ◻′ P ][] = ⊤ , λ x y _ → x
[ ◻′ P ]-dup x xs = ΣProp≡ (λ _ → isPropIsProp) (isoToPath (dup-◻ P x (xs .fst)))
[ ◻′ P ]-com x y xs = ΣProp≡ (λ _ → isPropIsProp) (isoToPath (com-◻ P x y (xs .fst)))

◻ : (P : A → Type p) → 𝒦 A → Type p
◻ P xs = [ ◻′ P ]↓ xs .fst

isProp-◻ : ∀ {P : A → Type p} {xs} → isProp (◻ P xs)
isProp-◻ {P = P} {xs = xs} = [ ◻′ P ]↓ xs .snd


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

open import Types
open import Functions
open import Paths
open import HLevel
open import Equivalences

module FiberEquivalences {i j k} {A : Set i} {P : A → Set k} {Q : A → Set j}
  (f : (x : A) → (P x → Q x)) where

-- We want to prove that if [f] induces an equivalence on the total spaces,
-- then [f] induces an equivalence fiberwise

total-map : Σ A P → Σ A Q
total-map (x , y) = (x , f x y)

module TotalMapEquiv (e : is-equiv total-map) where

  total-equiv : Σ A P ≃ Σ A Q
  total-equiv = (total-map , e)

  -- The inverse is propositionally fiberwise
  base-path-inverse : (x : A) (y : Q x) → π₁ ((total-equiv ⁻¹) ☆ (x , y)) ≡ x
  base-path-inverse x y = base-path (inverse-right-inverse total-equiv (x , y))

  -- And the action of [total-map] on paths is correct on the base path
  total-map-fiberwise-on-paths : {u v : Σ A P} (p : u ≡ v)
    → base-path (ap total-map p) ≡ base-path p
  total-map-fiberwise-on-paths {u} {.u} refl = refl

  -- Here is the fiberwise inverse, we use the inverse of the total map and
  -- transform it into a fiberwise map using [base-path-inverse]
  inv : ((x : A) → (Q x → P x))
  inv x y = transport P (base-path-inverse x y)
                        (π₂ ((total-equiv ⁻¹) ☆ (x , y)))

  -- We prove that [inv] is a right and left inverse to [f]

  inv-right-inverse : (x : A) (y : Q x) → f x (inv x y) ≡ y
  inv-right-inverse x y =
    app-trans _ _ f (base-path (inverse-right-inverse total-equiv (x , y)))
              (π₂ (inverse (_ , e) (x , y)))
    ∘ fiber-path (inverse-right-inverse total-equiv (x , y))

  inv-left-inverse : (x : A) (y : P x) → inv x (f x y) ≡ y
  inv-left-inverse x y =
    ap (λ u → transport P (base-path (inverse-right-inverse total-equiv
                                                             (x , f x y))) u)
        (lemma2 x y)
    ∘ (! (trans-concat P (base-path (inverse-right-inverse total-equiv
                                                                 (x , f x y)))
                               (! (base-path-inverse x (f x y))) y)
    ∘ ap (λ p → transport P p y)
          (opposite-left-inverse (ap π₁
            (inverse-right-inverse total-equiv (x , f x y))))) where

    lemma1 : (x : A) (y : P x)
      → base-path-inverse x (f x y)
        ≡ base-path (inverse-left-inverse total-equiv (x , y))
    lemma1 x y = ap base-path (inverse-triangle total-equiv (x , y))
                 ∘ total-map-fiberwise-on-paths _

    lemma2 : (x : A) (y : P x)
      → π₂ ((total-equiv ⁻¹) ☆ (x , f x y))
        ≡ transport P (! (base-path-inverse x (f x y))) y
    lemma2 x y = ! (fiber-path (! (inverse-left-inverse total-equiv (x , y))))
      ∘ ap (λ p → transport P p y)
            (ap-opposite π₁ (inverse-left-inverse total-equiv (x , y))
            ∘ ! (ap ! (lemma1 x y)))

  fiberwise-is-equiv : ((x : A) → is-equiv (f x))
  fiberwise-is-equiv x = iso-is-eq (f x) (inv x) (inv-right-inverse x)
                                              (inv-left-inverse x)

fiberwise-is-equiv : is-equiv total-map → ((x : A) → is-equiv (f x))
fiberwise-is-equiv = TotalMapEquiv.fiberwise-is-equiv


module Data.Bin.Rec where

open import Data.Bin hiding (suc; fromℕ)
open import Induction.WellFounded

open import Data.Nat using (ℕ; zero; suc) renaming (_<_ to _ℕ<_)
open import Data.Nat.Properties

open import Relation.Binary.PropositionalEquality
open import Data.Bin.Bijection

import Induction.Nat

wf : Well-founded _<_
wf x = go' x where
  P : ℕ → Set
  P x = Acc _<_ (fromℕ x)

  podgon : ∀ {y} → P (toℕ y) → Acc _<_ y
  podgon = subst (λ q → Acc _<_ q) (fromToℕ-inverse _)

  go'' : (x : ℕ) → ((y : ℕ) → y ℕ< x → P y) → P x
  go'' x rec = acc (λ { y (less ty<tfx) → podgon (rec (toℕ y) (subst (λ q → toℕ y ℕ< q) (toFromℕ-inverse x) ty<tfx ) )})

  go : (x : ℕ) → P x
  go = Induction.Nat.<-rec P go''

  go' : (x : Bin) → Acc _<_ x
  go' x = podgon (go (toℕ x))

open All wf

rec : ∀ (P : Bin → Set) → ((a : Bin) → ((a' : Bin) → (a' < a) → P a') → P a) → (a : Bin) → P a
rec P f = wfRec _ P f


open import Relation.Binary.Core

module PLRTree.Insert.Properties {A : Set}
                     (_≤_ : A → A → Set)
                     (tot≤ : Total _≤_) where

open import Data.Sum
open import PLRTree {A}
open import PLRTree.Compound {A}
open import PLRTree.Insert _≤_ tot≤

lemma-insert-compound : (x : A)(t : PLRTree) → Compound (insert x t)
lemma-insert-compound x leaf = compound
lemma-insert-compound x (node perfect y l r)
    with tot≤ x y | l | r
... | inj₁ x≤y | leaf | leaf = compound
... | inj₁ x≤y | leaf | node _ _ _ _ = compound
... | inj₁ x≤y | node _ _ _ _ | leaf = compound
... | inj₁ x≤y | node _ _ _ _ | node _ _ _ _ = compound
... | inj₂ y≤x | leaf | leaf = compound
... | inj₂ y≤x | leaf | node _ _ _ _ = compound
... | inj₂ y≤x | node _ _ _ _ | leaf = compound
... | inj₂ y≤x | node _ _ _ _ | node _ _ _ _ = compound
lemma-insert-compound x (node left y l _)
    with tot≤ x y
... | inj₁ x≤y
    with insert y l | lemma-insert-compound y l
... | node perfect _ _ _ | compound = compound
... | node left _ _ _ | compound = compound
... | node right _ _ _ | compound = compound
lemma-insert-compound x (node left y l _) | inj₂ y≤x
    with insert x l | lemma-insert-compound x l
... | node perfect _ _ _ | compound = compound
... | node left _ _ _ | compound = compound
... | node right _ _ _ | compound = compound
lemma-insert-compound x (node right y _ r)
    with tot≤ x y
... | inj₁ x≤y
    with insert y r | lemma-insert-compound y r
... | node perfect _ _ _ | compound = compound
... | node left _ _ _ | compound = compound
... | node right _ _ _ | compound = compound
lemma-insert-compound x (node right y _ r) | inj₂ y≤x
    with insert x r | lemma-insert-compound x r
... | node perfect _ _ _ | compound = compound
... | node left _ _ _ | compound = compound
... | node right _ _ _ | compound = compound


module Type.Identity where

import      Lvl
open import Type

private variable ℓ : Lvl.Level
private variable T : Type{ℓ}

-- Identity type.
-- Also called: Propositional equality.
-- Two terms are identical/equal when their data representation are the same.
data Id {T : Type{ℓ}} : T → T → Type{ℓ} where
  instance intro : ∀{x : T} → Id x x
  -- Interpretation:
  --   The only way to construct something of type Id is to use identical objects for both arguments.
  --   When matching on the constructor, the type checker "unifies" the two terms making them the same.
  --   This is how the builtin pattern matching by intro works, and therefore many propositions for identity becomes "trivial" syntactically.

{-# BUILTIN EQUALITY Id #-}
{-# BUILTIN REWRITE  Id #-}

elim : (P : ∀{x y : T} → (Id x y) → Type{ℓ}) → (∀{x} → P(intro{x = x})) → (∀{x y} → (eq : (Id x y)) → P(eq))
elim _ p intro = p


import      Lvl

-- TODO: Is it possible formalize this like this? Is it even correct?

-- Based on http://www.maths.ed.ac.uk/~tl/edinburgh_yrm/ (2017-11-22)
module Sets.ETCS where

  open import Logic.Propositional

  module Theory (S : Set(Lvl.𝟎)) (F : S → S → Set(Lvl.𝟎)) (_∘_ : ∀{a b c} → F(b)(c) → F(a)(b) → F(a)(c)) (_≡_ : ∀{a b} → F(a)(b) → F(a)(b) → Stmt{Lvl.𝟎}) where
    open import Functional hiding (_∘_)
    open import Logic.Predicate{Lvl.𝟎}{Lvl.𝟎}
    open import Logic.Propositional.Theorems{Lvl.𝟎}
    open import Relator.Equals{Lvl.𝟎} using () renaming (_≡_ to _≡ᵣ_)
    open import Type{Lvl.𝟎}

    Terminal : S → Stmt
    Terminal(x) = (∀{a : S} → (f g : F(a)(x)) → (f ≡ g))

    record Axioms : Set(Lvl.𝐒(Lvl.𝟎)) where
      field
        associativity : ∀{a b c d : S}{f : F(a)(b)}{g : F(b)(c)}{h : F(c)(d)} → ((h ∘ (g ∘ f)) ≡ ((h ∘ g) ∘ f))
        identity : ∀{a : S} → ∃{F(a)(a)}(id ↦ (∀{b : S}{f : F(a)(b)} → ((f ∘ id) ≡ f)) ∧ (∀{b : S}{f : F(b)(a)} → ((id ∘ f) ≡ f)))
        terminal : ∃(term ↦ Terminal(term))

      𝟏 : S
      𝟏 = [∃]-witness(terminal)

      _∈_ : ∀{a b : S} → F(a)(b) → S → Stmt
      _∈_ {a}{b} x X = (a ≡ᵣ 𝟏)∧(b ≡ᵣ X)

      _∉_ : ∀{a b : S} → F(a)(b) → S → Stmt
      _∉_ x X = ¬(x ∈ X)

      field
        empty : ∃{S}(∅ ↦ ∀{a b : S}{f : F(a)(b)} → (f ∉ ∅))

      -- TODO

  module Construction where
    open import Data
    open import Functional using (_∘_ ; id)
    open import Logic.Predicate{Lvl.𝐒(Lvl.𝟎)}{Lvl.𝟎}
    open import Logic.Propositional.Theorems{Lvl.𝐒(Lvl.𝟎)}
    open import Relator.Equals{Lvl.𝟎}

    Terminal : Set → Stmt
    Terminal(x) = (∀{a : Set}{f g : a → x} → (f ≡ g))

    _∈_ : ∀{a b : Set} → (a → b) → Set → Stmt
    _∈_ {a}{b} _ X = (a ≡ Unit)∧(b ≡ X)

    ∅ : Set
    ∅ = Empty

    -- TODO: Maybe use FunctionEquals instead?
    -- TODO: Is this construction working? Try to prove some of the theorems of standard set theory


{-# OPTIONS --safe #-}
module Cubical.ZCohomology.Groups.Connected where

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

open import Cubical.Data.Nat
open import Cubical.Data.Int renaming (_+_ to _+ℤ_; +Comm to +ℤ-comm ; +Assoc to +ℤ-assoc)
open import Cubical.Data.Sigma hiding (_×_)

open import Cubical.HITs.SetTruncation as ST
open import Cubical.HITs.PropositionalTruncation as PT
open import Cubical.HITs.Truncation as T
open import Cubical.HITs.Nullification

open import Cubical.Algebra.Group
open import Cubical.Algebra.Group.Instances.Int
open import Cubical.Algebra.Group.Morphisms
open import Cubical.Algebra.Group.MorphismProperties

open import Cubical.Homotopy.Connected

open import Cubical.ZCohomology.Base
open import Cubical.ZCohomology.GroupStructure
open import Cubical.ZCohomology.Groups.Unit

private
  H⁰-connected-type : ∀ {ℓ} {A : Type ℓ} (a : A) → isConnected 2 A → Iso (coHom 0 A) ℤ
  Iso.fun (H⁰-connected-type a con) = ST.rec isSetℤ λ f → f a
  Iso.inv (H⁰-connected-type a con) b = ∣ (λ x → b) ∣₂
  Iso.rightInv (H⁰-connected-type a con) b = refl
  Iso.leftInv (H⁰-connected-type a con) =
    ST.elim (λ _ → isOfHLevelPath 2 isSetSetTrunc _ _)
           λ f → cong ∣_∣₂ (funExt λ x → T.rec₊ (isSetℤ _ _) (cong f) (isConnectedPath 1 con a x .fst))

open IsGroupHom
open Iso

H⁰-connected : ∀ {ℓ} {A : Type ℓ} (a : A) → ((x : A) → ∥ a ≡ x ∥₁) → GroupIso (coHomGr 0 A) ℤGroup
fun (fst (H⁰-connected a con)) = ST.rec isSetℤ (λ f → f a)
inv (fst (H⁰-connected a con)) b = ∣ (λ _ → b) ∣₂
rightInv (fst (H⁰-connected a con)) _ = refl
leftInv (fst (H⁰-connected a con)) =
  ST.elim (λ _ → isProp→isSet (isSetSetTrunc _ _))
        (λ f → cong ∣_∣₂ (funExt λ x → PT.rec (isSetℤ _ _) (cong f) (con x)))
snd (H⁰-connected a con) = makeIsGroupHom (ST.elim2 (λ _ _ → isProp→isSet (isSetℤ _ _)) λ x y → refl)


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

module Categories.Category.Instance.Properties.Cats where

open import Data.Product using (_,_)

open import Categories.Category
open import Categories.Category.Construction.Functors
  using (Functors; eval; module curry)
open import Categories.Category.Cartesian using (Cartesian)
import Categories.Category.CartesianClosed as CCC
import Categories.Category.CartesianClosed.Canonical as Canonical
open import Categories.Category.Instance.Cats using (Cats)
open import Categories.Category.Monoidal.Instance.Cats
open import Categories.Functor using (Functor; _∘F_) renaming (id to idF)
open import Categories.Functor.Bifunctor using (Bifunctor)
open import Categories.Functor.Construction.Constant using (constNat)
import Categories.Morphism.Reasoning as MR
open import Categories.NaturalTransformation
  using (NaturalTransformation; _∘ˡ_) renaming (id to idNT)
open import Categories.NaturalTransformation.NaturalIsomorphism
  using (NaturalIsomorphism; _≃_; module LeftRightId)

-- It's easier to define exponentials with respect to the *canonical*
-- product.  The more generic version can then be given by appealing
-- to uniqueness (up to iso) of products.

module CanonicallyCartesianClosed {l} where
  private
    module Cats = Category (Cats l l l)
    module Cart = Cartesian (Product.Cats-is {l} {l} {l})
  open Cats using (_⇒_) renaming (Obj to Cat)
  open Cart hiding (η)

  infixr 9 _^_

  _^_ : Cat → Cat → Cat
  B ^ A = Functors A B

  -- The β law (aka computation principle) for exponential objects

  eval-comp : ∀ {A B C} {G : C × A ⇒ B} → eval ∘F (curry.F₀ G ⁂ idF) ≃ G
  eval-comp {A} {B} {C} {G} = record
    { F⇒G = record
      { η           = λ _ → id B
      ; commute     = λ _ → ∘-resp-≈ʳ B commute ○ MR.id-comm-sym B
      ; sym-commute = λ _ → ⟺ (∘-resp-≈ʳ B commute ○ MR.id-comm-sym B)
      }
    ; F⇐G = record
      { η           = λ _ → id B
      ; commute     = λ _ → ⟺ (MR.id-comm B ○ ∘-resp-≈ʳ B commute)
      ; sym-commute = λ _ → MR.id-comm B ○ ∘-resp-≈ʳ B commute
      }
    ; iso = iso-id-id
    }
    where
      open Functor G renaming (F₀ to G₀; F₁ to G₁)
      open Category hiding (_∘_)
      open Category B using (_∘_)
      open HomReasoning B
      open LeftRightId G

      commute : ∀ {a₁ a₂ b₁ b₂} {f₁ : C [ a₁ , b₁ ]} {f₂ : A [ a₂ , b₂ ]} →
                B [ (G₁ (f₁ , id A) ∘ G₁ (id C , f₂)) ≈ G₁ (f₁ , f₂) ]
      commute {_} {_} {_} {_} {f₁} {f₂} = begin
          G₁ (f₁ , id A) ∘ G₁ (id C , f₂)
        ≈˘⟨ homomorphism ⟩
          G₁ (C [ f₁ ∘ id C ] , A [ id A ∘ f₂ ])
        ≈⟨ F-resp-≈ (identityʳ C , identityˡ A) ⟩
          G₁ (f₁ , f₂)
        ∎

  -- The η law (aka uniqueness principle) for exponential objects

  η-exp : ∀ {A B C} {H : C ⇒ B ^ A} → H ≃ curry.F₀ (eval ∘F (H ⁂ idF))
  η-exp {A} {B} {C} {H} = record
    { F⇒G = record
      { η = λ _ → record
        { η           = λ _ → id B
        ; commute     = λ f → ⟺ (MR.id-comm B ○ ∘-resp-≈ʳ B (commute₁ f))
        ; sym-commute = λ f → MR.id-comm B ○ ∘-resp-≈ʳ B (commute₁ f)
        }
      ; commute       = λ f → ⟺ (MR.id-comm B ○ ∘-resp-≈ʳ B (commute₂ f))
      ; sym-commute   = λ f → MR.id-comm B ○ ∘-resp-≈ʳ B (commute₂ f)
      }
    ; F⇐G = record
      { η = λ _ → record
        { η           = λ _ → id B
        ; commute     = λ f → ∘-resp-≈ʳ B (commute₁ f) ○ MR.id-comm-sym B
        ; sym-commute = λ f → ⟺ (∘-resp-≈ʳ B (commute₁ f) ○ MR.id-comm-sym B)
        }
      ; commute       = λ f → ∘-resp-≈ʳ B (commute₂ f) ○ MR.id-comm-sym B
      ; sym-commute   = λ f → ⟺ (∘-resp-≈ʳ B (commute₂ f) ○ MR.id-comm-sym B)
      }
    ; iso = λ _ → record { isoˡ = identity² B; isoʳ = identity² B }
    }
    where
      open Functor using (identity) renaming (F₁ to _$₁_)
      open Functor H hiding (identity) renaming (F₀ to H₀; F₁ to H₁)
      open Category hiding (_∘_)
      open Category B using (_∘_)
      open HomReasoning B
      open NaturalTransformation
      open LeftRightId H

      commute₁ : ∀ {a b c} (f : A [ a , b ]) →
                 B [ (η (H₁ (id C)) b ∘ (H₀ c $₁ f)) ≈ H₀ c $₁ f ]
      commute₁ {_} {b} {c} f = begin
        η (H₁ (id C)) b ∘ (H₀ c $₁ f)  ≈⟨ ∘-resp-≈ˡ B (identity H) ⟩
        id B ∘ (H₀ c $₁ f)             ≈⟨ identityˡ B ⟩
        H₀ c $₁ f                      ∎

      commute₂ : ∀ {c₁ c₂} (f : C [ c₁ , c₂ ]) {a} →
                 B [ (η (H₁ f) a ∘ (H₀ c₁ $₁ id A)) ≈ η (H₁ f) a ]
      commute₂ {c} {_} f {a} = begin
        η (H₁ f) a ∘ (H₀ c $₁ id A)    ≈⟨ ∘-resp-≈ʳ B (identity (H₀ c)) ⟩
        η (H₁ f) a ∘ id B              ≈⟨ identityʳ B ⟩
        η (H₁ f) a                     ∎

  curry-unique : ∀ {A B C} {G : C ⇒ B ^ A} {H : C × A ⇒ B} →
                 eval ∘F (G ⁂ idF) ≃ H → G ≃ curry.F₀ H
  curry-unique {A} {B} {C} {G} {H} hyp =
    begin
      G
    ≈⟨ η-exp {A} {B} {C} {G} ⟩
      curry.F₀ (eval ∘F (G ⁂ idF))
    ≈⟨ curry.resp-NI {F = eval ∘F (G ⁂ idF)} {H} hyp ⟩
      curry.F₀ H
    ∎
    where
      open Functor
      open Cats.HomReasoning

  Cats-CCC : Canonical.CartesianClosed (Cats l l l)
  Cats-CCC = record
    { !            = !
    ; π₁           = π₁
    ; π₂           = π₂
    ; ⟨_,_⟩        = ⟨_,_⟩
    ; !-unique     = !-unique
    ; π₁-comp      = λ {_} {_} {F} {_} {G} → project₁ {h = F} {i = G}
    ; π₂-comp      = λ {_} {_} {F} {_} {G} → project₂ {h = F} {i = G}
    ; ⟨,⟩-unique   = unique
    ; eval         = eval
    ; curry        = curry.F₀
    ; eval-comp    = λ {_} {_} {_} {G} → eval-comp {G = G}
    ; curry-resp-≈ = λ {_} {_} {_} {G} {H} → curry.resp-NI {F = G} {H}
    ; curry-unique = λ {_} {_} {_} {G} {H} → curry-unique {G = G} {H}
    }

  open Canonical.CartesianClosed Cats-CCC

Cats-CCC : ∀ {l} → CCC.CartesianClosed (Cats l l l)
Cats-CCC =
  Canonical.Equivalence.fromCanonical _ CanonicallyCartesianClosed.Cats-CCC

module CartesianClosed {l} = CCC.CartesianClosed (Cats-CCC {l})


{-
Stream transducers have been described in:

  N. Ghani, P. Hancock, and D. Pattinson,
  Continuous functions on final coalgebras.
  In Proc. CMCS 2006, Electr. Notes in Theoret. Comp. Sci., 2006.

They have been modelled by mixed equi-(co)inductive sized types in

  A. Abel,
  Mixed Inductive/Coinductive Types and Strong Normalization.
  In APLAS 2007, LNCS 4807.

Here we model them by mutual data/codata and mixed recursion/corecursion.
Cf. examples/Termination/StreamProc.agda
 -}

module StreamEating where

open import Common.Coinduction

-- Infinite streams.

data Stream (A : Set) : Set where
  _∷_ : (x : A) (xs : ∞ (Stream A)) → Stream A

-- A stream processor SP A B consumes elements of A and produces
-- elements of B. It can only consume a finite number of A's before
-- producing a B.

data SP (A B : Set) : Set where
  get : (f : A → SP A B) → SP A B
  put : (b : B) (sp : ∞ (SP A B)) → SP A B

-- eat is defined by (outer) corecursion into Stream B
-- and an inner recursion on SP A B
eat : ∀ {A B} → SP A B → Stream A → Stream B
eat (get f)    (a ∷ as) = eat (f a) (♭ as)
eat (put b sp) as       = b ∷ (♯ eat (♭ sp) as)

_∘_ : ∀ {A B C} → SP B C → SP A B → SP A C
get f₁    ∘ put x sp₂ = f₁ x ∘ ♭ sp₂
put x sp₁ ∘ sp₂       = put x (♯ (♭ sp₁ ∘ sp₂))
sp₁       ∘ get f₂    = get (λ x → sp₁ ∘ f₂ x)