{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.ZCohomology.Groups.Wedge where

open import Cubical.ZCohomology.Base
open import Cubical.ZCohomology.Properties
open import Cubical.ZCohomology.MayerVietorisUnreduced
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Pointed
open import Cubical.HITs.Wedge
open import Cubical.HITs.SetTruncation renaming (elim to sElim ; elim2 to sElim2)
open import Cubical.HITs.PropositionalTruncation renaming (rec to pRec ; ∣_∣ to ∣_∣₁)
open import Cubical.Data.Nat
open import Cubical.Data.Prod
open import Cubical.Data.Unit
open import Cubical.Algebra.Group

open import Cubical.ZCohomology.Groups.Unit
open import Cubical.ZCohomology.Groups.Sn

open import Cubical.HITs.Pushout

--- This module contains a proof that Hⁿ(A ⋁ B) ≅ Hⁿ(A) × Hⁿ(B), n ≥ 1

module _ {ℓ ℓ'} (A : Pointed ℓ) (B : Pointed ℓ') where
  module I = MV (typ A) (typ B) Unit (λ _ → pt A) (λ _ → pt B)

  Hⁿ-⋁ : (n : ℕ) → GroupEquiv (coHomGr (suc n) (A ⋁ B)) (×coHomGr (suc n) (typ A) (typ B))
  Hⁿ-⋁ zero =
    BijectionIsoToGroupEquiv
      (bij-iso
        (grouphom
          (GroupHom.fun (I.i 1))
          (sElim2 (λ _ _ → isOfHLevelPath 2 (isOfHLevelΣ 2 setTruncIsSet λ _ → setTruncIsSet) _ _)
                  λ a b → GroupHom.isHom (I.i 1) ∣ a ∣₂ ∣ b ∣₂))
        (sElim (λ _ → isOfHLevelΠ 2 λ _ → isOfHLevelPath 2 setTruncIsSet _ _)
                λ f inker → helper ∣ f ∣₂ (I.Ker-i⊂Im-d 0 ∣ f ∣₂ inker))
        (sigmaElim (λ _ → isOfHLevelSuc 1 propTruncIsProp)
                   λ f g → I.Ker-Δ⊂Im-i 1 (∣ f ∣₂ , g) (isOfHLevelSuc 0 (isContrHⁿ-Unit 0) _ _)))
    where
    surj-helper : (x : coHom 0 Unit)
            → isInIm _ _ (I.Δ 0) x
    surj-helper =
      sElim (λ _ → isOfHLevelSuc 1 propTruncIsProp)
            λ f → ∣ (∣ (λ _ → f tt) ∣₂ , 0ₕ) , cong ∣_∣₂ (funExt (λ _ → cong ((f tt) +ₖ_) -0ₖ ∙ rUnitₖ (f tt))) ∣₁

    helper : (x : coHom 1 (A ⋁ B)) → isInIm _ _ (I.d 0) x
                  → x ≡ 0ₕ
    helper x inim =
      pRec (setTruncIsSet _ _)
           (λ p → sym (snd p) ∙
                       MV.Im-Δ⊂Ker-d _ _ Unit (λ _ → pt A) (λ _ → pt B) 0 (fst p) (surj-helper (fst p)))
             inim
  Hⁿ-⋁ (suc n) =
    vSES→GroupEquiv _ _
      (ses (isOfHLevelSuc 0 (isContrHⁿ-Unit n))
           (isOfHLevelSuc 0 (isContrHⁿ-Unit (suc n)))
           (I.d (suc n))
           (I.Δ (suc (suc n)))
           (I.i (suc (suc n)))
           (I.Ker-i⊂Im-d (suc n))
           (I.Ker-Δ⊂Im-i (suc (suc n))))

  open import Cubical.Foundations.Isomorphism
  wedgeConnected : ((x : typ A) → ∥ pt A ≡ x ∥) → ((x : typ B) → ∥ pt B ≡ x ∥) → (x : A ⋁ B) → ∥ (inl (pt A)) ≡ x ∥
  wedgeConnected conA conB =
    PushoutToProp (λ _ → propTruncIsProp)
                  (λ a → pRec propTruncIsProp (λ p → ∣ cong inl p ∣₁) (conA a))
                  λ b → pRec propTruncIsProp (λ p → ∣ push tt ∙ cong inr p ∣₁) (conB b)


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

open import Algebra.Construct.DirectProduct

module Construct.DirectProduct where

open import Algebra
import Algebra.Construct.DirectProduct as DirectProduct
open import Data.Product
open import Data.Product.Relation.Binary.Pointwise.NonDependent
open import Level using (Level; _⊔_)

private
  variable
    a b ℓ₁ ℓ₂ : Level

------------------------------------------------------------------------
-- Raw bundles

rawQuasigroup : RawQuasigroup a ℓ₁ → RawQuasigroup b ℓ₂ → RawQuasigroup (a ⊔ b) (ℓ₁ ⊔ ℓ₂)
rawQuasigroup M N = record
  { Carrier = M.Carrier × N.Carrier
  ; _≈_     = Pointwise M._≈_ N._≈_
  ; _∙_     = zip M._∙_ N._∙_
  ; _\\_    = zip M._\\_ N._\\_
  ; _//_    = zip M._//_ N._//_
  } where module M = RawQuasigroup M; module N = RawQuasigroup N

rawLoop : RawLoop a ℓ₁ → RawLoop b ℓ₂ → RawLoop (a ⊔ b) (ℓ₁ ⊔ ℓ₂)
rawLoop M N = record
  { Carrier = M.Carrier × N.Carrier
  ; _≈_     = Pointwise M._≈_ N._≈_
  ; _∙_     = zip M._∙_ N._∙_
  ; _\\_    = zip M._\\_ N._\\_
  ; _//_    = zip M._//_ N._//_
  ; ε       = M.ε , N.ε
  } where module M = RawLoop M; module N = RawLoop N

------------------------------------------------------------------------
-- Bundles

unitalMagma : UnitalMagma a ℓ₁ → UnitalMagma b ℓ₂ → UnitalMagma (a ⊔ b) (ℓ₁ ⊔ ℓ₂)
unitalMagma M N = record
  { ε = M.ε , N.ε
  ; isUnitalMagma = record
    { isMagma = Magma.isMagma (magma M.magma N.magma)
    ; identity = (M.identityˡ , N.identityˡ <*>_)
               , (M.identityʳ , N.identityʳ <*>_)
    }
  } where module M = UnitalMagma M; module N = UnitalMagma N

invertibleMagma : InvertibleMagma a ℓ₁ → InvertibleMagma b ℓ₂ → InvertibleMagma (a ⊔ b) (ℓ₁ ⊔ ℓ₂)
invertibleMagma M N = record
  { _⁻¹ = map M._⁻¹ N._⁻¹
  ; isInvertibleMagma = record
    { isMagma = Magma.isMagma (magma M.magma N.magma)
    ; inverse = (λ x → (M.inverseˡ , N.inverseˡ) <*> x)
                , (λ x → (M.inverseʳ , N.inverseʳ) <*> x)
    }
  } where module M = InvertibleMagma M; module N = InvertibleMagma N

invertibleUnitalMagma : InvertibleUnitalMagma a ℓ₁ → InvertibleUnitalMagma b ℓ₂ → InvertibleUnitalMagma (a ⊔ b) (ℓ₁ ⊔ ℓ₂)
invertibleUnitalMagma M N = record
  { ε = M.ε , N.ε
  ; isInvertibleUnitalMagma = record
    { isInvertibleMagma = InvertibleMagma.isInvertibleMagma (invertibleMagma M.invertibleMagma N.invertibleMagma)
    ; identity = (M.identityˡ , N.identityˡ <*>_)
               , (M.identityʳ , N.identityʳ <*>_)
    }
  } where module M = InvertibleUnitalMagma M; module N = InvertibleUnitalMagma N


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

module Categories.Category.Finite.Fin.Instance.Parallel where

open import Data.Nat using (ℕ)
open import Data.Fin
open import Data.Fin.Patterns
open import Relation.Binary.PropositionalEquality using (_≡_ ; refl)

open import Categories.Category.Finite.Fin
open import Categories.Category

private
  variable
    a b c d : Fin 2

--
--  /---0---\
-- 0         1
--  \---1---/
--
ParallelShape : FinCatShape
ParallelShape = record
  { size     = 2
  ; ∣_⇒_∣    = card
  ; hasShape = record
    { id        = id
    ; _∘_       = _∘_
    ; assoc     = assoc
    ; identityˡ = identityˡ
    ; identityʳ = identityʳ
    }
  }
  where card : Fin 2 → Fin 2 → ℕ
        card 0F 0F = 1
        card 0F 1F = 2
        card 1F 0F = 0
        card 1F 1F = 1

        id : Fin (card a a)
        id {0F} = 0F
        id {1F} = 0F

        _∘_ : ∀ {a b c} → Fin (card b c) → Fin (card a b) → Fin (card a c)
        _∘_ {0F} {0F} {0F} 0F 0F = 0F
        _∘_ {0F} {0F} {1F} 0F 0F = 0F
        _∘_ {0F} {0F} {1F} 1F 0F = 1F
        _∘_ {0F} {1F} {1F} 0F 0F = 0F
        _∘_ {0F} {1F} {1F} 0F 1F = 1F
        _∘_ {1F} {1F} {1F} 0F 0F = 0F

        assoc : ∀ {f : Fin (card a b)} {g : Fin (card b c)} {h : Fin (card c d)} →
                  ((h ∘ g) ∘ f) ≡ (h ∘ (g ∘ f))
        assoc {0F} {0F} {0F} {0F} {0F} {0F} {0F} = refl
        assoc {0F} {0F} {0F} {1F} {0F} {0F} {0F} = refl
        assoc {0F} {0F} {0F} {1F} {0F} {0F} {1F} = refl
        assoc {0F} {0F} {1F} {1F} {0F} {0F} {0F} = refl
        assoc {0F} {0F} {1F} {1F} {0F} {1F} {0F} = refl
        assoc {0F} {1F} {1F} {1F} {0F} {0F} {0F} = refl
        assoc {0F} {1F} {1F} {1F} {1F} {0F} {0F} = refl
        assoc {1F} {1F} {1F} {1F} {0F} {0F} {0F} = refl

        identityˡ : ∀ {a b} {f : Fin (card a b)} → (id ∘ f) ≡ f
        identityˡ {0F} {0F} {0F} = refl
        identityˡ {0F} {1F} {0F} = refl
        identityˡ {0F} {1F} {1F} = refl
        identityˡ {1F} {1F} {0F} = refl

        identityʳ : ∀ {a b} {f : Fin (card a b)} → (f ∘ id) ≡ f
        identityʳ {0F} {0F} {0F} = refl
        identityʳ {0F} {1F} {0F} = refl
        identityʳ {0F} {1F} {1F} = refl
        identityʳ {1F} {1F} {0F} = refl

Parallel : Category _ _ _
Parallel = FinCategory ParallelShape

module Parallel = Category Parallel


------------------------------------------------------------------------
-- The Agda standard library
--
-- Consequences of a monomorphism between binary relations
------------------------------------------------------------------------

-- See Data.Nat.Binary.Properties for examples of how this and similar
-- modules can be used to easily translate properties between types.

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

open import Function
open import Relation.Binary
open import Relation.Binary.Morphism

module Relation.Binary.Morphism.RelMonomorphism
  {a b ℓ₁ ℓ₂} {A : Set a} {B : Set b}
  {_∼₁_ : Rel A ℓ₁} {_∼₂_ : Rel B ℓ₂}
  {⟦_⟧ : A → B} (isMonomorphism : IsRelMonomorphism _∼₁_ _∼₂_ ⟦_⟧)
  where

open import Data.Sum.Base as Sum
open import Relation.Nullary using (yes; no)
open import Relation.Nullary.Decidable

open IsRelMonomorphism isMonomorphism

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

refl : Reflexive _∼₂_ → Reflexive _∼₁_
refl refl = injective refl

sym : Symmetric _∼₂_ → Symmetric _∼₁_
sym sym x∼y = injective (sym (cong x∼y))

trans : Transitive _∼₂_ → Transitive _∼₁_
trans trans x∼y y∼z = injective (trans (cong x∼y) (cong y∼z))

total : Total _∼₂_ → Total _∼₁_
total total x y = Sum.map injective injective (total ⟦ x ⟧ ⟦ y ⟧)

asym : Asymmetric _∼₂_ → Asymmetric _∼₁_
asym asym x∼y y∼x = asym (cong x∼y) (cong y∼x)

dec : Decidable _∼₂_ → Decidable _∼₁_
dec _∼?_ x y = map′ injective cong (⟦ x ⟧ ∼? ⟦ y ⟧)

------------------------------------------------------------------------
-- Structures

isEquivalence : IsEquivalence _∼₂_ → IsEquivalence _∼₁_
isEquivalence isEq = record
  { refl  = refl  E.refl
  ; sym   = sym   E.sym
  ; trans = trans E.trans
  } where module E = IsEquivalence isEq

isDecEquivalence : IsDecEquivalence _∼₂_ → IsDecEquivalence _∼₁_
isDecEquivalence isDecEq = record
  { isEquivalence  = isEquivalence E.isEquivalence
  ; _≟_            = dec E._≟_
  } where module E = IsDecEquivalence isDecEq


module InfConj where

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

record Stream (A : Set) : Set where
  coinductive
  constructor _∷_
  field
    hd : A
    tl : Stream A
open Stream public

-- | Partial elements
record D (A : Set) : Set where
  coinductive
  field step : A ⊎ D A
open D public

-- | Lift ⊎ to relations
data _⊎'_ {A B : Set} (R : A → A → Set) (S : B → B → Set) : A ⊎ B → A ⊎ B → Set where
  inj₁' : {x y : A} → R x y → (R ⊎' S) (inj₁ x) (inj₁ y)
  inj₂' : {x y : B} → S x y → (R ⊎' S) (inj₂ x) (inj₂ y)

-- | Bisimilarity for partial elements
record _~_ {A : Set} (x y : D A) : Set where
  coinductive
  field step~ : (_≡_ ⊎' _~_) (x .step) (y .step)
open _~_ public

-- | Injection into D
η : {A : Set} → A → D A
η a .step = inj₁ a

-- | Conjunction for partial Booleans
_∧'_ : D Bool → D Bool → D Bool
(x ∧' y) .step with x .step  | y .step
(x ∧' y) .step | inj₁ false  | v           = inj₁ false
(x ∧' y) .step | inj₁ true   | v           = v
(x ∧' y) .step | inj₂ x'     | inj₁ false  = inj₁ false
(x ∧' y) .step | inj₂ x'     | inj₁ true   = inj₂ x'
(x ∧' y) .step | inj₂ x'     | inj₂ y'     = inj₂ (x' ∧' y')

-- | Infinite conjunction
⋀∞ : Stream Bool → D Bool
⋀∞ s .step with s .hd
⋀∞ s .step | false = inj₁ false
⋀∞ s .step | true = inj₂ (⋀∞ (s .tl))

-- | Constant stream
K : {A : Set} → A → Stream A
K a .hd = a
K a .tl = K a

-- | Non-terminating computation
⊥ : {A : Set} → D A
⊥ .step = inj₂ ⊥

-- | Infinite conjunction of constant stream does not terminate
prop : ⋀∞ (K true) ~ ⊥
prop .step~ = inj₂' prop

-- | If there is an entry "false" in the stream, then the infinite conjunction
-- terminates. Here is just an example.
ex : ⋀∞ (false ∷ K true) ~ η false
ex .step~ = inj₁' refl


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

-----------------------------------------------------
-- Σ types
-----------------------------------------------------
data Σ {A : Set} (P : A → Set) : Set where
    Σ_intro : ∀ (a : A) → P a → Σ P

-----------------------------------------------------
-- Π type
-----------------------------------------------------
data Π {A : Set} (P : A → Set) : Set where
    Π_intro : (∀ (a : A) → P a) → Π P

-----------------------------------------------------
-- constT
-----------------------------------------------------
constT : ∀ (X : Set) (Y : Set) → Y → Set
constT x _ _ = x

-----------------------------------------------------
-- Tuples using Σ types (const)
-----------------------------------------------------
Σ-pair : ∀ (A B : Set) → Set
Σ-pair a b = Σ (constT b a)

Σ-mkPair : ∀ {A : Set}  {B : Set} → A → B → Σ-pair A B
Σ-mkPair a b = Σ_intro a b

Σ-fst : ∀ {A B : Set} → Σ-pair A B → A
Σ-fst (Σ_intro a _) = a

Σ-snd : ∀ {A B : Set} → Σ-pair A B → B
Σ-snd (Σ_intro _ b) = b

-----------------------------------------------------
-- Exponential using Π type (const)
-----------------------------------------------------
Π-function : ∀ (A B : Set) → Set
Π-function a b = Π (constT b a)

Π-mkFunction : ∀ {A B : Set} → (A → B) → Π-function A B
Π-mkFunction f = Π_intro f

Π-apply : ∀ {A B : Set} → Π-function A B → A → B
Π-apply (Π_intro f) a = f a

-----------------------------------------------------
-- bool
-----------------------------------------------------
bool : ∀ (A B : Set) → Bool → Set
bool a _ true  = a
bool _ b false = b

-----------------------------------------------------
-- Sum type using Σ types
-----------------------------------------------------
Σ-sum : ∀ (A B : Set) → Set
Σ-sum a b = Σ (bool a b)

Σ-sum_left : ∀ {A : Set} (B : Set) → A → Σ-sum A B
Σ-sum_left _ a = Σ_intro true a

Σ-sum_right : ∀ {B : Set} (A : Set) → B → Σ-sum A B
Σ-sum_right _ b = Σ_intro false b

Σ-sum_elim : ∀ {A B R : Set} → (A → R) → (B → R) → Σ-sum A B → R
Σ-sum_elim f _ (Σ_intro true  a) = f a
Σ-sum_elim _ g (Σ_intro false b) = g b

-----------------------------------------------------
-- prodPredicate
-----------------------------------------------------
prodPredicate : ∀ (A B R : Set) → Set
prodPredicate a b r = (a → r) → (b → r) → r

-----------------------------------------------------
-- Sum type using Π types
-----------------------------------------------------
data Π' {a b} {A : Set a} (P : A → Set b) : Set (a ⊔ b) where
    Π'_intro : (∀ (a : A) → P a) → Π' P

Π-sum : ∀ (A B : Set) → Set₁
Π-sum a b = Π' (prodPredicate a b)

Π-sum-left : ∀ {A : Set} (B : Set) → A → Π-sum A B
Π-sum-left _ a = Π'_intro (\_ f _ → f a)

Π-sum-right : ∀ {A : Set} (B : Set) → B → Π-sum A B
Π-sum-right _ b = Π'_intro (\_ _ g → g b)

Π-sum-elim : ∀ {A B R : Set} → (A → R) → (B → R) → Π-sum A B → R
Π-sum-elim f g (Π'_intro elim) = elim _ f g

-----------------------------------------------------
-- Extra: Tuples using Π types
-----------------------------------------------------
Π-pair : ∀ (A B : Set) → Set
Π-pair a b = Π (bool a b)

Π-mkPair : ∀ {A B : Set} → A → B → Π-pair A B
Π-mkPair a b = Π_intro f
    where
    f : (b : Bool) → bool _ _ b
    f true = a
    f false = b

Π-fst : ∀ {A B : Set} → Π-pair A B → A
Π-fst (Π_intro f) = f true

Π-snd : ∀ {A B : Set} → Π-pair A B → B
Π-snd (Π_intro f) = f false

---
-- ??
--

data Σ' {a b} {A : Set a} (P : A → Set b) : Set (a ⊔ b) where
    Σ'_intro : ∀ (a : A) → P a → Σ' P

id : ∀ {A : Set} → A → A
id a = a

x : ∀ (A : Set) → Set1
x a = Σ (\(b : Set1) → (a → b))

mk : ∀ (A B : Set) → A → x A B
mk _ b a' = Σ'_intro b (\f g → f (g a'))

elim : {A B : Set} → (A → B) → x A B → B
elim f (Σ'_intro _ g) = g id f

 -- : ∀ {A : Set} (B : Set) → A → Π-sum A B
--Π-sum-left _ a = Π'_intro (\_ f _ → f a)
--
--Π-sum-right : ∀ {A : Set} (B : Set) → B → Π-sum A B
--Π-sum-right _ b = Π'_intro (\_ _ g → g b)
--
--Π-sum-elim : ∀ {A B R : Set} → (A → R) → (B → R) → Π-sum A B → R
--Π-sum-elim f g (Π'_intro elim) = elim _ f g


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties satisfied by strict partial orders
------------------------------------------------------------------------

open import Relation.Binary

module Relation.Binary.Properties.StrictPartialOrder
       {s₁ s₂ s₃} (SPO : StrictPartialOrder s₁ s₂ s₃) where

open Relation.Binary.StrictPartialOrder SPO
  renaming (trans to <-trans)
import Relation.Binary.StrictToNonStrict as Conv
open Conv _≈_ _<_

------------------------------------------------------------------------
-- Strict partial orders can be converted to posets

poset : Poset _ _ _
poset = record
  { isPartialOrder = record
    { isPreorder = record
        { isEquivalence = isEquivalence
        ; reflexive     = reflexive
        ; trans         = trans isEquivalence <-resp-≈ <-trans
        }
    ; antisym = antisym isEquivalence <-trans irrefl
    }
  }

open Poset poset public


------------------------------------------------------------------------
-- The Agda standard library
--
-- Bisimilarity for Conats
------------------------------------------------------------------------

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

module Codata.Conat.Bisimilarity where

open import Level using (0ℓ)
open import Size
open import Codata.Thunk
open import Codata.Conat
open import Relation.Binary

infix 1 _⊢_≈_
data _⊢_≈_ i : (m n : Conat ∞) → Set where
  zero : i ⊢ zero ≈ zero
  suc  : ∀ {m n} → Thunk^R _⊢_≈_ i m n → i ⊢ suc m ≈ suc n

refl : ∀ {i m} → i ⊢ m ≈ m
refl {m = zero}  = zero
refl {m = suc m} = suc λ where .force → refl

sym : ∀ {i m n} → i ⊢ m ≈ n → i ⊢ n ≈ m
sym zero     = zero
sym (suc eq) = suc λ where .force → sym (eq .force)

trans : ∀ {i m n p} → i ⊢ m ≈ n → i ⊢ n ≈ p → i ⊢ m ≈ p
trans zero      zero      = zero
trans (suc eq₁) (suc eq₂) = suc λ where .force → trans (eq₁ .force) (eq₂ .force)

isEquivalence : ∀ {i} → IsEquivalence (i ⊢_≈_)
isEquivalence = record
  { refl  = refl
  ; sym   = sym
  ; trans = trans
  }

setoid : Size → Setoid 0ℓ 0ℓ
setoid i = record
  { isEquivalence = isEquivalence {i = i}
  }

module ≈-Reasoning {i} where

  open import Relation.Binary.Reasoning.Setoid (setoid i) public

infix 1 _⊢_≲_
data _⊢_≲_ i : (m n : Conat ∞) → Set where
  z≲n : ∀ {n} → i ⊢ zero ≲ n
  s≲s : ∀ {m n} → Thunk^R _⊢_≲_ i m n → i ⊢ suc m ≲ suc n

≈⇒≲ : ∀ {i m n} → i ⊢ m ≈ n → i ⊢ m ≲ n
≈⇒≲ zero     = z≲n
≈⇒≲ (suc eq) = s≲s λ where .force → ≈⇒≲ (eq .force)

≲-refl : ∀ {i m} → i ⊢ m ≲ m
≲-refl = ≈⇒≲ refl

≲-antisym : ∀ {i m n} → i ⊢ m ≲ n → i ⊢ n ≲ m → i ⊢ m ≈ n
≲-antisym z≲n      z≲n      = zero
≲-antisym (s≲s le) (s≲s ge) = suc λ where .force → ≲-antisym (le .force) (ge .force)

≲-trans : ∀ {i m n p} → i ⊢ m ≲ n → i ⊢ n ≲ p → i ⊢ m ≲ p
≲-trans z≲n       _         = z≲n
≲-trans (s≲s le₁) (s≲s le₂) = s≲s λ where .force → ≲-trans (le₁ .force) (le₂ .force)


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.Group.Subgroup where

open import Cubical.Core.Everything
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma

open import Cubical.Algebra
open import Cubical.Algebra.Group.Morphism
open import Cubical.Algebra.Monoid.Submonoid

open import Cubical.Relation.Unary
open import Cubical.Relation.Unary.Subtype

open import Cubical.HITs.PropositionalTruncation

record IsSubgroup {c ℓ} (G : Group c) (Member : Pred ⟨ G ⟩ ℓ) : Type (ℓ-max c ℓ) where
  constructor issubgroup

  private module G = Group G

  field
    preservesOp : G._•_ Preserves₂ Member
    preservesInv : G._⁻¹ Preserves Member
    preservesId : G.ε ∈ Member

  isSubmonoid : IsSubmonoid G.monoid Member
  isSubmonoid = record
    { preservesOp = preservesOp
    ; preservesId = preservesId
    }

  open IsSubmonoid isSubmonoid hiding (preservesOp; preservesId; _^_) public

  _⁻¹ : Op₁ Carrier
  (x , subx) ⁻¹ = x G.⁻¹ , preservesInv subx

  inverseˡ : LeftInverse ε _⁻¹ _•_
  inverseˡ _ = ΣPathTransport→PathΣ _ _ (G.inverseˡ _ , isProp[ Member ] _ _ _)

  inverseʳ : RightInverse ε _⁻¹ _•_
  inverseʳ _ = ΣPathTransport→PathΣ _ _ (G.inverseʳ _ , isProp[ Member ] _ _ _)

  inverse : Inverse ε _⁻¹ _•_
  inverse = inverseˡ , inverseʳ

  isGroup : IsGroup Carrier _•_ ε _⁻¹
  isGroup = record
    { isMonoid = isMonoid
    ; inverse = inverse
    }

  group : Group _
  group = record { isGroup = isGroup }

  open Group group using
    ( _^_
    ; _/_
    ; _/ˡ_
    ; inv-uniqueˡ
    ; inv-uniqueʳ
    ; cancelˡ
    ; cancelʳ
    ) public

record Subgroup {c} (G : Group c) ℓ : Type (ℓ-max c (ℓ-suc ℓ)) where
  constructor mksubgroup

  private module G = Group G

  field
    Member : Pred ⟨ G ⟩ ℓ
    isSubgroup : IsSubgroup G Member

  open IsSubgroup isSubgroup public

  submonoid : Submonoid G.monoid ℓ
  submonoid = record { isSubmonoid = isSubmonoid }

  open Submonoid submonoid using (submagma; subsemigroup)

instance
  SubgroupCarrier : ∀ {c ℓ} {G : Group c} → HasCarrier (Subgroup G ℓ) _
  SubgroupCarrier = record { ⟨_⟩ = Subgroup.Carrier }

private
  variable
    c ℓ : Level
    G : Group c

module _ {G : Group c} where
  open Group G

  ε-isSubgroup : IsSubgroup G ｛ ε ｝
  ε-isSubgroup = record
    { preservesOp = map2 λ p q → cong₂ _•_ p q ∙ identityʳ ε
    ; preservesInv = map λ p → cong _⁻¹ p ∙ cancelʳ ε (inverseˡ ε ∙ sym (identityʳ ε))
    ; preservesId = ∣ refl ∣
    }

  ε-subgroup : Subgroup G _
  ε-subgroup = record { isSubgroup = ε-isSubgroup }

  U-isSubgroup : IsSubgroup G U
  U-isSubgroup = record {} -- trivial

  U-subgroup : Subgroup G _
  U-subgroup = record { isSubgroup = U-isSubgroup }

IsNormal : Subgroup G ℓ → Type _
IsNormal {G = G} N =
  ∀ ((n , _) : ⟨ N ⟩) (g : ⟨ G ⟩) → g • n • g ⁻¹ ∈ Subgroup.Member N
  where
    open Group G

NormalSubgroup : Group c → (ℓ : Level) → Type _
NormalSubgroup G ℓ = Σ (Subgroup G ℓ) IsNormal


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

open import Categories.Category.Core
open import Categories.Comonad

-- verbatim dual of Categories.Adjoint.Construction.EilenbergMoore
module Categories.Adjoint.Construction.CoEilenbergMoore {o ℓ e} {C : Category o ℓ e} (M : Comonad C) where

open import Categories.Category.Construction.CoEilenbergMoore M
open import Categories.Adjoint
open import Categories.Functor
open import Categories.Functor.Properties
open import Categories.NaturalTransformation.NaturalIsomorphism using (niHelper)
open import Categories.NaturalTransformation.Core
open import Categories.NaturalTransformation.NaturalIsomorphism using (_≃_)
open import Categories.Morphism.Reasoning C

private
  module C = Category C
  module M = Comonad M
  open M.F
  open C
  open HomReasoning
  open Equiv

Forgetful : Functor CoEilenbergMoore C
Forgetful = record
  { F₀           = Comodule.A
  ; F₁           = Comodule⇒.arr
  ; identity     = refl
  ; homomorphism = refl
  ; F-resp-≈     = λ eq → eq
  }

Cofree : Functor C CoEilenbergMoore
Cofree = record
 { F₀ = λ A → record
  { A = F₀ A
  ; coaction = M.δ.η A
  ; commute = M.sym-assoc
  ; identity = Comonad.identityʳ M
  }
 ; F₁ = λ f → record
  { arr = F₁ f
  ; commute = M.δ.commute f
  }
 ; identity = identity
 ; homomorphism = homomorphism
 ; F-resp-≈ = F-resp-≈
 }

UC≃M : Forgetful ∘F Cofree ≃ M.F
UC≃M = niHelper (record
 { η = λ _ → F₁ C.id
 ; η⁻¹ = λ _ → F₁ C.id
 ; commute = λ f → [ M.F ]-resp-square id-comm-sym
 ; iso = λ _ → record
    { isoˡ = elimˡ identity ○ identity
    ; isoʳ = elimˡ identity ○ identity
    }
 })

Forgetful⊣Cofree : Forgetful ⊣ Cofree
Forgetful⊣Cofree = record
 { unit = record
  { η = λ X → let module X = Comodule X
      in record
        { arr     = X.coaction
        ; commute = ⟺ X.commute
        }
  ; commute = Comodule⇒.commute
  ; sym-commute = λ f → ⟺ (Comodule⇒.commute f)
  }
 ; counit = record
  { η = M.ε.η
  ; commute = M.ε.commute
  ; sym-commute = M.ε.sym-commute
  }
 ; zig = λ {A} → Comodule.identity A
 ; zag = λ {B} → Comonad.identityˡ M
 }


open import Agda.Builtin.FromNat
open import Data.Nat.Base  as ℕ using (ℕ; suc; zero; _>_; _≤?_)
open import Data.List.Base as L using (List; _∷_; []; _++_)
open import Relation.Nullary.Decidable using (True)
open import Relation.Binary.PropositionalEquality as P using (_≡_)

module Data.Pos where

open import Data.Nat.FromNat public

data ℕ⁺ : Set where
  suc : ℕ → ℕ⁺

instance
  NumberPos : Number ℕ⁺
  NumberPos = record { Constraint = Pos; fromNat = fromℕ }
    where
      Pos : ℕ → Set
      Pos n = True (suc zero ≤? n)
      fromℕ : (n : ℕ) {{p : Pos n}} → ℕ⁺
      fromℕ zero {{()}}
      fromℕ (suc zero)    = suc zero
      fromℕ (suc (suc n)) = suc (suc n)

toℕ : ℕ⁺ → ℕ
toℕ (suc n) = suc n

_+_ : ℕ⁺ → ℕ⁺ → ℕ⁺
suc m + n = suc (m ℕ.+ toℕ n)

toℕ-+ : (m {n} : ℕ⁺) → toℕ m ℕ.+ toℕ n ≡ toℕ (m + n)
toℕ-+ (suc m) = P.refl

replicate⁺ : ∀ {a} {A : Set a} → ℕ⁺ → A → List A
replicate⁺ (suc n) x = x ∷ L.replicate n x

replicate⁺-++-commute : ∀ {a} {A : Set a} {x : A} (m n : ℕ⁺) →
  replicate⁺ m x ++ replicate⁺ n x ≡ replicate⁺ (m + n) x
replicate⁺-++-commute (suc m) (suc n)
  = P.cong (_ ∷_) (replicate-++-commute m (suc n))
  where
    replicate-++-commute : ∀ {a} {A : Set a} {x : A} (m n : ℕ) →
      L.replicate m x ++ L.replicate n x ≡ L.replicate (m ℕ.+ n) x
    replicate-++-commute  zero   n = P.refl
    replicate-++-commute (suc m) n = P.cong (_ ∷_) (replicate-++-commute m n)


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

{-

This file defines integers as equivalence classes of pairs of natural numbers
using a direct & untruncated HIT definition (cf. HITs.Ints.DiffInt)

and some basic operations, and the zero value:

succ : DeltaInt → DeltaInt
pred : DeltaInt → DeltaInt
zero : {a : ℕ} → DeltaInt

and conversion function for ℕ and Int:

fromℕ : ℕ → DeltaInt
fromInt : Int → DeltaInt
toInt : DeltaInt → Int

and a generalized version of cancel:

cancelN : ∀ a b n → a ⊖ b ≡ (n + a) ⊖ n + b

-}

module Cubical.HITs.Ints.DeltaInt.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Data.Nat hiding (zero)
open import Cubical.Data.Int hiding (abs; sgn; _+_)

infixl 5 _⊖_
data DeltaInt : Type₀ where
  _⊖_    : ℕ → ℕ → DeltaInt
  cancel : ∀ a b → a ⊖ b ≡ suc a ⊖ suc b

succ : DeltaInt → DeltaInt
succ (x ⊖ y) = suc x ⊖ y
succ (cancel a b i) = cancel (suc a) b i

pred : DeltaInt → DeltaInt
pred (x ⊖ y) = x ⊖ suc y
pred (cancel a b i) = cancel a (suc b) i

zero : {a : ℕ} → DeltaInt
zero {a} = a ⊖ a

fromℕ : ℕ → DeltaInt
fromℕ n = n ⊖ 0

fromInt : Int → DeltaInt
fromInt (pos n) = fromℕ n
fromInt (negsuc n) = 0 ⊖ suc n

toInt : DeltaInt → Int
toInt (x ⊖ y) = x ℕ- y
toInt (cancel a b i) = a ℕ- b

cancelN : ∀ a b n → a ⊖ b ≡ (n + a) ⊖ n + b
cancelN a b 0 = refl
cancelN a b (suc n) = cancelN a b n ∙ cancel (n + a) (n + b)


open import Agda.Builtin.Nat

data List (A : Set) : Set where
  lnil : List A
  lcons : A → List A → List A

data Vec (A : Set) : Nat → Set where
  vnil  : Vec A 0
  vcons : ∀ {n} → A → Vec A n → Vec A (suc n)

pattern [] = lnil
pattern [] = vnil

pattern _∷_ x xs = lcons x xs
pattern _∷_ y ys = vcons y ys

lmap : ∀ {A B} → (A → B) → List A → List B
lmap f [] = []
lmap f (x ∷ xs) = f x ∷ lmap f xs

vmap : ∀ {A B n} → (A → B) → Vec A n → Vec B n
vmap f [] = []
vmap f (x ∷ xs) = f x ∷ vmap f xs


module optics where

  open import Function
  open import Data.Nat
  open import Data.Vec
  open import Agda.Builtin.Sigma
  open import Data.Product
  import Relation.Binary.PropositionalEquality as Eq
  open Eq using (_≡_; refl; trans; sym; cong; cong-app; subst)

  record TraversalF (S T A B : Set) : Set where
    field
      extract : Σ[ f ∈ (S -> ℕ) ] ((s : S) -> Vec A (f s) × (Vec B (f s) -> T))

  record Traversal (S T A B : Set) : Set where
    field
      --extract : S -> ∃[ n ] (Vec A n × (Vec B n -> T))
      extract : S -> Σ[ n ∈ ℕ ] Vec A n × (Vec B n -> T)

    get : (s : S) -> Vec A (fst (extract s))
    get = fst ∘ snd ∘ extract

    put : (s : S) -> Vec B (fst (extract s)) -> T
    put = snd ∘ snd ∘ extract

  record TraversalLaws (S A : Set) (t : Traversal S S A A): Set where
    open Traversal t public
    field
      get-put-law : (s : S) -> (put s) (get s) ≡ s
      -- put-get-law : (s : S) -> (v : Vec A (fst (Traversal.extract t s))) ->
      --  (Traversal.get t (Traversal.put t s v)) ≡ {!!}

  record Traversal2 (S A B T : Set) : Set where
    field
      extract : (s : S) -> Σ[ f ∈ (S -> ℕ) ] Vec A (f s) × (Vec B (f s) -> T)


import      Lvl
open import Type

module Data.IndexedList {ℓ ℓᵢ} (T : Type{ℓ}) {I : Type{ℓᵢ}} where

private variable i : I

record Index : Type{ℓᵢ Lvl.⊔ ℓ} where
  constructor intro
  field
    ∅   : I
    _⊰_ : T → I → I

module _ ((intro ∅ᵢ _⊰ᵢ_) : Index) where
  data IndexedList : I → Type{ℓᵢ Lvl.⊔ ℓ} where
    ∅   : IndexedList(∅ᵢ)
    _⊰_ : (x : T) → IndexedList(i) → IndexedList(x ⊰ᵢ i)

  infixr 1000 _⊰_

  private variable ℓₚ : Lvl.Level
  private variable index : Index
  private variable l : IndexedList i

  module _ (P : ∀{i} → IndexedList i → Type{ℓₚ}) where
    elim : P(∅) → (∀{i}(x)(l : IndexedList i) → P(l) → P(x ⊰ l)) → ((l : IndexedList i) → P(l))
    elim base next ∅       = base
    elim base next (x ⊰ l) = next x l (elim base next l)

module LongOper where
  pattern empty = ∅
  pattern prepend elem list = elem ⊰ list
pattern singleton x = x ⊰ ∅


module SemiLattice where

open import Prelude
open import PartialOrder as PO
import Chain

private
 module IsSemiLat
   {A : Set}(po : PartialOrder A)(_⊓_ : A -> A -> A) where
  private open module PO = PartialOrder po

  record IsSemiLattice : Set where
    field
      ⊓-lbL : forall {x y}   -> (x ⊓ y) ≤ x
      ⊓-lbR : forall {x y}   -> (x ⊓ y) ≤ y
      ⊓-glb : forall {x y z} -> z ≤ x -> z ≤ y -> z ≤ (x ⊓ y)

open IsSemiLat public

record SemiLattice (A : Set) : Set1 where
  field
    po  : PartialOrder A
    _⊓_ : A -> A -> A
    prf : IsSemiLattice po _⊓_

module SemiLat {A : Set}(L : SemiLattice A) where

  private module SL   = SemiLattice L
  private module SLPO = POrder SL.po
  private module IsSL = IsSemiLattice SL.po SL._⊓_ SL.prf

  open SLPO public
  open SL   public hiding (prf)
  open IsSL public

  private open module C≤ = Chain _≤_ (\x -> ≤-refl) (\x y z -> ≤-trans)
                      renaming (_===_ to _-≤-_; chain>_ to trans>_)

  ⊓-commute : forall {x y} -> (x ⊓ y) == (y ⊓ x)
  ⊓-commute = ≤-antisym lem lem
    where
      lem : forall {x y} -> (x ⊓ y) ≤ (y ⊓ x)
      lem = ⊓-glb ⊓-lbR ⊓-lbL

  ⊓-assoc : forall {x y z} -> (x ⊓ (y ⊓ z)) == ((x ⊓ y) ⊓ z)
  ⊓-assoc = ≤-antisym lem₁ lem₂
    where
      lem₁ : forall {x y z} -> (x ⊓ (y ⊓ z)) ≤ ((x ⊓ y) ⊓ z)
      lem₁ = ⊓-glb (⊓-glb ⊓-lbL (≤-trans ⊓-lbR ⊓-lbL))
                   (≤-trans ⊓-lbR ⊓-lbR)

      lem₂ : forall {x y z} ->  ((x ⊓ y) ⊓ z) ≤ (x ⊓ (y ⊓ z))
      lem₂ = ⊓-glb (≤-trans ⊓-lbL ⊓-lbL)
                   (⊓-glb (≤-trans ⊓-lbL ⊓-lbR) ⊓-lbR)

  ⊓-idem : forall {x} -> (x ⊓ x) == x
  ⊓-idem = ≤-antisym ⊓-lbL (⊓-glb ≤-refl ≤-refl)

  ≤⊓-L : forall {x y} -> (x ≤ y) ⇐⇒ ((x ⊓ y) == x)
  ≤⊓-L = (fwd , bwd)
    where
      fwd = \x≤y -> ≤-antisym ⊓-lbL (⊓-glb ≤-refl x≤y)
      bwd = \x⊓y=x -> ≤-trans (==≤-R x⊓y=x) ⊓-lbR

  ≤⊓-R : forall {x y} -> (y ≤ x) ⇐⇒ ((x ⊓ y) == y)
  ≤⊓-R {x}{y} = (fwd , bwd)
    where
      lem : (y ≤ x) ⇐⇒ ((y ⊓ x) == y)
      lem = ≤⊓-L

      fwd = \y≤x -> ==-trans ⊓-commute (fst lem y≤x)
      bwd = \x⊓y=y -> snd lem (==-trans ⊓-commute x⊓y=y)

  ⊓-monotone-R : forall {a} -> Monotone (\x -> a ⊓ x)
  ⊓-monotone-R x≤y = ⊓-glb ⊓-lbL (≤-trans ⊓-lbR x≤y)

  ⊓-monotone-L : forall {a} -> Monotone (\x -> x ⊓ a)
  ⊓-monotone-L {a}{x}{y} x≤y =
    trans> x ⊓ a
       -≤- a ⊓ x  by ==≤-L ⊓-commute
       -≤- a ⊓ y  by ⊓-monotone-R x≤y
       -≤- y ⊓ a  by ==≤-L ⊓-commute

  ≤⊓-compat : forall {w x y z} -> w ≤ y -> x ≤ z -> (w ⊓ x) ≤ (y ⊓ z)
  ≤⊓-compat {w}{x}{y}{z} w≤y x≤z =
    trans> w ⊓ x
       -≤- w ⊓ z  by ⊓-monotone-R x≤z
       -≤- y ⊓ z  by ⊓-monotone-L w≤y

  ⊓-cong : forall {w x y z} -> w == y -> x == z -> (w ⊓ x) == (y ⊓ z)
  ⊓-cong wy xz = ≤-antisym (≤⊓-compat (==≤-L wy) (==≤-L xz))
                           (≤⊓-compat (==≤-R wy) (==≤-R xz))

  ⊓-cong-L : forall {x y z} -> x == y -> (x ⊓ z) == (y ⊓ z)
  ⊓-cong-L xy = ⊓-cong xy ==-refl

  ⊓-cong-R : forall {x y z} -> x == y -> (z ⊓ x) == (z ⊓ y)
  ⊓-cong-R xy = ⊓-cong ==-refl xy


-- Andreas, 2016-09-20, issue #2196 reported by mechvel
-- Test case by Ulf

-- {-# OPTIONS -v tc.lhs.dot:40 #-}

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

record _×_ (A B : Set) : Set where
  constructor _,_
  field fst : A
        snd : B
open _×_

EqP₁ : ∀ {A B} (p q : A × B) → Set
EqP₁ (x , y) (z , w) = (x ≡ z) × (y ≡ w)

EqP₂ : ∀ {A B} (p q : A × B) → Set
EqP₂ p q = (fst p ≡ fst q) × (snd p ≡ snd q)

works : {A : Set} (p q : A × A) → EqP₁ p q → Set₁
works (x , y) .(x , y) (refl , refl) = Set

test  : {A : Set} (p q : A × A) → EqP₂ p q → Set₁
test  (x , y) .(x , y) (refl , refl) = Set

-- ERROR WAS:
-- Failed to infer the value of dotted pattern
-- when checking that the pattern .(x , y) has type .A × .A


{-# OPTIONS --no-universe-polymorphism #-}

open import Data.List
open import Data.Product
open import Data.Unit hiding (_≤_)
open import Data.Nat
open import Data.Empty
open import Relation.Nullary
open import Relation.Binary.Core hiding (Total)
import Level as L using (zero)

open import Lists
open import BagEquality
open import Equivalence
open import DivideEtImpera

module Mergesort where

merge : {A : Set} → {_<_ : Rel A L.zero} → Total _<_ → List A → List A → List A
merge _ [] ys = ys
merge _ (x ∷ xs) [] = (x ∷ xs)
merge total (x ∷ xs) (y ∷ ys) with (total x y)
merge total (x ∷ xs) (y ∷ ys) | (inj₁ x≤y) = x ∷ merge total xs (y ∷ ys)
merge total (x ∷ xs) (y ∷ ys) | (inj₂ y≤x) = y ∷ merge total (x ∷ xs) ys

merge-cong : {A : Set} → {_<_ : Rel A L.zero} → (total : Total _<_) → (xs ys : List A) → merge total xs ys ≈ (xs ++ ys)
merge-cong _ [] ys = λ z → z ∈ ys □↔
merge-cong _ (x ∷ xs) [] = λ z → z ∈ (x ∷ xs) ↔⟨ ++-comm [] (x ∷ xs) z ⟩
                                       z ∈ ((x ∷ xs) ++ [])  □↔
merge-cong total (x ∷ xs) (y ∷ ys) with (total x y)
merge-cong total (x ∷ xs) (y ∷ ys) | (inj₁ x≤y) = λ z →
               (z ≡ x) ⊕ z ∈ merge total xs (y ∷ ys)  ↔⟨ ⊕-cong ((z ≡ x) □↔) (merge-cong total xs (y ∷ ys) z) ⟩
               (z ≡ x) ⊕ z ∈ (xs ++ (y ∷ ys)) □↔

merge-cong total (x ∷ xs) (y ∷ ys) | (inj₂ y≤x) = λ z →
               (z ≡ y) ⊕ z ∈ merge total (x ∷ xs) ys  ↔⟨ ⊕-cong ((z ≡ y) □↔) (merge-cong total (x ∷ xs) ys z) ⟩
               (z ≡ y) ⊕ z ∈ ((x ∷ xs) ++ ys)         ↔⟨ ⊕-cong ((z ≡ y) □↔) (++-comm (x ∷ xs) ys z) ⟩
               (z ≡ y) ⊕ z ∈ (ys ++ (x ∷ xs))         ↔⟨ ++-comm (y ∷ ys) (x ∷ xs) z ⟩
               z ∈ ((x ∷ xs) ++ (y ∷ ys)) □↔

SmallerThanHead : {A : Set} → Rel A L.zero → A → List A → Set
SmallerThanHead _ x [] = ⊤
SmallerThanHead _<_ x (y ∷ ys) = _<_ x y

ord : {A : Set} → {_<_ : Rel A L.zero} → {x : A} → {xs : List A} → SmallerThanHead _<_ x xs →  Ordered _<_ xs → Ordered _<_ (x ∷ xs)
ord {xs = []} _ _ = SingleIsOrd
ord {xs = (y ∷ ys)} x≤y ordXs = HeadTailOrd x≤y ordXs

merge-order : {A : Set} → {_<_ : Rel A L.zero} → (total : Total _<_) → (xs ys : List A)
                               → Ordered _<_ xs → Ordered _<_ ys → Ordered _<_ (merge total xs ys)
merge-order _ []        ys _ ysOrd = ysOrd
merge-order _ (x ∷ xs) [] xsOrd _ = xsOrd
merge-order total (x ∷ xs) (y ∷ ys) _ _  with (total x y)
merge-order total (x ∷ xs) (y ∷ ys) _ _     | (inj₁ x≤y) with xs
merge-order total (x ∷ xs) (y ∷ ys) _ ysOrd | (inj₁ x≤y) | [] = HeadTailOrd x≤y ysOrd
merge-order {_<_ = _<_} total (x ∷ xs) (y ∷ ys) (HeadTailOrd x≤x₂ xsOrd)  ysOrd | (inj₁ x≤y) | (x₂ ∷ xs₂)
                      = ord x≤z (merge-order total (x₂ ∷ xs₂) (y ∷ ys) xsOrd ysOrd) where
                             x≤z : SmallerThanHead _<_ x (merge total (x₂ ∷ xs₂) (y ∷ ys))
                             x≤z with (total x₂ y)
                             x≤z | (inj₁ _) = x≤x₂
                             x≤z | (inj₂ _) = x≤y
merge-order total (x ∷ xs) (y ∷ ys) _ _     | (inj₂ y≤x) with ys
merge-order total (x ∷ xs) (y ∷ ys) xsOrd _ | (inj₂ y≤x) | [] = HeadTailOrd y≤x xsOrd
merge-order {_<_ = _<_} total (x ∷ xs) (y ∷ ys) xsOrd (HeadTailOrd y≤y₂ ysOrd) | (inj₂ y≤x) | (y₂ ∷ ys₂)
                      = ord y≤z (merge-order total (x ∷ xs) (y₂ ∷ ys₂) xsOrd ysOrd) where
                               y≤z : SmallerThanHead _<_ y (merge total (x ∷ xs) (y₂ ∷ ys₂))
                               y≤z with (total x y₂)
                               y≤z | (inj₁ _) = y≤x
                               y≤z | (inj₂ _) = y≤y₂

minus : ℕ → ℕ → ℕ
minus n zero          = n
minus zero (suc m)    = zero
minus (suc n) (suc m) = minus n m

minus-suc : {n m : ℕ} → m ≤ n → minus (suc n) m ≡ suc (minus n m)
minus-suc z≤n      = refl
minus-suc (s≤s pf) = minus-suc pf

bisect : {A : Set} → List A → (List A × List A)
bisect xs = splitAt ⌊ length xs /2⌋ xs

splitAtLen1 : {A : Set} →  (n : ℕ) → (xs : List A) → n ≤ (length xs) → length (proj₁ (splitAt n xs)) ≡ n
splitAtLen1 zero xs _ = refl
splitAtLen1 (suc n) [] ()
splitAtLen1 (suc n) (x ∷ xs) (s≤s pf) = suc (length (proj₁ (splitAt n xs))) =⟨ splitAtLen1 n xs pf under suc ⟩
                                        suc n □=

splitAtLen2 : {A : Set} →  (n : ℕ) → (xs : List A) → length (proj₂ (splitAt n xs)) ≡ minus (length xs) n
splitAtLen2 zero xs = refl
splitAtLen2 (suc n) [] = refl
splitAtLen2 (suc n) (x ∷ xs) = length (proj₂ (splitAt n xs)) =⟨ splitAtLen2 n xs ⟩
                                minus (length xs) n □=

s≤′s : {n m : ℕ} → n ≤′ m → suc n ≤′ suc m
s≤′s ≤′-refl      = ≤′-refl
s≤′s (≤′-step pf) = ≤′-step (s≤′s pf)

lte-cong : {n m : ℕ} → (n ≤ m) ⇔ (n ≤′ m)
lte-cong = record { to   = to' ;
                    from = from' } where
                            to' : {n m : ℕ} → n ≤ m → n ≤′ m
                            to' {m = zero}  z≤n = ≤′-refl
                            to' {m = suc m} z≤n = ≤′-step (to' z≤n)
                            to' (s≤s pf) = s≤′s (to' pf)
                            from' : {n m : ℕ} → n ≤′ m → n ≤ m
                            from' {zero} ≤′-refl = z≤n
                            from' {suc n} ≤′-refl = s≤s (from' ≤′-refl)
                            from' (≤′-step pf) = ≤-step (from' pf) where
                                   ≤-step : {n m : ℕ} → n ≤ m → n ≤ (suc m)
                                   ≤-step z≤n = z≤n
                                   ≤-step (s≤s pf) = s≤s (≤-step pf)

eq-rel-cong : {A : Set} → {rel : Rel A L.zero} →  {x y z : A} → x ≡ y → rel y z → rel x z
eq-rel-cong refl pf = pf

halfLte1 : (n : ℕ) → ⌊ n /2⌋ ≤′ n
halfLte1 zero          = ≤′-refl
halfLte1 (suc zero)    = ≤′-step ≤′-refl
halfLte1 (suc (suc n)) = ≤′-step (s≤′s (halfLte1 n))

halfLt1 : (n : ℕ) → ⌊ (suc (suc n)) /2⌋ <′ (suc (suc n))
halfLt1 n = s≤′s (s≤′s (halfLte1 n))

halfLte2 : (n : ℕ) → (minus n ⌊ n /2⌋) ≤′ n
halfLte2 zero          = ≤′-refl
halfLte2 (suc zero)    = ≤′-refl
halfLte2 (suc (suc n)) = ≤′-step (eq-rel-cong {rel = _≤′_} {x = minus (suc n) ⌊ n /2⌋} {y = suc (minus n ⌊ n /2⌋)}
                          (minus-suc (_⇔_.from lte-cong (halfLte1 n))) (s≤′s (halfLte2 n)))

halfLt2 : (n : ℕ) → (minus (suc (suc n)) ⌊ (suc (suc n)) /2⌋) <′ (suc (suc n))
halfLt2 n = s≤′s (eq-rel-cong {rel = _≤′_} {x = minus (suc n) ⌊ n /2⌋} {y = suc (minus n ⌊ n /2⌋)}
                          (minus-suc (_⇔_.from lte-cong (halfLte1 n))) (s≤′s (halfLte2 n)))

bisectPf1 : {A : Set} → (x y : A) → (zs : List A) → proj₁ (bisect (x ∷ y ∷ zs)) <l (x ∷ y ∷ zs)
bisectPf1 x y zs = eq-rel-cong {rel = _<′_}
        (splitAtLen1 ⌊ (suc (suc (length zs))) /2⌋ (x ∷ y ∷ zs) (_⇔_.from lte-cong (halfLte1 (suc (suc (length zs))))))
                   (halfLt1 (length zs))

bisectPf2 : {A : Set} → (x y : A) → (zs : List A) → proj₂ (bisect (x ∷ y ∷ zs)) <l (x ∷ y ∷ zs)
bisectPf2 x y zs = eq-rel-cong {rel = _<′_}
        (splitAtLen2 ⌊ (suc (suc (length zs))) /2⌋ (x ∷ y ∷ zs))
                   (halfLt2 (length zs))

splitAt-cong : {A : Set} → (n : ℕ) → (xs : List A) → proj₁ (splitAt n xs) ++ proj₂ (splitAt n xs) ≈ xs
splitAt-cong zero xs           z = z ∈ xs □↔
splitAt-cong (suc n) []        z = ⊥ □↔
splitAt-cong (suc n) (x ∷ xs) z = (z ≡ x) ⊕ z ∈ (proj₁ (splitAt n xs) ++ proj₂ (splitAt n xs))
                                             ↔⟨ ⊕-cong ((z ≡ x) □↔) (splitAt-cong n xs z) ⟩
                                   (z ≡ x) ⊕ z ∈ xs □↔

ms-inputCond : {A : Set} → List A → Set
ms-inputCond _ = ⊤

ms-decompCond : {A : Set} → List A → (⊤ × List A × List A) → Set
ms-decompCond xs (_ , ys , zs ) = ys ++ zs ≈ xs

ms-compCond : {A : Set} → Rel A L.zero → (⊤ × List A × List A) → List A → Set
ms-compCond rel (_ , xs , ys ) zs = zs ≈ xs ++ ys × (Ordered rel xs → Ordered rel ys → Ordered rel zs)

ms-outputCond : {A : Set} → Rel A L.zero → List A → List A → Set
ms-outputCond rel xs zs = (zs ≈ xs) × Ordered rel zs

ms-G : ⊤ → ⊤ → Σ ⊤ (λ x → ⊤)
ms-G _ _ = (⊤.tt , ⊤.tt)

ms-decomp : {A : Set} → (xs : List A) → ⊤ → ¬ ListPrimitive2 xs → Σ (⊤ × List A × List A)
              (λ z → ⊤ × ⊤ × ⊤ × (proj₁ (proj₂ z) <l xs) × (proj₂ (proj₂ z) <l xs) × ms-decompCond xs z)
ms-decomp [] _ notPrim = ⊥-elim (notPrim NilIsPrim2)
ms-decomp (x ∷ []) _ notPrim = ⊥-elim (notPrim SingleIsPrim2)
ms-decomp (x ∷ y ∷ zs)  _ _ = (⊤.tt , bisect (x ∷ y ∷ zs)) , (⊤.tt , ⊤.tt , ⊤.tt ,
                                                        bisectPf1 x y zs ,
                                                        bisectPf2 x y zs ,
                                                        splitAt-cong ⌊ (suc (suc (length zs))) /2⌋ (x ∷ y ∷ zs))

ms-comp : {A : Set} → {rel : Rel A L.zero} → Total rel → (z : (⊤ × List A × List A)) → Σ (List A) (ms-compCond rel z)
ms-comp total ( _ , xs , ys) = (merge total xs ys) , (merge-cong total xs ys , merge-order total xs ys)

ms-dirSolve : {A : Set} → (rel : Rel A L.zero) → (xs : List A) → ⊤ → ListPrimitive2 xs → Σ (List A) (ms-outputCond rel xs)
ms-dirSolve _ []             _ _    = [] , ((λ z → ⊥ □↔) , NilIsOrd)
ms-dirSolve _ (x ∷ [])      _ _    = (x ∷ []) , ((λ z → z ∈ (x ∷ []) □↔) , SingleIsOrd)
ms-dirSolve _ (x ∷ y ∷ zs) _ prim = ⊥-elim (consConsIsNotPrim2 prim)

ms-lemma : {A : Set} → (rel : Rel A L.zero) → ∀{xs ys₁ ys₂ zs₁ zs₂ ws} → ms-decompCond xs (⊤.tt , ys₁ , ys₂)
                           → ⊤ → ms-outputCond rel ys₁ zs₁ → ms-outputCond rel ys₂ zs₂
                              → ms-compCond rel (⊤.tt , zs₁ , zs₂) ws → ms-outputCond rel xs ws
ms-lemma rel {xs} {ys₁} {ys₂} {zs₁} {zs₂} {ws} ys₁++ys₂≈xs _ ( ys₁≈zs₁ , zs₁Ord ) ( ys₂≈zs₂ , zs₂Ord ) ( ws≈zs₁++zs₂ , compOrd)
                 = (λ z → z ∈ ws              ↔⟨ ws≈zs₁++zs₂ z ⟩
                           z ∈ (zs₁ ++ zs₂)    ↔⟨ Any-++ (z ≡_) zs₁ zs₂ ⟩
                           z ∈ zs₁ ⊕ z ∈ zs₂ ↔⟨ ⊕-cong (ys₁≈zs₁ z) (ys₂≈zs₂ z) ⟩
                           z ∈ ys₁ ⊕ z ∈ ys₂ ↔⟨ ↔sym (Any-++ (z ≡_) ys₁ ys₂) ⟩
                           z ∈ (ys₁ ++ ys₂)    ↔⟨ ys₁++ys₂≈xs z ⟩
                           z ∈ xs □↔) ,
                   compOrd zs₁Ord zs₂Ord

mergesort : {A : Set} → {rel : Rel A L.zero} → Total rel → (xs : List A) → Σ (List A) (λ zs → (zs ≈ xs) × Ordered rel zs)
mergesort {rel = rel} total xs = makeD&C2 <l-wellFounded
                                          prim2Dec
                                          ms-decomp
                                          (ms-comp total)
                                          ms-G
                                          (ms-dirSolve rel)
                                          (ms-lemma rel)
                                          xs ⊤.tt


module STLC.Term.Reduction where

open import STLC.Term as Term
open Term.Substitution using () renaming (_[/_] to _[/t_])

open import Data.Nat using (ℕ; _+_)

open import Relation.Binary.Construct.Closure.ReflexiveTransitive
  using (Star)

infix 4 _—→_

data _—→_ { n : ℕ } : Term n -> Term n -> Set where

  β-·₁ : ∀ { t₁ t₂ l : Term n }
    -> t₁ —→ t₂
    -- ----------------
    -> t₁ · l —→ t₂ · l

  β-·₂ : ∀ { v t₁ t₂ : Term n }
    -> Value v
    -> t₁ —→ t₂
    -- ----------------
    -> v · t₁ —→ v · t₂

  β-ƛ : ∀ { t : Term (1 + n) } {v : Term n }
    -> Value v
    -- --------------------
    -> (ƛ t) · v —→ (t [/t v ])

infix 2 _—↠_

_—↠_ : { n : ℕ } -> Term n -> Term n -> Set
_—↠_ = Star (_—→_)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Reflexive closures
------------------------------------------------------------------------

module Data.ReflexiveClosure where

open import Data.Unit
open import Level
open import Relation.Binary
open import Relation.Binary.Simple

------------------------------------------------------------------------
-- Reflexive closure

data Refl {a ℓ} {A : Set a} (_∼_ : Rel A ℓ) : Rel A (a ⊔ ℓ) where
  [_]  : ∀ {x y} (x∼y : x ∼ y) → Refl _∼_ x y
  refl : Reflexive (Refl _∼_)

-- Map.

map : ∀ {a a′ ℓ ℓ′} {A : Set a} {A′ : Set a′}
        {_R_ : Rel A ℓ} {_R′_ : Rel A′ ℓ′} {f : A → A′} →
      _R_ =[ f ]⇒ _R′_ → Refl _R_ =[ f ]⇒ Refl _R′_
map R⇒R′ [ xRy ] = [ R⇒R′ xRy ]
map R⇒R′ refl    = refl

-- The reflexive closure has no effect on reflexive relations.

drop-refl : ∀ {a ℓ} {A : Set a} {_R_ : Rel A ℓ} →
            Reflexive _R_ → Refl _R_ ⇒ _R_
drop-refl rfl [ x∼y ] = x∼y
drop-refl rfl refl    = rfl

------------------------------------------------------------------------
-- Example: Maybe

module Maybe where

  Maybe : ∀ {ℓ} → Set ℓ → Set ℓ
  Maybe A = Refl (Const A) tt tt

  nothing : ∀ {a} {A : Set a} → Maybe A
  nothing = refl

  just : ∀ {a} {A : Set a} → A → Maybe A
  just = [_]


-- Exponentials and closed categories
module CategoryTheory.BCCCs.Closed where
open import CategoryTheory.Categories
open import CategoryTheory.BCCCs.Cartesian

module _ {n} {ℂ : Category n} (Cℂ : Cartesian ℂ) where

    open Category ℂ
    open Cartesian Cℂ

    -- Exponential from two objects
    record Exponential (A B : obj) : Set (lsuc n) where
        field
            -- | Data
            -- Exponential object
            A⇒B : obj
            -- Evaluation map
            eval : A⇒B ⊗ A ~> B
            -- Canonical transposition morphism (currying)
            Λ : ∀{E} -> (E ⊗ A ~> B) -> (E ~> A⇒B)

            -- | Laws
            Λ-comm : ∀{E} -> {e : E ⊗ A ~> B}
                  -> eval ∘ (Λ e * id) ≈ e
            Λ-unique : ∀{E} -> {e : E ⊗ A ~> B} {m : E ~> A⇒B}
                  -> eval ∘ (m * id) ≈ e -> Λ e ≈ m
            Λ-cong : ∀{E} {f g : E ⊗ A ~> B}
                  -> f ≈ g -> Λ f ≈ Λ g

        -- Currying identity
        Λ-*id : ∀{D E} {f : E ⊗ A ~> B} {g : D ~> E}
             -> Λ (f ∘ (g * id)) ≈ Λ f ∘ g
        Λ-*id {D}{E}{f}{g} =
            begin
                Λ (f ∘ (g * id))
            ≈⟨ Λ-cong (≈-cong-left (Λ-comm [sym]) ≈> ∘-assoc) ⟩
                Λ (eval ∘ (Λ f * id) ∘ (g * id))
            ≈⟨ Λ-cong (≈-cong-right (*-idemp-dist-∘ id-left)) ⟩
                Λ (eval ∘ (Λ f ∘ g) * id)
            ≈⟨ Λ-unique r≈ ⟩
                Λ f ∘ g
            ∎

-- Type class for closed categories
-- definition using exponentials
record Closed {n} {ℂ : Category n} (Cℂ : Cartesian ℂ) : Set (lsuc n) where
    open Category ℂ
    field
        -- Exponential object for each pair of objects
        exp : ∀(A B : obj) -> Exponential Cℂ A B

    open module E {A} {B} = Exponential (exp A B) public

    -- Shorthand for exponential object
    infixr 20 _⇒_
    _⇒_ : (A B : obj) -> obj
    A ⇒ B = A⇒B {A} {B}


{-# OPTIONS --copatterns #-}

module Control.Category.Slice where

open import Level using (suc; _⊔_)
open import Relation.Binary hiding (_⇒_)

open import Control.Category
open Category using () renaming (Obj to obj)

-- Given a category C and an object Tgt in C we can define a new category
-- whose objects S are pairs of an object Src in C
-- and a morphism out from Src to Tgt.

record SliceObj {o h e} (C : Category o h e) (Tgt : obj C) : Set (o ⊔ h ⊔ e) where
  constructor sliceObj
  open Category C -- public
  field
    Src : Obj
    out : Src ⇒ Tgt

-- In the following, we fix a category C and an object Tgt.

module _ {o h e} {C : Category o h e} {Tgt : obj C} where

  -- We use _⇒_ for C's morphisms and _∘_ for their composition.
  private
    open module C = Category C hiding (id; ops)

    Slice = SliceObj C Tgt
    open module Slice = SliceObj {C = C} {Tgt = Tgt}

  -- A morphism in the slice category into Tgt
  -- from slice (S, s) to (T, t)
  -- is a morphism f : S ⇒ T such that t ∘ f ≡ s.

  record SliceMorphism (S T : Slice) : Set (h ⊔ e)
    where
    constructor sliceMorphism
    field
      mor      : Src S ⇒ Src T
      triangle : (mor ⟫ out T) ≈ out S

  -- Two morphisms in the slice category are equal
  -- iff they are equal in the underlying category C.

  SliceHom : (S T : Slice) → Setoid _ _
  SliceHom S T = record
    { Carrier       = SliceMorphism S T
    ; _≈_           = λ f g → SliceMorphism.mor f ≈ SliceMorphism.mor g
    ; isEquivalence = record
      { refl  = refl
      ; sym   = sym
      ; trans = trans
      }
    } where open IsEquivalence (≈-equiv {Src S} {Src T})

  -- We write S ⇉ T for a morphism from slice S to slice T

  open HomSet SliceHom using () renaming (_⇒_ to _⇉_; _≈_ to _≐_)

  -- The identity slice morphism is just the identity morphism.

  slice-id : ∀ {P} → P ⇉ P
  slice-id = record { mor = C.id; triangle = C.id-first }

  -- The composition of slice morphims is just the composition in C.

  comp : ∀ {S T U} → S ⇉ T → T ⇉ U → S ⇉ U
  comp (sliceMorphism f tri-f) (sliceMorphism g tri-g) = record
    { mor      = f ⟫ g
    ; triangle = ≈-trans (C.∘-assoc f) (≈-trans (C.∘-cong ≈-refl tri-g) tri-f)
    }

  ops : CategoryOps SliceHom
  ops = record { id = slice-id ; _⟫_ = comp}

  sliceIsCategory : IsCategory SliceHom
  sliceIsCategory = record
    { ops = ops
    ; laws = record
      { id-first = C.id-first -- id-first
      ; id-last  = C.id-last
      ; ∘-assoc  = λ f → C.∘-assoc _
      ; ∘-cong   = C.∘-cong
      }
    }

-- The slice category.

module _  {o h e} (C : Category o h e) (Tgt : obj C) where

  module C = Category C

  _/_ : Category (o ⊔ h ⊔ e) (e ⊔ h) e
  _/_ = record
    { Obj = SliceObj C Tgt
    ; Hom = SliceHom
    ; isCategory = sliceIsCategory
    }

  open Category _/_

-- The terminal object in C / Tgt is (Tgt, id).

  terminalSlice : Obj
  terminalSlice = record { Src = Tgt; out = C.id }

  open IsFinal

  isTerminalSlice : IsFinal Hom terminalSlice
  final           isTerminalSlice {sliceObj Src f}
    = sliceMorphism f C.id-last
  final-universal isTerminalSlice {sliceObj Src f} {sliceMorphism g tri}
    = C.≈-trans (C.≈-sym C.id-last) tri

-- The initial object in C / Tgt is (0, initial)

  module _ {⊥ : obj C} (⊥-initial : IsInitial C.Hom ⊥) where

    open IsInitial ⊥-initial
      renaming (initial to abort; initial-universal to abort-unique)

    initialSlice : Obj
    initialSlice = record { Src = ⊥; out = abort }

    open IsInitial

    isInitialSlice : IsInitial Hom initialSlice
    initial           isInitialSlice = sliceMorphism abort abort-unique
    initial-universal isInitialSlice = abort-unique


import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl; sym; trans; cong)
open Eq.≡-Reasoning
open import Function using (_∘_)
open import Data.Product using (_×_) using (_,_; proj₁; proj₂)
open import Data.Sum using (_⊎_; inj₁; inj₂)
open import Data.Unit using (⊤; tt)
open import Data.Empty using (⊥; ⊥-elim)

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

β-×₁ : ∀ {A B : Set} (x : A) (y : B) → proj₁ (x , y) ≡ x
β-×₁ x y = refl

β-×₂ : ∀ {A B : Set} (x : A) (y : B) → proj₂ (x , y) ≡ y
β-×₂ x y = refl

η-× : ∀ {A B : Set} (w : A × B) → (proj₁ w , proj₂ w) ≡ w
η-× (x , y) = refl

uniq-× : ∀ {A B C : Set} (h : C → A × B) (v : C) → (proj₁ (h v) , proj₂ (h v)) ≡ h v
uniq-× h v = η-× (h v)

⊎-elim : ∀ {A B C : Set} → (A → C) → (B → C) → (A ⊎ B → C)
⊎-elim f g (inj₁ x) = f x
⊎-elim f g (inj₂ y) = g y

β-⊎₁ : ∀ {A B C : Set} (f : A → C) (g : B → C) (x : A) → ⊎-elim f g (inj₁ x) ≡ f x
β-⊎₁ f g x = refl

β-⊎₂ : ∀ {A B C : Set} (f : A → C) (g : B → C) (y : B) → ⊎-elim f g (inj₂ y) ≡ g y
β-⊎₂ f g x = refl

η-⊎ : ∀ {A B : Set} (w : A ⊎ B) → ⊎-elim inj₁ inj₂ w ≡ w
η-⊎ (inj₁ x) = refl
η-⊎ (inj₂ y) = refl

natural-⊎ : ∀ {A B C D : Set} (f : A → C) (g : B → C) (h : C → D) (w : A ⊎ B) → ⊎-elim (h ∘ f) (h ∘ g) w ≡ (h ∘ ⊎-elim f g) w
natural-⊎ f g h (inj₁ x) = refl
natural-⊎ f g h (inj₂ y) = refl

uniq-⊎ : ∀ {A B C  : Set} (h : A ⊎ B → C) (w : A ⊎ B) → ⊎-elim (h ∘ inj₁) (h ∘ inj₂) w ≡ h w
uniq-⊎ h w rewrite natural-⊎ inj₁ inj₂ h w | η-⊎ w = refl

η-⊤ : ∀ (w : ⊤) → tt ≡ w
η-⊤ tt = refl

uniq-⊤ : ∀ {C : Set} (h : C → ⊤) (v : C) → tt ≡ h v
uniq-⊤ h v = η-⊤ (h v)

η-⊥ : ∀ (w : ⊥) → ⊥-elim w ≡ w
η-⊥ ()

natural-⊥ : ∀ {C D : Set} (h : C → D) (w : ⊥) → ⊥-elim w ≡ (h ∘ ⊥-elim) w
natural-⊥ h ()

uniq-⊥ : ∀ {C : Set} (h : ⊥ → C) (w : ⊥) → ⊥-elim w ≡ h w
uniq-⊥ h w rewrite natural-⊥ h w | η-⊥ w = refl

η-→ : ∀ {A B : Set} (f : A → B) → (λ{x → f x}) ≡ f
η-→ {A} {B} f = extensionality η-helper
  where
  η-lhs : A → B
  η-lhs = λ{x → f x}

  η-helper : (x : A) → η-lhs x ≡ f x
  η-helper x = refl


-- Andreas, 2015-05-01
-- With clauses for functions with flexible arity.

-- {-# OPTIONS -v tc.with:40 #-}

open import Common.Prelude
open import Common.Equality

mutual
  even : Nat → Bool
  even 0       = true
  even (suc n) = odd n

  odd  : Nat → Bool
  odd 0 = false
  odd (suc n) = even n

NPred : Nat → Set
NPred 0       = Bool
NPred (suc n) = Nat → NPred n

const : Bool → ∀{n} → NPred n
const b {0}       = b
const b {suc n} m = const b {n}

allOdd : ∀ n → NPred n
allOdd 0 = true
allOdd (suc n) m with even m
... | true  = const false
... | false = allOdd n

test : allOdd 4 1 3 5 7 ≡ true
test = refl


------------------------------------------------------------------------
-- agda-combinatorics
-- All modules
------------------------------------------------------------------------

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

module AgdaCombinatoricsEverything where

import Math.BinomialTheorem.Generic

-- Proof of the binomial theorem
import Math.BinomialTheorem.Nat

-- Definitions of combinatorial functions
import Math.Combinatorics.Function

-- Properties of combinatorial functions
import Math.Combinatorics.Function.Properties

-- Definitions of combinatorial functions on integer
import Math.Combinatorics.IntegerFunction

-- Properties of combinatorial functions on integer
import Math.Combinatorics.IntegerFunction.Properties

import Math.Combinatorics.ListFunction

import Math.Combinatorics.ListFunction.Properties

import Math.Combinatorics.VecFunction


------------------------------------------------------------------------------
-- Arithmetic properties (using induction on the FOTC natural numbers type)
------------------------------------------------------------------------------

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

-- Usually our proofs use pattern matching instead of the induction
-- principle associated with the FOTC natural numbers. The following
-- examples show some proofs using it.

module FOTC.Data.Nat.PropertiesByInductionATP where

open import FOTC.Base
open import FOTC.Data.Nat

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

+-leftIdentity : ∀ n → zero + n ≡ n
+-leftIdentity n = +-0x n

-- See Issue https://github.com/asr/apia/issues/81 .
+-rightIdentityA : D → Set
+-rightIdentityA i = i + zero ≡ i
{-# ATP definition +-rightIdentityA #-}

+-rightIdentity : ∀ {n} → N n → n + zero ≡ n
+-rightIdentity Nn = N-ind +-rightIdentityA A0 is Nn
  where
  postulate A0 : +-rightIdentityA zero
  {-# ATP prove A0 #-}

  postulate is : ∀ {i} → +-rightIdentityA i → +-rightIdentityA (succ₁ i)
  {-# ATP prove is #-}

-- See Issue https://github.com/asr/apia/issues/81 .
+-NA : D → D → Set
+-NA n i = N (i + n)
{-# ATP definition +-NA #-}

+-N : ∀ {m n} → N m → N n → N (m + n)
+-N {n = n} Nm Nn = N-ind (+-NA n) A0 is Nm
  where
  postulate A0 : +-NA n zero
  {-# ATP prove A0 #-}

  postulate is : ∀ {i} → +-NA n i → +-NA n (succ₁ i)
  {-# ATP prove is #-}

-- See Issue https://github.com/asr/apia/issues/81 .
+-assocA : D → D → D → Set
+-assocA n o i = i + n + o ≡ i + (n + o)
{-# ATP definition +-assocA #-}

+-assoc : ∀ {m} → N m → ∀ n o → m + n + o ≡ m + (n + o)
+-assoc Nm n o = N-ind (+-assocA n o) A0 is Nm
  where
  postulate A0 : +-assocA n o zero
  {-# ATP prove A0 #-}

  postulate is : ∀ {i} → +-assocA n o i → +-assocA n o (succ₁ i)
  {-# ATP prove is #-}

-- A proof without use ATPs definitions.
+-assoc' : ∀ {m} → N m → ∀ n o → m + n + o ≡ m + (n + o)
+-assoc' Nm n o = N-ind A A0 is Nm
  where
  A : D → Set
  A i = i + n + o ≡ i + (n + o)

  postulate A0 : zero + n + o ≡ zero + (n + o)
  {-# ATP prove A0 #-}

  postulate is : ∀ {i} →
                 i + n + o ≡ i + (n + o) →
                 succ₁ i + n + o ≡ succ₁ i + (n + o)
  {-# ATP prove is #-}

-- See Issue https://github.com/asr/apia/issues/81 .
x+Sy≡S[x+y]A : D → D → Set
x+Sy≡S[x+y]A n i = i + succ₁ n ≡ succ₁ (i + n)
{-# ATP definition x+Sy≡S[x+y]A #-}

x+Sy≡S[x+y] : ∀ {m} → N m → ∀ n → m + succ₁ n ≡ succ₁ (m + n)
x+Sy≡S[x+y] Nm n = N-ind (x+Sy≡S[x+y]A n) A0 is Nm
  where
  postulate A0 : x+Sy≡S[x+y]A n zero
  {-# ATP prove A0 #-}

  postulate is : ∀ {i} → x+Sy≡S[x+y]A n i → x+Sy≡S[x+y]A n (succ₁ i)
  {-# ATP prove is #-}

-- See Issue https://github.com/asr/apia/issues/81 .
+-commA : D → D → Set
+-commA n i = i + n ≡ n + i
{-# ATP definition +-commA #-}

+-comm : ∀ {m n} → N m → N n → m + n ≡ n + m
+-comm {n = n} Nm Nn = N-ind (+-commA n) A0 is Nm
  where
  postulate A0 : +-commA n zero
  {-# ATP prove A0 +-rightIdentity #-}

  postulate is : ∀ {i} → +-commA n i → +-commA n (succ₁ i)
  {-# ATP prove is x+Sy≡S[x+y] #-}


module Basics where

data Zero : Set where
record One : Set where constructor <>
data Two : Set where tt ff : Two

data Nat : Set where
  ze : Nat
  su : Nat -> Nat

data _+_ (S T : Set) : Set where
  inl : S -> S + T
  inr : T -> S + T

record Sg (S : Set)(T : S -> Set) : Set where
  constructor _,_
  field
    fst : S
    snd : T fst
open Sg public
_*_ : Set -> Set -> Set
S * T = Sg S \ _ -> T
infixr 4 _,_ _*_

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


{-# OPTIONS --cubical #-}

module Multidimensional.Data.NNat.Base where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Unit
open import Cubical.Data.Nat
open import Cubical.Data.Prod
open import Cubical.Data.Bool

open import Cubical.Relation.Nullary

open import Multidimensional.Data.Extra.Nat
open import Multidimensional.Data.Dir
open import Multidimensional.Data.DirNum

data N (r : ℕ) : Type₀ where
  bn : DirNum r → N r
  xr : DirNum r → N r → N r

-- should define induction principle for N r

-- we have 2ⁿ "unary" constructors, analogous to BNat with 2¹ (b0 and b1)
-- rename n to r
-- this likely introduces inefficiencies compared
-- to BinNat, with the max? check etc.
sucN : ∀ {n} → N n → N n
sucN {zero} (bn tt) = xr tt (bn tt)
sucN {zero} (xr tt x) = xr tt (sucN x)
sucN {suc n} (bn (↓ , ds)) = (bn (↑ , ds))
sucN {suc n} (bn (↑ , ds)) with max? ds
... | no _ = (bn (↓ , next ds))
... | yes _ = xr (zero-n (suc n)) (bn (one-n (suc n)))
sucN {suc n} (xr d x) with max? d
... | no _ = xr (next d) x
... | yes _ = xr (zero-n (suc n)) (sucN x)

sucnN : {r : ℕ} → (n : ℕ) → (N r → N r)
sucnN n = iter n sucN

doubleN : (r : ℕ) → N r → N r
doubleN zero (bn tt) = bn tt
doubleN zero (xr d x) = sucN (sucN (doubleN zero x))
doubleN (suc r) (bn x) with zero-n? x
... | yes _    = bn x
            -- bad:
... | no _ = caseBool (bn (doubleDirNum (suc r) x)) (xr (zero-n (suc r)) (bn x)) (doubleable-n? x)
-- ... | no _  | doubleable  = {!bn (doubleDirNum x)!}
-- ... | no _  | notdoubleable = xr (zero-n (suc r)) (bn x)
doubleN (suc r) (xr x x₁) = sucN (sucN (doubleN (suc r) x₁))

doublesN : (r : ℕ) → ℕ → N r → N r
doublesN r zero m = m
doublesN r (suc n) m = doublesN r n (doubleN r m)

N→ℕ : (r : ℕ) (x : N r) → ℕ
N→ℕ zero (bn tt) = zero
N→ℕ zero (xr tt x) = suc (N→ℕ zero x)
N→ℕ (suc r) (bn x) = DirNum→ℕ x
N→ℕ (suc r) (xr d x) = sucn (DirNum→ℕ d) (doublesℕ (suc r) (N→ℕ (suc r) x))

ℕ→N : (r : ℕ) → (n : ℕ) → N r
ℕ→N r zero = bn (zero-n r)
ℕ→N zero (suc n) = xr tt (ℕ→N zero n)
ℕ→N (suc r) (suc n) = sucN (ℕ→N (suc r) n)


-- Testcase for #2028 by Ulf

record ⊤ : Set where
  constructor tt

data Either (A B : Set) : Set where
  inl : A → Either A B
  inr : B → Either A B

Subset : Set → Set₁
Subset X = X → Set

U : ∀ {X} → Subset X
U _ = {!⊤!}

_⊆_ : ∀ {X} → Subset X → Subset X → Set
A ⊆ B = ∀ {x} → A x → B x

_∪_ : ∀ {X} → Subset X → Subset X → Subset X
(A ∪ B) x = Either (A x) (B x)

∪-bound : ∀ {X} {A : Subset X} → (A ∪ U) ⊆ U
∪-bound {X} {A} = aux
  where
    aux : _ → _
    aux (inl _) = tt
    aux (inr tt) = tt


{-# OPTIONS --show-implicit #-}
open import Agda.Builtin.Nat renaming (Nat to ℕ)
open import Agda.Builtin.Equality

postulate
  funext : {X : Set} {Y : X → Set} {f g : (x : X) → Y x} → (∀ x → f x ≡ g x) → f ≡ g

_::_ : {X : ℕ → Set} → X 0 → ((n : ℕ) → X (suc n)) → ((n : ℕ) → X n)
(x :: α) 0 = x
(x :: α) (suc n) = α n

hd : {X : ℕ → Set} → ((n : ℕ) → X n) → X 0
hd α = α 0

tl : {X : ℕ → Set} → ((n : ℕ) → X n) → ((n : ℕ) → X (suc n))
tl α n = α(suc n)

-- Needed to add the implicit arguments for funext in Agda 2.5.2:

hd-tl-eta : (X : ℕ → Set) {α : (n : ℕ) → X n} → (hd α :: tl α) ≡ α
hd-tl-eta X {α} = funext {Y = _} lemma
 where
  lemma : ∀ {α} → ∀ i → _::_ {_} (hd α) (tl α) i ≡ α i
  lemma 0 = refl
  lemma (suc i) = refl


{-# OPTIONS --safe #-}
module Cubical.Algebra.MonoidSolver.Solver where

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

open import Cubical.Data.FinData using (Fin)
open import Cubical.Data.Nat using (ℕ)
open import Cubical.Data.List
open import Cubical.Data.Vec using (Vec; lookup)

open import Cubical.Algebra.Monoid

open import Cubical.Algebra.MonoidSolver.MonoidExpression

private
  variable
    ℓ : Level

module Eval (M : Monoid ℓ) where
  open MonoidStr (snd M)

  Env : ℕ → Type ℓ
  Env n = Vec ⟨ M ⟩ n

  -- evaluation of an expression (without normalization)
  ⟦_⟧ : ∀{n} → Expr ⟨ M ⟩ n → Env n → ⟨ M ⟩
  ⟦ ε⊗ ⟧ v      = ε
  ⟦ ∣ i ⟧ v     = lookup i v
  ⟦ e₁ ⊗ e₂ ⟧ v = ⟦ e₁ ⟧ v · ⟦ e₂ ⟧ v

  NormalForm : ℕ → Type _
  NormalForm n = List (Fin n)

  -- normalization of an expression
  normalize : ∀{n} → Expr ⟨ M ⟩ n → NormalForm n
  normalize (∣ i)     = i ∷ []
  normalize ε⊗        = []
  normalize (e₁ ⊗ e₂) = (normalize e₁) ++ (normalize e₂)

  -- evaluation of normalform
  eval : ∀ {n} → NormalForm n → Env n → ⟨ M ⟩
  eval [] v       = ε
  eval (x ∷ xs) v = (lookup x v) · (eval xs v)

  -- some calculation
  evalIsHom : ∀ {n} (x y : NormalForm n) (v : Env n)
            → eval (x ++ y) v ≡ eval x v · eval y v
  evalIsHom [] y v       = sym (·IdL _)
  evalIsHom (x ∷ xs) y v =
    cong (λ m → (lookup x v) · m) (evalIsHom xs y v) ∙ ·Assoc _ _ _

module EqualityToNormalform (M : Monoid ℓ) where
  open Eval M
  open MonoidStr (snd M)

  -- proof that evaluation of an expression is invariant under normalization
  isEqualToNormalform : (n : ℕ)
                      → (e : Expr ⟨ M ⟩ n)
                      → (v : Env n)
                      → eval (normalize e) v ≡ ⟦ e ⟧ v
  isEqualToNormalform n (∣ i) v     = ·IdR _
  isEqualToNormalform n ε⊗ v        = refl
  isEqualToNormalform n (e₁ ⊗ e₂) v =
    eval ((normalize e₁) ++ (normalize e₂)) v         ≡⟨ evalIsHom (normalize e₁) (normalize e₂) v ⟩
    (eval (normalize e₁) v) · (eval (normalize e₂) v) ≡⟨ cong₂ _·_ (isEqualToNormalform n e₁ v) (isEqualToNormalform n e₂ v) ⟩
    ⟦ e₁ ⟧ v · ⟦ e₂ ⟧ v                               ∎

  solve : {n : ℕ}
        → (e₁ e₂ : Expr ⟨ M ⟩ n)
        → (v : Env n)
        → (p : eval (normalize e₁) v ≡ eval (normalize e₂) v)
        → ⟦ e₁ ⟧ v ≡ ⟦ e₂ ⟧ v
  solve e₁ e₂ v p =
    ⟦ e₁ ⟧ v              ≡⟨ sym (isEqualToNormalform _ e₁ v) ⟩
    eval (normalize e₁) v ≡⟨ p ⟩
    eval (normalize e₂) v ≡⟨ isEqualToNormalform _ e₂ v ⟩
    ⟦ e₂ ⟧ v              ∎

solve : (M : Monoid ℓ)
        {n : ℕ} (e₁ e₂ : Expr ⟨ M ⟩ n) (v : Eval.Env M n)
        (p :  Eval.eval M (Eval.normalize M e₁) v ≡ Eval.eval M (Eval.normalize M e₂) v)
        → _
solve M = EqualityToNormalform.solve M


------------------------------------------------------------------------
-- The Agda standard library
--
-- A binary representation of natural numbers
------------------------------------------------------------------------

module Data.Bin where

open import Data.Nat as Nat
  using (ℕ; zero; z≤n; s≤s) renaming (suc to 1+_)
open Nat.≤-Reasoning
import Data.Nat.Properties as NP
open import Data.Digit
open import Data.Fin as Fin using (Fin; zero) renaming (suc to 1+_)
open import Data.Fin.Properties as FP using (_+′_)
open import Data.List as List hiding (downFrom)
open import Function
open import Data.Product
open import Algebra
open import Relation.Binary
open import Relation.Binary.Consequences
open import Relation.Binary.PropositionalEquality as PropEq
  using (_≡_; _≢_; refl; sym)
open import Relation.Nullary
private
  module BitOrd = StrictTotalOrder (FP.strictTotalOrder 2)

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

-- A representation of binary natural numbers in which there is
-- exactly one representative for every number.

-- The function toℕ below defines the meaning of Bin.

infix 8 _1#

-- bs stands for the binary number 1<reverse bs>, which is positive.

Bin⁺ : Set
Bin⁺ = List Bit

data Bin : Set where
  -- Zero.
  0#  : Bin
  -- bs 1# stands for the binary number 1<reverse bs>.
  _1# : (bs : Bin⁺) → Bin

------------------------------------------------------------------------
-- Conversion functions

-- Converting to a list of bits starting with the _least_ significant
-- one.

toBits : Bin → List Bit
toBits 0#      = [ 0b ]
toBits (bs 1#) = bs ++ [ 1b ]

-- Converting to a natural number.

toℕ : Bin → ℕ
toℕ = fromDigits ∘ toBits

-- Converting from a list of bits, starting with the _least_
-- significant one.

fromBits : List Bit → Bin
fromBits []              = 0#
fromBits (b        ∷ bs) with fromBits bs
fromBits (b        ∷ bs) | bs′ 1# = (b ∷ bs′) 1#
fromBits (zero     ∷ bs) | 0#     = 0#
fromBits (1+ zero  ∷ bs) | 0#     = [] 1#
fromBits (1+ 1+ () ∷ bs) | _

-- Converting from a natural number.

fromℕ : ℕ → Bin
fromℕ n = fromBits $ proj₁ $ toDigits 2 n

------------------------------------------------------------------------
-- (Bin, _≡_, _<_) is a strict total order

infix 4 _<_

-- Order relation. Wrapped so that the parameters can be inferred.

data _<_ (b₁ b₂ : Bin) : Set where
  less : (lt : (Nat._<_ on toℕ) b₁ b₂) → b₁ < b₂

private
  <-trans : Transitive _<_
  <-trans (less lt₁) (less lt₂) = less (NP.<-trans lt₁ lt₂)

  asym : ∀ {b₁ b₂} → b₁ < b₂ → ¬ b₂ < b₁
  asym {b₁} {b₂} (less lt) (less gt) = tri⟶asym cmp lt gt
    where cmp = StrictTotalOrder.compare NP.strictTotalOrder

  irr : ∀ {b₁ b₂} → b₁ < b₂ → b₁ ≢ b₂
  irr lt eq = asym⟶irr (PropEq.resp₂ _<_) sym asym eq lt

  irr′ : ∀ {b} → ¬ b < b
  irr′ lt = irr lt refl

  ∷∙ : ∀ {b₁ b₂ bs₁ bs₂} →
       bs₁ 1# < bs₂ 1# → (b₁ ∷ bs₁) 1# < (b₂ ∷ bs₂) 1#
  ∷∙ {b₁} {b₂} {bs₁} {bs₂} (less lt) = less (begin
      1 + (m₁ + n₁ * 2)  ≤⟨ ≤-refl {x = 1} +-mono
                              (≤-pred (FP.bounded b₁) +-mono ≤-refl) ⟩
      1 + (1  + n₁ * 2)  ≡⟨ refl ⟩
            suc n₁ * 2   ≤⟨ lt *-mono ≤-refl ⟩
                n₂ * 2   ≤⟨ n≤m+n m₂ (n₂ * 2) ⟩
           m₂ + n₂ * 2   ∎
    )
    where
    open Nat; open NP
    open DecTotalOrder decTotalOrder renaming (refl to ≤-refl)
    m₁ = Fin.toℕ b₁;   m₂ = Fin.toℕ b₂
    n₁ = toℕ (bs₁ 1#); n₂ = toℕ (bs₂ 1#)

  ∙∷ : ∀ {b₁ b₂ bs} →
       Fin._<_ b₁ b₂ → (b₁ ∷ bs) 1# < (b₂ ∷ bs) 1#
  ∙∷ {b₁} {b₂} {bs} lt = less (begin
    1 + (m₁  + n * 2)  ≡⟨ sym (+-assoc 1 m₁ (n * 2)) ⟩
    (1 + m₁) + n * 2   ≤⟨ lt +-mono ≤-refl ⟩
         m₂  + n * 2   ∎)
    where
    open Nat; open NP
    open DecTotalOrder decTotalOrder renaming (refl to ≤-refl)
    open CommutativeSemiring commutativeSemiring using (+-assoc)
    m₁ = Fin.toℕ b₁; m₂ = Fin.toℕ b₂; n = toℕ (bs 1#)

  1<[23] : ∀ {b} → [] 1# < (b ∷ []) 1#
  1<[23] {b} = less (NP.n≤m+n (Fin.toℕ b) 2)

  1<2+ : ∀ {bs b} → [] 1# < (b ∷ bs) 1#
  1<2+ {[]}     = 1<[23]
  1<2+ {b ∷ bs} = <-trans 1<[23] (∷∙ {b₁ = b} (1<2+ {bs}))

  0<1 : 0# < [] 1#
  0<1 = less (s≤s z≤n)

  0<+ : ∀ {bs} → 0# < bs 1#
  0<+ {[]}     = 0<1
  0<+ {b ∷ bs} = <-trans 0<1 1<2+

  compare⁺ : Trichotomous (_≡_ on _1#) (_<_ on _1#)
  compare⁺ []         []         = tri≈ irr′ refl irr′
  compare⁺ []         (b ∷ bs)   = tri<       1<2+  (irr 1<2+) (asym 1<2+)
  compare⁺ (b ∷ bs)   []         = tri> (asym 1<2+) (irr 1<2+ ∘ sym) 1<2+
  compare⁺ (b₁ ∷ bs₁) (b₂ ∷ bs₂) with compare⁺ bs₁ bs₂
  ... | tri<  lt ¬eq ¬gt = tri<       (∷∙ lt)  (irr (∷∙ lt)) (asym (∷∙ lt))
  ... | tri> ¬lt ¬eq  gt = tri> (asym (∷∙ gt)) (irr (∷∙ gt) ∘ sym) (∷∙ gt)
  compare⁺ (b₁ ∷ bs) (b₂ ∷ .bs) | tri≈ ¬lt refl ¬gt with BitOrd.compare b₁ b₂
  compare⁺ (b  ∷ bs) (.b ∷ .bs) | tri≈ ¬lt refl ¬gt | tri≈ ¬lt′ refl ¬gt′ =
    tri≈ irr′ refl irr′
  ... | tri<  lt′ ¬eq ¬gt′ = tri<       (∙∷ lt′)  (irr (∙∷ lt′)) (asym (∙∷ lt′))
  ... | tri> ¬lt′ ¬eq  gt′ = tri> (asym (∙∷ gt′)) (irr (∙∷ gt′) ∘ sym) (∙∷ gt′)

  compare : Trichotomous _≡_ _<_
  compare 0#       0#       = tri≈ irr′ refl irr′
  compare 0#       (bs₂ 1#) = tri<       0<+  (irr 0<+) (asym 0<+)
  compare (bs₁ 1#) 0#       = tri> (asym 0<+) (irr 0<+ ∘ sym) 0<+
  compare (bs₁ 1#) (bs₂ 1#) = compare⁺ bs₁ bs₂

strictTotalOrder : StrictTotalOrder _ _ _
strictTotalOrder = record
  { Carrier            = Bin
  ; _≈_                = _≡_
  ; _<_                = _<_
  ; isStrictTotalOrder = record
    { isEquivalence = PropEq.isEquivalence
    ; trans         = <-trans
    ; compare       = compare
    ; <-resp-≈      = PropEq.resp₂ _<_
    }
  }

------------------------------------------------------------------------
-- (Bin, _≡_) is a decidable setoid

decSetoid : DecSetoid _ _
decSetoid = StrictTotalOrder.decSetoid strictTotalOrder

infix 4 _≟_

_≟_ : Decidable {A = Bin} _≡_
_≟_ = DecSetoid._≟_ decSetoid

------------------------------------------------------------------------
-- Arithmetic

-- Power of two.

infixr 8 2^_

2^_ : ℕ → Bin⁺
2^ 0    = []
2^ 1+ n = 0b ∷ 2^ n

-- Base 2 logarithm (rounded downwards).

⌊log₂_⌋ : Bin⁺ → ℕ
⌊log₂ (b ∷ bs) ⌋ = 1+ ⌊log₂ bs ⌋
⌊log₂ []       ⌋ = 0

-- Multiplication by 2.

infix 7 _*2 _*2+1

_*2 : Bin → Bin
0#      *2 = 0#
(bs 1#) *2 = (0b ∷ bs) 1#

_*2+1 : Bin → Bin
0#      *2+1 = [] 1#
(bs 1#) *2+1 = (1b ∷ bs) 1#

-- Division by 2, rounded downwards.

⌊_/2⌋ : Bin → Bin
⌊ 0#          /2⌋ = 0#
⌊ [] 1#       /2⌋ = 0#
⌊ (b ∷ bs) 1# /2⌋ = bs 1#

-- Addition.

Carry : Set
Carry = Bit

addBits : Carry → Bit → Bit → Carry × Bit
addBits c b₁ b₂ with c +′ (b₁ +′ b₂)
... | zero          = (0b , 0b)
... | 1+ zero       = (0b , 1b)
... | 1+ 1+ zero    = (1b , 0b)
... | 1+ 1+ 1+ zero = (1b , 1b)
... | 1+ 1+ 1+ 1+ ()

addCarryToBitList : Carry → List Bit → List Bit
addCarryToBitList zero      bs             = bs
addCarryToBitList (1+ zero) []             = 1b ∷ []
addCarryToBitList (1+ zero) (zero    ∷ bs) = 1b ∷ bs
addCarryToBitList (1+ zero) (1+ zero ∷ bs) = 0b ∷ addCarryToBitList 1b bs
addCarryToBitList (1+ 1+ ()) _
addCarryToBitList _ ((1+ 1+ ()) ∷ _)

addBitLists : Carry → List Bit → List Bit → List Bit
addBitLists c []         bs₂        = addCarryToBitList c bs₂
addBitLists c bs₁        []         = addCarryToBitList c bs₁
addBitLists c (b₁ ∷ bs₁) (b₂ ∷ bs₂) with addBits c b₁ b₂
... | (c' , b') = b' ∷ addBitLists c' bs₁ bs₂

infixl 6 _+_

_+_ : Bin → Bin → Bin
m + n = fromBits (addBitLists 0b (toBits m) (toBits n))

-- Multiplication.

infixl 7 _*_

_*_ : Bin → Bin → Bin
0#                 * n = 0#
[]              1# * n = n
-- (b + 2 * bs 1#) * n = b * n + 2 * (bs 1# * n)
(b        ∷ bs) 1# * n with bs 1# * n
(b        ∷ bs) 1# * n | 0#     = 0#
(zero     ∷ bs) 1# * n | bs' 1# = (0b ∷ bs') 1#
(1+ zero  ∷ bs) 1# * n | bs' 1# = n + (0b ∷ bs') 1#
((1+ 1+ ()) ∷ _) 1# * _ | _

-- Successor.

suc : Bin → Bin
suc n = [] 1# + n

-- Division by 2, rounded upwards.

⌈_/2⌉ : Bin → Bin
⌈ n /2⌉ = ⌊ suc n /2⌋

-- Predecessor.

pred : Bin⁺ → Bin
pred []              = 0#
pred (zero     ∷ bs) = pred bs *2+1
pred (1+ zero  ∷ bs) = (zero ∷ bs) 1#
pred (1+ 1+ () ∷ bs)

-- downFrom n enumerates all numbers from n - 1 to 0. This function is
-- linear in n. Analysis: fromℕ takes linear time, and the preds used
-- take amortised constant time (to see this, let the cost of a pred
-- be 2, and put 1 debit on every bit which is 1).

downFrom : ℕ → List Bin
downFrom n = helper n (fromℕ n)
  where
  helper : ℕ → Bin → List Bin
  helper zero   0#      = []
  helper (1+ n) (bs 1#) = n′ ∷ helper n n′
    where n′ = pred bs
  -- Impossible cases:
  helper zero   (_ 1#)  = []
  helper (1+ _) 0#      = []

------------------------------------------------------------------------
-- Tests

-- The tests below have been commented out since (at least one version
-- of) Agda is too slow or memory-hungry to type check them.

{-
-- The tests below are run when this module is type checked.

-- First some test helpers:

private

  testLimit : ℕ
  testLimit = 5

  nats : List ℕ
  nats = List.downFrom testLimit

  nats⁺ : List ℕ
  nats⁺ = filter (λ n → decToBool (Nat._≤?_ 1 n)) nats

  natPairs : List (ℕ × ℕ)
  natPairs = zip nats (reverse nats)

  _=[_]_ : (ℕ → ℕ) → List ℕ → (Bin → Bin) → Set
  f =[ ns ] g = map f ns ≡ map (toℕ ∘ g ∘ fromℕ) ns

  _=[_]₂_ : (ℕ → ℕ → ℕ) → List (ℕ × ℕ) → (Bin → Bin → Bin) → Set
  f =[ ps ]₂ g =
    map (uncurry f) ps ≡ map (toℕ ∘ uncurry (g on fromℕ)) ps

-- And then the tests:

private

  test-*2+1 : (λ n → Nat._+_ (Nat._*_ n 2) 1) =[ nats ] _*2+1
  test-*2+1 = refl

  test-*2 : (λ n → Nat._*_ n 2) =[ nats ] _*2
  test-*2 = refl

  test-⌊_/2⌋ : Nat.⌊_/2⌋ =[ nats ] ⌊_/2⌋
  test-⌊_/2⌋ = refl

  test-+ : Nat._+_ =[ natPairs ]₂ _+_
  test-+ = refl

  test-* : Nat._*_ =[ natPairs ]₂ _*_
  test-* = refl

  test-suc : 1+_ =[ nats ] suc
  test-suc = refl

  test-⌈_/2⌉ : Nat.⌈_/2⌉ =[ nats ] ⌈_/2⌉
  test-⌈_/2⌉ = refl

  drop-1# : Bin → Bin⁺
  drop-1# 0#      = []
  drop-1# (bs 1#) = bs

  test-pred : Nat.pred =[ nats⁺ ] (pred ∘ drop-1#)
  test-pred = refl

  test-downFrom : map toℕ (downFrom testLimit) ≡
                  List.downFrom testLimit
  test-downFrom = refl
-}


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

syntax Monad | M

type
  T : 1-ary

term
  ret  : α  ->  T α
  bind : T α  α.(T β)  ->  T β | _>>=_ r10

theory
  (LU) a : α   b : α.(T β) |> bind (ret(a), x. b[x]) =  b[a]
  (RU) t : T α |> bind (t, x. ret(x)) = t
  (AS) t : T α  b : α.(T β)  c : β.(T γ) |> bind (bind (t, x.b[x]), y.c[y]) = bind (t, x. bind (b[x], y.c[y]))
-}

module Monad.Equality where

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

open import Monad.Signature
open import Monad.Syntax

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

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

infix 1 _▹_⊢_≋ₐ_

-- Axioms of equality
data _▹_⊢_≋ₐ_ : ∀ 𝔐 Γ {α} → (𝔐 ▷ M) α Γ → (𝔐 ▷ M) α Γ → Set where
  LU : ⁅ α ⁆ ⁅ α ⊩ T β ⁆̣               ▹ ∅ ⊢         (ret 𝔞) >>= 𝔟⟨ x₀ ⟩ ≋ₐ 𝔟⟨ 𝔞 ⟩
  RU : ⁅ T α ⁆̣                         ▹ ∅ ⊢              𝔞 >>= (ret x₀) ≋ₐ 𝔞
  AS : ⁅ T α ⁆ ⁅ α ⊩ T β ⁆ ⁅ β ⊩ T γ ⁆̣ ▹ ∅ ⊢ (𝔞 >>= 𝔟⟨ x₀ ⟩) >>= 𝔠⟨ x₀ ⟩ ≋ₐ 𝔞 >>= (𝔟⟨ x₀ ⟩ >>= 𝔠⟨ x₀ ⟩)

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


open import Relation.Binary using (Setoid)

module Data.Vec.Any.Membership {a ℓ} (S : Setoid a ℓ) where
  open import Level using (_⊔_)
  open Setoid S renaming (Carrier to A; refl to ≈-refl; trans to ≈-trans )
  open import Relation.Nullary
  open import Relation.Binary
  open import Data.Fin
  open import Data.Nat as ℕ hiding (_⊔_)
  open import Data.Product as Prod hiding (map)
  open import Data.Vec as Vec hiding (map)
  open import Data.Vec.Equality
  open import Data.Vec.Any as Any
  open import Function using (_∘_; id; flip)
  open Equality S renaming (_≈_ to _≋_; trans to ≋-trans)

  infix 4 _∈′_ _∉′_
  _∈′_ : ∀ {n} → A → Vec A n → Set (a ⊔ ℓ)
  x ∈′ xs = Any (x ≈_) xs

  _∉′_ : ∀ {n} → A → Vec A n → Set (a ⊔ ℓ)
  x ∉′ xs = ¬ (x ∈′ xs)

  infix 4 _⊆_ _⊈_

  _⊆_  : ∀ {n m} → Vec A n → Vec A m → Set _
  xs ⊆ ys = ∀ {x} → x ∈′ xs → x ∈′ ys
  _⊈_  : ∀ {n m} → Vec A n → Vec A m → Set _
  xs ⊈ ys = ¬ (xs ⊆ ys)

  -- A variant of Vec.map.

  map-with-∈′ : ∀ {n b} {B : Set b}
             (xs : Vec A n) → (∀ {x} → x ∈′ xs → B) → Vec B n
  map-with-∈′ []       f = []
  map-with-∈′ (x ∷ xs) f = f (here ≈-refl)  ∷ map-with-∈′ xs (f ∘ there)

  -- Finds an element satisfying the predicate.

  find′ : ∀ {p n} {P : A → Set p} {xs : Vec A n} →
         Any P xs → ∃ λ x → x ∈′ xs × P x
  find′ (here px) = , here ≈-refl  , px
  find′ (there pxs) = Prod.map id (Prod.map there id) (find′ pxs)

  lose′ : ∀ {p n} {P : A → Set p} {x}{xs : Vec A n} →
         P Respects _≈_ → x ∈′ xs → P x → Any P xs
  lose′ resp x∈′xs  px = map (flip resp px) x∈′xs


{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Algebra.Magma.Morphism where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Functions.Embedding

open import Cubical.Algebra

private
  variable
    m n : Level

IsMagmaHom : (M : Magma m) (N : Magma n) → (⟨ M ⟩ → ⟨ N ⟩) → Type (ℓ-max m n)
IsMagmaHom M N fun = Homomorphic₂ fun (Magma._•_ M) (Magma._•_ N)

record MagmaHom (M : Magma m) (N : Magma n) : Type (ℓ-max m n) where
  constructor magmahom
  field
    fun : ⟨ M ⟩ → ⟨ N ⟩
    isHom : IsMagmaHom M N fun

record MagmaEquiv (M : Magma m) (N : Magma n) : Type (ℓ-max m n) where
  constructor magmaequiv
  field
    eq : ⟨ M ⟩ ≃ ⟨ N ⟩
    isHom : IsMagmaHom M N (equivFun eq)

  hom : MagmaHom M N
  hom = record { isHom = isHom }

instance
  MagmaHomOperators : HomOperators (Magma m) (Magma n) (ℓ-max m n)
  MagmaHomOperators = record { _⟶ᴴ_ = MagmaHom; _≃ᴴ_ = MagmaEquiv }


module stateDependentObjects where

open import Size renaming (Size to AgdaSize)
open import Agda.Builtin.Equality
open import Data.Nat.Base as N hiding (_⊔_)
open import Data.Product
open import Data.Vec as Vec using (Vec; []; _∷_; head; tail)
open import Function
open import NativeIO
open import Relation.Binary.PropositionalEquality
open import interactiveProgramsAgda
-- open import SizedIO.Base

{- State dependent interfaces, objects -}

record Interfaceˢ : Set₁ where
  field  Stateˢ  : Set
         Methodˢ : (s : Stateˢ) → Set
         Resultˢ : (s : Stateˢ) → (m : Methodˢ s) → Set
         nextˢ   : (s : Stateˢ) → (m : Methodˢ s) → (r : Resultˢ s m)
                   → Stateˢ

open Interfaceˢ public

{- State-Dependent Objects -}

record Objectˢ (I : Interfaceˢ) (s : Stateˢ I) : Set where
  coinductive
  field objectMethod :  (m : Methodˢ I s) →
                        Σ[ r ∈ Resultˢ I s m ] Objectˢ I (nextˢ I s m r)

open Objectˢ public

record IOObjectˢ (Iᵢₒ : IOInterface) (I : Interfaceˢ) (s : Stateˢ I) : Set where
  coinductive
  field method :  (m : Methodˢ I s) →
                  IO Iᵢₒ ∞ (Σ[ r ∈ Resultˢ I s m ] IOObjectˢ Iᵢₒ I (nextˢ I s m r))

{- Example of a Stack -}

StackStateˢ : Set
StackStateˢ = ℕ

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

StackResultˢ : (A : Set) → (s : StackStateˢ) → StackMethodˢ A s → Set
StackResultˢ A _  (push _)  =  Unit
StackResultˢ A _  pop       =  A

stackNextˢ  :  ∀ A n (m : StackMethodˢ A n) (r : StackResultˢ A n m) →  StackStateˢ
stackNextˢ A  n        (push x)  r  =  suc n
stackNextˢ A  (suc n)  pop       r  =  n

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

stack  :  ∀{A}{n : ℕ} (as : Vec A n) →  Objectˢ (StackInterfaceˢ A) n
objectMethod (stack as)        (push a)  =  _  ,  stack (a ∷ as)
objectMethod (stack (a ∷ as))  pop       =  a  ,  stack as

{- Reasoning about Stateful Objects -}

{- Bisimiliarity -}

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

  data  ΣR     {A : Set} {B : A → Set} (R : ∀{a} (b b' : B a) → Set)
               :  (p p' : Σ A B) → Set
        where
        eqΣ    :  ∀{a}{b b' : B a} → R b b' → ΣR R (a , b) (a , b')

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

  open _≅_ public

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

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

{-  Verifying Stack laws -}

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

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

  pop-after-push = refl , refl≅ _

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

    in   st ≅ st₂
  push-after-pop = refl≅ _

{- Bisimilarity of different stack implementations -}

  stackFState = ℕ → E

  pushStackF : E → stackFState → stackFState
  pushStackF e f = λ { 0       → e ;
                       (suc m) → f m}

  popStackFe : stackFState → E
  popStackFe f = f 0

  popStackFf  :  stackFState → stackFState
  popStackFf f = f ∘ suc

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

  stackF : ∀ (n : ℕ) (f : ℕ → E) → Objectˢ (StackInterfaceˢ E) n
  objectMethod (stackF n       f) (push e) = _ ,
                                             stackF (suc n) (pushStackF e f)
  objectMethod (stackF (suc n) f) pop      = popStackFe f ,
                                             stackF n (popStackFf f)

  impl-bisim : ∀{n f} v (p : tabulate n f ≡ v) → stackF n f ≅ stack v
  bisimMethod (impl-bisim v        p) (push e) =
    eqΣ (impl-bisim (e ∷ v)  (cong (_∷_ e)  p))

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


module plfa-code.Connectives where

import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open Eq.≡-Reasoning
open import Data.Nat using (ℕ)
open import Function using (_∘_)
open import plfa-code.Isomorphism using (_≃_; _≲_; extensionality)
open plfa-code.Isomorphism.≃-Reasoning

data _×_ (A B : Set) : Set where

  ⟨_,_⟩ :
      A
    → B
      -----
    → A × B

proj₁ : ∀ {A B : Set}
  → A × B
    -----
  → A
proj₁ ⟨ x , y ⟩ = x

proj₂ : ∀ {A B : Set}
  → A × B
    -----
  → B
proj₂ ⟨ x , y ⟩ = y

record _×′_ (A B : Set) : Set where
  field
    proj₁′ : A
    proj₂′ : B
open _×′_

η-× : ∀ {A B : Set} (w : A × B) → ⟨ proj₁ w , proj₂ w ⟩ ≡ w
η-× ⟨ x , y ⟩ = refl

infixr 2 _×_

data Bool : Set where
  true  : Bool
  false : Bool

data Tri : Set where
  aa : Tri
  bb : Tri
  cc : Tri

×-count : Bool × Tri → ℕ
×-count ⟨ true  , aa ⟩  =  1
×-count ⟨ true  , bb ⟩  =  2
×-count ⟨ true  , cc ⟩  =  3
×-count ⟨ false , aa ⟩  =  4
×-count ⟨ false , bb ⟩  =  5
×-count ⟨ false , cc ⟩  =  6

×-comm : ∀ {A B : Set} → A × B ≃ B × A
×-comm =
  record
    { to       =  λ{ ⟨ x , y ⟩ → ⟨ y , x ⟩ }
    ; from     =  λ{ ⟨ y , x ⟩ → ⟨ x , y ⟩ }
    ; from∘to  =  λ{ ⟨ x , y ⟩ → refl }
    ; to∘from  =  λ{ ⟨ y , x ⟩ → refl }
    }

×-assoc : ∀ {A B C : Set} → (A × B) × C ≃ A × (B × C)
×-assoc =
  record
    { to      = λ{ ⟨ ⟨ x , y ⟩ , z ⟩ → ⟨ x , ⟨ y , z ⟩ ⟩ }
    ; from    = λ{ ⟨ x , ⟨ y , z ⟩ ⟩ → ⟨ ⟨ x , y ⟩ , z ⟩ }
    ; from∘to = λ{ ⟨ ⟨ x , y ⟩ , z ⟩ → refl }
    ; to∘from = λ{ ⟨ x , ⟨ y , z ⟩ ⟩ → refl }
    }

---------- practice ----------
open plfa-code.Isomorphism using (_⇔_)
open _⇔_

⇔-≃-→×→ : ∀ {A B : Set} → A ⇔ B ≃ (A → B) × (B → A)
⇔-≃-→×→ =
  record
  { to      = λ x → ⟨ to x , from x ⟩
  ; from    = λ{ ⟨ A→B , B→A ⟩ → record { to = A→B ; from = B→A } }
  ; from∘to = λ x → refl
  ; to∘from = λ{ ⟨ A→B , B→A ⟩ → refl }
  }

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

data ⊤ : Set where

  tt :
    --
    ⊤

η-⊤ : ∀ (w : ⊤) → tt ≡ w
η-⊤ tt = refl

⊤-count : ⊤ → ℕ
⊤-count tt = 1

⊤-identityˡ : ∀ {A : Set} → ⊤ × A ≃ A
⊤-identityˡ =
  record
    { to      = λ{ ⟨ tt , x ⟩ → x }
    ; from    = λ x → ⟨ tt , x ⟩
    ; from∘to = λ{ ⟨ tt , x ⟩ → refl }
    ; to∘from = λ x → refl
    }

⊤-identityʳ : ∀ {A : Set} → (A × ⊤) ≃ A
⊤-identityʳ {A} =
  ≃-begin
    (A × ⊤)
  ≃⟨ ×-comm ⟩
    (⊤ × A)
  ≃⟨ ⊤-identityˡ ⟩
    A
  ≃-∎

data _⊎_ (A B : Set) : Set where

  inj₁ :
      A
      -----
    → A ⊎ B

  inj₂ :
      B
      -----
    → A ⊎ B

case-⊎ : ∀ {A B C : Set}
  → (A → C)
  → (B → C)
  → A ⊎ B
    -----------
  → C
case-⊎ f g (inj₁ x) = f x
case-⊎ f g (inj₂ y) = g y

η-⊎ : ∀ {A B : Set} (w : A ⊎ B) → case-⊎ inj₁ inj₂ w ≡ w
η-⊎ (inj₁ x) = refl
η-⊎ (inj₂ y) = refl

uniq-⊎ : ∀ {A B C : Set} (h : A ⊎ B → C) (w : A ⊎ B) →
  case-⊎ (h ∘ inj₁) (h ∘ inj₂) w ≡ h w
uniq-⊎ h (inj₁ x) = refl
uniq-⊎ h (inj₂ y) = refl

infix 1 _⊎_

⊎-count : Bool ⊎ Tri → ℕ
⊎-count (inj₁ true)  =  1
⊎-count (inj₁ false) =  2
⊎-count (inj₂ aa)    =  3
⊎-count (inj₂ bb)    =  4
⊎-count (inj₂ cc)    =  5

---------- practice ----------
⊎-comm : ∀ {A B : Set} → A ⊎ B ≃ B ⊎ A
⊎-comm =
  record
  { to      = λ{(inj₁ a) → inj₂ a ; (inj₂ b) → inj₁ b }
  ; from    = λ{(inj₁ b) → inj₂ b ; (inj₂ a) → inj₁ a }
  ; from∘to = λ{(inj₁ a) → refl ; (inj₂ b) → refl }
  ; to∘from = λ{(inj₁ b) → refl ; (inj₂ a) → refl }
  }

⊎-assoc : ∀ {A B C : Set} → (A ⊎ B) ⊎ C ≃ A ⊎ (B ⊎ C)
⊎-assoc =
  record
  { to      = to′
  ; from    = from′
  ; from∘to = from∘to′
  ; to∘from = to∘from′
  }
  where
    to′ : ∀ {A B C : Set} → (A ⊎ B) ⊎ C → A ⊎ (B ⊎ C)
    to′ (inj₁ (inj₁ a)) = inj₁ a
    to′ (inj₁ (inj₂ b)) = inj₂ (inj₁ b)
    to′ (inj₂ c) = inj₂ (inj₂ c)
    from′ : ∀ {A B C : Set} → A ⊎ (B ⊎ C) → (A ⊎ B) ⊎ C
    from′ (inj₁ a) = inj₁ (inj₁ a)
    from′ (inj₂ (inj₁ b)) = inj₁ (inj₂ b)
    from′ (inj₂ (inj₂ c)) = inj₂ c
    from∘to′ : ∀ (x) → from′ (to′ x) ≡ x
    from∘to′ (inj₁ (inj₁ a)) = refl
    from∘to′ (inj₁ (inj₂ b)) = refl
    from∘to′ (inj₂ c) = refl
    to∘from′ : ∀ (x) → to′ (from′ x) ≡ x
    to∘from′ (inj₁ a) = refl
    to∘from′ (inj₂ (inj₁ b)) = refl
    to∘from′ (inj₂ (inj₂ c)) = refl

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

data ⊥ : Set where
  -- no clauses!

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

uniq-⊥ : ∀ {C : Set} (h : ⊥ → C) (w : ⊥) → ⊥-elim w ≡ h w
uniq-⊥ h ()

⊥-count : ⊥ → ℕ
⊥-count ()

---------- practice ----------
⊥-identityˡ : ∀ {A : Set} → ⊥ ⊎ A ≃ A
⊥-identityˡ =
  record
  { to      = λ{ (inj₂ a) → a }
  ; from    = inj₂
  ; from∘to = λ{ (inj₂ a) → refl }
  ; to∘from = λ a → refl
  }

⊥-identityʳ : ∀ {A : Set} → A ⊎ ⊥ ≃ A
⊥-identityʳ {A} =
  ≃-begin
    (A ⊎ ⊥)
  ≃⟨ ⊎-comm ⟩
    (⊥ ⊎ A)
  ≃⟨ ⊥-identityˡ ⟩
    A
  ≃-∎

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

→-elim : ∀ {A B : Set}
  → (A → B)
  → A
    -------
  → B
→-elim L M = L M

η-→ : ∀ {A B : Set} (f : A → B) → (λ (x : A) → f x) ≡ f
η-→ f = refl

→-count : (Bool → Tri) → ℕ
→-count f with f true | f false
...          | aa     | aa      =   1
...          | aa     | bb      =   2
...          | aa     | cc      =   3
...          | bb     | aa      =   4
...          | bb     | bb      =   5
...          | bb     | cc      =   6
...          | cc     | aa      =   7
...          | cc     | bb      =   8
...          | cc     | cc      =   9

currying : ∀ {A B C : Set} → (A → B → C) ≃ (A × B → C)
currying =
  record
    { to      = λ f → λ{ ⟨ x , y ⟩ → f x y }
    ; from    = λ g x y → g ⟨ x , y ⟩
    ; from∘to = λ x → refl
    ; to∘from = λ{ g → extensionality λ{ ⟨ x , y ⟩ → refl } }
    }

→-distrib-⊎ : ∀ {A B C : Set} → (A ⊎ B → C) ≃ ((A → C) × (B → C))
→-distrib-⊎ =
  record
    { to      = λ{ f → ⟨ f ∘ inj₁ , f ∘ inj₂ ⟩ }
    ; from    = λ{ ⟨ g , h ⟩ → λ{ (inj₁ x) → g x ; (inj₂ y) → h y } }
    ; from∘to = λ{ f → extensionality λ{ (inj₁ x) → refl ; (inj₂ y) → refl } }
    ; to∘from = λ{ ⟨ g , h ⟩ → refl }
    }

→-distrib-× : ∀ {A B C : Set} → (A → B × C) ≃ (A → B) × (A → C)
→-distrib-× =
  record
    { to      = λ{ f → ⟨ proj₁ ∘ f , proj₂ ∘ f ⟩ }
    ; from    = λ{ ⟨ g , h ⟩ → λ x → ⟨ g x , h x ⟩ }
    ; from∘to = λ{ f → extensionality λ{ x → η-× (f x) } }
    ; to∘from = λ{ ⟨ g , h ⟩ → refl }
    }

×-distrib-⊎ : ∀ {A B C : Set} → (A ⊎ B) × C ≃ (A × C) ⊎ (B × C)
×-distrib-⊎ =
  record
    { to      = λ{ ⟨ inj₁ x , z ⟩ → (inj₁ ⟨ x , z ⟩)
                 ; ⟨ inj₂ y , z ⟩ → (inj₂ ⟨ y , z ⟩)
                 }
    ; from    = λ{ (inj₁ ⟨ x , z ⟩) → ⟨ inj₁ x , z ⟩
                 ; (inj₂ ⟨ y , z ⟩) → ⟨ inj₂ y , z ⟩
                 }
    ; from∘to = λ{ ⟨ inj₁ x , z ⟩ → refl
                 ; ⟨ inj₂ y , z ⟩ → refl
                 }
    ; to∘from = λ{ (inj₁ ⟨ x , z ⟩) → refl
                 ; (inj₂ ⟨ y , z ⟩) → refl
                 }
    }

⊎-distrib-× : ∀ {A B C : Set} → (A × B) ⊎ C ≲ (A ⊎ C) × (B ⊎ C)
⊎-distrib-× =
  record
    { to      = λ{ (inj₁ ⟨ x , y ⟩) → ⟨ inj₁ x , inj₁ y ⟩
                 ; (inj₂ z)         → ⟨ inj₂ z , inj₂ z ⟩
                 }
    ; from    = λ{ ⟨ inj₁ x , inj₁ y ⟩ → (inj₁ ⟨ x , y ⟩)
                 ; ⟨ inj₁ x , inj₂ z ⟩ → (inj₂ z)
                 ; ⟨ inj₂ z , _      ⟩ → (inj₂ z)
                 }
    ; from∘to = λ{ (inj₁ ⟨ x , y ⟩) → refl
                 ; (inj₂ z)         → refl
                 }
    }

---------- practice ----------
⊎-weak-× : ∀ {A B C : Set} → (A ⊎ B) × C → A ⊎ (B × C)
⊎-weak-× ⟨ inj₁ a , c ⟩ = inj₁ a
⊎-weak-× ⟨ inj₂ b , c ⟩ = inj₂ ⟨ b , c ⟩
-- the corresponding distributive law is ×-distrib-⊎, ×-distrib-⊎ is more strong

⊎×-implies-×⊎ : ∀ {A B C D : Set} → (A × B) ⊎ (C × D) → (A ⊎ C) × (B ⊎ D)
⊎×-implies-×⊎ (inj₁ ⟨ a , b ⟩) = ⟨ inj₁ a , inj₁ b ⟩
⊎×-implies-×⊎ (inj₂ ⟨ c , d ⟩) = ⟨ inj₂ c , inj₂ d ⟩
-- the converse doesn't hold. ⟨ inj₁ a , inj₂ d ⟩ could not build a
-- (A × B) ⊎ (C × D) value

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


------------------------------------------------------------------------------
-- The relation of divisibility on partial natural numbers
------------------------------------------------------------------------------

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

module FOTC.Data.Nat.Divisibility.NotBy0 where

open import FOTC.Base
open import FOTC.Data.Nat

infix 4 _∣_

------------------------------------------------------------------------------
-- The relation of divisibility (the symbol is '\mid' not '|')
--
-- (See documentation in FOTC.Data.Nat.Divisibility.By0)
--
-- In our definition 0∤0, which is used to prove properties of the gcd
-- as it is in GHC ≤ 7.0.4, where gcd 0 0 = undefined (see
-- http://hackage.haskell.org/trac/ghc/ticket/3304).

-- Note that @k@ should be a total natural number.
_∣_ : D → D → Set
m ∣ n =  (m ≢ zero) ∧ (∃[ k ] N k ∧ n ≡ k * m)
{-# ATP definition _∣_ #-}


-- Some proposition constructors.

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

module Tools.Nullary where

open import Tools.Empty

-- Negation.

infix 3 ¬_

¬_ : Set → Set
¬ P = P → ⊥

-- Decidable propositions.

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

-- If A and B are logically equivalent, then so are Dec A and Dec B.

map : ∀ {A B} → (A → B) → (B → A) → Dec A → Dec B
map f g (yes p) = yes (f p)
map f g (no ¬p) = no (λ x → ¬p (g x))


module GGT.Group.Bundles
  {a b ℓ}
  where

open import Algebra.Bundles using (Group)
open import Relation.Unary
open import Relation.Binary
open import Level
open import GGT.Group.Structures

record SubGroup (G : Group a ℓ) : Set (a ⊔ suc b ⊔ ℓ) where
  open Group G public
  field
    P : Pred Carrier b
    isSubGroup : IsSubGroup G P

  open IsSubGroup isSubGroup public
  -- imports ~
  -- xy-1 ∈ H => xy-1 = h => h'xy-1 = h'' => h'x = h''y -- right cosets
  -- x ↦ ω · x = ω · yx-1 · x = ω · y

cosetʳRel : {G : Group a ℓ} → (SubGroup G) → Setoid a b

cosetʳRel {G} H = record { Carrier = Carrier;
                           _≈_ = _∼_;
                           isEquivalence = iseq} where
                  open SubGroup H
                  open import GGT.Group.Facts G
                  iseq = record {refl  = cosetRelRefl isSubGroup ;
                                 sym   = cosetRelSym isSubGroup ;
                                 trans = cosetRelTrans isSubGroup }

syntax cosetʳRel {G} H = H \\ G


module Algebra.LabelledGraph.Reasoning where

open import Algebra.Dioid
open import Algebra.LabelledGraph

-- Standard syntax sugar for writing equational proofs
infix 4 _≈_
data _≈_ {A B eq} {d : Dioid B eq} (x y : LabelledGraph d A) : Set where
    prove : x ≡ y -> x ≈ y

infix 1 begin_
begin_ : ∀ {A B eq} {d : Dioid B eq} {x y : LabelledGraph d A} -> x ≈ y -> x ≡ y
begin prove p = p

infixr 2 _≡⟨_⟩_
_≡⟨_⟩_ : ∀ {A B eq} {d : Dioid B eq} (x : LabelledGraph d A) {y z : LabelledGraph d A} -> x ≡ y -> y ≈ z -> x ≈ z
_ ≡⟨ p ⟩ prove q = prove (transitivity p q)

infix 3 _∎
_∎ : ∀ {A B eq} {d : Dioid B eq} (x : LabelledGraph d A) -> x ≈ x
_∎ _ = prove reflexivity

infixl 8 _>>_
_>>_ : ∀ {A B eq} {d : Dioid B eq} {x y z : LabelledGraph d A} -> x ≡ y -> y ≡ z -> x ≡ z
_>>_ = transitivity

L : ∀ {A B eq} {d : Dioid B eq} {x y z : LabelledGraph d A} {r : B} -> x ≡ y -> x [ r ]> z ≡ y [ r ]> z
L = left-congruence

R : ∀ {A B eq} {d : Dioid B eq} {x y z : LabelledGraph d A} {r : B} -> x ≡ y -> z [ r ]> x ≡ z [ r ]> y
R = right-congruence


import Relation.Binary.PropositionalEquality as Eq
open Eq using (_≡_; refl)
open import Data.Nat using (ℕ; zero; suc)
open import Relation.Nullary using (Dec; yes; no)

data _≤_ : ℕ → ℕ → Set where
  z≤n : ∀ {n : ℕ} → zero ≤ n
  s≤s : ∀ {m n : ℕ} → m ≤ n → suc m ≤ suc n

_≤?_ : ∀ (m n : ℕ) → Dec (m ≤ n)
zero ≤? n = yes z≤n
suc m ≤? zero = no λ()
suc m ≤? suc n with m ≤? n
... | yes m≤n = yes (s≤s m≤n)
... | no ¬m≤n = no λ{ (s≤s m≤n) → ¬m≤n m≤n }

_ : 2 ≤? 4 ≡ yes (s≤s (s≤s z≤n))
_ = refl

_ : 4 ≤? 2 ≡ no {!!}
_ = refl

{-
Using ^C ^N, the term
  4 ≤? 2
evaluates to
  no (λ { (s≤s m≤n) → (λ { (s≤s m≤n) → (λ ()) 1 m≤n }) m≤n })
The 1 is spurious.
-}


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

module Cubical.Homotopy.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv.Properties

private
  variable
    ℓ ℓ' : Level

_∼_ : {X : Type ℓ} {Y : X → Type ℓ'} → (f g : (x : X) → Y x) → Type (ℓ-max ℓ ℓ')
_∼_ {X = X} f g = (x : X) → f x ≡ g x

funExt∼ : {X : Type ℓ} {Y : X → Type ℓ'} {f g : (x : X) → Y x} (H : f ∼ g) → f ≡ g
funExt∼ = funExt

∼-refl : {X : Type ℓ} {Y : X → Type ℓ'} {f : (x : X) → Y x} → f ∼ f
∼-refl {f = f} = λ x → refl {x = f x}


{-# OPTIONS --cubical --safe #-}
module Cubical.ZCohomology.S1.S1 where

open import Cubical.ZCohomology.Base
open import Cubical.ZCohomology.Properties
open import Cubical.HITs.S1
open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism
open import Cubical.HITs.SetTruncation
open import Cubical.HITs.Nullification
open import Cubical.Data.Int
open import Cubical.Data.Nat
open import Cubical.HITs.Truncation

----  H⁰(S¹) = ℤ  ----

coHom0-S1 : coHom zero S¹ ≡ Int
coHom0-S1 = (λ i → ∥ helpLemma i ∥₀ ) ∙ setId isSetInt
  where
  helpLemma : (S¹ → Int) ≡ Int
  helpLemma = isoToPath (iso fun funinv (λ _ → refl) (λ f → funExt (rinvLemma f)))
    where
    fun : (S¹ → Int) → Int
    fun f = f base

    funinv : Int → (S¹ → Int)
    funinv a base = a
    funinv a (loop i) = a

    rinvLemma : (f : S¹ → Int) → (x : S¹) → funinv (fun f) x ≡ f x
    rinvLemma f  base = refl
    rinvLemma f  (loop i) j = isSetInt (f base) (f base) (λ k → f (loop k)) refl (~ j) i

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

{- TODO : give Hᵏ(S¹) for all k -}