open import Coinduction using ( ∞ ; ♭ ; ♯_ )
open import Relation.Binary.PropositionalEquality using ( _≡_ ; _≢_ ; refl )
open import Relation.Nullary using ( Dec ; yes ; no )
open import System.IO.Transducers.Session using ( Session ; I ; Σ ; Γ ; _/_ ; IsI )

module System.IO.Transducers.Trace where

infixr 4 _≤_ _⊑_ _⊨_⊑_ _⊨_✓ _✓
infixr 5 _∷_ _++_

-- The semantics of a session is its set of traces.
-- The name "trace" comes from process algebra,
-- it's called a play in games semantics, or a word of an automaton.

data Trace (S : Session) : Set where
  [] : Trace S
  _∷_ : (a : Γ S) (as : Trace (S / a)) → (Trace S)

-- Traces ending in [] at type I are completed traces

data _⊨_✓ : ∀ S → (Trace S) → Set₁ where
  [] : I ⊨ [] ✓
  _∷_ : ∀ {S} a {as} → (S / a ⊨ as ✓) → (S ⊨ a ∷ as ✓)

_✓ : ∀ {S} → (Trace S) → Set₁
_✓ {S} as = S ⊨ as ✓

-- Prefix order on traces

data _⊨_⊑_ : ∀ S → (Trace S) → (Trace S) → Set₁ where
  [] : ∀ {S as} → (S ⊨ [] ⊑ as)
  _∷_ : ∀ {S} a {as bs} → (S / a ⊨ as ⊑ bs) → (S ⊨ a ∷ as ⊑ a ∷ bs)

_⊑_ : ∀ {S} → (Trace S) → (Trace S) → Set₁
_⊑_ {S} as bs = S ⊨ as ⊑ bs

-- For building buffers, it is useful to provide
-- snoc traces as well as cons traces.

data _≤_ : Session → Session → Set₁ where
  [] : ∀ {S} → (S ≤ S)
  _∷_ : ∀ {S T} a (as : S ≤ T) → (S / a ≤ T)

-- Snoc traces form categories, where composition is concatenation.

_++_ : ∀ {S T U} → (S ≤ T) → (T ≤ U) → (S ≤ U)
[]       ++ bs = bs
(a ∷ as) ++ bs = a ∷ (as ++ bs)

-- snoc traces can be reversed to form cons traces

revApp : ∀ {S T} → (S ≤ T) → (Trace S) → (Trace T)
revApp []       bs = bs
revApp (a ∷ as) bs = revApp as (a ∷ bs)

reverse : ∀ {S T} → (S ≤ T) → (Trace T)
reverse as = revApp as []


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

module Cubical.Data.Nat.Omniscience where

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

open import Cubical.Data.Bool
  renaming (Bool to 𝟚; Bool→Type to ⟨_⟩)
open import Cubical.Data.Nat
open import Cubical.Data.Nat.Order.Recursive

open import Cubical.Relation.Nullary

open import Cubical.Axiom.Omniscience

variable
  ℓ : Level
  A : Type ℓ
  F : A → Type ℓ

module _ where
  open Minimal

  never-least→never : (∀ m → ¬ Least F m) → (∀ m → ¬ F m)
  never-least→never ¬LF = wf-elim (flip ∘ curry ∘ ¬LF)

  never→never-least : (∀ m → ¬ F m) → (∀ m → ¬ Least F m)
  never→never-least ¬F m (Fm , _) = ¬F m Fm

  ¬least-wlpo : (∀(P : ℕ → 𝟚) → Dec (∀ x → ¬ Least (⟨_⟩ ∘ P) x)) → WLPO ℕ
  ¬least-wlpo lwlpo P = mapDec never-least→never (_∘ never→never-least) (lwlpo P)


open import Oscar.Prelude
open import Oscar.Class

module Oscar.Class.Reflexivity where

module Reflexivity'
  {𝔬} {𝔒 : Ø 𝔬}
  {𝔯} (_∼_ : 𝔒 → 𝔒 → Ø 𝔯)
  (x : 𝔒)
  = ℭLASS (_∼_) (x ∼ x)

module Reflexivity
  {𝔬} {𝔒 : Ø 𝔬}
  {𝔯} (_∼_ : 𝔒 → 𝔒 → Ø 𝔯)
  where
  class = ∀ {x} → Reflexivity'.class _∼_ x
  type = ∀ {x} → Reflexivity'.type _∼_ x
  method : ⦃ _ : class ⦄ → type
  method = Reflexivity'.method _∼_ _

module _
  {𝔬} {𝔒 : Ø 𝔬}
  {𝔯} {_∼_ : 𝔒 → 𝔒 → Ø 𝔯}
  where
  reflexivity = Reflexivity.method _∼_
  ε = reflexivity

module _
  {𝔬} {𝔒 : Ø 𝔬}
  {𝔯} (_∼_ : 𝔒 → 𝔒 → Ø 𝔯)
  where
  reflexivity[_] = Reflexivity.method _∼_
  ε[_] = reflexivity


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

-- Constructions of a Cocone from the Twisted Arrow function from a Cowedge
-- and vice-versa, by Duality.
-- Note that the proper functioning of this relies crucially on
-- Functor.op (Functor.op F) being definitionally equal to F.

open import Categories.Category using (Category)
open import Categories.Functor.Bifunctor using (Bifunctor)

module Categories.Diagram.Cowedge.Properties {o ℓ e o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′}
  (F : Bifunctor (Category.op C) C D) where

open import Level

open import Categories.Category.Construction.Cocones using (Cocones)
open import Categories.Category.Construction.Cowedges
open import Categories.Category.Construction.TwistedArrow
open import Categories.Category.Equivalence using (StrongEquivalence)
open import Categories.Diagram.Cocone
open import Categories.Diagram.Cowedge
open import Categories.Diagram.Duality
open import Categories.Diagram.Wedge.Properties
open import Categories.Functor hiding (id)
open import Categories.Functor.Instance.Twisted C D
import Categories.Morphism.Reasoning as MR
open import Categories.NaturalTransformation.Dinatural
open import Categories.NaturalTransformation.NaturalIsomorphism using (niHelper)

Cowedge-to-Cocone : (W : Cowedge F) → Cocone (Twist′ F)
Cowedge-to-Cocone W = coCone⇒Cocone D (Wedge-to-Cone (Functor.op F) (Cowedge⇒coWedge D W))

Cocone-to-Cowedge : Cocone (Twist′ F) → Cowedge F
Cocone-to-Cowedge C = coWedge⇒Cowedge D (Cone-to-Wedge (Functor.op F) (Cocone⇒coCone D C))

CooneTwist⇒CowedgeF : Functor (Cocones (Twist′ F)) (Cowedges F)
CooneTwist⇒CowedgeF = record
  { F₀ = Cocone-to-Cowedge
  ; F₁ = λ co⇒ → record { u = arr co⇒ ; commute = commute co⇒ }
  ; identity = Equiv.refl
  ; homomorphism = Equiv.refl
  ; F-resp-≈ = λ f≈g → f≈g
  }
  where
  open Cocone⇒
  open Category D

Cowedge⇒CoconeTwistF : Functor (Cowedges F) (Cocones (Twist′ F))
Cowedge⇒CoconeTwistF = record
  { F₀ = Cowedge-to-Cocone
  ; F₁ = λ we⇒ → record
    { arr = u we⇒
    ; commute = pullˡ (commute we⇒)
    }
  ; identity = Equiv.refl
  ; homomorphism = Equiv.refl
  ; F-resp-≈ = λ f≈g → f≈g
  }
  where
  open Cowedge
  open Cowedge-Morphism
  open Category D
  open MR D

-- The duality here is not just 'op', so spell out some of it.  Note how the proofs need the explicit commutations.
CoconesTwist≅Cowedges : StrongEquivalence (Cocones (Twist′ F)) (Cowedges F)
CoconesTwist≅Cowedges = record
  { F = CooneTwist⇒CowedgeF
  ; G = Cowedge⇒CoconeTwistF
  ; weak-inverse = record
    { F∘G≈id = niHelper (record
      { η = λ X → record { u = id ; commute = identityˡ ○ MR.elimʳ D identity }
      ; η⁻¹ = λ X → record { u = id ; commute = MR.id-comm-sym D ○ (refl⟩∘⟨ Equiv.sym identity) }
      ; commute = λ _ → MR.id-comm-sym D
      ; iso = λ _ → record { isoˡ = identity² ; isoʳ = identity² }
      })
    ; G∘F≈id = niHelper record
      { η = λ X → record { arr = id ; commute = λ {Y} → identityˡ ○ Coapex.commute (coapex X) (mor⇒ (MR.elimˡ C C.identity²)) }
      ; η⁻¹ = λ X → record { arr = id ; commute = λ {Y} → identityˡ ○ Equiv.sym (Coapex.commute (coapex X) (mor⇒ (MR.elimˡ C C.identity²))) }
      ; commute = λ _ → MR.id-comm-sym D
      ; iso = λ X → record { isoˡ = identity² ; isoʳ = identity² }
      }
    }
  }
  where
  module C = Category C
  open Category D
  open HomReasoning
  open Cocone
  open Functor F
  open Cowedge
  open DinaturalTransformation


------------------------------------------------------------------------------
-- Testing an implicit argument for natural numbers induction
------------------------------------------------------------------------------

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

module FOT.PA.Inductive.ImplicitArgumentInductionSL where

open import Data.Nat renaming ( suc to succ )
open import Relation.Binary.PropositionalEquality

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

succCong : ∀ {m n} → m ≡ n → succ m ≡ succ n
succCong refl = refl

-- N.B. It is not possible to use an implicit argument in the
-- inductive hypothesis.
ℕ-ind : (A : ℕ → Set) → A zero → (∀ {n} → A n → A (succ n)) → ∀ n → A n
ℕ-ind A A0 h zero     = A0
ℕ-ind A A0 h (succ n) = h (ℕ-ind A A0 h n)

+-assoc : ∀ m n o → m + n + o ≡ m + (n + o)
+-assoc m n o = ℕ-ind A A0 is m
  where
  A : ℕ → Set
  A i = i + n + o ≡ i + (n + o)

  A0 : A zero
  A0 = refl

  is : ∀ {i} → A i → A (succ i)
  is ih = succCong ih


module prelude where
open import Function using (id; _∘_) public
open import Data.Sum renaming (inj₁ to Σ₁; inj₂ to Σ₂) using (_⊎_) public
open import Data.Product renaming (proj₁ to π₁; proj₂ to π₂) using (Σ; _×_; _,_; ∃; Σ-syntax) public
open import Agda.Builtin.Unit using (⊤; tt) public
open import Data.Empty using (⊥) public
open import Data.Nat as Nat renaming (suc to ℕs; zero to ℕz; _+_ to _ℕ+_) using (ℕ) public
open import Relation.Binary.PropositionalEquality.Core as Eq using (_≡_; _≢_; refl; sym; trans; subst) renaming (cong to _⟨$⟩_) public
open Eq.≡-Reasoning using (_≡⟨⟩_; step-≡; _∎) public

postulate
  extensionality : {A : Set} {B : A → Set} {f g : (x : A) → B x}
                 → (∀ x → f x ≡ g x) → f ≡ g
extensionality2 : {A : Set} {B : A → Set} {C : (x : A) → B x → Set} {f g : (x : A) (y : B x) → C x y }
                 → (∀ x y → f x y ≡ g x y) → f ≡ g
extensionality2 λλf≡g = extensionality λ x → extensionality λ y → λλf≡g x y

trans-refl : {A : Set} {x y : A} (p : x ≡ y) → trans p refl ≡ p
trans-refl p rewrite p = refl

subst⋯ : {A : Set} {x y z : A} (P : A → Set) (p : x ≡ y) (q : y ≡ z) (Px : P x)
      → subst P (trans p q) Px ≡ subst P q (subst P p Px)
subst⋯ _ p _ _ rewrite p = refl

_×⁼_ : {A X : Set} {a b : A} {x y : X} → a ≡ b → x ≡ y → (a , x) ≡ (b , y)
_×⁼_ refl refl = refl

_⨄_ : {A B : Set} → (A → Set) → (B → Set) → A ⊎ B → Set
(F ⨄ G) (Σ₁ x) = F x
(F ⨄ G) (Σ₂ y) = G y
_⨃_ _⨉_ : {A B : Set} → (A → Set) → (B → Set) → A × B → Set
F ⨃ G = λ (a , b) → F a ⊎ G b
F ⨉ G = λ (a , b) → F a × G b

_$₁_ : ∀ {A B X : Set} (f : A → B) → A × X → B × X
f $₁ (a , x) = f a , x

_⁻¹ : {A B : Set} → (A → B) → B → Set
_⁻¹ {A} {B} f b = Σ[ a ∈ A ] (f a ≡ b)

uncurry : {a b c : Set} → (a → b → c) → (a × b) → c
uncurry f (a , b) = f a b


{-

Product of structures S and T: X ↦ S X × T X

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

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Transport
open import Cubical.Foundations.Univalence
open import Cubical.Foundations.Path
open import Cubical.Foundations.SIP
open import Cubical.Data.Sigma

private
  variable
    ℓ ℓ₁ ℓ₁' ℓ₂ ℓ₂' : Level

ProductStructure : (S₁ : Type ℓ → Type ℓ₁) (S₂ : Type ℓ → Type ℓ₂)
  → Type ℓ → Type (ℓ-max ℓ₁ ℓ₂)
ProductStructure S₁ S₂ X = S₁ X × S₂ X

ProductEquivStr :
  {S₁ : Type ℓ → Type ℓ₁} (ι₁ : StrEquiv S₁ ℓ₁')
  {S₂ : Type ℓ → Type ℓ₂} (ι₂ : StrEquiv S₂ ℓ₂')
  → StrEquiv (ProductStructure S₁ S₂) (ℓ-max ℓ₁' ℓ₂')
ProductEquivStr ι₁ ι₂ (X , s₁ , s₂) (Y , t₁ , t₂) f =
  (ι₁ (X , s₁) (Y , t₁) f) × (ι₂ (X , s₂) (Y , t₂) f)

productUnivalentStr :
  {S₁ : Type ℓ → Type ℓ₁} (ι₁ : StrEquiv S₁ ℓ₁') (θ₁ : UnivalentStr S₁ ι₁)
  {S₂ : Type ℓ → Type ℓ₂} (ι₂ : StrEquiv S₂ ℓ₂') (θ₂ : UnivalentStr S₂ ι₂)
  → UnivalentStr (ProductStructure S₁ S₂) (ProductEquivStr ι₁ ι₂)
productUnivalentStr {S₁ = S₁} ι₁ θ₁ {S₂} ι₂ θ₂ {X , s₁ , s₂} {Y , t₁ , t₂} e =
  compEquiv (Σ-cong-equiv (θ₁ e) (λ _ → θ₂ e)) ΣPath≃PathΣ

productEquivAction :
  {S₁ : Type ℓ → Type ℓ₁} (α₁ : EquivAction S₁)
  {S₂ : Type ℓ → Type ℓ₂} (α₂ : EquivAction S₂)
  → EquivAction (ProductStructure S₁ S₂)
productEquivAction α₁ α₂ e = Σ-cong-equiv (α₁ e) (λ _ → α₂ e)

productTransportStr :
  {S₁ : Type ℓ → Type ℓ₁} (α₁ : EquivAction S₁) (τ₁ : TransportStr α₁)
  {S₂ : Type ℓ → Type ℓ₂} (α₂ : EquivAction S₂) (τ₂ : TransportStr α₂)
  → TransportStr (productEquivAction α₁ α₂)
productTransportStr _ τ₁ _ τ₂ e (s₁ , s₂) = ΣPathP (τ₁ e s₁ , τ₂ e s₂)


{-# OPTIONS --no-universe-polymorphism #-}
open import Data.Product hiding (map)
open import Relation.Binary.Core
open import Function
open import Data.List
open import Data.Unit using (⊤)
open import Data.Empty

open import Equivalence

module BagEquality where

infixr 5 _⊕_

data _⊕_ (A B : Set) : Set where
             inj₁ : A → A ⊕ B
             inj₂ : B → A ⊕ B

uninhabited : {A : Set} → (A → ⊥) → A ↔ ⊥
uninhabited pf = record {to = pf;
                         from = ⊥-elim;
                         from-to = λ a → ⊥-elim (pf a);
                         to-from = λ false → ⊥-elim false}

Any : {A : Set} → (A → Set) → List A → Set
Any P []       = ⊥
Any P (x ∷ xs) = P x ⊕ Any P xs

infix 6 _∈_
_∈_ : {A : Set} → A → List A → Set
z ∈ xs = Any (λ y → z ≡ y) xs

infixr 4 _≈_

_≈_ : {A : Set} → List A → List A → Set
xs ≈ ys = ∀ z → z ∈ xs ↔ z ∈ ys

infix 10 _>>=_

_>>=_ : {A B : Set} → List A → (A → List B) → List B
xs >>= f = concat (map f xs)

⊕-left-identity : {A : Set} → ⊥ ⊕ A ↔ A
⊕-left-identity {A} = record { to      = to'        ;
                               from    = inj₂       ;
                               from-to = from-to'   ;
                               to-from = λ a → refl } where
                                    to' : ⊥ ⊕ A → A
                                    to' (inj₁ b) = ⊥-elim b
                                    to' (inj₂ a) = a
                                    from-to' : (s : ⊥ ⊕ A) → inj₂ (to' s) ≡ s
                                    from-to' (inj₁ b) = ⊥-elim b
                                    from-to' (inj₂ a) = refl

⊕-assoc : {A B C : Set} → A ⊕ (B ⊕ C) ↔ (A ⊕ B) ⊕ C
⊕-assoc {A} {B} {C} = record {to      = to'      ;
                              from    = from'    ;
                              from-to = from-to' ;
                              to-from = to-from' } where
                                  to' : A ⊕ (B ⊕ C) → (A ⊕ B) ⊕ C
                                  to' (inj₁ a)        = inj₁ (inj₁ a)
                                  to' (inj₂ (inj₁ b)) = inj₁ (inj₂ b)
                                  to' (inj₂ (inj₂ c)) = inj₂ c
                                  from' : (A ⊕ B) ⊕ C → A ⊕ (B ⊕ C)
                                  from' (inj₁ (inj₁ a)) = inj₁ a
                                  from' (inj₁ (inj₂ b)) = inj₂ (inj₁ b)
                                  from' (inj₂ c)        = inj₂ (inj₂ c)
                                  from-to' : (x : A ⊕ (B ⊕ C)) → from' (to' x) ≡ x
                                  from-to' (inj₁ _)        = refl
                                  from-to' (inj₂ (inj₁ _)) = refl
                                  from-to' (inj₂ (inj₂ _)) = refl
                                  to-from' : (y : (A ⊕ B) ⊕ C) → to' (from' y) ≡ y
                                  to-from' (inj₁ (inj₁ _)) = refl
                                  to-from' (inj₁ (inj₂ _)) = refl
                                  to-from' (inj₂ _)        = refl

⊕-comm : {A B : Set} → A ⊕ B ↔ B ⊕ A
⊕-comm {A} {B} = record {to      = to'      ;
                         from    = from'    ;
                         from-to = from-to' ;
                         to-from = to-from' } where
                               to' : A ⊕ B → B ⊕ A
                               to' (inj₁ a) = inj₂ a
                               to' (inj₂ b) = inj₁ b
                               from' : B ⊕ A → A ⊕ B
                               from' (inj₁ b) = inj₂ b
                               from' (inj₂ a) = inj₁ a
                               from-to' : (x : A ⊕ B) → from' (to' x) ≡ x
                               from-to' (inj₁ _) = refl
                               from-to' (inj₂ _) = refl
                               to-from' : (x : B ⊕ A) → to' (from' x) ≡ x
                               to-from' (inj₁ _) = refl
                               to-from' (inj₂ _) = refl

⊕-cong : {A₁ A₂ B₁ B₂ : Set} → A₁ ↔ A₂ → B₁ ↔ B₂ → A₁ ⊕ B₁ ↔ A₂ ⊕ B₂
⊕-cong {A₁} {A₂} {B₁} {B₂} A↔ B↔ = record { to = to';
                                            from = from';
                                            from-to = from-to';
                                            to-from = to-from' } where
                                               to' :  A₁ ⊕ B₁ → A₂ ⊕ B₂
                                               to' (inj₁ a) = inj₁ (_↔_.to A↔ a)
                                               to' (inj₂ b) = inj₂ (_↔_.to B↔ b)
                                               from' :  A₂ ⊕ B₂ → A₁ ⊕ B₁
                                               from' (inj₁ a) = inj₁ (_↔_.from A↔ a)
                                               from' (inj₂ b) = inj₂ (_↔_.from B↔ b)
                                               from-to' : (x : A₁ ⊕ B₁) → from' (to' x) ≡ x
                                               from-to' (inj₁ a) = _↔_.from-to A↔ a under inj₁
                                               from-to' (inj₂ b) = _↔_.from-to B↔ b under inj₂
                                               to-from' : (x : A₂ ⊕ B₂) → to' (from' x) ≡ x
                                               to-from' (inj₁ a) = _↔_.to-from A↔ a under inj₁
                                               to-from' (inj₂ b) = _↔_.to-from B↔ b under inj₂

×-cong : {A₁ A₂ B₁ B₂ : Set} → A₁ ↔ A₂ → B₁ ↔ B₂ → (A₁ × B₁) ↔ (A₂ × B₂)
×-cong {A₁} {A₂} {B₁} {B₂} A↔ B↔ = record { to      = to';
                                            from    = from';
                                            from-to = from-to';
                                            to-from = to-from' } where
                                               to'    :  A₁ × B₁ → A₂ × B₂
                                               to'   (a , b) = (_↔_.to A↔ a , _↔_.to B↔ b)
                                               from'  :  A₂ × B₂ → A₁ × B₁
                                               from' (a , b) = (_↔_.from A↔ a , _↔_.from B↔ b)
                                               pairEq : {A B : Set} {x y : A} {u v : B} → x ≡ y → u ≡ v → (x , u) ≡ (y , v)
                                               pairEq refl refl = refl
                                               from-to' : (x : A₁ × B₁) → from' (to' x) ≡ x
                                               from-to' (a , b) = pairEq (_↔_.from-to A↔ a) (_↔_.from-to B↔ b)
                                               to-from' : (y : A₂ × B₂) → to' (from' y) ≡ y
                                               to-from' (a , b) = pairEq (_↔_.to-from A↔ a) (_↔_.to-from B↔ b)

Any-++ : {A : Set} (P : A → Set) (xs ys : List A) → Any P (xs ++ ys) ↔ Any P xs ⊕ Any P ys

Any-++ P [] ys       = Any P ys ↔⟨ ↔sym ⊕-left-identity ⟩
                       ⊥ ⊕ Any P ys □↔

Any-++ P (x ∷ xs) ys = P x ⊕ Any P (xs ++ ys)        ↔⟨ ⊕-cong (P x □↔) (Any-++ P xs ys) ⟩
                       P x ⊕ (Any P xs ⊕ Any P ys)   ↔⟨ ⊕-assoc ⟩
                       (P x ⊕ Any P xs) ⊕ Any P ys   □↔

-- ++-assoc : {A : Set} (xs ys zs : List A) → ((xs ++ ys) ++ zs) ≡ (xs ++ (ys ++ zs))

++-comm : {A : Set} (xs ys : List A) → xs ++ ys ≈ ys ++ xs
++-comm xs ys z = z ∈ (xs ++ ys)      ↔⟨ Any-++ (z ≡_ )  xs ys ⟩
                  z ∈ xs ⊕ z ∈ ys     ↔⟨ ⊕-comm ⟩
                  z ∈ ys ⊕ z ∈ xs     ↔⟨ ↔sym (Any-++ (z ≡_ ) ys xs ) ⟩
                  z ∈ (ys ++ xs)      □↔

Any-concat : {A : Set} (P : A → Set) → (xss : List (List A)) → Any P (concat xss) ↔ Any (Any P) xss
Any-concat P []         = ⊥ □↔
Any-concat P (xs ∷ xss) = Any P (xs ++ concat xss)         ↔⟨ Any-++ P xs (concat xss) ⟩
                          Any P xs ⊕ Any P (concat xss)    ↔⟨ ⊕-cong (Any P xs □↔) (Any-concat P xss) ⟩
                          Any P xs ⊕ Any (Any P) xss       □↔

Any-map : {A B : Set} (P : B → Set) → (f : A → B) → (xs : List A) → Any P (map f xs) ↔ Any (P ∘ f) xs
Any-map P f []       = ⊥ □↔
Any-map P f (x ∷ xs) = P (f x) ⊕ Any P (map f xs) ↔⟨ ⊕-cong (P (f x) □↔) (Any-map P f xs) ⟩
                      (P ∘ f) x ⊕ Any (P ∘ f) xs □↔

Any->>= : {A B : Set} (P : B → Set) → (xs : List A) → (f : A → List B) → Any P (xs >>= f) ↔ Any (Any P ∘ f) xs
Any->>= P xs f = Any P (concat (map f xs))  ↔⟨ Any-concat P (map f xs) ⟩
                 Any (Any P) (map f xs)     ↔⟨ Any-map (Any P) f xs ⟩
                 Any (Any P ∘ f) xs         □↔

Any-∈ : {A : Set} {P : A → Set} {xs : List A} → Any P xs ↔ (∃ λ z → P z × z ∈ xs)
Any-∈ {A} {P} {[]}     = ⊥ ↔⟨ (↔sym ∘ uninhabited) (⊥-elim ∘ proj₂ ∘ proj₂) ⟩
                         (∃ λ z → P z × z ∈ []) □↔
Any-∈ {A} {P} {x ∷ xs} = record {to      = to'      ;
                                   from    = from'    ;
                                   from-to = from-to' ;
                                   to-from = to-from' } where
                                    to' : P x ⊕ Any P xs → ∃ (λ z → P z × z ∈ (x ∷ xs))
                                    to' (inj₁ px)  = x , (px , (inj₁ refl))
                                    to' (inj₂ any) = (proj₁ recEx) , ( (proj₁ ∘ proj₂) recEx , (inj₂ (proj₂ (proj₂ recEx))) ) where
                                           recEx = _↔_.to Any-∈ any
                                    from' : ∃ (λ z → P z × z ∈ (x ∷ xs)) → P x ⊕ Any P xs
                                    from' ex = from'' (proj₁ ex) (proj₁ (proj₂ ex)) (proj₂ (proj₂ ex)) where
                                           from'' : (z : A) → P z → z ∈ (x ∷ xs) → P x ⊕ Any P xs
                                           from'' .x px (inj₁ refl) = inj₁ px
                                           from''  z pz (inj₂ z∈xs) = inj₂ recAny where
                                                recAny = _↔_.from (Any-∈ {P = P}) (z , (pz , z∈xs))
                                    from-to' : (pf : P x ⊕ Any P xs) → from' (to' pf) ≡ pf
                                    from-to' (inj₁ px)  = refl
                                    from-to' (inj₂ any) = _↔_.from-to Any-∈ any under inj₂
                                    to-from' : (ex : ∃ (λ z → P z × z ∈ (x ∷ xs))) → to' (from' ex) ≡ ex
                                    to-from' ex = to-from'' (proj₁ ex) (proj₁ (proj₂ ex)) (proj₂ (proj₂ ex)) where
                                              to-from'' : (z : A) → (pz : P z) → (z∈xxs : z ∈ (x ∷ xs)) →
                                                             to' (from' ( z , ( pz , z∈xxs ))) ≡ ( z , ( pz , z∈xxs ))
                                              to-from'' .x px (inj₁ refl) = refl
                                              to-from''  z pz (inj₂ z∈xs) = _↔_.to-from (Any-∈ {P = P}) (z , ( pz , z∈xs ) )
                                                   under (λ ex → ((proj₁ ex) , ( (proj₁ ∘ proj₂) ex , (inj₂ (proj₂ (proj₂ ex))))))

∃-cong : {A : Set} {P Q : A → Set} → (∀ x → P x ↔ Q x) → (∃ λ x → P x) ↔ (∃ λ x → Q x)
∃-cong p = record {to     = λ ex → proj₁ ex ,  _↔_.to (p (proj₁ ex)) (proj₂ ex);
                   from    = λ ex → proj₁ ex ,  _↔_.from (p (proj₁ ex)) (proj₂ ex);
                   from-to = λ ex → _↔_.from-to (p (proj₁ ex)) (proj₂ ex) under λ pf → (proj₁ ex) , pf;
                   to-from = λ ex → _↔_.to-from (p (proj₁ ex)) (proj₂ ex) under λ pf → (proj₁ ex) , pf }

Any-cong : {A : Set} (P Q : A → Set) → (xs ys : List A) → (∀ x → P x ↔ Q x) → xs ≈ ys → Any P xs ↔ Any Q ys
Any-cong P Q xs ys p eq = Any P xs                   ↔⟨ Any-∈ ⟩
                          (∃ λ z → P z × z ∈ xs)  ↔⟨ ∃-cong (λ x → ×-cong (p x) (eq x)) ⟩
                          (∃ λ z → Q z × z ∈ ys)  ↔⟨ ↔sym Any-∈ ⟩
                          Any Q ys                  □↔

All-cong : {A : Set} {P Q : A → Set} → {xs ys : List A} → (∀ x → P x ↔ Q x) → xs ≈ ys →
                                                   (∀ x → x ∈ xs → P x) ⇔ (∀ y → y ∈ ys → Q y)
All-cong {P} {Q} {xs} {ys} p eq = record {to = λ P∀x y y∈ys → _↔_.to (p y) (P∀x y (_↔_.from (eq y) y∈ys));
                                          from = λ Q∀y x x∈xs → _↔_.from (p x) (Q∀y x (_↔_.to (eq x) x∈xs))}


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties related to All
------------------------------------------------------------------------

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

module Data.Maybe.Relation.Unary.All.Properties where

open import Data.Maybe.Base
open import Data.Maybe.Relation.Unary.All as All
  using (All; nothing; just)
open import Data.Product using (_×_; _,_)
open import Function
open import Relation.Unary

------------------------------------------------------------------------
-- Introduction (⁺) and elimination (⁻) rules for maybe operations
------------------------------------------------------------------------
-- map

module _ {a b p} {A : Set a} {B : Set b} {P : Pred B p} {f : A → B} where

  map⁺ : ∀ {mx} → All (P ∘ f) mx → All P (map f mx)
  map⁺ (just p) = just p
  map⁺ nothing  = nothing

  map⁻ : ∀ {mx} → All P (map f mx) → All (P ∘ f) mx
  map⁻ {just x}  (just px) = just px
  map⁻ {nothing} nothing   = nothing

-- A variant of All.map.

module _ {a b p q} {A : Set a} {B : Set b} {f : A → B}
         {P : Pred A p} {Q : Pred B q} where

  gmap : P ⊆ Q ∘ f → All P ⊆ All Q ∘ map f
  gmap g = map⁺ ∘ All.map g

------------------------------------------------------------------------
-- _<∣>_

module _ {a p} {A : Set a} {P : A → Set p} where

  <∣>⁺ : ∀ {mx my} → All P mx → All P my → All P (mx <∣> my)
  <∣>⁺ (just px) pmy = just px
  <∣>⁺ nothing   pmy = pmy

  <∣>⁻ : ∀ mx {my} → All P (mx <∣> my) → All P mx
  <∣>⁻ (just x) pmxy = pmxy
  <∣>⁻ nothing  pmxy = nothing


{-

This file contains:

- Properties of groupoid truncations

-}
{-# OPTIONS --cubical --safe #-}
module Cubical.HITs.GroupoidTruncation.Properties where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.HITs.GroupoidTruncation.Base

rec : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} (gB : isGroupoid B) → (A → B) → (∥ A ∥₁ → B)
rec gB f ∣ x ∣₁ = f x
rec gB f (squash₁ x y p q r s i j k) =
  gB _ _ _ _
    (λ m n → rec gB f (r m n))
    (λ m n → rec gB f (s m n))
    i j k

elim : ∀ {ℓ ℓ'} {A : Type ℓ} {B : ∥ A ∥₁ → Type ℓ'}
  (bG : (x : ∥ A ∥₁) → isGroupoid (B x))
  (f : (x : A) → B ∣ x ∣₁) (x : ∥ A ∥₁) → B x
elim bG f (∣ x ∣₁) = f x
elim bG f (squash₁ x y p q r s i j k) =
  isOfHLevel→isOfHLevelDep 3 bG _ _ _ _
    (λ j k → elim bG f (r j k)) (λ j k → elim bG f (s j k))
    (squash₁ x y p q r s)
    i j k


open import Data.Product using ( _,_ )
open import Data.Sum using ( inj₁ ; inj₂ )
open import FRP.LTL.ISet.Core using
  ( ISet ; I⟦_⟧ ; M⟦_⟧ ; ⟦_⟧ ; ⌈_⌉ ; splitM⟦_⟧ ; subsumM⟦_⟧ ; i→m ; m→i ) renaming
  ( [_] to [_]′ )
open import FRP.LTL.ISet.Stateless using ( _⇒_ ; _$_ )
open import FRP.LTL.Time.Bound using ( fin ; +∞ ; +∞-top ; ≼-refl ; _≼-trans_ ; _≼-total_ ; _≼-asym_ ; ≺-impl-⋡ )
open import FRP.LTL.Time.Interval using ( ↑ ; [_⟩; _⊑_ ; lb≺ub ; lb≼ ; _,_ ; Int )
open import FRP.LTL.Util using ( ≡-relevant ; ⊥-elim )
open import Relation.Binary.PropositionalEquality using ( refl )
open import Relation.Unary using ( _∈_ )

module FRP.LTL.ISet.Globally where

-- □ A is "A holds globally in the future"

□ : ISet → ISet
□ A = ⌈( λ t → M⟦ A ⟧ (↑ t) )⌉

-- Comonad structure of □

extend : ∀ {A B} → ⟦ A ⇒ B ⟧ → ⟦ □ A ⇒ □ B ⟧
extend {A} {B} f [ [ σ ]′ ]′ =
  [ (λ t t∈i → i→m (λ j j⊑↑t → f [ subsumM⟦ A ⟧ j (↑ t) j⊑↑t (σ t t∈i) ]′)) ]′

extract : ∀ {A} → ⟦ □ A ⇒ A ⟧
extract {A} {[_⟩ {fin s} {t} s≺t} [ [ σ ]′ ]′ =
  m→i (subsumM⟦ A ⟧ [ s≺t ⟩ (↑ s) (≼-refl , +∞-top) (σ s (≼-refl , s≺t)))
extract {A} {[_⟩ {+∞}    {t} ∞≺t} [ [ σ ]′ ]′ =
  ⊥-elim (≺-impl-⋡ ∞≺t +∞-top)

duplicate : ∀ {A} → ⟦ □ A ⇒ □ (□ A) ⟧
duplicate {A} [ [ σ ]′ ]′ =
  [ (λ t t∈i → [ (λ u u∈↑t → subsumM⟦ A ⟧ (↑ u) (↑ t) (lb≼ u∈↑t , ≼-refl) (σ t t∈i)) ]′) ]′

-- Applicative structure of □

[_] : ∀ {A} → ⟦ A ⟧ → ⟦ □ A ⟧
[ σ ] = [ (λ t t∈i → i→m (λ j j⊑↑t → σ)) ]′

_⟨*⟩_ : ∀ {A B} → ⟦ □ (A ⇒ B) ⇒ □ A ⇒ □ B ⟧
[ [ f ]′ ]′ ⟨*⟩ [ [ σ ]′ ]′ =
  [ (λ t t∈i → (f t t∈i) $ (σ t t∈i)) ]′


------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties of pointwise equality for containers
------------------------------------------------------------------------

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

module Data.Container.Relation.Binary.Pointwise.Properties where

open import Axiom.Extensionality.Propositional
open import Data.Container.Core
open import Data.Container.Relation.Binary.Pointwise
open import Data.Product using (_,_; Σ-syntax; -,_)
open import Level using (_⊔_)
open import Relation.Binary
open import Relation.Binary.PropositionalEquality as P
  using (_≡_; subst; cong)

module _ {s p x r} {X : Set x} (C : Container s p) (R : Rel X r) where

  refl : Reflexive R → Reflexive (Pointwise C R)
  refl R-refl = P.refl , λ p → R-refl

  sym : Symmetric R → Symmetric (Pointwise C R)
  sym R-sym (P.refl , f) = P.refl , λ p → R-sym (f p)

  trans : Transitive R → Transitive (Pointwise C R)
  trans R-trans (P.refl , f) (P.refl , g) = P.refl , λ p → R-trans (f p) (g p)

private

  -- Note that, if propositional equality were extensional, then
  -- Eq _≡_ and _≡_ would coincide.

  Eq⇒≡ : ∀ {s p x} {C : Container s p} {X : Set x} {xs ys : ⟦ C ⟧ X} →
         Extensionality p x → Pointwise C _≡_ xs ys → xs ≡ ys
  Eq⇒≡ ext (P.refl , f≈f′) = cong -,_ (ext f≈f′)


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

open import Cubical.Core.Everything

open import Cubical.Data.Prod.Base
open import Cubical.Data.Sigma

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

private
  variable
    ℓ ℓ' : Level
    A : Type ℓ
    B : Type ℓ'

-- Swapping is an equivalence

swap : A × B → B × A
swap (x , y) = (y , x)

swap-invol : (xy : A × B) → swap (swap xy) ≡ xy
swap-invol (_ , _) = refl

isEquivSwap : (A : Type ℓ) (B : Type ℓ') → isEquiv (λ (xy : A × B) → swap xy)
isEquivSwap A B = isoToIsEquiv (iso swap swap swap-invol swap-invol)

swapEquiv : (A : Type ℓ) (B : Type ℓ') → A × B ≃ B × A
swapEquiv A B = (swap , isEquivSwap A B)

swapEq : (A : Type ℓ) (B : Type ℓ') → A × B ≡ B × A
swapEq A B = ua (swapEquiv A B)

private
  open import Cubical.Data.Nat

  -- As × is defined as a datatype this computes as expected
  -- (i.e. "C-c C-n test1" reduces to (2 , 1)). If × is implemented
  -- using Sigma this would be "transp (λ i → swapEq ℕ ℕ i) i0 (1 , 2)"
  test : ℕ × ℕ
  test = transp (λ i → swapEq ℕ ℕ i) i0 (1 , 2)

  testrefl : test ≡ (2 , 1)
  testrefl = refl

-- equivalence between the sigma-based definition and the inductive one
A×B≃A×ΣB : A × B ≃ A ×Σ B
A×B≃A×ΣB = isoToEquiv (iso (λ { (a , b) → (a , b)})
                          (λ { (a , b) → (a , b)})
                          (λ _ → refl)
                          (λ { (a , b) → refl }))

A×B≡A×ΣB : A × B ≡ A ×Σ B
A×B≡A×ΣB = ua A×B≃A×ΣB

swapΣEquiv : (A : Type ℓ) (B : Type ℓ') → A ×Σ B ≃ B ×Σ A
swapΣEquiv A B = compEquiv (compEquiv (invEquiv A×B≃A×ΣB) (swapEquiv A B)) A×B≃A×ΣB

-- truncation for products
isOfHLevelProd : (n : ℕ) → isOfHLevel n A → isOfHLevel n B → isOfHLevel n (A × B)
isOfHLevelProd {A = A} {B = B} n h1 h2 =
  let h : isOfHLevel n (A ×Σ B)
      h = isOfHLevelΣ n h1 (λ _ → h2)
  in transport (λ i → isOfHLevel n (A×B≡A×ΣB {A = A} {B = B} (~ i))) h

×-≃ : ∀ {ℓ₁ ℓ₂ ℓ₃ ℓ₄} {A : Type ℓ₁} {B : Type ℓ₂} {C : Type ℓ₃} {D : Type ℓ₄}
    → A ≃ C → B ≃ D → A × B ≃ C × D
×-≃ {A = A} {B = B} {C = C} {D = D} f g = isoToEquiv (iso φ ψ η ε)
   where
    φ : A × B → C × D
    φ (a , b) = equivFun f a , equivFun g b

    ψ : C × D → A × B
    ψ (c , d) = equivFun (invEquiv f) c , equivFun (invEquiv g) d

    η : section φ ψ
    η (c , d) i = retEq f c i , retEq g d i

    ε : retract φ ψ
    ε (a , b) i = secEq f a i , secEq g b i


open import Formalization.PredicateLogic.Signature

module Formalization.PredicateLogic.Syntax.Tree (𝔏 : Signature) where
open Signature(𝔏)

open import Data.DependentWidthTree as Tree hiding (height)
import      Functional.Dependent
import      Lvl
open import Formalization.PredicateLogic.Syntax(𝔏)
open import Formalization.PredicateLogic.Syntax.Substitution(𝔏)
open import Functional using (_∘_ ; _∘₂_ ; _∘₃_ ; _∘₄_ ; swap ; _←_ ; _on₂_)
open import Numeral.Finite
open import Numeral.Natural.Function.Proofs
open import Numeral.Natural.Inductions
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Proofs
open import Numeral.Natural
open import Relator.Equals
open import Structure.Relator
open import Structure.Relator.Ordering
open import Structure.Relator.Ordering.Proofs
open import Type.Dependent
open import Type

private variable ℓ : Lvl.Level
private variable vars vars₁ vars₂ : ℕ
private variable φ ψ : Formula(vars)

tree : Formula(vars) → FiniteTreeStructure
tree (_ $ _) = Node 0 \()
tree ⊤       = Node 0 \()
tree ⊥       = Node 0 \()
tree (φ ∧ ψ) = Node 2 \{𝟎 → tree φ; (𝐒 𝟎) → tree ψ}
tree (φ ∨ ψ) = Node 2 \{𝟎 → tree φ; (𝐒 𝟎) → tree ψ}
tree (φ ⟶ ψ) = Node 2 \{𝟎 → tree φ; (𝐒 𝟎) → tree ψ}
tree (Ɐ φ)   = Node 1 \{𝟎 → tree φ}
tree (∃ φ)   = Node 1 \{𝟎 → tree φ}

height : Formula(vars) → ℕ
height = Tree.height ∘ tree

-- Ordering on formulas based on the height of their tree representation.
_<↑_ : (Σ ℕ Formula) → (Σ ℕ Formula) → Type
_<↑_ = (_<_) on₂ (height Functional.Dependent.∘ Σ.right)

substitute-height : ∀{t} → (height(substitute{vars₁ = vars₁}{vars₂ = vars₂} t φ) ≡ height φ)
substitute-height {φ = f $ x} = [≡]-intro
substitute-height {φ = ⊤}     = [≡]-intro
substitute-height {φ = ⊥}     = [≡]-intro
substitute-height {φ = φ ∧ ψ} {t} rewrite substitute-height {φ = φ}{t} rewrite substitute-height {φ = ψ}{t} = [≡]-intro
substitute-height {φ = φ ∨ ψ} {t} rewrite substitute-height {φ = φ}{t} rewrite substitute-height {φ = ψ}{t} = [≡]-intro
substitute-height {φ = φ ⟶ ψ} {t} rewrite substitute-height {φ = φ}{t} rewrite substitute-height {φ = ψ}{t} = [≡]-intro
substitute-height {φ = Ɐ φ}   {t} rewrite substitute-height {φ = φ}{termMapper𝐒 t} = [≡]-intro
substitute-height {φ = ∃ φ}   {t} rewrite substitute-height {φ = φ}{termMapper𝐒 t} = [≡]-intro

instance
  [<↑]-wellfounded : Strict.Properties.WellFounded(_<↑_)
  [<↑]-wellfounded = wellfounded-image-by-trans {f = height Functional.Dependent.∘ Σ.right}

induction-on-height : (P : ∀{vars} → Formula(vars) → Type{ℓ}) → (∀{vars}{φ : Formula(vars)} → (∀{vars}{ψ : Formula(vars)} → (height ψ < height φ) → P(ψ)) → P(φ)) → ∀{vars}{φ : Formula(vars)} → P(φ)
induction-on-height P step {vars}{φ} = Strict.Properties.wellfounded-induction(_<↑_) (\{ {intro vars φ} p → step{vars}{φ} \{vars}{ψ} ph → p{intro vars ψ} ⦃ ph ⦄}) {intro vars φ}

⊤-height-order : (height{vars} ⊤ ≤ height φ)
⊤-height-order = [≤]-minimum

⊥-height-order : (height{vars} ⊥ ≤ height φ)
⊥-height-order = [≤]-minimum

∧-height-orderₗ : (height φ < height(φ ∧ ψ))
∧-height-orderₗ = [≤]-with-[𝐒]

∧-height-orderᵣ : (height ψ < height(φ ∧ ψ))
∧-height-orderᵣ = [≤]-with-[𝐒]

∨-height-orderₗ : (height φ < height(φ ∨ ψ))
∨-height-orderₗ = [≤]-with-[𝐒]

∨-height-orderᵣ : (height ψ < height(φ ∨ ψ))
∨-height-orderᵣ = [≤]-with-[𝐒]

⟶-height-orderₗ : (height φ < height(φ ⟶ ψ))
⟶-height-orderₗ = [≤]-with-[𝐒]

⟶-height-orderᵣ : (height ψ < height(φ ⟶ ψ))
⟶-height-orderᵣ = [≤]-with-[𝐒]

Ɐ-height-order : (height φ < height(Ɐ φ))
Ɐ-height-order = [<]-of-[𝐒]

∃-height-order : (height φ < height(∃ φ))
∃-height-order = [<]-of-[𝐒]

-- induction-on-height : ∀{P : ∀{vars} → Formula(vars) → Type{ℓ}} → (∀{vars} → P{vars}(⊤)) → (∀{vars} → P{vars}(⊥)) → ((∀{vars}{ψ : Formula(vars)} → (height ψ < height φ) → P(ψ)) → P(φ)) → P(φ)
-- induction-on-height {φ = φ} base⊤ base⊥ step = step {!Strict.Properties.wellfounded-induction(_<↑_)!}


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

module Fragment.Setoid.Morphism.Properties where

open import Fragment.Setoid.Morphism.Base
open import Fragment.Setoid.Morphism.Setoid

open import Level using (Level)
open import Relation.Binary using (Setoid)

private
  variable
    a b c d ℓ₁ ℓ₂ ℓ₃ ℓ₄ : Level
    A : Setoid a ℓ₁
    B : Setoid b ℓ₂
    C : Setoid c ℓ₃
    D : Setoid d ℓ₄

id-unitˡ : ∀ {f : A ↝ B} → id · f ≗ f
id-unitˡ {B = B} = Setoid.refl B

id-unitʳ : ∀ {f : A ↝ B} → f · id ≗ f
id-unitʳ {B = B} = Setoid.refl B

·-assoc : ∀ (h : C ↝ D) (g : B ↝ C) (f : A ↝ B)
          → (h · g) · f ≗ h · (g · f)
·-assoc {D = D} _ _ _ = Setoid.refl D

·-congˡ : ∀ (h : B ↝ C) (f g : A ↝ B)
          → f ≗ g
          → h · f ≗ h · g
·-congˡ h _ _ f≗g = ∣ h ∣-cong f≗g

·-congʳ : ∀ (h : A ↝ B) (f g : B ↝ C)
          → f ≗ g
          → f · h ≗ g · h
·-congʳ _ _ _ f≗g = f≗g


module Linear where

open import Data.Product
open import Data.Sum
open import Data.Empty

-- 1. PROPOSITIONAL FRAGMENT

infixr 0 _⊸_
infixr 1 _⊕_ _⅋_
infixr 2 _&_ _⊗_

-- Linear propositions consist of a positive part (affirmation, φ₊) and a negative
-- part (refutation, φ₋). We prove a linear proposition by proving its affirmation.
-- If we have a refutation then we cannot have an affirmation, on pain of contra-
-- diction.
data LProp : Set₁ where
  lprop : (φ₊ : Set) → (φ₋ : Set) → (φ₋ → φ₊ → ⊥) → LProp

-- Linear negation exchanges affirmations and refutations.
~ : LProp → LProp
~ (lprop φ₊ φ₋ p) = lprop φ₋ φ₊ (λ a b → p b a)

-- Additive conjunction
_&_ : LProp → LProp → LProp
(lprop φ₊ φ₋ p) & (lprop ψ₊ ψ₋ q) = lprop (φ₊ × ψ₊) (φ₋ ⊎ ψ₋) pq where
  pq : (φ₋ ⊎ ψ₋) → (φ₊ × ψ₊) → ⊥
  pq (inj₁ ~a) (a , b) = p ~a a
  pq (inj₂ ~b) (a , b) = q ~b b

-- Additive disjunction: notice the symmetry between the proofs `pq` between
-- additive conjunctions and additive disjunctions.
_⊕_ : LProp → LProp → LProp
(lprop φ₊ φ₋ p) ⊕ (lprop ψ₊ ψ₋ q) = lprop (φ₋ ⊎ ψ₋) (φ₊ × ψ₊) pq where
  pq : (φ₊ × ψ₊) → (φ₋ ⊎ ψ₋) → ⊥
  pq (a , b) (inj₁ ~a) = p ~a a
  pq (a , b) (inj₂ ~b) = q ~b b

-- Multiplicative conjunction
_⊗_ : LProp → LProp → LProp
(lprop φ₊ φ₋ p) ⊗ (lprop ψ₊ ψ₋ q) = lprop (φ₊ × ψ₊) ((φ₊ → ψ₋) × (ψ₊ → φ₋)) pq where
  pq : ((φ₊ → ψ₋) × (ψ₊ → φ₋)) → (φ₊ × ψ₊) → ⊥
  pq (f , g) (a , b) = q (f a) b

-- Multiplicative disjunction
_⅋_ : LProp → LProp → LProp
(lprop φ₊ φ₋ p) ⅋ (lprop ψ₊ ψ₋ q) = lprop ((ψ₋ → φ₊) × (φ₋ → ψ₊)) (φ₋ × ψ₋) pq where
  pq : (φ₋ × ψ₋) → ((ψ₋ → φ₊) × (φ₋ → ψ₊)) → ⊥
  pq (~a , ~b) (f , g) = q ~b (g ~a)

-- Linear implication
_⊸_ : LProp → LProp → LProp
p ⊸ q = (~ p) ⅋ q

⟦_⟧ : LProp → Set
⟦ lprop φ₊ _ _ ⟧ = φ₊

_⊢_ : LProp → LProp → Set
Γ ⊢ P = ⟦ Γ ⊸ P ⟧

----------
-- Here we prove that these connectives satisfy Hesselink's axioms and rules
-- for the multiplicative fragment of linear logic. See also:
-- W. H. Hesselink: Axioms and models of linear logic, in Formal Aspects of Computing, 1990)

-- Identity axiom.
axiom-1 : (P : LProp) → ⟦ P ⊸ P ⟧
axiom-1 (lprop φ₊ φ₋ p) =
  (λ x → x) ,
  (λ x → x)

-- Commutativity of ⅋.
axiom-2 : (P Q : LProp) → ⟦ (P ⅋ Q) ⊸ (Q ⅋ P) ⟧
axiom-2 (lprop φ₊ φ₋ p) (lprop ψ₊ ψ₋ q) =
  (λ x → proj₂ x , proj₁ x) ,
  (λ x → proj₂ x , proj₁ x)

-- Associativity of ⅋: the proof looks ugly, but we really just re-associate ×.
axiom-3 : (P Q R : LProp) → ⟦ ((P ⅋ Q) ⅋ R) ⊸ (P ⅋ (Q ⅋ R)) ⟧
axiom-3
  (lprop φ₊ φ₋ p)
  (lprop ψ₊ ψ₋ q)
  (lprop ρ₊ ρ₋ r) =
    (λ x → (proj₁ x , proj₁ (proj₂ x)) , proj₂ (proj₂ x)) ,
    (λ x → (λ y → proj₁ (proj₁ x (proj₂ y)) (proj₁ y)) ,
    (λ y → (λ (z : ρ₋) → proj₂ (proj₁ x z) y) ,
    (λ z → proj₂ x (y , z))))

-- Finally, the analogues of the rules of inferece work as expected.
mp-rule : (P Q : LProp) → ⟦ P ⟧ → ⟦ P ⊸ Q ⟧ → ⟦ Q ⟧
mp-rule
  (lprop φ₊ φ₋ p)
  (lprop ψ₊ ψ₋ q) a ab =
    proj₂ ab a

mp-rule-ctx : (Γ P Q : LProp) → ⟦ Γ ⅋ P ⟧ → ⟦ P ⊸ Q ⟧ → ⟦ Γ ⅋ Q ⟧
mp-rule-ctx
  (lprop γ₊ γ₋ g)
  (lprop φ₊ φ₋ p)
  (lprop ψ₊ ψ₋ q) a ab =
    (λ x → proj₁ a (proj₁ ab x)) ,
    (λ x → proj₂ ab (proj₂ a x))

-- A deduction-like variant of the same result.
deduction : (Γ P Q : LProp) → (Γ ⅋ P) ⊢ Q → Γ ⊢ (P ⊸ Q)
deduction
  (lprop γ₊ γ₋ _)
  (lprop φ₊ φ₋ _)
  (lprop ψ₊ ψ₋ _) gpq =
    (λ pq → helper1 (proj₂ pq)) ,
    (λ g → helper2 ,
    (λ p → helper3 (λ _ → g) (λ _ → p))) where
      helper1 : ψ₋ → γ₋
      helper1 x = proj₁ (proj₁ gpq x)
      helper2 : ψ₋ → φ₋
      helper2 x = proj₂ (proj₁ gpq x)
      helper3 : (φ₋ → γ₊) → (γ₋ → φ₊) → ψ₊
      helper3 x y = proj₂ gpq (x , y)

----------
-- Here we prove the involutive property of negation.

open import Relation.Binary.PropositionalEquality

theorem : (P : LProp) → ~ (~ P) ≡ P
theorem (lprop φ₊ φ₋ x) = refl

-- 2. PROPOSITIONAL-EXPONENTIAL FRAGMENT

-- The "of course!" modality
! : LProp → LProp
! (lprop φ₊ φ₋ _) = lprop φ₊ (φ₊ → ⊥) λ z → z

-- The "why not?" modality
⁇ : LProp → LProp
⁇ (lprop φ₊ φ₋ _) = lprop (φ₋ → ⊥) φ₋ λ x y → y x

----------
-- Here we verify that the H-CLL axioms hold for the modalities.

-- A weakening axiom
axiom-1! : (P Q : LProp) → ⟦ P ⊸ (! Q ⊸ P) ⟧
axiom-1!
  (lprop φ₊ φ₋ p)
  (lprop ψ₊ ψ₋ q) =
    proj₂ ,
    λ y → (λ x _ → p x y) , (λ _ → y)

axiom-2! : (P Q : LProp) → ⟦ ! (P ⊸ Q) ⊸ (! P ⊸ ! Q) ⟧
axiom-2!
  (lprop φ₊ φ₋ p)
  (lprop ψ₊ ψ₋ q) =
    (λ x y → proj₂ x (proj₂ y (proj₁ x))) ,
    (λ x → (λ y z → y (proj₂ x z)) , proj₂ x)

axiom-3! : (P : LProp) → ⟦ ! P ⊸ P ⟧
axiom-3! (lprop φ₊ φ₋ p) = p , (λ x → x)

axiom-4! : (P : LProp) → ⟦ ! P ⊸ ! (! P) ⟧
axiom-4! (lprop φ₊ φ₋ p) = (λ x → x) , (λ x → x)

-- A contraction axiom
axiom-5! : (P Q : LProp) → ⟦ (! P ⊸ (! P ⊸ Q)) ⊸ (! P ⊸ Q) ⟧
axiom-5!
  (lprop φ₊ φ₋ p)
  (lprop ψ₊ ψ₋ q) =
  (λ pq → proj₁ pq , proj₁ pq , proj₂ pq) ,
  (λ x → (λ y z → proj₁ x (z , y) z) ,
  (λ y → proj₂ (proj₂ x y) y))

-- Fortunately, the modal inference rule is trivially verified.

modal-rule : (P : LProp) → ⟦ P ⟧ → ⟦ ! P ⟧
modal-rule (lprop φ₊ φ₋ p) x = x


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

open import HoTT

module homotopy.FinWedge where

module _ {i} {I} (X : Fin I → Ptd i) where

  {- the function for cofiber -}
  finwedge-f : Fin I → Σ (Fin I) (de⊙ ∘ X)
  finwedge-f = bigwedge-f X

  FinWedge : Type i
  FinWedge = BigWedge X

  ⊙FinWedge : Ptd i
  ⊙FinWedge = ⊙BigWedge X

module _ {i} {I} {X : Fin I → Ptd i} where

  fwbase : FinWedge X
  fwbase = bwbase

  fwin : (<I : Fin I) → de⊙ (X <I) → FinWedge X
  fwin = bwin

  ⊙fwin : (<I : Fin I) → X <I ⊙→ ⊙FinWedge X
  ⊙fwin = ⊙bwin

  fwglue : (<I : Fin I) → fwbase == fwin <I (pt (X <I))
  fwglue = cfglue

module _ {i} {I} {X : Ptd i} where

  ⊙fwproj-in : Fin I → Fin I → X ⊙→ X
  ⊙fwproj-in = ⊙bwproj-in Fin-has-dec-eq

  module FinWedgeProj (<I : Fin I) = BigWedgeProj Fin-has-dec-eq {X = X} <I

  fwproj : Fin I → FinWedge (λ _ → X) → de⊙ X
  fwproj = FinWedgeProj.f

  ⊙fwproj : Fin I → ⊙FinWedge (λ _ → X) ⊙→ X
  ⊙fwproj <I = fwproj <I , idp

  fwproj-fwin-diag : (<I : Fin I) → fwproj <I ∘ fwin <I ∼ idf (de⊙ X)
  fwproj-fwin-diag <I = bwproj-bwin-diag Fin-has-dec-eq <I

  fwproj-fwin-≠ : ∀ {<I <I'} → <I ≠ <I' → fwproj <I ∘ fwin <I' ∼ cst (pt X)
  fwproj-fwin-≠ = bwproj-bwin-≠ Fin-has-dec-eq

module _ {i₀ i₁} {I} {X₀ : Fin I → Ptd i₀} {X₁ : Fin I → Ptd i₁}
  (Xeq : ∀ <I → X₀ <I ⊙≃ X₁ <I) where

  finwedge-span-emap-r : SpanEquiv (cofiber-span (finwedge-f X₀)) (cofiber-span (finwedge-f X₁))
  finwedge-span-emap-r = bigwedge-span-emap-r Xeq

  FinWedge-emap-r : FinWedge X₀ ≃ FinWedge X₁
  FinWedge-emap-r = BigWedge-emap-r Xeq

  ⊙FinWedge-emap-r : ⊙FinWedge X₀ ⊙≃ ⊙FinWedge X₁
  ⊙FinWedge-emap-r = ⊙BigWedge-emap-r Xeq

module _ {i j} {I} {X : Ptd i} (<I : Fin I) where
  abstract
    fwproj-FinWedge-emap-r-lift :
        fwproj {X = ⊙Lift {j = j} X} <I ∘ –> (FinWedge-emap-r (λ _ → ⊙lift-equiv {j = j}))
      ∼ lift {j = j} ∘ fwproj {X = X} <I
    fwproj-FinWedge-emap-r-lift = bwproj-BigWedge-emap-r-lift Fin-has-dec-eq <I


------------------------------------------------------------------------
-- A definability result: A "closed value" is the semantics of a
-- closed term if and only if it satisfies all "Kripke predicates"
------------------------------------------------------------------------

-- This module is based on parts of Frederik Ramcke's (at the time of
-- writing forthcoming) MSc thesis, "On Definability and Normalization
-- by Evaluation in the Logical Framework". I have not followed
-- Ramcke's development to the letter, but I have taken inspiration
-- from it. Ramcke seems to in turn have taken inspiration from Jung
-- and Tiuryn's "A New Characterization of Lambda Definability".

import Axiom.Extensionality.Propositional as E
open import Level using (Level)
open import Data.Universe

-- The code makes use of the assumption that propositional equality is
-- extensional for functions.

module README.DependentlyTyped.Definability
  (Uni₀ : Universe Level.zero Level.zero)
  (ext : E.Extensionality Level.zero Level.zero)
  where

open import Data.Product as Prod renaming (curry to c)
open import Function.Base hiding (_∋_) renaming (const to k)
open import Function.Equality using (_⟨$⟩_)
open import Function.Equivalence
  using (_⇔_; module Equivalence; equivalence)
open import README.DependentlyTyped.NBE Uni₀ ext
open import README.DependentlyTyped.NormalForm Uni₀
open import README.DependentlyTyped.Term Uni₀
open import Relation.Binary.PropositionalEquality as P using (_≡_)

-- Predicates.

Predicate : Set₁
Predicate = ∀ {Γ σ} → Value Γ σ → Set

private
  variable
    Γ Δ : Ctxt
    Γ₊  : Ctxt₊ Γ
    σ τ : Type Γ
    P   : Predicate

-- Kripke predicates.

record Kripke (P : Predicate) : Set where
  field
    -- Single-step weakening.

    weaken₁ :
      {v : Value Γ σ} →
      P v → P (v /̂Val ŵk[ τ ])

    -- For π-types Kripke predicates have to be defined in a certain
    -- way (up to logical equivalence).

    definition-for-π :
      ∀ {σ τ} {f : Value Γ (Type-π σ τ)} →
      P f
        ⇔
      (∀ (Γ₊ : Ctxt₊ Γ) {v : Value (Γ ++₊ Γ₊) (σ /̂ ŵk₊ Γ₊)} →
         P v → P ((f /̂Val ŵk₊ Γ₊) ˢ v))

  -- Weakening.

  weaken :
    {v : Value Γ σ} (Γ₊ : Ctxt₊ Γ) →
    P v → P (v /̂Val ŵk₊ Γ₊)
  weaken ε        = id
  weaken (σ ◅ Γ₊) = weaken Γ₊ ∘ weaken₁

  -- A "fundamental theorem" for Kripke predicates.

  fundamental :
    {ρ̂ : Γ ⇨̂ Δ} →
    (∀ {σ} (x : Γ ∋ σ) → P (x /̂∋ ρ̂)) →
    (t : Γ ⊢ σ) →
    P (⟦ t ⟧ /̂Val ρ̂)
  fundamental hyp (var x)   = hyp x
  fundamental hyp (t₁ · t₂) =
    (Equivalence.to definition-for-π ⟨$⟩ fundamental hyp t₁)
      ε (fundamental hyp t₂)
  fundamental hyp (ƛ t) =
    Equivalence.from definition-for-π ⟨$⟩ λ Δ₊ p →
      fundamental
        (λ { zero    → p
           ; (suc x) → weaken Δ₊ (hyp x)
           })
        t

  -- A special case for closed terms.

  fundamental-closed : {σ : Type ε} → (t : ε ⊢ σ) → P ⟦ t ⟧
  fundamental-closed = fundamental (λ ())

open Kripke

-- A predicate based on V̌alue.

∃-V̌alue : Predicate
∃-V̌alue {Γ = Γ} {σ = σ} v =
  ∃ λ (v̌ : V̌alue Γ σ) → v ≅-Value ⟦̌ v̌ ⟧

-- ∃-V̌alue is a Kripke predicate.

∃-V̌alue-Kripke : Kripke ∃-V̌alue
weaken₁ ∃-V̌alue-Kripke =
  Prod.map ([_⟶_].function w̌eaken _)
           (λ { P.refl → [_⟶_].corresponds w̌eaken _ _ })
definition-for-π ∃-V̌alue-Kripke {Γ = Γ} {σ = σ} {τ = τ} {f = f} =
  equivalence
    (λ { (f , P.refl) Γ₊ (v , P.refl) →
         proj₁ f Γ₊ v , proj₂ f Γ₊ v
       })
    (λ hyp →
       let
         g : V̌alue-π Γ _ _ (IType-π σ τ)
         g = λ Γ₊ v → proj₁ (hyp Γ₊ (v , P.refl))

         lemma : f ≅-Value ⟦̌ _ ∣ g ⟧-π
         lemma =
           [ f ]                                                    ≡⟨⟩
           [ c ((f /̂Val ŵk₊ (_ ◅ ε)) ˢ ⟦ var zero ⟧n) ]             ≡⟨ curry-cong (ˢ-cong (P.refl {x = [ f /̂Val _ ]})
                                                                                (P.sym $ ňeutral-to-normal-identity _ _)) ⟩
           [ c ((f /̂Val ŵk₊ (_ ◅ ε)) ˢ
                ⟦ ňeutral-to-normal _ (var zero) ⟧n) ]              ≡⟨⟩
           [ c ((f /̂Val ŵk₊ (_ ◅ ε)) ˢ ⟦̌ řeflect _ (var zero) ⟧) ]  ≡⟨ curry-cong (proj₂ (hyp _ _)) ⟩
           [ c ⟦̌ g (_ ◅ ε) (řeflect _ (var zero)) ⟧ ]               ≡⟨ P.sym (unfold-⟦̌∣⟧-π _ g) ⟩
           [ ⟦̌ _ ∣ g ⟧-π ]                                          ∎
       in
         ( g
         , (λ Γ₊ v → [ (⟦̌ _ ∣ g ⟧-π /̂Val ŵk₊ Γ₊) ˢ ⟦̌ v ⟧ ]  ≡⟨ ˢ-cong (/̂Val-cong (P.sym lemma) P.refl) P.refl ⟩
                     [ (f /̂Val ŵk₊ Γ₊) ˢ ⟦̌ v ⟧ ]            ≡⟨ proj₂ (hyp _ _) ⟩
                     [ ⟦̌ g Γ₊ v ⟧ ]                         ∎)
         )
       , lemma
    )
  where
  open P.≡-Reasoning

-- The definability result.

definability :
  {σ : Type ε} {v : Value ε σ} →
  (∃ λ (t : ε ⊢ σ) → v ≡ ⟦ t ⟧)
    ⇔
  ({P : Predicate} → Kripke P → P v)
definability = equivalence
  (λ { (t , P.refl) kripke → fundamental-closed kripke t })
  (λ hyp → Prod.map ([_⟶_].function V̌al-subst.trans _)
                    ≅-Value-⇒-≡
                    (hyp ∃-V̌alue-Kripke))


open import Prelude

module Bij where
  record bij (From To : Set) : Set where
    field
      convert : From → To
      inj     : ∀{f1 f2} → convert f1 == convert f2 → f1 == f2
      surj    : (t : To) → Σ[ f ∈ From ] (convert f == t)

  convert-inv : ∀{F T : Set} {{bijFT : bij F T}} → T → F
  convert-inv {{bijFT}} t with bij.surj bijFT t
  ... | f , _ = f

  convert-inv-inj : ∀{F T : Set} {{bijFT : bij F T}} {t1 t2 : T} →
                      convert-inv {{bijFT}} t1 == convert-inv {{bijFT}} t2 →
                      t1 == t2
  convert-inv-inj ⦃ bijFT = bijFT ⦄ {t1} {t2} eq
    with bij.surj bijFT t1 | bij.surj bijFT t2
  ... | _ , p1 | _ , p2
    rewrite eq = ! p1 · p2

  convert-inv-surj : ∀{F T : Set} {{bijFT : bij F T}} (f : F) →
                       Σ[ t ∈ T ] (convert-inv {{bijFT}} t == f)
  convert-inv-surj ⦃ bijFT = bijFT ⦄ f with expr-eq (λ _ → bij.convert bijFT f)
  ... | t , teq with expr-eq (λ _ → bij.surj bijFT t)
  ... | (_ , seq) , refl = _ , bij.inj bijFT (seq · teq)

  convert-bij1 : ∀{F T : Set} {{bijFT : bij F T}} {f : F} →
                   convert-inv (bij.convert bijFT f) == f
  convert-bij1 ⦃ bijFT = bijFT ⦄ {f} with expr-eq (λ _ → convert-inv-surj f)
  ... | (_ , eq) , refl = eq

  convert-bij2 : ∀{F T : Set} {{bijFT : bij F T}} {t : T} →
                   bij.convert bijFT (convert-inv t) == t
  convert-bij2 ⦃ bijFT = bijFT ⦄ {t} with expr-eq (λ _ → bij.surj bijFT t)
  ... | (_ , eq) , refl = eq


{-# OPTIONS --universe-polymorphism #-}
module Coind where

open import Common.IO
open import Common.Level
open import Common.Nat
open import Common.Unit
open import Common.Coinduction renaming (♯_ to sharp; ♭ to flat)

{-
infix 1000 sharp_

postulate
  Infinity  : ∀ {a} (A : Set a) → Set a
  sharp_ : ∀ {a} {A : Set a} → A → Infinity A
  flat  : ∀ {a} {A : Set a} → Infinity A → A

{-# BUILTIN INFINITY Infinity  #-}
{-# BUILTIN SHARP    sharp_ #-}
{-# BUILTIN FLAT     flat  #-}
-}

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

ones : Stream Nat
ones = 1 :: (sharp ones)

twos : Stream Nat
twos = 2 :: (sharp twos)

incr : Nat -> Stream Nat
incr n = n :: (sharp (incr (n + 1)))

printStream : Nat -> Stream Nat -> IO Unit
printStream zero _ = putStrLn ""
printStream (suc steps) (n :: ns) =
    printNat n ,,
    printStream steps (flat ns)

main : IO Unit
main =
    printStream 10 twos ,,
    printStream 10 ones ,,
    printStream 10 (incr zero)


module Cats.Category.Fun where

open import Cats.Trans public using (Trans ; component ; natural ; id ; _∘_)

open import Relation.Binary using (Rel ; IsEquivalence ; _Preserves₂_⟶_⟶_)
open import Level

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

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

  infixr 4 _≈_

  private
    module C = Category C
    module D = Category D
    open D.≈
    open D.≈-Reasoning

  Obj : Set (lo ⊔ la ⊔ l≈ ⊔ lo′ ⊔ la′ ⊔ l≈′)
  Obj = Functor C D

  _⇒_ : Obj → Obj → Set (lo ⊔ la ⊔ la′ ⊔ l≈′)
  _⇒_ = Trans

  record _≈_ {F G} (θ ι : F ⇒ G) : Set (lo ⊔ l≈′) where
    constructor ≈-intro
    field
      ≈-elim : ∀ {c} → component θ c D.≈ component ι c

  open _≈_ public

  equiv : ∀ {F G} → IsEquivalence (_≈_ {F} {G})
  equiv = record
      { refl = ≈-intro refl
      ; sym = λ eq → ≈-intro (sym (≈-elim eq))
      ; trans = λ eq₁ eq₂ → ≈-intro (trans (≈-elim eq₁) (≈-elim eq₂))
      }

  Fun : Category (lo ⊔ la ⊔ l≈ ⊔ lo′ ⊔ la′ ⊔ l≈′) (lo ⊔ la ⊔ la′ ⊔ l≈′) (lo ⊔ l≈′)
  Fun = record
      { Obj = Obj
      ; _⇒_ = _⇒_
      ; _≈_ = _≈_
      ; id = id
      ; _∘_ = _∘_
      ; equiv = equiv
      ; ∘-resp = λ θ≈θ′ ι≈ι′ → ≈-intro (D.∘-resp (≈-elim θ≈θ′) (≈-elim ι≈ι′))
      ; id-r = ≈-intro D.id-r
      ; id-l = ≈-intro D.id-l
      ; assoc = ≈-intro D.assoc
      }


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

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

module Boolean.Definition where

data Bool : Set where
  BoolTrue : Bool
  BoolFalse : Bool
{-# BUILTIN BOOL  Bool  #-}
{-# BUILTIN TRUE  BoolTrue  #-}
{-# BUILTIN FALSE BoolFalse #-}

if_then_else_ : {a : _} → {A : Set a} → Bool → A → A → A
if BoolTrue then tr else fls = tr
if BoolFalse then tr else fls = fls

not : Bool → Bool
not BoolTrue = BoolFalse
not BoolFalse = BoolTrue

boolAnd : Bool → Bool → Bool
boolAnd BoolTrue y = y
boolAnd BoolFalse y = BoolFalse

boolOr : Bool → Bool → Bool
boolOr BoolTrue y = BoolTrue
boolOr BoolFalse y = y

xor : Bool → Bool → Bool
xor BoolTrue BoolTrue = BoolFalse
xor BoolTrue BoolFalse = BoolTrue
xor BoolFalse b = b


------------------------------------------------------------------------
-- Cyclic groups
------------------------------------------------------------------------

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

import Equality.Path as P

module Group.Cyclic
  {e⁺} (eq : ∀ {a p} → P.Equality-with-paths a p e⁺) where

open P.Derived-definitions-and-properties eq

open import Prelude as P
  hiding (id; _^_) renaming (_∘_ to _⊚_; _+_ to _⊕_)

open import Equality.Path.Isomorphisms eq
open import Equality.Path.Isomorphisms.Univalence eq
open import Equivalence-relation equality-with-J
  using (Is-equivalence-relation)
open import Equivalence equality-with-J using (_≃_)
open import Erased.Cubical eq
open import Function-universe equality-with-J hiding (_∘_)
open import Group equality-with-J as G
  using (Group; Abelian; _≃ᴳ_; Homomorphic)
open import H-level equality-with-J
open import H-level.Closure equality-with-J
open import H-level.Truncation.Propositional eq as T using (∥_∥; ∣_∣)
open import Integer equality-with-J hiding (suc) renaming (_*_ to _⊛_)
import Nat equality-with-J as Nat
open import Quotient eq as Q using (_/_)

open Homomorphic

private
  module ℤG = Group ℤ-group

private
  variable
    a     : Level
    A     : Type a
    g     : A
    G₁ G₂ : Group g
    n     : ℕ
    i j k : ℤ

------------------------------------------------------------------------
-- Cyclic groups

-- The property of being generated by an element.

Generated-by : (G : Group g) → Group.Carrier G → Type g
Generated-by G g =
  (x : Carrier) → ∥ (∃ λ (i : ℤ) → x ≡ g ^ i) ∥
  where
  open Group G

-- The property of being cyclic.

Cyclic : Group g → Type g
Cyclic G = ∥ ∃ (Generated-by G) ∥

-- Cyclic groups are abelian.

Cyclic→Abelian : (G : Group g) → Cyclic G → Abelian G
Cyclic→Abelian G c x y =
  flip (T.rec Carrier-is-set) c          λ (g , gen-by) →
  flip (T.rec Carrier-is-set) (gen-by x) λ (i , x≡) →
  flip (T.rec Carrier-is-set) (gen-by y) λ (j , y≡) →
    x ∘ y          ≡⟨ cong₂ _∘_ x≡ y≡ ⟩
    g ^ i ∘ g ^ j  ≡⟨ ^∘^ i ⟩
    g ^ (i + j)    ≡⟨ cong (g ^_) $ +-comm i ⟩
    g ^ (j + i)    ≡⟨ sym $ ^∘^ j ⟩
    g ^ j ∘ g ^ i  ≡⟨ sym $ cong₂ _∘_ y≡ x≡ ⟩∎
    y ∘ x          ∎
  where
  open Group G

-- If two groups are isomorphic, and one is generated by g, then the
-- other is generated by the image of g under the isomorphism.

≃ᴳ→Generated-by→Generated-by :
  (G₁≃G₂ : G₁ ≃ᴳ G₂) →
  Generated-by G₁ g →
  Generated-by G₂ (to G₁≃G₂ g)
≃ᴳ→Generated-by→Generated-by
  {G₁ = G₁} {G₂ = G₂} {g = g} G₁≃G₂ gen-by x =
  flip T.∥∥-map (gen-by (_≃_.from (G₁≃G₂ .related) x)) λ (i , x≡) →
    i
  , (x                    ≡⟨ sym $ _≃_.from-to (G₁≃G₂ .related) x≡ ⟩
     to G₁≃G₂ (g G₁.^ i)  ≡⟨ G.→ᴳ-^ G₁≃G₂ g i ⟩∎
     to G₁≃G₂ g G₂.^ i    ∎)
  where
  module G₁ = Group G₁
  module G₂ = Group G₂

-- If two groups are isomorphic, and one is cyclic, then the other one
-- is cyclic.

≃ᴳ→Cyclic→Cyclic : G₁ ≃ᴳ G₂ → Cyclic G₁ → Cyclic G₂
≃ᴳ→Cyclic→Cyclic G₁≃G₂ =
  T.∥∥-map λ (_ , gen-by) →
    _ , ≃ᴳ→Generated-by→Generated-by G₁≃G₂ gen-by

------------------------------------------------------------------------
-- The group of integers is cyclic

-- The group of integers is generated by + 1.

ℤ-generated-by-1 : Generated-by ℤ-group (+ 1)
ℤ-generated-by-1 i = ∣ i , sym (*-left-identity i) ∣

-- The group of integers is cyclic.

ℤ-cyclic : Cyclic ℤ-group
ℤ-cyclic = ∣ _ , ℤ-generated-by-1 ∣

------------------------------------------------------------------------
-- The group ℤ × ℤ is not cyclic

-- The direct product of the group of integers and the group of
-- integers is not cyclic.

ℤ×ℤ-not-cyclic : ¬ Cyclic (ℤ-group G.× ℤ-group)
ℤ×ℤ-not-cyclic =
  T.rec ⊥-propositional λ (g , gen-by) →
  flip (T.rec ⊥-propositional) (gen-by (+ 0 , + 1)) λ (i , 0,1≡) →
  flip (T.rec ⊥-propositional) (gen-by (+ 1 , + 0)) λ (j , 1,0≡) →
  lemma₂ g i j (0,1≡ , 1,0≡)
  where
  module G² = Group (ℤ-group G.× ℤ-group)

  0≡*+→≡0 : ∀ n i → + 0 ≡ i *+ P.suc n → i ≡ + 0
  0≡*+→≡0 n i 0≡ = case -⊎0⊎+ i of λ where
    (inj₁ neg)        → ⊥-elim $ ¬-0 (<0→*+suc<0 i n neg) (sym 0≡)
    (inj₂ (inj₁ ≡0))  → ≡0
    (inj₂ (inj₂ pos)) → ⊥-elim $ ¬+0 (>0→*+suc> i n pos) (sym 0≡)

  1≢0* : ∀ i → + 1 ≢ + 0 ⊛ i
  1≢0* i =
    + 1 ≡ + 0 ⊛ i  ↝⟨ flip trans (ℤG.id^ i) ⟩
    + 1 ≡ + 0      ↝⟨ +[1+]≢- ⟩□
    ⊥              □

  -≡0→≡0 : - i ≡ + 0 → i ≡ + 0
  -≡0→≡0 {i = i} hyp =
    i      ≡⟨ sym $ ℤG.involutive _ ⟩
    - - i  ≡⟨ cong -_ hyp ⟩
    - + 0  ≡⟨ ℤG.identity ⟩∎
    + 0    ∎

  lemma₁ :
    ∀ g₁ g₂ i j →
    ¬ ((+ 0 ≡ g₁ ⊛ i × + 1 ≡ g₂ ⊛ i) ×
       (+ 1 ≡ g₁ ⊛ j × + 0 ≡ g₂ ⊛ j))
  lemma₁ _ _ (+ zero) _ =
    (_ × + 1 ≡ + 0) × _  ↝⟨ proj₂ ⊚ proj₁ ⟩
    + 1 ≡ + 0            ↝⟨ +[1+]≢- ⟩□
    ⊥                    □

  lemma₁ g₁ g₂ (+ P.suc m) j =
    (+ 0 ≡ g₁ *+ P.suc m × _) × (+ 1 ≡ g₁ ⊛ j × _)  ↝⟨ Σ-map (0≡*+→≡0 m _ ⊚ proj₁) proj₁ ⟩
    g₁ ≡ + 0 × + 1 ≡ g₁ ⊛ j                         ↝⟨ (λ (p , q) → trans q (cong (_⊛ j) p)) ⟩
    + 1 ≡ (+ 0) ⊛ j                                 ↝⟨ 1≢0* j ⟩□
    ⊥                                               □

  lemma₁ g₁ g₂ -[1+ m ] j =
    (+ 0 ≡ (- g₁) *+ P.suc m × _) × (+ 1 ≡ g₁ ⊛ j × _)  ↝⟨ Σ-map (0≡*+→≡0 m _ ⊚ proj₁) proj₁ ⟩
    - g₁ ≡ + 0 × + 1 ≡ g₁ ⊛ j                           ↝⟨ Σ-map -≡0→≡0 P.id ⟩
    g₁ ≡ + 0 × + 1 ≡ g₁ ⊛ j                             ↝⟨ (λ (p , q) → trans q (cong (_⊛ j) p)) ⟩
    + 1 ≡ (+ 0) ⊛ j                                     ↝⟨ 1≢0* j ⟩□
    ⊥                                                   □

  lemma₂ : ∀ g i j → ¬ ((+ 0 , + 1) ≡ g G².^ i × (+ 1 , + 0) ≡ g G².^ j)
  lemma₂ g@(g₁ , g₂) i j =
    (+ 0 , + 1) ≡ g G².^ i × (+ 1 , + 0) ≡ g G².^ j  ↝⟨ Σ-map (flip trans (G.^-× ℤ-group ℤ-group i))
                                                              (flip trans (G.^-× ℤ-group ℤ-group j)) ⟩
    (+ 0 , + 1) ≡ (g₁ ⊛ i , g₂ ⊛ i) ×
    (+ 1 , + 0) ≡ (g₁ ⊛ j , g₂ ⊛ j)                  ↔⟨ inverse $ ≡×≡↔≡ ×-cong ≡×≡↔≡ ⟩

    (+ 0 ≡ g₁ ⊛ i × + 1 ≡ g₂ ⊛ i) ×
    (+ 1 ≡ g₁ ⊛ j × + 0 ≡ g₂ ⊛ j)                    ↝⟨ lemma₁ g₁ g₂ i j ⟩□

    ⊥                                                □

-- The group of integers is not isomorphic to the direct product of
-- the group of integers and the group of integers.

ℤ≄ᴳℤ×ℤ : ¬ ℤ-group ≃ᴳ (ℤ-group G.× ℤ-group)
ℤ≄ᴳℤ×ℤ =
  ℤ-group ≃ᴳ (ℤ-group G.× ℤ-group)  ↝⟨ flip ≃ᴳ→Cyclic→Cyclic ℤ-cyclic ⟩
  Cyclic (ℤ-group G.× ℤ-group)      ↝⟨ ℤ×ℤ-not-cyclic ⟩□
  ⊥                                 □

-- The group of integers is not equal to the direct product of the
-- group of integers and the group of integers.

ℤ≢ℤ×ℤ : ℤ-group ≢ (ℤ-group G.× ℤ-group)
ℤ≢ℤ×ℤ =
  ℤ-group ≡ (ℤ-group G.× ℤ-group)   ↝⟨ flip (subst (ℤ-group ≃ᴳ_)) G.↝ᴳ-refl ⟩
  ℤ-group ≃ᴳ (ℤ-group G.× ℤ-group)  ↝⟨ ℤ≄ᴳℤ×ℤ ⟩□
  ⊥                                 □

------------------------------------------------------------------------
-- The "equality modulo n" relation

-- Equality modulo n.

infix 4 _≡_mod_

_≡_mod_ : ℤ → ℤ → ℕ → Type
i ≡ j mod n = ∥ (∃ λ k → i ≡ j + k *+ n) ∥

-- The relation _≡_mod n is an equivalence relation.

≡-mod-is-equivalence-relation :
  ∀ n → Is-equivalence-relation (_≡_mod n)
≡-mod-is-equivalence-relation n = λ where
  .Is-equivalence-relation.reflexive {x = i} →
    ∣ + 0
    , (i             ≡⟨ sym +-right-identity ⟩
       i + + 0       ≡⟨ cong (_+_ i) $ sym $ ℤG.id^+ n ⟩∎
       i + + 0 *+ n  ∎)
    ∣
  .Is-equivalence-relation.symmetric {x = i} {y = j} →
    T.∥∥-map λ (k , i≡j+kn) →
        - k
      , (j                        ≡⟨ sym +-right-identity ⟩
         j + + 0                  ≡⟨ cong (_+_ j) $ sym $ +-right-inverse (k *+ n) ⟩
         j + (k *+ n - k *+ n)    ≡⟨ cong (_+_ j) $ cong (_+_ (k *+ n)) $ ℤG.^+⁻¹ n ⟩
         j + (k *+ n + - k *+ n)  ≡⟨ +-assoc j ⟩
         j + k *+ n + - k *+ n    ≡⟨ cong (_+ - k *+ n) $ sym i≡j+kn ⟩∎
         i + - k *+ n             ∎)

  .Is-equivalence-relation.transitive {x = i} {y = j} {z = k} →
    T.rec (Π-closure ext 1 λ _ →
           T.truncation-is-proposition) λ (l₁ , i≡j+l₁n) →
    T.∥∥-map λ (l₂ , j≡k+l₂n) →
        l₂ + l₁
      , (i                        ≡⟨ i≡j+l₁n ⟩
         j + l₁ *+ n              ≡⟨ cong (_+ l₁ *+ n) j≡k+l₂n ⟩
         k + l₂ *+ n + l₁ *+ n    ≡⟨ sym $ +-assoc k ⟩
         k + (l₂ *+ n + l₁ *+ n)  ≡⟨ cong (_+_ k) $ sym $ *+-distrib-+ n ⟩∎
         k + (l₂ + l₁) *+ n       ∎)

-- If i and j are equal modulo n, then i + k and j + k are also equal
-- modulo n.

+-cong : ∀ n j → i ≡ j mod n → i + k ≡ j + k mod n
+-cong {i = i} {k = k} n j = T.∥∥-map λ (l , i≡j+ln) →
    l
  , (i + k             ≡⟨ cong (_+ k) i≡j+ln ⟩
     j + l *+ n + k    ≡⟨ sym $ +-assoc j ⟩
     j + (l *+ n + k)  ≡⟨ cong (_+_ j) $ +-comm (l *+ n) ⟩
     j + (k + l *+ n)  ≡⟨ +-assoc j ⟩∎
     j + k + l *+ n    ∎)

-- If i and j are equal modulo n, then - i and - j are also equal
-- modulo n.

negate-cong : ∀ n j → i ≡ j mod n → - i ≡ - j mod n
negate-cong {i = i} n j = T.∥∥-map λ (k , i≡j+kn) →
    - k
  , (- i               ≡⟨ cong -_ i≡j+kn ⟩
     - (j + k *+ n)    ≡⟨ ℤG.∘⁻¹ {p = j} ⟩
     - (k *+ n) + - j  ≡⟨ +-comm (- (k *+ n)) ⟩
     - j + - (k *+ n)  ≡⟨ cong (_+_ (- j)) $ ℤG.^+⁻¹ n ⟩∎
     - j + - k *+ n    ∎)

-- If i and j are equal modulo n, then i *+ m and j *+ m are equal
-- modulo m * n.

*+-cong : ∀ m → i ≡ j mod n → i *+ m ≡ j *+ m mod m * n
*+-cong {i = i} {j = j} {n = n} m = T.∥∥-map λ (k , i≡j+kn) →
    k
  , (i *+ m                 ≡⟨ cong (_*+ m) i≡j+kn ⟩
     (j + k *+ n) *+ m      ≡⟨ ℤG.∘^+≡^+∘^+ (+-comm j) m ⟩
     j *+ m + k *+ n *+ m   ≡⟨ cong (_+_ (j *+ m)) $ ℤG.^+^+≡^+* n ⟩
     j *+ m + k *+ (n * m)  ≡⟨ cong (_+_ (j *+ m)) $ cong (k *+_) $ Nat.*-comm n ⟩∎
     j *+ m + k *+ (m * n)  ∎)

-- If i and j are equal modulo 2 * n, then ⌊ i /2⌋ and ⌊ j /2⌋ are
-- equal modulo n.

⌊/2⌋-cong : ∀ j n → i ≡ j mod 2 * n → ⌊ i /2⌋ ≡ ⌊ j /2⌋ mod n
⌊/2⌋-cong {i = i} j n = T.∥∥-map λ (k , i≡j+k2n) →
    k
  , (⌊ i /2⌋                  ≡⟨ cong ⌊_/2⌋ i≡j+k2n ⟩
     ⌊ j + k *+ (2 * n) /2⌋   ≡⟨ cong (⌊_/2⌋ ⊚ (_+_ j) ⊚ (k *+_)) $ sym $ Nat.*-comm n ⟩
     ⌊ j + k *+ (n * 2) /2⌋   ≡⟨ cong (⌊_/2⌋ ⊚ (_+_ j)) $ sym $ ℤG.^+^+≡^+* n ⟩
     ⌊ j + (k *+ n) *+ 2 /2⌋  ≡⟨ ⌊+*+2/2⌋≡ j ⟩∎
     ⌊ j /2⌋ + k *+ n         ∎)

-- It is not the case that 0 is equal to 1 modulo n, if n is at least
-- 2.

0≢1mod2+ : ∀ n → ¬ + 0 ≡ + 1 mod 2 ⊕ n
0≢1mod2+ n = T.rec ⊥-propositional $ uncurry lemma
  where
  lemma : ∀ k → + 0 ≢ + 1 + k *+ (2 ⊕ n)
  lemma (+ 0) =
    + 0 ≡ + 1 + + 0 *+ (2 ⊕ n)  ↝⟨ flip trans (cong (_+_ (+ 1)) $ ℤG.id^+ (2 ⊕ n)) ⟩
    + 0 ≡ + 1 + + 0             ↔⟨⟩
    + 0 ≡ + 1                   ↝⟨ +[1+]≢- ⊚ sym ⟩□
    ⊥                           □
  lemma (+ suc k) =
    + 0 ≡ + 1 + + suc k *+ (2 ⊕ n)         ↝⟨ flip ¬+0 ⊚ sym ⟩
    ¬ Positive (+ 1 + + suc k *+ (2 ⊕ n))  ↝⟨ _⊚ >0→>0→+>0 (+ 1) (+ suc k *+ (2 ⊕ n)) _ ⟩
    ¬ Positive (+ suc k *+ (2 ⊕ n))        ↝⟨ _$ >0→*+suc> (+ suc k) (suc n) _ ⟩□
    ⊥                                      □
  lemma -[1+ zero ] =
    + 0 ≡ + 1 + -[1+ 0 ] *+ (2 ⊕ n)             ↝⟨ flip trans (+-assoc (+ 1) {j = -[1+ 0 ]} {k = -[1+ 0 ] *+ (1 ⊕ n)}) ⟩
    + 0 ≡ + 1 + -[1+ 0 ] + -[1+ 0 ] *+ (1 ⊕ n)  ↝⟨ flip trans +-left-identity ⟩
    + 0 ≡ -[1+ 0 ] *+ (1 ⊕ n)                   ↝⟨ flip ¬-0 ⊚ sym ⟩
    ¬ Negative (-[1+ 0 ] *+ (1 ⊕ n))            ↝⟨ _$ <0→*+suc<0 -[1+ 0 ] n _ ⟩□
    ⊥                                           □
  lemma -[1+ suc k ] =
    + 0 ≡ + 1 + -[1+ suc k ] *+ (2 ⊕ n)                 ↝⟨ flip trans (+-assoc (+ 1) {j = -[1+ suc k ]} {k = -[1+ suc k ] *+ (1 ⊕ n)}) ⟩
    + 0 ≡ + 1 + -[1+ suc k ] + -[1+ suc k ] *+ (1 ⊕ n)  ↔⟨⟩
    + 0 ≡ -[1+ k ] + -[1+ suc k ] *+ (1 ⊕ n)            ↝⟨ flip ¬-0 ⊚ sym ⟩
    ¬ Negative (-[1+ k ] + -[1+ suc k ] *+ (1 ⊕ n))     ↝⟨ _⊚ <0→<0→+<0 -[1+ k ] (-[1+ suc k ] *+ (1 ⊕ n)) _ ⟩
    ¬ Negative (-[1+ suc k ] *+ (1 ⊕ n))                ↝⟨ _$ <0→*+suc<0 -[1+ suc k ] n _ ⟩□
    ⊥                                                   □

-- It is not the case that ⌊_/2⌋ distributes over _+_ modulo 2 ⊕ n
-- (for any n).

¬⌊+/2⌋≡⌊/2⌋+⌊/2⌋mod2+ :
  ¬ (∀ i j → ⌊ i + j /2⌋ ≡ ⌊ i /2⌋ + ⌊ j /2⌋ mod 2 ⊕ n)
¬⌊+/2⌋≡⌊/2⌋+⌊/2⌋mod2+ {n = n} =
  (∀ i j → ⌊ i + j /2⌋ ≡ ⌊ i /2⌋ + ⌊ j /2⌋ mod 2 ⊕ n)  ↝⟨ (_$ (+ 1)) ⊚ (_$ (+ 1)) ⟩
  + 1 ≡ + 0 mod 2 ⊕ n                                  ↝⟨ ≡-mod-is-equivalence-relation (2 ⊕ n)
                                                            .Is-equivalence-relation.symmetric ⟩
  + 0 ≡ + 1 mod 2 ⊕ n                                  ↝⟨ 0≢1mod2+ n ⟩□
  ⊥                                                    □

------------------------------------------------------------------------
-- Finite cyclic groups

-- ℤ/[1+ n ]ℤ is the group of integers with addition modulo 1 + n (the
-- finite cyclic group of order 1 + n).

ℤ/[1+_]ℤ : ℕ → Group lzero
ℤ/[1+ n ]ℤ = λ where
    .Group.Carrier        → ℤ / (_≡_mod suc n)
    .Group.Carrier-is-set → Q./-is-set
    .Group._∘_            → _+′_
    .Group.id             → Q.[ + 0 ]
    .Group._⁻¹            → -′_
    .Group.left-identity  → left-identity
    .Group.right-identity → right-identity
    .Group.assoc          → assoc
    .Group.left-inverse   → left-inverse
    .Group.right-inverse  → right-inverse
  where
  _+′_ : ℤ / (_≡_mod suc n) → ℤ / (_≡_mod suc n) → ℤ / (_≡_mod suc n)
  _+′_ = Q.rec λ where
    .Q.[]ʳ i → _+_ i Q./-map λ j₁ j₂ →
      j₁ ≡ j₂ mod suc n            ↝⟨ +-cong (suc n) j₂ ⟩
      j₁ + i ≡ j₂ + i mod suc n    ↝⟨ ≡⇒↝ _ $ cong₂ (_≡_mod suc n) (+-comm j₁) (+-comm j₂) ⟩□
      i + j₁ ≡ i + j₂ mod suc n    □
    .Q.is-setʳ →
      Π-closure ext 2 λ _ →
      Q./-is-set
    .Q.[]-respects-relationʳ {x = i₁} {y = i₂} i₁≡i₂ →
      ⟨ext⟩ $ Q.elim-prop λ where
        .Q.is-propositionʳ _ → Q./-is-set
        .Q.[]ʳ j             →         $⟨ i₁≡i₂ ⟩
          i₁ ≡ i₂ mod suc n            ↝⟨ +-cong (suc n) i₂ ⟩
          i₁ + j ≡ i₂ + j mod suc n    ↝⟨ Q.[]-respects-relation ⟩□
          Q.[ i₁ + j ] ≡ Q.[ i₂ + j ]  □

  -′_ : ℤ / (_≡_mod suc n) → ℤ / (_≡_mod suc n)
  -′_ = -_ Q./-map λ i₁ i₂ →
    i₁ ≡ i₂ mod suc n      ↝⟨ negate-cong (suc n) i₂ ⟩□
    - i₁ ≡ - i₂ mod suc n  □

  left-identity : ∀ i → Q.[ + 0 ] +′ i ≡ i
  left-identity = Q.elim-prop λ where
    .Q.is-propositionʳ _ → Q./-is-set
    .Q.[]ʳ _             → cong Q.[_] +-left-identity

  right-identity : ∀ i → i +′ Q.[ + 0 ] ≡ i
  right-identity = Q.elim-prop λ where
    .Q.is-propositionʳ _ → Q./-is-set
    .Q.[]ʳ _             → cong Q.[_] +-right-identity

  assoc : ∀ i j k → (i +′ (j +′ k)) ≡ ((i +′ j) +′ k)
  assoc = Q.elim-prop λ where
    .Q.is-propositionʳ _ → Π-closure ext 1 λ _ →
                           Π-closure ext 1 λ _ →
                           Q./-is-set
    .Q.[]ʳ i             → Q.elim-prop λ where
      .Q.is-propositionʳ _ → Π-closure ext 1 λ _ →
                             Q./-is-set
      .Q.[]ʳ _             → Q.elim-prop λ where
        .Q.is-propositionʳ _ → Q./-is-set
        .Q.[]ʳ _             → cong Q.[_] $ +-assoc i

  left-inverse : ∀ i → ((-′ i) +′ i) ≡ Q.[ + 0 ]
  left-inverse = Q.elim-prop λ where
    .Q.is-propositionʳ _ → Q./-is-set
    .Q.[]ʳ i             → cong Q.[_] $ +-left-inverse i

  right-inverse : ∀ i → (i +′ (-′ i)) ≡ Q.[ + 0 ]
  right-inverse = Q.elim-prop λ where
    .Q.is-propositionʳ _ → Q./-is-set
    .Q.[]ʳ i             → cong Q.[_] $ +-right-inverse i

-- ℤ/[1+ n ]ℤ is cyclic.

ℤ/ℤ-cyclic : Cyclic ℤ/[1+ n ]ℤ
ℤ/ℤ-cyclic {n = n} =
  ∣ Q.[ + 1 ]
  , (Q.elim-prop λ where
       .Q.is-propositionʳ _ → T.truncation-is-proposition
       .Q.[]ʳ i             →
         ∣ i
         , (Q.[ i ]           ≡⟨ cong Q.[_] $ sym $ *-left-identity i ⟩
            Q.[ + 1 ⊛ i ]     ≡⟨ lemma i ⟩∎
            Q.[ + 1 ] ℤ/.^ i  ∎)
         ∣)
  ∣
  where
  module ℤ/ = Group ℤ/[1+ n ]ℤ

  *+-lemma : ∀ n → Q.[ + 1 *+ n ] ≡ Q.[ + 1 ] ℤ/.^+ n
  *+-lemma zero    = refl _
  *+-lemma (suc n) =
    Q.[ + 1 *+ suc n ]                ≡⟨⟩
    Q.[ + 1 ] ℤ/.∘ Q.[ + 1 *+ n ]     ≡⟨ cong (Q.[ + 1 ] ℤ/.∘_) $ *+-lemma n ⟩∎
    Q.[ + 1 ] ℤ/.∘ Q.[ + 1 ] ℤ/.^+ n  ∎

  lemma : ∀ i → Q.[ + 1 ⊛ i ] ≡ Q.[ + 1 ] ℤ/.^ i
  lemma (+ n)    = *+-lemma n
  lemma -[1+ n ] =
    Q.[ + 1 ⊛ -[1+ n ] ]           ≡⟨⟩
    Q.[ -[ 1 ] *+ suc n ]          ≡⟨ cong Q.[_] $ sym $ ℤG.^+⁻¹ {p = + 1} (suc n) ⟩
    Q.[ - (+ 1 *+ suc n) ]         ≡⟨⟩
    Q.[ + 1 *+ suc n ] ℤ/.⁻¹       ≡⟨ cong ℤ/._⁻¹ $ *+-lemma (suc n) ⟩
    (Q.[ + 1 ] ℤ/.^+ suc n) ℤ/.⁻¹  ≡⟨ ℤ/.^+⁻¹ {p = Q.[ + 1 ]} (suc n) ⟩
    (Q.[ + 1 ] ℤ/.⁻¹) ℤ/.^+ suc n  ≡⟨⟩
    Q.[ + 1 ] ℤ/.^ -[1+ n ]        ∎

-- ℤ/[1+ n ]ℤ is abelian.

ℤ/ℤ-abelian : Abelian ℤ/[1+ n ]ℤ
ℤ/ℤ-abelian = Cyclic→Abelian ℤ/[1+ _ ]ℤ ℤ/ℤ-cyclic

-- For finite cyclic groups of order at least 2 the number 0 is not
-- equal to 1.
--
-- The proof uses propositional extensionality.

ℤ/ℤ-0≢1 :
  ∀ n →
  _≢_ {A = Group.Carrier ℤ/[1+ suc n ]ℤ}
    Q.[ + 0 ] Q.[ + 1 ]
ℤ/ℤ-0≢1 n =
  Stable-¬
    [ Q.[ + 0 ] ≡ Q.[ + 1 ]  ↔⟨ inverse $
                                Q.related≃[equal]
                                  prop-ext
                                  (≡-mod-is-equivalence-relation (2 P.+ n))
                                  T.truncation-is-proposition ⟩
      (+ 0 ≡ + 1 mod 2 ⊕ n)  ↝⟨ 0≢1mod2+ n ⟩□
      ⊥                      □
    ]

-- If any element in ℤ/2ℤ is added to itself we get 0.

private
  module ℤ/2ℤ = Group ℤ/[1+ 1 ]ℤ

ℤ/2ℤ-+≡0 : ∀ i → i ℤ/2ℤ.∘ i ≡ ℤ/2ℤ.id
ℤ/2ℤ-+≡0 = Q.elim-prop λ where
  .Q.is-propositionʳ _ → Q./-is-set
  .Q.[]ʳ i → Q.[]-respects-relation
    ∣ i
    , (i + i          ≡⟨ cong (_+_ i) $ sym +-right-identity ⟩
       i + (i + + 0)  ≡⟨⟩
       i *+ 2         ≡⟨ sym +-left-identity ⟩∎
       + 0 + i *+ 2   ∎)
    ∣


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

open import HoTT

module homotopy.S1SuspensionS0 where

{- To -}

module To = S¹Rec (north Bool) (merid _ false ∙ ! (merid _ true))

to : S¹ → Suspension Bool
to = To.f

{- From -}

from-merid : Bool → base == base
from-merid true = loop
from-merid false = idp

module From = SuspensionRec Bool base base from-merid

from : Suspension Bool → S¹
from = From.f

{- ToFrom and FromTo -}

postulate  -- TODO, easy and boring
  to-from : (x : Suspension Bool) → to (from x) == x
  from-to : (x : S¹) → from (to x) == x

e : S¹ ≃ Suspension Bool
e = equiv to from to-from from-to


------------------------------------------------------------------------------
-- FOCT list terms properties
------------------------------------------------------------------------------

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

module FOTC.Base.List.PropertiesATP where

open import FOTC.Base
open import FOTC.Base.List

------------------------------------------------------------------------------
-- Congruence properties

postulate ∷-leftCong : ∀ {x y xs} → x ≡ y → x ∷ xs ≡ y ∷ xs
{-# ATP prove ∷-leftCong #-}

postulate ∷-rightCong : ∀ {x xs ys} → xs ≡ ys → x ∷ xs ≡ x ∷ ys
{-# ATP prove ∷-rightCong #-}

postulate ∷-Cong : ∀ {x y xs ys} → x ≡ y → xs ≡ ys → x ∷ xs ≡ y ∷ ys
{-# ATP prove ∷-Cong #-}

postulate headCong : ∀ {xs ys} → xs ≡ ys → head₁ xs ≡ head₁ ys
{-# ATP prove headCong #-}

postulate tailCong : ∀ {xs ys} → xs ≡ ys → tail₁ xs ≡ tail₁ ys
{-# ATP prove tailCong #-}

------------------------------------------------------------------------------
-- Injective properties

postulate ∷-injective : ∀ {x y xs ys} → x ∷ xs ≡ y ∷ ys → x ≡ y ∧ xs ≡ ys
{-# ATP prove ∷-injective #-}


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

open import Categories.Category

module Categories.Category.Construction.Properties.Presheaves.Complete {o ℓ e} (C : Category o ℓ e) where

open import Categories.Category.Complete
open import Categories.Category.Complete.Finitely
open import Categories.Category.Complete.Properties
open import Categories.Category.Cocomplete
open import Categories.Category.Cocomplete.Finitely
open import Categories.Category.Cocomplete.Properties
open import Categories.Category.Construction.Presheaves
open import Categories.Category.Instance.Setoids
open import Categories.Category.Instance.Properties.Setoids

private
  module C = Category C

Presheaves-Complete : ∀ o′ ℓ′ e′ ℓ″ e″ → Complete o′ ℓ′ e′ (Presheaves C)
Presheaves-Complete o′ ℓ′ e′ ℓ″ e″ = Functors-Complete C.op (Setoids-Complete o′ ℓ′ e′ ℓ″ e″)

Presheaves-FinitelyComplete : ∀ o′ ℓ′ e′ ℓ″ e″ → FinitelyComplete (Presheaves C)
Presheaves-FinitelyComplete o′ ℓ′ e′ ℓ″ e″ = Complete⇒FinitelyComplete (Presheaves C) (Presheaves-Complete o′ ℓ′ e′ ℓ″ e″)

Presheaves-Cocomplete : ∀ o′ ℓ′ e′ ℓ″ e″ → Cocomplete o′ ℓ′ e′ (Presheaves C)
Presheaves-Cocomplete o′ ℓ′ e′ ℓ″ e″ = Functors-Cocomplete C.op (Setoids-Cocomplete o′ ℓ′ e′ ℓ″ e″)

Presheaves-FinitelyCocomplete : ∀ o′ ℓ′ e′ ℓ″ e″ → FinitelyCocomplete (Presheaves C)
Presheaves-FinitelyCocomplete o′ ℓ′ e′ ℓ″ e″ = Cocomplete⇒FinitelyCocomplete (Presheaves C) (Presheaves-Cocomplete o′ ℓ′ e′ ℓ″ e″)


module Operations.Combinatorial where

open import Data.Bool using (true; false)
import      Data.Bool as B
import      Data.Fin  as F
open import Data.Nat  using (ℕ; suc)
open import Data.Vec  using ([]; _∷_)
import      Data.Vec  as V
open import Relation.Binary.PropositionalEquality

open import Types
open import Eval

not : Closed (𝔹 ⇒ 𝔹)
not = lam (var F.zero refl nand var F.zero refl)

not-prf : ∀ {n} {ctx : Ctx n} {Γ : Env ctx} b → (Γ ⟦ not ⟧) b ≡ B.not b
not-prf true = refl
not-prf false = refl

not⁺ : ∀ n → Closed (𝔹⁺ n ⇒ 𝔹⁺ n)
not⁺ 0 = lam []
not⁺ (suc n) = lam (not ∙ head (var F.zero refl) ∷ not⁺ n ∙ tail (var F.zero refl))

not⁺-prf : ∀ {n m} {ctx : Ctx m} {Γ : Env ctx} bs → (Γ ⟦ not⁺ n ⟧) bs ≡ V.map B.not bs
not⁺-prf [] = refl
not⁺-prf (true ∷ bs) = cong₂ _∷_ refl (not⁺-prf bs)
not⁺-prf (false ∷ bs) = cong₂ _∷_ refl (not⁺-prf bs)

and : Closed (𝔹 ⇒ (𝔹 ⇒ 𝔹))
and = lam (lam (not ∙ ((var (F.suc F.zero) refl) nand (var F.zero refl))))

and-prf : ∀ a b → ([] ⟦ and ⟧) a b ≡ B._∧_ a b
and-prf  true  true = refl
and-prf  true false = refl
and-prf false  true = refl
and-prf false false = refl

and⁺ : ∀ n → Closed (𝔹⁺ n ⇒ (𝔹⁺ n ⇒ 𝔹⁺ n))
and⁺ 0 = lam (lam [])
and⁺ (suc n) = lam (lam (x ∷ xs))
  where
  x  = and    ∙ head (var (F.suc F.zero) refl) ∙ head (var F.zero refl)
  xs = and⁺ n ∙ tail (var (F.suc F.zero) refl) ∙ tail (var F.zero refl)

and⁺-prf : ∀ {n m} {ctx : Ctx m} {Γ : Env ctx} as bs → (Γ ⟦ and⁺ n ⟧) as bs ≡ V.zipWith B._∧_ as bs
and⁺-prf [] [] = refl
and⁺-prf ( true ∷ as) ( true ∷ bs) = cong₂ _∷_ refl (and⁺-prf as bs)
and⁺-prf ( true ∷ as) (false ∷ bs) = cong₂ _∷_ refl (and⁺-prf as bs)
and⁺-prf (false ∷ as) ( true ∷ bs) = cong₂ _∷_ refl (and⁺-prf as bs)
and⁺-prf (false ∷ as) (false ∷ bs) = cong₂ _∷_ refl (and⁺-prf as bs)

or : Closed (𝔹 ⇒ (𝔹 ⇒ 𝔹))
or = lam (lam (l nand r))
  where
  l = ((var (F.suc F.zero) refl) nand (var (F.suc F.zero) refl))
  r = ((var F.zero refl) nand (var F.zero refl))

or-prf : ∀ a b → ([] ⟦ or ⟧) a b ≡ B._∨_ a b
or-prf  true  true = refl
or-prf  true false = refl
or-prf false  true = refl
or-prf false false = refl

or⁺ : ∀ n → Closed (𝔹⁺ n ⇒ (𝔹⁺ n ⇒ 𝔹⁺ n))
or⁺ 0 = lam (lam [])
or⁺ (suc n) = lam (lam (x ∷ xs))
  where
  x  = or    ∙ head (var (F.suc F.zero) refl) ∙ head (var F.zero refl)
  xs = or⁺ n ∙ tail (var (F.suc F.zero) refl) ∙ tail (var F.zero refl)

or⁺-prf : ∀ {n m} {ctx : Ctx m} {Γ : Env ctx} as bs → (Γ ⟦ or⁺ n ⟧) as bs ≡ V.zipWith B._∨_ as bs
or⁺-prf [] [] = refl
or⁺-prf ( true ∷ as) ( true ∷ bs) = cong₂ _∷_ refl (or⁺-prf as bs)
or⁺-prf ( true ∷ as) (false ∷ bs) = cong₂ _∷_ refl (or⁺-prf as bs)
or⁺-prf (false ∷ as) ( true ∷ bs) = cong₂ _∷_ refl (or⁺-prf as bs)
or⁺-prf (false ∷ as) (false ∷ bs) = cong₂ _∷_ refl (or⁺-prf as bs)

xor : Closed (𝔹 ⇒ (𝔹 ⇒ 𝔹))
xor = lam (lam (lam (l nand r) ∙ x))
  where
  x = (var (F.suc F.zero) refl) nand (var F.zero refl)
  l = ((var (F.suc (F.suc F.zero)) refl) nand (var F.zero refl))
  r = ((var F.zero refl) nand (var (F.suc F.zero) refl))

xor-prf : ∀ a b → ([] ⟦ xor ⟧) a b ≡ B._xor_ a b
xor-prf  true  true = refl
xor-prf  true false = refl
xor-prf false  true = refl
xor-prf false false = refl

xor⁺ : ∀ n → Closed (𝔹⁺ n ⇒ (𝔹⁺ n ⇒ 𝔹⁺ n))
xor⁺ 0 = lam (lam [])
xor⁺ (suc n) = lam (lam (x ∷ xs))
  where
  x  = xor    ∙ head (var (F.suc F.zero) refl) ∙ head (var F.zero refl)
  xs = xor⁺ n ∙ tail (var (F.suc F.zero) refl) ∙ tail (var F.zero refl)

xor⁺-prf : ∀ {n m} {ctx : Ctx m} {Γ : Env ctx} as bs → (Γ ⟦ xor⁺ n ⟧) as bs ≡ V.zipWith B._xor_ as bs
xor⁺-prf [] [] = refl
xor⁺-prf ( true ∷ as) ( true ∷ bs) = cong₂ _∷_ refl (xor⁺-prf as bs)
xor⁺-prf ( true ∷ as) (false ∷ bs) = cong₂ _∷_ refl (xor⁺-prf as bs)
xor⁺-prf (false ∷ as) ( true ∷ bs) = cong₂ _∷_ refl (xor⁺-prf as bs)
xor⁺-prf (false ∷ as) (false ∷ bs) = cong₂ _∷_ refl (xor⁺-prf as bs)


module Issue121 where

bad : Set → Set
bad A = A → A

data Bool : Set where
  true  : Bool
  false : Bool

F : Bool → Set → Set
F true  = bad
F false = λ A → A

data D : Set where
  nop : (b : Bool) → F b D → D


module Numeral.Natural.Relation.Order.Classical where

import Lvl
open import Logic.Propositional
open import Numeral.Natural
open import Numeral.Natural.Relation.Order
open import Numeral.Natural.Relation.Order.Decidable
open import Numeral.Natural.Relation.Order.Proofs
open import Relator.Equals
open import Relator.Equals.Proofs
open import Structure.Relator.Properties
open import Relator.Ordering.Proofs
open import Type.Properties.Decidable.Proofs
open import Type

instance
  [≰][>]-sub : (_≰_) ⊆₂ (_>_)
  [≰][>]-sub = From-[≤][<].ByReflTriSub.[≰][>]-sub (_≤_)(_<_) ⦃ [<][≤]-sub = intro(sub₂(_<_)(_≤_)) ⦄ ⦃ [<]-classical = decider-classical _ ⦄

instance
  [≯][≤]-sub : (_≯_) ⊆₂ (_≤_)
  [≯][≤]-sub = From-[≤][<].ByReflTriSub.[≯][≤]-sub (_≤_)(_<_) ⦃ [<][≤]-sub = intro(sub₂(_<_)(_≤_)) ⦄ ⦃ [≤]-classical = decider-classical _ ⦄

instance
  [≱][<]-sub : (_≱_) ⊆₂ (_<_)
  [≱][<]-sub = From-[≤][<].ByReflTriSub.[≱][<]-sub (_≤_)(_<_) ⦃ [<][≤]-sub = intro(sub₂(_<_)(_≤_)) ⦄ ⦃ [<]-classical = decider-classical _ ⦄

instance
  [≮][≥]-sub : (_≮_) ⊆₂ (_≥_)
  [≮][≥]-sub = From-[≤][<].ByReflTriSub.[≮][≥]-sub (_≤_)(_<_) ⦃ [<][≤]-sub = intro(sub₂(_<_)(_≤_)) ⦄ ⦃ [≤]-classical = decider-classical _ ⦄

[≤]-or-[>] : ∀{a b : ℕ} → (a ≤ b) ∨ (a > b)
[≤]-or-[>] = From-[≤][<].ByReflTriSub.[≤]-or-[>] (_≤_)(_<_) ⦃ [<][≤]-sub = intro(sub₂(_<_)(_≤_)) ⦄ ⦃ [≤]-classical = decider-classical _ ⦄ ⦃ [<]-classical = decider-classical _ ⦄

[≥]-or-[<] : ∀{a b : ℕ} → (a ≥ b) ∨ (a < b)
[≥]-or-[<] = From-[≤][<].ByReflTriSub.[≥]-or-[<] (_≤_)(_<_) ⦃ [<][≤]-sub = intro(sub₂(_<_)(_≤_)) ⦄ ⦃ [≤]-classical = decider-classical _ ⦄ ⦃ [<]-classical = decider-classical _ ⦄


{-

This file contains quotient groups

-}
{-# OPTIONS --safe #-}
module Cubical.Algebra.Group.QuotientGroup where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Structure
open import Cubical.Foundations.Powerset
open import Cubical.Foundations.GroupoidLaws hiding (assoc)
open import Cubical.Data.Sigma
open import Cubical.HITs.SetQuotients.Base renaming (_/_ to _/s_)
open import Cubical.HITs.SetQuotients.Properties
open import Cubical.Relation.Binary.Base

open import Cubical.Algebra.Group.Base
open import Cubical.Algebra.Group.Properties
open import Cubical.Algebra.Group.Morphisms
open import Cubical.Algebra.Group.MorphismProperties
open import Cubical.Algebra.Group.Subgroup

private
  variable
    ℓ : Level

module _ (G' : Group ℓ) (H' : Subgroup G') (Hnormal : isNormal H') where

  open BinaryRelation
  open isSubgroup (snd H')
  open GroupStr (snd G')
  open GroupTheory G'
  private
    G = ⟨ G' ⟩

  _~_ : G → G → Type ℓ
  x ~ y = x · inv y ∈ ⟪ H' ⟫

  isRefl~ : isRefl _~_
  isRefl~ x = subst-∈ ⟪ H' ⟫ (sym (·InvR x)) id-closed

  G/H : Type ℓ
  G/H = G /s _~_

  1/H : G/H
  1/H = [ 1g ]

  _·/H_ : G/H → G/H → G/H
  x ·/H y = setQuotBinOp isRefl~ isRefl~ _·_ rem x y
   where
   rem : (a a' b b' : G)
       → a · inv a' ∈ ⟪ H' ⟫
       → b · inv b' ∈ ⟪ H' ⟫
       → (a · b) · inv (a' · b') ∈ ⟪ H' ⟫
   rem a a' b b' haa' hbb' = subst-∈ ⟪ H' ⟫ (cong (_ ·_) (sym (invDistr _ _))) rem5
     where
     rem1 : (inv a' · a) · b · inv b' ∈ ⟪ H' ⟫
     rem1 = ·CommNormalSubgroup H' Hnormal
              (op-closed  hbb' (·CommNormalSubgroup H' Hnormal haa'))

     rem2 : ((inv a' · a) · b) · inv b' ∈ ⟪ H' ⟫
     rem2 = subst-∈ ⟪ H' ⟫ (·Assoc _ _ _) rem1

     rem3 : inv b' · (inv a' · a) · b ∈ ⟪ H' ⟫
     rem3 = ·CommNormalSubgroup H' Hnormal rem2

     rem4 : (inv b' · inv a') · (a · b) ∈ ⟪ H' ⟫
     rem4 = subst-∈ ⟪ H' ⟫ (cong (inv b' ·_) (sym (·Assoc _ _ _)) ∙ ·Assoc _ _ _) rem3

     rem5 : (a · b) · inv b' · inv a' ∈ ⟪ H' ⟫
     rem5 = ·CommNormalSubgroup H' Hnormal rem4

  inv/H : G/H → G/H
  inv/H = setQuotUnaryOp inv rem
    where
    rem : (a a' : G) → a · inv a' ∈ ⟪ H' ⟫ → inv a · inv (inv a') ∈ ⟪ H' ⟫
    rem a a' haa' = subst-∈ ⟪ H' ⟫ (cong (inv a ·_) (sym (invInv a'))) rem1
      where
      ha'a : a' · inv a ∈ ⟪ H' ⟫
      ha'a = subst-∈ ⟪ H' ⟫ (invDistr a (inv a') ∙ cong (_· inv a) (invInv a')) (inv-closed haa')

      rem1 : inv a · a' ∈ ⟪ H' ⟫
      rem1 = ·CommNormalSubgroup H' Hnormal ha'a

  ·/H-assoc : (a b c : G/H) → (a ·/H (b ·/H c)) ≡ ((a ·/H b) ·/H c)
  ·/H-assoc = elimProp3 (λ x y z → squash/ _ _) λ x y z → cong [_] (·Assoc x y z)

  ·/H-rid : (a : G/H) → (a ·/H 1/H) ≡ a
  ·/H-rid = elimProp (λ x → squash/ _ _) λ x → cong [_] (·IdR x)

  ·/H-invr : (a : G/H) → (a ·/H inv/H a) ≡ 1/H
  ·/H-invr = elimProp (λ x → squash/ _ _) λ x → cong [_] (·InvR x)

  asGroup : Group ℓ
  asGroup = makeGroup-right 1/H _·/H_ inv/H squash/ ·/H-assoc ·/H-rid ·/H-invr

_/_ : (G : Group ℓ) → (H : NormalSubgroup G) → Group ℓ
G / H = asGroup G (H .fst) (H .snd)

[_]/G : {G : Group ℓ} {H : NormalSubgroup G} → ⟨ G ⟩ → ⟨ G / H ⟩
[ x ]/G = [ x ]

-- Quotienting by a trivial subgroup
module _ {G' : Group ℓ} (H' : NormalSubgroup G')
         (contrH : (x y : fst G') → _~_ G' (fst H') (snd H') x y → x ≡ y) where
  private
    -- open isSubgroup (snd H')
    open GroupStr (snd G')
    open GroupTheory G'
    G = fst G'
    G/H' = fst (G' / H')

    Code : (g : G) → G/H' → hProp ℓ
    Code g =
      elim (λ _ → isSetHProp)
        (λ a → (g ≡ a) , is-set _ _)
        λ a b r → Σ≡Prop (λ _ → isPropIsProp) (cong (g ≡_) (contrH a b r))

    decode : (g : G) (x : G/H') → [ g ] ≡ x → Code g x .fst
    decode g x = J (λ x _ → Code g x .fst) refl

  trivialRel→elimPath : {g h : G} → Path G/H' [ g ] [ h ] → g ≡ h
  trivialRel→elimPath {g = g} {h = h} = decode g [ h ]

  trivialRelIso : GroupIso G' (G' / H')
  Iso.fun (fst trivialRelIso) g = [ g ]
  Iso.inv (fst trivialRelIso) =
    rec is-set (λ g → g) contrH
  Iso.rightInv (fst trivialRelIso) =
    elimProp (λ _ → squash/ _ _) λ _ → refl
  Iso.leftInv (fst trivialRelIso) _ = refl
  snd trivialRelIso =
    makeIsGroupHom λ _ _ → refl


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

open import HoTT

module homotopy.SuspensionJoin {i} (A : Type i) where

{- To -}

false, : A → Bool × A
false, a = false , a

true, : A → Bool × A
true, a = true , a

module To = SuspensionRec {i} (left false :> Bool * A) (left true) (λ a → glue (false, a) ∙ ! (glue (true, a)))

to : Suspension A → (Bool * A)
to = To.f

{- From -}

from : Bool * A → Suspension A
from = From.f  module _ where

  from-bool : Bool → Suspension A
  from-bool false = north
  from-bool true = south

  from-glue : (c : Bool × A) → from-bool (fst c) == south
  from-glue (false , a) = merid a
  from-glue (true , a) = idp

  module From = PushoutRec {d = *-span Bool A} from-bool (λ _ → south) from-glue

{- ToFrom -}

to-from : (c : Bool * A) → to (from c) == c
to-from = Pushout-elim to-from-left (λ a → glue (true , a)) to-from-glue  where

  to-from-left : (b : Bool) → to (from (left b)) == left b
  to-from-left false = idp
  to-from-left true = idp

  to-from-glue' : (b : Bool) (a : A)
    → ap to (ap from (glue (b , a))) ∙' glue (true , a) == to-from-left b ∙ glue (b , a)
  to-from-glue' true a =
    ap to (ap from (glue (true , a))) ∙' glue (true , a)   =⟨ From.glue-β (true , a) |in-ctx (λ u → ap to u ∙' glue (true , a)) ⟩
    idp ∙' glue (true , a)                                 =⟨ ∙'-unit-l _ ⟩
    glue (true , a) ∎
  to-from-glue' false a =
    ap to (ap from (glue (false , a))) ∙' glue (true , a)   =⟨ From.glue-β (false , a) |in-ctx (λ u → ap to u ∙' glue (true , a)) ⟩
    ap to (merid a) ∙' glue (true , a)   =⟨ To.merid-β a |in-ctx (λ u → u ∙' glue (true , a)) ⟩
    (glue (false , a) ∙ ! (glue (true , a))) ∙' glue (true , a)   =⟨ coh (glue (false , a)) (glue (true , a)) ⟩
    glue (false , a) ∎  where

    coh : ∀ {i} {A : Type i} {a b c : A} (p : a == b) (q : c == b) → (p ∙ ! q) ∙' q == p
    coh idp idp = idp

  to-from-glue : (c : Bool × A)
    → to-from-left (fst c) == glue (true , snd c) [ (λ z → to (from z) == z) ↓ glue c ]
  to-from-glue c = ↓-∘=idf-in to from (uncurry to-from-glue' c)

{- FromTo -}

from-to : (c : Suspension A) → from (to c) == c
from-to = Suspension-elim idp idp from-to-merid  where

  from-to-merid' : (a : A) → ap from (ap to (merid a)) == merid a
  from-to-merid' a =
    ap from (ap to (merid a))   =⟨ To.merid-β a |in-ctx ap from ⟩
    ap from (glue (false , a) ∙ ! (glue (true , a)))   =⟨ ap-∙ from (glue (false , a)) (! (glue (true , a))) ⟩
    ap from (glue (false , a)) ∙ ap from (! (glue (true , a)))   =⟨ ap-! from (glue (true , a)) |in-ctx (λ u → ap from (glue (false , a)) ∙ u) ⟩
    ap from (glue (false , a)) ∙ ! (ap from (glue (true , a)))   =⟨ From.glue-β (false , a) |in-ctx (λ u → u ∙ ! (ap from (glue (true , a)))) ⟩
    merid a ∙ ! (ap from (glue (true , a)))   =⟨ From.glue-β (true , a) |in-ctx (λ u → merid a ∙ ! u) ⟩
    merid a ∙ idp   =⟨ ∙-unit-r _ ⟩
    merid a ∎

  from-to-merid : (a : A) → idp == idp [ (λ z → from (to z) == z) ↓ merid a ]
  from-to-merid a = ↓-∘=idf-in from to (from-to-merid' a)

{- Conclusion -}

e : Suspension A ≃ (Bool * A)
e = equiv to from to-from from-to


{-# OPTIONS --copatterns --sized-types #-}
-- {-# OPTIONS -v tc.size.solve:60 #-}

open import Common.Size
open import Common.Prelude
open import Common.Product

-- Sized streams via head/tail.

record Stream {i : Size} (A : Set) : Set where
  coinductive
  constructor delay
  field
    force : ∀ {j : Size< i} → A × Stream {j} A
open Stream public

_∷ˢ_ : ∀{i A} → A → Stream {i} A → Stream {↑ i} A
force (a ∷ˢ s) = a , s

-- Prepending a list to a stream.

_++ˢ_ : ∀ {i A} → List A → Stream {i} A → Stream {i} A
(a ∷ as) ++ˢ s = a ∷ˢ (as ++ˢ s)
[]       ++ˢ s = s


{-

Equalizer of functions f g : S X ⇉ T X such that f and g act on relation structures

-}
{-# OPTIONS --cubical --no-import-sorts --safe #-}
module Cubical.Structures.Relational.Equalizer where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.RelationalStructure
open import Cubical.Data.Sigma
open import Cubical.HITs.SetQuotients
open import Cubical.HITs.PropositionalTruncation as Trunc
open import Cubical.Relation.Binary.Base

private
  variable
    ℓ ℓ₁ ℓ₁' ℓ₂ ℓ₂' : Level

EqualizerStructure : {S : Type ℓ → Type ℓ₁} {T : Type ℓ → Type ℓ₂}
  (f g : ∀ X → S X → T X)
  → Type ℓ → Type (ℓ-max ℓ₁ ℓ₂)
EqualizerStructure {S = S} f g X = Σ[ s ∈ S X ] f X s ≡ g X s

EqualizerRelStr : {S : Type ℓ → Type ℓ₁} {T : Type ℓ → Type ℓ₂}
  {f g : ∀ X → S X → T X}
  → StrRel S ℓ₁' → StrRel T ℓ₂' → StrRel (EqualizerStructure f g) ℓ₁'
EqualizerRelStr ρ₁ ρ₂ R (s , _) (s' , _) = ρ₁ R s s'

equalizerSuitableRel : {S : Type ℓ → Type ℓ₁} {T : Type ℓ → Type ℓ₂}
  {f g : ∀ X → S X → T X}
  {ρ₁ : StrRel S ℓ₁'} {ρ₂ : StrRel T ℓ₂'}
  (αf : ∀ {X Y} {R : X → Y → Type ℓ} {s s'} → ρ₁ R s s' → ρ₂ R (f X s) (f Y s'))
  (αg : ∀ {X Y} {R : X → Y → Type ℓ} {s s'} → ρ₁ R s s' → ρ₂ R (g X s) (g Y s'))
  → SuitableStrRel S ρ₁
  → SuitableStrRel T ρ₂
  → SuitableStrRel (EqualizerStructure f g) (EqualizerRelStr ρ₁ ρ₂)
equalizerSuitableRel {f = f} {g} {ρ₁} {ρ₂} αf αg θ₁ θ₂ .quo (X , s , p) (R , qer) r =
  ( ((quo₁ .fst .fst , sym step₀ ∙ step₁) , quo₁ .fst .snd)
  , λ {((s' , _) , r') →
    Σ≡Prop (λ _ → θ₁ .prop (λ _ _ → squash/ _ _) _ _)
      (Σ≡Prop (λ _ → θ₂ .set squash/ _ _)
        (cong fst (quo₁ .snd (s' , r'))))}
  )
  where
  quo₁ = θ₁ .quo (X , s) (R , qer) r
  quo₂ = θ₂ .quo (X , f X s) (R , qer) (αf r)

  step₀ : quo₂ .fst .fst ≡ f (X / R .fst) (quo₁ .fst .fst)
  step₀ =
    cong fst
      (quo₂ .snd
        (f _ (quo₁ .fst .fst) , αf (quo₁ .fst .snd)))

  step₁ : quo₂ .fst .fst ≡ g (X / R .fst) (quo₁ .fst .fst)
  step₁ =
    cong fst
      (quo₂ .snd
        ( g _ (quo₁ .fst .fst)
        , subst (λ t → ρ₂ (graphRel [_]) t (g _ (quo₁ .fst .fst))) (sym p) (αg (quo₁ .fst .snd))
        ))
equalizerSuitableRel _ _ θ₁ _ .symmetric R = θ₁ .symmetric R
equalizerSuitableRel _ _ θ₁ _ .transitive R R' = θ₁ .transitive R R'
equalizerSuitableRel _ _ θ₁ θ₂ .set setX =
  isSetΣ (θ₁ .set setX) λ _ → isOfHLevelPath 2 (θ₂ .set setX) _ _
equalizerSuitableRel _ _ θ₁ _ .prop propR _ _ = θ₁ .prop propR _ _


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

open import lib.Basics
open import lib.NType2
open import lib.types.Group
open import lib.types.List
open import lib.types.Pi
open import lib.types.SetQuotient
open import lib.types.Word
open import lib.groups.GeneratedGroup
open import lib.groups.Homomorphism

module lib.groups.GeneratedAbelianGroup {i} {m} where

module GeneratedAbelianGroup (A : Type i) (R : Rel (Word A) m) where

  data AbGroupRel : Word A → Word A → Type (lmax i m) where
    agr-commutes : ∀ l₁ l₂ → AbGroupRel (l₁ ++ l₂) (l₂ ++ l₁)
    agr-rel : ∀ {l₁ l₂} → R l₁ l₂ → AbGroupRel l₁ l₂

  private
    module Gen = GeneratedGroup A AbGroupRel
  open Gen hiding (module HomomorphismEquiv; rel-holds) public

  agr-reverse : (w : Word A) → QuotWordRel (reverse w) w
  agr-reverse nil = qwr-refl idp
  agr-reverse (x :: w) =
    reverse w ++ (x :: nil)
      qwr⟨ qwr-rel (agr-commutes (reverse w) (x :: nil)) ⟩
    x :: reverse w
      qwr⟨ qwr-cong-r (x :: nil) (agr-reverse w) ⟩
    x :: w qwr∎

  GenAbGroup : AbGroup (lmax i m)
  GenAbGroup = grp , grp-is-abelian
    where
    grp : Group (lmax i m)
    grp = GenGroup
    module grp = Group grp
    grp-is-abelian : is-abelian grp
    grp-is-abelian =
      QuotWord-elim {P = λ a → ∀ b → grp.comp a b == grp.comp b a}
        (λ la →
          QuotWord-elim {P = λ b → grp.comp qw[ la ] b == grp.comp b qw[ la ]}
            (λ lb → quot-rel (qwr-rel (agr-commutes la lb)))
            (λ _ → prop-has-all-paths-↓))
        (λ _ → prop-has-all-paths-↓ {{Π-level ⟨⟩}})

  rel-holds : ∀ {w₁} {w₂} (r : R w₁ w₂) → qw[ w₁ ] == qw[ w₂ ]
  rel-holds r = Gen.rel-holds (agr-rel r)

  module GenAbGroup = AbGroup GenAbGroup

  {- Universal Properties -}
  module HomomorphismEquiv {j} (G : AbGroup j) where

    private
      module G = AbGroup G
      module R-RFs = RelationRespectingFunctions A R G.grp
      module AbGroupRel-RFs = RelationRespectingFunctions A AbGroupRel G.grp

    open R-RFs public

    private
      legal-functions-equiv : R-RFs.RelationRespectingFunction
                            ≃ AbGroupRel-RFs.RelationRespectingFunction
      legal-functions-equiv =
        equiv to from
              (λ lf → AbGroupRel-RFs.RelationRespectingFunction= idp)
              (λ lf → R-RFs.RelationRespectingFunction= idp)
        where
        to : R-RFs.RelationRespectingFunction → AbGroupRel-RFs.RelationRespectingFunction
        to (R-RFs.rel-res-fun f respects-R) =
          AbGroupRel-RFs.rel-res-fun f respects-AbGroupRel
          where
          respects-AbGroupRel : AbGroupRel-RFs.respects-rel f
          respects-AbGroupRel (agr-commutes l₁ l₂) =
            Word-extendᴳ G.grp f (l₁ ++ l₂)
              =⟨ Word-extendᴳ-++ G.grp f l₁ l₂ ⟩
            G.comp (Word-extendᴳ G.grp f l₁) (Word-extendᴳ G.grp f l₂)
              =⟨ G.comm (Word-extendᴳ G.grp f l₁) (Word-extendᴳ G.grp f l₂) ⟩
            G.comp (Word-extendᴳ G.grp f l₂) (Word-extendᴳ G.grp f l₁)
              =⟨ ! (Word-extendᴳ-++ G.grp f l₂ l₁) ⟩
            Word-extendᴳ G.grp f (l₂ ++ l₁) =∎
          respects-AbGroupRel (agr-rel r) = respects-R r
        from : AbGroupRel-RFs.RelationRespectingFunction → R-RFs.RelationRespectingFunction
        from (AbGroupRel-RFs.rel-res-fun f respects-AbGroupRel) =
          R-RFs.rel-res-fun f respects-R
          where
          respects-R : R-RFs.respects-rel f
          respects-R r = respects-AbGroupRel (agr-rel r)

    extend-equiv : R-RFs.RelationRespectingFunction ≃ (GenAbGroup.grp →ᴳ G.grp)
    extend-equiv =
      Gen.HomomorphismEquiv.extend-equiv G.grp ∘e legal-functions-equiv

    extend : R-RFs.RelationRespectingFunction → (GenAbGroup.grp →ᴳ G.grp)
    extend = –> extend-equiv


-- Andreas, 2015-06-24

{-# OPTIONS --copatterns #-}

-- {-# OPTIONS -v tc.with.strip:20 #-}

module _ where

open import Common.Equality
open import Common.Product

module SynchronousIO (I O : Set) where

  F : Set → Set
  F S = I → O × S

  record SyncIO : Set₁ where
    field
      St : Set
      tr : St → F St

  module Eq (A₁ A₂ : SyncIO) where

    open SyncIO A₁ renaming (St to S₁; tr to tr₁)
    open SyncIO A₂ renaming (St to S₂; tr to tr₂)

    record BiSim (s₁ : S₁) (s₂ : S₂) : Set where
      coinductive
      field
        force : ∀ (i : I) →
          let (o₁ , t₁) = tr₁ s₁ i
              (o₂ , t₂) = tr₂ s₂ i
          in  o₁ ≡ o₂ × BiSim t₁ t₂

  module Trans (A₁ A₂ A₃ : SyncIO) where

    open SyncIO A₁ renaming (St to S₁; tr to tr₁)
    open SyncIO A₂ renaming (St to S₂; tr to tr₂)
    open SyncIO A₃ renaming (St to S₃; tr to tr₃)

    open Eq A₁ A₂ renaming (BiSim to _₁≅₂_; module BiSim to B₁₂)
    open Eq A₂ A₃ renaming (BiSim to _₂≅₃_; module BiSim to B₂₃)
    open Eq A₁ A₃ renaming (BiSim to _₁≅₃_; module BiSim to B₁₃)

    open B₁₂ renaming (force to force₁₂)
    open B₂₃ renaming (force to force₂₃)
    open B₁₃ renaming (force to force₁₃)

    transitivity : ∀{s₁ s₂ s₃} (p : s₁ ₁≅₂ s₂) (p' : s₂ ₂≅₃ s₃) → s₁ ₁≅₃ s₃
    force₁₃ (transitivity p p') i with force₁₂ p i | force₂₃ p' i
    force₁₃ (transitivity p p') i | (q , r) | (q' , r') = trans q q' , transitivity r r'

-- with-clause stripping failed for projections from module applications
-- should work now


module Tactic.Nat where

open import Prelude
open import Tactic.Nat.Generic (quote _≤_) (quote id) (quote id) public

{-

All tactics know about addition, multiplication and subtraction
of natural numbers, and can prove equalities and inequalities (_<_).
The available tactics are:

  * auto

    Prove an equation or inequality.

  * by eq

    Prove the goal using the given assumption. For equalities it simplifies
    the goal and the assumption and checks if they match any of the following
    forms (up to symmetry):

          a ≡ b → a ≡ b
      a + b ≡ 0 → a ≡ 0

    For inequalities, to prove a < b -> c < d, it simplifies the assumption and
    goal and then tries to prove c′ ≤ a′ and b′ ≤ d′.

    When proving that an inequality follows from an equality a ≡ b, the equality
    is weakened to a ≤ b before applying the above procedure.

    Proving an equality from an inequality works if the inequality simplifies to
    a ≤ 0 (or a < 0 in which case it's trivial). It then reduces that to a ≡ 0
    and tries to prove the goal from that.

  * refute eq

    Proves an arbitrary proposition given a false equation. Works for equations
    that simplify to 0 ≡ suc n (or symmetric) or n < 0, for some n.

  * simplify-goal ?

    Simplify the current goal and let you keep working on the new goal.
    In most cases 'by prf' works better than
    'simplify-goal prf' since it will also simplify prf. The advantage
    of simplify-goal is that it allows holes in prf.

  * simplify eq λ x → ?

    Simplify the given equation (and the current goal) and bind the simplified
    equation to x in the new goal.

  * induction

    Prove a goal ∀ n → P n using induction. Applies 'auto' in the base case
    and 'by IH' in the step case.
-}


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

open import Categories.Category

module Categories.Object.Terminal.Limit {o ℓ e} (C : Category o ℓ e) where

open import Categories.Category.Lift
open import Categories.Category.Finite.Fin.Construction.Discrete
open import Categories.Object.Terminal C
open import Categories.Diagram.Limit
open import Categories.Functor.Core

import Categories.Category.Construction.Cones as Co

private
  module C = Category C
  open C

module _ {o′ ℓ′ e′} {F : Functor (liftC o′ ℓ′ e′ (Discrete 0)) C} where
  limit⇒⊥ : Limit F → Terminal
  limit⇒⊥ L = record
    { ⊤        = apex
    ; !        = rep record
      { apex = record
        { ψ       = λ ()
        ; commute = λ { {()} }
        }
      }
    ; !-unique = λ f → terminal.!-unique record
      { arr     = f
      ; commute = λ { {()} }
      }
    }
    where open Limit L

module _ o′ ℓ′ e′ where

  ⊥⇒limit-F : Functor (liftC o′ ℓ′ e′ (Discrete 0)) C
  ⊥⇒limit-F = record
    { F₀           = λ ()
    ; F₁           = λ { {()} }
    ; identity     = λ { {()} }
    ; homomorphism = λ { {()} }
    ; F-resp-≈     = λ { {()} }
    }

  ⊥⇒limit : Terminal → Limit ⊥⇒limit-F
  ⊥⇒limit t = record
    { terminal = record
      { ⊤        = record
        { N    = ⊤
        ; apex = record
          { ψ       = λ ()
          ; commute = λ { {()} }
          }
        }
      ; !        = λ {K} →
        let open Co.Cone ⊥⇒limit-F K
        in record
        { arr     = !
        ; commute = λ { {()} }
        }
      ; !-unique = λ f →
        let module f = Co.Cone⇒ ⊥⇒limit-F f
        in !-unique f.arr
      }
    }
    where open Terminal t