import Mathlib import Nominal namespace Algebra variable (𝔸 : Type) [Infinite 𝔸] [Countable 𝔸] [DecidableEq 𝔸] /-- A graded signature. -/ structure Signature where pure : Type free : Type bound : Type /-- Type representing the arguments required for an operation. -/ args : pure βŠ• free βŠ• bound β†’ Type args_fintype : βˆ€ f, Fintype (args f) := by intro; infer_instance /-- Depth of an operation. -/ depth : pure βŠ• free βŠ• bound β†’ β„• def Signature.pureArgs (sig : Signature) (f : sig.pure) : Type := sig.args (.inl f) def Signature.freeArgs (sig : Signature) (f : sig.free) : Type := sig.args (.inr (.inl f)) def Signature.boundArgs (sig : Signature) (f : sig.bound) : Type := sig.args (.inr (.inr f)) def Signature.pureArgs_fintype (sig : Signature) (f : sig.pure) : Fintype (sig.pureArgs f) := sig.args_fintype (.inl f) def Signature.freeArgs_fintype (sig : Signature) (f : sig.free) : Fintype (sig.freeArgs f) := sig.args_fintype (.inr (.inl f)) def Signature.boundArgs_fintype (sig : Signature) (f : sig.bound) : Fintype (sig.boundArgs f) := sig.args_fintype (.inr (.inr f)) def Signature.arity (sig : Signature) (f : sig.pure βŠ• sig.free βŠ• sig.bound) : β„• := (sig.args_fintype f).card def Signature.pureArity (sig : Signature) (f : sig.pure) : β„• := sig.arity (.inl f) def Signature.freeArity (sig : Signature) (f : sig.free) : β„• := sig.arity (.inr (.inl f)) def Signature.boundArity (sig : Signature) (f : sig.bound) : β„• := sig.arity (.inr (.inr f)) def Signature.pureDepth (sig : Signature) (f : sig.pure) : β„• := sig.depth (.inl f) def Signature.freeDepth (sig : Signature) (f : sig.free) : β„• := sig.depth (.inr (.inl f)) def Signature.boundDepth (sig : Signature) (f : sig.bound) : β„• := sig.depth (.inr (.inr f)) variable {sig : Signature} variable {X : Type} [NominalSet 𝔸 X] variable {Y : Type} [NominalSet 𝔸 Y] inductive Term (sig : Signature) (X : Type) [NominalSet 𝔸 X] | var (x : X) : Term sig X | pure (f : sig.pure) (args : sig.pureArgs f β†’ Term sig X) : Term sig X | free (a : 𝔸) (f : sig.free) (args : sig.freeArgs f β†’ Term sig X) : Term sig X | bound (a : 𝔸) (f : sig.bound) (args : sig.boundArgs f β†’ Term sig X) : Term sig X inductive Term.HasDepth : Term 𝔸 sig X β†’ β„• β†’ Prop | var (x : X) : HasDepth (.var x) 0 | pure (f : sig.pure) (args : sig.pureArgs f β†’ Term 𝔸 sig X) (k : β„•) : (βˆ€ arg : sig.pureArgs f, HasDepth (args arg) k) β†’ HasDepth (.pure f args) (k + sig.pureDepth f) | free (a : 𝔸) (f : sig.free) (args : sig.freeArgs f β†’ Term 𝔸 sig X) (k : β„•) : (βˆ€ arg : sig.freeArgs f, HasDepth (args arg) k) β†’ HasDepth (.free a f args) (k + sig.freeDepth f) | bound (a : 𝔸) (f : sig.bound) (args : sig.boundArgs f β†’ Term 𝔸 sig X) (k : β„•) : (βˆ€ arg : sig.boundArgs f, HasDepth (args arg) k) β†’ HasDepth (.bound a f args) (k + sig.boundDepth f) def TermAtDepth (sig : Signature) (X : Type) [NominalSet 𝔸 X] (n : β„•) := { t : Term 𝔸 sig X // t.HasDepth 𝔸 n } def Substitution (sig : Signature) (X : Type) [NominalSet 𝔸 X] (Y : Type) [NominalSet 𝔸 Y] (l : β„•) := X β†’ TermAtDepth 𝔸 sig Y l private def Substitution.apply' {l : β„•} (Οƒ : Substitution 𝔸 sig X Y l) : Term 𝔸 sig X β†’ Term 𝔸 sig Y | .var x => (Οƒ x).val | .pure f args => .pure f (fun x => Οƒ.apply' (args x)) | .free a f args => .free a f (fun x => Οƒ.apply' (args x)) | .bound a f args => .bound a f (fun x => Οƒ.apply' (args x)) def Substitution.apply {n l : β„•} (Οƒ : Substitution 𝔸 sig X Y l) (t : TermAtDepth 𝔸 sig X n) : TermAtDepth 𝔸 sig Y (n + l) := βŸ¨Οƒ.apply' 𝔸 t.val, by suffices βˆ€ t n, t.HasDepth 𝔸 n β†’ (Οƒ.apply' 𝔸 t).HasDepth 𝔸 (n + l) by exact this t.val n t.prop intro t; fun_induction apply' Β· intro n h; cases h rw [Nat.zero_add] exact (Οƒ _).prop all_goals intro n h; cases h; expose_names rw [Nat.add_right_comm] constructor; intro arg apply ih1; exact h arg⟩ private def rename' (Ο€ : FPerm 𝔸) : Term 𝔸 sig X β†’ Term 𝔸 sig X | .var x => .var x | .pure f args => .pure f (fun x => rename' Ο€ (args x)) | .free a f args => .free (Ο€ β€’ a) f (fun x => rename' Ο€ (args x)) | .bound a f args => .bound (Ο€ β€’ a) f (fun x => rename' Ο€ (args x)) private lemma one_rename (t : Term 𝔸 sig X) : rename' 𝔸 1 t = t := by induction' t <;> all_goals simp [rename', *] private lemma mul_rename (Ο€ Ο„ : FPerm 𝔸) (t : Term 𝔸 sig X) : rename' 𝔸 (Ο€ * Ο„) t = rename' 𝔸 Ο€ (rename' 𝔸 Ο„ t) := by induction' t <;> all_goals simp [rename', mul_smul, *] instance : PermSet 𝔸 (Term 𝔸 sig X) where smul := rename' 𝔸 one_smul := one_rename 𝔸 mul_smul := mul_rename 𝔸 private def rename {n : β„•} (Ο€ : FPerm 𝔸) (t : TermAtDepth 𝔸 sig X n) : TermAtDepth 𝔸 sig X n := βŸ¨Ο€ β€’ t.val, by suffices βˆ€ t n, t.HasDepth 𝔸 n β†’ (rename' 𝔸 Ο€ t).HasDepth 𝔸 n by exact this t.val n t.prop intro t; fun_induction rename' Β· intro n h; cases h; constructor all_goals intro n h; cases h expose_names constructor; intro arg apply ih1; exact h arg⟩ instance {n : β„•} : PermSet 𝔸 (TermAtDepth 𝔸 sig X n) where smul := rename 𝔸 one_smul t := by apply Subtype.eq; exact one_rename 𝔸 t.val mul_smul Ο€ Ο„ t := by apply Subtype.eq; exact mul_rename 𝔸 Ο€ Ο„ t.val end Algebra