------------------------------------------------------------------------
-- The Agda standard library
--
-- Pointwise lifting of relations to lists
------------------------------------------------------------------------

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

module Data.List.Relation.Binary.Pointwise where

open import Function.Base
open import Function.Inverse using (Inverse)
open import Data.Bool.Base using (true; false)
open import Data.Product hiding (map)
open import Data.List.Base as List hiding (map; head; tail; uncons)
open import Data.List.Properties using (≡-dec; length-++)
open import Data.List.Relation.Unary.All as All using (All; []; _∷_)
open import Data.List.Relation.Unary.AllPairs using (AllPairs; []; _∷_)
open import Data.List.Relation.Unary.Any using (Any; here; there)
open import Data.Fin.Base using (Fin) renaming (zero to fzero; suc to fsuc)
open import Data.Nat.Base using (ℕ; zero; suc)
open import Data.Nat.Properties
open import Level
open import Relation.Nullary hiding (Irrelevant)
open import Relation.Nullary.Negation using (contradiction)
import Relation.Nullary.Decidable as Dec using (map′)
open import Relation.Nullary.Product using (_×-dec_)
open import Relation.Unary as U using (Pred)
open import Relation.Binary renaming (Rel to Rel₂)
open import Relation.Binary.PropositionalEquality as P using (_≡_)

private
  variable
    a b c d p q r ℓ ℓ₁ ℓ₂ ℓ₃ : Level
    A : Set a
    B : Set b
    C : Set c
    D : Set d

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

infixr 5 _∷_

data Pointwise {A : Set a} {B : Set b} (_∼_ : REL A B ℓ)
               : List A → List B → Set (a ⊔ b ⊔ ℓ) where
  []  : Pointwise _∼_ [] []
  _∷_ : ∀ {x xs y ys} (x∼y : x ∼ y) (xs∼ys : Pointwise _∼_ xs ys) →
        Pointwise _∼_ (x ∷ xs) (y ∷ ys)

------------------------------------------------------------------------
-- Operations

module _ {_∼_ : REL A B ℓ} where

  head : ∀ {x y xs ys} → Pointwise _∼_ (x ∷ xs) (y ∷ ys) → x ∼ y
  head (x∼y ∷ xs∼ys) = x∼y

  tail : ∀ {x y xs ys} → Pointwise _∼_ (x ∷ xs) (y ∷ ys) →
         Pointwise _∼_ xs ys
  tail (x∼y ∷ xs∼ys) = xs∼ys

  uncons : ∀ {x y xs ys} → Pointwise _∼_ (x ∷ xs) (y ∷ ys) →
           x ∼ y × Pointwise _∼_ xs ys
  uncons = < head , tail >

  rec : ∀ (P : ∀ {xs ys} → Pointwise _∼_ xs ys → Set c) →
        (∀ {x y xs ys} {xs∼ys : Pointwise _∼_ xs ys} →
          (x∼y : x ∼ y) → P xs∼ys → P (x∼y ∷ xs∼ys)) →
        P [] →
        ∀ {xs ys} (xs∼ys : Pointwise _∼_ xs ys) → P xs∼ys
  rec P c n []            = n
  rec P c n (x∼y ∷ xs∼ys) = c x∼y (rec P c n xs∼ys)

  map : ∀ {_≈_ : REL A B ℓ₂} → _≈_ ⇒ _∼_ → Pointwise _≈_ ⇒ Pointwise _∼_
  map ≈⇒∼ []            = []
  map ≈⇒∼ (x≈y ∷ xs≈ys) = ≈⇒∼ x≈y ∷ map ≈⇒∼ xs≈ys

------------------------------------------------------------------------
-- Relational properties

reflexive : ∀ {_≈_ : REL A B ℓ₁} {_∼_ : REL A B ℓ₂} →
            _≈_ ⇒ _∼_ → Pointwise _≈_ ⇒ Pointwise _∼_
reflexive ≈⇒∼ []            = []
reflexive ≈⇒∼ (x≈y ∷ xs≈ys) = ≈⇒∼ x≈y ∷ reflexive ≈⇒∼ xs≈ys

refl : ∀ {_∼_ : Rel₂ A ℓ} → Reflexive _∼_ → Reflexive (Pointwise _∼_)
refl rfl {[]}     = []
refl rfl {x ∷ xs} = rfl ∷ refl rfl

symmetric : ∀ {_≈_ : REL A B ℓ₁} {_∼_ : REL B A ℓ₂} →
            Sym _≈_ _∼_ → Sym (Pointwise _≈_) (Pointwise _∼_)
symmetric sym []            = []
symmetric sym (x∼y ∷ xs∼ys) = sym x∼y ∷ symmetric sym xs∼ys

transitive : ∀ {_≋_ : REL A B ℓ₁} {_≈_ : REL B C ℓ₂} {_∼_ : REL A C ℓ₃} →
             Trans _≋_ _≈_ _∼_ →
             Trans (Pointwise _≋_) (Pointwise _≈_) (Pointwise _∼_)
transitive trans []            []            = []
transitive trans (x∼y ∷ xs∼ys) (y∼z ∷ ys∼zs) =
  trans x∼y y∼z ∷ transitive trans xs∼ys ys∼zs

antisymmetric : ∀ {_≤_ : REL A B ℓ₁} {_≤′_ : REL B A ℓ₂} {_≈_ : REL A B ℓ₃} →
                Antisym _≤_ _≤′_ _≈_ →
                Antisym (Pointwise _≤_) (Pointwise _≤′_) (Pointwise _≈_)
antisymmetric antisym []            []            = []
antisymmetric antisym (x∼y ∷ xs∼ys) (y∼x ∷ ys∼xs) =
  antisym x∼y y∼x ∷ antisymmetric antisym xs∼ys ys∼xs

respects₂ : ∀ {_≈_ : Rel₂ A ℓ₁} {_∼_ : Rel₂ A ℓ₂} →
            _∼_ Respects₂ _≈_ → (Pointwise _∼_) Respects₂ (Pointwise _≈_)
respects₂ {_≈_ = _≈_} {_∼_} resp = respʳ , respˡ
  where
  respʳ : (Pointwise _∼_) Respectsʳ (Pointwise _≈_)
  respʳ []            []            = []
  respʳ (x≈y ∷ xs≈ys) (z∼x ∷ zs∼xs) =
    proj₁ resp x≈y z∼x ∷ respʳ xs≈ys zs∼xs

  respˡ : (Pointwise _∼_) Respectsˡ (Pointwise _≈_)
  respˡ []            []            = []
  respˡ (x≈y ∷ xs≈ys) (x∼z ∷ xs∼zs) =
    proj₂ resp x≈y x∼z ∷ respˡ xs≈ys xs∼zs

module _ {_∼_ : REL A B ℓ} (dec : Decidable _∼_) where

  decidable : Decidable (Pointwise _∼_)
  decidable []       []       = yes []
  decidable []       (y ∷ ys) = no (λ ())
  decidable (x ∷ xs) []       = no (λ ())
  decidable (x ∷ xs) (y ∷ ys) =
    Dec.map′ (uncurry _∷_) uncons (dec x y ×-dec decidable xs ys)

module _ {_≈_ : Rel₂ A ℓ} where

  isEquivalence : IsEquivalence _≈_ → IsEquivalence (Pointwise _≈_)
  isEquivalence eq = record
    { refl  = refl       Eq.refl
    ; sym   = symmetric  Eq.sym
    ; trans = transitive Eq.trans
    } where module Eq = IsEquivalence eq

  isDecEquivalence : IsDecEquivalence _≈_ → IsDecEquivalence (Pointwise _≈_)
  isDecEquivalence eq = record
    { isEquivalence = isEquivalence DE.isEquivalence
    ; _≟_           = decidable     DE._≟_
    } where module DE = IsDecEquivalence eq

module _ {_≈_ : Rel₂ A ℓ₁} {_∼_ : Rel₂ A ℓ₂} where

  isPreorder : IsPreorder _≈_ _∼_ → IsPreorder (Pointwise _≈_) (Pointwise _∼_)
  isPreorder pre = record
    { isEquivalence = isEquivalence Pre.isEquivalence
    ; reflexive     = reflexive     Pre.reflexive
    ; trans         = transitive    Pre.trans
    } where module Pre = IsPreorder pre

  isPartialOrder : IsPartialOrder _≈_ _∼_ →
                   IsPartialOrder (Pointwise _≈_) (Pointwise _∼_)
  isPartialOrder po = record
    { isPreorder = isPreorder    PO.isPreorder
    ; antisym    = antisymmetric PO.antisym
    } where module PO = IsPartialOrder po

setoid : Setoid a ℓ → Setoid a (a ⊔ ℓ)
setoid s = record
  { isEquivalence = isEquivalence (Setoid.isEquivalence s)
  }

decSetoid : DecSetoid a ℓ → DecSetoid a (a ⊔ ℓ)
decSetoid d = record
  { isDecEquivalence = isDecEquivalence (DecSetoid.isDecEquivalence d)
  }

preorder : Preorder a ℓ₁ ℓ₂ → Preorder _ _ _
preorder p = record
  { isPreorder = isPreorder (Preorder.isPreorder p)
  }

poset : Poset a ℓ₁ ℓ₂ → Poset _ _ _
poset p = record
  { isPartialOrder = isPartialOrder (Poset.isPartialOrder p)
  }

------------------------------------------------------------------------
-- Relationships to other predicates

module _ {_∼_ : Rel₂ A ℓ} {P : Pred A p} where

  All-resp-Pointwise : P Respects _∼_ → (All P) Respects (Pointwise _∼_)
  All-resp-Pointwise resp []         []         = []
  All-resp-Pointwise resp (x∼y ∷ xs) (px ∷ pxs) =
    resp x∼y px ∷ All-resp-Pointwise resp xs pxs

  Any-resp-Pointwise : P Respects _∼_ → (Any P) Respects (Pointwise _∼_)
  Any-resp-Pointwise resp (x∼y ∷ xs) (here px)   = here (resp x∼y px)
  Any-resp-Pointwise resp (x∼y ∷ xs) (there pxs) = there (Any-resp-Pointwise resp xs pxs)

module _ {_∼_ : Rel₂ A ℓ} {R : Rel₂ A r} where

  AllPairs-resp-Pointwise : R Respects₂ _∼_ → (AllPairs R) Respects (Pointwise _∼_)
  AllPairs-resp-Pointwise _                    []         []         = []
  AllPairs-resp-Pointwise resp@(respₗ , respᵣ) (x∼y ∷ xs) (px ∷ pxs) =
    All-resp-Pointwise respₗ xs (All.map (respᵣ x∼y) px) ∷ (AllPairs-resp-Pointwise resp xs pxs)

------------------------------------------------------------------------
-- length

module _ {_∼_ : REL A B ℓ} where

  Pointwise-length : ∀ {xs ys} → Pointwise _∼_ xs ys →
                     length xs ≡ length ys
  Pointwise-length []            = P.refl
  Pointwise-length (x∼y ∷ xs∼ys) = P.cong ℕ.suc (Pointwise-length xs∼ys)

------------------------------------------------------------------------
-- tabulate

module _ {_∼_ : REL A B ℓ} where

  tabulate⁺ : ∀ {n} {f : Fin n → A} {g : Fin n → B} →
              (∀ i → f i ∼ g i) → Pointwise _∼_ (tabulate f) (tabulate g)
  tabulate⁺ {zero}  f∼g = []
  tabulate⁺ {suc n} f∼g = f∼g fzero ∷ tabulate⁺ (f∼g ∘ fsuc)

  tabulate⁻ : ∀ {n} {f : Fin n → A} {g : Fin n → B} →
              Pointwise _∼_ (tabulate f) (tabulate g) → (∀ i → f i ∼ g i)
  tabulate⁻ {suc n} (x∼y ∷ xs∼ys) fzero    = x∼y
  tabulate⁻ {suc n} (x∼y ∷ xs∼ys) (fsuc i) = tabulate⁻ xs∼ys i

------------------------------------------------------------------------
-- _++_

module _ {_∼_ : REL A B ℓ} where

  ++⁺ : ∀ {ws xs ys zs} → Pointwise _∼_ ws xs → Pointwise _∼_ ys zs →
        Pointwise _∼_ (ws ++ ys) (xs ++ zs)
  ++⁺ []            ys∼zs = ys∼zs
  ++⁺ (w∼x ∷ ws∼xs) ys∼zs = w∼x ∷ ++⁺ ws∼xs ys∼zs

module _ {_∼_ : Rel₂ A ℓ} where

  ++-cancelˡ : ∀ xs {ys zs : List A} → Pointwise _∼_ (xs ++ ys) (xs ++ zs) → Pointwise _∼_ ys zs
  ++-cancelˡ []       ys∼zs               = ys∼zs
  ++-cancelˡ (x ∷ xs) (_ ∷ xs++ys∼xs++zs) = ++-cancelˡ xs xs++ys∼xs++zs

  ++-cancelʳ : ∀ {xs : List A} ys zs → Pointwise _∼_ (ys ++ xs) (zs ++ xs) → Pointwise _∼_ ys zs
  ++-cancelʳ []       []       _             = []
  ++-cancelʳ (y ∷ ys) (z ∷ zs) (y∼z ∷ ys∼zs) = y∼z ∷ (++-cancelʳ ys zs ys∼zs)
  -- Impossible cases
  ++-cancelʳ {xs}     []       (z ∷ zs) eq   =
    contradiction (P.trans (Pointwise-length eq) (length-++ (z ∷ zs))) (m≢1+n+m (length xs))
  ++-cancelʳ {xs}     (y ∷ ys) []       eq   =
    contradiction (P.trans (P.sym (length-++ (y ∷ ys))) (Pointwise-length eq)) (m≢1+n+m (length xs) ∘ P.sym)

------------------------------------------------------------------------
-- concat

module _ {_∼_ : REL A B ℓ} where

  concat⁺ : ∀ {xss yss} → Pointwise (Pointwise _∼_) xss yss →
            Pointwise _∼_ (concat xss) (concat yss)
  concat⁺ []                = []
  concat⁺ (xs∼ys ∷ xss∼yss) = ++⁺ xs∼ys (concat⁺ xss∼yss)

------------------------------------------------------------------------
-- reverse

module _ {R : REL A B ℓ} where

  reverseAcc⁺ : ∀ {as bs as′ bs′} → Pointwise R as′ bs′ → Pointwise R as bs →
                Pointwise R (reverseAcc as′ as) (reverseAcc bs′ bs)
  reverseAcc⁺ rs′ []       = rs′
  reverseAcc⁺ rs′ (r ∷ rs) = reverseAcc⁺ (r ∷ rs′) rs

  ʳ++⁺ : ∀ {as bs as′ bs′} →
           Pointwise R as bs →
           Pointwise R as′ bs′ →
           Pointwise R (as ʳ++ as′) (bs ʳ++ bs′)
  ʳ++⁺ rs rs′ = reverseAcc⁺ rs′ rs

  reverse⁺ : ∀ {as bs} → Pointwise R as bs → Pointwise R (reverse as) (reverse bs)
  reverse⁺ = reverseAcc⁺ []

------------------------------------------------------------------------
-- map

module _ {R : REL C D ℓ} where

  map⁺ : ∀ {as bs} (f : A → C) (g : B → D) →
         Pointwise (λ a b → R (f a) (g b)) as bs →
         Pointwise R (List.map f as) (List.map g bs)
  map⁺ f g []       = []
  map⁺ f g (r ∷ rs) = r ∷ map⁺ f g rs

  map⁻ : ∀ {as bs} (f : A → C) (g : B → D) →
         Pointwise R (List.map f as) (List.map g bs) →
         Pointwise (λ a b → R (f a) (g b)) as bs
  map⁻ {as = []}     {[]}     f g [] = []
  map⁻ {as = []}     {b ∷ bs} f g rs = contradiction (Pointwise-length rs) λ()
  map⁻ {as = a ∷ as} {[]}     f g rs = contradiction (Pointwise-length rs) λ()
  map⁻ {as = a ∷ as} {b ∷ bs} f g (r ∷ rs) = r ∷ map⁻ f g rs

------------------------------------------------------------------------
-- filter

module _ {R : REL A B ℓ} {P : Pred A p} {Q : Pred B q}
         (P? : U.Decidable P) (Q? : U.Decidable Q)
         (P⇒Q : ∀ {a b} → R a b → P a → Q b)
         (Q⇒P : ∀ {a b} → R a b → Q b → P a)
         where

  filter⁺ : ∀ {as bs} → Pointwise R as bs → Pointwise R (filter P? as) (filter Q? bs)
  filter⁺ []       = []
  filter⁺ {a ∷ _} {b ∷ _} (r ∷ rs) with P? a | Q? b
  ... | true  because _ | true  because _ = r ∷ filter⁺ rs
  ... | false because _ | false because _ = filter⁺ rs
  ... | yes p | no ¬q = contradiction (P⇒Q r p) ¬q
  ... | no ¬p | yes q = contradiction (Q⇒P r q) ¬p

------------------------------------------------------------------------
-- replicate

module _ {R : REL A B ℓ} where

  replicate⁺ : ∀ {a b} → R a b → ∀ n → Pointwise R (replicate n a) (replicate n b)
  replicate⁺ r 0       = []
  replicate⁺ r (suc n) = r ∷ replicate⁺ r n

------------------------------------------------------------------------
-- Irrelevance

module _ {R : REL A B ℓ} where

  irrelevant : Irrelevant R → Irrelevant (Pointwise R)
  irrelevant R-irr [] [] = P.refl
  irrelevant R-irr (r ∷ rs) (r₁ ∷ rs₁) =
    P.cong₂ _∷_ (R-irr r r₁) (irrelevant R-irr rs rs₁)

------------------------------------------------------------------------
-- Properties of propositional pointwise

Pointwise-≡⇒≡ : Pointwise {A = A} _≡_ ⇒ _≡_
Pointwise-≡⇒≡ []               = P.refl
Pointwise-≡⇒≡ (P.refl ∷ xs∼ys) with Pointwise-≡⇒≡ xs∼ys
... | P.refl = P.refl

≡⇒Pointwise-≡ :  _≡_ ⇒ Pointwise {A = A} _≡_
≡⇒Pointwise-≡ P.refl = refl P.refl

Pointwise-≡↔≡ : Inverse (setoid (P.setoid A)) (P.setoid (List A))
Pointwise-≡↔≡ = record
  { to         = record { _⟨$⟩_ = id; cong = Pointwise-≡⇒≡ }
  ; from       = record { _⟨$⟩_ = id; cong = ≡⇒Pointwise-≡ }
  ; inverse-of = record
    { left-inverse-of  = λ _ → refl P.refl
    ; right-inverse-of = λ _ → P.refl
    }
  }

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

-- Version 0.15

Rel    = Pointwise
{-# WARNING_ON_USAGE Rel
"Warning: Rel was deprecated in v0.15.
Please use Pointwise instead."
#-}
Rel≡⇒≡ = Pointwise-≡⇒≡
{-# WARNING_ON_USAGE Rel≡⇒≡
"Warning: Rel≡⇒≡ was deprecated in v0.15.
Please use Pointwise-≡⇒≡ instead."
#-}
≡⇒Rel≡ = ≡⇒Pointwise-≡
{-# WARNING_ON_USAGE ≡⇒Rel≡
"Warning: ≡⇒Rel≡ was deprecated in v0.15.
Please use ≡⇒Pointwise-≡ instead."
#-}
Rel↔≡  = Pointwise-≡↔≡
{-# WARNING_ON_USAGE Rel↔≡
"Warning: Rel↔≡ was deprecated in v0.15.
Please use Pointwise-≡↔≡ instead."
#-}

-- Version 1.0

decidable-≡ = ≡-dec
{-# WARNING_ON_USAGE decidable-≡
"Warning: decidable-≡ was deprecated in v1.0.
Please use ≡-dec from `Data.List.Properties` instead."
#-}


open import Agda.Builtin.List
open import Agda.Builtin.Reflection
open import Agda.Builtin.Unit
open import Agda.Builtin.Nat

-- setup

infixl 5 _>>=_
_>>=_ = bindTC

defToTerm : Name → Definition → List (Arg Term) → Term
defToTerm _ (function cs) as = pat-lam cs as
defToTerm _ (data-cons d) as = con d as
defToTerm _ _ _ = unknown

derefImmediate : Term → TC Term
derefImmediate (def f args) = getDefinition f >>= λ f' → returnTC (defToTerm f f' args)
derefImmediate x = returnTC x

macro
  reflect : ∀ {ℓ} {t : Set ℓ} → t → Term → TC ⊤
  reflect x a = quoteTC x >>= derefImmediate >>= quoteTC >>= unify a

  unfold : Name → Term → TC ⊤
  unfold x a = getDefinition x >>= λ d → unify a (defToTerm x d [])

-- crash

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

vid vid' : ∀ n → Vec Nat n → Vec Nat n
vid n [] = []
vid n (x ∷ xs) = x ∷ xs

vid' = unfold vid

crash : Term
crash = reflect vid

len : ∀ {n} → Vec Nat n → Nat
len [] = 0
len (x ∷ xs) = suc (len xs)

-- Forces different order in clause tel and patterns
f f' : ∀ n → Vec Nat n → Vec Nat n → Nat
f n xs [] = n
f n xs (y ∷ ys) = n + y + len xs + len ys

f' = unfold f


module Ambient where

open import Relation.Nullary
     using (yes; no)

open import Data.String
     using (String; _≟_)

open import Data.Bool
     using (Bool; true; false)

open import Relation.Binary.PropositionalEquality
     using (_≢_; refl)
     renaming (_≡_ to _≡≡_)

open import Data.List
     using (List; []; _∷_; _++_; filter)

-- Local modules ---------------------------------------------------------------

open import Common
     using (Id)

open import Capability
     using (Capability; `_; In; Out; Open; ε; _∙_)
     renaming (_[_/_] to _[_/_]-capa; freeVar to freeVar-capa)

-- Process Definition ----------------------------------------------------------

infix  40 _[_/_]
infixr 30 Λ_∙_
infix  20 _[_]
infixr 10 _||_

data Process : Set where
  ν_∙_   : Id → Process → Process                 -- Restriction
  Zero   : Process                                -- Inactivity
  _||_   : Process → Process → Process            -- Composition
  !_     : Process → Process                      -- Replication
  _[_]   : Capability → Process → Process         -- Ambient
  _∙_    : Capability → Process → Process         -- Action
  Λ_∙_ : Id → Process → Process                 -- Input Action
  <_>    : Capability → Process                   -- Message

-- Free variable ---------------------------------------------------------------

_-_ : List Id → Id → List Id
[] - _      = []
(x ∷ xs) - y with x ≟ y
... | yes _ = xs - y
... | no _  = x ∷ (xs - y)

freeVar : Process → List Id
freeVar (ν x ∙ P) = freeVar P
freeVar Zero      = []
freeVar (P || Q)  = (freeVar P) ++ (freeVar Q)
freeVar (! P)     = freeVar P
freeVar (M [ P ]) = (freeVar-capa M) ++ (freeVar P)
freeVar (M ∙ P)   = (freeVar-capa M) ++ (freeVar P)
freeVar (Λ x ∙ P) = (freeVar P) - x
freeVar (< M >)   = freeVar-capa M

_∉_ : Id → List Id → Set
y ∉ l = member y l ≡≡ false
    where member : Id → List Id →  Bool -- Should propably use the List filter instead!
          member y []     = false
          member y (x ∷ xs) with x ≟ y
          ... | yes _ = true
          ... | no _  = member y xs

-- Process substitution --------------------------------------------------------

_[_/_] : Process → Id → Capability → Process

Zero [ _ / _ ]       = Zero
(P || Q) [ x / M ]   = P [ x / M ] || Q [ x / M ]
(! P) [ x / M ]      = ! (P [ x / M ])
(x [ P ]) [ y / M ]  = (x [ y / M ]-capa) [ P [ y / M ] ]
(ν x ∙ P) [ y / M ] with x ≟ y
... | yes _          = ν x ∙ P
... | no _           = ν x ∙ (P [ y / M ])
< N > [ x / M ]      = < N [ x / M ]-capa >
(Λ x ∙ P) [ y / M ] with x ≟ y
... | yes _          = Λ x ∙ P
... | no _           = Λ x ∙ (P [ y / M ])
( N ∙ P) [ x / M ]   = (N [ x / M ]-capa) ∙ (P [ x / M ])

module Test where
  a = "a"
  b = "b"

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

  _ : (` a [ < ` b > ]) [ b / Open a ] ≡≡ ` a [ < Open a > ]
  _ = refl

  _ : (< ` a > || < ` b >) [ b / Open a ] ≡≡ < ` a > || < Open a >
  _ = refl

-- Congruence ------------------------------------------------------------------

infix 5 _≡_

data _≡_ : Process → Process → Set where
  Struct-Refl    : ∀ {P}
                   -----
                 → P ≡ P

  Struct-Symm    : ∀ {P Q}
                 → P ≡ Q
                   -----
                 → Q ≡ P

  Struct-Trans   : ∀ {P Q R}
                 → P ≡ Q → Q ≡ R
                   -------------
                 → P ≡ R

  Struct-Res     : ∀ {n P Q}
                 → P ≡ Q
                   -----------------
                 → ν n ∙ P ≡ ν n ∙ Q

  Struct-Par     : ∀ {P Q R}
                 → P ≡ Q
                   ---------------
                 → P || R ≡ Q || R

  Struct-Repl    : ∀ {P Q}
                 → P ≡ Q
                   ---------
                 → ! P ≡ ! Q

  Struct-Amb     : ∀ {M P Q}
                 → P ≡ Q
                   -----------------
                 → M [ P ] ≡ M [ Q ]

  Struct-Action  : ∀ {M P Q}
                 → P ≡ Q
                   -------------
                 → M ∙ P ≡ M ∙ Q

  Struct-Input   : ∀ {x P Q}
                 → P ≡ Q
                   ---------------------
                 → Λ x ∙ P ≡ Λ x ∙ Q

  Struct-Comm    : ∀ {P Q}
                 → P ≡ Q
                   -----
                 → Q ≡ P

  Struct-Assoc   : ∀ {P Q R}
                   -----------------------------
                 → (P || Q) || R ≡ P || (Q || R)

  Struct-ResRes  : ∀ {n m P}
                 → n ≢ m
                   -----------------------------
                 → ν n ∙ ν m ∙ P ≡ ν m ∙ ν n ∙ P

  Struct-ResPar  : ∀ {n P Q}
                 → n ∉ freeVar(P)
                   -----------------------------
                 → ν n ∙ (P || Q) ≡ P || ν n ∙ Q

  Struct-ResAmb  : ∀ {n m P}
                 → n ≢ m
                   -----------------------------------
                 → ν n ∙ (` m [ P ]) ≡ ` m [ ν n ∙ P ]

  Struct-ZeroPar : ∀ {P}
                   -------------
                 → P || Zero ≡ P

  Struct-ZeroRes : ∀ {n}
                   -----------------
                 → ν n ∙ Zero ≡ Zero

  Struct-ZeroRep : ! Zero ≡ Zero

  Struct-ε       : ---------------
                   ε ∙ Zero ≡ Zero

  Struct-∙       : ∀ {M M' P}
                   ---------------------------
                 → (M ∙ M') ∙ P ≡ M ∙ (M' ∙ P)

-- Reduction rules -------------------------------------------------------------

infix 5 _~>_

data _~>_ : Process → Process → Set where
  Red-In    : ∀ {m n P Q R}
              -----------------------------------------------------------------
            → ` m [ In n ∙ P || Q ] || ` n [ R ] ~> ` n [ ` m [ P || Q ] || R ]

  Red-Out   : ∀ {m n P Q R}
              ------------------------------------------------------------------
            → ` m [ ` n [ Out m ∙ P || R ] || Q ] ~> ` m [ Q ] || ` n [ P || R ]

  Red-Open  : ∀ {m P Q}
              ---------------------------------
            → ` m [ P ] || Open m ∙ Q ~> P || Q

  Red-I/O   : ∀ {M x P}
              ---------------------------------
            → < M > || Λ x ∙ P ~> P [ x / M ]

  Red-Par   : ∀ {P Q R}
            → P ~> Q
              ------------------
            → P || R ~> Q || R

  Red-Res   : ∀ {n P Q}
            → P ~> Q
              --------------------
            → ν n ∙ P ~> ν n ∙ Q

  Red-Amb   : ∀ {M P Q}
            → P ~> Q
              --------------------
            → M [ P ] ~> M [ Q ]

  Red-≡     : ∀ {P P' Q Q'}
            → P' ≡ P  → P ~> Q → Q ≡ Q'
              -------------------------
            → P' ~> Q'

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


-- Andreas, 2015-06-29 polarity handling is broken
-- See also issue 1592

-- {-# OPTIONS -v tc.polarity:20 -v tc.proj.like:100 #-}
-- {-# OPTIONS -v tc.conv.elim:25 --show-implicit #-}

open import Common.Size
open import Common.Prelude

data D : Size → Set where
  c : ∀ i → D (↑ i)

record Type (a : Bool) : Set1 where
  constructor mkType
  field type : Set
open Type

Opp : Set → Set
Opp X = X → ⊥

-- projection-like contravariant function which does not unfold
abstract
  Contra : ∀ a (T : Type a) → Set
  Contra a (mkType A) = Opp A

-- Subtyping is broken for projection(-like) things.
-- This is exploitable as  Contra true (mkType X)  does not reduce to Opp X here.
cast : ∀{i} → Contra true (mkType (D i)) → Contra true (mkType (D (↑ i)))
cast x = x

-- Here it, does reduce.
abstract
  loop : ∀{i} → D i → ⊥
  loop (c i) = cast loop (c i)

absurd : ⊥
absurd = loop (c ∞)


------------------------------------------------------------------------
-- Laws related to return⋆
------------------------------------------------------------------------

module TotalParserCombinators.Laws.ReturnStar where

open import Algebra
open import Category.Monad
open import Codata.Musical.Notation
open import Data.List
import Data.List.Categorical
open import Data.List.Relation.Binary.BagAndSetEquality as Eq
  using (bag) renaming (_∼[_]_ to _List-∼[_]_)
open import Function
open import Level

private
  module BagMonoid {A : Set} =
    CommutativeMonoid (Eq.commutativeMonoid bag A)
  open module ListMonad =
    RawMonad {f = zero} Data.List.Categorical.monad
    using () renaming (_⊛_ to _⊛′_; _>>=_ to _>>=′_)

open import TotalParserCombinators.Derivative using (D)
open import TotalParserCombinators.Congruence
  hiding (fail)
import TotalParserCombinators.Laws.AdditiveMonoid as AdditiveMonoid
open import TotalParserCombinators.Laws.Derivative
open import TotalParserCombinators.Lib
open import TotalParserCombinators.Parser

-- return⋆ preserves equality.

cong : ∀ {k Tok R} {xs₁ xs₂ : List R} →
       xs₁ List-∼[ k ] xs₂ → return⋆ {Tok = Tok} xs₁ ∼[ k ]P return⋆ xs₂
cong {xs₁ = xs₁} {xs₂} xs₁≈xs₂ = xs₁≈xs₂ ∷ λ t → ♯ (
  D t (return⋆ xs₁)  ≅⟨ D-return⋆ xs₁ ⟩
  fail               ≅⟨ sym $ D-return⋆ xs₂ ⟩
  D t (return⋆ xs₂)  ∎)

-- return⋆ is homomorphic with respect to _++_/_∣_.

distrib-∣ :
  ∀ {Tok R} (xs₁ xs₂ : List R) →
  return⋆ {Tok = Tok} (xs₁ ++ xs₂) ≅P return⋆ xs₁ ∣ return⋆ xs₂
distrib-∣ xs₁ xs₂ =
  BagMonoid.refl ∷ λ t → ♯ (
    D t (return⋆ (xs₁ ++ xs₂))             ≅⟨ D-return⋆ (xs₁ ++ xs₂) ⟩
    fail                                   ≅⟨ sym $ AdditiveMonoid.left-identity fail ⟩
    fail ∣ fail                            ≅⟨ sym $ D-return⋆ xs₁ ∣ D-return⋆ xs₂ ⟩
    D t (return⋆ xs₁) ∣ D t (return⋆ xs₂)  ∎)

-- return⋆ is homomorphic with respect to _⊛′_/_⊛_.

distrib-⊛ :
  ∀ {Tok R₁ R₂} (fs : List (R₁ → R₂)) xs →
  return⋆ {Tok = Tok} (fs ⊛′ xs) ≅P return⋆ fs ⊛ return⋆ xs
distrib-⊛ fs xs =
  BagMonoid.refl ∷ λ t → ♯ (
    D t (return⋆ (fs ⊛′ xs))         ≅⟨ D-return⋆ (fs ⊛′ xs) ⟩

    fail                             ≅⟨ sym $ AdditiveMonoid.left-identity fail ⟩

    fail ∣ fail                      ≅⟨ sym $ left-zero-⊛ (return⋆ xs) ∣
                                              right-zero-⊛ (return⋆ fs) ⟩
    fail ⊛ return⋆ xs ∣
    return⋆ fs ⊛ fail                ≅⟨ sym $ [ ○ - ○ - ○ - ○ ] D-return⋆ fs ⊛ (return⋆ xs ∎) ∣
                                              [ ○ - ○ - ○ - ○ ] return⋆ fs ∎ ⊛ D-return⋆ xs ⟩
    D t (return⋆ fs) ⊛ return⋆ xs ∣
    return⋆ fs ⊛ D t (return⋆ xs)    ≅⟨ sym $ D-⊛ (return⋆ fs) (return⋆ xs) ⟩

    D t (return⋆ fs ⊛ return⋆ xs)    ∎)

-- return⋆ is homomorphic with respect to _>>=′_/_>>=_.

distrib->>= :
  ∀ {Tok R₁ R₂} xs (f : R₁ → List R₂) →
  return⋆ {Tok = Tok} (xs >>=′ f) ≅P return⋆ xs >>= (return⋆ ∘ f)
distrib->>= xs f =
  BagMonoid.refl ∷ λ t → ♯ (
    D t (return⋆ (xs >>=′ f))                   ≅⟨ D-return⋆ (xs >>=′ f) ⟩

    fail                                        ≅⟨ sym $ AdditiveMonoid.left-identity fail ⟩

    fail ∣ fail                                 ≅⟨ sym $ left-zero->>=  (return⋆ ∘ f) ∣
                                                         right-zero->>= (return⋆ xs) ⟩
    fail >>= (return⋆ ∘ f) ∣
    return⋆ xs >>= (λ _ → fail)                 ≅⟨ sym $ [ ○ - ○ - ○ - ○ ] D-return⋆ xs >>= (λ x → return⋆ (f x) ∎) ∣
                                                         [ ○ - ○ - ○ - ○ ] return⋆ xs ∎ >>= (λ x → D-return⋆ (f x)) ⟩
    D t (return⋆ xs) >>= (return⋆ ∘ f) ∣
    return⋆ xs >>= (λ x → D t (return⋆ (f x)))  ≅⟨ sym $ D->>= (return⋆ xs) (return⋆ ∘ f) ⟩

    D t (return⋆ xs >>= (return⋆ ∘ f))          ∎)


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

open import lib.Basics
open import lib.types.Paths
open import lib.types.Sigma
open import lib.types.Span
open import lib.types.Pointed
open import lib.types.Pushout

module lib.types.Join  where

module _ {i j} (A : Type i) (B : Type j) where

  *-span : Span
  *-span = span A B (A × B) fst snd

  infix 80 _*_

  _*_ : Type _
  _*_ = Pushout *-span

module JoinElim {i j} {A : Type i} {B : Type j} {k} {P : A * B → Type k}
  (left* : (a : A) → P (left a)) (right* : (b : B) → P (right b))
  (glue* : (ab : A × B) → left* (fst ab) == right* (snd ab) [ P ↓ glue ab ])
  = PushoutElim left* right* glue*
open JoinElim public using () renaming (f to Join-elim)

module JoinRec {i j} {A : Type i} {B : Type j} {k} {D : Type k}
  (left* : (a : A) → D) (right* : (b : B) → D)
  (glue* : (ab : A × B) → left* (fst ab) == right* (snd ab))
  = PushoutRec left* right* glue*
open JoinRec public using () renaming (f to Join-rec)

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

  *-⊙span : ⊙Span
  *-⊙span = ⊙span X Y (X ⊙× Y) ⊙fst ⊙snd

  infix 80 _⊙*_

  _⊙*_ : Ptd _
  _⊙*_ = ⊙Pushout *-⊙span

module _ {i i' j j'} {A : Type i} {A' : Type i'} {B : Type j} {B' : Type j'} where

  equiv-* : A ≃ A' → B ≃ B' → A * B ≃ A' * B'
  equiv-* eqA eqB = equiv to from to-from from-to where
    module To = JoinRec {D = A' * B'} (left ∘ –> eqA) (right ∘ –> eqB) (λ{(a , b) → glue (–> eqA a , –> eqB b)})
    module From = JoinRec {D = A * B} (left ∘ <– eqA) (right ∘ <– eqB) (λ{(a , b) → glue (<– eqA a , <– eqB b)})

    to : A * B → A' * B'
    to = To.f

    from : A' * B' → A * B
    from = From.f

    to-from : ∀ y → to (from y) == y
    to-from = Join-elim (ap left ∘ <–-inv-r eqA) (ap right ∘ <–-inv-r eqB) to-from-glue where
      to-from-glue : ∀ (ab : A' × B')
        → ap left (<–-inv-r eqA (fst ab)) == ap right (<–-inv-r eqB (snd ab)) [ (λ y → to (from y) == y) ↓ glue ab ]
      to-from-glue (a , b) = ↓-app=idf-in $
        ap left (<–-inv-r eqA a) ∙' glue (a , b)
          =⟨ htpy-natural'-app=cst (λ a → glue (a , b)) (<–-inv-r eqA a) ⟩
        glue (–> eqA (<– eqA a) , b)
          =⟨ ! $ htpy-natural-cst=app (λ b → glue (–> eqA (<– eqA a) , b)) (<–-inv-r eqB b) ⟩
        glue (–> eqA (<– eqA a) , –> eqB (<– eqB b)) ∙ ap right (<–-inv-r eqB b)
          =⟨ ! $ To.glue-β (<– eqA a , <– eqB b) |in-ctx (_∙ ap right (<–-inv-r eqB b)) ⟩
        ap to (glue (<– eqA a , <– eqB b)) ∙ ap right (<–-inv-r eqB b)
          =⟨ ! $ From.glue-β (a , b) |in-ctx (λ p → ap to p ∙ ap right (<–-inv-r eqB b)) ⟩
        ap to (ap from (glue (a , b))) ∙ ap right (<–-inv-r eqB b)
          =⟨ ! $ ap-∘ to from (glue (a , b)) |in-ctx (_∙ ap right (<–-inv-r eqB b)) ⟩
        ap (to ∘ from) (glue (a , b)) ∙ ap right (<–-inv-r eqB b)
          ∎

    from-to : ∀ x → from (to x) == x
    from-to = Join-elim (ap left ∘ <–-inv-l eqA) (ap right ∘ <–-inv-l eqB) from-to-glue where
      from-to-glue : ∀ (ab : A × B)
        → ap left (<–-inv-l eqA (fst ab)) == ap right (<–-inv-l eqB (snd ab)) [ (λ x → from (to x) == x) ↓ glue ab ]
      from-to-glue (a , b) = ↓-app=idf-in $
        ap left (<–-inv-l eqA a) ∙' glue (a , b)
          =⟨ htpy-natural'-app=cst (λ a → glue (a , b)) (<–-inv-l eqA a) ⟩
        glue (<– eqA (–> eqA a) , b)
          =⟨ ! $ htpy-natural-cst=app (λ b → glue (<– eqA (–> eqA a) , b)) (<–-inv-l eqB b) ⟩
        glue (<– eqA (–> eqA a) , <– eqB (–> eqB b)) ∙ ap right (<–-inv-l eqB b)
          =⟨ ! $ From.glue-β (–> eqA a , –> eqB b) |in-ctx (_∙ ap right (<–-inv-l eqB b)) ⟩
        ap from (glue (–> eqA a , –> eqB b)) ∙ ap right (<–-inv-l eqB b)
          =⟨ ! $ To.glue-β (a , b) |in-ctx (λ p → ap from p ∙ ap right (<–-inv-l eqB b)) ⟩
        ap from (ap to (glue (a , b))) ∙ ap right (<–-inv-l eqB b)
          =⟨ ! $ ap-∘ from to (glue (a , b)) |in-ctx (_∙ ap right (<–-inv-l eqB b)) ⟩
        ap (from ∘ to) (glue (a , b)) ∙ ap right (<–-inv-l eqB b)
          ∎

module _ {i i' j j'} {X : Ptd i} {X' : Ptd i'} {Y : Ptd j} {Y' : Ptd j'} where

  ⊙equiv-⊙* : X ⊙≃ X' → Y ⊙≃ Y' → X ⊙* Y ⊙≃ X' ⊙* Y'
  ⊙equiv-⊙* ⊙eqX ⊙eqY = ⊙≃-in (equiv-* (fst (⊙≃-out ⊙eqX)) (fst (⊙≃-out ⊙eqY))) (ap left (snd (⊙≃-out ⊙eqX)))


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

open import Agda.Builtin.Equality

module Case₀ where

  postulate
    I : Set
    P : I → Set

  variable
    p : P _

  postulate
    D : P _ → Set
    d : D p

module Case₁ where

  postulate
    I : Set
    P : I → Set
    Q : ∀ n → P n → Set

  variable
    q : Q _ _

  postulate
    D : ∀ {p} → Q _ p → Set
    d : D q

module Case₂ where

  postulate
    I : Set
    P : I → Set
    Q : ∀ n → P n → Set

  record R n (p : P n) : Set where
    constructor c
    field
      f : Q _ p

  variable
    q : Q _ _

  data D {p} : R _ p → Set where
    d : D (c q)

module Case₃ where

  variable
    A : Set
    a : A

  record B : Set where
    id = λ x → x ≡ x
    field
      b : id a


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

-- This is a utility module.
module Utils where

open import Induction.WellFounded as Wf
open import Data.List as List
open import Data.List.All
open import Data.Nat
open import Data.Maybe
open import Data.Product as ,
open import Data.Empty
open import Function

open import Relation.Nullary
open import Relation.Binary
open import Relation.Binary.PropositionalEquality

infix 6 _!
_! : ∀ {a} {A : Set a} → A → List A
a ! = a ∷ []

infixl 5 _‣_
_‣_ : ∀ {a} {A : Set a} → List A → List A → List A
l₁ ‣ l₂ = l₂ ++ l₁

lookupOpt : ∀ {a} {A : Set a} → List A → ℕ → Maybe A
lookupOpt [] n            = nothing
lookupOpt (x ∷ l) zero    = just x
lookupOpt (x ∷ l) (suc n) = lookupOpt l n

module _ {a} {A : Set a} where
  lookupOpt-map-inv : ∀ {b} {B : Set b} {f : A → B} l {n e} →
                        lookupOpt (List.map f l) n ≡ just e →
                        ∃[ e' ] (e ≡ f e' × lookupOpt l n ≡ just e')
  lookupOpt-map-inv [] {n} ()
  lookupOpt-map-inv (x ∷ l) {zero} refl = x , refl , refl
  lookupOpt-map-inv (x ∷ l) {suc n} eq  = lookupOpt-map-inv l eq

  lookupOpt-map : ∀ {b} {B : Set b} l (f : A → B) {n e} →
                    lookupOpt l n ≡ just e →
                    lookupOpt (List.map f l) n ≡ just (f e)
  lookupOpt-map [] f ()
  lookupOpt-map (x ∷ l) f {zero} refl = refl
  lookupOpt-map (x ∷ l) f {suc n} eq  = lookupOpt-map l f eq

  lookupOpt-All : ∀ {b} {P : A → Set b} {l n e} →
                    lookupOpt l n ≡ just e →
                    All P l →
                    P e
  lookupOpt-All {n = n} () []
  lookupOpt-All {n = zero} refl (px ∷ all) = px
  lookupOpt-All {n = suc n} eq (px ∷ all)  = lookupOpt-All eq all

  lookupOpt-app₁ : ∀ (l₁ l₂ : List A) {n} →
                     n < length l₁ →
                     lookupOpt (l₁ ++ l₂) n ≡ lookupOpt l₁ n
  lookupOpt-app₁ [] l₂ {n} ()
  lookupOpt-app₁ (x ∷ l₁) l₂ {zero} (s≤s n<l) = refl
  lookupOpt-app₁ (x ∷ l₁) l₂ {suc n} (s≤s n<l) = lookupOpt-app₁ l₁ l₂ n<l

  lookupOpt-app₂ : ∀ (l₁ l₂ : List A) n →
                     lookupOpt (l₁ ++ l₂) (length l₁ + n) ≡ lookupOpt l₂ n
  lookupOpt-app₂ [] l₂ n       = refl
  lookupOpt-app₂ (x ∷ l₁) l₂ n = lookupOpt-app₂ l₁ l₂ n

repeat : ∀ {a} {A : Set a} → ℕ → (f : A → A) → A → A
repeat zero f = id
repeat (suc n) f = f ∘ (repeat n f)

≤?-yes : ∀ {m n} (m≤n : m ≤ n) → (m ≤? n) ≡ yes m≤n
≤?-yes z≤n           = refl
≤?-yes (s≤s m≤n)
  rewrite ≤?-yes m≤n = refl

≤?-no : ∀ {m n} (m>n : ¬ m ≤ n) → ∃ λ ¬p → (m ≤? n) ≡ no ¬p
≤?-no {m} {n} m>n with m ≤? n
... | yes p = ⊥-elim $ m>n p
... | no _  = -, refl

module Measure {a b ℓ} {A : Set a} {B : Set b} {_≺_ : Rel A ℓ}
               (≺-wf : WellFounded _≺_)
               (m : B → A) where

  open import Level using () renaming (zero to lzero)
  import Relation.Binary.Reasoning.Base.Triple as Triple
  open Wf.Inverse-image {_<_ = _≺_} m using (wellFounded)

  open Wf.All (wellFounded ≺-wf) lzero using (wfRec) public

module LexicographicMeasure {a b c d ℓ₁ ℓ₂}
                            {A : Set a} {B : A → Set b}
                            {C : Set c} {D : C → Set d}
                            {_≺A_ : Rel A ℓ₁}
                            {[_]_≺B_ : ∀ x → Rel (B x) ℓ₂}
                            (≺A-wf : WellFounded _≺A_)
                            (≺B-wf : ∀ {x} → WellFounded ([ x ]_≺B_))
                            (mC : C → A)
                            (mD : ∀ {c} → D c → B (mC c)) where
  open import Level using () renaming (zero to lzero)
  module Lex = Wf.Lexicographic _≺A_ [_]_≺B_
  open Lex renaming (wellFounded to lex-wf ; _<_ to _≺′_)
  open Lex using (left ; right) public
  open Wf.Inverse-image renaming (wellFounded to m-wf)

  measure : Σ C D → Σ A B
  measure (c , d) = mC c , mD d

  ΣAB-wf : WellFounded _≺′_
  ΣAB-wf = lex-wf ≺A-wf ≺B-wf

  infix 3 _≺_
  _≺_ = _≺′_ on ,.map mC mD

  measure-wf : WellFounded _≺_
  measure-wf = m-wf measure ΣAB-wf

  open Wf.All measure-wf lzero using (wfRec) public


{-

  Functions building UARels and DUARels on Σ-types

-}
{-# OPTIONS --safe #-}
module Cubical.Displayed.Sigma where

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

open import Cubical.Data.Sigma

open import Cubical.Displayed.Base
open import Cubical.Displayed.Subst
open import Cubical.Displayed.Morphism
open import Cubical.Displayed.Constant

private
  variable
    ℓ ℓA ℓA' ℓP ℓ≅A ℓ≅A' ℓB ℓB' ℓ≅B ℓ≅B' ℓC ℓ≅C : Level

-- UARel on a Σ-type

∫ˢ : {A : Type ℓA} {𝒮-A : UARel A ℓ≅A} {B : A → Type ℓB} (𝒮ˢ-B : SubstRel 𝒮-A B)
  → UARel (Σ A B) (ℓ-max ℓ≅A ℓB)
∫ˢ 𝒮ˢ-B = ∫ (Subst→DUA 𝒮ˢ-B)

_×𝒮_ : {A : Type ℓA} (𝒮-A : UARel A ℓ≅A) {B : Type ℓB} (𝒮-B : UARel B ℓ≅B)
  → UARel (A × B) (ℓ-max ℓ≅A ℓ≅B)
𝒮-A ×𝒮 𝒮-B = ∫ (𝒮ᴰ-const 𝒮-A 𝒮-B)

-- Projection UARel morphisms

𝒮-fst : {A : Type ℓA} {𝒮-A : UARel A ℓ≅A} {B : A → Type ℓB} {𝒮ᴰ-B : DUARel 𝒮-A B ℓ≅B}
  → UARelHom (∫ 𝒮ᴰ-B) 𝒮-A
𝒮-fst .UARelHom.fun = fst
𝒮-fst .UARelHom.rel = fst
𝒮-fst .UARelHom.ua p = refl

𝒮-snd : {A : Type ℓA} {𝒮-A : UARel A ℓ≅A} {B : Type ℓB} {𝒮-B : UARel B ℓ≅B}
  → UARelHom (𝒮-A ×𝒮 𝒮-B) 𝒮-B
𝒮-snd .UARelHom.fun = snd
𝒮-snd .UARelHom.rel = snd
𝒮-snd .UARelHom.ua p = refl

-- Lift a DUARel to live over a Σ-type

𝒮ᴰ-Lift : {A : Type ℓA} (𝒮-A : UARel A ℓ≅A) {B : A → Type ℓB} (𝒮ᴰ-B : DUARel 𝒮-A B ℓ≅B)
  {C : A → Type ℓC} (𝒮ᴰ-C : DUARel 𝒮-A C ℓ≅C)
  → DUARel (∫ 𝒮ᴰ-C) (λ (a , _) → B a) ℓ≅B
𝒮ᴰ-Lift _  𝒮ᴰ-B _ = 𝒮ᴰ-reindex 𝒮-fst 𝒮ᴰ-B

-- DUARel on a Σ-type

module _ {A : Type ℓA} {𝒮-A : UARel A ℓ≅A}
  {B : A → Type ℓB} {ℓ≅B : Level} (𝒮ᴰ-B : DUARel 𝒮-A B ℓ≅B)
  {C : Σ A B → Type ℓC} {ℓ≅C : Level} (𝒮ᴰ-C : DUARel (∫ 𝒮ᴰ-B) C ℓ≅C)
  where

  open UARel 𝒮-A
  private
    module B = DUARel 𝒮ᴰ-B
    module C = DUARel 𝒮ᴰ-C

  𝒮ᴰ-Σ : DUARel 𝒮-A (λ a → Σ[ b ∈ B a ] C (a , b)) (ℓ-max ℓ≅B ℓ≅C)
  DUARel._≅ᴰ⟨_⟩_ 𝒮ᴰ-Σ (b , c) p (b' , c') =
    Σ[ q ∈ b B.≅ᴰ⟨ p ⟩ b' ]  (c C.≅ᴰ⟨ p , q ⟩ c')
  DUARel.uaᴰ 𝒮ᴰ-Σ (b ,  c) p (b' , c') =
    compEquiv
      (Σ-cong-equiv (B.uaᴰ b p b') (λ q → C.uaᴰ c (p , q) c'))
      ΣPath≃PathΣ

-- DUARel on a non-dependent Σ-type

module _ {A : Type ℓA} {𝒮-A : UARel A ℓ≅A}
  {B : A → Type ℓB} {ℓ≅B : Level} (𝒮ᴰ-B : DUARel 𝒮-A B ℓ≅B)
  {C : A → Type ℓC} {ℓ≅C : Level} (𝒮ᴰ-C : DUARel 𝒮-A C ℓ≅C)
  where

  _×𝒮ᴰ_ : DUARel 𝒮-A (λ a → B a × C a) (ℓ-max ℓ≅B ℓ≅C)
  _×𝒮ᴰ_ = 𝒮ᴰ-Σ 𝒮ᴰ-B (𝒮ᴰ-Lift 𝒮-A 𝒮ᴰ-C 𝒮ᴰ-B)

-- SubstRel on a Σ-type

module _ {A : Type ℓA} {𝒮-A : UARel A ℓ≅A}
  {B : A → Type ℓB} (𝒮ˢ-B : SubstRel 𝒮-A B)
  {C : Σ A B → Type ℓC} (𝒮ˢ-C : SubstRel (∫ˢ 𝒮ˢ-B) C)
  where

  open UARel 𝒮-A
  open SubstRel
  private
    module B = SubstRel 𝒮ˢ-B
    module C = SubstRel 𝒮ˢ-C

  𝒮ˢ-Σ : SubstRel 𝒮-A (λ a → Σ[ b ∈ B a ] C (a , b))
  𝒮ˢ-Σ .act p = Σ-cong-equiv (B.act p) (λ b → C.act (p , refl))
  𝒮ˢ-Σ .uaˢ p _ =
    fromPathP
      (DUARel.uaᴰ (𝒮ᴰ-Σ (Subst→DUA 𝒮ˢ-B) (Subst→DUA 𝒮ˢ-C))  _ p _ .fst (refl , refl))

-- SubstRel on a non-dependent product

module _ {A : Type ℓA} {𝒮-A : UARel A ℓ≅A}
  {B : A → Type ℓB} (𝒮ˢ-B : SubstRel 𝒮-A B)
  {C : A → Type ℓC} (𝒮ˢ-C : SubstRel 𝒮-A C)
  where

  open UARel 𝒮-A
  open SubstRel
  private
    module B = SubstRel 𝒮ˢ-B
    module C = SubstRel 𝒮ˢ-C

  _×𝒮ˢ_ : SubstRel 𝒮-A (λ a → B a × C a)
  _×𝒮ˢ_ .act p = ≃-× (B.act p) (C.act p)
  _×𝒮ˢ_ .uaˢ p (b , c) = ΣPathP (B.uaˢ p b , C.uaˢ p c)


------------------------------------------------------------------------
-- The Agda standard library
--
-- Some properties imply others
------------------------------------------------------------------------

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

module Relation.Unary.Consequences where

open import Relation.Unary
open import Relation.Nullary using (recompute)

dec⟶recomputable : {a ℓ : _} {A : Set a} {P : Pred A ℓ} → Decidable P → Recomputable P
dec⟶recomputable P-dec = recompute (P-dec _)


------------------------------------------------------------------------------
-- Properties stated in the Burstall's paper
------------------------------------------------------------------------------

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

module FOTC.Program.SortList.PropertiesI where

open import Common.FOL.Relation.Binary.EqReasoning

open import FOTC.Base
open import FOTC.Base.List
open import FOTC.Data.Bool
open import FOTC.Data.Bool.PropertiesI
open import FOTC.Data.Nat.Inequalities
open import FOTC.Data.Nat.Inequalities.PropertiesI
open import FOTC.Data.Nat.List.Type
open import FOTC.Data.Nat.Type
open import FOTC.Data.List
open import FOTC.Data.List.PropertiesI
open import FOTC.Program.SortList.Properties.Totality.BoolI
open import FOTC.Program.SortList.Properties.Totality.ListN-I
open import FOTC.Program.SortList.Properties.Totality.OrdList.FlattenI
open import FOTC.Program.SortList.Properties.Totality.OrdListI
open import FOTC.Program.SortList.Properties.Totality.OrdTreeI
open import FOTC.Program.SortList.Properties.Totality.TreeI
open import FOTC.Program.SortList.SortList

------------------------------------------------------------------------------
-- Induction on lit.
ind-lit : (A : D → Set) (f : D) → ∀ y₀ {xs} → ListN xs →
          A y₀ →
          (∀ {x} → N x → ∀ y → A y → A (f · x · y)) →
          A (lit f xs y₀)
ind-lit A f y₀ lnnil Ay₀ ih = subst A (sym (lit-[] f y₀)) Ay₀
ind-lit A f y₀ (lncons {i} {is} Ni LNis) Ay₀ ih =
  subst A
        (sym (lit-∷ f i is y₀))
        (ih Ni (lit f is y₀) (ind-lit A f y₀ LNis Ay₀ ih))

------------------------------------------------------------------------------
-- Burstall's lemma: If t is ordered then totree(i, t) is ordered.
toTree-OrdTree : ∀ {item t} → N item → Tree t → OrdTree t →
                 OrdTree (toTree · item · t)
toTree-OrdTree {item} Nitem tnil _ =
  ordTree (toTree · item · nil)
    ≡⟨ subst (λ x → ordTree (toTree · item · nil) ≡
                    ordTree x)
             (toTree-nil item)
             refl
    ⟩
  ordTree (tip item)
    ≡⟨ ordTree-tip item ⟩
  true ∎

toTree-OrdTree {item} Nitem (ttip {i} Ni) _ =
  case prf₁ prf₂ (x>y∨x≤y Ni Nitem)
  where
  prf₁ : i > item → OrdTree (toTree · item · tip i)
  prf₁ i>item =
    ordTree (toTree · item · tip i)
      ≡⟨ subst (λ t → ordTree (toTree · item · tip i) ≡ ordTree t)
               (toTree-tip item i)
               refl
      ⟩
    ordTree (if (le i item)
               then (node (tip i) item (tip item))
               else (node (tip item) i (tip i)))
      ≡⟨ subst (λ t → ordTree (if (le i item)
                                 then (node (tip i) item (tip item))
                                 else (node (tip item) i (tip i))) ≡
                      ordTree (if t
                                 then (node (tip i) item (tip item))
                                 else (node (tip item) i (tip i))))
               (x>y→x≰y Ni Nitem i>item)
                 refl
      ⟩
    ordTree (if false
               then (node (tip i) item (tip item))
               else (node (tip item) i (tip i)))
      ≡⟨ subst (λ t → ordTree (if false
                                 then (node (tip i) item (tip item))
                                 else (node (tip item) i (tip i))) ≡
                              ordTree t)
               (if-false (node (tip item) i (tip i)))
               refl
      ⟩
    ordTree (node (tip item) i (tip i))
      ≡⟨ ordTree-node (tip item) i (tip i) ⟩
    ordTree (tip item)
    && ordTree (tip i)
    && le-TreeItem (tip item) i
    && le-ItemTree i (tip i)
      ≡⟨ subst (λ t → ordTree (tip item)
                      && ordTree (tip i)
                      && le-TreeItem (tip item) i
                      && le-ItemTree i (tip i) ≡
                      t
                      && ordTree (tip i)
                      && le-TreeItem (tip item) i
                      && le-ItemTree i (tip i))
               (ordTree-tip item)
               refl
      ⟩
    true && ordTree (tip i) && le-TreeItem (tip item) i &&
    le-ItemTree i (tip i)
      ≡⟨ subst (λ t → true
                      && ordTree (tip i)
                      && le-TreeItem (tip item) i
                      && le-ItemTree i (tip i) ≡
                      true
                      && t
                      && le-TreeItem (tip item) i
                      && le-ItemTree i (tip i))
               (ordTree-tip i)
               refl
      ⟩
    true && true && le-TreeItem (tip item) i && le-ItemTree i (tip i)
      ≡⟨ subst (λ t → true && true && le-TreeItem (tip item) i &&
                      le-ItemTree i (tip i) ≡
                      true && true && t && le-ItemTree i (tip i))
               (le-TreeItem-tip item i)
               refl
      ⟩
    true && true && le item i && le-ItemTree i (tip i)
      ≡⟨ subst (λ t → true && true && le item i && le-ItemTree i (tip i) ≡
                      true && true && t && le-ItemTree i (tip i))
               (x<y→x≤y Nitem Ni i>item)
               refl
      ⟩
    true && true && true && le-ItemTree i (tip i)
      ≡⟨ subst (λ t → true && true && true && le-ItemTree i (tip i) ≡
                      true && true && true && t)
               (le-ItemTree-tip i i)
               refl
      ⟩
    true && true && true && le i i
      ≡⟨ subst (λ t → true && true && true && le i i ≡
                      true && true && true && t)
               (x≤x Ni)
               refl
      ⟩
    true && true && true && true
      ≡⟨ subst (λ t → true && true && true && true ≡ true && true && t)
               (t&&x≡x true)
               refl
      ⟩
    true && true && true
      ≡⟨ subst (λ t → true && true && true ≡ true && t)
               (t&&x≡x true)
               refl
      ⟩
    true && true
      ≡⟨ t&&x≡x true ⟩
    true ∎

  prf₂ : i ≤ item → OrdTree (toTree · item · tip i)
  prf₂ i≤item =
    ordTree (toTree · item · tip i)
      ≡⟨ subst (λ t → ordTree (toTree · item · tip i) ≡ ordTree t)
               (toTree-tip item i)
               refl
      ⟩
    ordTree (if (le i item)
               then (node (tip i) item (tip item))
               else (node (tip item) i (tip i)))
      ≡⟨ subst (λ t → ordTree (if (le i item)
                                 then (node (tip i) item (tip item))
                                 else (node (tip item) i (tip i))) ≡
                      ordTree (if t
                                 then (node (tip i) item (tip item))
                                 else (node (tip item) i (tip i))))
               i≤item
               refl
      ⟩
    ordTree (if true
               then (node (tip i) item (tip item))
               else (node (tip item) i (tip i)))
      ≡⟨ subst (λ t → ordTree (if true
                                 then (node (tip i) item (tip item))
                                 else (node (tip item) i (tip i))) ≡
                      ordTree t)
               (if-true (node (tip i) item (tip item)))
               refl
      ⟩
    ordTree (node (tip i) item (tip item))
      ≡⟨ ordTree-node (tip i) item (tip item) ⟩
    ordTree (tip i) && ordTree (tip item) && le-TreeItem (tip i) item &&
    le-ItemTree item (tip item)
      ≡⟨ subst (λ t → ordTree (tip i)             &&
                      ordTree (tip item)          &&
                      le-TreeItem (tip i) item     &&
                      le-ItemTree item (tip item)  ≡
                      t                           &&
                      ordTree (tip item)          &&
                      le-TreeItem (tip i) item     &&
                      le-ItemTree item (tip item))
               (ordTree-tip i)
               refl
      ⟩
    true && ordTree (tip item) && le-TreeItem (tip i) item &&
    le-ItemTree item (tip item)
      ≡⟨ subst (λ t → true                        &&
                      ordTree (tip item)          &&
                      le-TreeItem (tip i) item     &&
                      le-ItemTree item (tip item)  ≡
                      true                        &&
                      t                           &&
                      le-TreeItem (tip i) item     &&
                      le-ItemTree item (tip item))
               (ordTree-tip item)
               refl
      ⟩
    true && true && le-TreeItem (tip i) item && le-ItemTree item (tip item)
      ≡⟨ subst (λ t → true && true && le-TreeItem (tip i) item &&
                      le-ItemTree item (tip item) ≡
                      true && true && t && le-ItemTree item (tip item))
               (le-TreeItem-tip i item)
               refl
      ⟩
    true && true && le i item && le-ItemTree item (tip item)
      ≡⟨ subst (λ t → true && true && le i item && le-ItemTree item (tip item) ≡
                      true && true && t && le-ItemTree item (tip item))
               i≤item
               refl
      ⟩
    true && true && true && le-ItemTree item (tip item)
      ≡⟨ subst (λ t → true && true && true && le-ItemTree item (tip item) ≡
                      true && true && true && t)
               (le-ItemTree-tip item item)
               refl
      ⟩
    true && true && true && le item item
      ≡⟨ subst (λ t → true && true && true && le item item ≡
                      true && true && true && t)
               (x≤x Nitem)
               refl
      ⟩
    true && true && true && true
      ≡⟨ subst (λ t → true && true && true && true ≡ true && true && t)
               (t&&x≡x true)
               refl
      ⟩
    true && true && true
      ≡⟨ subst (λ t → true && true && true ≡ true && t) (t&&x≡x true) refl ⟩
    true && true
      ≡⟨ t&&x≡x true ⟩
    true ∎

toTree-OrdTree {item} Nitem (tnode {t₁} {i} {t₂} Tt₁ Ni Tt₂) OTtnode =
  case prf₁ prf₂ (x>y∨x≤y Ni Nitem)
  where
  prf₁ : i > item → OrdTree (toTree · item · node t₁ i t₂)
  prf₁ i>item =
    ordTree (toTree · item · node t₁ i t₂)
      ≡⟨ subst (λ t → ordTree (toTree · item · node t₁ i t₂) ≡ ordTree t)
               (toTree-node item t₁ i t₂)
               refl
      ⟩
    ordTree (if (le i item)
               then (node t₁ i (toTree · item · t₂))
               else (node (toTree · item · t₁) i t₂))
      ≡⟨ subst (λ t → ordTree (if (le i item)
                                 then (node t₁ i (toTree · item · t₂))
                                 else (node (toTree · item · t₁) i t₂)) ≡
                      ordTree (if t
                                 then (node t₁ i (toTree · item · t₂))
                                 else (node (toTree · item · t₁) i t₂)))
               (x>y→x≰y Ni Nitem i>item)
               refl
      ⟩
    ordTree (if false
               then (node t₁ i (toTree · item · t₂))
               else (node (toTree · item · t₁) i t₂))
      ≡⟨ subst (λ t → ordTree (if false
                                 then (node t₁ i (toTree · item · t₂))
                                 else (node (toTree · item · t₁) i t₂)) ≡
                      ordTree t)
               (if-false (node (toTree · item · t₁) i t₂))
               refl
      ⟩
    ordTree (node (toTree · item · t₁) i t₂)
      ≡⟨ ordTree-node (toTree · item · t₁) i t₂ ⟩
    ordTree (toTree · item · t₁)      &&
    ordTree t₂                        &&
    le-TreeItem (toTree · item · t₁) i &&
    le-ItemTree i t₂
      ≡⟨ subst (λ t → ordTree (toTree · item · t₁)      &&
                      ordTree t₂                        &&
                      le-TreeItem (toTree · item · t₁) i &&
                      le-ItemTree i t₂                   ≡
                      t                                 &&
                      ordTree t₂                        &&
                      le-TreeItem (toTree · item · t₁) i &&
                      le-ItemTree i t₂)
               (toTree-OrdTree Nitem Tt₁
                               (leftSubTree-OrdTree Tt₁ Ni Tt₂ OTtnode))
               refl
      ⟩
    true && ordTree t₂ && le-TreeItem (toTree · item · t₁) i &&
    le-ItemTree i t₂
      ≡⟨ subst (λ t → true                              &&
                      ordTree t₂                        &&
                      le-TreeItem (toTree · item · t₁) i &&
                      le-ItemTree i t₂                   ≡
                      true                              &&
                      t                                 &&
                      le-TreeItem (toTree · item · t₁) i &&
                      le-ItemTree i t₂)
               (rightSubTree-OrdTree Tt₁ Ni Tt₂ OTtnode)
               refl
      ⟩
    true && true && le-TreeItem (toTree · item · t₁) i && le-ItemTree i t₂
      ≡⟨ subst (λ t → true                              &&
                      true                              &&
                      le-TreeItem (toTree · item · t₁) i &&
                      le-ItemTree i t₂                   ≡
                      true && true && t && le-ItemTree i t₂)
               (toTree-OrdTree-helper₁ Ni Nitem i>item Tt₁
                 ((&&-list₄-t₃
                   (ordTree-Bool Tt₁)
                   (ordTree-Bool Tt₂)
                   (le-TreeItem-Bool Tt₁ Ni)
                   (le-ItemTree-Bool Ni Tt₂)
                   (trans (sym (ordTree-node t₁ i t₂)) OTtnode))))
               refl
      ⟩
    true && true && true && le-ItemTree i t₂
      ≡⟨ subst (λ t → true && true && true && le-ItemTree i t₂ ≡
                      true && true && true && t)
               (&&-list₄-t₄
                 (ordTree-Bool Tt₁)
                 (ordTree-Bool Tt₂)
                 (le-TreeItem-Bool Tt₁ Ni)
                 (le-ItemTree-Bool Ni Tt₂)
                 (trans (sym (ordTree-node t₁ i t₂)) OTtnode))
               refl
      ⟩
    true && true && true && true
      ≡⟨ subst (λ t → true && true && true && true ≡ true && true && t)
               (t&&x≡x true)
               refl
      ⟩
    true && true && true
      ≡⟨ subst (λ t → true && true && true ≡ true && t) (t&&x≡x true) refl ⟩
    true && true
      ≡⟨ t&&x≡x true ⟩
    true ∎

  prf₂ : i ≤ item → OrdTree (toTree · item · node t₁ i t₂)
  prf₂ i≤item =
    ordTree (toTree · item · node t₁ i t₂)
      ≡⟨ subst (λ t → ordTree (toTree · item · node t₁ i t₂) ≡ ordTree t)
               (toTree-node item t₁ i t₂)
               refl
      ⟩
    ordTree (if (le i item)
               then (node t₁ i (toTree · item · t₂))
               else (node (toTree · item · t₁) i t₂))
      ≡⟨ subst (λ t → ordTree (if (le i item)
                                 then (node t₁ i (toTree · item · t₂))
                                 else (node (toTree · item · t₁) i t₂)) ≡
                      ordTree (if t
                                 then (node t₁ i (toTree · item · t₂))
                                 else (node (toTree · item · t₁) i t₂)))
               i≤item
               refl
      ⟩
    ordTree (if true
               then (node t₁ i (toTree · item · t₂))
               else (node (toTree · item · t₁) i t₂))
      ≡⟨ subst (λ t → ordTree (if true
                                 then (node t₁ i (toTree · item · t₂))
                                 else (node (toTree · item · t₁) i t₂)) ≡
                      ordTree t)
               (if-true (node t₁ i (toTree · item · t₂)))
               refl
      ⟩
    ordTree (node t₁ i (toTree · item · t₂))
      ≡⟨ ordTree-node t₁ i (toTree · item · t₂) ⟩
    ordTree t₁                     &&
    ordTree (toTree · item · t₂)   &&
    le-TreeItem t₁ i                &&
    le-ItemTree i (toTree · item · t₂)
      ≡⟨ subst (λ t → ordTree t₁                        &&
                      ordTree (toTree · item · t₂)      &&
                      le-TreeItem t₁ i                   &&
                      le-ItemTree i (toTree · item · t₂) ≡
                      t                                 &&
                      ordTree (toTree · item · t₂)      &&
                      le-TreeItem t₁ i                   &&
                      le-ItemTree i (toTree · item · t₂))
               (leftSubTree-OrdTree Tt₁ Ni Tt₂ OTtnode)
               refl
      ⟩
    true && ordTree (toTree · item · t₂) && le-TreeItem t₁ i &&
    le-ItemTree i (toTree · item · t₂)
      ≡⟨ subst (λ t → true                              &&
                      ordTree (toTree · item · t₂)      &&
                      le-TreeItem t₁ i                   &&
                      le-ItemTree i (toTree · item · t₂) ≡
                      true                              &&
                      t                                 &&
                      le-TreeItem t₁ i                   &&
                      le-ItemTree i (toTree · item · t₂))
               (toTree-OrdTree Nitem Tt₂
                 (rightSubTree-OrdTree Tt₁ Ni Tt₂ OTtnode))
               refl
      ⟩
    true && true && le-TreeItem t₁ i && le-ItemTree i (toTree · item · t₂)
      ≡⟨ subst (λ t → true                              &&
                      true                              &&
                      le-TreeItem t₁ i                   &&
                      le-ItemTree i (toTree · item · t₂) ≡
                      true                              &&
                      true                              &&
                      t                                 &&
                      le-ItemTree i (toTree · item · t₂))
               (&&-list₄-t₃
                 (ordTree-Bool Tt₁)
                 (ordTree-Bool Tt₂)
                 (le-TreeItem-Bool Tt₁ Ni)
                 (le-ItemTree-Bool Ni Tt₂)
                 (trans (sym (ordTree-node t₁ i t₂)) OTtnode))
               refl
      ⟩
    true && true && true && le-ItemTree i (toTree · item · t₂)
      ≡⟨ subst (λ t → true                              &&
                      true                              &&
                      true                              &&
                      le-ItemTree i (toTree · item · t₂) ≡
                      true && true && true && t)
               (toTree-OrdTree-helper₂ Ni Nitem i≤item Tt₂
                 ((&&-list₄-t₄
                   (ordTree-Bool Tt₁)
                     (ordTree-Bool Tt₂)
                     (le-TreeItem-Bool Tt₁ Ni)
                     (le-ItemTree-Bool Ni Tt₂)
                     (trans (sym (ordTree-node t₁ i t₂)) OTtnode))))
                 refl
      ⟩
    true && true && true && true
      ≡⟨ subst (λ t → true && true && true && true ≡ true && true && t)
               (t&&x≡x true)
               refl
      ⟩
    true && true && true
      ≡⟨ subst (λ t → true && true && true ≡ true && t) (t&&x≡x true) refl ⟩
    true && true
      ≡⟨ t&&x≡x true ⟩
    true ∎

------------------------------------------------------------------------------
-- Burstall's lemma: ord(maketree(is)).

-- makeTree-TreeOrd : ∀ {is} → ListN is → OrdTree (makeTree is)
-- makeTree-TreeOrd LNis =
--   ind-lit OrdTree toTree nil LNis ordTree-nil
--           (λ Nx y TOy → toTree-OrdTree Nx {!!} TOy)

makeTree-OrdTree : ∀ {is} → ListN is → OrdTree (makeTree is)
makeTree-OrdTree lnnil =
  ordTree (lit toTree [] nil)
    ≡⟨ subst (λ t → ordTree (lit toTree [] nil) ≡ ordTree t)
             (lit-[] toTree nil)
             refl
    ⟩
  ordTree nil
    ≡⟨ ordTree-nil ⟩
  true ∎

makeTree-OrdTree (lncons {i} {is} Ni Lis) =
  ordTree (lit toTree (i ∷ is) nil)
    ≡⟨ subst (λ t → ordTree (lit toTree (i ∷ is) nil) ≡ ordTree t)
             (lit-∷ toTree i is nil)
             refl
    ⟩
  ordTree (toTree · i · (lit toTree is nil))
    ≡⟨ toTree-OrdTree Ni (makeTree-Tree Lis) (makeTree-OrdTree Lis) ⟩
  true ∎

------------------------------------------------------------------------------
-- Burstall's lemma: If ord(is1) and ord(is2) and is1 ≤ is2 then
-- ord(concat(is1, is2)).
++-OrdList : ∀ {is js} → ListN is → ListN js → OrdList is → OrdList js →
             ≤-Lists is js → OrdList (is ++ js)

++-OrdList {js = js} lnnil LNjs LOis LOjs is≤js =
  subst OrdList (sym (++-leftIdentity js)) LOjs

++-OrdList {js = js} (lncons {i} {is} Ni LNis) LNjs LOi∷is LOjs i∷is≤js =
  subst OrdList (sym (++-∷ i is js)) lemma
  where
  lemma : OrdList (i ∷ is ++ js)
  lemma =
    ordList (i ∷ is ++ js)
      ≡⟨ ordList-∷ i (is ++ js) ⟩
    le-ItemList i (is ++ js) && ordList (is ++ js)
      ≡⟨ subst (λ t → le-ItemList i (is ++ js) && ordList (is ++ js) ≡
                      t && ordList (is ++ js))
               (++-OrdList-helper Ni LNis LNjs
                 (&&-list₂-t₁ (le-ItemList-Bool Ni LNis)
                              (ordList-Bool LNis)
                              (trans (sym (ordList-∷ i is)) LOi∷is))
                 (&&-list₂-t₁ (le-ItemList-Bool Ni LNjs)
                              (le-Lists-Bool LNis LNjs)
                              (trans (sym (le-Lists-∷ i is js)) i∷is≤js))
                 (&&-list₂-t₂ (le-ItemList-Bool Ni LNjs)
                              (le-Lists-Bool LNis LNjs)
                              (trans (sym (le-Lists-∷ i is js)) i∷is≤js))
               )
               refl
      ⟩
    true && ordList (is ++ js)
      ≡⟨ subst (λ t → true && ordList (is ++ js) ≡ true && t)
               (++-OrdList LNis LNjs (subList-OrdList Ni LNis LOi∷is) LOjs
                           (&&-list₂-t₂
                             (le-ItemList-Bool Ni LNjs)
                             (le-Lists-Bool LNis LNjs)
                             (trans (sym (le-Lists-∷ i is js)) i∷is≤js)))
               refl
      ⟩
    true && true
      ≡⟨ t&&x≡x true ⟩
    true ∎

------------------------------------------------------------------------------
-- Burstall's lemma: If t is ordered then (flatten t) is ordered.
flatten-OrdList : ∀ {t} → Tree t → OrdTree t → OrdList (flatten t)
flatten-OrdList tnil OTt =
  subst OrdList (sym flatten-nil) ordList-[]

flatten-OrdList (ttip {i} Ni) OTt =
  ordList (flatten (tip i))
    ≡⟨ subst (λ t → ordList (flatten (tip i)) ≡ ordList t)
             (flatten-tip i)
             refl
    ⟩
  ordList (i ∷ [])
    ≡⟨ ordList-∷ i [] ⟩
  le-ItemList i [] && ordList []
    ≡⟨ subst₂ (λ t₁ t₂ → le-ItemList i [] && ordList [] ≡ t₁ && t₂)
              (le-ItemList-[] i)
              ordList-[]
              refl
    ⟩
  true && true
    ≡⟨ t&&x≡x true ⟩
  true ∎

flatten-OrdList (tnode {t₁} {i} {t₂} Tt₁ Ni Tt₂) OTt =
  ordList (flatten (node t₁ i t₂))
    ≡⟨ subst (λ t → ordList (flatten (node t₁ i t₂)) ≡ ordList t)
             (flatten-node t₁ i t₂)
             refl
    ⟩
  ordList (flatten t₁ ++ flatten t₂)
    ≡⟨ ++-OrdList (flatten-ListN Tt₁)
                  (flatten-ListN Tt₂)
                  (flatten-OrdList Tt₁ (leftSubTree-OrdTree Tt₁ Ni Tt₂ OTt))
                  (flatten-OrdList Tt₂ (rightSubTree-OrdTree Tt₁ Ni Tt₂ OTt))
                  (flatten-OrdList-helper Tt₁ Ni Tt₂ OTt)
    ⟩
  true ∎


-- Andreas, 2012-09-13
-- (The signature on the previous line does not apply to all of the
-- text in this file.)
module RelevanceSubtyping where

-- this naturally type-checks:
one : {A B : Set} → (.A → B) → A → B
one f x = f x

-- Subtyping is no longer supported for irrelevance, so the following
-- code is no longer accepted.

-- -- this type-checks because of subtyping
-- one' : {A B : Set} → (.A → B) → A → B
-- one' f = f


module Oscar.Data.Equality.properties where

-- open import Relation.Binary.PropositionalEquality public using (cong; cong₂; cong-app; subst; subst₂; sym; trans)

-- open import Oscar.Data.Equality
-- open import Oscar.Function
-- open import Oscar.Level
-- open import Oscar.Relation

-- -- ≡̇-refl : ∀ {a} {A : Set a} {b} {B : A → Set b} (f : (x : A) → B x) → f ≡̇ f
-- -- ≡̇-refl _ _ = refl

-- -- ≡̇-sym : ∀ {a} {A : Set a} {b} {B : A → Set b} {f g : (x : A) → B x} → f ≡̇ g → g ≡̇ f
-- -- ≡̇-sym f≡̇g = sym ∘ f≡̇g

-- -- ≡̇-trans : ∀ {a} {A : Set a} {b} {B : A → Set b} {f g : (x : A) → B x} → f ≡̇ g → {h : (x : A) → B x} → g ⟨ _≡̇ h ⟩→ f
-- -- ≡̇-trans f≡̇g g≡̇h x = trans (f≡̇g x) (g≡̇h x)

-- -- -- open import Oscar.Category.Setoid

-- -- -- instance

-- -- --   IsEquivalencePropositionalEquality : ∀ {a} {A : Set a} → IsEquivalence (_≡_ {A = A})
-- -- --   IsEquivalence.reflexivity IsEquivalencePropositionalEquality _ = refl
-- -- --   IsEquivalence.symmetry IsEquivalencePropositionalEquality = sym
-- -- --   IsEquivalence.transitivity IsEquivalencePropositionalEquality = λ ‵ → trans ‵

-- -- --   IsEquivalenceIndexedPropositionalEquality : ∀ {a} {A : Set a} {b} {B : A → Set b} → IsEquivalence (_≡̇_ {B = B})
-- -- --   IsEquivalence.reflexivity IsEquivalenceIndexedPropositionalEquality = ≡̇-refl
-- -- --   IsEquivalence.symmetry IsEquivalenceIndexedPropositionalEquality = ≡̇-sym
-- -- --   IsEquivalence.transitivity IsEquivalenceIndexedPropositionalEquality = ≡̇-trans

-- -- -- instance

-- -- --   IsSetoidPropositionalEquality : ∀ {a} {A : Set a} → IsSetoid A a
-- -- --   IsSetoid._≋_ IsSetoidPropositionalEquality = _≡_

-- -- --   IsSetoidIndexedPropositionalEquality : ∀ {a} {A : Set a} {b} {B : A → Set b} → IsSetoid ((x : A) → B x) (a ⊔ b)
-- -- --   IsSetoid._≋_ IsSetoidIndexedPropositionalEquality = _≡̇_

-- -- -- setoidPropositionalEquality : ∀ {a} (A : Set a) → Setoid a a
-- -- -- Setoid.⋆ (setoidPropositionalEquality A) = A

-- -- -- setoidIndexedPropositionalEquality : ∀ {a} {A : Set a} {b} (B : A → Set b) → Setoid (a ⊔ b) (a ⊔ b)
-- -- -- Setoid.⋆ (setoidIndexedPropositionalEquality {A = A} B) = (x : A) → B x
-- -- -- Setoid.isSetoid (setoidIndexedPropositionalEquality B) = IsSetoidIndexedPropositionalEquality {B = B}

-- -- -- open import Oscar.Category.Action

-- -- -- actionΣ : ∀ {a} {A : Set a} {b} (B : A → Set b) → Action A b b
-- -- -- Action.𝔄 (actionΣ B) x = setoidPropositionalEquality (B x)

-- -- -- _⇒_ : ∀ {a} (A : Set a) {b} (B : Set b) → Setoid _ _
-- -- -- _⇒_ A B = setoidIndexedPropositionalEquality {A = A} λ _ → B

-- -- -- open import Oscar.Category.Semigroupoid
-- -- -- open import Oscar.Category.Morphism

-- -- -- ⇧ : ∀ {a} {A : Set a} {b} (B : A → A → Set b) → Morphism A b b
-- -- -- Morphism._⇒_ (⇧ B) x y = setoidPropositionalEquality (B x y)

-- -- -- _⇨_ : ∀ {a} {A : Set a} {b} (B : A → Set b) {c} (C : A → Set c) → Morphism A (b ⊔ c) (b ⊔ c)
-- -- -- Morphism._⇒_ (B ⇨ C) = λ m n → B m ⇒ C n

-- -- -- IsSemigroupoid⋆ : ∀ {a} {A : Set a} {b} {B : A → Set b} {c} {C : A → Set c}
-- -- --                     (let _↦_ = λ m n → B m → C n)
-- -- --                     (_∙_ : ∀ {y z} → y ↦ z → ∀ {x} → x ↦ y → x ↦ z) → Set (lsuc (a ⊔ b ⊔ c))
-- -- -- IsSemigroupoid⋆ _∙_ = IsSemigroupoid (_ ⇨ _) _∙_

-- -- -- Semigroupoid⋆ :
-- -- --   ∀ {a} {A : Set a} {b} {B : A → Set b} {c} {C : A → Set c}
-- -- --                     (let _↦_ = λ m n → B m → C n)
-- -- --                     (_∙_ : ∀ {y z} → y ↦ z → ∀ {x} → x ↦ y → x ↦ z)
-- -- --     ⦃ _ : IsSemigroupoid⋆ _∙_ ⦄
-- -- --     → Semigroupoid _ _ _
-- -- -- Semigroupoid⋆ _∙_ = _ ⇨ _ , _∙_

-- -- -- open import Oscar.Category.Semigroupoid

-- -- -- instance

-- -- --   isSemigroupoidFunctions≡̇ : ∀ {a} {A : Set a} {b} {B : A → Set b} → IsSemigroupoid (B ⇨ B) (λ g f → g ∘ f)
-- -- --   IsSemigroupoid.extensionality isSemigroupoidFunctions≡̇ {f₂ = f₂} f₁≡̇f₂ g₁≡̇g₂ x rewrite f₁≡̇f₂ x = g₁≡̇g₂ (f₂ x)
-- -- --   IsSemigroupoid.associativity isSemigroupoidFunctions≡̇ _ _ _ _ = refl

-- -- -- semigroupoidFunction : ∀ {a} {A : Set a} {b} (B : A → Set b) → Semigroupoid _ _ _
-- -- -- semigroupoidFunction B = B ⇨ B , (λ ‵ → _∘_ ‵)

-- -- -- open import Oscar.Category.Category

-- -- -- instance

-- -- --   isCategoryFunctions≡̇ : ∀ {a} {A : Set a} {b} {B : A → Set b} → IsCategory (semigroupoidFunction B) id
-- -- --   IsCategory.left-identity isCategoryFunctions≡̇ _ _ = refl
-- -- --   IsCategory.right-identity isCategoryFunctions≡̇ _ _ = refl

-- -- -- categoryFunction : ∀ {a} {A : Set a} {b} (B : A → Set b) → Category _ _ _
-- -- -- categoryFunction B = semigroupoidFunction B , id

-- -- -- -- -- open import Oscar.Property.Reflexivity

-- -- -- -- -- instance Reflexivity≡ : ∀ {a} {A : Set a} → Reflexivity (_≡_ {A = A})
-- -- -- -- -- Reflexivity.reflexivity Reflexivity≡ _ = refl

-- -- -- -- -- instance Reflexivity≡̇ : ∀ {a} {A : Set a} {b} {B : A → Set b} → Reflexivity (_≡̇_ {B = B})
-- -- -- -- -- Reflexivity.reflexivity Reflexivity≡̇ _ _ = refl

-- -- -- -- -- open import Oscar.Property.Symmetry

-- -- -- -- -- instance Symmetry≡ : ∀ {a} {A : Set a} → Symmetry (_≡_ {A = A})
-- -- -- -- -- Symmetry.symmetry Symmetry≡ = sym

-- -- -- -- -- instance Symmetry≡̇ : ∀ {a} {A : Set a} {b} {B : A → Set b} → Symmetry (_≡̇_ {B = B})
-- -- -- -- -- Symmetry.symmetry Symmetry≡̇ = ≡̇-sym

-- -- -- -- -- open import Oscar.Property.Transitivity

-- -- -- -- -- instance Transitivity≡ : ∀ {a} {A : Set a} → Transitivity (_≡_ {A = A})
-- -- -- -- -- Transitivity.transitivity Transitivity≡ x≡y = trans x≡y

-- -- -- -- -- instance Transitivity≡̇ : ∀ {a} {A : Set a} {b} {B : A → Set b} → Transitivity (_≡̇_ {B = B})
-- -- -- -- -- Transitivity.transitivity Transitivity≡̇ = ≡̇-trans

-- -- -- -- -- -- {-
-- -- -- -- -- -- _∘₂_ : ∀ {a b c}
-- -- -- -- -- --         {A : Set a} {B : A → Set b} {C : {x : A} → B x → Set c} →
-- -- -- -- -- --         (∀ {x} (y : B x) → C y) → (g : (x : A) → B x) →
-- -- -- -- -- --         ((x : A) → C (g x))
-- -- -- -- -- -- f ∘₂ g = λ x → f (g x)
-- -- -- -- -- -- -}

-- -- -- -- -- -- open import Oscar.Class.Equivalence

-- -- -- -- -- -- instance ReflexivityPropositional : ∀ {a} {A : Set a} → Reflexivity (_≡_ {A = A})
-- -- -- -- -- -- Reflexivity.reflexivity ReflexivityPropositional = refl

-- -- -- -- -- -- instance SymmetryPropositional : ∀ {a} {A : Set a} → Symmetry (_≡_ {A = A})
-- -- -- -- -- -- Symmetry.symmetry SymmetryPropositional = sym

-- -- -- -- -- -- instance TransitivityPropositional : ∀ {a} {A : Set a} → Transitivity (_≡_ {A = A})
-- -- -- -- -- -- Transitivity.transitivity TransitivityPropositional = trans

-- -- -- -- -- -- open import Prelude using (it)

-- -- -- -- -- -- instance Equivalence⋆ : ∀ {a} {A : Set a} {ℓ} {_≋_ : A → A → Set ℓ} ⦃ _ : Reflexivity _≋_ ⦄ ⦃ _ : Symmetry _≋_ ⦄ ⦃ _ : Transitivity _≋_ ⦄ → Equivalence _≋_
-- -- -- -- -- -- Equivalence.reflexivityI Equivalence⋆ = it
-- -- -- -- -- -- Equivalence.symmetryI Equivalence⋆ = it
-- -- -- -- -- -- Equivalence.transitivityI Equivalence⋆ = it

-- -- -- -- -- -- -- -- {-
-- -- -- -- -- -- -- -- instance EquivalencePropositional : ∀ {a} {A : Set a} → Equivalence (_≡_ {A = A})
-- -- -- -- -- -- -- -- Equivalence.reflexivity EquivalencePropositional = refl
-- -- -- -- -- -- -- -- Equivalence.symmetry EquivalencePropositional = sym
-- -- -- -- -- -- -- -- Equivalence.transitivity EquivalencePropositional = trans

-- -- -- -- -- -- -- -- instance EquivalencePointwise : ∀ {a} {A : Set a} {b} {B : A → Set b} → Equivalence (_≡̇_ {B = B})
-- -- -- -- -- -- -- -- Equivalence.reflexivity EquivalencePointwise x = refl
-- -- -- -- -- -- -- -- Equivalence.symmetry EquivalencePointwise = ≡̇-sym
-- -- -- -- -- -- -- -- Equivalence.transitivity EquivalencePointwise = ≡̇-trans
-- -- -- -- -- -- -- -- -}

-- -- -- -- -- -- instance CongruousEquivalencesPropositional : ∀ {a} {A : Set a} {b} {B : Set b} → CongruousEquivalences (_≡_ {A = A}) (_≡_ {A = B})
-- -- -- -- -- -- CongruousEquivalences.equivalence₁ CongruousEquivalencesPropositional = it
-- -- -- -- -- -- CongruousEquivalences.equivalence₂ CongruousEquivalencesPropositional = it
-- -- -- -- -- -- CongruousEquivalences.congruity CongruousEquivalencesPropositional = cong

-- -- -- -- -- -- postulate
-- -- -- -- -- --   FunctionName : Set

-- -- -- -- -- -- open import Oscar.Data.Nat
-- -- -- -- -- -- open import Oscar.Data.Fin
-- -- -- -- -- -- open import Oscar.Data.Term FunctionName
-- -- -- -- -- -- open import Oscar.Data.Term.Injectivity FunctionName

-- -- -- -- -- -- instance InjectiveEquivalencesTermI : ∀ {m : Nat} → InjectiveEquivalences (_≡_ {A = Fin m}) (_≡_ {A = Term m}) Term.i Term.i
-- -- -- -- -- -- InjectiveEquivalences.equivalence₁ InjectiveEquivalencesTermI = it
-- -- -- -- -- -- InjectiveEquivalences.equivalence₂ InjectiveEquivalencesTermI = it
-- -- -- -- -- -- InjectiveEquivalences.injectivity InjectiveEquivalencesTermI refl = reflexivity

-- -- -- -- -- -- instance InjectiveEquivalencesTermLeft : ∀ {m : Nat} {r₁ r₂ : Term m} → InjectiveEquivalences _≡_ _≡_ (_fork r₁) (_fork r₂)
-- -- -- -- -- -- InjectiveEquivalences.equivalence₁ InjectiveEquivalencesTermLeft = it
-- -- -- -- -- -- InjectiveEquivalences.equivalence₂ InjectiveEquivalencesTermLeft = it
-- -- -- -- -- -- InjectiveEquivalences.injectivity InjectiveEquivalencesTermLeft refl = reflexivity

-- -- -- -- -- -- instance InjectiveEquivalencesTermRight : ∀ {m : Nat} {l₁ l₂ : Term m} → InjectiveEquivalences _≡_ _≡_ (l₁ fork_) (l₂ fork_)
-- -- -- -- -- -- InjectiveEquivalences.equivalence₁ InjectiveEquivalencesTermRight = it
-- -- -- -- -- -- InjectiveEquivalences.equivalence₂ InjectiveEquivalencesTermRight = it
-- -- -- -- -- -- InjectiveEquivalences.injectivity InjectiveEquivalencesTermRight refl = reflexivity

-- -- -- -- -- -- injectivity' :
-- -- -- -- -- --   ∀ {a} {A : Set a} {ℓ₁} {_≋₁_ : A → A → Set ℓ₁}
-- -- -- -- -- --     {b} {B : Set b}
-- -- -- -- -- --     {f : A → B}
-- -- -- -- -- --     {g : A → B}
-- -- -- -- -- --     ⦃ _ : InjectiveEquivalences _≋₁_ _≡_ f g ⦄ →
-- -- -- -- -- --   ∀ {x y} → f x ≡ g y → x ≋₁ y
-- -- -- -- -- -- injectivity' x = injectivity {_≋₂_ = _≡_} x

-- -- -- -- -- -- Term-forkLeft-inj' : ∀ {n} {l₁ r₁ l₂ r₂ : Term n} → l₁ fork r₁ ≡ l₂ fork r₂ → l₁ ≡ l₂
-- -- -- -- -- -- Term-forkLeft-inj' {n} {l₁} {r₁} {l₂} {r₂} x = injectivity' x
-- -- -- -- -- -- --Term-forkLeft-inj' {n} {l₁} {r₁} {l₂} {r₂} x = injectivity {_≋₂_ = _≡_} x
-- -- -- -- -- -- -- injectivity {_≋₁_ = {!_≡_!}} {_≋₂_ = {!_≡_!}} ⦃ InjectiveEquivalencesTermLeft ⦄ x

-- -- -- -- -- -- Term-forkRight-inj' : ∀ {n} {l₁ r₁ l₂ r₂ : Term n} → l₁ fork r₁ ≡ l₂ fork r₂ → r₁ ≡ r₂
-- -- -- -- -- -- Term-forkRight-inj' {n} {l₁} {r₁} {l₂} {r₂} x = injectivity' x
-- -- -- -- -- -- --Term-forkLeft-inj' {n} {l₁} {r₁} {l₂} {r₂} x = injectivity {_≋₂_ = _≡_} x
-- -- -- -- -- -- -- injectivity {_≋₁_ = {!_≡_!}} {_≋₂_ = {!_≡_!}} ⦃ InjectiveEquivalencesTermLeft ⦄ x


module _ where

open import Agda.Builtin.Reflection renaming (bindTC to _>>=_)
open import Agda.Builtin.Unit
open import Agda.Builtin.List
open import Agda.Builtin.Nat
open import Agda.Builtin.Equality
open import Agda.Builtin.Bool

_>>_ : {A B : Set} → TC A → TC B → TC B
m >> m₁ = m >>= λ _ → m₁

data Fin : Nat → Set where
  zero : ∀ {n} → Fin (suc n)
  suc  : ∀ {n} → Fin n → Fin (suc n)

macro
  reflectAndCheck : ∀ {a} {A : Set a} → A → Term → TC ⊤
  reflectAndCheck {A = A} x hole = withNormalisation true do
    `x  ← quoteTC x
    `A  ← quoteTC A
    ``x ← checkType `x `A >>= quoteTC
    unify hole ``x

  quoteUnquote : ∀ {a} {A : Set a} → A → Term → TC ⊤
  quoteUnquote x hole = withNormalisation true do
    `x ← quoteTC x
    unify hole `x

module _ (n : Nat) (A : Set) (m : Nat) (j : Fin m) where

  plam₁ : Fin n → Fin m
  plam₁ = λ where zero → j; (suc i) → j

  `plam₁ : Term
  `plam₁ = reflectAndCheck plam₁

  plam₁′ : Fin n → Fin m
  plam₁′ = quoteUnquote plam₁

  refined₁ : n ≡ suc m → Nat
  refined₁ refl = 0
    where
      plam : Fin n → Fin m
      plam = λ where zero → j; (suc i) → i

      `plam : Term
      `plam = reflectAndCheck plam

      plam′ : Fin n → Fin m
      plam′ = quoteUnquote plam

  refined₂ : m ≡ suc n → Nat
  refined₂ refl = 0
    where
      plam : Fin n → Fin m
      plam = λ where zero → j; (suc i) → suc (suc i)

      `plam : Term
      `plam = reflectAndCheck plam

      plam′ : Fin n → Fin m
      plam′ = quoteUnquote plam


--{-# OPTIONS -v tc.pos:100 #-}

open import Agda.Builtin.Equality

data ⊥ : Set where

postulate
  A : Set
  R : A → Set

magic : ⊥ → A
magic ()

test : (a : ⊥) → magic a ≡ magic _
test a = refl


------------------------------------------------------------------------
-- The two semantical definitions of subtyping are equivalent
------------------------------------------------------------------------

module RecursiveTypes.Subtyping.Semantic.Equivalence where

open import Data.Nat
open import Codata.Musical.Notation
open import Function.Base

open import RecursiveTypes.Syntax
open import RecursiveTypes.Subtyping.Semantic.Inductive
open import RecursiveTypes.Subtyping.Semantic.Coinductive

mutual

  ≤∞⇒≤↓ : ∀ {n} {σ τ : Tree n} → σ ≤∞ τ → σ ≤↓ τ
  ≤∞⇒≤↓ le              zero    = ⊥
  ≤∞⇒≤↓ ⊥               (suc k) = ⊥
  ≤∞⇒≤↓ ⊤               (suc k) = ⊤
  ≤∞⇒≤↓ var             (suc k) = refl
  ≤∞⇒≤↓ (τ₁≤σ₁ ⟶ σ₂≤τ₂) (suc k) = ≤∞⇒≤↑ (♭ τ₁≤σ₁) k ⟶ ≤∞⇒≤↓ (♭ σ₂≤τ₂) k

  ≤∞⇒≤↑ : ∀ {n} {σ τ : Tree n} → σ ≤∞ τ → σ ≤↑ τ
  ≤∞⇒≤↑ le              zero    = ⊤
  ≤∞⇒≤↑ ⊥               (suc k) = ⊥
  ≤∞⇒≤↑ ⊤               (suc k) = ⊤
  ≤∞⇒≤↑ var             (suc k) = refl
  ≤∞⇒≤↑ (τ₁≤σ₁ ⟶ σ₂≤τ₂) (suc k) = ≤∞⇒≤↓ (♭ τ₁≤σ₁) k ⟶ ≤∞⇒≤↑ (♭ σ₂≤τ₂) k

domain : ∀ {n} {σ₁ σ₂ τ₁ τ₂ : FinTree n} →
         σ₁ ⟶ σ₂ ≤Fin τ₁ ⟶ τ₂ → σ₂ ≤Fin τ₂
domain refl            = refl
domain (τ₁≤σ₁ ⟶ σ₂≤τ₂) = σ₂≤τ₂

codomain : ∀ {n} {σ₁ σ₂ τ₁ τ₂ : FinTree n} →
           σ₁ ⟶ σ₂ ≤Fin τ₁ ⟶ τ₂ → τ₁ ≤Fin σ₁
codomain refl            = refl
codomain (τ₁≤σ₁ ⟶ σ₂≤τ₂) = τ₁≤σ₁

mutual

  ≤↑⇒≤∞ : ∀ {n} (σ τ : Tree n) → σ ≤↑ τ → σ ≤∞ τ
  ≤↑⇒≤∞ ⊥ _ le = ⊥
  ≤↑⇒≤∞ _ ⊤ le = ⊤
  ≤↑⇒≤∞ ⊤ ⊥ le with le 1
  ... | ()
  ≤↑⇒≤∞ ⊤ (var x) le with le 1
  ... | ()
  ≤↑⇒≤∞ ⊤ (σ ⟶ τ) le with le 1
  ... | ()
  ≤↑⇒≤∞ (var x) ⊥ le with le 1
  ... | ()
  ≤↑⇒≤∞ (var x) (var x′) le with le 1
  ≤↑⇒≤∞ (var x) (var .x) le | refl = var
  ≤↑⇒≤∞ (var x) (σ ⟶ τ) le with le 1
  ... | ()
  ≤↑⇒≤∞ (σ₁ ⟶ τ₁) ⊥ le with le 1
  ... | ()
  ≤↑⇒≤∞ (σ₁ ⟶ τ₁) (var x) le with le 1
  ... | ()
  ≤↑⇒≤∞ (σ₁ ⟶ τ₁) (σ₂ ⟶ τ₂) le =
    ♯ ≤↓⇒≤∞ (♭ σ₂) (♭ σ₁) (codomain ∘ le ∘ suc) ⟶
    ♯ ≤↑⇒≤∞ (♭ τ₁) (♭ τ₂) (domain   ∘ le ∘ suc)

  ≤↓⇒≤∞ : ∀ {n} (σ τ : Tree n) → σ ≤↓ τ → σ ≤∞ τ
  ≤↓⇒≤∞ ⊥ _ le = ⊥
  ≤↓⇒≤∞ _ ⊤ le = ⊤
  ≤↓⇒≤∞ ⊤ ⊥ le with le 1
  ... | ()
  ≤↓⇒≤∞ ⊤ (var x) le with le 1
  ... | ()
  ≤↓⇒≤∞ ⊤ (σ ⟶ τ) le with le 1
  ... | ()
  ≤↓⇒≤∞ (var x) ⊥ le with le 1
  ... | ()
  ≤↓⇒≤∞ (var x) (var x′) le with le 1
  ≤↓⇒≤∞ (var x) (var .x) le | refl = var
  ≤↓⇒≤∞ (var x) (σ ⟶ τ) le with le 1
  ... | ()
  ≤↓⇒≤∞ (σ₁ ⟶ τ₁) ⊥ le with le 1
  ... | ()
  ≤↓⇒≤∞ (σ₁ ⟶ τ₁) (var x) le with le 1
  ... | ()
  ≤↓⇒≤∞ (σ₁ ⟶ τ₁) (σ₂ ⟶ τ₂) le =
    ♯ ≤↑⇒≤∞ (♭ σ₂) (♭ σ₁) (codomain ∘ le ∘ suc) ⟶
    ♯ ≤↓⇒≤∞ (♭ τ₁) (♭ τ₂) (domain   ∘ le ∘ suc)

Ind⇒Coind : ∀ {n} {σ τ : Ty n} → σ ≤Ind τ → σ ≤Coind τ
Ind⇒Coind = ≤↓⇒≤∞ _ _

Coind⇒Ind : ∀ {n} {σ τ : Ty n} → σ ≤Coind τ → σ ≤Ind τ
Coind⇒Ind = ≤∞⇒≤↓


module cfg1 where

open import Level renaming ( suc to succ ; zero to Zero )
open import Data.Nat  hiding ( _≟_ )
-- open import Data.Fin
-- open import Data.Product
open import Data.List
open import Data.Maybe
-- open import Data.Bool using ( Bool ; true ; false ; _∧_ ; _∨_ )
open import  Relation.Binary.PropositionalEquality hiding ( [_] )
open import Relation.Nullary using (¬_; Dec; yes; no)
open import logic

--
--   Java → Java Byte Code
--
--   CFG    Stack Machine (PDA)
--

data Node (Symbol  : Set) : Set where
    T : Symbol → Node Symbol
    N : Symbol → Node Symbol

data Seq (Symbol  : Set) : Set where
    _，_   :  Symbol  → Seq Symbol  → Seq Symbol
    _．    :  Symbol  → Seq Symbol
    Error    :  Seq Symbol

data Body (Symbol  : Set) : Set where
    _｜_   :  Seq Symbol  → Body Symbol  → Body Symbol
    _；    :  Seq Symbol  → Body Symbol

record CFGGrammer  (Symbol  : Set) : Set where
   field
      cfg : Symbol → Body Symbol
      top : Symbol
      eq? : Symbol → Symbol → Bool
      typeof : Symbol →  Node Symbol

infixr  80 _｜_
infixr  90 _；
infixr  100 _，_
infixr  110 _．

open CFGGrammer

-----------------
--
-- CGF language
--
-----------------

split : {Σ : Set} → (List Σ → Bool)
      → ( List Σ → Bool) → List Σ → Bool
split x y  [] = x [] /\ y []
split x y (h  ∷ t) = (x [] /\ y (h  ∷ t)) \/
  split (λ t1 → x (  h ∷ t1 ))  (λ t2 → y t2 ) t

cfg-language0 :  {Symbol  : Set} → CFGGrammer Symbol   → Body Symbol  →  List Symbol → Bool

{-# TERMINATING #-}
cfg-language1 :  {Symbol  : Set} → CFGGrammer Symbol   → Seq Symbol  →  List Symbol → Bool
cfg-language1 cg Error x = false
cfg-language1 cg (S ， seq) x with typeof cg S
cfg-language1 cg (_ ， seq) (x' ∷ t) | T x =  eq? cg x x' /\ cfg-language1 cg seq t
cfg-language1 cg (_ ， seq) [] | T x = false
cfg-language1 cg (_ ， seq) x | N nonTerminal = split (cfg-language0 cg (cfg cg nonTerminal) )(cfg-language1 cg seq ) x
cfg-language1 cg (S ．) x with typeof cg S
cfg-language1 cg (_ ．) (x' ∷ []) | T x =  eq? cg x x'
cfg-language1 cg (_ ．) _ | T x = false
cfg-language1 cg (_ ．) x | N nonTerminal = cfg-language0 cg (cfg cg nonTerminal) x

cfg-language0 cg _ [] = false
cfg-language0 cg (rule ｜ b) x =
     cfg-language1 cg rule x  \/ cfg-language0 cg b x
cfg-language0 cg (rule ；) x = cfg-language1 cg rule x

cfg-language :  {Symbol  : Set} → CFGGrammer Symbol   → List Symbol → Bool
cfg-language cg = cfg-language0 cg (cfg cg (top cg ))

data IFToken : Set where
   EA : IFToken
   EB : IFToken
   EC : IFToken
   IF : IFToken
   THEN : IFToken
   ELSE : IFToken
   SA : IFToken
   SB : IFToken
   SC : IFToken
   expr : IFToken
   statement : IFToken

token-eq? : IFToken → IFToken → Bool
token-eq? EA EA = true
token-eq? EB EB = true
token-eq? EC EC =  true
token-eq? IF IF =  true
token-eq? THEN THEN =  true
token-eq? ELSE ELSE = true
token-eq? SA SA =  true
token-eq? SB SB =  true
token-eq? SC SC = true
token-eq? expr expr = true
token-eq? statement statement = true
token-eq? _ _ = false

typeof-IFG : IFToken → Node IFToken
typeof-IFG expr = N expr
typeof-IFG statement = N statement
typeof-IFG x = T x

IFGrammer : CFGGrammer IFToken
IFGrammer = record {
      cfg = cfg'
    ; top = statement
    ; eq? = token-eq?
    ; typeof = typeof-IFG
   } where
     cfg' : IFToken → Body IFToken
     cfg' expr =  EA ． ｜  EB ．  ｜   EC ． ；
     cfg' statement =
           SA ． ｜   SB ．  ｜   SC ．
         ｜  IF ，  expr ， THEN ， statement ．
         ｜  IF ，  expr ， THEN ， statement  ，  ELSE  ，  statement ．
         ；
     cfg' x =  Error  ；

cfgtest1 = cfg-language IFGrammer (  SA ∷ [] )

cfgtest2 = cfg-language1 IFGrammer ( SA   ．) (  SA ∷ [] )

cfgtest3 = cfg-language1 IFGrammer ( SA    ．  ) (  SA ∷ [] )

cfgtest4 = cfg-language IFGrammer  (IF  ∷ EA ∷ THEN  ∷ SA ∷ [] )

cfgtest5 = cfg-language1 IFGrammer ( IF  ，  expr  ， THEN ，  statement  ． ) (IF  ∷ EA ∷ THEN  ∷ SA ∷ [] )
cfgtest6 = cfg-language1 IFGrammer ( statement  ．)(IF  ∷ EA ∷ SA ∷ [] )
cfgtest7 = cfg-language1 IFGrammer ( IF   ，   expr   ， THEN   ，   statement   ，   ELSE    ，   statement   ． )
    (IF  ∷ EA ∷ THEN   ∷ SA ∷ ELSE  ∷ SB  ∷ [] )
cfgtest8 = cfg-language IFGrammer  (IF ∷ EA ∷ THEN  ∷ IF ∷ EB ∷ THEN  ∷ SA ∷ ELSE  ∷ SB  ∷ [] )
cfgtest9 = cfg-language IFGrammer  (IF ∷ EB ∷ THEN ∷ SA ∷ ELSE  ∷ SB  ∷ [] )

data E1Token : Set where
   e1 : E1Token
   e[ : E1Token
   e] : E1Token
   expr : E1Token
   term : E1Token

E1-token-eq? : E1Token → E1Token → Bool
E1-token-eq? e1 e1 = true
E1-token-eq? e[ e] = true
E1-token-eq? e] e] = true
E1-token-eq? expr expr = true
E1-token-eq? term term = true
E1-token-eq? _ _ = false

typeof-E1 : E1Token → Node E1Token
typeof-E1 expr = N expr
typeof-E1 term = N term
typeof-E1 x = T x

E1Grammer : CFGGrammer E1Token
E1Grammer = record {
      cfg = cfgE
    ; top = expr
    ; eq? = E1-token-eq?
    ; typeof = typeof-E1
   } where
     cfgE : E1Token → Body E1Token
     cfgE expr = term ．
       ；
     cfgE term = e1  ．
       ｜   e[   ， expr  ，  e]   ．
       ；
     cfgE x = Error  ；

ecfgtest1 = cfg-language E1Grammer (  e1 ∷ [] )
ecfgtest2 = cfg-language E1Grammer (  e[ ∷ e1 ∷ e] ∷ [] )
ecfgtest3 = cfg-language E1Grammer (  e[ ∷ e[ ∷ e1 ∷ e] ∷ e] ∷ [] )
ecfgtest4 = cfg-language E1Grammer (  e[ ∷ e1 ∷ [] )

open import Function

left : {t : Set } → List E1Token → ( fail next : List E1Token → t ) → t
left ( e[ ∷ t ) fail next = next t
left t fail next = fail t

right : {t : Set } → List E1Token → ( fail next : List E1Token → t ) → t
right ( e] ∷ t ) fail next = next t
right t fail next = fail t

{-# TERMINATING #-}
expr1 : {t : Set } → List E1Token → ( fail next : List E1Token → t ) → t
expr1 ( e1 ∷ t ) fail next = next t
expr1 ( expr ∷ t ) fail next = next t
expr1 ( term  ∷ t ) fail next = next t
expr1 x fail next = left x fail $ λ x → expr1 x fail $ λ x → right x fail $ next
-- expr1 x fail next = left x fail ( λ x → expr1 x fail ( λ x → right x fail ( next )))

cfgtest01  = expr1 ( e[ ∷ e[ ∷ e1 ∷ e] ∷ e] ∷ [] ) (λ x → ⟪ false , x ⟫ ) (λ x → ⟪ true , x ⟫ )
cfgtest02  = expr1 ( e[ ∷ e[ ∷ e1 ∷ e] ∷ [] ) (λ x → ⟪ false , x ⟫ ) (λ x →  ⟪ true , x ⟫ )
cfgtest03  = expr1 ( e[ ∷ e[ ∷ e1 ∷ e] ∷ e] ∷ e] ∷ [] ) (λ x → ⟪ false , x ⟫ ) (λ x →  ⟪ true , x ⟫ )

open import pushdown

data CG1 : Set where
   ce : CG1
   c1 : CG1

pd  : CG1 → E1Token → CG1 → CG1 ∧ PushDown CG1
pd c1 e[ s = ⟪ c1 , push c1 ⟫
pd c1 e] c1 = ⟪ c1 , pop ⟫
pd c1 e1 c1 = ⟪ c1 , none ⟫
pd s expr s1 = ⟪ c1 , none ⟫
pd s term s1 = ⟪ c1 , none ⟫
pd s _ s1 = ⟪ ce , none ⟫

pok  : CG1 → Bool
pok c1  = true
pok s  = false

pnc : PushDownAutomaton CG1 E1Token CG1
pnc = record {
         pδ  = pd
      ;  pempty = ce
      ;  pok = pok
   }

pda-ce-test1 = PushDownAutomaton.paccept pnc c1 ( e[ ∷ e[ ∷ e1 ∷ e] ∷ e] ∷ [] ) []
pda-ce-test2 = PushDownAutomaton.paccept pnc c1 ( e[ ∷ e[ ∷ e1 ∷ e] ∷ [] ) []
pda-ce-test3 = PushDownAutomaton.paccept pnc c1 ( e[ ∷ e1 ∷ e] ∷ e1 ∷ [] ) []

record PNC (accept : Bool )  : Set where
  field
    orig-x : List E1Token
    pnc-q : CG1
    pnc-st : List CG1
    pnc-p : CG1 → List CG1 → Bool
    success : accept ≡ true  → pnc-p pnc-q pnc-st ≡ true  → PushDownAutomaton.paccept pnc c1 orig-x []  ≡ true
    failure : accept ≡ false → pnc-p pnc-q pnc-st ≡ false → PushDownAutomaton.paccept pnc c1 orig-x [] ≡ false

open import Data.Unit

{-# TERMINATING #-}
expr1P : {n : Level } {t : Set n } → (x : List E1Token ) → PNC true
    → ( fail : List E1Token → PNC false → t ) → ( next : List E1Token → PNC true → t ) → t
expr1P x _ _ _ = {!!}

expr1P-test : (x : List E1Token ) →  ⊤
expr1P-test x = expr1P x record { orig-x = x ; pnc-q = c1 ; pnc-st = []
      ; pnc-p = λ q st → PushDownAutomaton.paccept pnc q x st ; success = λ _ p → p ; failure = λ _ p → p }
      (λ x p → {!!} ) (λ x p → {!!} )

----
--
--  CFG to PDA
--

cfg→pda-state :  {Symbol  : Set} → CFGGrammer Symbol → Set
cfg→pda-state cfg = {!!}

cfg→pda-start :  {Symbol  : Set} → (cfg : CFGGrammer Symbol) → cfg→pda-state cfg
cfg→pda-start cfg = {!!}

cfg→pda :  {Symbol  : Set} → (cfg : CFGGrammer Symbol) → PDA (cfg→pda-state cfg) Symbol (cfg→pda-state cfg)
cfg→pda cfg = {!!}

cfg->pda : {Symbol  : Set} → (input : List Symbol)
    → (cfg : CFGGrammer Symbol)
    → PDA.paccept (cfg→pda cfg ) (cfg→pda-start cfg) input [] ≡  cfg-language cfg input
cfg->pda = {!!}

----
--
--  PDA to CFG
--
open import pushdown

pda→cfg :  {Symbol  : Set} { Q : Set} → (pda : PDA Q Symbol Q) → CFGGrammer Symbol
pda→cfg pda = record {
      cfg = {!!}
    ; top = {!!}
    ; eq? = {!!}
    ; typeof = {!!}
   }

pda->cfg : {Symbol  : Set} { Q : Set} → (start : Q) →  (input : List Symbol)
    → (pda : PDA  Q Symbol Q)
    → PDA.paccept pda start input [] ≡  cfg-language (pda→cfg pda) input
pda->cfg = {!!}

record CDGGrammer  (Symbol  : Set) : Set where
   field
      cdg : Seq Symbol  → Body Symbol
      top : Symbol
      eq? : Symbol → Symbol → Bool
      typeof : Symbol →  Node Symbol