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

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

module Data.Bool.Properties where

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

open import Algebra.FunctionProperties (_≡_ {A = Bool})
open import Algebra.Structures (_≡_ {A = Bool})
open ≡-Reasoning

------------------------------------------------------------------------
-- Queries

infix 4 _≟_

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

------------------------------------------------------------------------
-- 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
  }

∨-isCommutativeMonoid : IsCommutativeMonoid _∨_ false
∨-isCommutativeMonoid = record
  { isSemigroup = ∨-isSemigroup
  ; identityˡ   = ∨-identityˡ
  ; 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
  }

∧-isCommutativeMonoid : IsCommutativeMonoid _∧_ true
∧-isCommutativeMonoid = record
  { isSemigroup = ∧-isSemigroup
  ; identityˡ   = ∧-identityˡ
  ; 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
  }

∨-∧-isCommutativeSemiring
  : IsCommutativeSemiring _∨_ _∧_ false true
∨-∧-isCommutativeSemiring = record
  { +-isCommutativeMonoid = ∨-isCommutativeMonoid
  ; *-isCommutativeMonoid = ∧-isCommutativeMonoid
  ; distribʳ = ∧-distribʳ-∨
  ; zeroˡ    = ∧-zeroˡ
  }

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

∧-∨-isCommutativeSemiring
  : IsCommutativeSemiring _∧_ _∨_ true false
∧-∨-isCommutativeSemiring = record
  { +-isCommutativeMonoid = ∧-isCommutativeMonoid
  ; *-isCommutativeMonoid = ∨-isCommutativeMonoid
  ; distribʳ = ∨-distribʳ-∧
  ; zeroˡ    = ∨-zeroˡ
  }

∧-∨-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-¬ : ∀ {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)

⇔→≡ : {b₁ b₂ b : Bool} → b₁ ≡ b ⇔ b₂ ≡ b → b₁ ≡ b₂
⇔→≡ {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-≡ : ∀ {b} → T b ⇔ b ≡ true
T-≡ {false} = equivalence (λ ())       (λ ())
T-≡ {true}  = equivalence (const refl) (const _)

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

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

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

T-irrelevant : Irrelevant T
T-irrelevant {true}  _  _  = refl
T-irrelevant {false} () ()

T? : U.Decidable T
T? true  = yes _
T? false = no (λ ())

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

push-function-into-if :
  ∀ {a b} {A : Set a} {B : Set b} (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."
#-}


------------------------------------------------------------------------
-- The Agda standard library
--
-- Least common multiple
------------------------------------------------------------------------

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

module Data.Nat.LCM where

open import Algebra
open import Data.Nat.Base
open import Data.Nat.Coprimality using (Coprime)
open import Data.Nat.Divisibility
open import Data.Nat.DivMod
open import Data.Nat.Properties
open import Data.Nat.Solver
open import Data.Nat.GCD
open import Data.Product
open import Data.Sum.Base using (_⊎_; inj₁; inj₂)
open import Function
open import Relation.Binary.PropositionalEquality as P
  using (_≡_; refl; sym; trans; cong; cong₂; module ≡-Reasoning)
open import Relation.Binary
open import Relation.Nullary.Decidable using (False; fromWitnessFalse)

open +-*-Solver

private
  gcd≢0′ : ∀ m n → False (gcd (suc m) n ≟ 0)
  gcd≢0′ m n = fromWitnessFalse (gcd[m,n]≢0 (suc m) n (inj₁ (λ())))

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

lcm : ℕ → ℕ → ℕ
lcm zero        n = zero
lcm m@(suc m-1) n = m * (n / gcd m n) {gcd≢0′ m-1 n}

------------------------------------------------------------------------
-- Core properties

private
  rearrange : ∀ m-1 n → lcm (suc m-1) n ≡ ((suc m-1) * n / gcd (suc m-1) n) {gcd≢0′ m-1 n}
  rearrange m-1 n = sym (*-/-assoc m {n} {gcd m n} {gcd≢0′ m-1 n} (gcd[m,n]∣n m n))
    where m = suc m-1

m∣lcm[m,n] : ∀ m n → m ∣ lcm m n
m∣lcm[m,n] zero      n = 0 ∣0
m∣lcm[m,n] m@(suc _) n = m∣m*n (n / gcd m n)

n∣lcm[m,n] : ∀ m n → n ∣ lcm m n
n∣lcm[m,n] zero        n = n ∣0
n∣lcm[m,n] m@(suc m-1) n = begin
  n                 ∣⟨ m∣m*n (m / gcd m n) ⟩
  n * (m / gcd m n) ≡⟨ sym (*-/-assoc n {≢0 = gcd≢0′ m-1 n} (gcd[m,n]∣m m n)) ⟩
  n * m / gcd m n   ≡⟨ cong (λ v → (v / gcd m n) {gcd≢0′ m-1 n}) (*-comm n m) ⟩
  m * n / gcd m n   ≡⟨ sym (rearrange m-1 n) ⟩
  m * (n / gcd m n) ∎
  where open ∣-Reasoning

lcm-least : ∀ {m n c} → m ∣ c → n ∣ c → lcm m n ∣ c
lcm-least {zero}        {n} {c} 0∣c _   = 0∣c
lcm-least {m@(suc m-1)} {n} {c} m∣c n∣c = P.subst (_∣ c) (sym (rearrange m-1 n))
  (m∣n*o⇒m/n∣o {n≢0 = gcd≢0′ m-1 n} gcd[m,n]∣m*n mn∣c*gcd)
  where
  open ∣-Reasoning
  gcd[m,n]∣m*n : gcd m n ∣ m * n
  gcd[m,n]∣m*n = ∣-trans (gcd[m,n]∣m m n) (m∣m*n n)

  mn∣c*gcd : m * n ∣ c * gcd m n
  mn∣c*gcd = begin
    m * n               ∣⟨ gcd-greatest (P.subst (_∣ c * m) (*-comm n m) (*-monoˡ-∣ m n∣c)) (*-monoˡ-∣ n m∣c) ⟩
    gcd (c * m) (c * n) ≡⟨ sym (c*gcd[m,n]≡gcd[cm,cn] c m n) ⟩
    c * gcd m n         ∎

------------------------------------------------------------------------
-- Other properties

-- Note that all other properties of `gcd` should be inferable from the
-- 3 core properties above.

gcd*lcm : ∀ m n → gcd m n * lcm m n ≡ m * n
gcd*lcm zero        n = *-zeroʳ (gcd 0 n)
gcd*lcm m@(suc m-1) n = trans (cong (gcd m n *_) (rearrange m-1 n)) (m*[n/m]≡n {gcd m n} (begin
  gcd m n ∣⟨ gcd[m,n]∣m m n ⟩
  m       ∣⟨ m∣m*n n ⟩
  m * n   ∎))
  where open ∣-Reasoning

lcm[0,n]≡0 : ∀ n → lcm 0 n ≡ 0
lcm[0,n]≡0 n = 0∣⇒≡0 (m∣lcm[m,n] 0 n)

lcm[n,0]≡0 : ∀ n → lcm n 0 ≡ 0
lcm[n,0]≡0 n = 0∣⇒≡0 (n∣lcm[m,n] n 0)

lcm-comm : ∀ m n → lcm m n ≡ lcm n m
lcm-comm m n = ∣-antisym
  (lcm-least (n∣lcm[m,n] n m) (m∣lcm[m,n] n m))
  (lcm-least (n∣lcm[m,n] m n) (m∣lcm[m,n] m n))

------------------------------------------------------------------------
-- Least common multiple (lcm).

module LCM where

  -- Specification of the least common multiple (lcm) of two natural
  -- numbers.

  record LCM (i j lcm : ℕ) : Set where
    field
      -- The lcm is a common multiple.
      commonMultiple : i ∣ lcm × j ∣ lcm

      -- The lcm divides all common multiples, i.e. the lcm is the least
      -- common multiple according to the partial order _∣_.
      least : ∀ {m} → i ∣ m × j ∣ m → lcm ∣ m

  open LCM public

  -- The lcm is unique.

  unique : ∀ {d₁ d₂ m n} → LCM m n d₁ → LCM m n d₂ → d₁ ≡ d₂
  unique d₁ d₂ = ∣-antisym (LCM.least d₁ (LCM.commonMultiple d₂))
                           (LCM.least d₂ (LCM.commonMultiple d₁))

open LCM public using (LCM) hiding (module LCM)

------------------------------------------------------------------------
-- Calculating the LCM

lcm-LCM : ∀ m n → LCM m n (lcm m n)
lcm-LCM m n = record
  { commonMultiple = m∣lcm[m,n] m n , n∣lcm[m,n] m n
  ; least          = uncurry′ lcm-least
  }

mkLCM : ∀ m n → ∃ λ d → LCM m n d
mkLCM m n = lcm m n , lcm-LCM m n

GCD*LCM : ∀ {m n g l} → GCD m n g → LCM m n l → m * n ≡ g * l
GCD*LCM {m} {n} {g} {l} gc lc = sym (begin
  g * l             ≡⟨ cong₂ _*_ (GCD.unique gc (gcd-GCD m n)) (LCM.unique lc (lcm-LCM m n)) ⟩
  gcd m n * lcm m n ≡⟨ gcd*lcm m n ⟩
  m * n             ∎)
  where open ≡-Reasoning


module ListMember where

open import Prelude

data Member {A : Set} (x : A) : List A -> Set where
  here : {xs : List A} -> Member x (cons x xs)
  there : forall {y} -> {xs : List A} -> Member x xs -> Member x (cons y xs)

empty-no-member' : forall {A} -> {x : A} -> Member x nil -> Empty
empty-no-member' p = {!!}

empty-no-member : forall {A} -> {x : A} -> Not (Member x nil)
empty-no-member = is-absurd empty-no-member'

neither-here-nor-there' : forall {A} -> {x y : A} {ys : List A} -> (x == y -> Empty) -> (Member x ys -> Empty) -> Member x (cons y ys) -> Empty
neither-here-nor-there' not-here not-there member = {!!}

neither-here-nor-there : forall {A} -> {x y : A} {ys : List A} -> Not (x == y) -> Not (Member x ys) -> Not (Member x (cons y ys))
neither-here-nor-there (is-absurd not-here) (is-absurd not-there) = is-absurd (neither-here-nor-there' not-here not-there)

member : forall {A} -> ((x y : A) -> Dec (x == y)) -> (v : A) -> (vs : List A) -> Dec (Member v vs)
member eq? x nil = no empty-no-member
member eq? x (cons y ys) with eq? x y
member eq? x (cons y ys) | yes p = {!!}
member eq? x (cons y ys) | no pf with member eq? x ys
member eq? x (cons y ys) | no pf | member = {!!}


{-# OPTIONS --cubical --safe #-}
module Cubical.Data.Unit.Properties where

open import Cubical.Core.Everything

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

open import Cubical.Data.Nat
open import Cubical.Data.Unit.Base

isPropUnit : isProp Unit
isPropUnit _ _ i = tt

isContrUnit : isContr Unit
isContrUnit = tt , λ {tt → refl}

isOfHLevelUnit : (n : ℕ) → isOfHLevel n Unit
isOfHLevelUnit 0       = isContrUnit
isOfHLevelUnit 1       = isPropUnit
isOfHLevelUnit (suc n) = hLevelSuc n Unit (isOfHLevelUnit n)


open import Relation.Binary.Core

module Heapsort.Impl2 {A : Set}
                  (_≤_ : A → A → Set)
                  (tot≤ : Total _≤_)
                  (trans≤ : Transitive _≤_) where

open import BBHeap _≤_ hiding (flatten)
open import BBHeap.Compound _≤_
open import BBHeap.Drop _≤_ tot≤ trans≤
open import BBHeap.Drop.Properties _≤_ tot≤ trans≤
open import BBHeap.Heapify _≤_ tot≤ trans≤
open import BBHeap.Order _≤_
open import BBHeap.Order.Properties _≤_
open import Bound.Lower A
open import Bound.Lower.Order _≤_
open import Data.List hiding (drop)
open import OList _≤_

flatten : {b : Bound}(h : BBHeap b) → Acc h → OList b
flatten leaf _ = onil
flatten (left b≤x l⋘r) (acc rs) = :< b≤x (flatten (drop (cl b≤x l⋘r)) (rs (drop (cl b≤x l⋘r)) (lemma-drop≤′ (cl b≤x l⋘r))))
flatten (right b≤x l⋙r) (acc rs) = :< b≤x (flatten (drop (cr b≤x l⋙r)) (rs (drop (cr b≤x l⋙r)) (lemma-drop≤′ (cr b≤x l⋙r))))

heapsort : List A → OList bot
heapsort xs = flatten (heapify xs) (≺-wf (heapify xs))


{-# OPTIONS --guardedness #-}

record _≈_ {A : Set} (xs : Stream A) (ys : Stream A) : Set where
  coinductive
  field
    hd-≈ : hd xs ≡ hd ys
    tl-≈ : tl xs ≈ tl ys

even : ∀ {A} → Stream A → Stream A
hd (even x) = hd x
tl (even x) = even (tl (tl x))

odd : ∀ {A} → Stream A → Stream A
odd x = even (tl x)

split : ∀ {A} → Stream A → Stream A × Stream A
split xs = even xs , odd xs

merge : ∀ {A} → Stream A × Stream A → Stream A
hd (merge (fst , snd)) = hd fst
tl (merge (fst , snd)) = merge (snd , tl fst)

merge-split-id : ∀ {A} (xs : Stream A) → merge (split xs) ≈ xs
hd-≈ (merge-split-id _)  = refl
tl-≈ (merge-split-id xs) = merge-split-id (tl xs)


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

open import Setoids.Setoids
open import Agda.Primitive using (Level; lzero; lsuc; _⊔_)
open import Groups.Definition

module Groups.Actions.Definition where

record GroupAction {m n o p : _} {A : Set m} {S : Setoid {m} {o} A} {_·_ : A → A → A} {B : Set n} (G : Group S _·_) (X : Setoid {n} {p} B) : Set (m ⊔ n ⊔ o ⊔ p) where
  open Group G
  open Setoid S renaming (_∼_ to _∼G_)
  open Setoid X renaming (_∼_ to _∼X_)
  field
    action : A → B → B
    actionWellDefined1 : {g h : A} → {x : B} → (g ∼G h) → action g x ∼X action h x
    actionWellDefined2 : {g : A} → {x y : B} → (x ∼X y) → action g x ∼X action g y
    identityAction : {x : B} → action 0G x ∼X x
    associativeAction : {x : B} → {g h : A} → action (g · h) x ∼X action g (action h x)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Lists defined in terms of Data.Star
------------------------------------------------------------------------

module Data.Star.List where

open import Data.Star
open import Data.Unit
open import Relation.Binary.Simple
open import Data.Star.Nat

-- Lists.

List : Set → Set
List a = Star (Const a) tt tt

-- Nil and cons.

[] : ∀ {a} → List a
[] = ε

infixr 5 _∷_

_∷_ : ∀ {a} → a → List a → List a
_∷_ = _◅_

-- The sum of the elements in a list containing natural numbers.

sum : List ℕ → ℕ
sum = fold (Star Always) _+_ zero


{-# OPTIONS --without-K --safe #-}
module Categories.Adjoint where

-- Adjoints

open import Level

open import Data.Product using (_,_; _×_)
open import Function using (_$_) renaming (_∘_ to _∙_)
open import Function.Equality using (Π; _⟶_)
import Function.Inverse as FI
open import Relation.Binary using (Rel; IsEquivalence; Setoid)

-- be explicit in imports to 'see' where the information comes from
open import Categories.Category.Core using (Category)
open import Categories.Category.Product using (Product; _⁂_)
open import Categories.Category.Instance.Setoids
open import Categories.Morphism
open import Categories.Functor using (Functor; _∘F_) renaming (id to idF)
open import Categories.Functor.Bifunctor using (Bifunctor)
open import Categories.Functor.Hom using (Hom[_][-,-])
open import Categories.Functor.Construction.LiftSetoids
open import Categories.NaturalTransformation using (NaturalTransformation; ntHelper; _∘ₕ_; _∘ᵥ_; _∘ˡ_; _∘ʳ_)
  renaming (id to idN)
open import Categories.NaturalTransformation.NaturalIsomorphism
  using (NaturalIsomorphism; unitorˡ; unitorʳ; associator; _≃_)
import Categories.Morphism.Reasoning as MR

private
  variable
    o o′ o″ ℓ ℓ′ ℓ″ e e′ e″ : Level
    C D E : Category o ℓ e

record Adjoint (L : Functor C D) (R : Functor D C) : Set (levelOfTerm L ⊔ levelOfTerm R) where
  private
    module C = Category C
    module D = Category D
    module L = Functor L
    module R = Functor R

  field
    unit   : NaturalTransformation idF (R ∘F L)
    counit : NaturalTransformation (L ∘F R) idF

  module unit = NaturalTransformation unit
  module counit = NaturalTransformation counit

  field
    zig : ∀ {A : C.Obj} → counit.η (L.F₀ A) D.∘ L.F₁ (unit.η A) D.≈ D.id
    zag : ∀ {B : D.Obj} → R.F₁ (counit.η B) C.∘ unit.η (R.F₀ B) C.≈ C.id

  private
    variable
      A : C.Obj
      B : D.Obj

  Ladjunct : L.F₀ A D.⇒ B → A C.⇒ R.F₀ B
  Ladjunct f = R.F₁ f C.∘ unit.η _

  Radjunct : A C.⇒ R.F₀ B → L.F₀ A D.⇒ B
  Radjunct f = counit.η _ D.∘ L.F₁ f

  RLadjunct≈id : ∀ {f : L.F₀ A D.⇒ B} → Radjunct (Ladjunct f) D.≈ f
  RLadjunct≈id {f = f} = begin
    Radjunct (Ladjunct f)                            ≈⟨ refl⟩∘⟨ L.homomorphism ⟩
    counit.η _ D.∘ L.F₁ (R.F₁ f) D.∘ L.F₁ (unit.η _) ≈⟨ pullˡ (counit.commute f) ⟩
    (f D.∘ counit.η _) D.∘ L.F₁ (unit.η _)           ≈⟨ pullʳ zig ⟩
    f D.∘ D.id                                       ≈⟨ D.identityʳ ⟩
    f                                                ∎
    where open D.HomReasoning
          open MR D

  LRadjunct≈id : ∀ {f : A C.⇒ R.F₀ B} → Ladjunct (Radjunct f) C.≈ f
  LRadjunct≈id {f = f} = begin
    Ladjunct (Radjunct f)                              ≈⟨ R.homomorphism ⟩∘⟨refl ⟩
    (R.F₁ (counit.η _) C.∘ R.F₁ (L.F₁ f)) C.∘ unit.η _ ≈˘⟨ pushʳ (unit.commute f) ⟩
    R.F₁ (counit.η _) C.∘ unit.η _ C.∘ f               ≈⟨ pullˡ zag ⟩
    C.id C.∘ f                                         ≈⟨ C.identityˡ ⟩
    f                                                  ∎
    where open C.HomReasoning
          open MR C

  Hom[L-,-] : Bifunctor C.op D (Setoids _ _)
  Hom[L-,-] = Hom[ D ][-,-] ∘F (L.op ⁂ idF)

  Hom[-,R-] : Bifunctor C.op D (Setoids _ _)
  Hom[-,R-] = Hom[ C ][-,-] ∘F (idF ⁂ R)

  module Hom[L-,-] = Functor Hom[L-,-]
  module Hom[-,R-] = Functor Hom[-,R-]

  -- Inverse is more 'categorical' than bijection defined via injection/surjection
  Hom-inverse : ∀ A B → FI.Inverse (Hom[L-,-].F₀ (A , B)) (Hom[-,R-].F₀ (A , B))
  Hom-inverse A B = record
    { to = record
      { _⟨$⟩_ = Ladjunct {A} {B}
      ; cong = C.∘-resp-≈ˡ ∙ R.F-resp-≈
      }
    ; from = record
      { _⟨$⟩_ = Radjunct {A} {B}
      ; cong = D.∘-resp-≈ʳ ∙ L.F-resp-≈
      }
    ; inverse-of = record
      { left-inverse-of = λ _ → RLadjunct≈id
      ; right-inverse-of = λ _ → LRadjunct≈id
      }
    }

  module Hom-inverse {A} {B} = FI.Inverse (Hom-inverse A B)

  op : Adjoint R.op L.op
  op = record
    { unit   = counit.op
    ; counit = unit.op
    ; zig    = zag
    ; zag    = zig
    }

  -- naturality condition on the two hom functors.
  -- these conditions are separated out because a complication due to the
  -- universe level in Agda.
  module _ where
    open C
    open HomReasoning
    open MR C

    Ladjunct-comm : ∀ {X Y A B} {h i : L.F₀ X D.⇒ Y} {f : A ⇒ X} {g : Y D.⇒ B} →
                      h D.≈ i →
                      R.F₁ (g D.∘ h D.∘ L.F₁ f) ∘ unit.η A ≈ R.F₁ g ∘ (R.F₁ i ∘ unit.η X) ∘ f
    Ladjunct-comm {X} {Y} {A} {B} {h} {i} {f} {g} eq = begin
      R.F₁ (g D.∘ h D.∘ L.F₁ f) ∘ unit.η A         ≈⟨ R.homomorphism ⟩∘⟨refl ⟩
      (R.F₁ g ∘ R.F₁ (h D.∘ L.F₁ f)) ∘ unit.η A    ≈⟨ (refl⟩∘⟨ R.homomorphism) ⟩∘⟨refl ⟩
      (R.F₁ g ∘ R.F₁ h ∘ R.F₁ (L.F₁ f)) ∘ unit.η A ≈⟨ pullʳ assoc ⟩
      R.F₁ g ∘ R.F₁ h ∘ R.F₁ (L.F₁ f) ∘ unit.η A   ≈˘⟨ refl⟩∘⟨ ⟺ (R.F-resp-≈ eq) ⟩∘⟨ unit.commute f ⟩
      R.F₁ g ∘ R.F₁ i ∘ unit.η X ∘ f               ≈⟨ refl⟩∘⟨ sym-assoc ⟩
      R.F₁ g ∘ (R.F₁ i ∘ unit.η X) ∘ f             ∎

    Ladjunct-comm′ : ∀ {X A B} {f : A ⇒ X} {g : L.F₀ X D.⇒ B} →
                      Ladjunct (g D.∘ L.F₁ f) ≈ Ladjunct g ∘ f
    Ladjunct-comm′ = ∘-resp-≈ˡ R.homomorphism ○ (pullʳ (⟺ (unit.commute _))) ○ sym-assoc

    Ladjunct-resp-≈ : ∀ {A B} {f g : L.F₀ A D.⇒ B} → f D.≈ g → Ladjunct f ≈ Ladjunct g
    Ladjunct-resp-≈ eq = ∘-resp-≈ˡ (R.F-resp-≈ eq)

  module _ where
    open D
    open HomReasoning
    open MR D

    Radjunct-comm : ∀ {X Y A B} {h i : X C.⇒ R.F₀ Y} {f : A C.⇒ X} {g : Y ⇒ B} →
                      h C.≈ i →
                      counit.η B ∘ L.F₁ (R.F₁ g C.∘ h C.∘ f) ≈ g ∘ (counit.η Y ∘ L.F₁ i) ∘ L.F₁ f
    Radjunct-comm {X} {Y} {A} {B} {h} {i} {f} {g} eq = begin
      counit.η B ∘ L.F₁ (R.F₁ g C.∘ h C.∘ f)       ≈⟨ refl⟩∘⟨ L.homomorphism ⟩
      counit.η B ∘ L.F₁ (R.F₁ g) ∘ L.F₁ (h C.∘ f)  ≈⟨ pullˡ (counit.commute g) ⟩
      (g ∘ counit.η Y) ∘ L.F₁ (h C.∘ f)            ≈⟨ refl⟩∘⟨ L.homomorphism ⟩
      (g ∘ counit.η Y) ∘ L.F₁ h ∘ L.F₁ f           ≈⟨ refl⟩∘⟨ L.F-resp-≈ eq ⟩∘⟨refl ⟩
      (g ∘ counit.η Y) ∘ L.F₁ i ∘ L.F₁ f           ≈⟨ pullʳ sym-assoc ⟩
      g ∘ (counit.η Y ∘ L.F₁ i) ∘ L.F₁ f           ∎

    Radjunct-comm′ : ∀ {Y A B} {f : A C.⇒ R.F₀ Y} {g : Y ⇒ B} →
                      Radjunct (R.F₁ g C.∘ f) ≈ g ∘ Radjunct f
    Radjunct-comm′ = ∘-resp-≈ʳ L.homomorphism ○ pullˡ (counit.commute _) ○ assoc

    Radjunct-resp-≈ : ∀ {A B} {f g : A C.⇒ R.F₀ B} → f C.≈ g → Radjunct f ≈ Radjunct g
    Radjunct-resp-≈ eq = ∘-resp-≈ʳ (L.F-resp-≈ eq)

  -- a complication: the two hom functors do not live in the same Setoids,
  -- so they need to be mapped to the same Setoids first before establishing
  -- natural isomorphism!
  module _ where
    private
      levelℓ : Category o ℓ e → Level
      levelℓ {ℓ = ℓ} _ = ℓ

      levele : Category o ℓ e → Level
      levele {e = e} _ = e

    Hom[L-,-]′ : Bifunctor C.op D (Setoids _ _)
    Hom[L-,-]′ = LiftSetoids (levelℓ C) (levele C) ∘F Hom[ D ][-,-] ∘F (L.op ⁂ idF)

    Hom[-,R-]′ : Bifunctor C.op D (Setoids _ _)
    Hom[-,R-]′ = LiftSetoids (levelℓ D) (levele D) ∘F Hom[ C ][-,-] ∘F (idF ⁂ R)

    Hom-NI : NaturalIsomorphism Hom[L-,-]′ Hom[-,R-]′
    Hom-NI = record
      { F⇒G = ntHelper record
        { η       = λ _ → record
          { _⟨$⟩_ = λ f → lift (Ladjunct (lower f))
          ; cong  = λ eq → lift (Ladjunct-resp-≈ (lower eq))
          }
        ; commute = λ _ eq → lift $ Ladjunct-comm (lower eq)
        }
      ; F⇐G = ntHelper record
        { η       = λ _ → record
          { _⟨$⟩_ = λ f → lift (Radjunct (lower f))
          ; cong  = λ eq → lift (Radjunct-resp-≈ (lower eq))
          }
        ; commute = λ _ eq → lift $ Radjunct-comm (lower eq)
        }
      ; iso = λ X → record
        { isoˡ = λ eq → let open D.HomReasoning in lift (RLadjunct≈id ○ lower eq)
        ; isoʳ = λ eq → let open C.HomReasoning in lift (LRadjunct≈id ○ lower eq)
        }
      }

  module Hom-NI = NaturalIsomorphism Hom-NI

infix 5 _⊣_
_⊣_ = Adjoint

⊣-id : idF {C = C} ⊣ idF {C = C}
⊣-id {C = C} = record
  { unit   = F⇐G unitorˡ
  ; counit = F⇒G unitorʳ
  ; zig    = identityˡ
  ; zag    = identityʳ
  }
  where open Category C
        open NaturalIsomorphism


------------------------------------------------------------------------------
-- The division program is correct
------------------------------------------------------------------------------

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

-- This module proves the correctness of the division program using
-- repeated subtraction (Dybjer 1985).

-- Peter Dybjer. Program verification in a logical theory of
-- constructions. In Jean-Pierre Jouannaud, editor. Functional
-- Programming Languages and Computer Architecture, volume 201 of
-- LNCS, 1985, pages 334-349. Appears in revised form as Programming
-- Methodology Group Report 26, June 1986.

module LTC-PCF.Program.Division.CorrectnessProof where

open import LTC-PCF.Base
open import LTC-PCF.Data.Nat
open import LTC-PCF.Data.Nat.Inequalities
open import LTC-PCF.Data.Nat.Inequalities.Properties
open import LTC-PCF.Data.Nat.Properties

import LTC-PCF.Data.Nat.Induction.NonAcc.WF
open module WFInd = LTC-PCF.Data.Nat.Induction.NonAcc.WF.WFInd

open import LTC-PCF.Program.Division.Division
open import LTC-PCF.Program.Division.Specification
open import LTC-PCF.Program.Division.Result
open import LTC-PCF.Program.Division.Totality

------------------------------------------------------------------------------
-- The division program is correct when the dividend is less than the
-- divisor.
div-x<y-correct : ∀ {i j} → N i → N j → i < j → divSpec i j (div i j)
div-x<y-correct Ni Nj i<j = div-x<y-N i<j , div-x<y-resultCorrect Ni Nj i<j

-- The division program is correct when the dividend is greater or
-- equal than the divisor.
div-x≮y-correct : ∀ {i j} → N i → N j →
                  (∀ {i'} → N i' → i' < i → divSpec i' j (div i' j)) →
                  j > zero →
                  i ≮ j →
                  divSpec i j (div i j)
div-x≮y-correct {i} {j} Ni Nj ah j>0 i≮j =
  div-x≮y-N ih i≮j , div-x≮y-resultCorrect Ni Nj ih i≮j

  where
  -- The inductive hypothesis on i ∸ j.
  ih : divSpec (i ∸ j) j (div (i ∸ j) j)
  ih = ah {i ∸ j}
          (∸-N Ni Nj)
          (x≥y→y>0→x∸y<x Ni Nj (x≮y→x≥y Ni Nj i≮j) j>0)

------------------------------------------------------------------------------
-- The division program is correct.

-- We do the well-founded induction on i and we keep j fixed.
divCorrect : ∀ {i j} → N i → N j → j > zero → divSpec i j (div i j)
divCorrect {j = j} Ni Nj j>0 = <-wfind A ih Ni
  where
  A : D → Set
  A d = divSpec d j (div d j)

  -- The inductive step doesn't use the variable i (nor Ni). To make
  -- this clear we write down the inductive step using the variables m
  -- and n.
  ih : ∀ {n} → N n → (∀ {m} → N m → m < n → A m) → A n
  ih {n} Nn ah =
     case (div-x<y-correct Nn Nj) (div-x≮y-correct Nn Nj ah j>0) (x<y∨x≮y Nn Nj)


module CS410-Prelude where

------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- Standard Equipment for use in Exercises
------------------------------------------------------------------------------
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-- functional equipment (types may be generalized later)
------------------------------------------------------------------------------

-- the polymorphic identity function
id : {X : Set} -> X -> X
id x = x

-- standard composition: f << g is "f after g"
_<<_ : {X Y Z : Set} -> (Y -> Z) -> (X -> Y) -> (X -> Z)
(f << g) x = f (g x)

-- diagrammatic composition: f >> g is "f then g"
_>>_ : {X Y Z : Set} -> (X -> Y) -> (Y -> Z) -> (X -> Z)
                     --       ^^^^^^^^          dominoes!
(f >> g) x = g (f x)
infixr 5 _>>_

-- infix application
_$_ : {S : Set}{T : S -> Set}(f : (x : S) -> T x)(s : S) -> T s
f $ s = f s
infixl 2 _$_

------------------------------------------------------------------------------
-- some basic "logical" types
------------------------------------------------------------------------------

data Zero : Set where
  -- to give a value in a data, choose one constructor
  -- there are no constructors
  -- so that's impossible

record One : Set where
  -- to give a value in a record type, fill all its fields
  -- there are no fields
  -- so that's trivial
  --   (can we have a constructor, for convenience?)
  constructor <>

data _+_ (S : Set)(T : Set) : Set where -- "where" wants an indented block
  -- to offer a choice of constructors, list them with their types
  inl : S -> S + T     -- constructors can pack up stuff
  inr : T -> S + T
  -- in Haskell, this was called "Either S T"

record Sg (S : Set)(T : S -> Set) : Set where  -- Sg is short for "Sigma"
  constructor _,_
  field -- introduces a bunch of fields, listed with their types
    fst : S
    snd : T fst
-- make _*_ from Sg ?
open Sg public

_*_ : Set -> Set -> Set
S * T = Sg S \ _ -> T

infixr 4 _,_ _*_

------------------------------------------------------------------------------
-- natural numbers and addition
------------------------------------------------------------------------------

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

{-# BUILTIN NATURAL Nat #-}
--  ^^^^^^^^^^^^^^^^^^^       this pragma lets us use decimal notation

_+N_ : Nat -> Nat -> Nat
zero  +N y = y
suc x +N y = suc (x +N y)      -- there are other choices

------------------------------------------------------------------------------
-- equality
------------------------------------------------------------------------------

data _==_ {X : Set} : X -> X -> Set where
  refl : (x : X) -> x == x           -- the relation that's "only reflexive"

{-# BUILTIN EQUALITY _==_ #-}  -- we'll see what that's for, later

_=$=_ : {X Y : Set}{f f' : X -> Y}{x x' : X} ->
        f == f' -> x == x' -> f x == f' x'
refl f =$= refl x = refl (f x)

_=$_ : {S : Set}{T : S -> Set}{f g : (x : S) -> T x} -> (f == g) -> (x : S) -> f x == g x
refl f =$ x = refl (f x)

infixl 2 _=$=_ _=$_

sym : {X : Set}{x y : X} -> x == y -> y == x
sym (refl x) = refl x

_[QED] : {X : Set}(x : X) -> x == x
x [QED] = refl x
_=[_>=_ : {X : Set}(x : X){y z : X} -> x == y -> y == z -> x == z
x =[ refl .x >= q = q
_=<_]=_ : {X : Set}(x : X){y z : X} -> y == x -> y == z -> x == z
x =< refl .x ]= q = q
infixr 1 _=[_>=_ _=<_]=_
infixr 2 _[QED]

------------------------------------------------------------------------------
-- greater-than-or-equals
------------------------------------------------------------------------------

_>=_ : Nat -> Nat -> Set
x     >= zero   = One
zero  >= suc y  = Zero
suc x >= suc y  = x >= y

refl->= : (n : Nat) -> n >= n
refl->= zero    = record {}
refl->= (suc n) = refl->= n

trans->= : (x y z : Nat) -> x >= y -> y >= z -> x >= z
trans->=      x       y  zero    x>=y y>=z = record {}
trans->=      x  zero    (suc z) x>=y ()
trans->= zero    (suc y) (suc z) ()   y>=z
trans->= (suc x) (suc y) (suc z) x>=y y>=z = trans->= x y z x>=y y>=z

suc->= : (x : Nat) -> suc x >= x
suc->= zero    = <>
suc->= (suc x) = suc->= x

----------------------------------------------------------------------------
-- Two -- the type of Boolean values
----------------------------------------------------------------------------

data Two : Set where tt ff : Two
{-# BUILTIN BOOL Two #-}
{-# BUILTIN TRUE tt #-}
{-# BUILTIN FALSE ff #-}

-- nondependent conditional with traditional syntax
if_then_else_ : forall {l}{X : Set l} -> Two -> X -> X -> X
if tt then t else e = t
if ff then t else e = e

-- dependent conditional cooked for partial application
caseTwo : forall {l}{P : Two -> Set l} -> P tt -> P ff -> (b : Two) -> P b
caseTwo t f tt = t
caseTwo t f ff = f

----------------------------------------------------------------------------
-- lists
----------------------------------------------------------------------------

data List (X : Set) : Set where
  []   : List X
  _,-_ : (x : X)(xs : List X) -> List X
infixr 4 _,-_
{-# COMPILE GHC List = data [] ([] | (:)) #-}
{-# BUILTIN LIST List #-}

----------------------------------------------------------------------------
-- chars and strings
----------------------------------------------------------------------------

postulate       -- this means that we just suppose the following things exist...
  Char : Set
  String : Set
{-# BUILTIN CHAR Char #-}
{-# BUILTIN STRING String #-}

primitive       -- these are baked in; they even work!
  primCharEquality    : Char -> Char -> Two
  primStringAppend    : String -> String -> String
  primStringToList    : String -> List Char
  primStringFromList  : List Char -> String


------------------------------------------------------------------------
-- The Agda standard library
--
-- An inductive definition for the permutation relation
------------------------------------------------------------------------

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

module Data.List.Relation.Binary.Permutation.Inductive
  {a} {A : Set a} where

open import Data.List using (List; []; _∷_)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
import Relation.Binary.Reasoning.Setoid as EqReasoning

------------------------------------------------------------------------
-- An inductive definition of permutation

infix 3 _↭_

data _↭_ : Rel (List A) a where
  refl  : ∀ {xs}        → xs ↭ xs
  prep  : ∀ {xs ys} x   → xs ↭ ys → x ∷ xs ↭ x ∷ ys
  swap  : ∀ {xs ys} x y → xs ↭ ys → x ∷ y ∷ xs ↭ y ∷ x ∷ ys
  trans : ∀ {xs ys zs}  → xs ↭ ys → ys ↭ zs → xs ↭ zs

------------------------------------------------------------------------
-- _↭_ is an equivalence

↭-reflexive : _≡_ ⇒ _↭_
↭-reflexive refl = refl

↭-refl : Reflexive _↭_
↭-refl = refl

↭-sym : ∀ {xs ys} → xs ↭ ys → ys ↭ xs
↭-sym refl                = refl
↭-sym (prep x xs↭ys)      = prep x (↭-sym xs↭ys)
↭-sym (swap x y xs↭ys)    = swap y x (↭-sym xs↭ys)
↭-sym (trans xs↭ys ys↭zs) = trans (↭-sym ys↭zs) (↭-sym xs↭ys)

↭-trans : Transitive _↭_
↭-trans = trans

↭-isEquivalence : IsEquivalence _↭_
↭-isEquivalence = record
  { refl  = refl
  ; sym   = ↭-sym
  ; trans = trans
  }

↭-setoid : Setoid _ _
↭-setoid = record
  { isEquivalence = ↭-isEquivalence
  }

------------------------------------------------------------------------
-- A reasoning API to chain permutation proofs and allow "zooming in"
-- to localised reasoning.

module PermutationReasoning where

  open EqReasoning ↭-setoid
    using (_IsRelatedTo_; relTo)

  open EqReasoning ↭-setoid public
    using (begin_ ; _∎ ; _≡⟨⟩_; _≡⟨_⟩_)
    renaming (_≈⟨_⟩_ to _↭⟨_⟩_; _≈˘⟨_⟩_ to _↭˘⟨_⟩_)

  infixr 2 _∷_<⟨_⟩_  _∷_∷_<<⟨_⟩_

  -- Skip reasoning on the first element
  _∷_<⟨_⟩_ : ∀ x xs {ys zs : List A} → xs ↭ ys →
               (x ∷ ys) IsRelatedTo zs → (x ∷ xs) IsRelatedTo zs
  x ∷ xs <⟨ xs↭ys ⟩ rel = relTo (trans (prep x xs↭ys) (begin rel))

  -- Skip reasoning about the first two elements
  _∷_∷_<<⟨_⟩_ : ∀ x y xs {ys zs : List A} → xs ↭ ys →
                  (y ∷ x ∷ ys) IsRelatedTo zs → (x ∷ y ∷ xs) IsRelatedTo zs
  x ∷ y ∷ xs <<⟨ xs↭ys ⟩ rel = relTo (trans (swap x y xs↭ys) (begin rel))


module foldl where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning

open import lists using (List; []; _∷_; [_,_,_])

foldl : ∀ {A B : Set} → (B → A → B) → B → List A → B
foldl _⊗_ e []       = e
foldl _⊗_ e (x ∷ xs) = foldl _⊗_ (e ⊗ x) xs

test-foldl : ∀ {A B : Set} → (_⊗_ : B → A → B) → (e : B) → (x y z : A)
  → foldl _⊗_ e [ x , y , z ] ≡ ((e ⊗ x) ⊗ y) ⊗ z
test-foldl _⊗_ e x y z = refl


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

open import Cubical.Core.Everything

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

open import Cubical.Data.Bool.Base
open import Cubical.Data.Empty

open import Cubical.Relation.Nullary
open import Cubical.Relation.Nullary.DecidableEq

notnot : ∀ x → not (not x) ≡ x
notnot true  = refl
notnot false = refl

notIsEquiv : isEquiv not
notIsEquiv = isoToIsEquiv (iso not not notnot notnot)

notEquiv : Bool ≃ Bool
notEquiv = (not , notIsEquiv)

notEq : Bool ≡ Bool
notEq = ua notEquiv

private
  -- This computes to false as expected
  nfalse : Bool
  nfalse = transp (λ i → notEq i) i0 true

  -- Sanity check
  nfalsepath : nfalse ≡ false
  nfalsepath = refl

isSetBool : isSet Bool
isSetBool = Discrete→isSet _≟_

true≢false : ¬ true ≡ false
true≢false p = subst (λ b → if b then Bool else ⊥) p true

false≢true : ¬ false ≡ true
false≢true p = subst (λ b → if b then ⊥ else Bool) p true

not≢const : ∀ x → ¬ not x ≡ x
not≢const false = true≢false
not≢const true  = false≢true

zeroˡ : ∀ x → true or x ≡ true
zeroˡ false = refl
zeroˡ true  = refl

zeroʳ : ∀ x → x or true ≡ true
zeroʳ false = refl
zeroʳ true  = refl

or-identityˡ : ∀ x → false or x ≡ x
or-identityˡ false = refl
or-identityˡ true  = refl

or-identityʳ : ∀ x → x or false ≡ x
or-identityʳ false = refl
or-identityʳ true  = refl

or-comm      : ∀ x y → x or y ≡ y or x
or-comm false y =
  false or y ≡⟨ or-identityˡ y ⟩
  y          ≡⟨ sym (or-identityʳ y) ⟩
  y or false ∎
or-comm true y =
  true or y ≡⟨ zeroˡ y ⟩
  true      ≡⟨ sym (zeroʳ y) ⟩
  y or true ∎

or-assoc     : ∀ x y z → x or (y or z) ≡ (x or y) or z
or-assoc false y z =
  false or (y or z)   ≡⟨ or-identityˡ _ ⟩
  y or z              ≡[ i ]⟨ or-identityˡ y (~ i) or z ⟩
  ((false or y) or z) ∎
or-assoc true y z  =
 true or (y or z)  ≡⟨ zeroˡ _ ⟩
  true             ≡⟨ sym (zeroˡ _) ⟩
  true or z        ≡[ i ]⟨ zeroˡ y (~ i) or z ⟩
  (true or y) or z ∎

or-idem      : ∀ x → x or x ≡ x
or-idem false = refl
or-idem true  = refl

⊕-comm : ∀ x y → x ⊕ y ≡ y ⊕ x
⊕-comm false false = refl
⊕-comm false true  = refl
⊕-comm true  false = refl
⊕-comm true  true  = refl

⊕-assoc : ∀ x y z → x ⊕ (y ⊕ z) ≡ (x ⊕ y) ⊕ z
⊕-assoc false y z = refl
⊕-assoc true false z = refl
⊕-assoc true true z = notnot z

not-⊕ˡ : ∀ x y → not (x ⊕ y) ≡ not x ⊕ y
not-⊕ˡ false y = refl
not-⊕ˡ true  y = notnot y

⊕-invol : ∀ x y → x ⊕ (x ⊕ y) ≡ y
⊕-invol false x = refl
⊕-invol true  x = notnot x

isEquiv-⊕ : ∀ x → isEquiv (x ⊕_)
isEquiv-⊕ x = isoToIsEquiv (iso _ (x ⊕_) (⊕-invol x) (⊕-invol x))


module ProjectingRecordMeta where

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

-- Andreas, Feb/Apr 2011
record Prod (A B : Set) : Set where
  constructor _,_
  field
    fst : A
    snd : B

open Prod public

testProj : {A B : Set}(y z : Prod A B) ->
  let X : Prod A B
      X = _       -- Solution: fst y , snd z
  in (C : Set) -> (fst X == fst y -> snd X == snd z -> C) -> C
testProj y z C k = k refl refl
-- ok, Agda handles projections properly during unification

testProj' : {A B : Set}(y z : Prod A B) ->
  let X : Prod A B
      X = _       -- Solution: fst y , snd z
  in Prod (fst X == fst y) (snd X == snd z)
testProj' y z = refl , refl


-- {-# OPTIONS -v tc.conv:30 -v tc.conv.level:60 -v tc.meta.assign:15 #-}

module UniversePolymorphism where

open import Common.Level renaming (_⊔_ to max)

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

infixr 40 _∷_

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

map : ∀ {n a b}{A : Set a}{B : Set b} → (A → B) → Vec A n → Vec B n
map f []       = []
map f (x ∷ xs) = f x ∷ map f xs

vec : ∀ {n a}{A : Set a} → A → Vec A n
vec {zero}  _ = []
vec {suc n} x = x ∷ vec x

_<*>_ : ∀ {n a b}{A : Set a}{B : Set b} → Vec (A → B) n → Vec A n → Vec B n
[]       <*> []       = []
(f ∷ fs) <*> (x ∷ xs) = f x ∷ (fs <*> xs)

flip : ∀ {a b c}{A : Set a}{B : Set b}{C : Set c} →
       (A → B → C) → B → A → C
flip f x y = f y x

module Zip where

  Fun : ∀ {n a} → Vec (Set a) n → Set a → Set a
  Fun []       B = B
  Fun (A ∷ As) B = A → Fun As B

  app : ∀ {n m a}(As : Vec (Set a) n)(B : Set a) →
        Vec (Fun As B) m → Fun (map (flip Vec m) As) (Vec B m)
  app []       B bs = bs
  app (A ∷ As) B fs = λ as → app As B (fs <*> as)

  zipWith : ∀ {n m a}(As : Vec (Set a) n)(B : Set a) →
            Fun As B → Fun (map (flip Vec m) As) (Vec B m)
  zipWith As B f = app As B (vec f)

  zipWith₃ : ∀ {n a}{A B C D : Set a} → (A → B → C → D) → Vec A n → Vec B n → Vec C n → Vec D n
  zipWith₃ = zipWith (_ ∷ _ ∷ _ ∷ []) _

data Σ {a b}(A : Set a)(B : A → Set b) : Set (max a b) where
  _,_ : (x : A)(y : B x) → Σ A B

fst : ∀ {a b}{A : Set a}{B : A → Set b} → Σ A B → A
fst (x , y) = x

snd : ∀ {a b}{A : Set a}{B : A → Set b}(p : Σ A B) → B (fst p)
snd (x , y) = y

-- Normal Σ
List : ∀ {a} → Set a → Set a
List A = Σ _ (Vec A)

nil : ∀ {a}{A : Set a} → List A
nil = _ , []

cons : ∀ {a}{A : Set a} → A → List A → List A
cons x (_ , xs) = _ , x ∷ xs

AnyList : ∀ {i} → Set (lsuc i)
AnyList {i} = Σ (Set i) (List {i})


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

-- Thm: (∃x)A(x), (∀x)(A(x) ⇒ B(x)) ⊢ (∃x)B(x)

-- From: Elliott Mendelson. Introduction to mathematical logic. Chapman &
-- Hall, 4th edition, 1997, p. 155.

-- Rule A4: (∀x)A(x) ⇒ A(t) (with some conditions)
-- Rule E4: A(t) ⇒ (∃x)A(x) (with some conditions)
-- Rule C: From (∃x)A(x) to A(t) (with some conditions)

-- 1. (∃x)A(x)          Hyp
-- 2. (∀x)(A(x) ⇒ B(x)) Hyp
-- 3. A(b)              1, rule C
-- 4. A(b) ⇒ B(b)       2, rule A4
-- 5. B(b)              4,3 MP
-- 6. (∃x)B(x)          5, rule E4

module FOT.Common.FOL.Existential.Witness where

postulate
  D   : Set
  A B : D → Set

module Witness where

  infixr 7 _,_

  data ∃ (A : D → Set) : Set where
    _,_ : ∀ x → A x → ∃ A

  ∃-elim : {A : D → Set}{B : Set} → ∃ A → (∀ x → A x → B) → B
  ∃-elim (x , Ax) h = h x Ax

  -- A proof using the existential elimination.
  prf₁ : ∃ A → (∀ {x} → A x → B x) → ∃ B
  prf₁ h₁ h₂ = ∃-elim h₁ (λ x Ax → x , (h₂ Ax))

  -- A proof using pattern matching.
  prf₂ : ∃ A → (∀ {x} → A x → B x) → ∃ B
  prf₂ (x , Ax) h = x , h Ax

module NonWitness₁ where

  data ∃ (A : D → Set) : Set where
    ∃-intro : ∀ {x} → A x → ∃ A

  ∃-elim : {A : D → Set}{B : Set} → ∃ A → (∀ {x} → A x → B) → B
  ∃-elim (∃-intro Ax) h = h Ax

  -- A proof using the existential elimination.
  prf₁ : ∃ A → (∀ {x} → A x → B x) → ∃ B
  prf₁ h₁ h₂ = ∃-elim h₁ (λ Ax → ∃-intro (h₂ Ax))

  -- A proof using pattern matching.
  prf₂ : ∃ A → (∀ {x} → A x → B x) → ∃ B
  prf₂ (∃-intro Ax) h = ∃-intro (h Ax)

module NonWitness₂ where

  -- We add 3 to the fixities of the Agda standard library 0.8.1 (see
  -- Relation/Nullary/Core.agda).
  infix 6 ¬_

  -- The empty type.
  data ⊥ : Set where

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

  ¬_ : Set → Set
  ¬ A = A → ⊥

  ∃ : (D → Set) → Set
  ∃ A = ¬ (∀ x → ¬ (A x))

  prf : ∃ A → (∀ x → A x → B x) → ∃ B
  prf h₁ h₂ h₃ = h₁ (λ x Ax → h₃ x (h₂ x Ax))


open import Agda.Primitive

module Experimental.Equality where

  data _≡_ {ℓ} {A : Set ℓ} : A → A → Set ℓ where
    refl : ∀ {x : A} → x ≡ x

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

  tran : ∀ {ℓ} {A : Set ℓ} {x y z : A} → x ≡ y → y ≡ z → x ≡ z
  tran refl q = q

  ap : ∀ {ℓ k} {A : Set ℓ} {B : Set k} {x y : A} {f : A → B} → x ≡ y → f x ≡ f y
  ap refl = refl

  transport : ∀ {ℓ k} {A : Set ℓ} (B : A → Set k) {x y : A} → x ≡ y → B x → B y
  transport _ refl u = u


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

open import Cubical.Foundations.Everything renaming (_⁻¹ to _⁻¹ᵖ; assoc to ∙-assoc)
open import Function.Base using (_∋_)
import Cubical.Algebra.Group as Std
-- import Cubical.Structures.Group.Properties
open import MorePropAlgebra.Bundles

module MorePropAlgebra.Properties.Group {ℓ} (assumptions : Group {ℓ}) where
open Group assumptions renaming (Carrier to G)

import MorePropAlgebra.Properties.Monoid
module Monoid'Properties = MorePropAlgebra.Properties.Monoid   (record { Group assumptions }) -- how does this even work without renaming?
module Monoid'           =                            Monoid   (record { Group assumptions })
(      Monoid')          =                            Monoid ∋ (record { Group assumptions })

stdIsGroup : Std.IsGroup 0g _+_ (-_)
stdIsGroup  .Std.IsGroup.isMonoid = Monoid'Properties.stdIsMonoid
stdIsGroup  .Std.IsGroup.inverse  = is-inverse

stdGroup : Std.Group {ℓ}
stdGroup = record { Group assumptions ; isGroup = stdIsGroup }

module GroupLemmas' = Std.GroupLemmas stdGroup

-- module GroupLemmas (G : Group {ℓ}) where
--   open Group G public
--   abstract
--     simplL : (a : Carrier) {b c : Carrier} → a + b ≡ a + c → b ≡ c
--     simplR : {a b : Carrier} (c : Carrier) → a + c ≡ b + c → a ≡ b
--     invInvo : (a : Carrier) → - (- a) ≡ a
--     invId : - 0g ≡ 0g
--     idUniqueL : {e : Carrier} (x : Carrier) → e + x ≡ x → e ≡ 0g
--     idUniqueR : (x : Carrier) {e : Carrier} → x + e ≡ x → e ≡ 0g
--     invUniqueL : {g h : Carrier} → g + h ≡ 0g → g ≡ - h
--     invUniqueR : {g h : Carrier} → g + h ≡ 0g → h ≡ - g
--     invDistr : (a b : Carrier) → - (a + b) ≡ - b - a

-- private
--   simplR = GroupLemmas.simplR G

abstract
  invUniqueL : {g h : G} → g + h ≡ 0g → g ≡ - h
  invUniqueL {g} {h} p = GroupLemmas'.simplR h (p ∙ sym (is-invl h))

  -- ported from `Algebra.Properties.Group`
  private
    right-helper : ∀ x y → y ≡ - x + (x + y)
  right-helper x y = (
    y               ≡⟨ sym (snd (is-identity y)) ⟩
    0g          + y ≡⟨ cong₂ _+_ (sym (snd (is-inverse x))) refl  ⟩
    ((- x) + x) + y ≡⟨ sym (is-assoc (- x) x y) ⟩
    (- x) + (x + y) ∎)

  -- alternative:
  --   follows from uniqueness of -
  --     (a + -a) ≡ 0
  --     ∃! b . a + b = 0
  --   show that a is an additive inverse of - a then it must be THE additive inverse of - a and has to be called - - a which is a by uniqueness
  -involutive : ∀ x → - - x ≡ x
  -involutive x = (
    (- (- x))             ≡⟨ sym (fst (is-identity _)) ⟩
    (- (- x)) + 0g        ≡⟨ cong₂ _+_ refl (sym (snd (is-inverse _))) ⟩
    (- (- x)) + (- x + x) ≡⟨ sym (right-helper (- x) x) ⟩
    x                     ∎)


-- Product of two categories
{-# OPTIONS --safe #-}

module Cubical.Categories.Constructions.BinProduct where

open import Cubical.Categories.Category.Base
open import Cubical.Categories.Functor.Base
open import Cubical.Data.Sigma renaming (_×_ to _×'_)
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Prelude

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

open Category

_×_ : (C : Category ℓC ℓC') → (D : Category ℓD ℓD')
    → Category (ℓ-max ℓC ℓD) (ℓ-max ℓC' ℓD')

(C × D) .ob = (ob C) ×' (ob D)
(C × D) .Hom[_,_] (c , d) (c' , d') = (C [ c , c' ]) ×' (D [ d , d' ])
(C × D) .id = (id C , id D)
(C × D) ._⋆_ _ _ = (_ ⋆⟨ C ⟩ _ , _ ⋆⟨ D ⟩ _)
(C × D) .⋆IdL _ = ≡-× (⋆IdL C _) (⋆IdL D _)
(C × D) .⋆IdR _ = ≡-× (⋆IdR C _) (⋆IdR D _)
(C × D) .⋆Assoc _ _ _ = ≡-× (⋆Assoc C _ _ _) (⋆Assoc D _ _ _)
(C × D) .isSetHom = isSet× (isSetHom C) (isSetHom D)

infixr 5 _×_

-- Some useful functors
module _ (C : Category ℓC ℓC')
         (D : Category ℓD ℓD') where
  open Functor

  module _ (E : Category ℓE ℓE') where
    -- Associativity of product
    ×C-assoc : Functor (C × (D × E)) ((C × D) × E)
    ×C-assoc .F-ob (c , (d , e)) = ((c , d), e)
    ×C-assoc .F-hom (f , (g , h)) = ((f , g), h)
    ×C-assoc .F-id = refl
    ×C-assoc .F-seq _ _ = refl

  -- Left/right injections into product
  linj : (d : ob D) → Functor C (C × D)
  linj d .F-ob c = (c , d)
  linj d .F-hom f = (f , id D)
  linj d .F-id = refl
  linj d .F-seq f g = ≡-× refl (sym (⋆IdL D _))

  rinj : (c : ob C) → Functor D (C × D)
  rinj c .F-ob d = (c , d)
  rinj c .F-hom f = (id C , f)
  rinj c .F-id = refl
  rinj c .F-seq f g = ≡-× (sym (⋆IdL C _)) refl

{-
  TODO:
    - define inverse to `assoc`, prove isomorphism
    - prove product is commutative up to isomorphism
-}


----------------------------------------------------------------------
-- Copyright: 2013, Jan Stolarek, Lodz University of Technology     --
--                                                                  --
-- License: See LICENSE file in root of the repo                    --
-- Repo address: https://github.com/jstolarek/dep-typed-wbl-heaps   --
--                                                                  --
-- Definition of datatypes that represent ordering and functions    --
-- that operate on them. These datatypes are based on ideas         --
-- introduced in "Why Dependent Types Matter".                      --
----------------------------------------------------------------------

module Basics.Ordering where

open import Basics.Nat hiding (_≥_)

-- The ≥ type is a proof of greater-equal relation between two natural
-- numbers. It proves that: a) any number natural is greater or equal
-- to zero and b) any two natural numbers are in ≥ relation if their
-- predecessors are also in that relation.
data _≥_ : Nat → Nat → Set where
  ge0 : {  y : Nat}         → y     ≥ zero
  geS : {x y : Nat} → x ≥ y → suc x ≥ suc y

infixl 4 _≥_

-- Order datatype tells whether two numbers are in ≥ relation or
-- not. In that sense it is an equivalent of Bool datatype. Unlike
-- Bool however, Order supplies a proof of WHY the numbers are (or are
-- not) in the ≥ relation.
data Order : Nat → Nat → Set where
  ge : {x : Nat} {y : Nat} → x ≥ y → Order x y
  le : {x : Nat} {y : Nat} → y ≥ x → Order x y

-- order function takes two natural numbers and compares them,
-- returning the result of comparison together with a proof of the
-- result (result and its proof are encoded by Order datatype).
order : (a : Nat) → (b : Nat) → Order a b
order a       zero    = ge ge0
order zero    (suc b) = le ge0
order (suc a) (suc b) with order a b
order (suc a) (suc b) | ge a≥b = ge (geS a≥b)
order (suc a) (suc b) | le b≥a = le (geS b≥a)


module List where

data Bool : Set where
  true : Bool
  false : Bool

if_then_else_ : {A : Set} -> Bool -> A -> A -> A
if true  then x else y = x
if false then x else y = y

boolElim : (P : Bool -> Set) -> P true -> P false -> (b : Bool) -> P b
boolElim P t f true  = t
boolElim P t f false = f

data False : Set where
data True : Set where
  tt : True

data Or (A B : Set) : Set where
  inl : (a : A) -> Or A B
  inr : (b : B) -> Or A B

orElim : {A B : Set}
    -> (C : Or A B -> Set)
    -> (cl : (a : A) -> C(inl a))
    -> (cr : (b : B) -> C(inr b))
    -> (ab : Or A B)
    -> C ab
orElim {A} {B} C cl cr (inl a) = cl a
orElim {A} {B} C cl cr (inr b) = cr b

data Rel(A : Set) : Set1 where
  rel : (A -> A -> Set) -> Rel A

_is_than_ : {A : Set} -> A -> Rel A -> A -> Set
x is rel f than y = f x y

data Acc {A : Set} (less : Rel A) (x : A) : Set where
  acc : ((y : A) -> y is less than x -> Acc less y) -> Acc less x

data WO {A : Set} (less : Rel A) : Set where
  wo : ((x : A) -> Acc less x) -> WO less

data Nat : Set where
  Z : Nat
  S : Nat -> Nat

eqNat : Nat -> Nat -> Set
eqNat Z Z = True
eqNat (S m) (S n) = eqNat m n
eqNat _ _ = False

substEqNat : (P : Nat -> Set) -> (a b : Nat) -> (e : eqNat a b) -> (P a) -> P b
substEqNat P Z Z e pa = pa
substEqNat P (S x) (S x') e pa = substEqNat (\n -> P(S n)) x  x'  e  pa

ltNat : Nat -> Nat -> Set
ltNat    Z     Z  = False
ltNat    Z  (S n) = True
ltNat (S m) (S n) = ltNat m n
ltNat (S m)    Z  = False

ltZ-elim : (n : Nat) -> ltNat n Z -> {whatever : Set} -> whatever
ltZ-elim Z     ()
ltZ-elim (S _) ()

transNat : (x  y  z : Nat) -> ltNat x y -> ltNat y z -> ltNat x z
transNat x     y     Z     x<y y<z  = ltZ-elim y y<z
transNat x     Z     (S z) x<Z Z<Sz = ltZ-elim x x<Z
transNat Z     (S y) (S z) tt  y<z  = tt
transNat (S x) (S y) (S z) x<y y<z  = transNat x y z x<y y<z

ltNat-S-Lemma : (x : Nat) -> ltNat x (S x)
ltNat-S-Lemma Z     = tt
ltNat-S-Lemma (S x) = ltNat-S-Lemma x

ltNat-S-Lemma2 : (y z : Nat) -> ltNat y (S z) -> Or (eqNat z y) (ltNat y z)
ltNat-S-Lemma2 Z Z h = inl tt
ltNat-S-Lemma2 Z (S x) h = inr tt
ltNat-S-Lemma2 (S x) (S x') h = ltNat-S-Lemma2 x  x' h

ltNatRel : Rel Nat
ltNatRel = rel ltNat

less = ltNatRel

acc-Lemma1 : (x y : Nat) -> Acc less x -> eqNat x y -> Acc less y
acc-Lemma1 x y a e = substEqNat (Acc less ) x  y  e  a

acc-Lemma2 : (x y : Nat) -> Acc less x -> ltNat y x -> Acc less y
acc-Lemma2 x y (acc h) l = h y  l

-- postulate woltNat' : (n : Nat) -> Acc less n
woltNat' : (n : Nat) -> Acc less n
woltNat' Z     = acc (\y y<Z -> ltZ-elim y y<Z)
woltNat' (S x) = acc (\y y<Sx -> orElim (\w -> Acc less y) (\e -> substEqNat (Acc less ) x  y  e  (woltNat' x ) ) (acc-Lemma2 x y (woltNat' x)) (ltNat-S-Lemma2 y x y<Sx ))

woltNat : WO ltNatRel
woltNat = wo woltNat'

postulate le : Nat -> Nat -> Bool
postulate gt : Nat -> Nat -> Bool

data List (A : Set) : Set where
  nil  : List A
  cons : (x : A) -> (xs : List A) -> List A

_++_ : {A : Set} -> List A -> List A -> List A
nil         ++ ys = ys
(cons x xs) ++ ys = cons x (xs ++ ys)

length : {A : Set} -> List A -> Nat
length nil         = Z
length (cons x xs) = S (length xs)

filter : {A : Set} -> (A -> Bool) -> List A -> List A
filter p nil = nil
filter p (cons x xs) = if p x then cons x rest else rest
  where rest = filter p xs

filterLemma
  :  {A : Set} -> (p : A -> Bool) -> (xs : List A)
  -> length (filter p xs) is less than S (length xs)
filterLemma p nil         = tt
filterLemma p (cons x xs) =
  boolElim (\px -> length (if px then cons x (filter p xs)
                                 else (filter p xs))
                   is less than S (S (length xs)))
           (filterLemma p xs)
           (transNat (length (filter p xs)) (S (length xs)) (S (S (length xs)))
                     (filterLemma p xs) (ltNat-S-Lemma (length xs )))
           (p x)

qs : List Nat -> List Nat
qs nil         = nil
qs (cons x xs) = qs (filter (le x) xs)
                 ++ cons x nil
                 ++ qs (filter (gt x) xs)

data Measure : Set1 where
  μ : {M : Set} -> {rel : Rel M} -> (ord : WO rel) -> Measure

down1-measure : Measure
down1-measure = μ woltNat

qs-2-1-hint = \(x : Nat) -> \(xs : List Nat) -> filterLemma (le x) xs
qs-2-2-hint = \(x : Nat) -> \(xs : List Nat) -> filterLemma (gt x) xs


-- This is an implementation of the equality type for Sets. Agda's
-- standard equality is more powerful. The main idea here is to
-- illustrate the equality type.
module Equality where

open import Level
-- The equality of two elements of type A. The type a ≡ b is a family
-- of types which captures the statement of equality in A. Not all of
-- the types are inhabited as in general not all elements are equal
-- here. The only type that are inhabited are a ≡ a by the element
-- that we call definition. This is called refl (for reflection in
-- agda).
data _≡_  {ℓ} {A : Set ℓ} : (a b : A) → Set ℓ where
  refl : {x : A} → x ≡ x

-- ≡ is a symmetric relation.
sym : ∀{ℓ} {A : Set ℓ} {a b : A} → a ≡ b → b ≡ a
sym refl = refl

-- ≡ is a transitive relation.
trans : ∀ {ℓ} {A : Set ℓ} {a b c : A} → a ≡ b → b ≡ c → a ≡ c
trans pAB refl = pAB
-- trans refl pBC = pBC  -- alternate proof of transitivity.

-- Congruence. If we apply f to equals the result are also equal.
cong : ∀{ℓ₀ ℓ₁} {A : Set ℓ₀} {B : Set ℓ₁}
       {a₀ a₁ : A} → (f : A → B) → a₀ ≡ a₁ → f a₀ ≡ f a₁
cong f refl = refl

-- Pretty way of doing equational reasoning.  If we want to prove a₀ ≡
-- b through an intermediate set of equations use this. The general
-- form will look like.
--
-- begin a  ≈ a₀ by p₀
--          ≈ a₁ by p₁
--          ...
--          ≈ b  by p
-- ∎

begin : ∀{ℓ} {A : Set ℓ} (a : A) →  a ≡ a
_≈_by_ : ∀{ℓ} {A : Set ℓ} {a b : A} → a ≡ b → (c : A) → b ≡ c → a ≡ c
_∎ : ∀{ℓ} {A : Set ℓ} (a : A) → A

begin a = refl
aEb ≈ c by bEc = trans aEb bEc
x ∎ = x

infixl 1 _≈_by_
infixl 1 _≡_


-- Minimal implicational modal logic, PHOAS approach, initial encoding

module Pi.BoxMp where

open import Lib using (Nat; suc)

-- Types

infixr 0 _=>_
data Ty : Set where
  UNIT :             Ty
  _=>_ : Ty -> Ty -> Ty
  BOX  : Ty       -> Ty

-- Context and truth judgement with modal depth

Cx : Set1
Cx = Ty -> Nat -> Set

isTrue : Ty -> Nat -> Cx -> Set
isTrue a d tc = tc a d

-- Terms

module BoxMp where
  infixl 1 _$_
  data Tm (d : Nat) (tc : Cx) : Ty -> Set where
    var    : forall {a}      -> isTrue a d tc                 -> Tm d tc a
    lam'   : forall {a b}    -> (isTrue a d tc -> Tm d tc b)  -> Tm d tc (a => b)
    _$_    : forall {a b}    -> Tm d tc (a => b) -> Tm d tc a -> Tm d tc b
    box    : forall {a}      -> Tm (suc d) tc a               -> Tm d tc (BOX a)
    unbox' : forall {>d a b} -> Tm d tc (BOX a)  -> (isTrue a >d tc -> Tm d tc b) -> Tm d tc b

  lam'' : forall {d tc a b} -> (Tm d tc a -> Tm d tc b) -> Tm d tc (a => b)
  lam'' f = lam' \x -> f (var x)

  unbox'' : forall {d >d tc a b} -> Tm d tc (BOX a) -> (Tm >d tc a -> Tm d tc b) -> Tm d tc b
  unbox'' x f = unbox' x \y -> f (var y)

  syntax lam''   (\a -> b)    = lam a => b
  syntax unbox'' x' (\x -> y) = unbox x' as x => y

  Thm : Ty -> Set1
  Thm a = forall {d tc} -> Tm d tc a
open BoxMp public

-- Example theorems

rNec : forall {a} -> Thm a -> Thm (BOX a)
rNec x =
  box x

aK : forall {a b} -> Thm (BOX (a => b) => BOX a => BOX b)
aK =
  lam f' =>
    lam x' =>
      unbox f' as f =>
        unbox x' as x =>
          box (f $ x)

aT : forall {a} -> Thm (BOX a => a)
aT =
  lam x' =>
    unbox x' as x => x

a4 : forall {a} -> Thm (BOX a => BOX (BOX a))
a4 =
  lam x' =>
    unbox x' as x => box (box x)

t1 : forall {a} -> Thm (a => BOX (a => a))
t1 =
  lam _ => box (lam y => y)


------------------------------------------------------------------------------
-- Definition of FOTC Conat using Agda's co-inductive combinators
------------------------------------------------------------------------------

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

module FOT.FOTC.Data.Conat.TypeSL where

open import Codata.Musical.Notation
open import FOTC.Base

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

data Conat : D → Set where
  cozero : Conat zero
  cosucc : ∀ {n} → ∞ (Conat n) → Conat (succ₁ n)

Conat-out : ∀ {n} → Conat n → n ≡ zero ∨ (∃[ n' ] n ≡ succ₁ n' ∧ Conat n')
Conat-out cozero          = inj₁ refl
Conat-out (cosucc {n} Cn) = inj₂ (n , refl , ♭ Cn)

Conat-in : ∀ {n} →
           n ≡ zero ∨ (∃[ n' ] n ≡ succ₁ n' ∧ Conat n') →
           Conat n
Conat-in (inj₁ n≡0)              = subst Conat (sym n≡0) cozero
Conat-in (inj₂ (n' , prf , Cn')) = subst Conat (sym prf) (cosucc (♯ Cn'))

-- TODO (2019-01-04): Agda doesn't accept this definition which was
-- accepted by a previous version.
{-# TERMINATING #-}
Conat-coind : (A : D → Set) →
              (∀ {n} → A n → n ≡ zero ∨ (∃[ n' ] n ≡ succ₁ n' ∧ A n')) →
              ∀ {n} → A n → Conat n
Conat-coind A h An with h An
... | inj₁ refl = cozero
... | inj₂ (n' , refl , An') = cosucc (♯ (Conat-coind A h An'))

-- TODO (07 January 2014): We couldn't prove Conat-stronger-coind.
Conat-stronger-coind :
  ∀ (A : D → Set) {n} →
  (A n → n ≡ zero ∨ (∃[ n' ] n ≡ succ₁ n' ∧ A n')) →
  A n → Conat n
Conat-stronger-coind A h An with h An
... | inj₁ n≡0 = subst Conat (sym n≡0) cozero
... | inj₂ (n' , prf , An') =
  subst Conat (sym prf) (cosucc (♯ (Conat-coind A {!!} An')))

postulate
  ∞D    : D
  ∞-eq : ∞D ≡ succ₁ ∞D

-- TODO (06 January 2014): Agda doesn't accept the proof of Conat ∞D.
{-# TERMINATING #-}
∞-Conat : Conat ∞D
∞-Conat = subst Conat (sym ∞-eq) (cosucc (♯ ∞-Conat))


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

module Number.Prelude.Int where

open import Cubical.Data.Int public using
  ( Int
  ; fromNatInt
  ; fromNegInt
  ; sucInt
  ; predInt
  ; sucInt+
  ; predInt+
  ; _+pos_
  ; _+negsuc_
  ) renaming
  ( isSetInt to isSetℤ
  ; _-_      to infix 7 _-ᶻ_
  ; _+_      to infix 5 _+ᶻ_
  ; pos      to posᶻ
  ; negsuc   to negsucᶻ
  )
open import Number.Instances.Int public using
  ( +negsuc-identityˡ
  ; negsuc+negsuc≡+ⁿ
  ; sneg
  ; spos
  ) renaming
  ( _·_          to _·ᶻ_
  ; -_           to -ᶻ_
  ; _<_          to _<ᶻ_
  ; min          to minᶻ
  ; max          to maxᶻ
  ; is-min       to is-minᶻ
  ; is-max       to is-maxᶻ
  ; ·-reflects-< to ·ᶻ-reflects-<ᶻ
  ; is-LinearlyOrderedCommRing to is-LinearlyOrderedCommRingᶻ
  )

-- Int≅Builtin
-- Int≡Builtin
-- Sign
-- spos
-- sneg
-- _·ˢ_
-- sign
-- signed
-- -_
-- -involutive
-- _·_
-- _·'_
-- _·''_
-- ·''-nullifiesʳ
-- _<_
-- min
-- max
-- <-irrefl
-- <-trans
-- <-asym
-- <-cotrans
-- +-identityʳ
-- +-identityˡ
-- -1·≡-
-- negsuc≡-pos
-- negsuc-reflects-≡
-- pos-reflects-≡
-- possuc+negsuc≡0
-- sucInt[negsuc+pos]≡0
-- +-inverseʳ
-- +-inverseˡ
-- +-inverse
-- pos+pos≡+ⁿ
-- negsuc+negsuc≡+ⁿ
-- +negsuc-identityˡ
-- pos+negsuc≡⊎
-- negsuc+pos≡⊎
-- pos+negsuc≡negsuc+pos
-- predInt-
-- pos+negsuc-swap
-- negsuc+pos-swap
-- +negsuc-assoc
-- sucInt[negsuc+pos]≡pos
-- +pos-inverse
-- +pos-assoc
-- Trichotomy
-- _≟_
-- MinTrichtotomy
-- MaxTrichtotomy
-- min-trichotomy
-- max-trichotomy
-- is-min
-- is-max
-- sucInt-reflects-<
-- predInt-reflects-<
-- sucInt-preserves-<
-- predInt-preserves-<
-- +-preserves-<
-- +-reflects-<
-- +-reflects-<ˡ
-- +-<-ext
-- ·≡·'
-- ·'-nullifiesʳ
-- ·'-nullifiesˡ
-- -distrˡ
-- ·-comm
-- -distrʳ
-- ·'-assoc
-- ·'-assoc≡
-- ·-assoc
-- ·-nullifiesˡ
-- ·-nullifiesʳ
-- ·-identityˡ
-- ·-identityʳ
-- ·-preserves-<
-- ·-reflects-<
-- ·-sucInt
-- ·-sucIntˡ
-- ·-predInt
-- ·-predIntˡ
-- -distrib
-- ·-distribˡ
-- ·-distribʳ

-- ·-Semigroup .IsSemigroup.is-assoc
-- +-Monoid .IsMonoid.is-identity
-- ·-Monoid .IsMonoid.is-identity
-- is-Semiring .IsSemiring.is-dist
-- <-StrictLinearOrder .IsStrictLinearOrder.is-tricho


open import Empty

module Boolean where

  data Bool : Set where
    true : Bool
    false : Bool

  {-# BUILTIN BOOL Bool #-}
  {-# BUILTIN TRUE true #-}
  {-# BUILTIN FALSE false #-}

  T : Bool → Set
  T true = ⊤
  T false = ⊥

  not : Bool → Bool
  not true = false
  not false = true

  and : Bool → Bool → Bool
  and true true = true
  and _ _ = false

  or : Bool → Bool → Bool
  or false false = false
  or _ _ = true

  xor : Bool → Bool → Bool
  xor false true = true
  xor true false = true
  xor _ _ = false

  infixr 6 _∧_
  infixr 5 _∨_

  ¬_ : Set → Set
  ¬ A = A → ⊥

  data _∨_ A B : Set where
    Inl : A → A ∨ B
    Inr : B → A ∨ B

  data _∧_ A B : Set where
    Conj : A → B → A ∧ B

  _⇔_ : (P : Set) → (Q : Set) → Set
  a ⇔ b = (a → b) ∧ (b → a)

  ∧-symmetry : ∀ { A B : Set } → A ∧ B → B ∧ A
  ∧-symmetry (Conj x y) = Conj y x

  ∨-symmetry : ∀ { A B : Set } → A ∨ B → B ∨ A
  ∨-symmetry (Inl x) = Inr x
  ∨-symmetry (Inr y) = Inl y

  and_over : { A B C : Set } → A ∧ ( B ∨ C ) → ( A ∧ B ) ∨ ( A ∧ C )
  and_over (Conj x (Inl y)) = Inl (Conj x y)
  and_over (Conj x (Inr y)) = Inr (Conj x y)

  and_over' : { A B C : Set } → ( A ∧ B ) ∨ ( A ∧ C ) → A ∧ ( B ∨ C )
  and_over' (Inl (Conj x y)) = Conj x (Inl y)
  and_over' (Inr (Conj x y)) = Conj x (Inr y)

  or_over : { A B C : Set } → A ∨ ( B ∧ C ) → ( A ∨ B ) ∧ ( A ∨ C )
  or_over (Inl x) = Conj (Inl x) (Inl x)
  or_over (Inr (Conj x y)) = Conj (Inr x) (Inr y)

  or_over' : { A B C : Set } → ( A ∨ B ) ∧ ( A ∨ C ) → A ∨ ( B ∧ C )
  or_over' (Conj (Inl x) _) = Inl x
  or_over' (Conj _ (Inl y)) = Inl y
  or_over' (Conj (Inr x) (Inr y)) = Inr (Conj x y)

  or_over_negated : { A B : Set } → ( A ∨ ( ¬ A ∧ B ) ) → ( A ∨ B )
  or_over_negated (Inl x) = Inl x
  or_over_negated (Inr (Conj _ y)) = Inr y

  private
    proof₁ : { P Q : Set } → (P ∧ Q) → P
    proof₁ (Conj p q) = p

    proof₂ : { P Q : Set } → (P ∧ Q) → Q
    proof₂ (Conj p q) = q

  deMorgan₁ : { A B : Set } → ¬ A ∧ ¬ B → ¬ (A ∨ B)
  deMorgan₁ (Conj ¬x ¬y) (Inl x) = ¬x x
  deMorgan₁ (Conj ¬x ¬y) (Inr y) = ¬y y
  -- above is clearer if you re-write the type annotation as:
  --deMorgan₁ : { A B : Set } → (A → ⊥) ∧ (B → ⊥) → (A ∨ B) → ⊥

  deMorgan₂ : { A B : Set } → ¬ (A ∨ B) → ¬ A ∧ ¬ B
  deMorgan₂ z = Conj (λ x → z (Inl x)) (λ y → z (Inr y))

  deMorgan₃ : { A B : Set } → ¬ A ∨ ¬ B → ¬ (A ∧ B)
  deMorgan₃ (Inl ¬x) (Conj x _) = ¬x x
  deMorgan₃ (Inr ¬y) (Conj _ y) = ¬y y

  -- NOT provable.
  -- deMorgan₄ : { A B : Set } → ¬ (A ∧ B) → ¬ A ∨ ¬ B


module Vec where

open import Basics
open import Ix
open import All
open import Cutting
open import Tensor

data Vec (X : Set) : Nat -> Set where
  [] : Vec X zero
  _,-_ : forall {n} -> X -> Vec X n -> Vec X (suc n)

_+V_ : forall {X n m} -> Vec X n -> Vec X m -> Vec X (n +N m)
[]        +V ys = ys
(x ,- xs) +V ys = x ,- (xs +V ys)

record Applicative (F : Set -> Set) : Set1 where
  field
    pure : {X : Set} -> X -> F X
    _<*>_ : {S T : Set} -> F (S -> T) -> F S -> F T
  infixl 2 _<*>_

VecAppl : (n : Nat) -> Applicative \ X -> Vec X n
Applicative.pure (VecAppl zero)    x = []
Applicative.pure (VecAppl (suc n)) x = x ,- Applicative.pure (VecAppl n) x
Applicative._<*>_ (VecAppl .zero)    []        []        = []
Applicative._<*>_ (VecAppl .(suc _)) (f ,- fs) (s ,- ss) =
  f s ,- Applicative._<*>_ (VecAppl _) fs ss

module VTRAVERSE {F}(A : Applicative F) where

  open Applicative A

  vtraverse : forall {n S T} -> (S -> F T) -> Vec S n -> F (Vec T n)
  vtraverse f []        = pure []
  vtraverse f (s ,- ss) = pure _,-_ <*> f s <*> vtraverse f ss

Matrix : Set -> Nat * Nat -> Set
Matrix X (i , j) = Vec (Vec X i) j

xpose : forall {X ij} -> Matrix X ij -> Matrix X (swap ij)
xpose = vtraverse id where
  open VTRAVERSE (VecAppl _)

module VECALL {I : Set}{P : I -> Set}{n : Nat}where

  open Applicative (VecAppl n)

  vecAll : {is : List I} ->
         All (\ i -> Vec (P i) n) is -> Vec (All P is) n
  vecAll {[]} pss = pure <>
  vecAll {i ,- is} (ps , pss) = pure _,_ <*> ps <*> vecAll pss

  VecLiftAlg : (C : I |> I) ->
             Algebra (Cutting C) P ->
             Algebra (Cutting C) (\ i -> Vec (P i) n)
  VecLiftAlg C alg i (c 8>< pss) = pure (alg i << (c 8><_)) <*> vecAll pss

open VECALL

NatCutVecAlg : {X : Set} -> Algebra (Cutting NatCut) (Vec X)
NatCutVecAlg {X} .(m +N n) (m , n , refl .(m +N n) 8>< xm , xn , <>) = xm +V xn

open RECTANGLE

NatCut2DMatAlg : {X : Set} -> Algebra (Cutting RectCut) (Matrix X)
NatCut2DMatAlg _ (inl c 8>< ms) = VecLiftAlg NatCut NatCutVecAlg _ (c 8>< ms)
NatCut2DMatAlg _ (inr c 8>< ms) = NatCutVecAlg _ (c 8>< ms)


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

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

module Test₁ where

  record ⊤ {a} : Set a where
    constructor tt

  data G : (A : Set) → ⊤ {_} → Set where
    d : (x : ⊤) → G ⊤ x

  test : (g : G ⊤ tt) → Set
  test (d x) = ⊤

module Test₂ where

  postulate A : Set
            a : A

  record R {a} : Set a where
    constructor mkR
    field x : A

  data G : (A : Set) → R {_} → Set where
    d : (x : R) → G R x

  test : (g : G R (mkR a)) → R
  test (d x) = x

module Test₃ where

  postulate A : Set
            a : A

  record R {a} : Set a where
    constructor mkR
    field x y : A

  data G : (A : Set) → R {_} → Set where
    d : (x : R) → G R x

  -- Forced: mkR x y
  test₁ : ∀ x y → (g : G R (mkR x y)) → Set
  test₁ x y (d (mkR x y)) = A

  -- .(mkR x y) turns into z with x = .(R.x z) and y = .(R.y z)
  test₂ : ∀ x y → (g : G R (mkR x y)) → Set
  test₂ x y (d .(mkR x y)) = A

  test₃ : ∀ x y → (g : G R (mkR x y)) → Set
  test₃ .(R.x z) .(R.y z) (d z) = A


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

open import Level
-- open import Data.Product using (curry; _,_)
-- open import Function using () renaming (_∘_ to _·_)

open import Categories.Support.PropositionalEquality

open import Categories.Category
open import Categories.Categories
open import Categories.Object.Terminal
open import Categories.Terminal
open import Categories.Functor using (Functor) renaming (_∘_ to _∘F_; _≡_ to _≡F_; id to idF)
open import Categories.Functor.Constant using (Constant)
open import Categories.Bifunctor using (Bifunctor; reduce-×)
open import Categories.Product using (assocʳ; πˡ; πʳ)
open import Categories.NaturalIsomorphism
open import Categories.Bicategory.Helpers using (module BicategoryHelperFunctors)

record Bicategory (o ℓ t e : Level) : Set (suc (o ⊔ ℓ ⊔ t ⊔ e)) where
  open Terminal (One {ℓ} {t} {e})
  field
    Obj : Set o
    _⇒_ : (A B : Obj) → Category ℓ t e
    id : {A : Obj} → Functor ⊤ (A ⇒ A)
    —∘— : {A B C : Obj} → Bifunctor (B ⇒ C) (A ⇒ B) (A ⇒ C)

  _∘_ : {A B C : Obj} {L R : Category ℓ t e} → Functor L (B ⇒ C) → Functor R (A ⇒ B) → Bifunctor L R (A ⇒ C)
  _∘_ {A} {B} {C} F G = reduce-× {D₁ = B ⇒ C} {D₂ = A ⇒ B} —∘— F G

  field
    λᵤ : {A B : Obj} → NaturalIsomorphism (id ∘ idF {C = A ⇒ B}) (πʳ {C = ⊤} {A ⇒ B})
    ρᵤ : {A B : Obj} → NaturalIsomorphism (idF {C = A ⇒ B} ∘ id) (πˡ {C = A ⇒ B} {⊤})
    α : {A B C D : Obj} → NaturalIsomorphism (idF ∘ —∘—) (((—∘— ∘ idF) ∘F assocʳ (C ⇒ D) (B ⇒ C) (A ⇒ B)))

  private module BHF = BicategoryHelperFunctors(Obj)(_⇒_)(—∘—)(id)
  private module EQ = BHF.Coherence(λᵤ)(ρᵤ)(α)

  private module _⇒_ (A B : Obj) = Category (A ⇒ B)
  open _⇒_ public using () renaming (Obj to _⇒₁_)

  field
    .triangle : {A B C : Obj} (f : A ⇒₁ B) (g : B ⇒₁ C) → EQ.Triangle f g
    .pentagon : {A B C D E : Obj} (f : A ⇒₁ B) (g : B ⇒₁ C) (h : C ⇒₁ D) (i : D ⇒₁ E)
        → EQ.Pentagon f g h i

  -- do note that most of the "convenience" definitions in the Helpers module should really
  -- be here (but usable in both places).  Clean that up later.


module Prelude.Eq where

open import Prelude.Level

infix 4 _==_

data _==_ {l : Level}{A : Set l} (x : A) : A → Set l where
  refl : x == x

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

{-# BUILTIN EQUALITY _==_  #-}


module Categories.Functor.Construction.Product where

open import Categories.Category
open import Categories.Category.Cartesian
open import Categories.Category.BinaryProducts
open import Categories.Functor.Bifunctor

open import Data.Product using (_,_)

module _ {o ℓ e} (𝒞 : Category o ℓ e) (cartesian : Cartesian 𝒞) where
  open Cartesian cartesian
  open BinaryProducts products

  open Category 𝒞

  Product : Bifunctor 𝒞 𝒞 𝒞
  Product = record
              { F₀ = λ (x , y) → x × y
              ; F₁ = λ (f , g) → f ⁂ g
              ; identity = Equiv.trans (⟨⟩-cong₂ identityˡ identityˡ) η
              ; homomorphism = Equiv.sym ⁂∘⁂
              ; F-resp-≈ = λ (x , y) → ⁂-cong₂ x y
              }


open import Type

module Relator.Sets {ℓ ℓₑ ℓₛ} {E : Type{ℓₑ}} {S : Type{ℓₛ}} (_∈_ : E → S → Type{ℓ}) where

open import Functional
open import Logic.Propositional
open import Logic.Predicate

_∉_ : E → S → Type
_∉_ = (¬_) ∘₂ (_∈_)

_∋_ : S → E → Type
_∋_ = swap(_∈_)

_∌_ : S → E → Type
_∌_ = (¬_) ∘₂ (_∋_)

_⊆_ : S → S → Type
_⊆_ L₁ L₂ = ∀ₗ(x ↦ ((_→ᶠ_) on₂ (x ∈_)) L₁ L₂)

_⊇_ : S → S → Type
_⊇_ L₁ L₂ = ∀ₗ(x ↦ ((_←_) on₂ (x ∈_)) L₁ L₂)

_≡_ : S → S → Type
_≡_ L₁ L₂ = ∀ₗ(x ↦ ((_↔_) on₂ (x ∈_)) L₁ L₂)

_⊈_ : S → S → Type
_⊈_ = (¬_) ∘₂ (_⊆_)

_⊉_ : S → S → Type
_⊉_ = (¬_) ∘₂ (_⊇_)

_≢_ : S → S → Type
_≢_ = (¬_) ∘₂ (_≡_)


module Adjunctions where

open import Library
open import Categories
open import Functors

open Cat
open Fun

record Adj {a b c d}(C : Cat {a}{b})(D : Cat {c}{d}) : Set (a ⊔ b ⊔ c ⊔ d)
  where
  constructor adjunction
  field L        : Fun C D
        R        : Fun D C
        left     : {X : Obj C}{Y : Obj D} →
                   Hom D (OMap L X) Y → Hom C X (OMap R Y)
        right    : {X : Obj C}{Y : Obj D} →
                   Hom C X (OMap R Y) → Hom D (OMap L X) Y
        lawa     : {X : Obj C}{Y : Obj D}(f : Hom D (OMap L X) Y) →
                   right (left f) ≅ f
        lawb     : {X : Obj C}{Y : Obj D}(f : Hom C X (OMap R Y)) →
                   left (right f) ≅ f
        natleft  : {X X' : Obj C}{Y Y' : Obj D}
                   (f : Hom C X' X)(g : Hom D Y Y')
                   (h : Hom D (OMap L X) Y) →
                   comp C (HMap R g) (comp C (left h) f)
                   ≅
                   left (comp D g (comp D h (HMap L f)))
        natright : {X X' : Obj C}{Y Y' : Obj D}
                   (f : Hom C X' X)(g : Hom D Y Y')
                   (h : Hom C X (OMap R Y)) →
                   right (comp C (HMap R g) (comp C h f))
                   ≅
                   comp D g (comp D (right h) (HMap L f))


module #6 where

open import Level
open import Data.Bool
open import Relation.Binary.PropositionalEquality

{-
Exercise 1.6. Show that if we define A × B :≡ ∏(x:2) rec2(U, A, B, x), then we can give a
definition of indA×B for which the definitional equalities stated in §1.5 hold propositionally (i.e. using equality
types). (This requires the function extensionality axiom, which is introduced in §2.9.)
-}

rec₂ : ∀{c}{C : Set c} → C → C → Bool → C
rec₂ c₀ c₁ true = c₁
rec₂ c₀ c₁ false = c₀

ind₂ : ∀{c}(C : Bool → Set c) → C false → C true → (x : Bool) → C x
ind₂ C c₀ c₁ true = c₁
ind₂ C c₀ c₁ false = c₀

_×_ : ∀ {i} → Set i → Set i → Set i
A × B = (b : Bool) → if b then A else B

module ProductTwo {a}{A B : Set a} where

  _,_ : A → B → A × B
  _,_ x y true = x
  _,_ x y false = y

  proj₁ : A × B → A
  proj₁ x = x true

  proj₂ : A × B → B
  proj₂ x = x false

  postulate
    extensionality : ∀ {a b} {A : Set a} {B : A → Set b} (f g : (a : A) → B a) → (∀ x → f x ≡ g x) → f ≡ g

  indₓ₂ : ∀{c}{C : A × B -> Set c} → (f : (x : A)(y : B) → C (x , y)) → (x : A × B) → C (proj₁ x , proj₂ x)
  indₓ₂ f x = f (proj₁ x) (proj₂ x)

  indₓ₂-β : ∀{c}{C : A × B -> Set c} → (f : (x : A)(y : B) → C (x , y)) → (x : A × B) → indₓ₂ {C = C} f x ≡ f (proj₁ x) (proj₂ x)
  indₓ₂-β f x = refl


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

module Algebra.Construct.Free.Semilattice.Extensionality where

open import Prelude

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

open import HITs.PropositionalTruncation.Sugar
import HITs.PropositionalTruncation as PropTrunc
open import HITs.PropositionalTruncation.Properties

open import Path.Reasoning

infix 4 _↭_
_↭_ : 𝒦 A → 𝒦 A → Type _
xs ↭ ys = ∀ x → x ∈ xs ↔ x ∈ ys

in-cons : (x : A) (xs : 𝒦 A) → x ∈ xs → xs ≡ x ∷ xs
in-cons = λ x → ∥ in-cons′ x ∥⇓
  where
  in-cons′ : ∀ x → xs ∈𝒦 A ⇒∥ (x ∈ xs → xs ≡ x ∷ xs) ∥
  ∥ in-cons′ y ∥-prop {xs} p q i y∈xs = trunc xs (y ∷ xs) (p y∈xs) (q y∈xs) i
  ∥ in-cons′ y ∥[] ()
  ∥ in-cons′ y ∥ x ∷ xs ⟨ Pxs ⟩ = PropTrunc.rec (trunc _ _)
    λ { (inl x≡y) → sym (dup x xs) ; cong (_∷ x ∷ xs) x≡y
      ; (inr y∈xs) → cong (x ∷_) (Pxs y∈xs) ; com x y xs
      }

subset-ext : ∀ xs ys → (∀ (x : A) → x ∈ xs → x ∈ ys) → xs ∪ ys ≡ ys
subset-ext = ∥ subset-ext′ ∥⇓
  where
  subset-ext′ : xs ∈𝒦 A ⇒∥ (∀ ys → (∀ x → x ∈ xs → x ∈ ys) → xs ∪ ys ≡ ys) ∥
  ∥ subset-ext′ ∥-prop {xs} p q i ys perm = trunc (xs ∪ ys) ys (p ys perm) (q ys perm) i
  ∥ subset-ext′ ∥[] _ _ = refl
  ∥ subset-ext′ ∥ x ∷ xs ⟨ Pxs ⟩ ys perm =
    (x ∷ xs) ∪ ys ≡⟨ cons-distrib-∪ x xs ys ⟩
    xs ∪ (x ∷ ys) ≡⟨ Pxs (x ∷ ys) (λ y y∈xs → ∣ inr (perm y ∣ inr y∈xs ∣) ∣) ⟩
    x ∷ ys ≡˘⟨ in-cons x ys (perm x ∣ inl refl ∣) ⟩
    ys ∎

extensional : (xs ys : 𝒦 A) → (xs ↭ ys) → xs ≡ ys
extensional xs ys xs↭ys =
  xs ≡˘⟨ subset-ext ys xs (inv ∘ xs↭ys) ⟩
  ys ∪ xs ≡⟨ ∪-comm ys xs ⟩
  xs ∪ ys ≡⟨ subset-ext xs ys (fun ∘ xs↭ys) ⟩
  ys ∎


------------------------------------------------------------------------
-- The Agda standard library
--
-- Results concerning uniqueness of identity proofs
------------------------------------------------------------------------

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

module Axiom.UniquenessOfIdentityProofs where

open import Data.Empty
open import Relation.Nullary
open import Relation.Binary.Core
open import Relation.Binary.PropositionalEquality.Core

------------------------------------------------------------------------
-- Definition
--
-- Uniqueness of Identity Proofs (UIP) states that all proofs of
-- equality are themselves equal. In other words, the equality relation
-- is irrelevant. Here we define UIP relative to a given type.

UIP : ∀ {a} (A : Set a) → Set a
UIP A = Irrelevant {A = A} _≡_

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

-- UIP always holds when using axiom K
-- (see `Axiom.UniquenessOfIdentityProofs.WithK`).

-- The existence of a constant function over proofs of equality for
-- elements in A is enough to prove UIP for A. Indeed, we can relate any
-- proof to its image via this function which we then know is equal to
-- the image of any other proof.

module Constant⇒UIP
  {a} {A : Set a} (f : _≡_ {A = A} ⇒ _≡_)
  (f-constant : ∀ {a b} (p q : a ≡ b) → f p ≡ f q)
  where

  ≡-canonical : ∀ {a b} (p : a ≡ b) → trans (sym (f refl)) (f p) ≡ p
  ≡-canonical refl = trans-symˡ (f refl)

  ≡-irrelevant : UIP A
  ≡-irrelevant p q = begin
    p                          ≡⟨ sym (≡-canonical p) ⟩
    trans (sym (f refl)) (f p) ≡⟨ cong (trans _) (f-constant p q) ⟩
    trans (sym (f refl)) (f q) ≡⟨ ≡-canonical q ⟩
    q                          ∎ where open ≡-Reasoning

-- If equality is decidable for a given type, then we can prove UIP for
-- that type. Indeed, the decision procedure allows us to define a
-- function over proofs of equality which is constant: it returns the
-- proof produced by the decision procedure.

module Decidable⇒UIP
  {a} {A : Set a} (_≟_ : Decidable (_≡_ {A = A}))
  where

  ≡-normalise : _≡_ {A = A} ⇒ _≡_
  ≡-normalise {a} {b} a≡b with a ≟ b
  ... | yes p = p
  ... | no ¬p = ⊥-elim (¬p a≡b)

  ≡-normalise-constant : ∀ {a b} (p q : a ≡ b) → ≡-normalise p ≡ ≡-normalise q
  ≡-normalise-constant {a} {b} p q with a ≟ b
  ... | yes _ = refl
  ... | no ¬p = ⊥-elim (¬p p)

  ≡-irrelevant : UIP A
  ≡-irrelevant = Constant⇒UIP.≡-irrelevant ≡-normalise ≡-normalise-constant


module plfa-code.Negation where

open import Relation.Binary.PropositionalEquality using (_≡_; refl)
open import Data.Nat using (ℕ; zero; suc)
open import Data.Empty using (⊥; ⊥-elim)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Product using (_×_) renaming (_,_ to ⟨_,_⟩)
open import plfa-code.Isomorphism using (_≃_; extensionality)

¬_ : Set → Set
¬ A = A → ⊥

¬-elim : ∀ {A : Set}
  → ¬ A
  → A
    ---
  → ⊥
¬-elim ¬x x = ¬x x

infix 3 ¬_

¬¬-intro : ∀ {A : Set}
  → A
    -----
  → ¬ ¬ A
¬¬-intro x  =  λ ¬x → ¬x x

¬¬-intro′ : ∀ {A : Set}
  → A
    -----
  → ¬ ¬ A
¬¬-intro′ x ¬x = ¬x x

¬¬¬-elim : ∀ {A : Set}
  → ¬ ¬ ¬ A
    -------
  → ¬ A
¬¬¬-elim ¬¬¬x  =  λ x → ¬¬¬x (¬¬-intro x)

contraposition : ∀ {A B : Set}
  → (A → B)
    ------------
  → (¬ B → ¬ A)
contraposition f ¬y x = ¬y (f x)

_≢_ : ∀ {A : Set} → A → A → Set
x ≢ y  =  ¬ (x ≡ y)

_ : 1 ≢ 2
_ = λ ()

peano : ∀ {m : ℕ} → zero ≢ suc m
peano = λ ()

id : ⊥ → ⊥
id x = x

id′ : ⊥ → ⊥
id′ ()

id≡id′ : id ≡ id′
id≡id′ = extensionality (λ ())

assimilation : ∀ {A : Set} (¬x ¬x′ : ¬ A) → ¬x ≡ ¬x′
assimilation ¬x ¬x′ = extensionality (λ x → ⊥-elim (¬x′ x))

open Data.Nat using (_<_; _≤_; z≤n; s≤s)
open Relation.Binary.PropositionalEquality using (cong)
open import Function
open Data.Product using (proj₁; proj₂)

---------- practice ----------

<-irreflexive : ∀ {n : ℕ} → ¬ (n < n)
<-irreflexive {suc n} (s≤s n<n) = <-irreflexive n<n

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

inv-< : ∀ {m n} → suc m < suc n → m < n
inv-< (s≤s sm<sn) = sm<sn

inv-≡ : ∀ {m n} → suc m ≡ suc n → m ≡ n
inv-≡ refl = refl

<-trichotomy : ∀ (m n : ℕ) → Trichotomy m n
<-trichotomy zero    zero    = equal refl      (λ ()) (λ ())
<-trichotomy zero    (suc n) = less  (s≤s z≤n) (λ ()) (λ ())
<-trichotomy (suc m) zero    = greater (s≤s z≤n) (λ ()) (λ ())
<-trichotomy (suc m) (suc n) with <-trichotomy m n
... | less    m<n ¬n<m ¬m≡n = less       (s≤s m<n) (¬n<m ∘ inv-<) (¬m≡n ∘ inv-≡)
... | greater n<m ¬m≡n ¬m<n = greater    (s≤s n<m) (¬m≡n ∘ inv-≡) (¬m<n ∘ inv-<)
... | equal   m≡n ¬m<n ¬n<m = equal (cong suc m≡n) (¬m<n ∘ inv-<) (¬n<m ∘ inv-<)

⊎-dual-× : ∀ (A B : Set) → ¬ (A ⊎ B) ≃ (¬ A) × (¬ B)
⊎-dual-× A B =
  record
  { to      = λ ¬-A⊎B → ⟨ (¬-A⊎B ∘ inj₁) , (¬-A⊎B ∘ inj₂) ⟩
  ; from    = λ{ ¬A×¬B (inj₁ a) → proj₁ ¬A×¬B a
               ; ¬A×¬B (inj₂ b) → proj₂ ¬A×¬B b
               }
  ; from∘to = λ{x → assimilation _ x}
  ; to∘from = λ{ ⟨ ¬a , ¬b ⟩ → refl}
  }

-- ¬ (A × B) ≃ (¬ A) ⊎ (¬ B) does not hold, but we could say:
⊎¬-implies-¬× : ∀ (A B : Set) → (¬ A) ⊎ (¬ B) → ¬ (A × B)
⊎¬-implies-¬× A B (inj₁ ¬a) = λ ab → ¬a (proj₁ ab)
⊎¬-implies-¬× A B (inj₂ ¬b) = λ ab → ¬b (proj₂ ab)

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

em-irrefutable : ∀ {A : Set} → ¬ ¬ (A ⊎ ¬ A)
em-irrefutable k = k (inj₂ (λ x → k (inj₁ x)))

---------- practice ----------
-- to prove the implying relations among a group of
-- proposition P₀ P₁ P₂ ... Pₙ, we just need prove P₀ → P₁,
-- P₁ → P₂, ..., Pₙ₋₁ → Pₙ, Pₙ → P₀.

P₀ = ∀ {A : Set} → A ⊎ ¬ A
P₁ = ∀ {A : Set} → (¬ ¬ A → A)
P₂ = ∀ {A B : Set} → ((A → B) → A) → A
P₃ = ∀ {A B : Set} → (A → B) → ¬ A ⊎ B
P₄ = ∀ {A B : Set} → ¬ (¬ A × ¬ B) → A ⊎ B

P₀⇒P₁ : P₀ → P₁
P₀⇒P₁ p₀ {A} ¬¬a with p₀ {A}
...                 | inj₁ a  = a
...                 | inj₂ ¬a = ⊥-elim (¬¬a ¬a)

P₁⇒P₂ : P₁ → P₂
P₁⇒P₂ p₁ x = p₁ $ λ ¬a → (¬a $ x $ p₁ ∘ const ∘ ¬a)

P₂⇒P₃ : P₂ → P₃
P₂⇒P₃ p₂ {A} {B} f = p₂ {¬ A ⊎ B} {⊥} (λ z → inj₁ (z ∘ inj₂ ∘ f))

--- the prove 'P₃⇒P₄'  below referenced https://github.com/googleson78/plfa

P₃⇒P₀ : P₃ → P₀
P₃⇒P₀ p₃ {A} with p₃ Function.id
...        | inj₁ ¬x = inj₂ ¬x
...        | inj₂  x = inj₁ x

P₁⇒P₄ : P₁ → P₄
P₁⇒P₄ p₁ {A} {B} ¬x = p₁ (λ ¬y → ¬x ⟨ ¬y ∘ inj₁ , ¬y ∘ inj₂ ⟩)

P₃⇒P₄ : P₃ → P₄
P₃⇒P₄ = P₁⇒P₄ ∘ P₀⇒P₁ ∘ P₃⇒P₀

P₄⇒P₀ : P₄ → P₀
P₄⇒P₀ p₄ {A} = p₄ {A} {¬ A} $ proj₂ ˢ proj₁

Stable : Set → Set
Stable A = ¬ ¬ A → A

¬⇒stable : ∀ {A : Set} → ¬ A → Stable (¬ A)
¬⇒stable ¬a = ¬¬¬-elim

×⇒stable : ∀ {A B : Set} → Stable A → Stable B → Stable (A × B)
×⇒stable a b = λ x → ⟨ (a $ λ z → x (z ∘ proj₁)) , (b $ λ z → x (z ∘ proj₂)) ⟩


------------------------------------------------------------------------
-- The Agda standard library
--
-- Vectors defined as functions from a finite set to a type.
------------------------------------------------------------------------

-- This implementation is designed for reasoning about fixed-size
-- vectors where ease of retrieval of elements is prioritised.

-- See `Data.Vec` for an alternative implementation using inductive
-- data-types, which is more suitable for reasoning about vectors that
-- will grow or shrink in size.

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

module Data.Vec.Functional where

open import Data.Fin.Base using (Fin; zero; suc; splitAt; punchIn)
open import Data.List.Base as L using (List)
open import Data.Nat.Base using (ℕ; zero; suc; _+_)
open import Data.Product using (Σ; ∃; _×_; _,_; proj₁; proj₂)
open import Data.Sum.Base using (_⊎_; inj₁; inj₂; [_,_])
open import Data.Vec.Base as V using (Vec)
open import Function
open import Level using (Level)

infixr 5 _∷_ _++_
infixl 4 _⊛_

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

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

Vector : Set a → ℕ → Set a
Vector A n = Fin n → A

------------------------------------------------------------------------
-- Conversion

toVec : ∀ {n} → Vector A n → Vec A n
toVec = V.tabulate

fromVec : ∀ {n} → Vec A n → Vector A n
fromVec = V.lookup

toList : ∀ {n} → Vector A n → List A
toList = L.tabulate

fromList : ∀ (xs : List A) → Vector A (L.length xs)
fromList = L.lookup

------------------------------------------------------------------------
-- Construction and deconstruction

[] : Vector A zero
[] ()

_∷_ : ∀ {n} → A → Vector A n → Vector A (suc n)
(x ∷ xs) zero    = x
(x ∷ xs) (suc i) = xs i

head : ∀ {n} → Vector A (suc n) → A
head xs = xs zero

tail : ∀ {n} → Vector A (suc n) → Vector A n
tail xs = xs ∘ suc

uncons : ∀ {n} → Vector A (suc n) → A × Vector A n
uncons xs = head xs , tail xs

replicate : ∀ {n} → A → Vector A n
replicate = const

remove : ∀ {n} → Fin (suc n) → Vector A (suc n) → Vector A n
remove i t = t ∘ punchIn i

------------------------------------------------------------------------
-- Transformations

map : (A → B) → ∀ {n} → Vector A n → Vector B n
map f xs = f ∘ xs

_++_ : ∀ {m n} → Vector A m → Vector A n → Vector A (m + n)
_++_ {m = m} xs ys i = [ xs , ys ] (splitAt m i)

foldr : (A → B → B) → B → ∀ {n} → Vector A n → B
foldr f z {n = zero}  xs = z
foldr f z {n = suc n} xs = f (head xs) (foldr f z (tail xs))

foldl : (B → A → B) → B → ∀ {n} → Vector A n → B
foldl f z {n = zero}  xs = z
foldl f z {n = suc n} xs = foldl f (f z (head xs)) (tail xs)

rearrange : ∀ {m n} → (Fin m → Fin n) → Vector A n → Vector A m
rearrange r xs = xs ∘ r

_⊛_ : ∀ {n} → Vector (A → B) n → Vector A n → Vector B n
_⊛_ = _ˢ_

zipWith : (A → B → C) → ∀ {n} → Vector A n → Vector B n → Vector C n
zipWith f xs ys i = f (xs i) (ys i)

zip : ∀ {n} → Vector A n → Vector B n → Vector (A × B) n
zip = zipWith _,_


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

syntax Monoid | M

type
  * : 0-ary

term
  unit : * | ε
  add  : *  *  ->  * | _⊕_ l20

theory
  (εU⊕ᴸ) a |> add (unit, a) = a
  (εU⊕ᴿ) a |> add (a, unit) = a
  (⊕A) a b c |> add (add(a, b), c) = add (a, add(b, c))
-}

module Monoid.Signature where

open import SOAS.Context

open import SOAS.Common

open import SOAS.Syntax.Signature *T public
open import SOAS.Syntax.Build *T public

-- Operator symbols
data Mₒ : Set where
  unitₒ addₒ : Mₒ

-- Term signature
M:Sig : Signature Mₒ
M:Sig = sig λ
  {  unitₒ  → ⟼₀ *
  ;  addₒ   → (⊢₀ *) , (⊢₀ *) ⟼₂ *
  }

open Signature M:Sig public


{-# OPTIONS --safe #-}

module Cubical.Algebra.CommRing.Instances.UnivariatePoly where

open import Cubical.Foundations.Prelude
open import Cubical.Algebra.CommRing
open import Cubical.Algebra.Polynomials.Univariate.Base
open import Cubical.Algebra.Polynomials.Univariate.Properties

private
  variable
    ℓ : Level

UnivariatePoly : (CommRing ℓ) → CommRing ℓ
UnivariatePoly R = (PolyMod.Poly R) , str
    where
      open CommRingStr --(snd R)
      str : CommRingStr (PolyMod.Poly R)
      0r str = PolyModTheory.0P R
      1r str = PolyModTheory.1P R
      _+_ str = PolyModTheory._Poly+_ R
      _·_ str = PolyModTheory._Poly*_ R
      - str = PolyModTheory.Poly- R
      isCommRing str = makeIsCommRing (PolyMod.isSetPoly R)
                                      (PolyModTheory.Poly+Assoc R)
                                      (PolyModTheory.Poly+Rid R)
                                      (PolyModTheory.Poly+Inverses R)
                                      (PolyModTheory.Poly+Comm  R)
                                      (PolyModTheory.Poly*Associative R)
                                      (PolyModTheory.Poly*Rid R)
                                      (PolyModTheory.Poly*LDistrPoly+ R)
                                      (PolyModTheory.Poly*Commutative R)