Documentation

LambdaS.Ratio

Conversion ratios as syntax #

Concretely, convert x m ft contributes the ratio m/ft, and the round trip convert (convert x m ft) ft m accumulates (m/ft) · (ft/m) = 1; this file gives ratios like these a first-order syntax.

An earlier design, since deleted, carried a term's accumulated conversion ratio as a semantic object: at arrow type the ratio was a Lean function space. That works at first order and stops working at a unit binder, and the reason is worth stating, because it is a familiar one.

A function space is higher-order abstract syntax for the ratio map, and HOAS cannot be traversed or substituted into. Instantiating a unit variable is a substitution, so e[μ] has nowhere to send the ratio of e; and the map is contravariant at arrow type, so no covariant transport exists either. A ratio analysis built on function spaces has nothing to say at a quantifier: not a choice, an obstruction.

This file makes ratios first-order instead. Two things fall out beyond covering the quantifiers.

Substitution disappears rather than becoming structural: Tw.uapp records the instantiating unit instead of performing it, and the interpretation does the work. So there is no ratio-substitution lemma at all, and no transport.

And a first-order ratio is inspectable. With a function space you can define a term's ratio but never decide whether it is trivial; with syntax you can, which turns Twist.invariant_iff from a characterization into an algorithm: the compiler diagnostic "this program's conversions do not cancel, so its result depends on the declared magnitudes".

Shapes #

Ratios are indexed by a Shape (the type's skeleton) rather than by the type. That is not a simplification but an observation: the deleted semantic ratios never inspected a type's units, only its structure, so type-indexing was buying nothing. A shape records where the ratio is a unit (scalar), where it is a map (arrow), where it is a family of scalars (vec and mat, for spaces and linear maps: the drift of a vector is a vector of drifts, and the drift of a matrix is a matrix of drifts, indexed by component counts, which are unit-blind), and where a unit binder was crossed (bind).

inductive LambdaS.Shape :

The skeleton of a type, as far as conversion ratios can see.

  • scalar : Shape

    A quantity: the ratio is a unit expression.

  • arrow : ShapeShapeShape

    A function: the ratio maps ratios to ratios.

  • vec : Shape

    A space of the given length: one scalar ratio per component.

  • mat : Shape

    A linear map, by domain and codomain lengths: one scalar ratio per entry.

  • bind : ShapeShape

    Under a unit binder: the ratio lives one unit scope out.

Instances For
    def LambdaS.instDecidableEqShape.decEq (x✝ x✝¹ : Shape) :
    Decidable (x✝ = x✝¹)
    Equations
    Instances For
      @[instance_reducible]
      Equations
      Equations
      Instances For
        @[reducible]
        def LambdaS.Ty.shape {B D : Type} {j k : } :
        Ty B D j kShape

        The shape of a type. Units are ignored; only the structure survives.

        @[reducible] for the same reason Ty.den is: instance synthesis runs at reducible transparency, and SemTw (Ty.shape (.Q u)) has to resolve to the positive-real carrier.

        Equations
        Instances For
          def LambdaS.Ctx.shapes {B D : Type} {j k : } (Γ : Ctx B D j k) :

          The shapes of a context, one ratio variable per term variable.

          Equations
          Instances For
            @[simp]
            theorem LambdaS.Ctx.shapes_nil {B D : Type} {j k : } :
            @[simp]
            theorem LambdaS.Ctx.shapes_cons {B D : Type} {j k : } (τ : Ty B D j k) (Γ : Ctx B D j k) :
            shapes (τ :: Γ) = τ.shape :: Γ.shapes
            theorem LambdaS.Ctx.shapes_getElem? {B D : Type} {j k : } {Γ : Ctx B D j k} {n : } {τ : Ty B D j k} (h : Γ[n]? = some τ) :

            A context lookup, read at the shapes.

            @[simp]
            theorem LambdaS.Ty.shape_ground {B D : Type} {j k : } (τ : Ty B D j k) {j₀ k₀ : } (η : Fin kUExp B k₀) (δ : Fin jDExp D j₀) :
            (ground η δ τ).shape = τ.shape

            Shape is blind to units. Grounding a type through unit and dimension environments leaves its shape alone, which is why ratios need no transport: the Tw indexed by a type is equally an index for every instantiation of it. The space cases are List.length_map: lengths are unit-blind.

            @[simp]
            theorem LambdaS.Ty.shape_subst {B D : Type} {j k : } (τ : Ty B D j (k + 1)) (μ : UExp B k) :
            (τ.subst μ).shape = τ.shape
            @[simp]
            theorem LambdaS.Ty.shape_substDim {B D : Type} {j k : } (τ : Ty B D (j + 1) k) (d : DExp D j) :
            (τ.substDim d).shape = τ.shape
            @[simp]
            theorem LambdaS.Ty.shape_weaken {B D : Type} {j k : } (τ : Ty B D j k) :
            @[simp]
            theorem LambdaS.Ty.shape_weakenDim {B D : Type} {j k : } (τ : Ty B D j k) :
            @[simp]
            theorem LambdaS.Ctx.shapes_weaken {B D : Type} {j k : } (Γ : Ctx B D j k) :
            @[simp]
            theorem LambdaS.Ctx.shapes_weakenDim {B D : Type} {j k : } (Γ : Ctx B D j k) :

            The syntax of ratios #

            A ratio is an open term over a context of ratio variables (one for each free term variable) in the free abelian group generated by unit expressions, closed under abstraction and application so that the analysis passes first order.

            uapp records its instantiating unit rather than substituting it. That is what makes the whole construction transport-free.

            inductive LambdaS.Tw (B : Type) :
            List ShapeShapeType

            Conversion-ratio expressions.

            Instances For
              def LambdaS.Tw.castShape {B : Type} {k : } {Θ : List Shape} {s s' : Shape} (h : s = s') :
              Tw B k Θ sTw B k Θ s'

              Retyping a ratio along an equality of shapes. Needed only at uapp and dapp, where the result type is τ.subst σ and Ty.shape_subst is a theorem rather than a definitional equality, and at a matrix row, whose space is a map over the column space with List.length_map likewise a theorem.

              Equations
              Instances For
                @[simp]
                theorem LambdaS.Tw.castShape_rfl {B : Type} {k : } {Θ : List Shape} {s : Shape} (t : Tw B k Θ s) :
                castShape t = t

                Renaming and substitution #

                uapp records unit instantiation, so no unit-substitution is ever forced; but a recorded β-redex (app (lam t) s, or uapp (ulam t) μ) is opaque to the flat-form comparison, which costs completeness at the agreement checks. These operations let the redexes that arise at construction be reduced on the spot: a ratio-context renaming (for weakening a substituend under lam), a unit-scope pullback (for carrying a substituend under ulam, and for performing a recorded instantiation), and simultaneous substitution built from the two. Each preserves evaluation, which is proved below the interpreter.

                def LambdaS.Tw.liftR (f : ) :

                Lifting a ratio-context renaming under a binder.

                Equations
                Instances For
                  theorem LambdaS.Tw.liftR_ok {Θ Θ' : List Shape} {s₀ : Shape} (f : ) (hf : ∀ (n : ) (s : Shape), Θ[n]? = some sΘ'[f n]? = some s) (n : ) (s : Shape) :
                  (s₀ :: Θ)[n]? = some s → (s₀ :: Θ')[liftR f n]? = some s

                  A lifted renaming stays coherent with the shape contexts.

                  def LambdaS.Tw.rename {B : Type} {k : } {Θ Θ' : List Shape} (f : ) :
                  (∀ (n : ) (s : Shape), Θ[n]? = some sΘ'[f n]? = some s){s : Shape} → Tw B k Θ sTw B k Θ' s

                  Renaming the ratio context along a coherent index map.

                  Equations
                  Instances For
                    def LambdaS.Tw.weakenR {B : Type} {k : } {Θ : List Shape} {s₀ s : Shape} (t : Tw B k Θ s) :
                    Tw B k (s₀ :: Θ) s

                    Weakening by a fresh ratio variable at position 0.

                    Equations
                    Instances For
                      def LambdaS.Tw.pullU {B : Type} {k k' : } (η : Fin kUExp B k') {Θ : List Shape} {s : Shape} :
                      Tw B k Θ sTw B k' Θ s

                      Pulling a ratio back along a unit substitution: every unit constant is substituted, and a recorded instantiation records the substituted unit. The syntactic face of Scaling.pull.

                      Equations
                      Instances For
                        def LambdaS.Tw.uweaken {B : Type} {k : } {Θ : List Shape} {s : Shape} (t : Tw B k Θ s) :
                        Tw B (k + 1) Θ s

                        Weakening the unit scope by a fresh unit variable.

                        Equations
                        Instances For
                          def LambdaS.Tw.liftS {B : Type} {k : } {Θ Θ' : List Shape} {s₀ : Shape} (σ : (n : ) → (s : Shape) → Θ[n]? = some sTw B k Θ' s) (n : ) (s : Shape) :
                          (s₀ :: Θ)[n]? = some sTw B k (s₀ :: Θ') s

                          Lifting a simultaneous substitution under a binder: the bound variable maps to itself and everything else is weakened past it.

                          Equations
                          Instances For
                            def LambdaS.Tw.subst {B : Type} {k : } {Θ Θ' : List Shape} (σ : (n : ) → (s : Shape) → Θ[n]? = some sTw B k Θ' s) {s : Shape} :
                            Tw B k Θ sTw B k Θ' s

                            Simultaneous substitution of ratios for ratio variables. Crossing lam lifts the substitution; crossing ulam weakens every substituend's unit scope.

                            Equations
                            Instances For
                              def LambdaS.Tw.subst0 {B : Type} {k : } {Θ : List Shape} {s₀ s : Shape} (t : Tw B k (s₀ :: Θ) s) (a : Tw B k Θ s₀) :
                              Tw B k Θ s

                              Substituting for the most recently bound ratio variable.

                              Equations
                              • One or more equations did not get rendered due to their size.
                              Instances For
                                def LambdaS.Tw.appE {B : Type} {k : } {Θ : List Shape} {s t : Shape} :
                                Tw B k Θ (s.arrow t)Tw B k Θ sTw B k Θ t

                                Application that β-reduces when the head is a literal abstraction, so that a redex formed at construction is not left for the flat form to treat as an opaque atom.

                                Equations
                                Instances For
                                  def LambdaS.Tw.uappE {B : Type} {k : } {Θ : List Shape} {s : Shape} :
                                  Tw B k Θ s.bindUExp B kTw B k Θ s

                                  Unit instantiation that reduces when the head is a literal unit abstraction, by performing the recorded substitution through pullU.

                                  Equations
                                  Instances For

                                    What a ratio means #

                                    @[reducible]

                                    The semantic ratio at scalar shape: a positive real. A definition of its own so that the space shapes can be compositional in the scalar meaning: change the scalar carrier and every shape follows.

                                    Positivity is carried by the type rather than by a side relation: a ratio's value is built from scale factors (positive) by multiplication, division and rational powers (positivity-preserving), and the rational-power former is sound only on positives, so the carrier says so. This is the semantic face of the unit group having no zero.

                                    Equations
                                    Instances For
                                      noncomputable def LambdaS.SemScalar.rpow (x : SemScalar) (q : ) :

                                      Rational powers on positive scalars, via Real.rpow.

                                      Equations
                                      Instances For
                                        @[simp]
                                        theorem LambdaS.SemScalar.val_rpow (x : SemScalar) (q : ) :
                                        (x.rpow q) = x ^ q
                                        @[simp]
                                        theorem LambdaS.SemScalar.val_div (x y : SemScalar) :
                                        ↑(x / y) = x / y
                                        @[reducible]

                                        The semantic ratio at each shape: a scale factor at a quantity, a map at a function, a scale factor per component at a space, a scale factor per entry at a linear map (entry (j, i) is row j, column i), a family at a unit binder.

                                        Equations
                                        Instances For
                                          @[reducible]

                                          Semantic ratios for a ratio context.

                                          Equations
                                          Instances For
                                            def LambdaS.TwEnv.lookup {Θ : List Shape} {s : Shape} (n : ) :
                                            Θ[n]? = some sTwEnv ΘSemTw s

                                            Looking a ratio variable up.

                                            Equations
                                            Instances For
                                              noncomputable def LambdaS.Tw.eval {B : Type} [Fintype B] {k : } :
                                              Scaling B k{Θ : List Shape} → {s : Shape} → Tw B k Θ sTwEnv ΘSemTw s

                                              The meaning of a ratio, under a declared scaling. uapp is where the recorded instantiation is finally performed: semantically, by reading the family at the instantiating unit's magnitude.

                                              Equations
                                              Instances For
                                                @[simp]
                                                theorem LambdaS.Tw.eval_castShape {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {s s' : Shape} (h : s = s') (t : Tw B k Θ s) (ρ : TwEnv Θ) :
                                                eval ψ (castShape h t) ρ = h eval ψ t ρ

                                                Evaluation commutes with retyping.

                                                theorem LambdaS.Tw.eval_castShape_vec {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {n n' : } (h : Shape.vec n = Shape.vec n') (t : Tw B k Θ (Shape.vec n)) (ρ : TwEnv Θ) (i : Fin n') :
                                                eval ψ (castShape h t) ρ i = eval ψ t ρ (Fin.cast i)

                                                Retyping along an equality of vector shapes reindexes the components and changes nothing else. The equality in play is List.length_map at a matrix row, where the row space is a map over the column space.

                                                Derived vector and matrix combinators #

                                                vecOfFn and matOfFn build literal drift vectors and matrices from component functions. projE and rowE are proj and row that reduce on literals, so that the syntactic comparison in the drift computation sees a literal's components rather than an opaque projection; on anything that is not a literal they fall back to the formers.

                                                def LambdaS.Tw.vecOfFn {B : Type} {k : } {Θ : List Shape} {n : } :
                                                (Fin nTw B k Θ Shape.scalar)Tw B k Θ (Shape.vec n)

                                                A literal drift vector from a component function.

                                                Equations
                                                Instances For
                                                  def LambdaS.Tw.matOfFn {B : Type} {k : } {Θ : List Shape} {n m : } :
                                                  (Fin mTw B k Θ (Shape.vec n))Tw B k Θ (Shape.mat n m)

                                                  A literal drift matrix from a row function.

                                                  Equations
                                                  Instances For
                                                    def LambdaS.Tw.projE {B : Type} {k : } {Θ : List Shape} {n : } :
                                                    Tw B k Θ (Shape.vec n)Fin nTw B k Θ Shape.scalar

                                                    Projection that reduces on vector literals.

                                                    Equations
                                                    Instances For
                                                      def LambdaS.Tw.rowE {B : Type} {k : } {Θ : List Shape} {n m : } :
                                                      Tw B k Θ (Shape.mat n m)Fin mTw B k Θ (Shape.vec n)

                                                      Row extraction that reduces on matrix literals.

                                                      Equations
                                                      Instances For

                                                        Normalization #

                                                        appE and uappE reduce the redex at hand, but substitution can create another: a lam-bound variable in head position, instantiated by an abstraction, becomes a redex the construction site never sees. The flat-form comparison treats any surviving app as an atom, so a residue of this kind costs an agreement check its completeness. Tw.norm reduces every redex, under binders included, before a ratio is compared. It runs on fuel, one unit per reduction at a root; the ratio calculus is simply typed, so a normal form exists, and the fuel is a bound the normalizer never exhausts on the ratios twistOf builds, which nest applications no deeper than the program does. Exhausting it leaves a redex in place, which the comparison then declines: fuel costs completeness, never soundness (Tw.eval_norm).

                                                        def LambdaS.Tw.size {B : Type} {k : } {Θ : List Shape} {s : Shape} :
                                                        Tw B k Θ s

                                                        Node count of a ratio, the fuel Tw.norm runs on.

                                                        Equations
                                                        Instances For
                                                          @[irreducible]
                                                          def LambdaS.Tw.normN {B : Type} (n : ) {k : } {Θ : List Shape} {s : Shape} :
                                                          Tw B k Θ sTw B k Θ s

                                                          Full β-normalization on fuel: reduces app of a literal lam and uapp of a literal ulam wherever they occur, projections and rows of literals included, and leaves everything else in place.

                                                          Equations
                                                          Instances For
                                                            def LambdaS.Tw.norm {B : Type} {k : } {Θ : List Shape} {s : Shape} (t : Tw B k Θ s) :
                                                            Tw B k Θ s

                                                            Normalization at the fuel a ratio's own size supplies.

                                                            Equations
                                                            Instances For
                                                              def LambdaS.Tw.one {B : Type} {k : } {Θ : List Shape} (s : Shape) :
                                                              Tw B k Θ s

                                                              The trivial ratio, as syntax, at every shape: the unit 1 at a scalar, 1 in every component at a space, the constant trivial family at an arrow and under a unit binder. This is the ratio the frees-at-one assignment gives every context variable of a program: an input is a measurement, and a measurement rescales ideally, so its ratio is 1. Atoms are reserved for lam-bound variables, whose future arguments may genuinely drift.

                                                              Equations
                                                              Instances For
                                                                @[simp]
                                                                theorem LambdaS.Tw.eval_vecOfFn {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {n : } (f : Fin nTw B k Θ Shape.scalar) (ρ : TwEnv Θ) (i : Fin n) :
                                                                eval ψ (vecOfFn f) ρ i = eval ψ (f i) ρ
                                                                @[simp]
                                                                theorem LambdaS.Tw.eval_matOfFn {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {n m : } (g : Fin mTw B k Θ (Shape.vec n)) (ρ : TwEnv Θ) (a : Fin m) :
                                                                eval ψ (matOfFn g) ρ a = eval ψ (g a) ρ
                                                                @[simp]
                                                                theorem LambdaS.Tw.eval_projE {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {n : } (t : Tw B k Θ (Shape.vec n)) (i : Fin n) (ρ : TwEnv Θ) :
                                                                eval ψ (t.projE i) ρ = eval ψ t ρ i
                                                                @[simp]
                                                                theorem LambdaS.Tw.eval_rowE {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {n m : } (t : Tw B k Θ (Shape.mat n m)) (j : Fin m) (ρ : TwEnv Θ) :
                                                                eval ψ (t.rowE j) ρ = eval ψ t ρ j

                                                                Renaming and substitution preserve evaluation #

                                                                theorem LambdaS.Tw.eval_rename {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ Θ' : List Shape} (f : ) (hf : ∀ (n : ) (s : Shape), Θ[n]? = some sΘ'[f n]? = some s) {s : Shape} (t : Tw B k Θ s) (ρ : TwEnv Θ) (ρ' : TwEnv Θ') :
                                                                (∀ (n : ) (sh : Shape) (h : Θ[n]? = some sh), TwEnv.lookup (f n) ρ' = TwEnv.lookup n h ρ)eval ψ (rename f hf t) ρ' = eval ψ t ρ

                                                                Renaming preserves evaluation, at environments that agree along the renaming.

                                                                theorem LambdaS.Tw.eval_weakenR {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {s₀ s : Shape} (t : Tw B k Θ s) (r : SemTw s₀) (ρ : TwEnv Θ) :
                                                                eval ψ t.weakenR (r, ρ) = eval ψ t ρ

                                                                Weakening by a fresh ratio variable is invisible to evaluation.

                                                                theorem LambdaS.Tw.eval_pullU {B : Type} [Fintype B] {k k' : } (ψ : Scaling B k') (η : Fin kUExp B k') {Θ : List Shape} {s : Shape} (t : Tw B k Θ s) (ρ : TwEnv Θ) :
                                                                eval ψ (pullU η t) ρ = eval (ψ.pull η) t ρ

                                                                The unit-scope pullback is the syntactic face of Scaling.pull.

                                                                theorem LambdaS.Tw.eval_uweaken {B : Type} [Fintype B] {k : } (ψ : Scaling B k) (r : ) {Θ : List Shape} {s : Shape} (t : Tw B k Θ s) (ρ : TwEnv Θ) :
                                                                eval (ψ.cons r) t.uweaken ρ = eval ψ t ρ

                                                                Weakening the unit scope is invisible to evaluation.

                                                                theorem LambdaS.Tw.eval_subst {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ Θ' : List Shape} (σ : (n : ) → (s : Shape) → Θ[n]? = some sTw B k Θ' s) {s : Shape} (t : Tw B k Θ s) (ρ : TwEnv Θ) (ρ' : TwEnv Θ') :
                                                                (∀ (n : ) (sh : Shape) (h : Θ[n]? = some sh), eval ψ (σ n sh h) ρ' = TwEnv.lookup n h ρ)eval ψ (subst σ t) ρ' = eval ψ t ρ

                                                                Substitution preserves evaluation, at environments where each substituend evaluates to the value it replaces.

                                                                theorem LambdaS.Tw.eval_subst0 {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {s₀ s : Shape} (t : Tw B k (s₀ :: Θ) s) (a : Tw B k Θ s₀) (ρ : TwEnv Θ) :
                                                                eval ψ (t.subst0 a) ρ = eval ψ t (eval ψ a ρ, ρ)

                                                                β: substituting for the most recent ratio variable evaluates the body at the substituend's value.

                                                                @[simp]
                                                                theorem LambdaS.Tw.eval_appE {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {s t : Shape} (f : Tw B k Θ (s.arrow t)) (a : Tw B k Θ s) (ρ : TwEnv Θ) :
                                                                eval ψ (f.appE a) ρ = eval ψ f ρ (eval ψ a ρ)

                                                                The reducing application evaluates as app does.

                                                                @[simp]
                                                                theorem LambdaS.Tw.eval_uappE {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {s : Shape} (t : Tw B k Θ s.bind) (μ : UExp B k) (ρ : TwEnv Θ) :
                                                                eval ψ (t.uappE μ) ρ = eval ψ t ρ (ψ.logScale μ)

                                                                The reducing unit instantiation evaluates as uapp does: performing the recorded substitution syntactically agrees with reading the family at the instantiating unit's magnitude, which is Scaling.pull_subst.

                                                                theorem LambdaS.Tw.eval_normN {B : Type} [Fintype B] {k : } (ψ : Scaling B k) (n : ) {Θ : List Shape} {s : Shape} (t : Tw B k Θ s) (ρ : TwEnv Θ) :
                                                                eval ψ (normN n t) ρ = eval ψ t ρ

                                                                Normalization preserves evaluation, at every fuel.

                                                                @[simp]
                                                                theorem LambdaS.Tw.eval_norm {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} {s : Shape} (t : Tw B k Θ s) (ρ : TwEnv Θ) :
                                                                eval ψ t.norm ρ = eval ψ t ρ

                                                                Normalization preserves evaluation.

                                                                The trivial semantic ratio at each shape: 1 at a quantity, 1 in every component at a space, and "maps trivial to trivial" at a function.

                                                                Equations
                                                                Instances For
                                                                  theorem LambdaS.Tw.eval_one {B : Type} [Fintype B] {k : } (ψ : Scaling B k) {Θ : List Shape} (s : Shape) (θρ : TwEnv Θ) :
                                                                  eval ψ (one s) θρ = oneSem s

                                                                  The trivial syntactic ratio evaluates to the trivial semantic one, in every scaling and every environment.

                                                                  The twisted logical relation #

                                                                  Rel says a term is scale-invariant. TwRel says it is invariant up to a ratio, and it separates the two things a rescaling can move. The valuation the conversion factors are drawn from is rescaled by φ; the values themselves are rescaled by ψ. A conversion pays once for each: its factor V(u)/V(v) moves with φ, and the converted value moves with ψ at its source unit where its type promises the target. So the relation carries two readings of the ratio, s under φ and s' under ψ, and at a quantity the rescaled value is ψ(u) · s · s' times the original. At φ = ψ the ratio appears squared, the law of the paper's opening example; at ψ = 0 (values fixed, valuation moved) it appears once and the type's factor not at all, which is what makes a drift-free program declaration-independent; at φ = 0 (valuation fixed, values moved) it appears once beside the type's factor, which is the scaling law the Pi theorem consumes. At ratio 1 all three are Rel.

                                                                  At a unit binder the ratio is a family indexed by the bound unit's scaling, one family per reading, while the denotation is a family indexed by its magnitude. Those are different things, which is why all three indices appear; the rescaled denotation is read at r + s, the magnitude moved by the valuation's extension.

                                                                  def LambdaS.TwRel {B D : Type} [Fintype B] {j k : } (τ : Ty B D j k) :
                                                                  SemTw τ.shapeSemTw τ.shapeScaling B kScaling B kτ.denτ.denProp

                                                                  The logical relation, twisted by a ratio, read once under the valuation rescaling φ and once under the value rescaling ψ.

                                                                  Equations
                                                                  Instances For
                                                                    def LambdaS.IsOneSem (s : Shape) :
                                                                    SemTw sProp

                                                                    Having a trivial ratio, at every shape: 1 at a quantity, and at a function "maps trivial to trivial". The arrow clause is what a convert-free function satisfies (λx. x·x sends ratio 1 to 1 even though it squares others), and it is a predicate rather than a value for exactly that reason.

                                                                    Equations
                                                                    Instances For

                                                                      The canonical trivial ratio is trivial.

                                                                      @[simp]
                                                                      theorem LambdaS.trel_Q_one {B D : Type} [Fintype B] {k : } {u : UExp B k} (φ ψ : Scaling B k) (x y : ) :
                                                                      TwRel (Ty.Q u) 1 1 φ ψ x y Rel (Ty.Q u) ψ x y

                                                                      At the trivial ratio and at scalar type, TwRel is Rel. So Kennedy's theorem is the s = 1 case of the twisted one rather than a separate result. The valuation rescaling φ is invisible at scalar type: only conversion reads the valuation, and a trivial ratio says the conversions canceled.

                                                                      Stated at scalar type, and that is not a limitation to apologize for: at arrow type TwRel quantifies over every argument ratio, so it is strictly stronger than Rel there rather than equivalent to it. The scalar case is where the characterization is used, and where the two genuinely coincide.

                                                                      Positivity of ratios lives in the carrier itself, SemScalar, where the rational-power former needs it, rather than in a separate logical relation over shapes. A scalar ratio's value is positive by type, which is what lets the characterization divide by it, and it is the semantic face of the group having no zero.

                                                                      Transporting the twisted relation #

                                                                      The same shape as rel_ground and relCo_ground, carrying the two ratio readings as well. The ratios' transport is along an equality of shapes, which is why it costs nothing: Ty.shape_ground says grounding leaves the shape alone.

                                                                      theorem LambdaS.twRel_ground {B D : Type} [Fintype B] {j k : } (τ : Ty B D j k) {j₀ k₀ : } (η : Fin kUExp B k₀) (δ : Fin jDExp D j₀) (φ ψ : Scaling B k₀) {w v : SemTw τ.shape} {w' v' : SemTw (Ty.ground η δ τ).shape} {x y : τ.den} {x' y' : (Ty.ground η δ τ).den} :
                                                                      w w'v v'x x'y y' → (TwRel (Ty.ground η δ τ) w' v' φ ψ x' y' TwRel τ w v (φ.pull η) (ψ.pull η) x y)

                                                                      TwRel transports along grounding.

                                                                      theorem LambdaS.twRel_subst {B D : Type} [Fintype B] {j k : } (τ : Ty B D j (k + 1)) (σ : UExp B k) (φ ψ : Scaling B k) {w v : SemTw τ.shape} {w' v' : SemTw (τ.subst σ).shape} {x y : τ.den} {x' y' : (τ.subst σ).den} (hw : w w') (hv : v v') (hx : x x') (hy : y y') :
                                                                      TwRel (τ.subst σ) w' v' φ ψ x' y' TwRel τ w v (φ.cons (φ.logScale σ)) (ψ.cons (ψ.logScale σ)) x y

                                                                      Instantiating a unit variable, for TwRel.

                                                                      theorem LambdaS.twRel_substDim {B D : Type} [Fintype B] {j k : } (τ : Ty B D (j + 1) k) (d : DExp D j) (φ ψ : Scaling B k) {w v : SemTw τ.shape} {w' v' : SemTw (τ.substDim d).shape} {x y : τ.den} {x' y' : (τ.substDim d).den} (hw : w w') (hv : v v') (hx : x x') (hy : y y') :
                                                                      TwRel (τ.substDim d) w' v' φ ψ x' y' TwRel τ w v φ ψ x y

                                                                      Instantiating a dimension variable, for TwRel.

                                                                      theorem LambdaS.twRel_weaken {B D : Type} [Fintype B] {j k : } (τ : Ty B D j k) (φ ψ : Scaling B k) (s s' : ) {w v : SemTw τ.shape} {w' v' : SemTw τ.weaken.shape} {x y : τ.den} {x' y' : τ.weaken.den} (hw : w w') (hv : v v') (hx : x x') (hy : y y') :
                                                                      TwRel τ.weaken w' v' (φ.cons s) (ψ.cons s') x' y' TwRel τ w v φ ψ x y

                                                                      Weakening under a unit binder, for TwRel.

                                                                      Every argument enters with trivial ratio: a TwEnv of ones.

                                                                      Equations
                                                                      Instances For
                                                                        theorem LambdaS.TwEnv.lookup_oneTwEnv {Θ : List Shape} {s : Shape} (n : ) (h : Θ[n]? = some s) :
                                                                        lookup n h (oneTwEnv Θ) = oneSem s

                                                                        Looking up the all-ones environment gives the trivial ratio.

                                                                        def LambdaS.TwEnv.OnesFrom (p : ) {Θ : List Shape} (θρ : TwEnv Θ) :

                                                                        The pinned region of a ratio environment. A ratio environment is trivial from position p on: positions below p are the genuine atoms, introduced by lam binders, and positions at p and beyond are the program's own context variables, whose ratio the frees-at-one assignment fixes at 1.

                                                                        Equations
                                                                        Instances For
                                                                          theorem LambdaS.TwEnv.OnesFrom.cons {p : } {Θ : List Shape} {θρ : TwEnv Θ} {s : Shape} (r : SemTw s) ( : OnesFrom p θρ) :
                                                                          OnesFrom (p + 1) (r, θρ)

                                                                          Extending the environment at a fresh atom moves the pinned region one position out: the lam case of the scaling law.

                                                                          The all-ones environment is trivial from every position on.

                                                                          The symbolic normalizer #

                                                                          A ratio's value under ψ at the trivial environment is ψ.scale of a single unit expression, and that expression is computable. This is what makes the triviality of a ratio decidable, which is the point of ratios being syntax.

                                                                          The normalizer is environment-passing in the unit scope: rather than moving values between scopes (which would force a Kripke model, since the function space at arrow shape cannot be weakened), every value lives at one global scope k₀, and a term's own unit variables are interpreted through υ. Crossing a ulam extends υ; nothing is ever weakened. bind is interpreted as a function from unit expressions, not from reals: the semantic family is read only at magnitudes of expressible units (uapp records a UExp), so agreement there is agreement everywhere it is consulted.

                                                                          @[reducible]
                                                                          def LambdaS.SynTw (B : Type) (k₀ : ) :

                                                                          The symbolic model, at a fixed global unit scope.

                                                                          Equations
                                                                          Instances For
                                                                            def LambdaS.SynTw.one {B : Type} {k₀ : } (s : Shape) :
                                                                            SynTw B k₀ s

                                                                            Trivial values, at every shape.

                                                                            Equations
                                                                            Instances For
                                                                              @[reducible]
                                                                              def LambdaS.SynEnv (B : Type) (k₀ : ) :

                                                                              Symbolic environments.

                                                                              Equations
                                                                              Instances For
                                                                                def LambdaS.SynEnv.lookup {B : Type} {k₀ : } {Θ : List Shape} {s : Shape} (n : ) :
                                                                                Θ[n]? = some sSynEnv B k₀ ΘSynTw B k₀ s

                                                                                Looking a symbolic value up.

                                                                                Equations
                                                                                Instances For
                                                                                  def LambdaS.SynEnv.ones {B : Type} {k₀ : } (Θ : List Shape) :
                                                                                  SynEnv B k₀ Θ

                                                                                  The all-ones symbolic environment.

                                                                                  Equations
                                                                                  Instances For
                                                                                    def LambdaS.Tw.nf {B : Type} {k₀ k : } (υ : Fin kUExp B k₀) {Θ : List Shape} {s : Shape} :
                                                                                    Tw B k Θ sSynEnv B k₀ ΘSynTw B k₀ s

                                                                                    The normalizer. Computes the symbolic value of a ratio.

                                                                                    Equations
                                                                                    Instances For

                                                                                      Correctness #

                                                                                      def LambdaS.SRel {B : Type} [Fintype B] {k₀ : } (ψ : Scaling B k₀) (s : Shape) :
                                                                                      SynTw B k₀ sSemTw sProp

                                                                                      The relation between symbolic and semantic values. At bind the two families need only agree at magnitudes of expressible units: those are the only points uapp ever reads.

                                                                                      Equations
                                                                                      Instances For
                                                                                        def LambdaS.SRelEnv {B : Type} [Fintype B] {k₀ : } (ψ : Scaling B k₀) (Θ : List Shape) :
                                                                                        SynEnv B k₀ ΘTwEnv ΘProp

                                                                                        Environments related pointwise.

                                                                                        Equations
                                                                                        Instances For
                                                                                          theorem LambdaS.SRelEnv.lookup {B : Type} [Fintype B] {k₀ : } {ψ : Scaling B k₀} {Θ : List Shape} {s : Shape} (n : ) (h : Θ[n]? = some s) { : SynEnv B k₀ Θ} {θρ : TwEnv Θ} :
                                                                                          SRelEnv ψ Θ θρSRel ψ s (SynEnv.lookup n h ) (TwEnv.lookup n h θρ)
                                                                                          theorem LambdaS.srel_one {B : Type} [Fintype B] {k₀ : } (ψ : Scaling B k₀) (s : Shape) :
                                                                                          SRel ψ s (SynTw.one s) (oneSem s)

                                                                                          The trivial symbolic value relates to the trivial semantic one.

                                                                                          theorem LambdaS.srelEnv_ones {B : Type} [Fintype B] {k₀ : } (ψ : Scaling B k₀) (Θ : List Shape) :
                                                                                          SRelEnv ψ Θ (SynEnv.ones Θ) (oneTwEnv Θ)

                                                                                          The all-ones environments are related.

                                                                                          theorem LambdaS.Tw.nf_correct {B : Type} [Fintype B] {k₀ : } (ψ : Scaling B k₀) {k : } (υ : Fin kUExp B k₀) {Θ : List Shape} {s : Shape} (t : Tw B k Θ s) ( : SynEnv B k₀ Θ) (θρ : TwEnv Θ) :
                                                                                          SRelEnv ψ Θ θρSRel ψ s (nf υ t ) (eval (ψ.pull υ) t θρ)

                                                                                          The normalizer is correct. Its output, under SRel, matches the ratio's value (the ratio's unit scope read through υ, its scaling therefore the pullback). The ulam case is pull_cons and the uapp case is logScale_pull: the environment-passing design paying off, with no weakening, no Kripke structure, and no transport.