------------------------------------------------------------------------
-- The Agda standard library
--
-- Example of multi-sorted algebras as indexed containers
------------------------------------------------------------------------

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

module README.Data.Container.Indexed.MultiSortedAlgebraExample where

------------------------------------------------------------------------
-- Preliminaries
------------------------------------------------------------------------
-- We import library content for indexed containers, standard types,
-- and setoids.

open import Level

open import Data.Container.Indexed.Core using (Container; ⟦_⟧; _◃_/_)
open import Data.Container.Indexed.FreeMonad using (_⋆C_)
open import Data.W.Indexed using (W; sup)

open import Data.Product using (Σ; _×_; _,_; Σ-syntax)
open import Data.Sum using (_⊎_; inj₁; inj₂; [_,_])
open import Data.Empty.Polymorphic using (; ⊥-elim)

open import Function using (_∘_)
open import Function.Bundles using (Func)

open import Relation.Binary using (Setoid; IsEquivalence)
open import Relation.Binary.PropositionalEquality using (_≡_; refl)

import Data.Container.Indexed.Relation.Binary.Equality.Setoid as ICSetoid
import Relation.Binary.Reasoning.Setoid as SetoidReasoning

open Setoid using (Carrier; _≈_; isEquivalence)
open Func renaming (to to apply)

-- Letter ℓ denotes universe levels.

variable
   ℓ' ℓˢ ℓᵒ ℓᵃ ℓᵐ ℓᵉ ℓⁱ : Level
  I : Set ℓⁱ
  S : Set ℓˢ

------------------------------------------------------------------------
-- The interpretation of a container (Op ◃ Ar / sort) is
--
--   ⟦ Op ◃ Ar / sort ⟧ X s = Σ[ o ∈ Op s ] ((i : Ar o) → X (sort o i))
--
-- which contains pairs consisting of an operator $o$ and its collection
-- of arguments.  The least fixed point of (X ↦ ⟦ C ⟧ X) is the indexed
-- W-type given by C, and it contains closed first-order terms of the
-- multi-sorted algebra C.

-- We need to interpret indexed containers on Setoids.
-- This definition is missing from the standard library v1.7.

⟦_⟧s : (C : Container I S ℓᵒ ℓᵃ) (ξ : I  Setoid ℓᵐ ℓᵉ)  S  Setoid _ _
 C ⟧s ξ = ICSetoid.setoid ξ C

------------------------------------------------------------------------
-- Multi-sorted algebras
--------------------------------------------------------------------------
-- A multi-sorted algebra is an indexed container.
--
-- * Sorts are indexes.
--
-- * Operators are commands/shapes.
--
-- * Arities/argument are responses/positions.
--
-- Closed terms (initial model) are given by the W type for a container,
-- renamed to μ here (for least fixed-point).

-- We assume a fixed signature (Sort, Ops).

module _ (Sort : Set ℓˢ) (Ops : Container Sort Sort ℓᵒ ℓᵃ) where
  open Container Ops renaming
    ( Command   to  Op
    ; Response  to  Arity
    ; next      to  sort
    )

-- We let letter $s$ range over sorts and $\mathit{op}$ over operators.

  variable
    s s'    : Sort
    op op'  : Op s

------------------------------------------------------------------------
-- Models

  -- A model is given by an interpretation (Den $s$) for each sort $s$
  -- plus an interpretation (den $o$) for each operator $o$.

  record SetModel ℓᵐ : Set (ℓˢ  ℓᵒ  ℓᵃ  suc ℓᵐ) where
    field
      Den : Sort  Set ℓᵐ
      den : {s : Sort}   Ops  Den s  Den s

  -- The setoid model requires operators to respect equality.
  -- The Func record packs a function (apply) with a proof (cong)
  -- that the function maps equals to equals.

  record SetoidModel ℓᵐ ℓᵉ : Set (ℓˢ  ℓᵒ  ℓᵃ  suc (ℓᵐ  ℓᵉ)) where
    field
      Den  :  Sort  Setoid ℓᵐ ℓᵉ
      den  :  {s : Sort}  Func ( Ops ⟧s Den s) (Den s)


------------------------------------------------------------------------
-- Terms

  -- To obtain terms with free variables, we add additional nullary
  -- operators, each representing a variable.
  --
  -- These are covered in the standard library FreeMonad module,
  -- albeit with the restriction that the operator and variable sets
  -- have the same size.

  Cxt = Sort  Set ℓᵒ

  variable
    Γ Δ : Cxt

  -- Terms with free variables in Var.

  module _ (Var : Cxt) where

    -- We keep the same sorts, but add a nullary operator for each variable.

    Ops⁺ : Container Sort Sort ℓᵒ ℓᵃ
    Ops⁺ = Ops ⋆C Var

    -- Terms with variables are then given by the W-type for the extended container.

    Tm = W Ops⁺

    -- We define nice constructors for variables and operator application
    -- via pattern synonyms.
    -- Note that the $f$ in constructor var' is a function from the empty set,
    -- so it should be uniquely determined.  However, Agda's equality is
    -- more intensional and will not identify all functions from the empty set.
    -- Since we do not make use of the axiom of function extensionality,
    -- we sometimes have to consult the extensional equality of the
    -- function setoid.

    pattern _∙_ op args  = sup (inj₂ op , args)
    pattern var' x f     = sup (inj₁ x , f    )
    pattern var x        = var' x _

  -- Letter $t$ ranges over terms, and $\mathit{ts}$ over argument vectors.

  variable
    t t' t₁ t₂ t₃  :  Tm Γ s
    ts ts'         :  (i : Arity op)  Tm Γ (sort _ i)

------------------------------------------------------------------------
-- Parallel substitutions

  -- A substitution from Δ to Γ holds a term in Γ for each variable in Δ.

  Sub : (Γ Δ : Cxt)  Set _
  Sub Γ Δ = ∀{s} (x : Δ s)  Tm Γ s

  -- Application of a substitution.

  _[_] : (t : Tm Δ s) (σ : Sub Γ Δ)  Tm Γ s
  (var x  )  [ σ ] = σ x
  (op  ts)  [ σ ] = op  λ i  ts i [ σ ]

  -- Letter $σ$ ranges over substitutions.

  variable
    σ σ' : Sub Γ Δ

------------------------------------------------------------------------
-- Interpretation of terms in a model
------------------------------------------------------------------------

  -- Given an algebra $M$ of set-size $ℓ^m$ and equality-size $ℓ^e$,
  -- we define the interpretation of an $s$-sorted term $t$ as element
  -- of $M(s)$ according to an environment $ρ$ that maps each variable
  -- of sort $s'$ to an element of $M(s')$.

  module _ {M : SetoidModel ℓᵐ ℓᵉ} where
    open SetoidModel M

    -- Equality in $M$'s interpretation of sort $s$.

    _≃_ : Den s .Carrier  Den s .Carrier  Set _
    _≃_ {s = s} = Den s ._≈_

    -- An environment for Γ maps each variable $x : Γ(s)$ to an element of $M(s)$.
    -- Equality of environments is defined pointwise.

    Env : Cxt  Setoid _ _
    Env Γ .Carrier   = {s : Sort} (x : Γ s)  Den s .Carrier
    Env Γ ._≈_ ρ ρ'  = {s : Sort} (x : Γ s)  ρ x  ρ' x
    Env Γ .isEquivalence .IsEquivalence.refl   {s = s}   x = Den s .Setoid.refl
    Env Γ .isEquivalence .IsEquivalence.sym       h {s}  x = Den s .Setoid.sym   (h x)
    Env Γ .isEquivalence .IsEquivalence.trans  g  h {s}  x = Den s .Setoid.trans (g x) (h x)

    -- Interpretation of terms is iteration on the W-type.
    -- The standard library offers `iter' (on sets), but we need this to be a Func (on setoids).

    ⦅_⦆ : ∀{s} (t : Tm Γ s)  Func (Env Γ) (Den s)
     var x       .apply  ρ     = ρ x
     var x       .cong   ρ=ρ'  = ρ=ρ' x
     op  args   .apply  ρ     = den .apply  (op    , λ i   args i  .apply ρ)
     op  args   .cong   ρ=ρ'  = den .cong   (refl  , λ i   args i  .cong ρ=ρ')

    -- An equality between two terms holds in a model
    -- if the two terms are equal under all valuations of their free variables.

    Equal :  {Γ s} (t t' : Tm Γ s)  Set _
    Equal {Γ} {s} t t' =  (ρ : Env Γ .Carrier)   t  .apply ρ   t'  .apply ρ

    -- This notion is an equivalence relation.

    isEquiv : IsEquivalence (Equal {Γ = Γ} {s = s})
    isEquiv {s = s} .IsEquivalence.refl  ρ       = Den s .Setoid.refl
    isEquiv {s = s} .IsEquivalence.sym   e ρ     = Den s .Setoid.sym (e ρ)
    isEquiv {s = s} .IsEquivalence.trans e e' ρ  = Den s .Setoid.trans (e ρ) (e' ρ)

------------------------------------------------------------------------
-- Substitution lemma

    -- Evaluation of a substitution gives an environment.

    ⦅_⦆s : Sub Γ Δ  Env Γ .Carrier  Env Δ .Carrier
     σ ⦆s ρ x =  σ x  .apply ρ

    -- Substitution lemma: ⦅t[σ]⦆ρ ≃ ⦅t⦆⦅σ⦆ρ

    substitution : (t : Tm Δ s) (σ : Sub Γ Δ) (ρ : Env Γ .Carrier) 
       t [ σ ]  .apply ρ   t  .apply ( σ ⦆s ρ)
    substitution (var x)    σ ρ = Den _ .Setoid.refl
    substitution (op  ts)  σ ρ = den .cong (refl , λ i  substitution (ts i) σ ρ)

------------------------------------------------------------------------
-- Equations

  -- An equation is a pair $t ≐ t'$ of terms of the same sort in the same context.

  record Eq : Set (ℓˢ  suc ℓᵒ  ℓᵃ) where
    constructor _≐_
    field
      {cxt}  : Sort  Set ℓᵒ
      {srt}  : Sort
      lhs    : Tm cxt srt
      rhs    : Tm cxt srt

  -- Equation $t ≐ t'$ holding in model $M$.

  _⊧_ : (M : SetoidModel ℓᵐ ℓᵉ) (eq : Eq)  Set _
  M  (t  t') = Equal {M = M} t t'

  -- Sets of equations are presented as collection E : I → Eq
  -- for some index set I : Set ℓⁱ.

  -- An entailment/consequence $E ⊃ t ≐ t'$ is valid
  -- if $t ≐ t'$ holds in all models that satify equations $E$.

  module _ {ℓᵐ ℓᵉ} where

    _⊃_ : (E : I  Eq) (eq : Eq)  Set _
    E  eq =  (M : SetoidModel ℓᵐ ℓᵉ)  (∀ i  M  E i)  M  eq

  -- Derivations
  --------------

  -- Equalitional logic allows us to prove entailments via the
  -- inference rules for the judgment $E ⊢ Γ ▹ t ≡ t'$.
  -- This could be coined as equational theory over a given
  -- set of equations $E$.
  -- Relation $E ⊢ Γ ▹ \_ ≡ \_$ is the least congruence over the equations $E$.

  data _⊢_▹_≡_ {I : Set ℓⁱ}
    (E : I  Eq) : (Γ : Cxt) (t t' : Tm Γ s)  Set (ℓˢ  suc ℓᵒ  ℓᵃ  ℓⁱ) where

    hyp    :   i  let t  t' = E i in
              E  _  t  t'

    base   :   (x : Γ s) {f f' : (i : )  Tm _ (⊥-elim i)} 
              E  Γ  var' x f  var' x f'

    app    :  (∀ i  E  Γ  ts i  ts' i) 
              E  Γ  (op  ts)  (op  ts')

    sub    :  E  Δ  t  t' 
               (σ : Sub Γ Δ) 
              E  Γ  (t [ σ ])  (t' [ σ ])

    refl   :   (t : Tm Γ s) 
              E  Γ  t  t

    sym    :  E  Γ  t  t' 
              E  Γ  t'  t

    trans  :  E  Γ  t₁  t₂ 
              E  Γ  t₂  t₃ 
              E  Γ  t₁  t₃

------------------------------------------------------------------------
-- Soundness of the inference rules

  -- We assume a model $M$ that validates all equations in $E$.

  module Soundness {I : Set ℓⁱ} (E : I  Eq) (M : SetoidModel ℓᵐ ℓᵉ)
    (V :  i  M  E i) where
    open SetoidModel M

    -- In any model $M$ that satisfies the equations $E$,
    -- derived equality is actual equality.

    sound : E  Γ  t  t'  M  (t  t')

    sound (hyp i)                        =  V i
    sound (app {op = op} es) ρ           =  den .cong (refl , λ i  sound (es i) ρ)
    sound (sub {t = t} {t' = t'} e σ) ρ  =  begin
       t [ σ ]    .apply ρ   ≈⟨ substitution {M = M} t σ ρ 
       t          .apply ρ'  ≈⟨ sound e ρ' 
       t'         .apply ρ'  ≈⟨ substitution {M = M} t' σ ρ 
       t' [ σ ]   .apply ρ   
      where
      open SetoidReasoning (Den _)
      ρ' =  σ ⦆s ρ

    sound (base x {f} {f'})              =  isEquiv {M = M} .IsEquivalence.refl {var' x λ()}

    sound (refl t)                       =  isEquiv {M = M} .IsEquivalence.refl {t}
    sound (sym {t = t} {t' = t'} e)      =  isEquiv {M = M} .IsEquivalence.sym
                                            {x = t} {y = t'} (sound e)
    sound (trans  {t₁ = t₁} {t₂ = t₂}
                  {t₃ = t₃} e e')        =  isEquiv {M = M} .IsEquivalence.trans
                                            {i = t₁} {j = t₂} {k = t₃} (sound e) (sound e')


------------------------------------------------------------------------
-- Birkhoff's completeness theorem
------------------------------------------------------------------------

  -- Birkhoff proved that any equation $t ≐ t'$ is derivable from $E$
  -- when it is valid in all models satisfying $E$.  His proof (for
  -- single-sorted algebras) is a blue print for many more
  -- completeness proofs.  They all proceed by constructing a
  -- universal model aka term model.  In our case, it is terms
  -- quotiented by derivable equality $E ⊢ Γ ▹ \_ ≡ \_$.  It then
  -- suffices to prove that this model satisfies all equations in $E$.

------------------------------------------------------------------------
-- Universal model

  -- A term model for $E$ and $Γ$ interprets sort $s$ by (Tm Γ s) quotiented by $E ⊢ Γ ▹ \_ ≡ \_$.

  module TermModel {I : Set ℓⁱ} (E : I  Eq) where
    open SetoidModel

    -- Tm Γ s quotiented by E⊢Γ▹·≡·.

    TmSetoid : Cxt  Sort  Setoid _ _
    TmSetoid Γ s .Carrier                             = Tm Γ s
    TmSetoid Γ s ._≈_                                 = E  Γ ▹_≡_
    TmSetoid Γ s .isEquivalence .IsEquivalence.refl   = refl _
    TmSetoid Γ s .isEquivalence .IsEquivalence.sym    = sym
    TmSetoid Γ s .isEquivalence .IsEquivalence.trans  = trans

    -- The interpretation of an operator is simply the operator.
    -- This works because $E⊢Γ▹\_≡\_$ is a congruence.

    tmInterp :  {Γ s}  Func ( Ops ⟧s (TmSetoid Γ) s) (TmSetoid Γ s)
    tmInterp .apply (op , ts) = op  ts
    tmInterp .cong (refl , h) = app h

    -- The term model per context Γ.

    M : Cxt  SetoidModel _ _
    M Γ .Den = TmSetoid Γ
    M Γ .den = tmInterp

    -- The identity substitution σ₀ maps variables to themselves.

    σ₀ : {Γ : Cxt}  Sub Γ Γ
    σ₀ x = var' x  λ()

    -- σ₀ acts indeed as identity.

    identity : (t : Tm Γ s)  E  Γ  t [ σ₀ ]  t
    identity (var x)    = base x
    identity (op  ts)  = app λ i  identity (ts i)

    -- Evaluation in the term model is substitution $E ⊢ Γ ▹ ⦅t⦆σ ≡ t[σ]$.
    -- This would even hold "up to the nose" if we had function extensionality.

    evaluation : (t : Tm Δ s) (σ : Sub Γ Δ)  E  Γ  (⦅_⦆ {M = M Γ} t .apply σ)  (t [ σ ])
    evaluation (var x)    σ = refl (σ x)
    evaluation (op  ts)  σ = app  i  evaluation (ts i) σ)

    -- The term model satisfies all the equations it started out with.

    satisfies :  i  M Γ  E i
    satisfies i σ = begin
       tₗ  .apply σ  ≈⟨ evaluation tₗ σ 
      tₗ [ σ ]         ≈⟨ sub (hyp i) σ 
      tᵣ [ σ ]         ≈⟨ evaluation tᵣ σ 
       tᵣ  .apply σ  
      where
      open SetoidReasoning (TmSetoid _ _)
      tₗ  = E i .Eq.lhs
      tᵣ = E i .Eq.rhs

------------------------------------------------------------------------
-- Completeness

-- Birkhoff's completeness theorem \citeyearpar{birkhoff:1935}:
-- Any valid consequence is derivable in the equational theory.

  module Completeness {I : Set ℓⁱ} (E : I  Eq) {Γ s} {t t' : Tm Γ s} where
    open TermModel E

    completeness : E  (t  t')  E  Γ  t  t'
    completeness V =     begin
      t                  ≈˘⟨ identity t 
      t  [ σ₀ ]          ≈˘⟨ evaluation t σ₀ 
       t    .apply σ₀  ≈⟨ V (M Γ) satisfies σ₀ 
       t'   .apply σ₀  ≈⟨ evaluation t' σ₀ 
      t' [ σ₀ ]          ≈⟨ identity t' 
      t'                 
      where open SetoidReasoning (TmSetoid Γ s)