------------------------------------------------------------------------
-- The Agda standard library
--
-- A bunch of properties
------------------------------------------------------------------------

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

module Data.Bool.Properties where

open import Algebra.Bundles
open import Data.Bool.Base
open import Data.Empty
open import Data.Product
open import Data.Sum.Base
open import Function.Base
open import Function.Equality using (_⟨$⟩_)
open import Function.Equivalence
  using (_⇔_; equivalence; module Equivalence)
open import Level using (Level; 0ℓ)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality hiding ([_])
open import Relation.Nullary using (ofʸ; ofⁿ; does; proof; yes; no)
open import Relation.Nullary.Decidable using (True)
import Relation.Unary as U

open import Algebra.Definitions {A = Bool} _≡_
open import Algebra.Structures {A = Bool} _≡_
open ≡-Reasoning

private
  variable
    a b : Level
    A : Set a
    B : Set b

------------------------------------------------------------------------
-- Properties of _≡_

infix 4 _≟_

_≟_ : Decidable {A = Bool} _≡_
true  ≟ true  = yes refl
false ≟ false = yes refl
true  ≟ false = no λ()
false ≟ true  = no λ()

≡-setoid : Setoid 0ℓ 0ℓ
≡-setoid = setoid Bool

≡-decSetoid : DecSetoid 0ℓ 0ℓ
≡-decSetoid = decSetoid _≟_

------------------------------------------------------------------------
-- Properties of _≤_

-- Relational properties

≤-reflexive : _≡_ ⇒ _≤_
≤-reflexive refl = b≤b

≤-refl : Reflexive _≤_
≤-refl = ≤-reflexive refl

≤-trans : Transitive _≤_
≤-trans b≤b p   = p
≤-trans f≤t b≤b = f≤t

≤-antisym : Antisymmetric _≡_ _≤_
≤-antisym b≤b _ = refl

≤-minimum : Minimum _≤_ false
≤-minimum false = b≤b
≤-minimum true  = f≤t

≤-maximum : Maximum _≤_ true
≤-maximum false = f≤t
≤-maximum true  = b≤b

≤-total : Total _≤_
≤-total false b = inj₁ (≤-minimum b)
≤-total true  b = inj₂ (≤-maximum b)

infix 4 _≤?_

_≤?_ : Decidable _≤_
false ≤? b     = yes (≤-minimum b)
true  ≤? false = no λ ()
true  ≤? true  = yes b≤b

≤-irrelevant : Irrelevant _≤_
≤-irrelevant {_}     f≤t f≤t = refl
≤-irrelevant {false} b≤b b≤b = refl
≤-irrelevant {true}  b≤b b≤b = refl

-- Structures

≤-isPreorder : IsPreorder _≡_ _≤_
≤-isPreorder = record
  { isEquivalence = isEquivalence
  ; reflexive     = ≤-reflexive
  ; trans         = ≤-trans
  }

≤-isPartialOrder : IsPartialOrder _≡_ _≤_
≤-isPartialOrder = record
  { isPreorder = ≤-isPreorder
  ; antisym    = ≤-antisym
  }

≤-isTotalOrder : IsTotalOrder _≡_ _≤_
≤-isTotalOrder = record
  { isPartialOrder = ≤-isPartialOrder
  ; total          = ≤-total
  }

≤-isDecTotalOrder : IsDecTotalOrder _≡_ _≤_
≤-isDecTotalOrder = record
  { isTotalOrder = ≤-isTotalOrder
  ; _≟_          = _≟_
  ; _≤?_         = _≤?_
  }

-- Bundles

≤-poset : Poset 0ℓ 0ℓ 0ℓ
≤-poset = record
  { isPartialOrder = ≤-isPartialOrder
  }

≤-preorder : Preorder 0ℓ 0ℓ 0ℓ
≤-preorder = record
  { isPreorder = ≤-isPreorder
  }

≤-totalOrder : TotalOrder 0ℓ 0ℓ 0ℓ
≤-totalOrder = record
  { isTotalOrder = ≤-isTotalOrder
  }

≤-decTotalOrder : DecTotalOrder 0ℓ 0ℓ 0ℓ
≤-decTotalOrder = record
  { isDecTotalOrder = ≤-isDecTotalOrder
  }

------------------------------------------------------------------------
-- Properties of _<_

-- Relational properties

<-irrefl : Irreflexive _≡_ _<_
<-irrefl refl ()

<-asym : Asymmetric _<_
<-asym f<t ()

<-trans : Transitive _<_
<-trans f<t ()

<-transʳ : Trans _≤_ _<_ _<_
<-transʳ b≤b f<t = f<t

<-transˡ : Trans _<_ _≤_ _<_
<-transˡ f<t b≤b = f<t

<-cmp : Trichotomous _≡_ _<_
<-cmp false false = tri≈ (λ()) refl  (λ())
<-cmp false true  = tri< f<t   (λ()) (λ())
<-cmp true  false = tri> (λ()) (λ()) f<t
<-cmp true  true  = tri≈ (λ()) refl  (λ())

infix 4 _<?_

_<?_ : Decidable _<_
false <? false = no  (λ())
false <? true  = yes f<t
true  <? _     = no  (λ())

<-resp₂-≡ : _<_ Respects₂ _≡_
<-resp₂-≡ = subst (_ <_) , subst (_< _)

<-irrelevant : Irrelevant _<_
<-irrelevant f<t f<t = refl

-- Structures

<-isStrictPartialOrder : IsStrictPartialOrder _≡_ _<_
<-isStrictPartialOrder = record
  { isEquivalence = isEquivalence
  ; irrefl        = <-irrefl
  ; trans         = <-trans
  ; <-resp-≈      = <-resp₂-≡
  }

<-isStrictTotalOrder : IsStrictTotalOrder _≡_ _<_
<-isStrictTotalOrder = record
  { isEquivalence = isEquivalence
  ; trans         = <-trans
  ; compare       = <-cmp
  }

-- Bundles

<-strictPartialOrder : StrictPartialOrder 0ℓ 0ℓ 0ℓ
<-strictPartialOrder = record
  { isStrictPartialOrder = <-isStrictPartialOrder
  }

<-strictTotalOrder : StrictTotalOrder 0ℓ 0ℓ 0ℓ
<-strictTotalOrder = record
  { isStrictTotalOrder = <-isStrictTotalOrder
  }

------------------------------------------------------------------------
-- Properties of _∨_

∨-assoc : Associative _∨_
∨-assoc true  y z = refl
∨-assoc false y z = refl

∨-comm : Commutative _∨_
∨-comm true  true  = refl
∨-comm true  false = refl
∨-comm false true  = refl
∨-comm false false = refl

∨-identityˡ : LeftIdentity false _∨_
∨-identityˡ _ = refl

∨-identityʳ : RightIdentity false _∨_
∨-identityʳ false = refl
∨-identityʳ true  = refl

∨-identity : Identity false _∨_
∨-identity = ∨-identityˡ , ∨-identityʳ

∨-zeroˡ : LeftZero true _∨_
∨-zeroˡ _ = refl

∨-zeroʳ : RightZero true _∨_
∨-zeroʳ false = refl
∨-zeroʳ true  = refl

∨-zero : Zero true _∨_
∨-zero = ∨-zeroˡ , ∨-zeroʳ

∨-inverseˡ : LeftInverse true not _∨_
∨-inverseˡ false = refl
∨-inverseˡ true  = refl

∨-inverseʳ : RightInverse true not _∨_
∨-inverseʳ x = ∨-comm x (not x) ⟨ trans ⟩ ∨-inverseˡ x

∨-inverse : Inverse true not _∨_
∨-inverse = ∨-inverseˡ , ∨-inverseʳ

∨-idem : Idempotent _∨_
∨-idem false = refl
∨-idem true  = refl

∨-sel : Selective _∨_
∨-sel false y = inj₂ refl
∨-sel true y  = inj₁ refl

∨-isMagma : IsMagma _∨_
∨-isMagma = record
  { isEquivalence = isEquivalence
  ; ∙-cong        = cong₂ _∨_
  }

∨-magma : Magma 0ℓ 0ℓ
∨-magma = record
  { isMagma = ∨-isMagma
  }

∨-isSemigroup : IsSemigroup _∨_
∨-isSemigroup = record
  { isMagma = ∨-isMagma
  ; assoc   = ∨-assoc
  }

∨-semigroup : Semigroup 0ℓ 0ℓ
∨-semigroup = record
  { isSemigroup = ∨-isSemigroup
  }

∨-isBand : IsBand _∨_
∨-isBand = record
  { isSemigroup = ∨-isSemigroup
  ; idem        = ∨-idem
  }

∨-band : Band 0ℓ 0ℓ
∨-band = record
  { isBand = ∨-isBand
  }

∨-isSemilattice : IsSemilattice _∨_
∨-isSemilattice = record
  { isBand = ∨-isBand
  ; comm   = ∨-comm
  }

∨-semilattice : Semilattice 0ℓ 0ℓ
∨-semilattice = record
  { isSemilattice = ∨-isSemilattice
  }

∨-isMonoid : IsMonoid _∨_ false
∨-isMonoid = record
  { isSemigroup = ∨-isSemigroup
  ; identity = ∨-identity
  }

∨-isCommutativeMonoid : IsCommutativeMonoid _∨_ false
∨-isCommutativeMonoid = record
  { isMonoid = ∨-isMonoid
  ; comm = ∨-comm
  }

∨-commutativeMonoid : CommutativeMonoid 0ℓ 0ℓ
∨-commutativeMonoid = record
  { isCommutativeMonoid = ∨-isCommutativeMonoid
  }

∨-isIdempotentCommutativeMonoid :
  IsIdempotentCommutativeMonoid _∨_ false
∨-isIdempotentCommutativeMonoid = record
  { isCommutativeMonoid = ∨-isCommutativeMonoid
  ; idem                = ∨-idem
  }

∨-idempotentCommutativeMonoid : IdempotentCommutativeMonoid 0ℓ 0ℓ
∨-idempotentCommutativeMonoid = record
  { isIdempotentCommutativeMonoid = ∨-isIdempotentCommutativeMonoid
  }

------------------------------------------------------------------------
-- Properties of _∧_

∧-assoc : Associative _∧_
∧-assoc true  y z = refl
∧-assoc false y z = refl

∧-comm : Commutative _∧_
∧-comm true  true  = refl
∧-comm true  false = refl
∧-comm false true  = refl
∧-comm false false = refl

∧-identityˡ : LeftIdentity true _∧_
∧-identityˡ _ = refl

∧-identityʳ : RightIdentity true _∧_
∧-identityʳ false = refl
∧-identityʳ true  = refl

∧-identity : Identity true _∧_
∧-identity = ∧-identityˡ , ∧-identityʳ

∧-zeroˡ : LeftZero false _∧_
∧-zeroˡ _ = refl

∧-zeroʳ : RightZero false _∧_
∧-zeroʳ false = refl
∧-zeroʳ true  = refl

∧-zero : Zero false _∧_
∧-zero = ∧-zeroˡ , ∧-zeroʳ

∧-inverseˡ : LeftInverse false not _∧_
∧-inverseˡ false = refl
∧-inverseˡ true = refl

∧-inverseʳ : RightInverse false not _∧_
∧-inverseʳ x = ∧-comm x (not x) ⟨ trans ⟩ ∧-inverseˡ x

∧-inverse : Inverse false not _∧_
∧-inverse = ∧-inverseˡ , ∧-inverseʳ

∧-idem : Idempotent _∧_
∧-idem false = refl
∧-idem true  = refl

∧-sel : Selective _∧_
∧-sel false y = inj₁ refl
∧-sel true y  = inj₂ refl

∧-distribˡ-∨ : _∧_ DistributesOverˡ _∨_
∧-distribˡ-∨ true  y z = refl
∧-distribˡ-∨ false y z = refl

∧-distribʳ-∨ : _∧_ DistributesOverʳ _∨_
∧-distribʳ-∨ x y z = begin
  (y ∨ z) ∧ x     ≡⟨ ∧-comm (y ∨ z) x ⟩
  x ∧ (y ∨ z)     ≡⟨ ∧-distribˡ-∨ x y z ⟩
  x ∧ y ∨ x ∧ z   ≡⟨ cong₂ _∨_ (∧-comm x y) (∧-comm x z) ⟩
  y ∧ x ∨ z ∧ x   ∎

∧-distrib-∨ : _∧_ DistributesOver _∨_
∧-distrib-∨ = ∧-distribˡ-∨ , ∧-distribʳ-∨

∨-distribˡ-∧ : _∨_ DistributesOverˡ _∧_
∨-distribˡ-∧ true  y z = refl
∨-distribˡ-∧ false y z = refl

∨-distribʳ-∧ : _∨_ DistributesOverʳ _∧_
∨-distribʳ-∧ x y z = begin
  (y ∧ z) ∨ x        ≡⟨ ∨-comm (y ∧ z) x ⟩
  x ∨ (y ∧ z)        ≡⟨ ∨-distribˡ-∧ x y z ⟩
  (x ∨ y) ∧ (x ∨ z)  ≡⟨ cong₂ _∧_ (∨-comm x y) (∨-comm x z) ⟩
  (y ∨ x) ∧ (z ∨ x)  ∎

∨-distrib-∧ : _∨_ DistributesOver _∧_
∨-distrib-∧ = ∨-distribˡ-∧ , ∨-distribʳ-∧

∧-abs-∨ : _∧_ Absorbs _∨_
∧-abs-∨ true  y = refl
∧-abs-∨ false y = refl

∨-abs-∧ : _∨_ Absorbs _∧_
∨-abs-∧ true  y = refl
∨-abs-∧ false y = refl

∨-∧-absorptive : Absorptive _∨_ _∧_
∨-∧-absorptive = ∨-abs-∧ , ∧-abs-∨

∧-isMagma : IsMagma _∧_
∧-isMagma = record
  { isEquivalence = isEquivalence
  ; ∙-cong        = cong₂ _∧_
  }

∧-magma : Magma 0ℓ 0ℓ
∧-magma = record
  { isMagma = ∧-isMagma
  }

∧-isSemigroup : IsSemigroup _∧_
∧-isSemigroup = record
  { isMagma = ∧-isMagma
  ; assoc   = ∧-assoc
  }

∧-semigroup : Semigroup 0ℓ 0ℓ
∧-semigroup = record
  { isSemigroup = ∧-isSemigroup
  }

∧-isBand : IsBand _∧_
∧-isBand = record
  { isSemigroup = ∧-isSemigroup
  ; idem        = ∧-idem
  }

∧-band : Band 0ℓ 0ℓ
∧-band = record
  { isBand = ∧-isBand
  }

∧-isSemilattice : IsSemilattice _∧_
∧-isSemilattice = record
  { isBand = ∧-isBand
  ; comm   = ∧-comm
  }

∧-semilattice : Semilattice 0ℓ 0ℓ
∧-semilattice = record
  { isSemilattice = ∧-isSemilattice
  }

∧-isMonoid : IsMonoid _∧_ true
∧-isMonoid = record
  { isSemigroup = ∧-isSemigroup
  ; identity = ∧-identity
  }

∧-isCommutativeMonoid : IsCommutativeMonoid _∧_ true
∧-isCommutativeMonoid = record
  { isMonoid = ∧-isMonoid
  ; comm = ∧-comm
  }

∧-commutativeMonoid : CommutativeMonoid 0ℓ 0ℓ
∧-commutativeMonoid = record
  { isCommutativeMonoid = ∧-isCommutativeMonoid
  }

∧-isIdempotentCommutativeMonoid :
  IsIdempotentCommutativeMonoid _∧_ true
∧-isIdempotentCommutativeMonoid = record
  { isCommutativeMonoid = ∧-isCommutativeMonoid
  ; idem = ∧-idem
  }

∧-idempotentCommutativeMonoid : IdempotentCommutativeMonoid 0ℓ 0ℓ
∧-idempotentCommutativeMonoid = record
  { isIdempotentCommutativeMonoid = ∧-isIdempotentCommutativeMonoid
  }

∨-∧-isSemiring : IsSemiring _∨_ _∧_ false true
∨-∧-isSemiring = record
  { isSemiringWithoutAnnihilatingZero = record
    { +-isCommutativeMonoid = ∨-isCommutativeMonoid
    ; *-isMonoid = ∧-isMonoid
    ; distrib = ∧-distrib-∨
    }
  ; zero = ∧-zero
  }

∨-∧-isCommutativeSemiring
  : IsCommutativeSemiring _∨_ _∧_ false true
∨-∧-isCommutativeSemiring = record
  { isSemiring = ∨-∧-isSemiring
  ; *-comm = ∧-comm
  }

∨-∧-commutativeSemiring : CommutativeSemiring 0ℓ 0ℓ
∨-∧-commutativeSemiring = record
  { _+_                   = _∨_
  ; _*_                   = _∧_
  ; 0#                    = false
  ; 1#                    = true
  ; isCommutativeSemiring = ∨-∧-isCommutativeSemiring
  }

∧-∨-isSemiring : IsSemiring _∧_ _∨_ true false
∧-∨-isSemiring = record
  { isSemiringWithoutAnnihilatingZero = record
    { +-isCommutativeMonoid = ∧-isCommutativeMonoid
    ; *-isMonoid = ∨-isMonoid
    ; distrib = ∨-distrib-∧
    }
  ; zero = ∨-zero
  }

∧-∨-isCommutativeSemiring
  : IsCommutativeSemiring _∧_ _∨_ true false
∧-∨-isCommutativeSemiring = record
  { isSemiring = ∧-∨-isSemiring
  ; *-comm = ∨-comm
  }

∧-∨-commutativeSemiring : CommutativeSemiring 0ℓ 0ℓ
∧-∨-commutativeSemiring = record
  { _+_                   = _∧_
  ; _*_                   = _∨_
  ; 0#                    = true
  ; 1#                    = false
  ; isCommutativeSemiring = ∧-∨-isCommutativeSemiring
  }

∨-∧-isLattice : IsLattice _∨_ _∧_
∨-∧-isLattice = record
  { isEquivalence = isEquivalence
  ; ∨-comm        = ∨-comm
  ; ∨-assoc       = ∨-assoc
  ; ∨-cong        = cong₂ _∨_
  ; ∧-comm        = ∧-comm
  ; ∧-assoc       = ∧-assoc
  ; ∧-cong        = cong₂ _∧_
  ; absorptive    = ∨-∧-absorptive
  }

∨-∧-lattice : Lattice 0ℓ 0ℓ
∨-∧-lattice = record
  { isLattice = ∨-∧-isLattice
  }

∨-∧-isDistributiveLattice : IsDistributiveLattice _∨_ _∧_
∨-∧-isDistributiveLattice = record
  { isLattice    = ∨-∧-isLattice
  ; ∨-distribʳ-∧ = ∨-distribʳ-∧
  }

∨-∧-distributiveLattice : DistributiveLattice 0ℓ 0ℓ
∨-∧-distributiveLattice = record
  { isDistributiveLattice = ∨-∧-isDistributiveLattice
  }

∨-∧-isBooleanAlgebra : IsBooleanAlgebra _∨_ _∧_ not true false
∨-∧-isBooleanAlgebra = record
  { isDistributiveLattice = ∨-∧-isDistributiveLattice
  ; ∨-complementʳ = ∨-inverseʳ
  ; ∧-complementʳ = ∧-inverseʳ
  ; ¬-cong        = cong not
  }

∨-∧-booleanAlgebra : BooleanAlgebra 0ℓ 0ℓ
∨-∧-booleanAlgebra = record
  { isBooleanAlgebra = ∨-∧-isBooleanAlgebra
  }

------------------------------------------------------------------------
-- Properties of _xor_

xor-is-ok : ∀ x y → x xor y ≡ (x ∨ y) ∧ not (x ∧ y)
xor-is-ok true  y = refl
xor-is-ok false y = sym (∧-identityʳ _)

xor-∧-commutativeRing : CommutativeRing 0ℓ 0ℓ
xor-∧-commutativeRing = commutativeRing
  where
  import Algebra.Properties.BooleanAlgebra as BA
  open BA ∨-∧-booleanAlgebra
  open XorRing _xor_ xor-is-ok

------------------------------------------------------------------------
-- Miscellaneous other properties

not-involutive : Involutive not
not-involutive true  = refl
not-involutive false = refl

not-injective : ∀ {x y} → not x ≡ not y → x ≡ y
not-injective {false} {false} nx≢ny = refl
not-injective {true}  {true}  nx≢ny = refl

not-¬ : ∀ {x y} → x ≡ y → x ≢ not y
not-¬ {true}  refl ()
not-¬ {false} refl ()

¬-not : ∀ {x y} → x ≢ y → x ≡ not y
¬-not {true}  {true}  x≢y = ⊥-elim (x≢y refl)
¬-not {true}  {false} _   = refl
¬-not {false} {true}  _   = refl
¬-not {false} {false} x≢y = ⊥-elim (x≢y refl)

⇔→≡ : {x y z : Bool} → x ≡ z ⇔ y ≡ z → x ≡ y
⇔→≡ {true } {true }         hyp = refl
⇔→≡ {true } {false} {true } hyp = sym (Equivalence.to hyp ⟨$⟩ refl)
⇔→≡ {true } {false} {false} hyp = Equivalence.from hyp ⟨$⟩ refl
⇔→≡ {false} {true } {true } hyp = Equivalence.from hyp ⟨$⟩ refl
⇔→≡ {false} {true } {false} hyp = sym (Equivalence.to hyp ⟨$⟩ refl)
⇔→≡ {false} {false}         hyp = refl

T-≡ : ∀ {x} → T x ⇔ x ≡ true
T-≡ {false} = equivalence (λ ())       (λ ())
T-≡ {true}  = equivalence (const refl) (const _)

T-not-≡ : ∀ {x} → T (not x) ⇔ x ≡ false
T-not-≡ {false} = equivalence (const refl) (const _)
T-not-≡ {true}  = equivalence (λ ())       (λ ())

T-∧ : ∀ {x y} → T (x ∧ y) ⇔ (T x × T y)
T-∧ {true}  {true}  = equivalence (const (_ , _)) (const _)
T-∧ {true}  {false} = equivalence (λ ())          proj₂
T-∧ {false} {_}     = equivalence (λ ())          proj₁

T-∨ : ∀ {x y} → T (x ∨ y) ⇔ (T x ⊎ T y)
T-∨ {true}  {_}     = equivalence inj₁ (const _)
T-∨ {false} {true}  = equivalence inj₂ (const _)
T-∨ {false} {false} = equivalence inj₁ [ id , id ]

T-irrelevant : U.Irrelevant T
T-irrelevant {true}  _  _  = refl

T? : U.Decidable T
does  (T? b) = b
proof (T? true ) = ofʸ _
proof (T? false) = ofⁿ λ()

T?-diag : ∀ b → T b → True (T? b)
T?-diag true  _ = _

push-function-into-if : ∀ (f : A → B) x {y z} →
                        f (if x then y else z) ≡ (if x then f y else f z)
push-function-into-if _ true  = refl
push-function-into-if _ false = refl

------------------------------------------------------------------------
-- DEPRECATED NAMES
------------------------------------------------------------------------
-- Please use the new names as continuing support for the old names is
-- not guaranteed.

-- Version 0.15

∧-∨-distˡ   = ∧-distribˡ-∨
{-# WARNING_ON_USAGE ∧-∨-distˡ
"Warning: ∧-∨-distˡ was deprecated in v0.15.
Please use ∧-distribˡ-∨ instead."
#-}
∧-∨-distʳ   = ∧-distribʳ-∨
{-# WARNING_ON_USAGE ∧-∨-distʳ
"Warning: ∧-∨-distʳ was deprecated in v0.15.
Please use ∧-distribʳ-∨ instead."
#-}
distrib-∧-∨ = ∧-distrib-∨
{-# WARNING_ON_USAGE distrib-∧-∨
"Warning: distrib-∧-∨ was deprecated in v0.15.
Please use ∧-distrib-∨ instead."
#-}
∨-∧-distˡ   = ∨-distribˡ-∧
{-# WARNING_ON_USAGE ∨-∧-distˡ
"Warning: ∨-∧-distˡ was deprecated in v0.15.
Please use ∨-distribˡ-∧ instead."
#-}
∨-∧-distʳ   = ∨-distribʳ-∧
{-# WARNING_ON_USAGE ∨-∧-distʳ
"Warning: ∨-∧-distʳ was deprecated in v0.15.
Please use ∨-distribʳ-∧ instead."
#-}
∨-∧-distrib = ∨-distrib-∧
{-# WARNING_ON_USAGE ∨-∧-distrib
"Warning: ∨-∧-distrib was deprecated in v0.15.
Please use ∨-distrib-∧ instead."
#-}
∨-∧-abs    = ∨-abs-∧
{-# WARNING_ON_USAGE ∨-∧-abs
"Warning: ∨-∧-abs was deprecated in v0.15.
Please use ∨-abs-∧ instead."
#-}
∧-∨-abs    = ∧-abs-∨
{-# WARNING_ON_USAGE ∧-∨-abs
"Warning: ∧-∨-abs was deprecated in v0.15.
Please use ∧-abs-∨ instead."
#-}
not-∧-inverseˡ = ∧-inverseˡ
{-# WARNING_ON_USAGE not-∧-inverseˡ
"Warning: not-∧-inverseˡ was deprecated in v0.15.
Please use ∧-inverseˡ instead."
#-}
not-∧-inverseʳ = ∧-inverseʳ
{-# WARNING_ON_USAGE not-∧-inverseʳ
"Warning: not-∧-inverseʳ was deprecated in v0.15.
Please use ∧-inverseʳ instead."
#-}
not-∧-inverse = ∧-inverse
{-# WARNING_ON_USAGE not-∧-inverse
"Warning: not-∧-inverse was deprecated in v0.15.
Please use ∧-inverse instead."
#-}
not-∨-inverseˡ = ∨-inverseˡ
{-# WARNING_ON_USAGE not-∨-inverseˡ
"Warning: not-∨-inverseˡ was deprecated in v0.15.
Please use ∨-inverseˡ instead."
#-}
not-∨-inverseʳ = ∨-inverseʳ
{-# WARNING_ON_USAGE not-∨-inverseʳ
"Warning: not-∨-inverseʳ was deprecated in v0.15.
Please use ∨-inverseʳ instead."
#-}
not-∨-inverse = ∨-inverse
{-# WARNING_ON_USAGE not-∨-inverse
"Warning: not-∨-inverse was deprecated in v0.15.
Please use ∨-inverse instead."
#-}
isCommutativeSemiring-∨-∧ = ∨-∧-isCommutativeSemiring
{-# WARNING_ON_USAGE isCommutativeSemiring-∨-∧
"Warning: isCommutativeSemiring-∨-∧ was deprecated in v0.15.
Please use ∨-∧-isCommutativeSemiring instead."
#-}
commutativeSemiring-∨-∧   =  ∨-∧-commutativeSemiring
{-# WARNING_ON_USAGE commutativeSemiring-∨-∧
"Warning: commutativeSemiring-∨-∧ was deprecated in v0.15.
Please use ∨-∧-commutativeSemiring instead."
#-}
isCommutativeSemiring-∧-∨ = ∧-∨-isCommutativeSemiring
{-# WARNING_ON_USAGE isCommutativeSemiring-∧-∨
"Warning: isCommutativeSemiring-∧-∨ was deprecated in v0.15.
Please use ∧-∨-isCommutativeSemiring instead."
#-}
commutativeSemiring-∧-∨   = ∧-∨-commutativeSemiring
{-# WARNING_ON_USAGE commutativeSemiring-∧-∨
"Warning: commutativeSemiring-∧-∨ was deprecated in v0.15.
Please use ∧-∨-commutativeSemiring instead."
#-}
isBooleanAlgebra          = ∨-∧-isBooleanAlgebra
{-# WARNING_ON_USAGE isBooleanAlgebra
"Warning: isBooleanAlgebra was deprecated in v0.15.
Please use ∨-∧-isBooleanAlgebra instead."
#-}
booleanAlgebra            = ∨-∧-booleanAlgebra
{-# WARNING_ON_USAGE booleanAlgebra
"Warning: booleanAlgebra was deprecated in v0.15.
Please use ∨-∧-booleanAlgebra instead."
#-}
commutativeRing-xor-∧     = xor-∧-commutativeRing
{-# WARNING_ON_USAGE commutativeRing-xor-∧
"Warning: commutativeRing-xor-∧ was deprecated in v0.15.
Please use xor-∧-commutativeRing instead."
#-}
proof-irrelevance = T-irrelevant
{-# WARNING_ON_USAGE proof-irrelevance
"Warning: proof-irrelevance was deprecated in v0.15.
Please use T-irrelevant instead."
#-}

-- Version 1.0

T-irrelevance = T-irrelevant
{-# WARNING_ON_USAGE T-irrelevance
"Warning: T-irrelevance was deprecated in v1.0.
Please use T-irrelevant instead."
#-}


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

module Data.Tuple.Base where

open import Prelude hiding (⊤; tt)
open import Data.Unit.UniversePolymorphic
open import Data.Fin

Tuple : ∀ n → (Lift a (Fin n) → Type b) → Type b
Tuple zero    f = ⊤
Tuple {a = a} {b = b} (suc n) f = f (lift f0) × Tuple {a = a} {b = b} n (f ∘ lift ∘ fs ∘ lower)

private
  variable
    n : ℕ
    u : Level
    U : Lift a (Fin n) → Type u

ind : Tuple n U → (i : Lift a (Fin n)) → U i
ind {n = suc n} (x , xs) (lift f0)     = x
ind {n = suc n} (x , xs) (lift (fs i)) = ind xs (lift i)

tab : ((i : Lift a (Fin n)) → U i) → Tuple n U
tab {n = zero}  f = tt
tab {n = suc n} f = f (lift f0) , tab (f ∘ lift ∘ fs ∘ lower)

Π→Tuple→Π : ∀ {a n u} {U : Lift a (Fin n) → Type u} (xs : (i : Lift a (Fin n)) → U i) i → ind (tab xs) i ≡ xs i
Π→Tuple→Π {n = suc n} f (lift f0) = refl
Π→Tuple→Π {n = suc n} f (lift (fs i)) = Π→Tuple→Π (f ∘ lift ∘ fs ∘ lower) (lift i)

Tuple→Π→Tuple : ∀ {n} {U : Lift a (Fin n) → Type u} (xs : Tuple n U) → tab (ind xs) ≡ xs
Tuple→Π→Tuple {n = zero} tt = refl
Tuple→Π→Tuple {n = suc n} (x , xs) i .fst = x
Tuple→Π→Tuple {n = suc n} (x , xs) i .snd = Tuple→Π→Tuple xs i

Tuple⇔ΠFin : ∀ {a n u} {U : Lift a (Fin n) → Type u} → Tuple n U ⇔ ((i : Lift a (Fin n)) → U i)
Tuple⇔ΠFin .fun = ind
Tuple⇔ΠFin .inv = tab
Tuple⇔ΠFin .leftInv = Tuple→Π→Tuple
Tuple⇔ΠFin .rightInv x = funExt (Π→Tuple→Π x)


{-

This file contains:

- The first Eilenberg–Mac Lane type as a HIT

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.HITs.EilenbergMacLane1.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.GroupoidLaws
  renaming (assoc to assoc∙)
open import Cubical.Algebra.Group.Base

private
  variable ℓ : Level

module _ (Group@(G , str) : Group ℓ) where
  open GroupStr str

  data EM₁ : Type ℓ where
    embase : EM₁
    emloop : G → embase ≡ embase
    emcomp : (g h : G)
           → PathP (λ j → embase ≡ emloop h j) (emloop g) (emloop (g · h))
    emsquash : ∀ (x y : EM₁) (p q : x ≡ y) (r s : p ≡ q) → r ≡ s

  {- The emcomp constructor fills the square:
^
    emloop (g · h)
    [a]— — — >[c]
     ‖         ^
     ‖         | emloop h     ^
     ‖         |            j |
    [a]— — — >[b]          ∙ — >
       emloop g                i

    We use this to give another constructor-like construction:
  -}

  emloop-comp : (g h : G) → emloop (g · h) ≡ emloop g ∙ emloop h
  emloop-comp g h i = compPath-unique refl (emloop g) (emloop h)
    (emloop (g · h) , emcomp g h)
    (emloop g ∙ emloop h , compPath-filler (emloop g) (emloop h)) i .fst

  emloop-1g : emloop 1g ≡ refl
  emloop-1g =
       lUnit (emloop 1g)
    ∙∙ cong (_∙ emloop 1g) (sym (lCancel (emloop 1g)) )
    ∙∙ sym (assoc∙ _ _ _)
    ∙∙ cong (sym (emloop 1g) ∙_) (sym (emloop-comp 1g 1g) ∙ cong emloop (·IdL 1g))
    ∙∙ rCancel _

  emloop-sym : (g : G) → emloop (inv g) ≡ sym (emloop g)
  emloop-sym g =
       rUnit _
    ∙∙ cong (emloop (inv g) ∙_) (sym (rCancel (emloop g)))
    ∙∙ assoc∙ _ _ _
    ∙∙ cong (_∙ sym (emloop g)) (sym (emloop-comp (inv g) g) ∙∙ cong emloop (·InvL g) ∙∙ emloop-1g)
    ∙∙ sym (lUnit _)


{-# OPTIONS --safe #-}
module Cubical.Categories.Limits.Initial where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism renaming (Iso to _≅_)
open import Cubical.HITs.PropositionalTruncation.Base

open import Cubical.Data.Sigma

open import Cubical.Categories.Category
open import Cubical.Categories.Functor
open import Cubical.Categories.Adjoint

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

module _ (C : Category ℓ ℓ') where
  open Category C

  isInitial : (x : ob) → Type (ℓ-max ℓ ℓ')
  isInitial x = ∀ (y : ob) → isContr (C [ x , y ])

  Initial : Type (ℓ-max ℓ ℓ')
  Initial = Σ[ x ∈ ob ] isInitial x

  initialOb : Initial → ob
  initialOb = fst

  initialArrow : (T : Initial) (y : ob) → C [ initialOb T , y ]
  initialArrow T y = T .snd y .fst

  initialArrowUnique : {T : Initial} {y : ob} (f : C [ initialOb T , y ])
                      → initialArrow T y ≡ f
  initialArrowUnique {T} {y} f = T .snd y .snd f

  initialEndoIsId : (T : Initial) (f : C [ initialOb T , initialOb T ])
                   → f ≡ id
  initialEndoIsId T f = isContr→isProp (T .snd (initialOb T)) f id

  hasInitial : Type (ℓ-max ℓ ℓ')
  hasInitial = ∥ Initial ∥₁

  -- Initiality of an object is a proposition.
  isPropIsInitial : (x : ob) → isProp (isInitial x)
  isPropIsInitial _ = isPropΠ λ _ → isPropIsContr

  open CatIso

  -- Objects that are initial are isomorphic.
  initialToIso : (x y : Initial) → CatIso C (initialOb x) (initialOb y)
  mor (initialToIso x y) = initialArrow x (initialOb y)
  inv (initialToIso x y) = initialArrow y (initialOb x)
  sec (initialToIso x y) = initialEndoIsId y _
  ret (initialToIso x y) = initialEndoIsId x _

  open isUnivalent

  -- The type of initial objects of a univalent category is a proposition,
  -- i.e. all initial objects are equal.
  isPropInitial : (hC : isUnivalent C) → isProp Initial
  isPropInitial hC x y =
    Σ≡Prop isPropIsInitial (CatIsoToPath hC (initialToIso x y))

module _ {C : Category ℓC ℓC'} {D : Category ℓD ℓD'} (F : Functor C D) where
  open Category
  open Functor
  open NaturalBijection
  open _⊣_
  open _≅_

  preservesInitial : Type (ℓ-max (ℓ-max ℓC ℓC') (ℓ-max ℓD ℓD'))
  preservesInitial = ∀ (x : ob C) → isInitial C x → isInitial D (F-ob F x)

  isLeftAdjoint→preservesInitial : isLeftAdjoint F → preservesInitial
  fst (isLeftAdjoint→preservesInitial (G , F⊣G) x initX y) = _♯ F⊣G (fst (initX (F-ob G y)))
  snd (isLeftAdjoint→preservesInitial (G , F⊣G) x initX y) ψ =
    _♯ F⊣G (fst (initX (F-ob G y)))
      ≡⟨ cong (F⊣G ♯) (snd (initX (F-ob G y)) (_♭ F⊣G ψ)) ⟩
    _♯ F⊣G (_♭ F⊣G ψ)
      ≡⟨ leftInv (adjIso F⊣G) ψ ⟩
    ψ ∎


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

open import HoTT

module homotopy.PathSetIsInital {i} (A : Type i)
  -- (A-conn : is-connected 0 A)
  where

  open Cover

  module _
    (a₁ : A)
    -- And an arbitrary covering.
    {k} (cov : Cover A k)
    -- (cov-conn : is-connected 0 (Cover.TotalSpace cov))
    (a↑₁ : Fiber cov a₁)
    where

    private
      univ-cover = path-set-cover ⊙[ A , a₁ ]

    -- Weak initiality by transport.
    quotient-cover : CoverHom univ-cover cov
    quotient-cover _ p = cover-trace cov a↑₁ p

    -- Strong initiality by path induction.
    module Uniqueness
      (cover-hom : CoverHom univ-cover cov)
      (pres-a↑₁ : cover-hom a₁ idp₀ == a↑₁)
      where

      private
        lemma₁ : ∀ a p → cover-hom a [ p ] == quotient-cover a [ p ]
        lemma₁ ._ idp = pres-a↑₁

        lemma₂ : ∀ a p → cover-hom a p == quotient-cover a p
        lemma₂ a = Trunc-elim
          (λ p → =-preserves-level 0 (Cover.Fiber-level cov a))
          (lemma₁ a)

      theorem : cover-hom == quotient-cover
      theorem = λ= λ a → λ= $ lemma₂ a


-- There was a bug where f (suc n) didn't reduce for neutral n.
module Issue26 where

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

{-# BUILTIN NATURAL Nat  #-}
{-# BUILTIN ZERO    zero #-}
{-# BUILTIN SUC     suc  #-}

f : Nat -> Nat
f 0       = 0
f (suc n) = f n

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

lem : (n : Nat) -> f (suc n) == f n
lem n = refl


open import Categories
open import Monads

module Monads.Kleisli {a b}{C : Cat {a}{b}}(M : Monad C) where

open import Library
open Cat C
open Monad M

Kl : Cat
Kl = record{
  Obj  = Obj;
  Hom  = λ X Y → Hom X (T Y);
  iden = η;
  comp = λ f g → comp (bind f) g;
  idl  = λ{X}{Y}{f} →
    proof
    comp (bind η) f
    ≅⟨ cong (λ g → comp g f) law1 ⟩
    comp iden f
    ≅⟨ idl ⟩
    f
    ∎;
  idr  = law2;
  ass  = λ{_}{_}{_}{_}{f}{g}{h} →
    proof
    comp (bind (comp (bind f) g)) h
    ≅⟨ cong (λ f → comp f h) law3 ⟩
    comp (comp (bind f) (bind g)) h
    ≅⟨ ass ⟩
    comp (bind f) (comp (bind g) h)
    ∎}


module Cats.Category.Product.Binary where

open import Level using (_⊔_)
open import Relation.Binary using (Rel ; IsEquivalence ; _Preserves₂_⟶_⟶_)
open import Relation.Binary.Product.Pointwise using (×-isEquivalence ; Pointwise)

open import Cats.Category.Base
open import Cats.Util.Logic.Constructive using (_∧_ ; _,_)

module Build {lo la l≈ lo′ la′ l≈′}
  (C : Category lo la l≈)
  (D : Category lo′ la′ l≈′)
  where

  infixr 9 _∘_
  infixr 4 _≈_

  private
    module C = Category C
    module D = Category D

  Obj : Set (lo ⊔ lo′)
  Obj = C.Obj ∧ D.Obj

  _⇒_ : Obj → Obj → Set (la ⊔ la′)
  (A , A′) ⇒ (B , B′) = (A C.⇒ B) ∧ (A′ D.⇒ B′)

  _≈_ : ∀ {A B} → Rel (A ⇒ B) (l≈ ⊔ l≈′)
  _≈_ = Pointwise C._≈_ D._≈_

  id : {A : Obj} → A ⇒ A
  id = C.id , D.id

  _∘_ : ∀ {A B C} → B ⇒ C → A ⇒ B → A ⇒ C
  (f , f′) ∘ (g , g′) = f C.∘ g , f′ D.∘ g′

  equiv : ∀ {A B} → IsEquivalence (_≈_ {A} {B})
  equiv = ×-isEquivalence C.equiv D.equiv

  ∘-resp : ∀ {A B C} → _∘_ {A} {B} {C} Preserves₂ _≈_ ⟶ _≈_ ⟶ _≈_
  ∘-resp (eq₁ , eq₁′) (eq₂ , eq₂′) = C.∘-resp eq₁ eq₂ , D.∘-resp eq₁′ eq₂′

  id-r : ∀ {A B} {f : A ⇒ B} → f ∘ id ≈ f
  id-r = C.id-r , D.id-r

  id-l : ∀ {A B} {f : A ⇒ B} → id ∘ f ≈ f
  id-l = C.id-l , D.id-l

  assoc : ∀ {A B C D} {f : C ⇒ D} {g : B ⇒ C} {h : A ⇒ B}
    → (f ∘ g) ∘ h ≈ f ∘ (g ∘ h)
  assoc = C.assoc , D.assoc

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

open Build public using (_×_)


module list where

module List (A : Set) where

  data List : Set where
    nil  : List
    _::_ : A -> List -> List

  _++_ : List -> List -> List
  nil       ++ ys = ys
  (x :: xs) ++ ys = x :: (xs ++ ys)


{-# OPTIONS --cubical #-}

module Numeral.Natural.Equiv.Path where

open import Data.Boolean.Equiv.Path
open import Functional
open import Logic.Propositional
open import Numeral.Natural.Oper.Comparisons
open import Numeral.Natural
open import Relator.Equals.Proofs.Equivalence using () renaming ([≡]-equiv to Id-equiv ; [≡]-symmetry to Id-symmetry ; [≡]-to-function to Id-to-function ; [≡]-function to Id-function)
open import Structure.Function.Domain
open import Structure.Function
open import Structure.Relator.Properties
open import Type.Cubical.Path.Equality
open import Type.Cubical.Path
open import Type.Identity

instance
  𝐒-injective : Injective(𝐒)
  Injective.proof 𝐒-injective p = congruence₁(𝐏) p

ℕ-Path-to-Id : ∀{x y : ℕ} → (Path x y) → (Id x y)
ℕ-Path-to-Id {𝟎}   {𝟎}   p = intro
ℕ-Path-to-Id {𝟎}   {𝐒 y}   = [⊥]-elim ∘ Bool-different-values ∘ congruence₁(positive?)
ℕ-Path-to-Id {𝐒 x} {𝟎}     = [⊥]-elim ∘ Bool-different-values ∘ symmetry(Path) ∘ congruence₁(positive?)
ℕ-Path-to-Id {𝐒 x} {𝐒 y} p = congruence₁ ⦃ Id-equiv ⦄ ⦃ Id-equiv ⦄ (ℕ.𝐒) ⦃ Id-function ⦄ (ℕ-Path-to-Id {x}{y} (injective(ℕ.𝐒) p))


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

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Pointed
open import Cubical.HITs.Pushout.Base
open import Cubical.Data.Sigma
open import Cubical.Data.Unit

_⋁_ : ∀ {ℓ ℓ'} → Pointed ℓ → Pointed ℓ' → Type (ℓ-max ℓ ℓ')
_⋁_ (A , ptA) (B , ptB) = Pushout {A = Unit} {B = A} {C = B} (λ _ → ptA) (λ _ → ptB)

-- Pointed versions
_⋁∙ₗ_ : ∀ {ℓ ℓ'} → Pointed ℓ → Pointed ℓ' → Pointed (ℓ-max ℓ ℓ')
A ⋁∙ₗ B = (A ⋁ B) , (inl (snd A))

_⋁∙ᵣ_ : ∀ {ℓ ℓ'} → Pointed ℓ → Pointed ℓ' → Pointed (ℓ-max ℓ ℓ')
A ⋁∙ᵣ B = (A ⋁ B) , (inr (snd B))

-- Wedge sums of functions
_∨→_ : ∀ {ℓ ℓ' ℓ''} {A : Pointed ℓ} {B : Pointed ℓ'} {C : Pointed ℓ''}
      → (f : A →∙ C) (g : B →∙ C)
      → A ⋁ B → fst C
(f ∨→ g) (inl x) = fst f x
(f ∨→ g) (inr x) = fst g x
(f ∨→ g) (push a i₁) = (snd f ∙ sym (snd g)) i₁

-- Pointed version
∨→∙ : ∀ {ℓ ℓ' ℓ''} {A : Pointed ℓ} {B : Pointed ℓ'} {C : Pointed ℓ''}
   → (f : A →∙ C) (g : B →∙ C) → ((A ⋁∙ₗ B) →∙ C)
fst (∨→∙ {A = A} f g) = f ∨→ g
snd (∨→∙ {A = A} f g) = snd f

-- Wedge sum of Units is contractible
isContr-Unit⋁Unit : isContr ((Unit , tt) ⋁ (Unit , tt))
fst isContr-Unit⋁Unit = inl tt
snd isContr-Unit⋁Unit (inl tt) = refl
snd isContr-Unit⋁Unit (inr tt) = push tt
snd isContr-Unit⋁Unit (push tt i) j = push tt (i ∧ j)

⋁↪ : ∀ {ℓ ℓ'} {A : Pointed ℓ} {B : Pointed ℓ'}
      → A ⋁ B → typ A × typ B
⋁↪ {B = B} (inl x) = x , pt B
⋁↪ {A = A} (inr x) = pt A , x
⋁↪ {A = A} {B = B} (push a i) = pt A , pt B


module Numeral.Finite.Functions where

import Lvl
open import Syntax.Number
open import Lang.Instance
open import Logic.Propositional
open import Logic.Predicate
open import Numeral.Finite
open import Numeral.Finite.Bound
open import Numeral.Natural hiding (𝐏)
import      Numeral.Natural.Function as ℕ
import      Numeral.Natural.Function.Proofs as ℕ
open import Numeral.Natural.Oper

-- Maximum function.
-- Returns the greatest number.
max : ∀{a b} → 𝕟(a) → 𝕟(b) → 𝕟(ℕ.max a b)
max        𝟎      𝟎      = 𝟎
max {a}{b} (𝐒(x)) 𝟎      = bound-[≤] (ℕ.max-orderₗ {a}{b}) (𝐒(x))
max {a}{b} 𝟎      (𝐒(y)) = bound-[≤] (ℕ.max-orderᵣ {a}{b}) (𝐒(y))
max        (𝐒(x)) (𝐒(y)) = 𝐒(max x y)

-- Minimum function.
-- Returns the smallest number.
min : ∀{a b} → 𝕟(a) → 𝕟(b) → 𝕟(ℕ.min a b)
min 𝟎      𝟎      = 𝟎
min (𝐒(_)) 𝟎      = 𝟎
min 𝟎      (𝐒(_)) = 𝟎
min (𝐒(x)) (𝐒(y)) = 𝐒(min x y)


open import Agda.Builtin.Coinduction
open import Agda.Builtin.Nat
open import Agda.Builtin.List
open import Agda.Builtin.Equality

data Colist (A : Set) : Set where
  [] : Colist A
  _∷_ : A → ∞ (Colist A) → Colist A

from : Nat → Colist Nat
from n = let sn = suc n in n ∷ ♯ (from sn)

take : {A : Set} → Nat → Colist A → List A
take zero    xs = []
take (suc n) [] = []
take (suc n) (x ∷ xs) = x ∷ take n (♭ xs)

check : take 3 (from 5) ≡ 5 ∷ 6 ∷ 7 ∷ []
check = refl


module Computability.Recursive where

open import Data.Empty using (⊥; ⊥-elim)
open import Data.Unit using (⊤)
open import Data.Bool using (Bool; false; true)
open import Data.Nat using (ℕ; zero; suc; _+_; _*_; pred)
open import Data.Product using (_×_)
open import Data.Fin using (Fin; zero; suc; punchIn; punchOut)
open import Data.Sum using (_⊎_)
open import Data.Vec using (Vec; _∷_; []; lookup) renaming (map to map-Vec)
open import Function using (Bijective)
open import Relation.Binary.PropositionalEquality using (_≡_)
open import Level renaming (zero to lzero; suc to lsuc)

variable
  n m : ℕ
  b : Bool

data RecFun : (use-mu : Bool) → ℕ → Set where
  Var : Fin n → RecFun b n
  Bind : Vec (RecFun b m) n → RecFun b n → RecFun b m
  Zero : RecFun b 0
  Suc : RecFun b 1
  Rec : RecFun b n → RecFun b (2 + n) → RecFun b (suc n)
  Mu : RecFun b (suc n) → RecFun true n

mutual
  eval-no-mu : Vec ℕ n → RecFun false n → ℕ
  eval-no-mu v (Var i) = lookup v i
  eval-no-mu v (Bind xs r) = eval-no-mu (eval-bindings v xs) r
  eval-no-mu v Zero = zero
  eval-no-mu (x ∷ []) Suc = suc x
  eval-no-mu (x ∷ v) (Rec base rec) = eval-no-mu-rec x v base rec

  eval-bindings : ∀{n m} → Vec ℕ m → Vec (RecFun false m) n → Vec ℕ n
  eval-bindings v [] = []
  eval-bindings v (x ∷ xs) = eval-no-mu v x ∷ eval-bindings v xs

  eval-no-mu-rec : ℕ → Vec ℕ n → RecFun false n → RecFun false (2 + n) → ℕ
  eval-no-mu-rec zero v base rec = eval-no-mu v base
  eval-no-mu-rec (suc k) v base rec = eval-no-mu (k ∷ result ∷ v) rec
    where result = eval-no-mu-rec k v base rec

postulate
  enum-RecFun : ∀ vars → ℕ → RecFun true vars
  enum-RecFun-Surj : ∀ vars → ℕ → Bijective {A = ℕ} {B = RecFun true vars} _≡_ _≡_ (enum-RecFun vars)


module Issue739 where

record ⊤ : Set where
  constructor tt

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

uncurry : {A : Set} {B : A → Set} →
          ((x : A) → B x → Set) →
          Σ A B → Set
uncurry f (x , y) = f x y

data U : Set₁

El : U → Set

infixl 5 _▻_

data U where
  ε   : U
  _▻_ : (u : U) → (El u → Set) → U

El ε       = ⊤
El (u ▻ P) = Σ (El u) P

Id : ∀ u → (El u → Set) → El u → Set
Id u P = P

-- Type-checks:

works : U
works =
  ε
  ▻ (λ _ → ⊤)
  ▻ (λ { (_ , _) → ⊤ })

-- Type-checks:

works′ : U
works′ =
  ε
  ▻ (λ _ → ⊤)
  ▻ Id (_ ▻ _) (λ { (_ , _) → ⊤ })

-- Type-checks:

works″ : U
works″ =
  ε
  ▻ (λ _ → ⊤)
  ▻ Id _ (uncurry λ _ _ → ⊤)

-- Type-checks:

works‴ : U
works‴ =
  ε
  ▻ (λ _ → ⊤)
  ▻ Id _ const-⊤
  where
  const-⊤ : _ → _
  const-⊤ (_ , _) = ⊤

-- Type-checks:

works⁗ : U
works⁗ =
  ε
  ▻ (λ _ → ⊤)
  ▻ Id _ const-⊤
  where
  const-⊤ : _ → _
  const-⊤ = λ { (_ , _) → ⊤ }

-- Type-checks:

works′́ : U
works′́ =
  ε
  ▻ (λ _ → ⊤)
  ▻ Id _ (λ { _ → ⊤ })

-- Doesn't type-check (but I want to write something like this):

fails : U
fails =
  ε
  ▻ (λ _ → ⊤)
  ▻ Id _ (λ { (_ , _) → ⊤ })

-- Given all the working examples I'm led to believe that there is
-- something wrong with pattern-matching lambdas. Please correct me if
-- I'm wrong.

-- Andreas, 2012-10-29 should work now.


module Numeral.Natural.Coprime.Proofs where

open import Functional
open import Logic
open import Logic.Classical
open import Logic.Propositional
open import Logic.Propositional.Theorems
import      Lvl
open import Numeral.Finite
open import Numeral.Natural
open import Numeral.Natural.Coprime
open import Numeral.Natural.Decidable
open import Numeral.Natural.Function.GreatestCommonDivisor
open import Numeral.Natural.Relation.Divisibility.Proofs
open import Numeral.Natural.Oper
open import Numeral.Natural.Prime
open import Numeral.Natural.Prime.Proofs
open import Numeral.Natural.Relation.Divisibility
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Proofs
open import Relator.Equals
open import Structure.Relator.Properties
open import Type.Properties.Decidable.Proofs
open import Type

private variable n x y d p : ℕ

-- 1 is the only number coprime to itself because it does not have any divisors except for itself.
Coprime-reflexivity-condition : Coprime(n)(n) ↔ (n ≡ 1)
Coprime-reflexivity-condition {n} = [↔]-intro l (r{n}) where
  l : Coprime(n)(n) ← (n ≡ 1)
  Coprime.proof(l [≡]-intro) {a} a1 _ = [1]-only-divides-[1] (a1)

  r : ∀{n} → Coprime(n)(n) → (n ≡ 1)
  r {𝟎}       (intro z1)   = z1 Div𝟎 Div𝟎
  r {𝐒(𝟎)}    _            = [≡]-intro
  r {𝐒(𝐒(n))} (intro ssn1) = ssn1 {𝐒(𝐒(n))} divides-reflexivity divides-reflexivity

instance
  Coprime-symmetry : Symmetry(Coprime)
  Coprime.proof(Symmetry.proof Coprime-symmetry (intro proof)) {n} nx ny = proof {n} ny nx

-- The only number coprime to 0 is 1 because while all numbers divide 0, only 1 divides 1.
Coprime-of-0-condition : ∀{x} → Coprime(0)(x) → (x ≡ 1)
Coprime-of-0-condition {0}       (intro n1) = n1 Div𝟎 Div𝟎
Coprime-of-0-condition {1}       (intro n1) = [≡]-intro
Coprime-of-0-condition {𝐒(𝐒(x))} (intro n1) = n1 Div𝟎 divides-reflexivity

-- 1 is coprime to all numbers because only 1 divides 1.
Coprime-of-1 : Coprime(1)(x)
Coprime.proof (Coprime-of-1 {x}) {n} n1 nx = [1]-only-divides-[1] n1

Coprime-of-[+] : Coprime(x)(y) → Coprime(x)(x + y)
Coprime.proof (Coprime-of-[+] {x}{y} (intro proof)) {n} nx nxy = proof {n} nx ([↔]-to-[→] (divides-without-[+] nxy) nx)

-- Coprimality is obviously equivalent to the greatest common divisor being 1 by definition.
Coprime-gcd : Coprime(x)(y) ↔ (gcd(x)(y) ≡ 1)
Coprime-gcd = [↔]-transitivity ([↔]-intro l r) Gcd-gcd-value where
  l : Coprime(x)(y) ← Gcd(x)(y) 1
  Coprime.proof (l p) nx ny = [1]-only-divides-[1] (Gcd.maximum₂ p nx ny)

  r : Coprime(x)(y) → Gcd(x)(y) 1
  Gcd.divisor(r (intro coprim)) 𝟎     = [1]-divides
  Gcd.divisor(r (intro coprim)) (𝐒 𝟎) = [1]-divides
  Gcd.maximum(r (intro coprim)) dv with [≡]-intro ← coprim (dv 𝟎) (dv(𝐒 𝟎)) = [1]-divides

-- A smaller number and a greater prime number is coprime.
-- If the greater number is prime, then no smaller number will divide it except for 1, and greater numbers never divide smaller ones.
-- Examples (y = 7):
--   The prime factors of 7 is only itself (because it is prime).
--   Then the only alternatives for x are:
--   x ∈ {1,2,3,4,5,6}
--   None of them is able to have 7 as a prime factor because it is greater:
--   1=1, 2=2, 3=3, 4=2⋅2, 5=5, 6=2⋅3
Coprime-of-Prime : (𝐒(x) < y) → Prime(y) → Coprime(𝐒(x))(y)
Coprime.proof (Coprime-of-Prime (succ(succ lt)) prim) nx ny with prime-only-divisors prim ny
Coprime.proof (Coprime-of-Prime (succ(succ lt)) prim) nx ny | [∨]-introₗ n1        = n1
Coprime.proof (Coprime-of-Prime (succ(succ lt)) prim) nx ny | [∨]-introᵣ [≡]-intro with () ← [≤]-to-[≯] lt ([≤]-without-[𝐒] (divides-upper-limit nx))

-- A prime number either divides a number or forms a coprime pair.
-- If a prime number does not divide a number, then it cannot share any divisors because by definition, a prime only has 1 as a divisor.
Prime-to-div-or-coprime : Prime(x) → ((x ∣ y) ∨ Coprime(x)(y))
Prime-to-div-or-coprime {y = y} (intro {x} prim) = [¬→]-disjunctive-formᵣ ⦃ decider-to-classical ⦄ (intro ∘ coprim) where
  coprim : (𝐒(𝐒(x)) ∤ y) → ∀{n} → (n ∣ 𝐒(𝐒(x))) → (n ∣ y) → (n ≡ 1)
  coprim nxy {𝟎}   nx ny with () ← [0]-divides-not nx
  coprim nxy {𝐒 n} nx ny with prim nx
  ... | [∨]-introₗ [≡]-intro = [≡]-intro
  ... | [∨]-introᵣ [≡]-intro with () ← nxy ny

divides-to-converse-coprime : ∀{x y z} → (x ∣ y) → Coprime(y)(z) → Coprime(x)(z)
divides-to-converse-coprime xy (intro yz) = intro(nx ↦ nz ↦ yz (transitivity(_∣_) nx xy) nz)


{-# OPTIONS --exact-split #-}
module ExactSplitBerry where

data Bool : Set where
  true false : Bool

maj : Bool → Bool → Bool → Bool
maj true  true  true  = true
maj x     true  false = x
maj false y     true  = y
maj true  false z     = z
maj false false false = false


module Data.Option.Equiv where

import      Lvl
open import Data.Option
open import Structure.Function
open import Structure.Function.Domain
open import Structure.Setoid
open import Type

private variable ℓ ℓₑ ℓₑₐ : Lvl.Level
private variable A : Type{ℓ}

record Extensionality ⦃ equiv-A : Equiv{ℓₑₐ}(A) ⦄ (equiv : Equiv{ℓₑ}(Option(A))) : Type{Lvl.of(A) Lvl.⊔ ℓₑₐ Lvl.⊔ ℓₑ} where
  constructor intro
  private instance _ = equiv
  field
    ⦃ Some-function ⦄ : Function Some
    ⦃ Some-injective ⦄ : Injective Some
    cases-inequality : ∀{x : A} → (None ≢ Some(x))


module Data.Option.Equiv.Id where

import      Lvl
open import Data.Option
open import Data.Option.Functions
open import Data.Option.Equiv
open import Relator.Equals
open import Relator.Equals.Proofs.Equiv
open import Structure.Function
open import Structure.Function.Domain
open import Type

private variable ℓ : Lvl.Level
private variable T A B : Type{ℓ}
private variable f : A → B
private variable o : Option T

instance
  Some-injectivity : Injective {B = Option(T)} (Some)
  Injective.proof Some-injectivity [≡]-intro = [≡]-intro

instance
  Id-Option-extensionality : Extensionality{A = T} ([≡]-equiv)
  Extensionality.cases-inequality Id-Option-extensionality ()

map-injectivity : ⦃ inj-f : Injective(f) ⦄ → Injective(map f)
Injective.proof map-injectivity           {None}   {None}   [≡]-intro = [≡]-intro
Injective.proof (map-injectivity {f = f}) {Some x} {Some y} p         = congruence₁(Some) (injective f(injective(Some) p))

-- TODO: Generalize and move
map-None : (map f o ≡ None) → (o ≡ None)
map-None {o = None} p = [≡]-intro


module examplesPaperJFP.safeFibStackMachineObjectOriented where

open import Data.Nat
open import Data.List
open import Data.Vec
open import Data.Sum
open import Data.Fin renaming (_+_ to _+f_)
open import Data.Product
open import examplesPaperJFP.StatefulObject
open import examplesPaperJFP.StackBisim

open import examplesPaperJFP.triangleRightOperator

{- Object based version of safe stack
   it is essentially the last part of safeFibStackMachine.agda
   with the names simplified -}

{- the state is what we are computing right now:
   fib n  menas we need to compute fib n
   val k  means we have computed   the value k
-}

data FibState : Set where
  fib  :  ℕ  →  FibState
  val  :  ℕ  →  FibState

data FibStackEl : Set where
  _+•     :  ℕ  →  FibStackEl
  •+fib_  :  ℕ  →  FibStackEl

FibStack : ℕ → Set
FibStack = Objectˢ (StackInterfaceˢ FibStackEl)

FibStackmachine : Set
FibStackmachine = Σ[ n ∈ ℕ ] (FibState × FibStack n)

reduce : FibStackmachine →  FibStackmachine ⊎ ℕ
reduce  (n      ,  fib 0             ,  stack)  =  inj₁ (n  ,  val 1  ,  stack)
reduce  (n      ,  fib 1             ,  stack)  =  inj₁ (n  ,  val 1  ,  stack)
reduce  (n      ,  fib (suc (suc m)) ,  stack)  =
        objectMethod stack (push (•+fib m))   ▹   λ  {  (_ , stack₁) →
        inj₁ ( suc n , fib (suc m) , stack₁)         }
reduce  (0      ,  val k             ,  stack)  =   inj₂ k
reduce  (suc n  ,  val k             ,  stack)  =
        objectMethod stack pop                ▹   λ  {  (k′ +•    , stack₁) →
        inj₁ (n , val (k′ + k) , stack₁)
                                                     ;  (•+fib m  , stack₁) →
        objectMethod stack₁ (push (k +•))     ▹   λ  {  (_ , stack₂) →
        inj₁ (suc n , fib m , stack₂)                }}

iter : (m : ℕ) → FibStackmachine →  FibStackmachine ⊎ ℕ
iter  0        s  =  inj₁ s
iter  (suc n)  s  with  reduce s
... |  inj₁ s′    =  iter n s′
... |  inj₂ m     =  inj₂ m

computeFib : ℕ → ℕ →  FibStackmachine ⊎ ℕ
computeFib n m = iter n (0 , fib m , stack [])

fibO0 :  FibStackmachine ⊎ ℕ
fibO0 = computeFib 2 0

-- evaluates to inj₂ 1

fibO1 :  FibStackmachine ⊎ ℕ
fibO1 = computeFib 2 1
-- evaluates to inj₂ 1

fibO2 :  FibStackmachine ⊎ ℕ
fibO2 = computeFib 10 2
-- evaluates to inj₂ 2

fibO3 :  FibStackmachine ⊎ ℕ
fibO3 = computeFib 14 3
-- evaluates to inj₂ 3

fibO4 :  FibStackmachine ⊎ ℕ
fibO4 = computeFib 30 4
-- evaluates to inj₂ 5

fibO5 :  FibStackmachine ⊎ ℕ
fibO5 = computeFib 30 5
-- evaluates to inj₂ 8

{-# TERMINATING #-}
computeFibRec : FibStackmachine → ℕ
computeFibRec s with reduce s
... | inj₁ s′   = computeFibRec s′
... | inj₂ k    = k

fibUsingStack : ℕ → ℕ
fibUsingStack m = computeFibRec (0 , fib m , stack [])

test : List ℕ
test = fibUsingStack 0 ∷ fibUsingStack 1 ∷ fibUsingStack 2 ∷ fibUsingStack 3 ∷ fibUsingStack 4 ∷ fibUsingStack 5 ∷ fibUsingStack 6  ∷ []

testExpected : List ℕ
testExpected = 1 ∷ 1 ∷ 2 ∷ 3 ∷ 5 ∷ 8 ∷ 13 ∷ []


{-# OPTIONS --safe --without-K #-}
open import Relation.Binary

module Data.List.Membership.Setoid.Distinct  where

open import Data.List as List using (List; [];  _∷_; _++_)
open import Data.List.Any as Any hiding (map; head; tail)
open import Data.List.Any.Properties

open import Relation.Binary.PropositionalEquality as P using (_≡_)
open import Function
open import Function.Equivalence using (_⇔_; equivalence)
open import Function.Equality using (_⟨$⟩_)
open import Function.Inverse using ()
open import Function.Injection using (_↣_; Injection)
open import Data.Product hiding (map)
open import Data.Sum     hiding (map)
import Level as L
open import Data.Fin as Fin using (Fin)
open import Data.Nat as ℕ

module _ {a p} {S : Setoid a p} where
  open Setoid S renaming (Carrier to A)
  open import Data.List.Membership.Setoid (S)
  open import Data.List.Membership.Setoid.Properties
  open import Data.List.Membership.Setoid.Disjoint (S) renaming (Disjoint to _⋈_)
  open import Data.List.Membership.Setoid.Trans (S)
  open import Data.Empty
  data Distinct : List A → Set (a L.⊔ p) where
    distinct-[] : Distinct []
    _distinct-∷_by_ : ∀ x {xs} → Distinct xs → x ∉ xs → Distinct (x ∷ xs)

  head : ∀ {x}{xs : List A} → Distinct (x ∷ xs) → A
  head (x distinct-∷ _ by _) = x

  tail : ∀ {x}{xs : List A} → Distinct (x ∷ xs) → Distinct xs
  tail (_ distinct-∷ dis by _) = dis

  head∉tail : ∀ {x}{xs : List A} → Distinct (x ∷ xs) → x ∉ xs
  head∉tail (_ distinct-∷ _ by x∉xs) = x∉xs

  distinct-[_] : ∀ x → Distinct (List.[ x ])
  distinct-[ x ] = x distinct-∷ distinct-[] by (λ ())

  ⋈-++ : ∀ (xs ys : List A) →
    Distinct (xs ++ ys) ⇔ (Distinct xs × Distinct ys × xs ⋈ ys)
  ⋈-++ xs ys = equivalence to from
    where
      to : ∀ {xs ys : List A} → Distinct (xs ++ ys) → (Distinct xs × Distinct ys × xs ⋈ ys)
      to {[]} dys = distinct-[] , dys , disjoint-[]ʳ
      to {x ∷ xs} {ys} (.x distinct-∷ dis by x∉xsys) with to {xs = xs} dis
      ... | dxs , dys , xs⋈ys = x distinct-∷ dxs by (λ x∈xs → x∉xsys (++⁺ˡ x∈xs)) , dys ,
            λ { (here px) ∈ys → x∉xsys (++⁺ʳ xs (≈-trans-∈ (sym px) ∈ys)) ; (there ∈xs) ∈ys → xs⋈ys ∈xs ∈ys}

      from : ∀ {xs ys : List A} →
           (Distinct xs × Distinct ys × xs ⋈ ys) → Distinct (xs ++ ys)
      from (distinct-[] , dys , xs⋈ys) = dys
      from {xs = .x ∷ xs} ((x distinct-∷ dxs by x∉xs) , dys , xxs⋈ys) with from (dxs , dys , xxs⋈ys ∘ there)
      ... | dxsys = x distinct-∷ dxsys by λ x∈xsys → case ++⁻ xs x∈xsys of λ { (inj₁ x∈xs) → x∉xs x∈xs
                                                                               ; (inj₂ x∈ys) → xxs⋈ys (here refl) x∈ys}

  lookup-injective : {xs : List A}(dxs : Distinct xs) → ∀ {i j} → List.lookup xs i ≡ List.lookup xs j → i ≡ j
  lookup-injective distinct-[] {()} {()} _
  lookup-injective (x distinct-∷ dxs by x∉xs) {Fin.zero} {Fin.zero} _ = P.refl
  lookup-injective (x distinct-∷ dxs by x∉xs) {Fin.suc i} {Fin.suc j} eq = P.cong Fin.suc (lookup-injective dxs eq)
  lookup-injective {xs} (x distinct-∷ dxs by x∉xs) {Fin.zero} {Fin.suc j} eq rewrite eq = ⊥-elim (x∉xs (∈-lookup S _ j))
  lookup-injective (x distinct-∷ dxs by x∉xs) {Fin.suc i} {Fin.zero} eq rewrite P.sym eq = ⊥-elim (x∉xs (∈-lookup S _ i))

module _ {a₁ a₂ p₁ p₂}{S₁ : Setoid a₁ p₁} {S₂ : Setoid a₂ p₂} where
  open Setoid S₁ renaming (Carrier to A) using ()
  open Setoid S₂ renaming (Carrier to B) using ()
  open import Data.List.Membership.Setoid (S₂) renaming (_∉_ to _∉₂_) using ()
  open import Data.List.Membership.Setoid.Properties
  open import Data.List.Membership.Setoid.Trans (S₁)
  map : (f : Injection S₁ S₂) → ∀ {xs : List A} → Distinct {S = S₁} xs → Distinct {S = S₂} (List.map (Injection.to f ⟨$⟩_) xs)
  map f {[]} distinct-[] = distinct-[]
  map f {.x ∷ xs} (x distinct-∷ dis by x∉xs) = fx distinct-∷ map f dis by lemma
      where
        fx = Injection.to f ⟨$⟩ x

        lemma : fx ∉₂ List.map (Injection.to f ⟨$⟩_) xs
        lemma p with ∈-map⁻ S₁ S₂ p
        ... | _ , y∈xs , fx≈fy = x∉xs (≈-trans-∈ (Injection.injective f fx≈fy) y∈xs)


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

open import Algebra.Structures.Bundles.Field

module Algebra.Linear.Morphism
  {k ℓᵏ} (K : Field k ℓᵏ)
  where

open import Algebra.Linear.Morphism.Definitions K public
open import Algebra.Linear.Morphism.Bundles     K public
open import Algebra.Linear.Morphism.VectorSpace K public


module Numeral.Natural.Function.Proofs where

import      Lvl
open import Data.Tuple
open import Functional
open import Logic.Propositional
open import Logic.Propositional.Theorems
open import Numeral.Natural
open import Numeral.Natural.Function
open import Numeral.Natural.Relation.Order as ≤ using (_≤_ ; _≥_)
open import Numeral.Natural.Oper
open import Numeral.Natural.Oper.Proofs
open import Numeral.Natural.Oper.Proofs.Order
open import Numeral.Natural.Relation.Order.Proofs
open import Relator.Equals
open import Relator.Equals.Proofs
open import Structure.Function.Domain
import      Structure.Operator.Names as Names
open import Structure.Operator.Properties
open import Structure.Relator.Properties
open import Syntax.Transitivity

max-0ₗ : ∀{b} → (max 𝟎 b ≡ b)
max-0ₗ {𝟎}   = [≡]-intro
max-0ₗ {𝐒 b} = [≡]-intro
{-# REWRITE max-0ₗ #-}

max-0ᵣ : ∀{a} → (max a 𝟎 ≡ a)
max-0ᵣ {𝟎}   = [≡]-intro
max-0ᵣ {𝐒 a} = [≡]-intro
{-# REWRITE max-0ᵣ #-}

min-0ₗ : ∀{b} → (min 𝟎 b ≡ 𝟎)
min-0ₗ {𝟎}   = [≡]-intro
min-0ₗ {𝐒 b} = [≡]-intro
{-# REWRITE min-0ₗ #-}

min-0ᵣ : ∀{a} → (min a 𝟎 ≡ 𝟎)
min-0ᵣ {𝟎}   = [≡]-intro
min-0ᵣ {𝐒 a} = [≡]-intro
{-# REWRITE min-0ᵣ #-}

instance
  min-idempotence : Idempotence(min)
  min-idempotence = intro proof where
    proof : Names.Idempotence(min)
    proof{𝟎}   = [≡]-intro
    proof{𝐒 x} = [≡]-with(𝐒) (proof{x})

instance
  max-idempotence : Idempotence(max)
  max-idempotence = intro proof where
    proof : Names.Idempotence(max)
    proof{𝟎}   = [≡]-intro
    proof{𝐒 x} = [≡]-with(𝐒) (proof{x})

max-elementary : ∀{a b} → (max(a)(b) ≡ a + (b −₀ a))
max-elementary {𝟎}    {𝟎}    = [≡]-intro
max-elementary {𝟎}    {𝐒(b)} = [≡]-intro
max-elementary {𝐒(a)} {𝟎}    = [≡]-intro
max-elementary {𝐒(a)} {𝐒(b)} = [≡]-with(𝐒) (max-elementary {a} {b})

min-elementary : ∀{a b} → (min(a)(b) ≡ b −₀ (b −₀ a))
min-elementary {𝟎}    {𝟎}    = [≡]-intro
min-elementary {𝟎}    {𝐒(b)} = [≡]-intro
min-elementary {𝐒(a)} {𝟎}    = [≡]-intro
min-elementary {𝐒(a)} {𝐒(b)} = ([≡]-with(𝐒) (min-elementary {a} {b})) 🝖 (symmetry(_≡_) ([↔]-to-[→] [−₀][𝐒]ₗ-equality ([−₀]-lesser {b}{a})))

instance
  min-commutativity : Commutativity(min)
  Commutativity.proof(min-commutativity) = proof where
    proof : Names.Commutativity(min)
    proof{𝟎}   {𝟎}    = [≡]-intro
    proof{𝟎}   {𝐒(b)} = [≡]-intro
    proof{𝐒(a)}{𝟎}    = [≡]-intro
    proof{𝐒(a)}{𝐒(b)} = [≡]-with(𝐒) (proof{a}{b})

instance
  min-associativity : Associativity(min)
  Associativity.proof(min-associativity) = proof where
    proof : Names.Associativity(min)
    proof{𝟎}   {𝟎}   {𝟎}    = [≡]-intro
    proof{𝟎}   {𝟎}   {𝐒(c)} = [≡]-intro
    proof{𝟎}   {𝐒(b)}{𝟎}    = [≡]-intro
    proof{𝐒(a)}{𝟎}   {𝟎}    = [≡]-intro
    proof{𝟎}   {𝐒(b)}{𝐒(c)} = [≡]-intro
    proof{𝐒(a)}{𝟎}   {𝐒(c)} = [≡]-intro
    proof{𝐒(a)}{𝐒(b)}{𝟎}    = [≡]-intro
    proof{𝐒(a)}{𝐒(b)}{𝐒(c)} = [≡]-with(𝐒) (proof{a}{b}{c})
    -- min(min(𝐒x)(𝐒y))(𝐒z)
    -- = min(𝐒min(x)(y))(𝐒z)
    -- = 𝐒(min(min(x)(y))(z))
    -- = 𝐒(min(x)(min(y)(z)))
    -- = min(𝐒x)(𝐒min(y)(z))
    -- = min(𝐒x)(min(𝐒y)(𝐒z)

instance
  min-orderₗ : ∀{a b} → (min(a)(b) ≤ a)
  min-orderₗ {𝟎}   {𝟎}    = [≤]-minimum {𝟎}
  min-orderₗ {𝐒(a)}{𝟎}    = [≤]-minimum {𝐒(a)}
  min-orderₗ {𝟎}   {𝐒(b)} = [≤]-minimum {𝟎}
  min-orderₗ {𝐒(a)}{𝐒(b)} = [≤]-with-[𝐒] ⦃ min-orderₗ {a}{b} ⦄

instance
  min-orderᵣ : ∀{a b} → (min(a)(b) ≤ b)
  min-orderᵣ {𝟎}   {𝟎}    = [≤]-minimum {𝟎}
  min-orderᵣ {𝐒(a)}{𝟎}    = [≤]-minimum {𝟎}
  min-orderᵣ {𝟎}   {𝐒(b)} = [≤]-minimum {𝐒(b)}
  min-orderᵣ {𝐒(a)}{𝐒(b)} = [≤]-with-[𝐒] ⦃ min-orderᵣ {a}{b} ⦄

min-arg : ∀{a b} → (min(a)(b) ≡ a) ∨ (min(a)(b) ≡ b)
min-arg {𝟎}   {𝟎}    = [∨]-introₗ([≡]-intro)
min-arg {𝟎}   {𝐒(b)} = [∨]-introₗ([≡]-intro)
min-arg {𝐒(a)}{𝟎}    = [∨]-introᵣ([≡]-intro)
min-arg {𝐒(a)}{𝐒(b)} = constructive-dilemma ([≡]-with(𝐒)) ([≡]-with(𝐒)) (min-arg {a}{b})

min-defₗ : ∀{a b} → (a ≤ b) ↔ (min(a)(b) ≡ a)
min-defₗ {a}{b} = [↔]-intro (l{a}{b}) (r{a}{b}) where
  l : ∀{a b} → (a ≤ b) ← (min(a)(b) ≡ a)
  l {𝟎}   {𝟎}    _      = [≤]-minimum {𝟎}
  l {𝟎}   {𝐒(b)} _      = [≤]-minimum {𝐒(b)}
  l {𝐒(_)}{𝟎}    ()
  l {𝐒(a)}{𝐒(b)} minaba = [≤]-with-[𝐒] ⦃ l{a}{b} (injective(𝐒) (minaba)) ⦄

  r : ∀{a b} → (a ≤ b) → (min(a)(b) ≡ a)
  r {𝟎}   {𝟎}    _                     = [≡]-intro
  r {𝟎}   {𝐒(b)} _                     = [≡]-intro
  r {𝐒(_)}{𝟎}    ()
  r {𝐒(a)}{𝐒(b)} (≤.succ ab) = [≡]-with(𝐒) (r{a}{b} (ab))

min-defᵣ : ∀{a b} → (b ≤ a) ↔ (min(a)(b) ≡ b)
min-defᵣ {a}{b} = [≡]-substitutionᵣ (commutativity(min)) {expr ↦ (b ≤ a) ↔ (expr ≡ b)} (min-defₗ{b}{a})

instance
  max-commutativity : Commutativity(max)
  Commutativity.proof(max-commutativity) = proof where
    proof : Names.Commutativity(max)
    proof{𝟎}   {𝟎}    = [≡]-intro
    proof{𝟎}   {𝐒(b)} = [≡]-intro
    proof{𝐒(a)}{𝟎}    = [≡]-intro
    proof{𝐒(a)}{𝐒(b)} = [≡]-with(𝐒) (proof{a}{b})

instance
  max-associativity : Associativity(max)
  Associativity.proof(max-associativity) = proof where
    proof : Names.Associativity(max)
    proof{𝟎}   {𝟎}   {𝟎}    = [≡]-intro
    proof{𝟎}   {𝟎}   {𝐒(c)} = [≡]-intro
    proof{𝟎}   {𝐒(b)}{𝟎}    = [≡]-intro
    proof{𝐒(a)}{𝟎}   {𝟎}    = [≡]-intro
    proof{𝟎}   {𝐒(b)}{𝐒(c)} = [≡]-intro
    proof{𝐒(a)}{𝟎}   {𝐒(c)} = [≡]-intro
    proof{𝐒(a)}{𝐒(b)}{𝟎}    = [≡]-intro
    proof{𝐒(a)}{𝐒(b)}{𝐒(c)} = [≡]-with(𝐒) (proof{a}{b}{c})

-- max-[+]-distributivityₗ : Distributivityₗ(max)
-- max-[+]-distributivityᵣ : Distributivityᵣ(max)

instance
  max-orderₗ : ∀{a b} → (max(a)(b) ≥ a)
  max-orderₗ {𝟎}   {𝟎}    = [≤]-minimum {max(𝟎)(𝟎)}
  max-orderₗ {𝐒(a)}{𝟎}    = reflexivity(_≥_)
  max-orderₗ {𝟎}   {𝐒(b)} = [≤]-minimum {max(𝟎)(𝐒(b))}
  max-orderₗ {𝐒(a)}{𝐒(b)} = [≤]-with-[𝐒] ⦃ max-orderₗ {a}{b} ⦄

instance
  max-orderᵣ : ∀{a b} → (max(a)(b) ≥ b)
  max-orderᵣ {𝟎}   {𝟎}    = [≤]-minimum {max(𝟎)(𝟎)}
  max-orderᵣ {𝐒(a)}{𝟎}    = [≤]-minimum {max(𝐒(a))(𝟎)}
  max-orderᵣ {𝟎}   {𝐒(b)} = reflexivity(_≥_)
  max-orderᵣ {𝐒(a)}{𝐒(b)} = [≤]-with-[𝐒] ⦃ max-orderᵣ {a}{b} ⦄

max-arg : ∀{a b} → (max(a)(b) ≡ a)∨(max(a)(b) ≡ b)
max-arg {𝟎}   {𝟎}    = [∨]-introₗ([≡]-intro)
max-arg {𝟎}   {𝐒(b)} = [∨]-introᵣ([≡]-intro)
max-arg {𝐒(a)}{𝟎}    = [∨]-introₗ([≡]-intro)
max-arg {𝐒(a)}{𝐒(b)} = constructive-dilemma ([≡]-with(𝐒)) ([≡]-with(𝐒)) (max-arg {a}{b})

max-defₗ : ∀{a b} → (a ≥ b) ↔ (max(a)(b) ≡ a)
max-defₗ {a}{b} = [↔]-intro (l{a}{b}) (r{a}{b}) where
  l : ∀{a b} → (a ≥ b) ← (max(a)(b) ≡ a)
  l {𝟎}   {𝟎}    _      = [≤]-minimum {𝟎}
  l {𝟎}   {𝐒(_)} ()
  l {𝐒(a)}{𝟎}    _      = [≤]-minimum {𝐒(a)}
  l {𝐒(a)}{𝐒(b)} maxaba = [≤]-with-[𝐒] ⦃ l{a}{b}(injective(𝐒) (maxaba)) ⦄

  r : ∀{a b} → (a ≥ b) → (max(a)(b) ≡ a)
  r {𝟎}   {𝟎}    _                     = [≡]-intro
  r {𝟎}   {𝐒(_)} ()
  r {𝐒(_)}{𝟎}    _                     = [≡]-intro
  r {𝐒(a)}{𝐒(b)} (≤.succ ab) = [≡]-with(𝐒) (r{a}{b} (ab))

max-defᵣ : ∀{a b} → (b ≥ a) ↔ (max(a)(b) ≡ b)
max-defᵣ {a}{b} = [≡]-substitutionᵣ (commutativity(max)) {expr ↦ (b ≥ a) ↔ (expr ≡ b)} (max-defₗ{b}{a})

min-with-max : ∀{a b} → (min(a)(b) ≡ (a + b) −₀ max(a)(b))
min-with-max {a}{b} =
  min(a)(b)                 🝖-[ min-elementary{a}{b} ]
  b −₀ (b −₀ a)             🝖-[ [−₀][+]ₗ-nullify {a}{b}{b −₀ a} ]-sym
  (a + b) −₀ (a + (b −₀ a)) 🝖-[ [≡]-with((a + b) −₀_) (max-elementary{a}{b}) ]-sym
  (a + b) −₀ max(a)(b)      🝖-end

max-with-min : ∀{a b} → (max(a)(b) ≡ (a + b) −₀ min(a)(b))
max-with-min {a}{b} with [≤][>]-dichotomy {a}{b}
... | [∨]-introₗ ab =
  max(a)(b)            🝖-[ [↔]-to-[→] max-defᵣ ab ]
  b                    🝖-[ [−₀]ₗ[+]ₗ-nullify {a}{b} ]-sym
  (a + b) −₀ a         🝖-[ [≡]-with((a + b) −₀_) ([↔]-to-[→] min-defₗ ab) ]-sym
  (a + b) −₀ min(a)(b) 🝖-end
... | [∨]-introᵣ 𝐒ba with ba ← [≤]-predecessor 𝐒ba =
  max(a)(b)            🝖-[ [↔]-to-[→] max-defₗ ba ]
  a                    🝖-[ [−₀]ₗ[+]ᵣ-nullify {a}{b} ]-sym
  (a + b) −₀ b         🝖-[ [≡]-with((a + b) −₀_) ([↔]-to-[→] min-defᵣ ba) ]-sym
  (a + b) −₀ min(a)(b) 🝖-end

[≤]-conjunction-min : ∀{a b c} → ((a ≤ b) ∧ (a ≤ c)) ↔ (a ≤ min b c)
[≤]-conjunction-min {a}{b}{c} = [↔]-intro (a≤bc ↦ [∧]-intro (a≤bc 🝖 min-orderₗ) (a≤bc 🝖 min-orderᵣ)) (uncurry r) where
  r : ∀{a b c} → (a ≤ b) → (a ≤ c) → (a ≤ min b c)
  r {.0}     {b}      {c}     ≤.min  ≤.min = ≤.min
  r {.(𝐒 a)} {.(𝐒 b)} {.(𝐒 c)} (≤.succ {a} {b} ab) (≤.succ {y = c} ac) = [≤]-with-[𝐒] ⦃ r {a}{b}{c} ab ac ⦄

[≤]-conjunction-max : ∀{a b c} → ((a ≤ c) ∧ (b ≤ c)) ↔ (max a b ≤ c)
[≤]-conjunction-max {a}{b}{c} = [↔]-intro (ab≤c ↦ [∧]-intro (max-orderₗ 🝖 ab≤c) ((max-orderᵣ 🝖 ab≤c))) (uncurry r) where
  r : ∀{a b c} → (a ≤ c) → (b ≤ c) → (max a b ≤ c)
  r {.0}     {b@(𝐒 _)}{c}      ≤.min  bc     = bc
  r {a}      {.0}     {c}      ac     ≤.min  = ac
  r {𝐒 a} {𝐒 b} {𝐒 c} (≤.succ ac) (≤.succ bc) = [≤]-with-[𝐒] ⦃ r {a}{b}{c} ac bc ⦄

[≤]-disjunction-min : ∀{a b c} → ((a ≤ c) ∨ (b ≤ c)) ↔ (min a b ≤ c)
[≤]-disjunction-min = [↔]-intro
  (ab≤c ↦ [∨]-elim2
    ((_🝖 ab≤c) ∘ [≡]-to-[≤] ∘ symmetry(_≡_))
    ((_🝖 ab≤c) ∘ [≡]-to-[≤] ∘ symmetry(_≡_))
    min-arg
  )
  ([∨]-elim
    (min-orderₗ 🝖_)
    (min-orderᵣ 🝖_)
  )

[≤]-disjunction-max : ∀{a b c} → ((a ≤ b) ∨ (a ≤ c)) ↔ (a ≤ max b c)
[≤]-disjunction-max = [↔]-intro
  (a≤bc ↦ [∨]-elim2
    ((_🝖 a≤bc) ∘ [≡]-to-[≤])
    ((_🝖 a≤bc) ∘ [≡]-to-[≤])
    max-arg
  )
  ([∨]-elim
    (_🝖 max-orderₗ)
    (_🝖 max-orderᵣ)
  )

min-order-max : ∀{a b} → (min(a)(b) ≤ max(a)(b))
min-order-max {𝟎}   {b}   = [≤]-minimum
min-order-max {𝐒 a} {𝟎}   = [≤]-minimum
min-order-max {𝐒 a} {𝐒 b} = [≤]-with-[𝐒] ⦃ min-order-max {a}{b} ⦄

max-order-[+] : ∀{a b} → (max(a)(b) ≤ a + b)
max-order-[+] {a}{b} = [↔]-to-[→] [≤]-conjunction-max ([∧]-intro [≤]-of-[+]ₗ ([≤]-of-[+]ᵣ {a}{b}))


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

module canonical-value-forms where
  canonical-value-forms-b : ∀{Δ d} →
                            Δ , ∅ ⊢ d :: b →
                            d val →
                            d == c
  canonical-value-forms-b TAConst VConst = refl
  canonical-value-forms-b (TAVar x₁) ()
  canonical-value-forms-b (TAAp wt wt₁) ()
  canonical-value-forms-b (TAEHole x x₁) ()
  canonical-value-forms-b (TANEHole x wt x₁) ()
  canonical-value-forms-b (TACast wt x) ()
  canonical-value-forms-b (TAFailedCast wt x x₁ x₂) ()

  canonical-value-forms-arr : ∀{Δ d τ1 τ2} →
                              Δ , ∅ ⊢ d :: (τ1 ==> τ2) →
                              d val →
                              Σ[ x ∈ Nat ] Σ[ d' ∈ ihexp ]
                                ((d == (·λ x [ τ1 ] d')) ×
                                 (Δ , ■ (x , τ1) ⊢ d' :: τ2))
  canonical-value-forms-arr (TAVar x₁) ()
  canonical-value-forms-arr (TALam _ wt) VLam = _ , _ , refl , wt
  canonical-value-forms-arr (TAAp wt wt₁) ()
  canonical-value-forms-arr (TAEHole x x₁) ()
  canonical-value-forms-arr (TANEHole x wt x₁) ()
  canonical-value-forms-arr (TACast wt x) ()
  canonical-value-forms-arr (TAFailedCast x x₁ x₂ x₃) ()

  -- this argues (somewhat informally, because you still have to inspect
  -- the types of the theorems above and manually verify this property)
  -- that we didn't miss any cases above; this intentionally will make this
  -- file fail to typecheck if we added more types, hopefully forcing us to
  -- remember to add canonical forms lemmas as appropriate
  canonical-value-forms-coverage1 : ∀{Δ d τ} →
                                   Δ , ∅ ⊢ d :: τ →
                                   d val →
                                   τ ≠ b →
                                   ((τ1 : htyp) (τ2 : htyp) → τ ≠ (τ1 ==> τ2)) →
                                   ⊥
  canonical-value-forms-coverage1 TAConst VConst = λ z _ → z refl
  canonical-value-forms-coverage1 (TAVar x₁) ()
  canonical-value-forms-coverage1 (TALam _ wt) VLam = λ _ z → z _ _ refl
  canonical-value-forms-coverage1 (TAAp wt wt₁) ()
  canonical-value-forms-coverage1 (TAEHole x x₁) ()
  canonical-value-forms-coverage1 (TANEHole x wt x₁) ()
  canonical-value-forms-coverage1 (TACast wt x) ()
  canonical-value-forms-coverage1 (TAFailedCast wt x x₁ x₂) ()

  canonical-value-forms-coverage2 : ∀{Δ d} →
                                   Δ , ∅ ⊢ d :: ⦇-⦈ →
                                   d val →
                                   ⊥
  canonical-value-forms-coverage2 (TAVar x₁) ()
  canonical-value-forms-coverage2 (TAAp wt wt₁) ()
  canonical-value-forms-coverage2 (TAEHole x x₁) ()
  canonical-value-forms-coverage2 (TANEHole x wt x₁) ()
  canonical-value-forms-coverage2 (TACast wt x) ()
  canonical-value-forms-coverage2 (TAFailedCast wt x x₁ x₂) ()


module Example where

open import Prelude
import Typed

data Data : Set where
  nat  : Data
  bool : Data

Datatype : Data -> List (List Data)
Datatype nat  = ε ◄ ε ◄ (ε ◄ nat)
Datatype bool = ε ◄ ε ◄ ε

data Effect : Set where

data _⊆_ : Effect -> Effect -> Set where
  refl⊆  : forall {M} -> M ⊆ M

Monad : Effect -> Set -> Set
Monad e A = A

return : forall {M A} -> A -> Monad M A
return x = x

map    : forall {M A B} -> (A -> B) -> Monad M A -> Monad M B
map f m = f m

join   : forall {M A} -> Monad M (Monad M A) -> Monad M A
join m = m

morph  : forall {M N} -> M ⊆ N -> (A : Set) -> Monad M A -> Monad N A
morph _ A x = x

open module TT =
       Typed Data Datatype
             Effect _⊆_
             Monad
             (\{M A} -> return {M}{A})
             (\{M A B} -> map {M}{A}{B})
             (\{M A} -> join {M}{A})
             morph

zero : forall {M Γ} -> InV M Γ (TyCon nat)
zero = con (tl hd) ⟨⟩

suc : forall {M Γ} -> InV M Γ (TyCon nat) -> InV M Γ (TyCon nat)
suc n = con hd (⟨⟩ ◃ n)

true : forall {M Γ} -> InV M Γ (TyCon bool)
true = con hd ⟨⟩

false : forall {M Γ} -> InV M Γ (TyCon bool)
false = con (tl hd) ⟨⟩


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

open import lib.Basics
open import lib.types.Pi

module lib.types.Group where

record GroupStructure {i} (El : Type i) --(El-level : has-level 0 El)
  : Type i where
  constructor group-structure
  field
    ident : El
    inv : El → El
    comp : El → El → El
    unitl : ∀ a → comp ident a == a
    unitr : ∀ a → comp a ident == a
    assoc   : ∀ a b c → comp (comp a b) c == comp a (comp b c)
    invl    : ∀ a → (comp (inv a) a) == ident
    invr    : ∀ a → (comp a (inv a)) == ident

record Group i : Type (lsucc i) where
  constructor group
  field
    El : Type i
    El-level : has-level 0 El
    group-struct : GroupStructure El
  open GroupStructure group-struct public

  ⊙El : Σ (Type i) (λ A → A)
  ⊙El = (El , ident)

Group₀ : Type (lsucc lzero)
Group₀ = Group lzero

is-abelian : ∀ {i} → Group i → Type i
is-abelian G = (a b : Group.El G) → Group.comp G a b == Group.comp G b a

module _ where
  open GroupStructure

  abstract
    group-structure= : ∀ {i} {A : Type i} (pA : has-level 0 A)
      {id₁ id₂ : A} {inv₁ inv₂ : A → A} {comp₁ comp₂ : A → A → A}
      → ∀ {unitl₁ unitl₂} → ∀ {unitr₁ unitr₂} → ∀ {assoc₁ assoc₂}
      → ∀ {invr₁ invr₂} → ∀ {invl₁ invl₂}
      → (id₁ == id₂) → (inv₁ == inv₂) → (comp₁ == comp₂)
      → Path {A = GroupStructure A}
          (group-structure id₁ inv₁ comp₁ unitl₁ unitr₁ assoc₁ invl₁ invr₁)
          (group-structure id₂ inv₂ comp₂ unitl₂ unitr₂ assoc₂ invl₂ invr₂)
    group-structure= pA {id₁ = id₁} {inv₁ = inv₁} {comp₁ = comp₁} idp idp idp =
      ap5 (group-structure id₁ inv₁ comp₁)
        (prop-has-all-paths (Π-level (λ _ → pA _ _)) _ _)
        (prop-has-all-paths (Π-level (λ _ → pA _ _)) _ _)
        (prop-has-all-paths
          (Π-level (λ _ → Π-level (λ _ → Π-level (λ _ → pA _ _)))) _ _)
        (prop-has-all-paths (Π-level (λ _ → pA _ _)) _ _)
        (prop-has-all-paths (Π-level (λ _ → pA _ _)) _ _)
      where
      ap5 : ∀ {j} {C D E F G H : Type j}
        {c₁ c₂ : C} {d₁ d₂ : D} {e₁ e₂ : E} {f₁ f₂ : F} {g₁ g₂ : G}
        (f : C → D → E → F → G → H)
        → (c₁ == c₂) → (d₁ == d₂) → (e₁ == e₂) → (f₁ == f₂) → (g₁ == g₂)
        → f c₁ d₁ e₁ f₁ g₁ == f c₂ d₂ e₂ f₂ g₂
      ap5 f idp idp idp idp idp = idp

    ↓-group-structure= : ∀ {i} {A B : Type i}
      (A-level : has-level 0 A)
      {GS : GroupStructure A} {HS : GroupStructure B} (p : A == B)
      → (ident GS == ident HS [ (λ C → C) ↓ p ])
      → (inv GS == inv HS [ (λ C → C → C) ↓ p ])
      → (comp GS == comp HS [ (λ C → C → C → C) ↓ p ])
      → GS == HS [ GroupStructure ↓ p ]
    ↓-group-structure= A-level idp = group-structure= A-level

module _ {i} (G : Group i) where
  private
    open Group G
    infix 80 _⊙_
    _⊙_ = comp

  group-inv-unique-l : (g h : El) → (g ⊙ h == ident) → inv h == g
  group-inv-unique-l g h p =
    inv h              =⟨ ! (unitl (inv h)) ⟩
    ident ⊙ inv h      =⟨ ! p |in-ctx (λ w → w ⊙ inv h) ⟩
    (g ⊙ h) ⊙ inv h    =⟨ assoc g h (inv h) ⟩
    g ⊙ (h ⊙ inv h)    =⟨ invr h |in-ctx (λ w → g ⊙ w) ⟩
    g ⊙ ident          =⟨ unitr g ⟩
    g                     ∎

  group-inv-unique-r : (g h : El) → (g ⊙ h == ident) → inv g == h
  group-inv-unique-r g h p =
    inv g              =⟨ ! (unitr (inv g)) ⟩
    inv g ⊙ ident      =⟨ ! p |in-ctx (λ w → inv g ⊙ w) ⟩
    inv g ⊙ (g ⊙ h)    =⟨ ! (assoc (inv g) g h) ⟩
    (inv g ⊙ g) ⊙ h    =⟨ invl g |in-ctx (λ w → w ⊙ h) ⟩
    ident ⊙ h          =⟨ unitl h ⟩
    h                     ∎

  group-inv-ident : inv ident == ident
  group-inv-ident =
    group-inv-unique-l ident ident (unitl ident)

  group-inv-comp : (g₁ g₂ : El) → inv (g₁ ⊙ g₂) == inv g₂ ⊙ inv g₁
  group-inv-comp g₁ g₂ =
    group-inv-unique-r (g₁ ⊙ g₂) (inv g₂ ⊙ inv g₁) $
      (g₁ ⊙ g₂) ⊙ (inv g₂ ⊙ inv g₁)
        =⟨ assoc g₁ g₂ (inv g₂ ⊙ inv g₁) ⟩
      g₁ ⊙ (g₂ ⊙ (inv g₂ ⊙ inv g₁))
        =⟨ ! (assoc g₂ (inv g₂) (inv g₁)) |in-ctx (λ w → g₁ ⊙ w) ⟩
      g₁ ⊙ ((g₂ ⊙ inv g₂) ⊙ inv g₁)
        =⟨ invr g₂ |in-ctx (λ w → g₁ ⊙ (w ⊙ inv g₁)) ⟩
      g₁ ⊙ (ident ⊙ inv g₁)
        =⟨ unitl (inv g₁) |in-ctx (λ w → g₁ ⊙ w) ⟩
      g₁ ⊙ inv g₁
        =⟨ invr g₁ ⟩
      ident ∎

  group-inv-inv : (g : El) → inv (inv g) == g
  group-inv-inv g = group-inv-unique-r (inv g) g (invl g)

  group-cancel-l : (g : El) {h k : El} → g ⊙ h == g ⊙ k → h == k
  group-cancel-l g {h} {k} p =
    h                  =⟨ ! (unitl h) ⟩
    ident ⊙ h          =⟨ ap (λ w → w ⊙ h) (! (invl g)) ⟩
    (inv g ⊙ g) ⊙ h    =⟨ assoc (inv g) g h ⟩
    inv g ⊙ (g ⊙ h)    =⟨ ap (λ w → inv g ⊙ w) p ⟩
    inv g ⊙ (g ⊙ k)    =⟨ ! (assoc (inv g) g k) ⟩
    (inv g ⊙ g) ⊙ k    =⟨ ap (λ w → w ⊙ k) (invl g) ⟩
    ident ⊙ k          =⟨ unitl k ⟩
    k ∎

  group-cancel-r : (g : El) {h k : El} → h ⊙ g == k ⊙ g → h == k
  group-cancel-r g {h} {k} p =
    h                  =⟨ ! (unitr h) ⟩
    h ⊙ ident          =⟨ ap (λ w → h ⊙ w) (! (invr g)) ⟩
    h ⊙ (g ⊙ inv g)    =⟨ ! (assoc h g (inv g)) ⟩
    (h ⊙ g) ⊙ inv g    =⟨ ap (λ w → w ⊙ inv g) p ⟩
    (k ⊙ g) ⊙ inv g    =⟨ assoc k g (inv g) ⟩
    k ⊙ (g ⊙ inv g)    =⟨ ap (λ w → k ⊙ w) (invr g) ⟩
    k ⊙ ident          =⟨ unitr k ⟩
    k ∎


{-# OPTIONS --cubical #-}

module Type.Cubical where

import      Lvl
open import Type

open import Agda.Primitive public
  using (SSet)

open import Agda.Primitive.Cubical public
  using ()
  renaming (I to Interval) -- _ : SSet(Lvl.𝟎). Inhabitants can be seen as points on a closed unit interval.

module Interval where
  open Agda.Primitive.Cubical public
    using (
      Partial ; -- _ : ∀{ℓ} → Interval → Type{ℓ} → SSet(ℓ)
      PartialP -- _ : ∀{ℓ} → (i : Interval) → (.(Is-𝟏 i) → Type{ℓ}) → SSet(ℓ)
    )
    renaming (
      i0 to 𝟎 ; -- _ : Interval. 0 (the initial point) in the interval.
      i1 to 𝟏 ; -- _ : Interval. 1 (the terminal point) in the interval.
      primIMin to min ; -- _ : Interval → Interval → Interval. Chooses the point nearest 𝟎. Also called: _∧_ (from lattice structure).
      primIMax to max ; -- _ : Interval → Interval → Interval. Chooses the point nearest 𝟏. Also called: _∨_ (from lattice structure).
      primINeg to flip ; -- _ : Interval → Interval. Flips a point in the interval around the point of symmetry (the middle). Essentially (p ↦ 𝟏 − p).
      IsOne to Is-𝟏 ; -- _ : Interval → SSet(Lvl.𝟎). The predicate stating that a point is 𝟏.
      itIsOne to 𝟏-is-𝟏 ; -- _ : Is-𝟏(𝟏). Proof of 𝟏 being 𝟏.
      primComp to comp ; -- _ : ∀{ℓ : Interval → Lvl.Level} → (P : (i : Interval) → Type{ℓ(i)}) → ∀{i : Interval} → ((j : Interval) → .(Is-𝟏 i) → P(j)) → (P(𝟎) → P(𝟏))
      primHComp to hComp ; -- _ : ∀{ℓ}{A : Type{ℓ}}{i : Interval} → (Interval → .(Is-𝟏 i) → A) → (A → A)
      primTransp to transp -- _ : ∀{ℓ : Interval → Lvl.Level}(A : (i : Interval) → Type{ℓ(i)}) → Interval → A(𝟎)→ A(𝟏).
    )

  -- The distance to the nearest boundary.
  nearBound : Interval → Interval
  nearBound x = min x (flip x)

  -- The distance to the furthest boundary.
  farBound : Interval → Interval
  farBound x = max x (flip x)

  -- Proof of maximum of 𝟏 being 𝟏.
  maxₗ-is-𝟏 : ∀{x y} → Is-𝟏(x) → Is-𝟏(max x y)
  maxₗ-is-𝟏 {x}{y} = Agda.Primitive.Cubical.IsOne1 x y

  -- Proof of maximum of 𝟏 being 𝟏.
  maxᵣ-is-𝟏 : ∀{x y} → Is-𝟏(y) → Is-𝟏(max x y)
  maxᵣ-is-𝟏 {x}{y} = Agda.Primitive.Cubical.IsOne2 x y

  -- The predicate stating that a point is 𝟎.
  Is-𝟎 : Interval → SSet(Lvl.𝟎)
  Is-𝟎 i = Is-𝟏(flip i)

  -- Proof of 𝟎 being 𝟎.
  𝟎-is-𝟎 : Is-𝟎(𝟎)
  𝟎-is-𝟎 = 𝟏-is-𝟏

  -- Proof of minimum of 𝟎 being 𝟎.
  minₗ-is-𝟎 : ∀{x y} → Is-𝟎(x) → Is-𝟎(min x y)
  minₗ-is-𝟎 {x}{y} = maxₗ-is-𝟏 {flip x} {flip y}

  -- Proof of minimum of 𝟎 being 𝟎.
  minᵣ-is-𝟎 : ∀{x y} → Is-𝟎(y) → Is-𝟎(min x y)
  minᵣ-is-𝟎 {x}{y} = maxᵣ-is-𝟏 {flip x} {flip y}


{-# OPTIONS --postfix-projections #-}

module StateSized.StackStateDependent where

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

open import Relation.Binary using (Rel)
open import Relation.Binary.PropositionalEquality
open import Relation.Binary.Product.Pointwise

open import NativeIO

open import SizedIO.Base
open import SizedIO.Console hiding (main)

open import StateSizedIO.GUI.BaseStateDependent
open import StateSizedIO.Object
open import StateSizedIO.IOObject

open import Size

StackStateˢ = ℕ

data StackMethodˢ (A : Set) : StackStateˢ → Set where
  push : {n : StackStateˢ} → A → StackMethodˢ A n
  pop  : {n : StackStateˢ} → StackMethodˢ A (suc n)

StackResultˢ : (A : Set) → (s : StackStateˢ) → StackMethodˢ A s → Set
StackResultˢ A .n (push { n  } x₁)  = Unit
StackResultˢ A (suc .n)  (pop {n} ) = A

nˢ : (A : Set) → (s : StackStateˢ) → (m : StackMethodˢ A s) → (r : StackResultˢ A s m) → StackStateˢ
nˢ A .n (push { n } x)     r = suc n
nˢ A (suc .n) (pop  { n }) r = n

StackInterfaceˢ : (A : Set) → Interfaceˢ
StackInterfaceˢ A .Stateˢ  = StackStateˢ
StackInterfaceˢ A .Methodˢ = StackMethodˢ A
StackInterfaceˢ A .Resultˢ = StackResultˢ A
StackInterfaceˢ A .nextˢ = nˢ A

stackP : ∀{n : ℕ} → (i : Size) → (v : Vec String n) → IOObjectˢ consoleI (StackInterfaceˢ String) i n
method (stackP { n }   i es)       {j} (push e) = return (_ , stackP j (e ∷ es))
method (stackP {suc n} i (x ∷ xs)){j} pop      = return (x , stackP j xs)

-- UNSIZED Version, without IO

stackP' : ∀{n : ℕ} → (v : Vec String n) → Objectˢ (StackInterfaceˢ String) n
stackP' es .objectMethod (push e) = (_ , stackP' (e ∷ es))
stackP' (x ∷ xs) .objectMethod pop = x , stackP' xs

stackO : ∀{E : Set} {n : ℕ} (v : Vec E n) → Objectˢ (StackInterfaceˢ E) n
objectMethod (stackO es)      (push e) = _ , stackO (e ∷ es)
objectMethod (stackO (e ∷ es)) pop      = e , stackO es

stackF : ∀{E : Set} (n : ℕ) (f : ℕ → E) → Objectˢ (StackInterfaceˢ E) n
objectMethod (stackF n f) (push x) = _ , stackF (suc n)
  \{ zero → x
   ; (suc m) → f m
   }
objectMethod (stackF (suc n) f) pop = (f zero) , stackF n (f  ∘ suc)

tabulate : ∀{E : Set} (n : ℕ) (f : ℕ → E) → Vec E n
tabulate zero    f = []
tabulate (suc n) f = f zero ∷ tabulate n λ m → f (suc m)

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

  _≡×≅'_ : ∀{s} → (o o' : E × O s) → Set
  _≡×≅'_ = _≡_ ×-Rel _≅_

  Eq×Bisim : ∀ (s : S) → (o o' : E × O s) → Set
  Eq×Bisim s = _≡_ ×-Rel _≅_

  pop-after-push : ∀{n}{v : Vec E n} (e : E) (let stack = stackO v) →
     (objectMethod stack (push e) ▹   λ { (_ , stack₁) →
      objectMethod stack₁ pop     ▹   λ { (e₁ , stack₂) →
      ( e₁ , stack₂ )  }})
    ≡×≅' (e , stack)
  pop-after-push e = refl , refl≅ _

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

  -- The implementations of stacks with either vectors or functions are bisimilar.

  impl-bisim : ∀{n : ℕ} {f : ℕ → E} (v : Vec E n) (p : tabulate n f ≡ v)
    → stackF n f ≅ stackO v

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

  bisimMethod (impl-bisim (x ∷ v) p) pop rewrite cong head p =
    bisim (impl-bisim v (cong tail p))

program : IOConsole ∞ Unit
program =
  exec getLine                λ str₀ →
  method s₀ (push str₀) >>= λ{ (_ , s₁) →            -- empty
  exec getLine                λ   str₁ →
  method s₁ (push str₁) >>= λ{ (_ , s₂) →            -- full
  method s₂ pop         >>= λ{ (str₂ , s₃) →
  exec (putStrLn ("first pop: " Str.++ str₂)  ) λ _ →
  exec getLine                λ   str₃ →
  method s₃ (push str₃) >>= λ{ (_ , s₄) →
  method s₄ pop         >>= λ{ (str₄ , s₅) →
  exec (putStrLn ("second pop: " Str.++ str₄)  ) λ _ →
  method s₅ pop         >>= λ{ (str₅ , s₅) →
  exec (putStrLn ("third  pop: " Str.++ str₅)  ) λ _ →
  return unit
  }}}}}}
  where
    s₀ = stackP ∞ []

main : NativeIO Unit
main = translateIOConsole program


module Cats.Category.Discrete {li} (I : Set li) where

open import Data.Unit using (⊤)
open import Level

open import Cats.Category.Base
open import Cats.Functor using (Functor)

Obj : Set li
Obj = I

data _⇒_ : Obj → Obj → Set where
  id : ∀ {A} → A ⇒ A

_∘_ : ∀ {A B C} → B ⇒ C → A ⇒ B → A ⇒ C
id ∘ id = id

Discrete : Category li zero zero
Discrete = record
    { Obj = Obj
    ; _⇒_ = _⇒_
    ; _≈_ = λ _ _ → ⊤
    ; id = id
    ; _∘_ = _∘_
    ; equiv = _
    ; ∘-resp = _
    ; id-r = _
    ; id-l = _
    ; assoc = _
    }

functor : ∀ {lo la l≈} {C : Category lo la l≈}
  → (I → Category.Obj C)
  → Functor Discrete C
functor {C = C} f = record
    { fobj = f
    ; fmap = λ { id → C.id }
    ; fmap-resp = λ { {_} {_} {id} {id} _ → C.≈.refl }
    ; fmap-id = C.≈.refl
    ; fmap-∘ = λ { {f = id} {id} → C.id-l }
    }
  where
    module C = Category C


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

open import LogicalFormulae
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Functions.Definition
open import Setoids.Setoids
open import Setoids.Subset
open import Graphs.Definition

module Graphs.Bipartite where

Bipartite : {a b : _} {c : _} {V' : Set a} {V : Setoid {a} {b} V'} (G : Graph c V) → Set _
Bipartite {V' = V'} {V = V} G = Sg (V' → Set) (λ partition → ((x y : V') → (Setoid._∼_ V x y) → partition x → partition y) & ((x : V') → (partition x) || ((partition x) → False)) & ((x y : V') → (Graph._<->_ G x y) → (partition x) → ((partition y) → False)))


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

open import lib.Basics
open import lib.NType2
open import lib.types.Group
open import lib.types.Word
open import lib.groups.GeneratedAbelianGroup
open import lib.groups.GeneratedGroup
open import lib.groups.GroupProduct
open import lib.groups.Homomorphism
open import lib.groups.Isomorphism

module lib.groups.FreeAbelianGroup {i} where

module FreeAbelianGroup (A : Type i) where

  private
    module Gen = GeneratedAbelianGroup A empty-rel
  open Gen hiding (GenAbGroup; module HomomorphismEquiv) public

  CommutativityRel : Rel (Word A) i
  CommutativityRel = AbGroupRel

  FormalSumRel : Rel (Word A) i
  FormalSumRel = QuotWordRel

  FormalSum : Type i
  FormalSum = QuotWord

  FreeGroup : Group i
  FreeGroup = Gen.GenGroup

  FreeAbGroup : AbGroup i
  FreeAbGroup = Gen.GenAbGroup

  module FreeAbGroup = AbGroup FreeAbGroup

  {- Universal Property -}
  module Freeness {j} (G : AbGroup j) where

    private
      module G = AbGroup G

    extend-equiv : (A → G.El) ≃ (FreeAbGroup.grp →ᴳ G.grp)
    extend-equiv =
      Gen.HomomorphismEquiv.extend-equiv G ∘e every-function-respects-empty-rel-equiv A G.grp

    extend : (A → G.El) → (FreeAbGroup.grp →ᴳ G.grp)
    extend = –> extend-equiv

    extend-is-equiv : is-equiv extend
    extend-is-equiv = snd extend-equiv

    extend-hom : Πᴳ A (λ _ → G.grp) →ᴳ hom-group FreeAbGroup.grp G
    extend-hom = record {M} where
      module M where
        f : (A → G.El) → (FreeAbGroup.grp →ᴳ G.grp)
        f = extend
        abstract
          pres-comp : preserves-comp (Group.comp (Πᴳ A (λ _ → G.grp))) (Group.comp (hom-group FreeAbGroup.grp G)) f
          pres-comp = λ f₁ f₂ → group-hom= $ λ= $
            QuotWord-elim
              (Word-extendᴳ-comp G f₁ f₂)
              (λ _ → prop-has-all-paths-↓)

    extend-iso : Πᴳ A (λ _ → G.grp) ≃ᴳ hom-group FreeAbGroup.grp G
    extend-iso = extend-hom , snd extend-equiv


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

syntax Unit | U

type
  𝟙 : 0-ary

term
  unit : 𝟙

theory
  (𝟙η) u : 𝟙 |> u = unit
-}

module Unit.Signature where

open import SOAS.Context

-- Type declaration
data UT : Set where
  𝟙 : UT

open import SOAS.Syntax.Signature UT public
open import SOAS.Syntax.Build UT public

-- Operator symbols
data Uₒ : Set where
  unitₒ : Uₒ

-- Term signature
U:Sig : Signature Uₒ
U:Sig = sig λ
  {  unitₒ  → ⟼₀ 𝟙
  }

open Signature U:Sig public


------------------------------------------------------------------------
-- The Agda standard library
--
-- Streams
------------------------------------------------------------------------

module Data.Stream where

open import Coinduction
open import Data.Colist using (Colist; []; _∷_)
open import Data.Vec    using (Vec;    []; _∷_)
open import Data.Nat using (ℕ; zero; suc)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P using (_≡_)

------------------------------------------------------------------------
-- The type

infixr 5 _∷_

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

{-# IMPORT Data.FFI #-}
{-# COMPILED_DATA Stream Data.FFI.AgdaStream Data.FFI.Cons #-}

------------------------------------------------------------------------
-- Some operations

head : ∀ {A} → Stream A → A
head (x ∷ xs) = x

tail : ∀ {A} → Stream A → Stream A
tail (x ∷ xs) = ♭ xs

map : ∀ {A B} → (A → B) → Stream A → Stream B
map f (x ∷ xs) = f x ∷ ♯ map f (♭ xs)

zipWith : ∀ {A B C} →
          (A → B → C) → Stream A → Stream B → Stream C
zipWith _∙_ (x ∷ xs) (y ∷ ys) = (x ∙ y) ∷ ♯ zipWith _∙_ (♭ xs) (♭ ys)

take : ∀ {A} n → Stream A → Vec A n
take zero    xs       = []
take (suc n) (x ∷ xs) = x ∷ take n (♭ xs)

drop : ∀ {A} → ℕ → Stream A → Stream A
drop zero    xs       = xs
drop (suc n) (x ∷ xs) = drop n (♭ xs)

repeat : ∀ {A} → A → Stream A
repeat x = x ∷ ♯ repeat x

iterate : ∀ {A} → (A → A) → A → Stream A
iterate f x = x ∷ ♯ iterate f (f x)

-- Interleaves the two streams.

infixr 5 _⋎_

_⋎_ : ∀ {A} → Stream A → Stream A → Stream A
(x ∷ xs) ⋎ ys = x ∷ ♯ (ys ⋎ ♭ xs)

mutual

  -- Takes every other element from the stream, starting with the
  -- first one.

  evens : ∀ {A} → Stream A → Stream A
  evens (x ∷ xs) = x ∷ ♯ odds (♭ xs)

  -- Takes every other element from the stream, starting with the
  -- second one.

  odds : ∀ {A} → Stream A → Stream A
  odds (x ∷ xs) = evens (♭ xs)

toColist : ∀ {A} → Stream A → Colist A
toColist (x ∷ xs) = x ∷ ♯ toColist (♭ xs)

lookup : ∀ {A} → ℕ → Stream A → A
lookup zero    (x ∷ xs) = x
lookup (suc n) (x ∷ xs) = lookup n (♭ xs)

infixr 5 _++_

_++_ : ∀ {A} → Colist A → Stream A → Stream A
[]       ++ ys = ys
(x ∷ xs) ++ ys = x ∷ ♯ (♭ xs ++ ys)

------------------------------------------------------------------------
-- Equality and other relations

-- xs ≈ ys means that xs and ys are equal.

infix 4 _≈_

data _≈_ {A} : Stream A → Stream A → Set where
  _∷_ : ∀ {x y xs ys}
        (x≡ : x ≡ y) (xs≈ : ∞ (♭ xs ≈ ♭ ys)) → x ∷ xs ≈ y ∷ ys

-- x ∈ xs means that x is a member of xs.

infix 4 _∈_

data _∈_ {A} : A → Stream A → Set where
  here  : ∀ {x   xs}                   → x ∈ x ∷ xs
  there : ∀ {x y xs} (x∈xs : x ∈ ♭ xs) → x ∈ y ∷ xs

-- xs ⊑ ys means that xs is a prefix of ys.

infix 4 _⊑_

data _⊑_ {A} : Colist A → Stream A → Set where
  []  : ∀ {ys}                            → []     ⊑ ys
  _∷_ : ∀ x {xs ys} (p : ∞ (♭ xs ⊑ ♭ ys)) → x ∷ xs ⊑ x ∷ ys

------------------------------------------------------------------------
-- Some proofs

setoid : Set → Setoid _ _
setoid A = record
  { Carrier       = Stream A
  ; _≈_           = _≈_ {A}
  ; isEquivalence = record
    { refl  = refl
    ; sym   = sym
    ; trans = trans
    }
  }
  where
  refl : Reflexive _≈_
  refl {_ ∷ _} = P.refl ∷ ♯ refl

  sym : Symmetric _≈_
  sym (x≡ ∷ xs≈) = P.sym x≡ ∷ ♯ sym (♭ xs≈)

  trans : Transitive _≈_
  trans (x≡ ∷ xs≈) (y≡ ∷ ys≈) = P.trans x≡ y≡ ∷ ♯ trans (♭ xs≈) (♭ ys≈)

head-cong : ∀ {A} {xs ys : Stream A} → xs ≈ ys → head xs ≡ head ys
head-cong (x≡ ∷ _) = x≡

tail-cong : ∀ {A} {xs ys : Stream A} → xs ≈ ys → tail xs ≈ tail ys
tail-cong (_ ∷ xs≈) = ♭ xs≈

map-cong : ∀ {A B} (f : A → B) {xs ys} →
           xs ≈ ys → map f xs ≈ map f ys
map-cong f (x≡ ∷ xs≈) = P.cong f x≡ ∷ ♯ map-cong f (♭ xs≈)

zipWith-cong : ∀ {A B C} (_∙_ : A → B → C) {xs xs′ ys ys′} →
               xs ≈ xs′ → ys ≈ ys′ →
               zipWith _∙_ xs ys ≈ zipWith _∙_ xs′ ys′
zipWith-cong _∙_ (x≡ ∷ xs≈) (y≡ ∷ ys≈) =
  P.cong₂ _∙_ x≡ y≡ ∷ ♯ zipWith-cong _∙_ (♭ xs≈) (♭ ys≈)

infixr 5 _⋎-cong_

_⋎-cong_ : ∀ {A} {xs xs′ ys ys′ : Stream A} →
           xs ≈ xs′ → ys ≈ ys′ → xs ⋎ ys ≈ xs′ ⋎ ys′
(x ∷ xs≈) ⋎-cong ys≈ = x ∷ ♯ (ys≈ ⋎-cong ♭ xs≈)


{-
  Definition of function fixpoint and Kraus' lemma
-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Functions.Fixpoint where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.GroupoidLaws
open import Cubical.Foundations.Path

private
  variable
    ℓ : Level
    A : Type ℓ

Fixpoint : (A → A) → Type _
Fixpoint {A = A} f = Σ A (λ x → f x ≡ x)

fixpoint : {f : A → A} → Fixpoint f → A
fixpoint = fst

fixpointPath : {f : A → A} → (p : Fixpoint f) → f (fixpoint p) ≡ fixpoint p
fixpointPath = snd

-- Kraus' lemma
-- a version not using cubical features can be found at
-- https://www.cs.bham.ac.uk/~mhe/GeneralizedHedberg/html/GeneralizedHedberg.html#21576
2-Constant→isPropFixpoint : (f : A → A) → 2-Constant f → isProp (Fixpoint f)
2-Constant→isPropFixpoint f fconst (x , p) (y , q) i = s i , t i where
  noose : ∀ x y → f x ≡ f y
  noose x y = sym (fconst x x) ∙ fconst x y
  -- the main idea is that for any path p, cong f p does not depend on p
  -- but only on its endpoints and the structure of 2-Constant f
  KrausInsight : ∀ {x y} → (p : x ≡ y) → noose x y ≡ cong f p
  KrausInsight {x} = J (λ y p → noose x y ≡ cong f p) (lCancel (fconst x x))
  -- Need to solve for a path s : x ≡ y, such that:
  -- transport (λ i → cong f s i ≡ s i) p ≡ q
  s : x ≡ y
  s = sym p ∙∙ noose x y ∙∙ q
  t' : PathP (λ i → noose x y i ≡ s i) p q
  t' i j = doubleCompPath-filler (sym p) (noose x y) q j i
  t : PathP (λ i → cong f s i ≡ s i) p q
  t = subst (λ kraus → PathP (λ i → kraus i ≡ s i) p q) (KrausInsight s) t'


------------------------------------------------------------------------
-- The Agda standard library
--
-- Nullary relations (some core definitions)
------------------------------------------------------------------------

-- The definitions in this file are reexported by Relation.Nullary.

module Relation.Nullary.Core where

open import Data.Empty
open import Level

-- Negation.

infix 3 ¬_

¬_ : ∀ {ℓ} → Set ℓ → Set ℓ
¬ P = P → ⊥

-- Decidable relations.

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