BridgeInitFloat32 #
External (assumption-based) bridge: Lean's Init.Float32 ↔ IEEE32Exec.
Why assumptions are necessary:
Init.Float32 arithmetic in Lean is implemented by external runtime calls. Those calls are opaque
to the Lean kernel, so (inside Lean) we cannot prove that the runtime implementation coincides
bit-for-bit with any particular float32 specification.
We package the intended connection as a typeclass interface. If you (or your trusted runtime) can
discharge the assumptions that the runtime Float32 primitives match the executable kernel
IEEE32Exec bit-for-bit, then you can:
- execute with
Float32(runtime), - rewrite the result to
IEEE32Exec, - reuse the internal refinement theorems (
BridgeFP32.lean/BridgeFP32Expr.lean) to connect execution to theFP32rounding-on-ℝmodel on finite/no-overflow inputs.
This keeps the trust boundary explicit: the only unproved part is the external/runtime correctness assumption, which is unavoidable in a pure Lean development.
Background:
- IEEE 754-2019 (what it means to “match float32 semantics”): https://doi.org/10.1109/IEEESTD.2019.8766229
Reinterpret a runtime Float32 as the executable bit-level float32 (IEEE32Exec).
Instances For
What this bridge gives us #
This file does not prove anything about the runtime semantics of Float32. Instead, it gives a
clean interface that you can assume/provide:
- If the runtime
Float32primitives produce the same result bits asIEEE32Exec, then runtime evaluation can be rewritten intoIEEE32Execevaluation. - Once we are in
IEEE32Exec, we can use the internal bridge theorems to connect execution to theFP32rounding-on-ℝmodel on the finite/no-overflow path (BridgeFP32.lean,BridgeFP32Total.lean,BridgeFP32Expr.lean).
We keep this separation because it makes the trust boundary explicit: the only “axioms” are the bit-level runtime correctness assumptions below.
External correctness assumptions #
Derived bit-level refinement lemmas #
Derived lemmas (rewriting runtime to executable) #
The assumptions above are phrased as bit equalities. In practice we almost always want the more convenient value-level rewriting lemmas below:
toIEEE32Exec (a + b) = IEEE32Exec.add (toIEEE32Exec a) (toIEEE32Exec b), etc.
These are the lemmas you use to “turn a runtime evaluation into an IEEE32Exec evaluation”.
Rewrite runtime float32 addition into executable IEEE32Exec.add.
Rewrite runtime float32 subtraction into executable IEEE32Exec.sub (value-level form).
Rewrite runtime float32 multiplication into executable IEEE32Exec.mul (value-level form).
Rewrite runtime float32 division into executable IEEE32Exec.div (value-level form).
Rewrite runtime float32 negation into executable IEEE32Exec.neg (value-level form).
Rewrite runtime float32 square root into executable IEEE32Exec.sqrt (value-level form).
Converting an IEEE32Exec value to runtime Float32 and back returns the original bits.