10.1. Quantities and units (VIM4 2CD, Dybkær §13.3.3)
-
PropertyKindCalculus.Carrier[complete]
A numeric carrier Carrier R is the minimal arithmetic a kind-indexed
magnitude needs, supplied once per representation type R (a zero and an
addition; a LawfulCarrier adds the additive-monoid laws). In plain engineering
terms it is the number type plug: everything above it — kind discrimination,
scale gating, the dimension functor, the interaction algebra, extensivity — is
written against this class and so reused verbatim at every R. This is the role
TorchLean's Context α typeclass plays for tensor element types; the kind index
is the layer above the carrier that TorchLean does not have.
Lean code for Definition10.1.1●1 definition
Associated Lean declarations
-
PropertyKindCalculus.Carrier[complete]
-
PropertyKindCalculus.Carrier[complete]
-
classdefined in PropertyKindCalculus/Quantity.leancomplete
class PropertyKindCalculus.Carrier (R : Type) : Type
class PropertyKindCalculus.Carrier (R : Type) : Type
**The numeric carrier of a quantity (R10).** The minimal *additive* structure a kind-indexed magnitude needs in order to *aggregate*: a zero and an addition, supplied once per representation type `R`. This is the role TorchLean's `Context α` plays for tensor element types — the kind, scale, dimension, interaction, and extensivity layers are all written *against* this class and reused verbatim at every `R`. **Why a bespoke `zero`/`add` rather than extending Lean's `Zero`/`Add`?** Three reasons, all deliberate: * **It is the home of additivity (extensivity §13.5, R10), nothing more.** `Carrier` carries *exactly* the operation whose laws the extensivity capstone is about. It is intentionally *not* a field/ring: multiplication and division change the *kind* (length × length = area), so they are cross-kind operations gated by `ProductKind`/`QuotientKind` witnesses, not carrier methods (see `QuantityClassification`); subtraction and the transcendentals ride Lean's own `Sub`/`MathCarrier` at their use sites. Which operations are even *meaningful* is a property of a kind's *scale* (`Scale.lean`: `AllowsOrder`/`AllowsDifference`/ `AllowsRatio`), not of the carrier — so the carrier stays minimal and the licensing lives on the kind. * **It keeps the core Mathlib-free and self-contained.** Because `add`/`zero` are bespoke methods, derived carriers — `Carrier (ι → R)` (`QuantityVector`) and `Carrier (Complex R)` (`Complex`) — are built *directly* from `R`'s `Carrier`, with no need for Mathlib's `Pi`/`Complex` algebra instances and with no risk of *instance diamonds* against them in the Mathlib-backed `dimension` layer. * **It draws the R10 line sharply** (see `LawfulCarrier`). For ergonomic *computation*, the same-kind operator `+` is also available over Lean's `Add` (see the "Two additions" note below); on any carrier that is both a `Carrier` and an `Add`, the two coincide.Methods
zero : R
The additive unit (a zero magnitude).
add : R → R → R
Addition of magnitudes — the operation extensive aggregation (§13.5) is built from.
Realized as the Carrier / LawfulCarrier classes. Carrier R bundles zero
and add; LawfulCarrier R extends it with associativity, commutativity, and the
unit laws. Int and (in the Dimension library) ℝ are lawful carriers; Float
is a Carrier but deliberately not lawful (floating-point addition is not
associative).
-
PropertyKindCalculus.Quantity[complete]
A quantity Quantity k R is a magnitude of a fixed kind k, carried at a
representation type R (R10). It is indexed by k, a
kind-of-property, so the type system forbids forming
or comparing a Quantity k₁ R with a Quantity k₂ R when k_1 \neq k_2 — even
if both kinds are dimension one. This indexing is the fix for the dimension-1
conflation. The second index R is the numeric carrier: the same value type is
instantiated at \mathbb{R} and Int to prove, at Float to run today, and (the
planned float carriers) at FP32 to bound rounding and at IEEE32Exec to run with
NaN — the kind machinery above it written once for all of them.
Lean code for Definition10.1.2●1 definition
Associated Lean declarations
-
PropertyKindCalculus.Quantity[complete]
-
PropertyKindCalculus.Quantity[complete]
-
structuredefined in PropertyKindCalculus/Quantity.leancomplete
structure PropertyKindCalculus.Quantity (k : PropertyKindCalculus.KindOfProperty) (R : Type) : Type
structure PropertyKindCalculus.Quantity (k : PropertyKindCalculus.KindOfProperty) (R : Type) : Type
**A quantity (R10).** A magnitude of a fixed kind `k`, carried at a representation type `R`. Indexed by `k`, so the type system forbids forming or comparing a `Quantity k₁ R` with a `Quantity k₂ R` when `k₁ ≠ k₂`; indexed by `R`, so the same value type is instantiated at whichever numbers the task needs. This indexing *is* the fix for the dimension-1 conflation.
Fields
magnitude : R
§13.3.3 — the magnitude (the *number* of the reference-times-number form), carried at the representation type `R`.
Realized as structure Quantity (k : KindOfProperty) (R : Type) carrying a
magnitude in R, with same-kind addition Quantity.add : Quantity k R → Quantity
k R → Quantity k R (R4: the type forces both summands to share the kind). The
algebraic operations come from the carrier typeclass on
R; which operators are even admissible is the orthogonal scale gate (the
proved operator stratification, operator
monotonicity).
Representation-parametric additivity (R10). The additivity laws on quantities —
commutativity, associativity, and the zero unit —
q_1 + q_2 = q_2 + q_1, \quad (q_1+q_2)+q_3 = q_1+(q_2+q_3), \quad 0 + q = q
hold over every lawful carrier, established by a single proof and so available
at each R at once: at \mathbb{R} (the proof carrier) and at Int with no
R-specific argument. The very carrier where these laws are absent — an
executable Float, a carrier but not a lawful one — is what
the exec/spec refinement bridge below exists to reconcile. Builds on
the quantity layer.
Lean code for Theorem10.1.3●1 theorem
Associated Lean declarations
-
theoremdefined in PropertyKindCalculus/Quantity.leancomplete
theorem PropertyKindCalculus.Quantity.laws_parametric {k : PropertyKindCalculus.KindOfProperty} {R : Type} [PropertyKindCalculus.LawfulCarrier R] (h : PropertyKindCalculus.DifferenceKind k) (x y z : PropertyKindCalculus.Quantity k R) : PropertyKindCalculus.Quantity.add h x y = PropertyKindCalculus.Quantity.add h y x ∧ PropertyKindCalculus.Quantity.add h (PropertyKindCalculus.Quantity.add h x y) z = PropertyKindCalculus.Quantity.add h x (PropertyKindCalculus.Quantity.add h y z) ∧ PropertyKindCalculus.Quantity.add h PropertyKindCalculus.Quantity.zero x = x ∧ PropertyKindCalculus.Quantity.add h x PropertyKindCalculus.Quantity.zero = x
theorem PropertyKindCalculus.Quantity.laws_parametric {k : PropertyKindCalculus.KindOfProperty} {R : Type} [PropertyKindCalculus.LawfulCarrier R] (h : PropertyKindCalculus.DifferenceKind k) (x y z : PropertyKindCalculus.Quantity k R) : PropertyKindCalculus.Quantity.add h x y = PropertyKindCalculus.Quantity.add h y x ∧ PropertyKindCalculus.Quantity.add h (PropertyKindCalculus.Quantity.add h x y) z = PropertyKindCalculus.Quantity.add h x (PropertyKindCalculus.Quantity.add h y z) ∧ PropertyKindCalculus.Quantity.add h PropertyKindCalculus.Quantity.zero x = x ∧ PropertyKindCalculus.Quantity.add h x PropertyKindCalculus.Quantity.zero = x
**Representation-parametric additivity (R10).** The additivity laws hold over *any* lawful carrier, established by a single proof and so available at every `R` at once (`ℝ` for proofs, `Int`, …). The very `R` where these laws are absent — an executable float, a `Carrier` but not a `LawfulCarrier` — is what the planned exec/spec refinement bridge exists to reconcile.
Proved in PropertyKindCalculus.Quantity (axiom-free). Each law unfolds
Quantity.add to its carrier operation and rewrites by the corresponding
LawfulCarrier field; laws_parametric bundles the four. Specializing to Int
(core) and ℝ (in the Dimension library) reuses the same proof verbatim, which
is the R10 payoff.
-
PropertyKindCalculus.CarrierRefinement[complete]
A carrier refinement CarrierRefinement E S specifies how an exec carrier
E (fast, lossy) stands in for a spec carrier S (exact): a forgetful map
toSpec : E → S (the analogue of TorchLean's toReal) and a spec-side
round : S → S, with the single law that forgetting an exec addition equals
rounding the spec addition,
\mathrm{toSpec}(x +_E y) = \mathrm{round}\,(\mathrm{toSpec}\,x +_S \mathrm{toSpec}\,y).
In plain engineering terms it is the rounding contract between a slow exact
number type and the fast machine number that stands in for it. Builds on the
carrier.
Lean code for Definition10.1.4●1 definition
Associated Lean declarations
-
PropertyKindCalculus.CarrierRefinement[complete]
-
PropertyKindCalculus.CarrierRefinement[complete]
-
classdefined in PropertyKindCalculus/QuantityRefinement.leancomplete
class PropertyKindCalculus.CarrierRefinement (E S : Type) [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] : Type
class PropertyKindCalculus.CarrierRefinement (E S : Type) [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] : Type
**A carrier refinement (R10).** A specification of how an *exec* carrier `E` (fast, lossy — e.g. an IEEE-754 float) stands in for a *spec* carrier `S` (exact — e.g. `ℝ`): a forgetful map `toSpec : E → S` and a spec-side `round : S → S`, such that forgetting an exec addition equals rounding the spec addition. This is the abstract form of TorchLean's `BridgeFP32` pattern ("compute in `ℝ`, then round"). `toSpec` plays the role of TorchLean's `toReal`.Methods
toSpec : E → S
Forget an exec magnitude to its spec magnitude (TorchLean's `toReal`).
round : S → S
Snap a spec magnitude to the representable grid (rounding).
toSpec_zero : PropertyKindCalculus.CarrierRefinement.toSpec PropertyKindCalculus.Carrier.zero = PropertyKindCalculus.Carrier.zero
The exec zero forgets to the spec zero (zero is represented exactly).
toSpec_add : ∀ (x y : E), PropertyKindCalculus.CarrierRefinement.toSpec (PropertyKindCalculus.Carrier.add x y) = PropertyKindCalculus.CarrierRefinement.round E (PropertyKindCalculus.Carrier.add (PropertyKindCalculus.CarrierRefinement.toSpec x) (PropertyKindCalculus.CarrierRefinement.toSpec y))
**The bridge law.** Forgetting an exec addition equals rounding the spec addition of the forgotten summands.
Realized as the CarrierRefinement class (core, axiom-free). TorchLean's FP32
gives an unconditional instance over \mathbb{R}, and IEEE32Exec refines
\mathbb{R} on the finite path — both in the separately built Torch library.
Exec refines spec across representations (R10). For a kind-k quantity, the
exec sum viewed in the spec carrier is the rounding of the spec sum,
\mathrm{toSpec}(x +_E y) = \mathrm{round}\,(\mathrm{toSpec}\,x +_S \mathrm{toSpec}\,y),
established over any carrier refinement and so
holding at each at once. A law proved over the lawful spec carrier therefore
transfers to the executable run with one rounding step — the bridge that carries
the representation-parametric laws from the
lawful ℝ onto a float that is not lawful, so one kind-indexed value serves both
proof and execution.
Lean code for Theorem10.1.5●1 theorem
Associated Lean declarations
-
theoremdefined in PropertyKindCalculus/QuantityRefinement.leancomplete
theorem PropertyKindCalculus.Quantity.add_refines {k : PropertyKindCalculus.KindOfProperty} {E S : Type} [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [PropertyKindCalculus.CarrierRefinement E S] (h : PropertyKindCalculus.DifferenceKind k) (x y : PropertyKindCalculus.Quantity k E) : (PropertyKindCalculus.Quantity.add h x y).toSpec = PropertyKindCalculus.Quantity.roundBy (PropertyKindCalculus.CarrierRefinement.round E) (PropertyKindCalculus.Quantity.add h x.toSpec y.toSpec)
theorem PropertyKindCalculus.Quantity.add_refines {k : PropertyKindCalculus.KindOfProperty} {E S : Type} [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [PropertyKindCalculus.CarrierRefinement E S] (h : PropertyKindCalculus.DifferenceKind k) (x y : PropertyKindCalculus.Quantity k E) : (PropertyKindCalculus.Quantity.add h x y).toSpec = PropertyKindCalculus.Quantity.roundBy (PropertyKindCalculus.CarrierRefinement.round E) (PropertyKindCalculus.Quantity.add h x.toSpec y.toSpec)
**Exec refines spec across representations (R10 capstone).** For a kind-`k` quantity, the executable sum *viewed in the spec carrier* equals the rounding of the spec sum: $$ \mathrm{toSpec}(x +_E y) = \mathrm{round}\,(\mathrm{toSpec}\,x +_S \mathrm{toSpec}\,y). $$ This is `CarrierRefinement.toSpec_add` lifted along the kind index, so a law proved over the lawful spec carrier transfers to the executable run with one rounding step. The kind `k` is preserved throughout — the bridge never crosses kinds.
Proved as Quantity.add_refines (core, axiom-free): the CarrierRefinement bridge
law lifted along the kind index. It is instantiated concretely in the separately
built Torch library at TorchLean's binary32 — an unconditional
CarrierRefinement FP32 ℝ (the rounding spec has no overflow, so the law holds by
computation) and a conditional IEEE32Exec refinement on the finite/no-overflow
path (Quantity.add_refines_exec), where overflow is an explicit hypothesis rather
than a silent failure. This is TorchLean's Bridge/FP32 pattern ("compute in
\mathbb{R}, then round").
-
PropertyKindCalculus.MulRefinement[complete]
The bridge's multiplicative law. MulRefinement E S says that the same
forgetful map and rounding a carrier refinement
supplies for + also relate the exec product to the spec product,
\mathrm{toSpec}(x \cdot_E y) = \mathrm{round}\,(\mathrm{toSpec}\,x \cdot_S \mathrm{toSpec}\,y).
Held apart from the refinement rather than bundled into it, for two reasons. A
carrier can refine additively without having a \times at all — the carrier class
supplies only zero and addition — and an expression that uses +, \times and
\div at once would, under bundling, put two independent paths to toSpec and
round in scope simultaneously.
The line the split follows is data against proof, and it is what keeps the two extra
classes from re-creating the problem they avoid. A carrier refinement carries
functions, and two of them are two different functions, so it must reach a use site
by exactly one path. These two carry only equations, and a class in \mathrm{Prop} is
a subsingleton — any two of its instances are the same instance — so they may be
inherited, re-derived and diamonded freely without a term ever depending on which one
arrived.
Lean code for Definition10.1.6●1 definition
Associated Lean declarations
-
PropertyKindCalculus.MulRefinement[complete]
-
PropertyKindCalculus.MulRefinement[complete]
-
classdefined in PropertyKindCalculus/QuantityRefinement.leancomplete
class PropertyKindCalculus.MulRefinement (E S : Type) [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [Mul E] [Mul S] [PropertyKindCalculus.CarrierRefinement E S] : Prop
class PropertyKindCalculus.MulRefinement (E S : Type) [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [Mul E] [Mul S] [PropertyKindCalculus.CarrierRefinement E S] : Prop
**The bridge law for multiplication.** The same forgetful map and rounding that `CarrierRefinement` supplies for `+` also relate the exec product to the spec product: $$ \mathrm{toSpec}(x \cdot_E y) = \mathrm{round}\,(\mathrm{toSpec}\,x \cdot_S \mathrm{toSpec}\,y). $$ Held apart from `CarrierRefinement` rather than bundled into it, because `Carrier` supplies only zero and addition — a carrier can refine additively without having a `*` at all (and `Quantity.mul` likewise asks for `[Mul R] [ScalarCarrier R]` separately).Methods
toSpec_mul : ∀ (x y : E), PropertyKindCalculus.CarrierRefinement.toSpec (x * y) = PropertyKindCalculus.CarrierRefinement.round E (PropertyKindCalculus.CarrierRefinement.toSpec x * PropertyKindCalculus.CarrierRefinement.toSpec y)
Forgetting an exec product equals rounding the spec product of the forgotten factors.
Realized as the MulRefinement class (core, axiom-free), a Prop class
parametrized by a CarrierRefinement rather than extending it, so one carrier has
one forgetful map and one rounding. Instantiated at TorchLean's FP32 in the
separately built Torch library, where NF multiplication is ofReal (a·b) and
the law is therefore rfl.
-
PropertyKindCalculus.DivRefinement[complete]
The bridge's division law, in the same shape as
the multiplicative one — and unconditional, which is a
statement about specification carriers and not about machines. Both sides read the
spec carrier's total convention for x / 0, so at a zero divisor there is nothing
to exclude. A real executable format does not totalize division; it produces an
infinity or a NaN, and no rounding of a real quotient is either. So the hazard sits
one rung down, as an explicit hypothesis on the executable carrier's own theorem.
Lean code for Definition10.1.7●1 definition
Associated Lean declarations
-
PropertyKindCalculus.DivRefinement[complete]
-
PropertyKindCalculus.DivRefinement[complete]
-
classdefined in PropertyKindCalculus/QuantityRefinement.leancomplete
class PropertyKindCalculus.DivRefinement (E S : Type) [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [Div E] [Div S] [PropertyKindCalculus.CarrierRefinement E S] : Prop
class PropertyKindCalculus.DivRefinement (E S : Type) [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [Div E] [Div S] [PropertyKindCalculus.CarrierRefinement E S] : Prop
**The bridge law for division.** As for multiplication, with the caveat the module docstring records: this is unconditional only because the exec and spec carriers agree on what `x / 0` means, which a *specification* format can arrange and a machine format cannot. An executable carrier whose division produces an infinity or a NaN has no instance of this class; its refinement is a theorem with the denominator's nonzeroness as a hypothesis.
Methods
toSpec_div : ∀ (x y : E), PropertyKindCalculus.CarrierRefinement.toSpec (x / y) = PropertyKindCalculus.CarrierRefinement.round E (PropertyKindCalculus.CarrierRefinement.toSpec x / PropertyKindCalculus.CarrierRefinement.toSpec y)
Forgetting an exec quotient equals rounding the spec quotient of the forgotten operands.
Realized as the DivRefinement class (core, axiom-free), with the unconditional
DivRefinement FP32 ℝ instance in the Torch library. The executable rung's
Quantity.div_refines_exec asks that the executable quotient be finite, and the
Torch-tier probes discharge that on concrete binary32 values and then refute it at a
zero denominator, where the divisor's decoded mantissa is shown to be zero.
Exec refines spec across a licensed kind product (R10). For a
product law k_1 \times k_2 = k, the exec product viewed
in the spec carrier is the rounding of the spec product.
The additive bridge preserves one kind
throughout; this one does not, and that is its content. The kinds move, but they
move under the same product law on both sides, so the rounding obligation and the
kind license are independent and compose: a rounding step cannot launder a product
the kind calculus refuses, and a licensed product does not lose its license by being
computed in floats.
Lean code for Theorem10.1.8●1 theorem
Associated Lean declarations
-
theoremdefined in PropertyKindCalculus/QuantityRefinement.leancomplete
theorem PropertyKindCalculus.Quantity.mul_refines {E S : Type} [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [Mul E] [Mul S] [PropertyKindCalculus.ScalarCarrier E] [PropertyKindCalculus.ScalarCarrier S] [PropertyKindCalculus.CarrierRefinement E S] [PropertyKindCalculus.MulRefinement E S] {k₁ k₂ k : PropertyKindCalculus.KindOfProperty} (h : PropertyKindCalculus.ProductKind k₁ k₂ k) (x : PropertyKindCalculus.Quantity k₁ E) (y : PropertyKindCalculus.Quantity k₂ E) : (PropertyKindCalculus.Quantity.mul h x y).toSpec = PropertyKindCalculus.Quantity.roundBy (PropertyKindCalculus.CarrierRefinement.round E) (PropertyKindCalculus.Quantity.mul h x.toSpec y.toSpec)
theorem PropertyKindCalculus.Quantity.mul_refines {E S : Type} [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [Mul E] [Mul S] [PropertyKindCalculus.ScalarCarrier E] [PropertyKindCalculus.ScalarCarrier S] [PropertyKindCalculus.CarrierRefinement E S] [PropertyKindCalculus.MulRefinement E S] {k₁ k₂ k : PropertyKindCalculus.KindOfProperty} (h : PropertyKindCalculus.ProductKind k₁ k₂ k) (x : PropertyKindCalculus.Quantity k₁ E) (y : PropertyKindCalculus.Quantity k₂ E) : (PropertyKindCalculus.Quantity.mul h x y).toSpec = PropertyKindCalculus.Quantity.roundBy (PropertyKindCalculus.CarrierRefinement.round E) (PropertyKindCalculus.Quantity.mul h x.toSpec y.toSpec)
**Exec refines spec across a kind product (R10).** The kind-crossing companion of `add_refines`: for a licensed product `ProductKind k₁ k₂ k`, the executable product viewed in the spec carrier is the rounding of the spec product. `add_refines` preserves one kind throughout; this one does not, and that is the point. The kinds move — `k₁`, `k₂` to `k` — but they move *under the product law*, the same law on both sides of the bridge, so the refinement and the kind license are independent obligations that compose. A rounding step cannot launder a product the kind calculus refuses, and a licensed product does not lose its license by being computed in floats.
Proved as Quantity.mul_refines (core, depending on no axioms at all): the
MulRefinement law lifted along the kind product. Specialized at binary32 as
Quantity.mul_refines_fp32, and conditionally at the executable carrier as
Quantity.mul_refines_exec under decoding and finiteness hypotheses.
And across a licensed kind quotient (R10) — the rung a ratio, a conversion factor,
or a weighted carving's denominator rides. An additive
bridge carries the extensive mode and nothing else; the mean
of a constant, the parallel-axis correction, and every sensitivity coefficient are
+/\times/\div expressions, and none of them can cross on an additive
contract alone.
Lean code for Theorem10.1.9●1 theorem
Associated Lean declarations
-
theoremdefined in PropertyKindCalculus/QuantityRefinement.leancomplete
theorem PropertyKindCalculus.Quantity.div_refines {E S : Type} [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [Div E] [Div S] [PropertyKindCalculus.ScalarCarrier E] [PropertyKindCalculus.ScalarCarrier S] [PropertyKindCalculus.CarrierRefinement E S] [PropertyKindCalculus.DivRefinement E S] {k₁ k₂ k : PropertyKindCalculus.KindOfProperty} (h : PropertyKindCalculus.QuotientKind k₁ k₂ k) (x : PropertyKindCalculus.Quantity k₁ E) (y : PropertyKindCalculus.Quantity k₂ E) : (PropertyKindCalculus.Quantity.div h x y).toSpec = PropertyKindCalculus.Quantity.roundBy (PropertyKindCalculus.CarrierRefinement.round E) (PropertyKindCalculus.Quantity.div h x.toSpec y.toSpec)
theorem PropertyKindCalculus.Quantity.div_refines {E S : Type} [PropertyKindCalculus.Carrier E] [PropertyKindCalculus.Carrier S] [Div E] [Div S] [PropertyKindCalculus.ScalarCarrier E] [PropertyKindCalculus.ScalarCarrier S] [PropertyKindCalculus.CarrierRefinement E S] [PropertyKindCalculus.DivRefinement E S] {k₁ k₂ k : PropertyKindCalculus.KindOfProperty} (h : PropertyKindCalculus.QuotientKind k₁ k₂ k) (x : PropertyKindCalculus.Quantity k₁ E) (y : PropertyKindCalculus.Quantity k₂ E) : (PropertyKindCalculus.Quantity.div h x y).toSpec = PropertyKindCalculus.Quantity.roundBy (PropertyKindCalculus.CarrierRefinement.round E) (PropertyKindCalculus.Quantity.div h x.toSpec y.toSpec)
**Exec refines spec across a kind quotient (R10).** `mul_refines` for `QuotientKind` — the rung a ratio, a conversion factor, or the denominator of a weighted mean rides.
Proved as Quantity.div_refines (core, depending on no axioms at all), with
Quantity.div_refines_fp32 at the binary32 rounding spec and
Quantity.div_refines_exec at the executable carrier. Both are exercised over a
genuinely lossy toy carrier in the core probes — where 3 \times 3 reads 9 exactly
but forgets to 8 — so neither capstone is satisfied vacuously by an identity
rounding.
-
PropertyKindCalculus.instLawfulCarrierPi[complete]
Vector quantities: numerical array × one scalar unit (R11, ISO 80000-2 §18). A
vector (or tensor) quantity is a numerical array carried at one kind with one
scalar unit — not a per-coordinate collection of
number × unit values; "all units are scalars". This is the
carrier taken at a function-space type: Fin n → R is a
(lawful) carrier whenever R is, pointwise, so a vector quantity is
Quantity k (Fin n → R) and the
additivity laws transfer to it by the same
parametric proof. The quantity is coordinate-independent; only its numerical
components depend on the frame.
Lean code for Definition10.1.10●1 definition
Associated Lean declarations
-
PropertyKindCalculus.instLawfulCarrierPi[complete]
-
PropertyKindCalculus.instLawfulCarrierPi[complete]
-
defdefined in PropertyKindCalculus/QuantityVector.leancomplete
def PropertyKindCalculus.instLawfulCarrierPi {ι R : Type} [PropertyKindCalculus.LawfulCarrier R] : PropertyKindCalculus.LawfulCarrier (ι → R)
def PropertyKindCalculus.instLawfulCarrierPi {ι R : Type} [PropertyKindCalculus.LawfulCarrier R] : PropertyKindCalculus.LawfulCarrier (ι → R)
The pointwise carrier is **lawful** whenever `R` is — the additive-monoid laws hold coordinatewise (`funext` + the laws on `R`). Hence the quantity additivity laws transfer to vector (and, with nested function spaces, tensor) carriers by the same parametric proof, with no per-carrier argument.
Realized as the pointwise Carrier (ι → R) / LawfulCarrier (ι → R) instances
(core). The fuller structural apparatus — coordinate frames, tensor variance,
transforms — remains a separate, owed axis.
-
PropertyKindCalculus.RealUnit[complete]
A unit RealUnit k is a distinguished quantity of kind k
chosen as the reference: measuring expresses any quantity of kind k as
\text{number} \times \text{unit}. Because it is indexed by the same k,
"a metre" and "a unit of gravimetric water content" inhabit different types. This
is the real-valued refinement of the proved metrological unit: it replaces the symbolic numeral-and-reference form with a magnitude in
\mathbb{R}, so that conversion ratios become arithmetic.
Lean code for Definition10.1.11●1 definition
Associated Lean declarations
-
PropertyKindCalculus.RealUnit[complete]
-
PropertyKindCalculus.RealUnit[complete]
-
structuredefined in PropertyKindCalculus/UnitReal.leancomplete
structure PropertyKindCalculus.RealUnit (k : PropertyKindCalculus.KindOfProperty) : Type
structure PropertyKindCalculus.RealUnit (k : PropertyKindCalculus.KindOfProperty) : Type
**§18.12 — a unit as a chosen reference quantity, carrying its magnitude.** One quantity of the kind `k`, distinguished as the reference "with which any other quantity of the same kind can be compared to express the ratio of the two quantities as a number" (VIM4 2CD 1.12). `ref_ne_zero` is the condition that phrase presupposes and the symbolic layer never has to state: a reference of magnitude zero expresses no ratio. Carried as a field, so a degenerate unit is not a term of this type — the same discipline `WeightedCarving` applies to a mean's denominator.
Fields
ref : PropertyKindCalculus.Quantity k ℝ
The quantity of kind `k` chosen as the reference.
ref_ne_zero : self.ref.magnitude ≠ 0
**The license**: the reference has a nonzero magnitude, so ratios against it exist.
Realized as RealUnit k, a Quantity k ℝ chosen as the reference together with the one
condition the choice must satisfy: ref_ne_zero. That field is what the phrase "express the
ratio of the two quantities as a number" presupposes and the symbolic layer never has to
state — a reference of magnitude zero expresses no ratio — and carrying it makes a degenerate
unit not a term of the type. Measuring is measure : Quantity k ℝ → RealUnit k → ℝ, division
by the reference; ofNumber is the multiplication back; and the §13.3.3 number-and-reference
round-trip is then a bijection in both directions (measure_ofNumber, ofNumber_measure)
rather than a definitional unfolding. ratio is the §1.22 conversion factor for an arbitrary
chosen reference, nonzero from the two licenses and reciprocal in the two directions, of which
the power-of-radix factor is the special case. The
refinement inherits the §9.13.4 exclusions rather than widening them: WellFormed is the
symbolic layer's BearsUnit, so a nominal or ordinal kind bears no real-valued unit either.
Unit conversion is a faithful round-trip. For two commensurable units u_1, u_2
of the same kind k, converting a magnitude from u_1 to u_2 and back is the
identity:
\mathrm{convert}_{u_2 \to u_1}\bigl(\mathrm{convert}_{u_1 \to u_2}(x)\bigr) = x.
This is proved for the realized case: the SI-prefixed (decimal)
and binary-prefixed (IEC 80000-13) units, where the §1.22
conversion factor is a power of the radix — ten for SI, two for binary. That factor is
kept as its integer exponent, so the two directions are reciprocal on the nose
(+5 then -5 for \mathrm{km}\leftrightarrow\mathrm{cm}; +10 then -10 for
\mathrm{MiB}\leftrightarrow\mathrm{KiB}) — exact over \mathbb{Z}
(convertExp_roundtrip) and, numerically, over \mathbb{R} via a power-of-radix
factor that is structurally nonzero (convertReal_roundtrip). The exponent
bookkeeping is blind to the radix, so one proof serves both prefix families, gated
to a common radix; conversion across radices (a power of ten is never a power of two)
and across kinds is simply undefined — a type-level fact, not a runtime check. The
fully general conversion by an arbitrary chosen-reference ratio, over the
real-valued unit, remains the deeper refinement below.
Lean code for Theorem10.1.12●1 theorem
Associated Lean declarations
-
theoremdefined in PropertyKindCalculus/UnitPrefix.leancomplete
theorem PropertyKindCalculus.PrefixedUnit.convertExp_roundtrip (p q : PropertyKindCalculus.PrefixedUnit) (decExp : ℤ) : q.convertExp p (p.convertExp q decExp) = decExp
theorem PropertyKindCalculus.PrefixedUnit.convertExp_roundtrip (p q : PropertyKindCalculus.PrefixedUnit) (decExp : ℤ) : q.convertExp p (p.convertExp q decExp) = decExp
**§1.22 — unit conversion is a faithful round-trip.** Converting a magnitude from `p`-units to `q`-units and back to `p`-units recovers it *exactly*: no information is lost, because the power-of-radix exponent is an `Int` — an element of an additive group — and the two conversion factors are reciprocal (`shift_add_symm`). A truncating numeric ratio (over `Int`, or a rounded `Float`) could not close this on the nose; keeping the §1.22 factor as its integer *exponent* is exactly what makes the round-trip exact. Holds for SI decimal and IEC 80000-13 binary prefixes alike — one proof, since the exponent bookkeeping is blind to the radix.
Because the conversion factor is a power of ten, its exponent is an Int — an
element of an additive group — so the shift u_1\to u_2 (shift, the difference of
the prefix exponents) and the shift back sum to zero (shift_add_symm). The
round-trip on the decimal exponent is then x + (e_1 - e_2) + (e_2 - e_1) = x,
closed by omega with no rounding. The numeric \mathbb{R} companion multiplies by
10^{e_1-e_2} then 10^{e_2-e_1}; zpow_add₀ on 10\neq 0 collapses the
exponents to 10^0 = 1. Neither needs a chosen-reference nonzeroness hypothesis;
the general real-valued case is where one is needed, and it carries
ref_ne_zero as a field so that ratio_ne_zero follows from the two licenses and from
nothing else.
-
PropertyKindCalculus.dim_not_injective[complete]
The dimension-1 disambiguation (the motivating capstone). There exist distinct
kinds that map to the same dimension. Concretely, for volumetric and gravimetric
water content,
\mathrm{vwc} \neq \mathrm{gwc} \qquad\text{yet}\qquad \dim(\mathrm{vwc}) = \dim(\mathrm{gwc}) = \mathbf{1},
and likewise for permittivity and reflectivity. So the kind layer is a strict
refinement of the dimension layer: \dim is not injective. This is the statement
PhysLib — and any dimension-only model, whether OWL2 or a representation-rooted
hierarchy like SysML v2's — structurally cannot make. Uses
kind-of-property and the dimension map.
Lean code for Theorem10.1.13●1 theorem
Associated Lean declarations
-
PropertyKindCalculus.dim_not_injective[complete]
-
PropertyKindCalculus.dim_not_injective[complete]
-
theoremdefined in PropertyKindCalculus/Dimension.leancomplete
theorem PropertyKindCalculus.dim_not_injective : ∃ a b, a.kind LTMCTDimensionBase ≠ b.kind LTMCTDimensionBase ∧ a.toDimension = b.toDimension ∧ a.toDimension = 1
theorem PropertyKindCalculus.dim_not_injective : ∃ a b, a.kind LTMCTDimensionBase ≠ b.kind LTMCTDimensionBase ∧ a.toDimension = b.toDimension ∧ a.toDimension = 1
**The dimension-1 disambiguation — the motivating capstone.** `dim` is *not injective*: there are distinct kinds with the same dimension, both equal to the dimensionless `1`. Volumetric and gravimetric water content witness it. PhysLib's `Dimension`, and any dimension-only type system, cannot separate them; the kind layer does.
Proved in the Dimension library. vwc and gwc are declared as dimensioned
kinds with distinct kind ids, so vwc.kind ≠ gwc.kind is by decide; both
carry dim = 1, so their dimensions agree by rfl. Together they witness
\exists a\ b,\ a.\mathrm{kind} \neq b.\mathrm{kind} \wedge \dim a = \dim b \wedge \dim a = 1.
-
PropertyKindCalculus.SIPrefix[complete]
A decimal SI prefix SIPrefix is a name and symbol denoting a power-of-ten
factor (e.g. centi = 10^{-2}). Applied to a unit it produces a multiple
(VIM4 2CD 1.20) or submultiple (1.21) of that unit.
Lean code for Definition10.1.14●1 definition
Associated Lean declarations
-
PropertyKindCalculus.SIPrefix[complete]
-
PropertyKindCalculus.SIPrefix[complete]
-
structuredefined in PropertyKindCalculus/UnitPrefix.leancomplete
structure PropertyKindCalculus.SIPrefix : Type
structure PropertyKindCalculus.SIPrefix : Type
**§1.19 NOTE 5 — an SI prefix.** A decimal factor `10 ^ exponent` used to form a multiple (§1.20) or submultiple (§1.21) of a unit, carried with its name and symbol. For example `centi` is `(name := "centi", symbol := "c", exponent := -2)`.
Fields
name : String
The prefix name, e.g. `"centi"`.
symbol : String
The prefix symbol, prepended to the base unit symbol, e.g. `"c"`.
exponent : ℤ
The power of ten: the factor is `10 ^ exponent` (centi = `-2`, kilo = `3`).
A structure SIPrefix carrying name, symbol, and an integer exponent (the
factor is 10^{\text{exponent}}); the full SI set (quetta … quecto) is
enumerated as defs.
-
PropertyKindCalculus.BinaryPrefix[complete]
A binary prefix BinaryPrefix (IEC 80000-13) is the information-technology
counterpart of an SI prefix, denoting a power-of-two factor: kibi = 2^{10},
mebi = 2^{20}, …. IEC 80000-13 introduced these to disambiguate the "kilobyte"
between 10^3 and 2^{10} bytes — kibi names the binary one. They are not SI
prefixes (the SI is decimal-only), so they are a distinct type; but they form the same
multiples/submultiples and bear the same §1.22 conversion factor, and so reuse one
prefixed-unit and one conversion round-trip.
Lean code for Definition10.1.15●1 definition
Associated Lean declarations
-
PropertyKindCalculus.BinaryPrefix[complete]
-
PropertyKindCalculus.BinaryPrefix[complete]
-
structuredefined in PropertyKindCalculus/UnitPrefix.leancomplete
structure PropertyKindCalculus.BinaryPrefix : Type
structure PropertyKindCalculus.BinaryPrefix : Type
**IEC 80000-13 — a prefix for binary multiples.** The information-technology counterpart of an SI prefix, scaling by a power of *two* rather than ten: kibi `= 2¹⁰`, mebi `= 2²⁰`, gibi `= 2³⁰`, …. IEC 80000-13 (*Information science and technology*, Ed. 2.0, 2025-02) introduced these precisely to remove the "kilobyte" ambiguity between `10³` and `2¹⁰` bytes — `kibi` names the binary one unambiguously. These are **not** SI prefixes (the SI is decimal-only), which is why they are a separate type; but they form multiples/submultiples and bear a §1.22 conversion factor exactly as SI prefixes do — the two share the same prefixed-unit machinery.
Fields
name : String
The prefix name, e.g. `"kibi"`.
symbol : String
The prefix symbol, prepended to the base unit symbol, e.g. `"Ki"`.
exponent : ℤ
The power of two: the factor is `2 ^ exponent` (kibi = `10`, mebi = `20`).
A structure BinaryPrefix carrying name, symbol, and an integer exponent (the
factor is 2^{\text{exponent}}); the eight prefixes kibi … yobi are enumerated as
defs. A PrefixedUnit records the resolved radix (10 or 2) so that a single
convertExp_roundtrip serves both families, gated to a common radix.