open import Functional hiding (Domain)
import      Structure.Logic.Classical.NaturalDeduction
import      Structure.Logic.Classical.SetTheory.ZFC

module Structure.Logic.Classical.SetTheory.ZFC.BinaryRelatorSet {ℓₗ} {Formula} {ℓₘₗ} {Proof} {ℓₒ} {Domain} ⦃ classicLogic : _ ⦄ (_∈_ : Domain → Domain → Formula) ⦃ signature : _ ⦄ where
open Structure.Logic.Classical.NaturalDeduction.ClassicalLogic {ℓₗ} {Formula} {ℓₘₗ} {Proof} {ℓₒ} {Domain} (classicLogic)
open Structure.Logic.Classical.SetTheory.ZFC.Signature {ℓₗ} {Formula} {ℓₘₗ} {Proof} {ℓₒ} {Domain} ⦃ classicLogic ⦄ {_∈_} (signature)

open import Structure.Logic.Classical.SetTheory.SetBoundedQuantification ⦃ classicLogic ⦄ (_∈_)

-- Like:
--   (x,f(x)) = (x , y)
--   f = {(x , y)}
--   = {{{x},{x,y}}}
--   ⋃f = {{x},{x,y}}
--   ⋃²f = {x,y}
lefts : Domain → Domain
lefts(s) = filter(⋃(⋃ s)) (x ↦ ∃ₗ(y ↦ (x , y) ∈ s))

rights : Domain → Domain
rights(s) = filter(⋃(⋃ s)) (y ↦ ∃ₗ(x ↦ (x , y) ∈ s))

leftsOfMany : Domain → Domain → Domain
leftsOfMany f(S) = filter(⋃(⋃ f)) (a ↦ ∃ₛ(S)(y ↦ (a , y) ∈ f))

rightsOfMany : Domain → Domain → Domain
rightsOfMany f(S) = filter(⋃(⋃ f)) (a ↦ ∃ₛ(S)(x ↦ (x , a) ∈ f))

leftsOf : Domain → Domain → Domain
leftsOf f(y) = leftsOfMany f(singleton(y))

rightsOf : Domain → Domain → Domain
rightsOf f(x) = rightsOfMany f(singleton(x))

-- swap : Domain → Domain
-- swap(s) = filter(rights(s) ⨯ left(s)) (xy ↦ )


------------------------------------------------------------------------
-- The Agda standard library
--
-- Various forms of induction for natural numbers
------------------------------------------------------------------------

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

module Induction.Nat where

open import Function
open import Data.Nat
open import Data.Nat.Properties using (≤⇒≤′)
open import Data.Fin using (_≺_)
open import Data.Fin.Properties
open import Data.Product
open import Data.Unit
open import Induction
open import Induction.WellFounded as WF
open import Level using (Lift)
open import Relation.Binary.PropositionalEquality
open import Relation.Unary

------------------------------------------------------------------------
-- Ordinary induction

Rec : ∀ ℓ → RecStruct ℕ ℓ ℓ
Rec ℓ P zero    = Lift ℓ ⊤
Rec ℓ P (suc n) = P n

recBuilder : ∀ {ℓ} → RecursorBuilder (Rec ℓ)
recBuilder P f zero    = _
recBuilder P f (suc n) = f n (recBuilder P f n)

rec : ∀ {ℓ} → Recursor (Rec ℓ)
rec = build recBuilder

------------------------------------------------------------------------
-- Complete induction

CRec : ∀ ℓ → RecStruct ℕ ℓ ℓ
CRec ℓ P zero    = Lift ℓ ⊤
CRec ℓ P (suc n) = P n × CRec ℓ P n

cRecBuilder : ∀ {ℓ} → RecursorBuilder (CRec ℓ)
cRecBuilder P f zero    = _
cRecBuilder P f (suc n) = f n ih , ih
  where ih = cRecBuilder P f n

cRec : ∀ {ℓ} → Recursor (CRec ℓ)
cRec = build cRecBuilder

------------------------------------------------------------------------
-- Complete induction based on _<′_

<′-Rec : ∀ {ℓ} → RecStruct ℕ ℓ ℓ
<′-Rec = WfRec _<′_

mutual

  <′-wellFounded : WellFounded _<′_
  <′-wellFounded n = acc (<′-wellFounded′ n)

  <′-wellFounded′ : ∀ n → <′-Rec (Acc _<′_) n
  <′-wellFounded′ zero     _ ()
  <′-wellFounded′ (suc n) .n ≤′-refl       = <′-wellFounded n
  <′-wellFounded′ (suc n)  m (≤′-step m<n) = <′-wellFounded′ n m m<n

module _ {ℓ} where
  open WF.All <′-wellFounded ℓ public
    renaming ( wfRecBuilder to <′-recBuilder
             ; wfRec        to <′-rec
             )
    hiding (wfRec-builder)

------------------------------------------------------------------------
-- Complete induction based on _<_

<-Rec : ∀ {ℓ} → RecStruct ℕ ℓ ℓ
<-Rec = WfRec _<_

<-wellFounded : WellFounded _<_
<-wellFounded = Subrelation.wellFounded ≤⇒≤′ <′-wellFounded

module _ {ℓ} where
  open WF.All <-wellFounded ℓ public
    renaming ( wfRecBuilder to <-recBuilder
             ; wfRec        to <-rec
             )
    hiding (wfRec-builder)

------------------------------------------------------------------------
-- Complete induction based on _≺_

≺-Rec : ∀ {ℓ} → RecStruct ℕ ℓ ℓ
≺-Rec = WfRec _≺_

≺-wellFounded : WellFounded _≺_
≺-wellFounded = Subrelation.wellFounded ≺⇒<′ <′-wellFounded

module _ {ℓ} where
  open WF.All ≺-wellFounded ℓ public
    renaming ( wfRecBuilder to ≺-recBuilder
             ; wfRec        to ≺-rec
             )
    hiding (wfRec-builder)

------------------------------------------------------------------------
-- Examples

private

 module Examples where

  -- Doubles its input.

  twice : ℕ → ℕ
  twice = rec _ λ
    { zero    _       → zero
    ; (suc n) twice-n → suc (suc twice-n)
    }

  -- Halves its input (rounding downwards).
  --
  -- The step function is mentioned in a proof below, so it has been
  -- given a name. (The mutual keyword is used to avoid having to give
  -- a type signature for the step function.)

  mutual

    half₁-step = λ
      { zero          _                → zero
      ; (suc zero)    _                → zero
      ; (suc (suc n)) (_ , half₁n , _) → suc half₁n
      }

    half₁ : ℕ → ℕ
    half₁ = cRec _ half₁-step

  -- An alternative implementation of half₁.

  mutual

    half₂-step = λ
      { zero          _   → zero
      ; (suc zero)    _   → zero
      ; (suc (suc n)) rec → suc (rec n (≤′-step ≤′-refl))
      }

    half₂ : ℕ → ℕ
    half₂ = <′-rec _ half₂-step

  -- The application half₁ (2 + n) is definitionally equal to
  -- 1 + half₁ n. Perhaps it is instructive to see why.

  half₁-2+ : ∀ n → half₁ (2 + n) ≡ 1 + half₁ n
  half₁-2+ n = begin

    half₁ (2 + n)                                                         ≡⟨⟩

    cRec _ half₁-step (2 + n)                                             ≡⟨⟩

    half₁-step (2 + n) (cRecBuilder _ half₁-step (2 + n))                 ≡⟨⟩

    half₁-step (2 + n)
      (let ih = cRecBuilder _ half₁-step (1 + n) in
       half₁-step (1 + n) ih , ih)                                        ≡⟨⟩

    half₁-step (2 + n)
      (let ih = cRecBuilder _ half₁-step n in
       half₁-step (1 + n) (half₁-step n ih , ih) , half₁-step n ih , ih)  ≡⟨⟩

    1 + half₁-step n (cRecBuilder _ half₁-step n)                         ≡⟨⟩

    1 + cRec _ half₁-step n                                               ≡⟨⟩

    1 + half₁ n                                                           ∎

    where open ≡-Reasoning

  -- The application half₂ (2 + n) is definitionally equal to
  -- 1 + half₂ n. Perhaps it is instructive to see why.

  half₂-2+ : ∀ n → half₂ (2 + n) ≡ 1 + half₂ n
  half₂-2+ n = begin

    half₂ (2 + n)                                               ≡⟨⟩

    <′-rec _ half₂-step (2 + n)                                 ≡⟨⟩

    half₂-step (2 + n) (<′-recBuilder _ half₂-step (2 + n))     ≡⟨⟩

    1 + <′-recBuilder _ half₂-step (2 + n) n (≤′-step ≤′-refl)  ≡⟨⟩

    1 + Some.wfRecBuilder _ half₂-step (2 + n)
          (<′-wellFounded (2 + n)) n (≤′-step ≤′-refl)          ≡⟨⟩

    1 + Some.wfRecBuilder _ half₂-step (2 + n)
          (acc (<′-wellFounded′ (2 + n))) n (≤′-step ≤′-refl)   ≡⟨⟩

    1 + half₂-step n
          (Some.wfRecBuilder _ half₂-step n
             (<′-wellFounded′ (2 + n) n (≤′-step ≤′-refl)))     ≡⟨⟩

    1 + half₂-step n
          (Some.wfRecBuilder _ half₂-step n
             (<′-wellFounded′ (1 + n) n ≤′-refl))               ≡⟨⟩

    1 + half₂-step n
          (Some.wfRecBuilder _ half₂-step n (<′-wellFounded n)) ≡⟨⟩

    1 + half₂-step n (<′-recBuilder _ half₂-step n)             ≡⟨⟩

    1 + <′-rec _ half₂-step n                                   ≡⟨⟩

    1 + half₂ n                                                 ∎

    where open ≡-Reasoning

  -- Some properties that the functions above satisfy, proved using
  -- cRec.

  half₁-+₁ : ∀ n → half₁ (twice n) ≡ n
  half₁-+₁ = cRec _ λ
    { zero          _                        → refl
    ; (suc zero)    _                        → refl
    ; (suc (suc n)) (_ , half₁twice-n≡n , _) →
        cong (suc ∘ suc) half₁twice-n≡n
    }

  half₂-+₁ : ∀ n → half₂ (twice n) ≡ n
  half₂-+₁ = cRec _ λ
    { zero          _                        → refl
    ; (suc zero)    _                        → refl
    ; (suc (suc n)) (_ , half₁twice-n≡n , _) →
        cong (suc ∘ suc) half₁twice-n≡n
    }

  -- Some properties that the functions above satisfy, proved using
  -- <′-rec.

  half₁-+₂ : ∀ n → half₁ (twice n) ≡ n
  half₁-+₂ = <′-rec _ λ
    { zero          _   → refl
    ; (suc zero)    _   → refl
    ; (suc (suc n)) rec →
        cong (suc ∘ suc) (rec n (≤′-step ≤′-refl))
    }

  half₂-+₂ : ∀ n → half₂ (twice n) ≡ n
  half₂-+₂ = <′-rec _ λ
    { zero          _   → refl
    ; (suc zero)    _   → refl
    ; (suc (suc n)) rec →
        cong (suc ∘ suc) (rec n (≤′-step ≤′-refl))
    }

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

-- Version 0.15

rec-builder      = recBuilder
{-# WARNING_ON_USAGE rec-builder
"Warning: rec-builder was deprecated in v0.15.
Please use recBuilder instead."
#-}
cRec-builder     = cRecBuilder
{-# WARNING_ON_USAGE cRec-builder
"Warning: cRec-builder was deprecated in v0.15.
Please use cRecBuilder instead."
#-}
<′-rec-builder   = <′-recBuilder
{-# WARNING_ON_USAGE <′-rec-builder
"Warning: <′-rec-builder was deprecated in v0.15.
Please use <′-recBuilder instead."
#-}
<-rec-builder    = <-recBuilder
{-# WARNING_ON_USAGE <-rec-builder
"Warning: <-rec-builder was deprecated in v0.15.
Please use <-recBuilder instead."
#-}
≺-rec-builder    = ≺-recBuilder
{-# WARNING_ON_USAGE ≺-rec-builder
"Warning: ≺-rec-builder was deprecated in v0.15.
Please use ≺-recBuilder instead."
#-}
<′-well-founded  = <′-wellFounded
{-# WARNING_ON_USAGE <′-well-founded
"Warning: <′-well-founded was deprecated in v0.15.
Please use <′-wellFounded instead."
#-}
<′-well-founded′ = <′-wellFounded′
{-# WARNING_ON_USAGE <′-well-founded′
"Warning: <′-well-founded′ was deprecated in v0.15.
Please use <′-wellFounded′ instead."
#-}
<-well-founded   = <-wellFounded
{-# WARNING_ON_USAGE <-well-founded
"Warning: <-well-founded was deprecated in v0.15.
Please use <-wellFounded instead."
#-}
≺-well-founded   = ≺-wellFounded
{-# WARNING_ON_USAGE ≺-well-founded
"Warning: ≺-well-founded was deprecated in v0.15.
Please use ≺-wellFounded instead."
#-}


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

module Categories.Morphism.Universal where

open import Level
open import Categories.Category
open import Categories.Category.Construction.Comma
open import Categories.Functor
open import Categories.Object.Initial

record UniversalMorphism {o ℓ e o′ ℓ′ e′} {C : Category o ℓ e} {D : Category o′ ℓ′ e′}
                         (X : Category.Obj C) (F : Functor D C) : Set (e ⊔ ℓ ⊔ o′ ⊔ ℓ′ ⊔ e′) where
  X↙F : Category _ _ _
  X↙F = X ↙ F

  private
    module X↙F = Category X↙F

  field
    initial : Initial X↙F

  module initial = Initial initial
  open initial public


module Issue252 where

data I : Set where
  zero : I

data D : I → Set where
  c : ∀ i → D i → D i

id : I → I
id i = i

index : ∀ i → D i → I
index i _ = i

foo : ∀ i → D i → D zero
foo .i (c i d) with id i
foo ._ (c i d) | zero = d

bar : ∀ i → D i → D zero
bar .i (c i d) with index i d
bar ._ (c i d) | zero = d

-- In the context of the first goal d has type D i′, in the second it
-- has type D i. Well, not any more.


{-# OPTIONS --without-K #-}
module hott.equivalence.biinvertible where

open import sum
open import equality
open import function.core
open import function.isomorphism.core
open import function.isomorphism.utils
open import function.overloading
open import function.extensionality
open import hott.level.core
open import hott.level.closure
open import hott.equivalence.core
open import hott.equivalence.alternative
open import sets.unit

module _ {i j}{X : Set i}{Y : Set j} where
  InvL : (X → Y) → Set _
  InvL f = Σ (Y → X) λ g → (x : X) → g (f x) ≡ x

  InvR : (X → Y) → Set _
  InvR f = Σ (Y → X) λ g → (y : Y) → f (g y) ≡ y

  BiInv : (X → Y) → Set _
  BiInv f = InvL f × InvR f

_≈₂_ : ∀ {i j} → Set i → Set j → Set _
X ≈₂ Y = Σ (X → Y) BiInv

module _ {i j}{X : Set i}{Y : Set j} where
  ≅⇒b : X ≅ Y → X ≈₂ Y
  ≅⇒b f = apply f , (invert f , _≅_.iso₁ f) , (invert f , _≅_.iso₂ f)

  b⇒≅ : X ≈₂ Y → X ≅ Y
  b⇒≅ (f , (g , α) , (h , β)) = record
    { to = f
    ; from = g
    ; iso₁ = α
    ; iso₂ = λ y → sym (ap (f ∘' g) (β y)) · ap f (α (h y)) · β y }

  module _ (isom : X ≅ Y) where
    private
      f : X → Y
      f = apply isom

      φ : ∀ {k} (Z : Set k) → (X → Z) ≅ (Y → Z)
      φ Z = record
        { to = λ u → u ∘ invert isom
        ; from = λ v → v ∘ f
        ; iso₁ = λ u → funext λ x → ap u (_≅_.iso₁ isom x)
        ; iso₂ = λ v → funext λ y → ap v (_≅_.iso₂ isom y) }

    invl-level : contr (InvL f)
    invl-level = iso-level (Σ-ap-iso refl≅ λ g → sym≅ strong-funext-iso)
                           (proj₂ (≅⇒≈ (sym≅ (φ X))) id)

    private
      ψ : ∀ {k} (Z : Set k) → (Z → X) ≅ (Z → Y)
      ψ Z = record
        { to = λ u → f ∘ u
        ; from = λ v → invert isom ∘ v
        ; iso₁ = λ u → funext λ x → _≅_.iso₁ isom (u x)
        ; iso₂ = λ v → funext λ y → _≅_.iso₂ isom (v y) }

    invr-level : contr (InvR f)
    invr-level = iso-level (Σ-ap-iso refl≅ λ h → sym≅ strong-funext-iso)
                           (proj₂ (≅⇒≈ (ψ Y)) id)

  BiInv-level : (f : X → Y) → h 1 (BiInv f)
  BiInv-level f b₁ b₂ = h↑ (×-contr (invl-level isom) (invr-level isom)) b₁ b₂
    where
      isom : X ≅ Y
      isom = b⇒≅ (f , b₁)

  b⇔≈ : (X ≈₂ Y) ≅ (X ≈ Y)
  b⇔≈ = record
    { to = λ b → ≅⇒≈ (b⇒≅ b)
    ; from = λ φ → (≅⇒b (≈⇒≅ φ))
    ; iso₁ = λ { (f , b) → ap (λ b → f , b) (h1⇒prop (BiInv-level f) _ _) }
    ; iso₂ = λ { (f , e) → ap (λ e → f , e) (h1⇒prop (weak-equiv-h1 f) _ _) } }


-- Andreas, May - July 2016, implementing postfix projections

module Issue1963 where

module Prod where

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

  open Σ

  test : ∀{A} → A → Σ A λ _ → A
  test = λ where
    x .fst → x
    x .snd → x

module Stream where

  record Stream (A : Set) : Set where
    coinductive
    field head : A
          tail : Stream A

  open Stream

  repeat : ∀{A} (a : A) → Stream A
  repeat a .head = a
  repeat a. tail = repeat a

  zipWith : ∀{A B C} (f : A → B → C) (s : Stream A) (t : Stream B) → Stream C
  zipWith f s t .head = f (s .head) (t .head)
  zipWith f s t .tail = zipWith f (s .tail) (t .tail)

  module Fib (Nat : Set) (zero one : Nat) (plus : Nat → Nat → Nat) where

    {-# TERMINATING #-}
    fib : Stream Nat
    fib .head = zero
    fib .tail .head = one
    fib .tail .tail = zipWith plus fib (fib .tail)


open import Agda.Builtin.Size

postulate
  X : Set
  P : X → Set
  Q : (x : X) → P x → Set

data D (i : Size) : Set where
  c : D i

f : (i : Size) → D i → X
f i c = {!!}

g : (x : X) (y : P x) → Q x y → Q x y
g _ _ q = q

h : (i : Size) (n : D i) → P (f i n)
h _ c = {!!}

k : (n : D ∞) → Q (f ∞ n) (h ∞ n)
k _ = g _ (h _ {!!}) _


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

open import Level hiding (lift)
open import Data.Product

open import Categories.Category
open import Categories.Functor hiding (_∘_; _≡_)
open import Categories.Morphism.Cartesian
import Categories.Morphisms as Morphisms

record CartesianLifting {o₀ ℓ₀ e₀} {o₁ ℓ₁ e₁} {E : Category o₀ ℓ₀ e₀} {B : Category o₁ ℓ₁ e₁}
                        (p : Functor E B) {a e} (f : B [ a , Functor.F₀ p e ]) : Set (o₀ ⊔ ℓ₀ ⊔ e₀ ⊔ o₁ ⊔ ℓ₁ ⊔ e₁) where
  private module E = Category E
  private module B = Category B
  open B using (_∘_; _≡_)

  open Functor p renaming (F₀ to p₀; F₁ to p₁)
  open Morphisms B

  field
    e′ : E.Obj

    φ : E [ e′ , e ]
    proof : ∃ \ (h : a ≅ p₀ e′) → f ∘ _≅_.g h ≡ p₁ φ
    φ-cartesian : Cartesian p φ

record Fibration {o₀ ℓ₀ e₀} {o₁ ℓ₁ e₁} (E : Category o₀ ℓ₀ e₀) (B : Category o₁ ℓ₁ e₁) : Set (o₀ ⊔ ℓ₀ ⊔ e₀ ⊔ o₁ ⊔ ℓ₁ ⊔ e₁) where
  private module E = Category E
  private module B = Category B
  open B using (_∘_; _≡_)

  field
    p : Functor E B

  open Functor p renaming (F₀ to p₀; F₁ to p₁)

  open Morphisms B

  field
    lift : ∀ {a} e → (f : B [ a  , p₀ e ]) → CartesianLifting p f


{-# OPTIONS --type-in-type #-}  -- yes, I will let you cheat in this exercise
{-# OPTIONS --allow-unsolved-metas #-}  -- allows import, unfinished

------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- CS410 2017/18 Exercise 2  CATEGORIES AND MONADS (worth 25%)
------------------------------------------------------------------------------
------------------------------------------------------------------------------

-- NOTE (19/10/17)  This file is currently incomplete: more will arrive on
-- GitHub.

-- NOTE (29/10/17)  All components are now present.

------------------------------------------------------------------------------
-- Dependencies
------------------------------------------------------------------------------

open import CS410-Prelude
open import CS410-Categories
open import Ex1

------------------------------------------------------------------------------
-- Categorical Jigsaws (based on Ex1)
------------------------------------------------------------------------------

OPE : Category            -- The category of order-preserving embeddings...
OPE = record
  { Obj          = Nat    -- ...has numbers as objects...
  ; _~>_         = _<=_   -- ...and "thinnings" as arrows.
  ; id~>         = oi
  ; _>~>_        = _o>>_
  ; law-id~>>~>  = idThen-o>>
  ; law->~>id~>  = idAfter-o>>
  ; law->~>>~>   = assoc-o>>
  }

VEC : Nat -> SET => SET                -- Vectors of length n...
VEC n = record
  { F-Obj       = \ X -> Vec X n       -- ...give a functor from SET to SET...
  ; F-map       = \ f xs -> vMap f xs  -- ...doing vMap to arrows.

  -- Now prove the laws.
  ; F-map-id~>  = extensionality \ xs -> {!!}
  ; F-map->~>   = \ f g -> extensionality \ xs -> {!!}
  }

Op : Category -> Category             -- Every category has an opposite...
Op C = record
  { Obj          = Obj                -- ...with the same objects, but...
  ; _~>_         = \ S T -> T ~> S    -- ...arrows that go backwards!
                                      -- Now, find the rest!
  ; id~>         = id~>
  ; _>~>_        = \ f g -> g >~> f
  ; law-id~>>~>  = law->~>id~>
  ; law->~>id~>  = law-id~>>~>
  ; law->~>>~>   = {!!}
  } where open Category C

CHOOSE : Set -> OPE => Op SET    -- Show that thinnings from n to m...
CHOOSE X = record                -- ...act by selection...
  { F-Obj       = Vec X          -- ...to cut vectors down from m to n.
  ; F-map       = {!!}
  ; F-map-id~>  = extensionality {!!}
  ; F-map->~>   = \ f g -> extensionality {!!}
  }

--??--------------------------------------------------------------------------

------------------------------------------------------------------------------
-- The List Monad (a warm-up)
------------------------------------------------------------------------------

-- The declaration of List has been added to the CS410-Prelude file:

-- data List (X : Set) : Set where
--   []   : List X
--   _,-_ : (x : X)(xs : List X) -> List X
-- infixr 4 _,-_

-- Appending two lists is rather well known, so I'll not ask you to write it.

_+L_ : {X : Set} -> List X -> List X -> List X
[]        +L ys = ys
(x ,- xs) +L ys = x ,- (xs +L ys)
infixr 4 _+L_

-- But I will ask you to find some structure for it.

--??--2.2---------------------------------------------------------------------

LIST-MONOID : Set -> Category
LIST-MONOID X =            -- Show that _+L_ is the operation of a monoid,...
  record
  { Obj          = One     -- ... i.e., a category with one object.
  ; _~>_         = {!!}
  ; id~>         = {!!}
  ; _>~>_        = {!!}
  ; law-id~>>~>  = {!!}
  ; law->~>id~>  = {!!}
  ; law->~>>~>   = {!!}
  } where
  -- useful helper proofs (lemmas) go here

--??--------------------------------------------------------------------------

-- Next, functoriality of lists. Given a function on elements, show how to
-- apply that function to all the elements of a list. (Haskell calls this
-- operation "map".)

--??--2.3---------------------------------------------------------------------

list : {X Y : Set} -> (X -> Y) -> List X -> List Y
list f xs = {!!}

LIST : SET => SET
LIST = record
  { F-Obj       = List
  ; F-map       = list
  ; F-map-id~>  = extensionality {!!}
  ; F-map->~>   = \ f g -> extensionality {!!}
  } where
  -- useful helper proofs (lemmas) go here

--??--------------------------------------------------------------------------

-- Moreover, applying a function elementwise should respect appending.

--??--2.4---------------------------------------------------------------------

LIST+L : {X Y : Set}(f : X -> Y) -> LIST-MONOID X => LIST-MONOID Y
LIST+L {X}{Y} f = record
  { F-Obj       = id
  ; F-map       = list f -- this yellow will go once LIST-MONOID has arrows!
  ; F-map-id~>  = {!!}
  ; F-map->~>   = {!!}
  } where
  -- useful helper proofs (lemmas) go here

--??--------------------------------------------------------------------------

-- Next, we have two very important "natural transformations".

--??--2.5---------------------------------------------------------------------

SINGLE : ID ~~> LIST
SINGLE = record
  { xf          = \ x -> x ,- []      -- turn a value into a singleton list
  ; naturality  = \ f -> {!!}
  }

--??--------------------------------------------------------------------------

-- Here, naturality means that it doesn't matter
-- whether you apply a function f, then make a singleton list
-- or you make a singleton list, then apply f to all (one of) its elements.

-- Now, define the operation that concatenates a whole list of lists, and
-- show that it, too, is natural. That is, it doesn't matter whether you
-- transform the elements (two layers inside) then concatenate, or you
-- concatenate, then transform the elements.

--??--2.6---------------------------------------------------------------------

concat : {X : Set} -> List (List X) -> List X
concat xss = {!!}

CONCAT : (LIST >=> LIST) ~~> LIST
CONCAT = record
  { xf          = concat
  ; naturality  = {!!}
  } where
  -- useful helper proofs (lemmas) go here

--??--------------------------------------------------------------------------

-- You've nearly built your first monad! You just need to prove that
-- single and concat play nicely with each other.

--??--2.7---------------------------------------------------------------------

module LIST-MONAD where
  open MONAD LIST public
  ListMonad : Monad
  ListMonad = record
    { unit      = SINGLE
    ; mult      = CONCAT
    ; unitMult  = {!!}
    ; multUnit  = {!!}
    ; multMult  = {!!}
    } where
    -- useful helper proofs (lemmas) go here

-- open LIST-MONAD

--??--------------------------------------------------------------------------

-- More monads to come...

------------------------------------------------------------------------------
-- Categories of Indexed Sets
------------------------------------------------------------------------------

-- We can think of some
--   P : I -> Set
-- as a collection of sets indexed by I, such that
--   P i
-- means "exactly the P-things which fit with i".

-- You've met
--   Vec X : Nat -> Set
-- where
--   Vec X n
-- means "exactly the vectors which fit with n".

-- Now, given two such collections, S and T, we can make a collection
-- of function types: the functions which fit with i map the
-- S-things which fit with i to the T-things which fit with i.

_-:>_ : {I : Set} -> (I -> Set) -> (I -> Set) -> (I -> Set)
(S -:> T) i = S i -> T i

-- So, (Vec X -:> Vec Y) n contains the functions which turn
-- n Xs into n Ys.

-- Next, if we know such a collection of sets, we can claim to have
-- one for each index.

[_] : {I : Set} -> (I -> Set) -> Set
[ P ] = forall i -> P i    -- [_] {I} P = (i : I) -> P i

-- E.g., [ Vec X -:> Vec Y ] is the type of functions from X-vectors
-- to Y-vectors which preserve length.

-- For any such I, we get a category of indexed sets with index-preserving
-- functions.

_->SET : Set -> Category
I ->SET = record
  { Obj    = I -> Set                 -- I-indexed sets
  ; _~>_   = \ S T -> [ S -:> T ]     -- index-respecting functions
  ; id~>   = \ i -> id                -- the identity at every index
  ; _>~>_  = \ f g i -> f i >> g i    -- composition at every index
  ; law-id~>>~> = refl                -- and the laws are very boring
  ; law->~>id~> = refl
  ; law->~>>~>  = \ f g h -> refl _
  }

-- In fact, we didn't need to choose SET here. We could do this construction
-- for any category: index the objects; index the morphisms.
-- But SET is plenty to be getting on with.

-- Now, let me define an operation that makes types from lists.

All : {X : Set} -> (X -> Set) -> (List X -> Set)
All P [] = One
All P (x ,- xs) = P x * All P xs

-- The idea is that we get a tuple of P-things: one for each list element.
-- So
--     All P (1 ,- 2 ,- 3 ,- [])
--   = P 1 * P 2 * P 3 * One

-- Note that if you think of List One as a version of Nat,
-- All becomes a lot like Vec.

copy : Nat -> List One
copy zero = []
copy (suc n) = <> ,- copy n

VecCopy : Set -> Nat -> Set
VecCopy X n = All (\ _ -> X) (copy n)

-- Now, your turn...

--??--2.8---------------------------------------------------------------------

-- Show that, for any X, All induces a functor
-- from (X ->SET) to (List X ->SET)

all : {X : Set}{S T : X -> Set} ->
      [ S -:> T ] -> [ All S -:> All T ]
all f xs ss = {!!}

ALL : (X : Set) -> (X ->SET) => (List X ->SET)
ALL X = record
  { F-Obj      = All
  ; F-map      = all
  ; F-map-id~> = {!!}
  ; F-map->~>  = {!!}
  } where
  -- useful helper facts go here

--??--------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Cutting Things Up
------------------------------------------------------------------------------

-- Next, we're going to develop a very general technique for building
-- data structures.

-- We may think of an I |> O as a way to "cut O-shapes into I-shaped pieces".
-- The pointy end points to the type being cut; the flat end to the type of
-- pieces.

record _|>_ (I O : Set) : Set where
  field
    Cuts   : O -> Set                      -- given o : O, how may we cut it?
    inners : {o : O} -> Cuts o -> List I   -- given how we cut it, what are
                                           --   the shapes of its pieces?

-- Let us have some examples right away!

VecCut : One |> Nat              -- cut numbers into boring pieces
VecCut = record
  { Cuts = \ n -> One            -- there is one way to cut n
  ; inners = \ {n} _ -> copy n   -- and you get n pieces
  }

-- Here's a less boring example. You can cut a number into *two* pieces
-- by finding two numbers that add to it.

NatCut : Nat |> Nat
NatCut = record
  { Cuts = \ mn -> Sg Nat \ m -> Sg Nat \ n -> (m +N n) == mn
  ; inners = \ { (m , n , _) -> m ,- n ,- [] }
  }

-- The point is that we can make data structures that record how we
-- built an O-shaped thing from I-shaped pieces.

record Cutting {I O}(C : I |> O)(P : I -> Set)(o : O) : Set where
  constructor _8><_               -- "scissors"
  open _|>_ C
  field
    cut     : Cuts o              -- we decide how to cut o
    pieces  : All P (inners cut)  -- then we give all the pieces.
infixr 3 _8><_

-- For example...

VecCutting : Set -> Nat -> Set
VecCutting X = Cutting VecCut (\ _ -> X)

myVecCutting : VecCutting Char 5
myVecCutting = <> 8>< 'h' , 'e' , 'l' , 'l' , 'o' , <>

-- Or, if you let me fiddle about with strings for a moment,...
length : {X : Set} -> List X -> Nat
length [] = zero
length (x ,- xs) = suc (length xs)

listVec : {X : Set}(xs : List X) -> Vec X (length xs)
listVec [] = []
listVec (x ,- xs) = x ,- listVec xs

strVec : (s : String) -> Vec Char (length (primStringToList s))
strVec s = listVec (primStringToList s)

-- ...an example of cutting a number in two, with vector pieces.

footprints : Cutting NatCut (Vec Char) 10
footprints = (4 , 6 , refl 10) 8>< strVec "foot"
                                 , strVec "prints"
                                 , <>

-- Now, let me direct you to the =$ operator, now in CS410-Prelude.agda,
-- which you may find helps with the proofs in the following.

--??--2.9---------------------------------------------------------------------

-- Using what you already built for ALL, show that every Cutting C gives us
-- a functor between categories of indexed sets.

CUTTING : {I O : Set}(C : I |> O) -> (I ->SET) => (O ->SET)
CUTTING {I}{O} C = record
  { F-Obj = Cutting C
  ; F-map = {!!}
  ; F-map-id~> = extensionality \ o -> extensionality \ { (c 8>< ps) ->
     {!!} }
  ; F-map->~> = \ f g ->
     extensionality \ o -> extensionality \ { (c 8>< ps) ->
     {!!} }
  } where
  open _|>_ C
  open _=>_ (ALL I)

--??--------------------------------------------------------------------------

------------------------------------------------------------------------------
-- Interiors
------------------------------------------------------------------------------

-- Next, let me define the notion of an algebra for a given functor in C => C

module ALGEBRA {C : Category}(F : C => C) where
  open Category C
  open _=>_ F

  Algebra : (X : Obj) -> Set   -- we call X the "carrier" of the algebra...
  Algebra X = F-Obj X ~> X     -- ...and we explain how to turn a bunch of Xs
                               -- into one
open ALGEBRA

-- Some week, we'll build categories whose objects are algebras. Not this week.

-- Instead, let's work with them a bit.

-- If we know a way to cut I-shapes into I-shaped pieces, we can build the
-- ways to "tile" an I with I-shaped T-tiles.

data Interior {I}(C : I |> I)(T : I -> Set)(i : I) : Set where
                                         -- either...
  tile : T i -> Interior C T i           -- we have a tile that fits, or...
  <_>  : Cutting C (Interior C T) i ->   -- ...we cut, then tile the pieces.
         Interior C T i

-- Let me give you an example of an interior.

subbookkeeper : Interior NatCut (Vec Char) 13
subbookkeeper = < (3 , 10 , refl _)
                  8>< tile (strVec "sub")
                    , < (4 , 6 , refl _)
                        8>< tile (strVec "book")
                          , tile (strVec "keeper")
                          , <> >
                    , <> >

-- We make a 13-interior from
-- a 3-tile and a 10-interior made from a 4-tile and a 6-tile.

-- Guess what? Interior C is always a Monad! We'll get there.

module INTERIOR {I : Set}{C : I |> I} where  -- fix some C...

  open _|>_ C                                -- ...and open it

  open module I->SET {I : Set} = Category (I ->SET)  -- work in I ->SET

  -- tile gives us an arrow from T into Interior C T

  tile' : {T : I -> Set} -> [ T -:> Interior C T ]
  tile' i = tile

  -- <_> gives us an algebra!

  cut' : {T : I -> Set} -> Algebra (CUTTING C) (Interior C T)
  cut' i = <_>

  -- Now, other (CUTTING C) algebras give us operators on interiors.

  module INTERIORFOLD {P Q : I -> Set} where

    interiorFold :
      [ P -:> Q ] ->              -- if we can turn a P into a Q...
      Algebra (CUTTING C) Q ->    -- ...and a bunch of Qs into a Q...
      [ Interior C P -:> Q ]      -- ...we can turn an interior of Ps into a Q

    allInteriorFold :             -- annoyingly, we'll need a specialized "all"
      [ P -:> Q ] ->
      Algebra (CUTTING C) Q ->
      [ All (Interior C P) -:> All Q ]

    interiorFold pq qalg i (tile p)      = pq i p
    interiorFold pq qalg i < c 8>< pis > =
      qalg i (c 8>< allInteriorFold pq qalg (inners c) pis)

    -- recursively turn all the sub-interiors into Qs
    allInteriorFold pq qalg []        <>         = <>
    allInteriorFold pq qalg (i ,- is) (pi , pis) =
      interiorFold pq qalg i pi , allInteriorFold pq qalg is pis

    -- The trouble is that if you use
    --   all (interiorFold pq qalg)
    -- to process the sub-interiors, the termination checker complains.

    -- But if you've built "all" correctly, you should be able to prove this:

--??--2.10--------------------------------------------------------------------

    allInteriorFoldLaw : (pq : [ P -:> Q ])(qalg : Algebra (CUTTING C) Q) ->
      allInteriorFold pq qalg == all (interiorFold pq qalg)
    allInteriorFoldLaw pq qalg = extensionality \ is -> extensionality \ ps ->
      {!!}
      where
      -- helper lemmas go here

--??--------------------------------------------------------------------------

    -- Now, do me a favour and prove this extremely useful fact.
    -- Its purpose is to bottle the inductive proof method for functions
    -- built with interiorFold.

--??--2.11--------------------------------------------------------------------

    interiorFoldLemma :
      (pq : [ P -:> Q ])(qalg : Algebra (CUTTING C) Q)
      (f : [ Interior C P -:> Q ]) ->
      ((i : I)(p : P i) -> pq i p == f i (tile p)) ->
      ((i : I)(c : Cuts i)(ps : All (Interior C P) (inners c)) ->
        qalg i (c 8>< all f (inners c) ps) == f i < c 8>< ps >) ->
      (i : I)(pi : Interior C P i) -> interiorFold pq qalg i pi == f i pi

    interiorFoldLemma pq qalg f base step i pi = {!!}

--??--------------------------------------------------------------------------

    -- We'll use it in this form:

    interiorFoldLaw : (pq : [ P -:> Q ])(qalg : Algebra (CUTTING C) Q)
      (f : [ Interior C P -:> Q ]) ->
      ((i : I)(p : P i) -> pq i p == f i (tile p)) ->
      ((i : I)(c : Cuts i)(ps : All (Interior C P) (inners c)) ->
        qalg i (c 8>< all f (inners c) ps) == f i < c 8>< ps >) ->
      interiorFold pq qalg == f

    interiorFoldLaw pq qalg f base step =
      extensionality \ i -> extensionality \ pi ->
      interiorFoldLemma pq qalg f base step i pi

  open INTERIORFOLD

  -- Let me pay you back immediately!
  -- An interiorBind is an interiorFold which computes an Interior,
  --   rewrapping each layer with < ... >

  interiorBind : {X Y : I -> Set} ->
                 [ X -:> Interior C Y ] -> [ Interior C X -:> Interior C Y ]
  interiorBind f = interiorFold f (\ i -> <_>)

  -- Because an interiorBind *makes* an interior, we can say something useful
  -- about what happens if we follow it with an interiorFold.

  interiorBindFusion : {X Y Z : I -> Set} ->
    (f : [ X -:> Interior C Y ])
    (yz : [ Y -:> Z ])(zalg : Algebra (CUTTING C) Z) ->
    (interiorBind f >~> interiorFold yz zalg) ==
      interiorFold (f >~> interiorFold yz zalg) zalg

  -- That is, we can "fuse" the two together, making one interiorFold.

  -- I'll do the proof as it's a bit hairy. You've given me all I need.
  -- Note that I don't use extensionality, just laws that relate functions.

  interiorBindFusion f yz zalg =
    (interiorBind f >~> interiorFold yz zalg)
      =< interiorFoldLaw
         (f >~> interiorFold yz zalg) zalg
         (interiorBind f >~> interiorFold yz zalg)
         (\ i p -> refl (interiorFold yz zalg i (f i p)))
         (\ i c ps -> refl (zalg i) =$= (refl (c 8><_) =$= (
            ((all (interiorBind f >~> interiorFold yz zalg)
              =[ F-map->~> (interiorBind f) (interiorFold yz zalg) >=
            (all (interiorBind f) >~> all (interiorFold yz zalg))
              =< refl _>~>_
                 =$= allInteriorFoldLaw f cut'
                 =$= allInteriorFoldLaw yz zalg  ]=
            allInteriorFold f (\ i -> <_>) >~> allInteriorFold yz zalg [QED])
           =$ inners c =$= refl ps))))
      ]=
    interiorFold (f >~> interiorFold yz zalg) zalg [QED]
    where open _=>_ (ALL I)

  -- You should find that a very useful piece of kit. In fact, you should
  -- not need extensionality, either.

  -- We need Interior C to be a functor.

--??--2.12--------------------------------------------------------------------

  -- using interiorBind, implement the "F-map" for Interiors as a one-liner

  interior : {X Y : I -> Set} ->
             [ X -:> Y ] -> [ Interior C X -:> Interior C Y ]
  interior f = {!!}

  -- using interiorBindFusion, prove the following law for "fold after map"

  interiorFoldFusion : {P Q R : I -> Set}
    (pq : [ P -:> Q ])(qr : [ Q -:> R ])(ralg : Algebra (CUTTING C) R) ->
    (interior pq >~> interiorFold qr ralg) == interiorFold (pq >~> qr) ralg
  interiorFoldFusion pq qr ralg =
    interior pq >~> interiorFold qr ralg
      =[ {!!} >=
    interiorFold (pq >~> qr) ralg [QED]
    where open _=>_ (ALL I)

  -- and now, using interiorFoldFusion if it helps,
  -- complete the functor construction

  INTERIOR : (I ->SET) => (I ->SET)
  INTERIOR = record
    { F-Obj      = Interior C
    ; F-map      = interior
    ; F-map-id~> = {!!}
    ; F-map->~>  = {!!}
    } where open _=>_ (ALL I)

--??--------------------------------------------------------------------------

  -- Now let's build the Monad.
  -- You should find that all the laws you have to prove follow from the
  -- fusion laws you already have.

  open MONAD INTERIOR

--??--2.13--------------------------------------------------------------------

  WRAP : ID ~~> INTERIOR
  WRAP = record
    { xf         = {!!}
    ; naturality = {!!}
    }

  -- use interiorBind to define the following
  FLATTEN : (INTERIOR >=> INTERIOR) ~~> INTERIOR
  FLATTEN = record
    { xf         = {!!}
    ; naturality = {!!}
    }

  INTERIOR-Monad : Monad
  INTERIOR-Monad = record
    { unit = WRAP
    ; mult = FLATTEN
    ; unitMult = {!!}
    ; multUnit = {!!}
    ; multMult = {!!}
    } where
    open _=>_ INTERIOR

--??--------------------------------------------------------------------------

open INTERIOR
open INTERIORFOLD

-- You should be able to define an algebra on vectors for NatCut, using +V

--??--2.14--------------------------------------------------------------------

NatCutVecAlg : {X : Set} -> Algebra (CUTTING NatCut) (Vec X)
NatCutVecAlg n xsc = {!!}

--??--------------------------------------------------------------------------

-- Check that it puts things together suitably when you evaluate this:

test1 : Vec Char 13
test1 = interiorFold (\ _ -> id) NatCutVecAlg 13 subbookkeeper

------------------------------------------------------------------------------
-- Cutting Up Pairs
------------------------------------------------------------------------------

module CHOICE where
  open _|>_

--??--2.15--------------------------------------------------------------------

  -- Show that if you can cut up I and cut up J, then you can cut up I * J.
  -- You now have two dimensions (I and J). The idea is that you choose one
  -- dimension in which to make a cut, and keep everything in the other
  -- dimension the same.

  _+C_ : {I J : Set} ->  I |> I ->  J |> J  ->  (I * J) |> (I * J)
  Cuts   (P +C Q) (i , j) = Cuts P i + Cuts Q j
  inners (P +C Q) = {!!}

--??--------------------------------------------------------------------------

open CHOICE

-- That should get us the ability to cut up *rectangules* by cutting either
-- vertically or horizontally.

NatCut2D : (Nat * Nat) |> (Nat * Nat)
NatCut2D = NatCut +C NatCut

Matrix : Set -> Nat * Nat -> Set
Matrix X (w , h) = Vec (Vec X w) h

-- If you've done it right, you should find that the following typechecks.
-- It's the interior of a rectangle, tiled with matrices of characters.

rectangle : Interior NatCut2D (Matrix Char) (15 , 6)
rectangle = < inr (4 , 2 , refl _)
            8>< < inl (7 , 8 , refl _)
                8>< tile (strVec "seventy"
                       ,- strVec "kitchen"
                       ,- strVec "program"
                       ,- strVec "mistake"
                       ,- [])
                  , tile (strVec "thousand"
                       ,- strVec "soldiers"
                       ,- strVec "probably"
                       ,- strVec "undefine"
                       ,- [])
                  , <> >
              , tile (strVec "acknowledgement"
                   ,- strVec "procrastination"
                   ,- [])
              , <> >

-- Later, we'll use rectangular interiors as the underlying data structure
-- for a window manager.

-- But for now, one last thing.

--??--2.16--------------------------------------------------------------------

-- Show that if you have a vector of n Ps for every element of a list,
-- then you can make a vector of n (All P)s .
-- Hint: Ex1 provides some useful equipment for this job.

vecAll : {I : Set}{P : I -> Set}{is : List I}{n : Nat} ->
         All (\ i -> Vec (P i) n) is -> Vec (All P is) n
vecAll {is = is} pss = {!!}

-- Given vecAll, show that algebra for any cutting can be lifted
-- to an algebra on vectors.

VecLiftAlg : {I : Set}(C : I |> I){X : I -> Set}
             (alg : Algebra (CUTTING C) X){n : Nat} ->
             Algebra (CUTTING C) (\ i -> Vec (X i) n)
VecLiftAlg C alg i (c 8>< pss) = {!!}

-- Now show that you can build an algebra for matrices
-- which handles cuts in either dimension,
-- combining them either horizontally or vertically!

NatCut2DMatAlg : {X : Set} -> Algebra (CUTTING NatCut2D) (Matrix X)
NatCut2DMatAlg _ (inl c 8>< ms) = {!!}
NatCut2DMatAlg _ (inr c 8>< ms) = {!!}

--??--------------------------------------------------------------------------

-- And that should give you a way to glue pictures together from interiors.

picture : [ Interior NatCut2D (Matrix Char) -:> Matrix Char ]
picture = interiorFold (\ _ -> id) NatCut2DMatAlg

-- You should be able to check that the following gives you something
-- sensible:

test2 = picture _ rectangle


data Tm : Set where
  tzero : Tm
  tsucc : Tm → Tm
  tdiff : Tm → Tm → Tm

variable
  m n n' : Tm

data NotZero : Tm → Set where
  nzsucc : NotZero (tsucc n)
  nzdiff : NotZero (tdiff m n)

data Equal : Tm → Tm → Set where
  esucc : NotZero n → Equal (tsucc (tdiff tzero n)) n
  ediff : Equal n n' → Equal (tdiff m n) (tdiff m n')

data Foo : Tm → Set where
  fleft : Foo m → Foo (tdiff m n)
  frght : Foo n → Foo (tdiff m (tsucc n))

foo : Foo n → Equal n n' → Foo n'
foo (fleft f) e = {!!}
foo (frght (frght f)) (ediff (esucc nz)) = {!nz!} -- case-split on nz replaces nz with nzsucc


{-
Joseph Eremondi
Utrecht University Capita Selecta
UU# 4229924
July 22, 2015
-}

module SemiLinRE where

open import Data.Vec
open import Data.Nat
import Data.Fin as Fin

open import Data.List
import Data.List.All
open import Data.Bool
open import Data.Char

open import Data.Maybe

open import Data.Product
open import Relation.Binary
open import Relation.Binary.PropositionalEquality

open import Relation.Nullary
open import Relation.Nullary.Decidable
open import Relation.Binary.Core

open import Category.Monad

open import Data.Nat.Properties.Simple

open import Data.Maybe
open import Relation.Binary.PropositionalEquality
open ≡-Reasoning

open import Utils

open import Function

import RETypes

open import Data.Sum

open import SemiLin

open import Data.Vec.Equality
open import Data.Nat.Properties.Simple

module VecNatEq = Data.Vec.Equality.DecidableEquality (Relation.Binary.PropositionalEquality.decSetoid Data.Nat._≟_)

--Find the Parikh vector of a given word
--Here cmap is the mapping of each character to its position
--in the Parikh vector
wordParikh : {n : ℕ} -> (Char -> Fin.Fin n) -> (w : List Char) -> Parikh n
wordParikh cmap [] = v0
wordParikh cmap (x ∷ w) = (basis (cmap x)) +v (wordParikh cmap w)

--Show that the Parikh of concatenating two words
--Is the sum of their Parikhs
wordParikhPlus : {n : ℕ}
  -> (cmap : Char -> Fin.Fin n)
  -> (u : List Char)
  -> (v : List Char)
  -> wordParikh cmap (u Data.List.++ v) ≡ (wordParikh cmap u) +v (wordParikh cmap v)
wordParikhPlus cmap [] v = sym v0identLeft
wordParikhPlus {n} cmap (x ∷ u) v  =
  begin
    basis (cmap x) +v wordParikh cmap (u ++l v)
  ≡⟨ cong (λ y → basis (cmap x) +v y) (wordParikhPlus cmap u v) ⟩
    basis (cmap x) +v (wordParikh cmap u +v wordParikh cmap v)
  ≡⟨ sym vAssoc ⟩
    ((basis (cmap x) +v wordParikh cmap u) +v wordParikh cmap v ∎)
    where
      _++l_ = Data.List._++_

--The algorithm mapping regular expressions to the Parikh set of
--the language matched by the RE
--We prove this correct below
reSemiLin : {n : ℕ} {null? : RETypes.Null?} -> (Char -> Fin.Fin n) -> RETypes.RE null? -> SemiLinSet n
reSemiLin cmap RETypes.ε = Data.List.[ v0 , 0 , [] ]
reSemiLin cmap RETypes.∅ = []
reSemiLin cmap (RETypes.Lit x) = Data.List.[ basis (cmap x ) , 0 , [] ]
reSemiLin cmap (r1 RETypes.+ r2) = reSemiLin cmap r1 Data.List.++ reSemiLin cmap r2
reSemiLin cmap (r1 RETypes.· r2) = reSemiLin cmap r1 +s reSemiLin cmap r2
reSemiLin cmap (r RETypes.*)  = starSemiLin (reSemiLin cmap r)

{-
Show that s* ⊆ s +v s*
Not implemented due to time restrictions,
but should be possible, given that linStarExtend is implemented
in SemiLin.agda
-}
starExtend
  :  {n : ℕ}
  -> (v1 v2 : Parikh n )
  -> ( s ss : SemiLinSet n)
  -> ss ≡ starSemiLin s
  -> InSemiLin v1 s
  -> InSemiLin v2 ss
  -> InSemiLin (v1 +v v2) (starSemiLin s)
starExtend v1 v2 s ss spf inS inSS = {!!}

{-
Show that s* ⊇ s +v s*
Not completely implemented due to time restrictions,
but should be possible, given that linStarDecomp is implemented
in SemiLin.agda.

There are also some hard parts, for example, dealing with the proofs
that the returned vectors are non-zero (otherwise, we'd just trivially return v0 and v)
-}
starDecomp
 :  {n : ℕ}
 -> (v : Parikh n)
 -> (s ss : SemiLinSet n)
 -> v ≢ v0
 -> ss ≡ starSemiLin s
 -> InSemiLin v ss
 -> (∃ λ v1 -> ∃ λ v2 -> v1 +v v2 ≡ v × InSemiLin v1 s × InSemiLin v2 ss × v1 ≢ v0  )
starDecomp v s ss vpf spf inSemi = {!!}
{-
starDecomp v sh st .(sh ∷ st) .((v0 , 0 , []) ∷ starSum sh st ∷ []) vnz refl refl (InHead .v .(v0 , 0 , []) .(starSum sh st ∷ []) x) with emptyCombZero v x | vnz (emptyCombZero v x)
starDecomp .v0 sh st .(sh ∷ st) .((v0 , zero , []) ∷ [] Data.List.++ starSum sh st ∷ []) vnz refl refl (InHead .v0 .(v0 , zero , []) .(starSum sh st ∷ []) x) | refl | ()
starDecomp v sh [] .(sh ∷ []) .((v0 , 0 , []) ∷ (proj₁ sh , suc (proj₁ (proj₂ sh)) , proj₁ sh ∷ proj₂ (proj₂ sh)) ∷ []) vnz refl refl (InTail .v .(v0 , 0 , []) .((proj₁ sh , suc (proj₁ (proj₂ sh)) , proj₁ sh ∷ proj₂ (proj₂ sh)) ∷ []) (InHead .v .(proj₁ sh , suc (proj₁ (proj₂ sh)) , proj₁ sh ∷ proj₂ (proj₂ sh)) .[] starComb)) with linStarDecomp v sh _ vnz {!!} refl starComb
starDecomp v sh [] .(sh ∷ []) .((v0 , zero , []) ∷ [] Data.List.++ starSum sh [] ∷ []) vnz refl refl (InTail .v .(v0 , zero , []) .(starSum sh [] ∷ []) (InHead .v .(proj₁ sh , suc (proj₁ (proj₂ sh)) , proj₁ sh ∷ proj₂ (proj₂ sh)) .[] starComb)) | inj₁ lComb = v , v0 , v0identRight , InHead v sh [] lComb , InHead v0 (v0 , zero , []) _ (v0 , refl) , vnz
starDecomp v sh [] .(sh ∷ []) .((v0 , zero , []) ∷ [] Data.List.++ starSum sh [] ∷ []) vnz refl refl (InTail .v .(v0 , zero , []) .(starSum sh [] ∷ []) (InHead .v .(proj₁ sh , suc (proj₁ (proj₂ sh)) , proj₁ sh ∷ proj₂ (proj₂ sh)) .[] starComb)) | inj₂ (v1 , v2 , sumPf , comb1 , comb2 , zpf ) = v1 , v2 , sumPf , InHead v1 sh [] comb1 ,  InTail v2 (v0 , zero , []) _ (InHead v2 _ [] comb2) , zpf
starDecomp v sh [] .(sh ∷ []) .((v0 , 0 , []) ∷ (proj₁ sh , suc (proj₁ (proj₂ sh)) , proj₁ sh ∷ proj₂ (proj₂ sh)) ∷ []) vnz refl refl (InTail .v .(v0 , 0 , []) .((proj₁ sh , suc (proj₁ (proj₂ sh)) , proj₁ sh ∷ proj₂ (proj₂ sh)) ∷ []) (InTail .v .(proj₁ sh , suc (proj₁ (proj₂ sh)) , proj₁ sh ∷ proj₂ (proj₂ sh)) .[] ()))
starDecomp v sh (x ∷ st) .(sh ∷ x ∷ st) .((v0 , 0 , []) ∷ (proj₁ x +v proj₁ (starSum sh st) , suc (proj₁ (proj₂ x) + proj₁ (proj₂ (starSum sh st))) , proj₁ x ∷ proj₂ (proj₂ x) Data.Vec.++ proj₂ (proj₂ (starSum sh st))) ∷ []) vnz refl refl (InTail .v .(v0 , 0 , []) .((proj₁ x +v proj₁ (starSum sh st) , suc (proj₁ (proj₂ x) + proj₁ (proj₂ (starSum sh st))) , proj₁ x ∷ proj₂ (proj₂ x) Data.Vec.++ proj₂ (proj₂ (starSum sh st))) ∷ []) inSemi) = {!!} -}

--Stolen from the stdlib
listIdentity : {A : Set} -> (x : List A) -> (x Data.List.++ [] ) ≡ x
listIdentity [] = refl
listIdentity (x ∷ xs) = cong (_∷_ x) (listIdentity xs)

{-
Show that +s is actually the sum of two sets, that is,
if v1 is in S1, and v2 is in S2, then v1 +v v2
is in S1 +s S2
-}
sumPreserved :
  {n : ℕ}
  -> (u : Parikh n)
  -> (v : Parikh n)
  -- -> (uv : Parikh n)
  -> (su : SemiLinSet n)
  -> (sv : SemiLinSet n)
  -- -> (suv : SemiLinSet n)
  -- -> (uv ≡ u +v v)
  -- -> (suv ≡ su +s sv)
  -> InSemiLin u su
  -> InSemiLin v sv
  -> InSemiLin (u +v v) (su +s sv)
sumPreserved u v .((ub , um , uvecs) ∷ st) .((vb , vm , vvecs) ∷ st₁) (InHead .u (ub , um , uvecs) st (uconsts , upf)) (InHead .v (vb , vm , vvecs) st₁ (vconsts , vpf))
  rewrite   upf | vpf
  = InHead (u +v v) (ub +v vb , um + vm , uvecs Data.Vec.++ vvecs) (Data.List.map (_+l_ (ub , um , uvecs)) st₁ Data.List.++
                                                                       Data.List.foldr Data.List._++_ []
                                                                       (Data.List.map
                                                                        (λ z → z +l (vb , vm , vvecs) ∷ Data.List.map (_+l_ z) st₁) st))
  ((uconsts Data.Vec.++ vconsts) , trans (combSplit ub vb um vm uvecs vvecs uconsts vconsts)
  (sym (subst (λ x → u +v v ≡ x +v applyLinComb vb vm vvecs vconsts) (sym upf) (cong (λ x → u +v x) (sym vpf)))) )

sumPreserved u v .(sh ∷ st) .(sh₁ ∷ st₁) (InHead .u sh st x) (InTail .v sh₁ st₁ vIn) =
  let
    subCall1 : InSemiLin (u +v v) ((sh ∷ []) +s  st₁)
    subCall1 = sumPreserved u v (sh ∷ []) ( st₁) (InHead u sh [] x) vIn

    eqTest : (sh ∷ []) +s ( st₁) ≡ Data.List.map (λ l2 → sh +l l2) st₁
    eqTest =
      begin
      (sh ∷ []) +s (st₁)
      ≡⟨ refl ⟩
      Data.List.map (λ l2 → sh +l l2) ( st₁) Data.List.++ []
      ≡⟨ listIdentity (Data.List.map (_+l_ sh) st₁) ⟩
      Data.List.map (λ l2 → sh +l l2) (st₁)
      ≡⟨ refl ⟩
      (Data.List.map (λ l2 → sh +l l2) st₁ ∎)

    newCall = slExtend (u +v v) (Data.List.map (_+l_ sh) st₁) (subst (InSemiLin (u +v v)) eqTest subCall1) (sh +l sh₁) --
  in slConcatRight (u +v v) (Data.List.map (λ l2 → sh +l l2) (sh₁ ∷ st₁)) newCall (Data.List.foldr Data.List._++_ []
                                                                                (Data.List.map (λ z → z +l sh₁ ∷ Data.List.map (_+l_ z) st₁) st))
sumPreserved u v .(sh ∷ st) sv (InTail .u sh st uIn) vIn =
  (slConcatLeft (u +v v) (st +s sv) (sumPreserved u v st sv uIn vIn) (Data.List.map (λ x → sh +l x) sv))

--A useful lemma, avoids having to dig into the List monoid instance
rightCons : {A : Set} -> (l : List A) -> (l Data.List.++ [] ≡ l)
rightCons [] = refl
rightCons (x ∷ l) rewrite rightCons l = refl

{-
Show that, if a vector is in the union of two semi-linear sets,
then it must be in one of those sets.
Used in the proof for Union.
Called concat because we represent semi-linear sets as lists,
so union is just concatenating two semi-linear sets
-}
decomposeConcat
  :  {n : ℕ}
  -> (v : Parikh n)
  -> (s1 s2 s3 : SemiLinSet n)
  -> (s3 ≡ s1 Data.List.++ s2 )
  -> InSemiLin v s3
  -> InSemiLin v s1 ⊎ InSemiLin v s2
decomposeConcat v [] s2 .s2 refl inSemi = inj₂ inSemi
decomposeConcat v (x ∷ s1) s2 .(x ∷ s1 Data.List.++ s2) refl (InHead .v .x .(s1 Data.List.++ s2) x₁) = inj₁ (InHead v x s1 x₁)
decomposeConcat v (x ∷ s1) s2 .(x ∷ s1 Data.List.++ s2) refl (InTail .v .x .(s1 Data.List.++ s2) inSemi) with decomposeConcat v s1 s2 _ refl inSemi
decomposeConcat v (x₁ ∷ s1) s2 .(x₁ ∷ s1 Data.List.++ s2) refl (InTail .v .x₁ .(s1 Data.List.++ s2) inSemi) | inj₁ x = inj₁ (InTail v x₁ s1 x)
decomposeConcat v (x ∷ s1) s2 .(x ∷ s1 Data.List.++ s2) refl (InTail .v .x .(s1 Data.List.++ s2) inSemi) | inj₂ y = inj₂ y

concatEq : {n : ℕ} -> (l : LinSet n) -> (s : SemiLinSet n) -> (l ∷ []) +s s ≡ (Data.List.map (_+l_ l) s)
concatEq l [] = refl
concatEq l (x ∷ s) rewrite concatEq l s | listIdentity (l ∷ [])  = refl

{-
Show that if v is in l1 +l l2, then v = v1 +v v2 for some
v1 in l1 and v2 in l2.
This is the other half of the correcness proof of our sum functions, +l and +s
-}
decomposeLin
  :  {n : ℕ}
  -> (v : Parikh n)
  -> (l1 l2 l3 : LinSet n)
  -> (l3 ≡ l1 +l l2 )
  -> LinComb v l3
  -> ∃ λ v1 → ∃ λ v2 -> (v1 +v v2 ≡ v) × (LinComb v1 l1) × (LinComb v2 l2 )
decomposeLin .(applyLinComb (b1 +v b2) (m1 + m2) (vecs1 Data.Vec.++ vecs2) coeffs) (b1 , m1 , vecs1) (b2 , m2 , vecs2) .(b1 +v b2 , m1 + m2 , vecs1 Data.Vec.++ vecs2) refl (coeffs , refl) with Data.Vec.splitAt m1 coeffs
decomposeLin .(applyLinComb (b1 +v b2) (m1 + m2) (vecs1 Data.Vec.++ vecs2) (coeffs1 Data.Vec.++ coeffs2)) (b1 , m1 , vecs1) (b2 , m2 , vecs2) .(b1 +v b2 , m1 + m2 , vecs1 Data.Vec.++ vecs2) refl (.(coeffs1 Data.Vec.++ coeffs2) , refl) | coeffs1 , coeffs2 , refl rewrite combSplit b1 b2 m1 m2 vecs1 vecs2 coeffs1 coeffs2
  = applyLinComb b1 m1 vecs1 coeffs1 , (applyLinComb b2 m2 vecs2 coeffs2 , (refl , ((coeffs1 , refl) , (coeffs2 , refl))))

{-
Show that our Parikh function is a superset of the actual Parikh image of a Regular Expression.

We do this by showing that, for every word matching an RE, its Parikh vector
is in the Parikh Image of the RE
-}
reParikhCorrect :
  {n : ℕ}
  -> {null? : RETypes.Null?}
  -> (cmap : Char -> Fin.Fin n)
  -> (r : RETypes.RE null?)
  -> (w : List Char )
  -> RETypes.REMatch w r
  -> (wordPar : Parikh n)
  -> (wordParikh cmap w ≡ wordPar)
  -> (langParikh : SemiLinSet n)
  -> (langParikh ≡ reSemiLin cmap r )
  -> (InSemiLin wordPar langParikh )
reParikhCorrect cmap .RETypes.ε .[] RETypes.EmptyMatch .v0 refl .((v0 , 0 , []) ∷ []) refl = InHead v0 (v0 , zero , []) [] ([] , refl)
reParikhCorrect cmap .(RETypes.Lit c) .(c ∷ []) (RETypes.LitMatch c) .(basis (cmap c) +v v0) refl .((basis (cmap c) , 0 , []) ∷ []) refl =
  InHead (basis (cmap c) +v v0) (basis (cmap c) , zero , []) [] (subst (λ x → LinComb x (basis (cmap c) , zero , [])) (sym v0identRight) (v0 , (v0apply (basis (cmap c)) [])))
reParikhCorrect cmap (r1 RETypes.+ .r2) w (RETypes.LeftPlusMatch r2 match) wordPar wpf langParikh lpf =
  let
    leftParikh = reSemiLin cmap r1
    leftInSemi = reParikhCorrect cmap r1 w match wordPar wpf leftParikh refl
    --Idea: show that langParikh is leftParikh ++ rightParikh
    --And that this means that it must be in the concatentation
    extendToConcat : InSemiLin wordPar ((reSemiLin cmap r1 ) Data.List.++ (reSemiLin cmap r2))
    extendToConcat = slConcatRight wordPar (reSemiLin cmap r1) leftInSemi (reSemiLin cmap r2)
  in subst (λ x → InSemiLin wordPar x) (sym lpf) extendToConcat
reParikhCorrect cmap (.r1 RETypes.+ r2) w (RETypes.RightPlusMatch r1 match) wordPar wpf langParikh lpf = let
    rightParikh = reSemiLin cmap r2
    rightInSemi = reParikhCorrect cmap r2 w match wordPar wpf rightParikh refl
    --Idea: show that langParikh is leftParikh ++ rightParikh
    --And that this means that it must be in the concatentation
    extendToConcat : InSemiLin wordPar ((reSemiLin cmap r1 ) Data.List.++ (reSemiLin cmap r2))
    extendToConcat = slConcatLeft wordPar (reSemiLin cmap r2) rightInSemi (reSemiLin cmap r1)
  in subst (λ x → InSemiLin wordPar x) (sym lpf) extendToConcat
reParikhCorrect cmap (r1 RETypes.· r2) s3 (RETypes.ConcatMatch {s1 = s1} {s2 = s2} {spf = spf} match1 match2) .(wordParikh cmap s3) refl ._ refl rewrite (sym spf) |  (wordParikhPlus cmap s1 s2) =
 let
    leftParikh = reSemiLin cmap r1
    leftInSemi : InSemiLin (wordParikh cmap s1) leftParikh
    leftInSemi = reParikhCorrect cmap r1 s1 match1 (wordParikh cmap s1) refl (reSemiLin cmap r1) refl

    rightParikh = reSemiLin cmap r2
    rightInSemi : InSemiLin (wordParikh cmap s2) rightParikh
    rightInSemi = reParikhCorrect cmap r2 s2 match2 (wordParikh cmap s2) refl (reSemiLin cmap r2) refl

    wordParikhIsPlus : (wordParikh cmap s1) +v (wordParikh cmap s2) ≡ (wordParikh cmap (s1 Data.List.++ s2 ))
    wordParikhIsPlus = sym (wordParikhPlus cmap s1 s2)

  in sumPreserved (wordParikh cmap s1) (wordParikh cmap s2) leftParikh rightParikh leftInSemi rightInSemi
reParikhCorrect cmap (r RETypes.*) [] RETypes.EmptyStarMatch .v0 refl .(starSemiLin (reSemiLin cmap r)) refl = zeroInStar (reSemiLin cmap r) (starSemiLin (reSemiLin cmap r)) refl
reParikhCorrect cmap (r RETypes.*) .(s1 Data.List.++ s2 ) (RETypes.StarMatch {s1 = s1} {s2 = s2} {spf = refl} m1 m2) ._ refl .(starSemiLin (reSemiLin cmap r)) refl rewrite wordParikhPlus cmap s1 s2 =
  starExtend (wordParikh cmap s1) (wordParikh cmap s2) (reSemiLin cmap r) _ refl (reParikhCorrect cmap r s1 m1 (wordParikh cmap s1) refl (reSemiLin cmap r) refl) (reParikhCorrect cmap (r RETypes.*) s2 m2 (wordParikh cmap s2) refl (starSemiLin (reSemiLin cmap r)) refl)

{-
Show that if v is in s1 +s s2, then v = v1 +v v2 for some
v1 in s1 and v2 in s2.
This is the other half of the correcness proof of our sum functions, +l and +s
-}
decomposeSum
  :  {n : ℕ}
  -> (v : Parikh n)
  -> (s1 s2 s3 : SemiLinSet n)
  -> (s3 ≡ s1 +s s2 )
  -> InSemiLin v s3
  -> ∃ λ (v1 : Parikh n) → ∃ λ (v2 : Parikh n) -> (v1 +v v2 ≡ v) × (InSemiLin v1 s1) × (InSemiLin v2 s2 )
decomposeSum v [] [] .[] refl ()
decomposeSum v [] (x ∷ s2) .[] refl ()
decomposeSum v (x ∷ s1) [] .(Data.List.foldr Data.List._++_ [] (Data.List.map (λ l1 → []) s1)) refl ()
decomposeSum v ((b1 , m1 , vecs1) ∷ s1) ((b2 , m2 , vecs2) ∷ s2) ._ refl (InHead .v .(b1 +v b2 , m1 + m2 , vecs1 Data.Vec.++ vecs2) ._ lcomb) =
  let
    (v1 , v2 , plusPf , comb1 , comb2 ) = decomposeLin v (b1 , m1 , vecs1) (b2 , m2 , vecs2) (b1 +v b2 , m1 + m2 , vecs1 Data.Vec.++ vecs2) refl lcomb
  in v1 , v2 , plusPf , InHead v1 (b1 , m1 , vecs1) s1 comb1 , InHead v2 (b2 , m2 , vecs2) s2 comb2
decomposeSum v ((b1 , m1 , vecs1) ∷ s1) ((b2 , m2 , vecs2) ∷ s2) ._ refl (InTail .v .(b1 +v b2 , m1 + m2 , vecs1 Data.Vec.++ vecs2) ._ inSemi) with decomposeConcat v (Data.List.map (_+l_ (b1 , m1 , vecs1)) s2) (Data.List.foldr Data.List._++_ []
                                                                                (Data.List.map
                                                                                (λ z → z +l (b2 , m2 , vecs2) ∷ Data.List.map (_+l_ z) s2) s1)) (Data.List.map (_+l_ (b1 , m1 , vecs1)) s2 Data.List.++
                                                                                Data.List.foldr Data.List._++_ []
                                                                                (Data.List.map
                                                                                (λ z → z +l (b2 , m2 , vecs2) ∷ Data.List.map (_+l_ z) s2) s1)) refl inSemi
decomposeSum v ((b1 , m1 , vecs1) ∷ s1) ((b2 , m2 , vecs2) ∷ s2) .((b1 , m1 , vecs1) +l (b2 , m2 , vecs2) ∷ Data.List.map (_+l_ (b1 , m1 , vecs1)) s2 Data.List.++ Data.List.foldr Data.List._++_ [] (Data.List.map _ s1)) refl (InTail .v .(b1 +v b2 , m1 + m2 , vecs1 Data.Vec.++ vecs2) .(Data.List.map (_+l_ (b1 , m1 , vecs1)) s2 Data.List.++ Data.List.foldr Data.List._++_ [] (Data.List.map _ s1)) inSemi) | inj₁ inSub =
  let
    subCall1 = decomposeSum v ((b1 , m1 , vecs1) ∷ []) s2 _ refl (subst (λ x → InSemiLin v x) (sym (concatEq (b1 , m1 , vecs1) s2)) inSub)
    v1 , v2 , pf , xIn , yIn = subCall1
  in v1 , (v2 , (pf , (slCons v1 s1 (b1 , m1 , vecs1) xIn , slExtend v2 s2 yIn (b2 , m2 , vecs2))))
decomposeSum v ((b1 , m1 , vecs1) ∷ s1) ((b2 , m2 , vecs2) ∷ s2) .((b1 , m1 , vecs1) +l (b2 , m2 , vecs2) ∷ Data.List.map (_+l_ (b1 , m1 , vecs1)) s2 Data.List.++ Data.List.foldr Data.List._++_ [] (Data.List.map _ s1)) refl (InTail .v .(b1 +v b2 , m1 + m2 , vecs1 Data.Vec.++ vecs2) .(Data.List.map (_+l_ (b1 , m1 , vecs1)) s2 Data.List.++ Data.List.foldr Data.List._++_ [] (Data.List.map _ s1)) inSemi) | inj₂ inSub =
 let
   subCall1 = decomposeSum v s1 ((b2 , m2 , vecs2) ∷ s2) _ refl inSub
   v1 , v2 , pf , xIn , yIn = subCall1
 in v1 , v2 , pf , slExtend v1 s1 xIn (b1 , m1 , vecs1) , yIn

{-
Show that the generated Parikh image is a subset of the actual Parikh image.

We do this by showing that, for every vector in the generated Parikh image,
there's some word matched by the RE whose Parikh vector is that vector.
-}
--We have to convince the compiler that this is terminating
--Since I didn't have time to implement the proofs of non-zero vectors
--Which show that we only recurse on strictly smaller vectors in the Star case
{-# TERMINATING #-}
reParikhComplete : {n : ℕ} -> {null? : RETypes.Null?}
  -> (cmap : Char -> Fin.Fin n)
--  -> (imap : Fin.Fin n -> Char)
--  -> (invPf1 : (x : Char ) -> imap (cmap x) ≡ x)
--  -> (invPf2 : (x : Fin.Fin n ) -> cmap (imap x) ≡ x )
  -> (r : RETypes.RE null?)
  -> (v : Parikh n )
  -> (langParikh : SemiLinSet n)
  -> langParikh ≡ (reSemiLin cmap r )
  -> (InSemiLin v langParikh )
  -> ∃ (λ w -> (v ≡ wordParikh cmap w) × (RETypes.REMatch w r) )
reParikhComplete cmap RETypes.ε .v0 .((v0 , 0 , []) ∷ []) refl (InHead .v0 .(v0 , 0 , []) .[] (combConsts , refl)) = [] , refl , RETypes.EmptyMatch
reParikhComplete cmap RETypes.ε v .((v0 , 0 , []) ∷ []) refl (InTail .v .(v0 , 0 , []) .[] ())

--reParikhComplete cmap  RETypes.ε v .(sh ∷ st) lpf (InTail .v sh st inSemi) = {!!}
reParikhComplete cmap  RETypes.∅ v [] lpf ()
reParikhComplete cmap  RETypes.∅ v (h ∷ t) () inSemi
reParikhComplete cmap (RETypes.Lit x) langParikh [] inSemi ()
reParikhComplete cmap (RETypes.Lit x) .(basis (cmap x)) .((basis (cmap x) , 0 , []) ∷ []) refl (InHead .(basis (cmap x)) .(basis (cmap x) , 0 , []) .[] (consts , refl)) = (x ∷ []) , (sym v0identRight , RETypes.LitMatch x)
reParikhComplete cmap (RETypes.Lit x) v .((basis (cmap x) , 0 , []) ∷ []) refl (InTail .v .(basis (cmap x) , 0 , []) .[] ())
--reParikhComplete cmap (RETypes.Lit x) v .((basis (cmap x) , 0 , []) ∷ []) refl (InTail .v .(basis (cmap x) , 0 , []) .[] ())
reParikhComplete {null? = null?} cmap  (r1 RETypes.+ r2) v langParikh lpf inSemi with decomposeConcat v (reSemiLin cmap r1) (reSemiLin cmap r2) langParikh lpf inSemi
... | inj₁ in1 =
  let
    (subw , subPf , subMatch) = reParikhComplete cmap  r1 v (reSemiLin cmap r1) refl in1
  in subw , (subPf , (RETypes.LeftPlusMatch r2 subMatch))
... | inj₂ in2 =
  let
    (subw , subPf , subMatch) = reParikhComplete cmap  r2 v (reSemiLin cmap r2) refl in2
  in subw , (subPf , (RETypes.RightPlusMatch r1 subMatch))
reParikhComplete cmap (r1 RETypes.· r2) v ._ refl inSemi with decomposeSum v (reSemiLin cmap r1) (reSemiLin cmap r2) (reSemiLin cmap r1 +s reSemiLin cmap r2) refl inSemi | reParikhComplete cmap r1 (proj₁ (decomposeSum v (reSemiLin cmap r1) (reSemiLin cmap r2)
                                                                                (reSemiLin cmap r1 +s reSemiLin cmap r2) refl inSemi)) (reSemiLin cmap r1) refl (proj₁ (proj₂ (proj₂ (proj₂ (decomposeSum v (reSemiLin cmap r1) (reSemiLin cmap r2)
                                                                                (reSemiLin cmap r1 +s reSemiLin cmap r2) refl inSemi))))) | reParikhComplete cmap r2 (proj₁ (proj₂ (decomposeSum v (reSemiLin cmap r1) (reSemiLin cmap r2)
                                                                                (reSemiLin cmap r1 +s reSemiLin cmap r2) refl inSemi))) (reSemiLin cmap r2) refl (proj₂ (proj₂ (proj₂ (proj₂ (decomposeSum v (reSemiLin cmap r1) (reSemiLin cmap r2)
                                                                                (reSemiLin cmap r1 +s reSemiLin cmap r2) refl inSemi)))))
reParikhComplete cmap (r1 RETypes.· r2) .(wordParikh cmap w1 +v wordParikh cmap w2) .(Data.List.foldr Data.List._++_ [] (Data.List.map _ (reSemiLin cmap r1))) refl inSemi | .(wordParikh cmap w1) , .(wordParikh cmap w2) , refl , inSemi1 , inSemi2 | w1 , refl , match1 | w2 , refl , match2 = (w1 Data.List.++ w2) , ((sym (wordParikhPlus cmap w1 w2)) , (RETypes.ConcatMatch match1 match2))

reParikhComplete cmap (r RETypes.*) v langParikh lpf inSemi with (reSemiLin cmap r )
reParikhComplete cmap (r RETypes.*) v .((v0 , 0 , []) ∷ []) refl (InHead .v .(v0 , 0 , []) .[] x) | [] = [] , ((sym (proj₂ x)) , RETypes.EmptyStarMatch)
reParikhComplete cmap (r RETypes.*) v .((v0 , 0 , []) ∷ []) refl (InTail .v .(v0 , 0 , []) .[] ()) | []
reParikhComplete cmap (r RETypes.*) v .((v0 , 0 , []) ∷ starSum x rsl ∷ []) refl inSemi | x ∷ rsl =
  let
    --The first hole is the non-zero proofs that I couldn't work out
    --I'm not totally sure about the second, but I think I just need to apply some associativity to inSemi to get it to fit
    --into the second hole.
    splitVec = starDecomp v (reSemiLin cmap r) _ {!!} refl {!!}
    v1 , v2 , vpf , inS , inSS , _ = splitVec
    subCall1 = reParikhComplete cmap r v1 _ refl inS
    w1 , wpf1 , match  = subCall1
    subCall2 = reParikhComplete cmap (r RETypes.*) v2 _ refl inSS
    w2 , wpf2 , match2 = subCall2
  in (w1 Data.List.++ w2) , (trans (sym vpf) (sym (wordParikhPlus cmap w1 w2)) , RETypes.StarMatch match match2)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Propositional (intensional) equality
------------------------------------------------------------------------

module Relation.Binary.PropositionalEquality where

open import Function
open import Function.Equality using (Π; _⟶_; ≡-setoid)
open import Data.Product
open import Data.Unit.Core
open import Level
open import Relation.Binary
import Relation.Binary.Indexed as I
open import Relation.Binary.Consequences
open import Relation.Binary.HeterogeneousEquality.Core as H using (_≅_)

-- Some of the definitions can be found in the following modules:

open import Relation.Binary.Core public using (_≡_; refl; _≢_)
open import Relation.Binary.PropositionalEquality.Core public

------------------------------------------------------------------------
-- Some properties

subst₂ : ∀ {a b p} {A : Set a} {B : Set b} (P : A → B → Set p)
         {x₁ x₂ y₁ y₂} → x₁ ≡ x₂ → y₁ ≡ y₂ → P x₁ y₁ → P x₂ y₂
subst₂ P refl refl p = p

cong : ∀ {a b} {A : Set a} {B : Set b}
       (f : A → B) {x y} → x ≡ y → f x ≡ f y
cong f refl = refl

cong-app : ∀ {a b} {A : Set a} {B : A → Set b} {f g : (x : A) → B x} →
           f ≡ g → (x : A) → f x ≡ g x
cong-app refl x = refl

cong₂ : ∀ {a b c} {A : Set a} {B : Set b} {C : Set c}
        (f : A → B → C) {x y u v} → x ≡ y → u ≡ v → f x u ≡ f y v
cong₂ f refl refl = refl

proof-irrelevance : ∀ {a} {A : Set a} {x y : A} (p q : x ≡ y) → p ≡ q
proof-irrelevance refl refl = refl

setoid : ∀ {a} → Set a → Setoid _ _
setoid A = record
  { Carrier       = A
  ; _≈_           = _≡_
  ; isEquivalence = isEquivalence
  }

decSetoid : ∀ {a} {A : Set a} → Decidable (_≡_ {A = A}) → DecSetoid _ _
decSetoid dec = record
  { _≈_              = _≡_
  ; isDecEquivalence = record
      { isEquivalence = isEquivalence
      ; _≟_           = dec
      }
  }

isPreorder : ∀ {a} {A : Set a} → IsPreorder {A = A} _≡_ _≡_
isPreorder = record
  { isEquivalence = isEquivalence
  ; reflexive     = id
  ; trans         = trans
  }

preorder : ∀ {a} → Set a → Preorder _ _ _
preorder A = record
  { Carrier    = A
  ; _≈_        = _≡_
  ; _∼_        = _≡_
  ; isPreorder = isPreorder
  }

------------------------------------------------------------------------
-- Pointwise equality

infix 4 _≗_

_→-setoid_ : ∀ {a b} (A : Set a) (B : Set b) → Setoid _ _
A →-setoid B = ≡-setoid A (Setoid.indexedSetoid (setoid B))

_≗_ : ∀ {a b} {A : Set a} {B : Set b} (f g : A → B) → Set _
_≗_ {A = A} {B} = Setoid._≈_ (A →-setoid B)

:→-to-Π : ∀ {a b₁ b₂} {A : Set a} {B : I.Setoid _ b₁ b₂} →
          ((x : A) → I.Setoid.Carrier B x) → Π (setoid A) B
:→-to-Π {B = B} f = record { _⟨$⟩_ = f; cong = cong′ }
  where
  open I.Setoid B using (_≈_)

  cong′ : ∀ {x y} → x ≡ y → f x ≈ f y
  cong′ refl = I.Setoid.refl B

→-to-⟶ : ∀ {a b₁ b₂} {A : Set a} {B : Setoid b₁ b₂} →
         (A → Setoid.Carrier B) → setoid A ⟶ B
→-to-⟶ = :→-to-Π

------------------------------------------------------------------------
-- The old inspect idiom

-- The old inspect idiom has been deprecated, and may be removed in
-- the future. Use inspect on steroids instead.

module Deprecated-inspect where

  -- The inspect idiom can be used when you want to pattern match on
  -- the result r of some expression e, and you also need to
  -- "remember" that r ≡ e.

  -- The inspect idiom has a problem: sometimes you can only pattern
  -- match on the p part of p with-≡ eq if you also pattern match on
  -- the eq part, and then you no longer have access to the equality.
  -- Inspect on steroids solves this problem.

  data Inspect {a} {A : Set a} (x : A) : Set a where
    _with-≡_ : (y : A) (eq : x ≡ y) → Inspect x

  inspect : ∀ {a} {A : Set a} (x : A) → Inspect x
  inspect x = x with-≡ refl

  -- Example usage:

  -- f x y with inspect (g x)
  -- f x y | c z with-≡ eq = ...

------------------------------------------------------------------------
-- Inspect on steroids

-- Inspect on steroids can be used when you want to pattern match on
-- the result r of some expression e, and you also need to "remember"
-- that r ≡ e.

data Reveal_is_ {a} {A : Set a} (x : Hidden A) (y : A) : Set a where
  [_] : (eq : reveal x ≡ y) → Reveal x is y

inspect : ∀ {a b} {A : Set a} {B : A → Set b}
          (f : (x : A) → B x) (x : A) → Reveal (hide f x) is (f x)
inspect f x = [ refl ]

-- Example usage:

-- f x y with g x | inspect g x
-- f x y | c z | [ eq ] = ...

------------------------------------------------------------------------
-- Convenient syntax for equational reasoning

import Relation.Binary.EqReasoning as EqR

-- Relation.Binary.EqReasoning is more convenient to use with _≡_ if
-- the combinators take the type argument (a) as a hidden argument,
-- instead of being locked to a fixed type at module instantiation
-- time.

module ≡-Reasoning where
  module _ {a} {A : Set a} where
    open EqR (setoid A) public
      hiding (_≡⟨_⟩_) renaming (_≈⟨_⟩_ to _≡⟨_⟩_)

  infixr 2 _≅⟨_⟩_

  _≅⟨_⟩_ : ∀ {a} {A : Set a} (x : A) {y z : A} →
           x ≅ y → y IsRelatedTo z → x IsRelatedTo z
  _ ≅⟨ x≅y ⟩ y≡z = _ ≡⟨ H.≅-to-≡ x≅y ⟩ y≡z

------------------------------------------------------------------------
-- Functional extensionality

-- If _≡_ were extensional, then the following statement could be
-- proved.

Extensionality : (a b : Level) → Set _
Extensionality a b =
  {A : Set a} {B : A → Set b} {f g : (x : A) → B x} →
  (∀ x → f x ≡ g x) → f ≡ g

-- If extensionality holds for a given universe level, then it also
-- holds for lower ones.

extensionality-for-lower-levels :
  ∀ {a₁ b₁} a₂ b₂ →
  Extensionality (a₁ ⊔ a₂) (b₁ ⊔ b₂) → Extensionality a₁ b₁
extensionality-for-lower-levels a₂ b₂ ext f≡g =
  cong (λ h → lower ∘ h ∘ lift) $
    ext (cong (lift {ℓ = b₂}) ∘ f≡g ∘ lower {ℓ = a₂})

-- Functional extensionality implies a form of extensionality for
-- Π-types.

∀-extensionality :
  ∀ {a b} →
  Extensionality a (suc b) →
  {A : Set a} (B₁ B₂ : A → Set b) →
  (∀ x → B₁ x ≡ B₂ x) → (∀ x → B₁ x) ≡ (∀ x → B₂ x)
∀-extensionality ext B₁ B₂ B₁≡B₂ with ext B₁≡B₂
∀-extensionality ext B .B  B₁≡B₂ | refl = refl


module functions where

open import level
open import eq

{- Note that the Agda standard library has an interesting generalization
   of the following basic composition operator, with more dependent typing. -}

_∘_ : ∀{ℓ ℓ' ℓ''}{A : Set ℓ}{B : Set ℓ'}{C : Set ℓ''} →
      (B → C) → (A → B) → (A → C)
f ∘ g = λ x → f (g x)

∘-assoc : ∀{ℓ ℓ' ℓ'' ℓ'''}{A : Set ℓ}{B : Set ℓ'}{C : Set ℓ''}{D : Set ℓ'''}
           (f : C → D)(g : B → C)(h : A → B) → (f ∘ g) ∘ h ≡ f ∘ (g ∘ h)
∘-assoc f g h = refl

id : ∀{ℓ}{A : Set ℓ} → A → A
id = λ x → x

∘-id : ∀{ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'}(f : A → B) → f ∘ id ≡ f
∘-id f = refl

id-∘ : ∀{ℓ ℓ'}{A : Set ℓ}{B : Set ℓ'}(f : A → B) → id ∘ f ≡ f
id-∘ f = refl

extensionality : {ℓ₁ ℓ₂ : Level} → Set (lsuc ℓ₁ ⊔ lsuc ℓ₂)
extensionality {ℓ₁}{ℓ₂} = ∀{A : Set ℓ₁}{B : Set ℓ₂}{f g : A → B} → (∀{a : A} → f a ≡ g a) → f ≡ g

record Iso {ℓ₁ ℓ₂ : Level} (A : Set ℓ₁) (B : Set ℓ₂) : Set (ℓ₁ ⊔ ℓ₂) where
 constructor isIso
 field
   l-inv : A → B
   r-inv : B → A
   l-cancel : r-inv ∘ l-inv ≡ id
   r-cancel : l-inv ∘ r-inv ≡ id


------------------------------------------------------------------------
-- Descending lists
--
-- We present some simple examples to demonstrate
--
-- 1. the concatenation operation on sorted lists obtained by
--    transporting the one on finite multisets, and
--
-- 2. "sorting" finite multisets by converting into sorted lists.
------------------------------------------------------------------------

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

module Cubical.Data.DescendingList.Examples where

open import Cubical.Foundations.Everything

open import Cubical.Data.Empty
open import Cubical.Data.Nat

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

open import Cubical.HITs.FiniteMultiset

------------------------------------------------------------------------
-- The ordering relation on natural numbers
--
-- we work with the definition from the standard library.

infix 4 _≤_ _≥_

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

_≥_ : ℕ → ℕ → Set
m ≥ n = n ≤ m

≤pred : {n m : ℕ} → suc n ≤ suc m → n ≤ m
≤pred (s≤s r) = r

≥isPropValued : {n m : ℕ} → isProp (n ≥ m)
≥isPropValued z≤n z≤n = refl
≥isPropValued (s≤s p) (s≤s q) = cong s≤s (≥isPropValued p q)

≥dec : (x y : ℕ) → Dec (x ≥ y)
≥dec zero zero = yes z≤n
≥dec zero (suc y) = no (λ ())
≥dec (suc x) zero = yes z≤n
≥dec (suc x) (suc y) with ≥dec x y
≥dec (suc x) (suc y) | yes p = yes (s≤s p)
≥dec (suc x) (suc y) | no ¬p = no (λ r → ¬p (≤pred r))

≰→≥ : {x y : ℕ} → ¬ (x ≥ y) → y ≥ x
≰→≥ {zero} {y} f = z≤n
≰→≥ {suc x} {zero} f = ⊥-elim (f z≤n)
≰→≥ {suc x} {suc y} f = s≤s (≰→≥ λ g → f (s≤s g))

≥trans : {x y z : ℕ} → x ≥ y → y ≥ z → x ≥ z
≥trans z≤n z≤n = z≤n
≥trans (s≤s r) z≤n = z≤n
≥trans (s≤s r) (s≤s s) = s≤s (≥trans r s)

≤≥→≡ : {x y : ℕ} → x ≥ y → y ≥ x → x ≡ y
≤≥→≡ z≤n z≤n = refl
≤≥→≡ (s≤s r) (s≤s s) = cong suc (≤≥→≡ r s)

open import Cubical.Data.DescendingList.Base ℕ _≥_
open import Cubical.Data.DescendingList.Properties ℕ _≥_
open isSetDL ≥isPropValued discreteℕ
open IsoToFMSet discreteℕ ≥dec ≥isPropValued ≥trans ≰→≥ ≤≥→≡

------------------------------------------------------------------------
-- A simple example of concatenating sorted lists

l1 : DL
l1 = cons 4 (cons 3 (cons 2 [] ≥ᴴ[]) (≥ᴴcons (s≤s (s≤s z≤n)))) (≥ᴴcons (s≤s (s≤s (s≤s z≤n))))

l2 : DL
l2 = cons 2 (cons 0 [] ≥ᴴ[]) (≥ᴴcons z≤n)

l3 : DL
l3 = l1 ++ᴰᴸ l2

ValueOfl3 : l3 ≡ cons 4 (cons 3 (cons 2 (cons 2 (cons 0 _ _) _) _) _) _
ValueOfl3 = refl

l3=l2++l1 : l3 ≡ l2 ++ᴰᴸ l1
l3=l2++l1 = refl

LongerExample :   l1 ++ᴰᴸ l2 ++ᴰᴸ l1 ++ᴰᴸ l1 ++ᴰᴸ l2
                ≡ l2 ++ᴰᴸ l1 ++ᴰᴸ l2 ++ᴰᴸ l1 ++ᴰᴸ l1
LongerExample = refl

------------------------------------------------------------------------
-- A simple example of sorting finite multisets

m1 : FMSet ℕ
m1 = 13 ∷ 9 ∷ 78 ∷ 31 ∷ 86 ∷ 3 ∷ 0 ∷ 99 ∷ []

m2 : FMSet ℕ
m2 = 3 ∷ 1 ∷ 4 ∷ 1 ∷ 5 ∷ 9 ∷ []

m3 : FMSet ℕ
m3 = toFMSet (toDL (m1 ++ m2))

ValueOfm3 :
        m3 ≡ 99 ∷ 86 ∷ 78 ∷ 31 ∷ 13 ∷ 9 ∷ 9 ∷ 5 ∷ 4 ∷ 3 ∷ 3 ∷ 1 ∷ 1 ∷ 0 ∷ []
ValueOfm3 = refl

ValueOfm1++m2 :
  m1 ++ m2 ≡ 13 ∷ 9 ∷ 78 ∷ 31 ∷ 86 ∷ 3 ∷ 0 ∷ 99 ∷ 3 ∷ 1 ∷ 4 ∷ 1 ∷ 5 ∷ 9 ∷ []
ValueOfm1++m2 = refl

m3=m1++m2 : m3 ≡ m1 ++ m2
m3=m1++m2 = toFMSet∘toDL≡id (m1 ++ m2)


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

open import HoTT
open import homotopy.SuspAdjointLoop
open import cohomology.WithCoefficients

module cohomology.SuspAdjointLoopIso where

module SuspAdjointLoopIso {i j} (X : Ptd i) (Y : Ptd j) where

  module ΣAΩ = SuspAdjointLoop X (⊙Ω Y)
  GSΣ = →Ω-group-structure (⊙Susp X) Y
  GSΩ = →Ω-group-structure X (⊙Ω Y)
  open GroupStructure

  comp-path : (p q : fst (⊙Ω (⊙Ω Y))) → ap2 _∙_ p q == p ∙ q
  comp-path p q = ap2-out _∙_ p q ∙ ap2 _∙_ (lemma p) (ap-idf q)
    where
    lemma : ∀ {i} {A : Type i} {x y : A} {p q : x == y} (α : p == q)
      → ap (λ r → r ∙ idp) α == ∙-unit-r p ∙ α ∙' ! (∙-unit-r q)
    lemma {p = idp} idp = idp

  pres-comp-inner : (H₁ H₂ : fst (⊙Susp X ⊙→ ⊙Ω Y))
    → ΣAΩ.R (comp GSΣ H₁ H₂) == comp GSΩ (ΣAΩ.R H₁) (ΣAΩ.R H₂)
  pres-comp-inner H₁ H₂ =
    transport
       (λ {(op , op-path) →
          ΣAΩ.R (comp GSΣ H₁ H₂) ==
          transport (λ b → Σ (fst X → _) (λ h → h (snd X) == b)) op-path
            (ΣAΩ.comp-lift (snd X) idp idp op (ΣAΩ.R H₁) (ΣAΩ.R H₂))})
       (pair= (λ= (λ p → λ= (comp-path p)))
              {b = idp} {b' = idp} (↓-app=cst-in snd-path))
       (ΣAΩ.pres-comp _∙_ H₁ H₂)
    where
    snd-path : idp == ap (λ f → f idp idp) (λ= (λ p → λ= (comp-path p))) ∙ idp
    snd-path =
      idp
        =⟨ ! (app=-β (comp-path idp) idp) ⟩
      app= (λ= (comp-path idp)) idp
        =⟨ ap (λ q → app= q idp) (! (app=-β (λ p → λ= (comp-path p)) idp)) ⟩
      app= (app= (λ= (λ p → λ= (comp-path p))) idp) idp
        =⟨ ∘-ap (λ z → z idp) (λ z → z idp) (λ= (λ p → λ= (comp-path p))) ⟩
      ap (λ f → f idp idp) (λ= (λ p → λ= (comp-path p)))
        =⟨ ! (∙-unit-r _) ⟩
      ap (λ f → f idp idp) (λ= (λ p → λ= (comp-path p))) ∙ idp ∎

  iso : →Ω-Group (⊙Susp X) Y ≃ᴳ →Ω-Group X (⊙Ω Y)
  iso = Trunc-Group-iso ΣAΩ.R pres-comp-inner (snd (ΣAΩ.eqv))