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

syntax PDiff | PD

type
  * : 0-ary

term
  zero  : * | 𝟘
  add   : *  *  ->  * | _βŠ•_ l20
  one   : * | πŸ™
  mult  : *  *  ->  * | _βŠ—_ l20
  neg   : *  ->  * | βŠ–_ r50
  pd : *.*  *  ->  * | βˆ‚_∣_

theory
  (𝟘UβŠ•α΄Έ) a |> add (zero, a) = a
  (𝟘UβŠ•α΄Ώ) a |> add (a, zero) = a
  (βŠ•A) a b c |> add (add(a, b), c) = add (a, add(b, c))
  (βŠ•C) a b |> add(a, b) = add(b, a)
  (πŸ™UβŠ—α΄Έ) a |> mult (one, a) = a
  (πŸ™UβŠ—α΄Ώ) a |> mult (a, one) = a
  (βŠ—A) a b c |> mult (mult(a, b), c) = mult (a, mult(b, c))
  (βŠ—DβŠ•α΄Έ) a b c |> mult (a, add (b, c)) = add (mult(a, b), mult(a, c))
  (βŠ—DβŠ•α΄Ώ) a b c |> mult (add (a, b), c) = add (mult(a, c), mult(b, c))
  (𝟘XβŠ—α΄Έ) a |> mult (zero, a) = zero
  (𝟘XβŠ—α΄Ώ) a |> mult (a, zero) = zero
  (βŠ–NβŠ•α΄Έ) a |> add (neg (a), a) = zero
  (βŠ–NβŠ•α΄Ώ) a |> add (a, neg (a)) = zero
  (βŠ—C) a b |> mult(a, b) = mult(b, a)
  (βˆ‚βŠ•) a : * |> x : * |- d0 (add (x, a)) = one
  (βˆ‚βŠ—) a : * |> x : * |- d0 (mult(a, x)) = a
  (βˆ‚C) f : (*,*).* |> x : *  y : * |- d1 (d0 (f[x,y])) = d0 (d1 (f[x,y]))
  (βˆ‚Chβ‚‚) f : (*,*).*  g h : *.* |> x : * |- d0 (f[g[x], h[x]]) = add (mult(pd(z. f[z, h[x]], g[x]), d0(g[x])), mult(pd(z. f[g[x], z], h[x]), d0(h[x])))
  (βˆ‚Ch₁) f g : *.* |> x : * |- d0 (f[g[x]]) = mult (pd (z. f[z], g[x]), d0(g[x]))
-}


module PDiff.Syntax where

open import SOAS.Common
open import SOAS.Context
open import SOAS.Variable
open import SOAS.Families.Core
open import SOAS.Construction.Structure
open import SOAS.ContextMaps.Inductive

open import SOAS.Metatheory.Syntax

open import PDiff.Signature

private
  variable
    Ξ“ Ξ” Ξ  : Ctx
    Ξ± : *T
    𝔛 : Familyβ‚›

-- Inductive term declaration
module PD:Terms (𝔛 : Familyβ‚›) where

  data PD : Familyβ‚› where
    var  : ℐ β‡ΎΜ£ PD
    mvar : 𝔛 Ξ± Ξ  β†’ Sub PD Ξ  Ξ“ β†’ PD Ξ± Ξ“

    𝟘    : PD * Ξ“
    _βŠ•_  : PD * Ξ“ β†’ PD * Ξ“ β†’ PD * Ξ“
    πŸ™    : PD * Ξ“
    _βŠ—_  : PD * Ξ“ β†’ PD * Ξ“ β†’ PD * Ξ“
    βŠ–_   : PD * Ξ“ β†’ PD * Ξ“
    βˆ‚_∣_ : PD * (* βˆ™ Ξ“) β†’ PD * Ξ“ β†’ PD * Ξ“

  infixl 20 _βŠ•_
  infixl 30 _βŠ—_
  infixr 50 βŠ–_

  open import SOAS.Metatheory.MetaAlgebra β…€F 𝔛

  PDᡃ : MetaAlg PD
  PDᡃ = record
    { π‘Žπ‘™π‘” = Ξ» where
      (zeroβ‚’ β…‹ _)     β†’ 𝟘
      (addβ‚’  β…‹ a , b) β†’ _βŠ•_  a b
      (oneβ‚’  β…‹ _)     β†’ πŸ™
      (multβ‚’ β…‹ a , b) β†’ _βŠ—_  a b
      (negβ‚’  β…‹ a)     β†’ βŠ–_   a
      (pdβ‚’   β…‹ a , b) β†’ βˆ‚_∣_ a b
    ; π‘£π‘Žπ‘Ÿ = var ; π‘šπ‘£π‘Žπ‘Ÿ = Ξ» π”ͺ mΞ΅ β†’ mvar π”ͺ (tabulate mΞ΅) }

  module PDᡃ = MetaAlg PDᡃ

  module _ {π’œ : Familyβ‚›}(π’œα΅ƒ : MetaAlg π’œ) where

    open MetaAlg π’œα΅ƒ

    π•€π•–π•ž : PD β‡ΎΜ£ π’œ
    π•Š : Sub PD Ξ  Ξ“ β†’ Ξ  ~[ π’œ ]↝ Ξ“
    π•Š (t β—‚ Οƒ) new = π•€π•–π•ž t
    π•Š (t β—‚ Οƒ) (old v) = π•Š Οƒ v
    π•€π•–π•ž (mvar π”ͺ mΞ΅) = π‘šπ‘£π‘Žπ‘Ÿ π”ͺ (π•Š mΞ΅)
    π•€π•–π•ž (var v) = π‘£π‘Žπ‘Ÿ v

    π•€π•–π•ž  𝟘         = π‘Žπ‘™π‘” (zeroβ‚’ β…‹ tt)
    π•€π•–π•ž (_βŠ•_  a b) = π‘Žπ‘™π‘” (addβ‚’  β…‹ π•€π•–π•ž a , π•€π•–π•ž b)
    π•€π•–π•ž  πŸ™         = π‘Žπ‘™π‘” (oneβ‚’  β…‹ tt)
    π•€π•–π•ž (_βŠ—_  a b) = π‘Žπ‘™π‘” (multβ‚’ β…‹ π•€π•–π•ž a , π•€π•–π•ž b)
    π•€π•–π•ž (βŠ–_   a)   = π‘Žπ‘™π‘” (negβ‚’  β…‹ π•€π•–π•ž a)
    π•€π•–π•ž (βˆ‚_∣_ a b) = π‘Žπ‘™π‘” (pdβ‚’   β…‹ π•€π•–π•ž a , π•€π•–π•ž b)

    π•€π•–π•žα΅ƒβ‡’ : MetaAlgβ‡’ PDᡃ π’œα΅ƒ π•€π•–π•ž
    π•€π•–π•žα΅ƒβ‡’ = record
      { βŸ¨π‘Žπ‘™π‘”βŸ© = Ξ»{ {t = t} β†’ βŸ¨π‘Žπ‘™π‘”βŸ© t }
      ; βŸ¨π‘£π‘Žπ‘ŸβŸ© = refl
      ; βŸ¨π‘šπ‘£π‘Žπ‘ŸβŸ© = Ξ»{ {π”ͺ = π”ͺ}{mΞ΅} β†’ cong (π‘šπ‘£π‘Žπ‘Ÿ π”ͺ) (dext (π•Š-tab mΞ΅)) }  }
      where
      open ≑-Reasoning
      βŸ¨π‘Žπ‘™π‘”βŸ© : (t : β…€ PD Ξ± Ξ“) β†’ π•€π•–π•ž (PDᡃ.π‘Žπ‘™π‘” t) ≑ π‘Žπ‘™π‘” (⅀₁ π•€π•–π•ž t)
      βŸ¨π‘Žπ‘™π‘”βŸ© (zeroβ‚’ β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (addβ‚’  β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (oneβ‚’  β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (multβ‚’ β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (negβ‚’  β…‹ _) = refl
      βŸ¨π‘Žπ‘™π‘”βŸ© (pdβ‚’   β…‹ _) = refl

      π•Š-tab : (mΞ΅ : Ξ  ~[ PD ]↝ Ξ“)(v : ℐ Ξ± Ξ ) β†’ π•Š (tabulate mΞ΅) v ≑ π•€π•–π•ž (mΞ΅ v)
      π•Š-tab mΞ΅ new = refl
      π•Š-tab mΞ΅ (old v) = π•Š-tab (mΞ΅ ∘ old) v

    module _ (g : PD β‡ΎΜ£ π’œ)(gᡃ⇒ : MetaAlgβ‡’ PDᡃ π’œα΅ƒ g) where

      open MetaAlgβ‡’ gᡃ⇒

      π•€π•–π•ž! : (t : PD Ξ± Ξ“) β†’ π•€π•–π•ž t ≑ g t
      π•Š-ix : (mΞ΅ : Sub PD Ξ  Ξ“)(v : ℐ Ξ± Ξ ) β†’ π•Š mΞ΅ v ≑ g (index mΞ΅ v)
      π•Š-ix (x β—‚ mΞ΅) new = π•€π•–π•ž! x
      π•Š-ix (x β—‚ mΞ΅) (old v) = π•Š-ix mΞ΅ v
      π•€π•–π•ž! (mvar π”ͺ mΞ΅) rewrite cong (π‘šπ‘£π‘Žπ‘Ÿ π”ͺ) (dext (π•Š-ix mΞ΅))
        = trans (sym βŸ¨π‘šπ‘£π‘Žπ‘ŸβŸ©) (cong (g ∘ mvar π”ͺ) (tab∘ixβ‰ˆid mΞ΅))
      π•€π•–π•ž! (var v) = sym βŸ¨π‘£π‘Žπ‘ŸβŸ©

      π•€π•–π•ž! 𝟘 = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (_βŠ•_ a b) rewrite π•€π•–π•ž! a | π•€π•–π•ž! b = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! πŸ™ = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (_βŠ—_ a b) rewrite π•€π•–π•ž! a | π•€π•–π•ž! b = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (βŠ–_ a) rewrite π•€π•–π•ž! a = sym βŸ¨π‘Žπ‘™π‘”βŸ©
      π•€π•–π•ž! (βˆ‚_∣_ a b) rewrite π•€π•–π•ž! a | π•€π•–π•ž! b = sym βŸ¨π‘Žπ‘™π‘”βŸ©


-- Syntax instance for the signature
PD:Syn : Syntax
PD:Syn = record
  { β…€F = β…€F
  ; β…€:CS = β…€:CompatStr
  ; mvarα΅’ = PD:Terms.mvar
  ; 𝕋:Init = Ξ» 𝔛 β†’ let open PD:Terms 𝔛 in record
    { βŠ₯ = PD ⋉ PDᡃ
    ; βŠ₯-is-initial = record { ! = Ξ»{ {π’œ ⋉ π’œα΅ƒ} β†’ π•€π•–π•ž π’œα΅ƒ ⋉ π•€π•–π•žα΅ƒβ‡’ π’œα΅ƒ }
    ; !-unique = Ξ»{ {π’œ ⋉ π’œα΅ƒ} (f ⋉ fᡃ⇒) {x = t} β†’ π•€π•–π•ž! π’œα΅ƒ f fᡃ⇒ t } } } }

-- Instantiation of the syntax and metatheory
open Syntax PD:Syn public
open PD:Terms public
open import SOAS.Families.Build public
open import SOAS.Syntax.Shorthands PDᡃ public
open import SOAS.Metatheory PD:Syn public

-- Derived operations
βˆ‚β‚€_ : {𝔛 : Familyβ‚›} β†’ PD 𝔛 * (* βˆ™ Ξ“) β†’ PD 𝔛 * (* βˆ™ Ξ“)
βˆ‚β‚€_ {𝔛 = 𝔛} e = βˆ‚ Theory.π•¨π•œ 𝔛 e ∣ xβ‚€
βˆ‚β‚_ : {𝔛 : Familyβ‚›} β†’ PD 𝔛 * (* βˆ™ * βˆ™ Ξ“) β†’ PD 𝔛 * (* βˆ™ * βˆ™ Ξ“)
βˆ‚β‚_ {𝔛 = 𝔛} e = βˆ‚ Theory.π•¨π•œ 𝔛 e ∣ x₁
infix 10 βˆ‚β‚€_ βˆ‚β‚_