The translation f ≫ g of a composition η ∘ₖ κ, from the translations f of κ and g of
η (see comp_toHom).
8. Implementation of the translation
The translation performed by kernel_hom traverses the kernel expression twice (once to lift it to a common universe level, once to translate it into SFinKer) and builds, at each node, an instance of a translation lemma such as comp_toHom_of_eq or comp_lift_of_eq. Three design choices keep this cheap and safe.
8.1. Proofs by congruence lemmas
The proof of equivalence between the original equality and the translated one is not obtained by rewriting the goal with the translation lemmas (which requires abstracting a pattern and type-checking a motive at each step), but by congruence: each translation function returns the translated expression together with a proof that it is the translation of the original one, built from the proofs of its subterms. The translation lemmas are stated for this purpose with the translations of the subterms as hypotheses, so that each step of the translation is a single application of a lemma:
ProbabilityTheory.Kernel.comp_toHom_of_eq.{x, y, z, u} {X : Type x} {Y : Type y} {Z : Type z} [MeasurableSpace X] [MeasurableSpace Y] [MeasurableSpace Z] {SX SY SZ : SFinKer} {ex : SX.carrier ≃ᵐ X} {ey : SY.carrier ≃ᵐ Y} {ez : SZ.carrier ≃ᵐ Z} {η : ProbabilityTheory.Kernel X Y} {κ : ProbabilityTheory.Kernel Z X} [ProbabilityTheory.IsSFiniteKernel η] [ProbabilityTheory.IsSFiniteKernel κ] {f : SZ ⟶ SX} {g : SX ⟶ SY} (hf : f = κ.toHom) (hg : g = η.toHom) : CategoryTheory.CategoryStruct.comp f g = (η.comp κ).toHomProbabilityTheory.Kernel.comp_toHom_of_eq.{x, y, z, u} {X : Type x} {Y : Type y} {Z : Type z} [MeasurableSpace X] [MeasurableSpace Y] [MeasurableSpace Z] {SX SY SZ : SFinKer} {ex : SX.carrier ≃ᵐ X} {ey : SY.carrier ≃ᵐ Y} {ez : SZ.carrier ≃ᵐ Z} {η : ProbabilityTheory.Kernel X Y} {κ : ProbabilityTheory.Kernel Z X} [ProbabilityTheory.IsSFiniteKernel η] [ProbabilityTheory.IsSFiniteKernel κ] {f : SZ ⟶ SX} {g : SX ⟶ SY} (hf : f = κ.toHom) (hg : g = η.toHom) : CategoryTheory.CategoryStruct.comp f g = (η.comp κ).toHom
The same lemmas serve both directions: kernelToHom and homToKernel both return a proof of f = κ.toHom, where f is the morphism and κ the kernel. The equality of propositions is then obtained from toHom_congr_of_eq (or lift_congr_of_eq for the lifting, which follows the same structure in Eq-Lift).
ProbabilityTheory.Kernel.toHom_congr_of_eq.{x, y, u} {X : Type x} {Y : Type y} [MeasurableSpace X] [MeasurableSpace Y] {SX SY : SFinKer} {ex : SX.carrier ≃ᵐ X} {ey : SY.carrier ≃ᵐ Y} {κ η : ProbabilityTheory.Kernel X Y} [ProbabilityTheory.IsSFiniteKernel κ] [ProbabilityTheory.IsSFiniteKernel η] {f g : SX ⟶ SY} (hf : f = κ.toHom) (hg : g = η.toHom) : (κ = η) = (f = g)ProbabilityTheory.Kernel.toHom_congr_of_eq.{x, y, u} {X : Type x} {Y : Type y} [MeasurableSpace X] [MeasurableSpace Y] {SX SY : SFinKer} {ex : SX.carrier ≃ᵐ X} {ey : SY.carrier ≃ᵐ Y} {κ η : ProbabilityTheory.Kernel X Y} [ProbabilityTheory.IsSFiniteKernel κ] [ProbabilityTheory.IsSFiniteKernel η] {f g : SX ⟶ SY} (hf : f = κ.toHom) (hg : g = η.toHom) : (κ = η) = (f = g)
The equivalence between an equality of kernels and the equality of their translations f and
g, given by toHom_congr.
8.2. Terms built with Qq
The terms and the lemma instances are built with the quotations q(...) of Qq. A quotation is elaborated when the tactic is compiled, and only instantiated at run time: the result is as cheap as an explicit application (mkAppN with explicit universe levels and instances), without the unification and instance synthesis of mkAppM, which dominated the cost of the translation. Moreover, the quotations are type-checked against the statements of the lemmas, so that an argument in the wrong position is a compilation error rather than an ill-typed proof at run time. The category-theoretic instances of SFinKer (Category, MonoidalCategory, ...) are synthesized at compilation as well.
The expressions are typed by the expressions of their types: Q(Kernel $X $Y) is the type of the expressions of a kernel from X to Y. The kernel and categorical expressions are matched syntactically, with match_expr, and their subterms are then given such types. The recursion itself works on untyped expressions: kernelToHomQ gives the typed view of the translation of a subterm, assuming that the carriers of its source and target are those of homCarrier.
kernelToHomQ {u : Lean.Level} {X Y : Q(Type u)} {mX : Q(MeasurableSpace «$X»)} {mY : Q(MeasurableSpace «$Y»)} {SX SY : Q(SFinKer)} (ex : Q(«$SX».carrier ≃ᵐ «$X»)) (ey : Q(«$SY».carrier ≃ᵐ «$Y»)) (κ : Lean.Expr) : Lean.MetaM ((κ : Q(ProbabilityTheory.Kernel «$X» «$Y»)) × (x : Q(ProbabilityTheory.IsSFiniteKernel «$κ»)) × (f : Q(«$SX» ⟶ «$SY»)) × Q(«$f» = «$κ».toHom))kernelToHomQ {u : Lean.Level} {X Y : Q(Type u)} {mX : Q(MeasurableSpace «$X»)} {mY : Q(MeasurableSpace «$Y»)} {SX SY : Q(SFinKer)} (ex : Q(«$SX».carrier ≃ᵐ «$X»)) (ey : Q(«$SY».carrier ≃ᵐ «$Y»)) (κ : Lean.Expr) : Lean.MetaM ((κ : Q(ProbabilityTheory.Kernel «$X» «$Y»)) × (x : Q(ProbabilityTheory.IsSFiniteKernel «$κ»)) × (f : Q(«$SX» ⟶ «$SY»)) × Q(«$f» = «$κ».toHom))
Typed version of kernelToHom, for a kernel κ : Kernel X Y and the carriers ex : SX ≃ᵐ X
and ey : SY ≃ᵐ Y of X and Y given by homCarrier (as in kernelToHom): returns κ with its
IsSFiniteKernel instance, its translation f : SX ⟶ SY and the proof of f = κ.toHom.
8.3. Memoization
The instances (MeasurableSpace X, IsSFiniteKernel κ, ...) and the recursively built objects (measurable equivalences, objects of SFinKer) are memoized in a cache which is reset at the beginning of each transformation. The cache lives in Eq-Lift:
The cache of the lifting/unlifting transformations.
Constructor
TransformCache.mk
Fields
insts : Std.HashMap Lean.Expr Lean.Expr
Synthesized instances, keyed by the class application.
memo : Std.HashMap (Lean.Name × Lean.Expr) (Array Lean.Expr)
Memoized computations, keyed by a tag and an expression.
Empties the cache. To be called at the beginning of each transformation.
synthInstance with memoization.
8.4. Carriers
During the lifting, each measurable space comes with its lift to the common universe level and the measurable equivalence between them, computed once per carrier by liftCarrier, and recovered from the lifted space by unliftCarrier. Both live in Eq-Lift:
liftCarrier (w : Lean.Level) (X : Lean.Expr) : Lean.MetaM ((x : Lean.Level) × (X : Q(Type x)) × (x_1 : Q(MeasurableSpace «$X»)) × (X' : Q(Type w)) × (x_2 : Q(MeasurableSpace «$X'»)) × Q(«$X'» ≃ᵐ «$X»))liftCarrier (w : Lean.Level) (X : Lean.Expr) : Lean.MetaM ((x : Lean.Level) × (X : Q(Type x)) × (x_1 : Q(MeasurableSpace «$X»)) × (X' : Q(Type w)) × (x_2 : Q(MeasurableSpace «$X'»)) × Q(«$X'» ≃ᵐ «$X»))
The lift X' of a measurable space X : Type x to the universe w, together with the
MeasurableSpace instances of X and X' and the measurable equivalence X' ≃ᵐ X. Products are
lifted componentwise, PUnit to PUnit and the other types to ULift.
unliftCarrier (w : Lean.Level) (X' : Lean.Expr) : Lean.MetaM ((X' : Q(Type w)) × (x : Q(MeasurableSpace «$X'»)) × (x_1 : Lean.Level) × (X : Q(Type x_1)) × (x_2 : Q(MeasurableSpace «$X»)) × Q(«$X'» ≃ᵐ «$X»))unliftCarrier (w : Lean.Level) (X' : Lean.Expr) : Lean.MetaM ((X' : Q(Type w)) × (x : Q(MeasurableSpace «$X'»)) × (x_1 : Lean.Level) × (X : Q(Type x_1)) × (x_2 : Q(MeasurableSpace «$X»)) × Q(«$X'» ≃ᵐ «$X»))
A lifted measurable space X' : Type w with its original space X (see getOriginalType),
their MeasurableSpace instances and the measurable equivalence X' ≃ᵐ X of liftCarrier.
After the lifting, all the carriers live in the same universe, in which the translation takes place.
The universe level w of the carriers of a lifted kernel κ : Kernel X Y: all the carriers of
a lifted equality live in Type w.
The translation to SFinKer needs more data about each carrier X: the object of SFinKer it is translated to (SFinKer.of X, or a tensor product of such objects when X is a product, so that the monoidal tactics see the tensor structure) and the measurable equivalence between the carrier of this object and X, which is the argument ex of toHom and of the translation lemmas. They are computed once per carrier by homCarrier.
homCarrier (u : Lean.Level) (X : Lean.Expr) : Lean.MetaM ((X : Q(Type u)) × (x : Q(MeasurableSpace «$X»)) × (SX : Q(SFinKer)) × Q(«$SX».carrier ≃ᵐ «$X»))homCarrier (u : Lean.Level) (X : Lean.Expr) : Lean.MetaM ((X : Q(Type u)) × (x : Q(MeasurableSpace «$X»)) × (SX : Q(SFinKer)) × Q(«$SX».carrier ≃ᵐ «$X»))
The object SX of SFinKer.{u} associated with a measurable space X : Type u, together with
the MeasurableSpace instance of X and the measurable equivalence SX ≃ᵐ X. Products are
decomposed into tensor products and PUnit into the monoidal unit, so that the monoidal tactics see
the tensor structure (memoized).
homCarrierOfEquiv (u : Lean.Level) (e₀ : Lean.Expr) : Lean.MetaM ((X : Q(Type u)) × (x : Q(MeasurableSpace «$X»)) × (SX : Q(SFinKer)) × (_ : Q(«$SX».carrier ≃ᵐ «$X»)) × (v : Lean.Level) × (X₀ : Q(Type v)) × (x_2 : Q(MeasurableSpace «$X₀»)) × Q(«$X» ≃ᵐ «$X₀»))homCarrierOfEquiv (u : Lean.Level) (e₀ : Lean.Expr) : Lean.MetaM ((X : Q(Type u)) × (x : Q(MeasurableSpace «$X»)) × (SX : Q(SFinKer)) × (_ : Q(«$SX».carrier ≃ᵐ «$X»)) × (v : Lean.Level) × (X₀ : Q(Type v)) × (x_2 : Q(MeasurableSpace «$X₀»)) × Q(«$X» ≃ᵐ «$X₀»))
For a measurable equivalence e₀ : X ≃ᵐ X₀ from a lifted measurable space X : Type u to the
original space X₀ : Type v (an equivalence of Kernel.lift, or a component of one): the data of
homCarrier for X, then X₀ with its universe level and its MeasurableSpace instance, and
e₀.
In the other direction, the carrier of an object is computed by typeOfObj, and its data by homCarrier again.
objCarrier (u : Lean.Level) (SX : Lean.Expr) : Lean.MetaM ((SX : Q(SFinKer)) × (X : Q(Type u)) × (x : Q(MeasurableSpace «$X»)) × Q(«$SX».carrier ≃ᵐ «$X»))objCarrier (u : Lean.Level) (SX : Lean.Expr) : Lean.MetaM ((SX : Q(SFinKer)) × (X : Q(Type u)) × (x : Q(MeasurableSpace «$X»)) × Q(«$SX».carrier ≃ᵐ «$X»))
An object SX of SFinKer.{u} with its carrier X, the MeasurableSpace instance of X and
the measurable equivalence SX ≃ᵐ X of homCarrier.