Documentation

Mathlib.Data.PFunctor.Univariate.M

M-types #

M types are potentially infinite tree-like structures. They are defined as the greatest fixpoint of a polynomial functor.

inductive PFunctor.Approx.CofixA (F : PFunctor.{uA, uB}) :
β„• β†’ Type (max uA uB)

CofixA F n is an n level approximation of an M-type

Instances For
    def PFunctor.Approx.CofixA.default (F : PFunctor.{uA, uB}) [Inhabited F.A] (n : β„•) :
    CofixA F n

    default inhabitant of CofixA

    Instances For
      @[implicit_reducible]
      instance PFunctor.Approx.instInhabitedCofixAOfA (F : PFunctor.{uA, uB}) [Inhabited F.A] {n : β„•} :
      Inhabited (CofixA F n)
      def PFunctor.Approx.head' {F : PFunctor.{uA, uB}} {n : β„•} :
      CofixA F n.succ β†’ F.A

      The label of the root of the tree for a non-trivial approximation of the cofix of a pfunctor.

      Instances For
        def PFunctor.Approx.children' {F : PFunctor.{uA, uB}} {n : β„•} (x : CofixA F n.succ) :
        F.B (head' x) β†’ CofixA F n

        for a non-trivial approximation, return all the subtrees of the root

        Instances For
          inductive PFunctor.Approx.Agree {F : PFunctor.{uA, uB}} {n : β„•} :
          CofixA F n β†’ CofixA F (n + 1) β†’ Prop

          Relation between two approximations of the cofix of a pfunctor that state they both contain the same data until one of them is truncated

          Instances For
            def PFunctor.Approx.AllAgree {F : PFunctor.{uA, uB}} (x : (n : β„•) β†’ CofixA F n) :

            Given an infinite series of approximations approx, AllAgree approx states that they are all consistent with each other.

            Instances For
              theorem PFunctor.Approx.agree_children {F : PFunctor.{uA, uB}} {n : β„•} (x : CofixA F n.succ) (y : CofixA F (n.succ + 1)) {i : F.B (head' x)} {j : F.B (head' y)} (hβ‚€ : i ≍ j) (h₁ : Agree x y) :
              def PFunctor.Approx.truncate {F : PFunctor.{uA, uB}} {n : β„•} :
              CofixA F (n + 1) β†’ CofixA F n

              truncate a turns a into a more limited approximation

              Instances For
                theorem PFunctor.Approx.truncate_eq_of_agree {F : PFunctor.{uA, uB}} {n : β„•} (x : CofixA F n) (y : CofixA F n.succ) (h : Agree x y) :
                truncate y = x
                def PFunctor.Approx.sCorec {F : PFunctor.{uA, uB}} {X : Type w} (f : X β†’ ↑F X) :
                X β†’ (n : β„•) β†’ CofixA F n

                sCorec f i n creates an approximation of height n of the final coalgebra of f

                Instances For
                  theorem PFunctor.Approx.P_corec {F : PFunctor.{uA, uB}} {X : Type w} (f : X β†’ ↑F X) (i : X) (n : β„•) :
                  Agree (sCorec f i n) (sCorec f i n.succ)

                  Path F provides indices to access internal nodes in Corec F

                  Instances For
                    @[implicit_reducible]
                    theorem PFunctor.Approx.head_succ' {F : PFunctor.{uA, uB}} (n m : β„•) (x : (n : β„•) β†’ CofixA F n) (Hconsistent : AllAgree x) :
                    head' (x n.succ) = head' (x m.succ)
                    structure PFunctor.MIntl (F : PFunctor.{uA, uB}) :
                    Type (max uA uB)

                    Internal definition for M. It is needed to avoid name clashes between M.mk and M.casesOn and the declarations generated for the structure

                    Instances For
                      def PFunctor.M (F : PFunctor.{uA, uB}) :
                      Type (max uA uB)

                      For polynomial functor F, M F is its final coalgebra

                      Instances For
                        @[implicit_reducible]
                        instance PFunctor.MIntl.inhabited (F : PFunctor.{uA, uB}) [Inhabited F.A] :
                        Inhabited F.MIntl
                        @[implicit_reducible]
                        instance PFunctor.M.inhabited (F : PFunctor.{uA, uB}) [Inhabited F.A] :
                        Inhabited F.M
                        theorem PFunctor.M.ext' (F : PFunctor.{uA, uB}) (x y : F.M) (H : βˆ€ (i : β„•), x.approx i = y.approx i) :
                        x = y
                        def PFunctor.M.corec {F : PFunctor.{uA, uB}} {X : Type u_1} (f : X β†’ ↑F X) (i : X) :
                        F.M

                        Corecursor for the M-type defined by F.

                        Instances For
                          def PFunctor.M.head {F : PFunctor.{uA, uB}} (x : F.M) :
                          F.A

                          given a tree generated by F, head gives us the first piece of data it contains

                          Instances For
                            def PFunctor.M.children {F : PFunctor.{uA, uB}} (x : F.M) (i : F.B x.head) :
                            F.M

                            return all the subtrees of the root of a tree x : M F

                            Instances For
                              def PFunctor.M.ichildren {F : PFunctor.{uA, uB}} [Inhabited F.M] [DecidableEq F.A] (i : F.Idx) (x : F.M) :
                              F.M

                              select a subtree using an i : F.Idx or return an arbitrary tree if i designates no subtree of x

                              Instances For
                                theorem PFunctor.M.head_succ {F : PFunctor.{uA, uB}} (n m : β„•) (x : F.M) :
                                Approx.head' (x.approx n.succ) = Approx.head' (x.approx m.succ)
                                theorem PFunctor.M.head_eq_head' {F : PFunctor.{uA, uB}} (x : F.M) (n : β„•) :
                                x.head = Approx.head' (x.approx (n + 1))
                                theorem PFunctor.M.head'_eq_head {F : PFunctor.{uA, uB}} (x : F.M) (n : β„•) :
                                Approx.head' (x.approx (n + 1)) = x.head
                                def PFunctor.M.dest {F : PFunctor.{uA, uB}} :
                                F.M β†’ ↑F F.M

                                unfold an M-type

                                Instances For
                                  def PFunctor.M.Approx.sMk {F : PFunctor.{uA, uB}} (x : ↑F F.M) (n : β„•) :

                                  generates the approximations needed for M.mk

                                  Instances For
                                    def PFunctor.M.mk {F : PFunctor.{uA, uB}} (x : ↑F F.M) :
                                    F.M

                                    constructor for M-types

                                    Instances For
                                      inductive PFunctor.M.Agree' {F : PFunctor.{uA, uB}} :
                                      β„• β†’ F.M β†’ F.M β†’ Prop

                                      Agree' n relates two trees of type M F that are the same up to depth n

                                      Instances For
                                        @[simp]
                                        theorem PFunctor.M.dest_mk {F : PFunctor.{uA, uB}} (x : ↑F F.M) :
                                        (M.mk x).dest = x
                                        theorem PFunctor.M.mk_inj {F : PFunctor.{uA, uB}} {x y : ↑F F.M} (h : M.mk x = M.mk y) :
                                        x = y
                                        def PFunctor.M.cases {F : PFunctor.{uA, uB}} {r : F.M β†’ Sort w} (f : (x : ↑F F.M) β†’ r (M.mk x)) (x : F.M) :
                                        r x

                                        destructor for M-types

                                        Instances For
                                          def PFunctor.M.casesOn {F : PFunctor.{uA, uB}} {r : F.M β†’ Sort w} (x : F.M) (f : (x : ↑F F.M) β†’ r (M.mk x)) :
                                          r x

                                          destructor for M-types

                                          Instances For
                                            def PFunctor.M.casesOn' {F : PFunctor.{uA, uB}} {r : F.M β†’ Sort w} (x : F.M) (f : (a : F.A) β†’ (f : F.B a β†’ F.M) β†’ r (M.mk ⟨a, f⟩)) :
                                            r x

                                            destructor for M-types, similar to casesOn but also gives access directly to the root and subtrees on an M-type

                                            Instances For
                                              theorem PFunctor.M.approx_mk {F : PFunctor.{uA, uB}} (a : F.A) (f : F.B a β†’ F.M) (i : β„•) :
                                              (M.mk ⟨a, f⟩).approx i.succ = Approx.CofixA.intro a fun (j : F.B a) => (f j).approx i
                                              @[simp]
                                              theorem PFunctor.M.agree'_refl {F : PFunctor.{uA, uB}} {n : β„•} (x : F.M) :
                                              Agree' n x x
                                              theorem PFunctor.M.agree_iff_agree' {F : PFunctor.{uA, uB}} {n : β„•} (x y : F.M) :
                                              Approx.Agree (x.approx n) (y.approx (n + 1)) ↔ Agree' n x y
                                              @[simp]
                                              theorem PFunctor.M.cases_mk {F : PFunctor.{uA, uB}} {r : F.M β†’ Sort u_2} (x : ↑F F.M) (f : (x : ↑F F.M) β†’ r (M.mk x)) :
                                              M.cases f (M.mk x) = f x
                                              @[simp]
                                              theorem PFunctor.M.casesOn_mk {F : PFunctor.{uA, uB}} {r : F.M β†’ Sort u_2} (x : ↑F F.M) (f : (x : ↑F F.M) β†’ r (M.mk x)) :
                                              (M.mk x).casesOn f = f x
                                              @[simp]
                                              theorem PFunctor.M.casesOn_mk' {F : PFunctor.{uA, uB}} {r : F.M β†’ Sort u_2} {a : F.A} (x : F.B a β†’ F.M) (f : (a : F.A) β†’ (f : F.B a β†’ F.M) β†’ r (M.mk ⟨a, f⟩)) :
                                              (M.mk ⟨a, x⟩).casesOn' f = f a x
                                              inductive PFunctor.M.IsPath {F : PFunctor.{uA, uB}} :
                                              Approx.Path F β†’ F.M β†’ Prop

                                              IsPath p x tells us if p is a valid path through x

                                              Instances For
                                                theorem PFunctor.M.isPath_cons {F : PFunctor.{uA, uB}} {xs : Approx.Path F} {a a' : F.A} {f : F.B a β†’ F.M} {i : F.B a'} :
                                                IsPath (⟨a', i⟩ :: xs) (M.mk ⟨a, f⟩) β†’ a = a'
                                                theorem PFunctor.M.isPath_cons' {F : PFunctor.{uA, uB}} {xs : Approx.Path F} {a : F.A} {f : F.B a β†’ F.M} {i : F.B a} :
                                                IsPath (⟨a, i⟩ :: xs) (M.mk ⟨a, f⟩) β†’ IsPath xs (f i)
                                                def PFunctor.M.isubtree {F : PFunctor.{uA, uB}} [DecidableEq F.A] [Inhabited F.M] :
                                                Approx.Path F β†’ F.M β†’ F.M

                                                follow a path through a value of M F and return the subtree found at the end of the path if it is a valid path for that value and return a default tree

                                                Instances For
                                                  def PFunctor.M.iselect {F : PFunctor.{uA, uB}} [DecidableEq F.A] [Inhabited F.M] (ps : Approx.Path F) :
                                                  F.M β†’ F.A

                                                  similar to isubtree but returns the data at the end of the path instead of the whole subtree

                                                  Instances For
                                                    theorem PFunctor.M.iselect_eq_default {F : PFunctor.{uA, uB}} [DecidableEq F.A] [Inhabited F.M] (ps : Approx.Path F) (x : F.M) (h : Β¬IsPath ps x) :
                                                    @[simp]
                                                    theorem PFunctor.M.head_mk {F : PFunctor.{uA, uB}} (x : ↑F F.M) :
                                                    (M.mk x).head = x.fst
                                                    theorem PFunctor.M.children_mk {F : PFunctor.{uA, uB}} {a : F.A} (x : F.B a β†’ F.M) (i : F.B (M.mk ⟨a, x⟩).head) :
                                                    (M.mk ⟨a, x⟩).children i = x (cast β‹― i)
                                                    @[simp]
                                                    theorem PFunctor.M.ichildren_mk {F : PFunctor.{uA, uB}} [DecidableEq F.A] [Inhabited F.M] (x : ↑F F.M) (i : F.Idx) :
                                                    ichildren i (M.mk x) = x.iget i
                                                    @[simp]
                                                    theorem PFunctor.M.isubtree_cons {F : PFunctor.{uA, uB}} [DecidableEq F.A] [Inhabited F.M] (ps : Approx.Path F) {a : F.A} (f : F.B a β†’ F.M) {i : F.B a} :
                                                    isubtree (⟨a, i⟩ :: ps) (M.mk ⟨a, f⟩) = isubtree ps (f i)
                                                    @[simp]
                                                    theorem PFunctor.M.iselect_nil {F : PFunctor.{uA, uB}} [DecidableEq F.A] [Inhabited F.M] {a : F.A} (f : F.B a β†’ F.M) :
                                                    iselect [] (M.mk ⟨a, f⟩) = a
                                                    @[simp]
                                                    theorem PFunctor.M.iselect_cons {F : PFunctor.{uA, uB}} [DecidableEq F.A] [Inhabited F.M] (ps : Approx.Path F) {a : F.A} (f : F.B a β†’ F.M) {i : F.B a} :
                                                    iselect (⟨a, i⟩ :: ps) (M.mk ⟨a, f⟩) = iselect ps (f i)
                                                    theorem PFunctor.M.corec_def {F : PFunctor.{uA, uB}} {X : Type u_2} (f : X β†’ ↑F X) (xβ‚€ : X) :
                                                    M.corec f xβ‚€ = M.mk (F.map (M.corec f) (f xβ‚€))
                                                    theorem PFunctor.M.ext_aux {F : PFunctor.{uA, uB}} [Inhabited F.M] [DecidableEq F.A] {n : β„•} (x y z : F.M) (hx : Agree' n z x) (hy : Agree' n z y) (hrec : βˆ€ (ps : Approx.Path F), n = List.length ps β†’ iselect ps x = iselect ps y) :
                                                    x.approx (n + 1) = y.approx (n + 1)
                                                    theorem PFunctor.M.ext {F : PFunctor.{uA, uB}} [Inhabited F.M] [DecidableEq F.A] (x y : F.M) (H : βˆ€ (ps : Approx.Path F), iselect ps x = iselect ps y) :
                                                    x = y
                                                    structure PFunctor.M.IsBisimulation {F : PFunctor.{uA, uB}} (R : F.M β†’ F.M β†’ Prop) :

                                                    Bisimulation is the standard proof technique for equality between infinite tree-like structures

                                                    • head {a a' : F.A} {f : F.B a β†’ F.M} {f' : F.B a' β†’ F.M} : R (M.mk ⟨a, f⟩) (M.mk ⟨a', f'⟩) β†’ a = a'

                                                      The head of the trees are equal

                                                    • tail {a : F.A} {f f' : F.B a β†’ F.M} : R (M.mk ⟨a, f⟩) (M.mk ⟨a, f'⟩) β†’ βˆ€ (i : F.B a), R (f i) (f' i)

                                                      The tails are equal

                                                    Instances For
                                                      theorem PFunctor.M.nth_of_bisim {F : PFunctor.{uA, uB}} (R : F.M β†’ F.M β†’ Prop) [Inhabited F.M] [DecidableEq F.A] (bisim : IsBisimulation R) (s₁ sβ‚‚ : F.M) (ps : Approx.Path F) :
                                                      R s₁ sβ‚‚ β†’ IsPath ps s₁ ∨ IsPath ps sβ‚‚ β†’ iselect ps s₁ = iselect ps sβ‚‚ ∧ βˆƒ (a : F.A) (f : F.B a β†’ F.M) (f' : F.B a β†’ F.M), isubtree ps s₁ = M.mk ⟨a, f⟩ ∧ isubtree ps sβ‚‚ = M.mk ⟨a, f'⟩ ∧ βˆ€ (i : F.B a), R (f i) (f' i)
                                                      theorem PFunctor.M.eq_of_bisim {F : PFunctor.{uA, uB}} (R : F.M β†’ F.M β†’ Prop) [Nonempty F.M] (bisim : IsBisimulation R) (s₁ sβ‚‚ : F.M) :
                                                      R s₁ sβ‚‚ β†’ s₁ = sβ‚‚
                                                      def PFunctor.M.corecOn {F : PFunctor.{uA, uB}} {X : Type u_2} (xβ‚€ : X) (f : X β†’ ↑F X) :
                                                      F.M

                                                      corecursor for M F with swapped arguments

                                                      Instances For
                                                        theorem PFunctor.M.dest_corec {P : PFunctor.{uA, uB}} {Ξ± : Type u_2} (g : Ξ± β†’ ↑P Ξ±) (x : Ξ±) :
                                                        (M.corec g x).dest = P.map (M.corec g) (g x)
                                                        theorem PFunctor.M.bisim {P : PFunctor.{uA, uB}} (R : P.M β†’ P.M β†’ Prop) (h : βˆ€ (x y : P.M), R x y β†’ βˆƒ (a : P.A) (f : P.B a β†’ P.M) (f' : P.B a β†’ P.M), x.dest = ⟨a, f⟩ ∧ y.dest = ⟨a, f'⟩ ∧ βˆ€ (i : P.B a), R (f i) (f' i)) (x y : P.M) :
                                                        R x y β†’ x = y
                                                        theorem PFunctor.M.bisim' {P : PFunctor.{uA, uB}} {Ξ± : Type u_3} (Q : Ξ± β†’ Prop) (u v : Ξ± β†’ P.M) (h : βˆ€ (x : Ξ±), Q x β†’ βˆƒ (a : P.A) (f : P.B a β†’ P.M) (f' : P.B a β†’ P.M), (u x).dest = ⟨a, f⟩ ∧ (v x).dest = ⟨a, f'⟩ ∧ βˆ€ (i : P.B a), βˆƒ (x' : Ξ±), Q x' ∧ f i = u x' ∧ f' i = v x') (x : Ξ±) :
                                                        Q x β†’ u x = v x
                                                        theorem PFunctor.M.bisim_equiv {P : PFunctor.{uA, uB}} (R : P.M β†’ P.M β†’ Prop) (h : βˆ€ (x y : P.M), R x y β†’ βˆƒ (a : P.A) (f : P.B a β†’ P.M) (f' : P.B a β†’ P.M), x.dest = ⟨a, f⟩ ∧ y.dest = ⟨a, f'⟩ ∧ βˆ€ (i : P.B a), R (f i) (f' i)) (x y : P.M) :
                                                        R x y β†’ x = y
                                                        theorem PFunctor.M.corec_unique {P : PFunctor.{uA, uB}} {Ξ± : Type u_2} (g : Ξ± β†’ ↑P Ξ±) (f : Ξ± β†’ P.M) (hyp : βˆ€ (x : Ξ±), (f x).dest = P.map f (g x)) :
                                                        f = M.corec g
                                                        def PFunctor.M.corec₁ {P : PFunctor.{uA, uB}} {Ξ± : Type u} (F : (X : Type u) β†’ (Ξ± β†’ X) β†’ Ξ± β†’ ↑P X) :
                                                        Ξ± β†’ P.M

                                                        corecursor where the state of the computation can be sent downstream in the form of a recursive call

                                                        Instances For
                                                          def PFunctor.M.corec' {P : PFunctor.{uA, uB}} {Ξ± : Type u} (F : {X : Type (max u uA uB)} β†’ (Ξ± β†’ X) β†’ Ξ± β†’ P.M βŠ• ↑P X) (x : Ξ±) :
                                                          P.M

                                                          corecursor where it is possible to return a fully formed value at any point of the computation

                                                          Instances For