From 89e12f6f6151b60d00297bce11aa9dd62147636e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 28 Jun 2026 11:20:01 +0200 Subject: [PATCH 001/149] Add Exp.expRayToWad, the native-range inverse of lnWadToRay Computes floor(10**18 * exp(x / 10**27)) or one less (never overestimating) for x up to the octave k = round(x / (10**27 * ln2)) = 63, reverting Panic(0x11) above that. The result is monotone, equals 10**18 exactly at x == 0, and is 0 for x at or below floor(10**27 * ln(10**-18)). On the central octave it is tight, so expRayToWad(lnWadToRay(w)) == w - 1 for w/10**18 in [1/sqrt2, sqrt2) (== w at the scale point), letting a consumer in that regime recover w by adding one. The kernel reduces x = k*ln2 + t and evaluates the reciprocal-symmetric rational exp(t) = (Ev(t^2) + t*Od(t^2)) / (Ev(t^2) - t*Od(t^2)) -- Od degree 4, Ev degree 5 and monic -- on a mixed fixed-point staircase, then floors with the 2**k scaling folded into the closing shift. test/0.8.34/Exp.t.sol checks it differentially against a 120-digit mpmath oracle over FFI, plus the lnWadToRay round trip, monotonicity, the scale point, the over-range revert, and underflow to zero. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/vendor/Exp.sol | 117 +++++++++++++++++++++++++++++++++++++++++ test/0.8.34/Exp.t.sol | 85 ++++++++++++++++++++++++++++++ test/0.8.34/exp_ref.py | 20 +++++++ 3 files changed, 222 insertions(+) create mode 100644 src/vendor/Exp.sol create mode 100644 test/0.8.34/Exp.t.sol create mode 100644 test/0.8.34/exp_ref.py diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol new file mode 100644 index 000000000..b02a130a2 --- /dev/null +++ b/src/vendor/Exp.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.34; + +import {Panic} from "../utils/Panic.sol"; + +library Exp { + /// @notice Compute the natural exponential of a fixnum with 10**27 (ray) basis, returning the + /// result as a fixnum with 10**18 (wad) basis. The inverse of `Ln.lnWadToRay`. + /// @dev Let E = 10¹⁸ ⋅ exp(x / 10²⁷) be the exact, infinite-precision result. This function + /// returns either ⌊E⌋ or ⌊E⌋ - 1; it never overestimates. `expRayToWad(0) == 10**18` + /// exactly, and the result is never negative. The function is monotonic; x₁ < x₂ → + /// expRayToWad(x₁) ≤ expRayToWad(x₂). On the central octave it is tight (returns exactly + /// ⌊E⌋): for w with w / 10¹⁸ ∈ [1/√2, √2), `expRayToWad(lnWadToRay(w)) == w - 1` (and + /// `== w` at the scale point w = 10¹⁸), so a consumer constrained to that regime recovers + /// `w` by adding one. Reverts with `Panic(17)` when x is large enough to leave the + /// supported range (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10¹⁹). + function expRayToWad(int256 x) internal pure returns (int256 r) { + // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64, where the margin + // (which scales as 2ᵏ⁻⁶⁴ ulp) reaches one and the floor can fall two below E. + if (x >= 0x8e383a2cdfa1b74a9422d2e1) { + Panic.panic(Panic.ARITHMETIC_OVERFLOW); + } + r = _expRayToWad(x); + } + + /// @dev The supported-range kernel. Equivalent pseudocode; fixed-point truncations are + /// accounted for below: + /// k = round(x / (10²⁷⋅ln2)); // x = (k⋅ln2 + t)⋅10²⁷, |t| ≤ ln2/2 + /// t = x/10²⁷ - k⋅ln2; // reduced argument + /// e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) + /// r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; + /// r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 + /// return r + (x == 0); // pin exp(0) = 10¹⁸ exactly + /// + /// `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split + /// N(t) = Ev(t²) + t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational + /// that matches `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and + /// Od degree 4 (a (4,5) form, ≈135 bits); Ev is monic so its leading stage is a shift, not + /// a multiply. The relative error of the integer-rounded rational dwarfs the ≈2⁻⁶⁶ headroom + /// that flooring leaves on the central octave, so the round-trip with `lnWadToRay` lands + /// exactly one below the input there. + /// + /// Mixed fixed-point bases (a staircase): every quantity is rounded exactly once, and each + /// coefficient takes the widest basis fitting its minimal byte width, so a coefficient + /// followed by j more multiplies by v tolerates a shorter basis. + /// t: Q128 (one sdiv-free reduction; |t| ≤ ln2/2) + /// v = t²: Q128 (one `shr` by 128 from the Q256 product) + /// Ev Horner up the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) + /// Od Horner up the staircase Q105 → Q102 → Q93 → Q94 → Q87 + /// Ev, Od, t⋅Od, Num, Den final: Q87 (the basis shared by the closing quotient) + /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend `Num << 126` < 2²⁵⁶) + /// output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing + /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in + /// + /// The margin (2⁶²) is subtracted in the Q126 output grid so the accumulator never exceeds + /// E⋅2¹²⁶; margin plus the downward errors stay below one ulp on the central octave, so the + /// floor there is exactly ⌊E⌋, and below two ulps everywhere, so elsewhere it is ⌊E⌋ or + /// ⌊E⌋ - 1. `round(x / (10²⁷⋅ln2))` is computed half-open so the k = 0 band is exactly + /// [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching the image of `lnWadToRay` over [1/√2, √2). + function _expRayToWad(int256 x) private pure returns (int256 r) { + assembly ("memory-safe") { + // k = round(x / (10²⁷⋅ln2)), half-open. CINV = round(2²⁰⁰ / (10²⁷⋅ln2)); the +2¹⁹⁹ + // and `sar(200, …)` round to nearest with ties resolved toward +∞. + let k := sar(0xc8, add(shl(0xc7, 0x01), mul(0x724d54edbacbebbb95c52a0f6076, x))) + + // t in Q128. K27 = round(2²³⁵ / 10²⁷) places x/10²⁷ at Q135; subtracting + // k ⋅ round(ln2 ⋅ 2¹³⁵) leaves t at Q135 (the wider ln2 basis keeps k⋅ln2 exact), + // then `sar(7, …)` drops it to the Q128 working basis. + let t := + sar( + 0x07, + sub( + sar(0x64, mul(0x279d346de4781f921dd7a89933d54d1f72928, x)), + mul(0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a0, k) + ) + ) + + // v = t² in Q128 (nonnegative; logical shift). + let v := shr(0x80, mul(t, t)) + + // Ev(v), monic, Horner up the staircase. The leading v⁵ coefficient is one, so the + // first stage `(v >> 29) + a4` is a shift and an add. Coefficients are scaled by + // 1/e5 (shared with Od) so the quotient below is unaffected. + let ev := add(0xb9aacfad41060587203a79af0ebc, shr(0x1d, v)) + ev := add(0x9a036222e11aee18465042f8ea64c8, shr(0x82, mul(ev, v))) + ev := add(0x9064d965e1c4863b73604e0ddbec53f9, shr(0x80, mul(ev, v))) + ev := add(0x93f11e65781741b92fa7fc4f4fffcca2, shr(0x86, mul(ev, v))) + ev := add(0x4e14a45e8ec305e233e11b4174e214ac, shr(0x84, mul(ev, v))) + + // Od(v), Horner up the staircase. + let od := 0xdc07aff85e5bb5629d0fb64a84bb + od := add(0xc926ddbf3830ca5561cc01585402d0, shr(0x83, mul(od, v))) + od := add(0xad4506b00b1246c7e5b4fd33e1201b, shr(0x89, mul(od, v))) + od := add(0xaf5662483c4ce783a9ef5fe025f42e9e, shr(0x7f, mul(od, v))) + od := add(0x270a522f476182f119f08da0ba710a56, shr(0x87, mul(od, v))) + + // t⋅Od in Q87 (signed via t). Num = Ev + t⋅Od, Den = Ev - t⋅Od, both positive. + let tod := sar(0x80, mul(t, od)) + + // exp(t) in Q126: |Num ⋅ 2¹²⁶| < 2²⁵⁶ ∧ Den > 0. + r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) + + // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin, then floored by + // `sar(126 - k, …)` which folds in the 2ᵏ octave scaling (126 - k ∈ [64, 188]). + r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x4000000000000000)) + + // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x + // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs + // where the reduction would overflow, so it also discards those (otherwise garbage). + r := mul(slt(0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7, x), r) + + // exp(0) = 1 is the only input whose exact result is an integer; the construction lands + // on 10¹⁸ - 1, so add one back exactly there. + r := add(iszero(x), r) + } + } +} diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol new file mode 100644 index 000000000..b143b7d40 --- /dev/null +++ b/test/0.8.34/Exp.t.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.34; + +import {Exp} from "src/vendor/Exp.sol"; +import {Ln} from "src/vendor/Ln.sol"; +import {Test, stdError} from "@forge-std/Test.sol"; + +contract ExpTest is Test { + // First input whose octave count exceeds the supported range; `expRayToWad` reverts here. + int256 private constant _TOO_BIG = 0x8e383a2cdfa1b74a9422d2e1; + // floor(1e27 * ln(1e-18)): the greatest input whose exact result is < 1 and floors to 0. + int256 private constant _ZERO_MAX = -41446531673892822312323846185; + // Central octave [1/sqrt(2), sqrt(2)) in wad: the image over which the round trip is exact. + uint256 private constant _W_LO = 707106781186547525; + uint256 private constant _W_HI = 1414213562373095048; + + /// High-precision oracle: floor(1e18 * exp(x / 1e27)) via 120-digit arithmetic. + function _ref(int256 x) internal returns (int256) { + string[] memory cmd = new string[](3); + cmd[0] = "python3"; + cmd[1] = "test/0.8.34/exp_ref.py"; + cmd[2] = vm.toString(x); + return abi.decode(vm.ffi(cmd), (int256)); + } + + function expRayToWadExternal(int256 x) external pure returns (int256) { + return Exp.expRayToWad(x); + } + + /// Differential fuzz against the oracle: never overestimates and is floor-or-one-less across + /// the whole supported range. FFI spawns a process per run, so the run count is reduced. + /// forge-config: default.fuzz.runs = 512 + function testFuzzExpRayToWadDifferential(int256 x) external { + x = bound(x, _ZERO_MAX, _TOO_BIG - 1); + int256 r = Exp.expRayToWad(x); + int256 ref = _ref(x); + assertLe(r, ref, "overestimates exp"); + assertGe(r, ref - 1, "below floor minus one"); + assertGe(r, int256(0), "negative result"); + } + + function testExpRayToWadExactZero() external pure { + assertEq(Exp.expRayToWad(0), 1e18, "expRayToWad(0) != 1e18"); + } + + function testExpRayToWadOverRangeReverts() external { + vm.expectRevert(stdError.arithmeticError); + this.expRayToWadExternal(_TOO_BIG); + vm.expectRevert(stdError.arithmeticError); + this.expRayToWadExternal(type(int256).max); + } + + function testExpRayToWadUnderflowZero() external pure { + assertEq(Exp.expRayToWad(_ZERO_MAX), 0, "boundary not zero"); + assertEq(Exp.expRayToWad(_ZERO_MAX - 1), 0, "below boundary not zero"); + assertEq(Exp.expRayToWad(-50e27), 0, "deep negative not zero"); + assertEq(Exp.expRayToWad(-1e40), 0, "reduction-overflow region not zero"); + assertEq(Exp.expRayToWad(type(int256).min), 0, "int256.min not zero"); + } + + /// Round trip against `Ln` on the central octave: exactly off-by-one, and exact at the scale + /// point. A consumer in this regime recovers `w` by adding one. + function testFuzzExpRayToWadRoundTrip(uint256 w) external pure { + w = bound(w, _W_LO, _W_HI); + int256 back = Exp.expRayToWad(Ln.lnWadToRay(int256(w))); + if (w == 1e18) { + assertEq(back, int256(w), "scale point not exact"); + } else { + assertEq(back, int256(w) - 1, "round trip not w-1"); + } + } + + function testExpRayToWadRoundTripBoundaries() external pure { + assertEq(Exp.expRayToWad(Ln.lnWadToRay(int256(_W_LO))), int256(_W_LO) - 1); + assertEq(Exp.expRayToWad(Ln.lnWadToRay(int256(_W_HI))), int256(_W_HI) - 1); + assertEq(Exp.expRayToWad(Ln.lnWadToRay(1e18)), 1e18); + assertEq(Exp.expRayToWad(Ln.lnWadToRay(1e18 + 1)), 1e18); // w-1 + assertEq(Exp.expRayToWad(Ln.lnWadToRay(1e18 - 1)), 1e18 - 2); // w-1 + } + + function testFuzzExpRayToWadMonotone(int256 x) external pure { + x = bound(x, _ZERO_MAX, _TOO_BIG - 2); + assertGe(Exp.expRayToWad(x + 1), Exp.expRayToWad(x), "not monotone"); + } +} diff --git a/test/0.8.34/exp_ref.py b/test/0.8.34/exp_ref.py new file mode 100644 index 000000000..7744755ad --- /dev/null +++ b/test/0.8.34/exp_ref.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +"""High-precision reference for Exp.expRayToWad, used as the differential oracle over FFI. + +Prints floor(10**18 * exp(x / 10**27)) for the int256 argument `x`, ABI-encoded as a single +32-byte word (hex). The result is always non-negative over the tested range. +""" +import sys +import mpmath as mp + +mp.mp.dps = 120 + + +def main() -> None: + x = int(sys.argv[1]) + value = int(mp.floor(mp.mpf(10) ** 18 * mp.e ** (mp.mpf(x) / mp.mpf(10) ** 27))) + print("0x" + format(value & ((1 << 256) - 1), "064x")) + + +if __name__ == "__main__": + main() From 6b48449427ba017523fd46c8047ccb5675fb056d Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 28 Jun 2026 11:20:08 +0200 Subject: [PATCH 002/149] AGENTS.md: assembly and tooling conventions Document putting literal operands on the left of commutative ops (using the operand-flipped opcode when only one variant is commutative), the zero-arm-first form for boolean Yul switches, and the prohibition on pkill/killall (target a specific PID instead). Co-Authored-By: Claude Opus 4.8 (1M context) --- AGENTS.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index f37dfce08..b7b1bec42 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -139,6 +139,7 @@ Chain-specific functionality is composed via mixins. When adding a new DEX: | Precede every assembly block with: brief justification + equivalent Solidity pseudocode | Documents intent for reviewers | | Mark assembly blocks `memory-safe` when criteria are met | Enables compiler optimizations | | Use hex for all numeric constants in assembly (e.g. `0x60` not `96`, `0x20` not `32`) | Codebase convention; keeps assembly style uniform | +| Put literal operands on the left of commutative ops (`add`, `mul`, `and`, `or`, `xor`, `eq`); when only one variant is commutative, use the operand-flipped opcode to keep the literal left (e.g. `slt(C, x)` for `x > C`, `gt(C, x)` for `x < C`) | A leading literal is `PUSH`ed last, so the variable stays on top of the stack; this avoids `SWAP`/`DUP` shuffling during `via_ir` codegen and saves contract size | ### Gas Optimization @@ -453,6 +454,13 @@ non-idiomatic structure in order to achieve its goal. - Modify the `_dispatch` copy/paste pattern without updating all locations - Create standalone test files; use the project's test infrastructure - Use the `-f` or the `--force` flag to _**ANY**_ tool or utility, _EVER_. +- Use `pkill` or `killall`. To stop a specific background process, target it by its + PID (e.g. `kill "$pid"`); never match processes by name or pattern. +- Write a Yul `switch` of the form `switch case 1 { … } default { … }`. When + switching on a boolean, put the zero arm first: `switch case 0 { … } default + { … }`, so the `default` arm handles the truthy case (any nonzero), matching EVM + truthiness. Prefer a branchless select or an `if` over a two-arm boolean `switch` + where it reads more clearly. ### ALWAYS From 2c5976f0927a65f9fe5089b99df4422b65f9da2c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 28 Jun 2026 11:44:44 +0200 Subject: [PATCH 003/149] Optimize the Exp range reduction to a Q128 ln2 basis Rework the reduction t = x/10^27 - k*ln2: K27*x now takes a single sar(107, ...) to Q128 and subtracts k*floor(ln2*2^128), replacing the Q135 form (sar(100, ...), subtract k*round(ln2*2^135), then a second sar(7, ...)). One fewer SAR and a 16-byte ln2 word instead of 17 bytes. Correct the documented magnitude of E at the revert threshold: ~1.30*10^37, not 10^19. Add testFuzzExpRayToWadCentralExact, a direct oracle check over the central reduced-argument band. Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- src/vendor/Exp.sol | 16 ++++++---------- test/0.8.34/Exp.t.sol | 11 +++++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index b02a130a2..4a43a2821 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -13,7 +13,7 @@ library Exp { /// ⌊E⌋): for w with w / 10¹⁸ ∈ [1/√2, √2), `expRayToWad(lnWadToRay(w)) == w - 1` (and /// `== w` at the scale point w = 10¹⁸), so a consumer constrained to that regime recovers /// `w` by adding one. Reverts with `Panic(17)` when x is large enough to leave the - /// supported range (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10¹⁹). + /// supported range (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256 r) { // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64, where the margin // (which scales as 2ᵏ⁻⁶⁴ ulp) reaches one and the floor can fall two below E. @@ -63,16 +63,12 @@ library Exp { // and `sar(200, …)` round to nearest with ties resolved toward +∞. let k := sar(0xc8, add(shl(0xc7, 0x01), mul(0x724d54edbacbebbb95c52a0f6076, x))) - // t in Q128. K27 = round(2²³⁵ / 10²⁷) places x/10²⁷ at Q135; subtracting - // k ⋅ round(ln2 ⋅ 2¹³⁵) leaves t at Q135 (the wider ln2 basis keeps k⋅ln2 exact), - // then `sar(7, …)` drops it to the Q128 working basis. + // t in Q128. K27 = round(2²³⁵ / 10²⁷) places x/10²⁷ at Q128 after `sar(107, …)`; + // subtracting k ⋅ ⌊ln2 ⋅ 2¹²⁸⌋ leaves the reduced argument. let t := - sar( - 0x07, - sub( - sar(0x64, mul(0x279d346de4781f921dd7a89933d54d1f72928, x)), - mul(0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a0, k) - ) + sub( + sar(0x6b, mul(0x279d346de4781f921dd7a89933d54d1f72928, x)), + mul(0xb17217f7d1cf79abc9e3b39803f2f6af, k) ) // v = t² in Q128 (nonnegative; logical shift). diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index b143b7d40..814c8d5ab 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -10,6 +10,9 @@ contract ExpTest is Test { int256 private constant _TOO_BIG = 0x8e383a2cdfa1b74a9422d2e1; // floor(1e27 * ln(1e-18)): the greatest input whose exact result is < 1 and floors to 0. int256 private constant _ZERO_MAX = -41446531673892822312323846185; + // Central octave in ray input: [floor(-1e27 * ln(2) / 2), ceil(1e27 * ln(2) / 2)). + int256 private constant _CENTRAL_X_LO = -346573590279972654708616061; + int256 private constant _CENTRAL_X_HI = 346573590279972654708616061; // Central octave [1/sqrt(2), sqrt(2)) in wad: the image over which the round trip is exact. uint256 private constant _W_LO = 707106781186547525; uint256 private constant _W_HI = 1414213562373095048; @@ -43,6 +46,14 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(0), 1e18, "expRayToWad(0) != 1e18"); } + /// Direct oracle check over the central reduced-argument band, where the output is exact. + /// FFI spawns a process per run, so the run count is reduced. + /// forge-config: default.fuzz.runs = 512 + function testFuzzExpRayToWadCentralExact(int256 x) external { + x = bound(x, _CENTRAL_X_LO, _CENTRAL_X_HI - 1); + assertEq(Exp.expRayToWad(x), _ref(x), "central floor not exact"); + } + function testExpRayToWadOverRangeReverts() external { vm.expectRevert(stdError.arithmeticError); this.expRayToWadExternal(_TOO_BIG); From 1b060074677ca99ab3d5c3b6a3d7003419850b08 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 28 Jun 2026 21:26:08 +0200 Subject: [PATCH 004/149] Size the Exp margin to cover the range-reduction bias; never overestimate The 2^62 margin does not cover the upward bias of the Q128 range reduction (floor(ln2*2^128) under-subtracts k*ln2), so expRayToWad returned floor(E)+1 at k=62,63 -- violating the never-overestimate contract. Raise the one-sided margin to 0x594b01498486da8f, the least integer that covers the analytic worst-case overshoot S = 0.6976014718030033189 ulp, i.e. ceil(2^63*S) at the supported edge k=63. Both guarantees then close: A <= E (never over) and E-A < 1 (at most one ulp low). Document the exact per-source error budget and a monotonicity argument in the kernel comment, mirroring Ln.sol. Scrub comment references to identifiers absent from the code and correct the rational's stated precision (~135-bit approximation order, ~126-bit integer realization). Tests: raise the differential and central-exact FFI fuzz to 10000 runs; add deterministic octave-boundary monotonicity coverage and a high-k never-overestimate regression. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- src/vendor/Exp.sol | 67 +++++++++++++++++++++++++++++++------------ test/0.8.34/Exp.t.sol | 50 +++++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 23 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 4a43a2821..39177ab3a 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -16,7 +16,8 @@ library Exp { /// supported range (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256 r) { // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64, where the margin - // (which scales as 2ᵏ⁻⁶⁴ ulp) reaches one and the floor can fall two below E. + // (which scales as 2ᵏ⁻⁶³ of its k = 63 value) exceeds one ulp and the floor can fall two + // below E. if (x >= 0x8e383a2cdfa1b74a9422d2e1) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } @@ -35,10 +36,9 @@ library Exp { /// `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split /// N(t) = Ev(t²) + t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational /// that matches `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and - /// Od degree 4 (a (4,5) form, ≈135 bits); Ev is monic so its leading stage is a shift, not - /// a multiply. The relative error of the integer-rounded rational dwarfs the ≈2⁻⁶⁶ headroom - /// that flooring leaves on the central octave, so the round-trip with `lnWadToRay` lands - /// exactly one below the input there. + /// Od degree 4; in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the + /// integer coefficients realize ≈126 of them (the Q126 quotient). Ev is monic, so its + /// leading stage is a shift, not a multiply. /// /// Mixed fixed-point bases (a staircase): every quantity is rounded exactly once, and each /// coefficient takes the widest basis fitting its minimal byte width, so a coefficient @@ -47,16 +47,42 @@ library Exp { /// v = t²: Q128 (one `shr` by 128 from the Q256 product) /// Ev Horner up the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) /// Od Horner up the staircase Q105 → Q102 → Q93 → Q94 → Q87 - /// Ev, Od, t⋅Od, Num, Den final: Q87 (the basis shared by the closing quotient) - /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend `Num << 126` < 2²⁵⁶) + /// Ev, Od, t⋅Od, and the numerator/denominator: Q87 (the basis the closing quotient shares) + /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend, numerator << 126, < 2²⁵⁶) /// output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in /// - /// The margin (2⁶²) is subtracted in the Q126 output grid so the accumulator never exceeds - /// E⋅2¹²⁶; margin plus the downward errors stay below one ulp on the central octave, so the - /// floor there is exactly ⌊E⌋, and below two ulps everywhere, so elsewhere it is ⌊E⌋ or - /// ⌊E⌋ - 1. `round(x / (10²⁷⋅ln2))` is computed half-open so the k = 0 band is exactly - /// [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching the image of `lnWadToRay` over [1/√2, √2). + /// Error budget in output ulp (1 ulp = 10⁻¹⁸ of the result). Writing the margin-free + /// accumulator's excess over E as RAW = 10¹⁸⋅e⋅2ᵏ - E, the terms grow with the octave — the + /// reduction bias as k⋅2ᵏ, the rational and `sdiv` terms as 2ᵏ — so RAW peaks at the + /// supported edge k = 63. Bounding each source there: + /// reduction: ⌊ln2⋅2¹²⁸⌋ is rounded down, so k⋅ln2 is under-subtracted; the reduced + /// argument's positive bias lifts the accumulator by ≤ 0.6127005744787467880 ulp. + /// real-coefficient rational approximation + coefficient quantization (smooth) and the + /// integer Horner + closing `sdiv` truncation (a one-sided envelope, the Horner + /// error cancelling at the leading order because Ev appears in both Ev ± t⋅Od): + /// together ≤ 0.0849 ulp at the edge. + /// Hence RAW ≤ S, with the proven bound S = 0.6976014718030033189 ulp. The margin is the + /// least integer that covers S once placed in the Q126 grid: 0x594b01498486da8f = ⌈2⁶³⋅S⌉ + /// (worth ⌈2⁶³⋅S⌉⋅2⁻⁶³ ≈ S ulp at k = 63). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and because + /// RAW ≥ +0.0005121490606 there (the reduction bias keeps the accumulator above E), the + /// floor falls short by E - A ≤ 0.6970893227 < 1 — always ⌊E⌋ or ⌊E⌋ - 1. (No smaller + /// margin is provable; the largest demonstrably necessary is 0x513aec9797940001, the true + /// minimum lying between.) At k = 64 the margin exceeds one ulp and the floor can fall two + /// below E, so that input is reverted. On the central octave k = 0 the margin is + /// ⌈2⁶³⋅S⌉⋅2⁻¹²⁶ ≈ 7.56⋅10⁻²⁰ ulp and the downward total stays far below the ≈10⁻⁹ ulp gap + /// `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, + /// so the k = 0 band is exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image + /// over [1/√2, √2). + /// + /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, a relative + /// gain that exceeds the entire error span above (≤ S ≈ 7⋅10⁻³⁸ relative at k = 63, and + /// ∝ 2ᵏ below it) and its per-step variation — including the margin's doubling at each + /// octave boundary (≤ ⌈2⁶³⋅S⌉⋅2ᵏ⁻¹²⁶ ≈ 7⋅10⁻³⁸ relative) — by more than nine orders of + /// magnitude, so the pre-floor accumulator strictly increases at every step and its floor + /// is non-decreasing. The zeroing clamp and the +1 pin preserve order: below C the result + /// is 0 while just above it ⌊E⌋ ≥ 0, and at x = 0 the exact-on-central neighbours bracket + /// the pinned value (⌊E(-1)⌋ = 10¹⁸ - 1 ≤ 10¹⁸ ≤ ⌊E(1)⌋ = 10¹⁸). function _expRayToWad(int256 x) private pure returns (int256 r) { assembly ("memory-safe") { // k = round(x / (10²⁷⋅ln2)), half-open. CINV = round(2²⁰⁰ / (10²⁷⋅ln2)); the +2¹⁹⁹ @@ -75,8 +101,9 @@ library Exp { let v := shr(0x80, mul(t, t)) // Ev(v), monic, Horner up the staircase. The leading v⁵ coefficient is one, so the - // first stage `(v >> 29) + a4` is a shift and an add. Coefficients are scaled by - // 1/e5 (shared with Od) so the quotient below is unaffected. + // first stage is a shift and an add, not a multiply. Both polynomials carry a common + // scaling (the reciprocal of Ev's pre-normalization leading coefficient) that makes Ev + // monic and cancels in the quotient below. let ev := add(0xb9aacfad41060587203a79af0ebc, shr(0x1d, v)) ev := add(0x9a036222e11aee18465042f8ea64c8, shr(0x82, mul(ev, v))) ev := add(0x9064d965e1c4863b73604e0ddbec53f9, shr(0x80, mul(ev, v))) @@ -90,15 +117,17 @@ library Exp { od := add(0xaf5662483c4ce783a9ef5fe025f42e9e, shr(0x7f, mul(od, v))) od := add(0x270a522f476182f119f08da0ba710a56, shr(0x87, mul(od, v))) - // t⋅Od in Q87 (signed via t). Num = Ev + t⋅Od, Den = Ev - t⋅Od, both positive. + // t⋅Od in Q87 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are + // both positive. let tod := sar(0x80, mul(t, od)) - // exp(t) in Q126: |Num ⋅ 2¹²⁶| < 2²⁵⁶ ∧ Den > 0. + // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁶, the denominator > 0. r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) - // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin, then floored by - // `sar(126 - k, …)` which folds in the 2ᵏ octave scaling (126 - k ∈ [64, 188]). - r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x4000000000000000)) + // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum + // 0x594b01498486da8f = ⌈2⁶³⋅S⌉; see the budget above), then floored by `sar(126 - k, …)` + // which folds in the 2ᵏ octave scaling (126 - k ∈ [64, 188]). + r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x594b01498486da8f)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 814c8d5ab..26bb441de 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -31,8 +31,8 @@ contract ExpTest is Test { } /// Differential fuzz against the oracle: never overestimates and is floor-or-one-less across - /// the whole supported range. FFI spawns a process per run, so the run count is reduced. - /// forge-config: default.fuzz.runs = 512 + /// the whole supported range. + /// forge-config: default.fuzz.runs = 10000 function testFuzzExpRayToWadDifferential(int256 x) external { x = bound(x, _ZERO_MAX, _TOO_BIG - 1); int256 r = Exp.expRayToWad(x); @@ -47,8 +47,7 @@ contract ExpTest is Test { } /// Direct oracle check over the central reduced-argument band, where the output is exact. - /// FFI spawns a process per run, so the run count is reduced. - /// forge-config: default.fuzz.runs = 512 + /// forge-config: default.fuzz.runs = 10000 function testFuzzExpRayToWadCentralExact(int256 x) external { x = bound(x, _CENTRAL_X_LO, _CENTRAL_X_HI - 1); assertEq(Exp.expRayToWad(x), _ref(x), "central floor not exact"); @@ -93,4 +92,47 @@ contract ExpTest is Test { x = bound(x, _ZERO_MAX, _TOO_BIG - 2); assertGe(Exp.expRayToWad(x + 1), Exp.expRayToWad(x), "not monotone"); } + + /// First input of octave k: the least x with round(x / (10**27 * ln2)) == k, computed as + /// ceil((k*2**200 - 2**199) / CINV) with CINV = round(2**200 / (10**27 * ln2)), the same + /// reciprocal the kernel rounds with. + function _octaveStart(int256 k) private pure returns (int256) { + int256 CINV = 0x724d54edbacbebbb95c52a0f6076; + int256 num = k * (int256(1) << 200) - (int256(1) << 199); + return num >= 0 ? (num + CINV - 1) / CINV : num / CINV; + } + + /// Monotonicity is tightest where the octave count increments and the margin doubles. Check + /// every octave boundary in the supported range deterministically. + function testExpRayToWadOctaveBoundaryMonotone() external pure { + for (int256 k = -60; k <= 63; ++k) { + int256 xb = _octaveStart(k); + for (int256 x = xb - 2; x <= xb + 1; ++x) { + if (x + 1 >= _TOO_BIG) continue; + assertGe(Exp.expRayToWad(x + 1), Exp.expRayToWad(x), "octave-boundary monotonicity"); + } + } + } + + /// High-k inputs whose exact result sits just below an integer: the tightest points for the + /// never-overestimate guarantee, where the margin must cover the full reduction bias. + function testExpRayToWadNeverOverestimateHighK() external pure { + int256[4] memory xs = [ + int256(44014845965556527147989858478), + 43997357674525079384913362454, + 43314167405007111804561657812, + 43956299042314536509785490661 + ]; + int256[4] memory floors = [ + int256(13043817825332782212292423780355560294), + 12817686828684532031135154053443771706, + 6472974441739539356346729565753819877, + 12302067878139647644374925801327210534 + ]; + for (uint256 i; i < xs.length; ++i) { + int256 r = Exp.expRayToWad(xs[i]); + assertLe(r, floors[i], "overestimates exp"); + assertGe(r, floors[i] - 1, "below floor minus one"); + } + } } From 77c7798daafa265d1f05563ecec31efd2466b419 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 28 Jun 2026 22:28:23 +0200 Subject: [PATCH 005/149] Carry ln2 in one wide word; shrink the Exp margin 8x Subtract k*ln2 from K27*x at the Q235 product basis using a single 30-byte ln2 word, then one sar to Q128. This is the same op count (2 MUL, 1 SAR, 1 SUB) and runtime gas as the Q128 reduction -- only the ln2 constant widens (16 -> 30 bytes). The reduction's upward bias is negligible at this basis (~2.3e-6 ulp), so the analytic worst-case overshoot is S = 0.0858862987232991853 ulp and the one-sided margin its analytic minimum 0xafe527e18748a8a = ceil(2^63*S). Never-over and at-most-one-under still close; the error-budget comment is updated to match. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- src/vendor/Exp.sol | 63 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 39177ab3a..127e05283 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -43,7 +43,7 @@ library Exp { /// Mixed fixed-point bases (a staircase): every quantity is rounded exactly once, and each /// coefficient takes the widest basis fitting its minimal byte width, so a coefficient /// followed by j more multiplies by v tolerates a shorter basis. - /// t: Q128 (one sdiv-free reduction; |t| ≤ ln2/2) + /// t: Q128 (one `sar` from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln2/2) /// v = t²: Q128 (one `shr` by 128 from the Q256 product) /// Ev Horner up the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) /// Od Horner up the staircase Q105 → Q102 → Q93 → Q94 → Q87 @@ -53,32 +53,28 @@ library Exp { /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in /// /// Error budget in output ulp (1 ulp = 10⁻¹⁸ of the result). Writing the margin-free - /// accumulator's excess over E as RAW = 10¹⁸⋅e⋅2ᵏ - E, the terms grow with the octave — the - /// reduction bias as k⋅2ᵏ, the rational and `sdiv` terms as 2ᵏ — so RAW peaks at the - /// supported edge k = 63. Bounding each source there: - /// reduction: ⌊ln2⋅2¹²⁸⌋ is rounded down, so k⋅ln2 is under-subtracted; the reduced - /// argument's positive bias lifts the accumulator by ≤ 0.6127005744787467880 ulp. - /// real-coefficient rational approximation + coefficient quantization (smooth) and the - /// integer Horner + closing `sdiv` truncation (a one-sided envelope, the Horner - /// error cancelling at the leading order because Ev appears in both Ev ± t⋅Od): - /// together ≤ 0.0849 ulp at the edge. - /// Hence RAW ≤ S, with the proven bound S = 0.6976014718030033189 ulp. The margin is the - /// least integer that covers S once placed in the Q126 grid: 0x594b01498486da8f = ⌈2⁶³⋅S⌉ - /// (worth ⌈2⁶³⋅S⌉⋅2⁻⁶³ ≈ S ulp at k = 63). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and because - /// RAW ≥ +0.0005121490606 there (the reduction bias keeps the accumulator above E), the - /// floor falls short by E - A ≤ 0.6970893227 < 1 — always ⌊E⌋ or ⌊E⌋ - 1. (No smaller - /// margin is provable; the largest demonstrably necessary is 0x513aec9797940001, the true - /// minimum lying between.) At k = 64 the margin exceeds one ulp and the floor can fall two - /// below E, so that input is reverted. On the central octave k = 0 the margin is - /// ⌈2⁶³⋅S⌉⋅2⁻¹²⁶ ≈ 7.56⋅10⁻²⁰ ulp and the downward total stays far below the ≈10⁻⁹ ulp gap - /// `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, - /// so the k = 0 band is exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image - /// over [1/√2, √2). + /// accumulator's excess over E as RAW = 10¹⁸⋅e⋅2ᵏ - E, the rational and `sdiv` terms grow + /// as 2ᵏ, so RAW peaks at the supported edge k = 63. Bounding each source there: + /// reduction: ln2 is carried at Q235, so the under-subtraction of k⋅ln2 lifts the + /// accumulator by ≤ 2.32⋅10⁻⁶ ulp (negligible). + /// real-coefficient rational approximation + coefficient quantization (smooth), and the + /// integer Horner + closing `sdiv` truncation: a one-sided envelope. The Ev shared + /// by the numerator Ev + t⋅Od and denominator Ev - t⋅Od cancels at leading order, so + /// its truncation barely perturbs the quotient; together these stay ≤ 0.0859 ulp. + /// Hence RAW ≤ S, with the proven bound S = 0.0858862987232991853 ulp. The margin is the + /// least integer that covers S once placed in the Q126 grid: 0xafe527e18748a8a = ⌈2⁶³⋅S⌉ + /// (worth ≈ S ulp at k = 63). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and + /// E - A ≤ margin - min RAW ≤ 0.6057 < 1, so the floor is ⌊E⌋ or ⌊E⌋ - 1. At k = 64 the + /// margin exceeds one ulp and the floor can fall two below E, so that input is reverted. On + /// the central octave k = 0 the margin is ⌈2⁶³⋅S⌉⋅2⁻¹²⁶ ≈ 9.3⋅10⁻²¹ ulp, far below the + /// ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` + /// is half-open, so the k = 0 band is exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching + /// `lnWadToRay`'s image over [1/√2, √2). /// /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, a relative - /// gain that exceeds the entire error span above (≤ S ≈ 7⋅10⁻³⁸ relative at k = 63, and + /// gain that exceeds the entire error span above (≤ S ≈ 7⋅10⁻³⁹ relative at k = 63, and /// ∝ 2ᵏ below it) and its per-step variation — including the margin's doubling at each - /// octave boundary (≤ ⌈2⁶³⋅S⌉⋅2ᵏ⁻¹²⁶ ≈ 7⋅10⁻³⁸ relative) — by more than nine orders of + /// octave boundary (≤ ⌈2⁶³⋅S⌉⋅2ᵏ⁻¹²⁶ ≈ 7⋅10⁻³⁹ relative) — by more than nine orders of /// magnitude, so the pre-floor accumulator strictly increases at every step and its floor /// is non-decreasing. The zeroing clamp and the +1 pin preserve order: below C the result /// is 0 while just above it ⌊E⌋ ≥ 0, and at x = 0 the exact-on-central neighbours bracket @@ -89,12 +85,17 @@ library Exp { // and `sar(200, …)` round to nearest with ties resolved toward +∞. let k := sar(0xc8, add(shl(0xc7, 0x01), mul(0x724d54edbacbebbb95c52a0f6076, x))) - // t in Q128. K27 = round(2²³⁵ / 10²⁷) places x/10²⁷ at Q128 after `sar(107, …)`; - // subtracting k ⋅ ⌊ln2 ⋅ 2¹²⁸⌋ leaves the reduced argument. + // t in Q128. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln2 ⋅ 2²³⁵). Subtracting k ⋅ LN2 + // from K27 ⋅ x at the Q235 product basis (so the k ⋅ ln2 rounding error is ~2⁻²³⁵, far + // below an output ulp) then one `sar(107, …)` leaves the reduced argument at Q128. + // Carrying ln2 in a single wide word matches the op count of a Q128 reduction. let t := - sub( - sar(0x6b, mul(0x279d346de4781f921dd7a89933d54d1f72928, x)), - mul(0xb17217f7d1cf79abc9e3b39803f2f6af, k) + sar( + 0x6b, + sub( + mul(0x279d346de4781f921dd7a89933d54d1f72928, x), + mul(0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d, k) + ) ) // v = t² in Q128 (nonnegative; logical shift). @@ -125,9 +126,9 @@ library Exp { r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum - // 0x594b01498486da8f = ⌈2⁶³⋅S⌉; see the budget above), then floored by `sar(126 - k, …)` + // 0xafe527e18748a8a = ⌈2⁶³⋅S⌉; see the budget above), then floored by `sar(126 - k, …)` // which folds in the 2ᵏ octave scaling (126 - k ∈ [64, 188]). - r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x594b01498486da8f)) + r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xafe527e18748a8a)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs From 397d8520aed7eaad13139599d74f18de2ce38205 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 01:05:57 +0200 Subject: [PATCH 006/149] Scaffold the expRayToWad EVMYulLean proof: importer exp kind + package Add ExpWrapper.sol (selector 0x4187462b), an exp kind in formal/yul/YulImporter.lean and generate_from_forge.sh, and the formal/exp/ExpProof lake package mirroring formal/ln/LnProof. The generated ExpYul{,Runtime,Proof}.lean (gitignored) compile: run_exp_ray_to_wad_evm is the EVMYulLean interpretation of the compiled Yul, with the function chain external_fun_wrap_expRayToWad_99 -> fun_wrap_expRayToWad_99 -> fun_expRayToWad_70 (overflow guard) -> fun__expRayToWad_80 (kernel), plus fun_panic_8. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/.gitignore | 10 ++ formal/exp/ExpProof/ExpProof.lean | 1 + formal/exp/ExpProof/ExpProof/Cert/.gitkeep | 0 formal/exp/ExpProof/lake-manifest.json | 134 +++++++++++++++++++++ formal/exp/ExpProof/lakefile.toml | 11 ++ formal/exp/ExpProof/lean-toolchain | 1 + formal/yul/YulImporter.lean | 25 ++++ formal/yul/generate_from_forge.sh | 1 + src/wrappers/ExpWrapper.sol | 13 ++ 9 files changed, 196 insertions(+) create mode 100644 formal/exp/ExpProof/.gitignore create mode 100644 formal/exp/ExpProof/ExpProof.lean create mode 100644 formal/exp/ExpProof/ExpProof/Cert/.gitkeep create mode 100644 formal/exp/ExpProof/lake-manifest.json create mode 100644 formal/exp/ExpProof/lakefile.toml create mode 100644 formal/exp/ExpProof/lean-toolchain create mode 100644 src/wrappers/ExpWrapper.sol diff --git a/formal/exp/ExpProof/.gitignore b/formal/exp/ExpProof/.gitignore new file mode 100644 index 000000000..eb9f399b1 --- /dev/null +++ b/formal/exp/ExpProof/.gitignore @@ -0,0 +1,10 @@ +/.lake/ +/actual_axioms.txt + +# EVMYulLean artifacts generated from compiled ExpWrapper Yul IR. +/ExpProof/ExpYulRuntime.lean +/ExpProof/ExpYulProof.lean + +# Lean-generated certificate literals and cell covers — machine output. +/ExpProof/Cert/* +!/ExpProof/Cert/.gitkeep diff --git a/formal/exp/ExpProof/ExpProof.lean b/formal/exp/ExpProof/ExpProof.lean new file mode 100644 index 000000000..5fa40a040 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof.lean @@ -0,0 +1 @@ +import ExpProof.ExpYulProof diff --git a/formal/exp/ExpProof/ExpProof/Cert/.gitkeep b/formal/exp/ExpProof/ExpProof/Cert/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/formal/exp/ExpProof/lake-manifest.json b/formal/exp/ExpProof/lake-manifest.json new file mode 100644 index 000000000..ea840f9cf --- /dev/null +++ b/formal/exp/ExpProof/lake-manifest.json @@ -0,0 +1,134 @@ +{ + "version": "1.1.0", + "packagesDir": "../../yul/.lake/packages", + "packages": [ + { + "type": "path", + "scope": "", + "name": "FormalYul", + "manifestFile": "lake-manifest.json", + "inherited": false, + "dir": "../../yul", + "configFile": "lakefile.toml" + }, + { + "type": "path", + "scope": "", + "name": "evmyul", + "manifestFile": "lake-manifest.json", + "inherited": true, + "dir": "../../../lib/EVMYulLean", + "configFile": "lakefile.lean" + }, + { + "url": "https://github.com/leanprover-community/mathlib4.git", + "type": "git", + "subDir": null, + "scope": "", + "rev": "79e94a093aff4a60fb1b1f92d9681e407124c2ca", + "name": "mathlib", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.lean" + }, + { + "url": "https://github.com/leanprover-community/plausible", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "b100ad4c5d74a464f497aaa8e7c74d86bf39a56f", + "name": "plausible", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml" + }, + { + "url": "https://github.com/leanprover-community/LeanSearchClient", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "99657ad92e23804e279f77ea6dbdeebaa1317b98", + "name": "LeanSearchClient", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.toml" + }, + { + "url": "https://github.com/leanprover-community/import-graph", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "eb164a46de87078f27640ee71e6c3841defc2484", + "name": "importGraph", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml" + }, + { + "url": "https://github.com/leanprover-community/ProofWidgets4", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "1253a071e6939b0faf5c09d2b30b0bfc79dae407", + "name": "proofwidgets", + "manifestFile": "lake-manifest.json", + "inputRev": "v0.0.68", + "inherited": true, + "configFile": "lakefile.lean" + }, + { + "url": "https://github.com/leanprover-community/aesop", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "1256a18522728c2eeed6109b02dd2b8f207a2a3c", + "name": "aesop", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml" + }, + { + "url": "https://github.com/leanprover-community/quote4", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "917bfa5064b812b7fbd7112d018ea0b4def25ab3", + "name": "Qq", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml" + }, + { + "url": "https://github.com/leanprover-community/batteries", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "240676e9568c254a69be94801889d4b13f3b249f", + "name": "batteries", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml" + }, + { + "url": "https://github.com/leanprover/lean4-cli", + "type": "git", + "subDir": null, + "scope": "leanprover", + "rev": "c682c91d2d4dd59a7187e2ab977ac25bd1f87329", + "name": "Cli", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.toml" + } + ], + "name": "LnProof", + "lakeDir": ".lake" +} diff --git a/formal/exp/ExpProof/lakefile.toml b/formal/exp/ExpProof/lakefile.toml new file mode 100644 index 000000000..080004f08 --- /dev/null +++ b/formal/exp/ExpProof/lakefile.toml @@ -0,0 +1,11 @@ +name = "ExpProof" +version = "0.1.0" +defaultTargets = ["ExpProof"] +packagesDir = "../../yul/.lake/packages" + +[[lean_lib]] +name = "ExpProof" + +[[require]] +name = "FormalYul" +path = "../../yul" diff --git a/formal/exp/ExpProof/lean-toolchain b/formal/exp/ExpProof/lean-toolchain new file mode 100644 index 000000000..6ac6d4c4c --- /dev/null +++ b/formal/exp/ExpProof/lean-toolchain @@ -0,0 +1 @@ +leanprover/lean4:v4.22.0 diff --git a/formal/yul/YulImporter.lean b/formal/yul/YulImporter.lean index 1ed8b85b1..75b817dd1 100644 --- a/formal/yul/YulImporter.lean +++ b/formal/yul/YulImporter.lean @@ -12,6 +12,7 @@ inductive ModelKind where | cbrt | cbrt512 | ln + | exp deriving DecidableEq, Repr namespace ModelKind @@ -22,6 +23,7 @@ def parse : String → Option ModelKind | "cbrt" => some .cbrt | "cbrt512" => some .cbrt512 | "ln" => some .ln + | "exp" => some .exp | _ => none def namespaceName : ModelKind → String @@ -30,6 +32,7 @@ def namespaceName : ModelKind → String | .cbrt => "CbrtYul" | .cbrt512 => "Cbrt512Yul" | .ln => "LnYul" + | .exp => "ExpYul" def selectorCases : ModelKind → List String | .sqrt => ["0x5b29048a", "0x65c9cba1"] @@ -37,6 +40,7 @@ def selectorCases : ModelKind → List String | .cbrt => ["0x56df2b56", "0x29f2f4f1"] | .cbrt512 => ["0xa83a5c08", "0x7c0352fc"] | .ln => ["0xef102248", "0x31d42abd"] + | .exp => ["0x4187462b"] def functionPrefixes : ModelKind → List String | .sqrt => @@ -62,6 +66,9 @@ def functionPrefixes : ModelKind → List String | .ln => ["external_fun_wrap_lnWad_", "external_fun_wrap_lnWadToRay_", "fun_wrap_lnWad_", "fun_wrap_lnWadToRay_", "fun_lnWad_", "fun_lnWadToRay_"] + | .exp => + ["external_fun_wrap_expRayToWad_", + "fun_wrap_expRayToWad_", "fun_expRayToWad_", "fun__expRayToWad_"] def requiredCalls : ModelKind → List String | .sqrt => ["clz"] @@ -69,6 +76,7 @@ def requiredCalls : ModelKind → List String | .cbrt => ["clz"] | .cbrt512 => ["clz", "mulmod"] | .ln => ["clz", "sdiv"] + | .exp => ["sdiv"] end ModelKind @@ -491,12 +499,22 @@ def run_ln_wad_evm (x : Nat) : Except String Nat := FormalYul.callWord yulContract selector_lnWad [x] " +def runHelpersExp (contractDef : String) : String := +contractDef ++ " +def selector_expRayToWad : ByteArray := + FormalYul.bytes [0x41, 0x87, 0x46, 0x2b] + +def run_exp_ray_to_wad_evm (x : Nat) : Except String Nat := + FormalYul.callWord yulContract selector_expRayToWad [x] +" + def runHelpers : ModelKind → String → String | .sqrt => runHelpersSqrt | .sqrt512 => runHelpersSqrt512 | .cbrt => runHelpersCbrt | .cbrt512 => runHelpersCbrt512 | .ln => runHelpersLn + | .exp => runHelpersExp def dropLeanExtension (path : String) : String := if path.endsWith ".lean" then path.dropRight ".lean".length else path @@ -700,6 +718,13 @@ def generatedAliases (kind : ModelKind) (functions : List FunctionSource) : aliasByPrefix functions "fun_lnWad" "fun_lnWad_", aliasByPrefix functions "fun_lnWadToRay" "fun_lnWadToRay_" ] + | .exp => + sequence [ + aliasByPrefix functions "external_fun_wrap_expRayToWad" "external_fun_wrap_expRayToWad_", + aliasByPrefix functions "fun_wrap_expRayToWad" "fun_wrap_expRayToWad_", + aliasByPrefix functions "fun_expRayToWad" "fun_expRayToWad_", + aliasByPrefix functions "fun__expRayToWad" "fun__expRayToWad_" + ] def renderProof (kind : ModelKind) (contract : ParsedContract) (output : String) : Except String String := do let functions := contract.functions diff --git a/formal/yul/generate_from_forge.sh b/formal/yul/generate_from_forge.sh index 446c40e76..20cfbfaef 100755 --- a/formal/yul/generate_from_forge.sh +++ b/formal/yul/generate_from_forge.sh @@ -21,6 +21,7 @@ case "$kind" in cbrt) expected="29f2f4f1 56df2b56" ;; cbrt512) expected="7c0352fc a83a5c08" ;; ln) expected="31d42abd ef102248" ;; + exp) expected="4187462b" ;; *) echo "unknown kind: $kind" >&2; exit 2 ;; esac diff --git a/src/wrappers/ExpWrapper.sol b/src/wrappers/ExpWrapper.sol new file mode 100644 index 000000000..3aa610e5e --- /dev/null +++ b/src/wrappers/ExpWrapper.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.34; + +import {Exp} from "src/vendor/Exp.sol"; + +/// @dev Thin wrapper exposing Exp's internal function for `forge inspect ... ir`. +/// Function names are prefixed with `wrap_` to avoid Yul name collisions with the +/// library functions, keeping the IR unambiguous for the formal-proof code generator. +contract ExpWrapper { + function wrap_expRayToWad(int256 x) external pure returns (int256) { + return Exp.expRayToWad(x); + } +} From 8c58232f9065c03573b58c80946882ac04ffdfd2 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:22:54 +0200 Subject: [PATCH 007/149] Add reusable exp seam word-lemmas, overflow-guard, and revert reduction Direct on the EVMYulLean run_exp_ray_to_wad_evm interpretation (no hand model): - Seam/RuntimeShared.lean: u256 bounds, wordNat_sar/sdiv bridges, u256 idempotence (contract-agnostic; reused by both revert and the kernel arithmetic). - Seam/Guard.lean: slt(x, 0x8e383a2cdfa1b74a9422d2e1) = 0 for signed x at/above the threshold (the overflow-guard comparison; also bounds the in-range domain). - Seam/Revert.lean: primCall_revert_yul, the zero_value helper direct, and call_fun_panic_8_revert_direct (mstore;mstore;revert reduces to .error .Revert). All build and are axiom-clean ([propext, Classical.choice, Quot.sound]). This validates per-function interpreter reduction and revert mechanics on the exp contract. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Seam/Guard.lean | 49 +++++ formal/exp/ExpProof/ExpProof/Seam/Revert.lean | 80 +++++++ .../ExpProof/ExpProof/Seam/RuntimeShared.lean | 203 ++++++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Seam/Guard.lean create mode 100644 formal/exp/ExpProof/ExpProof/Seam/Revert.lean create mode 100644 formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean diff --git a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean new file mode 100644 index 000000000..5ebad267e --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean @@ -0,0 +1,49 @@ +import ExpProof.Seam.RuntimeShared + +/-! +# The overflow-guard comparison + +`fun_expRayToWad_70` branches on `iszero(slt(x, C))` with `C = 0x8e383a2cdfa1b74a9422d2e1` +(`= 0x8e383a2cdfa1b74a9422d2e1`, the first input whose octave count reaches 64). For a signed +input `x ≥ C` (with `u256 x < 2^255`, i.e. `x` a nonnegative signed value at least `C`), the +signed comparison `slt(x, C)` is `0`, so the guard `iszero(slt(x, C))` is `1` and the revert +branch is taken. Both `x` and `C` are below `2^255`, so neither is a negative signed value and the +comparison reduces to the unsigned `¬ (u256 x < C)`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- `C = 0x8e383a2cdfa1b74a9422d2e1` is below `2^255` (it is `≈ 2^95`). -/ +theorem thresh_lt_pow : (0x8e383a2cdfa1b74a9422d2e1 : Nat) < 2 ^ 255 := by decide + +/-- The overflow guard `slt(x, C)` is the word `0` for a signed input at or above the threshold, +so `iszero(slt(x, C))` is `1` and the revert branch fires. -/ +theorem slt_thresh_ge {x : Nat} + (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ u256 x) (h2 : u256 x < 2 ^ 255) : + EvmYul.UInt256.slt (EvmYul.UInt256.ofNat x) + (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1) + = EvmYul.UInt256.ofNat 0 := by + have hx : (EvmYul.UInt256.ofNat x).toNat = u256 x := by + have := wordNat_ofNat x; simpa [wordNat] using this + have hC : (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1).toNat + = 0x8e383a2cdfa1b74a9422d2e1 := by + have := wordNat_ofNat 0x8e383a2cdfa1b74a9422d2e1 + simpa [wordNat, u256, WORD_MOD] using this + have hCb : (0x8e383a2cdfa1b74a9422d2e1 : Nat) < 2 ^ 255 := thresh_lt_pow + unfold EvmYul.UInt256.slt EvmYul.UInt256.sltBool + rw [hx, hC] + rw [if_neg (by omega : ¬ (u256 x ≥ 2 ^ 255))] + rw [if_neg (by omega : ¬ ((0x8e383a2cdfa1b74a9422d2e1 : Nat) ≥ 2 ^ 255))] + have hnlt : ¬ EvmYul.UInt256.ofNat x + < EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1 := by + show ¬ (EvmYul.UInt256.ofNat x).toNat + < (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1).toNat + rw [hx, hC]; omega + simp [EvmYul.UInt256.fromBool, hnlt] + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean new file mode 100644 index 000000000..e46271d46 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean @@ -0,0 +1,80 @@ +import ExpProof.ExpYulProof +import ExpProof.Seam.RuntimeShared +import ExpProof.Seam.Guard +import FormalYul.Preservation + +/-! +# Revert reduction for the overflow guard + +`fun_expRayToWad_70` takes the overflow-guard branch for inputs at/above the threshold and calls +`fun_panic_8`, which does `mstore;mstore;revert(0x1c,0x24)`. These per-function "direct" lemmas +step the interpreter through that branch; mirrors the `ln` revert path. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- A Yul `revert(a, b)` primitive call halts with `.error .Revert`. -/ +private theorem primCall_revert_yul (fuel : Nat) (s : EvmYul.Yul.State) + (a b : EvmYul.UInt256) : + EvmYul.Yul.primCall (fuel + 1) s + (EvmYul.Operation.System EvmYul.Operation.SOp.REVERT : EvmYul.Operation .Yul) [a, b] = + .error EvmYul.Yul.Exception.Revert := by + rw [EvmYul.Yul.primCall.eq_def] + simp only [List.mem_cons, List.not_mem_nil, EvmYul.Operation.System.injEq, + Bool.not_eq_true, reduceCtorEq, or_self, and_false, if_false, + EvmYul.step.eq_def] + rfl + +/-- The `zero_value_for_split_t_int256()` helper returns the word `0`. -/ +private theorem call_zero_value_for_split_t_int256_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [] (.some "zero_value_for_split_t_int256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_zero_value_for_split_t_int256] + simp only [yulFunction_zero_value_for_split_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +set_option maxHeartbeats 8000000 in +/-- `fun_panic_8(code)` reverts: its body is `mstore(0,…); mstore(0x20,code); revert(0x1c,0x24)`. -/ +theorem call_fun_panic_8_revert_direct + (code fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 600) [FormalYul.word code] (.some "fun_panic_8") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .error EvmYul.Yul.Exception.Revert := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_panic_8] + simp only [yulFunction_fun_panic_8, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, primCall_revert_yul] + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean b/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean new file mode 100644 index 000000000..266914635 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean @@ -0,0 +1,203 @@ +import FormalYul.Preservation + +/-! +# Reusable, contract-agnostic word lemmas for the Exp runtime reduction + +These facts are general (not specific to `exp`): the `u256`/`int256` bounds and the +`wordNat`-preservation bridges for `sar` and `sdiv` (which `FormalYul.Preservation` does not +provide for signed shifts/division), plus the `u256`-idempotence absorbers for the `evm*` +results. They are used both by the revert proof and the kernel arithmetic reduction. Bodies are +copied verbatim from the `ln` proof's `Seam/RuntimeModel.lean` (they are not `ln`-specific). +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +theorem word_mod_eq : WORD_MOD = 2 ^ 256 := rfl + +theorem u256_lt_word (x : Nat) : u256 x < 2 ^ 256 := by + unfold u256 WORD_MOD + exact Nat.mod_lt _ (Nat.two_pow_pos 256) + +theorem u256_idem (x : Nat) : u256 (u256 x) = u256 x := by + unfold u256 WORD_MOD + exact Nat.mod_mod_of_dvd x (dvd_refl _) + +theorem u256_pos_bounds {x : Nat} (h : 0 < int256 (u256 x)) : + 1 ≤ u256 x ∧ u256 x < 2 ^ 255 := by + have hlt : u256 x < 2 ^ 256 := u256_lt_word x + unfold int256 at h + by_cases hb : u256 x < 2 ^ 255 + · simp only [hb, if_true] at h + have : 0 < u256 x := by exact_mod_cast h + exact ⟨this, hb⟩ + · exfalso + simp only [hb, if_false] at h + rw [intPow256] at h + have : (u256 x : Int) < 115792089237316195423570985008687907853269984665640564039457584007913129639936 := by + rw [← intPow256]; exact_mod_cast hlt + omega + +theorem wordNat_complement (a : EvmYul.UInt256) : + wordNat (EvmYul.UInt256.complement a) = evmNot (wordNat a) := by + have hav : a.toNat < 2 ^ 256 := by + simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size] + simp only [wordNat, EvmYul.UInt256.complement, EvmYul.UInt256.toNat, evmNot, u256, WORD_MOD, + Fin.sub_def, Fin.add_def, Fin.val_zero, Fin.val_one, EvmYul.UInt256.size] + omega + +theorem wordNat_sar (a b : EvmYul.UInt256) : + wordNat (EvmYul.UInt256.sar a b) = evmSar (wordNat a) (wordNat b) := by + have hb : wordNat b < 2 ^ 256 := by + simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size, wordNat] + have ha : wordNat a < 2 ^ 256 := by + simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size, wordNat] + have huina : u256 (wordNat a) = wordNat a := by + unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt ha + have huinb : u256 (wordNat b) = wordNat b := by + unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt hb + have hbz : ¬ (b < (⟨0⟩ : EvmYul.UInt256)) := by + have hz : (⟨0⟩ : EvmYul.UInt256).toNat = 0 := rfl + show ¬ (b.toNat < (⟨0⟩ : EvmYul.UInt256).toNat) + rw [hz]; omega + have hsltz : EvmYul.UInt256.sltBool b ⟨0⟩ = true ↔ 2 ^ 255 ≤ wordNat b := by + unfold EvmYul.UInt256.sltBool + by_cases hb255 : 2 ^ 255 ≤ wordNat b <;> + simp [hbz, wordNat, show (⟨0⟩ : EvmYul.UInt256).toNat = 0 from rfl] + unfold EvmYul.UInt256.sar + by_cases hneg : EvmYul.UInt256.sltBool b ⟨0⟩ = true + · rw [if_pos hneg] + have hvneg : 2 ^ 255 ≤ wordNat b := hsltz.mp hneg + rw [show (EvmYul.UInt256.complement b) >>> a + = EvmYul.UInt256.shiftRight (EvmYul.UInt256.complement b) a from rfl, + wordNat_complement, wordNat_shiftRight, wordNat_complement] + simp only [evmSar, evmShr, evmNot] + rw [huina, huinb, if_pos hvneg] + have hnotv : u256 (WORD_MOD - 1 - wordNat b) = WORD_MOD - 1 - wordNat b := by + unfold u256 WORD_MOD; apply Nat.mod_eq_of_lt; unfold WORD_MOD at hb; omega + rw [hnotv] + by_cases hs : wordNat a < 256 + · rw [if_pos hs, if_neg (by omega : ¬ 256 ≤ wordNat a)] + have hdiv : u256 ((WORD_MOD - 1 - wordNat b) / 2 ^ wordNat a) + = (WORD_MOD - 1 - wordNat b) / 2 ^ wordNat a := by + unfold u256 WORD_MOD; apply Nat.mod_eq_of_lt + have hle : (2 ^ 256 - 1 - wordNat b) / 2 ^ wordNat a ≤ 2 ^ 256 - 1 - wordNat b := + Nat.div_le_self _ _ + unfold WORD_MOD at hb; omega + rw [hdiv] + · rw [if_neg hs, if_pos (by omega : 256 ≤ wordNat a)] + have : u256 0 = 0 := by unfold u256 WORD_MOD; simp + rw [this]; omega + · rw [if_neg hneg] + have hvpos : wordNat b < 2 ^ 255 := by + by_contra hc; push_neg at hc; exact hneg (hsltz.mpr hc) + rw [show b >>> a = EvmYul.UInt256.shiftRight b a from rfl, wordNat_shiftRight] + simp only [evmSar, evmShr] + rw [huina, huinb, if_neg (by omega : ¬ 2 ^ 255 ≤ wordNat b)] + split_ifs <;> omega + +theorem size_eq_pow : EvmYul.UInt256.size = 2 ^ 256 := rfl + +private theorem toNat_neg_one (x : EvmYul.UInt256) : + wordNat (⟨x.val * (-1)⟩ : EvmYul.UInt256) + = (EvmYul.UInt256.size - wordNat x) % EvmYul.UInt256.size := by + have hrw : (x.val * (-1)) = (0 - x.val) := by rw [mul_neg_one, zero_sub] + rw [show (⟨x.val * (-1)⟩ : EvmYul.UInt256) = ⟨0 - x.val⟩ from congrArg _ hrw] + simp only [wordNat, EvmYul.UInt256.toNat, Fin.sub_def, Fin.val_zero, EvmYul.UInt256.size] + omega + +private theorem wordNat_abs (a : EvmYul.UInt256) : + wordNat (EvmYul.UInt256.abs a) + = if 2 ^ 255 ≤ wordNat a then (EvmYul.UInt256.size - wordNat a) % EvmYul.UInt256.size + else wordNat a := by + show (EvmYul.UInt256.abs a).toNat + = if 2 ^ 255 ≤ a.toNat then (EvmYul.UInt256.size - a.toNat) % EvmYul.UInt256.size + else a.toNat + unfold EvmYul.UInt256.abs + by_cases h : 2 ^ 255 ≤ a.toNat + · simp only [if_pos h]; exact toNat_neg_one a + · simp only [if_neg h] + +theorem wordNat_sdiv (a b : EvmYul.UInt256) : + wordNat (EvmYul.UInt256.sdiv a b) = evmSdiv (wordNat a) (wordNat b) := by + have ha : wordNat a < 2 ^ 256 := by + simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size, wordNat] + have hb : wordNat b < 2 ^ 256 := by + simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size, wordNat] + have hua : u256 (wordNat a) = wordNat a := by unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt ha + have hub : u256 (wordNat b) = wordNat b := by unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt hb + have hwm : WORD_MOD = 2 ^ 256 := word_mod_eq + have hsz : EvmYul.UInt256.size = 2 ^ 256 := size_eq_pow + simp only [evmSdiv, hua, hub, hwm] + unfold EvmYul.UInt256.sdiv + by_cases hna : 2 ^ 255 ≤ wordNat a <;> by_cases hnb : 2 ^ 255 ≤ wordNat b + · have dna : decide (2 ^ 255 ≤ wordNat a) = true := decide_eq_true_eq.mpr hna + have dnb : decide (2 ^ 255 ≤ wordNat b) = true := decide_eq_true_eq.mpr hnb + have m1 : (2 ^ 256 - wordNat a) % 2 ^ 256 = 2 ^ 256 - wordNat a := Nat.mod_eq_of_lt (by omega) + have m2 : (2 ^ 256 - wordNat b) % 2 ^ 256 = 2 ^ 256 - wordNat b := Nat.mod_eq_of_lt (by omega) + rw [if_pos (show 2 ^ 255 ≤ a.toNat from hna), if_pos (show 2 ^ 255 ≤ b.toNat from hnb), + wordNat_div, wordNat_abs, wordNat_abs, hsz, if_pos hna, if_pos hnb] + simp only [dna, dnb, if_true] + simp only [evmDiv, u256, WORD_MOD, m1, m2] + have hq : (2 ^ 256 - wordNat a) / (2 ^ 256 - wordNat b) ≤ 2 ^ 256 - wordNat a := Nat.div_le_self _ _ + revert hq + generalize (2 ^ 256 - wordNat a) / (2 ^ 256 - wordNat b) = q + intro hq + split_ifs <;> omega + · have dna : decide (2 ^ 255 ≤ wordNat a) = true := decide_eq_true_eq.mpr hna + have dnb : decide (2 ^ 255 ≤ wordNat b) = false := decide_eq_false_iff_not.mpr hnb + have m1 : (2 ^ 256 - wordNat a) % 2 ^ 256 = 2 ^ 256 - wordNat a := Nat.mod_eq_of_lt (by omega) + have hmodb : wordNat b % 2 ^ 256 = wordNat b := Nat.mod_eq_of_lt hb + rw [if_pos (show 2 ^ 255 ≤ a.toNat from hna), if_neg (show ¬ 2 ^ 255 ≤ b.toNat from hnb), + toNat_neg_one, hsz, wordNat_div, wordNat_abs, hsz, if_pos hna] + simp only [dna, dnb, Bool.true_eq_false, Bool.false_eq_true, + if_true, if_false] + simp only [evmDiv, u256, WORD_MOD, m1, hmodb] + have hq : (2 ^ 256 - wordNat a) / wordNat b ≤ 2 ^ 256 - wordNat a := Nat.div_le_self _ _ + revert hq + generalize (2 ^ 256 - wordNat a) / wordNat b = q + intro hq + split_ifs <;> omega + · have dna : decide (2 ^ 255 ≤ wordNat a) = false := decide_eq_false_iff_not.mpr hna + have dnb : decide (2 ^ 255 ≤ wordNat b) = true := decide_eq_true_eq.mpr hnb + have m2 : (2 ^ 256 - wordNat b) % 2 ^ 256 = 2 ^ 256 - wordNat b := Nat.mod_eq_of_lt (by omega) + have hmoda : wordNat a % 2 ^ 256 = wordNat a := Nat.mod_eq_of_lt ha + rw [if_neg (show ¬ 2 ^ 255 ≤ a.toNat from hna), if_pos (show 2 ^ 255 ≤ b.toNat from hnb), + toNat_neg_one, hsz, wordNat_div, wordNat_abs, hsz, if_pos hnb] + simp only [dna, dnb, Bool.false_eq_true, + if_true, if_false] + simp only [evmDiv, u256, WORD_MOD, m2, hmoda] + have hq : wordNat a / (2 ^ 256 - wordNat b) ≤ wordNat a := Nat.div_le_self _ _ + revert hq + generalize wordNat a / (2 ^ 256 - wordNat b) = q + intro hq + split_ifs <;> omega + · have dna : decide (2 ^ 255 ≤ wordNat a) = false := decide_eq_false_iff_not.mpr hna + have dnb : decide (2 ^ 255 ≤ wordNat b) = false := decide_eq_false_iff_not.mpr hnb + have hmoda : wordNat a % 2 ^ 256 = wordNat a := Nat.mod_eq_of_lt ha + have hmodb : wordNat b % 2 ^ 256 = wordNat b := Nat.mod_eq_of_lt hb + rw [if_neg (show ¬ 2 ^ 255 ≤ a.toNat from hna), if_neg (show ¬ 2 ^ 255 ≤ b.toNat from hnb), + wordNat_div] + simp only [dna, dnb, Bool.false_eq_true, + if_true, if_false] + simp only [evmDiv, u256, WORD_MOD, hmoda, hmodb] + have hq : wordNat a / wordNat b ≤ wordNat a := Nat.div_le_self _ _ + revert hq + generalize wordNat a / wordNat b = q + intro hq + split_ifs <;> omega + +theorem evmSar_u256_left (s v : Nat) : evmSar (u256 s) v = evmSar s v := by + simp only [evmSar, u256_idem] +theorem evmSar_u256_right (s v : Nat) : evmSar s (u256 v) = evmSar s v := by + simp only [evmSar, u256_idem] +theorem evmSdiv_u256_left (a b : Nat) : evmSdiv (u256 a) b = evmSdiv a b := by + simp only [evmSdiv, u256_idem] +theorem evmSdiv_u256_right (a b : Nat) : evmSdiv a (u256 b) = evmSdiv a b := by + simp only [evmSdiv, u256_idem] + +end ExpYul From 7a6e397552f3d46077203835158930578c0cf512 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:23:21 +0200 Subject: [PATCH 008/149] Prove fun_expRayToWad_70 reverts above the supported range Adds Seam/Helpers.lean (the solc ABI/cleanup-plumbing per-function directs, shared with the value path) and call_fun_expRayToWad_70_revert_direct in Seam/Revert.lean: for 0x8e383a2cdfa1b74a9422d2e1 <= u256 x < 2^255 the overflow guard fires and the function reverts via fun_panic_8(ARITHMETIC_OVERFLOW). This is the core supported-range revert logic. Axioms: [propext, Classical.choice, Quot.sound]. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .../exp/ExpProof/ExpProof/Seam/Helpers.lean | 325 ++++++++++++++++++ formal/exp/ExpProof/ExpProof/Seam/Revert.lean | 67 ++-- 2 files changed, 372 insertions(+), 20 deletions(-) create mode 100644 formal/exp/ExpProof/ExpProof/Seam/Helpers.lean diff --git a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean new file mode 100644 index 000000000..eed889044 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean @@ -0,0 +1,325 @@ +import ExpProof.ExpYulProof +import ExpProof.Seam.RuntimeShared +import FormalYul.Preservation + +/-! +# Per-function "direct" reductions for the trivial solc ABI/cleanup helpers + +These functions (`cleanup_*`, `identity`, `convert_*`, the constant accessor, `zero_value_*`) are +the solc-emitted plumbing called from `fun_expRayToWad_70`'s overflow guard and panic-code path. +Each is a one-liner; the directs step the interpreter through them. They are branch-agnostic — +the value path also evaluates the guard (to decide *not* to revert) — so they live here, shared by +both `Seam/Revert.lean` and the value-path seam. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- `zero_value_for_split_t_int256()` returns the word `0`. -/ +theorem call_zero_value_for_split_t_int256_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [] (.some "zero_value_for_split_t_int256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_zero_value_for_split_t_int256] + simp only [yulFunction_zero_value_for_split_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +/-- A one-line identity helper `f(value) -> out { out := value }` returns its argument. The proof +recipe is shared by `cleanup_t_int256`, `identity`, `cleanup_t_rational_*`, `cleanup_t_uint256`. -/ +theorem call_cleanup_t_int256_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] (.some "cleanup_t_int256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_int256] + simp only [yulFunction_cleanup_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +theorem call_identity_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] (.some "identity") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_identity] + simp only [yulFunction_identity, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +theorem call_cleanup_t_rational_44_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] + (.some "cleanup_t_rational_44014845965556527147994239713_by_1") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_cleanup_t_rational_44014845965556527147994239713_by_1] + simp only [yulFunction_cleanup_t_rational_44014845965556527147994239713_by_1, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +theorem call_cleanup_t_rational_17_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] + (.some "cleanup_t_rational_17_by_1") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_rational_17_by_1] + simp only [yulFunction_cleanup_t_rational_17_by_1, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +theorem call_cleanup_t_uint256_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] (.some "cleanup_t_uint256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_uint256] + simp only [yulFunction_cleanup_t_uint256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +/-- `convert_t_rational_44…_to_t_int256(value) -> converted` is +`cleanup_t_int256(identity(cleanup_t_rational_44…(value)))` — three identity calls, so it returns +its argument. Used to evaluate the overflow-guard comparison's right-hand side. -/ +theorem call_convert_44_to_int256_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 120)) [FormalYul.word v] + (.some "convert_t_rational_44014845965556527147994239713_by_1_to_t_int256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 120) = (fuel + extra) + 120 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_convert_t_rational_44014845965556527147994239713_by_1_to_t_int256] + simp only [yulFunction_convert_t_rational_44014845965556527147994239713_by_1_to_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h1 := + call_cleanup_t_rational_44_direct (v := v) (fuel := fuel + extra) (extra := 92) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h2 := + call_identity_direct (v := v) (fuel := fuel + extra) (extra := 94) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h3 := + call_cleanup_t_int256_direct (v := v) (fuel := fuel + extra) (extra := 96) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + simp [FormalYul.word] at h1 h2 h3 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, h1, h2, h3] + +/-- `cleanup_t_uint8(value) -> cleaned { cleaned := and(value, 0xff) }`. Specialized to the panic +code `0x11`, where `and(0x11, 0xff) = 0x11`. -/ +theorem call_cleanup_t_uint8_17_direct + (fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 20) [FormalYul.word 0x11] (.some "cleanup_t_uint8") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0x11]) := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_uint8] + simp only [yulFunction_cleanup_t_uint8, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +/-- `convert_t_rational_17_by_1_to_t_uint8(0x11) = 0x11` (= `cleanup_t_uint8(identity(cleanup_…(0x11)))`). -/ +theorem call_convert_17_to_uint8_17_direct + (fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 120) [FormalYul.word 0x11] + (.some "convert_t_rational_17_by_1_to_t_uint8") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0x11]) := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_convert_t_rational_17_by_1_to_t_uint8] + simp only [yulFunction_convert_t_rational_17_by_1_to_t_uint8, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h1 := + call_cleanup_t_rational_17_direct (v := 0x11) (fuel := fuel) (extra := 92) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h2 := + call_identity_direct (v := 0x11) (fuel := fuel) (extra := 94) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h3 := + call_cleanup_t_uint8_17_direct (fuel := fuel + 96) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + simp [FormalYul.word] at h1 h2 h3 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, h1, h2, h3] + +/-- `constant_ARITHMETIC_OVERFLOW_17() = 0x11` — the solc panic-code accessor for arithmetic +overflow (`0x11`). -/ +theorem call_constant_ARITHMETIC_OVERFLOW_17_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 160)) [] (.some "constant_ARITHMETIC_OVERFLOW_17") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0x11]) := by + rw [show fuel + (extra + 160) = (fuel + extra) + 160 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_constant_ARITHMETIC_OVERFLOW_17] + simp only [yulFunction_constant_ARITHMETIC_OVERFLOW_17, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hconv := + call_convert_17_to_uint8_17_direct (fuel := fuel + extra + 35) (shared := shared) + (store := Finmap.insert "expr_16" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + simp [FormalYul.word] at hconv + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, hconv] + +/-- `convert_t_uint8_to_t_uint256(0x11) = 0x11` (= `cleanup_t_uint256(identity(cleanup_t_uint8(0x11)))`). -/ +theorem call_convert_uint8_to_uint256_17_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 120)) [FormalYul.word 0x11] (.some "convert_t_uint8_to_t_uint256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0x11]) := by + rw [show fuel + (extra + 120) = (fuel + extra) + 120 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_convert_t_uint8_to_t_uint256] + simp only [yulFunction_convert_t_uint8_to_t_uint256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h1 := + call_cleanup_t_uint8_17_direct (fuel := fuel + extra + 92) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h2 := + call_identity_direct (v := 0x11) (fuel := fuel + extra) (extra := 94) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h3 := + call_cleanup_t_uint256_direct (v := 0x11) (fuel := fuel + extra) (extra := 96) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + simp [FormalYul.word] at h1 h2 h3 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, h1, h2, h3] + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean index e46271d46..bbd4f4ea1 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean @@ -1,6 +1,7 @@ import ExpProof.ExpYulProof import ExpProof.Seam.RuntimeShared import ExpProof.Seam.Guard +import ExpProof.Seam.Helpers import FormalYul.Preservation /-! @@ -30,51 +31,77 @@ private theorem primCall_revert_yul (fuel : Nat) (s : EvmYul.Yul.State) EvmYul.step.eq_def] rfl -/-- The `zero_value_for_split_t_int256()` helper returns the word `0`. -/ -private theorem call_zero_value_for_split_t_int256_direct - (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) +set_option maxHeartbeats 8000000 in +/-- `fun_panic_8(code)` reverts: its body is `mstore(0,…); mstore(0x20,code); revert(0x1c,0x24)`. -/ +theorem call_fun_panic_8_revert_direct + (code fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : - EvmYul.Yul.call (fuel + (extra + 20)) [] (.some "zero_value_for_split_t_int256") + EvmYul.Yul.call (fuel + (extra + 600)) [FormalYul.word code] (.some "fun_panic_8") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = - .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0]) := by - rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + .error EvmYul.Yul.Exception.Revert := by + rw [show fuel + (extra + 600) = (fuel + extra) + 600 by omega] rw [EvmYul.Yul.call.eq_def] - simp only [hlookup, Option.getD_some, yulContract_functions, - lookup_zero_value_for_split_t_int256] - simp only [yulFunction_zero_value_for_split_t_int256, + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_panic_8] + simp only [yulFunction_fun_panic_8, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word] + Finmap.lookup_insert, FormalYul.word, primCall_revert_yul] set_option maxHeartbeats 8000000 in -/-- `fun_panic_8(code)` reverts: its body is `mstore(0,…); mstore(0x20,code); revert(0x1c,0x24)`. -/ -theorem call_fun_panic_8_revert_direct - (code fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) +/-- For inputs at/above the overflow threshold, `fun_expRayToWad_70` takes the guard branch and +reverts via `fun_panic_8(ARITHMETIC_OVERFLOW)`. -/ +theorem call_fun_expRayToWad_70_revert_direct + (x fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = - some (FormalYul.accountFor yulContract)) : - EvmYul.Yul.call (fuel + 600) [FormalYul.word code] (.some "fun_panic_8") + some (FormalYul.accountFor yulContract)) + (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h2 : FormalYul.u256 x < 2 ^ 255) : + EvmYul.Yul.call (fuel + 1000) [FormalYul.word x] (.some "fun_expRayToWad_70") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .error EvmYul.Yul.Exception.Revert := by rw [EvmYul.Yul.call.eq_def] - simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_panic_8] - simp only [yulFunction_fun_panic_8, + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_70] + simp only [yulFunction_fun_expRayToWad_70, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execCall.eq_def, + have hconv44 := + call_convert_44_to_int256_direct (v := 0x8e383a2cdfa1b74a9422d2e1) (fuel := fuel) (extra := 867) + (shared := shared) (hlookup := hlookup) + have hcleanup := + call_cleanup_t_int256_direct (v := x) (fuel := fuel) (extra := 965) + (shared := shared) (hlookup := hlookup) + have hconvu := + call_convert_uint8_to_uint256_17_direct (fuel := fuel) (extra := 865) + (shared := shared) (hlookup := hlookup) + have hpanic := + call_fun_panic_8_revert_direct (code := 0x11) (fuel := fuel) (extra := 384) + (shared := shared) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at hconv44 hcleanup hconvu hpanic + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word, primCall_revert_yul] + Finmap.lookup_insert, FormalYul.word, + slt_thresh_ge h1 h2, + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 976) + (shared := shared) (hlookup := hlookup), + call_constant_ARITHMETIC_OVERFLOW_17_direct (fuel := fuel) (extra := 826) + (shared := shared) (hlookup := hlookup), + hcleanup, hconv44, hconvu, hpanic] end ExpYul From e9b89eb189331e161a52bec318a97faa7bff2430 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 02:33:41 +0200 Subject: [PATCH 009/149] Parametrize the exp 70-revert by fuel slack and add the wrapper revert Reformulate call_fun_expRayToWad_70_revert_direct to the (fuel + (extra + N)) slack form so callers can feed it inline, and add call_fun_wrap_expRayToWad_revert_direct (fun_wrap_expRayToWad_99 forwards to fun_expRayToWad_70). Completes the function-level supported-range revert chain. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Seam/Revert.lean | 53 ++++++++++++++++--- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean index bbd4f4ea1..77704facb 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean @@ -61,14 +61,15 @@ set_option maxHeartbeats 8000000 in /-- For inputs at/above the overflow threshold, `fun_expRayToWad_70` takes the guard branch and reverts via `fun_panic_8(ARITHMETIC_OVERFLOW)`. -/ theorem call_fun_expRayToWad_70_revert_direct - (x fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : - EvmYul.Yul.call (fuel + 1000) [FormalYul.word x] (.some "fun_expRayToWad_70") + EvmYul.Yul.call (fuel + (extra + 1000)) [FormalYul.word x] (.some "fun_expRayToWad_70") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .error EvmYul.Yul.Exception.Revert := by + rw [show fuel + (extra + 1000) = (fuel + extra) + 1000 by omega] rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_70] simp only [yulFunction_fun_expRayToWad_70, @@ -77,16 +78,16 @@ theorem call_fun_expRayToWad_70_revert_direct FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have hconv44 := - call_convert_44_to_int256_direct (v := 0x8e383a2cdfa1b74a9422d2e1) (fuel := fuel) (extra := 867) + call_convert_44_to_int256_direct (v := 0x8e383a2cdfa1b74a9422d2e1) (fuel := fuel + extra) (extra := 867) (shared := shared) (hlookup := hlookup) have hcleanup := - call_cleanup_t_int256_direct (v := x) (fuel := fuel) (extra := 965) + call_cleanup_t_int256_direct (v := x) (fuel := fuel + extra) (extra := 965) (shared := shared) (hlookup := hlookup) have hconvu := - call_convert_uint8_to_uint256_17_direct (fuel := fuel) (extra := 865) + call_convert_uint8_to_uint256_17_direct (fuel := fuel + extra) (extra := 865) (shared := shared) (hlookup := hlookup) have hpanic := - call_fun_panic_8_revert_direct (code := 0x11) (fuel := fuel) (extra := 384) + call_fun_panic_8_revert_direct (code := 0x11) (fuel := fuel + extra) (extra := 384) (shared := shared) (hlookup := hlookup) simp only [Nat.reduceAdd, FormalYul.word] at hconv44 hcleanup hconvu hpanic simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, @@ -98,10 +99,46 @@ theorem call_fun_expRayToWad_70_revert_direct EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, Finmap.lookup_insert, FormalYul.word, slt_thresh_ge h1 h2, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 976) + call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 976) (shared := shared) (hlookup := hlookup), - call_constant_ARITHMETIC_OVERFLOW_17_direct (fuel := fuel) (extra := 826) + call_constant_ARITHMETIC_OVERFLOW_17_direct (fuel := fuel + extra) (extra := 826) (shared := shared) (hlookup := hlookup), hcleanup, hconv44, hconvu, hpanic] +set_option maxHeartbeats 8000000 in +/-- The thin wrapper `fun_wrap_expRayToWad_99` just forwards to `fun_expRayToWad_70`, so it reverts +on the same out-of-range inputs. -/ +theorem call_fun_wrap_expRayToWad_revert_direct + (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) + (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h2 : FormalYul.u256 x < 2 ^ 255) : + EvmYul.Yul.call (fuel + (extra + 1200)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_99") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .error EvmYul.Yul.Exception.Revert := by + rw [show fuel + (extra + 1200) = (fuel + extra) + 1200 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_expRayToWad] + simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_99, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h70 := + call_fun_expRayToWad_70_revert_direct (x := x) (fuel := fuel + extra) (extra := 191) + (shared := shared) (h1 := h1) (h2 := h2) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at h70 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, + call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 1176) + (shared := shared) (hlookup := hlookup), + h70] + end ExpYul From 30c3f75955887491294154d0e1e45392057746f6 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:23:53 +0200 Subject: [PATCH 010/149] Prove expRayToWad reverts above the supported range Adds Seam/Dispatcher.lean (branch-agnostic dispatcher/calldata seam for ExpYul: expSharedAfterFreePtr, the ABI decode chain, shift_right_224, the 0x4187462b selector switch-case, and the contract-polymorphic runContract_revert_of_exec_revert) and the revert-specific external/dispatcher reductions in Seam/Revert.lean, yielding the top-level run_exp_ray_to_wad_evm_revert : 0x8e383a2cdfa1b74a9422d2e1 <= u256 x -> u256 x < 2^255 -> run_exp_ray_to_wad_evm x = .error "revert" proven directly on the EVMYulLean interpretation of the solc/forge Yul, with no new models. Axioms: [propext, Classical.choice, Quot.sound]. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../ExpProof/ExpProof/Seam/Dispatcher.lean | 372 ++++++++++++++++++ formal/exp/ExpProof/ExpProof/Seam/Revert.lean | 118 ++++++ 2 files changed, 490 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean diff --git a/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean b/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean new file mode 100644 index 000000000..95ad19cb4 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean @@ -0,0 +1,372 @@ +import ExpProof.ExpYulProof +import ExpProof.Seam.RuntimeShared +import ExpProof.Seam.Helpers +import FormalYul.Preservation + +/-! +# Branch-agnostic dispatcher / calldata seam for `ExpYul` + +The free-pointer setup, ABI calldata decode, selector extraction, switch-case selection, and the +contract-polymorphic `runContract` packaging are independent of which way `expRayToWad` resolves +(revert vs value), so they live here, shared by `Seam/Revert.lean` and the value path. Mirrors the +`ln` dispatcher seam. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- Shared state after the dispatcher's `mstore(64,128)` free-pointer init, for the +`expRayToWad` calldata. -/ +def expSharedAfterFreePtr (x : Nat) : EvmYul.SharedState .Yul := + let shared := FormalYul.sharedFor yulContract (selector_expRayToWad ++ FormalYul.encodeWords [x]) + { shared with toMachineState := shared.toMachineState.mstore (FormalYul.word 64) (FormalYul.word 128) } + +@[simp] +theorem expSharedAfterFreePtr_lookup (x : Nat) : + (expSharedAfterFreePtr x).accountMap.find? + (expSharedAfterFreePtr x).executionEnv.codeOwner = + some (FormalYul.accountFor yulContract) := by + simp [expSharedAfterFreePtr] + +@[simp] +theorem expSharedAfterFreePtr_calldata (x : Nat) : + (expSharedAfterFreePtr x).executionEnv.calldata = + selector_expRayToWad ++ FormalYul.encodeWords [x] := by + simp [expSharedAfterFreePtr, FormalYul.sharedFor, FormalYul.envFor] + +@[simp] +theorem expSharedAfterFreePtr_weiValue (x : Nat) : + (expSharedAfterFreePtr x).executionEnv.weiValue = ({ val := 0 } : EvmYul.UInt256) := by + simp [expSharedAfterFreePtr, FormalYul.sharedFor, FormalYul.envFor] + +@[simp] +theorem expSharedAfterFreePtr_mload64 (x : Nat) : + ((expSharedAfterFreePtr x).mload (FormalYul.word 64)).1 = FormalYul.word 128 := + FormalYul.Preservation.sharedFor_mload_freePtr_after_mstore yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x]) + +@[simp] +theorem expRayToWad_calldata_size (x : Nat) : + (selector_expRayToWad ++ FormalYul.encodeWords [x]).size = 36 := by + simp [selector_expRayToWad, FormalYul.encodeWords, + FormalYul.bytes, ByteArray.size_append, ByteArray.size_push, ByteArray.size_empty, + FormalYul.Preservation.encodeWord_size] + +@[simp] +theorem calldataload_expRayToWad_arg_of_calldata + (x : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hdata : shared.executionEnv.calldata = selector_expRayToWad ++ FormalYul.encodeWords [x]) : + EvmYul.State.calldataload + (EvmYul.Yul.State.Ok shared store).toState (FormalYul.word 4) = + FormalYul.word x := by + simp [EvmYul.State.calldataload, EvmYul.Yul.State.toState, hdata, + selector_expRayToWad, FormalYul.encodeWords] + +/-- `validator_revert_t_int256(value)` does `if iszero(eq(value, cleanup_t_int256(value))) {revert}`; +since `cleanup_t_int256` is the identity the equality always holds, so it never reverts. -/ +theorem call_validator_revert_t_int256_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 80)) [FormalYul.word v] (.some "validator_revert_t_int256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, []) := by + rw [show fuel + (extra + 80) = (fuel + extra) + 80 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_validator_revert_t_int256] + simp only [yulFunction_validator_revert_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hcleanup := + call_cleanup_t_int256_direct (v := v) (fuel := fuel + extra) (extra := 51) + (shared := shared) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at hcleanup + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, hcleanup] + +/-- `abi_decode_t_int256(offset, end) := calldataload(offset); validator(value)` — for the +`expRayToWad` calldata at offset 4 it reads `x` and validates (no revert). -/ +theorem call_abi_decode_t_int256_of_calldata + (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) + (hdata : shared.executionEnv.calldata = selector_expRayToWad ++ FormalYul.encodeWords [x]) : + EvmYul.Yul.call (fuel + (extra + 200)) [FormalYul.word 4, FormalYul.word 36] + (.some "abi_decode_t_int256") (.some yulContract) + (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word x]) := by + rw [show fuel + (extra + 200) = (fuel + extra) + 200 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_abi_decode_t_int256] + simp only [yulFunction_abi_decode_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hvalidator := + call_validator_revert_t_int256_direct (v := x) (fuel := fuel + extra) (extra := 115) + (shared := shared) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at hvalidator + have hload := + calldataload_expRayToWad_arg_of_calldata x shared + (Finmap.insert "offset" (FormalYul.word 4) + (Finmap.insert "end" (FormalYul.word 36) (Inhabited.default : EvmYul.Yul.VarStore))) + hdata + simp [FormalYul.word] at hload + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, hload, hvalidator] + +/-- `abi_decode_tuple_t_int256(headStart, dataEnd)` decodes the single `int256` argument `x`. -/ +theorem call_abi_decode_tuple_t_int256_of_calldata + (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) + (hdata : shared.executionEnv.calldata = selector_expRayToWad ++ FormalYul.encodeWords [x]) : + EvmYul.Yul.call (fuel + (extra + 320)) [FormalYul.word 4, FormalYul.word 36] + (.some "abi_decode_tuple_t_int256") (.some yulContract) + (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word x]) := by + rw [show fuel + (extra + 320) = (fuel + extra) + 320 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_abi_decode_tuple_t_int256] + simp only [yulFunction_abi_decode_tuple_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hdecode := + call_abi_decode_t_int256_of_calldata (x := x) (fuel := fuel + extra) (extra := 113) + (shared := shared) (hlookup := hlookup) (hdata := hdata) + simp only [Nat.reduceAdd, FormalYul.word] at hdecode + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, hdecode] + +/-- `shift_right_224_unsigned(value) := shr(224, value)`. -/ +theorem call_shift_right_224_unsigned_direct + (v : EvmYul.UInt256) (fuel : Nat) + (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 20) [v] (.some "shift_right_224_unsigned") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, + [EvmYul.UInt256.shiftRight v (FormalYul.word 224)]) := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, + Option.getD_some, yulContract_functions, lookup_shift_right_224_unsigned] + simp only [yulFunction_shift_right_224_unsigned, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [ + EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +theorem sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr (x : Nat) : + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (FormalYul.word 64) (FormalYul.word 128))) = + expSharedAfterFreePtr x := rfl + +theorem sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr_raw (x : Nat) : + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) = + expSharedAfterFreePtr x := by + simpa [FormalYul.word] using sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr x + +@[simp] +theorem sharedFor_expRayToWad_calldata_size (x : Nat) : + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).executionEnv.calldata.size = 36 := by + simp [FormalYul.sharedFor, FormalYul.envFor, expRayToWad_calldata_size] + +theorem expRayToWad_selector_afterFreePtr (x : Nat) : + EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (FormalYul.word 0)) + (FormalYul.word 224) = + FormalYul.word 1099384363 := by + have hselector := + FormalYul.Preservation.shiftRight_calldataload_selector_single_arg_of_calldata + (shared := expSharedAfterFreePtr x) + (store := (Inhabited.default : EvmYul.Yul.VarStore)) + (a := 0x41) (b := 0x87) (c := 0x46) (d := 0x2b) (x := x) + (by simp [selector_expRayToWad]) + simpa [EvmYul.fromBytesBigEndian, EvmYul.fromBytes', FormalYul.word] using hselector + +@[simp] +theorem expRayToWad_selector_sharedFor_mk (x : Nat) : + EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (FormalYul.word 64) (FormalYul.word 128))) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (FormalYul.word 0)) + (FormalYul.word 224) = + FormalYul.word 1099384363 := by + rw [sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr] + exact expRayToWad_selector_afterFreePtr x + +@[simp] +theorem selectSwitchCase_expRayToWad_sharedFor_mk (x : Nat) : + EvmYul.Yul.selectSwitchCase + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (FormalYul.word 64) (FormalYul.word 128))) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (FormalYul.word 0)) + (FormalYul.word 224)) + [(FormalYul.word 1099384363, + [EvmYul.Yul.Ast.Stmt.ExprStmtCall + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_99") [])])] = + some + [EvmYul.Yul.Ast.Stmt.ExprStmtCall + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_99") [])] := by + rw [expRayToWad_selector_sharedFor_mk] + rfl + +theorem selectSwitchCase_expRayToWad_sharedFor_mk_raw (x : Nat) : + EvmYul.Yul.selectSwitchCase + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + [(EvmYul.UInt256.ofNat 1099384363, + [EvmYul.Yul.Ast.Stmt.ExprStmtCall + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_99") [])])] = + some + [EvmYul.Yul.Ast.Stmt.ExprStmtCall + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_99") [])] := by + simpa [FormalYul.word] using selectSwitchCase_expRayToWad_sharedFor_mk x + +/-- Revert-analogue of `Preservation.runContract_ok_of_dispatcherReturn`: if the bare dispatcher +`exec` on `stateFor` reverts, the wrapped `runContract` returns `.error "revert"`. Contract +polymorphic; mirrors `ln`'s lemma verbatim. -/ +theorem runContract_revert_of_exec_revert + {contract : YulContract} {input : ByteArray} {execFuel : Nat} + (h : EvmYul.Yul.exec execFuel contract.dispatcher (.some contract) + (stateFor contract input) = .error EvmYul.Yul.Exception.Revert) : + runContract contract input (Nat.succ (Nat.succ execFuel)) = .error "revert" := by + unfold runContract + rw [EvmYul.Yul.callDispatcher.eq_def] + simp only [stateFor, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk, + EvmYul.Yul.State.executionEnv, sharedFor, envFor, accountMapFor, accountFor, + EvmYul.Yul.State.multifill, EvmYul.Yul.State.setStore, List.zip_nil_left, List.foldr_nil, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def] + rw [EvmYul.Yul.exec.eq_def] + simp only + have hdisp' : + EvmYul.Yul.exec execFuel contract.dispatcher (.some contract) + (EvmYul.Yul.State.Ok + { (Inhabited.default : EvmYul.SharedState .Yul) with + accountMap := accountMapFor contract + executionEnv := envFor contract input + gasAvailable := .ofNat 1000000000 } + (Inhabited.default : EvmYul.Yul.VarStore)) = + .error EvmYul.Yul.Exception.Revert := by + simpa [stateFor, sharedFor] using h + have hdisp'' : + EvmYul.Yul.exec execFuel contract.dispatcher (.some contract) + (EvmYul.Yul.State.Ok + { accountMap := accountMapFor contract, + σ₀ := (Inhabited.default : EvmYul.SharedState .Yul).σ₀, + totalGasUsedInBlock := (Inhabited.default : EvmYul.SharedState .Yul).totalGasUsedInBlock, + transactionReceipts := (Inhabited.default : EvmYul.SharedState .Yul).transactionReceipts, + substate := (Inhabited.default : EvmYul.SharedState .Yul).substate, + executionEnv := envFor contract input, + blocks := (Inhabited.default : EvmYul.SharedState .Yul).blocks, + genesisBlockHeader := (Inhabited.default : EvmYul.SharedState .Yul).genesisBlockHeader, + createdAccounts := (Inhabited.default : EvmYul.SharedState .Yul).createdAccounts, + gasAvailable := EvmYul.UInt256.ofNat 1000000000, + activeWords := (Inhabited.default : EvmYul.SharedState .Yul).activeWords, + memory := (Inhabited.default : EvmYul.SharedState .Yul).memory, + returnData := (Inhabited.default : EvmYul.SharedState .Yul).returnData, + H_return := (Inhabited.default : EvmYul.SharedState .Yul).H_return } + (Inhabited.default : EvmYul.Yul.VarStore)) = + .error EvmYul.Yul.Exception.Revert := by + simpa using hdisp' + have hdisp''' : + EvmYul.Yul.exec execFuel contract.dispatcher (.some contract) + (EvmYul.Yul.State.Ok + { accountMap := Batteries.RBMap.insert ∅ contractOwner + { (Inhabited.default : EvmYul.Account .Yul) with code := contract }, + σ₀ := (Inhabited.default : EvmYul.SharedState .Yul).σ₀, + totalGasUsedInBlock := (Inhabited.default : EvmYul.SharedState .Yul).totalGasUsedInBlock, + transactionReceipts := (Inhabited.default : EvmYul.SharedState .Yul).transactionReceipts, + substate := (Inhabited.default : EvmYul.SharedState .Yul).substate, + executionEnv := { (Inhabited.default : EvmYul.ExecutionEnv .Yul) with + calldata := input + code := contract + codeOwner := contractOwner + weiValue := ⟨0⟩ + perm := true }, + blocks := (Inhabited.default : EvmYul.SharedState .Yul).blocks, + genesisBlockHeader := (Inhabited.default : EvmYul.SharedState .Yul).genesisBlockHeader, + createdAccounts := (Inhabited.default : EvmYul.SharedState .Yul).createdAccounts, + gasAvailable := EvmYul.UInt256.ofNat 1000000000, + activeWords := (Inhabited.default : EvmYul.SharedState .Yul).activeWords, + memory := (Inhabited.default : EvmYul.SharedState .Yul).memory, + returnData := (Inhabited.default : EvmYul.SharedState .Yul).returnData, + H_return := (Inhabited.default : EvmYul.SharedState .Yul).H_return } + (Inhabited.default : EvmYul.Yul.VarStore)) = + .error EvmYul.Yul.Exception.Revert := by + simpa [accountMapFor, accountFor, envFor] using hdisp'' + rw [hdisp'''] + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean index 77704facb..ce012c243 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean @@ -2,6 +2,7 @@ import ExpProof.ExpYulProof import ExpProof.Seam.RuntimeShared import ExpProof.Seam.Guard import ExpProof.Seam.Helpers +import ExpProof.Seam.Dispatcher import FormalYul.Preservation /-! @@ -141,4 +142,121 @@ theorem call_fun_wrap_expRayToWad_revert_direct (shared := shared) (hlookup := hlookup), h70] +set_option maxHeartbeats 8000000 in +/-- The external entrypoint `external_fun_wrap_expRayToWad_99` decodes the calldata argument `x` +(`callvalue` is 0, so the value guard is skipped) and forwards to `fun_wrap_expRayToWad_99`, which +reverts for out-of-range `x`. -/ +theorem external_fun_wrap_expRayToWad_calldata_revert + (x : Nat) (store : EvmYul.Yul.VarStore) + (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h2 : FormalYul.u256 x < 2 ^ 255) : + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) = + .error EvmYul.Yul.Exception.Revert := by + rw [EvmYul.Yul.call.eq_def] + simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, + lookup_external_fun_wrap_expRayToWad] + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hdecode := + call_abi_decode_tuple_t_int256_of_calldata (x := x) (fuel := 0) (extra := 999664) + (shared := expSharedAfterFreePtr x) + (hlookup := expSharedAfterFreePtr_lookup x) + (hdata := expSharedAfterFreePtr_calldata x) + simp only [Nat.reduceAdd, FormalYul.word] at hdecode + have hwrap := + call_fun_wrap_expRayToWad_revert_direct (x := x) (fuel := 0) (extra := 998783) + (shared := expSharedAfterFreePtr x) + (hlookup := expSharedAfterFreePtr_lookup x) (h1 := h1) (h2 := h2) + simp only [Nat.reduceAdd, FormalYul.word] at hwrap + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.executionEnv, + expSharedAfterFreePtr_weiValue, expSharedAfterFreePtr_calldata, expRayToWad_calldata_size, + GetElem?.getElem!, decidableGetElem?, + EvmYul.Yul.State.instGetElemIdentifierLiteralMemVarStoreStore, + EvmYul.Yul.State.store, + Finmap.lookup_insert, + hdecode, hwrap] + +set_option maxHeartbeats 8000000 in +/-- The same revert, but starting from the exact state the dispatcher hands the external function +(free-pointer `mstore` baked into a `SharedState.mk`, with the extracted `selector` in the store). -/ +theorem external_fun_wrap_expRayToWad_dispatcher_state_revert + (x : Nat) + (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h2 : FormalYul.u256 x < 2 ^ 255) : + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore))) = + .error EvmYul.Yul.Exception.Revert := by + rw [sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr_raw] + exact external_fun_wrap_expRayToWad_calldata_revert (x := x) + (store := Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore)) h1 h2 + +set_option maxHeartbeats 8000000 in +/-- **Supported-range revert.** For any input at or above the supported-range threshold (and below `2^255`), +`expRayToWad` reverts: the EVM run of the `ExpWrapper` returns `.error "revert"`. -/ +theorem run_exp_ray_to_wad_evm_revert + (x : Nat) + (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h2 : FormalYul.u256 x < 2 ^ 255) : + run_exp_ray_to_wad_evm x = .error "revert" := by + have hexec : + EvmYul.Yul.exec 999998 yulContract.dispatcher (.some yulContract) + (stateFor yulContract (FormalYul.calldata selector_expRayToWad [x])) = + .error EvmYul.Yul.Exception.Revert := by + rw [yulContract_dispatcher] + simp +decide [FormalYul.calldata, stateFor, yulDispatcher, + EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', + EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.executionEnv, EvmYul.Yul.State.toMachineState, + FormalYul.word, call_shift_right_224_unsigned_direct] + rw [selectSwitchCase_expRayToWad_sharedFor_mk_raw x] + simp +decide [external_fun_wrap_expRayToWad_dispatcher_state_revert x h1 h2, + EvmYul.Yul.exec.eq_def, EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.multifill'] + have hrun : + runContract yulContract (FormalYul.calldata selector_expRayToWad [x]) 1000000 = + .error "revert" := + runContract_revert_of_exec_revert hexec + unfold run_exp_ray_to_wad_evm FormalYul.callWord FormalYul.call + rw [hrun] + rfl + end ExpYul From c5f0dc14639e27a616efba78ef83eaf3adbb1c40 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 02:54:57 +0200 Subject: [PATCH 011/149] Add exp-formal CI pass and axiom-gated Theorems signpost Theorems.lean restates the supported-range revert theorem (run_exp_ray_to_wad_evm_revert) and runs the axiom gate (#guard_msgs in #print axioms) pinning it to {propext, Classical.choice, Quot.sound}; the root ExpProof.lean imports it so the default lake build covers the whole proof and a stray axiom/sorry breaks the build. exp-formal.yml mirrors ln-formal.yml: regenerate the EVMYulLean artifacts from the compiled ExpWrapper Yul IR, then build the ExpProof package. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .github/workflows/exp-formal.yml | 100 +++++++++++++++++++++ formal/exp/ExpProof/ExpProof.lean | 5 +- formal/exp/ExpProof/ExpProof/Theorems.lean | 37 ++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/exp-formal.yml create mode 100644 formal/exp/ExpProof/ExpProof/Theorems.lean diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml new file mode 100644 index 000000000..ac5ef2cc8 --- /dev/null +++ b/.github/workflows/exp-formal.yml @@ -0,0 +1,100 @@ +name: Exp.sol Formal Check + +on: + push: + branches: + - master + paths: + - src/vendor/Exp.sol + - src/wrappers/ExpWrapper.sol + - formal/exp/** + - formal/yul/** + - foundry.toml + - remappings.txt + - .github/workflows/exp-formal.yml + pull_request: + paths: + - src/vendor/Exp.sol + - src/wrappers/ExpWrapper.sol + - formal/exp/** + - formal/yul/** + - foundry.toml + - remappings.txt + - .github/workflows/exp-formal.yml + +jobs: + exp-formal: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Install pinned Lean toolchain + run: | + curl https://raw.githubusercontent.com/leanprover/elan/917c18d0ad52f649c2603dc8b973f5b9fa5f8f43/elan-init.sh -sSf | sh -s -- -y --default-toolchain none + echo "$HOME/.elan/bin" >> "$GITHUB_PATH" + LEAN_TOOLCHAIN="$(cat formal/exp/ExpProof/lean-toolchain)" + "$HOME/.elan/bin/elan" toolchain install "$LEAN_TOOLCHAIN" + "$HOME/.elan/bin/elan" default "$LEAN_TOOLCHAIN" + + - name: Restore Lean build cache + uses: actions/cache@v4 + with: + path: | + formal/yul/.lake/build + formal/yul/.lake/packages/*/.lake/build + lib/EVMYulLean/.lake/build + formal/exp/ExpProof/.lake/build + key: ${{ runner.os }}-exp-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/exp/ExpProof/lakefile.toml', 'formal/exp/ExpProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/exp/ExpProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} + restore-keys: | + ${{ runner.os }}-exp-formal-lean- + ${{ runner.os }}-formal-lean- + + - name: Install solc 0.8.34 + run: forge build -- src/chains/Mainnet/TakerSubmitted.sol + env: + FOUNDRY_SOLC_VERSION: 0.8.34 + + - name: Fetch Mathlib cache + working-directory: formal/yul + run: | + # Mathlib's `cache get` fetches the ProofWidgets cloud release, then + # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch + # the release and ensure those directories exist before it runs. + lake build proofwidgets:release + mkdir -p \ + .lake/packages/proofwidgets/.lake/build/lib \ + .lake/packages/proofwidgets/.lake/build/ir + lake exe cache get + + - name: Build Yul importer + working-directory: formal/yul + run: lake build FormalYul.Preservation yul_importer + + - name: Generate EVMYulLean artifacts from compiled ExpWrapper Yul IR + run: | + ./formal/yul/generate_from_forge.sh \ + exp \ + src/wrappers/ExpWrapper.sol:ExpWrapper \ + formal/exp/ExpProof/ExpProof/ExpYul.lean \ + 0.8.34 + + - name: Fetch proof dependency cache + working-directory: formal/exp/ExpProof + run: | + # Mathlib's `cache get` fetches the ProofWidgets cloud release, then + # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch + # the release and ensure those directories exist before it runs. + lake build proofwidgets:release + mkdir -p \ + .lake/packages/proofwidgets/.lake/build/lib \ + .lake/packages/proofwidgets/.lake/build/ir + lake exe cache get + + - name: Build Exp proof package + working-directory: formal/exp/ExpProof + run: lake build diff --git a/formal/exp/ExpProof/ExpProof.lean b/formal/exp/ExpProof/ExpProof.lean index 5fa40a040..765a6a62d 100644 --- a/formal/exp/ExpProof/ExpProof.lean +++ b/formal/exp/ExpProof/ExpProof.lean @@ -1 +1,4 @@ -import ExpProof.ExpYulProof +-- This module serves as the root of the `ExpProof` library. +-- `Theorems` is the signpost: it states the proven properties of the compiled +-- runtime and runs the axiom gate, transitively importing the whole proof. +import ExpProof.Theorems diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean new file mode 100644 index 000000000..dd85c03c8 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -0,0 +1,37 @@ +import ExpProof.Seam.Revert + +/-! +# `expRayToWad` — proven properties of the compiled runtime (signpost) + +This file is the at-a-glance demonstration that the documented properties hold for *the +interpretation of the implementation*: the EVMYulLean execution of the compiled `ExpWrapper` Yul, +`run_exp_ray_to_wad_evm` (defined in the generated `ExpYulRuntime`). Each property below is a +runtime-level theorem; the axiom gate at the bottom pins it to Lean's three standard axioms, so a +stray `sorry` (or any new axiom) breaks the build. + +## Documented properties (about the runtime) + +| Property | Theorem | +|-------------------------------------------------|----------------------------------| +| Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1`| `run_exp_ray_to_wad_evm_revert` | + +The supported-range threshold is `0x8e383a2cdfa1b74a9422d2e1`; at or above it (and below `2^255`, +i.e. for any non-negative `int256` that large) the wrapper run halts with `revert`. +-/ + +namespace ExpYul + +open FormalYul + +/-- Reverts above the supported range. -/ +example (x : Nat) + (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h2 : FormalYul.u256 x < 2 ^ 255) : + run_exp_ray_to_wad_evm x = .error "revert" := + run_exp_ray_to_wad_evm_revert x h1 h2 + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_revert' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_revert + +end ExpYul From 2a43c71583b7a37e32190ad1f9eaef16894637d9 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 03:12:26 +0200 Subject: [PATCH 012/149] Reduce the exp value-path functions at the scale point x=0 Seam/Value.lean reduces fun__expRayToWad_80 / fun_expRayToWad_70 / fun_wrap_expRayToWad_99 at x=0 to 10^18: at the scale point every mul-by-x vanishes (k=t=v=0), the rational form is 2^126, and the iszero(0)=1 fix-up lands the result exactly at the wad unit. The overflow guard iszero(slt(0,threshold))=0 is concrete, so the panic branch is skipped without needing a general wordNat_slt. These are the function-level core of zero-input exactness; the ABI .ok dispatcher wrapping is next. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 126 +++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Seam/Value.lean diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean new file mode 100644 index 000000000..22a6224ad --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -0,0 +1,126 @@ +import ExpProof.ExpYulProof +import ExpProof.Seam.RuntimeShared +import ExpProof.Seam.Helpers +import ExpProof.Seam.Dispatcher +import FormalYul.Preservation + +/-! +# Value-path reductions for `expRayToWad` + +The non-reverting branch. This file establishes the scale-point input `x = 0`, where the +kernel collapses to concrete arithmetic and the `iszero(x)` fix-up lands the result exactly at the +wad unit `10^18`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +set_option maxHeartbeats 8000000 in +/-- The kernel `fun__expRayToWad_80` at the scale point `x = 0`: every `mul` by `x` vanishes, so +`k = t = v = 0`, the rational form evaluates to `2^126`, and the final `iszero(0) = 1` fix-up makes +the result exactly `10^18`. -/ +theorem call_fun__expRayToWad_80_zero_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 700)) [FormalYul.word 0] (.some "fun__expRayToWad_80") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 1000000000000000000]) := by + rw [show fuel + (extra + 700) = (fuel + extra) + 700 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun__expRayToWad_80] + simp only [yulFunction_fun__expRayToWad_80, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, + call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 676) + (shared := shared) (hlookup := hlookup)] + +set_option maxHeartbeats 8000000 in +/-- `fun_expRayToWad_70` at `x = 0`: the overflow guard `iszero(slt(0, threshold)) = 0` is false, so +the panic branch is skipped and the kernel result `10^18` is forwarded. -/ +theorem call_fun_expRayToWad_70_zero_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word 0] (.some "fun_expRayToWad_70") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 1000000000000000000]) := by + rw [show fuel + (extra + 900) = (fuel + extra) + 900 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_70] + simp only [yulFunction_fun_expRayToWad_70, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hconv44 := + call_convert_44_to_int256_direct (v := 0x8e383a2cdfa1b74a9422d2e1) (fuel := fuel + extra) (extra := 767) + (shared := shared) (hlookup := hlookup) + have hcleanup := + call_cleanup_t_int256_direct (v := 0) (fuel := fuel + extra) (extra := 865) + (shared := shared) (hlookup := hlookup) + have hkernel := + call_fun__expRayToWad_80_zero_direct (fuel := fuel + extra) (extra := 187) + (shared := shared) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at hconv44 hcleanup hkernel + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, + call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 876) + (shared := shared) (hlookup := hlookup), + hcleanup, hconv44, hkernel] + +set_option maxHeartbeats 8000000 in +/-- `fun_wrap_expRayToWad_99` at `x = 0` forwards to `fun_expRayToWad_70`, giving `10^18`. -/ +theorem call_fun_wrap_expRayToWad_zero_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word 0] (.some "fun_wrap_expRayToWad_99") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 1000000000000000000]) := by + rw [show fuel + (extra + 1100) = (fuel + extra) + 1100 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_expRayToWad] + simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_99, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h70 := + call_fun_expRayToWad_70_zero_direct (fuel := fuel + extra) (extra := 191) + (shared := shared) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at h70 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.revive, EvmYul.Yul.State.setLeave, + EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, + call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 1076) + (shared := shared) (hlookup := hlookup), + h70] + +end ExpYul From 50ab83cb818bf4280951938de9555dcf7e10fe27 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:25:11 +0200 Subject: [PATCH 013/149] Add branch-agnostic allocate/abi_encode directs for the exp value .ok path Adds call_allocate_unbounded_direct and the two abi_encode directs (Nat-indexed value) to Seam/Dispatcher.lean, reusable by the value-path ABI return. The helper lemmas cover the allocation and ABI return encoding sub-calls used by the scale-point value-path reduction. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Seam/Dispatcher.lean | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean b/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean index 95ad19cb4..54d420508 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean @@ -165,6 +165,107 @@ theorem call_abi_decode_tuple_t_int256_of_calldata EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, Finmap.lookup_insert, FormalYul.word, hdecode] +/-- `allocate_unbounded() := mload(64)` — returns the current free pointer. -/ +theorem call_allocate_unbounded_direct + (fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 20) [] (.some "allocate_unbounded") (.some yulContract) + (EvmYul.Yul.State.Ok shared store) = + .ok + ((EvmYul.Yul.State.Ok shared store).setMachineState + (((EvmYul.Yul.State.Ok shared store).toMachineState.mload (FormalYul.word 64)).2), + [((EvmYul.Yul.State.Ok shared store).toMachineState.mload (FormalYul.word 64)).1]) := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_allocate_unbounded] + simp only [yulFunction_allocate_unbounded, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [ + EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +/-- `abi_encode_t_int256_to_t_int256_fromStack(value, pos) := mstore(pos, cleanup(value))`, +specialized to a literal `value = word v` (the only shape the return path needs). -/ +theorem call_abi_encode_t_int256_to_t_int256_fromStack_direct + (v : Nat) (pos : EvmYul.UInt256) (fuel : Nat) (shared : EvmYul.SharedState .Yul) + (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 90) [FormalYul.word v, pos] + (.some "abi_encode_t_int256_to_t_int256_fromStack") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok ((EvmYul.Yul.State.Ok shared store).setMachineState + ((EvmYul.Yul.State.Ok shared store).toMachineState.mstore pos (FormalYul.word v)), []) := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_abi_encode_t_int256_to_t_int256_fromStack] + simp only [yulFunction_abi_encode_t_int256_to_t_int256_fromStack, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hcleanup := + call_cleanup_t_int256_direct (v := v) (fuel := fuel) (extra := 64) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word v) + (Finmap.insert "pos" pos (Inhabited.default : EvmYul.Yul.VarStore))) + (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at hcleanup + simp +decide [EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, hcleanup] + +/-- `abi_encode_tuple_t_int256__to_t_int256__fromStack(headStart, value)` encodes a single `int256` +return value (`value = word v`) and returns the tail pointer `headStart + 32`. -/ +theorem call_abi_encode_tuple_t_int256__to_t_int256__fromStack_direct + (headStart : EvmYul.UInt256) (v : Nat) (fuel : Nat) (shared : EvmYul.SharedState .Yul) + (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 150) [headStart, FormalYul.word v] + (.some "abi_encode_tuple_t_int256__to_t_int256__fromStack") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok ((EvmYul.Yul.State.Ok shared store).setMachineState + ((EvmYul.Yul.State.Ok shared store).toMachineState.mstore headStart (FormalYul.word v)), + [headStart + FormalYul.word 32]) := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_abi_encode_tuple_t_int256__to_t_int256__fromStack] + simp only [yulFunction_abi_encode_tuple_t_int256__to_t_int256__fromStack, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hencode := + call_abi_encode_t_int256_to_t_int256_fromStack_direct + (v := v) (pos := headStart + FormalYul.word 0) (fuel := fuel + 55) + (shared := shared) + (store := Finmap.insert "tail" (headStart + FormalYul.word 32) + (Finmap.insert "headStart" headStart + (Finmap.insert "value0" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)))) + (hlookup := hlookup) + simp [FormalYul.word] at hencode + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, hencode] + /-- `shift_right_224_unsigned(value) := shr(224, value)`. -/ theorem call_shift_right_224_unsigned_direct (v : EvmYul.UInt256) (fuel : Nat) From c6e17518d3ad32e428949f388c19754d6fc6b412 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:26:03 +0200 Subject: [PATCH 014/149] Prove expRayToWad(0) = 1e18 Completes the value path at the scale point x=0 through the ABI .ok dispatcher: run_exp_ray_to_wad_evm_zero : run_exp_ray_to_wad_evm 0 = .ok 1000000000000000000 At x=0 the kernel collapses to concrete arithmetic (k=t=v=0, rational form 2^126) and the iszero(0)=1 fix-up lands exactly 10^18; the guard is skipped (concrete slt), and the external entrypoint ABI-encodes and returns it. Added to the Theorems.lean axiom gate. Axioms: [propext, Classical.choice, Quot.sound]. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 277 +++++++++++++++++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 13 +- 2 files changed, 289 insertions(+), 1 deletion(-) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 22a6224ad..2b4e70f08 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -123,4 +123,281 @@ theorem call_fun_wrap_expRayToWad_zero_direct (shared := shared) (hlookup := hlookup), h70] +set_option maxHeartbeats 12000000 in +/-- The external entrypoint at `x = 0` ABI-encodes and returns `10^18`. -/ +theorem external_fun_wrap_expRayToWad_zero_calldata_result + (store : EvmYul.Yul.VarStore) : + ((match + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr 0) store) + with + | .error (.YulHalt state _) => FormalYul.resultWord (FormalYul.returnOf state) + | .error .Revert => .error "revert" + | .error err => .error (reprStr err) + | .ok (state, _) => FormalYul.resultWord (FormalYul.returnOf state)) : + Except String Nat) = + .ok 1000000000000000000 := by + rw [EvmYul.Yul.call.eq_def] + simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, + lookup_external_fun_wrap_expRayToWad] + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + let baseStore := + Finmap.insert "ret_0" (FormalYul.word 1000000000000000000) + (Finmap.insert "param_0" (FormalYul.word 0) (Inhabited.default : EvmYul.Yul.VarStore)) + let memPos := + ((EvmYul.Yul.State.Ok (expSharedAfterFreePtr 0) baseStore).toMachineState.mload + (FormalYul.word 64)).1 + let memShared := + { expSharedAfterFreePtr 0 with + toMachineState := + ((EvmYul.Yul.State.Ok (expSharedAfterFreePtr 0) baseStore).toMachineState.mload + (FormalYul.word 64)).2 } + let encStore := Finmap.insert "memPos" memPos baseStore + have hdecode := + call_abi_decode_tuple_t_int256_of_calldata (x := 0) (fuel := 0) (extra := 999664) + (shared := expSharedAfterFreePtr 0) + (store := (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := expSharedAfterFreePtr_lookup 0) + (hdata := expSharedAfterFreePtr_calldata 0) + simp only [Nat.reduceAdd, FormalYul.word] at hdecode + have hwrap := + call_fun_wrap_expRayToWad_zero_direct (fuel := 0) (extra := 998883) + (shared := expSharedAfterFreePtr 0) + (store := Finmap.insert "param_0" (FormalYul.word 0) + (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := expSharedAfterFreePtr_lookup 0) + simp only [Nat.reduceAdd, FormalYul.word] at hwrap + have halloc := + call_allocate_unbounded_direct (fuel := 999962) (shared := expSharedAfterFreePtr 0) + (store := baseStore) (hlookup := expSharedAfterFreePtr_lookup 0) + simp only [FormalYul.word, baseStore] at halloc + have hencode := + call_abi_encode_tuple_t_int256__to_t_int256__fromStack_direct + (headStart := memPos) (v := 1000000000000000000) (fuel := 999831) + (shared := memShared) (store := encStore) + (hlookup := by simp [memShared, expSharedAfterFreePtr_lookup 0]) + simp [FormalYul.word, memShared, encStore, memPos, baseStore] at hencode + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.executionEnv, + expSharedAfterFreePtr_weiValue, expSharedAfterFreePtr_calldata, expRayToWad_calldata_size, + GetElem?.getElem!, decidableGetElem?, + EvmYul.Yul.State.instGetElemIdentifierLiteralMemVarStoreStore, + EvmYul.Yul.State.store, + EvmYul.Yul.State.toMachineState, FormalYul.returnOf, + Finmap.lookup_insert, Finmap.lookup_insert_of_ne, + hdecode, hwrap, halloc, hencode, baseStore, memPos, memShared, encStore] + have hmload : + ((expSharedAfterFreePtr 0).mload (EvmYul.UInt256.ofNat 64)).1 = + EvmYul.UInt256.ofNat 128 := by + simpa [FormalYul.word] using expSharedAfterFreePtr_mload64 0 + rw [hmload] + have hretLen : + EvmYul.UInt256.ofNat 128 + EvmYul.UInt256.ofNat 32 - EvmYul.UInt256.ofNat 128 = + FormalYul.word 32 := by decide + rw [hretLen] + rw [FormalYul.Preservation.resultWord_evmReturn_mstore_word] + have hnat : + (EvmYul.UInt256.ofNat 1000000000000000000).toNat = 1000000000000000000 := by + change FormalYul.wordNat (EvmYul.UInt256.ofNat 1000000000000000000) = 1000000000000000000 + exact (FormalYul.Preservation.wordNat_ofNat 1000000000000000000).trans + (FormalYul.Preservation.u256_eq_of_lt _ (by decide)) + rw [hnat] + +set_option maxHeartbeats 12000000 in +/-- The external entrypoint at `x = 0` halts (returns), as opposed to reverting. -/ +theorem external_fun_wrap_expRayToWad_zero_calldata_halts + (store : EvmYul.Yul.VarStore) : + ∃ state value, + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr 0) store) = + .error (.YulHalt state value) := by + rw [EvmYul.Yul.call.eq_def] + simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, + lookup_external_fun_wrap_expRayToWad] + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + let baseStore := + Finmap.insert "ret_0" (FormalYul.word 1000000000000000000) + (Finmap.insert "param_0" (FormalYul.word 0) (Inhabited.default : EvmYul.Yul.VarStore)) + let memPos := + ((EvmYul.Yul.State.Ok (expSharedAfterFreePtr 0) baseStore).toMachineState.mload + (FormalYul.word 64)).1 + let memShared := + { expSharedAfterFreePtr 0 with + toMachineState := + ((EvmYul.Yul.State.Ok (expSharedAfterFreePtr 0) baseStore).toMachineState.mload + (FormalYul.word 64)).2 } + let encStore := Finmap.insert "memPos" memPos baseStore + have hdecode := + call_abi_decode_tuple_t_int256_of_calldata (x := 0) (fuel := 0) (extra := 999664) + (shared := expSharedAfterFreePtr 0) + (store := (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := expSharedAfterFreePtr_lookup 0) + (hdata := expSharedAfterFreePtr_calldata 0) + simp only [Nat.reduceAdd, FormalYul.word] at hdecode + have hwrap := + call_fun_wrap_expRayToWad_zero_direct (fuel := 0) (extra := 998883) + (shared := expSharedAfterFreePtr 0) + (store := Finmap.insert "param_0" (FormalYul.word 0) + (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := expSharedAfterFreePtr_lookup 0) + simp only [Nat.reduceAdd, FormalYul.word] at hwrap + have halloc := + call_allocate_unbounded_direct (fuel := 999962) (shared := expSharedAfterFreePtr 0) + (store := baseStore) (hlookup := expSharedAfterFreePtr_lookup 0) + simp only [FormalYul.word, baseStore] at halloc + have hencode := + call_abi_encode_tuple_t_int256__to_t_int256__fromStack_direct + (headStart := memPos) (v := 1000000000000000000) (fuel := 999831) + (shared := memShared) (store := encStore) + (hlookup := by simp [memShared, expSharedAfterFreePtr_lookup 0]) + simp [FormalYul.word, memShared, encStore, memPos, baseStore] at hencode + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.executionEnv, + expSharedAfterFreePtr_weiValue, expSharedAfterFreePtr_calldata, expRayToWad_calldata_size, + GetElem?.getElem!, decidableGetElem?, + EvmYul.Yul.State.instGetElemIdentifierLiteralMemVarStoreStore, + EvmYul.Yul.State.store, + EvmYul.Yul.State.toMachineState, FormalYul.returnOf, + Finmap.lookup_insert, Finmap.lookup_insert_of_ne, + hdecode, hwrap, halloc, hencode, baseStore, memPos, memShared, encStore] + +set_option maxHeartbeats 12000000 in +/-- Result, starting from the exact state the dispatcher hands the external function. -/ +theorem external_fun_wrap_expRayToWad_zero_dispatcher_state_result : + ((match + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [0])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [0])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [0])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [0])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore))) + with + | .error (.YulHalt state _) => FormalYul.resultWord (FormalYul.returnOf state) + | .error .Revert => .error "revert" + | .error err => .error (reprStr err) + | .ok (state, _) => FormalYul.resultWord (FormalYul.returnOf state)) : + Except String Nat) = + .ok 1000000000000000000 := by + rw [sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr_raw] + exact external_fun_wrap_expRayToWad_zero_calldata_result + (store := Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr 0) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore)) + +set_option maxHeartbeats 12000000 in +/-- Halt, starting from the exact state the dispatcher hands the external function. -/ +theorem external_fun_wrap_expRayToWad_zero_dispatcher_state_halts : + ∃ state value, + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [0])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [0])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [0])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [0])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore))) = + .error (.YulHalt state value) := by + rw [sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr_raw] + exact external_fun_wrap_expRayToWad_zero_calldata_halts + (store := Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr 0) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore)) + +set_option maxHeartbeats 12000000 in +/-- **Zero-input exactness.** `expRayToWad(0)` returns the wad unit `10^18`: the EVM run of the `ExpWrapper` +on input `0` yields `.ok 10^18`. -/ +theorem run_exp_ray_to_wad_evm_zero : + run_exp_ray_to_wad_evm 0 = .ok 1000000000000000000 := by + obtain ⟨haltState, _haltValue, hhalt⟩ := + external_fun_wrap_expRayToWad_zero_dispatcher_state_halts + have hresult := external_fun_wrap_expRayToWad_zero_dispatcher_state_result + rw [hhalt] at hresult + have hReturn : + FormalYul.Preservation.DispatcherReturn yulContract + (FormalYul.calldata selector_expRayToWad [0]) 999998 (FormalYul.returnOf haltState) := by + apply FormalYul.Preservation.dispatcherReturn_of_exec_halt + (hdispatcher := yulContract_dispatcher) + refine ⟨haltState, _haltValue, ?_, rfl⟩ + simp +decide [FormalYul.calldata, FormalYul.stateFor, + yulDispatcher, EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', + EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, + EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, + EvmYul.Yul.State.executionEnv, + EvmYul.Yul.State.toMachineState, + GetElem?.getElem!, decidableGetElem?, + EvmYul.Yul.State.instGetElemIdentifierLiteralMemVarStoreStore, + EvmYul.Yul.State.store, Finmap.lookup_insert, + FormalYul.word, + call_shift_right_224_unsigned_direct] + rw [selectSwitchCase_expRayToWad_sharedFor_mk_raw 0] + simp +decide [hhalt, EvmYul.Yul.exec.eq_def, + EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.multifill'] + unfold run_exp_ray_to_wad_evm + exact FormalYul.Preservation.callWord_ok_of_dispatcherReturn_result_1000000 + (contract := yulContract) (selector := selector_expRayToWad) (args := [0]) + (hReturn := hReturn) (by simpa using hresult) + end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index dd85c03c8..ab3fec600 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -1,4 +1,5 @@ import ExpProof.Seam.Revert +import ExpProof.Seam.Value /-! # `expRayToWad` — proven properties of the compiled runtime (signpost) @@ -14,9 +15,11 @@ stray `sorry` (or any new axiom) breaks the build. | Property | Theorem | |-------------------------------------------------|----------------------------------| | Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1`| `run_exp_ray_to_wad_evm_revert` | +| Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | The supported-range threshold is `0x8e383a2cdfa1b74a9422d2e1`; at or above it (and below `2^255`, -i.e. for any non-negative `int256` that large) the wrapper run halts with `revert`. +i.e. for any non-negative `int256` that large) the wrapper run halts with `revert`. At the scale +point `x = 0` the run returns the wad unit `10^18` exactly. -/ namespace ExpYul @@ -30,8 +33,16 @@ example (x : Nat) run_exp_ray_to_wad_evm x = .error "revert" := run_exp_ray_to_wad_evm_revert x h1 h2 +/-- `expRayToWad(0)` returns the wad unit exactly. -/ +example : run_exp_ray_to_wad_evm 0 = .ok 1000000000000000000 := + run_exp_ray_to_wad_evm_zero + /-- info: 'ExpYul.run_exp_ray_to_wad_evm_revert' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in #print axioms run_exp_ray_to_wad_evm_revert +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_zero' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_zero + end ExpYul From 0d1618f8abb5976b8376989f0acafd0e6a07f13c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:26:34 +0200 Subject: [PATCH 015/149] Prove the wordNat_slt bridge for the general exp kernel reduction Adds wordNat_slt (wordNat (UInt256.slt a b) = evmSlt (wordNat a) (wordNat b)) and the evmSlt_u256 absorbers to Seam/RuntimeShared.lean. evmSlt already existed in FormalYul/Word.lean; this is the missing wordNat-preservation bridge, proven via a 4-way sign case-split on the excess-2^255 offset comparison. Prerequisite for the symbolic-x kernel reduction used by the runtime floor and monotonicity claims. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Seam/RuntimeShared.lean | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean b/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean index 266914635..e57aa8f25 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean @@ -191,6 +191,54 @@ theorem wordNat_sdiv (a b : EvmYul.UInt256) : intro hq split_ifs <;> omega +theorem wordNat_slt (a b : EvmYul.UInt256) : + wordNat (EvmYul.UInt256.slt a b) = evmSlt (wordNat a) (wordNat b) := by + have ha : a.toNat < 2 ^ 256 := by simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size] + have hb : b.toNat < 2 ^ 256 := by simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size] + have hua : u256 (wordNat a) = wordNat a := by unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt ha + have hub : u256 (wordNat b) = wordNat b := by unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt hb + have hlt2 : (a < b) ↔ (a.toNat < b.toNat) := Iff.rfl + -- Offset (excess-2^255) values of the two operands, in closed form per sign. + have offneg : ∀ c : Nat, c < 2 ^ 256 → 2 ^ 255 ≤ c → + (c + 2 ^ 255) % 2 ^ 256 = c - 2 ^ 255 := by + intro c hc hcn + rw [show c + 2 ^ 255 = (c - 2 ^ 255) + 2 ^ 256 by omega, Nat.add_mod_right, + Nat.mod_eq_of_lt (by omega)] + have offpos : ∀ c : Nat, c < 2 ^ 256 → c < 2 ^ 255 → + (c + 2 ^ 255) % 2 ^ 256 = c + 2 ^ 255 := by + intro c hc hcp; exact Nat.mod_eq_of_lt (by omega) + have key : EvmYul.UInt256.sltBool a b = + decide ((a.toNat + 2 ^ 255) % 2 ^ 256 < (b.toNat + 2 ^ 255) % 2 ^ 256) := by + unfold EvmYul.UInt256.sltBool + simp only [ge_iff_le] + by_cases hna : 2 ^ 255 ≤ a.toNat <;> by_cases hnb : 2 ^ 255 ≤ b.toNat + · rw [if_pos hna, if_pos hnb, offneg _ ha hna, offneg _ hb hnb] + apply decide_eq_decide.mpr; rw [hlt2]; omega + · rw [if_pos hna, if_neg hnb, offneg _ ha hna, offpos _ hb (by omega), eq_comm, + decide_eq_true_eq]; omega + · rw [if_neg hna, if_pos hnb, offpos _ ha (by omega), offneg _ hb hnb, eq_comm, + decide_eq_false_iff_not]; omega + · rw [if_neg hna, if_neg hnb, offpos _ ha (by omega), offpos _ hb (by omega)] + apply decide_eq_decide.mpr; rw [hlt2]; omega + have hLHS : wordNat (EvmYul.UInt256.slt a b) = + if (a.toNat + 2 ^ 255) % 2 ^ 256 < (b.toNat + 2 ^ 255) % 2 ^ 256 then 1 else 0 := by + unfold EvmYul.UInt256.slt + rw [key] + simp only [EvmYul.fromBool, Bool.toUInt256, decide_eq_true_eq] + split_ifs <;> decide + have hua' : u256 (wordNat a) = a.toNat := hua + have hub' : u256 (wordNat b) = b.toNat := hub + have hRHS : evmSlt (wordNat a) (wordNat b) = + if (a.toNat + 2 ^ 255) % 2 ^ 256 < (b.toNat + 2 ^ 255) % 2 ^ 256 then 1 else 0 := by + unfold evmSlt + rw [hua', hub', word_mod_eq] + rw [hLHS, hRHS] + +theorem evmSlt_u256_left (a b : Nat) : evmSlt (u256 a) b = evmSlt a b := by + simp only [evmSlt, u256_idem] +theorem evmSlt_u256_right (a b : Nat) : evmSlt a (u256 b) = evmSlt a b := by + simp only [evmSlt, u256_idem] + theorem evmSar_u256_left (s v : Nat) : evmSar (u256 s) v = evmSar s v := by simp only [evmSar, u256_idem] theorem evmSar_u256_right (s v : Nat) : evmSar s (u256 v) = evmSar s v := by From 8c7ca7dc549fc5b410c5f240041b4e8e5a1d4489 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:27:25 +0200 Subject: [PATCH 016/149] Reduce the general exp kernel to the evm* tree (symbolic x) call_fun__expRayToWad_80_direct reduces fun__expRayToWad_80(x) to the inline let-shared evm* arithmetic tree (transcribed from Exp.sol _expRayToWad, no hand model) via eq_of_wordNat_eq + the wordNat_*/evm*_u256 bridges (incl. the new wordNat_slt). The foundation for the runtime floor and monotonicity claims. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 64 ++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 2b4e70f08..96d937a7f 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -400,4 +400,68 @@ theorem run_exp_ray_to_wad_evm_zero : (contract := yulContract) (selector := selector_expRayToWad) (args := [0]) (hReturn := hReturn) (by simpa using hresult) +set_option maxHeartbeats 4000000 in +/-- General kernel reduction for symbolic `x`: `fun__expRayToWad_80(x)` evaluates to the inline, +`let`-shared `evm*` arithmetic tree transcribed from `Exp.sol`'s `_expRayToWad` (constants are the +literal hex). No hand model: the RHS is the interpreter's own `evm*` ops. The foundation for +the runtime floor and monotonicity claims. -/ +theorem call_fun__expRayToWad_80_direct + (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 700)) [FormalYul.word x] (.some "fun__expRayToWad_80") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( + let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) + let v := evmShr 0x80 (evmMul t t) + let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let tod := evmSar 0x80 (evmMul t od) + let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + evmAdd (evmIszero x) + (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + )]) := by + rw [show fuel + (extra + 700) = (fuel + extra) + 700 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun__expRayToWad_80] + simp only [yulFunction_fun__expRayToWad_80, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, + call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 676) + (shared := shared) (hlookup := hlookup)] + apply FormalYul.Preservation.eq_of_wordNat_eq + simp only [FormalYul.Preservation.wordNat_shiftRight, FormalYul.Preservation.wordNat_shiftLeft, + FormalYul.Preservation.wordNat_add, FormalYul.Preservation.wordNat_sub, + FormalYul.Preservation.wordNat_mul, FormalYul.Preservation.wordNat_iszero, + FormalYul.Preservation.wordNat_ofNat, wordNat_sar, wordNat_sdiv, wordNat_slt] + simp only [FormalYul.Preservation.evmAdd_u256_left, FormalYul.Preservation.evmAdd_u256_right, + FormalYul.Preservation.evmSub_u256_left, FormalYul.Preservation.evmSub_u256_right, + FormalYul.Preservation.evmMul_u256_left, FormalYul.Preservation.evmMul_u256_right, + FormalYul.Preservation.evmShl_u256_left, FormalYul.Preservation.evmShl_u256_right, + FormalYul.Preservation.evmShr_u256_left, FormalYul.Preservation.evmShr_u256_right, + FormalYul.Preservation.evmIszero_u256, evmSar_u256_left, evmSar_u256_right, + evmSdiv_u256_left, evmSdiv_u256_right, evmSlt_u256_left, evmSlt_u256_right, + u256_idem, FormalYul.Preservation.u256_evmAdd] + end ExpYul From 568099f9b93a9157893abae81f860cc6e2b13998 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 04:45:57 +0200 Subject: [PATCH 017/149] Add the slt_thresh_lt guard-skip sibling for the exp value path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit slt(x, threshold) = 1 for signed x < threshold (either negative, or nonnegative below the threshold) — the complement of slt_thresh_ge. Lets the value-path fun_expRayToWad_70 reduction skip the panic branch. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Seam/Guard.lean | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean index 5ebad267e..f3d0d8659 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean @@ -46,4 +46,33 @@ theorem slt_thresh_ge {x : Nat} rw [hx, hC]; omega simp [EvmYul.UInt256.fromBool, hnlt] +/-- The overflow guard `slt(x, C)` is the word `1` for a signed input strictly below the threshold +(`x` either a negative signed value, `2^255 ≤ u256 x`, or a nonnegative value below `C`), so +`iszero(slt(x, C))` is `0` and the panic branch is skipped (value path). -/ +theorem slt_thresh_lt {x : Nat} + (hval : u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ u256 x) : + EvmYul.UInt256.slt (EvmYul.UInt256.ofNat x) + (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1) + = EvmYul.UInt256.ofNat 1 := by + have hx : (EvmYul.UInt256.ofNat x).toNat = u256 x := by + have := wordNat_ofNat x; simpa [wordNat] using this + have hC : (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1).toNat + = 0x8e383a2cdfa1b74a9422d2e1 := by + have := wordNat_ofNat 0x8e383a2cdfa1b74a9422d2e1 + simpa [wordNat, u256, WORD_MOD] using this + have hCb : (0x8e383a2cdfa1b74a9422d2e1 : Nat) < 2 ^ 255 := thresh_lt_pow + unfold EvmYul.UInt256.slt EvmYul.UInt256.sltBool + rw [hx, hC] + rw [if_neg (by omega : ¬ ((0x8e383a2cdfa1b74a9422d2e1 : Nat) ≥ 2 ^ 255))] + rcases hval with hlt | hneg + · rw [if_neg (by omega : ¬ (u256 x ≥ 2 ^ 255))] + have hlt' : EvmYul.UInt256.ofNat x + < EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1 := by + show (EvmYul.UInt256.ofNat x).toNat + < (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1).toNat + rw [hx, hC]; omega + simp [EvmYul.UInt256.fromBool, hlt'] + · rw [if_pos (by omega : u256 x ≥ 2 ^ 255)] + simp [EvmYul.UInt256.fromBool] + end ExpYul From 3a07533d4507055621d865d371545ea08cc3fe5c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 04:53:16 +0200 Subject: [PATCH 018/149] Prove the exp value-path function chain returns the evm* tree (symbolic x) call_fun_expRayToWad_70_direct (guard skipped via slt_thresh_lt) and call_fun_wrap_expRayToWad_direct forward the kernel evm* tree for any signed input below the threshold (u256 x < 0x8e3...2e1 or 2^255 <= u256 x). Completes the function-level value path (kernel -> 70 -> wrap), all returning the inline tree. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 120 +++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 96d937a7f..26d5e0303 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -1,6 +1,7 @@ import ExpProof.ExpYulProof import ExpProof.Seam.RuntimeShared import ExpProof.Seam.Helpers +import ExpProof.Seam.Guard import ExpProof.Seam.Dispatcher import FormalYul.Preservation @@ -464,4 +465,123 @@ theorem call_fun__expRayToWad_80_direct evmSdiv_u256_left, evmSdiv_u256_right, evmSlt_u256_left, evmSlt_u256_right, u256_idem, FormalYul.Preservation.u256_evmAdd] +set_option maxHeartbeats 4000000 in +/-- `fun_expRayToWad_70(x)` for a signed input strictly below the threshold: the overflow guard +`iszero(slt(x, C)) = 0` is skipped (via `slt_thresh_lt`), so the kernel result — the `evm*` tree — +is forwarded. -/ +theorem call_fun_expRayToWad_70_direct + (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) + (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word x] (.some "fun_expRayToWad_70") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( + let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) + let v := evmShr 0x80 (evmMul t t) + let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let tod := evmSar 0x80 (evmMul t od) + let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + evmAdd (evmIszero x) + (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + )]) := by + rw [show fuel + (extra + 900) = (fuel + extra) + 900 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_70] + simp only [yulFunction_fun_expRayToWad_70, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hconv44 := + call_convert_44_to_int256_direct (v := 0x8e383a2cdfa1b74a9422d2e1) (fuel := fuel + extra) (extra := 767) + (shared := shared) (hlookup := hlookup) + have hcleanup := + call_cleanup_t_int256_direct (v := x) (fuel := fuel + extra) (extra := 865) + (shared := shared) (hlookup := hlookup) + have hkernel := + call_fun__expRayToWad_80_direct (x := x) (fuel := fuel + extra) (extra := 187) + (shared := shared) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at hconv44 hcleanup hkernel + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, + slt_thresh_lt hval, + call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 876) + (shared := shared) (hlookup := hlookup), + hcleanup, hconv44, hkernel] + +set_option maxHeartbeats 4000000 in +/-- `fun_wrap_expRayToWad_99(x)` for a signed input below the threshold forwards to +`fun_expRayToWad_70`, returning the `evm*` tree. -/ +theorem call_fun_wrap_expRayToWad_direct + (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) + (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_99") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( + let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) + let v := evmShr 0x80 (evmMul t t) + let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let tod := evmSar 0x80 (evmMul t od) + let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + evmAdd (evmIszero x) + (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + )]) := by + rw [show fuel + (extra + 1100) = (fuel + extra) + 1100 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_expRayToWad] + simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_99, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h70 := + call_fun_expRayToWad_70_direct (x := x) (fuel := fuel + extra) (extra := 191) + (shared := shared) (hlookup := hlookup) (hval := hval) + simp only [Nat.reduceAdd, FormalYul.word] at h70 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.revive, EvmYul.Yul.State.setLeave, + EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, + call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 1076) + (shared := shared) (hlookup := hlookup), + h70] + end ExpYul From 2a70ec2dbfbc28d908e5547fa9a1fdfec6ca0633 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:28:36 +0200 Subject: [PATCH 019/149] Reduce the exp run-level value path to the evm* tree run_exp_ray_to_wad_evm_eq_tree : for signed x below the threshold, run_exp_ray_to_wad_evm x = .ok (the inline evm* arithmetic tree). Value-preserving mirror of run_exp_ray_to_wad_evm_zero through the ABI dispatcher, threading hval into the wrapper. Adds the generic RuntimeShared.toNat_ofNat_evmAdd helper. In the Theorems.lean axiom gate. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Seam/RuntimeShared.lean | 9 + formal/exp/ExpProof/ExpProof/Seam/Value.lean | 385 ++++++++++++++++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 9 +- 3 files changed, 402 insertions(+), 1 deletion(-) diff --git a/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean b/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean index e57aa8f25..2688adb06 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean @@ -234,6 +234,15 @@ theorem wordNat_slt (a b : EvmYul.UInt256) : rw [hua', hub', word_mod_eq] rw [hLHS, hRHS] +/-- An `evmAdd` result is already `u256`-wrapped, so injecting it through `ofNat` and reading its +`toNat` is the identity. Discharges the run-level `resultWord` extraction without re-stating the +evm* tree. -/ +theorem toNat_ofNat_evmAdd (a b : Nat) : + (EvmYul.UInt256.ofNat (evmAdd a b)).toNat = evmAdd a b := by + change wordNat (EvmYul.UInt256.ofNat (evmAdd a b)) = evmAdd a b + rw [FormalYul.Preservation.wordNat_ofNat] + exact FormalYul.Preservation.u256_evmAdd a b + theorem evmSlt_u256_left (a b : Nat) : evmSlt (u256 a) b = evmSlt a b := by simp only [evmSlt, u256_idem] theorem evmSlt_u256_right (a b : Nat) : evmSlt a (u256 b) = evmSlt a b := by diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 26d5e0303..25d653398 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -584,4 +584,389 @@ theorem call_fun_wrap_expRayToWad_direct (shared := shared) (hlookup := hlookup), h70] +set_option maxHeartbeats 16000000 in +/-- The external entrypoint for a signed input below the threshold ABI-encodes and returns the +`evm*` tree. -/ +theorem external_fun_wrap_expRayToWad_calldata_result + (x : Nat) (store : EvmYul.Yul.VarStore) + (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + ((match + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) + with + | .error (.YulHalt state _) => FormalYul.resultWord (FormalYul.returnOf state) + | .error .Revert => .error "revert" + | .error err => .error (reprStr err) + | .ok (state, _) => FormalYul.resultWord (FormalYul.returnOf state)) : + Except String Nat) = + .ok ( + let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) + let v := evmShr 0x80 (evmMul t t) + let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let tod := evmSar 0x80 (evmMul t od) + let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + evmAdd (evmIszero x) + (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + ) := by + rw [EvmYul.Yul.call.eq_def] + simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, + lookup_external_fun_wrap_expRayToWad] + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + set tree : Nat := + (let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) + let v := evmShr 0x80 (evmMul t t) + let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let tod := evmSar 0x80 (evmMul t od) + let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + evmAdd (evmIszero x) + (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) + with htree + let baseStore := + Finmap.insert "ret_0" (FormalYul.word tree) + (Finmap.insert "param_0" (FormalYul.word x) (Inhabited.default : EvmYul.Yul.VarStore)) + let memPos := + ((EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) baseStore).toMachineState.mload + (FormalYul.word 64)).1 + let memShared := + { expSharedAfterFreePtr x with + toMachineState := + ((EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) baseStore).toMachineState.mload + (FormalYul.word 64)).2 } + let encStore := Finmap.insert "memPos" memPos baseStore + have hdecode := + call_abi_decode_tuple_t_int256_of_calldata (x := x) (fuel := 0) (extra := 999664) + (shared := expSharedAfterFreePtr x) + (store := (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := expSharedAfterFreePtr_lookup x) + (hdata := expSharedAfterFreePtr_calldata x) + simp only [Nat.reduceAdd, FormalYul.word] at hdecode + have hwrap := + call_fun_wrap_expRayToWad_direct (x := x) (fuel := 0) (extra := 998883) + (shared := expSharedAfterFreePtr x) + (store := Finmap.insert "param_0" (FormalYul.word x) + (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := expSharedAfterFreePtr_lookup x) (hval := hval) + simp only [Nat.reduceAdd, FormalYul.word, ← htree] at hwrap + have halloc := + call_allocate_unbounded_direct (fuel := 999962) (shared := expSharedAfterFreePtr x) + (store := baseStore) (hlookup := expSharedAfterFreePtr_lookup x) + simp only [FormalYul.word, baseStore] at halloc + have hencode := + call_abi_encode_tuple_t_int256__to_t_int256__fromStack_direct + (headStart := memPos) (v := tree) (fuel := 999831) + (shared := memShared) (store := encStore) + (hlookup := by simp [memShared, expSharedAfterFreePtr_lookup x]) + simp [FormalYul.word, memShared, encStore, memPos, baseStore] at hencode + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.executionEnv, + expSharedAfterFreePtr_weiValue, expSharedAfterFreePtr_calldata, expRayToWad_calldata_size, + GetElem?.getElem!, decidableGetElem?, + EvmYul.Yul.State.instGetElemIdentifierLiteralMemVarStoreStore, + EvmYul.Yul.State.store, + EvmYul.Yul.State.toMachineState, FormalYul.returnOf, + Finmap.lookup_insert, Finmap.lookup_insert_of_ne, + hdecode, hwrap, halloc, hencode, baseStore, memPos, memShared, encStore] + have hmload : + ((expSharedAfterFreePtr x).mload (EvmYul.UInt256.ofNat 64)).1 = + EvmYul.UInt256.ofNat 128 := by + simpa [FormalYul.word] using expSharedAfterFreePtr_mload64 x + rw [hmload] + have hretLen : + EvmYul.UInt256.ofNat 128 + EvmYul.UInt256.ofNat 32 - EvmYul.UInt256.ofNat 128 = + FormalYul.word 32 := by decide + rw [hretLen] + rw [FormalYul.Preservation.resultWord_evmReturn_mstore_word] + rw [htree] + exact congrArg _ (toNat_ofNat_evmAdd _ _) + +set_option maxHeartbeats 16000000 in +/-- The external entrypoint halts (returns) for a signed input below the threshold. -/ +theorem external_fun_wrap_expRayToWad_calldata_halts + (x : Nat) (store : EvmYul.Yul.VarStore) + (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + ∃ state value, + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) = + .error (.YulHalt state value) := by + rw [EvmYul.Yul.call.eq_def] + simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, + lookup_external_fun_wrap_expRayToWad] + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + set tree : Nat := + (let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) + let v := evmShr 0x80 (evmMul t t) + let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let tod := evmSar 0x80 (evmMul t od) + let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + evmAdd (evmIszero x) + (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) + with htree + let baseStore := + Finmap.insert "ret_0" (FormalYul.word tree) + (Finmap.insert "param_0" (FormalYul.word x) (Inhabited.default : EvmYul.Yul.VarStore)) + let memPos := + ((EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) baseStore).toMachineState.mload + (FormalYul.word 64)).1 + let memShared := + { expSharedAfterFreePtr x with + toMachineState := + ((EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) baseStore).toMachineState.mload + (FormalYul.word 64)).2 } + let encStore := Finmap.insert "memPos" memPos baseStore + have hdecode := + call_abi_decode_tuple_t_int256_of_calldata (x := x) (fuel := 0) (extra := 999664) + (shared := expSharedAfterFreePtr x) + (store := (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := expSharedAfterFreePtr_lookup x) + (hdata := expSharedAfterFreePtr_calldata x) + simp only [Nat.reduceAdd, FormalYul.word] at hdecode + have hwrap := + call_fun_wrap_expRayToWad_direct (x := x) (fuel := 0) (extra := 998883) + (shared := expSharedAfterFreePtr x) + (store := Finmap.insert "param_0" (FormalYul.word x) + (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := expSharedAfterFreePtr_lookup x) (hval := hval) + simp only [Nat.reduceAdd, FormalYul.word, ← htree] at hwrap + have halloc := + call_allocate_unbounded_direct (fuel := 999962) (shared := expSharedAfterFreePtr x) + (store := baseStore) (hlookup := expSharedAfterFreePtr_lookup x) + simp only [FormalYul.word, baseStore] at halloc + have hencode := + call_abi_encode_tuple_t_int256__to_t_int256__fromStack_direct + (headStart := memPos) (v := tree) (fuel := 999831) + (shared := memShared) (store := encStore) + (hlookup := by simp [memShared, expSharedAfterFreePtr_lookup x]) + simp [FormalYul.word, memShared, encStore, memPos, baseStore] at hencode + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.executionEnv, + expSharedAfterFreePtr_weiValue, expSharedAfterFreePtr_calldata, expRayToWad_calldata_size, + GetElem?.getElem!, decidableGetElem?, + EvmYul.Yul.State.instGetElemIdentifierLiteralMemVarStoreStore, + EvmYul.Yul.State.store, + EvmYul.Yul.State.toMachineState, + Finmap.lookup_insert, Finmap.lookup_insert_of_ne, + hdecode, hwrap, halloc, hencode, baseStore, memPos, memShared, encStore] + +set_option maxHeartbeats 16000000 in +/-- Result from the dispatcher-handed state. -/ +theorem external_fun_wrap_expRayToWad_dispatcher_state_result + (x : Nat) + (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + ((match + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore))) + with + | .error (.YulHalt state _) => FormalYul.resultWord (FormalYul.returnOf state) + | .error .Revert => .error "revert" + | .error err => .error (reprStr err) + | .ok (state, _) => FormalYul.resultWord (FormalYul.returnOf state)) : + Except String Nat) = + .ok ( + let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) + let v := evmShr 0x80 (evmMul t t) + let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let tod := evmSar 0x80 (evmMul t od) + let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + evmAdd (evmIszero x) + (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + ) := by + rw [sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr_raw] + exact external_fun_wrap_expRayToWad_calldata_result (x := x) + (store := Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore)) hval + +set_option maxHeartbeats 16000000 in +/-- Halt from the dispatcher-handed state. -/ +theorem external_fun_wrap_expRayToWad_dispatcher_state_halts + (x : Nat) + (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + ∃ state value, + EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok + (EvmYul.SharedState.mk + (FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).toState + ((FormalYul.sharedFor yulContract + (selector_expRayToWad ++ FormalYul.encodeWords [x])).mstore + (EvmYul.UInt256.ofNat 64) (EvmYul.UInt256.ofNat 128))) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore))) = + .error (.YulHalt state value) := by + rw [sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr_raw] + exact external_fun_wrap_expRayToWad_calldata_halts (x := x) + (store := Finmap.insert "selector" + (EvmYul.UInt256.shiftRight + (EvmYul.State.calldataload + (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) + (Inhabited.default : EvmYul.Yul.VarStore)).toState + (EvmYul.UInt256.ofNat 0)) + (EvmYul.UInt256.ofNat 224)) + (Inhabited.default : EvmYul.Yul.VarStore)) hval + +set_option maxHeartbeats 16000000 in +/-- **Value path.** For any signed input strictly below the supported-range threshold, +`run_exp_ray_to_wad_evm x` returns the `evm*` arithmetic tree ``. The handle for +the runtime floor and monotonicity claims at the run level. -/ +theorem run_exp_ray_to_wad_evm_eq_tree + (x : Nat) + (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + run_exp_ray_to_wad_evm x = .ok ( + let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) + let v := evmShr 0x80 (evmMul t t) + let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let tod := evmSar 0x80 (evmMul t od) + let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + evmAdd (evmIszero x) + (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + ) := by + obtain ⟨haltState, _haltValue, hhalt⟩ := + external_fun_wrap_expRayToWad_dispatcher_state_halts x hval + have hresult := external_fun_wrap_expRayToWad_dispatcher_state_result x hval + rw [hhalt] at hresult + have hReturn : + FormalYul.Preservation.DispatcherReturn yulContract + (FormalYul.calldata selector_expRayToWad [x]) 999998 (FormalYul.returnOf haltState) := by + apply FormalYul.Preservation.dispatcherReturn_of_exec_halt + (hdispatcher := yulContract_dispatcher) + refine ⟨haltState, _haltValue, ?_, rfl⟩ + simp +decide [FormalYul.calldata, FormalYul.stateFor, + yulDispatcher, EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', + EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, + EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, + EvmYul.Yul.State.executionEnv, + EvmYul.Yul.State.toMachineState, + GetElem?.getElem!, decidableGetElem?, + EvmYul.Yul.State.instGetElemIdentifierLiteralMemVarStoreStore, + EvmYul.Yul.State.store, Finmap.lookup_insert, + FormalYul.word, + call_shift_right_224_unsigned_direct] + rw [selectSwitchCase_expRayToWad_sharedFor_mk_raw x] + simp +decide [hhalt, EvmYul.Yul.exec.eq_def, + EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.multifill'] + unfold run_exp_ray_to_wad_evm + exact FormalYul.Preservation.callWord_ok_of_dispatcherReturn_result_1000000 + (contract := yulContract) (selector := selector_expRayToWad) (args := [x]) + (hReturn := hReturn) (by simpa using hresult) + end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index ab3fec600..953ad6a6f 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -16,10 +16,13 @@ stray `sorry` (or any new axiom) breaks the build. |-------------------------------------------------|----------------------------------| | Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1`| `run_exp_ray_to_wad_evm_revert` | | Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | +| Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | The supported-range threshold is `0x8e383a2cdfa1b74a9422d2e1`; at or above it (and below `2^255`, i.e. for any non-negative `int256` that large) the wrapper run halts with `revert`. At the scale -point `x = 0` the run returns the wad unit `10^18` exactly. +point `x = 0` the run returns the wad unit `10^18` exactly. For any signed input strictly below the +threshold the run returns the inline `evm*` arithmetic tree (the handle for the floor/monotone/bound +properties), reduced with no hand model. -/ namespace ExpYul @@ -45,4 +48,8 @@ example : run_exp_ray_to_wad_evm 0 = .ok 1000000000000000000 := #guard_msgs in #print axioms run_exp_ray_to_wad_evm_zero +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_eq_tree' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_eq_tree + end ExpYul From 6c43f9c8514a3dea22d3bb034617d105ac52c0fc Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 05:44:02 +0200 Subject: [PATCH 020/149] Add the word-level transport foundation for exp monotonicity (Mono/WordMono) Ports the contract-agnostic int256 floor/division/shift transports the exp monotonicity argument needs into the ExpYul namespace: a general evmSar floor sandwich (arbitrary shift), evmSdiv sign-pinned transports, evmShr/evmShl in-range identities, cross-multiplied division monotonicity, and Int multiplication-monotonicity helpers. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- .../exp/ExpProof/ExpProof/Mono/WordMono.lean | 365 ++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/WordMono.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean b/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean new file mode 100644 index 000000000..40621c4a3 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean @@ -0,0 +1,365 @@ +import ExpProof.Seam.RuntimeShared + +/-! +# Word-level monotonicity and transport lemmas for the `exp` tree + +The `exp` monotonicity argument reasons about `` (an `evm*` Nat expression) through its +two's-complement signed view `int256`. This file collects the contract-agnostic facts the +argument needs that the shared `FormalYul.Preservation` does not already provide: + +* general floor sandwiches for `evmSar`/`evmShr` (the arithmetic/logical right shifts), at an + arbitrary shift amount, expressed against the signed value; +* the `evmSdiv` sign-pinned transports (one per sign pattern, quotients over `Int.toNat` + magnitudes); +* cross-multiplied monotonicity of truncated division; +* small `Int` multiplication-monotonicity helpers. + +`FormalYul.Preservation` already supplies the `int256` transports for `add`/`sub`/`mul` and the +`int256`/`uint256OfInt` round-trips, so those are used directly. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-! ## Power numerals as `Int` (for `omega`) -/ + +theorem ipow256 : + (2 : Int) ^ 256 = + 115792089237316195423570985008687907853269984665640564039457584007913129639936 := by + norm_num + +theorem ipow255 : + (2 : Int) ^ 255 = + 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by + norm_num + +/-! ## `Int` multiplication-monotonicity helpers -/ + +theorem mul_le_mul_right_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : a * c ≤ b * c := + Int.mul_le_mul_of_nonneg_right h hc + +theorem mul_le_mul_left_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : c * a ≤ c * b := + Int.mul_le_mul_of_nonneg_left h hc + +/-- Cancellation of a positive literal factor. -/ +theorem le_of_mul_le_mul_pos {a b c : Int} (h : a * c ≤ b * c) (hc : 0 < c) : a ≤ b := by + rcases Int.lt_or_le b a with hlt | hle + · exfalso + have := Int.mul_lt_mul_of_pos_right hlt hc + omega + · exact hle + +/-! ## Magnitude bounds and the signed-`u256` conversions -/ + +theorem u256_of_lt {w : Nat} (h : w < 2 ^ 256) : u256 w = w := u256_of_lt_pow256 h + +theorem toInt_lt {w : Nat} (h : w < 2 ^ 256) : int256 w < 2 ^ 255 := int256_lt h +theorem toInt_ge {w : Nat} (h : w < 2 ^ 256) : -(2 ^ 255) ≤ int256 w := int256_ge h +theorem toInt_of_lt {w : Nat} (h : w < 2 ^ 255) : int256 w = (w : Int) := int256_of_lt h +theorem ofInt_lt (x : Int) : uint256OfInt x < 2 ^ 256 := uint256OfInt_lt x +theorem toInt_ofInt {x : Int} (h1 : -(2 ^ 255) ≤ x) (h2 : x < 2 ^ 255) : + int256 (uint256OfInt x) = x := int256_uint256OfInt h1 h2 + +theorem evmAdd_lt (a b : Nat) : evmAdd a b < 2 ^ 256 := evmAdd_lt_pow256 a b +theorem evmSub_lt (a b : Nat) : evmSub a b < 2 ^ 256 := evmSub_lt_pow256 a b +theorem evmMul_lt (a b : Nat) : evmMul a b < 2 ^ 256 := evmMul_lt_pow256 a b + +theorem pow256_pos : (0 : Nat) < 2 ^ 256 := Nat.two_pow_pos 256 + +theorem evmShr_lt (s w : Nat) : evmShr s w < 2 ^ 256 := by + unfold evmShr u256 + simp only [word_mod_eq] + have hv : w % 2 ^ 256 < 2 ^ 256 := Nat.mod_lt _ pow256_pos + split + · exact Nat.lt_of_le_of_lt (Nat.div_le_self _ _) hv + · exact pow256_pos + +theorem evmShl_lt (s w : Nat) : evmShl s w < 2 ^ 256 := by + unfold evmShl u256 + simp only [word_mod_eq] + split + · exact Nat.mod_lt _ pow256_pos + · exact pow256_pos + +theorem evmSar_lt (s w : Nat) : evmSar s w < 2 ^ 256 := by + unfold evmSar u256 + simp only [word_mod_eq] + have hv : w % 2 ^ 256 < 2 ^ 256 := Nat.mod_lt _ pow256_pos + have hsub : ∀ X : Nat, 2 ^ 256 - 1 - X < 2 ^ 256 := fun X => + Nat.lt_of_le_of_lt (Nat.sub_le _ _) (by omega) + have hsub1 : (2 ^ 256 - 1 : Nat) < 2 ^ 256 := by omega + have hdiv : w % 2 ^ 256 / 2 ^ (s % 2 ^ 256) < 2 ^ 256 := + Nat.lt_of_le_of_lt (Nat.div_le_self _ _) hv + repeat' split + · exact hsub1 + · exact hsub _ + · exact pow256_pos + · exact hdiv + +theorem evmSdiv_lt (a b : Nat) : evmSdiv a b < 2 ^ 256 := by + unfold evmSdiv u256 + simp only [word_mod_eq] + have ha : a % 2 ^ 256 < 2 ^ 256 := Nat.mod_lt _ pow256_pos + have hb : b % 2 ^ 256 < 2 ^ 256 := Nat.mod_lt _ pow256_pos + repeat' split + all_goals (first | exact Nat.mod_lt _ pow256_pos | omega) + +/-! ## Re-export of the `add`/`sub`/`mul` transports under short names -/ + +theorem evmAdd_transport {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) + (h1 : -(2 ^ 255) ≤ int256 a + int256 b) (h2 : int256 a + int256 b < 2 ^ 255) : + int256 (evmAdd a b) = int256 a + int256 b := evmAdd_int256 ha hb h1 h2 + +theorem evmSub_transport {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) + (h1 : -(2 ^ 255) ≤ int256 a - int256 b) (h2 : int256 a - int256 b < 2 ^ 255) : + int256 (evmSub a b) = int256 a - int256 b := evmSub_int256 ha hb h1 h2 + +theorem evmMul_transport {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) + (h1 : -(2 ^ 255) ≤ int256 a * int256 b) (h2 : int256 a * int256 b < 2 ^ 255) : + int256 (evmMul a b) = int256 a * int256 b := evmMul_int256 ha hb h1 h2 + +/-! ## `evmShr` as floor division for in-range nonnegative operands -/ + +theorem evmShr_eq_div {s : Nat} (hs : s < 256) {w : Nat} (h : w < 2 ^ 256) : + evmShr s w = w / 2 ^ s := by + have hwm : w % 2 ^ 256 = w := Nat.mod_eq_of_lt h + have hsm : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) + unfold evmShr u256 + simp only [word_mod_eq, hwm, hsm] + rw [if_pos (by omega : s < 256)] + +/-! ## `evmShl` as multiplication when the product fits -/ + +theorem evmShl_eq {s : Nat} (hs : s < 256) {w : Nat} (h : w * 2 ^ s < 2 ^ 256) : + evmShl s w = w * 2 ^ s := by + unfold evmShl u256 + simp only [word_mod_eq] + have hs2 : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) + have hpos : 0 < 2 ^ s := Nat.two_pow_pos s + have hw : w < 2 ^ 256 := by + have h1 : w * 1 ≤ w * 2 ^ s := Nat.mul_le_mul_left w hpos + omega + rw [hs2, if_pos hs, Nat.mod_eq_of_lt hw, Nat.mod_eq_of_lt h] + +/-! ## `evmSar` general floor sandwich (signed value) -/ + +/-- `evmSar s w` is the signed floor of `int256 w / 2^s` for a shift `s < 256`: +`2^s · int256 (evmSar s w) ≤ int256 w < 2^s · int256 (evmSar s w) + 2^s`, and the result is a +valid word. This is the single fact the floor step needs (`s = 126 - k` is a runtime value, and +`126 - k ∈ [63, 127]` over the supported octaves). -/ +theorem evmSar_sandwich {s : Nat} (hs : s < 256) {w : Nat} (h : w < 2 ^ 256) : + evmSar s w < 2 ^ 256 ∧ + (2 ^ s : Int) * int256 (evmSar s w) ≤ int256 w ∧ + int256 w < (2 ^ s : Int) * int256 (evmSar s w) + (2 ^ s : Int) := by + have hps : (0 : Nat) < 2 ^ s := Nat.two_pow_pos s + have hwm : w % 2 ^ 256 = w := Nat.mod_eq_of_lt h + have hsm : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) + -- `2^256 = 2^s * 2^(256-s)`, so the complement's floor relates to `w`'s floor. + have hsplit : (2 : Nat) ^ 256 = 2 ^ s * 2 ^ (256 - s) := by + rw [← Nat.pow_add]; congr 1; omega + have hsne : ¬ 256 ≤ s := by omega + unfold evmSar u256 int256 + simp only [word_mod_eq, hwm, hsm, hsne, if_false] + by_cases hneg : 2 ^ 255 ≤ w + · rw [if_pos hneg] + -- result word = 2^256 - 1 - (2^256 - 1 - w)/2^s; it is in the negative half. + set m := 2 ^ 256 - 1 - w with hm + set q := m / 2 ^ s with hq + have hmlt : m < 2 ^ 255 := by omega + -- floor facts for q + have hqlo : 2 ^ s * q ≤ m := by rw [Nat.mul_comm]; exact Nat.div_mul_le_self m (2 ^ s) + have hqhi : m < 2 ^ s * q + 2 ^ s := by + have hdm := Nat.div_add_mod m (2 ^ s) + have hmod := Nat.mod_lt m hps + have hc : 2 ^ s * (m / 2 ^ s) = q * 2 ^ s := by rw [← hq]; exact Nat.mul_comm _ _ + have hc2 : 2 ^ s * q = q * 2 ^ s := Nat.mul_comm _ _ + omega + have hqle : q ≤ m := by rw [hq]; exact Nat.div_le_self m (2 ^ s) + have hqlt : q < 2 ^ 255 := by omega + -- the result word `rw = 2^256 - 1 - q` lies in the negative half + have hrwlt : (2 ^ 256 - 1 - q) < 2 ^ 256 := + Nat.lt_of_le_of_lt (Nat.sub_le _ _) (by omega) + have hrwneg : 2 ^ 255 ≤ 2 ^ 256 - 1 - q := by omega + rw [if_neg (Nat.not_lt.mpr hrwneg)] + rw [if_neg (Nat.not_lt.mpr hneg)] + -- Cast the Nat-level floor facts to `Int` once, as relations among `↑q`, `↑w`, `↑(2^s)`. + have hqloI : (2 ^ s : Int) * (q : Int) ≤ (2 ^ 256 : Int) - 1 - (w : Int) := by + have h0 : ((2 ^ s * q : Nat) : Int) ≤ ((m : Nat) : Int) := by exact_mod_cast hqlo + have hmI : ((m : Nat) : Int) = (2 ^ 256 : Int) - 1 - (w : Int) := by + rw [hm]; simp only [ipow256]; push_cast [Nat.sub_sub]; omega + push_cast at h0; rw [hmI] at h0; linarith + have hqhiI : (2 ^ 256 : Int) - 1 - (w : Int) < (2 ^ s : Int) * (q : Int) + (2 ^ s : Int) := by + have h0 : ((m : Nat) : Int) < ((2 ^ s * q + 2 ^ s : Nat) : Int) := by exact_mod_cast hqhi + have hmI : ((m : Nat) : Int) = (2 ^ 256 : Int) - 1 - (w : Int) := by + rw [hm]; simp only [ipow256]; push_cast [Nat.sub_sub]; omega + push_cast at h0; rw [hmI] at h0; linarith + have hresI : ((2 ^ 256 - 1 - q : Nat) : Int) = (2 ^ 256 : Int) - 1 - (q : Int) := by + simp only [ipow256]; push_cast [Nat.sub_sub]; omega + refine ⟨hrwlt, ?_, ?_⟩ + · rw [hresI]; nlinarith [hqloI] + · rw [hresI]; nlinarith [hqhiI] + · rw [if_neg hneg] + -- nonnegative: result word = w / 2^s, both halves nonnegative. + set q := w / 2 ^ s with hq + have hqlt : q < 2 ^ 255 := by + have : w / 2 ^ s ≤ w := Nat.div_le_self w (2 ^ s) + omega + have hqlt2 : q < 2 ^ 256 := by omega + rw [if_pos hqlt, if_pos (by omega : w < 2 ^ 255)] + have hfloor := Nat.div_mul_le_self w (2 ^ s) + have hfloor2 : w < (w / 2 ^ s) * 2 ^ s + 2 ^ s := by + have hdm := Nat.div_add_mod w (2 ^ s) + have hmod := Nat.mod_lt w hps + have hc : 2 ^ s * (w / 2 ^ s) = (w / 2 ^ s) * 2 ^ s := Nat.mul_comm _ _ + omega + refine ⟨hqlt2, ?_, ?_⟩ + · have he : (2 ^ s : Int) * (q : Int) = ((2 ^ s * q : Nat) : Int) := by push_cast; ring + rw [he] + have hh : 2 ^ s * q ≤ w := by rw [hq, Nat.mul_comm]; exact hfloor + exact_mod_cast hh + · have he : (2 ^ s : Int) * (q : Int) + (2 ^ s : Int) = ((2 ^ s * q + 2 ^ s : Nat) : Int) := by + push_cast; ring + rw [he] + have hh : w < 2 ^ s * q + 2 ^ s := by rw [hq, Nat.mul_comm]; exact hfloor2 + exact_mod_cast hh + +/-! ## `evmSdiv` sign-pinned transports -/ + +theorem toInt_u256_of_small {q : Nat} (h : q < 2 ^ 255) : int256 (u256 q) = (q : Int) := by + unfold int256 u256 + simp only [word_mod_eq, ipow256] at * + split <;> omega + +theorem toInt_u256_neg {q : Nat} (h : q ≤ 2 ^ 255) : + int256 (u256 (WORD_MOD - q)) = -(q : Int) := by + unfold int256 u256 + simp only [word_mod_eq, ipow256] at * + split <;> omega + +theorem evmSdiv_pos_pos {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) + (h1 : 0 ≤ int256 a) (h2 : 0 < int256 b) : + int256 (evmSdiv a b) = (((int256 a).toNat / (int256 b).toNat : Nat) : Int) := by + have hna : ¬ 2 ^ 255 ≤ a := by + unfold int256 at h1; simp only [ipow256] at *; split at h1 <;> omega + have hnb : ¬ 2 ^ 255 ≤ b := by + unfold int256 at h2; simp only [ipow256] at *; split at h2 <;> omega + have hb0 : ¬ b = 0 := by + unfold int256 at h2; split at h2 <;> omega + have ea : (int256 a).toNat = a := by + unfold int256; simp only [ipow256] at *; split <;> omega + have eb : (int256 b).toNat = b := by + unfold int256; simp only [ipow256] at *; split <;> omega + unfold evmSdiv + simp only [u256_of_lt ha, u256_of_lt hb, decide_eq_false hna, decide_eq_false hnb, + Bool.false_eq_true, if_true, if_false, if_neg hb0, ea, eb] + have hq : a / b < 2 ^ 255 := by + have := Nat.div_le_self a b + omega + rw [toInt_u256_of_small hq] + +theorem evmSdiv_neg_pos {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) + (h1 : int256 a < 0) (hmin : -(2 ^ 255) < int256 a) (h2 : 0 < int256 b) : + int256 (evmSdiv a b) = -(((- int256 a).toNat / (int256 b).toNat : Nat) : Int) := by + have hna : 2 ^ 255 ≤ a := by + unfold int256 at h1; simp only [ipow255, ipow256] at *; split at h1 <;> omega + have hnb : ¬ 2 ^ 255 ≤ b := by + unfold int256 at h2; simp only [ipow255, ipow256] at *; split at h2 <;> omega + have hb0 : ¬ b = 0 := by + unfold int256 at h2; split at h2 <;> omega + have ea : (- int256 a).toNat = WORD_MOD - a := by + unfold int256; simp only [word_mod_eq, ipow255, ipow256] at *; split <;> omega + have eb : (int256 b).toNat = b := by + unfold int256; simp only [ipow255, ipow256] at *; split <;> omega + unfold evmSdiv + simp only [u256_of_lt ha, u256_of_lt hb, decide_eq_true hna, decide_eq_false hnb, + Bool.false_eq_true, Bool.true_eq_false, if_true, if_false, if_neg hb0, ea, eb] + have hq : (WORD_MOD - a) / b ≤ 2 ^ 255 := by + have h3 : WORD_MOD - a ≤ 2 ^ 255 := by + unfold int256 at hmin; simp only [word_mod_eq, ipow255, ipow256] at * + split at hmin <;> omega + have := Nat.div_le_self (WORD_MOD - a) b + omega + rw [toInt_u256_neg hq] + +theorem evmSdiv_pos_neg {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) + (h1 : 0 ≤ int256 a) (h2 : int256 b < 0) : + int256 (evmSdiv a b) = -(((int256 a).toNat / (- int256 b).toNat : Nat) : Int) := by + have hna : ¬ 2 ^ 255 ≤ a := by + unfold int256 at h1; simp only [ipow256] at *; split at h1 <;> omega + have hnb : 2 ^ 255 ≤ b := by + unfold int256 at h2; simp only [ipow256] at *; split at h2 <;> omega + have hb0 : ¬ b = 0 := by + intro h; subst h; simp only [] at hnb; omega + have ea : (int256 a).toNat = a := by + unfold int256; simp only [ipow256] at *; split <;> omega + have eb : (- int256 b).toNat = WORD_MOD - b := by + unfold int256; simp only [word_mod_eq, ipow256] at *; split <;> omega + unfold evmSdiv + simp only [u256_of_lt ha, u256_of_lt hb, decide_eq_false hna, decide_eq_true hnb, + Bool.false_eq_true, if_true, if_false, if_neg hb0, ea, eb] + have hq : a / (WORD_MOD - b) ≤ 2 ^ 255 := by + have h3 : a < 2 ^ 255 := by + unfold int256 at h1; simp only [ipow256] at *; split at h1 <;> omega + have := Nat.div_le_self a (WORD_MOD - b) + omega + rw [toInt_u256_neg hq] + +theorem evmSdiv_neg_neg {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) + (h1 : int256 a < 0) (hmin : -(2 ^ 255) < int256 a) (h2 : int256 b < 0) : + int256 (evmSdiv a b) = (((- int256 a).toNat / (- int256 b).toNat : Nat) : Int) := by + have hna : 2 ^ 255 ≤ a := by + unfold int256 at h1; simp only [ipow255, ipow256] at *; split at h1 <;> omega + have hnb : 2 ^ 255 ≤ b := by + unfold int256 at h2; simp only [ipow255, ipow256] at *; split at h2 <;> omega + have hb0 : ¬ b = 0 := by + intro h; subst h; simp only [] at hnb; omega + have ea : (- int256 a).toNat = WORD_MOD - a := by + unfold int256; simp only [word_mod_eq, ipow255, ipow256] at *; split <;> omega + have eb : (- int256 b).toNat = WORD_MOD - b := by + unfold int256; simp only [word_mod_eq, ipow255, ipow256] at *; split <;> omega + unfold evmSdiv + simp only [u256_of_lt ha, u256_of_lt hb, decide_eq_true hna, decide_eq_true hnb, + if_true, if_neg hb0, ea, eb] + have hq : (WORD_MOD - a) / (WORD_MOD - b) < 2 ^ 255 := by + have h3 : WORD_MOD - a ≤ 2 ^ 255 := by + unfold int256 at hmin; simp only [word_mod_eq, ipow255, ipow256] at * + split at hmin <;> omega + have := Nat.div_le_self (WORD_MOD - a) (WORD_MOD - b) + simp only [word_mod_eq, ipow255] at * + omega + rw [toInt_u256_of_small hq] + +/-! ## Cross-multiplied monotonicity of `Nat` division -/ + +theorem nat_div_cross_mono {a b c d : Nat} (hb : 0 < b) (hd : 0 < d) + (h : a * d ≤ c * b) : a / b ≤ c / d := by + rw [Nat.le_div_iff_mul_le hd] + have h1 : a / b * b ≤ a := Nat.div_mul_le_self a b + have h2 : a / b * b * d ≤ a * d := Nat.mul_le_mul_right d h1 + have h3 : a / b * b * d ≤ c * b := Nat.le_trans h2 h + have h4 : a / b * d * b ≤ c * b := by + have : a / b * b * d = a / b * d * b := by + rw [Nat.mul_assoc, Nat.mul_comm b d, ← Nat.mul_assoc] + omega + exact Nat.le_of_mul_le_mul_right h4 hb + +theorem toNat_mul_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) : + x.toNat * y.toNat = (x * y).toNat := by + obtain ⟨a, rfl⟩ := Int.eq_ofNat_of_zero_le hx + obtain ⟨b, rfl⟩ := Int.eq_ofNat_of_zero_le hy + rfl + +/-- Cross-multiplication to truncated-division monotonicity over signed positive numerators. -/ +theorem cross_to_div {n1 n2 W1 W2 : Int} (hn1 : 0 ≤ n1) (hn2 : 0 ≤ n2) + (hW1 : 0 < W1) (hW2 : 0 < W2) (hcross : n1 * W2 ≤ n2 * W1) : + n1.toNat / W1.toNat ≤ n2.toNat / W2.toNat := by + refine nat_div_cross_mono (by omega) (by omega) ?_ + have e1 := toNat_mul_of_nonneg hn1 (by omega : (0:Int) ≤ W2) + have e2 := toNat_mul_of_nonneg hn2 (by omega : (0:Int) ≤ W1) + omega + +end ExpYul From d90527e2601c099f168d165e646d6b0ea977ab17 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 05:58:15 +0200 Subject: [PATCH 021/149] Add the exp layered tree definition and run-level bridge (Mono/Tree, Mono/RunBridge) Captures as thin layered defs (kTree/tTree/vTree/evTree/odTree/todTree/ r0Tree/r1Tree/expTree) so the deep Horner accumulator is never forced into whnf (which overflows the kernel C stack). Proves run_exp_ray_to_wad_evm x = .ok (expTree x) on the supported domain, and the signed-comparison characterisation of the evmSlt clamp. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- .../exp/ExpProof/ExpProof/Mono/RunBridge.lean | 27 ++++ formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 143 ++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Tree.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean new file mode 100644 index 000000000..f18e3996f --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean @@ -0,0 +1,27 @@ +import ExpProof.Mono.Tree +import ExpProof.Seam.Value + +/-! +# Bridge from the run-level value tree to `expTree` + +`run_exp_ray_to_wad_evm_eq_tree` returns the inline `let`-shared `evm*` tree; `expTree` is the +same value organised into thin layers. They are definitionally equal (each layer unfolds to one +piece of the inline tree), so the run returns `expTree x` on the supported domain. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- `expTree x` is the inline value tree. -/ +theorem run_exp_ray_to_wad_evm_eq_expTree + (x : Nat) + (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + run_exp_ray_to_wad_evm x = .ok (expTree x) := by + rw [run_exp_ray_to_wad_evm_eq_tree x hval] + rfl + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean new file mode 100644 index 000000000..42b83a455 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -0,0 +1,143 @@ +import ExpProof.Mono.WordMono + +/-! +# The `exp` tree as a function of the input, in layered pieces + +`` (the value `run_exp_ray_to_wad_evm` returns, established by +`run_exp_ray_to_wad_evm_eq_tree`) is captured here, decomposed into thin named layers so that the +deeply-nested Horner accumulator never has to be materialised by the kernel (forcing whnf of the +full tree overflows the C stack — every layer below keeps the next level behind one `def`). + +The outermost layer is the zeroing clamp and the scale-point pin: + +``` +expTree x = evmAdd (evmIszero x) (evmMul (evmSlt C x) (r1Tree x)) +``` + +with `C = ⌊-18·ln10·10²⁷⌋` a negative signed boundary. Monotonicity of `int256 (expTree ·)` +reduces to a single analytic obligation about the floored accumulator `r1Tree` on the meaningful +region `int256 C < int256 x` (the clamp forces `0` below it). +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-! ## Constants -/ + +/-- `C = ⌊-18·ln10·10²⁷⌋`, the greatest `x` whose exact result is below `1` (the 0/1 boundary). -/ +def Cmask : Nat := 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 + +/-- The supported-range threshold; the run reverts at or above it. -/ +def C0thresh : Nat := 0x8e383a2cdfa1b74a9422d2e1 + +theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by + unfold Cmask int256 + norm_num + +theorem Cmask_lt : Cmask < 2 ^ 256 := by unfold Cmask; norm_num + +/-! ## The kernel pieces as thin layered functions of the input word + +Each layer is a one-line `def`; the kernel only ever delta-unfolds one level at a time, so the +deep Horner accumulator is never forced into whnf. -/ + +/-- Octave index word `k = round(x / (10²⁷·ln2))` (half-open, ties toward `+∞`). -/ +def kTree (x : Nat) : Nat := + evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + +/-- Reduced argument `t` in Q128. -/ +def tTree (x : Nat) : Nat := + evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d (kTree x))) + +/-- `v = t²` in Q128. -/ +def vTree (x : Nat) : Nat := evmShr 0x80 (evmMul (tTree x) (tTree x)) + +/-- `Ev(v)`, the even (degree-5, monic) Horner accumulator. -/ +def evTree (x : Nat) : Nat := + let v := vTree x + evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + +/-- `Od(v)`, the odd (degree-4) Horner accumulator. -/ +def odTree (x : Nat) : Nat := + let v := vTree x + evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + +/-- `t·Od(v)` in Q87 (signed via `t`). -/ +def todTree (x : Nat) : Nat := evmSar 0x80 (evmMul (tTree x) (odTree x)) + +/-- `exp(t)` in Q126: the reciprocal-symmetric quotient `(Ev + t·Od)/(Ev − t·Od)`. -/ +def r0Tree (x : Nat) : Nat := + evmSdiv (evmShl 0x7e (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) + +/-- The floored, `2ᵏ`-scaled, margin-subtracted accumulator (the body upstream of the clamp). -/ +def r1Tree (x : Nat) : Nat := + evmSar (evmSub 0x7e (kTree x)) (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) + +/-- ``: the clamp/pin shell wrapped around `r1Tree`. -/ +def expTree (x : Nat) : Nat := + evmAdd (evmIszero x) (evmMul (evmSlt Cmask x) (r1Tree x)) + +theorem r1Tree_lt (x : Nat) : r1Tree x < 2 ^ 256 := by unfold r1Tree; exact evmSar_lt _ _ +theorem expTree_lt (x : Nat) : expTree x < 2 ^ 256 := by unfold expTree; exact evmAdd_lt _ _ + +/-! ## Small word/`Int` facts for the clamp and pin -/ + +/-- `evmSlt a b` is the signed comparison (of the canonical words) as a `{0,1}` word. -/ +theorem evmSlt_eq_ite (a b : Nat) : + evmSlt a b = if int256 (u256 a) < int256 (u256 b) then 1 else 0 := by + have hua : u256 a < 2 ^ 256 := u256_lt_word a + have hub : u256 b < 2 ^ 256 := u256_lt_word b + have offneg : ∀ c : Nat, c < 2 ^ 256 → 2 ^ 255 ≤ c → + (c + 2 ^ 255) % 2 ^ 256 = c - 2 ^ 255 := by + intro c hc hcn + rw [show c + 2 ^ 255 = (c - 2 ^ 255) + 2 ^ 256 by omega, Nat.add_mod_right, + Nat.mod_eq_of_lt (by omega)] + have offpos : ∀ c : Nat, c < 2 ^ 256 → c < 2 ^ 255 → + (c + 2 ^ 255) % 2 ^ 256 = c + 2 ^ 255 := by + intro c hc hcp; exact Nat.mod_eq_of_lt (by omega) + have hai : (u256 a : Int) < 2 ^ 256 := by simp only [ipow256]; exact_mod_cast hua + have hbi : (u256 b : Int) < 2 ^ 256 := by simp only [ipow256]; exact_mod_cast hub + -- The offset (excess-2^255) comparison the opcode performs coincides with the signed order. + have key : ((u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256) ↔ + (int256 (u256 a) < int256 (u256 b)) := by + unfold int256 + simp only [ipow255, ipow256] at hai hbi + by_cases ha : 2 ^ 255 ≤ u256 a <;> by_cases hb : 2 ^ 255 ≤ u256 b + · rw [offneg _ hua ha, offneg _ hub hb, + if_neg (by omega : ¬ u256 a < 2 ^ 255), if_neg (by omega : ¬ u256 b < 2 ^ 255)] + constructor <;> intro h <;> omega + · rw [offneg _ hua ha, offpos _ hub (by omega), + if_neg (by omega : ¬ u256 a < 2 ^ 255), if_pos (by omega : u256 b < 2 ^ 255)] + constructor <;> intro h <;> omega + · rw [offpos _ hua (by omega), offneg _ hub hb, + if_pos (by omega : u256 a < 2 ^ 255), if_neg (by omega : ¬ u256 b < 2 ^ 255)] + constructor <;> intro h <;> omega + · rw [offpos _ hua (by omega), offpos _ hub (by omega), + if_pos (by omega : u256 a < 2 ^ 255), if_pos (by omega : u256 b < 2 ^ 255)] + constructor <;> intro h <;> omega + have hslt : evmSlt a b = if int256 (u256 a) < int256 (u256 b) then 1 else 0 := by + unfold evmSlt + by_cases hcmp : (u256 a + 2 ^ 255) % WORD_MOD < (u256 b + 2 ^ 255) % WORD_MOD + · have hcmp' : (u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256 := hcmp + rw [if_pos hcmp, if_pos (key.mp hcmp')] + · have hcmp' : ¬ (u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256 := hcmp + rw [if_neg hcmp, if_neg (fun h => hcmp' (key.mpr h))] + exact hslt + +/-- `evmIszero x` is `1` exactly when the word is `0`. -/ +theorem evmIszero_eq_ite (x : Nat) : evmIszero x = if u256 x = 0 then 1 else 0 := rfl + +end ExpYul From 5900f7e00defd5aaddf1966a8558416308b87617 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 06:10:42 +0200 Subject: [PATCH 022/149] Add the exp clamp/pin shell decomposition (Mono/Shell, Mono/ShellOn) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduces int256 (expTree ·) monotonicity to the meaningful region: below the clamp boundary C (a negative signed value) expTree x = 0 (clamp off, pin cannot fire); above it the decode is [x=0] + r1Tree x. Proved via an abstract body word so the kernel never reduces the Horner accumulator. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Mono/Shell.lean | 66 +++++++++++++++++++ .../exp/ExpProof/ExpProof/Mono/ShellOn.lean | 55 ++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Shell.lean create mode 100644 formal/exp/ExpProof/ExpProof/Mono/ShellOn.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/Shell.lean b/formal/exp/ExpProof/ExpProof/Mono/Shell.lean new file mode 100644 index 000000000..51e4a1763 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Shell.lean @@ -0,0 +1,66 @@ +import ExpProof.Mono.Tree + +/-! +# The clamp/pin shell: reducing `expTree` monotonicity to the meaningful region + +`expTree x = evmAdd (evmIszero x) (evmMul (evmSlt C x) (r1Tree x))`. Two regions: + +* **masked off** (`int256 (u256 x) ≤ int256 C`): the clamp is `0`, and since `int256 C < 0` the + pin cannot fire either, so `expTree x = 0`; +* **masked on** (`int256 C < int256 (u256 x)`): the clamp is transparent, so + `int256 (expTree x) = [x = 0] + int256 (r1Tree x)`. + +Given the analytic facts on the masked-on region — `r1Tree` nonnegative and nondecreasing in the +signed input, and the `x = 0` neighbours bracketing the pin — `expTree` is monotone over the whole +domain. This file packages that reduction; the analytic facts are its hypotheses. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +attribute [local irreducible] r1Tree r0Tree evTree odTree todTree tTree vTree kTree + +/-- `int256 C < 0`: the clamp boundary is a negative signed value. -/ +theorem int256_Cmask_neg : int256 (u256 Cmask) < 0 := by + rw [u256_of_lt Cmask_lt, int256_Cmask]; norm_num + +/-! ## `{0,1}` word arithmetic -/ + +theorem evmMul_zero_left (b : Nat) : evmMul 0 b = 0 := by + have h0 : u256 0 = 0 := by unfold u256; simp + unfold evmMul; rw [h0, Nat.zero_mul]; unfold u256; simp +theorem evmMul_one_left {b : Nat} (hb : b < 2 ^ 256) : evmMul 1 b = b := by + have h1 : u256 1 = 1 := by unfold u256; simp [word_mod_eq] + have hbb : u256 b = b := u256_of_lt hb + unfold evmMul; rw [h1, hbb, Nat.one_mul, hbb] +theorem evmAdd_zero_left {b : Nat} (hb : b < 2 ^ 256) : evmAdd 0 b = b := by + have h0 : u256 0 = 0 := by unfold u256; simp + have hbb : u256 b = b := u256_of_lt hb + unfold evmAdd; rw [h0, hbb, Nat.zero_add, hbb] + +/-! ## The masked-off region: `expTree x = 0` -/ + +/-- Below or at the clamp boundary the result is `0` (the clamp zeroes it and the pin cannot fire +because the boundary is negative, so `x ≠ 0`). -/ +theorem expTree_eq_zero_of_le {x : Nat} (h : int256 (u256 x) ≤ int256 (u256 Cmask)) : + expTree x = 0 := by + unfold expTree + have hmask : evmSlt Cmask x = 0 := by + rw [evmSlt_eq_ite] + rw [if_neg (by omega : ¬ int256 (u256 Cmask) < int256 (u256 x))] + have hpin : evmIszero x = 0 := by + have hxne : u256 x ≠ 0 := by + intro h0 + have : int256 (u256 x) = 0 := by rw [h0]; rfl + have hneg := int256_Cmask_neg + omega + unfold evmIszero + rw [if_neg hxne] + rw [hmask, hpin, evmMul_zero_left] + rfl + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/ShellOn.lean b/formal/exp/ExpProof/ExpProof/Mono/ShellOn.lean new file mode 100644 index 000000000..aabfb5581 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/ShellOn.lean @@ -0,0 +1,55 @@ +import ExpProof.Mono.Tree + +/-! +# The masked-on region: `int256 (expTree x) = [x = 0] + int256 (r1Tree x)` + +Above the clamp boundary the clamp word is `1`, so the body value passes through and only the +`x = 0` pin adds one. The decode is proved for an *abstract* body word `R` (never the deep tree), +then specialised, so the kernel never has to reduce the Horner accumulator. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +private theorem evmMul_one_left' {b : Nat} (hb : b < 2 ^ 256) : evmMul 1 b = b := by + have h1 : u256 1 = 1 := by unfold u256; simp [word_mod_eq] + have hbb : u256 b = b := u256_of_lt hb + unfold evmMul; rw [h1, hbb, Nat.one_mul, hbb] +private theorem evmAdd_zero_left' {b : Nat} (hb : b < 2 ^ 256) : evmAdd 0 b = b := by + have h0 : u256 0 = 0 := by unfold u256; simp + have hbb : u256 b = b := u256_of_lt hb + unfold evmAdd; rw [h0, hbb, Nat.zero_add, hbb] + +/-- The clamp/pin shell decode for an abstract body word `R` above the boundary. -/ +theorem int256_shell_of_gt {x R : Nat} + (hmask : int256 (u256 Cmask) < int256 (u256 x)) (hR : R < 2 ^ 254) : + int256 (evmAdd (evmIszero x) (evmMul (evmSlt Cmask x) R)) = + (if u256 x = 0 then 1 else 0) + (R : Int) := by + have hR' : R < 2 ^ 255 := by have : (2:Nat)^254 < 2^255 := by norm_num + omega + have hRlt : R < 2 ^ 256 := by have : (2:Nat)^254 < 2^256 := by norm_num + omega + have hsl : evmSlt Cmask x = 1 := by rw [evmSlt_eq_ite, if_pos hmask] + rw [hsl, evmMul_one_left' hRlt] + unfold evmIszero + have h1 : int256 1 = 1 := by decide + have hRnn : int256 R = (R : Int) := int256_of_lt hR' + have hpow : (2 : Int) ^ 254 < 2 ^ 255 := by norm_num + by_cases hx0 : u256 x = 0 + · rw [if_pos hx0, evmAdd_int256 (by norm_num) hRlt + (by rw [h1, hRnn]; simp only [ipow255]; omega) + (by rw [h1, hRnn]; simp only [ipow255] at hpow ⊢; omega), if_pos hx0, h1, hRnn] + · rw [if_neg hx0, evmAdd_zero_left' hRlt, if_neg hx0, int256_of_lt hR']; ring + +/-- Specialisation to the actual body word `r1Tree x`. -/ +theorem int256_expTree_of_gt {x : Nat} + (hmask : int256 (u256 Cmask) < int256 (u256 x)) + (hr1 : r1Tree x < 2 ^ 254) : + int256 (expTree x) = (if u256 x = 0 then 1 else 0) + (r1Tree x : Int) := + int256_shell_of_gt hmask hr1 + +end ExpYul From 6b913b53d5cfe37f7bd8da614afd7b471bf9a95e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 06:14:53 +0200 Subject: [PATCH 023/149] Reduce top-level exp monotonicity to the region analytic core (Mono/Top) Bundles the analytic obligations as RegionMonotonicityFacts (r1Tree in range, nonnegative, nondecreasing, and the scale-point pin clearance) and derives expTree_mono over the whole supported domain by casing on the clamp boundary. Lifts it to the run level as run_exp_ray_to_wad_evm_mono, modulo the analytic core. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Mono/Top.lean | 146 +++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Top.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean new file mode 100644 index 000000000..0539199ca --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -0,0 +1,146 @@ +import ExpProof.Mono.Shell +import ExpProof.Mono.ShellOn +import ExpProof.Mono.RunBridge + +/-! +# Top-level monotonicity reduction + +`expTree` is monotone over the supported domain once the analytic facts on the meaningful region +(`int256 C < int256 x`) are supplied: + +* `r1Tree` is in range (`< 2^254`); +* `r1Tree` is nondecreasing in the signed input; +* the scale-point jump: `1 + r1Tree 0 ≤ r1Tree x` for any `x > 0` in the region (the `+1` pin at + `x = 0` is bracketed by the exact-on-central neighbours). + +The clamp forces `0` below the boundary, and `0 ≤ r1Tree` there above, so the boundary crossing is +order-preserving. Inputs are canonical words (`x < 2^256`, as the ABI decode produces). This file +bundles those facts as `RegionMonotonicityFacts` and derives `expTree_mono`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- The analytic monotonicity facts on the meaningful region `int256 C < int256 x < C0` +(for canonical words). -/ +structure RegionMonotonicityFacts : Prop where + /-- `r1Tree` never exceeds `≈ 2^123 < 2^254`. -/ + range : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → + int256 x < int256 C0thresh → r1Tree x < 2 ^ 254 + /-- `0 ≤ r1Tree` on the region (the floored `exp` value is never negative). -/ + nonneg : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → + int256 x < int256 C0thresh → 0 ≤ (r1Tree x : Int) + /-- `r1Tree` is nondecreasing in the signed input across the region. -/ + mono : ∀ x1 x2 : Nat, x1 < 2 ^ 256 → x2 < 2 ^ 256 → int256 Cmask < int256 x1 → + int256 x1 ≤ int256 x2 → int256 x2 < int256 C0thresh → + (r1Tree x1 : Int) ≤ (r1Tree x2 : Int) + /-- The scale-point jump: above `x = 0` the body has already cleared `1 + r1Tree 0`. -/ + pin : ∀ x : Nat, x < 2 ^ 256 → 0 < int256 x → int256 x < int256 C0thresh → + 1 + (r1Tree 0 : Int) ≤ (r1Tree x : Int) + +theorem int256_C0thresh : int256 C0thresh = 44014845965556527147994239713 := by + unfold C0thresh int256 + norm_num + +theorem int256_Cmask_lt0 : int256 Cmask < 0 := by rw [int256_Cmask]; norm_num + +theorem int256_zero : int256 (0 : Nat) = 0 := rfl + +/-- For a canonical word, `int256 x = 0 ↔ x = 0`. -/ +theorem int256_eq_zero_iff {x : Nat} (hx : x < 2 ^ 256) : int256 x = 0 ↔ x = 0 := by + unfold int256 + simp only [intPow256] at * + constructor + · intro h; split at h <;> omega + · intro h; subst h; rfl + +theorem u256_id {x : Nat} (hx : x < 2 ^ 256) : u256 x = x := u256_of_lt hx + +/-- **The tree monotonicity.** Under the region monotonicity facts, `int256 (expTree ·)` is +nondecreasing over the whole supported domain (`int256 x1 ≤ int256 x2 < C0`, canonical words). -/ +theorem expTree_mono (H : RegionMonotonicityFacts) {x1 x2 : Nat} + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hle : int256 x1 ≤ int256 x2) + (hdom : int256 x2 < int256 C0thresh) : + int256 (expTree x1) ≤ int256 (expTree x2) := by + have hCneg : int256 Cmask < 0 := int256_Cmask_lt0 + have hu1 : u256 x1 = x1 := u256_id hx1 + have hu2 : u256 x2 = x2 := u256_id hx2 + have huC : u256 Cmask = Cmask := u256_id Cmask_lt + -- Rewrite the boundary-comparison hypotheses into canonical form. + by_cases h1 : int256 Cmask < int256 x1 + · -- x1 above the boundary ⇒ x2 above it too + have h2 : int256 Cmask < int256 x2 := lt_of_lt_of_le h1 hle + have hdom1 : int256 x1 < int256 C0thresh := lt_of_le_of_lt hle hdom + have hr1 : r1Tree x1 < 2 ^ 254 := H.range x1 hx1 h1 hdom1 + have hr2 : r1Tree x2 < 2 ^ 254 := H.range x2 hx2 h2 hdom + have hmask1 : int256 (u256 Cmask) < int256 (u256 x1) := by rw [huC, hu1]; exact h1 + have hmask2 : int256 (u256 Cmask) < int256 (u256 x2) := by rw [huC, hu2]; exact h2 + rw [int256_expTree_of_gt hmask1 hr1, int256_expTree_of_gt hmask2 hr2] + have hmono : (r1Tree x1 : Int) ≤ (r1Tree x2 : Int) := H.mono x1 x2 hx1 hx2 h1 hle hdom + rw [hu1, hu2] + by_cases hz1 : x1 = 0 + · subst hz1 + have hzero : u256 (0 : Nat) = 0 := by rw [u256_zero] + by_cases hz2 : x2 = 0 + · subst hz2; simp + · -- x1 = 0 < x2 + have hx2pos : 0 < int256 x2 := by + have hne : int256 x2 ≠ 0 := fun h => hz2 ((int256_eq_zero_iff hx2).mp h) + have : (0 : Int) = int256 (0 : Nat) := int256_zero.symm + omega + have hpin := H.pin x2 hx2 hx2pos hdom + rw [if_pos rfl, if_neg hz2] + omega + · by_cases hz2 : x2 = 0 + · subst hz2 + rw [if_neg hz1, if_pos rfl] + omega + · rw [if_neg hz1, if_neg hz2]; omega + · -- x1 at/below the boundary ⇒ expTree x1 = 0 + have hx1le : int256 (u256 x1) ≤ int256 (u256 Cmask) := by rw [hu1, huC]; omega + rw [expTree_eq_zero_of_le hx1le] + by_cases h2 : int256 Cmask < int256 x2 + · have hr2 : r1Tree x2 < 2 ^ 254 := H.range x2 hx2 h2 hdom + have hmask2 : int256 (u256 Cmask) < int256 (u256 x2) := by rw [huC, hu2]; exact h2 + rw [int256_expTree_of_gt hmask2 hr2] + have hnn : 0 ≤ (r1Tree x2 : Int) := H.nonneg x2 hx2 h2 hdom + have hz : int256 (0 : Nat) = 0 := int256_zero + rw [hu2, hz] + split <;> omega + · have hx2le : int256 (u256 x2) ≤ int256 (u256 Cmask) := by rw [hu2, huC]; omega + rw [expTree_eq_zero_of_le hx2le] + +/-- A canonical word strictly below the supported threshold is in the non-reverting run domain. -/ +theorem domain_of_below_C0 {x : Nat} (hx : x < 2 ^ 256) (h : int256 x < int256 C0thresh) : + u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ u256 x := by + rw [u256_id hx] + rw [int256_C0thresh] at h + by_cases hb : x < 2 ^ 255 + · left + have : int256 x = (x : Int) := int256_of_lt hb + rw [this] at h + have : (x : Int) < 44014845965556527147994239713 := h + have hC0 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) = 44014845965556527147994239713 := by norm_num + rw [hC0]; exact_mod_cast h + · right; omega + +/-- **Runtime monotonicity.** Under the region monotonicity facts, the compiled +`expRayToWad` signed results are `≤`-ordered for ordered canonical inputs strictly below the +supported threshold (the entire non-reverting `int256` domain). -/ +theorem run_exp_ray_to_wad_evm_mono (H : RegionMonotonicityFacts) (x1 x2 : Nat) + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hle : int256 x1 ≤ int256 x2) (hdom : int256 x2 < int256 C0thresh) : + ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ + int256 r1 ≤ int256 r2 := by + have hdom1 : int256 x1 < int256 C0thresh := lt_of_le_of_lt hle hdom + refine ⟨expTree x1, expTree x2, ?_, ?_, ?_⟩ + · exact run_exp_ray_to_wad_evm_eq_expTree x1 (domain_of_below_C0 hx1 hdom1) + · exact run_exp_ray_to_wad_evm_eq_expTree x2 (domain_of_below_C0 hx2 hdom) + · exact expTree_mono H hx1 hx2 hle hdom + +end ExpYul From acfea239314c822a503d62a0fd45641e81eca51e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 06:20:33 +0200 Subject: [PATCH 024/149] Add the exp octave-index transport and its monotonicity (Mono/Octave) Transports the rounding-shift argument 2^199 + CINV*x to Int (no overflow on the meaningful region, |int256 x| < 2^96), establishes the k floor sandwich, and proves k = round(x/(10^27 ln2)) is nondecreasing in the signed input. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Mono/Octave.lean | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Octave.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean new file mode 100644 index 000000000..b17d2c857 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean @@ -0,0 +1,127 @@ +import ExpProof.Mono.Tree + +/-! +# Octave-index and reduced-argument transports + +On the meaningful region the input word `x` (canonical, `< 2^256`) has signed value in +`(C, C0) ⊂ (−2^96, 2^96)`. This file transports the first two kernel stages — the octave index +`k = round(x/(10²⁷·ln2))` and the reduced argument `t` — to closed `Int` forms via the no-overflow +bounds, and proves `k` is nondecreasing in `int256 x` and (for a fixed `k`) `t` is nondecreasing in +`int256 x`. + +Constants and their bit widths (so every product stays below `2^255`): +`CINV` 111 bits, `K27` 146 bits, `LN2` 235 bits, `|int256 x| < 2^96`, `k ∈ [-60, 63]`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- The signed value of `x` on the meaningful region is bounded by `2^96`. -/ +theorem region_x_bound {x : Nat} (hC : int256 Cmask < int256 x) + (hC0 : int256 x < int256 C0thresh) : + -(2 ^ 96 : Int) < int256 x ∧ int256 x < 2 ^ 96 := by + rw [int256_Cmask] at hC + have hC0' : int256 x < 44014845965556527147994239713 := by + rw [show int256 C0thresh = 44014845965556527147994239713 from by + unfold C0thresh int256; norm_num] at hC0 + exact hC0 + constructor <;> [skip; skip] <;> simp only [show (2:Int)^96 = 79228162514264337593543950336 from by norm_num] <;> omega + +theorem CINV_lt : (0x724d54edbacbebbb95c52a0f6076 : Nat) < 2 ^ 112 := by norm_num +theorem K27_lt : (0x279d346de4781f921dd7a89933d54d1f72928 : Nat) < 2 ^ 146 := by norm_num +theorem LN2_lt : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Nat) < 2 ^ 235 := by + norm_num + +/-- `int256` of the constant `CINV` (it is below `2^255`, so the signed view is the literal). -/ +theorem int256_CINV : int256 0x724d54edbacbebbb95c52a0f6076 = 0x724d54edbacbebbb95c52a0f6076 := by + unfold int256; norm_num +theorem int256_K27 : + int256 0x279d346de4781f921dd7a89933d54d1f72928 = 0x279d346de4781f921dd7a89933d54d1f72928 := by + unfold int256; norm_num +theorem int256_LN2 : + int256 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d = + 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d := by + unfold int256; norm_num + +/-- `2^199 = evmShl 0xc7 1`. -/ +theorem evmShl_c7_one : evmShl 0xc7 1 = 2 ^ 199 := by + rw [evmShl_eq (by norm_num) (by norm_num)]; norm_num + +/-! ## The octave index `k` -/ + +/-- The argument of the rounding shift, transported to `Int`: `2^199 + CINV · int256 x`. -/ +theorem int256_kArg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + int256 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) = + 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x := by + obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 + have hx96 : (-(2 ^ 96 : Int)) < int256 x ∧ int256 x < 2 ^ 96 := ⟨hxlo, hxhi⟩ + have hb96 : (2 : Int) ^ 96 = 79228162514264337593543950336 := by norm_num + -- the product `CINV * int256 x` fits + have hmul : int256 (evmMul 0x724d54edbacbebbb95c52a0f6076 x) = + 0x724d54edbacbebbb95c52a0f6076 * int256 x := by + rw [evmMul_transport (by norm_num) hx ?_ ?_, int256_CINV] + · rw [int256_CINV] + simp only [hb96] at hxlo hxhi + have : -(2 ^ 255 : Int) ≤ 0x724d54edbacbebbb95c52a0f6076 * int256 x := by + simp only [ipow255]; nlinarith [hxlo, hxhi] + exact this + · rw [int256_CINV] + simp only [hb96] at hxlo hxhi + simp only [ipow255]; nlinarith [hxlo, hxhi] + have hshl : evmShl 0xc7 1 = 2 ^ 199 := evmShl_c7_one + rw [hshl] + have hpow199 : (2 : Nat) ^ 199 < 2 ^ 256 := by norm_num + rw [evmAdd_transport hpow199 (evmMul_lt _ _) ?_ ?_] + · rw [hmul] + have : int256 (2 ^ 199 : Nat) = (2 ^ 199 : Int) := by + rw [int256_of_lt (by norm_num)]; norm_num + rw [this] + · rw [hmul] + have h199 : int256 (2 ^ 199 : Nat) = (2 ^ 199 : Int) := by + rw [int256_of_lt (by norm_num)]; norm_num + rw [h199]; simp only [hb96, ipow255] at *; nlinarith [hxlo, hxhi] + · rw [hmul] + have h199 : int256 (2 ^ 199 : Nat) = (2 ^ 199 : Int) := by + rw [int256_of_lt (by norm_num)]; norm_num + rw [h199]; simp only [hb96, ipow255] at *; nlinarith [hxlo, hxhi] + +/-- The argument of the `k`-rounding shift is a valid word (so the sandwich applies). -/ +theorem kArg_lt {x : Nat} : + evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x) < 2 ^ 256 := evmAdd_lt _ _ + +/-- The `k`-floor sandwich on the meaningful region: `2^200·k ≤ 2^199 + CINV·x < 2^200·k + 2^200`. -/ +theorem kTree_sandwich {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 ^ 200 : Int) * int256 (kTree x) ≤ 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x ∧ + 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x < + (2 ^ 200 : Int) * int256 (kTree x) + 2 ^ 200 := by + unfold kTree + obtain ⟨_, hlo, hhi⟩ := evmSar_sandwich (s := 0xc8) (by norm_num) (kArg_lt (x := x)) + rw [int256_kArg hx hC hC0] at hlo hhi + exact ⟨by simpa using hlo, by simpa using hhi⟩ + +/-- `k` is nondecreasing in the signed input across the meaningful region. -/ +theorem kTree_mono {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hle : int256 x1 ≤ int256 x2) + (hC02 : int256 x2 < int256 C0thresh) : + int256 (kTree x1) ≤ int256 (kTree x2) := by + have hC2 : int256 Cmask < int256 x2 := lt_of_lt_of_le hC1 hle + have hC01 : int256 x1 < int256 C0thresh := lt_of_le_of_lt hle hC02 + obtain ⟨hlo1, hhi1⟩ := kTree_sandwich hx1 hC1 hC01 + obtain ⟨hlo2, hhi2⟩ := kTree_sandwich hx2 hC2 hC02 + -- kArg increases with int256 x (CINV > 0), and floor is monotone. + have hcinv : (0 : Int) < 0x724d54edbacbebbb95c52a0f6076 := by norm_num + have hargle : 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x1 ≤ + 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x2 := by + have := mul_le_mul_left_nonneg hle (le_of_lt hcinv) + omega + -- from the two sandwiches: 2^200·k1 ≤ arg1 ≤ arg2 < 2^200·k2 + 2^200 ⇒ k1 < k2 + 1 ⇒ k1 ≤ k2 + have hpow : (0 : Int) < 2 ^ 200 := by norm_num + nlinarith [hlo1, hhi2, hargle, hpow] + +end ExpYul From 3b835eb6146e6d66782b821e1abcb75dbfd4ece3 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 06:24:17 +0200 Subject: [PATCH 025/149] Add the exp k bound and reduced-argument transport (Mono/Octave) Adds the octave-index bound (-61 <= k <= 63 on the region) and transports the reduced-argument shift K27*x - LN2*k to Int (products stay below 2^255). Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Mono/Octave.lean | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean index b17d2c857..03823bc82 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean @@ -124,4 +124,60 @@ theorem kTree_mono {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hpow : (0 : Int) < 2 ^ 200 := by norm_num nlinarith [hlo1, hhi2, hargle, hpow] +/-- On the meaningful region the octave index is bounded: `-61 ≤ k ≤ 63`. -/ +theorem kTree_bound {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + -61 ≤ int256 (kTree x) ∧ int256 (kTree x) ≤ 63 := by + obtain ⟨hlo, hhi⟩ := kTree_sandwich hx hC hC0 + have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask + have hC0i : int256 C0thresh = 44014845965556527147994239713 := by + unfold C0thresh int256; norm_num + rw [hCi] at hC + rw [hC0i] at hC0 + have hcinv : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by + norm_num + -- bound the rounding-shift argument from the exact region endpoints. + have hprod_lo : (0x724d54edbacbebbb95c52a0f6076 : Int) * int256 x > + 0x724d54edbacbebbb95c52a0f6076 * (-41446531673892822312323846185) := by + rw [hcinv]; nlinarith [hC] + have hprod_hi : (0x724d54edbacbebbb95c52a0f6076 : Int) * int256 x < + 0x724d54edbacbebbb95c52a0f6076 * 44014845965556527147994239713 := by + rw [hcinv]; nlinarith [hC0] + constructor + · nlinarith [hhi, hprod_lo] + · nlinarith [hlo, hprod_hi] + +/-! ## The reduced argument `t` -/ + +/-- The argument of the `t`-reduction shift, transported to `Int`: +`K27 · int256 x − LN2 · int256 k`. -/ +theorem int256_tArg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + int256 (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d (kTree x))) = + 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x - + 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) := by + have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask + have hC0i : int256 C0thresh = 44014845965556527147994239713 := by + unfold C0thresh int256; norm_num + have hxr := hC; rw [hCi] at hxr + have hxr0 := hC0; rw [hC0i] at hxr0 + obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 + have hk256 : kTree x < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ + -- transport the two products. + have hmul1 : int256 (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) = + 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x := by + rw [evmMul_transport (by norm_num) hx ?_ ?_, int256_K27] + · rw [int256_K27]; simp only [ipow255]; nlinarith [hxr, hxr0] + · rw [int256_K27]; simp only [ipow255]; nlinarith [hxr, hxr0] + have hmul2 : + int256 (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d (kTree x)) = + 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) := by + rw [evmMul_transport (by norm_num) (by exact evmSar_lt _ _) ?_ ?_, int256_LN2] + · rw [int256_LN2]; simp only [ipow255]; nlinarith [hklo, hkhi] + · rw [int256_LN2]; simp only [ipow255]; nlinarith [hklo, hkhi] + rw [evmSub_transport (evmMul_lt _ _) (evmMul_lt _ _) ?_ ?_, hmul1, hmul2] + · rw [hmul1, hmul2]; simp only [ipow255]; nlinarith [hxr, hxr0, hklo, hkhi] + · rw [hmul1, hmul2]; simp only [ipow255]; nlinarith [hxr, hxr0, hklo, hkhi] + end ExpYul From 002b79b6e062f9091bc8f1f3ac68eb3b7db875cd Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 06:25:50 +0200 Subject: [PATCH 026/149] Prove within-octave reduced-argument monotonicity (Mono/Octave) Adds the t floor sandwich and proves t is nondecreasing in the signed input within a fixed octave (K27 > 0, floor of an increasing affine map). Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Mono/Octave.lean | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean index 03823bc82..abc64e2b3 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean @@ -180,4 +180,44 @@ theorem int256_tArg {x : Nat} (hx : x < 2 ^ 256) · rw [hmul1, hmul2]; simp only [ipow255]; nlinarith [hxr, hxr0, hklo, hkhi] · rw [hmul1, hmul2]; simp only [ipow255]; nlinarith [hxr, hxr0, hklo, hkhi] +/-- The `t`-reduction shift argument is a valid word. -/ +theorem tArg_lt {x : Nat} : + evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d (kTree x)) + < 2 ^ 256 := evmSub_lt _ _ + +/-- `t = sar(107, tArg)` floor sandwich: `2^107·t ≤ K27·x − LN2·k < 2^107·t + 2^107`. -/ +theorem tTree_sandwich {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 ^ 107 : Int) * int256 (tTree x) ≤ + 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x - + 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) ∧ + 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x - + 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) < + (2 ^ 107 : Int) * int256 (tTree x) + 2 ^ 107 := by + unfold tTree + obtain ⟨_, hlo, hhi⟩ := evmSar_sandwich (s := 0x6b) (by norm_num) (tArg_lt (x := x)) + rw [int256_tArg hx hC hC0] at hlo hhi + exact ⟨by simpa using hlo, by simpa using hhi⟩ + +/-- Within a fixed octave (`k` constant), `t` is nondecreasing in the signed input +(`K27 > 0`, and the floor of an increasing affine map is monotone). -/ +theorem tTree_mono_sameOctave {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x1) = int256 (kTree x2)) (hle : int256 x1 ≤ int256 x2) : + int256 (tTree x1) ≤ int256 (tTree x2) := by + obtain ⟨hlo1, hhi1⟩ := tTree_sandwich hx1 hC1 hC01 + obtain ⟨hlo2, hhi2⟩ := tTree_sandwich hx2 hC2 hC02 + rw [hk] at hlo1 hhi1 + have hk27 : (0 : Int) < 0x279d346de4781f921dd7a89933d54d1f72928 := by norm_num + have hargle : 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x1 - + 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x2) ≤ + 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x2 - + 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x2) := by + have := mul_le_mul_left_nonneg hle (le_of_lt hk27) + omega + have hpow : (0 : Int) < 2 ^ 107 := by norm_num + nlinarith [hlo1, hhi2, hargle, hpow] + end ExpYul From fa4903ccb4ecc9869a0cff62dc924741e2171db4 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 06:29:30 +0200 Subject: [PATCH 027/149] Add the Mono facade and the Theorems gate entry for monotonicity Wires the Mono layer into the package and adds run_exp_ray_to_wad_evm_mono to the Theorems signpost with its axiom gate (axioms = the three standard ones). The theorem holds over the whole supported domain given the meaningful-region core RegionMonotonicityFacts; the clamp/pin shell, run-level bridge, and octave-index / reduced-argument transports and monotonicity are unconditional. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Mono.lean | 12 ++++++++++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono.lean b/formal/exp/ExpProof/ExpProof/Mono.lean new file mode 100644 index 000000000..4a6fcf975 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono.lean @@ -0,0 +1,12 @@ +import ExpProof.Mono.Top +import ExpProof.Mono.Octave + +/-! +# Mono facade + +Monotonicity of the compiled `expRayToWad` runtime. `Top` is the entry point: +`expTree_mono` / `run_exp_ray_to_wad_evm_mono` reduce monotonicity over the whole supported domain +to the analytic facts on the meaningful region (`RegionMonotonicityFacts`), via the clamp/pin shell (`Shell`, +`ShellOn`) and the run-level bridge (`RunBridge`). `Octave` supplies the octave-index and +reduced-argument transports and their monotonicity; `WordMono` the word-level transports. +-/ diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 953ad6a6f..cee8fa4c0 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -1,5 +1,6 @@ import ExpProof.Seam.Revert import ExpProof.Seam.Value +import ExpProof.Mono /-! # `expRayToWad` — proven properties of the compiled runtime (signpost) @@ -17,6 +18,14 @@ stray `sorry` (or any new axiom) breaks the build. | Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1`| `run_exp_ray_to_wad_evm_revert` | | Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | | Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | +| Monotone in the input (modulo the region core) | `run_exp_ray_to_wad_evm_mono` | + +The monotonicity theorem `run_exp_ray_to_wad_evm_mono` is proved over the whole supported domain; +it takes the analytic facts of the meaningful region (`RegionMonotonicityFacts`: `r1Tree` in range, +nonnegative, nondecreasing, and the scale-point pin clearance) as a hypothesis. The clamp/pin +shell, the run-level bridge, and the octave-index / reduced-argument transports and their +monotonicity are proved without that hypothesis; the rational-quotient (`sdiv`) within-octave step +and the octave-seam compensation are represented by `RegionMonotonicityFacts`. The supported-range threshold is `0x8e383a2cdfa1b74a9422d2e1`; at or above it (and below `2^255`, i.e. for any non-negative `int256` that large) the wrapper run halts with `revert`. At the scale @@ -52,4 +61,17 @@ example : run_exp_ray_to_wad_evm 0 = .ok 1000000000000000000 := #guard_msgs in #print axioms run_exp_ray_to_wad_evm_eq_tree +/-- Monotone over the whole supported domain, given the meaningful-region analytic core. -/ +example (H : RegionMonotonicityFacts) (x1 x2 : Nat) + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hle : FormalYul.Preservation.int256 x1 ≤ FormalYul.Preservation.int256 x2) + (hdom : FormalYul.Preservation.int256 x2 < FormalYul.Preservation.int256 C0thresh) : + ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ + FormalYul.Preservation.int256 r1 ≤ FormalYul.Preservation.int256 r2 := + run_exp_ray_to_wad_evm_mono H x1 x2 hx1 hx2 hle hdom + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_mono' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_mono + end ExpYul From 4b46b76f044a9c159d5bf27530f1b5e8f2cd7b4f Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 07:16:47 +0200 Subject: [PATCH 028/149] Port cert Foundation (Poly) and exp Horner-stage transports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port ln's polynomial-nonnegativity certificate checker (Foundation/Poly.lean, namespace ExpPoly) into ExpProof, and add the Horner-stage Int transports (Mono/Stages.lean): - the reduced-argument bound |int256 (tTree x)| < 2^127 (from the coupled k-/t-octave sandwiches); - v = t² in Q128 as a Nat, < 2^126; - two-sided bounds on the even/odd Horner accumulators (0x4e14… ≤ ev < 2^127, 0x270a… ≤ od < 2^126) via a chained no-overflow stage bound. All axiom-clean ([propext, Classical.choice, Quot.sound]). Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Foundation/Poly.lean | 225 ++++++++++++ formal/exp/ExpProof/ExpProof/Mono/Stages.lean | 344 ++++++++++++++++++ 2 files changed, 569 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Foundation/Poly.lean create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Stages.lean diff --git a/formal/exp/ExpProof/ExpProof/Foundation/Poly.lean b/formal/exp/ExpProof/ExpProof/Foundation/Poly.lean new file mode 100644 index 000000000..64b7eaf8b --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Foundation/Poly.lean @@ -0,0 +1,225 @@ +import Init + +/-! +# Polynomial positivity certificates + +Dense `Int` polynomials (coefficients low-order first), interval-Horner +evaluation over nonnegative domains, and a fuel-bounded adaptive bisection +checker whose `true` result soundly certifies `0 ≤ P(x)` for every integer +`x` in the queried range. The checker is executed by the kernel via `decide`, +so the analytic components of the monotonicity proof reduce to computation. +-/ + +namespace ExpPoly + +/-- Multiplication monotonicity helpers (Init-only, so spelled out). -/ +theorem mul_le_mul_left_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : + c * a ≤ c * b := by + have h1 : 0 ≤ c * (b - a) := Int.mul_nonneg hc (by omega) + rw [Int.mul_sub] at h1 + omega + +theorem mul_le_mul_right_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : + a * c ≤ b * c := by + have h1 : 0 ≤ (b - a) * c := Int.mul_nonneg (by omega) hc + rw [Int.sub_mul] at h1 + omega + +theorem mul_le_mul_left_nonpos {a b c : Int} (h : a ≤ b) (hc : c ≤ 0) : + c * b ≤ c * a := by + have h1 : 0 ≤ -c * (b - a) := Int.mul_nonneg (by omega) (by omega) + rw [Int.mul_sub, Int.neg_mul, Int.neg_mul] at h1 + omega + +def evalPoly : List Int → Int → Int + | [], _ => 0 + | c :: cs, x => c + x * evalPoly cs x + +/-- Interval Horner over a nonnegative domain `[lo, hi]`, `0 ≤ lo`. Returns +`(vlo, vhi)` with `vlo ≤ P(x) ≤ vhi` for all `x ∈ [lo, hi]`. -/ +def hornerIv : List Int → Int → Int → Int × Int + | [], _, _ => (0, 0) + | c :: cs, lo, hi => + let (plo, phi) := hornerIv cs lo hi + let mlo := if 0 ≤ plo then lo * plo else hi * plo + let mhi := if 0 ≤ phi then hi * phi else lo * phi + (c + mlo, c + mhi) + +theorem hornerIv_sound (cs : List Int) {lo hi x : Int} + (h0 : 0 ≤ lo) (h1 : lo ≤ x) (h2 : x ≤ hi) : + (hornerIv cs lo hi).1 ≤ evalPoly cs x ∧ evalPoly cs x ≤ (hornerIv cs lo hi).2 := by + induction cs with + | nil => simp [hornerIv, evalPoly] + | cons c cs ih => + obtain ⟨ihlo, ihhi⟩ := ih + simp only [hornerIv, evalPoly] + constructor + · -- lower bound + have hx : 0 ≤ x := by omega + split + · -- 0 ≤ plo : lo * plo ≤ x * plo ≤ x * P(x) + rename_i hplo + have s1 : lo * (hornerIv cs lo hi).1 ≤ x * (hornerIv cs lo hi).1 := + mul_le_mul_right_nonneg h1 hplo + have s2 : x * (hornerIv cs lo hi).1 ≤ x * evalPoly cs x := + mul_le_mul_left_nonneg ihlo hx + omega + · -- plo < 0 : hi * plo ≤ x * plo ≤ x * P(x) + rename_i hplo + have hplo' : (hornerIv cs lo hi).1 ≤ 0 := by omega + have s1 : hi * (hornerIv cs lo hi).1 ≤ x * (hornerIv cs lo hi).1 := by + have hcomm := mul_le_mul_left_nonpos h2 hplo' + rw [Int.mul_comm ((hornerIv cs lo hi).1) hi, + Int.mul_comm ((hornerIv cs lo hi).1) x] at hcomm + exact hcomm + have s2 : x * (hornerIv cs lo hi).1 ≤ x * evalPoly cs x := + mul_le_mul_left_nonneg ihlo hx + omega + · -- upper bound + have hx : 0 ≤ x := by omega + split + · -- 0 ≤ phi : x * P(x) ≤ x * phi ≤ hi * phi + rename_i hphi + have s2 : x * evalPoly cs x ≤ x * (hornerIv cs lo hi).2 := + mul_le_mul_left_nonneg ihhi hx + have s1 : x * (hornerIv cs lo hi).2 ≤ hi * (hornerIv cs lo hi).2 := + mul_le_mul_right_nonneg h2 hphi + omega + · -- phi < 0 : x * P(x) ≤ x * phi ≤ lo * phi + rename_i hphi + have hphi' : (hornerIv cs lo hi).2 ≤ 0 := by omega + have s2 : x * evalPoly cs x ≤ x * (hornerIv cs lo hi).2 := + mul_le_mul_left_nonneg ihhi hx + have s1 : x * (hornerIv cs lo hi).2 ≤ lo * (hornerIv cs lo hi).2 := by + have hcomm := mul_le_mul_left_nonpos h1 hphi' + rw [Int.mul_comm ((hornerIv cs lo hi).2) lo, + Int.mul_comm ((hornerIv cs lo hi).2) x] at hcomm + exact hcomm + omega + +/-- Adaptive bisection: certifies `0 ≤ P(x)` for every integer `x ∈ [lo, hi]`. -/ +def checkNonneg (cs : List Int) (lo hi : Int) : Nat → Bool + | 0 => false + | fuel + 1 => + if hi < lo then true + else if 0 ≤ (hornerIv cs lo hi).1 then true + else if lo = hi then false + else + let mid := (lo + hi) / 2 + checkNonneg cs lo mid fuel && checkNonneg cs (mid + 1) hi fuel + +theorem checkNonneg_sound (cs : List Int) (fuel : Nat) : + ∀ lo hi : Int, 0 ≤ lo → checkNonneg cs lo hi fuel = true → + ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly cs x := by + induction fuel with + | zero => intro lo hi _ h; simp [checkNonneg] at h + | succ fuel ih => + intro lo hi hlo h x hx1 hx2 + unfold checkNonneg at h + split at h + · omega + · split at h + · rename_i hiv + have := (hornerIv_sound cs hlo hx1 hx2).1 + omega + · split at h + · exact absurd h (by simp) + · rw [Bool.and_eq_true] at h + by_cases hm : x ≤ (lo + hi) / 2 + · exact ih lo ((lo + hi) / 2) hlo h.1 x hx1 hm + · exact ih ((lo + hi) / 2 + 1) hi (by omega) h.2 x (by omega) hx2 + +/-! ## Polynomial algebra (with evaluation lemmas) -/ + +def polyAdd : List Int → List Int → List Int + | [], q => q + | p, [] => p + | a :: p, b :: q => (a + b) :: polyAdd p q + +theorem evalPoly_polyAdd (p q : List Int) (x : Int) : + evalPoly (polyAdd p q) x = evalPoly p x + evalPoly q x := by + induction p generalizing q with + | nil => simp [polyAdd, evalPoly] + | cons a p ih => + cases q with + | nil => simp [polyAdd, evalPoly] + | cons b q => + simp only [polyAdd, evalPoly, ih] + rw [Int.mul_add] + omega + +def polyNeg (p : List Int) : List Int := p.map (-·) + +theorem evalPoly_polyNeg (p : List Int) (x : Int) : + evalPoly (polyNeg p) x = -evalPoly p x := by + induction p with + | nil => simp [polyNeg, evalPoly] + | cons a p ih => + simp only [polyNeg, List.map, evalPoly] at * + rw [ih] + rw [show x * -evalPoly p x = -(x * evalPoly p x) by rw [Int.mul_neg]] + omega + +def polySub (p q : List Int) : List Int := polyAdd p (polyNeg q) + +theorem evalPoly_polySub (p q : List Int) (x : Int) : + evalPoly (polySub p q) x = evalPoly p x - evalPoly q x := by + unfold polySub + rw [evalPoly_polyAdd, evalPoly_polyNeg] + omega + +def polyScale (a : Int) (p : List Int) : List Int := p.map (a * ·) + +theorem evalPoly_polyScale (a : Int) (p : List Int) (x : Int) : + evalPoly (polyScale a p) x = a * evalPoly p x := by + induction p with + | nil => simp [polyScale, evalPoly] + | cons c p ih => + simp only [polyScale, List.map, evalPoly] at * + rw [ih, Int.mul_add] + rw [show x * (a * evalPoly p x) = a * (x * evalPoly p x) by + rw [← Int.mul_assoc, Int.mul_comm x a, Int.mul_assoc]] + +theorem evalPoly_singleton (c x : Int) : evalPoly [c] x = c := by + simp [evalPoly] + +def polyMulX (p : List Int) : List Int := 0 :: p + +theorem evalPoly_polyMulX (p : List Int) (x : Int) : + evalPoly (polyMulX p) x = x * evalPoly p x := by + simp [polyMulX, evalPoly] + +def polyMul : List Int → List Int → List Int + | [], _ => [] + | a :: p, q => polyAdd (polyScale a q) (polyMulX (polyMul p q)) + +theorem evalPoly_polyMul (p q : List Int) (x : Int) : + evalPoly (polyMul p q) x = evalPoly p x * evalPoly q x := by + induction p with + | nil => simp [polyMul, evalPoly] + | cons a p ih => + simp only [polyMul, evalPoly] + rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyMulX, ih] + rw [Int.add_mul] + rw [show x * (evalPoly p x * evalPoly q x) = x * evalPoly p x * evalPoly q x by + rw [Int.mul_assoc]] + +/-- Composition with `x + 1`: `evalPoly (polyCompAdd1 p) x = evalPoly p (x + 1)`. -/ +def polyCompAdd1 : List Int → List Int + | [] => [] + | c :: cs => + let q := polyCompAdd1 cs + polyAdd [c] (polyAdd q (polyMulX q)) + +theorem evalPoly_polyCompAdd1 (p : List Int) (x : Int) : + evalPoly (polyCompAdd1 p) x = evalPoly p (x + 1) := by + induction p with + | nil => simp [polyCompAdd1, evalPoly] + | cons c cs ih => + simp only [polyCompAdd1, evalPoly] + rw [evalPoly_polyAdd, evalPoly_polyAdd, evalPoly_polyMulX, ih] + simp only [evalPoly] + rw [Int.add_mul, Int.one_mul] + omega + +end ExpPoly diff --git a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean new file mode 100644 index 000000000..e07d2235e --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean @@ -0,0 +1,344 @@ +import ExpProof.Mono.Octave + +/-! +# Horner-stage transports for the `exp` kernel + +The reduced argument `t = tTree x` is bounded by `2^127` on the meaningful region (the octave +reduction keeps `|t| < ln2/2 · 2^128`). From that bound this file transports the downstream kernel +stages to closed `Int`/bound forms: + +* `v = t²` in Q128 (a nonnegative logical shift, `< 2^126`); +* the even/odd Horner accumulators `ev`, `od` (two-sided constant bounds); +* `tod = t·Od` in Q87 (a signed shift, transported to `Int`); +* the numerator `ev + tod` and denominator `ev − tod` are both strictly positive; +* `r0 = exp(t)·2^126`, the reciprocal-symmetric quotient, is strictly positive and `< 2^128`. + +These are the facts the range/nonneg obligations and the rational-quotient step build on. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-! ## The reduced-argument bound `|t| < 2^127` -/ + +/-- On the meaningful region the reduced argument is bounded: `-2^127 < int256 (tTree x) < 2^127`. +The octave reduction couples `k` to `x` (`2^200·k ≈ CINV·x`), so the residual `K27·x − LN2·k` +stays inside `±ln2/2·2^235`, leaving `|t| < ln2/2·2^128 < 2^127`. -/ +theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + -(2 ^ 127 : Int) < int256 (tTree x) ∧ int256 (tTree x) < 2 ^ 127 := by + obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 + obtain ⟨hklo, hkhi⟩ := kTree_sandwich hx hC hC0 + obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 + -- numeric forms + have hb96 : (2 : Int) ^ 96 = 79228162514264337593543950336 := by norm_num + rw [hb96] at hxlo hxhi + -- constants as decimal + have hK27 : (0x279d346de4781f921dd7a89933d54d1f72928 : Int) = + 55213970774324510299478046898216203619608872 := by norm_num + have hLN2 : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num + have hCINV : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by + norm_num + rw [hK27, hLN2] at htlo hthi + rw [hCINV] at hklo hkhi + set t := int256 (tTree x) + set k := int256 (kTree x) + set X := int256 x + -- powers of two as decimals + have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num + have p127 : (2 : Int) ^ 127 = 170141183460469231731687303715884105728 := by norm_num + have p199 : (2 : Int) ^ 199 = + 803469022129495137770981046170581301261101496891396417650688 := by norm_num + have p200 : (2 : Int) ^ 200 = + 1606938044258990275541962092341162602522202993782792835301376 := by norm_num + rw [p107] at htlo hthi + rw [p199, p200] at hklo hkhi + rw [p127] + -- Eliminate `k` by scaling both sandwiches to the common factor `2^200`, then bound `X`. + -- LN2 (positive) times the k-sandwich: + have hLN2pos : (0 : Int) < 38271408169742254668347313025622401492114385419650052359639581444463709 := by + norm_num + have hklo' : 38271408169742254668347313025622401492114385419650052359639581444463709 * + (1606938044258990275541962092341162602522202993782792835301376 * k) ≤ + 38271408169742254668347313025622401492114385419650052359639581444463709 * + (803469022129495137770981046170581301261101496891396417650688 + + 2318321547468254865173387471183990 * X) := + mul_le_mul_left_nonneg hklo (le_of_lt hLN2pos) + have hkhi' : 38271408169742254668347313025622401492114385419650052359639581444463709 * + (803469022129495137770981046170581301261101496891396417650688 + + 2318321547468254865173387471183990 * X) < + 38271408169742254668347313025622401492114385419650052359639581444463709 * + (1606938044258990275541962092341162602522202993782792835301376 * k + + 1606938044258990275541962092341162602522202993782792835301376) := + by + have := mul_le_mul_left_nonneg (le_of_lt hkhi) (le_of_lt hLN2pos) + rcases lt_or_eq_of_le this with h | h + · exact h + · exact absurd h.symm (by + have := Int.mul_lt_mul_of_pos_left hkhi hLN2pos; omega) + -- 2^200 times the t-sandwich: + have hp200pos : (0 : Int) < 1606938044258990275541962092341162602522202993782792835301376 := by + norm_num + have htlo' : 1606938044258990275541962092341162602522202993782792835301376 * + (162259276829213363391578010288128 * t) ≤ + 1606938044258990275541962092341162602522202993782792835301376 * + (55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k) := + mul_le_mul_left_nonneg htlo (le_of_lt hp200pos) + have hthi' : 1606938044258990275541962092341162602522202993782792835301376 * + (55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k) < + 1606938044258990275541962092341162602522202993782792835301376 * + (162259276829213363391578010288128 * t + 162259276829213363391578010288128) := + by + have := mul_le_mul_left_nonneg (le_of_lt hthi) (le_of_lt hp200pos) + rcases lt_or_eq_of_le this with h | h + · exact h + · exact absurd h.symm (by + have := Int.mul_lt_mul_of_pos_left hthi hp200pos; omega) + constructor + · nlinarith [htlo', hthi', hklo', hkhi', hxlo, hxhi] + · nlinarith [htlo', hthi', hklo', hkhi', hxlo, hxhi] + +/-! ## `v = t²` in Q128 -/ + +/-- The Q128 square `v = ⌊t²/2^128⌋` as a `Nat`: nonnegative, and `< 2^126`. The shift argument +`t·t` fits in a word because `|t| < 2^127` gives `t² < 2^254`. -/ +theorem vTree_eq {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (vTree x : Int) = (int256 (tTree x))^2 / 2 ^ 128 ∧ vTree x < 2 ^ 126 := by + obtain ⟨htlo, hthi⟩ := tTree_bound hx hC hC0 + have htw : tTree x < 2 ^ 256 := by unfold tTree; exact evmSar_lt _ _ + -- the signed square equals the unsigned product of the canonical word with itself + set t := int256 (tTree x) with htdef + have hsq_lt : t ^ 2 < 2 ^ 254 := by + have hp127 : (2:Int)^127 = 170141183460469231731687303715884105728 := by norm_num + have hp254 : (2:Int)^254 = 28948022309329048855892746252171976963317496166410141009864396001978282409984 := by norm_num + rw [hp127] at htlo hthi + rw [hp254, sq] + nlinarith [htlo, hthi] + have hsq_nn : 0 ≤ t ^ 2 := by positivity + -- `tTree x · tTree x` as a word equals `t²` (transport), nonneg, `< 2^254`. + have hmul : int256 (evmMul (tTree x) (tTree x)) = t * t := + evmMul_transport htw htw + (by rw [← sq]; simp only [ipow255]; nlinarith [hsq_nn, hsq_lt]) + (by rw [← sq]; simp only [ipow255]; nlinarith [hsq_lt]) + have hmul_lt : evmMul (tTree x) (tTree x) < 2 ^ 256 := evmMul_lt _ _ + -- its `int256` is nonneg and below `2^254`, so it is the literal Nat value + have hmul_small : evmMul (tTree x) (tTree x) < 2 ^ 255 := by + have h := hmul + unfold int256 at h + split at h <;> simp only [ipow255, ipow256] at * <;> nlinarith [hsq_nn, hsq_lt] + have hmul_nat : (evmMul (tTree x) (tTree x) : Int) = t * t := by + rw [← hmul]; exact (int256_of_lt hmul_small).symm + have hmul_nat_lt : evmMul (tTree x) (tTree x) < 2 ^ 254 := by + have : ((evmMul (tTree x) (tTree x) : Nat) : Int) < 2 ^ 254 := by + rw [hmul_nat, ← sq]; exact hsq_lt + exact_mod_cast this + refine ⟨?_, ?_⟩ + · unfold vTree + rw [evmShr_eq_div (by norm_num) hmul_lt] + have he : ((evmMul (tTree x) (tTree x) / 2 ^ 128 : Nat) : Int) = + (evmMul (tTree x) (tTree x) : Int) / 2 ^ 128 := by + rw [Int.ofNat_ediv]; norm_num + rw [he, hmul_nat, ← sq] + · unfold vTree + rw [evmShr_eq_div (by norm_num) hmul_lt] + have : evmMul (tTree x) (tTree x) / 2 ^ 128 < 2 ^ 254 / 2 ^ 128 := + Nat.div_lt_div_of_lt_of_dvd (by norm_num) hmul_nat_lt + have he : (2:Nat) ^ 254 / 2 ^ 128 = 2 ^ 126 := by + rw [Nat.pow_div (by norm_num) (by norm_num)] + omega + +/-! ## Exact word arithmetic when the operands fit -/ + +/-- `evmAdd` is ordinary addition when the sum fits in a word. -/ +theorem evmAdd_eq_nat {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) (h : a + b < 2 ^ 256) : + evmAdd a b = a + b := by + unfold evmAdd + rw [u256_of_lt ha, u256_of_lt hb, u256_of_lt h] + +/-- `evmMul` is ordinary multiplication when the product fits in a word. -/ +theorem evmMul_eq_nat {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) (h : a * b < 2 ^ 256) : + evmMul a b = a * b := by + unfold evmMul + rw [u256_of_lt ha, u256_of_lt hb, u256_of_lt h] + +/-- One Horner stage upper bound: if `prev < P`, `v < V`, `P · V ≤ 2^256`, and `sh < 256`, then +`evmAdd c (evmShr sh (evmMul prev v)) ≤ c + P * V / 2 ^ sh`, provided the sum fits. -/ +theorem stage_le {c prev v P V sh : Nat} (hprev : prev < P) (hv : v < V) + (hPV : P * V < 2 ^ 256) (hsh : sh < 256) + (hsum : c + P * V / 2 ^ sh < 2 ^ 256) : + evmAdd c (evmShr sh (evmMul prev v)) ≤ c + P * V / 2 ^ sh := by + have hV0 : 0 < V := Nat.pos_of_ne_zero (fun h => by subst h; exact absurd hv (by omega)) + have hprodle : prev * v ≤ P * V := Nat.mul_le_mul (le_of_lt hprev) (le_of_lt hv) + have hPle : P ≤ P * V := Nat.le_mul_of_pos_right P hV0 + have hVle : V ≤ P * V := Nat.le_mul_of_pos_left V (by omega : 0 < P) + have hpv : prev * v < 2 ^ 256 := by omega + have hprev256 : prev < 2 ^ 256 := by omega + have hv256 : v < 2 ^ 256 := by omega + have hmul : evmMul prev v = prev * v := evmMul_eq_nat hprev256 hv256 hpv + have hshr : evmShr sh (evmMul prev v) = prev * v / 2 ^ sh := by + rw [hmul]; exact evmShr_eq_div hsh hpv + have hterm : prev * v / 2 ^ sh ≤ P * V / 2 ^ sh := Nat.div_le_div_right hprodle + rw [hshr] + have hterm_lt : prev * v / 2 ^ sh < 2 ^ 256 := by omega + rw [evmAdd_eq_nat (a := c) (b := prev * v / 2 ^ sh) (by omega) hterm_lt (by omega)] + omega + +/-- One Horner stage lower bound: when the stage does not overflow the accumulator dominates its +leading coefficient (the `evmShr` term is nonnegative). The no-overflow hypothesis is supplied via +the matching `stage_le` upper bound at each call site. -/ +theorem stage_ge {c prev v sh : Nat} (hc : c < 2 ^ 256) + (hsum : c + evmShr sh (evmMul prev v) < 2 ^ 256) : + c ≤ evmAdd c (evmShr sh (evmMul prev v)) := by + have hsh_lt : evmShr sh (evmMul prev v) < 2 ^ 256 := evmShr_lt _ _ + rw [evmAdd_eq_nat hc hsh_lt hsum]; omega + +/-! ## The even/odd Horner accumulators + +Each stage `evmAdd c (evmShr sh (evmMul prev v))` is bounded two-sidedly: it never wraps (so it +dominates its leading coefficient `c`), and the truncated tail keeps it below `c + ⌊P·V/2^sh⌋`. +The bounds chain from `v < 2^126` through the five even / four odd stages. -/ + +/-- The truncated stage tail is bounded by `⌊P·V/2^sh⌋`. -/ +theorem stage_term_le {prev v P V sh : Nat} (hprev : prev < P) (hv : v < V) + (hPV : P * V < 2 ^ 256) (hsh : sh < 256) : + evmShr sh (evmMul prev v) ≤ P * V / 2 ^ sh := by + have hV0 : 0 < V := Nat.pos_of_ne_zero (fun h => by subst h; exact absurd hv (by omega)) + have hP0 : 0 < P := by omega + have hprodle : prev * v ≤ P * V := Nat.mul_le_mul (le_of_lt hprev) (le_of_lt hv) + have hPle : P ≤ P * V := Nat.le_mul_of_pos_right P hV0 + have hVle : V ≤ P * V := Nat.le_mul_of_pos_left V hP0 + have hpv : prev * v < 2 ^ 256 := by omega + have hmul : evmMul prev v = prev * v := evmMul_eq_nat (by omega) (by omega) hpv + rw [hmul, evmShr_eq_div hsh hpv] + exact Nat.div_le_div_right hprodle + +/-- Combined two-sided bound for one Horner stage that does not overflow. -/ +theorem stage_bounds {c prev v P V sh : Nat} (hprev : prev < P) (hv : v < V) + (hPV : P * V < 2 ^ 256) (hsh : sh < 256) + (hsum : c + P * V / 2 ^ sh < 2 ^ 256) : + c ≤ evmAdd c (evmShr sh (evmMul prev v)) ∧ + evmAdd c (evmShr sh (evmMul prev v)) ≤ c + P * V / 2 ^ sh := by + have hub := stage_le hprev hv hPV hsh hsum + have hterm := stage_term_le hprev hv hPV hsh + refine ⟨?_, hub⟩ + -- abstract the (nonlinear) division so `omega` reasons purely linearly + generalize hT : P * V / 2 ^ sh = T at hsum hterm + have hc256 : c < 2 ^ 256 := by omega + exact stage_ge hc256 (by omega) + +theorem ev0_lt {v : Nat} (hv : v < 2 ^ 126) : + evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) < 2 ^ 113 := by + have hsh0 : evmShr 0x1d v = v / 2 ^ 0x1d := evmShr_eq_div (by norm_num) (by omega) + have hev0t : v / 2 ^ 0x1d < 2 ^ 97 := by + have : v / 2 ^ 0x1d < 2 ^ 126 / 2 ^ 0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv + have he : (2:Nat) ^ 126 / 2 ^ 0x1d = 2 ^ 97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] + omega + rw [hsh0, evmAdd_eq_nat (by norm_num) (by omega) (by omega)]; omega + +theorem ev0_ge {v : Nat} (hv : v < 2 ^ 126) : + 0xb9aacfad41060587203a79af0ebc ≤ evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) := by + have hsh0 : evmShr 0x1d v = v / 2 ^ 0x1d := evmShr_eq_div (by norm_num) (by omega) + have hev0t : v / 2 ^ 0x1d < 2 ^ 97 := by + have : v / 2 ^ 0x1d < 2 ^ 126 / 2 ^ 0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv + have he : (2:Nat) ^ 126 / 2 ^ 0x1d = 2 ^ 97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] + omega + rw [hsh0, evmAdd_eq_nat (by norm_num) (by omega) (by omega)]; omega + +/-- Helper to discharge `2^pe·2^ve/2^sh = 2^e` for the chained stage ceilings. -/ +theorem pvd (pe ve sh e : Nat) (hpe : pe + ve = sh + e) : + (2:Nat) ^ pe * 2 ^ ve / 2 ^ sh = 2 ^ e := by + rw [← Nat.pow_add, hpe, Nat.pow_add, Nat.mul_div_cancel_left _ (Nat.two_pow_pos sh)] + +/-- Two-sided bound on the even Horner accumulator: `0x4e14… ≤ ev < 2^127`. -/ +theorem evTree_facts {x : Nat} (hv : vTree x < 2 ^ 126) : + 0x4e14a45e8ec305e233e11b4174e214ac ≤ evTree x ∧ evTree x < 2 ^ 127 := by + have hev : evTree x = + evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d (vTree x))) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl + rw [hev] + set v := vTree x with hvdef + have h0 := ev0_lt hv + set ev0 := evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) with hev0 + have h1 : evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul ev0 v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0x9a036222e11aee18465042f8ea64c8) (prev := ev0) (v := v) + (P := 2 ^ 113) (V := 2 ^ 126) (sh := 0x82) h0 hv (by norm_num) (by norm_num) + (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num)).2 + rw [pvd 113 126 130 109 (by norm_num)] at this; omega + set ev1 := evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul ev0 v)) with hev1 + have h2 : evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul ev1 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0x9064d965e1c4863b73604e0ddbec53f9) (prev := ev1) (v := v) + (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x80) h1 hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 128 119 (by norm_num)] at this; omega + set ev2 := evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul ev1 v)) with hev2 + have h3 : evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul ev2 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (prev := ev2) (v := v) + (P := 2 ^ 129) (V := 2 ^ 126) (sh := 0x86) h2 hv (by norm_num) (by norm_num) + (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num)).2 + rw [pvd 129 126 134 121 (by norm_num)] at this; omega + set ev3 := evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul ev2 v)) with hev3 + have hfin := stage_bounds (c := 0x4e14a45e8ec305e233e11b4174e214ac) (prev := ev3) (v := v) + (P := 2 ^ 129) (V := 2 ^ 126) (sh := 0x84) h3 hv (by norm_num) (by norm_num) + (by rw [pvd 129 126 132 123 (by norm_num)]; norm_num) + rw [pvd 129 126 132 123 (by norm_num)] at hfin + refine ⟨hfin.1, ?_⟩ + have : (0x4e14a45e8ec305e233e11b4174e214ac : Nat) + 2 ^ 123 < 2 ^ 127 := by norm_num + omega + +theorem evTree_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evTree x < 2 ^ 127 := (evTree_facts hv).2 +theorem evTree_ge {x : Nat} (hv : vTree x < 2 ^ 126) : + 0x4e14a45e8ec305e233e11b4174e214ac ≤ evTree x := (evTree_facts hv).1 + +/-- Two-sided bound on the odd Horner accumulator: `0x270a… ≤ od < 2^126`. -/ +theorem odTree_facts {x : Nat} (hv : vTree x < 2 ^ 126) : + 0x270a522f476182f119f08da0ba710a56 ≤ odTree x ∧ odTree x < 2 ^ 126 := by + have hod : odTree x = + evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl + rw [hod] + set v := vTree x with hvdef + have h0 : evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0xc926ddbf3830ca5561cc01585402d0) (prev := 0xdc07aff85e5bb5629d0fb64a84bb) (v := v) + (P := 2 ^ 112) (V := 2 ^ 126) (sh := 0x83) (by norm_num) hv (by norm_num) (by norm_num) + (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num)).2 + rw [pvd 112 126 131 107 (by norm_num)] at this; omega + set od0 := evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb v)) with hod0 + have h1 : evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul od0 v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0xad4506b00b1246c7e5b4fd33e1201b) (prev := od0) (v := v) + (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x89) h0 hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 137 110 (by norm_num)] at this; omega + set od1 := evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul od0 v)) with hod1 + have h2 : evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul od1 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (prev := od1) (v := v) + (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x7f) h1 hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 127 120 (by norm_num)] at this; omega + set od2 := evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul od1 v)) with hod2 + have hfin := stage_bounds (c := 0x270a522f476182f119f08da0ba710a56) (prev := od2) (v := v) + (P := 2 ^ 129) (V := 2 ^ 126) (sh := 0x87) h2 hv (by norm_num) (by norm_num) + (by rw [pvd 129 126 135 120 (by norm_num)]; norm_num) + rw [pvd 129 126 135 120 (by norm_num)] at hfin + refine ⟨hfin.1, ?_⟩ + have : (0x270a522f476182f119f08da0ba710a56 : Nat) + 2 ^ 119 < 2 ^ 126 := by norm_num + omega + +theorem odTree_lt {x : Nat} (hv : vTree x < 2 ^ 126) : odTree x < 2 ^ 126 := (odTree_facts hv).2 +theorem odTree_ge {x : Nat} (hv : vTree x < 2 ^ 126) : + 0x270a522f476182f119f08da0ba710a56 ≤ odTree x := (odTree_facts hv).1 + +end ExpYul From d4486b9bec1c13146e6063fdd7e42f1f1940a506 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 07:40:57 +0200 Subject: [PATCH 029/149] Add quotient-stage transports for the exp kernel (tod, num/den, r0) Mono/Quot.lean assembles the reciprocal-symmetric quotient from the Horner stage bounds, all via abstract opaque-word helpers so the deep Horner tree is never forced into whnf: - tod = t*Od in Q87 transported to Int, |tod| < 2^125; - num = ev+tod and den = ev-tod are strictly positive; - r0 = sdiv(2^126*num, den) satisfies 1 <= r0 < 2^128. These supply the range/nonneg obligations of RegionMonotonicityFacts. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Mono/Quot.lean | 263 ++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Quot.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean new file mode 100644 index 000000000..4508cc8df --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean @@ -0,0 +1,263 @@ +import ExpProof.Mono.Stages + +/-! +# The reciprocal-symmetric quotient stage + +From the stage bounds this file assembles the closing quotient `r0 = exp(t)·2^126`: + +* `tod = ⌊t·Od / 2^128⌋` transported to `Int`, with `|tod| < 2^125`; +* the numerator `num = ev + tod` and denominator `den = ev − tod` are strictly positive (the + reduced argument keeps `|tod|` well below `ev`); +* `r0 = sdiv(2^126·num, den)` is strictly positive and below `2^128`. + +These give the range and nonnegativity obligations directly, and (via the cross-multiplication +identity) reduce the within-octave monotonicity to a fact about `tod·ev`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-! ## `tod = t·Od` in Q87 -/ + +/-- `tod` transported to `Int`: a signed floor with `|tod| < 2^125`. The product `t·Od` fits a word +(`|t| < 2^127`, `Od < 2^126`, so `|t·Od| < 2^253`). -/ +theorem todTree_bound {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + -(2 ^ 125 : Int) ≤ int256 (todTree x) ∧ int256 (todTree x) < 2 ^ 125 ∧ + (2 ^ 128 : Int) * int256 (todTree x) ≤ int256 (tTree x) * (odTree x : Int) ∧ + int256 (tTree x) * (odTree x : Int) < + (2 ^ 128 : Int) * int256 (todTree x) + 2 ^ 128 := by + obtain ⟨htlo, hthi⟩ := tTree_bound hx hC hC0 + obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 + have hodlt : odTree x < 2 ^ 126 := odTree_lt hvlt + have htw : tTree x < 2 ^ 256 := by unfold tTree; exact evmSar_lt _ _ + have hodw : odTree x < 2 ^ 256 := by unfold odTree; exact evmAdd_lt _ _ + set t := int256 (tTree x) with htdef + -- od is a small nonnegative word + have hodi : int256 (odTree x) = (odTree x : Int) := int256_of_lt (by + have : (2:Nat)^126 < 2 ^ 255 := by norm_num + omega) + have hod_nn : 0 ≤ (odTree x : Int) := by positivity + have hod_ub : (odTree x : Int) < 2 ^ 126 := by exact_mod_cast hodlt + -- the product t·od fits + have hp127 : (2:Int)^127 = 170141183460469231731687303715884105728 := by norm_num + have hp126 : (2:Int)^126 = 85070591730234615865843651857942052864 := by norm_num + have hp253 : (2:Int)^253 = 14474011154664524427946373126085988481658748083205070504932198000989141204992 := by norm_num + have hp255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by norm_num + have hprod_lt : t * (odTree x : Int) < 2 ^ 253 := by + rw [hp127] at htlo hthi; rw [hp126] at hod_ub; rw [hp253]; nlinarith [htlo, hthi, hod_nn, hod_ub] + have hprod_gt : -(2 ^ 253 : Int) < t * (odTree x : Int) := by + rw [hp127] at htlo hthi; rw [hp126] at hod_ub; rw [hp253]; nlinarith [htlo, hthi, hod_nn, hod_ub] + -- transport the multiply + have hmul : int256 (evmMul (tTree x) (odTree x)) = t * (odTree x : Int) := by + have := evmMul_transport htw hodw (by rw [hodi]; simp only [ipow255]; nlinarith [hprod_gt, hp253, hp255]) + (by rw [hodi]; simp only [ipow255]; nlinarith [hprod_lt, hp253, hp255]) + rw [hodi] at this; exact this + have hmul_lt : evmMul (tTree x) (odTree x) < 2 ^ 256 := evmMul_lt _ _ + -- the `sar 128` floor sandwich + obtain ⟨_, hsl, hsh⟩ := evmSar_sandwich (s := 0x80) (by norm_num) hmul_lt + rw [hmul] at hsl hsh + have hsh128 : (2:Int) ^ 0x80 = 2 ^ 128 := by norm_num + rw [hsh128] at hsl hsh + have htodeq : int256 (todTree x) = int256 (evmSar 0x80 (evmMul (tTree x) (odTree x))) := by + unfold todTree; rfl + rw [htodeq] + refine ⟨?_, ?_, hsl, hsh⟩ + · -- lower bound: 2^128·tod ≤ t·od and t·od > -2^253 ⇒ tod > -2^125 + nlinarith [hsl, hprod_gt, hp253] + · -- upper bound: t·od < 2^128·tod + 2^128 and t·od < 2^253 ⇒ tod < 2^125 + nlinarith [hsh, hprod_lt, hp253] + +/-! ## Numerator and denominator -/ + +/-- Abstract numerator/denominator positivity: stated over opaque words `E` (the even accumulator) +and `TD` (the signed `t·Od` shift) with their bounds, so the deep Horner tree is never forced. -/ +theorem numden_pos_of {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) + (hev_lo : (103786963415199049567855548359006885036 : Int) ≤ (E : Int)) + (hev_hi : (E : Int) < 2 ^ 127) + (htod_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD) + (htod_hi : int256 TD < 42535295865117307932921825928971026432) : + int256 (evmAdd E TD) = (E : Int) + int256 TD ∧ + int256 (evmSub E TD) = (E : Int) - int256 TD ∧ + 0 < (E : Int) + int256 TD ∧ + 0 < (E : Int) - int256 TD := by + have hevi : int256 E = (E : Int) := int256_of_lt (by + have : (2:Nat)^127 < 2 ^ 255 := by norm_num + omega) + have hp127 : (E : Int) < 170141183460469231731687303715884105728 := by + rw [show (170141183460469231731687303715884105728 : Int) = 2 ^ 127 by norm_num]; exact hev_hi + have hadd : int256 (evmAdd E TD) = (E : Int) + int256 TD := by + have := evmAdd_transport hevw htodw + (by rw [hevi]; simp only [ipow255]; omega) + (by rw [hevi]; simp only [ipow255]; omega) + rw [hevi] at this; exact this + have hsub : int256 (evmSub E TD) = (E : Int) - int256 TD := by + have := evmSub_transport hevw htodw + (by rw [hevi]; simp only [ipow255]; omega) + (by rw [hevi]; simp only [ipow255]; omega) + rw [hevi] at this; exact this + exact ⟨hadd, hsub, by omega, by omega⟩ + +/-- `num = ev + tod` and `den = ev − tod`, transported to `Int`, are both strictly positive: the +even accumulator dominates `|tod|`. -/ +theorem numden_pos {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + int256 (evmAdd (evTree x) (todTree x)) = (evTree x : Int) + int256 (todTree x) ∧ + int256 (evmSub (evTree x) (todTree x)) = (evTree x : Int) - int256 (todTree x) ∧ + 0 < (evTree x : Int) + int256 (todTree x) ∧ + 0 < (evTree x : Int) - int256 (todTree x) := by + obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 + obtain ⟨hev_lo, hev_hi⟩ := evTree_facts hvlt + obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ + have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ + refine numden_pos_of hevw htodw ?_ ?_ ?_ ?_ + · have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 by norm_num] at this + exact this + · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hev_hi + rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this + · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact htod_lo + · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact htod_hi + +/-! ## The closing quotient `r0 = exp(t)·2^126` -/ + +/-- Abstract quotient bounds over opaque numerator/denominator words. `r0 = ⌊2^126·N/D⌋` lies in +`[1, 2^128)`: the dividend `2^126·N` fits a word, `D ≤ 2^126·N` keeps the quotient `≥ 1`, and +`N < 4·D` keeps it below `2^128`. -/ +theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD : D < 2 ^ 256) + (hDi : int256 D = (D : Int)) + (hNpos : 0 < (N : Int)) (hDpos : 0 < (D : Int)) + (hNlo : 2 ^ 125 ≤ N) + (hND : (N : Int) < 4 * (D : Int)) : + 1 ≤ int256 (evmSdiv (evmShl 0x7e N) D) ∧ int256 (evmSdiv (evmShl 0x7e N) D) < 2 ^ 128 := by + -- shl(126, N) = N·2^126 (fits: N < 2^128 ⇒ N·2^126 < 2^254) + have hshl : evmShl 0x7e N = N * 2 ^ 0x7e := by + refine evmShl_eq (by norm_num) ?_ + have : N * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := by + have hp : 0 < 2 ^ 0x7e := Nat.two_pow_pos _ + exact (Nat.mul_lt_mul_right hp).mpr hN + rw [show (2:Nat) ^ 128 * 2 ^ 0x7e = 2 ^ 254 by rw [← Nat.pow_add]] at this + omega + have hNpos' : 0 < N := by exact_mod_cast hNpos + have hShlLt254 : N * 2 ^ 0x7e < 2 ^ 254 := by + have hp : 0 < 2 ^ 0x7e := Nat.two_pow_pos _ + calc N * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := (Nat.mul_lt_mul_right hp).mpr hN + _ = 2 ^ 254 := by rw [← Nat.pow_add] + have hShlLt255 : N * 2 ^ 0x7e < 2 ^ 255 := by + have : (2:Nat) ^ 254 < 2 ^ 255 := by norm_num + omega + have hdivpos : 0 < int256 (evmShl 0x7e N) := by + rw [hshl, int256_of_lt hShlLt255] + have hpos : 0 < N * 2 ^ 0x7e := Nat.mul_pos hNpos' (Nat.two_pow_pos _) + exact_mod_cast hpos + -- both operands positive ⇒ sdiv = floor division + have hshl_lt : evmShl 0x7e N < 2 ^ 256 := evmShl_lt _ _ + rw [evmSdiv_pos_pos hshl_lt hD (le_of_lt hdivpos) (by rw [hDi]; exact hDpos)] + -- the toNat magnitudes + have hshl_nat : evmShl 0x7e N = N * 2 ^ 0x7e := hshl + have hN_toNat : (int256 (evmShl 0x7e N)).toNat = N * 2 ^ 0x7e := by + rw [hshl, int256_of_lt hShlLt255, Int.toNat_natCast] + have hD_toNat : (int256 D).toNat = D := by rw [hDi, Int.toNat_natCast] + rw [hN_toNat, hD_toNat] + set q := N * 2 ^ 0x7e / D with hq + have hDnat_pos : 0 < D := by exact_mod_cast hDpos + have hNnat_pos : 0 < N := by exact_mod_cast hNpos + have hq_lt : q < 2 ^ 128 := by + rw [hq] + rw [Nat.div_lt_iff_lt_mul hDnat_pos] + -- N·2^126 < 2^128·D ⟺ N < 4·D + have hND' : N < 4 * D := by + have : (N : Int) < 4 * (D : Int) := hND + have h4 : ((4 * D : Nat) : Int) = 4 * (D : Int) := by push_cast; ring + rw [← h4] at this; exact_mod_cast this + calc N * 2 ^ 0x7e < 4 * D * 2 ^ 0x7e := by + have hp : 0 < 2 ^ 0x7e := Nat.two_pow_pos _ + exact (Nat.mul_lt_mul_right hp).mpr hND' + _ = 2 ^ 128 * D := by + rw [show (4:Nat) * D * 2 ^ 0x7e = (4 * 2 ^ 0x7e) * D by ring, + show (4:Nat) * 2 ^ 0x7e = 2 ^ 128 by norm_num] + have hq_ge : 1 ≤ q := by + rw [hq, Nat.le_div_iff_mul_le hDnat_pos, Nat.one_mul] + -- D < 2^128 ≤ 2^125·2^126 ≤ N·2^126 + have h1 : (2:Nat) ^ 128 ≤ 2 ^ 125 * 2 ^ 0x7e := by + rw [← Nat.pow_add]; exact Nat.pow_le_pow_right (by norm_num) (by norm_num) + have h2 : (2:Nat) ^ 125 * 2 ^ 0x7e ≤ N * 2 ^ 0x7e := Nat.mul_le_mul_right _ hNlo + omega + exact ⟨by exact_mod_cast hq_ge, by + have : (q : Int) < 2 ^ 128 := by exact_mod_cast hq_lt + simpa using this⟩ + +/-- For a canonical word with nonnegative signed value, the signed value is the Nat value (and the +word lies in the lower half). -/ +theorem int256_eq_of_nonneg {w : Nat} (hw : w < 2 ^ 256) (hnn : 0 ≤ int256 w) : + int256 w = (w : Int) ∧ w < 2 ^ 255 := by + unfold int256 at hnn ⊢ + split at hnn + · rename_i h; exact ⟨if_pos h, h⟩ + · rename_i h; exfalso; simp only [ipow256] at hnn; have : (w : Int) < 2 ^ 256 := by exact_mod_cast hw + simp only [ipow256] at this; omega + +/-- Abstract `r0` bounds: `1 ≤ r0 < 2^128` over opaque even/odd words `E`, `TD` with their bounds. +`r0 = sdiv(2^126·(E+TD), E−TD)`; the numerator and denominator are positive and the quotient lands +in `[1, 2^128)` (the reduced argument keeps `exp(t) ∈ [1/√2, √2)`). -/ +theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) + (hev_lo : (103786963415199049567855548359006885036 : Int) ≤ (E : Int)) + (hev_hi : (E : Int) < 2 ^ 127) + (htod_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD) + (htod_hi : int256 TD < 42535295865117307932921825928971026432) : + 1 ≤ int256 (evmSdiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) ∧ + int256 (evmSdiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) < 2 ^ 128 := by + obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos_of hevw htodw hev_lo hev_hi htod_lo htod_hi + have hNwlt : evmAdd E TD < 2 ^ 256 := evmAdd_lt _ _ + have hDwlt : evmSub E TD < 2 ^ 256 := evmSub_lt _ _ + -- numeric forms + have h128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num + have h127 : (2:Int)^127 = 170141183460469231731687303715884105728 := by norm_num + rw [h127] at hev_hi + -- canonical Nat values for num and den + obtain ⟨hNi, hNlt255⟩ := int256_eq_of_nonneg hNwlt (by rw [hadd]; omega) + obtain ⟨hDi, hDlt255⟩ := int256_eq_of_nonneg hDwlt (by rw [hsub]; omega) + -- numerator and denominator Nat bounds + have hNlt128 : evmAdd E TD < 2 ^ 128 := by + have : ((evmAdd E TD : Nat) : Int) < 2 ^ 128 := by rw [← hNi, hadd, h128]; omega + exact_mod_cast this + have hDlt128 : evmSub E TD < 2 ^ 128 := by + have : ((evmSub E TD : Nat) : Int) < 2 ^ 128 := by rw [← hDi, hsub, h128]; omega + exact_mod_cast this + have hNlo : 2 ^ 125 ≤ evmAdd E TD := by + have : (2 ^ 125 : Int) ≤ ((evmAdd E TD : Nat) : Int) := by + rw [← hNi, hadd, show (2:Int)^125 = 42535295865117307932921825928971026432 by norm_num]; omega + exact_mod_cast this + have hND : ((evmAdd E TD : Nat) : Int) < 4 * ((evmSub E TD : Nat) : Int) := by + rw [← hNi, ← hDi, hadd, hsub]; omega + have hNpos : 0 < ((evmAdd E TD : Nat) : Int) := by rw [← hNi, hadd]; omega + have hDpos : 0 < ((evmSub E TD : Nat) : Int) := by rw [← hDi, hsub]; omega + exact r0Tree_bounds_of hNlt128 hDlt128 hDwlt hDi hNpos hDpos hNlo hND + +/-- `1 ≤ r0Tree x < 2^128` on the meaningful region. -/ +theorem r0Tree_bounds {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + 1 ≤ int256 (r0Tree x) ∧ int256 (r0Tree x) < 2 ^ 128 := by + obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 + obtain ⟨hev_lo, hev_hi⟩ := evTree_facts hvlt + obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + have hr0 : r0Tree x = + evmSdiv (evmShl 0x7e (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) := rfl + rw [hr0] + have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ + have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ + refine r0Tree_bounds_ofEvTod hevw htodw ?_ ?_ ?_ ?_ + · have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 by norm_num] at this + exact this + · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hev_hi + rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this + · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact htod_lo + · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact htod_hi + +end ExpYul From dc95959f2cf5015f35210a8c30b8a8351c24880c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 07:56:54 +0200 Subject: [PATCH 030/149] Discharge RegionMonotonicityFacts range and nonneg obligations Mono/RangeNonneg.lean closes two of the four RegionMonotonicityFacts fields: - range: r1Tree x < 2^254 (the closing shift s = 126-k in [63,187] floors the shift argument WAD*r0-MARGIN < 2^188 down below 2^125 < 2^254); - nonneg: 0 <= (r1Tree x : Int) (trivial Nat cast), plus the signed int256 (r1Tree x) >= 0 used by the floor argument. Both via abstract opaque-word helpers (closing_shift, shiftArg_bounds_of, closingSar_facts) so the deep Horner tree is never forced. Adds r0Tree_lt to Tree.lean. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 167 ++++++++++++++++++ formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 1 + 2 files changed, 168 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean new file mode 100644 index 000000000..b34d324e1 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -0,0 +1,167 @@ +import ExpProof.Mono.Quot + +/-! +# The range and nonnegativity obligations of `RegionMonotonicityFacts` + +`r1Tree x = sar(126 − k, WAD·r0 − MARGIN)` closes the kernel: it scales the Q126 quotient onto the +`10¹⁸·2¹²⁶` grid, subtracts the one-sided margin, and floors with the `2ᵏ` octave scaling folded +into the shift (`126 − k ∈ [63, 187]`). + +* **nonneg**: `r0 ≥ 1` gives `WAD·r0 ≥ WAD > MARGIN`, so the shift argument is nonnegative; a + nonnegative arithmetic shift stays nonnegative. +* **range**: `r0 < 2^128` gives `WAD·r0 < 2^188`, so even before the shift the argument is below + `2^188`, and the floor is below `2^125 < 2^254`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-! ## The closing shift amount `126 − k` -/ + +/-- The shift word `evmSub 0x7e k` equals `126 − int256 k` as a `Nat`, and lies in `[63, 187]` on +the meaningful region (`k ∈ [−61, 63]`). -/ +theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + ∃ s : Nat, evmSub 0x7e (kTree x) = s ∧ 63 ≤ s ∧ s ≤ 187 ∧ + (s : Int) = 126 - int256 (kTree x) := by + obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 + have hkw : kTree x < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ + -- 126 (as int) - int256 k, transported through evmSub + have h126 : int256 (0x7e : Nat) = 126 := by + rw [int256_of_lt (by norm_num)]; simp + have hip255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by + norm_num + have hsub : int256 (evmSub 0x7e (kTree x)) = 126 - int256 (kTree x) := by + have := evmSub_transport (a := 0x7e) (b := kTree x) (by norm_num) hkw + (by rw [h126, hip255]; omega) + (by rw [h126, hip255]; omega) + rw [h126] at this; exact this + -- the result is a small nonnegative word, so its Nat value is 126 - int256 k + have hsublt : evmSub 0x7e (kTree x) < 2 ^ 256 := evmSub_lt _ _ + have hnn : 0 ≤ int256 (evmSub 0x7e (kTree x)) := by rw [hsub]; omega + obtain ⟨heq, hlt255⟩ := int256_eq_of_nonneg hsublt hnn + refine ⟨evmSub 0x7e (kTree x), rfl, ?_, ?_, ?_⟩ + · -- 63 ≤ s + have : (63 : Int) ≤ ((evmSub 0x7e (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega + exact_mod_cast this + · have : ((evmSub 0x7e (kTree x) : Nat) : Int) ≤ 187 := by rw [← heq, hsub]; omega + exact_mod_cast this + · rw [← heq]; exact hsub + +/-! ## The shift argument `WAD·r0 − MARGIN` -/ + +/-- Abstract bound on the shift argument `WAD·r0 − MARGIN` over an opaque `r0` word in `[1, 2^128)`: +its signed value is in `[WAD − MARGIN, 2^188)`, in particular nonnegative and below `2^188`. -/ +theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) + (hr0_lo : 1 ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 128) : + int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) = + 0xde0b6b3a7640000 * int256 r0 - 0xafe527e18748a8a ∧ + 0 ≤ 0xde0b6b3a7640000 * int256 r0 - 0xafe527e18748a8a ∧ + 0xde0b6b3a7640000 * int256 r0 - 0xafe527e18748a8a < 2 ^ 188 := by + have hwad : int256 (0xde0b6b3a7640000 : Nat) = 0xde0b6b3a7640000 := by + rw [int256_of_lt (by norm_num)]; simp + have hwadlt : (0xde0b6b3a7640000 : Nat) < 2 ^ 256 := by norm_num + have hp128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num + have hp188 : (2:Int)^188 = 392318858461667547739736838950479151006397215279002157056 := by norm_num + have hwadc : (0xde0b6b3a7640000 : Int) = 1000000000000000000 := by norm_num + have hmarc : (0xafe527e18748a8a : Int) = 792161285993433738 := by norm_num + rw [hp128] at hr0_hi + -- the product WAD·r0 transported + have hmul : int256 (evmMul 0xde0b6b3a7640000 r0) = 0xde0b6b3a7640000 * int256 r0 := by + have := evmMul_transport hwadlt hr0w + (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) + (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) + rw [hwad] at this; exact this + have hmullt : evmMul 0xde0b6b3a7640000 r0 < 2 ^ 256 := evmMul_lt _ _ + have hmarlt : (0xafe527e18748a8a : Nat) < 2 ^ 256 := by norm_num + have hmari : int256 (0xafe527e18748a8a : Nat) = 0xafe527e18748a8a := by + rw [int256_of_lt (by norm_num)]; simp + -- transport the subtraction + have hsub : int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) = + 0xde0b6b3a7640000 * int256 r0 - 0xafe527e18748a8a := by + have := evmSub_transport hmullt hmarlt + (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) + (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) + rw [hmul, hmari] at this; exact this + refine ⟨hsub, ?_, ?_⟩ + · rw [hwadc, hmarc]; nlinarith [hr0_lo] + · rw [hwadc, hmarc, hp188]; nlinarith [hr0_hi] + +/-! ## Abstract floor facts for the closing shift -/ + +/-- Abstract closing-shift facts over an opaque shift argument word `W` and shift `s ∈ [63, 187]` +with `int256 W ∈ [0, 2^188)`: the floor `sar(s, W)` is nonnegative and below `2^125`. -/ +theorem closingSar_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 63 ≤ s) (hshi : s ≤ 187) + (hWnn : 0 ≤ int256 W) (hWhi : int256 W < 2 ^ 188) : + 0 ≤ int256 (evmSar s W) ∧ int256 (evmSar s W) < 2 ^ 125 := by + obtain ⟨_, hsl, hsh⟩ := evmSar_sandwich (s := s) (by omega) hWw + have hpow : (0 : Int) < 2 ^ s := by positivity + set R := int256 (evmSar s W) with hR + have hnn : 0 ≤ R := by + by_contra hneg + push_neg at hneg + have h2 : (2 : Int) ^ s * (R + 1) ≤ 0 := by + have : (2:Int)^s * (R + 1) ≤ 2^s * 0 := mul_le_mul_left_nonneg (by omega) (le_of_lt hpow) + simpa using this + nlinarith [hWnn, h2, hsh] + refine ⟨hnn, ?_⟩ + have hp63 : (2 : Int) ^ 63 ≤ 2 ^ s := pow_le_pow_right₀ (by norm_num) hslo + by_contra hge + push_neg at hge + have hp188 : (2:Int)^188 = 392318858461667547739736838950479151006397215279002157056 := by norm_num + have hp125 : (2:Int)^125 = 42535295865117307932921825928971026432 := by norm_num + have hp63v : (2:Int)^63 = 9223372036854775808 := by norm_num + have h1 : (2:Int)^63 * 2^125 ≤ 2^63 * R := mul_le_mul_left_nonneg hge (by positivity) + have h2 : (2:Int)^63 * R ≤ 2^s * R := mul_le_mul_right_nonneg hp63 hnn + rw [hp188] at hWhi + rw [hp63v, hp125] at h1 + nlinarith [hsl, hWhi, h1, h2] + +/-! ## The discharged obligations -/ + +/-- **`nonneg`**: `0 ≤ (r1Tree x : Int)`. The body word is a `Nat`, so its signed-as-`Int` cast is +trivially nonnegative; the meaningful "result is never negative" is enforced by the clamp shell. -/ +theorem r1Tree_nonneg (x : Nat) : 0 ≤ (r1Tree x : Int) := Int.natCast_nonneg _ + +/-- The signed value `int256 (r1Tree x)` is nonnegative (the floor of a nonnegative quantity). -/ +theorem r1Tree_int256_nonneg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + 0 ≤ int256 (r1Tree x) := by + obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 + obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 + obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi + have hr1 : r1Tree x = evmSar (evmSub 0x7e (kTree x)) + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) := rfl + rw [hr1, hseq] + exact (closingSar_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) + (by rw [hargeq]; exact harghi)).1 + +/-- **`range`**: `r1Tree x < 2^254` on the meaningful region. -/ +theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + r1Tree x < 2 ^ 254 := by + obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 + obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 + obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi + have hr1 : r1Tree x = evmSar (evmSub 0x7e (kTree x)) + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) := rfl + obtain ⟨hnn, hlt⟩ := closingSar_facts (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) + (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi) + -- int256 (r1Tree x) ∈ [0, 2^125) ⇒ the Nat word is < 2^254 + have hReq : int256 (r1Tree x) = int256 (evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a)) := by + rw [hr1, hseq] + rw [← hReq] at hnn hlt + have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x + obtain ⟨hi, _⟩ := int256_eq_of_nonneg hr1w hnn + have hp254 : (2:Int)^125 < 2^254 := by norm_num + have hcast : ((r1Tree x : Nat) : Int) < 2 ^ 254 := by + rw [← hi] + generalize int256 (r1Tree x) = V at hlt ⊢ + omega + exact_mod_cast hcast + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean index 42b83a455..6fcef64e9 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -90,6 +90,7 @@ def r1Tree (x : Nat) : Nat := def expTree (x : Nat) : Nat := evmAdd (evmIszero x) (evmMul (evmSlt Cmask x) (r1Tree x)) +theorem r0Tree_lt (x : Nat) : r0Tree x < 2 ^ 256 := by unfold r0Tree; exact evmSdiv_lt _ _ theorem r1Tree_lt (x : Nat) : r1Tree x < 2 ^ 256 := by unfold r1Tree; exact evmSar_lt _ _ theorem expTree_lt (x : Nat) : expTree x < 2 ^ 256 := by unfold expTree; exact evmAdd_lt _ _ From cb2c588c6fe2702562e9ee24ad9f19e2113e5b85 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 08:11:28 +0200 Subject: [PATCH 031/149] Reduce same-octave r0 monotonicity to the tod*ev cross inequality Mono/Cross.lean: the cross-product of the two reciprocal-symmetric fractions collapses exactly (cross_identity, by ring) to num1*den2 - num2*den1 = 2*(tod1*ev2 - tod2*ev1), so r0_mono_of_cross derives r0(x1) <= r0(x2) (the two sdiv quotients ordered) from num/den positivity and the single cross inequality tod1*ev2 <= tod2*ev1, via evmSdiv_pos_pos + cross_to_div. Abstract over opaque even/odd words; the shl126_transport and numSum_lt helpers carry fresh kernel frames to avoid a cumulative C-stack overflow. Axiom-clean. The same-octave analytic certificate is tod1*ev2 <= tod2*ev1 itself. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Mono/Cross.lean | 115 +++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Cross.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean new file mode 100644 index 000000000..b340832c0 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean @@ -0,0 +1,115 @@ +import ExpProof.Mono.Quot + +/-! +# Same-octave monotonicity of the quotient `r0` + +Within a fixed octave (`k` constant) the closing accumulator `r1Tree` is monotone in the input iff +the Q126 quotient `r0Tree` is. With `num = ev + tod`, `den = ev − tod` (both strictly positive), +`r0 = ⌊2^126·num/den⌋`, so + +``` +r0(x1) ≤ r0(x2) ⟸ num1·den2 ≤ num2·den1 (cross-multiply over positive den) +``` + +and the cross product simplifies exactly: + +``` +num1·den2 − num2·den1 = 2·(tod1·ev2 − tod2·ev1), +``` + +so the whole same-octave step reduces to `tod1·ev2 ≤ tod2·ev1`. This file proves that reduction (the +algebraic identity and the cross-to-division transport); the inequality `tod1·ev2 ≤ tod2·ev1` itself +is the same-octave analytic certificate (it holds with large slack at the guaranteed per-step +reduced-argument gap, and fails only at sub-step granularity). +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- The cross-product of the two reciprocal-symmetric fractions collapses to a `tod·ev` cross. -/ +theorem cross_identity (ev1 ev2 tod1 tod2 : Int) : + (ev1 + tod1) * (ev2 - tod2) - (ev2 + tod2) * (ev1 - tod1) = + 2 * (tod1 * ev2 - tod2 * ev1) := by ring + +/-- `num = ev + tod < 2^128` (signed), from the even-accumulator and reduced-argument bounds. Stated +as its own lemma so it carries a fresh kernel stack frame. -/ +theorem numSum_lt {W : Nat} {ev tod : Int} (hW : int256 W = ev + tod) + (hev : ev < 2 ^ 127) (htod : tod < 2 ^ 127) : int256 W < 2 ^ 128 := by + rw [hW, show (2:Int)^128 = 2^127 + 2^127 from by ring]; omega + +/-- The `shl 0x7e N` dividend transported to `Int` when `N`'s signed value is in `[0, 2^128)`: +`int256 (shl 126 N) = 2^126 · int256 N`, and the result is in `[0, 2^255)`. -/ +theorem shl126_transport {N : Nat} (hNw : N < 2 ^ 256) (hNnn : 0 ≤ int256 N) + (hNlt : int256 N < 2 ^ 128) : + int256 (evmShl 0x7e N) = 2 ^ 0x7e * int256 N := by + obtain ⟨hNi, _⟩ := int256_eq_of_nonneg hNw hNnn + have hNnat : N < 2 ^ 128 := by + have : ((N : Nat) : Int) < 2 ^ 128 := by rw [← hNi]; exact hNlt + exact_mod_cast this + have hfit : N * 2 ^ 0x7e < 2 ^ 256 := by + calc N * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := (Nat.mul_lt_mul_right (Nat.two_pow_pos _)).mpr hNnat + _ = 2 ^ 254 := by rw [← Nat.pow_add] + _ < 2 ^ 256 := by norm_num + have hfit255 : N * 2 ^ 0x7e < 2 ^ 255 := by + calc N * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := (Nat.mul_lt_mul_right (Nat.two_pow_pos _)).mpr hNnat + _ = 2 ^ 254 := by rw [← Nat.pow_add] + _ < 2 ^ 255 := by norm_num + rw [evmShl_eq (by norm_num) hfit, int256_of_lt hfit255, hNi] + push_cast; ring + +/-- Abstract `r0` monotonicity from the `tod·ev` cross inequality, over opaque even/odd words. +Given the numerator/denominator positivity and `tod1·ev2 ≤ tod2·ev1`, the two `sdiv` quotients are +`≤`-ordered. -/ +theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} + (hE1 : E1 < 2 ^ 256) (hTD1 : TD1 < 2 ^ 256) (hE2 : E2 < 2 ^ 256) (hTD2 : TD2 < 2 ^ 256) + (hev1_lo : (103786963415199049567855548359006885036 : Int) ≤ (E1 : Int)) + (hev1_hi : (E1 : Int) < 2 ^ 127) + (htod1_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD1) + (htod1_hi : int256 TD1 < 42535295865117307932921825928971026432) + (hev2_lo : (103786963415199049567855548359006885036 : Int) ≤ (E2 : Int)) + (hev2_hi : (E2 : Int) < 2 ^ 127) + (htod2_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD2) + (htod2_hi : int256 TD2 < 42535295865117307932921825928971026432) + (hcross : int256 TD1 * (E2 : Int) ≤ int256 TD2 * (E1 : Int)) : + int256 (evmSdiv (evmShl 0x7e (evmAdd E1 TD1)) (evmSub E1 TD1)) ≤ + int256 (evmSdiv (evmShl 0x7e (evmAdd E2 TD2)) (evmSub E2 TD2)) := by + obtain ⟨hadd1, hsub1, hnum1, hden1⟩ := numden_pos_of hE1 hTD1 hev1_lo hev1_hi htod1_lo htod1_hi + obtain ⟨hadd2, hsub2, hnum2, hden2⟩ := numden_pos_of hE2 hTD2 hev2_lo hev2_hi htod2_lo htod2_hi + -- bound the tod magnitude by 2^127 (looser, symbolic) to avoid large-literal kernel work + have htod1_hi' : int256 TD1 < 2 ^ 127 := by + have : (42535295865117307932921825928971026432 : Int) < 2 ^ 127 := by norm_num + omega + have htod2_hi' : int256 TD2 < 2 ^ 127 := by + have : (42535295865117307932921825928971026432 : Int) < 2 ^ 127 := by norm_num + omega + -- numerator/denominator are positive and below 2^128 (signed) + have hN1lt : int256 (evmAdd E1 TD1) < 2 ^ 128 := numSum_lt hadd1 hev1_hi htod1_hi' + have hN2lt : int256 (evmAdd E2 TD2) < 2 ^ 128 := numSum_lt hadd2 hev2_hi htod2_hi' + -- denominator positivity in `int256 (evmSub …)` form + have hD1pos : 0 < int256 (evmSub E1 TD1) := by rw [hsub1]; exact hden1 + have hD2pos : 0 < int256 (evmSub E2 TD2) := by rw [hsub2]; exact hden2 + -- shl dividends transported + have hA1 : int256 (evmShl 0x7e (evmAdd E1 TD1)) = 2 ^ 0x7e * int256 (evmAdd E1 TD1) := + shl126_transport (evmAdd_lt _ _) (le_of_lt (hadd1 ▸ hnum1)) hN1lt + have hA2 : int256 (evmShl 0x7e (evmAdd E2 TD2)) = 2 ^ 0x7e * int256 (evmAdd E2 TD2) := + shl126_transport (evmAdd_lt _ _) (le_of_lt (hadd2 ▸ hnum2)) hN2lt + have hA1pos : 0 < int256 (evmShl 0x7e (evmAdd E1 TD1)) := by + rw [hA1]; exact Int.mul_pos (by positivity) (hadd1 ▸ hnum1) + have hA2pos : 0 < int256 (evmShl 0x7e (evmAdd E2 TD2)) := by + rw [hA2]; exact Int.mul_pos (by positivity) (hadd2 ▸ hnum2) + -- both sdivs are floor divisions of nonnegative magnitudes + rw [evmSdiv_pos_pos (evmShl_lt _ _) (evmSub_lt _ _) (le_of_lt hA1pos) hD1pos, + evmSdiv_pos_pos (evmShl_lt _ _) (evmSub_lt _ _) (le_of_lt hA2pos) hD2pos] + -- cross_to_div with the cross product A1·B2 ≤ A2·B1 + have hdd := cross_to_div (le_of_lt hA1pos) (le_of_lt hA2pos) hD1pos hD2pos (by + rw [hA1, hA2, hsub1, hsub2, hadd1, hadd2] + -- 2^126·(E1+TD1)·(E2−TD2) ≤ 2^126·(E2+TD2)·(E1−TD1) ⟺ tod1·ev2 ≤ tod2·ev1 + have hid1 := cross_identity (E1 : Int) (E2 : Int) (int256 TD1) (int256 TD2) + nlinarith [hcross, hid1]) + exact_mod_cast hdd + +end ExpYul From daad001e978ba9183939a03f0258cafabe53fe6c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 08:50:28 +0200 Subject: [PATCH 032/149] Add per-stage Lipschitz bound for the exp Horner accumulators `stage_lip` bounds how much one Horner stage `evmAdd c (evmShr sh (evmMul prev v))` moves under a bounded change of `v` and the incoming accumulator `prev`, the building block for the near-constancy of `Ev`/`Od` across adjacent inputs. Rests on the floored-sum bound `add_div_le_add`. Stated over opaque words so the deep accumulator tree is never forced. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../exp/ExpProof/ExpProof/Mono/Lipschitz.lean | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean b/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean new file mode 100644 index 000000000..9d4f9f2c9 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean @@ -0,0 +1,113 @@ +import ExpProof.Mono.Stages + +/-! +# A composed Lipschitz bound for the even/odd Horner accumulators + +Adjacent same-octave inputs move the reduced argument `t` by the small step `G ≤ t2 − t1 ≤ G + 1`, +hence move `v = ⌊t²/2^128⌋` by at most `W = G + 1`. The even/odd accumulators `Ev`/`Od` are then +nearly constant: each Horner stage `evmAdd c (evmShr sh (evmMul prev v))` changes by a bounded +amount under a bounded change of `v` (and of the incoming accumulator `prev`), and the five/four +stages compose to the constants `DEv`/`DOd`. + +The single-stage bound rests on a floor-difference fact: shifting two operands right by the same +amount changes their difference by at most the shifted difference plus one. Everything is stated +over opaque words so the deep accumulator trees are never forced into whnf. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- The per-step reduced-argument gap `G = ⌊K27 / 2^107⌋`. -/ +def Gstep : Nat := 340282366920 + +/-- Floored sum bound: `⌊(b + n)/d⌋ ≤ ⌊b/d⌋ + ⌊n/d⌋ + 1`. The two truncations of the split lose at +most one unit jointly. -/ +theorem add_div_le_add {b n d : Nat} (hd : 0 < d) : + (b + n) / d ≤ b / d + n / d + 1 := by + have m1 := Nat.mod_lt b hd + have m2 := Nat.mod_lt n hd + have hb := Nat.div_add_mod b d + have hn := Nat.div_add_mod n d + have key : d * ((b + n) / d) < d * (b / d + n / d + 2) := by + have hbn : b + n < d * (b / d) + d + (d * (n / d) + d) := by omega + have e : d * (b / d + n / d + 2) = d * (b / d) + d * (n / d) + d + d := by ring + have hle : d * ((b + n) / d) ≤ b + n := by rw [Nat.mul_comm]; exact Nat.div_mul_le_self _ _ + omega + have hlt := Nat.lt_of_mul_lt_mul_left key + omega + +/-- One Horner stage's Lipschitz bound. With `prev_i ≤ P`, `v_i ≤ 2^126`, the products fitting a +word, `|v2 − v1| ≤ W` and `|prev2 − prev1| ≤ Dprev`, the stage output `evmAdd c (evmShr sh (evmMul +prev v))` moves by at most `⌊(P·W + 2^126·Dprev)/2^sh⌋ + 1`. Stated as a two-sided `Nat` distance +over opaque words. -/ +theorem stage_lip {c prev1 prev2 v1 v2 P Dprev W sh : Nat} + (hp1 : prev1 ≤ P) (hp2 : prev2 ≤ P) (hv1 : v1 < 2 ^ 126) (hv2 : v2 < 2 ^ 126) + (hvg1 : v1 ≤ v2 + W) (hvg2 : v2 ≤ v1 + W) + (hpg1 : prev1 ≤ prev2 + Dprev) (hpg2 : prev2 ≤ prev1 + Dprev) + (hPV : P * 2 ^ 126 < 2 ^ 256) (hsh : sh < 256) + (hsum1 : c + P * 2 ^ 126 / 2 ^ sh < 2 ^ 256) : + evmAdd c (evmShr sh (evmMul prev1 v1)) ≤ + evmAdd c (evmShr sh (evmMul prev2 v2)) + ((P * W + 2 ^ 126 * Dprev) / 2 ^ sh + 1) ∧ + evmAdd c (evmShr sh (evmMul prev2 v2)) ≤ + evmAdd c (evmShr sh (evmMul prev1 v1)) + ((P * W + 2 ^ 126 * Dprev) / 2 ^ sh + 1) := by + -- products are exact (fit a word) and the stage adds are exact (no overflow) + have hpvbnd : ∀ p v : Nat, p ≤ P → v < 2 ^ 126 → p * v < 2 ^ 256 ∧ p * v ≤ P * 2 ^ 126 := by + intro p v hp hv + have h1 : p * v ≤ P * v := Nat.mul_le_mul_right _ hp + have h2 : P * v ≤ P * 2 ^ 126 := Nat.mul_le_mul_left _ (le_of_lt hv) + exact ⟨by omega, by omega⟩ + obtain ⟨hpv1lt, hpv1le⟩ := hpvbnd prev1 v1 hp1 hv1 + obtain ⟨hpv2lt, hpv2le⟩ := hpvbnd prev2 v2 hp2 hv2 + have hm1 : evmMul prev1 v1 = prev1 * v1 := + evmMul_eq_nat (by omega) (by omega) hpv1lt + have hm2 : evmMul prev2 v2 = prev2 * v2 := + evmMul_eq_nat (by omega) (by omega) hpv2lt + have hs1 : evmShr sh (evmMul prev1 v1) = prev1 * v1 / 2 ^ sh := by + rw [hm1]; exact evmShr_eq_div hsh hpv1lt + have hs2 : evmShr sh (evmMul prev2 v2) = prev2 * v2 / 2 ^ sh := by + rw [hm2]; exact evmShr_eq_div hsh hpv2lt + have hsh1 : prev1 * v1 / 2 ^ sh ≤ P * 2 ^ 126 / 2 ^ sh := Nat.div_le_div_right hpv1le + have hsh2 : prev2 * v2 / 2 ^ sh ≤ P * 2 ^ 126 / 2 ^ sh := Nat.div_le_div_right hpv2le + have he1 : evmAdd c (evmShr sh (evmMul prev1 v1)) = c + prev1 * v1 / 2 ^ sh := by + rw [hs1, evmAdd_eq_nat (by omega) (by omega) (by omega)] + have he2 : evmAdd c (evmShr sh (evmMul prev2 v2)) = c + prev2 * v2 / 2 ^ sh := by + rw [hs2, evmAdd_eq_nat (by omega) (by omega) (by omega)] + rw [he1, he2] + -- bound the product difference: |prev2·v2 − prev1·v1| ≤ P·W + 2^126·Dprev + have hprodbound : ∀ pa pb va vb : Nat, pa ≤ P → pb ≤ P → va < 2 ^ 126 → vb < 2 ^ 126 → + va ≤ vb + W → pa ≤ pb + Dprev → + pa * va ≤ pb * vb + (P * W + 2 ^ 126 * Dprev) := by + intro pa pb va vb hpa hpb hva hvb hvgap hpgap + -- pa·va ≤ pa·(vb + W) = pa·vb + pa·W ≤ pa·vb + P·W + -- pa·vb ≤ (pb + Dprev)·vb = pb·vb + Dprev·vb ≤ pb·vb + Dprev·2^126 + have t1 : pa * va ≤ pa * (vb + W) := Nat.mul_le_mul_left _ hvgap + have t2 : pa * (vb + W) = pa * vb + pa * W := by ring + have t3 : pa * W ≤ P * W := Nat.mul_le_mul_right _ hpa + have t4 : pa * vb ≤ (pb + Dprev) * vb := Nat.mul_le_mul_right _ hpgap + have t5 : (pb + Dprev) * vb = pb * vb + Dprev * vb := by ring + have t6 : Dprev * vb ≤ Dprev * 2 ^ 126 := Nat.mul_le_mul_left _ (le_of_lt hvb) + have t7 : Dprev * 2 ^ 126 = 2 ^ 126 * Dprev := Nat.mul_comm _ _ + omega + have hpd12 := hprodbound prev1 prev2 v1 v2 hp1 hp2 hv1 hv2 hvg1 hpg1 + have hpd21 := hprodbound prev2 prev1 v2 v1 hp2 hp1 hv2 hv1 hvg2 hpg2 + have hsh0 : 0 < 2 ^ sh := Nat.two_pow_pos sh + set B := (P * W + 2 ^ 126 * Dprev) / 2 ^ sh with hB + -- one-sided floor bound: `prev1·v1/2^sh ≤ prev2·v2/2^sh + (B + 1)` + have hone : ∀ pa va pb vb : Nat, pa * va ≤ pb * vb + (P * W + 2 ^ 126 * Dprev) → + pa * va / 2 ^ sh ≤ pb * vb / 2 ^ sh + (B + 1) := by + intro pa va pb vb hbnd + -- `pa·va/2^sh ≤ (pb·vb + N)/2^sh ≤ pb·vb/2^sh + N/2^sh + 1`, and `N/2^sh = B`. + have s1 : pa * va / 2 ^ sh ≤ (pb * vb + (P * W + 2 ^ 126 * Dprev)) / 2 ^ sh := + Nat.div_le_div_right hbnd + have s2 := add_div_le_add (b := pb * vb) (n := P * W + 2 ^ 126 * Dprev) hsh0 + rw [← hB] at s2 + omega + have h12 := hone prev1 v1 prev2 v2 hpd12 + have h21 := hone prev2 v2 prev1 v1 hpd21 + omega + +end ExpYul From e86f5bf6980a46d35973fb906c5a007858fe8e40 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 08:53:45 +0200 Subject: [PATCH 033/149] Add reduced/squared-argument step gaps for adjacent same-octave inputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `tTree_step`: the reduced argument advances by `G` or `G+1` between two inputs adjacent in the signed order within one octave (`K27 = G·2^107 + r`, floor algebra on the two `tTree` sandwiches). `vTree_sandwich`/`vTree_step`: the squared argument `v = ⌊t²/2^128⌋` then moves by at most `G+1`, since `|t2²−t1²| = |t2−t1|·|t2+t1| < (G+1)·2^128` with `|t| < 2^127`. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Mono/Gaps.lean | 111 ++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Gaps.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean b/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean new file mode 100644 index 000000000..dd59d5a53 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean @@ -0,0 +1,111 @@ +import ExpProof.Mono.Lipschitz + +/-! +# Reduced-argument and squared-argument step gaps for adjacent same-octave inputs + +For two inputs adjacent in the signed order (`int256 x2 = int256 x1 + 1`) lying in a common octave +(`kTree x1 = kTree x2`), the reduced argument advances by a fixed step: + +``` +G ≤ int256 (tTree x2) − int256 (tTree x1) ≤ G + 1, G = ⌊K27 / 2^107⌋ = 340282366920. +``` + +From that, the squared argument `v = ⌊t²/2^128⌋` (which drives the even/odd accumulators) moves by +at most `G + 1`: `|t2² − t1²| = |t2 − t1|·|t2 + t1| < (G + 1)·2^128` since `|t| < 2^127`, and the +common-denominator floor loses at most one unit. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- `K27 = G·2^107 + r` with `0 < r < 2^107`: the reduced-argument constant's quotient by the +shift is exactly `G`. -/ +theorem K27_decomp : + (0x279d346de4781f921dd7a89933d54d1f72928 : Int) = + Gstep * 2 ^ 107 + 152274402897802763547896603683112 := by + unfold Gstep; norm_num + +theorem Gstep_rem_pos : (0 : Int) < 152274402897802763547896603683112 := by norm_num +theorem Gstep_rem_lt : (152274402897802763547896603683112 : Int) < 2 ^ 107 := by norm_num + +/-- The reduced-argument step for adjacent same-octave inputs is `G` or `G + 1`. -/ +theorem tTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x1) = int256 (kTree x2)) + (hadj : int256 x2 = int256 x1 + 1) : + (Gstep : Int) ≤ int256 (tTree x2) - int256 (tTree x1) ∧ + int256 (tTree x2) - int256 (tTree x1) ≤ Gstep + 1 := by + obtain ⟨hlo1, hhi1⟩ := tTree_sandwich hx1 hC1 hC01 + obtain ⟨hlo2, hhi2⟩ := tTree_sandwich hx2 hC2 hC02 + rw [hk] at hlo1 hhi1 + -- the `K27·x − LN2·k` term advances by exactly `K27` from x1 to x2 + have hK27 := K27_decomp + have hp107 : (0 : Int) < 2 ^ 107 := by norm_num + set K27 := (0x279d346de4781f921dd7a89933d54d1f72928 : Int) with hK27def + set LN2 := (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) with hLN2def + set k := int256 (kTree x2) + set t1 := int256 (tTree x1) + set t2 := int256 (tTree x2) + set X1 := int256 x1 + set X2 := int256 x2 + -- the affine value at x2 exceeds that at x1 by exactly K27 + have hstep : K27 * X2 - LN2 * k = (K27 * X1 - LN2 * k) + K27 := by rw [hadj]; ring + rw [hstep] at hlo2 hhi2 + -- combine: 2^107·t1 ≤ A < 2^107·t1 + 2^107 and 2^107·t2 ≤ A + K27 < 2^107·t2 + 2^107 + set A := K27 * X1 - LN2 * k + -- with K27 = G·2^107 + r, 0 < r < 2^107 + have hrem_pos := Gstep_rem_pos + have hrem_lt := Gstep_rem_lt + constructor + · nlinarith [hlo1, hhi1, hlo2, hhi2, hK27, hrem_pos, hrem_lt, hp107] + · nlinarith [hlo1, hhi1, hlo2, hhi2, hK27, hrem_pos, hrem_lt, hp107] + +/-- The squared-argument floor sandwich: `2^128·v ≤ t² < 2^128·v + 2^128`, from `vTree_eq`. -/ +theorem vTree_sandwich {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 ^ 128 : Int) * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ + (int256 (tTree x)) ^ 2 < (2 ^ 128 : Int) * (vTree x : Int) + 2 ^ 128 := by + obtain ⟨hveq, _⟩ := vTree_eq hx hC hC0 + rw [hveq] + set a := (int256 (tTree x)) ^ 2 with ha + have h1 := Int.ediv_add_emod a (2 ^ 128) + have h2 := Int.emod_nonneg a (by norm_num : (2 : Int) ^ 128 ≠ 0) + have h3 := Int.emod_lt_of_pos a (by norm_num : (0 : Int) < 2 ^ 128) + constructor <;> nlinarith [h1, h2, h3] + +/-- The squared-argument step for adjacent same-octave inputs is bounded by `G + 1`. -/ +theorem vTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x1) = int256 (kTree x2)) + (hadj : int256 x2 = int256 x1 + 1) : + -((Gstep : Int) + 1) ≤ (vTree x2 : Int) - (vTree x1 : Int) ∧ + (vTree x2 : Int) - (vTree x1 : Int) ≤ Gstep + 1 := by + obtain ⟨htg1, htg2⟩ := tTree_step hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + obtain ⟨htlo1, hthi1⟩ := tTree_bound hx1 hC1 hC01 + obtain ⟨htlo2, hthi2⟩ := tTree_bound hx2 hC2 hC02 + obtain ⟨hvlo1, hvhi1⟩ := vTree_sandwich hx1 hC1 hC01 + obtain ⟨hvlo2, hvhi2⟩ := vTree_sandwich hx2 hC2 hC02 + have hGpos : (0 : Int) ≤ Gstep := by unfold Gstep; norm_num + have hp127 : (2 : Int) ^ 127 = 170141183460469231731687303715884105728 := by norm_num + have hp128 : (2 : Int) ^ 128 = 340282366920938463463374607431768211456 := by norm_num + rw [hp127] at htlo1 hthi1 htlo2 hthi2 + rw [hp128] at hvlo1 hvhi1 hvlo2 hvhi2 + set t1 := int256 (tTree x1) + set t2 := int256 (tTree x2) + set v1 := (vTree x1 : Int) + set v2 := (vTree x2 : Int) + -- `t2² − t1² = (t2 − t1)(t2 + t1)`, with `|t2 − t1| ≤ G + 1`, `|t1 + t2| < 2^128`. + have hsqdiff : t2 ^ 2 - t1 ^ 2 = (t2 - t1) * (t2 + t1) := by ring + have hGv : (Gstep : Int) = 340282366920 := by unfold Gstep; norm_num + rw [hGv] at htg1 htg2 ⊢ + constructor + · nlinarith [hvlo1, hvhi1, hvlo2, hvhi2, htg1, htg2, htlo1, hthi1, htlo2, hthi2, hsqdiff] + · nlinarith [hvlo1, hvhi1, hvlo2, hvhi2, htg1, htg2, htlo1, hthi1, htlo2, hthi2, hsqdiff] + +end ExpYul From e71fca9acbdd9440c0ca6d80b463ec81a53ddeb7 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 09:01:10 +0200 Subject: [PATCH 034/149] Add composed Lipschitz bounds for the exp even/odd accumulators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `evTree_lip`/`odTree_lip`: telescoping the per-stage `stage_lip` through the five even / four odd Horner stages bounds the accumulator change by `DEv = 42701611664` / `DOd = 5327301648` under a squared-argument gap `|v2 − v1| ≤ W = G + 1`. The stages are named layers (`evS0..evS3`, `odS0..odS2`) with their `2^k` ceilings re-derived from the `stage_bounds` machinery, kept opaque so the deep accumulator tree is never forced. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../exp/ExpProof/ExpProof/Mono/EvOdLip.lean | 229 ++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean new file mode 100644 index 000000000..15b114f50 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean @@ -0,0 +1,229 @@ +import ExpProof.Mono.Gaps + +/-! +# Near-constancy of the even/odd accumulators across adjacent inputs + +Telescoping `stage_lip` through the five even / four odd Horner stages, with the squared-argument +gap `|v2 − v1| ≤ W = G + 1` from `vTree_step`, bounds the change of the accumulators: + +``` +|evTree x2 − evTree x1| ≤ DEv = 42701611664, +|odTree x2 − odTree x1| ≤ DOd = 5327301648. +``` + +The intermediate per-stage prev bounds reuse the chained `2^k` ceilings established inside +`evTree_facts`/`odTree_facts`; each stage application keeps the accumulator words opaque so the +deep tree is never forced. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- Two-sided distance abbreviation. -/ +def dist_le (a b D : Nat) : Prop := a ≤ b + D ∧ b ≤ a + D + +theorem dist_le.symm {a b D : Nat} (h : dist_le a b D) : dist_le b a D := ⟨h.2, h.1⟩ + +/-- The leading even stage `a4 + ⌊v/2^29⌋` moves by at most `(W >> 0x1d) + 1` under `|v2−v1| ≤ W`. -/ +theorem evLead_lip {c v1 v2 W : Nat} (hc : c < 2 ^ 255) (hv1 : v1 < 2 ^ 126) (hv2 : v2 < 2 ^ 126) + (hvg1 : v1 ≤ v2 + W) (hvg2 : v2 ≤ v1 + W) : + dist_le (evmAdd c (evmShr 0x1d v1)) (evmAdd c (evmShr 0x1d v2)) ((W / 2 ^ 0x1d) + 1) := by + have hd1 : evmShr 0x1d v1 = v1 / 2 ^ 0x1d := evmShr_eq_div (by norm_num) (by omega) + have hd2 : evmShr 0x1d v2 = v2 / 2 ^ 0x1d := evmShr_eq_div (by norm_num) (by omega) + have hsh0 : (0 : Nat) < 2 ^ 0x1d := Nat.two_pow_pos _ + -- `v/2^29 < 2^97`, so the sum fits below `2^256` + have hb1 : v1 / 2 ^ 0x1d < 2 ^ 97 := by + have : v1 / 2 ^ 0x1d < 2 ^ 126 / 2 ^ 0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv1 + have he : (2:Nat) ^ 126 / 2 ^ 0x1d = 2 ^ 97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] + omega + have hb2 : v2 / 2 ^ 0x1d < 2 ^ 97 := by + have : v2 / 2 ^ 0x1d < 2 ^ 126 / 2 ^ 0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv2 + have he : (2:Nat) ^ 126 / 2 ^ 0x1d = 2 ^ 97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] + omega + have hlt1 : v1 / 2 ^ 0x1d < 2 ^ 256 := by + have h : (2:Nat) ^ 97 < 2 ^ 256 := by norm_num + omega + have hlt2 : v2 / 2 ^ 0x1d < 2 ^ 256 := by + have h : (2:Nat) ^ 97 < 2 ^ 256 := by norm_num + omega + have hc256 : c < 2 ^ 256 := by + have h : (2:Nat) ^ 255 < 2 ^ 256 := by norm_num + omega + have hsm : (2:Nat)^255 + 2^97 < 2^256 := by norm_num + have he1 : evmAdd c (evmShr 0x1d v1) = c + v1 / 2 ^ 0x1d := by + rw [hd1, evmAdd_eq_nat hc256 hlt1 (by omega)] + have he2 : evmAdd c (evmShr 0x1d v2) = c + v2 / 2 ^ 0x1d := by + rw [hd2, evmAdd_eq_nat hc256 hlt2 (by omega)] + rw [he1, he2] + -- |v1/d − v2/d| ≤ |v1−v2|/d + 1 ≤ W/d + 1, via the additive floored-sum bound + have h12 : v1 / 2 ^ 0x1d ≤ v2 / 2 ^ 0x1d + (W / 2 ^ 0x1d + 1) := by + have s1 : v1 / 2 ^ 0x1d ≤ (v2 + W) / 2 ^ 0x1d := Nat.div_le_div_right hvg1 + have s2 := add_div_le_add (b := v2) (n := W) hsh0 + omega + have h21 : v2 / 2 ^ 0x1d ≤ v1 / 2 ^ 0x1d + (W / 2 ^ 0x1d + 1) := by + have s1 : v2 / 2 ^ 0x1d ≤ (v1 + W) / 2 ^ 0x1d := Nat.div_le_div_right hvg2 + have s2 := add_div_le_add (b := v1) (n := W) hsh0 + omega + exact ⟨by omega, by omega⟩ + +/-- The leading odd stage is the bare constant `b4` (no `v`-dependence): distance `0`. -/ +theorem odLead_const (c : Nat) : dist_le c c 0 := ⟨by omega, by omega⟩ + +/-- `stage_lip` repackaged in the `dist_le` form for a fixed stage shift. -/ +theorem stage_lip_dist {c prev1 prev2 v1 v2 P Dprev W sh : Nat} + (hp1 : prev1 ≤ P) (hp2 : prev2 ≤ P) (hv1 : v1 < 2 ^ 126) (hv2 : v2 < 2 ^ 126) + (hvg1 : v1 ≤ v2 + W) (hvg2 : v2 ≤ v1 + W) + (hpd : dist_le prev1 prev2 Dprev) + (hPV : P * 2 ^ 126 < 2 ^ 256) (hsh : sh < 256) + (hsum1 : c + P * 2 ^ 126 / 2 ^ sh < 2 ^ 256) : + dist_le (evmAdd c (evmShr sh (evmMul prev1 v1))) (evmAdd c (evmShr sh (evmMul prev2 v2))) + ((P * W + 2 ^ 126 * Dprev) / 2 ^ sh + 1) := + stage_lip hp1 hp2 hv1 hv2 hvg1 hvg2 hpd.1 hpd.2 hPV hsh hsum1 + +/-! ## The even Horner stages as named layers, with their `2^k` ceilings -/ + +def evS0 (x : Nat) : Nat := evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d (vTree x)) +def evS1 (x : Nat) : Nat := evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul (evS0 x) (vTree x))) +def evS2 (x : Nat) : Nat := evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul (evS1 x) (vTree x))) +def evS3 (x : Nat) : Nat := evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul (evS2 x) (vTree x))) + +theorem evTree_layers (x : Nat) : + evTree x = evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul (evS3 x) (vTree x))) := + rfl + +theorem evS0_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evS0 x < 2 ^ 113 := ev0_lt hv + +theorem evS1_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evS1 x < 2 ^ 121 := by + have := (stage_bounds (c := 0x9a036222e11aee18465042f8ea64c8) (prev := evS0 x) (v := vTree x) + (P := 2 ^ 113) (V := 2 ^ 126) (sh := 0x82) (evS0_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num)).2 + rw [pvd 113 126 130 109 (by norm_num)] at this; unfold evS1; omega + +theorem evS2_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evS2 x < 2 ^ 129 := by + have := (stage_bounds (c := 0x9064d965e1c4863b73604e0ddbec53f9) (prev := evS1 x) (v := vTree x) + (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x80) (evS1_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 128 119 (by norm_num)] at this; unfold evS2; omega + +theorem evS3_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evS3 x < 2 ^ 129 := by + have := (stage_bounds (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (prev := evS2 x) (v := vTree x) + (P := 2 ^ 129) (V := 2 ^ 126) (sh := 0x86) (evS2_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num)).2 + rw [pvd 129 126 134 121 (by norm_num)] at this; unfold evS3; omega + +/-! ## The odd Horner stages as named layers -/ + +def odS0 (x : Nat) : Nat := evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb (vTree x))) +def odS1 (x : Nat) : Nat := evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul (odS0 x) (vTree x))) +def odS2 (x : Nat) : Nat := evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul (odS1 x) (vTree x))) + +theorem odTree_layers (x : Nat) : + odTree x = evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul (odS2 x) (vTree x))) := + rfl + +theorem odS0_lt {x : Nat} (hv : vTree x < 2 ^ 126) : odS0 x < 2 ^ 121 := by + have := (stage_bounds (c := 0xc926ddbf3830ca5561cc01585402d0) (prev := 0xdc07aff85e5bb5629d0fb64a84bb) + (v := vTree x) (P := 2 ^ 112) (V := 2 ^ 126) (sh := 0x83) (by norm_num) hv (by norm_num) + (by norm_num) (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num)).2 + rw [pvd 112 126 131 107 (by norm_num)] at this; unfold odS0; omega + +theorem odS1_lt {x : Nat} (hv : vTree x < 2 ^ 126) : odS1 x < 2 ^ 121 := by + have := (stage_bounds (c := 0xad4506b00b1246c7e5b4fd33e1201b) (prev := odS0 x) (v := vTree x) + (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x89) (odS0_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 137 110 (by norm_num)] at this; unfold odS1; omega + +theorem odS2_lt {x : Nat} (hv : vTree x < 2 ^ 126) : odS2 x < 2 ^ 129 := by + have := (stage_bounds (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (prev := odS1 x) (v := vTree x) + (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x7f) (odS1_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 127 120 (by norm_num)] at this; unfold odS2; omega + +/-! ## Composed Lipschitz bounds -/ + +/-- The step width `W = G + 1`. -/ +def Wstep : Nat := 340282366921 + +theorem Wstep_eq : Wstep = Gstep + 1 := by unfold Wstep Gstep; rfl + +/-- **Even accumulator near-constancy.** Under a squared-argument gap `|v2 − v1| ≤ W` the even +accumulator changes by at most `DEv = 42701611664`. -/ +theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 126) (hv2 : vTree x2 < 2 ^ 126) + (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : + dist_le (evTree x1) (evTree x2) 42701611664 := by + -- leading stage + have d0 : dist_le (evS0 x1) (evS0 x2) 634 := by + have h := evLead_lip (c := 0xb9aacfad41060587203a79af0ebc) (W := Wstep) (by norm_num) hv1 hv2 hg1 hg2 + have he : (Wstep / 2 ^ 0x1d) + 1 = 634 := by unfold Wstep; decide + rw [he] at h; exact h + -- stage 1 + have d1 : dist_le (evS1 x1) (evS1 x2) 2596189 := by + have h := stage_lip_dist (c := 0x9a036222e11aee18465042f8ea64c8) (P := 2 ^ 113) (sh := 0x82) (W := Wstep) + (Dprev := 634) (le_of_lt (evS0_lt hv1)) (le_of_lt (evS0_lt hv2)) hv1 hv2 hg1 hg2 d0 + (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 113 * Wstep + 2 ^ 126 * 634) / 2 ^ 0x82 + 1 = 2596189 := by unfold Wstep; decide + rw [he] at h; exact h + -- stage 2 + have d2 : dist_le (evS2 x1) (evS2 x2) 2659105039 := by + have h := stage_lip_dist (c := 0x9064d965e1c4863b73604e0ddbec53f9) (P := 2 ^ 121) (sh := 0x80) (W := Wstep) + (Dprev := 2596189) (le_of_lt (evS1_lt hv1)) (le_of_lt (evS1_lt hv2)) hv1 hv2 hg1 hg2 d1 + (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 121 * Wstep + 2 ^ 126 * 2596189) / 2 ^ 0x80 + 1 = 2659105039 := by + unfold Wstep; decide + rw [he] at h; exact h + -- stage 3 + have d3 : dist_le (evS3 x1) (evS3 x2) 10644211096 := by + have h := stage_lip_dist (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (P := 2 ^ 129) (sh := 0x86) (W := Wstep) + (Dprev := 2659105039) (le_of_lt (evS2_lt hv1)) (le_of_lt (evS2_lt hv2)) hv1 hv2 hg1 hg2 d2 + (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 129 * Wstep + 2 ^ 126 * 2659105039) / 2 ^ 0x86 + 1 = 10644211096 := by + unfold Wstep; decide + rw [he] at h; exact h + -- final stage + have hfin := stage_lip_dist (c := 0x4e14a45e8ec305e233e11b4174e214ac) (P := 2 ^ 129) (sh := 0x84) (W := Wstep) + (Dprev := 10644211096) (le_of_lt (evS3_lt hv1)) (le_of_lt (evS3_lt hv2)) hv1 hv2 hg1 hg2 d3 + (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 129 * Wstep + 2 ^ 126 * 10644211096) / 2 ^ 0x84 + 1 = 42701611664 := by + unfold Wstep; decide + rw [he] at hfin + rw [evTree_layers, evTree_layers]; exact hfin + +/-- **Odd accumulator near-constancy.** Under a squared-argument gap `|v2 − v1| ≤ W` the odd +accumulator changes by at most `DOd = 5327301648`. -/ +theorem odTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 126) (hv2 : vTree x2 < 2 ^ 126) + (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : + dist_le (odTree x1) (odTree x2) 5327301648 := by + -- stage 0: prev is the constant leading coefficient (distance 0) + have d0 : dist_le (odS0 x1) (odS0 x2) 649038 := by + have h := stage_lip_dist (c := 0xc926ddbf3830ca5561cc01585402d0) (P := 2 ^ 112) (sh := 0x83) (W := Wstep) + (Dprev := 0) (prev1 := 0xdc07aff85e5bb5629d0fb64a84bb) (prev2 := 0xdc07aff85e5bb5629d0fb64a84bb) + (by norm_num) (by norm_num) hv1 hv2 hg1 hg2 (odLead_const _) (by norm_num) (by norm_num) + (by norm_num) + have he : (2 ^ 112 * Wstep + 2 ^ 126 * 0) / 2 ^ 0x83 + 1 = 649038 := by unfold Wstep; decide + rw [he] at h; exact h + have d1 : dist_le (odS1 x1) (odS1 x2) 5192614 := by + have h := stage_lip_dist (c := 0xad4506b00b1246c7e5b4fd33e1201b) (P := 2 ^ 121) (sh := 0x89) (W := Wstep) + (Dprev := 649038) (le_of_lt (odS0_lt hv1)) (le_of_lt (odS0_lt hv2)) hv1 hv2 hg1 hg2 d0 + (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 121 * Wstep + 2 ^ 126 * 649038) / 2 ^ 0x89 + 1 = 5192614 := by unfold Wstep; decide + rw [he] at h; exact h + have d2 : dist_le (odS2 x1) (odS2 x2) 5319508291 := by + have h := stage_lip_dist (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (P := 2 ^ 121) (sh := 0x7f) (W := Wstep) + (Dprev := 5192614) (le_of_lt (odS1_lt hv1)) (le_of_lt (odS1_lt hv2)) hv1 hv2 hg1 hg2 d1 + (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 121 * Wstep + 2 ^ 126 * 5192614) / 2 ^ 0x7f + 1 = 5319508291 := by + unfold Wstep; decide + rw [he] at h; exact h + have hfin := stage_lip_dist (c := 0x270a522f476182f119f08da0ba710a56) (P := 2 ^ 129) (sh := 0x87) (W := Wstep) + (Dprev := 5319508291) (le_of_lt (odS2_lt hv1)) (le_of_lt (odS2_lt hv2)) hv1 hv2 hg1 hg2 d2 + (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 129 * Wstep + 2 ^ 126 * 5319508291) / 2 ^ 0x87 + 1 = 5327301648 := by + unfold Wstep; decide + rw [he] at hfin + rw [odTree_layers, odTree_layers]; exact hfin + +end ExpYul From fc50b860e11e4b4d19e39fd0c72cece499e5a444 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 09:10:27 +0200 Subject: [PATCH 035/149] Prove the same-octave cross inequality tod1*ev2 <= tod2*ev1 `smooth_cross`: for adjacent same-octave inputs the smooth inequality `t1*od1*ev2 + 2^128*ev1 <= t2*od2*ev1` holds, with the gain `d*od2*ev1` (`G <= d <= G+1`) dominating the loss controlled by the Lipschitz near-constancy of `Ev`/`Od` and the `|t| < 2^127` bound. `tod_cross` then bridges through the `tod` floor sandwich (`todTree_bound`) and `ev1 > 0` to the cross inequality that `r0_mono_of_cross` consumes. Both axiom-clean; the analytic cores are abstract over opaque values so the deep accumulator tree is never forced. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../exp/ExpProof/ExpProof/Mono/CrossCert.lean | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean new file mode 100644 index 000000000..aa3e076f2 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean @@ -0,0 +1,230 @@ +import ExpProof.Mono.EvOdLip +import ExpProof.Mono.Cross + +/-! +# The same-octave cross inequality + +For adjacent same-octave inputs the reciprocal-symmetric quotient `r0` is monotone. By the +cross-multiplication identity (`Cross.lean`) this reduces to `tod1·ev2 ≤ tod2·ev1`, which the floor +sandwich for `tod` (`Quot.todTree_bound`) reduces in turn to the **smooth** inequality + +``` +t1·od1·ev2 + 2^128·ev1 ≤ t2·od2·ev1. +``` + +The smooth inequality holds with large margin: writing `t2 = t1 + d`, `G ≤ d ≤ G + 1`, the gain +`d·od2·ev1 ≥ G·b0·a0` dominates the loss `2^128·ev1 + |t1|·|od1·ev2 − od2·ev1|`, the latter bounded +through the Lipschitz near-constancy of `Ev`/`Od` (`EvOdLip.lean`). +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- The even accumulator's signed value is its (nonnegative) Nat value, in `[a0, 2^127)`. -/ +theorem evTree_int {x : Nat} (hv : vTree x < 2 ^ 126) : + (103786963415199049567855548359006885036 : Int) ≤ (evTree x : Int) ∧ + (evTree x : Int) < 2 ^ 127 := by + obtain ⟨hlo, hhi⟩ := evTree_facts hv + constructor + · have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo + rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 by + norm_num] at this + exact this + · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hhi + rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this + +/-- The odd accumulator's signed value is its (nonnegative) Nat value, in `[b0, 2^126)`. -/ +theorem odTree_int {x : Nat} (hv : vTree x < 2 ^ 126) : + (51893481707599524783927774179503442518 : Int) ≤ (odTree x : Int) ∧ + (odTree x : Int) < 2 ^ 126 := by + obtain ⟨hlo, hhi⟩ := odTree_facts hv + constructor + · have : (0x270a522f476182f119f08da0ba710a56 : Int) ≤ (odTree x : Int) := by exact_mod_cast hlo + rw [show (0x270a522f476182f119f08da0ba710a56 : Int) = 51893481707599524783927774179503442518 by + norm_num] at this + exact this + · have : (odTree x : Int) < (2 ^ 126 : Nat) := by exact_mod_cast hhi + rw [show ((2 ^ 126 : Nat) : Int) = 2 ^ 126 by norm_num] at this; exact this + +/-- The even/odd accumulators' signed difference is bounded by `DEv`/`DOd` (the Lipschitz bound +transported to `Int`). -/ +theorem evTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 126) (hv2 : vTree x2 < 2 ^ 126) + (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : + -(42701611664 : Int) ≤ (evTree x1 : Int) - (evTree x2 : Int) ∧ + (evTree x1 : Int) - (evTree x2 : Int) ≤ 42701611664 := by + obtain ⟨h1, h2⟩ := evTree_lip hv1 hv2 hg1 hg2 + have c1 : ((evTree x1 : Nat) : Int) ≤ (evTree x2 : Int) + 42701611664 := by exact_mod_cast h1 + have c2 : ((evTree x2 : Nat) : Int) ≤ (evTree x1 : Int) + 42701611664 := by exact_mod_cast h2 + omega + +theorem odTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 126) (hv2 : vTree x2 < 2 ^ 126) + (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : + -(5327301648 : Int) ≤ (odTree x1 : Int) - (odTree x2 : Int) ∧ + (odTree x1 : Int) - (odTree x2 : Int) ≤ 5327301648 := by + obtain ⟨h1, h2⟩ := odTree_lip hv1 hv2 hg1 hg2 + have c1 : ((odTree x1 : Nat) : Int) ≤ (odTree x2 : Int) + 5327301648 := by exact_mod_cast h1 + have c2 : ((odTree x2 : Nat) : Int) ≤ (odTree x1 : Int) + 5327301648 := by exact_mod_cast h2 + omega + +/-- The squared-argument step, as a `Nat` two-sided gap (`vTree x_i ≤ vTree x_j + W`). -/ +theorem vTree_step_nat {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x1) = int256 (kTree x2)) + (hadj : int256 x2 = int256 x1 + 1) : + vTree x1 ≤ vTree x2 + Wstep ∧ vTree x2 ≤ vTree x1 + Wstep := by + obtain ⟨hlo, hhi⟩ := vTree_step hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + have hW : (Wstep : Int) = Gstep + 1 := by unfold Wstep Gstep; norm_num + have c1 : (vTree x1 : Int) ≤ (vTree x2 : Int) + Wstep := by rw [hW]; omega + have c2 : (vTree x2 : Int) ≤ (vTree x1 : Int) + Wstep := by rw [hW]; omega + exact ⟨by exact_mod_cast c1, by exact_mod_cast c2⟩ + +/-- Abstract smooth certificate over opaque accumulator/argument values. The gain `d·od2·ev1` +dominates the loss `2^128·ev2 + |t1|·|od1·ev2 − od2·ev1|`, where the cross difference is controlled +by the Lipschitz near-constancy. -/ +theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} + (hd1 : (340282366920 : Int) ≤ d) (hd2 : d ≤ 340282366921) + (ht1lo : -(170141183460469231731687303715884105728 : Int) < t1) + (ht1hi : t1 < 170141183460469231731687303715884105728) + (hev1lo : (103786963415199049567855548359006885036 : Int) ≤ ev1) + (hev1hi : ev1 < 170141183460469231731687303715884105728) + (hev2lo : (103786963415199049567855548359006885036 : Int) ≤ ev2) + (hev2hi : ev2 < 170141183460469231731687303715884105728) + (hod1lo : (51893481707599524783927774179503442518 : Int) ≤ od1) + (hod1hi : od1 < 85070591730234615865843651857942052864) + (hod2lo : (51893481707599524783927774179503442518 : Int) ≤ od2) + (hod2hi : od2 < 85070591730234615865843651857942052864) + (hevd1 : -(42701611664 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 42701611664) + (hodd1 : -(5327301648 : Int) ≤ od1 - od2) (hodd2 : od1 - od2 ≤ 5327301648) : + t1 * od1 * ev2 + 340282366920938463463374607431768211456 * ev1 ≤ + (t1 + d) * od2 * ev1 := by + -- cross difference `cd = od1·ev2 − od2·ev1`, bounded by `CB = DOd·2^127 + 2^126·DEv` + have hcd_eq : od1 * ev2 - od2 * ev1 = (od1 - od2) * ev2 + od2 * (ev2 - ev1) := by ring + -- bound each piece + have hev2nn : (0 : Int) ≤ ev2 := by linarith + have hod2nn : (0 : Int) ≤ od2 := by linarith + have hp1 : (od1 - od2) * ev2 ≤ 5327301648 * 170141183460469231731687303715884105728 := by + nlinarith [hodd2, hodd1, hev2nn, hev2hi] + have hp1' : -(5327301648 * 170141183460469231731687303715884105728 : Int) ≤ (od1 - od2) * ev2 := by + nlinarith [hodd1, hev2nn, hev2hi] + have hp2 : od2 * (ev2 - ev1) ≤ 85070591730234615865843651857942052864 * 42701611664 := by + nlinarith [hod2nn, hod2hi, hevd1, hevd2] + have hp2' : -(85070591730234615865843651857942052864 * 42701611664 : Int) ≤ od2 * (ev2 - ev1) := by + nlinarith [hod2nn, hod2hi, hevd1, hevd2] + -- so |cd| ≤ CB + set CB : Int := 5327301648 * 170141183460469231731687303715884105728 + + 85070591730234615865843651857942052864 * 42701611664 with hCB + have hcd_hi : od1 * ev2 - od2 * ev1 ≤ CB := by rw [hcd_eq, hCB]; linarith + have hcd_lo : -CB ≤ od1 * ev2 - od2 * ev1 := by rw [hcd_eq, hCB]; linarith + -- `t1·(od1·ev2 − od2·ev1) ≤ 2^127·CB` + have hCBnn : (0 : Int) ≤ CB := by rw [hCB]; norm_num + have htcd : t1 * (od1 * ev2 - od2 * ev1) ≤ 170141183460469231731687303715884105728 * CB := by + rcases le_total 0 t1 with ht | ht + · have h1 : t1 * (od1 * ev2 - od2 * ev1) ≤ t1 * CB := + mul_le_mul_left_nonneg hcd_hi ht + have h2 : t1 * CB ≤ 170141183460469231731687303715884105728 * CB := + mul_le_mul_right_nonneg (le_of_lt ht1hi) hCBnn + linarith + · have h1 : t1 * (od1 * ev2 - od2 * ev1) ≤ t1 * (-CB) := by + have := mul_le_mul_left_nonneg hcd_lo (show (0:Int) ≤ -t1 by linarith) + nlinarith [this] + have h2 : t1 * (-CB) ≤ 170141183460469231731687303715884105728 * CB := by nlinarith [ht1lo, hCBnn, ht] + linarith + -- gain: d·od2·ev1 ≥ 340282366920·b0·a0 + have hev1nn : (0 : Int) ≤ ev1 := by linarith + have hgain : (340282366920 : Int) * 51893481707599524783927774179503442518 * + 103786963415199049567855548359006885036 ≤ d * od2 * ev1 := by + have g1 : (340282366920 : Int) * 51893481707599524783927774179503442518 ≤ d * od2 := by + have := mul_le_mul hd1 hod2lo (by norm_num : (0:Int) ≤ 51893481707599524783927774179503442518) (by linarith) + linarith + have g2 : (340282366920 : Int) * 51893481707599524783927774179503442518 * + 103786963415199049567855548359006885036 ≤ (d * od2) * ev1 := + mul_le_mul g1 hev1lo (by norm_num) (by positivity) + linarith [g2] + -- assemble: goal `t1·od1·ev2 + 2^128·ev2 ≤ (t1+d)·od2·ev1 = t1·od2·ev1 + d·od2·ev1` + -- `t1·od1·ev2 − t1·od2·ev1 = t1·(od1·ev2 − od2·ev1) ≤ 2^127·CB` + have hexpand : (t1 + d) * od2 * ev1 = t1 * od2 * ev1 + d * od2 * ev1 := by ring + have hdecomp : t1 * od1 * ev2 - t1 * od2 * ev1 = t1 * (od1 * ev2 - od2 * ev1) := by ring + rw [hexpand] + -- numeric closure: 2^128·ev2 + 2^127·CB ≤ gain, and ev2 < 2^127 + have hkey : (340282366920938463463374607431768211456 : Int) * ev1 + + 170141183460469231731687303715884105728 * CB ≤ + (340282366920 : Int) * 51893481707599524783927774179503442518 * + 103786963415199049567855548359006885036 := by + rw [hCB] + nlinarith [hev1hi] + nlinarith [htcd, hgain, hkey, hdecomp] + +/-- **The smooth certificate.** For adjacent same-octave inputs, +`t1·od1·ev2 + 2^128·ev2 ≤ t2·od2·ev1`. -/ +theorem smooth_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x1) = int256 (kTree x2)) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (tTree x1) * (odTree x1 : Int) * (evTree x2 : Int) + + 2 ^ 128 * (evTree x1 : Int) ≤ + int256 (tTree x2) * (odTree x2 : Int) * (evTree x1 : Int) := by + have hv1 : vTree x1 < 2 ^ 126 := (vTree_eq hx1 hC1 hC01).2 + have hv2 : vTree x2 < 2 ^ 126 := (vTree_eq hx2 hC2 hC02).2 + obtain ⟨hg1, hg2⟩ := vTree_step_nat hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + obtain ⟨hev1lo, hev1hi⟩ := evTree_int hv1 + obtain ⟨hev2lo, hev2hi⟩ := evTree_int hv2 + obtain ⟨hod1lo, hod1hi⟩ := odTree_int hv1 + obtain ⟨hod2lo, hod2hi⟩ := odTree_int hv2 + obtain ⟨hevd1, hevd2⟩ := evTree_lip_int hv1 hv2 hg1 hg2 + obtain ⟨hodd1, hodd2⟩ := odTree_lip_int hv1 hv2 hg1 hg2 + obtain ⟨htg1, htg2⟩ := tTree_step hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + obtain ⟨htlo1, hthi1⟩ := tTree_bound hx1 hC1 hC01 + -- numeric rewrites of the power bounds + have hGv : (Gstep : Int) = 340282366920 := by unfold Gstep; norm_num + rw [hGv] at htg1 htg2 + rw [show (2 : Int) ^ 127 = 170141183460469231731687303715884105728 by norm_num] at hev1hi hev2hi htlo1 hthi1 + rw [show (2 : Int) ^ 126 = 85070591730234615865843651857942052864 by norm_num] at hod1hi hod2hi + rw [show (2 : Int) ^ 128 = 340282366920938463463374607431768211456 by norm_num] + -- t2 = t1 + d, d ∈ [G, G+1] + have ht2eq : int256 (tTree x2) = int256 (tTree x1) + (int256 (tTree x2) - int256 (tTree x1)) := by + ring + rw [ht2eq] + exact smooth_cross_of htg1 htg2 htlo1 hthi1 hev1lo hev1hi hev2lo hev2hi hod1lo hod1hi hod2lo hod2hi + hevd1 hevd2 hodd1 hodd2 + +/-- Abstract bridge: from the two `tod` floor sandwiches, the smooth inequality, and `ev1 > 0`, +the cross inequality `tod1·ev2 ≤ tod2·ev1` follows. -/ +theorem tod_cross_of {tod1 tod2 tprod1 tprod2 ev1 ev2 : Int} + (hfl1 : (2 : Int) ^ 128 * tod1 ≤ tprod1) (hfu2 : tprod2 < 2 ^ 128 * tod2 + 2 ^ 128) + (hev1pos : 0 < ev1) (hev2nn : 0 ≤ ev2) + (hsmooth : tprod1 * ev2 + 2 ^ 128 * ev1 ≤ tprod2 * ev1) : + tod1 * ev2 ≤ tod2 * ev1 := by + -- 2^128·tod1·ev2 ≤ tprod1·ev2 ≤ tprod2·ev1 − 2^128·ev1 < 2^128·tod2·ev1 + have hp : (0 : Int) < 2 ^ 128 := by norm_num + have s1 : 2 ^ 128 * tod1 * ev2 ≤ tprod1 * ev2 := mul_le_mul_right_nonneg hfl1 hev2nn + have s2 : tprod2 * ev1 < (2 ^ 128 * tod2 + 2 ^ 128) * ev1 := + Int.mul_lt_mul_of_pos_right hfu2 hev1pos + -- 2^128·tod1·ev2 ≤ tprod1·ev2 ≤ tprod2·ev1 − 2^128·ev1 < 2^128·tod2·ev1 + 2^128·ev1 − 2^128·ev1 + have hchain : 2 ^ 128 * (tod1 * ev2) < 2 ^ 128 * (tod2 * ev1) := by nlinarith [s1, s2, hsmooth] + exact le_of_lt (lt_of_mul_lt_mul_left hchain (by norm_num : (0:Int) ≤ 2 ^ 128)) + +/-- **The same-octave cross inequality.** For adjacent same-octave inputs, +`tod1·ev2 ≤ tod2·ev1`. -/ +theorem tod_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x1) = int256 (kTree x2)) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (todTree x1) * (evTree x2 : Int) ≤ int256 (todTree x2) * (evTree x1 : Int) := by + obtain ⟨_, _, hfl1, _⟩ := todTree_bound hx1 hC1 hC01 + obtain ⟨_, _, _, hfu2⟩ := todTree_bound hx2 hC2 hC02 + have hv1 : vTree x1 < 2 ^ 126 := (vTree_eq hx1 hC1 hC01).2 + have hv2 : vTree x2 < 2 ^ 126 := (vTree_eq hx2 hC2 hC02).2 + have hev1pos : 0 < (evTree x1 : Int) := by + have := (evTree_int hv1).1; linarith + have hev2nn : 0 ≤ (evTree x2 : Int) := Int.natCast_nonneg _ + exact tod_cross_of hfl1 hfu2 hev1pos hev2nn + (smooth_cross hx1 hx2 hC1 hC01 hC2 hC02 hk hadj) + +end ExpYul From 5d1140dc541fc69442e46be4d5d7e34fbc87cdc0 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 09:14:14 +0200 Subject: [PATCH 036/149] Prove the within-octave adjacent r0/r1 monotone step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `r0_mono_adjacent`: feeds the same-octave cross inequality `tod_cross` to `r0_mono_of_cross` for two inputs adjacent in the signed order within an octave. `r1_mono_adjacent`: with `k` fixed the closing shift `126 − k` is fixed (`closing_shift_eq`, via `int256` injectivity on canonical words), so the arithmetic-shift floor of the nondecreasing `WAD·r0 − MARGIN` is nondecreasing. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../exp/ExpProof/ExpProof/Mono/StepMono.lean | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/StepMono.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean new file mode 100644 index 000000000..caa250a44 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean @@ -0,0 +1,117 @@ +import ExpProof.Mono.CrossCert +import ExpProof.Mono.RangeNonneg + +/-! +# The within-octave adjacent step + +For two inputs adjacent in the signed order (`int256 x2 = int256 x1 + 1`) in a common octave, the +quotient `r0` is nondecreasing (`r0_mono_adjacent`, via the cross inequality `tod_cross` fed to +`r0_mono_of_cross`), and hence so is the closing accumulator `r1` (`r1_mono_adjacent`): with `k` +fixed the closing shift `126 − k` is fixed, and the arithmetic-shift floor of the nondecreasing +`WAD·r0 − MARGIN` is nondecreasing. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- The `tod`-bound hypotheses of `r0_mono_of_cross`, in the `2^125` form. -/ +theorem todTree_cross_bounds {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + -(42535295865117307932921825928971026432 : Int) ≤ int256 (todTree x) ∧ + int256 (todTree x) < 42535295865117307932921825928971026432 := by + obtain ⟨hlo, hhi, _, _⟩ := todTree_bound hx hC hC0 + refine ⟨?_, ?_⟩ + · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact hlo + · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact hhi + +/-- **Adjacent `r0` monotonicity** within an octave. -/ +theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x1) = int256 (kTree x2)) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (r0Tree x1) ≤ int256 (r0Tree x2) := by + have hv1 : vTree x1 < 2 ^ 126 := (vTree_eq hx1 hC1 hC01).2 + have hv2 : vTree x2 < 2 ^ 126 := (vTree_eq hx2 hC2 hC02).2 + obtain ⟨hev1lo, hev1hi⟩ := evTree_int hv1 + obtain ⟨hev2lo, hev2hi⟩ := evTree_int hv2 + obtain ⟨htod1lo, htod1hi⟩ := todTree_cross_bounds hx1 hC1 hC01 + obtain ⟨htod2lo, htod2hi⟩ := todTree_cross_bounds hx2 hC2 hC02 + have hevw1 : evTree x1 < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ + have hevw2 : evTree x2 < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ + have htodw1 : todTree x1 < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ + have htodw2 : todTree x2 < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ + have hcross := tod_cross hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + have hr01 : r0Tree x1 = + evmSdiv (evmShl 0x7e (evmAdd (evTree x1) (todTree x1))) (evmSub (evTree x1) (todTree x1)) := rfl + have hr02 : r0Tree x2 = + evmSdiv (evmShl 0x7e (evmAdd (evTree x2) (todTree x2))) (evmSub (evTree x2) (todTree x2)) := rfl + rw [hr01, hr02] + exact r0_mono_of_cross hevw1 htodw1 hevw2 htodw2 hev1lo hev1hi htod1lo htod1hi + hev2lo hev2hi htod2lo htod2hi hcross + +/-- The closing shift words coincide across an octave. -/ +theorem closing_shift_eq {x1 x2 : Nat} + (hk : int256 (kTree x1) = int256 (kTree x2)) + (hk1 : kTree x1 < 2 ^ 256) (hk2 : kTree x2 < 2 ^ 256) : + evmSub 0x7e (kTree x1) = evmSub 0x7e (kTree x2) := by + -- `int256` is injective on canonical words (`[0, 2^256)`), so `k` words coincide. + have hinj : ∀ a b : Nat, a < 2 ^ 256 → b < 2 ^ 256 → int256 a = int256 b → a = b := by + intro a b ha hb h + have hp : (2 : Int) ^ 256 = 115792089237316195423570985008687907853269984665640564039457584007913129639936 := + intPow256 + have ha' : (a : Int) < 2 ^ 256 := by exact_mod_cast ha + have hb' : (b : Int) < 2 ^ 256 := by exact_mod_cast hb + rw [hp] at ha' hb' + unfold int256 at h + split at h <;> split at h <;> first | (rw [hp] at h; omega) | omega + rw [hinj _ _ hk1 hk2 hk] + +/-- **Adjacent `r1` monotonicity** within an octave: with `k` fixed, the closing shift is fixed and +the arithmetic-shift floor of the nondecreasing shift argument is nondecreasing. -/ +theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x1) = int256 (kTree x2)) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (r1Tree x1) ≤ int256 (r1Tree x2) := by + have hr0mono := r0_mono_adjacent hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + obtain ⟨hr0lo1, hr0hi1⟩ := r0Tree_bounds hx1 hC1 hC01 + obtain ⟨hr0lo2, hr0hi2⟩ := r0Tree_bounds hx2 hC2 hC02 + -- the shift argument `WAD·r0 − MARGIN` is nondecreasing + obtain ⟨harg1eq, harg1nn, harg1hi⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 + obtain ⟨harg2eq, harg2nn, harg2hi⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 + -- the closing shift words coincide + have hk1w : kTree x1 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ + have hk2w : kTree x2 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ + have hseq := closing_shift_eq hk hk1w hk2w + obtain ⟨s, hseqx, hslo, hshi, _⟩ := closing_shift hx1 hC1 hC01 + have hr1eq1 : r1Tree x1 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xafe527e18748a8a) := by + unfold r1Tree; rw [hseqx] + have hr1eq2 : r1Tree x2 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xafe527e18748a8a) := by + unfold r1Tree; rw [← hseq, hseqx] + rw [hr1eq1, hr1eq2] + -- the two shift arguments, transported to `Int`, are ordered (monotone `r0`) + set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xafe527e18748a8a with harg1 + set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xafe527e18748a8a with harg2 + have hargle : int256 arg1 ≤ int256 arg2 := by + rw [harg1eq, harg2eq] + have hwad : (0 : Int) ≤ 0xde0b6b3a7640000 := by norm_num + have := mul_le_mul_left_nonneg hr0mono hwad + omega + -- `evmSar s` is monotone in the signed value (the floor of the same shift) + have ha1lt : arg1 < 2 ^ 256 := by rw [harg1]; exact evmSub_lt _ _ + have ha2lt : arg2 < 2 ^ 256 := by rw [harg2]; exact evmSub_lt _ _ + obtain ⟨_, hsl1, hsh1⟩ := evmSar_sandwich (s := s) (by omega) ha1lt + obtain ⟨_, hsl2, hsh2⟩ := evmSar_sandwich (s := s) (by omega) ha2lt + have hpow : (0 : Int) < 2 ^ s := by positivity + set R1 := int256 (evmSar s arg1) + set R2 := int256 (evmSar s arg2) + -- `2^s·R1 ≤ arg1 ≤ arg2 < 2^s·R2 + 2^s ⇒ R1 < R2 + 1 ⇒ R1 ≤ R2` + nlinarith [hsl1, hsh2, hargle, hpow] + +end ExpYul From 88db2c77c125e330a9fb90b03e76e4cd9f116ed8 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 09:26:41 +0200 Subject: [PATCH 037/149] Lift the adjacent step to region monotonicity of r1Tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `kTree_step`: the octave index advances by 0 or 1 per unit input step (`CINV ≪ 2^200`). `r1_step` combines the same-octave step (`r1_mono_adjacent`) with the octave-seam step, the latter carried as an explicit `SeamStep` hypothesis. `r1_mono_steps`/`r1Tree_region_mono` then induct over the signed-integer interval (canonical round-trip via `uint256OfInt_int256`) to give `r1Tree` nondecreasing across the whole region, modulo `SeamStep`. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../ExpProof/ExpProof/Mono/RegionMono.lean | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean new file mode 100644 index 000000000..8408b2e75 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean @@ -0,0 +1,142 @@ +import ExpProof.Mono.StepMono + +/-! +# Lifting the adjacent step to the whole region + +The octave index advances by at most one per unit input step (`kTree_step`). Combined with the +same-octave step (`r1_mono_adjacent`) and the octave-seam step, the unit step `r1Tree x1 ≤ +r1Tree x2` (for `int256 x2 = int256 x1 + 1` in region) holds; induction over the signed-integer +interval then gives `r1Tree` nondecreasing across the whole region. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- The octave index advances by `0` or `1` per unit input step (`CINV ≪ 2^200`). -/ +theorem kTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (kTree x2) = int256 (kTree x1) ∨ int256 (kTree x2) = int256 (kTree x1) + 1 := by + obtain ⟨hlo1, hhi1⟩ := kTree_sandwich hx1 hC1 hC01 + obtain ⟨hlo2, hhi2⟩ := kTree_sandwich hx2 hC2 hC02 + have hmono := kTree_mono hx1 hx2 hC1 (by omega) hC02 + -- the rounding argument advances by exactly `CINV < 2^200` + set k1 := int256 (kTree x1) + set k2 := int256 (kTree x2) + have hcinv : (0x724d54edbacbebbb95c52a0f6076 : Int) < 2 ^ 200 := by norm_num + have hcinvpos : (0 : Int) < 0x724d54edbacbebbb95c52a0f6076 := by norm_num + have hp200 : (0 : Int) < 2 ^ 200 := by norm_num + -- argument at x2 exceeds that at x1 by exactly CINV + have hstep : (2 ^ 199 : Int) + 0x724d54edbacbebbb95c52a0f6076 * int256 x2 = + (2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x1) + 0x724d54edbacbebbb95c52a0f6076 := by + rw [hadj]; ring + rw [hstep] at hlo2 hhi2 + -- 2^200·k2 ≤ A + CINV < 2^200·k1 + 2^200 + CINV < 2^200·(k1 + 2), so k2 < k1 + 2 ⇒ k2 ≤ k1 + 1 + have hupper : k2 < k1 + 2 := by nlinarith [hlo2, hhi1, hcinv, hp200] + omega + +/-- **The octave-seam step** (`k` advances by one): `r1Tree` is nondecreasing across the boundary. +The accumulators are still nearly constant (`v_a ≈ v_b`), the reduced argument flips sign +(`t_b ≈ −t_a`), and the closing shift loses one bit, so `r1Tree x1 ≤ r1Tree x2`. Carried as an +explicit hypothesis (`SeamStep`) until its analytic certificate is discharged; the same-octave step +and the induction below are unconditional. -/ +def SeamStep : Prop := + ∀ {x1 x2 : Nat}, x1 < 2 ^ 256 → x2 < 2 ^ 256 → + int256 Cmask < int256 x1 → int256 x1 < int256 C0thresh → + int256 Cmask < int256 x2 → int256 x2 < int256 C0thresh → + int256 (kTree x2) = int256 (kTree x1) + 1 → + int256 x2 = int256 x1 + 1 → + int256 (r1Tree x1) ≤ int256 (r1Tree x2) + +/-- **The unit step**: `r1Tree` is nondecreasing for two inputs adjacent in the signed order +(same-octave proved; the seam supplied by `SeamStep`). -/ +theorem r1_step (hseamstep : SeamStep) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (r1Tree x1) ≤ int256 (r1Tree x2) := by + rcases kTree_step hx1 hx2 hC1 hC01 hC2 hC02 hadj with hsame | hseam + · exact r1_mono_adjacent hx1 hx2 hC1 hC01 hC2 hC02 hsame.symm hadj + · exact hseamstep hx1 hx2 hC1 hC01 hC2 hC02 hseam hadj + +/-! ## The integer-step induction -/ + +theorem int256_C0thresh_loc : int256 C0thresh = 44014845965556527147994239713 := by + unfold C0thresh int256; norm_num + +/-- A signed value strictly inside the region is a canonical word with that signed value. -/ +theorem region_word {v : Int} (hlo : int256 Cmask < v) (hhi : v < int256 C0thresh) : + uint256OfInt v < 2 ^ 256 ∧ int256 (uint256OfInt v) = v := by + have hC0 : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh_loc + have hCm : int256 Cmask = -41446531673892822312323846185 := int256_Cmask + rw [hCm] at hlo; rw [hC0] at hhi + refine ⟨uint256OfInt_lt v, ?_⟩ + refine int256_uint256OfInt ?_ ?_ + · simp only [ipow255]; omega + · simp only [ipow255]; omega + +/-- Induction on the number of unit steps: `r1Tree` is nondecreasing from any region input to one +`n` steps above it (every intermediate value staying in the region). -/ +theorem r1_mono_steps (hseamstep : SeamStep) (n : Nat) : ∀ x1 : Nat, x1 < 2 ^ 256 → + int256 Cmask < int256 x1 → int256 x1 + n < int256 C0thresh → + int256 (r1Tree x1) ≤ int256 (r1Tree (uint256OfInt (int256 x1 + n))) := by + induction n with + | zero => + intro x1 hx1 hC1 _ + have hw : uint256OfInt (int256 x1 + (0 : Nat)) = x1 := by + rw [show ((0 : Nat) : Int) = 0 by rfl, Int.add_zero] + exact uint256OfInt_int256 hx1 + rw [hw] + | succ m ih => + intro x1 hx1 hC1 hbnd + -- the step target `x1 + 1` + obtain ⟨hw1lt, hw1eq⟩ := region_word (v := int256 x1 + 1) (by omega) (by + have : int256 x1 + (m + 1 : Nat) < int256 C0thresh := hbnd + push_cast at this; omega) + set y := uint256OfInt (int256 x1 + 1) with hy + have hCy : int256 Cmask < int256 y := by rw [hw1eq]; omega + have hCy0 : int256 y < int256 C0thresh := by + rw [hw1eq] + have : int256 x1 + (m + 1 : Nat) < int256 C0thresh := hbnd + push_cast at this; omega + -- the unit step x1 → y + have hstep : int256 (r1Tree x1) ≤ int256 (r1Tree y) := + r1_step hseamstep hx1 hw1lt hC1 (by omega) hCy hCy0 (by rw [hw1eq]) + -- m steps from y + have hrec := ih y hw1lt hCy (by + rw [hw1eq] + have : int256 x1 + (m + 1 : Nat) < int256 C0thresh := hbnd + push_cast at this; omega) + -- `int256 y + m = int256 x1 + (m + 1)` + have hsum : int256 y + (m : Int) = int256 x1 + (m + 1 : Nat) := by rw [hw1eq]; push_cast; ring + rw [hsum] at hrec + have htgt : int256 x1 + ((m : Nat) + 1 : Nat) = int256 x1 + (m + 1 : Nat) := by push_cast; ring + calc int256 (r1Tree x1) ≤ int256 (r1Tree y) := hstep + _ ≤ int256 (r1Tree (uint256OfInt (int256 x1 + (m + 1 : Nat)))) := hrec + +/-- **Region monotonicity of `r1Tree`** (the `RegionMonotonicityFacts.mono` field): for canonical inputs in +the region with `int256 x1 ≤ int256 x2`, `r1Tree x1 ≤ r1Tree x2`. -/ +theorem r1Tree_region_mono (hseamstep : SeamStep) {x1 x2 : Nat} + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hle : int256 x1 ≤ int256 x2) + (hC02 : int256 x2 < int256 C0thresh) : + int256 (r1Tree x1) ≤ int256 (r1Tree x2) := by + -- `x2 = uint256OfInt (int256 x1 + n)` with `n = (int256 x2 − int256 x1).toNat` + set n := (int256 x2 - int256 x1).toNat with hn + have hnval : (n : Int) = int256 x2 - int256 x1 := by + rw [hn]; exact Int.toNat_of_nonneg (by omega) + have hbnd : int256 x1 + (n : Int) < int256 C0thresh := by rw [hnval]; omega + have hstep := r1_mono_steps hseamstep n x1 hx1 hC1 hbnd + -- `uint256OfInt (int256 x1 + n) = x2` + have hx2eq : int256 x1 + (n : Int) = int256 x2 := by rw [hnval]; ring + have hcanon : uint256OfInt (int256 x1 + (n : Int)) = x2 := by + rw [hx2eq]; exact uint256OfInt_int256 hx2 + rw [hcanon] at hstep + exact hstep + +end ExpYul From 26ea25fa15c53a01fddccdbb6a8d68ebd8d2e87a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 09:31:09 +0200 Subject: [PATCH 038/149] Reduce RegionMonotonicityFacts to the octave-seam step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `r1Tree_pin`: the scale-point pin (`1 + r1Tree 0 ≤ r1Tree x` for x>0) from region monotonicity at the canonical word `1` plus the decided values `r1Tree 0 = 10^18 − 1`, `r1Tree 1 = 10^18`. `regionMonotonicityFacts_of_seam`: bundles `range`/`nonneg` (unconditional) with `mono`/`pin` (reduced to `SeamStep`) into `RegionMonotonicityFacts`, and `run_exp_ray_to_wad_evm_mono_of_seam` carries runtime monotonicity over the whole non-reverting domain modulo the single octave-seam obligation. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Mono/Pin.lean | 57 ++++++++++++++++++++++ formal/exp/ExpProof/ExpProof/Mono/Top.lean | 33 +++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Pin.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono/Pin.lean b/formal/exp/ExpProof/ExpProof/Mono/Pin.lean new file mode 100644 index 000000000..46eba43d2 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Pin.lean @@ -0,0 +1,57 @@ +import ExpProof.Mono.RegionMono + +/-! +# The scale-point pin + +At `x = 0` the body has the value `r1Tree 0 = 10^18 − 1`, one below the unit, and the `+iszero` +shell adds the final unit. Above the scale point (`int256 x > 0`) the body has already cleared +`1 + r1Tree 0 = 10^18 = r1Tree 1`: monotonicity from the canonical word `1` gives +`r1Tree 1 ≤ r1Tree x`, and the two scale-point values are decided. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- `r1Tree 0 = 10^18 − 1` (decided). -/ +theorem r1Tree_zero : r1Tree 0 = 999999999999999999 := by decide + +/-- `r1Tree 1 = 10^18` (decided); the scale-point `+1` step. -/ +theorem r1Tree_one : r1Tree 1 = 1000000000000000000 := by decide + +/-- **The scale-point pin** (the `RegionMonotonicityFacts.pin` field), modulo the seam step: above `x = 0` +the body has cleared `1 + r1Tree 0`. -/ +theorem r1Tree_pin (hseamstep : SeamStep) {x : Nat} (hx : x < 2 ^ 256) + (hpos : 0 < int256 x) (hC0 : int256 x < int256 C0thresh) : + 1 + (r1Tree 0 : Int) ≤ (r1Tree x : Int) := by + -- the canonical word `1` has signed value `1 ≤ int256 x` + have h1w : (1 : Nat) < 2 ^ 256 := by norm_num + have h1int : int256 (1 : Nat) = 1 := by decide + have hC1 : int256 Cmask < int256 (1 : Nat) := by + rw [h1int, int256_Cmask]; norm_num + have hle : int256 (1 : Nat) ≤ int256 x := by rw [h1int]; omega + -- monotonicity from `1` to `x` + have hmono := r1Tree_region_mono hseamstep h1w hx hC1 hle hC0 + -- both values are small (`< 2^254`), so `int256` is the Nat cast + have hrange_x : r1Tree x < 2 ^ 254 := by + have hC1x : int256 Cmask < int256 x := lt_of_lt_of_le hC1 hle + exact r1Tree_range hx hC1x hC0 + have hr1x_int : int256 (r1Tree x) = (r1Tree x : Int) := by + refine int256_of_lt ?_ + have : (2 : Nat) ^ 254 < 2 ^ 255 := by norm_num + omega + have hr11 : r1Tree 1 = 1000000000000000000 := r1Tree_one + have hr11_int : int256 (r1Tree 1) = (r1Tree 1 : Int) := by + rw [hr11]; decide + rw [hr1x_int, hr11_int] at hmono + -- `r1Tree 1 = 10^18 = 1 + r1Tree 0` + have hr10 : r1Tree 0 = 999999999999999999 := r1Tree_zero + rw [hr11] at hmono + rw [hr10] + push_cast at hmono ⊢ + omega + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index 0539199ca..292ee4cb3 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -1,6 +1,7 @@ import ExpProof.Mono.Shell import ExpProof.Mono.ShellOn import ExpProof.Mono.RunBridge +import ExpProof.Mono.Pin /-! # Top-level monotonicity reduction @@ -46,6 +47,28 @@ theorem int256_C0thresh : int256 C0thresh = 44014845965556527147994239713 := by unfold C0thresh int256 norm_num +/-- The region monotonicity facts hold given the octave-seam step: `range`/`nonneg` are +unconditional, and `mono`/`pin` reduce (via the same-octave step and the region induction) to +`SeamStep`. -/ +theorem regionMonotonicityFacts_of_seam (hseamstep : SeamStep) : RegionMonotonicityFacts where + range := fun x hx hC hC0 => r1Tree_range hx hC hC0 + nonneg := fun x _ _ _ => r1Tree_nonneg x + mono := fun x1 x2 hx1 hx2 hC1 hle hC02 => by + have h := r1Tree_region_mono hseamstep hx1 hx2 hC1 hle hC02 + -- transport `int256 ≤` to `Nat-cast ≤` (both below `2^254 < 2^255`) + have hC2 : int256 Cmask < int256 x2 := lt_of_lt_of_le hC1 hle + have hC01 : int256 x1 < int256 C0thresh := lt_of_le_of_lt hle hC02 + have hr1 : r1Tree x1 < 2 ^ 254 := r1Tree_range hx1 hC1 hC01 + have hr2 : r1Tree x2 < 2 ^ 254 := r1Tree_range hx2 hC2 hC02 + have e1 : int256 (r1Tree x1) = (r1Tree x1 : Int) := + int256_of_lt (by have : (2:Nat)^254 < 2^255 := by norm_num + omega) + have e2 : int256 (r1Tree x2) = (r1Tree x2 : Int) := + int256_of_lt (by have : (2:Nat)^254 < 2^255 := by norm_num + omega) + rw [e1, e2] at h; exact h + pin := fun x hx hpos hC0 => r1Tree_pin hseamstep hx hpos hC0 + theorem int256_Cmask_lt0 : int256 Cmask < 0 := by rw [int256_Cmask]; norm_num theorem int256_zero : int256 (0 : Nat) = 0 := rfl @@ -143,4 +166,14 @@ theorem run_exp_ray_to_wad_evm_mono (H : RegionMonotonicityFacts) (x1 x2 : Nat) · exact run_exp_ray_to_wad_evm_eq_expTree x2 (domain_of_below_C0 hx2 hdom) · exact expTree_mono H hx1 hx2 hle hdom +/-- **Runtime monotonicity, modulo the octave seam.** With `range`/`nonneg` and the +same-octave/induction machinery all discharged, monotonicity over the entire non-reverting domain +follows from the single octave-seam step `SeamStep`. -/ +theorem run_exp_ray_to_wad_evm_mono_of_seam (hseamstep : SeamStep) (x1 x2 : Nat) + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hle : int256 x1 ≤ int256 x2) (hdom : int256 x2 < int256 C0thresh) : + ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ + int256 r1 ≤ int256 r2 := + run_exp_ray_to_wad_evm_mono (regionMonotonicityFacts_of_seam hseamstep) x1 x2 hx1 hx2 hle hdom + end ExpYul From 2715aa0d276108f34eb44973a06e1ba4002240e8 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 10:23:12 +0200 Subject: [PATCH 039/149] Reduce the octave-seam step to the r0 doubling bound The seam step (r1Tree nondecreasing across an octave boundary) reduces to the r0 doubling bound r0Tree x1 < 2*r0Tree x2 (SeamR0Bound). Across the seam the closing shift 126-k drops exactly one bit, so with the same shift argument arg = WAD*r0 - MARGIN the floor identity r1b = floor(2*arg2/2^s) >= floor(arg1/2^s) = r1a holds whenever arg1 <= 2*arg2, which (MARGIN < WAD) follows from SeamR0Bound. The assembly names the deep evmSar/evmSub/evmMul shift arguments opaquely (set ... with) before applying the abstract floor lemma seam_close, so the kernel never forces the deep tree behind r1Tree into whnf and the cumulative elaboration depth stays bounded. seamStep_of_seamR0 : SeamR0Bound -> SeamStep wires this into the existing regionTwoMono_of_seam reduction. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Mono.lean | 1 + formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 110 ++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Seam.lean diff --git a/formal/exp/ExpProof/ExpProof/Mono.lean b/formal/exp/ExpProof/ExpProof/Mono.lean index 4a6fcf975..daf98ca2f 100644 --- a/formal/exp/ExpProof/ExpProof/Mono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono.lean @@ -1,5 +1,6 @@ import ExpProof.Mono.Top import ExpProof.Mono.Octave +import ExpProof.Mono.Seam /-! # Mono facade diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean new file mode 100644 index 000000000..da17599be --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -0,0 +1,110 @@ +import ExpProof.Mono.RegionMono + +/-! +# The octave-seam step from the `r0` doubling bound + +Across a seam (`k` advances by one, `int256 x2 = int256 x1 + 1`) the closing shift `126 − k` drops +exactly one bit, so with the same shift argument `arg = WAD·r0 − MARGIN` the floor identity + +``` +r1Tree x2 = ⌊arg2 / 2^(s−1)⌋ = ⌊2·arg2 / 2^s⌋ ≥ ⌊arg1 / 2^s⌋ = r1Tree x1 ⟸ arg1 ≤ 2·arg2 +``` + +reduces the seam step to `arg1 ≤ 2·arg2`, which (since `MARGIN < WAD`) follows from the **`r0` +doubling bound** `r0Tree x1 < 2·r0Tree x2` (`SeamR0Bound`). The reduction is assembled over the +opaque shift-argument words (`seam_close`), so the deep `evmSar`/`evmSub`/`evmMul` tree behind +`r1Tree` is never forced into whnf. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- **The `r0` doubling bound across a seam.** For adjacent inputs crossing one octave +(`int256 (kTree x2) = int256 (kTree x1) + 1`, `int256 x2 = int256 x1 + 1`), the Q126 quotient at +most doubles: `r0Tree x1 < 2·r0Tree x2`. (Across the seam the reduced argument flips sign +`t_b ≈ −t_a`, so `r0_a ≈ exp(t_a)·2^126 ≈ √2·2^126` and `r0_b ≈ exp(−t_a)·2^126 ≈ 2^126/√2`, hence +`r0_a/r0_b ≈ 2`.) -/ +def SeamR0Bound : Prop := + ∀ {x1 x2 : Nat}, x1 < 2 ^ 256 → x2 < 2 ^ 256 → + int256 Cmask < int256 x1 → int256 x1 < int256 C0thresh → + int256 Cmask < int256 x2 → int256 x2 < int256 C0thresh → + int256 (kTree x2) = int256 (kTree x1) + 1 → + int256 x2 = int256 x1 + 1 → + int256 (r0Tree x1) < 2 * int256 (r0Tree x2) + +/-- Abstract seam floor reduction over opaque shift-argument words and shift amounts. With the +closing shift dropping one bit (`s2 + 1 = s1`) and `arg1 ≤ 2·arg2`, the two arithmetic-shift floors +are `≤`-ordered: `⌊arg1 / 2^s1⌋ ≤ ⌊arg2 / 2^(s1−1)⌋`. -/ +theorem seam_close {arg1 arg2 s1 s2 : Nat} + (ha1 : arg1 < 2 ^ 256) (ha2 : arg2 < 2 ^ 256) + (hs1 : s1 < 256) (hs2 : s2 < 256) (hseq : s2 + 1 = s1) + (hle : int256 arg1 ≤ 2 * int256 arg2) : + int256 (evmSar s1 arg1) ≤ int256 (evmSar s2 arg2) := by + obtain ⟨_, hsl1, _⟩ := evmSar_sandwich (s := s1) hs1 ha1 + obtain ⟨_, _, hsh2⟩ := evmSar_sandwich (s := s2) hs2 ha2 + have hpow : (2 : Int) ^ s1 = 2 * 2 ^ s2 := by rw [← hseq, pow_succ]; ring + have hp2 : (0 : Int) < 2 ^ s2 := by positivity + set R1 := int256 (evmSar s1 arg1) + set R2 := int256 (evmSar s2 arg2) + -- `2^s1·R1 ≤ arg1 ≤ 2·arg2 < 2·(2^s2·R2 + 2^s2) = 2^s1·R2 + 2^s1` ⇒ `R1 < R2 + 1` ⇒ `R1 ≤ R2`. + rw [hpow] at hsl1 + nlinarith [hsl1, hsh2, hle, hp2] + +/-- The closing shifts at a seam differ by one (`s2 = s1 − 1`), both in `[63, 187]`. -/ +theorem seam_closing_shifts {x1 x2 : Nat} + (hx1 : x1 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hx2 : x2 < 2 ^ 256) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x2) = int256 (kTree x1) + 1) : + ∃ s1 s2 : Nat, evmSub 0x7e (kTree x1) = s1 ∧ evmSub 0x7e (kTree x2) = s2 ∧ + s1 < 256 ∧ s2 < 256 ∧ s2 + 1 = s1 := by + obtain ⟨s1, hs1eq, _, hs1hi, hs1int⟩ := closing_shift hx1 hC1 hC01 + obtain ⟨s2, hs2eq, hs2lo, _, hs2int⟩ := closing_shift hx2 hC2 hC02 + refine ⟨s1, s2, hs1eq, hs2eq, by omega, by omega, ?_⟩ + -- `(s2 : Int) + 1 = 126 − k2 + 1 = 126 − k1 = (s1 : Int)` + have : (s2 : Int) + 1 = (s1 : Int) := by rw [hs1int, hs2int, hk]; ring + omega + +/-- **The octave-seam step from the `r0` doubling bound.** Given `SeamR0Bound`, the closing +accumulator is nondecreasing across a seam. The shift arguments are named opaquely before the +floor lemma, so the deep tree behind `r1Tree` is never reduced. -/ +theorem seamStep_of_r0 (hr0 : SeamR0Bound) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x2) = int256 (kTree x1) + 1) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (r1Tree x1) ≤ int256 (r1Tree x2) := by + obtain ⟨s1, s2, hs1eq, hs2eq, hs1lt, hs2lt, hseq⟩ := + seam_closing_shifts hx1 hC1 hC01 hx2 hC2 hC02 hk + obtain ⟨hr0lo1, hr0hi1⟩ := r0Tree_bounds hx1 hC1 hC01 + obtain ⟨hr0lo2, hr0hi2⟩ := r0Tree_bounds hx2 hC2 hC02 + obtain ⟨harg1eq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 + obtain ⟨harg2eq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 + have hr1eq1 : r1Tree x1 = + evmSar s1 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xafe527e18748a8a) := by + unfold r1Tree; rw [hs1eq] + have hr1eq2 : r1Tree x2 = + evmSar s2 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xafe527e18748a8a) := by + unfold r1Tree; rw [hs2eq] + rw [hr1eq1, hr1eq2] + -- name the deep shift arguments opaquely before feeding the floor lemma + set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xafe527e18748a8a with harg1def + set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xafe527e18748a8a with harg2def + have hr0bound : int256 (r0Tree x1) < 2 * int256 (r0Tree x2) := + hr0 hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + have hargle : int256 arg1 ≤ 2 * int256 arg2 := by + rw [harg1eq, harg2eq, show (0xde0b6b3a7640000 : Int) = 1000000000000000000 by norm_num, + show (0xafe527e18748a8a : Int) = 792161285993433738 by norm_num] + -- `WAD·r0a − M ≤ 2·(WAD·r0b − M)` ⟸ `WAD·r0a + M ≤ 2·WAD·r0b` ⟸ `r0a ≤ 2·r0b − 1` and `M ≤ WAD` + nlinarith [hr0bound] + exact seam_close (harg1def ▸ evmSub_lt _ _) (harg2def ▸ evmSub_lt _ _) hs1lt hs2lt hseq hargle + +/-- The seam step (`SeamStep`) follows from the `r0` doubling bound. -/ +theorem seamStep_of_seamR0 (hr0 : SeamR0Bound) : SeamStep := + fun hx1 hx2 hC1 hC01 hC2 hC02 hk hadj => + seamStep_of_r0 hr0 hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + +end ExpYul From 37e41efb0f66c59600b96f87e173edd736441068 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 10:29:46 +0200 Subject: [PATCH 040/149] Reduce runtime monotonicity to the single seam r0 doubling bound run_exp_ray_to_wad_evm_mono_of_seamR0 gives runtime monotonicity over the whole non-reverting domain from the single analytic obligation SeamR0Bound (r0Tree x1 < 2*r0Tree x2 across one octave), via seamStep_of_seamR0 -> run_exp_ray_to_wad_evm_mono_of_seam. The kernel-wall floor reduction, range, nonneg, the same-octave step, the region induction, and the scale-point pin are all unconditional and axiom-clean; the axiom gate in Theorems.lean pins the new theorem to [propext, Classical.choice, Quot.sound]. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Mono/Top.lean | 12 ++++++++++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index 292ee4cb3..8c586f98c 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -2,6 +2,7 @@ import ExpProof.Mono.Shell import ExpProof.Mono.ShellOn import ExpProof.Mono.RunBridge import ExpProof.Mono.Pin +import ExpProof.Mono.Seam /-! # Top-level monotonicity reduction @@ -176,4 +177,15 @@ theorem run_exp_ray_to_wad_evm_mono_of_seam (hseamstep : SeamStep) (x1 x2 : Nat) int256 r1 ≤ int256 r2 := run_exp_ray_to_wad_evm_mono (regionMonotonicityFacts_of_seam hseamstep) x1 x2 hx1 hx2 hle hdom +/-- **Runtime monotonicity, modulo the octave-seam `r0` doubling bound.** With the +kernel-wall floor reduction (`Seam.seamStep_of_seamR0`) and all of `range`/`nonneg`/same-octave/ +induction discharged, monotonicity over the entire non-reverting domain follows from the single +analytic bound `SeamR0Bound` (`r0Tree x1 < 2·r0Tree x2` across one octave). -/ +theorem run_exp_ray_to_wad_evm_mono_of_seamR0 (hr0 : SeamR0Bound) (x1 x2 : Nat) + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hle : int256 x1 ≤ int256 x2) (hdom : int256 x2 < int256 C0thresh) : + ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ + int256 r1 ≤ int256 r2 := + run_exp_ray_to_wad_evm_mono_of_seam (seamStep_of_seamR0 hr0) x1 x2 hx1 hx2 hle hdom + end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index cee8fa4c0..6029bc4fa 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -74,4 +74,21 @@ example (H : RegionMonotonicityFacts) (x1 x2 : Nat) #guard_msgs in #print axioms run_exp_ray_to_wad_evm_mono +/-- Monotone over the whole supported domain, reduced to the single analytic obligation +`SeamR0Bound` (the octave-seam `r0` doubling bound). The kernel-wall floor reduction, the +`range`/`nonneg` obligations, the same-octave step, the region induction, and the scale-point pin are +all proved unconditionally; what remains for an unconditional monotonicity theorem is the minimax +accuracy bound `SeamR0Bound`. -/ +example (hr0 : SeamR0Bound) (x1 x2 : Nat) + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hle : FormalYul.Preservation.int256 x1 ≤ FormalYul.Preservation.int256 x2) + (hdom : FormalYul.Preservation.int256 x2 < FormalYul.Preservation.int256 C0thresh) : + ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ + FormalYul.Preservation.int256 r1 ≤ FormalYul.Preservation.int256 r2 := + run_exp_ray_to_wad_evm_mono_of_seamR0 hr0 x1 x2 hx1 hx2 hle hdom + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_mono_of_seamR0' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_mono_of_seamR0 + end ExpYul From 62539d2fca2156f23b31a7c1b876856347bc3dfd Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 10:53:31 +0200 Subject: [PATCH 041/149] Add `Common` package: shared function-agnostic proof machinery Introduce a new Lean package `formal/common` that holds the function-agnostic proof machinery extracted from `LnProof` so it can be shared with `ExpProof`: - `Common.Poly` (interval-Horner nonnegativity certificates, polynomial algebra, recentered cell walks, Kronecker identity testing and packed shifts). - `Common.Exp` (the `e^(p/q)` Taylor-cut framework: `expNum`, partial-sum monotonicity, the geometric tail bound, and the `capUB`/`capLB` interface). - `Common.RealExpBridge` (the `Real.exp` bridge for the partial-sum caps; the only Mathlib-using module). The package layers `FormalYul -> Common`, shares the same pinned toolchain and `../yul/.lake/packages` directory as `LnProof`/`ExpProof`, and builds green. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/common/.gitignore | 1 + formal/common/Common.lean | 13 + formal/common/Common/Foundation/ExpSum.lean | 857 ++++++++++++++++++ .../common/Common/Foundation/Kronecker.lean | 272 ++++++ .../Common/Foundation/KroneckerShift.lean | 288 ++++++ formal/common/Common/Foundation/Poly.lean | 225 +++++ .../common/Common/Foundation/ShiftCert.lean | 422 +++++++++ formal/common/Common/Seam/RealExpBridge.lean | 148 +++ formal/common/lake-manifest.json | 109 +++ formal/common/lakefile.toml | 11 + formal/common/lean-toolchain | 1 + 11 files changed, 2347 insertions(+) create mode 100644 formal/common/.gitignore create mode 100644 formal/common/Common.lean create mode 100644 formal/common/Common/Foundation/ExpSum.lean create mode 100644 formal/common/Common/Foundation/Kronecker.lean create mode 100644 formal/common/Common/Foundation/KroneckerShift.lean create mode 100644 formal/common/Common/Foundation/Poly.lean create mode 100644 formal/common/Common/Foundation/ShiftCert.lean create mode 100644 formal/common/Common/Seam/RealExpBridge.lean create mode 100644 formal/common/lake-manifest.json create mode 100644 formal/common/lakefile.toml create mode 100644 formal/common/lean-toolchain diff --git a/formal/common/.gitignore b/formal/common/.gitignore new file mode 100644 index 000000000..4080d07df --- /dev/null +++ b/formal/common/.gitignore @@ -0,0 +1 @@ +/.lake/ diff --git a/formal/common/Common.lean b/formal/common/Common.lean new file mode 100644 index 000000000..aacbaff83 --- /dev/null +++ b/formal/common/Common.lean @@ -0,0 +1,13 @@ +-- This module serves as the root of the `Common` library: the shared, +-- function-agnostic Lean machinery used by the per-function Yul correctness +-- proofs (`LnProof`, `ExpProof`). Nothing here models any specific +-- implementation. It is generic interval-Horner nonnegativity certificates and +-- Kronecker identity-testing / packed-shift cell walks (`Common.Poly`), the +-- `e^(p/q)` Taylor-cut framework (`Common.Exp`), and the `Real.exp` bridge for +-- the partial-sum caps (`Common.RealExpBridge`). +import Common.Foundation.Poly +import Common.Foundation.ExpSum +import Common.Foundation.ShiftCert +import Common.Foundation.Kronecker +import Common.Foundation.KroneckerShift +import Common.Seam.RealExpBridge diff --git a/formal/common/Common/Foundation/ExpSum.lean b/formal/common/Common/Foundation/ExpSum.lean new file mode 100644 index 000000000..7970a8d41 --- /dev/null +++ b/formal/common/Common/Foundation/ExpSum.lean @@ -0,0 +1,857 @@ +import Init + +/-! +# Exponential partial sums over scaled integers + +`S_N(p/q) = Σ_{j ≤ N} (p/q)^j / j!` is represented exactly by the integer +`expNum N p q = Σ_{j ≤ N} (N!/j!) p^j q^(N-j)`, so that +`S_N(p/q) = expNum N p q / (N! q^N)`. Arguments are nonnegative rationals +given as `Nat` pairs. For `t ≥ 0` the partial sums increase to `e^t`, which +is how the finite cut certificates arithmetize the `lnWad` logarithm bounds: +an upper bound on `e^t` is `∀ N` a bound on `S_N`, and a lower bound is +witnessed by a single `S_N`. + +Everything here is `Nat` arithmetic: monotonicity in `N` and in the +argument, a geometric tail bound (turning one evaluated partial sum into a +bound for all `N`), and the binomial subset-product inequalities standing +in for `e^(a+b) = e^a * e^b`. +-/ + +namespace Common.Exp + +def fact : Nat → Nat + | 0 => 1 + | n + 1 => (n + 1) * fact n + +theorem fact_pos (n : Nat) : 0 < fact n := by + induction n with + | zero => decide + | succ k ih => simp only [fact]; exact Nat.mul_pos (Nat.succ_pos k) ih + +/-- `expNum N p q = Σ_{j ≤ N} (N!/j!) p^j q^(N-j)`, by the recursion +`E_{N+1} = (N+1) q E_N + p^(N+1)`. -/ +def expNum : Nat → Nat → Nat → Nat + | 0, _, _ => 1 + | n + 1, p, q => (n + 1) * q * expNum n p q + p ^ (n + 1) + +theorem expNum_pos {p q : Nat} (hq : 0 < q) : ∀ n, 0 < expNum n p q := by + intro n + induction n with + | zero => simp only [expNum]; omega + | succ k ih => + simp only [expNum] + have h1 : 0 < (k + 1) * q * expNum k p q := + Nat.mul_pos (Nat.mul_pos (Nat.succ_pos k) hq) ih + omega + +/-- Comparison helpers: `S_N(p/q) ≤ y/w` and `S_N(p/q) ≥ y/w` as integer +inequalities (`q, w` positive at use sites). -/ +def sumLE (n p q y w : Nat) : Prop := expNum n p q * w ≤ y * (fact n * q ^ n) +def sumGE (n p q y w : Nat) : Prop := y * (fact n * q ^ n) ≤ expNum n p q * w + +instance (n p q y w : Nat) : Decidable (sumLE n p q y w) := by + unfold sumLE; infer_instance +instance (n p q y w : Nat) : Decidable (sumGE n p q y w) := by + unfold sumGE; infer_instance + +/-! ## Finite sums -/ + +/-- `tsum n f = f 0 + f 1 + ... + f n`. -/ +def tsum : Nat → (Nat → Nat) → Nat + | 0, f => f 0 + | n + 1, f => tsum n f + f (n + 1) + +theorem tsum_le_tsum {f g : Nat → Nat} {n : Nat} (h : ∀ i, i ≤ n → f i ≤ g i) : + tsum n f ≤ tsum n g := by + induction n with + | zero => exact h 0 (Nat.le_refl 0) + | succ k ih => + simp only [tsum] + have h1 := ih (fun i hi => h i (Nat.le_succ_of_le hi)) + have h2 := h (k + 1) (Nat.le_refl _) + omega + +theorem tsum_congr {f g : Nat → Nat} {n : Nat} (h : ∀ i, i ≤ n → f i = g i) : + tsum n f = tsum n g := by + induction n with + | zero => exact h 0 (Nat.le_refl 0) + | succ k ih => + simp only [tsum] + rw [ih (fun i hi => h i (Nat.le_succ_of_le hi)), h (k + 1) (Nat.le_refl _)] + +theorem tsum_mul_const {f : Nat → Nat} {n c : Nat} : + tsum n f * c = tsum n (fun i => f i * c) := by + induction n with + | zero => rfl + | succ k ih => simp only [tsum, Nat.add_mul, ih] + +theorem const_mul_tsum {f : Nat → Nat} {n c : Nat} : + c * tsum n f = tsum n (fun i => c * f i) := by + induction n with + | zero => rfl + | succ k ih => simp only [tsum, Nat.mul_add, ih] + +theorem tsum_add {f g : Nat → Nat} {n : Nat} : + tsum n (fun i => f i + g i) = tsum n f + tsum n g := by + induction n with + | zero => rfl + | succ k ih => simp only [tsum, ih]; omega + +theorem first_le_tsum (f : Nat → Nat) (n : Nat) : f 0 ≤ tsum n f := by + induction n with + | zero => exact Nat.le_refl _ + | succ k ih => simp only [tsum]; omega + +theorem tsum_prefix_le {f : Nat → Nat} {n m : Nat} (h : n ≤ m) : + tsum n f ≤ tsum m f := by + induction m with + | zero => cases Nat.le_zero.mp h; exact Nat.le_refl _ + | succ k ih => + rcases Nat.lt_or_ge n (k + 1) with hlt | hge + · have := ih (by omega) + simp only [tsum] + omega + · have he : n = k + 1 := by omega + rw [he] + exact Nat.le_refl _ + +/-- Sum transpose: diagonal-major to column-major over the triangle +`{(i, j) : i + j ≤ c}`. -/ +theorem tri_transpose (T : Nat → Nat → Nat) (c : Nat) : + tsum c (fun n => tsum n (fun i => T i (n - i))) = + tsum c (fun i => tsum (c - i) (fun j => T i j)) := by + induction c with + | zero => rfl + | succ k ih => + -- peel the diagonal n = k+1 on the left, the last entries on the right + have hr : tsum (k + 1) (fun i => tsum (k + 1 - i) (fun j => T i j)) = + tsum k (fun i => tsum (k - i) (fun j => T i j)) + + tsum (k + 1) (fun i => T i (k + 1 - i)) := by + have hsplit : ∀ i, i ≤ k → + tsum (k + 1 - i) (fun j => T i j) = + tsum (k - i) (fun j => T i j) + T i (k + 1 - i) := by + intro i hi + have he : k + 1 - i = (k - i) + 1 := by omega + rw [he] + rfl + calc tsum (k + 1) (fun i => tsum (k + 1 - i) (fun j => T i j)) + = tsum k (fun i => tsum (k + 1 - i) (fun j => T i j)) + + tsum 0 (fun j => T (k + 1) j) := by + show tsum k _ + tsum (k + 1 - (k + 1)) _ = _ + rw [Nat.sub_self] + _ = tsum k (fun i => tsum (k - i) (fun j => T i j) + T i (k + 1 - i)) + + T (k + 1) 0 := by + rw [tsum_congr (fun i hi => hsplit i hi)] + rfl + _ = tsum k (fun i => tsum (k - i) (fun j => T i j)) + + tsum k (fun i => T i (k + 1 - i)) + T (k + 1) 0 := by + rw [tsum_add] + _ = tsum k (fun i => tsum (k - i) (fun j => T i j)) + + tsum (k + 1) (fun i => T i (k + 1 - i)) := by + have : tsum (k + 1) (fun i => T i (k + 1 - i)) = + tsum k (fun i => T i (k + 1 - i)) + T (k + 1) 0 := by + have he : k + 1 - (k + 1) = 0 := by omega + simp only [tsum, he] + omega + simp only [tsum] at * + omega + +/-- Box-into-triangle: summing a nonnegative term over `[0,N] × [0,M]` is at +most the sum over the triangle `{i + j ≤ N + M}`. -/ +theorem box_le_tri (T : Nat → Nat → Nat) (N M : Nat) : + tsum N (fun i => tsum M (fun j => T i j)) ≤ + tsum (N + M) (fun n => tsum n (fun i => T i (n - i))) := by + rw [tri_transpose] + calc tsum N (fun i => tsum M (fun j => T i j)) + ≤ tsum N (fun i => tsum (N + M - i) (fun j => T i j)) := + tsum_le_tsum (fun i hi => tsum_prefix_le (by omega)) + _ ≤ tsum (N + M) (fun i => tsum (N + M - i) (fun j => T i j)) := + tsum_prefix_le (by omega) + +/-- Triangle-into-box: the triangle `{i + j ≤ K}` sits inside `[0,K] × [0,K]`. -/ +theorem tri_le_box (T : Nat → Nat → Nat) (K : Nat) : + tsum K (fun n => tsum n (fun i => T i (n - i))) ≤ + tsum K (fun i => tsum K (fun j => T i j)) := by + rw [tri_transpose] + exact tsum_le_tsum (fun i hi => tsum_prefix_le (by omega)) + +/-! ## Coefficients -/ + +/-- Rising product: `ffacAux j d = (j+1)(j+2)...(j+d) = (j+d)!/j!`. -/ +def ffacAux (j : Nat) : Nat → Nat + | 0 => 1 + | d + 1 => (j + d + 1) * ffacAux j d + +theorem ffacAux_mul_fact (j : Nat) : ∀ d, ffacAux j d * fact j = fact (j + d) := by + intro d + induction d with + | zero => simp only [ffacAux, Nat.one_mul, Nat.add_zero] + | succ k ih => + simp only [ffacAux] + calc (j + k + 1) * ffacAux j k * fact j + = (j + k + 1) * (ffacAux j k * fact j) := by rw [Nat.mul_assoc] + _ = (j + k + 1) * fact (j + k) := by rw [ih] + _ = fact (j + k + 1) := rfl + +/-- Front peel: `tsum (n+1) f = f 0 + Σ_{i ≤ n} f (i+1)`. -/ +theorem tsum_shift (f : Nat → Nat) (n : Nat) : + tsum (n + 1) f = f 0 + tsum n (fun i => f (i + 1)) := by + induction n with + | zero => rfl + | succ m ih => + have h1 : tsum (m + 2) f = tsum (m + 1) f + f (m + 2) := rfl + have h2 : tsum (m + 1) (fun i => f (i + 1)) = + tsum m (fun i => f (i + 1)) + f (m + 2) := rfl + rw [h1, ih, h2] + omega + +/-- Pascal-recursive binomial coefficient. -/ +def cho : Nat → Nat → Nat + | _, 0 => 1 + | 0, _ + 1 => 0 + | n + 1, i + 1 => cho n i + cho n (i + 1) + +theorem cho_eq_zero_of_lt : ∀ {n i : Nat}, n < i → cho n i = 0 := by + intro n + induction n with + | zero => intro i h; match i, h with | i + 1, _ => rfl + | succ k ih => + intro i h + match i, h with + | i + 1, h => + show cho k i + cho k (i + 1) = 0 + rw [ih (by omega), ih (by omega)] + +theorem cho_self : ∀ n, cho n n = 1 := by + intro n + induction n with + | zero => rfl + | succ k ih => + show cho k k + cho k (k + 1) = 1 + rw [ih, cho_eq_zero_of_lt (Nat.lt_succ_self k)] + +theorem cho_fact : ∀ n i, i ≤ n → cho n i * (fact i * fact (n - i)) = fact n := by + intro n + induction n with + | zero => intro i h; cases Nat.le_zero.mp h; rfl + | succ k ih => + intro i h + match i with + | 0 => + show 1 * (1 * fact (k + 1)) = fact (k + 1) + omega + | i + 1 => + show (cho k i + cho k (i + 1)) * (fact (i + 1) * fact (k + 1 - (i + 1))) = + fact (k + 1) + have hf1 : fact (i + 1) = (i + 1) * fact i := rfl + rcases Nat.lt_or_ge k (i + 1) with hlt | hge + · -- top of the column: i = k, the second binomial vanishes + have he : i = k := by omega + rw [he, cho_self, show cho k (k + 1) = 0 from cho_eq_zero_of_lt (Nat.lt_succ_self k), + Nat.sub_self] + show (1 + 0) * (fact (k + 1) * 1) = fact (k + 1) + omega + · have h1 := ih i (by omega) + have h2 := ih (i + 1) hge + have hs1 : k + 1 - (i + 1) = k - i := by omega + have hs2 : k - i = (k - (i + 1)) + 1 := by omega + -- cho k i * ((i+1)! * (k-i)!) = (i+1) * k! + have e1 : cho k i * (fact (i + 1) * fact (k - i)) = (i + 1) * fact k := by + rw [hf1, ← h1] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + -- cho k (i+1) * ((i+1)! * (k-i)!) = (k-i) * k! + have e2 : cho k (i + 1) * (fact (i + 1) * fact (k - i)) = (k - i) * fact k := by + rw [hs2, show fact ((k - (i + 1)) + 1) = ((k - (i + 1)) + 1) * fact (k - (i + 1)) + from rfl, ← h2] + simp only [Nat.mul_left_comm] + rw [hs1, Nat.add_mul, e1, e2, ← Nat.add_mul] + have hc : i + 1 + (k - i) = k + 1 := by omega + rw [hc] + rfl + +/-- Binomial theorem. -/ +theorem add_pow (a b n : Nat) : + (a + b) ^ n = tsum n (fun i => cho n i * a ^ i * b ^ (n - i)) := by + induction n with + | zero => + show 1 = cho 0 0 * a ^ 0 * b ^ 0 + rfl + | succ k ih => + have step : (a + b) ^ (k + 1) = + tsum k (fun i => cho k i * a ^ (i + 1) * b ^ (k - i)) + + tsum k (fun i => cho k i * a ^ i * b ^ (k + 1 - i)) := by + have hx : (a + b) ^ (k + 1) = (a + b) ^ k * a + (a + b) ^ k * b := by + rw [Nat.pow_succ, Nat.mul_add] + rw [hx, ih, tsum_mul_const, tsum_mul_const] + congr 1 + · refine tsum_congr (fun i hi => ?_) + rw [Nat.pow_succ] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + · refine tsum_congr (fun i hi => ?_) + rw [show k + 1 - i = (k - i) + 1 by omega, Nat.pow_succ] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [step] + have peel : tsum (k + 1) (fun i => cho (k + 1) i * a ^ i * b ^ (k + 1 - i)) = + b ^ (k + 1) + + tsum k (fun i => cho (k + 1) (i + 1) * a ^ (i + 1) * b ^ (k - i)) := by + rw [tsum_shift] + congr 1 + · show cho (k + 1) 0 * a ^ 0 * b ^ (k + 1) = b ^ (k + 1) + show 1 * 1 * b ^ (k + 1) = b ^ (k + 1) + omega + · exact tsum_congr (fun i hi => by rw [show k + 1 - (i + 1) = k - i by omega]) + rw [peel] + have pascal : tsum k (fun i => cho (k + 1) (i + 1) * a ^ (i + 1) * b ^ (k - i)) = + tsum k (fun i => cho k i * a ^ (i + 1) * b ^ (k - i)) + + tsum k (fun i => cho k (i + 1) * a ^ (i + 1) * b ^ (k - i)) := by + rw [← tsum_add] + refine tsum_congr (fun i hi => ?_) + show (cho k i + cho k (i + 1)) * _ * _ = _ + rw [Nat.add_mul, Nat.add_mul] + rw [pascal] + -- the b-branch of `step` equals b^(k+1) plus the shifted Pascal remainder + have hb : tsum k (fun i => cho k i * a ^ i * b ^ (k + 1 - i)) = + b ^ (k + 1) + tsum k (fun i => cho k (i + 1) * a ^ (i + 1) * b ^ (k - i)) := by + cases k with + | zero => + show cho 0 0 * a ^ 0 * b ^ 1 = b ^ 1 + cho 0 1 * a ^ 1 * b ^ 0 + show 1 * 1 * b ^ 1 = b ^ 1 + 0 * a ^ 1 * b ^ 0 + omega + | succ m => + rw [tsum_shift] + have hcong : tsum m + (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 + 1 - (i + 1))) = + tsum m (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 - i)) := + tsum_congr (fun i hi => by + rw [show m + 1 + 1 - (i + 1) = m + 1 - i by omega]) + have hext : tsum (m + 1) + (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 - i)) = + tsum m (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 - i)) + + cho (m + 1) (m + 2) * a ^ (m + 2) * b ^ (m + 1 - (m + 1)) := rfl + have hz : cho (m + 1) (m + 2) = 0 := cho_eq_zero_of_lt (by omega) + rw [hz, Nat.zero_mul, Nat.zero_mul, Nat.add_zero] at hext + show 1 * 1 * b ^ (m + 2) + + tsum m (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * + b ^ (m + 1 + 1 - (i + 1))) = + b ^ (m + 2) + + tsum (m + 1) (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 - i)) + rw [hcong, hext] + omega + rw [hb] + omega + +/-! ## `expNum` as a sum, and the product inequalities -/ + +theorem expNum_eq_tsum (n p q : Nat) : + expNum n p q = tsum n (fun j => ffacAux j (n - j) * p ^ j * q ^ (n - j)) := by + induction n with + | zero => rfl + | succ k ih => + show (k + 1) * q * expNum k p q + p ^ (k + 1) = _ + rw [ih, const_mul_tsum] + have hsum : tsum k (fun j => (k + 1) * q * + (ffacAux j (k - j) * p ^ j * q ^ (k - j))) = + tsum k (fun j => ffacAux j (k + 1 - j) * p ^ j * q ^ (k + 1 - j)) := by + refine tsum_congr (fun j hj => ?_) + have h1 : k + 1 - j = (k - j) + 1 := by omega + rw [h1] + have h2 : ffacAux j (k - j + 1) = (j + (k - j) + 1) * ffacAux j (k - j) := rfl + rw [h2, show j + (k - j) + 1 = k + 1 by omega, Nat.pow_succ] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [hsum] + have hlast : tsum (k + 1) (fun j => ffacAux j (k + 1 - j) * p ^ j * q ^ (k + 1 - j)) = + tsum k (fun j => ffacAux j (k + 1 - j) * p ^ j * q ^ (k + 1 - j)) + + ffacAux (k + 1) (k + 1 - (k + 1)) * p ^ (k + 1) * q ^ (k + 1 - (k + 1)) := rfl + rw [hlast, Nat.sub_self] + show _ = _ + 1 * p ^ (k + 1) * 1 + omega + +theorem mul_pos' {a b : Nat} (ha : 0 < a) (hb : 0 < b) : 0 < a * b := + Nat.mul_pos ha hb + +/-- The convolution coefficient identity behind both product inequalities. -/ +theorem coef_eq {N M i j : Nat} (hi : i ≤ N) (hj : j ≤ M) : + ffacAux i (N - i) * ffacAux j (M - j) * fact (N + M) = + fact N * fact M * (ffacAux (i + j) (N + M - (i + j)) * cho (i + j) i) := by + refine Nat.eq_of_mul_eq_mul_right (mul_pos' (fact_pos i) (fact_pos j)) ?_ + have hL : ffacAux i (N - i) * ffacAux j (M - j) * fact (N + M) * (fact i * fact j) = + (ffacAux i (N - i) * fact i) * ((ffacAux j (M - j) * fact j) * fact (N + M)) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [hL, ffacAux_mul_fact, ffacAux_mul_fact, + show i + (N - i) = N by omega, show j + (M - j) = M by omega] + have hR : fact N * fact M * (ffacAux (i + j) (N + M - (i + j)) * cho (i + j) i) * + (fact i * fact j) = + fact N * (fact M * (ffacAux (i + j) (N + M - (i + j)) * + (cho (i + j) i * (fact i * fact j)))) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [hR, show fact j = fact (i + j - i) by rw [show i + j - i = j by omega], + cho_fact (i + j) i (by omega), ffacAux_mul_fact, + show i + j + (N + M - (i + j)) = N + M by omega] + +theorem tsum_mul_tsum (f g : Nat → Nat) (N M c : Nat) : + tsum N f * tsum M g * c = + tsum N (fun i => tsum M (fun j => f i * (g j * c))) := by + calc tsum N f * tsum M g * c + = tsum N (fun i => f i * (tsum M g * c)) := by + rw [Nat.mul_assoc, tsum_mul_const] + _ = tsum N (fun i => tsum M (fun j => f i * (g j * c))) := by + refine tsum_congr (fun i hi => ?_) + rw [tsum_mul_const, const_mul_tsum] + +/-- Box form of a product of two partial sums (times a constant). -/ +theorem expNum_mul_box (N M p1 p2 q c : Nat) : + expNum N p1 q * expNum M p2 q * c = + tsum N (fun i => tsum M (fun j => + ffacAux i (N - i) * ffacAux j (M - j) * c * + (p1 ^ i * (p2 ^ j * (q ^ (N - i) * q ^ (M - j)))))) := by + rw [expNum_eq_tsum, expNum_eq_tsum, tsum_mul_tsum] + refine tsum_congr (fun i hi => tsum_congr (fun j hj => ?_)) + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + +/-- Second convolution coefficient identity (triangle side, equal scales). -/ +theorem coef_eq2 {K n i : Nat} (hn : n ≤ K) (hi : i ≤ n) : + ffacAux n (K - n) * cho n i * fact K = + ffacAux i (K - i) * ffacAux (n - i) (K - (n - i)) := by + refine Nat.eq_of_mul_eq_mul_right (mul_pos' (fact_pos i) (fact_pos (n - i))) ?_ + have hL : ffacAux n (K - n) * cho n i * fact K * (fact i * fact (n - i)) = + ffacAux n (K - n) * ((cho n i * (fact i * fact (n - i))) * fact K) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [hL, cho_fact n i hi] + have hL2 : ffacAux n (K - n) * (fact n * fact K) = + (ffacAux n (K - n) * fact n) * fact K := by + rw [Nat.mul_assoc] + rw [hL2, ffacAux_mul_fact, show n + (K - n) = K by omega] + have hR : ffacAux i (K - i) * ffacAux (n - i) (K - (n - i)) * (fact i * fact (n - i)) = + (ffacAux i (K - i) * fact i) * (ffacAux (n - i) (K - (n - i)) * fact (n - i)) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [hR, ffacAux_mul_fact, ffacAux_mul_fact, show i + (K - i) = K by omega, + show n - i + (K - (n - i)) = K by omega] + +/-- Triangle form of a partial sum at a sum argument (times a constant). -/ +theorem expNum_add_tri (C p1 p2 q c : Nat) : + expNum C (p1 + p2) q * c = + tsum C (fun n => tsum n (fun i => + ffacAux (i + (n - i)) (C - (i + (n - i))) * cho (i + (n - i)) i * c * + (p1 ^ i * (p2 ^ (n - i) * q ^ (C - (i + (n - i))))))) := by + rw [expNum_eq_tsum, tsum_mul_const] + refine tsum_congr (fun n hn => ?_) + show ffacAux n (C - n) * (p1 + p2) ^ n * q ^ (C - n) * c = _ + rw [add_pow, const_mul_tsum, tsum_mul_const, tsum_mul_const] + refine tsum_congr (fun i hi => ?_) + rw [show i + (n - i) = n by omega] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + +/-- `S_N(p1/q) S_M(p2/q) ≤ S_{N+M}((p1+p2)/q)`, integer-scaled. -/ +theorem prod_le_sum (N M p1 p2 q : Nat) : + expNum N p1 q * expNum M p2 q * fact (N + M) ≤ + expNum (N + M) (p1 + p2) q * (fact N * fact M) := by + rw [expNum_mul_box N M p1 p2 q (fact (N + M)), + expNum_add_tri (N + M) p1 p2 q (fact N * fact M)] + refine Nat.le_trans (tsum_le_tsum fun i hi => tsum_le_tsum fun j hj => + Nat.le_of_eq ?_) + (box_le_tri (fun i j => + ffacAux (i + j) (N + M - (i + j)) * cho (i + j) i * (fact N * fact M) * + (p1 ^ i * (p2 ^ j * q ^ (N + M - (i + j))))) N M) + have hq : q ^ (N - i) * q ^ (M - j) = q ^ (N + M - (i + j)) := by + rw [← Nat.pow_add] + congr 1 + omega + rw [hq, coef_eq hi hj] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + +/-- `S_K((p1+p2)/q) ≤ S_K(p1/q) S_K(p2/q)`, integer-scaled. -/ +theorem sum_le_prod (K p1 p2 q : Nat) : + expNum K (p1 + p2) q * (fact K * q ^ K) ≤ expNum K p1 q * expNum K p2 q := by + rw [expNum_add_tri K p1 p2 q (fact K * q ^ K), + show expNum K p1 q * expNum K p2 q = expNum K p1 q * expNum K p2 q * 1 from + (Nat.mul_one _).symm, + expNum_mul_box K K p1 p2 q 1] + refine Nat.le_trans (Nat.le_of_eq ?_) + (tri_le_box (fun i j => + ffacAux i (K - i) * ffacAux j (K - j) * 1 * + (p1 ^ i * (p2 ^ j * (q ^ (K - i) * q ^ (K - j))))) K) + refine tsum_congr (fun n hn => tsum_congr (fun i hi => ?_)) + rw [show i + (n - i) = n by omega, + show ffacAux i (K - i) * ffacAux (n - i) (K - (n - i)) = + ffacAux n (K - n) * cho n i * fact K from (coef_eq2 hn hi).symm, + show q ^ (K - i) * q ^ (K - (n - i)) = q ^ K * q ^ (K - n) from by + rw [← Nat.pow_add, ← Nat.pow_add] + congr 1 + omega] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm, Nat.one_mul] + +/-! ## Monotonicity and the tail bound -/ + +/-- Cross-scale fraction transitivity: `a/b ≤ c/d ≤ e/f → a/b ≤ e/f`. -/ +theorem div_le_trans {a b c d e f : Nat} (hd : 0 < d) + (h1 : a * d ≤ c * b) (h2 : c * f ≤ e * d) : a * f ≤ e * b := by + refine Nat.le_of_mul_le_mul_right ?_ hd + calc a * f * d = a * d * f := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + _ ≤ c * b * f := Nat.mul_le_mul_right f h1 + _ = c * f * b := by simp only [Nat.mul_comm, Nat.mul_left_comm] + _ ≤ e * d * b := Nat.mul_le_mul_right b h2 + _ = e * b * d := by simp only [Nat.mul_comm, Nat.mul_left_comm] + +theorem expNum_step_le (n p q : Nat) : + (n + 1) * q * expNum n p q ≤ expNum (n + 1) p q := by + show _ ≤ (n + 1) * q * expNum n p q + p ^ (n + 1) + omega + +/-- `S_n ≤ S_m` for `n ≤ m`, cross-scaled. -/ +theorem expNum_mono_N {p q : Nat} {n m : Nat} (h : n ≤ m) : + expNum n p q * (fact m * q ^ m) ≤ expNum m p q * (fact n * q ^ n) := by + have key : ∀ d, expNum n p q * (fact (n + d) * q ^ (n + d)) ≤ + expNum (n + d) p q * (fact n * q ^ n) := by + intro d + induction d with + | zero => exact Nat.le_refl _ + | succ k ih => + have hf : fact (n + (k + 1)) = (n + k + 1) * fact (n + k) := rfl + have hp : q ^ (n + (k + 1)) = q ^ (n + k) * q := by + rw [show n + (k + 1) = (n + k) + 1 by omega, Nat.pow_succ] + have e1 : expNum n p q * (fact (n + (k + 1)) * q ^ (n + (k + 1))) = + (n + k + 1) * q * (expNum n p q * (fact (n + k) * q ^ (n + k))) := by + rw [hf, hp] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [e1] + have step1 : (n + k + 1) * q * (expNum n p q * (fact (n + k) * q ^ (n + k))) ≤ + (n + k + 1) * q * (expNum (n + k) p q * (fact n * q ^ n)) := + Nat.mul_le_mul_left _ ih + have e2 : (n + k + 1) * q * (expNum (n + k) p q * (fact n * q ^ n)) = + (n + k + 1) * q * expNum (n + k) p q * (fact n * q ^ n) := by + simp only [Nat.mul_assoc] + have step2 : (n + k + 1) * q * expNum (n + k) p q * (fact n * q ^ n) ≤ + expNum (n + k + 1) p q * (fact n * q ^ n) := + Nat.mul_le_mul_right _ (expNum_step_le (n + k) p q) + rw [show n + (k + 1) = n + k + 1 from rfl] + omega + have hkey := key (m - n) + rw [show n + (m - n) = m by omega] at hkey + exact hkey + +/-- Argument monotonicity: `p/q ≤ p'/q'` gives `S_n(p/q) ≤ S_n(p'/q')`. -/ +theorem expNum_arg_mono {p q p' q' : Nat} (h : p * q' ≤ p' * q) (n : Nat) : + expNum n p q * q' ^ n ≤ expNum n p' q' * q ^ n := by + induction n with + | zero => exact Nat.le_refl _ + | succ k ih => + show ((k + 1) * q * expNum k p q + p ^ (k + 1)) * q' ^ (k + 1) ≤ + ((k + 1) * q' * expNum k p' q' + p' ^ (k + 1)) * q ^ (k + 1) + rw [Nat.add_mul ((k + 1) * q * expNum k p q) (p ^ (k + 1)) (q' ^ (k + 1)), + Nat.add_mul ((k + 1) * q' * expNum k p' q') (p' ^ (k + 1)) (q ^ (k + 1))] + have h1 : (k + 1) * q * expNum k p q * q' ^ (k + 1) ≤ + (k + 1) * q' * expNum k p' q' * q ^ (k + 1) := by + have e1 : (k + 1) * q * expNum k p q * q' ^ (k + 1) = + (k + 1) * (q * q') * (expNum k p q * q' ^ k) := by + rw [Nat.pow_succ] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + have e2 : (k + 1) * q' * expNum k p' q' * q ^ (k + 1) = + (k + 1) * (q * q') * (expNum k p' q' * q ^ k) := by + rw [Nat.pow_succ] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [e1, e2] + exact Nat.mul_le_mul_left _ ih + have h2 : p ^ (k + 1) * q' ^ (k + 1) ≤ p' ^ (k + 1) * q ^ (k + 1) := by + rw [← Nat.mul_pow, ← Nat.mul_pow] + exact Nat.pow_le_pow_left h (k + 1) + omega + +theorem expNum_zero_arg (n q : Nat) : expNum n 0 q = fact n * q ^ n := by + induction n with + | zero => rfl + | succ k ih => + show (k + 1) * q * expNum k 0 q + 0 ^ (k + 1) = fact (k + 1) * q ^ (k + 1) + rw [ih, show (0 : Nat) ^ (k + 1) = 0 by rw [Nat.zero_pow (by omega)], + show fact (k + 1) = (k + 1) * fact k from rfl, Nat.pow_succ] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + omega + +/-- One step of the decreasing tail potential +`B_M = (E_M (M+1) q + 2 p^(M+1)) / ((M+1)! q^(M+1))`, for `2p ≤ (M+2)q`. -/ +theorem tail_potential_step {p q M : Nat} (hM : 2 * p ≤ (M + 2) * q) : + expNum (M + 1) p q * ((M + 2) * q) + 2 * p ^ (M + 2) ≤ + (expNum M p q * ((M + 1) * q) + 2 * p ^ (M + 1)) * ((M + 2) * q) := by + have hE : expNum (M + 1) p q = (M + 1) * q * expNum M p q + p ^ (M + 1) := rfl + have hp2 : p ^ (M + 2) = p * p ^ (M + 1) := by + rw [show M + 2 = (M + 1) + 1 by omega, Nat.pow_succ, Nat.mul_comm] + have hkey : 2 * (p * p ^ (M + 1)) ≤ (M + 2) * q * p ^ (M + 1) := by + rw [← Nat.mul_assoc] + exact Nat.mul_le_mul_right _ hM + have eL : expNum (M + 1) p q * ((M + 2) * q) + 2 * p ^ (M + 2) = + expNum M p q * ((M + 1) * q) * ((M + 2) * q) + + (M + 2) * q * p ^ (M + 1) + 2 * (p * p ^ (M + 1)) := by + rw [hE, hp2, Nat.add_mul ((M + 1) * q * expNum M p q) (p ^ (M + 1)) ((M + 2) * q)] + have a1 : (M + 1) * q * expNum M p q * ((M + 2) * q) = + expNum M p q * ((M + 1) * q) * ((M + 2) * q) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + have a2 : p ^ (M + 1) * ((M + 2) * q) = (M + 2) * q * p ^ (M + 1) := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + omega + have eR : (expNum M p q * ((M + 1) * q) + 2 * p ^ (M + 1)) * ((M + 2) * q) = + expNum M p q * ((M + 1) * q) * ((M + 2) * q) + + 2 * ((M + 2) * q * p ^ (M + 1)) := by + rw [Nat.add_mul (expNum M p q * ((M + 1) * q)) (2 * p ^ (M + 1)) ((M + 2) * q)] + have a3 : 2 * p ^ (M + 1) * ((M + 2) * q) = 2 * ((M + 2) * q * p ^ (M + 1)) := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + omega + omega + +/-- All partial sums beyond `K` stay under the `K`-th tail potential: +`S_M ≤ B_K` for `M ≥ K` when `2p ≤ (K+2)q`. -/ +theorem tail_bound {p q K : Nat} (hq : 0 < q) (hK : 2 * p ≤ (K + 2) * q) : + ∀ M, expNum M p q * (fact (K + 1) * q ^ (K + 1)) ≤ + (expNum K p q * ((K + 1) * q) + 2 * p ^ (K + 1)) * (fact M * q ^ M) := by + -- denominators are positive + have hden : ∀ j, 0 < fact j * q ^ j := fun j => + mul_pos' (fact_pos j) (Nat.pow_pos hq) + -- B_(K+d) ≤ B_K by chaining the potential step + have hB : ∀ d, + (expNum (K + d) p q * ((K + d + 1) * q) + 2 * p ^ (K + d + 1)) * + (fact (K + 1) * q ^ (K + 1)) ≤ + (expNum K p q * ((K + 1) * q) + 2 * p ^ (K + 1)) * + (fact (K + d + 1) * q ^ (K + d + 1)) := by + intro d + induction d with + | zero => exact Nat.le_refl _ + | succ e ih => + have hstep := tail_potential_step (p := p) (q := q) (M := K + e) + (by have : (K + 2) * q ≤ (K + e + 2) * q := Nat.mul_le_mul_right q (by omega) + omega) + -- B_(K+e+1) ≤ B_(K+e) cross-scaled, then transitivity with ih + have hcross : (expNum (K + e + 1) p q * ((K + e + 2) * q) + 2 * p ^ (K + e + 2)) * + (fact (K + e + 1) * q ^ (K + e + 1)) ≤ + (expNum (K + e) p q * ((K + e + 1) * q) + 2 * p ^ (K + e + 1)) * + (fact (K + e + 2) * q ^ (K + e + 2)) := by + have hf : fact (K + e + 2) = (K + e + 2) * fact (K + e + 1) := rfl + have hp : q ^ (K + e + 2) = q ^ (K + e + 1) * q := by + rw [show K + e + 2 = (K + e + 1) + 1 by omega, Nat.pow_succ] + rw [hf, hp] + have e1 : (expNum (K + e) p q * ((K + e + 1) * q) + 2 * p ^ (K + e + 1)) * + ((K + e + 2) * fact (K + e + 1) * (q ^ (K + e + 1) * q)) = + ((expNum (K + e) p q * ((K + e + 1) * q) + 2 * p ^ (K + e + 1)) * + ((K + e + 2) * q)) * (fact (K + e + 1) * q ^ (K + e + 1)) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [e1] + exact Nat.mul_le_mul_right _ (by + rw [show K + e + 1 + 1 = K + e + 2 by omega] at hstep + exact hstep) + rw [show K + (e + 1) = K + e + 1 by omega] + exact div_le_trans (hden (K + e + 1)) hcross ih + intro M + rcases Nat.lt_or_ge M K with hlt | hge + · -- below K: S_M ≤ S_K ≤ B_K + have hmono := expNum_mono_N (p := p) (q := q) (Nat.le_of_lt hlt) + have hSK : expNum K p q * (fact (K + 1) * q ^ (K + 1)) ≤ + (expNum K p q * ((K + 1) * q) + 2 * p ^ (K + 1)) * (fact K * q ^ K) := by + have e1 : expNum K p q * (fact (K + 1) * q ^ (K + 1)) = + expNum K p q * ((K + 1) * q) * (fact K * q ^ K) := by + rw [show fact (K + 1) = (K + 1) * fact K from rfl, Nat.pow_succ] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [e1] + exact Nat.mul_le_mul_right _ (by omega) + exact div_le_trans (hden K) hmono hSK + · -- at or above K: S_M ≤ B_M ≤ B_K + have hSM : expNum M p q * (fact (M + 1) * q ^ (M + 1)) ≤ + (expNum M p q * ((M + 1) * q) + 2 * p ^ (M + 1)) * (fact M * q ^ M) := by + have e1 : expNum M p q * (fact (M + 1) * q ^ (M + 1)) = + expNum M p q * ((M + 1) * q) * (fact M * q ^ M) := by + rw [show fact (M + 1) = (M + 1) * fact M from rfl, Nat.pow_succ] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + rw [e1] + exact Nat.mul_le_mul_right _ (by omega) + have hBM := hB (M - K) + rw [show K + (M - K) = M by omega] at hBM + exact div_le_trans (hden (M + 1)) hSM hBM + +/-! ## Exponential caps + +`capUB p q y w` says `e^(p/q) ≤ y/w` (every partial sum is bounded); +`capLB p q y w` says `e^(p/q) ≥ y/w` (some partial sum already reaches it). +These four-`Nat` relations are the interface the floor-specification +assembly uses; the lemmas below are the surrogates for +`e^(a+b) = e^a e^b` and monotonicity. +-/ + +def capUB (p q y w : Nat) : Prop := ∀ n, expNum n p q * w ≤ y * (fact n * q ^ n) + +def capLB (p q y w : Nat) : Prop := ∃ n, y * (fact n * q ^ n) ≤ expNum n p q * w + +theorem capUB_mul {p1 p2 q y1 w1 y2 w2 : Nat} (hq : 0 < q) + (h1 : capUB p1 q y1 w1) (h2 : capUB p2 q y2 w2) : + capUB (p1 + p2) q (y1 * y2) (w1 * w2) := by + intro n + have hd : 0 < fact n * q ^ n := mul_pos' (fact_pos n) (Nat.pow_pos hq) + refine Nat.le_of_mul_le_mul_right ?_ hd + calc expNum n (p1 + p2) q * (w1 * w2) * (fact n * q ^ n) + = expNum n (p1 + p2) q * (fact n * q ^ n) * (w1 * w2) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ expNum n p1 q * expNum n p2 q * (w1 * w2) := + Nat.mul_le_mul_right _ (sum_le_prod n p1 p2 q) + _ = (expNum n p1 q * w1) * (expNum n p2 q * w2) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (y1 * (fact n * q ^ n)) * (y2 * (fact n * q ^ n)) := + Nat.mul_le_mul (h1 n) (h2 n) + _ = y1 * y2 * (fact n * q ^ n) * (fact n * q ^ n) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + +theorem capLB_mul {p1 p2 q y1 w1 y2 w2 : Nat} + (h1 : capLB p1 q y1 w1) (h2 : capLB p2 q y2 w2) : + capLB (p1 + p2) q (y1 * y2) (w1 * w2) := by + obtain ⟨n1, e1⟩ := h1 + obtain ⟨n2, e2⟩ := h2 + refine ⟨n1 + n2, ?_⟩ + have hd : 0 < fact n1 * fact n2 := mul_pos' (fact_pos n1) (fact_pos n2) + refine Nat.le_of_mul_le_mul_right ?_ hd + calc y1 * y2 * (fact (n1 + n2) * q ^ (n1 + n2)) * (fact n1 * fact n2) + = (y1 * (fact n1 * q ^ n1)) * (y2 * (fact n2 * q ^ n2)) * fact (n1 + n2) := by + rw [show q ^ (n1 + n2) = q ^ n1 * q ^ n2 from Nat.pow_add q n1 n2] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (expNum n1 p1 q * w1) * (expNum n2 p2 q * w2) * fact (n1 + n2) := + Nat.mul_le_mul_right _ (Nat.mul_le_mul e1 e2) + _ = expNum n1 p1 q * expNum n2 p2 q * fact (n1 + n2) * (w1 * w2) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ expNum (n1 + n2) (p1 + p2) q * (fact n1 * fact n2) * (w1 * w2) := + Nat.mul_le_mul_right _ (prod_le_sum n1 n2 p1 p2 q) + _ = expNum (n1 + n2) (p1 + p2) q * (w1 * w2) * (fact n1 * fact n2) := by + simp only [Nat.mul_assoc, Nat.mul_comm] + +/-- Quotient mover: from `e^(a+b) ≤ C/W` and `e^b ≥ G/V`, get `e^a ≤ CV/(WG)`. -/ +theorem capUB_cancel {pa pb q C W G V : Nat} (hq : 0 < q) + (hsum : capUB (pa + pb) q C W) (hb : capLB pb q G V) : + capUB pa q (C * V) (W * G) := by + intro n + obtain ⟨m, hm⟩ := hb + have hd : 0 < fact m * q ^ m * fact (n + m) := + mul_pos' (mul_pos' (fact_pos m) (Nat.pow_pos hq)) (fact_pos (n + m)) + refine Nat.le_of_mul_le_mul_right ?_ hd + calc expNum n pa q * (W * G) * (fact m * q ^ m * fact (n + m)) + = (G * (fact m * q ^ m)) * (expNum n pa q * W * fact (n + m)) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (expNum m pb q * V) * (expNum n pa q * W * fact (n + m)) := + Nat.mul_le_mul_right _ hm + _ = (expNum n pa q * expNum m pb q * fact (n + m)) * (W * V) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (expNum (n + m) (pa + pb) q * (fact n * fact m)) * (W * V) := + Nat.mul_le_mul_right _ (prod_le_sum n m pa pb q) + _ = (expNum (n + m) (pa + pb) q * W) * (fact n * fact m * V) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (C * (fact (n + m) * q ^ (n + m))) * (fact n * fact m * V) := + Nat.mul_le_mul_right _ (hsum (n + m)) + _ = C * V * (fact n * q ^ n) * (fact m * q ^ m * fact (n + m)) := by + rw [show q ^ (n + m) = q ^ n * q ^ m from Nat.pow_add q n m] + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + +theorem capUB_one (q : Nat) : capUB 0 q 1 1 := by + intro n + rw [expNum_zero_arg] + omega + +theorem capLB_one (q : Nat) : capLB 0 q 1 1 := + ⟨0, by rw [expNum_zero_arg]; omega⟩ + +theorem capUB_pow {p q y w : Nat} (hq : 0 < q) (h : capUB p q y w) : + ∀ k, capUB (k * p) q (y ^ k) (w ^ k) := by + intro k + induction k with + | zero => + show capUB (0 * p) q (y ^ 0) (w ^ 0) + rw [Nat.zero_mul] + exact capUB_one q + | succ j ih => + have := capUB_mul hq ih h + rw [(Nat.succ_mul j p).symm] at this + rw [Nat.pow_succ, Nat.pow_succ] + exact this + +theorem capLB_pow {p q y w : Nat} (h : capLB p q y w) : + ∀ k, capLB (k * p) q (y ^ k) (w ^ k) := by + intro k + induction k with + | zero => + show capLB (0 * p) q (y ^ 0) (w ^ 0) + rw [Nat.zero_mul] + exact capLB_one q + | succ j ih => + have := capLB_mul ih h + rw [(Nat.succ_mul j p).symm] at this + rw [Nat.pow_succ, Nat.pow_succ] + exact this + +/-- Transport an upper cap down a smaller argument: `p/q ≤ p'/q'`. -/ +theorem capUB_arg {p q p' q' y w : Nat} (hq' : 0 < q') (h : p * q' ≤ p' * q) + (hub : capUB p' q' y w) : capUB p q y w := by + intro n + have hd : 0 < q' ^ n := Nat.pow_pos hq' + refine Nat.le_of_mul_le_mul_right ?_ hd + calc expNum n p q * w * q' ^ n + = (expNum n p q * q' ^ n) * w := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (expNum n p' q' * q ^ n) * w := + Nat.mul_le_mul_right _ (expNum_arg_mono h n) + _ = (expNum n p' q' * w) * q ^ n := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (y * (fact n * q' ^ n)) * q ^ n := + Nat.mul_le_mul_right _ (hub n) + _ = y * (fact n * q ^ n) * q' ^ n := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + +/-- Transport a lower cap up a larger argument: `p'/q' ≤ p/q`. -/ +theorem capLB_arg {p q p' q' y w : Nat} (hq' : 0 < q') (h : p' * q ≤ p * q') + (hlb : capLB p' q' y w) : capLB p q y w := by + obtain ⟨n, hn⟩ := hlb + refine ⟨n, ?_⟩ + have hd : 0 < q' ^ n := Nat.pow_pos hq' + refine Nat.le_of_mul_le_mul_right ?_ hd + calc y * (fact n * q ^ n) * q' ^ n + = (y * (fact n * q' ^ n)) * q ^ n := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (expNum n p' q' * w) * q ^ n := + Nat.mul_le_mul_right _ hn + _ = (expNum n p' q' * q ^ n) * w := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + _ ≤ (expNum n p q * q' ^ n) * w := + Nat.mul_le_mul_right _ (expNum_arg_mono h n) + _ = expNum n p q * w * q' ^ n := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + +/-- Weaken an upper cap to a looser target: `y/w ≤ y'/w'`. -/ +theorem capUB_weaken {p q y w y' w' : Nat} (hw : 0 < w) + (h : capUB p q y w) (hyy : y * w' ≤ y' * w) : capUB p q y' w' := by + intro n + refine Nat.le_of_mul_le_mul_right ?_ hw + calc expNum n p q * w' * w = expNum n p q * w * w' := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + _ ≤ y * (fact n * q ^ n) * w' := Nat.mul_le_mul_right _ (h n) + _ = y * w' * (fact n * q ^ n) := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ y' * w * (fact n * q ^ n) := Nat.mul_le_mul_right _ hyy + _ = y' * (fact n * q ^ n) * w := by + simp only [Nat.mul_assoc, Nat.mul_comm] + +/-- Strengthen a lower cap to a looser target: `y'/w' ≤ y/w`. -/ +theorem capLB_weaken {p q y w y' w' : Nat} (hw : 0 < w) + (h : capLB p q y w) (hyy : y' * w ≤ y * w') : capLB p q y' w' := by + obtain ⟨n, hn⟩ := h + refine ⟨n, ?_⟩ + refine Nat.le_of_mul_le_mul_right ?_ hw + calc y' * (fact n * q ^ n) * w = y' * w * (fact n * q ^ n) := by + simp only [Nat.mul_assoc, Nat.mul_comm] + _ ≤ y * w' * (fact n * q ^ n) := Nat.mul_le_mul_right _ hyy + _ = y * (fact n * q ^ n) * w' := by + simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + _ ≤ expNum n p q * w * w' := Nat.mul_le_mul_right _ hn + _ = expNum n p q * w' * w := by + simp only [Nat.mul_comm, Nat.mul_left_comm] + +/-- Turn one evaluated partial sum plus the geometric tail into a full upper +cap: with `2p ≤ (K+2)q` and +`(E_K (K+1) q + 2 p^(K+1)) w ≤ y (K+1)! q^(K+1)`, conclude `e^(p/q) ≤ y/w`. -/ +theorem capUB_of_partial {p q K y w : Nat} (hq : 0 < q) (hK : 2 * p ≤ (K + 2) * q) + (h : (expNum K p q * ((K + 1) * q) + 2 * p ^ (K + 1)) * w ≤ + y * (fact (K + 1) * q ^ (K + 1))) : capUB p q y w := by + intro M + exact div_le_trans (mul_pos' (fact_pos (K + 1)) (Nat.pow_pos hq)) + (tail_bound hq hK M) h + +end Common.Exp diff --git a/formal/common/Common/Foundation/Kronecker.lean b/formal/common/Common/Foundation/Kronecker.lean new file mode 100644 index 000000000..e3f35c2ef --- /dev/null +++ b/formal/common/Common/Foundation/Kronecker.lean @@ -0,0 +1,272 @@ +import Common.Foundation.ShiftCert + +/-! +# Polynomial identity testing by Kronecker evaluation + +Two integer polynomials with ℓ1-norm below half of `2^B` agree everywhere +as soon as they agree at the single point `2^B`: the evaluation is the +balanced radix-`2^B` digit string of the coefficient list, which is +unique. This turns the certificate-vs-literal equalities — whose direct +list-equality decides force the whole construction through the kernel's +per-coefficient evaluation overhead — into one closed integer-arithmetic +comparison plus a symbolic ℓ1 bound. +-/ + +namespace Common.Poly + +/-- ℓ1 norm of the coefficient list. -/ +def polyL1 : List Int → Nat + | [] => 0 + | c :: cs => c.natAbs + polyL1 cs + +theorem pow2_cast (B : Nat) : ((2 : Int) ^ B) = ((2 ^ B : Nat) : Int) := by + rw [Int.natCast_pow] + rfl + +/-- A multiple of `2^B` strictly inside `(-2^B, 2^B)` is zero. -/ +theorem eq_zero_of_mul_pow {B : Nat} {d k : Int} (hd : d = 2 ^ B * k) + (h1 : -(2 ^ B) < d) (h2 : d < 2 ^ B) : d = 0 ∧ k = 0 := by + have hP : (0 : Int) < 2 ^ B := by + have e : ((2 : Int) ^ B) = ((2 ^ B : Nat) : Int) := by + rw [Int.natCast_pow] + rfl + have h2 : 0 < 2 ^ B := Nat.pow_pos (by omega) + omega + rcases Int.lt_or_le k 0 with hk | hk + · exfalso + have h1k : k ≤ -1 := by omega + have := mul_le_mul_left_nonneg h1k (by omega : (0 : Int) ≤ 2 ^ B) + have e : (2 : Int) ^ B * (-1) = -(2 ^ B) := by + rw [Int.mul_neg, Int.mul_one] + omega + rcases Int.lt_or_le 0 k with hk2 | hk2 + · exfalso + have h1k : 1 ≤ k := by omega + have := mul_le_mul_left_nonneg h1k (by omega : (0 : Int) ≤ 2 ^ B) + have e : (2 : Int) ^ B * 1 = 2 ^ B := Int.mul_one _ + omega + · have hk0 : k = 0 := by omega + subst hk0 + rw [Int.mul_zero] at hd + exact ⟨hd, rfl⟩ + +/-- Rewrite `(2 : Int) ^ n` through `Nat.pow`. The `Int` monoid power is +`npowRec` (a linear chain of multiplications the kernel does not accelerate), +whereas `Nat.pow` is a GMP-backed kernel primitive. Rewriting with this before +a `decide +kernel` that evaluates a Kronecker point keeps the base a single +cheap literal instead of an `n`-step reduction recomputed at every use. -/ +theorem int_two_pow (n : Nat) : (2 : Int) ^ n = ((2 ^ n : Nat) : Int) := + (Int.natCast_pow 2 n).symm + +/-- Polynomials with small ℓ1 norm that agree at `2^B` agree everywhere. -/ +theorem evalPoly_ext {B : Nat} : ∀ (p q : List Int), + polyL1 p * 2 < 2 ^ B → polyL1 q * 2 < 2 ^ B → + evalPoly p ((2 : Int) ^ B) = evalPoly q ((2 : Int) ^ B) → + ∀ x : Int, evalPoly p x = evalPoly q x := by + intro p + induction p with + | nil => + intro q + induction q with + | nil => intro _ _ _ _; rfl + | cons b q' ihq => + intro hp hq he x + -- 0 = b + 2^B e' forces b = 0 and e' = 0 + show evalPoly ([] : List Int) x = b + x * evalPoly q' x + have he' : (0 : Int) = b + 2 ^ B * evalPoly q' ((2 : Int) ^ B) := he + simp only [polyL1] at hq + have hb : b.natAbs * 2 < 2 ^ B ∧ polyL1 q' * 2 < 2 ^ B := by omega + have hbI : -(2 ^ B : Int) < b ∧ (b : Int) < 2 ^ B := by + rw [pow2_cast B] + omega + obtain ⟨hb0, hk0⟩ := eq_zero_of_mul_pow (B := B) (d := -b) + (k := evalPoly q' ((2 : Int) ^ B)) (by omega) (by omega) (by omega) + have htail := ihq hp hb.2 (by + show (0 : Int) = evalPoly q' ((2 : Int) ^ B) + omega) x + show (0 : Int) = b + x * evalPoly q' x + have : evalPoly ([] : List Int) x = (0 : Int) := rfl + rw [this] at htail + rw [← htail] + omega + | cons a p' ihp => + intro q + match q with + | [] => + intro hp hq he x + have he' : a + 2 ^ B * evalPoly p' ((2 : Int) ^ B) = (0 : Int) := he + simp only [polyL1] at hp + have ha : a.natAbs * 2 < 2 ^ B ∧ polyL1 p' * 2 < 2 ^ B := by omega + have haI : -(2 ^ B : Int) < a ∧ (a : Int) < 2 ^ B := by + rw [pow2_cast B] + omega + obtain ⟨ha0, hk0⟩ := eq_zero_of_mul_pow (B := B) (d := -a) + (k := evalPoly p' ((2 : Int) ^ B)) (by omega) (by omega) (by omega) + have htail := ihp [] ha.2 hq (by + show evalPoly p' ((2 : Int) ^ B) = (0 : Int) + omega) x + show a + x * evalPoly p' x = (0 : Int) + have h0 : evalPoly ([] : List Int) x = (0 : Int) := rfl + rw [h0] at htail + rw [htail] + omega + | b :: q' => + intro hp hq he x + have he' : a + 2 ^ B * evalPoly p' ((2 : Int) ^ B) = + b + 2 ^ B * evalPoly q' ((2 : Int) ^ B) := he + simp only [polyL1] at hp hq + have hb : a.natAbs * 2 < 2 ^ B ∧ polyL1 p' * 2 < 2 ^ B ∧ + b.natAbs * 2 < 2 ^ B ∧ polyL1 q' * 2 < 2 ^ B := by omega + have habI : -(2 ^ B : Int) < a - b ∧ (a - b : Int) < 2 ^ B := by + rw [pow2_cast B] + omega + have hd : a - b = 2 ^ B * (evalPoly q' ((2 : Int) ^ B) - + evalPoly p' ((2 : Int) ^ B)) := by + have e := Int.mul_sub ((2 : Int) ^ B) (evalPoly q' ((2 : Int) ^ B)) + (evalPoly p' ((2 : Int) ^ B)) + generalize hE1 : (2 : Int) ^ B * evalPoly p' ((2 : Int) ^ B) = E1 at he' e + generalize hE2 : (2 : Int) ^ B * evalPoly q' ((2 : Int) ^ B) = E2 at he' e + omega + obtain ⟨hab0, hk0⟩ := eq_zero_of_mul_pow (B := B) hd habI.1 habI.2 + have htail := ihp q' hb.2.1 hb.2.2.2 (by omega) x + show a + x * evalPoly p' x = b + x * evalPoly q' x + rw [htail] + omega + +theorem eval01 (x : Int) : evalPoly ([0, 1] : List Int) x = x := by + show (0 : Int) + x * (1 + x * 0) = x + omega + +/-! ## ℓ1 bounds through the polynomial operations -/ + +theorem polyL1_polyAdd : ∀ (p q : List Int), polyL1 (polyAdd p q) ≤ polyL1 p + polyL1 q := by + intro p + induction p with + | nil => + intro q + simp [polyAdd, polyL1] + | cons a p ih => + intro q + match q with + | [] => + show polyL1 (a :: p) ≤ polyL1 (a :: p) + polyL1 ([] : List Int) + simp only [polyL1] + omega + | b :: q => + show (a + b).natAbs + polyL1 (polyAdd p q) ≤ + (a.natAbs + polyL1 p) + (b.natAbs + polyL1 q) + have h1 := ih q + have h2 := Int.natAbs_add_le a b + omega + +theorem polyL1_polyScale (a : Int) : ∀ (p : List Int), + polyL1 (polyScale a p) ≤ a.natAbs * polyL1 p := by + intro p + induction p with + | nil => exact Nat.le_refl _ + | cons c cs ih => + show (a * c).natAbs + polyL1 (polyScale a cs) ≤ a.natAbs * (c.natAbs + polyL1 cs) + rw [Int.natAbs_mul] + have hd : a.natAbs * (c.natAbs + polyL1 cs) = + a.natAbs * c.natAbs + a.natAbs * polyL1 cs := Nat.mul_add _ _ _ + generalize hg1 : a.natAbs * c.natAbs = X at * + generalize hg2 : a.natAbs * polyL1 cs = Y at * + omega + +theorem polyL1_polyMulX (p : List Int) : polyL1 (polyMulX p) = polyL1 p := by + show (0 : Int).natAbs + polyL1 p = polyL1 p + omega + +theorem polyL1_polyNeg : ∀ (p : List Int), polyL1 (polyNeg p) = polyL1 p := by + intro p + induction p with + | nil => rfl + | cons c cs ih => + show (-c).natAbs + polyL1 (polyNeg cs) = c.natAbs + polyL1 cs + rw [Int.natAbs_neg, ih] + +theorem polyL1_polyMul : ∀ (p q : List Int), polyL1 (polyMul p q) ≤ polyL1 p * polyL1 q := by + intro p + induction p with + | nil => + intro q + show polyL1 ([] : List Int) ≤ polyL1 ([] : List Int) * polyL1 q + simp only [polyL1] + omega + | cons a p ih => + intro q + show polyL1 (polyAdd (polyScale a q) (polyMulX (polyMul p q))) ≤ + (a.natAbs + polyL1 p) * polyL1 q + have h1 := polyL1_polyAdd (polyScale a q) (polyMulX (polyMul p q)) + have h2 := polyL1_polyScale a q + have h3 := polyL1_polyMulX (polyMul p q) + have h4 := ih q + have hd : (a.natAbs + polyL1 p) * polyL1 q = + a.natAbs * polyL1 q + polyL1 p * polyL1 q := Nat.add_mul _ _ _ + generalize hg1 : a.natAbs * polyL1 q = X at * + generalize hg2 : polyL1 p * polyL1 q = Y at * + omega + +theorem polyL1_polyPow (p : List Int) : ∀ (k : Nat), + polyL1 (polyPow p k) ≤ polyL1 p ^ k := by + intro k + induction k with + | zero => + show (1 : Int).natAbs + polyL1 ([] : List Int) ≤ 1 + decide + | succ n ih => + show polyL1 (polyMul p (polyPow p n)) ≤ polyL1 p ^ (n + 1) + have h1 := polyL1_polyMul p (polyPow p n) + have h2 : polyL1 p ^ (n + 1) = polyL1 p ^ n * polyL1 p := Nat.pow_succ _ _ + have h3 : polyL1 p * polyL1 (polyPow p n) ≤ polyL1 p * polyL1 p ^ n := + Nat.mul_le_mul_left _ ih + have h4 : polyL1 p * polyL1 p ^ n = polyL1 p ^ n * polyL1 p := Nat.mul_comm _ _ + generalize hg1 : polyL1 p * polyL1 (polyPow p n) = X at * + generalize hg2 : polyL1 p * polyL1 p ^ n = Y at * + generalize hg3 : polyL1 p ^ n * polyL1 p = Z at * + omega + +theorem polyL1_expPolyNum (tn td : List Int) : ∀ (k : Nat), + polyL1 (expPolyNum tn td k) ≤ Common.Exp.expNum k (polyL1 tn) (polyL1 td) := by + intro k + induction k with + | zero => + show (1 : Int).natAbs + polyL1 ([] : List Int) ≤ 1 + decide + | succ n ih => + show polyL1 (polyAdd (polyScale ((n : Int) + 1) (polyMul td (expPolyNum tn td n))) + (polyPow tn (n + 1))) ≤ + (n + 1) * polyL1 td * Common.Exp.expNum n (polyL1 tn) (polyL1 td) + + polyL1 tn ^ (n + 1) + have h1 := polyL1_polyAdd (polyScale ((n : Int) + 1) + (polyMul td (expPolyNum tn td n))) (polyPow tn (n + 1)) + have h2 := polyL1_polyScale ((n : Int) + 1) (polyMul td (expPolyNum tn td n)) + have h3 := polyL1_polyMul td (expPolyNum tn td n) + have h4 := polyL1_polyPow tn (n + 1) + have hna : ((n : Int) + 1).natAbs = n + 1 := by omega + rw [hna] at h2 + have h5 : (n + 1) * polyL1 (polyMul td (expPolyNum tn td n)) ≤ + (n + 1) * (polyL1 td * polyL1 (expPolyNum tn td n)) := + Nat.mul_le_mul_left _ h3 + have h6 : polyL1 td * polyL1 (expPolyNum tn td n) ≤ + polyL1 td * Common.Exp.expNum n (polyL1 tn) (polyL1 td) := + Nat.mul_le_mul_left _ ih + have h7 : (n + 1) * (polyL1 td * polyL1 (expPolyNum tn td n)) ≤ + (n + 1) * (polyL1 td * Common.Exp.expNum n (polyL1 tn) (polyL1 td)) := + Nat.mul_le_mul_left _ h6 + have h8 : (n + 1) * (polyL1 td * Common.Exp.expNum n (polyL1 tn) (polyL1 td)) = + (n + 1) * polyL1 td * Common.Exp.expNum n (polyL1 tn) (polyL1 td) := + (Nat.mul_assoc _ _ _).symm + generalize hg1 : polyL1 (polyScale ((n : Int) + 1) + (polyMul td (expPolyNum tn td n))) = A at * + generalize hg2 : (n + 1) * polyL1 (polyMul td (expPolyNum tn td n)) = C at * + generalize hg3 : (n + 1) * (polyL1 td * polyL1 (expPolyNum tn td n)) = D at * + generalize hg4 : (n + 1) * (polyL1 td * Common.Exp.expNum n (polyL1 tn) (polyL1 td)) = E at * + generalize hg5 : (n + 1) * polyL1 td * Common.Exp.expNum n (polyL1 tn) (polyL1 td) = F at * + generalize hg6 : polyL1 (polyPow tn (n + 1)) = G at * + generalize hg7 : polyL1 tn ^ (n + 1) = H at * + generalize hg8 : polyL1 (polyAdd (polyScale ((n : Int) + 1) + (polyMul td (expPolyNum tn td n))) (polyPow tn (n + 1))) = T at * + omega + +end Common.Poly diff --git a/formal/common/Common/Foundation/KroneckerShift.lean b/formal/common/Common/Foundation/KroneckerShift.lean new file mode 100644 index 000000000..c17d23410 --- /dev/null +++ b/formal/common/Common/Foundation/KroneckerShift.lean @@ -0,0 +1,288 @@ +import Common.Foundation.Kronecker + +/-! +# Packed Taylor shifts for the cell walks + +The cell checker Taylor-shifts each certificate literal with a +Kronecker-substitution homomorphism: the shifted polynomial is *computed* +inside the decide as a handful of GMP-scale operations on sign-split packed +naturals (`kShiftHorner`, untrusted), then *certified* by one evaluation +identity at `2^B` through `evalPoly_ext`. The packed computation +needs no correctness lemmas: if it produced anything other than the true +shift, the evaluation identity in the checker would fail. The remaining +bound is an ℓ1 bound for true shifts, carried by `aeval`, the +absolute-value evaluation. +-/ + +namespace Common.Poly + +/-- Kronecker digit width shared by the cell-walk `checkCoverK` decides and +the cert-vs-literal `evalPoly_ext` identities. It must exceed `log2(2·ℓ1)` +of the certificates; the binding floor is the cell-walk `aeval` bound at +`~2^37772` (the certificate coefficients are `~37k`-bit and decay `~104` +bits per degree, so every monomial term is `~`constant scale), with the +eval-identity `polyL1` floor at `~2^37392`. This clears both with a +`~228`-bit margin, so it is near-minimal rather than arbitrary. -/ +def kB : Nat := 38000 + +/-! ## ℓ1 of a Taylor shift -/ + +/-- Evaluate the coefficient-magnitude polynomial at a `Nat` point. -/ +def aeval : List Int → Nat → Nat + | [], _ => 0 + | c :: cs, m => c.natAbs + m * aeval cs m + +theorem synthDiv_rem (p : List Int) (a : Int) : + (synthDiv p a).2 = evalPoly p a := by + have h := synthDiv_eval p a a + have e : a - a = 0 := by omega + rw [e, Int.mul_zero] at h + omega + +/-- Triangle inequality for evaluation against `aeval`. -/ +theorem evalPoly_natAbs_le : ∀ (p : List Int) (x : Int), + (evalPoly p x).natAbs ≤ aeval p x.natAbs := by + intro p + induction p with + | nil => intro x; exact Nat.le_refl _ + | cons c cs ih => + intro x + show (c + x * evalPoly cs x).natAbs ≤ c.natAbs + x.natAbs * aeval cs x.natAbs + have h1 := Int.natAbs_add_le c (x * evalPoly cs x) + have h2 : (x * evalPoly cs x).natAbs = x.natAbs * (evalPoly cs x).natAbs := + Int.natAbs_mul x (evalPoly cs x) + have h3 := ih x + have h4 : x.natAbs * (evalPoly cs x).natAbs ≤ x.natAbs * aeval cs x.natAbs := + Nat.mul_le_mul_left _ h3 + generalize hg1 : x.natAbs * (evalPoly cs x).natAbs = A at * + generalize hg2 : x.natAbs * aeval cs x.natAbs = B at * + omega + +/-- `aeval` is monotone in the point. -/ +theorem aeval_mono : ∀ (p : List Int) {m n : Nat}, m ≤ n → + aeval p m ≤ aeval p n := by + intro p + induction p with + | nil => intro m n _; exact Nat.le_refl _ + | cons c cs ih => + intro m n h + show c.natAbs + m * aeval cs m ≤ c.natAbs + n * aeval cs n + have h1 := ih h + have h2 : m * aeval cs m ≤ n * aeval cs n := + Nat.mul_le_mul h h1 + omega + +/-- The synthetic-division step preserves the `aeval` budget: remainder +magnitude plus the quotient's budget fit inside the dividend's budget at +`M = 1 + |a|`. -/ +theorem synthDiv_aeval_le : ∀ (p : List Int) (a : Int), + (evalPoly p a).natAbs + aeval (synthDiv p a).1 (1 + a.natAbs) ≤ + aeval p (1 + a.natAbs) := by + intro p + induction p with + | nil => + intro a + show (0 : Int).natAbs + 0 ≤ 0 + omega + | cons c cs ih => + intro a + match cs, ih with + | [], _ => + show (c + a * evalPoly ([] : List Int) a).natAbs + + aeval ([] : List Int) (1 + a.natAbs) ≤ c.natAbs + (1 + a.natAbs) * 0 + show (c + a * 0).natAbs + 0 ≤ c.natAbs + (1 + a.natAbs) * 0 + have e : c + a * 0 = c := by omega + rw [e] + omega + | c2 :: cs', ih => + have hrec := ih a + have hrem := synthDiv_rem (c2 :: cs') a + show (c + a * evalPoly (c2 :: cs') a).natAbs + + aeval ((synthDiv (c2 :: cs') a).2 :: (synthDiv (c2 :: cs') a).1) + (1 + a.natAbs) ≤ + c.natAbs + (1 + a.natAbs) * aeval (c2 :: cs') (1 + a.natAbs) + show (c + a * evalPoly (c2 :: cs') a).natAbs + + ((synthDiv (c2 :: cs') a).2.natAbs + + (1 + a.natAbs) * aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs)) ≤ + c.natAbs + (1 + a.natAbs) * aeval (c2 :: cs') (1 + a.natAbs) + rw [hrem] + have h1 := Int.natAbs_add_le c (a * evalPoly (c2 :: cs') a) + have h2 : (a * evalPoly (c2 :: cs') a).natAbs = + a.natAbs * (evalPoly (c2 :: cs') a).natAbs := + Int.natAbs_mul a (evalPoly (c2 :: cs') a) + have h3 : (1 + a.natAbs) * aeval (c2 :: cs') (1 + a.natAbs) = + aeval (c2 :: cs') (1 + a.natAbs) + + a.natAbs * aeval (c2 :: cs') (1 + a.natAbs) := by + rw [Nat.add_mul, Nat.one_mul] + have h4 : a.natAbs * ((evalPoly (c2 :: cs') a).natAbs + + aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs)) ≤ + a.natAbs * aeval (c2 :: cs') (1 + a.natAbs) := + Nat.mul_le_mul_left _ hrec + have h5 : a.natAbs * ((evalPoly (c2 :: cs') a).natAbs + + aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs)) = + a.natAbs * (evalPoly (c2 :: cs') a).natAbs + + a.natAbs * aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) := + Nat.mul_add _ _ _ + have h6 : (1 + a.natAbs) * aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) = + aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) + + a.natAbs * aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) := by + rw [Nat.add_mul, Nat.one_mul] + generalize hgEa : (evalPoly (c2 :: cs') a).natAbs = Ea at * + generalize hgQ : aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) = Q at * + generalize hgC : aeval (c2 :: cs') (1 + a.natAbs) = Cv at * + generalize hgX1 : a.natAbs * Ea = X1 at * + generalize hgX2 : a.natAbs * Q = X2 at * + generalize hgX3 : a.natAbs * Cv = X3 at * + generalize hgX4 : a.natAbs * (Ea + Q) = X4 at * + omega + +/-- ℓ1 of the Taylor shift is bounded by the absolute evaluation at +`1 + |a|`. -/ +theorem polyL1_polyShiftAux : ∀ (fuel : Nat) (p : List Int) (a : Int), + polyL1 (polyShiftAux fuel p a) ≤ aeval p (1 + a.natAbs) := by + intro fuel + induction fuel with + | zero => + intro p a + show polyL1 ([] : List Int) ≤ aeval p (1 + a.natAbs) + show 0 ≤ aeval p (1 + a.natAbs) + omega + | succ f ih => + intro p a + match p with + | [] => + show (0 : Nat) ≤ 0 + omega + | c :: cs => + show polyL1 ((synthDiv (c :: cs) a).2 :: + polyShiftAux f (synthDiv (c :: cs) a).1 a) ≤ + aeval (c :: cs) (1 + a.natAbs) + show (synthDiv (c :: cs) a).2.natAbs + + polyL1 (polyShiftAux f (synthDiv (c :: cs) a).1 a) ≤ + aeval (c :: cs) (1 + a.natAbs) + have h1 := ih (synthDiv (c :: cs) a).1 a + have h2 := synthDiv_aeval_le (c :: cs) a + have h3 := synthDiv_rem (c :: cs) a + have h4 : aeval (synthDiv (c :: cs) a).1 (1 + a.natAbs) ≤ + aeval (synthDiv (c :: cs) a).1 (1 + a.natAbs) := Nat.le_refl _ + generalize hg1 : polyL1 (polyShiftAux f (synthDiv (c :: cs) a).1 a) = L at * + generalize hg2 : aeval (synthDiv (c :: cs) a).1 (1 + a.natAbs) = Q at * + generalize hg3 : aeval (c :: cs) (1 + a.natAbs) = Cv at * + omega + +theorem polyL1_polyShift (p : List Int) (a : Int) : + polyL1 (polyShift p a) ≤ aeval p (1 + a.natAbs) := + polyL1_polyShiftAux p.length p a + +/-! ## Untrusted packed shift computation -/ + +/-- Sign-split packed polynomial: positive and negative digit strings in +radix `2^B`. Used only as a fast way to *compute* candidate coefficient +lists inside `decide`; nothing about it is trusted. -/ +structure KPoly where + pos : Nat + neg : Nat + +def kAdd (a b : KPoly) : KPoly := ⟨a.pos + b.pos, a.neg + b.neg⟩ + +def kMul (a b : KPoly) : KPoly := + ⟨a.pos * b.pos + a.neg * b.neg, a.pos * b.neg + a.neg * b.pos⟩ + +def kOfInt (c : Int) : KPoly := + ⟨c.toNat, (-c).toNat⟩ + +/-- Packed `x + a`. -/ +def kXA (B : Nat) (a : Int) : KPoly := + kAdd (kOfInt a) ⟨2 ^ B, 0⟩ + +/-- Packed Taylor shift by Horner: `p(x + a)` accumulated as packed +multiply-adds. -/ +def kShiftHorner (B : Nat) (a : Int) : List Int → KPoly + | [] => ⟨0, 0⟩ + | c :: cs => kAdd (kOfInt c) (kMul (kXA B a) (kShiftHorner B a cs)) + +/-- Signed digit extraction. -/ +def unpack (B : Nat) : Nat → KPoly → List Int + | 0, _ => [] + | len + 1, A => + (((A.pos &&& (2 ^ B - 1) : Nat) : Int) - ((A.neg &&& (2 ^ B - 1) : Nat) : Int)) :: + unpack B len ⟨A.pos >>> B, A.neg >>> B⟩ + +/-- Square ladder `x^(2^0), x^(2^1), …` of the given depth. -/ +def kSquares (x : KPoly) : Nat → List KPoly + | 0 => [x] + | d + 1 => + match kSquares x d with + | [] => [] + | s :: rest => kMul s s :: s :: rest + +/-- Power from a precomputed square ladder (most significant first). -/ +def kPowL : List KPoly → Nat → KPoly + | [], _ => ⟨1, 0⟩ + | s :: rest, n => + let h := kPowL rest (n % 2 ^ rest.length) + if n / 2 ^ rest.length % 2 = 1 then kMul h s else h + +/-- Divide-and-conquer packed Taylor shift: +`P(x+a) = P₀(x+a) + (x+a)^m · P₁(x+a)` with `m = ⌊n/2⌋`. The expensive +full-size multiplications happen only near the top of the recursion, so +the cost is a handful of full-size GMP products. -/ +def kShiftDC (B : Nat) (a : Int) (sq : List KPoly) : Nat → List Int → KPoly + | 0, p => kShiftHorner B a p + | fuel + 1, p => + if p.length ≤ 16 then kShiftHorner B a p + else + let m := p.length / 2 + kAdd (kShiftDC B a sq fuel (p.take m)) + (kMul (kPowL sq m) (kShiftDC B a sq fuel (p.drop m))) + +/-- The in-kernel shifted-witness candidate. -/ +def kShiftWitness (B : Nat) (C : List Int) (a : Int) : List Int := + unpack B C.length (kShiftDC B a (kSquares (kXA B a) 9) 16 C) + +/-! ## The witness-checked cell walk -/ + +/-- Certify `0 ≤ P(x)` on `[lo, hi]` by walking cells; each cell's +shifted polynomial is computed packed and certified by one evaluation +identity at `2^B` plus the ℓ1 bounds that make `evalPoly_ext` apply. -/ +def checkCoverK (B : Nat) (C : List Int) (lo hi : Int) : List Int → Bool + | [] => decide (hi < lo) + | w :: ws => + let S := kShiftWitness B C lo + decide (0 ≤ w) && + decide (polyL1 S * 2 < 2 ^ B) && + decide (aeval C (1 + lo.natAbs) * 2 < 2 ^ B) && + decide (evalPoly S (((2 ^ B : Nat) : Int)) = evalPoly C (lo + ((2 ^ B : Nat) : Int))) && + decide (0 ≤ (hornerIv S 0 w).1) && + checkCoverK B C (lo + w + 1) hi ws + +theorem checkCoverK_sound (B : Nat) (C : List Int) (ws : List Int) : + ∀ lo hi : Int, checkCoverK B C lo hi ws = true → + ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly C x := by + induction ws with + | nil => + intro lo hi h x h1 h2 + simp only [checkCoverK, decide_eq_true_eq] at h + omega + | cons w ws ih => + intro lo hi h x h1 h2 + simp only [checkCoverK, Bool.and_eq_true, decide_eq_true_eq] at h + obtain ⟨⟨⟨⟨hw, hS⟩, hC⟩, he⟩, hcell⟩ := h.1 + have hrest := h.2 + rcases Int.lt_or_le (lo + w) x with hout | hin + · exact ih (lo + w + 1) hi hrest x (by omega) h2 + · -- the witness agrees with the true shift everywhere + have hshift : polyL1 (polyShift C lo) * 2 < 2 ^ B := by + have := polyL1_polyShift C lo + omega + have hext := evalPoly_ext (B := B) (kShiftWitness B C lo) + (polyShift C lo) hS hshift + (by rw [polyShift_eval, pow2_cast]; exact he) + have hs := (hornerIv_sound (kShiftWitness B C lo) (lo := 0) (hi := w) + (x := x - lo) (Int.le_refl 0) (by omega) (by omega)).1 + have hx := hext (x - lo) + rw [polyShift_eval] at hx + rw [show lo + (x - lo) = x by omega] at hx + omega + +end Common.Poly diff --git a/formal/common/Common/Foundation/Poly.lean b/formal/common/Common/Foundation/Poly.lean new file mode 100644 index 000000000..721f2ab5c --- /dev/null +++ b/formal/common/Common/Foundation/Poly.lean @@ -0,0 +1,225 @@ +import Init + +/-! +# Polynomial positivity certificates + +Dense `Int` polynomials (coefficients low-order first), interval-Horner +evaluation over nonnegative domains, and a fuel-bounded adaptive bisection +checker whose `true` result soundly certifies `0 ≤ P(x)` for every integer +`x` in the queried range. The checker is executed by the kernel via `decide`, +so the analytic components of the monotonicity proof reduce to computation. +-/ + +namespace Common.Poly + +/-- Multiplication monotonicity helpers (Init-only, so spelled out). -/ +theorem mul_le_mul_left_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : + c * a ≤ c * b := by + have h1 : 0 ≤ c * (b - a) := Int.mul_nonneg hc (by omega) + rw [Int.mul_sub] at h1 + omega + +theorem mul_le_mul_right_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : + a * c ≤ b * c := by + have h1 : 0 ≤ (b - a) * c := Int.mul_nonneg (by omega) hc + rw [Int.sub_mul] at h1 + omega + +theorem mul_le_mul_left_nonpos {a b c : Int} (h : a ≤ b) (hc : c ≤ 0) : + c * b ≤ c * a := by + have h1 : 0 ≤ -c * (b - a) := Int.mul_nonneg (by omega) (by omega) + rw [Int.mul_sub, Int.neg_mul, Int.neg_mul] at h1 + omega + +def evalPoly : List Int → Int → Int + | [], _ => 0 + | c :: cs, x => c + x * evalPoly cs x + +/-- Interval Horner over a nonnegative domain `[lo, hi]`, `0 ≤ lo`. Returns +`(vlo, vhi)` with `vlo ≤ P(x) ≤ vhi` for all `x ∈ [lo, hi]`. -/ +def hornerIv : List Int → Int → Int → Int × Int + | [], _, _ => (0, 0) + | c :: cs, lo, hi => + let (plo, phi) := hornerIv cs lo hi + let mlo := if 0 ≤ plo then lo * plo else hi * plo + let mhi := if 0 ≤ phi then hi * phi else lo * phi + (c + mlo, c + mhi) + +theorem hornerIv_sound (cs : List Int) {lo hi x : Int} + (h0 : 0 ≤ lo) (h1 : lo ≤ x) (h2 : x ≤ hi) : + (hornerIv cs lo hi).1 ≤ evalPoly cs x ∧ evalPoly cs x ≤ (hornerIv cs lo hi).2 := by + induction cs with + | nil => simp [hornerIv, evalPoly] + | cons c cs ih => + obtain ⟨ihlo, ihhi⟩ := ih + simp only [hornerIv, evalPoly] + constructor + · -- lower bound + have hx : 0 ≤ x := by omega + split + · -- 0 ≤ plo : lo * plo ≤ x * plo ≤ x * P(x) + rename_i hplo + have s1 : lo * (hornerIv cs lo hi).1 ≤ x * (hornerIv cs lo hi).1 := + mul_le_mul_right_nonneg h1 hplo + have s2 : x * (hornerIv cs lo hi).1 ≤ x * evalPoly cs x := + mul_le_mul_left_nonneg ihlo hx + omega + · -- plo < 0 : hi * plo ≤ x * plo ≤ x * P(x) + rename_i hplo + have hplo' : (hornerIv cs lo hi).1 ≤ 0 := by omega + have s1 : hi * (hornerIv cs lo hi).1 ≤ x * (hornerIv cs lo hi).1 := by + have hcomm := mul_le_mul_left_nonpos h2 hplo' + rw [Int.mul_comm ((hornerIv cs lo hi).1) hi, + Int.mul_comm ((hornerIv cs lo hi).1) x] at hcomm + exact hcomm + have s2 : x * (hornerIv cs lo hi).1 ≤ x * evalPoly cs x := + mul_le_mul_left_nonneg ihlo hx + omega + · -- upper bound + have hx : 0 ≤ x := by omega + split + · -- 0 ≤ phi : x * P(x) ≤ x * phi ≤ hi * phi + rename_i hphi + have s2 : x * evalPoly cs x ≤ x * (hornerIv cs lo hi).2 := + mul_le_mul_left_nonneg ihhi hx + have s1 : x * (hornerIv cs lo hi).2 ≤ hi * (hornerIv cs lo hi).2 := + mul_le_mul_right_nonneg h2 hphi + omega + · -- phi < 0 : x * P(x) ≤ x * phi ≤ lo * phi + rename_i hphi + have hphi' : (hornerIv cs lo hi).2 ≤ 0 := by omega + have s2 : x * evalPoly cs x ≤ x * (hornerIv cs lo hi).2 := + mul_le_mul_left_nonneg ihhi hx + have s1 : x * (hornerIv cs lo hi).2 ≤ lo * (hornerIv cs lo hi).2 := by + have hcomm := mul_le_mul_left_nonpos h1 hphi' + rw [Int.mul_comm ((hornerIv cs lo hi).2) lo, + Int.mul_comm ((hornerIv cs lo hi).2) x] at hcomm + exact hcomm + omega + +/-- Adaptive bisection: certifies `0 ≤ P(x)` for every integer `x ∈ [lo, hi]`. -/ +def checkNonneg (cs : List Int) (lo hi : Int) : Nat → Bool + | 0 => false + | fuel + 1 => + if hi < lo then true + else if 0 ≤ (hornerIv cs lo hi).1 then true + else if lo = hi then false + else + let mid := (lo + hi) / 2 + checkNonneg cs lo mid fuel && checkNonneg cs (mid + 1) hi fuel + +theorem checkNonneg_sound (cs : List Int) (fuel : Nat) : + ∀ lo hi : Int, 0 ≤ lo → checkNonneg cs lo hi fuel = true → + ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly cs x := by + induction fuel with + | zero => intro lo hi _ h; simp [checkNonneg] at h + | succ fuel ih => + intro lo hi hlo h x hx1 hx2 + unfold checkNonneg at h + split at h + · omega + · split at h + · rename_i hiv + have := (hornerIv_sound cs hlo hx1 hx2).1 + omega + · split at h + · exact absurd h (by simp) + · rw [Bool.and_eq_true] at h + by_cases hm : x ≤ (lo + hi) / 2 + · exact ih lo ((lo + hi) / 2) hlo h.1 x hx1 hm + · exact ih ((lo + hi) / 2 + 1) hi (by omega) h.2 x (by omega) hx2 + +/-! ## Polynomial algebra (with evaluation lemmas) -/ + +def polyAdd : List Int → List Int → List Int + | [], q => q + | p, [] => p + | a :: p, b :: q => (a + b) :: polyAdd p q + +theorem evalPoly_polyAdd (p q : List Int) (x : Int) : + evalPoly (polyAdd p q) x = evalPoly p x + evalPoly q x := by + induction p generalizing q with + | nil => simp [polyAdd, evalPoly] + | cons a p ih => + cases q with + | nil => simp [polyAdd, evalPoly] + | cons b q => + simp only [polyAdd, evalPoly, ih] + rw [Int.mul_add] + omega + +def polyNeg (p : List Int) : List Int := p.map (-·) + +theorem evalPoly_polyNeg (p : List Int) (x : Int) : + evalPoly (polyNeg p) x = -evalPoly p x := by + induction p with + | nil => simp [polyNeg, evalPoly] + | cons a p ih => + simp only [polyNeg, List.map, evalPoly] at * + rw [ih] + rw [show x * -evalPoly p x = -(x * evalPoly p x) by rw [Int.mul_neg]] + omega + +def polySub (p q : List Int) : List Int := polyAdd p (polyNeg q) + +theorem evalPoly_polySub (p q : List Int) (x : Int) : + evalPoly (polySub p q) x = evalPoly p x - evalPoly q x := by + unfold polySub + rw [evalPoly_polyAdd, evalPoly_polyNeg] + omega + +def polyScale (a : Int) (p : List Int) : List Int := p.map (a * ·) + +theorem evalPoly_polyScale (a : Int) (p : List Int) (x : Int) : + evalPoly (polyScale a p) x = a * evalPoly p x := by + induction p with + | nil => simp [polyScale, evalPoly] + | cons c p ih => + simp only [polyScale, List.map, evalPoly] at * + rw [ih, Int.mul_add] + rw [show x * (a * evalPoly p x) = a * (x * evalPoly p x) by + rw [← Int.mul_assoc, Int.mul_comm x a, Int.mul_assoc]] + +theorem evalPoly_singleton (c x : Int) : evalPoly [c] x = c := by + simp [evalPoly] + +def polyMulX (p : List Int) : List Int := 0 :: p + +theorem evalPoly_polyMulX (p : List Int) (x : Int) : + evalPoly (polyMulX p) x = x * evalPoly p x := by + simp [polyMulX, evalPoly] + +def polyMul : List Int → List Int → List Int + | [], _ => [] + | a :: p, q => polyAdd (polyScale a q) (polyMulX (polyMul p q)) + +theorem evalPoly_polyMul (p q : List Int) (x : Int) : + evalPoly (polyMul p q) x = evalPoly p x * evalPoly q x := by + induction p with + | nil => simp [polyMul, evalPoly] + | cons a p ih => + simp only [polyMul, evalPoly] + rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyMulX, ih] + rw [Int.add_mul] + rw [show x * (evalPoly p x * evalPoly q x) = x * evalPoly p x * evalPoly q x by + rw [Int.mul_assoc]] + +/-- Composition with `x + 1`: `evalPoly (polyCompAdd1 p) x = evalPoly p (x + 1)`. -/ +def polyCompAdd1 : List Int → List Int + | [] => [] + | c :: cs => + let q := polyCompAdd1 cs + polyAdd [c] (polyAdd q (polyMulX q)) + +theorem evalPoly_polyCompAdd1 (p : List Int) (x : Int) : + evalPoly (polyCompAdd1 p) x = evalPoly p (x + 1) := by + induction p with + | nil => simp [polyCompAdd1, evalPoly] + | cons c cs ih => + simp only [polyCompAdd1, evalPoly] + rw [evalPoly_polyAdd, evalPoly_polyAdd, evalPoly_polyMulX, ih] + simp only [evalPoly] + rw [Int.add_mul, Int.one_mul] + omega + +end Common.Poly diff --git a/formal/common/Common/Foundation/ShiftCert.lean b/formal/common/Common/Foundation/ShiftCert.lean new file mode 100644 index 000000000..da69cd4d4 --- /dev/null +++ b/formal/common/Common/Foundation/ShiftCert.lean @@ -0,0 +1,422 @@ +import Common.Foundation.Poly +import Common.Foundation.ExpSum + +/-! +# Recentered polynomial nonnegativity certificates + +The floor-specification certificate polynomials have ~1e-28 relative slack: +plain interval Horner cannot see the cancellation between their huge +monomials, so bisection alone would need ~1e30 cells. Recentering a +polynomial at each cell's left endpoint (an exact integer Taylor shift) +exposes the cancellation symbolically; interval Horner over the shifted +cell `[0, w]` then converges with a few hundred cells. + +`checkCover` walks a caller-supplied list of cell widths and certifies +`0 ≤ P(x)` for every integer `x` in `[lo, hi]`. + +The file also provides the polynomial-level partial-sum numerator +(`expPolyNum`) and its evaluation lemma, connecting the certificate +polynomials to the `expNum` caps of `Common.Foundation.ExpSum`. +-/ + +namespace Common.Poly + +/-- Synthetic division by `(x - a)`: `P(x) = Q(x) (x - a) + r`. -/ +def synthDiv : List Int → Int → List Int × Int + | [], _ => ([], 0) + | [c], _ => ([], c) + | c :: cs, a => + ((synthDiv cs a).2 :: (synthDiv cs a).1, c + a * (synthDiv cs a).2) + +theorem synthDiv_eval (C : List Int) (a x : Int) : + evalPoly C x = evalPoly (synthDiv C a).1 x * (x - a) + (synthDiv C a).2 := by + match C with + | [] => simp [synthDiv, evalPoly] + | [c] => simp [synthDiv, evalPoly] + | c :: c2 :: cs => + have ih := synthDiv_eval (c2 :: cs) a x + show c + x * evalPoly (c2 :: cs) x = _ + rw [ih] + show _ = ((synthDiv (c2 :: cs) a).2 + + x * evalPoly ((synthDiv (c2 :: cs) a).1) x) * (x - a) + + (c + a * (synthDiv (c2 :: cs) a).2) + rw [Int.add_mul] + have e1 : x * (evalPoly (synthDiv (c2 :: cs) a).1 x * (x - a) + + (synthDiv (c2 :: cs) a).2) = + x * evalPoly (synthDiv (c2 :: cs) a).1 x * (x - a) + + x * (synthDiv (c2 :: cs) a).2 := by + rw [Int.mul_add, Int.mul_assoc] + have e2 : x * (synthDiv (c2 :: cs) a).2 = + (x - a) * (synthDiv (c2 :: cs) a).2 + a * (synthDiv (c2 :: cs) a).2 := by + rw [Int.sub_mul] + omega + have e3 : (x - a) * (synthDiv (c2 :: cs) a).2 = + (synthDiv (c2 :: cs) a).2 * (x - a) := Int.mul_comm _ _ + omega + +theorem synthDiv_length : ∀ (C : List Int) (a : Int), C ≠ [] → + (synthDiv C a).1.length + 1 = C.length := by + intro C a h + match C with + | [c] => rfl + | c :: c2 :: cs => + have ih := synthDiv_length (c2 :: cs) a (by simp) + show ((synthDiv (c2 :: cs) a).2 :: (synthDiv (c2 :: cs) a).1).length + 1 = _ + simp only [List.length_cons] at * + omega + +/-- Fuel-based Taylor shift (structural recursion, so the kernel computes +it inside `decide`). -/ +def polyShiftAux : Nat → List Int → Int → List Int + | 0, _, _ => [] + | _ + 1, [], _ => [] + | fuel + 1, c :: cs, a => + (synthDiv (c :: cs) a).2 :: polyShiftAux fuel (synthDiv (c :: cs) a).1 a + +/-- Exact Taylor shift: `evalPoly (polyShift C a) δ = evalPoly C (a + δ)`. -/ +def polyShift (C : List Int) (a : Int) : List Int := + polyShiftAux C.length C a + +theorem polyShiftAux_eval (fuel : Nat) : + ∀ (C : List Int) (a δ : Int), C.length ≤ fuel → + evalPoly (polyShiftAux fuel C a) δ = evalPoly C (a + δ) := by + induction fuel with + | zero => + intro C a δ h + have : C = [] := List.eq_nil_of_length_eq_zero (by omega) + subst this + rfl + | succ f ih => + intro C a δ h + match C with + | [] => rfl + | c :: cs => + show (synthDiv (c :: cs) a).2 + + δ * evalPoly (polyShiftAux f (synthDiv (c :: cs) a).1 a) δ = _ + have hlen : (synthDiv (c :: cs) a).1.length ≤ f := by + have := synthDiv_length (c :: cs) a (by simp) + simp only [List.length_cons] at * + omega + rw [ih _ a δ hlen, synthDiv_eval (c :: cs) a (a + δ)] + have e1 : evalPoly (synthDiv (c :: cs) a).1 (a + δ) * (a + δ - a) = + δ * evalPoly (synthDiv (c :: cs) a).1 (a + δ) := by + rw [show a + δ - a = δ by omega, Int.mul_comm] + omega + +theorem polyShift_eval (C : List Int) (a δ : Int) : + evalPoly (polyShift C a) δ = evalPoly C (a + δ) := + polyShiftAux_eval C.length C a δ (Nat.le_refl _) + +/-- Certify `0 ≤ P(x)` for every integer `x ∈ [lo, hi]` by walking cells of +the given widths, recentering at each cell's left endpoint. -/ +def checkCover (C : List Int) (lo hi : Int) : List Int → Bool + | [] => decide (hi < lo) + | w :: ws => + decide (0 ≤ w) && decide (0 ≤ (hornerIv (polyShift C lo) 0 w).1) && + checkCover C (lo + w + 1) hi ws + +theorem checkCover_sound (C : List Int) (ws : List Int) : + ∀ lo hi : Int, checkCover C lo hi ws = true → + ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly C x := by + induction ws with + | nil => + intro lo hi h x h1 h2 + simp only [checkCover, decide_eq_true_eq] at h + omega + | cons w ws ih => + intro lo hi h x h1 h2 + simp only [checkCover, Bool.and_eq_true, decide_eq_true_eq] at h + obtain ⟨⟨hw, hcell⟩, hrest⟩ := h + rcases Int.lt_or_le (lo + w) x with hout | hin + · exact ih (lo + w + 1) hi hrest x (by omega) h2 + · have hs := (hornerIv_sound (polyShift C lo) (lo := 0) (hi := w) + (x := x - lo) (Int.le_refl 0) (by omega) (by omega)).1 + rw [polyShift_eval] at hs + rw [show lo + (x - lo) = x by omega] at hs + omega + +/-! ## Partial-sum numerators at the polynomial level -/ + +/-- Int mirror of `Common.Exp.expNum`. -/ +def expNumI : Nat → Int → Int → Int + | 0, _, _ => 1 + | n + 1, p, q => (n + 1) * q * expNumI n p q + p ^ (n + 1) + +theorem expNumI_eq_expNum (k : Nat) (p q : Nat) : + expNumI k (p : Int) (q : Int) = (Common.Exp.expNum k p q : Int) := by + induction k with + | zero => rfl + | succ n ih => + show ((n : Int) + 1) * q * expNumI n p q + (p : Int) ^ (n + 1) = _ + rw [ih] + show _ = ((((n + 1) * q * Common.Exp.expNum n p q + p ^ (n + 1) : Nat)) : Int) + push_cast + omega + +def polyPow (P : List Int) : Nat → List Int + | 0 => [1] + | n + 1 => polyMul P (polyPow P n) + +theorem evalPoly_polyPow (P : List Int) (n : Nat) (x : Int) : + evalPoly (polyPow P n) x = evalPoly P x ^ n := by + induction n with + | zero => simp [polyPow, evalPoly] + | succ k ih => + show evalPoly (polyMul P (polyPow P k)) x = _ + rw [evalPoly_polyMul, ih] + rw [show evalPoly P x ^ (k + 1) = evalPoly P x ^ k * evalPoly P x from + Int.pow_succ _ _] + rw [Int.mul_comm] + +/-- Polynomial-level partial-sum numerator: evaluates to +`expNumI k (TN(x)) (TD(x))`. -/ +def expPolyNum (TN TD : List Int) : Nat → List Int + | 0 => [1] + | n + 1 => + polyAdd (polyScale ((n : Int) + 1) (polyMul TD (expPolyNum TN TD n))) + (polyPow TN (n + 1)) + +theorem evalPoly_expPolyNum (TN TD : List Int) (k : Nat) (x : Int) : + evalPoly (expPolyNum TN TD k) x = + expNumI k (evalPoly TN x) (evalPoly TD x) := by + induction k with + | zero => simp [expPolyNum, expNumI, evalPoly] + | succ n ih => + show evalPoly (polyAdd (polyScale ((n : Int) + 1) + (polyMul TD (expPolyNum TN TD n))) (polyPow TN (n + 1))) x = _ + rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyMul, ih, + evalPoly_polyPow] + show _ = ((n : Int) + 1) * evalPoly TD x * expNumI n (evalPoly TN x) + (evalPoly TD x) + evalPoly TN x ^ (n + 1) + rw [← Int.mul_assoc] + +/-! ## Crude range and difference bounds over a box + +`polyHi cs B` bounds `evalPoly cs t` from above for `t ∈ [0, B]`; +`polyAbs cs B` bounds its magnitude; `polyDiffHi cs B` bounds the divided +difference `(P(y) - P(x))/(y - x)` from above for `0 ≤ x ≤ y ≤ B`. A +negative `polyDiffHi` certificate proves the polynomial decreasing on the +whole box, which is how the bracket lemmas compare pipeline stage values +at integer points against the certificate polynomials' rational interval +ends. -/ + +def iabs (c : Int) : Int := if c < 0 then -c else c + +def polyHi : List Int → Int → Int + | [], _ => 0 + | c :: cs, B => c + B * max (polyHi cs B) 0 + +def polyDiffHi : List Int → Int → Int + | [], _ => 0 + | _ :: cs, B => polyHi cs B + max (B * polyDiffHi cs B) 0 + +theorem polyHi_bound (cs : List Int) (B : Int) : + ∀ t : Int, 0 ≤ t → t ≤ B → evalPoly cs t ≤ polyHi cs B := by + induction cs with + | nil => intro t _ _; exact Int.le_refl _ + | cons c cs ih => + intro t h0 hB + show c + t * evalPoly cs t ≤ c + B * max (polyHi cs B) 0 + have hT := ih t h0 hB + rcases Int.le_total (evalPoly cs t) 0 with hneg | hpos + · have h1 : t * evalPoly cs t ≤ 0 := Int.mul_nonpos_of_nonneg_of_nonpos h0 hneg + have h2 : 0 ≤ B * max (polyHi cs B) 0 := + Int.mul_nonneg (by omega) (by omega) + omega + · have h1 : t * evalPoly cs t ≤ B * evalPoly cs t := + mul_le_mul_right_nonneg hB hpos + have h2 : B * evalPoly cs t ≤ B * max (polyHi cs B) 0 := + mul_le_mul_left_nonneg (by omega) (by omega) + omega + +theorem polyDiffHi_bound (cs : List Int) (B : Int) : + ∀ x y : Int, 0 ≤ x → x ≤ y → y ≤ B → + evalPoly cs y - evalPoly cs x ≤ polyDiffHi cs B * (y - x) := by + induction cs with + | nil => + intro x y _ _ _ + show (0 : Int) - 0 ≤ 0 * (y - x) + omega + | cons c cs ih => + intro x y hx hxy hyB + show c + y * evalPoly cs y - (c + x * evalPoly cs x) ≤ + (polyHi cs B + max (B * polyDiffHi cs B) 0) * (y - x) + -- y T(y) - x T(x) = (y - x) T(y) + x (T(y) - T(x)) + have hsplit : y * evalPoly cs y - x * evalPoly cs x = + (y - x) * evalPoly cs y + x * (evalPoly cs y - evalPoly cs x) := by + rw [Int.sub_mul, Int.mul_sub] + omega + have h1 : (y - x) * evalPoly cs y ≤ (y - x) * polyHi cs B := + mul_le_mul_left_nonneg (polyHi_bound cs B y (by omega) hyB) (by omega) + have h2 : x * (evalPoly cs y - evalPoly cs x) ≤ max (B * polyDiffHi cs B) 0 * (y - x) := by + have hd := ih x y hx hxy hyB + rcases Int.le_total 0 (polyDiffHi cs B) with hD | hD + · have s1 : x * (evalPoly cs y - evalPoly cs x) ≤ x * (polyDiffHi cs B * (y - x)) := by + rcases Int.le_total (evalPoly cs y - evalPoly cs x) (polyDiffHi cs B * (y - x)) + with h | h + · exact mul_le_mul_left_nonneg h hx + · have : evalPoly cs y - evalPoly cs x = polyDiffHi cs B * (y - x) := by omega + rw [this] + exact Int.le_refl _ + have s2 : x * (polyDiffHi cs B * (y - x)) ≤ B * (polyDiffHi cs B * (y - x)) := + mul_le_mul_right_nonneg (by omega) + (Int.mul_nonneg hD (by omega)) + have e1 : B * (polyDiffHi cs B * (y - x)) = B * polyDiffHi cs B * (y - x) := by + rw [Int.mul_assoc] + have hmax : B * polyDiffHi cs B * (y - x) ≤ max (B * polyDiffHi cs B) 0 * (y - x) := + mul_le_mul_right_nonneg (by omega) (by omega) + omega + · -- divided difference is nonpositive: x * diff ≤ 0 + have hd0 : evalPoly cs y - evalPoly cs x ≤ 0 := by + have : polyDiffHi cs B * (y - x) ≤ 0 := + Int.mul_nonpos_of_nonpos_of_nonneg hD (by omega) + omega + have s1 : x * (evalPoly cs y - evalPoly cs x) ≤ 0 := + Int.mul_nonpos_of_nonneg_of_nonpos hx hd0 + have : 0 ≤ max (B * polyDiffHi cs B) 0 * (y - x) := + Int.mul_nonneg (by omega) (by omega) + omega + have e2 : (polyHi cs B + max (B * polyDiffHi cs B) 0) * (y - x) = + (y - x) * polyHi cs B + max (B * polyDiffHi cs B) 0 * (y - x) := by + rw [Int.add_mul, Int.mul_comm (polyHi cs B) (y - x)] + omega + +/-! ## Homogenized two-point evaluation -/ + +/-- `homPoly cs num den` is `Σ_j cs_j num^j den^(deg - j)` at the +polynomial level. -/ +def homPoly : List Int → List Int → List Int → List Int + | [], _, _ => [0] + | c :: cs, num, den => + polyAdd (polyScale c (polyPow den cs.length)) (polyMul num (homPoly cs num den)) + +/-- `homEvalI cs n d = Σ_j cs_j n^j d^(deg-j)`, Horner-style. -/ +def homEvalI : List Int → Int → Int → Int + | [], _, _ => 0 + | c :: cs, nv, dv => c * dv ^ cs.length + nv * homEvalI cs nv dv + +theorem evalPoly_homPoly (cs : List Int) (num den : List Int) (x : Int) : + evalPoly (homPoly cs num den) x = + homEvalI cs (evalPoly num x) (evalPoly den x) := by + induction cs with + | nil => + show (0 : Int) + x * 0 = 0 + omega + | cons c cs ih => + show evalPoly (polyAdd (polyScale c (polyPow den cs.length)) + (polyMul num (homPoly cs num den))) x = _ + rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyPow, evalPoly_polyMul, ih] + rfl + +/-- The trivial homogenization identity: at the pair `(u d, d)` the +homogenized value collapses to `d^deg · P(u)`. -/ +theorem homEvalI_collapse (u D : Int) : + ∀ (c : Int) (cs : List Int), + homEvalI (c :: cs) (u * D) D = D ^ cs.length * evalPoly (c :: cs) u := by + intro c cs + induction cs generalizing c with + | nil => + show c * D ^ 0 + u * D * 0 = D ^ 0 * (c + u * 0) + rw [Int.mul_zero, Int.mul_zero, Int.add_zero, Int.add_zero, Int.mul_comm] + | cons c2 cs ih => + show c * D ^ (c2 :: cs).length + u * D * homEvalI (c2 :: cs) (u * D) D = _ + rw [ih c2] + show c * D ^ (cs.length + 1) + u * D * (D ^ cs.length * evalPoly (c2 :: cs) u) = + D ^ (cs.length + 1) * (c + u * evalPoly (c2 :: cs) u) + have e1 : (D : Int) ^ (cs.length + 1) = D * D ^ cs.length := by + rw [Int.pow_succ, Int.mul_comm] + rw [e1, Int.mul_add] + have e2 : u * D * (D ^ cs.length * evalPoly (c2 :: cs) u) = + D * D ^ cs.length * (u * evalPoly (c2 :: cs) u) := by + simp only [Int.mul_assoc, Int.mul_left_comm] + have e3 : c * (D * D ^ cs.length) = D * D ^ cs.length * c := by + rw [Int.mul_comm] + omega + +/-! ## Sharing-friendly mirrors of the shift checker + +`synthDiv` names its recursive result three times, and the kernel +re-evaluates each occurrence during `decide`. The `M`-variants bind the +recursive result through a `match`, so the kernel computes it once per +step; `checkCoverM_sound` transfers soundness from the reference checker. +-/ + +def synthDivM : List Int → Int → List Int × Int + | [], _ => ([], 0) + | [c], _ => ([], c) + | c :: cs, a => + match synthDivM cs a with + | (q, r) => (r :: q, c + a * r) + +theorem synthDivM_eq : ∀ (C : List Int) (a : Int), synthDivM C a = synthDiv C a := by + intro C a + match C with + | [] => rfl + | [c] => rfl + | c :: c2 :: cs => + have ih := synthDivM_eq (c2 :: cs) a + show (match synthDivM (c2 :: cs) a with + | (q, r) => (r :: q, c + a * r)) = _ + rw [ih] + rcases h : synthDiv (c2 :: cs) a with ⟨q, r⟩ + show (r :: q, c + a * r) = ((synthDiv (c2 :: cs) a).2 :: (synthDiv (c2 :: cs) a).1, + c + a * (synthDiv (c2 :: cs) a).2) + rw [h] + +def polyShiftAuxM : Nat → List Int → Int → List Int + | 0, _, _ => [] + | _ + 1, [], _ => [] + | fuel + 1, c :: cs, a => + match synthDivM (c :: cs) a with + | (q, r) => r :: polyShiftAuxM fuel q a + +theorem polyShiftAuxM_eq : ∀ (fuel : Nat) (C : List Int) (a : Int), + polyShiftAuxM fuel C a = polyShiftAux fuel C a := by + intro fuel + induction fuel with + | zero => intro C a; rfl + | succ f ih => + intro C a + match C with + | [] => rfl + | c :: cs => + show (match synthDivM (c :: cs) a with + | (q, r) => r :: polyShiftAuxM f q a) = _ + rw [synthDivM_eq] + rcases h : synthDiv (c :: cs) a with ⟨q, r⟩ + show r :: polyShiftAuxM f q a = + (synthDiv (c :: cs) a).2 :: polyShiftAux f (synthDiv (c :: cs) a).1 a + rw [h, ih] + +def polyShiftM (C : List Int) (a : Int) : List Int := + polyShiftAuxM C.length C a + +theorem polyShiftM_eq (C : List Int) (a : Int) : polyShiftM C a = polyShift C a := + polyShiftAuxM_eq C.length C a + +def checkCoverM (C : List Int) (lo hi : Int) : List Int → Bool + | [] => decide (hi < lo) + | w :: ws => + decide (0 ≤ w) && decide (0 ≤ (hornerIv (polyShiftM C lo) 0 w).1) && + checkCoverM C (lo + w + 1) hi ws + +theorem checkCoverM_eq (C : List Int) : ∀ (ws : List Int) (lo hi : Int), + checkCoverM C lo hi ws = checkCover C lo hi ws := by + intro ws + induction ws with + | nil => intro lo hi; rfl + | cons w ws ih => + intro lo hi + show (decide (0 ≤ w) && decide (0 ≤ (hornerIv (polyShiftM C lo) 0 w).1) && + checkCoverM C (lo + w + 1) hi ws) = _ + rw [polyShiftM_eq, ih] + rfl + +theorem checkCoverM_sound (C : List Int) (ws : List Int) (lo hi : Int) + (h : checkCoverM C lo hi ws = true) : + ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly C x := by + refine checkCover_sound C ws lo hi ?_ + rw [← checkCoverM_eq] + exact h + +end Common.Poly diff --git a/formal/common/Common/Seam/RealExpBridge.lean b/formal/common/Common/Seam/RealExpBridge.lean new file mode 100644 index 000000000..8f2b8720a --- /dev/null +++ b/formal/common/Common/Seam/RealExpBridge.lean @@ -0,0 +1,148 @@ +import Mathlib.Analysis.SpecialFunctions.Log.Basic +import Mathlib.Analysis.SpecialFunctions.Exponential +import Common.Foundation.ExpSum + +open scoped BigOperators + +/-! +# Real-exponential bridge for the partial-sum caps + +`capUB`/`capLB` are integer-scaled bounds on the truncated Taylor sums of +`e^(p/q)`. This module connects them to `Real.exp`: the partial sums of +`exp` agree with `expNum`, so an upper cap bounds `Real.exp` from above and a +lower cap bounds it from below. These bridges are function-agnostic — they +only use the `Common.Exp` partial-sum interface and Mathlib's `Real.exp`. +-/ + +namespace Common.RealExpBridge + +open Common.Exp + +noncomputable section + +lemma fact_eq_factorial (n : Nat) : fact n = Nat.factorial n := by + induction n with + | zero => rfl + | succ k ih => simp [fact, Nat.factorial_succ, ih] + +lemma tsum_nat_cast_sum_range (n : Nat) (f : Nat → Nat) : + ((Common.Exp.tsum n f : Nat) : Real) = ∑ j ∈ Finset.range (n + 1), (f j : Real) := by + induction n with + | zero => simp [Common.Exp.tsum] + | succ k ih => + simp [Common.Exp.tsum, ih, Finset.sum_range_succ, Nat.cast_add] + +lemma expNum_div_eq_sum_range (n p q : Nat) (hq : 0 < q) : + (expNum n p q : Real) / ((fact n * q ^ n : Nat) : Real) = + ∑ j ∈ Finset.range (n + 1), ((p : Real) / q) ^ j / ((fact j : Nat) : Real) := by + rw [expNum_eq_tsum] + rw [show ((Common.Exp.tsum n (fun j => ffacAux j (n - j) * p ^ j * q ^ (n - j)) : Nat) : Real) = + ∑ j ∈ Finset.range (n + 1), ((ffacAux j (n - j) * p ^ j * q ^ (n - j) : Nat) : Real) from + tsum_nat_cast_sum_range n (fun j => ffacAux j (n - j) * p ^ j * q ^ (n - j))] + rw [div_eq_mul_inv, Finset.sum_mul] + apply Finset.sum_congr rfl + intro j hj + have hjle : j ≤ n := Nat.lt_succ.mp (Finset.mem_range.mp hj) + have hqn : (q : Real) ≠ 0 := by exact_mod_cast ne_of_gt hq + have hfactj : ((fact j : Nat) : Real) ≠ 0 := by + exact_mod_cast ne_of_gt (fact_pos j) + have hfactn : ((fact n : Nat) : Real) ≠ 0 := by + exact_mod_cast ne_of_gt (fact_pos n) + have hden : (((fact n * q ^ n : Nat) : Real)) ≠ 0 := by + exact_mod_cast ne_of_gt (Nat.mul_pos (fact_pos n) (Nat.pow_pos hq)) + have hff : (ffacAux j (n - j) * fact j : Nat) = fact n := by + rw [ffacAux_mul_fact] + congr 1 + omega + have hffR : ((ffacAux j (n - j) : Nat) : Real) * ((fact j : Nat) : Real) = ((fact n : Nat) : Real) := by + norm_num [← Nat.cast_mul, hff] + have hpow : (q : Real) ^ n = (q : Real) ^ j * (q : Real) ^ (n - j) := by + rw [← pow_add] + congr 1 + omega + norm_num [Nat.cast_mul, Nat.cast_pow] + field_simp [hden, hfactj, hfactn, hqn] + rw [hpow] + ring_nf + rw [← hffR] + ring + +lemma exp_hasSum (t : Real) : HasSum (fun n : Nat => t ^ n / ((fact n : Nat) : Real)) (Real.exp t) := by + have h := NormedSpace.expSeries_div_hasSum_exp (𝕂 := Real) (𝔸 := Real) t + simpa [fact_eq_factorial, Real.exp_eq_exp_ℝ] using h + +lemma expTerm_nonneg {p q : Nat} (hq : 0 < q) (i : Nat) : + 0 ≤ ((p : Real) / q) ^ i / ((fact i : Nat) : Real) := by + have hpq : 0 ≤ (p : Real) / q := by positivity + have hf : 0 ≤ ((fact i : Nat) : Real) := by positivity + exact div_nonneg (pow_nonneg hpq i) hf + +lemma div_le_of_cross_mul_le {a b c d : Real} (hc : 0 < c) (hd : 0 < d) + (h : a * d ≤ b * c) : a / c ≤ b / d := by + by_contra hnot + have hlt : b / d < a / c := lt_of_not_ge hnot + have hlt1 := mul_lt_mul_of_pos_right hlt hc + have hlt2 := mul_lt_mul_of_pos_right hlt1 hd + field_simp [hc.ne', hd.ne'] at hlt2 + nlinarith + +lemma capUB_bound_real {p q y w : Nat} (hq : 0 < q) (hw : 0 < w) + (n : Nat) (h : capUB p q y w) : + (expNum n p q : Real) / ((fact n * q ^ n : Nat) : Real) ≤ (y : Real) / w := by + have hnat := h n + have hreal : (expNum n p q : Real) * (w : Real) ≤ + (y : Real) * ((fact n * q ^ n : Nat) : Real) := by + exact_mod_cast hnat + have hdenpos : 0 < ((fact n * q ^ n : Nat) : Real) := by + exact_mod_cast Nat.mul_pos (fact_pos n) (Nat.pow_pos hq) + have hwpos : 0 < (w : Real) := by exact_mod_cast hw + exact div_le_of_cross_mul_le hdenpos hwpos hreal + +lemma capLB_bound_real {p q y w : Nat} (hq : 0 < q) (hw : 0 < w) + {n : Nat} (h : y * (fact n * q ^ n) ≤ expNum n p q * w) : + (y : Real) / w ≤ (expNum n p q : Real) / ((fact n * q ^ n : Nat) : Real) := by + have hreal : (y : Real) * ((fact n * q ^ n : Nat) : Real) ≤ + (expNum n p q : Real) * (w : Real) := by + exact_mod_cast h + have hdenpos : 0 < ((fact n * q ^ n : Nat) : Real) := by + exact_mod_cast Nat.mul_pos (fact_pos n) (Nat.pow_pos hq) + have hwpos : 0 < (w : Real) := by exact_mod_cast hw + exact div_le_of_cross_mul_le hwpos hdenpos hreal + +lemma exp_le_of_capUB {p q y w : Nat} (hq : 0 < q) (hw : 0 < w) + (h : capUB p q y w) : Real.exp ((p : Real) / q) ≤ (y : Real) / w := by + have hs := exp_hasSum ((p : Real) / q) + rw [← hs.tsum_eq] + refine Summable.tsum_le_of_sum_le hs.summable ?_ + intro s + by_cases hsempty : s.Nonempty + · let N := s.max' hsempty + have hsub : s ⊆ Finset.range (N + 1) := by + intro i hi + exact Finset.mem_range.mpr (Nat.lt_succ.mpr (Finset.le_max' s i hi)) + calc ∑ i ∈ s, ((p : Real) / q) ^ i / ((fact i : Nat) : Real) + ≤ ∑ i ∈ Finset.range (N + 1), ((p : Real) / q) ^ i / ((fact i : Nat) : Real) := by + exact Finset.sum_le_sum_of_subset_of_nonneg hsub (fun i hi his => expTerm_nonneg hq i) + _ = (expNum N p q : Real) / ((fact N * q ^ N : Nat) : Real) := by + rw [expNum_div_eq_sum_range N p q hq] + _ ≤ (y : Real) / w := capUB_bound_real hq hw N h + · have hs0 : s = ∅ := Finset.not_nonempty_iff_eq_empty.mp hsempty + rw [hs0] + simp only [Finset.sum_empty] + exact div_nonneg (Nat.cast_nonneg _) (by positivity) + +lemma le_exp_of_capLB {p q y w : Nat} (hq : 0 < q) (hw : 0 < w) + (h : capLB p q y w) : (y : Real) / w ≤ Real.exp ((p : Real) / q) := by + obtain ⟨n, hn⟩ := h + have hs := exp_hasSum ((p : Real) / q) + rw [← hs.tsum_eq] + calc (y : Real) / w + ≤ (expNum n p q : Real) / ((fact n * q ^ n : Nat) : Real) := capLB_bound_real hq hw hn + _ = ∑ i ∈ Finset.range (n + 1), ((p : Real) / q) ^ i / ((fact i : Nat) : Real) := by + rw [expNum_div_eq_sum_range n p q hq] + _ ≤ ∑' i : Nat, ((p : Real) / q) ^ i / ((fact i : Nat) : Real) := by + exact Summable.sum_le_tsum _ (fun i hi => expTerm_nonneg hq i) hs.summable + +end + +end Common.RealExpBridge diff --git a/formal/common/lake-manifest.json b/formal/common/lake-manifest.json new file mode 100644 index 000000000..14b5add11 --- /dev/null +++ b/formal/common/lake-manifest.json @@ -0,0 +1,109 @@ +{"version": "1.1.0", + "packagesDir": "../yul/.lake/packages", + "packages": + [{"type": "path", + "scope": "", + "name": "FormalYul", + "manifestFile": "lake-manifest.json", + "inherited": false, + "dir": "../yul", + "configFile": "lakefile.toml"}, + {"type": "path", + "scope": "", + "name": "evmyul", + "manifestFile": "lake-manifest.json", + "inherited": true, + "dir": "../yul/../../lib/EVMYulLean", + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/mathlib4.git", + "type": "git", + "subDir": null, + "scope": "", + "rev": "79e94a093aff4a60fb1b1f92d9681e407124c2ca", + "name": "mathlib", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/plausible", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "b100ad4c5d74a464f497aaa8e7c74d86bf39a56f", + "name": "plausible", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/LeanSearchClient", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "99657ad92e23804e279f77ea6dbdeebaa1317b98", + "name": "LeanSearchClient", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/import-graph", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "eb164a46de87078f27640ee71e6c3841defc2484", + "name": "importGraph", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/ProofWidgets4", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "1253a071e6939b0faf5c09d2b30b0bfc79dae407", + "name": "proofwidgets", + "manifestFile": "lake-manifest.json", + "inputRev": "v0.0.68", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/aesop", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "1256a18522728c2eeed6109b02dd2b8f207a2a3c", + "name": "aesop", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/quote4", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "917bfa5064b812b7fbd7112d018ea0b4def25ab3", + "name": "Qq", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/batteries", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "240676e9568c254a69be94801889d4b13f3b249f", + "name": "batteries", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover/lean4-cli", + "type": "git", + "subDir": null, + "scope": "leanprover", + "rev": "c682c91d2d4dd59a7187e2ab977ac25bd1f87329", + "name": "Cli", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.toml"}], + "name": "Common", + "lakeDir": ".lake"} diff --git a/formal/common/lakefile.toml b/formal/common/lakefile.toml new file mode 100644 index 000000000..471f19c44 --- /dev/null +++ b/formal/common/lakefile.toml @@ -0,0 +1,11 @@ +name = "Common" +version = "0.1.0" +defaultTargets = ["Common"] +packagesDir = "../yul/.lake/packages" + +[[lean_lib]] +name = "Common" + +[[require]] +name = "FormalYul" +path = "../yul" diff --git a/formal/common/lean-toolchain b/formal/common/lean-toolchain new file mode 100644 index 000000000..6ac6d4c4c --- /dev/null +++ b/formal/common/lean-toolchain @@ -0,0 +1 @@ +leanprover/lean4:v4.22.0 From 725153c06174535f4d89cfb6e0e40613f8399c08 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 11:24:10 +0200 Subject: [PATCH 042/149] Repoint `LnProof` at the shared `Common` package Remove the function-agnostic Foundation modules (`Poly`, `ExpSum`, `ShiftCert`, `Kronecker`, `KroneckerShift`) from `LnProof` and consume them from `Common` instead: require `Common` in the lakefile/manifest, repoint every `import`/`open`/qualified reference (`LnPoly` -> `Common.Poly`, `LnExp` -> `Common.Exp`), and re-point the generators (`GenCover`, `GenErr1`, `GenErrLit`) and their emitted certificate imports. `Seam/RealLog` now imports the generic `Real.exp` bridges from `Common.Seam.RealExpBridge`; only the `lnWad`-specific WadRay/log closure remains local. Two `Floor/Bracket` reassociation steps that relied on `simp`'s permutative term ordering (sensitive to the renamed `evalPoly` declaration name) are made deterministic with `Int.mul_left_comm`. The proof builds green and the `Theorems` axiom gate still pins every public runtime theorem to `[propext, Classical.choice, Quot.sound]`. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/ln/LnProof/GenCover.lean | 6 +- formal/ln/LnProof/GenErr1.lean | 4 +- formal/ln/LnProof/GenErrLit.lean | 10 +- formal/ln/LnProof/LnProof/Error/Bound.lean | 2 +- formal/ln/LnProof/LnProof/Error/Cert.lean | 2 +- .../ln/LnProof/LnProof/Error/Core/Args.lean | 2 +- .../LnProof/LnProof/Error/Core/Assembly.lean | 2 +- .../ln/LnProof/LnProof/Error/Core/Bounds.lean | 2 +- .../LnProof/LnProof/Error/Core/BranchBn.lean | 2 +- .../LnProof/Error/Core/BranchCert.lean | 2 +- .../LnProof/LnProof/Error/Core/BranchNeg.lean | 2 +- .../LnProof/LnProof/Error/Core/BranchPos.lean | 2 +- .../ln/LnProof/LnProof/Error/Core/Budget.lean | 2 +- .../ln/LnProof/LnProof/Error/Core/C160.lean | 2 +- .../LnProof/LnProof/Error/Core/CutDefs.lean | 2 +- .../ln/LnProof/LnProof/Error/Core/Direct.lean | 2 +- .../LnProof/LnProof/Error/Core/ExpMargin.lean | 2 +- .../LnProof/Error/Core/PhaseCover.lean | 2 +- .../LnProof/LnProof/Error/Core/PhaseGe.lean | 2 +- .../LnProof/LnProof/Error/Core/PhaseLt.lean | 2 +- .../LnProof/LnProof/Error/Core/Residue.lean | 2 +- .../LnProof/Error/Core/ResidueCover.lean | 2 +- .../ln/LnProof/LnProof/Error/FactoredCap.lean | 2 +- formal/ln/LnProof/LnProof/Error/GeBridge.lean | 2 +- formal/ln/LnProof/LnProof/Error/LtBridge.lean | 12 +- .../LnProof/LnProof/Error/LtFactoredCap.lean | 2 +- formal/ln/LnProof/LnProof/Floor/Assembly.lean | 2 +- formal/ln/LnProof/LnProof/Floor/Bracket.lean | 10 +- formal/ln/LnProof/LnProof/Floor/Budget.lean | 6 +- formal/ln/LnProof/LnProof/Floor/Caps.lean | 2 +- formal/ln/LnProof/LnProof/Floor/CertAux.lean | 2 +- formal/ln/LnProof/LnProof/Floor/CertDefs.lean | 4 +- formal/ln/LnProof/LnProof/Floor/CertGeLo.lean | 8 +- formal/ln/LnProof/LnProof/Floor/CertGeUp.lean | 12 +- formal/ln/LnProof/LnProof/Floor/CertLtLo.lean | 14 +- formal/ln/LnProof/LnProof/Floor/CertLtUp.lean | 10 +- formal/ln/LnProof/LnProof/Floor/Consts.lean | 4 +- formal/ln/LnProof/LnProof/Floor/CutEquiv.lean | 2 +- formal/ln/LnProof/LnProof/Floor/Model.lean | 2 +- formal/ln/LnProof/LnProof/Floor/Spec.lean | 2 +- formal/ln/LnProof/LnProof/Floor/Window.lean | 2 +- formal/ln/LnProof/LnProof/Foundation.lean | 20 +- .../ln/LnProof/LnProof/Foundation/ExpSum.lean | 857 ------------------ .../LnProof/LnProof/Foundation/Kronecker.lean | 272 ------ .../LnProof/Foundation/KroneckerShift.lean | 288 ------ .../ln/LnProof/LnProof/Foundation/Poly.lean | 225 ----- .../LnProof/LnProof/Foundation/ShiftCert.lean | 422 --------- formal/ln/LnProof/LnProof/Model/Body.lean | 4 +- formal/ln/LnProof/LnProof/Mono/Certs.lean | 4 +- formal/ln/LnProof/LnProof/Mono/Octave.lean | 2 +- formal/ln/LnProof/LnProof/Mono/Step.lean | 2 +- formal/ln/LnProof/LnProof/Mono/ZOctave.lean | 2 +- formal/ln/LnProof/LnProof/Seam/RealLog.lean | 127 +-- formal/ln/LnProof/LnProof/Spec/Cut.lean | 4 +- formal/ln/LnProof/lake-manifest.json | 250 +++-- formal/ln/LnProof/lakefile.toml | 4 + 56 files changed, 220 insertions(+), 2421 deletions(-) delete mode 100644 formal/ln/LnProof/LnProof/Foundation/ExpSum.lean delete mode 100644 formal/ln/LnProof/LnProof/Foundation/Kronecker.lean delete mode 100644 formal/ln/LnProof/LnProof/Foundation/KroneckerShift.lean delete mode 100644 formal/ln/LnProof/LnProof/Foundation/Poly.lean delete mode 100644 formal/ln/LnProof/LnProof/Foundation/ShiftCert.lean diff --git a/formal/ln/LnProof/GenCover.lean b/formal/ln/LnProof/GenCover.lean index 7d3514107..df9b9b2d5 100644 --- a/formal/ln/LnProof/GenCover.lean +++ b/formal/ln/LnProof/GenCover.lean @@ -1,5 +1,5 @@ import LnProof.Cert.FloorCertLit -import LnProof.Foundation.KroneckerShift +import Common.Foundation.KroneckerShift /-! # Cover generator @@ -14,7 +14,7 @@ module. Run with `lake env lean GenCover.lean` (after `lake build LnProof.Cert.FloorCertLit`). -/ -open LnPoly LnFloorCert +open Common.Poly LnFloorCert namespace GenCover @@ -57,7 +57,7 @@ def emit (nm litName symName evalEqName modPrefix cellPrefix nonnegName : String let (a, w) := aw let nn := pad2 i let body := - s!"import LnProof.Cert.FloorCertLit\nimport LnProof.Foundation.KroneckerShift\n\nnamespace LnFloorCert\nopen LnPoly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{nn} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend LnFloorCert\n" + s!"import LnProof.Cert.FloorCertLit\nimport Common.Foundation.KroneckerShift\n\nnamespace LnFloorCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{nn} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend LnFloorCert\n" IO.FS.writeFile s!"LnProof/Cert/{modPrefix}{nn}.lean" body -- ladder + imports let mut imps := "" diff --git a/formal/ln/LnProof/GenErr1.lean b/formal/ln/LnProof/GenErr1.lean index c4a66e196..ac6e89ad7 100644 --- a/formal/ln/LnProof/GenErr1.lean +++ b/formal/ln/LnProof/GenErr1.lean @@ -6,10 +6,10 @@ cap on `e^(BIASc·2²⁷/QS)` used by `capBLtight` and the error weights. Comput from the model inputs (BIASc), so it tracks any bias change. Run with `lake env lean GenErr1.lean` (after `lake build LnProof.Floor.Consts`). -/ -open LnExp LnFloor LnYul +open Common.Exp LnFloor LnYul #eval do - let bcap := (LnExp.expNum 130 (BIASc * 2 ^ 27) QS * (10 ^ 18 * 10 ^ 42)) / (LnExp.fact 130 * QS ^ 130) + let bcap := (Common.Exp.expNum 130 (BIASc * 2 ^ 27) QS * (10 ^ 18 * 10 ^ 42)) / (Common.Exp.fact 130 * QS ^ 130) IO.FS.writeFile "LnProof/Cert/BiasCapNum.lean" s!"/-! Generated by GenErr1 (lake env lean GenErr1.lean): the tight bias-cap\nnumerator BIASCAPNUM, the sharp lower cap on e^(BIASc·2^27/QS) used by\ncapBLtight and the error weights. -/\nnamespace LnFloorCert\n\ndef biasCapNum : Nat := {bcap}\n\nend LnFloorCert\n" IO.println s!"BiasCapNum written: {bcap}" diff --git a/formal/ln/LnProof/GenErrLit.lean b/formal/ln/LnProof/GenErrLit.lean index c400dac19..930d08c57 100644 --- a/formal/ln/LnProof/GenErrLit.lean +++ b/formal/ln/LnProof/GenErrLit.lean @@ -1,5 +1,5 @@ import LnProof.Error.Core -import LnProof.Foundation.KroneckerShift +import Common.Foundation.KroneckerShift /-! Generate the error-bound cert literals (ErrCertLtLit / ErrCertGeLit) and their covers for the current BIASc and `lnErrorBoundNum`. Computes @@ -8,14 +8,14 @@ inline (mirroring the ErrCert*Bridge constructions) so it does not depend on the bridges building, then walks the `checkCoverK` covers (literal signature, as the checked `errLt_nonneg`/`errGe_nonneg` theorems use). -/ -open LnPoly LnFloorCert LnExp LnFloor LnYul +open Common.Poly LnFloorCert Common.Exp LnFloor LnYul namespace GenErrLit -- All derived from the model inputs (BIASc in the model and `lnErrorBoundNum` -- in ErrorBoundCert), so generation tracks changes to those. def biasCapNum : Nat := - (LnExp.expNum 130 (BIASc * 2 ^ 27) QS * (10 ^ 18 * 10 ^ 42)) / (LnExp.fact 130 * QS ^ 130) + (Common.Exp.expNum 130 (BIASc * 2 ^ 27) QS * (10 ^ 18 * 10 ^ 42)) / (Common.Exp.fact 130 * QS ^ 130) def errLtK : Int := (10 ^ 31 * (10 ^ 18 * 10 ^ 42) * lnErrQ * (10 ^ 40 + 160) : Nat) def errGeK : Int := errLtK def errLtW : Nat := biasCapNum * (lnErrQ + minPosAvail) * wadRayStrictDen * 10 ^ 40 @@ -68,11 +68,11 @@ def emit (litFile litName coverMod modPrefix cellPrefix nonnegName : String) (C for (aw, i) in cells.zipIdx do let (a, w) := aw IO.FS.writeFile s!"LnProof/Cert/{modPrefix}{pad2 i}.lean" - s!"import LnProof.Cert.{litFile}\nimport LnProof.Foundation.KroneckerShift\n\nnamespace LnFloorCert\nopen LnPoly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{pad2 i} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend LnFloorCert\n" + s!"import LnProof.Cert.{litFile}\nimport Common.Foundation.KroneckerShift\n\nnamespace LnFloorCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{pad2 i} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend LnFloorCert\n" let lb := "{"; let rb := "}" let mut s := "" for (_, i) in cells.zipIdx do s := s ++ s!"import LnProof.Cert.{modPrefix}{pad2 i}\n" - s := s ++ s!"\nnamespace LnFloorCert\nopen LnPoly\n\nset_option maxRecDepth 100000\n\n" + s := s ++ s!"\nnamespace LnFloorCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\n" s := s ++ s!"theorem {nonnegName} {lb}m : Int{rb} (h1 : {lo} ≤ m) (h2 : m ≤ {hi}) :\n 0 ≤ evalPoly {litName} m := by\n" let n := cells.length for (aw, i) in cells.zipIdx do diff --git a/formal/ln/LnProof/LnProof/Error/Bound.lean b/formal/ln/LnProof/LnProof/Error/Bound.lean index b807c4988..c6f901082 100644 --- a/formal/ln/LnProof/LnProof/Error/Bound.lean +++ b/formal/ln/LnProof/LnProof/Error/Bound.lean @@ -21,7 +21,7 @@ from the floor bracket `1 ≤ posResidueGap` (`posResidueGap_bounds`). namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Cert.lean b/formal/ln/LnProof/LnProof/Error/Cert.lean index 95cd9af05..4f6494274 100644 --- a/formal/ln/LnProof/LnProof/Error/Cert.lean +++ b/formal/ln/LnProof/LnProof/Error/Cert.lean @@ -5,7 +5,7 @@ bound; the theorems below are checked by Lean's kernel. -/ namespace LnFloorCert -open LnExp LnFloor LnYul +open Common.Exp LnFloor LnYul def lnErrorBoundNum : Nat := 1698600000 def lnErrorBoundDen : Nat := 1000000000 diff --git a/formal/ln/LnProof/LnProof/Error/Core/Args.lean b/formal/ln/LnProof/LnProof/Error/Core/Args.lean index d73f27ac2..dce9eaae5 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/Args.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/Args.lean @@ -15,7 +15,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/Assembly.lean b/formal/ln/LnProof/LnProof/Error/Core/Assembly.lean index 4b2c91257..bb40efa72 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/Assembly.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/Assembly.lean @@ -25,7 +25,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/Bounds.lean b/formal/ln/LnProof/LnProof/Error/Core/Bounds.lean index d48de4d4d..ece4e125b 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/Bounds.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/Bounds.lean @@ -21,7 +21,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/BranchBn.lean b/formal/ln/LnProof/LnProof/Error/Core/BranchBn.lean index 018685dcd..426be3626 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/BranchBn.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/BranchBn.lean @@ -16,7 +16,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/BranchCert.lean b/formal/ln/LnProof/LnProof/Error/Core/BranchCert.lean index d3c3d968f..c0e8d18c5 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/BranchCert.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/BranchCert.lean @@ -22,7 +22,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/BranchNeg.lean b/formal/ln/LnProof/LnProof/Error/Core/BranchNeg.lean index 663c2ab3c..0a8d05fe9 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/BranchNeg.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/BranchNeg.lean @@ -17,7 +17,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/BranchPos.lean b/formal/ln/LnProof/LnProof/Error/Core/BranchPos.lean index 268a4bbda..61a3ba905 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/BranchPos.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/BranchPos.lean @@ -19,7 +19,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/Budget.lean b/formal/ln/LnProof/LnProof/Error/Core/Budget.lean index 2e62b75e2..4df1bdd7a 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/Budget.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/Budget.lean @@ -15,7 +15,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/C160.lean b/formal/ln/LnProof/LnProof/Error/Core/C160.lean index e0de44382..de6da4d65 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/C160.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/C160.lean @@ -16,7 +16,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/CutDefs.lean b/formal/ln/LnProof/LnProof/Error/Core/CutDefs.lean index 5c135c31f..d6b3d13c3 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/CutDefs.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/CutDefs.lean @@ -14,7 +14,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/Direct.lean b/formal/ln/LnProof/LnProof/Error/Core/Direct.lean index f9e2048fb..75f5538b5 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/Direct.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/Direct.lean @@ -18,7 +18,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/ExpMargin.lean b/formal/ln/LnProof/LnProof/Error/Core/ExpMargin.lean index bc10fcb79..d2510e210 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/ExpMargin.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/ExpMargin.lean @@ -15,7 +15,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/PhaseCover.lean b/formal/ln/LnProof/LnProof/Error/Core/PhaseCover.lean index 5f6f4f727..c27f6fcc0 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/PhaseCover.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/PhaseCover.lean @@ -19,7 +19,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/PhaseGe.lean b/formal/ln/LnProof/LnProof/Error/Core/PhaseGe.lean index 5500e724e..322068b29 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/PhaseGe.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/PhaseGe.lean @@ -17,7 +17,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/PhaseLt.lean b/formal/ln/LnProof/LnProof/Error/Core/PhaseLt.lean index 5b1a2bc54..5573c2689 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/PhaseLt.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/PhaseLt.lean @@ -20,7 +20,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/Residue.lean b/formal/ln/LnProof/LnProof/Error/Core/Residue.lean index f7df76612..3249c2c00 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/Residue.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/Residue.lean @@ -15,7 +15,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/Core/ResidueCover.lean b/formal/ln/LnProof/LnProof/Error/Core/ResidueCover.lean index dd535fa0a..4db2dbbf1 100644 --- a/formal/ln/LnProof/LnProof/Error/Core/ResidueCover.lean +++ b/formal/ln/LnProof/LnProof/Error/Core/ResidueCover.lean @@ -16,7 +16,7 @@ set_option maxRecDepth 100000 namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly attribute [local irreducible] lnWadToRayBody diff --git a/formal/ln/LnProof/LnProof/Error/FactoredCap.lean b/formal/ln/LnProof/LnProof/Error/FactoredCap.lean index 55a5ea2de..611bc810b 100644 --- a/formal/ln/LnProof/LnProof/Error/FactoredCap.lean +++ b/formal/ln/LnProof/LnProof/Error/FactoredCap.lean @@ -26,7 +26,7 @@ so any sharper `capLB` for the x1 part drops straight in. namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly set_option maxRecDepth 100000 diff --git a/formal/ln/LnProof/LnProof/Error/GeBridge.lean b/formal/ln/LnProof/LnProof/Error/GeBridge.lean index b32b9f1b7..639d1be97 100644 --- a/formal/ln/LnProof/LnProof/Error/GeBridge.lean +++ b/formal/ln/LnProof/LnProof/Error/GeBridge.lean @@ -20,7 +20,7 @@ The constants are the octave-extracted cell parameters at namespace LnFloorCert -open LnYul LnPoly LnExp +open LnYul Common.Poly Common.Exp set_option maxRecDepth 100000 diff --git a/formal/ln/LnProof/LnProof/Error/LtBridge.lean b/formal/ln/LnProof/LnProof/Error/LtBridge.lean index a7f8f1d41..059c7e13b 100644 --- a/formal/ln/LnProof/LnProof/Error/LtBridge.lean +++ b/formal/ln/LnProof/LnProof/Error/LtBridge.lean @@ -21,7 +21,7 @@ The constants are the octave-extracted cell parameters at the active namespace LnFloorCert -open LnYul LnPoly LnExp +open LnYul Common.Poly Common.Exp set_option maxRecDepth 100000 @@ -61,26 +61,26 @@ theorem errLt_eval_eq : ∀ x : Int, evalPoly certErrLt x = evalPoly certErrLtLi have h9 := polyL1_polyMul (expPolyNum ltTNLit ltTDLit 22) ltTDLit have h10 := polyL1_expPolyNum ltTNLit ltTDLit 22 have h11 : polyL1 (expPolyNum ltTNLit ltTDLit 22) * polyL1 ltTDLit ≤ - LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit := + Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit := Nat.mul_le_mul_right _ h10 have h12 : (23 : Int).natAbs * polyL1 (polyMul (expPolyNum ltTNLit ltTDLit 22) ltTDLit) ≤ - (23 : Int).natAbs * (LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) := + (23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) := Nat.mul_le_mul_left _ (Nat.le_trans h9 h11) have h13 := polyL1_polyScale (2 : Int) (polyPow ltTNLit 23) have h14 := polyL1_polyPow ltTNLit 23 have h15 : (2 : Int).natAbs * polyL1 (polyPow ltTNLit 23) ≤ (2 : Int).natAbs * polyL1 ltTNLit ^ 23 := Nat.mul_le_mul_left _ h14 have h16 : polyL1 ([1, 1] : List Int) * polyL1 (polyAdd (polyScale 23 (polyMul (expPolyNum ltTNLit ltTDLit 22) ltTDLit)) (polyScale 2 (polyPow ltTNLit 23))) ≤ - polyL1 ([1, 1] : List Int) * ((23 : Int).natAbs * (LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23) := by + polyL1 ([1, 1] : List Int) * ((23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23) := by refine Nat.mul_le_mul_left _ ?_ have hx := Nat.le_trans h8 h12 have hy := Nat.le_trans h13 h15 omega have h17 : (-errLtK).natAbs * polyL1 (polyMul ([1, 1] : List Int) (polyAdd (polyScale 23 (polyMul (expPolyNum ltTNLit ltTDLit 22) ltTDLit)) (polyScale 2 (polyPow ltTNLit 23)))) ≤ - (-errLtK).natAbs * (polyL1 ([1, 1] : List Int) * ((23 : Int).natAbs * (LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23)) := + (-errLtK).natAbs * (polyL1 ([1, 1] : List Int) * ((23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23)) := Nat.mul_le_mul_left _ (Nat.le_trans h6 h16) have hfin : (((errLtW : Int) * (fact 23 : Int)).natAbs * polyL1 ltTDLit ^ 23 + - (-errLtK).natAbs * (polyL1 ([1, 1] : List Int) * ((23 : Int).natAbs * (LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23))) * 2 < 2 ^ kB := by + (-errLtK).natAbs * (polyL1 ([1, 1] : List Int) * ((23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23))) * 2 < 2 ^ kB := by decide +kernel have hA := Nat.le_trans h2 h4 have hB := Nat.le_trans h5 h17 diff --git a/formal/ln/LnProof/LnProof/Error/LtFactoredCap.lean b/formal/ln/LnProof/LnProof/Error/LtFactoredCap.lean index 9d5fe24ee..f6b2df7af 100644 --- a/formal/ln/LnProof/LnProof/Error/LtFactoredCap.lean +++ b/formal/ln/LnProof/LnProof/Error/LtFactoredCap.lean @@ -15,7 +15,7 @@ The LT-branch error-bound cut needs an *upper* cap on `e^(|H|·part)` (because namespace LnFloorCert -open LnYul LnFloor LnExp LnPoly +open LnYul LnFloor Common.Exp Common.Poly set_option maxRecDepth 100000 diff --git a/formal/ln/LnProof/LnProof/Floor/Assembly.lean b/formal/ln/LnProof/LnProof/Floor/Assembly.lean index f146a348d..38fb91881 100644 --- a/formal/ln/LnProof/LnProof/Floor/Assembly.lean +++ b/formal/ln/LnProof/LnProof/Floor/Assembly.lean @@ -17,7 +17,7 @@ on each `clz` side. -/ namespace LnFloorCert -open LnYul LnPoly LnExp LnFloor +open LnYul Common.Poly Common.Exp LnFloor /-- `V·2^27` splits into the three cap exponents (positive binade shift). -/ theorem v_scale_pos (X1v : Int) (c : Nat) (hc : c ≤ 160) : diff --git a/formal/ln/LnProof/LnProof/Floor/Bracket.lean b/formal/ln/LnProof/LnProof/Floor/Bracket.lean index 89f50e19b..1eaf013f0 100644 --- a/formal/ln/LnProof/LnProof/Floor/Bracket.lean +++ b/formal/ln/LnProof/LnProof/Floor/Bracket.lean @@ -23,7 +23,7 @@ set_option exponentiation.threshold 512 namespace LnFloorCert -open LnYul LnPoly +open LnYul Common.Poly /-- `z`-magnitude division bracket on the `m ≥ S` branch: `q = ⌊(m-S) 2^100 / (m+S)⌋` and `int256 (zWord m) = -q`. -/ @@ -1760,8 +1760,8 @@ theorem bracket_ge_lo {m : Nat} (h1 : Sc + 46 ≤ m) (h2 : m < MHI) : -- final assembly rw [evalTN2b_ge, evalTD2b_ge] have egoal : X1v * (2 ^ 99 * (2 ^ 56 * evalPoly geDLO (m : Int))) = - 2 ^ 99 * (X1v * (2 ^ 56 * evalPoly geDLO (m : Int))) := by - simp only [Int.mul_assoc, Int.mul_comm] + 2 ^ 99 * (X1v * (2 ^ 56 * evalPoly geDLO (m : Int))) := + Int.mul_left_comm _ _ _ rw [egoal] have edist : (X1v + 1) * (2 ^ 56 * evalPoly geDLO (m : Int)) = X1v * (2 ^ 56 * evalPoly geDLO (m : Int)) + 2 ^ 56 * evalPoly geDLO (m : Int) := by @@ -2592,8 +2592,8 @@ theorem bracket_lt_lo {m : Nat} (h1 : MLO ≤ m) (h2 : m + 46 ≤ Sc) : -- final assembly rw [evalTN2b_lt, evalTD2b_lt] have egoal : X1v * (2 ^ 99 * (2 ^ 56 * evalPoly ltDLO (m : Int))) = - 2 ^ 99 * (X1v * (2 ^ 56 * evalPoly ltDLO (m : Int))) := by - simp only [Int.mul_assoc, Int.mul_comm] + 2 ^ 99 * (X1v * (2 ^ 56 * evalPoly ltDLO (m : Int))) := + Int.mul_left_comm _ _ _ rw [egoal] have edist : (X1v + 1) * (2 ^ 56 * evalPoly ltDLO (m : Int)) = X1v * (2 ^ 56 * evalPoly ltDLO (m : Int)) + 2 ^ 56 * evalPoly ltDLO (m : Int) := by diff --git a/formal/ln/LnProof/LnProof/Floor/Budget.lean b/formal/ln/LnProof/LnProof/Floor/Budget.lean index ceaa607d2..5bf7227f3 100644 --- a/formal/ln/LnProof/LnProof/Floor/Budget.lean +++ b/formal/ln/LnProof/LnProof/Floor/Budget.lean @@ -1,4 +1,4 @@ -import LnProof.Foundation.ExpSum +import Common.Foundation.ExpSum /-! # Per-exponent budget inequalities @@ -18,7 +18,7 @@ Also provides `capLB_cancel`, the lower mirror of `capUB_cancel`, used to move the `2^|k|` factor across the quotient when `k < 0`. -/ -namespace LnExp +namespace Common.Exp /-- `e^(pa/q) = e^((pa+pb)/q) / e^(pb/q) ≥ (C/W) / (G/V)`. -/ theorem capLB_cancel {pa pb q C W G V : Nat} (hq : 0 < q) @@ -44,7 +44,7 @@ theorem capLB_cancel {pa pb q C W G V : Nat} (hq : 0 < q) _ = expNum n pa q * (W * G) * (fact n * q ^ n) := by simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] -end LnExp +end Common.Exp namespace LnFloorCert diff --git a/formal/ln/LnProof/LnProof/Floor/Caps.lean b/formal/ln/LnProof/LnProof/Floor/Caps.lean index a81f53253..3bfe286b3 100644 --- a/formal/ln/LnProof/LnProof/Floor/Caps.lean +++ b/formal/ln/LnProof/LnProof/Floor/Caps.lean @@ -14,7 +14,7 @@ mirrors, with `ε = 42/10^29`, over the common denominator `10^27 · 2^99`. -/ namespace LnFloorCert -open LnYul LnPoly LnExp +open LnYul Common.Poly Common.Exp set_option maxRecDepth 100000 diff --git a/formal/ln/LnProof/LnProof/Floor/CertAux.lean b/formal/ln/LnProof/LnProof/Floor/CertAux.lean index 383bc4f5b..3ffbad005 100644 --- a/formal/ln/LnProof/LnProof/Floor/CertAux.lean +++ b/formal/ln/LnProof/LnProof/Floor/CertAux.lean @@ -1,7 +1,7 @@ import LnProof.Floor.CertDefs namespace LnFloorCert -open LnPoly +open Common.Poly set_option maxRecDepth 100000 diff --git a/formal/ln/LnProof/LnProof/Floor/CertDefs.lean b/formal/ln/LnProof/LnProof/Floor/CertDefs.lean index c6832162d..2a3023eea 100644 --- a/formal/ln/LnProof/LnProof/Floor/CertDefs.lean +++ b/formal/ln/LnProof/LnProof/Floor/CertDefs.lean @@ -1,4 +1,4 @@ -import LnProof.Foundation.ShiftCert +import Common.Foundation.ShiftCert import LnProof.Model.Body /-! @@ -14,7 +14,7 @@ are in the `FloorCert*` files. namespace LnFloorCert -open LnPoly LnYul +open Common.Poly LnYul def WINDOW : Nat := 46 diff --git a/formal/ln/LnProof/LnProof/Floor/CertGeLo.lean b/formal/ln/LnProof/LnProof/Floor/CertGeLo.lean index 9295f19b9..6b09f3bb3 100644 --- a/formal/ln/LnProof/LnProof/Floor/CertGeLo.lean +++ b/formal/ln/LnProof/LnProof/Floor/CertGeLo.lean @@ -1,6 +1,6 @@ import LnProof.Floor.CertDefs import LnProof.Cert.FloorCertLit -import LnProof.Foundation.Kronecker +import Common.Foundation.Kronecker import LnProof.Cert.FloorCertGeLoC00 import LnProof.Cert.FloorCertGeLoC01 import LnProof.Cert.FloorCertGeLoC02 @@ -19,7 +19,7 @@ import LnProof.Cert.FloorCertGeLoC14 import LnProof.Cert.FloorCertGeLoC15 namespace LnFloorCert -open LnYul LnPoly +open LnYul Common.Poly set_option maxRecDepth 100000 @@ -46,7 +46,7 @@ theorem geLo_eval_eq : ∀ x : Int, evalPoly certGeLo x = evalPoly certGeLoLit x have h3 := polyL1_expPolyNum geTN2bLit geTD2bLit 22 have h7 : (EUD * (Sc : Int)).natAbs * polyL1 (expPolyNum geTN2bLit geTD2bLit 22) ≤ (EUD * (Sc : Int)).natAbs * - LnExp.expNum 22 (polyL1 geTN2bLit) (polyL1 geTD2bLit) := + Common.Exp.expNum 22 (polyL1 geTN2bLit) (polyL1 geTD2bLit) := Nat.mul_le_mul_left _ h3 have h4 := polyL1_polyScale (-(EUD - EUNl) * KF) (polyMul [0, 1] (polyPow geTD2bLit 22)) have h5 := polyL1_polyMul ([0, 1] : List Int) (polyPow geTD2bLit 22) @@ -60,7 +60,7 @@ theorem geLo_eval_eq : ∀ x : Int, evalPoly certGeLo x = evalPoly certGeLoLit x (polyL1 ([0, 1] : List Int) * polyL1 geTD2bLit ^ 22) := Nat.mul_le_mul_left _ (Nat.le_trans h5 h8) have hfin : ((EUD * (Sc : Int)).natAbs * - LnExp.expNum 22 (polyL1 geTN2bLit) (polyL1 geTD2bLit) + + Common.Exp.expNum 22 (polyL1 geTN2bLit) (polyL1 geTD2bLit) + (-(EUD - EUNl) * KF).natAbs * (polyL1 ([0, 1] : List Int) * polyL1 geTD2bLit ^ 22)) * 2 < 2 ^ kB := by decide +kernel diff --git a/formal/ln/LnProof/LnProof/Floor/CertGeUp.lean b/formal/ln/LnProof/LnProof/Floor/CertGeUp.lean index 0bd2b0209..18e89c32d 100644 --- a/formal/ln/LnProof/LnProof/Floor/CertGeUp.lean +++ b/formal/ln/LnProof/LnProof/Floor/CertGeUp.lean @@ -1,6 +1,6 @@ import LnProof.Floor.CertDefs import LnProof.Cert.FloorCertLit -import LnProof.Foundation.Kronecker +import Common.Foundation.Kronecker import LnProof.Cert.FloorCertGeUpC00 import LnProof.Cert.FloorCertGeUpC01 import LnProof.Cert.FloorCertGeUpC02 @@ -18,7 +18,7 @@ import LnProof.Cert.FloorCertGeUpC13 import LnProof.Cert.FloorCertGeUpC14 namespace LnFloorCert -open LnYul LnPoly +open LnYul Common.Poly set_option maxRecDepth 100000 @@ -56,23 +56,23 @@ theorem geUp_eval_eq : ∀ x : Int, evalPoly certGeUp x = evalPoly certGeUpLit x have h10 := polyL1_polyMul (expPolyNum geTNLit geTDLit 22) geTDLit have h11 := polyL1_expPolyNum geTNLit geTDLit 22 have h12 : polyL1 (expPolyNum geTNLit geTDLit 22) * polyL1 geTDLit ≤ - LnExp.expNum 22 (polyL1 geTNLit) (polyL1 geTDLit) * polyL1 geTDLit := + Common.Exp.expNum 22 (polyL1 geTNLit) (polyL1 geTDLit) * polyL1 geTDLit := Nat.mul_le_mul_right _ h11 have h13 : (23 : Int).natAbs * polyL1 (polyMul (expPolyNum geTNLit geTDLit 22) geTDLit) ≤ - (23 : Int).natAbs * (LnExp.expNum 22 (polyL1 geTNLit) (polyL1 geTDLit) * polyL1 geTDLit) := + (23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 geTNLit) (polyL1 geTDLit) * polyL1 geTDLit) := Nat.mul_le_mul_left _ (Nat.le_trans h10 h12) have h14 := polyL1_polyScale (2 : Int) (polyPow geTNLit 23) have h15 := polyL1_polyPow geTNLit 23 have h16 : (2 : Int).natAbs * polyL1 (polyPow geTNLit 23) ≤ (2 : Int).natAbs * polyL1 geTNLit ^ 23 := Nat.mul_le_mul_left _ h15 have h17 : (-(Sc : Int) * EUD).natAbs * polyL1 (polyAdd (polyScale 23 (polyMul (expPolyNum geTNLit geTDLit 22) geTDLit)) (polyScale 2 (polyPow geTNLit 23))) ≤ - (-(Sc : Int) * EUD).natAbs * ((23 : Int).natAbs * (LnExp.expNum 22 (polyL1 geTNLit) (polyL1 geTDLit) * polyL1 geTDLit) + (2 : Int).natAbs * polyL1 geTNLit ^ 23) := by + (-(Sc : Int) * EUD).natAbs * ((23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 geTNLit) (polyL1 geTDLit) * polyL1 geTDLit) + (2 : Int).natAbs * polyL1 geTNLit ^ 23) := by refine Nat.mul_le_mul_left _ ?_ have := Nat.le_trans h9 h13 have h14' := Nat.le_trans h14 h16 omega have hfin : (((EUD + EUN) * KF1).natAbs * (polyL1 ([0, 1] : List Int) * polyL1 geTDLit ^ 23) + - (-(Sc : Int) * EUD).natAbs * ((23 : Int).natAbs * (LnExp.expNum 22 (polyL1 geTNLit) (polyL1 geTDLit) * polyL1 geTDLit) + (2 : Int).natAbs * polyL1 geTNLit ^ 23)) * 2 < 2 ^ kB := by + (-(Sc : Int) * EUD).natAbs * ((23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 geTNLit) (polyL1 geTDLit) * polyL1 geTDLit) + (2 : Int).natAbs * polyL1 geTNLit ^ 23)) * 2 < 2 ^ kB := by decide +kernel have hA := Nat.le_trans h2 h6 have hB := Nat.le_trans h7 h17 diff --git a/formal/ln/LnProof/LnProof/Floor/CertLtLo.lean b/formal/ln/LnProof/LnProof/Floor/CertLtLo.lean index a0f2ec3c4..b5c0528e5 100644 --- a/formal/ln/LnProof/LnProof/Floor/CertLtLo.lean +++ b/formal/ln/LnProof/LnProof/Floor/CertLtLo.lean @@ -1,6 +1,6 @@ import LnProof.Floor.CertDefs import LnProof.Cert.FloorCertLit -import LnProof.Foundation.Kronecker +import Common.Foundation.Kronecker import LnProof.Cert.FloorCertLtLoC00 import LnProof.Cert.FloorCertLtLoC01 import LnProof.Cert.FloorCertLtLoC02 @@ -19,7 +19,7 @@ import LnProof.Cert.FloorCertLtLoC14 import LnProof.Cert.FloorCertLtLoC15 namespace LnFloorCert -open LnYul LnPoly +open LnYul Common.Poly set_option maxRecDepth 100000 @@ -54,26 +54,26 @@ theorem ltLo_eval_eq : ∀ x : Int, evalPoly certLtLo x = evalPoly certLtLoLit x have h9 := polyL1_polyMul (expPolyNum ltTNLit ltTDLit 22) ltTDLit have h10 := polyL1_expPolyNum ltTNLit ltTDLit 22 have h11 : polyL1 (expPolyNum ltTNLit ltTDLit 22) * polyL1 ltTDLit ≤ - LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit := + Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit := Nat.mul_le_mul_right _ h10 have h12 : (23 : Int).natAbs * polyL1 (polyMul (expPolyNum ltTNLit ltTDLit 22) ltTDLit) ≤ - (23 : Int).natAbs * (LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) := + (23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) := Nat.mul_le_mul_left _ (Nat.le_trans h9 h11) have h13 := polyL1_polyScale (2 : Int) (polyPow ltTNLit 23) have h14 := polyL1_polyPow ltTNLit 23 have h15 : (2 : Int).natAbs * polyL1 (polyPow ltTNLit 23) ≤ (2 : Int).natAbs * polyL1 ltTNLit ^ 23 := Nat.mul_le_mul_left _ h14 have h16 : polyL1 ([0, 1] : List Int) * polyL1 (polyAdd (polyScale 23 (polyMul (expPolyNum ltTNLit ltTDLit 22) ltTDLit)) (polyScale 2 (polyPow ltTNLit 23))) ≤ - polyL1 ([0, 1] : List Int) * ((23 : Int).natAbs * (LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23) := by + polyL1 ([0, 1] : List Int) * ((23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23) := by refine Nat.mul_le_mul_left _ ?_ have hx := Nat.le_trans h8 h12 have hy := Nat.le_trans h13 h15 omega have h17 : (-(EUD - EUNl)).natAbs * polyL1 (polyMul ([0, 1] : List Int) (polyAdd (polyScale 23 (polyMul (expPolyNum ltTNLit ltTDLit 22) ltTDLit)) (polyScale 2 (polyPow ltTNLit 23)))) ≤ - (-(EUD - EUNl)).natAbs * (polyL1 ([0, 1] : List Int) * ((23 : Int).natAbs * (LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23)) := + (-(EUD - EUNl)).natAbs * (polyL1 ([0, 1] : List Int) * ((23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23)) := Nat.mul_le_mul_left _ (Nat.le_trans h6 h16) have hfin : (((Sc : Int) * EUD * KF1).natAbs * polyL1 ltTDLit ^ 23 + - (-(EUD - EUNl)).natAbs * (polyL1 ([0, 1] : List Int) * ((23 : Int).natAbs * (LnExp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23))) * 2 < 2 ^ kB := by + (-(EUD - EUNl)).natAbs * (polyL1 ([0, 1] : List Int) * ((23 : Int).natAbs * (Common.Exp.expNum 22 (polyL1 ltTNLit) (polyL1 ltTDLit) * polyL1 ltTDLit) + (2 : Int).natAbs * polyL1 ltTNLit ^ 23))) * 2 < 2 ^ kB := by decide +kernel have hA := Nat.le_trans h2 h4 have hB := Nat.le_trans h5 h17 diff --git a/formal/ln/LnProof/LnProof/Floor/CertLtUp.lean b/formal/ln/LnProof/LnProof/Floor/CertLtUp.lean index d12203d6f..1408cc3b0 100644 --- a/formal/ln/LnProof/LnProof/Floor/CertLtUp.lean +++ b/formal/ln/LnProof/LnProof/Floor/CertLtUp.lean @@ -1,6 +1,6 @@ import LnProof.Floor.CertDefs import LnProof.Cert.FloorCertLit -import LnProof.Foundation.Kronecker +import Common.Foundation.Kronecker import LnProof.Cert.FloorCertLtUpC00 import LnProof.Cert.FloorCertLtUpC01 import LnProof.Cert.FloorCertLtUpC02 @@ -20,7 +20,7 @@ import LnProof.Cert.FloorCertLtUpC15 import LnProof.Cert.FloorCertLtUpC16 namespace LnFloorCert -open LnYul LnPoly +open LnYul Common.Poly set_option maxRecDepth 100000 @@ -47,17 +47,17 @@ theorem ltUp_eval_eq : ∀ x : Int, evalPoly certLtUp x = evalPoly certLtUpLit x have h3 := polyL1_polyMul ([0, 1] : List Int) (expPolyNum ltTN2bLit ltTD2bLit 22) have h4 := polyL1_expPolyNum ltTN2bLit ltTD2bLit 22 have h5 : polyL1 ([0, 1] : List Int) * polyL1 (expPolyNum ltTN2bLit ltTD2bLit 22) ≤ - polyL1 ([0, 1] : List Int) * LnExp.expNum 22 (polyL1 ltTN2bLit) (polyL1 ltTD2bLit) := + polyL1 ([0, 1] : List Int) * Common.Exp.expNum 22 (polyL1 ltTN2bLit) (polyL1 ltTD2bLit) := Nat.mul_le_mul_left _ h4 have h6 : (EUD + EUN).natAbs * polyL1 (polyMul ([0, 1] : List Int) (expPolyNum ltTN2bLit ltTD2bLit 22)) ≤ - (EUD + EUN).natAbs * (polyL1 ([0, 1] : List Int) * LnExp.expNum 22 (polyL1 ltTN2bLit) (polyL1 ltTD2bLit)) := + (EUD + EUN).natAbs * (polyL1 ([0, 1] : List Int) * Common.Exp.expNum 22 (polyL1 ltTN2bLit) (polyL1 ltTD2bLit)) := Nat.mul_le_mul_left _ (Nat.le_trans h3 h5) have h7 := polyL1_polyScale (-EUD * (Sc : Int) * KF) (polyPow ltTD2bLit 22) have h8 := polyL1_polyPow ltTD2bLit 22 have h9 : (-EUD * (Sc : Int) * KF).natAbs * polyL1 (polyPow ltTD2bLit 22) ≤ (-EUD * (Sc : Int) * KF).natAbs * polyL1 ltTD2bLit ^ 22 := Nat.mul_le_mul_left _ h8 - have hfin : ((EUD + EUN).natAbs * (polyL1 ([0, 1] : List Int) * LnExp.expNum 22 (polyL1 ltTN2bLit) (polyL1 ltTD2bLit)) + + have hfin : ((EUD + EUN).natAbs * (polyL1 ([0, 1] : List Int) * Common.Exp.expNum 22 (polyL1 ltTN2bLit) (polyL1 ltTD2bLit)) + (-EUD * (Sc : Int) * KF).natAbs * polyL1 ltTD2bLit ^ 22) * 2 < 2 ^ kB := by decide +kernel have hA := Nat.le_trans h2 h6 diff --git a/formal/ln/LnProof/LnProof/Floor/Consts.lean b/formal/ln/LnProof/LnProof/Floor/Consts.lean index 82cd2a2bf..515e8bb3a 100644 --- a/formal/ln/LnProof/LnProof/Floor/Consts.lean +++ b/formal/ln/LnProof/LnProof/Floor/Consts.lean @@ -1,4 +1,4 @@ -import LnProof.Foundation.ExpSum +import Common.Foundation.ExpSum import LnProof.Model.Body import LnProof.Spec.Cut @@ -20,7 +20,7 @@ set_option maxRecDepth 8192 namespace LnFloor -open LnExp LnYul +open Common.Exp LnYul /-- `e^(LN2c 2^27 / QS) ≤ 2 (1 + 1e-40)`: the scaled `ln 2` constant. -/ theorem cap2U : capUB (LN2c * 2 ^ 27) QS (2 * (10 ^ 40 + 1)) (10 ^ 40) := by diff --git a/formal/ln/LnProof/LnProof/Floor/CutEquiv.lean b/formal/ln/LnProof/LnProof/Floor/CutEquiv.lean index 95911a218..8f3a57545 100644 --- a/formal/ln/LnProof/LnProof/Floor/CutEquiv.lean +++ b/formal/ln/LnProof/LnProof/Floor/CutEquiv.lean @@ -22,7 +22,7 @@ cut-log predicates. namespace LnFloorCert -open LnYul LnExp LnFloor +open LnYul Common.Exp LnFloor /-- `FloorSpecA` is exactly the lower cut-log comparison. -/ theorem FloorSpecA_iff_cutLeLogWadRay {r : Int} {x : Nat} : diff --git a/formal/ln/LnProof/LnProof/Floor/Model.lean b/formal/ln/LnProof/LnProof/Floor/Model.lean index 0f5f8d795..d4cf00dfb 100644 --- a/formal/ln/LnProof/LnProof/Floor/Model.lean +++ b/formal/ln/LnProof/LnProof/Floor/Model.lean @@ -19,7 +19,7 @@ set_option maxRecDepth 4096 namespace LnFloor -open LnYul LnPoly +open LnYul Common.Poly /-- Mantissa word of `x`. -/ def mant (x : Nat) : Nat := evmShr 160 (evmShl (evmClz x) x) diff --git a/formal/ln/LnProof/LnProof/Floor/Spec.lean b/formal/ln/LnProof/LnProof/Floor/Spec.lean index cfddd4390..78e8fa2a3 100644 --- a/formal/ln/LnProof/LnProof/Floor/Spec.lean +++ b/formal/ln/LnProof/LnProof/Floor/Spec.lean @@ -28,7 +28,7 @@ as an explicit log-cut specification. -/ namespace LnFloorCert -open LnYul LnPoly LnExp LnFloor +open LnYul Common.Poly Common.Exp LnFloor -- The self-corrected body term repeats the accumulator (the `s == -1` test -- reads the shifted result), so elaboration-time `whnf` of it is expensive. diff --git a/formal/ln/LnProof/LnProof/Floor/Window.lean b/formal/ln/LnProof/LnProof/Floor/Window.lean index f98cc1e8c..42fcda60e 100644 --- a/formal/ln/LnProof/LnProof/Floor/Window.lean +++ b/formal/ln/LnProof/LnProof/Floor/Window.lean @@ -22,7 +22,7 @@ cover each whole branch. -/ namespace LnFloorCert -open LnYul LnPoly LnExp LnFloor +open LnYul Common.Poly Common.Exp LnFloor set_option maxRecDepth 10000 diff --git a/formal/ln/LnProof/LnProof/Foundation.lean b/formal/ln/LnProof/LnProof/Foundation.lean index a4d41134b..edda25870 100644 --- a/formal/ln/LnProof/LnProof/Foundation.lean +++ b/formal/ln/LnProof/LnProof/Foundation.lean @@ -1,16 +1,16 @@ /-! # Foundation facade -Domain-agnostic primitives shared across the proof: EVM-word arithmetic -transport (`Word`, `WordDiv`), the exponential partial-sum interface -(`ExpSum`), and the polynomial-positivity / Kronecker certificate machinery -(`Poly`, `ShiftCert`, `Kronecker`, `KroneckerShift`). No `lnWad`-specific -semantics live here. +Domain-agnostic primitives this proof relies on: EVM-word arithmetic transport +(`Word`, `WordDiv`, local), plus the function-agnostic machinery from the +shared `Common` package — the exponential partial-sum interface (`Common.Exp`) +and the polynomial-positivity / Kronecker certificate machinery +(`Common.Poly`). No `lnWad`-specific semantics live here. -/ import LnProof.Foundation.Word import LnProof.Foundation.WordDiv -import LnProof.Foundation.ExpSum -import LnProof.Foundation.Poly -import LnProof.Foundation.ShiftCert -import LnProof.Foundation.Kronecker -import LnProof.Foundation.KroneckerShift +import Common.Foundation.ExpSum +import Common.Foundation.Poly +import Common.Foundation.ShiftCert +import Common.Foundation.Kronecker +import Common.Foundation.KroneckerShift diff --git a/formal/ln/LnProof/LnProof/Foundation/ExpSum.lean b/formal/ln/LnProof/LnProof/Foundation/ExpSum.lean deleted file mode 100644 index 8990ec049..000000000 --- a/formal/ln/LnProof/LnProof/Foundation/ExpSum.lean +++ /dev/null @@ -1,857 +0,0 @@ -import Init - -/-! -# Exponential partial sums over scaled integers - -`S_N(p/q) = Σ_{j ≤ N} (p/q)^j / j!` is represented exactly by the integer -`expNum N p q = Σ_{j ≤ N} (N!/j!) p^j q^(N-j)`, so that -`S_N(p/q) = expNum N p q / (N! q^N)`. Arguments are nonnegative rationals -given as `Nat` pairs. For `t ≥ 0` the partial sums increase to `e^t`, which -is how the finite cut certificates arithmetize the `lnWad` logarithm bounds: -an upper bound on `e^t` is `∀ N` a bound on `S_N`, and a lower bound is -witnessed by a single `S_N`. - -Everything here is `Nat` arithmetic: monotonicity in `N` and in the -argument, a geometric tail bound (turning one evaluated partial sum into a -bound for all `N`), and the binomial subset-product inequalities standing -in for `e^(a+b) = e^a * e^b`. --/ - -namespace LnExp - -def fact : Nat → Nat - | 0 => 1 - | n + 1 => (n + 1) * fact n - -theorem fact_pos (n : Nat) : 0 < fact n := by - induction n with - | zero => decide - | succ k ih => simp only [fact]; exact Nat.mul_pos (Nat.succ_pos k) ih - -/-- `expNum N p q = Σ_{j ≤ N} (N!/j!) p^j q^(N-j)`, by the recursion -`E_{N+1} = (N+1) q E_N + p^(N+1)`. -/ -def expNum : Nat → Nat → Nat → Nat - | 0, _, _ => 1 - | n + 1, p, q => (n + 1) * q * expNum n p q + p ^ (n + 1) - -theorem expNum_pos {p q : Nat} (hq : 0 < q) : ∀ n, 0 < expNum n p q := by - intro n - induction n with - | zero => simp only [expNum]; omega - | succ k ih => - simp only [expNum] - have h1 : 0 < (k + 1) * q * expNum k p q := - Nat.mul_pos (Nat.mul_pos (Nat.succ_pos k) hq) ih - omega - -/-- Comparison helpers: `S_N(p/q) ≤ y/w` and `S_N(p/q) ≥ y/w` as integer -inequalities (`q, w` positive at use sites). -/ -def sumLE (n p q y w : Nat) : Prop := expNum n p q * w ≤ y * (fact n * q ^ n) -def sumGE (n p q y w : Nat) : Prop := y * (fact n * q ^ n) ≤ expNum n p q * w - -instance (n p q y w : Nat) : Decidable (sumLE n p q y w) := by - unfold sumLE; infer_instance -instance (n p q y w : Nat) : Decidable (sumGE n p q y w) := by - unfold sumGE; infer_instance - -/-! ## Finite sums -/ - -/-- `tsum n f = f 0 + f 1 + ... + f n`. -/ -def tsum : Nat → (Nat → Nat) → Nat - | 0, f => f 0 - | n + 1, f => tsum n f + f (n + 1) - -theorem tsum_le_tsum {f g : Nat → Nat} {n : Nat} (h : ∀ i, i ≤ n → f i ≤ g i) : - tsum n f ≤ tsum n g := by - induction n with - | zero => exact h 0 (Nat.le_refl 0) - | succ k ih => - simp only [tsum] - have h1 := ih (fun i hi => h i (Nat.le_succ_of_le hi)) - have h2 := h (k + 1) (Nat.le_refl _) - omega - -theorem tsum_congr {f g : Nat → Nat} {n : Nat} (h : ∀ i, i ≤ n → f i = g i) : - tsum n f = tsum n g := by - induction n with - | zero => exact h 0 (Nat.le_refl 0) - | succ k ih => - simp only [tsum] - rw [ih (fun i hi => h i (Nat.le_succ_of_le hi)), h (k + 1) (Nat.le_refl _)] - -theorem tsum_mul_const {f : Nat → Nat} {n c : Nat} : - tsum n f * c = tsum n (fun i => f i * c) := by - induction n with - | zero => rfl - | succ k ih => simp only [tsum, Nat.add_mul, ih] - -theorem const_mul_tsum {f : Nat → Nat} {n c : Nat} : - c * tsum n f = tsum n (fun i => c * f i) := by - induction n with - | zero => rfl - | succ k ih => simp only [tsum, Nat.mul_add, ih] - -theorem tsum_add {f g : Nat → Nat} {n : Nat} : - tsum n (fun i => f i + g i) = tsum n f + tsum n g := by - induction n with - | zero => rfl - | succ k ih => simp only [tsum, ih]; omega - -theorem first_le_tsum (f : Nat → Nat) (n : Nat) : f 0 ≤ tsum n f := by - induction n with - | zero => exact Nat.le_refl _ - | succ k ih => simp only [tsum]; omega - -theorem tsum_prefix_le {f : Nat → Nat} {n m : Nat} (h : n ≤ m) : - tsum n f ≤ tsum m f := by - induction m with - | zero => cases Nat.le_zero.mp h; exact Nat.le_refl _ - | succ k ih => - rcases Nat.lt_or_ge n (k + 1) with hlt | hge - · have := ih (by omega) - simp only [tsum] - omega - · have he : n = k + 1 := by omega - rw [he] - exact Nat.le_refl _ - -/-- Sum transpose: diagonal-major to column-major over the triangle -`{(i, j) : i + j ≤ c}`. -/ -theorem tri_transpose (T : Nat → Nat → Nat) (c : Nat) : - tsum c (fun n => tsum n (fun i => T i (n - i))) = - tsum c (fun i => tsum (c - i) (fun j => T i j)) := by - induction c with - | zero => rfl - | succ k ih => - -- peel the diagonal n = k+1 on the left, the last entries on the right - have hr : tsum (k + 1) (fun i => tsum (k + 1 - i) (fun j => T i j)) = - tsum k (fun i => tsum (k - i) (fun j => T i j)) + - tsum (k + 1) (fun i => T i (k + 1 - i)) := by - have hsplit : ∀ i, i ≤ k → - tsum (k + 1 - i) (fun j => T i j) = - tsum (k - i) (fun j => T i j) + T i (k + 1 - i) := by - intro i hi - have he : k + 1 - i = (k - i) + 1 := by omega - rw [he] - rfl - calc tsum (k + 1) (fun i => tsum (k + 1 - i) (fun j => T i j)) - = tsum k (fun i => tsum (k + 1 - i) (fun j => T i j)) + - tsum 0 (fun j => T (k + 1) j) := by - show tsum k _ + tsum (k + 1 - (k + 1)) _ = _ - rw [Nat.sub_self] - _ = tsum k (fun i => tsum (k - i) (fun j => T i j) + T i (k + 1 - i)) + - T (k + 1) 0 := by - rw [tsum_congr (fun i hi => hsplit i hi)] - rfl - _ = tsum k (fun i => tsum (k - i) (fun j => T i j)) + - tsum k (fun i => T i (k + 1 - i)) + T (k + 1) 0 := by - rw [tsum_add] - _ = tsum k (fun i => tsum (k - i) (fun j => T i j)) + - tsum (k + 1) (fun i => T i (k + 1 - i)) := by - have : tsum (k + 1) (fun i => T i (k + 1 - i)) = - tsum k (fun i => T i (k + 1 - i)) + T (k + 1) 0 := by - have he : k + 1 - (k + 1) = 0 := by omega - simp only [tsum, he] - omega - simp only [tsum] at * - omega - -/-- Box-into-triangle: summing a nonnegative term over `[0,N] × [0,M]` is at -most the sum over the triangle `{i + j ≤ N + M}`. -/ -theorem box_le_tri (T : Nat → Nat → Nat) (N M : Nat) : - tsum N (fun i => tsum M (fun j => T i j)) ≤ - tsum (N + M) (fun n => tsum n (fun i => T i (n - i))) := by - rw [tri_transpose] - calc tsum N (fun i => tsum M (fun j => T i j)) - ≤ tsum N (fun i => tsum (N + M - i) (fun j => T i j)) := - tsum_le_tsum (fun i hi => tsum_prefix_le (by omega)) - _ ≤ tsum (N + M) (fun i => tsum (N + M - i) (fun j => T i j)) := - tsum_prefix_le (by omega) - -/-- Triangle-into-box: the triangle `{i + j ≤ K}` sits inside `[0,K] × [0,K]`. -/ -theorem tri_le_box (T : Nat → Nat → Nat) (K : Nat) : - tsum K (fun n => tsum n (fun i => T i (n - i))) ≤ - tsum K (fun i => tsum K (fun j => T i j)) := by - rw [tri_transpose] - exact tsum_le_tsum (fun i hi => tsum_prefix_le (by omega)) - -/-! ## Coefficients -/ - -/-- Rising product: `ffacAux j d = (j+1)(j+2)...(j+d) = (j+d)!/j!`. -/ -def ffacAux (j : Nat) : Nat → Nat - | 0 => 1 - | d + 1 => (j + d + 1) * ffacAux j d - -theorem ffacAux_mul_fact (j : Nat) : ∀ d, ffacAux j d * fact j = fact (j + d) := by - intro d - induction d with - | zero => simp only [ffacAux, Nat.one_mul, Nat.add_zero] - | succ k ih => - simp only [ffacAux] - calc (j + k + 1) * ffacAux j k * fact j - = (j + k + 1) * (ffacAux j k * fact j) := by rw [Nat.mul_assoc] - _ = (j + k + 1) * fact (j + k) := by rw [ih] - _ = fact (j + k + 1) := rfl - -/-- Front peel: `tsum (n+1) f = f 0 + Σ_{i ≤ n} f (i+1)`. -/ -theorem tsum_shift (f : Nat → Nat) (n : Nat) : - tsum (n + 1) f = f 0 + tsum n (fun i => f (i + 1)) := by - induction n with - | zero => rfl - | succ m ih => - have h1 : tsum (m + 2) f = tsum (m + 1) f + f (m + 2) := rfl - have h2 : tsum (m + 1) (fun i => f (i + 1)) = - tsum m (fun i => f (i + 1)) + f (m + 2) := rfl - rw [h1, ih, h2] - omega - -/-- Pascal-recursive binomial coefficient. -/ -def cho : Nat → Nat → Nat - | _, 0 => 1 - | 0, _ + 1 => 0 - | n + 1, i + 1 => cho n i + cho n (i + 1) - -theorem cho_eq_zero_of_lt : ∀ {n i : Nat}, n < i → cho n i = 0 := by - intro n - induction n with - | zero => intro i h; match i, h with | i + 1, _ => rfl - | succ k ih => - intro i h - match i, h with - | i + 1, h => - show cho k i + cho k (i + 1) = 0 - rw [ih (by omega), ih (by omega)] - -theorem cho_self : ∀ n, cho n n = 1 := by - intro n - induction n with - | zero => rfl - | succ k ih => - show cho k k + cho k (k + 1) = 1 - rw [ih, cho_eq_zero_of_lt (Nat.lt_succ_self k)] - -theorem cho_fact : ∀ n i, i ≤ n → cho n i * (fact i * fact (n - i)) = fact n := by - intro n - induction n with - | zero => intro i h; cases Nat.le_zero.mp h; rfl - | succ k ih => - intro i h - match i with - | 0 => - show 1 * (1 * fact (k + 1)) = fact (k + 1) - omega - | i + 1 => - show (cho k i + cho k (i + 1)) * (fact (i + 1) * fact (k + 1 - (i + 1))) = - fact (k + 1) - have hf1 : fact (i + 1) = (i + 1) * fact i := rfl - rcases Nat.lt_or_ge k (i + 1) with hlt | hge - · -- top of the column: i = k, the second binomial vanishes - have he : i = k := by omega - rw [he, cho_self, show cho k (k + 1) = 0 from cho_eq_zero_of_lt (Nat.lt_succ_self k), - Nat.sub_self] - show (1 + 0) * (fact (k + 1) * 1) = fact (k + 1) - omega - · have h1 := ih i (by omega) - have h2 := ih (i + 1) hge - have hs1 : k + 1 - (i + 1) = k - i := by omega - have hs2 : k - i = (k - (i + 1)) + 1 := by omega - -- cho k i * ((i+1)! * (k-i)!) = (i+1) * k! - have e1 : cho k i * (fact (i + 1) * fact (k - i)) = (i + 1) * fact k := by - rw [hf1, ← h1] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - -- cho k (i+1) * ((i+1)! * (k-i)!) = (k-i) * k! - have e2 : cho k (i + 1) * (fact (i + 1) * fact (k - i)) = (k - i) * fact k := by - rw [hs2, show fact ((k - (i + 1)) + 1) = ((k - (i + 1)) + 1) * fact (k - (i + 1)) - from rfl, ← h2] - simp only [Nat.mul_left_comm] - rw [hs1, Nat.add_mul, e1, e2, ← Nat.add_mul] - have hc : i + 1 + (k - i) = k + 1 := by omega - rw [hc] - rfl - -/-- Binomial theorem. -/ -theorem add_pow (a b n : Nat) : - (a + b) ^ n = tsum n (fun i => cho n i * a ^ i * b ^ (n - i)) := by - induction n with - | zero => - show 1 = cho 0 0 * a ^ 0 * b ^ 0 - rfl - | succ k ih => - have step : (a + b) ^ (k + 1) = - tsum k (fun i => cho k i * a ^ (i + 1) * b ^ (k - i)) + - tsum k (fun i => cho k i * a ^ i * b ^ (k + 1 - i)) := by - have hx : (a + b) ^ (k + 1) = (a + b) ^ k * a + (a + b) ^ k * b := by - rw [Nat.pow_succ, Nat.mul_add] - rw [hx, ih, tsum_mul_const, tsum_mul_const] - congr 1 - · refine tsum_congr (fun i hi => ?_) - rw [Nat.pow_succ] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - · refine tsum_congr (fun i hi => ?_) - rw [show k + 1 - i = (k - i) + 1 by omega, Nat.pow_succ] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [step] - have peel : tsum (k + 1) (fun i => cho (k + 1) i * a ^ i * b ^ (k + 1 - i)) = - b ^ (k + 1) + - tsum k (fun i => cho (k + 1) (i + 1) * a ^ (i + 1) * b ^ (k - i)) := by - rw [tsum_shift] - congr 1 - · show cho (k + 1) 0 * a ^ 0 * b ^ (k + 1) = b ^ (k + 1) - show 1 * 1 * b ^ (k + 1) = b ^ (k + 1) - omega - · exact tsum_congr (fun i hi => by rw [show k + 1 - (i + 1) = k - i by omega]) - rw [peel] - have pascal : tsum k (fun i => cho (k + 1) (i + 1) * a ^ (i + 1) * b ^ (k - i)) = - tsum k (fun i => cho k i * a ^ (i + 1) * b ^ (k - i)) + - tsum k (fun i => cho k (i + 1) * a ^ (i + 1) * b ^ (k - i)) := by - rw [← tsum_add] - refine tsum_congr (fun i hi => ?_) - show (cho k i + cho k (i + 1)) * _ * _ = _ - rw [Nat.add_mul, Nat.add_mul] - rw [pascal] - -- the b-branch of `step` equals b^(k+1) plus the shifted Pascal remainder - have hb : tsum k (fun i => cho k i * a ^ i * b ^ (k + 1 - i)) = - b ^ (k + 1) + tsum k (fun i => cho k (i + 1) * a ^ (i + 1) * b ^ (k - i)) := by - cases k with - | zero => - show cho 0 0 * a ^ 0 * b ^ 1 = b ^ 1 + cho 0 1 * a ^ 1 * b ^ 0 - show 1 * 1 * b ^ 1 = b ^ 1 + 0 * a ^ 1 * b ^ 0 - omega - | succ m => - rw [tsum_shift] - have hcong : tsum m - (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 + 1 - (i + 1))) = - tsum m (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 - i)) := - tsum_congr (fun i hi => by - rw [show m + 1 + 1 - (i + 1) = m + 1 - i by omega]) - have hext : tsum (m + 1) - (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 - i)) = - tsum m (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 - i)) + - cho (m + 1) (m + 2) * a ^ (m + 2) * b ^ (m + 1 - (m + 1)) := rfl - have hz : cho (m + 1) (m + 2) = 0 := cho_eq_zero_of_lt (by omega) - rw [hz, Nat.zero_mul, Nat.zero_mul, Nat.add_zero] at hext - show 1 * 1 * b ^ (m + 2) + - tsum m (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * - b ^ (m + 1 + 1 - (i + 1))) = - b ^ (m + 2) + - tsum (m + 1) (fun i => cho (m + 1) (i + 1) * a ^ (i + 1) * b ^ (m + 1 - i)) - rw [hcong, hext] - omega - rw [hb] - omega - -/-! ## `expNum` as a sum, and the product inequalities -/ - -theorem expNum_eq_tsum (n p q : Nat) : - expNum n p q = tsum n (fun j => ffacAux j (n - j) * p ^ j * q ^ (n - j)) := by - induction n with - | zero => rfl - | succ k ih => - show (k + 1) * q * expNum k p q + p ^ (k + 1) = _ - rw [ih, const_mul_tsum] - have hsum : tsum k (fun j => (k + 1) * q * - (ffacAux j (k - j) * p ^ j * q ^ (k - j))) = - tsum k (fun j => ffacAux j (k + 1 - j) * p ^ j * q ^ (k + 1 - j)) := by - refine tsum_congr (fun j hj => ?_) - have h1 : k + 1 - j = (k - j) + 1 := by omega - rw [h1] - have h2 : ffacAux j (k - j + 1) = (j + (k - j) + 1) * ffacAux j (k - j) := rfl - rw [h2, show j + (k - j) + 1 = k + 1 by omega, Nat.pow_succ] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [hsum] - have hlast : tsum (k + 1) (fun j => ffacAux j (k + 1 - j) * p ^ j * q ^ (k + 1 - j)) = - tsum k (fun j => ffacAux j (k + 1 - j) * p ^ j * q ^ (k + 1 - j)) + - ffacAux (k + 1) (k + 1 - (k + 1)) * p ^ (k + 1) * q ^ (k + 1 - (k + 1)) := rfl - rw [hlast, Nat.sub_self] - show _ = _ + 1 * p ^ (k + 1) * 1 - omega - -theorem mul_pos' {a b : Nat} (ha : 0 < a) (hb : 0 < b) : 0 < a * b := - Nat.mul_pos ha hb - -/-- The convolution coefficient identity behind both product inequalities. -/ -theorem coef_eq {N M i j : Nat} (hi : i ≤ N) (hj : j ≤ M) : - ffacAux i (N - i) * ffacAux j (M - j) * fact (N + M) = - fact N * fact M * (ffacAux (i + j) (N + M - (i + j)) * cho (i + j) i) := by - refine Nat.eq_of_mul_eq_mul_right (mul_pos' (fact_pos i) (fact_pos j)) ?_ - have hL : ffacAux i (N - i) * ffacAux j (M - j) * fact (N + M) * (fact i * fact j) = - (ffacAux i (N - i) * fact i) * ((ffacAux j (M - j) * fact j) * fact (N + M)) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [hL, ffacAux_mul_fact, ffacAux_mul_fact, - show i + (N - i) = N by omega, show j + (M - j) = M by omega] - have hR : fact N * fact M * (ffacAux (i + j) (N + M - (i + j)) * cho (i + j) i) * - (fact i * fact j) = - fact N * (fact M * (ffacAux (i + j) (N + M - (i + j)) * - (cho (i + j) i * (fact i * fact j)))) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [hR, show fact j = fact (i + j - i) by rw [show i + j - i = j by omega], - cho_fact (i + j) i (by omega), ffacAux_mul_fact, - show i + j + (N + M - (i + j)) = N + M by omega] - -theorem tsum_mul_tsum (f g : Nat → Nat) (N M c : Nat) : - tsum N f * tsum M g * c = - tsum N (fun i => tsum M (fun j => f i * (g j * c))) := by - calc tsum N f * tsum M g * c - = tsum N (fun i => f i * (tsum M g * c)) := by - rw [Nat.mul_assoc, tsum_mul_const] - _ = tsum N (fun i => tsum M (fun j => f i * (g j * c))) := by - refine tsum_congr (fun i hi => ?_) - rw [tsum_mul_const, const_mul_tsum] - -/-- Box form of a product of two partial sums (times a constant). -/ -theorem expNum_mul_box (N M p1 p2 q c : Nat) : - expNum N p1 q * expNum M p2 q * c = - tsum N (fun i => tsum M (fun j => - ffacAux i (N - i) * ffacAux j (M - j) * c * - (p1 ^ i * (p2 ^ j * (q ^ (N - i) * q ^ (M - j)))))) := by - rw [expNum_eq_tsum, expNum_eq_tsum, tsum_mul_tsum] - refine tsum_congr (fun i hi => tsum_congr (fun j hj => ?_)) - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - -/-- Second convolution coefficient identity (triangle side, equal scales). -/ -theorem coef_eq2 {K n i : Nat} (hn : n ≤ K) (hi : i ≤ n) : - ffacAux n (K - n) * cho n i * fact K = - ffacAux i (K - i) * ffacAux (n - i) (K - (n - i)) := by - refine Nat.eq_of_mul_eq_mul_right (mul_pos' (fact_pos i) (fact_pos (n - i))) ?_ - have hL : ffacAux n (K - n) * cho n i * fact K * (fact i * fact (n - i)) = - ffacAux n (K - n) * ((cho n i * (fact i * fact (n - i))) * fact K) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [hL, cho_fact n i hi] - have hL2 : ffacAux n (K - n) * (fact n * fact K) = - (ffacAux n (K - n) * fact n) * fact K := by - rw [Nat.mul_assoc] - rw [hL2, ffacAux_mul_fact, show n + (K - n) = K by omega] - have hR : ffacAux i (K - i) * ffacAux (n - i) (K - (n - i)) * (fact i * fact (n - i)) = - (ffacAux i (K - i) * fact i) * (ffacAux (n - i) (K - (n - i)) * fact (n - i)) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [hR, ffacAux_mul_fact, ffacAux_mul_fact, show i + (K - i) = K by omega, - show n - i + (K - (n - i)) = K by omega] - -/-- Triangle form of a partial sum at a sum argument (times a constant). -/ -theorem expNum_add_tri (C p1 p2 q c : Nat) : - expNum C (p1 + p2) q * c = - tsum C (fun n => tsum n (fun i => - ffacAux (i + (n - i)) (C - (i + (n - i))) * cho (i + (n - i)) i * c * - (p1 ^ i * (p2 ^ (n - i) * q ^ (C - (i + (n - i))))))) := by - rw [expNum_eq_tsum, tsum_mul_const] - refine tsum_congr (fun n hn => ?_) - show ffacAux n (C - n) * (p1 + p2) ^ n * q ^ (C - n) * c = _ - rw [add_pow, const_mul_tsum, tsum_mul_const, tsum_mul_const] - refine tsum_congr (fun i hi => ?_) - rw [show i + (n - i) = n by omega] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - -/-- `S_N(p1/q) S_M(p2/q) ≤ S_{N+M}((p1+p2)/q)`, integer-scaled. -/ -theorem prod_le_sum (N M p1 p2 q : Nat) : - expNum N p1 q * expNum M p2 q * fact (N + M) ≤ - expNum (N + M) (p1 + p2) q * (fact N * fact M) := by - rw [expNum_mul_box N M p1 p2 q (fact (N + M)), - expNum_add_tri (N + M) p1 p2 q (fact N * fact M)] - refine Nat.le_trans (tsum_le_tsum fun i hi => tsum_le_tsum fun j hj => - Nat.le_of_eq ?_) - (box_le_tri (fun i j => - ffacAux (i + j) (N + M - (i + j)) * cho (i + j) i * (fact N * fact M) * - (p1 ^ i * (p2 ^ j * q ^ (N + M - (i + j))))) N M) - have hq : q ^ (N - i) * q ^ (M - j) = q ^ (N + M - (i + j)) := by - rw [← Nat.pow_add] - congr 1 - omega - rw [hq, coef_eq hi hj] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - -/-- `S_K((p1+p2)/q) ≤ S_K(p1/q) S_K(p2/q)`, integer-scaled. -/ -theorem sum_le_prod (K p1 p2 q : Nat) : - expNum K (p1 + p2) q * (fact K * q ^ K) ≤ expNum K p1 q * expNum K p2 q := by - rw [expNum_add_tri K p1 p2 q (fact K * q ^ K), - show expNum K p1 q * expNum K p2 q = expNum K p1 q * expNum K p2 q * 1 from - (Nat.mul_one _).symm, - expNum_mul_box K K p1 p2 q 1] - refine Nat.le_trans (Nat.le_of_eq ?_) - (tri_le_box (fun i j => - ffacAux i (K - i) * ffacAux j (K - j) * 1 * - (p1 ^ i * (p2 ^ j * (q ^ (K - i) * q ^ (K - j))))) K) - refine tsum_congr (fun n hn => tsum_congr (fun i hi => ?_)) - rw [show i + (n - i) = n by omega, - show ffacAux i (K - i) * ffacAux (n - i) (K - (n - i)) = - ffacAux n (K - n) * cho n i * fact K from (coef_eq2 hn hi).symm, - show q ^ (K - i) * q ^ (K - (n - i)) = q ^ K * q ^ (K - n) from by - rw [← Nat.pow_add, ← Nat.pow_add] - congr 1 - omega] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm, Nat.mul_one] - -/-! ## Monotonicity and the tail bound -/ - -/-- Cross-scale fraction transitivity: `a/b ≤ c/d ≤ e/f → a/b ≤ e/f`. -/ -theorem div_le_trans {a b c d e f : Nat} (hd : 0 < d) - (h1 : a * d ≤ c * b) (h2 : c * f ≤ e * d) : a * f ≤ e * b := by - refine Nat.le_of_mul_le_mul_right ?_ hd - calc a * f * d = a * d * f := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - _ ≤ c * b * f := Nat.mul_le_mul_right f h1 - _ = c * f * b := by simp only [Nat.mul_comm, Nat.mul_left_comm] - _ ≤ e * d * b := Nat.mul_le_mul_right b h2 - _ = e * b * d := by simp only [Nat.mul_comm, Nat.mul_left_comm] - -theorem expNum_step_le (n p q : Nat) : - (n + 1) * q * expNum n p q ≤ expNum (n + 1) p q := by - show _ ≤ (n + 1) * q * expNum n p q + p ^ (n + 1) - omega - -/-- `S_n ≤ S_m` for `n ≤ m`, cross-scaled. -/ -theorem expNum_mono_N {p q : Nat} {n m : Nat} (h : n ≤ m) : - expNum n p q * (fact m * q ^ m) ≤ expNum m p q * (fact n * q ^ n) := by - have key : ∀ d, expNum n p q * (fact (n + d) * q ^ (n + d)) ≤ - expNum (n + d) p q * (fact n * q ^ n) := by - intro d - induction d with - | zero => exact Nat.le_refl _ - | succ k ih => - have hf : fact (n + (k + 1)) = (n + k + 1) * fact (n + k) := rfl - have hp : q ^ (n + (k + 1)) = q ^ (n + k) * q := by - rw [show n + (k + 1) = (n + k) + 1 by omega, Nat.pow_succ] - have e1 : expNum n p q * (fact (n + (k + 1)) * q ^ (n + (k + 1))) = - (n + k + 1) * q * (expNum n p q * (fact (n + k) * q ^ (n + k))) := by - rw [hf, hp] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [e1] - have step1 : (n + k + 1) * q * (expNum n p q * (fact (n + k) * q ^ (n + k))) ≤ - (n + k + 1) * q * (expNum (n + k) p q * (fact n * q ^ n)) := - Nat.mul_le_mul_left _ ih - have e2 : (n + k + 1) * q * (expNum (n + k) p q * (fact n * q ^ n)) = - (n + k + 1) * q * expNum (n + k) p q * (fact n * q ^ n) := by - simp only [Nat.mul_assoc] - have step2 : (n + k + 1) * q * expNum (n + k) p q * (fact n * q ^ n) ≤ - expNum (n + k + 1) p q * (fact n * q ^ n) := - Nat.mul_le_mul_right _ (expNum_step_le (n + k) p q) - rw [show n + (k + 1) = n + k + 1 from rfl] - omega - have hkey := key (m - n) - rw [show n + (m - n) = m by omega] at hkey - exact hkey - -/-- Argument monotonicity: `p/q ≤ p'/q'` gives `S_n(p/q) ≤ S_n(p'/q')`. -/ -theorem expNum_arg_mono {p q p' q' : Nat} (h : p * q' ≤ p' * q) (n : Nat) : - expNum n p q * q' ^ n ≤ expNum n p' q' * q ^ n := by - induction n with - | zero => exact Nat.le_refl _ - | succ k ih => - show ((k + 1) * q * expNum k p q + p ^ (k + 1)) * q' ^ (k + 1) ≤ - ((k + 1) * q' * expNum k p' q' + p' ^ (k + 1)) * q ^ (k + 1) - rw [Nat.add_mul ((k + 1) * q * expNum k p q) (p ^ (k + 1)) (q' ^ (k + 1)), - Nat.add_mul ((k + 1) * q' * expNum k p' q') (p' ^ (k + 1)) (q ^ (k + 1))] - have h1 : (k + 1) * q * expNum k p q * q' ^ (k + 1) ≤ - (k + 1) * q' * expNum k p' q' * q ^ (k + 1) := by - have e1 : (k + 1) * q * expNum k p q * q' ^ (k + 1) = - (k + 1) * (q * q') * (expNum k p q * q' ^ k) := by - rw [Nat.pow_succ] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - have e2 : (k + 1) * q' * expNum k p' q' * q ^ (k + 1) = - (k + 1) * (q * q') * (expNum k p' q' * q ^ k) := by - rw [Nat.pow_succ] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [e1, e2] - exact Nat.mul_le_mul_left _ ih - have h2 : p ^ (k + 1) * q' ^ (k + 1) ≤ p' ^ (k + 1) * q ^ (k + 1) := by - rw [← Nat.mul_pow, ← Nat.mul_pow] - exact Nat.pow_le_pow_left h (k + 1) - omega - -theorem expNum_zero_arg (n q : Nat) : expNum n 0 q = fact n * q ^ n := by - induction n with - | zero => rfl - | succ k ih => - show (k + 1) * q * expNum k 0 q + 0 ^ (k + 1) = fact (k + 1) * q ^ (k + 1) - rw [ih, show (0 : Nat) ^ (k + 1) = 0 by rw [Nat.zero_pow (by omega)], - show fact (k + 1) = (k + 1) * fact k from rfl, Nat.pow_succ] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - omega - -/-- One step of the decreasing tail potential -`B_M = (E_M (M+1) q + 2 p^(M+1)) / ((M+1)! q^(M+1))`, for `2p ≤ (M+2)q`. -/ -theorem tail_potential_step {p q M : Nat} (hM : 2 * p ≤ (M + 2) * q) : - expNum (M + 1) p q * ((M + 2) * q) + 2 * p ^ (M + 2) ≤ - (expNum M p q * ((M + 1) * q) + 2 * p ^ (M + 1)) * ((M + 2) * q) := by - have hE : expNum (M + 1) p q = (M + 1) * q * expNum M p q + p ^ (M + 1) := rfl - have hp2 : p ^ (M + 2) = p * p ^ (M + 1) := by - rw [show M + 2 = (M + 1) + 1 by omega, Nat.pow_succ, Nat.mul_comm] - have hkey : 2 * (p * p ^ (M + 1)) ≤ (M + 2) * q * p ^ (M + 1) := by - rw [← Nat.mul_assoc] - exact Nat.mul_le_mul_right _ hM - have eL : expNum (M + 1) p q * ((M + 2) * q) + 2 * p ^ (M + 2) = - expNum M p q * ((M + 1) * q) * ((M + 2) * q) + - (M + 2) * q * p ^ (M + 1) + 2 * (p * p ^ (M + 1)) := by - rw [hE, hp2, Nat.add_mul ((M + 1) * q * expNum M p q) (p ^ (M + 1)) ((M + 2) * q)] - have a1 : (M + 1) * q * expNum M p q * ((M + 2) * q) = - expNum M p q * ((M + 1) * q) * ((M + 2) * q) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - have a2 : p ^ (M + 1) * ((M + 2) * q) = (M + 2) * q * p ^ (M + 1) := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - omega - have eR : (expNum M p q * ((M + 1) * q) + 2 * p ^ (M + 1)) * ((M + 2) * q) = - expNum M p q * ((M + 1) * q) * ((M + 2) * q) + - 2 * ((M + 2) * q * p ^ (M + 1)) := by - rw [Nat.add_mul (expNum M p q * ((M + 1) * q)) (2 * p ^ (M + 1)) ((M + 2) * q)] - have a3 : 2 * p ^ (M + 1) * ((M + 2) * q) = 2 * ((M + 2) * q * p ^ (M + 1)) := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - omega - omega - -/-- All partial sums beyond `K` stay under the `K`-th tail potential: -`S_M ≤ B_K` for `M ≥ K` when `2p ≤ (K+2)q`. -/ -theorem tail_bound {p q K : Nat} (hq : 0 < q) (hK : 2 * p ≤ (K + 2) * q) : - ∀ M, expNum M p q * (fact (K + 1) * q ^ (K + 1)) ≤ - (expNum K p q * ((K + 1) * q) + 2 * p ^ (K + 1)) * (fact M * q ^ M) := by - -- denominators are positive - have hden : ∀ j, 0 < fact j * q ^ j := fun j => - mul_pos' (fact_pos j) (Nat.pow_pos hq) - -- B_(K+d) ≤ B_K by chaining the potential step - have hB : ∀ d, - (expNum (K + d) p q * ((K + d + 1) * q) + 2 * p ^ (K + d + 1)) * - (fact (K + 1) * q ^ (K + 1)) ≤ - (expNum K p q * ((K + 1) * q) + 2 * p ^ (K + 1)) * - (fact (K + d + 1) * q ^ (K + d + 1)) := by - intro d - induction d with - | zero => exact Nat.le_refl _ - | succ e ih => - have hstep := tail_potential_step (p := p) (q := q) (M := K + e) - (by have : (K + 2) * q ≤ (K + e + 2) * q := Nat.mul_le_mul_right q (by omega) - omega) - -- B_(K+e+1) ≤ B_(K+e) cross-scaled, then transitivity with ih - have hcross : (expNum (K + e + 1) p q * ((K + e + 2) * q) + 2 * p ^ (K + e + 2)) * - (fact (K + e + 1) * q ^ (K + e + 1)) ≤ - (expNum (K + e) p q * ((K + e + 1) * q) + 2 * p ^ (K + e + 1)) * - (fact (K + e + 2) * q ^ (K + e + 2)) := by - have hf : fact (K + e + 2) = (K + e + 2) * fact (K + e + 1) := rfl - have hp : q ^ (K + e + 2) = q ^ (K + e + 1) * q := by - rw [show K + e + 2 = (K + e + 1) + 1 by omega, Nat.pow_succ] - rw [hf, hp] - have e1 : (expNum (K + e) p q * ((K + e + 1) * q) + 2 * p ^ (K + e + 1)) * - ((K + e + 2) * fact (K + e + 1) * (q ^ (K + e + 1) * q)) = - ((expNum (K + e) p q * ((K + e + 1) * q) + 2 * p ^ (K + e + 1)) * - ((K + e + 2) * q)) * (fact (K + e + 1) * q ^ (K + e + 1)) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [e1] - exact Nat.mul_le_mul_right _ (by - rw [show K + e + 1 + 1 = K + e + 2 by omega] at hstep - exact hstep) - rw [show K + (e + 1) = K + e + 1 by omega] - exact div_le_trans (hden (K + e + 1)) hcross ih - intro M - rcases Nat.lt_or_ge M K with hlt | hge - · -- below K: S_M ≤ S_K ≤ B_K - have hmono := expNum_mono_N (p := p) (q := q) (Nat.le_of_lt hlt) - have hSK : expNum K p q * (fact (K + 1) * q ^ (K + 1)) ≤ - (expNum K p q * ((K + 1) * q) + 2 * p ^ (K + 1)) * (fact K * q ^ K) := by - have e1 : expNum K p q * (fact (K + 1) * q ^ (K + 1)) = - expNum K p q * ((K + 1) * q) * (fact K * q ^ K) := by - rw [show fact (K + 1) = (K + 1) * fact K from rfl, Nat.pow_succ] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [e1] - exact Nat.mul_le_mul_right _ (by omega) - exact div_le_trans (hden K) hmono hSK - · -- at or above K: S_M ≤ B_M ≤ B_K - have hSM : expNum M p q * (fact (M + 1) * q ^ (M + 1)) ≤ - (expNum M p q * ((M + 1) * q) + 2 * p ^ (M + 1)) * (fact M * q ^ M) := by - have e1 : expNum M p q * (fact (M + 1) * q ^ (M + 1)) = - expNum M p q * ((M + 1) * q) * (fact M * q ^ M) := by - rw [show fact (M + 1) = (M + 1) * fact M from rfl, Nat.pow_succ] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - rw [e1] - exact Nat.mul_le_mul_right _ (by omega) - have hBM := hB (M - K) - rw [show K + (M - K) = M by omega] at hBM - exact div_le_trans (hden (M + 1)) hSM hBM - -/-! ## Exponential caps - -`capUB p q y w` says `e^(p/q) ≤ y/w` (every partial sum is bounded); -`capLB p q y w` says `e^(p/q) ≥ y/w` (some partial sum already reaches it). -These four-`Nat` relations are the interface the floor-specification -assembly uses; the lemmas below are the surrogates for -`e^(a+b) = e^a e^b` and monotonicity. --/ - -def capUB (p q y w : Nat) : Prop := ∀ n, expNum n p q * w ≤ y * (fact n * q ^ n) - -def capLB (p q y w : Nat) : Prop := ∃ n, y * (fact n * q ^ n) ≤ expNum n p q * w - -theorem capUB_mul {p1 p2 q y1 w1 y2 w2 : Nat} (hq : 0 < q) - (h1 : capUB p1 q y1 w1) (h2 : capUB p2 q y2 w2) : - capUB (p1 + p2) q (y1 * y2) (w1 * w2) := by - intro n - have hd : 0 < fact n * q ^ n := mul_pos' (fact_pos n) (Nat.pow_pos hq) - refine Nat.le_of_mul_le_mul_right ?_ hd - calc expNum n (p1 + p2) q * (w1 * w2) * (fact n * q ^ n) - = expNum n (p1 + p2) q * (fact n * q ^ n) * (w1 * w2) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ expNum n p1 q * expNum n p2 q * (w1 * w2) := - Nat.mul_le_mul_right _ (sum_le_prod n p1 p2 q) - _ = (expNum n p1 q * w1) * (expNum n p2 q * w2) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (y1 * (fact n * q ^ n)) * (y2 * (fact n * q ^ n)) := - Nat.mul_le_mul (h1 n) (h2 n) - _ = y1 * y2 * (fact n * q ^ n) * (fact n * q ^ n) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - -theorem capLB_mul {p1 p2 q y1 w1 y2 w2 : Nat} - (h1 : capLB p1 q y1 w1) (h2 : capLB p2 q y2 w2) : - capLB (p1 + p2) q (y1 * y2) (w1 * w2) := by - obtain ⟨n1, e1⟩ := h1 - obtain ⟨n2, e2⟩ := h2 - refine ⟨n1 + n2, ?_⟩ - have hd : 0 < fact n1 * fact n2 := mul_pos' (fact_pos n1) (fact_pos n2) - refine Nat.le_of_mul_le_mul_right ?_ hd - calc y1 * y2 * (fact (n1 + n2) * q ^ (n1 + n2)) * (fact n1 * fact n2) - = (y1 * (fact n1 * q ^ n1)) * (y2 * (fact n2 * q ^ n2)) * fact (n1 + n2) := by - rw [show q ^ (n1 + n2) = q ^ n1 * q ^ n2 from Nat.pow_add q n1 n2] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (expNum n1 p1 q * w1) * (expNum n2 p2 q * w2) * fact (n1 + n2) := - Nat.mul_le_mul_right _ (Nat.mul_le_mul e1 e2) - _ = expNum n1 p1 q * expNum n2 p2 q * fact (n1 + n2) * (w1 * w2) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ expNum (n1 + n2) (p1 + p2) q * (fact n1 * fact n2) * (w1 * w2) := - Nat.mul_le_mul_right _ (prod_le_sum n1 n2 p1 p2 q) - _ = expNum (n1 + n2) (p1 + p2) q * (w1 * w2) * (fact n1 * fact n2) := by - simp only [Nat.mul_assoc, Nat.mul_comm] - -/-- Quotient mover: from `e^(a+b) ≤ C/W` and `e^b ≥ G/V`, get `e^a ≤ CV/(WG)`. -/ -theorem capUB_cancel {pa pb q C W G V : Nat} (hq : 0 < q) - (hsum : capUB (pa + pb) q C W) (hb : capLB pb q G V) : - capUB pa q (C * V) (W * G) := by - intro n - obtain ⟨m, hm⟩ := hb - have hd : 0 < fact m * q ^ m * fact (n + m) := - mul_pos' (mul_pos' (fact_pos m) (Nat.pow_pos hq)) (fact_pos (n + m)) - refine Nat.le_of_mul_le_mul_right ?_ hd - calc expNum n pa q * (W * G) * (fact m * q ^ m * fact (n + m)) - = (G * (fact m * q ^ m)) * (expNum n pa q * W * fact (n + m)) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (expNum m pb q * V) * (expNum n pa q * W * fact (n + m)) := - Nat.mul_le_mul_right _ hm - _ = (expNum n pa q * expNum m pb q * fact (n + m)) * (W * V) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (expNum (n + m) (pa + pb) q * (fact n * fact m)) * (W * V) := - Nat.mul_le_mul_right _ (prod_le_sum n m pa pb q) - _ = (expNum (n + m) (pa + pb) q * W) * (fact n * fact m * V) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (C * (fact (n + m) * q ^ (n + m))) * (fact n * fact m * V) := - Nat.mul_le_mul_right _ (hsum (n + m)) - _ = C * V * (fact n * q ^ n) * (fact m * q ^ m * fact (n + m)) := by - rw [show q ^ (n + m) = q ^ n * q ^ m from Nat.pow_add q n m] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - -theorem capUB_one (q : Nat) : capUB 0 q 1 1 := by - intro n - rw [expNum_zero_arg] - omega - -theorem capLB_one (q : Nat) : capLB 0 q 1 1 := - ⟨0, by rw [expNum_zero_arg]; omega⟩ - -theorem capUB_pow {p q y w : Nat} (hq : 0 < q) (h : capUB p q y w) : - ∀ k, capUB (k * p) q (y ^ k) (w ^ k) := by - intro k - induction k with - | zero => - show capUB (0 * p) q (y ^ 0) (w ^ 0) - rw [Nat.zero_mul] - exact capUB_one q - | succ j ih => - have := capUB_mul hq ih h - rw [(Nat.succ_mul j p).symm] at this - rw [Nat.pow_succ, Nat.pow_succ] - exact this - -theorem capLB_pow {p q y w : Nat} (h : capLB p q y w) : - ∀ k, capLB (k * p) q (y ^ k) (w ^ k) := by - intro k - induction k with - | zero => - show capLB (0 * p) q (y ^ 0) (w ^ 0) - rw [Nat.zero_mul] - exact capLB_one q - | succ j ih => - have := capLB_mul ih h - rw [(Nat.succ_mul j p).symm] at this - rw [Nat.pow_succ, Nat.pow_succ] - exact this - -/-- Transport an upper cap down a smaller argument: `p/q ≤ p'/q'`. -/ -theorem capUB_arg {p q p' q' y w : Nat} (hq' : 0 < q') (h : p * q' ≤ p' * q) - (hub : capUB p' q' y w) : capUB p q y w := by - intro n - have hd : 0 < q' ^ n := Nat.pow_pos hq' - refine Nat.le_of_mul_le_mul_right ?_ hd - calc expNum n p q * w * q' ^ n - = (expNum n p q * q' ^ n) * w := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (expNum n p' q' * q ^ n) * w := - Nat.mul_le_mul_right _ (expNum_arg_mono h n) - _ = (expNum n p' q' * w) * q ^ n := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (y * (fact n * q' ^ n)) * q ^ n := - Nat.mul_le_mul_right _ (hub n) - _ = y * (fact n * q ^ n) * q' ^ n := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - -/-- Transport a lower cap up a larger argument: `p'/q' ≤ p/q`. -/ -theorem capLB_arg {p q p' q' y w : Nat} (hq' : 0 < q') (h : p' * q ≤ p * q') - (hlb : capLB p' q' y w) : capLB p q y w := by - obtain ⟨n, hn⟩ := hlb - refine ⟨n, ?_⟩ - have hd : 0 < q' ^ n := Nat.pow_pos hq' - refine Nat.le_of_mul_le_mul_right ?_ hd - calc y * (fact n * q ^ n) * q' ^ n - = (y * (fact n * q' ^ n)) * q ^ n := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (expNum n p' q' * w) * q ^ n := - Nat.mul_le_mul_right _ hn - _ = (expNum n p' q' * q ^ n) * w := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - _ ≤ (expNum n p q * q' ^ n) * w := - Nat.mul_le_mul_right _ (expNum_arg_mono h n) - _ = expNum n p q * w * q' ^ n := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - -/-- Weaken an upper cap to a looser target: `y/w ≤ y'/w'`. -/ -theorem capUB_weaken {p q y w y' w' : Nat} (hw : 0 < w) - (h : capUB p q y w) (hyy : y * w' ≤ y' * w) : capUB p q y' w' := by - intro n - refine Nat.le_of_mul_le_mul_right ?_ hw - calc expNum n p q * w' * w = expNum n p q * w * w' := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - _ ≤ y * (fact n * q ^ n) * w' := Nat.mul_le_mul_right _ (h n) - _ = y * w' * (fact n * q ^ n) := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ y' * w * (fact n * q ^ n) := Nat.mul_le_mul_right _ hyy - _ = y' * (fact n * q ^ n) * w := by - simp only [Nat.mul_assoc, Nat.mul_comm] - -/-- Strengthen a lower cap to a looser target: `y'/w' ≤ y/w`. -/ -theorem capLB_weaken {p q y w y' w' : Nat} (hw : 0 < w) - (h : capLB p q y w) (hyy : y' * w ≤ y * w') : capLB p q y' w' := by - obtain ⟨n, hn⟩ := h - refine ⟨n, ?_⟩ - refine Nat.le_of_mul_le_mul_right ?_ hw - calc y' * (fact n * q ^ n) * w = y' * w * (fact n * q ^ n) := by - simp only [Nat.mul_assoc, Nat.mul_comm] - _ ≤ y * w' * (fact n * q ^ n) := Nat.mul_le_mul_right _ hyy - _ = y * (fact n * q ^ n) * w' := by - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] - _ ≤ expNum n p q * w * w' := Nat.mul_le_mul_right _ hn - _ = expNum n p q * w' * w := by - simp only [Nat.mul_comm, Nat.mul_left_comm] - -/-- Turn one evaluated partial sum plus the geometric tail into a full upper -cap: with `2p ≤ (K+2)q` and -`(E_K (K+1) q + 2 p^(K+1)) w ≤ y (K+1)! q^(K+1)`, conclude `e^(p/q) ≤ y/w`. -/ -theorem capUB_of_partial {p q K y w : Nat} (hq : 0 < q) (hK : 2 * p ≤ (K + 2) * q) - (h : (expNum K p q * ((K + 1) * q) + 2 * p ^ (K + 1)) * w ≤ - y * (fact (K + 1) * q ^ (K + 1))) : capUB p q y w := by - intro M - exact div_le_trans (mul_pos' (fact_pos (K + 1)) (Nat.pow_pos hq)) - (tail_bound hq hK M) h - -end LnExp diff --git a/formal/ln/LnProof/LnProof/Foundation/Kronecker.lean b/formal/ln/LnProof/LnProof/Foundation/Kronecker.lean deleted file mode 100644 index e0fa68eb1..000000000 --- a/formal/ln/LnProof/LnProof/Foundation/Kronecker.lean +++ /dev/null @@ -1,272 +0,0 @@ -import LnProof.Foundation.ShiftCert - -/-! -# Polynomial identity testing by Kronecker evaluation - -Two integer polynomials with ℓ1-norm below half of `2^B` agree everywhere -as soon as they agree at the single point `2^B`: the evaluation is the -balanced radix-`2^B` digit string of the coefficient list, which is -unique. This turns the certificate-vs-literal equalities — whose direct -list-equality decides force the whole construction through the kernel's -per-coefficient evaluation overhead — into one closed integer-arithmetic -comparison plus a symbolic ℓ1 bound. --/ - -namespace LnPoly - -/-- ℓ1 norm of the coefficient list. -/ -def polyL1 : List Int → Nat - | [] => 0 - | c :: cs => c.natAbs + polyL1 cs - -theorem pow2_cast (B : Nat) : ((2 : Int) ^ B) = ((2 ^ B : Nat) : Int) := by - rw [Int.natCast_pow] - rfl - -/-- A multiple of `2^B` strictly inside `(-2^B, 2^B)` is zero. -/ -theorem eq_zero_of_mul_pow {B : Nat} {d k : Int} (hd : d = 2 ^ B * k) - (h1 : -(2 ^ B) < d) (h2 : d < 2 ^ B) : d = 0 ∧ k = 0 := by - have hP : (0 : Int) < 2 ^ B := by - have e : ((2 : Int) ^ B) = ((2 ^ B : Nat) : Int) := by - rw [Int.natCast_pow] - rfl - have h2 : 0 < 2 ^ B := Nat.pow_pos (by omega) - omega - rcases Int.lt_or_le k 0 with hk | hk - · exfalso - have h1k : k ≤ -1 := by omega - have := mul_le_mul_left_nonneg h1k (by omega : (0 : Int) ≤ 2 ^ B) - have e : (2 : Int) ^ B * (-1) = -(2 ^ B) := by - rw [Int.mul_neg, Int.mul_one] - omega - rcases Int.lt_or_le 0 k with hk2 | hk2 - · exfalso - have h1k : 1 ≤ k := by omega - have := mul_le_mul_left_nonneg h1k (by omega : (0 : Int) ≤ 2 ^ B) - have e : (2 : Int) ^ B * 1 = 2 ^ B := Int.mul_one _ - omega - · have hk0 : k = 0 := by omega - subst hk0 - rw [Int.mul_zero] at hd - exact ⟨hd, rfl⟩ - -/-- Rewrite `(2 : Int) ^ n` through `Nat.pow`. The `Int` monoid power is -`npowRec` (a linear chain of multiplications the kernel does not accelerate), -whereas `Nat.pow` is a GMP-backed kernel primitive. Rewriting with this before -a `decide +kernel` that evaluates a Kronecker point keeps the base a single -cheap literal instead of an `n`-step reduction recomputed at every use. -/ -theorem int_two_pow (n : Nat) : (2 : Int) ^ n = ((2 ^ n : Nat) : Int) := - (Int.natCast_pow 2 n).symm - -/-- Polynomials with small ℓ1 norm that agree at `2^B` agree everywhere. -/ -theorem evalPoly_ext {B : Nat} : ∀ (p q : List Int), - polyL1 p * 2 < 2 ^ B → polyL1 q * 2 < 2 ^ B → - evalPoly p ((2 : Int) ^ B) = evalPoly q ((2 : Int) ^ B) → - ∀ x : Int, evalPoly p x = evalPoly q x := by - intro p - induction p with - | nil => - intro q - induction q with - | nil => intro _ _ _ _; rfl - | cons b q' ihq => - intro hp hq he x - -- 0 = b + 2^B e' forces b = 0 and e' = 0 - show evalPoly ([] : List Int) x = b + x * evalPoly q' x - have he' : (0 : Int) = b + 2 ^ B * evalPoly q' ((2 : Int) ^ B) := he - simp only [polyL1] at hq - have hb : b.natAbs * 2 < 2 ^ B ∧ polyL1 q' * 2 < 2 ^ B := by omega - have hbI : -(2 ^ B : Int) < b ∧ (b : Int) < 2 ^ B := by - rw [pow2_cast B] - omega - obtain ⟨hb0, hk0⟩ := eq_zero_of_mul_pow (B := B) (d := -b) - (k := evalPoly q' ((2 : Int) ^ B)) (by omega) (by omega) (by omega) - have htail := ihq hp hb.2 (by - show (0 : Int) = evalPoly q' ((2 : Int) ^ B) - omega) x - show (0 : Int) = b + x * evalPoly q' x - have : evalPoly ([] : List Int) x = (0 : Int) := rfl - rw [this] at htail - rw [← htail] - omega - | cons a p' ihp => - intro q - match q with - | [] => - intro hp hq he x - have he' : a + 2 ^ B * evalPoly p' ((2 : Int) ^ B) = (0 : Int) := he - simp only [polyL1] at hp - have ha : a.natAbs * 2 < 2 ^ B ∧ polyL1 p' * 2 < 2 ^ B := by omega - have haI : -(2 ^ B : Int) < a ∧ (a : Int) < 2 ^ B := by - rw [pow2_cast B] - omega - obtain ⟨ha0, hk0⟩ := eq_zero_of_mul_pow (B := B) (d := -a) - (k := evalPoly p' ((2 : Int) ^ B)) (by omega) (by omega) (by omega) - have htail := ihp [] ha.2 hq (by - show evalPoly p' ((2 : Int) ^ B) = (0 : Int) - omega) x - show a + x * evalPoly p' x = (0 : Int) - have h0 : evalPoly ([] : List Int) x = (0 : Int) := rfl - rw [h0] at htail - rw [htail] - omega - | b :: q' => - intro hp hq he x - have he' : a + 2 ^ B * evalPoly p' ((2 : Int) ^ B) = - b + 2 ^ B * evalPoly q' ((2 : Int) ^ B) := he - simp only [polyL1] at hp hq - have hb : a.natAbs * 2 < 2 ^ B ∧ polyL1 p' * 2 < 2 ^ B ∧ - b.natAbs * 2 < 2 ^ B ∧ polyL1 q' * 2 < 2 ^ B := by omega - have habI : -(2 ^ B : Int) < a - b ∧ (a - b : Int) < 2 ^ B := by - rw [pow2_cast B] - omega - have hd : a - b = 2 ^ B * (evalPoly q' ((2 : Int) ^ B) - - evalPoly p' ((2 : Int) ^ B)) := by - have e := Int.mul_sub ((2 : Int) ^ B) (evalPoly q' ((2 : Int) ^ B)) - (evalPoly p' ((2 : Int) ^ B)) - generalize hE1 : (2 : Int) ^ B * evalPoly p' ((2 : Int) ^ B) = E1 at he' e - generalize hE2 : (2 : Int) ^ B * evalPoly q' ((2 : Int) ^ B) = E2 at he' e - omega - obtain ⟨hab0, hk0⟩ := eq_zero_of_mul_pow (B := B) hd habI.1 habI.2 - have htail := ihp q' hb.2.1 hb.2.2.2 (by omega) x - show a + x * evalPoly p' x = b + x * evalPoly q' x - rw [htail] - omega - -theorem eval01 (x : Int) : evalPoly ([0, 1] : List Int) x = x := by - show (0 : Int) + x * (1 + x * 0) = x - omega - -/-! ## ℓ1 bounds through the polynomial operations -/ - -theorem polyL1_polyAdd : ∀ (p q : List Int), polyL1 (polyAdd p q) ≤ polyL1 p + polyL1 q := by - intro p - induction p with - | nil => - intro q - simp [polyAdd, polyL1] - | cons a p ih => - intro q - match q with - | [] => - show polyL1 (a :: p) ≤ polyL1 (a :: p) + polyL1 ([] : List Int) - simp only [polyL1] - omega - | b :: q => - show (a + b).natAbs + polyL1 (polyAdd p q) ≤ - (a.natAbs + polyL1 p) + (b.natAbs + polyL1 q) - have h1 := ih q - have h2 := Int.natAbs_add_le a b - omega - -theorem polyL1_polyScale (a : Int) : ∀ (p : List Int), - polyL1 (polyScale a p) ≤ a.natAbs * polyL1 p := by - intro p - induction p with - | nil => exact Nat.le_refl _ - | cons c cs ih => - show (a * c).natAbs + polyL1 (polyScale a cs) ≤ a.natAbs * (c.natAbs + polyL1 cs) - rw [Int.natAbs_mul] - have hd : a.natAbs * (c.natAbs + polyL1 cs) = - a.natAbs * c.natAbs + a.natAbs * polyL1 cs := Nat.mul_add _ _ _ - generalize hg1 : a.natAbs * c.natAbs = X at * - generalize hg2 : a.natAbs * polyL1 cs = Y at * - omega - -theorem polyL1_polyMulX (p : List Int) : polyL1 (polyMulX p) = polyL1 p := by - show (0 : Int).natAbs + polyL1 p = polyL1 p - omega - -theorem polyL1_polyNeg : ∀ (p : List Int), polyL1 (polyNeg p) = polyL1 p := by - intro p - induction p with - | nil => rfl - | cons c cs ih => - show (-c).natAbs + polyL1 (polyNeg cs) = c.natAbs + polyL1 cs - rw [Int.natAbs_neg, ih] - -theorem polyL1_polyMul : ∀ (p q : List Int), polyL1 (polyMul p q) ≤ polyL1 p * polyL1 q := by - intro p - induction p with - | nil => - intro q - show polyL1 ([] : List Int) ≤ polyL1 ([] : List Int) * polyL1 q - simp only [polyL1] - omega - | cons a p ih => - intro q - show polyL1 (polyAdd (polyScale a q) (polyMulX (polyMul p q))) ≤ - (a.natAbs + polyL1 p) * polyL1 q - have h1 := polyL1_polyAdd (polyScale a q) (polyMulX (polyMul p q)) - have h2 := polyL1_polyScale a q - have h3 := polyL1_polyMulX (polyMul p q) - have h4 := ih q - have hd : (a.natAbs + polyL1 p) * polyL1 q = - a.natAbs * polyL1 q + polyL1 p * polyL1 q := Nat.add_mul _ _ _ - generalize hg1 : a.natAbs * polyL1 q = X at * - generalize hg2 : polyL1 p * polyL1 q = Y at * - omega - -theorem polyL1_polyPow (p : List Int) : ∀ (k : Nat), - polyL1 (polyPow p k) ≤ polyL1 p ^ k := by - intro k - induction k with - | zero => - show (1 : Int).natAbs + polyL1 ([] : List Int) ≤ 1 - decide - | succ n ih => - show polyL1 (polyMul p (polyPow p n)) ≤ polyL1 p ^ (n + 1) - have h1 := polyL1_polyMul p (polyPow p n) - have h2 : polyL1 p ^ (n + 1) = polyL1 p ^ n * polyL1 p := Nat.pow_succ _ _ - have h3 : polyL1 p * polyL1 (polyPow p n) ≤ polyL1 p * polyL1 p ^ n := - Nat.mul_le_mul_left _ ih - have h4 : polyL1 p * polyL1 p ^ n = polyL1 p ^ n * polyL1 p := Nat.mul_comm _ _ - generalize hg1 : polyL1 p * polyL1 (polyPow p n) = X at * - generalize hg2 : polyL1 p * polyL1 p ^ n = Y at * - generalize hg3 : polyL1 p ^ n * polyL1 p = Z at * - omega - -theorem polyL1_expPolyNum (tn td : List Int) : ∀ (k : Nat), - polyL1 (expPolyNum tn td k) ≤ LnExp.expNum k (polyL1 tn) (polyL1 td) := by - intro k - induction k with - | zero => - show (1 : Int).natAbs + polyL1 ([] : List Int) ≤ 1 - decide - | succ n ih => - show polyL1 (polyAdd (polyScale ((n : Int) + 1) (polyMul td (expPolyNum tn td n))) - (polyPow tn (n + 1))) ≤ - (n + 1) * polyL1 td * LnExp.expNum n (polyL1 tn) (polyL1 td) + - polyL1 tn ^ (n + 1) - have h1 := polyL1_polyAdd (polyScale ((n : Int) + 1) - (polyMul td (expPolyNum tn td n))) (polyPow tn (n + 1)) - have h2 := polyL1_polyScale ((n : Int) + 1) (polyMul td (expPolyNum tn td n)) - have h3 := polyL1_polyMul td (expPolyNum tn td n) - have h4 := polyL1_polyPow tn (n + 1) - have hna : ((n : Int) + 1).natAbs = n + 1 := by omega - rw [hna] at h2 - have h5 : (n + 1) * polyL1 (polyMul td (expPolyNum tn td n)) ≤ - (n + 1) * (polyL1 td * polyL1 (expPolyNum tn td n)) := - Nat.mul_le_mul_left _ h3 - have h6 : polyL1 td * polyL1 (expPolyNum tn td n) ≤ - polyL1 td * LnExp.expNum n (polyL1 tn) (polyL1 td) := - Nat.mul_le_mul_left _ ih - have h7 : (n + 1) * (polyL1 td * polyL1 (expPolyNum tn td n)) ≤ - (n + 1) * (polyL1 td * LnExp.expNum n (polyL1 tn) (polyL1 td)) := - Nat.mul_le_mul_left _ h6 - have h8 : (n + 1) * (polyL1 td * LnExp.expNum n (polyL1 tn) (polyL1 td)) = - (n + 1) * polyL1 td * LnExp.expNum n (polyL1 tn) (polyL1 td) := - (Nat.mul_assoc _ _ _).symm - generalize hg1 : polyL1 (polyScale ((n : Int) + 1) - (polyMul td (expPolyNum tn td n))) = A at * - generalize hg2 : (n + 1) * polyL1 (polyMul td (expPolyNum tn td n)) = C at * - generalize hg3 : (n + 1) * (polyL1 td * polyL1 (expPolyNum tn td n)) = D at * - generalize hg4 : (n + 1) * (polyL1 td * LnExp.expNum n (polyL1 tn) (polyL1 td)) = E at * - generalize hg5 : (n + 1) * polyL1 td * LnExp.expNum n (polyL1 tn) (polyL1 td) = F at * - generalize hg6 : polyL1 (polyPow tn (n + 1)) = G at * - generalize hg7 : polyL1 tn ^ (n + 1) = H at * - generalize hg8 : polyL1 (polyAdd (polyScale ((n : Int) + 1) - (polyMul td (expPolyNum tn td n))) (polyPow tn (n + 1))) = T at * - omega - -end LnPoly diff --git a/formal/ln/LnProof/LnProof/Foundation/KroneckerShift.lean b/formal/ln/LnProof/LnProof/Foundation/KroneckerShift.lean deleted file mode 100644 index 710f40894..000000000 --- a/formal/ln/LnProof/LnProof/Foundation/KroneckerShift.lean +++ /dev/null @@ -1,288 +0,0 @@ -import LnProof.Foundation.Kronecker - -/-! -# Packed Taylor shifts for the cell walks - -The cell checker Taylor-shifts each certificate literal with a -Kronecker-substitution homomorphism: the shifted polynomial is *computed* -inside the decide as a handful of GMP-scale operations on sign-split packed -naturals (`kShiftHorner`, untrusted), then *certified* by one evaluation -identity at `2^B` through `evalPoly_ext`. The packed computation -needs no correctness lemmas: if it produced anything other than the true -shift, the evaluation identity in the checker would fail. The remaining -bound is an ℓ1 bound for true shifts, carried by `aeval`, the -absolute-value evaluation. --/ - -namespace LnPoly - -/-- Kronecker digit width shared by the cell-walk `checkCoverK` decides and -the cert-vs-literal `evalPoly_ext` identities. It must exceed `log2(2·ℓ1)` -of the certificates; the binding floor is the cell-walk `aeval` bound at -`~2^37772` (the certificate coefficients are `~37k`-bit and decay `~104` -bits per degree, so every monomial term is `~`constant scale), with the -eval-identity `polyL1` floor at `~2^37392`. This clears both with a -`~228`-bit margin, so it is near-minimal rather than arbitrary. -/ -def kB : Nat := 38000 - -/-! ## ℓ1 of a Taylor shift -/ - -/-- Evaluate the coefficient-magnitude polynomial at a `Nat` point. -/ -def aeval : List Int → Nat → Nat - | [], _ => 0 - | c :: cs, m => c.natAbs + m * aeval cs m - -theorem synthDiv_rem (p : List Int) (a : Int) : - (synthDiv p a).2 = evalPoly p a := by - have h := synthDiv_eval p a a - have e : a - a = 0 := by omega - rw [e, Int.mul_zero] at h - omega - -/-- Triangle inequality for evaluation against `aeval`. -/ -theorem evalPoly_natAbs_le : ∀ (p : List Int) (x : Int), - (evalPoly p x).natAbs ≤ aeval p x.natAbs := by - intro p - induction p with - | nil => intro x; exact Nat.le_refl _ - | cons c cs ih => - intro x - show (c + x * evalPoly cs x).natAbs ≤ c.natAbs + x.natAbs * aeval cs x.natAbs - have h1 := Int.natAbs_add_le c (x * evalPoly cs x) - have h2 : (x * evalPoly cs x).natAbs = x.natAbs * (evalPoly cs x).natAbs := - Int.natAbs_mul x (evalPoly cs x) - have h3 := ih x - have h4 : x.natAbs * (evalPoly cs x).natAbs ≤ x.natAbs * aeval cs x.natAbs := - Nat.mul_le_mul_left _ h3 - generalize hg1 : x.natAbs * (evalPoly cs x).natAbs = A at * - generalize hg2 : x.natAbs * aeval cs x.natAbs = B at * - omega - -/-- `aeval` is monotone in the point. -/ -theorem aeval_mono : ∀ (p : List Int) {m n : Nat}, m ≤ n → - aeval p m ≤ aeval p n := by - intro p - induction p with - | nil => intro m n _; exact Nat.le_refl _ - | cons c cs ih => - intro m n h - show c.natAbs + m * aeval cs m ≤ c.natAbs + n * aeval cs n - have h1 := ih h - have h2 : m * aeval cs m ≤ n * aeval cs n := - Nat.mul_le_mul h h1 - omega - -/-- The synthetic-division step preserves the `aeval` budget: remainder -magnitude plus the quotient's budget fit inside the dividend's budget at -`M = 1 + |a|`. -/ -theorem synthDiv_aeval_le : ∀ (p : List Int) (a : Int), - (evalPoly p a).natAbs + aeval (synthDiv p a).1 (1 + a.natAbs) ≤ - aeval p (1 + a.natAbs) := by - intro p - induction p with - | nil => - intro a - show (0 : Int).natAbs + 0 ≤ 0 - omega - | cons c cs ih => - intro a - match cs, ih with - | [], _ => - show (c + a * evalPoly ([] : List Int) a).natAbs + - aeval ([] : List Int) (1 + a.natAbs) ≤ c.natAbs + (1 + a.natAbs) * 0 - show (c + a * 0).natAbs + 0 ≤ c.natAbs + (1 + a.natAbs) * 0 - have e : c + a * 0 = c := by omega - rw [e] - omega - | c2 :: cs', ih => - have hrec := ih a - have hrem := synthDiv_rem (c2 :: cs') a - show (c + a * evalPoly (c2 :: cs') a).natAbs + - aeval ((synthDiv (c2 :: cs') a).2 :: (synthDiv (c2 :: cs') a).1) - (1 + a.natAbs) ≤ - c.natAbs + (1 + a.natAbs) * aeval (c2 :: cs') (1 + a.natAbs) - show (c + a * evalPoly (c2 :: cs') a).natAbs + - ((synthDiv (c2 :: cs') a).2.natAbs + - (1 + a.natAbs) * aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs)) ≤ - c.natAbs + (1 + a.natAbs) * aeval (c2 :: cs') (1 + a.natAbs) - rw [hrem] - have h1 := Int.natAbs_add_le c (a * evalPoly (c2 :: cs') a) - have h2 : (a * evalPoly (c2 :: cs') a).natAbs = - a.natAbs * (evalPoly (c2 :: cs') a).natAbs := - Int.natAbs_mul a (evalPoly (c2 :: cs') a) - have h3 : (1 + a.natAbs) * aeval (c2 :: cs') (1 + a.natAbs) = - aeval (c2 :: cs') (1 + a.natAbs) + - a.natAbs * aeval (c2 :: cs') (1 + a.natAbs) := by - rw [Nat.add_mul, Nat.one_mul] - have h4 : a.natAbs * ((evalPoly (c2 :: cs') a).natAbs + - aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs)) ≤ - a.natAbs * aeval (c2 :: cs') (1 + a.natAbs) := - Nat.mul_le_mul_left _ hrec - have h5 : a.natAbs * ((evalPoly (c2 :: cs') a).natAbs + - aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs)) = - a.natAbs * (evalPoly (c2 :: cs') a).natAbs + - a.natAbs * aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) := - Nat.mul_add _ _ _ - have h6 : (1 + a.natAbs) * aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) = - aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) + - a.natAbs * aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) := by - rw [Nat.add_mul, Nat.one_mul] - generalize hgEa : (evalPoly (c2 :: cs') a).natAbs = Ea at * - generalize hgQ : aeval (synthDiv (c2 :: cs') a).1 (1 + a.natAbs) = Q at * - generalize hgC : aeval (c2 :: cs') (1 + a.natAbs) = Cv at * - generalize hgX1 : a.natAbs * Ea = X1 at * - generalize hgX2 : a.natAbs * Q = X2 at * - generalize hgX3 : a.natAbs * Cv = X3 at * - generalize hgX4 : a.natAbs * (Ea + Q) = X4 at * - omega - -/-- ℓ1 of the Taylor shift is bounded by the absolute evaluation at -`1 + |a|`. -/ -theorem polyL1_polyShiftAux : ∀ (fuel : Nat) (p : List Int) (a : Int), - polyL1 (polyShiftAux fuel p a) ≤ aeval p (1 + a.natAbs) := by - intro fuel - induction fuel with - | zero => - intro p a - show polyL1 ([] : List Int) ≤ aeval p (1 + a.natAbs) - show 0 ≤ aeval p (1 + a.natAbs) - omega - | succ f ih => - intro p a - match p with - | [] => - show (0 : Nat) ≤ 0 - omega - | c :: cs => - show polyL1 ((synthDiv (c :: cs) a).2 :: - polyShiftAux f (synthDiv (c :: cs) a).1 a) ≤ - aeval (c :: cs) (1 + a.natAbs) - show (synthDiv (c :: cs) a).2.natAbs + - polyL1 (polyShiftAux f (synthDiv (c :: cs) a).1 a) ≤ - aeval (c :: cs) (1 + a.natAbs) - have h1 := ih (synthDiv (c :: cs) a).1 a - have h2 := synthDiv_aeval_le (c :: cs) a - have h3 := synthDiv_rem (c :: cs) a - have h4 : aeval (synthDiv (c :: cs) a).1 (1 + a.natAbs) ≤ - aeval (synthDiv (c :: cs) a).1 (1 + a.natAbs) := Nat.le_refl _ - generalize hg1 : polyL1 (polyShiftAux f (synthDiv (c :: cs) a).1 a) = L at * - generalize hg2 : aeval (synthDiv (c :: cs) a).1 (1 + a.natAbs) = Q at * - generalize hg3 : aeval (c :: cs) (1 + a.natAbs) = Cv at * - omega - -theorem polyL1_polyShift (p : List Int) (a : Int) : - polyL1 (polyShift p a) ≤ aeval p (1 + a.natAbs) := - polyL1_polyShiftAux p.length p a - -/-! ## Untrusted packed shift computation -/ - -/-- Sign-split packed polynomial: positive and negative digit strings in -radix `2^B`. Used only as a fast way to *compute* candidate coefficient -lists inside `decide`; nothing about it is trusted. -/ -structure KPoly where - pos : Nat - neg : Nat - -def kAdd (a b : KPoly) : KPoly := ⟨a.pos + b.pos, a.neg + b.neg⟩ - -def kMul (a b : KPoly) : KPoly := - ⟨a.pos * b.pos + a.neg * b.neg, a.pos * b.neg + a.neg * b.pos⟩ - -def kOfInt (c : Int) : KPoly := - ⟨c.toNat, (-c).toNat⟩ - -/-- Packed `x + a`. -/ -def kXA (B : Nat) (a : Int) : KPoly := - kAdd (kOfInt a) ⟨2 ^ B, 0⟩ - -/-- Packed Taylor shift by Horner: `p(x + a)` accumulated as packed -multiply-adds. -/ -def kShiftHorner (B : Nat) (a : Int) : List Int → KPoly - | [] => ⟨0, 0⟩ - | c :: cs => kAdd (kOfInt c) (kMul (kXA B a) (kShiftHorner B a cs)) - -/-- Signed digit extraction. -/ -def unpack (B : Nat) : Nat → KPoly → List Int - | 0, _ => [] - | len + 1, A => - (((A.pos &&& (2 ^ B - 1) : Nat) : Int) - ((A.neg &&& (2 ^ B - 1) : Nat) : Int)) :: - unpack B len ⟨A.pos >>> B, A.neg >>> B⟩ - -/-- Square ladder `x^(2^0), x^(2^1), …` of the given depth. -/ -def kSquares (x : KPoly) : Nat → List KPoly - | 0 => [x] - | d + 1 => - match kSquares x d with - | [] => [] - | s :: rest => kMul s s :: s :: rest - -/-- Power from a precomputed square ladder (most significant first). -/ -def kPowL : List KPoly → Nat → KPoly - | [], _ => ⟨1, 0⟩ - | s :: rest, n => - let h := kPowL rest (n % 2 ^ rest.length) - if n / 2 ^ rest.length % 2 = 1 then kMul h s else h - -/-- Divide-and-conquer packed Taylor shift: -`P(x+a) = P₀(x+a) + (x+a)^m · P₁(x+a)` with `m = ⌊n/2⌋`. The expensive -full-size multiplications happen only near the top of the recursion, so -the cost is a handful of full-size GMP products. -/ -def kShiftDC (B : Nat) (a : Int) (sq : List KPoly) : Nat → List Int → KPoly - | 0, p => kShiftHorner B a p - | fuel + 1, p => - if p.length ≤ 16 then kShiftHorner B a p - else - let m := p.length / 2 - kAdd (kShiftDC B a sq fuel (p.take m)) - (kMul (kPowL sq m) (kShiftDC B a sq fuel (p.drop m))) - -/-- The in-kernel shifted-witness candidate. -/ -def kShiftWitness (B : Nat) (C : List Int) (a : Int) : List Int := - unpack B C.length (kShiftDC B a (kSquares (kXA B a) 9) 16 C) - -/-! ## The witness-checked cell walk -/ - -/-- Certify `0 ≤ P(x)` on `[lo, hi]` by walking cells; each cell's -shifted polynomial is computed packed and certified by one evaluation -identity at `2^B` plus the ℓ1 bounds that make `evalPoly_ext` apply. -/ -def checkCoverK (B : Nat) (C : List Int) (lo hi : Int) : List Int → Bool - | [] => decide (hi < lo) - | w :: ws => - let S := kShiftWitness B C lo - decide (0 ≤ w) && - decide (polyL1 S * 2 < 2 ^ B) && - decide (aeval C (1 + lo.natAbs) * 2 < 2 ^ B) && - decide (evalPoly S (((2 ^ B : Nat) : Int)) = evalPoly C (lo + ((2 ^ B : Nat) : Int))) && - decide (0 ≤ (hornerIv S 0 w).1) && - checkCoverK B C (lo + w + 1) hi ws - -theorem checkCoverK_sound (B : Nat) (C : List Int) (ws : List Int) : - ∀ lo hi : Int, checkCoverK B C lo hi ws = true → - ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly C x := by - induction ws with - | nil => - intro lo hi h x h1 h2 - simp only [checkCoverK, decide_eq_true_eq] at h - omega - | cons w ws ih => - intro lo hi h x h1 h2 - simp only [checkCoverK, Bool.and_eq_true, decide_eq_true_eq] at h - obtain ⟨⟨⟨⟨hw, hS⟩, hC⟩, he⟩, hcell⟩ := h.1 - have hrest := h.2 - rcases Int.lt_or_le (lo + w) x with hout | hin - · exact ih (lo + w + 1) hi hrest x (by omega) h2 - · -- the witness agrees with the true shift everywhere - have hshift : polyL1 (polyShift C lo) * 2 < 2 ^ B := by - have := polyL1_polyShift C lo - omega - have hext := evalPoly_ext (B := B) (kShiftWitness B C lo) - (polyShift C lo) hS hshift - (by rw [polyShift_eval, pow2_cast]; exact he) - have hs := (hornerIv_sound (kShiftWitness B C lo) (lo := 0) (hi := w) - (x := x - lo) (Int.le_refl 0) (by omega) (by omega)).1 - have hx := hext (x - lo) - rw [polyShift_eval] at hx - rw [show lo + (x - lo) = x by omega] at hx - omega - -end LnPoly diff --git a/formal/ln/LnProof/LnProof/Foundation/Poly.lean b/formal/ln/LnProof/LnProof/Foundation/Poly.lean deleted file mode 100644 index 6f38b2d54..000000000 --- a/formal/ln/LnProof/LnProof/Foundation/Poly.lean +++ /dev/null @@ -1,225 +0,0 @@ -import Init - -/-! -# Polynomial positivity certificates - -Dense `Int` polynomials (coefficients low-order first), interval-Horner -evaluation over nonnegative domains, and a fuel-bounded adaptive bisection -checker whose `true` result soundly certifies `0 ≤ P(x)` for every integer -`x` in the queried range. The checker is executed by the kernel via `decide`, -so the analytic components of the monotonicity proof reduce to computation. --/ - -namespace LnPoly - -/-- Multiplication monotonicity helpers (Init-only, so spelled out). -/ -theorem mul_le_mul_left_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : - c * a ≤ c * b := by - have h1 : 0 ≤ c * (b - a) := Int.mul_nonneg hc (by omega) - rw [Int.mul_sub] at h1 - omega - -theorem mul_le_mul_right_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : - a * c ≤ b * c := by - have h1 : 0 ≤ (b - a) * c := Int.mul_nonneg (by omega) hc - rw [Int.sub_mul] at h1 - omega - -theorem mul_le_mul_left_nonpos {a b c : Int} (h : a ≤ b) (hc : c ≤ 0) : - c * b ≤ c * a := by - have h1 : 0 ≤ -c * (b - a) := Int.mul_nonneg (by omega) (by omega) - rw [Int.mul_sub, Int.neg_mul, Int.neg_mul] at h1 - omega - -def evalPoly : List Int → Int → Int - | [], _ => 0 - | c :: cs, x => c + x * evalPoly cs x - -/-- Interval Horner over a nonnegative domain `[lo, hi]`, `0 ≤ lo`. Returns -`(vlo, vhi)` with `vlo ≤ P(x) ≤ vhi` for all `x ∈ [lo, hi]`. -/ -def hornerIv : List Int → Int → Int → Int × Int - | [], _, _ => (0, 0) - | c :: cs, lo, hi => - let (plo, phi) := hornerIv cs lo hi - let mlo := if 0 ≤ plo then lo * plo else hi * plo - let mhi := if 0 ≤ phi then hi * phi else lo * phi - (c + mlo, c + mhi) - -theorem hornerIv_sound (cs : List Int) {lo hi x : Int} - (h0 : 0 ≤ lo) (h1 : lo ≤ x) (h2 : x ≤ hi) : - (hornerIv cs lo hi).1 ≤ evalPoly cs x ∧ evalPoly cs x ≤ (hornerIv cs lo hi).2 := by - induction cs with - | nil => simp [hornerIv, evalPoly] - | cons c cs ih => - obtain ⟨ihlo, ihhi⟩ := ih - simp only [hornerIv, evalPoly] - constructor - · -- lower bound - have hx : 0 ≤ x := by omega - split - · -- 0 ≤ plo : lo * plo ≤ x * plo ≤ x * P(x) - rename_i hplo - have s1 : lo * (hornerIv cs lo hi).1 ≤ x * (hornerIv cs lo hi).1 := - mul_le_mul_right_nonneg h1 hplo - have s2 : x * (hornerIv cs lo hi).1 ≤ x * evalPoly cs x := - mul_le_mul_left_nonneg ihlo hx - omega - · -- plo < 0 : hi * plo ≤ x * plo ≤ x * P(x) - rename_i hplo - have hplo' : (hornerIv cs lo hi).1 ≤ 0 := by omega - have s1 : hi * (hornerIv cs lo hi).1 ≤ x * (hornerIv cs lo hi).1 := by - have hcomm := mul_le_mul_left_nonpos h2 hplo' - rw [Int.mul_comm ((hornerIv cs lo hi).1) hi, - Int.mul_comm ((hornerIv cs lo hi).1) x] at hcomm - exact hcomm - have s2 : x * (hornerIv cs lo hi).1 ≤ x * evalPoly cs x := - mul_le_mul_left_nonneg ihlo hx - omega - · -- upper bound - have hx : 0 ≤ x := by omega - split - · -- 0 ≤ phi : x * P(x) ≤ x * phi ≤ hi * phi - rename_i hphi - have s2 : x * evalPoly cs x ≤ x * (hornerIv cs lo hi).2 := - mul_le_mul_left_nonneg ihhi hx - have s1 : x * (hornerIv cs lo hi).2 ≤ hi * (hornerIv cs lo hi).2 := - mul_le_mul_right_nonneg h2 hphi - omega - · -- phi < 0 : x * P(x) ≤ x * phi ≤ lo * phi - rename_i hphi - have hphi' : (hornerIv cs lo hi).2 ≤ 0 := by omega - have s2 : x * evalPoly cs x ≤ x * (hornerIv cs lo hi).2 := - mul_le_mul_left_nonneg ihhi hx - have s1 : x * (hornerIv cs lo hi).2 ≤ lo * (hornerIv cs lo hi).2 := by - have hcomm := mul_le_mul_left_nonpos h1 hphi' - rw [Int.mul_comm ((hornerIv cs lo hi).2) lo, - Int.mul_comm ((hornerIv cs lo hi).2) x] at hcomm - exact hcomm - omega - -/-- Adaptive bisection: certifies `0 ≤ P(x)` for every integer `x ∈ [lo, hi]`. -/ -def checkNonneg (cs : List Int) (lo hi : Int) : Nat → Bool - | 0 => false - | fuel + 1 => - if hi < lo then true - else if 0 ≤ (hornerIv cs lo hi).1 then true - else if lo = hi then false - else - let mid := (lo + hi) / 2 - checkNonneg cs lo mid fuel && checkNonneg cs (mid + 1) hi fuel - -theorem checkNonneg_sound (cs : List Int) (fuel : Nat) : - ∀ lo hi : Int, 0 ≤ lo → checkNonneg cs lo hi fuel = true → - ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly cs x := by - induction fuel with - | zero => intro lo hi _ h; simp [checkNonneg] at h - | succ fuel ih => - intro lo hi hlo h x hx1 hx2 - unfold checkNonneg at h - split at h - · omega - · split at h - · rename_i hiv - have := (hornerIv_sound cs hlo hx1 hx2).1 - omega - · split at h - · exact absurd h (by simp) - · rw [Bool.and_eq_true] at h - by_cases hm : x ≤ (lo + hi) / 2 - · exact ih lo ((lo + hi) / 2) hlo h.1 x hx1 hm - · exact ih ((lo + hi) / 2 + 1) hi (by omega) h.2 x (by omega) hx2 - -/-! ## Polynomial algebra (with evaluation lemmas) -/ - -def polyAdd : List Int → List Int → List Int - | [], q => q - | p, [] => p - | a :: p, b :: q => (a + b) :: polyAdd p q - -theorem evalPoly_polyAdd (p q : List Int) (x : Int) : - evalPoly (polyAdd p q) x = evalPoly p x + evalPoly q x := by - induction p generalizing q with - | nil => simp [polyAdd, evalPoly] - | cons a p ih => - cases q with - | nil => simp [polyAdd, evalPoly] - | cons b q => - simp only [polyAdd, evalPoly, ih] - rw [Int.mul_add] - omega - -def polyNeg (p : List Int) : List Int := p.map (-·) - -theorem evalPoly_polyNeg (p : List Int) (x : Int) : - evalPoly (polyNeg p) x = -evalPoly p x := by - induction p with - | nil => simp [polyNeg, evalPoly] - | cons a p ih => - simp only [polyNeg, List.map, evalPoly] at * - rw [ih] - rw [show x * -evalPoly p x = -(x * evalPoly p x) by rw [Int.mul_neg]] - omega - -def polySub (p q : List Int) : List Int := polyAdd p (polyNeg q) - -theorem evalPoly_polySub (p q : List Int) (x : Int) : - evalPoly (polySub p q) x = evalPoly p x - evalPoly q x := by - unfold polySub - rw [evalPoly_polyAdd, evalPoly_polyNeg] - omega - -def polyScale (a : Int) (p : List Int) : List Int := p.map (a * ·) - -theorem evalPoly_polyScale (a : Int) (p : List Int) (x : Int) : - evalPoly (polyScale a p) x = a * evalPoly p x := by - induction p with - | nil => simp [polyScale, evalPoly] - | cons c p ih => - simp only [polyScale, List.map, evalPoly] at * - rw [ih, Int.mul_add] - rw [show x * (a * evalPoly p x) = a * (x * evalPoly p x) by - rw [← Int.mul_assoc, Int.mul_comm x a, Int.mul_assoc]] - -theorem evalPoly_singleton (c x : Int) : evalPoly [c] x = c := by - simp [evalPoly] - -def polyMulX (p : List Int) : List Int := 0 :: p - -theorem evalPoly_polyMulX (p : List Int) (x : Int) : - evalPoly (polyMulX p) x = x * evalPoly p x := by - simp [polyMulX, evalPoly] - -def polyMul : List Int → List Int → List Int - | [], _ => [] - | a :: p, q => polyAdd (polyScale a q) (polyMulX (polyMul p q)) - -theorem evalPoly_polyMul (p q : List Int) (x : Int) : - evalPoly (polyMul p q) x = evalPoly p x * evalPoly q x := by - induction p with - | nil => simp [polyMul, evalPoly] - | cons a p ih => - simp only [polyMul, evalPoly] - rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyMulX, ih] - rw [Int.add_mul] - rw [show x * (evalPoly p x * evalPoly q x) = x * evalPoly p x * evalPoly q x by - rw [Int.mul_assoc]] - -/-- Composition with `x + 1`: `evalPoly (polyCompAdd1 p) x = evalPoly p (x + 1)`. -/ -def polyCompAdd1 : List Int → List Int - | [] => [] - | c :: cs => - let q := polyCompAdd1 cs - polyAdd [c] (polyAdd q (polyMulX q)) - -theorem evalPoly_polyCompAdd1 (p : List Int) (x : Int) : - evalPoly (polyCompAdd1 p) x = evalPoly p (x + 1) := by - induction p with - | nil => simp [polyCompAdd1, evalPoly] - | cons c cs ih => - simp only [polyCompAdd1, evalPoly] - rw [evalPoly_polyAdd, evalPoly_polyAdd, evalPoly_polyMulX, ih] - simp only [evalPoly] - rw [Int.add_mul, Int.one_mul] - omega - -end LnPoly diff --git a/formal/ln/LnProof/LnProof/Foundation/ShiftCert.lean b/formal/ln/LnProof/LnProof/Foundation/ShiftCert.lean deleted file mode 100644 index 5f0e77f8b..000000000 --- a/formal/ln/LnProof/LnProof/Foundation/ShiftCert.lean +++ /dev/null @@ -1,422 +0,0 @@ -import LnProof.Foundation.Poly -import LnProof.Foundation.ExpSum - -/-! -# Recentered polynomial nonnegativity certificates - -The floor-specification certificate polynomials have ~1e-28 relative slack: -plain interval Horner cannot see the cancellation between their huge -monomials, so bisection alone would need ~1e30 cells. Recentering a -polynomial at each cell's left endpoint (an exact integer Taylor shift) -exposes the cancellation symbolically; interval Horner over the shifted -cell `[0, w]` then converges with a few hundred cells. - -`checkCover` walks a caller-supplied list of cell widths and certifies -`0 ≤ P(x)` for every integer `x` in `[lo, hi]`. - -The file also provides the polynomial-level partial-sum numerator -(`expPolyNum`) and its evaluation lemma, connecting the certificate -polynomials to the `expNum` caps of `LnProof.Foundation.ExpSum`. --/ - -namespace LnPoly - -/-- Synthetic division by `(x - a)`: `P(x) = Q(x) (x - a) + r`. -/ -def synthDiv : List Int → Int → List Int × Int - | [], _ => ([], 0) - | [c], _ => ([], c) - | c :: cs, a => - ((synthDiv cs a).2 :: (synthDiv cs a).1, c + a * (synthDiv cs a).2) - -theorem synthDiv_eval (C : List Int) (a x : Int) : - evalPoly C x = evalPoly (synthDiv C a).1 x * (x - a) + (synthDiv C a).2 := by - match C with - | [] => simp [synthDiv, evalPoly] - | [c] => simp [synthDiv, evalPoly] - | c :: c2 :: cs => - have ih := synthDiv_eval (c2 :: cs) a x - show c + x * evalPoly (c2 :: cs) x = _ - rw [ih] - show _ = ((synthDiv (c2 :: cs) a).2 + - x * evalPoly ((synthDiv (c2 :: cs) a).1) x) * (x - a) + - (c + a * (synthDiv (c2 :: cs) a).2) - rw [Int.add_mul] - have e1 : x * (evalPoly (synthDiv (c2 :: cs) a).1 x * (x - a) + - (synthDiv (c2 :: cs) a).2) = - x * evalPoly (synthDiv (c2 :: cs) a).1 x * (x - a) + - x * (synthDiv (c2 :: cs) a).2 := by - rw [Int.mul_add, Int.mul_assoc] - have e2 : x * (synthDiv (c2 :: cs) a).2 = - (x - a) * (synthDiv (c2 :: cs) a).2 + a * (synthDiv (c2 :: cs) a).2 := by - rw [Int.sub_mul] - omega - have e3 : (x - a) * (synthDiv (c2 :: cs) a).2 = - (synthDiv (c2 :: cs) a).2 * (x - a) := Int.mul_comm _ _ - omega - -theorem synthDiv_length : ∀ (C : List Int) (a : Int), C ≠ [] → - (synthDiv C a).1.length + 1 = C.length := by - intro C a h - match C with - | [c] => rfl - | c :: c2 :: cs => - have ih := synthDiv_length (c2 :: cs) a (by simp) - show ((synthDiv (c2 :: cs) a).2 :: (synthDiv (c2 :: cs) a).1).length + 1 = _ - simp only [List.length_cons] at * - omega - -/-- Fuel-based Taylor shift (structural recursion, so the kernel computes -it inside `decide`). -/ -def polyShiftAux : Nat → List Int → Int → List Int - | 0, _, _ => [] - | _ + 1, [], _ => [] - | fuel + 1, c :: cs, a => - (synthDiv (c :: cs) a).2 :: polyShiftAux fuel (synthDiv (c :: cs) a).1 a - -/-- Exact Taylor shift: `evalPoly (polyShift C a) δ = evalPoly C (a + δ)`. -/ -def polyShift (C : List Int) (a : Int) : List Int := - polyShiftAux C.length C a - -theorem polyShiftAux_eval (fuel : Nat) : - ∀ (C : List Int) (a δ : Int), C.length ≤ fuel → - evalPoly (polyShiftAux fuel C a) δ = evalPoly C (a + δ) := by - induction fuel with - | zero => - intro C a δ h - have : C = [] := List.eq_nil_of_length_eq_zero (by omega) - subst this - rfl - | succ f ih => - intro C a δ h - match C with - | [] => rfl - | c :: cs => - show (synthDiv (c :: cs) a).2 + - δ * evalPoly (polyShiftAux f (synthDiv (c :: cs) a).1 a) δ = _ - have hlen : (synthDiv (c :: cs) a).1.length ≤ f := by - have := synthDiv_length (c :: cs) a (by simp) - simp only [List.length_cons] at * - omega - rw [ih _ a δ hlen, synthDiv_eval (c :: cs) a (a + δ)] - have e1 : evalPoly (synthDiv (c :: cs) a).1 (a + δ) * (a + δ - a) = - δ * evalPoly (synthDiv (c :: cs) a).1 (a + δ) := by - rw [show a + δ - a = δ by omega, Int.mul_comm] - omega - -theorem polyShift_eval (C : List Int) (a δ : Int) : - evalPoly (polyShift C a) δ = evalPoly C (a + δ) := - polyShiftAux_eval C.length C a δ (Nat.le_refl _) - -/-- Certify `0 ≤ P(x)` for every integer `x ∈ [lo, hi]` by walking cells of -the given widths, recentering at each cell's left endpoint. -/ -def checkCover (C : List Int) (lo hi : Int) : List Int → Bool - | [] => decide (hi < lo) - | w :: ws => - decide (0 ≤ w) && decide (0 ≤ (hornerIv (polyShift C lo) 0 w).1) && - checkCover C (lo + w + 1) hi ws - -theorem checkCover_sound (C : List Int) (ws : List Int) : - ∀ lo hi : Int, checkCover C lo hi ws = true → - ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly C x := by - induction ws with - | nil => - intro lo hi h x h1 h2 - simp only [checkCover, decide_eq_true_eq] at h - omega - | cons w ws ih => - intro lo hi h x h1 h2 - simp only [checkCover, Bool.and_eq_true, decide_eq_true_eq] at h - obtain ⟨⟨hw, hcell⟩, hrest⟩ := h - rcases Int.lt_or_le (lo + w) x with hout | hin - · exact ih (lo + w + 1) hi hrest x (by omega) h2 - · have hs := (hornerIv_sound (polyShift C lo) (lo := 0) (hi := w) - (x := x - lo) (Int.le_refl 0) (by omega) (by omega)).1 - rw [polyShift_eval] at hs - rw [show lo + (x - lo) = x by omega] at hs - omega - -/-! ## Partial-sum numerators at the polynomial level -/ - -/-- Int mirror of `LnExp.expNum`. -/ -def expNumI : Nat → Int → Int → Int - | 0, _, _ => 1 - | n + 1, p, q => (n + 1) * q * expNumI n p q + p ^ (n + 1) - -theorem expNumI_eq_expNum (k : Nat) (p q : Nat) : - expNumI k (p : Int) (q : Int) = (LnExp.expNum k p q : Int) := by - induction k with - | zero => rfl - | succ n ih => - show ((n : Int) + 1) * q * expNumI n p q + (p : Int) ^ (n + 1) = _ - rw [ih] - show _ = ((((n + 1) * q * LnExp.expNum n p q + p ^ (n + 1) : Nat)) : Int) - push_cast - omega - -def polyPow (P : List Int) : Nat → List Int - | 0 => [1] - | n + 1 => polyMul P (polyPow P n) - -theorem evalPoly_polyPow (P : List Int) (n : Nat) (x : Int) : - evalPoly (polyPow P n) x = evalPoly P x ^ n := by - induction n with - | zero => simp [polyPow, evalPoly] - | succ k ih => - show evalPoly (polyMul P (polyPow P k)) x = _ - rw [evalPoly_polyMul, ih] - rw [show evalPoly P x ^ (k + 1) = evalPoly P x ^ k * evalPoly P x from - Int.pow_succ _ _] - rw [Int.mul_comm] - -/-- Polynomial-level partial-sum numerator: evaluates to -`expNumI k (TN(x)) (TD(x))`. -/ -def expPolyNum (TN TD : List Int) : Nat → List Int - | 0 => [1] - | n + 1 => - polyAdd (polyScale ((n : Int) + 1) (polyMul TD (expPolyNum TN TD n))) - (polyPow TN (n + 1)) - -theorem evalPoly_expPolyNum (TN TD : List Int) (k : Nat) (x : Int) : - evalPoly (expPolyNum TN TD k) x = - expNumI k (evalPoly TN x) (evalPoly TD x) := by - induction k with - | zero => simp [expPolyNum, expNumI, evalPoly] - | succ n ih => - show evalPoly (polyAdd (polyScale ((n : Int) + 1) - (polyMul TD (expPolyNum TN TD n))) (polyPow TN (n + 1))) x = _ - rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyMul, ih, - evalPoly_polyPow] - show _ = ((n : Int) + 1) * evalPoly TD x * expNumI n (evalPoly TN x) - (evalPoly TD x) + evalPoly TN x ^ (n + 1) - rw [← Int.mul_assoc] - -/-! ## Crude range and difference bounds over a box - -`polyHi cs B` bounds `evalPoly cs t` from above for `t ∈ [0, B]`; -`polyAbs cs B` bounds its magnitude; `polyDiffHi cs B` bounds the divided -difference `(P(y) - P(x))/(y - x)` from above for `0 ≤ x ≤ y ≤ B`. A -negative `polyDiffHi` certificate proves the polynomial decreasing on the -whole box, which is how the bracket lemmas compare pipeline stage values -at integer points against the certificate polynomials' rational interval -ends. -/ - -def iabs (c : Int) : Int := if c < 0 then -c else c - -def polyHi : List Int → Int → Int - | [], _ => 0 - | c :: cs, B => c + B * max (polyHi cs B) 0 - -def polyDiffHi : List Int → Int → Int - | [], _ => 0 - | _ :: cs, B => polyHi cs B + max (B * polyDiffHi cs B) 0 - -theorem polyHi_bound (cs : List Int) (B : Int) : - ∀ t : Int, 0 ≤ t → t ≤ B → evalPoly cs t ≤ polyHi cs B := by - induction cs with - | nil => intro t _ _; exact Int.le_refl _ - | cons c cs ih => - intro t h0 hB - show c + t * evalPoly cs t ≤ c + B * max (polyHi cs B) 0 - have hT := ih t h0 hB - rcases Int.le_total (evalPoly cs t) 0 with hneg | hpos - · have h1 : t * evalPoly cs t ≤ 0 := Int.mul_nonpos_of_nonneg_of_nonpos h0 hneg - have h2 : 0 ≤ B * max (polyHi cs B) 0 := - Int.mul_nonneg (by omega) (by omega) - omega - · have h1 : t * evalPoly cs t ≤ B * evalPoly cs t := - mul_le_mul_right_nonneg hB hpos - have h2 : B * evalPoly cs t ≤ B * max (polyHi cs B) 0 := - mul_le_mul_left_nonneg (by omega) (by omega) - omega - -theorem polyDiffHi_bound (cs : List Int) (B : Int) : - ∀ x y : Int, 0 ≤ x → x ≤ y → y ≤ B → - evalPoly cs y - evalPoly cs x ≤ polyDiffHi cs B * (y - x) := by - induction cs with - | nil => - intro x y _ _ _ - show (0 : Int) - 0 ≤ 0 * (y - x) - omega - | cons c cs ih => - intro x y hx hxy hyB - show c + y * evalPoly cs y - (c + x * evalPoly cs x) ≤ - (polyHi cs B + max (B * polyDiffHi cs B) 0) * (y - x) - -- y T(y) - x T(x) = (y - x) T(y) + x (T(y) - T(x)) - have hsplit : y * evalPoly cs y - x * evalPoly cs x = - (y - x) * evalPoly cs y + x * (evalPoly cs y - evalPoly cs x) := by - rw [Int.sub_mul, Int.mul_sub] - omega - have h1 : (y - x) * evalPoly cs y ≤ (y - x) * polyHi cs B := - mul_le_mul_left_nonneg (polyHi_bound cs B y (by omega) hyB) (by omega) - have h2 : x * (evalPoly cs y - evalPoly cs x) ≤ max (B * polyDiffHi cs B) 0 * (y - x) := by - have hd := ih x y hx hxy hyB - rcases Int.le_total 0 (polyDiffHi cs B) with hD | hD - · have s1 : x * (evalPoly cs y - evalPoly cs x) ≤ x * (polyDiffHi cs B * (y - x)) := by - rcases Int.le_total (evalPoly cs y - evalPoly cs x) (polyDiffHi cs B * (y - x)) - with h | h - · exact mul_le_mul_left_nonneg h hx - · have : evalPoly cs y - evalPoly cs x = polyDiffHi cs B * (y - x) := by omega - rw [this] - exact Int.le_refl _ - have s2 : x * (polyDiffHi cs B * (y - x)) ≤ B * (polyDiffHi cs B * (y - x)) := - mul_le_mul_right_nonneg (by omega) - (Int.mul_nonneg hD (by omega)) - have e1 : B * (polyDiffHi cs B * (y - x)) = B * polyDiffHi cs B * (y - x) := by - rw [Int.mul_assoc] - have hmax : B * polyDiffHi cs B * (y - x) ≤ max (B * polyDiffHi cs B) 0 * (y - x) := - mul_le_mul_right_nonneg (by omega) (by omega) - omega - · -- divided difference is nonpositive: x * diff ≤ 0 - have hd0 : evalPoly cs y - evalPoly cs x ≤ 0 := by - have : polyDiffHi cs B * (y - x) ≤ 0 := - Int.mul_nonpos_of_nonpos_of_nonneg hD (by omega) - omega - have s1 : x * (evalPoly cs y - evalPoly cs x) ≤ 0 := - Int.mul_nonpos_of_nonneg_of_nonpos hx hd0 - have : 0 ≤ max (B * polyDiffHi cs B) 0 * (y - x) := - Int.mul_nonneg (by omega) (by omega) - omega - have e2 : (polyHi cs B + max (B * polyDiffHi cs B) 0) * (y - x) = - (y - x) * polyHi cs B + max (B * polyDiffHi cs B) 0 * (y - x) := by - rw [Int.add_mul, Int.mul_comm (polyHi cs B) (y - x)] - omega - -/-! ## Homogenized two-point evaluation -/ - -/-- `homPoly cs num den` is `Σ_j cs_j num^j den^(deg - j)` at the -polynomial level. -/ -def homPoly : List Int → List Int → List Int → List Int - | [], _, _ => [0] - | c :: cs, num, den => - polyAdd (polyScale c (polyPow den cs.length)) (polyMul num (homPoly cs num den)) - -/-- `homEvalI cs n d = Σ_j cs_j n^j d^(deg-j)`, Horner-style. -/ -def homEvalI : List Int → Int → Int → Int - | [], _, _ => 0 - | c :: cs, nv, dv => c * dv ^ cs.length + nv * homEvalI cs nv dv - -theorem evalPoly_homPoly (cs : List Int) (num den : List Int) (x : Int) : - evalPoly (homPoly cs num den) x = - homEvalI cs (evalPoly num x) (evalPoly den x) := by - induction cs with - | nil => - show (0 : Int) + x * 0 = 0 - omega - | cons c cs ih => - show evalPoly (polyAdd (polyScale c (polyPow den cs.length)) - (polyMul num (homPoly cs num den))) x = _ - rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyPow, evalPoly_polyMul, ih] - rfl - -/-- The trivial homogenization identity: at the pair `(u d, d)` the -homogenized value collapses to `d^deg · P(u)`. -/ -theorem homEvalI_collapse (u D : Int) : - ∀ (c : Int) (cs : List Int), - homEvalI (c :: cs) (u * D) D = D ^ cs.length * evalPoly (c :: cs) u := by - intro c cs - induction cs generalizing c with - | nil => - show c * D ^ 0 + u * D * 0 = D ^ 0 * (c + u * 0) - rw [Int.mul_zero, Int.mul_zero, Int.add_zero, Int.add_zero, Int.mul_comm] - | cons c2 cs ih => - show c * D ^ (c2 :: cs).length + u * D * homEvalI (c2 :: cs) (u * D) D = _ - rw [ih c2] - show c * D ^ (cs.length + 1) + u * D * (D ^ cs.length * evalPoly (c2 :: cs) u) = - D ^ (cs.length + 1) * (c + u * evalPoly (c2 :: cs) u) - have e1 : (D : Int) ^ (cs.length + 1) = D * D ^ cs.length := by - rw [Int.pow_succ, Int.mul_comm] - rw [e1, Int.mul_add] - have e2 : u * D * (D ^ cs.length * evalPoly (c2 :: cs) u) = - D * D ^ cs.length * (u * evalPoly (c2 :: cs) u) := by - simp only [Int.mul_assoc, Int.mul_left_comm] - have e3 : c * (D * D ^ cs.length) = D * D ^ cs.length * c := by - rw [Int.mul_comm] - omega - -/-! ## Sharing-friendly mirrors of the shift checker - -`synthDiv` names its recursive result three times, and the kernel -re-evaluates each occurrence during `decide`. The `M`-variants bind the -recursive result through a `match`, so the kernel computes it once per -step; `checkCoverM_sound` transfers soundness from the reference checker. --/ - -def synthDivM : List Int → Int → List Int × Int - | [], _ => ([], 0) - | [c], _ => ([], c) - | c :: cs, a => - match synthDivM cs a with - | (q, r) => (r :: q, c + a * r) - -theorem synthDivM_eq : ∀ (C : List Int) (a : Int), synthDivM C a = synthDiv C a := by - intro C a - match C with - | [] => rfl - | [c] => rfl - | c :: c2 :: cs => - have ih := synthDivM_eq (c2 :: cs) a - show (match synthDivM (c2 :: cs) a with - | (q, r) => (r :: q, c + a * r)) = _ - rw [ih] - rcases h : synthDiv (c2 :: cs) a with ⟨q, r⟩ - show (r :: q, c + a * r) = ((synthDiv (c2 :: cs) a).2 :: (synthDiv (c2 :: cs) a).1, - c + a * (synthDiv (c2 :: cs) a).2) - rw [h] - -def polyShiftAuxM : Nat → List Int → Int → List Int - | 0, _, _ => [] - | _ + 1, [], _ => [] - | fuel + 1, c :: cs, a => - match synthDivM (c :: cs) a with - | (q, r) => r :: polyShiftAuxM fuel q a - -theorem polyShiftAuxM_eq : ∀ (fuel : Nat) (C : List Int) (a : Int), - polyShiftAuxM fuel C a = polyShiftAux fuel C a := by - intro fuel - induction fuel with - | zero => intro C a; rfl - | succ f ih => - intro C a - match C with - | [] => rfl - | c :: cs => - show (match synthDivM (c :: cs) a with - | (q, r) => r :: polyShiftAuxM f q a) = _ - rw [synthDivM_eq] - rcases h : synthDiv (c :: cs) a with ⟨q, r⟩ - show r :: polyShiftAuxM f q a = - (synthDiv (c :: cs) a).2 :: polyShiftAux f (synthDiv (c :: cs) a).1 a - rw [h, ih] - -def polyShiftM (C : List Int) (a : Int) : List Int := - polyShiftAuxM C.length C a - -theorem polyShiftM_eq (C : List Int) (a : Int) : polyShiftM C a = polyShift C a := - polyShiftAuxM_eq C.length C a - -def checkCoverM (C : List Int) (lo hi : Int) : List Int → Bool - | [] => decide (hi < lo) - | w :: ws => - decide (0 ≤ w) && decide (0 ≤ (hornerIv (polyShiftM C lo) 0 w).1) && - checkCoverM C (lo + w + 1) hi ws - -theorem checkCoverM_eq (C : List Int) : ∀ (ws : List Int) (lo hi : Int), - checkCoverM C lo hi ws = checkCover C lo hi ws := by - intro ws - induction ws with - | nil => intro lo hi; rfl - | cons w ws ih => - intro lo hi - show (decide (0 ≤ w) && decide (0 ≤ (hornerIv (polyShiftM C lo) 0 w).1) && - checkCoverM C (lo + w + 1) hi ws) = _ - rw [polyShiftM_eq, ih] - rfl - -theorem checkCoverM_sound (C : List Int) (ws : List Int) (lo hi : Int) - (h : checkCoverM C lo hi ws = true) : - ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly C x := by - refine checkCover_sound C ws lo hi ?_ - rw [← checkCoverM_eq] - exact h - -end LnPoly diff --git a/formal/ln/LnProof/LnProof/Model/Body.lean b/formal/ln/LnProof/LnProof/Model/Body.lean index af353b9c5..64c07a48a 100644 --- a/formal/ln/LnProof/LnProof/Model/Body.lean +++ b/formal/ln/LnProof/LnProof/Model/Body.lean @@ -1,5 +1,5 @@ import LnProof.Foundation.WordDiv -import LnProof.Foundation.Poly +import Common.Foundation.Poly open FormalYul open FormalYul.Preservation @@ -18,7 +18,7 @@ unfold `Int` powers of this size). namespace LnYul -open LnPoly +open Common.Poly def Sc : Nat := 56022770974786139918731938227 def P4c : Nat := 4542704643877621417440 diff --git a/formal/ln/LnProof/LnProof/Mono/Certs.lean b/formal/ln/LnProof/LnProof/Mono/Certs.lean index 9f5f9b423..fc0d590ab 100644 --- a/formal/ln/LnProof/LnProof/Mono/Certs.lean +++ b/formal/ln/LnProof/LnProof/Mono/Certs.lean @@ -1,5 +1,5 @@ import LnProof.Model.Body -import LnProof.Foundation.Poly +import Common.Foundation.Poly /-! # Decidable certificates @@ -13,7 +13,7 @@ the polynomial-side sign facts. namespace LnYul -open LnPoly +open Common.Poly def UcI : Int := 2332259347626381040680638252 def ZcI : Int := 217494458298375249691265569570 diff --git a/formal/ln/LnProof/LnProof/Mono/Octave.lean b/formal/ln/LnProof/LnProof/Mono/Octave.lean index 670486cf4..9509543ad 100644 --- a/formal/ln/LnProof/LnProof/Mono/Octave.lean +++ b/formal/ln/LnProof/LnProof/Mono/Octave.lean @@ -17,7 +17,7 @@ set_option maxRecDepth 4096 namespace LnYul -open LnPoly +open Common.Poly /-- The body tail downstream of `(k, mantissa)`: the floored accumulator `s = sar72(X1·K + ln2·k + BIAS)`, self-corrected via `s + (s == -1)`. The diff --git a/formal/ln/LnProof/LnProof/Mono/Step.lean b/formal/ln/LnProof/LnProof/Mono/Step.lean index 4007a44c0..2f555707f 100644 --- a/formal/ln/LnProof/LnProof/Mono/Step.lean +++ b/formal/ln/LnProof/LnProof/Mono/Step.lean @@ -15,7 +15,7 @@ through the truncation sandwiches. namespace LnYul -open LnPoly +open Common.Poly def x1W (z : Nat) : Nat := evmSdiv (evmMul (pS4 (uWord z)) z) (qS5 (uWord z)) diff --git a/formal/ln/LnProof/LnProof/Mono/ZOctave.lean b/formal/ln/LnProof/LnProof/Mono/ZOctave.lean index 41e46a782..d76e526ba 100644 --- a/formal/ln/LnProof/LnProof/Mono/ZOctave.lean +++ b/formal/ln/LnProof/LnProof/Mono/ZOctave.lean @@ -16,7 +16,7 @@ set_option maxRecDepth 4096 namespace LnYul -open LnPoly +open Common.Poly def MLO : Nat := 2 ^ 95 def MHI : Nat := 2 ^ 96 diff --git a/formal/ln/LnProof/LnProof/Seam/RealLog.lean b/formal/ln/LnProof/LnProof/Seam/RealLog.lean index 4ae985699..36849bb1a 100644 --- a/formal/ln/LnProof/LnProof/Seam/RealLog.lean +++ b/formal/ln/LnProof/LnProof/Seam/RealLog.lean @@ -1,6 +1,6 @@ import Mathlib.Analysis.SpecialFunctions.Log.Basic import Mathlib.Analysis.SpecialFunctions.Exponential -import LnProof.Foundation.ExpSum +import Common.Seam.RealExpBridge import LnProof.Spec.Real import LnProof.Spec.Cut @@ -8,133 +8,10 @@ open scoped BigOperators namespace LnRealBridge -open LnExp LnFloor LnFloorCert +open Common.Exp Common.RealExpBridge LnFloor LnFloorCert noncomputable section -lemma fact_eq_factorial (n : Nat) : fact n = Nat.factorial n := by - induction n with - | zero => rfl - | succ k ih => simp [fact, Nat.factorial_succ, ih] - -lemma tsum_nat_cast_sum_range (n : Nat) (f : Nat → Nat) : - ((LnExp.tsum n f : Nat) : Real) = ∑ j ∈ Finset.range (n + 1), (f j : Real) := by - induction n with - | zero => simp [LnExp.tsum] - | succ k ih => - simp [LnExp.tsum, ih, Finset.sum_range_succ, Nat.cast_add] - -lemma expNum_div_eq_sum_range (n p q : Nat) (hq : 0 < q) : - (expNum n p q : Real) / ((fact n * q ^ n : Nat) : Real) = - ∑ j ∈ Finset.range (n + 1), ((p : Real) / q) ^ j / ((fact j : Nat) : Real) := by - rw [expNum_eq_tsum] - rw [show ((LnExp.tsum n (fun j => ffacAux j (n - j) * p ^ j * q ^ (n - j)) : Nat) : Real) = - ∑ j ∈ Finset.range (n + 1), ((ffacAux j (n - j) * p ^ j * q ^ (n - j) : Nat) : Real) from - tsum_nat_cast_sum_range n (fun j => ffacAux j (n - j) * p ^ j * q ^ (n - j))] - rw [div_eq_mul_inv, Finset.sum_mul] - apply Finset.sum_congr rfl - intro j hj - have hjle : j ≤ n := Nat.lt_succ.mp (Finset.mem_range.mp hj) - have hqn : (q : Real) ≠ 0 := by exact_mod_cast ne_of_gt hq - have hfactj : ((fact j : Nat) : Real) ≠ 0 := by - exact_mod_cast ne_of_gt (fact_pos j) - have hfactn : ((fact n : Nat) : Real) ≠ 0 := by - exact_mod_cast ne_of_gt (fact_pos n) - have hden : (((fact n * q ^ n : Nat) : Real)) ≠ 0 := by - exact_mod_cast ne_of_gt (Nat.mul_pos (fact_pos n) (Nat.pow_pos hq)) - have hff : (ffacAux j (n - j) * fact j : Nat) = fact n := by - rw [ffacAux_mul_fact] - congr 1 - omega - have hffR : ((ffacAux j (n - j) : Nat) : Real) * ((fact j : Nat) : Real) = ((fact n : Nat) : Real) := by - norm_num [← Nat.cast_mul, hff] - have hpow : (q : Real) ^ n = (q : Real) ^ j * (q : Real) ^ (n - j) := by - rw [← pow_add] - congr 1 - omega - norm_num [Nat.cast_mul, Nat.cast_pow] - field_simp [hden, hfactj, hfactn, hqn] - rw [hpow] - ring_nf - rw [← hffR] - ring - -lemma exp_hasSum (t : Real) : HasSum (fun n : Nat => t ^ n / ((fact n : Nat) : Real)) (Real.exp t) := by - have h := NormedSpace.expSeries_div_hasSum_exp (𝕂 := Real) (𝔸 := Real) t - simpa [fact_eq_factorial, Real.exp_eq_exp_ℝ] using h - -lemma expTerm_nonneg {p q : Nat} (hq : 0 < q) (i : Nat) : - 0 ≤ ((p : Real) / q) ^ i / ((fact i : Nat) : Real) := by - have hpq : 0 ≤ (p : Real) / q := by positivity - have hf : 0 ≤ ((fact i : Nat) : Real) := by positivity - exact div_nonneg (pow_nonneg hpq i) hf - -lemma div_le_of_cross_mul_le {a b c d : Real} (hc : 0 < c) (hd : 0 < d) - (h : a * d ≤ b * c) : a / c ≤ b / d := by - by_contra hnot - have hlt : b / d < a / c := lt_of_not_ge hnot - have hlt1 := mul_lt_mul_of_pos_right hlt hc - have hlt2 := mul_lt_mul_of_pos_right hlt1 hd - field_simp [hc.ne', hd.ne'] at hlt2 - nlinarith - -lemma capUB_bound_real {p q y w : Nat} (hq : 0 < q) (hw : 0 < w) - (n : Nat) (h : capUB p q y w) : - (expNum n p q : Real) / ((fact n * q ^ n : Nat) : Real) ≤ (y : Real) / w := by - have hnat := h n - have hreal : (expNum n p q : Real) * (w : Real) ≤ - (y : Real) * ((fact n * q ^ n : Nat) : Real) := by - exact_mod_cast hnat - have hdenpos : 0 < ((fact n * q ^ n : Nat) : Real) := by - exact_mod_cast Nat.mul_pos (fact_pos n) (Nat.pow_pos hq) - have hwpos : 0 < (w : Real) := by exact_mod_cast hw - exact div_le_of_cross_mul_le hdenpos hwpos hreal - -lemma capLB_bound_real {p q y w : Nat} (hq : 0 < q) (hw : 0 < w) - {n : Nat} (h : y * (fact n * q ^ n) ≤ expNum n p q * w) : - (y : Real) / w ≤ (expNum n p q : Real) / ((fact n * q ^ n : Nat) : Real) := by - have hreal : (y : Real) * ((fact n * q ^ n : Nat) : Real) ≤ - (expNum n p q : Real) * (w : Real) := by - exact_mod_cast h - have hdenpos : 0 < ((fact n * q ^ n : Nat) : Real) := by - exact_mod_cast Nat.mul_pos (fact_pos n) (Nat.pow_pos hq) - have hwpos : 0 < (w : Real) := by exact_mod_cast hw - exact div_le_of_cross_mul_le hwpos hdenpos hreal - -lemma exp_le_of_capUB {p q y w : Nat} (hq : 0 < q) (hw : 0 < w) - (h : capUB p q y w) : Real.exp ((p : Real) / q) ≤ (y : Real) / w := by - have hs := exp_hasSum ((p : Real) / q) - rw [← hs.tsum_eq] - refine Summable.tsum_le_of_sum_le hs.summable ?_ - intro s - by_cases hsempty : s.Nonempty - · let N := s.max' hsempty - have hsub : s ⊆ Finset.range (N + 1) := by - intro i hi - exact Finset.mem_range.mpr (Nat.lt_succ.mpr (Finset.le_max' s i hi)) - calc ∑ i ∈ s, ((p : Real) / q) ^ i / ((fact i : Nat) : Real) - ≤ ∑ i ∈ Finset.range (N + 1), ((p : Real) / q) ^ i / ((fact i : Nat) : Real) := by - exact Finset.sum_le_sum_of_subset_of_nonneg hsub (fun i hi his => expTerm_nonneg hq i) - _ = (expNum N p q : Real) / ((fact N * q ^ N : Nat) : Real) := by - rw [expNum_div_eq_sum_range N p q hq] - _ ≤ (y : Real) / w := capUB_bound_real hq hw N h - · have hs0 : s = ∅ := Finset.not_nonempty_iff_eq_empty.mp hsempty - rw [hs0] - simp only [Finset.sum_empty] - exact div_nonneg (Nat.cast_nonneg _) (by positivity) - -lemma le_exp_of_capLB {p q y w : Nat} (hq : 0 < q) (hw : 0 < w) - (h : capLB p q y w) : (y : Real) / w ≤ Real.exp ((p : Real) / q) := by - obtain ⟨n, hn⟩ := h - have hs := exp_hasSum ((p : Real) / q) - rw [← hs.tsum_eq] - calc (y : Real) / w - ≤ (expNum n p q : Real) / ((fact n * q ^ n : Nat) : Real) := capLB_bound_real hq hw hn - _ = ∑ i ∈ Finset.range (n + 1), ((p : Real) / q) ^ i / ((fact i : Nat) : Real) := by - rw [expNum_div_eq_sum_range n p q hq] - _ ≤ ∑' i : Nat, ((p : Real) / q) ^ i / ((fact i : Nat) : Real) := by - exact Summable.sum_le_tsum _ (fun i hi => expTerm_nonneg hq i) hs.summable - lemma QS_pos : 0 < QS := LnFloor.QS_pos lemma ray_exp_arg_of_nonneg {r : Int} (hr : 0 ≤ r) : diff --git a/formal/ln/LnProof/LnProof/Spec/Cut.lean b/formal/ln/LnProof/LnProof/Spec/Cut.lean index fe9c17610..1b7a4aa04 100644 --- a/formal/ln/LnProof/LnProof/Spec/Cut.lean +++ b/formal/ln/LnProof/LnProof/Spec/Cut.lean @@ -1,4 +1,4 @@ -import LnProof.Foundation.ExpSum +import Common.Foundation.ExpSum /-! # Shared exponential/logarithm cut specification @@ -23,7 +23,7 @@ end LnFloor namespace LnFloorCert -open LnExp LnFloor +open Common.Exp LnFloor /-- Cut statement for `exp(p/q) <= y/w`: every exact Taylor partial sum is bounded by the target rational. -/ diff --git a/formal/ln/LnProof/lake-manifest.json b/formal/ln/LnProof/lake-manifest.json index ea840f9cf..d10f195a9 100644 --- a/formal/ln/LnProof/lake-manifest.json +++ b/formal/ln/LnProof/lake-manifest.json @@ -1,134 +1,116 @@ -{ - "version": "1.1.0", - "packagesDir": "../../yul/.lake/packages", - "packages": [ - { - "type": "path", - "scope": "", - "name": "FormalYul", - "manifestFile": "lake-manifest.json", - "inherited": false, - "dir": "../../yul", - "configFile": "lakefile.toml" - }, - { - "type": "path", - "scope": "", - "name": "evmyul", - "manifestFile": "lake-manifest.json", - "inherited": true, - "dir": "../../../lib/EVMYulLean", - "configFile": "lakefile.lean" - }, - { - "url": "https://github.com/leanprover-community/mathlib4.git", - "type": "git", - "subDir": null, - "scope": "", - "rev": "79e94a093aff4a60fb1b1f92d9681e407124c2ca", - "name": "mathlib", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.lean" - }, - { - "url": "https://github.com/leanprover-community/plausible", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "b100ad4c5d74a464f497aaa8e7c74d86bf39a56f", - "name": "plausible", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/LeanSearchClient", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "99657ad92e23804e279f77ea6dbdeebaa1317b98", - "name": "LeanSearchClient", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/import-graph", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "eb164a46de87078f27640ee71e6c3841defc2484", - "name": "importGraph", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/ProofWidgets4", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "1253a071e6939b0faf5c09d2b30b0bfc79dae407", - "name": "proofwidgets", - "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.68", - "inherited": true, - "configFile": "lakefile.lean" - }, - { - "url": "https://github.com/leanprover-community/aesop", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "1256a18522728c2eeed6109b02dd2b8f207a2a3c", - "name": "aesop", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/quote4", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "917bfa5064b812b7fbd7112d018ea0b4def25ab3", - "name": "Qq", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/batteries", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "240676e9568c254a69be94801889d4b13f3b249f", - "name": "batteries", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover/lean4-cli", - "type": "git", - "subDir": null, - "scope": "leanprover", - "rev": "c682c91d2d4dd59a7187e2ab977ac25bd1f87329", - "name": "Cli", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, - "configFile": "lakefile.toml" - } - ], - "name": "LnProof", - "lakeDir": ".lake" -} +{"version": "1.1.0", + "packagesDir": "../../yul/.lake/packages", + "packages": + [{"type": "path", + "scope": "", + "name": "Common", + "manifestFile": "lake-manifest.json", + "inherited": false, + "dir": "../../common", + "configFile": "lakefile.toml"}, + {"type": "path", + "scope": "", + "name": "FormalYul", + "manifestFile": "lake-manifest.json", + "inherited": false, + "dir": "../../yul", + "configFile": "lakefile.toml"}, + {"type": "path", + "scope": "", + "name": "evmyul", + "manifestFile": "lake-manifest.json", + "inherited": true, + "dir": "../../common/../yul/../../lib/EVMYulLean", + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/mathlib4.git", + "type": "git", + "subDir": null, + "scope": "", + "rev": "79e94a093aff4a60fb1b1f92d9681e407124c2ca", + "name": "mathlib", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/plausible", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "b100ad4c5d74a464f497aaa8e7c74d86bf39a56f", + "name": "plausible", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/LeanSearchClient", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "99657ad92e23804e279f77ea6dbdeebaa1317b98", + "name": "LeanSearchClient", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/import-graph", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "eb164a46de87078f27640ee71e6c3841defc2484", + "name": "importGraph", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/ProofWidgets4", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "1253a071e6939b0faf5c09d2b30b0bfc79dae407", + "name": "proofwidgets", + "manifestFile": "lake-manifest.json", + "inputRev": "v0.0.68", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/aesop", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "1256a18522728c2eeed6109b02dd2b8f207a2a3c", + "name": "aesop", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/quote4", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "917bfa5064b812b7fbd7112d018ea0b4def25ab3", + "name": "Qq", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/batteries", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "240676e9568c254a69be94801889d4b13f3b249f", + "name": "batteries", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover/lean4-cli", + "type": "git", + "subDir": null, + "scope": "leanprover", + "rev": "c682c91d2d4dd59a7187e2ab977ac25bd1f87329", + "name": "Cli", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.toml"}], + "name": "LnProof", + "lakeDir": ".lake"} diff --git a/formal/ln/LnProof/lakefile.toml b/formal/ln/LnProof/lakefile.toml index 46a74d1d5..c4b51d8fd 100644 --- a/formal/ln/LnProof/lakefile.toml +++ b/formal/ln/LnProof/lakefile.toml @@ -9,3 +9,7 @@ name = "LnProof" [[require]] name = "FormalYul" path = "../../yul" + +[[require]] +name = "Common" +path = "../../common" From 71f949fbe2635708e2bdafdee2876b8e9519d185 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 11:32:50 +0200 Subject: [PATCH 043/149] Extract shared EVM-word lemmas to `Common.Word`; repoint `ExpProof` The `u256`/`int256` bounds and the `wordNat`-preservation bridges for `sar`/`sdiv`/`slt` (plus the `u256`-idempotence absorbers) were duplicated verbatim between the two proofs. Move them into `Common.Word` and repoint `ExpProof`: - Delete `ExpProof/Seam/RuntimeShared.lean` (whose own header noted it was copied verbatim from `ln`); its importers now `import Common.Word`, and the files that use the lemmas `open Common.Word`. - Delete the orphaned `ExpProof/Foundation/Poly.lean` (an unused verbatim copy of the polynomial certificate checker; the `exp` monotonicity proof carries its own multiplication-monotonicity helpers in `Mono/WordMono`). - Require `Common` in the `ExpProof` lakefile/manifest. `ExpProof` builds green and its `Theorems` axiom gate still pins every public runtime theorem to `[propext, Classical.choice, Quot.sound]`. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/common/Common.lean | 6 +- .../Common/Word.lean} | 17 +- .../ExpProof/ExpProof/Foundation/Poly.lean | 225 ---------------- formal/exp/ExpProof/ExpProof/Mono/Shell.lean | 1 + .../exp/ExpProof/ExpProof/Mono/ShellOn.lean | 1 + formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 1 + .../exp/ExpProof/ExpProof/Mono/WordMono.lean | 3 +- .../ExpProof/ExpProof/Seam/Dispatcher.lean | 2 +- formal/exp/ExpProof/ExpProof/Seam/Guard.lean | 2 +- .../exp/ExpProof/ExpProof/Seam/Helpers.lean | 2 +- formal/exp/ExpProof/ExpProof/Seam/Revert.lean | 2 +- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 3 +- formal/exp/ExpProof/lake-manifest.json | 250 ++++++++---------- formal/exp/ExpProof/lakefile.toml | 4 + 14 files changed, 144 insertions(+), 375 deletions(-) rename formal/{exp/ExpProof/ExpProof/Seam/RuntimeShared.lean => common/Common/Word.lean} (95%) delete mode 100644 formal/exp/ExpProof/ExpProof/Foundation/Poly.lean diff --git a/formal/common/Common.lean b/formal/common/Common.lean index aacbaff83..0a324d72f 100644 --- a/formal/common/Common.lean +++ b/formal/common/Common.lean @@ -3,8 +3,10 @@ -- proofs (`LnProof`, `ExpProof`). Nothing here models any specific -- implementation. It is generic interval-Horner nonnegativity certificates and -- Kronecker identity-testing / packed-shift cell walks (`Common.Poly`), the --- `e^(p/q)` Taylor-cut framework (`Common.Exp`), and the `Real.exp` bridge for --- the partial-sum caps (`Common.RealExpBridge`). +-- `e^(p/q)` Taylor-cut framework (`Common.Exp`), the `Real.exp` bridge for the +-- partial-sum caps (`Common.RealExpBridge`), and the EVM-word op-preservation +-- bridges (`Common.Word`). +import Common.Word import Common.Foundation.Poly import Common.Foundation.ExpSum import Common.Foundation.ShiftCert diff --git a/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean b/formal/common/Common/Word.lean similarity index 95% rename from formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean rename to formal/common/Common/Word.lean index 2688adb06..d5b2a9e97 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/RuntimeShared.lean +++ b/formal/common/Common/Word.lean @@ -1,16 +1,17 @@ import FormalYul.Preservation /-! -# Reusable, contract-agnostic word lemmas for the Exp runtime reduction +# Reusable, contract-agnostic EVM-word lemmas -These facts are general (not specific to `exp`): the `u256`/`int256` bounds and the -`wordNat`-preservation bridges for `sar` and `sdiv` (which `FormalYul.Preservation` does not -provide for signed shifts/division), plus the `u256`-idempotence absorbers for the `evm*` -results. They are used both by the revert proof and the kernel arithmetic reduction. Bodies are -copied verbatim from the `ln` proof's `Seam/RuntimeModel.lean` (they are not `ln`-specific). +Function-agnostic facts about the compiled-runtime word operations: the +`u256`/`int256` bounds, the `wordNat`-preservation bridges for `sar`/`sdiv`/`slt` +(which `FormalYul.Preservation` does not provide for signed shifts/division), +and the `u256`-idempotence absorbers for the `evm*` results. They are used by +the runtime reductions of the per-function proofs and contain nothing specific +to any one implementation. -/ -namespace ExpYul +namespace Common.Word open FormalYul open FormalYul.Preservation @@ -257,4 +258,4 @@ theorem evmSdiv_u256_left (a b : Nat) : evmSdiv (u256 a) b = evmSdiv a b := by theorem evmSdiv_u256_right (a b : Nat) : evmSdiv a (u256 b) = evmSdiv a b := by simp only [evmSdiv, u256_idem] -end ExpYul +end Common.Word diff --git a/formal/exp/ExpProof/ExpProof/Foundation/Poly.lean b/formal/exp/ExpProof/ExpProof/Foundation/Poly.lean deleted file mode 100644 index 64b7eaf8b..000000000 --- a/formal/exp/ExpProof/ExpProof/Foundation/Poly.lean +++ /dev/null @@ -1,225 +0,0 @@ -import Init - -/-! -# Polynomial positivity certificates - -Dense `Int` polynomials (coefficients low-order first), interval-Horner -evaluation over nonnegative domains, and a fuel-bounded adaptive bisection -checker whose `true` result soundly certifies `0 ≤ P(x)` for every integer -`x` in the queried range. The checker is executed by the kernel via `decide`, -so the analytic components of the monotonicity proof reduce to computation. --/ - -namespace ExpPoly - -/-- Multiplication monotonicity helpers (Init-only, so spelled out). -/ -theorem mul_le_mul_left_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : - c * a ≤ c * b := by - have h1 : 0 ≤ c * (b - a) := Int.mul_nonneg hc (by omega) - rw [Int.mul_sub] at h1 - omega - -theorem mul_le_mul_right_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : - a * c ≤ b * c := by - have h1 : 0 ≤ (b - a) * c := Int.mul_nonneg (by omega) hc - rw [Int.sub_mul] at h1 - omega - -theorem mul_le_mul_left_nonpos {a b c : Int} (h : a ≤ b) (hc : c ≤ 0) : - c * b ≤ c * a := by - have h1 : 0 ≤ -c * (b - a) := Int.mul_nonneg (by omega) (by omega) - rw [Int.mul_sub, Int.neg_mul, Int.neg_mul] at h1 - omega - -def evalPoly : List Int → Int → Int - | [], _ => 0 - | c :: cs, x => c + x * evalPoly cs x - -/-- Interval Horner over a nonnegative domain `[lo, hi]`, `0 ≤ lo`. Returns -`(vlo, vhi)` with `vlo ≤ P(x) ≤ vhi` for all `x ∈ [lo, hi]`. -/ -def hornerIv : List Int → Int → Int → Int × Int - | [], _, _ => (0, 0) - | c :: cs, lo, hi => - let (plo, phi) := hornerIv cs lo hi - let mlo := if 0 ≤ plo then lo * plo else hi * plo - let mhi := if 0 ≤ phi then hi * phi else lo * phi - (c + mlo, c + mhi) - -theorem hornerIv_sound (cs : List Int) {lo hi x : Int} - (h0 : 0 ≤ lo) (h1 : lo ≤ x) (h2 : x ≤ hi) : - (hornerIv cs lo hi).1 ≤ evalPoly cs x ∧ evalPoly cs x ≤ (hornerIv cs lo hi).2 := by - induction cs with - | nil => simp [hornerIv, evalPoly] - | cons c cs ih => - obtain ⟨ihlo, ihhi⟩ := ih - simp only [hornerIv, evalPoly] - constructor - · -- lower bound - have hx : 0 ≤ x := by omega - split - · -- 0 ≤ plo : lo * plo ≤ x * plo ≤ x * P(x) - rename_i hplo - have s1 : lo * (hornerIv cs lo hi).1 ≤ x * (hornerIv cs lo hi).1 := - mul_le_mul_right_nonneg h1 hplo - have s2 : x * (hornerIv cs lo hi).1 ≤ x * evalPoly cs x := - mul_le_mul_left_nonneg ihlo hx - omega - · -- plo < 0 : hi * plo ≤ x * plo ≤ x * P(x) - rename_i hplo - have hplo' : (hornerIv cs lo hi).1 ≤ 0 := by omega - have s1 : hi * (hornerIv cs lo hi).1 ≤ x * (hornerIv cs lo hi).1 := by - have hcomm := mul_le_mul_left_nonpos h2 hplo' - rw [Int.mul_comm ((hornerIv cs lo hi).1) hi, - Int.mul_comm ((hornerIv cs lo hi).1) x] at hcomm - exact hcomm - have s2 : x * (hornerIv cs lo hi).1 ≤ x * evalPoly cs x := - mul_le_mul_left_nonneg ihlo hx - omega - · -- upper bound - have hx : 0 ≤ x := by omega - split - · -- 0 ≤ phi : x * P(x) ≤ x * phi ≤ hi * phi - rename_i hphi - have s2 : x * evalPoly cs x ≤ x * (hornerIv cs lo hi).2 := - mul_le_mul_left_nonneg ihhi hx - have s1 : x * (hornerIv cs lo hi).2 ≤ hi * (hornerIv cs lo hi).2 := - mul_le_mul_right_nonneg h2 hphi - omega - · -- phi < 0 : x * P(x) ≤ x * phi ≤ lo * phi - rename_i hphi - have hphi' : (hornerIv cs lo hi).2 ≤ 0 := by omega - have s2 : x * evalPoly cs x ≤ x * (hornerIv cs lo hi).2 := - mul_le_mul_left_nonneg ihhi hx - have s1 : x * (hornerIv cs lo hi).2 ≤ lo * (hornerIv cs lo hi).2 := by - have hcomm := mul_le_mul_left_nonpos h1 hphi' - rw [Int.mul_comm ((hornerIv cs lo hi).2) lo, - Int.mul_comm ((hornerIv cs lo hi).2) x] at hcomm - exact hcomm - omega - -/-- Adaptive bisection: certifies `0 ≤ P(x)` for every integer `x ∈ [lo, hi]`. -/ -def checkNonneg (cs : List Int) (lo hi : Int) : Nat → Bool - | 0 => false - | fuel + 1 => - if hi < lo then true - else if 0 ≤ (hornerIv cs lo hi).1 then true - else if lo = hi then false - else - let mid := (lo + hi) / 2 - checkNonneg cs lo mid fuel && checkNonneg cs (mid + 1) hi fuel - -theorem checkNonneg_sound (cs : List Int) (fuel : Nat) : - ∀ lo hi : Int, 0 ≤ lo → checkNonneg cs lo hi fuel = true → - ∀ x : Int, lo ≤ x → x ≤ hi → 0 ≤ evalPoly cs x := by - induction fuel with - | zero => intro lo hi _ h; simp [checkNonneg] at h - | succ fuel ih => - intro lo hi hlo h x hx1 hx2 - unfold checkNonneg at h - split at h - · omega - · split at h - · rename_i hiv - have := (hornerIv_sound cs hlo hx1 hx2).1 - omega - · split at h - · exact absurd h (by simp) - · rw [Bool.and_eq_true] at h - by_cases hm : x ≤ (lo + hi) / 2 - · exact ih lo ((lo + hi) / 2) hlo h.1 x hx1 hm - · exact ih ((lo + hi) / 2 + 1) hi (by omega) h.2 x (by omega) hx2 - -/-! ## Polynomial algebra (with evaluation lemmas) -/ - -def polyAdd : List Int → List Int → List Int - | [], q => q - | p, [] => p - | a :: p, b :: q => (a + b) :: polyAdd p q - -theorem evalPoly_polyAdd (p q : List Int) (x : Int) : - evalPoly (polyAdd p q) x = evalPoly p x + evalPoly q x := by - induction p generalizing q with - | nil => simp [polyAdd, evalPoly] - | cons a p ih => - cases q with - | nil => simp [polyAdd, evalPoly] - | cons b q => - simp only [polyAdd, evalPoly, ih] - rw [Int.mul_add] - omega - -def polyNeg (p : List Int) : List Int := p.map (-·) - -theorem evalPoly_polyNeg (p : List Int) (x : Int) : - evalPoly (polyNeg p) x = -evalPoly p x := by - induction p with - | nil => simp [polyNeg, evalPoly] - | cons a p ih => - simp only [polyNeg, List.map, evalPoly] at * - rw [ih] - rw [show x * -evalPoly p x = -(x * evalPoly p x) by rw [Int.mul_neg]] - omega - -def polySub (p q : List Int) : List Int := polyAdd p (polyNeg q) - -theorem evalPoly_polySub (p q : List Int) (x : Int) : - evalPoly (polySub p q) x = evalPoly p x - evalPoly q x := by - unfold polySub - rw [evalPoly_polyAdd, evalPoly_polyNeg] - omega - -def polyScale (a : Int) (p : List Int) : List Int := p.map (a * ·) - -theorem evalPoly_polyScale (a : Int) (p : List Int) (x : Int) : - evalPoly (polyScale a p) x = a * evalPoly p x := by - induction p with - | nil => simp [polyScale, evalPoly] - | cons c p ih => - simp only [polyScale, List.map, evalPoly] at * - rw [ih, Int.mul_add] - rw [show x * (a * evalPoly p x) = a * (x * evalPoly p x) by - rw [← Int.mul_assoc, Int.mul_comm x a, Int.mul_assoc]] - -theorem evalPoly_singleton (c x : Int) : evalPoly [c] x = c := by - simp [evalPoly] - -def polyMulX (p : List Int) : List Int := 0 :: p - -theorem evalPoly_polyMulX (p : List Int) (x : Int) : - evalPoly (polyMulX p) x = x * evalPoly p x := by - simp [polyMulX, evalPoly] - -def polyMul : List Int → List Int → List Int - | [], _ => [] - | a :: p, q => polyAdd (polyScale a q) (polyMulX (polyMul p q)) - -theorem evalPoly_polyMul (p q : List Int) (x : Int) : - evalPoly (polyMul p q) x = evalPoly p x * evalPoly q x := by - induction p with - | nil => simp [polyMul, evalPoly] - | cons a p ih => - simp only [polyMul, evalPoly] - rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyMulX, ih] - rw [Int.add_mul] - rw [show x * (evalPoly p x * evalPoly q x) = x * evalPoly p x * evalPoly q x by - rw [Int.mul_assoc]] - -/-- Composition with `x + 1`: `evalPoly (polyCompAdd1 p) x = evalPoly p (x + 1)`. -/ -def polyCompAdd1 : List Int → List Int - | [] => [] - | c :: cs => - let q := polyCompAdd1 cs - polyAdd [c] (polyAdd q (polyMulX q)) - -theorem evalPoly_polyCompAdd1 (p : List Int) (x : Int) : - evalPoly (polyCompAdd1 p) x = evalPoly p (x + 1) := by - induction p with - | nil => simp [polyCompAdd1, evalPoly] - | cons c cs ih => - simp only [polyCompAdd1, evalPoly] - rw [evalPoly_polyAdd, evalPoly_polyAdd, evalPoly_polyMulX, ih] - simp only [evalPoly] - rw [Int.add_mul, Int.one_mul] - omega - -end ExpPoly diff --git a/formal/exp/ExpProof/ExpProof/Mono/Shell.lean b/formal/exp/ExpProof/ExpProof/Mono/Shell.lean index 51e4a1763..5ef91531d 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Shell.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Shell.lean @@ -19,6 +19,7 @@ namespace ExpYul open FormalYul open FormalYul.Preservation +open Common.Word set_option maxRecDepth 100000 diff --git a/formal/exp/ExpProof/ExpProof/Mono/ShellOn.lean b/formal/exp/ExpProof/ExpProof/Mono/ShellOn.lean index aabfb5581..397b9849d 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/ShellOn.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/ShellOn.lean @@ -12,6 +12,7 @@ namespace ExpYul open FormalYul open FormalYul.Preservation +open Common.Word set_option maxRecDepth 100000 diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean index 6fcef64e9..803f0c23e 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -23,6 +23,7 @@ namespace ExpYul open FormalYul open FormalYul.Preservation +open Common.Word set_option maxRecDepth 100000 diff --git a/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean b/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean index 40621c4a3..3dfec4d47 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean @@ -1,4 +1,4 @@ -import ExpProof.Seam.RuntimeShared +import Common.Word /-! # Word-level monotonicity and transport lemmas for the `exp` tree @@ -22,6 +22,7 @@ namespace ExpYul open FormalYul open FormalYul.Preservation +open Common.Word set_option maxRecDepth 100000 diff --git a/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean b/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean index 54d420508..974501fbd 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean @@ -1,5 +1,5 @@ import ExpProof.ExpYulProof -import ExpProof.Seam.RuntimeShared +import Common.Word import ExpProof.Seam.Helpers import FormalYul.Preservation diff --git a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean index f3d0d8659..48b0f2f92 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean @@ -1,4 +1,4 @@ -import ExpProof.Seam.RuntimeShared +import Common.Word /-! # The overflow-guard comparison diff --git a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean index eed889044..8bceb1518 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean @@ -1,5 +1,5 @@ import ExpProof.ExpYulProof -import ExpProof.Seam.RuntimeShared +import Common.Word import FormalYul.Preservation /-! diff --git a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean index ce012c243..b05c9b4f4 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean @@ -1,5 +1,5 @@ import ExpProof.ExpYulProof -import ExpProof.Seam.RuntimeShared +import Common.Word import ExpProof.Seam.Guard import ExpProof.Seam.Helpers import ExpProof.Seam.Dispatcher diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 25d653398..9e94c05cf 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -1,5 +1,5 @@ import ExpProof.ExpYulProof -import ExpProof.Seam.RuntimeShared +import Common.Word import ExpProof.Seam.Helpers import ExpProof.Seam.Guard import ExpProof.Seam.Dispatcher @@ -17,6 +17,7 @@ namespace ExpYul open FormalYul open FormalYul.Preservation +open Common.Word set_option maxRecDepth 100000 diff --git a/formal/exp/ExpProof/lake-manifest.json b/formal/exp/ExpProof/lake-manifest.json index ea840f9cf..f2f7eb5e2 100644 --- a/formal/exp/ExpProof/lake-manifest.json +++ b/formal/exp/ExpProof/lake-manifest.json @@ -1,134 +1,116 @@ -{ - "version": "1.1.0", - "packagesDir": "../../yul/.lake/packages", - "packages": [ - { - "type": "path", - "scope": "", - "name": "FormalYul", - "manifestFile": "lake-manifest.json", - "inherited": false, - "dir": "../../yul", - "configFile": "lakefile.toml" - }, - { - "type": "path", - "scope": "", - "name": "evmyul", - "manifestFile": "lake-manifest.json", - "inherited": true, - "dir": "../../../lib/EVMYulLean", - "configFile": "lakefile.lean" - }, - { - "url": "https://github.com/leanprover-community/mathlib4.git", - "type": "git", - "subDir": null, - "scope": "", - "rev": "79e94a093aff4a60fb1b1f92d9681e407124c2ca", - "name": "mathlib", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.lean" - }, - { - "url": "https://github.com/leanprover-community/plausible", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "b100ad4c5d74a464f497aaa8e7c74d86bf39a56f", - "name": "plausible", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/LeanSearchClient", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "99657ad92e23804e279f77ea6dbdeebaa1317b98", - "name": "LeanSearchClient", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/import-graph", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "eb164a46de87078f27640ee71e6c3841defc2484", - "name": "importGraph", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/ProofWidgets4", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "1253a071e6939b0faf5c09d2b30b0bfc79dae407", - "name": "proofwidgets", - "manifestFile": "lake-manifest.json", - "inputRev": "v0.0.68", - "inherited": true, - "configFile": "lakefile.lean" - }, - { - "url": "https://github.com/leanprover-community/aesop", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "1256a18522728c2eeed6109b02dd2b8f207a2a3c", - "name": "aesop", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/quote4", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "917bfa5064b812b7fbd7112d018ea0b4def25ab3", - "name": "Qq", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover-community/batteries", - "type": "git", - "subDir": null, - "scope": "leanprover-community", - "rev": "240676e9568c254a69be94801889d4b13f3b249f", - "name": "batteries", - "manifestFile": "lake-manifest.json", - "inputRev": "v4.22.0", - "inherited": true, - "configFile": "lakefile.toml" - }, - { - "url": "https://github.com/leanprover/lean4-cli", - "type": "git", - "subDir": null, - "scope": "leanprover", - "rev": "c682c91d2d4dd59a7187e2ab977ac25bd1f87329", - "name": "Cli", - "manifestFile": "lake-manifest.json", - "inputRev": "main", - "inherited": true, - "configFile": "lakefile.toml" - } - ], - "name": "LnProof", - "lakeDir": ".lake" -} +{"version": "1.1.0", + "packagesDir": "../../yul/.lake/packages", + "packages": + [{"type": "path", + "scope": "", + "name": "Common", + "manifestFile": "lake-manifest.json", + "inherited": false, + "dir": "../../common", + "configFile": "lakefile.toml"}, + {"type": "path", + "scope": "", + "name": "FormalYul", + "manifestFile": "lake-manifest.json", + "inherited": false, + "dir": "../../yul", + "configFile": "lakefile.toml"}, + {"type": "path", + "scope": "", + "name": "evmyul", + "manifestFile": "lake-manifest.json", + "inherited": true, + "dir": "../../common/../yul/../../lib/EVMYulLean", + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/mathlib4.git", + "type": "git", + "subDir": null, + "scope": "", + "rev": "79e94a093aff4a60fb1b1f92d9681e407124c2ca", + "name": "mathlib", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/plausible", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "b100ad4c5d74a464f497aaa8e7c74d86bf39a56f", + "name": "plausible", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/LeanSearchClient", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "99657ad92e23804e279f77ea6dbdeebaa1317b98", + "name": "LeanSearchClient", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/import-graph", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "eb164a46de87078f27640ee71e6c3841defc2484", + "name": "importGraph", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/ProofWidgets4", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "1253a071e6939b0faf5c09d2b30b0bfc79dae407", + "name": "proofwidgets", + "manifestFile": "lake-manifest.json", + "inputRev": "v0.0.68", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/aesop", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "1256a18522728c2eeed6109b02dd2b8f207a2a3c", + "name": "aesop", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/quote4", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "917bfa5064b812b7fbd7112d018ea0b4def25ab3", + "name": "Qq", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover-community/batteries", + "type": "git", + "subDir": null, + "scope": "leanprover-community", + "rev": "240676e9568c254a69be94801889d4b13f3b249f", + "name": "batteries", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.22.0", + "inherited": true, + "configFile": "lakefile.toml"}, + {"url": "https://github.com/leanprover/lean4-cli", + "type": "git", + "subDir": null, + "scope": "leanprover", + "rev": "c682c91d2d4dd59a7187e2ab977ac25bd1f87329", + "name": "Cli", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.toml"}], + "name": "ExpProof", + "lakeDir": ".lake"} diff --git a/formal/exp/ExpProof/lakefile.toml b/formal/exp/ExpProof/lakefile.toml index 080004f08..82d3a37dc 100644 --- a/formal/exp/ExpProof/lakefile.toml +++ b/formal/exp/ExpProof/lakefile.toml @@ -9,3 +9,7 @@ name = "ExpProof" [[require]] name = "FormalYul" path = "../../yul" + +[[require]] +name = "Common" +path = "../../common" From aacceb5827164c31ae7dc1f9b4441ce321f2578c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 11:36:26 +0200 Subject: [PATCH 044/149] CI: build `Common` in the ln/exp formal checks Both formal-proof workflows now trigger on `formal/common/**`, cache `formal/common/.lake/build` keyed on the `Common` package files, and the ln certificate-regeneration step builds `Common.Foundation.KroneckerShift` (the module moved out of `LnProof`). `lake build` resolves the local `Common` dependency transitively from each proof package, so no separate fetch step is needed. The `formal/ln` README is updated to match. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/exp-formal.yml | 5 ++++- .github/workflows/ln-formal.yml | 7 +++++-- formal/ln/README.md | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index ac5ef2cc8..2ba7e0163 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -8,6 +8,7 @@ on: - src/vendor/Exp.sol - src/wrappers/ExpWrapper.sol - formal/exp/** + - formal/common/** - formal/yul/** - foundry.toml - remappings.txt @@ -17,6 +18,7 @@ on: - src/vendor/Exp.sol - src/wrappers/ExpWrapper.sol - formal/exp/** + - formal/common/** - formal/yul/** - foundry.toml - remappings.txt @@ -48,8 +50,9 @@ jobs: formal/yul/.lake/build formal/yul/.lake/packages/*/.lake/build lib/EVMYulLean/.lake/build + formal/common/.lake/build formal/exp/ExpProof/.lake/build - key: ${{ runner.os }}-exp-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/exp/ExpProof/lakefile.toml', 'formal/exp/ExpProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/exp/ExpProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} + key: ${{ runner.os }}-exp-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/common/lakefile.toml', 'formal/common/lake-manifest.json', 'formal/common/**/*.lean', 'formal/exp/ExpProof/lakefile.toml', 'formal/exp/ExpProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/exp/ExpProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} restore-keys: | ${{ runner.os }}-exp-formal-lean- ${{ runner.os }}-formal-lean- diff --git a/.github/workflows/ln-formal.yml b/.github/workflows/ln-formal.yml index 01d12a2ce..6aedc488a 100644 --- a/.github/workflows/ln-formal.yml +++ b/.github/workflows/ln-formal.yml @@ -8,6 +8,7 @@ on: - src/vendor/Ln.sol - src/wrappers/LnWrapper.sol - formal/ln/** + - formal/common/** - formal/yul/** - foundry.toml - remappings.txt @@ -17,6 +18,7 @@ on: - src/vendor/Ln.sol - src/wrappers/LnWrapper.sol - formal/ln/** + - formal/common/** - formal/yul/** - foundry.toml - remappings.txt @@ -48,8 +50,9 @@ jobs: formal/yul/.lake/build formal/yul/.lake/packages/*/.lake/build lib/EVMYulLean/.lake/build + formal/common/.lake/build formal/ln/LnProof/.lake/build - key: ${{ runner.os }}-ln-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/ln/LnProof/lakefile.toml', 'formal/ln/LnProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/ln/LnProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} + key: ${{ runner.os }}-ln-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/common/lakefile.toml', 'formal/common/lake-manifest.json', 'formal/common/**/*.lean', 'formal/ln/LnProof/lakefile.toml', 'formal/ln/LnProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/ln/LnProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} restore-keys: | ${{ runner.os }}-ln-formal-lean- ${{ runner.os }}-formal-lean- @@ -98,7 +101,7 @@ jobs: - name: Generate Lean certificate artifacts working-directory: formal/ln/LnProof run: | - lake build LnProof.Floor.CertDefs LnProof.Foundation.KroneckerShift LnProof.Floor.Consts + lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts lake env lean GenFloorCertLit.lean lake build LnProof.Cert.FloorCertLit lake env lean GenCover.lean diff --git a/formal/ln/README.md b/formal/ln/README.md index 3fba08d3a..cea278093 100644 --- a/formal/ln/README.md +++ b/formal/ln/README.md @@ -35,7 +35,7 @@ facade module (`Foundation.lean`, `Spec.lean`, …) re-exporting its public face | Directory | Role | |----------------|------| -| `Foundation/` | Domain-agnostic primitives: EVM-word transport (`Word`, `WordDiv`), `ExpSum` (Taylor partial sums), polynomial/Kronecker cert machinery (`Poly`, `ShiftCert`, `Kronecker`, `KroneckerShift`). | +| `Foundation/` | Domain-agnostic EVM-word transport (`Word`, `WordDiv`). The Taylor partial sums and the polynomial/Kronecker certificate machinery live in the shared `Common` package (`Common.Exp`, `Common.Poly`). | | `Spec/` | What "correct" means: `Real` (the `Real.log` target) and `Cut` (its real-free arithmetization). | | `Model/` | `Body` — the reference implementation (`lnWadToRayBody` / `lnWadBody`). | | `Mono/` | Monotonicity of the model over its domain (`Top` is the entry point). | @@ -69,7 +69,7 @@ The **generated certificates** under `Cert/` (ignored) come from the in-tree generators, run from `formal/ln/LnProof`: ```bash -lake build LnProof.Floor.CertDefs LnProof.Foundation.KroneckerShift LnProof.Floor.Consts +lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts lake env lean GenFloorCertLit.lean lake build LnProof.Cert.FloorCertLit lake env lean GenCover.lean From 1a400a625a5719082990527bec3275ca530f0bfa Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 11:44:49 +0200 Subject: [PATCH 045/149] Add expRayToWad Real.exp floor-bracket spec Public Real.exp target E = 10^18*exp(x/10^27) with the floor brackets for the global never-over/under-by-less-than-two bound, the core-octave exact floor, and the 1-unit underestimate bound with an achieved-witness predicate. Includes the floor facts deriving membership/equality from the brackets and the scale-point checks at E = 10^18 for x = 0. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../exp/ExpProof/ExpProof/Spec/RealExp.lean | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Spec/RealExp.lean diff --git a/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean b/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean new file mode 100644 index 000000000..2757f1ab2 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean @@ -0,0 +1,113 @@ +import Mathlib.Analysis.SpecialFunctions.Exponential +import Mathlib.Algebra.Order.Floor.Defs +import Mathlib.Data.Real.Basic + +/-! +# Public `expRayToWad` real specification + +The public correctness target is a fixed-point bracket around `Real.exp`. The +input `x` is a signed ray-scale exponent (an `int256`, transported here as an +`Int`); the runtime returns the wad-scale value `r` (also an `Int`). The target +is `E = 10^18 · exp(x / 10^27)`. + +The global bracket is 2-wide: `r ≤ E` (never over) together with `E < r + 2` +(under by less than two output units). It pins `r` to `{⌊E⌋, ⌊E⌋ − 1}` and gives +`r ≤ ⌊E⌋`. The central-octave bracket is 1-wide, `r ≤ E ∧ E < r + 1`, which pins +`r = ⌊E⌋`. The one-unit underestimation bound is `r ≥ ⌊E⌋ − 1`, with a separate +achieved-witness predicate for a supported input attaining `r = ⌊E⌋ − 1`. + +These predicates are stated over abstract `r : Int`; the EVM-side modules +discharge them for the runtime result. The arithmetic facts here are +self-contained (Mathlib floor + cast lemmas only). +-/ + +namespace ExpRealSpec + +noncomputable section + +def WAD : Nat := 10 ^ 18 +def RAY : Nat := 10 ^ 27 + +/-- The half-octave bound `H = ⌊10²⁷·ln2/2⌋`; the core octave is `x ∈ [−H, H)`. -/ +def H : Int := 346573590279972654708616060 + +/-- `E = 10^18 · exp(x / 10^27)`, the real target of `expRayToWad`. -/ +def expRayToWadTarget (x : Int) : Real := + (WAD : Real) * Real.exp ((x : Real) / (RAY : Real)) + +/-- **Floor-or-one-less bracket.** The result never exceeds the target and is under it +by strictly less than two output units: `r ≤ E ∧ E < r + 2`. -/ +def FloorOrOneLessBracket (x : Int) (r : Int) : Prop := + (r : Real) ≤ expRayToWadTarget x ∧ expRayToWadTarget x < (r : Real) + 2 + +/-- **Exact-floor bracket (core octave).** On the core octave `x ∈ [−H, H)` +the result is the exact floor: `r ≤ E ∧ E < r + 1`. -/ +def ExactFloorBracket (x : Int) (r : Int) : Prop := + (r : Real) ≤ expRayToWadTarget x ∧ expRayToWadTarget x < (r : Real) + 1 + +/-- **One-unit underestimation bound.** The result underestimates by at most one output +unit: `r ≥ ⌊E⌋ − 1`. -/ +def UnderByAtMostOne (x : Int) (r : Int) : Prop := + ⌊expRayToWadTarget x⌋ - 1 ≤ r + +/-- **One-unit underestimation witness.** Some supported input attains the worst-case +1-unit underestimate `r = ⌊E⌋ − 1` (a `run`-level existence statement; the +predicate carries the runtime result via `result`). -/ +def UnderByOneWitness (supported : Int → Prop) (result : Int → Int) : Prop := + ∃ x : Int, supported x ∧ result x = ⌊expRayToWadTarget x⌋ - 1 + +/-! ## Floor facts: turning the brackets into membership / equality -/ + +/-- A 2-wide never-over bracket forces `r ∈ {⌊E⌋, ⌊E⌋ − 1}`. -/ +theorem floorOrOneLess_mem_floor {x r : Int} (h : FloorOrOneLessBracket x r) : + r = ⌊expRayToWadTarget x⌋ ∨ r = ⌊expRayToWadTarget x⌋ - 1 := by + obtain ⟨hle, hlt⟩ := h + set E := expRayToWadTarget x with hE + have hrle : r ≤ ⌊E⌋ := Int.le_floor.mpr hle + have hfloorlt : (⌊E⌋ : Real) ≤ E := Int.floor_le E + -- `E < r + 2` and `⌊E⌋ ≤ E` give `⌊E⌋ < r + 2`, i.e. `⌊E⌋ ≤ r + 1`. + have hlt2 : (⌊E⌋ : Real) < (r : Real) + 2 := lt_of_le_of_lt hfloorlt hlt + have hlt2' : (⌊E⌋ : Real) < ((r + 2 : Int) : Real) := by push_cast; linarith + have hge : ⌊E⌋ < r + 2 := by exact_mod_cast hlt2' + omega + +/-- The never-over half: `r ≤ ⌊E⌋`. -/ +theorem floorOrOneLess_le_floor {x r : Int} (h : FloorOrOneLessBracket x r) : + r ≤ ⌊expRayToWadTarget x⌋ := + Int.le_floor.mpr h.1 + +/-- A 1-wide never-over bracket forces `r = ⌊E⌋` exactly. -/ +theorem exactFloor_eq_floor {x r : Int} (h : ExactFloorBracket x r) : + r = ⌊expRayToWadTarget x⌋ := by + obtain ⟨hle, hlt⟩ := h + set E := expRayToWadTarget x with hE + have hrle : r ≤ ⌊E⌋ := Int.le_floor.mpr hle + -- `E < r + 1` means `⌊E⌋ ≤ r`. + have hge : ⌊E⌋ ≤ r := by + have hlt' : E < ((r + 1 : Int) : Real) := by push_cast; linarith + have : ⌊E⌋ < r + 1 := Int.floor_lt.mpr hlt' + omega + omega + +/-- The floor-or-one-less bracket implies the one-unit underestimation bound. -/ +theorem floorOrOneLess_to_underByAtMostOne {x r : Int} (h : FloorOrOneLessBracket x r) : + UnderByAtMostOne x r := by + unfold UnderByAtMostOne + rcases floorOrOneLess_mem_floor h with heq | heq <;> omega + +/-! ## Scale point: `x = 0` gives `E = WAD = 10^18` -/ + +theorem expRayToWadTarget_zero : expRayToWadTarget 0 = (WAD : Real) := by + simp [expRayToWadTarget] + +/-- The floor-or-one-less bracket holds at the scale point with the proven result `r = 10^18`. -/ +theorem floorOrOneLess_zero : FloorOrOneLessBracket 0 (10 ^ 18) := by + constructor <;> rw [expRayToWadTarget_zero] <;> simp [WAD] + +/-- The exact-floor bracket holds at the scale point with the proven result `r = 10^18`. -/ +theorem exactFloor_zero : ExactFloorBracket 0 (10 ^ 18) := by + constructor <;> rw [expRayToWadTarget_zero] <;> simp [WAD] + +end + +end ExpRealSpec From c9893d3ec69e65caf816e90c02c0c205a294ec9c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 11:46:08 +0200 Subject: [PATCH 046/149] Add expRayToWad real-free Nat cut predicates Never-over (capUB) and not-two-below (capLB) cuts on the octave-scaled reduced argument exp(t), plus the core-octave-exact variant, over a common denominator. The octave-fold lemmas (capUB_mul/capLB_mul over the ln2 factor) exhibit how the unfolded Taylor caps compose into the folded cuts. Defs + the composition obligation only; the cuts themselves are the Taylor-certificate target. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Spec/Cut.lean | 109 +++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Spec/Cut.lean diff --git a/formal/exp/ExpProof/ExpProof/Spec/Cut.lean b/formal/exp/ExpProof/ExpProof/Spec/Cut.lean new file mode 100644 index 000000000..4c6c9a165 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Spec/Cut.lean @@ -0,0 +1,109 @@ +import Common.Foundation.ExpSum + +/-! +# Real-free `Nat` cut specification for `expRayToWad` + +The runtime reduces `x` to an octave count `k` and a reduced argument +`t ∈ [−ln2/2, ln2/2)`, then forms `exp(x/RAY) = 2^k · exp(t)`. The pre-floor +accumulator is `A = (WAD·r0 − MARGIN)/2^(126−k)` with `r0 = ê(t)·2^126` the +`sdiv` result; the runtime returns `⌊A⌋` (clamped). The correctness brackets +reduce to two rational comparisons on `exp(t)`: + +* a never-over cut — an upper bound `exp(t) ≤ yUB/wUB` — that, after folding the + octave `2^k` and subtracting the margin, gives `A ≤ E`; +* a not-too-low cut — a lower bound `yLB/wLB ≤ exp(t)` — that, after the same + fold, gives `E < A + 1`. + +These are encoded with `Common.Exp.capUB`/`capLB` over a common denominator. The +reduced argument is carried as a rational `t = tNum/tDen` and the octave as a +`Nat` exponent `k`; the negative-`x` branch is the reciprocal cut on `−t`. This +module only *defines* the cut predicates and the octave fold — it does not prove +they hold; the Taylor certificates prove that. No `Real`/Mathlib dependency. +-/ + +namespace ExpFloor + +/-- Common denominator of the reduced exponent argument: the ray scale times the +Q99 headroom the runtime carries (mirrors the `ln` proof's `QS`). -/ +def QS : Nat := 10 ^ 27 * 2 ^ 99 + +theorem QS_pos : 0 < QS := by + unfold QS; exact Nat.mul_pos (Nat.pow_pos (by decide)) (Nat.pow_pos (by decide)) + +def WAD : Nat := 10 ^ 18 + +theorem WAD_pos : 0 < WAD := by unfold WAD; exact Nat.pow_pos (by decide) + +end ExpFloor + +namespace ExpFloorCert + +open Common.Exp ExpFloor + +/-- Upper cut on the reduced argument: `exp(tNum/tDen) ≤ yUB/wUB`, encoded as +`Common.Exp.capUB` (every exact Taylor partial sum is bounded by the target). -/ +def CutExpTaylorLe (tNum tDen yUB wUB : Nat) : Prop := capUB tNum tDen yUB wUB + +/-- Lower cut on the reduced argument: `yLB/wLB ≤ exp(tNum/tDen)`, encoded as +`Common.Exp.capLB` (one exact Taylor partial sum reaches the target). -/ +def CutRatioLeExpTaylor (yLB wLB tNum tDen : Nat) : Prop := capLB tNum tDen yLB wLB + +/-- **Never-over cut.** The reduced-argument exponential, scaled by the octave +`2^k`, stays at or below the rational `yUB/wUB`. The Taylor certificates establish +the base `CutExpTaylorLe` (an upper cap at Taylor depth `K = 27` over the cell that +contains `tNum/tDen`); folding the octave is `capUB_pow`/`capUB_mul`. The +margin/floor step that turns `2^k·exp(t) ≤ yUB/wUB` into `A ≤ E` is a bridge +hypothesis. -/ +def ExpNeverOverCut (tNum tDen k yUB wUB : Nat) : Prop := + capUB (k * tDen + tNum) tDen yUB wUB + +/-- **Not-two-below cut.** The octave-scaled reduced exponential is at or above +the rational `yLB/wLB`. The Taylor certificate establishes the base +`CutRatioLeExpTaylor` (a lower cap at Taylor depth `K = 27`); the octave fold is +`capLB_pow`/`capLB_mul`. The margin/floor step turning `2^k·exp(t) ≥ yLB/wLB` +into `E < A + 1` is a bridge hypothesis. -/ +def ExpNotTwoBelowCut (tNum tDen k yLB wLB : Nat) : Prop := + capLB (k * tDen + tNum) tDen yLB wLB + +/-- **Core-octave exact cut.** On the core octave `k = 0` the never-over and +not-two-below cuts collapse onto the bare reduced argument: an upper cap with +target `yUB/wUB` and a lower cap with target `yLB/wLB` on `exp(tNum/tDen)`. The +1-wide exact-floor bracket follows from these alone (no octave fold; the margin +slack at `k = 0` is negligible). -/ +def CoreOctaveExactCut (tNum tDen yUB wUB yLB wLB : Nat) : Prop := + CutExpTaylorLe tNum tDen yUB wUB ∧ CutRatioLeExpTaylor yLB wLB tNum tDen + +/-! ## Octave fold + +The cut predicates are stated already-folded (`k * tDen + tNum`). The factored +form — a Taylor cap on the reduced argument plus a Taylor cap on `ln2` for the +octave factor `(e^{ln2})^k = 2^k` — composes into the folded cut via the generic +`capUB_mul`/`capUB_pow` (resp. `capLB_*`). These lemmas exhibit that composition +so the Taylor certificates can target the unfolded pieces. `ln2Num/ln2Den ≈ ln 2`. -/ + +/-- A reduced-argument upper cap together with an upper cap on the octave factor +`(e^{ln2Num/ln2Den})^k` (with `ln2Den = tDen`) folds into the never-over cut. -/ +theorem expNeverOverCut_of_fold {tNum tDen k ln2Num yT wT yOct wOct : Nat} + (hq : 0 < tDen) + (hT : CutExpTaylorLe tNum tDen yT wT) + (hOct : capUB (k * ln2Num) tDen (yOct ^ k) (wOct ^ k)) + (hln2 : ln2Num = tDen) : + ExpNeverOverCut tNum tDen k (yT * yOct ^ k) (wT * wOct ^ k) := by + unfold ExpNeverOverCut + subst hln2 + rw [Nat.add_comm] + exact capUB_mul hq hT hOct + +/-- A reduced-argument lower cap together with a lower cap on the octave factor +folds into the not-two-below cut. -/ +theorem expNotTwoBelowCut_of_fold {tNum tDen k ln2Num yT wT yOct wOct : Nat} + (hT : CutRatioLeExpTaylor yT wT tNum tDen) + (hOct : capLB (k * ln2Num) tDen (yOct ^ k) (wOct ^ k)) + (hln2 : ln2Num = tDen) : + ExpNotTwoBelowCut tNum tDen k (yT * yOct ^ k) (wT * wOct ^ k) := by + unfold ExpNotTwoBelowCut + subst hln2 + rw [Nat.add_comm] + exact capLB_mul hT hOct + +end ExpFloorCert From 21c1e1ac46c0a085be669b644261a8cb4aefdfd4 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 11:48:52 +0200 Subject: [PATCH 047/149] Add expRayToWad real bridge from cuts and accumulator to floor brackets Two reductions. Cut-to-Real.exp lemmas turn the folded cuts into Real.exp bounds, with exp_folded_arg exhibiting the multiplicative octave fold (exp 1)^k and the negative-branch reciprocal lemmas (Real.exp_neg). The accumulator bridge lemmas reduce the public brackets to the cut conclusions A <= E / E < A+1 plus the floor step r = floor A, supplied by the certificate and floor layers. Standalone and axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../exp/ExpProof/ExpProof/Seam/RealExp.lean | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Seam/RealExp.lean diff --git a/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean b/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean new file mode 100644 index 000000000..0bc370bc1 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean @@ -0,0 +1,171 @@ +import Mathlib.Analysis.SpecialFunctions.Exponential +import Mathlib.Algebra.Order.Floor.Defs +import Common.Seam.RealExpBridge +import ExpProof.Spec.RealExp +import ExpProof.Spec.Cut + +open scoped BigOperators + +/-! +# `expRayToWad` real bridge + +The bridge from the real-free `Nat` cuts (`ExpProof.Spec.Cut`) to the public +`Real.exp` brackets (`ExpProof.Spec.RealExp`). + +The bridge has two reductions: + +1. *Cut → real exp bound.* `Common.RealExpBridge.exp_le_of_capUB` / + `le_exp_of_capLB` turn a folded `capUB`/`capLB` directly into a `Real.exp` + bound on the cut argument. The octave-folded argument `(k·tDen + tNum)/tDen` + already equals `k·1 + tNum/tDen`, and `exp(k + s) = (e^1)^k · e^s`; but the + tie to `E = WAD·exp(x/RAY)` runs through the runtime's specific octave/argument + constants (the reduced-argument identity `x/RAY = k·ln2 + t`), which the + certificate and floor layers supply. So this reduction is exposed as the standalone + `expBound_of_*Cut` lemmas, and the connection to `E` is taken as a hypothesis. + +2. *Pre-floor accumulator → bracket.* The cut conclusions are the real + inequalities `A ≤ E` (never over) and `E < A + 1` (not two below) on the + pre-floor accumulator `A`; the runtime returns `r = ⌊A⌋` (the `Floor` layer, + after its floor proof). Given those three facts the public brackets follow by + `Int.floor` reasoning. These are the standalone, axiom-clean reduction lemmas + used by the certificate and floor layers. +-/ + +namespace ExpRealBridge + +open Common.Exp Common.RealExpBridge ExpFloor ExpFloorCert ExpRealSpec + +noncomputable section + +/-! ## Cut To A `Real.exp` Bound On The Folded Argument + +The folded cut argument `(k·tDen + tNum)/tDen` splits as `k + tNum/tDen`, so +`exp((k·tDen + tNum)/tDen) = (exp 1)^k · exp(tNum/tDen)` — the multiplicative +octave factor `(e^a)^k` the floor layer folds against the runtime's `2^k` +(with `a = ln2` in the unfolded `ln2`-denominator form). -/ + +/-- The octave fold on the cut argument: an integer step `k` factors out +multiplicatively. -/ +theorem exp_folded_arg {tNum tDen k : Nat} (hq : 0 < tDen) : + Real.exp (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) = + (Real.exp 1) ^ k * Real.exp ((tNum : Real) / (tDen : Real)) := by + have hqne : (tDen : Real) ≠ 0 := by + have : (0 : Real) < (tDen : Real) := by exact_mod_cast hq + exact ne_of_gt this + have harg : (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) = + (k : Real) + (tNum : Real) / (tDen : Real) := by + push_cast + field_simp + rw [harg, Real.exp_add, ← Real.exp_nat_mul, mul_one] + + +/-- The never-over cut yields a real upper bound on the octave-folded +exponential: `exp((k·tDen + tNum)/tDen) ≤ yUB/wUB`. -/ +theorem expBound_of_neverOverCut {tNum tDen k yUB wUB : Nat} + (hq : 0 < tDen) (hw : 0 < wUB) + (hcut : ExpNeverOverCut tNum tDen k yUB wUB) : + Real.exp (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) ≤ (yUB : Real) / wUB := + exp_le_of_capUB hq hw hcut + +/-- The not-two-below cut yields a real lower bound on the octave-folded +exponential: `yLB/wLB ≤ exp((k·tDen + tNum)/tDen)`. -/ +theorem expBound_of_notTwoBelowCut {tNum tDen k yLB wLB : Nat} + (hq : 0 < tDen) (hw : 0 < wLB) + (hcut : ExpNotTwoBelowCut tNum tDen k yLB wLB) : + (yLB : Real) / wLB ≤ Real.exp (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) := + le_exp_of_capLB hq hw hcut + +/-- Core-octave (`k = 0`) upper bound on the bare reduced argument. -/ +theorem expBound_of_coreOctaveExactCut_le {tNum tDen yUB wUB yLB wLB : Nat} + (hq : 0 < tDen) (hw : 0 < wUB) + (hcut : CoreOctaveExactCut tNum tDen yUB wUB yLB wLB) : + Real.exp ((tNum : Real) / (tDen : Real)) ≤ (yUB : Real) / wUB := + exp_le_of_capUB hq hw hcut.1 + +/-- Core-octave (`k = 0`) lower bound on the bare reduced argument. -/ +theorem expBound_of_coreOctaveExactCut_ge {tNum tDen yUB wUB yLB wLB : Nat} + (hq : 0 < tDen) (hw : 0 < wLB) + (hcut : CoreOctaveExactCut tNum tDen yUB wUB yLB wLB) : + (yLB : Real) / wLB ≤ Real.exp ((tNum : Real) / (tDen : Real)) := + le_exp_of_capLB hq hw hcut.2 + +/-! ## Negative-argument reciprocal + +For `x < 0` the runtime reduces `−x` and forms `exp(x/RAY) = 1 / exp(−x/RAY)`. +The lower cap on `exp(−t)` becomes the upper bound the never-over half needs, and +vice versa; `Real.exp_neg` is the bridge. These standalone lemmas expose that +reciprocal so the floor layer can route the negative branch. -/ + +/-- `exp(−s) = 1 / exp(s)`; the reciprocal relating the two sign branches. -/ +theorem exp_neg_eq_inv (s : Real) : Real.exp (-s) = (Real.exp s)⁻¹ := + Real.exp_neg s + +/-- A lower cap on `exp(s)` is an upper bound on `exp(−s)`: if `g/v ≤ exp(s)` and +`g/v > 0` then `exp(−s) ≤ v/g`. -/ +theorem expNeg_le_of_le_exp {s : Real} {g v : Real} (hg : 0 < g) (hv : 0 < v) + (h : g / v ≤ Real.exp s) : Real.exp (-s) ≤ v / g := by + rw [exp_neg_eq_inv] + have hexp_pos : 0 < Real.exp s := Real.exp_pos s + have hgv : (0 : Real) < g / v := div_pos hg hv + rw [inv_le_comm₀ hexp_pos (by positivity)] + calc (v / g) ⁻¹ = g / v := by rw [inv_div] + _ ≤ Real.exp s := h + +/-- An upper cap on `exp(s)` is a lower bound on `exp(−s)`: if `exp(s) ≤ y/w` and +`y/w > 0` then `w/y ≤ exp(−s)`. -/ +theorem le_expNeg_of_exp_le {s : Real} {y w : Real} (hy : 0 < y) (hw : 0 < w) + (h : Real.exp s ≤ y / w) : w / y ≤ Real.exp (-s) := by + rw [exp_neg_eq_inv] + have hexp_pos : 0 < Real.exp s := Real.exp_pos s + rw [le_inv_comm₀ (by positivity) hexp_pos] + calc Real.exp s ≤ y / w := h + _ = (w / y)⁻¹ := by rw [inv_div] + +/-! ## Pre-floor Accumulator To Public Brackets + +`A` is the real pre-floor accumulator and `r = ⌊A⌋` the runtime result (the +`Floor` layer discharges `r = ⌊A⌋`). The cut conclusions are +`A ≤ E` (never over) and `E < A + 1` (not two below). -/ + +/-- **Floor-or-one-less reduction.** From the never-over conclusion `A ≤ E`, the +not-two-below conclusion `E < A + 1`, and the floor step `(r : Real) = ⌊A⌋` (so +`r ≤ A < r + 1`), the global 2-wide bracket holds. -/ +theorem floorOrOneLessBracket_of_accum {x : Int} {r : Int} {A : Real} + (hfloor : (r : Real) ≤ A) (hfloor1 : A < (r : Real) + 1) + (hover : A ≤ expRayToWadTarget x) + (hunder : expRayToWadTarget x < A + 1) : + FloorOrOneLessBracket x r := by + refine ⟨le_trans hfloor hover, ?_⟩ + calc expRayToWadTarget x < A + 1 := hunder + _ < ((r : Real) + 1) + 1 := by linarith + _ = (r : Real) + 2 := by ring + +/-- **Exact-floor reduction.** On the core octave the margin slack is negligible, +so the floor catches `E` exactly: from `r ≤ A`, the never-over `A ≤ E`, and the +sharpened upper bound `E < r + 1`, the 1-wide bracket holds. -/ +theorem exactFloorBracket_of_accum {x : Int} {r : Int} {A : Real} + (hfloor : (r : Real) ≤ A) + (hover : A ≤ expRayToWadTarget x) + (hexact : expRayToWadTarget x < (r : Real) + 1) : + ExactFloorBracket x r := + ⟨le_trans hfloor hover, hexact⟩ + +/-- **One-unit underestimation reduction.** The lower bound `r ≥ ⌊E⌋ − 1` is the +lower half of the floor-or-one-less bracket; given that bracket it follows. -/ +theorem underByAtMostOne_of_floorOrOneLess {x : Int} {r : Int} + (h : FloorOrOneLessBracket x r) : UnderByAtMostOne x r := + floorOrOneLess_to_underByAtMostOne h + +/-- **One-unit underestimation reduction, direct.** From the pre-floor accumulator facts the +1-unit lower bound follows directly. -/ +theorem underByAtMostOne_of_accum {x : Int} {r : Int} {A : Real} + (hfloor : (r : Real) ≤ A) (hfloor1 : A < (r : Real) + 1) + (hover : A ≤ expRayToWadTarget x) + (hunder : expRayToWadTarget x < A + 1) : + UnderByAtMostOne x r := + floorOrOneLess_to_underByAtMostOne + (floorOrOneLessBracket_of_accum hfloor hfloor1 hover hunder) + +end + +end ExpRealBridge From ca4c0c7e781dff3649dd05d704fe3960ecb19646 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 12:13:46 +0200 Subject: [PATCH 048/149] Add exp reduced-argument Taylor cut cert generator and symbolic defs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the `#eval` generator (`GenExpLit.lean`) and the hand-written symbolic cut definitions (`Floor/CertDefs.lean`) for the bare-argument Taylor caps on `exp(t)`. `CertDefs.lean` builds, from the implementation's even/odd coefficients and per-stage shifts (cleared to an exact integer scale), the reduced-argument rational `ê(t) = NUM(t)/DEN(t)`, the margin-nudged targets `ê·(1+2⁻¹²⁰)` / `ê·(1−2⁻¹²⁶)`, and the two `Common.Exp.capUB_of_partial`/`capLB` cut certificate polynomials at Taylor depth K = 27. `GenExpLit.lean` emits the building-block + cert literal lists and walks `[0, H128]` with `checkCoverK` (adaptive `maxW` cells, `kB = 38000`), producing per-cell `decide +kernel` theorems and the symbolic-cert↔literal equality + nonnegativity ladders. Cell counts: never-over 2, not-two-below 3, NUM-nonneg 1, DEN≥1 1 (7 cells total); all build axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../exp/ExpProof/ExpProof/Floor/CertDefs.lean | 124 +++++++++++++++ formal/exp/ExpProof/GenExpLit.lean | 149 ++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/CertDefs.lean create mode 100644 formal/exp/ExpProof/GenExpLit.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefs.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefs.lean new file mode 100644 index 000000000..1b40b9a4e --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/CertDefs.lean @@ -0,0 +1,124 @@ +import Common.Foundation.ShiftCert + +/-! +# The reduced-argument rational target and its Taylor cut certificates + +The runtime forms `r0 = ⌊ê(t)·2^126⌋` with `ê(t) = (Ev(v) + t·Od(v))/(Ev(v) − t·Od(v))`, +`v = t²`, the reciprocal-symmetric rational of the even/odd Horner accumulators. The Taylor certificates +sandwich this rational by `exp(t)` within the runtime margin: they +establishes, over the reduced domain `t ∈ [0, H128]` (the cert variable `t` is the Q128 +reduced argument, `tDen = 2^128`), the two bare-argument Taylor caps + +* never-over `exp(t) ≤ yUB(t)/wUB(t)` (`capUB`), and +* not-two-below `yLB(t)/wLB(t) ≤ exp(t)` (`capLB`), + +where the targets are the *exact* rational `ê(t) = NUM(t)/DEN(t)` (built here from the +implementation's even/odd coefficients, with the common `2^1193` scale cancelling) nudged by a +dyadic margin: `yUB/wUB = ê·(1 + 2⁻¹²⁰)` and `yLB/wLB = ê·(1 − 2⁻¹²⁶)`. The negative-`t` branch +reuses these via the reciprocal bridge; the octave `2^k` fold is handled by the `*_of_fold` lemmas. + +`NUM`/`DEN` are derived from the same `A0..A4`/`B0..B4` even/odd coefficients and per-stage shifts +that `Mono/Tree.lean` reads off the compiled `_expRayToWad`, with every `>>` cleared to an exact +integer scale (`Ev` to `2^1193`, `t·Od` to `2^1170`, then both lifted to the common `2^1193`). The +cert polynomials are the standard `Common.Exp.capUB_of_partial` / `capLB` shapes at Taylor depth +`K = 27` (the depth that resolves `exp(t)` to below the rational's `~2⁻¹³⁰` accuracy on +`|t| ≤ ln2/2`). +-/ + +namespace ExpCert + +open Common.Poly + +/-! ## The reduced-argument denominator and the cert domain -/ + +/-- The reduced-argument denominator `tDen = 2^128`: the runtime carries `t` in Q128. -/ +def Qexp : Nat := 2 ^ 128 + +/-- The cert variable upper bound `H128 = ⌊ln2/2 · 2^128⌋`; the reduced argument satisfies +`0 ≤ t ≤ H128` on the nonnegative half of the core domain. -/ +def H128 : Nat := 117932881612756647068972071382077242199 + +/-! ## Exact integer `ê(t) = NUM(t)/DEN(t)` from the implementation coefficients + +The even/odd Horner accumulators evaluated as exact polynomials in the Q128 integer `t`, with each +runtime `>>sh` cleared to an integer scale. `evNum` accumulates `Ev` to scale `2^1193`; `odNum` +accumulates `Od` to scale `2^1042`; `t·Od` (scale `2^1170`) is lifted by `2^23` to the common +`2^1193`. The shared `2^1193` cancels in `ê = NUM/DEN`, so the scale is immaterial to the cut. -/ + +/-- `t²·P` at the polynomial level. -/ +def mulT2 (P : List Int) : List Int := 0 :: 0 :: P + +/-- The even Horner accumulator `Ev`, cleared to scale `2^1193` (a polynomial in `t`, even +degrees only). The per-stage constants are the even coefficients `A0..A4` lifted by the cleared +shift product. -/ +def evNum : List Int := + polyAdd [0x4e14a45e8ec305e233e11b4174e214ac * 2 ^ 1193] + (mulT2 (polyAdd [0x93f11e65781741b92fa7fc4f4fffcca2 * 2 ^ 933] + (mulT2 (polyAdd [0x9064d965e1c4863b73604e0ddbec53f9 * 2 ^ 671] + (mulT2 (polyAdd [0x9a036222e11aee18465042f8ea64c8 * 2 ^ 415] + (mulT2 (polyAdd [0xb9aacfad41060587203a79af0ebc * 2 ^ 157] [0, 0, 1])))))))) + +/-- The odd Horner accumulator `Od`, cleared to scale `2^1042` (a polynomial in `t`, even degrees +only — the leading `t` factor is applied in `tod`). The per-stage constants are the odd +coefficients `B0..B4`. -/ +def odNum : List Int := + polyAdd [0x270a522f476182f119f08da0ba710a56 * 2 ^ 1042] + (mulT2 (polyAdd [0xaf5662483c4ce783a9ef5fe025f42e9e * 2 ^ 779] + (mulT2 (polyAdd [0xad4506b00b1246c7e5b4fd33e1201b * 2 ^ 524] + (mulT2 (polyAdd [0xc926ddbf3830ca5561cc01585402d0 * 2 ^ 259] + (mulT2 [0xdc07aff85e5bb5629d0fb64a84bb]))))))) + +/-- `t·Od` lifted to the common scale `2^1193` (`= 2^23 · t · odNum`). -/ +def todNum : List Int := polyScale (2 ^ 23) (0 :: odNum) + +/-- `ê`-numerator `NUM(t) = Ev(t) + t·Od(t)` (scale `2^1193`). -/ +def numExp : List Int := polyAdd evNum todNum + +/-- `ê`-denominator `DEN(t) = Ev(t) − t·Od(t)` (scale `2^1193`). -/ +def denExp : List Int := polySub evNum todNum + +/-! ## Taylor partial-sum numerator at the cut argument + +`expN27 = expPolyNum [0,1] [Qexp] 27` evaluates to `expNumI 27 t Qexp` (the integer numerator of the +depth-27 partial sum `S_27(t/Qexp)`). -/ + +/-- Polynomial-level depth-27 partial-sum numerator at argument `t/Qexp`. -/ +def expN27 : List Int := expPolyNum [0, 1] [(Qexp : Int)] 27 + +/-! ## Margin-nudged rational targets + +`yUB/wUB = ê·(1 + 2⁻¹²⁰)` and `yLB/wLB = ê·(1 − 2⁻¹²⁶)`. The numerator margins ride on `NUM`; the +denominator margins are the bare `2^120`/`2^126`. -/ + +def yUB : List Int := polyScale (2 ^ 120 + 1) numExp +def wUB : List Int := polyScale (2 ^ 120) denExp +def yLB : List Int := polyScale (2 ^ 126 - 1) numExp +def wLB : List Int := polyScale (2 ^ 126) denExp + +/-! ## The cut certificate polynomials + +`certExpUp = yUB·(28!·Qexp²⁸) − (expN27·(28·Qexp) + 2·t²⁸)·wUB`, the `capUB_of_partial` residue at +`K = 27`; nonnegativity on a cell gives `capUB t Qexp (yUB t) (wUB t)`. + +`certExpLo = expN27·wLB − yLB·(27!·Qexp²⁷)`, the `capLB` residue at the single partial sum `n = 27`; +nonnegativity gives `capLB t Qexp (yLB t) (wLB t)`. -/ + +/-- `28! · Qexp^28`. -/ +def fact28Q28 : Int := 304888344611713860501504000000 * (Qexp : Int) ^ 28 + +/-- `27! · Qexp^27`. -/ +def fact27Q27 : Int := 10888869450418352160768000000 * (Qexp : Int) ^ 27 + +/-- The `capUB_of_partial` tail polynomial `expN27·(28·Qexp) + 2·t²⁸`. -/ +def tailUp : List Int := + polyAdd (polyScale (28 * (Qexp : Int)) expN27) (polyScale 2 (polyPow [0, 1] 28)) + +def certExpUp : List Int := polySub (polyScale fact28Q28 yUB) (polyMul tailUp wUB) + +def certExpLo : List Int := polySub (polyMul expN27 wLB) (polyScale fact27Q27 yLB) + +/-- `DEN(t) − 1`: nonnegativity over the domain certifies `1 ≤ DEN(t)`, so the rational denominator +is a positive `Nat`. -/ +def certDenM1 : List Int := polyAdd denExp [-1] + +end ExpCert diff --git a/formal/exp/ExpProof/GenExpLit.lean b/formal/exp/ExpProof/GenExpLit.lean new file mode 100644 index 000000000..54a4197a3 --- /dev/null +++ b/formal/exp/ExpProof/GenExpLit.lean @@ -0,0 +1,149 @@ +import ExpProof.Floor.CertDefs +import Common.Foundation.KroneckerShift + +/-! +# Cert literal + cover generator for the reduced-argument Taylor caps + +Computes the never-over (`certExpUp`) and not-two-below (`certExpLo`) certificate polynomials from +the symbolic `ExpCert` definitions, emits all the building-block + cert literal coefficient lists +(`Cert/ExpCertLit.lean`), then greedily walks `[0, H128]` for each — at every anchor `a` taking the +largest cell width `w` with `0 ≤ (hornerIv (kShiftWitness kB C a) 0 w).1`, exactly the predicate the +in-kernel `checkCoverK` decides — and writes one `Cert/Exp{Up,Lo}C.lean` cell file per sub-cell +plus the cover module (`Cert/ExpUp.lean`/`Cert/ExpLo.lean`) with the symbolic-cert↔literal equality +and the `_nonneg` ladder. + +Run with `lake env lean GenExpLit.lean` after `lake build ExpProof.Floor.CertDefs`. Output is +deterministic (byte-identical on re-run). Only the generated `Cert/*` files are machine output; this +generator and the hand-written `Floor/CertDefs.lean` symbolic definitions are tracked. +-/ + +open Common.Poly ExpCert + +namespace GenExpLit + +/-- Drop trailing zero coefficients. -/ +def ptrim (a : List Int) : List Int := + let r := (a.reverse.dropWhile (· == 0)).reverse + if r.isEmpty then [0] else r + +/-- Largest `w ∈ [0, hiW]` with `0 ≤ (hornerIv S 0 w).1` (non-increasing in `w`). -/ +partial def maxW (S : List Int) (hiW : Int) : Int := + let rec bs (lo hi : Int) : Int := + if lo ≥ hi then lo + else let mid := (lo + hi + 1) / 2 + if 0 ≤ (hornerIv S 0 mid).1 then bs mid hi else bs lo (mid - 1) + bs 0 hiW + +/-- Greedy walk → `(reached?, (anchor, width) list)`. -/ +partial def walk (C : List Int) (lo hi : Int) : Bool × List (Int × Int) := + let rec go (a : Int) (fuel : Nat) (acc : List (Int × Int)) : Bool × List (Int × Int) := + match fuel with + | 0 => (false, acc.reverse) + | fuel + 1 => + if a > hi then (true, acc.reverse) + else + let S := kShiftWitness kB C a + if 0 ≤ (hornerIv S 0 0).1 then + let w := maxW S (hi - a) + go (a + w + 1) fuel ((a, w) :: acc) + else (false, ((a, -1) :: acc).reverse) + go lo 200000 [] + +def pad2 (i : Nat) : String := (if i < 10 then "0" else "") ++ toString i + +/-- Walk `[lo, hi]`, write one cell file per sub-cell, then write the cover module: the cell +imports, the symbolic-cert↔literal equality `{certEqName}` (built by rewriting the building-block +literals so the kernel never has to whnf the full symbolic construction), the `{litNonneg}` cell +ladder over the literal, and `{symNonneg}` lifting it to the symbolic cert. `eqTac` rewrites the +symbolic cert to its literal via the block equalities. -/ +def emit (litName coverMod modPrefix cellPrefix certEqName litNonneg symNonneg symName eqTac : String) + (C : List Int) (lo hi : Int) : IO Unit := do + let (ok, cells) := walk C lo hi + IO.println s!"-- {coverMod}: reached={ok} ncells={cells.length}" + if ! ok then IO.println s!"-- FAILED tail: {cells.drop (cells.length - 2)}"; return + for (aw, i) in cells.zipIdx do + let (a, w) := aw + IO.FS.writeFile s!"ExpProof/Cert/{modPrefix}{pad2 i}.lean" + s!"import ExpProof.Cert.ExpCertLit\nimport Common.Foundation.KroneckerShift\n\nnamespace ExpCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{pad2 i} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend ExpCert\n" + let lb := "{"; let rb := "}" + let mut s := "import ExpProof.Floor.CertDefs\nimport ExpProof.Cert.ExpCertLit\nimport Common.Foundation.KroneckerShift\n" + for (_, i) in cells.zipIdx do s := s ++ s!"import ExpProof.Cert.{modPrefix}{pad2 i}\n" + s := s ++ s!"\nnamespace ExpCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\n" + -- the symbolic cert equals the emitted literal: rewrite the building blocks to their + -- literals (each shallow enough for the kernel), then the residual `polyMul`/`polySub`/ + -- `polyScale` is over literal lists and reduces by `decide +kernel`. + s := s ++ s!"theorem {certEqName} : {symName} = {litName} := by\n{eqTac}\n\n" + -- the cell ladder over the literal + s := s ++ s!"theorem {litNonneg} {lb}t : Int{rb} (h1 : {lo} ≤ t) (h2 : t ≤ {hi}) :\n" + s := s ++ s!" 0 ≤ evalPoly {litName} t := by\n" + let n := cells.length + for (aw, i) in cells.zipIdx do + let (a, w) := aw + if i + 1 < n then + s := s ++ s!" rcases Int.lt_or_le t ({a + w} + 1) with h | h\n · exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} t (by omega) (by omega)\n" + else + s := s ++ s!" exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} t (by omega) h2\n" + -- lift to the symbolic cert + s := s ++ s!"\ntheorem {symNonneg} {lb}t : Int{rb} (h1 : {lo} ≤ t) (h2 : t ≤ {hi}) :\n" + s := s ++ s!" 0 ≤ evalPoly {symName} t := by\n rw [{certEqName}]; exact {litNonneg} h1 h2\n" + s := s ++ "\nend ExpCert\n" + IO.FS.writeFile s!"ExpProof/Cert/{coverMod}.lean" s + +def litText (name : String) (c : List Int) : String := + "def " ++ name ++ " : List Int := [\n " ++ + String.intercalate ",\n " (c.map toString) ++ "]\n\n" + +end GenExpLit + +open GenExpLit + +/-- Tactic block proving `certExpUp = certExpUpLit`. -/ +def upEqTac : String := + " have hy : yUB = yUBLit := by unfold yUB numExp evNum todNum odNum mulT2; decide +kernel\n" ++ + " have hw : wUB = wUBLit := by unfold wUB denExp evNum todNum odNum mulT2; decide +kernel\n" ++ + " have ht : tailUp = tailUpLit := by unfold tailUp expN27; decide +kernel\n" ++ + " unfold certExpUp\n rw [hy, hw, ht]\n decide +kernel" + +/-- Tactic block proving `certExpLo = certExpLoLit`. -/ +def loEqTac : String := + " have he : expN27 = expN27Lit := by unfold expN27; decide +kernel\n" ++ + " have hy : yLB = yLBLit := by unfold yLB numExp evNum todNum odNum mulT2; decide +kernel\n" ++ + " have hw : wLB = wLBLit := by unfold wLB denExp evNum todNum odNum mulT2; decide +kernel\n" ++ + " unfold certExpLo\n rw [he, hy, hw]\n decide +kernel" + +/-- Tactic block proving `numExp = numExpLit`. -/ +def numEqTac : String := + " unfold numExp evNum todNum odNum mulT2\n decide +kernel" + +/-- Tactic block proving `certDenM1 = certDenM1Lit`. -/ +def denM1EqTac : String := + " unfold certDenM1 denExp evNum todNum odNum mulT2\n decide +kernel" + +#eval do + let cUp := ptrim certExpUp + let cLo := ptrim certExpLo + -- the building-block literals (degree ≤ 27) the cert-equality proofs rewrite through, plus + -- the cert/denominator literals the cells reference. + IO.FS.writeFile "ExpProof/Cert/ExpCertLit.lean" + ("/-! Generated cut-certificate literal coefficient lists. -/\n\nnamespace ExpCert\n\n" ++ + litText "numExpLit" (ptrim numExp) ++ + litText "denExpLit" (ptrim denExp) ++ + litText "expN27Lit" (ptrim expN27) ++ + litText "tailUpLit" (ptrim tailUp) ++ + litText "yUBLit" (ptrim yUB) ++ + litText "wUBLit" (ptrim wUB) ++ + litText "yLBLit" (ptrim yLB) ++ + litText "wLBLit" (ptrim wLB) ++ + litText "certDenM1Lit" (ptrim certDenM1) ++ + litText "certExpUpLit" cUp ++ + litText "certExpLoLit" cLo ++ + "end ExpCert\n") + IO.println "literals written" + emit "certExpUpLit" "ExpUp" "ExpUpC" "expUp_cell" "certExpUp_eq" "expUpLit_nonneg" + "expUp_nonneg" "certExpUp" upEqTac cUp 0 (H128 : Int) + emit "certExpLoLit" "ExpLo" "ExpLoC" "expLo_cell" "certExpLo_eq" "expLoLit_nonneg" + "expLo_nonneg" "certExpLo" loEqTac cLo 0 (H128 : Int) + emit "numExpLit" "ExpNum" "ExpNumC" "expNum_cell" "numExp_eq" "numExpLit_nonneg" + "numExp_nonneg" "numExp" numEqTac (ptrim numExp) 0 (H128 : Int) + emit "certDenM1Lit" "ExpDenM1" "ExpDenM1C" "denM1_cell" "certDenM1_eq" "denM1Lit_nonneg" + "denM1_nonneg" "certDenM1" denM1EqTac (ptrim certDenM1) 0 (H128 : Int) From 3a79e2d0e65dbef6ad0aef87fd3b682da00c2c99 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 12:20:46 +0200 Subject: [PATCH 049/149] Add exp reduced-argument Taylor cap bridge (Floor/Caps.lean) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converts the cell-cover certificate nonnegativity (`Cert/Exp{Up,Lo,Num,DenM1}`) into the bare-argument Taylor caps the floor layer folds with the octave `2^k`. `capUB27_of_int`/`capLB27_of_int` are the depth-K=27 `Common.Exp.capUB_of_partial` / `capLB` Int→Nat bridges (precomputing `28!`/`27!`). The eval-shape lemmas expand each cert polynomial to the exact cap residue in the rational targets, and `denExp_ge_one`/`numExp_nonneg'` give the rational positivity. The result: * `cutExpTaylorLe_holds` — `ExpFloorCert.CutExpTaylorLe t Qexp (yUB t) (wUB t)` (never-over `exp(t) ≤ ê·(1 + 2⁻¹²⁰)`); * `cutRatioLeExpTaylor_holds` — `ExpFloorCert.CutRatioLeExpTaylor (yLB t) (wLB t) t Qexp` (not-two-below `ê·(1 − 2⁻¹²⁶) ≤ exp(t)`), for every reduced argument `t ∈ [0, H128]` (the nonnegative half of the core domain; the negative branch reuses these via the reciprocal branch), with `Qexp = 2^128`. Both are axiom-clean ({propext, Classical.choice, Quot.sound}), enforced by in-file `#guard_msgs` axiom gates. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Floor/Caps.lean | 229 +++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/Caps.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/Caps.lean b/formal/exp/ExpProof/ExpProof/Floor/Caps.lean new file mode 100644 index 000000000..630511016 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/Caps.lean @@ -0,0 +1,229 @@ +import Mathlib.Tactic.NormNum +import Mathlib.Tactic.Ring +import Mathlib.Tactic.Positivity +import Mathlib.Algebra.Order.Floor.Defs +import ExpProof.Cert.ExpUp +import ExpProof.Cert.ExpLo +import ExpProof.Cert.ExpNum +import ExpProof.Cert.ExpDenM1 +import ExpProof.Spec.Cut + +/-! +# From cell certificates to the reduced-argument Taylor caps + +The cell covers (`Cert/ExpUp`, `Cert/ExpLo`, `Cert/ExpNum`, `Cert/ExpDenM1`) certify the four +certificate polynomials nonnegative over `t ∈ [0, H128]`. This module converts that nonnegativity +into the two bare-argument Taylor caps the floor layer folds with `2^k`: + +* `cutExpTaylorLe_holds` — `CutExpTaylorLe t Qexp (yUB t) (wUB t)` (never-over `exp(t) ≤ ê·(1+2⁻¹²⁰)`); +* `cutRatioLeExpTaylor_holds` — `CutRatioLeExpTaylor (yLB t) (wLB t) t Qexp` + (not-two-below `ê·(1−2⁻¹²⁶) ≤ exp(t)`), + +for every reduced argument `t ∈ [0, H128]` (the nonnegative half of the core domain; the negative +branch reuses these via the reciprocal branch). The targets are the implementation's exact rational +`ê(t) = NUM(t)/DEN(t)` nudged by the dyadic margin, with `Qexp = 2^128` the reduced-argument +denominator. + +The bridge is the depth-`K = 27` `Common.Exp.capUB_of_partial`/`capLB` shape, exactly mirroring the +`ln` proof's `capUB22_of_int`/`capLB22_of_int` at the deeper Taylor depth `exp`'s wider argument +window requires. +-/ + +namespace ExpCert + +open Common.Poly Common.Exp ExpFloorCert + +set_option maxRecDepth 100000 + +/-! ## The two Int→Nat cap bridges at Taylor depth `K = 27` -/ + +/-- One evaluated partial sum (depth 27) plus the geometric tail gives a full upper cap. -/ +theorem capUB27_of_int {tn td y w : Nat} (htd : 0 < td) (hH : 2 * tn ≤ 29 * td) + (h : (expNumI 27 (tn : Int) (td : Int) * (28 * (td : Int)) + 2 * (tn : Int) ^ 28) * + (w : Int) ≤ (y : Int) * (304888344611713860501504000000 * (td : Int) ^ 28)) : + capUB tn td y w := by + refine capUB_of_partial htd (by omega : 2 * tn ≤ (27 + 2) * td) ?_ + show (expNum 27 tn td * ((27 + 1) * td) + 2 * tn ^ (27 + 1)) * w ≤ y * (fact 28 * td ^ 28) + rw [show fact 28 = 304888344611713860501504000000 from by decide, + show (27 + 1) = 28 from rfl] + refine Int.ofNat_le.mp ?_ + rw [expNumI_eq_expNum] at h + simp only [Int.natCast_mul, Int.natCast_add, Int.natCast_pow] + exact h + +/-- The single depth-27 partial sum reaches the lower target. -/ +theorem capLB27_of_int {tn td y w : Nat} + (h : (y : Int) * (10888869450418352160768000000 * (td : Int) ^ 27) ≤ + expNumI 27 (tn : Int) (td : Int) * (w : Int)) : + capLB tn td y w := by + refine ⟨27, ?_⟩ + show y * (fact 27 * td ^ 27) ≤ expNum 27 tn td * w + rw [show fact 27 = 10888869450418352160768000000 from by decide] + refine Int.ofNat_le.mp ?_ + rw [expNumI_eq_expNum] at h + simp only [Int.natCast_mul, Int.natCast_pow] + exact h + +/-! ## Evaluation shapes of the certificate polynomials + +`expN27` evaluates to the depth-27 partial-sum numerator; the cert polynomials expand to the exact +`capUB_of_partial`/`capLB` residues in the rational targets. -/ + +theorem evalExpN27 (t : Int) : evalPoly expN27 t = expNumI 27 t (Qexp : Int) := by + unfold expN27 + rw [evalPoly_expPolyNum] + congr 1 <;> simp [evalPoly] + +theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 120 + 1) * evalPoly numExp t := by + unfold yUB; rw [evalPoly_polyScale] + +theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 120 * evalPoly denExp t := by + unfold wUB; rw [evalPoly_polyScale] + +theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 126 - 1) * evalPoly numExp t := by + unfold yLB; rw [evalPoly_polyScale] + +theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 126 * evalPoly denExp t := by + unfold wLB; rw [evalPoly_polyScale] + +theorem evalTailUp (t : Int) : + evalPoly tailUp t = 28 * (Qexp : Int) * expNumI 27 t (Qexp : Int) + 2 * t ^ 28 := by + unfold tailUp + rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyScale, evalPoly_polyPow, evalExpN27] + congr 1 + show _ = 2 * t ^ 28 + rw [show evalPoly ([0, 1] : List Int) t = t from by simp [evalPoly]] + +/-- The never-over cert evaluates to the `capUB27_of_int` residue. -/ +theorem evalCertExpUp (t : Int) : + evalPoly certExpUp t = + fact28Q28 * evalPoly yUB t - + (28 * (Qexp : Int) * expNumI 27 t (Qexp : Int) + 2 * t ^ 28) * evalPoly wUB t := by + unfold certExpUp + rw [evalPoly_polySub, evalPoly_polyScale, evalPoly_polyMul, evalTailUp] + +/-- The not-two-below cert evaluates to the `capLB27_of_int` residue. -/ +theorem evalCertExpLo (t : Int) : + evalPoly certExpLo t = + expNumI 27 t (Qexp : Int) * evalPoly wLB t - fact27Q27 * evalPoly yLB t := by + unfold certExpLo + rw [evalPoly_polySub, evalPoly_polyMul, evalPoly_polyScale, evalExpN27] + +/-! ## Positivity of the rational over the domain -/ + +/-- `1 ≤ DEN(t)` over the domain (the rational denominator is a positive `Nat`). -/ +theorem denExp_ge_one {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + 1 ≤ evalPoly denExp t := by + have h := denM1_nonneg h1 h2 + unfold certDenM1 at h + rw [evalPoly_polyAdd] at h + rw [show evalPoly ([-1] : List Int) t = -1 from by simp [evalPoly]] at h + omega + +/-- `0 ≤ NUM(t)` over the domain. -/ +theorem numExp_nonneg' {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + 0 ≤ evalPoly numExp t := numExp_nonneg h1 h2 + +/-! ## The bare-argument Taylor caps + +`Qexp = 2^128` is positive, `t.toNat`/the rational targets cast back to themselves on the domain, +and the certificate residues are exactly the `capUB27_of_int`/`capLB27_of_int` hypotheses. -/ + +theorem Qexp_eq : (Qexp : Int) = 2 ^ 128 := by unfold Qexp; norm_num + +theorem Qexp_pos : 0 < Qexp := by unfold Qexp; norm_num + +/-- **Never-over cap** at the rational `yUB/wUB = ê·(1 + 2⁻¹²⁰)`: for every reduced argument +`t ∈ [0, H128]`, `exp(t/Qexp) ≤ yUB(t)/wUB(t)`. -/ +theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + capUB t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := by + have hnum : 0 ≤ evalPoly numExp t := numExp_nonneg h1 h2 + have hden : 1 ≤ evalPoly denExp t := denExp_ge_one h1 h2 + have hden0 : 0 ≤ evalPoly denExp t := by omega + have hc120 : (0 : Int) ≤ 2 ^ 120 + 1 := by norm_num + have hp120 : (0 : Int) ≤ 2 ^ 120 := by norm_num + have hyub : 0 ≤ evalPoly yUB t := by + rw [evalYUB]; exact Int.mul_nonneg hc120 hnum + have hwub : 0 ≤ evalPoly wUB t := by + rw [evalWUB]; exact Int.mul_nonneg hp120 hden0 + have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 + have hyn : ((evalPoly yUB t).toNat : Int) = evalPoly yUB t := Int.toNat_of_nonneg hyub + have hwn : ((evalPoly wUB t).toNat : Int) = evalPoly wUB t := Int.toNat_of_nonneg hwub + refine capUB27_of_int Qexp_pos ?_ ?_ + · -- `2·t.toNat ≤ 29·Qexp`: `t.toNat ≤ H128 < Qexp = 2^128` + have htle : t.toNat ≤ H128 := by + have : (t.toNat : Int) ≤ (H128 : Int) := by rw [htn]; exact h2 + exact_mod_cast this + have hHQ : 2 * H128 < 29 * Qexp := by unfold H128 Qexp; norm_num + omega + · -- the cert residue is the `capUB27_of_int` hypothesis + rw [htn, hyn, hwn, Qexp_eq] + have h := expUp_nonneg h1 h2 + rw [evalCertExpUp] at h + unfold fact28Q28 at h + rw [Qexp_eq] at h + -- `0 ≤ A·yUB − tail·wUB ⟹ tail·wUB ≤ A·yUB` + have key : (28 * (2 : Int) ^ 128 * expNumI 27 t (2 ^ 128) + 2 * t ^ 28) * evalPoly wUB t ≤ + 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := by omega + -- match the `capUB27_of_int` shape `... ≤ y·(C·td^28)` + calc (expNumI 27 t (2 ^ 128) * (28 * (2 : Int) ^ 128) + 2 * t ^ 28) * evalPoly wUB t + = (28 * (2 : Int) ^ 128 * expNumI 27 t (2 ^ 128) + 2 * t ^ 28) * evalPoly wUB t := by ring + _ ≤ 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := key + _ = evalPoly yUB t * (304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28) := by ring + +/-- **Not-two-below cap** at the rational `yLB/wLB = ê·(1 − 2⁻¹²⁶)`: for every reduced argument +`t ∈ [0, H128]`, `yLB(t)/wLB(t) ≤ exp(t/Qexp)`. -/ +theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + capLB t.toNat Qexp (evalPoly yLB t).toNat (evalPoly wLB t).toNat := by + have hnum : 0 ≤ evalPoly numExp t := numExp_nonneg h1 h2 + have hden : 1 ≤ evalPoly denExp t := denExp_ge_one h1 h2 + have hden0 : 0 ≤ evalPoly denExp t := by omega + have hc126 : (0 : Int) ≤ 2 ^ 126 - 1 := by norm_num + have hp126 : (0 : Int) ≤ 2 ^ 126 := by norm_num + have hylb : 0 ≤ evalPoly yLB t := by + rw [evalYLB]; exact Int.mul_nonneg hc126 hnum + have hwlb : 0 ≤ evalPoly wLB t := by + rw [evalWLB]; exact Int.mul_nonneg hp126 hden0 + have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 + have hyn : ((evalPoly yLB t).toNat : Int) = evalPoly yLB t := Int.toNat_of_nonneg hylb + have hwn : ((evalPoly wLB t).toNat : Int) = evalPoly wLB t := Int.toNat_of_nonneg hwlb + refine capLB27_of_int ?_ + rw [htn, hyn, hwn, Qexp_eq] + have h := expLo_nonneg h1 h2 + rw [evalCertExpLo] at h + unfold fact27Q27 at h + rw [Qexp_eq] at h + -- `0 ≤ expN27·wLB − C·yLB ⟹ C·yLB ≤ expN27·wLB` + calc evalPoly yLB t * (10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27) + = 10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27 * evalPoly yLB t := by ring + _ ≤ expNumI 27 t (2 ^ 128) * evalPoly wLB t := by omega + +/-! ## The bare-argument Taylor caps as cut predicates + +`ExpFloorCert.CutExpTaylorLe`/`CutRatioLeExpTaylor` are definitionally `capUB`/`capLB`, so the two +caps above are exactly the never-over and not-two-below cuts on the reduced argument. These are the +bare-argument caps for every reduced `t` in the nonnegative half of the core domain; the octave-fold +lemmas compose them with `2^k` (via `expNeverOverCut_of_fold` / `expNotTwoBelowCut_of_fold`) and +bridge to the runtime accumulator. -/ + +/-- **Never-over Taylor cut.** For every reduced argument `t ∈ [0, H128]`, +`exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê(t)·(1 + 2⁻¹²⁰)`. -/ +theorem cutExpTaylorLe_holds {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + CutExpTaylorLe t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := + capExpUp h1 h2 + +/-- **Not-two-below Taylor cut.** For every reduced argument `t ∈ [0, H128]`, +`yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê(t)·(1 − 2⁻¹²⁶)`. -/ +theorem cutRatioLeExpTaylor_holds {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + CutRatioLeExpTaylor (evalPoly yLB t).toNat (evalPoly wLB t).toNat t.toNat Qexp := + capExpLo h1 h2 + +/-- info: 'ExpCert.cutExpTaylorLe_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms cutExpTaylorLe_holds + +/-- info: 'ExpCert.cutRatioLeExpTaylor_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms cutRatioLeExpTaylor_holds + +end ExpCert From f9b201ef1e4417f07c5a039bc4621738c1c2bc05 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 12:21:42 +0200 Subject: [PATCH 050/149] Regenerate + verify exp cut certs in CI Add the cert-generation step to `exp-formal.yml` (mirroring `ln-formal.yml`): build the symbolic cut definitions, run the `#eval` generator to (re)emit the gitignored `Cert/*` literals and cell covers, then the full `lake build` recompiles them and runs the axiom gates. The generated output is deterministic (byte-identical on re-run), so CI verifies the checked-in proof against freshly regenerated certs. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/exp-formal.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index 2ba7e0163..daa5afc87 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -98,6 +98,12 @@ jobs: .lake/packages/proofwidgets/.lake/build/ir lake exe cache get + - name: Generate Lean certificate artifacts + working-directory: formal/exp/ExpProof + run: | + lake build ExpProof.Floor.CertDefs Common.Foundation.KroneckerShift + lake env lean GenExpLit.lean + - name: Build Exp proof package working-directory: formal/exp/ExpProof run: lake build From d4f494623b60545b217268dec4da0c094c3edeac Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 12:41:25 +0200 Subject: [PATCH 051/149] Add exp floor brackets and worst-case comment The floor + clamp/pin branch assembly reduces the public Real.exp brackets (global never-over + under-by-less-than-two, core-octave exact floor, and one-unit underestimation) to a single analytic obligation RuntimeAccumBound: the real pre-floor accumulator brackets E. The closing-shift floor (r = floor(A) via the evmSar sandwich), the clamp/pin shell branch split, and the scale-point cross-check are all proved directly and axiom-clean. RuntimeAccumBound carries the cert-fold + truncation bridge, mirroring how run_exp_ray_to_wad_evm_mono carries RegionMonotonicityFacts. Exp.sol gains the worst-case-error clause (the 1-ulp underestimate is achieved, floor-2 never occurs). Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../exp/ExpProof/ExpProof/Floor/Public.lean | 127 ++++++++++++ formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 190 ++++++++++++++++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 46 +++++ src/vendor/Exp.sol | 6 +- 4 files changed, 367 insertions(+), 2 deletions(-) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/Public.lean create mode 100644 formal/exp/ExpProof/ExpProof/Floor/Spec.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/Public.lean b/formal/exp/ExpProof/ExpProof/Floor/Public.lean new file mode 100644 index 000000000..754df653d --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/Public.lean @@ -0,0 +1,127 @@ +import ExpProof.Floor.Spec +import ExpProof.Mono + +/-! +# Public floor-bracket theorems for the compiled runtime + +Assembling the floor brackets (`Floor.Spec`, given `RuntimeAccumBound`) and the clamp/pin shell +(`Mono.Shell`/`Mono.ShellOn`) into run-level statements about `run_exp_ray_to_wad_evm`. + +The result word `expTree x` decomposes by the clamp boundary: + +* `x = 0` — the scale point, `expTree 0 = 10¹⁸`; the brackets hold by the scale-point lemmas; +* `int256 x ≤ int256 Cmask` — below the 0/1 boundary, `expTree x = 0` and `E < 1`, so the global + bracket holds with `r = 0`; +* the meaningful region with `x ≠ 0` — `int256 (expTree x) = int256 (r1Tree x)` (the clamp is + transparent and the pin does not fire), so the `Floor.Spec` region brackets transport directly. + +Each public theorem is stated on the runtime result `r` with `run_exp_ray_to_wad_evm x = .ok r`, +and carries the single analytic obligation `RuntimeAccumBound` (the cert-fold + truncation bridge), +exactly as `run_exp_ray_to_wad_evm_mono` carries `RegionMonotonicityFacts`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Word +open ExpRealSpec + +noncomputable section + +set_option maxRecDepth 100000 + +/-! ## The result word equals the body on the region away from the scale point -/ + +/-- For a region input that is not the scale point, the run result is the body floor: above the +clamp boundary the clamp is transparent and the `x = 0` pin does not fire. -/ +theorem int256_expTree_region_ne_zero {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (hne : x ≠ 0) : + int256 (expTree x) = int256 (r1Tree x) := by + have hr1 : r1Tree x < 2 ^ 254 := r1Tree_range hx hC hC0 + have hmask : int256 (u256 Cmask) < int256 (u256 x) := by + rw [u256_of_lt Cmask_lt, u256_of_lt hx]; exact hC + rw [int256_expTree_of_gt hmask hr1] + have hx0 : u256 x ≠ 0 := by rw [u256_of_lt hx]; exact hne + have hr1eq : int256 (r1Tree x) = (r1Tree x : Int) := + int256_of_lt (by have : (2:Nat)^254 < 2^255 := by norm_num + omega) + rw [if_neg hx0, zero_add, hr1eq] + +/-! ## Global never-over and floor-or-one-less bracket -/ + +/-- **Global floor-or-one-less bracket.** Given the analytic accumulator bound, for every signed input strictly +below the supported threshold the runtime result `r` satisfies the 2-wide never-over bracket +`r ≤ E ∧ E < r + 2`. -/ +theorem run_exp_ray_to_wad_evm_floorOrOneLess (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) + (hC0 : int256 x < int256 C0thresh) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ FloorOrOneLessBracket x (int256 r) := by + refine ⟨expTree x, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hx hC0), ?_⟩ + by_cases hC : int256 Cmask < int256 x + · by_cases hz : x = 0 + · -- scale point + subst hz + have he : expTree 0 = 1000000000000000000 := by + have := run_exp_ray_to_wad_evm_zero + rw [run_exp_ray_to_wad_evm_eq_expTree 0 (domain_of_below_C0 hx hC0)] at this + exact Except.ok.inj this.symm + rw [he] + have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by + rw [int256_of_lt (by norm_num)]; norm_num + rw [h0]; exact floorOrOneLess_zero + · rw [int256_expTree_region_ne_zero hx hC hC0 hz] + exact floorOrOneLessBracket_region H' hx hC hC0 + · -- below/at the clamp boundary: result is 0, E < 2 + push_neg at hC + have hle : int256 (u256 x) ≤ int256 (u256 Cmask) := by + rw [u256_of_lt hx, u256_of_lt Cmask_lt]; exact hC + rw [expTree_eq_zero_of_le hle] + have hz0 : int256 (0 : Nat) = 0 := rfl + rw [hz0] + refine ⟨?_, ?_⟩ + · rw [Int.cast_zero] + have hpos : (0 : Real) ≤ expRayToWadTarget x := by + unfold expRayToWadTarget + have := Real.exp_pos ((x : Real) / (RAY : Real)) + positivity + exact hpos + · have := H'.belowC x hC + rw [Int.cast_zero]; linarith [this] + +/-! ## One-unit underestimation bound -/ + +/-- **One-unit underestimation bound (global).** Given the analytic accumulator bound, the runtime result +underestimates by at most one output unit: `⌊E⌋ − 1 ≤ r`. -/ +theorem run_exp_ray_to_wad_evm_underByAtMostOne (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) + (hC0 : int256 x < int256 C0thresh) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ UnderByAtMostOne x (int256 r) := by + obtain ⟨r, hrun, hbr⟩ := run_exp_ray_to_wad_evm_floorOrOneLess H' x hx hC0 + exact ⟨r, hrun, floorOrOneLess_to_underByAtMostOne hbr⟩ + +/-! ## Central-octave exact floor -/ + +/-- **Central-octave exact floor.** Given the analytic accumulator bound, on the core band +`x ∈ [−H, H)` the runtime result is the exact floor: `r ≤ E ∧ E < r + 1`, pinning `r = ⌊E⌋`. -/ +theorem run_exp_ray_to_wad_evm_exactFloor (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) + (hlo : -H ≤ int256 x) (hhi : int256 x < H) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExactFloorBracket x (int256 r) := by + have hCmlt : int256 Cmask < -H := by rw [int256_Cmask]; unfold H; norm_num + have hC : int256 Cmask < int256 x := lt_of_lt_of_le hCmlt hlo + have hC0 : int256 x < int256 C0thresh := lt_of_lt_of_le hhi (le_of_lt int256_H_lt_C0) + refine ⟨expTree x, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hx hC0), ?_⟩ + by_cases hz : x = 0 + · subst hz + have he : expTree 0 = 1000000000000000000 := by + have := run_exp_ray_to_wad_evm_zero + rw [run_exp_ray_to_wad_evm_eq_expTree 0 (domain_of_below_C0 hx hC0)] at this + exact Except.ok.inj this.symm + rw [he] + have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by + rw [int256_of_lt (by norm_num)]; norm_num + rw [h0]; exact exactFloor_zero + · rw [int256_expTree_region_ne_zero hx hC hC0 hz] + exact exactFloorBracket_region H' hx hlo hhi + +end + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean new file mode 100644 index 000000000..c157c98fd --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -0,0 +1,190 @@ +import ExpProof.Mono.RunBridge +import ExpProof.Mono.RangeNonneg +import ExpProof.Seam.RealExp + +/-! +# Floor + branch assembly: the public `Real.exp` brackets + +`run_exp_ray_to_wad_evm_eq_expTree` returns `expTree x`, the clamp/pin shell around the floored +accumulator `r1Tree x = sar(126 − k, WAD·r0 − MARGIN)`. On the meaningful region the closing shift +`s = 126 − k ∈ [63, 187]` is positive and the shift argument `arg = WAD·r0 − MARGIN` is nonnegative, +so the runtime result is exactly the integer floor `⌊arg / 2^s⌋` of the *real* pre-floor accumulator + +``` +A = (WAD·r0 − MARGIN) / 2^(126 − k). +``` + +The two floor facts `(r : Real) ≤ A` and `A < (r : Real) + 1` (i.e. `r = ⌊A⌋`) are established here +from the `evmSar` sandwich. What is not a runtime-plumbing fact — and is collected +into the single analytic obligation `RuntimeAccumBound` below — is the relation between the +*real-valued* runtime accumulator `A` and the target `E = WAD·exp(x/RAY)`: + +* never-over `A ≤ E`, and +* deficit-under-one `E < A + 1` (and the sharpened `E < r + 1` on the core octave). + +`RuntimeAccumBound` packages exactly those, mirroring the way `Mono.RegionMonotonicityFacts`/`Mono.SeamR0Bound` +isolate the monotonicity analytic core. Given it, this file derives the public floor brackets +(chaining the `ExpRealBridge.*_of_accum` reductions); the analytic core itself +is the cert-fold + truncation bridge (the cert `Floor/Caps` against the exact rational, plus the +reduced-argument and Horner-truncation envelopes the `MARGIN` absorbs). +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Word +open ExpRealSpec + +noncomputable section + +set_option maxRecDepth 100000 + +/-! ## The closing-shift floor, unconditionally -/ + +/-- A nonnegative arithmetic right shift is the integer floor of the division: with `s < 256`, +`W < 2^256` and `0 ≤ int256 W`, `int256 (evmSar s W)` is `⌊int256 W / 2^s⌋`, characterised by the +floor sandwich `2^s·R ≤ int256 W < 2^s·R + 2^s`. -/ +theorem sar_floor_sandwich {W s : Nat} (hs : s < 256) (hWw : W < 2 ^ 256) : + (2 ^ s : Int) * int256 (evmSar s W) ≤ int256 W ∧ + int256 W < (2 ^ s : Int) * int256 (evmSar s W) + 2 ^ s := by + obtain ⟨_, hlo, hhi⟩ := evmSar_sandwich hs hWw + exact ⟨hlo, hhi⟩ + +/-- The real pre-floor accumulator `A = arg / 2^s` and the runtime result `r = int256 (evmSar s W)` +satisfy `(r : Real) ≤ A < (r : Real) + 1`. This is the floor step the bridge reduction takes as a +hypothesis; here it is discharged from the `evmSar` sandwich (`s < 256`). -/ +theorem sar_real_floor {W s : Nat} (hs : s < 256) (hWw : W < 2 ^ 256) : + let r : Int := int256 (evmSar s W) + let A : Real := (int256 W : Real) / (2 ^ s : Real) + (r : Real) ≤ A ∧ A < (r : Real) + 1 := by + intro r A + obtain ⟨hlo, hhi⟩ := sar_floor_sandwich hs hWw + have hps : (0 : Real) < (2 ^ s : Real) := by positivity + have hpcast : ((2 ^ s : Int) : Real) = (2 ^ s : Real) := by push_cast; ring + -- transport the integer sandwich to `Real` + have hloR : (2 ^ s : Real) * (r : Real) ≤ (int256 W : Real) := by + have h : ((((2 ^ s : Int) * int256 (evmSar s W)) : Int) : Real) ≤ ((int256 W : Int) : Real) := + Int.cast_le.mpr hlo + push_cast at h; linarith [h] + have hhiR : (int256 W : Real) < (2 ^ s : Real) * (r : Real) + (2 ^ s : Real) := by + have h : ((int256 W : Int) : Real) < + ((((2 ^ s : Int) * int256 (evmSar s W) + 2 ^ s) : Int) : Real) := Int.cast_lt.mpr hhi + push_cast at h; linarith [h] + refine ⟨?_, ?_⟩ + · rw [le_div_iff₀ hps]; linarith [hloR] + · rw [div_lt_iff₀ hps]; nlinarith [hhiR, hps] + +/-! ## The runtime accumulator as a real number + +For `x > 0` in the meaningful region the result is the body word, `expTree x = r1Tree x`, with +`r1Tree x = evmSar (126 − k) (WAD·r0 − MARGIN)`. Its real pre-floor accumulator is + +``` +A x = int256 (WAD·r0 − MARGIN) / 2^(126 − k). +``` +-/ + +/-- The real pre-floor accumulator of the runtime body, as an explicit `Real`. -/ +def accumReal (x : Nat) : Real := + (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) : Real) / + (2 ^ (evmSub 0x7e (kTree x)) : Real) + +/-- On the meaningful region the body word `r1Tree x` is the integer floor of its real accumulator +`accumReal x`: `(r1Tree x : Real) ≤ accumReal x < (r1Tree x : Real) + 1`. -/ +theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (int256 (r1Tree x) : Real) ≤ accumReal x ∧ + accumReal x < (int256 (r1Tree x) : Real) + 1 := by + obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 + have hr1 : r1Tree x = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) := by + have : r1Tree x = evmSar (evmSub 0x7e (kTree x)) + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) := rfl + rw [this, hseq] + have hWw : evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a < 2 ^ 256 := + evmSub_lt _ _ + have hfloor := sar_real_floor (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) + (s := s) (by omega) hWw + simp only at hfloor + -- align `accumReal` (shift `evmSub 0x7e (kTree x)`) with the lemma's shift `s` + have hAeq : accumReal x = + (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) : Real) / + (2 ^ s : Real) := by + unfold accumReal; rw [hseq] + rw [hAeq, hr1] + exact hfloor + +/-! ## The analytic obligation: the runtime accumulator brackets `E` + +`RuntimeAccumBound` packages the relation between the real pre-floor accumulator `accumReal x` and +the public target `E = expRayToWadTarget x` that the cert-fold + truncation bridge must establish: + +* `over` — never over: `accumReal x ≤ E` for any region input; +* `under` — deficit under one: `E < accumReal x + 1` for any region input; +* `centralExactness` — the sharpened core-octave bound `E < (r1Tree x : Real) + 1` (the negligible `k = 0` + margin floors `E` exactly), for inputs in the core band `[−H, H)`. + +It is the floor-side analogue of `Mono.RegionMonotonicityFacts`/`Mono.SeamR0Bound`: every runtime-plumbing and +floor fact is proved directly; the public floor brackets depend on this single +analytic core (the cert against the exact rational `ê(t) = NUM/DEN` folded with the octave `2^k`, +together with the reduced-argument `(x/RAY − k·ln2)` ≈ `tTree/2¹²⁸` envelope and the Horner-`sdiv` +truncation envelope — all absorbed by the `MARGIN`). -/ +structure RuntimeAccumBound : Prop where + /-- Never over: the real pre-floor accumulator does not exceed the target. Holds for any region + input (the never-over relation `r0 ≤ exp(t)·2¹²⁶ + MARGIN/WAD` is octave-independent and + sign-symmetric). -/ + over : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → + accumReal x ≤ expRayToWadTarget x + /-- Deficit under one: the target is below the accumulator plus one. -/ + under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → + expRayToWadTarget x < accumReal x + 1 + /-- Core-octave exactness: on the core band `x ∈ [−H, H)` the negligible `k = 0` margin floors + `E` exactly onto the result. -/ + centralExactness : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → + -H ≤ int256 x → int256 x < H → + expRayToWadTarget x < (int256 (r1Tree x) : Real) + 1 + /-- Below the clamp boundary the target is below one output unit (`E < 1`), so the clamped result + `0` is the floor. `Cmask = ⌊−18·ln10·10²⁷⌋` is the exact 0/1 boundary; `x ≤ Cmask` gives + `x/10²⁷ ≤ −18·ln10`, hence `E = 10¹⁸·exp(x/10²⁷) ≤ 1`. -/ + belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget x < 2 + +/-! ## The region floor brackets, given `RuntimeAccumBound` -/ + +theorem int256_C0thresh_floc : int256 C0thresh = 44014845965556527147994239713 := by + unfold C0thresh int256; norm_num + +theorem int256_H_lt_C0 : (H : Int) < int256 C0thresh := by + rw [int256_C0thresh_floc]; unfold H; norm_num + +theorem int256_zero_le_Cmask : int256 Cmask < 0 := by rw [int256_Cmask]; norm_num + +/-- **Floor-or-one-less bracket on the region**, given the analytic accumulator bound: the body result +`r = int256 (r1Tree x)` satisfies `r ≤ E ∧ E < r + 2`. -/ +theorem floorOrOneLessBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + FloorOrOneLessBracket x (int256 (r1Tree x)) := by + obtain ⟨hfl, hfl1⟩ := r1Tree_floor_accum hx hC hC0 + exact ExpRealBridge.floorOrOneLessBracket_of_accum hfl hfl1 + (H'.over x hx hC hC0) (H'.under x hx hC hC0) + +/-- **Exact-floor bracket on the core octave** (`x ∈ [−H, H)`), given the analytic accumulator +bound: `r ≤ E ∧ E < r + 1`. -/ +theorem exactFloorBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) + (hlo : -H ≤ int256 x) (hhi : int256 x < H) : + ExactFloorBracket x (int256 (r1Tree x)) := by + have hCmlt : int256 Cmask < -H := by rw [int256_Cmask]; unfold H; norm_num + have hC : int256 Cmask < int256 x := lt_of_lt_of_le hCmlt hlo + have hC0 : int256 x < int256 C0thresh := lt_of_lt_of_le hhi (le_of_lt int256_H_lt_C0) + obtain ⟨hfl, _⟩ := r1Tree_floor_accum hx hC hC0 + exact ExpRealBridge.exactFloorBracket_of_accum hfl + (H'.over x hx hC hC0) (H'.centralExactness x hx hC hC0 hlo hhi) + +/-- **One-unit underestimation bound on the region**, given the analytic accumulator bound: `⌊E⌋ − 1 ≤ r`. -/ +theorem underByAtMostOne_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + UnderByAtMostOne x (int256 (r1Tree x)) := + ExpRealBridge.underByAtMostOne_of_floorOrOneLess (floorOrOneLessBracket_region H' hx hC hC0) + +end + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 6029bc4fa..b0ae2c73a 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -1,6 +1,7 @@ import ExpProof.Seam.Revert import ExpProof.Seam.Value import ExpProof.Mono +import ExpProof.Floor.Public /-! # `expRayToWad` — proven properties of the compiled runtime (signpost) @@ -91,4 +92,49 @@ example (hr0 : SeamR0Bound) (x1 x2 : Nat) #guard_msgs in #print axioms run_exp_ray_to_wad_evm_mono_of_seamR0 +/-! ## `Real.exp` floor brackets, modulo the runtime accumulator bound + +Each bracket is stated on the runtime result `r` (`run_exp_ray_to_wad_evm x = .ok r`) against the +target `E = 10¹⁸·exp(x/10²⁷)`, and carries the single analytic obligation `RuntimeAccumBound` (the +real pre-floor accumulator brackets `E`: never over, deficit under one, core-octave exact, and the +below-clamp `E < 1`). The runtime reduction, the closing-shift floor, the clamp/pin shell branch +split, and the scale-point exactness are proved directly; the floor brackets depend on +`RuntimeAccumBound` — the cert (`Floor.Caps`, against the exact rational `ê = NUM/DEN`) folded with +the octave `2^k`, plus the reduced-argument and Horner-`sdiv` truncation envelopes the `MARGIN` +absorbs. This mirrors `run_exp_ray_to_wad_evm_mono`'s `RegionMonotonicityFacts` hypothesis. -/ + +/-- Global never-over and floor-or-one-less bracket, given the runtime accumulator bound. -/ +example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) + (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.FloorOrOneLessBracket x + (FormalYul.Preservation.int256 r) := + run_exp_ray_to_wad_evm_floorOrOneLess H' x hx hC0 + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_floorOrOneLess' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_floorOrOneLess + +/-- Central-octave exact floor, given the runtime accumulator bound. -/ +example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) + (hlo : -ExpRealSpec.H ≤ FormalYul.Preservation.int256 x) + (hhi : FormalYul.Preservation.int256 x < ExpRealSpec.H) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.ExactFloorBracket x + (FormalYul.Preservation.int256 r) := + run_exp_ray_to_wad_evm_exactFloor H' x hx hlo hhi + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_exactFloor' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_exactFloor + +/-- One-unit underestimation bound, given the runtime accumulator bound. -/ +example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) + (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.UnderByAtMostOne x + (FormalYul.Preservation.int256 r) := + run_exp_ray_to_wad_evm_underByAtMostOne H' x hx hC0 + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_underByAtMostOne' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_underByAtMostOne + end ExpYul diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 127e05283..a961119be 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -64,8 +64,10 @@ library Exp { /// Hence RAW ≤ S, with the proven bound S = 0.0858862987232991853 ulp. The margin is the /// least integer that covers S once placed in the Q126 grid: 0xafe527e18748a8a = ⌈2⁶³⋅S⌉ /// (worth ≈ S ulp at k = 63). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and - /// E - A ≤ margin - min RAW ≤ 0.6057 < 1, so the floor is ⌊E⌋ or ⌊E⌋ - 1. At k = 64 the - /// margin exceeds one ulp and the floor can fall two below E, so that input is reverted. On + /// E - A ≤ margin - min RAW ≤ 0.6057 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the 1-ulp + /// underestimate is achieved, ⌊E⌋ - 2 never occurs). At k = 64 the margin and truncation + /// envelope scale to more than one ulp and the floor can fall two below E, so that input is + /// reverted. On /// the central octave k = 0 the margin is ⌈2⁶³⋅S⌉⋅2⁻¹²⁶ ≈ 9.3⋅10⁻²¹ ulp, far below the /// ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` /// is half-open, so the k = 0 band is exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching From e02a358e25423cfa16299ec331e30d372ca3b046 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 12:55:44 +0200 Subject: [PATCH 052/149] Reduce the exp accumulator bound to the octave-folded r0 bound The closing-shift plumbing (the shift-argument transport WAD*r0 - MARGIN and the nonnegative closing shift 126 - k) reduces RuntimeAccumBound to RuntimeR0Bound: the never-over/deficit inequalities collapse to bounds on the Q126 quotient r0Tree x against E*2^(126-k), free of any Real.exp octave-fold bookkeeping. The reduction runtimeAccumBound_of_r0 is unconditional and axiom-clean; the public floor brackets reduce to RuntimeR0Bound (the cert Floor.Caps against ehat = NUM/DEN folded with 2^k, plus the reduced-argument and Horner-sdiv truncation envelopes the MARGIN absorbs). Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 119 +++++++++++++++++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 14 +++ 2 files changed, 133 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/Fold.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean new file mode 100644 index 000000000..f731bf95a --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -0,0 +1,119 @@ +import ExpProof.Floor.Spec + +/-! +# Reducing the accumulator bound to a clean `r0`-vs-`exp` bound + +`RuntimeAccumBound` (the obligation `Floor.Public` carries) is about the real pre-floor accumulator +`accumReal x = (WAD·r0 − MARGIN) / 2^(126 − k)`. This file peels the runtime plumbing off it: using +the proven shift-argument transport (`shiftArg_bounds_of`: `int256 (WAD·r0 − MARGIN) = WAD·r0 − MARGIN` +as `Int`) and the closing-shift value (`closing_shift`: the shift word is `126 − int256 k`, +nonnegative), the never-over and deficit inequalities collapse to *octave-folded* `r0` bounds against +the target. + +Writing `s = 126 − int256 (kTree x) ≥ 0`, `WAD = 10¹⁸`, `MARGIN = 0xafe527e18748a8a`, the algebra is: + +``` +accumReal x ≤ E ⟺ WAD·r0 − MARGIN ≤ E·2^s +E < accumReal x + 1 ⟺ E·2^s < WAD·r0 − MARGIN + 2^s +``` + +with `E = expRayToWadTarget x`. `RuntimeR0Bound` packages exactly those two inequalities (plus the +sign facts the transport needs), so a discharge of it gives `RuntimeAccumBound.over`/`under` +directly. The analytic content of `RuntimeR0Bound` — `r0Tree x ≈ exp(x/10²⁷)·2^126/2^k` +within the `MARGIN` envelope — is the cert (`Floor.Caps`, against `ê = NUM/DEN`) folded with the +octave `2^k` together with the reduced-argument and Horner-`sdiv` truncation envelopes; this module +performs only the (unconditional, axiom-clean) plumbing reduction. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Word +open ExpRealSpec + +noncomputable section + +set_option maxRecDepth 100000 + +/-! ## The shift-argument value and the closing shift, as real quantities -/ + +/-- On the region, the numeric shift argument `WAD·r0 − MARGIN` (transported to `Int` and then to +`Real`) is `WAD·(int256 r0) − MARGIN`, and it is nonnegative. -/ +theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + ∃ s : Nat, (s : Int) = 126 - int256 (kTree x) ∧ + accumReal x = + ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - (792161285993433738 : Real)) / + (2 ^ s : Real) := by + obtain ⟨s, hseq, _, _, hsint⟩ := closing_shift hx hC hC0 + obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 + obtain ⟨hargeq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi + refine ⟨s, hsint, ?_⟩ + unfold accumReal + rw [hseq] + -- the integer shift argument has the closed value `WAD·r0 − MARGIN` + have hwadc : (0xde0b6b3a7640000 : Int) = 1000000000000000000 := by norm_num + have hmarc : (0xafe527e18748a8a : Int) = 792161285993433738 := by norm_num + rw [hargeq, hwadc, hmarc] + push_cast + ring + +/-! ## The clean octave-folded `r0` bound + +`RuntimeR0Bound` is the elementary statement the cert-fold + truncation bridge must establish: with +`s = 126 − int256 k` the closing shift, the floored accumulator brackets `E`. Phrasing it directly +on `WAD·r0 − MARGIN` vs `E·2^s` keeps it free of any `Real.exp` octave-fold bookkeeping — that +bookkeeping is internal to the eventual discharge (the `2^k` is `2^(126 − s)` here). -/ +structure RuntimeR0Bound : Prop where + /-- Never over: `WAD·r0 − MARGIN ≤ E·2^(126 − k)`. -/ + over : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → + ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 ≤ + expRayToWadTarget x * (2 ^ s : Real) + /-- Deficit under one: `E·2^(126 − k) < WAD·r0 − MARGIN + 2^(126 − k)`. -/ + under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → + ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → + expRayToWadTarget x * (2 ^ s : Real) < + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 + (2 ^ s : Real) + /-- Core-octave exactness, in the same `WAD·r0`-vs-`E` shape: on `x ∈ [−H, H)` the deficit closes + to the sharper `E·2^s < WAD·r0 − MARGIN + 2^s`, where additionally `2^s` is small enough that the + floor catches `E` exactly. Stated as the body-result-relative bound to mirror `centralExactness`. -/ + centralExactness : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → + -H ≤ int256 x → int256 x < H → + expRayToWadTarget x < (int256 (r1Tree x) : Real) + 1 + /-- Below the clamp boundary `E < 1` (carried through verbatim). -/ + belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget x < 2 + +/-- **The plumbing reduction.** `RuntimeR0Bound` discharges `RuntimeAccumBound`: the never-over and +deficit inequalities transport across the closing shift `2^s > 0`. -/ +theorem runtimeAccumBound_of_r0 (H : RuntimeR0Bound) : RuntimeAccumBound where + over := fun x hx hC hC0 => by + obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 + have hps : (0 : Real) < (2 ^ s : Real) := by positivity + have hb := H.over x hx hC hC0 s hsint + rw [hAeq, div_le_iff₀ hps] + linarith [hb] + under := fun x hx hC hC0 => by + obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 + have hps : (0 : Real) < (2 ^ s : Real) := by positivity + have hb := H.under x hx hC hC0 s hsint + -- goal `E < accumReal x + 1`; rewrite `accumReal` and clear the `/2^s` + rw [hAeq] + -- `E < arg/2^s + 1` ⟺ `E·2^s < arg + 2^s` + have key : expRayToWadTarget x * (2 ^ s : Real) < + ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real) := + hb + have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) / + (2 ^ s : Real) + 1 = + (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real)) / + (2 ^ s : Real) := by + field_simp + rw [hdiv, lt_div_iff₀ hps] + linarith [key] + centralExactness := fun x hx hC hC0 hlo hhi => H.centralExactness x hx hC hC0 hlo hhi + belowC := fun x hxle => H.belowC x hxle + +end + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index b0ae2c73a..62389b01e 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -2,6 +2,7 @@ import ExpProof.Seam.Revert import ExpProof.Seam.Value import ExpProof.Mono import ExpProof.Floor.Public +import ExpProof.Floor.Fold /-! # `expRayToWad` — proven properties of the compiled runtime (signpost) @@ -137,4 +138,17 @@ example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) #guard_msgs in #print axioms run_exp_ray_to_wad_evm_underByAtMostOne +/-! ## The accumulator obligation reduced to the octave-folded `r0` bound + +`RuntimeAccumBound` (the accumulator-vs-target bracket) reduces — by the unconditional closing-shift +plumbing — to `RuntimeR0Bound`, the cleaner statement that the Q126 quotient `r0Tree x` brackets the +target across the octave shift `2^(126 − k)`. The public floor brackets therefore reduce to +`RuntimeR0Bound` (the cert `Floor.Caps` against `ê = NUM/DEN`, folded with `2^k`, plus the +reduced-argument and Horner-`sdiv` truncation envelopes the `MARGIN` absorbs). -/ +example (H : RuntimeR0Bound) : RuntimeAccumBound := runtimeAccumBound_of_r0 H + +/-- info: 'ExpYul.runtimeAccumBound_of_r0' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms runtimeAccumBound_of_r0 + end ExpYul From 1f91ade0aeacca5aaf7788bfaa4605ecf458b648 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 13:10:05 +0200 Subject: [PATCH 053/149] Prove the exp reduced argument stays in the cert domain [-H128, H128] The reduced-argument Taylor caps are certified over t in [0, H128]; this establishes |tTree x| <= H128 on the meaningful region so the caps can be instantiated at the runtime reduced argument. The bound is the integer-k fact: the per-octave-band x-ranges (interval_cases over k in [-61, 63]) together with the reduction sandwich pin t below the cert edge, where a real LP relaxation is unbounded. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../exp/ExpProof/ExpProof/Floor/TBound.lean | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/TBound.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean new file mode 100644 index 000000000..3af9303cb --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean @@ -0,0 +1,71 @@ +import ExpProof.Mono.Octave +import Mathlib.Tactic.IntervalCases + +/-! +# The reduced argument stays in the cert domain `[−H128, H128]` + +The reduced-argument Taylor caps (`Floor.Caps`) are certified over `t ∈ [0, H128]` with +`H128 = ⌊ln2/2 · 2¹²⁸⌋`. To instantiate them at the runtime reduced argument `t = tTree x` we +need `|tTree x| ≤ H128` on the meaningful region. + +This is the integer-`k` fact the experiments flagged: a real linear-program relaxation of the +octave/reduced-argument sandwiches is unbounded (it decouples `k` from `x`), but the *integer* +`k`-rounding sandwich `2²⁰⁰·k ≤ 2¹⁹⁹ + CINV·x < 2²⁰⁰·k + 2²⁰⁰` ties `k` to `x` tightly enough that +the maximum of the reduction argument `K27·x − LN2·k` over the integer region is strictly below +`2¹⁰⁷·(H128 + 1)` (and symmetrically above `−2¹⁰⁷·(H128 + 1)`). `omega` discharges the resulting +linear-integer system — it performs the per-`k`-band case analysis internally. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-- On the meaningful region the reduced argument lands in the certificate domain: +`-H128 ≤ tTree x ≤ H128` (as signed integers), where `H128 = ⌊ln2/2 · 2¹²⁸⌋`. -/ +theorem tTree_in_cert_domain {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + -(117932881612756647068972071382077242199 : Int) ≤ int256 (tTree x) ∧ + int256 (tTree x) ≤ 117932881612756647068972071382077242199 := by + obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 + obtain ⟨hklo, hkhi⟩ := kTree_sandwich hx hC hC0 + obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 + obtain ⟨hkblo, hkbhi⟩ := kTree_bound hx hC hC0 + -- region endpoints as decimals + have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask + have hC0i : int256 C0thresh = 44014845965556527147994239713 := by + unfold C0thresh int256; norm_num + rw [hCi] at hC + rw [hC0i] at hC0 + -- constants as decimals + have hK27 : (0x279d346de4781f921dd7a89933d54d1f72928 : Int) = + 55213970774324510299478046898216203619608872 := by norm_num + have hLN2 : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num + have hCINV : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by + norm_num + rw [hK27, hLN2] at htlo hthi + rw [hCINV] at hklo hkhi + set t := int256 (tTree x) with htdef + set k := int256 (kTree x) with hkdef + set X := int256 x with hXdef + -- powers of two as decimals + have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num + have p199 : (2 : Int) ^ 199 = + 803469022129495137770981046170581301261101496891396417650688 := by norm_num + have p200 : (2 : Int) ^ 200 = + 1606938044258990275541962092341162602522202993782792835301376 := by norm_num + have pH : (117932881612756647068972071382077242199 : Int) = + 117932881612756647068972071382077242199 := rfl + rw [p107] at htlo hthi + rw [p199, p200] at hklo hkhi + clear_value k + -- For each fixed integer octave index `k ∈ [−61, 63]` the band of consistent `x` together with + -- the reduction sandwich pins `t` to the cert domain; `omega` closes each band (the coupling is + -- linear in `x` and `t` once `k` is a literal). + clear htdef hXdef hkdef hCi hC0i hK27 hLN2 hCINV pH p107 p199 p200 hx hxlo hxhi + interval_cases k <;> constructor <;> omega + +end ExpYul From a0e2a257b83b77cbaa52560ba30eabad944c3f5a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:47:40 +0200 Subject: [PATCH 054/149] Fix exp floor-bracket spec to target the signed input value The accumulator/r0 obligations and the public brackets stated the real target as expRayToWadTarget (up-cast of the Nat word x), i.e. WAD*exp(word/RAY). For inputs whose int256 value is negative the word is near 2^256, making the target astronomically large; the `under`/`belowC`/central-exactness obligations were then false and the public brackets vacuous for the entire negative half of the supported range. Target the decoded signed value expRayToWadTarget (int256 x) throughout (RuntimeR0Bound, RuntimeAccumBound, the region brackets, the public floor-bracket theorems, and the Theorems gate). This makes the obligations satisfiable and the public statements faithful to the runtime, which decodes its argument as an int256. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 10 +++++----- .../exp/ExpProof/ExpProof/Floor/Public.lean | 20 +++++++++++-------- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 14 ++++++------- formal/exp/ExpProof/ExpProof/Theorems.lean | 12 +++++------ 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index f731bf95a..ea24f5b0a 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -70,20 +70,20 @@ structure RuntimeR0Bound : Prop where over : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 ≤ - expRayToWadTarget x * (2 ^ s : Real) + expRayToWadTarget (int256 x) * (2 ^ s : Real) /-- Deficit under one: `E·2^(126 − k) < WAD·r0 − MARGIN + 2^(126 − k)`. -/ under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → - expRayToWadTarget x * (2 ^ s : Real) < + expRayToWadTarget (int256 x) * (2 ^ s : Real) < (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 + (2 ^ s : Real) /-- Core-octave exactness, in the same `WAD·r0`-vs-`E` shape: on `x ∈ [−H, H)` the deficit closes to the sharper `E·2^s < WAD·r0 − MARGIN + 2^s`, where additionally `2^s` is small enough that the floor catches `E` exactly. Stated as the body-result-relative bound to mirror `centralExactness`. -/ centralExactness : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → -H ≤ int256 x → int256 x < H → - expRayToWadTarget x < (int256 (r1Tree x) : Real) + 1 + expRayToWadTarget (int256 x) < (int256 (r1Tree x) : Real) + 1 /-- Below the clamp boundary `E < 1` (carried through verbatim). -/ - belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget x < 2 + belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 2 /-- **The plumbing reduction.** `RuntimeR0Bound` discharges `RuntimeAccumBound`: the never-over and deficit inequalities transport across the closing shift `2^s > 0`. -/ @@ -101,7 +101,7 @@ theorem runtimeAccumBound_of_r0 (H : RuntimeR0Bound) : RuntimeAccumBound where -- goal `E < accumReal x + 1`; rewrite `accumReal` and clear the `/2^s` rw [hAeq] -- `E < arg/2^s + 1` ⟺ `E·2^s < arg + 2^s` - have key : expRayToWadTarget x * (2 ^ s : Real) < + have key : expRayToWadTarget (int256 x) * (2 ^ s : Real) < ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real) := hb have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) / diff --git a/formal/exp/ExpProof/ExpProof/Floor/Public.lean b/formal/exp/ExpProof/ExpProof/Floor/Public.lean index 754df653d..c4269e712 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Public.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Public.lean @@ -55,7 +55,7 @@ below the supported threshold the runtime result `r` satisfies the 2-wide never- `r ≤ E ∧ E < r + 2`. -/ theorem run_exp_ray_to_wad_evm_floorOrOneLess (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) (hC0 : int256 x < int256 C0thresh) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ FloorOrOneLessBracket x (int256 r) := by + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ FloorOrOneLessBracket (int256 x) (int256 r) := by refine ⟨expTree x, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hx hC0), ?_⟩ by_cases hC : int256 Cmask < int256 x · by_cases hz : x = 0 @@ -68,24 +68,27 @@ theorem run_exp_ray_to_wad_evm_floorOrOneLess (H' : RuntimeAccumBound) (x : Nat) rw [he] have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by rw [int256_of_lt (by norm_num)]; norm_num - rw [h0]; exact floorOrOneLess_zero + have hi0 : int256 (0 : Nat) = (0 : Int) := rfl + rw [h0, hi0]; exact floorOrOneLess_zero · rw [int256_expTree_region_ne_zero hx hC hC0 hz] exact floorOrOneLessBracket_region H' hx hC hC0 · -- below/at the clamp boundary: result is 0, E < 2 push_neg at hC have hle : int256 (u256 x) ≤ int256 (u256 Cmask) := by rw [u256_of_lt hx, u256_of_lt Cmask_lt]; exact hC + have hle' : int256 x ≤ int256 Cmask := by + rw [u256_of_lt hx, u256_of_lt Cmask_lt] at hle; exact hle rw [expTree_eq_zero_of_le hle] have hz0 : int256 (0 : Nat) = 0 := rfl rw [hz0] refine ⟨?_, ?_⟩ · rw [Int.cast_zero] - have hpos : (0 : Real) ≤ expRayToWadTarget x := by + have hpos : (0 : Real) ≤ expRayToWadTarget (int256 x) := by unfold expRayToWadTarget - have := Real.exp_pos ((x : Real) / (RAY : Real)) + have := Real.exp_pos ((int256 x : Real) / (RAY : Real)) positivity exact hpos - · have := H'.belowC x hC + · have := H'.belowC x hle' rw [Int.cast_zero]; linarith [this] /-! ## One-unit underestimation bound -/ @@ -94,7 +97,7 @@ theorem run_exp_ray_to_wad_evm_floorOrOneLess (H' : RuntimeAccumBound) (x : Nat) underestimates by at most one output unit: `⌊E⌋ − 1 ≤ r`. -/ theorem run_exp_ray_to_wad_evm_underByAtMostOne (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) (hC0 : int256 x < int256 C0thresh) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ UnderByAtMostOne x (int256 r) := by + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ UnderByAtMostOne (int256 x) (int256 r) := by obtain ⟨r, hrun, hbr⟩ := run_exp_ray_to_wad_evm_floorOrOneLess H' x hx hC0 exact ⟨r, hrun, floorOrOneLess_to_underByAtMostOne hbr⟩ @@ -104,7 +107,7 @@ theorem run_exp_ray_to_wad_evm_underByAtMostOne (H' : RuntimeAccumBound) (x : Na `x ∈ [−H, H)` the runtime result is the exact floor: `r ≤ E ∧ E < r + 1`, pinning `r = ⌊E⌋`. -/ theorem run_exp_ray_to_wad_evm_exactFloor (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) (hlo : -H ≤ int256 x) (hhi : int256 x < H) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExactFloorBracket x (int256 r) := by + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExactFloorBracket (int256 x) (int256 r) := by have hCmlt : int256 Cmask < -H := by rw [int256_Cmask]; unfold H; norm_num have hC : int256 Cmask < int256 x := lt_of_lt_of_le hCmlt hlo have hC0 : int256 x < int256 C0thresh := lt_of_lt_of_le hhi (le_of_lt int256_H_lt_C0) @@ -118,7 +121,8 @@ theorem run_exp_ray_to_wad_evm_exactFloor (H' : RuntimeAccumBound) (x : Nat) (hx rw [he] have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by rw [int256_of_lt (by norm_num)]; norm_num - rw [h0]; exact exactFloor_zero + have hi0 : int256 (0 : Nat) = (0 : Int) := rfl + rw [h0, hi0]; exact exactFloor_zero · rw [int256_expTree_region_ne_zero hx hC hC0 hz] exact exactFloorBracket_region H' hx hlo hhi diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index c157c98fd..45778dda5 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -134,19 +134,19 @@ structure RuntimeAccumBound : Prop where input (the never-over relation `r0 ≤ exp(t)·2¹²⁶ + MARGIN/WAD` is octave-independent and sign-symmetric). -/ over : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - accumReal x ≤ expRayToWadTarget x + accumReal x ≤ expRayToWadTarget (int256 x) /-- Deficit under one: the target is below the accumulator plus one. -/ under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - expRayToWadTarget x < accumReal x + 1 + expRayToWadTarget (int256 x) < accumReal x + 1 /-- Core-octave exactness: on the core band `x ∈ [−H, H)` the negligible `k = 0` margin floors `E` exactly onto the result. -/ centralExactness : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → -H ≤ int256 x → int256 x < H → - expRayToWadTarget x < (int256 (r1Tree x) : Real) + 1 + expRayToWadTarget (int256 x) < (int256 (r1Tree x) : Real) + 1 /-- Below the clamp boundary the target is below one output unit (`E < 1`), so the clamped result `0` is the floor. `Cmask = ⌊−18·ln10·10²⁷⌋` is the exact 0/1 boundary; `x ≤ Cmask` gives `x/10²⁷ ≤ −18·ln10`, hence `E = 10¹⁸·exp(x/10²⁷) ≤ 1`. -/ - belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget x < 2 + belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 2 /-! ## The region floor brackets, given `RuntimeAccumBound` -/ @@ -162,7 +162,7 @@ theorem int256_zero_le_Cmask : int256 Cmask < 0 := by rw [int256_Cmask]; norm_nu `r = int256 (r1Tree x)` satisfies `r ≤ E ∧ E < r + 2`. -/ theorem floorOrOneLessBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - FloorOrOneLessBracket x (int256 (r1Tree x)) := by + FloorOrOneLessBracket (int256 x) (int256 (r1Tree x)) := by obtain ⟨hfl, hfl1⟩ := r1Tree_floor_accum hx hC hC0 exact ExpRealBridge.floorOrOneLessBracket_of_accum hfl hfl1 (H'.over x hx hC hC0) (H'.under x hx hC hC0) @@ -171,7 +171,7 @@ theorem floorOrOneLessBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x bound: `r ≤ E ∧ E < r + 1`. -/ theorem exactFloorBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) (hlo : -H ≤ int256 x) (hhi : int256 x < H) : - ExactFloorBracket x (int256 (r1Tree x)) := by + ExactFloorBracket (int256 x) (int256 (r1Tree x)) := by have hCmlt : int256 Cmask < -H := by rw [int256_Cmask]; unfold H; norm_num have hC : int256 Cmask < int256 x := lt_of_lt_of_le hCmlt hlo have hC0 : int256 x < int256 C0thresh := lt_of_lt_of_le hhi (le_of_lt int256_H_lt_C0) @@ -182,7 +182,7 @@ theorem exactFloorBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 /-- **One-unit underestimation bound on the region**, given the analytic accumulator bound: `⌊E⌋ − 1 ≤ r`. -/ theorem underByAtMostOne_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - UnderByAtMostOne x (int256 (r1Tree x)) := + UnderByAtMostOne (int256 x) (int256 (r1Tree x)) := ExpRealBridge.underByAtMostOne_of_floorOrOneLess (floorOrOneLessBracket_region H' hx hC hC0) end diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 62389b01e..9211f690b 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -107,8 +107,8 @@ absorbs. This mirrors `run_exp_ray_to_wad_evm_mono`'s `RegionMonotonicityFacts` /-- Global never-over and floor-or-one-less bracket, given the runtime accumulator bound. -/ example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.FloorOrOneLessBracket x - (FormalYul.Preservation.int256 r) := + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.FloorOrOneLessBracket + (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := run_exp_ray_to_wad_evm_floorOrOneLess H' x hx hC0 /-- info: 'ExpYul.run_exp_ray_to_wad_evm_floorOrOneLess' depends on axioms: [propext, Classical.choice, Quot.sound] -/ @@ -119,8 +119,8 @@ example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) (hlo : -ExpRealSpec.H ≤ FormalYul.Preservation.int256 x) (hhi : FormalYul.Preservation.int256 x < ExpRealSpec.H) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.ExactFloorBracket x - (FormalYul.Preservation.int256 r) := + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.ExactFloorBracket + (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := run_exp_ray_to_wad_evm_exactFloor H' x hx hlo hhi /-- info: 'ExpYul.run_exp_ray_to_wad_evm_exactFloor' depends on axioms: [propext, Classical.choice, Quot.sound] -/ @@ -130,8 +130,8 @@ example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) /-- One-unit underestimation bound, given the runtime accumulator bound. -/ example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.UnderByAtMostOne x - (FormalYul.Preservation.int256 r) := + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.UnderByAtMostOne + (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := run_exp_ray_to_wad_evm_underByAtMostOne H' x hx hC0 /-- info: 'ExpYul.run_exp_ray_to_wad_evm_underByAtMostOne' depends on axioms: [propext, Classical.choice, Quot.sound] -/ From deb104b793940cc5058b129588132a6c56cfcfe1 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 13:26:18 +0200 Subject: [PATCH 055/149] Prove the exp below-clamp target bound (RuntimeR0Bound.belowC) Below the 0/1 clamp boundary the target E = 10^18*exp(int256 x / 10^27) is under two output units: int256 x <= Cmask < -41*10^27 and exp is increasing, so E <= 10^18*exp(-41), and exp(-41) = (exp 1)^(-41) < 2*10^-18 because exp 1 > 2.7182818283 (Real.exp_one_gt_d9) forces (exp 1)^41 > 2.7182818283^41 > 5*10^17. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean new file mode 100644 index 000000000..706bb0f9e --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -0,0 +1,70 @@ +import ExpProof.Floor.Fold +import ExpProof.Floor.TBound +import Mathlib.Data.Complex.ExponentialBounds + +/-! +# Discharging the runtime `r0` bound + +`RuntimeR0Bound` (the single analytic obligation for the public floor brackets) brackets the Q126 quotient +`r0Tree x` against the target `E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(126 − k)`. +This file discharges its self-contained `belowC` field — below the clamp boundary the target is +under one output unit — directly from a `Real.exp` rational bound. + +`belowC`: for any word `x` whose signed value is at or below `Cmask = ⌊−18·ln10·10²⁷⌋`, the target +`E = 10¹⁸·exp(int256 x / 10²⁷)` is below `2`. Since `Cmask < −41·10²⁷` and `exp` is increasing, +`E ≤ 10¹⁸·exp(−41)`, and `exp(−41) = (exp 1)⁻⁴¹ < 2·10⁻¹⁸` because `exp 1 > 2.7182818283` (Mathlib's +`Real.exp_one_gt_d9`) forces `(exp 1)⁴¹ > 2.7182818283⁴¹ > 5·10¹⁷`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open ExpRealSpec +open Real + +noncomputable section + +set_option maxRecDepth 100000 + +/-- **Below the clamp boundary the target is under two output units.** For any word `x` whose signed +value is at or below the 0/1 clamp boundary `Cmask`, `E = 10¹⁸·exp(int256 x / 10²⁷) < 2`. -/ +theorem belowC_target_lt_two {x : Nat} (hxle : int256 x ≤ int256 Cmask) : + expRayToWadTarget (int256 x) < 2 := by + unfold expRayToWadTarget + have hCm : int256 Cmask = -41446531673892822312323846185 := int256_Cmask + rw [hCm] at hxle + have hRAY : (RAY : Real) = 10 ^ 27 := by unfold RAY; norm_num + have hWAD : (WAD : Real) = 10 ^ 18 := by unfold WAD; norm_num + have hxR : (int256 x : Real) ≤ -41446531673892822312323846185 := by exact_mod_cast hxle + -- the reduced argument is at most `−41` + have harg : (int256 x : Real) / (RAY : Real) ≤ -41 := by + rw [hRAY, div_le_iff₀ (by norm_num : (0:Real) < 10 ^ 27)] + nlinarith [hxR] + have hmono : Real.exp ((int256 x : Real) / (RAY : Real)) ≤ Real.exp (-41) := + Real.exp_le_exp.mpr harg + -- `(exp 1)^41 > 5·10^17` from `exp 1 > 2.7182818283` + have hexp41 : (5 * 10 ^ 17 : ℝ) < (Real.exp 1) ^ 41 := by + have h2 : (5 * 10 ^ 17 : ℝ) < (2.7182818283 : ℝ) ^ 41 := by norm_num + calc (5 * 10 ^ 17 : ℝ) < (2.7182818283 : ℝ) ^ 41 := h2 + _ < (Real.exp 1) ^ 41 := by gcongr; exact Real.exp_one_gt_d9 + have hen : Real.exp (-41) = ((Real.exp 1) ^ 41)⁻¹ := by + rw [show (-41 : ℝ) = -((41 : ℕ) * (1 : ℝ)) by push_cast; ring, Real.exp_neg, Real.exp_nat_mul] + have hp : (0 : ℝ) < (Real.exp 1) ^ 41 := by positivity + have hexpneg41 : Real.exp (-41) < 2 / 10 ^ 18 := by + rw [hen, inv_lt_iff_one_lt_mul₀ hp, div_mul_eq_mul_div, lt_div_iff₀ (by norm_num : (0:ℝ) < 10 ^ 18)] + nlinarith [hexp41] + rw [hWAD] + calc (10 ^ 18 : ℝ) * Real.exp ((int256 x : Real) / (RAY : Real)) + ≤ 10 ^ 18 * Real.exp (-41) := by + nlinarith [hmono, Real.exp_pos ((int256 x : Real) / (RAY : Real))] + _ < 10 ^ 18 * (2 / 10 ^ 18) := by nlinarith [hexpneg41] + _ = 2 := by norm_num + +/-- info: 'ExpYul.belowC_target_lt_two' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms belowC_target_lt_two + +end + +end ExpYul From b04d64cc585f4378f76ae52fa0a56533fff9264b Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 13:45:17 +0200 Subject: [PATCH 056/149] Add the exp even-Horner truncation bridge (RuntimeR0Bound gap-2, even half) The runtime even accumulator evTree x truncates each Horner >> stage; this proves it brackets the exact even polynomial evNumV (vTree x) (degree-5 in v at the cleared scale 2^553) within 2 units. Building blocks, all axiom-clean: - stage_exact: one Horner stage is the exact integer floor c + floor(prev*v/2^sh) (2^sh-scaled two-sided bracket); - tele_step: the telescoping induction step -- a stage bracket plus the cumulative invariant at scale 2^c0 gives the invariant at 2^(c0+sh), the propagated loss staying < 2^sh because sh >= 128 exceeds the 126-bit width of v; - ev0_exact: the leading shr-of-v stage; - even_stage: one telescoped runtime stage (stage_exact + tele_step composed); - evNumV / evTree_bracket: the 5-stage assembly. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 220 +++++++++++++++++- 1 file changed, 210 insertions(+), 10 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index 706bb0f9e..9b30d2d3e 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -1,5 +1,6 @@ import ExpProof.Floor.Fold import ExpProof.Floor.TBound +import ExpProof.Mono.Quot import Mathlib.Data.Complex.ExponentialBounds /-! @@ -7,26 +8,227 @@ import Mathlib.Data.Complex.ExponentialBounds `RuntimeR0Bound` (the single analytic obligation for the public floor brackets) brackets the Q126 quotient `r0Tree x` against the target `E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(126 − k)`. -This file discharges its self-contained `belowC` field — below the clamp boundary the target is -under one output unit — directly from a `Real.exp` rational bound. +This file builds two ingredients of that discharge: -`belowC`: for any word `x` whose signed value is at or below `Cmask = ⌊−18·ln10·10²⁷⌋`, the target -`E = 10¹⁸·exp(int256 x / 10²⁷)` is below `2`. Since `Cmask < −41·10²⁷` and `exp` is increasing, -`E ≤ 10¹⁸·exp(−41)`, and `exp(−41) = (exp 1)⁻⁴¹ < 2·10⁻¹⁸` because `exp 1 > 2.7182818283` (Mathlib's -`Real.exp_one_gt_d9`) forces `(exp 1)⁴¹ > 2.7182818283⁴¹ > 5·10¹⁷`. +* the **gap-2 (Horner-truncation) bridge** for the even accumulator — the runtime `evTree x`, which + truncates each Horner `>>` stage, brackets the exact even polynomial `evNumV (vTree x)` (a degree-5 + polynomial in `v` at the cleared scale `2^553`) within `2` units: per-stage floor losses telescope + with shrinking amplification (each stage shift exceeds `126 = ⌈log₂ v⌉`); +* the self-contained **`belowC`** field — below the clamp boundary the target is under one output + unit — directly from a `Real.exp` rational bound. -/ namespace ExpYul open FormalYul open FormalYul.Preservation + +set_option maxRecDepth 100000 + +/-! ## Gap-2: the even Horner accumulator brackets the exact polynomial + +Each runtime Horner stage `evmAdd c (evmShr sh (evmMul prev v))` is the integer floor +`c + ⌊prev·v / 2^sh⌋`; the floor loss `< 1` at scale `2^sh`. Cleared to the common scale `2^553` +the runtime accumulator `evTree x` brackets the exact degree-5 polynomial `evNumV (vTree x)` within +`2·2^553`: the propagated loss stays below `2^sh` because every stage shift exceeds the `126`-bit +width of `v = vTree x`. -/ + +theorem stage_exact {c prev v sh : Nat} (hprev : prev < 2^256) (hvw : v < 2^256) + (hpv : prev * v < 2 ^ 256) (hsh : sh < 256) + (hc : c < 2 ^ 256) (hsum : c + prev * v / 2 ^ sh < 2 ^ 256) : + 2 ^ sh * (evmAdd c (evmShr sh (evmMul prev v)) - c) ≤ prev * v ∧ + prev * v < 2 ^ sh * (evmAdd c (evmShr sh (evmMul prev v)) - c) + 2 ^ sh := by + have hmul : evmMul prev v = prev * v := evmMul_eq_nat hprev hvw hpv + have hshr : evmShr sh (evmMul prev v) = prev * v / 2 ^ sh := by rw [hmul]; exact evmShr_eq_div hsh hpv + have hshr_lt : prev * v / 2 ^ sh < 2 ^ 256 := lt_of_le_of_lt (Nat.div_le_self _ _) hpv + rw [hshr, evmAdd_eq_nat hc hshr_lt hsum, Nat.add_sub_cancel_left] + have hpos : 0 < 2 ^ sh := Nat.two_pow_pos sh + have hdm := Nat.div_add_mod (prev * v) (2 ^ sh) + have hmod := Nat.mod_lt (prev * v) hpos + generalize prev * v / 2 ^ sh = q at * + generalize prev * v % 2 ^ sh = r at * + omega + +theorem tele_step (e0 e1 v A c0 s E0 : Nat) + (hv : v < 2^126) (hs : 128 ≤ s) (hAe1 : A ≤ e1) + (hb0lo : 2^c0 * e0 ≤ E0) (hb0hi : E0 < 2^c0 * e0 + 2 * 2^c0) + (hslo : 2^s * (e1 - A) ≤ e0 * v) (hshi : e0 * v < 2^s * (e1 - A) + 2^s) : + 2^(c0+s) * e1 ≤ A * 2^(c0+s) + E0 * v ∧ + A * 2^(c0+s) + E0 * v < 2^(c0+s) * e1 + 2 * 2^(c0+s) := by + have hpc0 : (0:Nat) < 2^c0 := Nat.two_pow_pos _ + have hps : (0:Nat) < 2^s := Nat.two_pow_pos _ + have hsplit : (2:Nat)^(c0+s) = 2^c0 * 2^s := by rw [Nat.pow_add] + set d := e1 - A with hd + have he1eq : e1 = A + d := by omega + have hvs : 2 * 2^c0 * v < 2^(c0+s) := by + rw [hsplit] + have h2v : 2 * v < 2^s := by + have h127 : (2:Nat)*2^126 = 2^127 := by ring + have h128 : (2:Nat)^127 ≤ 2^s := Nat.pow_le_pow_right (by norm_num) (by omega) + omega + calc 2*2^c0*v = 2^c0*(2*v) := by ring + _ < 2^c0 * 2^s := (Nat.mul_lt_mul_left hpc0).mpr h2v + rw [hsplit, he1eq] + have key_lo : 2^c0 * 2^s * d ≤ E0 * v := by + calc 2^c0 * 2^s * d = 2^c0 * (2^s * d) := by ring + _ ≤ 2^c0 * (e0 * v) := by gcongr + _ = (2^c0 * e0) * v := by ring + _ ≤ E0 * v := by gcongr + have hps2 : (0:Nat) < 2^(c0+s) := Nat.two_pow_pos _ + have key_hi : E0 * v < 2^c0 * 2^s * d + 2 * 2^(c0+s) := by + rcases Nat.eq_zero_or_pos v with hv0 | hv0 + · subst hv0; simpa using hps2 + have h1 : E0 * v < (2^c0 * e0 + 2*2^c0) * v := (Nat.mul_lt_mul_right hv0).mpr hb0hi + have h2 : (2^c0 * e0 + 2*2^c0) * v = 2^c0 * (e0*v) + 2*2^c0*v := by ring + have h3 : 2^c0 * (e0*v) < 2^c0 * (2^s*d + 2^s) := (Nat.mul_lt_mul_left hpc0).mpr hshi + have h4 : 2^c0 * (2^s*d+2^s) = 2^c0*2^s*d + 2^c0*2^s := by ring + rw [hsplit] at hvs + omega + constructor + · nlinarith [key_lo] + · nlinarith [key_hi] + +theorem ev0_exact {v : Nat} (hv : v < 2 ^ 126) : + 2^0x1d * (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) - 0xb9aacfad41060587203a79af0ebc) ≤ v ∧ + v < 2^0x1d * (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) - 0xb9aacfad41060587203a79af0ebc) + 2^0x1d := by + have hshr : evmShr 0x1d v = v / 2^0x1d := evmShr_eq_div (by norm_num) (by omega) + have ht : v / 2^0x1d < 2^97 := by + have : v / 2^0x1d < 2^126/2^0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv + have he : (2:Nat)^126/2^0x1d = 2^97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] + omega + rw [hshr, evmAdd_eq_nat (by norm_num) (by omega) (by omega), Nat.add_sub_cancel_left] + have hpos : 0 < 2^0x1d := Nat.two_pow_pos _ + have hdm := Nat.div_add_mod v (2^0x1d) + have hmod := Nat.mod_lt v hpos + generalize v / 2^0x1d = q at * + generalize v % 2^0x1d = r at * + omega + +def evNumV (v : Nat) : Nat := + let e0 := 0xb9aacfad41060587203a79af0ebc * 2^29 + v + let e1 := 0x9a036222e11aee18465042f8ea64c8 * 2^159 + e0 * v + let e2 := 0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + e1 * v + let e3 := 0x93f11e65781741b92fa7fc4f4fffcca2 * 2^421 + e2 * v + 0x4e14a45e8ec305e233e11b4174e214ac * 2^553 + e3 * v + +-- helper: one telescoping stage as applied to runtime tree, producing the stage value bound + bracket +theorem even_stage (c P prev v cum sh Eprev : Nat) + (hv : v < 2^126) (hs : 128 ≤ sh) (hsh256 : sh < 256) (hprevlt : prev < P) (hPV : P * 2^126 < 2^256) + (hsum : c + P * 2^126 / 2^sh < 2^256) (hclt : c < 2^256) + (hElo : 2^cum * prev ≤ Eprev) (hEhi : Eprev < 2^cum * prev + 2 * 2^cum) : + 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) ≤ c * 2^(cum+sh) + Eprev * v ∧ + c * 2^(cum+sh) + Eprev * v < 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) + 2 * 2^(cum+sh) := by + have hprev256 : prev < 2^256 := by have : P ≤ 2^256 := by omega + omega + have hv256 : v < 2^256 := by have : (2:Nat)^126 < 2^256 := by norm_num + omega + have hpv : prev * v < 2^256 := lt_of_lt_of_le (Nat.mul_lt_mul'' hprevlt hv) (by omega) + have hsum' : c + prev * v / 2^sh < 2^256 := by + have : prev * v / 2^sh ≤ P * 2^126 / 2^sh := by + apply Nat.div_le_div_right; exact Nat.le_of_lt (Nat.mul_lt_mul'' hprevlt hv) + omega + have hst := stage_exact hprev256 hv256 hpv hsh256 hclt hsum' + set ev1 := evmAdd c (evmShr sh (evmMul prev v)) with hev1 + have hge : c ≤ ev1 := by + rw [hev1, evmAdd_eq_nat hclt (by exact evmShr_lt _ _) (by + have hmul : evmMul prev v = prev * v := evmMul_eq_nat hprev256 hv256 hpv + have : evmShr sh (evmMul prev v) = prev*v/2^sh := by rw [hmul]; exact evmShr_eq_div (by omega) hpv + rw [this]; omega)] + omega + exact tele_step prev ev1 v c cum sh Eprev hv hs hge hElo hEhi hst.1 hst.2 + +#check @even_stage + +theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : + 2^553 * evTree x ≤ evNumV (vTree x) ∧ evNumV (vTree x) < 2^553 * evTree x + 2 * 2^553 := by + have hev : evTree x = + evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul + (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul + (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul + (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul + (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d (vTree x))) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl + set v := vTree x with hvdef + -- stage 0 + have h0 := ev0_exact hv + set e0 := evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) with he0 + have he0lt : e0 < 2 ^ 113 := ev0_lt hv + have he0ge : 0xb9aacfad41060587203a79af0ebc ≤ e0 := ev0_ge hv + -- E0 = A4*2^29 + v; bracket 2^29*e0 <= E0 < 2^29*e0 + 2*2^29 + have h29 : (0x1d : Nat) = 29 := by norm_num + rw [h29] at h0 + have hE0lo : 2^29 * e0 ≤ 0xb9aacfad41060587203a79af0ebc * 2^29 + v := by have := h0.1; omega + have hE0hi : 0xb9aacfad41060587203a79af0ebc * 2^29 + v < 2^29 * e0 + 2 * 2^29 := by have := h0.2; omega + -- stage 1: cum 29 -> 159, sh=0x82=130, P=2^113 + have s1 := even_stage 0x9a036222e11aee18465042f8ea64c8 (2^113) e0 v 29 0x82 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) hv (by norm_num) (by norm_num) he0lt (by norm_num) + (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num) (by norm_num) hE0lo hE0hi + set e1 := evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul e0 v)) with he1 + have he1lt : e1 < 2^121 := by + have := (stage_bounds (c := 0x9a036222e11aee18465042f8ea64c8) (prev := e0) (v := v) + (P := 2^113) (V := 2^126) (sh := 0x82) he0lt hv (by norm_num) (by norm_num) + (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num)).2 + rw [pvd 113 126 130 109 (by norm_num)] at this; omega + -- E1 = A1stage*2^159 + E0*v (cum 159). s1 gives bracket on e1 with this E1. + -- stage 2: cum 159 -> 287, sh=0x80=128, P=2^121 + have s2 := even_stage 0x9064d965e1c4863b73604e0ddbec53f9 (2^121) e1 v 159 0x80 + (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) + hv (by norm_num) (by norm_num) he1lt (by norm_num) + (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 + set e2 := evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul e1 v)) with he2 + have he2lt : e2 < 2^129 := by + have := (stage_bounds (c := 0x9064d965e1c4863b73604e0ddbec53f9) (prev := e1) (v := v) + (P := 2^121) (V := 2^126) (sh := 0x80) he1lt hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 128 119 (by norm_num)] at this; omega + -- stage 3: cum 287 -> 421, sh=0x86=134, P=2^129 + have s3 := even_stage 0x93f11e65781741b92fa7fc4f4fffcca2 (2^129) e2 v 287 0x86 + (0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + + (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) * v) + hv (by norm_num) (by norm_num) he2lt (by norm_num) + (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num) (by norm_num) s2.1 s2.2 + set e3 := evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul e2 v)) with he3 + have he3lt : e3 < 2^129 := by + have := (stage_bounds (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (prev := e2) (v := v) + (P := 2^129) (V := 2^126) (sh := 0x86) he2lt hv (by norm_num) (by norm_num) + (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num)).2 + rw [pvd 129 126 134 121 (by norm_num)] at this; omega + -- stage 4: cum 421 -> 553, sh=0x84=132, P=2^129 + have s4 := even_stage 0x4e14a45e8ec305e233e11b4174e214ac (2^129) e3 v 421 0x84 + (0x93f11e65781741b92fa7fc4f4fffcca2 * 2^421 + + (0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + + (0x9a036222e11aee18465042f8ea64c8 * 2^159 + + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) * v) * v) + hv (by norm_num) (by norm_num) he3lt (by norm_num) + (by rw [pvd 129 126 132 123 (by norm_num)]; norm_num) (by norm_num) s3.1 s3.2 + -- assemble: evTree x = e4 (the stage-4 value), evNumV v = the cumulative E4. + rw [hev] + -- unfold evNumV to the same E4 expression + show 2^553 * evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul e3 v)) ≤ evNumV v ∧ + evNumV v < 2^553 * evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul e3 v)) + 2 * 2^553 + unfold evNumV + -- s4 has the right shape with cum+sh = 421+132 = 553 + have e553 : (421:Nat) + 0x84 = 553 := by norm_num + rw [e553] at s4 + -- the E4 in s4 = A0*2^553 + E3*v matches evNumV's let-expansion + constructor + · have := s4.1 + -- s4.1: 2^553 * e4 <= A0 * 2^553 + E3 * v. evNumV v = A0*2^553 + E3*v (after let). + convert this using 2 <;> ring + · have := s4.2 + convert this using 2 <;> ring + + +/-- info: 'ExpYul.evTree_bracket' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms evTree_bracket + +/-! ## The below-clamp target bound (`RuntimeR0Bound.belowC`) -/ + open ExpRealSpec open Real noncomputable section -set_option maxRecDepth 100000 - /-- **Below the clamp boundary the target is under two output units.** For any word `x` whose signed value is at or below the 0/1 clamp boundary `Cmask`, `E = 10¹⁸·exp(int256 x / 10²⁷) < 2`. -/ theorem belowC_target_lt_two {x : Nat} (hxle : int256 x ≤ int256 Cmask) : @@ -37,13 +239,11 @@ theorem belowC_target_lt_two {x : Nat} (hxle : int256 x ≤ int256 Cmask) : have hRAY : (RAY : Real) = 10 ^ 27 := by unfold RAY; norm_num have hWAD : (WAD : Real) = 10 ^ 18 := by unfold WAD; norm_num have hxR : (int256 x : Real) ≤ -41446531673892822312323846185 := by exact_mod_cast hxle - -- the reduced argument is at most `−41` have harg : (int256 x : Real) / (RAY : Real) ≤ -41 := by rw [hRAY, div_le_iff₀ (by norm_num : (0:Real) < 10 ^ 27)] nlinarith [hxR] have hmono : Real.exp ((int256 x : Real) / (RAY : Real)) ≤ Real.exp (-41) := Real.exp_le_exp.mpr harg - -- `(exp 1)^41 > 5·10^17` from `exp 1 > 2.7182818283` have hexp41 : (5 * 10 ^ 17 : ℝ) < (Real.exp 1) ^ 41 := by have h2 : (5 * 10 ^ 17 : ℝ) < (2.7182818283 : ℝ) ^ 41 := by norm_num calc (5 * 10 ^ 17 : ℝ) < (2.7182818283 : ℝ) ^ 41 := h2 From 59ff19b51f82b8689e9947dd45b57ea71bb8be2a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 13:48:00 +0200 Subject: [PATCH 057/149] Add the exp odd-Horner truncation bridge (RuntimeR0Bound gap-2, odd half) Mirror of the even bridge for the odd accumulator: the runtime odTree x (leading constant B4 then four mul/shr stages, shifts 0x83/0x89/0x7f/0x87) brackets the exact degree-4 polynomial odNumV (vTree x) within 2 units at the cleared scale 2^530. Reuses the shared horner_stage / tele_step machinery (relaxed to shift >= 127 to admit the 0x7f stage). Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 96 +++++++++++++++++-- 1 file changed, 87 insertions(+), 9 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index 9b30d2d3e..d7699372d 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -50,7 +50,7 @@ theorem stage_exact {c prev v sh : Nat} (hprev : prev < 2^256) (hvw : v < 2^256) omega theorem tele_step (e0 e1 v A c0 s E0 : Nat) - (hv : v < 2^126) (hs : 128 ≤ s) (hAe1 : A ≤ e1) + (hv : v < 2^126) (hs : 127 ≤ s) (hAe1 : A ≤ e1) (hb0lo : 2^c0 * e0 ≤ E0) (hb0hi : E0 < 2^c0 * e0 + 2 * 2^c0) (hslo : 2^s * (e1 - A) ≤ e0 * v) (hshi : e0 * v < 2^s * (e1 - A) + 2^s) : 2^(c0+s) * e1 ≤ A * 2^(c0+s) + E0 * v ∧ @@ -111,9 +111,11 @@ def evNumV (v : Nat) : Nat := let e3 := 0x93f11e65781741b92fa7fc4f4fffcca2 * 2^421 + e2 * v 0x4e14a45e8ec305e233e11b4174e214ac * 2^553 + e3 * v --- helper: one telescoping stage as applied to runtime tree, producing the stage value bound + bracket -theorem even_stage (c P prev v cum sh Eprev : Nat) - (hv : v < 2^126) (hs : 128 ≤ sh) (hsh256 : sh < 256) (hprevlt : prev < P) (hPV : P * 2^126 < 2^256) +/-- One telescoped runtime Horner stage: the stage value `evmAdd c (shr sh (mul prev v))` cleared to +scale `2^(cum+sh)` brackets `c·2^(cum+sh) + Eprev·v` within `2·2^(cum+sh)`, given the cumulative +bracket on `prev` at scale `2^cum`. -/ +theorem horner_stage (c P prev v cum sh Eprev : Nat) + (hv : v < 2^126) (hs : 127 ≤ sh) (hsh256 : sh < 256) (hprevlt : prev < P) (hPV : P * 2^126 < 2^256) (hsum : c + P * 2^126 / 2^sh < 2^256) (hclt : c < 2^256) (hElo : 2^cum * prev ≤ Eprev) (hEhi : Eprev < 2^cum * prev + 2 * 2^cum) : 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) ≤ c * 2^(cum+sh) + Eprev * v ∧ @@ -137,7 +139,6 @@ theorem even_stage (c P prev v cum sh Eprev : Nat) omega exact tele_step prev ev1 v c cum sh Eprev hv hs hge hElo hEhi hst.1 hst.2 -#check @even_stage theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : 2^553 * evTree x ≤ evNumV (vTree x) ∧ evNumV (vTree x) < 2^553 * evTree x + 2 * 2^553 := by @@ -159,7 +160,7 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : have hE0lo : 2^29 * e0 ≤ 0xb9aacfad41060587203a79af0ebc * 2^29 + v := by have := h0.1; omega have hE0hi : 0xb9aacfad41060587203a79af0ebc * 2^29 + v < 2^29 * e0 + 2 * 2^29 := by have := h0.2; omega -- stage 1: cum 29 -> 159, sh=0x82=130, P=2^113 - have s1 := even_stage 0x9a036222e11aee18465042f8ea64c8 (2^113) e0 v 29 0x82 + have s1 := horner_stage 0x9a036222e11aee18465042f8ea64c8 (2^113) e0 v 29 0x82 (0xb9aacfad41060587203a79af0ebc * 2^29 + v) hv (by norm_num) (by norm_num) he0lt (by norm_num) (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num) (by norm_num) hE0lo hE0hi set e1 := evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul e0 v)) with he1 @@ -170,7 +171,7 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : rw [pvd 113 126 130 109 (by norm_num)] at this; omega -- E1 = A1stage*2^159 + E0*v (cum 159). s1 gives bracket on e1 with this E1. -- stage 2: cum 159 -> 287, sh=0x80=128, P=2^121 - have s2 := even_stage 0x9064d965e1c4863b73604e0ddbec53f9 (2^121) e1 v 159 0x80 + have s2 := horner_stage 0x9064d965e1c4863b73604e0ddbec53f9 (2^121) e1 v 159 0x80 (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) hv (by norm_num) (by norm_num) he1lt (by norm_num) (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 @@ -181,7 +182,7 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num)).2 rw [pvd 121 126 128 119 (by norm_num)] at this; omega -- stage 3: cum 287 -> 421, sh=0x86=134, P=2^129 - have s3 := even_stage 0x93f11e65781741b92fa7fc4f4fffcca2 (2^129) e2 v 287 0x86 + have s3 := horner_stage 0x93f11e65781741b92fa7fc4f4fffcca2 (2^129) e2 v 287 0x86 (0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) * v) hv (by norm_num) (by norm_num) he2lt (by norm_num) @@ -193,7 +194,7 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num)).2 rw [pvd 129 126 134 121 (by norm_num)] at this; omega -- stage 4: cum 421 -> 553, sh=0x84=132, P=2^129 - have s4 := even_stage 0x4e14a45e8ec305e233e11b4174e214ac (2^129) e3 v 421 0x84 + have s4 := horner_stage 0x4e14a45e8ec305e233e11b4174e214ac (2^129) e3 v 421 0x84 (0x93f11e65781741b92fa7fc4f4fffcca2 * 2^421 + (0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + (0x9a036222e11aee18465042f8ea64c8 * 2^159 + @@ -222,6 +223,83 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : #guard_msgs in #print axioms evTree_bracket +/-! ## Gap-2: the odd Horner accumulator brackets the exact polynomial + +The odd accumulator starts at the leading constant `B4` (scale `0`) and runs four mul/shr stages +(shifts `0x83, 0x89, 0x7f, 0x87`, cumulative `131, 268, 395, 530`). Cleared to scale `2^530` the +runtime `odTree x` brackets the exact degree-4 polynomial `odNumV (vTree x)` within `2·2^530`. -/ + +/-- Exact integer odd-Horner numerator (degree-4 in `v`, scale `2^530`). -/ +def odNumV (v : Nat) : Nat := + let o1 := 0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v + let o2 := 0xad4506b00b1246c7e5b4fd33e1201b * 2^268 + o1 * v + let o3 := 0xaf5662483c4ce783a9ef5fe025f42e9e * 2^395 + o2 * v + 0x270a522f476182f119f08da0ba710a56 * 2^530 + o3 * v + +/-- Runtime odd-Horner accumulator brackets the exact polynomial within `2` ulp at scale `2^530`. -/ +theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : + 2^530 * odTree x ≤ odNumV (vTree x) ∧ odNumV (vTree x) < 2^530 * odTree x + 2 * 2^530 := by + have hod : odTree x = + evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul + (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul + (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul + (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul + 0xdc07aff85e5bb5629d0fb64a84bb (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl + set v := vTree x with hvdef + -- the leading constant is its own (trivial) cumulative bracket at scale 2^0 + have hB4lo : 2^0 * 0xdc07aff85e5bb5629d0fb64a84bb ≤ 0xdc07aff85e5bb5629d0fb64a84bb := by norm_num + have hB4hi : (0xdc07aff85e5bb5629d0fb64a84bb : Nat) < 2^0 * 0xdc07aff85e5bb5629d0fb64a84bb + 2 * 2^0 := by norm_num + -- stage 1: cum 0 -> 131, sh=0x83=131, prev=B4<2^112 + have s1 := horner_stage 0xc926ddbf3830ca5561cc01585402d0 (2^112) 0xdc07aff85e5bb5629d0fb64a84bb v 0 0x83 + 0xdc07aff85e5bb5629d0fb64a84bb hv (by norm_num) (by norm_num) (by norm_num) (by norm_num) + (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num) (by norm_num) hB4lo hB4hi + set o1 := evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb v)) with ho1 + have ho1lt : o1 < 2^121 := by + have := (stage_bounds (c := 0xc926ddbf3830ca5561cc01585402d0) (prev := 0xdc07aff85e5bb5629d0fb64a84bb) (v := v) + (P := 2^112) (V := 2^126) (sh := 0x83) (by norm_num) hv (by norm_num) (by norm_num) + (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num)).2 + rw [pvd 112 126 131 107 (by norm_num)] at this; omega + -- stage 2: cum 131 -> 268, sh=0x89=137, prev=o1<2^121 + have s2 := horner_stage 0xad4506b00b1246c7e5b4fd33e1201b (2^121) o1 v 131 0x89 + (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) hv (by norm_num) (by norm_num) ho1lt (by norm_num) + (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 + set o2 := evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul o1 v)) with ho2 + have ho2lt : o2 < 2^121 := by + have := (stage_bounds (c := 0xad4506b00b1246c7e5b4fd33e1201b) (prev := o1) (v := v) + (P := 2^121) (V := 2^126) (sh := 0x89) ho1lt hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 137 110 (by norm_num)] at this; omega + -- stage 3: cum 268 -> 395, sh=0x7f=127, prev=o2<2^121 + have s3 := horner_stage 0xaf5662483c4ce783a9ef5fe025f42e9e (2^121) o2 v 268 0x7f + (0xad4506b00b1246c7e5b4fd33e1201b * 2^268 + + (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) * v) hv (by norm_num) (by norm_num) ho2lt (by norm_num) + (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num) (by norm_num) s2.1 s2.2 + set o3 := evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul o2 v)) with ho3 + have ho3lt : o3 < 2^129 := by + have := (stage_bounds (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (prev := o2) (v := v) + (P := 2^121) (V := 2^126) (sh := 0x7f) ho2lt hv (by norm_num) (by norm_num) + (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num)).2 + rw [pvd 121 126 127 120 (by norm_num)] at this; omega + -- stage 4: cum 395 -> 530, sh=0x87=135, prev=o3<2^129 + have s4 := horner_stage 0x270a522f476182f119f08da0ba710a56 (2^129) o3 v 395 0x87 + (0xaf5662483c4ce783a9ef5fe025f42e9e * 2^395 + + (0xad4506b00b1246c7e5b4fd33e1201b * 2^268 + + (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) * v) * v) hv (by norm_num) (by norm_num) ho3lt (by norm_num) + (by rw [pvd 129 126 135 120 (by norm_num)]; norm_num) (by norm_num) s3.1 s3.2 + rw [hod] + show 2^530 * evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul o3 v)) ≤ odNumV v ∧ + odNumV v < 2^530 * evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul o3 v)) + 2 * 2^530 + unfold odNumV + have e530 : (395:Nat) + 0x87 = 530 := by norm_num + rw [e530] at s4 + constructor + · have := s4.1; convert this using 2 <;> ring + · have := s4.2; convert this using 2 <;> ring + +/-- info: 'ExpYul.odTree_bracket' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms odTree_bracket + /-! ## The below-clamp target bound (`RuntimeR0Bound.belowC`) -/ open ExpRealSpec From 0c91cad24e47708968648fcf78a213ce607f004f Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 13:50:32 +0200 Subject: [PATCH 058/149] Wire the discharged RuntimeR0Bound ingredients into the exp gate Theorems.lean now imports Floor.R0Bound and gates tTree_in_cert_domain, evTree_bracket, odTree_bracket, and belowC_target_lt_two so the axiom-clean build enforces them. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Theorems.lean | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 9211f690b..f2a04baa4 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -3,6 +3,7 @@ import ExpProof.Seam.Value import ExpProof.Mono import ExpProof.Floor.Public import ExpProof.Floor.Fold +import ExpProof.Floor.R0Bound /-! # `expRayToWad` — proven properties of the compiled runtime (signpost) @@ -151,4 +152,38 @@ example (H : RuntimeR0Bound) : RuntimeAccumBound := runtimeAccumBound_of_r0 H #guard_msgs in #print axioms runtimeAccumBound_of_r0 +/-! ## Discharged ingredients of `RuntimeR0Bound` + +The single open obligation `RuntimeR0Bound` is being discharged piecewise. The following are proved +unconditionally and axiom-clean: + +* `tTree_in_cert_domain` — the runtime reduced argument stays in the certificate domain + `|tTree x| ≤ H128`, so the Taylor caps (`Floor.Caps`) instantiate at `t := tTree x`; +* `evTree_bracket` / `odTree_bracket` — the **gap-2 Horner-truncation bridge**: the runtime even/odd + accumulators bracket the exact integer polynomials `evNumV`/`odNumV` (in `v = vTree x`) within `2` + units at the cleared scales `2^553`/`2^530`; +* `belowC_target_lt_two` — the `RuntimeR0Bound.belowC` field (below the clamp boundary `E < 2`). -/ +example {x : Nat} (hx : x < 2 ^ 256) + (hC : FormalYul.Preservation.int256 Cmask < FormalYul.Preservation.int256 x) + (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : + -(117932881612756647068972071382077242199 : Int) ≤ FormalYul.Preservation.int256 (tTree x) ∧ + FormalYul.Preservation.int256 (tTree x) ≤ 117932881612756647068972071382077242199 := + tTree_in_cert_domain hx hC hC0 + +/-- info: 'ExpYul.tTree_in_cert_domain' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms tTree_in_cert_domain + +/-- info: 'ExpYul.evTree_bracket' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms evTree_bracket + +/-- info: 'ExpYul.odTree_bracket' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms odTree_bracket + +/-- info: 'ExpYul.belowC_target_lt_two' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms belowC_target_lt_two + end ExpYul From a7d05fe89870755c114e17ea791d2c4d377ee47c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:49:38 +0200 Subject: [PATCH 059/149] Add the exp v-form Taylor cert for RuntimeR0Bound MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds a cut certificate directly on the runtime's v-form rational ê_v = (evNumV·2¹⁰⁵ + t·odNumV)/(evNumV·2¹⁰⁵ − t·odNumV), v = t²/2¹²⁸. The v-form NUM/DEN are degree-10 in t at the cleared scale 2^1193; the caps cutExpTaylorLeV_holds/cutRatioLeExpTaylorV_holds hold over [0,H128] at Taylor depth K=27, axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .github/workflows/exp-formal.yml | 3 +- formal/exp/ExpProof/ExpProof/Floor/CapsV.lean | 210 ++++++++++++++++++ .../ExpProof/ExpProof/Floor/CertDefsV.lean | 112 ++++++++++ formal/exp/ExpProof/GenExpVLit.lean | 136 ++++++++++++ 4 files changed, 460 insertions(+), 1 deletion(-) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/CapsV.lean create mode 100644 formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean create mode 100644 formal/exp/ExpProof/GenExpVLit.lean diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index daa5afc87..437b481da 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -101,8 +101,9 @@ jobs: - name: Generate Lean certificate artifacts working-directory: formal/exp/ExpProof run: | - lake build ExpProof.Floor.CertDefs Common.Foundation.KroneckerShift + lake build ExpProof.Floor.CertDefs ExpProof.Floor.CertDefsV Common.Foundation.KroneckerShift lake env lean GenExpLit.lean + lake env lean GenExpVLit.lean - name: Build Exp proof package working-directory: formal/exp/ExpProof diff --git a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean new file mode 100644 index 000000000..f5647f5ce --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean @@ -0,0 +1,210 @@ +import Mathlib.Tactic.NormNum +import Mathlib.Tactic.Ring +import Mathlib.Tactic.Positivity +import Mathlib.Algebra.Order.Floor.Defs +import ExpProof.Cert.ExpVUp +import ExpProof.Cert.ExpVLo +import ExpProof.Cert.ExpVNum +import ExpProof.Cert.ExpVDenM1 +import ExpProof.Spec.Cut + +/-! +# From cell certificates to the **v-form** reduced-argument Taylor caps + +The v-form cell covers (`Cert/ExpVUp`, `Cert/ExpVLo`, `Cert/ExpVNum`, `Cert/ExpVDenM1`) certify the +four v-form certificate polynomials nonnegative over `t ∈ [0, H128]`. This module converts that +nonnegativity into the two bare-argument Taylor caps the floor layer folds with `2^k`, targeting the +implementation's exact **v-form** rational `ê_v(t) = NUM(t)/DEN(t)` (built from the even/odd Horner +polynomials in `v = t²`) nudged by the dyadic margin, with `Qexp = 2^128`: + +* `cutExpTaylorLeV_holds` — `CutExpTaylorLe t Qexp (yUB t) (wUB t)` (never-over `exp(t) ≤ ê_v·(1+2⁻¹²⁰)`); +* `cutRatioLeExpTaylorV_holds` — `CutRatioLeExpTaylor (yLB t) (wLB t) t Qexp` + (not-two-below `ê_v·(1−2⁻¹²⁶) ≤ exp(t)`). + +These differ from the t-form caps only in the rational target (`ê_v` vs `ê_t`, equal as reals +but distinct integer polynomials): the runtime truncation bridge lands on `ê_v`, so the floor layer +needs the cut phrased on `ê_v`. The bridge is the depth-`K = 27` `Common.Exp.capUB_of_partial`/`capLB` +shape. +-/ + +namespace ExpCertV + +open Common.Poly Common.Exp ExpFloorCert + +set_option maxRecDepth 100000 + +/-! ## The two Int→Nat cap bridges at Taylor depth `K = 27` -/ + +/-- One evaluated partial sum (depth 27) plus the geometric tail gives a full upper cap. -/ +theorem capUB27_of_int {tn td y w : Nat} (htd : 0 < td) (hH : 2 * tn ≤ 29 * td) + (h : (expNumI 27 (tn : Int) (td : Int) * (28 * (td : Int)) + 2 * (tn : Int) ^ 28) * + (w : Int) ≤ (y : Int) * (304888344611713860501504000000 * (td : Int) ^ 28)) : + capUB tn td y w := by + refine capUB_of_partial htd (by omega : 2 * tn ≤ (27 + 2) * td) ?_ + show (expNum 27 tn td * ((27 + 1) * td) + 2 * tn ^ (27 + 1)) * w ≤ y * (fact 28 * td ^ 28) + rw [show fact 28 = 304888344611713860501504000000 from by decide, + show (27 + 1) = 28 from rfl] + refine Int.ofNat_le.mp ?_ + rw [expNumI_eq_expNum] at h + simp only [Int.natCast_mul, Int.natCast_add, Int.natCast_pow] + exact h + +/-- The single depth-27 partial sum reaches the lower target. -/ +theorem capLB27_of_int {tn td y w : Nat} + (h : (y : Int) * (10888869450418352160768000000 * (td : Int) ^ 27) ≤ + expNumI 27 (tn : Int) (td : Int) * (w : Int)) : + capLB tn td y w := by + refine ⟨27, ?_⟩ + show y * (fact 27 * td ^ 27) ≤ expNum 27 tn td * w + rw [show fact 27 = 10888869450418352160768000000 from by decide] + refine Int.ofNat_le.mp ?_ + rw [expNumI_eq_expNum] at h + simp only [Int.natCast_mul, Int.natCast_pow] + exact h + +/-! ## Evaluation shapes of the certificate polynomials -/ + +theorem evalExpN27 (t : Int) : evalPoly expN27 t = expNumI 27 t (Qexp : Int) := by + unfold expN27 + rw [evalPoly_expPolyNum] + congr 1 <;> simp [evalPoly] + +theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 120 + 1) * evalPoly numExpV t := by + unfold yUB; rw [evalPoly_polyScale] + +theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 120 * evalPoly denExpV t := by + unfold wUB; rw [evalPoly_polyScale] + +theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 126 - 1) * evalPoly numExpV t := by + unfold yLB; rw [evalPoly_polyScale] + +theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 126 * evalPoly denExpV t := by + unfold wLB; rw [evalPoly_polyScale] + +theorem evalTailUp (t : Int) : + evalPoly tailUp t = 28 * (Qexp : Int) * expNumI 27 t (Qexp : Int) + 2 * t ^ 28 := by + unfold tailUp + rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyScale, evalPoly_polyPow, evalExpN27] + congr 1 + show _ = 2 * t ^ 28 + rw [show evalPoly ([0, 1] : List Int) t = t from by simp [evalPoly]] + +/-- The never-over cert evaluates to the `capUB27_of_int` residue. -/ +theorem evalCertExpUp (t : Int) : + evalPoly certExpUp t = + fact28Q28 * evalPoly yUB t - + (28 * (Qexp : Int) * expNumI 27 t (Qexp : Int) + 2 * t ^ 28) * evalPoly wUB t := by + unfold certExpUp + rw [evalPoly_polySub, evalPoly_polyScale, evalPoly_polyMul, evalTailUp] + +/-- The not-two-below cert evaluates to the `capLB27_of_int` residue. -/ +theorem evalCertExpLo (t : Int) : + evalPoly certExpLo t = + expNumI 27 t (Qexp : Int) * evalPoly wLB t - fact27Q27 * evalPoly yLB t := by + unfold certExpLo + rw [evalPoly_polySub, evalPoly_polyMul, evalPoly_polyScale, evalExpN27] + +/-! ## Positivity of the rational over the domain -/ + +/-- `1 ≤ DEN(t)` over the domain. -/ +theorem denExpV_ge_one {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + 1 ≤ evalPoly denExpV t := by + have h := denM1V_nonneg h1 h2 + unfold certDenM1 at h + rw [evalPoly_polyAdd] at h + rw [show evalPoly ([-1] : List Int) t = -1 from by simp [evalPoly]] at h + omega + +/-- `0 ≤ NUM(t)` over the domain. -/ +theorem numExpV_nonneg' {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 + +/-! ## The bare-argument Taylor caps -/ + +theorem Qexp_eq : (Qexp : Int) = 2 ^ 128 := by unfold Qexp; norm_num + +theorem Qexp_pos : 0 < Qexp := by unfold Qexp; norm_num + +/-- **Never-over cap** at the v-form rational `yUB/wUB = ê_v·(1 + 2⁻¹²⁰)`: for every reduced argument +`t ∈ [0, H128]`, `exp(t/Qexp) ≤ yUB(t)/wUB(t)`. -/ +theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + capUB t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := by + have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 + have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 + have hden0 : 0 ≤ evalPoly denExpV t := by omega + have hc120 : (0 : Int) ≤ 2 ^ 120 + 1 := by norm_num + have hp120 : (0 : Int) ≤ 2 ^ 120 := by norm_num + have hyub : 0 ≤ evalPoly yUB t := by + rw [evalYUB]; exact Int.mul_nonneg hc120 hnum + have hwub : 0 ≤ evalPoly wUB t := by + rw [evalWUB]; exact Int.mul_nonneg hp120 hden0 + have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 + have hyn : ((evalPoly yUB t).toNat : Int) = evalPoly yUB t := Int.toNat_of_nonneg hyub + have hwn : ((evalPoly wUB t).toNat : Int) = evalPoly wUB t := Int.toNat_of_nonneg hwub + refine capUB27_of_int Qexp_pos ?_ ?_ + · have htle : t.toNat ≤ H128 := by + have : (t.toNat : Int) ≤ (H128 : Int) := by rw [htn]; exact h2 + exact_mod_cast this + have hHQ : 2 * H128 < 29 * Qexp := by unfold H128 Qexp; norm_num + omega + · rw [htn, hyn, hwn, Qexp_eq] + have h := expVUp_nonneg h1 h2 + rw [evalCertExpUp] at h + unfold fact28Q28 at h + rw [Qexp_eq] at h + have key : (28 * (2 : Int) ^ 128 * expNumI 27 t (2 ^ 128) + 2 * t ^ 28) * evalPoly wUB t ≤ + 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := by omega + calc (expNumI 27 t (2 ^ 128) * (28 * (2 : Int) ^ 128) + 2 * t ^ 28) * evalPoly wUB t + = (28 * (2 : Int) ^ 128 * expNumI 27 t (2 ^ 128) + 2 * t ^ 28) * evalPoly wUB t := by ring + _ ≤ 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := key + _ = evalPoly yUB t * (304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28) := by ring + +/-- **Not-two-below cap** at the v-form rational `yLB/wLB = ê_v·(1 − 2⁻¹²⁶)`: for every reduced +argument `t ∈ [0, H128]`, `yLB(t)/wLB(t) ≤ exp(t/Qexp)`. -/ +theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + capLB t.toNat Qexp (evalPoly yLB t).toNat (evalPoly wLB t).toNat := by + have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 + have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 + have hden0 : 0 ≤ evalPoly denExpV t := by omega + have hc126 : (0 : Int) ≤ 2 ^ 126 - 1 := by norm_num + have hp126 : (0 : Int) ≤ 2 ^ 126 := by norm_num + have hylb : 0 ≤ evalPoly yLB t := by + rw [evalYLB]; exact Int.mul_nonneg hc126 hnum + have hwlb : 0 ≤ evalPoly wLB t := by + rw [evalWLB]; exact Int.mul_nonneg hp126 hden0 + have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 + have hyn : ((evalPoly yLB t).toNat : Int) = evalPoly yLB t := Int.toNat_of_nonneg hylb + have hwn : ((evalPoly wLB t).toNat : Int) = evalPoly wLB t := Int.toNat_of_nonneg hwlb + refine capLB27_of_int ?_ + rw [htn, hyn, hwn, Qexp_eq] + have h := expVLo_nonneg h1 h2 + rw [evalCertExpLo] at h + unfold fact27Q27 at h + rw [Qexp_eq] at h + calc evalPoly yLB t * (10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27) + = 10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27 * evalPoly yLB t := by ring + _ ≤ expNumI 27 t (2 ^ 128) * evalPoly wLB t := by omega + +/-! ## The bare-argument v-form caps as cut predicates -/ + +/-- **Never-over Taylor cut (v-form).** For every reduced argument `t ∈ [0, H128]`, +`exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê_v(t)·(1 + 2⁻¹²⁰)`. -/ +theorem cutExpTaylorLeV_holds {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + CutExpTaylorLe t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := + capExpUp h1 h2 + +/-- **Not-two-below Taylor cut (v-form).** For every reduced argument `t ∈ [0, H128]`, +`yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê_v(t)·(1 − 2⁻¹²⁶)`. -/ +theorem cutRatioLeExpTaylorV_holds {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : + CutRatioLeExpTaylor (evalPoly yLB t).toNat (evalPoly wLB t).toNat t.toNat Qexp := + capExpLo h1 h2 + +/-- info: 'ExpCertV.cutExpTaylorLeV_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms cutExpTaylorLeV_holds + +/-- info: 'ExpCertV.cutRatioLeExpTaylorV_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms cutRatioLeExpTaylorV_holds + +end ExpCertV diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean new file mode 100644 index 000000000..6f51d140d --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean @@ -0,0 +1,112 @@ +import Common.Foundation.ShiftCert + +/-! +# The v-form reduced-argument rational target and its Taylor cut certificates + +The runtime forms `r0 = ⌊ê_v(t)·2^126⌋` with the **v-form** rational + +``` +ê_v(t) = (evNumV(v) · 2^105 + t · odNumV(v)) / (evNumV(v) · 2^105 − t · odNumV(v)), v = t²/2^128, +``` + +built from the exact integer even/odd Horner polynomials `evNumV`/`odNumV` (defined in +`Floor/R0Bound.lean` as functions of the integer `v = vTree x`). The runtime's truncation bridge +lands on this representation, so the floor layer needs a cut certificate phrased on `ê_v`, not on the +t-form `ê_t = numExp/denExp`. `ê_v` and `ê_t` are equal as reals but differ as integer +polynomials (different shift-clearing), so this module re-derives the cut against `ê_v` directly. + +Here `v = t²` is carried symbolically (each Horner stage multiplies by `t²` via `mulT2`, with the +runtime per-stage `>>128` cleared into the per-stage scale): `evNumVPoly` accumulates `Ev` to the +cleared scale `2^1193` and `odNumVPoly` accumulates `Od` to `2^1042`; `t·Od` (lifted by `2^23`) joins +`Ev` at the common `2^1193`. The shared scale cancels in `ê_v = NUM/DEN`. As a polynomial in `t` the +numerator/denominator are degree 10. + +The cut is the standard `Common.Exp.capUB_of_partial`/`capLB` shape at Taylor depth `K = 27`, nudging +the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹²⁰)`, `yLB/wLB = ê_v·(1 − 2⁻¹²⁶)`); the +verified envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.057` ulp is far inside those margins. +-/ + +namespace ExpCertV + +open Common.Poly + +/-! ## The reduced-argument denominator and the cert domain -/ + +/-- The reduced-argument denominator `tDen = 2^128`: the runtime carries `t` in Q128. -/ +def Qexp : Nat := 2 ^ 128 + +/-- The cert variable upper bound `H128 = ⌊ln2/2 · 2^128⌋`. -/ +def H128 : Nat := 117932881612756647068972071382077242199 + +/-! ## Exact integer `ê_v(t) = NUM(t)/DEN(t)` from the implementation coefficients + +The even/odd Horner accumulators evaluated as exact polynomials in `t` with `v = t²/2^128`, each +runtime per-stage `>>128` cleared into the stage scale. `evNumVPoly` is `evNumV(t²)` cleared to scale +`2^640` (so its evaluation is `Ev·2^1193`); `odNumVPoly` is `odNumV(t²)` cleared to scale `2^512` +(evaluation `Od·2^1042`); `t·Od` (lifted by `2^23` to the common `2^1193`) joins `Ev`. The shared +`2^1193` cancels in `ê_v = NUM/DEN`. -/ + +/-- `t²·P` at the polynomial level (one Horner `·v` stage, with the runtime `>>128` cleared into the +per-stage constant scale). -/ +def mulT2 (P : List Int) : List Int := 0 :: 0 :: P + +/-- The even Horner accumulator `Ev`, cleared to scale `2^640` (evaluation `Ev·2^1193`). The +per-stage constants are the even coefficients `A0..A4` lifted by the cleared stage scale; the +innermost monic `v` stage clears to `[A4·2^157, 0, 1]`. -/ +def evNumVPoly : List Int := + polyAdd [0x4e14a45e8ec305e233e11b4174e214ac * 2 ^ 1193] + (mulT2 (polyAdd [0x93f11e65781741b92fa7fc4f4fffcca2 * 2 ^ 933] + (mulT2 (polyAdd [0x9064d965e1c4863b73604e0ddbec53f9 * 2 ^ 671] + (mulT2 (polyAdd [0x9a036222e11aee18465042f8ea64c8 * 2 ^ 415] + (mulT2 [0xb9aacfad41060587203a79af0ebc * 2 ^ 157, 0, 1]))))))) + +/-- The odd Horner accumulator `Od`, cleared to scale `2^512` (evaluation `Od·2^1042`). -/ +def odNumVPoly : List Int := + polyAdd [0x270a522f476182f119f08da0ba710a56 * 2 ^ 1042] + (mulT2 (polyAdd [0xaf5662483c4ce783a9ef5fe025f42e9e * 2 ^ 779] + (mulT2 (polyAdd [0xad4506b00b1246c7e5b4fd33e1201b * 2 ^ 524] + (mulT2 [0xc926ddbf3830ca5561cc01585402d0 * 2 ^ 259, 0, 0xdc07aff85e5bb5629d0fb64a84bb]))))) + +/-- `t·Od` lifted to the common scale `2^1193` (`= 2^23 · t · odNumVPoly`). -/ +def todNumV : List Int := polyScale (2 ^ 23) (0 :: odNumVPoly) + +/-- `ê_v`-numerator `NUM(t) = Ev(t) + t·Od(t)` (scale `2^1193`). -/ +def numExpV : List Int := polyAdd evNumVPoly todNumV + +/-- `ê_v`-denominator `DEN(t) = Ev(t) − t·Od(t)` (scale `2^1193`). -/ +def denExpV : List Int := polySub evNumVPoly todNumV + +/-! ## Taylor partial-sum numerator at the cut argument -/ + +/-- Polynomial-level depth-27 partial-sum numerator at argument `t/Qexp`. -/ +def expN27 : List Int := expPolyNum [0, 1] [(Qexp : Int)] 27 + +/-! ## Margin-nudged rational targets + +`yUB/wUB = ê_v·(1 + 2⁻¹²⁰)` and `yLB/wLB = ê_v·(1 − 2⁻¹²⁶)`. -/ + +def yUB : List Int := polyScale (2 ^ 120 + 1) numExpV +def wUB : List Int := polyScale (2 ^ 120) denExpV +def yLB : List Int := polyScale (2 ^ 126 - 1) numExpV +def wLB : List Int := polyScale (2 ^ 126) denExpV + +/-! ## The cut certificate polynomials -/ + +/-- `28! · Qexp^28`. -/ +def fact28Q28 : Int := 304888344611713860501504000000 * (Qexp : Int) ^ 28 + +/-- `27! · Qexp^27`. -/ +def fact27Q27 : Int := 10888869450418352160768000000 * (Qexp : Int) ^ 27 + +/-- The `capUB_of_partial` tail polynomial `expN27·(28·Qexp) + 2·t²⁸`. -/ +def tailUp : List Int := + polyAdd (polyScale (28 * (Qexp : Int)) expN27) (polyScale 2 (polyPow [0, 1] 28)) + +def certExpUp : List Int := polySub (polyScale fact28Q28 yUB) (polyMul tailUp wUB) + +def certExpLo : List Int := polySub (polyMul expN27 wLB) (polyScale fact27Q27 yLB) + +/-- `DEN(t) − 1`: nonnegativity over the domain certifies `1 ≤ DEN(t)`. -/ +def certDenM1 : List Int := polyAdd denExpV [-1] + +end ExpCertV diff --git a/formal/exp/ExpProof/GenExpVLit.lean b/formal/exp/ExpProof/GenExpVLit.lean new file mode 100644 index 000000000..f1b98192e --- /dev/null +++ b/formal/exp/ExpProof/GenExpVLit.lean @@ -0,0 +1,136 @@ +import ExpProof.Floor.CertDefsV +import Common.Foundation.KroneckerShift + +/-! +# Cert literal + cover generator for the **v-form** reduced-argument Taylor caps + +Computes the never-over (`certExpUp`) and not-two-below (`certExpLo`) v-form certificate polynomials +from the symbolic `ExpCertV` definitions, emits the building-block + cert literal coefficient lists +(`Cert/ExpVCertLit.lean`), then greedily walks `[0, H128]` for each — exactly the predicate the +in-kernel `checkCoverK` decides — and writes one `Cert/ExpV{Up,Lo,…}C.lean` cell file per sub-cell +plus the cover module with the symbolic-cert↔literal equality and the `_nonneg` ladder. + +Run with `lake env lean GenExpVLit.lean` after `lake build ExpProof.Floor.CertDefsV`. Output is +deterministic (byte-identical on re-run). Only the generated `Cert/ExpV*` files are machine output; +this generator and the hand-written `Floor/CertDefsV.lean` symbolic definitions are tracked. +-/ + +open Common.Poly ExpCertV + +namespace GenExpVLit + +/-- Drop trailing zero coefficients. -/ +def ptrim (a : List Int) : List Int := + let r := (a.reverse.dropWhile (· == 0)).reverse + if r.isEmpty then [0] else r + +/-- Largest `w ∈ [0, hiW]` with `0 ≤ (hornerIv S 0 w).1` (non-increasing in `w`). -/ +partial def maxW (S : List Int) (hiW : Int) : Int := + let rec bs (lo hi : Int) : Int := + if lo ≥ hi then lo + else let mid := (lo + hi + 1) / 2 + if 0 ≤ (hornerIv S 0 mid).1 then bs mid hi else bs lo (mid - 1) + bs 0 hiW + +/-- Greedy walk → `(reached?, (anchor, width) list)`. -/ +partial def walk (C : List Int) (lo hi : Int) : Bool × List (Int × Int) := + let rec go (a : Int) (fuel : Nat) (acc : List (Int × Int)) : Bool × List (Int × Int) := + match fuel with + | 0 => (false, acc.reverse) + | fuel + 1 => + if a > hi then (true, acc.reverse) + else + let S := kShiftWitness kB C a + if 0 ≤ (hornerIv S 0 0).1 then + let w := maxW S (hi - a) + go (a + w + 1) fuel ((a, w) :: acc) + else (false, ((a, -1) :: acc).reverse) + go lo 200000 [] + +def pad2 (i : Nat) : String := (if i < 10 then "0" else "") ++ toString i + +/-- Walk `[lo, hi]`, write one cell file per sub-cell, then write the cover module. -/ +def emit (litName coverMod modPrefix cellPrefix certEqName litNonneg symNonneg symName eqTac : String) + (C : List Int) (lo hi : Int) : IO Unit := do + let (ok, cells) := walk C lo hi + IO.println s!"-- {coverMod}: reached={ok} ncells={cells.length}" + if ! ok then IO.println s!"-- FAILED tail: {cells.drop (cells.length - 2)}"; return + for (aw, i) in cells.zipIdx do + let (a, w) := aw + IO.FS.writeFile s!"ExpProof/Cert/{modPrefix}{pad2 i}.lean" + s!"import ExpProof.Cert.ExpVCertLit\nimport Common.Foundation.KroneckerShift\n\nnamespace ExpCertV\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{pad2 i} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend ExpCertV\n" + let lb := "{"; let rb := "}" + let mut s := "import ExpProof.Floor.CertDefsV\nimport ExpProof.Cert.ExpVCertLit\nimport Common.Foundation.KroneckerShift\n" + for (_, i) in cells.zipIdx do s := s ++ s!"import ExpProof.Cert.{modPrefix}{pad2 i}\n" + s := s ++ s!"\nnamespace ExpCertV\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\n" + s := s ++ s!"theorem {certEqName} : {symName} = {litName} := by\n{eqTac}\n\n" + s := s ++ s!"theorem {litNonneg} {lb}t : Int{rb} (h1 : {lo} ≤ t) (h2 : t ≤ {hi}) :\n" + s := s ++ s!" 0 ≤ evalPoly {litName} t := by\n" + let n := cells.length + for (aw, i) in cells.zipIdx do + let (a, w) := aw + if i + 1 < n then + s := s ++ s!" rcases Int.lt_or_le t ({a + w} + 1) with h | h\n · exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} t (by omega) (by omega)\n" + else + s := s ++ s!" exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} t (by omega) h2\n" + s := s ++ s!"\ntheorem {symNonneg} {lb}t : Int{rb} (h1 : {lo} ≤ t) (h2 : t ≤ {hi}) :\n" + s := s ++ s!" 0 ≤ evalPoly {symName} t := by\n rw [{certEqName}]; exact {litNonneg} h1 h2\n" + s := s ++ "\nend ExpCertV\n" + IO.FS.writeFile s!"ExpProof/Cert/{coverMod}.lean" s + +def litText (name : String) (c : List Int) : String := + "def " ++ name ++ " : List Int := [\n " ++ + String.intercalate ",\n " (c.map toString) ++ "]\n\n" + +end GenExpVLit + +open GenExpVLit + +/-- Tactic block proving `certExpUp = certExpUpLit`. -/ +def upEqTac : String := + " have hy : yUB = yUBLit := by unfold yUB numExpV evNumVPoly todNumV odNumVPoly mulT2; decide +kernel\n" ++ + " have hw : wUB = wUBLit := by unfold wUB denExpV evNumVPoly todNumV odNumVPoly mulT2; decide +kernel\n" ++ + " have ht : tailUp = tailUpLit := by unfold tailUp expN27; decide +kernel\n" ++ + " unfold certExpUp\n rw [hy, hw, ht]\n decide +kernel" + +/-- Tactic block proving `certExpLo = certExpLoLit`. -/ +def loEqTac : String := + " have he : expN27 = expN27Lit := by unfold expN27; decide +kernel\n" ++ + " have hy : yLB = yLBLit := by unfold yLB numExpV evNumVPoly todNumV odNumVPoly mulT2; decide +kernel\n" ++ + " have hw : wLB = wLBLit := by unfold wLB denExpV evNumVPoly todNumV odNumVPoly mulT2; decide +kernel\n" ++ + " unfold certExpLo\n rw [he, hy, hw]\n decide +kernel" + +/-- Tactic block proving `numExpV = numExpVLit`. -/ +def numEqTac : String := + " unfold numExpV evNumVPoly todNumV odNumVPoly mulT2\n decide +kernel" + +/-- Tactic block proving `certDenM1 = certDenM1Lit`. -/ +def denM1EqTac : String := + " unfold certDenM1 denExpV evNumVPoly todNumV odNumVPoly mulT2\n decide +kernel" + +#eval do + let cUp := ptrim certExpUp + let cLo := ptrim certExpLo + IO.FS.writeFile "ExpProof/Cert/ExpVCertLit.lean" + ("/-! Generated v-form cut-certificate literal coefficient lists. -/\n\nnamespace ExpCertV\n\n" ++ + litText "numExpVLit" (ptrim numExpV) ++ + litText "denExpVLit" (ptrim denExpV) ++ + litText "expN27Lit" (ptrim expN27) ++ + litText "tailUpLit" (ptrim tailUp) ++ + litText "yUBLit" (ptrim yUB) ++ + litText "wUBLit" (ptrim wUB) ++ + litText "yLBLit" (ptrim yLB) ++ + litText "wLBLit" (ptrim wLB) ++ + litText "certDenM1Lit" (ptrim certDenM1) ++ + litText "certExpUpLit" cUp ++ + litText "certExpLoLit" cLo ++ + "end ExpCertV\n") + IO.println "v-form literals written" + emit "certExpUpLit" "ExpVUp" "ExpVUpC" "expVUp_cell" "certExpUp_eq" "expVUpLit_nonneg" + "expVUp_nonneg" "certExpUp" upEqTac cUp 0 (H128 : Int) + emit "certExpLoLit" "ExpVLo" "ExpVLoC" "expVLo_cell" "certExpLo_eq" "expVLoLit_nonneg" + "expVLo_nonneg" "certExpLo" loEqTac cLo 0 (H128 : Int) + emit "numExpVLit" "ExpVNum" "ExpVNumC" "expVNum_cell" "numExpV_eq" "numExpVLit_nonneg" + "numExpV_nonneg" "numExpV" numEqTac (ptrim numExpV) 0 (H128 : Int) + emit "certDenM1Lit" "ExpVDenM1" "ExpVDenM1C" "expVDenM1_cell" "certDenM1_eq" "denM1VLit_nonneg" + "denM1V_nonneg" "certDenM1" denM1EqTac (ptrim certDenM1) 0 (H128 : Int) From 4658fa1de1e9d53dc8db4808ba3c5852add25495 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 14:34:53 +0200 Subject: [PATCH 060/149] Add the exp reduced-argument real bound (RuntimeR0Bound gap-1) Certifies a 235-bit two-sided bound on Real.log 2 (LN2/2^235 <= ln2 < (LN2+1)/2^235) via the same Taylor-cut machinery the floor layer uses (depth-50 capUB, depth-49 capLB; no high-precision Mathlib log input), then proves |rt - t/2^128| < 2/2^128 where rt = X/RAY - k*ln2 is the reduced argument. Both axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../exp/ExpProof/ExpProof/Floor/Ln2Bound.lean | 106 ++++++++++ .../exp/ExpProof/ExpProof/Floor/Reduce.lean | 197 ++++++++++++++++++ 2 files changed, 303 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/Ln2Bound.lean create mode 100644 formal/exp/ExpProof/ExpProof/Floor/Reduce.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/Ln2Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/Ln2Bound.lean new file mode 100644 index 000000000..db3becf41 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/Ln2Bound.lean @@ -0,0 +1,106 @@ +import Common.Seam.RealExpBridge +import Mathlib.Analysis.SpecialFunctions.Log.Basic + +/-! +# A 235-bit two-sided bound on `Real.log 2` + +The runtime reduces `x` by the octave constant `LN2 = ⌊ln2·2²³⁵⌋` +(`= 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d`). Closing the reduced-argument +real identity (`x/RAY − k·ln2 ≈ t/2¹²⁸`) needs `ln2` pinned to that 235-bit grid: + +``` +LN2 / 2²³⁵ ≤ ln 2 < (LN2 + 1) / 2²³⁵. +``` + +Mathlib only provides `ln2` to ten digits (`log_two_lt_d9`/`log_two_gt_d9`), far short of the ~71 +digits required. This module certifies both sides through the *same* Taylor-cut machinery the floor +layer uses, with no high-precision Mathlib `log` input: + +* `2 ≤ exp((LN2+1)/2²³⁵)` is a depth-49 `capLB` (a single partial sum reaches `2`), giving + `(LN2+1)/2²³⁵ ≥ ln 2` after `Real.le_log_iff_exp_le`-style reasoning; +* `exp(LN2/2²³⁵) ≤ 2` is a depth-50 `capUB_of_partial` (the geometric tail fits under `2`), giving + `LN2/2²³⁵ ≤ ln 2`. + +Both certificate inequalities are concrete `Nat` comparisons (decided in the kernel), so the bound is +axiom-clean. +-/ + +namespace ExpYul + +open Common.Exp Common.RealExpBridge + +noncomputable section + +set_option maxRecDepth 100000 + +/-- The runtime octave constant `LN2 = ⌊ln2·2²³⁵⌋`. -/ +def LN2c : Nat := 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d + +/-- The decimal value of `LN2c`. -/ +theorem LN2c_eq : LN2c = 38271408169742254668347313025622401492114385419650052359639581444463709 := by + unfold LN2c; norm_num + +/-! ## `exp(LN2/2²³⁵) ≤ 2` via a depth-50 upper cap -/ + +/-- The upper cut: every Taylor partial sum of `exp(LN2/2²³⁵)` stays at or below `2`. -/ +theorem ln2_capUB : capUB LN2c (2 ^ 235) 2 1 := by + refine capUB_of_partial (by norm_num) (K := 50) ?_ ?_ + · rw [LN2c_eq]; norm_num + · rw [LN2c_eq]; decide +kernel + +/-- `exp(LN2/2²³⁵) ≤ 2`. -/ +theorem exp_ln2_le_two : Real.exp ((LN2c : Real) / (2 ^ 235 : Real)) ≤ 2 := by + have h := exp_le_of_capUB (p := LN2c) (q := 2 ^ 235) (y := 2) (w := 1) + (by norm_num) (by norm_num) ln2_capUB + have hq : (((2 ^ 235 : Nat) : Nat) : Real) = (2 ^ 235 : Real) := by + rw [Nat.cast_pow]; norm_num + rw [hq] at h + simpa using h + +/-! ## `2 ≤ exp((LN2+1)/2²³⁵)` via a depth-49 lower cap -/ + +/-- The lower cut: the depth-49 Taylor partial sum of `exp((LN2+1)/2²³⁵)` reaches `2`. -/ +theorem ln2_capLB : capLB (LN2c + 1) (2 ^ 235) 2 1 := by + refine ⟨49, ?_⟩ + rw [LN2c_eq]; decide +kernel + +/-- `2 ≤ exp((LN2+1)/2²³⁵)`. -/ +theorem two_le_exp_ln2_succ : + (2 : Real) ≤ Real.exp (((LN2c : Real) + 1) / (2 ^ 235 : Real)) := by + have h := le_exp_of_capLB (p := LN2c + 1) (q := 2 ^ 235) (y := 2) (w := 1) + (by norm_num) (by norm_num) ln2_capLB + have hq : (((2 ^ 235 : Nat) : Nat) : Real) = (2 ^ 235 : Real) := by + rw [Nat.cast_pow]; norm_num + have hp : (((LN2c + 1 : Nat) : Real)) = (LN2c : Real) + 1 := by push_cast; ring + rw [hq, hp] at h + simpa using h + +/-! ## The two-sided `ln 2` bound -/ + +theorem two_pow_235_pos : (0 : Real) < (2 ^ 235 : Real) := by positivity + +/-- **Lower bound:** `LN2/2²³⁵ ≤ ln 2`. From `exp(LN2/2²³⁵) ≤ 2`, applying `Real.log` (monotone) and +`Real.log_exp`. -/ +theorem ln2_lower : (LN2c : Real) / (2 ^ 235 : Real) ≤ Real.log 2 := by + have h := exp_ln2_le_two + have := Real.log_le_log (Real.exp_pos _) h + rwa [Real.log_exp] at this + +/-- **Upper bound:** `ln 2 < (LN2+1)/2²³⁵`. From `2 ≤ exp((LN2+1)/2²³⁵)` (and strictness off the +boundary, since `LN2 = ⌊ln2·2²³⁵⌋` is strict). -/ +theorem ln2_upper : Real.log 2 ≤ ((LN2c : Real) + 1) / (2 ^ 235 : Real) := by + have h := two_le_exp_ln2_succ + have := Real.log_le_log (by norm_num : (0:Real) < 2) h + rwa [Real.log_exp] at this + +/-- info: 'ExpYul.ln2_lower' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms ln2_lower + +/-- info: 'ExpYul.ln2_upper' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms ln2_upper + +end + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean new file mode 100644 index 000000000..76ec4dd5d --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean @@ -0,0 +1,197 @@ +import ExpProof.Floor.Ln2Bound +import ExpProof.Floor.TBound +import ExpProof.Spec.RealExp + +/-! +# The reduced-argument real identity (gap-1) + +The runtime forms the reduced argument `t = tTree x` (Q128) and octave index `k = kTree x` so that +`exp(x/RAY) = 2^k · exp(rt)` with `rt = X/RAY − k·ln2` (`X = int256 x`). To fold the cert's +`exp(t/2¹²⁸)` bound onto the target, the reduced argument `rt` must coincide with `t/2¹²⁸` up to a +margin the runtime `MARGIN` absorbs: + +``` +|rt − t/2¹²⁸| < 2 / 2¹²⁸. +``` + +Decompose `rt − t/2¹²⁸ = P1 + P2 + P3`: + +* `P1 = X·(1/RAY − K27/2²³⁵)` — the rational coefficient error over `|X| < 2⁹⁶`, below `2⁻¹³³`; +* `P2 = k·(LN2/2²³⁵ − ln2)` — the `ln2`-grid error (`0 ≤ ln2 − LN2/2²³⁵ < 2⁻²³⁵`, from `Ln2Bound`) + over `|k| ≤ 63`, below `2⁻²²⁹`; +* `P3 = (K27·X − LN2·k)/2²³⁵ − t/2¹²⁸ ∈ [0, 1/2¹²⁸)` — the integer `t`-rounding sandwich. + +The sum is below `2/2¹²⁸`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Real + +noncomputable section + +set_option maxRecDepth 100000 +set_option maxHeartbeats 2000000 + +/-- The reduced argument `rt = X/RAY − k·ln2`. -/ +def reducedArg (x : Nat) : Real := + (int256 x : Real) / (10 ^ 27 : Real) - (int256 (kTree x) : Real) * Real.log 2 + +/-- **Reduced-argument real bound (gap-1).** On the meaningful region the reduced argument `rt` +agrees with `t/2¹²⁸` to within `2/2¹²⁸`. -/ +theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + |reducedArg x - (int256 (tTree x) : Real) / (2 ^ 128 : Real)| < 2 / (2 ^ 128 : Real) := by + obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 + obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 + obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 + have hln2lo := ln2_lower + have hln2hi := ln2_upper + set t : Int := int256 (tTree x) with htdef + set k : Int := int256 (kTree x) with hkdef + set X : Int := int256 x with hXdef + have hK : (0x279d346de4781f921dd7a89933d54d1f72928 : Int) = 55213970774324510299478046898216203619608872 := by norm_num + have hL : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num + rw [hK, hL] at htlo hthi + -- ln2 bounds cleaned to decimal Real + have hLN2decimal : ((LN2c : Nat) : Real) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by + unfold LN2c; norm_num + rw [hLN2decimal] at hln2lo hln2hi + -- Real abbreviations + set LR : Real := Real.log 2 with hLRdef + set XR : Real := (X : Real) with hXRdef + set kR : Real := (k : Real) with hkRdef + set tR : Real := (t : Real) with htRdef + -- numeric Real names + set N235 : Real := (2 ^ 235 : Real) with hN235 + set N128 : Real := (2 ^ 128 : Real) with hN128 + set LN2R : Real := (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) with hLN2R + set K27R : Real := (55213970774324510299478046898216203619608872 : Real) with hK27R + have hp235 : (0 : Real) < N235 := by rw [hN235]; positivity + have hp128 : (0 : Real) < N128 := by rw [hN128]; positivity + have hpRAY : (0 : Real) < (10 ^ 27 : Real) := by positivity + -- 2^235 = 2^128 · 2^107 + have hsplit : N235 = N128 * 2 ^ 107 := by rw [hN235, hN128, ← pow_add] + -- the three pieces + set P1 : Real := XR * (1 / (10 ^ 27 : Real) - K27R / N235) with hP1def + set P2 : Real := kR * (LN2R / N235 - LR) with hP2def + set P3 : Real := (K27R * XR - LN2R * kR) / N235 - tR / N128 with hP3def + -- identity: reducedArg x - t/2^128 = P1 + P2 + P3 + have hident : XR / (10 ^ 27 : Real) - kR * LR - tR / N128 = P1 + P2 + P3 := by + rw [hP1def, hP2def, hP3def]; ring + -- bound P1 : |P1| < 2^96·N/(2^235·10^27) where N = K27·10^27 − 2^235 = 222636907558699806209605632 + -- We bound P1 ∈ (−ε, ε) with ε = 2^96·N/(2^235·10^27) < 2⁻¹³². Use explicit endpoints. + have hXloR : -(79228162514264337593543950336 : Real) < XR := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hxlo; rw [hXRdef] + rw [show ((2:Int)^96 : Int) = 79228162514264337593543950336 from by norm_num] at this + push_cast at this; linarith [this] + have hXhiR : XR < (79228162514264337593543950336 : Real) := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hxhi; rw [hXRdef] + rw [show ((2:Int)^96 : Int) = 79228162514264337593543950336 from by norm_num] at this + push_cast at this; linarith [this] + -- coefficient: 1/10^27 − K27/2^235 < 0, magnitude m := (K27·10^27 − 2^235)/(2^235·10^27) + have hcoeff_eq : (1 / (10 ^ 27 : Real) - K27R / N235) = + -((K27R * (10 ^ 27 : Real) - N235) / (N235 * (10 ^ 27 : Real))) := by + rw [hK27R, hN235]; field_simp; ring + have hcoeff_num : K27R * (10 ^ 27 : Real) - N235 = 222636907558699806209605632 := by + rw [hK27R, hN235]; norm_num + -- |P1| < 2⁻¹³² (a generous bound): |XR| < 2^96, |coeff| = m, and 2^96·m < 2⁻¹³². + have hP1_abs : |P1| < 1 / (4 * N128) := by + rw [hP1def, hcoeff_eq, hcoeff_num, abs_mul] + have hden_pos : (0 : Real) < N235 * (10 ^ 27 : Real) := by positivity + have hco_abs : |(-(222636907558699806209605632 / (N235 * (10 ^ 27 : Real))))| = + 222636907558699806209605632 / (N235 * (10 ^ 27 : Real)) := by + rw [abs_neg, abs_of_pos (by positivity)] + rw [hco_abs] + have hX_abs : |XR| < 79228162514264337593543950336 := abs_lt.mpr ⟨hXloR, hXhiR⟩ + have hco_pos : (0:Real) < 222636907558699806209605632 / (N235 * (10 ^ 27 : Real)) := by positivity + calc |XR| * (222636907558699806209605632 / (N235 * (10 ^ 27 : Real))) + < 79228162514264337593543950336 * (222636907558699806209605632 / (N235 * (10 ^ 27 : Real))) := + (mul_lt_mul_right hco_pos).mpr hX_abs + _ = 79228162514264337593543950336 * 222636907558699806209605632 / + (N235 * (10 ^ 27 : Real)) := by rw [mul_div_assoc] + _ < 1 / (4 * N128) := by + rw [hN235, hN128, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num + -- bound P2 : 0 ≤ LN2R/N235 − LR... actually ln2 ≥ LN2/2^235, so LN2R/N235 − LR ≤ 0, and ≥ −1/N235. + have hP2_lo : LN2R / N235 - LR ≤ 0 := by linarith [hln2lo] + have hP2_hi : -(1 / N235) ≤ LN2R / N235 - LR := by + have : LR ≤ (LN2R + 1) / N235 := hln2hi + rw [add_div] at this; linarith [this] + -- |k| ≤ 63 ⇒ |P2| ≤ 63/N235 < 1/N128 + have hkloR : -(61 : Real) ≤ kR := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] + have hkhiR : kR ≤ (63 : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] + have hP2_abs : |P2| < 1 / (4 * N128) := by + rw [hP2def] + have h1 : |kR| ≤ 63 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by + rw [abs_le] + refine ⟨by linarith [hP2_hi], ?_⟩ + have hpos : (0:Real) ≤ 1 / N235 := by positivity + linarith [hP2_lo, hpos] + have hbound : |kR * (LN2R / N235 - LR)| ≤ 63 * (1 / N235) := by + rw [abs_mul] + exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) + have hlt : 63 * (1 / N235) < 1 / (4 * N128) := by + rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num + linarith [hbound, hlt] + -- bound P3 ∈ [0, 1/N128) from the integer sandwich + have hP3int_lo : (0 : Int) ≤ 55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t := by omega + have hP3int_hi : 55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t < 2 ^ 107 := by omega + -- P3 = (A − 2^107·t)/N235, with the numerator (a Real cast of an Int) in [0, 2^107) + have hnumR_lo : (0 : Real) ≤ K27R * XR - LN2R * kR - 2 ^ 107 * tR := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hP3int_lo + rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] + push_cast at h; linarith [h] + have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 107 * tR < 2 ^ 107 := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hP3int_hi + rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] + push_cast at h; linarith [h] + have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 107 * tR) / N235 := by + rw [hP3def, hsplit]; field_simp; ring + have hP3_lo : 0 ≤ P3 := by rw [hP3eq]; exact div_nonneg hnumR_lo (le_of_lt hp235) + have hP3_hi : P3 < 1 / N128 := by + rw [hP3eq, hsplit, div_lt_div_iff₀ (by positivity) (by positivity)] + nlinarith [hnumR_hi, hp128] + -- assemble + show |reducedArg x - tR / N128| < 2 / N128 + rw [show reducedArg x = XR / (10 ^ 27 : Real) - kR * LR from rfl] + rw [hident, abs_lt] + have hP1 := abs_lt.mp hP1_abs + have hP2 := abs_lt.mp hP2_abs + clear_value N128 N235 + -- 1/(4N) + 1/(4N) = 1/(2N) ≤ 1/N ≤ 2/N + have hquarter : (1 : Real) / (4 * N128) + 1 / (4 * N128) ≤ 1 / N128 := by + have he : (1 : Real) / (4 * N128) + 1 / (4 * N128) = (1 / N128) / 2 := by + field_simp; ring + rw [he]; linarith [div_nonneg (le_of_lt (by positivity : (0:Real) < 1/N128)) (by norm_num : (0:Real) ≤ 2), + half_le_self (le_of_lt (by positivity : (0:Real) < 1/N128))] + have htwo : (1 : Real) / N128 ≤ 2 / N128 := by + have : (2 : Real) / N128 = 1/N128 + 1/N128 := by ring + rw [this]; linarith [div_pos (by norm_num : (0:Real) < 1) hp128] + have hsum_hi : P1 + P2 + P3 < 2 / N128 := by + have h12 : P1 + P2 < 1 / N128 := by linarith [hP1.2, hP2.2, hquarter] + have : (2 : Real) / N128 = 1 / N128 + 1 / N128 := by ring + rw [this]; linarith [h12, hP3_hi] + have hsum_lo : -(2 / N128) < P1 + P2 + P3 := by + have h12 : -(1 / N128) < P1 + P2 := by + have hq2 : -(1 / N128) ≤ -(1 / (4 * N128)) + -(1 / (4 * N128)) := by linarith [hquarter] + linarith [hP1.1, hP2.1, hq2] + have : (2 : Real) / N128 = 1 / N128 + 1 / N128 := by ring + rw [this]; linarith [h12, hP3_lo] + exact ⟨hsum_lo, hsum_hi⟩ + +/-- info: 'ExpYul.reducedArg_close' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms reducedArg_close + +end + +end ExpYul From 8289fe59c5f7f8438f37935ec724383bc0656f1d Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 14:46:47 +0200 Subject: [PATCH 061/149] Add the exp v-truncation cert-polynomial bridge (RuntimeR0Bound, even half) The v-form cert polynomial in t (exact v=t^2/2^128) brackets the runtime even Horner accumulator: 2^1193*evTree x <= evalPoly evNumVPoly t < 2^1193*evTree x + 3*2^1193, composing the gap-2 Horner-truncation bridge with the v-truncation (one v-step of the monotone Horner poly is below 2^553). Foundations: Pev/Pod w-polynomials, the squaring/grid identities, monotonicity of nonneg-coeff polynomials. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean new file mode 100644 index 000000000..4c92a4564 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -0,0 +1,201 @@ +import ExpProof.Floor.R0Bound +import ExpProof.Floor.CapsV +import ExpProof.Floor.Reduce +import ExpProof.Mono.Quot +import Common.Seam.RealExpBridge + +/-! +# The per-point `r0`-vs-`exp` bridge + +This module brackets the Q126 quotient `r0Tree x` against `2¹²⁶·exp(rt)` (`rt = X/RAY − k·ln2` the +reduced argument), the single content left for `RuntimeR0Bound`/`SeamR0Bound`. It chains: + +* the **v-truncation** `evNumV(vTree x)·2⁶⁴⁰ ≤ evalPoly evNumVPoly t < evNumV(vTree x)·2⁶⁴⁰ + 2¹¹⁹³` + (the cert polynomial in `t` uses the exact `v = t²/2¹²⁸`; the gap-2 bridge uses the truncated + `vTree x = ⌊t²/2¹²⁸⌋`; one `v`-step of the monotone Horner polynomial is below `2⁵⁵³`); +* the **gap-2 Horner-truncation bridge** (`evTree_bracket`/`odTree_bracket`, already proven); +* the **`sdiv` floor** `r0·den ≤ 2¹²⁶·num < (r0+1)·den`; +* the **v-form cert** (`CapsV`) `exp(t/2¹²⁸) ≈ ê_v` within a dyadic margin; +* the **reduced-argument bound** (`Reduce`) `|rt − t/2¹²⁸| < 2/2¹²⁸`. + +The net envelope `r0Tree x ∈ (2¹²⁶·exp(rt) − C₋, 2¹²⁶·exp(rt) + C₊)` is what the `MARGIN`-absorbing +`over`/`under`/seam inequalities consume. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Poly + +set_option maxRecDepth 100000 + +/-! ## The even/odd Horner polynomials in `w = t²` and the cert-polynomial bridge -/ + +/-- The even Horner polynomial in `w` (degree 5, monic), at the cleared scale `2¹¹⁹³`. -/ +def Pev : List Int := + [0x4e14a45e8ec305e233e11b4174e214ac * 2 ^ 1193, + 0x93f11e65781741b92fa7fc4f4fffcca2 * 2 ^ 933, + 0x9064d965e1c4863b73604e0ddbec53f9 * 2 ^ 671, + 0x9a036222e11aee18465042f8ea64c8 * 2 ^ 415, + 0xb9aacfad41060587203a79af0ebc * 2 ^ 157, + 1] + +/-- The odd Horner polynomial in `w` (degree 4), at the cleared scale `2¹⁰⁴²`. -/ +def Pod : List Int := + [0x270a522f476182f119f08da0ba710a56 * 2 ^ 1042, + 0xaf5662483c4ce783a9ef5fe025f42e9e * 2 ^ 779, + 0xad4506b00b1246c7e5b4fd33e1201b * 2 ^ 524, + 0xc926ddbf3830ca5561cc01585402d0 * 2 ^ 259, + 0xdc07aff85e5bb5629d0fb64a84bb] + +/-- `evNumVPoly(t) = Pev(t²)`: the cert even polynomial is `Pev` composed with squaring. -/ +theorem evNumVPoly_eq_Pev_sq (t : Int) : + evalPoly ExpCertV.evNumVPoly t = evalPoly Pev (t ^ 2) := by + unfold ExpCertV.evNumVPoly ExpCertV.mulT2 Pev + simp only [evalPoly_polyAdd, evalPoly_polyScale, evalPoly] + ring + +/-- `odNumVPoly(t) = Pod(t²)`. -/ +theorem odNumVPoly_eq_Pod_sq (t : Int) : + evalPoly ExpCertV.odNumVPoly t = evalPoly Pod (t ^ 2) := by + unfold ExpCertV.odNumVPoly ExpCertV.mulT2 Pod + simp only [evalPoly_polyAdd, evalPoly_polyScale, evalPoly] + ring + +/-- `Pev(2¹²⁸·v) = evNumV(v)·2⁶⁴⁰` — the `w`-polynomial at the grid point `w = 2¹²⁸·v` recovers the +integer even-Horner accumulator (scaled). -/ +theorem Pev_grid (v : Nat) : evalPoly Pev (2 ^ 128 * (v : Int)) = (evNumV v : Int) * 2 ^ 640 := by + unfold Pev evNumV + simp only [evalPoly] + push_cast + ring + +/-- `Pod(2¹²⁸·v) = odNumV(v)·2⁵¹²`. -/ +theorem Pod_grid (v : Nat) : evalPoly Pod (2 ^ 128 * (v : Int)) = (odNumV v : Int) * 2 ^ 512 := by + unfold Pod odNumV + simp only [evalPoly] + push_cast + ring + +/-! ## Monotonicity of the `w`-polynomials and the single-`v`-step bound -/ + +/-- A polynomial with nonnegative coefficients evaluates nonnegatively on the nonnegative domain. -/ +theorem evalPoly_nonneg_of_nonneg {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) {a : Int} (ha : 0 ≤ a) : + 0 ≤ evalPoly p a := by + induction p with + | nil => simp [evalPoly] + | cons c cs ih => + have hc : 0 ≤ c := hp c List.mem_cons_self + have hcs : ∀ d ∈ cs, 0 ≤ d := fun d hd => hp d (List.mem_cons_of_mem c hd) + simp only [evalPoly] + exact Int.add_nonneg hc (Int.mul_nonneg ha (ih hcs)) + +/-- A polynomial with nonnegative coefficients is monotone on the nonnegative domain. -/ +theorem evalPoly_mono_of_nonneg {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) {a b : Int} + (ha : 0 ≤ a) (hab : a ≤ b) : evalPoly p a ≤ evalPoly p b := by + induction p with + | nil => simp [evalPoly] + | cons c cs ih => + have hcs : ∀ d ∈ cs, 0 ≤ d := fun d hd => hp d (List.mem_cons_of_mem c hd) + have hih := ih hcs + have hb : 0 ≤ b := le_trans ha hab + have hcsnn : 0 ≤ evalPoly cs a := evalPoly_nonneg_of_nonneg hcs ha + simp only [evalPoly] + have h1 : a * evalPoly cs a ≤ b * evalPoly cs b := by + calc a * evalPoly cs a ≤ b * evalPoly cs a := + mul_le_mul_of_nonneg_right hab hcsnn + _ ≤ b * evalPoly cs b := mul_le_mul_of_nonneg_left hih hb + linarith [h1] + +theorem Pev_coeffs_nonneg : ∀ c ∈ Pev, (0 : Int) ≤ c := by + unfold Pev; intro c hc; fin_cases hc <;> positivity + +theorem Pod_coeffs_nonneg : ∀ c ∈ Pod, (0 : Int) ≤ c := by + unfold Pod; intro c hc; fin_cases hc <;> positivity + +/-- `Pev` is monotone on the nonnegative domain. -/ +theorem Pev_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : + evalPoly Pev a ≤ evalPoly Pev b := evalPoly_mono_of_nonneg Pev_coeffs_nonneg ha hab + +/-- `Pod` is monotone on the nonnegative domain. -/ +theorem Pod_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : + evalPoly Pod a ≤ evalPoly Pod b := evalPoly_mono_of_nonneg Pod_coeffs_nonneg ha hab + +/-- One `v`-step of the even Horner polynomial is below `2⁵⁵³` for `v < 2¹²⁶`. -/ +theorem evNumV_step {v : Nat} (hv : v < 2 ^ 126) : + (evNumV (v + 1) : Int) - (evNumV v : Int) < 2 ^ 553 := by + unfold evNumV + push_cast + have hvle : (v : Int) < 2 ^ 126 := by exact_mod_cast hv + have hvnn : (0 : Int) ≤ (v : Int) := by positivity + nlinarith [hvle, hvnn, mul_nonneg hvnn hvnn, Int.mul_nonneg hvnn (Int.mul_nonneg hvnn hvnn), + Int.mul_nonneg (Int.mul_nonneg hvnn hvnn) (Int.mul_nonneg hvnn hvnn)] + +/-- One `v`-step of the odd Horner polynomial is below `2⁵³⁰` for `v < 2¹²⁶`. -/ +theorem odNumV_step {v : Nat} (hv : v < 2 ^ 126) : + (odNumV (v + 1) : Int) - (odNumV v : Int) < 2 ^ 530 := by + unfold odNumV + push_cast + have hvle : (v : Int) < 2 ^ 126 := by exact_mod_cast hv + have hvnn : (0 : Int) ≤ (v : Int) := by positivity + nlinarith [hvle, hvnn, mul_nonneg hvnn hvnn, Int.mul_nonneg hvnn (Int.mul_nonneg hvnn hvnn)] + +/-! ## The cert polynomial brackets the runtime accumulator (gap-2 ∘ v-truncation) -/ + +/-- The squared reduced argument splits as `t² = 2¹²⁸·vTree x + r` with `0 ≤ r < 2¹²⁸`. -/ +theorem tsq_split {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + 2 ^ 128 * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ + (int256 (tTree x)) ^ 2 < 2 ^ 128 * (vTree x : Int) + 2 ^ 128 := by + obtain ⟨hveq, _⟩ := vTree_eq hx hC hC0 + have hsqnn : (0 : Int) ≤ (int256 (tTree x)) ^ 2 := sq_nonneg _ + have hdm := Int.ediv_add_emod ((int256 (tTree x)) ^ 2) (2 ^ 128) + have hmod_lt := Int.emod_lt_of_pos ((int256 (tTree x)) ^ 2) (by norm_num : (0:Int) < 2 ^ 128) + have hmod_nn := Int.emod_nonneg ((int256 (tTree x)) ^ 2) (by norm_num : (2:Int) ^ 128 ≠ 0) + rw [hveq] + constructor + · nlinarith [hdm, hmod_nn] + · nlinarith [hdm, hmod_lt] + +/-- **The even cert polynomial brackets the runtime even accumulator** (gap-2 ∘ v-truncation): +`2¹¹⁹³·evTree x ≤ evalPoly evNumVPoly t < 2¹¹⁹³·evTree x + 3·2¹¹⁹³`. -/ +theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + 2 ^ 1193 * (evTree x : Int) ≤ evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) ∧ + evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) < 2 ^ 1193 * (evTree x : Int) + 3 * 2 ^ 1193 := by + obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 + obtain ⟨hg2lo, hg2hi⟩ := evTree_bracket hvlt + obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 + set t := int256 (tTree x) with htdef + have hsqnn : (0 : Int) ≤ t ^ 2 := sq_nonneg _ + have hgridnn : (0 : Int) ≤ 2 ^ 128 * (vTree x : Int) := by positivity + -- v-truncation: Pev(2^128·vTree) ≤ Pev(t²) ≤ Pev(2^128·vTree + 2^128) (monotone) + have hmono_lo : evalPoly Pev (2 ^ 128 * (vTree x : Int)) ≤ evalPoly Pev (t ^ 2) := + Pev_mono hgridnn hsqlo + have hmono_hi : evalPoly Pev (t ^ 2) ≤ evalPoly Pev (2 ^ 128 * ((vTree x + 1 : Nat) : Int)) := by + apply Pev_mono hsqnn + push_cast; linarith [hsqhi] + rw [evNumVPoly_eq_Pev_sq] + rw [Pev_grid] at hmono_lo + rw [Pev_grid (vTree x + 1)] at hmono_hi + -- gap-2: evNumV(vTree)·2^640 ≥ 2^553·evTree·2^640 = 2^1193·evTree + have hg2lo' : 2 ^ 1193 * (evTree x : Int) ≤ (evNumV (vTree x) : Int) * 2 ^ 640 := by + have h : (2 ^ 553 * evTree x : Nat) ≤ evNumV (vTree x) := hg2lo + have : (2 ^ 553 * evTree x : Int) ≤ (evNumV (vTree x) : Int) := by exact_mod_cast h + nlinarith [this] + have hg2hi' : (evNumV (vTree x) : Int) * 2 ^ 640 < 2 ^ 1193 * (evTree x : Int) + 2 * 2 ^ 1193 := by + have h : evNumV (vTree x) < 2 ^ 553 * evTree x + 2 * 2 ^ 553 := hg2hi + have : (evNumV (vTree x) : Int) < (2 ^ 553 * evTree x + 2 * 2 ^ 553 : Nat) := by exact_mod_cast h + push_cast at this; nlinarith [this] + -- step bound: evNumV(vTree+1)·2^640 < evNumV(vTree)·2^640 + 2^1193 + have hstep := evNumV_step hvlt + have hstep' : (evNumV (vTree x + 1) : Int) * 2 ^ 640 < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1193 := by + nlinarith [hstep] + refine ⟨le_trans hg2lo' hmono_lo, ?_⟩ + calc evalPoly Pev (t ^ 2) ≤ (evNumV (vTree x + 1) : Int) * 2 ^ 640 := hmono_hi + _ < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1193 := hstep' + _ < 2 ^ 1193 * (evTree x : Int) + 2 * 2 ^ 1193 + 2 ^ 1193 := by linarith [hg2hi'] + _ = 2 ^ 1193 * (evTree x : Int) + 3 * 2 ^ 1193 := by ring + +end ExpYul From 5a28eb62b9e20a684090985b7714b76940fc83dd Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 15:01:29 +0200 Subject: [PATCH 062/149] Add the exp odd/tod/num/den cert brackets and the sdiv floor sandwich Extends the v-truncation bridge to the odd accumulator, the t*Od term (nonnegative half), and the numerator/denominator; adds the Q126 quotient floor characterization r0*den <= 2^126*num < (r0+1)*den. All axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 4c92a4564..09fa29848 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -2,6 +2,7 @@ import ExpProof.Floor.R0Bound import ExpProof.Floor.CapsV import ExpProof.Floor.Reduce import ExpProof.Mono.Quot +import ExpProof.Mono.Cross import Common.Seam.RealExpBridge /-! @@ -198,4 +199,226 @@ theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) _ < 2 ^ 1193 * (evTree x : Int) + 2 * 2 ^ 1193 + 2 ^ 1193 := by linarith [hg2hi'] _ = 2 ^ 1193 * (evTree x : Int) + 3 * 2 ^ 1193 := by ring +/-- **The odd cert polynomial brackets the runtime odd accumulator** (gap-2 ∘ v-truncation): +`2¹⁰⁴²·odTree x ≤ evalPoly odNumVPoly t < 2¹⁰⁴²·odTree x + 3·2¹⁰⁴²`. -/ +theorem odNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + 2 ^ 1042 * (odTree x : Int) ≤ evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) ∧ + evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) < 2 ^ 1042 * (odTree x : Int) + 3 * 2 ^ 1042 := by + obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 + obtain ⟨hg2lo, hg2hi⟩ := odTree_bracket hvlt + obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 + set t := int256 (tTree x) with htdef + have hsqnn : (0 : Int) ≤ t ^ 2 := sq_nonneg _ + have hgridnn : (0 : Int) ≤ 2 ^ 128 * (vTree x : Int) := by positivity + have hmono_lo : evalPoly Pod (2 ^ 128 * (vTree x : Int)) ≤ evalPoly Pod (t ^ 2) := + Pod_mono hgridnn hsqlo + have hmono_hi : evalPoly Pod (t ^ 2) ≤ evalPoly Pod (2 ^ 128 * ((vTree x + 1 : Nat) : Int)) := by + apply Pod_mono hsqnn + push_cast; linarith [hsqhi] + rw [odNumVPoly_eq_Pod_sq] + rw [Pod_grid] at hmono_lo + rw [Pod_grid (vTree x + 1)] at hmono_hi + have hg2lo' : 2 ^ 1042 * (odTree x : Int) ≤ (odNumV (vTree x) : Int) * 2 ^ 512 := by + have h : (2 ^ 530 * odTree x : Nat) ≤ odNumV (vTree x) := hg2lo + have : (2 ^ 530 * odTree x : Int) ≤ (odNumV (vTree x) : Int) := by exact_mod_cast h + nlinarith [this] + have hg2hi' : (odNumV (vTree x) : Int) * 2 ^ 512 < 2 ^ 1042 * (odTree x : Int) + 2 * 2 ^ 1042 := by + have h : odNumV (vTree x) < 2 ^ 530 * odTree x + 2 * 2 ^ 530 := hg2hi + have : (odNumV (vTree x) : Int) < (2 ^ 530 * odTree x + 2 * 2 ^ 530 : Nat) := by exact_mod_cast h + push_cast at this; nlinarith [this] + have hstep := odNumV_step hvlt + have hstep' : (odNumV (vTree x + 1) : Int) * 2 ^ 512 < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1042 := by + nlinarith [hstep] + refine ⟨le_trans hg2lo' hmono_lo, ?_⟩ + calc evalPoly Pod (t ^ 2) ≤ (odNumV (vTree x + 1) : Int) * 2 ^ 512 := hmono_hi + _ < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1042 := hstep' + _ < 2 ^ 1042 * (odTree x : Int) + 2 * 2 ^ 1042 + 2 ^ 1042 := by linarith [hg2hi'] + _ = 2 ^ 1042 * (odTree x : Int) + 3 * 2 ^ 1042 := by ring + +/-! ## The `t·Od` term and the numerator/denominator brackets (nonnegative half `t ≥ 0`) -/ + +/-- `evalPoly todNumV t = 2²³ · t · evalPoly odNumVPoly t`. -/ +theorem evalTodNumV (t : Int) : + evalPoly ExpCertV.todNumV t = 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := by + unfold ExpCertV.todNumV + rw [evalPoly_polyScale] + simp only [evalPoly] + ring + +/-- `evalPoly numExpV t = evalPoly evNumVPoly t + evalPoly todNumV t`. -/ +theorem evalNumExpV (t : Int) : + evalPoly ExpCertV.numExpV t = evalPoly ExpCertV.evNumVPoly t + evalPoly ExpCertV.todNumV t := by + unfold ExpCertV.numExpV; rw [evalPoly_polyAdd] + +/-- `evalPoly denExpV t = evalPoly evNumVPoly t − evalPoly todNumV t`. -/ +theorem evalDenExpV (t : Int) : + evalPoly ExpCertV.denExpV t = evalPoly ExpCertV.evNumVPoly t - evalPoly ExpCertV.todNumV t := by + unfold ExpCertV.denExpV; rw [evalPoly_polySub] + +/-- **The `t·Od` cert term brackets the runtime `tod`** (nonnegative half): for `0 ≤ t`, +`2¹¹⁹³·tod ≤ evalPoly todNumV t < 2¹¹⁹³·tod + 2⁵·2¹¹⁹³`. -/ +theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 2 ^ 1193 * (int256 (todTree x)) ≤ evalPoly ExpCertV.todNumV (int256 (tTree x)) ∧ + evalPoly ExpCertV.todNumV (int256 (tTree x)) < 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 5 * 2 ^ 1193 := by + obtain ⟨_, _, htodlo, htodhi⟩ := todTree_bound hx hC hC0 + obtain ⟨hodlo, hodhi⟩ := odNumVPoly_bracket hx hC hC0 + set t := int256 (tTree x) with htdef + rw [evalTodNumV] + -- odTree ≥ 0 + have hodnn : (0 : Int) ≤ (odTree x : Int) := by positivity + -- 2^128·tod ≤ t·odTree < 2^128·tod + 2^128 + -- multiply odd bracket by t·2^23 (t ≥ 0): + have hmul_lo : t * (2 ^ 1042 * (odTree x : Int)) ≤ t * evalPoly ExpCertV.odNumVPoly t := + mul_le_mul_of_nonneg_left hodlo htnn + have hmul_hi : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int) + 3 * 2 ^ 1042) := + mul_le_mul_of_nonneg_left (le_of_lt hodhi) htnn + -- tod·2^128 ≤ t·odTree and t·odTree < tod·2^128 + 2^128 + have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo + have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi + constructor + · -- 2^1193·tod ≤ 2^23·(t·odpoly). 2^1193·tod = 2^23·(2^1042·(2^128·tod)) ... use 2^1193=2^23·2^1042·2^128 + have key : 2 ^ 1193 * (int256 (todTree x)) ≤ 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int))) := by + have e : (2 : Int) ^ 23 * (2 ^ 1042 * ((2:Int) ^ 128 * (int256 (todTree x)))) = + 2 ^ 1193 * (int256 (todTree x)) := by ring + rw [← e] + have := mul_le_mul_of_nonneg_left htod_lo (by positivity : (0:Int) ≤ 2 ^ 23 * 2 ^ 1042) + nlinarith [this] + calc 2 ^ 1193 * (int256 (todTree x)) ≤ 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int))) := key + _ ≤ 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := + mul_le_mul_of_nonneg_left hmul_lo (by positivity) + · -- 2^23·(t·odpoly) < 2^1193·tod + 2^5·2^1193 + -- t·odpoly ≤ t·(2^1042·odTree + 3·2^1042) = 2^1042·(t·odTree) + 3·2^1042·t + -- t·odTree < 2^128·tod + 2^128. t < 2^128 (|t| < H128 < 2^128). + obtain ⟨htlo', hthi'⟩ := tTree_bound hx hC hC0 + have htlt : t < 2 ^ 128 := by + have : t < 2 ^ 127 := by rw [show ((2:Int)^127) = 170141183460469231731687303715884105728 from by norm_num]; exact hthi' + have : (2:Int)^127 < 2 ^ 128 := by norm_num + omega + have key : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) < + 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 5 * 2 ^ 1193 := by + have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ 2 ^ 1042 * (t * (odTree x : Int)) + 3 * 2 ^ 1042 * t := by + nlinarith [hmul_hi] + have h2 : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htod_hi + nlinarith [h1, h2, htlt, htnn, mul_nonneg htnn hodnn] + exact key + +/-! ## The numerator/denominator cert brackets and the `r0`-vs-`ê_v` bracket -/ + +/-- The numerator cert polynomial brackets `2¹¹⁹³·num_rt` (`num_rt = ev + tod`): within `35·2¹¹⁹³`. -/ +theorem numExpV_bracket {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 2 ^ 1193 * ((evTree x : Int) + int256 (todTree x)) ≤ evalPoly ExpCertV.numExpV (int256 (tTree x)) ∧ + evalPoly ExpCertV.numExpV (int256 (tTree x)) < + 2 ^ 1193 * ((evTree x : Int) + int256 (todTree x)) + 35 * 2 ^ 1193 := by + obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 + obtain ⟨htodlo, htodhi⟩ := todNumV_bracket hx hC hC0 htnn + rw [evalNumExpV] + constructor + · nlinarith [hevlo, htodlo] + · nlinarith [hevhi, htodhi] + +/-- The denominator cert polynomial brackets `2¹¹⁹³·den_rt` (`den_rt = ev − tod`): within `32·2¹¹⁹³`. -/ +theorem denExpV_bracket {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) - 32 * 2 ^ 1193 ≤ + evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ + evalPoly ExpCertV.denExpV (int256 (tTree x)) < + 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) + 3 * 2 ^ 1193 := by + obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 + obtain ⟨htodlo, htodhi⟩ := todNumV_bracket hx hC hC0 htnn + rw [evalDenExpV] + constructor + · nlinarith [hevlo, htodhi] + · nlinarith [hevhi, htodlo] + +/-! ## The `sdiv` floor sandwich -/ + +/-- The Q126 quotient is the integer floor: `r0·den_rt ≤ 2¹²⁶·num_rt < (r0+1)·den_rt` with +`num_rt = ev + tod`, `den_rt = ev − tod`. -/ +theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + int256 (r0Tree x) * ((evTree x : Int) - int256 (todTree x)) ≤ + 2 ^ 126 * ((evTree x : Int) + int256 (todTree x)) ∧ + 2 ^ 126 * ((evTree x : Int) + int256 (todTree x)) < + (int256 (r0Tree x) + 1) * ((evTree x : Int) - int256 (todTree x)) := by + obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos hx hC hC0 + obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 + set num := evmAdd (evTree x) (todTree x) with hnumdef + set den := evmSub (evTree x) (todTree x) with hdendef + have hnumw : num < 2 ^ 256 := evmAdd_lt _ _ + have hdenw : den < 2 ^ 256 := evmSub_lt _ _ + -- num, den are below 2^128 (signed = Nat value) + have hnumi : int256 num = (evTree x : Int) + int256 (todTree x) := hadd + have hdeni : int256 den = (evTree x : Int) - int256 (todTree x) := hsub + -- num < 2^128, den < 2^128 + obtain ⟨hnumeq, hnum255⟩ := int256_eq_of_nonneg hnumw (by rw [hnumi]; omega) + obtain ⟨hdeneq, hden255⟩ := int256_eq_of_nonneg hdenw (by rw [hdeni]; omega) + -- the shl: int256 (shl 126 num) = 2^126·int256 num + have hnumlt128 : int256 num < 2 ^ 128 := by + -- num = ev + tod < 2^127 + 2^125 < 2^128 + obtain ⟨_, hevhi⟩ := evTree_facts (vTree_eq hx hC hC0).2 + obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + rw [hnumi] + have : (evTree x : Int) < 2 ^ 127 := by exact_mod_cast hevhi + have ht125 : int256 (todTree x) < 2 ^ 125 := by + rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num]; exact htod_hi + nlinarith [this, ht125] + have hshl : int256 (evmShl 0x7e num) = 2 ^ 0x7e * int256 num := + shl126_transport hnumw (by rw [hnumi]; omega) hnumlt128 + -- r0 = sdiv (shl 126 num) den, with both operands positive + have hr0eq : r0Tree x = evmSdiv (evmShl 0x7e num) den := rfl + have hshlw : evmShl 0x7e num < 2 ^ 256 := evmShl_lt _ _ + have hshlpos : 0 ≤ int256 (evmShl 0x7e num) := by rw [hshl, hnumi]; positivity + have hdenpos' : 0 < int256 den := by rw [hdeni]; omega + have hdiv := evmSdiv_pos_pos hshlw hdenw hshlpos hdenpos' + rw [← hr0eq] at hdiv + -- toNat values + have hshl_toNat : (int256 (evmShl 0x7e num)).toNat = (evmShl 0x7e num) := by + have h := int256_eq_of_nonneg hshlw hshlpos + rw [h.1, Int.toNat_natCast] + have hden_toNat : (int256 den).toNat = den := by rw [hdeneq, Int.toNat_natCast] + rw [hshl_toNat, hden_toNat] at hdiv + -- the Nat floor: r0 = (shl 126 num) / den + have hnumnat128 : num < 2 ^ 128 := by + have hh : ((num : Nat) : Int) < 2 ^ 128 := by rw [hnumeq] at hnumlt128; exact hnumlt128 + exact_mod_cast hh + have hshlval : evmShl 0x7e num = num * 2 ^ 0x7e := by + refine evmShl_eq (by norm_num) ?_ + calc num * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := (Nat.mul_lt_mul_right (Nat.two_pow_pos _)).mpr hnumnat128 + _ = 2 ^ 254 := by rw [← Nat.pow_add] + _ < 2 ^ 256 := by norm_num + -- Nat floor sandwich on the opaque dividend M := num·2^126 + have hdennat : 0 < den := by + have hh : (0:Int) < (den:Int) := by rw [hdeneq] at hdenpos'; exact hdenpos' + exact_mod_cast hh + rw [hshlval] at hdiv + set M := num * 2 ^ 0x7e with hMdef + set q := M / den with hqdef + have hfloor_lo : q * den ≤ M := Nat.div_mul_le_self _ _ + have hfloor_hi : M < (q + 1) * den := by + have hdm : den * q + M % den = M := Nat.div_add_mod M den + have hmod : M % den < den := Nat.mod_lt M hdennat + calc M = den * q + M % den := hdm.symm + _ < den * q + den := Nat.add_lt_add_left hmod _ + _ = (q + 1) * den := by ring + -- transport to Int with the canonical values + have hr0nat : int256 (r0Tree x) = (q : Int) := hdiv + -- canonical: (num:Int) = ev + tod, (den:Int) = ev - tod + have hgoalnum : (evTree x : Int) + int256 (todTree x) = (num : Int) := by rw [← hnumi, hnumeq] + have hgoalden : (evTree x : Int) - int256 (todTree x) = (den : Int) := by rw [← hdeni, hdeneq] + rw [hr0nat, hgoalnum, hgoalden] + have heM : (M : Int) = 2 ^ 126 * (num : Int) := by rw [hMdef]; push_cast; ring + constructor + · have h : (q * den : Nat) ≤ M := hfloor_lo + have hInt : (q : Int) * (den : Int) ≤ (M : Int) := by exact_mod_cast h + rw [heM] at hInt; linarith [hInt] + · have h : M < ((q + 1) * den : Nat) := hfloor_hi + have hInt : (M : Int) < ((q : Int) + 1) * (den : Int) := by exact_mod_cast h + rw [heM] at hInt; linarith [hInt] + end ExpYul From 879cf4fa241b04a33a358ad3227856bab712059c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 15:10:12 +0200 Subject: [PATCH 063/149] Tighten exp v-form cert margins to 2^-130 and gap-1 to 9/(8*2^128) The runtime over/under budget (MARGIN/WAD = 0.79) requires the cert rational accuracy and the reduced-argument error to stay well under one output unit; retune both to within budget: cert margins 2^-130 (the certificate envelope leaves slack inside the budget), gap-1 < 9/(8*2^128). Cert cover regenerated (deterministic). Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/CapsV.lean | 24 ++++---- .../ExpProof/ExpProof/Floor/CertDefsV.lean | 14 +++-- .../exp/ExpProof/ExpProof/Floor/Reduce.lean | 57 ++++++++++--------- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean index f5647f5ce..acb488999 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean @@ -17,9 +17,9 @@ nonnegativity into the two bare-argument Taylor caps the floor layer folds with implementation's exact **v-form** rational `ê_v(t) = NUM(t)/DEN(t)` (built from the even/odd Horner polynomials in `v = t²`) nudged by the dyadic margin, with `Qexp = 2^128`: -* `cutExpTaylorLeV_holds` — `CutExpTaylorLe t Qexp (yUB t) (wUB t)` (never-over `exp(t) ≤ ê_v·(1+2⁻¹²⁰)`); +* `cutExpTaylorLeV_holds` — `CutExpTaylorLe t Qexp (yUB t) (wUB t)` (never-over `exp(t) ≤ ê_v·(1+2⁻¹³⁰)`); * `cutRatioLeExpTaylorV_holds` — `CutRatioLeExpTaylor (yLB t) (wLB t) t Qexp` - (not-two-below `ê_v·(1−2⁻¹²⁶) ≤ exp(t)`). + (not-two-below `ê_v·(1−2⁻¹³⁰) ≤ exp(t)`). These differ from the t-form caps only in the rational target (`ê_v` vs `ê_t`, equal as reals but distinct integer polynomials): the runtime truncation bridge lands on `ê_v`, so the floor layer @@ -69,16 +69,16 @@ theorem evalExpN27 (t : Int) : evalPoly expN27 t = expNumI 27 t (Qexp : Int) := rw [evalPoly_expPolyNum] congr 1 <;> simp [evalPoly] -theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 120 + 1) * evalPoly numExpV t := by +theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 130 + 1) * evalPoly numExpV t := by unfold yUB; rw [evalPoly_polyScale] -theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 120 * evalPoly denExpV t := by +theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 130 * evalPoly denExpV t := by unfold wUB; rw [evalPoly_polyScale] -theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 126 - 1) * evalPoly numExpV t := by +theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 130 - 1) * evalPoly numExpV t := by unfold yLB; rw [evalPoly_polyScale] -theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 126 * evalPoly denExpV t := by +theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 130 * evalPoly denExpV t := by unfold wLB; rw [evalPoly_polyScale] theorem evalTailUp (t : Int) : @@ -125,15 +125,15 @@ theorem Qexp_eq : (Qexp : Int) = 2 ^ 128 := by unfold Qexp; norm_num theorem Qexp_pos : 0 < Qexp := by unfold Qexp; norm_num -/-- **Never-over cap** at the v-form rational `yUB/wUB = ê_v·(1 + 2⁻¹²⁰)`: for every reduced argument +/-- **Never-over cap** at the v-form rational `yUB/wUB = ê_v·(1 + 2⁻¹³⁰)`: for every reduced argument `t ∈ [0, H128]`, `exp(t/Qexp) ≤ yUB(t)/wUB(t)`. -/ theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : capUB t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := by have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 have hden0 : 0 ≤ evalPoly denExpV t := by omega - have hc120 : (0 : Int) ≤ 2 ^ 120 + 1 := by norm_num - have hp120 : (0 : Int) ≤ 2 ^ 120 := by norm_num + have hc120 : (0 : Int) ≤ 2 ^ 130 + 1 := by norm_num + have hp120 : (0 : Int) ≤ 2 ^ 130 := by norm_num have hyub : 0 ≤ evalPoly yUB t := by rw [evalYUB]; exact Int.mul_nonneg hc120 hnum have hwub : 0 ≤ evalPoly wUB t := by @@ -159,15 +159,15 @@ theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : _ ≤ 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := key _ = evalPoly yUB t * (304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28) := by ring -/-- **Not-two-below cap** at the v-form rational `yLB/wLB = ê_v·(1 − 2⁻¹²⁶)`: for every reduced +/-- **Not-two-below cap** at the v-form rational `yLB/wLB = ê_v·(1 − 2⁻¹³⁰)`: for every reduced argument `t ∈ [0, H128]`, `yLB(t)/wLB(t) ≤ exp(t/Qexp)`. -/ theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : capLB t.toNat Qexp (evalPoly yLB t).toNat (evalPoly wLB t).toNat := by have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 have hden0 : 0 ≤ evalPoly denExpV t := by omega - have hc126 : (0 : Int) ≤ 2 ^ 126 - 1 := by norm_num - have hp126 : (0 : Int) ≤ 2 ^ 126 := by norm_num + have hc126 : (0 : Int) ≤ 2 ^ 130 - 1 := by norm_num + have hp126 : (0 : Int) ≤ 2 ^ 130 := by norm_num have hylb : 0 ≤ evalPoly yLB t := by rw [evalYLB]; exact Int.mul_nonneg hc126 hnum have hwlb : 0 ≤ evalPoly wLB t := by diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean index 6f51d140d..afef04a19 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean @@ -83,12 +83,14 @@ def expN27 : List Int := expPolyNum [0, 1] [(Qexp : Int)] 27 /-! ## Margin-nudged rational targets -`yUB/wUB = ê_v·(1 + 2⁻¹²⁰)` and `yLB/wLB = ê_v·(1 − 2⁻¹²⁶)`. -/ - -def yUB : List Int := polyScale (2 ^ 120 + 1) numExpV -def wUB : List Int := polyScale (2 ^ 120) denExpV -def yLB : List Int := polyScale (2 ^ 126 - 1) numExpV -def wLB : List Int := polyScale (2 ^ 126) denExpV +`yUB/wUB = ê_v·(1 + 2⁻¹³⁰)` and `yLB/wLB = ê_v·(1 − 2⁻¹³⁰)`. The tight `2⁻¹³⁰` margins keep the +`2¹²⁶·(ê_v − exp)` contribution to the runtime over/under budget below `2¹²⁶·exp·2⁻¹³⁰ ≈ 0.09` ulp, +inside the `MARGIN`; the verified envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.057` ulp leaves slack. -/ + +def yUB : List Int := polyScale (2 ^ 130 + 1) numExpV +def wUB : List Int := polyScale (2 ^ 130) denExpV +def yLB : List Int := polyScale (2 ^ 130 - 1) numExpV +def wLB : List Int := polyScale (2 ^ 130) denExpV /-! ## The cut certificate polynomials -/ diff --git a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean index 76ec4dd5d..3866861df 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean @@ -40,10 +40,11 @@ def reducedArg (x : Nat) : Real := (int256 x : Real) / (10 ^ 27 : Real) - (int256 (kTree x) : Real) * Real.log 2 /-- **Reduced-argument real bound (gap-1).** On the meaningful region the reduced argument `rt` -agrees with `t/2¹²⁸` to within `2/2¹²⁸`. -/ +agrees with `t/2¹²⁸` to within `9/(8·2¹²⁸)` (the integer `t`-rounding sandwich `[0, 1/2¹²⁸)` +dominates; the rational and `ln2`-grid errors are below `2⁻¹³²`). -/ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - |reducedArg x - (int256 (tTree x) : Real) / (2 ^ 128 : Real)| < 2 / (2 ^ 128 : Real) := by + |reducedArg x - (int256 (tTree x) : Real) / (2 ^ 128 : Real)| < 9 / (8 * (2 ^ 128 : Real)) := by obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 @@ -100,7 +101,7 @@ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) have hcoeff_num : K27R * (10 ^ 27 : Real) - N235 = 222636907558699806209605632 := by rw [hK27R, hN235]; norm_num -- |P1| < 2⁻¹³² (a generous bound): |XR| < 2^96, |coeff| = m, and 2^96·m < 2⁻¹³². - have hP1_abs : |P1| < 1 / (4 * N128) := by + have hP1_abs : |P1| < 1 / (64 * N128) := by rw [hP1def, hcoeff_eq, hcoeff_num, abs_mul] have hden_pos : (0 : Real) < N235 * (10 ^ 27 : Real) := by positivity have hco_abs : |(-(222636907558699806209605632 / (N235 * (10 ^ 27 : Real))))| = @@ -114,7 +115,7 @@ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) (mul_lt_mul_right hco_pos).mpr hX_abs _ = 79228162514264337593543950336 * 222636907558699806209605632 / (N235 * (10 ^ 27 : Real)) := by rw [mul_div_assoc] - _ < 1 / (4 * N128) := by + _ < 1 / (64 * N128) := by rw [hN235, hN128, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num -- bound P2 : 0 ≤ LN2R/N235 − LR... actually ln2 ≥ LN2/2^235, so LN2R/N235 − LR ≤ 0, and ≥ −1/N235. have hP2_lo : LN2R / N235 - LR ≤ 0 := by linarith [hln2lo] @@ -126,7 +127,7 @@ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] have hkhiR : kR ≤ (63 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] - have hP2_abs : |P2| < 1 / (4 * N128) := by + have hP2_abs : |P2| < 1 / (64 * N128) := by rw [hP2def] have h1 : |kR| ≤ 63 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by @@ -137,7 +138,7 @@ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) have hbound : |kR * (LN2R / N235 - LR)| ≤ 63 * (1 / N235) := by rw [abs_mul] exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) - have hlt : 63 * (1 / N235) < 1 / (4 * N128) := by + have hlt : 63 * (1 / N235) < 1 / (64 * N128) := by rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num linarith [hbound, hlt] -- bound P3 ∈ [0, 1/N128) from the integer sandwich @@ -161,31 +162,35 @@ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) rw [hP3eq, hsplit, div_lt_div_iff₀ (by positivity) (by positivity)] nlinarith [hnumR_hi, hp128] -- assemble - show |reducedArg x - tR / N128| < 2 / N128 + show |reducedArg x - tR / N128| < 9 / (8 * N128) rw [show reducedArg x = XR / (10 ^ 27 : Real) - kR * LR from rfl] rw [hident, abs_lt] have hP1 := abs_lt.mp hP1_abs have hP2 := abs_lt.mp hP2_abs clear_value N128 N235 - -- 1/(4N) + 1/(4N) = 1/(2N) ≤ 1/N ≤ 2/N - have hquarter : (1 : Real) / (4 * N128) + 1 / (4 * N128) ≤ 1 / N128 := by - have he : (1 : Real) / (4 * N128) + 1 / (4 * N128) = (1 / N128) / 2 := by - field_simp; ring - rw [he]; linarith [div_nonneg (le_of_lt (by positivity : (0:Real) < 1/N128)) (by norm_num : (0:Real) ≤ 2), - half_le_self (le_of_lt (by positivity : (0:Real) < 1/N128))] - have htwo : (1 : Real) / N128 ≤ 2 / N128 := by - have : (2 : Real) / N128 = 1/N128 + 1/N128 := by ring - rw [this]; linarith [div_pos (by norm_num : (0:Real) < 1) hp128] - have hsum_hi : P1 + P2 + P3 < 2 / N128 := by - have h12 : P1 + P2 < 1 / N128 := by linarith [hP1.2, hP2.2, hquarter] - have : (2 : Real) / N128 = 1 / N128 + 1 / N128 := by ring - rw [this]; linarith [h12, hP3_hi] - have hsum_lo : -(2 / N128) < P1 + P2 + P3 := by - have h12 : -(1 / N128) < P1 + P2 := by - have hq2 : -(1 / N128) ≤ -(1 / (4 * N128)) + -(1 / (4 * N128)) := by linarith [hquarter] - linarith [hP1.1, hP2.1, hq2] - have : (2 : Real) / N128 = 1 / N128 + 1 / N128 := by ring - rw [this]; linarith [h12, hP3_lo] + -- P1+P2 < 2/(64N) = 1/(32N); P3 ∈ [0, 1/N). 9/(8N) = 36/(32N) covers 33/(32N). + have hp128' : (0 : Real) < 1 / N128 := by positivity + -- 1/(64N)+1/(64N) ≤ 1/(32N) ≤ 1/(8N) + have he12 : (1 : Real) / (64 * N128) + 1 / (64 * N128) = 1 / (32 * N128) := by + field_simp; ring + have h32_8 : (1 : Real) / (32 * N128) ≤ 1 / (8 * N128) := by + rw [div_le_div_iff₀ (by positivity) (by positivity)]; linarith [hp128] + have h1_8N : (1 : Real) / N128 + 1 / (8 * N128) = 9 / (8 * N128) := by + field_simp; ring + have hsum_hi : P1 + P2 + P3 < 9 / (8 * N128) := by + have h12 : P1 + P2 < 1 / (8 * N128) := by + have : P1 + P2 < 1 / (32 * N128) := by rw [← he12]; linarith [hP1.2, hP2.2] + linarith [this, h32_8] + rw [← h1_8N]; linarith [h12, hP3_hi] + have hsum_lo : -(9 / (8 * N128)) < P1 + P2 + P3 := by + have h12 : -(1 / (8 * N128)) < P1 + P2 := by + have hlo : -(1 / (32 * N128)) < P1 + P2 := by + rw [show -(1 / (32 * N128)) = -(1 / (64 * N128)) + -(1 / (64 * N128)) from by rw [← he12]; ring] + linarith [hP1.1, hP2.1] + linarith [hlo, h32_8] + have hneg : -(9 / (8 * N128)) < -(1 / (8 * N128)) + 0 := by + rw [← h1_8N]; linarith [hp128'] + linarith [h12, hP3_lo, hneg] exact ⟨hsum_lo, hsum_hi⟩ /-- info: 'ExpYul.reducedArg_close' depends on axioms: [propext, Classical.choice, Quot.sound] -/ From bfee64218aefed96c09ef27fa06a7d6dff42b5be Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 15:12:32 +0200 Subject: [PATCH 064/149] Tighten the exp tod cert bracket to 4*2^1193 Sharpens the t*Od truncation bracket (was the loose 2^5*2^1193) using t < 2^127 (H128 < 2^127) in the propagated-loss step, needed to keep the r0-vs-rational cross-product envelope inside the runtime MARGIN. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 09fa29848..67601100e 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -262,7 +262,7 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : 2 ^ 1193 * (int256 (todTree x)) ≤ evalPoly ExpCertV.todNumV (int256 (tTree x)) ∧ - evalPoly ExpCertV.todNumV (int256 (tTree x)) < 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 5 * 2 ^ 1193 := by + evalPoly ExpCertV.todNumV (int256 (tTree x)) < 2 ^ 1193 * (int256 (todTree x)) + 4 * 2 ^ 1193 := by obtain ⟨_, _, htodlo, htodhi⟩ := todTree_bound hx hC hC0 obtain ⟨hodlo, hodhi⟩ := odNumVPoly_bracket hx hC hC0 set t := int256 (tTree x) with htdef @@ -298,7 +298,7 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) have : (2:Int)^127 < 2 ^ 128 := by norm_num omega have key : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) < - 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 5 * 2 ^ 1193 := by + 2 ^ 1193 * (int256 (todTree x)) + 4 * 2 ^ 1193 := by have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ 2 ^ 1042 * (t * (odTree x : Int)) + 3 * 2 ^ 1042 * t := by nlinarith [hmul_hi] have h2 : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htod_hi From 5889df8a62b37ba2545bd6a5a02c97b52e7fcb0d Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 15:18:48 +0200 Subject: [PATCH 065/149] Add the exp r0-vs-cert-rational bracket (RuntimeR0Bound/SeamR0Bound) Chains the sdiv floor sandwich with the numerator/denominator cert brackets and a positive lower bound on denExpV to bracket the runtime quotient against the v-form rational: r0*denExpV < 2^126*numExpV + 49*denExpV and 2^126*numExpV < (r0+1)*denExpV + 700*denExpV. The loose constants are absorbed by the runtime MARGIN (per-point) and the ~10^11 octave-seam doubling slack. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 67601100e..084f8189c 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -30,6 +30,7 @@ open FormalYul.Preservation open Common.Poly set_option maxRecDepth 100000 +set_option maxHeartbeats 1600000 /-! ## The even/odd Horner polynomials in `w = t²` and the cert-polynomial bridge -/ @@ -421,4 +422,110 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) have hInt : (M : Int) < ((q : Int) + 1) * (den : Int) := by exact_mod_cast h rw [heM] at hInt; linarith [hInt] +/-! ## A positive lower bound on the cert denominator -/ + +/-- `den_rt = ev − tod > 2¹²⁵` on the region (the even accumulator dominates `|tod|`). -/ +theorem den_rt_lb {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 : Int) ^ 125 < (evTree x : Int) - int256 (todTree x) := by + obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 + obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + have hev : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + have ht125 : int256 (todTree x) < 2 ^ 125 := by + rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num]; exact htod_hi + rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 from by norm_num] at hev + rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 ⊢ + omega + +/-- The cert denominator is bounded below: `denExpV(t) > 2¹³¹⁷` on the region. -/ +theorem denExpV_lb {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (2 : Int) ^ 1317 < evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨hlo, _⟩ := denExpV_bracket hx hC hC0 htnn + have hden := den_rt_lb hx hC hC0 + -- denExpV ≥ 2^1193·den_rt − 32·2^1193 > 2^1193·2^125 − 32·2^1193 = 2^1318 − 32·2^1193 > 2^1317 + have hstep : 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) - 32 * 2 ^ 1193 > + 2 ^ 1193 * (2 ^ 125 : Int) - 32 * 2 ^ 1193 := by + have := mul_lt_mul_of_pos_left hden (by positivity : (0:Int) < 2 ^ 1193) + linarith [this] + have hnum : 2 ^ 1193 * (2 ^ 125 : Int) - 32 * 2 ^ 1193 > 2 ^ 1317 := by + rw [show (2:Int)^1193 * 2 ^ 125 = 2 ^ 1318 from by rw [← pow_add]] + have h18 : (2:Int)^1318 = 2 * 2 ^ 1317 := by rw [show (1318:Nat) = 1 + 1317 from rfl, pow_add]; ring + have h93 : (2:Int)^1193 < 2 ^ 1317 := by + apply pow_lt_pow_right₀ (by norm_num) (by norm_num) + nlinarith [h18, h93] + linarith [hlo, hstep, hnum] + +/-! ## The `r0`-vs-cert-rational bracket (direct chain) -/ + +/-- **`r0Tree x` brackets `2¹²⁶·ê_v`**: `r0·denExpV < 2¹²⁶·numExpV + 49·denExpV` and +`2¹²⁶·numExpV < (r0+1)·denExpV + 700·denExpV`. The loose constants are MARGIN/seam-absorbed. -/ +theorem r0_vs_certRatio {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) < + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) + + 49 * evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) < + (int256 (r0Tree x) + 1) * evalPoly ExpCertV.denExpV (int256 (tTree x)) + + 700 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hnumlo, hnumhi⟩ := numExpV_bracket hx hC hC0 htnn + obtain ⟨hdenlo, hdenhi⟩ := denExpV_bracket hx hC hC0 htnn + obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 + have hdenExpV_lb := denExpV_lb hx hC hC0 htnn + set r0 := int256 (r0Tree x) with hr0def + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + set NE := evalPoly ExpCertV.numExpV (int256 (tTree x)) with hNEdef + set DE := evalPoly ExpCertV.denExpV (int256 (tTree x)) with hDEdef + have hDEpos : (0 : Int) < DE := by + have h : (2:Int)^1317 > 0 := by positivity + linarith [hdenExpV_lb, h] + have hr0pos : 0 ≤ r0 := by linarith [hr0lo] + have hr0lt : r0 < 2 ^ 128 := hr0hi + have hp1193 : (0 : Int) < 2 ^ 1193 := by positivity + have hden_nn : (0 : Int) ≤ den := by + have h := den_rt_lb hx hC hC0; rw [← hdendef] at h; positivity + -- DE bounds vs den·2^1193 (denExpV_bracket): DE - 3·2^1193 < den·2^1193 ≤ DE + 32·2^1193 + have hden2_lo : 2 ^ 1193 * den ≤ DE + 32 * 2 ^ 1193 := by linarith [hdenlo] + have hden2_hi : DE - 3 * 2 ^ 1193 < 2 ^ 1193 * den := by linarith [hdenhi] + -- NE bounds (numExpV_bracket): num·2^1193 ≤ NE < num·2^1193 + 35·2^1193 + have hnum2_lo : 2 ^ 1193 * num ≤ NE := hnumlo + have hnum2_hi : NE < 2 ^ 1193 * num + 35 * 2 ^ 1193 := hnumhi + -- 49·DE > 49·2^1317 > 3·2^1321 ≥ 3·2^1193·r0 + have h2_1321 : (3 : Int) * 2 ^ 1193 * (2 ^ 128 : Int) = 3 * 2 ^ 1321 := by rw [mul_assoc, ← pow_add] + have hr0_loss : 3 * 2 ^ 1193 * r0 < 49 * DE := by + have h1 : 3 * 2 ^ 1193 * r0 < 3 * 2 ^ 1193 * 2 ^ 128 := by + apply mul_lt_mul_of_pos_left hr0lt; positivity + have h2 : (3 : Int) * 2 ^ 1321 < 49 * 2 ^ 1317 := by + rw [show (1321:Nat) = 4 + 1317 from rfl, pow_add]; ring_nf; nlinarith [pow_pos (by norm_num : (0:Int)<2) 1317] + rw [h2_1321] at h1 + linarith [h1, h2, mul_lt_mul_of_pos_left hdenExpV_lb (by norm_num : (0:Int) < 49)] + -- 700·DE > 35·2^1319 + 32·2^1193·(r0+1) (under loss) + have hunder_loss : 35 * 2 ^ 126 * 2 ^ 1193 + 32 * 2 ^ 1193 * (r0 + 1) < 700 * DE := by + have h1 : 32 * 2 ^ 1193 * (r0 + 1) < 32 * 2 ^ 1193 * (2 ^ 128 + 1) := by + apply mul_lt_mul_of_pos_left (by linarith [hr0lt]); positivity + have hr0p1 : (32 : Int) * 2 ^ 1193 * (2 ^ 128 + 1) < 33 * 2 ^ 1321 := by + rw [show (1321:Nat) = 4 + 1317 from rfl, pow_add]; ring_nf + nlinarith [pow_pos (by norm_num : (0:Int)<2) 1193, pow_pos (by norm_num : (0:Int)<2) 1317] + have h35 : (35 : Int) * 2 ^ 126 * 2 ^ 1193 = 35 * 2 ^ 1319 := by rw [mul_assoc, ← pow_add] + have hbound : (35 : Int) * 2 ^ 1319 + 33 * 2 ^ 1321 < 700 * 2 ^ 1317 := by + rw [show (1319:Nat) = 2 + 1317 from rfl, show (1321:Nat) = 4 + 1317 from rfl, pow_add, pow_add] + ring_nf; nlinarith [pow_pos (by norm_num : (0:Int)<2) 1317] + rw [h35] + linarith [h1, hr0p1, hbound, mul_lt_mul_of_pos_left hdenExpV_lb (by norm_num : (0:Int) < 700)] + -- abstract the powers so the final steps stay linear in the kernel + have hfl_lo := mul_le_mul_of_nonneg_left hfloor_lo (by positivity : (0:Int) ≤ 2 ^ 1193) + have hfl_hi := mul_lt_mul_of_pos_left hfloor_hi hp1193 + have hnumstep := mul_le_mul_of_nonneg_left hnum2_lo (by positivity : (0:Int) ≤ 2 ^ 126) + have hNEstep := mul_lt_mul_of_pos_left hnum2_hi (by positivity : (0:Int) < 2 ^ 126) + have hr0den_lo := mul_le_mul_of_nonneg_left (le_of_lt hden2_hi) hr0pos + have hr0den_hi := mul_le_mul_of_nonneg_left hden2_lo (by linarith [hr0pos] : (0:Int) ≤ r0 + 1) + -- expand products into a common shape via ring_nf, then linarith over the atoms + constructor + · nlinarith [hfl_lo, hnumstep, hr0den_lo, hr0_loss, hDEpos, hp1193] + · nlinarith [hfl_hi, hNEstep, hr0den_hi, hunder_loss, hDEpos, hp1193] + end ExpYul From 2c1bc43d46374e35b5f0b4880e83cc01e89e5f26 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 16:21:38 +0200 Subject: [PATCH 066/149] Add the exp octave-fold target identity, cert real bounds, and loose per-point over MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The octave real identity E·2^(126−k) = WAD·2¹²⁶·exp(rt) (target_octave_fold, via exp(X/RAY) = exp(rt)·2^k), the cert exp brackets at the runtime reduced argument (certUp_real/certLo_real, pushing the v-form Taylor caps through the abstract RealExpBridge), the ln2/2 domain bounds, and the loose per-point never-over r0 ≤ 2¹²⁶·exp(rt) + 50 (r0_real_over_loose, nonnegative half) that the octave-seam doubling absorbs. All axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 084f8189c..d8bb6aca3 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -4,6 +4,7 @@ import ExpProof.Floor.Reduce import ExpProof.Mono.Quot import ExpProof.Mono.Cross import Common.Seam.RealExpBridge +import Mathlib.Analysis.SpecialFunctions.Pow.Real /-! # The per-point `r0`-vs-`exp` bridge @@ -528,4 +529,312 @@ theorem r0_vs_certRatio {x : Nat} (hx : x < 2 ^ 256) · nlinarith [hfl_lo, hnumstep, hr0den_lo, hr0_loss, hDEpos, hp1193] · nlinarith [hfl_hi, hNEstep, hr0den_hi, hunder_loss, hDEpos, hp1193] +/-! ## The octave real identity `E·2^(126−k) = WAD·2¹²⁶·exp(rt)` + +The target `E = WAD·exp(X/RAY)`. With `rt = X/RAY − k·ln2` the reduced argument, `exp(X/RAY) = +exp(rt)·2^k`, so the closing-shift fold `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`. This collapses the +`RuntimeR0Bound.over`/`under` inequalities (stated against `E·2^s`, `s = 126 − k`) onto the clean +octave-independent never-over/deficit relation `r0 ≈ 2¹²⁶·exp(rt)`. -/ + +open ExpRealSpec Real Common.RealExpBridge + +/-- `exp(X/RAY) = exp(rt)·2^k` (`k = int256 (kTree x)`, possibly negative; `2^k` is a real `zpow`). -/ +theorem exp_X_over_RAY (x : Nat) : + Real.exp ((int256 x : Real) / (10 ^ 27 : Real)) = + Real.exp (reducedArg x) * (2 : Real) ^ (int256 (kTree x)) := by + have hlog : Real.exp ((int256 (kTree x) : Real) * Real.log 2) = (2 : Real) ^ (int256 (kTree x)) := by + rw [← Real.rpow_intCast 2 (int256 (kTree x)), + Real.rpow_def_of_pos (by norm_num : (0:Real) < 2), mul_comm] + rw [show (int256 x : Real) / (10 ^ 27 : Real) = + reducedArg x + (int256 (kTree x) : Real) * Real.log 2 from by + unfold reducedArg; ring, + Real.exp_add, hlog] + +/-- **The octave fold of the target.** `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`, with `s = 126 − k` the +closing shift. -/ +theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 126 - int256 (kTree x)) : + expRayToWadTarget (int256 x) * (2 ^ s : Real) = + (WAD : Real) * (2 ^ 126 : Real) * Real.exp (reducedArg x) := by + unfold expRayToWadTarget + rw [show (RAY : Real) = (10 ^ 27 : Real) from by unfold RAY; norm_num, exp_X_over_RAY x] + -- 2^k · 2^s = 2^126 with k+s = 126 (k : Int, s : Nat). + set k := int256 (kTree x) with hkdef + have hks : k + (s : Int) = 126 := by omega + have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (126 : Nat) := by + rw [show ((2 : Real) ^ (s : Nat)) = (2 : Real) ^ (s : Int) from by + rw [zpow_natCast], ← zpow_add₀ (by norm_num : (2:Real) ≠ 0), hks] + norm_num + rw [show ((2 ^ s : Real)) = (2 : Real) ^ (s : Nat) from by norm_num] + calc (WAD : Real) * (Real.exp (reducedArg x) * (2 : Real) ^ k) * (2 : Real) ^ (s : Nat) + = (WAD : Real) * ((2 : Real) ^ k * (2 : Real) ^ (s : Nat)) * Real.exp (reducedArg x) := by ring + _ = (WAD : Real) * (2 ^ 126 : Real) * Real.exp (reducedArg x) := by + rw [hpow] + +/-! ## The cert `Real.exp` bounds at the runtime reduced argument (nonnegative half) + +Instantiating the v-form Taylor caps (`ExpCertV.capExpUp`/`capExpLo`) at `t = int256 (tTree x)` (in +the cert domain `[0, H128]` on the nonnegative half) and pushing through the abstract +`Common.RealExpBridge` yields `Real.exp(t/2¹²⁸)` bracketed by the margin-nudged rational `ê_v = +NE/DE`. Both `NE = evalPoly numExpV t` and `DE = evalPoly denExpV t` are positive on the domain. -/ + +/-- The numerator/denominator cert-polynomial values are nonnegative / positive on `[0, H128]`. -/ +theorem certNE_nonneg {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : + 0 ≤ evalPoly ExpCertV.numExpV t := ExpCertV.numExpV_nonneg' h1 h2 + +theorem certDE_pos {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : + 1 ≤ evalPoly ExpCertV.denExpV t := ExpCertV.denExpV_ge_one h1 h2 + +/-- **Never-over cert real bound (nonneg half).** `(2¹³⁰−1)·NE / (2¹³⁰·DE) ≤ exp(t/2¹²⁸)`, the +not-two-below cap pushed to `Real.exp`. -/ +theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : + ((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ + Real.exp ((t : Real) / (2 ^ 128 : Real)) := by + have hcap := ExpCertV.capExpLo h1 h2 + have hwpos : 0 < (evalPoly ExpCertV.wLB t).toNat := by + have hpos : 0 < evalPoly ExpCertV.wLB t := by + rw [ExpCertV.evalWLB] + exact mul_pos (by norm_num) (by have := certDE_pos h1 h2; omega) + omega + have h := le_exp_of_capLB (q := ExpCertV.Qexp) ExpCertV.Qexp_pos hwpos hcap + -- the cap is on `(t.toNat : Real)/Qexp`; rewrite to `(t:Real)/2^128` + have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 + have hylb : 0 ≤ evalPoly ExpCertV.yLB t := by + rw [ExpCertV.evalYLB]; exact Int.mul_nonneg (by norm_num) (certNE_nonneg h1 h2) + have hwlb : 0 ≤ evalPoly ExpCertV.wLB t := by + rw [ExpCertV.evalWLB] + exact Int.mul_nonneg (by norm_num) (by have := certDE_pos h1 h2; omega) + have hyn : ((evalPoly ExpCertV.yLB t).toNat : Int) = evalPoly ExpCertV.yLB t := Int.toNat_of_nonneg hylb + have hwn : ((evalPoly ExpCertV.wLB t).toNat : Int) = evalPoly ExpCertV.wLB t := Int.toNat_of_nonneg hwlb + have harg : ((t.toNat : Nat) : Real) / ((ExpCertV.Qexp : Nat) : Real) = (t : Real) / (2 ^ 128 : Real) := by + rw [show ((ExpCertV.Qexp : Nat) : Real) = (2 ^ 128 : Real) from by unfold ExpCertV.Qexp; norm_num] + congr 1 + have : ((t.toNat : Nat) : Real) = (t : Real) := by + have := htn; exact_mod_cast this + exact this + rw [harg] at h + -- rewrite yLB/wLB to (2^130-1)·NE / (2^130·DE) + have hynr : ((evalPoly ExpCertV.yLB t).toNat : Real) = ((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by + have : ((evalPoly ExpCertV.yLB t).toNat : Int) = (2 ^ 130 - 1) * evalPoly ExpCertV.numExpV t := by + rw [hyn, ExpCertV.evalYLB] + have := congrArg (fun z : Int => (z : Real)) this + push_cast at this ⊢; linarith [this] + have hwnr : ((evalPoly ExpCertV.wLB t).toNat : Real) = ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by + have : ((evalPoly ExpCertV.wLB t).toNat : Int) = 2 ^ 130 * evalPoly ExpCertV.denExpV t := by + rw [hwn, ExpCertV.evalWLB] + have := congrArg (fun z : Int => (z : Real)) this + push_cast at this ⊢; linarith [this] + rw [hynr, hwnr] at h + exact h + +/-- **Not-two-below cert real bound (nonneg half).** `exp(t/2¹²⁸) ≤ (2¹³⁰+1)·NE / (2¹³⁰·DE)`. -/ +theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : + Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ + ((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + have hcap := ExpCertV.capExpUp h1 h2 + have hwpos : 0 < (evalPoly ExpCertV.wUB t).toNat := by + have hpos : 0 < evalPoly ExpCertV.wUB t := by + rw [ExpCertV.evalWUB] + exact mul_pos (by norm_num) (by have := certDE_pos h1 h2; omega) + omega + have h := exp_le_of_capUB (q := ExpCertV.Qexp) ExpCertV.Qexp_pos hwpos hcap + have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 + have hyub : 0 ≤ evalPoly ExpCertV.yUB t := by + rw [ExpCertV.evalYUB]; exact Int.mul_nonneg (by norm_num) (certNE_nonneg h1 h2) + have hwub : 0 ≤ evalPoly ExpCertV.wUB t := by + rw [ExpCertV.evalWUB] + exact Int.mul_nonneg (by norm_num) (by have := certDE_pos h1 h2; omega) + have hyn : ((evalPoly ExpCertV.yUB t).toNat : Int) = evalPoly ExpCertV.yUB t := Int.toNat_of_nonneg hyub + have hwn : ((evalPoly ExpCertV.wUB t).toNat : Int) = evalPoly ExpCertV.wUB t := Int.toNat_of_nonneg hwub + have harg : ((t.toNat : Nat) : Real) / ((ExpCertV.Qexp : Nat) : Real) = (t : Real) / (2 ^ 128 : Real) := by + rw [show ((ExpCertV.Qexp : Nat) : Real) = (2 ^ 128 : Real) from by unfold ExpCertV.Qexp; norm_num] + congr 1 + have : ((t.toNat : Nat) : Real) = (t : Real) := by + have := htn; exact_mod_cast this + exact this + rw [harg] at h + have hynr : ((evalPoly ExpCertV.yUB t).toNat : Real) = ((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by + have : ((evalPoly ExpCertV.yUB t).toNat : Int) = (2 ^ 130 + 1) * evalPoly ExpCertV.numExpV t := by + rw [hyn, ExpCertV.evalYUB] + have := congrArg (fun z : Int => (z : Real)) this + push_cast at this ⊢; linarith [this] + have hwnr : ((evalPoly ExpCertV.wUB t).toNat : Real) = ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by + have : ((evalPoly ExpCertV.wUB t).toNat : Int) = 2 ^ 130 * evalPoly ExpCertV.denExpV t := by + rw [hwn, ExpCertV.evalWUB] + have := congrArg (fun z : Int => (z : Real)) this + push_cast at this ⊢; linarith [this] + rw [hynr, hwnr] at h + exact h + +/-! ## The reduced argument stays below `ln2/2`, and the loose exp envelopes -/ + +/-- On the nonnegative half of the region the reduced argument is below `ln2/2`: +`t/2¹²⁸ ≤ log 2 / 2`. -/ +theorem t_over_2128_le_half_log2 {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ Real.log 2 / 2 := by + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + -- t ≤ H128 ≤ ⌊ln2/2·2^128⌋, and LN2/2^235 ≤ ln2 gives H128/2^128 ≤ ln2/2 + have hln2lo := ln2_lower + rw [LN2c_eq] at hln2lo + -- LN2/2^235 ≤ log 2. H128 = 117932881612756647068972071382077242199. + -- t/2^128 ≤ H128/2^128. need H128/2^128 ≤ log2/2. Use 2·H128/2^128 ≤ 2·(ln2/2) = ln2. + have htR : (int256 (tTree x) : Real) ≤ (117932881612756647068972071382077242199 : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hthi; push_cast at this; linarith [this] + have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity + rw [div_le_div_iff₀ hp128 (by norm_num : (0:Real) < 2)] + -- t·2 ≤ log2·2^128. Have t ≤ H128, and 2·H128 ≤ log2·2^128 (from LN2 bound). + have hkey : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := by + -- log2 ≥ LN2/2^235 ⟹ log2·2^128 ≥ LN2·2^128/2^235 = LN2/2^107. Check 2·H128 ≤ LN2/2^107. + have h1 : (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := by + apply mul_le_mul_of_nonneg_right hln2lo (by positivity) + have h2 : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ + (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) := by + rw [div_mul_eq_mul_div, le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)] + norm_num + linarith [h1, h2] + nlinarith [htR, hkey] + +/-- The reduced exponential is below `√2 < 2` (loose). -/ +theorem exp_reducedArg_le_two {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + Real.exp (reducedArg x) ≤ 2 := by + -- |rt| ≤ ln2/2 + tiny ⟹ rt < log2 ⟹ exp(rt) < exp(log2) = 2; we prove ≤ 2 generously. + obtain ⟨htlo, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have hclose := reducedArg_close hx hC hC0 + have habs := abs_lt.mp hclose + -- rt < t/2^128 + 9/(8·2^128) ≤ H128/2^128 + 1 < log2 (very loose: H128/2^128 < 0.347) + have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity + have htR : (int256 (tTree x) : Real) ≤ (117932881612756647068972071382077242199 : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hthi; push_cast at this; linarith [this] + have hln2 : (0.6931471805 : Real) ≤ Real.log 2 := by + have := ln2_lower; rw [LN2c_eq] at this + have h2 : (0.6931471805 : Real) ≤ (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) := by + rw [le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)]; norm_num + linarith [this, h2] + have hrtlt : reducedArg x ≤ Real.log 2 := by + have h9 : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 1 := by + rw [div_le_one (by positivity)]; norm_num + have htdiv : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ 0.35 := by + rw [div_le_iff₀ hp128]; nlinarith [htR] + -- rt < t/2^128 + 9/(8·2^128) ≤ 0.35 + 1 ... too loose vs log2 ≈ 0.693. tighten 9/8 bound. + have h9' : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 0.34 := by + rw [div_le_iff₀ (by positivity)]; norm_num + linarith [habs.2, htdiv, h9', hln2] + calc Real.exp (reducedArg x) ≤ Real.exp (Real.log 2) := Real.exp_le_exp.mpr hrtlt + _ = 2 := Real.exp_log (by norm_num) + +/-- `exp(t/2¹²⁸) ≤ 2` (loose). -/ +theorem exp_t_le_two {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) ≤ 2 := by + have hle := t_over_2128_le_half_log2 hx hC hC0 htnn + have hhalf : Real.log 2 / 2 ≤ Real.log 2 := by + have : (0:Real) ≤ Real.log 2 := by rw [Real.le_log_iff_exp_le (by norm_num)]; simp [Real.exp_zero] + linarith + calc Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) + ≤ Real.exp (Real.log 2) := Real.exp_le_exp.mpr (le_trans hle hhalf) + _ = 2 := Real.exp_log (by norm_num) + +/-- The convexity bound `exp(b) − exp(a) ≤ (b−a)·exp(b)`. -/ +theorem exp_diff_le (a b : Real) : Real.exp b - Real.exp a ≤ (b - a) * Real.exp b := by + have key : Real.exp a = Real.exp (a - b) * Real.exp b := by rw [← Real.exp_add]; ring_nf + have h1 : a - b + 1 ≤ Real.exp (a - b) := Real.add_one_le_exp (a - b) + have hb : 0 < Real.exp b := Real.exp_pos b + rw [key]; nlinarith [h1, hb] + +/-! ## The loose per-point real bounds (nonnegative half) + +These bracket `(r0Tree x : Real)` against `2¹²⁶·exp(rt)` with loose octave-seam-absorbed constants +(`+50` over, `+701` under). They suffice for `SeamR0Bound`, whose octave-seam doubling has ~10¹¹ +slack. The over side does not yet meet the per-point `MARGIN` budget — that needs the tight +cross-product sharpening; here only the loose `r0_vs_certRatio` constants are used. -/ + +/-- **Loose per-point never-over** (nonneg half): `r0 ≤ 2¹²⁶·exp(rt) + 50`. -/ +theorem r0_real_over_loose {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 50 := by + obtain ⟨hover, _⟩ := r0_vs_certRatio hx hC hC0 htnn + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + set t := int256 (tTree x) with htdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + have hDElb := denExpV_lb hx hC hC0 htnn + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + have hoverR : (int256 (r0Tree x) : Real) * (DE : Real) < + (2 ^ 126 : Real) * (NE : Real) + 49 * (DE : Real) := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hover + push_cast at this; linarith [this] + have hr0_lt : (int256 (r0Tree x) : Real) < (2 ^ 126 : Real) * (NE : Real) / (DE : Real) + 49 := by + rw [div_add' _ _ _ (ne_of_gt hDEpos), lt_div_iff₀ hDEpos] + nlinarith [hoverR, hDEpos] + have hcertlo := certLo_real htnn htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by + have := certNE_nonneg htnn htdom; exact_mod_cast this + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + have hExp_t_le_two := exp_t_le_two hx hC hC0 htnn + rw [← hEtdef] at hExp_t_le_two + set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by + have hc : ((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + rw [hMpdef] + have key : (NE : Real) / (DE : Real) = + ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) * + (((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real))) := by + push_cast; field_simp; ring + rw [key, mul_comm Et _] + exact mul_le_mul_of_nonneg_left hc (by positivity) + have hclose := abs_lt.mp (reducedArg_close hx hC hC0) + set Ert := Real.exp (reducedArg x) with hErtdef + have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ + have hgap1 : (t : Real) / (2 ^ 128 : Real) - reducedArg x < 9 / (8 * (2 ^ 128 : Real)) := by + have := hclose.1; linarith [this] + have hEt_nonneg : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) + have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp + have hEtMp_Ert : Et * Mp - Ert ≤ + Et * (1 / ((2 ^ 130 : Real) - 1)) + (9 / (8 * (2 ^ 128 : Real))) * Et := by + have h1 : Et * Mp - Ert = Et * (Mp - 1) + (Et - Ert) := by ring + rw [h1, hMp1] + have hgap : Et - Ert ≤ (9 / (8 * (2 ^ 128 : Real))) * Et := by + calc Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := hExp_diff + _ ≤ (9 / (8 * (2 ^ 128 : Real))) * Et := + mul_le_mul_of_nonneg_right (le_of_lt hgap1) hEt_nonneg + linarith [hgap] + have hfinal : (2 ^ 126 : Real) * (Et * Mp) ≤ (2 ^ 126 : Real) * Ert + 1 := by + have hb1 : Et * (1 / ((2 ^ 130 : Real) - 1)) ≤ 2 / ((2 ^ 130 : Real) - 1) := by + rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)]; nlinarith [hExp_t_le_two] + have hb2 : (9 / (8 * (2 ^ 128 : Real))) * Et ≤ (9 / (8 * (2 ^ 128 : Real))) * 2 := + mul_le_mul_of_nonneg_left hExp_t_le_two (by positivity) + have hbb : Et * Mp - Ert ≤ + 2 / ((2 ^ 130 : Real) - 1) + (9 / (8 * (2 ^ 128 : Real))) * 2 := by + linarith [hEtMp_Ert, hb1, hb2] + have hnum : (2 ^ 126 : Real) * + (2 / ((2 ^ 130 : Real) - 1) + (9 / (8 * (2 ^ 128 : Real))) * 2) ≤ 1 := by norm_num + set Xb : Real := 2 / ((2 ^ 130 : Real) - 1) + (9 / (8 * (2 ^ 128 : Real))) * 2 with hXbdef + have hscaled : (2 ^ 126 : Real) * (Et * Mp - Ert) ≤ (2 ^ 126 : Real) * Xb := + mul_le_mul_of_nonneg_left hbb (by positivity) + have hdist : (2 ^ 126 : Real) * (Et * Mp - Ert) = + (2 ^ 126 : Real) * (Et * Mp) - (2 ^ 126 : Real) * Ert := by ring + rw [hdist] at hscaled + linarith [hscaled, hnum] + have hstep : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (2 ^ 126 : Real) * Ert + 1 := + le_trans (mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real))) hfinal + have heq : (2 ^ 126 : Real) * (NE : Real) / (DE : Real) = + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := by ring + rw [heq] at hr0_lt + linarith [hr0_lt, hstep] + end ExpYul From d1485c013d21d1263c1fe50d8f4a0da22b5d59a1 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 16:26:15 +0200 Subject: [PATCH 067/149] Add the exp loose per-point deficit bound (nonnegative half) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit r0_real_under_loose: 2¹²⁶·exp(rt) ≤ r0 + 705, via r0_vs_certRatio (under), the v-form cert never-too-below (certUp_real), and the convexity gap-1 bound. Together with r0_real_over_loose this brackets r0 against 2¹²⁶·exp(rt) on the nonnegative half with octave-seam-absorbed constants. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index d8bb6aca3..e63bccd64 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -837,4 +837,101 @@ theorem r0_real_over_loose {x : Nat} (hx : x < 2 ^ 256) rw [heq] at hr0_lt linarith [hr0_lt, hstep] +/-- **Loose per-point deficit** (nonneg half): `2¹²⁶·exp(rt) ≤ r0 + 705`. -/ +theorem r0_real_under_loose {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 705 := by + obtain ⟨_, hunder⟩ := r0_vs_certRatio hx hC hC0 htnn + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 + set t := int256 (tTree x) with htdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + have hDElb := denExpV_lb hx hC hC0 htnn + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + -- 2^126·NE/DE < r0 + 701 + have hunderR : (2 ^ 126 : Real) * (NE : Real) < + ((int256 (r0Tree x) : Real) + 1) * (DE : Real) + 700 * (DE : Real) := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hunder + push_cast at this; linarith [this] + have hr0_gt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (int256 (r0Tree x) : Real) + 701 := by + rw [mul_div_assoc'] + rw [div_lt_iff₀ hDEpos] + nlinarith [hunderR, hDEpos] + -- certUp: exp(t/2^128) ≤ (2^130+1)·NE/(2^130·DE) = (NE/DE)·M⁺⁺ + have hcertup := certUp_real htnn htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by + have := certNE_nonneg htnn htdom; exact_mod_cast this + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef + have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mpp := by + have hc : Et ≤ ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real)) := hcertup + rw [hMppdef] + have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) = + ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 130 : Int) : Real) * (DE : Real)) := by + push_cast; field_simp; ring + rw [key]; exact hc + -- 2^126·Et ≤ 2^126·(NE/DE)·Mpp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mpp-1). + have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) + have hMpp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp + have hr0R : (int256 (r0Tree x) : Real) < (2 ^ 128 : Real) := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi + rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h + have hr0nn : (0 : Real) ≤ (int256 (r0Tree x) : Real) := by + obtain ⟨hlo, _⟩ := r0Tree_bounds hx hC hC0 + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlo; push_cast at this; linarith [this] + -- 2^126·Et ≤ r0 + 702 + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (int256 (r0Tree x) : Real) + 702 := by + have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) := + mul_le_mul_of_nonneg_left hEt_le (by positivity) + -- (NE/DE)·Mpp = NE/DE + (NE/DE)·(Mpp-1) + have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) = + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) := by ring + -- 2^126·(NE/DE)·(Mpp-1) ≤ 1. use 2^126·(NE/DE) < r0+701 < 2^128+701, ·2^-130 < 1 + have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) ≤ 1 := by + rw [hMpp1] + have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := + mul_nonneg (by positivity) hNEDE_nn + have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 701 := by + linarith [hr0_gt, hr0R] + calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / (2 ^ 130 : Real)) + ≤ ((2 ^ 128 : Real) + 701) * (1 / (2 ^ 130 : Real)) := + mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) + _ ≤ 1 := by norm_num + linarith [h1, h2 ▸ h1, h3, hr0_gt] + -- gap1: 2^126·(Ert - Et) ≤ 2.25 (via convexity + exp(rt) ≤ 2) + set Ert := Real.exp (reducedArg x) with hErtdef + have hclose := abs_lt.mp (reducedArg_close hx hC hC0) + have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ + have hErt_le_two := exp_reducedArg_le_two hx hC hC0 + rw [← hErtdef] at hErt_le_two + have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) + have hgap : Ert - Et ≤ (9 / (8 * (2 ^ 128 : Real))) * Ert := by + have hd : reducedArg x - (t : Real) / (2 ^ 128 : Real) < 9 / (8 * (2 ^ 128 : Real)) := by + have := hclose.2; linarith [this] + calc Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := hExp_diff + _ ≤ (9 / (8 * (2 ^ 128 : Real))) * Ert := mul_le_mul_of_nonneg_right (le_of_lt hd) hErt_nn + have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 3 := by + have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * Ert) := + mul_le_mul_of_nonneg_left hgap (by positivity) + have h2 : (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * Ert) ≤ + (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * 2) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) + have h3 : (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * 2) ≤ 3 := by norm_num + linarith [h1, h2, h3] + -- assemble: 2^126·Ert = 2^126·Et + 2^126·(Ert-Et) ≤ (r0+702) + 3 + have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring + rw [hdist] + linarith [hEt_bound, hgap126] + end ExpYul From f1fe98791165b0987fc5e045357a0f699ba578d3 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 16:38:55 +0200 Subject: [PATCH 068/149] Add the exp negative-half integer brackets and reciprocal symmetry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The negative-t (t ≤ 0) integer brackets (todNumV_bracket_neg with the flipped odd-Horner sign, numExpV/denExpV_bracket_neg, denExpV_lb_neg, r0_vs_certRatio_neg with loose octave-seam-absorbed constants 150/700), and the reciprocal symmetry numExpV(−t) = denExpV(t) / denExpV(−t) = numExpV(t) (evNumVPoly even, todNumV odd). These feed the negative-half per-point real bound via the cert at −t. Axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index e63bccd64..6f2117851 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -258,6 +258,28 @@ theorem evalDenExpV (t : Int) : evalPoly ExpCertV.denExpV t = evalPoly ExpCertV.evNumVPoly t - evalPoly ExpCertV.todNumV t := by unfold ExpCertV.denExpV; rw [evalPoly_polySub] +/-- `evNumVPoly` is even (`= Pev(t²)`). -/ +theorem evNumVPoly_even (t : Int) : + evalPoly ExpCertV.evNumVPoly (-t) = evalPoly ExpCertV.evNumVPoly t := by + rw [evNumVPoly_eq_Pev_sq, evNumVPoly_eq_Pev_sq] + congr 1; ring + +/-- `todNumV` is odd (`= 2²³·t·Pod(t²)`). -/ +theorem todNumV_odd (t : Int) : + evalPoly ExpCertV.todNumV (-t) = -evalPoly ExpCertV.todNumV t := by + rw [evalTodNumV, evalTodNumV, odNumVPoly_eq_Pod_sq, odNumVPoly_eq_Pod_sq] + rw [show ((-t)^2 : Int) = t^2 from by ring] + ring + +/-- **Reciprocal symmetry** `numExpV(−t) = denExpV(t)` and `denExpV(−t) = numExpV(t)`. -/ +theorem numExpV_neg_eq_denExpV (t : Int) : + evalPoly ExpCertV.numExpV (-t) = evalPoly ExpCertV.denExpV t := by + rw [evalNumExpV, evalDenExpV, evNumVPoly_even, todNumV_odd]; ring + +theorem denExpV_neg_eq_numExpV (t : Int) : + evalPoly ExpCertV.denExpV (-t) = evalPoly ExpCertV.numExpV t := by + rw [evalDenExpV, evalNumExpV, evNumVPoly_even, todNumV_odd]; ring + /-- **The `t·Od` cert term brackets the runtime `tod`** (nonnegative half): for `0 ≤ t`, `2¹¹⁹³·tod ≤ evalPoly todNumV t < 2¹¹⁹³·tod + 2⁵·2¹¹⁹³`. -/ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) @@ -529,6 +551,180 @@ theorem r0_vs_certRatio {x : Nat} (hx : x < 2 ^ 256) · nlinarith [hfl_lo, hnumstep, hr0den_lo, hr0_loss, hDEpos, hp1193] · nlinarith [hfl_hi, hNEstep, hr0den_hi, hunder_loss, hDEpos, hp1193] +/-! ## The negative-half integer brackets + +For `t < 0` the runtime `tod = ⌊t·od/2¹²⁸⌋` is nonpositive, so the `t·Od` cert term `todNumV(t)` +(odd in `t`) is also nonpositive; multiplying the (sign-independent) odd-Horner bracket by `2²³·t < 0` +flips the inequalities. The even-Horner bracket `evNumVPoly_bracket` is sign-independent (even poly). +Assembling gives the numerator/denominator brackets and the same loose `r0`-vs-`ê_v` constants, with +the floor sandwich `r0_floor_sandwich` (itself sign-free). -/ + +/-- **`todNumV` bracket (negative half).** For `t ≤ 0`: +`2¹¹⁹³·tod − 4·2¹¹⁹³ < todNumV(t) < 2¹¹⁹³·tod + 2·2¹¹⁹³`. -/ +theorem todNumV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + 2 ^ 1193 * (int256 (todTree x)) - 4 * 2 ^ 1193 < evalPoly ExpCertV.todNumV (int256 (tTree x)) ∧ + evalPoly ExpCertV.todNumV (int256 (tTree x)) < 2 ^ 1193 * (int256 (todTree x)) + 2 * 2 ^ 1193 := by + obtain ⟨_, _, htodlo, htodhi⟩ := todTree_bound hx hC hC0 + obtain ⟨hodlo, hodhi⟩ := odNumVPoly_bracket hx hC hC0 + obtain ⟨htlo', hthi'⟩ := tTree_bound hx hC hC0 + set t := int256 (tTree x) with htdef + rw [evalTodNumV] + have hodnn : (0 : Int) ≤ (odTree x : Int) := by positivity + have hodpolynn : (0 : Int) ≤ evalPoly ExpCertV.odNumVPoly t := le_trans (by positivity) hodlo + -- multiply odd bracket by t ≤ 0 (flips): + have hmul_lo : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int)) := + mul_le_mul_of_nonpos_left hodlo htneg + have hmul_hi : t * (2 ^ 1042 * (odTree x : Int) + 3 * 2 ^ 1042) ≤ t * evalPoly ExpCertV.odNumVPoly t := + mul_le_mul_of_nonpos_left (le_of_lt hodhi) htneg + have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo + have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi + have htgt : -(2 ^ 128 : Int) < t := by + have : -(2:Int)^127 < t := htlo' + have h2 : -(2:Int)^128 < -(2:Int)^127 := by norm_num + omega + constructor + · -- todNumV = 2^23·(t·odpoly) > 2^23·(t·(2^1042 odTree + 3·2^1042)) (since hmul_hi gives ≥) + -- = 2^1065·(t·odTree) + 3·2^1065·t ≥ 2^1193·tod + 3·2^1065·t > 2^1193·tod - 3·2^1193 + have h1 : 2 ^ 1042 * (t * (odTree x : Int)) + 3 * 2 ^ 1042 * t ≤ t * evalPoly ExpCertV.odNumVPoly t := by + nlinarith [hmul_hi] + have h2 : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htod_lo + nlinarith [h1, h2, htgt] + · -- todNumV = 2^23·(t·odpoly) ≤ 2^23·(t·2^1042 odTree) = 2^1065·(t·odTree) < 2^1193·tod + 2^1193 + have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ 2 ^ 1042 * (t * (odTree x : Int)) := by + nlinarith [hmul_lo] + have h2 : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htod_hi + nlinarith [h1, h2] + +/-- **Numerator/denominator brackets (negative half).** `NE ∈ (S·num_rt − 4S, S·num_rt + 4S)`, +`DE ∈ (S·den_rt − 2S, S·den_rt + 4S)` (`S = 2¹¹⁹³`, `num_rt = ev + tod`, `den_rt = ev − tod`). -/ +theorem numExpV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + 2 ^ 1193 * ((evTree x : Int) + int256 (todTree x)) - 4 * 2 ^ 1193 < + evalPoly ExpCertV.numExpV (int256 (tTree x)) ∧ + evalPoly ExpCertV.numExpV (int256 (tTree x)) < + 2 ^ 1193 * ((evTree x : Int) + int256 (todTree x)) + 5 * 2 ^ 1193 := by + obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 + obtain ⟨htodlo, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg + rw [evalNumExpV] + constructor + · nlinarith [hevlo, htodlo] + · nlinarith [hevhi, htodhi] + +theorem denExpV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 1193 < + evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ + evalPoly ExpCertV.denExpV (int256 (tTree x)) < + 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) + 7 * 2 ^ 1193 := by + obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 + obtain ⟨htodlo, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg + rw [evalDenExpV] + constructor + · nlinarith [hevlo, htodhi] + · nlinarith [hevhi, htodlo] + +/-- The cert denominator stays large on the negative half too: `denExpV(t) > 2¹³¹⁷`. (For `t < 0`, +`den_rt = ev − tod ≥ ev > 2¹²⁵`, so `DE > S·2¹²⁵ − 2S > 2¹³¹⁷`.) -/ +theorem denExpV_lb_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + (2 : Int) ^ 1317 < evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨hlo, _⟩ := denExpV_bracket_neg hx hC hC0 htneg + -- den_rt = ev − tod ≥ ev > 2^125 (tod ≤ 0 on the negative half) + obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 + obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + have hev : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 from by norm_num] at hev + -- tod ≤ 0 ⇒ den_rt = ev − tod ≥ ev > 2^125 + have htodnp : int256 (todTree x) ≤ 0 := by + -- from todTree_bound: 2^128·tod ≤ t·od, t ≤ 0, od ≥ 0 ⇒ t·od ≤ 0 ⇒ tod ≤ 0 + obtain ⟨_, _, htl, _⟩ := todTree_bound hx hC hC0 + have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn + nlinarith [htl, this] + have hden_rt : (2 : Int) ^ 125 < (evTree x : Int) - int256 (todTree x) := by + rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] + omega + have hstep : 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 1193 > + 2 ^ 1193 * (2 ^ 125 : Int) - 2 * 2 ^ 1193 := by + have := mul_lt_mul_of_pos_left hden_rt (by positivity : (0:Int) < 2 ^ 1193) + linarith [this] + have hnum : 2 ^ 1193 * (2 ^ 125 : Int) - 2 * 2 ^ 1193 > 2 ^ 1317 := by + rw [show (2:Int)^1193 * 2 ^ 125 = 2 ^ 1318 from by rw [← pow_add]] + have h18 : (2:Int)^1318 = 2 * 2 ^ 1317 := by rw [show (1318:Nat) = 1 + 1317 from rfl, pow_add]; ring + have h93 : (2:Int)^1193 < 2 ^ 1317 := pow_lt_pow_right₀ (by norm_num) (by norm_num) + nlinarith [h18, h93] + linarith [hlo, hstep, hnum] + +/-- **`r0`-vs-cert-rational bracket (negative half).** Same loose constants as the nonnegative half. -/ +theorem r0_vs_certRatio_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) < + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) + + 150 * evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) < + (int256 (r0Tree x) + 1) * evalPoly ExpCertV.denExpV (int256 (tTree x)) + + 700 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hnumlo, hnumhi⟩ := numExpV_bracket_neg hx hC hC0 htneg + obtain ⟨hdenlo, hdenhi⟩ := denExpV_bracket_neg hx hC hC0 htneg + obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 + have hdenExpV_lb := denExpV_lb_neg hx hC hC0 htneg + set r0 := int256 (r0Tree x) with hr0def + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + set NE := evalPoly ExpCertV.numExpV (int256 (tTree x)) with hNEdef + set DE := evalPoly ExpCertV.denExpV (int256 (tTree x)) with hDEdef + have hDEpos : (0 : Int) < DE := by + have h : (2:Int)^1317 > 0 := by positivity + linarith [hdenExpV_lb, h] + have hr0pos : 0 ≤ r0 := by linarith [hr0lo] + have hr0lt : r0 < 2 ^ 128 := hr0hi + have hp1193 : (0 : Int) < 2 ^ 1193 := by positivity + -- DE bounds vs den·2^1193: DE - 7·2^1193 < den·2^1193 ≤ DE + 2·2^1193 + have hden2_lo : 2 ^ 1193 * den ≤ DE + 2 * 2 ^ 1193 := by linarith [hdenlo] + have hden2_hi : DE - 7 * 2 ^ 1193 < 2 ^ 1193 * den := by linarith [hdenhi] + -- NE bounds: num·2^1193 - 4·2^1193 ≤ NE < num·2^1193 + 5·2^1193 + have hnum2_lo : 2 ^ 1193 * num - 4 * 2 ^ 1193 ≤ NE := by linarith [hnumlo] + have hnum2_hi : NE < 2 ^ 1193 * num + 5 * 2 ^ 1193 := hnumhi + -- loss budgets dominated by 150·DE / 700·DE (DE > 2^1317, r0 < 2^128) + have hr0_loss : 7 * 2 ^ 1193 * r0 + 4 * 2 ^ 126 * 2 ^ 1193 < 150 * DE := by + have h1 : (7 : Int) * 2 ^ 1193 * r0 < 7 * 2 ^ 1193 * 2 ^ 128 := by + have := mul_lt_mul_of_pos_left hr0lt (by positivity : (0:Int) < 7 * 2 ^ 1193) + nlinarith [this] + have hb : (7 : Int) * 2 ^ 1193 * 2 ^ 128 + 4 * 2 ^ 126 * 2 ^ 1193 < 150 * 2 ^ 1317 := by + rw [show (7:Int) * 2 ^ 1193 * 2 ^ 128 = 7 * 2 ^ 1321 from by rw [mul_assoc, ← pow_add], + show (4:Int) * 2 ^ 126 * 2 ^ 1193 = 4 * 2 ^ 1319 from by rw [mul_assoc, ← pow_add], + show (1321:Nat) = 4 + 1317 from rfl, show (1319:Nat) = 2 + 1317 from rfl, pow_add, pow_add] + ring_nf; nlinarith [pow_pos (by norm_num : (0:Int)<2) 1317] + linarith [h1, hb, mul_lt_mul_of_pos_left hdenExpV_lb (by norm_num : (0:Int) < 150)] + have hunder_loss : 5 * 2 ^ 126 * 2 ^ 1193 + 2 * 2 ^ 1193 * (r0 + 1) < 700 * DE := by + have h1 : 2 * 2 ^ 1193 * (r0 + 1) < 2 * 2 ^ 1193 * (2 ^ 128 + 1) := by + apply mul_lt_mul_of_pos_left (by linarith [hr0lt]); positivity + have hr0p1 : (2 : Int) * 2 ^ 1193 * (2 ^ 128 + 1) < 3 * 2 ^ 1321 := by + rw [show (1321:Nat) = 4 + 1317 from rfl, pow_add]; ring_nf + nlinarith [pow_pos (by norm_num : (0:Int)<2) 1193, pow_pos (by norm_num : (0:Int)<2) 1317] + have h35 : (5 : Int) * 2 ^ 126 * 2 ^ 1193 = 5 * 2 ^ 1319 := by rw [mul_assoc, ← pow_add] + have hbound : (5 : Int) * 2 ^ 1319 + 3 * 2 ^ 1321 < 700 * 2 ^ 1317 := by + rw [show (1319:Nat) = 2 + 1317 from rfl, show (1321:Nat) = 4 + 1317 from rfl, pow_add, pow_add] + ring_nf; nlinarith [pow_pos (by norm_num : (0:Int)<2) 1317] + rw [h35] + linarith [h1, hr0p1, hbound, mul_lt_mul_of_pos_left hdenExpV_lb (by norm_num : (0:Int) < 700)] + have hfl_lo := mul_le_mul_of_nonneg_left hfloor_lo (by positivity : (0:Int) ≤ 2 ^ 1193) + have hfl_hi := mul_lt_mul_of_pos_left hfloor_hi hp1193 + have hnumstep := mul_le_mul_of_nonneg_left hnum2_lo (by positivity : (0:Int) ≤ 2 ^ 126) + have hNEstep := mul_lt_mul_of_pos_left hnum2_hi (by positivity : (0:Int) < 2 ^ 126) + have hr0den_lo := mul_le_mul_of_nonneg_left (le_of_lt hden2_hi) hr0pos + have hr0den_hi := mul_le_mul_of_nonneg_left hden2_lo (by linarith [hr0pos] : (0:Int) ≤ r0 + 1) + constructor + · nlinarith [hfl_lo, hnumstep, hr0den_lo, hr0_loss, hDEpos, hp1193] + · nlinarith [hfl_hi, hNEstep, hr0den_hi, hunder_loss, hDEpos, hp1193] + /-! ## The octave real identity `E·2^(126−k) = WAD·2¹²⁶·exp(rt)` The target `E = WAD·exp(X/RAY)`. With `rt = X/RAY − k·ln2` the reduced argument, `exp(X/RAY) = From 373ac16d2053bebbdc858fd6d2af6608d7209bea Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 16:49:00 +0200 Subject: [PATCH 069/149] Add the exp negative-half and combined per-point real bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cert real brackets at a negative reduced argument (certUp_real_neg/ certLo_real_neg, via the reciprocal symmetry + exp(−s)=1/exp(s)), the negative-half loose per-point bounds (r0_real_over/under_loose_neg), and the sign-unified combined bounds r0_real_over (r0 ≤ 2¹²⁶·exp(rt) + 152) and r0_real_under (2¹²⁶·exp(rt) ≤ r0 + 705) valid for every meaningful-region input. All axiom-clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 292 +++++++++++++++++- 1 file changed, 291 insertions(+), 1 deletion(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 6f2117851..452f1b1f8 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -863,7 +863,100 @@ theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) rw [hynr, hwnr] at h exact h -/-! ## The reduced argument stays below `ln2/2`, and the loose exp envelopes -/ +/-! ## The cert `Real.exp` bounds at a negative reduced argument (via the reciprocal symmetry) + +For `t ≤ 0` (with `−t ∈ [0, H128]`) the cert at `u = −t`, composed with `numExpV(−t) = denExpV(t)`, +`denExpV(−t) = numExpV(t)` and `exp(−s) = 1/exp(s)`, brackets `exp(t/2¹²⁸)` against the same +margin-nudged rational `NE(t)/DE(t)` — the over side needs `NE/DE ≤ exp·(2¹³⁰+1)/2¹³⁰`, the under +side `exp ≤ (NE/DE)·2¹³⁰/(2¹³⁰−1)`. The cert denominators `NE(t)`, `DE(t)` are positive. -/ + +/-- The odd cert polynomial `odNumVPoly` is nonnegative everywhere (`= Pod(t²)`, nonneg coeffs). -/ +theorem odNumVPoly_nonneg (t : Int) : 0 ≤ evalPoly ExpCertV.odNumVPoly t := by + rw [odNumVPoly_eq_Pod_sq] + exact evalPoly_nonneg_of_nonneg Pod_coeffs_nonneg (by positivity) + +/-- For `t ≤ 0` with `−t ∈ [0, H128]` the cert numerator/denominator at `t` are positive. -/ +theorem certNE_pos_neg_aux {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : + 0 < evalPoly ExpCertV.numExpV t ∧ 0 < evalPoly ExpCertV.denExpV t := by + have hnt : 0 ≤ -t := by omega + -- numExpV(t) = denExpV(-t) ≥ 1 > 0 + have h1' : evalPoly ExpCertV.numExpV t = evalPoly ExpCertV.denExpV (-t) := by + have := numExpV_neg_eq_denExpV (-t); rwa [neg_neg] at this + have hde : 1 ≤ evalPoly ExpCertV.denExpV (-t) := ExpCertV.denExpV_ge_one hnt h2 + -- denExpV(t) = evNumVPoly(t) − todNumV(t); for t ≤ 0, todNumV(t) ≤ 0, and evNumVPoly(t) ≥ 1 + have htod_np : evalPoly ExpCertV.todNumV t ≤ 0 := by + rw [evalTodNumV] + have hodnn := odNumVPoly_nonneg t + have : t * evalPoly ExpCertV.odNumVPoly t ≤ 0 := mul_nonpos_of_nonpos_of_nonneg h1 hodnn + nlinarith [this] + have hev1 : 1 ≤ evalPoly ExpCertV.evNumVPoly t := by + -- evNumVPoly(t) = evNumVPoly(-t) (even) ≥ denExpV(-t) ≥ 1 (todNumV(-t) ≥ 0) + have heven : evalPoly ExpCertV.evNumVPoly t = evalPoly ExpCertV.evNumVPoly (-t) := by + rw [← evNumVPoly_even (-t), neg_neg] + have htodnt : 0 ≤ evalPoly ExpCertV.todNumV (-t) := by + rw [evalTodNumV] + exact Int.mul_nonneg (by positivity) (Int.mul_nonneg hnt (odNumVPoly_nonneg (-t))) + have hde' := hde + rw [evalDenExpV] at hde' + rw [heven]; linarith [hde', htodnt] + refine ⟨by rw [h1']; omega, ?_⟩ + rw [evalDenExpV]; linarith [hev1, htod_np] + +/-- **Never-too-below cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: +`exp(t/2¹²⁸) ≤ (2¹³⁰·NE) / ((2¹³⁰−1)·DE)`. -/ +theorem certUp_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : + Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ + ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + have hnt : 0 ≤ -t := by omega + have hcl := certLo_real hnt h2 + rw [numExpV_neg_eq_denExpV, denExpV_neg_eq_numExpV] at hcl + obtain ⟨hNEpos, hDEpos⟩ := certNE_pos_neg_aux h1 h2 + have hNER : (0 : Real) < (evalPoly ExpCertV.numExpV t : Real) := by exact_mod_cast hNEpos + have hDER : (0 : Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos + have hexpneg : Real.exp (((-t) : Int) / (2 ^ 128 : Real)) = + (Real.exp ((t : Real) / (2 ^ 128 : Real)))⁻¹ := by + rw [show (((-t):Int) : Real) / (2 ^ 128 : Real) = -((t : Real) / (2 ^ 128 : Real)) from by + push_cast; ring, Real.exp_neg] + rw [hexpneg] at hcl + have hexppos := Real.exp_pos ((t : Real) / (2 ^ 128 : Real)) + have hlhs_pos : (0:Real) < ((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity + rw [le_inv_comm₀ hlhs_pos hexppos] at hcl + calc Real.exp ((t : Real) / (2 ^ 128 : Real)) + ≤ (((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := hcl + _ = ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + rw [inv_div] + +/-- **Never-over cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: +`(2¹³⁰·NE) / ((2¹³⁰+1)·DE) ≤ exp(t/2¹²⁸)`. -/ +theorem certLo_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : + ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ + Real.exp ((t : Real) / (2 ^ 128 : Real)) := by + have hnt : 0 ≤ -t := by omega + have hcu := certUp_real hnt h2 + rw [numExpV_neg_eq_denExpV, denExpV_neg_eq_numExpV] at hcu + obtain ⟨hNEpos, hDEpos⟩ := certNE_pos_neg_aux h1 h2 + have hNER : (0 : Real) < (evalPoly ExpCertV.numExpV t : Real) := by exact_mod_cast hNEpos + have hDER : (0 : Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos + have hexpneg : Real.exp (((-t) : Int) / (2 ^ 128 : Real)) = + (Real.exp ((t : Real) / (2 ^ 128 : Real)))⁻¹ := by + rw [show (((-t):Int) : Real) / (2 ^ 128 : Real) = -((t : Real) / (2 ^ 128 : Real)) from by + push_cast; ring, Real.exp_neg] + rw [hexpneg] at hcu + have hexppos := Real.exp_pos ((t : Real) / (2 ^ 128 : Real)) + have hrhs_pos : (0:Real) < ((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity + rw [inv_le_comm₀ hexppos hrhs_pos] at hcu + calc ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) + = (((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := by + rw [inv_div] + _ ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) := hcu /-- On the nonnegative half of the region the reduced argument is below `ln2/2`: `t/2¹²⁸ ≤ log 2 / 2`. -/ @@ -1130,4 +1223,201 @@ theorem r0_real_under_loose {x : Nat} (hx : x < 2 ^ 256) rw [hdist] linarith [hEt_bound, hgap126] +/-! ## The loose per-point real bounds (negative half) -/ + +/-- `t/2¹²⁸ ≤ 0` and the cert domain `−t ≤ H128` for the negative half. -/ +theorem tdom_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : (-(int256 (tTree x))) ≤ (ExpCertV.H128 : Int) := by + obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + omega + +/-- **Loose per-point never-over** (negative half): `r0 ≤ 2¹²⁶·exp(rt) + 152`. -/ +theorem r0_real_over_loose_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 152 := by + obtain ⟨hover, _⟩ := r0_vs_certRatio_neg hx hC hC0 htneg + have htdom := tdom_neg hx hC hC0 htneg + set t := int256 (tTree x) with htdef + have hDElb := denExpV_lb_neg hx hC hC0 htneg + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos + exact_mod_cast this + have hoverR : (int256 (r0Tree x) : Real) * (DE : Real) < + (2 ^ 126 : Real) * (NE : Real) + 150 * (DE : Real) := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hover + push_cast at this; linarith [this] + have hr0_lt : (int256 (r0Tree x) : Real) < (2 ^ 126 : Real) * (NE : Real) / (DE : Real) + 150 := by + rw [div_add' _ _ _ (ne_of_gt hDEpos), lt_div_iff₀ hDEpos] + nlinarith [hoverR, hDEpos] + -- NE/DE ≤ exp(t/2^128)·M⁺⁺ from certLo_real_neg + have hcl := certLo_real_neg htneg htdom + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef + have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mpp := by + -- hcl: 2^130·NE/((2^130+1)·DE) ≤ Et ⇒ NE/DE ≤ Et·(2^130+1)/2^130 + rw [hMppdef] + have key : (NE : Real) / (DE : Real) = + ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) * + (((2 ^ 130 : Int) : Real) * (NE : Real) / + (((2 ^ 130 + 1 : Int) : Real) * (DE : Real))) := by + push_cast; field_simp; ring + rw [key, mul_comm Et _] + exact mul_le_mul_of_nonneg_left hcl (by positivity) + -- exp(t/2^128) ≤ 1 (t ≤ 0) and exp(rt) bound + have hEt_le_one : Et ≤ 1 := by + rw [hEtdef] + have : (t : Real) / (2 ^ 128 : Real) ≤ 0 := by + apply div_nonpos_of_nonpos_of_nonneg _ (by positivity) + exact_mod_cast htneg + calc Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ Real.exp 0 := Real.exp_le_exp.mpr this + _ = 1 := Real.exp_zero + have hEt_nonneg : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) + have hclose := abs_lt.mp (reducedArg_close hx hC hC0) + set Ert := Real.exp (reducedArg x) with hErtdef + have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ + have hgap1 : (t : Real) / (2 ^ 128 : Real) - reducedArg x < 9 / (8 * (2 ^ 128 : Real)) := by + have := hclose.1; linarith [this] + have hMp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp + have hfinal : (2 ^ 126 : Real) * (Et * Mpp) ≤ (2 ^ 126 : Real) * Ert + 1 := by + have hEtMp_Ert : Et * Mpp - Ert ≤ + Et * (1 / (2 ^ 130 : Real)) + (9 / (8 * (2 ^ 128 : Real))) * Et := by + have h1 : Et * Mpp - Ert = Et * (Mpp - 1) + (Et - Ert) := by ring + rw [h1, hMp1] + have hgap : Et - Ert ≤ (9 / (8 * (2 ^ 128 : Real))) * Et := by + calc Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := hExp_diff + _ ≤ (9 / (8 * (2 ^ 128 : Real))) * Et := + mul_le_mul_of_nonneg_right (le_of_lt hgap1) hEt_nonneg + linarith [hgap] + have hb1 : Et * (1 / (2 ^ 130 : Real)) ≤ 1 / (2 ^ 130 : Real) := by + rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)]; nlinarith [hEt_le_one] + have hb2 : (9 / (8 * (2 ^ 128 : Real))) * Et ≤ (9 / (8 * (2 ^ 128 : Real))) * 1 := + mul_le_mul_of_nonneg_left hEt_le_one (by positivity) + set Xb : Real := 1 / (2 ^ 130 : Real) + (9 / (8 * (2 ^ 128 : Real))) * 1 with hXbdef + have hbb : Et * Mpp - Ert ≤ Xb := by rw [hXbdef]; linarith [hEtMp_Ert, hb1, hb2] + have hnum : (2 ^ 126 : Real) * Xb ≤ 1 := by rw [hXbdef]; norm_num + have hscaled : (2 ^ 126 : Real) * (Et * Mpp - Ert) ≤ (2 ^ 126 : Real) * Xb := + mul_le_mul_of_nonneg_left hbb (by positivity) + have hdist : (2 ^ 126 : Real) * (Et * Mpp - Ert) = + (2 ^ 126 : Real) * (Et * Mpp) - (2 ^ 126 : Real) * Ert := by ring + rw [hdist] at hscaled; linarith [hscaled, hnum] + have hstep : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (2 ^ 126 : Real) * Ert + 1 := + le_trans (mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real))) hfinal + have heq : (2 ^ 126 : Real) * (NE : Real) / (DE : Real) = + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := by ring + rw [heq] at hr0_lt + linarith [hr0_lt, hstep] + +/-- **Loose per-point deficit** (negative half): `2¹²⁶·exp(rt) ≤ r0 + 705`. -/ +theorem r0_real_under_loose_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 705 := by + obtain ⟨_, hunder⟩ := r0_vs_certRatio_neg hx hC hC0 htneg + obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 + have htdom := tdom_neg hx hC hC0 htneg + set t := int256 (tTree x) with htdef + have hDElb := denExpV_lb_neg hx hC hC0 htneg + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos + exact_mod_cast this + have hunderR : (2 ^ 126 : Real) * (NE : Real) < + ((int256 (r0Tree x) : Real) + 1) * (DE : Real) + 700 * (DE : Real) := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hunder + push_cast at this; linarith [this] + have hr0_gt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (int256 (r0Tree x) : Real) + 701 := by + rw [mul_div_assoc']; rw [div_lt_iff₀ hDEpos] + nlinarith [hunderR, hDEpos] + -- certUp_real_neg: exp(t/2^128) ≤ (NE/DE)·M⁺ + have hcu := certUp_real_neg htneg htdom + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mp := by + rw [hMpdef] + have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) = + ((2 ^ 130 : Int) : Real) * (NE : Real) / + (((2 ^ 130 - 1 : Int) : Real) * (DE : Real)) := by + push_cast; field_simp; ring + rw [key]; exact hcu + have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) + have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp + have hr0R : (int256 (r0Tree x) : Real) < (2 ^ 128 : Real) := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi + rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (int256 (r0Tree x) : Real) + 702 := by + have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := + mul_le_mul_of_nonneg_left hEt_le (by positivity) + have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) := by ring + have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) ≤ 1 := by + rw [hMp1] + have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 701 := by + linarith [hr0_gt, hr0R] + have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := + mul_nonneg (by positivity) hNEDE_nn + calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / ((2 ^ 130 : Real) - 1)) + ≤ ((2 ^ 128 : Real) + 701) * (1 / ((2 ^ 130 : Real) - 1)) := + mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) + _ ≤ 1 := by norm_num + linarith [h1, h2 ▸ h1, h3, hr0_gt] + set Ert := Real.exp (reducedArg x) with hErtdef + have hclose := abs_lt.mp (reducedArg_close hx hC hC0) + have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ + have hErt_le_two := exp_reducedArg_le_two hx hC hC0 + rw [← hErtdef] at hErt_le_two + have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) + have hgap : Ert - Et ≤ (9 / (8 * (2 ^ 128 : Real))) * Ert := by + have hd : reducedArg x - (t : Real) / (2 ^ 128 : Real) < 9 / (8 * (2 ^ 128 : Real)) := by + have := hclose.2; linarith [this] + calc Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := hExp_diff + _ ≤ (9 / (8 * (2 ^ 128 : Real))) * Ert := mul_le_mul_of_nonneg_right (le_of_lt hd) hErt_nn + have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 3 := by + have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * Ert) := + mul_le_mul_of_nonneg_left hgap (by positivity) + have h2 : (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * Ert) ≤ + (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * 2) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) + have h3 : (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * 2) ≤ 3 := by norm_num + linarith [h1, h2, h3] + have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring + rw [hdist] + linarith [hEt_bound, hgap126] + +/-! ## The combined per-point real bounds (both signs) + +Case-splitting on the sign of the reduced argument unifies the two halves into loose octave-seam +brackets valid for every meaningful-region input. -/ + +/-- **Per-point never-over** (any sign): `r0 ≤ 2¹²⁶·exp(rt) + 152`. -/ +theorem r0_real_over {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 152 := by + rcases le_or_lt 0 (int256 (tTree x)) with htnn | htneg + · linarith [r0_real_over_loose hx hC hC0 htnn] + · exact r0_real_over_loose_neg hx hC hC0 (le_of_lt htneg) + +/-- **Per-point deficit** (any sign): `2¹²⁶·exp(rt) ≤ r0 + 705`. -/ +theorem r0_real_under {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 705 := by + rcases le_or_lt 0 (int256 (tTree x)) with htnn | htneg + · exact r0_real_under_loose hx hC hC0 htnn + · exact r0_real_under_loose_neg hx hC hC0 (le_of_lt htneg) + end ExpYul From 13cd65d9d447e4254bc78a9d69bb0f4d9ef84221 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:51:36 +0200 Subject: [PATCH 070/149] Discharge SeamR0Bound for runtime monotonicity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The octave-seam r0-doubling bound r0Tree x1 < 2·r0Tree x2 (r0_seam_double / seamR0Bound_holds) follows from the per-point real bracket r0Tree x ≈ 2¹²⁶·exp(rt) (both signs) and the seam exp relation exp(rt1) = 2·exp(rt2)·exp(−1/RAY): the strict 1−exp(−1/RAY) ≈ 1/RAY slack (against r0Tree x2 > 2¹²⁴) dwarfs the loose envelope constants. run_exp_ray_to_wad_evm_mono_unconditional drops the RegionMonotonicityFacts hypothesis. Gated axiom-clean in Theorems.lean. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 119 ++++++++++++++++++ formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean | 33 +++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 32 ++++- 3 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 452f1b1f8..44de561f6 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -1420,4 +1420,123 @@ theorem r0_real_under {x : Nat} (hx : x < 2 ^ 256) · exact r0_real_under_loose hx hC hC0 htnn · exact r0_real_under_loose_neg hx hC hC0 (le_of_lt htneg) +/-! ## The octave-seam `r0`-doubling consequence -/ + +/-- The reduced argument is above `−log 2` on the region, so `exp(rt) > 1/2`. -/ +theorem exp_reducedArg_gt_half {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (1 : Real) / 2 < Real.exp (reducedArg x) := by + obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 + have hclose := abs_lt.mp (reducedArg_close hx hC hC0) + have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity + have htR : -(117932881612756647068972071382077242199 : Real) ≤ (int256 (tTree x) : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo; push_cast at this; linarith [this] + -- rt > t/2^128 - 9/(8·2^128) ≥ -H128/2^128 - 1 > -log 2 (log2 ≥ 0.693) + have hln2 : (0.6931471805 : Real) ≤ Real.log 2 := by + have := ln2_lower; rw [LN2c_eq] at this + have h2 : (0.6931471805 : Real) ≤ + (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) := by + rw [le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)]; norm_num + linarith [this, h2] + have htdiv : -(0.35 : Real) ≤ (int256 (tTree x) : Real) / (2 ^ 128 : Real) := by + rw [le_div_iff₀ hp128]; nlinarith [htR] + have h9 : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 0.34 := by + rw [div_le_iff₀ (by positivity)]; norm_num + have hrt : -(Real.log 2) < reducedArg x := by linarith [hclose.1, htdiv, h9, hln2] + have : Real.exp (-(Real.log 2)) < Real.exp (reducedArg x) := Real.exp_lt_exp.mpr hrt + rwa [Real.exp_neg, Real.exp_log (by norm_num : (0:Real) < 2), show (2:Real)⁻¹ = 1/2 from by norm_num] at this + +/-- A lower bound on the quotient: `2¹²⁴ < r0Tree x`. (`r0 ≥ 2¹²⁶·exp(rt) − 705 > 2¹²⁶·(1/2) − 705`.) -/ +theorem r0Tree_gt_2_124 {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 : Real) ^ 124 < (int256 (r0Tree x) : Real) := by + have hu := r0_real_under hx hC hC0 + have hh := exp_reducedArg_gt_half hx hC hC0 + -- 2^126·exp(rt) > 2^126·(1/2) = 2^125; r0 ≥ 2^126·exp(rt) − 705 > 2^125 − 705 > 2^124 + have h1 : (2 ^ 126 : Real) * (1 / 2) < (2 ^ 126 : Real) * Real.exp (reducedArg x) := + mul_lt_mul_of_pos_left hh (by positivity) + have h2 : (2 ^ 126 : Real) * (1 / 2) = (2 ^ 125 : Real) := by norm_num + have h3 : (2 : Real) ^ 124 + 705 < (2 ^ 125 : Real) := by norm_num + linarith [hu, h1, h2 ▸ h1, h3] + +/-- **The seam exp relation.** Across a seam (`X2 = X1 + 1`, `k2 = k1 + 1`), +`exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`. -/ +theorem reducedArg_seam {x1 x2 : Nat} + (hk : int256 (kTree x2) = int256 (kTree x1) + 1) + (hadj : int256 x2 = int256 x1 + 1) : + Real.exp (reducedArg x1) = + 2 * Real.exp (reducedArg x2) * Real.exp (-(1 / (10 ^ 27 : Real))) := by + have hrel : reducedArg x1 = reducedArg x2 + Real.log 2 + (-(1 / (10 ^ 27 : Real))) := by + unfold reducedArg + rw [show (int256 x2 : Real) = (int256 x1 : Real) + 1 from by exact_mod_cast hadj, + show (int256 (kTree x2) : Real) = (int256 (kTree x1) : Real) + 1 from by exact_mod_cast hk] + ring + rw [hrel, Real.exp_add, Real.exp_add, Real.exp_log (by norm_num : (0:Real) < 2)] + ring + +/-- **`r0` at most doubles across a seam** (real reduction of `SeamR0Bound`). The strict slack from +`exp(−1/RAY) < 1` (and `r0Tree x2 > 2¹²⁴`) dwarfs the loose per-point envelope constants. -/ +theorem r0_seam_double {x1 x2 : Nat} + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x2) = int256 (kTree x1) + 1) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (r0Tree x1) < 2 * int256 (r0Tree x2) := by + have hover1 := r0_real_over hx1 hC1 hC01 + have hunder2 := r0_real_under hx2 hC2 hC02 + have hr0_2_big := r0Tree_gt_2_124 hx2 hC2 hC02 + have hseam := reducedArg_seam hk hadj + -- exp(-1/RAY) < 1 and ≥ 1 - 1/RAY ⇒ 1 - exp(-1/RAY) ≥ 1/RAY - ... use the convexity-style bound + set E1 := Real.exp (reducedArg x1) with hE1 + set E2 := Real.exp (reducedArg x2) with hE2 + set y := Real.exp (-(1 / (10 ^ 27 : Real))) with hy + have hy_lt_one : y < 1 := by + rw [hy]; rw [show (1:Real) = Real.exp 0 from (Real.exp_zero).symm] + exact Real.exp_lt_exp.mpr (by norm_num) + have hy_pos : 0 < y := Real.exp_pos _ + -- y ≤ 1 - 1/(2·RAY) (since exp(-z) ≤ 1 - z + z²/2 ≤ 1 - z/2 for small z>0) + have hy_bound : y ≤ 1 - 1 / (2 * (10 ^ 27 : Real)) := by + -- exp(-z) = 1/exp(z) ≤ 1/(1+z) ≤ 1 - z/2 for z ∈ (0,1] + rw [hy] + have hz : (0:Real) < 1 / (10 ^ 27 : Real) := by positivity + have hez : (1 : Real) + 1 / (10 ^ 27 : Real) ≤ Real.exp (1 / (10 ^ 27 : Real)) := by + have := Real.add_one_le_exp (1 / (10 ^ 27 : Real)); linarith [this] + rw [Real.exp_neg] + have hexppos : 0 < Real.exp (1 / (10 ^ 27 : Real)) := Real.exp_pos _ + rw [inv_le_iff_one_le_mul₀ hexppos] + have h1z : (1 - 1 / (2 * (10 ^ 27 : Real))) * (1 + 1 / (10 ^ 27 : Real)) ≥ 1 := by + rw [ge_iff_le]; nlinarith [sq_nonneg (1 / (10 ^ 27 : Real))] + nlinarith [hez, h1z, hexppos, mul_pos (by positivity : (0:Real) < 1 - 1/(2*(10^27:Real))) hexppos] + -- 2^126·E1 = 2·(2^126·E2)·y ≤ 2·(r0_2 + 705)·y + have hE2bound : (2 ^ 126 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + 705 := hunder2 + have hr0_1 : (int256 (r0Tree x1) : Real) ≤ 2 * ((int256 (r0Tree x2) : Real) + 705) * y + 152 := by + have h1 : (2 ^ 126 : Real) * E1 = 2 * ((2 ^ 126 : Real) * E2) * y := by rw [hseam]; ring + have h2 : (int256 (r0Tree x1) : Real) ≤ (2 ^ 126 : Real) * E1 + 152 := hover1 + rw [h1] at h2 + have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 705) * y := + mul_le_mul_of_nonneg_right (by linarith [mul_le_mul_of_nonneg_left hE2bound (by norm_num : (0:Real) ≤ 2)]) (le_of_lt hy_pos) + linarith [h2, h3] + -- need: 2·(r0_2+705)·y + 152 < 2·r0_2. use y ≤ 1 - 1/(2·RAY), r0_2 > 2^124. + have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^124)] + have hkey : 2 * ((int256 (r0Tree x2) : Real) + 705) * y + 152 < 2 * (int256 (r0Tree x2) : Real) := by + -- 2(r0+705)y ≤ 2(r0+705)(1 - 1/(2RAY)). Then 2(r0+705) - 2(r0+705)/(2RAY) + 152 < 2 r0 + -- ⟺ 1410 + 152 < 2(r0+705)/(2RAY) = (r0+705)/RAY. r0 > 2^124 ⇒ (r0+705)/RAY > 2^124/10^27 ≈ 21 + -- WAIT: 2^124/10^27 ≈ 21 < 1562. Need bigger lower bound on r0! use r0 > 2^124 too weak. + have hyb : 2 * ((int256 (r0Tree x2) : Real) + 705) * y ≤ + 2 * ((int256 (r0Tree x2) : Real) + 705) * (1 - 1 / (2 * (10 ^ 27 : Real))) := + mul_le_mul_of_nonneg_left hy_bound (by linarith [hr0_2nn]) + have hexpand : 2 * ((int256 (r0Tree x2) : Real) + 705) * (1 - 1 / (2 * (10 ^ 27 : Real))) = + 2 * (int256 (r0Tree x2) : Real) + 1410 - + ((int256 (r0Tree x2) : Real) + 705) / (10 ^ 27 : Real) := by field_simp; ring + have hbig : ((int256 (r0Tree x2) : Real) + 705) / (10 ^ 27 : Real) > 1562 := by + rw [gt_iff_lt, lt_div_iff₀ (by positivity)] + nlinarith [hr0_2_big, (by norm_num : (1562:Real) * 10 ^ 27 + 1 < 2 ^ 124)] + linarith [hyb, hexpand ▸ hyb, hbig] + have hreal : (int256 (r0Tree x1) : Real) < 2 * (int256 (r0Tree x2) : Real) := by + linarith [hr0_1, hkey] + have : (int256 (r0Tree x1) : Real) < ((2 * int256 (r0Tree x2) : Int) : Real) := by + push_cast; linarith [hreal] + exact_mod_cast this + end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean b/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean new file mode 100644 index 000000000..f7cb416a7 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean @@ -0,0 +1,33 @@ +import ExpProof.Mono.Top +import ExpProof.Floor.R0Exp + +/-! +# Discharging the octave-seam `r0`-doubling bound for monotonicity + +`SeamR0Bound` (`r0Tree x1 < 2·r0Tree x2` across one octave seam) is the single analytic obligation +that `run_exp_ray_to_wad_evm_mono_of_seamR0` carries. The per-point real bracket `r0Tree x ≈ +2¹²⁶·exp(rt)` (`Floor.R0Exp`, both signs) together with the seam exp relation `rt1 = rt2 + ln2 − +1/RAY` discharges it: `exp(rt1) = 2·exp(rt2)·exp(−1/RAY) < 2·exp(rt2)` strictly, and the +`1 − exp(−1/RAY) ≈ 1/RAY` slack (against `r0Tree x2 > 2¹²⁴`) dwarfs the loose per-point envelope +constants. This closes `run_exp_ray_to_wad_evm_mono` without an external monotonicity hypothesis. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation + +/-- **The octave-seam `r0`-doubling bound holds.** -/ +theorem seamR0Bound_holds : SeamR0Bound := + fun hx1 hx2 hC1 hC01 hC2 hC02 hk hadj => + r0_seam_double hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + +/-- **Runtime monotonicity, with the seam bound discharged.** -/ +theorem run_exp_ray_to_wad_evm_mono_unconditional (x1 x2 : Nat) + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hle : int256 x1 ≤ int256 x2) (hdom : int256 x2 < int256 C0thresh) : + ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ + int256 r1 ≤ int256 r2 := + run_exp_ray_to_wad_evm_mono_of_seamR0 seamR0Bound_holds x1 x2 hx1 hx2 hle hdom + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index f2a04baa4..7fd3c67c5 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -1,6 +1,7 @@ import ExpProof.Seam.Revert import ExpProof.Seam.Value import ExpProof.Mono +import ExpProof.Mono.SeamR0 import ExpProof.Floor.Public import ExpProof.Floor.Fold import ExpProof.Floor.R0Bound @@ -80,8 +81,8 @@ example (H : RegionMonotonicityFacts) (x1 x2 : Nat) /-- Monotone over the whole supported domain, reduced to the single analytic obligation `SeamR0Bound` (the octave-seam `r0` doubling bound). The kernel-wall floor reduction, the `range`/`nonneg` obligations, the same-octave step, the region induction, and the scale-point pin are -all proved unconditionally; what remains for an unconditional monotonicity theorem is the minimax -accuracy bound `SeamR0Bound`. -/ +proved without this hypothesis; the monotonicity theorem here depends on the seam accuracy bound +`SeamR0Bound`. -/ example (hr0 : SeamR0Bound) (x1 x2 : Nat) (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hle : FormalYul.Preservation.int256 x1 ≤ FormalYul.Preservation.int256 x2) @@ -94,6 +95,30 @@ example (hr0 : SeamR0Bound) (x1 x2 : Nat) #guard_msgs in #print axioms run_exp_ray_to_wad_evm_mono_of_seamR0 +/-! ## Runtime monotonicity with the seam bound discharged + +The octave-seam `r0`-doubling bound `SeamR0Bound` is discharged (`seamR0Bound_holds`, via the +per-point real bracket `r0Tree x ≈ 2¹²⁶·exp(rt)` and the seam relation `exp(rt1) = +2·exp(rt2)·exp(−1/RAY)`), so monotonicity holds over the whole supported domain with no analytic +hypothesis. -/ + +/-- Monotone over the whole supported domain without an external monotonicity hypothesis. -/ +example (x1 x2 : Nat) + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hle : FormalYul.Preservation.int256 x1 ≤ FormalYul.Preservation.int256 x2) + (hdom : FormalYul.Preservation.int256 x2 < FormalYul.Preservation.int256 C0thresh) : + ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ + FormalYul.Preservation.int256 r1 ≤ FormalYul.Preservation.int256 r2 := + run_exp_ray_to_wad_evm_mono_unconditional x1 x2 hx1 hx2 hle hdom + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_mono_unconditional' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_mono_unconditional + +/-- info: 'ExpYul.seamR0Bound_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms seamR0Bound_holds + /-! ## `Real.exp` floor brackets, modulo the runtime accumulator bound Each bracket is stated on the runtime result `r` (`run_exp_ray_to_wad_evm x = .ok r`) against the @@ -154,8 +179,7 @@ example (H : RuntimeR0Bound) : RuntimeAccumBound := runtimeAccumBound_of_r0 H /-! ## Discharged ingredients of `RuntimeR0Bound` -The single open obligation `RuntimeR0Bound` is being discharged piecewise. The following are proved -unconditionally and axiom-clean: +The following `RuntimeR0Bound` ingredients are proved directly and axiom-clean: * `tTree_in_cert_domain` — the runtime reduced argument stays in the certificate domain `|tTree x| ≤ H128`, so the Taylor caps (`Floor.Caps`) instantiate at `t := tTree x`; From 7503a4ab54fde0d1e3c78d23e942a8042eb7c80a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 17:01:56 +0200 Subject: [PATCH 071/149] Use le_or_gt in the exp per-point sign split (drop deprecated le_or_lt) Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 44de561f6..14c4f4eb5 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -1408,7 +1408,7 @@ brackets valid for every meaningful-region input. -/ theorem r0_real_over {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 152 := by - rcases le_or_lt 0 (int256 (tTree x)) with htnn | htneg + rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · linarith [r0_real_over_loose hx hC hC0 htnn] · exact r0_real_over_loose_neg hx hC hC0 (le_of_lt htneg) @@ -1416,7 +1416,7 @@ theorem r0_real_over {x : Nat} (hx : x < 2 ^ 256) theorem r0_real_under {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 705 := by - rcases le_or_lt 0 (int256 (tTree x)) with htnn | htneg + rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_under_loose hx hC hC0 htnn · exact r0_real_under_loose_neg hx hC hC0 (le_of_lt htneg) From e06806f7a849fcf3dbdccaa08f0bac59de3dc9ef Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:52:17 +0200 Subject: [PATCH 072/149] Add the exp fractional gap-2 telescoping Replace the integer tele_step's loose +2 Horner floor-loss bound with a fractional telescoping (tele_step_frac/horner_stage_frac) that tracks the exact dyadic deficit width Wnum*2^p: evTree_bracket within 1065041*2^533, odTree_bracket within 67305505*2^504. The loose downstream monotonicity seam chain is preserved. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 207 ++++++++++++++---- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 85 ++++--- 2 files changed, 223 insertions(+), 69 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index d7699372d..f92090c31 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -24,6 +24,7 @@ open FormalYul open FormalYul.Preservation set_option maxRecDepth 100000 +set_option maxHeartbeats 1000000 /-! ## Gap-2: the even Horner accumulator brackets the exact polynomial @@ -88,6 +89,85 @@ theorem tele_step (e0 e1 v A c0 s E0 : Nat) · nlinarith [key_lo] · nlinarith [key_hi] +/-! ## The fractional telescoping bound + +The integer `tele_step` above yields a per-stage `+2` width because it carries the input width +verbatim (`E0 < 2^c0·e0 + 2·2^c0`). The *fractional* version tracks the exact deficit width as +`Wnum·2^p` (a dyadic rational `Wnum/2^(cum-p)` at the cumulative scale `2^cum`). Across a stage with +shift `s ≥ 127` the carried width is attenuated by `v/2^s ≤ 2^(126-s) < 1`, so the width evolves as +`W' = W·2^(126-s) + 1`. With `r_i = 2^(126-s_i) < 1` the widths stay strictly below `1/(1−max r)`, +recovering the true ≈1.02-unit gap-2 envelope instead of the loose `+2`. + +The state is `2^cum·e ≤ E < 2^cum·e + Wnum·2^p` with `p ≤ cum` (the width exponent). One stage with +shift `s` (constant `A`, `e1 = A + ⌊e0·v/2^s⌋`) produces the new width `Wnum' = Wnum + 2^(cum+s−p−126)` +at exponent `p' = p + 126` and scale `cum' = cum + s`. -/ +theorem tele_step_frac (e0 e1 v A cum s p Wnum E0 : Nat) + (hv : v < 2^126) (hs : 126 ≤ s) (hAe1 : A ≤ e1) (hpcum : p + 126 ≤ cum + s) + (hb0lo : 2^cum * e0 ≤ E0) (hb0hi : E0 < 2^cum * e0 + Wnum * 2^p) + (hslo : 2^s * (e1 - A) ≤ e0 * v) (hshi : e0 * v < 2^s * (e1 - A) + 2^s) : + 2^(cum+s) * e1 ≤ A * 2^(cum+s) + E0 * v ∧ + A * 2^(cum+s) + E0 * v < + 2^(cum+s) * e1 + (Wnum + 2^(cum+s-(p+126))) * 2^(p+126) := by + -- factor the relevant power identities, then abstract every `2^…` to an opaque var + have hsplit : (2:Nat)^(cum+s) = 2^cum * 2^s := by rw [Nat.pow_add] + -- key: 2^cum · 2^s = 2^(p+126) · 2^(cum+s-(p+126)) = 2^p · 2^126 · G + have hG : (2:Nat)^cum * 2^s = (2^p * 2^126) * 2^(cum+s-(p+126)) := by + rw [show (2:Nat)^p * 2^126 = 2^(p+126) from by rw [Nat.pow_add], + ← Nat.pow_add, ← Nat.pow_add]; congr 1; omega + have hPP126 : (2:Nat)^(p+126) = 2^p * 2^126 := by rw [Nat.pow_add] + have hP126 : (0:Nat) < 2^126 := Nat.two_pow_pos _ + have hPcum : (0:Nat) < 2^cum := Nat.two_pow_pos _ + set d := e1 - A with hd + have he1eq : e1 = A + d := by omega + -- abstract powers + set P := (2:Nat)^cum with hPdef + set Q := (2:Nat)^s with hQdef + set R := (2:Nat)^p with hRdef + set H := (2:Nat)^126 with hHdef + set G := (2:Nat)^(cum+s-(p+126)) with hGdef + -- collected facts in abstract form + rw [hsplit, he1eq] + rw [show (2:Nat)^(p+126) = R * H from hPP126] + have hPQ : P * Q = (R * H) * G := hG + have hvH : v ≤ H := le_of_lt hv + have hRpos : 0 < R := by rw [hRdef]; exact Nat.two_pow_pos _ + have hHpos : 0 < H := by rw [hHdef]; exact Nat.two_pow_pos _ + have hGpos : 0 < G := by rw [hGdef]; exact Nat.two_pow_pos _ + clear_value P Q R H G + have hRHpos : 0 < R * H := Nat.mul_pos hRpos hHpos + -- lower bound + have key_lo : P * Q * d ≤ E0 * v := by + calc P * Q * d = P * (Q * d) := by ring + _ ≤ P * (e0 * v) := by gcongr + _ = (P * e0) * v := by ring + _ ≤ E0 * v := by gcongr + -- upper bound, an explicit chain in the abstract powers + have key_hi : E0 * v < P * Q * d + (Wnum + G) * (R * H) := by + rcases Nat.eq_zero_or_pos v with hv0 | hv0 + · subst hv0 + have hpos : (0:Nat) < (Wnum + G) * (R * H) := + Nat.mul_pos (by omega) hRHpos + have : E0 * 0 < P * Q * d + (Wnum + G) * (R * H) := by + rw [Nat.mul_zero]; exact Nat.lt_of_lt_of_le hpos (Nat.le_add_left _ _) + simpa using this + have h1 : E0 * v < (P * e0 + Wnum * R) * v := (Nat.mul_lt_mul_right hv0).mpr hb0hi + have h3 : P * (e0 * v) < P * (Q * d + Q) := (Nat.mul_lt_mul_left hPcum).mpr hshi + have hcarry : Wnum * R * v ≤ Wnum * (R * H) := by + calc Wnum * R * v ≤ Wnum * R * H := by gcongr + _ = Wnum * (R * H) := by ring + calc E0 * v < (P * e0 + Wnum * R) * v := h1 + _ = P * (e0 * v) + Wnum * R * v := by ring + _ < P * (Q * d + Q) + Wnum * (R * H) := by + exact Nat.add_lt_add_of_lt_of_le h3 hcarry + _ = P * Q * d + (R * H) * G + Wnum * (R * H) := by rw [← hPQ]; ring + _ = P * Q * d + (Wnum + G) * (R * H) := by ring + refine ⟨?_, ?_⟩ + · calc P * Q * (A + d) = A * (P * Q) + P * Q * d := by ring + _ ≤ A * (P * Q) + E0 * v := by exact Nat.add_le_add_left key_lo _ + · calc A * (P * Q) + E0 * v < A * (P * Q) + (P * Q * d + (Wnum + G) * (R * H)) := + Nat.add_lt_add_left key_hi _ + _ = P * Q * (A + d) + (Wnum + G) * (R * H) := by ring + theorem ev0_exact {v : Nat} (hv : v < 2 ^ 126) : 2^0x1d * (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) - 0xb9aacfad41060587203a79af0ebc) ≤ v ∧ v < 2^0x1d * (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) - 0xb9aacfad41060587203a79af0ebc) + 2^0x1d := by @@ -139,9 +219,40 @@ theorem horner_stage (c P prev v cum sh Eprev : Nat) omega exact tele_step prev ev1 v c cum sh Eprev hv hs hge hElo hEhi hst.1 hst.2 +/-- The fractional version of `horner_stage`: a runtime Horner stage propagates a *dyadic-fraction* +deficit width `Wnum·2^p` into `(Wnum + 2^(cum+sh−p−126))·2^(p+126)` (the carried width is attenuated +by `v/2^sh ≤ 2^(126−sh) < 1`). Consumes `tele_step_frac`. -/ +theorem horner_stage_frac (c P prev v cum sh p Wnum Eprev : Nat) + (hv : v < 2^126) (hs : 126 ≤ sh) (hsh256 : sh < 256) (hprevlt : prev < P) + (hPV : P * 2^126 < 2^256) (hpcum : p + 126 ≤ cum + sh) + (hsum : c + P * 2^126 / 2^sh < 2^256) (hclt : c < 2^256) + (hElo : 2^cum * prev ≤ Eprev) (hEhi : Eprev < 2^cum * prev + Wnum * 2^p) : + 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) ≤ c * 2^(cum+sh) + Eprev * v ∧ + c * 2^(cum+sh) + Eprev * v < + 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) + + (Wnum + 2^(cum+sh-(p+126))) * 2^(p+126) := by + have hprev256 : prev < 2^256 := by have : P ≤ 2^256 := by omega + omega + have hv256 : v < 2^256 := by have : (2:Nat)^126 < 2^256 := by norm_num + omega + have hpv : prev * v < 2^256 := lt_of_lt_of_le (Nat.mul_lt_mul'' hprevlt hv) (by omega) + have hsum' : c + prev * v / 2^sh < 2^256 := by + have : prev * v / 2^sh ≤ P * 2^126 / 2^sh := by + apply Nat.div_le_div_right; exact Nat.le_of_lt (Nat.mul_lt_mul'' hprevlt hv) + omega + have hst := stage_exact hprev256 hv256 hpv hsh256 hclt hsum' + set ev1 := evmAdd c (evmShr sh (evmMul prev v)) with hev1 + have hge : c ≤ ev1 := by + rw [hev1, evmAdd_eq_nat hclt (by exact evmShr_lt _ _) (by + have hmul : evmMul prev v = prev * v := evmMul_eq_nat hprev256 hv256 hpv + have : evmShr sh (evmMul prev v) = prev*v/2^sh := by rw [hmul]; exact evmShr_eq_div (by omega) hpv + rw [this]; omega)] + omega + exact tele_step_frac prev ev1 v c cum sh p Wnum Eprev hv hs hge hpcum hElo hEhi hst.1 hst.2 + theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : - 2^553 * evTree x ≤ evNumV (vTree x) ∧ evNumV (vTree x) < 2^553 * evTree x + 2 * 2^553 := by + 2^553 * evTree x ≤ evNumV (vTree x) ∧ evNumV (vTree x) < 2^553 * evTree x + 1065041 * 2^533 := by have hev : evTree x = evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul @@ -149,71 +260,73 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d (vTree x))) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl set v := vTree x with hvdef - -- stage 0 + -- stage 0: width 1·2^29 (p=29, Wnum=1) have h0 := ev0_exact hv set e0 := evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) with he0 have he0lt : e0 < 2 ^ 113 := ev0_lt hv have he0ge : 0xb9aacfad41060587203a79af0ebc ≤ e0 := ev0_ge hv - -- E0 = A4*2^29 + v; bracket 2^29*e0 <= E0 < 2^29*e0 + 2*2^29 have h29 : (0x1d : Nat) = 29 := by norm_num rw [h29] at h0 have hE0lo : 2^29 * e0 ≤ 0xb9aacfad41060587203a79af0ebc * 2^29 + v := by have := h0.1; omega - have hE0hi : 0xb9aacfad41060587203a79af0ebc * 2^29 + v < 2^29 * e0 + 2 * 2^29 := by have := h0.2; omega - -- stage 1: cum 29 -> 159, sh=0x82=130, P=2^113 - have s1 := horner_stage 0x9a036222e11aee18465042f8ea64c8 (2^113) e0 v 29 0x82 + have hE0hi : 0xb9aacfad41060587203a79af0ebc * 2^29 + v < 2^29 * e0 + 1 * 2^29 := by have := h0.2; omega + -- stage 1: cum 29 -> 159, sh=130; p 29 -> 155; Wnum 1 -> 17 + have s1 := horner_stage_frac 0x9a036222e11aee18465042f8ea64c8 (2^113) e0 v 29 0x82 29 1 (0xb9aacfad41060587203a79af0ebc * 2^29 + v) hv (by norm_num) (by norm_num) he0lt (by norm_num) - (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num) (by norm_num) hE0lo hE0hi + (by norm_num) (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num) (by norm_num) hE0lo hE0hi + -- normalise the stage-1 width `(1 + 2^(159-155))·2^155` to `17·2^155` + rw [show (29:Nat)+0x82-(29+126) = 4 from by norm_num, show (1:Nat)+2^4 = 17 from by norm_num, + show (29:Nat)+126 = 155 from by norm_num, show (29:Nat)+0x82 = 159 from by norm_num] at s1 set e1 := evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul e0 v)) with he1 have he1lt : e1 < 2^121 := by have := (stage_bounds (c := 0x9a036222e11aee18465042f8ea64c8) (prev := e0) (v := v) (P := 2^113) (V := 2^126) (sh := 0x82) he0lt hv (by norm_num) (by norm_num) (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num)).2 rw [pvd 113 126 130 109 (by norm_num)] at this; omega - -- E1 = A1stage*2^159 + E0*v (cum 159). s1 gives bracket on e1 with this E1. - -- stage 2: cum 159 -> 287, sh=0x80=128, P=2^121 - have s2 := horner_stage 0x9064d965e1c4863b73604e0ddbec53f9 (2^121) e1 v 159 0x80 + -- stage 2: cum 159 -> 287, sh=128; p 155 -> 281; Wnum 17 -> 81 + have s2 := horner_stage_frac 0x9064d965e1c4863b73604e0ddbec53f9 (2^121) e1 v 159 0x80 155 17 (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) hv (by norm_num) (by norm_num) he1lt (by norm_num) - (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 + (by norm_num) (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 + rw [show (159:Nat)+0x80-(155+126) = 6 from by norm_num, show (17:Nat)+2^6 = 81 from by norm_num, + show (155:Nat)+126 = 281 from by norm_num, show (159:Nat)+0x80 = 287 from by norm_num] at s2 set e2 := evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul e1 v)) with he2 have he2lt : e2 < 2^129 := by have := (stage_bounds (c := 0x9064d965e1c4863b73604e0ddbec53f9) (prev := e1) (v := v) (P := 2^121) (V := 2^126) (sh := 0x80) he1lt hv (by norm_num) (by norm_num) (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num)).2 rw [pvd 121 126 128 119 (by norm_num)] at this; omega - -- stage 3: cum 287 -> 421, sh=0x86=134, P=2^129 - have s3 := horner_stage 0x93f11e65781741b92fa7fc4f4fffcca2 (2^129) e2 v 287 0x86 + -- stage 3: cum 287 -> 421, sh=134; p 281 -> 407; Wnum 81 -> 16465 + have s3 := horner_stage_frac 0x93f11e65781741b92fa7fc4f4fffcca2 (2^129) e2 v 287 0x86 281 81 (0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) * v) hv (by norm_num) (by norm_num) he2lt (by norm_num) - (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num) (by norm_num) s2.1 s2.2 + (by norm_num) (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num) (by norm_num) s2.1 s2.2 + rw [show (287:Nat)+0x86-(281+126) = 14 from by norm_num, show (81:Nat)+2^14 = 16465 from by norm_num, + show (281:Nat)+126 = 407 from by norm_num, show (287:Nat)+0x86 = 421 from by norm_num] at s3 set e3 := evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul e2 v)) with he3 have he3lt : e3 < 2^129 := by have := (stage_bounds (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (prev := e2) (v := v) (P := 2^129) (V := 2^126) (sh := 0x86) he2lt hv (by norm_num) (by norm_num) (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num)).2 rw [pvd 129 126 134 121 (by norm_num)] at this; omega - -- stage 4: cum 421 -> 553, sh=0x84=132, P=2^129 - have s4 := horner_stage 0x4e14a45e8ec305e233e11b4174e214ac (2^129) e3 v 421 0x84 + -- stage 4: cum 421 -> 553, sh=132; p 407 -> 533; Wnum 16465 -> 1065041 + have s4 := horner_stage_frac 0x4e14a45e8ec305e233e11b4174e214ac (2^129) e3 v 421 0x84 407 16465 (0x93f11e65781741b92fa7fc4f4fffcca2 * 2^421 + (0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) * v) * v) hv (by norm_num) (by norm_num) he3lt (by norm_num) - (by rw [pvd 129 126 132 123 (by norm_num)]; norm_num) (by norm_num) s3.1 s3.2 + (by norm_num) (by rw [pvd 129 126 132 123 (by norm_num)]; norm_num) (by norm_num) s3.1 s3.2 + rw [show (421:Nat)+0x84-(407+126) = 20 from by norm_num, + show (16465:Nat)+2^20 = 1065041 from by norm_num, + show (407:Nat)+126 = 533 from by norm_num, show (421:Nat)+0x84 = 553 from by norm_num] at s4 -- assemble: evTree x = e4 (the stage-4 value), evNumV v = the cumulative E4. rw [hev] - -- unfold evNumV to the same E4 expression show 2^553 * evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul e3 v)) ≤ evNumV v ∧ - evNumV v < 2^553 * evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul e3 v)) + 2 * 2^553 + evNumV v < 2^553 * evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul e3 v)) + 1065041 * 2^533 unfold evNumV - -- s4 has the right shape with cum+sh = 421+132 = 553 - have e553 : (421:Nat) + 0x84 = 553 := by norm_num - rw [e553] at s4 - -- the E4 in s4 = A0*2^553 + E3*v matches evNumV's let-expansion constructor · have := s4.1 - -- s4.1: 2^553 * e4 <= A0 * 2^553 + E3 * v. evNumV v = A0*2^553 + E3*v (after let). convert this using 2 <;> ring · have := s4.2 convert this using 2 <;> ring @@ -236,9 +349,10 @@ def odNumV (v : Nat) : Nat := let o3 := 0xaf5662483c4ce783a9ef5fe025f42e9e * 2^395 + o2 * v 0x270a522f476182f119f08da0ba710a56 * 2^530 + o3 * v -/-- Runtime odd-Horner accumulator brackets the exact polynomial within `2` ulp at scale `2^530`. -/ +/-- Runtime odd-Horner accumulator brackets the exact polynomial within `1.003·2^530` (the +fractional gap-2 envelope) at scale `2^530`. -/ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : - 2^530 * odTree x ≤ odNumV (vTree x) ∧ odNumV (vTree x) < 2^530 * odTree x + 2 * 2^530 := by + 2^530 * odTree x ≤ odNumV (vTree x) ∧ odNumV (vTree x) < 2^530 * odTree x + 67305505 * 2^504 := by have hod : odTree x = evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul @@ -246,52 +360,59 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl set v := vTree x with hvdef - -- the leading constant is its own (trivial) cumulative bracket at scale 2^0 + -- the leading constant is exact; track it as width 1·2^0 (B0 < B0 + 1) have hB4lo : 2^0 * 0xdc07aff85e5bb5629d0fb64a84bb ≤ 0xdc07aff85e5bb5629d0fb64a84bb := by norm_num - have hB4hi : (0xdc07aff85e5bb5629d0fb64a84bb : Nat) < 2^0 * 0xdc07aff85e5bb5629d0fb64a84bb + 2 * 2^0 := by norm_num - -- stage 1: cum 0 -> 131, sh=0x83=131, prev=B4<2^112 - have s1 := horner_stage 0xc926ddbf3830ca5561cc01585402d0 (2^112) 0xdc07aff85e5bb5629d0fb64a84bb v 0 0x83 + have hB4hi : (0xdc07aff85e5bb5629d0fb64a84bb : Nat) < 2^0 * 0xdc07aff85e5bb5629d0fb64a84bb + 1 * 2^0 := by norm_num + -- stage 1: cum 0 -> 131, sh=131; p 0 -> 126; Wnum 1 -> 33 + have s1 := horner_stage_frac 0xc926ddbf3830ca5561cc01585402d0 (2^112) 0xdc07aff85e5bb5629d0fb64a84bb v 0 0x83 0 1 0xdc07aff85e5bb5629d0fb64a84bb hv (by norm_num) (by norm_num) (by norm_num) (by norm_num) - (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num) (by norm_num) hB4lo hB4hi + (by norm_num) (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num) (by norm_num) hB4lo hB4hi + rw [show (0:Nat)+0x83-(0+126) = 5 from by norm_num, show (1:Nat)+2^5 = 33 from by norm_num, + show (0:Nat)+126 = 126 from by norm_num, show (0:Nat)+0x83 = 131 from by norm_num] at s1 set o1 := evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb v)) with ho1 have ho1lt : o1 < 2^121 := by have := (stage_bounds (c := 0xc926ddbf3830ca5561cc01585402d0) (prev := 0xdc07aff85e5bb5629d0fb64a84bb) (v := v) (P := 2^112) (V := 2^126) (sh := 0x83) (by norm_num) hv (by norm_num) (by norm_num) (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num)).2 rw [pvd 112 126 131 107 (by norm_num)] at this; omega - -- stage 2: cum 131 -> 268, sh=0x89=137, prev=o1<2^121 - have s2 := horner_stage 0xad4506b00b1246c7e5b4fd33e1201b (2^121) o1 v 131 0x89 + -- stage 2: cum 131 -> 268, sh=137; p 126 -> 252; Wnum 33 -> 65569 + have s2 := horner_stage_frac 0xad4506b00b1246c7e5b4fd33e1201b (2^121) o1 v 131 0x89 126 33 (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) hv (by norm_num) (by norm_num) ho1lt (by norm_num) - (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 + (by norm_num) (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 + rw [show (131:Nat)+0x89-(126+126) = 16 from by norm_num, show (33:Nat)+2^16 = 65569 from by norm_num, + show (126:Nat)+126 = 252 from by norm_num, show (131:Nat)+0x89 = 268 from by norm_num] at s2 set o2 := evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul o1 v)) with ho2 have ho2lt : o2 < 2^121 := by have := (stage_bounds (c := 0xad4506b00b1246c7e5b4fd33e1201b) (prev := o1) (v := v) (P := 2^121) (V := 2^126) (sh := 0x89) ho1lt hv (by norm_num) (by norm_num) (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num)).2 rw [pvd 121 126 137 110 (by norm_num)] at this; omega - -- stage 3: cum 268 -> 395, sh=0x7f=127, prev=o2<2^121 - have s3 := horner_stage 0xaf5662483c4ce783a9ef5fe025f42e9e (2^121) o2 v 268 0x7f + -- stage 3: cum 268 -> 395, sh=127; p 252 -> 378; Wnum 65569 -> 196641 + have s3 := horner_stage_frac 0xaf5662483c4ce783a9ef5fe025f42e9e (2^121) o2 v 268 0x7f 252 65569 (0xad4506b00b1246c7e5b4fd33e1201b * 2^268 + (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) * v) hv (by norm_num) (by norm_num) ho2lt (by norm_num) - (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num) (by norm_num) s2.1 s2.2 + (by norm_num) (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num) (by norm_num) s2.1 s2.2 + rw [show (268:Nat)+0x7f-(252+126) = 17 from by norm_num, show (65569:Nat)+2^17 = 196641 from by norm_num, + show (252:Nat)+126 = 378 from by norm_num, show (268:Nat)+0x7f = 395 from by norm_num] at s3 set o3 := evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul o2 v)) with ho3 have ho3lt : o3 < 2^129 := by have := (stage_bounds (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (prev := o2) (v := v) (P := 2^121) (V := 2^126) (sh := 0x7f) ho2lt hv (by norm_num) (by norm_num) (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num)).2 rw [pvd 121 126 127 120 (by norm_num)] at this; omega - -- stage 4: cum 395 -> 530, sh=0x87=135, prev=o3<2^129 - have s4 := horner_stage 0x270a522f476182f119f08da0ba710a56 (2^129) o3 v 395 0x87 + -- stage 4: cum 395 -> 530, sh=135; p 378 -> 504; Wnum 196641 -> 67305505 + have s4 := horner_stage_frac 0x270a522f476182f119f08da0ba710a56 (2^129) o3 v 395 0x87 378 196641 (0xaf5662483c4ce783a9ef5fe025f42e9e * 2^395 + (0xad4506b00b1246c7e5b4fd33e1201b * 2^268 + (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) * v) * v) hv (by norm_num) (by norm_num) ho3lt (by norm_num) - (by rw [pvd 129 126 135 120 (by norm_num)]; norm_num) (by norm_num) s3.1 s3.2 + (by norm_num) (by rw [pvd 129 126 135 120 (by norm_num)]; norm_num) (by norm_num) s3.1 s3.2 + rw [show (395:Nat)+0x87-(378+126) = 26 from by norm_num, + show (196641:Nat)+2^26 = 67305505 from by norm_num, + show (378:Nat)+126 = 504 from by norm_num, show (395:Nat)+0x87 = 530 from by norm_num] at s4 rw [hod] show 2^530 * evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul o3 v)) ≤ odNumV v ∧ - odNumV v < 2^530 * evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul o3 v)) + 2 * 2^530 + odNumV v < 2^530 * evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul o3 v)) + 67305505 * 2^504 unfold odNumV - have e530 : (395:Nat) + 0x87 = 530 := by norm_num - rw [e530] at s4 constructor · have := s4.1; convert this using 2 <;> ring · have := s4.2; convert this using 2 <;> ring diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 14c4f4eb5..5cf45daea 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -162,11 +162,13 @@ theorem tsq_split {x : Nat} (hx : x < 2 ^ 256) · nlinarith [hdm, hmod_lt] /-- **The even cert polynomial brackets the runtime even accumulator** (gap-2 ∘ v-truncation): -`2¹¹⁹³·evTree x ≤ evalPoly evNumVPoly t < 2¹¹⁹³·evTree x + 3·2¹¹⁹³`. -/ +`2¹¹⁹³·evTree x ≤ evalPoly evNumVPoly t < 2¹¹⁹³·evTree x + 2113617·2¹¹⁷³` (the fractional gap-2 width +`1065041·2¹¹⁷³` plus one v-step `2¹¹⁹³ = 2²⁰·2¹¹⁷³`, summing to `2113617·2¹¹⁷³ ≈ 2.0157·2¹¹⁹³`). -/ theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : 2 ^ 1193 * (evTree x : Int) ≤ evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) ∧ - evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) < 2 ^ 1193 * (evTree x : Int) + 3 * 2 ^ 1193 := by + evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) < + 2 ^ 1193 * (evTree x : Int) + 2113617 * 2 ^ 1173 := by obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 obtain ⟨hg2lo, hg2hi⟩ := evTree_bracket hvlt obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 @@ -187,9 +189,10 @@ theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) have h : (2 ^ 553 * evTree x : Nat) ≤ evNumV (vTree x) := hg2lo have : (2 ^ 553 * evTree x : Int) ≤ (evNumV (vTree x) : Int) := by exact_mod_cast h nlinarith [this] - have hg2hi' : (evNumV (vTree x) : Int) * 2 ^ 640 < 2 ^ 1193 * (evTree x : Int) + 2 * 2 ^ 1193 := by - have h : evNumV (vTree x) < 2 ^ 553 * evTree x + 2 * 2 ^ 553 := hg2hi - have : (evNumV (vTree x) : Int) < (2 ^ 553 * evTree x + 2 * 2 ^ 553 : Nat) := by exact_mod_cast h + -- gap-2 hi (fractional): evNumV(vTree)·2^640 < 2^1193·evTree + 1065041·2^1173 + have hg2hi' : (evNumV (vTree x) : Int) * 2 ^ 640 < 2 ^ 1193 * (evTree x : Int) + 1065041 * 2 ^ 1173 := by + have h : evNumV (vTree x) < 2 ^ 553 * evTree x + 1065041 * 2 ^ 533 := hg2hi + have : (evNumV (vTree x) : Int) < (2 ^ 553 * evTree x + 1065041 * 2 ^ 533 : Nat) := by exact_mod_cast h push_cast at this; nlinarith [this] -- step bound: evNumV(vTree+1)·2^640 < evNumV(vTree)·2^640 + 2^1193 have hstep := evNumV_step hvlt @@ -198,15 +201,18 @@ theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) refine ⟨le_trans hg2lo' hmono_lo, ?_⟩ calc evalPoly Pev (t ^ 2) ≤ (evNumV (vTree x + 1) : Int) * 2 ^ 640 := hmono_hi _ < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1193 := hstep' - _ < 2 ^ 1193 * (evTree x : Int) + 2 * 2 ^ 1193 + 2 ^ 1193 := by linarith [hg2hi'] - _ = 2 ^ 1193 * (evTree x : Int) + 3 * 2 ^ 1193 := by ring + _ < 2 ^ 1193 * (evTree x : Int) + 1065041 * 2 ^ 1173 + 2 ^ 1193 := by linarith [hg2hi'] + _ = 2 ^ 1193 * (evTree x : Int) + 2113617 * 2 ^ 1173 := by + rw [show (2:Int) ^ 1193 = 2 ^ 20 * 2 ^ 1173 from by rw [← pow_add]]; ring /-- **The odd cert polynomial brackets the runtime odd accumulator** (gap-2 ∘ v-truncation): -`2¹⁰⁴²·odTree x ≤ evalPoly odNumVPoly t < 2¹⁰⁴²·odTree x + 3·2¹⁰⁴²`. -/ +`2¹⁰⁴²·odTree x ≤ evalPoly odNumVPoly t < 2¹⁰⁴²·odTree x + 134414369·2¹⁰¹⁶` (the fractional gap-2 +width `67305505·2¹⁰¹⁶` plus one v-step `2¹⁰⁴² = 2²⁶·2¹⁰¹⁶`, summing to `≈ 1.003·2¹⁰⁴²`). -/ theorem odNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : 2 ^ 1042 * (odTree x : Int) ≤ evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) ∧ - evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) < 2 ^ 1042 * (odTree x : Int) + 3 * 2 ^ 1042 := by + evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) < + 2 ^ 1042 * (odTree x : Int) + 134414369 * 2 ^ 1016 := by obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 obtain ⟨hg2lo, hg2hi⟩ := odTree_bracket hvlt obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 @@ -225,9 +231,9 @@ theorem odNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) have h : (2 ^ 530 * odTree x : Nat) ≤ odNumV (vTree x) := hg2lo have : (2 ^ 530 * odTree x : Int) ≤ (odNumV (vTree x) : Int) := by exact_mod_cast h nlinarith [this] - have hg2hi' : (odNumV (vTree x) : Int) * 2 ^ 512 < 2 ^ 1042 * (odTree x : Int) + 2 * 2 ^ 1042 := by - have h : odNumV (vTree x) < 2 ^ 530 * odTree x + 2 * 2 ^ 530 := hg2hi - have : (odNumV (vTree x) : Int) < (2 ^ 530 * odTree x + 2 * 2 ^ 530 : Nat) := by exact_mod_cast h + have hg2hi' : (odNumV (vTree x) : Int) * 2 ^ 512 < 2 ^ 1042 * (odTree x : Int) + 67305505 * 2 ^ 1016 := by + have h : odNumV (vTree x) < 2 ^ 530 * odTree x + 67305505 * 2 ^ 504 := hg2hi + have : (odNumV (vTree x) : Int) < (2 ^ 530 * odTree x + 67305505 * 2 ^ 504 : Nat) := by exact_mod_cast h push_cast at this; nlinarith [this] have hstep := odNumV_step hvlt have hstep' : (odNumV (vTree x + 1) : Int) * 2 ^ 512 < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1042 := by @@ -235,8 +241,9 @@ theorem odNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) refine ⟨le_trans hg2lo' hmono_lo, ?_⟩ calc evalPoly Pod (t ^ 2) ≤ (odNumV (vTree x + 1) : Int) * 2 ^ 512 := hmono_hi _ < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1042 := hstep' - _ < 2 ^ 1042 * (odTree x : Int) + 2 * 2 ^ 1042 + 2 ^ 1042 := by linarith [hg2hi'] - _ = 2 ^ 1042 * (odTree x : Int) + 3 * 2 ^ 1042 := by ring + _ < 2 ^ 1042 * (odTree x : Int) + 67305505 * 2 ^ 1016 + 2 ^ 1042 := by linarith [hg2hi'] + _ = 2 ^ 1042 * (odTree x : Int) + 134414369 * 2 ^ 1016 := by + rw [show (2:Int) ^ 1042 = 2 ^ 26 * 2 ^ 1016 from by rw [← pow_add]]; ring /-! ## The `t·Od` term and the numerator/denominator brackets (nonnegative half `t ≥ 0`) -/ @@ -297,7 +304,7 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) -- multiply odd bracket by t·2^23 (t ≥ 0): have hmul_lo : t * (2 ^ 1042 * (odTree x : Int)) ≤ t * evalPoly ExpCertV.odNumVPoly t := mul_le_mul_of_nonneg_left hodlo htnn - have hmul_hi : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int) + 3 * 2 ^ 1042) := + have hmul_hi : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int) + 134414369 * 2 ^ 1016) := mul_le_mul_of_nonneg_left (le_of_lt hodhi) htnn -- tod·2^128 ≤ t·odTree and t·odTree < tod·2^128 + 2^128 have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo @@ -313,9 +320,8 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) calc 2 ^ 1193 * (int256 (todTree x)) ≤ 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int))) := key _ ≤ 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := mul_le_mul_of_nonneg_left hmul_lo (by positivity) - · -- 2^23·(t·odpoly) < 2^1193·tod + 2^5·2^1193 - -- t·odpoly ≤ t·(2^1042·odTree + 3·2^1042) = 2^1042·(t·odTree) + 3·2^1042·t - -- t·odTree < 2^128·tod + 2^128. t < 2^128 (|t| < H128 < 2^128). + · -- 2^23·(t·odpoly) < 2^1193·tod + 4·2^1193 (the tight odd width 134414369·2^1016·t stays well under) + -- t·odpoly ≤ 2^1042·(t·odTree) + 134414369·2^1016·t, t·odTree < 2^128·tod + 2^128, t < 2^128. obtain ⟨htlo', hthi'⟩ := tTree_bound hx hC hC0 have htlt : t < 2 ^ 128 := by have : t < 2 ^ 127 := by rw [show ((2:Int)^127) = 170141183460469231731687303715884105728 from by norm_num]; exact hthi' @@ -323,10 +329,25 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) omega have key : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) < 2 ^ 1193 * (int256 (todTree x)) + 4 * 2 ^ 1193 := by - have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ 2 ^ 1042 * (t * (odTree x : Int)) + 3 * 2 ^ 1042 * t := by + have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ + 2 ^ 1042 * (t * (odTree x : Int)) + 134414369 * 2 ^ 1016 * t := by nlinarith [hmul_hi] have h2 : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htod_hi - nlinarith [h1, h2, htlt, htnn, mul_nonneg htnn hodnn] + -- 2^23·134414369·2^1016·t < 134414369·2^1167 < 3·2^1193 (t < 2^128, 134414369 < 3·2^26) + have hpow : (134414369 : Int) * 2 ^ 1167 < 3 * 2 ^ 1193 := by + have he : (3:Int) * 2 ^ 1193 = (3 * 2 ^ 26) * 2 ^ 1167 := by + rw [show (3:Int) * 2 ^ 26 * 2 ^ 1167 = 3 * (2 ^ 26 * 2 ^ 1167) from by ring, + show (2:Int) ^ 26 * 2 ^ 1167 = 2 ^ (26 + 1167) from by rw [← pow_add], + show (26:Nat) + 1167 = 1193 from by norm_num] + rw [he] + have : (134414369 : Int) < 3 * 2 ^ 26 := by norm_num + nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1167, this] + have hcarry : (2:Int) ^ 23 * (134414369 * 2 ^ 1016 * t) ≤ 134414369 * 2 ^ 1167 := by + have ht : (2:Int) ^ 23 * (134414369 * 2 ^ 1016 * t) = 134414369 * 2 ^ 1039 * t := by + rw [show (2:Int) ^ 1039 = 2 ^ 23 * 2 ^ 1016 from by rw [← pow_add]]; ring + rw [ht, show (2:Int) ^ 1167 = 2 ^ 1039 * 2 ^ 128 from by rw [← pow_add]] + nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1039, htlt, htnn] + nlinarith [h1, h2, htlt, htnn, mul_nonneg htnn hodnn, hcarry, hpow] exact key /-! ## The numerator/denominator cert brackets and the `r0`-vs-`ê_v` bracket -/ @@ -576,7 +597,7 @@ theorem todNumV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) -- multiply odd bracket by t ≤ 0 (flips): have hmul_lo : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int)) := mul_le_mul_of_nonpos_left hodlo htneg - have hmul_hi : t * (2 ^ 1042 * (odTree x : Int) + 3 * 2 ^ 1042) ≤ t * evalPoly ExpCertV.odNumVPoly t := + have hmul_hi : t * (2 ^ 1042 * (odTree x : Int) + 134414369 * 2 ^ 1016) ≤ t * evalPoly ExpCertV.odNumVPoly t := mul_le_mul_of_nonpos_left (le_of_lt hodhi) htneg have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi @@ -585,12 +606,24 @@ theorem todNumV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) have h2 : -(2:Int)^128 < -(2:Int)^127 := by norm_num omega constructor - · -- todNumV = 2^23·(t·odpoly) > 2^23·(t·(2^1042 odTree + 3·2^1042)) (since hmul_hi gives ≥) - -- = 2^1065·(t·odTree) + 3·2^1065·t ≥ 2^1193·tod + 3·2^1065·t > 2^1193·tod - 3·2^1193 - have h1 : 2 ^ 1042 * (t * (odTree x : Int)) + 3 * 2 ^ 1042 * t ≤ t * evalPoly ExpCertV.odNumVPoly t := by - nlinarith [hmul_hi] + · -- todNumV = 2^23·(t·odpoly) ≥ 2^1065·(t·odTree) + 134414369·2^1039·t (since t ≤ 0, the odd width + -- contributes a negative shift) ≥ 2^1193·tod − 134414369·2^1167/... > 2^1193·tod − 4·2^1193 + have h1 : 2 ^ 1042 * (t * (odTree x : Int)) + 134414369 * 2 ^ 1016 * t ≤ + t * evalPoly ExpCertV.odNumVPoly t := by nlinarith [hmul_hi] have h2 : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htod_lo - nlinarith [h1, h2, htgt] + -- 2^23·134414369·2^1016·t > -134414369·2^1167 > -3·2^1193 (t > -2^128) + have hcarry : -(134414369 * 2 ^ 1167 : Int) < (2:Int) ^ 23 * (134414369 * 2 ^ 1016 * t) := by + have ht : (2:Int) ^ 23 * (134414369 * 2 ^ 1016 * t) = 134414369 * 2 ^ 1039 * t := by + rw [show (2:Int) ^ 1039 = 2 ^ 23 * 2 ^ 1016 from by rw [← pow_add]]; ring + rw [ht, show (134414369 : Int) * 2 ^ 1167 = 134414369 * 2 ^ 1039 * 2 ^ 128 from by + rw [show (2:Int) ^ 1167 = 2 ^ 1039 * 2 ^ 128 from by rw [← pow_add]]; ring] + nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1039, htgt] + have hpow : -(134414369 * 2 ^ 1167 : Int) ≥ -(3 * 2 ^ 1193) := by + rw [ge_iff_le, neg_le_neg_iff, show (3:Int) * 2 ^ 1193 = (3 * 2 ^ 26) * 2 ^ 1167 from by + rw [show (2:Int) ^ 1193 = 2 ^ 26 * 2 ^ 1167 from by rw [← pow_add]]; ring] + have : (134414369 : Int) ≤ 3 * 2 ^ 26 := by norm_num + nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1167, this] + nlinarith [h1, h2, htgt, hcarry, hpow] · -- todNumV = 2^23·(t·odpoly) ≤ 2^23·(t·2^1042 odTree) = 2^1065·(t·odTree) < 2^1193·tod + 2^1193 have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ 2 ^ 1042 * (t * (odTree x : Int)) := by nlinarith [hmul_lo] From 2b0a9cf5cb9c3abdec25d7b2c2642634ad856aa4 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 18:17:43 +0200 Subject: [PATCH 073/149] Tighten the exp v-step bound to feed the joint over budget Bound the runtime-vs-cert v-truncation step evNumV(v+1)-evNumV(v) by 2^549 (even) / 2^525 (odd), shrinking the evNumVPoly/odNumVPoly bracket widths to 1130577*2^1173 (~1.078*2^1193) and 69402657*2^1016 (~1.003*2^1042), the tight even-truncation envelope the joint Cr cross-product needs. The loose downstream chain is preserved. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 88 ++++++++++--------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 5cf45daea..b421cff72 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -125,9 +125,11 @@ theorem Pev_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : theorem Pod_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : evalPoly Pod a ≤ evalPoly Pod b := evalPoly_mono_of_nonneg Pod_coeffs_nonneg ha hab -/-- One `v`-step of the even Horner polynomial is below `2⁵⁵³` for `v < 2¹²⁶`. -/ +/-- One `v`-step of the even Horner polynomial is below `2⁵⁴⁹ = 2⁵⁵³/16` for `v < 2¹²⁶` (the step is +`≈ 0.036·2⁵⁵³` at the band top; the dyadic `2⁵⁴⁹` leaves comfortable headroom). The tightness here +feeds the joint `over` budget. -/ theorem evNumV_step {v : Nat} (hv : v < 2 ^ 126) : - (evNumV (v + 1) : Int) - (evNumV v : Int) < 2 ^ 553 := by + (evNumV (v + 1) : Int) - (evNumV v : Int) < 2 ^ 549 := by unfold evNumV push_cast have hvle : (v : Int) < 2 ^ 126 := by exact_mod_cast hv @@ -135,9 +137,9 @@ theorem evNumV_step {v : Nat} (hv : v < 2 ^ 126) : nlinarith [hvle, hvnn, mul_nonneg hvnn hvnn, Int.mul_nonneg hvnn (Int.mul_nonneg hvnn hvnn), Int.mul_nonneg (Int.mul_nonneg hvnn hvnn) (Int.mul_nonneg hvnn hvnn)] -/-- One `v`-step of the odd Horner polynomial is below `2⁵³⁰` for `v < 2¹²⁶`. -/ +/-- One `v`-step of the odd Horner polynomial is below `2⁵²⁵ = 2⁵³⁰/32` for `v < 2¹²⁶`. -/ theorem odNumV_step {v : Nat} (hv : v < 2 ^ 126) : - (odNumV (v + 1) : Int) - (odNumV v : Int) < 2 ^ 530 := by + (odNumV (v + 1) : Int) - (odNumV v : Int) < 2 ^ 525 := by unfold odNumV push_cast have hvle : (v : Int) < 2 ^ 126 := by exact_mod_cast hv @@ -162,13 +164,13 @@ theorem tsq_split {x : Nat} (hx : x < 2 ^ 256) · nlinarith [hdm, hmod_lt] /-- **The even cert polynomial brackets the runtime even accumulator** (gap-2 ∘ v-truncation): -`2¹¹⁹³·evTree x ≤ evalPoly evNumVPoly t < 2¹¹⁹³·evTree x + 2113617·2¹¹⁷³` (the fractional gap-2 width -`1065041·2¹¹⁷³` plus one v-step `2¹¹⁹³ = 2²⁰·2¹¹⁷³`, summing to `2113617·2¹¹⁷³ ≈ 2.0157·2¹¹⁹³`). -/ +`2¹¹⁹³·evTree x ≤ evalPoly evNumVPoly t < 2¹¹⁹³·evTree x + 1130577·2¹¹⁷³` (the fractional gap-2 width +`1065041·2¹¹⁷³` plus one tight v-step `2¹¹⁸⁹ = 2¹⁶·2¹¹⁷³`, summing to `1130577·2¹¹⁷³ ≈ 1.078·2¹¹⁹³`). -/ theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : 2 ^ 1193 * (evTree x : Int) ≤ evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) ∧ evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) < - 2 ^ 1193 * (evTree x : Int) + 2113617 * 2 ^ 1173 := by + 2 ^ 1193 * (evTree x : Int) + 1130577 * 2 ^ 1173 := by obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 obtain ⟨hg2lo, hg2hi⟩ := evTree_bracket hvlt obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 @@ -194,25 +196,26 @@ theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) have h : evNumV (vTree x) < 2 ^ 553 * evTree x + 1065041 * 2 ^ 533 := hg2hi have : (evNumV (vTree x) : Int) < (2 ^ 553 * evTree x + 1065041 * 2 ^ 533 : Nat) := by exact_mod_cast h push_cast at this; nlinarith [this] - -- step bound: evNumV(vTree+1)·2^640 < evNumV(vTree)·2^640 + 2^1193 + -- tight v-step: evNumV(vTree+1)·2^640 < evNumV(vTree)·2^640 + 2^549·2^640 = … + 2^1189 have hstep := evNumV_step hvlt - have hstep' : (evNumV (vTree x + 1) : Int) * 2 ^ 640 < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1193 := by - nlinarith [hstep] + have hstep' : (evNumV (vTree x + 1) : Int) * 2 ^ 640 < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1189 := by + have he : (2:Int) ^ 1189 = 2 ^ 549 * 2 ^ 640 := by rw [← pow_add] + rw [he]; nlinarith [hstep, pow_pos (by norm_num : (0:Int) < 2) 640] refine ⟨le_trans hg2lo' hmono_lo, ?_⟩ calc evalPoly Pev (t ^ 2) ≤ (evNumV (vTree x + 1) : Int) * 2 ^ 640 := hmono_hi - _ < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1193 := hstep' - _ < 2 ^ 1193 * (evTree x : Int) + 1065041 * 2 ^ 1173 + 2 ^ 1193 := by linarith [hg2hi'] - _ = 2 ^ 1193 * (evTree x : Int) + 2113617 * 2 ^ 1173 := by - rw [show (2:Int) ^ 1193 = 2 ^ 20 * 2 ^ 1173 from by rw [← pow_add]]; ring + _ < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1189 := hstep' + _ < 2 ^ 1193 * (evTree x : Int) + 1065041 * 2 ^ 1173 + 2 ^ 1189 := by linarith [hg2hi'] + _ = 2 ^ 1193 * (evTree x : Int) + 1130577 * 2 ^ 1173 := by + rw [show (2:Int) ^ 1189 = 2 ^ 16 * 2 ^ 1173 from by rw [← pow_add]]; ring /-- **The odd cert polynomial brackets the runtime odd accumulator** (gap-2 ∘ v-truncation): -`2¹⁰⁴²·odTree x ≤ evalPoly odNumVPoly t < 2¹⁰⁴²·odTree x + 134414369·2¹⁰¹⁶` (the fractional gap-2 -width `67305505·2¹⁰¹⁶` plus one v-step `2¹⁰⁴² = 2²⁶·2¹⁰¹⁶`, summing to `≈ 1.003·2¹⁰⁴²`). -/ +`2¹⁰⁴²·odTree x ≤ evalPoly odNumVPoly t < 2¹⁰⁴²·odTree x + 69402657·2¹⁰¹⁶` (the fractional gap-2 +width `67305505·2¹⁰¹⁶` plus one tight v-step `2¹⁰³⁷ = 2²¹·2¹⁰¹⁶`, summing to `≈ 1.003·2¹⁰⁴²`). -/ theorem odNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : 2 ^ 1042 * (odTree x : Int) ≤ evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) ∧ evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) < - 2 ^ 1042 * (odTree x : Int) + 134414369 * 2 ^ 1016 := by + 2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016 := by obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 obtain ⟨hg2lo, hg2hi⟩ := odTree_bracket hvlt obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 @@ -236,14 +239,15 @@ theorem odNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) have : (odNumV (vTree x) : Int) < (2 ^ 530 * odTree x + 67305505 * 2 ^ 504 : Nat) := by exact_mod_cast h push_cast at this; nlinarith [this] have hstep := odNumV_step hvlt - have hstep' : (odNumV (vTree x + 1) : Int) * 2 ^ 512 < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1042 := by - nlinarith [hstep] + have hstep' : (odNumV (vTree x + 1) : Int) * 2 ^ 512 < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1037 := by + have he : (2:Int) ^ 1037 = 2 ^ 525 * 2 ^ 512 := by rw [← pow_add] + rw [he]; nlinarith [hstep, pow_pos (by norm_num : (0:Int) < 2) 512] refine ⟨le_trans hg2lo' hmono_lo, ?_⟩ calc evalPoly Pod (t ^ 2) ≤ (odNumV (vTree x + 1) : Int) * 2 ^ 512 := hmono_hi - _ < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1042 := hstep' - _ < 2 ^ 1042 * (odTree x : Int) + 67305505 * 2 ^ 1016 + 2 ^ 1042 := by linarith [hg2hi'] - _ = 2 ^ 1042 * (odTree x : Int) + 134414369 * 2 ^ 1016 := by - rw [show (2:Int) ^ 1042 = 2 ^ 26 * 2 ^ 1016 from by rw [← pow_add]]; ring + _ < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1037 := hstep' + _ < 2 ^ 1042 * (odTree x : Int) + 67305505 * 2 ^ 1016 + 2 ^ 1037 := by linarith [hg2hi'] + _ = 2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016 := by + rw [show (2:Int) ^ 1037 = 2 ^ 21 * 2 ^ 1016 from by rw [← pow_add]]; ring /-! ## The `t·Od` term and the numerator/denominator brackets (nonnegative half `t ≥ 0`) -/ @@ -304,7 +308,7 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) -- multiply odd bracket by t·2^23 (t ≥ 0): have hmul_lo : t * (2 ^ 1042 * (odTree x : Int)) ≤ t * evalPoly ExpCertV.odNumVPoly t := mul_le_mul_of_nonneg_left hodlo htnn - have hmul_hi : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int) + 134414369 * 2 ^ 1016) := + have hmul_hi : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016) := mul_le_mul_of_nonneg_left (le_of_lt hodhi) htnn -- tod·2^128 ≤ t·odTree and t·odTree < tod·2^128 + 2^128 have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo @@ -320,8 +324,8 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) calc 2 ^ 1193 * (int256 (todTree x)) ≤ 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int))) := key _ ≤ 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := mul_le_mul_of_nonneg_left hmul_lo (by positivity) - · -- 2^23·(t·odpoly) < 2^1193·tod + 4·2^1193 (the tight odd width 134414369·2^1016·t stays well under) - -- t·odpoly ≤ 2^1042·(t·odTree) + 134414369·2^1016·t, t·odTree < 2^128·tod + 2^128, t < 2^128. + · -- 2^23·(t·odpoly) < 2^1193·tod + 4·2^1193 (the tight odd width 69402657·2^1016·t stays well under) + -- t·odpoly ≤ 2^1042·(t·odTree) + 69402657·2^1016·t, t·odTree < 2^128·tod + 2^128, t < 2^128. obtain ⟨htlo', hthi'⟩ := tTree_bound hx hC hC0 have htlt : t < 2 ^ 128 := by have : t < 2 ^ 127 := by rw [show ((2:Int)^127) = 170141183460469231731687303715884105728 from by norm_num]; exact hthi' @@ -330,20 +334,20 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) have key : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) < 2 ^ 1193 * (int256 (todTree x)) + 4 * 2 ^ 1193 := by have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ - 2 ^ 1042 * (t * (odTree x : Int)) + 134414369 * 2 ^ 1016 * t := by + 2 ^ 1042 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1016 * t := by nlinarith [hmul_hi] have h2 : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htod_hi - -- 2^23·134414369·2^1016·t < 134414369·2^1167 < 3·2^1193 (t < 2^128, 134414369 < 3·2^26) - have hpow : (134414369 : Int) * 2 ^ 1167 < 3 * 2 ^ 1193 := by + -- 2^23·69402657·2^1016·t < 69402657·2^1167 < 3·2^1193 (t < 2^128, 69402657 < 3·2^26) + have hpow : (69402657 : Int) * 2 ^ 1167 < 3 * 2 ^ 1193 := by have he : (3:Int) * 2 ^ 1193 = (3 * 2 ^ 26) * 2 ^ 1167 := by rw [show (3:Int) * 2 ^ 26 * 2 ^ 1167 = 3 * (2 ^ 26 * 2 ^ 1167) from by ring, show (2:Int) ^ 26 * 2 ^ 1167 = 2 ^ (26 + 1167) from by rw [← pow_add], show (26:Nat) + 1167 = 1193 from by norm_num] rw [he] - have : (134414369 : Int) < 3 * 2 ^ 26 := by norm_num + have : (69402657 : Int) < 3 * 2 ^ 26 := by norm_num nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1167, this] - have hcarry : (2:Int) ^ 23 * (134414369 * 2 ^ 1016 * t) ≤ 134414369 * 2 ^ 1167 := by - have ht : (2:Int) ^ 23 * (134414369 * 2 ^ 1016 * t) = 134414369 * 2 ^ 1039 * t := by + have hcarry : (2:Int) ^ 23 * (69402657 * 2 ^ 1016 * t) ≤ 69402657 * 2 ^ 1167 := by + have ht : (2:Int) ^ 23 * (69402657 * 2 ^ 1016 * t) = 69402657 * 2 ^ 1039 * t := by rw [show (2:Int) ^ 1039 = 2 ^ 23 * 2 ^ 1016 from by rw [← pow_add]]; ring rw [ht, show (2:Int) ^ 1167 = 2 ^ 1039 * 2 ^ 128 from by rw [← pow_add]] nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1039, htlt, htnn] @@ -597,7 +601,7 @@ theorem todNumV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) -- multiply odd bracket by t ≤ 0 (flips): have hmul_lo : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int)) := mul_le_mul_of_nonpos_left hodlo htneg - have hmul_hi : t * (2 ^ 1042 * (odTree x : Int) + 134414369 * 2 ^ 1016) ≤ t * evalPoly ExpCertV.odNumVPoly t := + have hmul_hi : t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016) ≤ t * evalPoly ExpCertV.odNumVPoly t := mul_le_mul_of_nonpos_left (le_of_lt hodhi) htneg have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi @@ -606,22 +610,22 @@ theorem todNumV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) have h2 : -(2:Int)^128 < -(2:Int)^127 := by norm_num omega constructor - · -- todNumV = 2^23·(t·odpoly) ≥ 2^1065·(t·odTree) + 134414369·2^1039·t (since t ≤ 0, the odd width - -- contributes a negative shift) ≥ 2^1193·tod − 134414369·2^1167/... > 2^1193·tod − 4·2^1193 - have h1 : 2 ^ 1042 * (t * (odTree x : Int)) + 134414369 * 2 ^ 1016 * t ≤ + · -- todNumV = 2^23·(t·odpoly) ≥ 2^1065·(t·odTree) + 69402657·2^1039·t (since t ≤ 0, the odd width + -- contributes a negative shift) ≥ 2^1193·tod − 69402657·2^1167/... > 2^1193·tod − 4·2^1193 + have h1 : 2 ^ 1042 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1016 * t ≤ t * evalPoly ExpCertV.odNumVPoly t := by nlinarith [hmul_hi] have h2 : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htod_lo - -- 2^23·134414369·2^1016·t > -134414369·2^1167 > -3·2^1193 (t > -2^128) - have hcarry : -(134414369 * 2 ^ 1167 : Int) < (2:Int) ^ 23 * (134414369 * 2 ^ 1016 * t) := by - have ht : (2:Int) ^ 23 * (134414369 * 2 ^ 1016 * t) = 134414369 * 2 ^ 1039 * t := by + -- 2^23·69402657·2^1016·t > -69402657·2^1167 > -3·2^1193 (t > -2^128) + have hcarry : -(69402657 * 2 ^ 1167 : Int) < (2:Int) ^ 23 * (69402657 * 2 ^ 1016 * t) := by + have ht : (2:Int) ^ 23 * (69402657 * 2 ^ 1016 * t) = 69402657 * 2 ^ 1039 * t := by rw [show (2:Int) ^ 1039 = 2 ^ 23 * 2 ^ 1016 from by rw [← pow_add]]; ring - rw [ht, show (134414369 : Int) * 2 ^ 1167 = 134414369 * 2 ^ 1039 * 2 ^ 128 from by + rw [ht, show (69402657 : Int) * 2 ^ 1167 = 69402657 * 2 ^ 1039 * 2 ^ 128 from by rw [show (2:Int) ^ 1167 = 2 ^ 1039 * 2 ^ 128 from by rw [← pow_add]]; ring] nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1039, htgt] - have hpow : -(134414369 * 2 ^ 1167 : Int) ≥ -(3 * 2 ^ 1193) := by + have hpow : -(69402657 * 2 ^ 1167 : Int) ≥ -(3 * 2 ^ 1193) := by rw [ge_iff_le, neg_le_neg_iff, show (3:Int) * 2 ^ 1193 = (3 * 2 ^ 26) * 2 ^ 1167 from by rw [show (2:Int) ^ 1193 = 2 ^ 26 * 2 ^ 1167 from by rw [← pow_add]]; ring] - have : (134414369 : Int) ≤ 3 * 2 ^ 26 := by norm_num + have : (69402657 : Int) ≤ 3 * 2 ^ 26 := by norm_num nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1167, this] nlinarith [h1, h2, htgt, hcarry, hpow] · -- todNumV = 2^23·(t·odpoly) ≤ 2^23·(t·2^1042 odTree) = 2^1065·(t·odTree) < 2^1193·tod + 2^1193 From 8ab5c665f55c0192fbad0e9e704703c72a6cff46 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:52:50 +0200 Subject: [PATCH 074/149] Prove the exp joint per-point never-over (nonneg half) within the margin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit r0_real_over_tight: r0 ≤ 2^126·exp(rt) + 19/25 for t ≥ 0, meeting the MARGIN/WAD = 0.792 budget (19/25 = 0.76 < 0.792161). The shared even truncation cancels via the sdiv floor (r0·DE − 2^126·NE ≤ W_ev·(r0−2^126)), with ê ≤ √2, den ≥ 0.72·2^126 (ev ≥ A4, tod < 2^125), and the tight one-sided gap-1 reducedArg_close_over (P3 ≥ 0). Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 336 +++++++++++++++++- .../exp/ExpProof/ExpProof/Floor/Reduce.lean | 139 ++++++++ 2 files changed, 470 insertions(+), 5 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index b421cff72..11018b69a 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -125,6 +125,11 @@ theorem Pev_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : theorem Pod_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : evalPoly Pod a ≤ evalPoly Pod b := evalPoly_mono_of_nonneg Pod_coeffs_nonneg ha hab +/-- The odd cert polynomial `odNumVPoly` is nonnegative everywhere (`= Pod(t²)`, nonneg coeffs). -/ +theorem odNumVPoly_nonneg (t : Int) : 0 ≤ evalPoly ExpCertV.odNumVPoly t := by + rw [odNumVPoly_eq_Pod_sq] + exact evalPoly_nonneg_of_nonneg Pod_coeffs_nonneg (by positivity) + /-- One `v`-step of the even Horner polynomial is below `2⁵⁴⁹ = 2⁵⁵³/16` for `v < 2¹²⁶` (the step is `≈ 0.036·2⁵⁵³` at the band top; the dyadic `2⁵⁴⁹` leaves comfortable headroom). The tightness here feeds the joint `over` budget. -/ @@ -576,6 +581,73 @@ theorem r0_vs_certRatio {x : Nat} (hx : x < 2 ^ 256) · nlinarith [hfl_lo, hnumstep, hr0den_lo, hr0_loss, hDEpos, hp1193] · nlinarith [hfl_hi, hNEstep, hr0den_hi, hunder_loss, hDEpos, hp1193] +-- Joint cert-ratio over: r0·DE − 2^126·NE ≤ W_ev_int·(r0−2^126), W_ev_int = 1130577·2^1173. +-- evP = evalPoly evNumVPoly t, NE = evP + todP, DE = evP − todP. Ee = evP − 2^1193·ev ∈ [0,W_ev). +-- todP ≥ 2^1193·tod. Floor: r0·den ≤ 2^126·num. +theorem r0_certRatio_over_tight {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) (hr0ge : (2:Int)^126 ≤ int256 (r0Tree x)) : + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) - + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) ≤ + 1130577 * 2 ^ 1173 * (int256 (r0Tree x) - 2 ^ 126) := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 + obtain ⟨htodlo, _⟩ := todNumV_bracket hx hC hC0 htnn + rw [evalNumExpV, evalDenExpV] + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set evP := evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) with hevP + set todP := evalPoly ExpCertV.todNumV (int256 (tTree x)) with htodP + -- r0·(evP−todP) − 2^126·(evP+todP) = evP·(r0−2^126) − todP·(r0+2^126) + -- ≤ (2^1193·ev + W_ev)·(r0−2^126) − 2^1193·tod·(r0+2^126) + -- [evP ≤ 2^1193 ev + W_ev (hevhi), r0−2^126≥0; todP ≥ 2^1193 tod (htodlo), -(·)(r0+2^126)≤0] + -- = 2^1193·[ev(r0−2^126) − tod(r0+2^126)] + W_ev·(r0−2^126) + -- = 2^1193·[(ev−tod)·r0 − 2^126·(ev+tod)] + W_ev·(r0−2^126) + -- = 2^1193·[den·r0 − 2^126·num] + W_ev·(r0−2^126) ≤ 0 + W_ev·(r0−2^126) [floor] + have hr0m : (0:Int) ≤ r0 - 2^126 := by linarith [hr0ge] + have hr0p : (0:Int) ≤ r0 + 2^126 := by linarith [hr0ge] + -- evP ≤ 2^1193 ev + W_ev + have hWev : evP ≤ 2^1193 * ev + 1130577 * 2^1173 := le_of_lt hevhi + -- bound the two terms + have hterm1 : evP * (r0 - 2^126) ≤ (2^1193 * ev + 1130577 * 2^1173) * (r0 - 2^126) := + mul_le_mul_of_nonneg_right hWev hr0m + have hterm2 : 2^1193 * tod * (r0 + 2^126) ≤ todP * (r0 + 2^126) := + mul_le_mul_of_nonneg_right htodlo hr0p + -- floor: r0·den ≤ 2^126·num, i.e. den·r0 - 2^126·num ≤ 0 (den=ev-tod, num=ev+tod) + have hfloor : r0 * (ev - tod) - 2^126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + -- assemble: 2^1193·(den·r0 − 2^126·num) ≤ 0 + have hfloor1193 : (2:Int)^1193 * (r0 * (ev - tod) - 2^126 * (ev + tod)) ≤ 0 := + mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor + nlinarith [hterm1, hterm2, hfloor1193] + +-- For r0 ≤ 2^126 the cert-ratio over is ≤ 0: evP·(r0−2^126) ≤ 0 and todP ≥ 0. +theorem r0_certRatio_over_small {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) (hr0le : int256 (r0Tree x) ≤ (2:Int)^126) : + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) - + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) ≤ 0 := by + rw [evalNumExpV, evalDenExpV] + set r0 := int256 (r0Tree x) with hr0def + set evP := evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) with hevP + set todP := evalPoly ExpCertV.todNumV (int256 (tTree x)) with htodP + -- evP ≥ 0, todP ≥ 0 (nonneg half), r0−2^126 ≤ 0, r0+2^126 ≥ 0 + have hevPnn : (0:Int) ≤ evP := by + obtain ⟨hlo, _⟩ := evNumVPoly_bracket hx hC hC0 + have : (0:Int) ≤ 2^1193 * (evTree x : Int) := by positivity + linarith [hlo, this] + have htodPnn : (0:Int) ≤ todP := by + rw [htodP, evalTodNumV] + exact mul_nonneg (by positivity) (mul_nonneg htnn (odNumVPoly_nonneg _)) + have hr0nn : (0:Int) ≤ r0 := by obtain ⟨hlo, _⟩ := r0Tree_bounds hx hC hC0; linarith [hlo] + have hr0m : r0 - 2^126 ≤ 0 := by linarith [hr0le] + have hr0p : (0:Int) ≤ r0 + 2^126 := by positivity + -- r0·(evP−todP) − 2^126·(evP+todP) = evP·(r0−2^126) − todP·(r0+2^126) ≤ 0 + have h1 : evP * (r0 - 2^126) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos hevPnn hr0m + have h2 : 0 ≤ todP * (r0 + 2^126) := mul_nonneg htodPnn hr0p + nlinarith [h1, h2] + + /-! ## The negative-half integer brackets For `t < 0` the runtime `tod = ⌊t·od/2¹²⁸⌋` is nonpositive, so the `t·Od` cert term `todNumV(t)` @@ -907,11 +979,6 @@ For `t ≤ 0` (with `−t ∈ [0, H128]`) the cert at `u = −t`, composed with margin-nudged rational `NE(t)/DE(t)` — the over side needs `NE/DE ≤ exp·(2¹³⁰+1)/2¹³⁰`, the under side `exp ≤ (NE/DE)·2¹³⁰/(2¹³⁰−1)`. The cert denominators `NE(t)`, `DE(t)` are positive. -/ -/-- The odd cert polynomial `odNumVPoly` is nonnegative everywhere (`= Pod(t²)`, nonneg coeffs). -/ -theorem odNumVPoly_nonneg (t : Int) : 0 ≤ evalPoly ExpCertV.odNumVPoly t := by - rw [odNumVPoly_eq_Pod_sq] - exact evalPoly_nonneg_of_nonneg Pod_coeffs_nonneg (by positivity) - /-- For `t ≤ 0` with `−t ∈ [0, H128]` the cert numerator/denominator at `t` are positive. -/ theorem certNE_pos_neg_aux {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : 0 < evalPoly ExpCertV.numExpV t ∧ 0 < evalPoly ExpCertV.denExpV t := by @@ -1072,6 +1139,265 @@ theorem exp_diff_le (a b : Real) : Real.exp b - Real.exp a ≤ (b - a) * Real.ex have hb : 0 < Real.exp b := Real.exp_pos b rw [key]; nlinarith [h1, hb] +/-! ## The tight joint per-point never-over (nonnegative half) -/ + +-- exp(t/2^128) ≤ √2 on the nonneg half. +theorem exp_t_le_sqrt2 {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) ≤ Real.sqrt 2 := by + have hle := t_over_2128_le_half_log2 hx hC hC0 htnn + calc Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) + ≤ Real.exp (Real.log 2 / 2) := Real.exp_le_exp.mpr hle + _ = Real.sqrt 2 := by + rw [Real.sqrt_eq_rpow, Real.rpow_def_of_pos (by norm_num : (0:Real) < 2)]; ring_nf + +-- den ≥ A4 − 2^125 (≈ 0.72·2^126): den = ev − tod, ev ≥ A4, tod < 2^125. +theorem den_ge_072 {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (61251667550081741634933722430035858604 : Int) ≤ + (evTree x : Int) - int256 (todTree x) := by + obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 + obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + have hev : (103786963415199049567855548359006885036 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + have ht125 : int256 (todTree x) < 2 ^ 125 := by + rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num]; exact htod_hi + rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 + omega + +/-- **The joint per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + 19/25` — within the +`MARGIN/WAD = 0.792` budget. Combines the joint cert-ratio over (the shared even truncation cancels +via the floor), `exp(t/2¹²⁸) ≤ √2`, `den ≥ 0.72·2¹²⁶`, and the tight one-sided gap-1. -/ +theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + set t := int256 (tTree x) with htdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + have hDElb := denExpV_lb hx hC hC0 htnn + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + have hNEnn : (0 : Real) ≤ (NE : Real) := by + have := certNE_nonneg htnn htdom; exact_mod_cast this + set r0 := int256 (r0Tree x) with hr0def + -- certLo: NE/DE ≤ Et·Mp, Mp = 2^130/(2^130−1); Et = exp(t/2^128) ≤ √2. + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + have hcertlo := certLo_real htnn htdom + set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn + rw [← hEtdef] at hEtsqrt2 + have hEtnn : (0 : Real) ≤ Et := le_of_lt (Real.exp_pos _) + have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by + have hc : ((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + rw [hMpdef] + have key : (NE : Real) / (DE : Real) = + ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) * + (((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real))) := by + push_cast; field_simp; ring + rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) + -- r0 ≤ 2^126·num/den (floor) + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hnumlo, _⟩ := numExpV_bracket hx hC hC0 htnn + obtain ⟨_, hdenhi⟩ := denExpV_bracket hx hC hC0 htnn + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ den := den_ge_072 hx hC hC0 + have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden072 + have hdenR : (0:Real) < (den : Real) := by exact_mod_cast hdenpos + have hden072R : (61251667550081741634933722430035858604 : Real) ≤ (den : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hden072; push_cast at this; linarith [this] + have hr0_le_numden : (r0 : Real) ≤ (2 ^ 126 : Real) * (num : Real) / (den : Real) := by + rw [le_div_iff₀ hdenR] + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hfloor_lo; push_cast at this; nlinarith [this] + -- bound num: 2^1193·num ≤ NE ≤ Et·Mp·DE ≤ √2·Mp·DE; DE < 2^1193·den + 3·2^1193 (denExpV hi) + have hnumloR : (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hnumlo; push_cast at this; linarith [this] + have hdenhiR : (DE : Real) < (2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193 := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hdenhi; push_cast at this; linarith [this] + have hMp_pos : (0:Real) < Mp := by rw [hMpdef]; positivity + -- NE ≤ √2·Mp·DE + have hNE_le : (NE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by + have h1 : (NE : Real) ≤ Et * Mp * (DE : Real) := by + have := mul_le_mul_of_nonneg_right hNEDE_le (le_of_lt hDEpos) + rwa [div_mul_cancel₀ _ (ne_of_gt hDEpos)] at this + have h2 : Et * Mp * (DE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by + apply mul_le_mul_of_nonneg_right _ (le_of_lt hDEpos) + exact mul_le_mul_of_nonneg_right hEtsqrt2 (le_of_lt hMp_pos) + linarith [h1, h2] + -- num ≤ √2·Mp·(den + 3) + have hnum_le : (num : Real) ≤ Real.sqrt 2 * Mp * ((den : Real) + 3) := by + have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity + rw [← mul_le_mul_left hp] + calc (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := hnumloR + _ ≤ Real.sqrt 2 * Mp * (DE : Real) := hNE_le + _ ≤ Real.sqrt 2 * Mp * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := by + apply mul_le_mul_of_nonneg_left (le_of_lt hdenhiR) + rw [hMpdef]; positivity + _ = (2 ^ 1193 : Real) * (Real.sqrt 2 * Mp * ((den : Real) + 3)) := by ring + -- √2 ≤ 14143/10000 (since (14143/10000)² > 2) + have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by + rw [Real.sqrt_le_iff]; constructor <;> norm_num + have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ + -- Mp ≤ 14143/10000 ⁻¹ ... we need √2·Mp ≤ 14144/10000 (a hair above √2; Mp = 1 + 1/(2^130−1)) + have hMp_le : Mp ≤ 14144 / 14143 := by + rw [hMpdef, div_le_div_iff₀ (by norm_num) (by norm_num)] + have h130 : (14144 : Real) ≤ 2 ^ 130 := by + rw [show (2:Real) ^ 130 = 1361129467683753853853498429727072845824 from by norm_num]; norm_num + nlinarith [h130] + -- √2·Mp ≤ 14144/10000 + have hsM_le : Real.sqrt 2 * Mp ≤ 14144 / 10000 := by + have hMpnn : (0:Real) ≤ Mp := by rw [hMpdef]; positivity + calc Real.sqrt 2 * Mp ≤ (14143 / 10000) * (14144 / 14143) := + mul_le_mul hsqrt2_val hMp_le hMpnn (by norm_num) + _ = 14144 / 10000 := by norm_num + -- (r0 − 2^126)·den ≤ 2^126·(num − den) ≤ 2^126·(√2·Mp·(den+3) − den) ≤ 2^126·(4145/10000)·den + have hr0_den : ((r0 : Real) - 2 ^ 126) * (den : Real) ≤ (2 ^ 126 : Real) * (4145 / 10000) * (den : Real) := by + -- floor (Real): r0·den ≤ 2^126·num + have hfl : (r0 : Real) * (den : Real) ≤ (2 ^ 126 : Real) * (num : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hfloor_lo; push_cast at this; linarith [this] + -- num ≤ √2·Mp·(den+3) ≤ (14144/10000)·(den+3) + have hnum2 : (num : Real) ≤ (14144 / 10000) * ((den : Real) + 3) := by + have hpos : (0:Real) ≤ (den : Real) + 3 := by linarith [hden072R] + calc (num : Real) ≤ Real.sqrt 2 * Mp * ((den : Real) + 3) := hnum_le + _ ≤ (14144 / 10000) * ((den : Real) + 3) := mul_le_mul_of_nonneg_right hsM_le hpos + -- (r0−2^126)·den = r0·den − 2^126·den ≤ 2^126·num − 2^126·den + have hstep1 : ((r0 : Real) - 2 ^ 126) * (den : Real) ≤ (2 ^ 126 : Real) * (num : Real) - 2 ^ 126 * (den : Real) := by + nlinarith [hfl] + -- 2^126·num ≤ 2^126·(14144/10000)·(den+3) (scale hnum2 by 2^126 > 0) + have hstep2 : (2 ^ 126 : Real) * (num : Real) ≤ (2 ^ 126 : Real) * ((14144 / 10000) * ((den : Real) + 3)) := + mul_le_mul_of_nonneg_left hnum2 (by positivity) + -- 2^126·(14144/10000·(den+3)) − 2^126·den ≤ 2^126·(4145/10000)·den ⟺ 42432 ≤ den (from den ≥ 0.72·2^126) + have hden42432 : (42432 : Real) ≤ (den : Real) := by + have h : (42432 : Real) ≤ 61251667550081741634933722430035858604 := by norm_num + linarith [hden072R, h] + nlinarith [hstep1, hstep2, hden42432, mul_pos (by norm_num : (0:Real) < 2^126) hdenR] + have hr0m_bound : (r0 : Real) - 2 ^ 126 ≤ (2 ^ 126 : Real) * 4145 / 10000 := by + have hkey : ((r0 : Real) - 2 ^ 126) * (den : Real) ≤ ((2 ^ 126 : Real) * 4145 / 10000) * (den : Real) := by + have : (2 ^ 126 : Real) * (4145 / 10000) * (den : Real) = ((2 ^ 126 : Real) * 4145 / 10000) * (den : Real) := by ring + linarith [hr0_den, this ▸ hr0_den] + exact le_of_mul_le_mul_right hkey hdenR + -- DE ≥ 2^1193·den − 32·2^1193 (denExpV lo bracket) + obtain ⟨hdenlo, _⟩ := denExpV_bracket hx hC hC0 htnn + have hDElo32 : (2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193 ≤ (DE : Real) := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hdenlo + push_cast at h + rw [hdendef, hDEdef]; push_cast; linarith [h] + -- cR term: W_ev·(r0−2^126)/DE ≤ 64/100 (provable ≈ 0.62) + have hr0m_nn : (0:Real) ≤ (r0 : Real) - 2 ^ 126 ∨ (r0 : Real) - 2 ^ 126 < 0 := le_or_gt _ _ |>.imp_left id + have hcR : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) ≤ 64 / 100 := by + rcases le_or_gt ((r0:Real) - 2^126) 0 with hle0 | hgt0 + · -- numerator ≤ 0, so the fraction ≤ 0 ≤ 64/100 + have hnumneg : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) ≤ 0 := + mul_nonpos_of_nonneg_of_nonpos (by positivity) hle0 + have : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) ≤ 0 := + div_nonpos_of_nonpos_of_nonneg hnumneg (le_of_lt hDEpos) + linarith [this] + · -- 0 < r0−2^126 ≤ 2^126·4145/10000; DE ≥ 2^1193(den−32) > 0 with den ≥ 0.72·2^126 + rw [div_le_iff₀ hDEpos] + -- W_ev·(r0−2^126) ≤ (64/100)·DE. W_ev = 1130577·2^1173. use DE ≥ 2^1193(den−32). + have hnum_le : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) ≤ + 1130577 * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) := + mul_le_mul_of_nonneg_left hr0m_bound (by positivity) + -- (64/100)·DE ≥ (64/100)·2^1193·(den−32); need W_ev·2^126·4145/10000 ≤ (64/100)·2^1193·(den−32) + have hbudget : (1130577 : Real) * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) ≤ + (64 / 100) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) := by + -- both sides are (·)·2^1193. LHS = (1130577·4145/10000·2^106)·2^1193; RHS = (64/100·(den−32))·2^1193 + have hLHS : (1130577 : Real) * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) = + (1130577 * 4145 / 10000 * 2 ^ 106) * 2 ^ 1193 := by + have e1 : (2:Real) ^ 1173 * 2 ^ 126 = 2 ^ 106 * 2 ^ 1193 := by + rw [← pow_add, ← pow_add] + linear_combination (1130577 * 4145 / 10000) * e1 + have hRHS : (64 / 100 : Real) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) = + (64 / 100 * ((den : Real) - 32)) * 2 ^ 1193 := by ring + rw [hLHS, hRHS] + have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity + rw [mul_le_mul_right hp] + have h106 : (1130577 * 4145 / 10000 * 2 ^ 106 : Real) ≤ + 64 / 100 * (61251667550081741634933722430035858604 - 32) := by + rw [show (2:Real) ^ 106 = 81129638414606681695789005144064 from by norm_num]; norm_num + nlinarith [h106, hden072R] + calc (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) + ≤ 1130577 * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) := hnum_le + _ ≤ (64 / 100) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) := hbudget + _ ≤ (64 / 100) * (DE : Real) := mul_le_mul_of_nonneg_left hDElo32 (by norm_num) + -- r0 ≤ 2^126·NE/DE + 64/100 (case-split: small ⟹ r0·DE ≤ 2^126·NE; big ⟹ joint + hcR) + have hr0_div : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 64 / 100 := by + rcases le_or_gt r0 (2^126) with hsm | hbg + · -- small: r0·DE ≤ 2^126·NE (r0_certRatio_over_small), so r0 ≤ 2^126·NE/DE ≤ … + 64/100 + have hi := r0_certRatio_over_small hx hC hC0 htnn hsm + have hiR : (r0 : Real) * (DE : Real) ≤ (2 ^ 126 : Real) * (NE : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] + have hr0le : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := by + rw [mul_div_assoc', le_div_iff₀ hDEpos]; linarith [hiR] + linarith [hr0le] + · -- big: r0·DE − 2^126·NE ≤ W_ev·(r0−2^126) (joint tight); divide by DE; add hcR + have hi := r0_certRatio_over_tight hx hC hC0 htnn (le_of_lt hbg) + have hjointR : (r0 : Real) * (DE : Real) - (2 ^ 126 : Real) * (NE : Real) ≤ + (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] + have hstep : (r0 : Real) ≤ (2 ^ 126 : Real) * (NE : Real) / (DE : Real) + + (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) := by + rw [div_add_div_same, le_div_iff₀ hDEpos]; nlinarith [hjointR, hDEpos] + rw [mul_div_assoc] at hstep + linarith [hstep, hcR] + -- 2^126·NE/DE ≤ 2^126·Et·Mp = 2^126·Et + 2^126·Et·(Mp−1); cMp = 2^126·Et·(Mp−1) ≤ small + have hMp1 : Mp - 1 = 1 / (2 ^ 130 - 1 : Real) := by rw [hMpdef]; field_simp + have hcMp : (2 ^ 126 : Real) * Et * (Mp - 1) ≤ 1 / 10 := by + rw [hMp1] + have hb : (2 ^ 126 : Real) * Et * (1 / (2 ^ 130 - 1 : Real)) ≤ + (2 ^ 126 : Real) * Real.sqrt 2 * (1 / (2 ^ 130 - 1 : Real)) := by + apply mul_le_mul_of_nonneg_right _ (by positivity) + exact mul_le_mul_of_nonneg_left hEtsqrt2 (by positivity) + have hn : (2 ^ 126 : Real) * Real.sqrt 2 * (1 / (2 ^ 130 - 1 : Real)) ≤ 1 / 10 := by + rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] + nlinarith [hsqrt2_val, hsqrt2_nn] + linarith [hb, hn] + -- gap1: Et − exp(rt) ≤ (t/2^128 − rt)·Et < (1/(32·2^128))·Et ≤ (1/(32·2^128))·√2 + set Ert := Real.exp (reducedArg x) with hErtdef + have hgapover := reducedArg_close_over hx hC hC0 + have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ + have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 1 / 50 := by + have h1 : Et - Ert ≤ (1 / (32 * (2 ^ 128 : Real))) * Et := + le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapover) hEtnn) + have h2 : (2 ^ 126 : Real) * (Et - Ert) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) := + mul_le_mul_of_nonneg_left h1 (by positivity) + have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) ≤ + (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hEtsqrt2 (by positivity)) (by positivity) + have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) ≤ 1 / 50 := by + rw [show (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) = + Real.sqrt 2 * (2 ^ 126 / (32 * 2 ^ 128)) from by ring] + have : (2 ^ 126 : Real) / (32 * 2 ^ 128) = 1 / 128 := by norm_num + rw [this]; nlinarith [hsqrt2_val, hsqrt2_nn] + linarith [h2, h3, h4] + -- assemble: r0 ≤ 2^126·(NE/DE) + 64/100 ≤ 2^126·Et·Mp + 64/100 + -- = 2^126·Et + 2^126·Et·(Mp−1) + 64/100 ≤ 2^126·Et + 1/10 + 64/100 + -- 2^126·Et = 2^126·Ert + 2^126·(Et−Ert) ≤ 2^126·Ert + 1/50 + -- total ≤ 2^126·Ert + 1/50 + 1/10 + 64/100 = 2^126·Ert + 0.72 ≤ 2^126·Ert + 47/64 + have hNEMp : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ + (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mp - 1) := by + have h := mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real)) + nlinarith [h] + -- final + have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + 1 / 50 := by + nlinarith [hcGap1] + calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 64 / 100 := hr0_div + _ ≤ ((2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mp - 1)) + 64 / 100 := by linarith [hNEMp] + _ ≤ ((2 ^ 126 : Real) * Et + 1 / 10) + 64 / 100 := by linarith [hcMp] + _ ≤ (((2 ^ 126 : Real) * Ert + 1 / 50) + 1 / 10) + 64 / 100 := by linarith [hEtErt] + _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by rw [hErtdef]; ring + + /-! ## The loose per-point real bounds (nonnegative half) These bracket `(r0Tree x : Real)` against `2¹²⁶·exp(rt)` with loose octave-seam-absorbed constants diff --git a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean index 3866861df..c3dfe4ed0 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean @@ -39,6 +39,145 @@ set_option maxHeartbeats 2000000 def reducedArg (x : Nat) : Real := (int256 x : Real) / (10 ^ 27 : Real) - (int256 (kTree x) : Real) * Real.log 2 +/-- **Reduced-argument tight over bound (gap-1, one-sided).** On the meaningful region the integer +`t`-rounding residual `P3 ≥ 0` makes the over direction strictly tighter than the symmetric bound: +`t/2¹²⁸ − rt < 1/(32·2¹²⁸)` (the `ln2`-grid and rational errors alone, since `P3 ≥ 0` only helps). +This is the gap-1 contribution the joint never-over budget consumes. -/ +theorem reducedArg_close_over {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (int256 (tTree x) : Real) / (2 ^ 128 : Real) - reducedArg x < 1 / (32 * (2 ^ 128 : Real)) := by + obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 + obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 + obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 + have hln2lo := ln2_lower + have hln2hi := ln2_upper + set t : Int := int256 (tTree x) with htdef + set k : Int := int256 (kTree x) with hkdef + set X : Int := int256 x with hXdef + have hK : (0x279d346de4781f921dd7a89933d54d1f72928 : Int) = 55213970774324510299478046898216203619608872 := by norm_num + have hL : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num + rw [hK, hL] at htlo hthi + -- ln2 bounds cleaned to decimal Real + have hLN2decimal : ((LN2c : Nat) : Real) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by + unfold LN2c; norm_num + rw [hLN2decimal] at hln2lo hln2hi + -- Real abbreviations + set LR : Real := Real.log 2 with hLRdef + set XR : Real := (X : Real) with hXRdef + set kR : Real := (k : Real) with hkRdef + set tR : Real := (t : Real) with htRdef + -- numeric Real names + set N235 : Real := (2 ^ 235 : Real) with hN235 + set N128 : Real := (2 ^ 128 : Real) with hN128 + set LN2R : Real := (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) with hLN2R + set K27R : Real := (55213970774324510299478046898216203619608872 : Real) with hK27R + have hp235 : (0 : Real) < N235 := by rw [hN235]; positivity + have hp128 : (0 : Real) < N128 := by rw [hN128]; positivity + have hpRAY : (0 : Real) < (10 ^ 27 : Real) := by positivity + -- 2^235 = 2^128 · 2^107 + have hsplit : N235 = N128 * 2 ^ 107 := by rw [hN235, hN128, ← pow_add] + -- the three pieces + set P1 : Real := XR * (1 / (10 ^ 27 : Real) - K27R / N235) with hP1def + set P2 : Real := kR * (LN2R / N235 - LR) with hP2def + set P3 : Real := (K27R * XR - LN2R * kR) / N235 - tR / N128 with hP3def + -- identity: reducedArg x - t/2^128 = P1 + P2 + P3 + have hident : XR / (10 ^ 27 : Real) - kR * LR - tR / N128 = P1 + P2 + P3 := by + rw [hP1def, hP2def, hP3def]; ring + -- bound P1 : |P1| < 2^96·N/(2^235·10^27) where N = K27·10^27 − 2^235 = 222636907558699806209605632 + -- We bound P1 ∈ (−ε, ε) with ε = 2^96·N/(2^235·10^27) < 2⁻¹³². Use explicit endpoints. + have hXloR : -(79228162514264337593543950336 : Real) < XR := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hxlo; rw [hXRdef] + rw [show ((2:Int)^96 : Int) = 79228162514264337593543950336 from by norm_num] at this + push_cast at this; linarith [this] + have hXhiR : XR < (79228162514264337593543950336 : Real) := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hxhi; rw [hXRdef] + rw [show ((2:Int)^96 : Int) = 79228162514264337593543950336 from by norm_num] at this + push_cast at this; linarith [this] + -- coefficient: 1/10^27 − K27/2^235 < 0, magnitude m := (K27·10^27 − 2^235)/(2^235·10^27) + have hcoeff_eq : (1 / (10 ^ 27 : Real) - K27R / N235) = + -((K27R * (10 ^ 27 : Real) - N235) / (N235 * (10 ^ 27 : Real))) := by + rw [hK27R, hN235]; field_simp; ring + have hcoeff_num : K27R * (10 ^ 27 : Real) - N235 = 222636907558699806209605632 := by + rw [hK27R, hN235]; norm_num + -- |P1| < 2⁻¹³² (a generous bound): |XR| < 2^96, |coeff| = m, and 2^96·m < 2⁻¹³². + have hP1_abs : |P1| < 1 / (64 * N128) := by + rw [hP1def, hcoeff_eq, hcoeff_num, abs_mul] + have hden_pos : (0 : Real) < N235 * (10 ^ 27 : Real) := by positivity + have hco_abs : |(-(222636907558699806209605632 / (N235 * (10 ^ 27 : Real))))| = + 222636907558699806209605632 / (N235 * (10 ^ 27 : Real)) := by + rw [abs_neg, abs_of_pos (by positivity)] + rw [hco_abs] + have hX_abs : |XR| < 79228162514264337593543950336 := abs_lt.mpr ⟨hXloR, hXhiR⟩ + have hco_pos : (0:Real) < 222636907558699806209605632 / (N235 * (10 ^ 27 : Real)) := by positivity + calc |XR| * (222636907558699806209605632 / (N235 * (10 ^ 27 : Real))) + < 79228162514264337593543950336 * (222636907558699806209605632 / (N235 * (10 ^ 27 : Real))) := + (mul_lt_mul_right hco_pos).mpr hX_abs + _ = 79228162514264337593543950336 * 222636907558699806209605632 / + (N235 * (10 ^ 27 : Real)) := by rw [mul_div_assoc] + _ < 1 / (64 * N128) := by + rw [hN235, hN128, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num + -- bound P2 : 0 ≤ LN2R/N235 − LR... actually ln2 ≥ LN2/2^235, so LN2R/N235 − LR ≤ 0, and ≥ −1/N235. + have hP2_lo : LN2R / N235 - LR ≤ 0 := by linarith [hln2lo] + have hP2_hi : -(1 / N235) ≤ LN2R / N235 - LR := by + have : LR ≤ (LN2R + 1) / N235 := hln2hi + rw [add_div] at this; linarith [this] + -- |k| ≤ 63 ⇒ |P2| ≤ 63/N235 < 1/N128 + have hkloR : -(61 : Real) ≤ kR := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] + have hkhiR : kR ≤ (63 : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] + have hP2_abs : |P2| < 1 / (64 * N128) := by + rw [hP2def] + have h1 : |kR| ≤ 63 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by + rw [abs_le] + refine ⟨by linarith [hP2_hi], ?_⟩ + have hpos : (0:Real) ≤ 1 / N235 := by positivity + linarith [hP2_lo, hpos] + have hbound : |kR * (LN2R / N235 - LR)| ≤ 63 * (1 / N235) := by + rw [abs_mul] + exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) + have hlt : 63 * (1 / N235) < 1 / (64 * N128) := by + rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num + linarith [hbound, hlt] + -- bound P3 ∈ [0, 1/N128) from the integer sandwich + have hP3int_lo : (0 : Int) ≤ 55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t := by omega + have hP3int_hi : 55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t < 2 ^ 107 := by omega + -- P3 = (A − 2^107·t)/N235, with the numerator (a Real cast of an Int) in [0, 2^107) + have hnumR_lo : (0 : Real) ≤ K27R * XR - LN2R * kR - 2 ^ 107 * tR := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hP3int_lo + rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] + push_cast at h; linarith [h] + have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 107 * tR < 2 ^ 107 := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hP3int_hi + rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] + push_cast at h; linarith [h] + have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 107 * tR) / N235 := by + rw [hP3def, hsplit]; field_simp; ring + have hP3_lo : 0 ≤ P3 := by rw [hP3eq]; exact div_nonneg hnumR_lo (le_of_lt hp235) + have hP3_hi : P3 < 1 / N128 := by + rw [hP3eq, hsplit, div_lt_div_iff₀ (by positivity) (by positivity)] + nlinarith [hnumR_hi, hp128] + -- assemble: tR/N128 − rt = −(P1+P2+P3) < 1/(32 N128), since P1+P2 > −1/(32 N128) and P3 ≥ 0 + have hP1 := abs_lt.mp hP1_abs + have hP2 := abs_lt.mp hP2_abs + clear_value N128 N235 + have he12 : (1 : Real) / (64 * N128) + 1 / (64 * N128) = 1 / (32 * N128) := by + field_simp; ring + have hredeq : reducedArg x = XR / (10 ^ 27 : Real) - kR * LR := rfl + have hident' : (tR / N128 - reducedArg x) = -(P1 + P2 + P3) := by + rw [hredeq]; linarith [hident] + rw [hident'] + -- P1+P2 > −1/(32 N128); P3 ≥ 0 + have h12lo : -(1 / (32 * N128)) < P1 + P2 := by + rw [show -(1 / (32 * N128)) = -(1 / (64 * N128)) + -(1 / (64 * N128)) from by rw [← he12]; ring] + linarith [hP1.1, hP2.1] + linarith [h12lo, hP3_lo] + /-- **Reduced-argument real bound (gap-1).** On the meaningful region the reduced argument `rt` agrees with `t/2¹²⁸` to within `9/(8·2¹²⁸)` (the integer `t`-rounding sandwich `[0, 1/2¹²⁸)` dominates; the rational and `ln2`-grid errors are below `2⁻¹³²`). -/ From e6188b29aa7f2dcb5461ac118934687e5ce6b40d Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:53:23 +0200 Subject: [PATCH 075/149] Prove the exp joint never-over on the negative half MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit r0_real_over_tight_neg + r0_real_over_within: r0 ≤ 2^126·exp(rt) + 19/25 for all meaningful-region inputs (both signs), within MARGIN/WAD = 0.792. The negative half uses the |t|·od coupling (todNumV_lb_neg: Et' ≥ W_od·2^1039·t) to control the tod-truncation × (r0+2^126) cross term, with ê ≥ 1/√2 (exp(rt) ≥ 7/10) and od ≥ B4. New region facts exp_t_ge_inv_sqrt2, exp_reducedArg_ge_07, num_ge_23_den. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 433 ++++++++++++++++++ 1 file changed, 433 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 11018b69a..81a4ff563 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -1398,6 +1398,7 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by rw [hErtdef]; ring + /-! ## The loose per-point real bounds (nonnegative half) These bracket `(r0Tree x : Real)` against `2¹²⁶·exp(rt)` with loose octave-seam-absorbed constants @@ -1783,6 +1784,438 @@ theorem r0_real_under {x : Nat} (hx : x < 2 ^ 256) · exact r0_real_under_loose hx hC hC0 htnn · exact r0_real_under_loose_neg hx hC hC0 (le_of_lt htneg) +/-! ## The tight joint per-point never-over (negative half + combined) -/ + +theorem exp_t_ge_inv_sqrt2 {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (Real.sqrt 2)⁻¹ ≤ Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) := by + obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 + -- t/2^128 ≥ -H128/2^128 ≥ -log2/2 + have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity + have htR : -(117932881612756647068972071382077242199 : Real) ≤ (int256 (tTree x) : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo; push_cast at this; linarith [this] + -- -log2/2 ≤ t/2^128: 2·H128 ≤ log2·2^128 (from log2 ≥ LN2/2^235) + have hln2lo := ln2_lower; rw [LN2c_eq] at hln2lo + have hkey : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := by + have h1 : (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := + mul_le_mul_of_nonneg_right hln2lo (by positivity) + have h2 : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ + (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) := by + rw [div_mul_eq_mul_div, le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)]; norm_num + linarith [h1, h2] + have hge : -(Real.log 2 / 2) ≤ (int256 (tTree x) : Real) / (2 ^ 128 : Real) := by + have hmul : -(Real.log 2 / 2) * (2 ^ 128 : Real) ≤ (int256 (tTree x) : Real) := by + nlinarith [htR, hkey] + exact (le_div_iff₀ hp128).mpr hmul + have hexpsq : Real.exp (Real.log 2 / 2) = Real.sqrt 2 := by + rw [Real.sqrt_eq_rpow, Real.rpow_def_of_pos (by norm_num : (0:Real) < 2)] + congr 1; ring + have hsq : (Real.sqrt 2)⁻¹ = Real.exp (-(Real.log 2 / 2)) := by + rw [Real.exp_neg, hexpsq] + rw [hsq] + exact Real.exp_le_exp.mpr hge + +-- exp(rt) ≥ 7/10 on the region (rt = t/2^128 + (rt − t/2^128); exp(t/2^128) ≥ 1/√2, the gap is tiny). + +theorem exp_reducedArg_ge_07 {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (7 : Real) / 10 ≤ Real.exp (reducedArg x) := by + have hge := exp_t_ge_inv_sqrt2 hx hC hC0 + have hclose := abs_lt.mp (reducedArg_close hx hC hC0) + set t := int256 (tTree x) with htdef + -- exp(rt) = exp(t/2^128)·exp(rt − t/2^128) ≥ (1/√2)·exp(rt − t/2^128) + have hsplit : Real.exp (reducedArg x) = + Real.exp ((t : Real) / (2 ^ 128 : Real)) * Real.exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) := by + rw [← Real.exp_add]; congr 1; ring + -- exp(rt − t/2^128) ≥ 1 + (rt − t/2^128) ≥ 1 − 9/(8·2^128) + have hgap : reducedArg x - (t : Real) / (2 ^ 128 : Real) > -(9 / (8 * (2 ^ 128 : Real))) := by + have := hclose.1; linarith [this] + have hconv : (1 : Real) - 9 / (8 * (2 ^ 128 : Real)) ≤ Real.exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) := by + have h := Real.add_one_le_exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) + linarith [h, hgap] + -- √2⁻¹ ≥ 7071/10000 (⟺ √2 ≤ 10000/7071, since (10000/7071)² > 2) + have hsqrt2_pos : (0:Real) < Real.sqrt 2 := Real.sqrt_pos.mpr (by norm_num) + have hsqrt2_le : Real.sqrt 2 ≤ 10000 / 7071 := by + rw [Real.sqrt_le_iff]; constructor <;> norm_num + have hinvsqrt2 : (7071 : Real) / 10000 ≤ (Real.sqrt 2)⁻¹ := by + rw [le_inv_comm₀ (by norm_num) hsqrt2_pos] + calc Real.sqrt 2 ≤ 10000 / 7071 := hsqrt2_le + _ = (7071 / 10000)⁻¹ := by norm_num + have hgap_small : (1 : Real) - 9 / (8 * (2 ^ 128 : Real)) ≥ 9999 / 10000 := by + have : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 1 / 10000 := by + rw [div_le_div_iff₀ (by positivity) (by norm_num)]; norm_num + linarith [this] + rw [hsplit] + have hpos : (0:Real) ≤ Real.exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) := le_of_lt (Real.exp_pos _) + calc (7:Real)/10 ≤ (7071/10000) * (9999/10000) := by norm_num + _ ≤ (Real.sqrt 2)⁻¹ * (1 - 9 / (8 * (2 ^ 128 : Real))) := by + apply mul_le_mul hinvsqrt2 (by linarith [hgap_small]) (by norm_num) (by positivity) + _ ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) * Real.exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) := by + apply mul_le_mul hge hconv (by positivity) (le_of_lt (Real.exp_pos _)) + + +-- num ≥ (2/3)·den for t ≤ 0: r0 ≤ 2^126·num/den (floor), r0 ≥ 2^126·exp(rt)−705 > (2/3)·2^126. + +theorem num_ge_23_den {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + 2 * ((evTree x : Int) - int256 (todTree x)) ≤ 3 * ((evTree x : Int) + int256 (todTree x)) := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + have hu := r0_real_under hx hC hC0 + have hge07 := exp_reducedArg_ge_07 hx hC hC0 + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ den := den_ge_072 hx hC hC0 + have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden072 + have hdenR : (0:Real) < (den : Real) := by exact_mod_cast hdenpos + have hr0R : (2 ^ 126 : Real) * (7/10) - 705 ≤ (int256 (r0Tree x) : Real) := by + have h1 : (2 ^ 126 : Real) * (7/10) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) := + mul_le_mul_of_nonneg_left hge07 (by positivity) + linarith [hu, h1] + have hflR : (int256 (r0Tree x) : Real) * (den : Real) ≤ (2 ^ 126 : Real) * (num : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hfloor_lo; push_cast at this; linarith [this] + have hnumden : (2 ^ 126 : Real) * (7/10) * (den : Real) - 705 * (den : Real) ≤ (2 ^ 126 : Real) * (num : Real) := by + nlinarith [hr0R, hflR, hdenR] + have hkey : (2 : Real) * (den : Real) ≤ 3 * (num : Real) := by + have hp : (0:Real) < (2 ^ 126 : Real) := by positivity + have hnum_ge : (7/10) * (den : Real) - 705 * (den : Real) / (2 ^ 126 : Real) ≤ (num : Real) := by + rw [← mul_le_mul_left hp] + have heq : (2 ^ 126 : Real) * ((7/10) * (den : Real) - 705 * (den : Real) / (2 ^ 126 : Real)) = + (2 ^ 126 : Real) * (7/10) * (den : Real) - 705 * (den : Real) := by field_simp; ring + rw [heq]; exact hnumden + have hden_big : (705 : Real) * (den : Real) / (2 ^ 126 : Real) ≤ (1/100) * (den : Real) := by + rw [div_le_iff₀ hp] + nlinarith [hdenR, hden072, (by norm_num : (0:Real) < (2:Real)^126)] + nlinarith [hnum_ge, hden_big, hdenR] + have : ((2 * den : Int) : Real) ≤ ((3 * num : Int) : Real) := by push_cast; linarith [hkey] + exact_mod_cast this + + +-- The integer cR bound (negative half): 100·W_od·2^1039·(−t)·(r0+2^126) ≤ 64·DE. +-- Chain (multiplied by od·den > 0): (−t)·od ≤ 2^128·(−tod); (r0+2^126)·den ≤ 2^127·ev; +-- (−tod)·ev = (den²−num²)/4 ≤ 5·den²/36 (from 3·num ≥ 2·den ⟹ 9·num² ≥ 4·den²); od ≥ B4; DE ≥ 2^1193(den−2). + +theorem todNumV_lb_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + 2 ^ 1193 * (int256 (todTree x)) + 69402657 * 2 ^ 1039 * (int256 (tTree x)) ≤ + evalPoly ExpCertV.todNumV (int256 (tTree x)) := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + obtain ⟨hodlo, hodhi⟩ := odNumVPoly_bracket hx hC hC0 + set t := int256 (tTree x) with htdef + rw [evalTodNumV] + -- todP = 2^23·t·odpoly. t ≤ 0, odpoly < 2^1042·od + W_od·2^1016 ⟹ 2^23·t·odpoly ≥ 2^23·t·(2^1042 od + W_od 2^1016) + have hmul : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) ≤ + 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := by + apply mul_le_mul_of_nonneg_left _ (by positivity) + exact mul_le_mul_of_nonpos_left (le_of_lt hodhi) htneg + -- 2^23·t·(2^1042 od + W_od 2^1016) = 2^1065·(t·od) + W_od·2^1039·t ≥ 2^1193·tod + W_od·2^1039·t + have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo + have key : 2 ^ 1193 * (int256 (todTree x)) + 69402657 * 2 ^ 1039 * t ≤ + 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) := by + have e1 : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) = + 2 ^ 1065 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1039 * t := by ring + have e2 : (2 : Int) ^ 1065 * ((2 ^ 128 : Int) * (int256 (todTree x))) = 2 ^ 1193 * (int256 (todTree x)) := by + rw [show (2:Int) ^ 1193 = 2 ^ 1065 * 2 ^ 128 from by rw [← pow_add]]; ring + rw [e1] + have h := mul_le_mul_of_nonneg_left htod_lo (by positivity : (0:Int) ≤ 2 ^ 1065) + nlinarith [h, e2] + linarith [hmul, key] + +/-- **Negative-half joint cert-ratio over** (`t ≤ 0`): `r0·DE − 2¹²⁶·NE ≤ W_od·2¹⁰³⁹·|t|·(r0+2¹²⁶)`. +The even truncation `Ee·(r0−2¹²⁶) ≤ 0` (since `r0 < 2¹²⁶`) is dropped; the binding term is the odd +truncation, attenuated to the `t`-scale by `W_od·2¹⁰³⁹·t`. -/ + +theorem r0_certRatio_over_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) - + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) ≤ + 69402657 * 2 ^ 1039 * (-(int256 (tTree x))) * (int256 (r0Tree x) + 2 ^ 126) := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hevlo, _⟩ := evNumVPoly_bracket hx hC hC0 + have htodlb := todNumV_lb_neg hx hC hC0 htneg + rw [evalNumExpV, evalDenExpV] + set t := int256 (tTree x) with htdef + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set evP := evalPoly ExpCertV.evNumVPoly t with hevP + set todP := evalPoly ExpCertV.todNumV t with htodP + obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 + have hr0nn : (0:Int) ≤ r0 := by linarith [hr0lo] + -- tod ≤ 0 for t ≤ 0 (tod = ⌊t·od/2^128⌋, t ≤ 0, od ≥ 0) + have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have htod_np : tod ≤ 0 := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + -- 2^128·tod ≤ t·od ≤ 0 + have htod_nonpos : (2 ^ 128 : Int) * tod ≤ 0 := le_trans htodlo (mul_nonpos_of_nonpos_of_nonneg htneg hodnn) + nlinarith [htod_nonpos] + -- r0 ≤ 2^126: r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den ⟺ tod ≤ 0); den > 0 + have hdenpos : (0:Int) < ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this + linarith [this, (by norm_num : (0:Int) < 61251667550081741634933722430035858604)] + have hr0le126 : r0 ≤ 2 ^ 126 := by + have hnumden : r0 * (ev - tod) ≤ 2 ^ 126 * (ev - tod) := by + have h1 : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo + nlinarith [h1, htod_np, (by positivity : (0:Int) ≤ (2:Int)^126)] + have := le_of_mul_le_mul_right hnumden hdenpos + exact this + have hr0m_np : r0 - 2 ^ 126 ≤ 0 := by linarith [hr0le126] + have hr0p_nn : (0:Int) ≤ r0 + 2 ^ 126 := by positivity + -- evP·(r0−2^126) ≤ 2^1193·ev·(r0−2^126) [evP ≥ 2^1193 ev, r0−2^126 ≤ 0] + have hterm1 : evP * (r0 - 2 ^ 126) ≤ 2 ^ 1193 * ev * (r0 - 2 ^ 126) := + mul_le_mul_of_nonpos_right hevlo hr0m_np + -- −todP·(r0+2^126) ≤ −(2^1193·tod + W_od·2^1039·t)·(r0+2^126) [todP ≥ lower, r0+2^126 ≥ 0] + have hterm2 : -(todP * (r0 + 2 ^ 126)) ≤ -((2 ^ 1193 * tod + 69402657 * 2 ^ 1039 * t) * (r0 + 2 ^ 126)) := by + have := mul_le_mul_of_nonneg_right htodlb hr0p_nn + linarith [this] + -- floor: 2^1193·(den·r0 − 2^126·num) ≤ 0 + have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor1193 : (2 ^ 1193 : Int) * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor + -- assemble + nlinarith [hterm1, hterm2, hfloor1193] + +/-- **The joint per-point never-over (negative half).** `r0 ≤ 2¹²⁶·exp(rt) + 19/25` for `t ≤ 0`. -/ + +theorem r0_certRatio_over_neg_bound {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + 100 * (69402657 * 2 ^ 1039 * (-(int256 (tTree x))) * (int256 (r0Tree x) + 2 ^ 126)) ≤ + 64 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hdenlo, _⟩ := denExpV_bracket_neg hx hC hC0 htneg + set t := int256 (tTree x) with htdef + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set od := (odTree x : Int) with hoddef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + -- basic facts + have hodB4 : (51893481707599524783927774179503442518 : Int) ≤ od := by + -- od ≥ B4 (odd leading constant; odTree = B4 + nonneg shifts) + have : (0x270a522f476182f119f08da0ba710a56 : Nat) ≤ odTree x := odTree_ge (vTree_eq hx hC hC0).2 + have h := (@Int.ofNat_le _ _).mpr this + rw [show ((0x270a522f476182f119f08da0ba710a56 : Nat) : Int) = 51893481707599524783927774179503442518 from by norm_num] at h + rw [hoddef]; exact_mod_cast h + have hodpos : (0:Int) < od := lt_of_lt_of_le (by norm_num) hodB4 + have htnp : t ≤ 0 := htneg + have hntnn : (0:Int) ≤ -t := by omega + -- tod ≤ 0 + have hodnn : (0:Int) ≤ od := le_of_lt hodpos + have htod_np : tod ≤ 0 := by + have hle : (2 ^ 128 : Int) * tod ≤ t * od := htodlo + have : t * od ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htnp hodnn + nlinarith [hle, this] + have hntodnn : (0:Int) ≤ -tod := by omega + -- den := ev - tod > 0; den ≥ 0.72·2^126 + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 + -- (1) (−t)·od ≤ 2^128·(−tod): 2^128·tod ≤ t·od ⟹ −t·od ≤ −2^128·tod = 2^128·(−tod) + have hstep1 : (-t) * od ≤ 2 ^ 128 * (-tod) := by + have hle : (2 ^ 128 : Int) * tod ≤ t * od := htodlo; nlinarith [hle] + -- (2) (r0+2^126)·(ev−tod) ≤ 2^127·ev: r0·(ev−tod) ≤ 2^126·(ev+tod) (floor), +2^126·(ev−tod) + have hstep2 : (r0 + 2 ^ 126) * (ev - tod) ≤ 2 ^ 127 * ev := by + have hfl : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo + nlinarith [hfl] + -- (3) 9·num² ≥ 4·den² from 3·num ≥ 2·den (num=ev+tod ≥ 0, den=ev−tod > 0) + have h32 := num_ge_23_den hx hC hC0 + have h32' : 2 * (ev - tod) ≤ 3 * (ev + tod) := by rw [← hevdef, ← htoddef] at h32; exact h32 + have hnumnn : (0:Int) ≤ ev + tod := by + obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 + obtain ⟨htod_lo, _, _, _⟩ := todTree_bound hx hC hC0 + have he : (103786963415199049567855548359006885036 : Int) ≤ ev := by rw [hevdef]; exact_mod_cast hevlo + have ht : -(2 ^ 125 : Int) ≤ tod := htod_lo + have h2 : (2:Int)^125 = 42535295865117307932921825928971026432 := by norm_num + rw [h2] at ht; linarith [he, ht] + -- (4) (−tod)·ev = (den²−num²)/4 ; 9·num²≥4·den² ⟹ 4·(−tod)·ev = den²−num² ≤ den² − (4/9)den² = (5/9)den² + -- ⟹ 36·(−tod)·ev ≤ 5·den². (num=ev+tod, den=ev−tod, num²−tod... use ring) + have hstep4 : 36 * ((-tod) * ev) ≤ 5 * (ev - tod) ^ 2 := by + have hsq : 9 * (ev + tod) ^ 2 ≥ 4 * (ev - tod) ^ 2 := by nlinarith [h32', hnumnn, hdenpos] + nlinarith [hsq] + -- abstract den, od, DE; carry the chain through the positive product od·den + set den := ev - tod with hdendef' + have hdR2 : (r0 + 2 ^ 126) * den ≤ 2 ^ 127 * ev := hstep2 + have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by + obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 + have hr0nn : (0:Int) ≤ r0 := by linarith [hr0lo] + positivity + -- A1 := (−t)·(r0+2^126)·(od·den) ≤ 2^255·5·den²/36 ... carry without division: + -- chain on 36·A1 ≤ 5·2^255·den² + have hntden : (0:Int) ≤ 2 ^ 128 * (-tod) := by positivity + -- (−t)·od·(r0+2^126)·den ≤ 2^128·(−tod)·(r0+2^126)·den [hstep1, (r0+2^126)·den ≥ 0] + have hP1 : (-t) * od * ((r0 + 2 ^ 126) * den) ≤ 2 ^ 128 * (-tod) * ((r0 + 2 ^ 126) * den) := by + apply mul_le_mul_of_nonneg_right hstep1 (mul_nonneg hr0p (le_of_lt hdenpos)) + -- 2^128·(−tod)·(r0+2^126)·den ≤ 2^128·(−tod)·2^127·ev [hstep2, 2^128(−tod) ≥ 0] + have hP2 : 2 ^ 128 * (-tod) * ((r0 + 2 ^ 126) * den) ≤ 2 ^ 128 * (-tod) * (2 ^ 127 * ev) := + mul_le_mul_of_nonneg_left hdR2 hntden + -- combine + hstep4: 36·(−t)·od·(r0+2^126)·den ≤ 36·2^255·(−tod)·ev ≤ 5·2^255·den² + have hevnn : (0:Int) ≤ ev := by nlinarith [hdenpos, htod_np] + have hP3 : 36 * ((-t) * od * ((r0 + 2 ^ 126) * den)) ≤ 5 * 2 ^ 255 * den ^ 2 := by + have h255 : 2 ^ 128 * (-tod) * (2 ^ 127 * ev) = 2 ^ 255 * ((-tod) * ev) := by + rw [show (2:Int) ^ 255 = 2 ^ 128 * 2 ^ 127 from by rw [← pow_add]]; ring + have hchain : (-t) * od * ((r0 + 2 ^ 126) * den) ≤ 2 ^ 255 * ((-tod) * ev) := by + rw [← h255]; linarith [hP1, hP2] + have h36 : 36 * (2 ^ 255 * ((-tod) * ev)) ≤ 2 ^ 255 * (5 * den ^ 2) := by + have := mul_le_mul_of_nonneg_left hstep4 (by positivity : (0:Int) ≤ 2 ^ 255) + nlinarith [this] + nlinarith [hchain, h36, (by positivity : (0:Int) ≤ (36:Int))] + -- DE > 2^1193·(den − 2); od ≥ B4. RHS 64·DE·(od·den) ≥ 64·2^1193(den−2)·B4·den + have hDElo : 2 ^ 1193 * den - 2 * 2 ^ 1193 < DE := hdenlo + -- final: 100·W·2^1039·(−t)·(r0+2^126) ≤ 64·DE. multiply both by od·den (>0) and use 36·(LHS·od·den) ≤ ... + set q := od * den with hqdef + have hqpos : (0:Int) < q := by rw [hqdef]; exact mul_pos hodpos hdenpos + -- 36·100·W·2^1039·(−t)·(r0+2^126)·q ≤ 100·W·2^1039·(5·2^255·den²) [hP3 scaled] + -- and 64·DE·q ≥ 64·(2^1193 den − 2·2^1193)·B4·den via DE>… od≥B4 + -- prove via le_of_mul_le_mul_right with multiplier q, after establishing the multiplied inequality. + rw [← mul_le_mul_right hqpos] + -- goal: 100·W·2^1039·(−t)·(r0+2^126)·q ≤ 64·DE·q + have hLHS : 100 * (69402657 * 2 ^ 1039 * (-t) * (r0 + 2 ^ 126)) * q = + 100 * 69402657 * 2 ^ 1039 * ((-t) * od * ((r0 + 2 ^ 126) * den)) := by rw [hqdef]; ring + rw [hLHS] + -- 36·LHS ≤ 100·69402657·2^1039·(5·2^255·den²) =: RHS36 ; and 36·(64·DE·q) ≥ 36·64·(2^1193 den − 2·2^1193)·B4·den + -- show LHS ≤ 64·DE·q via: 36·LHS ≤ 36·(64·DE·q) + have hmul36 : 36 * (100 * 69402657 * 2 ^ 1039 * ((-t) * od * ((r0 + 2 ^ 126) * den))) ≤ + 36 * (64 * DE * q) := by + have hL : 36 * (100 * 69402657 * 2 ^ 1039 * ((-t) * od * ((r0 + 2 ^ 126) * den))) ≤ + 100 * 69402657 * 2 ^ 1039 * (5 * 2 ^ 255 * den ^ 2) := by + have := mul_le_mul_of_nonneg_left hP3 (by positivity : (0:Int) ≤ 100 * 69402657 * 2 ^ 1039) + nlinarith [this] + have hR : 100 * 69402657 * 2 ^ 1039 * (5 * 2 ^ 255 * den ^ 2) ≤ 36 * (64 * DE * q) := by + -- 36·64·DE·q ≥ 36·64·(2^1193 den − 2·2^1193)·B4·den (DE > …, od ≥ B4, den > 0) + have hDEq : 36 * (64 * DE * q) ≥ 36 * 64 * ((2 ^ 1193 * den - 2 * 2 ^ 1193) * (51893481707599524783927774179503442518 * den)) := by + rw [hqdef] + have hDEnn : (0:Int) ≤ DE := by + have := denExpV_lb_neg hx hC hC0 htneg; rw [← hDEdef] at this + have h2 : (0:Int) < 2 ^ 1317 := by positivity + linarith [this, h2] + have h1 : (2 ^ 1193 * den - 2 * 2 ^ 1193) * 51893481707599524783927774179503442518 ≤ DE * od := + mul_le_mul (le_of_lt hDElo) hodB4 (by norm_num) hDEnn + nlinarith [h1, hdenpos] + -- 100·69402657·5·2^1294·den² ≤ 36·64·2^1193·B4·(den−2)·den (factor 2^1193, den) + have hcore : 100 * 69402657 * 2 ^ 1039 * (5 * 2 ^ 255 * den ^ 2) ≤ + 36 * 64 * ((2 ^ 1193 * den - 2 * 2 ^ 1193) * (51893481707599524783927774179503442518 * den)) := by + -- both sides = (·)·2^1193·den. LHS = (100·69402657·5·2^101)·2^1193·den². + have hpe1 : (2:Int) ^ 1039 * 2 ^ 255 = 2 ^ 101 * 2 ^ 1193 := by rw [← pow_add, ← pow_add] + have eL : 100 * 69402657 * 2 ^ 1039 * (5 * 2 ^ 255 * den ^ 2) = + (100 * 69402657 * 5 * 2 ^ 101) * (2 ^ 1193 * den ^ 2) := by + linear_combination (100 * 69402657 * 5 * den ^ 2) * hpe1 + have eR : 36 * 64 * ((2 ^ 1193 * den - 2 * 2 ^ 1193) * (51893481707599524783927774179503442518 * den)) = + (36 * 64 * 51893481707599524783927774179503442518) * (2 ^ 1193 * (den - 2) * den) := by ring + rw [eL, eR] + -- (100·69402657·5·2^101)·den ≤ (36·64·B4)·(den−2) [divide common 2^1193·den; den ≥ 0.72·2^126 ≫ 2] + have hfactor : (100 * 69402657 * 5 * 2 ^ 101 : Int) * den ≤ (36 * 64 * 51893481707599524783927774179503442518) * (den - 2) := by + nlinarith [hden072, hdenpos] + have hp1193den : (0:Int) ≤ 2 ^ 1193 * den := by positivity + nlinarith [hfactor, hp1193den, hdenpos, (by positivity : (0:Int) ≤ (2:Int)^1193)] + linarith [hDEq, hcore] + linarith [hL, hR] + nlinarith [hmul36] + +theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by + have htdom := tdom_neg hx hC hC0 htneg + set t := int256 (tTree x) with htdef + have hDElb := denExpV_lb_neg hx hC hC0 htneg + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos + exact_mod_cast this + set r0 := int256 (r0Tree x) with hr0def + -- certLo_real_neg: NE/DE ≤ Et·Mpp, Mpp = (2^130+1)/2^130 + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + have hcertlo := certLo_real_neg htneg htdom + set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef + have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mpp := by + have hc : ((2 ^ 130 : Int) : Real) * (NE : Real) / + (((2 ^ 130 + 1 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + rw [hMppdef] + have key : (NE : Real) / (DE : Real) = + ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) * + (((2 ^ 130 : Int) : Real) * (NE : Real) / + (((2 ^ 130 + 1 : Int) : Real) * (DE : Real))) := by + push_cast; field_simp; ring + rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) + -- Et ≤ 1 (t ≤ 0) + have hEt_le_one : Et ≤ 1 := by + rw [hEtdef, show (1:Real) = Real.exp 0 from (Real.exp_zero).symm] + apply Real.exp_le_exp.mpr + have htR : (t : Real) ≤ 0 := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htneg; push_cast at this; linarith [this] + apply div_nonpos_of_nonpos_of_nonneg htR (by positivity) + have hEtnn : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) + -- cR_neg: r0·DE − 2^126·NE ≤ (64/100)·DE (Int: certRatio_neg ≤ W·2^1039(−t)(r0+2^126), bound by 64·DE/100) + have hcR' : (r0 : Real) * (DE : Real) - (2 ^ 126 : Real) * (NE : Real) ≤ (64 / 100) * (DE : Real) := by + have hcr := r0_certRatio_over_neg hx hC hC0 htneg + have hbd := r0_certRatio_over_neg_bound hx hC hC0 htneg + -- chain (Int): 100·(r0·DE − 2^126·NE) ≤ 100·W·2^1039·(−t)·(r0+2^126) ≤ 64·DE + have hint : 100 * (r0 * (evalPoly ExpCertV.denExpV t) - 2 ^ 126 * (evalPoly ExpCertV.numExpV t)) ≤ + 64 * (evalPoly ExpCertV.denExpV t) := by + have h1 : 100 * (r0 * (evalPoly ExpCertV.denExpV t) - 2 ^ 126 * (evalPoly ExpCertV.numExpV t)) ≤ + 100 * (69402657 * 2 ^ 1039 * (-t) * (r0 + 2 ^ 126)) := by + apply mul_le_mul_of_nonneg_left hcr (by norm_num) + linarith [h1, hbd] + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hint; push_cast at this + rw [hNEdef, hDEdef]; linarith [this] + -- r0 ≤ 2^126·NE/DE + 64/100 + have hr0_div : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 64 / 100 := by + have hkey : (r0 : Real) ≤ ((2 ^ 126 : Real) * (NE : Real) + (64 / 100) * (DE : Real)) / (DE : Real) := by + rw [le_div_iff₀ hDEpos]; nlinarith [hcR', hDEpos] + rw [add_div, mul_div_assoc, mul_div_assoc, div_self (ne_of_gt hDEpos), mul_one] at hkey + linarith [hkey] + -- assemble: r0 ≤ 2^126·Et·Mpp + 64/100 = 2^126·Et + 2^126·Et·(Mpp−1) + 64/100 + -- ≤ 2^126·Et + 1/16 + 64/100; 2^126·Et ≤ 2^126·exp(rt) + 1/128 (gap1 over) + have hMpp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp + have hcMp : (2 ^ 126 : Real) * Et * (Mpp - 1) ≤ 1 / 16 := by + rw [hMpp1] + have : (2 ^ 126 : Real) * Et * (1 / (2 ^ 130 : Real)) ≤ (2 ^ 126 : Real) * 1 * (1 / (2 ^ 130 : Real)) := by + apply mul_le_mul_of_nonneg_right _ (by positivity) + exact mul_le_mul_of_nonneg_left hEt_le_one (by positivity) + have hn : (2 ^ 126 : Real) * 1 * (1 / (2 ^ 130 : Real)) ≤ 1 / 16 := by norm_num + linarith [this, hn] + set Ert := Real.exp (reducedArg x) with hErtdef + have hgapover := reducedArg_close_over hx hC hC0 + have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ + have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 1 / 128 := by + have h1 : Et - Ert ≤ (1 / (32 * (2 ^ 128 : Real))) * Et := + le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapover) hEtnn) + have h2 : (2 ^ 126 : Real) * (Et - Ert) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) := + mul_le_mul_of_nonneg_left h1 (by positivity) + have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) ≤ + (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * 1) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hEt_le_one (by positivity)) (by positivity) + have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * 1) ≤ 1 / 128 := by norm_num + linarith [h2, h3, h4] + have hNEMp : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ + (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mpp - 1) := by + have h := mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real)) + nlinarith [h] + have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + 1 / 128 := by nlinarith [hcGap1] + calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 64 / 100 := hr0_div + _ ≤ ((2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mpp - 1)) + 64 / 100 := by linarith [hNEMp] + _ ≤ ((2 ^ 126 : Real) * Et + 1 / 16) + 64 / 100 := by linarith [hcMp] + _ ≤ (((2 ^ 126 : Real) * Ert + 1 / 128) + 1 / 16) + 64 / 100 := by linarith [hEtErt] + _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by + rw [hErtdef]; have : (1:Real)/128 + 1/16 + 64/100 ≤ 19/25 := by norm_num + linarith [this] + +/-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + 19/25` (≤ MARGIN/WAD). -/ +theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by + rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg + · exact r0_real_over_tight hx hC hC0 htnn + · exact r0_real_over_tight_neg hx hC hC0 (le_of_lt htneg) + + /-! ## The octave-seam `r0`-doubling consequence -/ /-- The reduced argument is above `−log 2` on the region, so `exp(rt) > 1/2`. -/ From 84140691810813fc71e4b373034c8bf60ae6bd35 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 22:03:31 +0200 Subject: [PATCH 076/149] Add the exp per-point deficit (under) brackets, both signs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mirror of the never-over r0_real_over_within: per-point 2^126·exp(rt) ≤ r0 + 8 (r0_real_under_within), within the closing-shift deficit budget 2^63/WAD − MARGIN/WAD = 8.43 at the binding k = 63. Nonneg half drops the even truncation Ee·(2^126−r0) ≤ 0 (r0 ≥ 2^126) and bounds the tod truncation (todNumV_ub, t ≤ H128 far below 2^128); negative half drops the tod and bounds the even truncation (r0 ≤ 2^126). The joint cert-ratio under fits via num ≤ 1.45·den (num_le_145_den) and den ≥ A4. Tight one-sided gap-1 reducedArg_close_under (33/(32·2^128)). Co-Authored-By: Claude Opus 4.8 (1M context) --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 570 ++++++++++++++++++ .../exp/ExpProof/ExpProof/Floor/Reduce.lean | 121 ++++ 2 files changed, 691 insertions(+) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 81a4ff563..d51a49f12 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -2335,4 +2335,574 @@ theorem r0_seam_double {x1 x2 : Nat} push_cast; linarith [hreal] exact_mod_cast this +/-! ## The deficit (under) side: per-point `2¹²⁶·exp(rt) ≤ r0 + 8` (both signs) + +Mirror of the never-over `r0_real_over_within`. The nonneg half drops the even truncation +`Ee·(2¹²⁶−r0) ≤ 0` and bounds the tod truncation; the negative half drops the tod and bounds the +even truncation. Both feed the closing-shift deficit budget `c_under < 8.43 = 2⁶³/WAD − MARGIN/WAD` +at the binding `k = 63`. -/ + +/-- **`todNumV` upper bound (nonneg half).** For `0 ≤ t`: +`todNumV(t) ≤ 2¹¹⁹³·tod + 2¹¹⁹³ + W_od·2¹⁰³⁹·t`. -/ +theorem todNumV_ub {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + evalPoly ExpCertV.todNumV (int256 (tTree x)) ≤ + 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 + 69402657 * 2 ^ 1039 * (int256 (tTree x)) := by + obtain ⟨_, _, _, htodhi⟩ := todTree_bound hx hC hC0 + obtain ⟨_, hodhi⟩ := odNumVPoly_bracket hx hC hC0 + set t := int256 (tTree x) with htdef + rw [evalTodNumV] + -- todP = 2^23·t·odpoly. t ≥ 0, odpoly ≤ 2^1042·od + W_od·2^1016 ⟹ 2^23·t·odpoly ≤ 2^23·t·(…) + have hmul : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) ≤ + 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) := by + apply mul_le_mul_of_nonneg_left _ (by positivity) + exact mul_le_mul_of_nonneg_left (le_of_lt hodhi) htnn + -- 2^23·t·(2^1042 od + W_od 2^1016) = 2^1065·(t·od) + W_od·2^1039·t ; 2^1065·(t·od) < 2^1193·tod + 2^1193 + have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi + have key : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) ≤ + 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t := by + have e1 : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) = + 2 ^ 1065 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1039 * t := by ring + have e2 : (2 : Int) ^ 1065 * ((2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128) = + 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 := by + rw [show (2:Int) ^ 1193 = 2 ^ 1065 * 2 ^ 128 from by rw [← pow_add]]; ring + rw [e1] + have h := mul_le_mul_of_nonneg_left (le_of_lt htod_hi) (by positivity : (0:Int) ≤ 2 ^ 1065) + rw [e2] at h + linarith [h] + linarith [hmul, key] + +/-- **`num ≤ 1.45·den`** (`ê ≤ 1.45`) on the nonneg half, from `exp(t/2¹²⁸) ≤ √2` and the cert. -/ +theorem num_le_145_den {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 100 * ((evTree x : Int) + int256 (todTree x)) ≤ 145 * ((evTree x : Int) - int256 (todTree x)) := by + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + set t := int256 (tTree x) with htdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + have hDElb := denExpV_lb hx hC hC0 htnn + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + have hcertlo := certLo_real htnn htdom + set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn + rw [← hEtdef] at hEtsqrt2 + have hMp_pos : (0:Real) < Mp := by rw [hMpdef]; positivity + have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by + have hc : ((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + rw [hMpdef] + have key : (NE : Real) / (DE : Real) = + ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) * + (((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real))) := by + push_cast; field_simp; ring + rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) + -- num bound: 2^1193·num ≤ NE, DE < 2^1193·den + 3·2^1193 + obtain ⟨hnumlo, _⟩ := numExpV_bracket hx hC hC0 htnn + obtain ⟨_, hdenhi⟩ := denExpV_bracket hx hC hC0 htnn + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ den := den_ge_072 hx hC hC0 + have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden072 + have hdenR : (0:Real) < (den : Real) := by exact_mod_cast hdenpos + have hden072R : (61251667550081741634933722430035858604 : Real) ≤ (den : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hden072; push_cast at this; linarith [this] + have hnumloR : (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hnumlo; push_cast at this; linarith [this] + have hdenhiR : (DE : Real) < (2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193 := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hdenhi; push_cast at this; linarith [this] + have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by + rw [Real.sqrt_le_iff]; constructor <;> norm_num + have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ + have hMp_le : Mp ≤ 14144 / 14143 := by + rw [hMpdef, div_le_div_iff₀ (by norm_num) (by norm_num)] + have h130 : (14144 : Real) ≤ 2 ^ 130 := by + rw [show (2:Real) ^ 130 = 1361129467683753853853498429727072845824 from by norm_num]; norm_num + nlinarith [h130] + have hsM_le : Real.sqrt 2 * Mp ≤ 14144 / 10000 := by + have hMpnn : (0:Real) ≤ Mp := by rw [hMpdef]; positivity + calc Real.sqrt 2 * Mp ≤ (14143 / 10000) * (14144 / 14143) := + mul_le_mul hsqrt2_val hMp_le hMpnn (by norm_num) + _ = 14144 / 10000 := by norm_num + -- NE ≤ √2·Mp·DE ≤ (14144/10000)·DE + have hNE_le : (NE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by + have h1 : (NE : Real) ≤ Et * Mp * (DE : Real) := by + have := mul_le_mul_of_nonneg_right hNEDE_le (le_of_lt hDEpos) + rwa [div_mul_cancel₀ _ (ne_of_gt hDEpos)] at this + have h2 : Et * Mp * (DE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by + apply mul_le_mul_of_nonneg_right _ (le_of_lt hDEpos) + exact mul_le_mul_of_nonneg_right hEtsqrt2 (le_of_lt hMp_pos) + linarith [h1, h2] + -- num ≤ (14144/10000)·(den+3) + have hnum_le : (num : Real) ≤ (14144 / 10000) * ((den : Real) + 3) := by + have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity + rw [← mul_le_mul_left hp] + calc (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := hnumloR + _ ≤ Real.sqrt 2 * Mp * (DE : Real) := hNE_le + _ ≤ (14144 / 10000) * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := by + calc Real.sqrt 2 * Mp * (DE : Real) + ≤ (14144 / 10000) * (DE : Real) := mul_le_mul_of_nonneg_right hsM_le (le_of_lt hDEpos) + _ ≤ (14144 / 10000) * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := + mul_le_mul_of_nonneg_left (le_of_lt hdenhiR) (by norm_num) + _ = (2 ^ 1193 : Real) * ((14144 / 10000) * ((den : Real) + 3)) := by ring + -- 100·num ≤ 145·den as Real: 100·(14144/10000)(den+3) ≤ 145·den ⟺ den huge + have hkey : (100 : Real) * (num : Real) ≤ 145 * (den : Real) := by + have h1 : (100 : Real) * (num : Real) ≤ 100 * ((14144 / 10000) * ((den : Real) + 3)) := + mul_le_mul_of_nonneg_left hnum_le (by norm_num) + nlinarith [h1, hden072R] + have : ((100 * num : Int) : Real) ≤ ((145 * den : Int) : Real) := by push_cast; linarith [hkey] + exact_mod_cast this + +/-- `r0` is bracketed on the nonneg half: `2¹²⁶ ≤ r0 ≤ 1.45·2¹²⁶` (so `2¹²⁶+r0 ≤ 2.45·2¹²⁶`). -/ +theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (2 : Int) ^ 126 ≤ int256 (r0Tree x) ∧ + 100 * (int256 (r0Tree x)) ≤ 145 * 2 ^ 126 := by + obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + have h145 := num_le_145_den hx hC hC0 htnn + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 + -- tod ≥ 0 on nonneg half + have htodnn : (0:Int) ≤ tod := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have htod : (2 ^ 128 : Int) * tod ≤ int256 (tTree x) * (odTree x : Int) := htodlo + have hpos : (0:Int) ≤ int256 (tTree x) * (odTree x : Int) := mul_nonneg htnn hodnn + nlinarith [htod, hpos] + refine ⟨?_, ?_⟩ + · -- 2^126 ≤ r0: 2^126·num < (r0+1)·den, num ≥ den ⟹ 2^126·den < (r0+1)·den ⟹ 2^126 < r0+1 + have hnumden : (2:Int)^126 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := by nlinarith [htodnn] + have h : (2:Int)^126 * (ev - tod) < (r0 + 1) * (ev - tod) := lt_of_le_of_lt hnumden hfloor_hi + have := lt_of_mul_lt_mul_right h (le_of_lt hdenpos) + omega + · -- 100·r0 ≤ 145·2^126: 100·r0·den ≤ 100·2^126·num ≤ 2^126·145·den + have h1 : 100 * (r0 * (ev - tod)) ≤ 100 * (2 ^ 126 * (ev + tod)) := + mul_le_mul_of_nonneg_left hfloor_lo (by norm_num) + have h2 : (2:Int)^126 * (100 * (ev + tod)) ≤ 2 ^ 126 * (145 * (ev - tod)) := + mul_le_mul_of_nonneg_left h145 (by positivity) + have hchain : 100 * r0 * (ev - tod) ≤ 145 * 2 ^ 126 * (ev - tod) := by nlinarith [h1, h2] + exact le_of_mul_le_mul_right hchain hdenpos + +/-- **Joint cert-ratio under (nonneg half):** `2¹²⁶·NE − r0·DE ≤ 7·DE`. The shared even truncation +`Ee·(2¹²⁶−r0) ≤ 0` (since `r0 ≥ 2¹²⁶`) is dropped; the floor `2¹²⁶·num − r0·den < den` gives the +`2¹¹⁹³·den` term, and the binding tod truncation `Et' ≤ (2¹¹⁹³ + W_od·2¹⁰³⁹·t)·(2¹²⁶+r0)` is small +because `t ≤ H128` is far below `2¹²⁸`. -/ +theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ + 7 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hevlo, _⟩ := evNumVPoly_bracket hx hC hC0 + have htodub := todNumV_ub hx hC hC0 htnn + obtain ⟨hr0lo, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn + obtain ⟨hdenlo, _⟩ := denExpV_bracket hx hC hC0 htnn + have hDElb := denExpV_lb hx hC hC0 htnn + rw [evalNumExpV, evalDenExpV] + set t := int256 (tTree x) with htdef + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set evP := evalPoly ExpCertV.evNumVPoly t with hevP + set todP := evalPoly ExpCertV.todNumV t with htodP + set DE := evP - todP with hDEdef + -- 2^126·NE − r0·DE = evP·(2^126−r0) + todP·(2^126+r0) + -- = 2^1193·[2^126·num − r0·den] + Ee·(2^126−r0) + Et'·(2^126+r0) + -- ≤ 2^1193·den + 0 + (2^1193 + W·2^1039·t)·(2^126+r0) + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 + have h2126r0_np : (2:Int) ^ 126 - r0 ≤ 0 := by linarith [hr0lo] + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by positivity + -- evP·(2^126−r0) ≤ 2^1193·ev·(2^126−r0) (evP ≥ 2^1193·ev, factor ≤ 0) + have hterm1 : evP * (2 ^ 126 - r0) ≤ 2 ^ 1193 * ev * (2 ^ 126 - r0) := + mul_le_mul_of_nonpos_right hevlo h2126r0_np + -- todP·(2^126+r0) ≤ (2^1193·tod + 2^1193 + W·2^1039·t)·(2^126+r0) (todP upper, factor ≥ 0) + have hterm2 : todP * (2 ^ 126 + r0) ≤ + (2 ^ 1193 * tod + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := + mul_le_mul_of_nonneg_right htodub hr0p_nn + -- floor: 2^126·num − r0·den < den, scaled by 2^1193: 2^1193·(2^126·num − r0·den) < 2^1193·den + have hfloor_lt : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) < (ev - tod) := by linarith [hfloor_hi] + have hfloor1193 : (2 ^ 1193 : Int) * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) < + 2 ^ 1193 * (ev - tod) := by + have := mul_lt_mul_of_pos_left hfloor_lt (by positivity : (0:Int) < 2 ^ 1193); linarith [this] + -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + (2^1193 + W·2^1039·t)·(2^126+r0) + have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ + 2 ^ 1193 * (ev - tod) + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by + rw [hDEdef]; nlinarith [hterm1, hterm2, hfloor1193] + -- now bound the RHS ≤ 6·DE. + -- (A) 2^1193·den ≤ DE + 32·2^1193 (denExpV hi), and 32·2^1193 ≤ DE (DE > 2^1317): 2^1193·den ≤ 2·DE + have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 32 * 2 ^ 1193 := by + rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] + have h32 : (32 : Int) * 2 ^ 1193 ≤ DE := by + have hD1317 : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] + have : (32 : Int) * 2 ^ 1193 < 2 ^ 1317 := by + rw [show (32:Int) * 2 ^ 1193 = 2 ^ 1198 from by rw [show (32:Int)=2^5 from by norm_num, ← pow_add]] + exact pow_lt_pow_right₀ (by norm_num) (by norm_num) + linarith [this, hD1317] + have hAterm : 2 ^ 1193 * (ev - tod) ≤ 2 * DE := by linarith [hden2, h32] + -- (B) (2^1193 + W·2^1039·t)·(2^126+r0) ≤ 4·DE. bound via t ≤ H128, 2^126+r0 ≤ 2.45·2^126. + have hDElb' : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have htH : t ≤ 117932881612756647068972071382077242199 := hthi + -- 2^126 + r0 ≤ 2.45·2^126, i.e. 100·(2^126+r0) ≤ 245·2^126 + have hr0p_bound : 100 * (2 ^ 126 + r0) ≤ 245 * 2 ^ 126 := by linarith [hr0hi145] + have hBterm : (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) ≤ 5 * DE := by + have hDEden : 2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193 ≤ DE := by + rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] + have hden_lo : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + -- 2^1193 + W·2^1039·t ≤ 2^1193 + W·2^1039·H128 (t ≤ H128, t ≥ 0) + have hcoeff : 2 ^ 1193 + 69402657 * 2 ^ 1039 * t ≤ + 2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199 := by + have := mul_le_mul_of_nonneg_left htH (by positivity : (0:Int) ≤ 69402657 * 2 ^ 1039); linarith [this] + have hC0nn : (0:Int) ≤ 2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199 := by positivity + have hLHS : (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) ≤ + (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0) := + mul_le_mul_of_nonneg_right hcoeff hr0p_nn + -- 100·(C0·(2^126+r0)) ≤ C0·245·2^126 + have hLHS2 : 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) ≤ + (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := by + have := mul_le_mul_of_nonneg_left hr0p_bound hC0nn; nlinarith [this] + -- key integer cert (common 2^1165 scale): C0·245·2^126 ≤ 500·(2^1193·(den−32)). + have hkey : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) ≤ + 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by + -- factor everything to the common 2^1165 scale and compare coefficients + have hA : (2:Int) ^ 1193 * 2 ^ 126 = 2 ^ 154 * 2 ^ 1165 := by rw [← pow_add, ← pow_add] + have hpe2 : (2:Int) ^ 1039 * 2 ^ 126 = 2 ^ 1165 := by rw [← pow_add] + have hpe3 : (2:Int) ^ 1193 = 2 ^ 28 * 2 ^ 1165 := by rw [← pow_add] + have hp : (0:Int) < (2:Int) ^ 1165 := by positivity + -- the coefficient inequality, scaled by 2^1165 + have hcoeff_le : (245 * 2 ^ 154 + 245 * 69402657 * 117932881612756647068972071382077242199 : Int) ≤ + 500 * 2 ^ 28 * ((ev - tod) - 32) := by + have h154 : (2:Int)^154 = 22835963083295358096932575511191922182123945984 := by norm_num + have h28 : (2:Int)^28 = 268435456 := by norm_num + rw [h154, h28]; nlinarith [hden_lo] + have hscaled := mul_le_mul_of_nonneg_right hcoeff_le (le_of_lt hp) + -- rewrite both sides to the (·)·2^1165 form + calc (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) + = (245 * 2 ^ 154 + 245 * 69402657 * 117932881612756647068972071382077242199) * 2 ^ 1165 := by + linear_combination (245 : Int) * hA + (245 * 69402657 * 117932881612756647068972071382077242199 : Int) * hpe2 + _ ≤ (500 * 2 ^ 28 * ((ev - tod) - 32)) * 2 ^ 1165 := hscaled + _ = 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by + linear_combination (-500 * ((ev - tod) - 32) : Int) * hpe3 + nlinarith [hLHS, hLHS2, hkey, hDEden] + linarith [hcombine, hAterm, hBterm] + +/-- **The joint per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 8`. From the joint +cert-ratio under (`2¹²⁶·NE − r0·DE ≤ 7·DE`), the not-too-below cert (`exp ≤ (NE/DE)·M⁺`), and the +under-direction gap-1 (`exp(rt) ≤ √2`, `rt − t/2¹²⁸ < 33/(32·2¹²⁸)`). -/ +theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + have hunder := r0_certRatio_under_nonneg hx hC hC0 htnn + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + set t := int256 (tTree x) with htdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + have hDElb := denExpV_lb hx hC hC0 htnn + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + set r0 := int256 (r0Tree x) with hr0def + -- 2^126·NE/DE ≤ r0 + 7 + have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ 7 * (DE : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] + have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 7 := by + rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos] + -- certUp: exp(t/2^128) ≤ (NE/DE)·Mpp + have hcertup := certUp_real htnn htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by + have := certNE_nonneg htnn htdom; exact_mod_cast this + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef + have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mpp := by + have hc : Et ≤ ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real)) := hcertup + rw [hMppdef] + have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) = + ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 130 : Int) : Real) * (DE : Real)) := by + push_cast; field_simp; ring + rw [key]; exact hc + have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) + have hMpp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp + -- Et ≤ √2 (nonneg half) + have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn + rw [← hEtdef] at hEtsqrt2 + have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num + have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ + -- 2^126·Et ≤ 2^126·(NE/DE)·Mpp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mpp−1) ≤ (r0+7) + 1/4 + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 7 + 3 / 10 := by + have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) := + mul_le_mul_of_nonneg_left hEt_le (by positivity) + have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) = + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) := by ring + -- 2^126·(NE/DE)·(Mpp−1) ≤ 3/10. NE/DE·2^126 ≤ r0+7 ≤ 2^128+7; ·(1/2^130) ≈ 1/4 < 3/10. + have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) ≤ 3 / 10 := by + rw [hMpp1] + obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 + have hr0R : (r0 : Real) < (2 ^ 128 : Real) := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi + rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h + have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn + have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 7 := by + linarith [hr0_ge, hr0R] + calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / (2 ^ 130 : Real)) + ≤ ((2 ^ 128 : Real) + 7) * (1 / (2 ^ 130 : Real)) := + mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) + _ ≤ 3 / 10 := by norm_num + linarith [h1, h2 ▸ h1, h3, hr0_ge] + -- gap-1 (under, tight): Ert − Et ≤ (rt − t/2^128)·Ert, rt − t/2^128 < 33/(32·2^128), Ert ≤ 2 + set Ert := Real.exp (reducedArg x) with hErtdef + have hgapunder := reducedArg_close_under hx hC hC0 + have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ + have hErt_le_two := exp_reducedArg_le_two hx hC hC0 + rw [← hErtdef] at hErt_le_two + have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) + have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 6 / 10 := by + have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := + le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) + have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := + mul_le_mul_of_nonneg_left hgap (by positivity) + have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ + (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) + have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) ≤ 6 / 10 := by norm_num + linarith [h1, h2, h3] + -- assemble: 2^126·Ert = 2^126·Et + 2^126·(Ert−Et) ≤ (r0+7+1/4) + 6/10 < r0 + 8 + have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 8 + linarith [hEt_bound, hgap126, hdist] + +/-- `r0 ≤ 2¹²⁶` on the negative half (num ≤ den ⟺ tod ≤ 0). -/ +theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + int256 (r0Tree x) ≤ 2 ^ 126 := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 + have htodnp : tod ≤ 0 := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn + nlinarith [htodlo, this] + -- r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den) + have hnumden : r0 * (ev - tod) ≤ 2 ^ 126 * (ev - tod) := by + have h1 : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo + nlinarith [h1, htodnp, (by positivity : (0:Int) ≤ (2:Int)^126)] + exact le_of_mul_le_mul_right hnumden hdenpos + +/-- **Joint cert-ratio under (negative half):** `2¹²⁶·NE − r0·DE ≤ 6·DE`. The binding even +truncation `Ee·(2¹²⁶−r0)` (small factor) and the tod truncation `Et'·(2¹²⁶+r0)` both fit. -/ +theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ + 7 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 + obtain ⟨_, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg + have hr0le := r0_le_2126_neg hx hC hC0 htneg + obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 + obtain ⟨hdenlo, _⟩ := denExpV_bracket_neg hx hC hC0 htneg + have hDElb := denExpV_lb_neg hx hC hC0 htneg + rw [evalNumExpV, evalDenExpV] + set t := int256 (tTree x) with htdef + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set evP := evalPoly ExpCertV.evNumVPoly t with hevP + set todP := evalPoly ExpCertV.todNumV t with htodP + set DE := evP - todP with hDEdef + have hden_lo : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + -- on the neg half tod ≤ 0, so den = ev − tod ≥ ev ≥ A4 + have htod_np : tod ≤ 0 := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have : t * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn + nlinarith [htodlo, this] + have hden_A4 : (103786963415199049567855548359006885036 : Int) ≤ ev - tod := by + obtain ⟨hevlo', _⟩ := evTree_facts (vTree_eq hx hC hC0).2 + have hev : (103786963415199049567855548359006885036 : Int) ≤ ev := by + rw [hevdef]; have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo' + rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 from by norm_num] at this + exact this + linarith [hev, htod_np] + have h2126r0_nn : (0:Int) ≤ 2 ^ 126 - r0 := by linarith [hr0le] + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by positivity + -- Ee = evP − 2^1193·ev ∈ [0, W_ev). evP·(2^126−r0) ≤ (2^1193·ev + W_ev)·(2^126−r0) + have hterm1 : evP * (2 ^ 126 - r0) ≤ (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) := + mul_le_mul_of_nonneg_right (le_of_lt hevhi) h2126r0_nn + -- Et' = todP − 2^1193·tod < 2·2^1193 ⟹ todP < 2^1193·tod + 2·2^1193; todP·(2^126+r0) ≤ (2^1193·tod+2·2^1193)·(2^126+r0) + have hterm2 : todP * (2 ^ 126 + r0) ≤ (2 ^ 1193 * tod + 2 * 2 ^ 1193) * (2 ^ 126 + r0) := + mul_le_mul_of_nonneg_right (le_of_lt htodhi) hr0p_nn + -- floor: 2^126·num − r0·den < den ⟹ 2^1193·(2^126·num − r0·den) < 2^1193·den + have hfloor_lt : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) < (ev - tod) := by linarith [hfloor_hi] + have hfloor1193 : (2 ^ 1193 : Int) * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) < + 2 ^ 1193 * (ev - tod) := by + have := mul_lt_mul_of_pos_left hfloor_lt (by positivity : (0:Int) < 2 ^ 1193); linarith [this] + -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + W_ev·(2^126−r0) + 2·2^1193·(2^126+r0) + have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ + 2 ^ 1193 * (ev - tod) + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by + rw [hDEdef]; nlinarith [hterm1, hterm2, hfloor1193] + -- bound RHS by 6·DE. DE ≥ 2^1193·(den−2), den ≥ den_lo. + have hDEden : 2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193 ≤ DE := by + rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] + -- (A) 2^1193·den ≤ DE + 2·2^1193 ≤ 2·DE (32·2^1193... no, 2·2^1193 ≤ DE since DE>2^1317) + have hD1317 : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] + have h2 : (2 : Int) * 2 ^ 1193 ≤ DE := by + have he : (2 : Int) * 2 ^ 1193 = 2 ^ 1194 := by rw [show (1194:Nat) = 1193 + 1 from rfl, pow_succ]; ring + have : (2 : Int) * 2 ^ 1193 < 2 ^ 1317 := by + rw [he]; exact pow_lt_pow_right₀ (by norm_num) (by norm_num) + linarith [this, hD1317] + have hAterm : 2 ^ 1193 * (ev - tod) ≤ 2 * DE := by + have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 2 * 2 ^ 1193 := by linarith [hDEden] + linarith [hden2, h2] + -- (B) W_ev·(2^126−r0) ≤ 2·DE (2^126−r0 ≤ 2^126; W_ev·2^126 = 1130577·2^1299; vs 2·DE ≥ 2·2^1193·(den−2)) + have hBterm : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1 * DE := by + have hle : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1130577 * 2 ^ 1173 * 2 ^ 126 := + mul_le_mul_of_nonneg_left (by linarith [hr0lo]) (by positivity) + -- 1130577·2^1173·2^126 = 1130577·2^1299 ; DE ≥ 2^1193·(den−2); 1130577·2^106 ≤ (den−2) + have hkey : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 ≤ 1 * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) := by + have hA : (2:Int) ^ 1173 * 2 ^ 126 = 2 ^ 106 * 2 ^ 1193 := by rw [← pow_add, ← pow_add] + have hp : (0:Int) < (2:Int) ^ 1193 := by positivity + have heL : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 = (1130577 * 2 ^ 106) * 2 ^ 1193 := by + have e : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 = 1130577 * (2 ^ 1173 * 2 ^ 126) := by ring + rw [e, hA]; ring + have heR : (1 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (1 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring + rw [heL, heR, mul_le_mul_right hp] + have h106 : (2:Int)^106 = 81129638414606681695789005144064 := by norm_num + rw [h106]; nlinarith [hden_A4] + linarith [hle, hkey] + -- (C) 2·2^1193·(2^126+r0) ≤ 2·DE. (2^126+r0) ≤ 2·2^126 (r0 ≤ 2^126); 2·2^1193·2·2^126 = 4·2^1319; vs 2·DE. + have hCterm : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 4 * DE := by + have hle : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 2 * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) := + mul_le_mul_of_nonneg_left (by linarith [hr0le]) (by positivity) + have hkey : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) ≤ 4 * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) := by + have hA : (2:Int) ^ 1193 * 2 ^ 126 = 2 ^ 1319 := by rw [← pow_add] + have hp : (0:Int) < (2:Int) ^ 1193 := by positivity + -- LHS = 2·2^1193·2·2^126 = 4·2^1319 = (4·2^126)·2^1193; RHS = 2·((den)−2)·2^1193 + have heL : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) = (4 * 2 ^ 126) * 2 ^ 1193 := by ring + have heR : (4 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (4 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring + rw [heL, heR, mul_le_mul_right hp] + have h126 : (2:Int)^126 = 85070591730234615865843651857942052864 := by norm_num + rw [h126]; nlinarith [hden_A4] + linarith [hle, hkey] + linarith [hcombine, hAterm, hBterm, hCterm] + +/-- **Per-point deficit (tight, negative half).** `2¹²⁶·exp(rt) ≤ r0 + 8` for `t ≤ 0`. -/ +theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + have hunder := r0_certRatio_under_neg hx hC hC0 htneg + have htdom := tdom_neg hx hC hC0 htneg + set t := int256 (tTree x) with htdef + have hDElb := denExpV_lb_neg hx hC hC0 htneg + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + set r0 := int256 (r0Tree x) with hr0def + have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ 7 * (DE : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] + have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 7 := by + rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos] + -- certUp_real_neg: exp(t/2^128) ≤ (NE/DE)·Mp, Mp = 2^130/(2^130−1) + have hcu := certUp_real_neg htneg htdom + obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos + exact_mod_cast this + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mp := by + rw [hMpdef] + have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) = + ((2 ^ 130 : Int) : Real) * (NE : Real) / (((2 ^ 130 - 1 : Int) : Real) * (DE : Real)) := by + push_cast; field_simp; ring + rw [key]; exact hcu + have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) + have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp + -- 2^126·Et ≤ 2^126·(NE/DE)·Mp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mp−1) ≤ (r0+6) + 1/4 + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 7 + 3 / 10 := by + have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := + mul_le_mul_of_nonneg_left hEt_le (by positivity) + have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) := by ring + have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) ≤ 3 / 10 := by + rw [hMp1] + obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 + have hr0R : (r0 : Real) < (2 ^ 128 : Real) := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi + rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h + have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn + have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 7 := by + linarith [hr0_ge, hr0R] + calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / ((2 ^ 130 : Real) - 1)) + ≤ ((2 ^ 128 : Real) + 7) * (1 / ((2 ^ 130 : Real) - 1)) := + mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) + _ ≤ 3 / 10 := by norm_num + linarith [h1, h2 ▸ h1, h3, hr0_ge] + -- gap-1 (under, tight) + set Ert := Real.exp (reducedArg x) with hErtdef + have hgapunder := reducedArg_close_under hx hC hC0 + have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ + have hErt_le_two := exp_reducedArg_le_two hx hC hC0 + rw [← hErtdef] at hErt_le_two + have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) + have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 6 / 10 := by + have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := + le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) + have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := + mul_le_mul_of_nonneg_left hgap (by positivity) + have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ + (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) + have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) ≤ 6 / 10 := by norm_num + linarith [h1, h2, h3] + have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 8 + linarith [hEt_bound, hgap126, hdist] + +/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 8`. -/ +theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg + · exact r0_real_under_tight hx hC hC0 htnn + · exact r0_real_under_tight_neg hx hC hC0 (le_of_lt htneg) + end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean index c3dfe4ed0..0eddcbcec 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean @@ -178,6 +178,127 @@ theorem reducedArg_close_over {x : Nat} (hx : x < 2 ^ 256) linarith [hP1.1, hP2.1] linarith [h12lo, hP3_lo] +/-- **Reduced-argument tight under bound (gap-1, one-sided).** The deficit direction: the integer +`t`-rounding residual `P3 ∈ [0, 1/2¹²⁸)` and the `ln2`-grid/rational errors `P1 + P2 < 1/(32·2¹²⁸)` +give `rt − t/2¹²⁸ < 33/(32·2¹²⁸)`. This is the gap-1 contribution the joint deficit budget +consumes (tighter than the symmetric `9/(8·2¹²⁸) = 36/(32·2¹²⁸)`). -/ +theorem reducedArg_close_under {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + reducedArg x - (int256 (tTree x) : Real) / (2 ^ 128 : Real) < 33 / (32 * (2 ^ 128 : Real)) := by + obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 + obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 + obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 + have hln2lo := ln2_lower + have hln2hi := ln2_upper + set t : Int := int256 (tTree x) with htdef + set k : Int := int256 (kTree x) with hkdef + set X : Int := int256 x with hXdef + have hK : (0x279d346de4781f921dd7a89933d54d1f72928 : Int) = 55213970774324510299478046898216203619608872 := by norm_num + have hL : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num + rw [hK, hL] at htlo hthi + have hLN2decimal : ((LN2c : Nat) : Real) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by + unfold LN2c; norm_num + rw [hLN2decimal] at hln2lo hln2hi + set LR : Real := Real.log 2 with hLRdef + set XR : Real := (X : Real) with hXRdef + set kR : Real := (k : Real) with hkRdef + set tR : Real := (t : Real) with htRdef + set N235 : Real := (2 ^ 235 : Real) with hN235 + set N128 : Real := (2 ^ 128 : Real) with hN128 + set LN2R : Real := (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) with hLN2R + set K27R : Real := (55213970774324510299478046898216203619608872 : Real) with hK27R + have hp235 : (0 : Real) < N235 := by rw [hN235]; positivity + have hp128 : (0 : Real) < N128 := by rw [hN128]; positivity + have hpRAY : (0 : Real) < (10 ^ 27 : Real) := by positivity + have hsplit : N235 = N128 * 2 ^ 107 := by rw [hN235, hN128, ← pow_add] + set P1 : Real := XR * (1 / (10 ^ 27 : Real) - K27R / N235) with hP1def + set P2 : Real := kR * (LN2R / N235 - LR) with hP2def + set P3 : Real := (K27R * XR - LN2R * kR) / N235 - tR / N128 with hP3def + have hident : XR / (10 ^ 27 : Real) - kR * LR - tR / N128 = P1 + P2 + P3 := by + rw [hP1def, hP2def, hP3def]; ring + have hXloR : -(79228162514264337593543950336 : Real) < XR := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hxlo; rw [hXRdef] + rw [show ((2:Int)^96 : Int) = 79228162514264337593543950336 from by norm_num] at this + push_cast at this; linarith [this] + have hXhiR : XR < (79228162514264337593543950336 : Real) := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hxhi; rw [hXRdef] + rw [show ((2:Int)^96 : Int) = 79228162514264337593543950336 from by norm_num] at this + push_cast at this; linarith [this] + have hcoeff_eq : (1 / (10 ^ 27 : Real) - K27R / N235) = + -((K27R * (10 ^ 27 : Real) - N235) / (N235 * (10 ^ 27 : Real))) := by + rw [hK27R, hN235]; field_simp; ring + have hcoeff_num : K27R * (10 ^ 27 : Real) - N235 = 222636907558699806209605632 := by + rw [hK27R, hN235]; norm_num + have hP1_abs : |P1| < 1 / (64 * N128) := by + rw [hP1def, hcoeff_eq, hcoeff_num, abs_mul] + have hden_pos : (0 : Real) < N235 * (10 ^ 27 : Real) := by positivity + have hco_abs : |(-(222636907558699806209605632 / (N235 * (10 ^ 27 : Real))))| = + 222636907558699806209605632 / (N235 * (10 ^ 27 : Real)) := by + rw [abs_neg, abs_of_pos (by positivity)] + rw [hco_abs] + have hX_abs : |XR| < 79228162514264337593543950336 := abs_lt.mpr ⟨hXloR, hXhiR⟩ + have hco_pos : (0:Real) < 222636907558699806209605632 / (N235 * (10 ^ 27 : Real)) := by positivity + calc |XR| * (222636907558699806209605632 / (N235 * (10 ^ 27 : Real))) + < 79228162514264337593543950336 * (222636907558699806209605632 / (N235 * (10 ^ 27 : Real))) := + (mul_lt_mul_right hco_pos).mpr hX_abs + _ = 79228162514264337593543950336 * 222636907558699806209605632 / + (N235 * (10 ^ 27 : Real)) := by rw [mul_div_assoc] + _ < 1 / (64 * N128) := by + rw [hN235, hN128, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num + have hP2_lo : LN2R / N235 - LR ≤ 0 := by linarith [hln2lo] + have hP2_hi : -(1 / N235) ≤ LN2R / N235 - LR := by + have : LR ≤ (LN2R + 1) / N235 := hln2hi + rw [add_div] at this; linarith [this] + have hkloR : -(61 : Real) ≤ kR := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] + have hkhiR : kR ≤ (63 : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] + have hP2_abs : |P2| < 1 / (64 * N128) := by + rw [hP2def] + have h1 : |kR| ≤ 63 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by + rw [abs_le] + refine ⟨by linarith [hP2_hi], ?_⟩ + have hpos : (0:Real) ≤ 1 / N235 := by positivity + linarith [hP2_lo, hpos] + have hbound : |kR * (LN2R / N235 - LR)| ≤ 63 * (1 / N235) := by + rw [abs_mul] + exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) + have hlt : 63 * (1 / N235) < 1 / (64 * N128) := by + rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num + linarith [hbound, hlt] + have hP3int_hi : 55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t < 2 ^ 107 := by omega + have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 107 * tR < 2 ^ 107 := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hP3int_hi + rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] + push_cast at h; linarith [h] + have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 107 * tR) / N235 := by + rw [hP3def, hsplit]; field_simp; ring + have hP3_hi : P3 < 1 / N128 := by + rw [hP3eq, hsplit, div_lt_div_iff₀ (by positivity) (by positivity)] + nlinarith [hnumR_hi, hp128] + -- assemble: rt − t/2^128 = P1+P2+P3 < 1/(32 N128) + 1/N128 = 33/(32 N128) + have hP1 := abs_lt.mp hP1_abs + have hP2 := abs_lt.mp hP2_abs + clear_value N128 N235 + have he12 : (1 : Real) / (64 * N128) + 1 / (64 * N128) = 1 / (32 * N128) := by + field_simp; ring + have h1_32N : (1 : Real) / (32 * N128) + 1 / N128 = 33 / (32 * N128) := by + field_simp; ring + have hredeq : reducedArg x = XR / (10 ^ 27 : Real) - kR * LR := rfl + have hident' : (reducedArg x - tR / N128) = P1 + P2 + P3 := by + rw [hredeq]; linarith [hident] + rw [hident'] + have h12 : P1 + P2 < 1 / (32 * N128) := by rw [← he12]; linarith [hP1.2, hP2.2] + rw [← h1_32N]; linarith [h12, hP3_hi] + +/-- info: 'ExpYul.reducedArg_close_under' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms reducedArg_close_under + /-- **Reduced-argument real bound (gap-1).** On the meaningful region the reduced argument `rt` agrees with `t/2¹²⁸` to within `9/(8·2¹²⁸)` (the integer `t`-rounding sandwich `[0, 1/2¹²⁸)` dominates; the rational and `ln2`-grid errors are below `2⁻¹³²`). -/ From 5d32b5a11220b53eb2f36a86f57eb1e21d9c0404 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:55:57 +0200 Subject: [PATCH 077/149] Make exp global floor brackets hypothesis-free; reduce central exact floor to central exactness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit accumReal_over/accumReal_under (Floor/R0BoundHolds.lean) discharge the never-over and deficit-under-one accumulator fields by folding the per-point r0_real_over_within/r0_real_under_within brackets onto the target via target_octave_fold (E·2^s = WAD·2^126·exp(rt), s = 126 − k), using WAD·19/25 ≤ MARGIN (over) and 8·WAD + MARGIN < 2^63 ≤ 2^s (under). run_exp_ray_to_wad_evm_floorOrOneLess_uncond and run_exp_ray_to_wad_evm_underByAtMostOne_uncond (Floor/PublicUncond.lean) drop the RuntimeAccumBound hypothesis. The central-octave exact-floor theorem reduces to CentralExactness, the central exactness inequality E < r1Tree x + 1 on [−H, H). All gated in Theorems.lean, each #print axioms = [propext, Classical.choice, Quot.sound]. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../ExpProof/ExpProof/Floor/PublicUncond.lean | 112 ++++++++++++++++++ .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 99 ++++++++++++++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 58 +++++++++ 3 files changed, 269 insertions(+) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean create mode 100644 formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean b/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean new file mode 100644 index 000000000..dfec066bf --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean @@ -0,0 +1,112 @@ +import ExpProof.Floor.Public +import ExpProof.Floor.R0BoundHolds + +/-! +# Hypothesis-free global floor brackets for the compiled runtime + +The global floor-or-one-less and one-unit underestimation brackets consume only the +never-over/deficit/below-clamp facts (`accumReal_over`, `accumReal_under`, +`belowC_target_lt_two`). They become hypothesis-free here. + +The central-octave exact-floor bracket additionally needs `CentralExactness`: the obligation +`E < r1Tree x + 1` on `[−H, H)`. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Word +open ExpRealSpec + +noncomputable section + +set_option maxRecDepth 100000 + +/-- **Global floor-or-one-less bracket.** For every signed input strictly below the supported +threshold the runtime result `r` satisfies the 2-wide never-over bracket `r ≤ E ∧ E < r + 2`. -/ +theorem run_exp_ray_to_wad_evm_floorOrOneLess_uncond (x : Nat) (hx : x < 2 ^ 256) + (hC0 : int256 x < int256 C0thresh) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ FloorOrOneLessBracket (int256 x) (int256 r) := by + refine ⟨expTree x, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hx hC0), ?_⟩ + by_cases hC : int256 Cmask < int256 x + · by_cases hz : x = 0 + · subst hz + have he : expTree 0 = 1000000000000000000 := by + have := run_exp_ray_to_wad_evm_zero + rw [run_exp_ray_to_wad_evm_eq_expTree 0 (domain_of_below_C0 hx hC0)] at this + exact Except.ok.inj this.symm + rw [he] + have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by + rw [int256_of_lt (by norm_num)]; norm_num + have hi0 : int256 (0 : Nat) = (0 : Int) := rfl + rw [h0, hi0]; exact floorOrOneLess_zero + · rw [int256_expTree_region_ne_zero hx hC hC0 hz] + exact floorOrOneLessBracket_region_uncond hx hC hC0 + · push_neg at hC + have hle : int256 (u256 x) ≤ int256 (u256 Cmask) := by + rw [u256_of_lt hx, u256_of_lt Cmask_lt]; exact hC + have hle' : int256 x ≤ int256 Cmask := by + rw [u256_of_lt hx, u256_of_lt Cmask_lt] at hle; exact hle + rw [expTree_eq_zero_of_le hle] + have hz0 : int256 (0 : Nat) = 0 := rfl + rw [hz0] + refine ⟨?_, ?_⟩ + · rw [Int.cast_zero] + have hpos : (0 : Real) ≤ expRayToWadTarget (int256 x) := by + unfold expRayToWadTarget + have := Real.exp_pos ((int256 x : Real) / (RAY : Real)) + positivity + exact hpos + · have := belowC_target_lt_two hle' + rw [Int.cast_zero]; linarith [this] + +/-- **One-unit underestimation bound (global).** `⌊E⌋ − 1 ≤ r`. -/ +theorem run_exp_ray_to_wad_evm_underByAtMostOne_uncond (x : Nat) (hx : x < 2 ^ 256) + (hC0 : int256 x < int256 C0thresh) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ UnderByAtMostOne (int256 x) (int256 r) := by + obtain ⟨r, hrun, hbr⟩ := run_exp_ray_to_wad_evm_floorOrOneLess_uncond x hx hC0 + exact ⟨r, hrun, floorOrOneLess_to_underByAtMostOne hbr⟩ + +/-! ## Central-octave exact floor from central exactness + +The central exactness obligation states that on `[−H, H)` the runtime body satisfies +`E < r1Tree x + 1`, which completes the exact-floor bracket together with the already proved +never-over and floor facts. -/ + +/-- The central-exactness obligation (`E < r1Tree x + 1` on the core octave). -/ +def CentralExactness : Prop := + ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → + -H ≤ int256 x → int256 x < H → + expRayToWadTarget (int256 x) < (int256 (r1Tree x) : Real) + 1 + +/-- **Central-octave exact floor, given central exactness.** On `x ∈ [−H, H)` the runtime result is +the exact floor `r = ⌊E⌋`. The never-over and floor facts are hypothesis-free; only the upper +exactness `E < r + 1` is assumed. -/ +theorem run_exp_ray_to_wad_evm_exactFloor_of_centralExactness + (hcentral : CentralExactness) (x : Nat) (hx : x < 2 ^ 256) + (hlo : -H ≤ int256 x) (hhi : int256 x < H) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExactFloorBracket (int256 x) (int256 r) := by + have hCmlt : int256 Cmask < -H := by rw [int256_Cmask]; unfold H; norm_num + have hC : int256 Cmask < int256 x := lt_of_lt_of_le hCmlt hlo + have hC0 : int256 x < int256 C0thresh := lt_of_lt_of_le hhi (le_of_lt int256_H_lt_C0) + refine ⟨expTree x, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hx hC0), ?_⟩ + by_cases hz : x = 0 + · subst hz + have he : expTree 0 = 1000000000000000000 := by + have := run_exp_ray_to_wad_evm_zero + rw [run_exp_ray_to_wad_evm_eq_expTree 0 (domain_of_below_C0 hx hC0)] at this + exact Except.ok.inj this.symm + rw [he] + have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by + rw [int256_of_lt (by norm_num)]; norm_num + have hi0 : int256 (0 : Nat) = (0 : Int) := rfl + rw [h0, hi0]; exact exactFloor_zero + · rw [int256_expTree_region_ne_zero hx hC hC0 hz] + obtain ⟨hfl, _⟩ := r1Tree_floor_accum hx hC hC0 + exact ExpRealBridge.exactFloorBracket_of_accum hfl + (accumReal_over x hx hC hC0) (hcentral x hx hC hC0 hlo hhi) + +end + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean new file mode 100644 index 000000000..f88d2f352 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -0,0 +1,99 @@ +import ExpProof.Floor.Fold +import ExpProof.Floor.R0Exp + +/-! +# Discharging the never-over / deficit / below-clamp fields of `RuntimeR0Bound` + +The per-point `r0`-vs-`exp` brackets (`r0_real_over_within`, `r0_real_under_within`) and the +below-clamp bound (`belowC_target_lt_two`) discharge three of the four `RuntimeAccumBound` fields +unconditionally and axiom-clean, via the octave fold `E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the +closing shift; `k ≤ 63` so `s ≥ 63`). + +* `over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 19/25` and `WAD·19/25 ≤ MARGIN`; +* `under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 8` and `8·WAD + MARGIN < 2⁶³ ≤ 2^s`; +* `belowC` ⟸ `belowC_target_lt_two`. + +These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free +(they consume only `over`/`under`/`belowC`). The central-octave exact-floor bracket additionally +depends on the `centralExactness` obligation. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Word +open ExpRealSpec + +noncomputable section + +set_option maxRecDepth 100000 + +/-- The accumulator never exceeds the target on the region (`RuntimeAccumBound.over`). -/ +theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) + (hC0 : int256 x < int256 C0thresh) : + accumReal x ≤ expRayToWadTarget (int256 x) := by + obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 + have hps : (0 : Real) < (2 ^ s : Real) := by positivity + have hfold := target_octave_fold s hsint + have hover := r0_real_over_within hx hC hC0 + set Ert := Real.exp (reducedArg x) with hErt + -- WAD·r0 − MARGIN ≤ WAD·2^126·Ert = E·2^s + have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 ≤ + expRayToWadTarget (int256 x) * (2 ^ s : Real) := by + rw [hfold] + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 19 / 25 := hover + have hscaled : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) ≤ + (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 19 / 25) := + mul_le_mul_of_nonneg_left hr0R (by norm_num) + have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num + rw [hwad]; nlinarith [hscaled] + rw [hAeq, div_le_iff₀ hps]; linarith [hbound] + +/-- The target is below the accumulator plus one on the region (`RuntimeAccumBound.under`). -/ +theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) + (hC0 : int256 x < int256 C0thresh) : + expRayToWadTarget (int256 x) < accumReal x + 1 := by + obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 + have hps : (0 : Real) < (2 ^ s : Real) := by positivity + have hfold := target_octave_fold s hsint + have hunder := r0_real_under_within hx hC hC0 + obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 + set Ert := Real.exp (reducedArg x) with hErt + -- E·2^s = WAD·2^126·Ert < WAD·r0 − MARGIN + 2^s + have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < + ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real) := by + rw [hfold] + have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 8 := hunder + have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num + have hs63 : (63 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs63n : 63 ≤ s := by exact_mod_cast hs63 + have hpow : (2 ^ 63 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs63n + rw [hwad] + have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ + (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 8) := + mul_le_mul_of_nonneg_left (by linarith [hr0R]) (by norm_num) + have hbudget : (10 ^ 18 : Real) * 8 + 792161285993433738 < (2 ^ 63 : Real) := by norm_num + nlinarith [h8wad, hbudget, hpow] + -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s + rw [hAeq] + have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) / + (2 ^ s : Real) + 1 = + (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real)) / + (2 ^ s : Real) := by field_simp + rw [hdiv, lt_div_iff₀ hps]; linarith [hbound] + +/-! ## Hypothesis-free region brackets for the global floor bounds -/ + +/-- **Floor-or-one-less bracket on the region.** The body result satisfies `r ≤ E ∧ E < r+2`, +discharged from the proven `accumReal_over`/`accumReal_under` (no `RuntimeAccumBound` hypothesis). -/ +theorem floorOrOneLessBracket_region_uncond {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + FloorOrOneLessBracket (int256 x) (int256 (r1Tree x)) := by + obtain ⟨hfl, hfl1⟩ := r1Tree_floor_accum hx hC hC0 + exact ExpRealBridge.floorOrOneLessBracket_of_accum hfl hfl1 + (accumReal_over x hx hC hC0) (accumReal_under x hx hC hC0) + +end + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 7fd3c67c5..d18f89944 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -3,6 +3,8 @@ import ExpProof.Seam.Value import ExpProof.Mono import ExpProof.Mono.SeamR0 import ExpProof.Floor.Public +import ExpProof.Floor.PublicUncond +import ExpProof.Floor.R0BoundHolds import ExpProof.Floor.Fold import ExpProof.Floor.R0Bound @@ -210,4 +212,60 @@ example {x : Nat} (hx : x < 2 ^ 256) #guard_msgs in #print axioms belowC_target_lt_two +/-! ## Hypothesis-free global floor brackets + +The never-over (`r0_real_over_within`) and deficit (`r0_real_under_within`) per-point `r0`-vs-`exp` +brackets, folded onto the target through the closing-shift octave fold, discharge the accumulator's +never-over (`accumReal_over`) and deficit (`accumReal_under`) fields unconditionally and axiom-clean. +The global floor-or-one-less and one-unit underestimation brackets consume only those plus the +below-clamp `belowC_target_lt_two`, so they hold with no analytic hypothesis. -/ + +/-- Global floor-or-one-less bracket, with no analytic hypothesis. -/ +example (x : Nat) (hx : x < 2 ^ 256) + (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.FloorOrOneLessBracket + (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := + run_exp_ray_to_wad_evm_floorOrOneLess_uncond x hx hC0 + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_floorOrOneLess_uncond' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_floorOrOneLess_uncond + +/-- One-unit underestimation bound, with no analytic hypothesis. -/ +example (x : Nat) (hx : x < 2 ^ 256) + (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.UnderByAtMostOne + (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := + run_exp_ray_to_wad_evm_underByAtMostOne_uncond x hx hC0 + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_underByAtMostOne_uncond' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_underByAtMostOne_uncond + +/-! ## Central-octave exact floor from central exactness + +The never-over and floor facts of the central-octave exact-floor bracket are hypothesis-free. The +additional input is the core-octave upper exactness `E < r1Tree x + 1` on `[−H, H)`, +`CentralExactness`; together these imply that the runtime returns exactly `⌊E⌋` on the core octave. -/ + +/-- Central-octave exact floor, given central exactness. -/ +example (hcentral : CentralExactness) (x : Nat) (hx : x < 2 ^ 256) + (hlo : -ExpRealSpec.H ≤ FormalYul.Preservation.int256 x) + (hhi : FormalYul.Preservation.int256 x < ExpRealSpec.H) : + ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.ExactFloorBracket + (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := + run_exp_ray_to_wad_evm_exactFloor_of_centralExactness hcentral x hx hlo hhi + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_exactFloor_of_centralExactness' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_exactFloor_of_centralExactness + +/-- info: 'ExpYul.accumReal_over' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms accumReal_over + +/-- info: 'ExpYul.accumReal_under' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms accumReal_under + end ExpYul From b0c1fd62d97d8f395b1a6045c762a715245e622b Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:46:59 +0200 Subject: [PATCH 078/149] Speed up the Floor/R0Exp.lean compile The cost is tactic elaboration (zero decide; the Kronecker poly-cert trick does not apply). Two correctness-preserving rewrites: - positivity on a Nat-tree cast (0 <= (odTree x : Int) etc.) descends the deep tree term; replaced with Int.natCast_nonneg / mul_nonneg / linarith. Pure-power positivity left alone. - nlinarith over the 2^1193/2^1317/den^2 product goals is slow; where the goal is linear in the product atoms, supply the ring identity as a have and use linarith; htod_np via le_of_mul_le_mul_left. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 73 ++++++++++++------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index d51a49f12..caf1bdbab 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -138,7 +138,7 @@ theorem evNumV_step {v : Nat} (hv : v < 2 ^ 126) : unfold evNumV push_cast have hvle : (v : Int) < 2 ^ 126 := by exact_mod_cast hv - have hvnn : (0 : Int) ≤ (v : Int) := by positivity + have hvnn : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ nlinarith [hvle, hvnn, mul_nonneg hvnn hvnn, Int.mul_nonneg hvnn (Int.mul_nonneg hvnn hvnn), Int.mul_nonneg (Int.mul_nonneg hvnn hvnn) (Int.mul_nonneg hvnn hvnn)] @@ -148,7 +148,7 @@ theorem odNumV_step {v : Nat} (hv : v < 2 ^ 126) : unfold odNumV push_cast have hvle : (v : Int) < 2 ^ 126 := by exact_mod_cast hv - have hvnn : (0 : Int) ≤ (v : Int) := by positivity + have hvnn : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ nlinarith [hvle, hvnn, mul_nonneg hvnn hvnn, Int.mul_nonneg hvnn (Int.mul_nonneg hvnn hvnn)] /-! ## The cert polynomial brackets the runtime accumulator (gap-2 ∘ v-truncation) -/ @@ -181,7 +181,7 @@ theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 set t := int256 (tTree x) with htdef have hsqnn : (0 : Int) ≤ t ^ 2 := sq_nonneg _ - have hgridnn : (0 : Int) ≤ 2 ^ 128 * (vTree x : Int) := by positivity + have hgridnn : (0 : Int) ≤ 2 ^ 128 * (vTree x : Int) := mul_nonneg (by norm_num) (Int.natCast_nonneg _) -- v-truncation: Pev(2^128·vTree) ≤ Pev(t²) ≤ Pev(2^128·vTree + 2^128) (monotone) have hmono_lo : evalPoly Pev (2 ^ 128 * (vTree x : Int)) ≤ evalPoly Pev (t ^ 2) := Pev_mono hgridnn hsqlo @@ -226,7 +226,7 @@ theorem odNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 set t := int256 (tTree x) with htdef have hsqnn : (0 : Int) ≤ t ^ 2 := sq_nonneg _ - have hgridnn : (0 : Int) ≤ 2 ^ 128 * (vTree x : Int) := by positivity + have hgridnn : (0 : Int) ≤ 2 ^ 128 * (vTree x : Int) := mul_nonneg (by norm_num) (Int.natCast_nonneg _) have hmono_lo : evalPoly Pod (2 ^ 128 * (vTree x : Int)) ≤ evalPoly Pod (t ^ 2) := Pod_mono hgridnn hsqlo have hmono_hi : evalPoly Pod (t ^ 2) ≤ evalPoly Pod (2 ^ 128 * ((vTree x + 1 : Nat) : Int)) := by @@ -308,7 +308,7 @@ theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) set t := int256 (tTree x) with htdef rw [evalTodNumV] -- odTree ≥ 0 - have hodnn : (0 : Int) ≤ (odTree x : Int) := by positivity + have hodnn : (0 : Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ -- 2^128·tod ≤ t·odTree < 2^128·tod + 2^128 -- multiply odd bracket by t·2^23 (t ≥ 0): have hmul_lo : t * (2 ^ 1042 * (odTree x : Int)) ≤ t * evalPoly ExpCertV.odNumVPoly t := @@ -634,7 +634,7 @@ theorem r0_certRatio_over_small {x : Nat} (hx : x < 2 ^ 256) -- evP ≥ 0, todP ≥ 0 (nonneg half), r0−2^126 ≤ 0, r0+2^126 ≥ 0 have hevPnn : (0:Int) ≤ evP := by obtain ⟨hlo, _⟩ := evNumVPoly_bracket hx hC hC0 - have : (0:Int) ≤ 2^1193 * (evTree x : Int) := by positivity + have : (0:Int) ≤ 2^1193 * (evTree x : Int) := mul_nonneg (by norm_num) (Int.natCast_nonneg _) linarith [hlo, this] have htodPnn : (0:Int) ≤ todP := by rw [htodP, evalTodNumV] @@ -668,7 +668,7 @@ theorem todNumV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨htlo', hthi'⟩ := tTree_bound hx hC hC0 set t := int256 (tTree x) with htdef rw [evalTodNumV] - have hodnn : (0 : Int) ≤ (odTree x : Int) := by positivity + have hodnn : (0 : Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ have hodpolynn : (0 : Int) ≤ evalPoly ExpCertV.odNumVPoly t := le_trans (by positivity) hodlo -- multiply odd bracket by t ≤ 0 (flips): have hmul_lo : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int)) := @@ -752,7 +752,7 @@ theorem denExpV_lb_neg {x : Nat} (hx : x < 2 ^ 256) have htodnp : int256 (todTree x) ≤ 0 := by -- from todTree_bound: 2^128·tod ≤ t·od, t ≤ 0, od ≥ 0 ⇒ t·od ≤ 0 ⇒ tod ≤ 0 obtain ⟨_, _, htl, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn nlinarith [htl, this] have hden_rt : (2 : Int) ^ 125 < (evTree x : Int) - int256 (todTree x) := by @@ -1944,7 +1944,7 @@ theorem r0_certRatio_over_neg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 have hr0nn : (0:Int) ≤ r0 := by linarith [hr0lo] -- tod ≤ 0 for t ≤ 0 (tod = ⌊t·od/2^128⌋, t ≤ 0, od ≥ 0) - have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ have htod_np : tod ≤ 0 := by obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 -- 2^128·tod ≤ t·od ≤ 0 @@ -2044,7 +2044,7 @@ theorem r0_certRatio_over_neg_bound {x : Nat} (hx : x < 2 ^ 256) positivity -- A1 := (−t)·(r0+2^126)·(od·den) ≤ 2^255·5·den²/36 ... carry without division: -- chain on 36·A1 ≤ 5·2^255·den² - have hntden : (0:Int) ≤ 2 ^ 128 * (-tod) := by positivity + have hntden : (0:Int) ≤ 2 ^ 128 * (-tod) := mul_nonneg (by norm_num) (by linarith [htod_np]) -- (−t)·od·(r0+2^126)·den ≤ 2^128·(−tod)·(r0+2^126)·den [hstep1, (r0+2^126)·den ≥ 0] have hP1 : (-t) * od * ((r0 + 2 ^ 126) * den) ≤ 2 ^ 128 * (-tod) * ((r0 + 2 ^ 126) * den) := by apply mul_le_mul_of_nonneg_right hstep1 (mul_nonneg hr0p (le_of_lt hdenpos)) @@ -2480,7 +2480,7 @@ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) -- tod ≥ 0 on nonneg half have htodnn : (0:Int) ≤ tod := by obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ have htod : (2 ^ 128 : Int) * tod ≤ int256 (tTree x) * (odTree x : Int) := htodlo have hpos : (0:Int) ≤ int256 (tTree x) * (odTree x : Int) := mul_nonneg htnn hodnn nlinarith [htod, hpos] @@ -2529,7 +2529,7 @@ theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 have h2126r0_np : (2:Int) ^ 126 - r0 ≤ 0 := by linarith [hr0lo] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by positivity + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] -- evP·(2^126−r0) ≤ 2^1193·ev·(2^126−r0) (evP ≥ 2^1193·ev, factor ≤ 0) have hterm1 : evP * (2 ^ 126 - r0) ≤ 2 ^ 1193 * ev * (2 ^ 126 - r0) := mul_le_mul_of_nonpos_right hevlo h2126r0_np @@ -2545,7 +2545,12 @@ theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + (2^1193 + W·2^1039·t)·(2^126+r0) have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ 2 ^ 1193 * (ev - tod) + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by - rw [hDEdef]; nlinarith [hterm1, hterm2, hfloor1193] + have hid1 : 2 ^ 126 * (evP + todP) - r0 * DE = evP * (2 ^ 126 - r0) + todP * (2 ^ 126 + r0) := by + rw [hDEdef]; ring + have hid2 : 2 ^ 1193 * ev * (2 ^ 126 - r0) + (2 ^ 1193 * tod + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) + = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) + + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by ring + rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] -- now bound the RHS ≤ 6·DE. -- (A) 2^1193·den ≤ DE + 32·2^1193 (denExpV hi), and 32·2^1193 ≤ DE (DE > 2^1317): 2^1193·den ≤ 2·DE have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 32 * 2 ^ 1193 := by @@ -2579,7 +2584,12 @@ theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) -- 100·(C0·(2^126+r0)) ≤ C0·245·2^126 have hLHS2 : 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) ≤ (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := by - have := mul_le_mul_of_nonneg_left hr0p_bound hC0nn; nlinarith [this] + have h := mul_le_mul_of_nonneg_left hr0p_bound hC0nn + have hid : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (100 * (2 ^ 126 + r0)) + = 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) := by ring + have hid2 : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) + = (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := rfl + linarith [h, hid] -- key integer cert (common 2^1165 scale): C0·245·2^126 ≤ 500·(2^1193·(den−32)). have hkey : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) ≤ 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by @@ -2593,7 +2603,7 @@ theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) 500 * 2 ^ 28 * ((ev - tod) - 32) := by have h154 : (2:Int)^154 = 22835963083295358096932575511191922182123945984 := by norm_num have h28 : (2:Int)^28 = 268435456 := by norm_num - rw [h154, h28]; nlinarith [hden_lo] + rw [h154, h28]; linarith [hden_lo] have hscaled := mul_le_mul_of_nonneg_right hcoeff_le (le_of_lt hp) -- rewrite both sides to the (·)·2^1165 form calc (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) @@ -2602,7 +2612,9 @@ theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) _ ≤ (500 * 2 ^ 28 * ((ev - tod) - 32)) * 2 ^ 1165 := hscaled _ = 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by linear_combination (-500 * ((ev - tod) - 32) : Int) * hpe3 - nlinarith [hLHS, hLHS2, hkey, hDEden] + -- LHS ≤ C0·(2^126+r0); 100·that ≤ C0·245·2^126 ≤ 500·(2^1193 den − 32·2^1193) ≤ 500·DE; so LHS ≤ 5·DE + have h500 : (500 : Int) * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) ≤ 500 * DE := by linarith [hDEden] + linarith [hLHS, hLHS2, hkey, h500] linarith [hcombine, hAterm, hBterm] /-- **The joint per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 8`. From the joint @@ -2711,7 +2723,7 @@ theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 have htodnp : tod ≤ 0 := by obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn nlinarith [htodlo, this] -- r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den) @@ -2748,9 +2760,10 @@ theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) -- on the neg half tod ≤ 0, so den = ev − tod ≥ ev ≥ A4 have htod_np : tod ≤ 0 := by obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := by positivity - have : t * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn - nlinarith [htodlo, this] + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ + have hp : t * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn + have h2 : (2 ^ 128 : Int) * tod ≤ 2 ^ 128 * 0 := by simpa using le_trans htodlo hp + exact le_of_mul_le_mul_left h2 (by norm_num) have hden_A4 : (103786963415199049567855548359006885036 : Int) ≤ ev - tod := by obtain ⟨hevlo', _⟩ := evTree_facts (vTree_eq hx hC hC0).2 have hev : (103786963415199049567855548359006885036 : Int) ≤ ev := by @@ -2759,7 +2772,7 @@ theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) exact this linarith [hev, htod_np] have h2126r0_nn : (0:Int) ≤ 2 ^ 126 - r0 := by linarith [hr0le] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by positivity + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] -- Ee = evP − 2^1193·ev ∈ [0, W_ev). evP·(2^126−r0) ≤ (2^1193·ev + W_ev)·(2^126−r0) have hterm1 : evP * (2 ^ 126 - r0) ≤ (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) := mul_le_mul_of_nonneg_right (le_of_lt hevhi) h2126r0_nn @@ -2774,7 +2787,13 @@ theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + W_ev·(2^126−r0) + 2·2^1193·(2^126+r0) have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ 2 ^ 1193 * (ev - tod) + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by - rw [hDEdef]; nlinarith [hterm1, hterm2, hfloor1193] + have hid1 : 2 ^ 126 * (evP + todP) - r0 * DE = evP * (2 ^ 126 - r0) + todP * (2 ^ 126 + r0) := by + rw [hDEdef]; ring + have hid2 : (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) + + (2 ^ 1193 * tod + 2 * 2 ^ 1193) * (2 ^ 126 + r0) + = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) + + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by ring + rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] -- bound RHS by 6·DE. DE ≥ 2^1193·(den−2), den ≥ den_lo. have hDEden : 2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193 ≤ DE := by rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] @@ -2801,8 +2820,9 @@ theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) rw [e, hA]; ring have heR : (1 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (1 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring rw [heL, heR, mul_le_mul_right hp] - have h106 : (2:Int)^106 = 81129638414606681695789005144064 := by norm_num - rw [h106]; nlinarith [hden_A4] + have h106 : (1130577 * 2 ^ 106 : Int) = 91723303209870778371580046068760444928 := by norm_num + calc (1130577 * 2 ^ 106 : Int) = 91723303209870778371580046068760444928 := h106 + _ ≤ 1 * ((ev - tod) - 2) := by linarith [hden_A4] linarith [hle, hkey] -- (C) 2·2^1193·(2^126+r0) ≤ 2·DE. (2^126+r0) ≤ 2·2^126 (r0 ≤ 2^126); 2·2^1193·2·2^126 = 4·2^1319; vs 2·DE. have hCterm : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 4 * DE := by @@ -2815,8 +2835,9 @@ theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) have heL : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) = (4 * 2 ^ 126) * 2 ^ 1193 := by ring have heR : (4 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (4 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring rw [heL, heR, mul_le_mul_right hp] - have h126 : (2:Int)^126 = 85070591730234615865843651857942052864 := by norm_num - rw [h126]; nlinarith [hden_A4] + have h126 : (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := by norm_num + calc (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := h126 + _ ≤ 4 * ((ev - tod) - 2) := by linarith [hden_A4] linarith [hle, hkey] linarith [hcombine, hAterm, hBterm, hCterm] From 874a1b8a85267381f08f2758c99306ca9fdec318 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Mon, 29 Jun 2026 23:54:12 +0200 Subject: [PATCH 079/149] Split the deficit side into Floor/R0ExpUnder.lean Move the under cluster (todNumV_ub through r0_real_under_within) out of the ~2900-line R0Exp.lean into R0ExpUnder.lean (imports R0Exp). The cut is clean: the under theorems reference only the over/shared lemmas (in R0Exp) and each other. R0BoundHolds.lean now imports R0ExpUnder. Incremental builds editing one side no longer recheck the other, and the smaller over+shared R0Exp kernel-checks faster. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 1 + formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 591 ----------------- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 611 ++++++++++++++++++ 3 files changed, 612 insertions(+), 591 deletions(-) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index f88d2f352..e86b8d4aa 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -1,5 +1,6 @@ import ExpProof.Floor.Fold import ExpProof.Floor.R0Exp +import ExpProof.Floor.R0ExpUnder /-! # Discharging the never-over / deficit / below-clamp fields of `RuntimeR0Bound` diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index caf1bdbab..0cb3062e0 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -2335,595 +2335,4 @@ theorem r0_seam_double {x1 x2 : Nat} push_cast; linarith [hreal] exact_mod_cast this -/-! ## The deficit (under) side: per-point `2¹²⁶·exp(rt) ≤ r0 + 8` (both signs) - -Mirror of the never-over `r0_real_over_within`. The nonneg half drops the even truncation -`Ee·(2¹²⁶−r0) ≤ 0` and bounds the tod truncation; the negative half drops the tod and bounds the -even truncation. Both feed the closing-shift deficit budget `c_under < 8.43 = 2⁶³/WAD − MARGIN/WAD` -at the binding `k = 63`. -/ - -/-- **`todNumV` upper bound (nonneg half).** For `0 ≤ t`: -`todNumV(t) ≤ 2¹¹⁹³·tod + 2¹¹⁹³ + W_od·2¹⁰³⁹·t`. -/ -theorem todNumV_ub {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - evalPoly ExpCertV.todNumV (int256 (tTree x)) ≤ - 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 + 69402657 * 2 ^ 1039 * (int256 (tTree x)) := by - obtain ⟨_, _, _, htodhi⟩ := todTree_bound hx hC hC0 - obtain ⟨_, hodhi⟩ := odNumVPoly_bracket hx hC hC0 - set t := int256 (tTree x) with htdef - rw [evalTodNumV] - -- todP = 2^23·t·odpoly. t ≥ 0, odpoly ≤ 2^1042·od + W_od·2^1016 ⟹ 2^23·t·odpoly ≤ 2^23·t·(…) - have hmul : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) ≤ - 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) := by - apply mul_le_mul_of_nonneg_left _ (by positivity) - exact mul_le_mul_of_nonneg_left (le_of_lt hodhi) htnn - -- 2^23·t·(2^1042 od + W_od 2^1016) = 2^1065·(t·od) + W_od·2^1039·t ; 2^1065·(t·od) < 2^1193·tod + 2^1193 - have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi - have key : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) ≤ - 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t := by - have e1 : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) = - 2 ^ 1065 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1039 * t := by ring - have e2 : (2 : Int) ^ 1065 * ((2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128) = - 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 := by - rw [show (2:Int) ^ 1193 = 2 ^ 1065 * 2 ^ 128 from by rw [← pow_add]]; ring - rw [e1] - have h := mul_le_mul_of_nonneg_left (le_of_lt htod_hi) (by positivity : (0:Int) ≤ 2 ^ 1065) - rw [e2] at h - linarith [h] - linarith [hmul, key] - -/-- **`num ≤ 1.45·den`** (`ê ≤ 1.45`) on the nonneg half, from `exp(t/2¹²⁸) ≤ √2` and the cert. -/ -theorem num_le_145_den {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - 100 * ((evTree x : Int) + int256 (todTree x)) ≤ 145 * ((evTree x : Int) - int256 (todTree x)) := by - obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - set t := int256 (tTree x) with htdef - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] - exact hthi - have hDElb := denExpV_lb hx hC hC0 htnn - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - have hcertlo := certLo_real htnn htdom - set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef - have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn - rw [← hEtdef] at hEtsqrt2 - have hMp_pos : (0:Real) < Mp := by rw [hMpdef]; positivity - have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by - have hc : ((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo - rw [hMpdef] - have key : (NE : Real) / (DE : Real) = - ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) * - (((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real))) := by - push_cast; field_simp; ring - rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) - -- num bound: 2^1193·num ≤ NE, DE < 2^1193·den + 3·2^1193 - obtain ⟨hnumlo, _⟩ := numExpV_bracket hx hC hC0 htnn - obtain ⟨_, hdenhi⟩ := denExpV_bracket hx hC hC0 htnn - set num := (evTree x : Int) + int256 (todTree x) with hnumdef - set den := (evTree x : Int) - int256 (todTree x) with hdendef - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ den := den_ge_072 hx hC hC0 - have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden072 - have hdenR : (0:Real) < (den : Real) := by exact_mod_cast hdenpos - have hden072R : (61251667550081741634933722430035858604 : Real) ≤ (den : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hden072; push_cast at this; linarith [this] - have hnumloR : (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hnumlo; push_cast at this; linarith [this] - have hdenhiR : (DE : Real) < (2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193 := by - have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hdenhi; push_cast at this; linarith [this] - have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by - rw [Real.sqrt_le_iff]; constructor <;> norm_num - have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ - have hMp_le : Mp ≤ 14144 / 14143 := by - rw [hMpdef, div_le_div_iff₀ (by norm_num) (by norm_num)] - have h130 : (14144 : Real) ≤ 2 ^ 130 := by - rw [show (2:Real) ^ 130 = 1361129467683753853853498429727072845824 from by norm_num]; norm_num - nlinarith [h130] - have hsM_le : Real.sqrt 2 * Mp ≤ 14144 / 10000 := by - have hMpnn : (0:Real) ≤ Mp := by rw [hMpdef]; positivity - calc Real.sqrt 2 * Mp ≤ (14143 / 10000) * (14144 / 14143) := - mul_le_mul hsqrt2_val hMp_le hMpnn (by norm_num) - _ = 14144 / 10000 := by norm_num - -- NE ≤ √2·Mp·DE ≤ (14144/10000)·DE - have hNE_le : (NE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by - have h1 : (NE : Real) ≤ Et * Mp * (DE : Real) := by - have := mul_le_mul_of_nonneg_right hNEDE_le (le_of_lt hDEpos) - rwa [div_mul_cancel₀ _ (ne_of_gt hDEpos)] at this - have h2 : Et * Mp * (DE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by - apply mul_le_mul_of_nonneg_right _ (le_of_lt hDEpos) - exact mul_le_mul_of_nonneg_right hEtsqrt2 (le_of_lt hMp_pos) - linarith [h1, h2] - -- num ≤ (14144/10000)·(den+3) - have hnum_le : (num : Real) ≤ (14144 / 10000) * ((den : Real) + 3) := by - have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity - rw [← mul_le_mul_left hp] - calc (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := hnumloR - _ ≤ Real.sqrt 2 * Mp * (DE : Real) := hNE_le - _ ≤ (14144 / 10000) * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := by - calc Real.sqrt 2 * Mp * (DE : Real) - ≤ (14144 / 10000) * (DE : Real) := mul_le_mul_of_nonneg_right hsM_le (le_of_lt hDEpos) - _ ≤ (14144 / 10000) * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := - mul_le_mul_of_nonneg_left (le_of_lt hdenhiR) (by norm_num) - _ = (2 ^ 1193 : Real) * ((14144 / 10000) * ((den : Real) + 3)) := by ring - -- 100·num ≤ 145·den as Real: 100·(14144/10000)(den+3) ≤ 145·den ⟺ den huge - have hkey : (100 : Real) * (num : Real) ≤ 145 * (den : Real) := by - have h1 : (100 : Real) * (num : Real) ≤ 100 * ((14144 / 10000) * ((den : Real) + 3)) := - mul_le_mul_of_nonneg_left hnum_le (by norm_num) - nlinarith [h1, hden072R] - have : ((100 * num : Int) : Real) ≤ ((145 * den : Int) : Real) := by push_cast; linarith [hkey] - exact_mod_cast this - -/-- `r0` is bracketed on the nonneg half: `2¹²⁶ ≤ r0 ≤ 1.45·2¹²⁶` (so `2¹²⁶+r0 ≤ 2.45·2¹²⁶`). -/ -theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - (2 : Int) ^ 126 ≤ int256 (r0Tree x) ∧ - 100 * (int256 (r0Tree x)) ≤ 145 * 2 ^ 126 := by - obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 - have h145 := num_le_145_den hx hC hC0 htnn - set r0 := int256 (r0Tree x) with hr0def - set ev := (evTree x : Int) with hevdef - set tod := int256 (todTree x) with htoddef - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 - -- tod ≥ 0 on nonneg half - have htodnn : (0:Int) ≤ tod := by - obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have htod : (2 ^ 128 : Int) * tod ≤ int256 (tTree x) * (odTree x : Int) := htodlo - have hpos : (0:Int) ≤ int256 (tTree x) * (odTree x : Int) := mul_nonneg htnn hodnn - nlinarith [htod, hpos] - refine ⟨?_, ?_⟩ - · -- 2^126 ≤ r0: 2^126·num < (r0+1)·den, num ≥ den ⟹ 2^126·den < (r0+1)·den ⟹ 2^126 < r0+1 - have hnumden : (2:Int)^126 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := by nlinarith [htodnn] - have h : (2:Int)^126 * (ev - tod) < (r0 + 1) * (ev - tod) := lt_of_le_of_lt hnumden hfloor_hi - have := lt_of_mul_lt_mul_right h (le_of_lt hdenpos) - omega - · -- 100·r0 ≤ 145·2^126: 100·r0·den ≤ 100·2^126·num ≤ 2^126·145·den - have h1 : 100 * (r0 * (ev - tod)) ≤ 100 * (2 ^ 126 * (ev + tod)) := - mul_le_mul_of_nonneg_left hfloor_lo (by norm_num) - have h2 : (2:Int)^126 * (100 * (ev + tod)) ≤ 2 ^ 126 * (145 * (ev - tod)) := - mul_le_mul_of_nonneg_left h145 (by positivity) - have hchain : 100 * r0 * (ev - tod) ≤ 145 * 2 ^ 126 * (ev - tod) := by nlinarith [h1, h2] - exact le_of_mul_le_mul_right hchain hdenpos - -/-- **Joint cert-ratio under (nonneg half):** `2¹²⁶·NE − r0·DE ≤ 7·DE`. The shared even truncation -`Ee·(2¹²⁶−r0) ≤ 0` (since `r0 ≥ 2¹²⁶`) is dropped; the floor `2¹²⁶·num − r0·den < den` gives the -`2¹¹⁹³·den` term, and the binding tod truncation `Et' ≤ (2¹¹⁹³ + W_od·2¹⁰³⁹·t)·(2¹²⁶+r0)` is small -because `t ≤ H128` is far below `2¹²⁸`. -/ -theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ - 7 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by - obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hevlo, _⟩ := evNumVPoly_bracket hx hC hC0 - have htodub := todNumV_ub hx hC hC0 htnn - obtain ⟨hr0lo, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn - obtain ⟨hdenlo, _⟩ := denExpV_bracket hx hC hC0 htnn - have hDElb := denExpV_lb hx hC hC0 htnn - rw [evalNumExpV, evalDenExpV] - set t := int256 (tTree x) with htdef - set r0 := int256 (r0Tree x) with hr0def - set ev := (evTree x : Int) with hevdef - set tod := int256 (todTree x) with htoddef - set evP := evalPoly ExpCertV.evNumVPoly t with hevP - set todP := evalPoly ExpCertV.todNumV t with htodP - set DE := evP - todP with hDEdef - -- 2^126·NE − r0·DE = evP·(2^126−r0) + todP·(2^126+r0) - -- = 2^1193·[2^126·num − r0·den] + Ee·(2^126−r0) + Et'·(2^126+r0) - -- ≤ 2^1193·den + 0 + (2^1193 + W·2^1039·t)·(2^126+r0) - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 - have h2126r0_np : (2:Int) ^ 126 - r0 ≤ 0 := by linarith [hr0lo] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] - -- evP·(2^126−r0) ≤ 2^1193·ev·(2^126−r0) (evP ≥ 2^1193·ev, factor ≤ 0) - have hterm1 : evP * (2 ^ 126 - r0) ≤ 2 ^ 1193 * ev * (2 ^ 126 - r0) := - mul_le_mul_of_nonpos_right hevlo h2126r0_np - -- todP·(2^126+r0) ≤ (2^1193·tod + 2^1193 + W·2^1039·t)·(2^126+r0) (todP upper, factor ≥ 0) - have hterm2 : todP * (2 ^ 126 + r0) ≤ - (2 ^ 1193 * tod + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := - mul_le_mul_of_nonneg_right htodub hr0p_nn - -- floor: 2^126·num − r0·den < den, scaled by 2^1193: 2^1193·(2^126·num − r0·den) < 2^1193·den - have hfloor_lt : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) < (ev - tod) := by linarith [hfloor_hi] - have hfloor1193 : (2 ^ 1193 : Int) * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) < - 2 ^ 1193 * (ev - tod) := by - have := mul_lt_mul_of_pos_left hfloor_lt (by positivity : (0:Int) < 2 ^ 1193); linarith [this] - -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + (2^1193 + W·2^1039·t)·(2^126+r0) - have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ - 2 ^ 1193 * (ev - tod) + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by - have hid1 : 2 ^ 126 * (evP + todP) - r0 * DE = evP * (2 ^ 126 - r0) + todP * (2 ^ 126 + r0) := by - rw [hDEdef]; ring - have hid2 : 2 ^ 1193 * ev * (2 ^ 126 - r0) + (2 ^ 1193 * tod + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) - = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) - + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by ring - rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] - -- now bound the RHS ≤ 6·DE. - -- (A) 2^1193·den ≤ DE + 32·2^1193 (denExpV hi), and 32·2^1193 ≤ DE (DE > 2^1317): 2^1193·den ≤ 2·DE - have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 32 * 2 ^ 1193 := by - rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] - have h32 : (32 : Int) * 2 ^ 1193 ≤ DE := by - have hD1317 : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] - have : (32 : Int) * 2 ^ 1193 < 2 ^ 1317 := by - rw [show (32:Int) * 2 ^ 1193 = 2 ^ 1198 from by rw [show (32:Int)=2^5 from by norm_num, ← pow_add]] - exact pow_lt_pow_right₀ (by norm_num) (by norm_num) - linarith [this, hD1317] - have hAterm : 2 ^ 1193 * (ev - tod) ≤ 2 * DE := by linarith [hden2, h32] - -- (B) (2^1193 + W·2^1039·t)·(2^126+r0) ≤ 4·DE. bound via t ≤ H128, 2^126+r0 ≤ 2.45·2^126. - have hDElb' : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] - obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - have htH : t ≤ 117932881612756647068972071382077242199 := hthi - -- 2^126 + r0 ≤ 2.45·2^126, i.e. 100·(2^126+r0) ≤ 245·2^126 - have hr0p_bound : 100 * (2 ^ 126 + r0) ≤ 245 * 2 ^ 126 := by linarith [hr0hi145] - have hBterm : (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) ≤ 5 * DE := by - have hDEden : 2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193 ≤ DE := by - rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] - have hden_lo : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - -- 2^1193 + W·2^1039·t ≤ 2^1193 + W·2^1039·H128 (t ≤ H128, t ≥ 0) - have hcoeff : 2 ^ 1193 + 69402657 * 2 ^ 1039 * t ≤ - 2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199 := by - have := mul_le_mul_of_nonneg_left htH (by positivity : (0:Int) ≤ 69402657 * 2 ^ 1039); linarith [this] - have hC0nn : (0:Int) ≤ 2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199 := by positivity - have hLHS : (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) ≤ - (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0) := - mul_le_mul_of_nonneg_right hcoeff hr0p_nn - -- 100·(C0·(2^126+r0)) ≤ C0·245·2^126 - have hLHS2 : 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) ≤ - (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := by - have h := mul_le_mul_of_nonneg_left hr0p_bound hC0nn - have hid : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (100 * (2 ^ 126 + r0)) - = 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) := by ring - have hid2 : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) - = (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := rfl - linarith [h, hid] - -- key integer cert (common 2^1165 scale): C0·245·2^126 ≤ 500·(2^1193·(den−32)). - have hkey : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) ≤ - 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by - -- factor everything to the common 2^1165 scale and compare coefficients - have hA : (2:Int) ^ 1193 * 2 ^ 126 = 2 ^ 154 * 2 ^ 1165 := by rw [← pow_add, ← pow_add] - have hpe2 : (2:Int) ^ 1039 * 2 ^ 126 = 2 ^ 1165 := by rw [← pow_add] - have hpe3 : (2:Int) ^ 1193 = 2 ^ 28 * 2 ^ 1165 := by rw [← pow_add] - have hp : (0:Int) < (2:Int) ^ 1165 := by positivity - -- the coefficient inequality, scaled by 2^1165 - have hcoeff_le : (245 * 2 ^ 154 + 245 * 69402657 * 117932881612756647068972071382077242199 : Int) ≤ - 500 * 2 ^ 28 * ((ev - tod) - 32) := by - have h154 : (2:Int)^154 = 22835963083295358096932575511191922182123945984 := by norm_num - have h28 : (2:Int)^28 = 268435456 := by norm_num - rw [h154, h28]; linarith [hden_lo] - have hscaled := mul_le_mul_of_nonneg_right hcoeff_le (le_of_lt hp) - -- rewrite both sides to the (·)·2^1165 form - calc (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) - = (245 * 2 ^ 154 + 245 * 69402657 * 117932881612756647068972071382077242199) * 2 ^ 1165 := by - linear_combination (245 : Int) * hA + (245 * 69402657 * 117932881612756647068972071382077242199 : Int) * hpe2 - _ ≤ (500 * 2 ^ 28 * ((ev - tod) - 32)) * 2 ^ 1165 := hscaled - _ = 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by - linear_combination (-500 * ((ev - tod) - 32) : Int) * hpe3 - -- LHS ≤ C0·(2^126+r0); 100·that ≤ C0·245·2^126 ≤ 500·(2^1193 den − 32·2^1193) ≤ 500·DE; so LHS ≤ 5·DE - have h500 : (500 : Int) * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) ≤ 500 * DE := by linarith [hDEden] - linarith [hLHS, hLHS2, hkey, h500] - linarith [hcombine, hAterm, hBterm] - -/-- **The joint per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 8`. From the joint -cert-ratio under (`2¹²⁶·NE − r0·DE ≤ 7·DE`), the not-too-below cert (`exp ≤ (NE/DE)·M⁺`), and the -under-direction gap-1 (`exp(rt) ≤ √2`, `rt − t/2¹²⁸ < 33/(32·2¹²⁸)`). -/ -theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by - have hunder := r0_certRatio_under_nonneg hx hC hC0 htnn - obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - set t := int256 (tTree x) with htdef - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] - exact hthi - have hDElb := denExpV_lb hx hC hC0 htnn - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - set r0 := int256 (r0Tree x) with hr0def - -- 2^126·NE/DE ≤ r0 + 7 - have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ 7 * (DE : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] - have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 7 := by - rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos] - -- certUp: exp(t/2^128) ≤ (NE/DE)·Mpp - have hcertup := certUp_real htnn htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by - have := certNE_nonneg htnn htdom; exact_mod_cast this - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef - have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mpp := by - have hc : Et ≤ ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real)) := hcertup - rw [hMppdef] - have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) = - ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 130 : Int) : Real) * (DE : Real)) := by - push_cast; field_simp; ring - rw [key]; exact hc - have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) - have hMpp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp - -- Et ≤ √2 (nonneg half) - have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn - rw [← hEtdef] at hEtsqrt2 - have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num - have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ - -- 2^126·Et ≤ 2^126·(NE/DE)·Mpp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mpp−1) ≤ (r0+7) + 1/4 - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 7 + 3 / 10 := by - have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) := - mul_le_mul_of_nonneg_left hEt_le (by positivity) - have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) = - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) := by ring - -- 2^126·(NE/DE)·(Mpp−1) ≤ 3/10. NE/DE·2^126 ≤ r0+7 ≤ 2^128+7; ·(1/2^130) ≈ 1/4 < 3/10. - have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) ≤ 3 / 10 := by - rw [hMpp1] - obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 - have hr0R : (r0 : Real) < (2 ^ 128 : Real) := by - have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi - rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h - have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn - have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 7 := by - linarith [hr0_ge, hr0R] - calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / (2 ^ 130 : Real)) - ≤ ((2 ^ 128 : Real) + 7) * (1 / (2 ^ 130 : Real)) := - mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) - _ ≤ 3 / 10 := by norm_num - linarith [h1, h2 ▸ h1, h3, hr0_ge] - -- gap-1 (under, tight): Ert − Et ≤ (rt − t/2^128)·Ert, rt − t/2^128 < 33/(32·2^128), Ert ≤ 2 - set Ert := Real.exp (reducedArg x) with hErtdef - have hgapunder := reducedArg_close_under hx hC hC0 - have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ - have hErt_le_two := exp_reducedArg_le_two hx hC hC0 - rw [← hErtdef] at hErt_le_two - have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 6 / 10 := by - have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := - le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) - have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := - mul_le_mul_of_nonneg_left hgap (by positivity) - have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ - (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) := - mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) ≤ 6 / 10 := by norm_num - linarith [h1, h2, h3] - -- assemble: 2^126·Ert = 2^126·Et + 2^126·(Ert−Et) ≤ (r0+7+1/4) + 6/10 < r0 + 8 - have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 8 - linarith [hEt_bound, hgap126, hdist] - -/-- `r0 ≤ 2¹²⁶` on the negative half (num ≤ den ⟺ tod ≤ 0). -/ -theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - int256 (r0Tree x) ≤ 2 ^ 126 := by - obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 - set r0 := int256 (r0Tree x) with hr0def - set ev := (evTree x : Int) with hevdef - set tod := int256 (todTree x) with htoddef - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 - have htodnp : tod ≤ 0 := by - obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn - nlinarith [htodlo, this] - -- r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den) - have hnumden : r0 * (ev - tod) ≤ 2 ^ 126 * (ev - tod) := by - have h1 : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo - nlinarith [h1, htodnp, (by positivity : (0:Int) ≤ (2:Int)^126)] - exact le_of_mul_le_mul_right hnumden hdenpos - -/-- **Joint cert-ratio under (negative half):** `2¹²⁶·NE − r0·DE ≤ 6·DE`. The binding even -truncation `Ee·(2¹²⁶−r0)` (small factor) and the tod truncation `Et'·(2¹²⁶+r0)` both fit. -/ -theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ - 7 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by - obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 - obtain ⟨_, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg - have hr0le := r0_le_2126_neg hx hC hC0 htneg - obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 - obtain ⟨hdenlo, _⟩ := denExpV_bracket_neg hx hC hC0 htneg - have hDElb := denExpV_lb_neg hx hC hC0 htneg - rw [evalNumExpV, evalDenExpV] - set t := int256 (tTree x) with htdef - set r0 := int256 (r0Tree x) with hr0def - set ev := (evTree x : Int) with hevdef - set tod := int256 (todTree x) with htoddef - set evP := evalPoly ExpCertV.evNumVPoly t with hevP - set todP := evalPoly ExpCertV.todNumV t with htodP - set DE := evP - todP with hDEdef - have hden_lo : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - -- on the neg half tod ≤ 0, so den = ev − tod ≥ ev ≥ A4 - have htod_np : tod ≤ 0 := by - obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have hp : t * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn - have h2 : (2 ^ 128 : Int) * tod ≤ 2 ^ 128 * 0 := by simpa using le_trans htodlo hp - exact le_of_mul_le_mul_left h2 (by norm_num) - have hden_A4 : (103786963415199049567855548359006885036 : Int) ≤ ev - tod := by - obtain ⟨hevlo', _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - have hev : (103786963415199049567855548359006885036 : Int) ≤ ev := by - rw [hevdef]; have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo' - rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 from by norm_num] at this - exact this - linarith [hev, htod_np] - have h2126r0_nn : (0:Int) ≤ 2 ^ 126 - r0 := by linarith [hr0le] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] - -- Ee = evP − 2^1193·ev ∈ [0, W_ev). evP·(2^126−r0) ≤ (2^1193·ev + W_ev)·(2^126−r0) - have hterm1 : evP * (2 ^ 126 - r0) ≤ (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) := - mul_le_mul_of_nonneg_right (le_of_lt hevhi) h2126r0_nn - -- Et' = todP − 2^1193·tod < 2·2^1193 ⟹ todP < 2^1193·tod + 2·2^1193; todP·(2^126+r0) ≤ (2^1193·tod+2·2^1193)·(2^126+r0) - have hterm2 : todP * (2 ^ 126 + r0) ≤ (2 ^ 1193 * tod + 2 * 2 ^ 1193) * (2 ^ 126 + r0) := - mul_le_mul_of_nonneg_right (le_of_lt htodhi) hr0p_nn - -- floor: 2^126·num − r0·den < den ⟹ 2^1193·(2^126·num − r0·den) < 2^1193·den - have hfloor_lt : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) < (ev - tod) := by linarith [hfloor_hi] - have hfloor1193 : (2 ^ 1193 : Int) * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) < - 2 ^ 1193 * (ev - tod) := by - have := mul_lt_mul_of_pos_left hfloor_lt (by positivity : (0:Int) < 2 ^ 1193); linarith [this] - -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + W_ev·(2^126−r0) + 2·2^1193·(2^126+r0) - have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ - 2 ^ 1193 * (ev - tod) + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by - have hid1 : 2 ^ 126 * (evP + todP) - r0 * DE = evP * (2 ^ 126 - r0) + todP * (2 ^ 126 + r0) := by - rw [hDEdef]; ring - have hid2 : (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) - + (2 ^ 1193 * tod + 2 * 2 ^ 1193) * (2 ^ 126 + r0) - = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) - + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by ring - rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] - -- bound RHS by 6·DE. DE ≥ 2^1193·(den−2), den ≥ den_lo. - have hDEden : 2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193 ≤ DE := by - rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] - -- (A) 2^1193·den ≤ DE + 2·2^1193 ≤ 2·DE (32·2^1193... no, 2·2^1193 ≤ DE since DE>2^1317) - have hD1317 : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] - have h2 : (2 : Int) * 2 ^ 1193 ≤ DE := by - have he : (2 : Int) * 2 ^ 1193 = 2 ^ 1194 := by rw [show (1194:Nat) = 1193 + 1 from rfl, pow_succ]; ring - have : (2 : Int) * 2 ^ 1193 < 2 ^ 1317 := by - rw [he]; exact pow_lt_pow_right₀ (by norm_num) (by norm_num) - linarith [this, hD1317] - have hAterm : 2 ^ 1193 * (ev - tod) ≤ 2 * DE := by - have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 2 * 2 ^ 1193 := by linarith [hDEden] - linarith [hden2, h2] - -- (B) W_ev·(2^126−r0) ≤ 2·DE (2^126−r0 ≤ 2^126; W_ev·2^126 = 1130577·2^1299; vs 2·DE ≥ 2·2^1193·(den−2)) - have hBterm : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1 * DE := by - have hle : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1130577 * 2 ^ 1173 * 2 ^ 126 := - mul_le_mul_of_nonneg_left (by linarith [hr0lo]) (by positivity) - -- 1130577·2^1173·2^126 = 1130577·2^1299 ; DE ≥ 2^1193·(den−2); 1130577·2^106 ≤ (den−2) - have hkey : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 ≤ 1 * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) := by - have hA : (2:Int) ^ 1173 * 2 ^ 126 = 2 ^ 106 * 2 ^ 1193 := by rw [← pow_add, ← pow_add] - have hp : (0:Int) < (2:Int) ^ 1193 := by positivity - have heL : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 = (1130577 * 2 ^ 106) * 2 ^ 1193 := by - have e : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 = 1130577 * (2 ^ 1173 * 2 ^ 126) := by ring - rw [e, hA]; ring - have heR : (1 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (1 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring - rw [heL, heR, mul_le_mul_right hp] - have h106 : (1130577 * 2 ^ 106 : Int) = 91723303209870778371580046068760444928 := by norm_num - calc (1130577 * 2 ^ 106 : Int) = 91723303209870778371580046068760444928 := h106 - _ ≤ 1 * ((ev - tod) - 2) := by linarith [hden_A4] - linarith [hle, hkey] - -- (C) 2·2^1193·(2^126+r0) ≤ 2·DE. (2^126+r0) ≤ 2·2^126 (r0 ≤ 2^126); 2·2^1193·2·2^126 = 4·2^1319; vs 2·DE. - have hCterm : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 4 * DE := by - have hle : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 2 * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) := - mul_le_mul_of_nonneg_left (by linarith [hr0le]) (by positivity) - have hkey : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) ≤ 4 * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) := by - have hA : (2:Int) ^ 1193 * 2 ^ 126 = 2 ^ 1319 := by rw [← pow_add] - have hp : (0:Int) < (2:Int) ^ 1193 := by positivity - -- LHS = 2·2^1193·2·2^126 = 4·2^1319 = (4·2^126)·2^1193; RHS = 2·((den)−2)·2^1193 - have heL : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) = (4 * 2 ^ 126) * 2 ^ 1193 := by ring - have heR : (4 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (4 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring - rw [heL, heR, mul_le_mul_right hp] - have h126 : (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := by norm_num - calc (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := h126 - _ ≤ 4 * ((ev - tod) - 2) := by linarith [hden_A4] - linarith [hle, hkey] - linarith [hcombine, hAterm, hBterm, hCterm] - -/-- **Per-point deficit (tight, negative half).** `2¹²⁶·exp(rt) ≤ r0 + 8` for `t ≤ 0`. -/ -theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by - have hunder := r0_certRatio_under_neg hx hC hC0 htneg - have htdom := tdom_neg hx hC hC0 htneg - set t := int256 (tTree x) with htdef - have hDElb := denExpV_lb_neg hx hC hC0 htneg - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - set r0 := int256 (r0Tree x) with hr0def - have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ 7 * (DE : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] - have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 7 := by - rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos] - -- certUp_real_neg: exp(t/2^128) ≤ (NE/DE)·Mp, Mp = 2^130/(2^130−1) - have hcu := certUp_real_neg htneg htdom - obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos - exact_mod_cast this - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef - have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mp := by - rw [hMpdef] - have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) = - ((2 ^ 130 : Int) : Real) * (NE : Real) / (((2 ^ 130 - 1 : Int) : Real) * (DE : Real)) := by - push_cast; field_simp; ring - rw [key]; exact hcu - have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) - have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp - -- 2^126·Et ≤ 2^126·(NE/DE)·Mp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mp−1) ≤ (r0+6) + 1/4 - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 7 + 3 / 10 := by - have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := - mul_le_mul_of_nonneg_left hEt_le (by positivity) - have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) := by ring - have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) ≤ 3 / 10 := by - rw [hMp1] - obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 - have hr0R : (r0 : Real) < (2 ^ 128 : Real) := by - have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi - rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h - have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn - have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 7 := by - linarith [hr0_ge, hr0R] - calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / ((2 ^ 130 : Real) - 1)) - ≤ ((2 ^ 128 : Real) + 7) * (1 / ((2 ^ 130 : Real) - 1)) := - mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) - _ ≤ 3 / 10 := by norm_num - linarith [h1, h2 ▸ h1, h3, hr0_ge] - -- gap-1 (under, tight) - set Ert := Real.exp (reducedArg x) with hErtdef - have hgapunder := reducedArg_close_under hx hC hC0 - have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ - have hErt_le_two := exp_reducedArg_le_two hx hC hC0 - rw [← hErtdef] at hErt_le_two - have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 6 / 10 := by - have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := - le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) - have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := - mul_le_mul_of_nonneg_left hgap (by positivity) - have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ - (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) := - mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) ≤ 6 / 10 := by norm_num - linarith [h1, h2, h3] - have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 8 - linarith [hEt_bound, hgap126, hdist] - -/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 8`. -/ -theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by - rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg - · exact r0_real_under_tight hx hC hC0 htnn - · exact r0_real_under_tight_neg hx hC hC0 (le_of_lt htneg) - end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean new file mode 100644 index 000000000..c9bc2e89d --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -0,0 +1,611 @@ +import ExpProof.Floor.R0Exp + +/-! +# The deficit (under) side of the per-point `r0`-vs-`exp` bridge + +Split out of `R0Exp.lean` so the over and under clusters compile (and kernel-check) in parallel and +incremental edits to one do not recheck the other. Mirror of the never-over `r0_real_over_within`: +the per-point deficit `2¹²⁶·exp(rt) ≤ r0 + 8` (`r0_real_under_within`), both signs. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Poly + +set_option maxRecDepth 100000 +set_option maxHeartbeats 1600000 + +/-! ## The deficit (under) side: per-point `2¹²⁶·exp(rt) ≤ r0 + 8` (both signs) + +Mirror of the never-over `r0_real_over_within`. The nonneg half drops the even truncation +`Ee·(2¹²⁶−r0) ≤ 0` and bounds the tod truncation; the negative half drops the tod and bounds the +even truncation. Both feed the closing-shift deficit budget `c_under < 8.43 = 2⁶³/WAD − MARGIN/WAD` +at the binding `k = 63`. -/ + +/-- **`todNumV` upper bound (nonneg half).** For `0 ≤ t`: +`todNumV(t) ≤ 2¹¹⁹³·tod + 2¹¹⁹³ + W_od·2¹⁰³⁹·t`. -/ +theorem todNumV_ub {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + evalPoly ExpCertV.todNumV (int256 (tTree x)) ≤ + 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 + 69402657 * 2 ^ 1039 * (int256 (tTree x)) := by + obtain ⟨_, _, _, htodhi⟩ := todTree_bound hx hC hC0 + obtain ⟨_, hodhi⟩ := odNumVPoly_bracket hx hC hC0 + set t := int256 (tTree x) with htdef + rw [evalTodNumV] + -- todP = 2^23·t·odpoly. t ≥ 0, odpoly ≤ 2^1042·od + W_od·2^1016 ⟹ 2^23·t·odpoly ≤ 2^23·t·(…) + have hmul : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) ≤ + 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) := by + apply mul_le_mul_of_nonneg_left _ (by positivity) + exact mul_le_mul_of_nonneg_left (le_of_lt hodhi) htnn + -- 2^23·t·(2^1042 od + W_od 2^1016) = 2^1065·(t·od) + W_od·2^1039·t ; 2^1065·(t·od) < 2^1193·tod + 2^1193 + have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi + have key : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) ≤ + 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t := by + have e1 : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) = + 2 ^ 1065 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1039 * t := by ring + have e2 : (2 : Int) ^ 1065 * ((2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128) = + 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 := by + rw [show (2:Int) ^ 1193 = 2 ^ 1065 * 2 ^ 128 from by rw [← pow_add]]; ring + rw [e1] + have h := mul_le_mul_of_nonneg_left (le_of_lt htod_hi) (by positivity : (0:Int) ≤ 2 ^ 1065) + rw [e2] at h + linarith [h] + linarith [hmul, key] + +/-- **`num ≤ 1.45·den`** (`ê ≤ 1.45`) on the nonneg half, from `exp(t/2¹²⁸) ≤ √2` and the cert. -/ +theorem num_le_145_den {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 100 * ((evTree x : Int) + int256 (todTree x)) ≤ 145 * ((evTree x : Int) - int256 (todTree x)) := by + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + set t := int256 (tTree x) with htdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + have hDElb := denExpV_lb hx hC hC0 htnn + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + have hcertlo := certLo_real htnn htdom + set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn + rw [← hEtdef] at hEtsqrt2 + have hMp_pos : (0:Real) < Mp := by rw [hMpdef]; positivity + have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by + have hc : ((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + rw [hMpdef] + have key : (NE : Real) / (DE : Real) = + ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) * + (((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real))) := by + push_cast; field_simp; ring + rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) + -- num bound: 2^1193·num ≤ NE, DE < 2^1193·den + 3·2^1193 + obtain ⟨hnumlo, _⟩ := numExpV_bracket hx hC hC0 htnn + obtain ⟨_, hdenhi⟩ := denExpV_bracket hx hC hC0 htnn + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ den := den_ge_072 hx hC hC0 + have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden072 + have hdenR : (0:Real) < (den : Real) := by exact_mod_cast hdenpos + have hden072R : (61251667550081741634933722430035858604 : Real) ≤ (den : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hden072; push_cast at this; linarith [this] + have hnumloR : (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hnumlo; push_cast at this; linarith [this] + have hdenhiR : (DE : Real) < (2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193 := by + have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hdenhi; push_cast at this; linarith [this] + have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by + rw [Real.sqrt_le_iff]; constructor <;> norm_num + have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ + have hMp_le : Mp ≤ 14144 / 14143 := by + rw [hMpdef, div_le_div_iff₀ (by norm_num) (by norm_num)] + have h130 : (14144 : Real) ≤ 2 ^ 130 := by + rw [show (2:Real) ^ 130 = 1361129467683753853853498429727072845824 from by norm_num]; norm_num + nlinarith [h130] + have hsM_le : Real.sqrt 2 * Mp ≤ 14144 / 10000 := by + have hMpnn : (0:Real) ≤ Mp := by rw [hMpdef]; positivity + calc Real.sqrt 2 * Mp ≤ (14143 / 10000) * (14144 / 14143) := + mul_le_mul hsqrt2_val hMp_le hMpnn (by norm_num) + _ = 14144 / 10000 := by norm_num + -- NE ≤ √2·Mp·DE ≤ (14144/10000)·DE + have hNE_le : (NE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by + have h1 : (NE : Real) ≤ Et * Mp * (DE : Real) := by + have := mul_le_mul_of_nonneg_right hNEDE_le (le_of_lt hDEpos) + rwa [div_mul_cancel₀ _ (ne_of_gt hDEpos)] at this + have h2 : Et * Mp * (DE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by + apply mul_le_mul_of_nonneg_right _ (le_of_lt hDEpos) + exact mul_le_mul_of_nonneg_right hEtsqrt2 (le_of_lt hMp_pos) + linarith [h1, h2] + -- num ≤ (14144/10000)·(den+3) + have hnum_le : (num : Real) ≤ (14144 / 10000) * ((den : Real) + 3) := by + have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity + rw [← mul_le_mul_left hp] + calc (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := hnumloR + _ ≤ Real.sqrt 2 * Mp * (DE : Real) := hNE_le + _ ≤ (14144 / 10000) * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := by + calc Real.sqrt 2 * Mp * (DE : Real) + ≤ (14144 / 10000) * (DE : Real) := mul_le_mul_of_nonneg_right hsM_le (le_of_lt hDEpos) + _ ≤ (14144 / 10000) * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := + mul_le_mul_of_nonneg_left (le_of_lt hdenhiR) (by norm_num) + _ = (2 ^ 1193 : Real) * ((14144 / 10000) * ((den : Real) + 3)) := by ring + -- 100·num ≤ 145·den as Real: 100·(14144/10000)(den+3) ≤ 145·den ⟺ den huge + have hkey : (100 : Real) * (num : Real) ≤ 145 * (den : Real) := by + have h1 : (100 : Real) * (num : Real) ≤ 100 * ((14144 / 10000) * ((den : Real) + 3)) := + mul_le_mul_of_nonneg_left hnum_le (by norm_num) + nlinarith [h1, hden072R] + have : ((100 * num : Int) : Real) ≤ ((145 * den : Int) : Real) := by push_cast; linarith [hkey] + exact_mod_cast this + +/-- `r0` is bracketed on the nonneg half: `2¹²⁶ ≤ r0 ≤ 1.45·2¹²⁶` (so `2¹²⁶+r0 ≤ 2.45·2¹²⁶`). -/ +theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (2 : Int) ^ 126 ≤ int256 (r0Tree x) ∧ + 100 * (int256 (r0Tree x)) ≤ 145 * 2 ^ 126 := by + obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + have h145 := num_le_145_den hx hC hC0 htnn + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 + -- tod ≥ 0 on nonneg half + have htodnn : (0:Int) ≤ tod := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ + have htod : (2 ^ 128 : Int) * tod ≤ int256 (tTree x) * (odTree x : Int) := htodlo + have hpos : (0:Int) ≤ int256 (tTree x) * (odTree x : Int) := mul_nonneg htnn hodnn + nlinarith [htod, hpos] + refine ⟨?_, ?_⟩ + · -- 2^126 ≤ r0: 2^126·num < (r0+1)·den, num ≥ den ⟹ 2^126·den < (r0+1)·den ⟹ 2^126 < r0+1 + have hnumden : (2:Int)^126 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := by nlinarith [htodnn] + have h : (2:Int)^126 * (ev - tod) < (r0 + 1) * (ev - tod) := lt_of_le_of_lt hnumden hfloor_hi + have := lt_of_mul_lt_mul_right h (le_of_lt hdenpos) + omega + · -- 100·r0 ≤ 145·2^126: 100·r0·den ≤ 100·2^126·num ≤ 2^126·145·den + have h1 : 100 * (r0 * (ev - tod)) ≤ 100 * (2 ^ 126 * (ev + tod)) := + mul_le_mul_of_nonneg_left hfloor_lo (by norm_num) + have h2 : (2:Int)^126 * (100 * (ev + tod)) ≤ 2 ^ 126 * (145 * (ev - tod)) := + mul_le_mul_of_nonneg_left h145 (by positivity) + have hchain : 100 * r0 * (ev - tod) ≤ 145 * 2 ^ 126 * (ev - tod) := by nlinarith [h1, h2] + exact le_of_mul_le_mul_right hchain hdenpos + +/-- **Joint cert-ratio under (nonneg half):** `2¹²⁶·NE − r0·DE ≤ 7·DE`. The shared even truncation +`Ee·(2¹²⁶−r0) ≤ 0` (since `r0 ≥ 2¹²⁶`) is dropped; the floor `2¹²⁶·num − r0·den < den` gives the +`2¹¹⁹³·den` term, and the binding tod truncation `Et' ≤ (2¹¹⁹³ + W_od·2¹⁰³⁹·t)·(2¹²⁶+r0)` is small +because `t ≤ H128` is far below `2¹²⁸`. -/ +theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ + 7 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hevlo, _⟩ := evNumVPoly_bracket hx hC hC0 + have htodub := todNumV_ub hx hC hC0 htnn + obtain ⟨hr0lo, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn + obtain ⟨hdenlo, _⟩ := denExpV_bracket hx hC hC0 htnn + have hDElb := denExpV_lb hx hC hC0 htnn + rw [evalNumExpV, evalDenExpV] + set t := int256 (tTree x) with htdef + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set evP := evalPoly ExpCertV.evNumVPoly t with hevP + set todP := evalPoly ExpCertV.todNumV t with htodP + set DE := evP - todP with hDEdef + -- 2^126·NE − r0·DE = evP·(2^126−r0) + todP·(2^126+r0) + -- = 2^1193·[2^126·num − r0·den] + Ee·(2^126−r0) + Et'·(2^126+r0) + -- ≤ 2^1193·den + 0 + (2^1193 + W·2^1039·t)·(2^126+r0) + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 + have h2126r0_np : (2:Int) ^ 126 - r0 ≤ 0 := by linarith [hr0lo] + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] + -- evP·(2^126−r0) ≤ 2^1193·ev·(2^126−r0) (evP ≥ 2^1193·ev, factor ≤ 0) + have hterm1 : evP * (2 ^ 126 - r0) ≤ 2 ^ 1193 * ev * (2 ^ 126 - r0) := + mul_le_mul_of_nonpos_right hevlo h2126r0_np + -- todP·(2^126+r0) ≤ (2^1193·tod + 2^1193 + W·2^1039·t)·(2^126+r0) (todP upper, factor ≥ 0) + have hterm2 : todP * (2 ^ 126 + r0) ≤ + (2 ^ 1193 * tod + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := + mul_le_mul_of_nonneg_right htodub hr0p_nn + -- floor: 2^126·num − r0·den < den, scaled by 2^1193: 2^1193·(2^126·num − r0·den) < 2^1193·den + have hfloor_lt : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) < (ev - tod) := by linarith [hfloor_hi] + have hfloor1193 : (2 ^ 1193 : Int) * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) < + 2 ^ 1193 * (ev - tod) := by + have := mul_lt_mul_of_pos_left hfloor_lt (by positivity : (0:Int) < 2 ^ 1193); linarith [this] + -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + (2^1193 + W·2^1039·t)·(2^126+r0) + have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ + 2 ^ 1193 * (ev - tod) + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by + have hid1 : 2 ^ 126 * (evP + todP) - r0 * DE = evP * (2 ^ 126 - r0) + todP * (2 ^ 126 + r0) := by + rw [hDEdef]; ring + have hid2 : 2 ^ 1193 * ev * (2 ^ 126 - r0) + (2 ^ 1193 * tod + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) + = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) + + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by ring + rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] + -- now bound the RHS ≤ 6·DE. + -- (A) 2^1193·den ≤ DE + 32·2^1193 (denExpV hi), and 32·2^1193 ≤ DE (DE > 2^1317): 2^1193·den ≤ 2·DE + have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 32 * 2 ^ 1193 := by + rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] + have h32 : (32 : Int) * 2 ^ 1193 ≤ DE := by + have hD1317 : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] + have : (32 : Int) * 2 ^ 1193 < 2 ^ 1317 := by + rw [show (32:Int) * 2 ^ 1193 = 2 ^ 1198 from by rw [show (32:Int)=2^5 from by norm_num, ← pow_add]] + exact pow_lt_pow_right₀ (by norm_num) (by norm_num) + linarith [this, hD1317] + have hAterm : 2 ^ 1193 * (ev - tod) ≤ 2 * DE := by linarith [hden2, h32] + -- (B) (2^1193 + W·2^1039·t)·(2^126+r0) ≤ 4·DE. bound via t ≤ H128, 2^126+r0 ≤ 2.45·2^126. + have hDElb' : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have htH : t ≤ 117932881612756647068972071382077242199 := hthi + -- 2^126 + r0 ≤ 2.45·2^126, i.e. 100·(2^126+r0) ≤ 245·2^126 + have hr0p_bound : 100 * (2 ^ 126 + r0) ≤ 245 * 2 ^ 126 := by linarith [hr0hi145] + have hBterm : (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) ≤ 5 * DE := by + have hDEden : 2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193 ≤ DE := by + rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] + have hden_lo : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + -- 2^1193 + W·2^1039·t ≤ 2^1193 + W·2^1039·H128 (t ≤ H128, t ≥ 0) + have hcoeff : 2 ^ 1193 + 69402657 * 2 ^ 1039 * t ≤ + 2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199 := by + have := mul_le_mul_of_nonneg_left htH (by positivity : (0:Int) ≤ 69402657 * 2 ^ 1039); linarith [this] + have hC0nn : (0:Int) ≤ 2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199 := by positivity + have hLHS : (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) ≤ + (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0) := + mul_le_mul_of_nonneg_right hcoeff hr0p_nn + -- 100·(C0·(2^126+r0)) ≤ C0·245·2^126 + have hLHS2 : 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) ≤ + (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := by + have h := mul_le_mul_of_nonneg_left hr0p_bound hC0nn + have hid : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (100 * (2 ^ 126 + r0)) + = 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) := by ring + have hid2 : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) + = (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := rfl + linarith [h, hid] + -- key integer cert (common 2^1165 scale): C0·245·2^126 ≤ 500·(2^1193·(den−32)). + have hkey : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) ≤ + 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by + -- factor everything to the common 2^1165 scale and compare coefficients + have hA : (2:Int) ^ 1193 * 2 ^ 126 = 2 ^ 154 * 2 ^ 1165 := by rw [← pow_add, ← pow_add] + have hpe2 : (2:Int) ^ 1039 * 2 ^ 126 = 2 ^ 1165 := by rw [← pow_add] + have hpe3 : (2:Int) ^ 1193 = 2 ^ 28 * 2 ^ 1165 := by rw [← pow_add] + have hp : (0:Int) < (2:Int) ^ 1165 := by positivity + -- the coefficient inequality, scaled by 2^1165 + have hcoeff_le : (245 * 2 ^ 154 + 245 * 69402657 * 117932881612756647068972071382077242199 : Int) ≤ + 500 * 2 ^ 28 * ((ev - tod) - 32) := by + have h154 : (2:Int)^154 = 22835963083295358096932575511191922182123945984 := by norm_num + have h28 : (2:Int)^28 = 268435456 := by norm_num + rw [h154, h28]; linarith [hden_lo] + have hscaled := mul_le_mul_of_nonneg_right hcoeff_le (le_of_lt hp) + -- rewrite both sides to the (·)·2^1165 form + calc (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) + = (245 * 2 ^ 154 + 245 * 69402657 * 117932881612756647068972071382077242199) * 2 ^ 1165 := by + linear_combination (245 : Int) * hA + (245 * 69402657 * 117932881612756647068972071382077242199 : Int) * hpe2 + _ ≤ (500 * 2 ^ 28 * ((ev - tod) - 32)) * 2 ^ 1165 := hscaled + _ = 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by + linear_combination (-500 * ((ev - tod) - 32) : Int) * hpe3 + -- LHS ≤ C0·(2^126+r0); 100·that ≤ C0·245·2^126 ≤ 500·(2^1193 den − 32·2^1193) ≤ 500·DE; so LHS ≤ 5·DE + have h500 : (500 : Int) * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) ≤ 500 * DE := by linarith [hDEden] + linarith [hLHS, hLHS2, hkey, h500] + linarith [hcombine, hAterm, hBterm] + +/-- **The joint per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 8`. From the joint +cert-ratio under (`2¹²⁶·NE − r0·DE ≤ 7·DE`), the not-too-below cert (`exp ≤ (NE/DE)·M⁺`), and the +under-direction gap-1 (`exp(rt) ≤ √2`, `rt − t/2¹²⁸ < 33/(32·2¹²⁸)`). -/ +theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + have hunder := r0_certRatio_under_nonneg hx hC hC0 htnn + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + set t := int256 (tTree x) with htdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + have hDElb := denExpV_lb hx hC hC0 htnn + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + set r0 := int256 (r0Tree x) with hr0def + -- 2^126·NE/DE ≤ r0 + 7 + have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ 7 * (DE : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] + have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 7 := by + rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos] + -- certUp: exp(t/2^128) ≤ (NE/DE)·Mpp + have hcertup := certUp_real htnn htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by + have := certNE_nonneg htnn htdom; exact_mod_cast this + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef + have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mpp := by + have hc : Et ≤ ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / + (((2 ^ 130 : Int) : Real) * (DE : Real)) := hcertup + rw [hMppdef] + have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) = + ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 130 : Int) : Real) * (DE : Real)) := by + push_cast; field_simp; ring + rw [key]; exact hc + have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) + have hMpp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp + -- Et ≤ √2 (nonneg half) + have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn + rw [← hEtdef] at hEtsqrt2 + have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num + have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ + -- 2^126·Et ≤ 2^126·(NE/DE)·Mpp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mpp−1) ≤ (r0+7) + 1/4 + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 7 + 3 / 10 := by + have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) := + mul_le_mul_of_nonneg_left hEt_le (by positivity) + have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) = + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) := by ring + -- 2^126·(NE/DE)·(Mpp−1) ≤ 3/10. NE/DE·2^126 ≤ r0+7 ≤ 2^128+7; ·(1/2^130) ≈ 1/4 < 3/10. + have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) ≤ 3 / 10 := by + rw [hMpp1] + obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 + have hr0R : (r0 : Real) < (2 ^ 128 : Real) := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi + rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h + have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn + have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 7 := by + linarith [hr0_ge, hr0R] + calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / (2 ^ 130 : Real)) + ≤ ((2 ^ 128 : Real) + 7) * (1 / (2 ^ 130 : Real)) := + mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) + _ ≤ 3 / 10 := by norm_num + linarith [h1, h2 ▸ h1, h3, hr0_ge] + -- gap-1 (under, tight): Ert − Et ≤ (rt − t/2^128)·Ert, rt − t/2^128 < 33/(32·2^128), Ert ≤ 2 + set Ert := Real.exp (reducedArg x) with hErtdef + have hgapunder := reducedArg_close_under hx hC hC0 + have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ + have hErt_le_two := exp_reducedArg_le_two hx hC hC0 + rw [← hErtdef] at hErt_le_two + have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) + have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 6 / 10 := by + have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := + le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) + have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := + mul_le_mul_of_nonneg_left hgap (by positivity) + have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ + (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) + have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) ≤ 6 / 10 := by norm_num + linarith [h1, h2, h3] + -- assemble: 2^126·Ert = 2^126·Et + 2^126·(Ert−Et) ≤ (r0+7+1/4) + 6/10 < r0 + 8 + have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 8 + linarith [hEt_bound, hgap126, hdist] + +/-- `r0 ≤ 2¹²⁶` on the negative half (num ≤ den ⟺ tod ≤ 0). -/ +theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + int256 (r0Tree x) ≤ 2 ^ 126 := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 + have htodnp : tod ≤ 0 := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ + have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn + nlinarith [htodlo, this] + -- r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den) + have hnumden : r0 * (ev - tod) ≤ 2 ^ 126 * (ev - tod) := by + have h1 : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo + nlinarith [h1, htodnp, (by positivity : (0:Int) ≤ (2:Int)^126)] + exact le_of_mul_le_mul_right hnumden hdenpos + +/-- **Joint cert-ratio under (negative half):** `2¹²⁶·NE − r0·DE ≤ 6·DE`. The binding even +truncation `Ee·(2¹²⁶−r0)` (small factor) and the tod truncation `Et'·(2¹²⁶+r0)` both fit. -/ +theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - + int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ + 7 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 + obtain ⟨_, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg + have hr0le := r0_le_2126_neg hx hC hC0 htneg + obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 + obtain ⟨hdenlo, _⟩ := denExpV_bracket_neg hx hC hC0 htneg + have hDElb := denExpV_lb_neg hx hC hC0 htneg + rw [evalNumExpV, evalDenExpV] + set t := int256 (tTree x) with htdef + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set evP := evalPoly ExpCertV.evNumVPoly t with hevP + set todP := evalPoly ExpCertV.todNumV t with htodP + set DE := evP - todP with hDEdef + have hden_lo : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + -- on the neg half tod ≤ 0, so den = ev − tod ≥ ev ≥ A4 + have htod_np : tod ≤ 0 := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ + have hp : t * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn + have h2 : (2 ^ 128 : Int) * tod ≤ 2 ^ 128 * 0 := by simpa using le_trans htodlo hp + exact le_of_mul_le_mul_left h2 (by norm_num) + have hden_A4 : (103786963415199049567855548359006885036 : Int) ≤ ev - tod := by + obtain ⟨hevlo', _⟩ := evTree_facts (vTree_eq hx hC hC0).2 + have hev : (103786963415199049567855548359006885036 : Int) ≤ ev := by + rw [hevdef]; have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo' + rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 from by norm_num] at this + exact this + linarith [hev, htod_np] + have h2126r0_nn : (0:Int) ≤ 2 ^ 126 - r0 := by linarith [hr0le] + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] + -- Ee = evP − 2^1193·ev ∈ [0, W_ev). evP·(2^126−r0) ≤ (2^1193·ev + W_ev)·(2^126−r0) + have hterm1 : evP * (2 ^ 126 - r0) ≤ (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) := + mul_le_mul_of_nonneg_right (le_of_lt hevhi) h2126r0_nn + -- Et' = todP − 2^1193·tod < 2·2^1193 ⟹ todP < 2^1193·tod + 2·2^1193; todP·(2^126+r0) ≤ (2^1193·tod+2·2^1193)·(2^126+r0) + have hterm2 : todP * (2 ^ 126 + r0) ≤ (2 ^ 1193 * tod + 2 * 2 ^ 1193) * (2 ^ 126 + r0) := + mul_le_mul_of_nonneg_right (le_of_lt htodhi) hr0p_nn + -- floor: 2^126·num − r0·den < den ⟹ 2^1193·(2^126·num − r0·den) < 2^1193·den + have hfloor_lt : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) < (ev - tod) := by linarith [hfloor_hi] + have hfloor1193 : (2 ^ 1193 : Int) * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) < + 2 ^ 1193 * (ev - tod) := by + have := mul_lt_mul_of_pos_left hfloor_lt (by positivity : (0:Int) < 2 ^ 1193); linarith [this] + -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + W_ev·(2^126−r0) + 2·2^1193·(2^126+r0) + have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ + 2 ^ 1193 * (ev - tod) + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by + have hid1 : 2 ^ 126 * (evP + todP) - r0 * DE = evP * (2 ^ 126 - r0) + todP * (2 ^ 126 + r0) := by + rw [hDEdef]; ring + have hid2 : (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) + + (2 ^ 1193 * tod + 2 * 2 ^ 1193) * (2 ^ 126 + r0) + = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) + + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by ring + rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] + -- bound RHS by 6·DE. DE ≥ 2^1193·(den−2), den ≥ den_lo. + have hDEden : 2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193 ≤ DE := by + rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] + -- (A) 2^1193·den ≤ DE + 2·2^1193 ≤ 2·DE (32·2^1193... no, 2·2^1193 ≤ DE since DE>2^1317) + have hD1317 : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] + have h2 : (2 : Int) * 2 ^ 1193 ≤ DE := by + have he : (2 : Int) * 2 ^ 1193 = 2 ^ 1194 := by rw [show (1194:Nat) = 1193 + 1 from rfl, pow_succ]; ring + have : (2 : Int) * 2 ^ 1193 < 2 ^ 1317 := by + rw [he]; exact pow_lt_pow_right₀ (by norm_num) (by norm_num) + linarith [this, hD1317] + have hAterm : 2 ^ 1193 * (ev - tod) ≤ 2 * DE := by + have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 2 * 2 ^ 1193 := by linarith [hDEden] + linarith [hden2, h2] + -- (B) W_ev·(2^126−r0) ≤ 2·DE (2^126−r0 ≤ 2^126; W_ev·2^126 = 1130577·2^1299; vs 2·DE ≥ 2·2^1193·(den−2)) + have hBterm : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1 * DE := by + have hle : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1130577 * 2 ^ 1173 * 2 ^ 126 := + mul_le_mul_of_nonneg_left (by linarith [hr0lo]) (by positivity) + -- 1130577·2^1173·2^126 = 1130577·2^1299 ; DE ≥ 2^1193·(den−2); 1130577·2^106 ≤ (den−2) + have hkey : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 ≤ 1 * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) := by + have hA : (2:Int) ^ 1173 * 2 ^ 126 = 2 ^ 106 * 2 ^ 1193 := by rw [← pow_add, ← pow_add] + have hp : (0:Int) < (2:Int) ^ 1193 := by positivity + have heL : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 = (1130577 * 2 ^ 106) * 2 ^ 1193 := by + have e : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 = 1130577 * (2 ^ 1173 * 2 ^ 126) := by ring + rw [e, hA]; ring + have heR : (1 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (1 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring + rw [heL, heR, mul_le_mul_right hp] + have h106 : (1130577 * 2 ^ 106 : Int) = 91723303209870778371580046068760444928 := by norm_num + calc (1130577 * 2 ^ 106 : Int) = 91723303209870778371580046068760444928 := h106 + _ ≤ 1 * ((ev - tod) - 2) := by linarith [hden_A4] + linarith [hle, hkey] + -- (C) 2·2^1193·(2^126+r0) ≤ 2·DE. (2^126+r0) ≤ 2·2^126 (r0 ≤ 2^126); 2·2^1193·2·2^126 = 4·2^1319; vs 2·DE. + have hCterm : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 4 * DE := by + have hle : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 2 * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) := + mul_le_mul_of_nonneg_left (by linarith [hr0le]) (by positivity) + have hkey : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) ≤ 4 * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) := by + have hA : (2:Int) ^ 1193 * 2 ^ 126 = 2 ^ 1319 := by rw [← pow_add] + have hp : (0:Int) < (2:Int) ^ 1193 := by positivity + -- LHS = 2·2^1193·2·2^126 = 4·2^1319 = (4·2^126)·2^1193; RHS = 2·((den)−2)·2^1193 + have heL : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) = (4 * 2 ^ 126) * 2 ^ 1193 := by ring + have heR : (4 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (4 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring + rw [heL, heR, mul_le_mul_right hp] + have h126 : (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := by norm_num + calc (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := h126 + _ ≤ 4 * ((ev - tod) - 2) := by linarith [hden_A4] + linarith [hle, hkey] + linarith [hcombine, hAterm, hBterm, hCterm] + +/-- **Per-point deficit (tight, negative half).** `2¹²⁶·exp(rt) ≤ r0 + 8` for `t ≤ 0`. -/ +theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + have hunder := r0_certRatio_under_neg hx hC hC0 htneg + have htdom := tdom_neg hx hC hC0 htneg + set t := int256 (tTree x) with htdef + have hDElb := denExpV_lb_neg hx hC hC0 htneg + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + have hDEpos_int : (0 : Int) < DE := by + have : (0:Int) < 2 ^ 1317 := by positivity + linarith [hDElb, this] + have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + set r0 := int256 (r0Tree x) with hr0def + have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ 7 * (DE : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] + have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 7 := by + rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos] + -- certUp_real_neg: exp(t/2^128) ≤ (NE/DE)·Mp, Mp = 2^130/(2^130−1) + have hcu := certUp_real_neg htneg htdom + obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom + have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos + exact_mod_cast this + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mp := by + rw [hMpdef] + have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) = + ((2 ^ 130 : Int) : Real) * (NE : Real) / (((2 ^ 130 - 1 : Int) : Real) * (DE : Real)) := by + push_cast; field_simp; ring + rw [key]; exact hcu + have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) + have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp + -- 2^126·Et ≤ 2^126·(NE/DE)·Mp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mp−1) ≤ (r0+6) + 1/4 + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 7 + 3 / 10 := by + have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := + mul_le_mul_of_nonneg_left hEt_le (by positivity) + have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) := by ring + have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) ≤ 3 / 10 := by + rw [hMp1] + obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 + have hr0R : (r0 : Real) < (2 ^ 128 : Real) := by + have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi + rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h + have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn + have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 7 := by + linarith [hr0_ge, hr0R] + calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / ((2 ^ 130 : Real) - 1)) + ≤ ((2 ^ 128 : Real) + 7) * (1 / ((2 ^ 130 : Real) - 1)) := + mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) + _ ≤ 3 / 10 := by norm_num + linarith [h1, h2 ▸ h1, h3, hr0_ge] + -- gap-1 (under, tight) + set Ert := Real.exp (reducedArg x) with hErtdef + have hgapunder := reducedArg_close_under hx hC hC0 + have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ + have hErt_le_two := exp_reducedArg_le_two hx hC hC0 + rw [← hErtdef] at hErt_le_two + have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) + have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 6 / 10 := by + have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := + le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) + have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := + mul_le_mul_of_nonneg_left hgap (by positivity) + have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ + (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) + have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) ≤ 6 / 10 := by norm_num + linarith [h1, h2, h3] + have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 8 + linarith [hEt_bound, hgap126, hdist] + +/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 8`. -/ +theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg + · exact r0_real_under_tight hx hC hC0 htnn + · exact r0_real_under_tight_neg hx hC hC0 (le_of_lt htneg) + +end ExpYul From 25d16a345fdc5ce25b6d1a871c288fc62f0e9a7c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 00:01:55 +0200 Subject: [PATCH 080/149] Speed up the over-side R0Exp tactics Apply the nlinarith->linarith + positivity-fix pattern to the over cluster: r0_certRatio_over_neg's joint cross-product combine via a ring identity + linarith (was nlinarith); hevnn via Int.natCast_nonneg; the three tod <= 0 proofs via le_of_mul_le_mul_left on 2^128*tod <= 2^128*0 (was nlinarith); hstep1 via linarith on the negated bound. The genuinely-nonlinear den^2 nlinarith are left as-is. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 0cb3062e0..23959d30d 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -1949,7 +1949,8 @@ theorem r0_certRatio_over_neg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 -- 2^128·tod ≤ t·od ≤ 0 have htod_nonpos : (2 ^ 128 : Int) * tod ≤ 0 := le_trans htodlo (mul_nonpos_of_nonpos_of_nonneg htneg hodnn) - nlinarith [htod_nonpos] + have h2 : (2 ^ 128 : Int) * tod ≤ 2 ^ 128 * 0 := by simpa using htod_nonpos + exact le_of_mul_le_mul_left h2 (by norm_num) -- r0 ≤ 2^126: r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den ⟺ tod ≤ 0); den > 0 have hdenpos : (0:Int) < ev - tod := by have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this @@ -1973,8 +1974,13 @@ theorem r0_certRatio_over_neg {x : Nat} (hx : x < 2 ^ 256) have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] have hfloor1193 : (2 ^ 1193 : Int) * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor - -- assemble - nlinarith [hterm1, hterm2, hfloor1193] + -- assemble: the goal LHS is evP·(r0−2^126) − todP·(r0+2^126); the bound terms collapse via the floor + have hid1 : r0 * (evP - todP) - 2 ^ 126 * (evP + todP) = evP * (r0 - 2 ^ 126) - todP * (r0 + 2 ^ 126) := by ring + have hid2 : 2 ^ 1193 * ev * (r0 - 2 ^ 126) - (2 ^ 1193 * tod + 69402657 * 2 ^ 1039 * t) * (r0 + 2 ^ 126) + = 2 ^ 1193 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) + 69402657 * 2 ^ 1039 * (-t) * (r0 + 2 ^ 126) := by + ring + rw [hid1] + linarith [hterm1, hterm2, hfloor1193, hid2] /-- **The joint per-point never-over (negative half).** `r0 ≤ 2¹²⁶·exp(rt) + 19/25` for `t ≤ 0`. -/ @@ -2006,8 +2012,9 @@ theorem r0_certRatio_over_neg_bound {x : Nat} (hx : x < 2 ^ 256) have hodnn : (0:Int) ≤ od := le_of_lt hodpos have htod_np : tod ≤ 0 := by have hle : (2 ^ 128 : Int) * tod ≤ t * od := htodlo - have : t * od ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htnp hodnn - nlinarith [hle, this] + have hp : t * od ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htnp hodnn + have h2 : (2 ^ 128 : Int) * tod ≤ 2 ^ 128 * 0 := by simpa using le_trans hle hp + exact le_of_mul_le_mul_left h2 (by norm_num) have hntodnn : (0:Int) ≤ -tod := by omega -- den := ev - tod > 0; den ≥ 0.72·2^126 have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by @@ -2015,7 +2022,10 @@ theorem r0_certRatio_over_neg_bound {x : Nat} (hx : x < 2 ^ 256) have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 -- (1) (−t)·od ≤ 2^128·(−tod): 2^128·tod ≤ t·od ⟹ −t·od ≤ −2^128·tod = 2^128·(−tod) have hstep1 : (-t) * od ≤ 2 ^ 128 * (-tod) := by - have hle : (2 ^ 128 : Int) * tod ≤ t * od := htodlo; nlinarith [hle] + have hle : (2 ^ 128 : Int) * tod ≤ t * od := htodlo + have he : (-t) * od = -(t * od) := by ring + have he2 : (2:Int) ^ 128 * (-tod) = -(2 ^ 128 * tod) := by ring + rw [he, he2]; linarith [hle] -- (2) (r0+2^126)·(ev−tod) ≤ 2^127·ev: r0·(ev−tod) ≤ 2^126·(ev+tod) (floor), +2^126·(ev−tod) have hstep2 : (r0 + 2 ^ 126) * (ev - tod) ≤ 2 ^ 127 * ev := by have hfl : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo @@ -2052,7 +2062,7 @@ theorem r0_certRatio_over_neg_bound {x : Nat} (hx : x < 2 ^ 256) have hP2 : 2 ^ 128 * (-tod) * ((r0 + 2 ^ 126) * den) ≤ 2 ^ 128 * (-tod) * (2 ^ 127 * ev) := mul_le_mul_of_nonneg_left hdR2 hntden -- combine + hstep4: 36·(−t)·od·(r0+2^126)·den ≤ 36·2^255·(−tod)·ev ≤ 5·2^255·den² - have hevnn : (0:Int) ≤ ev := by nlinarith [hdenpos, htod_np] + have hevnn : (0:Int) ≤ ev := by rw [hevdef]; exact Int.natCast_nonneg _ have hP3 : 36 * ((-t) * od * ((r0 + 2 ^ 126) * den)) ≤ 5 * 2 ^ 255 * den ^ 2 := by have h255 : 2 ^ 128 * (-tod) * (2 ^ 127 * ev) = 2 ^ 255 * ((-tod) * ev) := by rw [show (2:Int) ^ 255 = 2 ^ 128 * 2 ^ 127 from by rw [← pow_add]]; ring From 717d0d8f61d0ba2688a985ccb09a569cfa2a8fbc Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 00:17:34 +0200 Subject: [PATCH 081/149] Wire LnProof into the exp proof package for the round-trip The round-trip guarantee (`expRayToWad(lnWadToRay(w)) == w - 1`) composes the exp runtime with the verified `lnWadToRay` runtime, so ExpProof now requires LnProof. The exp CI gains the LnProof artifact generation and build steps it transitively depends on, and its cache covers LnProof's build directory. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .github/workflows/exp-formal.yml | 44 +++++++++++++++++++++++++- formal/exp/ExpProof/lake-manifest.json | 9 +++++- formal/exp/ExpProof/lakefile.toml | 4 +++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index 437b481da..1594ba6e6 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -6,8 +6,11 @@ on: - master paths: - src/vendor/Exp.sol + - src/vendor/Ln.sol - src/wrappers/ExpWrapper.sol + - src/wrappers/LnWrapper.sol - formal/exp/** + - formal/ln/** - formal/common/** - formal/yul/** - foundry.toml @@ -16,8 +19,11 @@ on: pull_request: paths: - src/vendor/Exp.sol + - src/vendor/Ln.sol - src/wrappers/ExpWrapper.sol + - src/wrappers/LnWrapper.sol - formal/exp/** + - formal/ln/** - formal/common/** - formal/yul/** - foundry.toml @@ -51,8 +57,9 @@ jobs: formal/yul/.lake/packages/*/.lake/build lib/EVMYulLean/.lake/build formal/common/.lake/build + formal/ln/LnProof/.lake/build formal/exp/ExpProof/.lake/build - key: ${{ runner.os }}-exp-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/common/lakefile.toml', 'formal/common/lake-manifest.json', 'formal/common/**/*.lean', 'formal/exp/ExpProof/lakefile.toml', 'formal/exp/ExpProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/exp/ExpProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} + key: ${{ runner.os }}-exp-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/common/lakefile.toml', 'formal/common/lake-manifest.json', 'formal/common/**/*.lean', 'formal/ln/LnProof/lakefile.toml', 'formal/ln/LnProof/lake-manifest.json', 'formal/ln/LnProof/**/*.lean', 'formal/exp/ExpProof/lakefile.toml', 'formal/exp/ExpProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/exp/ExpProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} restore-keys: | ${{ runner.os }}-exp-formal-lean- ${{ runner.os }}-formal-lean- @@ -86,6 +93,41 @@ jobs: formal/exp/ExpProof/ExpProof/ExpYul.lean \ 0.8.34 + - name: Generate EVMYulLean artifacts from compiled LnWrapper Yul IR + run: | + ./formal/yul/generate_from_forge.sh \ + ln \ + src/wrappers/LnWrapper.sol:LnWrapper \ + formal/ln/LnProof/LnProof/LnYul.lean \ + 0.8.34 + + - name: Fetch ln proof dependency cache + working-directory: formal/ln/LnProof + run: | + # Mathlib's `cache get` fetches the ProofWidgets cloud release, then + # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch + # the release and ensure those directories exist before it runs. + lake build proofwidgets:release + mkdir -p \ + .lake/packages/proofwidgets/.lake/build/lib \ + .lake/packages/proofwidgets/.lake/build/ir + lake exe cache get + + - name: Generate ln Lean certificate artifacts + working-directory: formal/ln/LnProof + run: | + lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts + lake env lean GenFloorCertLit.lean + lake build LnProof.Cert.FloorCertLit + lake env lean GenCover.lean + lake env lean GenErr1.lean + lake build LnProof.Error.Core + lake env lean GenErrLit.lean + + - name: Build Ln proof dependency + working-directory: formal/ln/LnProof + run: lake build + - name: Fetch proof dependency cache working-directory: formal/exp/ExpProof run: | diff --git a/formal/exp/ExpProof/lake-manifest.json b/formal/exp/ExpProof/lake-manifest.json index f2f7eb5e2..740ce6f8f 100644 --- a/formal/exp/ExpProof/lake-manifest.json +++ b/formal/exp/ExpProof/lake-manifest.json @@ -2,6 +2,13 @@ "packagesDir": "../../yul/.lake/packages", "packages": [{"type": "path", + "scope": "", + "name": "LnProof", + "manifestFile": "lake-manifest.json", + "inherited": false, + "dir": "../../ln/LnProof", + "configFile": "lakefile.toml"}, + {"type": "path", "scope": "", "name": "Common", "manifestFile": "lake-manifest.json", @@ -20,7 +27,7 @@ "name": "evmyul", "manifestFile": "lake-manifest.json", "inherited": true, - "dir": "../../common/../yul/../../lib/EVMYulLean", + "dir": "../../ln/LnProof/../../common/../yul/../../lib/EVMYulLean", "configFile": "lakefile.lean"}, {"url": "https://github.com/leanprover-community/mathlib4.git", "type": "git", diff --git a/formal/exp/ExpProof/lakefile.toml b/formal/exp/ExpProof/lakefile.toml index 82d3a37dc..455736d3e 100644 --- a/formal/exp/ExpProof/lakefile.toml +++ b/formal/exp/ExpProof/lakefile.toml @@ -13,3 +13,7 @@ path = "../../yul" [[require]] name = "Common" path = "../../common" + +[[require]] +name = "LnProof" +path = "../../ln/LnProof" From 58fe2b6454ea5ed118c06bce695ed56bf8dba848 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 00:39:23 +0200 Subject: [PATCH 082/149] Prove the expRayToWad/lnWadToRay round trip For w on the central band w/10^18 in [1/sqrt2, sqrt2), the runtime composition expRayToWad(lnWadToRay(w)) returns w - 1, and returns w at the scale point w = 10^18. This is the form documented by Exp.sol. The proof composes the verified lnWadToRay runtime (LnProof) with the exp runtime: the lnWadToRay error bracket places the target E in (w - 1, w], and the exp runtime strict never-over plus region-uniform deficit pin the floored body word to w - 1. The theorem is unconditional and axiom-clean ([propext, Classical.choice, Quot.sound]). Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex --- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 394 ++++++++++++++++++ formal/exp/ExpProof/ExpProof/Theorems.lean | 32 +- 2 files changed, 420 insertions(+), 6 deletions(-) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean new file mode 100644 index 000000000..688f22061 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -0,0 +1,394 @@ +import ExpProof.Floor.PublicUncond +import LnProof.Theorems +import LnProof.Correct +import LnProof.Spec.Real + +/-! +# The `lnWadToRay` round trip: `expRayToWad(lnWadToRay(w)) = w − 1` + +`Exp.sol` documents that `expRayToWad` is the inverse of `Ln.lnWadToRay` on the central octave: for +`w` with `w/10¹⁸ ∈ [1/√2, √2)` the round trip returns `w − 1` (and `w` at the scale point +`w = 10¹⁸`). The proof targets that documented composition: `lnWadToRay`'s ≈10⁻⁹-ulp envelope keeps +the target `E` a fixed distance below the integer `w`, far above the ≈10⁻¹⁹-ulp accumulator deficit. + +The proof composes the verified `lnWadToRay` runtime (`LnProof`) with the exp runtime: + +* `lnWadToRayRuntimeCorrect` brackets `x = lnWadToRay(w)` against `X = 10²⁷·ln(w/10¹⁸)` + (`x ≤ X < x + 2`), so `E = 10¹⁸·exp(x/10²⁷) = w·exp((x − X)/10²⁷) ∈ (w − 1, w]`; +* the exp runtime's strict never-over (`accumReal x < E`, from the `MARGIN` slack) and floor + (`r1Tree x = ⌊accumReal x⌋`) pin `w − 1 ≤ accumReal x < w`, hence `r1Tree x = w − 1`; +* at `w = 10¹⁸`, `lnWadToRay(10¹⁸) = 0` and `expRayToWad(0) = 10¹⁸` (the scale-point pins). +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Word +open ExpRealSpec + +noncomputable section + +set_option maxRecDepth 100000 + +/-! ## Strict never-over: the accumulator stays a positive distance below the target + +`accumReal_over` gives `accumReal x ≤ E`. The `MARGIN` is sized strictly above the never-over +envelope `WAD·19/25`, so the inequality is in fact strict — the slack +`δ = MARGIN − WAD·19/25 = 32161285993433738 > 0` (worth `δ/2^s` after the closing shift). The round +trip needs this strictness to rule out `accumReal x = w` exactly. -/ + +/-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the target. +The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 19/25` plus `WAD·19/25 < MARGIN` give a strictly negative +residue. -/ +theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) + (hC0 : int256 x < int256 C0thresh) : + accumReal x < expRayToWadTarget (int256 x) := by + obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 + have hps : (0 : Real) < (2 ^ s : Real) := by positivity + have hfold := target_octave_fold s hsint + have hover := r0_real_over_within hx hC hC0 + set Ert := Real.exp (reducedArg x) with hErt + -- WAD·r0 − MARGIN < WAD·2^126·Ert = E·2^s, using WAD·19/25 < MARGIN + have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 < + expRayToWadTarget (int256 x) * (2 ^ s : Real) := by + rw [hfold] + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 19 / 25 := hover + have hscaled : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) ≤ + (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 19 / 25) := + mul_le_mul_of_nonneg_left hr0R (by norm_num) + have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num + rw [hwad] + -- WAD·19/25 = 760000000000000000 < 792161285993433738 + nlinarith [hscaled] + rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] + +/-- **Accumulator deficit, region-uniform.** On the region the accumulator is below the target by +strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 8` and the +octave fold give `accumReal x ≥ E − (8·WAD + MARGIN)/2^s` with `s = 126 − k ≥ 63`, and +`(8·WAD + MARGIN)/2⁶³ < 24/25`. The tightness below one is what closes the round trip together with +`lnWadToRay`'s ≈10⁻⁹ envelope. -/ +theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) + (hC0 : int256 x < int256 C0thresh) : + expRayToWadTarget (int256 x) - 24 / 25 < accumReal x := by + obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 + have hps : (0 : Real) < (2 ^ s : Real) := by positivity + have hfold := target_octave_fold s hsint + have hunder := r0_real_under_within hx hC hC0 + obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 + set Ert := Real.exp (reducedArg x) with hErt + have hs63 : (63 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs63n : 63 ≤ s := by exact_mod_cast hs63 + have hpow : (2 ^ 63 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs63n + -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = WAD·2^126·Ert ≤ WAD·(r0 + 8) + -- and 8·WAD + MARGIN < (24/25)·2^63 ≤ (24/25)·2^s + have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 := by + have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = + (WAD : Real) * (2 ^ 126 : Real) * Ert := hfold + have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 8 := hunder + have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num + have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ + (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 8) := + mul_le_mul_of_nonneg_left hr0R (by norm_num) + have hbudget : (10 ^ 18 : Real) * 8 + 792161285993433738 < (24 / 25) * (2 ^ 63 : Real) := by + norm_num + rw [hwad] at hkey + have hEs : (10 ^ 18 : Real) * 2 ^ 126 * Ert ≤ + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) + (10 ^ 18 : Real) * 8 := by + nlinarith [h8wad] + -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; E·2^s = 10^18·2^126·Ert ; (24/25)·2^s ≥ (24/25)·2^63 + have h2425 : (24 / 25 : Real) * (2 ^ 63 : Real) ≤ (24 / 25) * (2 ^ s : Real) := + mul_le_mul_of_nonneg_left hpow (by norm_num) + nlinarith [hkey, hEs, hbudget, hpow, h2425] + rw [hAeq, lt_div_iff₀ hps]; linarith [hbound] + +/-! ## The `lnWadToRay` envelope on the round-trip band + +`Wlo = ⌈10¹⁸/√2⌉` and `Whi = ⌊10¹⁸·√2⌋` are the integer endpoints of the half-open band +`w/10¹⁸ ∈ [1/√2, √2)`; over it `w/10¹⁸ ∈ (1/2, 2)`. -/ + +/-- The lower endpoint `⌈10¹⁸/√2⌉`. -/ +def Wlo : Nat := 707106781186547525 + +/-- The upper endpoint `⌊10¹⁸·√2⌋`. -/ +def Whi : Nat := 1414213562373095048 + +/-- `log 2 < 1` (from `2 < e`). -/ +theorem log_two_lt_one : Real.log 2 < 1 := by + have h2e : (2 : Real) < Real.exp 1 := lt_trans (by norm_num) Real.exp_one_gt_d9 + have := Real.log_lt_log (by norm_num : (0:Real) < 2) h2e + rwa [Real.log_exp] at this + +/-- The `Real`-valued ratio facts on the round-trip band: `1/2 < w/10¹⁸ < 2`. -/ +theorem band_ratio_bounds {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : + (1 : Real) / 2 < (w : Real) / (10 ^ 18 : Real) ∧ + (w : Real) / (10 ^ 18 : Real) < 2 := by + have hwlo : (Wlo : Real) ≤ (w : Real) := by exact_mod_cast hlo + have hwhi : (w : Real) ≤ (Whi : Real) := by exact_mod_cast hhi + have hWlo : (Wlo : Real) = 707106781186547525 := by unfold Wlo; norm_num + have hWhi : (Whi : Real) = 1414213562373095048 := by unfold Whi; norm_num + rw [hWlo] at hwlo; rw [hWhi] at hwhi + constructor + · rw [lt_div_iff₀ (by positivity)]; linarith [hwlo] + · rw [div_lt_iff₀ (by positivity)]; linarith [hwhi] + +/-- **The `lnWadToRay` envelope.** For `w` on the round-trip band and the signed ray output `r` of +`lnWadToRay(w)` bracketed by `X = 10²⁷·ln(w/10¹⁸)` (`r ≤ X < r + 2`), the exp target +`E = expRayToWadTarget r` satisfies `w − 1 < E ≤ w`, and `r` lies in the exp region +`(Cmask, C0thresh)`. -/ +theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) + (hr_le : (r : Real) ≤ LnRealSpec.lnWadToRayTarget w) + (hr_lt : LnRealSpec.lnWadToRayTarget w < ((r + 2 : Int) : Real)) : + ((w : Real) - 1 / 25 < expRayToWadTarget r ∧ expRayToWadTarget r ≤ (w : Real)) ∧ + int256 Cmask < r ∧ r < int256 C0thresh := by + have hwpos : (0 : Real) < (w : Real) := by + have : (0 : Nat) < w := lt_of_lt_of_le (by unfold Wlo; norm_num) hlo + exact_mod_cast this + obtain ⟨hratlo, hrathi⟩ := band_ratio_bounds hlo hhi + -- abbreviations + set L : Real := Real.log ((w : Real) / (10 ^ 18 : Real)) with hLdef + have hXeq : LnRealSpec.lnWadToRayTarget w = (10 ^ 27 : Real) * L := by + unfold LnRealSpec.lnWadToRayTarget LnRealSpec.wadRatio LnRealSpec.RAY LnRealSpec.WAD + rw [hLdef]; push_cast; ring + rw [hXeq] at hr_le hr_lt + have hwr_pos : (0 : Real) < (w : Real) / (10 ^ 18 : Real) := by positivity + have hexpL : Real.exp L = (w : Real) / (10 ^ 18 : Real) := by + rw [hLdef, Real.exp_log hwr_pos] + -- E = 10^18 · exp(r/10^27) + have hEeq : expRayToWadTarget r = (10 ^ 18 : Real) * Real.exp ((r : Real) / (10 ^ 27 : Real)) := by + unfold expRayToWadTarget WAD RAY; push_cast; ring + -- never-over: r/10^27 ≤ L ⇒ exp ≤ w/10^18 ⇒ E ≤ w + have hrle' : (r : Real) / (10 ^ 27 : Real) ≤ L := by + rw [div_le_iff₀ (by positivity)]; nlinarith [hr_le] + have hEle : expRayToWadTarget r ≤ (w : Real) := by + rw [hEeq] + have hexp_le : Real.exp ((r : Real) / (10 ^ 27 : Real)) ≤ Real.exp L := Real.exp_le_exp.mpr hrle' + rw [hexpL] at hexp_le + have : (10 ^ 18 : Real) * Real.exp ((r : Real) / (10 ^ 27 : Real)) ≤ + (10 ^ 18 : Real) * ((w : Real) / (10 ^ 18 : Real)) := + mul_le_mul_of_nonneg_left hexp_le (by norm_num) + calc (10 ^ 18 : Real) * Real.exp ((r : Real) / (10 ^ 27 : Real)) ≤ + (10 ^ 18 : Real) * ((w : Real) / (10 ^ 18 : Real)) := this + _ = (w : Real) := by field_simp + -- deficit: r/10^27 > L − 2/10^27 ⇒ exp > (w/10^18)·exp(−2/10^27) ≥ (w/10^18)·(1 − 2/10^27) + have hrgt' : L - 2 / (10 ^ 27 : Real) < (r : Real) / (10 ^ 27 : Real) := by + rw [lt_div_iff₀ (by positivity)]; push_cast at hr_lt; nlinarith [hr_lt] + have hElt : (w : Real) - 1 / 25 < expRayToWadTarget r := by + rw [hEeq] + -- exp(r/10^27) > exp(L − 2/10^27) = exp(L)·exp(−2/10^27) + have hexp_gt : Real.exp (L - 2 / (10 ^ 27 : Real)) < Real.exp ((r : Real) / (10 ^ 27 : Real)) := + Real.exp_lt_exp.mpr hrgt' + have hsplit : Real.exp (L - 2 / (10 ^ 27 : Real)) = + ((w : Real) / (10 ^ 18 : Real)) * Real.exp (-(2 / (10 ^ 27 : Real))) := by + rw [show L - 2 / (10 ^ 27 : Real) = L + (-(2 / (10 ^ 27 : Real))) from by ring, + Real.exp_add, hexpL] + -- exp(−u) ≥ 1 − u + have hone : (1 : Real) + (-(2 / (10 ^ 27 : Real))) ≤ Real.exp (-(2 / (10 ^ 27 : Real))) := by + have := Real.add_one_le_exp (-(2 / (10 ^ 27 : Real))); linarith [this] + have hwr_nn : (0 : Real) ≤ (w : Real) / (10 ^ 18 : Real) := le_of_lt hwr_pos + -- (w/10^18)·exp(−u) ≥ (w/10^18)·(1 − u) + have hstep : ((w : Real) / (10 ^ 18 : Real)) * (1 - 2 / (10 ^ 27 : Real)) ≤ + ((w : Real) / (10 ^ 18 : Real)) * Real.exp (-(2 / (10 ^ 27 : Real))) := + mul_le_mul_of_nonneg_left (by linarith [hone]) hwr_nn + -- 10^18 · (w/10^18)·(1 − 2/10^27) = w − 2w/10^27 > w − 1/25 since 2w·25 < 10^27 + have h2w : 25 * (2 * (w : Real)) < (10 ^ 27 : Real) := by + have : (w : Real) ≤ (Whi : Real) := by exact_mod_cast hhi + have hWhi : (Whi : Real) = 1414213562373095048 := by unfold Whi; norm_num + rw [hWhi] at this; linarith [this] + have hexp_r_gt : ((w : Real) / (10 ^ 18 : Real)) * (1 - 2 / (10 ^ 27 : Real)) < + Real.exp ((r : Real) / (10 ^ 27 : Real)) := by + rw [hsplit] at hexp_gt; linarith [hstep, hexp_gt] + have hmul : (10 ^ 18 : Real) * (((w : Real) / (10 ^ 18 : Real)) * (1 - 2 / (10 ^ 27 : Real))) < + (10 ^ 18 : Real) * Real.exp ((r : Real) / (10 ^ 27 : Real)) := + mul_lt_mul_of_pos_left hexp_r_gt (by norm_num) + have hlhs : (10 ^ 18 : Real) * (((w : Real) / (10 ^ 18 : Real)) * (1 - 2 / (10 ^ 27 : Real))) = + (w : Real) - 2 * (w : Real) / (10 ^ 27 : Real) := by field_simp; ring + rw [hlhs] at hmul + -- w − 2w/10^27 > w − 1/25 since 2w/10^27 < 1/25 + have h2wd : 2 * (w : Real) / (10 ^ 27 : Real) < 1 / 25 := by + rw [div_lt_iff₀ (by positivity)]; linarith [h2w] + linarith [hmul, h2wd] + -- region membership of r + have hCmask : int256 Cmask = -41446531673892822312323846185 := int256_Cmask + have hC0 : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh_floc + -- L > log(1/2) = −log 2 > −1 ; X = 10^27·L > −10^27 ; r ≥ X − 2 > Cmask + have hLgt : -(1 : Real) < L := by + have h12 : Real.log ((1:Real)/2) < L := by + rw [hLdef]; exact Real.log_lt_log (by norm_num) hratlo + have hlog12 : Real.log ((1:Real)/2) = -(Real.log 2) := by + rw [show (1:Real)/2 = (2:Real)⁻¹ from by norm_num, Real.log_inv] + rw [hlog12] at h12 + linarith [h12, log_two_lt_one] + have hLlt : L < 1 := by + have h2 : L < Real.log 2 := by rw [hLdef]; exact Real.log_lt_log hwr_pos hrathi + linarith [h2, log_two_lt_one] + refine ⟨⟨hElt, hEle⟩, ?_, ?_⟩ + · -- Cmask < r : r > 10^27·L − 2 > −10^27 − 2 > Cmask + rw [hCmask] + have hXlo : -(10 ^ 27 : Real) < (10 ^ 27 : Real) * L := by nlinarith [hLgt] + have hr_gt_X2 : (10 ^ 27 : Real) * L - 2 < (r : Real) := by push_cast at hr_lt; linarith [hr_lt] + have : (-41446531673892822312323846185 : Real) < (r : Real) := by + have : (-41446531673892822312323846185 : Real) < -(10 ^ 27 : Real) - 2 := by norm_num + linarith [this, hXlo, hr_gt_X2] + exact_mod_cast this + · -- r < C0thresh : r ≤ 10^27·L < 10^27 < C0thresh + rw [hC0] + have hXhi : (10 ^ 27 : Real) * L < (10 ^ 27 : Real) := by nlinarith [hLlt] + have : (r : Real) < (44014845965556527147994239713 : Real) := by + have hc : (10 ^ 27 : Real) < (44014845965556527147994239713 : Real) := by norm_num + linarith [hr_le, hXhi, hc] + exact_mod_cast this + +/-! ## Floor pinning: the body returns exactly `w − 1` + +With strict never-over (`accumReal x < E ≤ w`) and the region-uniform deficit +(`accumReal x > E − 24/25 > w − 1`), the accumulator lies in `(w − 1, w)`, so its floor — the body +word `r1Tree x` — is exactly `w − 1`. -/ + +/-- **Floor pin.** On the region, if `w − 1/25 < E ≤ w` then the floored body word is exactly +`w − 1`. The strict never-over puts `accumReal x < E ≤ w`, and the region-uniform deficit puts +`accumReal x > E − 24/25 > w − 1`, so `accumReal x ∈ (w − 1, w)` and its floor is `w − 1`. -/ +theorem r1Tree_eq_w_sub_one {x w : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) + (hC0 : int256 x < int256 C0thresh) + (hElt : (w : Real) - 1 / 25 < expRayToWadTarget (int256 x)) + (hEle : expRayToWadTarget (int256 x) ≤ (w : Real)) : + int256 (r1Tree x) = (w : Int) - 1 := by + set R1 : Int := int256 (r1Tree x) with hR1def + obtain ⟨hfl, hfl1⟩ := r1Tree_floor_accum hx hC hC0 + have hover := accumReal_over_strict x hx hC hC0 + have hdef := accumReal_deficit_lt_one x hx hC hC0 + -- upper: R1 ≤ accum < E ≤ w ⇒ R1 < w ⇒ R1 ≤ w − 1 + have hRltw : (R1 : Real) < (w : Real) := + calc (R1 : Real) ≤ accumReal x := hfl + _ < expRayToWadTarget (int256 x) := hover + _ ≤ (w : Real) := hEle + have hRle : R1 ≤ (w : Int) - 1 := by + have : R1 < (w : Int) := by exact_mod_cast hRltw + omega + -- lower: accum > E − 24/25 > (w − 1/25) − 24/25 = w − 1 ; accum < R1 + 1 ⇒ R1 + 1 > w − 1 + have hacc_lo : (w : Real) - 1 < accumReal x := by linarith [hdef, hElt] + have hR1_gt : (w : Real) - 2 < (R1 : Real) := by linarith [hacc_lo, hfl1] + have hRge : (w : Int) - 1 ≤ R1 := by + have : (w : Int) - 1 < R1 + 1 := by + exact_mod_cast (by linarith [hR1_gt] : (w : Real) - 1 < (R1 : Real) + 1) + omega + omega + +/-! ## The round trip + +`run_exp_ray_to_wad_evm (run_ln_wad_to_ray_evm w) = w − 1` for `w` on the band, `= w` at the scale +point. The composition feeds the verified `lnWadToRay` Nat output straight into the exp runtime. + +The runtime bodies (`lnWadToRayBody`, `expTree`, `r1Tree`) are deep arithmetic trees; their +definitions are kept opaque here so that floor/cast reasoning over the composed result never forces +the kernel to whnf-reduce them (which overflows the recursion stack). -/ + +attribute [local irreducible] LnYul.lnWadToRayBody expTree r1Tree r0Tree kTree + +/-- The Nat ln output and its facts: for `w` on the band the `lnWadToRay` runtime succeeds with a +256-bit word `result` whose signed value `int256 result` is bracketed against `10²⁷·ln(w/10¹⁸)`. -/ +theorem lnWadToRay_band_run {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : + ∃ result : Nat, LnYul.run_ln_wad_to_ray_evm w = .ok result ∧ result < 2 ^ 256 ∧ + (int256 result : Real) ≤ LnRealSpec.lnWadToRayTarget w ∧ + LnRealSpec.lnWadToRayTarget w < ((int256 result + 2 : Int) : Real) := by + have hwlt : w < 2 ^ 256 := by + have : w ≤ Whi := hhi + have hWhi : Whi < 2 ^ 256 := by unfold Whi; norm_num + omega + have hux : u256 w = w := u256_of_lt hwlt + have hwpos_nat : 0 < w := lt_of_lt_of_le (by unfold Wlo; norm_num) hlo + have hpos : 1 ≤ u256 w := by rw [hux]; omega + have hpos2 : u256 w < 2 ^ 255 := by + rw [hux]; have hWhi : Whi < 2 ^ 255 := by unfold Whi; norm_num + omega + -- the runtime body + have hrun := LnYul.run_ln_wad_to_ray_evm_eq_body w hpos hpos2 + rw [hux] at hrun + set result : Nat := LnYul.lnWadToRayBody w with hresdef + have hreslt : result < 2 ^ 256 := LnYul.lnWadToRayBody_lt hwlt + -- the spec bracket, via the public correctness theorem + have hsigned : LnYul.signedPositiveInput w := by + unfold LnYul.signedPositiveInput; rw [hux, int256_of_lt (by omega : w < 2 ^ 255)] + exact_mod_cast hwpos_nat + obtain ⟨r, hrunsigned, hspec⟩ := LnYul.lnWadToRayRuntimeCorrect w hwlt hsigned + -- identify r with int256 result + rw [LnYul.runLnWadToRaySigned_ok_iff] at hrunsigned + obtain ⟨result', hrun', hsr⟩ := hrunsigned + rw [hrun] at hrun' + have hres' : result' = result := Except.ok.inj hrun'.symm + subst hres' + have hreq : r = int256 result := by + rw [← hsr]; show int256 (u256 result) = int256 result + rw [u256_of_lt hreslt] + subst hreq + obtain ⟨hle, hlt⟩ := hspec + exact ⟨result, hrun, hreslt, hle, hlt⟩ + +/-- **The `lnWadToRay` round trip.** For every `w` whose ratio lies in the +central band `w/10¹⁸ ∈ [1/√2, √2)` — equivalently `Wlo ≤ w ≤ Whi` — the composition +`expRayToWad ∘ lnWadToRay` recovers `w − 1`, and recovers `w` exactly at the scale point +`w = 10¹⁸`. Stated at the runtime level: `lnWadToRay`'s 256-bit output `x` fed straight into the exp +runtime returns the documented value. -/ +theorem run_exp_ray_to_wad_evm_lnWadToRay_roundTrip {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : + ∃ x r : Nat, LnYul.run_ln_wad_to_ray_evm w = .ok x ∧ run_exp_ray_to_wad_evm x = .ok r ∧ + (w = 10 ^ 18 → (r : Int) = 10 ^ 18) ∧ (w ≠ 10 ^ 18 → (r : Int) = (w : Int) - 1) := by + obtain ⟨x, hlnrun, hxlt, hle, hlt⟩ := lnWadToRay_band_run hlo hhi + -- the exp target bracket + region membership for x's signed value + obtain ⟨⟨hElt, hEle⟩, hCmask, hC0⟩ := expTarget_band (int256 x) hlo hhi hle hlt + refine ⟨x, expTree x, hlnrun, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hxlt hC0), + ?_, ?_⟩ + · -- scale point: w = 10^18 ⇒ x = 0 ⇒ expTree 0 = 10^18 + intro hw + subst hw + -- lnWadToRay(10^18) = 0 + have hx0 : x = 0 := by + have := LnYul.run_ln_wad_to_ray_evm_zero_at_wad + rw [this] at hlnrun; exact (Except.ok.inj hlnrun).symm + subst hx0 + have he : expTree 0 = 1000000000000000000 := by + have := run_exp_ray_to_wad_evm_zero + rw [run_exp_ray_to_wad_evm_eq_expTree 0 (domain_of_below_C0 hxlt hC0)] at this + exact Except.ok.inj this + rw [he]; norm_num + · -- non scale point: x ≠ 0, region ⇒ body word = w − 1 + intro hw + have hx_ne : x ≠ 0 := by + intro hx0 + -- x = 0 ⇒ int256 x = 0 ⇒ E = 10^18 ; but E ≤ w and w − 1/25 < E so w ∈ (E, E + 1/25]; w = 10^18 + apply hw + have hE0 : expRayToWadTarget (int256 x) = (10 ^ 18 : Real) := by + rw [hx0]; show expRayToWadTarget (int256 (0 : Nat)) = (10 ^ 18 : Real) + have : int256 (0 : Nat) = (0 : Int) := rfl + rw [this, expRayToWadTarget_zero]; unfold WAD; norm_num + -- 10^18 ≤ w and w − 1/25 < 10^18 ⇒ w = 10^18 (integers) + rw [hE0] at hElt hEle + have hwge : (10 ^ 18 : Real) ≤ (w : Real) := hEle + have hwlt : (w : Real) < (10 ^ 18 : Real) + 1 / 25 := by linarith [hElt] + have h1 : (10 : Int) ^ 18 ≤ (w : Int) := by exact_mod_cast hwge + have h2 : (w : Real) < (10 ^ 18 : Real) + 1 := by linarith [hwlt] + have h3 : (w : Int) < (10 : Int) ^ 18 + 1 := by exact_mod_cast h2 + omega + have hC : int256 Cmask < int256 x := hCmask + -- the floored body word equals w − 1 + have hbody : int256 (r1Tree x) = (w : Int) - 1 := r1Tree_eq_w_sub_one hxlt hC hC0 hElt hEle + -- expTree x = r1Tree x on the region (x ≠ 0) + have hexpeq : int256 (expTree x) = int256 (r1Tree x) := + int256_expTree_region_ne_zero hxlt hC hC0 hx_ne + -- the body word is nonnegative (= w − 1 ≥ 0), so int256 (expTree x) = (expTree x : Int) + have hge1 : 1 ≤ w := le_trans (by unfold Wlo; norm_num) hlo + have hbody_pos : (0 : Int) ≤ (w : Int) - 1 := by + have : (1 : Int) ≤ (w : Int) := by exact_mod_cast hge1 + omega + have hexp_nn : 0 ≤ int256 (expTree x) := by rw [hexpeq, hbody]; exact hbody_pos + have hexp_word : int256 (expTree x) = (expTree x : Int) := + (int256_eq_of_nonneg (expTree_lt x) hexp_nn).1 + rw [← hexp_word, hexpeq, hbody] + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_lnWadToRay_roundTrip' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_lnWadToRay_roundTrip + +end + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index d18f89944..6a855541a 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -7,6 +7,7 @@ import ExpProof.Floor.PublicUncond import ExpProof.Floor.R0BoundHolds import ExpProof.Floor.Fold import ExpProof.Floor.R0Bound +import ExpProof.Floor.RoundTrip /-! # `expRayToWad` — proven properties of the compiled runtime (signpost) @@ -19,12 +20,13 @@ stray `sorry` (or any new axiom) breaks the build. ## Documented properties (about the runtime) -| Property | Theorem | -|-------------------------------------------------|----------------------------------| -| Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1`| `run_exp_ray_to_wad_evm_revert` | -| Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | -| Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | -| Monotone in the input (modulo the region core) | `run_exp_ray_to_wad_evm_mono` | +| Property | Theorem | +|-------------------------------------------------|-----------------------------------------------| +| Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1`| `run_exp_ray_to_wad_evm_revert` | +| Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | +| Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | +| Monotone in the input (modulo the region core) | `run_exp_ray_to_wad_evm_mono` | +| `lnWadToRay` round trip recovers `w − 1` | `run_exp_ray_to_wad_evm_lnWadToRay_roundTrip` | The monotonicity theorem `run_exp_ray_to_wad_evm_mono` is proved over the whole supported domain; it takes the analytic facts of the meaningful region (`RegionMonotonicityFacts`: `r1Tree` in range, @@ -242,6 +244,24 @@ example (x : Nat) (hx : x < 2 ^ 256) #guard_msgs in #print axioms run_exp_ray_to_wad_evm_underByAtMostOne_uncond +/-! ## The `lnWadToRay` round trip + +For `w` with `w/10¹⁸ ∈ [1/√2, √2)`, the compiled composition +`expRayToWad(lnWadToRay(w))` returns `w − 1`, and returns `w` at the scale point +`w = 10¹⁸`. The proof composes the verified `lnWadToRay` runtime (`LnProof`) with the exp runtime. -/ + +/-- The `lnWadToRay` round trip, with no analytic hypothesis. For `w` on the central band +(`Wlo ≤ w ≤ Whi`, i.e. `w/10¹⁸ ∈ [1/√2, √2)`), the runtime composition returns `w − 1`, and `w` at +the scale point. -/ +example {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : + ∃ x r : Nat, LnYul.run_ln_wad_to_ray_evm w = .ok x ∧ run_exp_ray_to_wad_evm x = .ok r ∧ + (w = 10 ^ 18 → (r : Int) = 10 ^ 18) ∧ (w ≠ 10 ^ 18 → (r : Int) = (w : Int) - 1) := + run_exp_ray_to_wad_evm_lnWadToRay_roundTrip hlo hhi + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_lnWadToRay_roundTrip' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_lnWadToRay_roundTrip + /-! ## Central-octave exact floor from central exactness The never-over and floor facts of the central-octave exact-floor bracket are hypothesis-free. The From 5481ffa9812ef2fabfa91f5cbecad90cf728b25b Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 17:05:06 +0200 Subject: [PATCH 083/149] Switch the exp cert pipeline to the v-form and restate the round trip Replace the t-form certificate pathway (Floor/Caps.lean, Floor/CertDefs.lean, GenExpLit.lean and its exp-formal.yml generation step) with the v-form (Floor/CapsV, Floor/CertDefsV, GenExpVLit), the form the runtime truncation bridge lands on. Restructure Mono around it: extract the runtime constants to Mono/Consts.lean, add Mono/WordFacts.lean, and rework Mono/Tree.lean's layered definitions. Restate the public round-trip documentation on the canonical central wad band 707106781186547525 <= w <= 1414213562373095048: expRayToWad(lnWadToRay(w)) == w - 1, except at the scale point w = 10^18 where it returns w. Drop the @notice claim that the result is exactly floor(E) across the central octave -- the guarantee is the round trip, not central-octave exactness -- and remove testFuzzExpRayToWadCentralExact and the _CENTRAL_X_* constants that encoded that claim. Install mpmath in the unit-test CI job for the remaining FFI oracle tests. Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .github/workflows/exp-formal.yml | 15 +- .github/workflows/test.yml | 3 + formal/exp/ExpProof/ExpProof/Floor/Caps.lean | 229 ------------------ .../exp/ExpProof/ExpProof/Floor/CertDefs.lean | 124 ---------- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 13 +- .../exp/ExpProof/ExpProof/Floor/Public.lean | 25 -- .../ExpProof/ExpProof/Floor/PublicUncond.lean | 42 ---- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 10 +- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 5 +- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 5 +- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 19 +- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 23 +- .../exp/ExpProof/ExpProof/Floor/TBound.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 55 +++++ .../exp/ExpProof/ExpProof/Mono/RunBridge.lean | 5 + formal/exp/ExpProof/ExpProof/Mono/Top.lean | 4 +- formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 149 +++--------- .../exp/ExpProof/ExpProof/Mono/WordFacts.lean | 61 +++++ .../exp/ExpProof/ExpProof/Seam/RealExp.lean | 24 -- formal/exp/ExpProof/ExpProof/Spec/Cut.lean | 8 - .../exp/ExpProof/ExpProof/Spec/RealExp.lean | 25 +- formal/exp/ExpProof/ExpProof/Theorems.lean | 52 +--- formal/exp/ExpProof/GenExpLit.lean | 149 ------------ src/vendor/Exp.sol | 39 ++- test/0.8.34/Exp.t.sol | 18 +- 25 files changed, 234 insertions(+), 870 deletions(-) delete mode 100644 formal/exp/ExpProof/ExpProof/Floor/Caps.lean delete mode 100644 formal/exp/ExpProof/ExpProof/Floor/CertDefs.lean create mode 100644 formal/exp/ExpProof/ExpProof/Mono/Consts.lean create mode 100644 formal/exp/ExpProof/ExpProof/Mono/WordFacts.lean delete mode 100644 formal/exp/ExpProof/GenExpLit.lean diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index 1594ba6e6..e42bbb5f2 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -72,9 +72,7 @@ jobs: - name: Fetch Mathlib cache working-directory: formal/yul run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. + # ProofWidgets release directories must exist for `lake exe cache get`. lake build proofwidgets:release mkdir -p \ .lake/packages/proofwidgets/.lake/build/lib \ @@ -104,9 +102,7 @@ jobs: - name: Fetch ln proof dependency cache working-directory: formal/ln/LnProof run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. + # ProofWidgets release directories must exist for `lake exe cache get`. lake build proofwidgets:release mkdir -p \ .lake/packages/proofwidgets/.lake/build/lib \ @@ -131,9 +127,7 @@ jobs: - name: Fetch proof dependency cache working-directory: formal/exp/ExpProof run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. + # ProofWidgets release directories must exist for `lake exe cache get`. lake build proofwidgets:release mkdir -p \ .lake/packages/proofwidgets/.lake/build/lib \ @@ -143,8 +137,7 @@ jobs: - name: Generate Lean certificate artifacts working-directory: formal/exp/ExpProof run: | - lake build ExpProof.Floor.CertDefs ExpProof.Floor.CertDefsV Common.Foundation.KroneckerShift - lake env lean GenExpLit.lean + lake build ExpProof.Floor.CertDefsV Common.Foundation.KroneckerShift lake env lean GenExpVLit.lean - name: Build Exp proof package diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2eb6471c3..83b54f524 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,6 +29,9 @@ jobs: - name: Install dependencies run: git submodule update --recursive --init + - name: Install Python test dependencies + run: python3 -m pip install mpmath==1.3.0 + - name: Build Safe Guard run: forge build src/deployer/SafeGuard.sol env: diff --git a/formal/exp/ExpProof/ExpProof/Floor/Caps.lean b/formal/exp/ExpProof/ExpProof/Floor/Caps.lean deleted file mode 100644 index 630511016..000000000 --- a/formal/exp/ExpProof/ExpProof/Floor/Caps.lean +++ /dev/null @@ -1,229 +0,0 @@ -import Mathlib.Tactic.NormNum -import Mathlib.Tactic.Ring -import Mathlib.Tactic.Positivity -import Mathlib.Algebra.Order.Floor.Defs -import ExpProof.Cert.ExpUp -import ExpProof.Cert.ExpLo -import ExpProof.Cert.ExpNum -import ExpProof.Cert.ExpDenM1 -import ExpProof.Spec.Cut - -/-! -# From cell certificates to the reduced-argument Taylor caps - -The cell covers (`Cert/ExpUp`, `Cert/ExpLo`, `Cert/ExpNum`, `Cert/ExpDenM1`) certify the four -certificate polynomials nonnegative over `t ∈ [0, H128]`. This module converts that nonnegativity -into the two bare-argument Taylor caps the floor layer folds with `2^k`: - -* `cutExpTaylorLe_holds` — `CutExpTaylorLe t Qexp (yUB t) (wUB t)` (never-over `exp(t) ≤ ê·(1+2⁻¹²⁰)`); -* `cutRatioLeExpTaylor_holds` — `CutRatioLeExpTaylor (yLB t) (wLB t) t Qexp` - (not-two-below `ê·(1−2⁻¹²⁶) ≤ exp(t)`), - -for every reduced argument `t ∈ [0, H128]` (the nonnegative half of the core domain; the negative -branch reuses these via the reciprocal branch). The targets are the implementation's exact rational -`ê(t) = NUM(t)/DEN(t)` nudged by the dyadic margin, with `Qexp = 2^128` the reduced-argument -denominator. - -The bridge is the depth-`K = 27` `Common.Exp.capUB_of_partial`/`capLB` shape, exactly mirroring the -`ln` proof's `capUB22_of_int`/`capLB22_of_int` at the deeper Taylor depth `exp`'s wider argument -window requires. --/ - -namespace ExpCert - -open Common.Poly Common.Exp ExpFloorCert - -set_option maxRecDepth 100000 - -/-! ## The two Int→Nat cap bridges at Taylor depth `K = 27` -/ - -/-- One evaluated partial sum (depth 27) plus the geometric tail gives a full upper cap. -/ -theorem capUB27_of_int {tn td y w : Nat} (htd : 0 < td) (hH : 2 * tn ≤ 29 * td) - (h : (expNumI 27 (tn : Int) (td : Int) * (28 * (td : Int)) + 2 * (tn : Int) ^ 28) * - (w : Int) ≤ (y : Int) * (304888344611713860501504000000 * (td : Int) ^ 28)) : - capUB tn td y w := by - refine capUB_of_partial htd (by omega : 2 * tn ≤ (27 + 2) * td) ?_ - show (expNum 27 tn td * ((27 + 1) * td) + 2 * tn ^ (27 + 1)) * w ≤ y * (fact 28 * td ^ 28) - rw [show fact 28 = 304888344611713860501504000000 from by decide, - show (27 + 1) = 28 from rfl] - refine Int.ofNat_le.mp ?_ - rw [expNumI_eq_expNum] at h - simp only [Int.natCast_mul, Int.natCast_add, Int.natCast_pow] - exact h - -/-- The single depth-27 partial sum reaches the lower target. -/ -theorem capLB27_of_int {tn td y w : Nat} - (h : (y : Int) * (10888869450418352160768000000 * (td : Int) ^ 27) ≤ - expNumI 27 (tn : Int) (td : Int) * (w : Int)) : - capLB tn td y w := by - refine ⟨27, ?_⟩ - show y * (fact 27 * td ^ 27) ≤ expNum 27 tn td * w - rw [show fact 27 = 10888869450418352160768000000 from by decide] - refine Int.ofNat_le.mp ?_ - rw [expNumI_eq_expNum] at h - simp only [Int.natCast_mul, Int.natCast_pow] - exact h - -/-! ## Evaluation shapes of the certificate polynomials - -`expN27` evaluates to the depth-27 partial-sum numerator; the cert polynomials expand to the exact -`capUB_of_partial`/`capLB` residues in the rational targets. -/ - -theorem evalExpN27 (t : Int) : evalPoly expN27 t = expNumI 27 t (Qexp : Int) := by - unfold expN27 - rw [evalPoly_expPolyNum] - congr 1 <;> simp [evalPoly] - -theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 120 + 1) * evalPoly numExp t := by - unfold yUB; rw [evalPoly_polyScale] - -theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 120 * evalPoly denExp t := by - unfold wUB; rw [evalPoly_polyScale] - -theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 126 - 1) * evalPoly numExp t := by - unfold yLB; rw [evalPoly_polyScale] - -theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 126 * evalPoly denExp t := by - unfold wLB; rw [evalPoly_polyScale] - -theorem evalTailUp (t : Int) : - evalPoly tailUp t = 28 * (Qexp : Int) * expNumI 27 t (Qexp : Int) + 2 * t ^ 28 := by - unfold tailUp - rw [evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyScale, evalPoly_polyPow, evalExpN27] - congr 1 - show _ = 2 * t ^ 28 - rw [show evalPoly ([0, 1] : List Int) t = t from by simp [evalPoly]] - -/-- The never-over cert evaluates to the `capUB27_of_int` residue. -/ -theorem evalCertExpUp (t : Int) : - evalPoly certExpUp t = - fact28Q28 * evalPoly yUB t - - (28 * (Qexp : Int) * expNumI 27 t (Qexp : Int) + 2 * t ^ 28) * evalPoly wUB t := by - unfold certExpUp - rw [evalPoly_polySub, evalPoly_polyScale, evalPoly_polyMul, evalTailUp] - -/-- The not-two-below cert evaluates to the `capLB27_of_int` residue. -/ -theorem evalCertExpLo (t : Int) : - evalPoly certExpLo t = - expNumI 27 t (Qexp : Int) * evalPoly wLB t - fact27Q27 * evalPoly yLB t := by - unfold certExpLo - rw [evalPoly_polySub, evalPoly_polyMul, evalPoly_polyScale, evalExpN27] - -/-! ## Positivity of the rational over the domain -/ - -/-- `1 ≤ DEN(t)` over the domain (the rational denominator is a positive `Nat`). -/ -theorem denExp_ge_one {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : - 1 ≤ evalPoly denExp t := by - have h := denM1_nonneg h1 h2 - unfold certDenM1 at h - rw [evalPoly_polyAdd] at h - rw [show evalPoly ([-1] : List Int) t = -1 from by simp [evalPoly]] at h - omega - -/-- `0 ≤ NUM(t)` over the domain. -/ -theorem numExp_nonneg' {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : - 0 ≤ evalPoly numExp t := numExp_nonneg h1 h2 - -/-! ## The bare-argument Taylor caps - -`Qexp = 2^128` is positive, `t.toNat`/the rational targets cast back to themselves on the domain, -and the certificate residues are exactly the `capUB27_of_int`/`capLB27_of_int` hypotheses. -/ - -theorem Qexp_eq : (Qexp : Int) = 2 ^ 128 := by unfold Qexp; norm_num - -theorem Qexp_pos : 0 < Qexp := by unfold Qexp; norm_num - -/-- **Never-over cap** at the rational `yUB/wUB = ê·(1 + 2⁻¹²⁰)`: for every reduced argument -`t ∈ [0, H128]`, `exp(t/Qexp) ≤ yUB(t)/wUB(t)`. -/ -theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : - capUB t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := by - have hnum : 0 ≤ evalPoly numExp t := numExp_nonneg h1 h2 - have hden : 1 ≤ evalPoly denExp t := denExp_ge_one h1 h2 - have hden0 : 0 ≤ evalPoly denExp t := by omega - have hc120 : (0 : Int) ≤ 2 ^ 120 + 1 := by norm_num - have hp120 : (0 : Int) ≤ 2 ^ 120 := by norm_num - have hyub : 0 ≤ evalPoly yUB t := by - rw [evalYUB]; exact Int.mul_nonneg hc120 hnum - have hwub : 0 ≤ evalPoly wUB t := by - rw [evalWUB]; exact Int.mul_nonneg hp120 hden0 - have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 - have hyn : ((evalPoly yUB t).toNat : Int) = evalPoly yUB t := Int.toNat_of_nonneg hyub - have hwn : ((evalPoly wUB t).toNat : Int) = evalPoly wUB t := Int.toNat_of_nonneg hwub - refine capUB27_of_int Qexp_pos ?_ ?_ - · -- `2·t.toNat ≤ 29·Qexp`: `t.toNat ≤ H128 < Qexp = 2^128` - have htle : t.toNat ≤ H128 := by - have : (t.toNat : Int) ≤ (H128 : Int) := by rw [htn]; exact h2 - exact_mod_cast this - have hHQ : 2 * H128 < 29 * Qexp := by unfold H128 Qexp; norm_num - omega - · -- the cert residue is the `capUB27_of_int` hypothesis - rw [htn, hyn, hwn, Qexp_eq] - have h := expUp_nonneg h1 h2 - rw [evalCertExpUp] at h - unfold fact28Q28 at h - rw [Qexp_eq] at h - -- `0 ≤ A·yUB − tail·wUB ⟹ tail·wUB ≤ A·yUB` - have key : (28 * (2 : Int) ^ 128 * expNumI 27 t (2 ^ 128) + 2 * t ^ 28) * evalPoly wUB t ≤ - 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := by omega - -- match the `capUB27_of_int` shape `... ≤ y·(C·td^28)` - calc (expNumI 27 t (2 ^ 128) * (28 * (2 : Int) ^ 128) + 2 * t ^ 28) * evalPoly wUB t - = (28 * (2 : Int) ^ 128 * expNumI 27 t (2 ^ 128) + 2 * t ^ 28) * evalPoly wUB t := by ring - _ ≤ 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := key - _ = evalPoly yUB t * (304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28) := by ring - -/-- **Not-two-below cap** at the rational `yLB/wLB = ê·(1 − 2⁻¹²⁶)`: for every reduced argument -`t ∈ [0, H128]`, `yLB(t)/wLB(t) ≤ exp(t/Qexp)`. -/ -theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : - capLB t.toNat Qexp (evalPoly yLB t).toNat (evalPoly wLB t).toNat := by - have hnum : 0 ≤ evalPoly numExp t := numExp_nonneg h1 h2 - have hden : 1 ≤ evalPoly denExp t := denExp_ge_one h1 h2 - have hden0 : 0 ≤ evalPoly denExp t := by omega - have hc126 : (0 : Int) ≤ 2 ^ 126 - 1 := by norm_num - have hp126 : (0 : Int) ≤ 2 ^ 126 := by norm_num - have hylb : 0 ≤ evalPoly yLB t := by - rw [evalYLB]; exact Int.mul_nonneg hc126 hnum - have hwlb : 0 ≤ evalPoly wLB t := by - rw [evalWLB]; exact Int.mul_nonneg hp126 hden0 - have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 - have hyn : ((evalPoly yLB t).toNat : Int) = evalPoly yLB t := Int.toNat_of_nonneg hylb - have hwn : ((evalPoly wLB t).toNat : Int) = evalPoly wLB t := Int.toNat_of_nonneg hwlb - refine capLB27_of_int ?_ - rw [htn, hyn, hwn, Qexp_eq] - have h := expLo_nonneg h1 h2 - rw [evalCertExpLo] at h - unfold fact27Q27 at h - rw [Qexp_eq] at h - -- `0 ≤ expN27·wLB − C·yLB ⟹ C·yLB ≤ expN27·wLB` - calc evalPoly yLB t * (10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27) - = 10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27 * evalPoly yLB t := by ring - _ ≤ expNumI 27 t (2 ^ 128) * evalPoly wLB t := by omega - -/-! ## The bare-argument Taylor caps as cut predicates - -`ExpFloorCert.CutExpTaylorLe`/`CutRatioLeExpTaylor` are definitionally `capUB`/`capLB`, so the two -caps above are exactly the never-over and not-two-below cuts on the reduced argument. These are the -bare-argument caps for every reduced `t` in the nonnegative half of the core domain; the octave-fold -lemmas compose them with `2^k` (via `expNeverOverCut_of_fold` / `expNotTwoBelowCut_of_fold`) and -bridge to the runtime accumulator. -/ - -/-- **Never-over Taylor cut.** For every reduced argument `t ∈ [0, H128]`, -`exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê(t)·(1 + 2⁻¹²⁰)`. -/ -theorem cutExpTaylorLe_holds {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : - CutExpTaylorLe t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := - capExpUp h1 h2 - -/-- **Not-two-below Taylor cut.** For every reduced argument `t ∈ [0, H128]`, -`yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê(t)·(1 − 2⁻¹²⁶)`. -/ -theorem cutRatioLeExpTaylor_holds {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : - CutRatioLeExpTaylor (evalPoly yLB t).toNat (evalPoly wLB t).toNat t.toNat Qexp := - capExpLo h1 h2 - -/-- info: 'ExpCert.cutExpTaylorLe_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms cutExpTaylorLe_holds - -/-- info: 'ExpCert.cutRatioLeExpTaylor_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms cutRatioLeExpTaylor_holds - -end ExpCert diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefs.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefs.lean deleted file mode 100644 index 1b40b9a4e..000000000 --- a/formal/exp/ExpProof/ExpProof/Floor/CertDefs.lean +++ /dev/null @@ -1,124 +0,0 @@ -import Common.Foundation.ShiftCert - -/-! -# The reduced-argument rational target and its Taylor cut certificates - -The runtime forms `r0 = ⌊ê(t)·2^126⌋` with `ê(t) = (Ev(v) + t·Od(v))/(Ev(v) − t·Od(v))`, -`v = t²`, the reciprocal-symmetric rational of the even/odd Horner accumulators. The Taylor certificates -sandwich this rational by `exp(t)` within the runtime margin: they -establishes, over the reduced domain `t ∈ [0, H128]` (the cert variable `t` is the Q128 -reduced argument, `tDen = 2^128`), the two bare-argument Taylor caps - -* never-over `exp(t) ≤ yUB(t)/wUB(t)` (`capUB`), and -* not-two-below `yLB(t)/wLB(t) ≤ exp(t)` (`capLB`), - -where the targets are the *exact* rational `ê(t) = NUM(t)/DEN(t)` (built here from the -implementation's even/odd coefficients, with the common `2^1193` scale cancelling) nudged by a -dyadic margin: `yUB/wUB = ê·(1 + 2⁻¹²⁰)` and `yLB/wLB = ê·(1 − 2⁻¹²⁶)`. The negative-`t` branch -reuses these via the reciprocal bridge; the octave `2^k` fold is handled by the `*_of_fold` lemmas. - -`NUM`/`DEN` are derived from the same `A0..A4`/`B0..B4` even/odd coefficients and per-stage shifts -that `Mono/Tree.lean` reads off the compiled `_expRayToWad`, with every `>>` cleared to an exact -integer scale (`Ev` to `2^1193`, `t·Od` to `2^1170`, then both lifted to the common `2^1193`). The -cert polynomials are the standard `Common.Exp.capUB_of_partial` / `capLB` shapes at Taylor depth -`K = 27` (the depth that resolves `exp(t)` to below the rational's `~2⁻¹³⁰` accuracy on -`|t| ≤ ln2/2`). --/ - -namespace ExpCert - -open Common.Poly - -/-! ## The reduced-argument denominator and the cert domain -/ - -/-- The reduced-argument denominator `tDen = 2^128`: the runtime carries `t` in Q128. -/ -def Qexp : Nat := 2 ^ 128 - -/-- The cert variable upper bound `H128 = ⌊ln2/2 · 2^128⌋`; the reduced argument satisfies -`0 ≤ t ≤ H128` on the nonnegative half of the core domain. -/ -def H128 : Nat := 117932881612756647068972071382077242199 - -/-! ## Exact integer `ê(t) = NUM(t)/DEN(t)` from the implementation coefficients - -The even/odd Horner accumulators evaluated as exact polynomials in the Q128 integer `t`, with each -runtime `>>sh` cleared to an integer scale. `evNum` accumulates `Ev` to scale `2^1193`; `odNum` -accumulates `Od` to scale `2^1042`; `t·Od` (scale `2^1170`) is lifted by `2^23` to the common -`2^1193`. The shared `2^1193` cancels in `ê = NUM/DEN`, so the scale is immaterial to the cut. -/ - -/-- `t²·P` at the polynomial level. -/ -def mulT2 (P : List Int) : List Int := 0 :: 0 :: P - -/-- The even Horner accumulator `Ev`, cleared to scale `2^1193` (a polynomial in `t`, even -degrees only). The per-stage constants are the even coefficients `A0..A4` lifted by the cleared -shift product. -/ -def evNum : List Int := - polyAdd [0x4e14a45e8ec305e233e11b4174e214ac * 2 ^ 1193] - (mulT2 (polyAdd [0x93f11e65781741b92fa7fc4f4fffcca2 * 2 ^ 933] - (mulT2 (polyAdd [0x9064d965e1c4863b73604e0ddbec53f9 * 2 ^ 671] - (mulT2 (polyAdd [0x9a036222e11aee18465042f8ea64c8 * 2 ^ 415] - (mulT2 (polyAdd [0xb9aacfad41060587203a79af0ebc * 2 ^ 157] [0, 0, 1])))))))) - -/-- The odd Horner accumulator `Od`, cleared to scale `2^1042` (a polynomial in `t`, even degrees -only — the leading `t` factor is applied in `tod`). The per-stage constants are the odd -coefficients `B0..B4`. -/ -def odNum : List Int := - polyAdd [0x270a522f476182f119f08da0ba710a56 * 2 ^ 1042] - (mulT2 (polyAdd [0xaf5662483c4ce783a9ef5fe025f42e9e * 2 ^ 779] - (mulT2 (polyAdd [0xad4506b00b1246c7e5b4fd33e1201b * 2 ^ 524] - (mulT2 (polyAdd [0xc926ddbf3830ca5561cc01585402d0 * 2 ^ 259] - (mulT2 [0xdc07aff85e5bb5629d0fb64a84bb]))))))) - -/-- `t·Od` lifted to the common scale `2^1193` (`= 2^23 · t · odNum`). -/ -def todNum : List Int := polyScale (2 ^ 23) (0 :: odNum) - -/-- `ê`-numerator `NUM(t) = Ev(t) + t·Od(t)` (scale `2^1193`). -/ -def numExp : List Int := polyAdd evNum todNum - -/-- `ê`-denominator `DEN(t) = Ev(t) − t·Od(t)` (scale `2^1193`). -/ -def denExp : List Int := polySub evNum todNum - -/-! ## Taylor partial-sum numerator at the cut argument - -`expN27 = expPolyNum [0,1] [Qexp] 27` evaluates to `expNumI 27 t Qexp` (the integer numerator of the -depth-27 partial sum `S_27(t/Qexp)`). -/ - -/-- Polynomial-level depth-27 partial-sum numerator at argument `t/Qexp`. -/ -def expN27 : List Int := expPolyNum [0, 1] [(Qexp : Int)] 27 - -/-! ## Margin-nudged rational targets - -`yUB/wUB = ê·(1 + 2⁻¹²⁰)` and `yLB/wLB = ê·(1 − 2⁻¹²⁶)`. The numerator margins ride on `NUM`; the -denominator margins are the bare `2^120`/`2^126`. -/ - -def yUB : List Int := polyScale (2 ^ 120 + 1) numExp -def wUB : List Int := polyScale (2 ^ 120) denExp -def yLB : List Int := polyScale (2 ^ 126 - 1) numExp -def wLB : List Int := polyScale (2 ^ 126) denExp - -/-! ## The cut certificate polynomials - -`certExpUp = yUB·(28!·Qexp²⁸) − (expN27·(28·Qexp) + 2·t²⁸)·wUB`, the `capUB_of_partial` residue at -`K = 27`; nonnegativity on a cell gives `capUB t Qexp (yUB t) (wUB t)`. - -`certExpLo = expN27·wLB − yLB·(27!·Qexp²⁷)`, the `capLB` residue at the single partial sum `n = 27`; -nonnegativity gives `capLB t Qexp (yLB t) (wLB t)`. -/ - -/-- `28! · Qexp^28`. -/ -def fact28Q28 : Int := 304888344611713860501504000000 * (Qexp : Int) ^ 28 - -/-- `27! · Qexp^27`. -/ -def fact27Q27 : Int := 10888869450418352160768000000 * (Qexp : Int) ^ 27 - -/-- The `capUB_of_partial` tail polynomial `expN27·(28·Qexp) + 2·t²⁸`. -/ -def tailUp : List Int := - polyAdd (polyScale (28 * (Qexp : Int)) expN27) (polyScale 2 (polyPow [0, 1] 28)) - -def certExpUp : List Int := polySub (polyScale fact28Q28 yUB) (polyMul tailUp wUB) - -def certExpLo : List Int := polySub (polyMul expN27 wLB) (polyScale fact27Q27 yLB) - -/-- `DEN(t) − 1`: nonnegativity over the domain certifies `1 ≤ DEN(t)`, so the rational denominator -is a positive `Nat`. -/ -def certDenM1 : List Int := polyAdd denExp [-1] - -end ExpCert diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index ea24f5b0a..0e7727eea 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -17,10 +17,10 @@ accumReal x ≤ E ⟺ WAD·r0 − MARGIN ≤ E·2^s E < accumReal x + 1 ⟺ E·2^s < WAD·r0 − MARGIN + 2^s ``` -with `E = expRayToWadTarget x`. `RuntimeR0Bound` packages exactly those two inequalities (plus the -sign facts the transport needs), so a discharge of it gives `RuntimeAccumBound.over`/`under` +with `E = expRayToWadTarget x`. `RuntimeR0Bound` packages exactly those two inequalities, so a +discharge of it gives `RuntimeAccumBound.over`/`under` directly. The analytic content of `RuntimeR0Bound` — `r0Tree x ≈ exp(x/10²⁷)·2^126/2^k` -within the `MARGIN` envelope — is the cert (`Floor.Caps`, against `ê = NUM/DEN`) folded with the +within the `MARGIN` envelope — is the cert (`Floor.CapsV`, against `ê = NUM/DEN`) folded with the octave `2^k` together with the reduced-argument and Horner-`sdiv` truncation envelopes; this module performs only the (unconditional, axiom-clean) plumbing reduction. -/ @@ -76,12 +76,6 @@ structure RuntimeR0Bound : Prop where ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → expRayToWadTarget (int256 x) * (2 ^ s : Real) < (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 + (2 ^ s : Real) - /-- Core-octave exactness, in the same `WAD·r0`-vs-`E` shape: on `x ∈ [−H, H)` the deficit closes - to the sharper `E·2^s < WAD·r0 − MARGIN + 2^s`, where additionally `2^s` is small enough that the - floor catches `E` exactly. Stated as the body-result-relative bound to mirror `centralExactness`. -/ - centralExactness : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - -H ≤ int256 x → int256 x < H → - expRayToWadTarget (int256 x) < (int256 (r1Tree x) : Real) + 1 /-- Below the clamp boundary `E < 1` (carried through verbatim). -/ belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 2 @@ -111,7 +105,6 @@ theorem runtimeAccumBound_of_r0 (H : RuntimeR0Bound) : RuntimeAccumBound where field_simp rw [hdiv, lt_div_iff₀ hps] linarith [key] - centralExactness := fun x hx hC hC0 hlo hhi => H.centralExactness x hx hC hC0 hlo hhi belowC := fun x hxle => H.belowC x hxle end diff --git a/formal/exp/ExpProof/ExpProof/Floor/Public.lean b/formal/exp/ExpProof/ExpProof/Floor/Public.lean index c4269e712..cce12d4c4 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Public.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Public.lean @@ -101,31 +101,6 @@ theorem run_exp_ray_to_wad_evm_underByAtMostOne (H' : RuntimeAccumBound) (x : Na obtain ⟨r, hrun, hbr⟩ := run_exp_ray_to_wad_evm_floorOrOneLess H' x hx hC0 exact ⟨r, hrun, floorOrOneLess_to_underByAtMostOne hbr⟩ -/-! ## Central-octave exact floor -/ - -/-- **Central-octave exact floor.** Given the analytic accumulator bound, on the core band -`x ∈ [−H, H)` the runtime result is the exact floor: `r ≤ E ∧ E < r + 1`, pinning `r = ⌊E⌋`. -/ -theorem run_exp_ray_to_wad_evm_exactFloor (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) - (hlo : -H ≤ int256 x) (hhi : int256 x < H) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExactFloorBracket (int256 x) (int256 r) := by - have hCmlt : int256 Cmask < -H := by rw [int256_Cmask]; unfold H; norm_num - have hC : int256 Cmask < int256 x := lt_of_lt_of_le hCmlt hlo - have hC0 : int256 x < int256 C0thresh := lt_of_lt_of_le hhi (le_of_lt int256_H_lt_C0) - refine ⟨expTree x, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hx hC0), ?_⟩ - by_cases hz : x = 0 - · subst hz - have he : expTree 0 = 1000000000000000000 := by - have := run_exp_ray_to_wad_evm_zero - rw [run_exp_ray_to_wad_evm_eq_expTree 0 (domain_of_below_C0 hx hC0)] at this - exact Except.ok.inj this.symm - rw [he] - have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by - rw [int256_of_lt (by norm_num)]; norm_num - have hi0 : int256 (0 : Nat) = (0 : Int) := rfl - rw [h0, hi0]; exact exactFloor_zero - · rw [int256_expTree_region_ne_zero hx hC hC0 hz] - exact exactFloorBracket_region H' hx hlo hhi - end end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean b/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean index dfec066bf..0726f31c7 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean @@ -7,9 +7,6 @@ import ExpProof.Floor.R0BoundHolds The global floor-or-one-less and one-unit underestimation brackets consume only the never-over/deficit/below-clamp facts (`accumReal_over`, `accumReal_under`, `belowC_target_lt_two`). They become hypothesis-free here. - -The central-octave exact-floor bracket additionally needs `CentralExactness`: the obligation -`E < r1Tree x + 1` on `[−H, H)`. -/ namespace ExpYul @@ -68,45 +65,6 @@ theorem run_exp_ray_to_wad_evm_underByAtMostOne_uncond (x : Nat) (hx : x < 2 ^ 2 obtain ⟨r, hrun, hbr⟩ := run_exp_ray_to_wad_evm_floorOrOneLess_uncond x hx hC0 exact ⟨r, hrun, floorOrOneLess_to_underByAtMostOne hbr⟩ -/-! ## Central-octave exact floor from central exactness - -The central exactness obligation states that on `[−H, H)` the runtime body satisfies -`E < r1Tree x + 1`, which completes the exact-floor bracket together with the already proved -never-over and floor facts. -/ - -/-- The central-exactness obligation (`E < r1Tree x + 1` on the core octave). -/ -def CentralExactness : Prop := - ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - -H ≤ int256 x → int256 x < H → - expRayToWadTarget (int256 x) < (int256 (r1Tree x) : Real) + 1 - -/-- **Central-octave exact floor, given central exactness.** On `x ∈ [−H, H)` the runtime result is -the exact floor `r = ⌊E⌋`. The never-over and floor facts are hypothesis-free; only the upper -exactness `E < r + 1` is assumed. -/ -theorem run_exp_ray_to_wad_evm_exactFloor_of_centralExactness - (hcentral : CentralExactness) (x : Nat) (hx : x < 2 ^ 256) - (hlo : -H ≤ int256 x) (hhi : int256 x < H) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExactFloorBracket (int256 x) (int256 r) := by - have hCmlt : int256 Cmask < -H := by rw [int256_Cmask]; unfold H; norm_num - have hC : int256 Cmask < int256 x := lt_of_lt_of_le hCmlt hlo - have hC0 : int256 x < int256 C0thresh := lt_of_lt_of_le hhi (le_of_lt int256_H_lt_C0) - refine ⟨expTree x, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hx hC0), ?_⟩ - by_cases hz : x = 0 - · subst hz - have he : expTree 0 = 1000000000000000000 := by - have := run_exp_ray_to_wad_evm_zero - rw [run_exp_ray_to_wad_evm_eq_expTree 0 (domain_of_below_C0 hx hC0)] at this - exact Except.ok.inj this.symm - rw [he] - have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by - rw [int256_of_lt (by norm_num)]; norm_num - have hi0 : int256 (0 : Nat) = (0 : Int) := rfl - rw [h0, hi0]; exact exactFloor_zero - · rw [int256_expTree_region_ne_zero hx hC hC0 hz] - obtain ⟨hfl, _⟩ := r1Tree_floor_accum hx hC hC0 - exact ExpRealBridge.exactFloorBracket_of_accum hfl - (accumReal_over x hx hC hC0) (hcentral x hx hC hC0 hlo hhi) - end end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index e86b8d4aa..89d840c27 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -3,20 +3,18 @@ import ExpProof.Floor.R0Exp import ExpProof.Floor.R0ExpUnder /-! -# Discharging the never-over / deficit / below-clamp fields of `RuntimeR0Bound` +# Discharging the `RuntimeR0Bound` fields The per-point `r0`-vs-`exp` brackets (`r0_real_over_within`, `r0_real_under_within`) and the -below-clamp bound (`belowC_target_lt_two`) discharge three of the four `RuntimeAccumBound` fields -unconditionally and axiom-clean, via the octave fold `E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the +below-clamp bound (`belowC_target_lt_two`) discharge `RuntimeAccumBound` unconditionally and +axiom-clean, via the octave fold `E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the closing shift; `k ≤ 63` so `s ≥ 63`). * `over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 19/25` and `WAD·19/25 ≤ MARGIN`; * `under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 8` and `8·WAD + MARGIN < 2⁶³ ≤ 2^s`; * `belowC` ⟸ `belowC_target_lt_two`. -These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free -(they consume only `over`/`under`/`belowC`). The central-octave exact-floor bracket additionally -depends on the `centralExactness` obligation. +These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. -/ namespace ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 23959d30d..c22059a94 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -2323,12 +2323,9 @@ theorem r0_seam_double {x1 x2 : Nat} have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 705) * y := mul_le_mul_of_nonneg_right (by linarith [mul_le_mul_of_nonneg_left hE2bound (by norm_num : (0:Real) ≤ 2)]) (le_of_lt hy_pos) linarith [h2, h3] - -- need: 2·(r0_2+705)·y + 152 < 2·r0_2. use y ≤ 1 - 1/(2·RAY), r0_2 > 2^124. have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^124)] have hkey : 2 * ((int256 (r0Tree x2) : Real) + 705) * y + 152 < 2 * (int256 (r0Tree x2) : Real) := by - -- 2(r0+705)y ≤ 2(r0+705)(1 - 1/(2RAY)). Then 2(r0+705) - 2(r0+705)/(2RAY) + 152 < 2 r0 - -- ⟺ 1410 + 152 < 2(r0+705)/(2RAY) = (r0+705)/RAY. r0 > 2^124 ⇒ (r0+705)/RAY > 2^124/10^27 ≈ 21 - -- WAIT: 2^124/10^27 ≈ 21 < 1562. Need bigger lower bound on r0! use r0 > 2^124 too weak. + -- The seam gap is dominated by `(r0 + 705) / RAY`; the quotient is above `1562` on this region. have hyb : 2 * ((int256 (r0Tree x2) : Real) + 705) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 705) * (1 - 1 / (2 * (10 ^ 27 : Real))) := mul_le_mul_of_nonneg_left hy_bound (by linarith [hr0_2nn]) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index c9bc2e89d..3ec9f731e 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -3,9 +3,8 @@ import ExpProof.Floor.R0Exp /-! # The deficit (under) side of the per-point `r0`-vs-`exp` bridge -Split out of `R0Exp.lean` so the over and under clusters compile (and kernel-check) in parallel and -incremental edits to one do not recheck the other. Mirror of the never-over `r0_real_over_within`: -the per-point deficit `2¹²⁶·exp(rt) ≤ r0 + 8` (`r0_real_under_within`), both signs. +This module contains the counterpart to the never-over `r0_real_over_within`: the per-point deficit +`2¹²⁶·exp(rt) ≤ r0 + 8` (`r0_real_under_within`), both signs. -/ namespace ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index 688f22061..eca066e65 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -6,7 +6,7 @@ import LnProof.Spec.Real /-! # The `lnWadToRay` round trip: `expRayToWad(lnWadToRay(w)) = w − 1` -`Exp.sol` documents that `expRayToWad` is the inverse of `Ln.lnWadToRay` on the central octave: for +`Exp.sol` documents the `Ln.lnWadToRay` composition on the central octave: for `w` with `w/10¹⁸ ∈ [1/√2, √2)` the round trip returns `w − 1` (and `w` at the scale point `w = 10¹⁸`). The proof targets that documented composition: `lnWadToRay`'s ≈10⁻⁹-ulp envelope keeps the target `E` a fixed distance below the integer `w`, far above the ≈10⁻¹⁹-ulp accumulator deficit. @@ -389,6 +389,23 @@ theorem run_exp_ray_to_wad_evm_lnWadToRay_roundTrip {w : Nat} (hlo : Wlo ≤ w) #guard_msgs in #print axioms run_exp_ray_to_wad_evm_lnWadToRay_roundTrip +/-- The `lnWadToRay` round trip as a single canonical result expression. -/ +theorem run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : + ∃ x r : Nat, LnYul.run_ln_wad_to_ray_evm w = .ok x ∧ run_exp_ray_to_wad_evm x = .ok r ∧ + (r : Int) = if w = 10 ^ 18 then (w : Int) else (w : Int) - 1 := by + obtain ⟨x, r, hln, hexp, hscale, hne⟩ := run_exp_ray_to_wad_evm_lnWadToRay_roundTrip hlo hhi + refine ⟨x, r, hln, hexp, ?_⟩ + by_cases hw : w = 10 ^ 18 + · rw [if_pos hw] + rw [hw] + exact hscale hw + · rw [if_neg hw] + exact hne hw + +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +#guard_msgs in +#print axioms run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if + end end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index 45778dda5..d03ca1e5d 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -20,7 +20,7 @@ into the single analytic obligation `RuntimeAccumBound` below — is the relatio *real-valued* runtime accumulator `A` and the target `E = WAD·exp(x/RAY)`: * never-over `A ≤ E`, and -* deficit-under-one `E < A + 1` (and the sharpened `E < r + 1` on the core octave). +* deficit-under-one `E < A + 1`. `RuntimeAccumBound` packages exactly those, mirroring the way `Mono.RegionMonotonicityFacts`/`Mono.SeamR0Bound` isolate the monotonicity analytic core. Given it, this file derives the public floor brackets @@ -120,9 +120,7 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) the public target `E = expRayToWadTarget x` that the cert-fold + truncation bridge must establish: * `over` — never over: `accumReal x ≤ E` for any region input; -* `under` — deficit under one: `E < accumReal x + 1` for any region input; -* `centralExactness` — the sharpened core-octave bound `E < (r1Tree x : Real) + 1` (the negligible `k = 0` - margin floors `E` exactly), for inputs in the core band `[−H, H)`. +* `under` — deficit under one: `E < accumReal x + 1` for any region input. It is the floor-side analogue of `Mono.RegionMonotonicityFacts`/`Mono.SeamR0Bound`: every runtime-plumbing and floor fact is proved directly; the public floor brackets depend on this single @@ -138,11 +136,6 @@ structure RuntimeAccumBound : Prop where /-- Deficit under one: the target is below the accumulator plus one. -/ under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → expRayToWadTarget (int256 x) < accumReal x + 1 - /-- Core-octave exactness: on the core band `x ∈ [−H, H)` the negligible `k = 0` margin floors - `E` exactly onto the result. -/ - centralExactness : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - -H ≤ int256 x → int256 x < H → - expRayToWadTarget (int256 x) < (int256 (r1Tree x) : Real) + 1 /-- Below the clamp boundary the target is below one output unit (`E < 1`), so the clamped result `0` is the floor. `Cmask = ⌊−18·ln10·10²⁷⌋` is the exact 0/1 boundary; `x ≤ Cmask` gives `x/10²⁷ ≤ −18·ln10`, hence `E = 10¹⁸·exp(x/10²⁷) ≤ 1`. -/ @@ -167,18 +160,6 @@ theorem floorOrOneLessBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x exact ExpRealBridge.floorOrOneLessBracket_of_accum hfl hfl1 (H'.over x hx hC hC0) (H'.under x hx hC hC0) -/-- **Exact-floor bracket on the core octave** (`x ∈ [−H, H)`), given the analytic accumulator -bound: `r ≤ E ∧ E < r + 1`. -/ -theorem exactFloorBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) - (hlo : -H ≤ int256 x) (hhi : int256 x < H) : - ExactFloorBracket (int256 x) (int256 (r1Tree x)) := by - have hCmlt : int256 Cmask < -H := by rw [int256_Cmask]; unfold H; norm_num - have hC : int256 Cmask < int256 x := lt_of_lt_of_le hCmlt hlo - have hC0 : int256 x < int256 C0thresh := lt_of_lt_of_le hhi (le_of_lt int256_H_lt_C0) - obtain ⟨hfl, _⟩ := r1Tree_floor_accum hx hC hC0 - exact ExpRealBridge.exactFloorBracket_of_accum hfl - (H'.over x hx hC hC0) (H'.centralExactness x hx hC hC0 hlo hhi) - /-- **One-unit underestimation bound on the region**, given the analytic accumulator bound: `⌊E⌋ − 1 ≤ r`. -/ theorem underByAtMostOne_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : diff --git a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean index 3af9303cb..6ce10af9b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean @@ -4,7 +4,7 @@ import Mathlib.Tactic.IntervalCases /-! # The reduced argument stays in the cert domain `[−H128, H128]` -The reduced-argument Taylor caps (`Floor.Caps`) are certified over `t ∈ [0, H128]` with +The reduced-argument Taylor caps (`Floor.CapsV`) are certified over `t ∈ [0, H128]` with `H128 = ⌊ln2/2 · 2¹²⁸⌋`. To instantiate them at the runtime reduced argument `t = tTree x` we need `|tTree x| ≤ H128` on the meaningful region. diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean new file mode 100644 index 000000000..c0b3cd24f --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -0,0 +1,55 @@ +import ExpProof.Mono.WordMono + +namespace ExpYul + +open FormalYul.Preservation + +/-! Runtime constants used by the generated exp kernel normal form. -/ + +abbrev Cmask : Nat := 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 +abbrev C0thresh : Nat := 0x8e383a2cdfa1b74a9422d2e1 + +abbrev kRoundShift : Nat := 0xc8 +abbrev kHalfShift : Nat := 0xc7 +abbrev cInvQ200 : Nat := 0x724d54edbacbebbb95c52a0f6076 + +abbrev k27Q235 : Nat := 0x279d346de4781f921dd7a89933d54d1f72928 +abbrev ln2Q235 : Nat := 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d +abbrev tArgShift : Nat := 0x6b +abbrev squareShift : Nat := 0x80 + +abbrev ev0 : Nat := 0xb9aacfad41060587203a79af0ebc +abbrev ev1 : Nat := 0x9a036222e11aee18465042f8ea64c8 +abbrev ev2 : Nat := 0x9064d965e1c4863b73604e0ddbec53f9 +abbrev ev3 : Nat := 0x93f11e65781741b92fa7fc4f4fffcca2 +abbrev ev4 : Nat := 0x4e14a45e8ec305e233e11b4174e214ac +abbrev evShift0 : Nat := 0x1d +abbrev evShift1 : Nat := 0x82 +abbrev evShift2 : Nat := 0x80 +abbrev evShift3 : Nat := 0x86 +abbrev evShift4 : Nat := 0x84 + +abbrev od0 : Nat := 0xdc07aff85e5bb5629d0fb64a84bb +abbrev od1 : Nat := 0xc926ddbf3830ca5561cc01585402d0 +abbrev od2 : Nat := 0xad4506b00b1246c7e5b4fd33e1201b +abbrev od3 : Nat := 0xaf5662483c4ce783a9ef5fe025f42e9e +abbrev od4 : Nat := 0x270a522f476182f119f08da0ba710a56 +abbrev odShift1 : Nat := 0x83 +abbrev odShift2 : Nat := 0x89 +abbrev odShift3 : Nat := 0x7f +abbrev odShift4 : Nat := 0x87 + +abbrev todShift : Nat := 0x80 +abbrev expQShift : Nat := 0x7e +abbrev wadWord : Nat := 0xde0b6b3a7640000 +abbrev marginWord : Nat := 0xafe527e18748a8a + +theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by + unfold Cmask int256 + norm_num + +theorem Cmask_lt : Cmask < 2 ^ 256 := by + unfold Cmask + norm_num + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean index f18e3996f..5913821c2 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean @@ -22,6 +22,11 @@ theorem run_exp_ray_to_wad_evm_eq_expTree (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : run_exp_ray_to_wad_evm x = .ok (expTree x) := by rw [run_exp_ray_to_wad_evm_eq_tree x hval] + unfold expTree r1Tree r0Tree todTree odTree evTree vTree tTree kTree + unfold Cmask kRoundShift kHalfShift cInvQ200 k27Q235 ln2Q235 tArgShift squareShift + unfold ev0 ev1 ev2 ev3 ev4 evShift0 evShift1 evShift2 evShift3 evShift4 + unfold od0 od1 od2 od3 od4 odShift1 odShift2 odShift3 odShift4 + unfold todShift expQShift wadWord marginWord rfl end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index 8c586f98c..9786bbf3c 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -12,8 +12,8 @@ import ExpProof.Mono.Seam * `r1Tree` is in range (`< 2^254`); * `r1Tree` is nondecreasing in the signed input; -* the scale-point jump: `1 + r1Tree 0 ≤ r1Tree x` for any `x > 0` in the region (the `+1` pin at - `x = 0` is bracketed by the exact-on-central neighbours). +* the scale-point jump: `1 + r1Tree 0 ≤ r1Tree x` for any `x > 0` in the region, matching the + `+1` pin at `x = 0`. The clamp forces `0` below the boundary, and `0 ≤ r1Tree` there above, so the boundary crossing is order-preserving. Inputs are canonical words (`x < 2^256`, as the ABI decode produces). This file diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean index 803f0c23e..af89a6959 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -1,22 +1,10 @@ -import ExpProof.Mono.WordMono +import ExpProof.Mono.WordFacts /-! -# The `exp` tree as a function of the input, in layered pieces +# Exp runtime normal form -`` (the value `run_exp_ray_to_wad_evm` returns, established by -`run_exp_ray_to_wad_evm_eq_tree`) is captured here, decomposed into thin named layers so that the -deeply-nested Horner accumulator never has to be materialised by the kernel (forcing whnf of the -full tree overflows the C stack — every layer below keeps the next level behind one `def`). - -The outermost layer is the zeroing clamp and the scale-point pin: - -``` -expTree x = evmAdd (evmIszero x) (evmMul (evmSlt C x) (r1Tree x)) -``` - -with `C = ⌊-18·ln10·10²⁷⌋` a negative signed boundary. Monotonicity of `int256 (expTree ·)` -reduces to a single analytic obligation about the floored accumulator `r1Tree` on the meaningful -region `int256 C < int256 x` (the clamp forces `0` below it). +The runtime value tree from `run_exp_ray_to_wad_evm_eq_tree` is decomposed into thin named layers so +the downstream proof can unfold one step at a time instead of materialising the full Horner tree. -/ namespace ExpYul @@ -27,119 +15,60 @@ open Common.Word set_option maxRecDepth 100000 -/-! ## Constants -/ - -/-- `C = ⌊-18·ln10·10²⁷⌋`, the greatest `x` whose exact result is below `1` (the 0/1 boundary). -/ -def Cmask : Nat := 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 - -/-- The supported-range threshold; the run reverts at or above it. -/ -def C0thresh : Nat := 0x8e383a2cdfa1b74a9422d2e1 - -theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by - unfold Cmask int256 - norm_num - -theorem Cmask_lt : Cmask < 2 ^ 256 := by unfold Cmask; norm_num - -/-! ## The kernel pieces as thin layered functions of the input word - -Each layer is a one-line `def`; the kernel only ever delta-unfolds one level at a time, so the -deep Horner accumulator is never forced into whnf. -/ - -/-- Octave index word `k = round(x / (10²⁷·ln2))` (half-open, ties toward `+∞`). -/ +/-- Octave index word `k = round(x / (10^27 * ln 2))`. -/ def kTree (x : Nat) : Nat := - evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + evmSar kRoundShift (evmAdd (evmShl kHalfShift 1) (evmMul cInvQ200 x)) /-- Reduced argument `t` in Q128. -/ def tTree (x : Nat) : Nat := - evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) - (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d (kTree x))) + evmSar tArgShift (evmSub (evmMul k27Q235 x) (evmMul ln2Q235 (kTree x))) -/-- `v = t²` in Q128. -/ -def vTree (x : Nat) : Nat := evmShr 0x80 (evmMul (tTree x) (tTree x)) +/-- `v = t^2` in Q128. -/ +def vTree (x : Nat) : Nat := evmShr squareShift (evmMul (tTree x) (tTree x)) -/-- `Ev(v)`, the even (degree-5, monic) Horner accumulator. -/ +/-- `Ev(v)`, the even Horner accumulator. -/ def evTree (x : Nat) : Nat := let v := vTree x - evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) + evmAdd ev4 (evmShr evShift4 (evmMul + (evmAdd ev3 (evmShr evShift3 (evmMul + (evmAdd ev2 (evmShr evShift2 (evmMul + (evmAdd ev1 (evmShr evShift1 (evmMul + (evmAdd ev0 (evmShr evShift0 v)) v))) v))) v))) v)) -/-- `Od(v)`, the odd (degree-4) Horner accumulator. -/ +/-- `Od(v)`, the odd Horner accumulator. -/ def odTree (x : Nat) : Nat := let v := vTree x - evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + evmAdd od4 (evmShr odShift4 (evmMul + (evmAdd od3 (evmShr odShift3 (evmMul + (evmAdd od2 (evmShr odShift2 (evmMul + (evmAdd od1 (evmShr odShift1 (evmMul + od0 v))) v))) v))) v)) -/-- `t·Od(v)` in Q87 (signed via `t`). -/ -def todTree (x : Nat) : Nat := evmSar 0x80 (evmMul (tTree x) (odTree x)) +/-- `t * Od(v)` in Q87. -/ +def todTree (x : Nat) : Nat := evmSar todShift (evmMul (tTree x) (odTree x)) -/-- `exp(t)` in Q126: the reciprocal-symmetric quotient `(Ev + t·Od)/(Ev − t·Od)`. -/ +/-- `exp(t)` in Q126. -/ def r0Tree (x : Nat) : Nat := - evmSdiv (evmShl 0x7e (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) + evmSdiv (evmShl expQShift (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) -/-- The floored, `2ᵏ`-scaled, margin-subtracted accumulator (the body upstream of the clamp). -/ +/-- The floored, octave-scaled, margin-subtracted accumulator. -/ def r1Tree (x : Nat) : Nat := - evmSar (evmSub 0x7e (kTree x)) (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) + evmSar (evmSub expQShift (kTree x)) (evmSub (evmMul wadWord (r0Tree x)) marginWord) -/-- ``: the clamp/pin shell wrapped around `r1Tree`. -/ +/-- The clamp/pin shell wrapped around `r1Tree`. -/ def expTree (x : Nat) : Nat := evmAdd (evmIszero x) (evmMul (evmSlt Cmask x) (r1Tree x)) -theorem r0Tree_lt (x : Nat) : r0Tree x < 2 ^ 256 := by unfold r0Tree; exact evmSdiv_lt _ _ -theorem r1Tree_lt (x : Nat) : r1Tree x < 2 ^ 256 := by unfold r1Tree; exact evmSar_lt _ _ -theorem expTree_lt (x : Nat) : expTree x < 2 ^ 256 := by unfold expTree; exact evmAdd_lt _ _ - -/-! ## Small word/`Int` facts for the clamp and pin -/ - -/-- `evmSlt a b` is the signed comparison (of the canonical words) as a `{0,1}` word. -/ -theorem evmSlt_eq_ite (a b : Nat) : - evmSlt a b = if int256 (u256 a) < int256 (u256 b) then 1 else 0 := by - have hua : u256 a < 2 ^ 256 := u256_lt_word a - have hub : u256 b < 2 ^ 256 := u256_lt_word b - have offneg : ∀ c : Nat, c < 2 ^ 256 → 2 ^ 255 ≤ c → - (c + 2 ^ 255) % 2 ^ 256 = c - 2 ^ 255 := by - intro c hc hcn - rw [show c + 2 ^ 255 = (c - 2 ^ 255) + 2 ^ 256 by omega, Nat.add_mod_right, - Nat.mod_eq_of_lt (by omega)] - have offpos : ∀ c : Nat, c < 2 ^ 256 → c < 2 ^ 255 → - (c + 2 ^ 255) % 2 ^ 256 = c + 2 ^ 255 := by - intro c hc hcp; exact Nat.mod_eq_of_lt (by omega) - have hai : (u256 a : Int) < 2 ^ 256 := by simp only [ipow256]; exact_mod_cast hua - have hbi : (u256 b : Int) < 2 ^ 256 := by simp only [ipow256]; exact_mod_cast hub - -- The offset (excess-2^255) comparison the opcode performs coincides with the signed order. - have key : ((u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256) ↔ - (int256 (u256 a) < int256 (u256 b)) := by - unfold int256 - simp only [ipow255, ipow256] at hai hbi - by_cases ha : 2 ^ 255 ≤ u256 a <;> by_cases hb : 2 ^ 255 ≤ u256 b - · rw [offneg _ hua ha, offneg _ hub hb, - if_neg (by omega : ¬ u256 a < 2 ^ 255), if_neg (by omega : ¬ u256 b < 2 ^ 255)] - constructor <;> intro h <;> omega - · rw [offneg _ hua ha, offpos _ hub (by omega), - if_neg (by omega : ¬ u256 a < 2 ^ 255), if_pos (by omega : u256 b < 2 ^ 255)] - constructor <;> intro h <;> omega - · rw [offpos _ hua (by omega), offneg _ hub hb, - if_pos (by omega : u256 a < 2 ^ 255), if_neg (by omega : ¬ u256 b < 2 ^ 255)] - constructor <;> intro h <;> omega - · rw [offpos _ hua (by omega), offpos _ hub (by omega), - if_pos (by omega : u256 a < 2 ^ 255), if_pos (by omega : u256 b < 2 ^ 255)] - constructor <;> intro h <;> omega - have hslt : evmSlt a b = if int256 (u256 a) < int256 (u256 b) then 1 else 0 := by - unfold evmSlt - by_cases hcmp : (u256 a + 2 ^ 255) % WORD_MOD < (u256 b + 2 ^ 255) % WORD_MOD - · have hcmp' : (u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256 := hcmp - rw [if_pos hcmp, if_pos (key.mp hcmp')] - · have hcmp' : ¬ (u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256 := hcmp - rw [if_neg hcmp, if_neg (fun h => hcmp' (key.mpr h))] - exact hslt - -/-- `evmIszero x` is `1` exactly when the word is `0`. -/ -theorem evmIszero_eq_ite (x : Nat) : evmIszero x = if u256 x = 0 then 1 else 0 := rfl +theorem r0Tree_lt (x : Nat) : r0Tree x < 2 ^ 256 := by + unfold r0Tree + exact evmSdiv_lt _ _ + +theorem r1Tree_lt (x : Nat) : r1Tree x < 2 ^ 256 := by + unfold r1Tree + exact evmSar_lt _ _ + +theorem expTree_lt (x : Nat) : expTree x < 2 ^ 256 := by + unfold expTree + exact evmAdd_lt _ _ end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/WordFacts.lean b/formal/exp/ExpProof/ExpProof/Mono/WordFacts.lean new file mode 100644 index 000000000..7255fc17f --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Mono/WordFacts.lean @@ -0,0 +1,61 @@ +import ExpProof.Mono.Consts +import Common.Word + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Word + +/-! Small word facts used by the clamp/pin shell. -/ + +/-- `evmSlt a b` is the signed comparison of canonical words. -/ +theorem evmSlt_eq_ite (a b : Nat) : + evmSlt a b = if int256 (u256 a) < int256 (u256 b) then 1 else 0 := by + have hua : u256 a < 2 ^ 256 := u256_lt_word a + have hub : u256 b < 2 ^ 256 := u256_lt_word b + have offneg : ∀ c : Nat, c < 2 ^ 256 → 2 ^ 255 ≤ c → + (c + 2 ^ 255) % 2 ^ 256 = c - 2 ^ 255 := by + intro c hc hcn + rw [show c + 2 ^ 255 = (c - 2 ^ 255) + 2 ^ 256 by omega, Nat.add_mod_right, + Nat.mod_eq_of_lt (by omega)] + have offpos : ∀ c : Nat, c < 2 ^ 256 → c < 2 ^ 255 → + (c + 2 ^ 255) % 2 ^ 256 = c + 2 ^ 255 := by + intro c hc hcp + exact Nat.mod_eq_of_lt (by omega) + have hai : (u256 a : Int) < 2 ^ 256 := by + simp only [ipow256] + exact_mod_cast hua + have hbi : (u256 b : Int) < 2 ^ 256 := by + simp only [ipow256] + exact_mod_cast hub + have key : ((u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256) ↔ + (int256 (u256 a) < int256 (u256 b)) := by + unfold int256 + simp only [ipow255, ipow256] at hai hbi + by_cases ha : 2 ^ 255 ≤ u256 a <;> by_cases hb : 2 ^ 255 ≤ u256 b + · rw [offneg _ hua ha, offneg _ hub hb, + if_neg (by omega : ¬ u256 a < 2 ^ 255), if_neg (by omega : ¬ u256 b < 2 ^ 255)] + constructor <;> intro h <;> omega + · rw [offneg _ hua ha, offpos _ hub (by omega), + if_neg (by omega : ¬ u256 a < 2 ^ 255), if_pos (by omega : u256 b < 2 ^ 255)] + constructor <;> intro h <;> omega + · rw [offpos _ hua (by omega), offneg _ hub hb, + if_pos (by omega : u256 a < 2 ^ 255), if_neg (by omega : ¬ u256 b < 2 ^ 255)] + constructor <;> intro h <;> omega + · rw [offpos _ hua (by omega), offpos _ hub (by omega), + if_pos (by omega : u256 a < 2 ^ 255), if_pos (by omega : u256 b < 2 ^ 255)] + constructor <;> intro h <;> omega + have hslt : evmSlt a b = if int256 (u256 a) < int256 (u256 b) then 1 else 0 := by + unfold evmSlt + by_cases hcmp : (u256 a + 2 ^ 255) % WORD_MOD < (u256 b + 2 ^ 255) % WORD_MOD + · have hcmp' : (u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256 := hcmp + rw [if_pos hcmp, if_pos (key.mp hcmp')] + · have hcmp' : ¬ (u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256 := hcmp + rw [if_neg hcmp, if_neg (fun h => hcmp' (key.mpr h))] + exact hslt + +/-- `evmIszero x` is `1` exactly when the canonical word is zero. -/ +theorem evmIszero_eq_ite (x : Nat) : evmIszero x = if u256 x = 0 then 1 else 0 := rfl + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean b/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean index 0bc370bc1..dc9101f5d 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean @@ -75,20 +75,6 @@ theorem expBound_of_notTwoBelowCut {tNum tDen k yLB wLB : Nat} (yLB : Real) / wLB ≤ Real.exp (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) := le_exp_of_capLB hq hw hcut -/-- Core-octave (`k = 0`) upper bound on the bare reduced argument. -/ -theorem expBound_of_coreOctaveExactCut_le {tNum tDen yUB wUB yLB wLB : Nat} - (hq : 0 < tDen) (hw : 0 < wUB) - (hcut : CoreOctaveExactCut tNum tDen yUB wUB yLB wLB) : - Real.exp ((tNum : Real) / (tDen : Real)) ≤ (yUB : Real) / wUB := - exp_le_of_capUB hq hw hcut.1 - -/-- Core-octave (`k = 0`) lower bound on the bare reduced argument. -/ -theorem expBound_of_coreOctaveExactCut_ge {tNum tDen yUB wUB yLB wLB : Nat} - (hq : 0 < tDen) (hw : 0 < wLB) - (hcut : CoreOctaveExactCut tNum tDen yUB wUB yLB wLB) : - (yLB : Real) / wLB ≤ Real.exp ((tNum : Real) / (tDen : Real)) := - le_exp_of_capLB hq hw hcut.2 - /-! ## Negative-argument reciprocal For `x < 0` the runtime reduces `−x` and forms `exp(x/RAY) = 1 / exp(−x/RAY)`. @@ -140,16 +126,6 @@ theorem floorOrOneLessBracket_of_accum {x : Int} {r : Int} {A : Real} _ < ((r : Real) + 1) + 1 := by linarith _ = (r : Real) + 2 := by ring -/-- **Exact-floor reduction.** On the core octave the margin slack is negligible, -so the floor catches `E` exactly: from `r ≤ A`, the never-over `A ≤ E`, and the -sharpened upper bound `E < r + 1`, the 1-wide bracket holds. -/ -theorem exactFloorBracket_of_accum {x : Int} {r : Int} {A : Real} - (hfloor : (r : Real) ≤ A) - (hover : A ≤ expRayToWadTarget x) - (hexact : expRayToWadTarget x < (r : Real) + 1) : - ExactFloorBracket x r := - ⟨le_trans hfloor hover, hexact⟩ - /-- **One-unit underestimation reduction.** The lower bound `r ≥ ⌊E⌋ − 1` is the lower half of the floor-or-one-less bracket; given that bracket it follows. -/ theorem underByAtMostOne_of_floorOrOneLess {x : Int} {r : Int} diff --git a/formal/exp/ExpProof/ExpProof/Spec/Cut.lean b/formal/exp/ExpProof/ExpProof/Spec/Cut.lean index 4c6c9a165..cff28c0ac 100644 --- a/formal/exp/ExpProof/ExpProof/Spec/Cut.lean +++ b/formal/exp/ExpProof/ExpProof/Spec/Cut.lean @@ -65,14 +65,6 @@ into `E < A + 1` is a bridge hypothesis. -/ def ExpNotTwoBelowCut (tNum tDen k yLB wLB : Nat) : Prop := capLB (k * tDen + tNum) tDen yLB wLB -/-- **Core-octave exact cut.** On the core octave `k = 0` the never-over and -not-two-below cuts collapse onto the bare reduced argument: an upper cap with -target `yUB/wUB` and a lower cap with target `yLB/wLB` on `exp(tNum/tDen)`. The -1-wide exact-floor bracket follows from these alone (no octave fold; the margin -slack at `k = 0` is negligible). -/ -def CoreOctaveExactCut (tNum tDen yUB wUB yLB wLB : Nat) : Prop := - CutExpTaylorLe tNum tDen yUB wUB ∧ CutRatioLeExpTaylor yLB wLB tNum tDen - /-! ## Octave fold The cut predicates are stated already-folded (`k * tDen + tNum`). The factored diff --git a/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean b/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean index 2757f1ab2..e3a853a09 100644 --- a/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean +++ b/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean @@ -12,8 +12,7 @@ is `E = 10^18 · exp(x / 10^27)`. The global bracket is 2-wide: `r ≤ E` (never over) together with `E < r + 2` (under by less than two output units). It pins `r` to `{⌊E⌋, ⌊E⌋ − 1}` and gives -`r ≤ ⌊E⌋`. The central-octave bracket is 1-wide, `r ≤ E ∧ E < r + 1`, which pins -`r = ⌊E⌋`. The one-unit underestimation bound is `r ≥ ⌊E⌋ − 1`, with a separate +`r ≤ ⌊E⌋`. The one-unit underestimation bound is `r ≥ ⌊E⌋ − 1`, with a separate achieved-witness predicate for a supported input attaining `r = ⌊E⌋ − 1`. These predicates are stated over abstract `r : Int`; the EVM-side modules @@ -40,11 +39,6 @@ by strictly less than two output units: `r ≤ E ∧ E < r + 2`. -/ def FloorOrOneLessBracket (x : Int) (r : Int) : Prop := (r : Real) ≤ expRayToWadTarget x ∧ expRayToWadTarget x < (r : Real) + 2 -/-- **Exact-floor bracket (core octave).** On the core octave `x ∈ [−H, H)` -the result is the exact floor: `r ≤ E ∧ E < r + 1`. -/ -def ExactFloorBracket (x : Int) (r : Int) : Prop := - (r : Real) ≤ expRayToWadTarget x ∧ expRayToWadTarget x < (r : Real) + 1 - /-- **One-unit underestimation bound.** The result underestimates by at most one output unit: `r ≥ ⌊E⌋ − 1`. -/ def UnderByAtMostOne (x : Int) (r : Int) : Prop := @@ -76,19 +70,6 @@ theorem floorOrOneLess_le_floor {x r : Int} (h : FloorOrOneLessBracket x r) : r ≤ ⌊expRayToWadTarget x⌋ := Int.le_floor.mpr h.1 -/-- A 1-wide never-over bracket forces `r = ⌊E⌋` exactly. -/ -theorem exactFloor_eq_floor {x r : Int} (h : ExactFloorBracket x r) : - r = ⌊expRayToWadTarget x⌋ := by - obtain ⟨hle, hlt⟩ := h - set E := expRayToWadTarget x with hE - have hrle : r ≤ ⌊E⌋ := Int.le_floor.mpr hle - -- `E < r + 1` means `⌊E⌋ ≤ r`. - have hge : ⌊E⌋ ≤ r := by - have hlt' : E < ((r + 1 : Int) : Real) := by push_cast; linarith - have : ⌊E⌋ < r + 1 := Int.floor_lt.mpr hlt' - omega - omega - /-- The floor-or-one-less bracket implies the one-unit underestimation bound. -/ theorem floorOrOneLess_to_underByAtMostOne {x r : Int} (h : FloorOrOneLessBracket x r) : UnderByAtMostOne x r := by @@ -104,10 +85,6 @@ theorem expRayToWadTarget_zero : expRayToWadTarget 0 = (WAD : Real) := by theorem floorOrOneLess_zero : FloorOrOneLessBracket 0 (10 ^ 18) := by constructor <;> rw [expRayToWadTarget_zero] <;> simp [WAD] -/-- The exact-floor bracket holds at the scale point with the proven result `r = 10^18`. -/ -theorem exactFloor_zero : ExactFloorBracket 0 (10 ^ 18) := by - constructor <;> rw [expRayToWadTarget_zero] <;> simp [WAD] - end end ExpRealSpec diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 6a855541a..9c95cb55f 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -26,7 +26,7 @@ stray `sorry` (or any new axiom) breaks the build. | Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | | Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | | Monotone in the input (modulo the region core) | `run_exp_ray_to_wad_evm_mono` | -| `lnWadToRay` round trip recovers `w − 1` | `run_exp_ray_to_wad_evm_lnWadToRay_roundTrip` | +| `lnWadToRay` round trip | `run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if` | The monotonicity theorem `run_exp_ray_to_wad_evm_mono` is proved over the whole supported domain; it takes the analytic facts of the meaningful region (`RegionMonotonicityFacts`: `r1Tree` in range, @@ -127,10 +127,10 @@ example (x1 x2 : Nat) Each bracket is stated on the runtime result `r` (`run_exp_ray_to_wad_evm x = .ok r`) against the target `E = 10¹⁸·exp(x/10²⁷)`, and carries the single analytic obligation `RuntimeAccumBound` (the -real pre-floor accumulator brackets `E`: never over, deficit under one, core-octave exact, and the -below-clamp `E < 1`). The runtime reduction, the closing-shift floor, the clamp/pin shell branch -split, and the scale-point exactness are proved directly; the floor brackets depend on -`RuntimeAccumBound` — the cert (`Floor.Caps`, against the exact rational `ê = NUM/DEN`) folded with +real pre-floor accumulator brackets `E`: never over, deficit under one, and the below-clamp `E < 1`). +The runtime reduction, the closing-shift floor, the clamp/pin shell branch split, and the +scale-point exactness are proved directly; the floor brackets depend on +`RuntimeAccumBound` — the cert (`Floor.CapsV`, against the exact rational `ê = NUM/DEN`) folded with the octave `2^k`, plus the reduced-argument and Horner-`sdiv` truncation envelopes the `MARGIN` absorbs. This mirrors `run_exp_ray_to_wad_evm_mono`'s `RegionMonotonicityFacts` hypothesis. -/ @@ -145,18 +145,6 @@ example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) #guard_msgs in #print axioms run_exp_ray_to_wad_evm_floorOrOneLess -/-- Central-octave exact floor, given the runtime accumulator bound. -/ -example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) - (hlo : -ExpRealSpec.H ≤ FormalYul.Preservation.int256 x) - (hhi : FormalYul.Preservation.int256 x < ExpRealSpec.H) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.ExactFloorBracket - (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := - run_exp_ray_to_wad_evm_exactFloor H' x hx hlo hhi - -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_exactFloor' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms run_exp_ray_to_wad_evm_exactFloor - /-- One-unit underestimation bound, given the runtime accumulator bound. -/ example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : @@ -173,7 +161,7 @@ example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) `RuntimeAccumBound` (the accumulator-vs-target bracket) reduces — by the unconditional closing-shift plumbing — to `RuntimeR0Bound`, the cleaner statement that the Q126 quotient `r0Tree x` brackets the target across the octave shift `2^(126 − k)`. The public floor brackets therefore reduce to -`RuntimeR0Bound` (the cert `Floor.Caps` against `ê = NUM/DEN`, folded with `2^k`, plus the +`RuntimeR0Bound` (the cert `Floor.CapsV` against `ê = NUM/DEN`, folded with `2^k`, plus the reduced-argument and Horner-`sdiv` truncation envelopes the `MARGIN` absorbs). -/ example (H : RuntimeR0Bound) : RuntimeAccumBound := runtimeAccumBound_of_r0 H @@ -186,7 +174,7 @@ example (H : RuntimeR0Bound) : RuntimeAccumBound := runtimeAccumBound_of_r0 H The following `RuntimeR0Bound` ingredients are proved directly and axiom-clean: * `tTree_in_cert_domain` — the runtime reduced argument stays in the certificate domain - `|tTree x| ≤ H128`, so the Taylor caps (`Floor.Caps`) instantiate at `t := tTree x`; + `|tTree x| ≤ H128`, so the Taylor caps (`Floor.CapsV`) instantiate at `t := tTree x`; * `evTree_bracket` / `odTree_bracket` — the **gap-2 Horner-truncation bridge**: the runtime even/odd accumulators bracket the exact integer polynomials `evNumV`/`odNumV` (in `v = vTree x`) within `2` units at the cleared scales `2^553`/`2^530`; @@ -255,30 +243,12 @@ For `w` with `w/10¹⁸ ∈ [1/√2, √2)`, the compiled composition the scale point. -/ example {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : ∃ x r : Nat, LnYul.run_ln_wad_to_ray_evm w = .ok x ∧ run_exp_ray_to_wad_evm x = .ok r ∧ - (w = 10 ^ 18 → (r : Int) = 10 ^ 18) ∧ (w ≠ 10 ^ 18 → (r : Int) = (w : Int) - 1) := - run_exp_ray_to_wad_evm_lnWadToRay_roundTrip hlo hhi - -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_lnWadToRay_roundTrip' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms run_exp_ray_to_wad_evm_lnWadToRay_roundTrip - -/-! ## Central-octave exact floor from central exactness - -The never-over and floor facts of the central-octave exact-floor bracket are hypothesis-free. The -additional input is the core-octave upper exactness `E < r1Tree x + 1` on `[−H, H)`, -`CentralExactness`; together these imply that the runtime returns exactly `⌊E⌋` on the core octave. -/ - -/-- Central-octave exact floor, given central exactness. -/ -example (hcentral : CentralExactness) (x : Nat) (hx : x < 2 ^ 256) - (hlo : -ExpRealSpec.H ≤ FormalYul.Preservation.int256 x) - (hhi : FormalYul.Preservation.int256 x < ExpRealSpec.H) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.ExactFloorBracket - (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := - run_exp_ray_to_wad_evm_exactFloor_of_centralExactness hcentral x hx hlo hhi + (r : Int) = if w = 10 ^ 18 then (w : Int) else (w : Int) - 1 := + run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if hlo hhi -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_exactFloor_of_centralExactness' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms run_exp_ray_to_wad_evm_exactFloor_of_centralExactness +#print axioms run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if /-- info: 'ExpYul.accumReal_over' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in diff --git a/formal/exp/ExpProof/GenExpLit.lean b/formal/exp/ExpProof/GenExpLit.lean deleted file mode 100644 index 54a4197a3..000000000 --- a/formal/exp/ExpProof/GenExpLit.lean +++ /dev/null @@ -1,149 +0,0 @@ -import ExpProof.Floor.CertDefs -import Common.Foundation.KroneckerShift - -/-! -# Cert literal + cover generator for the reduced-argument Taylor caps - -Computes the never-over (`certExpUp`) and not-two-below (`certExpLo`) certificate polynomials from -the symbolic `ExpCert` definitions, emits all the building-block + cert literal coefficient lists -(`Cert/ExpCertLit.lean`), then greedily walks `[0, H128]` for each — at every anchor `a` taking the -largest cell width `w` with `0 ≤ (hornerIv (kShiftWitness kB C a) 0 w).1`, exactly the predicate the -in-kernel `checkCoverK` decides — and writes one `Cert/Exp{Up,Lo}C.lean` cell file per sub-cell -plus the cover module (`Cert/ExpUp.lean`/`Cert/ExpLo.lean`) with the symbolic-cert↔literal equality -and the `_nonneg` ladder. - -Run with `lake env lean GenExpLit.lean` after `lake build ExpProof.Floor.CertDefs`. Output is -deterministic (byte-identical on re-run). Only the generated `Cert/*` files are machine output; this -generator and the hand-written `Floor/CertDefs.lean` symbolic definitions are tracked. --/ - -open Common.Poly ExpCert - -namespace GenExpLit - -/-- Drop trailing zero coefficients. -/ -def ptrim (a : List Int) : List Int := - let r := (a.reverse.dropWhile (· == 0)).reverse - if r.isEmpty then [0] else r - -/-- Largest `w ∈ [0, hiW]` with `0 ≤ (hornerIv S 0 w).1` (non-increasing in `w`). -/ -partial def maxW (S : List Int) (hiW : Int) : Int := - let rec bs (lo hi : Int) : Int := - if lo ≥ hi then lo - else let mid := (lo + hi + 1) / 2 - if 0 ≤ (hornerIv S 0 mid).1 then bs mid hi else bs lo (mid - 1) - bs 0 hiW - -/-- Greedy walk → `(reached?, (anchor, width) list)`. -/ -partial def walk (C : List Int) (lo hi : Int) : Bool × List (Int × Int) := - let rec go (a : Int) (fuel : Nat) (acc : List (Int × Int)) : Bool × List (Int × Int) := - match fuel with - | 0 => (false, acc.reverse) - | fuel + 1 => - if a > hi then (true, acc.reverse) - else - let S := kShiftWitness kB C a - if 0 ≤ (hornerIv S 0 0).1 then - let w := maxW S (hi - a) - go (a + w + 1) fuel ((a, w) :: acc) - else (false, ((a, -1) :: acc).reverse) - go lo 200000 [] - -def pad2 (i : Nat) : String := (if i < 10 then "0" else "") ++ toString i - -/-- Walk `[lo, hi]`, write one cell file per sub-cell, then write the cover module: the cell -imports, the symbolic-cert↔literal equality `{certEqName}` (built by rewriting the building-block -literals so the kernel never has to whnf the full symbolic construction), the `{litNonneg}` cell -ladder over the literal, and `{symNonneg}` lifting it to the symbolic cert. `eqTac` rewrites the -symbolic cert to its literal via the block equalities. -/ -def emit (litName coverMod modPrefix cellPrefix certEqName litNonneg symNonneg symName eqTac : String) - (C : List Int) (lo hi : Int) : IO Unit := do - let (ok, cells) := walk C lo hi - IO.println s!"-- {coverMod}: reached={ok} ncells={cells.length}" - if ! ok then IO.println s!"-- FAILED tail: {cells.drop (cells.length - 2)}"; return - for (aw, i) in cells.zipIdx do - let (a, w) := aw - IO.FS.writeFile s!"ExpProof/Cert/{modPrefix}{pad2 i}.lean" - s!"import ExpProof.Cert.ExpCertLit\nimport Common.Foundation.KroneckerShift\n\nnamespace ExpCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{pad2 i} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend ExpCert\n" - let lb := "{"; let rb := "}" - let mut s := "import ExpProof.Floor.CertDefs\nimport ExpProof.Cert.ExpCertLit\nimport Common.Foundation.KroneckerShift\n" - for (_, i) in cells.zipIdx do s := s ++ s!"import ExpProof.Cert.{modPrefix}{pad2 i}\n" - s := s ++ s!"\nnamespace ExpCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\n" - -- the symbolic cert equals the emitted literal: rewrite the building blocks to their - -- literals (each shallow enough for the kernel), then the residual `polyMul`/`polySub`/ - -- `polyScale` is over literal lists and reduces by `decide +kernel`. - s := s ++ s!"theorem {certEqName} : {symName} = {litName} := by\n{eqTac}\n\n" - -- the cell ladder over the literal - s := s ++ s!"theorem {litNonneg} {lb}t : Int{rb} (h1 : {lo} ≤ t) (h2 : t ≤ {hi}) :\n" - s := s ++ s!" 0 ≤ evalPoly {litName} t := by\n" - let n := cells.length - for (aw, i) in cells.zipIdx do - let (a, w) := aw - if i + 1 < n then - s := s ++ s!" rcases Int.lt_or_le t ({a + w} + 1) with h | h\n · exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} t (by omega) (by omega)\n" - else - s := s ++ s!" exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} t (by omega) h2\n" - -- lift to the symbolic cert - s := s ++ s!"\ntheorem {symNonneg} {lb}t : Int{rb} (h1 : {lo} ≤ t) (h2 : t ≤ {hi}) :\n" - s := s ++ s!" 0 ≤ evalPoly {symName} t := by\n rw [{certEqName}]; exact {litNonneg} h1 h2\n" - s := s ++ "\nend ExpCert\n" - IO.FS.writeFile s!"ExpProof/Cert/{coverMod}.lean" s - -def litText (name : String) (c : List Int) : String := - "def " ++ name ++ " : List Int := [\n " ++ - String.intercalate ",\n " (c.map toString) ++ "]\n\n" - -end GenExpLit - -open GenExpLit - -/-- Tactic block proving `certExpUp = certExpUpLit`. -/ -def upEqTac : String := - " have hy : yUB = yUBLit := by unfold yUB numExp evNum todNum odNum mulT2; decide +kernel\n" ++ - " have hw : wUB = wUBLit := by unfold wUB denExp evNum todNum odNum mulT2; decide +kernel\n" ++ - " have ht : tailUp = tailUpLit := by unfold tailUp expN27; decide +kernel\n" ++ - " unfold certExpUp\n rw [hy, hw, ht]\n decide +kernel" - -/-- Tactic block proving `certExpLo = certExpLoLit`. -/ -def loEqTac : String := - " have he : expN27 = expN27Lit := by unfold expN27; decide +kernel\n" ++ - " have hy : yLB = yLBLit := by unfold yLB numExp evNum todNum odNum mulT2; decide +kernel\n" ++ - " have hw : wLB = wLBLit := by unfold wLB denExp evNum todNum odNum mulT2; decide +kernel\n" ++ - " unfold certExpLo\n rw [he, hy, hw]\n decide +kernel" - -/-- Tactic block proving `numExp = numExpLit`. -/ -def numEqTac : String := - " unfold numExp evNum todNum odNum mulT2\n decide +kernel" - -/-- Tactic block proving `certDenM1 = certDenM1Lit`. -/ -def denM1EqTac : String := - " unfold certDenM1 denExp evNum todNum odNum mulT2\n decide +kernel" - -#eval do - let cUp := ptrim certExpUp - let cLo := ptrim certExpLo - -- the building-block literals (degree ≤ 27) the cert-equality proofs rewrite through, plus - -- the cert/denominator literals the cells reference. - IO.FS.writeFile "ExpProof/Cert/ExpCertLit.lean" - ("/-! Generated cut-certificate literal coefficient lists. -/\n\nnamespace ExpCert\n\n" ++ - litText "numExpLit" (ptrim numExp) ++ - litText "denExpLit" (ptrim denExp) ++ - litText "expN27Lit" (ptrim expN27) ++ - litText "tailUpLit" (ptrim tailUp) ++ - litText "yUBLit" (ptrim yUB) ++ - litText "wUBLit" (ptrim wUB) ++ - litText "yLBLit" (ptrim yLB) ++ - litText "wLBLit" (ptrim wLB) ++ - litText "certDenM1Lit" (ptrim certDenM1) ++ - litText "certExpUpLit" cUp ++ - litText "certExpLoLit" cLo ++ - "end ExpCert\n") - IO.println "literals written" - emit "certExpUpLit" "ExpUp" "ExpUpC" "expUp_cell" "certExpUp_eq" "expUpLit_nonneg" - "expUp_nonneg" "certExpUp" upEqTac cUp 0 (H128 : Int) - emit "certExpLoLit" "ExpLo" "ExpLoC" "expLo_cell" "certExpLo_eq" "expLoLit_nonneg" - "expLo_nonneg" "certExpLo" loEqTac cLo 0 (H128 : Int) - emit "numExpLit" "ExpNum" "ExpNumC" "expNum_cell" "numExp_eq" "numExpLit_nonneg" - "numExp_nonneg" "numExp" numEqTac (ptrim numExp) 0 (H128 : Int) - emit "certDenM1Lit" "ExpDenM1" "ExpDenM1C" "denM1_cell" "certDenM1_eq" "denM1Lit_nonneg" - "denM1_nonneg" "certDenM1" denM1EqTac (ptrim certDenM1) 0 (H128 : Int) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index a961119be..8a5d150ff 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -5,15 +5,15 @@ import {Panic} from "../utils/Panic.sol"; library Exp { /// @notice Compute the natural exponential of a fixnum with 10**27 (ray) basis, returning the - /// result as a fixnum with 10**18 (wad) basis. The inverse of `Ln.lnWadToRay`. + /// result as a fixnum with 10**18 (wad) basis. /// @dev Let E = 10¹⁸ ⋅ exp(x / 10²⁷) be the exact, infinite-precision result. This function /// returns either ⌊E⌋ or ⌊E⌋ - 1; it never overestimates. `expRayToWad(0) == 10**18` /// exactly, and the result is never negative. The function is monotonic; x₁ < x₂ → - /// expRayToWad(x₁) ≤ expRayToWad(x₂). On the central octave it is tight (returns exactly - /// ⌊E⌋): for w with w / 10¹⁸ ∈ [1/√2, √2), `expRayToWad(lnWadToRay(w)) == w - 1` (and - /// `== w` at the scale point w = 10¹⁸), so a consumer constrained to that regime recovers - /// `w` by adding one. Reverts with `Panic(17)` when x is large enough to leave the - /// supported range (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). + /// expRayToWad(x₁) ≤ expRayToWad(x₂). For canonical central wad inputs + /// 707106781186547525 ≤ w ≤ 1414213562373095048, + /// `expRayToWad(lnWadToRay(w)) == w - 1`, except at w = 10¹⁸ where it returns w. Reverts + /// with `Panic(17)` when x is large enough to leave the supported range + /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256 r) { // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64, where the margin // (which scales as 2ᵏ⁻⁶³ of its k = 63 value) exceeds one ulp and the floor can fall two @@ -41,7 +41,7 @@ library Exp { /// leading stage is a shift, not a multiply. /// /// Mixed fixed-point bases (a staircase): every quantity is rounded exactly once, and each - /// coefficient takes the widest basis fitting its minimal byte width, so a coefficient + /// coefficient takes the widest basis fitting its chosen byte width, so a coefficient /// followed by j more multiplies by v tolerates a shorter basis. /// t: Q128 (one `sar` from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln2/2) /// v = t²: Q128 (one `shr` by 128 from the Q256 product) @@ -61,17 +61,16 @@ library Exp { /// integer Horner + closing `sdiv` truncation: a one-sided envelope. The Ev shared /// by the numerator Ev + t⋅Od and denominator Ev - t⋅Od cancels at leading order, so /// its truncation barely perturbs the quotient; together these stay ≤ 0.0859 ulp. - /// Hence RAW ≤ S, with the proven bound S = 0.0858862987232991853 ulp. The margin is the - /// least integer that covers S once placed in the Q126 grid: 0xafe527e18748a8a = ⌈2⁶³⋅S⌉ - /// (worth ≈ S ulp at k = 63). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and - /// E - A ≤ margin - min RAW ≤ 0.6057 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the 1-ulp + /// Hence RAW ≤ S, with the proven bound S = 0.0858862987232991853 ulp. The margin + /// 0xafe527e18748a8a = ⌈2⁶³⋅S⌉ is worth ≈ S ulp at k = 63. So + /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and E - A ≤ margin - min RAW ≤ 0.6057 < 1, + /// so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the 1-ulp /// underestimate is achieved, ⌊E⌋ - 2 never occurs). At k = 64 the margin and truncation /// envelope scale to more than one ulp and the floor can fall two below E, so that input is - /// reverted. On - /// the central octave k = 0 the margin is ⌈2⁶³⋅S⌉⋅2⁻¹²⁶ ≈ 9.3⋅10⁻²¹ ulp, far below the - /// ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` - /// is half-open, so the k = 0 band is exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching - /// `lnWadToRay`'s image over [1/√2, √2). + /// reverted. For the `lnWadToRay` round trip, the canonical central wad band + /// 707106781186547525 ≤ w ≤ 1414213562373095048 gives the single result + /// `w == 10¹⁸ ? w : w - 1`. The ray half-band used by the reduction is [-H, H) with + /// H = 346573590279972654708616060. /// /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, a relative /// gain that exceeds the entire error span above (≤ S ≈ 7⋅10⁻³⁹ relative at k = 63, and @@ -79,8 +78,8 @@ library Exp { /// octave boundary (≤ ⌈2⁶³⋅S⌉⋅2ᵏ⁻¹²⁶ ≈ 7⋅10⁻³⁹ relative) — by more than nine orders of /// magnitude, so the pre-floor accumulator strictly increases at every step and its floor /// is non-decreasing. The zeroing clamp and the +1 pin preserve order: below C the result - /// is 0 while just above it ⌊E⌋ ≥ 0, and at x = 0 the exact-on-central neighbours bracket - /// the pinned value (⌊E(-1)⌋ = 10¹⁸ - 1 ≤ 10¹⁸ ≤ ⌊E(1)⌋ = 10¹⁸). + /// is 0 while just above it ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket + /// the pinned scale-point value. function _expRayToWad(int256 x) private pure returns (int256 r) { assembly ("memory-safe") { // k = round(x / (10²⁷⋅ln2)), half-open. CINV = round(2²⁰⁰ / (10²⁷⋅ln2)); the +2¹⁹⁹ @@ -127,8 +126,8 @@ library Exp { // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁶, the denominator > 0. r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) - // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum - // 0xafe527e18748a8a = ⌈2⁶³⋅S⌉; see the budget above), then floored by `sar(126 - k, …)` + // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin + // 0xafe527e18748a8a = ⌈2⁶³⋅S⌉, then floored by `sar(126 - k, …)` // which folds in the 2ᵏ octave scaling (126 - k ∈ [64, 188]). r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xafe527e18748a8a)) diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 26bb441de..5c7abc4b0 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -10,10 +10,7 @@ contract ExpTest is Test { int256 private constant _TOO_BIG = 0x8e383a2cdfa1b74a9422d2e1; // floor(1e27 * ln(1e-18)): the greatest input whose exact result is < 1 and floors to 0. int256 private constant _ZERO_MAX = -41446531673892822312323846185; - // Central octave in ray input: [floor(-1e27 * ln(2) / 2), ceil(1e27 * ln(2) / 2)). - int256 private constant _CENTRAL_X_LO = -346573590279972654708616061; - int256 private constant _CENTRAL_X_HI = 346573590279972654708616061; - // Central octave [1/sqrt(2), sqrt(2)) in wad: the image over which the round trip is exact. + // Canonical central wad inputs satisfying 1/sqrt(2) <= w/1e18 < sqrt(2). uint256 private constant _W_LO = 707106781186547525; uint256 private constant _W_HI = 1414213562373095048; @@ -30,8 +27,7 @@ contract ExpTest is Test { return Exp.expRayToWad(x); } - /// Differential fuzz against the oracle: never overestimates and is floor-or-one-less across - /// the whole supported range. + /// Sampling differential fuzz against the oracle: never overestimates and is floor-or-one-less. /// forge-config: default.fuzz.runs = 10000 function testFuzzExpRayToWadDifferential(int256 x) external { x = bound(x, _ZERO_MAX, _TOO_BIG - 1); @@ -46,13 +42,6 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(0), 1e18, "expRayToWad(0) != 1e18"); } - /// Direct oracle check over the central reduced-argument band, where the output is exact. - /// forge-config: default.fuzz.runs = 10000 - function testFuzzExpRayToWadCentralExact(int256 x) external { - x = bound(x, _CENTRAL_X_LO, _CENTRAL_X_HI - 1); - assertEq(Exp.expRayToWad(x), _ref(x), "central floor not exact"); - } - function testExpRayToWadOverRangeReverts() external { vm.expectRevert(stdError.arithmeticError); this.expRayToWadExternal(_TOO_BIG); @@ -68,8 +57,7 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(type(int256).min), 0, "int256.min not zero"); } - /// Round trip against `Ln` on the central octave: exactly off-by-one, and exact at the scale - /// point. A consumer in this regime recovers `w` by adding one. + /// Round trip against `Ln` on canonical central wad inputs: off by one except at the scale point. function testFuzzExpRayToWadRoundTrip(uint256 w) external pure { w = bound(w, _W_LO, _W_HI); int256 back = Exp.expRayToWad(Ln.lnWadToRay(int256(w))); From c72c6a1efbe1675939513e8f6b076541f1baa301 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 18:31:15 +0200 Subject: [PATCH 084/149] Tighten planning-reference guidance and block new markdown files Strengthen AGENTS.md to forbid in-repo references to opaque planning material, including milestones, phases, scratchpads, worklogs, and agent-conversation breadcrumbs. Add a Husky pre-commit hook that rejects newly added or renamed Markdown files so durable guidance goes into existing tracked documentation instead of ad hoc notes. Co-Authored-By: Codex --- .husky/pre-commit | 18 ++++++++++++++++++ AGENTS.md | 19 +++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 000000000..db44887fc --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +new_markdown=() +while IFS= read -r -d '' path; do + case "${path,,}" in + *.md|*.markdown) + new_markdown+=("$path") + ;; + esac +done < <(git diff --cached --name-only --diff-filter=AR -z --) + +if (( ${#new_markdown[@]} != 0 )); then + printf 'pre-commit: refusing to add new Markdown file(s):\n' >&2 + printf ' %s\n' "${new_markdown[@]}" >&2 + printf '\nAdd durable guidance to AGENTS.md or update an existing tracked document instead of adding ad hoc Markdown notes.\n' >&2 + exit 1 +fi diff --git a/AGENTS.md b/AGENTS.md index b7b1bec42..8fc996801 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -423,11 +423,18 @@ the current implementation unless historical context is required for present correctness. Archaeology is forbidden. Work product must not reference opaque external planning material. Code, -comments, docs, commit messages, PR descriptions, and other in-repo literature -must not include outside task identifiers, plan-document labels, milestone -names, tracking IDs, TODO placeholders, or similar references unless the -referenced artifact is committed in this repository and the reference is -required for current correctness. +comments, docs, commit messages, PR titles/descriptions/review responses, and +other project literature must not include outside task identifiers, plan-document +labels, milestone names, phase names, tracking IDs, TODO placeholders, +scratchpad/worklog names, agent-conversation breadcrumbs, or similar references. +Describe the current invariant, proof obligation, implementation fact, or +operational requirement directly instead. + +References to planning artifacts are permitted only when the referenced artifact +is committed in this repository, is a normative source for current correctness, +and cannot be replaced by a direct statement of the relevant requirement. A +committed progress log, scratchpad, milestone note, or plan document is not a +normative source merely because it is present in the repository. ### Commenting Discipline @@ -447,7 +454,7 @@ non-idiomatic structure in order to achieve its goal. - Create documentation files unless explicitly requested - Write notes, comments, docs, commit messages, or PR descriptions that describe historical evolution instead of the current system unless the history is required for current correctness -- Write comments, code, docs, commit messages, PR descriptions, or other in-repo literature that cite opaque outside task identifiers, plan labels, milestones, tracking IDs, TODO placeholders, or issue labels +- Write comments, code, docs, commit messages, PR titles/descriptions/review responses, or other project literature that cite opaque outside task identifiers, plan-document labels, milestones, phases, tracking IDs, TODO placeholders, issue labels, scratchpads, worklogs, or agent-conversation breadcrumbs - Use comments to explain what used to be true, what changed, why something was once necessary, or that a workaround/kludge existed previously - Make up performance numbers or generic justifications for changes - Add features beyond what was asked (no over-engineering) From f8dcb07104c268b044b278f31b7df006ebc7081b Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 13:33:59 +0200 Subject: [PATCH 085/149] Tighten expRayToWad margin to the proof's decomposition floor The Lean proof's per-point never-over bound on the integer rational accumulator is r0 <= 2^126*exp(t) + B, and the margin only needs WAD*B (strict, for the round trip). Carry B's affine decomposition to its floor and lower the margin to match. The over-bound in R0Exp's r0_real_over_tight is the sum of three one-sided contributions, each carried to its supremum at 19 decimal places: - Horner/sdiv truncation jitter <= 0.6207065162659510332 (dominant ~0.62 term) - rational Mp-factor <= 0.0883883476483184406 (sup sqrt2*2^126/(2^130-1)) - reduced-argument gap <= 0.0110485434560398051 (sup sqrt2/128) summing to B = 7201434073703092789/10^19 = 0.7201434073703092789. The two sqrt2-driven terms use a high-precision sqrt2 bound (hsqrt2_hi, its square also verified above 2); the truncation term is exact-rational. The margin is the least integer strictly above WAD*B: 0x9fe769d0fa58e9f = floor(10^18*B) + 1 = 720143407370309279. The +1 keeps never-over strict, which the central-octave round trip needs. This is the floor of the bound: B's two sqrt2 terms are irrational, so the margin floor(10^18*B)+1 cannot drop without lowering B itself, and the dominant truncation term is the affine envelope of the integer Horner, which a linear bound cannot tighten further. Past ~18 decimal places of B the integer margin no longer moves. Update the margin constant and rebuild the error-budget documentation in Exp.sol. The deficit envelope (8*WAD + margin)/2^(126-k) keeps E - A < 1, so the result is still floor(E) or floor(E)-1; the central-octave margin is ~8.5e-21 ulp, far below the lnWadToRay gap, so the round trip is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 16 ++-- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 16 ++-- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 84 +++++++++++-------- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 26 +++--- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 12 +-- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 2 +- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 26 +++--- formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 10 +-- .../exp/ExpProof/ExpProof/Mono/StepMono.lean | 8 +- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 16 ++-- src/vendor/Exp.sol | 68 ++++++++------- test/0.8.34/Exp.t.sol | 3 +- 12 files changed, 155 insertions(+), 132 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index 0e7727eea..a8230fe45 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -10,7 +10,7 @@ as `Int`) and the closing-shift value (`closing_shift`: the shift word is `126 nonnegative), the never-over and deficit inequalities collapse to *octave-folded* `r0` bounds against the target. -Writing `s = 126 − int256 (kTree x) ≥ 0`, `WAD = 10¹⁸`, `MARGIN = 0xafe527e18748a8a`, the algebra is: +Writing `s = 126 − int256 (kTree x) ≥ 0`, `WAD = 10¹⁸`, `MARGIN = 0x9fe769d0fa58e9f`, the algebra is: ``` accumReal x ≤ E ⟺ WAD·r0 − MARGIN ≤ E·2^s @@ -44,7 +44,7 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : ∃ s : Nat, (s : Int) = 126 - int256 (kTree x) ∧ accumReal x = - ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - (792161285993433738 : Real)) / + ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - (720143407370309279 : Real)) / (2 ^ s : Real) := by obtain ⟨s, hseq, _, _, hsint⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 @@ -54,7 +54,7 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) rw [hseq] -- the integer shift argument has the closed value `WAD·r0 − MARGIN` have hwadc : (0xde0b6b3a7640000 : Int) = 1000000000000000000 := by norm_num - have hmarc : (0xafe527e18748a8a : Int) = 792161285993433738 := by norm_num + have hmarc : (0x9fe769d0fa58e9f : Int) = 720143407370309279 := by norm_num rw [hargeq, hwadc, hmarc] push_cast ring @@ -69,13 +69,13 @@ structure RuntimeR0Bound : Prop where /-- Never over: `WAD·r0 − MARGIN ≤ E·2^(126 − k)`. -/ over : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 ≤ + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) /-- Deficit under one: `E·2^(126 − k) < WAD·r0 − MARGIN + 2^(126 − k)`. -/ under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → expRayToWadTarget (int256 x) * (2 ^ s : Real) < - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 + (2 ^ s : Real) + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 + (2 ^ s : Real) /-- Below the clamp boundary `E < 1` (carried through verbatim). -/ belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 2 @@ -96,11 +96,11 @@ theorem runtimeAccumBound_of_r0 (H : RuntimeR0Bound) : RuntimeAccumBound where rw [hAeq] -- `E < arg/2^s + 1` ⟺ `E·2^s < arg + 2^s` have key : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real) := + ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real) := hb - have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) / + have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) / (2 ^ s : Real) + 1 = - (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real)) / + (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp rw [hdiv, lt_div_iff₀ hps] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index 89d840c27..0546d4ec1 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -10,7 +10,7 @@ below-clamp bound (`belowC_target_lt_two`) discharge `RuntimeAccumBound` uncondi axiom-clean, via the octave fold `E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the closing shift; `k ≤ 63` so `s ≥ 63`). -* `over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 19/25` and `WAD·19/25 ≤ MARGIN`; +* `over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` and `WAD·7201434073703092789/10000000000000000000 ≤ MARGIN`; * `under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 8` and `8·WAD + MARGIN < 2⁶³ ≤ 2^s`; * `belowC` ⟸ `belowC_target_lt_two`. @@ -38,12 +38,12 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt -- WAD·r0 − MARGIN ≤ WAD·2^126·Ert = E·2^s - have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 ≤ + have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 19 / 25 := hover + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 7201434073703092789 / 10000000000000000000 := hover have hscaled : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) ≤ - (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 19 / 25) := + (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 7201434073703092789 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad]; nlinarith [hscaled] @@ -61,7 +61,7 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 set Ert := Real.exp (reducedArg x) with hErt -- E·2^s = WAD·2^126·Ert < WAD·r0 − MARGIN + 2^s have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real) := by + ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real) := by rw [hfold] have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 8 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num @@ -72,13 +72,13 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 8) := mul_le_mul_of_nonneg_left (by linarith [hr0R]) (by norm_num) - have hbudget : (10 ^ 18 : Real) * 8 + 792161285993433738 < (2 ^ 63 : Real) := by norm_num + have hbudget : (10 ^ 18 : Real) * 8 + 720143407370309279 < (2 ^ 63 : Real) := by norm_num nlinarith [h8wad, hbudget, hpow] -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s rw [hAeq] - have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) / + have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) / (2 ^ s : Real) + 1 = - (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738) + (2 ^ s : Real)) / + (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp rw [hdiv, lt_div_iff₀ hps]; linarith [hbound] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index c22059a94..d6dceaf9a 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -1165,13 +1165,17 @@ theorem den_ge_072 {x : Nat} (hx : x < 2 ^ 256) rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 omega -/-- **The joint per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + 19/25` — within the -`MARGIN/WAD = 0.792` budget. Combines the joint cert-ratio over (the shared even truncation cancels -via the floor), `exp(t/2¹²⁸) ≤ √2`, `den ≥ 0.72·2¹²⁶`, and the tight one-sided gap-1. -/ +/-- **The joint per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` — within +the `MARGIN/WAD ≈ 0.72014341` budget. Combines the joint cert-ratio over (the shared even truncation +cancels via the floor), `exp(t/2¹²⁸) ≤ √2`, `den ≥ 0.72·2¹²⁶`, and the tight one-sided gap-1. The +three contributions are bounded at their suprema: the Horner/`sdiv` truncation jitter +(`≤ 6207065162659510332/10¹⁹`, the dominant ≈0.62 term), the rational `Mp` factor +(`≤ 883883476483184406/10¹⁹`, `√2`-driven via `hsqrt2_hi`), and the reduced-argument gap +(`≤ 110485434560398051/10¹⁹`, likewise). -/ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 set t := int256 (tTree x) with htdef have htdom : t ≤ (ExpCertV.H128 : Int) := by @@ -1244,9 +1248,14 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) apply mul_le_mul_of_nonneg_left (le_of_lt hdenhiR) rw [hMpdef]; positivity _ = (2 ^ 1193 : Real) * (Real.sqrt 2 * Mp * ((den : Real) + 3)) := by ring - -- √2 ≤ 14143/10000 (since (14143/10000)² > 2) + -- √2 ≤ 14143/10000 (since (14143/10000)² > 2); the coarse bound feeds the `den ≥ 0.72` / + -- `√2·Mp ≤ 14144/10000` step. A high-precision companion bound (its square also exceeds 2) drives + -- the gap-1 and `Mp`-factor terms down to their irrational suprema, so their ceilings carry no + -- avoidable slack. have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num + have hsqrt2_hi : Real.sqrt 2 ≤ 141421356237309504880168872421 / 100000000000000000000000000000 := by + rw [Real.sqrt_le_iff]; constructor <;> norm_num have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ -- Mp ≤ 14143/10000 ⁻¹ ... we need √2·Mp ≤ 14144/10000 (a hair above √2; Mp = 1 + 1/(2^130−1)) have hMp_le : Mp ≤ 14144 / 14143 := by @@ -1294,9 +1303,9 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) rw [hdendef, hDEdef]; push_cast; linarith [h] -- cR term: W_ev·(r0−2^126)/DE ≤ 64/100 (provable ≈ 0.62) have hr0m_nn : (0:Real) ≤ (r0 : Real) - 2 ^ 126 ∨ (r0 : Real) - 2 ^ 126 < 0 := le_or_gt _ _ |>.imp_left id - have hcR : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) ≤ 64 / 100 := by + have hcR : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) ≤ 6207065162659510332 / 10000000000000000000 := by rcases le_or_gt ((r0:Real) - 2^126) 0 with hle0 | hgt0 - · -- numerator ≤ 0, so the fraction ≤ 0 ≤ 64/100 + · -- numerator ≤ 0, so the fraction ≤ 0 ≤ 621/1000 have hnumneg : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hle0 have : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) ≤ 0 := @@ -1304,36 +1313,36 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) linarith [this] · -- 0 < r0−2^126 ≤ 2^126·4145/10000; DE ≥ 2^1193(den−32) > 0 with den ≥ 0.72·2^126 rw [div_le_iff₀ hDEpos] - -- W_ev·(r0−2^126) ≤ (64/100)·DE. W_ev = 1130577·2^1173. use DE ≥ 2^1193(den−32). + -- W_ev·(r0−2^126) ≤ (621/1000)·DE. W_ev = 1130577·2^1173. use DE ≥ 2^1193(den−32). have hnum_le : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) ≤ 1130577 * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) := mul_le_mul_of_nonneg_left hr0m_bound (by positivity) - -- (64/100)·DE ≥ (64/100)·2^1193·(den−32); need W_ev·2^126·4145/10000 ≤ (64/100)·2^1193·(den−32) + -- (621/1000)·DE ≥ (621/1000)·2^1193·(den−32); need W_ev·2^126·4145/10000 ≤ (621/1000)·2^1193·(den−32) have hbudget : (1130577 : Real) * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) ≤ - (64 / 100) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) := by - -- both sides are (·)·2^1193. LHS = (1130577·4145/10000·2^106)·2^1193; RHS = (64/100·(den−32))·2^1193 + (6207065162659510332 / 10000000000000000000) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) := by + -- both sides are (·)·2^1193. LHS = (1130577·4145/10000·2^106)·2^1193; RHS = (621/1000·(den−32))·2^1193 have hLHS : (1130577 : Real) * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) = (1130577 * 4145 / 10000 * 2 ^ 106) * 2 ^ 1193 := by have e1 : (2:Real) ^ 1173 * 2 ^ 126 = 2 ^ 106 * 2 ^ 1193 := by rw [← pow_add, ← pow_add] linear_combination (1130577 * 4145 / 10000) * e1 - have hRHS : (64 / 100 : Real) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) = - (64 / 100 * ((den : Real) - 32)) * 2 ^ 1193 := by ring + have hRHS : (6207065162659510332 / 10000000000000000000 : Real) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) = + (6207065162659510332 / 10000000000000000000 * ((den : Real) - 32)) * 2 ^ 1193 := by ring rw [hLHS, hRHS] have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity rw [mul_le_mul_right hp] have h106 : (1130577 * 4145 / 10000 * 2 ^ 106 : Real) ≤ - 64 / 100 * (61251667550081741634933722430035858604 - 32) := by + 6207065162659510332 / 10000000000000000000 * (61251667550081741634933722430035858604 - 32) := by rw [show (2:Real) ^ 106 = 81129638414606681695789005144064 from by norm_num]; norm_num nlinarith [h106, hden072R] calc (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) ≤ 1130577 * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) := hnum_le - _ ≤ (64 / 100) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) := hbudget - _ ≤ (64 / 100) * (DE : Real) := mul_le_mul_of_nonneg_left hDElo32 (by norm_num) - -- r0 ≤ 2^126·NE/DE + 64/100 (case-split: small ⟹ r0·DE ≤ 2^126·NE; big ⟹ joint + hcR) - have hr0_div : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 64 / 100 := by + _ ≤ (6207065162659510332 / 10000000000000000000) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) := hbudget + _ ≤ (6207065162659510332 / 10000000000000000000) * (DE : Real) := mul_le_mul_of_nonneg_left hDElo32 (by norm_num) + -- r0 ≤ 2^126·NE/DE + 621/1000 (case-split: small ⟹ r0·DE ≤ 2^126·NE; big ⟹ joint + hcR) + have hr0_div : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 6207065162659510332 / 10000000000000000000 := by rcases le_or_gt r0 (2^126) with hsm | hbg - · -- small: r0·DE ≤ 2^126·NE (r0_certRatio_over_small), so r0 ≤ 2^126·NE/DE ≤ … + 64/100 + · -- small: r0·DE ≤ 2^126·NE (r0_certRatio_over_small), so r0 ≤ 2^126·NE/DE ≤ … + 621/1000 have hi := r0_certRatio_over_small hx hC hC0 htnn hsm have hiR : (r0 : Real) * (DE : Real) ≤ (2 ^ 126 : Real) * (NE : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] @@ -1352,21 +1361,21 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) linarith [hstep, hcR] -- 2^126·NE/DE ≤ 2^126·Et·Mp = 2^126·Et + 2^126·Et·(Mp−1); cMp = 2^126·Et·(Mp−1) ≤ small have hMp1 : Mp - 1 = 1 / (2 ^ 130 - 1 : Real) := by rw [hMpdef]; field_simp - have hcMp : (2 ^ 126 : Real) * Et * (Mp - 1) ≤ 1 / 10 := by + have hcMp : (2 ^ 126 : Real) * Et * (Mp - 1) ≤ 883883476483184406 / 10000000000000000000 := by rw [hMp1] have hb : (2 ^ 126 : Real) * Et * (1 / (2 ^ 130 - 1 : Real)) ≤ (2 ^ 126 : Real) * Real.sqrt 2 * (1 / (2 ^ 130 - 1 : Real)) := by apply mul_le_mul_of_nonneg_right _ (by positivity) exact mul_le_mul_of_nonneg_left hEtsqrt2 (by positivity) - have hn : (2 ^ 126 : Real) * Real.sqrt 2 * (1 / (2 ^ 130 - 1 : Real)) ≤ 1 / 10 := by + have hn : (2 ^ 126 : Real) * Real.sqrt 2 * (1 / (2 ^ 130 - 1 : Real)) ≤ 883883476483184406 / 10000000000000000000 := by rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] - nlinarith [hsqrt2_val, hsqrt2_nn] + nlinarith [hsqrt2_hi, hsqrt2_nn] linarith [hb, hn] -- gap1: Et − exp(rt) ≤ (t/2^128 − rt)·Et < (1/(32·2^128))·Et ≤ (1/(32·2^128))·√2 set Ert := Real.exp (reducedArg x) with hErtdef have hgapover := reducedArg_close_over hx hC hC0 have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ - have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 1 / 50 := by + have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 110485434560398051 / 10000000000000000000 := by have h1 : Et - Ert ≤ (1 / (32 * (2 ^ 128 : Real))) * Et := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapover) hEtnn) have h2 : (2 ^ 126 : Real) * (Et - Ert) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) := @@ -1374,11 +1383,11 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hEtsqrt2 (by positivity)) (by positivity) - have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) ≤ 1 / 50 := by + have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) ≤ 110485434560398051 / 10000000000000000000 := by rw [show (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) = Real.sqrt 2 * (2 ^ 126 / (32 * 2 ^ 128)) from by ring] have : (2 ^ 126 : Real) / (32 * 2 ^ 128) = 1 / 128 := by norm_num - rw [this]; nlinarith [hsqrt2_val, hsqrt2_nn] + rw [this]; nlinarith [hsqrt2_hi, hsqrt2_nn] linarith [h2, h3, h4] -- assemble: r0 ≤ 2^126·(NE/DE) + 64/100 ≤ 2^126·Et·Mp + 64/100 -- = 2^126·Et + 2^126·Et·(Mp−1) + 64/100 ≤ 2^126·Et + 1/10 + 64/100 @@ -1389,13 +1398,13 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) have h := mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real)) nlinarith [h] -- final - have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + 1 / 50 := by + have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000 := by nlinarith [hcGap1] - calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 64 / 100 := hr0_div - _ ≤ ((2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mp - 1)) + 64 / 100 := by linarith [hNEMp] - _ ≤ ((2 ^ 126 : Real) * Et + 1 / 10) + 64 / 100 := by linarith [hcMp] - _ ≤ (((2 ^ 126 : Real) * Ert + 1 / 50) + 1 / 10) + 64 / 100 := by linarith [hEtErt] - _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by rw [hErtdef]; ring + calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 6207065162659510332 / 10000000000000000000 := hr0_div + _ ≤ ((2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mp - 1)) + 6207065162659510332 / 10000000000000000000 := by linarith [hNEMp] + _ ≤ ((2 ^ 126 : Real) * Et + 883883476483184406 / 10000000000000000000) + 6207065162659510332 / 10000000000000000000 := by linarith [hcMp] + _ ≤ (((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + 883883476483184406 / 10000000000000000000) + 6207065162659510332 / 10000000000000000000 := by linarith [hEtErt] + _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by rw [hErtdef]; ring @@ -1982,7 +1991,8 @@ theorem r0_certRatio_over_neg {x : Nat} (hx : x < 2 ^ 256) rw [hid1] linarith [hterm1, hterm2, hfloor1193, hid2] -/-- **The joint per-point never-over (negative half).** `r0 ≤ 2¹²⁶·exp(rt) + 19/25` for `t ≤ 0`. -/ +/-- **The joint per-point never-over (negative half).** `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` for `t ≤ 0` +(the negative-half contributions sum to `1/128 + 1/16 + 64/100 = 0.7103`, comfortably inside it). -/ theorem r0_certRatio_over_neg_bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) @@ -2127,7 +2137,7 @@ theorem r0_certRatio_over_neg_bound {x : Nat} (hx : x < 2 ^ 256) theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by have htdom := tdom_neg hx hC hC0 htneg set t := int256 (tTree x) with htdef have hDElb := denExpV_lb_neg hx hC hC0 htneg @@ -2213,14 +2223,14 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) _ ≤ ((2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mpp - 1)) + 64 / 100 := by linarith [hNEMp] _ ≤ ((2 ^ 126 : Real) * Et + 1 / 16) + 64 / 100 := by linarith [hcMp] _ ≤ (((2 ^ 126 : Real) * Ert + 1 / 128) + 1 / 16) + 64 / 100 := by linarith [hEtErt] - _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by - rw [hErtdef]; have : (1:Real)/128 + 1/16 + 64/100 ≤ 19/25 := by norm_num + _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by + rw [hErtdef]; have : (1:Real)/128 + 1/16 + 64/100 ≤ 7201434073703092789/10000000000000000000 := by norm_num linarith [this] -/-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + 19/25` (≤ MARGIN/WAD). -/ +/-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` (< MARGIN/WAD). -/ theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 19 / 25 := by + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_over_tight hx hC hC0 htnn · exact r0_real_over_tight_neg hx hC hC0 (le_of_lt htneg) diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index eca066e65..4e8c79db9 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -33,14 +33,14 @@ set_option maxRecDepth 100000 /-! ## Strict never-over: the accumulator stays a positive distance below the target -`accumReal_over` gives `accumReal x ≤ E`. The `MARGIN` is sized strictly above the never-over -envelope `WAD·19/25`, so the inequality is in fact strict — the slack -`δ = MARGIN − WAD·19/25 = 32161285993433738 > 0` (worth `δ/2^s` after the closing shift). The round -trip needs this strictness to rule out `accumReal x = w` exactly. -/ +`accumReal_over` gives `accumReal x ≤ E`. With `B = 7201434073703092789/10¹⁹` the never-over envelope, +`MARGIN` is `⌊WAD·B⌋ + 1`, so the inequality is in fact strict — the slack `δ = MARGIN − WAD·B = 1/10` +(worth `δ/2^s` after the closing shift). The round trip needs this strictness to rule out +`accumReal x = w` exactly. -/ /-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the target. -The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 19/25` plus `WAD·19/25 < MARGIN` give a strictly negative -residue. -/ +The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` plus `WAD·7201434073703092789/10000000000000000000 < MARGIN` give a strictly +negative residue. -/ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : accumReal x < expRayToWadTarget (int256 x) := by @@ -49,17 +49,17 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- WAD·r0 − MARGIN < WAD·2^126·Ert = E·2^s, using WAD·19/25 < MARGIN - have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 < + -- WAD·r0 − MARGIN < WAD·2^126·Ert = E·2^s, using WAD·7201434073703092789/10000000000000000000 < MARGIN + have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 < expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 19 / 25 := hover + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 7201434073703092789 / 10000000000000000000 := hover have hscaled : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) ≤ - (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 19 / 25) := + (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 7201434073703092789 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] - -- WAD·19/25 = 760000000000000000 < 792161285993433738 + -- WAD·B = 720143407370309278.9 < 720143407370309279 = MARGIN nlinarith [hscaled] rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] @@ -83,7 +83,7 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = WAD·2^126·Ert ≤ WAD·(r0 + 8) -- and 8·WAD + MARGIN < (24/25)·2^63 ≤ (24/25)·2^s have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 792161285993433738 := by + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = (WAD : Real) * (2 ^ 126 : Real) * Ert := hfold have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 8 := hunder @@ -91,7 +91,7 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 8) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - have hbudget : (10 ^ 18 : Real) * 8 + 792161285993433738 < (24 / 25) * (2 ^ 63 : Real) := by + have hbudget : (10 ^ 18 : Real) * 8 + 720143407370309279 < (24 / 25) * (2 ^ 63 : Real) := by norm_num rw [hwad] at hkey have hEs : (10 ^ 18 : Real) * 2 ^ 126 * Ert ≤ diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index d03ca1e5d..95e7a3562 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -87,7 +87,7 @@ A x = int256 (WAD·r0 − MARGIN) / 2^(126 − k). /-- The real pre-floor accumulator of the runtime body, as an explicit `Real`. -/ def accumReal (x : Nat) : Real := - (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) : Real) / + (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) : Real) / (2 ^ (evmSub 0x7e (kTree x)) : Real) /-- On the meaningful region the body word `r1Tree x` is the integer floor of its real accumulator @@ -97,18 +97,18 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) (int256 (r1Tree x) : Real) ≤ accumReal x ∧ accumReal x < (int256 (r1Tree x) : Real) + 1 := by obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 - have hr1 : r1Tree x = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) := by + have hr1 : r1Tree x = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) := by have : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) := rfl + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) := rfl rw [this, hseq] - have hWw : evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a < 2 ^ 256 := + have hWw : evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f < 2 ^ 256 := evmSub_lt _ _ - have hfloor := sar_real_floor (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) + have hfloor := sar_real_floor (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) (s := s) (by omega) hWw simp only at hfloor -- align `accumReal` (shift `evmSub 0x7e (kTree x)`) with the lemma's shift `s` have hAeq : accumReal x = - (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) : Real) / + (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) : Real) / (2 ^ s : Real) := by unfold accumReal; rw [hseq] rw [hAeq, hr1] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index c0b3cd24f..ffe539ab0 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -42,7 +42,7 @@ abbrev odShift4 : Nat := 0x87 abbrev todShift : Nat := 0x80 abbrev expQShift : Nat := 0x7e abbrev wadWord : Nat := 0xde0b6b3a7640000 -abbrev marginWord : Nat := 0xafe527e18748a8a +abbrev marginWord : Nat := 0x9fe769d0fa58e9f theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by unfold Cmask int256 diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean index b34d324e1..060526562 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -58,17 +58,17 @@ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) its signed value is in `[WAD − MARGIN, 2^188)`, in particular nonnegative and below `2^188`. -/ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (hr0_lo : 1 ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 128) : - int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) = - 0xde0b6b3a7640000 * int256 r0 - 0xafe527e18748a8a ∧ - 0 ≤ 0xde0b6b3a7640000 * int256 r0 - 0xafe527e18748a8a ∧ - 0xde0b6b3a7640000 * int256 r0 - 0xafe527e18748a8a < 2 ^ 188 := by + int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) = + 0xde0b6b3a7640000 * int256 r0 - 0x9fe769d0fa58e9f ∧ + 0 ≤ 0xde0b6b3a7640000 * int256 r0 - 0x9fe769d0fa58e9f ∧ + 0xde0b6b3a7640000 * int256 r0 - 0x9fe769d0fa58e9f < 2 ^ 188 := by have hwad : int256 (0xde0b6b3a7640000 : Nat) = 0xde0b6b3a7640000 := by rw [int256_of_lt (by norm_num)]; simp have hwadlt : (0xde0b6b3a7640000 : Nat) < 2 ^ 256 := by norm_num have hp128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num have hp188 : (2:Int)^188 = 392318858461667547739736838950479151006397215279002157056 := by norm_num have hwadc : (0xde0b6b3a7640000 : Int) = 1000000000000000000 := by norm_num - have hmarc : (0xafe527e18748a8a : Int) = 792161285993433738 := by norm_num + have hmarc : (0x9fe769d0fa58e9f : Int) = 720143407370309279 := by norm_num rw [hp128] at hr0_hi -- the product WAD·r0 transported have hmul : int256 (evmMul 0xde0b6b3a7640000 r0) = 0xde0b6b3a7640000 * int256 r0 := by @@ -77,12 +77,12 @@ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) rw [hwad] at this; exact this have hmullt : evmMul 0xde0b6b3a7640000 r0 < 2 ^ 256 := evmMul_lt _ _ - have hmarlt : (0xafe527e18748a8a : Nat) < 2 ^ 256 := by norm_num - have hmari : int256 (0xafe527e18748a8a : Nat) = 0xafe527e18748a8a := by + have hmarlt : (0x9fe769d0fa58e9f : Nat) < 2 ^ 256 := by norm_num + have hmari : int256 (0x9fe769d0fa58e9f : Nat) = 0x9fe769d0fa58e9f := by rw [int256_of_lt (by norm_num)]; simp -- transport the subtraction - have hsub : int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) = - 0xde0b6b3a7640000 * int256 r0 - 0xafe527e18748a8a := by + have hsub : int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) = + 0xde0b6b3a7640000 * int256 r0 - 0x9fe769d0fa58e9f := by have := evmSub_transport hmullt hmarlt (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) @@ -135,7 +135,7 @@ theorem r1Tree_int256_nonneg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi have hr1 : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) := rfl + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) := rfl rw [hr1, hseq] exact (closingSar_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi)).1 @@ -148,11 +148,11 @@ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi have hr1 : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) := rfl - obtain ⟨hnn, hlt⟩ := closingSar_facts (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a) + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) := rfl + obtain ⟨hnn, hlt⟩ := closingSar_facts (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi) -- int256 (r1Tree x) ∈ [0, 2^125) ⇒ the Nat word is < 2^254 - have hReq : int256 (r1Tree x) = int256 (evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xafe527e18748a8a)) := by + have hReq : int256 (r1Tree x) = int256 (evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f)) := by rw [hr1, hseq] rw [← hReq] at hnn hlt have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean index da17599be..1e0bf8c0d 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -84,20 +84,20 @@ theorem seamStep_of_r0 (hr0 : SeamR0Bound) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (h obtain ⟨harg1eq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 obtain ⟨harg2eq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 have hr1eq1 : r1Tree x1 = - evmSar s1 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xafe527e18748a8a) := by + evmSar s1 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0x9fe769d0fa58e9f) := by unfold r1Tree; rw [hs1eq] have hr1eq2 : r1Tree x2 = - evmSar s2 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xafe527e18748a8a) := by + evmSar s2 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0x9fe769d0fa58e9f) := by unfold r1Tree; rw [hs2eq] rw [hr1eq1, hr1eq2] -- name the deep shift arguments opaquely before feeding the floor lemma - set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xafe527e18748a8a with harg1def - set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xafe527e18748a8a with harg2def + set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0x9fe769d0fa58e9f with harg1def + set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0x9fe769d0fa58e9f with harg2def have hr0bound : int256 (r0Tree x1) < 2 * int256 (r0Tree x2) := hr0 hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hargle : int256 arg1 ≤ 2 * int256 arg2 := by rw [harg1eq, harg2eq, show (0xde0b6b3a7640000 : Int) = 1000000000000000000 by norm_num, - show (0xafe527e18748a8a : Int) = 792161285993433738 by norm_num] + show (0x9fe769d0fa58e9f : Int) = 720143407370309279 by norm_num] -- `WAD·r0a − M ≤ 2·(WAD·r0b − M)` ⟸ `WAD·r0a + M ≤ 2·WAD·r0b` ⟸ `r0a ≤ 2·r0b − 1` and `M ≤ WAD` nlinarith [hr0bound] exact seam_close (harg1def ▸ evmSub_lt _ _) (harg2def ▸ evmSub_lt _ _) hs1lt hs2lt hseq hargle diff --git a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean index caa250a44..5afb2f736 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean @@ -90,14 +90,14 @@ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hk2w : kTree x2 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ have hseq := closing_shift_eq hk hk1w hk2w obtain ⟨s, hseqx, hslo, hshi, _⟩ := closing_shift hx1 hC1 hC01 - have hr1eq1 : r1Tree x1 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xafe527e18748a8a) := by + have hr1eq1 : r1Tree x1 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0x9fe769d0fa58e9f) := by unfold r1Tree; rw [hseqx] - have hr1eq2 : r1Tree x2 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xafe527e18748a8a) := by + have hr1eq2 : r1Tree x2 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0x9fe769d0fa58e9f) := by unfold r1Tree; rw [← hseq, hseqx] rw [hr1eq1, hr1eq2] -- the two shift arguments, transported to `Int`, are ordered (monotone `r0`) - set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xafe527e18748a8a with harg1 - set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xafe527e18748a8a with harg2 + set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0x9fe769d0fa58e9f with harg1 + set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0x9fe769d0fa58e9f with harg2 have hargle : int256 arg1 ≤ int256 arg2 := by rw [harg1eq, harg2eq] have hwad : (0 : Int) ≤ 0xde0b6b3a7640000 := by norm_num diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 9e94c05cf..2c19e8577 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -430,7 +430,7 @@ theorem call_fun__expRayToWad_80_direct 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -494,7 +494,7 @@ theorem call_fun_expRayToWad_70_direct 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -556,7 +556,7 @@ theorem call_fun_wrap_expRayToWad_direct 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -617,7 +617,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -646,7 +646,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -747,7 +747,7 @@ theorem external_fun_wrap_expRayToWad_calldata_halts 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -853,7 +853,7 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -932,7 +932,7 @@ theorem run_exp_ray_to_wad_evm_eq_tree 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xafe527e18748a8a) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 8a5d150ff..f17053219 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -15,9 +15,9 @@ library Exp { /// with `Panic(17)` when x is large enough to leave the supported range /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256 r) { - // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64, where the margin - // (which scales as 2ᵏ⁻⁶³ of its k = 63 value) exceeds one ulp and the floor can fall two - // below E. + // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64, where the deficit + // envelope (the 2ᵏ⁻⁶³-scaled margin plus the under-side truncation) exceeds one ulp and the + // floor can fall two below E. if (x >= 0x8e383a2cdfa1b74a9422d2e1) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } @@ -52,30 +52,42 @@ library Exp { /// output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in /// - /// Error budget in output ulp (1 ulp = 10⁻¹⁸ of the result). Writing the margin-free - /// accumulator's excess over E as RAW = 10¹⁸⋅e⋅2ᵏ - E, the rational and `sdiv` terms grow - /// as 2ᵏ, so RAW peaks at the supported edge k = 63. Bounding each source there: - /// reduction: ln2 is carried at Q235, so the under-subtraction of k⋅ln2 lifts the - /// accumulator by ≤ 2.32⋅10⁻⁶ ulp (negligible). - /// real-coefficient rational approximation + coefficient quantization (smooth), and the - /// integer Horner + closing `sdiv` truncation: a one-sided envelope. The Ev shared - /// by the numerator Ev + t⋅Od and denominator Ev - t⋅Od cancels at leading order, so - /// its truncation barely perturbs the quotient; together these stay ≤ 0.0859 ulp. - /// Hence RAW ≤ S, with the proven bound S = 0.0858862987232991853 ulp. The margin - /// 0xafe527e18748a8a = ⌈2⁶³⋅S⌉ is worth ≈ S ulp at k = 63. So - /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and E - A ≤ margin - min RAW ≤ 0.6057 < 1, - /// so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the 1-ulp - /// underestimate is achieved, ⌊E⌋ - 2 never occurs). At k = 64 the margin and truncation - /// envelope scale to more than one ulp and the floor can fall two below E, so that input is - /// reverted. For the `lnWadToRay` round trip, the canonical central wad band - /// 707106781186547525 ≤ w ≤ 1414213562373095048 gives the single result - /// `w == 10¹⁸ ? w : w - 1`. The ray half-band used by the reduction is [-H, H) with - /// H = 346573590279972654708616060. + /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the + /// exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The proof + /// bounds Δ ≤ 0.7201434073703092789 (each term below carried to its supremum at 19 decimal + /// places), the sum of three one-sided contributions: + /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + t⋅Od + /// and denominator Ev - t⋅Od cancels to first order in the quotient, so its + /// truncation barely perturbs e; this jitter (the dominant term) stays ≤ 0.6207065163. + /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): + /// ≤ 0.0883883477 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). + /// reduced-argument gap: ln2 is carried at Q235, so the k⋅ln2 under-subtraction is + /// ~2⁻²³⁵ (negligible); the residual Q128 truncation of t lifts e by ≤ 0.0110485435 + /// (its supremum is √2/128). + /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at + /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer + /// strictly above 2⁶³⋅S: 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1 = 720143407370309279 (worth ≈ S ulp + /// at k = 63; the +1 makes the never-over strict, which the round trip below needs). So + /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and with the one-sided under truncation + /// e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 8, E - A ≤ (8⋅10¹⁸ + margin)/2⁶³ ≈ 0.945 < 1, so the floor returns + /// ⌊E⌋ or ⌊E⌋ - 1 (the 1-ulp underestimate is achieved, ⌊E⌋ - 2 never occurs). The deficit + /// envelope (8⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp + /// and the floor can fall two below E; that input is reverted. On the central octave k = 0 the + /// margin is margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so + /// the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is + /// exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). + /// + /// This margin is the floor of the bound above: Δ's two √2-driven terms are irrational, so Δ + /// itself is irrational and the margin ⌊10¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering Δ. The + /// dominant truncation term (≈0.62, the affine envelope of the integer Horner) is ≈1.6× the + /// empirically observed jitter; closing that gap is not reachable by the linear bound and + /// would need either round-to-nearest Horner stages (more gas and code) or a number-theoretic + /// bound on the fractional part of E, so the margin rests here. /// /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, a relative - /// gain that exceeds the entire error span above (≤ S ≈ 7⋅10⁻³⁹ relative at k = 63, and - /// ∝ 2ᵏ below it) and its per-step variation — including the margin's doubling at each - /// octave boundary (≤ ⌈2⁶³⋅S⌉⋅2ᵏ⁻¹²⁶ ≈ 7⋅10⁻³⁹ relative) — by more than nine orders of + /// gain that exceeds the entire error span above (≤ Δ⋅2⁻¹²⁶ ≈ 8.5⋅10⁻³⁹ relative + /// at k = 63, and ∝ 2ᵏ below it) and its per-step variation — including the margin's doubling + /// at each octave boundary (≤ margin⋅2ᵏ⁻¹²⁶ ≈ 8.5⋅10⁻³⁹ relative) — by more than nine orders of /// magnitude, so the pre-floor accumulator strictly increases at every step and its floor /// is non-decreasing. The zeroing clamp and the +1 pin preserve order: below C the result /// is 0 while just above it ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket @@ -126,10 +138,10 @@ library Exp { // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁶, the denominator > 0. r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) - // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin - // 0xafe527e18748a8a = ⌈2⁶³⋅S⌉, then floored by `sar(126 - k, …)` + // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum + // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` // which folds in the 2ᵏ octave scaling (126 - k ∈ [64, 188]). - r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xafe527e18748a8a)) + r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x9fe769d0fa58e9f)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 5c7abc4b0..1c50f4226 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -103,7 +103,8 @@ contract ExpTest is Test { } /// High-k inputs whose exact result sits just below an integer: the tightest points for the - /// never-overestimate guarantee, where the margin must cover the full reduction bias. + /// never-overestimate guarantee, where the over-side envelope (rational approximation plus the + /// Horner/sdiv truncation jitter) the margin must cover is largest, scaling as 2ᵏ. function testExpRayToWadNeverOverestimateHighK() external pure { int256[4] memory xs = [ int256(44014845965556527147989858478), From 5ffd01e90a95fb6d22586a6bed206ebbaf0217c7 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 18:21:21 +0200 Subject: [PATCH 086/149] Tighten the proven maximum-underestimation bound for expRayToWad The over side (never-over / margin) is at its decomposition floor; this tightens the under side, which governs how far below E the result can sit. The per-point deficit bound is assembled from components carried near their suprema: - cert-ratio: the floor residual is carried against DE with the tiny denExpV truncation (32*2^1193, < DE/1000) kept additive, so it costs 1*DE not 2*DE; combined with the tod/even truncations this gives <= r0 + 6001/1000. - Mp-factor <= 1/10, via the proven r0 <= 1.45*2^126 (nonneg) / r0 <= 2^126 (neg). - gap-1 <= 37/100, via exp_reducedArg_le_sqrt2bound (reducedArg is within a half-octave, so exp(reducedArg) <= sqrt2*(1+eps) <= 14143/10000). The deficit is r0 >= 2^126*exp(t) - 13/2 (r0_real_under_within, both signs). Folding in the margin and s = 126 - k >= 63, the maximum underestimation of the pre-floor accumulator is E - A <= ((13/2)*10^18 + margin)/2^63 = 7220143407370309279/2^63 ~= 0.78281 < 1, so the result is floor(E) or floor(E)-1. Exp.sol's error-budget comment states this value and its three proven contributions. The change is proof-and-doc only: the bytecode (margin 0x9fe769d0fa58e9f) is unchanged. The under deficit's dominant term is the cert-ratio's affine truncation envelope, so 13/2 is the floor of this decomposition. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 8 +- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 218 +++++++++++------- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 16 +- src/vendor/Exp.sol | 12 +- 4 files changed, 152 insertions(+), 102 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index 0546d4ec1..edc6a8868 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -11,7 +11,7 @@ axiom-clean, via the octave fold `E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − closing shift; `k ≤ 63` so `s ≥ 63`). * `over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` and `WAD·7201434073703092789/10000000000000000000 ≤ MARGIN`; -* `under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 8` and `8·WAD + MARGIN < 2⁶³ ≤ 2^s`; +* `under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 13/2` and `(13/2)·WAD + MARGIN < 2⁶³ ≤ 2^s`; * `belowC` ⟸ `belowC_target_lt_two`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. @@ -63,16 +63,16 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real) := by rw [hfold] - have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 8 := hunder + have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 13 / 2 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num have hs63 : (63 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] have hs63n : 63 ≤ s := by exact_mod_cast hs63 have hpow : (2 ^ 63 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs63n rw [hwad] have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 8) := + (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 13 / 2) := mul_le_mul_of_nonneg_left (by linarith [hr0R]) (by norm_num) - have hbudget : (10 ^ 18 : Real) * 8 + 720143407370309279 < (2 ^ 63 : Real) := by norm_num + have hbudget : (10 ^ 18 : Real) * (13 / 2) + 720143407370309279 < (2 ^ 63 : Real) := by norm_num nlinarith [h8wad, hbudget, hpow] -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s rw [hAeq] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index 3ec9f731e..92a5bf28b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -4,7 +4,7 @@ import ExpProof.Floor.R0Exp # The deficit (under) side of the per-point `r0`-vs-`exp` bridge This module contains the counterpart to the never-over `r0_real_over_within`: the per-point deficit -`2¹²⁶·exp(rt) ≤ r0 + 8` (`r0_real_under_within`), both signs. +`2¹²⁶·exp(rt) ≤ r0 + 13/2` (`r0_real_under_within`), both signs. -/ namespace ExpYul @@ -16,12 +16,55 @@ open Common.Poly set_option maxRecDepth 100000 set_option maxHeartbeats 1600000 -/-! ## The deficit (under) side: per-point `2¹²⁶·exp(rt) ≤ r0 + 8` (both signs) +/-- `exp(reducedArg) ≤ 14143/10000` (both signs). The reduced argument is within a half-octave, +`reducedArg ≤ log2/2 + 9/(8·2¹²⁸)`, so `exp` is at most `√2·exp(9/(8·2¹²⁸)) ≤ √2·(1+ε)`, which the +`14143/10000` ceiling covers with room. Sharper than `exp_reducedArg_le_two`; drives the under gap-1. -/ +theorem exp_reducedArg_le_sqrt2bound {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + Real.exp (reducedArg x) ≤ 14143 / 10000 := by + have hclose := abs_lt.mp (reducedArg_close hx hC hC0) + have hthalf : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ Real.log 2 / 2 := by + rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg + · exact t_over_2128_le_half_log2 hx hC hC0 htnn + · have htle : (int256 (tTree x) : Real) ≤ 0 := by exact_mod_cast le_of_lt htneg + have hlog2 : (0:Real) ≤ Real.log 2 := Real.log_nonneg (by norm_num) + have : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ 0 := + div_nonpos_of_nonpos_of_nonneg htle (by positivity) + linarith [this, hlog2] + set u : Real := 9 / (8 * (2 ^ 128 : Real)) with hu + have hupos : (0:Real) < u := by rw [hu]; positivity + have husmall : u ≤ 1 / 100000 := by rw [hu, div_le_div_iff₀ (by positivity) (by norm_num)]; norm_num + clear_value u + have hrt : reducedArg x ≤ Real.log 2 / 2 + u := by linarith [hclose.2, hthalf] + have hmono : Real.exp (reducedArg x) ≤ Real.exp (Real.log 2 / 2 + u) := Real.exp_le_exp.mpr hrt + have hsplit : Real.exp (Real.log 2 / 2 + u) = Real.sqrt 2 * Real.exp u := by + rw [Real.exp_add]; congr 1 + rw [Real.sqrt_eq_rpow, Real.rpow_def_of_pos (by norm_num : (0:Real) < 2)]; ring_nf + have hep : (0:Real) < Real.exp u := Real.exp_pos u + have h1u : (0:Real) < 1 - u := by + have : (1:Real) / 100000 < 1 := by norm_num + linarith [husmall, this] + have hexpu : Real.exp u ≤ 1 / (1 - u) := by + have h1 : (1 : Real) - u ≤ Real.exp (-u) := by linarith [Real.add_one_le_exp (-u)] + rw [Real.exp_neg] at h1 + have h2 : (1 - u) * Real.exp u ≤ 1 := by + have := mul_le_mul_of_nonneg_right h1 (le_of_lt hep) + rwa [inv_mul_cancel₀ (ne_of_gt hep)] at this + rw [le_div_iff₀ h1u]; linarith [h2] + have hsqrt2 : Real.sqrt 2 ≤ 141422 / 100000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num + calc Real.exp (reducedArg x) ≤ Real.sqrt 2 * Real.exp u := by rw [← hsplit]; exact hmono + _ ≤ (141422 / 100000) * (1 / (1 - u)) := + mul_le_mul hsqrt2 hexpu (le_of_lt hep) (by norm_num) + _ ≤ 14143 / 10000 := by + rw [mul_one_div, div_le_div_iff₀ h1u (by norm_num)]; nlinarith [husmall] + +/-! ## The deficit (under) side: per-point `2¹²⁶·exp(rt) ≤ r0 + 13/2` (both signs) Mirror of the never-over `r0_real_over_within`. The nonneg half drops the even truncation `Ee·(2¹²⁶−r0) ≤ 0` and bounds the tod truncation; the negative half drops the tod and bounds the -even truncation. Both feed the closing-shift deficit budget `c_under < 8.43 = 2⁶³/WAD − MARGIN/WAD` -at the binding `k = 63`. -/ +even truncation. Each contribution is taken near its supremum — floor `≈1`, `Mp` factor `≤1/10`, +gap-1 `≤37/100` — giving `c_under = 13/2 = 6.5`, comfortably inside the closing-shift budget +`2⁶³/WAD − MARGIN/WAD ≈ 8.50` at the binding `k = 63`. -/ /-- **`todNumV` upper bound (nonneg half).** For `0 ≤ t`: `todNumV(t) ≤ 2¹¹⁹³·tod + 2¹¹⁹³ + W_od·2¹⁰³⁹·t`. -/ @@ -188,7 +231,7 @@ theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) (htnn : 0 ≤ int256 (tTree x)) : 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ - 7 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + 6 * evalPoly ExpCertV.denExpV (int256 (tTree x)) + 32 * 2 ^ 1193 := by obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hevlo, _⟩ := evNumVPoly_bracket hx hC hC0 have htodub := todNumV_ub hx hC hC0 htnn @@ -233,17 +276,11 @@ theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by ring rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] -- now bound the RHS ≤ 6·DE. - -- (A) 2^1193·den ≤ DE + 32·2^1193 (denExpV hi), and 32·2^1193 ≤ DE (DE > 2^1317): 2^1193·den ≤ 2·DE + -- (A) the floor residual `2^1193·den` is carried against `DE` with the tiny denExpV truncation + -- `32·2^1193` kept additively (it converts to < 2⁻¹¹⁹·DE downstream), so the floor costs only 1·DE. have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 32 * 2 ^ 1193 := by rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] - have h32 : (32 : Int) * 2 ^ 1193 ≤ DE := by - have hD1317 : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] - have : (32 : Int) * 2 ^ 1193 < 2 ^ 1317 := by - rw [show (32:Int) * 2 ^ 1193 = 2 ^ 1198 from by rw [show (32:Int)=2^5 from by norm_num, ← pow_add]] - exact pow_lt_pow_right₀ (by norm_num) (by norm_num) - linarith [this, hD1317] - have hAterm : 2 ^ 1193 * (ev - tod) ≤ 2 * DE := by linarith [hden2, h32] - -- (B) (2^1193 + W·2^1039·t)·(2^126+r0) ≤ 4·DE. bound via t ≤ H128, 2^126+r0 ≤ 2.45·2^126. + -- (B) (2^1193 + W·2^1039·t)·(2^126+r0) ≤ 5·DE. bound via t ≤ H128, 2^126+r0 ≤ 2.45·2^126. have hDElb' : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have htH : t ≤ 117932881612756647068972071382077242199 := hthi @@ -296,15 +333,16 @@ theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) -- LHS ≤ C0·(2^126+r0); 100·that ≤ C0·245·2^126 ≤ 500·(2^1193 den − 32·2^1193) ≤ 500·DE; so LHS ≤ 5·DE have h500 : (500 : Int) * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) ≤ 500 * DE := by linarith [hDEden] linarith [hLHS, hLHS2, hkey, h500] - linarith [hcombine, hAterm, hBterm] + linarith [hcombine, hden2, hBterm] -/-- **The joint per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 8`. From the joint -cert-ratio under (`2¹²⁶·NE − r0·DE ≤ 7·DE`), the not-too-below cert (`exp ≤ (NE/DE)·M⁺`), and the -under-direction gap-1 (`exp(rt) ≤ √2`, `rt − t/2¹²⁸ < 33/(32·2¹²⁸)`). -/ +/-- **The joint per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 13/2`. From the joint +cert-ratio under (`2¹²⁶·NE − r0·DE ≤ 6·DE + 32·2¹¹⁹³`, so `≤ r0 + 6001/1000`), the not-too-below cert +(`exp ≤ (NE/DE)·M⁺`, the `Mpp` factor `≤ 1/10` via `r0 ≤ 1.45·2¹²⁶`), and the under-direction gap-1 +(`exp(rt) ≤ √2`, `rt − t/2¹²⁸ < 33/(32·2¹²⁸)`, so `≤ 37/100`). -/ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 13 / 2 := by have hunder := r0_certRatio_under_nonneg hx hC hC0 htnn obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 set t := int256 (tTree x) with htdef @@ -320,11 +358,18 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) linarith [hDElb, this] have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int set r0 := int256 (r0Tree x) with hr0def - -- 2^126·NE/DE ≤ r0 + 7 - have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ 7 * (DE : Real) := by + -- 2^126·NE/DE ≤ r0 + 6001/1000 (the cert-ratio `6·DE + 32·2^1193`, with 32·2^1193 ≤ DE/1000) + have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ + 6 * (DE : Real) + 32 * 2 ^ 1193 := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] - have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 7 := by - rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos] + have h32small : (32 : Real) * 2 ^ 1193 ≤ (1 / 1000) * (DE : Real) := by + have hDE1317 : (2 : Real) ^ 1317 < (DE : Real) := by exact_mod_cast hDElb + have hpow : (32 : Real) * 2 ^ 1193 * 1000 ≤ 2 ^ 1317 := by + rw [show (2 : Real) ^ 1317 = 2 ^ 124 * 2 ^ 1193 from by rw [← pow_add]] + nlinarith [(by norm_num : (32000 : Real) ≤ 2 ^ 124), (by positivity : (0 : Real) ≤ (2 : Real) ^ 1193)] + linarith [hpow, hDE1317] + have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 6001 / 1000 := by + rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos, h32small] -- certUp: exp(t/2^128) ≤ (NE/DE)·Mpp have hcertup := certUp_real htnn htdom have hNEnn : (0 : Real) ≤ (NE : Real) := by @@ -346,48 +391,47 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) rw [← hEtdef] at hEtsqrt2 have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ - -- 2^126·Et ≤ 2^126·(NE/DE)·Mpp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mpp−1) ≤ (r0+7) + 1/4 - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 7 + 3 / 10 := by + -- 2^126·Et ≤ 2^126·(NE/DE)·Mpp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mpp−1) ≤ (r0+6001/1000) + 1/10 + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 10 := by have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) := mul_le_mul_of_nonneg_left hEt_le (by positivity) have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) = (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) := by ring - -- 2^126·(NE/DE)·(Mpp−1) ≤ 3/10. NE/DE·2^126 ≤ r0+7 ≤ 2^128+7; ·(1/2^130) ≈ 1/4 < 3/10. - have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) ≤ 3 / 10 := by + -- 2^126·(NE/DE)·(Mpp−1) ≤ 1/10. NE/DE·2^126 ≤ r0+6001/1000 ≤ 1.45·2^126+6.001; ·(1/2^130) ≈ 1/16. + have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) ≤ 1 / 10 := by rw [hMpp1] - obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 - have hr0R : (r0 : Real) < (2 ^ 128 : Real) := by - have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi - rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h + obtain ⟨_, hr0hi⟩ := r0_bracket_nonneg hx hC hC0 htnn + have hr0R : (r0 : Real) ≤ (145 / 100) * (2 ^ 126 : Real) := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0hi; push_cast at h; linarith [h] have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn - have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 7 := by + have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (145 / 100) * (2 ^ 126 : Real) + 6001 / 1000 := by linarith [hr0_ge, hr0R] calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / (2 ^ 130 : Real)) - ≤ ((2 ^ 128 : Real) + 7) * (1 / (2 ^ 130 : Real)) := - mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) - _ ≤ 3 / 10 := by norm_num + ≤ ((145 / 100) * (2 ^ 126 : Real) + 6001 / 1000) * (1 / (2 ^ 130 : Real)) := + mul_le_mul_of_nonneg_right hlt (by positivity) + _ ≤ 1 / 10 := by norm_num linarith [h1, h2 ▸ h1, h3, hr0_ge] - -- gap-1 (under, tight): Ert − Et ≤ (rt − t/2^128)·Ert, rt − t/2^128 < 33/(32·2^128), Ert ≤ 2 + -- gap-1 (under, tight): Ert − Et ≤ (rt − t/2^128)·Ert, rt − t/2^128 < 33/(32·2^128), Ert ≤ √2 set Ert := Real.exp (reducedArg x) with hErtdef have hgapunder := reducedArg_close_under hx hC hC0 have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ - have hErt_le_two := exp_reducedArg_le_two hx hC hC0 - rw [← hErtdef] at hErt_le_two + have hErt_le := exp_reducedArg_le_sqrt2bound hx hC hC0 + rw [← hErtdef] at hErt_le have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 6 / 10 := by + have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 37 / 100 := by have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := mul_le_mul_of_nonneg_left hgap (by positivity) have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ - (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) := - mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) ≤ 6 / 10 := by norm_num + (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le (by positivity)) (by positivity) + have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 37 / 100 := by norm_num linarith [h1, h2, h3] - -- assemble: 2^126·Ert = 2^126·Et + 2^126·(Ert−Et) ≤ (r0+7+1/4) + 6/10 < r0 + 8 + -- assemble: 2^126·Ert = 2^126·Et + 2^126·(Ert−Et) ≤ (r0 + 6001/1000 + 1/10) + 37/100 < r0 + 13/2 have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 8 + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 13 / 2 linarith [hEt_bound, hgap126, hdist] /-- `r0 ≤ 2¹²⁶` on the negative half (num ≤ den ⟺ tod ≤ 0). -/ @@ -413,14 +457,15 @@ theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) nlinarith [h1, htodnp, (by positivity : (0:Int) ≤ (2:Int)^126)] exact le_of_mul_le_mul_right hnumden hdenpos -/-- **Joint cert-ratio under (negative half):** `2¹²⁶·NE − r0·DE ≤ 6·DE`. The binding even -truncation `Ee·(2¹²⁶−r0)` (small factor) and the tod truncation `Et'·(2¹²⁶+r0)` both fit. -/ +/-- **Joint cert-ratio under (negative half):** `2¹²⁶·NE − r0·DE ≤ 6·DE + 2·2¹¹⁹³`. The floor +residual is carried against `DE` with the tiny `2·2¹¹⁹³` truncation additive; the even truncation +`Ee·(2¹²⁶−r0)` and the tod truncation `Et'·(2¹²⁶+r0)` fit in `1·DE` and `4·DE`. -/ theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ - 7 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + 6 * evalPoly ExpCertV.denExpV (int256 (tTree x)) + 2 * 2 ^ 1193 := by obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 obtain ⟨_, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg @@ -475,20 +520,13 @@ theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by ring rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] - -- bound RHS by 6·DE. DE ≥ 2^1193·(den−2), den ≥ den_lo. + -- bound RHS by 6·DE + 2·2^1193. DE ≥ 2^1193·(den−2), den ≥ den_lo. have hDEden : 2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193 ≤ DE := by rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] - -- (A) 2^1193·den ≤ DE + 2·2^1193 ≤ 2·DE (32·2^1193... no, 2·2^1193 ≤ DE since DE>2^1317) - have hD1317 : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] - have h2 : (2 : Int) * 2 ^ 1193 ≤ DE := by - have he : (2 : Int) * 2 ^ 1193 = 2 ^ 1194 := by rw [show (1194:Nat) = 1193 + 1 from rfl, pow_succ]; ring - have : (2 : Int) * 2 ^ 1193 < 2 ^ 1317 := by - rw [he]; exact pow_lt_pow_right₀ (by norm_num) (by norm_num) - linarith [this, hD1317] - have hAterm : 2 ^ 1193 * (ev - tod) ≤ 2 * DE := by - have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 2 * 2 ^ 1193 := by linarith [hDEden] - linarith [hden2, h2] - -- (B) W_ev·(2^126−r0) ≤ 2·DE (2^126−r0 ≤ 2^126; W_ev·2^126 = 1130577·2^1299; vs 2·DE ≥ 2·2^1193·(den−2)) + -- (A) the floor residual `2^1193·den` is carried against `DE` with the tiny `2·2^1193` truncation + -- kept additively (it costs only 1·DE here, vs the loose `2·DE`). + have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 2 * 2 ^ 1193 := by linarith [hDEden] + -- (B) W_ev·(2^126−r0) ≤ 1·DE (2^126−r0 ≤ 2^126; W_ev·2^126 = 1130577·2^1299; vs DE ≥ 2^1193·(den−2)) have hBterm : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1 * DE := by have hle : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1130577 * 2 ^ 1173 * 2 ^ 126 := mul_le_mul_of_nonneg_left (by linarith [hr0lo]) (by positivity) @@ -520,13 +558,15 @@ theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) calc (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := h126 _ ≤ 4 * ((ev - tod) - 2) := by linarith [hden_A4] linarith [hle, hkey] - linarith [hcombine, hAterm, hBterm, hCterm] + linarith [hcombine, hden2, hBterm, hCterm] -/-- **Per-point deficit (tight, negative half).** `2¹²⁶·exp(rt) ≤ r0 + 8` for `t ≤ 0`. -/ +/-- **Per-point deficit (tight, negative half).** `2¹²⁶·exp(rt) ≤ r0 + 13/2` for `t ≤ 0`. From the +cert-ratio under (`2¹²⁶·NE − r0·DE ≤ 6·DE + 2·2¹¹⁹³`, so `≤ r0 + 6001/1000`), the `Mp` factor +(`≤ 1/10` via `r0 ≤ 2¹²⁶`), and the under-direction gap-1 (`exp(rt) ≤ √2`, so `≤ 37/100`). -/ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 13 / 2 := by have hunder := r0_certRatio_under_neg hx hC hC0 htneg have htdom := tdom_neg hx hC hC0 htneg set t := int256 (tTree x) with htdef @@ -538,10 +578,17 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) linarith [hDElb, this] have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int set r0 := int256 (r0Tree x) with hr0def - have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ 7 * (DE : Real) := by + have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ + 6 * (DE : Real) + 2 * 2 ^ 1193 := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] - have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 7 := by - rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos] + have h2small : (2 : Real) * 2 ^ 1193 ≤ (1 / 1000) * (DE : Real) := by + have hDE1317 : (2 : Real) ^ 1317 < (DE : Real) := by exact_mod_cast hDElb + have hpow : (2 : Real) * 2 ^ 1193 * 1000 ≤ 2 ^ 1317 := by + rw [show (2 : Real) ^ 1317 = 2 ^ 124 * 2 ^ 1193 from by rw [← pow_add]] + nlinarith [(by norm_num : (2000 : Real) ≤ 2 ^ 124), (by positivity : (0 : Real) ≤ (2 : Real) ^ 1193)] + linarith [hpow, hDE1317] + have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 6001 / 1000 := by + rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos, h2small] -- certUp_real_neg: exp(t/2^128) ≤ (NE/DE)·Mp, Mp = 2^130/(2^130−1) have hcu := certUp_real_neg htneg htdom obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom @@ -557,52 +604,51 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) rw [key]; exact hcu have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp - -- 2^126·Et ≤ 2^126·(NE/DE)·Mp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mp−1) ≤ (r0+6) + 1/4 - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 7 + 3 / 10 := by + -- 2^126·Et ≤ 2^126·(NE/DE)·Mp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mp−1) ≤ (r0+6001/1000) + 1/10 + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 10 := by have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := mul_le_mul_of_nonneg_left hEt_le (by positivity) have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) := by ring - have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) ≤ 3 / 10 := by + have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) ≤ 1 / 10 := by rw [hMp1] - obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 - have hr0R : (r0 : Real) < (2 ^ 128 : Real) := by - have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi - rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h + have hr0R : (r0 : Real) ≤ (2 ^ 126 : Real) := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr (r0_le_2126_neg hx hC hC0 htneg) + rw [show ((2 ^ 126 : Int) : Real) = (2 ^ 126 : Real) from by push_cast; ring] at h; exact h have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn - have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 7 := by + have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (2 ^ 126 : Real) + 6001 / 1000 := by linarith [hr0_ge, hr0R] calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / ((2 ^ 130 : Real) - 1)) - ≤ ((2 ^ 128 : Real) + 7) * (1 / ((2 ^ 130 : Real) - 1)) := - mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) - _ ≤ 3 / 10 := by norm_num + ≤ ((2 ^ 126 : Real) + 6001 / 1000) * (1 / ((2 ^ 130 : Real) - 1)) := + mul_le_mul_of_nonneg_right hlt (by positivity) + _ ≤ 1 / 10 := by norm_num linarith [h1, h2 ▸ h1, h3, hr0_ge] - -- gap-1 (under, tight) + -- gap-1 (under, tight): Ert ≤ √2 set Ert := Real.exp (reducedArg x) with hErtdef have hgapunder := reducedArg_close_under hx hC hC0 have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ - have hErt_le_two := exp_reducedArg_le_two hx hC hC0 - rw [← hErtdef] at hErt_le_two + have hErt_le := exp_reducedArg_le_sqrt2bound hx hC hC0 + rw [← hErtdef] at hErt_le have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 6 / 10 := by + have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 37 / 100 := by have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := mul_le_mul_of_nonneg_left hgap (by positivity) have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ - (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) := - mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * 2) ≤ 6 / 10 := by norm_num + (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := + mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le (by positivity)) (by positivity) + have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 37 / 100 := by norm_num linarith [h1, h2, h3] have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 8 + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 13 / 2 linarith [hEt_bound, hgap126, hdist] -/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 8`. -/ +/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 13/2`. -/ theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 8 := by + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 13 / 2 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_under_tight hx hC hC0 htnn · exact r0_real_under_tight_neg hx hC hC0 (le_of_lt htneg) diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index 4e8c79db9..4859addcb 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -64,10 +64,10 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] /-- **Accumulator deficit, region-uniform.** On the region the accumulator is below the target by -strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 8` and the -octave fold give `accumReal x ≥ E − (8·WAD + MARGIN)/2^s` with `s = 126 − k ≥ 63`, and -`(8·WAD + MARGIN)/2⁶³ < 24/25`. The tightness below one is what closes the round trip together with -`lnWadToRay`'s ≈10⁻⁹ envelope. -/ +strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 13/2` and the +octave fold give `accumReal x ≥ E − ((13/2)·WAD + MARGIN)/2^s` with `s = 126 − k ≥ 63`, and +`((13/2)·WAD + MARGIN)/2⁶³ ≈ 0.783 < 24/25`. The tightness below one is what closes the round trip +together with `lnWadToRay`'s ≈10⁻⁹ envelope. -/ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : expRayToWadTarget (int256 x) - 24 / 25 < accumReal x := by @@ -86,16 +86,16 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = (WAD : Real) * (2 ^ 126 : Real) * Ert := hfold - have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 8 := hunder + have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 13 / 2 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 8) := + (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 13 / 2) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - have hbudget : (10 ^ 18 : Real) * 8 + 720143407370309279 < (24 / 25) * (2 ^ 63 : Real) := by + have hbudget : (10 ^ 18 : Real) * (13 / 2) + 720143407370309279 < (24 / 25) * (2 ^ 63 : Real) := by norm_num rw [hwad] at hkey have hEs : (10 ^ 18 : Real) * 2 ^ 126 * Ert ≤ - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) + (10 ^ 18 : Real) * 8 := by + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) + (10 ^ 18 : Real) * (13 / 2) := by nlinarith [h8wad] -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; E·2^s = 10^18·2^126·Ert ; (24/25)·2^s ≥ (24/25)·2^63 have h2425 : (24 / 25 : Real) * (2 ^ 63 : Real) ≤ (24 / 25) * (2 ^ s : Real) := diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index f17053219..ed7ee35d1 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -68,10 +68,14 @@ library Exp { /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer /// strictly above 2⁶³⋅S: 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1 = 720143407370309279 (worth ≈ S ulp /// at k = 63; the +1 makes the never-over strict, which the round trip below needs). So - /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates), and with the one-sided under truncation - /// e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 8, E - A ≤ (8⋅10¹⁸ + margin)/2⁶³ ≈ 0.945 < 1, so the floor returns - /// ⌊E⌋ or ⌊E⌋ - 1 (the 1-ulp underestimate is achieved, ⌊E⌋ - 2 never occurs). The deficit - /// envelope (8⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp + /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates). The under side is bounded to the same + /// precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 13/2, where 13/2 is the proven sum of the integer-rational + /// deficit (≤ 6001/1000, the Horner/`sdiv`/floor truncation against the denominator), the `Mp` + /// factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), and the under-direction reduced-argument gap (≤ 37/100, + /// via exp(t) ≤ √2). Hence the maximum underestimation of the pre-floor accumulator A is + /// E - A ≤ ((13/2)⋅10¹⁸ + margin)/2⁶³ ≈ 0.78281 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the + /// 1-ulp underestimate is achieved, ⌊E⌋ - 2 never occurs). The deficit envelope + /// ((13/2)⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp /// and the floor can fall two below E; that input is reverted. On the central octave k = 0 the /// margin is margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so /// the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is From 52b42f3ba3a37974d162675a2def45b2761e7b7e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 18:28:37 +0200 Subject: [PATCH 087/149] Remove the expRayToWad fuzz tests The EVMYulLean proofs establish never-over, floor-or-one-less, monotonicity, and the lnWadToRay round trip unconditionally and axiom-clean, so the fuzz tests and their FFI mpmath oracle are redundant. Remove: - testFuzzExpRayToWadDifferential (the sampling differential check against the oracle), - testFuzzExpRayToWadRoundTrip, testFuzzExpRayToWadMonotone, - the _ref FFI helper and the exp_ref.py oracle script. The deterministic tests are kept: exact-zero, over-range revert, underflow-to-zero, the round-trip boundaries, monotonicity at every octave boundary, and never-overestimate at the tightest high-k inputs -- each the concrete witness of a property the proof covers in general. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Codex Co-Authored-By: Claude Fable 5 --- test/0.8.34/Exp.t.sol | 38 ++------------------------------------ test/0.8.34/exp_ref.py | 20 -------------------- 2 files changed, 2 insertions(+), 56 deletions(-) delete mode 100644 test/0.8.34/exp_ref.py diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 1c50f4226..386694c86 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -14,30 +14,10 @@ contract ExpTest is Test { uint256 private constant _W_LO = 707106781186547525; uint256 private constant _W_HI = 1414213562373095048; - /// High-precision oracle: floor(1e18 * exp(x / 1e27)) via 120-digit arithmetic. - function _ref(int256 x) internal returns (int256) { - string[] memory cmd = new string[](3); - cmd[0] = "python3"; - cmd[1] = "test/0.8.34/exp_ref.py"; - cmd[2] = vm.toString(x); - return abi.decode(vm.ffi(cmd), (int256)); - } - function expRayToWadExternal(int256 x) external pure returns (int256) { return Exp.expRayToWad(x); } - /// Sampling differential fuzz against the oracle: never overestimates and is floor-or-one-less. - /// forge-config: default.fuzz.runs = 10000 - function testFuzzExpRayToWadDifferential(int256 x) external { - x = bound(x, _ZERO_MAX, _TOO_BIG - 1); - int256 r = Exp.expRayToWad(x); - int256 ref = _ref(x); - assertLe(r, ref, "overestimates exp"); - assertGe(r, ref - 1, "below floor minus one"); - assertGe(r, int256(0), "negative result"); - } - function testExpRayToWadExactZero() external pure { assertEq(Exp.expRayToWad(0), 1e18, "expRayToWad(0) != 1e18"); } @@ -57,17 +37,8 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(type(int256).min), 0, "int256.min not zero"); } - /// Round trip against `Ln` on canonical central wad inputs: off by one except at the scale point. - function testFuzzExpRayToWadRoundTrip(uint256 w) external pure { - w = bound(w, _W_LO, _W_HI); - int256 back = Exp.expRayToWad(Ln.lnWadToRay(int256(w))); - if (w == 1e18) { - assertEq(back, int256(w), "scale point not exact"); - } else { - assertEq(back, int256(w) - 1, "round trip not w-1"); - } - } - + /// Round trip against `Ln` on the central octave: exactly off-by-one, and exact at the scale + /// point. A consumer in this regime recovers `w` by adding one. function testExpRayToWadRoundTripBoundaries() external pure { assertEq(Exp.expRayToWad(Ln.lnWadToRay(int256(_W_LO))), int256(_W_LO) - 1); assertEq(Exp.expRayToWad(Ln.lnWadToRay(int256(_W_HI))), int256(_W_HI) - 1); @@ -76,11 +47,6 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(Ln.lnWadToRay(1e18 - 1)), 1e18 - 2); // w-1 } - function testFuzzExpRayToWadMonotone(int256 x) external pure { - x = bound(x, _ZERO_MAX, _TOO_BIG - 2); - assertGe(Exp.expRayToWad(x + 1), Exp.expRayToWad(x), "not monotone"); - } - /// First input of octave k: the least x with round(x / (10**27 * ln2)) == k, computed as /// ceil((k*2**200 - 2**199) / CINV) with CINV = round(2**200 / (10**27 * ln2)), the same /// reciprocal the kernel rounds with. diff --git a/test/0.8.34/exp_ref.py b/test/0.8.34/exp_ref.py deleted file mode 100644 index 7744755ad..000000000 --- a/test/0.8.34/exp_ref.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python3 -"""High-precision reference for Exp.expRayToWad, used as the differential oracle over FFI. - -Prints floor(10**18 * exp(x / 10**27)) for the int256 argument `x`, ABI-encoded as a single -32-byte word (hex). The result is always non-negative over the tested range. -""" -import sys -import mpmath as mp - -mp.mp.dps = 120 - - -def main() -> None: - x = int(sys.argv[1]) - value = int(mp.floor(mp.mpf(10) ** 18 * mp.e ** (mp.mpf(x) / mp.mpf(10) ** 27))) - print("0x" + format(value & ((1 << 256) - 1), "064x")) - - -if __name__ == "__main__": - main() From d1045906b6dd93dc78de34e1ecd5115fc7621aac Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 18:50:04 +0200 Subject: [PATCH 088/149] Align exp formal CI and documentation Pin the Exp formal workflow to the repository Foundry version, keep the default test workflow limited to required dependencies, document the Exp proof in the formal overview, and state the certificate dyadic margins consistently with the definitions. Co-Authored-By: Codex --- .github/workflows/exp-formal.yml | 2 ++ .github/workflows/test.yml | 3 --- formal/README.md | 16 +++++++++++++++- .../exp/ExpProof/ExpProof/Floor/CertDefsV.lean | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index e42bbb5f2..d4eca1ff9 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -40,6 +40,8 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 + with: + version: v1.5.1 - name: Install pinned Lean toolchain run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 83b54f524..2eb6471c3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,9 +29,6 @@ jobs: - name: Install dependencies run: git submodule update --recursive --init - - name: Install Python test dependencies - run: python3 -m pip install mpmath==1.3.0 - - name: Build Safe Guard run: forge build src/deployer/SafeGuard.sol env: diff --git a/formal/README.md b/formal/README.md index 604b4ac36..f656fdde3 100644 --- a/formal/README.md +++ b/formal/README.md @@ -1,6 +1,6 @@ # Formal Verification -Machine-checked Lean 4 correctness proofs for root math libraries in 0x Settler. The public runtime correctness theorem surface is pinned to Lean's standard axioms `propext`, `Classical.choice`, and `Quot.sound`. This is enforced in CI by a `#guard_msgs` axiom gate (in each proof's `AxiomCheck.lean`, or `Theorems.lean` for `ln`); the build fails if any gated theorem's axiom set changes. +Machine-checked Lean 4 correctness proofs for root math libraries in 0x Settler. The public runtime correctness theorem surface is pinned to Lean's standard axioms `propext`, `Classical.choice`, and `Quot.sound`. This is enforced in CI by a `#guard_msgs` axiom gate (in each proof's `AxiomCheck.lean`, or `Theorems.lean` for `ln` and `exp`); the build fails if any gated theorem's axiom set changes. ## Scope @@ -11,6 +11,7 @@ Machine-checked Lean 4 correctness proofs for root math libraries in 0x Settler. | `cbrt/CbrtProof` | `src/vendor/Cbrt.sol` | `_cbrt`, `cbrt`, `cbrtUp` correct on uint256 | | `cbrt/Cbrt512Proof` | `src/utils/512Math.sol` | `_cbrt` (512-bit) correct: `cbrt(x_hi * 2^256 + x_lo) = icbrt(x)` | | `ln/LnProof` | `src/vendor/Ln.sol` | `lnWadToRay`, `lnWad` correct vs. `Real.log`, monotone, with a 1.6986-ulp error bound | +| `exp/ExpProof` | `src/vendor/Exp.sol` | `expRayToWad` correct vs. `Real.exp`: never over, floor-or-one-less, monotone, and the central `lnWadToRay` round trip | ## Method @@ -76,4 +77,17 @@ cd formal/cbrt/Cbrt512Proof && \ cd formal/ln/LnProof && \ lake build LnProof.LnYulRuntime LnProof.LnYulProof + +# --- exp --- +./formal/yul/generate_from_forge.sh \ + exp \ + src/wrappers/ExpWrapper.sol:ExpWrapper \ + formal/exp/ExpProof/ExpProof/ExpYul.lean \ + 0.8.34 + +cd formal/exp/ExpProof && \ + lake build ExpProof.ExpYulRuntime ExpProof.ExpYulProof && \ + lake build ExpProof.Floor.CertDefsV Common.Foundation.KroneckerShift && \ + lake env lean GenExpVLit.lean && \ + lake build ``` diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean index afef04a19..8fb497757 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean @@ -22,7 +22,7 @@ cleared scale `2^1193` and `odNumVPoly` accumulates `Od` to `2^1042`; `t·Od` (l numerator/denominator are degree 10. The cut is the standard `Common.Exp.capUB_of_partial`/`capLB` shape at Taylor depth `K = 27`, nudging -the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹²⁰)`, `yLB/wLB = ê_v·(1 − 2⁻¹²⁶)`); the +the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹³⁰)`, `yLB/wLB = ê_v·(1 − 2⁻¹³⁰)`); the verified envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.057` ulp is far inside those margins. -/ From 374cc75097e1d4766e5be25ca9969b00c8128c0b Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 19:28:09 +0200 Subject: [PATCH 089/149] Strengthen exp clamp boundary proof Prove the exact below-clamp target boundary using concrete exponential cap certificates and carry the stricter E < 1 obligation through the floor proof interfaces. Co-Authored-By: Codex --- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 2 +- .../exp/ExpProof/ExpProof/Floor/Public.lean | 2 +- .../ExpProof/ExpProof/Floor/PublicUncond.lean | 4 +- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 134 +++++++++++++----- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 4 +- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 6 +- formal/exp/ExpProof/ExpProof/Theorems.lean | 8 +- 7 files changed, 114 insertions(+), 46 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index a8230fe45..6bd29b9de 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -77,7 +77,7 @@ structure RuntimeR0Bound : Prop where expRayToWadTarget (int256 x) * (2 ^ s : Real) < (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 + (2 ^ s : Real) /-- Below the clamp boundary `E < 1` (carried through verbatim). -/ - belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 2 + belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 1 /-- **The plumbing reduction.** `RuntimeR0Bound` discharges `RuntimeAccumBound`: the never-over and deficit inequalities transport across the closing shift `2^s > 0`. -/ diff --git a/formal/exp/ExpProof/ExpProof/Floor/Public.lean b/formal/exp/ExpProof/ExpProof/Floor/Public.lean index cce12d4c4..2d5ed9b5f 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Public.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Public.lean @@ -72,7 +72,7 @@ theorem run_exp_ray_to_wad_evm_floorOrOneLess (H' : RuntimeAccumBound) (x : Nat) rw [h0, hi0]; exact floorOrOneLess_zero · rw [int256_expTree_region_ne_zero hx hC hC0 hz] exact floorOrOneLessBracket_region H' hx hC hC0 - · -- below/at the clamp boundary: result is 0, E < 2 + · -- below/at the clamp boundary: result is 0, E < 1 push_neg at hC have hle : int256 (u256 x) ≤ int256 (u256 Cmask) := by rw [u256_of_lt hx, u256_of_lt Cmask_lt]; exact hC diff --git a/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean b/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean index 0726f31c7..029a48d18 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean @@ -6,7 +6,7 @@ import ExpProof.Floor.R0BoundHolds The global floor-or-one-less and one-unit underestimation brackets consume only the never-over/deficit/below-clamp facts (`accumReal_over`, `accumReal_under`, -`belowC_target_lt_two`). They become hypothesis-free here. +`belowC_target_lt_one`). They become hypothesis-free here. -/ namespace ExpYul @@ -55,7 +55,7 @@ theorem run_exp_ray_to_wad_evm_floorOrOneLess_uncond (x : Nat) (hx : x < 2 ^ 256 have := Real.exp_pos ((int256 x : Real) / (RAY : Real)) positivity exact hpos - · have := belowC_target_lt_two hle' + · have := belowC_target_lt_one hle' rw [Int.cast_zero]; linarith [this] /-- **One-unit underestimation bound (global).** `⌊E⌋ − 1 ≤ r`. -/ diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index f92090c31..6c2e79159 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -424,45 +424,113 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : /-! ## The below-clamp target bound (`RuntimeR0Bound.belowC`) -/ open ExpRealSpec +open Common.Exp Common.RealExpBridge open Real noncomputable section -/-- **Below the clamp boundary the target is under two output units.** For any word `x` whose signed -value is at or below the 0/1 clamp boundary `Cmask`, `E = 10¹⁸·exp(int256 x / 10²⁷) < 2`. -/ -theorem belowC_target_lt_two {x : Nat} (hxle : int256 x ≤ int256 Cmask) : - expRayToWadTarget (int256 x) < 2 := by +/-- Absolute value of the signed clamp boundary. -/ +private abbrev CmaskAbs : Nat := 41446531673892822312323846185 + +/-- A lower cap certifying `10¹⁸ < exp(|Cmask| / 10²⁷)`. -/ +private theorem exp_CmaskAbs_capLB : capLB CmaskAbs (10 ^ 27) (10 ^ 28 + 1) (10 ^ 10) := by + refine ⟨129, ?_⟩ + unfold CmaskAbs + decide +kernel + +/-- An upper cap certifying `exp((|Cmask| - 1) / 10²⁷) < 10¹⁸`. -/ +private theorem exp_CmaskAbs_pred_capUB : capUB (CmaskAbs - 1) (10 ^ 27) (10 ^ 28 - 1) (10 ^ 10) := by + refine capUB_of_partial (by norm_num) (K := 129) ?_ ?_ + · unfold CmaskAbs + norm_num + · unfold CmaskAbs + decide +kernel + +private theorem exp_CmaskAbs_gt_WAD : + (WAD : Real) < Real.exp ((CmaskAbs : Real) / (RAY : Real)) := by + have hcap := le_exp_of_capLB (p := CmaskAbs) (q := 10 ^ 27) + (y := 10 ^ 28 + 1) (w := 10 ^ 10) (by norm_num) (by norm_num) exp_CmaskAbs_capLB + have htarget : (WAD : Real) < ((10 ^ 28 + 1 : Nat) : Real) / ((10 ^ 10 : Nat) : Real) := by + unfold WAD + norm_num + have h := lt_of_lt_of_le htarget hcap + simpa [RAY] using h + +private theorem exp_CmaskAbs_pred_lt_WAD : + Real.exp (((CmaskAbs - 1 : Nat) : Real) / (RAY : Real)) < (WAD : Real) := by + have hcap := exp_le_of_capUB (p := CmaskAbs - 1) (q := 10 ^ 27) + (y := 10 ^ 28 - 1) (w := 10 ^ 10) (by norm_num) (by norm_num) exp_CmaskAbs_pred_capUB + have htarget : ((10 ^ 28 - 1 : Nat) : Real) / ((10 ^ 10 : Nat) : Real) < (WAD : Real) := by + unfold WAD + norm_num + have h := lt_of_le_of_lt hcap htarget + simpa [RAY] using h + +/-- At `Cmask`, the real target is below one output unit. -/ +theorem expRayToWadTarget_Cmask_lt_one : expRayToWadTarget (int256 Cmask) < 1 := by + have hCm : int256 Cmask = - (CmaskAbs : Int) := by + rw [int256_Cmask] + norm_num [CmaskAbs] + have hgt := exp_CmaskAbs_gt_WAD unfold expRayToWadTarget - have hCm : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - rw [hCm] at hxle - have hRAY : (RAY : Real) = 10 ^ 27 := by unfold RAY; norm_num - have hWAD : (WAD : Real) = 10 ^ 18 := by unfold WAD; norm_num - have hxR : (int256 x : Real) ≤ -41446531673892822312323846185 := by exact_mod_cast hxle - have harg : (int256 x : Real) / (RAY : Real) ≤ -41 := by - rw [hRAY, div_le_iff₀ (by norm_num : (0:Real) < 10 ^ 27)] - nlinarith [hxR] - have hmono : Real.exp ((int256 x : Real) / (RAY : Real)) ≤ Real.exp (-41) := - Real.exp_le_exp.mpr harg - have hexp41 : (5 * 10 ^ 17 : ℝ) < (Real.exp 1) ^ 41 := by - have h2 : (5 * 10 ^ 17 : ℝ) < (2.7182818283 : ℝ) ^ 41 := by norm_num - calc (5 * 10 ^ 17 : ℝ) < (2.7182818283 : ℝ) ^ 41 := h2 - _ < (Real.exp 1) ^ 41 := by gcongr; exact Real.exp_one_gt_d9 - have hen : Real.exp (-41) = ((Real.exp 1) ^ 41)⁻¹ := by - rw [show (-41 : ℝ) = -((41 : ℕ) * (1 : ℝ)) by push_cast; ring, Real.exp_neg, Real.exp_nat_mul] - have hp : (0 : ℝ) < (Real.exp 1) ^ 41 := by positivity - have hexpneg41 : Real.exp (-41) < 2 / 10 ^ 18 := by - rw [hen, inv_lt_iff_one_lt_mul₀ hp, div_mul_eq_mul_div, lt_div_iff₀ (by norm_num : (0:ℝ) < 10 ^ 18)] - nlinarith [hexp41] - rw [hWAD] - calc (10 ^ 18 : ℝ) * Real.exp ((int256 x : Real) / (RAY : Real)) - ≤ 10 ^ 18 * Real.exp (-41) := by - nlinarith [hmono, Real.exp_pos ((int256 x : Real) / (RAY : Real))] - _ < 10 ^ 18 * (2 / 10 ^ 18) := by nlinarith [hexpneg41] - _ = 2 := by norm_num - -/-- info: 'ExpYul.belowC_target_lt_two' depends on axioms: [propext, Classical.choice, Quot.sound] -/ + rw [hCm] + simp only [Int.cast_neg, Int.cast_natCast] + rw [neg_div, Real.exp_neg, ← div_eq_mul_inv] + rw [div_lt_iff₀ (Real.exp_pos ((CmaskAbs : Real) / (RAY : Real)))] + simpa using hgt + +/-- Just above `Cmask`, the real target is above one output unit. -/ +theorem one_lt_expRayToWadTarget_Cmask_succ : 1 < expRayToWadTarget (int256 Cmask + 1) := by + have hCm : int256 Cmask = - (CmaskAbs : Int) := by + rw [int256_Cmask] + norm_num [CmaskAbs] + have hpred : int256 Cmask + 1 = - ((CmaskAbs - 1 : Nat) : Int) := by + rw [hCm] + norm_num [CmaskAbs] + have hlt := exp_CmaskAbs_pred_lt_WAD + unfold expRayToWadTarget + rw [hpred] + simp only [Int.cast_neg, Int.cast_natCast] + rw [neg_div, Real.exp_neg, ← div_eq_mul_inv] + rw [lt_div_iff₀ (Real.exp_pos (((CmaskAbs - 1 : Nat) : Real) / (RAY : Real)))] + simpa using hlt + +/-- The real target is monotone in the signed input. -/ +theorem expRayToWadTarget_mono {a b : Int} (h : a ≤ b) : + expRayToWadTarget a ≤ expRayToWadTarget b := by + unfold expRayToWadTarget + have hRAY : (0 : Real) < (RAY : Real) := by + unfold RAY + norm_num + have hargs : (a : Real) / (RAY : Real) ≤ (b : Real) / (RAY : Real) := by + rw [div_le_div_iff_of_pos_right hRAY] + exact_mod_cast h + exact mul_le_mul_of_nonneg_left (Real.exp_le_exp.mpr hargs) (by unfold WAD; norm_num) + +/-- `Cmask` is the exact signed boundary where the real target crosses one output unit. -/ +theorem expRayToWadTarget_lt_one_iff (z : Int) : + expRayToWadTarget z < 1 ↔ z ≤ int256 Cmask := by + constructor + · intro hz + by_contra hnot + push_neg at hnot + have hsucc : int256 Cmask + 1 ≤ z := by omega + have hmono := expRayToWadTarget_mono hsucc + have h1 := one_lt_expRayToWadTarget_Cmask_succ + linarith + · intro hz + have hmono := expRayToWadTarget_mono hz + have hlt := expRayToWadTarget_Cmask_lt_one + linarith + +/-- Below the clamp boundary the target is under one output unit. -/ +theorem belowC_target_lt_one {x : Nat} (hxle : int256 x ≤ int256 Cmask) : + expRayToWadTarget (int256 x) < 1 := + (expRayToWadTarget_lt_one_iff (int256 x)).2 hxle + +/-- info: 'ExpYul.belowC_target_lt_one' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms belowC_target_lt_two +#print axioms belowC_target_lt_one end diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index edc6a8868..2c1f0b318 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -6,13 +6,13 @@ import ExpProof.Floor.R0ExpUnder # Discharging the `RuntimeR0Bound` fields The per-point `r0`-vs-`exp` brackets (`r0_real_over_within`, `r0_real_under_within`) and the -below-clamp bound (`belowC_target_lt_two`) discharge `RuntimeAccumBound` unconditionally and +below-clamp bound (`belowC_target_lt_one`) discharge `RuntimeAccumBound` unconditionally and axiom-clean, via the octave fold `E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the closing shift; `k ≤ 63` so `s ≥ 63`). * `over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` and `WAD·7201434073703092789/10000000000000000000 ≤ MARGIN`; * `under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 13/2` and `(13/2)·WAD + MARGIN < 2⁶³ ≤ 2^s`; -* `belowC` ⟸ `belowC_target_lt_two`. +* `belowC` ⟸ `belowC_target_lt_one`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. -/ diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index 95e7a3562..221c0b904 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -137,9 +137,9 @@ structure RuntimeAccumBound : Prop where under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → expRayToWadTarget (int256 x) < accumReal x + 1 /-- Below the clamp boundary the target is below one output unit (`E < 1`), so the clamped result - `0` is the floor. `Cmask = ⌊−18·ln10·10²⁷⌋` is the exact 0/1 boundary; `x ≤ Cmask` gives - `x/10²⁷ ≤ −18·ln10`, hence `E = 10¹⁸·exp(x/10²⁷) ≤ 1`. -/ - belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 2 + `0` is the floor. `Cmask` is the exact 0/1 boundary: the target is still strictly below one at + `Cmask` and strictly above one at `Cmask + 1`. -/ + belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 1 /-! ## The region floor brackets, given `RuntimeAccumBound` -/ diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 9c95cb55f..c88134e94 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -178,7 +178,7 @@ The following `RuntimeR0Bound` ingredients are proved directly and axiom-clean: * `evTree_bracket` / `odTree_bracket` — the **gap-2 Horner-truncation bridge**: the runtime even/odd accumulators bracket the exact integer polynomials `evNumV`/`odNumV` (in `v = vTree x`) within `2` units at the cleared scales `2^553`/`2^530`; -* `belowC_target_lt_two` — the `RuntimeR0Bound.belowC` field (below the clamp boundary `E < 2`). -/ +* `belowC_target_lt_one` — the `RuntimeR0Bound.belowC` field (below the clamp boundary `E < 1`). -/ example {x : Nat} (hx : x < 2 ^ 256) (hC : FormalYul.Preservation.int256 Cmask < FormalYul.Preservation.int256 x) (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : @@ -198,9 +198,9 @@ example {x : Nat} (hx : x < 2 ^ 256) #guard_msgs in #print axioms odTree_bracket -/-- info: 'ExpYul.belowC_target_lt_two' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +/-- info: 'ExpYul.belowC_target_lt_one' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms belowC_target_lt_two +#print axioms belowC_target_lt_one /-! ## Hypothesis-free global floor brackets @@ -208,7 +208,7 @@ The never-over (`r0_real_over_within`) and deficit (`r0_real_under_within`) per- brackets, folded onto the target through the closing-shift octave fold, discharge the accumulator's never-over (`accumReal_over`) and deficit (`accumReal_under`) fields unconditionally and axiom-clean. The global floor-or-one-less and one-unit underestimation brackets consume only those plus the -below-clamp `belowC_target_lt_two`, so they hold with no analytic hypothesis. -/ +below-clamp `belowC_target_lt_one`, so they hold with no analytic hypothesis. -/ /-- Global floor-or-one-less bracket, with no analytic hypothesis. -/ example (x : Nat) (hx : x < 2 ^ 256) From c23a4c14ba8bb0855fa0c60b11294f42086f8593 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 1 Jul 2026 23:57:22 +0200 Subject: [PATCH 090/149] Align the Exp.sol error-budget comment with the proofs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct the closing-shift range to the proven 126 - k ∈ [63, 187] (the supported edge is k = 63). Restate the over-side reduced-argument term as the proof's one-sided constant-grid envelope: the Q128 floor of t only pushes e downward and is budgeted on the under side, so the over side is the K27/LN2 grid residue enveloped at 2⁻¹³³. Cite the signed-word dividend bound 2²⁵⁵ for the closing sdiv, bound the k⋅ln2 grid error by 2⁻²²⁹, and restate the monotonicity error span in one frame (grid units, in which the band is k-independent). Document in Ln.sol that the exp round trip consumes lnWadToRay's error envelope and is re-verified by the exp formal check on changes to that file. Co-Authored-By: Claude Fable 5 --- src/vendor/Exp.sol | 25 +++++++++++++++---------- src/vendor/Ln.sol | 4 +++- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index ed7ee35d1..230ce39c0 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -48,7 +48,8 @@ library Exp { /// Ev Horner up the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) /// Od Horner up the staircase Q105 → Q102 → Q93 → Q94 → Q87 /// Ev, Od, t⋅Od, and the numerator/denominator: Q87 (the basis the closing quotient shares) - /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend, numerator << 126, < 2²⁵⁶) + /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend, numerator << 126, stays + /// below 2²⁵⁵: a nonnegative signed word) /// output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in /// @@ -61,9 +62,11 @@ library Exp { /// truncation barely perturbs e; this jitter (the dominant term) stays ≤ 0.6207065163. /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): /// ≤ 0.0883883477 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). - /// reduced-argument gap: ln2 is carried at Q235, so the k⋅ln2 under-subtraction is - /// ~2⁻²³⁵ (negligible); the residual Q128 truncation of t lifts e by ≤ 0.0110485435 - /// (its supremum is √2/128). + /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction + /// is budgeted on the under side); the over side is the K27/LN2 constant-grid + /// residue (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes + /// one-sidedly at 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 + /// (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer /// strictly above 2⁶³⋅S: 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1 = 720143407370309279 (worth ≈ S ulp @@ -88,11 +91,13 @@ library Exp { /// would need either round-to-nearest Horner stages (more gas and code) or a number-theoretic /// bound on the fractional part of E, so the margin rests here. /// - /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, a relative - /// gain that exceeds the entire error span above (≤ Δ⋅2⁻¹²⁶ ≈ 8.5⋅10⁻³⁹ relative - /// at k = 63, and ∝ 2ᵏ below it) and its per-step variation — including the margin's doubling - /// at each octave boundary (≤ margin⋅2ᵏ⁻¹²⁶ ≈ 8.5⋅10⁻³⁹ relative) — by more than nine orders of - /// magnitude, so the pre-floor accumulator strictly increases at every step and its floor + /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves + /// the pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The + /// error terms above confine the accumulator to a band of width 10¹⁸⋅(Δ + 13/2) ≈ + /// 7.2⋅10¹⁸ grid units just below E's grid image at every octave (in grid units the band + /// is k-independent; an octave seam rescales E and the band together), so the per-step + /// gain exceeds any adverse swing within the band by more than nine orders of magnitude, + /// and the pre-floor accumulator strictly increases at every step; its floor /// is non-decreasing. The zeroing clamp and the +1 pin preserve order: below C the result /// is 0 while just above it ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket /// the pinned scale-point value. @@ -144,7 +149,7 @@ library Exp { // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` - // which folds in the 2ᵏ octave scaling (126 - k ∈ [64, 188]). + // which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 187]). r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x9fe769d0fa58e9f)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x diff --git a/src/vendor/Ln.sol b/src/vendor/Ln.sol index e999b0143..c4a3062e9 100644 --- a/src/vendor/Ln.sol +++ b/src/vendor/Ln.sol @@ -8,7 +8,9 @@ library Ln { /// returns either ⌊L⌋ or ⌊L⌋ - 1; it never overestimates. `lnWadToRay(10**18) == 0` /// exactly, and the result is negative iff `x < 10**18`. The maximum error is less than /// 1.6986ulp. `lnWadToRay` is monotonic; x₁ < x₂ → lnWadToRay(x₁) ≤ - /// lnWadToRay(x₂). Reverts with `Panic(18)` when `x <= 0`. + /// lnWadToRay(x₂). Reverts with `Panic(18)` when `x <= 0`. The central-octave round trip + /// documented on `Exp.expRayToWad` consumes this error envelope; the exp formal check + /// re-verifies that round trip on any change to this file. function lnWadToRay(int256 x) internal pure returns (int256 r) { // Equivalent pseudocode; fixed-point truncations are accounted for below: // require(x > 0); From acaef4863988f5294e4d9b1d96e41f2a67db78d3 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 1 Jul 2026 23:57:35 +0200 Subject: [PATCH 091/149] Cover the exp edges, the 1-ulp witness, and oracle-free fuzz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the octave-boundary monotonicity loop to the k = 64 seam, which exercises the largest supported input expRayToWad(_TOO_BIG - 1). Assert the exact values at the clamp's live side (_ZERO_MAX + 1 returns 1) and at the scale point's neighbors (x = ±1, bracketing the +1 pin). Add a deterministic witness that the 1-ulp underestimate is achieved (x = 44e27 + 1 returns floor(E) - 1), a floor bracket at the supported edge, and an oracle-free fuzz test asserting never-negative and adjacent monotonicity across the supported domain, including octave interiors and the clamp seam. Expected values derived with mpmath at 80 digits. Co-Authored-By: Claude Fable 5 --- test/0.8.34/Exp.t.sol | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 386694c86..7f8265252 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -22,6 +22,14 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(0), 1e18, "expRayToWad(0) != 1e18"); } + /// The +1 pin at x = 0 sits between its neighbors: E(-1) and E(1) straddle 10**18 by ~1e-9 + /// ulp, far above the accumulator deficit, so both neighbors floor exactly and bracket the + /// pinned value. + function testExpRayToWadScalePointNeighbors() external pure { + assertEq(Exp.expRayToWad(-1), 1e18 - 1, "expRayToWad(-1) != 1e18 - 1"); + assertEq(Exp.expRayToWad(1), 1e18, "expRayToWad(1) != 1e18"); + } + function testExpRayToWadOverRangeReverts() external { vm.expectRevert(stdError.arithmeticError); this.expRayToWadExternal(_TOO_BIG); @@ -35,6 +43,8 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(-50e27), 0, "deep negative not zero"); assertEq(Exp.expRayToWad(-1e40), 0, "reduction-overflow region not zero"); assertEq(Exp.expRayToWad(type(int256).min), 0, "int256.min not zero"); + // First input past the clamp: E - 1 ~= 3.2e-28 (mpmath, 80 digits), so floor(E) = 1. + assertEq(Exp.expRayToWad(_ZERO_MAX + 1), 1, "first live input not one"); } /// Round trip against `Ln` on the central octave: exactly off-by-one, and exact at the scale @@ -59,7 +69,7 @@ contract ExpTest is Test { /// Monotonicity is tightest where the octave count increments and the margin doubles. Check /// every octave boundary in the supported range deterministically. function testExpRayToWadOctaveBoundaryMonotone() external pure { - for (int256 k = -60; k <= 63; ++k) { + for (int256 k = -60; k <= 64; ++k) { int256 xb = _octaveStart(k); for (int256 x = xb - 2; x <= xb + 1; ++x) { if (x + 1 >= _TOO_BIG) continue; @@ -90,4 +100,31 @@ contract ExpTest is Test { assertGe(r, floors[i] - 1, "below floor minus one"); } } + + /// The largest supported input, one below the revert threshold. floor(E) computed with + /// mpmath at 80 digits; frac(E) ~= 0.74, comfortably inside the k = 63 deficit envelope. + function testExpRayToWadSupportedEdge() external pure { + int256 r = Exp.expRayToWad(_TOO_BIG - 1); + int256 floorE = 13043817825332782212349571798501714341; + assertLe(r, floorE, "overestimates exp"); + assertGe(r, floorE - 1, "below floor minus one"); + } + + /// The 1-ulp underestimate is achieved: the least x >= 44e27 whose result is floor(E) - 1. + /// frac(E) ~= 0.1605 (mpmath, 80 digits) sits below the accumulated deficit at k = 63, so + /// the floored accumulator lands one under the exact floor. + function testExpRayToWadUnderestimateByOneWitness() external pure { + int256 x = 44000000000000000000000000001; + int256 floorE = 12851600114359308275809299644994699372; + assertEq(Exp.expRayToWad(x), floorE - 1, "not the 1-ulp underestimate"); + } + + /// Never negative and monotone at every adjacent pair; oracle-free, so it covers octave + /// interiors and the clamp seam without an external reference. + function testFuzzExpRayToWadMonotoneNonNegative(int256 x) external pure { + x = bound(x, _ZERO_MAX - 1e27, _TOO_BIG - 2); + int256 r = Exp.expRayToWad(x); + assertGe(r, 0, "negative result"); + assertGe(Exp.expRayToWad(x + 1), r, "adjacent monotonicity"); + } } From 73ae66e1a4e10f6267d308b0b3c28106b669100a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Wed, 1 Jul 2026 23:57:35 +0200 Subject: [PATCH 092/149] Re-run the exp proof on all its inputs; share the LnProof pipeline Trigger exp-formal.yml on src/utils/Panic.sol (compiled into ExpWrapper's Yul, including the proven revert path) and every formal workflow on lib/EVMYulLean and .gitmodules (a submodule bump changes the EVM model under the proofs). Factor the LnProof build steps duplicated between ln-formal.yml and exp-formal.yml into the composite action .github/actions/build-ln-proof, restoring the full ProofWidgets-workaround rationale in the shared copy. Complete formal/README.md's ln build block (cert generation and the full package build) and gate the exp block on it: ExpProof requires a built LnProof for the round trip. Co-Authored-By: Claude Fable 5 --- .github/actions/build-ln-proof/action.yml | 47 +++++++++++++++++++++++ .github/workflows/cbrt-formal.yml | 4 ++ .github/workflows/cbrt512-formal.yml | 4 ++ .github/workflows/exp-formal.yml | 38 ++++-------------- .github/workflows/ln-formal.yml | 38 +++--------------- .github/workflows/sqrt-formal.yml | 4 ++ .github/workflows/sqrt512-formal.yml | 4 ++ formal/README.md | 15 ++++++-- 8 files changed, 87 insertions(+), 67 deletions(-) create mode 100644 .github/actions/build-ln-proof/action.yml diff --git a/.github/actions/build-ln-proof/action.yml b/.github/actions/build-ln-proof/action.yml new file mode 100644 index 000000000..db77ff554 --- /dev/null +++ b/.github/actions/build-ln-proof/action.yml @@ -0,0 +1,47 @@ +name: Build LnProof +description: >- + Generate the LnWrapper EVMYulLean artifacts and certificate literals, then + build the LnProof Lean package. Requires Foundry, solc 0.8.34, the pinned + Lean toolchain, and a built formal/yul importer. + +runs: + using: composite + steps: + - name: Generate EVMYulLean artifacts from compiled LnWrapper Yul IR + shell: bash + run: | + ./formal/yul/generate_from_forge.sh \ + ln \ + src/wrappers/LnWrapper.sol:LnWrapper \ + formal/ln/LnProof/LnProof/LnYul.lean \ + 0.8.34 + + - name: Fetch Ln proof dependency cache + shell: bash + working-directory: formal/ln/LnProof + run: | + # Mathlib's `cache get` fetches the ProofWidgets cloud release, then + # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch + # the release and ensure those directories exist before it runs. + lake build proofwidgets:release + mkdir -p \ + .lake/packages/proofwidgets/.lake/build/lib \ + .lake/packages/proofwidgets/.lake/build/ir + lake exe cache get + + - name: Generate Ln certificate artifacts + shell: bash + working-directory: formal/ln/LnProof + run: | + lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts + lake env lean GenFloorCertLit.lean + lake build LnProof.Cert.FloorCertLit + lake env lean GenCover.lean + lake env lean GenErr1.lean + lake build LnProof.Error.Core + lake env lean GenErrLit.lean + + - name: Build Ln proof package + shell: bash + working-directory: formal/ln/LnProof + run: lake build diff --git a/.github/workflows/cbrt-formal.yml b/.github/workflows/cbrt-formal.yml index d9e4dcfb1..6499be78d 100644 --- a/.github/workflows/cbrt-formal.yml +++ b/.github/workflows/cbrt-formal.yml @@ -12,6 +12,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/cbrt-formal.yml pull_request: paths: @@ -22,6 +24,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/cbrt-formal.yml jobs: diff --git a/.github/workflows/cbrt512-formal.yml b/.github/workflows/cbrt512-formal.yml index dd2e436ca..f14f8521a 100644 --- a/.github/workflows/cbrt512-formal.yml +++ b/.github/workflows/cbrt512-formal.yml @@ -19,6 +19,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/cbrt512-formal.yml pull_request: paths: @@ -36,6 +38,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/cbrt512-formal.yml jobs: diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index d4eca1ff9..061e8f628 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -5,6 +5,7 @@ on: branches: - master paths: + - src/utils/Panic.sol - src/vendor/Exp.sol - src/vendor/Ln.sol - src/wrappers/ExpWrapper.sol @@ -15,9 +16,12 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/exp-formal.yml pull_request: paths: + - src/utils/Panic.sol - src/vendor/Exp.sol - src/vendor/Ln.sol - src/wrappers/ExpWrapper.sol @@ -28,6 +32,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/exp-formal.yml jobs: @@ -93,38 +99,8 @@ jobs: formal/exp/ExpProof/ExpProof/ExpYul.lean \ 0.8.34 - - name: Generate EVMYulLean artifacts from compiled LnWrapper Yul IR - run: | - ./formal/yul/generate_from_forge.sh \ - ln \ - src/wrappers/LnWrapper.sol:LnWrapper \ - formal/ln/LnProof/LnProof/LnYul.lean \ - 0.8.34 - - - name: Fetch ln proof dependency cache - working-directory: formal/ln/LnProof - run: | - # ProofWidgets release directories must exist for `lake exe cache get`. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get - - - name: Generate ln Lean certificate artifacts - working-directory: formal/ln/LnProof - run: | - lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts - lake env lean GenFloorCertLit.lean - lake build LnProof.Cert.FloorCertLit - lake env lean GenCover.lean - lake env lean GenErr1.lean - lake build LnProof.Error.Core - lake env lean GenErrLit.lean - - name: Build Ln proof dependency - working-directory: formal/ln/LnProof - run: lake build + uses: ./.github/actions/build-ln-proof - name: Fetch proof dependency cache working-directory: formal/exp/ExpProof diff --git a/.github/workflows/ln-formal.yml b/.github/workflows/ln-formal.yml index 6aedc488a..bf89292a3 100644 --- a/.github/workflows/ln-formal.yml +++ b/.github/workflows/ln-formal.yml @@ -12,6 +12,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/ln-formal.yml pull_request: paths: @@ -22,6 +24,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/ln-formal.yml jobs: @@ -78,37 +82,5 @@ jobs: working-directory: formal/yul run: lake build FormalYul.Preservation yul_importer - - name: Generate EVMYulLean artifacts from compiled LnWrapper Yul IR - run: | - ./formal/yul/generate_from_forge.sh \ - ln \ - src/wrappers/LnWrapper.sol:LnWrapper \ - formal/ln/LnProof/LnProof/LnYul.lean \ - 0.8.34 - - - name: Fetch proof dependency cache - working-directory: formal/ln/LnProof - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get - - - name: Generate Lean certificate artifacts - working-directory: formal/ln/LnProof - run: | - lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts - lake env lean GenFloorCertLit.lean - lake build LnProof.Cert.FloorCertLit - lake env lean GenCover.lean - lake env lean GenErr1.lean - lake build LnProof.Error.Core - lake env lean GenErrLit.lean - - name: Build Ln proof package - working-directory: formal/ln/LnProof - run: lake build + uses: ./.github/actions/build-ln-proof diff --git a/.github/workflows/sqrt-formal.yml b/.github/workflows/sqrt-formal.yml index 9f3d289c9..6a47e440e 100644 --- a/.github/workflows/sqrt-formal.yml +++ b/.github/workflows/sqrt-formal.yml @@ -12,6 +12,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/sqrt-formal.yml pull_request: paths: @@ -22,6 +24,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/sqrt-formal.yml jobs: diff --git a/.github/workflows/sqrt512-formal.yml b/.github/workflows/sqrt512-formal.yml index 571f56919..8bd9d9700 100644 --- a/.github/workflows/sqrt512-formal.yml +++ b/.github/workflows/sqrt512-formal.yml @@ -19,6 +19,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/sqrt512-formal.yml pull_request: paths: @@ -36,6 +38,8 @@ on: - formal/yul/** - foundry.toml - remappings.txt + - .gitmodules + - lib/EVMYulLean - .github/workflows/sqrt512-formal.yml jobs: diff --git a/formal/README.md b/formal/README.md index f656fdde3..8f328154f 100644 --- a/formal/README.md +++ b/formal/README.md @@ -73,12 +73,21 @@ cd formal/cbrt/Cbrt512Proof && \ ./formal/yul/generate_from_forge.sh \ ln \ src/wrappers/LnWrapper.sol:LnWrapper \ - formal/ln/LnProof/LnProof/LnYul.lean + formal/ln/LnProof/LnProof/LnYul.lean \ + 0.8.34 cd formal/ln/LnProof && \ - lake build LnProof.LnYulRuntime LnProof.LnYulProof + lake build LnProof.LnYulRuntime LnProof.LnYulProof && \ + lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts && \ + lake env lean GenFloorCertLit.lean && \ + lake build LnProof.Cert.FloorCertLit && \ + lake env lean GenCover.lean && \ + lake env lean GenErr1.lean && \ + lake build LnProof.Error.Core && \ + lake env lean GenErrLit.lean && \ + lake build -# --- exp --- +# --- exp (requires a fully built LnProof for the round trip: run the ln block first) --- ./formal/yul/generate_from_forge.sh \ exp \ src/wrappers/ExpWrapper.sol:ExpWrapper \ From 0c7f13ae40035b3976b2503d8315f4bc5b1a9245 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 00:06:16 +0200 Subject: [PATCH 093/149] Prune the dead exp proof pathway; signpost the unconditional surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delete the unused folded-Nat-cut pathway and the superseded conditional floor brackets: Spec/Cut.lean; the conditional Floor/Public.lean theorems (the shared region helper moves to PublicUncond.lean); RuntimeAccumBound and RuntimeR0Bound with their gate-only reduction; the cut-predicate re-typings in Floor/CapsV.lean (the caps are axiom-gated directly); and the unused Spec/RealExp.lean items (H, UnderByOneWitness, floorOrOneLess_le_floor). Consolidate the triplicated int256_C0thresh into Mono/Consts.lean and give the files the direct imports the deleted chain used to supply. Theorems.lean now lists the actual public surface — both unconditional floor brackets, unconditional monotonicity, revert, scale point, tree reduction, and the round trip — and gates exactly the theorems it lists plus their discharged ingredients. Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/CapsV.lean | 36 +--- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 79 +-------- .../exp/ExpProof/ExpProof/Floor/Public.lean | 106 ----------- .../ExpProof/ExpProof/Floor/PublicUncond.lean | 29 ++- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 15 +- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 20 +-- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 13 +- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 2 +- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 74 +------- .../exp/ExpProof/ExpProof/Floor/TBound.lean | 3 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 4 + formal/exp/ExpProof/ExpProof/Mono/Octave.lean | 9 +- .../ExpProof/ExpProof/Mono/RegionMono.lean | 5 +- formal/exp/ExpProof/ExpProof/Mono/Top.lean | 4 - .../exp/ExpProof/ExpProof/Seam/RealExp.lean | 111 +----------- formal/exp/ExpProof/ExpProof/Spec/Cut.lean | 101 ----------- .../exp/ExpProof/ExpProof/Spec/RealExp.lean | 19 +- formal/exp/ExpProof/ExpProof/Theorems.lean | 166 +++++------------- 18 files changed, 140 insertions(+), 656 deletions(-) delete mode 100644 formal/exp/ExpProof/ExpProof/Floor/Public.lean delete mode 100644 formal/exp/ExpProof/ExpProof/Spec/Cut.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean index acb488999..e0cc5ad93 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean @@ -2,11 +2,11 @@ import Mathlib.Tactic.NormNum import Mathlib.Tactic.Ring import Mathlib.Tactic.Positivity import Mathlib.Algebra.Order.Floor.Defs +import Common.Foundation.ExpSum import ExpProof.Cert.ExpVUp import ExpProof.Cert.ExpVLo import ExpProof.Cert.ExpVNum import ExpProof.Cert.ExpVDenM1 -import ExpProof.Spec.Cut /-! # From cell certificates to the **v-form** reduced-argument Taylor caps @@ -17,19 +17,15 @@ nonnegativity into the two bare-argument Taylor caps the floor layer folds with implementation's exact **v-form** rational `ê_v(t) = NUM(t)/DEN(t)` (built from the even/odd Horner polynomials in `v = t²`) nudged by the dyadic margin, with `Qexp = 2^128`: -* `cutExpTaylorLeV_holds` — `CutExpTaylorLe t Qexp (yUB t) (wUB t)` (never-over `exp(t) ≤ ê_v·(1+2⁻¹³⁰)`); -* `cutRatioLeExpTaylorV_holds` — `CutRatioLeExpTaylor (yLB t) (wLB t) t Qexp` - (not-two-below `ê_v·(1−2⁻¹³⁰) ≤ exp(t)`). +* `capExpUp` — never-over `exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê_v·(1 + 2⁻¹³⁰)`; +* `capExpLo` — not-two-below `yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê_v·(1 − 2⁻¹³⁰)`. -These differ from the t-form caps only in the rational target (`ê_v` vs `ê_t`, equal as reals -but distinct integer polynomials): the runtime truncation bridge lands on `ê_v`, so the floor layer -needs the cut phrased on `ê_v`. The bridge is the depth-`K = 27` `Common.Exp.capUB_of_partial`/`capLB` -shape. +The bridge is the depth-`K = 27` `Common.Exp.capUB_of_partial`/`capLB` shape. -/ namespace ExpCertV -open Common.Poly Common.Exp ExpFloorCert +open Common.Poly Common.Exp set_option maxRecDepth 100000 @@ -185,26 +181,12 @@ theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : = 10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27 * evalPoly yLB t := by ring _ ≤ expNumI 27 t (2 ^ 128) * evalPoly wLB t := by omega -/-! ## The bare-argument v-form caps as cut predicates -/ - -/-- **Never-over Taylor cut (v-form).** For every reduced argument `t ∈ [0, H128]`, -`exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê_v(t)·(1 + 2⁻¹²⁰)`. -/ -theorem cutExpTaylorLeV_holds {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : - CutExpTaylorLe t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := - capExpUp h1 h2 - -/-- **Not-two-below Taylor cut (v-form).** For every reduced argument `t ∈ [0, H128]`, -`yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê_v(t)·(1 − 2⁻¹²⁶)`. -/ -theorem cutRatioLeExpTaylorV_holds {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : - CutRatioLeExpTaylor (evalPoly yLB t).toNat (evalPoly wLB t).toNat t.toNat Qexp := - capExpLo h1 h2 - -/-- info: 'ExpCertV.cutExpTaylorLeV_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +/-- info: 'ExpCertV.capExpUp' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms cutExpTaylorLeV_holds +#print axioms capExpUp -/-- info: 'ExpCertV.cutRatioLeExpTaylorV_holds' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +/-- info: 'ExpCertV.capExpLo' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms cutRatioLeExpTaylorV_holds +#print axioms capExpLo end ExpCertV diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index 6bd29b9de..236f8ef89 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -1,28 +1,14 @@ import ExpProof.Floor.Spec /-! -# Reducing the accumulator bound to a clean `r0`-vs-`exp` bound - -`RuntimeAccumBound` (the obligation `Floor.Public` carries) is about the real pre-floor accumulator -`accumReal x = (WAD·r0 − MARGIN) / 2^(126 − k)`. This file peels the runtime plumbing off it: using -the proven shift-argument transport (`shiftArg_bounds_of`: `int256 (WAD·r0 − MARGIN) = WAD·r0 − MARGIN` -as `Int`) and the closing-shift value (`closing_shift`: the shift word is `126 − int256 k`, -nonnegative), the never-over and deficit inequalities collapse to *octave-folded* `r0` bounds against -the target. - -Writing `s = 126 − int256 (kTree x) ≥ 0`, `WAD = 10¹⁸`, `MARGIN = 0x9fe769d0fa58e9f`, the algebra is: - -``` -accumReal x ≤ E ⟺ WAD·r0 − MARGIN ≤ E·2^s -E < accumReal x + 1 ⟺ E·2^s < WAD·r0 − MARGIN + 2^s -``` - -with `E = expRayToWadTarget x`. `RuntimeR0Bound` packages exactly those two inequalities, so a -discharge of it gives `RuntimeAccumBound.over`/`under` -directly. The analytic content of `RuntimeR0Bound` — `r0Tree x ≈ exp(x/10²⁷)·2^126/2^k` -within the `MARGIN` envelope — is the cert (`Floor.CapsV`, against `ê = NUM/DEN`) folded with the -octave `2^k` together with the reduced-argument and Horner-`sdiv` truncation envelopes; this module -performs only the (unconditional, axiom-clean) plumbing reduction. +# The runtime accumulator in closed real form + +The real pre-floor accumulator is `accumReal x = (WAD·r0 − MARGIN) / 2^(126 − k)`. This file peels +the runtime plumbing off it: using the proven shift-argument transport (`shiftArg_bounds_of`: +`int256 (WAD·r0 − MARGIN) = WAD·r0 − MARGIN` as `Int`) and the closing-shift value +(`closing_shift`: the shift word is `126 − int256 k`, nonnegative), the accumulator takes the +closed form `(WAD·(int256 r0) − MARGIN) / 2^s` with `s = 126 − int256 (kTree x)`, the form the +never-over and deficit discharges (`Floor.R0BoundHolds`) fold the octave against. -/ namespace ExpYul @@ -30,7 +16,6 @@ namespace ExpYul open FormalYul open FormalYul.Preservation open Common.Word -open ExpRealSpec noncomputable section @@ -59,54 +44,6 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) push_cast ring -/-! ## The clean octave-folded `r0` bound - -`RuntimeR0Bound` is the elementary statement the cert-fold + truncation bridge must establish: with -`s = 126 − int256 k` the closing shift, the floored accumulator brackets `E`. Phrasing it directly -on `WAD·r0 − MARGIN` vs `E·2^s` keeps it free of any `Real.exp` octave-fold bookkeeping — that -bookkeeping is internal to the eventual discharge (the `2^k` is `2^(126 − s)` here). -/ -structure RuntimeR0Bound : Prop where - /-- Never over: `WAD·r0 − MARGIN ≤ E·2^(126 − k)`. -/ - over : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 ≤ - expRayToWadTarget (int256 x) * (2 ^ s : Real) - /-- Deficit under one: `E·2^(126 − k) < WAD·r0 − MARGIN + 2^(126 − k)`. -/ - under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - ∀ s : Nat, (s : Int) = 126 - int256 (kTree x) → - expRayToWadTarget (int256 x) * (2 ^ s : Real) < - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 + (2 ^ s : Real) - /-- Below the clamp boundary `E < 1` (carried through verbatim). -/ - belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 1 - -/-- **The plumbing reduction.** `RuntimeR0Bound` discharges `RuntimeAccumBound`: the never-over and -deficit inequalities transport across the closing shift `2^s > 0`. -/ -theorem runtimeAccumBound_of_r0 (H : RuntimeR0Bound) : RuntimeAccumBound where - over := fun x hx hC hC0 => by - obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 - have hps : (0 : Real) < (2 ^ s : Real) := by positivity - have hb := H.over x hx hC hC0 s hsint - rw [hAeq, div_le_iff₀ hps] - linarith [hb] - under := fun x hx hC hC0 => by - obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 - have hps : (0 : Real) < (2 ^ s : Real) := by positivity - have hb := H.under x hx hC hC0 s hsint - -- goal `E < accumReal x + 1`; rewrite `accumReal` and clear the `/2^s` - rw [hAeq] - -- `E < arg/2^s + 1` ⟺ `E·2^s < arg + 2^s` - have key : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real) := - hb - have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) / - (2 ^ s : Real) + 1 = - (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real)) / - (2 ^ s : Real) := by - field_simp - rw [hdiv, lt_div_iff₀ hps] - linarith [key] - belowC := fun x hxle => H.belowC x hxle - end end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/Public.lean b/formal/exp/ExpProof/ExpProof/Floor/Public.lean deleted file mode 100644 index 2d5ed9b5f..000000000 --- a/formal/exp/ExpProof/ExpProof/Floor/Public.lean +++ /dev/null @@ -1,106 +0,0 @@ -import ExpProof.Floor.Spec -import ExpProof.Mono - -/-! -# Public floor-bracket theorems for the compiled runtime - -Assembling the floor brackets (`Floor.Spec`, given `RuntimeAccumBound`) and the clamp/pin shell -(`Mono.Shell`/`Mono.ShellOn`) into run-level statements about `run_exp_ray_to_wad_evm`. - -The result word `expTree x` decomposes by the clamp boundary: - -* `x = 0` — the scale point, `expTree 0 = 10¹⁸`; the brackets hold by the scale-point lemmas; -* `int256 x ≤ int256 Cmask` — below the 0/1 boundary, `expTree x = 0` and `E < 1`, so the global - bracket holds with `r = 0`; -* the meaningful region with `x ≠ 0` — `int256 (expTree x) = int256 (r1Tree x)` (the clamp is - transparent and the pin does not fire), so the `Floor.Spec` region brackets transport directly. - -Each public theorem is stated on the runtime result `r` with `run_exp_ray_to_wad_evm x = .ok r`, -and carries the single analytic obligation `RuntimeAccumBound` (the cert-fold + truncation bridge), -exactly as `run_exp_ray_to_wad_evm_mono` carries `RegionMonotonicityFacts`. --/ - -namespace ExpYul - -open FormalYul -open FormalYul.Preservation -open Common.Word -open ExpRealSpec - -noncomputable section - -set_option maxRecDepth 100000 - -/-! ## The result word equals the body on the region away from the scale point -/ - -/-- For a region input that is not the scale point, the run result is the body floor: above the -clamp boundary the clamp is transparent and the `x = 0` pin does not fire. -/ -theorem int256_expTree_region_ne_zero {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (hne : x ≠ 0) : - int256 (expTree x) = int256 (r1Tree x) := by - have hr1 : r1Tree x < 2 ^ 254 := r1Tree_range hx hC hC0 - have hmask : int256 (u256 Cmask) < int256 (u256 x) := by - rw [u256_of_lt Cmask_lt, u256_of_lt hx]; exact hC - rw [int256_expTree_of_gt hmask hr1] - have hx0 : u256 x ≠ 0 := by rw [u256_of_lt hx]; exact hne - have hr1eq : int256 (r1Tree x) = (r1Tree x : Int) := - int256_of_lt (by have : (2:Nat)^254 < 2^255 := by norm_num - omega) - rw [if_neg hx0, zero_add, hr1eq] - -/-! ## Global never-over and floor-or-one-less bracket -/ - -/-- **Global floor-or-one-less bracket.** Given the analytic accumulator bound, for every signed input strictly -below the supported threshold the runtime result `r` satisfies the 2-wide never-over bracket -`r ≤ E ∧ E < r + 2`. -/ -theorem run_exp_ray_to_wad_evm_floorOrOneLess (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) - (hC0 : int256 x < int256 C0thresh) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ FloorOrOneLessBracket (int256 x) (int256 r) := by - refine ⟨expTree x, run_exp_ray_to_wad_evm_eq_expTree x (domain_of_below_C0 hx hC0), ?_⟩ - by_cases hC : int256 Cmask < int256 x - · by_cases hz : x = 0 - · -- scale point - subst hz - have he : expTree 0 = 1000000000000000000 := by - have := run_exp_ray_to_wad_evm_zero - rw [run_exp_ray_to_wad_evm_eq_expTree 0 (domain_of_below_C0 hx hC0)] at this - exact Except.ok.inj this.symm - rw [he] - have h0 : int256 (1000000000000000000 : Nat) = (10 ^ 18 : Int) := by - rw [int256_of_lt (by norm_num)]; norm_num - have hi0 : int256 (0 : Nat) = (0 : Int) := rfl - rw [h0, hi0]; exact floorOrOneLess_zero - · rw [int256_expTree_region_ne_zero hx hC hC0 hz] - exact floorOrOneLessBracket_region H' hx hC hC0 - · -- below/at the clamp boundary: result is 0, E < 1 - push_neg at hC - have hle : int256 (u256 x) ≤ int256 (u256 Cmask) := by - rw [u256_of_lt hx, u256_of_lt Cmask_lt]; exact hC - have hle' : int256 x ≤ int256 Cmask := by - rw [u256_of_lt hx, u256_of_lt Cmask_lt] at hle; exact hle - rw [expTree_eq_zero_of_le hle] - have hz0 : int256 (0 : Nat) = 0 := rfl - rw [hz0] - refine ⟨?_, ?_⟩ - · rw [Int.cast_zero] - have hpos : (0 : Real) ≤ expRayToWadTarget (int256 x) := by - unfold expRayToWadTarget - have := Real.exp_pos ((int256 x : Real) / (RAY : Real)) - positivity - exact hpos - · have := H'.belowC x hle' - rw [Int.cast_zero]; linarith [this] - -/-! ## One-unit underestimation bound -/ - -/-- **One-unit underestimation bound (global).** Given the analytic accumulator bound, the runtime result -underestimates by at most one output unit: `⌊E⌋ − 1 ≤ r`. -/ -theorem run_exp_ray_to_wad_evm_underByAtMostOne (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) - (hC0 : int256 x < int256 C0thresh) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ UnderByAtMostOne (int256 x) (int256 r) := by - obtain ⟨r, hrun, hbr⟩ := run_exp_ray_to_wad_evm_floorOrOneLess H' x hx hC0 - exact ⟨r, hrun, floorOrOneLess_to_underByAtMostOne hbr⟩ - -end - -end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean b/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean index 029a48d18..b90bcec8b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/PublicUncond.lean @@ -1,12 +1,22 @@ -import ExpProof.Floor.Public import ExpProof.Floor.R0BoundHolds +import ExpProof.Mono /-! # Hypothesis-free global floor brackets for the compiled runtime +Assembling the floor brackets and the clamp/pin shell (`Mono.Shell`/`Mono.ShellOn`) into run-level +statements about `run_exp_ray_to_wad_evm`. The result word `expTree x` decomposes by the clamp +boundary: + +* `x = 0` — the scale point, `expTree 0 = 10¹⁸`; the brackets hold by the scale-point lemmas; +* `int256 x ≤ int256 Cmask` — below the 0/1 boundary, `expTree x = 0` and `E < 1`, so the global + bracket holds with `r = 0`; +* the meaningful region with `x ≠ 0` — `int256 (expTree x) = int256 (r1Tree x)` (the clamp is + transparent and the pin does not fire), so the region brackets transport directly. + The global floor-or-one-less and one-unit underestimation brackets consume only the never-over/deficit/below-clamp facts (`accumReal_over`, `accumReal_under`, -`belowC_target_lt_one`). They become hypothesis-free here. +`belowC_target_lt_one`); they carry no analytic hypothesis. -/ namespace ExpYul @@ -20,6 +30,21 @@ noncomputable section set_option maxRecDepth 100000 +/-- For a region input that is not the scale point, the run result is the body floor: above the +clamp boundary the clamp is transparent and the `x = 0` pin does not fire. -/ +theorem int256_expTree_region_ne_zero {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (hne : x ≠ 0) : + int256 (expTree x) = int256 (r1Tree x) := by + have hr1 : r1Tree x < 2 ^ 254 := r1Tree_range hx hC hC0 + have hmask : int256 (u256 Cmask) < int256 (u256 x) := by + rw [u256_of_lt Cmask_lt, u256_of_lt hx]; exact hC + rw [int256_expTree_of_gt hmask hr1] + have hx0 : u256 x ≠ 0 := by rw [u256_of_lt hx]; exact hne + have hr1eq : int256 (r1Tree x) = (r1Tree x : Int) := + int256_of_lt (by have : (2:Nat)^254 < 2^255 := by norm_num + omega) + rw [if_neg hx0, zero_add, hr1eq] + /-- **Global floor-or-one-less bracket.** For every signed input strictly below the supported threshold the runtime result `r` satisfies the 2-wide never-over bracket `r ≤ E ∧ E < r + 2`. -/ theorem run_exp_ray_to_wad_evm_floorOrOneLess_uncond (x : Nat) (hx : x < 2 ^ 256) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index 6c2e79159..6d711e8fa 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -1,20 +1,23 @@ import ExpProof.Floor.Fold import ExpProof.Floor.TBound import ExpProof.Mono.Quot +import ExpProof.Spec.RealExp +import Common.Foundation.ExpSum +import Common.Seam.RealExpBridge import Mathlib.Data.Complex.ExponentialBounds /-! # Discharging the runtime `r0` bound -`RuntimeR0Bound` (the single analytic obligation for the public floor brackets) brackets the Q126 quotient -`r0Tree x` against the target `E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(126 − k)`. -This file builds two ingredients of that discharge: +The public floor brackets need the Q126 quotient `r0Tree x` bracketed against the target +`E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(126 − k)`. This file builds two +ingredients of that discharge: -* the **gap-2 (Horner-truncation) bridge** for the even accumulator — the runtime `evTree x`, which +* the **Horner-truncation bridge** for the even accumulator — the runtime `evTree x`, which truncates each Horner `>>` stage, brackets the exact even polynomial `evNumV (vTree x)` (a degree-5 polynomial in `v` at the cleared scale `2^553`) within `2` units: per-stage floor losses telescope with shrinking amplification (each stage shift exceeds `126 = ⌈log₂ v⌉`); -* the self-contained **`belowC`** field — below the clamp boundary the target is under one output +* the self-contained **below-clamp bound** — below the clamp boundary the target is under one output unit — directly from a `Real.exp` rational bound. -/ @@ -421,7 +424,7 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : #guard_msgs in #print axioms odTree_bracket -/-! ## The below-clamp target bound (`RuntimeR0Bound.belowC`) -/ +/-! ## The below-clamp target bound -/ open ExpRealSpec open Common.Exp Common.RealExpBridge diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index 2c1f0b318..6102521bd 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -1,18 +1,18 @@ import ExpProof.Floor.Fold import ExpProof.Floor.R0Exp import ExpProof.Floor.R0ExpUnder +import ExpProof.Seam.RealExp /-! -# Discharging the `RuntimeR0Bound` fields +# The accumulator-vs-target brackets, discharged The per-point `r0`-vs-`exp` brackets (`r0_real_over_within`, `r0_real_under_within`) and the -below-clamp bound (`belowC_target_lt_one`) discharge `RuntimeAccumBound` unconditionally and -axiom-clean, via the octave fold `E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the -closing shift; `k ≤ 63` so `s ≥ 63`). +below-clamp bound (`belowC_target_lt_one`) establish the never-over and deficit-under-one facts +about the real pre-floor accumulator unconditionally and axiom-clean, via the octave fold +`E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the closing shift; `k ≤ 63` so `s ≥ 63`). -* `over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` and `WAD·7201434073703092789/10000000000000000000 ≤ MARGIN`; -* `under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 13/2` and `(13/2)·WAD + MARGIN < 2⁶³ ≤ 2^s`; -* `belowC` ⟸ `belowC_target_lt_one`. +* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` and `WAD·7201434073703092789/10000000000000000000 ≤ MARGIN`; +* `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 13/2` and `(13/2)·WAD + MARGIN < 2⁶³ ≤ 2^s`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. -/ @@ -28,7 +28,7 @@ noncomputable section set_option maxRecDepth 100000 -/-- The accumulator never exceeds the target on the region (`RuntimeAccumBound.over`). -/ +/-- The accumulator never exceeds the target on the region. -/ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : accumReal x ≤ expRayToWadTarget (int256 x) := by @@ -49,7 +49,7 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 rw [hwad]; nlinarith [hscaled] rw [hAeq, div_le_iff₀ hps]; linarith [hbound] -/-- The target is below the accumulator plus one on the region (`RuntimeAccumBound.under`). -/ +/-- The target is below the accumulator plus one on the region. -/ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : expRayToWadTarget (int256 x) < accumReal x + 1 := by @@ -85,7 +85,7 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 /-! ## Hypothesis-free region brackets for the global floor bounds -/ /-- **Floor-or-one-less bracket on the region.** The body result satisfies `r ≤ E ∧ E < r+2`, -discharged from the proven `accumReal_over`/`accumReal_under` (no `RuntimeAccumBound` hypothesis). -/ +discharged from the proven `accumReal_over`/`accumReal_under`. -/ theorem floorOrOneLessBracket_region_uncond {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : FloorOrOneLessBracket (int256 x) (int256 (r1Tree x)) := by diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index d6dceaf9a..b2238101e 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -10,12 +10,13 @@ import Mathlib.Analysis.SpecialFunctions.Pow.Real # The per-point `r0`-vs-`exp` bridge This module brackets the Q126 quotient `r0Tree x` against `2¹²⁶·exp(rt)` (`rt = X/RAY − k·ln2` the -reduced argument), the single content left for `RuntimeR0Bound`/`SeamR0Bound`. It chains: +reduced argument), the analytic content the floor brackets (`Floor.R0BoundHolds`) and the seam bound +(`SeamR0Bound`) consume. It chains: * the **v-truncation** `evNumV(vTree x)·2⁶⁴⁰ ≤ evalPoly evNumVPoly t < evNumV(vTree x)·2⁶⁴⁰ + 2¹¹⁹³` - (the cert polynomial in `t` uses the exact `v = t²/2¹²⁸`; the gap-2 bridge uses the truncated - `vTree x = ⌊t²/2¹²⁸⌋`; one `v`-step of the monotone Horner polynomial is below `2⁵⁵³`); -* the **gap-2 Horner-truncation bridge** (`evTree_bracket`/`odTree_bracket`, already proven); + (the cert polynomial in `t` uses the exact `v = t²/2¹²⁸`; the Horner-truncation bridge uses the + truncated `vTree x = ⌊t²/2¹²⁸⌋`; one `v`-step of the monotone Horner polynomial is below `2⁵⁵³`); +* the **Horner-truncation bridge** (`evTree_bracket`/`odTree_bracket`); * the **`sdiv` floor** `r0·den ≤ 2¹²⁶·num < (r0+1)·den`; * the **v-form cert** (`CapsV`) `exp(t/2¹²⁸) ≈ ê_v` within a dyadic margin; * the **reduced-argument bound** (`Reduce`) `|rt − t/2¹²⁸| < 2/2¹²⁸`. @@ -838,8 +839,8 @@ theorem r0_vs_certRatio_neg {x : Nat} (hx : x < 2 ^ 256) The target `E = WAD·exp(X/RAY)`. With `rt = X/RAY − k·ln2` the reduced argument, `exp(X/RAY) = exp(rt)·2^k`, so the closing-shift fold `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`. This collapses the -`RuntimeR0Bound.over`/`under` inequalities (stated against `E·2^s`, `s = 126 − k`) onto the clean -octave-independent never-over/deficit relation `r0 ≈ 2¹²⁶·exp(rt)`. -/ +never-over/deficit inequalities (stated against `E·2^s`, `s = 126 − k`) onto the clean +octave-independent relation `r0 ≈ 2¹²⁶·exp(rt)`. -/ open ExpRealSpec Real Common.RealExpBridge diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index 4859addcb..c2358c7b5 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -211,7 +211,7 @@ theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) linarith [hmul, h2wd] -- region membership of r have hCmask : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0 : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh_floc + have hC0 : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh -- L > log(1/2) = −log 2 > −1 ; X = 10^27·L > −10^27 ; r ≥ X − 2 > Cmask have hLgt : -(1 : Real) < L := by have h12 : Real.log ((1:Real)/2) < L := by diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index 221c0b904..2c1640685 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -1,6 +1,8 @@ +import Mathlib.Data.Real.Basic +import Mathlib.Tactic.Positivity +import Mathlib.Tactic.Linarith import ExpProof.Mono.RunBridge import ExpProof.Mono.RangeNonneg -import ExpProof.Seam.RealExp /-! # Floor + branch assembly: the public `Real.exp` brackets @@ -15,18 +17,11 @@ A = (WAD·r0 − MARGIN) / 2^(126 − k). ``` The two floor facts `(r : Real) ≤ A` and `A < (r : Real) + 1` (i.e. `r = ⌊A⌋`) are established here -from the `evmSar` sandwich. What is not a runtime-plumbing fact — and is collected -into the single analytic obligation `RuntimeAccumBound` below — is the relation between the -*real-valued* runtime accumulator `A` and the target `E = WAD·exp(x/RAY)`: - -* never-over `A ≤ E`, and -* deficit-under-one `E < A + 1`. - -`RuntimeAccumBound` packages exactly those, mirroring the way `Mono.RegionMonotonicityFacts`/`Mono.SeamR0Bound` -isolate the monotonicity analytic core. Given it, this file derives the public floor brackets -(chaining the `ExpRealBridge.*_of_accum` reductions); the analytic core itself -is the cert-fold + truncation bridge (the cert `Floor/Caps` against the exact rational, plus the -reduced-argument and Horner-truncation envelopes the `MARGIN` absorbs). +from the `evmSar` sandwich. The relation between the *real-valued* runtime accumulator `A` and the +target `E = WAD·exp(x/RAY)` — never-over `A ≤ E` and deficit-under-one `E < A + 1` — is not a +runtime-plumbing fact; it is discharged in `Floor.R0BoundHolds` (`accumReal_over`/`accumReal_under`: +the cert `Floor/CapsV` against the exact rational, plus the reduced-argument and Horner-truncation +envelopes the `MARGIN` absorbs). -/ namespace ExpYul @@ -34,7 +29,6 @@ namespace ExpYul open FormalYul open FormalYul.Preservation open Common.Word -open ExpRealSpec noncomputable section @@ -114,58 +108,6 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) rw [hAeq, hr1] exact hfloor -/-! ## The analytic obligation: the runtime accumulator brackets `E` - -`RuntimeAccumBound` packages the relation between the real pre-floor accumulator `accumReal x` and -the public target `E = expRayToWadTarget x` that the cert-fold + truncation bridge must establish: - -* `over` — never over: `accumReal x ≤ E` for any region input; -* `under` — deficit under one: `E < accumReal x + 1` for any region input. - -It is the floor-side analogue of `Mono.RegionMonotonicityFacts`/`Mono.SeamR0Bound`: every runtime-plumbing and -floor fact is proved directly; the public floor brackets depend on this single -analytic core (the cert against the exact rational `ê(t) = NUM/DEN` folded with the octave `2^k`, -together with the reduced-argument `(x/RAY − k·ln2)` ≈ `tTree/2¹²⁸` envelope and the Horner-`sdiv` -truncation envelope — all absorbed by the `MARGIN`). -/ -structure RuntimeAccumBound : Prop where - /-- Never over: the real pre-floor accumulator does not exceed the target. Holds for any region - input (the never-over relation `r0 ≤ exp(t)·2¹²⁶ + MARGIN/WAD` is octave-independent and - sign-symmetric). -/ - over : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - accumReal x ≤ expRayToWadTarget (int256 x) - /-- Deficit under one: the target is below the accumulator plus one. -/ - under : ∀ x : Nat, x < 2 ^ 256 → int256 Cmask < int256 x → int256 x < int256 C0thresh → - expRayToWadTarget (int256 x) < accumReal x + 1 - /-- Below the clamp boundary the target is below one output unit (`E < 1`), so the clamped result - `0` is the floor. `Cmask` is the exact 0/1 boundary: the target is still strictly below one at - `Cmask` and strictly above one at `Cmask + 1`. -/ - belowC : ∀ x : Nat, int256 x ≤ int256 Cmask → expRayToWadTarget (int256 x) < 1 - -/-! ## The region floor brackets, given `RuntimeAccumBound` -/ - -theorem int256_C0thresh_floc : int256 C0thresh = 44014845965556527147994239713 := by - unfold C0thresh int256; norm_num - -theorem int256_H_lt_C0 : (H : Int) < int256 C0thresh := by - rw [int256_C0thresh_floc]; unfold H; norm_num - -theorem int256_zero_le_Cmask : int256 Cmask < 0 := by rw [int256_Cmask]; norm_num - -/-- **Floor-or-one-less bracket on the region**, given the analytic accumulator bound: the body result -`r = int256 (r1Tree x)` satisfies `r ≤ E ∧ E < r + 2`. -/ -theorem floorOrOneLessBracket_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - FloorOrOneLessBracket (int256 x) (int256 (r1Tree x)) := by - obtain ⟨hfl, hfl1⟩ := r1Tree_floor_accum hx hC hC0 - exact ExpRealBridge.floorOrOneLessBracket_of_accum hfl hfl1 - (H'.over x hx hC hC0) (H'.under x hx hC hC0) - -/-- **One-unit underestimation bound on the region**, given the analytic accumulator bound: `⌊E⌋ − 1 ≤ r`. -/ -theorem underByAtMostOne_region {x : Nat} (H' : RuntimeAccumBound) (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - UnderByAtMostOne (int256 x) (int256 (r1Tree x)) := - ExpRealBridge.underByAtMostOne_of_floorOrOneLess (floorOrOneLessBracket_region H' hx hC hC0) - end end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean index 6ce10af9b..dc2ae90b2 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean @@ -35,8 +35,7 @@ theorem tTree_in_cert_domain {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hkblo, hkbhi⟩ := kTree_bound hx hC hC0 -- region endpoints as decimals have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44014845965556527147994239713 := by - unfold C0thresh int256; norm_num + have hC0i : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh rw [hCi] at hC rw [hC0i] at hC0 -- constants as decimals diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index ffe539ab0..b471eb1dc 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -52,4 +52,8 @@ theorem Cmask_lt : Cmask < 2 ^ 256 := by unfold Cmask norm_num +theorem int256_C0thresh : int256 C0thresh = 44014845965556527147994239713 := by + unfold C0thresh int256 + norm_num + end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean index abc64e2b3..08418ea6c 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean @@ -26,8 +26,7 @@ theorem region_x_bound {x : Nat} (hC : int256 Cmask < int256 x) -(2 ^ 96 : Int) < int256 x ∧ int256 x < 2 ^ 96 := by rw [int256_Cmask] at hC have hC0' : int256 x < 44014845965556527147994239713 := by - rw [show int256 C0thresh = 44014845965556527147994239713 from by - unfold C0thresh int256; norm_num] at hC0 + rw [int256_C0thresh] at hC0 exact hC0 constructor <;> [skip; skip] <;> simp only [show (2:Int)^96 = 79228162514264337593543950336 from by norm_num] <;> omega @@ -130,8 +129,7 @@ theorem kTree_bound {x : Nat} (hx : x < 2 ^ 256) -61 ≤ int256 (kTree x) ∧ int256 (kTree x) ≤ 63 := by obtain ⟨hlo, hhi⟩ := kTree_sandwich hx hC hC0 have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44014845965556527147994239713 := by - unfold C0thresh int256; norm_num + have hC0i : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh rw [hCi] at hC rw [hC0i] at hC0 have hcinv : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by @@ -158,8 +156,7 @@ theorem int256_tArg {x : Nat} (hx : x < 2 ^ 256) 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x - 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) := by have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44014845965556527147994239713 := by - unfold C0thresh int256; norm_num + have hC0i : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh have hxr := hC; rw [hCi] at hxr have hxr0 := hC0; rw [hC0i] at hxr0 obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 diff --git a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean index 8408b2e75..68f1407fc 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean @@ -66,13 +66,10 @@ theorem r1_step (hseamstep : SeamStep) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : /-! ## The integer-step induction -/ -theorem int256_C0thresh_loc : int256 C0thresh = 44014845965556527147994239713 := by - unfold C0thresh int256; norm_num - /-- A signed value strictly inside the region is a canonical word with that signed value. -/ theorem region_word {v : Int} (hlo : int256 Cmask < v) (hhi : v < int256 C0thresh) : uint256OfInt v < 2 ^ 256 ∧ int256 (uint256OfInt v) = v := by - have hC0 : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh_loc + have hC0 : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh have hCm : int256 Cmask = -41446531673892822312323846185 := int256_Cmask rw [hCm] at hlo; rw [hC0] at hhi refine ⟨uint256OfInt_lt v, ?_⟩ diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index 9786bbf3c..08efc28f5 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -44,10 +44,6 @@ structure RegionMonotonicityFacts : Prop where pin : ∀ x : Nat, x < 2 ^ 256 → 0 < int256 x → int256 x < int256 C0thresh → 1 + (r1Tree 0 : Int) ≤ (r1Tree x : Int) -theorem int256_C0thresh : int256 C0thresh = 44014845965556527147994239713 := by - unfold C0thresh int256 - norm_num - /-- The region monotonicity facts hold given the octave-seam step: `range`/`nonneg` are unconditional, and `mono`/`pin` reduce (via the same-octave step and the region induction) to `SeamStep`. -/ diff --git a/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean b/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean index dc9101f5d..4dabc41d4 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/RealExp.lean @@ -1,112 +1,21 @@ -import Mathlib.Analysis.SpecialFunctions.Exponential import Mathlib.Algebra.Order.Floor.Defs -import Common.Seam.RealExpBridge import ExpProof.Spec.RealExp -import ExpProof.Spec.Cut - -open scoped BigOperators /-! # `expRayToWad` real bridge -The bridge from the real-free `Nat` cuts (`ExpProof.Spec.Cut`) to the public -`Real.exp` brackets (`ExpProof.Spec.RealExp`). - -The bridge has two reductions: - -1. *Cut → real exp bound.* `Common.RealExpBridge.exp_le_of_capUB` / - `le_exp_of_capLB` turn a folded `capUB`/`capLB` directly into a `Real.exp` - bound on the cut argument. The octave-folded argument `(k·tDen + tNum)/tDen` - already equals `k·1 + tNum/tDen`, and `exp(k + s) = (e^1)^k · e^s`; but the - tie to `E = WAD·exp(x/RAY)` runs through the runtime's specific octave/argument - constants (the reduced-argument identity `x/RAY = k·ln2 + t`), which the - certificate and floor layers supply. So this reduction is exposed as the standalone - `expBound_of_*Cut` lemmas, and the connection to `E` is taken as a hypothesis. - -2. *Pre-floor accumulator → bracket.* The cut conclusions are the real - inequalities `A ≤ E` (never over) and `E < A + 1` (not two below) on the - pre-floor accumulator `A`; the runtime returns `r = ⌊A⌋` (the `Floor` layer, - after its floor proof). Given those three facts the public brackets follow by - `Int.floor` reasoning. These are the standalone, axiom-clean reduction lemmas - used by the certificate and floor layers. +The reduction from the pre-floor accumulator inequalities to the public `Real.exp` brackets +(`ExpProof.Spec.RealExp`): the never-over `A ≤ E` and not-two-below `E < A + 1` facts on the real +pre-floor accumulator `A`, together with the floor step `r = ⌊A⌋` (discharged by the `Floor` +layer), yield the public brackets by `Int.floor` reasoning. -/ namespace ExpRealBridge -open Common.Exp Common.RealExpBridge ExpFloor ExpFloorCert ExpRealSpec +open ExpRealSpec noncomputable section -/-! ## Cut To A `Real.exp` Bound On The Folded Argument - -The folded cut argument `(k·tDen + tNum)/tDen` splits as `k + tNum/tDen`, so -`exp((k·tDen + tNum)/tDen) = (exp 1)^k · exp(tNum/tDen)` — the multiplicative -octave factor `(e^a)^k` the floor layer folds against the runtime's `2^k` -(with `a = ln2` in the unfolded `ln2`-denominator form). -/ - -/-- The octave fold on the cut argument: an integer step `k` factors out -multiplicatively. -/ -theorem exp_folded_arg {tNum tDen k : Nat} (hq : 0 < tDen) : - Real.exp (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) = - (Real.exp 1) ^ k * Real.exp ((tNum : Real) / (tDen : Real)) := by - have hqne : (tDen : Real) ≠ 0 := by - have : (0 : Real) < (tDen : Real) := by exact_mod_cast hq - exact ne_of_gt this - have harg : (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) = - (k : Real) + (tNum : Real) / (tDen : Real) := by - push_cast - field_simp - rw [harg, Real.exp_add, ← Real.exp_nat_mul, mul_one] - - -/-- The never-over cut yields a real upper bound on the octave-folded -exponential: `exp((k·tDen + tNum)/tDen) ≤ yUB/wUB`. -/ -theorem expBound_of_neverOverCut {tNum tDen k yUB wUB : Nat} - (hq : 0 < tDen) (hw : 0 < wUB) - (hcut : ExpNeverOverCut tNum tDen k yUB wUB) : - Real.exp (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) ≤ (yUB : Real) / wUB := - exp_le_of_capUB hq hw hcut - -/-- The not-two-below cut yields a real lower bound on the octave-folded -exponential: `yLB/wLB ≤ exp((k·tDen + tNum)/tDen)`. -/ -theorem expBound_of_notTwoBelowCut {tNum tDen k yLB wLB : Nat} - (hq : 0 < tDen) (hw : 0 < wLB) - (hcut : ExpNotTwoBelowCut tNum tDen k yLB wLB) : - (yLB : Real) / wLB ≤ Real.exp (((k * tDen + tNum : Nat) : Real) / (tDen : Real)) := - le_exp_of_capLB hq hw hcut - -/-! ## Negative-argument reciprocal - -For `x < 0` the runtime reduces `−x` and forms `exp(x/RAY) = 1 / exp(−x/RAY)`. -The lower cap on `exp(−t)` becomes the upper bound the never-over half needs, and -vice versa; `Real.exp_neg` is the bridge. These standalone lemmas expose that -reciprocal so the floor layer can route the negative branch. -/ - -/-- `exp(−s) = 1 / exp(s)`; the reciprocal relating the two sign branches. -/ -theorem exp_neg_eq_inv (s : Real) : Real.exp (-s) = (Real.exp s)⁻¹ := - Real.exp_neg s - -/-- A lower cap on `exp(s)` is an upper bound on `exp(−s)`: if `g/v ≤ exp(s)` and -`g/v > 0` then `exp(−s) ≤ v/g`. -/ -theorem expNeg_le_of_le_exp {s : Real} {g v : Real} (hg : 0 < g) (hv : 0 < v) - (h : g / v ≤ Real.exp s) : Real.exp (-s) ≤ v / g := by - rw [exp_neg_eq_inv] - have hexp_pos : 0 < Real.exp s := Real.exp_pos s - have hgv : (0 : Real) < g / v := div_pos hg hv - rw [inv_le_comm₀ hexp_pos (by positivity)] - calc (v / g) ⁻¹ = g / v := by rw [inv_div] - _ ≤ Real.exp s := h - -/-- An upper cap on `exp(s)` is a lower bound on `exp(−s)`: if `exp(s) ≤ y/w` and -`y/w > 0` then `w/y ≤ exp(−s)`. -/ -theorem le_expNeg_of_exp_le {s : Real} {y w : Real} (hy : 0 < y) (hw : 0 < w) - (h : Real.exp s ≤ y / w) : w / y ≤ Real.exp (-s) := by - rw [exp_neg_eq_inv] - have hexp_pos : 0 < Real.exp s := Real.exp_pos s - rw [le_inv_comm₀ (by positivity) hexp_pos] - calc Real.exp s ≤ y / w := h - _ = (w / y)⁻¹ := by rw [inv_div] - /-! ## Pre-floor Accumulator To Public Brackets `A` is the real pre-floor accumulator and `r = ⌊A⌋` the runtime result (the @@ -132,16 +41,6 @@ theorem underByAtMostOne_of_floorOrOneLess {x : Int} {r : Int} (h : FloorOrOneLessBracket x r) : UnderByAtMostOne x r := floorOrOneLess_to_underByAtMostOne h -/-- **One-unit underestimation reduction, direct.** From the pre-floor accumulator facts the -1-unit lower bound follows directly. -/ -theorem underByAtMostOne_of_accum {x : Int} {r : Int} {A : Real} - (hfloor : (r : Real) ≤ A) (hfloor1 : A < (r : Real) + 1) - (hover : A ≤ expRayToWadTarget x) - (hunder : expRayToWadTarget x < A + 1) : - UnderByAtMostOne x r := - floorOrOneLess_to_underByAtMostOne - (floorOrOneLessBracket_of_accum hfloor hfloor1 hover hunder) - end end ExpRealBridge diff --git a/formal/exp/ExpProof/ExpProof/Spec/Cut.lean b/formal/exp/ExpProof/ExpProof/Spec/Cut.lean deleted file mode 100644 index cff28c0ac..000000000 --- a/formal/exp/ExpProof/ExpProof/Spec/Cut.lean +++ /dev/null @@ -1,101 +0,0 @@ -import Common.Foundation.ExpSum - -/-! -# Real-free `Nat` cut specification for `expRayToWad` - -The runtime reduces `x` to an octave count `k` and a reduced argument -`t ∈ [−ln2/2, ln2/2)`, then forms `exp(x/RAY) = 2^k · exp(t)`. The pre-floor -accumulator is `A = (WAD·r0 − MARGIN)/2^(126−k)` with `r0 = ê(t)·2^126` the -`sdiv` result; the runtime returns `⌊A⌋` (clamped). The correctness brackets -reduce to two rational comparisons on `exp(t)`: - -* a never-over cut — an upper bound `exp(t) ≤ yUB/wUB` — that, after folding the - octave `2^k` and subtracting the margin, gives `A ≤ E`; -* a not-too-low cut — a lower bound `yLB/wLB ≤ exp(t)` — that, after the same - fold, gives `E < A + 1`. - -These are encoded with `Common.Exp.capUB`/`capLB` over a common denominator. The -reduced argument is carried as a rational `t = tNum/tDen` and the octave as a -`Nat` exponent `k`; the negative-`x` branch is the reciprocal cut on `−t`. This -module only *defines* the cut predicates and the octave fold — it does not prove -they hold; the Taylor certificates prove that. No `Real`/Mathlib dependency. --/ - -namespace ExpFloor - -/-- Common denominator of the reduced exponent argument: the ray scale times the -Q99 headroom the runtime carries (mirrors the `ln` proof's `QS`). -/ -def QS : Nat := 10 ^ 27 * 2 ^ 99 - -theorem QS_pos : 0 < QS := by - unfold QS; exact Nat.mul_pos (Nat.pow_pos (by decide)) (Nat.pow_pos (by decide)) - -def WAD : Nat := 10 ^ 18 - -theorem WAD_pos : 0 < WAD := by unfold WAD; exact Nat.pow_pos (by decide) - -end ExpFloor - -namespace ExpFloorCert - -open Common.Exp ExpFloor - -/-- Upper cut on the reduced argument: `exp(tNum/tDen) ≤ yUB/wUB`, encoded as -`Common.Exp.capUB` (every exact Taylor partial sum is bounded by the target). -/ -def CutExpTaylorLe (tNum tDen yUB wUB : Nat) : Prop := capUB tNum tDen yUB wUB - -/-- Lower cut on the reduced argument: `yLB/wLB ≤ exp(tNum/tDen)`, encoded as -`Common.Exp.capLB` (one exact Taylor partial sum reaches the target). -/ -def CutRatioLeExpTaylor (yLB wLB tNum tDen : Nat) : Prop := capLB tNum tDen yLB wLB - -/-- **Never-over cut.** The reduced-argument exponential, scaled by the octave -`2^k`, stays at or below the rational `yUB/wUB`. The Taylor certificates establish -the base `CutExpTaylorLe` (an upper cap at Taylor depth `K = 27` over the cell that -contains `tNum/tDen`); folding the octave is `capUB_pow`/`capUB_mul`. The -margin/floor step that turns `2^k·exp(t) ≤ yUB/wUB` into `A ≤ E` is a bridge -hypothesis. -/ -def ExpNeverOverCut (tNum tDen k yUB wUB : Nat) : Prop := - capUB (k * tDen + tNum) tDen yUB wUB - -/-- **Not-two-below cut.** The octave-scaled reduced exponential is at or above -the rational `yLB/wLB`. The Taylor certificate establishes the base -`CutRatioLeExpTaylor` (a lower cap at Taylor depth `K = 27`); the octave fold is -`capLB_pow`/`capLB_mul`. The margin/floor step turning `2^k·exp(t) ≥ yLB/wLB` -into `E < A + 1` is a bridge hypothesis. -/ -def ExpNotTwoBelowCut (tNum tDen k yLB wLB : Nat) : Prop := - capLB (k * tDen + tNum) tDen yLB wLB - -/-! ## Octave fold - -The cut predicates are stated already-folded (`k * tDen + tNum`). The factored -form — a Taylor cap on the reduced argument plus a Taylor cap on `ln2` for the -octave factor `(e^{ln2})^k = 2^k` — composes into the folded cut via the generic -`capUB_mul`/`capUB_pow` (resp. `capLB_*`). These lemmas exhibit that composition -so the Taylor certificates can target the unfolded pieces. `ln2Num/ln2Den ≈ ln 2`. -/ - -/-- A reduced-argument upper cap together with an upper cap on the octave factor -`(e^{ln2Num/ln2Den})^k` (with `ln2Den = tDen`) folds into the never-over cut. -/ -theorem expNeverOverCut_of_fold {tNum tDen k ln2Num yT wT yOct wOct : Nat} - (hq : 0 < tDen) - (hT : CutExpTaylorLe tNum tDen yT wT) - (hOct : capUB (k * ln2Num) tDen (yOct ^ k) (wOct ^ k)) - (hln2 : ln2Num = tDen) : - ExpNeverOverCut tNum tDen k (yT * yOct ^ k) (wT * wOct ^ k) := by - unfold ExpNeverOverCut - subst hln2 - rw [Nat.add_comm] - exact capUB_mul hq hT hOct - -/-- A reduced-argument lower cap together with a lower cap on the octave factor -folds into the not-two-below cut. -/ -theorem expNotTwoBelowCut_of_fold {tNum tDen k ln2Num yT wT yOct wOct : Nat} - (hT : CutRatioLeExpTaylor yT wT tNum tDen) - (hOct : capLB (k * ln2Num) tDen (yOct ^ k) (wOct ^ k)) - (hln2 : ln2Num = tDen) : - ExpNotTwoBelowCut tNum tDen k (yT * yOct ^ k) (wT * wOct ^ k) := by - unfold ExpNotTwoBelowCut - subst hln2 - rw [Nat.add_comm] - exact capLB_mul hT hOct - -end ExpFloorCert diff --git a/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean b/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean index e3a853a09..e307f4a5d 100644 --- a/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean +++ b/formal/exp/ExpProof/ExpProof/Spec/RealExp.lean @@ -11,9 +11,8 @@ input `x` is a signed ray-scale exponent (an `int256`, transported here as an is `E = 10^18 · exp(x / 10^27)`. The global bracket is 2-wide: `r ≤ E` (never over) together with `E < r + 2` -(under by less than two output units). It pins `r` to `{⌊E⌋, ⌊E⌋ − 1}` and gives -`r ≤ ⌊E⌋`. The one-unit underestimation bound is `r ≥ ⌊E⌋ − 1`, with a separate -achieved-witness predicate for a supported input attaining `r = ⌊E⌋ − 1`. +(under by less than two output units). It pins `r` to `{⌊E⌋, ⌊E⌋ − 1}`. The +one-unit underestimation bound is `r ≥ ⌊E⌋ − 1`. These predicates are stated over abstract `r : Int`; the EVM-side modules discharge them for the runtime result. The arithmetic facts here are @@ -27,9 +26,6 @@ noncomputable section def WAD : Nat := 10 ^ 18 def RAY : Nat := 10 ^ 27 -/-- The half-octave bound `H = ⌊10²⁷·ln2/2⌋`; the core octave is `x ∈ [−H, H)`. -/ -def H : Int := 346573590279972654708616060 - /-- `E = 10^18 · exp(x / 10^27)`, the real target of `expRayToWad`. -/ def expRayToWadTarget (x : Int) : Real := (WAD : Real) * Real.exp ((x : Real) / (RAY : Real)) @@ -44,12 +40,6 @@ unit: `r ≥ ⌊E⌋ − 1`. -/ def UnderByAtMostOne (x : Int) (r : Int) : Prop := ⌊expRayToWadTarget x⌋ - 1 ≤ r -/-- **One-unit underestimation witness.** Some supported input attains the worst-case -1-unit underestimate `r = ⌊E⌋ − 1` (a `run`-level existence statement; the -predicate carries the runtime result via `result`). -/ -def UnderByOneWitness (supported : Int → Prop) (result : Int → Int) : Prop := - ∃ x : Int, supported x ∧ result x = ⌊expRayToWadTarget x⌋ - 1 - /-! ## Floor facts: turning the brackets into membership / equality -/ /-- A 2-wide never-over bracket forces `r ∈ {⌊E⌋, ⌊E⌋ − 1}`. -/ @@ -65,11 +55,6 @@ theorem floorOrOneLess_mem_floor {x r : Int} (h : FloorOrOneLessBracket x r) : have hge : ⌊E⌋ < r + 2 := by exact_mod_cast hlt2' omega -/-- The never-over half: `r ≤ ⌊E⌋`. -/ -theorem floorOrOneLess_le_floor {x r : Int} (h : FloorOrOneLessBracket x r) : - r ≤ ⌊expRayToWadTarget x⌋ := - Int.le_floor.mpr h.1 - /-- The floor-or-one-less bracket implies the one-unit underestimation bound. -/ theorem floorOrOneLess_to_underByAtMostOne {x r : Int} (h : FloorOrOneLessBracket x r) : UnderByAtMostOne x r := by diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index c88134e94..dc4f46469 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -2,10 +2,8 @@ import ExpProof.Seam.Revert import ExpProof.Seam.Value import ExpProof.Mono import ExpProof.Mono.SeamR0 -import ExpProof.Floor.Public import ExpProof.Floor.PublicUncond import ExpProof.Floor.R0BoundHolds -import ExpProof.Floor.Fold import ExpProof.Floor.R0Bound import ExpProof.Floor.RoundTrip @@ -20,20 +18,20 @@ stray `sorry` (or any new axiom) breaks the build. ## Documented properties (about the runtime) -| Property | Theorem | -|-------------------------------------------------|-----------------------------------------------| -| Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1`| `run_exp_ray_to_wad_evm_revert` | -| Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | -| Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | -| Monotone in the input (modulo the region core) | `run_exp_ray_to_wad_evm_mono` | -| `lnWadToRay` round trip | `run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if` | - -The monotonicity theorem `run_exp_ray_to_wad_evm_mono` is proved over the whole supported domain; -it takes the analytic facts of the meaningful region (`RegionMonotonicityFacts`: `r1Tree` in range, -nonnegative, nondecreasing, and the scale-point pin clearance) as a hypothesis. The clamp/pin -shell, the run-level bridge, and the octave-index / reduced-argument transports and their -monotonicity are proved without that hypothesis; the rational-quotient (`sdiv`) within-octave step -and the octave-seam compensation are represented by `RegionMonotonicityFacts`. +| Property | Theorem | +|---------------------------------------------------|--------------------------------------------------| +| Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1` | `run_exp_ray_to_wad_evm_revert` | +| Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | +| Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | +| Never over / floor-or-one-less: `r ≤ E < r + 2` | `run_exp_ray_to_wad_evm_floorOrOneLess_uncond` | +| Underestimates by at most one: `⌊E⌋ − 1 ≤ r` | `run_exp_ray_to_wad_evm_underByAtMostOne_uncond` | +| Monotone in the input | `run_exp_ray_to_wad_evm_mono_unconditional` | +| `lnWadToRay` round trip | `run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if` | + +Every property is unconditional. The monotonicity analytic core (`RegionMonotonicityFacts`, +reduced to the octave-seam `r0` doubling bound `SeamR0Bound`) is discharged by +`seamR0Bound_holds`; the floor brackets consume the discharged accumulator facts +(`accumReal_over`, `accumReal_under`, `belowC_target_lt_one`) directly. The supported-range threshold is `0x8e383a2cdfa1b74a9422d2e1`; at or above it (and below `2^255`, i.e. for any non-negative `int256` that large) the wrapper run halts with `revert`. At the scale @@ -69,44 +67,14 @@ example : run_exp_ray_to_wad_evm 0 = .ok 1000000000000000000 := #guard_msgs in #print axioms run_exp_ray_to_wad_evm_eq_tree -/-- Monotone over the whole supported domain, given the meaningful-region analytic core. -/ -example (H : RegionMonotonicityFacts) (x1 x2 : Nat) - (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) - (hle : FormalYul.Preservation.int256 x1 ≤ FormalYul.Preservation.int256 x2) - (hdom : FormalYul.Preservation.int256 x2 < FormalYul.Preservation.int256 C0thresh) : - ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ - FormalYul.Preservation.int256 r1 ≤ FormalYul.Preservation.int256 r2 := - run_exp_ray_to_wad_evm_mono H x1 x2 hx1 hx2 hle hdom - -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_mono' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms run_exp_ray_to_wad_evm_mono - -/-- Monotone over the whole supported domain, reduced to the single analytic obligation -`SeamR0Bound` (the octave-seam `r0` doubling bound). The kernel-wall floor reduction, the -`range`/`nonneg` obligations, the same-octave step, the region induction, and the scale-point pin are -proved without this hypothesis; the monotonicity theorem here depends on the seam accuracy bound -`SeamR0Bound`. -/ -example (hr0 : SeamR0Bound) (x1 x2 : Nat) - (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) - (hle : FormalYul.Preservation.int256 x1 ≤ FormalYul.Preservation.int256 x2) - (hdom : FormalYul.Preservation.int256 x2 < FormalYul.Preservation.int256 C0thresh) : - ∃ r1 r2, run_exp_ray_to_wad_evm x1 = .ok r1 ∧ run_exp_ray_to_wad_evm x2 = .ok r2 ∧ - FormalYul.Preservation.int256 r1 ≤ FormalYul.Preservation.int256 r2 := - run_exp_ray_to_wad_evm_mono_of_seamR0 hr0 x1 x2 hx1 hx2 hle hdom - -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_mono_of_seamR0' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms run_exp_ray_to_wad_evm_mono_of_seamR0 - -/-! ## Runtime monotonicity with the seam bound discharged +/-! ## Monotonicity The octave-seam `r0`-doubling bound `SeamR0Bound` is discharged (`seamR0Bound_holds`, via the per-point real bracket `r0Tree x ≈ 2¹²⁶·exp(rt)` and the seam relation `exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`), so monotonicity holds over the whole supported domain with no analytic hypothesis. -/ -/-- Monotone over the whole supported domain without an external monotonicity hypothesis. -/ +/-- Monotone over the whole supported domain. -/ example (x1 x2 : Nat) (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hle : FormalYul.Preservation.int256 x1 ≤ FormalYul.Preservation.int256 x2) @@ -123,62 +91,49 @@ example (x1 x2 : Nat) #guard_msgs in #print axioms seamR0Bound_holds -/-! ## `Real.exp` floor brackets, modulo the runtime accumulator bound +/-! ## `Real.exp` floor brackets Each bracket is stated on the runtime result `r` (`run_exp_ray_to_wad_evm x = .ok r`) against the -target `E = 10¹⁸·exp(x/10²⁷)`, and carries the single analytic obligation `RuntimeAccumBound` (the -real pre-floor accumulator brackets `E`: never over, deficit under one, and the below-clamp `E < 1`). -The runtime reduction, the closing-shift floor, the clamp/pin shell branch split, and the -scale-point exactness are proved directly; the floor brackets depend on -`RuntimeAccumBound` — the cert (`Floor.CapsV`, against the exact rational `ê = NUM/DEN`) folded with -the octave `2^k`, plus the reduced-argument and Horner-`sdiv` truncation envelopes the `MARGIN` -absorbs. This mirrors `run_exp_ray_to_wad_evm_mono`'s `RegionMonotonicityFacts` hypothesis. -/ - -/-- Global never-over and floor-or-one-less bracket, given the runtime accumulator bound. -/ -example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) +target `E = 10¹⁸·exp(x/10²⁷)`. The pre-floor accumulator brackets `E` unconditionally +(`accumReal_over`/`accumReal_under`: the cert `Floor.CapsV` against the exact rational +`ê = NUM/DEN`, folded with the octave `2^k`, plus the reduced-argument and Horner-`sdiv` +truncation envelopes the `MARGIN` absorbs), and below the clamp the target satisfies `E < 1` +(`belowC_target_lt_one`), so the global brackets hold with no analytic hypothesis. -/ + +/-- Global floor-or-one-less bracket. -/ +example (x : Nat) (hx : x < 2 ^ 256) (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.FloorOrOneLessBracket (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := - run_exp_ray_to_wad_evm_floorOrOneLess H' x hx hC0 + run_exp_ray_to_wad_evm_floorOrOneLess_uncond x hx hC0 -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_floorOrOneLess' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_floorOrOneLess_uncond' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms run_exp_ray_to_wad_evm_floorOrOneLess +#print axioms run_exp_ray_to_wad_evm_floorOrOneLess_uncond -/-- One-unit underestimation bound, given the runtime accumulator bound. -/ -example (H' : RuntimeAccumBound) (x : Nat) (hx : x < 2 ^ 256) +/-- One-unit underestimation bound. -/ +example (x : Nat) (hx : x < 2 ^ 256) (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.UnderByAtMostOne (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := - run_exp_ray_to_wad_evm_underByAtMostOne H' x hx hC0 - -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_underByAtMostOne' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms run_exp_ray_to_wad_evm_underByAtMostOne - -/-! ## The accumulator obligation reduced to the octave-folded `r0` bound - -`RuntimeAccumBound` (the accumulator-vs-target bracket) reduces — by the unconditional closing-shift -plumbing — to `RuntimeR0Bound`, the cleaner statement that the Q126 quotient `r0Tree x` brackets the -target across the octave shift `2^(126 − k)`. The public floor brackets therefore reduce to -`RuntimeR0Bound` (the cert `Floor.CapsV` against `ê = NUM/DEN`, folded with `2^k`, plus the -reduced-argument and Horner-`sdiv` truncation envelopes the `MARGIN` absorbs). -/ -example (H : RuntimeR0Bound) : RuntimeAccumBound := runtimeAccumBound_of_r0 H + run_exp_ray_to_wad_evm_underByAtMostOne_uncond x hx hC0 -/-- info: 'ExpYul.runtimeAccumBound_of_r0' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +/-- info: 'ExpYul.run_exp_ray_to_wad_evm_underByAtMostOne_uncond' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms runtimeAccumBound_of_r0 +#print axioms run_exp_ray_to_wad_evm_underByAtMostOne_uncond -/-! ## Discharged ingredients of `RuntimeR0Bound` +/-! ## Discharged ingredients -The following `RuntimeR0Bound` ingredients are proved directly and axiom-clean: +Proved directly and axiom-clean: * `tTree_in_cert_domain` — the runtime reduced argument stays in the certificate domain `|tTree x| ≤ H128`, so the Taylor caps (`Floor.CapsV`) instantiate at `t := tTree x`; -* `evTree_bracket` / `odTree_bracket` — the **gap-2 Horner-truncation bridge**: the runtime even/odd +* `evTree_bracket` / `odTree_bracket` — the Horner-truncation bridge: the runtime even/odd accumulators bracket the exact integer polynomials `evNumV`/`odNumV` (in `v = vTree x`) within `2` units at the cleared scales `2^553`/`2^530`; -* `belowC_target_lt_one` — the `RuntimeR0Bound.belowC` field (below the clamp boundary `E < 1`). -/ +* `belowC_target_lt_one` — below the clamp boundary the target satisfies `E < 1`; +* `accumReal_over` / `accumReal_under` — the pre-floor accumulator never exceeds `E` and lies + within one output unit below it. -/ example {x : Nat} (hx : x < 2 ^ 256) (hC : FormalYul.Preservation.int256 Cmask < FormalYul.Preservation.int256 x) (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : @@ -202,35 +157,13 @@ example {x : Nat} (hx : x < 2 ^ 256) #guard_msgs in #print axioms belowC_target_lt_one -/-! ## Hypothesis-free global floor brackets - -The never-over (`r0_real_over_within`) and deficit (`r0_real_under_within`) per-point `r0`-vs-`exp` -brackets, folded onto the target through the closing-shift octave fold, discharge the accumulator's -never-over (`accumReal_over`) and deficit (`accumReal_under`) fields unconditionally and axiom-clean. -The global floor-or-one-less and one-unit underestimation brackets consume only those plus the -below-clamp `belowC_target_lt_one`, so they hold with no analytic hypothesis. -/ - -/-- Global floor-or-one-less bracket, with no analytic hypothesis. -/ -example (x : Nat) (hx : x < 2 ^ 256) - (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.FloorOrOneLessBracket - (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := - run_exp_ray_to_wad_evm_floorOrOneLess_uncond x hx hC0 - -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_floorOrOneLess_uncond' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +/-- info: 'ExpYul.accumReal_over' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms run_exp_ray_to_wad_evm_floorOrOneLess_uncond - -/-- One-unit underestimation bound, with no analytic hypothesis. -/ -example (x : Nat) (hx : x < 2 ^ 256) - (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : - ∃ r, run_exp_ray_to_wad_evm x = .ok r ∧ ExpRealSpec.UnderByAtMostOne - (FormalYul.Preservation.int256 x) (FormalYul.Preservation.int256 r) := - run_exp_ray_to_wad_evm_underByAtMostOne_uncond x hx hC0 +#print axioms accumReal_over -/-- info: 'ExpYul.run_exp_ray_to_wad_evm_underByAtMostOne_uncond' depends on axioms: [propext, Classical.choice, Quot.sound] -/ +/-- info: 'ExpYul.accumReal_under' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in -#print axioms run_exp_ray_to_wad_evm_underByAtMostOne_uncond +#print axioms accumReal_under /-! ## The `lnWadToRay` round trip @@ -238,9 +171,8 @@ For `w` with `w/10¹⁸ ∈ [1/√2, √2)`, the compiled composition `expRayToWad(lnWadToRay(w))` returns `w − 1`, and returns `w` at the scale point `w = 10¹⁸`. The proof composes the verified `lnWadToRay` runtime (`LnProof`) with the exp runtime. -/ -/-- The `lnWadToRay` round trip, with no analytic hypothesis. For `w` on the central band -(`Wlo ≤ w ≤ Whi`, i.e. `w/10¹⁸ ∈ [1/√2, √2)`), the runtime composition returns `w − 1`, and `w` at -the scale point. -/ +/-- The `lnWadToRay` round trip. For `w` on the central band (`Wlo ≤ w ≤ Whi`, i.e. +`w/10¹⁸ ∈ [1/√2, √2)`), the runtime composition returns `w − 1`, and `w` at the scale point. -/ example {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : ∃ x r : Nat, LnYul.run_ln_wad_to_ray_evm w = .ok x ∧ run_exp_ray_to_wad_evm x = .ok r ∧ (r : Int) = if w = 10 ^ 18 then (w : Int) else (w : Int) - 1 := @@ -250,12 +182,4 @@ example {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : #guard_msgs in #print axioms run_exp_ray_to_wad_evm_lnWadToRay_roundTrip_if -/-- info: 'ExpYul.accumReal_over' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms accumReal_over - -/-- info: 'ExpYul.accumReal_under' depends on axioms: [propext, Classical.choice, Quot.sound] -/ -#guard_msgs in -#print axioms accumReal_under - end ExpYul From 1ece210fd478a608408323c163b1bfe4f2acf4b0 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 00:06:56 +0200 Subject: [PATCH 094/149] State the exp proof comments in current terms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Describe TBound's integer-k fact directly; point the loose R0Exp per-point bounds at r0_real_over_tight for the margin budget; name the seam-step reduction by what it does; and align Mono/Octave's stated k range with kTree_bound (k ∈ [-61, 63]). Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 4 ++-- formal/exp/ExpProof/ExpProof/Floor/TBound.lean | 4 ++-- formal/exp/ExpProof/ExpProof/Mono/Octave.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Top.lean | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index b2238101e..14cfb2fd0 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -1413,8 +1413,8 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) These bracket `(r0Tree x : Real)` against `2¹²⁶·exp(rt)` with loose octave-seam-absorbed constants (`+50` over, `+701` under). They suffice for `SeamR0Bound`, whose octave-seam doubling has ~10¹¹ -slack. The over side does not yet meet the per-point `MARGIN` budget — that needs the tight -cross-product sharpening; here only the loose `r0_vs_certRatio` constants are used. -/ +slack, and consume only the loose `r0_vs_certRatio` constants; the per-point `MARGIN` budget is met +by `r0_real_over_tight` above, via the cross-product sharpening. -/ /-- **Loose per-point never-over** (nonneg half): `r0 ≤ 2¹²⁶·exp(rt) + 50`. -/ theorem r0_real_over_loose {x : Nat} (hx : x < 2 ^ 256) diff --git a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean index dc2ae90b2..531f04d50 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean @@ -8,8 +8,8 @@ The reduced-argument Taylor caps (`Floor.CapsV`) are certified over `t ∈ [0, H `H128 = ⌊ln2/2 · 2¹²⁸⌋`. To instantiate them at the runtime reduced argument `t = tTree x` we need `|tTree x| ≤ H128` on the meaningful region. -This is the integer-`k` fact the experiments flagged: a real linear-program relaxation of the -octave/reduced-argument sandwiches is unbounded (it decouples `k` from `x`), but the *integer* +This is an integer-`k` fact: a real linear-program relaxation of the octave/reduced-argument +sandwiches is unbounded (it decouples `k` from `x`), but the *integer* `k`-rounding sandwich `2²⁰⁰·k ≤ 2¹⁹⁹ + CINV·x < 2²⁰⁰·k + 2²⁰⁰` ties `k` to `x` tightly enough that the maximum of the reduction argument `K27·x − LN2·k` over the integer region is strictly below `2¹⁰⁷·(H128 + 1)` (and symmetrically above `−2¹⁰⁷·(H128 + 1)`). `omega` discharges the resulting diff --git a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean index 08418ea6c..d9067668a 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean @@ -10,7 +10,7 @@ bounds, and proves `k` is nondecreasing in `int256 x` and (for a fixed `k`) `t` `int256 x`. Constants and their bit widths (so every product stays below `2^255`): -`CINV` 111 bits, `K27` 146 bits, `LN2` 235 bits, `|int256 x| < 2^96`, `k ∈ [-60, 63]`. +`CINV` 111 bits, `K27` 146 bits, `LN2` 235 bits, `|int256 x| < 2^96`, `k ∈ [-61, 63]`. -/ namespace ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index 08efc28f5..259f06c1b 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -174,7 +174,7 @@ theorem run_exp_ray_to_wad_evm_mono_of_seam (hseamstep : SeamStep) (x1 x2 : Nat) run_exp_ray_to_wad_evm_mono (regionMonotonicityFacts_of_seam hseamstep) x1 x2 hx1 hx2 hle hdom /-- **Runtime monotonicity, modulo the octave-seam `r0` doubling bound.** With the -kernel-wall floor reduction (`Seam.seamStep_of_seamR0`) and all of `range`/`nonneg`/same-octave/ +seam-step reduction (`Seam.seamStep_of_seamR0`) and all of `range`/`nonneg`/same-octave/ induction discharged, monotonicity over the entire non-reverting domain follows from the single analytic bound `SeamR0Bound` (`r0Tree x1 < 2·r0Tree x2` across one octave). -/ theorem run_exp_ray_to_wad_evm_mono_of_seamR0 (hr0 : SeamR0Bound) (x1 x2 : Nat) From 5eae57f04e679167c1bd8e6ef0c2608525f854ce Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 30 Jun 2026 19:53:14 +0200 Subject: [PATCH 095/149] Delete pyproject.toml --- pyproject.toml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 56cebcc48..000000000 --- a/pyproject.toml +++ /dev/null @@ -1,21 +0,0 @@ -[tool.black] -target-version = ["py311"] - -[tool.isort] -profile = "black" -py_version = 311 -known_first_party = ["formal"] - -[tool.mypy] -python_version = "3.11" -files = ["formal"] -strict = true -disallow_any_expr = true -disallow_any_decorated = true -disallow_any_explicit = true -disallow_any_generics = true -disallow_any_unimported = true -disallow_subclassing_any = true -warn_unreachable = true -show_error_codes = true -pretty = true From e7a0d6d11d8ca49b58e03f548463b879ba0948a1 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 09:52:44 +0200 Subject: [PATCH 096/149] WIP: clean up slop --- src/vendor/Exp.sol | 108 +++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 53 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 230ce39c0..729252ee9 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -33,12 +33,12 @@ library Exp { /// r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 /// return r + (x == 0); // pin exp(0) = 10¹⁸ exactly /// - /// `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split - /// N(t) = Ev(t²) + t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational - /// that matches `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and - /// Od degree 4; in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the - /// integer coefficients realize ≈126 of them (the Q126 quotient). Ev is monic, so its - /// leading stage is a shift, not a multiply. + /// `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split N(t) = Ev(t²) + /// + t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational that matches + /// `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and Od degree 4; + /// in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the integer + /// coefficients realize ≈126 of them (the Q126 quotient). Ev is monic, so its leading + /// stage is a shift, not a multiply. /// /// Mixed fixed-point bases (a staircase): every quantity is rounded exactly once, and each /// coefficient takes the widest basis fitting its chosen byte width, so a coefficient @@ -47,60 +47,62 @@ library Exp { /// v = t²: Q128 (one `shr` by 128 from the Q256 product) /// Ev Horner up the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) /// Od Horner up the staircase Q105 → Q102 → Q93 → Q94 → Q87 - /// Ev, Od, t⋅Od, and the numerator/denominator: Q87 (the basis the closing quotient shares) + /// Ev, Od, t⋅Od, and the numerator/denominator: Q87 (the basis the closing quotient + /// shares) /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend, numerator << 126, stays /// below 2²⁵⁵: a nonnegative signed word) /// output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in /// - /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the - /// exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The proof - /// bounds Δ ≤ 0.7201434073703092789 (each term below carried to its supremum at 19 decimal - /// places), the sum of three one-sided contributions: - /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + t⋅Od - /// and denominator Ev - t⋅Od cancels to first order in the quotient, so its - /// truncation barely perturbs e; this jitter (the dominant term) stays ≤ 0.6207065163. - /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): - /// ≤ 0.0883883477 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). - /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction - /// is budgeted on the under side); the over side is the K27/LN2 constant-grid - /// residue (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes - /// one-sidedly at 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 - /// (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). - /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer - /// strictly above 2⁶³⋅S: 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1 = 720143407370309279 (worth ≈ S ulp - /// at k = 63; the +1 makes the never-over strict, which the round trip below needs). So - /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates). The under side is bounded to the same - /// precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 13/2, where 13/2 is the proven sum of the integer-rational - /// deficit (≤ 6001/1000, the Horner/`sdiv`/floor truncation against the denominator), the `Mp` - /// factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), and the under-direction reduced-argument gap (≤ 37/100, - /// via exp(t) ≤ √2). Hence the maximum underestimation of the pre-floor accumulator A is - /// E - A ≤ ((13/2)⋅10¹⁸ + margin)/2⁶³ ≈ 0.78281 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the - /// 1-ulp underestimate is achieved, ⌊E⌋ - 2 never occurs). The deficit envelope - /// ((13/2)⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp - /// and the floor can fall two below E; that input is reverted. On the central octave k = 0 the - /// margin is margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so - /// the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is + /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over + /// the exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The + /// proof bounds Δ ≤ 0.7201434073703092789 (each term below carried to its supremum at 19 + /// decimal places), the sum of three one-sided contributions: + /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + + /// t⋅Od and denominator Ev - t⋅Od cancels to first order in the quotient, so its + /// truncation barely perturbs e; this jitter (the dominant term) stays ≤ + /// 0.6207065163. + /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and + /// exp): ≤ 0.0883883477 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). + /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is + /// budgeted on the under side); the over side is the K27/LN2 constant-grid residue + /// (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly + /// at 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 (√2⋅2¹²⁶/(32⋅2¹²⁸) = + /// √2/128). + /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 + /// at S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least + /// integer strictly above 2⁶³⋅S: 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1 = 720143407370309279 + /// (worth ≈ S ulp at k = 63; the +1 makes the never-over strict, which the round trip + /// below needs). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates). The under side is + /// bounded to the same precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 13/2, where 13/2 is the proven + /// sum of the integer-rational deficit (≤ 6001/1000, the Horner/`sdiv`/floor truncation + /// against the denominator), the `Mp` factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), and the + /// under-direction reduced-argument gap (≤ 37/100, via exp(t) ≤ √2). Hence the maximum + /// underestimation of the pre-floor accumulator A is E - A ≤ ((13/2)⋅10¹⁸ + margin)/2⁶³ ≈ + /// 0.78281 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The deficit envelope ((13/2)⋅10¹⁸ + + /// margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp and the floor + /// can fall two below E; that input is reverted. On the central octave k = 0 the margin is + /// margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the + /// round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is /// exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). /// - /// This margin is the floor of the bound above: Δ's two √2-driven terms are irrational, so Δ - /// itself is irrational and the margin ⌊10¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering Δ. The - /// dominant truncation term (≈0.62, the affine envelope of the integer Horner) is ≈1.6× the - /// empirically observed jitter; closing that gap is not reachable by the linear bound and - /// would need either round-to-nearest Horner stages (more gas and code) or a number-theoretic - /// bound on the fractional part of E, so the margin rests here. + /// This margin is the floor of the bound above: Δ's two √2-driven terms are irrational, so + /// Δ itself is irrational and the margin ⌊10¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering + /// Δ. The dominant truncation term (≈0.62, the affine envelope of the integer Horner) is + /// ≈1.6× the empirically observed jitter; closing that gap is not reachable by the linear + /// bound and would need either round-to-nearest Horner stages (more gas and code) or a + /// number-theoretic bound on the fractional part of E, so the margin rests here. /// /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves - /// the pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The - /// error terms above confine the accumulator to a band of width 10¹⁸⋅(Δ + 13/2) ≈ - /// 7.2⋅10¹⁸ grid units just below E's grid image at every octave (in grid units the band - /// is k-independent; an octave seam rescales E and the band together), so the per-step - /// gain exceeds any adverse swing within the band by more than nine orders of magnitude, - /// and the pre-floor accumulator strictly increases at every step; its floor - /// is non-decreasing. The zeroing clamp and the +1 pin preserve order: below C the result - /// is 0 while just above it ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket - /// the pinned scale-point value. + /// the pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The error + /// terms above confine the accumulator to a band of width 10¹⁸⋅(Δ + 13/2) ≈ 7.2⋅10¹⁸ grid + /// units just below E's grid image at every octave (in grid units the band is + /// k-independent; an octave seam rescales E and the band together), so the per-step gain + /// exceeds any adverse swing within the band by more than nine orders of magnitude, and + /// the pre-floor accumulator strictly increases at every step; its floor is + /// non-decreasing. The zeroing clamp and the +1 pin preserve order: below C the result is + /// 0 while just above it ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket the + /// pinned scale-point value. function _expRayToWad(int256 x) private pure returns (int256 r) { assembly ("memory-safe") { // k = round(x / (10²⁷⋅ln2)), half-open. CINV = round(2²⁰⁰ / (10²⁷⋅ln2)); the +2¹⁹⁹ @@ -144,12 +146,12 @@ library Exp { // both positive. let tod := sar(0x80, mul(t, od)) - // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁶, the denominator > 0. + // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁵, the denominator > 0. r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` - // which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 187]). + // which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 186]). r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x9fe769d0fa58e9f)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x From 29f469d3da5a6c73a32df2898a3e70b354fb15f6 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 09:54:27 +0200 Subject: [PATCH 097/149] WIP: clean up slop --- src/vendor/Exp.sol | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 729252ee9..24e3e9708 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -8,11 +8,10 @@ library Exp { /// result as a fixnum with 10**18 (wad) basis. /// @dev Let E = 10¹⁸ ⋅ exp(x / 10²⁷) be the exact, infinite-precision result. This function /// returns either ⌊E⌋ or ⌊E⌋ - 1; it never overestimates. `expRayToWad(0) == 10**18` - /// exactly, and the result is never negative. The function is monotonic; x₁ < x₂ → - /// expRayToWad(x₁) ≤ expRayToWad(x₂). For canonical central wad inputs - /// 707106781186547525 ≤ w ≤ 1414213562373095048, - /// `expRayToWad(lnWadToRay(w)) == w - 1`, except at w = 10¹⁸ where it returns w. Reverts - /// with `Panic(17)` when x is large enough to leave the supported range + /// exactly. The result is never negative. The function is monotonic; x₁ < x₂ → + /// expRayToWad(x₁) ≤ expRayToWad(x₂). For "central" inputs 707106781186547525 ≤ w ≤ + /// 1414213562373095048, `expRayToWad(lnWadToRay(w)) == w - 1`, except at w = 10¹⁸ where it + /// returns w. Reverts with `Panic(17)` when x is large enough to leave the supported range /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256 r) { // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64, where the deficit From f6049d05c7de3e8a1463461560a78d54fb5c7b05 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 09:54:49 +0200 Subject: [PATCH 098/149] WIP: clean up slop --- src/vendor/Exp.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 24e3e9708..5164e197a 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -83,7 +83,7 @@ library Exp { /// can fall two below E; that input is reverted. On the central octave k = 0 the margin is /// margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the /// round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is - /// exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). + /// exactly [-H, H] with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). /// /// This margin is the floor of the bound above: Δ's two √2-driven terms are irrational, so /// Δ itself is irrational and the margin ⌊10¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering From e3b45efce0c354e7880c9e6581d5545a115f127d Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 09:56:50 +0200 Subject: [PATCH 099/149] WIP: clean up slop --- src/vendor/Exp.sol | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 5164e197a..b2782a7c7 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -55,18 +55,17 @@ library Exp { /// /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over /// the exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The - /// proof bounds Δ ≤ 0.7201434073703092789 (each term below carried to its supremum at 19 - /// decimal places), the sum of three one-sided contributions: + /// proof bounds Δ ≤ 0.7201434073703092789, the sum of three one-sided contributions: /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + /// t⋅Od and denominator Ev - t⋅Od cancels to first order in the quotient, so its - /// truncation barely perturbs e; this jitter (the dominant term) stays ≤ - /// 0.6207065163. + /// truncation barely perturbs e; this jitter (the dominant term) stays < + /// 0.62071. /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and - /// exp): ≤ 0.0883883477 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). + /// exp): < 0.08839 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is /// budgeted on the under side); the over side is the K27/LN2 constant-grid residue /// (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly - /// at 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 (√2⋅2¹²⁶/(32⋅2¹²⁸) = + /// at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = /// √2/128). /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 /// at S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least From b26ab44b89363193a80bc0ba643c941c815b4b43 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 09:57:31 +0200 Subject: [PATCH 100/149] WIP: clean up slop --- src/vendor/Exp.sol | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index b2782a7c7..26cce1293 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -84,13 +84,6 @@ library Exp { /// round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is /// exactly [-H, H] with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). /// - /// This margin is the floor of the bound above: Δ's two √2-driven terms are irrational, so - /// Δ itself is irrational and the margin ⌊10¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering - /// Δ. The dominant truncation term (≈0.62, the affine envelope of the integer Horner) is - /// ≈1.6× the empirically observed jitter; closing that gap is not reachable by the linear - /// bound and would need either round-to-nearest Horner stages (more gas and code) or a - /// number-theoretic bound on the fractional part of E, so the margin rests here. - /// /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves /// the pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The error /// terms above confine the accumulator to a band of width 10¹⁸⋅(Δ + 13/2) ≈ 7.2⋅10¹⁸ grid From 2b85d70158702ea6657a87bd0d088f8ef29fcb97 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 09:58:37 +0200 Subject: [PATCH 101/149] WIP: clean up slop --- src/vendor/Exp.sol | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 26cce1293..affb098ce 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -14,9 +14,8 @@ library Exp { /// returns w. Reverts with `Panic(17)` when x is large enough to leave the supported range /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256 r) { - // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64, where the deficit - // envelope (the 2ᵏ⁻⁶³-scaled margin plus the under-side truncation) exceeds one ulp and the - // floor can fall two below E. + // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64. The rounding error + // in `_expRayToWad` exceeds 1ulp at that scale. if (x >= 0x8e383a2cdfa1b74a9422d2e1) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } From 51a0ca9716ea7c0c2aa5000eacbc091e49c17d40 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 09:59:27 +0200 Subject: [PATCH 102/149] WIP: clean up slop --- src/vendor/Exp.sol | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index affb098ce..f2a6621f2 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -14,8 +14,8 @@ library Exp { /// returns w. Reverts with `Panic(17)` when x is large enough to leave the supported range /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256 r) { - // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64. The rounding error - // in `_expRayToWad` exceeds 1ulp at that scale. + // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64. The error in + // `_expRayToWad` exceeds 1ulp at that scale. if (x >= 0x8e383a2cdfa1b74a9422d2e1) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } @@ -77,11 +77,11 @@ library Exp { /// under-direction reduced-argument gap (≤ 37/100, via exp(t) ≤ √2). Hence the maximum /// underestimation of the pre-floor accumulator A is E - A ≤ ((13/2)⋅10¹⁸ + margin)/2⁶³ ≈ /// 0.78281 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The deficit envelope ((13/2)⋅10¹⁸ + - /// margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp and the floor - /// can fall two below E; that input is reverted. On the central octave k = 0 the margin is - /// margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the - /// round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is - /// exactly [-H, H] with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). + /// margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds 1ulp. On the central + /// octave k = 0 the margin is margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap + /// `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is + /// half-open, so the k = 0 band is exactly [-H, H] with H = ⌊10²⁷⋅ln2/2⌋, matching + /// `lnWadToRay`'s image over [1/√2, √2). /// /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves /// the pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The error From e444a7d25e2ec56e2365f058eab2583dc8b6540e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:05:43 +0200 Subject: [PATCH 103/149] WIP: clean up slop --- test/0.8.34/Exp.t.sol | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 7f8265252..9601b2279 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -43,7 +43,7 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(-50e27), 0, "deep negative not zero"); assertEq(Exp.expRayToWad(-1e40), 0, "reduction-overflow region not zero"); assertEq(Exp.expRayToWad(type(int256).min), 0, "int256.min not zero"); - // First input past the clamp: E - 1 ~= 3.2e-28 (mpmath, 80 digits), so floor(E) = 1. + // First input past the clamp: E - 1 ~= 3.2e-28, so floor(E) = 1. assertEq(Exp.expRayToWad(_ZERO_MAX + 1), 1, "first live input not one"); } @@ -101,8 +101,8 @@ contract ExpTest is Test { } } - /// The largest supported input, one below the revert threshold. floor(E) computed with - /// mpmath at 80 digits; frac(E) ~= 0.74, comfortably inside the k = 63 deficit envelope. + /// The largest supported input, one below the revert threshold. frac(E) ~= 0.74, comfortably + /// inside the k = 63 deficit envelope. function testExpRayToWadSupportedEdge() external pure { int256 r = Exp.expRayToWad(_TOO_BIG - 1); int256 floorE = 13043817825332782212349571798501714341; @@ -111,8 +111,8 @@ contract ExpTest is Test { } /// The 1-ulp underestimate is achieved: the least x >= 44e27 whose result is floor(E) - 1. - /// frac(E) ~= 0.1605 (mpmath, 80 digits) sits below the accumulated deficit at k = 63, so - /// the floored accumulator lands one under the exact floor. + /// frac(E) ~= 0.1605 sits below the accumulated deficit at k = 63, so the floored accumulator + /// lands one under the exact floor. function testExpRayToWadUnderestimateByOneWitness() external pure { int256 x = 44000000000000000000000000001; int256 floorE = 12851600114359308275809299644994699372; From 5a6a6a37248d7735c6f0cd86852db2c6bb5134c1 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:06:30 +0200 Subject: [PATCH 104/149] WIP: clean up slop --- src/wrappers/CbrtWrapper.sol | 2 +- src/wrappers/ExpWrapper.sol | 2 +- src/wrappers/LnWrapper.sol | 2 +- src/wrappers/SqrtWrapper.sol | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wrappers/CbrtWrapper.sol b/src/wrappers/CbrtWrapper.sol index bad2aef35..85ad07652 100644 --- a/src/wrappers/CbrtWrapper.sol +++ b/src/wrappers/CbrtWrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity =0.8.34; import {Cbrt} from "src/vendor/Cbrt.sol"; diff --git a/src/wrappers/ExpWrapper.sol b/src/wrappers/ExpWrapper.sol index 3aa610e5e..59a8d3ea6 100644 --- a/src/wrappers/ExpWrapper.sol +++ b/src/wrappers/ExpWrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.34; +pragma solidity =0.8.34; import {Exp} from "src/vendor/Exp.sol"; diff --git a/src/wrappers/LnWrapper.sol b/src/wrappers/LnWrapper.sol index cff4190f0..d6d937262 100644 --- a/src/wrappers/LnWrapper.sol +++ b/src/wrappers/LnWrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.34; +pragma solidity =0.8.34; import {Ln} from "src/vendor/Ln.sol"; diff --git a/src/wrappers/SqrtWrapper.sol b/src/wrappers/SqrtWrapper.sol index 126ec470c..2798047ab 100644 --- a/src/wrappers/SqrtWrapper.sol +++ b/src/wrappers/SqrtWrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; +pragma solidity =0.8.34; import {Sqrt} from "src/vendor/Sqrt.sol"; From 12762220e46a8a2d9fcd8be51cd8286f9ece3476 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:08:43 +0200 Subject: [PATCH 105/149] WIP: clean up slop --- .github/workflows/cbrt-formal.yml | 2 +- .github/workflows/cbrt512-formal.yml | 2 +- .github/workflows/exp-formal.yml | 2 +- .github/workflows/ln-formal.yml | 2 +- .github/workflows/sqrt-formal.yml | 2 +- .github/workflows/sqrt512-formal.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cbrt-formal.yml b/.github/workflows/cbrt-formal.yml index 6499be78d..c4f743ab0 100644 --- a/.github/workflows/cbrt-formal.yml +++ b/.github/workflows/cbrt-formal.yml @@ -61,7 +61,7 @@ jobs: ${{ runner.os }}-formal-lean- - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol + run: forge build -- src/wrappers/CbrtWrapper.sol env: FOUNDRY_SOLC_VERSION: 0.8.34 diff --git a/.github/workflows/cbrt512-formal.yml b/.github/workflows/cbrt512-formal.yml index f14f8521a..36b960649 100644 --- a/.github/workflows/cbrt512-formal.yml +++ b/.github/workflows/cbrt512-formal.yml @@ -77,7 +77,7 @@ jobs: ${{ runner.os }}-formal-lean- - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol + run: forge build -- src/wrappers/Cbrt512Wrapper.sol env: FOUNDRY_SOLC_VERSION: 0.8.34 diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index 061e8f628..237bcae4c 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -73,7 +73,7 @@ jobs: ${{ runner.os }}-formal-lean- - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol + run: forge build -- src/wrappers/ExpWrapper.sol env: FOUNDRY_SOLC_VERSION: 0.8.34 diff --git a/.github/workflows/ln-formal.yml b/.github/workflows/ln-formal.yml index bf89292a3..828799292 100644 --- a/.github/workflows/ln-formal.yml +++ b/.github/workflows/ln-formal.yml @@ -62,7 +62,7 @@ jobs: ${{ runner.os }}-formal-lean- - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol + run: forge build -- src/wrappers/LnWrapper.sol env: FOUNDRY_SOLC_VERSION: 0.8.34 diff --git a/.github/workflows/sqrt-formal.yml b/.github/workflows/sqrt-formal.yml index 6a47e440e..1f406b634 100644 --- a/.github/workflows/sqrt-formal.yml +++ b/.github/workflows/sqrt-formal.yml @@ -61,7 +61,7 @@ jobs: ${{ runner.os }}-formal-lean- - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol + run: forge build -- src/wrappers/SqrtWrapper.sol env: FOUNDRY_SOLC_VERSION: 0.8.34 diff --git a/.github/workflows/sqrt512-formal.yml b/.github/workflows/sqrt512-formal.yml index 8bd9d9700..16e24350b 100644 --- a/.github/workflows/sqrt512-formal.yml +++ b/.github/workflows/sqrt512-formal.yml @@ -77,7 +77,7 @@ jobs: ${{ runner.os }}-formal-lean- - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol + run: forge build -- src/wrappers/Sqrt512Wrapper.sol env: FOUNDRY_SOLC_VERSION: 0.8.34 From 4f61b03ab286024eff18a374b6a70900b7007474 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:08:57 +0200 Subject: [PATCH 106/149] Fix missing CI trigger --- .github/workflows/exp-formal.yml | 2 ++ .github/workflows/ln-formal.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index 237bcae4c..0c1d985cf 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -19,6 +19,7 @@ on: - .gitmodules - lib/EVMYulLean - .github/workflows/exp-formal.yml + - .github/actions/build-ln-proof/action.yml pull_request: paths: - src/utils/Panic.sol @@ -35,6 +36,7 @@ on: - .gitmodules - lib/EVMYulLean - .github/workflows/exp-formal.yml + - .github/actions/build-ln-proof/action.yml jobs: exp-formal: diff --git a/.github/workflows/ln-formal.yml b/.github/workflows/ln-formal.yml index 828799292..355900b1d 100644 --- a/.github/workflows/ln-formal.yml +++ b/.github/workflows/ln-formal.yml @@ -15,6 +15,7 @@ on: - .gitmodules - lib/EVMYulLean - .github/workflows/ln-formal.yml + - .github/actions/build-ln-proof/action.yml pull_request: paths: - src/vendor/Ln.sol @@ -27,6 +28,7 @@ on: - .gitmodules - lib/EVMYulLean - .github/workflows/ln-formal.yml + - .github/actions/build-ln-proof/action.yml jobs: ln-formal: From e35bb61d61126aa906df8f8b09b89d616f3170f6 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:13:57 +0200 Subject: [PATCH 107/149] WIP: clean up slop --- src/vendor/Exp.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index f2a6621f2..91a5e6f9a 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -53,8 +53,10 @@ library Exp { /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in /// /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over - /// the exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The - /// proof bounds Δ ≤ 0.7201434073703092789, the sum of three one-sided contributions: + /// the exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the + /// tightest bound the proof technique can bear, in spite of the fact that the worst-case + /// error contributions do not co-occur. The proof bounds Δ ≤ 0.7201434073703092789, the + /// sum of three one-sided contributions: /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + /// t⋅Od and denominator Ev - t⋅Od cancels to first order in the quotient, so its /// truncation barely perturbs e; this jitter (the dominant term) stays < From 05ecaf1df856b199f1adda92f37e861b2aa2a7d2 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:15:46 +0200 Subject: [PATCH 108/149] Homogenize --- src/vendor/Ln.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/vendor/Ln.sol b/src/vendor/Ln.sol index c4a3062e9..eb061d3f9 100644 --- a/src/vendor/Ln.sol +++ b/src/vendor/Ln.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.34; +import {Panic} from "../utils/Panic.sol"; + library Ln { /// @notice Compute the natural logarithm of a positive fixnum with 10**18 (wad) basis, /// returning the result as a fixnum with 10**27 (ray) basis. @@ -12,6 +14,10 @@ library Ln { /// documented on `Exp.expRayToWad` consumes this error envelope; the exp formal check /// re-verifies that round trip on any change to this file. function lnWadToRay(int256 x) internal pure returns (int256 r) { + if (x <= 0) { + Panic.panic(Panic.DIVISION_BY_ZERO); + } + // Equivalent pseudocode; fixed-point truncations are accounted for below: // require(x > 0); // k = ⌊log₂(x)⌋ - 95; // x = m ⋅ 2ᵏ, m ∈ [2⁹⁵, 2⁹⁶) @@ -63,12 +69,6 @@ library Ln { // multi-unit z decrease, and `SDIV` truncation toward zero preserves order. The x = 10¹⁸ // correction preserves monotonicity because its neighbors' results bracket [0, 999999999]. assembly ("memory-safe") { - if iszero(slt(0x00, x)) { - mstore(0x00, 0x4e487b71) // selector for `Panic(uint256)` - mstore(0x20, 0x12) // panic code for division by zero - revert(0x1c, 0x24) - } - // Normalize: x := m, a Q95 fixnum, m ∈ [1, 2), truncated from x / 2ᵏ. Truncation // underestimates ln(x) by less than 2⁻⁹⁵ (only possible when k > 0). let c := clz(x) From 742f1701b09a7f76e45da0f0d1b0054af18c8a3f Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:31:49 +0200 Subject: [PATCH 109/149] Share the formal CI toolchain setup across the proof workflows Two composite actions carry the steps every *-formal workflow runs identically. setup-formal installs Foundry v1.5.1 and the pinned Lean toolchain, restores the Lean build cache, installs solc 0.8.34, fetches the Yul importer's Mathlib cache, and builds the importer, parameterized by the per-proof toolchain files and cache configuration; when several toolchain files are given, the extras must pin the same toolchain as the first. fetch-lean-cache runs `lake exe cache get` with the ProofWidgets release workaround for any Lean package. The six proof workflows and build-ln-proof consume them, and each workflow's path filters cover the actions it uses through them. The cache key concatenates the shared-glob hash with the per-proof-glob hash; the restore-keys prefixes match caches of any key shape. Co-Authored-By: Claude Fable 5 --- .github/actions/build-ln-proof/action.yml | 14 +--- .github/actions/fetch-lean-cache/action.yml | 25 +++++++ .github/actions/setup-formal/action.yml | 83 +++++++++++++++++++++ .github/workflows/cbrt-formal.yml | 68 ++++------------- .github/workflows/cbrt512-formal.yml | 74 ++++++------------ .github/workflows/exp-formal.yml | 72 ++++++------------ .github/workflows/ln-formal.yml | 58 ++++---------- .github/workflows/sqrt-formal.yml | 68 ++++------------- .github/workflows/sqrt512-formal.yml | 74 ++++++------------ 9 files changed, 223 insertions(+), 313 deletions(-) create mode 100644 .github/actions/fetch-lean-cache/action.yml create mode 100644 .github/actions/setup-formal/action.yml diff --git a/.github/actions/build-ln-proof/action.yml b/.github/actions/build-ln-proof/action.yml index db77ff554..f646a8701 100644 --- a/.github/actions/build-ln-proof/action.yml +++ b/.github/actions/build-ln-proof/action.yml @@ -17,17 +17,9 @@ runs: 0.8.34 - name: Fetch Ln proof dependency cache - shell: bash - working-directory: formal/ln/LnProof - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get + uses: ./.github/actions/fetch-lean-cache + with: + working-directory: formal/ln/LnProof - name: Generate Ln certificate artifacts shell: bash diff --git a/.github/actions/fetch-lean-cache/action.yml b/.github/actions/fetch-lean-cache/action.yml new file mode 100644 index 000000000..f5467af2e --- /dev/null +++ b/.github/actions/fetch-lean-cache/action.yml @@ -0,0 +1,25 @@ +name: Fetch Lean build cache +description: >- + Run `lake exe cache get` for a Lean package, first materializing the + ProofWidgets release layout it requires. + +inputs: + working-directory: + description: Directory containing the Lean package's lakefile. + required: true + +runs: + using: composite + steps: + - name: Fetch Lean build cache + shell: bash + working-directory: ${{ inputs.working-directory }} + run: | + # Mathlib's `cache get` fetches the ProofWidgets cloud release, then + # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch + # the release and ensure those directories exist before it runs. + lake build proofwidgets:release + mkdir -p \ + .lake/packages/proofwidgets/.lake/build/lib \ + .lake/packages/proofwidgets/.lake/build/ir + lake exe cache get diff --git a/.github/actions/setup-formal/action.yml b/.github/actions/setup-formal/action.yml new file mode 100644 index 000000000..c40e40033 --- /dev/null +++ b/.github/actions/setup-formal/action.yml @@ -0,0 +1,83 @@ +name: Set up the formal toolchain +description: >- + The shared prefix of every *-formal workflow: install Foundry and the pinned + Lean toolchain, restore the Lean build cache, install solc 0.8.34, fetch the + Yul importer's Mathlib cache, and build the Yul importer. Requires the + repository (with submodules) to be checked out first. + +inputs: + lean-toolchain-files: + description: >- + Newline-separated lean-toolchain file paths. The first names the + toolchain to install; every subsequent file must pin the same toolchain. + required: true + cache-name: + description: Per-proof segment of the Lean build cache key (e.g. exp-formal). + required: true + cache-paths: + description: >- + Newline-separated proof-package build directories to cache, in addition + to the Yul importer's and EVMYulLean's. + required: true + cache-hash-globs: + description: >- + Newline-separated hashFiles patterns covering the proof packages' lake + configuration and Lean sources, hashed into the cache key alongside the + Yul importer's and EVMYulLean's. + required: true + +runs: + using: composite + steps: + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: v1.5.1 + + - name: Install pinned Lean toolchain + shell: bash + env: + LEAN_TOOLCHAIN_FILES: ${{ inputs.lean-toolchain-files }} + run: | + curl https://raw.githubusercontent.com/leanprover/elan/917c18d0ad52f649c2603dc8b973f5b9fa5f8f43/elan-init.sh -sSf | sh -s -- -y --default-toolchain none + echo "$HOME/.elan/bin" >> "$GITHUB_PATH" + LEAN_TOOLCHAIN='' + while IFS= read -r file; do + [ -n "$file" ] || continue + if [ -z "$LEAN_TOOLCHAIN" ]; then + LEAN_TOOLCHAIN="$(cat "$file")" + else + test "$LEAN_TOOLCHAIN" = "$(cat "$file")" + fi + done <<< "$LEAN_TOOLCHAIN_FILES" + "$HOME/.elan/bin/elan" toolchain install "$LEAN_TOOLCHAIN" + "$HOME/.elan/bin/elan" default "$LEAN_TOOLCHAIN" + + - name: Restore Lean build cache + uses: actions/cache@v4 + with: + path: | + formal/yul/.lake/build + formal/yul/.lake/packages/*/.lake/build + lib/EVMYulLean/.lake/build + ${{ inputs.cache-paths }} + key: ${{ runner.os }}-${{ inputs.cache-name }}-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'lib/EVMYulLean/**/*.lean') }}-${{ hashFiles(inputs.cache-hash-globs) }} + restore-keys: | + ${{ runner.os }}-${{ inputs.cache-name }}-lean- + ${{ runner.os }}-formal-lean- + + - name: Install solc 0.8.34 + shell: bash + run: forge build -- src/chains/Mainnet/TakerSubmitted.sol + env: + FOUNDRY_SOLC_VERSION: 0.8.34 + + - name: Fetch Mathlib cache + uses: ./.github/actions/fetch-lean-cache + with: + working-directory: formal/yul + + - name: Build Yul importer + shell: bash + working-directory: formal/yul + run: lake build FormalYul.Preservation yul_importer diff --git a/.github/workflows/cbrt-formal.yml b/.github/workflows/cbrt-formal.yml index 6499be78d..7790a1aec 100644 --- a/.github/workflows/cbrt-formal.yml +++ b/.github/workflows/cbrt-formal.yml @@ -14,6 +14,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/cbrt-formal.yml pull_request: paths: @@ -26,6 +28,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/cbrt-formal.yml jobs: @@ -36,50 +40,17 @@ jobs: with: submodules: recursive - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - - - name: Install pinned Lean toolchain - run: | - curl https://raw.githubusercontent.com/leanprover/elan/917c18d0ad52f649c2603dc8b973f5b9fa5f8f43/elan-init.sh -sSf | sh -s -- -y --default-toolchain none - echo "$HOME/.elan/bin" >> "$GITHUB_PATH" - LEAN_TOOLCHAIN="$(cat formal/cbrt/CbrtProof/lean-toolchain)" - "$HOME/.elan/bin/elan" toolchain install "$LEAN_TOOLCHAIN" - "$HOME/.elan/bin/elan" default "$LEAN_TOOLCHAIN" - - - name: Restore Lean build cache - uses: actions/cache@v4 + - name: Set up the formal toolchain + uses: ./.github/actions/setup-formal with: - path: | - formal/yul/.lake/build - formal/yul/.lake/packages/*/.lake/build - lib/EVMYulLean/.lake/build + lean-toolchain-files: formal/cbrt/CbrtProof/lean-toolchain + cache-name: cbrt-formal + cache-paths: | formal/cbrt/CbrtProof/.lake/build - key: ${{ runner.os }}-cbrt-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/cbrt/CbrtProof/lakefile.toml', 'formal/cbrt/CbrtProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/cbrt/CbrtProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} - restore-keys: | - ${{ runner.os }}-cbrt-formal-lean- - ${{ runner.os }}-formal-lean- - - - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol - env: - FOUNDRY_SOLC_VERSION: 0.8.34 - - - name: Fetch Mathlib cache - working-directory: formal/yul - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get - - - name: Build Yul importer - working-directory: formal/yul - run: lake build FormalYul.Preservation yul_importer + cache-hash-globs: | + formal/cbrt/CbrtProof/lakefile.toml + formal/cbrt/CbrtProof/lake-manifest.json + formal/cbrt/CbrtProof/**/*.lean - name: Generate EVMYulLean artifacts from compiled CbrtWrapper Yul IR run: | @@ -95,16 +66,9 @@ jobs: --output formal/cbrt/CbrtProof/CbrtProof/FiniteCert.lean - name: Fetch proof dependency cache - working-directory: formal/cbrt/CbrtProof - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get + uses: ./.github/actions/fetch-lean-cache + with: + working-directory: formal/cbrt/CbrtProof - name: Build Cbrt proof package working-directory: formal/cbrt/CbrtProof diff --git a/.github/workflows/cbrt512-formal.yml b/.github/workflows/cbrt512-formal.yml index f14f8521a..848d18f4f 100644 --- a/.github/workflows/cbrt512-formal.yml +++ b/.github/workflows/cbrt512-formal.yml @@ -21,6 +21,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/cbrt512-formal.yml pull_request: paths: @@ -40,6 +42,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/cbrt512-formal.yml jobs: @@ -50,52 +54,23 @@ jobs: with: submodules: recursive - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - - - name: Install pinned Lean toolchain - run: | - curl https://raw.githubusercontent.com/leanprover/elan/917c18d0ad52f649c2603dc8b973f5b9fa5f8f43/elan-init.sh -sSf | sh -s -- -y --default-toolchain none - echo "$HOME/.elan/bin" >> "$GITHUB_PATH" - LEAN_TOOLCHAIN="$(cat formal/cbrt/Cbrt512Proof/lean-toolchain)" - test "$LEAN_TOOLCHAIN" = "$(cat formal/cbrt/CbrtProof/lean-toolchain)" - "$HOME/.elan/bin/elan" toolchain install "$LEAN_TOOLCHAIN" - "$HOME/.elan/bin/elan" default "$LEAN_TOOLCHAIN" - - - name: Restore Lean build cache - uses: actions/cache@v4 + - name: Set up the formal toolchain + uses: ./.github/actions/setup-formal with: - path: | - formal/yul/.lake/build - formal/yul/.lake/packages/*/.lake/build - lib/EVMYulLean/.lake/build + lean-toolchain-files: | + formal/cbrt/Cbrt512Proof/lean-toolchain + formal/cbrt/CbrtProof/lean-toolchain + cache-name: cbrt512-formal + cache-paths: | formal/cbrt/CbrtProof/.lake/build formal/cbrt/Cbrt512Proof/.lake/build - key: ${{ runner.os }}-cbrt512-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/cbrt/CbrtProof/lakefile.toml', 'formal/cbrt/CbrtProof/lake-manifest.json', 'formal/cbrt/Cbrt512Proof/lakefile.toml', 'formal/cbrt/Cbrt512Proof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/cbrt/CbrtProof/**/*.lean', 'formal/cbrt/Cbrt512Proof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} - restore-keys: | - ${{ runner.os }}-cbrt512-formal-lean- - ${{ runner.os }}-formal-lean- - - - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol - env: - FOUNDRY_SOLC_VERSION: 0.8.34 - - - name: Fetch Mathlib cache - working-directory: formal/yul - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get - - - name: Build Yul importer - working-directory: formal/yul - run: lake build FormalYul.Preservation yul_importer + cache-hash-globs: | + formal/cbrt/CbrtProof/lakefile.toml + formal/cbrt/CbrtProof/lake-manifest.json + formal/cbrt/Cbrt512Proof/lakefile.toml + formal/cbrt/Cbrt512Proof/lake-manifest.json + formal/cbrt/CbrtProof/**/*.lean + formal/cbrt/Cbrt512Proof/**/*.lean - name: Generate 512-bit EVMYulLean artifacts from compiled Cbrt512Wrapper Yul IR run: | @@ -111,16 +86,9 @@ jobs: --output formal/cbrt/CbrtProof/CbrtProof/FiniteCert.lean - name: Fetch proof dependency cache - working-directory: formal/cbrt/Cbrt512Proof - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get + uses: ./.github/actions/fetch-lean-cache + with: + working-directory: formal/cbrt/Cbrt512Proof - name: Build Cbrt512 proof package working-directory: formal/cbrt/Cbrt512Proof diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index 061e8f628..945f24ea2 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -18,6 +18,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/exp-formal.yml pull_request: paths: @@ -34,6 +36,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/exp-formal.yml jobs: @@ -44,52 +48,25 @@ jobs: with: submodules: recursive - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 + - name: Set up the formal toolchain + uses: ./.github/actions/setup-formal with: - version: v1.5.1 - - - name: Install pinned Lean toolchain - run: | - curl https://raw.githubusercontent.com/leanprover/elan/917c18d0ad52f649c2603dc8b973f5b9fa5f8f43/elan-init.sh -sSf | sh -s -- -y --default-toolchain none - echo "$HOME/.elan/bin" >> "$GITHUB_PATH" - LEAN_TOOLCHAIN="$(cat formal/exp/ExpProof/lean-toolchain)" - "$HOME/.elan/bin/elan" toolchain install "$LEAN_TOOLCHAIN" - "$HOME/.elan/bin/elan" default "$LEAN_TOOLCHAIN" - - - name: Restore Lean build cache - uses: actions/cache@v4 - with: - path: | - formal/yul/.lake/build - formal/yul/.lake/packages/*/.lake/build - lib/EVMYulLean/.lake/build + lean-toolchain-files: formal/exp/ExpProof/lean-toolchain + cache-name: exp-formal + cache-paths: | formal/common/.lake/build formal/ln/LnProof/.lake/build formal/exp/ExpProof/.lake/build - key: ${{ runner.os }}-exp-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/common/lakefile.toml', 'formal/common/lake-manifest.json', 'formal/common/**/*.lean', 'formal/ln/LnProof/lakefile.toml', 'formal/ln/LnProof/lake-manifest.json', 'formal/ln/LnProof/**/*.lean', 'formal/exp/ExpProof/lakefile.toml', 'formal/exp/ExpProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/exp/ExpProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} - restore-keys: | - ${{ runner.os }}-exp-formal-lean- - ${{ runner.os }}-formal-lean- - - - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol - env: - FOUNDRY_SOLC_VERSION: 0.8.34 - - - name: Fetch Mathlib cache - working-directory: formal/yul - run: | - # ProofWidgets release directories must exist for `lake exe cache get`. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get - - - name: Build Yul importer - working-directory: formal/yul - run: lake build FormalYul.Preservation yul_importer + cache-hash-globs: | + formal/common/lakefile.toml + formal/common/lake-manifest.json + formal/common/**/*.lean + formal/ln/LnProof/lakefile.toml + formal/ln/LnProof/lake-manifest.json + formal/ln/LnProof/**/*.lean + formal/exp/ExpProof/lakefile.toml + formal/exp/ExpProof/lake-manifest.json + formal/exp/ExpProof/**/*.lean - name: Generate EVMYulLean artifacts from compiled ExpWrapper Yul IR run: | @@ -103,14 +80,9 @@ jobs: uses: ./.github/actions/build-ln-proof - name: Fetch proof dependency cache - working-directory: formal/exp/ExpProof - run: | - # ProofWidgets release directories must exist for `lake exe cache get`. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get + uses: ./.github/actions/fetch-lean-cache + with: + working-directory: formal/exp/ExpProof - name: Generate Lean certificate artifacts working-directory: formal/exp/ExpProof diff --git a/.github/workflows/ln-formal.yml b/.github/workflows/ln-formal.yml index bf89292a3..11e67732e 100644 --- a/.github/workflows/ln-formal.yml +++ b/.github/workflows/ln-formal.yml @@ -14,6 +14,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/ln-formal.yml pull_request: paths: @@ -26,6 +28,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/ln-formal.yml jobs: @@ -36,51 +40,21 @@ jobs: with: submodules: recursive - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - - - name: Install pinned Lean toolchain - run: | - curl https://raw.githubusercontent.com/leanprover/elan/917c18d0ad52f649c2603dc8b973f5b9fa5f8f43/elan-init.sh -sSf | sh -s -- -y --default-toolchain none - echo "$HOME/.elan/bin" >> "$GITHUB_PATH" - LEAN_TOOLCHAIN="$(cat formal/ln/LnProof/lean-toolchain)" - "$HOME/.elan/bin/elan" toolchain install "$LEAN_TOOLCHAIN" - "$HOME/.elan/bin/elan" default "$LEAN_TOOLCHAIN" - - - name: Restore Lean build cache - uses: actions/cache@v4 + - name: Set up the formal toolchain + uses: ./.github/actions/setup-formal with: - path: | - formal/yul/.lake/build - formal/yul/.lake/packages/*/.lake/build - lib/EVMYulLean/.lake/build + lean-toolchain-files: formal/ln/LnProof/lean-toolchain + cache-name: ln-formal + cache-paths: | formal/common/.lake/build formal/ln/LnProof/.lake/build - key: ${{ runner.os }}-ln-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/common/lakefile.toml', 'formal/common/lake-manifest.json', 'formal/common/**/*.lean', 'formal/ln/LnProof/lakefile.toml', 'formal/ln/LnProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/ln/LnProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} - restore-keys: | - ${{ runner.os }}-ln-formal-lean- - ${{ runner.os }}-formal-lean- - - - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol - env: - FOUNDRY_SOLC_VERSION: 0.8.34 - - - name: Fetch Mathlib cache - working-directory: formal/yul - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get - - - name: Build Yul importer - working-directory: formal/yul - run: lake build FormalYul.Preservation yul_importer + cache-hash-globs: | + formal/common/lakefile.toml + formal/common/lake-manifest.json + formal/common/**/*.lean + formal/ln/LnProof/lakefile.toml + formal/ln/LnProof/lake-manifest.json + formal/ln/LnProof/**/*.lean - name: Build Ln proof package uses: ./.github/actions/build-ln-proof diff --git a/.github/workflows/sqrt-formal.yml b/.github/workflows/sqrt-formal.yml index 6a47e440e..961f0666f 100644 --- a/.github/workflows/sqrt-formal.yml +++ b/.github/workflows/sqrt-formal.yml @@ -14,6 +14,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/sqrt-formal.yml pull_request: paths: @@ -26,6 +28,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/sqrt-formal.yml jobs: @@ -36,50 +40,17 @@ jobs: with: submodules: recursive - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - - - name: Install pinned Lean toolchain - run: | - curl https://raw.githubusercontent.com/leanprover/elan/917c18d0ad52f649c2603dc8b973f5b9fa5f8f43/elan-init.sh -sSf | sh -s -- -y --default-toolchain none - echo "$HOME/.elan/bin" >> "$GITHUB_PATH" - LEAN_TOOLCHAIN="$(cat formal/sqrt/SqrtProof/lean-toolchain)" - "$HOME/.elan/bin/elan" toolchain install "$LEAN_TOOLCHAIN" - "$HOME/.elan/bin/elan" default "$LEAN_TOOLCHAIN" - - - name: Restore Lean build cache - uses: actions/cache@v4 + - name: Set up the formal toolchain + uses: ./.github/actions/setup-formal with: - path: | - formal/yul/.lake/build - formal/yul/.lake/packages/*/.lake/build - lib/EVMYulLean/.lake/build + lean-toolchain-files: formal/sqrt/SqrtProof/lean-toolchain + cache-name: sqrt-formal + cache-paths: | formal/sqrt/SqrtProof/.lake/build - key: ${{ runner.os }}-sqrt-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/sqrt/SqrtProof/lakefile.toml', 'formal/sqrt/SqrtProof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/sqrt/SqrtProof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} - restore-keys: | - ${{ runner.os }}-sqrt-formal-lean- - ${{ runner.os }}-formal-lean- - - - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol - env: - FOUNDRY_SOLC_VERSION: 0.8.34 - - - name: Fetch Mathlib cache - working-directory: formal/yul - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get - - - name: Build Yul importer - working-directory: formal/yul - run: lake build FormalYul.Preservation yul_importer + cache-hash-globs: | + formal/sqrt/SqrtProof/lakefile.toml + formal/sqrt/SqrtProof/lake-manifest.json + formal/sqrt/SqrtProof/**/*.lean - name: Generate EVMYulLean artifacts from compiled SqrtWrapper Yul IR run: | @@ -95,16 +66,9 @@ jobs: --output formal/sqrt/SqrtProof/SqrtProof/FiniteCert.lean - name: Fetch proof dependency cache - working-directory: formal/sqrt/SqrtProof - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get + uses: ./.github/actions/fetch-lean-cache + with: + working-directory: formal/sqrt/SqrtProof - name: Build Sqrt proof package working-directory: formal/sqrt/SqrtProof diff --git a/.github/workflows/sqrt512-formal.yml b/.github/workflows/sqrt512-formal.yml index 8bd9d9700..98d5e798b 100644 --- a/.github/workflows/sqrt512-formal.yml +++ b/.github/workflows/sqrt512-formal.yml @@ -21,6 +21,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/sqrt512-formal.yml pull_request: paths: @@ -40,6 +42,8 @@ on: - remappings.txt - .gitmodules - lib/EVMYulLean + - .github/actions/setup-formal/** + - .github/actions/fetch-lean-cache/** - .github/workflows/sqrt512-formal.yml jobs: @@ -50,52 +54,23 @@ jobs: with: submodules: recursive - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - - - name: Install pinned Lean toolchain - run: | - curl https://raw.githubusercontent.com/leanprover/elan/917c18d0ad52f649c2603dc8b973f5b9fa5f8f43/elan-init.sh -sSf | sh -s -- -y --default-toolchain none - echo "$HOME/.elan/bin" >> "$GITHUB_PATH" - LEAN_TOOLCHAIN="$(cat formal/sqrt/Sqrt512Proof/lean-toolchain)" - test "$LEAN_TOOLCHAIN" = "$(cat formal/sqrt/SqrtProof/lean-toolchain)" - "$HOME/.elan/bin/elan" toolchain install "$LEAN_TOOLCHAIN" - "$HOME/.elan/bin/elan" default "$LEAN_TOOLCHAIN" - - - name: Restore Lean build cache - uses: actions/cache@v4 + - name: Set up the formal toolchain + uses: ./.github/actions/setup-formal with: - path: | - formal/yul/.lake/build - formal/yul/.lake/packages/*/.lake/build - lib/EVMYulLean/.lake/build + lean-toolchain-files: | + formal/sqrt/Sqrt512Proof/lean-toolchain + formal/sqrt/SqrtProof/lean-toolchain + cache-name: sqrt512-formal + cache-paths: | formal/sqrt/SqrtProof/.lake/build formal/sqrt/Sqrt512Proof/.lake/build - key: ${{ runner.os }}-sqrt512-formal-lean-${{ hashFiles('formal/yul/lean-toolchain', 'formal/yul/lakefile.toml', 'formal/yul/lake-manifest.json', 'formal/sqrt/SqrtProof/lakefile.toml', 'formal/sqrt/SqrtProof/lake-manifest.json', 'formal/sqrt/Sqrt512Proof/lakefile.toml', 'formal/sqrt/Sqrt512Proof/lake-manifest.json', 'formal/yul/FormalYul/**/*.lean', 'formal/sqrt/SqrtProof/**/*.lean', 'formal/sqrt/Sqrt512Proof/**/*.lean', 'lib/EVMYulLean/**/*.lean') }} - restore-keys: | - ${{ runner.os }}-sqrt512-formal-lean- - ${{ runner.os }}-formal-lean- - - - name: Install solc 0.8.34 - run: forge build -- src/chains/Mainnet/TakerSubmitted.sol - env: - FOUNDRY_SOLC_VERSION: 0.8.34 - - - name: Fetch Mathlib cache - working-directory: formal/yul - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get - - - name: Build Yul importer - working-directory: formal/yul - run: lake build FormalYul.Preservation yul_importer + cache-hash-globs: | + formal/sqrt/SqrtProof/lakefile.toml + formal/sqrt/SqrtProof/lake-manifest.json + formal/sqrt/Sqrt512Proof/lakefile.toml + formal/sqrt/Sqrt512Proof/lake-manifest.json + formal/sqrt/SqrtProof/**/*.lean + formal/sqrt/Sqrt512Proof/**/*.lean - name: Generate 512-bit EVMYulLean artifacts from compiled Sqrt512Wrapper Yul IR run: | @@ -111,16 +86,9 @@ jobs: --output formal/sqrt/SqrtProof/SqrtProof/FiniteCert.lean - name: Fetch proof dependency cache - working-directory: formal/sqrt/Sqrt512Proof - run: | - # Mathlib's `cache get` fetches the ProofWidgets cloud release, then - # deletes its `lib`/`ir` outputs and fails if they are missing. Fetch - # the release and ensure those directories exist before it runs. - lake build proofwidgets:release - mkdir -p \ - .lake/packages/proofwidgets/.lake/build/lib \ - .lake/packages/proofwidgets/.lake/build/ir - lake exe cache get + uses: ./.github/actions/fetch-lean-cache + with: + working-directory: formal/sqrt/Sqrt512Proof - name: Build Sqrt512 proof package working-directory: formal/sqrt/Sqrt512Proof From 9d7cad5a158be704473fb95846a2749da5b76ede Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:31:57 +0200 Subject: [PATCH 110/149] Add exact-floor witnesses across the exp negative octaves Eight deterministic value witnesses spread over k = -1 through k = -60, the deepest octave above the clamp. floor(E) is computed with mpmath at 80 digits; every point has frac(E) > 0.09 while the deficit envelope at k <= -1 is below 1e-19 ulp, so each assertion is an exact equality rather than the two-wide bracket. Co-Authored-By: Claude Fable 5 --- test/0.8.34/Exp.t.sol | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 7f8265252..c4a652608 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -101,6 +101,28 @@ contract ExpTest is Test { } } + /// Exact value witnesses across the negative octaves, k = -1 down to k = -60 (the deepest + /// octave above the clamp). floor(E) computed with mpmath at 80 digits; every point has + /// frac(E) > 0.09 while the deficit envelope at k <= -1 is below 1e-19 ulp, so each result + /// is exactly floor(E). + function testExpRayToWadNegativeHalfExactFloor() external pure { + int256[8] memory xs = [ + int256(-1e27), // k = -1 + -1.5e27, // k = -2 + -5e27, // k = -7 + -10e27, // k = -14 + -20e27, // k = -29 + -30e27, // k = -43 + -40e27, // k = -58 + -41.3e27 // k = -60 + ]; + int256[8] memory floors = + [int256(367879441171442321), 223130160148429828, 6737946999085467, 45399929762484, 2061153622, 93576, 4, 1]; + for (uint256 i; i < xs.length; ++i) { + assertEq(Exp.expRayToWad(xs[i]), floors[i], "negative-half floor"); + } + } + /// The largest supported input, one below the revert threshold. floor(E) computed with /// mpmath at 80 digits; frac(E) ~= 0.74, comfortably inside the k = 63 deficit envelope. function testExpRayToWadSupportedEdge() external pure { From 3531403e71408f695a1e933ea8404679303f686a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:52:59 +0200 Subject: [PATCH 111/149] Refer to src/wrappers/ in AGENTS.md --- AGENTS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 8fc996801..09e962a64 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -75,7 +75,8 @@ src/ ├── deployer/ # Deployment infrastructure ├── multicall/ # ERC-2771 multicall forwarding ├── utils/ # Utilities (512Math, UnsafeMath, etc.) -└── vendor/ # Vendored libraries (SafeTransferLib, FullMath) +├── vendor/ # Vendored libraries (SafeTransferLib, FullMath) +└── wrappers/ # Minimal wrapper contracts for math libraries test/ ├── integration/ # Fork tests (run with FOUNDRY_PROFILE=integration) From cfdaa9329102baa32e3903750dcfac30d5b0cd4a Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:53:27 +0200 Subject: [PATCH 112/149] WIP: clean up slop --- src/vendor/Exp.sol | 156 ++++++++++++++++++++++----------------------- 1 file changed, 77 insertions(+), 79 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 91a5e6f9a..a13a24a4f 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -22,82 +22,79 @@ library Exp { r = _expRayToWad(x); } - /// @dev The supported-range kernel. Equivalent pseudocode; fixed-point truncations are - /// accounted for below: - /// k = round(x / (10²⁷⋅ln2)); // x = (k⋅ln2 + t)⋅10²⁷, |t| ≤ ln2/2 - /// t = x/10²⁷ - k⋅ln2; // reduced argument - /// e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) - /// r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; - /// r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 - /// return r + (x == 0); // pin exp(0) = 10¹⁸ exactly - /// - /// `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split N(t) = Ev(t²) - /// + t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational that matches - /// `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and Od degree 4; - /// in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the integer - /// coefficients realize ≈126 of them (the Q126 quotient). Ev is monic, so its leading - /// stage is a shift, not a multiply. - /// - /// Mixed fixed-point bases (a staircase): every quantity is rounded exactly once, and each - /// coefficient takes the widest basis fitting its chosen byte width, so a coefficient - /// followed by j more multiplies by v tolerates a shorter basis. - /// t: Q128 (one `sar` from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln2/2) - /// v = t²: Q128 (one `shr` by 128 from the Q256 product) - /// Ev Horner up the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) - /// Od Horner up the staircase Q105 → Q102 → Q93 → Q94 → Q87 - /// Ev, Od, t⋅Od, and the numerator/denominator: Q87 (the basis the closing quotient - /// shares) - /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend, numerator << 126, stays - /// below 2²⁵⁵: a nonnegative signed word) - /// output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing - /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in - /// - /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over - /// the exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the - /// tightest bound the proof technique can bear, in spite of the fact that the worst-case - /// error contributions do not co-occur. The proof bounds Δ ≤ 0.7201434073703092789, the - /// sum of three one-sided contributions: - /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + - /// t⋅Od and denominator Ev - t⋅Od cancels to first order in the quotient, so its - /// truncation barely perturbs e; this jitter (the dominant term) stays < - /// 0.62071. - /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and - /// exp): < 0.08839 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). - /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is - /// budgeted on the under side); the over side is the K27/LN2 constant-grid residue - /// (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly - /// at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = - /// √2/128). - /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 - /// at S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least - /// integer strictly above 2⁶³⋅S: 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1 = 720143407370309279 - /// (worth ≈ S ulp at k = 63; the +1 makes the never-over strict, which the round trip - /// below needs). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates). The under side is - /// bounded to the same precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 13/2, where 13/2 is the proven - /// sum of the integer-rational deficit (≤ 6001/1000, the Horner/`sdiv`/floor truncation - /// against the denominator), the `Mp` factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), and the - /// under-direction reduced-argument gap (≤ 37/100, via exp(t) ≤ √2). Hence the maximum - /// underestimation of the pre-floor accumulator A is E - A ≤ ((13/2)⋅10¹⁸ + margin)/2⁶³ ≈ - /// 0.78281 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The deficit envelope ((13/2)⋅10¹⁸ + - /// margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds 1ulp. On the central - /// octave k = 0 the margin is margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap - /// `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is - /// half-open, so the k = 0 band is exactly [-H, H] with H = ⌊10²⁷⋅ln2/2⌋, matching - /// `lnWadToRay`'s image over [1/√2, √2). - /// - /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves - /// the pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The error - /// terms above confine the accumulator to a band of width 10¹⁸⋅(Δ + 13/2) ≈ 7.2⋅10¹⁸ grid - /// units just below E's grid image at every octave (in grid units the band is - /// k-independent; an octave seam rescales E and the band together), so the per-step gain - /// exceeds any adverse swing within the band by more than nine orders of magnitude, and - /// the pre-floor accumulator strictly increases at every step; its floor is - /// non-decreasing. The zeroing clamp and the +1 pin preserve order: below C the result is - /// 0 while just above it ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket the - /// pinned scale-point value. + /// @dev The rational polynomial approximation kernel function _expRayToWad(int256 x) private pure returns (int256 r) { + // Equivalent pseudocode; fixed-point truncations are accounted for below: + // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln2 + t)⋅10²⁷, |t| ≤ ln2/2 + // t = x/10²⁷ - k⋅ln2; // reduced argument (Q128) + // e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) (Ev Q87; Od Q87; e Q126) + // r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; // wad + // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 + // return r + (x == 0); // pin exp(0) = 10¹⁸ exactly + // + // `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split N(t) = Ev(t²) + + // t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational that matches + // `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and Od degree 4; in + // exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the integer + // coefficients realize ≈126 of them. Ev is monic, so its leading stage is a shift, not a + // multiply. + // + // Mixed fixed-point bases (a staircase): each coefficient takes the widest basis fitting + // its chosen byte width, so a coefficient followed by j more multiplies by v tolerates a + // shorter basis. Each renormalizing shift lands a value directly at the basis its consumer + // needs. + // t: Q128 (one `SAR` from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln2/2) + // v = t²: Q128 (one `SHR` by 128 from the Q256 product) + // Ev Horner down the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) + // Od Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q87 + // Ev, Od, t⋅Od, and the numerator/denominator: Q87 + // quotient: one `SDIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays + // below 2²⁵⁵: a nonnegative signed word) + // output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing `sar(126 - k, + // …)` is the single output-rounding floor, with 2ᵏ folded in + // + // Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the + // exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the + // tightest bound the proof technique can bear, in spite of the fact that the worst-case + // error contributions do not co-occur. The proof bounds Δ ≤ 0.7201434073703092789, the sum + // of three one-sided contributions: + // integer Horner + closing `SDIV` truncation: the Ev shared by the numerator Ev + t⋅Od + // and denominator Ev - t⋅Od cancels to first order in the quotient, so its + // truncation barely perturbs e; this jitter stays < 0.62071. + // rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): + // < 0.08839 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). + // reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is + // budgeted on the under side); the over side is the K27/LN2 constant-grid residue + // (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly + // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = + // √2/128). + // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at + // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least + // integer strictly above 2⁶³⋅S: 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1 = 720143407370309279 + // (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never overestimate + // requirement). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E. The under side is bounded to the same precision: + // e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 13/2, where 13/2 is the proven sum of the integer-rational deficit + // (≤ 6001/1000, the Horner/`sdiv`/floor truncation against the denominator), the `Mp` + // factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), and the under-direction reduced-argument gap (≤ + // 37/100, via exp(t) ≤ √2). Hence the maximum underestimation of the pre-floor accumulator + // A is E - A ≤ ((13/2)⋅10¹⁸ + margin)/2⁶³ ≈ 0.78281 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - + // 1. The deficit envelope ((13/2)⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = + // 64 it exceeds 1ulp. On the central octave k = 0 the margin is margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ + // ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to + // ⌊E⌋. The k = 0 band is exactly [-H, H] with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s + // image over [1/√2, √2). + // + // Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves the + // pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The error terms + // above confine the accumulator to a band of width 10¹⁸⋅(Δ + 13/2) ≈ 7.2⋅10¹⁸ grid units + // just below E's grid image at every octave (in grid units the band is k-independent; an + // octave seam rescales E and the band together), so the per-step gain exceeds any adverse + // swing within the band by more than 9 orders of magnitude, and the pre-floor accumulator + // strictly increases at every step; its floor is non-decreasing. The zeroing clamp and the + // +1 pin at x = 0 preserve order: below C the result is 0 while just above it ⌊E⌋ ≥ 0, and + // the adjacent runtime values around x = 0 bracket the pinned scale-point value. assembly ("memory-safe") { - // k = round(x / (10²⁷⋅ln2)), half-open. CINV = round(2²⁰⁰ / (10²⁷⋅ln2)); the +2¹⁹⁹ + // k = round(x / (10²⁷⋅ln(2))), half-open. CINV = round(2²⁰⁰ / (10²⁷⋅ln(2))); the +2¹⁹⁹ // and `sar(200, …)` round to nearest with ties resolved toward +∞. let k := sar(0xc8, add(shl(0xc7, 0x01), mul(0x724d54edbacbebbb95c52a0f6076, x))) @@ -117,7 +114,7 @@ library Exp { // v = t² in Q128 (nonnegative; logical shift). let v := shr(0x80, mul(t, t)) - // Ev(v), monic, Horner up the staircase. The leading v⁵ coefficient is one, so the + // Ev(v), monic, Horner down the staircase. The leading v⁵ coefficient is 1, so the // first stage is a shift and an add, not a multiply. Both polynomials carry a common // scaling (the reciprocal of Ev's pre-normalization leading coefficient) that makes Ev // monic and cancels in the quotient below. @@ -127,7 +124,7 @@ library Exp { ev := add(0x93f11e65781741b92fa7fc4f4fffcca2, shr(0x86, mul(ev, v))) ev := add(0x4e14a45e8ec305e233e11b4174e214ac, shr(0x84, mul(ev, v))) - // Od(v), Horner up the staircase. + // Od(v), Horner down the staircase. let od := 0xdc07aff85e5bb5629d0fb64a84bb od := add(0xc926ddbf3830ca5561cc01585402d0, shr(0x83, mul(od, v))) od := add(0xad4506b00b1246c7e5b4fd33e1201b, shr(0x89, mul(od, v))) @@ -138,12 +135,13 @@ library Exp { // both positive. let tod := sar(0x80, mul(t, od)) - // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁵, the denominator > 0. + // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁵, the denominator > + // 0. r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum - // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` - // which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 186]). + // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - + // k, …)` which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 186]). r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x9fe769d0fa58e9f)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x From 46d670e59e09510017a3f9ec2cccc72d3f6e7a25 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 10:59:39 +0200 Subject: [PATCH 113/149] Carry v at Q123 so the exp monic stage is a bare add Q123 is the widest basis at which the monic-stage product ev*v stays inside 256 bits (Q124 overflows at |t| = H128), and sharing it between v and the lifted v^4 coefficient lets Ev's leading stage consume v with a single add: no multiply and no shift. Every consuming shift is rebased; the staircase bases from the second stage on are unchanged. The coarser argument grid costs a fourth one-sided budget term: the Q123 floor of t^2 lifts e by at most 2^3 * sup|de/dv| = 0.3287207024962306750 (supremum at t = ln2/2) on the over side and half that, by reciprocal symmetry, on the under side. The margin is the budget floor 0xe8e5059ce405bb2 = floor(10^18 * 1.0488641098665399539) + 1, keeping the 1/10 never-over strictness slack; the under budget becomes 67/10, leaving the k = 63 deficit envelope at 0.84013 < 1, so the revert threshold and all documented properties are unchanged. Verified against a 60-digit reference over a 20k-point sweep (never-over, floor-or-one-less, adjacent monotonicity) and by the unchanged unit-test witnesses; 9 gas and one byte of runtime code cheaper per the wrapper measurement. The Lean proof package still certifies the previous kernel; it is repaired separately. Co-Authored-By: Claude Fable 5 --- src/vendor/Exp.sol | 102 ++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 44 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 230ce39c0..31dac8aea 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -37,15 +37,19 @@ library Exp { /// N(t) = Ev(t²) + t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational /// that matches `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and /// Od degree 4; in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the - /// integer coefficients realize ≈126 of them (the Q126 quotient). Ev is monic, so its - /// leading stage is a shift, not a multiply. + /// integer coefficients realize ≈126 of them (the Q126 quotient). Ev is monic and its + /// leading coefficient literal is carried at v's own basis, so its leading stage is a + /// single add: no multiply and no shift. /// /// Mixed fixed-point bases (a staircase): every quantity is rounded exactly once, and each /// coefficient takes the widest basis fitting its chosen byte width, so a coefficient /// followed by j more multiplies by v tolerates a shorter basis. /// t: Q128 (one `sar` from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln2/2) - /// v = t²: Q128 (one `shr` by 128 from the Q256 product) - /// Ev Horner up the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) + /// v = t²: Q123 (one `shr` by 133 from the Q256 product); the widest basis whose + /// monic-stage product ev⋅v stays inside 256 bits, so Ev's leading stage + /// consumes v with no renormalizing shift + /// Ev Horner up the staircase Q123 → Q97 → Q97 → Q91 → Q87 (monic leading stage on + /// v's basis) /// Od Horner up the staircase Q105 → Q102 → Q93 → Q94 → Q87 /// Ev, Od, t⋅Od, and the numerator/denominator: Q87 (the basis the closing quotient shares) /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend, numerator << 126, stays @@ -54,47 +58,55 @@ library Exp { /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in /// /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the - /// exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The proof - /// bounds Δ ≤ 0.7201434073703092789 (each term below carried to its supremum at 19 decimal - /// places), the sum of three one-sided contributions: + /// exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The budget + /// bounds Δ ≤ 1.0488641098665399539 (each term below carried to its supremum at 19 decimal + /// places), the sum of four one-sided contributions: /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + t⋅Od /// and denominator Ev - t⋅Od cancels to first order in the quotient, so its - /// truncation barely perturbs e; this jitter (the dominant term) stays ≤ 0.6207065163. + /// truncation barely perturbs e; this jitter stays ≤ 0.6207065163. + /// argument granularity: v carries t² on the Q123 grid, and its floor only lowers the + /// polynomials' shared argument (by < 2⁻¹²³), which lifts e on the t > 0 half by + /// ≤ 0.3287207024962306750 = 2³⋅sup|∂e/∂v̂| (v̂ = v⋅2⁻¹²³; the sensitivity + /// supremum 0.0410900878… sits at t = ln2/2). The t < 0 direction is budgeted + /// on the under side. /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): /// ≤ 0.0883883477 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction /// is budgeted on the under side); the over side is the K27/LN2 constant-grid - /// residue (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes - /// one-sidedly at 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 + /// residue (the k⋅ln2 grid error stays below 2⁻²²⁹), enveloped one-sidedly at + /// 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 /// (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0781 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer - /// strictly above 2⁶³⋅S: 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1 = 720143407370309279 (worth ≈ S ulp + /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1137 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer + /// strictly above 2⁶³⋅S: 0xe8e5059ce405bb2 = ⌊10¹⁸⋅Δ⌋ + 1 = 1048864109866539954 (worth ≈ S ulp /// at k = 63; the +1 makes the never-over strict, which the round trip below needs). So /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates). The under side is bounded to the same - /// precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 13/2, where 13/2 is the proven sum of the integer-rational + /// precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 67/10, where 67/10 bounds the sum of the integer-rational /// deficit (≤ 6001/1000, the Horner/`sdiv`/floor truncation against the denominator), the `Mp` - /// factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), and the under-direction reduced-argument gap (≤ 37/100, - /// via exp(t) ≤ √2). Hence the maximum underestimation of the pre-floor accumulator A is - /// E - A ≤ ((13/2)⋅10¹⁸ + margin)/2⁶³ ≈ 0.78281 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the + /// factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), the under-direction reduced-argument gap (≤ 37/100, + /// via exp(t) ≤ √2), and the under-direction argument granularity (≤ 17/100: the over-side + /// supremum divided by e^(ln2) = 2, by reciprocal symmetry). Hence the maximum + /// underestimation of the pre-floor accumulator A is + /// E - A ≤ ((67/10)⋅10¹⁸ + margin)/2⁶³ ≈ 0.84013 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the /// 1-ulp underestimate is achieved, ⌊E⌋ - 2 never occurs). The deficit envelope - /// ((13/2)⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp + /// ((67/10)⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp /// and the floor can fall two below E; that input is reverted. On the central octave k = 0 the - /// margin is margin⋅2⁻¹²⁶ ≈ 8.5⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so + /// margin is margin⋅2⁻¹²⁶ ≈ 1.2⋅10⁻²⁰ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so /// the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is /// exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). /// - /// This margin is the floor of the bound above: Δ's two √2-driven terms are irrational, so Δ - /// itself is irrational and the margin ⌊10¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering Δ. The - /// dominant truncation term (≈0.62, the affine envelope of the integer Horner) is ≈1.6× the - /// empirically observed jitter; closing that gap is not reachable by the linear bound and - /// would need either round-to-nearest Horner stages (more gas and code) or a number-theoretic - /// bound on the fractional part of E, so the margin rests here. + /// This margin is the floor of the bound above: Δ's √2-driven terms and its ln2-edge + /// sensitivity supremum are irrational, so Δ itself is irrational and the margin + /// ⌊10¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering Δ. The truncation term (≈0.62, the + /// affine envelope of the integer Horner) is ≈1.6× the empirically observed jitter; + /// closing that gap is not reachable by the linear bound and would need either + /// round-to-nearest Horner stages (more gas and code) or a number-theoretic bound on the + /// fractional part of E, so the margin rests here. /// /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves /// the pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The - /// error terms above confine the accumulator to a band of width 10¹⁸⋅(Δ + 13/2) ≈ - /// 7.2⋅10¹⁸ grid units just below E's grid image at every octave (in grid units the band + /// error terms above confine the accumulator to a band of width 10¹⁸⋅(Δ + 67/10) ≈ + /// 7.7⋅10¹⁸ grid units just below E's grid image at every octave (in grid units the band /// is k-independent; an octave seam rescales E and the band together), so the per-step /// gain exceeds any adverse swing within the band by more than nine orders of magnitude, /// and the pre-floor accumulator strictly increases at every step; its floor @@ -120,25 +132,27 @@ library Exp { ) ) - // v = t² in Q128 (nonnegative; logical shift). - let v := shr(0x80, mul(t, t)) + // v = t² in Q123 (nonnegative; logical shift): the widest basis at which the + // monic-stage product below stays inside 256 bits. + let v := shr(0x85, mul(t, t)) - // Ev(v), monic, Horner up the staircase. The leading v⁵ coefficient is one, so the - // first stage is a shift and an add, not a multiply. Both polynomials carry a common - // scaling (the reciprocal of Ev's pre-normalization leading coefficient) that makes Ev - // monic and cancels in the quotient below. - let ev := add(0xb9aacfad41060587203a79af0ebc, shr(0x1d, v)) - ev := add(0x9a036222e11aee18465042f8ea64c8, shr(0x82, mul(ev, v))) - ev := add(0x9064d965e1c4863b73604e0ddbec53f9, shr(0x80, mul(ev, v))) - ev := add(0x93f11e65781741b92fa7fc4f4fffcca2, shr(0x86, mul(ev, v))) - ev := add(0x4e14a45e8ec305e233e11b4174e214ac, shr(0x84, mul(ev, v))) + // Ev(v), monic, Horner up the staircase. The leading v⁵ coefficient is one and the + // v⁴ coefficient literal is carried at v's own Q123 basis, so the first stage is a + // single add. Both polynomials carry a common scaling (the reciprocal of Ev's + // pre-normalization leading coefficient) that makes Ev monic and cancels in the + // quotient below. + let ev := add(0xb9aacfad41060587203a79af0ebc000000, v) + ev := add(0x9a036222e11aee18465042f8ea64c8, shr(0x95, mul(ev, v))) + ev := add(0x9064d965e1c4863b73604e0ddbec53f9, shr(0x7b, mul(ev, v))) + ev := add(0x93f11e65781741b92fa7fc4f4fffcca2, shr(0x81, mul(ev, v))) + ev := add(0x4e14a45e8ec305e233e11b4174e214ac, shr(0x7f, mul(ev, v))) // Od(v), Horner up the staircase. let od := 0xdc07aff85e5bb5629d0fb64a84bb - od := add(0xc926ddbf3830ca5561cc01585402d0, shr(0x83, mul(od, v))) - od := add(0xad4506b00b1246c7e5b4fd33e1201b, shr(0x89, mul(od, v))) - od := add(0xaf5662483c4ce783a9ef5fe025f42e9e, shr(0x7f, mul(od, v))) - od := add(0x270a522f476182f119f08da0ba710a56, shr(0x87, mul(od, v))) + od := add(0xc926ddbf3830ca5561cc01585402d0, shr(0x7e, mul(od, v))) + od := add(0xad4506b00b1246c7e5b4fd33e1201b, shr(0x84, mul(od, v))) + od := add(0xaf5662483c4ce783a9ef5fe025f42e9e, shr(0x7a, mul(od, v))) + od := add(0x270a522f476182f119f08da0ba710a56, shr(0x82, mul(od, v))) // t⋅Od in Q87 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are // both positive. @@ -147,10 +161,10 @@ library Exp { // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁶, the denominator > 0. r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) - // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum - // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` + // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin + // (0xe8e5059ce405bb2 = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` // which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 187]). - r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x9fe769d0fa58e9f)) + r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xe8e5059ce405bb2)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs From 0429f666cf15f57c628b955de0c405b1446d39ad Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 11:42:43 +0200 Subject: [PATCH 114/149] Carry the exp rational at full staircase precision; tighten the margin The ten coefficients are the fully converged relative-error minimax of the reciprocal-symmetric (4,5) rational (level 2.19e-41, ~135 bits), rounded at the staircase bases -- the monic-stage coefficient now carries all of Q123 -- with the low bits then chosen jointly to re-center the ten quantization residuals. The realized envelope 2^126*|e - exp(t)| equioscillates at +/-0.0188 ulp (~131 bits realized), 3x tighter than plain rounding permits, and fits the Mp cut nudge at 2^-131 with 2.4x slack. Halving the nudge lowers the Mp budget term to 0.0441941739 and the margin to 0xdf14dfbde520dbe = floor(10^18 * 1.0046699360423807336) + 1, keeping never-over strictness; the under-side Mp term drops to 1/20 and the k = 63 deficit envelope to 0.83535 < 1. Every documented property, witness, and byte width is unchanged; verified by a 60-digit 20k-point sweep (never-over, floor-or-one-less, adjacent monotonicity) and the unit suite. Co-Authored-By: Claude Fable 5 --- src/vendor/Exp.sol | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 31dac8aea..52fad1819 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -37,7 +37,9 @@ library Exp { /// N(t) = Ev(t²) + t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational /// that matches `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and /// Od degree 4; in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the - /// integer coefficients realize ≈126 of them (the Q126 quotient). Ev is monic and its + /// integer coefficients realize ≈131 of them (the Q126 quotient): each coefficient's low bits + /// are chosen jointly, after rounding at the staircase bases, to re-center the ten + /// quantization residuals, holding the realized envelope at ≤ 0.019 ulp. Ev is monic and its /// leading coefficient literal is carried at v's own basis, so its leading stage is a /// single add: no multiply and no shift. /// @@ -59,7 +61,7 @@ library Exp { /// /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the /// exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The budget - /// bounds Δ ≤ 1.0488641098665399539 (each term below carried to its supremum at 19 decimal + /// bounds Δ ≤ 1.0046699360423807336 (each term below carried to its supremum at 19 decimal /// places), the sum of four one-sided contributions: /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + t⋅Od /// and denominator Ev - t⋅Od cancels to first order in the quotient, so its @@ -70,24 +72,24 @@ library Exp { /// supremum 0.0410900878… sits at t = ln2/2). The t < 0 direction is budgeted /// on the under side. /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): - /// ≤ 0.0883883477 (its supremum is √2⋅2¹²⁶/(2¹³⁰-1)). + /// ≤ 0.0441941739 (its supremum is √2⋅2¹²⁶/(2¹³¹-1)). /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction /// is budgeted on the under side); the over side is the K27/LN2 constant-grid /// residue (the k⋅ln2 grid error stays below 2⁻²²⁹), enveloped one-sidedly at /// 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 /// (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1137 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer - /// strictly above 2⁶³⋅S: 0xe8e5059ce405bb2 = ⌊10¹⁸⋅Δ⌋ + 1 = 1048864109866539954 (worth ≈ S ulp + /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1089 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer + /// strictly above 2⁶³⋅S: 0xdf14dfbde520dbe = ⌊10¹⁸⋅Δ⌋ + 1 = 1004669936042380734 (worth ≈ S ulp /// at k = 63; the +1 makes the never-over strict, which the round trip below needs). So /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates). The under side is bounded to the same /// precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 67/10, where 67/10 bounds the sum of the integer-rational /// deficit (≤ 6001/1000, the Horner/`sdiv`/floor truncation against the denominator), the `Mp` - /// factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), the under-direction reduced-argument gap (≤ 37/100, + /// factor (≤ 1/20, via e ≤ 1.45·2¹²⁶), the under-direction reduced-argument gap (≤ 37/100, /// via exp(t) ≤ √2), and the under-direction argument granularity (≤ 17/100: the over-side /// supremum divided by e^(ln2) = 2, by reciprocal symmetry). Hence the maximum /// underestimation of the pre-floor accumulator A is - /// E - A ≤ ((67/10)⋅10¹⁸ + margin)/2⁶³ ≈ 0.84013 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the + /// E - A ≤ ((67/10)⋅10¹⁸ + margin)/2⁶³ ≈ 0.83535 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the /// 1-ulp underestimate is achieved, ⌊E⌋ - 2 never occurs). The deficit envelope /// ((67/10)⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp /// and the floor can fall two below E; that input is reverted. On the central octave k = 0 the @@ -141,18 +143,18 @@ library Exp { // single add. Both polynomials carry a common scaling (the reciprocal of Ev's // pre-normalization leading coefficient) that makes Ev monic and cancels in the // quotient below. - let ev := add(0xb9aacfad41060587203a79af0ebc000000, v) - ev := add(0x9a036222e11aee18465042f8ea64c8, shr(0x95, mul(ev, v))) - ev := add(0x9064d965e1c4863b73604e0ddbec53f9, shr(0x7b, mul(ev, v))) - ev := add(0x93f11e65781741b92fa7fc4f4fffcca2, shr(0x81, mul(ev, v))) - ev := add(0x4e14a45e8ec305e233e11b4174e214ac, shr(0x7f, mul(ev, v))) + let ev := add(0xb9aacfacf3c10b378435f8e22adf48500e, v) + ev := add(0x9a036222841f47c6ed6fc3f7602053, shr(0x95, mul(ev, v))) + ev := add(0x9064d9657e9a21fc16bb69331c5c3057, shr(0x7b, mul(ev, v))) + ev := add(0x93f11e650dd6c64b96ce79065cdf809e, shr(0x81, mul(ev, v))) + ev := add(0x4e14a45e5650b506e97f4c5da23861e2, shr(0x7f, mul(ev, v))) // Od(v), Horner up the staircase. - let od := 0xdc07aff85e5bb5629d0fb64a84bb - od := add(0xc926ddbf3830ca5561cc01585402d0, shr(0x7e, mul(od, v))) - od := add(0xad4506b00b1246c7e5b4fd33e1201b, shr(0x84, mul(od, v))) - od := add(0xaf5662483c4ce783a9ef5fe025f42e9e, shr(0x7a, mul(od, v))) - od := add(0x270a522f476182f119f08da0ba710a56, shr(0x82, mul(od, v))) + let od := 0xdc07aff8276bde9a361278df6a10 + od := add(0xc926ddbecdeeb42e68cd16db7da8c1, shr(0x7e, mul(od, v))) + od := add(0xad4506af99be27419341e1816ff351, shr(0x84, mul(od, v))) + od := add(0xaf566247c05753b42892f77b67a6b7c6, shr(0x7a, mul(od, v))) + od := add(0x270a522f2b285a8374bfa62ed11c30f1, shr(0x82, mul(od, v))) // t⋅Od in Q87 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are // both positive. @@ -162,9 +164,9 @@ library Exp { r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin - // (0xe8e5059ce405bb2 = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` + // (0xdf14dfbde520dbe = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` // which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 187]). - r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xe8e5059ce405bb2)) + r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xdf14dfbde520dbe)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs From bc6b64eeeb5729223c88b839a2c7ed3e099c487b Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 11:45:17 +0200 Subject: [PATCH 115/149] Document the fixed-point rational coefficient derivation pipeline The three-step method behind the Ln.sol/Exp.sol constants: converged weighted rational Remez (with the consumer-metric weight and coefficient-level convergence), staircase quantization at byte-width-widest bases, and joint integer low-bit refinement of the quantization residuals via linearized sensitivity curves. Includes the verification bar each step must clear before the margin constant is derived. Co-Authored-By: Claude Fable 5 --- formal/README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/formal/README.md b/formal/README.md index 8f328154f..3b041cbeb 100644 --- a/formal/README.md +++ b/formal/README.md @@ -20,6 +20,58 @@ Machine-checked Lean 4 correctness proofs for root math libraries in 0x Settler. 3. **The `formal/yul` Lake importer** consumes `forge inspect ... ir` output and emits ignored EVMYulLean runtime/proof modules. 4. **Runtime bridge modules** execute ABI calls through EVMYulLean against the Yul emitted by solc. The implementation is Solidity; Lean proof machinery consumes the generated Yul artifacts rather than a second hand-maintained model. +## Deriving the fixed-point rational coefficients + +The polynomial/rational coefficients in `Ln.sol` and `Exp.sol` (and their error margins) +come from a three-step pipeline. Exact minimax fitting alone is not enough: rounding an +optimal real-coefficient rational at the mixed fixed-point staircase bases re-rolls ten +independent quantization residuals and typically triples the realized error, so the +integer low bits are re-optimized jointly after rounding. + +1. **Converged weighted rational Remez** ([Bloemen's scheme](https://xn--2-umb.com/22/approximation/)): + fit the target under the weight that the consumer's error metric induces. For + `expRayToWad`, `Od(v)/Ev(v) ≈ tanh(√v/2)/√v` on `v ∈ [0, (ln2/2)²]` under + `w(v) = 2√v·cosh²(√v/2)`, the pushforward of the relative error of + `(Ev + t·Od)/(Ev − t·Od)` against `exp(t)`. Each iteration solves the linearized + equioscillation system at the current alternation nodes, closing on the level `e` + with a root find: + + ```python + # nodes x[i], signs s[i], weights w[i]; unknowns: p, q (q0 = 1), level e + # p(x_i) − (f(x_i) + s_i·e/w_i)·(q(x_i) − 1) = f(x_i) + s_i·e/w_i + e = findroot(lambda e: solve_linear(e)[2] - e, e0) # e_out = e_in at the optimum + ``` + + Iterate node exchange until the *coefficients* converge, not merely the level: the + leading coefficient lies along a near-null direction of the objective (its monomial + contributes ~`4e-17` of the polynomial's value on the domain) and settles orders of + magnitude later than `e`. + +2. **Staircase quantization**: round each real coefficient to nearest at its staircase + basis — the widest basis whose literal fits the chosen byte width, with the leading + (monic-stage) coefficient carried at `v`'s own basis so that stage needs no + renormalizing shift. + +3. **Joint low-bit refinement**: the realized error is linear in per-coefficient grain + offsets `n_i`, so precompute the base error curve and one sensitivity curve per + coefficient once in high precision, then search the integer offsets in fast float + arithmetic: + + ```python + err(t; n) = base(t) + Σ_i n_i·φ_i(t), φ_i(t) = ∂ê/∂c_i · 2^(126−b_i) # Q126 ulps + minimize over n ∈ ℤ^10: max(max_t err, −min_t err) # coordinate + pair descent + ``` + + Low-degree coefficients dominate (one grain of a Q87 constant term moves the quotient + by ~0.3–0.8 ulp); the descent needs paired moves because single-coefficient steps are + too coarse near the optimum. The refined ensemble equioscillates in the max metric — + for `Exp.sol`, at ±0.019 ulp against plain rounding's ~0.35 — which is what lets the + certificate's dyadic nudge (and with it the subtracted output margin) tighten. + +Every step is re-verified against the exact target at ≥60 digits on a dense grid, and +the resulting envelope must clear the proof's cut-certificate nudge with slack before +the margin constant is derived from the error budget. + ## Build Generated EVMYulLean artifacts (`*YulRuntime.lean`, `*YulProof.lean`) are `.gitignore`d and regenerated in CI. See `.github/workflows/*-formal.yml` for the canonical build steps. From d5d72ca8daece1afec16c0add1cc30c9b8d6b78e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 12:02:15 +0200 Subject: [PATCH 116/149] WIP: clean up slop --- src/vendor/Exp.sol | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index a13a24a4f..6f2914059 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -48,7 +48,7 @@ library Exp { // Ev Horner down the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) // Od Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q87 // Ev, Od, t⋅Od, and the numerator/denominator: Q87 - // quotient: one `SDIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays + // quotient: one `DIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays // below 2²⁵⁵: a nonnegative signed word) // output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing `sar(126 - k, // …)` is the single output-rounding floor, with 2ᵏ folded in @@ -58,7 +58,7 @@ library Exp { // tightest bound the proof technique can bear, in spite of the fact that the worst-case // error contributions do not co-occur. The proof bounds Δ ≤ 0.7201434073703092789, the sum // of three one-sided contributions: - // integer Horner + closing `SDIV` truncation: the Ev shared by the numerator Ev + t⋅Od + // integer Horner + closing `DIV` truncation: the Ev shared by the numerator Ev + t⋅Od // and denominator Ev - t⋅Od cancels to first order in the quotient, so its // truncation barely perturbs e; this jitter stays < 0.62071. // rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): @@ -74,7 +74,7 @@ library Exp { // (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never overestimate // requirement). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E. The under side is bounded to the same precision: // e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 13/2, where 13/2 is the proven sum of the integer-rational deficit - // (≤ 6001/1000, the Horner/`sdiv`/floor truncation against the denominator), the `Mp` + // (≤ 6001/1000, the Horner/`DIV`/floor truncation against the denominator), the `Mp` // factor (≤ 1/10, via e ≤ 1.45·2¹²⁶), and the under-direction reduced-argument gap (≤ // 37/100, via exp(t) ≤ √2). Hence the maximum underestimation of the pre-floor accumulator // A is E - A ≤ ((13/2)⋅10¹⁸ + margin)/2⁶³ ≈ 0.78281 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - @@ -101,7 +101,7 @@ library Exp { // t in Q128. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln2 ⋅ 2²³⁵). Subtracting k ⋅ LN2 // from K27 ⋅ x at the Q235 product basis (so the k ⋅ ln2 rounding error is ~2⁻²³⁵, far // below an output ulp) then one `sar(107, …)` leaves the reduced argument at Q128. - // Carrying ln2 in a single wide word matches the op count of a Q128 reduction. + // Carrying ln(2) in a single wide word matches the op count of a Q128 reduction. let t := sar( 0x6b, @@ -115,9 +115,7 @@ library Exp { let v := shr(0x80, mul(t, t)) // Ev(v), monic, Horner down the staircase. The leading v⁵ coefficient is 1, so the - // first stage is a shift and an add, not a multiply. Both polynomials carry a common - // scaling (the reciprocal of Ev's pre-normalization leading coefficient) that makes Ev - // monic and cancels in the quotient below. + // first stage is a shift and an add, not a multiply. let ev := add(0xb9aacfad41060587203a79af0ebc, shr(0x1d, v)) ev := add(0x9a036222e11aee18465042f8ea64c8, shr(0x82, mul(ev, v))) ev := add(0x9064d965e1c4863b73604e0ddbec53f9, shr(0x80, mul(ev, v))) @@ -137,7 +135,7 @@ library Exp { // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁵, the denominator > // 0. - r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) + r := div(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - From 32120e58d7609c8505f025f1d5d8b725aa42f61e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 12:06:08 +0200 Subject: [PATCH 117/149] Set the exp margin at the certifiable granularity envelope The argument-granularity budget term must be a bound a finite certificate can close, not the bare pointwise supremum. One v-grain moves the quotient by exactly 2t*(Od*dEv - Ev*dOd)/(D*D'); the step combination is coefficient-wise one-signed (maximal at the domain edge) while D dips at an interior point, so the certified envelope takes the numerator at v_max over a global denominator floor: 0.3395595387735630095 over (pointwise supremum 0.3287), 0.1685843742692980488 <= 17/100 under. The margin is the budget floor 0xe17cfd91868d72d = floor(10^18 * 1.0155087723197130681) + 1; the k = 63 deficit envelope is 0.83652 < 1 and every documented property, witness, and byte width is unchanged (60-digit sweep re-run; unit suite green). Co-Authored-By: Claude Fable 5 --- src/vendor/Exp.sol | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 52fad1819..20be17db7 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -61,16 +61,18 @@ library Exp { /// /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the /// exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The budget - /// bounds Δ ≤ 1.0046699360423807336 (each term below carried to its supremum at 19 decimal + /// bounds Δ ≤ 1.0155087723197130681 (each term below carried to its supremum at 19 decimal /// places), the sum of four one-sided contributions: /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + t⋅Od /// and denominator Ev - t⋅Od cancels to first order in the quotient, so its /// truncation barely perturbs e; this jitter stays ≤ 0.6207065163. /// argument granularity: v carries t² on the Q123 grid, and its floor only lowers the /// polynomials' shared argument (by < 2⁻¹²³), which lifts e on the t > 0 half by - /// ≤ 0.3287207024962306750 = 2³⋅sup|∂e/∂v̂| (v̂ = v⋅2⁻¹²³; the sensitivity - /// supremum 0.0410900878… sits at t = ln2/2). The t < 0 direction is budgeted - /// on the under side. + /// ≤ 0.3395595387735630095: one v-grain moves the quotient by + /// 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose one-signed numerator is maximal at the + /// domain edge and whose denominator is floored globally (the pointwise + /// supremum is ≈ 0.3287 at t = ln2/2). The t < 0 direction is budgeted on + /// the under side. /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): /// ≤ 0.0441941739 (its supremum is √2⋅2¹²⁶/(2¹³¹-1)). /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction @@ -79,17 +81,17 @@ library Exp { /// 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 /// (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1089 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer - /// strictly above 2⁶³⋅S: 0xdf14dfbde520dbe = ⌊10¹⁸⋅Δ⌋ + 1 = 1004669936042380734 (worth ≈ S ulp + /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1101 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer + /// strictly above 2⁶³⋅S: 0xe17cfd91868d72d = ⌊10¹⁸⋅Δ⌋ + 1 = 1015508772319713069 (worth ≈ S ulp /// at k = 63; the +1 makes the never-over strict, which the round trip below needs). So /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates). The under side is bounded to the same /// precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 67/10, where 67/10 bounds the sum of the integer-rational /// deficit (≤ 6001/1000, the Horner/`sdiv`/floor truncation against the denominator), the `Mp` /// factor (≤ 1/20, via e ≤ 1.45·2¹²⁶), the under-direction reduced-argument gap (≤ 37/100, - /// via exp(t) ≤ √2), and the under-direction argument granularity (≤ 17/100: the over-side - /// supremum divided by e^(ln2) = 2, by reciprocal symmetry). Hence the maximum + /// via exp(t) ≤ √2), and the under-direction argument granularity (≤ 17/100, the same + /// one-grain envelope with the negative-half denominator floor). Hence the maximum /// underestimation of the pre-floor accumulator A is - /// E - A ≤ ((67/10)⋅10¹⁸ + margin)/2⁶³ ≈ 0.83535 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the + /// E - A ≤ ((67/10)⋅10¹⁸ + margin)/2⁶³ ≈ 0.83652 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the /// 1-ulp underestimate is achieved, ⌊E⌋ - 2 never occurs). The deficit envelope /// ((67/10)⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp /// and the floor can fall two below E; that input is reverted. On the central octave k = 0 the @@ -164,9 +166,9 @@ library Exp { r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin - // (0xdf14dfbde520dbe = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` + // (0xe17cfd91868d72d = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` // which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 187]). - r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xdf14dfbde520dbe)) + r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xe17cfd91868d72d)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs From 053090fdc86370ba26039391ff39ff18845390ed Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 12:19:55 +0200 Subject: [PATCH 118/149] State the exact Ln bias margin The one-sided bias margin implied by the shipped literal is 1.5976e21 Q72 units = 0.33830 ulp (ideal bias (ln(s/2^95) + 95 ln2 - 18 ln10) * 10^27 * 2^72 minus the constant); the comment said ~1.607e21 (0.3403). The downward-error total under the exact figure is 0.6964 < 0.699, as required. Co-Authored-By: Claude Fable 5 --- src/vendor/Ln.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vendor/Ln.sol b/src/vendor/Ln.sol index c4a3062e9..19617b6a4 100644 --- a/src/vendor/Ln.sol +++ b/src/vendor/Ln.sol @@ -50,7 +50,7 @@ library Ln { // approximation and coefficient quantization ≤0.327 combined; mantissa (Q95) truncation // ≤2⁻⁹⁵⋅10²⁷ ≈ 0.026 (downward only); z, u, and `SDIV` truncations ≤0.005 combined; Horner // stage truncations ≤10⁻⁴; ln(2) and bias constant rounding ≤10⁻¹⁹. The bias is reduced by - // a margin of ~1.607⋅10²¹ units (0.3403 ulp), so the Q72 accumulator never exceeds L⋅2⁷²; + // a margin of ~1.598⋅10²¹ units (0.3383 ulp), so the Q72 accumulator never exceeds L⋅2⁷²; // margin plus downward errors total < 0.699 ⋅ 2⁷², so it always exceeds (L-1)⋅2⁷². // `sar(72, …)` therefore yields ⌊L⌋ or ⌊L⌋ - 1. // From 5d22714355563cfa21703bcf1049d88a2d843b38 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 13:54:29 +0200 Subject: [PATCH 119/149] WIP: clean up slop --- src/vendor/Exp.sol | 30 +++++++++++++++--------------- src/vendor/Ln.sol | 10 +++++----- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 6f2914059..4d0041926 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -25,28 +25,29 @@ library Exp { /// @dev The rational polynomial approximation kernel function _expRayToWad(int256 x) private pure returns (int256 r) { // Equivalent pseudocode; fixed-point truncations are accounted for below: - // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln2 + t)⋅10²⁷, |t| ≤ ln2/2 - // t = x/10²⁷ - k⋅ln2; // reduced argument (Q128) - // e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) (Ev Q87; Od Q87; e Q126) - // r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; // wad - // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 - // return r + (x == 0); // pin exp(0) = 10¹⁸ exactly + // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln2 + t)⋅10²⁷, |t| ≤ ln2/2 + // t = x/10²⁷ - k⋅ln2; // reduced argument (Q128) + // e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) (Ev Q87; Od Q87; e Q126) + // r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; // wad + // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 + // return r + (x == 0); // pin exp(0) = 10¹⁸ exactly // // `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split N(t) = Ev(t²) + // t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational that matches - // `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln2/2)²]. Ev is degree 5 and Od degree 4; in - // exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the integer - // coefficients realize ≈126 of them. Ev is monic, so its leading stage is a shift, not a + // `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln(2)/2)²]. Ev(v) is degree 5 and Od degree + // 4(v); in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the integer + // coefficients realize ≈126 of them. Ev(v) is monic, so its leading stage is a shift, not a // multiply. // // Mixed fixed-point bases (a staircase): each coefficient takes the widest basis fitting // its chosen byte width, so a coefficient followed by j more multiplies by v tolerates a // shorter basis. Each renormalizing shift lands a value directly at the basis its consumer // needs. - // t: Q128 (one `SAR` from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln2/2) - // v = t²: Q128 (one `SHR` by 128 from the Q256 product) - // Ev Horner down the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at Q99) - // Od Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q87 + // t: Q128 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2) + // v = t²: Q128 + // Ev(v) Horner down the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at + // Q99) + // Od(v) Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q87 // Ev, Od, t⋅Od, and the numerator/denominator: Q87 // quotient: one `DIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays // below 2²⁵⁵: a nonnegative signed word) @@ -98,10 +99,9 @@ library Exp { // and `sar(200, …)` round to nearest with ties resolved toward +∞. let k := sar(0xc8, add(shl(0xc7, 0x01), mul(0x724d54edbacbebbb95c52a0f6076, x))) - // t in Q128. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln2 ⋅ 2²³⁵). Subtracting k ⋅ LN2 + // t in Q128. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln(2) ⋅ 2²³⁵). Subtracting k ⋅ LN2 // from K27 ⋅ x at the Q235 product basis (so the k ⋅ ln2 rounding error is ~2⁻²³⁵, far // below an output ulp) then one `sar(107, …)` leaves the reduced argument at Q128. - // Carrying ln(2) in a single wide word matches the op count of a Q128 reduction. let t := sar( 0x6b, diff --git a/src/vendor/Ln.sol b/src/vendor/Ln.sol index eb061d3f9..7da71a4ce 100644 --- a/src/vendor/Ln.sol +++ b/src/vendor/Ln.sol @@ -20,10 +20,10 @@ library Ln { // Equivalent pseudocode; fixed-point truncations are accounted for below: // require(x > 0); - // k = ⌊log₂(x)⌋ - 95; // x = m ⋅ 2ᵏ, m ∈ [2⁹⁵, 2⁹⁶) - // m = x / 2ᵏ; // Q95 fixnum ∈ [1, 2) - // z = (s - m) / (m + s); // s = √2 ⋅ 2⁹⁵; |z| ≤ 3 - 2√2 - // h = atanh(-z) = (p(z²) ⋅ z) / q(z²); // ln(m / 2⁹⁵) = 2h + ln(s / 2⁹⁵) + // k = ⌊log₂(x)⌋ - 95; // x = m ⋅ 2ᵏ, m ∈ [2⁹⁵, 2⁹⁶) + // m = x / 2ᵏ; // Q95 fixnum ∈ [1, 2) + // z = (s - m) / (m + s); // s = √2 ⋅ 2⁹⁵; |z| ≤ 3 - 2√2 + // h = atanh(-z) = (p(z²) ⋅ z) / q(z²); // ln(m / 2⁹⁵) = 2h + ln(s / 2⁹⁵) // r = ⌊10²⁷ ⋅ (2h + ln(s) + k⋅ln(2) - 18⋅ln(10)) - margin⌋ // return r + (r = -1); // @@ -35,7 +35,7 @@ library Ln { // error of the integer-rounded rational 2⋅√u⋅|p/-q - f|⋅10²⁷ is ≤0.327ulp. // // Mixed fixed-point bases, chosen so every renormalizing shift lands a value directly - // at the basis its consumer needs (each quantity is rounded exactly once): + // at the basis its consumer needs: // m: Q95 (truncated from x; error < 2⁻⁹⁵) // z: Q100 (one sdiv) // u = z²: Q96 (one `shr` by 104, straight from the Q200 product) From 456f1f066cc83863cd71a1559fb8ae8de50623d2 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 13:57:02 +0200 Subject: [PATCH 120/149] WIP: clean up slop --- src/vendor/Exp.sol | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 4d0041926..ee7258753 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -34,15 +34,14 @@ library Exp { // // `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split N(t) = Ev(t²) + // t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational that matches - // `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln(2)/2)²]. Ev(v) is degree 5 and Od degree - // 4(v); in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the integer - // coefficients realize ≈126 of them. Ev(v) is monic, so its leading stage is a shift, not a - // multiply. + // `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln(2)/2)²]. Ev(v) is degree 5 and Od(v) + // degree 4; in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the + // integer coefficients realize ≈126 of them. Ev(v) is monic, so its leading stage is a + // shift, not a multiply. // // Mixed fixed-point bases (a staircase): each coefficient takes the widest basis fitting - // its chosen byte width, so a coefficient followed by j more multiplies by v tolerates a - // shorter basis. Each renormalizing shift lands a value directly at the basis its consumer - // needs. + // its chosen byte width. A coefficient followed by more multiplies by v tolerates a shorter + // basis. Each renormalizing shift lands a value directly at the basis its consumer needs. // t: Q128 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2) // v = t²: Q128 // Ev(v) Horner down the staircase Q99 → Q97 → Q97 → Q91 → Q87 (monic leading stage at From 28802d21c9ec29c9d270690822c5712ae4858e97 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 13:58:24 +0200 Subject: [PATCH 121/149] WIP: clean up slop --- src/vendor/Exp.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index ee7258753..a412381e5 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -50,7 +50,7 @@ library Exp { // Ev, Od, t⋅Od, and the numerator/denominator: Q87 // quotient: one `DIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays // below 2²⁵⁵: a nonnegative signed word) - // output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing `sar(126 - k, + // output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing `shr(126 - k, // …)` is the single output-rounding floor, with 2ᵏ folded in // // Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the @@ -137,9 +137,9 @@ library Exp { r := div(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin (the provable minimum - // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - + // 0x9fe769d0fa58e9f = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `shr(126 - // k, …)` which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 186]). - r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x9fe769d0fa58e9f)) + r := shr(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0x9fe769d0fa58e9f)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs From 51b4b7946fac062a0b811359e70019e5f1609a0d Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 14:55:22 +0200 Subject: [PATCH 122/149] Re-derive the exp proof for the Q123 kernel The certificate layer, runtime trees, and floor brackets now certify the Q123 kernel: v is carried at Q123, the monic stage is a bare add (exact, so the Ev telescope has one fewer lossy stage; brackets tighten to ~1.008/~1.002 units at the cleared scales 2^528/2^510), all ten coefficients are the refit literals, and the margin is 0xe17cfd91868d72d. The accumulator-vs-target bound is a four-link chain: (1) runtime vs the exact integer-v rational (Horner truncation + sdiv floor only), (2) the argument-granularity link -- new Floor/GranV + Floor/GranPair prove the one-grain quotient step 2t*K(v)/(D(v)*D(v+1)) via the degree-8 step combination K = Od*dEv - Ev*dOd (all nine coefficients positive, maximal at vmax) over certified denominator floors (new one-cell cover families certDOver/certDUnder), (3) the reciprocal-symmetric cut certificates at the 2^-131 nudge, (4) the reduced-argument envelope. Over budget 10155087723197130681/10^19 with strictness slack 0.9; under budget 67/10. Because the margin exceeds one wad unit, r0Tree_bounds strengthens to 2^123 <= r0 and the octave-seam bound to r0_1 + 2 <= 2*r0_2; the seam slack covers both. Full lake build is green from scratch and every public theorem in Theorems.lean is pinned to [propext, Classical.choice, Quot.sound] by the axiom gates; no public statement changed. Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/CapsV.lean | 24 +- .../ExpProof/ExpProof/Floor/CertDefsV.lean | 114 +- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 4 +- .../exp/ExpProof/ExpProof/Floor/GranPair.lean | 413 +++ formal/exp/ExpProof/ExpProof/Floor/GranV.lean | 610 ++++ .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 517 ++- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 22 +- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 2764 +++++------------ .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 903 +++--- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 32 +- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 16 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 45 +- formal/exp/ExpProof/ExpProof/Mono/Cross.lean | 4 +- .../exp/ExpProof/ExpProof/Mono/CrossCert.lean | 89 +- .../exp/ExpProof/ExpProof/Mono/EvOdLip.lean | 262 +- formal/exp/ExpProof/ExpProof/Mono/Gaps.lean | 38 +- .../exp/ExpProof/ExpProof/Mono/Lipschitz.lean | 60 +- formal/exp/ExpProof/ExpProof/Mono/Quot.lean | 43 +- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 43 +- .../exp/ExpProof/ExpProof/Mono/RunBridge.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 29 +- formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean | 17 +- formal/exp/ExpProof/ExpProof/Mono/Stages.lean | 288 +- .../exp/ExpProof/ExpProof/Mono/StepMono.lean | 12 +- formal/exp/ExpProof/ExpProof/Mono/Top.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 4 +- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 192 +- formal/exp/ExpProof/ExpProof/Theorems.lean | 9 +- formal/exp/ExpProof/GenExpVLit.lean | 14 + 29 files changed, 3219 insertions(+), 3353 deletions(-) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/GranPair.lean create mode 100644 formal/exp/ExpProof/ExpProof/Floor/GranV.lean diff --git a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean index e0cc5ad93..001b19751 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean @@ -17,8 +17,8 @@ nonnegativity into the two bare-argument Taylor caps the floor layer folds with implementation's exact **v-form** rational `ê_v(t) = NUM(t)/DEN(t)` (built from the even/odd Horner polynomials in `v = t²`) nudged by the dyadic margin, with `Qexp = 2^128`: -* `capExpUp` — never-over `exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê_v·(1 + 2⁻¹³⁰)`; -* `capExpLo` — not-two-below `yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê_v·(1 − 2⁻¹³⁰)`. +* `capExpUp` — never-over `exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê_v·(1 + 2⁻¹³¹)`; +* `capExpLo` — not-two-below `yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`. The bridge is the depth-`K = 27` `Common.Exp.capUB_of_partial`/`capLB` shape. -/ @@ -65,16 +65,16 @@ theorem evalExpN27 (t : Int) : evalPoly expN27 t = expNumI 27 t (Qexp : Int) := rw [evalPoly_expPolyNum] congr 1 <;> simp [evalPoly] -theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 130 + 1) * evalPoly numExpV t := by +theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 131 + 1) * evalPoly numExpV t := by unfold yUB; rw [evalPoly_polyScale] -theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 130 * evalPoly denExpV t := by +theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 131 * evalPoly denExpV t := by unfold wUB; rw [evalPoly_polyScale] -theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 130 - 1) * evalPoly numExpV t := by +theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 131 - 1) * evalPoly numExpV t := by unfold yLB; rw [evalPoly_polyScale] -theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 130 * evalPoly denExpV t := by +theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 131 * evalPoly denExpV t := by unfold wLB; rw [evalPoly_polyScale] theorem evalTailUp (t : Int) : @@ -121,15 +121,15 @@ theorem Qexp_eq : (Qexp : Int) = 2 ^ 128 := by unfold Qexp; norm_num theorem Qexp_pos : 0 < Qexp := by unfold Qexp; norm_num -/-- **Never-over cap** at the v-form rational `yUB/wUB = ê_v·(1 + 2⁻¹³⁰)`: for every reduced argument +/-- **Never-over cap** at the v-form rational `yUB/wUB = ê_v·(1 + 2⁻¹³¹)`: for every reduced argument `t ∈ [0, H128]`, `exp(t/Qexp) ≤ yUB(t)/wUB(t)`. -/ theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : capUB t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := by have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 have hden0 : 0 ≤ evalPoly denExpV t := by omega - have hc120 : (0 : Int) ≤ 2 ^ 130 + 1 := by norm_num - have hp120 : (0 : Int) ≤ 2 ^ 130 := by norm_num + have hc120 : (0 : Int) ≤ 2 ^ 131 + 1 := by norm_num + have hp120 : (0 : Int) ≤ 2 ^ 131 := by norm_num have hyub : 0 ≤ evalPoly yUB t := by rw [evalYUB]; exact Int.mul_nonneg hc120 hnum have hwub : 0 ≤ evalPoly wUB t := by @@ -155,15 +155,15 @@ theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : _ ≤ 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := key _ = evalPoly yUB t * (304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28) := by ring -/-- **Not-two-below cap** at the v-form rational `yLB/wLB = ê_v·(1 − 2⁻¹³⁰)`: for every reduced +/-- **Not-two-below cap** at the v-form rational `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`: for every reduced argument `t ∈ [0, H128]`, `yLB(t)/wLB(t) ≤ exp(t/Qexp)`. -/ theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : capLB t.toNat Qexp (evalPoly yLB t).toNat (evalPoly wLB t).toNat := by have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 have hden0 : 0 ≤ evalPoly denExpV t := by omega - have hc126 : (0 : Int) ≤ 2 ^ 130 - 1 := by norm_num - have hp126 : (0 : Int) ≤ 2 ^ 130 := by norm_num + have hc126 : (0 : Int) ≤ 2 ^ 131 - 1 := by norm_num + have hp126 : (0 : Int) ≤ 2 ^ 131 := by norm_num have hylb : 0 ≤ evalPoly yLB t := by rw [evalYLB]; exact Int.mul_nonneg hc126 hnum have hwlb : 0 ≤ evalPoly wLB t := by diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean index 8fb497757..22ddf65a2 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean @@ -1,12 +1,12 @@ import Common.Foundation.ShiftCert /-! -# The v-form reduced-argument rational target and its Taylor cut certificates +# The v-form reduced-argument rational target and its cut / denominator-floor certificates The runtime forms `r0 = ⌊ê_v(t)·2^126⌋` with the **v-form** rational ``` -ê_v(t) = (evNumV(v) · 2^105 + t · odNumV(v)) / (evNumV(v) · 2^105 − t · odNumV(v)), v = t²/2^128, +ê_v(t) = (evNumV(v) · 2^110 + t · odNumV(v)) / (evNumV(v) · 2^110 − t · odNumV(v)), v = t²/2^133, ``` built from the exact integer even/odd Horner polynomials `evNumV`/`odNumV` (defined in @@ -16,14 +16,19 @@ t-form `ê_t = numExp/denExp`. `ê_v` and `ê_t` are equal as reals but differ a polynomials (different shift-clearing), so this module re-derives the cut against `ê_v` directly. Here `v = t²` is carried symbolically (each Horner stage multiplies by `t²` via `mulT2`, with the -runtime per-stage `>>128` cleared into the per-stage scale): `evNumVPoly` accumulates `Ev` to the +runtime per-stage shift cleared into the per-stage scale): `evNumVPoly` accumulates `Ev` to the cleared scale `2^1193` and `odNumVPoly` accumulates `Od` to `2^1042`; `t·Od` (lifted by `2^23`) joins `Ev` at the common `2^1193`. The shared scale cancels in `ê_v = NUM/DEN`. As a polynomial in `t` the numerator/denominator are degree 10. -The cut is the standard `Common.Exp.capUB_of_partial`/`capLB` shape at Taylor depth `K = 27`, nudging -the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹³⁰)`, `yLB/wLB = ê_v·(1 − 2⁻¹³⁰)`); the -verified envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.057` ulp is far inside those margins. +Two certificate shapes are declared: + +* the Taylor cut, the standard `Common.Exp.capUB_of_partial`/`capLB` shape at depth `K = 27`, + nudging the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹³¹)`, `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`); + the realized envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.019` ulp is inside those margins with 2.3× slack; +* the **denominator floors** over the integer `v`-grid (`certDOver`/`certDUnder`), which pin + `Ev(v)·2^110 ∓ H128·Od(v)` above explicit constants for every `v ∈ [0, vmaxV + 1]`; the + argument-granularity link divides one `v`-grid step of `ê_v` by these floors. -/ namespace ExpCertV @@ -40,32 +45,32 @@ def H128 : Nat := 117932881612756647068972071382077242199 /-! ## Exact integer `ê_v(t) = NUM(t)/DEN(t)` from the implementation coefficients -The even/odd Horner accumulators evaluated as exact polynomials in `t` with `v = t²/2^128`, each -runtime per-stage `>>128` cleared into the stage scale. `evNumVPoly` is `evNumV(t²)` cleared to scale -`2^640` (so its evaluation is `Ev·2^1193`); `odNumVPoly` is `odNumV(t²)` cleared to scale `2^512` -(evaluation `Od·2^1042`); `t·Od` (lifted by `2^23` to the common `2^1193`) joins `Ev`. The shared -`2^1193` cancels in `ê_v = NUM/DEN`. -/ +The even/odd Horner accumulators evaluated as exact polynomials in `t` with `v = t²/2^133`, each +runtime per-stage shift cleared into the stage scale. `evNumVPoly` is `evNumV(t²)` cleared so its +evaluation is `Ev·2^1193` (`= evNumV(v)·2^665` at grid points `t² = 2^133·v`); `odNumVPoly` +evaluates to `Od·2^1042` (`= odNumV(v)·2^532` at grid points); `t·Od` (lifted by `2^23` to the +common `2^1193`) joins `Ev`. The shared `2^1193` cancels in `ê_v = NUM/DEN`. -/ -/-- `t²·P` at the polynomial level (one Horner `·v` stage, with the runtime `>>128` cleared into the -per-stage constant scale). -/ +/-- `t²·P` at the polynomial level (one Horner `·v` stage, with the runtime per-stage shift cleared +into the per-stage constant scale). -/ def mulT2 (P : List Int) : List Int := 0 :: 0 :: P -/-- The even Horner accumulator `Ev`, cleared to scale `2^640` (evaluation `Ev·2^1193`). The -per-stage constants are the even coefficients `A0..A4` lifted by the cleared stage scale; the -innermost monic `v` stage clears to `[A4·2^157, 0, 1]`. -/ +/-- The even Horner accumulator `Ev` (evaluation `Ev·2^1193`; `evNumV(v)·2^665` at grid points). +The per-stage constants are the even coefficients `A0..A4` lifted by the cleared stage scale; the +innermost monic `v` stage clears to `[A4·2^133, 0, 1]` (A4 is carried at v's own Q123 basis). -/ def evNumVPoly : List Int := - polyAdd [0x4e14a45e8ec305e233e11b4174e214ac * 2 ^ 1193] - (mulT2 (polyAdd [0x93f11e65781741b92fa7fc4f4fffcca2 * 2 ^ 933] - (mulT2 (polyAdd [0x9064d965e1c4863b73604e0ddbec53f9 * 2 ^ 671] - (mulT2 (polyAdd [0x9a036222e11aee18465042f8ea64c8 * 2 ^ 415] - (mulT2 [0xb9aacfad41060587203a79af0ebc * 2 ^ 157, 0, 1]))))))) + polyAdd [0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193] + (mulT2 (polyAdd [0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933] + (mulT2 (polyAdd [0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671] + (mulT2 (polyAdd [0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415] + (mulT2 [0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133, 0, 1]))))))) -/-- The odd Horner accumulator `Od`, cleared to scale `2^512` (evaluation `Od·2^1042`). -/ +/-- The odd Horner accumulator `Od` (evaluation `Od·2^1042`; `odNumV(v)·2^532` at grid points). -/ def odNumVPoly : List Int := - polyAdd [0x270a522f476182f119f08da0ba710a56 * 2 ^ 1042] - (mulT2 (polyAdd [0xaf5662483c4ce783a9ef5fe025f42e9e * 2 ^ 779] - (mulT2 (polyAdd [0xad4506b00b1246c7e5b4fd33e1201b * 2 ^ 524] - (mulT2 [0xc926ddbf3830ca5561cc01585402d0 * 2 ^ 259, 0, 0xdc07aff85e5bb5629d0fb64a84bb]))))) + polyAdd [0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042] + (mulT2 (polyAdd [0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779] + (mulT2 (polyAdd [0xad4506af99be27419341e1816ff351 * 2 ^ 524] + (mulT2 [0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259, 0, 0xdc07aff8276bde9a361278df6a10]))))) /-- `t·Od` lifted to the common scale `2^1193` (`= 2^23 · t · odNumVPoly`). -/ def todNumV : List Int := polyScale (2 ^ 23) (0 :: odNumVPoly) @@ -83,14 +88,14 @@ def expN27 : List Int := expPolyNum [0, 1] [(Qexp : Int)] 27 /-! ## Margin-nudged rational targets -`yUB/wUB = ê_v·(1 + 2⁻¹³⁰)` and `yLB/wLB = ê_v·(1 − 2⁻¹³⁰)`. The tight `2⁻¹³⁰` margins keep the -`2¹²⁶·(ê_v − exp)` contribution to the runtime over/under budget below `2¹²⁶·exp·2⁻¹³⁰ ≈ 0.09` ulp, -inside the `MARGIN`; the verified envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.057` ulp leaves slack. -/ +`yUB/wUB = ê_v·(1 + 2⁻¹³¹)` and `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`. The tight `2⁻¹³¹` margins keep the +`2¹²⁶·(ê_v − exp)` contribution to the runtime over/under budget below `2¹²⁶·exp·2⁻¹³¹ ≈ 0.045` ulp, +inside the `MARGIN`; the realized envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.019` ulp leaves slack. -/ -def yUB : List Int := polyScale (2 ^ 130 + 1) numExpV -def wUB : List Int := polyScale (2 ^ 130) denExpV -def yLB : List Int := polyScale (2 ^ 130 - 1) numExpV -def wLB : List Int := polyScale (2 ^ 130) denExpV +def yUB : List Int := polyScale (2 ^ 131 + 1) numExpV +def wUB : List Int := polyScale (2 ^ 131) denExpV +def yLB : List Int := polyScale (2 ^ 131 - 1) numExpV +def wLB : List Int := polyScale (2 ^ 131) denExpV /-! ## The cut certificate polynomials -/ @@ -111,4 +116,47 @@ def certExpLo : List Int := polySub (polyMul expN27 wLB) (polyScale fact27Q27 yL /-- `DEN(t) − 1`: nonnegativity over the domain certifies `1 ≤ DEN(t)`. -/ def certDenM1 : List Int := polyAdd denExpV [-1] +/-! ## The v-grid denominator floors + +The argument-granularity link works on the integer `v`-grid: with `Ev(v)`/`Od(v)` the exact integer +Horner polynomials (cleared scales `2^528`/`2^510`; `Floor/R0Bound.lean`), the aligned rational is +`ê_v = (Ev·2^110 + t·Od) / (Ev·2^110 − t·Od)` and one grid step of it is bounded by dividing the +`K`-identity numerator by the two floors below. The grid never leaves `[0, vmaxV + 1]` +(`v = ⌊t²/2^133⌋ ≤ vmaxV` for `|t| ≤ H128`, and the step looks one cell ahead). -/ + +/-- The top of the `v`-grid: `vmaxV = ⌊H128²/2^133⌋`. -/ +def vmaxV : Nat := 1277263193518626341050532535110179582 + +/-- The even integer Horner polynomial `Ev` in `v` (degree 5, monic, cleared scale `2^528`): +coefficient list of `evNumV` (`Floor/R0Bound.lean`). -/ +def evVPoly : List Int := + [0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 528, + 0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 401, + 0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 272, + 0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 149, + 0xb9aacfacf3c10b378435f8e22adf48500e, + 1] + +/-- The odd integer Horner polynomial `Od` in `v` (degree 4, cleared scale `2^510`). -/ +def odVPoly : List Int := + [0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 510, + 0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 380, + 0xad4506af99be27419341e1816ff351 * 2 ^ 258, + 0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 126, + 0xdc07aff8276bde9a361278df6a10] + +/-- Over-half denominator floor: `Ev(v)·2^110 − H128·Od(v) − 554482771859·2^725 ≥ 0` on +`[0, vmaxV + 1]` (so `DEN(v, t) ≥ 554482771859·2^725` for every `0 ≤ t ≤ H128`; the floor constant +is `2^725` times the real-scale minimum `≈ 5.5448·10¹¹`, attained at `v = 0`). -/ +def certDOver : List Int := + polyAdd (polySub (polyScale (2 ^ 110) evVPoly) (polyScale (H128 : Int) odVPoly)) + [-(554482771859 * 2 ^ 725)] + +/-- Under-half denominator floor: `Ev(v)·2^110 + H128·Od(v) − 786932288647·2^725 ≥ 0` on +`[0, vmaxV + 1]` (the `t = −H128` denominator; the granularity lift is monotone in `|t|`, so this +single evaluation floors the whole negative half). -/ +def certDUnder : List Int := + polyAdd (polyAdd (polyScale (2 ^ 110) evVPoly) (polyScale (H128 : Int) odVPoly)) + [-(786932288647 * 2 ^ 725)] + end ExpCertV diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index 236f8ef89..58420da54 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -29,7 +29,7 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : ∃ s : Nat, (s : Int) = 126 - int256 (kTree x) ∧ accumReal x = - ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - (720143407370309279 : Real)) / + ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - (1015508772319713069 : Real)) / (2 ^ s : Real) := by obtain ⟨s, hseq, _, _, hsint⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 @@ -39,7 +39,7 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) rw [hseq] -- the integer shift argument has the closed value `WAD·r0 − MARGIN` have hwadc : (0xde0b6b3a7640000 : Int) = 1000000000000000000 := by norm_num - have hmarc : (0x9fe769d0fa58e9f : Int) = 720143407370309279 := by norm_num + have hmarc : (0xe17cfd91868d72d : Int) = 1015508772319713069 := by norm_num rw [hargeq, hwadc, hmarc] push_cast ring diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean b/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean new file mode 100644 index 000000000..8990c9376 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean @@ -0,0 +1,413 @@ +import ExpProof.Floor.GranV + +/-! +# The exported real-level granularity bounds + +The two per-side packagings of the `Floor.GranV` machinery that the `r0`-vs-`exp` chains consume: +one `v`-grid grain lifts `2¹²⁶·ê` by at most `3395595387735630095/10¹⁹` on the `t ≥ 0` half +(never-over side) and by at most `1685843742692980488/10¹⁹` — `Mp`-factor included — on the +`t ≤ 0` half (deficit side); the respective opposite directions are free. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Poly + +set_option maxRecDepth 100000 +set_option maxHeartbeats 1600000 +set_option exponentiation.threshold 2000 + +/-! ## The exported real-level granularity bounds -/ + +noncomputable section + +/-- **Granularity, never-over half (`t ≥ 0`)**: the cert rational never exceeds the grid rational, +and the grid rational exceeds the cert rational by at most one `K`-step: +`2¹²⁶·(ê(v) − ê(t²)) ≤ 3395595387735630095/10¹⁹`. -/ +theorem gran_over_pair {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (evalPoly ExpCertV.numExpV (int256 (tTree x)) : Real) / + (evalPoly ExpCertV.denExpV (int256 (tTree x)) : Real) ≤ + (NUMv (vTree x) (int256 (tTree x)) : Real) / (DENv (vTree x) (int256 (tTree x)) : Real) ∧ + (2 ^ 126 : Real) * ((NUMv (vTree x) (int256 (tTree x)) : Real) / + (DENv (vTree x) (int256 (tTree x)) : Real)) ≤ + (2 ^ 126 : Real) * ((evalPoly ExpCertV.numExpV (int256 (tTree x)) : Real) / + (evalPoly ExpCertV.denExpV (int256 (tTree x)) : Real)) + + 3395595387735630095 / 10000000000000000000 := by + obtain ⟨htie1, htie2⟩ := tie_over hx hC hC0 htnn + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have hvle := vTree_le_vmax hx hC hC0 + set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + -- denominators + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hD1 : 554482771859 * 2 ^ 725 ≤ DENv (v + 1) t := DENv_ge_over (by omega) htnn hthi + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD + have hD1pos : (0:Int) < DENv (v + 1) t := lt_of_lt_of_le (by positivity) hD1 + have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom + have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + have hD1R : (0:Real) < (DENv (v + 1) t : Real) := by exact_mod_cast hD1pos + have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos + -- part 1: NE/DE ≤ NUMv/DENv (cross form htie1) + have hpart1 : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ + (NUMv v t : Real) / (DENv v t : Real) := by + rw [div_le_div_iff₀ hDER hDR] + exact_mod_cast htie1 + refine ⟨hpart1, ?_⟩ + -- part 2: Qv − Qw ≤ Qv − Qv1 = one K-step ≤ budget/2^126 + have hQv1_le_Qw : (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) ≤ + (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) := by + rw [div_le_div_iff₀ hD1R hDER] + exact_mod_cast htie2 + have hstep_eq : (NUMv v t : Real) / (DENv v t : Real) - + (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) = + ((2 * t * 2 ^ 110 * KpM v : Int) : Real) / + ((DENv v t : Real) * (DENv (v + 1) t : Real)) := by + rw [div_sub_div _ _ (ne_of_gt hDR) (ne_of_gt hD1R)] + congr 1 + have hid := step_identity v t + have hcast : ((NUMv v t : Int) : Real) * ((DENv (v + 1) t : Int) : Real) - + ((DENv v t : Int) : Real) * ((NUMv (v + 1) t : Int) : Real) = + ((2 * t * 2 ^ 110 * KpM v : Int) : Real) := by + rw [show ((2 * t * 2 ^ 110 * KpM v : Int) : Real) = + ((NUMv v t * DENv (v + 1) t - NUMv (v + 1) t * DENv v t : Int) : Real) from by + exact_mod_cast (congrArg (fun z : Int => (z : Real)) hid.symm)] + push_cast + ring + exact hcast + -- numerator and denominator bounds for the K-step + have hKnn := KpM_nonneg v + have hKle := KpM_le_KVMAX hvle + have hnum_nn : (0:Int) ≤ 2 * t * 2 ^ 110 * KpM v := by positivity + have hnum_le : 2 * t * 2 ^ 110 * KpM v ≤ + 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc := by + have h1 : 2 * t * 2 ^ 110 * KpM v ≤ + 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v := by + have hcoef : 2 * t * 2 ^ 110 ≤ 2 * 117932881612756647068972071382077242199 * 2 ^ 110 := by + nlinarith [hthi] + exact mul_le_mul_of_nonneg_right hcoef hKnn + have h2 : 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v ≤ + 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc := + mul_le_mul_of_nonneg_left hKle (by positivity) + linarith [h1, h2] + have hden_ge : (554482771859 * 2 ^ 725 : Real) * (554482771859 * 2 ^ 725 : Real) ≤ + (DENv v t : Real) * (DENv (v + 1) t : Real) := by + have hDRc : (554482771859 * 2 ^ 725 : Real) ≤ (DENv v t : Real) := by exact_mod_cast hD + have hD1Rc : (554482771859 * 2 ^ 725 : Real) ≤ (DENv (v + 1) t : Real) := by exact_mod_cast hD1 + exact mul_le_mul hDRc hD1Rc (by positivity) (le_of_lt hDR) + -- the K-step fraction is inside the budget + have hfrac : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) / + ((DENv v t : Real) * (DENv (v + 1) t : Real)) ≤ + 3395595387735630095 / 10000000000000000000 / 2 ^ 126 := by + have hdd : (0:Real) < (DENv v t : Real) * (DENv (v + 1) t : Real) := mul_pos hDR hD1R + rw [div_le_div_iff₀ hdd (by positivity : (0:Real) < (2:Real) ^ 126)] + have hnumR : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) ≤ + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) := by + exact_mod_cast hnum_le + have h1 : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) * 2 ^ 126 ≤ + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * 2 ^ 126 := + mul_le_mul_of_nonneg_right hnumR (by positivity) + have h2 : ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * + 2 ^ 126 ≤ (3395595387735630095 / 10000000000000000000 : Real) * + ((554482771859 * 2 ^ 725 : Real) * (554482771859 * 2 ^ 725 : Real)) := by + rw [div_mul_eq_mul_div, le_div_iff₀ (by norm_num : (0:Real) < 10000000000000000000)] + have hint : (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) * + 2 ^ 126 * 10000000000000000000 ≤ (3395595387735630095 : Int) * + ((554482771859 * 2 ^ 725) * (554482771859 * 2 ^ 725)) := by + unfold KVMAXc + norm_num + exact_mod_cast hint + have h3 : (3395595387735630095 / 10000000000000000000 : Real) * + ((554482771859 * 2 ^ 725 : Real) * (554482771859 * 2 ^ 725 : Real)) ≤ + (3395595387735630095 / 10000000000000000000 : Real) * + ((DENv v t : Real) * (DENv (v + 1) t : Real)) := + mul_le_mul_of_nonneg_left hden_ge (by positivity) + exact le_trans h1 (le_trans h2 h3) + -- assemble part 2 + have hQvQw : (NUMv v t : Real) / (DENv v t : Real) - + (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ + 3395595387735630095 / 10000000000000000000 / 2 ^ 126 := by + linarith [hstep_eq, hfrac, hQv1_le_Qw] + have h2126 := mul_le_mul_of_nonneg_left hQvQw (by positivity : (0:Real) ≤ (2:Real) ^ 126) + have hcancel : (2:Real) ^ 126 * (3395595387735630095 / 10000000000000000000 / 2 ^ 126) = + 3395595387735630095 / 10000000000000000000 := by + norm_num + rw [hcancel] at h2126 + linarith [h2126] + +/-- **Granularity, deficit half (`t ≤ 0`)**: the grid rational never exceeds the cert rational, and +the cert rational exceeds the grid rational — `Mp`-factor `2¹³¹/(2¹³¹−1)` included — by at most +`1685843742692980488/10¹⁹` after scaling by `2¹²⁶`. The one-grain lift is monotone in `|t|` +(the sign condition is the over-half denominator floor), so the `t = −H128` denominator floor +`certDUnder` applies for every `t` in the half. -/ +theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnp : int256 (tTree x) ≤ 0) : + (NUMv (vTree x) (int256 (tTree x)) : Real) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ + (evalPoly ExpCertV.numExpV (int256 (tTree x)) : Real) / + (evalPoly ExpCertV.denExpV (int256 (tTree x)) : Real) ∧ + (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * + ((evalPoly ExpCertV.numExpV (int256 (tTree x)) : Real) / + (evalPoly ExpCertV.denExpV (int256 (tTree x)) : Real) - + (NUMv (vTree x) (int256 (tTree x)) : Real) / (DENv (vTree x) (int256 (tTree x)) : Real)) ≤ + 1685843742692980488 / 10000000000000000000 := by + obtain ⟨htie1, htie2⟩ := tie_under hx hC hC0 htnp + obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 + have hvle := vTree_le_vmax hx hC hC0 + set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + have hntH : -t ≤ 117932881612756647068972071382077242199 := by linarith [htlo] + have htdom : -t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hntH + -- denominators + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htnp + have hD1 : 554482771859 * 2 ^ 725 ≤ DENv (v + 1) t := DENv_ge_neg (by omega) htnp + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD + have hD1pos : (0:Int) < DENv (v + 1) t := lt_of_lt_of_le (by positivity) hD1 + have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htnp htdom).2 + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + have hD1R : (0:Real) < (DENv (v + 1) t : Real) := by exact_mod_cast hD1pos + have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos + -- part 1: NUMv/DENv ≤ NE/DE + have hpart1 : (NUMv v t : Real) / (DENv v t : Real) ≤ + (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) := by + rw [div_le_div_iff₀ hDR hDER] + exact_mod_cast htie1 + refine ⟨hpart1, ?_⟩ + -- part 2: Qw − Qv ≤ Qv1 − Qv = one K-step, |t|-monotone, floored at t = −H128 + have hQw_le_Qv1 : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ + (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) := by + rw [div_le_div_iff₀ hDER hD1R] + exact_mod_cast htie2 + have hstep_eq : (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) - + (NUMv v t : Real) / (DENv v t : Real) = + ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) / + ((DENv (v + 1) t : Real) * (DENv v t : Real)) := by + rw [div_sub_div _ _ (ne_of_gt hD1R) (ne_of_gt hDR)] + congr 1 + have hid := step_identity v t + have hswap : NUMv (v + 1) t * DENv v t - DENv (v + 1) t * NUMv v t = + 2 * (-t) * 2 ^ 110 * KpM v := by linear_combination -hid + rw [show ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) = + ((NUMv (v + 1) t * DENv v t - DENv (v + 1) t * NUMv v t : Int) : Real) from by + exact_mod_cast (congrArg (fun z : Int => (z : Real)) hswap.symm)] + push_cast + ring + -- the |t|-monotonicity: u·D(H)·D′(H) ≤ H·D(u)·D′(u) with u = −t ≤ H + set u : Int := -t with hudef + have hu0 : (0:Int) ≤ u := by rw [hudef]; linarith [htnp] + set A : Int := (evNumV v : Int) * 2 ^ 110 with hAdef + set Bo : Int := (odNumV v : Int) with hBodef + set A1 : Int := (evNumV (v + 1) : Int) * 2 ^ 110 with hA1def + set Bo1 : Int := (odNumV (v + 1) : Int) with hBo1def + have hBo_nn : (0:Int) ≤ Bo := Int.natCast_nonneg _ + have hBo1_nn : (0:Int) ≤ Bo1 := Int.natCast_nonneg _ + have hAB : 117932881612756647068972071382077242199 * Bo ≤ A := HOd_le_Ev (by omega) + have hA1B1 : 117932881612756647068972071382077242199 * Bo1 ≤ A1 := HOd_le_Ev (by omega) + have hDu : DENv v t = A + u * Bo := by unfold DENv; rw [hAdef, hBodef, hudef]; ring + have hDu1 : DENv (v + 1) t = A1 + u * Bo1 := by + unfold DENv; rw [hA1def, hBo1def, hudef]; ring + have hmono : u * ((A + 117932881612756647068972071382077242199 * Bo) * + (A1 + 117932881612756647068972071382077242199 * Bo1)) ≤ + 117932881612756647068972071382077242199 * ((A + u * Bo) * (A1 + u * Bo1)) := by + have hid : 117932881612756647068972071382077242199 * ((A + u * Bo) * (A1 + u * Bo1)) - + u * ((A + 117932881612756647068972071382077242199 * Bo) * + (A1 + 117932881612756647068972071382077242199 * Bo1)) = + (117932881612756647068972071382077242199 - u) * + (A * A1 - 117932881612756647068972071382077242199 * u * (Bo * Bo1)) := by ring + have hprod : 117932881612756647068972071382077242199 * u * (Bo * Bo1) ≤ A * A1 := by + have h1 : 117932881612756647068972071382077242199 * u * (Bo * Bo1) ≤ + 117932881612756647068972071382077242199 * + 117932881612756647068972071382077242199 * (Bo * Bo1) := by + have := mul_le_mul_of_nonneg_right + (mul_le_mul_of_nonneg_left hntH + (by norm_num : (0:Int) ≤ 117932881612756647068972071382077242199)) + (mul_nonneg hBo_nn hBo1_nn) + linarith [this] + have h2 : (117932881612756647068972071382077242199 * + 117932881612756647068972071382077242199 * (Bo * Bo1) : Int) = + (117932881612756647068972071382077242199 * Bo) * + (117932881612756647068972071382077242199 * Bo1) := by ring + have h3 : (117932881612756647068972071382077242199 * Bo) * + (117932881612756647068972071382077242199 * Bo1) ≤ A * A1 := + mul_le_mul hAB hA1B1 + (mul_nonneg (by norm_num) hBo1_nn) + (le_trans (mul_nonneg (by norm_num) hBo_nn) hAB) + linarith [h1, h2 ▸ h1, h3] + have hfac1 : (0:Int) ≤ 117932881612756647068972071382077242199 - u := by + rw [hudef]; linarith [hntH] + have hfac2 : (0:Int) ≤ A * A1 - 117932881612756647068972071382077242199 * u * (Bo * Bo1) := by + linarith [hprod] + linarith only [mul_nonneg hfac1 hfac2, hid] + -- floor the H128-denominators with the under certificate + have hDH : 786932288647 * 2 ^ 725 ≤ A + 117932881612756647068972071382077242199 * Bo := by + have := D_at_H_ge_under (v := v) (by omega) + rw [hAdef, hBodef]; linarith [this] + have hDH1 : 786932288647 * 2 ^ 725 ≤ A1 + 117932881612756647068972071382077242199 * Bo1 := by + have := D_at_H_ge_under (v := v + 1) (by omega) + rw [hA1def, hBo1def]; linarith [this] + have hDHpos : (0:Int) < A + 117932881612756647068972071382077242199 * Bo := + lt_of_lt_of_le (by positivity) hDH + have hDH1pos : (0:Int) < A1 + 117932881612756647068972071382077242199 * Bo1 := + lt_of_lt_of_le (by positivity) hDH1 + have hKnn := KpM_nonneg v + have hKle := KpM_le_KVMAX hvle + -- the fraction chain: u-step ≤ H-step ≤ literal maximum + have hfracu : ((2 * u * 2 ^ 110 * KpM v : Int) : Real) / + ((DENv (v + 1) t : Real) * (DENv v t : Real)) ≤ + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) / + (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) := by + have hdd : (0:Real) < (DENv (v + 1) t : Real) * (DENv v t : Real) := mul_pos hD1R hDR + have hdH : (0:Real) < ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by + have h1 : (0:Real) < ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) := by + exact_mod_cast hDH1pos + have h2 : (0:Real) < ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by + exact_mod_cast hDHpos + exact mul_pos h1 h2 + rw [div_le_div_iff₀ hdd hdH] + -- cross-multiplied: (2u·2^110·Kp)·(D1(H)·D(H)) ≤ (2H·2^110·Kp)·(D1(u)·D(u)) + have hint : (2 * u * 2 ^ 110 * KpM v) * + ((A1 + 117932881612756647068972071382077242199 * Bo1) * + (A + 117932881612756647068972071382077242199 * Bo)) ≤ + (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v) * + ((A1 + u * Bo1) * (A + u * Bo)) := by + have hc : (0:Int) ≤ 2 * 2 ^ 110 * KpM v := + mul_nonneg (by norm_num) hKnn + have hscaled := mul_le_mul_of_nonneg_left hmono hc + linarith only [hscaled] + have hrw : (DENv (v + 1) t : Real) * (DENv v t : Real) = + (((A1 + u * Bo1) * (A + u * Bo) : Int) : Real) := by + rw [hDu, hDu1]; push_cast; ring + rw [hrw] + calc ((2 * u * 2 ^ 110 * KpM v : Int) : Real) * + (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) + = (((2 * u * 2 ^ 110 * KpM v) * + ((A1 + 117932881612756647068972071382077242199 * Bo1) * + (A + 117932881612756647068972071382077242199 * Bo)) : Int) : Real) := by + push_cast; ring + _ ≤ (((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v) * + ((A1 + u * Bo1) * (A + u * Bo)) : Int) : Real) := by exact_mod_cast hint + _ = ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) * + (((A1 + u * Bo1) * (A + u * Bo) : Int) : Real) := by push_cast; ring + have hfracH : ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) / + (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) ≤ + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) := by + have hdH : (0:Real) < ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by + have h1 : (0:Real) < ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) := by + exact_mod_cast hDH1pos + have h2 : (0:Real) < ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by + exact_mod_cast hDHpos + exact mul_pos h1 h2 + rw [div_le_div_iff₀ hdH (by positivity)] + have hnum : ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) ≤ + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) := by + have : (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) ≤ + 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc := + mul_le_mul_of_nonneg_left hKle (by positivity) + exact_mod_cast this + have hnum_nn : (0:Real) ≤ + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) := by + have : (0:Int) ≤ 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v := + mul_nonneg (by norm_num) hKnn + exact_mod_cast this + have hden : ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) ≤ + ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by + have h1 : (786932288647 * 2 ^ 725 : Real) ≤ + ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) := by + exact_mod_cast hDH1 + have h2 : (786932288647 * 2 ^ 725 : Real) ≤ + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by + exact_mod_cast hDH + exact mul_le_mul h1 h2 (by positivity) (by exact_mod_cast le_of_lt hDH1pos) + calc ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) * + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) + ≤ ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) := + mul_le_mul_of_nonneg_right hnum (by positivity) + _ ≤ ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * + (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) := by + apply mul_le_mul_of_nonneg_left hden + exact le_trans hnum_nn hnum + -- the literal budget, Mp-factor included + have hbudget : (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * + (((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real))) ≤ + 1685843742692980488 / 10000000000000000000 := by + have hMp1 : (0:Real) < (2 ^ 131 : Real) - 1 := by norm_num + have hDD : (0:Real) < (786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real) := by + positivity + rw [show (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * + (((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real))) = + ((2 ^ 126 * 2 ^ 131 : Real) * + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real)) / + ((((2 ^ 131 : Real) - 1)) * + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real))) from by + field_simp + try ring] + rw [div_le_div_iff₀ (by positivity) (by norm_num : (0:Real) < 10000000000000000000)] + have hint : (2 ^ 126 * 2 ^ 131 : Int) * + (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc) * + 10000000000000000000 ≤ (1685843742692980488 : Int) * + ((2 ^ 131 - 1) * ((786932288647 * 2 ^ 725) * (786932288647 * 2 ^ 725))) := by + unfold KVMAXc + norm_num + calc (2 ^ 126 * 2 ^ 131 : Real) * + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * + 10000000000000000000 + = (((2 ^ 126 * 2 ^ 131 : Int) * + (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc) * + 10000000000000000000 : Int) : Real) := by push_cast; ring + _ ≤ (((1685843742692980488 : Int) * + ((2 ^ 131 - 1) * ((786932288647 * 2 ^ 725) * (786932288647 * 2 ^ 725))) : Int) : Real) := by + exact_mod_cast hint + _ = (1685843742692980488 : Real) * + (((2 ^ 131 : Real) - 1) * + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real))) := by + push_cast; ring + -- assemble part 2 + have hgap_le : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) - + (NUMv v t : Real) / (DENv v t : Real) ≤ + ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) := by + have hu_eq : ((2 * u * 2 ^ 110 * KpM v : Int) : Real) = + ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) := by rw [hudef] + calc (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) - + (NUMv v t : Real) / (DENv v t : Real) + ≤ (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) - + (NUMv v t : Real) / (DENv v t : Real) := by linarith [hQw_le_Qv1] + _ = ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) / + ((DENv (v + 1) t : Real) * (DENv v t : Real)) := hstep_eq + _ = ((2 * u * 2 ^ 110 * KpM v : Int) : Real) / + ((DENv (v + 1) t : Real) * (DENv v t : Real)) := by rw [hu_eq] + _ ≤ ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) / + (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * + ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) := hfracu + _ ≤ ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / + ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) := hfracH + have hMpnn : (0:Real) ≤ (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) := by + have : (0:Real) < (2 ^ 131 : Real) - 1 := by norm_num + positivity + exact le_trans (mul_le_mul_of_nonneg_left hgap_le hMpnn) hbudget + +end + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean new file mode 100644 index 000000000..069ab6813 --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean @@ -0,0 +1,610 @@ +import ExpProof.Floor.R0Bound +import ExpProof.Floor.CapsV +import ExpProof.Cert.ExpVDOver +import ExpProof.Cert.ExpVDUnder + +/-! +# The argument-granularity link: `ê` at the floored `v` vs `ê` at the exact `t²` + +The runtime evaluates the even/odd polynomials at `v = ⌊t²/2^133⌋`, while the Taylor cut +(`Floor/CapsV`) certifies the rational at the exact square `t²`. This module bounds the gap. With +the aligned integer rational on the `v`-grid + +``` +ê(v, t) = NUMv(v, t) / DENv(v, t), NUMv = Ev(v)·2^110 + t·Od(v), DENv = Ev(v)·2^110 − t·Od(v) +``` + +(scale `2^725 = 2^(528+87+110)`; `Ev`/`Od` are `evNumV`/`odNumV` from `Floor/R0Bound`), three facts +combine: + +* **the tie** — as a function of the square argument `w`, the rational is monotone (decreasing for + `t > 0`, increasing for `t < 0`): the cross-product `Pev(b)·Pod(a) − Pev(a)·Pod(b) ≥ 0` for + `0 ≤ a ≤ b` holds pairwise on the coefficients, so the cert value `ê(t²)` lies between the two + grid values `ê(v, t)` and `ê(v+1, t)`; +* **the `K` identity** — one grid step is exact algebra: + `NUMv(v)·DENv(v+1) − NUMv(v+1)·DENv(v) = 2t·2^110·K(v)` with + `K(v) = Od(v)·Ev(v+1) − Ev(v)·Od(v+1)`, a degree-8 polynomial in `v` with all nine coefficients + positive, so `0 ≤ K(v) ≤ K(vmaxV)` on the grid; +* **the denominator floors** — the cover certificates `certDOver`/`certDUnder` pin + `Ev(v)·2^110 ∓ H128·Od(v)` above explicit constants over the whole grid `[0, vmaxV + 1]`; on the + negative half the one-grain lift `2|t|·K/(D·D′)` is additionally monotone in `|t|` (the derivative + sign reduces to the over-half floor `Ev·2^110 − |t|·Od ≥ 0`), so the `t = −H128` floor applies. + +`Floor/GranPair` packages these into the two per-side real-level budget bounds the `r0`-vs-`exp` +chains consume. +-/ + +namespace ExpYul + +open FormalYul +open FormalYul.Preservation +open Common.Poly + +set_option maxRecDepth 100000 +set_option maxHeartbeats 1600000 +set_option exponentiation.threshold 2000 + +/-! ## Generic polynomial positivity/monotonicity -/ + +/-- A polynomial with nonnegative coefficients evaluates nonnegatively on the nonnegative domain. -/ +theorem evalPoly_nonneg_of_nonneg {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) {a : Int} (ha : 0 ≤ a) : + 0 ≤ evalPoly p a := by + induction p with + | nil => simp [evalPoly] + | cons c cs ih => + have hc : 0 ≤ c := hp c List.mem_cons_self + have hcs : ∀ d ∈ cs, 0 ≤ d := fun d hd => hp d (List.mem_cons_of_mem c hd) + simp only [evalPoly] + exact Int.add_nonneg hc (Int.mul_nonneg ha (ih hcs)) + +/-- A polynomial with nonnegative coefficients is monotone on the nonnegative domain. -/ +theorem evalPoly_mono_of_nonneg {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) {a b : Int} + (ha : 0 ≤ a) (hab : a ≤ b) : evalPoly p a ≤ evalPoly p b := by + induction p with + | nil => simp [evalPoly] + | cons c cs ih => + have hcs : ∀ d ∈ cs, 0 ≤ d := fun d hd => hp d (List.mem_cons_of_mem c hd) + have hih := ih hcs + have hb : 0 ≤ b := le_trans ha hab + have hcsnn : 0 ≤ evalPoly cs a := evalPoly_nonneg_of_nonneg hcs ha + simp only [evalPoly] + have h1 : a * evalPoly cs a ≤ b * evalPoly cs b := by + calc a * evalPoly cs a ≤ b * evalPoly cs a := + mul_le_mul_of_nonneg_right hab hcsnn + _ ≤ b * evalPoly cs b := mul_le_mul_of_nonneg_left hih hb + linarith [h1] + +/-! ## The even/odd polynomials in the square argument `w = t²` -/ + +/-- The even Horner polynomial in `w` (degree 5, monic), at the cleared scale `2¹¹⁹³`. -/ +def Pev : List Int := + [0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193, + 0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933, + 0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671, + 0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415, + 0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133, + 1] + +/-- The odd Horner polynomial in `w` (degree 4), at the cleared scale `2¹⁰⁴²`. -/ +def Pod : List Int := + [0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042, + 0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779, + 0xad4506af99be27419341e1816ff351 * 2 ^ 524, + 0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259, + 0xdc07aff8276bde9a361278df6a10] + +/-- `evNumVPoly(t) = Pev(t²)`: the cert even polynomial is `Pev` composed with squaring. -/ +theorem evNumVPoly_eq_Pev_sq (t : Int) : + evalPoly ExpCertV.evNumVPoly t = evalPoly Pev (t ^ 2) := by + unfold ExpCertV.evNumVPoly ExpCertV.mulT2 Pev + simp only [evalPoly_polyAdd, evalPoly_polyScale, evalPoly] + ring + +/-- `odNumVPoly(t) = Pod(t²)`. -/ +theorem odNumVPoly_eq_Pod_sq (t : Int) : + evalPoly ExpCertV.odNumVPoly t = evalPoly Pod (t ^ 2) := by + unfold ExpCertV.odNumVPoly ExpCertV.mulT2 Pod + simp only [evalPoly_polyAdd, evalPoly_polyScale, evalPoly] + ring + +/-- `Pev(2¹³³·v) = evNumV(v)·2⁶⁶⁵` — the `w`-polynomial at the grid point `w = 2¹³³·v` recovers the +integer even-Horner accumulator (scaled). -/ +theorem Pev_grid (v : Nat) : evalPoly Pev (2 ^ 133 * (v : Int)) = (evNumV v : Int) * 2 ^ 665 := by + unfold Pev evNumV + simp only [evalPoly] + push_cast + ring + +/-- `Pod(2¹³³·v) = odNumV(v)·2⁵³²`. -/ +theorem Pod_grid (v : Nat) : evalPoly Pod (2 ^ 133 * (v : Int)) = (odNumV v : Int) * 2 ^ 532 := by + unfold Pod odNumV + simp only [evalPoly] + push_cast + ring + +theorem Pod_coeffs_nonneg : ∀ c ∈ Pod, (0 : Int) ≤ c := by + unfold Pod; intro c hc; fin_cases hc <;> positivity + +/-- The odd cert polynomial `odNumVPoly` is nonnegative everywhere (`= Pod(t²)`, nonneg coeffs). -/ +theorem odNumVPoly_nonneg (t : Int) : 0 ≤ evalPoly ExpCertV.odNumVPoly t := by + rw [odNumVPoly_eq_Pod_sq] + exact evalPoly_nonneg_of_nonneg Pod_coeffs_nonneg (by positivity) + +/-! ## Evaluation shapes and the reciprocal symmetry of the cert rational -/ + +/-- `evalPoly todNumV t = 2²³ · t · evalPoly odNumVPoly t`. -/ +theorem evalTodNumV (t : Int) : + evalPoly ExpCertV.todNumV t = 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := by + unfold ExpCertV.todNumV + rw [evalPoly_polyScale] + simp only [evalPoly] + ring + +/-- `evalPoly numExpV t = evalPoly evNumVPoly t + evalPoly todNumV t`. -/ +theorem evalNumExpV (t : Int) : + evalPoly ExpCertV.numExpV t = evalPoly ExpCertV.evNumVPoly t + evalPoly ExpCertV.todNumV t := by + unfold ExpCertV.numExpV; rw [evalPoly_polyAdd] + +/-- `evalPoly denExpV t = evalPoly evNumVPoly t − evalPoly todNumV t`. -/ +theorem evalDenExpV (t : Int) : + evalPoly ExpCertV.denExpV t = evalPoly ExpCertV.evNumVPoly t - evalPoly ExpCertV.todNumV t := by + unfold ExpCertV.denExpV; rw [evalPoly_polySub] + +/-- `evNumVPoly` is even (`= Pev(t²)`). -/ +theorem evNumVPoly_even (t : Int) : + evalPoly ExpCertV.evNumVPoly (-t) = evalPoly ExpCertV.evNumVPoly t := by + rw [evNumVPoly_eq_Pev_sq, evNumVPoly_eq_Pev_sq] + congr 1; ring + +/-- `todNumV` is odd (`= 2²³·t·Pod(t²)`). -/ +theorem todNumV_odd (t : Int) : + evalPoly ExpCertV.todNumV (-t) = -evalPoly ExpCertV.todNumV t := by + rw [evalTodNumV, evalTodNumV, odNumVPoly_eq_Pod_sq, odNumVPoly_eq_Pod_sq] + rw [show ((-t)^2 : Int) = t^2 from by ring] + ring + +/-- **Reciprocal symmetry** `numExpV(−t) = denExpV(t)` and `denExpV(−t) = numExpV(t)`. -/ +theorem numExpV_neg_eq_denExpV (t : Int) : + evalPoly ExpCertV.numExpV (-t) = evalPoly ExpCertV.denExpV t := by + rw [evalNumExpV, evalDenExpV, evNumVPoly_even, todNumV_odd]; ring + +theorem denExpV_neg_eq_numExpV (t : Int) : + evalPoly ExpCertV.denExpV (-t) = evalPoly ExpCertV.numExpV t := by + rw [evalDenExpV, evalNumExpV, evNumVPoly_even, todNumV_odd]; ring + +/-- The numerator/denominator cert-polynomial values are nonnegative / positive on `[0, H128]`. -/ +theorem certNE_nonneg {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : + 0 ≤ evalPoly ExpCertV.numExpV t := ExpCertV.numExpV_nonneg' h1 h2 + +theorem certDE_pos {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : + 1 ≤ evalPoly ExpCertV.denExpV t := ExpCertV.denExpV_ge_one h1 h2 + +/-- For `t ≤ 0` with `−t ∈ [0, H128]` the cert numerator/denominator at `t` are positive. -/ +theorem certNE_pos_neg_aux {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : + 0 < evalPoly ExpCertV.numExpV t ∧ 0 < evalPoly ExpCertV.denExpV t := by + have hnt : 0 ≤ -t := by omega + -- numExpV(t) = denExpV(-t) ≥ 1 > 0 + have h1' : evalPoly ExpCertV.numExpV t = evalPoly ExpCertV.denExpV (-t) := by + have := numExpV_neg_eq_denExpV (-t); rwa [neg_neg] at this + have hde : 1 ≤ evalPoly ExpCertV.denExpV (-t) := ExpCertV.denExpV_ge_one hnt h2 + -- denExpV(t) = evNumVPoly(t) − todNumV(t); for t ≤ 0, todNumV(t) ≤ 0, and evNumVPoly(t) ≥ 1 + have htod_np : evalPoly ExpCertV.todNumV t ≤ 0 := by + rw [evalTodNumV] + have hodnn := odNumVPoly_nonneg t + have : t * evalPoly ExpCertV.odNumVPoly t ≤ 0 := mul_nonpos_of_nonpos_of_nonneg h1 hodnn + nlinarith [this] + have hev1 : 1 ≤ evalPoly ExpCertV.evNumVPoly t := by + have heven : evalPoly ExpCertV.evNumVPoly t = evalPoly ExpCertV.evNumVPoly (-t) := by + rw [← evNumVPoly_even (-t), neg_neg] + have htodnt : 0 ≤ evalPoly ExpCertV.todNumV (-t) := by + rw [evalTodNumV] + exact Int.mul_nonneg (by positivity) (Int.mul_nonneg hnt (odNumVPoly_nonneg (-t))) + have hde' := hde + rw [evalDenExpV] at hde' + rw [heven]; linarith [hde', htodnt] + refine ⟨by rw [h1']; omega, ?_⟩ + rw [evalDenExpV]; linarith [hev1, htod_np] + +/-! ## The aligned integer rational on the `v`-grid -/ + +/-- `NUMv(v, t) = Ev(v)·2^110 + t·Od(v)` at the common scale `2^725`. -/ +def NUMv (v : Nat) (t : Int) : Int := (evNumV v : Int) * 2 ^ 110 + t * (odNumV v : Int) + +/-- `DENv(v, t) = Ev(v)·2^110 − t·Od(v)` at the common scale `2^725`. -/ +def DENv (v : Nat) (t : Int) : Int := (evNumV v : Int) * 2 ^ 110 - t * (odNumV v : Int) + +/-- `evNumV` as an `evalPoly` over the cert coefficient list. -/ +theorem evNumV_eq_poly (v : Nat) : (evNumV v : Int) = evalPoly ExpCertV.evVPoly (v : Int) := by + unfold evNumV ExpCertV.evVPoly + simp only [evalPoly] + push_cast + ring + +theorem odNumV_eq_poly (v : Nat) : (odNumV v : Int) = evalPoly ExpCertV.odVPoly (v : Int) := by + unfold odNumV ExpCertV.odVPoly + simp only [evalPoly] + push_cast + ring + +/-! ## The certified denominator floors over the grid -/ + +/-- The over-half denominator floor: `DENv(v, t) ≥ 554482771859·2^725` for `0 ≤ t ≤ H128` on the +grid `[0, vmaxV + 1]`, from the cover certificate `certDOver`. -/ +theorem DENv_ge_over {v : Nat} {t : Int} (hv : v ≤ ExpCertV.vmaxV + 1) + (ht0 : 0 ≤ t) (htH : t ≤ 117932881612756647068972071382077242199) : + 554482771859 * 2 ^ 725 ≤ DENv v t := by + have hvI : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ + have hvI2 : (v : Int) ≤ 1277263193518626341050532535110179583 := by + have h : v ≤ 1277263193518626341050532535110179583 := by + unfold ExpCertV.vmaxV at hv; omega + exact_mod_cast h + have hcert := ExpCertV.dOverV_nonneg hvI hvI2 + have hH : ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 := by + unfold ExpCertV.H128; norm_num + have hexp : evalPoly ExpCertV.certDOver (v : Int) = + (evNumV v : Int) * 2 ^ 110 - 117932881612756647068972071382077242199 * (odNumV v : Int) + - 554482771859 * 2 ^ 725 := by + unfold ExpCertV.certDOver + rw [evalPoly_polyAdd, evalPoly_polySub, evalPoly_polyScale, evalPoly_polyScale, + ← evNumV_eq_poly, ← odNumV_eq_poly, hH] + simp only [evalPoly] + ring + rw [hexp] at hcert + have hOd_nn : (0 : Int) ≤ (odNumV v : Int) := Int.natCast_nonneg _ + have htOd : t * (odNumV v : Int) ≤ 117932881612756647068972071382077242199 * (odNumV v : Int) := + mul_le_mul_of_nonneg_right htH hOd_nn + unfold DENv + linarith [hcert, htOd] + +/-- The under-half denominator floor at the domain edge: +`Ev(v)·2^110 + H128·Od(v) ≥ 786932288647·2^725` on the grid, from `certDUnder`. -/ +theorem D_at_H_ge_under {v : Nat} (hv : v ≤ ExpCertV.vmaxV + 1) : + 786932288647 * 2 ^ 725 ≤ + (evNumV v : Int) * 2 ^ 110 + 117932881612756647068972071382077242199 * (odNumV v : Int) := by + have hvI : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ + have hvI2 : (v : Int) ≤ 1277263193518626341050532535110179583 := by + have h : v ≤ 1277263193518626341050532535110179583 := by + unfold ExpCertV.vmaxV at hv; omega + exact_mod_cast h + have hcert := ExpCertV.dUnderV_nonneg hvI hvI2 + have hH : ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 := by + unfold ExpCertV.H128; norm_num + have hexp : evalPoly ExpCertV.certDUnder (v : Int) = + (evNumV v : Int) * 2 ^ 110 + 117932881612756647068972071382077242199 * (odNumV v : Int) + - 786932288647 * 2 ^ 725 := by + unfold ExpCertV.certDUnder + rw [evalPoly_polyAdd, evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyScale, + ← evNumV_eq_poly, ← odNumV_eq_poly, hH] + simp only [evalPoly] + ring + rw [hexp] at hcert + linarith [hcert] + +/-- The scaled even value dominates the whole `H128`-scaled odd value (the over floor is positive): +`H128·Od(v) ≤ Ev(v)·2^110` on the grid. -/ +theorem HOd_le_Ev {v : Nat} (hv : v ≤ ExpCertV.vmaxV + 1) : + 117932881612756647068972071382077242199 * (odNumV v : Int) ≤ (evNumV v : Int) * 2 ^ 110 := by + have h := DENv_ge_over hv (t := 117932881612756647068972071382077242199) (by norm_num) le_rfl + unfold DENv at h + have : (0 : Int) < 554482771859 * 2 ^ 725 := by positivity + linarith [h, this] + +/-- The scaled even value alone clears the over floor. -/ +theorem Ev_scaled_ge {v : Nat} (hv : v ≤ ExpCertV.vmaxV + 1) : + 554482771859 * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 110 := by + have h := DENv_ge_over hv (t := 0) le_rfl (by norm_num) + unfold DENv at h + linarith [h] + +/-- On the nonpositive half the denominator is bounded below by the scaled even value. -/ +theorem DENv_ge_neg {v : Nat} {t : Int} (hv : v ≤ ExpCertV.vmaxV + 1) (htnp : t ≤ 0) : + 554482771859 * 2 ^ 725 ≤ DENv v t := by + have hOd_nn : (0 : Int) ≤ (odNumV v : Int) := Int.natCast_nonneg _ + have h := Ev_scaled_ge hv + have htOd : t * (odNumV v : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htnp hOd_nn + unfold DENv + linarith [h, htOd] + +/-! ## The `K` step polynomial -/ + +/-- One-grid-step cross product `K(v) = Od(v)·Ev(v+1) − Ev(v)·Od(v+1)`. -/ +def KpM (v : Nat) : Int := + (odNumV v : Int) * (evNumV (v + 1) : Int) - (evNumV v : Int) * (odNumV (v + 1) : Int) + +/-- `K` expanded: degree 8 in `v`, all nine coefficients positive. -/ +def Kpoly : List Int := [ + 124314103365382948540818484389625511162300300154596353471434559263576710760858295817293092085008263137731720671247221648067596832296011712645000813284745609572799860614715339074429845004953604219102947508964005670501289338774093304568104691068782792841751722685380505527135804513603544359590666402647994177984765095548996198922954351638285344422494208, + 430693347524554794343417296651509686134557738098954307704214627733020390530278276854672725773269273195478624746887483823521915971792313550530664645765146330112240663991043334744169297019302744406385806086948888789809498977224640089404613426031164334553095878029211115721153838092053743221232923214856740321361920, + 686241798384522667273603851832009005832991722966895305486733489217475120780434741578221376750207665260280559483314421737861160359613911796076366378147384024630930905683143857451910151039919766317250012570559885388869355828462187828089296162106016837843019513341114421608448, + 516930441971039446793370708723350125364637202395800871195912177274842681404775759909985132791355705126258878499764647160096038572134699599657143783480012402118176141075234265877953175422112442922930396729118643533020785802714646839296, + 204444652500469654421705147174126797534284466591134372022748954577461360623715926111412069421315335549677153452480685493529231437120364790325762132070320513045724004787419978918913755181249161744, + 41949223685511975480580776931828146057677792415359815945353299890032432268755601779612364142307888289245407764490095148612742616445009325314635169114466368, + 4316880982720124500406644109788966154643851890842252965238156761257284790660493659638039728545632279862302184602720, + 177702252311948919910468951720184092402653220933754361350350337206870976576, + 4462739169817451478086891138411024] + +/-- `K(vmaxV)`, the grid maximum of the step polynomial. -/ +def KVMAXc : Int := + 124865332739294834873516593328989107938627445220226415417519301074933005975501368871244922433473497551230403824606042833804361870589257536716807944070843003611163671987701060317587976677928870720398225511779857554302723969319393493947608003945282319951972195880806029003395011394810609114195299961562530515199537076949072909524942387258516947793649920 + +theorem Kpoly_coeffs_nonneg : ∀ c ∈ Kpoly, (0 : Int) ≤ c := by + unfold Kpoly; intro c hc; fin_cases hc <;> norm_num + +theorem KpM_eq_poly (v : Nat) : KpM v = evalPoly Kpoly (v : Int) := by + unfold KpM evNumV odNumV Kpoly + simp only [evalPoly] + push_cast + ring + +theorem KpM_nonneg (v : Nat) : 0 ≤ KpM v := by + rw [KpM_eq_poly] + exact evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (Int.natCast_nonneg _) + +theorem KpM_le_KVMAX {v : Nat} (hv : v ≤ ExpCertV.vmaxV) : KpM v ≤ KVMAXc := by + rw [KpM_eq_poly] + have hvI : (v : Int) ≤ (1277263193518626341050532535110179582 : Int) := by + have h : v ≤ 1277263193518626341050532535110179582 := by + unfold ExpCertV.vmaxV at hv; omega + exact_mod_cast h + have h1 : evalPoly Kpoly (v : Int) ≤ + evalPoly Kpoly (1277263193518626341050532535110179582 : Int) := + evalPoly_mono_of_nonneg Kpoly_coeffs_nonneg (Int.natCast_nonneg _) hvI + have h2 : evalPoly Kpoly (1277263193518626341050532535110179582 : Int) = KVMAXc := by + simp only [Kpoly, evalPoly, KVMAXc] + norm_num + linarith [h1, h2 ▸ h1] + +/-- **The discrete quotient identity**: one grid step of the aligned rational is exact algebra. -/ +theorem step_identity (v : Nat) (t : Int) : + NUMv v t * DENv (v + 1) t - NUMv (v + 1) t * DENv v t = 2 * t * 2 ^ 110 * KpM v := by + unfold NUMv DENv KpM + ring + +/-! ## Grid placement of the exact square -/ + +/-- The squared reduced argument splits as `t² = 2¹³³·vTree x + r` with `0 ≤ r < 2¹³³`. -/ +theorem tsq_split {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + 2 ^ 133 * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ + (int256 (tTree x)) ^ 2 < 2 ^ 133 * (vTree x : Int) + 2 ^ 133 := by + obtain ⟨hveq, _⟩ := vTree_eq hx hC hC0 + have hsqnn : (0 : Int) ≤ (int256 (tTree x)) ^ 2 := sq_nonneg _ + have hdm := Int.ediv_add_emod ((int256 (tTree x)) ^ 2) (2 ^ 133) + have hmod_lt := Int.emod_lt_of_pos ((int256 (tTree x)) ^ 2) (by norm_num : (0:Int) < 2 ^ 133) + have hmod_nn := Int.emod_nonneg ((int256 (tTree x)) ^ 2) (by norm_num : (2:Int) ^ 133 ≠ 0) + rw [hveq] + constructor + · nlinarith [hdm, hmod_nn] + · nlinarith [hdm, hmod_lt] + +/-- The grid index never leaves the certified domain: `vTree x ≤ vmaxV`. -/ +theorem vTree_le_vmax {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + vTree x ≤ ExpCertV.vmaxV := by + obtain ⟨hlo, _⟩ := tsq_split hx hC hC0 + obtain ⟨htlo, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have ht2 : (int256 (tTree x)) ^ 2 ≤ 117932881612756647068972071382077242199 ^ 2 := by + nlinarith [htlo, hthi] + have hlt : 2 ^ 133 * (vTree x : Int) < + 2 ^ 133 * (1277263193518626341050532535110179583 : Int) := by + calc 2 ^ 133 * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 := hlo + _ ≤ 117932881612756647068972071382077242199 ^ 2 := ht2 + _ < 2 ^ 133 * 1277263193518626341050532535110179583 := by norm_num + have hvI : (vTree x : Int) < 1277263193518626341050532535110179583 := + lt_of_mul_lt_mul_left hlt (by positivity) + have hvN : vTree x < 1277263193518626341050532535110179583 := by exact_mod_cast hvI + unfold ExpCertV.vmaxV + omega + +/-! ## Cross-monotonicity of the rational in the square argument -/ + +/-- Power cross-product monotonicity: `a^(j+d)·b^j ≤ a^j·b^(j+d)` for `0 ≤ a ≤ b`. -/ +theorem pow_pair_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) (j d : Nat) : + a ^ (j + d) * b ^ j ≤ a ^ j * b ^ (j + d) := by + have hb : 0 ≤ b := le_trans ha hab + have h := pow_le_pow_left₀ ha hab d + calc a ^ (j + d) * b ^ j = (a ^ j * b ^ j) * a ^ d := by rw [pow_add]; ring + _ ≤ (a ^ j * b ^ j) * b ^ d := by + exact mul_le_mul_of_nonneg_left h (mul_nonneg (pow_nonneg ha _) (pow_nonneg hb _)) + _ = a ^ j * b ^ (j + d) := by rw [pow_add]; ring + +/-- **The cross product is one-signed**: `Pev(b)·Pod(a) − Pev(a)·Pod(b) ≥ 0` for `0 ≤ a ≤ b`. Every +pairwise coefficient cross `e_i·o_j − e_j·o_i` (`i > j`) is nonnegative, and each pair's power +cross `a^j·b^i − a^i·b^j` is nonnegative on `0 ≤ a ≤ b`. -/ +theorem pev_pod_cross {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : + 0 ≤ evalPoly Pev b * evalPoly Pod a - evalPoly Pev a * evalPoly Pod b := by + have hexpand : evalPoly Pev b * evalPoly Pod a - evalPoly Pev a * evalPoly Pod b = + (((0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) + + (((0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) + + (((0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) + + (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) + + (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) + + (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) + + (((1) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) + + (((1) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) + + (((1) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) + + (((1) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) + + (((1) * (0xdc07aff8276bde9a361278df6a10) - (0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0) : Int)) * (a ^ 4 * b ^ 5 - a ^ 5 * b ^ 4) := by + simp only [Pev, Pod, evalPoly] + ring + have h10 : (0:Int) ≤ (((0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 1; simpa using this) + have h20 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 2; simpa using this) + have h21 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 1; simpa using this) + have h30 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 3; simpa using this) + have h31 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 2; simpa using this) + have h32 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 1; simpa using this) + have h40 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 4; simpa using this) + have h41 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 3; simpa using this) + have h42 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 2; simpa using this) + have h43 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 3 1; simpa using this) + have h50 : (0:Int) ≤ (((1) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 5; simpa using this) + have h51 : (0:Int) ≤ (((1) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 4; simpa using this) + have h52 : (0:Int) ≤ (((1) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 3; simpa using this) + have h53 : (0:Int) ≤ (((1) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 3 2; simpa using this) + have h54 : (0:Int) ≤ (((1) * (0xdc07aff8276bde9a361278df6a10) - (0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0) : Int)) * (a ^ 4 * b ^ 5 - a ^ 5 * b ^ 4) := + mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 4 1; simpa using this) + rw [hexpand] + linarith [h10, h20, h21, h30, h31, h32, h40, h41, h42, h43, h50, h51, h52, h53, h54] + +/-- **The tie**: with `s ≥ 0` and `0 ≤ a ≤ b`, the `w`-argument rational is nonincreasing: +`(Pev(b) + s·Pod(b))·(Pev(a) − s·Pod(a)) ≤ (Pev(a) + s·Pod(a))·(Pev(b) − s·Pod(b))`. -/ +theorem tie_cross {a b : Int} (s : Int) (ha : 0 ≤ a) (hab : a ≤ b) (hs : 0 ≤ s) : + (evalPoly Pev b + s * evalPoly Pod b) * (evalPoly Pev a - s * evalPoly Pod a) ≤ + (evalPoly Pev a + s * evalPoly Pod a) * (evalPoly Pev b - s * evalPoly Pod b) := by + have hG := pev_pod_cross ha hab + have hid : (evalPoly Pev a + s * evalPoly Pod a) * (evalPoly Pev b - s * evalPoly Pod b) - + (evalPoly Pev b + s * evalPoly Pod b) * (evalPoly Pev a - s * evalPoly Pod a) = + 2 * (s * (evalPoly Pev b * evalPoly Pod a - evalPoly Pev a * evalPoly Pod b)) := by + ring + have := mul_nonneg hs hG + linarith [hid, this] + +/-! ## The grid/cert bridge -/ + +/-- The `w`-polynomials at a grid point recover the aligned rational's numerator (scale `2^555`). -/ +theorem grid_num_eq (v : Nat) (t : Int) : + evalPoly Pev (2 ^ 133 * (v : Int)) + 2 ^ 23 * t * evalPoly Pod (2 ^ 133 * (v : Int)) = + 2 ^ 555 * NUMv v t := by + rw [Pev_grid, Pod_grid] + unfold NUMv + ring + +theorem grid_den_eq (v : Nat) (t : Int) : + evalPoly Pev (2 ^ 133 * (v : Int)) - 2 ^ 23 * t * evalPoly Pod (2 ^ 133 * (v : Int)) = + 2 ^ 555 * DENv v t := by + rw [Pev_grid, Pod_grid] + unfold DENv + ring + +/-- The cert polynomials at `t` are the `w`-polynomials at the exact square. -/ +theorem NE_eq_w (t : Int) : + evalPoly ExpCertV.numExpV t = evalPoly Pev (t ^ 2) + 2 ^ 23 * t * evalPoly Pod (t ^ 2) := by + rw [evalNumExpV, evalTodNumV, ← evNumVPoly_eq_Pev_sq, ← odNumVPoly_eq_Pod_sq] + ring + +theorem DE_eq_w (t : Int) : + evalPoly ExpCertV.denExpV t = evalPoly Pev (t ^ 2) - 2 ^ 23 * t * evalPoly Pod (t ^ 2) := by + rw [evalDenExpV, evalTodNumV, ← evNumVPoly_eq_Pev_sq, ← odNumVPoly_eq_Pod_sq] + ring + +/-- **The tie at the runtime point (nonnegative half)**: the cert rational at `t²` lies between the +two grid values, as cross products. -/ +theorem tie_over {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + evalPoly ExpCertV.numExpV (int256 (tTree x)) * DENv (vTree x) (int256 (tTree x)) ≤ + NUMv (vTree x) (int256 (tTree x)) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ + NUMv (vTree x + 1) (int256 (tTree x)) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ + evalPoly ExpCertV.numExpV (int256 (tTree x)) * DENv (vTree x + 1) (int256 (tTree x)) := by + obtain ⟨haw, hwb⟩ := tsq_split hx hC hC0 + set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + have hs : (0:Int) ≤ 2 ^ 23 * t := by positivity + have ha : (0:Int) ≤ 2 ^ 133 * (v : Int) := by positivity + have hw : (0:Int) ≤ t ^ 2 := sq_nonneg _ + have hb1 : t ^ 2 ≤ 2 ^ 133 * ((v + 1 : Nat) : Int) := by push_cast; linarith [hwb] + have hp555 : (0:Int) < 2 ^ 555 := by positivity + constructor + · -- a := grid v, b := t²: NE·(2^555·DENv v) ≤ (2^555·NUMv v)·DE + have h1 := tie_cross (a := 2 ^ 133 * (v : Int)) (b := t ^ 2) (2 ^ 23 * t) ha haw hs + rw [grid_num_eq, grid_den_eq, ← NE_eq_w, ← DE_eq_w] at h1 + -- h1 : NE·(2^555·DENv v t) ≤ (2^555·NUMv v t)·DE + have h2 : 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv v t) ≤ + 2 ^ 555 * (NUMv v t * evalPoly ExpCertV.denExpV t) := by + calc 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv v t) + = evalPoly ExpCertV.numExpV t * (2 ^ 555 * DENv v t) := by ring + _ ≤ 2 ^ 555 * NUMv v t * evalPoly ExpCertV.denExpV t := h1 + _ = 2 ^ 555 * (NUMv v t * evalPoly ExpCertV.denExpV t) := by ring + exact le_of_mul_le_mul_left h2 hp555 + · -- a := t², b := grid (v+1): (2^555·NUMv (v+1))·DE ≤ NE·(2^555·DENv (v+1)) + have h1 := tie_cross (a := t ^ 2) (b := 2 ^ 133 * ((v + 1 : Nat) : Int)) (2 ^ 23 * t) hw hb1 hs + rw [grid_num_eq, grid_den_eq, ← NE_eq_w, ← DE_eq_w] at h1 + -- h1 : (2^555·NUMv (v+1) t)·DE ≤ NE·(2^555·DENv (v+1) t) + have h2 : 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) ≤ + 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) := by + calc 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) + = 2 ^ 555 * NUMv (v + 1) t * evalPoly ExpCertV.denExpV t := by ring + _ ≤ evalPoly ExpCertV.numExpV t * (2 ^ 555 * DENv (v + 1) t) := h1 + _ = 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) := by ring + exact le_of_mul_le_mul_left h2 hp555 + +/-- **The tie at the runtime point (nonpositive half)**: the directions flip. -/ +theorem tie_under {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnp : int256 (tTree x) ≤ 0) : + NUMv (vTree x) (int256 (tTree x)) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ + evalPoly ExpCertV.numExpV (int256 (tTree x)) * DENv (vTree x) (int256 (tTree x)) ∧ + evalPoly ExpCertV.numExpV (int256 (tTree x)) * DENv (vTree x + 1) (int256 (tTree x)) ≤ + NUMv (vTree x + 1) (int256 (tTree x)) * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by + obtain ⟨haw, hwb⟩ := tsq_split hx hC hC0 + set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + have hs : (0:Int) ≤ 2 ^ 23 * (-t) := by + have : (0:Int) ≤ -t := by linarith [htnp] + positivity + have ha : (0:Int) ≤ 2 ^ 133 * (v : Int) := by positivity + have hw : (0:Int) ≤ t ^ 2 := sq_nonneg _ + have hb1 : t ^ 2 ≤ 2 ^ 133 * ((v + 1 : Nat) : Int) := by push_cast; linarith [hwb] + have hp555 : (0:Int) < 2 ^ 555 := by positivity + -- with σ = −s ≥ 0, the `N`/`D` roles swap: Pev + σ·Pod = DENv-form, Pev − σ·Pod = NUMv-form + constructor + · have h1 := tie_cross (a := 2 ^ 133 * (v : Int)) (b := t ^ 2) (2 ^ 23 * (-t)) ha haw hs + -- rewrite σ-forms into t-forms: Pev x + 2^23·(−t)·Pod x = Pev x − 2^23·t·Pod x + have e1 : evalPoly Pev (t ^ 2) + 2 ^ 23 * (-t) * evalPoly Pod (t ^ 2) = + evalPoly ExpCertV.denExpV t := by rw [DE_eq_w]; ring + have e2 : evalPoly Pev (2 ^ 133 * (v : Int)) - 2 ^ 23 * (-t) * evalPoly Pod (2 ^ 133 * (v : Int)) = + 2 ^ 555 * NUMv v t := by rw [← grid_num_eq]; ring + have e3 : evalPoly Pev (2 ^ 133 * (v : Int)) + 2 ^ 23 * (-t) * evalPoly Pod (2 ^ 133 * (v : Int)) = + 2 ^ 555 * DENv v t := by rw [← grid_den_eq]; ring + have e4 : evalPoly Pev (t ^ 2) - 2 ^ 23 * (-t) * evalPoly Pod (t ^ 2) = + evalPoly ExpCertV.numExpV t := by rw [NE_eq_w]; ring + rw [e1, e2, e3, e4] at h1 + -- h1 : DE·(2^555·NUMv v t) ≤ (2^555·DENv v t)·NE + have h2 : 2 ^ 555 * (NUMv v t * evalPoly ExpCertV.denExpV t) ≤ + 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv v t) := by + calc 2 ^ 555 * (NUMv v t * evalPoly ExpCertV.denExpV t) + = evalPoly ExpCertV.denExpV t * (2 ^ 555 * NUMv v t) := by ring + _ ≤ 2 ^ 555 * DENv v t * evalPoly ExpCertV.numExpV t := h1 + _ = 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv v t) := by ring + exact le_of_mul_le_mul_left h2 hp555 + · have h1 := tie_cross (a := t ^ 2) (b := 2 ^ 133 * ((v + 1 : Nat) : Int)) (2 ^ 23 * (-t)) hw hb1 hs + have e1 : evalPoly Pev (2 ^ 133 * ((v + 1 : Nat) : Int)) + + 2 ^ 23 * (-t) * evalPoly Pod (2 ^ 133 * ((v + 1 : Nat) : Int)) = + 2 ^ 555 * DENv (v + 1) t := by rw [← grid_den_eq]; ring + have e2 : evalPoly Pev (t ^ 2) - 2 ^ 23 * (-t) * evalPoly Pod (t ^ 2) = + evalPoly ExpCertV.numExpV t := by rw [NE_eq_w]; ring + have e3 : evalPoly Pev (t ^ 2) + 2 ^ 23 * (-t) * evalPoly Pod (t ^ 2) = + evalPoly ExpCertV.denExpV t := by rw [DE_eq_w]; ring + have e4 : evalPoly Pev (2 ^ 133 * ((v + 1 : Nat) : Int)) - + 2 ^ 23 * (-t) * evalPoly Pod (2 ^ 133 * ((v + 1 : Nat) : Int)) = + 2 ^ 555 * NUMv (v + 1) t := by rw [← grid_num_eq]; ring + rw [e1, e2, e3, e4] at h1 + -- h1 : (2^555·DENv (v+1) t)·NE ≤ DE·(2^555·NUMv (v+1) t) + have h2 : 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) ≤ + 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) := by + calc 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) + = 2 ^ 555 * DENv (v + 1) t * evalPoly ExpCertV.numExpV t := by ring + _ ≤ evalPoly ExpCertV.denExpV t * (2 ^ 555 * NUMv (v + 1) t) := h1 + _ = 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) := by ring + exact le_of_mul_le_mul_left h2 hp555 + + +end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index 6d711e8fa..904b5e834 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -13,10 +13,12 @@ The public floor brackets need the Q126 quotient `r0Tree x` bracketed against th `E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(126 − k)`. This file builds two ingredients of that discharge: -* the **Horner-truncation bridge** for the even accumulator — the runtime `evTree x`, which - truncates each Horner `>>` stage, brackets the exact even polynomial `evNumV (vTree x)` (a degree-5 - polynomial in `v` at the cleared scale `2^553`) within `2` units: per-stage floor losses telescope - with shrinking amplification (each stage shift exceeds `126 = ⌈log₂ v⌉`); +* the **Horner-truncation bridge** for the even/odd accumulators — the runtime `evTree x`/`odTree x`, + which truncate each Horner `>>` stage, bracket the exact integer polynomials `evNumV (vTree x)` + (degree 5, cleared scale `2^528`) and `odNumV (vTree x)` (degree 4, cleared scale `2^510`): the + monic leading stage is an exact add, and the four lossy stages' floor losses telescope with + shrinking amplification (each stage shift exceeds `120 = ⌈log₂ v⌉`), leaving widths + `283678831804417·2^480 ≈ 1.0079·2^528` and `1075052609·2^480 ≈ 1.0013·2^510`; * the self-contained **below-clamp bound** — below the clamp boundary the target is under one output unit — directly from a `Real.exp` rational bound. -/ @@ -29,13 +31,13 @@ open FormalYul.Preservation set_option maxRecDepth 100000 set_option maxHeartbeats 1000000 -/-! ## Gap-2: the even Horner accumulator brackets the exact polynomial +/-! ## The Horner accumulators bracket the exact polynomials Each runtime Horner stage `evmAdd c (evmShr sh (evmMul prev v))` is the integer floor -`c + ⌊prev·v / 2^sh⌋`; the floor loss `< 1` at scale `2^sh`. Cleared to the common scale `2^553` -the runtime accumulator `evTree x` brackets the exact degree-5 polynomial `evNumV (vTree x)` within -`2·2^553`: the propagated loss stays below `2^sh` because every stage shift exceeds the `126`-bit -width of `v = vTree x`. -/ +`c + ⌊prev·v / 2^sh⌋`; the floor loss `< 1` at scale `2^sh`. The *fractional* telescope tracks the +exact deficit width as `Wnum·2^p` (a dyadic rational `Wnum/2^(cum−p)` at the cumulative scale +`2^cum`). Across a stage with shift `s ≥ 120` the carried width is attenuated by +`v/2^s ≤ 2^(120−s) < 1`, so the width evolves as `W' = W·2^(120−s) + 1` and stays near one unit. -/ theorem stage_exact {c prev v sh : Nat} (hprev : prev < 2^256) (hvw : v < 2^256) (hpv : prev * v < 2 ^ 256) (hsh : sh < 256) @@ -53,72 +55,24 @@ theorem stage_exact {c prev v sh : Nat} (hprev : prev < 2^256) (hvw : v < 2^256) generalize prev * v % 2 ^ sh = r at * omega -theorem tele_step (e0 e1 v A c0 s E0 : Nat) - (hv : v < 2^126) (hs : 127 ≤ s) (hAe1 : A ≤ e1) - (hb0lo : 2^c0 * e0 ≤ E0) (hb0hi : E0 < 2^c0 * e0 + 2 * 2^c0) - (hslo : 2^s * (e1 - A) ≤ e0 * v) (hshi : e0 * v < 2^s * (e1 - A) + 2^s) : - 2^(c0+s) * e1 ≤ A * 2^(c0+s) + E0 * v ∧ - A * 2^(c0+s) + E0 * v < 2^(c0+s) * e1 + 2 * 2^(c0+s) := by - have hpc0 : (0:Nat) < 2^c0 := Nat.two_pow_pos _ - have hps : (0:Nat) < 2^s := Nat.two_pow_pos _ - have hsplit : (2:Nat)^(c0+s) = 2^c0 * 2^s := by rw [Nat.pow_add] - set d := e1 - A with hd - have he1eq : e1 = A + d := by omega - have hvs : 2 * 2^c0 * v < 2^(c0+s) := by - rw [hsplit] - have h2v : 2 * v < 2^s := by - have h127 : (2:Nat)*2^126 = 2^127 := by ring - have h128 : (2:Nat)^127 ≤ 2^s := Nat.pow_le_pow_right (by norm_num) (by omega) - omega - calc 2*2^c0*v = 2^c0*(2*v) := by ring - _ < 2^c0 * 2^s := (Nat.mul_lt_mul_left hpc0).mpr h2v - rw [hsplit, he1eq] - have key_lo : 2^c0 * 2^s * d ≤ E0 * v := by - calc 2^c0 * 2^s * d = 2^c0 * (2^s * d) := by ring - _ ≤ 2^c0 * (e0 * v) := by gcongr - _ = (2^c0 * e0) * v := by ring - _ ≤ E0 * v := by gcongr - have hps2 : (0:Nat) < 2^(c0+s) := Nat.two_pow_pos _ - have key_hi : E0 * v < 2^c0 * 2^s * d + 2 * 2^(c0+s) := by - rcases Nat.eq_zero_or_pos v with hv0 | hv0 - · subst hv0; simpa using hps2 - have h1 : E0 * v < (2^c0 * e0 + 2*2^c0) * v := (Nat.mul_lt_mul_right hv0).mpr hb0hi - have h2 : (2^c0 * e0 + 2*2^c0) * v = 2^c0 * (e0*v) + 2*2^c0*v := by ring - have h3 : 2^c0 * (e0*v) < 2^c0 * (2^s*d + 2^s) := (Nat.mul_lt_mul_left hpc0).mpr hshi - have h4 : 2^c0 * (2^s*d+2^s) = 2^c0*2^s*d + 2^c0*2^s := by ring - rw [hsplit] at hvs - omega - constructor - · nlinarith [key_lo] - · nlinarith [key_hi] - -/-! ## The fractional telescoping bound - -The integer `tele_step` above yields a per-stage `+2` width because it carries the input width -verbatim (`E0 < 2^c0·e0 + 2·2^c0`). The *fractional* version tracks the exact deficit width as -`Wnum·2^p` (a dyadic rational `Wnum/2^(cum-p)` at the cumulative scale `2^cum`). Across a stage with -shift `s ≥ 127` the carried width is attenuated by `v/2^s ≤ 2^(126-s) < 1`, so the width evolves as -`W' = W·2^(126-s) + 1`. With `r_i = 2^(126-s_i) < 1` the widths stay strictly below `1/(1−max r)`, -recovering the true ≈1.02-unit gap-2 envelope instead of the loose `+2`. - -The state is `2^cum·e ≤ E < 2^cum·e + Wnum·2^p` with `p ≤ cum` (the width exponent). One stage with -shift `s` (constant `A`, `e1 = A + ⌊e0·v/2^s⌋`) produces the new width `Wnum' = Wnum + 2^(cum+s−p−126)` -at exponent `p' = p + 126` and scale `cum' = cum + s`. -/ +/-- The state is `2^cum·e ≤ E < 2^cum·e + Wnum·2^p` with `p ≤ cum` (the width exponent). One stage +with shift `s ≥ 120` (constant `A`, `e1 = A + ⌊e0·v/2^s⌋`, `v < 2^120`) produces the new width +`Wnum' = Wnum + 2^(cum+s−p−120)` at exponent `p' = p + 120` and scale `cum' = cum + s`. -/ theorem tele_step_frac (e0 e1 v A cum s p Wnum E0 : Nat) - (hv : v < 2^126) (hs : 126 ≤ s) (hAe1 : A ≤ e1) (hpcum : p + 126 ≤ cum + s) + (hv : v < 2^120) (hs : 120 ≤ s) (hAe1 : A ≤ e1) (hpcum : p + 120 ≤ cum + s) (hb0lo : 2^cum * e0 ≤ E0) (hb0hi : E0 < 2^cum * e0 + Wnum * 2^p) (hslo : 2^s * (e1 - A) ≤ e0 * v) (hshi : e0 * v < 2^s * (e1 - A) + 2^s) : 2^(cum+s) * e1 ≤ A * 2^(cum+s) + E0 * v ∧ A * 2^(cum+s) + E0 * v < - 2^(cum+s) * e1 + (Wnum + 2^(cum+s-(p+126))) * 2^(p+126) := by + 2^(cum+s) * e1 + (Wnum + 2^(cum+s-(p+120))) * 2^(p+120) := by -- factor the relevant power identities, then abstract every `2^…` to an opaque var have hsplit : (2:Nat)^(cum+s) = 2^cum * 2^s := by rw [Nat.pow_add] - -- key: 2^cum · 2^s = 2^(p+126) · 2^(cum+s-(p+126)) = 2^p · 2^126 · G - have hG : (2:Nat)^cum * 2^s = (2^p * 2^126) * 2^(cum+s-(p+126)) := by - rw [show (2:Nat)^p * 2^126 = 2^(p+126) from by rw [Nat.pow_add], + -- key: 2^cum · 2^s = 2^(p+120) · 2^(cum+s-(p+120)) = 2^p · 2^120 · G + have hG : (2:Nat)^cum * 2^s = (2^p * 2^120) * 2^(cum+s-(p+120)) := by + rw [show (2:Nat)^p * 2^120 = 2^(p+120) from by rw [Nat.pow_add], ← Nat.pow_add, ← Nat.pow_add]; congr 1; omega - have hPP126 : (2:Nat)^(p+126) = 2^p * 2^126 := by rw [Nat.pow_add] - have hP126 : (0:Nat) < 2^126 := Nat.two_pow_pos _ + have hPP120 : (2:Nat)^(p+120) = 2^p * 2^120 := by rw [Nat.pow_add] + have hP120 : (0:Nat) < 2^120 := Nat.two_pow_pos _ have hPcum : (0:Nat) < 2^cum := Nat.two_pow_pos _ set d := e1 - A with hd have he1eq : e1 = A + d := by omega @@ -126,11 +80,11 @@ theorem tele_step_frac (e0 e1 v A cum s p Wnum E0 : Nat) set P := (2:Nat)^cum with hPdef set Q := (2:Nat)^s with hQdef set R := (2:Nat)^p with hRdef - set H := (2:Nat)^126 with hHdef - set G := (2:Nat)^(cum+s-(p+126)) with hGdef + set H := (2:Nat)^120 with hHdef + set G := (2:Nat)^(cum+s-(p+120)) with hGdef -- collected facts in abstract form rw [hsplit, he1eq] - rw [show (2:Nat)^(p+126) = R * H from hPP126] + rw [show (2:Nat)^(p+120) = R * H from hPP120] have hPQ : P * Q = (R * H) * G := hG have hvH : v ≤ H := le_of_lt hv have hRpos : 0 < R := by rw [hRdef]; exact Nat.two_pow_pos _ @@ -171,162 +125,160 @@ theorem tele_step_frac (e0 e1 v A cum s p Wnum E0 : Nat) Nat.add_lt_add_left key_hi _ _ = P * Q * (A + d) + (Wnum + G) * (R * H) := by ring -theorem ev0_exact {v : Nat} (hv : v < 2 ^ 126) : - 2^0x1d * (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) - 0xb9aacfad41060587203a79af0ebc) ≤ v ∧ - v < 2^0x1d * (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) - 0xb9aacfad41060587203a79af0ebc) + 2^0x1d := by - have hshr : evmShr 0x1d v = v / 2^0x1d := evmShr_eq_div (by norm_num) (by omega) - have ht : v / 2^0x1d < 2^97 := by - have : v / 2^0x1d < 2^126/2^0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv - have he : (2:Nat)^126/2^0x1d = 2^97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] - omega - rw [hshr, evmAdd_eq_nat (by norm_num) (by omega) (by omega), Nat.add_sub_cancel_left] - have hpos : 0 < 2^0x1d := Nat.two_pow_pos _ - have hdm := Nat.div_add_mod v (2^0x1d) - have hmod := Nat.mod_lt v hpos - generalize v / 2^0x1d = q at * - generalize v % 2^0x1d = r at * - omega - -def evNumV (v : Nat) : Nat := - let e0 := 0xb9aacfad41060587203a79af0ebc * 2^29 + v - let e1 := 0x9a036222e11aee18465042f8ea64c8 * 2^159 + e0 * v - let e2 := 0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + e1 * v - let e3 := 0x93f11e65781741b92fa7fc4f4fffcca2 * 2^421 + e2 * v - 0x4e14a45e8ec305e233e11b4174e214ac * 2^553 + e3 * v - -/-- One telescoped runtime Horner stage: the stage value `evmAdd c (shr sh (mul prev v))` cleared to -scale `2^(cum+sh)` brackets `c·2^(cum+sh) + Eprev·v` within `2·2^(cum+sh)`, given the cumulative -bracket on `prev` at scale `2^cum`. -/ -theorem horner_stage (c P prev v cum sh Eprev : Nat) - (hv : v < 2^126) (hs : 127 ≤ sh) (hsh256 : sh < 256) (hprevlt : prev < P) (hPV : P * 2^126 < 2^256) - (hsum : c + P * 2^126 / 2^sh < 2^256) (hclt : c < 2^256) - (hElo : 2^cum * prev ≤ Eprev) (hEhi : Eprev < 2^cum * prev + 2 * 2^cum) : - 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) ≤ c * 2^(cum+sh) + Eprev * v ∧ - c * 2^(cum+sh) + Eprev * v < 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) + 2 * 2^(cum+sh) := by - have hprev256 : prev < 2^256 := by have : P ≤ 2^256 := by omega - omega - have hv256 : v < 2^256 := by have : (2:Nat)^126 < 2^256 := by norm_num - omega - have hpv : prev * v < 2^256 := lt_of_lt_of_le (Nat.mul_lt_mul'' hprevlt hv) (by omega) - have hsum' : c + prev * v / 2^sh < 2^256 := by - have : prev * v / 2^sh ≤ P * 2^126 / 2^sh := by - apply Nat.div_le_div_right; exact Nat.le_of_lt (Nat.mul_lt_mul'' hprevlt hv) - omega - have hst := stage_exact hprev256 hv256 hpv hsh256 hclt hsum' - set ev1 := evmAdd c (evmShr sh (evmMul prev v)) with hev1 - have hge : c ≤ ev1 := by - rw [hev1, evmAdd_eq_nat hclt (by exact evmShr_lt _ _) (by - have hmul : evmMul prev v = prev * v := evmMul_eq_nat hprev256 hv256 hpv - have : evmShr sh (evmMul prev v) = prev*v/2^sh := by rw [hmul]; exact evmShr_eq_div (by omega) hpv - rw [this]; omega)] - omega - exact tele_step prev ev1 v c cum sh Eprev hv hs hge hElo hEhi hst.1 hst.2 - -/-- The fractional version of `horner_stage`: a runtime Horner stage propagates a *dyadic-fraction* -deficit width `Wnum·2^p` into `(Wnum + 2^(cum+sh−p−126))·2^(p+126)` (the carried width is attenuated -by `v/2^sh ≤ 2^(126−sh) < 1`). Consumes `tele_step_frac`. -/ -theorem horner_stage_frac (c P prev v cum sh p Wnum Eprev : Nat) - (hv : v < 2^126) (hs : 126 ≤ sh) (hsh256 : sh < 256) (hprevlt : prev < P) - (hPV : P * 2^126 < 2^256) (hpcum : p + 126 ≤ cum + sh) - (hsum : c + P * 2^126 / 2^sh < 2^256) (hclt : c < 2^256) +/-- One runtime Horner stage propagates a dyadic-fraction deficit width `Wnum·2^p` into +`(Wnum + 2^(cum+sh−p−120))·2^(p+120)` (the carried width is attenuated by `v/2^sh ≤ 2^(120−sh) < 1`). +Consumes `tele_step_frac`; the word-arithmetic side conditions are discharged from the raw product +bound `prev·v < 2^256` and the coefficient cap `c < 2^160`. -/ +theorem horner_stage_frac (c prev v cum sh p Wnum Eprev : Nat) + (hv : v < 2^120) (hs : 120 ≤ sh) (hsh256 : sh < 256) + (hprev256 : prev < 2^256) (hpv : prev * v < 2^256) (hclt : c < 2^160) + (hpcum : p + 120 ≤ cum + sh) (hElo : 2^cum * prev ≤ Eprev) (hEhi : Eprev < 2^cum * prev + Wnum * 2^p) : 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) ≤ c * 2^(cum+sh) + Eprev * v ∧ c * 2^(cum+sh) + Eprev * v < 2^(cum+sh) * (evmAdd c (evmShr sh (evmMul prev v))) + - (Wnum + 2^(cum+sh-(p+126))) * 2^(p+126) := by - have hprev256 : prev < 2^256 := by have : P ≤ 2^256 := by omega - omega - have hv256 : v < 2^256 := by have : (2:Nat)^126 < 2^256 := by norm_num + (Wnum + 2^(cum+sh-(p+120))) * 2^(p+120) := by + have hv256 : v < 2^256 := by have : (2:Nat)^120 < 2^256 := by norm_num + omega + have hc256 : c < 2^256 := by have : (2:Nat)^160 < 2^256 := by norm_num omega - have hpv : prev * v < 2^256 := lt_of_lt_of_le (Nat.mul_lt_mul'' hprevlt hv) (by omega) - have hsum' : c + prev * v / 2^sh < 2^256 := by - have : prev * v / 2^sh ≤ P * 2^126 / 2^sh := by - apply Nat.div_le_div_right; exact Nat.le_of_lt (Nat.mul_lt_mul'' hprevlt hv) + -- the truncated stage term is below `2^136`: the product is a word and the shift is ≥ 120 + have hterm : prev * v / 2 ^ sh < 2 ^ 136 := by + have h1 : prev * v / 2 ^ sh ≤ prev * v / 2 ^ 120 := + Nat.div_le_div_left (Nat.pow_le_pow_right (by norm_num) hs) (Nat.two_pow_pos _) + have h2 : prev * v / 2 ^ 120 < 2 ^ 136 := by + rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] + calc prev * v < 2 ^ 256 := hpv + _ = 2 ^ 136 * 2 ^ 120 := by rw [← Nat.pow_add] omega - have hst := stage_exact hprev256 hv256 hpv hsh256 hclt hsum' + have hsum' : c + prev * v / 2 ^ sh < 2 ^ 256 := by + have : (2:Nat)^160 + 2^136 < 2^256 := by norm_num + omega + have hst := stage_exact hprev256 hv256 hpv hsh256 hc256 hsum' set ev1 := evmAdd c (evmShr sh (evmMul prev v)) with hev1 have hge : c ≤ ev1 := by - rw [hev1, evmAdd_eq_nat hclt (by exact evmShr_lt _ _) (by + rw [hev1, evmAdd_eq_nat hc256 (by exact evmShr_lt _ _) (by have hmul : evmMul prev v = prev * v := evmMul_eq_nat hprev256 hv256 hpv have : evmShr sh (evmMul prev v) = prev*v/2^sh := by rw [hmul]; exact evmShr_eq_div (by omega) hpv rw [this]; omega)] omega exact tele_step_frac prev ev1 v c cum sh p Wnum Eprev hv hs hge hpcum hElo hEhi hst.1 hst.2 +/-! ## The even accumulator + +The monic leading stage `ev0 = A4 + v` is an exact add (width `1·2^0`); the four `mul/shr` stages +(shifts `0x95, 0x7b, 0x81, 0x7f`, cumulative `149, 272, 401, 528`) telescope the width to +`283678831804417·2^480 ≈ 1.0079·2^528`. -/ -theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : - 2^553 * evTree x ≤ evNumV (vTree x) ∧ evNumV (vTree x) < 2^553 * evTree x + 1065041 * 2^533 := by +/-- Exact integer even-Horner accumulator (degree-5 monic in `v`, cleared scale `2^528`). -/ +def evNumV (v : Nat) : Nat := + let e0 := 0xb9aacfacf3c10b378435f8e22adf48500e + v + let e1 := 0x9a036222841f47c6ed6fc3f7602053 * 2^149 + e0 * v + let e2 := 0x9064d9657e9a21fc16bb69331c5c3057 * 2^272 + e1 * v + let e3 := 0x93f11e650dd6c64b96ce79065cdf809e * 2^401 + e2 * v + 0x4e14a45e5650b506e97f4c5da23861e2 * 2^528 + e3 * v + +theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : + 2^528 * evTree x ≤ evNumV (vTree x) ∧ + evNumV (vTree x) < 2^528 * evTree x + 283678831804417 * 2^480 := by have hev : evTree x = - evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d (vTree x))) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl + evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e (vTree x)) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl set v := vTree x with hvdef - -- stage 0: width 1·2^29 (p=29, Wnum=1) - have h0 := ev0_exact hv - set e0 := evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) with he0 - have he0lt : e0 < 2 ^ 113 := ev0_lt hv - have he0ge : 0xb9aacfad41060587203a79af0ebc ≤ e0 := ev0_ge hv - have h29 : (0x1d : Nat) = 29 := by norm_num - rw [h29] at h0 - have hE0lo : 2^29 * e0 ≤ 0xb9aacfad41060587203a79af0ebc * 2^29 + v := by have := h0.1; omega - have hE0hi : 0xb9aacfad41060587203a79af0ebc * 2^29 + v < 2^29 * e0 + 1 * 2^29 := by have := h0.2; omega - -- stage 1: cum 29 -> 159, sh=130; p 29 -> 155; Wnum 1 -> 17 - have s1 := horner_stage_frac 0x9a036222e11aee18465042f8ea64c8 (2^113) e0 v 29 0x82 29 1 - (0xb9aacfad41060587203a79af0ebc * 2^29 + v) hv (by norm_num) (by norm_num) he0lt (by norm_num) - (by norm_num) (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num) (by norm_num) hE0lo hE0hi - -- normalise the stage-1 width `(1 + 2^(159-155))·2^155` to `17·2^155` - rw [show (29:Nat)+0x82-(29+126) = 4 from by norm_num, show (1:Nat)+2^4 = 17 from by norm_num, - show (29:Nat)+126 = 155 from by norm_num, show (29:Nat)+0x82 = 159 from by norm_num] at s1 - set e1 := evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul e0 v)) with he1 + -- stage 0: the monic add is exact; width 1·2^0 + have he0eq : evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v = + 0xb9aacfacf3c10b378435f8e22adf48500e + v := + evmAdd_eq_nat (by norm_num) (by have : (2:Nat)^120 < 2^256 := by norm_num + omega) + (by have : (0xb9aacfacf3c10b378435f8e22adf48500e : Nat) + 2^120 < 2^256 := by norm_num + omega) + set e0 := evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v with he0 + have he0lt : e0 < 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120 := ev0_lt hv + have hE0lo : 2^0 * e0 ≤ 0xb9aacfacf3c10b378435f8e22adf48500e + v := by + rw [he0eq, pow_zero, one_mul] + have hE0hi : 0xb9aacfacf3c10b378435f8e22adf48500e + v < 2^0 * e0 + 1 * 2^0 := by + rw [he0eq, pow_zero, one_mul, mul_one] + omega + -- stage 1: cum 0 -> 149, sh=149; p 0 -> 120; Wnum 1 -> 536870913 + have s1 := horner_stage_frac 0x9a036222841f47c6ed6fc3f7602053 e0 v 0 0x95 0 1 + (0xb9aacfacf3c10b378435f8e22adf48500e + v) hv (by norm_num) (by norm_num) + (by have : (0xb9aacfacf3c10b378435f8e22adf48500e : Nat) + 2^120 < 2^256 := by norm_num + omega) + (by calc e0 * v < (0xb9aacfacf3c10b378435f8e22adf48500e + 2^120) * 2^120 := + Nat.mul_lt_mul'' he0lt hv + _ < 2^256 := by norm_num) + (by norm_num) (by norm_num) hE0lo hE0hi + rw [show (0:Nat)+0x95-(0+120) = 29 from by norm_num, show (1:Nat)+2^29 = 536870913 from by norm_num, + show (0:Nat)+120 = 120 from by norm_num, show (0:Nat)+0x95 = 149 from by norm_num] at s1 + set e1 := evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul e0 v)) with he1 have he1lt : e1 < 2^121 := by - have := (stage_bounds (c := 0x9a036222e11aee18465042f8ea64c8) (prev := e0) (v := v) - (P := 2^113) (V := 2^126) (sh := 0x82) he0lt hv (by norm_num) (by norm_num) - (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num)).2 - rw [pvd 113 126 130 109 (by norm_num)] at this; omega - -- stage 2: cum 159 -> 287, sh=128; p 155 -> 281; Wnum 17 -> 81 - have s2 := horner_stage_frac 0x9064d965e1c4863b73604e0ddbec53f9 (2^121) e1 v 159 0x80 155 17 - (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) - hv (by norm_num) (by norm_num) he1lt (by norm_num) - (by norm_num) (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 - rw [show (159:Nat)+0x80-(155+126) = 6 from by norm_num, show (17:Nat)+2^6 = 81 from by norm_num, - show (155:Nat)+126 = 281 from by norm_num, show (159:Nat)+0x80 = 287 from by norm_num] at s2 - set e2 := evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul e1 v)) with he2 + have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7602053) (prev := e0) (v := v) + (P := 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) (V := 2 ^ 120) (sh := 0x95) he0lt hv + (by norm_num) (by norm_num) (by norm_num)).2 + have hcap : (0x9a036222841f47c6ed6fc3f7602053 : Nat) + + (0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) * 2 ^ 120 / 2 ^ 0x95 < 2 ^ 121 := by + norm_num + omega + -- stage 2: cum 149 -> 272, sh=123; p 120 -> 240; Wnum 536870913 -> 4831838209 + have s2 := horner_stage_frac 0x9064d9657e9a21fc16bb69331c5c3057 e1 v 149 0x7b 120 536870913 + (0x9a036222841f47c6ed6fc3f7602053 * 2^149 + (0xb9aacfacf3c10b378435f8e22adf48500e + v) * v) + hv (by norm_num) (by norm_num) + (by have : (2:Nat)^121 < 2^256 := by norm_num + omega) + (by calc e1 * v < 2^121 * 2^120 := Nat.mul_lt_mul'' he1lt hv + _ < 2^256 := by norm_num) + (by norm_num) (by norm_num) s1.1 s1.2 + rw [show (149:Nat)+0x7b-(120+120) = 32 from by norm_num, + show (536870913:Nat)+2^32 = 4831838209 from by norm_num, + show (120:Nat)+120 = 240 from by norm_num, show (149:Nat)+0x7b = 272 from by norm_num] at s2 + set e2 := evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul e1 v)) with he2 have he2lt : e2 < 2^129 := by - have := (stage_bounds (c := 0x9064d965e1c4863b73604e0ddbec53f9) (prev := e1) (v := v) - (P := 2^121) (V := 2^126) (sh := 0x80) he1lt hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 128 119 (by norm_num)] at this; omega - -- stage 3: cum 287 -> 421, sh=134; p 281 -> 407; Wnum 81 -> 16465 - have s3 := horner_stage_frac 0x93f11e65781741b92fa7fc4f4fffcca2 (2^129) e2 v 287 0x86 281 81 - (0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + - (0x9a036222e11aee18465042f8ea64c8 * 2^159 + (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) * v) - hv (by norm_num) (by norm_num) he2lt (by norm_num) - (by norm_num) (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num) (by norm_num) s2.1 s2.2 - rw [show (287:Nat)+0x86-(281+126) = 14 from by norm_num, show (81:Nat)+2^14 = 16465 from by norm_num, - show (281:Nat)+126 = 407 from by norm_num, show (287:Nat)+0x86 = 421 from by norm_num] at s3 - set e3 := evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul e2 v)) with he3 + have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331c5c3057) (prev := e1) (v := v) + (P := 2^121) (V := 2^120) (sh := 0x7b) he1lt hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 123 118 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 123 118 (by norm_num)] at this; omega + -- stage 3: cum 272 -> 401, sh=129; p 240 -> 360; Wnum 4831838209 -> 2203855093761 + have s3 := horner_stage_frac 0x93f11e650dd6c64b96ce79065cdf809e e2 v 272 0x81 240 4831838209 + (0x9064d9657e9a21fc16bb69331c5c3057 * 2^272 + + (0x9a036222841f47c6ed6fc3f7602053 * 2^149 + (0xb9aacfacf3c10b378435f8e22adf48500e + v) * v) * v) + hv (by norm_num) (by norm_num) + (by have : (2:Nat)^129 < 2^256 := by norm_num + omega) + (by calc e2 * v < 2^129 * 2^120 := Nat.mul_lt_mul'' he2lt hv + _ < 2^256 := by norm_num) + (by norm_num) (by norm_num) s2.1 s2.2 + rw [show (272:Nat)+0x81-(240+120) = 41 from by norm_num, + show (4831838209:Nat)+2^41 = 2203855093761 from by norm_num, + show (240:Nat)+120 = 360 from by norm_num, show (272:Nat)+0x81 = 401 from by norm_num] at s3 + set e3 := evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul e2 v)) with he3 have he3lt : e3 < 2^129 := by - have := (stage_bounds (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (prev := e2) (v := v) - (P := 2^129) (V := 2^126) (sh := 0x86) he2lt hv (by norm_num) (by norm_num) - (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num)).2 - rw [pvd 129 126 134 121 (by norm_num)] at this; omega - -- stage 4: cum 421 -> 553, sh=132; p 407 -> 533; Wnum 16465 -> 1065041 - have s4 := horner_stage_frac 0x4e14a45e8ec305e233e11b4174e214ac (2^129) e3 v 421 0x84 407 16465 - (0x93f11e65781741b92fa7fc4f4fffcca2 * 2^421 + - (0x9064d965e1c4863b73604e0ddbec53f9 * 2^287 + - (0x9a036222e11aee18465042f8ea64c8 * 2^159 + - (0xb9aacfad41060587203a79af0ebc * 2^29 + v) * v) * v) * v) - hv (by norm_num) (by norm_num) he3lt (by norm_num) - (by norm_num) (by rw [pvd 129 126 132 123 (by norm_num)]; norm_num) (by norm_num) s3.1 s3.2 - rw [show (421:Nat)+0x84-(407+126) = 20 from by norm_num, - show (16465:Nat)+2^20 = 1065041 from by norm_num, - show (407:Nat)+126 = 533 from by norm_num, show (421:Nat)+0x84 = 553 from by norm_num] at s4 + have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf809e) (prev := e2) (v := v) + (P := 2^129) (V := 2^120) (sh := 0x81) he2lt hv (by norm_num) (by norm_num) + (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 + rw [pvd 129 120 129 120 (by norm_num)] at this; omega + -- stage 4: cum 401 -> 528, sh=127; p 360 -> 480; Wnum 2203855093761 -> 283678831804417 + have s4 := horner_stage_frac 0x4e14a45e5650b506e97f4c5da23861e2 e3 v 401 0x7f 360 2203855093761 + (0x93f11e650dd6c64b96ce79065cdf809e * 2^401 + + (0x9064d9657e9a21fc16bb69331c5c3057 * 2^272 + + (0x9a036222841f47c6ed6fc3f7602053 * 2^149 + + (0xb9aacfacf3c10b378435f8e22adf48500e + v) * v) * v) * v) + hv (by norm_num) (by norm_num) + (by have : (2:Nat)^129 < 2^256 := by norm_num + omega) + (by calc e3 * v < 2^129 * 2^120 := Nat.mul_lt_mul'' he3lt hv + _ < 2^256 := by norm_num) + (by norm_num) (by norm_num) s3.1 s3.2 + rw [show (401:Nat)+0x7f-(360+120) = 48 from by norm_num, + show (2203855093761:Nat)+2^48 = 283678831804417 from by norm_num, + show (360:Nat)+120 = 480 from by norm_num, show (401:Nat)+0x7f = 528 from by norm_num] at s4 -- assemble: evTree x = e4 (the stage-4 value), evNumV v = the cumulative E4. rw [hev] - show 2^553 * evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul e3 v)) ≤ evNumV v ∧ - evNumV v < 2^553 * evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul e3 v)) + 1065041 * 2^533 + show 2^528 * evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul e3 v)) ≤ evNumV v ∧ + evNumV v < 2^528 * evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul e3 v)) + + 283678831804417 * 2^480 unfold evNumV constructor · have := s4.1 @@ -339,82 +291,105 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : #guard_msgs in #print axioms evTree_bracket -/-! ## Gap-2: the odd Horner accumulator brackets the exact polynomial +/-! ## The odd accumulator -The odd accumulator starts at the leading constant `B4` (scale `0`) and runs four mul/shr stages -(shifts `0x83, 0x89, 0x7f, 0x87`, cumulative `131, 268, 395, 530`). Cleared to scale `2^530` the -runtime `odTree x` brackets the exact degree-4 polynomial `odNumV (vTree x)` within `2·2^530`. -/ +The odd accumulator starts at the exact leading constant `B4` (scale `0`) and runs four mul/shr +stages (shifts `0x7e, 0x84, 0x7a, 0x82`, cumulative `126, 258, 380, 510`), telescoping the width to +`1075052609·2^480 ≈ 1.0013·2^510`. -/ -/-- Exact integer odd-Horner numerator (degree-4 in `v`, scale `2^530`). -/ +/-- Exact integer odd-Horner accumulator (degree-4 in `v`, cleared scale `2^510`). -/ def odNumV (v : Nat) : Nat := - let o1 := 0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v - let o2 := 0xad4506b00b1246c7e5b4fd33e1201b * 2^268 + o1 * v - let o3 := 0xaf5662483c4ce783a9ef5fe025f42e9e * 2^395 + o2 * v - 0x270a522f476182f119f08da0ba710a56 * 2^530 + o3 * v - -/-- Runtime odd-Horner accumulator brackets the exact polynomial within `1.003·2^530` (the -fractional gap-2 envelope) at scale `2^530`. -/ -theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 126) : - 2^530 * odTree x ≤ odNumV (vTree x) ∧ odNumV (vTree x) < 2^530 * odTree x + 67305505 * 2^504 := by + let o1 := 0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v + let o2 := 0xad4506af99be27419341e1816ff351 * 2^258 + o1 * v + let o3 := 0xaf566247c05753b42892f77b67a6b7c6 * 2^380 + o2 * v + 0x270a522f2b285a8374bfa62ed11c30f1 * 2^510 + o3 * v + +theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : + 2^510 * odTree x ≤ odNumV (vTree x) ∧ + odNumV (vTree x) < 2^510 * odTree x + 1075052609 * 2^480 := by have hod : odTree x = - evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl + evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl set v := vTree x with hvdef - -- the leading constant is exact; track it as width 1·2^0 (B0 < B0 + 1) - have hB4lo : 2^0 * 0xdc07aff85e5bb5629d0fb64a84bb ≤ 0xdc07aff85e5bb5629d0fb64a84bb := by norm_num - have hB4hi : (0xdc07aff85e5bb5629d0fb64a84bb : Nat) < 2^0 * 0xdc07aff85e5bb5629d0fb64a84bb + 1 * 2^0 := by norm_num - -- stage 1: cum 0 -> 131, sh=131; p 0 -> 126; Wnum 1 -> 33 - have s1 := horner_stage_frac 0xc926ddbf3830ca5561cc01585402d0 (2^112) 0xdc07aff85e5bb5629d0fb64a84bb v 0 0x83 0 1 - 0xdc07aff85e5bb5629d0fb64a84bb hv (by norm_num) (by norm_num) (by norm_num) (by norm_num) - (by norm_num) (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num) (by norm_num) hB4lo hB4hi - rw [show (0:Nat)+0x83-(0+126) = 5 from by norm_num, show (1:Nat)+2^5 = 33 from by norm_num, - show (0:Nat)+126 = 126 from by norm_num, show (0:Nat)+0x83 = 131 from by norm_num] at s1 - set o1 := evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb v)) with ho1 + -- the leading constant is exact; track it as width 1·2^0 (B4 < B4 + 1) + have hB4lo : 2^0 * 0xdc07aff8276bde9a361278df6a10 ≤ 0xdc07aff8276bde9a361278df6a10 := by norm_num + have hB4hi : (0xdc07aff8276bde9a361278df6a10 : Nat) < + 2^0 * 0xdc07aff8276bde9a361278df6a10 + 1 * 2^0 := by norm_num + -- stage 1: cum 0 -> 126, sh=126; p 0 -> 120; Wnum 1 -> 65 + have s1 := horner_stage_frac 0xc926ddbecdeeb42e68cd16db7da8c1 + 0xdc07aff8276bde9a361278df6a10 v 0 0x7e 0 1 + 0xdc07aff8276bde9a361278df6a10 hv (by norm_num) (by norm_num) (by norm_num) + (by calc (0xdc07aff8276bde9a361278df6a10 : Nat) * v < 2^112 * 2^120 := + Nat.mul_lt_mul'' (by norm_num) hv + _ < 2^256 := by norm_num) + (by norm_num) (by norm_num) hB4lo hB4hi + rw [show (0:Nat)+0x7e-(0+120) = 6 from by norm_num, show (1:Nat)+2^6 = 65 from by norm_num, + show (0:Nat)+120 = 120 from by norm_num, show (0:Nat)+0x7e = 126 from by norm_num] at s1 + set o1 := evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 + (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v)) with ho1 have ho1lt : o1 < 2^121 := by - have := (stage_bounds (c := 0xc926ddbf3830ca5561cc01585402d0) (prev := 0xdc07aff85e5bb5629d0fb64a84bb) (v := v) - (P := 2^112) (V := 2^126) (sh := 0x83) (by norm_num) hv (by norm_num) (by norm_num) - (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num)).2 - rw [pvd 112 126 131 107 (by norm_num)] at this; omega - -- stage 2: cum 131 -> 268, sh=137; p 126 -> 252; Wnum 33 -> 65569 - have s2 := horner_stage_frac 0xad4506b00b1246c7e5b4fd33e1201b (2^121) o1 v 131 0x89 126 33 - (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) hv (by norm_num) (by norm_num) ho1lt (by norm_num) - (by norm_num) (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num) (by norm_num) s1.1 s1.2 - rw [show (131:Nat)+0x89-(126+126) = 16 from by norm_num, show (33:Nat)+2^16 = 65569 from by norm_num, - show (126:Nat)+126 = 252 from by norm_num, show (131:Nat)+0x89 = 268 from by norm_num] at s2 - set o2 := evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul o1 v)) with ho2 + have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7da8c1) + (prev := 0xdc07aff8276bde9a361278df6a10) (v := v) + (P := 2^112) (V := 2^120) (sh := 0x7e) (by norm_num) hv (by norm_num) (by norm_num) + (by rw [pvd 112 120 126 106 (by norm_num)]; norm_num)).2 + rw [pvd 112 120 126 106 (by norm_num)] at this; omega + -- stage 2: cum 126 -> 258, sh=132; p 120 -> 240; Wnum 65 -> 262209 + have s2 := horner_stage_frac 0xad4506af99be27419341e1816ff351 o1 v 126 0x84 120 65 + (0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) hv + (by norm_num) (by norm_num) + (by have : (2:Nat)^121 < 2^256 := by norm_num + omega) + (by calc o1 * v < 2^121 * 2^120 := Nat.mul_lt_mul'' ho1lt hv + _ < 2^256 := by norm_num) + (by norm_num) (by norm_num) s1.1 s1.2 + rw [show (126:Nat)+0x84-(120+120) = 18 from by norm_num, show (65:Nat)+2^18 = 262209 from by norm_num, + show (120:Nat)+120 = 240 from by norm_num, show (126:Nat)+0x84 = 258 from by norm_num] at s2 + set o2 := evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul o1 v)) with ho2 have ho2lt : o2 < 2^121 := by - have := (stage_bounds (c := 0xad4506b00b1246c7e5b4fd33e1201b) (prev := o1) (v := v) - (P := 2^121) (V := 2^126) (sh := 0x89) ho1lt hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 137 110 (by norm_num)] at this; omega - -- stage 3: cum 268 -> 395, sh=127; p 252 -> 378; Wnum 65569 -> 196641 - have s3 := horner_stage_frac 0xaf5662483c4ce783a9ef5fe025f42e9e (2^121) o2 v 268 0x7f 252 65569 - (0xad4506b00b1246c7e5b4fd33e1201b * 2^268 + - (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) * v) hv (by norm_num) (by norm_num) ho2lt (by norm_num) - (by norm_num) (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num) (by norm_num) s2.1 s2.2 - rw [show (268:Nat)+0x7f-(252+126) = 17 from by norm_num, show (65569:Nat)+2^17 = 196641 from by norm_num, - show (252:Nat)+126 = 378 from by norm_num, show (268:Nat)+0x7f = 395 from by norm_num] at s3 - set o3 := evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul o2 v)) with ho3 + have := (stage_bounds (c := 0xad4506af99be27419341e1816ff351) (prev := o1) (v := v) + (P := 2^121) (V := 2^120) (sh := 0x84) ho1lt hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 132 109 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 132 109 (by norm_num)] at this; omega + -- stage 3: cum 258 -> 380, sh=122; p 240 -> 360; Wnum 262209 -> 1310785 + have s3 := horner_stage_frac 0xaf566247c05753b42892f77b67a6b7c6 o2 v 258 0x7a 240 262209 + (0xad4506af99be27419341e1816ff351 * 2^258 + + (0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) * v) hv + (by norm_num) (by norm_num) + (by have : (2:Nat)^121 < 2^256 := by norm_num + omega) + (by calc o2 * v < 2^121 * 2^120 := Nat.mul_lt_mul'' ho2lt hv + _ < 2^256 := by norm_num) + (by norm_num) (by norm_num) s2.1 s2.2 + rw [show (258:Nat)+0x7a-(240+120) = 20 from by norm_num, + show (262209:Nat)+2^20 = 1310785 from by norm_num, + show (240:Nat)+120 = 360 from by norm_num, show (258:Nat)+0x7a = 380 from by norm_num] at s3 + set o3 := evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul o2 v)) with ho3 have ho3lt : o3 < 2^129 := by - have := (stage_bounds (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (prev := o2) (v := v) - (P := 2^121) (V := 2^126) (sh := 0x7f) ho2lt hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 127 120 (by norm_num)] at this; omega - -- stage 4: cum 395 -> 530, sh=135; p 378 -> 504; Wnum 196641 -> 67305505 - have s4 := horner_stage_frac 0x270a522f476182f119f08da0ba710a56 (2^129) o3 v 395 0x87 378 196641 - (0xaf5662483c4ce783a9ef5fe025f42e9e * 2^395 + - (0xad4506b00b1246c7e5b4fd33e1201b * 2^268 + - (0xc926ddbf3830ca5561cc01585402d0 * 2^131 + 0xdc07aff85e5bb5629d0fb64a84bb * v) * v) * v) hv (by norm_num) (by norm_num) ho3lt (by norm_num) - (by norm_num) (by rw [pvd 129 126 135 120 (by norm_num)]; norm_num) (by norm_num) s3.1 s3.2 - rw [show (395:Nat)+0x87-(378+126) = 26 from by norm_num, - show (196641:Nat)+2^26 = 67305505 from by norm_num, - show (378:Nat)+126 = 504 from by norm_num, show (395:Nat)+0x87 = 530 from by norm_num] at s4 + have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c6) (prev := o2) (v := v) + (P := 2^121) (V := 2^120) (sh := 0x7a) ho2lt hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 122 119 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 122 119 (by norm_num)] at this; omega + -- stage 4: cum 380 -> 510, sh=130; p 360 -> 480; Wnum 1310785 -> 1075052609 + have s4 := horner_stage_frac 0x270a522f2b285a8374bfa62ed11c30f1 o3 v 380 0x82 360 1310785 + (0xaf566247c05753b42892f77b67a6b7c6 * 2^380 + + (0xad4506af99be27419341e1816ff351 * 2^258 + + (0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) * v) * v) hv + (by norm_num) (by norm_num) + (by have : (2:Nat)^129 < 2^256 := by norm_num + omega) + (by calc o3 * v < 2^129 * 2^120 := Nat.mul_lt_mul'' ho3lt hv + _ < 2^256 := by norm_num) + (by norm_num) (by norm_num) s3.1 s3.2 + rw [show (380:Nat)+0x82-(360+120) = 30 from by norm_num, + show (1310785:Nat)+2^30 = 1075052609 from by norm_num, + show (360:Nat)+120 = 480 from by norm_num, show (380:Nat)+0x82 = 510 from by norm_num] at s4 rw [hod] - show 2^530 * evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul o3 v)) ≤ odNumV v ∧ - odNumV v < 2^530 * evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul o3 v)) + 67305505 * 2^504 + show 2^510 * evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul o3 v)) ≤ odNumV v ∧ + odNumV v < 2^510 * evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul o3 v)) + + 1075052609 * 2^480 unfold odNumV constructor · have := s4.1; convert this using 2 <;> ring diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index 6102521bd..e2a8b4359 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -11,8 +11,8 @@ below-clamp bound (`belowC_target_lt_one`) establish the never-over and deficit- about the real pre-floor accumulator unconditionally and axiom-clean, via the octave fold `E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the closing shift; `k ≤ 63` so `s ≥ 63`). -* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` and `WAD·7201434073703092789/10000000000000000000 ≤ MARGIN`; -* `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 13/2` and `(13/2)·WAD + MARGIN < 2⁶³ ≤ 2^s`. +* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 10155087723197130681/10000000000000000000` and `WAD·10155087723197130681/10000000000000000000 ≤ MARGIN`; +* `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 67/10` and `(67/10)·WAD + MARGIN < 2⁶³ ≤ 2^s`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. -/ @@ -38,12 +38,12 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt -- WAD·r0 − MARGIN ≤ WAD·2^126·Ert = E·2^s - have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 ≤ + have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 7201434073703092789 / 10000000000000000000 := hover + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 10155087723197130681 / 10000000000000000000 := hover have hscaled : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) ≤ - (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 7201434073703092789 / 10000000000000000000) := + (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 10155087723197130681 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad]; nlinarith [hscaled] @@ -61,24 +61,24 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 set Ert := Real.exp (reducedArg x) with hErt -- E·2^s = WAD·2^126·Ert < WAD·r0 − MARGIN + 2^s have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real) := by + ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069) + (2 ^ s : Real) := by rw [hfold] - have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 13 / 2 := hunder + have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 67 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num have hs63 : (63 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] have hs63n : 63 ≤ s := by exact_mod_cast hs63 have hpow : (2 ^ 63 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs63n rw [hwad] have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 13 / 2) := + (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 67 / 10) := mul_le_mul_of_nonneg_left (by linarith [hr0R]) (by norm_num) - have hbudget : (10 ^ 18 : Real) * (13 / 2) + 720143407370309279 < (2 ^ 63 : Real) := by norm_num + have hbudget : (10 ^ 18 : Real) * (67 / 10) + 1015508772319713069 < (2 ^ 63 : Real) := by norm_num nlinarith [h8wad, hbudget, hpow] -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s rw [hAeq] - have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) / + have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069) / (2 ^ s : Real) + 1 = - (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279) + (2 ^ s : Real)) / + (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp rw [hdiv, lt_div_iff₀ hps]; linarith [hbound] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 14cfb2fd0..b3bafe710 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -1,5 +1,4 @@ -import ExpProof.Floor.R0Bound -import ExpProof.Floor.CapsV +import ExpProof.Floor.GranPair import ExpProof.Floor.Reduce import ExpProof.Mono.Quot import ExpProof.Mono.Cross @@ -7,22 +6,26 @@ import Common.Seam.RealExpBridge import Mathlib.Analysis.SpecialFunctions.Pow.Real /-! -# The per-point `r0`-vs-`exp` bridge - -This module brackets the Q126 quotient `r0Tree x` against `2¹²⁶·exp(rt)` (`rt = X/RAY − k·ln2` the -reduced argument), the analytic content the floor brackets (`Floor.R0BoundHolds`) and the seam bound -(`SeamR0Bound`) consume. It chains: - -* the **v-truncation** `evNumV(vTree x)·2⁶⁴⁰ ≤ evalPoly evNumVPoly t < evNumV(vTree x)·2⁶⁴⁰ + 2¹¹⁹³` - (the cert polynomial in `t` uses the exact `v = t²/2¹²⁸`; the Horner-truncation bridge uses the - truncated `vTree x = ⌊t²/2¹²⁸⌋`; one `v`-step of the monotone Horner polynomial is below `2⁵⁵³`); -* the **Horner-truncation bridge** (`evTree_bracket`/`odTree_bracket`); -* the **`sdiv` floor** `r0·den ≤ 2¹²⁶·num < (r0+1)·den`; -* the **v-form cert** (`CapsV`) `exp(t/2¹²⁸) ≈ ê_v` within a dyadic margin; -* the **reduced-argument bound** (`Reduce`) `|rt − t/2¹²⁸| < 2/2¹²⁸`. - -The net envelope `r0Tree x ∈ (2¹²⁶·exp(rt) − C₋, 2¹²⁶·exp(rt) + C₊)` is what the `MARGIN`-absorbing -`over`/`under`/seam inequalities consume. +# The per-point `r0`-vs-`exp` bridge (never-over side) + +This module bounds the Q126 quotient `r0Tree x` above by `2¹²⁶·exp(rt)` plus the never-over budget +(`rt = X/RAY − k·ln2` the reduced argument), the analytic content the floor brackets +(`Floor.R0BoundHolds`) consume. The chain has four links: + +1. **`r0` vs `ê(v)`** — Horner stage truncation and the closing `sdiv` floor only: the runtime + accumulators bracket the exact integer polynomials (`evTree_bracket`/`odTree_bracket`), and the + shared even truncation cancels through the floor, leaving the jitter + `≤ 6207065162659510332/10¹⁹`; +2. **`ê(v)` vs `ê(t²)`** — the argument-granularity link (`Floor.GranV`): one `v`-grid grain, + `≤ 3395595387735630095/10¹⁹` on this half; +3. **`ê(t²)` vs `exp(t/2¹²⁸)`** — the `2⁻¹³¹`-nudged Taylor cut (`Floor.CapsV`), the `Mp` factor + `≤ 441941738241592203/10¹⁹`; +4. **`exp(t/2¹²⁸)` vs `exp(rt)`** — the reduced-argument gap (`Floor.Reduce`), + `≤ 110485434560398051/10¹⁹`. + +The total is the budget `B = 10155087723197130681/10¹⁹`; `MARGIN = ⌊10¹⁸·B⌋ + 1`. On the `t ≤ 0` +half link 2 is free (the grain moves `ê` the other way) and links 3–4 shrink (`ê ≤ 1`), so the same +`B` covers both halves. -/ namespace ExpYul @@ -33,363 +36,7 @@ open Common.Poly set_option maxRecDepth 100000 set_option maxHeartbeats 1600000 - -/-! ## The even/odd Horner polynomials in `w = t²` and the cert-polynomial bridge -/ - -/-- The even Horner polynomial in `w` (degree 5, monic), at the cleared scale `2¹¹⁹³`. -/ -def Pev : List Int := - [0x4e14a45e8ec305e233e11b4174e214ac * 2 ^ 1193, - 0x93f11e65781741b92fa7fc4f4fffcca2 * 2 ^ 933, - 0x9064d965e1c4863b73604e0ddbec53f9 * 2 ^ 671, - 0x9a036222e11aee18465042f8ea64c8 * 2 ^ 415, - 0xb9aacfad41060587203a79af0ebc * 2 ^ 157, - 1] - -/-- The odd Horner polynomial in `w` (degree 4), at the cleared scale `2¹⁰⁴²`. -/ -def Pod : List Int := - [0x270a522f476182f119f08da0ba710a56 * 2 ^ 1042, - 0xaf5662483c4ce783a9ef5fe025f42e9e * 2 ^ 779, - 0xad4506b00b1246c7e5b4fd33e1201b * 2 ^ 524, - 0xc926ddbf3830ca5561cc01585402d0 * 2 ^ 259, - 0xdc07aff85e5bb5629d0fb64a84bb] - -/-- `evNumVPoly(t) = Pev(t²)`: the cert even polynomial is `Pev` composed with squaring. -/ -theorem evNumVPoly_eq_Pev_sq (t : Int) : - evalPoly ExpCertV.evNumVPoly t = evalPoly Pev (t ^ 2) := by - unfold ExpCertV.evNumVPoly ExpCertV.mulT2 Pev - simp only [evalPoly_polyAdd, evalPoly_polyScale, evalPoly] - ring - -/-- `odNumVPoly(t) = Pod(t²)`. -/ -theorem odNumVPoly_eq_Pod_sq (t : Int) : - evalPoly ExpCertV.odNumVPoly t = evalPoly Pod (t ^ 2) := by - unfold ExpCertV.odNumVPoly ExpCertV.mulT2 Pod - simp only [evalPoly_polyAdd, evalPoly_polyScale, evalPoly] - ring - -/-- `Pev(2¹²⁸·v) = evNumV(v)·2⁶⁴⁰` — the `w`-polynomial at the grid point `w = 2¹²⁸·v` recovers the -integer even-Horner accumulator (scaled). -/ -theorem Pev_grid (v : Nat) : evalPoly Pev (2 ^ 128 * (v : Int)) = (evNumV v : Int) * 2 ^ 640 := by - unfold Pev evNumV - simp only [evalPoly] - push_cast - ring - -/-- `Pod(2¹²⁸·v) = odNumV(v)·2⁵¹²`. -/ -theorem Pod_grid (v : Nat) : evalPoly Pod (2 ^ 128 * (v : Int)) = (odNumV v : Int) * 2 ^ 512 := by - unfold Pod odNumV - simp only [evalPoly] - push_cast - ring - -/-! ## Monotonicity of the `w`-polynomials and the single-`v`-step bound -/ - -/-- A polynomial with nonnegative coefficients evaluates nonnegatively on the nonnegative domain. -/ -theorem evalPoly_nonneg_of_nonneg {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) {a : Int} (ha : 0 ≤ a) : - 0 ≤ evalPoly p a := by - induction p with - | nil => simp [evalPoly] - | cons c cs ih => - have hc : 0 ≤ c := hp c List.mem_cons_self - have hcs : ∀ d ∈ cs, 0 ≤ d := fun d hd => hp d (List.mem_cons_of_mem c hd) - simp only [evalPoly] - exact Int.add_nonneg hc (Int.mul_nonneg ha (ih hcs)) - -/-- A polynomial with nonnegative coefficients is monotone on the nonnegative domain. -/ -theorem evalPoly_mono_of_nonneg {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) {a b : Int} - (ha : 0 ≤ a) (hab : a ≤ b) : evalPoly p a ≤ evalPoly p b := by - induction p with - | nil => simp [evalPoly] - | cons c cs ih => - have hcs : ∀ d ∈ cs, 0 ≤ d := fun d hd => hp d (List.mem_cons_of_mem c hd) - have hih := ih hcs - have hb : 0 ≤ b := le_trans ha hab - have hcsnn : 0 ≤ evalPoly cs a := evalPoly_nonneg_of_nonneg hcs ha - simp only [evalPoly] - have h1 : a * evalPoly cs a ≤ b * evalPoly cs b := by - calc a * evalPoly cs a ≤ b * evalPoly cs a := - mul_le_mul_of_nonneg_right hab hcsnn - _ ≤ b * evalPoly cs b := mul_le_mul_of_nonneg_left hih hb - linarith [h1] - -theorem Pev_coeffs_nonneg : ∀ c ∈ Pev, (0 : Int) ≤ c := by - unfold Pev; intro c hc; fin_cases hc <;> positivity - -theorem Pod_coeffs_nonneg : ∀ c ∈ Pod, (0 : Int) ≤ c := by - unfold Pod; intro c hc; fin_cases hc <;> positivity - -/-- `Pev` is monotone on the nonnegative domain. -/ -theorem Pev_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : - evalPoly Pev a ≤ evalPoly Pev b := evalPoly_mono_of_nonneg Pev_coeffs_nonneg ha hab - -/-- `Pod` is monotone on the nonnegative domain. -/ -theorem Pod_mono {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : - evalPoly Pod a ≤ evalPoly Pod b := evalPoly_mono_of_nonneg Pod_coeffs_nonneg ha hab - -/-- The odd cert polynomial `odNumVPoly` is nonnegative everywhere (`= Pod(t²)`, nonneg coeffs). -/ -theorem odNumVPoly_nonneg (t : Int) : 0 ≤ evalPoly ExpCertV.odNumVPoly t := by - rw [odNumVPoly_eq_Pod_sq] - exact evalPoly_nonneg_of_nonneg Pod_coeffs_nonneg (by positivity) - -/-- One `v`-step of the even Horner polynomial is below `2⁵⁴⁹ = 2⁵⁵³/16` for `v < 2¹²⁶` (the step is -`≈ 0.036·2⁵⁵³` at the band top; the dyadic `2⁵⁴⁹` leaves comfortable headroom). The tightness here -feeds the joint `over` budget. -/ -theorem evNumV_step {v : Nat} (hv : v < 2 ^ 126) : - (evNumV (v + 1) : Int) - (evNumV v : Int) < 2 ^ 549 := by - unfold evNumV - push_cast - have hvle : (v : Int) < 2 ^ 126 := by exact_mod_cast hv - have hvnn : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ - nlinarith [hvle, hvnn, mul_nonneg hvnn hvnn, Int.mul_nonneg hvnn (Int.mul_nonneg hvnn hvnn), - Int.mul_nonneg (Int.mul_nonneg hvnn hvnn) (Int.mul_nonneg hvnn hvnn)] - -/-- One `v`-step of the odd Horner polynomial is below `2⁵²⁵ = 2⁵³⁰/32` for `v < 2¹²⁶`. -/ -theorem odNumV_step {v : Nat} (hv : v < 2 ^ 126) : - (odNumV (v + 1) : Int) - (odNumV v : Int) < 2 ^ 525 := by - unfold odNumV - push_cast - have hvle : (v : Int) < 2 ^ 126 := by exact_mod_cast hv - have hvnn : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ - nlinarith [hvle, hvnn, mul_nonneg hvnn hvnn, Int.mul_nonneg hvnn (Int.mul_nonneg hvnn hvnn)] - -/-! ## The cert polynomial brackets the runtime accumulator (gap-2 ∘ v-truncation) -/ - -/-- The squared reduced argument splits as `t² = 2¹²⁸·vTree x + r` with `0 ≤ r < 2¹²⁸`. -/ -theorem tsq_split {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 2 ^ 128 * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ - (int256 (tTree x)) ^ 2 < 2 ^ 128 * (vTree x : Int) + 2 ^ 128 := by - obtain ⟨hveq, _⟩ := vTree_eq hx hC hC0 - have hsqnn : (0 : Int) ≤ (int256 (tTree x)) ^ 2 := sq_nonneg _ - have hdm := Int.ediv_add_emod ((int256 (tTree x)) ^ 2) (2 ^ 128) - have hmod_lt := Int.emod_lt_of_pos ((int256 (tTree x)) ^ 2) (by norm_num : (0:Int) < 2 ^ 128) - have hmod_nn := Int.emod_nonneg ((int256 (tTree x)) ^ 2) (by norm_num : (2:Int) ^ 128 ≠ 0) - rw [hveq] - constructor - · nlinarith [hdm, hmod_nn] - · nlinarith [hdm, hmod_lt] - -/-- **The even cert polynomial brackets the runtime even accumulator** (gap-2 ∘ v-truncation): -`2¹¹⁹³·evTree x ≤ evalPoly evNumVPoly t < 2¹¹⁹³·evTree x + 1130577·2¹¹⁷³` (the fractional gap-2 width -`1065041·2¹¹⁷³` plus one tight v-step `2¹¹⁸⁹ = 2¹⁶·2¹¹⁷³`, summing to `1130577·2¹¹⁷³ ≈ 1.078·2¹¹⁹³`). -/ -theorem evNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 2 ^ 1193 * (evTree x : Int) ≤ evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) ∧ - evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) < - 2 ^ 1193 * (evTree x : Int) + 1130577 * 2 ^ 1173 := by - obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 - obtain ⟨hg2lo, hg2hi⟩ := evTree_bracket hvlt - obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 - set t := int256 (tTree x) with htdef - have hsqnn : (0 : Int) ≤ t ^ 2 := sq_nonneg _ - have hgridnn : (0 : Int) ≤ 2 ^ 128 * (vTree x : Int) := mul_nonneg (by norm_num) (Int.natCast_nonneg _) - -- v-truncation: Pev(2^128·vTree) ≤ Pev(t²) ≤ Pev(2^128·vTree + 2^128) (monotone) - have hmono_lo : evalPoly Pev (2 ^ 128 * (vTree x : Int)) ≤ evalPoly Pev (t ^ 2) := - Pev_mono hgridnn hsqlo - have hmono_hi : evalPoly Pev (t ^ 2) ≤ evalPoly Pev (2 ^ 128 * ((vTree x + 1 : Nat) : Int)) := by - apply Pev_mono hsqnn - push_cast; linarith [hsqhi] - rw [evNumVPoly_eq_Pev_sq] - rw [Pev_grid] at hmono_lo - rw [Pev_grid (vTree x + 1)] at hmono_hi - -- gap-2: evNumV(vTree)·2^640 ≥ 2^553·evTree·2^640 = 2^1193·evTree - have hg2lo' : 2 ^ 1193 * (evTree x : Int) ≤ (evNumV (vTree x) : Int) * 2 ^ 640 := by - have h : (2 ^ 553 * evTree x : Nat) ≤ evNumV (vTree x) := hg2lo - have : (2 ^ 553 * evTree x : Int) ≤ (evNumV (vTree x) : Int) := by exact_mod_cast h - nlinarith [this] - -- gap-2 hi (fractional): evNumV(vTree)·2^640 < 2^1193·evTree + 1065041·2^1173 - have hg2hi' : (evNumV (vTree x) : Int) * 2 ^ 640 < 2 ^ 1193 * (evTree x : Int) + 1065041 * 2 ^ 1173 := by - have h : evNumV (vTree x) < 2 ^ 553 * evTree x + 1065041 * 2 ^ 533 := hg2hi - have : (evNumV (vTree x) : Int) < (2 ^ 553 * evTree x + 1065041 * 2 ^ 533 : Nat) := by exact_mod_cast h - push_cast at this; nlinarith [this] - -- tight v-step: evNumV(vTree+1)·2^640 < evNumV(vTree)·2^640 + 2^549·2^640 = … + 2^1189 - have hstep := evNumV_step hvlt - have hstep' : (evNumV (vTree x + 1) : Int) * 2 ^ 640 < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1189 := by - have he : (2:Int) ^ 1189 = 2 ^ 549 * 2 ^ 640 := by rw [← pow_add] - rw [he]; nlinarith [hstep, pow_pos (by norm_num : (0:Int) < 2) 640] - refine ⟨le_trans hg2lo' hmono_lo, ?_⟩ - calc evalPoly Pev (t ^ 2) ≤ (evNumV (vTree x + 1) : Int) * 2 ^ 640 := hmono_hi - _ < (evNumV (vTree x) : Int) * 2 ^ 640 + 2 ^ 1189 := hstep' - _ < 2 ^ 1193 * (evTree x : Int) + 1065041 * 2 ^ 1173 + 2 ^ 1189 := by linarith [hg2hi'] - _ = 2 ^ 1193 * (evTree x : Int) + 1130577 * 2 ^ 1173 := by - rw [show (2:Int) ^ 1189 = 2 ^ 16 * 2 ^ 1173 from by rw [← pow_add]]; ring - -/-- **The odd cert polynomial brackets the runtime odd accumulator** (gap-2 ∘ v-truncation): -`2¹⁰⁴²·odTree x ≤ evalPoly odNumVPoly t < 2¹⁰⁴²·odTree x + 69402657·2¹⁰¹⁶` (the fractional gap-2 -width `67305505·2¹⁰¹⁶` plus one tight v-step `2¹⁰³⁷ = 2²¹·2¹⁰¹⁶`, summing to `≈ 1.003·2¹⁰⁴²`). -/ -theorem odNumVPoly_bracket {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 2 ^ 1042 * (odTree x : Int) ≤ evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) ∧ - evalPoly ExpCertV.odNumVPoly (int256 (tTree x)) < - 2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016 := by - obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 - obtain ⟨hg2lo, hg2hi⟩ := odTree_bracket hvlt - obtain ⟨hsqlo, hsqhi⟩ := tsq_split hx hC hC0 - set t := int256 (tTree x) with htdef - have hsqnn : (0 : Int) ≤ t ^ 2 := sq_nonneg _ - have hgridnn : (0 : Int) ≤ 2 ^ 128 * (vTree x : Int) := mul_nonneg (by norm_num) (Int.natCast_nonneg _) - have hmono_lo : evalPoly Pod (2 ^ 128 * (vTree x : Int)) ≤ evalPoly Pod (t ^ 2) := - Pod_mono hgridnn hsqlo - have hmono_hi : evalPoly Pod (t ^ 2) ≤ evalPoly Pod (2 ^ 128 * ((vTree x + 1 : Nat) : Int)) := by - apply Pod_mono hsqnn - push_cast; linarith [hsqhi] - rw [odNumVPoly_eq_Pod_sq] - rw [Pod_grid] at hmono_lo - rw [Pod_grid (vTree x + 1)] at hmono_hi - have hg2lo' : 2 ^ 1042 * (odTree x : Int) ≤ (odNumV (vTree x) : Int) * 2 ^ 512 := by - have h : (2 ^ 530 * odTree x : Nat) ≤ odNumV (vTree x) := hg2lo - have : (2 ^ 530 * odTree x : Int) ≤ (odNumV (vTree x) : Int) := by exact_mod_cast h - nlinarith [this] - have hg2hi' : (odNumV (vTree x) : Int) * 2 ^ 512 < 2 ^ 1042 * (odTree x : Int) + 67305505 * 2 ^ 1016 := by - have h : odNumV (vTree x) < 2 ^ 530 * odTree x + 67305505 * 2 ^ 504 := hg2hi - have : (odNumV (vTree x) : Int) < (2 ^ 530 * odTree x + 67305505 * 2 ^ 504 : Nat) := by exact_mod_cast h - push_cast at this; nlinarith [this] - have hstep := odNumV_step hvlt - have hstep' : (odNumV (vTree x + 1) : Int) * 2 ^ 512 < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1037 := by - have he : (2:Int) ^ 1037 = 2 ^ 525 * 2 ^ 512 := by rw [← pow_add] - rw [he]; nlinarith [hstep, pow_pos (by norm_num : (0:Int) < 2) 512] - refine ⟨le_trans hg2lo' hmono_lo, ?_⟩ - calc evalPoly Pod (t ^ 2) ≤ (odNumV (vTree x + 1) : Int) * 2 ^ 512 := hmono_hi - _ < (odNumV (vTree x) : Int) * 2 ^ 512 + 2 ^ 1037 := hstep' - _ < 2 ^ 1042 * (odTree x : Int) + 67305505 * 2 ^ 1016 + 2 ^ 1037 := by linarith [hg2hi'] - _ = 2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016 := by - rw [show (2:Int) ^ 1037 = 2 ^ 21 * 2 ^ 1016 from by rw [← pow_add]]; ring - -/-! ## The `t·Od` term and the numerator/denominator brackets (nonnegative half `t ≥ 0`) -/ - -/-- `evalPoly todNumV t = 2²³ · t · evalPoly odNumVPoly t`. -/ -theorem evalTodNumV (t : Int) : - evalPoly ExpCertV.todNumV t = 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := by - unfold ExpCertV.todNumV - rw [evalPoly_polyScale] - simp only [evalPoly] - ring - -/-- `evalPoly numExpV t = evalPoly evNumVPoly t + evalPoly todNumV t`. -/ -theorem evalNumExpV (t : Int) : - evalPoly ExpCertV.numExpV t = evalPoly ExpCertV.evNumVPoly t + evalPoly ExpCertV.todNumV t := by - unfold ExpCertV.numExpV; rw [evalPoly_polyAdd] - -/-- `evalPoly denExpV t = evalPoly evNumVPoly t − evalPoly todNumV t`. -/ -theorem evalDenExpV (t : Int) : - evalPoly ExpCertV.denExpV t = evalPoly ExpCertV.evNumVPoly t - evalPoly ExpCertV.todNumV t := by - unfold ExpCertV.denExpV; rw [evalPoly_polySub] - -/-- `evNumVPoly` is even (`= Pev(t²)`). -/ -theorem evNumVPoly_even (t : Int) : - evalPoly ExpCertV.evNumVPoly (-t) = evalPoly ExpCertV.evNumVPoly t := by - rw [evNumVPoly_eq_Pev_sq, evNumVPoly_eq_Pev_sq] - congr 1; ring - -/-- `todNumV` is odd (`= 2²³·t·Pod(t²)`). -/ -theorem todNumV_odd (t : Int) : - evalPoly ExpCertV.todNumV (-t) = -evalPoly ExpCertV.todNumV t := by - rw [evalTodNumV, evalTodNumV, odNumVPoly_eq_Pod_sq, odNumVPoly_eq_Pod_sq] - rw [show ((-t)^2 : Int) = t^2 from by ring] - ring - -/-- **Reciprocal symmetry** `numExpV(−t) = denExpV(t)` and `denExpV(−t) = numExpV(t)`. -/ -theorem numExpV_neg_eq_denExpV (t : Int) : - evalPoly ExpCertV.numExpV (-t) = evalPoly ExpCertV.denExpV t := by - rw [evalNumExpV, evalDenExpV, evNumVPoly_even, todNumV_odd]; ring - -theorem denExpV_neg_eq_numExpV (t : Int) : - evalPoly ExpCertV.denExpV (-t) = evalPoly ExpCertV.numExpV t := by - rw [evalDenExpV, evalNumExpV, evNumVPoly_even, todNumV_odd]; ring - -/-- **The `t·Od` cert term brackets the runtime `tod`** (nonnegative half): for `0 ≤ t`, -`2¹¹⁹³·tod ≤ evalPoly todNumV t < 2¹¹⁹³·tod + 2⁵·2¹¹⁹³`. -/ -theorem todNumV_bracket {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - 2 ^ 1193 * (int256 (todTree x)) ≤ evalPoly ExpCertV.todNumV (int256 (tTree x)) ∧ - evalPoly ExpCertV.todNumV (int256 (tTree x)) < 2 ^ 1193 * (int256 (todTree x)) + 4 * 2 ^ 1193 := by - obtain ⟨_, _, htodlo, htodhi⟩ := todTree_bound hx hC hC0 - obtain ⟨hodlo, hodhi⟩ := odNumVPoly_bracket hx hC hC0 - set t := int256 (tTree x) with htdef - rw [evalTodNumV] - -- odTree ≥ 0 - have hodnn : (0 : Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - -- 2^128·tod ≤ t·odTree < 2^128·tod + 2^128 - -- multiply odd bracket by t·2^23 (t ≥ 0): - have hmul_lo : t * (2 ^ 1042 * (odTree x : Int)) ≤ t * evalPoly ExpCertV.odNumVPoly t := - mul_le_mul_of_nonneg_left hodlo htnn - have hmul_hi : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016) := - mul_le_mul_of_nonneg_left (le_of_lt hodhi) htnn - -- tod·2^128 ≤ t·odTree and t·odTree < tod·2^128 + 2^128 - have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo - have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi - constructor - · -- 2^1193·tod ≤ 2^23·(t·odpoly). 2^1193·tod = 2^23·(2^1042·(2^128·tod)) ... use 2^1193=2^23·2^1042·2^128 - have key : 2 ^ 1193 * (int256 (todTree x)) ≤ 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int))) := by - have e : (2 : Int) ^ 23 * (2 ^ 1042 * ((2:Int) ^ 128 * (int256 (todTree x)))) = - 2 ^ 1193 * (int256 (todTree x)) := by ring - rw [← e] - have := mul_le_mul_of_nonneg_left htod_lo (by positivity : (0:Int) ≤ 2 ^ 23 * 2 ^ 1042) - nlinarith [this] - calc 2 ^ 1193 * (int256 (todTree x)) ≤ 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int))) := key - _ ≤ 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := - mul_le_mul_of_nonneg_left hmul_lo (by positivity) - · -- 2^23·(t·odpoly) < 2^1193·tod + 4·2^1193 (the tight odd width 69402657·2^1016·t stays well under) - -- t·odpoly ≤ 2^1042·(t·odTree) + 69402657·2^1016·t, t·odTree < 2^128·tod + 2^128, t < 2^128. - obtain ⟨htlo', hthi'⟩ := tTree_bound hx hC hC0 - have htlt : t < 2 ^ 128 := by - have : t < 2 ^ 127 := by rw [show ((2:Int)^127) = 170141183460469231731687303715884105728 from by norm_num]; exact hthi' - have : (2:Int)^127 < 2 ^ 128 := by norm_num - omega - have key : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) < - 2 ^ 1193 * (int256 (todTree x)) + 4 * 2 ^ 1193 := by - have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ - 2 ^ 1042 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1016 * t := by - nlinarith [hmul_hi] - have h2 : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htod_hi - -- 2^23·69402657·2^1016·t < 69402657·2^1167 < 3·2^1193 (t < 2^128, 69402657 < 3·2^26) - have hpow : (69402657 : Int) * 2 ^ 1167 < 3 * 2 ^ 1193 := by - have he : (3:Int) * 2 ^ 1193 = (3 * 2 ^ 26) * 2 ^ 1167 := by - rw [show (3:Int) * 2 ^ 26 * 2 ^ 1167 = 3 * (2 ^ 26 * 2 ^ 1167) from by ring, - show (2:Int) ^ 26 * 2 ^ 1167 = 2 ^ (26 + 1167) from by rw [← pow_add], - show (26:Nat) + 1167 = 1193 from by norm_num] - rw [he] - have : (69402657 : Int) < 3 * 2 ^ 26 := by norm_num - nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1167, this] - have hcarry : (2:Int) ^ 23 * (69402657 * 2 ^ 1016 * t) ≤ 69402657 * 2 ^ 1167 := by - have ht : (2:Int) ^ 23 * (69402657 * 2 ^ 1016 * t) = 69402657 * 2 ^ 1039 * t := by - rw [show (2:Int) ^ 1039 = 2 ^ 23 * 2 ^ 1016 from by rw [← pow_add]]; ring - rw [ht, show (2:Int) ^ 1167 = 2 ^ 1039 * 2 ^ 128 from by rw [← pow_add]] - nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1039, htlt, htnn] - nlinarith [h1, h2, htlt, htnn, mul_nonneg htnn hodnn, hcarry, hpow] - exact key - -/-! ## The numerator/denominator cert brackets and the `r0`-vs-`ê_v` bracket -/ - -/-- The numerator cert polynomial brackets `2¹¹⁹³·num_rt` (`num_rt = ev + tod`): within `35·2¹¹⁹³`. -/ -theorem numExpV_bracket {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - 2 ^ 1193 * ((evTree x : Int) + int256 (todTree x)) ≤ evalPoly ExpCertV.numExpV (int256 (tTree x)) ∧ - evalPoly ExpCertV.numExpV (int256 (tTree x)) < - 2 ^ 1193 * ((evTree x : Int) + int256 (todTree x)) + 35 * 2 ^ 1193 := by - obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 - obtain ⟨htodlo, htodhi⟩ := todNumV_bracket hx hC hC0 htnn - rw [evalNumExpV] - constructor - · nlinarith [hevlo, htodlo] - · nlinarith [hevhi, htodhi] - -/-- The denominator cert polynomial brackets `2¹¹⁹³·den_rt` (`den_rt = ev − tod`): within `32·2¹¹⁹³`. -/ -theorem denExpV_bracket {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) - 32 * 2 ^ 1193 ≤ - evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ - evalPoly ExpCertV.denExpV (int256 (tTree x)) < - 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) + 3 * 2 ^ 1193 := by - obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 - obtain ⟨htodlo, htodhi⟩ := todNumV_bracket hx hC hC0 htnn - rw [evalDenExpV] - constructor - · nlinarith [hevlo, htodhi] - · nlinarith [hevhi, htodlo] +set_option exponentiation.threshold 2000 /-! ## The `sdiv` floor sandwich -/ @@ -420,8 +67,7 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 rw [hnumi] have : (evTree x : Int) < 2 ^ 127 := by exact_mod_cast hevhi - have ht125 : int256 (todTree x) < 2 ^ 125 := by - rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num]; exact htod_hi + have ht125 : int256 (todTree x) < 2 ^ 125 := htod_hi nlinarith [this, ht125] have hshl : int256 (evmShl 0x7e num) = 2 ^ 0x7e * int256 num := shl126_transport hnumw (by rw [hnumi]; omega) hnumlt128 @@ -476,425 +122,295 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) have hInt : (M : Int) < ((q : Int) + 1) * (den : Int) := by exact_mod_cast h rw [heM] at hInt; linarith [hInt] -/-! ## A positive lower bound on the cert denominator -/ - -/-- `den_rt = ev − tod > 2¹²⁵` on the region (the even accumulator dominates `|tod|`). -/ -theorem den_rt_lb {x : Nat} (hx : x < 2 ^ 256) +/-- `den_rt = ev − tod ≥ 0.72·2¹²⁶` on the region (the even accumulator dominates `|tod|`). -/ +theorem den_ge_072 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 : Int) ^ 125 < (evTree x : Int) - int256 (todTree x) := by + (61251667532612381706986956632087880162 : Int) ≤ + (evTree x : Int) - int256 (todTree x) := by obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 - have hev : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo - have ht125 : int256 (todTree x) < 2 ^ 125 := by - rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num]; exact htod_hi - rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 from by norm_num] at hev - rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 ⊢ + obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + have hev : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + have ht125 : int256 (todTree x) < 2 ^ 125 := htod_hi + rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 from by norm_num] at hev + rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 omega -/-- The cert denominator is bounded below: `denExpV(t) > 2¹³¹⁷` on the region. -/ -theorem denExpV_lb {x : Nat} (hx : x < 2 ^ 256) +/-- On the nonpositive half `tod ≤ 0` and hence `r0 ≤ 2¹²⁶` (num ≤ den). -/ +theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + int256 (r0Tree x) ≤ 2 ^ 126 := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + have hden072 : (61251667532612381706986956632087880162 : Int) ≤ ev - tod := by + have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 + have htodnp : tod ≤ 0 := by + obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 + have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ + have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn + nlinarith [htodlo, this] + -- r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den) + have hnumden : r0 * (ev - tod) ≤ 2 ^ 126 * (ev - tod) := by + have h1 : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo + nlinarith [h1, htodnp, (by positivity : (0:Int) ≤ (2:Int)^126)] + exact le_of_mul_le_mul_right hnumden hdenpos + +/-! ## The runtime brackets lifted to the `2^725` alignment + +`NUMv/DENv = Ev·2^110 ± t·Od` (`Floor.GranV`). The Horner-truncation brackets +(`evTree_bracket`/`odTree_bracket`, widths `Wev = 283678831804417·2^480 ≈ 1.0079·2^528` and +`Wod = 1075052609·2^480 ≈ 1.0013·2^510`) and the `tod` floor (`todTree_bound`) tie them to the +runtime `ev`/`tod` at the common scale `2^638`. -/ + +/-- The `Int`-cast Horner brackets and `tod` floor collected. -/ +theorem bridge_facts {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + 2 ^ 528 * (evTree x : Int) ≤ (evNumV (vTree x) : Int) ∧ + (evNumV (vTree x) : Int) < 2 ^ 528 * (evTree x : Int) + 283678831804417 * 2 ^ 480 ∧ + 2 ^ 510 * (odTree x : Int) ≤ (odNumV (vTree x) : Int) ∧ + (odNumV (vTree x) : Int) < 2 ^ 510 * (odTree x : Int) + 1075052609 * 2 ^ 480 := by + obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 + obtain ⟨hev_lo, hev_hi⟩ := evTree_bracket hvlt + obtain ⟨hod_lo, hod_hi⟩ := odTree_bracket hvlt + refine ⟨?_, ?_, ?_, ?_⟩ + · exact_mod_cast hev_lo + · exact_mod_cast hev_hi + · exact_mod_cast hod_lo + · exact_mod_cast hod_hi + +/-- The `t·Od` product brackets (nonnegative half): `2⁶³⁸·tod ≤ t·Od` and +`t·Od ≤ 2⁶³⁸·tod + 2⁶³⁸ + Wod·2⁴⁸⁰·t`. -/ +theorem tOd_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (2 : Int) ^ 1317 < evalPoly ExpCertV.denExpV (int256 (tTree x)) := by - obtain ⟨hlo, _⟩ := denExpV_bracket hx hC hC0 htnn - have hden := den_rt_lb hx hC hC0 - -- denExpV ≥ 2^1193·den_rt − 32·2^1193 > 2^1193·2^125 − 32·2^1193 = 2^1318 − 32·2^1193 > 2^1317 - have hstep : 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) - 32 * 2 ^ 1193 > - 2 ^ 1193 * (2 ^ 125 : Int) - 32 * 2 ^ 1193 := by - have := mul_lt_mul_of_pos_left hden (by positivity : (0:Int) < 2 ^ 1193) - linarith [this] - have hnum : 2 ^ 1193 * (2 ^ 125 : Int) - 32 * 2 ^ 1193 > 2 ^ 1317 := by - rw [show (2:Int)^1193 * 2 ^ 125 = 2 ^ 1318 from by rw [← pow_add]] - have h18 : (2:Int)^1318 = 2 * 2 ^ 1317 := by rw [show (1318:Nat) = 1 + 1317 from rfl, pow_add]; ring - have h93 : (2:Int)^1193 < 2 ^ 1317 := by - apply pow_lt_pow_right₀ (by norm_num) (by norm_num) - nlinarith [h18, h93] - linarith [hlo, hstep, hnum] - -/-! ## The `r0`-vs-cert-rational bracket (direct chain) -/ + 2 ^ 638 * int256 (todTree x) ≤ int256 (tTree x) * (odNumV (vTree x) : Int) ∧ + int256 (tTree x) * (odNumV (vTree x) : Int) ≤ + 2 ^ 638 * int256 (todTree x) + 2 ^ 638 + 1075052609 * 2 ^ 480 * int256 (tTree x) := by + obtain ⟨_, _, hOp_lo, hOp_hi⟩ := bridge_facts hx hC hC0 + obtain ⟨_, _, htod_lo, htod_hi⟩ := todTree_bound hx hC hC0 + set t := int256 (tTree x) with htdef + set od := (odTree x : Int) with hoddef + set tod := int256 (todTree x) with htoddef + set Op := (odNumV (vTree x) : Int) with hOpdef + constructor + · -- t·Op ≥ t·(2^510·od) = 2^510·(t·od) ≥ 2^510·(2^128·tod) = 2^638·tod + have h1 : t * (2 ^ 510 * od) ≤ t * Op := mul_le_mul_of_nonneg_left hOp_lo htnn + have h2 : (2:Int) ^ 510 * (2 ^ 128 * tod) ≤ 2 ^ 510 * (t * od) := + mul_le_mul_of_nonneg_left htod_lo (by positivity) + nlinarith [h1, h2] + · -- t·Op ≤ t·(2^510·od + Wod·2^480) ≤ 2^510·(2^128·tod + 2^128) + Wod·2^480·t + have h1 : t * Op ≤ t * (2 ^ 510 * od + 1075052609 * 2 ^ 480) := + mul_le_mul_of_nonneg_left (le_of_lt hOp_hi) htnn + have h2 : (2:Int) ^ 510 * (t * od) ≤ 2 ^ 510 * (2 ^ 128 * tod + 2 ^ 128) := + mul_le_mul_of_nonneg_left (le_of_lt htod_hi) (by positivity) + nlinarith [h1, h2] -/-- **`r0Tree x` brackets `2¹²⁶·ê_v`**: `r0·denExpV < 2¹²⁶·numExpV + 49·denExpV` and -`2¹²⁶·numExpV < (r0+1)·denExpV + 700·denExpV`. The loose constants are MARGIN/seam-absorbed. -/ -theorem r0_vs_certRatio {x : Nat} (hx : x < 2 ^ 256) +/-- The `t·Od` product brackets (nonpositive half): `t·Od ≤ 2⁶³⁸·tod + 2⁶³⁸` and +`2⁶³⁸·tod − Wod·2⁴⁸⁰·(−t) ≤ t·Od`. -/ +theorem tOd_bracket_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) < - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) + - 49 * evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) < - (int256 (r0Tree x) + 1) * evalPoly ExpCertV.denExpV (int256 (tTree x)) + - 700 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by - obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hnumlo, hnumhi⟩ := numExpV_bracket hx hC hC0 htnn - obtain ⟨hdenlo, hdenhi⟩ := denExpV_bracket hx hC hC0 htnn - obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 - have hdenExpV_lb := denExpV_lb hx hC hC0 htnn - set r0 := int256 (r0Tree x) with hr0def - set num := (evTree x : Int) + int256 (todTree x) with hnumdef - set den := (evTree x : Int) - int256 (todTree x) with hdendef - set NE := evalPoly ExpCertV.numExpV (int256 (tTree x)) with hNEdef - set DE := evalPoly ExpCertV.denExpV (int256 (tTree x)) with hDEdef - have hDEpos : (0 : Int) < DE := by - have h : (2:Int)^1317 > 0 := by positivity - linarith [hdenExpV_lb, h] - have hr0pos : 0 ≤ r0 := by linarith [hr0lo] - have hr0lt : r0 < 2 ^ 128 := hr0hi - have hp1193 : (0 : Int) < 2 ^ 1193 := by positivity - have hden_nn : (0 : Int) ≤ den := by - have h := den_rt_lb hx hC hC0; rw [← hdendef] at h; positivity - -- DE bounds vs den·2^1193 (denExpV_bracket): DE - 3·2^1193 < den·2^1193 ≤ DE + 32·2^1193 - have hden2_lo : 2 ^ 1193 * den ≤ DE + 32 * 2 ^ 1193 := by linarith [hdenlo] - have hden2_hi : DE - 3 * 2 ^ 1193 < 2 ^ 1193 * den := by linarith [hdenhi] - -- NE bounds (numExpV_bracket): num·2^1193 ≤ NE < num·2^1193 + 35·2^1193 - have hnum2_lo : 2 ^ 1193 * num ≤ NE := hnumlo - have hnum2_hi : NE < 2 ^ 1193 * num + 35 * 2 ^ 1193 := hnumhi - -- 49·DE > 49·2^1317 > 3·2^1321 ≥ 3·2^1193·r0 - have h2_1321 : (3 : Int) * 2 ^ 1193 * (2 ^ 128 : Int) = 3 * 2 ^ 1321 := by rw [mul_assoc, ← pow_add] - have hr0_loss : 3 * 2 ^ 1193 * r0 < 49 * DE := by - have h1 : 3 * 2 ^ 1193 * r0 < 3 * 2 ^ 1193 * 2 ^ 128 := by - apply mul_lt_mul_of_pos_left hr0lt; positivity - have h2 : (3 : Int) * 2 ^ 1321 < 49 * 2 ^ 1317 := by - rw [show (1321:Nat) = 4 + 1317 from rfl, pow_add]; ring_nf; nlinarith [pow_pos (by norm_num : (0:Int)<2) 1317] - rw [h2_1321] at h1 - linarith [h1, h2, mul_lt_mul_of_pos_left hdenExpV_lb (by norm_num : (0:Int) < 49)] - -- 700·DE > 35·2^1319 + 32·2^1193·(r0+1) (under loss) - have hunder_loss : 35 * 2 ^ 126 * 2 ^ 1193 + 32 * 2 ^ 1193 * (r0 + 1) < 700 * DE := by - have h1 : 32 * 2 ^ 1193 * (r0 + 1) < 32 * 2 ^ 1193 * (2 ^ 128 + 1) := by - apply mul_lt_mul_of_pos_left (by linarith [hr0lt]); positivity - have hr0p1 : (32 : Int) * 2 ^ 1193 * (2 ^ 128 + 1) < 33 * 2 ^ 1321 := by - rw [show (1321:Nat) = 4 + 1317 from rfl, pow_add]; ring_nf - nlinarith [pow_pos (by norm_num : (0:Int)<2) 1193, pow_pos (by norm_num : (0:Int)<2) 1317] - have h35 : (35 : Int) * 2 ^ 126 * 2 ^ 1193 = 35 * 2 ^ 1319 := by rw [mul_assoc, ← pow_add] - have hbound : (35 : Int) * 2 ^ 1319 + 33 * 2 ^ 1321 < 700 * 2 ^ 1317 := by - rw [show (1319:Nat) = 2 + 1317 from rfl, show (1321:Nat) = 4 + 1317 from rfl, pow_add, pow_add] - ring_nf; nlinarith [pow_pos (by norm_num : (0:Int)<2) 1317] - rw [h35] - linarith [h1, hr0p1, hbound, mul_lt_mul_of_pos_left hdenExpV_lb (by norm_num : (0:Int) < 700)] - -- abstract the powers so the final steps stay linear in the kernel - have hfl_lo := mul_le_mul_of_nonneg_left hfloor_lo (by positivity : (0:Int) ≤ 2 ^ 1193) - have hfl_hi := mul_lt_mul_of_pos_left hfloor_hi hp1193 - have hnumstep := mul_le_mul_of_nonneg_left hnum2_lo (by positivity : (0:Int) ≤ 2 ^ 126) - have hNEstep := mul_lt_mul_of_pos_left hnum2_hi (by positivity : (0:Int) < 2 ^ 126) - have hr0den_lo := mul_le_mul_of_nonneg_left (le_of_lt hden2_hi) hr0pos - have hr0den_hi := mul_le_mul_of_nonneg_left hden2_lo (by linarith [hr0pos] : (0:Int) ≤ r0 + 1) - -- expand products into a common shape via ring_nf, then linarith over the atoms + (htneg : int256 (tTree x) ≤ 0) : + int256 (tTree x) * (odNumV (vTree x) : Int) ≤ 2 ^ 638 * int256 (todTree x) + 2 ^ 638 ∧ + 2 ^ 638 * int256 (todTree x) - 1075052609 * 2 ^ 480 * (-(int256 (tTree x))) ≤ + int256 (tTree x) * (odNumV (vTree x) : Int) := by + obtain ⟨_, _, hOp_lo, hOp_hi⟩ := bridge_facts hx hC hC0 + obtain ⟨_, _, htod_lo, htod_hi⟩ := todTree_bound hx hC hC0 + set t := int256 (tTree x) with htdef + set od := (odTree x : Int) with hoddef + set tod := int256 (todTree x) with htoddef + set Op := (odNumV (vTree x) : Int) with hOpdef constructor - · nlinarith [hfl_lo, hnumstep, hr0den_lo, hr0_loss, hDEpos, hp1193] - · nlinarith [hfl_hi, hNEstep, hr0den_hi, hunder_loss, hDEpos, hp1193] + · -- t·Op ≤ t·(2^510·od) = 2^510·(t·od) ≤ 2^510·(2^128·tod + 2^128) + have h1 : t * Op ≤ t * (2 ^ 510 * od) := mul_le_mul_of_nonpos_left hOp_lo htneg + have h2 : (2:Int) ^ 510 * (t * od) ≤ 2 ^ 510 * (2 ^ 128 * tod + 2 ^ 128) := + mul_le_mul_of_nonneg_left (le_of_lt htod_hi) (by positivity) + nlinarith [h1, h2] + · -- t·Op ≥ t·(2^510·od + Wod·2^480) = 2^510·(t·od) + Wod·2^480·t ≥ 2^638·tod − Wod·2^480·(−t) + have h1 : t * (2 ^ 510 * od + 1075052609 * 2 ^ 480) ≤ t * Op := + mul_le_mul_of_nonpos_left (le_of_lt hOp_hi) htneg + have h2 : (2:Int) ^ 510 * (2 ^ 128 * tod) ≤ 2 ^ 510 * (t * od) := + mul_le_mul_of_nonneg_left htod_lo (by positivity) + nlinarith [h1, h2] + +/-! ## Link 1 (over side): `r0` vs the grid rational, shared-`Ev` cancellation -/ --- Joint cert-ratio over: r0·DE − 2^126·NE ≤ W_ev_int·(r0−2^126), W_ev_int = 1130577·2^1173. --- evP = evalPoly evNumVPoly t, NE = evP + todP, DE = evP − todP. Ee = evP − 2^1193·ev ∈ [0,W_ev). --- todP ≥ 2^1193·tod. Floor: r0·den ≤ 2^126·num. -theorem r0_certRatio_over_tight {x : Nat} (hx : x < 2 ^ 256) +/-- **Joint link-1 over (nonneg half, `r0 ≥ 2¹²⁶`)**: the shared even truncation cancels through +the floor, `r0·DENv − 2¹²⁶·NUMv ≤ Wev·2⁵⁹⁰·(r0 − 2¹²⁶)`. -/ +theorem link1_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) (hr0ge : (2:Int)^126 ≤ int256 (r0Tree x)) : - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) - - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) ≤ - 1130577 * 2 ^ 1173 * (int256 (r0Tree x) - 2 ^ 126) := by + (htnn : 0 ≤ int256 (tTree x)) (hr0ge : (2:Int) ^ 126 ≤ int256 (r0Tree x)) : + int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - + 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) ≤ + 283678831804417 * 2 ^ 590 * (int256 (r0Tree x) - 2 ^ 126) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 - obtain ⟨htodlo, _⟩ := todNumV_bracket hx hC hC0 htnn - rw [evalNumExpV, evalDenExpV] + obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 + obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn + unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - set evP := evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) with hevP - set todP := evalPoly ExpCertV.todNumV (int256 (tTree x)) with htodP - -- r0·(evP−todP) − 2^126·(evP+todP) = evP·(r0−2^126) − todP·(r0+2^126) - -- ≤ (2^1193·ev + W_ev)·(r0−2^126) − 2^1193·tod·(r0+2^126) - -- [evP ≤ 2^1193 ev + W_ev (hevhi), r0−2^126≥0; todP ≥ 2^1193 tod (htodlo), -(·)(r0+2^126)≤0] - -- = 2^1193·[ev(r0−2^126) − tod(r0+2^126)] + W_ev·(r0−2^126) - -- = 2^1193·[(ev−tod)·r0 − 2^126·(ev+tod)] + W_ev·(r0−2^126) - -- = 2^1193·[den·r0 − 2^126·num] + W_ev·(r0−2^126) ≤ 0 + W_ev·(r0−2^126) [floor] - have hr0m : (0:Int) ≤ r0 - 2^126 := by linarith [hr0ge] - have hr0p : (0:Int) ≤ r0 + 2^126 := by linarith [hr0ge] - -- evP ≤ 2^1193 ev + W_ev - have hWev : evP ≤ 2^1193 * ev + 1130577 * 2^1173 := le_of_lt hevhi - -- bound the two terms - have hterm1 : evP * (r0 - 2^126) ≤ (2^1193 * ev + 1130577 * 2^1173) * (r0 - 2^126) := - mul_le_mul_of_nonneg_right hWev hr0m - have hterm2 : 2^1193 * tod * (r0 + 2^126) ≤ todP * (r0 + 2^126) := - mul_le_mul_of_nonneg_right htodlo hr0p - -- floor: r0·den ≤ 2^126·num, i.e. den·r0 - 2^126·num ≤ 0 (den=ev-tod, num=ev+tod) - have hfloor : r0 * (ev - tod) - 2^126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - -- assemble: 2^1193·(den·r0 − 2^126·num) ≤ 0 - have hfloor1193 : (2:Int)^1193 * (r0 * (ev - tod) - 2^126 * (ev + tod)) ≤ 0 := + set t := int256 (tTree x) with htdef + set Ep := (evNumV (vTree x) : Int) with hEpdef + set Op := (odNumV (vTree x) : Int) with hOpdef + have hr0m : (0:Int) ≤ r0 - 2 ^ 126 := by linarith [hr0ge] + have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by linarith [hr0ge] + -- Ep·2^110·(r0−2^126) ≤ (2^638·ev + Wev·2^590)·(r0−2^126) + have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ + (2 ^ 638 * ev + 283678831804417 * 2 ^ 590) * (r0 - 2 ^ 126) := by + apply mul_le_mul_of_nonneg_right _ hr0m + nlinarith [hEp_hi] + -- −(t·Op)·(r0+2^126) ≤ −(2^638·tod)·(r0+2^126) + have hterm2 : 2 ^ 638 * tod * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := + mul_le_mul_of_nonneg_right (by linarith [htOp_lo]) hr0p + -- floor: r0·den − 2^126·num ≤ 0, scaled by 2^638 + have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 638 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor - nlinarith [hterm1, hterm2, hfloor1193] + nlinarith [hterm1, hterm2, hfloor638] --- For r0 ≤ 2^126 the cert-ratio over is ≤ 0: evP·(r0−2^126) ≤ 0 and todP ≥ 0. -theorem r0_certRatio_over_small {x : Nat} (hx : x < 2 ^ 256) +/-- **Link-1 over (nonneg half, `r0 ≤ 2¹²⁶`)**: the residue is nonpositive outright. -/ +theorem link1_over_small {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) (hr0le : int256 (r0Tree x) ≤ (2:Int)^126) : - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) - - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) ≤ 0 := by - rw [evalNumExpV, evalDenExpV] + (htnn : 0 ≤ int256 (tTree x)) (hr0le : int256 (r0Tree x) ≤ (2:Int) ^ 126) : + int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - + 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) ≤ 0 := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 + obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn + unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def - set evP := evalPoly ExpCertV.evNumVPoly (int256 (tTree x)) with hevP - set todP := evalPoly ExpCertV.todNumV (int256 (tTree x)) with htodP - -- evP ≥ 0, todP ≥ 0 (nonneg half), r0−2^126 ≤ 0, r0+2^126 ≥ 0 - have hevPnn : (0:Int) ≤ evP := by - obtain ⟨hlo, _⟩ := evNumVPoly_bracket hx hC hC0 - have : (0:Int) ≤ 2^1193 * (evTree x : Int) := mul_nonneg (by norm_num) (Int.natCast_nonneg _) - linarith [hlo, this] - have htodPnn : (0:Int) ≤ todP := by - rw [htodP, evalTodNumV] - exact mul_nonneg (by positivity) (mul_nonneg htnn (odNumVPoly_nonneg _)) - have hr0nn : (0:Int) ≤ r0 := by obtain ⟨hlo, _⟩ := r0Tree_bounds hx hC hC0; linarith [hlo] - have hr0m : r0 - 2^126 ≤ 0 := by linarith [hr0le] - have hr0p : (0:Int) ≤ r0 + 2^126 := by positivity - -- r0·(evP−todP) − 2^126·(evP+todP) = evP·(r0−2^126) − todP·(r0+2^126) ≤ 0 - have h1 : evP * (r0 - 2^126) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos hevPnn hr0m - have h2 : 0 ≤ todP * (r0 + 2^126) := mul_nonneg htodPnn hr0p - nlinarith [h1, h2] - - -/-! ## The negative-half integer brackets - -For `t < 0` the runtime `tod = ⌊t·od/2¹²⁸⌋` is nonpositive, so the `t·Od` cert term `todNumV(t)` -(odd in `t`) is also nonpositive; multiplying the (sign-independent) odd-Horner bracket by `2²³·t < 0` -flips the inequalities. The even-Horner bracket `evNumVPoly_bracket` is sign-independent (even poly). -Assembling gives the numerator/denominator brackets and the same loose `r0`-vs-`ê_v` constants, with -the floor sandwich `r0_floor_sandwich` (itself sign-free). -/ + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set t := int256 (tTree x) with htdef + set Ep := (evNumV (vTree x) : Int) with hEpdef + set Op := (odNumV (vTree x) : Int) with hOpdef + obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 + have hr0nn : (0:Int) ≤ r0 := by + have : (0:Int) < 2 ^ 123 := by positivity + linarith [hr0lo] + have hr0m : r0 - 2 ^ 126 ≤ 0 := by linarith [hr0le] + have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by positivity + -- Ep·2^110·(r0−2^126) ≤ 2^638·ev·(r0−2^126) (Ep·2^110 ≥ 2^638·ev, factor ≤ 0) + have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ 2 ^ 638 * ev * (r0 - 2 ^ 126) := by + apply mul_le_mul_of_nonpos_right _ hr0m + nlinarith [hEp_lo] + have hterm2 : 2 ^ 638 * tod * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := + mul_le_mul_of_nonneg_right (by linarith [htOp_lo]) hr0p + have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 638 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor + nlinarith [hterm1, hterm2, hfloor638] -/-- **`todNumV` bracket (negative half).** For `t ≤ 0`: -`2¹¹⁹³·tod − 4·2¹¹⁹³ < todNumV(t) < 2¹¹⁹³·tod + 2·2¹¹⁹³`. -/ -theorem todNumV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) +/-- **Link-1 over (nonpositive half)**: the even truncation drops (`r0 ≤ 2¹²⁶`); the odd truncation +survives attenuated to the `t`-scale: `r0·DENv − 2¹²⁶·NUMv ≤ Wod·2⁴⁸⁰·(−t)·(r0 + 2¹²⁶)`. -/ +theorem link1_over_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - 2 ^ 1193 * (int256 (todTree x)) - 4 * 2 ^ 1193 < evalPoly ExpCertV.todNumV (int256 (tTree x)) ∧ - evalPoly ExpCertV.todNumV (int256 (tTree x)) < 2 ^ 1193 * (int256 (todTree x)) + 2 * 2 ^ 1193 := by - obtain ⟨_, _, htodlo, htodhi⟩ := todTree_bound hx hC hC0 - obtain ⟨hodlo, hodhi⟩ := odNumVPoly_bracket hx hC hC0 - obtain ⟨htlo', hthi'⟩ := tTree_bound hx hC hC0 + int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - + 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) ≤ + 1075052609 * 2 ^ 480 * (-(int256 (tTree x))) * (int256 (r0Tree x) + 2 ^ 126) := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 + obtain ⟨_, htOp_lo⟩ := tOd_bracket_neg hx hC hC0 htneg + have hr0le := r0_le_2126_neg hx hC hC0 htneg + unfold NUMv DENv + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef set t := int256 (tTree x) with htdef - rw [evalTodNumV] - have hodnn : (0 : Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have hodpolynn : (0 : Int) ≤ evalPoly ExpCertV.odNumVPoly t := le_trans (by positivity) hodlo - -- multiply odd bracket by t ≤ 0 (flips): - have hmul_lo : t * evalPoly ExpCertV.odNumVPoly t ≤ t * (2 ^ 1042 * (odTree x : Int)) := - mul_le_mul_of_nonpos_left hodlo htneg - have hmul_hi : t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016) ≤ t * evalPoly ExpCertV.odNumVPoly t := - mul_le_mul_of_nonpos_left (le_of_lt hodhi) htneg - have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo - have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi - have htgt : -(2 ^ 128 : Int) < t := by - have : -(2:Int)^127 < t := htlo' - have h2 : -(2:Int)^128 < -(2:Int)^127 := by norm_num - omega - constructor - · -- todNumV = 2^23·(t·odpoly) ≥ 2^1065·(t·odTree) + 69402657·2^1039·t (since t ≤ 0, the odd width - -- contributes a negative shift) ≥ 2^1193·tod − 69402657·2^1167/... > 2^1193·tod − 4·2^1193 - have h1 : 2 ^ 1042 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1016 * t ≤ - t * evalPoly ExpCertV.odNumVPoly t := by nlinarith [hmul_hi] - have h2 : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htod_lo - -- 2^23·69402657·2^1016·t > -69402657·2^1167 > -3·2^1193 (t > -2^128) - have hcarry : -(69402657 * 2 ^ 1167 : Int) < (2:Int) ^ 23 * (69402657 * 2 ^ 1016 * t) := by - have ht : (2:Int) ^ 23 * (69402657 * 2 ^ 1016 * t) = 69402657 * 2 ^ 1039 * t := by - rw [show (2:Int) ^ 1039 = 2 ^ 23 * 2 ^ 1016 from by rw [← pow_add]]; ring - rw [ht, show (69402657 : Int) * 2 ^ 1167 = 69402657 * 2 ^ 1039 * 2 ^ 128 from by - rw [show (2:Int) ^ 1167 = 2 ^ 1039 * 2 ^ 128 from by rw [← pow_add]]; ring] - nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1039, htgt] - have hpow : -(69402657 * 2 ^ 1167 : Int) ≥ -(3 * 2 ^ 1193) := by - rw [ge_iff_le, neg_le_neg_iff, show (3:Int) * 2 ^ 1193 = (3 * 2 ^ 26) * 2 ^ 1167 from by - rw [show (2:Int) ^ 1193 = 2 ^ 26 * 2 ^ 1167 from by rw [← pow_add]]; ring] - have : (69402657 : Int) ≤ 3 * 2 ^ 26 := by norm_num - nlinarith [pow_pos (by norm_num : (0:Int) < 2) 1167, this] - nlinarith [h1, h2, htgt, hcarry, hpow] - · -- todNumV = 2^23·(t·odpoly) ≤ 2^23·(t·2^1042 odTree) = 2^1065·(t·odTree) < 2^1193·tod + 2^1193 - have h1 : t * evalPoly ExpCertV.odNumVPoly t ≤ 2 ^ 1042 * (t * (odTree x : Int)) := by - nlinarith [hmul_lo] - have h2 : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htod_hi - nlinarith [h1, h2] + set Ep := (evNumV (vTree x) : Int) with hEpdef + set Op := (odNumV (vTree x) : Int) with hOpdef + obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 + have hr0nn : (0:Int) ≤ r0 := by + have : (0:Int) < 2 ^ 123 := by positivity + linarith [hr0lo] + have hr0m : r0 - 2 ^ 126 ≤ 0 := by linarith [hr0le] + have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by positivity + have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ 2 ^ 638 * ev * (r0 - 2 ^ 126) := by + apply mul_le_mul_of_nonpos_right _ hr0m + nlinarith [hEp_lo] + -- −(t·Op)·(r0+2^126) ≤ (−2^638·tod + Wod·2^480·(−t))·(r0+2^126) + have hterm2 : (2 ^ 638 * tod - 1075052609 * 2 ^ 480 * (-t)) * (r0 + 2 ^ 126) ≤ + t * Op * (r0 + 2 ^ 126) := + mul_le_mul_of_nonneg_right htOp_lo hr0p + have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 638 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor + nlinarith [hterm1, hterm2, hfloor638] -/-- **Numerator/denominator brackets (negative half).** `NE ∈ (S·num_rt − 4S, S·num_rt + 4S)`, -`DE ∈ (S·den_rt − 2S, S·den_rt + 4S)` (`S = 2¹¹⁹³`, `num_rt = ev + tod`, `den_rt = ev − tod`). -/ -theorem numExpV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - 2 ^ 1193 * ((evTree x : Int) + int256 (todTree x)) - 4 * 2 ^ 1193 < - evalPoly ExpCertV.numExpV (int256 (tTree x)) ∧ - evalPoly ExpCertV.numExpV (int256 (tTree x)) < - 2 ^ 1193 * ((evTree x : Int) + int256 (todTree x)) + 5 * 2 ^ 1193 := by - obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 - obtain ⟨htodlo, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg - rw [evalNumExpV] - constructor - · nlinarith [hevlo, htodlo] - · nlinarith [hevhi, htodhi] +/-! ## Denominator bounds for the grid rational in runtime terms -/ -theorem denExpV_bracket_neg {x : Nat} (hx : x < 2 ^ 256) +/-- On the nonneg half `DENv` brackets the runtime denominator: +`2⁶³⁸·(den − 2) ≤ DENv ≤ 2⁶³⁸·den + Wev·2⁵⁹⁰` (`den = ev − tod`). -/ +theorem DENv_runtime_bracket {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 1193 < - evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ - evalPoly ExpCertV.denExpV (int256 (tTree x)) < - 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) + 7 * 2 ^ 1193 := by - obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 - obtain ⟨htodlo, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg - rw [evalDenExpV] + (htnn : 0 ≤ int256 (tTree x)) : + 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 638 ≤ + DENv (vTree x) (int256 (tTree x)) ∧ + DENv (vTree x) (int256 (tTree x)) ≤ + 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) + 283678831804417 * 2 ^ 590 := by + obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 + obtain ⟨htOp_lo, htOp_hi⟩ := tOd_bracket_nonneg hx hC hC0 htnn + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + unfold DENv + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set t := int256 (tTree x) with htdef + set Ep := (evNumV (vTree x) : Int) with hEpdef + set Op := (odNumV (vTree x) : Int) with hOpdef constructor - · nlinarith [hevlo, htodhi] - · nlinarith [hevhi, htodlo] - -/-- The cert denominator stays large on the negative half too: `denExpV(t) > 2¹³¹⁷`. (For `t < 0`, -`den_rt = ev − tod ≥ ev > 2¹²⁵`, so `DE > S·2¹²⁵ − 2S > 2¹³¹⁷`.) -/ -theorem denExpV_lb_neg {x : Nat} (hx : x < 2 ^ 256) + · -- lower: Ep·2^110 ≥ 2^638·ev; t·Op ≤ 2^638·tod + 2^638 + Wod·2^480·t, t ≤ H128; + -- Wod·2^480·H128 + 2^638 ≤ 2·2^638 + have h1 : 2 ^ 638 * ev ≤ Ep * 2 ^ 110 := by nlinarith [hEp_lo] + have h2 : 1075052609 * 2 ^ 480 * t ≤ + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199 := + mul_le_mul_of_nonneg_left hthi (by positivity) + have h3 : (1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199 : Int) + 2 ^ 638 ≤ + 2 * 2 ^ 638 := by norm_num + linarith [h1, htOp_hi, h2, h3] + · -- upper: Ep·2^110 ≤ 2^638·ev + Wev·2^590; t·Op ≥ 2^638·tod + have h1 : Ep * 2 ^ 110 ≤ 2 ^ 638 * ev + 283678831804417 * 2 ^ 590 := by nlinarith [hEp_hi] + linarith [h1, htOp_lo] + +/-- On the nonpositive half `DENv` dominates the scaled even accumulator: `2⁶³⁸·ev ≤ DENv`. -/ +theorem DENv_ge_ev_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (2 : Int) ^ 1317 < evalPoly ExpCertV.denExpV (int256 (tTree x)) := by - obtain ⟨hlo, _⟩ := denExpV_bracket_neg hx hC hC0 htneg - -- den_rt = ev − tod ≥ ev > 2^125 (tod ≤ 0 on the negative half) - obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 - have hev : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo - rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 from by norm_num] at hev - -- tod ≤ 0 ⇒ den_rt = ev − tod ≥ ev > 2^125 - have htodnp : int256 (todTree x) ≤ 0 := by - -- from todTree_bound: 2^128·tod ≤ t·od, t ≤ 0, od ≥ 0 ⇒ t·od ≤ 0 ⇒ tod ≤ 0 - obtain ⟨_, _, htl, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn - nlinarith [htl, this] - have hden_rt : (2 : Int) ^ 125 < (evTree x : Int) - int256 (todTree x) := by - rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] - omega - have hstep : 2 ^ 1193 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 1193 > - 2 ^ 1193 * (2 ^ 125 : Int) - 2 * 2 ^ 1193 := by - have := mul_lt_mul_of_pos_left hden_rt (by positivity : (0:Int) < 2 ^ 1193) - linarith [this] - have hnum : 2 ^ 1193 * (2 ^ 125 : Int) - 2 * 2 ^ 1193 > 2 ^ 1317 := by - rw [show (2:Int)^1193 * 2 ^ 125 = 2 ^ 1318 from by rw [← pow_add]] - have h18 : (2:Int)^1318 = 2 * 2 ^ 1317 := by rw [show (1318:Nat) = 1 + 1317 from rfl, pow_add]; ring - have h93 : (2:Int)^1193 < 2 ^ 1317 := pow_lt_pow_right₀ (by norm_num) (by norm_num) - nlinarith [h18, h93] - linarith [hlo, hstep, hnum] - -/-- **`r0`-vs-cert-rational bracket (negative half).** Same loose constants as the nonnegative half. -/ -theorem r0_vs_certRatio_neg {x : Nat} (hx : x < 2 ^ 256) + 2 ^ 638 * (evTree x : Int) ≤ DENv (vTree x) (int256 (tTree x)) := by + obtain ⟨hEp_lo, _, _, hOp_hi⟩ := bridge_facts hx hC hC0 + unfold DENv + have hOp_nn : (0:Int) ≤ (odNumV (vTree x) : Int) := Int.natCast_nonneg _ + have htOp : int256 (tTree x) * (odNumV (vTree x) : Int) ≤ 0 := + mul_nonpos_of_nonpos_of_nonneg htneg hOp_nn + nlinarith [hEp_lo, htOp] + +/-- On the nonneg half `NUMv` dominates the scaled runtime numerator: `2⁶³⁸·num ≤ NUMv`. -/ +theorem NUMv_ge_num {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) < - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) + - 150 * evalPoly ExpCertV.denExpV (int256 (tTree x)) ∧ - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) < - (int256 (r0Tree x) + 1) * evalPoly ExpCertV.denExpV (int256 (tTree x)) + - 700 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by - obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hnumlo, hnumhi⟩ := numExpV_bracket_neg hx hC hC0 htneg - obtain ⟨hdenlo, hdenhi⟩ := denExpV_bracket_neg hx hC hC0 htneg - obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 - have hdenExpV_lb := denExpV_lb_neg hx hC hC0 htneg - set r0 := int256 (r0Tree x) with hr0def - set num := (evTree x : Int) + int256 (todTree x) with hnumdef - set den := (evTree x : Int) - int256 (todTree x) with hdendef - set NE := evalPoly ExpCertV.numExpV (int256 (tTree x)) with hNEdef - set DE := evalPoly ExpCertV.denExpV (int256 (tTree x)) with hDEdef - have hDEpos : (0 : Int) < DE := by - have h : (2:Int)^1317 > 0 := by positivity - linarith [hdenExpV_lb, h] - have hr0pos : 0 ≤ r0 := by linarith [hr0lo] - have hr0lt : r0 < 2 ^ 128 := hr0hi - have hp1193 : (0 : Int) < 2 ^ 1193 := by positivity - -- DE bounds vs den·2^1193: DE - 7·2^1193 < den·2^1193 ≤ DE + 2·2^1193 - have hden2_lo : 2 ^ 1193 * den ≤ DE + 2 * 2 ^ 1193 := by linarith [hdenlo] - have hden2_hi : DE - 7 * 2 ^ 1193 < 2 ^ 1193 * den := by linarith [hdenhi] - -- NE bounds: num·2^1193 - 4·2^1193 ≤ NE < num·2^1193 + 5·2^1193 - have hnum2_lo : 2 ^ 1193 * num - 4 * 2 ^ 1193 ≤ NE := by linarith [hnumlo] - have hnum2_hi : NE < 2 ^ 1193 * num + 5 * 2 ^ 1193 := hnumhi - -- loss budgets dominated by 150·DE / 700·DE (DE > 2^1317, r0 < 2^128) - have hr0_loss : 7 * 2 ^ 1193 * r0 + 4 * 2 ^ 126 * 2 ^ 1193 < 150 * DE := by - have h1 : (7 : Int) * 2 ^ 1193 * r0 < 7 * 2 ^ 1193 * 2 ^ 128 := by - have := mul_lt_mul_of_pos_left hr0lt (by positivity : (0:Int) < 7 * 2 ^ 1193) - nlinarith [this] - have hb : (7 : Int) * 2 ^ 1193 * 2 ^ 128 + 4 * 2 ^ 126 * 2 ^ 1193 < 150 * 2 ^ 1317 := by - rw [show (7:Int) * 2 ^ 1193 * 2 ^ 128 = 7 * 2 ^ 1321 from by rw [mul_assoc, ← pow_add], - show (4:Int) * 2 ^ 126 * 2 ^ 1193 = 4 * 2 ^ 1319 from by rw [mul_assoc, ← pow_add], - show (1321:Nat) = 4 + 1317 from rfl, show (1319:Nat) = 2 + 1317 from rfl, pow_add, pow_add] - ring_nf; nlinarith [pow_pos (by norm_num : (0:Int)<2) 1317] - linarith [h1, hb, mul_lt_mul_of_pos_left hdenExpV_lb (by norm_num : (0:Int) < 150)] - have hunder_loss : 5 * 2 ^ 126 * 2 ^ 1193 + 2 * 2 ^ 1193 * (r0 + 1) < 700 * DE := by - have h1 : 2 * 2 ^ 1193 * (r0 + 1) < 2 * 2 ^ 1193 * (2 ^ 128 + 1) := by - apply mul_lt_mul_of_pos_left (by linarith [hr0lt]); positivity - have hr0p1 : (2 : Int) * 2 ^ 1193 * (2 ^ 128 + 1) < 3 * 2 ^ 1321 := by - rw [show (1321:Nat) = 4 + 1317 from rfl, pow_add]; ring_nf - nlinarith [pow_pos (by norm_num : (0:Int)<2) 1193, pow_pos (by norm_num : (0:Int)<2) 1317] - have h35 : (5 : Int) * 2 ^ 126 * 2 ^ 1193 = 5 * 2 ^ 1319 := by rw [mul_assoc, ← pow_add] - have hbound : (5 : Int) * 2 ^ 1319 + 3 * 2 ^ 1321 < 700 * 2 ^ 1317 := by - rw [show (1319:Nat) = 2 + 1317 from rfl, show (1321:Nat) = 4 + 1317 from rfl, pow_add, pow_add] - ring_nf; nlinarith [pow_pos (by norm_num : (0:Int)<2) 1317] - rw [h35] - linarith [h1, hr0p1, hbound, mul_lt_mul_of_pos_left hdenExpV_lb (by norm_num : (0:Int) < 700)] - have hfl_lo := mul_le_mul_of_nonneg_left hfloor_lo (by positivity : (0:Int) ≤ 2 ^ 1193) - have hfl_hi := mul_lt_mul_of_pos_left hfloor_hi hp1193 - have hnumstep := mul_le_mul_of_nonneg_left hnum2_lo (by positivity : (0:Int) ≤ 2 ^ 126) - have hNEstep := mul_lt_mul_of_pos_left hnum2_hi (by positivity : (0:Int) < 2 ^ 126) - have hr0den_lo := mul_le_mul_of_nonneg_left (le_of_lt hden2_hi) hr0pos - have hr0den_hi := mul_le_mul_of_nonneg_left hden2_lo (by linarith [hr0pos] : (0:Int) ≤ r0 + 1) - constructor - · nlinarith [hfl_lo, hnumstep, hr0den_lo, hr0_loss, hDEpos, hp1193] - · nlinarith [hfl_hi, hNEstep, hr0den_hi, hunder_loss, hDEpos, hp1193] - -/-! ## The octave real identity `E·2^(126−k) = WAD·2¹²⁶·exp(rt)` - -The target `E = WAD·exp(X/RAY)`. With `rt = X/RAY − k·ln2` the reduced argument, `exp(X/RAY) = -exp(rt)·2^k`, so the closing-shift fold `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`. This collapses the -never-over/deficit inequalities (stated against `E·2^s`, `s = 126 − k`) onto the clean -octave-independent relation `r0 ≈ 2¹²⁶·exp(rt)`. -/ - -open ExpRealSpec Real Common.RealExpBridge - -/-- `exp(X/RAY) = exp(rt)·2^k` (`k = int256 (kTree x)`, possibly negative; `2^k` is a real `zpow`). -/ -theorem exp_X_over_RAY (x : Nat) : - Real.exp ((int256 x : Real) / (10 ^ 27 : Real)) = - Real.exp (reducedArg x) * (2 : Real) ^ (int256 (kTree x)) := by - have hlog : Real.exp ((int256 (kTree x) : Real) * Real.log 2) = (2 : Real) ^ (int256 (kTree x)) := by - rw [← Real.rpow_intCast 2 (int256 (kTree x)), - Real.rpow_def_of_pos (by norm_num : (0:Real) < 2), mul_comm] - rw [show (int256 x : Real) / (10 ^ 27 : Real) = - reducedArg x + (int256 (kTree x) : Real) * Real.log 2 from by - unfold reducedArg; ring, - Real.exp_add, hlog] - -/-- **The octave fold of the target.** `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`, with `s = 126 − k` the -closing shift. -/ -theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 126 - int256 (kTree x)) : - expRayToWadTarget (int256 x) * (2 ^ s : Real) = - (WAD : Real) * (2 ^ 126 : Real) * Real.exp (reducedArg x) := by - unfold expRayToWadTarget - rw [show (RAY : Real) = (10 ^ 27 : Real) from by unfold RAY; norm_num, exp_X_over_RAY x] - -- 2^k · 2^s = 2^126 with k+s = 126 (k : Int, s : Nat). - set k := int256 (kTree x) with hkdef - have hks : k + (s : Int) = 126 := by omega - have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (126 : Nat) := by - rw [show ((2 : Real) ^ (s : Nat)) = (2 : Real) ^ (s : Int) from by - rw [zpow_natCast], ← zpow_add₀ (by norm_num : (2:Real) ≠ 0), hks] - norm_num - rw [show ((2 ^ s : Real)) = (2 : Real) ^ (s : Nat) from by norm_num] - calc (WAD : Real) * (Real.exp (reducedArg x) * (2 : Real) ^ k) * (2 : Real) ^ (s : Nat) - = (WAD : Real) * ((2 : Real) ^ k * (2 : Real) ^ (s : Nat)) * Real.exp (reducedArg x) := by ring - _ = (WAD : Real) * (2 ^ 126 : Real) * Real.exp (reducedArg x) := by - rw [hpow] + (htnn : 0 ≤ int256 (tTree x)) : + 2 ^ 638 * ((evTree x : Int) + int256 (todTree x)) ≤ NUMv (vTree x) (int256 (tTree x)) := by + obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 + obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn + unfold NUMv + nlinarith [hEp_lo, htOp_lo] -/-! ## The cert `Real.exp` bounds at the runtime reduced argument (nonnegative half) +/-! ## The cert `Real.exp` bounds at the runtime reduced argument -Instantiating the v-form Taylor caps (`ExpCertV.capExpUp`/`capExpLo`) at `t = int256 (tTree x)` (in -the cert domain `[0, H128]` on the nonnegative half) and pushing through the abstract -`Common.RealExpBridge` yields `Real.exp(t/2¹²⁸)` bracketed by the margin-nudged rational `ê_v = -NE/DE`. Both `NE = evalPoly numExpV t` and `DE = evalPoly denExpV t` are positive on the domain. -/ +Instantiating the v-form Taylor caps (`ExpCertV.capExpUp`/`capExpLo`, `2⁻¹³¹` nudge) at +`t = int256 (tTree x)` and pushing through the abstract `Common.RealExpBridge` brackets +`Real.exp(t/2¹²⁸)` by the margin-nudged rational `ê = NE/DE`. -/ -/-- The numerator/denominator cert-polynomial values are nonnegative / positive on `[0, H128]`. -/ -theorem certNE_nonneg {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : - 0 ≤ evalPoly ExpCertV.numExpV t := ExpCertV.numExpV_nonneg' h1 h2 +open ExpRealSpec Real Common.RealExpBridge Common.Exp -theorem certDE_pos {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : - 1 ≤ evalPoly ExpCertV.denExpV t := ExpCertV.denExpV_ge_one h1 h2 +noncomputable section -/-- **Never-over cert real bound (nonneg half).** `(2¹³⁰−1)·NE / (2¹³⁰·DE) ≤ exp(t/2¹²⁸)`, the -not-two-below cap pushed to `Real.exp`. -/ +/-- **Never-over cert real bound (nonneg half).** `(2¹³¹−1)·NE / (2¹³¹·DE) ≤ exp(t/2¹²⁸)`. -/ theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : - ((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ + ((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) := by have hcap := ExpCertV.capExpLo h1 h2 have hwpos : 0 < (evalPoly ExpCertV.wLB t).toNat := by @@ -903,7 +419,6 @@ theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) exact mul_pos (by norm_num) (by have := certDE_pos h1 h2; omega) omega have h := le_exp_of_capLB (q := ExpCertV.Qexp) ExpCertV.Qexp_pos hwpos hcap - -- the cap is on `(t.toNat : Real)/Qexp`; rewrite to `(t:Real)/2^128` have htn : (t.toNat : Int) = t := Int.toNat_of_nonneg h1 have hylb : 0 ≤ evalPoly ExpCertV.yLB t := by rw [ExpCertV.evalYLB]; exact Int.mul_nonneg (by norm_num) (certNE_nonneg h1 h2) @@ -919,25 +434,24 @@ theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) have := htn; exact_mod_cast this exact this rw [harg] at h - -- rewrite yLB/wLB to (2^130-1)·NE / (2^130·DE) - have hynr : ((evalPoly ExpCertV.yLB t).toNat : Real) = ((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by - have : ((evalPoly ExpCertV.yLB t).toNat : Int) = (2 ^ 130 - 1) * evalPoly ExpCertV.numExpV t := by + have hynr : ((evalPoly ExpCertV.yLB t).toNat : Real) = ((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by + have : ((evalPoly ExpCertV.yLB t).toNat : Int) = (2 ^ 131 - 1) * evalPoly ExpCertV.numExpV t := by rw [hyn, ExpCertV.evalYLB] have := congrArg (fun z : Int => (z : Real)) this push_cast at this ⊢; linarith [this] - have hwnr : ((evalPoly ExpCertV.wLB t).toNat : Real) = ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by - have : ((evalPoly ExpCertV.wLB t).toNat : Int) = 2 ^ 130 * evalPoly ExpCertV.denExpV t := by + have hwnr : ((evalPoly ExpCertV.wLB t).toNat : Real) = ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by + have : ((evalPoly ExpCertV.wLB t).toNat : Int) = 2 ^ 131 * evalPoly ExpCertV.denExpV t := by rw [hwn, ExpCertV.evalWLB] have := congrArg (fun z : Int => (z : Real)) this push_cast at this ⊢; linarith [this] rw [hynr, hwnr] at h exact h -/-- **Not-two-below cert real bound (nonneg half).** `exp(t/2¹²⁸) ≤ (2¹³⁰+1)·NE / (2¹³⁰·DE)`. -/ +/-- **Not-two-below cert real bound (nonneg half).** `exp(t/2¹²⁸) ≤ (2¹³¹+1)·NE / (2¹³¹·DE)`. -/ theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ - ((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + ((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by have hcap := ExpCertV.capExpUp h1 h2 have hwpos : 0 < (evalPoly ExpCertV.wUB t).toNat := by have hpos : 0 < evalPoly ExpCertV.wUB t := by @@ -960,59 +474,25 @@ theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) have := htn; exact_mod_cast this exact this rw [harg] at h - have hynr : ((evalPoly ExpCertV.yUB t).toNat : Real) = ((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by - have : ((evalPoly ExpCertV.yUB t).toNat : Int) = (2 ^ 130 + 1) * evalPoly ExpCertV.numExpV t := by + have hynr : ((evalPoly ExpCertV.yUB t).toNat : Real) = ((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by + have : ((evalPoly ExpCertV.yUB t).toNat : Int) = (2 ^ 131 + 1) * evalPoly ExpCertV.numExpV t := by rw [hyn, ExpCertV.evalYUB] have := congrArg (fun z : Int => (z : Real)) this push_cast at this ⊢; linarith [this] - have hwnr : ((evalPoly ExpCertV.wUB t).toNat : Real) = ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by - have : ((evalPoly ExpCertV.wUB t).toNat : Int) = 2 ^ 130 * evalPoly ExpCertV.denExpV t := by + have hwnr : ((evalPoly ExpCertV.wUB t).toNat : Real) = ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by + have : ((evalPoly ExpCertV.wUB t).toNat : Int) = 2 ^ 131 * evalPoly ExpCertV.denExpV t := by rw [hwn, ExpCertV.evalWUB] have := congrArg (fun z : Int => (z : Real)) this push_cast at this ⊢; linarith [this] rw [hynr, hwnr] at h exact h -/-! ## The cert `Real.exp` bounds at a negative reduced argument (via the reciprocal symmetry) - -For `t ≤ 0` (with `−t ∈ [0, H128]`) the cert at `u = −t`, composed with `numExpV(−t) = denExpV(t)`, -`denExpV(−t) = numExpV(t)` and `exp(−s) = 1/exp(s)`, brackets `exp(t/2¹²⁸)` against the same -margin-nudged rational `NE(t)/DE(t)` — the over side needs `NE/DE ≤ exp·(2¹³⁰+1)/2¹³⁰`, the under -side `exp ≤ (NE/DE)·2¹³⁰/(2¹³⁰−1)`. The cert denominators `NE(t)`, `DE(t)` are positive. -/ - -/-- For `t ≤ 0` with `−t ∈ [0, H128]` the cert numerator/denominator at `t` are positive. -/ -theorem certNE_pos_neg_aux {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : - 0 < evalPoly ExpCertV.numExpV t ∧ 0 < evalPoly ExpCertV.denExpV t := by - have hnt : 0 ≤ -t := by omega - -- numExpV(t) = denExpV(-t) ≥ 1 > 0 - have h1' : evalPoly ExpCertV.numExpV t = evalPoly ExpCertV.denExpV (-t) := by - have := numExpV_neg_eq_denExpV (-t); rwa [neg_neg] at this - have hde : 1 ≤ evalPoly ExpCertV.denExpV (-t) := ExpCertV.denExpV_ge_one hnt h2 - -- denExpV(t) = evNumVPoly(t) − todNumV(t); for t ≤ 0, todNumV(t) ≤ 0, and evNumVPoly(t) ≥ 1 - have htod_np : evalPoly ExpCertV.todNumV t ≤ 0 := by - rw [evalTodNumV] - have hodnn := odNumVPoly_nonneg t - have : t * evalPoly ExpCertV.odNumVPoly t ≤ 0 := mul_nonpos_of_nonpos_of_nonneg h1 hodnn - nlinarith [this] - have hev1 : 1 ≤ evalPoly ExpCertV.evNumVPoly t := by - -- evNumVPoly(t) = evNumVPoly(-t) (even) ≥ denExpV(-t) ≥ 1 (todNumV(-t) ≥ 0) - have heven : evalPoly ExpCertV.evNumVPoly t = evalPoly ExpCertV.evNumVPoly (-t) := by - rw [← evNumVPoly_even (-t), neg_neg] - have htodnt : 0 ≤ evalPoly ExpCertV.todNumV (-t) := by - rw [evalTodNumV] - exact Int.mul_nonneg (by positivity) (Int.mul_nonneg hnt (odNumVPoly_nonneg (-t))) - have hde' := hde - rw [evalDenExpV] at hde' - rw [heven]; linarith [hde', htodnt] - refine ⟨by rw [h1']; omega, ?_⟩ - rw [evalDenExpV]; linarith [hev1, htod_np] - -/-- **Never-too-below cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: -`exp(t/2¹²⁸) ≤ (2¹³⁰·NE) / ((2¹³⁰−1)·DE)`. -/ +/-- **Not-too-below cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: +`exp(t/2¹²⁸) ≤ (2¹³¹·NE) / ((2¹³¹−1)·DE)`. -/ theorem certUp_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ - ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by have hnt : 0 ≤ -t := by omega have hcl := certLo_real hnt h2 rw [numExpV_neg_eq_denExpV, denExpV_neg_eq_numExpV] at hcl @@ -1025,21 +505,21 @@ theorem certUp_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : push_cast; ring, Real.exp_neg] rw [hexpneg] at hcl have hexppos := Real.exp_pos ((t : Real) / (2 ^ 128 : Real)) - have hlhs_pos : (0:Real) < ((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / - (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity + have hlhs_pos : (0:Real) < ((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity rw [le_inv_comm₀ hlhs_pos hexppos] at hcl calc Real.exp ((t : Real) / (2 ^ 128 : Real)) - ≤ (((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / - (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := hcl - _ = ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 130 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + ≤ (((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := hcl + _ = ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by rw [inv_div] /-- **Never-over cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: -`(2¹³⁰·NE) / ((2¹³⁰+1)·DE) ≤ exp(t/2¹²⁸)`. -/ +`(2¹³¹·NE) / ((2¹³¹+1)·DE) ≤ exp(t/2¹²⁸)`. -/ theorem certLo_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : - ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ + ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) := by have hnt : 0 ≤ -t := by omega have hcu := certUp_real hnt h2 @@ -1053,16 +533,27 @@ theorem certLo_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : push_cast; ring, Real.exp_neg] rw [hexpneg] at hcu have hexppos := Real.exp_pos ((t : Real) / (2 ^ 128 : Real)) - have hrhs_pos : (0:Real) < ((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / - (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity + have hrhs_pos : (0:Real) < ((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity rw [inv_le_comm₀ hexppos hrhs_pos] at hcu - calc ((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) - = (((2 ^ 130 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / - (((2 ^ 130 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := by + calc ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) + = (((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := by rw [inv_div] _ ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) := hcu +/-- `t/2¹²⁸ ≤ 0` gives the cert domain `−t ≤ H128` for the negative half. -/ +theorem tdom_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : (-(int256 (tTree x))) ≤ (ExpCertV.H128 : Int) := by + obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + omega + +/-! ## Analytic helpers on the reduced argument -/ + /-- On the nonnegative half of the region the reduced argument is below `ln2/2`: `t/2¹²⁸ ≤ log 2 / 2`. -/ theorem t_over_2128_le_half_log2 {x : Nat} (hx : x < 2 ^ 256) @@ -1070,18 +561,13 @@ theorem t_over_2128_le_half_log2 {x : Nat} (hx : x < 2 ^ 256) (htnn : 0 ≤ int256 (tTree x)) : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ Real.log 2 / 2 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - -- t ≤ H128 ≤ ⌊ln2/2·2^128⌋, and LN2/2^235 ≤ ln2 gives H128/2^128 ≤ ln2/2 have hln2lo := ln2_lower rw [LN2c_eq] at hln2lo - -- LN2/2^235 ≤ log 2. H128 = 117932881612756647068972071382077242199. - -- t/2^128 ≤ H128/2^128. need H128/2^128 ≤ log2/2. Use 2·H128/2^128 ≤ 2·(ln2/2) = ln2. have htR : (int256 (tTree x) : Real) ≤ (117932881612756647068972071382077242199 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hthi; push_cast at this; linarith [this] have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity rw [div_le_div_iff₀ hp128 (by norm_num : (0:Real) < 2)] - -- t·2 ≤ log2·2^128. Have t ≤ H128, and 2·H128 ≤ log2·2^128 (from LN2 bound). have hkey : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := by - -- log2 ≥ LN2/2^235 ⟹ log2·2^128 ≥ LN2·2^128/2^235 = LN2/2^107. Check 2·H128 ≤ LN2/2^107. have h1 : (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := by apply mul_le_mul_of_nonneg_right hln2lo (by positivity) have h2 : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ @@ -1091,47 +577,16 @@ theorem t_over_2128_le_half_log2 {x : Nat} (hx : x < 2 ^ 256) linarith [h1, h2] nlinarith [htR, hkey] -/-- The reduced exponential is below `√2 < 2` (loose). -/ -theorem exp_reducedArg_le_two {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - Real.exp (reducedArg x) ≤ 2 := by - -- |rt| ≤ ln2/2 + tiny ⟹ rt < log2 ⟹ exp(rt) < exp(log2) = 2; we prove ≤ 2 generously. - obtain ⟨htlo, hthi⟩ := tTree_in_cert_domain hx hC hC0 - have hclose := reducedArg_close hx hC hC0 - have habs := abs_lt.mp hclose - -- rt < t/2^128 + 9/(8·2^128) ≤ H128/2^128 + 1 < log2 (very loose: H128/2^128 < 0.347) - have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity - have htR : (int256 (tTree x) : Real) ≤ (117932881612756647068972071382077242199 : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hthi; push_cast at this; linarith [this] - have hln2 : (0.6931471805 : Real) ≤ Real.log 2 := by - have := ln2_lower; rw [LN2c_eq] at this - have h2 : (0.6931471805 : Real) ≤ (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) := by - rw [le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)]; norm_num - linarith [this, h2] - have hrtlt : reducedArg x ≤ Real.log 2 := by - have h9 : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 1 := by - rw [div_le_one (by positivity)]; norm_num - have htdiv : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ 0.35 := by - rw [div_le_iff₀ hp128]; nlinarith [htR] - -- rt < t/2^128 + 9/(8·2^128) ≤ 0.35 + 1 ... too loose vs log2 ≈ 0.693. tighten 9/8 bound. - have h9' : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 0.34 := by - rw [div_le_iff₀ (by positivity)]; norm_num - linarith [habs.2, htdiv, h9', hln2] - calc Real.exp (reducedArg x) ≤ Real.exp (Real.log 2) := Real.exp_le_exp.mpr hrtlt - _ = 2 := Real.exp_log (by norm_num) - -/-- `exp(t/2¹²⁸) ≤ 2` (loose). -/ -theorem exp_t_le_two {x : Nat} (hx : x < 2 ^ 256) +/-- `exp(t/2¹²⁸) ≤ √2` on the nonneg half. -/ +theorem exp_t_le_sqrt2 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) ≤ 2 := by + Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) ≤ Real.sqrt 2 := by have hle := t_over_2128_le_half_log2 hx hC hC0 htnn - have hhalf : Real.log 2 / 2 ≤ Real.log 2 := by - have : (0:Real) ≤ Real.log 2 := by rw [Real.le_log_iff_exp_le (by norm_num)]; simp [Real.exp_zero] - linarith calc Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) - ≤ Real.exp (Real.log 2) := Real.exp_le_exp.mpr (le_trans hle hhalf) - _ = 2 := Real.exp_log (by norm_num) + ≤ Real.exp (Real.log 2 / 2) := Real.exp_le_exp.mpr hle + _ = Real.sqrt 2 := by + rw [Real.sqrt_eq_rpow, Real.rpow_def_of_pos (by norm_num : (0:Real) < 2)]; ring_nf /-- The convexity bound `exp(b) − exp(a) ≤ (b−a)·exp(b)`. -/ theorem exp_diff_le (a b : Real) : Real.exp b - Real.exp a ≤ (b - a) * Real.exp b := by @@ -1140,239 +595,306 @@ theorem exp_diff_le (a b : Real) : Real.exp b - Real.exp a ≤ (b - a) * Real.ex have hb : 0 < Real.exp b := Real.exp_pos b rw [key]; nlinarith [h1, hb] -/-! ## The tight joint per-point never-over (nonnegative half) -/ +/-- The reduced argument is above `−log 2` on the region, so `exp(rt) > 1/2`. -/ +theorem exp_reducedArg_gt_half {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (1 : Real) / 2 < Real.exp (reducedArg x) := by + obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 + have hclose := abs_lt.mp (reducedArg_close hx hC hC0) + have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity + have htR : -(117932881612756647068972071382077242199 : Real) ≤ (int256 (tTree x) : Real) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo; push_cast at this; linarith [this] + have hln2 : (0.6931471805 : Real) ≤ Real.log 2 := by + have := ln2_lower; rw [LN2c_eq] at this + have h2 : (0.6931471805 : Real) ≤ + (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) := by + rw [le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)]; norm_num + linarith [this, h2] + have htdiv : -(0.35 : Real) ≤ (int256 (tTree x) : Real) / (2 ^ 128 : Real) := by + rw [le_div_iff₀ hp128]; nlinarith [htR] + have h9 : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 0.34 := by + rw [div_le_iff₀ (by positivity)]; norm_num + have hrt : -(Real.log 2) < reducedArg x := by linarith [hclose.1, htdiv, h9, hln2] + have : Real.exp (-(Real.log 2)) < Real.exp (reducedArg x) := Real.exp_lt_exp.mpr hrt + rwa [Real.exp_neg, Real.exp_log (by norm_num : (0:Real) < 2), show (2:Real)⁻¹ = 1/2 from by norm_num] at this --- exp(t/2^128) ≤ √2 on the nonneg half. -theorem exp_t_le_sqrt2 {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) ≤ Real.sqrt 2 := by - have hle := t_over_2128_le_half_log2 hx hC hC0 htnn - calc Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) - ≤ Real.exp (Real.log 2 / 2) := Real.exp_le_exp.mpr hle - _ = Real.sqrt 2 := by - rw [Real.sqrt_eq_rpow, Real.rpow_def_of_pos (by norm_num : (0:Real) < 2)]; ring_nf +/-! ## The `r0 ≤ 1.4146·2¹²⁶` cap and the runtime numerator ceiling --- den ≥ A4 − 2^125 (≈ 0.72·2^126): den = ev − tod, ev ≥ A4, tod < 2^125. -theorem den_ge_072 {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (61251667550081741634933722430035858604 : Int) ≤ - (evTree x : Int) - int256 (todTree x) := by - obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 - have hev : (103786963415199049567855548359006885036 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo - have ht125 : int256 (todTree x) < 2 ^ 125 := by - rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num]; exact htod_hi - rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 - omega +The grid rational is capped through links 2–3: `ê(v) ≤ ê(t²) + grain ≤ √2·Mp + grain ≤ 14145/10⁴`. +Pulling that back through the truncation brackets caps the runtime numerator +(`10⁴·num ≤ 14145·den + 28290`, hence `100·num ≤ 145·den`) and the quotient +(`10⁴·(r0 − 2¹²⁶) ≤ 4146·2¹²⁶`). -/ -/-- **The joint per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` — within -the `MARGIN/WAD ≈ 0.72014341` budget. Combines the joint cert-ratio over (the shared even truncation -cancels via the floor), `exp(t/2¹²⁸) ≤ √2`, `den ≥ 0.72·2¹²⁶`, and the tight one-sided gap-1. The -three contributions are bounded at their suprema: the Horner/`sdiv` truncation jitter -(`≤ 6207065162659510332/10¹⁹`, the dominant ≈0.62 term), the rational `Mp` factor -(`≤ 883883476483184406/10¹⁹`, `√2`-driven via `hsqrt2_hi`), and the reduced-argument gap -(`≤ 110485434560398051/10¹⁹`, likewise). -/ -theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) +/-- The grid rational is below `14145/10000` on the nonneg half. -/ +theorem Qv_le_14145 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by + (NUMv (vTree x) (int256 (tTree x)) : Real) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ + 14145 / 10000 := by + obtain ⟨_, hgran⟩ := gran_over_pair hx hC hC0 htnn obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 set t := int256 (tTree x) with htdef have htdom : t ≤ (ExpCertV.H128 : Int) := by rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by unfold ExpCertV.H128; norm_num] exact hthi - have hDElb := denExpV_lb hx hC hC0 htnn - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - have hNEnn : (0 : Real) ≤ (NE : Real) := by + have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom + have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by + have : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE + exact_mod_cast this + have hNEnn : (0:Real) ≤ (evalPoly ExpCertV.numExpV t : Real) := by have := certNE_nonneg htnn htdom; exact_mod_cast this - set r0 := int256 (r0Tree x) with hr0def - -- certLo: NE/DE ≤ Et·Mp, Mp = 2^130/(2^130−1); Et = exp(t/2^128) ≤ √2. - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + -- NE/DE ≤ Et·Mp ≤ √2·(2^131/(2^131−1)) ≤ 14144/10000 have hcertlo := certLo_real htnn htdom - set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn rw [← hEtdef] at hEtsqrt2 - have hEtnn : (0 : Real) ≤ Et := le_of_lt (Real.exp_pos _) - have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by - have hc : ((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo - rw [hMpdef] - have key : (NE : Real) / (DE : Real) = - ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) * - (((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real))) := by + have hNEDE_le : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ + Et * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) := by + have hc : ((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ Et := hcertlo + have key : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) = + ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * + (((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real))) := by push_cast; field_simp; ring - rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) - -- r0 ≤ 2^126·num/den (floor) - obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hnumlo, _⟩ := numExpV_bracket hx hC hC0 htnn - obtain ⟨_, hdenhi⟩ := denExpV_bracket hx hC hC0 htnn - set num := (evTree x : Int) + int256 (todTree x) with hnumdef - set den := (evTree x : Int) - int256 (todTree x) with hdendef - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ den := den_ge_072 hx hC hC0 - have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden072 - have hdenR : (0:Real) < (den : Real) := by exact_mod_cast hdenpos - have hden072R : (61251667550081741634933722430035858604 : Real) ≤ (den : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hden072; push_cast at this; linarith [this] - have hr0_le_numden : (r0 : Real) ≤ (2 ^ 126 : Real) * (num : Real) / (den : Real) := by - rw [le_div_iff₀ hdenR] - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hfloor_lo; push_cast at this; nlinarith [this] - -- bound num: 2^1193·num ≤ NE ≤ Et·Mp·DE ≤ √2·Mp·DE; DE < 2^1193·den + 3·2^1193 (denExpV hi) - have hnumloR : (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hnumlo; push_cast at this; linarith [this] - have hdenhiR : (DE : Real) < (2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193 := by - have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hdenhi; push_cast at this; linarith [this] - have hMp_pos : (0:Real) < Mp := by rw [hMpdef]; positivity - -- NE ≤ √2·Mp·DE - have hNE_le : (NE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by - have h1 : (NE : Real) ≤ Et * Mp * (DE : Real) := by - have := mul_le_mul_of_nonneg_right hNEDE_le (le_of_lt hDEpos) - rwa [div_mul_cancel₀ _ (ne_of_gt hDEpos)] at this - have h2 : Et * Mp * (DE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by - apply mul_le_mul_of_nonneg_right _ (le_of_lt hDEpos) - exact mul_le_mul_of_nonneg_right hEtsqrt2 (le_of_lt hMp_pos) - linarith [h1, h2] - -- num ≤ √2·Mp·(den + 3) - have hnum_le : (num : Real) ≤ Real.sqrt 2 * Mp * ((den : Real) + 3) := by - have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity - rw [← mul_le_mul_left hp] - calc (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := hnumloR - _ ≤ Real.sqrt 2 * Mp * (DE : Real) := hNE_le - _ ≤ Real.sqrt 2 * Mp * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := by - apply mul_le_mul_of_nonneg_left (le_of_lt hdenhiR) - rw [hMpdef]; positivity - _ = (2 ^ 1193 : Real) * (Real.sqrt 2 * Mp * ((den : Real) + 3)) := by ring - -- √2 ≤ 14143/10000 (since (14143/10000)² > 2); the coarse bound feeds the `den ≥ 0.72` / - -- `√2·Mp ≤ 14144/10000` step. A high-precision companion bound (its square also exceeds 2) drives - -- the gap-1 and `Mp`-factor terms down to their irrational suprema, so their ceilings carry no - -- avoidable slack. + rw [key, mul_comm Et _] + exact mul_le_mul_of_nonneg_left hc (by positivity) have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num - have hsqrt2_hi : Real.sqrt 2 ≤ 141421356237309504880168872421 / 100000000000000000000000000000 := by - rw [Real.sqrt_le_iff]; constructor <;> norm_num - have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ - -- Mp ≤ 14143/10000 ⁻¹ ... we need √2·Mp ≤ 14144/10000 (a hair above √2; Mp = 1 + 1/(2^130−1)) - have hMp_le : Mp ≤ 14144 / 14143 := by - rw [hMpdef, div_le_div_iff₀ (by norm_num) (by norm_num)] - have h130 : (14144 : Real) ≤ 2 ^ 130 := by - rw [show (2:Real) ^ 130 = 1361129467683753853853498429727072845824 from by norm_num]; norm_num - nlinarith [h130] - -- √2·Mp ≤ 14144/10000 - have hsM_le : Real.sqrt 2 * Mp ≤ 14144 / 10000 := by - have hMpnn : (0:Real) ≤ Mp := by rw [hMpdef]; positivity - calc Real.sqrt 2 * Mp ≤ (14143 / 10000) * (14144 / 14143) := - mul_le_mul hsqrt2_val hMp_le hMpnn (by norm_num) - _ = 14144 / 10000 := by norm_num - -- (r0 − 2^126)·den ≤ 2^126·(num − den) ≤ 2^126·(√2·Mp·(den+3) − den) ≤ 2^126·(4145/10000)·den - have hr0_den : ((r0 : Real) - 2 ^ 126) * (den : Real) ≤ (2 ^ 126 : Real) * (4145 / 10000) * (den : Real) := by - -- floor (Real): r0·den ≤ 2^126·num - have hfl : (r0 : Real) * (den : Real) ≤ (2 ^ 126 : Real) * (num : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hfloor_lo; push_cast at this; linarith [this] - -- num ≤ √2·Mp·(den+3) ≤ (14144/10000)·(den+3) - have hnum2 : (num : Real) ≤ (14144 / 10000) * ((den : Real) + 3) := by - have hpos : (0:Real) ≤ (den : Real) + 3 := by linarith [hden072R] - calc (num : Real) ≤ Real.sqrt 2 * Mp * ((den : Real) + 3) := hnum_le - _ ≤ (14144 / 10000) * ((den : Real) + 3) := mul_le_mul_of_nonneg_right hsM_le hpos - -- (r0−2^126)·den = r0·den − 2^126·den ≤ 2^126·num − 2^126·den - have hstep1 : ((r0 : Real) - 2 ^ 126) * (den : Real) ≤ (2 ^ 126 : Real) * (num : Real) - 2 ^ 126 * (den : Real) := by - nlinarith [hfl] - -- 2^126·num ≤ 2^126·(14144/10000)·(den+3) (scale hnum2 by 2^126 > 0) - have hstep2 : (2 ^ 126 : Real) * (num : Real) ≤ (2 ^ 126 : Real) * ((14144 / 10000) * ((den : Real) + 3)) := - mul_le_mul_of_nonneg_left hnum2 (by positivity) - -- 2^126·(14144/10000·(den+3)) − 2^126·den ≤ 2^126·(4145/10000)·den ⟺ 42432 ≤ den (from den ≥ 0.72·2^126) - have hden42432 : (42432 : Real) ≤ (den : Real) := by - have h : (42432 : Real) ≤ 61251667550081741634933722430035858604 := by norm_num - linarith [hden072R, h] - nlinarith [hstep1, hstep2, hden42432, mul_pos (by norm_num : (0:Real) < 2^126) hdenR] - have hr0m_bound : (r0 : Real) - 2 ^ 126 ≤ (2 ^ 126 : Real) * 4145 / 10000 := by - have hkey : ((r0 : Real) - 2 ^ 126) * (den : Real) ≤ ((2 ^ 126 : Real) * 4145 / 10000) * (den : Real) := by - have : (2 ^ 126 : Real) * (4145 / 10000) * (den : Real) = ((2 ^ 126 : Real) * 4145 / 10000) * (den : Real) := by ring - linarith [hr0_den, this ▸ hr0_den] - exact le_of_mul_le_mul_right hkey hdenR - -- DE ≥ 2^1193·den − 32·2^1193 (denExpV lo bracket) - obtain ⟨hdenlo, _⟩ := denExpV_bracket hx hC hC0 htnn - have hDElo32 : (2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193 ≤ (DE : Real) := by - have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hdenlo - push_cast at h - rw [hdendef, hDEdef]; push_cast; linarith [h] - -- cR term: W_ev·(r0−2^126)/DE ≤ 64/100 (provable ≈ 0.62) - have hr0m_nn : (0:Real) ≤ (r0 : Real) - 2 ^ 126 ∨ (r0 : Real) - 2 ^ 126 < 0 := le_or_gt _ _ |>.imp_left id - have hcR : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) ≤ 6207065162659510332 / 10000000000000000000 := by - rcases le_or_gt ((r0:Real) - 2^126) 0 with hle0 | hgt0 - · -- numerator ≤ 0, so the fraction ≤ 0 ≤ 621/1000 - have hnumneg : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) ≤ 0 := - mul_nonpos_of_nonneg_of_nonpos (by positivity) hle0 - have : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) ≤ 0 := - div_nonpos_of_nonpos_of_nonneg hnumneg (le_of_lt hDEpos) - linarith [this] - · -- 0 < r0−2^126 ≤ 2^126·4145/10000; DE ≥ 2^1193(den−32) > 0 with den ≥ 0.72·2^126 - rw [div_le_iff₀ hDEpos] - -- W_ev·(r0−2^126) ≤ (621/1000)·DE. W_ev = 1130577·2^1173. use DE ≥ 2^1193(den−32). - have hnum_le : (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) ≤ - 1130577 * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) := - mul_le_mul_of_nonneg_left hr0m_bound (by positivity) - -- (621/1000)·DE ≥ (621/1000)·2^1193·(den−32); need W_ev·2^126·4145/10000 ≤ (621/1000)·2^1193·(den−32) - have hbudget : (1130577 : Real) * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) ≤ - (6207065162659510332 / 10000000000000000000) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) := by - -- both sides are (·)·2^1193. LHS = (1130577·4145/10000·2^106)·2^1193; RHS = (621/1000·(den−32))·2^1193 - have hLHS : (1130577 : Real) * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) = - (1130577 * 4145 / 10000 * 2 ^ 106) * 2 ^ 1193 := by - have e1 : (2:Real) ^ 1173 * 2 ^ 126 = 2 ^ 106 * 2 ^ 1193 := by - rw [← pow_add, ← pow_add] - linear_combination (1130577 * 4145 / 10000) * e1 - have hRHS : (6207065162659510332 / 10000000000000000000 : Real) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) = - (6207065162659510332 / 10000000000000000000 * ((den : Real) - 32)) * 2 ^ 1193 := by ring - rw [hLHS, hRHS] - have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity - rw [mul_le_mul_right hp] - have h106 : (1130577 * 4145 / 10000 * 2 ^ 106 : Real) ≤ - 6207065162659510332 / 10000000000000000000 * (61251667550081741634933722430035858604 - 32) := by - rw [show (2:Real) ^ 106 = 81129638414606681695789005144064 from by norm_num]; norm_num - nlinarith [h106, hden072R] - calc (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) - ≤ 1130577 * 2 ^ 1173 * ((2 ^ 126 : Real) * 4145 / 10000) := hnum_le - _ ≤ (6207065162659510332 / 10000000000000000000) * ((2 ^ 1193 : Real) * (den : Real) - 32 * 2 ^ 1193) := hbudget - _ ≤ (6207065162659510332 / 10000000000000000000) * (DE : Real) := mul_le_mul_of_nonneg_left hDElo32 (by norm_num) - -- r0 ≤ 2^126·NE/DE + 621/1000 (case-split: small ⟹ r0·DE ≤ 2^126·NE; big ⟹ joint + hcR) - have hr0_div : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 6207065162659510332 / 10000000000000000000 := by + have hMp_le : ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) ≤ 14144 / 14143 := by + rw [div_le_div_iff₀ (by norm_num) (by norm_num)] + have h131 : (14144 : Real) ≤ 2 ^ 131 := by norm_num + nlinarith [h131] + have hNEDE14144 : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ + 14144 / 10000 := by + have hEtnn : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) + have h1 : Et * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) ≤ + (14143 / 10000) * (14144 / 14143) := by + apply mul_le_mul (le_trans hEtsqrt2 hsqrt2_val) hMp_le (by positivity) (by norm_num) + have h2 : (14143 / 10000 : Real) * (14144 / 14143) = 14144 / 10000 := by norm_num + linarith [hNEDE_le, h1, h2 ▸ h1] + -- add the grain: 2^126·Qv ≤ 2^126·(NE/DE) + 0.34 ⟹ Qv ≤ 14144/10000 + 0.34/2^126 ≤ 14145/10000 + have h2126 : (2 ^ 126 : Real) * ((NUMv (vTree x) t : Real) / (DENv (vTree x) t : Real)) ≤ + (2 ^ 126 : Real) * (14144 / 10000) + 3395595387735630095 / 10000000000000000000 := by + have := mul_le_mul_of_nonneg_left hNEDE14144 (by positivity : (0:Real) ≤ (2:Real) ^ 126) + linarith [hgran, this] + have hfin : (2 ^ 126 : Real) * (14144 / 10000) + 3395595387735630095 / 10000000000000000000 ≤ + (2 ^ 126 : Real) * (14145 / 10000) := by norm_num + have hp : (0:Real) < (2 ^ 126 : Real) := by positivity + exact le_of_mul_le_mul_left (le_trans h2126 hfin) hp + +/-- The runtime numerator ceiling: `10⁴·num ≤ 14145·den + 28290`. -/ +theorem num_ceiling {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 10000 * ((evTree x : Int) + int256 (todTree x)) ≤ + 14145 * ((evTree x : Int) - int256 (todTree x)) + 28290 := by + have hQv := Qv_le_14145 hx hC hC0 htnn + obtain ⟨hthi_lo, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have hvle := vTree_le_vmax hx hC hC0 + set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + -- 10000·NUMv ≤ 14145·DENv (from the real cap) + have hNUM_le : 10000 * NUMv v t ≤ 14145 * DENv v t := by + have hR : (NUMv v t : Real) ≤ (14145 / 10000) * (DENv v t : Real) := by + have := mul_le_mul_of_nonneg_right hQv (le_of_lt hDR) + rwa [div_mul_cancel₀ _ (ne_of_gt hDR)] at this + have hR2 : (10000 : Real) * (NUMv v t : Real) ≤ 14145 * (DENv v t : Real) := by + nlinarith [hR] + exact_mod_cast hR2 + -- pull back through the brackets: 2^638·num ≤ NUMv; DENv ≤ 2^638·den + Wev·2^590 + have hNUM_ge := NUMv_ge_num hx hC hC0 htnn + obtain ⟨_, hDEN_le⟩ := DENv_runtime_bracket hx hC hC0 htnn + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + -- 10000·2^638·num ≤ 14145·(2^638·den + Wev·2^590) ≤ 2^638·(14145·den + 28290) + have hchain : 10000 * (2 ^ 638 * num) ≤ 2 ^ 638 * (14145 * den + 28290) := by + have h1 : 10000 * (2 ^ 638 * num) ≤ 10000 * NUMv v t := + mul_le_mul_of_nonneg_left hNUM_ge (by norm_num) + have h2 : 14145 * DENv v t ≤ 14145 * (2 ^ 638 * den + 283678831804417 * 2 ^ 590) := + mul_le_mul_of_nonneg_left hDEN_le (by norm_num) + have h3 : (14145 : Int) * (2 ^ 638 * den + 283678831804417 * 2 ^ 590) ≤ + 2 ^ 638 * (14145 * den + 28290) := by + have hW : (14145 : Int) * (283678831804417 * 2 ^ 590) ≤ 28290 * 2 ^ 638 := by norm_num + nlinarith [hW] + linarith [h1, hNUM_le, h2, h3] + have hp : (0:Int) < 2 ^ 638 := by positivity + have h2 : 2 ^ 638 * (10000 * num) ≤ 2 ^ 638 * (14145 * den + 28290) := by linarith [hchain] + exact le_of_mul_le_mul_left h2 hp + +/-- `100·num ≤ 145·den` (`ê ≤ 1.45`) on the nonneg half. -/ +theorem num_le_145_den {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 100 * ((evTree x : Int) + int256 (todTree x)) ≤ 145 * ((evTree x : Int) - int256 (todTree x)) := by + have hceil := num_ceiling hx hC hC0 htnn + have hden := den_ge_072 hx hC hC0 + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + -- 100·(10000·num) ≤ 100·(14145·den + 28290) ≤ 10000·(145·den) since 355·den ≥ 2829000 + nlinarith [hceil, hden] + +/-- The quotient cap: `10⁴·(r0 − 2¹²⁶) ≤ 4146·2¹²⁶` on the nonneg half. -/ +theorem r0_cap {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + 10000 * (int256 (r0Tree x) - 2 ^ 126) ≤ 4146 * 2 ^ 126 := by + obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 + have hceil := num_ceiling hx hC hC0 htnn + have hden := den_ge_072 hx hC hC0 + set r0 := int256 (r0Tree x) with hr0def + set num := (evTree x : Int) + int256 (todTree x) with hnumdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden + -- 10000·(r0−2^126)·den ≤ 2^126·(10000·num − 10000·den) ≤ 2^126·(4145·den + 28290) ≤ 4146·2^126·den + have h1 : 10000 * (r0 - 2 ^ 126) * den ≤ 2 ^ 126 * (4145 * den + 28290) := by + nlinarith [hfloor_lo, hceil] + have h2 : (2:Int) ^ 126 * (4145 * den + 28290) ≤ 4146 * 2 ^ 126 * den := by + nlinarith [hden] + have hchain : 10000 * (r0 - 2 ^ 126) * den ≤ 4146 * 2 ^ 126 * den := le_trans h1 h2 + exact le_of_mul_le_mul_right hchain hdenpos + +/-! ## The per-point never-over (nonnegative half) -/ + +/-- The link-1 jitter divided by `DENv` stays inside its budget (nonneg half): +`Wev·2⁵⁹⁰·(r0 − 2¹²⁶)/DENv ≤ 6207065162659510332/10¹⁹`. -/ +theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (283678831804417 : Real) * 2 ^ 590 * ((int256 (r0Tree x) : Real) - 2 ^ 126) / + (DENv (vTree x) (int256 (tTree x)) : Real) ≤ + 6207065162659510332 / 10000000000000000000 := by + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have hvle := vTree_le_vmax hx hC hC0 + set r0 := int256 (r0Tree x) with hr0def + set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + rcases le_or_gt ((r0:Real) - 2^126) 0 with hle0 | hgt0 + · have hnumneg : (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ 0 := + mul_nonpos_of_nonneg_of_nonpos (by positivity) hle0 + have : (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) / (DENv v t : Real) ≤ 0 := + div_nonpos_of_nonpos_of_nonneg hnumneg (le_of_lt hDR) + linarith [this] + · rw [div_le_iff₀ hDR] + -- r0 − 2^126 ≤ 4146·2^126/10^4 (r0_cap); DENv ≥ 2^638·(den−2) ≥ 2^638·(den_lo−2) + have hcap := r0_cap hx hC hC0 htnn + have hcapR : (r0 : Real) - 2 ^ 126 ≤ 4146 * 2 ^ 126 / 10000 := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hcap + push_cast at h + linarith [h] + obtain ⟨hDEN_ge, _⟩ := DENv_runtime_bracket hx hC hC0 htnn + have hden := den_ge_072 hx hC hC0 + have hDENlow : (2:Int) ^ 638 * (61251667532612381706986956632087880162 - 2) ≤ DENv v t := by + have : (2:Int) ^ 638 * (61251667532612381706986956632087880162 - 2) ≤ + 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 638 := by + nlinarith [hden] + linarith [this, hDEN_ge] + have hDENlowR : ((2:Real) ^ 638 * (61251667532612381706986956632087880162 - 2)) ≤ + (DENv v t : Real) := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDENlow + push_cast at h + linarith [h] + have hnum_le : (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ + (283678831804417 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := + mul_le_mul_of_nonneg_left hcapR (by positivity) + have hbudget : (283678831804417 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) ≤ + (6207065162659510332 / 10000000000000000000) * + ((2:Real) ^ 638 * (61251667532612381706986956632087880162 - 2)) := by + norm_num + calc (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) + ≤ (283678831804417 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := hnum_le + _ ≤ (6207065162659510332 / 10000000000000000000) * + ((2:Real) ^ 638 * (61251667532612381706986956632087880162 - 2)) := hbudget + _ ≤ (6207065162659510332 / 10000000000000000000) * (DENv v t : Real) := + mul_le_mul_of_nonneg_left hDENlowR (by norm_num) + +/-- **The per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + B` with the four-link budget +`B = 10155087723197130681/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3396…`, the `Mp` +factor `≤ √2·2¹²⁶/(2¹³¹−1) ≤ 0.0442…`, and the reduced-argument gap `≤ √2/128 ≤ 0.0111…`. -/ +theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htnn : 0 ≤ int256 (tTree x)) : + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + + 10155087723197130681 / 10000000000000000000 := by + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have hvle := vTree_le_vmax hx hC hC0 + set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + have htdom : t ≤ (ExpCertV.H128 : Int) := by + rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by + unfold ExpCertV.H128; norm_num] + exact hthi + set r0 := int256 (r0Tree x) with hr0def + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom + have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by + have : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE + exact_mod_cast this + -- link 1: r0 ≤ 2^126·Qv + jitter + have hlink1 : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + 6207065162659510332 / 10000000000000000000 := by rcases le_or_gt r0 (2^126) with hsm | hbg - · -- small: r0·DE ≤ 2^126·NE (r0_certRatio_over_small), so r0 ≤ 2^126·NE/DE ≤ … + 621/1000 - have hi := r0_certRatio_over_small hx hC hC0 htnn hsm - have hiR : (r0 : Real) * (DE : Real) ≤ (2 ^ 126 : Real) * (NE : Real) := by + · have hi := link1_over_small hx hC hC0 htnn hsm + have hiR : (r0 : Real) * (DENv v t : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] - have hr0le : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := by - rw [mul_div_assoc', le_div_iff₀ hDEpos]; linarith [hiR] + have hr0le : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) := by + rw [mul_div_assoc', le_div_iff₀ hDR]; linarith [hiR] linarith [hr0le] - · -- big: r0·DE − 2^126·NE ≤ W_ev·(r0−2^126) (joint tight); divide by DE; add hcR - have hi := r0_certRatio_over_tight hx hC hC0 htnn (le_of_lt hbg) - have hjointR : (r0 : Real) * (DE : Real) - (2 ^ 126 : Real) * (NE : Real) ≤ - (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) := by + · have hi := link1_over_tight hx hC hC0 htnn (le_of_lt hbg) + have hjointR : (r0 : Real) * (DENv v t : Real) - (2 ^ 126 : Real) * (NUMv v t : Real) ≤ + (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] - have hstep : (r0 : Real) ≤ (2 ^ 126 : Real) * (NE : Real) / (DE : Real) + - (1130577 : Real) * 2 ^ 1173 * ((r0 : Real) - 2 ^ 126) / (DE : Real) := by - rw [div_add_div_same, le_div_iff₀ hDEpos]; nlinarith [hjointR, hDEpos] + have hstep : (r0 : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) / (DENv v t : Real) + + (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) / (DENv v t : Real) := by + rw [div_add_div_same, le_div_iff₀ hDR]; nlinarith [hjointR, hDR] rw [mul_div_assoc] at hstep - linarith [hstep, hcR] - -- 2^126·NE/DE ≤ 2^126·Et·Mp = 2^126·Et + 2^126·Et·(Mp−1); cMp = 2^126·Et·(Mp−1) ≤ small - have hMp1 : Mp - 1 = 1 / (2 ^ 130 - 1 : Real) := by rw [hMpdef]; field_simp - have hcMp : (2 ^ 126 : Real) * Et * (Mp - 1) ≤ 883883476483184406 / 10000000000000000000 := by + linarith [hstep, jitter_over_budget hx hC hC0 htnn] + -- link 2: 2^126·Qv ≤ 2^126·(NE/DE) + grain + obtain ⟨_, hgran⟩ := gran_over_pair hx hC hC0 htnn + -- link 3: NE/DE ≤ Et·Mp; Mp excess ≤ √2·2^126/(2^131−1) + have hcertlo := certLo_real htnn htdom + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + set Mp : Real := (2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1) with hMpdef + have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn + rw [← hEtdef] at hEtsqrt2 + have hEtnn : (0 : Real) ≤ Et := le_of_lt (Real.exp_pos _) + have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by + have hc : ((2 ^ 131 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 131 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + rw [hMpdef] + have key : (NE : Real) / (DE : Real) = + ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * + (((2 ^ 131 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 131 : Int) : Real) * (DE : Real))) := by + push_cast; field_simp; ring + rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) + have hsqrt2_hi : Real.sqrt 2 ≤ 141421356237309504880168872421 / 100000000000000000000000000000 := by + rw [Real.sqrt_le_iff]; constructor <;> norm_num + have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ + have hMp1 : Mp - 1 = 1 / ((2 ^ 131 : Real) - 1) := by rw [hMpdef]; field_simp + have hcMp : (2 ^ 126 : Real) * Et * (Mp - 1) ≤ 441941738241592203 / 10000000000000000000 := by rw [hMp1] - have hb : (2 ^ 126 : Real) * Et * (1 / (2 ^ 130 - 1 : Real)) ≤ - (2 ^ 126 : Real) * Real.sqrt 2 * (1 / (2 ^ 130 - 1 : Real)) := by + have hb : (2 ^ 126 : Real) * Et * (1 / ((2 ^ 131 : Real) - 1)) ≤ + (2 ^ 126 : Real) * Real.sqrt 2 * (1 / ((2 ^ 131 : Real) - 1)) := by apply mul_le_mul_of_nonneg_right _ (by positivity) exact mul_le_mul_of_nonneg_left hEtsqrt2 (by positivity) - have hn : (2 ^ 126 : Real) * Real.sqrt 2 * (1 / (2 ^ 130 - 1 : Real)) ≤ 883883476483184406 / 10000000000000000000 := by + have hn : (2 ^ 126 : Real) * Real.sqrt 2 * (1 / ((2 ^ 131 : Real) - 1)) ≤ + 441941738241592203 / 10000000000000000000 := by rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] nlinarith [hsqrt2_hi, hsqrt2_nn] linarith [hb, hn] - -- gap1: Et − exp(rt) ≤ (t/2^128 − rt)·Et < (1/(32·2^128))·Et ≤ (1/(32·2^128))·√2 + -- link 4: 2^126·(Et − Ert) ≤ √2/128 set Ert := Real.exp (reducedArg x) with hErtdef have hgapover := reducedArg_close_over hx hC hC0 have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ @@ -1384,828 +906,175 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hEtsqrt2 (by positivity)) (by positivity) - have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) ≤ 110485434560398051 / 10000000000000000000 := by + have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) ≤ + 110485434560398051 / 10000000000000000000 := by rw [show (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) = Real.sqrt 2 * (2 ^ 126 / (32 * 2 ^ 128)) from by ring] have : (2 ^ 126 : Real) / (32 * 2 ^ 128) = 1 / 128 := by norm_num rw [this]; nlinarith [hsqrt2_hi, hsqrt2_nn] linarith [h2, h3, h4] - -- assemble: r0 ≤ 2^126·(NE/DE) + 64/100 ≤ 2^126·Et·Mp + 64/100 - -- = 2^126·Et + 2^126·Et·(Mp−1) + 64/100 ≤ 2^126·Et + 1/10 + 64/100 - -- 2^126·Et = 2^126·Ert + 2^126·(Et−Ert) ≤ 2^126·Ert + 1/50 - -- total ≤ 2^126·Ert + 1/50 + 1/10 + 64/100 = 2^126·Ert + 0.72 ≤ 2^126·Ert + 47/64 + -- assemble have hNEMp : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mp - 1) := by have h := mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real)) nlinarith [h] - -- final - have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000 := by + have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + + 110485434560398051 / 10000000000000000000 := by nlinarith [hcGap1] - calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 6207065162659510332 / 10000000000000000000 := hr0_div - _ ≤ ((2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mp - 1)) + 6207065162659510332 / 10000000000000000000 := by linarith [hNEMp] - _ ≤ ((2 ^ 126 : Real) * Et + 883883476483184406 / 10000000000000000000) + 6207065162659510332 / 10000000000000000000 := by linarith [hcMp] - _ ≤ (((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + 883883476483184406 / 10000000000000000000) + 6207065162659510332 / 10000000000000000000 := by linarith [hEtErt] - _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by rw [hErtdef]; ring - - - -/-! ## The loose per-point real bounds (nonnegative half) - -These bracket `(r0Tree x : Real)` against `2¹²⁶·exp(rt)` with loose octave-seam-absorbed constants -(`+50` over, `+701` under). They suffice for `SeamR0Bound`, whose octave-seam doubling has ~10¹¹ -slack, and consume only the loose `r0_vs_certRatio` constants; the per-point `MARGIN` budget is met -by `r0_real_over_tight` above, via the cross-product sharpening. -/ - -/-- **Loose per-point never-over** (nonneg half): `r0 ≤ 2¹²⁶·exp(rt) + 50`. -/ -theorem r0_real_over_loose {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 50 := by - obtain ⟨hover, _⟩ := r0_vs_certRatio hx hC hC0 htnn - obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - set t := int256 (tTree x) with htdef - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] - exact hthi - have hDElb := denExpV_lb hx hC hC0 htnn - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - have hoverR : (int256 (r0Tree x) : Real) * (DE : Real) < - (2 ^ 126 : Real) * (NE : Real) + 49 * (DE : Real) := by - have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hover - push_cast at this; linarith [this] - have hr0_lt : (int256 (r0Tree x) : Real) < (2 ^ 126 : Real) * (NE : Real) / (DE : Real) + 49 := by - rw [div_add' _ _ _ (ne_of_gt hDEpos), lt_div_iff₀ hDEpos] - nlinarith [hoverR, hDEpos] - have hcertlo := certLo_real htnn htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by - have := certNE_nonneg htnn htdom; exact_mod_cast this - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - have hExp_t_le_two := exp_t_le_two hx hC hC0 htnn - rw [← hEtdef] at hExp_t_le_two - set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef - have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by - have hc : ((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo - rw [hMpdef] - have key : (NE : Real) / (DE : Real) = - ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) * - (((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real))) := by - push_cast; field_simp; ring - rw [key, mul_comm Et _] - exact mul_le_mul_of_nonneg_left hc (by positivity) - have hclose := abs_lt.mp (reducedArg_close hx hC hC0) - set Ert := Real.exp (reducedArg x) with hErtdef - have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ - have hgap1 : (t : Real) / (2 ^ 128 : Real) - reducedArg x < 9 / (8 * (2 ^ 128 : Real)) := by - have := hclose.1; linarith [this] - have hEt_nonneg : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) - have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp - have hEtMp_Ert : Et * Mp - Ert ≤ - Et * (1 / ((2 ^ 130 : Real) - 1)) + (9 / (8 * (2 ^ 128 : Real))) * Et := by - have h1 : Et * Mp - Ert = Et * (Mp - 1) + (Et - Ert) := by ring - rw [h1, hMp1] - have hgap : Et - Ert ≤ (9 / (8 * (2 ^ 128 : Real))) * Et := by - calc Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := hExp_diff - _ ≤ (9 / (8 * (2 ^ 128 : Real))) * Et := - mul_le_mul_of_nonneg_right (le_of_lt hgap1) hEt_nonneg - linarith [hgap] - have hfinal : (2 ^ 126 : Real) * (Et * Mp) ≤ (2 ^ 126 : Real) * Ert + 1 := by - have hb1 : Et * (1 / ((2 ^ 130 : Real) - 1)) ≤ 2 / ((2 ^ 130 : Real) - 1) := by - rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)]; nlinarith [hExp_t_le_two] - have hb2 : (9 / (8 * (2 ^ 128 : Real))) * Et ≤ (9 / (8 * (2 ^ 128 : Real))) * 2 := - mul_le_mul_of_nonneg_left hExp_t_le_two (by positivity) - have hbb : Et * Mp - Ert ≤ - 2 / ((2 ^ 130 : Real) - 1) + (9 / (8 * (2 ^ 128 : Real))) * 2 := by - linarith [hEtMp_Ert, hb1, hb2] - have hnum : (2 ^ 126 : Real) * - (2 / ((2 ^ 130 : Real) - 1) + (9 / (8 * (2 ^ 128 : Real))) * 2) ≤ 1 := by norm_num - set Xb : Real := 2 / ((2 ^ 130 : Real) - 1) + (9 / (8 * (2 ^ 128 : Real))) * 2 with hXbdef - have hscaled : (2 ^ 126 : Real) * (Et * Mp - Ert) ≤ (2 ^ 126 : Real) * Xb := - mul_le_mul_of_nonneg_left hbb (by positivity) - have hdist : (2 ^ 126 : Real) * (Et * Mp - Ert) = - (2 ^ 126 : Real) * (Et * Mp) - (2 ^ 126 : Real) * Ert := by ring - rw [hdist] at hscaled - linarith [hscaled, hnum] - have hstep : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (2 ^ 126 : Real) * Ert + 1 := - le_trans (mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real))) hfinal - have heq : (2 ^ 126 : Real) * (NE : Real) / (DE : Real) = - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := by ring - rw [heq] at hr0_lt - linarith [hr0_lt, hstep] - -/-- **Loose per-point deficit** (nonneg half): `2¹²⁶·exp(rt) ≤ r0 + 705`. -/ -theorem r0_real_under_loose {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 705 := by - obtain ⟨_, hunder⟩ := r0_vs_certRatio hx hC hC0 htnn - obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 - set t := int256 (tTree x) with htdef - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] - exact hthi - have hDElb := denExpV_lb hx hC hC0 htnn - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - -- 2^126·NE/DE < r0 + 701 - have hunderR : (2 ^ 126 : Real) * (NE : Real) < - ((int256 (r0Tree x) : Real) + 1) * (DE : Real) + 700 * (DE : Real) := by - have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hunder - push_cast at this; linarith [this] - have hr0_gt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (int256 (r0Tree x) : Real) + 701 := by - rw [mul_div_assoc'] - rw [div_lt_iff₀ hDEpos] - nlinarith [hunderR, hDEpos] - -- certUp: exp(t/2^128) ≤ (2^130+1)·NE/(2^130·DE) = (NE/DE)·M⁺⁺ - have hcertup := certUp_real htnn htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by - have := certNE_nonneg htnn htdom; exact_mod_cast this - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef - have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mpp := by - have hc : Et ≤ ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real)) := hcertup - rw [hMppdef] - have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) = - ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 130 : Int) : Real) * (DE : Real)) := by - push_cast; field_simp; ring - rw [key]; exact hc - -- 2^126·Et ≤ 2^126·(NE/DE)·Mpp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mpp-1). - have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) - have hMpp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp - have hr0R : (int256 (r0Tree x) : Real) < (2 ^ 128 : Real) := by - have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi - rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h - have hr0nn : (0 : Real) ≤ (int256 (r0Tree x) : Real) := by - obtain ⟨hlo, _⟩ := r0Tree_bounds hx hC hC0 - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlo; push_cast at this; linarith [this] - -- 2^126·Et ≤ r0 + 702 - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (int256 (r0Tree x) : Real) + 702 := by - have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) := - mul_le_mul_of_nonneg_left hEt_le (by positivity) - -- (NE/DE)·Mpp = NE/DE + (NE/DE)·(Mpp-1) - have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) = - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) := by ring - -- 2^126·(NE/DE)·(Mpp-1) ≤ 1. use 2^126·(NE/DE) < r0+701 < 2^128+701, ·2^-130 < 1 - have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) ≤ 1 := by - rw [hMpp1] - have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := - mul_nonneg (by positivity) hNEDE_nn - have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 701 := by - linarith [hr0_gt, hr0R] - calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / (2 ^ 130 : Real)) - ≤ ((2 ^ 128 : Real) + 701) * (1 / (2 ^ 130 : Real)) := - mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) - _ ≤ 1 := by norm_num - linarith [h1, h2 ▸ h1, h3, hr0_gt] - -- gap1: 2^126·(Ert - Et) ≤ 2.25 (via convexity + exp(rt) ≤ 2) - set Ert := Real.exp (reducedArg x) with hErtdef - have hclose := abs_lt.mp (reducedArg_close hx hC hC0) - have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ - have hErt_le_two := exp_reducedArg_le_two hx hC hC0 - rw [← hErtdef] at hErt_le_two - have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap : Ert - Et ≤ (9 / (8 * (2 ^ 128 : Real))) * Ert := by - have hd : reducedArg x - (t : Real) / (2 ^ 128 : Real) < 9 / (8 * (2 ^ 128 : Real)) := by - have := hclose.2; linarith [this] - calc Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := hExp_diff - _ ≤ (9 / (8 * (2 ^ 128 : Real))) * Ert := mul_le_mul_of_nonneg_right (le_of_lt hd) hErt_nn - have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 3 := by - have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * Ert) := - mul_le_mul_of_nonneg_left hgap (by positivity) - have h2 : (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * Ert) ≤ - (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * 2) := - mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * 2) ≤ 3 := by norm_num - linarith [h1, h2, h3] - -- assemble: 2^126·Ert = 2^126·Et + 2^126·(Ert-Et) ≤ (r0+702) + 3 - have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - rw [hdist] - linarith [hEt_bound, hgap126] - -/-! ## The loose per-point real bounds (negative half) -/ - -/-- `t/2¹²⁸ ≤ 0` and the cert domain `−t ≤ H128` for the negative half. -/ -theorem tdom_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : (-(int256 (tTree x))) ≤ (ExpCertV.H128 : Int) := by - obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] - omega - -/-- **Loose per-point never-over** (negative half): `r0 ≤ 2¹²⁶·exp(rt) + 152`. -/ -theorem r0_real_over_loose_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 152 := by - obtain ⟨hover, _⟩ := r0_vs_certRatio_neg hx hC hC0 htneg - have htdom := tdom_neg hx hC hC0 htneg - set t := int256 (tTree x) with htdef - have hDElb := denExpV_lb_neg hx hC hC0 htneg - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos - exact_mod_cast this - have hoverR : (int256 (r0Tree x) : Real) * (DE : Real) < - (2 ^ 126 : Real) * (NE : Real) + 150 * (DE : Real) := by - have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hover - push_cast at this; linarith [this] - have hr0_lt : (int256 (r0Tree x) : Real) < (2 ^ 126 : Real) * (NE : Real) / (DE : Real) + 150 := by - rw [div_add' _ _ _ (ne_of_gt hDEpos), lt_div_iff₀ hDEpos] - nlinarith [hoverR, hDEpos] - -- NE/DE ≤ exp(t/2^128)·M⁺⁺ from certLo_real_neg - have hcl := certLo_real_neg htneg htdom - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef - have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mpp := by - -- hcl: 2^130·NE/((2^130+1)·DE) ≤ Et ⇒ NE/DE ≤ Et·(2^130+1)/2^130 - rw [hMppdef] - have key : (NE : Real) / (DE : Real) = - ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) * - (((2 ^ 130 : Int) : Real) * (NE : Real) / - (((2 ^ 130 + 1 : Int) : Real) * (DE : Real))) := by - push_cast; field_simp; ring - rw [key, mul_comm Et _] - exact mul_le_mul_of_nonneg_left hcl (by positivity) - -- exp(t/2^128) ≤ 1 (t ≤ 0) and exp(rt) bound - have hEt_le_one : Et ≤ 1 := by - rw [hEtdef] - have : (t : Real) / (2 ^ 128 : Real) ≤ 0 := by - apply div_nonpos_of_nonpos_of_nonneg _ (by positivity) - exact_mod_cast htneg - calc Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ Real.exp 0 := Real.exp_le_exp.mpr this - _ = 1 := Real.exp_zero - have hEt_nonneg : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) - have hclose := abs_lt.mp (reducedArg_close hx hC hC0) - set Ert := Real.exp (reducedArg x) with hErtdef - have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ - have hgap1 : (t : Real) / (2 ^ 128 : Real) - reducedArg x < 9 / (8 * (2 ^ 128 : Real)) := by - have := hclose.1; linarith [this] - have hMp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp - have hfinal : (2 ^ 126 : Real) * (Et * Mpp) ≤ (2 ^ 126 : Real) * Ert + 1 := by - have hEtMp_Ert : Et * Mpp - Ert ≤ - Et * (1 / (2 ^ 130 : Real)) + (9 / (8 * (2 ^ 128 : Real))) * Et := by - have h1 : Et * Mpp - Ert = Et * (Mpp - 1) + (Et - Ert) := by ring - rw [h1, hMp1] - have hgap : Et - Ert ≤ (9 / (8 * (2 ^ 128 : Real))) * Et := by - calc Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := hExp_diff - _ ≤ (9 / (8 * (2 ^ 128 : Real))) * Et := - mul_le_mul_of_nonneg_right (le_of_lt hgap1) hEt_nonneg - linarith [hgap] - have hb1 : Et * (1 / (2 ^ 130 : Real)) ≤ 1 / (2 ^ 130 : Real) := by - rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)]; nlinarith [hEt_le_one] - have hb2 : (9 / (8 * (2 ^ 128 : Real))) * Et ≤ (9 / (8 * (2 ^ 128 : Real))) * 1 := - mul_le_mul_of_nonneg_left hEt_le_one (by positivity) - set Xb : Real := 1 / (2 ^ 130 : Real) + (9 / (8 * (2 ^ 128 : Real))) * 1 with hXbdef - have hbb : Et * Mpp - Ert ≤ Xb := by rw [hXbdef]; linarith [hEtMp_Ert, hb1, hb2] - have hnum : (2 ^ 126 : Real) * Xb ≤ 1 := by rw [hXbdef]; norm_num - have hscaled : (2 ^ 126 : Real) * (Et * Mpp - Ert) ≤ (2 ^ 126 : Real) * Xb := - mul_le_mul_of_nonneg_left hbb (by positivity) - have hdist : (2 ^ 126 : Real) * (Et * Mpp - Ert) = - (2 ^ 126 : Real) * (Et * Mpp) - (2 ^ 126 : Real) * Ert := by ring - rw [hdist] at hscaled; linarith [hscaled, hnum] - have hstep : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (2 ^ 126 : Real) * Ert + 1 := - le_trans (mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real))) hfinal - have heq : (2 ^ 126 : Real) * (NE : Real) / (DE : Real) = - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := by ring - rw [heq] at hr0_lt - linarith [hr0_lt, hstep] - -/-- **Loose per-point deficit** (negative half): `2¹²⁶·exp(rt) ≤ r0 + 705`. -/ -theorem r0_real_under_loose_neg {x : Nat} (hx : x < 2 ^ 256) + calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + 6207065162659510332 / 10000000000000000000 := hlink1 + _ ≤ ((2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + + 3395595387735630095 / 10000000000000000000) + + 6207065162659510332 / 10000000000000000000 := by linarith [hgran] + _ ≤ (((2 ^ 126 : Real) * Et + 441941738241592203 / 10000000000000000000) + + 3395595387735630095 / 10000000000000000000) + + 6207065162659510332 / 10000000000000000000 := by linarith [hNEMp, hcMp] + _ ≤ ((((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + + 441941738241592203 / 10000000000000000000) + + 3395595387735630095 / 10000000000000000000) + + 6207065162659510332 / 10000000000000000000 := by linarith [hEtErt] + _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + + 10155087723197130681 / 10000000000000000000 := by rw [hErtdef]; ring + +/-! ## The per-point never-over (nonpositive half) -/ + +/-- The link-1 jitter budget on the nonpositive half: +`Wod·2⁴⁸⁰·(−t)·(r0 + 2¹²⁶)/DENv ≤ 6207065162659510332/10¹⁹`. -/ +theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 705 := by - obtain ⟨_, hunder⟩ := r0_vs_certRatio_neg hx hC hC0 htneg - obtain ⟨_, hr0hi⟩ := r0Tree_bounds hx hC hC0 - have htdom := tdom_neg hx hC hC0 htneg - set t := int256 (tTree x) with htdef - have hDElb := denExpV_lb_neg hx hC hC0 htneg - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos - exact_mod_cast this - have hunderR : (2 ^ 126 : Real) * (NE : Real) < - ((int256 (r0Tree x) : Real) + 1) * (DE : Real) + 700 * (DE : Real) := by - have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hunder - push_cast at this; linarith [this] - have hr0_gt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (int256 (r0Tree x) : Real) + 701 := by - rw [mul_div_assoc']; rw [div_lt_iff₀ hDEpos] - nlinarith [hunderR, hDEpos] - -- certUp_real_neg: exp(t/2^128) ≤ (NE/DE)·M⁺ - have hcu := certUp_real_neg htneg htdom - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef - have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mp := by - rw [hMpdef] - have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) = - ((2 ^ 130 : Int) : Real) * (NE : Real) / - (((2 ^ 130 - 1 : Int) : Real) * (DE : Real)) := by - push_cast; field_simp; ring - rw [key]; exact hcu - have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) - have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp - have hr0R : (int256 (r0Tree x) : Real) < (2 ^ 128 : Real) := by - have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hr0hi - rw [show ((2 ^ 128 : Int) : Real) = (2 ^ 128 : Real) from by push_cast; ring] at h; exact h - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (int256 (r0Tree x) : Real) + 702 := by - have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := - mul_le_mul_of_nonneg_left hEt_le (by positivity) - have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) := by ring - have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) ≤ 1 := by - rw [hMp1] - have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) < (2 ^ 128 : Real) + 701 := by - linarith [hr0_gt, hr0R] - have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := - mul_nonneg (by positivity) hNEDE_nn - calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / ((2 ^ 130 : Real) - 1)) - ≤ ((2 ^ 128 : Real) + 701) * (1 / ((2 ^ 130 : Real) - 1)) := - mul_le_mul_of_nonneg_right (le_of_lt hlt) (by positivity) - _ ≤ 1 := by norm_num - linarith [h1, h2 ▸ h1, h3, hr0_gt] - set Ert := Real.exp (reducedArg x) with hErtdef - have hclose := abs_lt.mp (reducedArg_close hx hC hC0) - have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ - have hErt_le_two := exp_reducedArg_le_two hx hC hC0 - rw [← hErtdef] at hErt_le_two - have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap : Ert - Et ≤ (9 / (8 * (2 ^ 128 : Real))) * Ert := by - have hd : reducedArg x - (t : Real) / (2 ^ 128 : Real) < 9 / (8 * (2 ^ 128 : Real)) := by - have := hclose.2; linarith [this] - calc Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := hExp_diff - _ ≤ (9 / (8 * (2 ^ 128 : Real))) * Ert := mul_le_mul_of_nonneg_right (le_of_lt hd) hErt_nn - have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 3 := by - have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * Ert) := - mul_le_mul_of_nonneg_left hgap (by positivity) - have h2 : (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * Ert) ≤ - (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * 2) := - mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le_two (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((9 / (8 * (2 ^ 128 : Real))) * 2) ≤ 3 := by norm_num - linarith [h1, h2, h3] - have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - rw [hdist] - linarith [hEt_bound, hgap126] - -/-! ## The combined per-point real bounds (both signs) - -Case-splitting on the sign of the reduced argument unifies the two halves into loose octave-seam -brackets valid for every meaningful-region input. -/ - -/-- **Per-point never-over** (any sign): `r0 ≤ 2¹²⁶·exp(rt) + 152`. -/ -theorem r0_real_over {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 152 := by - rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg - · linarith [r0_real_over_loose hx hC hC0 htnn] - · exact r0_real_over_loose_neg hx hC hC0 (le_of_lt htneg) - -/-- **Per-point deficit** (any sign): `2¹²⁶·exp(rt) ≤ r0 + 705`. -/ -theorem r0_real_under {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 705 := by - rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg - · exact r0_real_under_loose hx hC hC0 htnn - · exact r0_real_under_loose_neg hx hC hC0 (le_of_lt htneg) - -/-! ## The tight joint per-point never-over (negative half + combined) -/ - -theorem exp_t_ge_inv_sqrt2 {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (Real.sqrt 2)⁻¹ ≤ Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) := by + (1075052609 : Real) * 2 ^ 480 * (-(int256 (tTree x) : Real)) * + ((int256 (r0Tree x) : Real) + 2 ^ 126) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ + 6207065162659510332 / 10000000000000000000 := by obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 - -- t/2^128 ≥ -H128/2^128 ≥ -log2/2 - have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity - have htR : -(117932881612756647068972071382077242199 : Real) ≤ (int256 (tTree x) : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo; push_cast at this; linarith [this] - -- -log2/2 ≤ t/2^128: 2·H128 ≤ log2·2^128 (from log2 ≥ LN2/2^235) - have hln2lo := ln2_lower; rw [LN2c_eq] at hln2lo - have hkey : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := by - have h1 : (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := - mul_le_mul_of_nonneg_right hln2lo (by positivity) - have h2 : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ - (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) := by - rw [div_mul_eq_mul_div, le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)]; norm_num - linarith [h1, h2] - have hge : -(Real.log 2 / 2) ≤ (int256 (tTree x) : Real) / (2 ^ 128 : Real) := by - have hmul : -(Real.log 2 / 2) * (2 ^ 128 : Real) ≤ (int256 (tTree x) : Real) := by - nlinarith [htR, hkey] - exact (le_div_iff₀ hp128).mpr hmul - have hexpsq : Real.exp (Real.log 2 / 2) = Real.sqrt 2 := by - rw [Real.sqrt_eq_rpow, Real.rpow_def_of_pos (by norm_num : (0:Real) < 2)] - congr 1; ring - have hsq : (Real.sqrt 2)⁻¹ = Real.exp (-(Real.log 2 / 2)) := by - rw [Real.exp_neg, hexpsq] - rw [hsq] - exact Real.exp_le_exp.mpr hge - --- exp(rt) ≥ 7/10 on the region (rt = t/2^128 + (rt − t/2^128); exp(t/2^128) ≥ 1/√2, the gap is tiny). - -theorem exp_reducedArg_ge_07 {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (7 : Real) / 10 ≤ Real.exp (reducedArg x) := by - have hge := exp_t_ge_inv_sqrt2 hx hC hC0 - have hclose := abs_lt.mp (reducedArg_close hx hC hC0) - set t := int256 (tTree x) with htdef - -- exp(rt) = exp(t/2^128)·exp(rt − t/2^128) ≥ (1/√2)·exp(rt − t/2^128) - have hsplit : Real.exp (reducedArg x) = - Real.exp ((t : Real) / (2 ^ 128 : Real)) * Real.exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) := by - rw [← Real.exp_add]; congr 1; ring - -- exp(rt − t/2^128) ≥ 1 + (rt − t/2^128) ≥ 1 − 9/(8·2^128) - have hgap : reducedArg x - (t : Real) / (2 ^ 128 : Real) > -(9 / (8 * (2 ^ 128 : Real))) := by - have := hclose.1; linarith [this] - have hconv : (1 : Real) - 9 / (8 * (2 ^ 128 : Real)) ≤ Real.exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) := by - have h := Real.add_one_le_exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) - linarith [h, hgap] - -- √2⁻¹ ≥ 7071/10000 (⟺ √2 ≤ 10000/7071, since (10000/7071)² > 2) - have hsqrt2_pos : (0:Real) < Real.sqrt 2 := Real.sqrt_pos.mpr (by norm_num) - have hsqrt2_le : Real.sqrt 2 ≤ 10000 / 7071 := by - rw [Real.sqrt_le_iff]; constructor <;> norm_num - have hinvsqrt2 : (7071 : Real) / 10000 ≤ (Real.sqrt 2)⁻¹ := by - rw [le_inv_comm₀ (by norm_num) hsqrt2_pos] - calc Real.sqrt 2 ≤ 10000 / 7071 := hsqrt2_le - _ = (7071 / 10000)⁻¹ := by norm_num - have hgap_small : (1 : Real) - 9 / (8 * (2 ^ 128 : Real)) ≥ 9999 / 10000 := by - have : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 1 / 10000 := by - rw [div_le_div_iff₀ (by positivity) (by norm_num)]; norm_num - linarith [this] - rw [hsplit] - have hpos : (0:Real) ≤ Real.exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) := le_of_lt (Real.exp_pos _) - calc (7:Real)/10 ≤ (7071/10000) * (9999/10000) := by norm_num - _ ≤ (Real.sqrt 2)⁻¹ * (1 - 9 / (8 * (2 ^ 128 : Real))) := by - apply mul_le_mul hinvsqrt2 (by linarith [hgap_small]) (by norm_num) (by positivity) - _ ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) * Real.exp (reducedArg x - (t : Real) / (2 ^ 128 : Real)) := by - apply mul_le_mul hge hconv (by positivity) (le_of_lt (Real.exp_pos _)) - - --- num ≥ (2/3)·den for t ≤ 0: r0 ≤ 2^126·num/den (floor), r0 ≥ 2^126·exp(rt)−705 > (2/3)·2^126. - -theorem num_ge_23_den {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 2 * ((evTree x : Int) - int256 (todTree x)) ≤ 3 * ((evTree x : Int) + int256 (todTree x)) := by - obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 - have hu := r0_real_under hx hC hC0 - have hge07 := exp_reducedArg_ge_07 hx hC hC0 - set num := (evTree x : Int) + int256 (todTree x) with hnumdef - set den := (evTree x : Int) - int256 (todTree x) with hdendef - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ den := den_ge_072 hx hC hC0 - have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden072 - have hdenR : (0:Real) < (den : Real) := by exact_mod_cast hdenpos - have hr0R : (2 ^ 126 : Real) * (7/10) - 705 ≤ (int256 (r0Tree x) : Real) := by - have h1 : (2 ^ 126 : Real) * (7/10) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) := - mul_le_mul_of_nonneg_left hge07 (by positivity) - linarith [hu, h1] - have hflR : (int256 (r0Tree x) : Real) * (den : Real) ≤ (2 ^ 126 : Real) * (num : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hfloor_lo; push_cast at this; linarith [this] - have hnumden : (2 ^ 126 : Real) * (7/10) * (den : Real) - 705 * (den : Real) ≤ (2 ^ 126 : Real) * (num : Real) := by - nlinarith [hr0R, hflR, hdenR] - have hkey : (2 : Real) * (den : Real) ≤ 3 * (num : Real) := by - have hp : (0:Real) < (2 ^ 126 : Real) := by positivity - have hnum_ge : (7/10) * (den : Real) - 705 * (den : Real) / (2 ^ 126 : Real) ≤ (num : Real) := by - rw [← mul_le_mul_left hp] - have heq : (2 ^ 126 : Real) * ((7/10) * (den : Real) - 705 * (den : Real) / (2 ^ 126 : Real)) = - (2 ^ 126 : Real) * (7/10) * (den : Real) - 705 * (den : Real) := by field_simp; ring - rw [heq]; exact hnumden - have hden_big : (705 : Real) * (den : Real) / (2 ^ 126 : Real) ≤ (1/100) * (den : Real) := by - rw [div_le_iff₀ hp] - nlinarith [hdenR, hden072, (by norm_num : (0:Real) < (2:Real)^126)] - nlinarith [hnum_ge, hden_big, hdenR] - have : ((2 * den : Int) : Real) ≤ ((3 * num : Int) : Real) := by push_cast; linarith [hkey] - exact_mod_cast this - - --- The integer cR bound (negative half): 100·W_od·2^1039·(−t)·(r0+2^126) ≤ 64·DE. --- Chain (multiplied by od·den > 0): (−t)·od ≤ 2^128·(−tod); (r0+2^126)·den ≤ 2^127·ev; --- (−tod)·ev = (den²−num²)/4 ≤ 5·den²/36 (from 3·num ≥ 2·den ⟹ 9·num² ≥ 4·den²); od ≥ B4; DE ≥ 2^1193(den−2). - -theorem todNumV_lb_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - 2 ^ 1193 * (int256 (todTree x)) + 69402657 * 2 ^ 1039 * (int256 (tTree x)) ≤ - evalPoly ExpCertV.todNumV (int256 (tTree x)) := by - obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - obtain ⟨hodlo, hodhi⟩ := odNumVPoly_bracket hx hC hC0 - set t := int256 (tTree x) with htdef - rw [evalTodNumV] - -- todP = 2^23·t·odpoly. t ≤ 0, odpoly < 2^1042·od + W_od·2^1016 ⟹ 2^23·t·odpoly ≥ 2^23·t·(2^1042 od + W_od 2^1016) - have hmul : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) ≤ - 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := by - apply mul_le_mul_of_nonneg_left _ (by positivity) - exact mul_le_mul_of_nonpos_left (le_of_lt hodhi) htneg - -- 2^23·t·(2^1042 od + W_od 2^1016) = 2^1065·(t·od) + W_od·2^1039·t ≥ 2^1193·tod + W_od·2^1039·t - have htod_lo : (2 ^ 128 : Int) * (int256 (todTree x)) ≤ t * (odTree x : Int) := htodlo - have key : 2 ^ 1193 * (int256 (todTree x)) + 69402657 * 2 ^ 1039 * t ≤ - 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) := by - have e1 : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) = - 2 ^ 1065 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1039 * t := by ring - have e2 : (2 : Int) ^ 1065 * ((2 ^ 128 : Int) * (int256 (todTree x))) = 2 ^ 1193 * (int256 (todTree x)) := by - rw [show (2:Int) ^ 1193 = 2 ^ 1065 * 2 ^ 128 from by rw [← pow_add]]; ring - rw [e1] - have h := mul_le_mul_of_nonneg_left htod_lo (by positivity : (0:Int) ≤ 2 ^ 1065) - nlinarith [h, e2] - linarith [hmul, key] - -/-- **Negative-half joint cert-ratio over** (`t ≤ 0`): `r0·DE − 2¹²⁶·NE ≤ W_od·2¹⁰³⁹·|t|·(r0+2¹²⁶)`. -The even truncation `Ee·(r0−2¹²⁶) ≤ 0` (since `r0 < 2¹²⁶`) is dropped; the binding term is the odd -truncation, attenuated to the `t`-scale by `W_od·2¹⁰³⁹·t`. -/ - -theorem r0_certRatio_over_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) - - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) ≤ - 69402657 * 2 ^ 1039 * (-(int256 (tTree x))) * (int256 (r0Tree x) + 2 ^ 126) := by - obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hevlo, _⟩ := evNumVPoly_bracket hx hC hC0 - have htodlb := todNumV_lb_neg hx hC hC0 htneg - rw [evalNumExpV, evalDenExpV] - set t := int256 (tTree x) with htdef - set r0 := int256 (r0Tree x) with hr0def - set ev := (evTree x : Int) with hevdef - set tod := int256 (todTree x) with htoddef - set evP := evalPoly ExpCertV.evNumVPoly t with hevP - set todP := evalPoly ExpCertV.todNumV t with htodP + have hr0le := r0_le_2126_neg hx hC hC0 htneg obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 - have hr0nn : (0:Int) ≤ r0 := by linarith [hr0lo] - -- tod ≤ 0 for t ≤ 0 (tod = ⌊t·od/2^128⌋, t ≤ 0, od ≥ 0) - have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have htod_np : tod ≤ 0 := by - obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - -- 2^128·tod ≤ t·od ≤ 0 - have htod_nonpos : (2 ^ 128 : Int) * tod ≤ 0 := le_trans htodlo (mul_nonpos_of_nonpos_of_nonneg htneg hodnn) - have h2 : (2 ^ 128 : Int) * tod ≤ 2 ^ 128 * 0 := by simpa using htod_nonpos - exact le_of_mul_le_mul_left h2 (by norm_num) - -- r0 ≤ 2^126: r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den ⟺ tod ≤ 0); den > 0 - have hdenpos : (0:Int) < ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this - linarith [this, (by norm_num : (0:Int) < 61251667550081741634933722430035858604)] - have hr0le126 : r0 ≤ 2 ^ 126 := by - have hnumden : r0 * (ev - tod) ≤ 2 ^ 126 * (ev - tod) := by - have h1 : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo - nlinarith [h1, htod_np, (by positivity : (0:Int) ≤ (2:Int)^126)] - have := le_of_mul_le_mul_right hnumden hdenpos + have hDEN_ge := DENv_ge_ev_neg hx hC hC0 htneg + obtain ⟨hev_lo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 + set r0 := int256 (r0Tree x) with hr0def + set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + have hev : (103786963397729689639908782561058906594 : Int) ≤ (evTree x : Int) := by + have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 from by norm_num] at this exact this - have hr0m_np : r0 - 2 ^ 126 ≤ 0 := by linarith [hr0le126] - have hr0p_nn : (0:Int) ≤ r0 + 2 ^ 126 := by positivity - -- evP·(r0−2^126) ≤ 2^1193·ev·(r0−2^126) [evP ≥ 2^1193 ev, r0−2^126 ≤ 0] - have hterm1 : evP * (r0 - 2 ^ 126) ≤ 2 ^ 1193 * ev * (r0 - 2 ^ 126) := - mul_le_mul_of_nonpos_right hevlo hr0m_np - -- −todP·(r0+2^126) ≤ −(2^1193·tod + W_od·2^1039·t)·(r0+2^126) [todP ≥ lower, r0+2^126 ≥ 0] - have hterm2 : -(todP * (r0 + 2 ^ 126)) ≤ -((2 ^ 1193 * tod + 69402657 * 2 ^ 1039 * t) * (r0 + 2 ^ 126)) := by - have := mul_le_mul_of_nonneg_right htodlb hr0p_nn + have hDEN_low : (2:Int) ^ 638 * 103786963397729689639908782561058906594 ≤ DENv v t := by + have : (2:Int) ^ 638 * 103786963397729689639908782561058906594 ≤ 2 ^ 638 * (evTree x : Int) := + mul_le_mul_of_nonneg_left hev (by positivity) + linarith [this, hDEN_ge] + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hDEN_low + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + rw [div_le_iff₀ hDR] + -- numerator ≤ Wod·2^480·H128·2·2^126; DENv ≥ 2^638·A0 + have hntR : (0:Real) ≤ -(t : Real) := by + have : (t : Real) ≤ 0 := by exact_mod_cast htneg + linarith + have hntH : -(t : Real) ≤ 117932881612756647068972071382077242199 := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo + push_cast at h + linarith [h] + have hr0pR : (0:Real) ≤ (r0 : Real) + 2 ^ 126 := by + have h : (0:Int) ≤ r0 := by + have : (0:Int) < 2 ^ 123 := by positivity + linarith [hr0lo] + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr h + push_cast at this linarith [this] - -- floor: 2^1193·(den·r0 − 2^126·num) ≤ 0 - have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor1193 : (2 ^ 1193 : Int) * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := - mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor - -- assemble: the goal LHS is evP·(r0−2^126) − todP·(r0+2^126); the bound terms collapse via the floor - have hid1 : r0 * (evP - todP) - 2 ^ 126 * (evP + todP) = evP * (r0 - 2 ^ 126) - todP * (r0 + 2 ^ 126) := by ring - have hid2 : 2 ^ 1193 * ev * (r0 - 2 ^ 126) - (2 ^ 1193 * tod + 69402657 * 2 ^ 1039 * t) * (r0 + 2 ^ 126) - = 2 ^ 1193 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) + 69402657 * 2 ^ 1039 * (-t) * (r0 + 2 ^ 126) := by - ring - rw [hid1] - linarith [hterm1, hterm2, hfloor1193, hid2] - -/-- **The joint per-point never-over (negative half).** `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` for `t ≤ 0` -(the negative-half contributions sum to `1/128 + 1/16 + 64/100 = 0.7103`, comfortably inside it). -/ - -theorem r0_certRatio_over_neg_bound {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - 100 * (69402657 * 2 ^ 1039 * (-(int256 (tTree x))) * (int256 (r0Tree x) + 2 ^ 126)) ≤ - 64 * evalPoly ExpCertV.denExpV (int256 (tTree x)) := by - obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hdenlo, _⟩ := denExpV_bracket_neg hx hC hC0 htneg - set t := int256 (tTree x) with htdef - set r0 := int256 (r0Tree x) with hr0def - set ev := (evTree x : Int) with hevdef - set tod := int256 (todTree x) with htoddef - set od := (odTree x : Int) with hoddef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - -- basic facts - have hodB4 : (51893481707599524783927774179503442518 : Int) ≤ od := by - -- od ≥ B4 (odd leading constant; odTree = B4 + nonneg shifts) - have : (0x270a522f476182f119f08da0ba710a56 : Nat) ≤ odTree x := odTree_ge (vTree_eq hx hC hC0).2 - have h := (@Int.ofNat_le _ _).mpr this - rw [show ((0x270a522f476182f119f08da0ba710a56 : Nat) : Int) = 51893481707599524783927774179503442518 from by norm_num] at h - rw [hoddef]; exact_mod_cast h - have hodpos : (0:Int) < od := lt_of_lt_of_le (by norm_num) hodB4 - have htnp : t ≤ 0 := htneg - have hntnn : (0:Int) ≤ -t := by omega - -- tod ≤ 0 - have hodnn : (0:Int) ≤ od := le_of_lt hodpos - have htod_np : tod ≤ 0 := by - have hle : (2 ^ 128 : Int) * tod ≤ t * od := htodlo - have hp : t * od ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htnp hodnn - have h2 : (2 ^ 128 : Int) * tod ≤ 2 ^ 128 * 0 := by simpa using le_trans hle hp - exact le_of_mul_le_mul_left h2 (by norm_num) - have hntodnn : (0:Int) ≤ -tod := by omega - -- den := ev - tod > 0; den ≥ 0.72·2^126 - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 - -- (1) (−t)·od ≤ 2^128·(−tod): 2^128·tod ≤ t·od ⟹ −t·od ≤ −2^128·tod = 2^128·(−tod) - have hstep1 : (-t) * od ≤ 2 ^ 128 * (-tod) := by - have hle : (2 ^ 128 : Int) * tod ≤ t * od := htodlo - have he : (-t) * od = -(t * od) := by ring - have he2 : (2:Int) ^ 128 * (-tod) = -(2 ^ 128 * tod) := by ring - rw [he, he2]; linarith [hle] - -- (2) (r0+2^126)·(ev−tod) ≤ 2^127·ev: r0·(ev−tod) ≤ 2^126·(ev+tod) (floor), +2^126·(ev−tod) - have hstep2 : (r0 + 2 ^ 126) * (ev - tod) ≤ 2 ^ 127 * ev := by - have hfl : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo - nlinarith [hfl] - -- (3) 9·num² ≥ 4·den² from 3·num ≥ 2·den (num=ev+tod ≥ 0, den=ev−tod > 0) - have h32 := num_ge_23_den hx hC hC0 - have h32' : 2 * (ev - tod) ≤ 3 * (ev + tod) := by rw [← hevdef, ← htoddef] at h32; exact h32 - have hnumnn : (0:Int) ≤ ev + tod := by - obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨htod_lo, _, _, _⟩ := todTree_bound hx hC hC0 - have he : (103786963415199049567855548359006885036 : Int) ≤ ev := by rw [hevdef]; exact_mod_cast hevlo - have ht : -(2 ^ 125 : Int) ≤ tod := htod_lo - have h2 : (2:Int)^125 = 42535295865117307932921825928971026432 := by norm_num - rw [h2] at ht; linarith [he, ht] - -- (4) (−tod)·ev = (den²−num²)/4 ; 9·num²≥4·den² ⟹ 4·(−tod)·ev = den²−num² ≤ den² − (4/9)den² = (5/9)den² - -- ⟹ 36·(−tod)·ev ≤ 5·den². (num=ev+tod, den=ev−tod, num²−tod... use ring) - have hstep4 : 36 * ((-tod) * ev) ≤ 5 * (ev - tod) ^ 2 := by - have hsq : 9 * (ev + tod) ^ 2 ≥ 4 * (ev - tod) ^ 2 := by nlinarith [h32', hnumnn, hdenpos] - nlinarith [hsq] - -- abstract den, od, DE; carry the chain through the positive product od·den - set den := ev - tod with hdendef' - have hdR2 : (r0 + 2 ^ 126) * den ≤ 2 ^ 127 * ev := hstep2 - have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by - obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 - have hr0nn : (0:Int) ≤ r0 := by linarith [hr0lo] - positivity - -- A1 := (−t)·(r0+2^126)·(od·den) ≤ 2^255·5·den²/36 ... carry without division: - -- chain on 36·A1 ≤ 5·2^255·den² - have hntden : (0:Int) ≤ 2 ^ 128 * (-tod) := mul_nonneg (by norm_num) (by linarith [htod_np]) - -- (−t)·od·(r0+2^126)·den ≤ 2^128·(−tod)·(r0+2^126)·den [hstep1, (r0+2^126)·den ≥ 0] - have hP1 : (-t) * od * ((r0 + 2 ^ 126) * den) ≤ 2 ^ 128 * (-tod) * ((r0 + 2 ^ 126) * den) := by - apply mul_le_mul_of_nonneg_right hstep1 (mul_nonneg hr0p (le_of_lt hdenpos)) - -- 2^128·(−tod)·(r0+2^126)·den ≤ 2^128·(−tod)·2^127·ev [hstep2, 2^128(−tod) ≥ 0] - have hP2 : 2 ^ 128 * (-tod) * ((r0 + 2 ^ 126) * den) ≤ 2 ^ 128 * (-tod) * (2 ^ 127 * ev) := - mul_le_mul_of_nonneg_left hdR2 hntden - -- combine + hstep4: 36·(−t)·od·(r0+2^126)·den ≤ 36·2^255·(−tod)·ev ≤ 5·2^255·den² - have hevnn : (0:Int) ≤ ev := by rw [hevdef]; exact Int.natCast_nonneg _ - have hP3 : 36 * ((-t) * od * ((r0 + 2 ^ 126) * den)) ≤ 5 * 2 ^ 255 * den ^ 2 := by - have h255 : 2 ^ 128 * (-tod) * (2 ^ 127 * ev) = 2 ^ 255 * ((-tod) * ev) := by - rw [show (2:Int) ^ 255 = 2 ^ 128 * 2 ^ 127 from by rw [← pow_add]]; ring - have hchain : (-t) * od * ((r0 + 2 ^ 126) * den) ≤ 2 ^ 255 * ((-tod) * ev) := by - rw [← h255]; linarith [hP1, hP2] - have h36 : 36 * (2 ^ 255 * ((-tod) * ev)) ≤ 2 ^ 255 * (5 * den ^ 2) := by - have := mul_le_mul_of_nonneg_left hstep4 (by positivity : (0:Int) ≤ 2 ^ 255) - nlinarith [this] - nlinarith [hchain, h36, (by positivity : (0:Int) ≤ (36:Int))] - -- DE > 2^1193·(den − 2); od ≥ B4. RHS 64·DE·(od·den) ≥ 64·2^1193(den−2)·B4·den - have hDElo : 2 ^ 1193 * den - 2 * 2 ^ 1193 < DE := hdenlo - -- final: 100·W·2^1039·(−t)·(r0+2^126) ≤ 64·DE. multiply both by od·den (>0) and use 36·(LHS·od·den) ≤ ... - set q := od * den with hqdef - have hqpos : (0:Int) < q := by rw [hqdef]; exact mul_pos hodpos hdenpos - -- 36·100·W·2^1039·(−t)·(r0+2^126)·q ≤ 100·W·2^1039·(5·2^255·den²) [hP3 scaled] - -- and 64·DE·q ≥ 64·(2^1193 den − 2·2^1193)·B4·den via DE>… od≥B4 - -- prove via le_of_mul_le_mul_right with multiplier q, after establishing the multiplied inequality. - rw [← mul_le_mul_right hqpos] - -- goal: 100·W·2^1039·(−t)·(r0+2^126)·q ≤ 64·DE·q - have hLHS : 100 * (69402657 * 2 ^ 1039 * (-t) * (r0 + 2 ^ 126)) * q = - 100 * 69402657 * 2 ^ 1039 * ((-t) * od * ((r0 + 2 ^ 126) * den)) := by rw [hqdef]; ring - rw [hLHS] - -- 36·LHS ≤ 100·69402657·2^1039·(5·2^255·den²) =: RHS36 ; and 36·(64·DE·q) ≥ 36·64·(2^1193 den − 2·2^1193)·B4·den - -- show LHS ≤ 64·DE·q via: 36·LHS ≤ 36·(64·DE·q) - have hmul36 : 36 * (100 * 69402657 * 2 ^ 1039 * ((-t) * od * ((r0 + 2 ^ 126) * den))) ≤ - 36 * (64 * DE * q) := by - have hL : 36 * (100 * 69402657 * 2 ^ 1039 * ((-t) * od * ((r0 + 2 ^ 126) * den))) ≤ - 100 * 69402657 * 2 ^ 1039 * (5 * 2 ^ 255 * den ^ 2) := by - have := mul_le_mul_of_nonneg_left hP3 (by positivity : (0:Int) ≤ 100 * 69402657 * 2 ^ 1039) - nlinarith [this] - have hR : 100 * 69402657 * 2 ^ 1039 * (5 * 2 ^ 255 * den ^ 2) ≤ 36 * (64 * DE * q) := by - -- 36·64·DE·q ≥ 36·64·(2^1193 den − 2·2^1193)·B4·den (DE > …, od ≥ B4, den > 0) - have hDEq : 36 * (64 * DE * q) ≥ 36 * 64 * ((2 ^ 1193 * den - 2 * 2 ^ 1193) * (51893481707599524783927774179503442518 * den)) := by - rw [hqdef] - have hDEnn : (0:Int) ≤ DE := by - have := denExpV_lb_neg hx hC hC0 htneg; rw [← hDEdef] at this - have h2 : (0:Int) < 2 ^ 1317 := by positivity - linarith [this, h2] - have h1 : (2 ^ 1193 * den - 2 * 2 ^ 1193) * 51893481707599524783927774179503442518 ≤ DE * od := - mul_le_mul (le_of_lt hDElo) hodB4 (by norm_num) hDEnn - nlinarith [h1, hdenpos] - -- 100·69402657·5·2^1294·den² ≤ 36·64·2^1193·B4·(den−2)·den (factor 2^1193, den) - have hcore : 100 * 69402657 * 2 ^ 1039 * (5 * 2 ^ 255 * den ^ 2) ≤ - 36 * 64 * ((2 ^ 1193 * den - 2 * 2 ^ 1193) * (51893481707599524783927774179503442518 * den)) := by - -- both sides = (·)·2^1193·den. LHS = (100·69402657·5·2^101)·2^1193·den². - have hpe1 : (2:Int) ^ 1039 * 2 ^ 255 = 2 ^ 101 * 2 ^ 1193 := by rw [← pow_add, ← pow_add] - have eL : 100 * 69402657 * 2 ^ 1039 * (5 * 2 ^ 255 * den ^ 2) = - (100 * 69402657 * 5 * 2 ^ 101) * (2 ^ 1193 * den ^ 2) := by - linear_combination (100 * 69402657 * 5 * den ^ 2) * hpe1 - have eR : 36 * 64 * ((2 ^ 1193 * den - 2 * 2 ^ 1193) * (51893481707599524783927774179503442518 * den)) = - (36 * 64 * 51893481707599524783927774179503442518) * (2 ^ 1193 * (den - 2) * den) := by ring - rw [eL, eR] - -- (100·69402657·5·2^101)·den ≤ (36·64·B4)·(den−2) [divide common 2^1193·den; den ≥ 0.72·2^126 ≫ 2] - have hfactor : (100 * 69402657 * 5 * 2 ^ 101 : Int) * den ≤ (36 * 64 * 51893481707599524783927774179503442518) * (den - 2) := by - nlinarith [hden072, hdenpos] - have hp1193den : (0:Int) ≤ 2 ^ 1193 * den := by positivity - nlinarith [hfactor, hp1193den, hdenpos, (by positivity : (0:Int) ≤ (2:Int)^1193)] - linarith [hDEq, hcore] - linarith [hL, hR] - nlinarith [hmul36] - + have hr0pH : (r0 : Real) + 2 ^ 126 ≤ 2 * 2 ^ 126 := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le + push_cast at h + linarith [h] + have hnum_le : (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) ≤ + (1075052609 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := by + have h1 : (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) ≤ + (1075052609 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 := + mul_le_mul_of_nonneg_left hntH (by positivity) + exact mul_le_mul h1 hr0pH hr0pR (by positivity) + have hDENlowR : ((2:Real) ^ 638 * 103786963397729689639908782561058906594) ≤ (DENv v t : Real) := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDEN_low + push_cast at h + linarith [h] + have hbudget : (1075052609 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * + (2 * 2 ^ 126) ≤ (6207065162659510332 / 10000000000000000000) * + ((2:Real) ^ 638 * 103786963397729689639908782561058906594) := by + norm_num + calc (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) + ≤ (1075052609 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := + hnum_le + _ ≤ (6207065162659510332 / 10000000000000000000) * + ((2:Real) ^ 638 * 103786963397729689639908782561058906594) := hbudget + _ ≤ (6207065162659510332 / 10000000000000000000) * (DENv v t : Real) := + mul_le_mul_of_nonneg_left hDENlowR (by norm_num) + +/-- **The per-point never-over (nonpositive half).** The granularity is free here; the `Mp` factor +and reduced-argument gap shrink (`Et ≤ 1`), so the same budget `B` covers the half. -/ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + + 10155087723197130681 / 10000000000000000000 := by have htdom := tdom_neg hx hC hC0 htneg + have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef - have hDElb := denExpV_lb_neg hx hC hC0 htneg - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos - exact_mod_cast this + set v := vTree x with hvdef set r0 := int256 (r0Tree x) with hr0def - -- certLo_real_neg: NE/DE ≤ Et·Mpp, Mpp = (2^130+1)/2^130 - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htneg + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htneg htdom).2 + have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos + -- link 1: r0 ≤ 2^126·Qv + jitter + have hlink1 : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + 6207065162659510332 / 10000000000000000000 := by + have hi := link1_over_neg hx hC hC0 htneg + have hiR : (r0 : Real) * (DENv v t : Real) - (2 ^ 126 : Real) * (NUMv v t : Real) ≤ + (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) := by + have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] + have hstep : (r0 : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) / (DENv v t : Real) + + (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) / + (DENv v t : Real) := by + rw [div_add_div_same, le_div_iff₀ hDR]; nlinarith [hiR, hDR] + rw [mul_div_assoc] at hstep + linarith [hstep, jitter_over_budget_neg hx hC hC0 htneg] + -- link 2 (free): Qv ≤ NE/DE + obtain ⟨hgran1, _⟩ := gran_under_pair hx hC hC0 htneg + -- link 3: NE/DE ≤ Et·Mpp with Et ≤ 1 have hcertlo := certLo_real_neg htneg htdom - set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef + set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef2 + set Mpp : Real := ((2 ^ 131 : Real) + 1) / (2 ^ 131 : Real) with hMppdef have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mpp := by - have hc : ((2 ^ 130 : Int) : Real) * (NE : Real) / - (((2 ^ 130 + 1 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + have hc : ((2 ^ 131 : Int) : Real) * (NE : Real) / + (((2 ^ 131 + 1 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo rw [hMppdef] have key : (NE : Real) / (DE : Real) = - ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) * - (((2 ^ 130 : Int) : Real) * (NE : Real) / - (((2 ^ 130 + 1 : Int) : Real) * (DE : Real))) := by + (((2 ^ 131 : Real) + 1) / (2 ^ 131 : Real)) * + (((2 ^ 131 : Int) : Real) * (NE : Real) / + (((2 ^ 131 + 1 : Int) : Real) * (DE : Real))) := by push_cast; field_simp; ring rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) - -- Et ≤ 1 (t ≤ 0) have hEt_le_one : Et ≤ 1 := by rw [hEtdef, show (1:Real) = Real.exp 0 from (Real.exp_zero).symm] apply Real.exp_le_exp.mpr - have htR : (t : Real) ≤ 0 := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htneg; push_cast at this; linarith [this] + have htR : (t : Real) ≤ 0 := by exact_mod_cast htneg apply div_nonpos_of_nonpos_of_nonneg htR (by positivity) have hEtnn : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) - -- cR_neg: r0·DE − 2^126·NE ≤ (64/100)·DE (Int: certRatio_neg ≤ W·2^1039(−t)(r0+2^126), bound by 64·DE/100) - have hcR' : (r0 : Real) * (DE : Real) - (2 ^ 126 : Real) * (NE : Real) ≤ (64 / 100) * (DE : Real) := by - have hcr := r0_certRatio_over_neg hx hC hC0 htneg - have hbd := r0_certRatio_over_neg_bound hx hC hC0 htneg - -- chain (Int): 100·(r0·DE − 2^126·NE) ≤ 100·W·2^1039·(−t)·(r0+2^126) ≤ 64·DE - have hint : 100 * (r0 * (evalPoly ExpCertV.denExpV t) - 2 ^ 126 * (evalPoly ExpCertV.numExpV t)) ≤ - 64 * (evalPoly ExpCertV.denExpV t) := by - have h1 : 100 * (r0 * (evalPoly ExpCertV.denExpV t) - 2 ^ 126 * (evalPoly ExpCertV.numExpV t)) ≤ - 100 * (69402657 * 2 ^ 1039 * (-t) * (r0 + 2 ^ 126)) := by - apply mul_le_mul_of_nonneg_left hcr (by norm_num) - linarith [h1, hbd] - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hint; push_cast at this - rw [hNEdef, hDEdef]; linarith [this] - -- r0 ≤ 2^126·NE/DE + 64/100 - have hr0_div : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 64 / 100 := by - have hkey : (r0 : Real) ≤ ((2 ^ 126 : Real) * (NE : Real) + (64 / 100) * (DE : Real)) / (DE : Real) := by - rw [le_div_iff₀ hDEpos]; nlinarith [hcR', hDEpos] - rw [add_div, mul_div_assoc, mul_div_assoc, div_self (ne_of_gt hDEpos), mul_one] at hkey - linarith [hkey] - -- assemble: r0 ≤ 2^126·Et·Mpp + 64/100 = 2^126·Et + 2^126·Et·(Mpp−1) + 64/100 - -- ≤ 2^126·Et + 1/16 + 64/100; 2^126·Et ≤ 2^126·exp(rt) + 1/128 (gap1 over) - have hMpp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp - have hcMp : (2 ^ 126 : Real) * Et * (Mpp - 1) ≤ 1 / 16 := by + have hMpp1 : Mpp - 1 = 1 / (2 ^ 131 : Real) := by rw [hMppdef]; field_simp + have hcMp : (2 ^ 126 : Real) * Et * (Mpp - 1) ≤ 441941738241592203 / 10000000000000000000 := by rw [hMpp1] - have : (2 ^ 126 : Real) * Et * (1 / (2 ^ 130 : Real)) ≤ (2 ^ 126 : Real) * 1 * (1 / (2 ^ 130 : Real)) := by + have h1 : (2 ^ 126 : Real) * Et * (1 / (2 ^ 131 : Real)) ≤ + (2 ^ 126 : Real) * 1 * (1 / (2 ^ 131 : Real)) := by apply mul_le_mul_of_nonneg_right _ (by positivity) exact mul_le_mul_of_nonneg_left hEt_le_one (by positivity) - have hn : (2 ^ 126 : Real) * 1 * (1 / (2 ^ 130 : Real)) ≤ 1 / 16 := by norm_num - linarith [this, hn] + have hn : (2 ^ 126 : Real) * 1 * (1 / (2 ^ 131 : Real)) ≤ + 441941738241592203 / 10000000000000000000 := by norm_num + linarith [h1, hn] + -- link 4 with Et ≤ 1 set Ert := Real.exp (reducedArg x) with hErtdef have hgapover := reducedArg_close_over hx hC hC0 have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ - have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 1 / 128 := by + have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 110485434560398051 / 10000000000000000000 := by have h1 : Et - Ert ≤ (1 / (32 * (2 ^ 128 : Real))) * Et := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapover) hEtnn) have h2 : (2 ^ 126 : Real) * (Et - Ert) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) := @@ -2213,144 +1082,85 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * 1) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hEt_le_one (by positivity)) (by positivity) - have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * 1) ≤ 1 / 128 := by norm_num + have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * 1) ≤ + 110485434560398051 / 10000000000000000000 := by norm_num linarith [h2, h3, h4] + -- assemble have hNEMp : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mpp - 1) := by have h := mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real)) nlinarith [h] - have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + 1 / 128 := by nlinarith [hcGap1] - calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 64 / 100 := hr0_div - _ ≤ ((2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * Et * (Mpp - 1)) + 64 / 100 := by linarith [hNEMp] - _ ≤ ((2 ^ 126 : Real) * Et + 1 / 16) + 64 / 100 := by linarith [hcMp] - _ ≤ (((2 ^ 126 : Real) * Ert + 1 / 128) + 1 / 16) + 64 / 100 := by linarith [hEtErt] - _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by - rw [hErtdef]; have : (1:Real)/128 + 1/16 + 64/100 ≤ 7201434073703092789/10000000000000000000 := by norm_num + have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + + 110485434560398051 / 10000000000000000000 := by nlinarith [hcGap1] + have hgranR : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := + mul_le_mul_of_nonneg_left hgran1 (by positivity) + calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + 6207065162659510332 / 10000000000000000000 := hlink1 + _ ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + + 6207065162659510332 / 10000000000000000000 := by linarith [hgranR] + _ ≤ ((2 ^ 126 : Real) * Et + 441941738241592203 / 10000000000000000000) + + 6207065162659510332 / 10000000000000000000 := by linarith [hNEMp, hcMp] + _ ≤ (((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + + 441941738241592203 / 10000000000000000000) + + 6207065162659510332 / 10000000000000000000 := by linarith [hEtErt] + _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + + 10155087723197130681 / 10000000000000000000 := by + rw [hErtdef] + have : (110485434560398051 : Real) / 10000000000000000000 + + 441941738241592203 / 10000000000000000000 + + 6207065162659510332 / 10000000000000000000 ≤ + 10155087723197130681 / 10000000000000000000 := by norm_num linarith [this] -/-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` (< MARGIN/WAD). -/ +/-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + B` (`WAD·B < MARGIN`). -/ theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + 7201434073703092789 / 10000000000000000000 := by + (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + + 10155087723197130681 / 10000000000000000000 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_over_tight hx hC hC0 htnn · exact r0_real_over_tight_neg hx hC hC0 (le_of_lt htneg) +/-! ## The octave real identity `E·2^(126−k) = WAD·2¹²⁶·exp(rt)` -/-! ## The octave-seam `r0`-doubling consequence -/ - -/-- The reduced argument is above `−log 2` on the region, so `exp(rt) > 1/2`. -/ -theorem exp_reducedArg_gt_half {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (1 : Real) / 2 < Real.exp (reducedArg x) := by - obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 - have hclose := abs_lt.mp (reducedArg_close hx hC hC0) - have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity - have htR : -(117932881612756647068972071382077242199 : Real) ≤ (int256 (tTree x) : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo; push_cast at this; linarith [this] - -- rt > t/2^128 - 9/(8·2^128) ≥ -H128/2^128 - 1 > -log 2 (log2 ≥ 0.693) - have hln2 : (0.6931471805 : Real) ≤ Real.log 2 := by - have := ln2_lower; rw [LN2c_eq] at this - have h2 : (0.6931471805 : Real) ≤ - (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) := by - rw [le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)]; norm_num - linarith [this, h2] - have htdiv : -(0.35 : Real) ≤ (int256 (tTree x) : Real) / (2 ^ 128 : Real) := by - rw [le_div_iff₀ hp128]; nlinarith [htR] - have h9 : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 0.34 := by - rw [div_le_iff₀ (by positivity)]; norm_num - have hrt : -(Real.log 2) < reducedArg x := by linarith [hclose.1, htdiv, h9, hln2] - have : Real.exp (-(Real.log 2)) < Real.exp (reducedArg x) := Real.exp_lt_exp.mpr hrt - rwa [Real.exp_neg, Real.exp_log (by norm_num : (0:Real) < 2), show (2:Real)⁻¹ = 1/2 from by norm_num] at this +The target `E = WAD·exp(X/RAY)`. With `rt = X/RAY − k·ln2` the reduced argument, `exp(X/RAY) = +exp(rt)·2^k`, so the closing-shift fold `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`. This collapses the +never-over/deficit inequalities (stated against `E·2^s`, `s = 126 − k`) onto the clean +octave-independent relation `r0 ≈ 2¹²⁶·exp(rt)`. -/ -/-- A lower bound on the quotient: `2¹²⁴ < r0Tree x`. (`r0 ≥ 2¹²⁶·exp(rt) − 705 > 2¹²⁶·(1/2) − 705`.) -/ -theorem r0Tree_gt_2_124 {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 : Real) ^ 124 < (int256 (r0Tree x) : Real) := by - have hu := r0_real_under hx hC hC0 - have hh := exp_reducedArg_gt_half hx hC hC0 - -- 2^126·exp(rt) > 2^126·(1/2) = 2^125; r0 ≥ 2^126·exp(rt) − 705 > 2^125 − 705 > 2^124 - have h1 : (2 ^ 126 : Real) * (1 / 2) < (2 ^ 126 : Real) * Real.exp (reducedArg x) := - mul_lt_mul_of_pos_left hh (by positivity) - have h2 : (2 ^ 126 : Real) * (1 / 2) = (2 ^ 125 : Real) := by norm_num - have h3 : (2 : Real) ^ 124 + 705 < (2 ^ 125 : Real) := by norm_num - linarith [hu, h1, h2 ▸ h1, h3] +/-- `exp(X/RAY) = exp(rt)·2^k` (`k = int256 (kTree x)`, possibly negative; `2^k` is a real `zpow`). -/ +theorem exp_X_over_RAY (x : Nat) : + Real.exp ((int256 x : Real) / (10 ^ 27 : Real)) = + Real.exp (reducedArg x) * (2 : Real) ^ (int256 (kTree x)) := by + have hlog : Real.exp ((int256 (kTree x) : Real) * Real.log 2) = (2 : Real) ^ (int256 (kTree x)) := by + rw [← Real.rpow_intCast 2 (int256 (kTree x)), + Real.rpow_def_of_pos (by norm_num : (0:Real) < 2), mul_comm] + rw [show (int256 x : Real) / (10 ^ 27 : Real) = + reducedArg x + (int256 (kTree x) : Real) * Real.log 2 from by + unfold reducedArg; ring, + Real.exp_add, hlog] -/-- **The seam exp relation.** Across a seam (`X2 = X1 + 1`, `k2 = k1 + 1`), -`exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`. -/ -theorem reducedArg_seam {x1 x2 : Nat} - (hk : int256 (kTree x2) = int256 (kTree x1) + 1) - (hadj : int256 x2 = int256 x1 + 1) : - Real.exp (reducedArg x1) = - 2 * Real.exp (reducedArg x2) * Real.exp (-(1 / (10 ^ 27 : Real))) := by - have hrel : reducedArg x1 = reducedArg x2 + Real.log 2 + (-(1 / (10 ^ 27 : Real))) := by - unfold reducedArg - rw [show (int256 x2 : Real) = (int256 x1 : Real) + 1 from by exact_mod_cast hadj, - show (int256 (kTree x2) : Real) = (int256 (kTree x1) : Real) + 1 from by exact_mod_cast hk] - ring - rw [hrel, Real.exp_add, Real.exp_add, Real.exp_log (by norm_num : (0:Real) < 2)] - ring +/-- **The octave fold of the target.** `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`, with `s = 126 − k` the +closing shift. -/ +theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 126 - int256 (kTree x)) : + expRayToWadTarget (int256 x) * (2 ^ s : Real) = + (WAD : Real) * (2 ^ 126 : Real) * Real.exp (reducedArg x) := by + unfold expRayToWadTarget + rw [show (RAY : Real) = (10 ^ 27 : Real) from by unfold RAY; norm_num, exp_X_over_RAY x] + -- 2^k · 2^s = 2^126 with k+s = 126 (k : Int, s : Nat). + set k := int256 (kTree x) with hkdef + have hks : k + (s : Int) = 126 := by omega + have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (126 : Nat) := by + rw [show ((2 : Real) ^ (s : Nat)) = (2 : Real) ^ (s : Int) from by + rw [zpow_natCast], ← zpow_add₀ (by norm_num : (2:Real) ≠ 0), hks] + norm_num + rw [show ((2 ^ s : Real)) = (2 : Real) ^ (s : Nat) from by norm_num] + calc (WAD : Real) * (Real.exp (reducedArg x) * (2 : Real) ^ k) * (2 : Real) ^ (s : Nat) + = (WAD : Real) * ((2 : Real) ^ k * (2 : Real) ^ (s : Nat)) * Real.exp (reducedArg x) := by ring + _ = (WAD : Real) * (2 ^ 126 : Real) * Real.exp (reducedArg x) := by + rw [hpow] -/-- **`r0` at most doubles across a seam** (real reduction of `SeamR0Bound`). The strict slack from -`exp(−1/RAY) < 1` (and `r0Tree x2 > 2¹²⁴`) dwarfs the loose per-point envelope constants. -/ -theorem r0_seam_double {x1 x2 : Nat} - (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) - (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) - (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) - (hk : int256 (kTree x2) = int256 (kTree x1) + 1) - (hadj : int256 x2 = int256 x1 + 1) : - int256 (r0Tree x1) < 2 * int256 (r0Tree x2) := by - have hover1 := r0_real_over hx1 hC1 hC01 - have hunder2 := r0_real_under hx2 hC2 hC02 - have hr0_2_big := r0Tree_gt_2_124 hx2 hC2 hC02 - have hseam := reducedArg_seam hk hadj - -- exp(-1/RAY) < 1 and ≥ 1 - 1/RAY ⇒ 1 - exp(-1/RAY) ≥ 1/RAY - ... use the convexity-style bound - set E1 := Real.exp (reducedArg x1) with hE1 - set E2 := Real.exp (reducedArg x2) with hE2 - set y := Real.exp (-(1 / (10 ^ 27 : Real))) with hy - have hy_lt_one : y < 1 := by - rw [hy]; rw [show (1:Real) = Real.exp 0 from (Real.exp_zero).symm] - exact Real.exp_lt_exp.mpr (by norm_num) - have hy_pos : 0 < y := Real.exp_pos _ - -- y ≤ 1 - 1/(2·RAY) (since exp(-z) ≤ 1 - z + z²/2 ≤ 1 - z/2 for small z>0) - have hy_bound : y ≤ 1 - 1 / (2 * (10 ^ 27 : Real)) := by - -- exp(-z) = 1/exp(z) ≤ 1/(1+z) ≤ 1 - z/2 for z ∈ (0,1] - rw [hy] - have hz : (0:Real) < 1 / (10 ^ 27 : Real) := by positivity - have hez : (1 : Real) + 1 / (10 ^ 27 : Real) ≤ Real.exp (1 / (10 ^ 27 : Real)) := by - have := Real.add_one_le_exp (1 / (10 ^ 27 : Real)); linarith [this] - rw [Real.exp_neg] - have hexppos : 0 < Real.exp (1 / (10 ^ 27 : Real)) := Real.exp_pos _ - rw [inv_le_iff_one_le_mul₀ hexppos] - have h1z : (1 - 1 / (2 * (10 ^ 27 : Real))) * (1 + 1 / (10 ^ 27 : Real)) ≥ 1 := by - rw [ge_iff_le]; nlinarith [sq_nonneg (1 / (10 ^ 27 : Real))] - nlinarith [hez, h1z, hexppos, mul_pos (by positivity : (0:Real) < 1 - 1/(2*(10^27:Real))) hexppos] - -- 2^126·E1 = 2·(2^126·E2)·y ≤ 2·(r0_2 + 705)·y - have hE2bound : (2 ^ 126 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + 705 := hunder2 - have hr0_1 : (int256 (r0Tree x1) : Real) ≤ 2 * ((int256 (r0Tree x2) : Real) + 705) * y + 152 := by - have h1 : (2 ^ 126 : Real) * E1 = 2 * ((2 ^ 126 : Real) * E2) * y := by rw [hseam]; ring - have h2 : (int256 (r0Tree x1) : Real) ≤ (2 ^ 126 : Real) * E1 + 152 := hover1 - rw [h1] at h2 - have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 705) * y := - mul_le_mul_of_nonneg_right (by linarith [mul_le_mul_of_nonneg_left hE2bound (by norm_num : (0:Real) ≤ 2)]) (le_of_lt hy_pos) - linarith [h2, h3] - have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^124)] - have hkey : 2 * ((int256 (r0Tree x2) : Real) + 705) * y + 152 < 2 * (int256 (r0Tree x2) : Real) := by - -- The seam gap is dominated by `(r0 + 705) / RAY`; the quotient is above `1562` on this region. - have hyb : 2 * ((int256 (r0Tree x2) : Real) + 705) * y ≤ - 2 * ((int256 (r0Tree x2) : Real) + 705) * (1 - 1 / (2 * (10 ^ 27 : Real))) := - mul_le_mul_of_nonneg_left hy_bound (by linarith [hr0_2nn]) - have hexpand : 2 * ((int256 (r0Tree x2) : Real) + 705) * (1 - 1 / (2 * (10 ^ 27 : Real))) = - 2 * (int256 (r0Tree x2) : Real) + 1410 - - ((int256 (r0Tree x2) : Real) + 705) / (10 ^ 27 : Real) := by field_simp; ring - have hbig : ((int256 (r0Tree x2) : Real) + 705) / (10 ^ 27 : Real) > 1562 := by - rw [gt_iff_lt, lt_div_iff₀ (by positivity)] - nlinarith [hr0_2_big, (by norm_num : (1562:Real) * 10 ^ 27 + 1 < 2 ^ 124)] - linarith [hyb, hexpand ▸ hyb, hbig] - have hreal : (int256 (r0Tree x1) : Real) < 2 * (int256 (r0Tree x2) : Real) := by - linarith [hr0_1, hkey] - have : (int256 (r0Tree x1) : Real) < ((2 * int256 (r0Tree x2) : Int) : Real) := by - push_cast; linarith [hreal] - exact_mod_cast this +end end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index 92a5bf28b..9913563d9 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -1,10 +1,21 @@ import ExpProof.Floor.R0Exp /-! -# The deficit (under) side of the per-point `r0`-vs-`exp` bridge +# The deficit (under) side of the per-point `r0`-vs-`exp` bridge, and the seam bound This module contains the counterpart to the never-over `r0_real_over_within`: the per-point deficit -`2¹²⁶·exp(rt) ≤ r0 + 13/2` (`r0_real_under_within`), both signs. +`2¹²⁶·exp(rt) ≤ r0 + 67/10` (`r0_real_under_within`), both signs, with the same four-link chain: + +1. link-1 deficit against the grid rational, `≤ 6001/1000`; +2. the argument granularity (`Floor.GranV`) — free on the `t ≥ 0` half, `≤ 1685843742692980488/10¹⁹` + (`Mp`-folded) on the `t ≤ 0` half; +3. the `Mp` factor, `≤ 1/20` (via `r0 ≤ 1.45·2¹²⁶`); +4. the under-direction reduced-argument gap, `≤ 37/100` (via `exp(rt) ≤ √2·(1+ε)`). + +The sum `6001/1000 + 1/20 + 1685843742692980488/10¹⁹ + 37/100 ≤ 67/10` feeds the `k = 63` deficit +envelope `((67/10)·10¹⁸ + MARGIN)/2⁶³ < 1`. The module closes with the octave-seam `r0`-doubling +bound `r0₁ + 2 ≤ 2·r0₂` (`SeamR0Bound`), where the `1 − exp(−1/RAY)` seam slack (≈ `1.7·10¹¹` grid +units against `r0₂ > 2¹²⁴`) dwarfs both per-point budgets and the two integer units. -/ namespace ExpYul @@ -15,10 +26,13 @@ open Common.Poly set_option maxRecDepth 100000 set_option maxHeartbeats 1600000 +set_option exponentiation.threshold 2000 + +noncomputable section /-- `exp(reducedArg) ≤ 14143/10000` (both signs). The reduced argument is within a half-octave, -`reducedArg ≤ log2/2 + 9/(8·2¹²⁸)`, so `exp` is at most `√2·exp(9/(8·2¹²⁸)) ≤ √2·(1+ε)`, which the -`14143/10000` ceiling covers with room. Sharper than `exp_reducedArg_le_two`; drives the under gap-1. -/ +`reducedArg ≤ log2/2 + 33/(32·2¹²⁸)`, so `exp` is at most `√2·(1+ε)`, which the `14143/10000` +ceiling covers with room. Drives the under gap-1. -/ theorem exp_reducedArg_le_sqrt2bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : Real.exp (reducedArg x) ≤ 14143 / 10000 := by @@ -58,136 +72,9 @@ theorem exp_reducedArg_le_sqrt2bound {x : Nat} (hx : x < 2 ^ 256) _ ≤ 14143 / 10000 := by rw [mul_one_div, div_le_div_iff₀ h1u (by norm_num)]; nlinarith [husmall] -/-! ## The deficit (under) side: per-point `2¹²⁶·exp(rt) ≤ r0 + 13/2` (both signs) - -Mirror of the never-over `r0_real_over_within`. The nonneg half drops the even truncation -`Ee·(2¹²⁶−r0) ≤ 0` and bounds the tod truncation; the negative half drops the tod and bounds the -even truncation. Each contribution is taken near its supremum — floor `≈1`, `Mp` factor `≤1/10`, -gap-1 `≤37/100` — giving `c_under = 13/2 = 6.5`, comfortably inside the closing-shift budget -`2⁶³/WAD − MARGIN/WAD ≈ 8.50` at the binding `k = 63`. -/ - -/-- **`todNumV` upper bound (nonneg half).** For `0 ≤ t`: -`todNumV(t) ≤ 2¹¹⁹³·tod + 2¹¹⁹³ + W_od·2¹⁰³⁹·t`. -/ -theorem todNumV_ub {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - evalPoly ExpCertV.todNumV (int256 (tTree x)) ≤ - 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 + 69402657 * 2 ^ 1039 * (int256 (tTree x)) := by - obtain ⟨_, _, _, htodhi⟩ := todTree_bound hx hC hC0 - obtain ⟨_, hodhi⟩ := odNumVPoly_bracket hx hC hC0 - set t := int256 (tTree x) with htdef - rw [evalTodNumV] - -- todP = 2^23·t·odpoly. t ≥ 0, odpoly ≤ 2^1042·od + W_od·2^1016 ⟹ 2^23·t·odpoly ≤ 2^23·t·(…) - have hmul : 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) ≤ - 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) := by - apply mul_le_mul_of_nonneg_left _ (by positivity) - exact mul_le_mul_of_nonneg_left (le_of_lt hodhi) htnn - -- 2^23·t·(2^1042 od + W_od 2^1016) = 2^1065·(t·od) + W_od·2^1039·t ; 2^1065·(t·od) < 2^1193·tod + 2^1193 - have htod_hi : t * (odTree x : Int) < (2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128 := htodhi - have key : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) ≤ - 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t := by - have e1 : 2 ^ 23 * (t * (2 ^ 1042 * (odTree x : Int) + 69402657 * 2 ^ 1016)) = - 2 ^ 1065 * (t * (odTree x : Int)) + 69402657 * 2 ^ 1039 * t := by ring - have e2 : (2 : Int) ^ 1065 * ((2 ^ 128 : Int) * (int256 (todTree x)) + 2 ^ 128) = - 2 ^ 1193 * (int256 (todTree x)) + 2 ^ 1193 := by - rw [show (2:Int) ^ 1193 = 2 ^ 1065 * 2 ^ 128 from by rw [← pow_add]]; ring - rw [e1] - have h := mul_le_mul_of_nonneg_left (le_of_lt htod_hi) (by positivity : (0:Int) ≤ 2 ^ 1065) - rw [e2] at h - linarith [h] - linarith [hmul, key] - -/-- **`num ≤ 1.45·den`** (`ê ≤ 1.45`) on the nonneg half, from `exp(t/2¹²⁸) ≤ √2` and the cert. -/ -theorem num_le_145_den {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : - 100 * ((evTree x : Int) + int256 (todTree x)) ≤ 145 * ((evTree x : Int) - int256 (todTree x)) := by - obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - set t := int256 (tTree x) with htdef - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] - exact hthi - have hDElb := denExpV_lb hx hC hC0 htnn - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - have hcertlo := certLo_real htnn htdom - set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef - have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn - rw [← hEtdef] at hEtsqrt2 - have hMp_pos : (0:Real) < Mp := by rw [hMpdef]; positivity - have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by - have hc : ((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo - rw [hMpdef] - have key : (NE : Real) / (DE : Real) = - ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) * - (((2 ^ 130 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real))) := by - push_cast; field_simp; ring - rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) - -- num bound: 2^1193·num ≤ NE, DE < 2^1193·den + 3·2^1193 - obtain ⟨hnumlo, _⟩ := numExpV_bracket hx hC hC0 htnn - obtain ⟨_, hdenhi⟩ := denExpV_bracket hx hC hC0 htnn - set num := (evTree x : Int) + int256 (todTree x) with hnumdef - set den := (evTree x : Int) - int256 (todTree x) with hdendef - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ den := den_ge_072 hx hC hC0 - have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden072 - have hdenR : (0:Real) < (den : Real) := by exact_mod_cast hdenpos - have hden072R : (61251667550081741634933722430035858604 : Real) ≤ (den : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hden072; push_cast at this; linarith [this] - have hnumloR : (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hnumlo; push_cast at this; linarith [this] - have hdenhiR : (DE : Real) < (2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193 := by - have := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hdenhi; push_cast at this; linarith [this] - have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by - rw [Real.sqrt_le_iff]; constructor <;> norm_num - have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ - have hMp_le : Mp ≤ 14144 / 14143 := by - rw [hMpdef, div_le_div_iff₀ (by norm_num) (by norm_num)] - have h130 : (14144 : Real) ≤ 2 ^ 130 := by - rw [show (2:Real) ^ 130 = 1361129467683753853853498429727072845824 from by norm_num]; norm_num - nlinarith [h130] - have hsM_le : Real.sqrt 2 * Mp ≤ 14144 / 10000 := by - have hMpnn : (0:Real) ≤ Mp := by rw [hMpdef]; positivity - calc Real.sqrt 2 * Mp ≤ (14143 / 10000) * (14144 / 14143) := - mul_le_mul hsqrt2_val hMp_le hMpnn (by norm_num) - _ = 14144 / 10000 := by norm_num - -- NE ≤ √2·Mp·DE ≤ (14144/10000)·DE - have hNE_le : (NE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by - have h1 : (NE : Real) ≤ Et * Mp * (DE : Real) := by - have := mul_le_mul_of_nonneg_right hNEDE_le (le_of_lt hDEpos) - rwa [div_mul_cancel₀ _ (ne_of_gt hDEpos)] at this - have h2 : Et * Mp * (DE : Real) ≤ Real.sqrt 2 * Mp * (DE : Real) := by - apply mul_le_mul_of_nonneg_right _ (le_of_lt hDEpos) - exact mul_le_mul_of_nonneg_right hEtsqrt2 (le_of_lt hMp_pos) - linarith [h1, h2] - -- num ≤ (14144/10000)·(den+3) - have hnum_le : (num : Real) ≤ (14144 / 10000) * ((den : Real) + 3) := by - have hp : (0:Real) < (2 ^ 1193 : Real) := by positivity - rw [← mul_le_mul_left hp] - calc (2 ^ 1193 : Real) * (num : Real) ≤ (NE : Real) := hnumloR - _ ≤ Real.sqrt 2 * Mp * (DE : Real) := hNE_le - _ ≤ (14144 / 10000) * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := by - calc Real.sqrt 2 * Mp * (DE : Real) - ≤ (14144 / 10000) * (DE : Real) := mul_le_mul_of_nonneg_right hsM_le (le_of_lt hDEpos) - _ ≤ (14144 / 10000) * ((2 ^ 1193 : Real) * (den : Real) + 3 * 2 ^ 1193) := - mul_le_mul_of_nonneg_left (le_of_lt hdenhiR) (by norm_num) - _ = (2 ^ 1193 : Real) * ((14144 / 10000) * ((den : Real) + 3)) := by ring - -- 100·num ≤ 145·den as Real: 100·(14144/10000)(den+3) ≤ 145·den ⟺ den huge - have hkey : (100 : Real) * (num : Real) ≤ 145 * (den : Real) := by - have h1 : (100 : Real) * (num : Real) ≤ 100 * ((14144 / 10000) * ((den : Real) + 3)) := - mul_le_mul_of_nonneg_left hnum_le (by norm_num) - nlinarith [h1, hden072R] - have : ((100 * num : Int) : Real) ≤ ((145 * den : Int) : Real) := by push_cast; linarith [hkey] - exact_mod_cast this +/-! ## The `r0` bracket on the nonneg half -/ -/-- `r0` is bracketed on the nonneg half: `2¹²⁶ ≤ r0 ≤ 1.45·2¹²⁶` (so `2¹²⁶+r0 ≤ 2.45·2¹²⁶`). -/ +/-- `r0` is bracketed on the nonneg half: `2¹²⁶ ≤ r0` and `100·r0 ≤ 145·2¹²⁶`. -/ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : @@ -198,7 +85,7 @@ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by + have hden072 : (61251667532612381706986956632087880162 : Int) ≤ ev - tod := by have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 -- tod ≥ 0 on nonneg half @@ -222,197 +109,246 @@ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) have hchain : 100 * r0 * (ev - tod) ≤ 145 * 2 ^ 126 * (ev - tod) := by nlinarith [h1, h2] exact le_of_mul_le_mul_right hchain hdenpos -/-- **Joint cert-ratio under (nonneg half):** `2¹²⁶·NE − r0·DE ≤ 7·DE`. The shared even truncation -`Ee·(2¹²⁶−r0) ≤ 0` (since `r0 ≥ 2¹²⁶`) is dropped; the floor `2¹²⁶·num − r0·den < den` gives the -`2¹¹⁹³·den` term, and the binding tod truncation `Et' ≤ (2¹¹⁹³ + W_od·2¹⁰³⁹·t)·(2¹²⁶+r0)` is small -because `t ≤ H128` is far below `2¹²⁸`. -/ -theorem r0_certRatio_under_nonneg {x : Nat} (hx : x < 2 ^ 256) +/-! ## Link 1 (under side): the grid rational vs `r0` -/ + +/-- **Link-1 under (nonneg half)**: `1000·(2¹²⁶·NUMv − r0·DENv) ≤ 6001·DENv`. The floor residual +costs one denominator; the odd-truncation carry `(2⁶³⁸ + Wod·2⁴⁸⁰·t)·(2¹²⁶ + r0)` fits in five +(`t ≤ H128`, `r0 ≤ 1.45·2¹²⁶`, `den ≥ 0.72·2¹²⁶`). -/ +theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ - 6 * evalPoly ExpCertV.denExpV (int256 (tTree x)) + 32 * 2 ^ 1193 := by - obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hevlo, _⟩ := evNumVPoly_bracket hx hC hC0 - have htodub := todNumV_ub hx hC hC0 htnn + 1000 * (2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - + int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x))) ≤ + 6001 * DENv (vTree x) (int256 (tTree x)) := by + obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 + obtain ⟨_, htOp_hi⟩ := tOd_bracket_nonneg hx hC hC0 htnn obtain ⟨hr0lo, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn - obtain ⟨hdenlo, _⟩ := denExpV_bracket hx hC hC0 htnn - have hDElb := denExpV_lb hx hC hC0 htnn - rw [evalNumExpV, evalDenExpV] - set t := int256 (tTree x) with htdef + obtain ⟨hDEN_ge, _⟩ := DENv_runtime_bracket hx hC hC0 htnn + obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have hden := den_ge_072 hx hC hC0 + have hLHS : 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - + int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) ≤ + 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) + + (2 ^ 638 + 1075052609 * 2 ^ 480 * int256 (tTree x)) * (2 ^ 126 + int256 (r0Tree x)) := by + unfold NUMv DENv + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set t := int256 (tTree x) with htdef + set Ep := (evNumV (vTree x) : Int) with hEpdef + set Op := (odNumV (vTree x) : Int) with hOpdef + have h2126r0_np : (2:Int) ^ 126 - r0 ≤ 0 := by linarith [hr0lo] + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] + -- Ep·2^110·(2^126−r0) ≤ 2^638·ev·(2^126−r0) + have hterm1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ 2 ^ 638 * ev * (2 ^ 126 - r0) := by + apply mul_le_mul_of_nonpos_right _ h2126r0_np + nlinarith [hEp_lo] + -- t·Op·(2^126+r0) ≤ (2^638·tod + 2^638 + Wod·2^480·t)·(2^126+r0) + have hterm2 : t * Op * (2 ^ 126 + r0) ≤ + (2 ^ 638 * tod + 2 ^ 638 + 1075052609 * 2 ^ 480 * t) * (2 ^ 126 + r0) := + mul_le_mul_of_nonneg_right htOp_hi hr0p_nn + -- floor: 2^126·num − r0·den < den, scaled by 2^638 + have hfloor : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by + linarith [hfloor_hi] + have hfloor638 : (2:Int) ^ 638 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) ≤ + 2 ^ 638 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) + nlinarith [hterm1, hterm2, hfloor638] + -- budget the two additive pieces against DENv set r0 := int256 (r0Tree x) with hr0def + set t := int256 (tTree x) with htdef + set den := (evTree x : Int) - int256 (todTree x) with hdendef + set D := DENv (vTree x) t with hDdef + have hA : 2 ^ 638 * den ≤ D + 2 * 2 ^ 638 := by rw [hDdef]; linarith [hDEN_ge] + have hDlow : (2:Int) ^ 638 * (61251667532612381706986956632087880162 - 2) ≤ D := by + have h1 : (2:Int) ^ 638 * (61251667532612381706986956632087880162 - 2) ≤ + 2 ^ 638 * den - 2 * 2 ^ 638 := by nlinarith [hden] + rw [hDdef]; linarith [h1, hDEN_ge] + have hB : (2 ^ 638 + 1075052609 * 2 ^ 480 * t) * (2 ^ 126 + r0) ≤ 5 * D := by + have hcoef : 2 ^ 638 + 1075052609 * 2 ^ 480 * t ≤ + 2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199 := by + have := mul_le_mul_of_nonneg_left hthi (by positivity : (0:Int) ≤ 1075052609 * 2 ^ 480) + linarith [this] + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [(r0_bracket_nonneg hx hC hC0 htnn).1] + have h1 : (2 ^ 638 + 1075052609 * 2 ^ 480 * t) * (2 ^ 126 + r0) ≤ + (2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199) * + (2 ^ 126 + r0) := mul_le_mul_of_nonneg_right hcoef hr0p_nn + have h2 : 100 * ((2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199) * + (2 ^ 126 + r0)) ≤ + (2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199) * + (245 * 2 ^ 126) := by + have hr0cap : 100 * (2 ^ 126 + r0) ≤ 245 * 2 ^ 126 := by linarith [hr0hi145] + nlinarith [hr0cap] + have h3 : (2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199) * + (245 * 2 ^ 126) ≤ 500 * (2 ^ 638 * (61251667532612381706986956632087880162 - 2)) := by + norm_num + have h4 : (500 : Int) * (2 ^ 638 * (61251667532612381706986956632087880162 - 2)) ≤ 500 * D := + mul_le_mul_of_nonneg_left hDlow (by norm_num) + linarith [h1, h2, h3, h4] + have hC2000 : (2000 : Int) * 2 ^ 638 ≤ D := by + have : (2000 : Int) * 2 ^ 638 ≤ 2 ^ 638 * (61251667532612381706986956632087880162 - 2) := by + norm_num + linarith [this, hDlow] + linarith [hLHS, hA, hB, hC2000] + +/-- **Link-1 under (nonpositive half)**: same `6001/1000` budget; the even-truncation width and the +`tod`-floor unit are absorbed by `DENv ≥ 2⁶³⁸·ev ≥ 2⁶³⁸·A0`. -/ +theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) + (htneg : int256 (tTree x) ≤ 0) : + 1000 * (2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - + int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x))) ≤ + 6001 * DENv (vTree x) (int256 (tTree x)) := by + obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 + obtain ⟨htOp_hi, _⟩ := tOd_bracket_neg hx hC hC0 htneg + have hr0le := r0_le_2126_neg hx hC hC0 htneg + obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 + have hDEN_ge := DENv_ge_ev_neg hx hC hC0 htneg + obtain ⟨hev_lo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 + obtain ⟨htod_lo125, _, _, _⟩ := todTree_bound hx hC hC0 + have hLHS : 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - + int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) ≤ + 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) + + 283678831804417 * 2 ^ 590 * 2 ^ 126 + 2 * 2 ^ 638 * 2 ^ 126 := by + unfold NUMv DENv + set r0 := int256 (r0Tree x) with hr0def + set ev := (evTree x : Int) with hevdef + set tod := int256 (todTree x) with htoddef + set t := int256 (tTree x) with htdef + set Ep := (evNumV (vTree x) : Int) with hEpdef + set Op := (odNumV (vTree x) : Int) with hOpdef + have hr0nn : (0:Int) ≤ r0 := by + have : (0:Int) < 2 ^ 123 := by positivity + linarith [hr0lo] + have h2126r0_nn : (0:Int) ≤ 2 ^ 126 - r0 := by linarith [hr0le] + have h2126r0_le : (2:Int) ^ 126 - r0 ≤ 2 ^ 126 := by linarith [hr0nn] + have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by positivity + have hr0p_le : (2:Int) ^ 126 + r0 ≤ 2 * 2 ^ 126 := by linarith [hr0le] + -- Ep·2^110·(2^126−r0) ≤ 2^638·ev·(2^126−r0) + Wev·2^590·2^126 + have hterm1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ + 2 ^ 638 * ev * (2 ^ 126 - r0) + 283678831804417 * 2 ^ 590 * 2 ^ 126 := by + have h1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ + (2 ^ 638 * ev + 283678831804417 * 2 ^ 590) * (2 ^ 126 - r0) := by + apply mul_le_mul_of_nonneg_right _ h2126r0_nn + nlinarith [hEp_hi] + have h2 : (283678831804417 : Int) * 2 ^ 590 * (2 ^ 126 - r0) ≤ + 283678831804417 * 2 ^ 590 * 2 ^ 126 := + mul_le_mul_of_nonneg_left h2126r0_le (by positivity) + nlinarith [h1, h2] + -- t·Op·(2^126+r0) ≤ (2^638·tod + 2^638)·(2^126+r0) ≤ 2^638·tod·(2^126+r0) + 2·2^638·2^126 + have hterm2 : t * Op * (2 ^ 126 + r0) ≤ + 2 ^ 638 * tod * (2 ^ 126 + r0) + 2 * 2 ^ 638 * 2 ^ 126 := by + have h1 : t * Op * (2 ^ 126 + r0) ≤ (2 ^ 638 * tod + 2 ^ 638) * (2 ^ 126 + r0) := + mul_le_mul_of_nonneg_right htOp_hi hr0p_nn + have h2 : (2:Int) ^ 638 * (2 ^ 126 + r0) ≤ 2 ^ 638 * (2 * 2 ^ 126) := + mul_le_mul_of_nonneg_left hr0p_le (by positivity) + nlinarith [h1, h2] + -- floor: 2^126·num − r0·den ≤ den, scaled + have hfloor : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by + linarith [hfloor_hi] + have hfloor638 : (2:Int) ^ 638 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) ≤ + 2 ^ 638 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) + nlinarith [hterm1, hterm2, hfloor638] + -- budget against DENv ≥ 2^638·ev ≥ 2^638·A0; den ≤ ev + 2^125 set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - set evP := evalPoly ExpCertV.evNumVPoly t with hevP - set todP := evalPoly ExpCertV.todNumV t with htodP - set DE := evP - todP with hDEdef - -- 2^126·NE − r0·DE = evP·(2^126−r0) + todP·(2^126+r0) - -- = 2^1193·[2^126·num − r0·den] + Ee·(2^126−r0) + Et'·(2^126+r0) - -- ≤ 2^1193·den + 0 + (2^1193 + W·2^1039·t)·(2^126+r0) - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 - have h2126r0_np : (2:Int) ^ 126 - r0 ≤ 0 := by linarith [hr0lo] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] - -- evP·(2^126−r0) ≤ 2^1193·ev·(2^126−r0) (evP ≥ 2^1193·ev, factor ≤ 0) - have hterm1 : evP * (2 ^ 126 - r0) ≤ 2 ^ 1193 * ev * (2 ^ 126 - r0) := - mul_le_mul_of_nonpos_right hevlo h2126r0_np - -- todP·(2^126+r0) ≤ (2^1193·tod + 2^1193 + W·2^1039·t)·(2^126+r0) (todP upper, factor ≥ 0) - have hterm2 : todP * (2 ^ 126 + r0) ≤ - (2 ^ 1193 * tod + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := - mul_le_mul_of_nonneg_right htodub hr0p_nn - -- floor: 2^126·num − r0·den < den, scaled by 2^1193: 2^1193·(2^126·num − r0·den) < 2^1193·den - have hfloor_lt : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) < (ev - tod) := by linarith [hfloor_hi] - have hfloor1193 : (2 ^ 1193 : Int) * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) < - 2 ^ 1193 * (ev - tod) := by - have := mul_lt_mul_of_pos_left hfloor_lt (by positivity : (0:Int) < 2 ^ 1193); linarith [this] - -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + (2^1193 + W·2^1039·t)·(2^126+r0) - have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ - 2 ^ 1193 * (ev - tod) + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by - have hid1 : 2 ^ 126 * (evP + todP) - r0 * DE = evP * (2 ^ 126 - r0) + todP * (2 ^ 126 + r0) := by - rw [hDEdef]; ring - have hid2 : 2 ^ 1193 * ev * (2 ^ 126 - r0) + (2 ^ 1193 * tod + 2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) - = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) - + (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) := by ring - rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] - -- now bound the RHS ≤ 6·DE. - -- (A) the floor residual `2^1193·den` is carried against `DE` with the tiny denExpV truncation - -- `32·2^1193` kept additively (it converts to < 2⁻¹¹⁹·DE downstream), so the floor costs only 1·DE. - have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 32 * 2 ^ 1193 := by - rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] - -- (B) (2^1193 + W·2^1039·t)·(2^126+r0) ≤ 5·DE. bound via t ≤ H128, 2^126+r0 ≤ 2.45·2^126. - have hDElb' : (2:Int)^1317 < DE := by rw [hDEdef, evalDenExpV] at *; linarith [hDElb] - obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - have htH : t ≤ 117932881612756647068972071382077242199 := hthi - -- 2^126 + r0 ≤ 2.45·2^126, i.e. 100·(2^126+r0) ≤ 245·2^126 - have hr0p_bound : 100 * (2 ^ 126 + r0) ≤ 245 * 2 ^ 126 := by linarith [hr0hi145] - have hBterm : (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) ≤ 5 * DE := by - have hDEden : 2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193 ≤ DE := by - rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] - have hden_lo : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - -- 2^1193 + W·2^1039·t ≤ 2^1193 + W·2^1039·H128 (t ≤ H128, t ≥ 0) - have hcoeff : 2 ^ 1193 + 69402657 * 2 ^ 1039 * t ≤ - 2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199 := by - have := mul_le_mul_of_nonneg_left htH (by positivity : (0:Int) ≤ 69402657 * 2 ^ 1039); linarith [this] - have hC0nn : (0:Int) ≤ 2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199 := by positivity - have hLHS : (2 ^ 1193 + 69402657 * 2 ^ 1039 * t) * (2 ^ 126 + r0) ≤ - (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0) := - mul_le_mul_of_nonneg_right hcoeff hr0p_nn - -- 100·(C0·(2^126+r0)) ≤ C0·245·2^126 - have hLHS2 : 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) ≤ - (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := by - have h := mul_le_mul_of_nonneg_left hr0p_bound hC0nn - have hid : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (100 * (2 ^ 126 + r0)) - = 100 * ((2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) := by ring - have hid2 : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) - = (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := rfl - linarith [h, hid] - -- key integer cert (common 2^1165 scale): C0·245·2^126 ≤ 500·(2^1193·(den−32)). - have hkey : (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) ≤ - 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by - -- factor everything to the common 2^1165 scale and compare coefficients - have hA : (2:Int) ^ 1193 * 2 ^ 126 = 2 ^ 154 * 2 ^ 1165 := by rw [← pow_add, ← pow_add] - have hpe2 : (2:Int) ^ 1039 * 2 ^ 126 = 2 ^ 1165 := by rw [← pow_add] - have hpe3 : (2:Int) ^ 1193 = 2 ^ 28 * 2 ^ 1165 := by rw [← pow_add] - have hp : (0:Int) < (2:Int) ^ 1165 := by positivity - -- the coefficient inequality, scaled by 2^1165 - have hcoeff_le : (245 * 2 ^ 154 + 245 * 69402657 * 117932881612756647068972071382077242199 : Int) ≤ - 500 * 2 ^ 28 * ((ev - tod) - 32) := by - have h154 : (2:Int)^154 = 22835963083295358096932575511191922182123945984 := by norm_num - have h28 : (2:Int)^28 = 268435456 := by norm_num - rw [h154, h28]; linarith [hden_lo] - have hscaled := mul_le_mul_of_nonneg_right hcoeff_le (le_of_lt hp) - -- rewrite both sides to the (·)·2^1165 form - calc (2 ^ 1193 + 69402657 * 2 ^ 1039 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) - = (245 * 2 ^ 154 + 245 * 69402657 * 117932881612756647068972071382077242199) * 2 ^ 1165 := by - linear_combination (245 : Int) * hA + (245 * 69402657 * 117932881612756647068972071382077242199 : Int) * hpe2 - _ ≤ (500 * 2 ^ 28 * ((ev - tod) - 32)) * 2 ^ 1165 := hscaled - _ = 500 * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) := by - linear_combination (-500 * ((ev - tod) - 32) : Int) * hpe3 - -- LHS ≤ C0·(2^126+r0); 100·that ≤ C0·245·2^126 ≤ 500·(2^1193 den − 32·2^1193) ≤ 500·DE; so LHS ≤ 5·DE - have h500 : (500 : Int) * (2 ^ 1193 * (ev - tod) - 32 * 2 ^ 1193) ≤ 500 * DE := by linarith [hDEden] - linarith [hLHS, hLHS2, hkey, h500] - linarith [hcombine, hden2, hBterm] + set D := DENv (vTree x) (int256 (tTree x)) with hDdef + have hev : (103786963397729689639908782561058906594 : Int) ≤ ev := by + have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ ev := by + rw [hevdef]; exact_mod_cast hev_lo + rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 from by norm_num] at this + exact this + have hden_le : ev - tod ≤ ev + 2 ^ 125 := by + have : -(2 ^ 125 : Int) ≤ tod := htod_lo125 + linarith [this] + have hDev : 2 ^ 638 * ev ≤ D := hDEN_ge + -- 1000·(2^638·(ev + 2^125) + Wev·2^590·2^126 + 2·2^638·2^126) ≤ 1000·2^638·ev + 5001·2^638·A0 + have hlit : 1000 * (2 ^ 638 * 2 ^ 125 + 283678831804417 * 2 ^ 590 * 2 ^ 126 + + 2 * 2 ^ 638 * 2 ^ 126) ≤ + (5001 : Int) * (2 ^ 638 * 103786963397729689639908782561058906594) := by + norm_num + have hAev : (5001 : Int) * (2 ^ 638 * 103786963397729689639908782561058906594) ≤ 5001 * D := by + have h1 : (2:Int) ^ 638 * 103786963397729689639908782561058906594 ≤ 2 ^ 638 * ev := + mul_le_mul_of_nonneg_left hev (by positivity) + have := le_trans h1 hDev + nlinarith [this] + nlinarith [hLHS, hden_le, hDev, hlit, hAev] -/-- **The joint per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 13/2`. From the joint -cert-ratio under (`2¹²⁶·NE − r0·DE ≤ 6·DE + 32·2¹¹⁹³`, so `≤ r0 + 6001/1000`), the not-too-below cert -(`exp ≤ (NE/DE)·M⁺`, the `Mpp` factor `≤ 1/10` via `r0 ≤ 1.45·2¹²⁶`), and the under-direction gap-1 -(`exp(rt) ≤ √2`, `rt − t/2¹²⁸ < 33/(32·2¹²⁸)`, so `≤ 37/100`). -/ +/-! ## The per-point deficit (nonneg half) -/ + +/-- **The per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 67/10`: link-1 `≤ 6001/1000`, the +`Mp` factor `≤ 1/20`, the under gap `≤ 37/100`; the granularity is free on this half. -/ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 13 / 2 := by - have hunder := r0_certRatio_under_nonneg hx hC hC0 htnn + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 67 / 10 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 + have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef + set v := vTree x with hvdef + set r0 := int256 (r0Tree x) with hr0def have htdom : t ≤ (ExpCertV.H128 : Int) := by rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by unfold ExpCertV.H128; norm_num] exact hthi - have hDElb := denExpV_lb hx hC hC0 htnn - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int - set r0 := int256 (r0Tree x) with hr0def - -- 2^126·NE/DE ≤ r0 + 6001/1000 (the cert-ratio `6·DE + 32·2^1193`, with 32·2^1193 ≤ DE/1000) - have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ - 6 * (DE : Real) + 32 * 2 ^ 1193 := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] - have h32small : (32 : Real) * 2 ^ 1193 ≤ (1 / 1000) * (DE : Real) := by - have hDE1317 : (2 : Real) ^ 1317 < (DE : Real) := by exact_mod_cast hDElb - have hpow : (32 : Real) * 2 ^ 1193 * 1000 ≤ 2 ^ 1317 := by - rw [show (2 : Real) ^ 1317 = 2 ^ 124 * 2 ^ 1193 from by rw [← pow_add]] - nlinarith [(by norm_num : (32000 : Real) ≤ 2 ^ 124), (by positivity : (0 : Real) ≤ (2 : Real) ^ 1193)] - linarith [hpow, hDE1317] - have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 6001 / 1000 := by - rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos, h32small] - -- certUp: exp(t/2^128) ≤ (NE/DE)·Mpp + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom + have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by + have : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE + exact_mod_cast this + -- link 1: 2^126·Qv ≤ r0 + 6001/1000 + have hlink1 := link1_under_int hx hC hC0 htnn + have hQv_le : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (r0 : Real) + 6001 / 1000 := by + rw [mul_div_assoc', div_le_iff₀ hDR] + have hR := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlink1 + push_cast at hR + nlinarith [hR, hDR] + -- link 2 (free): NE/DE ≤ Qv + obtain ⟨hgran1, _⟩ := gran_over_pair hx hC hC0 htnn + -- link 3: Et ≤ (NE/DE)·Mpp ≤ Qv·Mpp; Mpp excess ≤ 1/20 via r0 ≤ 1.45·2^126 have hcertup := certUp_real htnn htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by - have := certNE_nonneg htnn htdom; exact_mod_cast this set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - set Mpp : Real := (2 ^ 130 + 1 : Real) / (2 ^ 130 : Real) with hMppdef + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + set Mpp : Real := ((2 ^ 131 : Real) + 1) / (2 ^ 131 : Real) with hMppdef have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mpp := by - have hc : Et ≤ ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / - (((2 ^ 130 : Int) : Real) * (DE : Real)) := hcertup + have hc : Et ≤ ((2 ^ 131 + 1 : Int) : Real) * (NE : Real) / + (((2 ^ 131 : Int) : Real) * (DE : Real)) := hcertup rw [hMppdef] - have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 + 1 : Real) / (2 ^ 130 : Real)) = - ((2 ^ 130 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 130 : Int) : Real) * (DE : Real)) := by + have key : ((NE : Real) / (DE : Real)) * (((2 ^ 131 : Real) + 1) / (2 ^ 131 : Real)) = + ((2 ^ 131 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 131 : Int) : Real) * (DE : Real)) := by push_cast; field_simp; ring rw [key]; exact hc - have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) - have hMpp1 : Mpp - 1 = 1 / (2 ^ 130 : Real) := by rw [hMppdef]; field_simp - -- Et ≤ √2 (nonneg half) - have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn - rw [← hEtdef] at hEtsqrt2 - have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num - have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ - -- 2^126·Et ≤ 2^126·(NE/DE)·Mpp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mpp−1) ≤ (r0+6001/1000) + 1/10 - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 10 := by - have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) := - mul_le_mul_of_nonneg_left hEt_le (by positivity) - have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mpp) = - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) := by ring - -- 2^126·(NE/DE)·(Mpp−1) ≤ 1/10. NE/DE·2^126 ≤ r0+6001/1000 ≤ 1.45·2^126+6.001; ·(1/2^130) ≈ 1/16. - have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mpp - 1) ≤ 1 / 10 := by + have hMpp_nn : (0:Real) ≤ Mpp := by rw [hMppdef]; positivity + have hEt_le_Qv : Et ≤ ((NUMv v t : Real) / (DENv v t : Real)) * Mpp := + le_trans hEt_le (mul_le_mul_of_nonneg_right hgran1 hMpp_nn) + have hMpp1 : Mpp - 1 = 1 / (2 ^ 131 : Real) := by rw [hMppdef]; field_simp + obtain ⟨_, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn + have hr0R : (r0 : Real) ≤ (145 / 100) * (2 ^ 126 : Real) := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0hi145 + push_cast at h + linarith [h] + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 20 := by + have h1 : (2 ^ 126 : Real) * Et ≤ + (2 ^ 126 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) := + mul_le_mul_of_nonneg_left hEt_le_Qv (by positivity) + have h2 : (2 ^ 126 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) = + (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) := by ring + have h3 : ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) ≤ 1 / 20 := by rw [hMpp1] - obtain ⟨_, hr0hi⟩ := r0_bracket_nonneg hx hC hC0 htnn - have hr0R : (r0 : Real) ≤ (145 / 100) * (2 ^ 126 : Real) := by - have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0hi; push_cast at h; linarith [h] - have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn - have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (145 / 100) * (2 ^ 126 : Real) + 6001 / 1000 := by - linarith [hr0_ge, hr0R] - calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / (2 ^ 130 : Real)) - ≤ ((145 / 100) * (2 ^ 126 : Real) + 6001 / 1000) * (1 / (2 ^ 130 : Real)) := - mul_le_mul_of_nonneg_right hlt (by positivity) - _ ≤ 1 / 10 := by norm_num - linarith [h1, h2 ▸ h1, h3, hr0_ge] - -- gap-1 (under, tight): Ert − Et ≤ (rt − t/2^128)·Ert, rt − t/2^128 < 33/(32·2^128), Ert ≤ √2 + have hcap : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (145 / 100) * (2 ^ 126 : Real) + 6001 / 1000 := by linarith [hQv_le, hr0R] + have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / (2 ^ 131 : Real)) + have hfin : ((145 / 100) * (2 ^ 126 : Real) + 6001 / 1000) * (1 / (2 ^ 131 : Real)) ≤ + 1 / 20 := by norm_num + linarith [this, hfin] + linarith [h1, h2 ▸ h1, h3, hQv_le] + -- link 4 (under gap): 2^126·(Ert − Et) ≤ 37/100 set Ert := Real.exp (reducedArg x) with hErtdef have hgapunder := reducedArg_close_under hx hC hC0 have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ @@ -427,204 +363,89 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 37 / 100 := by norm_num + have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 37 / 100 := by + norm_num linarith [h1, h2, h3] - -- assemble: 2^126·Ert = 2^126·Et + 2^126·(Ert−Et) ≤ (r0 + 6001/1000 + 1/10) + 37/100 < r0 + 13/2 - have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 13 / 2 - linarith [hEt_bound, hgap126, hdist] + have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by + ring + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 67 / 10 + have hsum : (6001 : Real) / 1000 + 1 / 20 + 37 / 100 ≤ 67 / 10 := by norm_num + linarith [hEt_bound, hgap126, hdist, hsum] -/-- `r0 ≤ 2¹²⁶` on the negative half (num ≤ den ⟺ tod ≤ 0). -/ -theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - int256 (r0Tree x) ≤ 2 ^ 126 := by - obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 - set r0 := int256 (r0Tree x) with hr0def - set ev := (evTree x : Int) with hevdef - set tod := int256 (todTree x) with htoddef - have hden072 : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 - have htodnp : tod ≤ 0 := by - obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn - nlinarith [htodlo, this] - -- r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den) - have hnumden : r0 * (ev - tod) ≤ 2 ^ 126 * (ev - tod) := by - have h1 : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo - nlinarith [h1, htodnp, (by positivity : (0:Int) ≤ (2:Int)^126)] - exact le_of_mul_le_mul_right hnumden hdenpos - -/-- **Joint cert-ratio under (negative half):** `2¹²⁶·NE − r0·DE ≤ 6·DE + 2·2¹¹⁹³`. The floor -residual is carried against `DE` with the tiny `2·2¹¹⁹³` truncation additive; the even truncation -`Ee·(2¹²⁶−r0)` and the tod truncation `Et'·(2¹²⁶+r0)` fit in `1·DE` and `4·DE`. -/ -theorem r0_certRatio_under_neg {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : - 2 ^ 126 * evalPoly ExpCertV.numExpV (int256 (tTree x)) - - int256 (r0Tree x) * evalPoly ExpCertV.denExpV (int256 (tTree x)) ≤ - 6 * evalPoly ExpCertV.denExpV (int256 (tTree x)) + 2 * 2 ^ 1193 := by - obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 - obtain ⟨hevlo, hevhi⟩ := evNumVPoly_bracket hx hC hC0 - obtain ⟨_, htodhi⟩ := todNumV_bracket_neg hx hC hC0 htneg - have hr0le := r0_le_2126_neg hx hC hC0 htneg - obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 - obtain ⟨hdenlo, _⟩ := denExpV_bracket_neg hx hC hC0 htneg - have hDElb := denExpV_lb_neg hx hC hC0 htneg - rw [evalNumExpV, evalDenExpV] - set t := int256 (tTree x) with htdef - set r0 := int256 (r0Tree x) with hr0def - set ev := (evTree x : Int) with hevdef - set tod := int256 (todTree x) with htoddef - set evP := evalPoly ExpCertV.evNumVPoly t with hevP - set todP := evalPoly ExpCertV.todNumV t with htodP - set DE := evP - todP with hDEdef - have hden_lo : (61251667550081741634933722430035858604 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this - -- on the neg half tod ≤ 0, so den = ev − tod ≥ ev ≥ A4 - have htod_np : tod ≤ 0 := by - obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 - have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have hp : t * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn - have h2 : (2 ^ 128 : Int) * tod ≤ 2 ^ 128 * 0 := by simpa using le_trans htodlo hp - exact le_of_mul_le_mul_left h2 (by norm_num) - have hden_A4 : (103786963415199049567855548359006885036 : Int) ≤ ev - tod := by - obtain ⟨hevlo', _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - have hev : (103786963415199049567855548359006885036 : Int) ≤ ev := by - rw [hevdef]; have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo' - rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 from by norm_num] at this - exact this - linarith [hev, htod_np] - have h2126r0_nn : (0:Int) ≤ 2 ^ 126 - r0 := by linarith [hr0le] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] - -- Ee = evP − 2^1193·ev ∈ [0, W_ev). evP·(2^126−r0) ≤ (2^1193·ev + W_ev)·(2^126−r0) - have hterm1 : evP * (2 ^ 126 - r0) ≤ (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) := - mul_le_mul_of_nonneg_right (le_of_lt hevhi) h2126r0_nn - -- Et' = todP − 2^1193·tod < 2·2^1193 ⟹ todP < 2^1193·tod + 2·2^1193; todP·(2^126+r0) ≤ (2^1193·tod+2·2^1193)·(2^126+r0) - have hterm2 : todP * (2 ^ 126 + r0) ≤ (2 ^ 1193 * tod + 2 * 2 ^ 1193) * (2 ^ 126 + r0) := - mul_le_mul_of_nonneg_right (le_of_lt htodhi) hr0p_nn - -- floor: 2^126·num − r0·den < den ⟹ 2^1193·(2^126·num − r0·den) < 2^1193·den - have hfloor_lt : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) < (ev - tod) := by linarith [hfloor_hi] - have hfloor1193 : (2 ^ 1193 : Int) * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) < - 2 ^ 1193 * (ev - tod) := by - have := mul_lt_mul_of_pos_left hfloor_lt (by positivity : (0:Int) < 2 ^ 1193); linarith [this] - -- combine: 2^126·NE − r0·DE ≤ 2^1193·den + W_ev·(2^126−r0) + 2·2^1193·(2^126+r0) - have hcombine : 2 ^ 126 * (evP + todP) - r0 * DE ≤ - 2 ^ 1193 * (ev - tod) + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by - have hid1 : 2 ^ 126 * (evP + todP) - r0 * DE = evP * (2 ^ 126 - r0) + todP * (2 ^ 126 + r0) := by - rw [hDEdef]; ring - have hid2 : (2 ^ 1193 * ev + 1130577 * 2 ^ 1173) * (2 ^ 126 - r0) - + (2 ^ 1193 * tod + 2 * 2 ^ 1193) * (2 ^ 126 + r0) - = 2 ^ 1193 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) - + 1130577 * 2 ^ 1173 * (2 ^ 126 - r0) + 2 * 2 ^ 1193 * (2 ^ 126 + r0) := by ring - rw [hid1]; linarith [hterm1, hterm2, hfloor1193, hid2] - -- bound RHS by 6·DE + 2·2^1193. DE ≥ 2^1193·(den−2), den ≥ den_lo. - have hDEden : 2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193 ≤ DE := by - rw [hDEdef, evalDenExpV] at *; linarith [hdenlo] - -- (A) the floor residual `2^1193·den` is carried against `DE` with the tiny `2·2^1193` truncation - -- kept additively (it costs only 1·DE here, vs the loose `2·DE`). - have hden2 : 2 ^ 1193 * (ev - tod) ≤ DE + 2 * 2 ^ 1193 := by linarith [hDEden] - -- (B) W_ev·(2^126−r0) ≤ 1·DE (2^126−r0 ≤ 2^126; W_ev·2^126 = 1130577·2^1299; vs DE ≥ 2^1193·(den−2)) - have hBterm : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1 * DE := by - have hle : (1130577 : Int) * 2 ^ 1173 * (2 ^ 126 - r0) ≤ 1130577 * 2 ^ 1173 * 2 ^ 126 := - mul_le_mul_of_nonneg_left (by linarith [hr0lo]) (by positivity) - -- 1130577·2^1173·2^126 = 1130577·2^1299 ; DE ≥ 2^1193·(den−2); 1130577·2^106 ≤ (den−2) - have hkey : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 ≤ 1 * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) := by - have hA : (2:Int) ^ 1173 * 2 ^ 126 = 2 ^ 106 * 2 ^ 1193 := by rw [← pow_add, ← pow_add] - have hp : (0:Int) < (2:Int) ^ 1193 := by positivity - have heL : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 = (1130577 * 2 ^ 106) * 2 ^ 1193 := by - have e : (1130577 : Int) * 2 ^ 1173 * 2 ^ 126 = 1130577 * (2 ^ 1173 * 2 ^ 126) := by ring - rw [e, hA]; ring - have heR : (1 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (1 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring - rw [heL, heR, mul_le_mul_right hp] - have h106 : (1130577 * 2 ^ 106 : Int) = 91723303209870778371580046068760444928 := by norm_num - calc (1130577 * 2 ^ 106 : Int) = 91723303209870778371580046068760444928 := h106 - _ ≤ 1 * ((ev - tod) - 2) := by linarith [hden_A4] - linarith [hle, hkey] - -- (C) 2·2^1193·(2^126+r0) ≤ 2·DE. (2^126+r0) ≤ 2·2^126 (r0 ≤ 2^126); 2·2^1193·2·2^126 = 4·2^1319; vs 2·DE. - have hCterm : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 4 * DE := by - have hle : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + r0) ≤ 2 * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) := - mul_le_mul_of_nonneg_left (by linarith [hr0le]) (by positivity) - have hkey : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) ≤ 4 * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) := by - have hA : (2:Int) ^ 1193 * 2 ^ 126 = 2 ^ 1319 := by rw [← pow_add] - have hp : (0:Int) < (2:Int) ^ 1193 := by positivity - -- LHS = 2·2^1193·2·2^126 = 4·2^1319 = (4·2^126)·2^1193; RHS = 2·((den)−2)·2^1193 - have heL : (2 : Int) * 2 ^ 1193 * (2 ^ 126 + 2 ^ 126) = (4 * 2 ^ 126) * 2 ^ 1193 := by ring - have heR : (4 : Int) * (2 ^ 1193 * (ev - tod) - 2 * 2 ^ 1193) = (4 * ((ev - tod) - 2)) * 2 ^ 1193 := by ring - rw [heL, heR, mul_le_mul_right hp] - have h126 : (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := by norm_num - calc (4 * 2 ^ 126 : Int) = 340282366920938463463374607431768211456 := h126 - _ ≤ 4 * ((ev - tod) - 2) := by linarith [hden_A4] - linarith [hle, hkey] - linarith [hcombine, hden2, hBterm, hCterm] +/-! ## The per-point deficit (nonpositive half) -/ -/-- **Per-point deficit (tight, negative half).** `2¹²⁶·exp(rt) ≤ r0 + 13/2` for `t ≤ 0`. From the -cert-ratio under (`2¹²⁶·NE − r0·DE ≤ 6·DE + 2·2¹¹⁹³`, so `≤ r0 + 6001/1000`), the `Mp` factor -(`≤ 1/10` via `r0 ≤ 2¹²⁶`), and the under-direction gap-1 (`exp(rt) ≤ √2`, so `≤ 37/100`). -/ +/-- **The per-point deficit (nonpositive half).** `2¹²⁶·exp(rt) ≤ r0 + 67/10`: link-1 `≤ 6001/1000`, +the `Mp`-folded granularity `≤ 1685843742692980488/10¹⁹`, the `Mp` factor `≤ 1/20` +(via `r0 ≤ 2¹²⁶`), the under gap `≤ 37/100`. -/ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 13 / 2 := by - have hunder := r0_certRatio_under_neg hx hC hC0 htneg + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 67 / 10 := by have htdom := tdom_neg hx hC hC0 htneg + have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef - have hDElb := denExpV_lb_neg hx hC hC0 htneg - set NE := evalPoly ExpCertV.numExpV t with hNEdef - set DE := evalPoly ExpCertV.denExpV t with hDEdef - have hDEpos_int : (0 : Int) < DE := by - have : (0:Int) < 2 ^ 1317 := by positivity - linarith [hDElb, this] - have hDEpos : (0 : Real) < (DE : Real) := by exact_mod_cast hDEpos_int + set v := vTree x with hvdef set r0 := int256 (r0Tree x) with hr0def - have hunderR : (2 ^ 126 : Real) * (NE : Real) - (r0 : Real) * (DE : Real) ≤ - 6 * (DE : Real) + 2 * 2 ^ 1193 := by - have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hunder; push_cast at this; linarith [this] - have h2small : (2 : Real) * 2 ^ 1193 ≤ (1 / 1000) * (DE : Real) := by - have hDE1317 : (2 : Real) ^ 1317 < (DE : Real) := by exact_mod_cast hDElb - have hpow : (2 : Real) * 2 ^ 1193 * 1000 ≤ 2 ^ 1317 := by - rw [show (2 : Real) ^ 1317 = 2 ^ 124 * 2 ^ 1193 from by rw [← pow_add]] - nlinarith [(by norm_num : (2000 : Real) ≤ 2 ^ 124), (by positivity : (0 : Real) ≤ (2 : Real) ^ 1193)] - linarith [hpow, hDE1317] - have hr0_ge : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (r0 : Real) + 6001 / 1000 := by - rw [mul_div_assoc', div_le_iff₀ hDEpos]; nlinarith [hunderR, hDEpos, h2small] - -- certUp_real_neg: exp(t/2^128) ≤ (NE/DE)·Mp, Mp = 2^130/(2^130−1) - have hcu := certUp_real_neg htneg htdom - obtain ⟨hNEpos, _⟩ := certNE_pos_neg_aux htneg htdom - have hNEnn : (0 : Real) ≤ (NE : Real) := by have : (0:Int) ≤ NE := le_of_lt hNEpos - exact_mod_cast this + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htneg + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD + have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos + have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htneg htdom).2 + have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos + -- link 1: 2^126·Qv ≤ r0 + 6001/1000 + have hlink1 := link1_under_int_neg hx hC hC0 htneg + have hQv_le : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (r0 : Real) + 6001 / 1000 := by + rw [mul_div_assoc', div_le_iff₀ hDR] + have hR := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlink1 + push_cast at hR + nlinarith [hR, hDR] + -- links 2+3: Et ≤ (NE/DE)·Mp = Qv·Mp + (NE/DE − Qv)·Mp + have hcertup := certUp_real_neg htneg htdom set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - set Mp : Real := (2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1) with hMpdef + set NE := evalPoly ExpCertV.numExpV t with hNEdef + set DE := evalPoly ExpCertV.denExpV t with hDEdef + set Mp : Real := (2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1) with hMpdef have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mp := by rw [hMpdef] - have key : ((NE : Real) / (DE : Real)) * ((2 ^ 130 : Real) / ((2 ^ 130 : Real) - 1)) = - ((2 ^ 130 : Int) : Real) * (NE : Real) / (((2 ^ 130 - 1 : Int) : Real) * (DE : Real)) := by + have key : ((NE : Real) / (DE : Real)) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) = + ((2 ^ 131 : Int) : Real) * (NE : Real) / + (((2 ^ 131 - 1 : Int) : Real) * (DE : Real)) := by push_cast; field_simp; ring - rw [key]; exact hcu - have hNEDE_nn : (0 : Real) ≤ (NE : Real) / (DE : Real) := div_nonneg hNEnn (le_of_lt hDEpos) - have hMp1 : Mp - 1 = 1 / ((2 ^ 130 : Real) - 1) := by rw [hMpdef]; field_simp - -- 2^126·Et ≤ 2^126·(NE/DE)·Mp = 2^126·(NE/DE) + 2^126·(NE/DE)·(Mp−1) ≤ (r0+6001/1000) + 1/10 - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 10 := by + rw [key]; exact hcertup + obtain ⟨_, hgran2⟩ := gran_under_pair hx hC hC0 htneg + have hMp_nn : (0:Real) ≤ Mp := by + rw [hMpdef] + have : (0:Real) < (2 ^ 131 : Real) - 1 := by norm_num + positivity + have hMp1 : Mp - 1 = 1 / ((2 ^ 131 : Real) - 1) := by rw [hMpdef]; field_simp + have hr0le := r0_le_2126_neg hx hC hC0 htneg + have hr0R : (r0 : Real) ≤ (2 ^ 126 : Real) := by + have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le + push_cast at h + linarith [h] + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 20 + + 1685843742692980488 / 10000000000000000000 := by have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := mul_le_mul_of_nonneg_left hEt_le (by positivity) - have h2 : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) := by ring - have h3 : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (Mp - 1) ≤ 1 / 10 := by + -- split: 2^126·(NE/DE)·Mp = 2^126·Qv + 2^126·Qv·(Mp−1) + 2^126·Mp·(NE/DE − Qv) + have hsplit : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = + (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) + + (2 ^ 126 : Real) * Mp * + ((NE : Real) / (DE : Real) - (NUMv v t : Real) / (DENv v t : Real)) := by ring + have hMpterm : ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) ≤ + 1 / 20 := by rw [hMp1] - have hr0R : (r0 : Real) ≤ (2 ^ 126 : Real) := by - have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr (r0_le_2126_neg hx hC hC0 htneg) - rw [show ((2 ^ 126 : Int) : Real) = (2 ^ 126 : Real) from by push_cast; ring] at h; exact h - have hpos : (0:Real) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_nonneg (by positivity) hNEDE_nn - have hlt : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ (2 ^ 126 : Real) + 6001 / 1000 := by - linarith [hr0_ge, hr0R] - calc (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) * (1 / ((2 ^ 130 : Real) - 1)) - ≤ ((2 ^ 126 : Real) + 6001 / 1000) * (1 / ((2 ^ 130 : Real) - 1)) := - mul_le_mul_of_nonneg_right hlt (by positivity) - _ ≤ 1 / 10 := by norm_num - linarith [h1, h2 ▸ h1, h3, hr0_ge] - -- gap-1 (under, tight): Ert ≤ √2 + have hcap : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (2 ^ 126 : Real) + 6001 / 1000 := by linarith [hQv_le, hr0R] + have := mul_le_mul_of_nonneg_right hcap + (by positivity : (0:Real) ≤ 1 / ((2 ^ 131 : Real) - 1)) + have hfin : ((2 ^ 126 : Real) + 6001 / 1000) * (1 / ((2 ^ 131 : Real) - 1)) ≤ 1 / 20 := by + rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] + norm_num + linarith [this, hfin] + linarith [h1, hsplit ▸ h1, hMpterm, hgran2, hQv_le] + -- link 4 (under gap): 2^126·(Ert − Et) ≤ 37/100 set Ert := Real.exp (reducedArg x) with hErtdef have hgapunder := reducedArg_close_under hx hC hC0 have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ @@ -639,18 +460,120 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 37 / 100 := by norm_num + have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 37 / 100 := by + norm_num linarith [h1, h2, h3] - have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 13 / 2 - linarith [hEt_bound, hgap126, hdist] + have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by + ring + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 67 / 10 + have hsum : (6001 : Real) / 1000 + 1 / 20 + 1685843742692980488 / 10000000000000000000 + + 37 / 100 ≤ 67 / 10 := by norm_num + linarith [hEt_bound, hgap126, hdist, hsum] -/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 13/2`. -/ +/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 67/10`. -/ theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 13 / 2 := by + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 67 / 10 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_under_tight hx hC hC0 htnn · exact r0_real_under_tight_neg hx hC hC0 (le_of_lt htneg) +/-! ## The octave-seam `r0`-doubling consequence -/ + +/-- A lower bound on the quotient: `2¹²⁴ < r0Tree x`. +(`r0 ≥ 2¹²⁶·exp(rt) − 67/10 > 2¹²⁶·(1/2) − 67/10 > 2¹²⁴`.) -/ +theorem r0Tree_gt_2_124 {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (2 : Real) ^ 124 < (int256 (r0Tree x) : Real) := by + have hu := r0_real_under_within hx hC hC0 + have hh := exp_reducedArg_gt_half hx hC hC0 + have h1 : (2 ^ 126 : Real) * (1 / 2) < (2 ^ 126 : Real) * Real.exp (reducedArg x) := + mul_lt_mul_of_pos_left hh (by positivity) + have h2 : (2 ^ 126 : Real) * (1 / 2) = (2 ^ 125 : Real) := by norm_num + have h3 : (2 : Real) ^ 124 + 67 / 10 < (2 ^ 125 : Real) := by norm_num + linarith [hu, h1, h2 ▸ h1, h3] + +/-- **The seam exp relation.** Across a seam (`X2 = X1 + 1`, `k2 = k1 + 1`), +`exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`. -/ +theorem reducedArg_seam {x1 x2 : Nat} + (hk : int256 (kTree x2) = int256 (kTree x1) + 1) + (hadj : int256 x2 = int256 x1 + 1) : + Real.exp (reducedArg x1) = + 2 * Real.exp (reducedArg x2) * Real.exp (-(1 / (10 ^ 27 : Real))) := by + have hrel : reducedArg x1 = reducedArg x2 + Real.log 2 + (-(1 / (10 ^ 27 : Real))) := by + unfold reducedArg + rw [show (int256 x2 : Real) = (int256 x1 : Real) + 1 from by exact_mod_cast hadj, + show (int256 (kTree x2) : Real) = (int256 (kTree x1) : Real) + 1 from by exact_mod_cast hk] + ring + rw [hrel, Real.exp_add, Real.exp_add, Real.exp_log (by norm_num : (0:Real) < 2)] + ring + +/-- **`r0` at most doubles across a seam, two units short** (the real reduction of `SeamR0Bound`). +The strict slack from `exp(−1/RAY) < 1` (against `r0Tree x2 > 2¹²⁴`, worth ≈ `1.7·10¹¹` grid units) +dwarfs the per-point envelopes and the two integer units. -/ +theorem r0_seam_double {x1 x2 : Nat} + (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) + (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) + (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) + (hk : int256 (kTree x2) = int256 (kTree x1) + 1) + (hadj : int256 x2 = int256 x1 + 1) : + int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) := by + have hover1 := r0_real_over_within hx1 hC1 hC01 + have hunder2 := r0_real_under_within hx2 hC2 hC02 + have hr0_2_big := r0Tree_gt_2_124 hx2 hC2 hC02 + have hseam := reducedArg_seam hk hadj + set E1 := Real.exp (reducedArg x1) with hE1 + set E2 := Real.exp (reducedArg x2) with hE2 + set y := Real.exp (-(1 / (10 ^ 27 : Real))) with hy + have hy_pos : 0 < y := Real.exp_pos _ + -- y ≤ 1 - 1/(2·RAY) + have hy_bound : y ≤ 1 - 1 / (2 * (10 ^ 27 : Real)) := by + rw [hy] + have hz : (0:Real) < 1 / (10 ^ 27 : Real) := by positivity + have hez : (1 : Real) + 1 / (10 ^ 27 : Real) ≤ Real.exp (1 / (10 ^ 27 : Real)) := by + have := Real.add_one_le_exp (1 / (10 ^ 27 : Real)); linarith [this] + rw [Real.exp_neg] + have hexppos : 0 < Real.exp (1 / (10 ^ 27 : Real)) := Real.exp_pos _ + rw [inv_le_iff_one_le_mul₀ hexppos] + have h1z : (1 - 1 / (2 * (10 ^ 27 : Real))) * (1 + 1 / (10 ^ 27 : Real)) ≥ 1 := by + rw [ge_iff_le]; nlinarith [sq_nonneg (1 / (10 ^ 27 : Real))] + nlinarith [hez, h1z, hexppos, mul_pos (by positivity : (0:Real) < 1 - 1/(2*(10^27:Real))) hexppos] + -- 2^126·E1 = 2·(2^126·E2)·y ≤ 2·(r0_2 + 67/10)·y + have hE2bound : (2 ^ 126 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + 67 / 10 := hunder2 + have hr0_1 : (int256 (r0Tree x1) : Real) ≤ + 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y + + 10155087723197130681 / 10000000000000000000 := by + have h1 : (2 ^ 126 : Real) * E1 = 2 * ((2 ^ 126 : Real) * E2) * y := by rw [hseam]; ring + have h2 : (int256 (r0Tree x1) : Real) ≤ (2 ^ 126 : Real) * E1 + + 10155087723197130681 / 10000000000000000000 := hover1 + rw [h1] at h2 + have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y := + mul_le_mul_of_nonneg_right + (by linarith [mul_le_mul_of_nonneg_left hE2bound (by norm_num : (0:Real) ≤ 2)]) + (le_of_lt hy_pos) + linarith [h2, h3] + have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by + linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^124)] + have hkey : 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y + + 10155087723197130681 / 10000000000000000000 + 2 < 2 * (int256 (r0Tree x2) : Real) := by + -- the seam gap is dominated by `(r0 + 67/10) / RAY`; the quotient exceeds `1562` here + have hyb : 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y ≤ + 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) := + mul_le_mul_of_nonneg_left hy_bound (by linarith [hr0_2nn]) + have hexpand : 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) = + 2 * (int256 (r0Tree x2) : Real) + 67 / 5 - + ((int256 (r0Tree x2) : Real) + 67 / 10) / (10 ^ 27 : Real) := by field_simp; ring + have hbig : ((int256 (r0Tree x2) : Real) + 67 / 10) / (10 ^ 27 : Real) > 1562 := by + rw [gt_iff_lt, lt_div_iff₀ (by positivity)] + nlinarith [hr0_2_big, (by norm_num : (1562:Real) * 10 ^ 27 + 1 < 2 ^ 124)] + linarith [hyb, hexpand ▸ hyb, hbig] + have hreal : (int256 (r0Tree x1) : Real) + 2 ≤ 2 * (int256 (r0Tree x2) : Real) := by + linarith [hr0_1, hkey] + have hcast : ((int256 (r0Tree x1) + 2 : Int) : Real) ≤ ((2 * int256 (r0Tree x2) : Int) : Real) := by + push_cast + linarith [hreal] + exact_mod_cast hcast + +end + end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index c2358c7b5..4494e76e5 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -33,13 +33,13 @@ set_option maxRecDepth 100000 /-! ## Strict never-over: the accumulator stays a positive distance below the target -`accumReal_over` gives `accumReal x ≤ E`. With `B = 7201434073703092789/10¹⁹` the never-over envelope, -`MARGIN` is `⌊WAD·B⌋ + 1`, so the inequality is in fact strict — the slack `δ = MARGIN − WAD·B = 1/10` +`accumReal_over` gives `accumReal x ≤ E`. With `B = 10155087723197130681/10¹⁹` the never-over envelope, +`MARGIN` is `⌊WAD·B⌋ + 1`, so the inequality is in fact strict — the slack `δ = MARGIN − WAD·B = 9/10` (worth `δ/2^s` after the closing shift). The round trip needs this strictness to rule out `accumReal x = w` exactly. -/ /-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the target. -The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 7201434073703092789/10000000000000000000` plus `WAD·7201434073703092789/10000000000000000000 < MARGIN` give a strictly +The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 10155087723197130681/10000000000000000000` plus `WAD·10155087723197130681/10000000000000000000 < MARGIN` give a strictly negative residue. -/ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -49,24 +49,24 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- WAD·r0 − MARGIN < WAD·2^126·Ert = E·2^s, using WAD·7201434073703092789/10000000000000000000 < MARGIN - have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 < + -- WAD·r0 − MARGIN < WAD·2^126·Ert = E·2^s, using WAD·10155087723197130681/10000000000000000000 < MARGIN + have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069 < expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 7201434073703092789 / 10000000000000000000 := hover + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 10155087723197130681 / 10000000000000000000 := hover have hscaled : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) ≤ - (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 7201434073703092789 / 10000000000000000000) := + (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 10155087723197130681 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] - -- WAD·B = 720143407370309278.9 < 720143407370309279 = MARGIN + -- WAD·B = 1015508772319713068.1 < 1015508772319713069 = MARGIN nlinarith [hscaled] rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] /-- **Accumulator deficit, region-uniform.** On the region the accumulator is below the target by -strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 13/2` and the -octave fold give `accumReal x ≥ E − ((13/2)·WAD + MARGIN)/2^s` with `s = 126 − k ≥ 63`, and -`((13/2)·WAD + MARGIN)/2⁶³ ≈ 0.783 < 24/25`. The tightness below one is what closes the round trip +strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 67/10` and the +octave fold give `accumReal x ≥ E − ((67/10)·WAD + MARGIN)/2^s` with `s = 126 − k ≥ 63`, and +`((67/10)·WAD + MARGIN)/2⁶³ ≈ 0.837 < 24/25`. The tightness below one is what closes the round trip together with `lnWadToRay`'s ≈10⁻⁹ envelope. -/ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -83,19 +83,19 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = WAD·2^126·Ert ≤ WAD·(r0 + 8) -- and 8·WAD + MARGIN < (24/25)·2^63 ≤ (24/25)·2^s have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 720143407370309279 := by + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = (WAD : Real) * (2 ^ 126 : Real) * Ert := hfold - have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 13 / 2 := hunder + have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 67 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 13 / 2) := + (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 67 / 10) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - have hbudget : (10 ^ 18 : Real) * (13 / 2) + 720143407370309279 < (24 / 25) * (2 ^ 63 : Real) := by + have hbudget : (10 ^ 18 : Real) * (67 / 10) + 1015508772319713069 < (24 / 25) * (2 ^ 63 : Real) := by norm_num rw [hwad] at hkey have hEs : (10 ^ 18 : Real) * 2 ^ 126 * Ert ≤ - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) + (10 ^ 18 : Real) * (13 / 2) := by + (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) + (10 ^ 18 : Real) * (67 / 10) := by nlinarith [h8wad] -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; E·2^s = 10^18·2^126·Ert ; (24/25)·2^s ≥ (24/25)·2^63 have h2425 : (24 / 25 : Real) * (2 ^ 63 : Real) ≤ (24 / 25) * (2 ^ s : Real) := diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index 2c1640685..c9e80d16b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -20,8 +20,8 @@ The two floor facts `(r : Real) ≤ A` and `A < (r : Real) + 1` (i.e. `r = ⌊A from the `evmSar` sandwich. The relation between the *real-valued* runtime accumulator `A` and the target `E = WAD·exp(x/RAY)` — never-over `A ≤ E` and deficit-under-one `E < A + 1` — is not a runtime-plumbing fact; it is discharged in `Floor.R0BoundHolds` (`accumReal_over`/`accumReal_under`: -the cert `Floor/CapsV` against the exact rational, plus the reduced-argument and Horner-truncation -envelopes the `MARGIN` absorbs). +the cert `Floor/CapsV` against the exact rational, plus the argument-granularity, reduced-argument +and Horner-truncation envelopes the `MARGIN` absorbs). -/ namespace ExpYul @@ -81,7 +81,7 @@ A x = int256 (WAD·r0 − MARGIN) / 2^(126 − k). /-- The real pre-floor accumulator of the runtime body, as an explicit `Real`. -/ def accumReal (x : Nat) : Real := - (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) : Real) / + (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) : Real) / (2 ^ (evmSub 0x7e (kTree x)) : Real) /-- On the meaningful region the body word `r1Tree x` is the integer floor of its real accumulator @@ -91,18 +91,18 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) (int256 (r1Tree x) : Real) ≤ accumReal x ∧ accumReal x < (int256 (r1Tree x) : Real) + 1 := by obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 - have hr1 : r1Tree x = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) := by + have hr1 : r1Tree x = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) := by have : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) := rfl + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) := rfl rw [this, hseq] - have hWw : evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f < 2 ^ 256 := + have hWw : evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d < 2 ^ 256 := evmSub_lt _ _ - have hfloor := sar_real_floor (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) + have hfloor := sar_real_floor (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) (s := s) (by omega) hWw simp only at hfloor -- align `accumReal` (shift `evmSub 0x7e (kTree x)`) with the lemma's shift `s` have hAeq : accumReal x = - (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) : Real) / + (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) : Real) / (2 ^ s : Real) := by unfold accumReal; rw [hseq] rw [hAeq, hr1] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index b471eb1dc..d56be0b35 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -16,33 +16,32 @@ abbrev cInvQ200 : Nat := 0x724d54edbacbebbb95c52a0f6076 abbrev k27Q235 : Nat := 0x279d346de4781f921dd7a89933d54d1f72928 abbrev ln2Q235 : Nat := 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d abbrev tArgShift : Nat := 0x6b -abbrev squareShift : Nat := 0x80 - -abbrev ev0 : Nat := 0xb9aacfad41060587203a79af0ebc -abbrev ev1 : Nat := 0x9a036222e11aee18465042f8ea64c8 -abbrev ev2 : Nat := 0x9064d965e1c4863b73604e0ddbec53f9 -abbrev ev3 : Nat := 0x93f11e65781741b92fa7fc4f4fffcca2 -abbrev ev4 : Nat := 0x4e14a45e8ec305e233e11b4174e214ac -abbrev evShift0 : Nat := 0x1d -abbrev evShift1 : Nat := 0x82 -abbrev evShift2 : Nat := 0x80 -abbrev evShift3 : Nat := 0x86 -abbrev evShift4 : Nat := 0x84 - -abbrev od0 : Nat := 0xdc07aff85e5bb5629d0fb64a84bb -abbrev od1 : Nat := 0xc926ddbf3830ca5561cc01585402d0 -abbrev od2 : Nat := 0xad4506b00b1246c7e5b4fd33e1201b -abbrev od3 : Nat := 0xaf5662483c4ce783a9ef5fe025f42e9e -abbrev od4 : Nat := 0x270a522f476182f119f08da0ba710a56 -abbrev odShift1 : Nat := 0x83 -abbrev odShift2 : Nat := 0x89 -abbrev odShift3 : Nat := 0x7f -abbrev odShift4 : Nat := 0x87 +abbrev squareShift : Nat := 0x85 + +abbrev ev0 : Nat := 0xb9aacfacf3c10b378435f8e22adf48500e +abbrev ev1 : Nat := 0x9a036222841f47c6ed6fc3f7602053 +abbrev ev2 : Nat := 0x9064d9657e9a21fc16bb69331c5c3057 +abbrev ev3 : Nat := 0x93f11e650dd6c64b96ce79065cdf809e +abbrev ev4 : Nat := 0x4e14a45e5650b506e97f4c5da23861e2 +abbrev evShift1 : Nat := 0x95 +abbrev evShift2 : Nat := 0x7b +abbrev evShift3 : Nat := 0x81 +abbrev evShift4 : Nat := 0x7f + +abbrev od0 : Nat := 0xdc07aff8276bde9a361278df6a10 +abbrev od1 : Nat := 0xc926ddbecdeeb42e68cd16db7da8c1 +abbrev od2 : Nat := 0xad4506af99be27419341e1816ff351 +abbrev od3 : Nat := 0xaf566247c05753b42892f77b67a6b7c6 +abbrev od4 : Nat := 0x270a522f2b285a8374bfa62ed11c30f1 +abbrev odShift1 : Nat := 0x7e +abbrev odShift2 : Nat := 0x84 +abbrev odShift3 : Nat := 0x7a +abbrev odShift4 : Nat := 0x82 abbrev todShift : Nat := 0x80 abbrev expQShift : Nat := 0x7e abbrev wadWord : Nat := 0xde0b6b3a7640000 -abbrev marginWord : Nat := 0x9fe769d0fa58e9f +abbrev marginWord : Nat := 0xe17cfd91868d72d theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by unfold Cmask int256 diff --git a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean index b340832c0..4dc492073 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean @@ -66,11 +66,11 @@ Given the numerator/denominator positivity and `tod1·ev2 ≤ tod2·ev1`, the tw `≤`-ordered. -/ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} (hE1 : E1 < 2 ^ 256) (hTD1 : TD1 < 2 ^ 256) (hE2 : E2 < 2 ^ 256) (hTD2 : TD2 < 2 ^ 256) - (hev1_lo : (103786963415199049567855548359006885036 : Int) ≤ (E1 : Int)) + (hev1_lo : (103786963397729689639908782561058906594 : Int) ≤ (E1 : Int)) (hev1_hi : (E1 : Int) < 2 ^ 127) (htod1_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD1) (htod1_hi : int256 TD1 < 42535295865117307932921825928971026432) - (hev2_lo : (103786963415199049567855548359006885036 : Int) ≤ (E2 : Int)) + (hev2_lo : (103786963397729689639908782561058906594 : Int) ≤ (E2 : Int)) (hev2_hi : (E2 : Int) < 2 ^ 127) (htod2_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD2) (htod2_hi : int256 TD2 < 42535295865117307932921825928971026432) diff --git a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean index aa3e076f2..83dab1fbe 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean @@ -25,26 +25,26 @@ open FormalYul.Preservation set_option maxRecDepth 100000 /-- The even accumulator's signed value is its (nonnegative) Nat value, in `[a0, 2^127)`. -/ -theorem evTree_int {x : Nat} (hv : vTree x < 2 ^ 126) : - (103786963415199049567855548359006885036 : Int) ≤ (evTree x : Int) ∧ +theorem evTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : + (103786963397729689639908782561058906594 : Int) ≤ (evTree x : Int) ∧ (evTree x : Int) < 2 ^ 127 := by obtain ⟨hlo, hhi⟩ := evTree_facts hv constructor - · have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo - rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 by + · have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo + rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 by norm_num] at this exact this · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hhi rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this /-- The odd accumulator's signed value is its (nonnegative) Nat value, in `[b0, 2^126)`. -/ -theorem odTree_int {x : Nat} (hv : vTree x < 2 ^ 126) : - (51893481707599524783927774179503442518 : Int) ≤ (odTree x : Int) ∧ +theorem odTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : + (51893481698864844819954391280529453297 : Int) ≤ (odTree x : Int) ∧ (odTree x : Int) < 2 ^ 126 := by obtain ⟨hlo, hhi⟩ := odTree_facts hv constructor - · have : (0x270a522f476182f119f08da0ba710a56 : Int) ≤ (odTree x : Int) := by exact_mod_cast hlo - rw [show (0x270a522f476182f119f08da0ba710a56 : Int) = 51893481707599524783927774179503442518 by + · have : (0x270a522f2b285a8374bfa62ed11c30f1 : Int) ≤ (odTree x : Int) := by exact_mod_cast hlo + rw [show (0x270a522f2b285a8374bfa62ed11c30f1 : Int) = 51893481698864844819954391280529453297 by norm_num] at this exact this · have : (odTree x : Int) < (2 ^ 126 : Nat) := by exact_mod_cast hhi @@ -52,22 +52,22 @@ theorem odTree_int {x : Nat} (hv : vTree x < 2 ^ 126) : /-- The even/odd accumulators' signed difference is bounded by `DEv`/`DOd` (the Lipschitz bound transported to `Int`). -/ -theorem evTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 126) (hv2 : vTree x2 < 2 ^ 126) +theorem evTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - -(42701611664 : Int) ≤ (evTree x1 : Int) - (evTree x2 : Int) ∧ - (evTree x1 : Int) - (evTree x2 : Int) ≤ 42701611664 := by + -(42618413185 : Int) ≤ (evTree x1 : Int) - (evTree x2 : Int) ∧ + (evTree x1 : Int) - (evTree x2 : Int) ≤ 42618413185 := by obtain ⟨h1, h2⟩ := evTree_lip hv1 hv2 hg1 hg2 - have c1 : ((evTree x1 : Nat) : Int) ≤ (evTree x2 : Int) + 42701611664 := by exact_mod_cast h1 - have c2 : ((evTree x2 : Nat) : Int) ≤ (evTree x1 : Int) + 42701611664 := by exact_mod_cast h2 + have c1 : ((evTree x1 : Nat) : Int) ≤ (evTree x2 : Int) + 42618413185 := by exact_mod_cast h1 + have c2 : ((evTree x2 : Nat) : Int) ≤ (evTree x1 : Int) + 42618413185 := by exact_mod_cast h2 omega -theorem odTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 126) (hv2 : vTree x2 < 2 ^ 126) +theorem odTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - -(5327301648 : Int) ≤ (odTree x1 : Int) - (odTree x2 : Int) ∧ - (odTree x1 : Int) - (odTree x2 : Int) ≤ 5327301648 := by + -(5322105549 : Int) ≤ (odTree x1 : Int) - (odTree x2 : Int) ∧ + (odTree x1 : Int) - (odTree x2 : Int) ≤ 5322105549 := by obtain ⟨h1, h2⟩ := odTree_lip hv1 hv2 hg1 hg2 - have c1 : ((odTree x1 : Nat) : Int) ≤ (odTree x2 : Int) + 5327301648 := by exact_mod_cast h1 - have c2 : ((odTree x2 : Nat) : Int) ≤ (odTree x1 : Int) + 5327301648 := by exact_mod_cast h2 + have c1 : ((odTree x1 : Nat) : Int) ≤ (odTree x2 : Int) + 5322105549 := by exact_mod_cast h1 + have c2 : ((odTree x2 : Nat) : Int) ≤ (odTree x1 : Int) + 5322105549 := by exact_mod_cast h2 omega /-- The squared-argument step, as a `Nat` two-sided gap (`vTree x_i ≤ vTree x_j + W`). -/ @@ -78,9 +78,8 @@ theorem vTree_step_nat {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hadj : int256 x2 = int256 x1 + 1) : vTree x1 ≤ vTree x2 + Wstep ∧ vTree x2 ≤ vTree x1 + Wstep := by obtain ⟨hlo, hhi⟩ := vTree_step hx1 hx2 hC1 hC01 hC2 hC02 hk hadj - have hW : (Wstep : Int) = Gstep + 1 := by unfold Wstep Gstep; norm_num - have c1 : (vTree x1 : Int) ≤ (vTree x2 : Int) + Wstep := by rw [hW]; omega - have c2 : (vTree x2 : Int) ≤ (vTree x1 : Int) + Wstep := by rw [hW]; omega + have c1 : (vTree x1 : Int) ≤ (vTree x2 : Int) + Wstep := by omega + have c2 : (vTree x2 : Int) ≤ (vTree x1 : Int) + Wstep := by omega exact ⟨by exact_mod_cast c1, by exact_mod_cast c2⟩ /-- Abstract smooth certificate over opaque accumulator/argument values. The gain `d·od2·ev1` @@ -90,16 +89,16 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} (hd1 : (340282366920 : Int) ≤ d) (hd2 : d ≤ 340282366921) (ht1lo : -(170141183460469231731687303715884105728 : Int) < t1) (ht1hi : t1 < 170141183460469231731687303715884105728) - (hev1lo : (103786963415199049567855548359006885036 : Int) ≤ ev1) + (hev1lo : (103786963397729689639908782561058906594 : Int) ≤ ev1) (hev1hi : ev1 < 170141183460469231731687303715884105728) - (hev2lo : (103786963415199049567855548359006885036 : Int) ≤ ev2) + (hev2lo : (103786963397729689639908782561058906594 : Int) ≤ ev2) (hev2hi : ev2 < 170141183460469231731687303715884105728) - (hod1lo : (51893481707599524783927774179503442518 : Int) ≤ od1) + (hod1lo : (51893481698864844819954391280529453297 : Int) ≤ od1) (hod1hi : od1 < 85070591730234615865843651857942052864) - (hod2lo : (51893481707599524783927774179503442518 : Int) ≤ od2) + (hod2lo : (51893481698864844819954391280529453297 : Int) ≤ od2) (hod2hi : od2 < 85070591730234615865843651857942052864) - (hevd1 : -(42701611664 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 42701611664) - (hodd1 : -(5327301648 : Int) ≤ od1 - od2) (hodd2 : od1 - od2 ≤ 5327301648) : + (hevd1 : -(42618413185 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 42618413185) + (hodd1 : -(5322105549 : Int) ≤ od1 - od2) (hodd2 : od1 - od2 ≤ 5322105549) : t1 * od1 * ev2 + 340282366920938463463374607431768211456 * ev1 ≤ (t1 + d) * od2 * ev1 := by -- cross difference `cd = od1·ev2 − od2·ev1`, bounded by `CB = DOd·2^127 + 2^126·DEv` @@ -107,17 +106,17 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} -- bound each piece have hev2nn : (0 : Int) ≤ ev2 := by linarith have hod2nn : (0 : Int) ≤ od2 := by linarith - have hp1 : (od1 - od2) * ev2 ≤ 5327301648 * 170141183460469231731687303715884105728 := by + have hp1 : (od1 - od2) * ev2 ≤ 5322105549 * 170141183460469231731687303715884105728 := by nlinarith [hodd2, hodd1, hev2nn, hev2hi] - have hp1' : -(5327301648 * 170141183460469231731687303715884105728 : Int) ≤ (od1 - od2) * ev2 := by + have hp1' : -(5322105549 * 170141183460469231731687303715884105728 : Int) ≤ (od1 - od2) * ev2 := by nlinarith [hodd1, hev2nn, hev2hi] - have hp2 : od2 * (ev2 - ev1) ≤ 85070591730234615865843651857942052864 * 42701611664 := by + have hp2 : od2 * (ev2 - ev1) ≤ 85070591730234615865843651857942052864 * 42618413185 := by nlinarith [hod2nn, hod2hi, hevd1, hevd2] - have hp2' : -(85070591730234615865843651857942052864 * 42701611664 : Int) ≤ od2 * (ev2 - ev1) := by + have hp2' : -(85070591730234615865843651857942052864 * 42618413185 : Int) ≤ od2 * (ev2 - ev1) := by nlinarith [hod2nn, hod2hi, hevd1, hevd2] -- so |cd| ≤ CB - set CB : Int := 5327301648 * 170141183460469231731687303715884105728 + - 85070591730234615865843651857942052864 * 42701611664 with hCB + set CB : Int := 5322105549 * 170141183460469231731687303715884105728 + + 85070591730234615865843651857942052864 * 42618413185 with hCB have hcd_hi : od1 * ev2 - od2 * ev1 ≤ CB := by rw [hcd_eq, hCB]; linarith have hcd_lo : -CB ≤ od1 * ev2 - od2 * ev1 := by rw [hcd_eq, hCB]; linarith -- `t1·(od1·ev2 − od2·ev1) ≤ 2^127·CB` @@ -136,13 +135,13 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} linarith -- gain: d·od2·ev1 ≥ 340282366920·b0·a0 have hev1nn : (0 : Int) ≤ ev1 := by linarith - have hgain : (340282366920 : Int) * 51893481707599524783927774179503442518 * - 103786963415199049567855548359006885036 ≤ d * od2 * ev1 := by - have g1 : (340282366920 : Int) * 51893481707599524783927774179503442518 ≤ d * od2 := by - have := mul_le_mul hd1 hod2lo (by norm_num : (0:Int) ≤ 51893481707599524783927774179503442518) (by linarith) + have hgain : (340282366920 : Int) * 51893481698864844819954391280529453297 * + 103786963397729689639908782561058906594 ≤ d * od2 * ev1 := by + have g1 : (340282366920 : Int) * 51893481698864844819954391280529453297 ≤ d * od2 := by + have := mul_le_mul hd1 hod2lo (by norm_num : (0:Int) ≤ 51893481698864844819954391280529453297) (by linarith) linarith - have g2 : (340282366920 : Int) * 51893481707599524783927774179503442518 * - 103786963415199049567855548359006885036 ≤ (d * od2) * ev1 := + have g2 : (340282366920 : Int) * 51893481698864844819954391280529453297 * + 103786963397729689639908782561058906594 ≤ (d * od2) * ev1 := mul_le_mul g1 hev1lo (by norm_num) (by positivity) linarith [g2] -- assemble: goal `t1·od1·ev2 + 2^128·ev2 ≤ (t1+d)·od2·ev1 = t1·od2·ev1 + d·od2·ev1` @@ -153,8 +152,8 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} -- numeric closure: 2^128·ev2 + 2^127·CB ≤ gain, and ev2 < 2^127 have hkey : (340282366920938463463374607431768211456 : Int) * ev1 + 170141183460469231731687303715884105728 * CB ≤ - (340282366920 : Int) * 51893481707599524783927774179503442518 * - 103786963415199049567855548359006885036 := by + (340282366920 : Int) * 51893481698864844819954391280529453297 * + 103786963397729689639908782561058906594 := by rw [hCB] nlinarith [hev1hi] nlinarith [htcd, hgain, hkey, hdecomp] @@ -169,8 +168,8 @@ theorem smooth_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) int256 (tTree x1) * (odTree x1 : Int) * (evTree x2 : Int) + 2 ^ 128 * (evTree x1 : Int) ≤ int256 (tTree x2) * (odTree x2 : Int) * (evTree x1 : Int) := by - have hv1 : vTree x1 < 2 ^ 126 := (vTree_eq hx1 hC1 hC01).2 - have hv2 : vTree x2 < 2 ^ 126 := (vTree_eq hx2 hC2 hC02).2 + have hv1 : vTree x1 < 2 ^ 120 := (vTree_eq hx1 hC1 hC01).2 + have hv2 : vTree x2 < 2 ^ 120 := (vTree_eq hx2 hC2 hC02).2 obtain ⟨hg1, hg2⟩ := vTree_step_nat hx1 hx2 hC1 hC01 hC2 hC02 hk hadj obtain ⟨hev1lo, hev1hi⟩ := evTree_int hv1 obtain ⟨hev2lo, hev2hi⟩ := evTree_int hv2 @@ -219,8 +218,8 @@ theorem tod_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) int256 (todTree x1) * (evTree x2 : Int) ≤ int256 (todTree x2) * (evTree x1 : Int) := by obtain ⟨_, _, hfl1, _⟩ := todTree_bound hx1 hC1 hC01 obtain ⟨_, _, _, hfu2⟩ := todTree_bound hx2 hC2 hC02 - have hv1 : vTree x1 < 2 ^ 126 := (vTree_eq hx1 hC1 hC01).2 - have hv2 : vTree x2 < 2 ^ 126 := (vTree_eq hx2 hC2 hC02).2 + have hv1 : vTree x1 < 2 ^ 120 := (vTree_eq hx1 hC1 hC01).2 + have hv2 : vTree x2 < 2 ^ 120 := (vTree_eq hx2 hC2 hC02).2 have hev1pos : 0 < (evTree x1 : Int) := by have := (evTree_int hv1).1; linarith have hev2nn : 0 ≤ (evTree x2 : Int) := Int.natCast_nonneg _ diff --git a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean index 15b114f50..e65e389d5 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean @@ -4,14 +4,14 @@ import ExpProof.Mono.Gaps # Near-constancy of the even/odd accumulators across adjacent inputs Telescoping `stage_lip` through the five even / four odd Horner stages, with the squared-argument -gap `|v2 − v1| ≤ W = G + 1` from `vTree_step`, bounds the change of the accumulators: +gap `|v2 − v1| ≤ W` from `vTree_step`, bounds the change of the accumulators: ``` -|evTree x2 − evTree x1| ≤ DEv = 42701611664, -|odTree x2 − odTree x1| ≤ DOd = 5327301648. +|evTree x2 − evTree x1| ≤ DEv = 42618413185, +|odTree x2 − odTree x1| ≤ DOd = 5322105549. ``` -The intermediate per-stage prev bounds reuse the chained `2^k` ceilings established inside +The intermediate per-stage prev bounds reuse the chained ceilings established inside `evTree_facts`/`odTree_facts`; each stage application keeps the accumulator words opaque so the deep tree is never forced. -/ @@ -28,200 +28,174 @@ def dist_le (a b D : Nat) : Prop := a ≤ b + D ∧ b ≤ a + D theorem dist_le.symm {a b D : Nat} (h : dist_le a b D) : dist_le b a D := ⟨h.2, h.1⟩ -/-- The leading even stage `a4 + ⌊v/2^29⌋` moves by at most `(W >> 0x1d) + 1` under `|v2−v1| ≤ W`. -/ -theorem evLead_lip {c v1 v2 W : Nat} (hc : c < 2 ^ 255) (hv1 : v1 < 2 ^ 126) (hv2 : v2 < 2 ^ 126) +/-- The monic leading even stage `a4 + v` is a bare add: it moves by exactly the argument gap +`|v2 − v1| ≤ W`. -/ +theorem evLead_lip {c v1 v2 W : Nat} (hc : c < 2 ^ 255) (hv1 : v1 < 2 ^ 120) (hv2 : v2 < 2 ^ 120) (hvg1 : v1 ≤ v2 + W) (hvg2 : v2 ≤ v1 + W) : - dist_le (evmAdd c (evmShr 0x1d v1)) (evmAdd c (evmShr 0x1d v2)) ((W / 2 ^ 0x1d) + 1) := by - have hd1 : evmShr 0x1d v1 = v1 / 2 ^ 0x1d := evmShr_eq_div (by norm_num) (by omega) - have hd2 : evmShr 0x1d v2 = v2 / 2 ^ 0x1d := evmShr_eq_div (by norm_num) (by omega) - have hsh0 : (0 : Nat) < 2 ^ 0x1d := Nat.two_pow_pos _ - -- `v/2^29 < 2^97`, so the sum fits below `2^256` - have hb1 : v1 / 2 ^ 0x1d < 2 ^ 97 := by - have : v1 / 2 ^ 0x1d < 2 ^ 126 / 2 ^ 0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv1 - have he : (2:Nat) ^ 126 / 2 ^ 0x1d = 2 ^ 97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] - omega - have hb2 : v2 / 2 ^ 0x1d < 2 ^ 97 := by - have : v2 / 2 ^ 0x1d < 2 ^ 126 / 2 ^ 0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv2 - have he : (2:Nat) ^ 126 / 2 ^ 0x1d = 2 ^ 97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] - omega - have hlt1 : v1 / 2 ^ 0x1d < 2 ^ 256 := by - have h : (2:Nat) ^ 97 < 2 ^ 256 := by norm_num - omega - have hlt2 : v2 / 2 ^ 0x1d < 2 ^ 256 := by - have h : (2:Nat) ^ 97 < 2 ^ 256 := by norm_num - omega - have hc256 : c < 2 ^ 256 := by - have h : (2:Nat) ^ 255 < 2 ^ 256 := by norm_num - omega - have hsm : (2:Nat)^255 + 2^97 < 2^256 := by norm_num - have he1 : evmAdd c (evmShr 0x1d v1) = c + v1 / 2 ^ 0x1d := by - rw [hd1, evmAdd_eq_nat hc256 hlt1 (by omega)] - have he2 : evmAdd c (evmShr 0x1d v2) = c + v2 / 2 ^ 0x1d := by - rw [hd2, evmAdd_eq_nat hc256 hlt2 (by omega)] + dist_le (evmAdd c v1) (evmAdd c v2) W := by + have he1 : evmAdd c v1 = c + v1 := evmAdd_eq_nat (by omega) (by omega) (by omega) + have he2 : evmAdd c v2 = c + v2 := evmAdd_eq_nat (by omega) (by omega) (by omega) rw [he1, he2] - -- |v1/d − v2/d| ≤ |v1−v2|/d + 1 ≤ W/d + 1, via the additive floored-sum bound - have h12 : v1 / 2 ^ 0x1d ≤ v2 / 2 ^ 0x1d + (W / 2 ^ 0x1d + 1) := by - have s1 : v1 / 2 ^ 0x1d ≤ (v2 + W) / 2 ^ 0x1d := Nat.div_le_div_right hvg1 - have s2 := add_div_le_add (b := v2) (n := W) hsh0 - omega - have h21 : v2 / 2 ^ 0x1d ≤ v1 / 2 ^ 0x1d + (W / 2 ^ 0x1d + 1) := by - have s1 : v2 / 2 ^ 0x1d ≤ (v1 + W) / 2 ^ 0x1d := Nat.div_le_div_right hvg2 - have s2 := add_div_le_add (b := v1) (n := W) hsh0 - omega exact ⟨by omega, by omega⟩ /-- The leading odd stage is the bare constant `b4` (no `v`-dependence): distance `0`. -/ theorem odLead_const (c : Nat) : dist_le c c 0 := ⟨by omega, by omega⟩ /-- `stage_lip` repackaged in the `dist_le` form for a fixed stage shift. -/ -theorem stage_lip_dist {c prev1 prev2 v1 v2 P Dprev W sh : Nat} - (hp1 : prev1 ≤ P) (hp2 : prev2 ≤ P) (hv1 : v1 < 2 ^ 126) (hv2 : v2 < 2 ^ 126) +theorem stage_lip_dist {c prev1 prev2 v1 v2 P V Dprev W sh : Nat} + (hp1 : prev1 ≤ P) (hp2 : prev2 ≤ P) (hv1 : v1 < V) (hv2 : v2 < V) (hvg1 : v1 ≤ v2 + W) (hvg2 : v2 ≤ v1 + W) (hpd : dist_le prev1 prev2 Dprev) - (hPV : P * 2 ^ 126 < 2 ^ 256) (hsh : sh < 256) - (hsum1 : c + P * 2 ^ 126 / 2 ^ sh < 2 ^ 256) : + (hPV : P * V < 2 ^ 256) (hsh : sh < 256) + (hsum1 : c + P * V / 2 ^ sh < 2 ^ 256) (hVw : V < 2 ^ 256) : dist_le (evmAdd c (evmShr sh (evmMul prev1 v1))) (evmAdd c (evmShr sh (evmMul prev2 v2))) - ((P * W + 2 ^ 126 * Dprev) / 2 ^ sh + 1) := - stage_lip hp1 hp2 hv1 hv2 hvg1 hvg2 hpd.1 hpd.2 hPV hsh hsum1 + ((P * W + V * Dprev) / 2 ^ sh + 1) := + stage_lip hp1 hp2 hv1 hv2 hvg1 hvg2 hpd.1 hpd.2 hPV hsh hsum1 hVw -/-! ## The even Horner stages as named layers, with their `2^k` ceilings -/ +/-! ## The even Horner stages as named layers, with their chained ceilings -/ -def evS0 (x : Nat) : Nat := evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d (vTree x)) -def evS1 (x : Nat) : Nat := evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul (evS0 x) (vTree x))) -def evS2 (x : Nat) : Nat := evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul (evS1 x) (vTree x))) -def evS3 (x : Nat) : Nat := evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul (evS2 x) (vTree x))) +def evS0 (x : Nat) : Nat := evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e (vTree x) +def evS1 (x : Nat) : Nat := evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evS0 x) (vTree x))) +def evS2 (x : Nat) : Nat := evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evS1 x) (vTree x))) +def evS3 (x : Nat) : Nat := evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evS2 x) (vTree x))) theorem evTree_layers (x : Nat) : - evTree x = evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul (evS3 x) (vTree x))) := + evTree x = evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul (evS3 x) (vTree x))) := rfl -theorem evS0_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evS0 x < 2 ^ 113 := ev0_lt hv - -theorem evS1_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evS1 x < 2 ^ 121 := by - have := (stage_bounds (c := 0x9a036222e11aee18465042f8ea64c8) (prev := evS0 x) (v := vTree x) - (P := 2 ^ 113) (V := 2 ^ 126) (sh := 0x82) (evS0_lt hv) hv (by norm_num) (by norm_num) - (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num)).2 - rw [pvd 113 126 130 109 (by norm_num)] at this; unfold evS1; omega - -theorem evS2_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evS2 x < 2 ^ 129 := by - have := (stage_bounds (c := 0x9064d965e1c4863b73604e0ddbec53f9) (prev := evS1 x) (v := vTree x) - (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x80) (evS1_lt hv) hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 128 119 (by norm_num)] at this; unfold evS2; omega - -theorem evS3_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evS3 x < 2 ^ 129 := by - have := (stage_bounds (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (prev := evS2 x) (v := vTree x) - (P := 2 ^ 129) (V := 2 ^ 126) (sh := 0x86) (evS2_lt hv) hv (by norm_num) (by norm_num) - (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num)).2 - rw [pvd 129 126 134 121 (by norm_num)] at this; unfold evS3; omega +theorem evS0_lt {x : Nat} (hv : vTree x < 2 ^ 120) : + evS0 x < 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120 := ev0_lt hv + +theorem evS1_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evS1 x < 2 ^ 121 := by + have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7602053) (prev := evS0 x) (v := vTree x) + (P := 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) (V := 2 ^ 120) (sh := 0x95) + (evS0_lt hv) hv (by norm_num) (by norm_num) (by norm_num)).2 + have hcap : (0x9a036222841f47c6ed6fc3f7602053 : Nat) + + (0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) * 2 ^ 120 / 2 ^ 0x95 < 2 ^ 121 := by + norm_num + unfold evS1; omega + +theorem evS2_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evS2 x < 2 ^ 129 := by + have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331c5c3057) (prev := evS1 x) (v := vTree x) + (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7b) (evS1_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 123 118 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 123 118 (by norm_num)] at this; unfold evS2; omega + +theorem evS3_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evS3 x < 2 ^ 129 := by + have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf809e) (prev := evS2 x) (v := vTree x) + (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x81) (evS2_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 + rw [pvd 129 120 129 120 (by norm_num)] at this; unfold evS3; omega /-! ## The odd Horner stages as named layers -/ -def odS0 (x : Nat) : Nat := evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb (vTree x))) -def odS1 (x : Nat) : Nat := evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul (odS0 x) (vTree x))) -def odS2 (x : Nat) : Nat := evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul (odS1 x) (vTree x))) +def odS0 (x : Nat) : Nat := evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 (vTree x))) +def odS1 (x : Nat) : Nat := evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (odS0 x) (vTree x))) +def odS2 (x : Nat) : Nat := evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (odS1 x) (vTree x))) theorem odTree_layers (x : Nat) : - odTree x = evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul (odS2 x) (vTree x))) := + odTree x = evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul (odS2 x) (vTree x))) := rfl -theorem odS0_lt {x : Nat} (hv : vTree x < 2 ^ 126) : odS0 x < 2 ^ 121 := by - have := (stage_bounds (c := 0xc926ddbf3830ca5561cc01585402d0) (prev := 0xdc07aff85e5bb5629d0fb64a84bb) - (v := vTree x) (P := 2 ^ 112) (V := 2 ^ 126) (sh := 0x83) (by norm_num) hv (by norm_num) - (by norm_num) (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num)).2 - rw [pvd 112 126 131 107 (by norm_num)] at this; unfold odS0; omega +theorem odS0_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS0 x < 2 ^ 121 := by + have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7da8c1) (prev := 0xdc07aff8276bde9a361278df6a10) + (v := vTree x) (P := 2 ^ 112) (V := 2 ^ 120) (sh := 0x7e) (by norm_num) hv (by norm_num) + (by norm_num) (by rw [pvd 112 120 126 106 (by norm_num)]; norm_num)).2 + rw [pvd 112 120 126 106 (by norm_num)] at this; unfold odS0; omega -theorem odS1_lt {x : Nat} (hv : vTree x < 2 ^ 126) : odS1 x < 2 ^ 121 := by - have := (stage_bounds (c := 0xad4506b00b1246c7e5b4fd33e1201b) (prev := odS0 x) (v := vTree x) - (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x89) (odS0_lt hv) hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 137 110 (by norm_num)] at this; unfold odS1; omega +theorem odS1_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS1 x < 2 ^ 121 := by + have := (stage_bounds (c := 0xad4506af99be27419341e1816ff351) (prev := odS0 x) (v := vTree x) + (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x84) (odS0_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 132 109 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 132 109 (by norm_num)] at this; unfold odS1; omega -theorem odS2_lt {x : Nat} (hv : vTree x < 2 ^ 126) : odS2 x < 2 ^ 129 := by - have := (stage_bounds (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (prev := odS1 x) (v := vTree x) - (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x7f) (odS1_lt hv) hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 127 120 (by norm_num)] at this; unfold odS2; omega +theorem odS2_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS2 x < 2 ^ 129 := by + have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c6) (prev := odS1 x) (v := vTree x) + (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7a) (odS1_lt hv) hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 122 119 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 122 119 (by norm_num)] at this; unfold odS2; omega /-! ## Composed Lipschitz bounds -/ -/-- The step width `W = G + 1`. -/ -def Wstep : Nat := 340282366921 - -theorem Wstep_eq : Wstep = Gstep + 1 := by unfold Wstep Gstep; rfl - /-- **Even accumulator near-constancy.** Under a squared-argument gap `|v2 − v1| ≤ W` the even -accumulator changes by at most `DEv = 42701611664`. -/ -theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 126) (hv2 : vTree x2 < 2 ^ 126) +accumulator changes by at most `DEv = 42618413185`. -/ +theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - dist_le (evTree x1) (evTree x2) 42701611664 := by - -- leading stage - have d0 : dist_le (evS0 x1) (evS0 x2) 634 := by - have h := evLead_lip (c := 0xb9aacfad41060587203a79af0ebc) (W := Wstep) (by norm_num) hv1 hv2 hg1 hg2 - have he : (Wstep / 2 ^ 0x1d) + 1 = 634 := by unfold Wstep; decide - rw [he] at h; exact h + dist_le (evTree x1) (evTree x2) 42618413185 := by + -- monic leading stage: distance exactly the argument gap + have d0 : dist_le (evS0 x1) (evS0 x2) Wstep := + evLead_lip (c := 0xb9aacfacf3c10b378435f8e22adf48500e) (W := Wstep) (by norm_num) hv1 hv2 hg1 hg2 -- stage 1 - have d1 : dist_le (evS1 x1) (evS1 x2) 2596189 := by - have h := stage_lip_dist (c := 0x9a036222e11aee18465042f8ea64c8) (P := 2 ^ 113) (sh := 0x82) (W := Wstep) - (Dprev := 634) (le_of_lt (evS0_lt hv1)) (le_of_lt (evS0_lt hv2)) hv1 hv2 hg1 hg2 d0 - (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 113 * Wstep + 2 ^ 126 * 634) / 2 ^ 0x82 + 1 = 2596189 := by unfold Wstep; decide + have d1 : dist_le (evS1 x1) (evS1 x2) 941485 := by + have h := stage_lip_dist (c := 0x9a036222841f47c6ed6fc3f7602053) + (P := 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) (V := 2 ^ 120) (sh := 0x95) (W := Wstep) + (Dprev := Wstep) (le_of_lt (evS0_lt hv1)) (le_of_lt (evS0_lt hv2)) hv1 hv2 hg1 hg2 d0 + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + have he : ((0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) * Wstep + 2 ^ 120 * Wstep) / 2 ^ 0x95 + 1 = + 941485 := by unfold Wstep; decide rw [he] at h; exact h -- stage 2 - have d2 : dist_le (evS2 x1) (evS2 x2) 2659105039 := by - have h := stage_lip_dist (c := 0x9064d965e1c4863b73604e0ddbec53f9) (P := 2 ^ 121) (sh := 0x80) (W := Wstep) - (Dprev := 2596189) (le_of_lt (evS1_lt hv1)) (le_of_lt (evS1_lt hv2)) hv1 hv2 hg1 hg2 d1 - (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 121 * Wstep + 2 ^ 126 * 2596189) / 2 ^ 0x80 + 1 = 2659105039 := by + have d2 : dist_le (evS2 x1) (evS2 x2) 2658573678 := by + have h := stage_lip_dist (c := 0x9064d9657e9a21fc16bb69331c5c3057) (P := 2 ^ 121) (V := 2 ^ 120) + (sh := 0x7b) (W := Wstep) + (Dprev := 941485) (le_of_lt (evS1_lt hv1)) (le_of_lt (evS1_lt hv2)) hv1 hv2 hg1 hg2 d1 + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 121 * Wstep + 2 ^ 120 * 941485) / 2 ^ 0x7b + 1 = 2658573678 := by unfold Wstep; decide rw [he] at h; exact h -- stage 3 - have d3 : dist_le (evS3 x1) (evS3 x2) 10644211096 := by - have h := stage_lip_dist (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (P := 2 ^ 129) (sh := 0x86) (W := Wstep) - (Dprev := 2659105039) (le_of_lt (evS2_lt hv1)) (le_of_lt (evS2_lt hv2)) hv1 hv2 hg1 hg2 d2 - (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 129 * Wstep + 2 ^ 126 * 2659105039) / 2 ^ 0x86 + 1 = 10644211096 := by + have d3 : dist_le (evS3 x1) (evS3 x2) 10639016494 := by + have h := stage_lip_dist (c := 0x93f11e650dd6c64b96ce79065cdf809e) (P := 2 ^ 129) (V := 2 ^ 120) + (sh := 0x81) (W := Wstep) + (Dprev := 2658573678) (le_of_lt (evS2_lt hv1)) (le_of_lt (evS2_lt hv2)) hv1 hv2 hg1 hg2 d2 + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 129 * Wstep + 2 ^ 120 * 2658573678) / 2 ^ 0x81 + 1 = 10639016494 := by unfold Wstep; decide rw [he] at h; exact h -- final stage - have hfin := stage_lip_dist (c := 0x4e14a45e8ec305e233e11b4174e214ac) (P := 2 ^ 129) (sh := 0x84) (W := Wstep) - (Dprev := 10644211096) (le_of_lt (evS3_lt hv1)) (le_of_lt (evS3_lt hv2)) hv1 hv2 hg1 hg2 d3 - (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 129 * Wstep + 2 ^ 126 * 10644211096) / 2 ^ 0x84 + 1 = 42701611664 := by + have hfin := stage_lip_dist (c := 0x4e14a45e5650b506e97f4c5da23861e2) (P := 2 ^ 129) (V := 2 ^ 120) + (sh := 0x7f) (W := Wstep) + (Dprev := 10639016494) (le_of_lt (evS3_lt hv1)) (le_of_lt (evS3_lt hv2)) hv1 hv2 hg1 hg2 d3 + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 129 * Wstep + 2 ^ 120 * 10639016494) / 2 ^ 0x7f + 1 = 42618413185 := by unfold Wstep; decide rw [he] at hfin rw [evTree_layers, evTree_layers]; exact hfin /-- **Odd accumulator near-constancy.** Under a squared-argument gap `|v2 − v1| ≤ W` the odd -accumulator changes by at most `DOd = 5327301648`. -/ -theorem odTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 126) (hv2 : vTree x2 < 2 ^ 126) +accumulator changes by at most `DOd = 5322105549`. -/ +theorem odTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - dist_le (odTree x1) (odTree x2) 5327301648 := by + dist_le (odTree x1) (odTree x2) 5322105549 := by -- stage 0: prev is the constant leading coefficient (distance 0) have d0 : dist_le (odS0 x1) (odS0 x2) 649038 := by - have h := stage_lip_dist (c := 0xc926ddbf3830ca5561cc01585402d0) (P := 2 ^ 112) (sh := 0x83) (W := Wstep) - (Dprev := 0) (prev1 := 0xdc07aff85e5bb5629d0fb64a84bb) (prev2 := 0xdc07aff85e5bb5629d0fb64a84bb) + have h := stage_lip_dist (c := 0xc926ddbecdeeb42e68cd16db7da8c1) (P := 2 ^ 112) (V := 2 ^ 120) + (sh := 0x7e) (W := Wstep) + (Dprev := 0) (prev1 := 0xdc07aff8276bde9a361278df6a10) (prev2 := 0xdc07aff8276bde9a361278df6a10) (by norm_num) (by norm_num) hv1 hv2 hg1 hg2 (odLead_const _) (by norm_num) (by norm_num) - (by norm_num) - have he : (2 ^ 112 * Wstep + 2 ^ 126 * 0) / 2 ^ 0x83 + 1 = 649038 := by unfold Wstep; decide + (by norm_num) (by norm_num) + have he : (2 ^ 112 * Wstep + 2 ^ 120 * 0) / 2 ^ 0x7e + 1 = 649038 := by unfold Wstep; decide rw [he] at h; exact h - have d1 : dist_le (odS1 x1) (odS1 x2) 5192614 := by - have h := stage_lip_dist (c := 0xad4506b00b1246c7e5b4fd33e1201b) (P := 2 ^ 121) (sh := 0x89) (W := Wstep) + have d1 : dist_le (odS1 x1) (odS1 x2) 5192456 := by + have h := stage_lip_dist (c := 0xad4506af99be27419341e1816ff351) (P := 2 ^ 121) (V := 2 ^ 120) + (sh := 0x84) (W := Wstep) (Dprev := 649038) (le_of_lt (odS0_lt hv1)) (le_of_lt (odS0_lt hv2)) hv1 hv2 hg1 hg2 d0 - (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 121 * Wstep + 2 ^ 126 * 649038) / 2 ^ 0x89 + 1 = 5192614 := by unfold Wstep; decide + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 121 * Wstep + 2 ^ 120 * 649038) / 2 ^ 0x84 + 1 = 5192456 := by unfold Wstep; decide rw [he] at h; exact h - have d2 : dist_le (odS2 x1) (odS2 x2) 5319508291 := by - have h := stage_lip_dist (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (P := 2 ^ 121) (sh := 0x7f) (W := Wstep) - (Dprev := 5192614) (le_of_lt (odS1_lt hv1)) (le_of_lt (odS1_lt hv2)) hv1 hv2 hg1 hg2 d1 - (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 121 * Wstep + 2 ^ 126 * 5192614) / 2 ^ 0x7f + 1 = 5319508291 := by + have d2 : dist_le (odS2 x1) (odS2 x2) 5318210098 := by + have h := stage_lip_dist (c := 0xaf566247c05753b42892f77b67a6b7c6) (P := 2 ^ 121) (V := 2 ^ 120) + (sh := 0x7a) (W := Wstep) + (Dprev := 5192456) (le_of_lt (odS1_lt hv1)) (le_of_lt (odS1_lt hv2)) hv1 hv2 hg1 hg2 d1 + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 121 * Wstep + 2 ^ 120 * 5192456) / 2 ^ 0x7a + 1 = 5318210098 := by unfold Wstep; decide rw [he] at h; exact h - have hfin := stage_lip_dist (c := 0x270a522f476182f119f08da0ba710a56) (P := 2 ^ 129) (sh := 0x87) (W := Wstep) - (Dprev := 5319508291) (le_of_lt (odS2_lt hv1)) (le_of_lt (odS2_lt hv2)) hv1 hv2 hg1 hg2 d2 - (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 129 * Wstep + 2 ^ 126 * 5319508291) / 2 ^ 0x87 + 1 = 5327301648 := by + have hfin := stage_lip_dist (c := 0x270a522f2b285a8374bfa62ed11c30f1) (P := 2 ^ 129) (V := 2 ^ 120) + (sh := 0x82) (W := Wstep) + (Dprev := 5318210098) (le_of_lt (odS2_lt hv1)) (le_of_lt (odS2_lt hv2)) hv1 hv2 hg1 hg2 d2 + (by norm_num) (by norm_num) (by norm_num) (by norm_num) + have he : (2 ^ 129 * Wstep + 2 ^ 120 * 5318210098) / 2 ^ 0x82 + 1 = 5322105549 := by unfold Wstep; decide rw [he] at hfin rw [odTree_layers, odTree_layers]; exact hfin diff --git a/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean b/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean index dd59d5a53..24f554041 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean @@ -10,9 +10,9 @@ For two inputs adjacent in the signed order (`int256 x2 = int256 x1 + 1`) lying G ≤ int256 (tTree x2) − int256 (tTree x1) ≤ G + 1, G = ⌊K27 / 2^107⌋ = 340282366920. ``` -From that, the squared argument `v = ⌊t²/2^128⌋` (which drives the even/odd accumulators) moves by -at most `G + 1`: `|t2² − t1²| = |t2 − t1|·|t2 + t1| < (G + 1)·2^128` since `|t| < 2^127`, and the -common-denominator floor loses at most one unit. +From that, the squared argument `v = ⌊t²/2^133⌋` (which drives the even/odd accumulators) moves by +at most `W = ⌊(G + 1)/2^5⌋ + 1`: `|t2² − t1²| = |t2 − t1|·|t2 + t1| < (G + 1)·2^128` since +`|t| < 2^127`, and the common-denominator floor loses at most one unit at the `2^133` scale. -/ namespace ExpYul @@ -65,27 +65,33 @@ theorem tTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) · nlinarith [hlo1, hhi1, hlo2, hhi2, hK27, hrem_pos, hrem_lt, hp107] · nlinarith [hlo1, hhi1, hlo2, hhi2, hK27, hrem_pos, hrem_lt, hp107] -/-- The squared-argument floor sandwich: `2^128·v ≤ t² < 2^128·v + 2^128`, from `vTree_eq`. -/ +/-- The squared-argument floor sandwich: `2^133·v ≤ t² < 2^133·v + 2^133`, from `vTree_eq`. -/ theorem vTree_sandwich {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 128 : Int) * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ - (int256 (tTree x)) ^ 2 < (2 ^ 128 : Int) * (vTree x : Int) + 2 ^ 128 := by + (2 ^ 133 : Int) * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ + (int256 (tTree x)) ^ 2 < (2 ^ 133 : Int) * (vTree x : Int) + 2 ^ 133 := by obtain ⟨hveq, _⟩ := vTree_eq hx hC hC0 rw [hveq] set a := (int256 (tTree x)) ^ 2 with ha - have h1 := Int.ediv_add_emod a (2 ^ 128) - have h2 := Int.emod_nonneg a (by norm_num : (2 : Int) ^ 128 ≠ 0) - have h3 := Int.emod_lt_of_pos a (by norm_num : (0 : Int) < 2 ^ 128) + have h1 := Int.ediv_add_emod a (2 ^ 133) + have h2 := Int.emod_nonneg a (by norm_num : (2 : Int) ^ 133 ≠ 0) + have h3 := Int.emod_lt_of_pos a (by norm_num : (0 : Int) < 2 ^ 133) constructor <;> nlinarith [h1, h2, h3] -/-- The squared-argument step for adjacent same-octave inputs is bounded by `G + 1`. -/ +/-- The squared-argument step width `W = ⌊(G + 1)/2^5⌋ + 1`: one `v` unit is `2^133` of `t²`, so +the reduced-argument step `G + 1` moves `v` by at most `(G + 1)·2^128/2^133` plus one floor unit. -/ +def Wstep : Nat := 10633823967 + +theorem Wstep_eq : Wstep = (Gstep + 1) / 2 ^ 5 + 1 := by unfold Wstep Gstep; rfl + +/-- The squared-argument step for adjacent same-octave inputs is bounded by `W`. -/ theorem vTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) (hk : int256 (kTree x1) = int256 (kTree x2)) (hadj : int256 x2 = int256 x1 + 1) : - -((Gstep : Int) + 1) ≤ (vTree x2 : Int) - (vTree x1 : Int) ∧ - (vTree x2 : Int) - (vTree x1 : Int) ≤ Gstep + 1 := by + -((Wstep : Int)) ≤ (vTree x2 : Int) - (vTree x1 : Int) ∧ + (vTree x2 : Int) - (vTree x1 : Int) ≤ Wstep := by obtain ⟨htg1, htg2⟩ := tTree_step hx1 hx2 hC1 hC01 hC2 hC02 hk hadj obtain ⟨htlo1, hthi1⟩ := tTree_bound hx1 hC1 hC01 obtain ⟨htlo2, hthi2⟩ := tTree_bound hx2 hC2 hC02 @@ -93,9 +99,9 @@ theorem vTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) obtain ⟨hvlo2, hvhi2⟩ := vTree_sandwich hx2 hC2 hC02 have hGpos : (0 : Int) ≤ Gstep := by unfold Gstep; norm_num have hp127 : (2 : Int) ^ 127 = 170141183460469231731687303715884105728 := by norm_num - have hp128 : (2 : Int) ^ 128 = 340282366920938463463374607431768211456 := by norm_num + have hp133 : (2 : Int) ^ 133 = 10889035741470030830827987437816582766592 := by norm_num rw [hp127] at htlo1 hthi1 htlo2 hthi2 - rw [hp128] at hvlo1 hvhi1 hvlo2 hvhi2 + rw [hp133] at hvlo1 hvhi1 hvlo2 hvhi2 set t1 := int256 (tTree x1) set t2 := int256 (tTree x2) set v1 := (vTree x1 : Int) @@ -103,7 +109,9 @@ theorem vTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) -- `t2² − t1² = (t2 − t1)(t2 + t1)`, with `|t2 − t1| ≤ G + 1`, `|t1 + t2| < 2^128`. have hsqdiff : t2 ^ 2 - t1 ^ 2 = (t2 - t1) * (t2 + t1) := by ring have hGv : (Gstep : Int) = 340282366920 := by unfold Gstep; norm_num - rw [hGv] at htg1 htg2 ⊢ + have hWv : (Wstep : Int) = 10633823967 := by unfold Wstep; norm_num + rw [hGv] at htg1 htg2 + rw [hWv] constructor · nlinarith [hvlo1, hvhi1, hvlo2, hvhi2, htg1, htg2, htlo1, hthi1, htlo2, hthi2, hsqdiff] · nlinarith [hvlo1, hvhi1, hvlo2, hvhi2, htg1, htg2, htlo1, hthi1, htlo2, hthi2, hsqdiff] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean b/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean index 9d4f9f2c9..c2c306b2a 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean @@ -4,10 +4,10 @@ import ExpProof.Mono.Stages # A composed Lipschitz bound for the even/odd Horner accumulators Adjacent same-octave inputs move the reduced argument `t` by the small step `G ≤ t2 − t1 ≤ G + 1`, -hence move `v = ⌊t²/2^128⌋` by at most `W = G + 1`. The even/odd accumulators `Ev`/`Od` are then -nearly constant: each Horner stage `evmAdd c (evmShr sh (evmMul prev v))` changes by a bounded -amount under a bounded change of `v` (and of the incoming accumulator `prev`), and the five/four -stages compose to the constants `DEv`/`DOd`. +hence move `v = ⌊t²/2^133⌋` by at most `W = ⌊(G + 1)/2^5⌋ + 1`. The even/odd accumulators +`Ev`/`Od` are then nearly constant: each Horner stage `evmAdd c (evmShr sh (evmMul prev v))` +changes by a bounded amount under a bounded change of `v` (and of the incoming accumulator +`prev`), and the five/four stages compose to the constants `DEv`/`DOd`. The single-stage bound rests on a floor-difference fact: shifting two operands right by the same amount changes their difference by at most the shifted difference plus one. Everything is stated @@ -40,25 +40,31 @@ theorem add_div_le_add {b n d : Nat} (hd : 0 < d) : have hlt := Nat.lt_of_mul_lt_mul_left key omega -/-- One Horner stage's Lipschitz bound. With `prev_i ≤ P`, `v_i ≤ 2^126`, the products fitting a +/-- One Horner stage's Lipschitz bound. With `prev_i ≤ P`, `v_i < V`, the products fitting a word, `|v2 − v1| ≤ W` and `|prev2 − prev1| ≤ Dprev`, the stage output `evmAdd c (evmShr sh (evmMul -prev v))` moves by at most `⌊(P·W + 2^126·Dprev)/2^sh⌋ + 1`. Stated as a two-sided `Nat` distance -over opaque words. -/ -theorem stage_lip {c prev1 prev2 v1 v2 P Dprev W sh : Nat} - (hp1 : prev1 ≤ P) (hp2 : prev2 ≤ P) (hv1 : v1 < 2 ^ 126) (hv2 : v2 < 2 ^ 126) +prev v))` moves by at most `⌊(P·W + V·Dprev)/2^sh⌋ + 1`. Stated as a two-sided `Nat` distance +over opaque words. The argument cap `V` is a parameter because the monic-fed stage has no +power-of-two headroom: its `P·V` fits a word only against the exact coefficient literal. -/ +theorem stage_lip {c prev1 prev2 v1 v2 P V Dprev W sh : Nat} + (hp1 : prev1 ≤ P) (hp2 : prev2 ≤ P) (hv1 : v1 < V) (hv2 : v2 < V) (hvg1 : v1 ≤ v2 + W) (hvg2 : v2 ≤ v1 + W) (hpg1 : prev1 ≤ prev2 + Dprev) (hpg2 : prev2 ≤ prev1 + Dprev) - (hPV : P * 2 ^ 126 < 2 ^ 256) (hsh : sh < 256) - (hsum1 : c + P * 2 ^ 126 / 2 ^ sh < 2 ^ 256) : + (hPV : P * V < 2 ^ 256) (hsh : sh < 256) + (hsum1 : c + P * V / 2 ^ sh < 2 ^ 256) (hVw : V < 2 ^ 256) : evmAdd c (evmShr sh (evmMul prev1 v1)) ≤ - evmAdd c (evmShr sh (evmMul prev2 v2)) + ((P * W + 2 ^ 126 * Dprev) / 2 ^ sh + 1) ∧ + evmAdd c (evmShr sh (evmMul prev2 v2)) + ((P * W + V * Dprev) / 2 ^ sh + 1) ∧ evmAdd c (evmShr sh (evmMul prev2 v2)) ≤ - evmAdd c (evmShr sh (evmMul prev1 v1)) + ((P * W + 2 ^ 126 * Dprev) / 2 ^ sh + 1) := by + evmAdd c (evmShr sh (evmMul prev1 v1)) + ((P * W + V * Dprev) / 2 ^ sh + 1) := by + -- the caps fit a word: `V` by hypothesis, `P` because `P ≤ P·V < 2^256` (`V ≥ 1` from `v1 < V`) + have hV1 : 0 < V := by omega + have hP256 : P < 2 ^ 256 := by + have := Nat.le_mul_of_pos_right P hV1 + omega -- products are exact (fit a word) and the stage adds are exact (no overflow) - have hpvbnd : ∀ p v : Nat, p ≤ P → v < 2 ^ 126 → p * v < 2 ^ 256 ∧ p * v ≤ P * 2 ^ 126 := by + have hpvbnd : ∀ p v : Nat, p ≤ P → v < V → p * v < 2 ^ 256 ∧ p * v ≤ P * V := by intro p v hp hv have h1 : p * v ≤ P * v := Nat.mul_le_mul_right _ hp - have h2 : P * v ≤ P * 2 ^ 126 := Nat.mul_le_mul_left _ (le_of_lt hv) + have h2 : P * v ≤ P * V := Nat.mul_le_mul_left _ (le_of_lt hv) exact ⟨by omega, by omega⟩ obtain ⟨hpv1lt, hpv1le⟩ := hpvbnd prev1 v1 hp1 hv1 obtain ⟨hpv2lt, hpv2le⟩ := hpvbnd prev2 v2 hp2 hv2 @@ -70,40 +76,40 @@ theorem stage_lip {c prev1 prev2 v1 v2 P Dprev W sh : Nat} rw [hm1]; exact evmShr_eq_div hsh hpv1lt have hs2 : evmShr sh (evmMul prev2 v2) = prev2 * v2 / 2 ^ sh := by rw [hm2]; exact evmShr_eq_div hsh hpv2lt - have hsh1 : prev1 * v1 / 2 ^ sh ≤ P * 2 ^ 126 / 2 ^ sh := Nat.div_le_div_right hpv1le - have hsh2 : prev2 * v2 / 2 ^ sh ≤ P * 2 ^ 126 / 2 ^ sh := Nat.div_le_div_right hpv2le + have hsh1 : prev1 * v1 / 2 ^ sh ≤ P * V / 2 ^ sh := Nat.div_le_div_right hpv1le + have hsh2 : prev2 * v2 / 2 ^ sh ≤ P * V / 2 ^ sh := Nat.div_le_div_right hpv2le have he1 : evmAdd c (evmShr sh (evmMul prev1 v1)) = c + prev1 * v1 / 2 ^ sh := by rw [hs1, evmAdd_eq_nat (by omega) (by omega) (by omega)] have he2 : evmAdd c (evmShr sh (evmMul prev2 v2)) = c + prev2 * v2 / 2 ^ sh := by rw [hs2, evmAdd_eq_nat (by omega) (by omega) (by omega)] rw [he1, he2] - -- bound the product difference: |prev2·v2 − prev1·v1| ≤ P·W + 2^126·Dprev - have hprodbound : ∀ pa pb va vb : Nat, pa ≤ P → pb ≤ P → va < 2 ^ 126 → vb < 2 ^ 126 → + -- bound the product difference: |prev2·v2 − prev1·v1| ≤ P·W + V·Dprev + have hprodbound : ∀ pa pb va vb : Nat, pa ≤ P → pb ≤ P → va < V → vb < V → va ≤ vb + W → pa ≤ pb + Dprev → - pa * va ≤ pb * vb + (P * W + 2 ^ 126 * Dprev) := by + pa * va ≤ pb * vb + (P * W + V * Dprev) := by intro pa pb va vb hpa hpb hva hvb hvgap hpgap -- pa·va ≤ pa·(vb + W) = pa·vb + pa·W ≤ pa·vb + P·W - -- pa·vb ≤ (pb + Dprev)·vb = pb·vb + Dprev·vb ≤ pb·vb + Dprev·2^126 + -- pa·vb ≤ (pb + Dprev)·vb = pb·vb + Dprev·vb ≤ pb·vb + Dprev·V have t1 : pa * va ≤ pa * (vb + W) := Nat.mul_le_mul_left _ hvgap have t2 : pa * (vb + W) = pa * vb + pa * W := by ring have t3 : pa * W ≤ P * W := Nat.mul_le_mul_right _ hpa have t4 : pa * vb ≤ (pb + Dprev) * vb := Nat.mul_le_mul_right _ hpgap have t5 : (pb + Dprev) * vb = pb * vb + Dprev * vb := by ring - have t6 : Dprev * vb ≤ Dprev * 2 ^ 126 := Nat.mul_le_mul_left _ (le_of_lt hvb) - have t7 : Dprev * 2 ^ 126 = 2 ^ 126 * Dprev := Nat.mul_comm _ _ + have t6 : Dprev * vb ≤ Dprev * V := Nat.mul_le_mul_left _ (le_of_lt hvb) + have t7 : Dprev * V = V * Dprev := Nat.mul_comm _ _ omega have hpd12 := hprodbound prev1 prev2 v1 v2 hp1 hp2 hv1 hv2 hvg1 hpg1 have hpd21 := hprodbound prev2 prev1 v2 v1 hp2 hp1 hv2 hv1 hvg2 hpg2 have hsh0 : 0 < 2 ^ sh := Nat.two_pow_pos sh - set B := (P * W + 2 ^ 126 * Dprev) / 2 ^ sh with hB + set B := (P * W + V * Dprev) / 2 ^ sh with hB -- one-sided floor bound: `prev1·v1/2^sh ≤ prev2·v2/2^sh + (B + 1)` - have hone : ∀ pa va pb vb : Nat, pa * va ≤ pb * vb + (P * W + 2 ^ 126 * Dprev) → + have hone : ∀ pa va pb vb : Nat, pa * va ≤ pb * vb + (P * W + V * Dprev) → pa * va / 2 ^ sh ≤ pb * vb / 2 ^ sh + (B + 1) := by intro pa va pb vb hbnd -- `pa·va/2^sh ≤ (pb·vb + N)/2^sh ≤ pb·vb/2^sh + N/2^sh + 1`, and `N/2^sh = B`. - have s1 : pa * va / 2 ^ sh ≤ (pb * vb + (P * W + 2 ^ 126 * Dprev)) / 2 ^ sh := + have s1 : pa * va / 2 ^ sh ≤ (pb * vb + (P * W + V * Dprev)) / 2 ^ sh := Nat.div_le_div_right hbnd - have s2 := add_div_le_add (b := pb * vb) (n := P * W + 2 ^ 126 * Dprev) hsh0 + have s2 := add_div_le_add (b := pb * vb) (n := P * W + V * Dprev) hsh0 rw [← hB] at s2 omega have h12 := hone prev1 v1 prev2 v2 hpd12 diff --git a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean index 4508cc8df..fdcc25839 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean @@ -8,7 +8,7 @@ From the stage bounds this file assembles the closing quotient `r0 = exp(t)·2^1 * `tod = ⌊t·Od / 2^128⌋` transported to `Int`, with `|tod| < 2^125`; * the numerator `num = ev + tod` and denominator `den = ev − tod` are strictly positive (the reduced argument keeps `|tod|` well below `ev`); -* `r0 = sdiv(2^126·num, den)` is strictly positive and below `2^128`. +* `r0 = sdiv(2^126·num, den)` is at least `2^123` and below `2^128`. These give the range and nonnegativity obligations directly, and (via the cross-multiplication identity) reduce the within-octave monotonicity to a fact about `tod·ev`. @@ -77,7 +77,7 @@ theorem todTree_bound {x : Nat} (hx : x < 2 ^ 256) /-- Abstract numerator/denominator positivity: stated over opaque words `E` (the even accumulator) and `TD` (the signed `t·Od` shift) with their bounds, so the deep Horner tree is never forced. -/ theorem numden_pos_of {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) - (hev_lo : (103786963415199049567855548359006885036 : Int) ≤ (E : Int)) + (hev_lo : (103786963397729689639908782561058906594 : Int) ≤ (E : Int)) (hev_hi : (E : Int) < 2 ^ 127) (htod_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD) (htod_hi : int256 TD < 42535295865117307932921825928971026432) : @@ -116,8 +116,8 @@ theorem numden_pos {x : Nat} (hx : x < 2 ^ 256) have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ refine numden_pos_of hevw htodw ?_ ?_ ?_ ?_ - · have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 by norm_num] at this + · have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 by norm_num] at this exact this · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hev_hi rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this @@ -127,14 +127,15 @@ theorem numden_pos {x : Nat} (hx : x < 2 ^ 256) /-! ## The closing quotient `r0 = exp(t)·2^126` -/ /-- Abstract quotient bounds over opaque numerator/denominator words. `r0 = ⌊2^126·N/D⌋` lies in -`[1, 2^128)`: the dividend `2^126·N` fits a word, `D ≤ 2^126·N` keeps the quotient `≥ 1`, and +`[2^123, 2^128)`: the dividend `2^126·N` fits a word, `2^123·D < 2^251 ≤ 2^126·N` keeps the +quotient `≥ 2^123` (which the closing stage needs, since the margin exceeds one wad unit), and `N < 4·D` keeps it below `2^128`. -/ theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD : D < 2 ^ 256) (hDi : int256 D = (D : Int)) (hNpos : 0 < (N : Int)) (hDpos : 0 < (D : Int)) (hNlo : 2 ^ 125 ≤ N) (hND : (N : Int) < 4 * (D : Int)) : - 1 ≤ int256 (evmSdiv (evmShl 0x7e N) D) ∧ int256 (evmSdiv (evmShl 0x7e N) D) < 2 ^ 128 := by + 2 ^ 123 ≤ int256 (evmSdiv (evmShl 0x7e N) D) ∧ int256 (evmSdiv (evmShl 0x7e N) D) < 2 ^ 128 := by -- shl(126, N) = N·2^126 (fits: N < 2^128 ⇒ N·2^126 < 2^254) have hshl : evmShl 0x7e N = N * 2 ^ 0x7e := by refine evmShl_eq (by norm_num) ?_ @@ -181,12 +182,12 @@ theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD _ = 2 ^ 128 * D := by rw [show (4:Nat) * D * 2 ^ 0x7e = (4 * 2 ^ 0x7e) * D by ring, show (4:Nat) * 2 ^ 0x7e = 2 ^ 128 by norm_num] - have hq_ge : 1 ≤ q := by - rw [hq, Nat.le_div_iff_mul_le hDnat_pos, Nat.one_mul] - -- D < 2^128 ≤ 2^125·2^126 ≤ N·2^126 - have h1 : (2:Nat) ^ 128 ≤ 2 ^ 125 * 2 ^ 0x7e := by - rw [← Nat.pow_add]; exact Nat.pow_le_pow_right (by norm_num) (by norm_num) - have h2 : (2:Nat) ^ 125 * 2 ^ 0x7e ≤ N * 2 ^ 0x7e := Nat.mul_le_mul_right _ hNlo + have hq_ge : 2 ^ 123 ≤ q := by + rw [hq, Nat.le_div_iff_mul_le hDnat_pos] + -- 2^123·D < 2^123·2^128 = 2^125·2^126 ≤ N·2^126 + have h1 : (2:Nat) ^ 123 * D ≤ 2 ^ 123 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hDlt) + have h2 : (2:Nat) ^ 123 * 2 ^ 128 = 2 ^ 125 * 2 ^ 0x7e := by norm_num + have h3 : (2:Nat) ^ 125 * 2 ^ 0x7e ≤ N * 2 ^ 0x7e := Nat.mul_le_mul_right _ hNlo omega exact ⟨by exact_mod_cast hq_ge, by have : (q : Int) < 2 ^ 128 := by exact_mod_cast hq_lt @@ -202,15 +203,15 @@ theorem int256_eq_of_nonneg {w : Nat} (hw : w < 2 ^ 256) (hnn : 0 ≤ int256 w) · rename_i h; exfalso; simp only [ipow256] at hnn; have : (w : Int) < 2 ^ 256 := by exact_mod_cast hw simp only [ipow256] at this; omega -/-- Abstract `r0` bounds: `1 ≤ r0 < 2^128` over opaque even/odd words `E`, `TD` with their bounds. -`r0 = sdiv(2^126·(E+TD), E−TD)`; the numerator and denominator are positive and the quotient lands -in `[1, 2^128)` (the reduced argument keeps `exp(t) ∈ [1/√2, √2)`). -/ +/-- Abstract `r0` bounds: `2^123 ≤ r0 < 2^128` over opaque even/odd words `E`, `TD` with their +bounds. `r0 = sdiv(2^126·(E+TD), E−TD)`; the numerator and denominator are positive and the +quotient lands in `[2^123, 2^128)` (the reduced argument keeps `exp(t) ∈ [1/√2, √2)`). -/ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) - (hev_lo : (103786963415199049567855548359006885036 : Int) ≤ (E : Int)) + (hev_lo : (103786963397729689639908782561058906594 : Int) ≤ (E : Int)) (hev_hi : (E : Int) < 2 ^ 127) (htod_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD) (htod_hi : int256 TD < 42535295865117307932921825928971026432) : - 1 ≤ int256 (evmSdiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) ∧ + 2 ^ 123 ≤ int256 (evmSdiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) ∧ int256 (evmSdiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) < 2 ^ 128 := by obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos_of hevw htodw hev_lo hev_hi htod_lo htod_hi have hNwlt : evmAdd E TD < 2 ^ 256 := evmAdd_lt _ _ @@ -239,10 +240,10 @@ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 have hDpos : 0 < ((evmSub E TD : Nat) : Int) := by rw [← hDi, hsub]; omega exact r0Tree_bounds_of hNlt128 hDlt128 hDwlt hDi hNpos hDpos hNlo hND -/-- `1 ≤ r0Tree x < 2^128` on the meaningful region. -/ +/-- `2^123 ≤ r0Tree x < 2^128` on the meaningful region. -/ theorem r0Tree_bounds {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 1 ≤ int256 (r0Tree x) ∧ int256 (r0Tree x) < 2 ^ 128 := by + 2 ^ 123 ≤ int256 (r0Tree x) ∧ int256 (r0Tree x) < 2 ^ 128 := by obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 obtain ⟨hev_lo, hev_hi⟩ := evTree_facts hvlt obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 @@ -252,8 +253,8 @@ theorem r0Tree_bounds {x : Nat} (hx : x < 2 ^ 256) have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ refine r0Tree_bounds_ofEvTod hevw htodw ?_ ?_ ?_ ?_ - · have : (0x4e14a45e8ec305e233e11b4174e214ac : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x4e14a45e8ec305e233e11b4174e214ac : Int) = 103786963415199049567855548359006885036 by norm_num] at this + · have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 by norm_num] at this exact this · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hev_hi rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean index 060526562..d34b971e7 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -7,8 +7,9 @@ import ExpProof.Mono.Quot `10¹⁸·2¹²⁶` grid, subtracts the one-sided margin, and floors with the `2ᵏ` octave scaling folded into the shift (`126 − k ∈ [63, 187]`). -* **nonneg**: `r0 ≥ 1` gives `WAD·r0 ≥ WAD > MARGIN`, so the shift argument is nonnegative; a - nonnegative arithmetic shift stays nonnegative. +* **nonneg**: `r0 ≥ 2^123` gives `WAD·r0 > MARGIN` (the margin exceeds one wad unit, so `r0 ≥ 1` + alone would not do), and the shift argument is nonnegative; a nonnegative arithmetic shift + stays nonnegative. * **range**: `r0 < 2^128` gives `WAD·r0 < 2^188`, so even before the shift the argument is below `2^188`, and the floor is below `2^125 < 2^254`. -/ @@ -54,21 +55,22 @@ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) /-! ## The shift argument `WAD·r0 − MARGIN` -/ -/-- Abstract bound on the shift argument `WAD·r0 − MARGIN` over an opaque `r0` word in `[1, 2^128)`: -its signed value is in `[WAD − MARGIN, 2^188)`, in particular nonnegative and below `2^188`. -/ +/-- Abstract bound on the shift argument `WAD·r0 − MARGIN` over an opaque `r0` word in +`[2^123, 2^128)`: its signed value is in `[WAD·2^123 − MARGIN, 2^188)`, in particular nonnegative +and below `2^188`. -/ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) - (hr0_lo : 1 ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 128) : - int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) = - 0xde0b6b3a7640000 * int256 r0 - 0x9fe769d0fa58e9f ∧ - 0 ≤ 0xde0b6b3a7640000 * int256 r0 - 0x9fe769d0fa58e9f ∧ - 0xde0b6b3a7640000 * int256 r0 - 0x9fe769d0fa58e9f < 2 ^ 188 := by + (hr0_lo : (2 ^ 123 : Int) ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 128) : + int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) = + 0xde0b6b3a7640000 * int256 r0 - 0xe17cfd91868d72d ∧ + 0 ≤ 0xde0b6b3a7640000 * int256 r0 - 0xe17cfd91868d72d ∧ + 0xde0b6b3a7640000 * int256 r0 - 0xe17cfd91868d72d < 2 ^ 188 := by have hwad : int256 (0xde0b6b3a7640000 : Nat) = 0xde0b6b3a7640000 := by rw [int256_of_lt (by norm_num)]; simp have hwadlt : (0xde0b6b3a7640000 : Nat) < 2 ^ 256 := by norm_num have hp128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num have hp188 : (2:Int)^188 = 392318858461667547739736838950479151006397215279002157056 := by norm_num have hwadc : (0xde0b6b3a7640000 : Int) = 1000000000000000000 := by norm_num - have hmarc : (0x9fe769d0fa58e9f : Int) = 720143407370309279 := by norm_num + have hmarc : (0xe17cfd91868d72d : Int) = 1015508772319713069 := by norm_num rw [hp128] at hr0_hi -- the product WAD·r0 transported have hmul : int256 (evmMul 0xde0b6b3a7640000 r0) = 0xde0b6b3a7640000 * int256 r0 := by @@ -77,18 +79,21 @@ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) rw [hwad] at this; exact this have hmullt : evmMul 0xde0b6b3a7640000 r0 < 2 ^ 256 := evmMul_lt _ _ - have hmarlt : (0x9fe769d0fa58e9f : Nat) < 2 ^ 256 := by norm_num - have hmari : int256 (0x9fe769d0fa58e9f : Nat) = 0x9fe769d0fa58e9f := by + have hmarlt : (0xe17cfd91868d72d : Nat) < 2 ^ 256 := by norm_num + have hmari : int256 (0xe17cfd91868d72d : Nat) = 0xe17cfd91868d72d := by rw [int256_of_lt (by norm_num)]; simp -- transport the subtraction - have hsub : int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) = - 0xde0b6b3a7640000 * int256 r0 - 0x9fe769d0fa58e9f := by + have hsub : int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) = + 0xde0b6b3a7640000 * int256 r0 - 0xe17cfd91868d72d := by have := evmSub_transport hmullt hmarlt (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) rw [hmul, hmari] at this; exact this refine ⟨hsub, ?_, ?_⟩ - · rw [hwadc, hmarc]; nlinarith [hr0_lo] + · rw [hwadc, hmarc] + have hp123 : (2:Int)^123 = 10633823966279326983230456482242756608 := by norm_num + rw [hp123] at hr0_lo + nlinarith [hr0_lo] · rw [hwadc, hmarc, hp188]; nlinarith [hr0_hi] /-! ## Abstract floor facts for the closing shift -/ @@ -135,7 +140,7 @@ theorem r1Tree_int256_nonneg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi have hr1 : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) := rfl + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) := rfl rw [hr1, hseq] exact (closingSar_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi)).1 @@ -148,11 +153,11 @@ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi have hr1 : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) := rfl - obtain ⟨hnn, hlt⟩ := closingSar_facts (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f) + (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) := rfl + obtain ⟨hnn, hlt⟩ := closingSar_facts (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi) -- int256 (r1Tree x) ∈ [0, 2^125) ⇒ the Nat word is < 2^254 - have hReq : int256 (r1Tree x) = int256 (evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0x9fe769d0fa58e9f)) := by + have hReq : int256 (r1Tree x) = int256 (evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d)) := by rw [hr1, hseq] rw [← hReq] at hnn hlt have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x diff --git a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean index 5913821c2..e1650adef 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean @@ -24,7 +24,7 @@ theorem run_exp_ray_to_wad_evm_eq_expTree rw [run_exp_ray_to_wad_evm_eq_tree x hval] unfold expTree r1Tree r0Tree todTree odTree evTree vTree tTree kTree unfold Cmask kRoundShift kHalfShift cInvQ200 k27Q235 ln2Q235 tArgShift squareShift - unfold ev0 ev1 ev2 ev3 ev4 evShift0 evShift1 evShift2 evShift3 evShift4 + unfold ev0 ev1 ev2 ev3 ev4 evShift1 evShift2 evShift3 evShift4 unfold od0 od1 od2 od3 od4 odShift1 odShift2 odShift3 odShift4 unfold todShift expQShift wadWord marginWord rfl diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean index 1e0bf8c0d..fc986cde4 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -10,8 +10,9 @@ exactly one bit, so with the same shift argument `arg = WAD·r0 − MARGIN` the r1Tree x2 = ⌊arg2 / 2^(s−1)⌋ = ⌊2·arg2 / 2^s⌋ ≥ ⌊arg1 / 2^s⌋ = r1Tree x1 ⟸ arg1 ≤ 2·arg2 ``` -reduces the seam step to `arg1 ≤ 2·arg2`, which (since `MARGIN < WAD`) follows from the **`r0` -doubling bound** `r0Tree x1 < 2·r0Tree x2` (`SeamR0Bound`). The reduction is assembled over the +reduces the seam step to `arg1 ≤ 2·arg2`, which (since `MARGIN < 2·WAD`) follows from the **`r0` +doubling bound** `r0Tree x1 + 2 ≤ 2·r0Tree x2` (`SeamR0Bound`; the comparison consumes two +integer units of the doubling gap because the margin exceeds one wad unit). The reduction is assembled over the opaque shift-argument words (`seam_close`), so the deep `evmSar`/`evmSub`/`evmMul` tree behind `r1Tree` is never forced into whnf. -/ @@ -25,16 +26,18 @@ set_option maxRecDepth 100000 /-- **The `r0` doubling bound across a seam.** For adjacent inputs crossing one octave (`int256 (kTree x2) = int256 (kTree x1) + 1`, `int256 x2 = int256 x1 + 1`), the Q126 quotient at -most doubles: `r0Tree x1 < 2·r0Tree x2`. (Across the seam the reduced argument flips sign -`t_b ≈ −t_a`, so `r0_a ≈ exp(t_a)·2^126 ≈ √2·2^126` and `r0_b ≈ exp(−t_a)·2^126 ≈ 2^126/√2`, hence -`r0_a/r0_b ≈ 2`.) -/ +most doubles, two units short: `r0Tree x1 + 2 ≤ 2·r0Tree x2`. (Across the seam the reduced +argument flips sign `t_b ≈ −t_a`, so `r0_a ≈ exp(t_a)·2^126 ≈ √2·2^126` and +`r0_b ≈ exp(−t_a)·2^126 ≈ 2^126/√2`, hence `r0_a/r0_b ≈ 2·exp(−1/RAY)`, short of doubling by +`≈ 2·r0_b/RAY ≈ 1.7·10^11` grid units — far more than the two units consumed by the seam-floor +comparison below.) -/ def SeamR0Bound : Prop := ∀ {x1 x2 : Nat}, x1 < 2 ^ 256 → x2 < 2 ^ 256 → int256 Cmask < int256 x1 → int256 x1 < int256 C0thresh → int256 Cmask < int256 x2 → int256 x2 < int256 C0thresh → int256 (kTree x2) = int256 (kTree x1) + 1 → int256 x2 = int256 x1 + 1 → - int256 (r0Tree x1) < 2 * int256 (r0Tree x2) + int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) /-- Abstract seam floor reduction over opaque shift-argument words and shift amounts. With the closing shift dropping one bit (`s2 + 1 = s1`) and `arg1 ≤ 2·arg2`, the two arithmetic-shift floors @@ -84,21 +87,21 @@ theorem seamStep_of_r0 (hr0 : SeamR0Bound) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (h obtain ⟨harg1eq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 obtain ⟨harg2eq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 have hr1eq1 : r1Tree x1 = - evmSar s1 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0x9fe769d0fa58e9f) := by + evmSar s1 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xe17cfd91868d72d) := by unfold r1Tree; rw [hs1eq] have hr1eq2 : r1Tree x2 = - evmSar s2 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0x9fe769d0fa58e9f) := by + evmSar s2 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xe17cfd91868d72d) := by unfold r1Tree; rw [hs2eq] rw [hr1eq1, hr1eq2] -- name the deep shift arguments opaquely before feeding the floor lemma - set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0x9fe769d0fa58e9f with harg1def - set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0x9fe769d0fa58e9f with harg2def - have hr0bound : int256 (r0Tree x1) < 2 * int256 (r0Tree x2) := + set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xe17cfd91868d72d with harg1def + set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xe17cfd91868d72d with harg2def + have hr0bound : int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) := hr0 hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hargle : int256 arg1 ≤ 2 * int256 arg2 := by rw [harg1eq, harg2eq, show (0xde0b6b3a7640000 : Int) = 1000000000000000000 by norm_num, - show (0x9fe769d0fa58e9f : Int) = 720143407370309279 by norm_num] - -- `WAD·r0a − M ≤ 2·(WAD·r0b − M)` ⟸ `WAD·r0a + M ≤ 2·WAD·r0b` ⟸ `r0a ≤ 2·r0b − 1` and `M ≤ WAD` + show (0xe17cfd91868d72d : Int) = 1015508772319713069 by norm_num] + -- `WAD·r0a − M ≤ 2·(WAD·r0b − M)` ⟸ `WAD·r0a + M ≤ 2·WAD·r0b` ⟸ `r0a ≤ 2·r0b − 2` and `M ≤ 2·WAD` nlinarith [hr0bound] exact seam_close (harg1def ▸ evmSub_lt _ _) (harg2def ▸ evmSub_lt _ _) hs1lt hs2lt hseq hargle diff --git a/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean b/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean index f7cb416a7..333826673 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean @@ -1,15 +1,18 @@ import ExpProof.Mono.Top -import ExpProof.Floor.R0Exp +import ExpProof.Floor.R0ExpUnder /-! # Discharging the octave-seam `r0`-doubling bound for monotonicity -`SeamR0Bound` (`r0Tree x1 < 2·r0Tree x2` across one octave seam) is the single analytic obligation -that `run_exp_ray_to_wad_evm_mono_of_seamR0` carries. The per-point real bracket `r0Tree x ≈ -2¹²⁶·exp(rt)` (`Floor.R0Exp`, both signs) together with the seam exp relation `rt1 = rt2 + ln2 − -1/RAY` discharges it: `exp(rt1) = 2·exp(rt2)·exp(−1/RAY) < 2·exp(rt2)` strictly, and the -`1 − exp(−1/RAY) ≈ 1/RAY` slack (against `r0Tree x2 > 2¹²⁴`) dwarfs the loose per-point envelope -constants. This closes `run_exp_ray_to_wad_evm_mono` without an external monotonicity hypothesis. +`SeamR0Bound` (`r0Tree x1 + 2 ≤ 2·r0Tree x2` across one octave seam) is the single analytic +obligation that `run_exp_ray_to_wad_evm_mono_of_seamR0` carries. The per-point real bracket +`r0Tree x ≈ 2¹²⁶·exp(rt)` (`Floor.R0Exp`/`Floor.R0ExpUnder`, both signs) together with the seam +exp relation +`rt1 = rt2 + ln2 − 1/RAY` discharges it: `exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`, and the +`1 − exp(−1/RAY) ≈ 1/RAY` slack (against `r0Tree x2 > 2¹²⁴`, worth `≈ 1.7·10¹¹` grid units) +dwarfs both the loose per-point envelope constants and the two integer units the seam-floor +comparison consumes. This closes `run_exp_ray_to_wad_evm_mono` without an external monotonicity +hypothesis. -/ namespace ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean index e07d2235e..794654998 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean @@ -4,11 +4,14 @@ import ExpProof.Mono.Octave # Horner-stage transports for the `exp` kernel The reduced argument `t = tTree x` is bounded by `2^127` on the meaningful region (the octave -reduction keeps `|t| < ln2/2 · 2^128`). From that bound this file transports the downstream kernel -stages to closed `Int`/bound forms: +reduction keeps `|t| < ln2/2 · 2^128`; a sharper `1.2·10^38` form squares below `2^253`). From +those bounds this file transports the downstream kernel stages to closed `Int`/bound forms: -* `v = t²` in Q128 (a nonnegative logical shift, `< 2^126`); -* the even/odd Horner accumulators `ev`, `od` (two-sided constant bounds); +* `v = t²` in Q123 (a nonnegative logical shift, `< 2^120`); +* the even/odd Horner accumulators `ev`, `od` (two-sided constant bounds); the monic leading + stage is a bare add of `v` at its own basis, and its product with `v` is the only stage with + no power-of-two headroom — its multiply safety rests on the exact coefficient literal against + `v < 2^120`; * `tod = t·Od` in Q87 (a signed shift, transported to `Int`); * the numerator `ev + tod` and denominator `ev − tod` are both strictly positive; * `r0 = exp(t)·2^126`, the reciprocal-symmetric quotient, is strictly positive and `< 2^128`. @@ -105,53 +108,125 @@ theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) · nlinarith [htlo', hthi', hklo', hkhi', hxlo, hxhi] · nlinarith [htlo', hthi', hklo', hkhi', hxlo, hxhi] -/-! ## `v = t²` in Q128 -/ +/-- The sharper reduced-argument bound `|t| < 1.2·10^38`: the true envelope is +`ln2/2 · 2^128 ≈ 1.1793·10^38`, and this relaxation still squares below `2^253`, which is what the +Q123 square and the monic-stage multiply safety need. Same sandwich elimination as `tTree_bound`, +closed against the sharper literal. -/ +theorem tTree_bound_sharp {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + -(120000000000000000000000000000000000000 : Int) < int256 (tTree x) ∧ + int256 (tTree x) < 120000000000000000000000000000000000000 := by + obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 + obtain ⟨hklo, hkhi⟩ := kTree_sandwich hx hC hC0 + obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 + have hb96 : (2 : Int) ^ 96 = 79228162514264337593543950336 := by norm_num + rw [hb96] at hxlo hxhi + have hK27 : (0x279d346de4781f921dd7a89933d54d1f72928 : Int) = + 55213970774324510299478046898216203619608872 := by norm_num + have hLN2 : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = + 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num + have hCINV : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by + norm_num + rw [hK27, hLN2] at htlo hthi + rw [hCINV] at hklo hkhi + set t := int256 (tTree x) + set k := int256 (kTree x) + set X := int256 x + have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num + have p199 : (2 : Int) ^ 199 = + 803469022129495137770981046170581301261101496891396417650688 := by norm_num + have p200 : (2 : Int) ^ 200 = + 1606938044258990275541962092341162602522202993782792835301376 := by norm_num + rw [p107] at htlo hthi + rw [p199, p200] at hklo hkhi + have hLN2pos : (0 : Int) < 38271408169742254668347313025622401492114385419650052359639581444463709 := by + norm_num + have hklo' : 38271408169742254668347313025622401492114385419650052359639581444463709 * + (1606938044258990275541962092341162602522202993782792835301376 * k) ≤ + 38271408169742254668347313025622401492114385419650052359639581444463709 * + (803469022129495137770981046170581301261101496891396417650688 + + 2318321547468254865173387471183990 * X) := + mul_le_mul_left_nonneg hklo (le_of_lt hLN2pos) + have hkhi' : 38271408169742254668347313025622401492114385419650052359639581444463709 * + (803469022129495137770981046170581301261101496891396417650688 + + 2318321547468254865173387471183990 * X) < + 38271408169742254668347313025622401492114385419650052359639581444463709 * + (1606938044258990275541962092341162602522202993782792835301376 * k + + 1606938044258990275541962092341162602522202993782792835301376) := + by + have := mul_le_mul_left_nonneg (le_of_lt hkhi) (le_of_lt hLN2pos) + rcases lt_or_eq_of_le this with h | h + · exact h + · exact absurd h.symm (by + have := Int.mul_lt_mul_of_pos_left hkhi hLN2pos; omega) + have hp200pos : (0 : Int) < 1606938044258990275541962092341162602522202993782792835301376 := by + norm_num + have htlo' : 1606938044258990275541962092341162602522202993782792835301376 * + (162259276829213363391578010288128 * t) ≤ + 1606938044258990275541962092341162602522202993782792835301376 * + (55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k) := + mul_le_mul_left_nonneg htlo (le_of_lt hp200pos) + have hthi' : 1606938044258990275541962092341162602522202993782792835301376 * + (55213970774324510299478046898216203619608872 * X - + 38271408169742254668347313025622401492114385419650052359639581444463709 * k) < + 1606938044258990275541962092341162602522202993782792835301376 * + (162259276829213363391578010288128 * t + 162259276829213363391578010288128) := + by + have := mul_le_mul_left_nonneg (le_of_lt hthi) (le_of_lt hp200pos) + rcases lt_or_eq_of_le this with h | h + · exact h + · exact absurd h.symm (by + have := Int.mul_lt_mul_of_pos_left hthi hp200pos; omega) + constructor + · nlinarith [htlo', hthi', hklo', hkhi', hxlo, hxhi] + · nlinarith [htlo', hthi', hklo', hkhi', hxlo, hxhi] -/-- The Q128 square `v = ⌊t²/2^128⌋` as a `Nat`: nonnegative, and `< 2^126`. The shift argument -`t·t` fits in a word because `|t| < 2^127` gives `t² < 2^254`. -/ +/-! ## `v = t²` in Q123 -/ + +/-- The Q123 square `v = ⌊t²/2^133⌋` as a `Nat`: nonnegative, and `< 2^120`. The shift argument +`t·t` fits in a word because `|t| < 1.2·10^38` gives `t² < 2^253`. -/ theorem vTree_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (vTree x : Int) = (int256 (tTree x))^2 / 2 ^ 128 ∧ vTree x < 2 ^ 126 := by - obtain ⟨htlo, hthi⟩ := tTree_bound hx hC hC0 + (vTree x : Int) = (int256 (tTree x))^2 / 2 ^ 133 ∧ vTree x < 2 ^ 120 := by + obtain ⟨htlo, hthi⟩ := tTree_bound_sharp hx hC hC0 have htw : tTree x < 2 ^ 256 := by unfold tTree; exact evmSar_lt _ _ -- the signed square equals the unsigned product of the canonical word with itself set t := int256 (tTree x) with htdef - have hsq_lt : t ^ 2 < 2 ^ 254 := by - have hp127 : (2:Int)^127 = 170141183460469231731687303715884105728 := by norm_num - have hp254 : (2:Int)^254 = 28948022309329048855892746252171976963317496166410141009864396001978282409984 := by norm_num - rw [hp127] at htlo hthi - rw [hp254, sq] + have hsq_lt : t ^ 2 < 2 ^ 253 := by + have hp253 : (2:Int)^253 = 14474011154664524427946373126085988481658748083205070504932198000989141204992 := by norm_num + rw [hp253, sq] nlinarith [htlo, hthi] have hsq_nn : 0 ≤ t ^ 2 := by positivity - -- `tTree x · tTree x` as a word equals `t²` (transport), nonneg, `< 2^254`. + -- `tTree x · tTree x` as a word equals `t²` (transport), nonneg, `< 2^253`. have hmul : int256 (evmMul (tTree x) (tTree x)) = t * t := evmMul_transport htw htw (by rw [← sq]; simp only [ipow255]; nlinarith [hsq_nn, hsq_lt]) (by rw [← sq]; simp only [ipow255]; nlinarith [hsq_lt]) have hmul_lt : evmMul (tTree x) (tTree x) < 2 ^ 256 := evmMul_lt _ _ - -- its `int256` is nonneg and below `2^254`, so it is the literal Nat value + -- its `int256` is nonneg and below `2^253`, so it is the literal Nat value have hmul_small : evmMul (tTree x) (tTree x) < 2 ^ 255 := by have h := hmul unfold int256 at h split at h <;> simp only [ipow255, ipow256] at * <;> nlinarith [hsq_nn, hsq_lt] have hmul_nat : (evmMul (tTree x) (tTree x) : Int) = t * t := by rw [← hmul]; exact (int256_of_lt hmul_small).symm - have hmul_nat_lt : evmMul (tTree x) (tTree x) < 2 ^ 254 := by - have : ((evmMul (tTree x) (tTree x) : Nat) : Int) < 2 ^ 254 := by + have hmul_nat_lt : evmMul (tTree x) (tTree x) < 2 ^ 253 := by + have : ((evmMul (tTree x) (tTree x) : Nat) : Int) < 2 ^ 253 := by rw [hmul_nat, ← sq]; exact hsq_lt exact_mod_cast this refine ⟨?_, ?_⟩ · unfold vTree rw [evmShr_eq_div (by norm_num) hmul_lt] - have he : ((evmMul (tTree x) (tTree x) / 2 ^ 128 : Nat) : Int) = - (evmMul (tTree x) (tTree x) : Int) / 2 ^ 128 := by + have he : ((evmMul (tTree x) (tTree x) / 2 ^ 133 : Nat) : Int) = + (evmMul (tTree x) (tTree x) : Int) / 2 ^ 133 := by rw [Int.ofNat_ediv]; norm_num rw [he, hmul_nat, ← sq] · unfold vTree rw [evmShr_eq_div (by norm_num) hmul_lt] - have : evmMul (tTree x) (tTree x) / 2 ^ 128 < 2 ^ 254 / 2 ^ 128 := + have : evmMul (tTree x) (tTree x) / 2 ^ 133 < 2 ^ 253 / 2 ^ 133 := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hmul_nat_lt - have he : (2:Nat) ^ 254 / 2 ^ 128 = 2 ^ 126 := by + have he : (2:Nat) ^ 253 / 2 ^ 133 = 2 ^ 120 := by rw [Nat.pow_div (by norm_num) (by norm_num)] omega @@ -204,7 +279,9 @@ theorem stage_ge {c prev v sh : Nat} (hc : c < 2 ^ 256) Each stage `evmAdd c (evmShr sh (evmMul prev v))` is bounded two-sidedly: it never wraps (so it dominates its leading coefficient `c`), and the truncated tail keeps it below `c + ⌊P·V/2^sh⌋`. -The bounds chain from `v < 2^126` through the five even / four odd stages. -/ +The bounds chain from `v < 2^120` through the five even / four odd stages; the monic leading +stage contributes `ev0 + v` directly, so the first multiply's safety cap is the exact sum +`ev0 + 2^120` rather than a power of two. -/ /-- The truncated stage tail is bounded by `⌊P·V/2^sh⌋`. -/ theorem stage_term_le {prev v P V sh : Nat} (hprev : prev < P) (hv : v < V) @@ -234,111 +311,108 @@ theorem stage_bounds {c prev v P V sh : Nat} (hprev : prev < P) (hv : v < V) have hc256 : c < 2 ^ 256 := by omega exact stage_ge hc256 (by omega) -theorem ev0_lt {v : Nat} (hv : v < 2 ^ 126) : - evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) < 2 ^ 113 := by - have hsh0 : evmShr 0x1d v = v / 2 ^ 0x1d := evmShr_eq_div (by norm_num) (by omega) - have hev0t : v / 2 ^ 0x1d < 2 ^ 97 := by - have : v / 2 ^ 0x1d < 2 ^ 126 / 2 ^ 0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv - have he : (2:Nat) ^ 126 / 2 ^ 0x1d = 2 ^ 97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] - omega - rw [hsh0, evmAdd_eq_nat (by norm_num) (by omega) (by omega)]; omega +/-- The monic leading stage `ev0 + v` is an exact add, capped by the exact sum `ev0 + 2^120`. -/ +theorem ev0_lt {v : Nat} (hv : v < 2 ^ 120) : + evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v < + 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120 := by + rw [evmAdd_eq_nat (by norm_num) (by omega) (by omega)]; omega -theorem ev0_ge {v : Nat} (hv : v < 2 ^ 126) : - 0xb9aacfad41060587203a79af0ebc ≤ evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) := by - have hsh0 : evmShr 0x1d v = v / 2 ^ 0x1d := evmShr_eq_div (by norm_num) (by omega) - have hev0t : v / 2 ^ 0x1d < 2 ^ 97 := by - have : v / 2 ^ 0x1d < 2 ^ 126 / 2 ^ 0x1d := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hv - have he : (2:Nat) ^ 126 / 2 ^ 0x1d = 2 ^ 97 := by rw [Nat.pow_div (by norm_num) (by norm_num)] - omega - rw [hsh0, evmAdd_eq_nat (by norm_num) (by omega) (by omega)]; omega +theorem ev0_ge {v : Nat} (hv : v < 2 ^ 120) : + 0xb9aacfacf3c10b378435f8e22adf48500e ≤ evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v := by + rw [evmAdd_eq_nat (by norm_num) (by omega) (by omega)]; omega /-- Helper to discharge `2^pe·2^ve/2^sh = 2^e` for the chained stage ceilings. -/ theorem pvd (pe ve sh e : Nat) (hpe : pe + ve = sh + e) : (2:Nat) ^ pe * 2 ^ ve / 2 ^ sh = 2 ^ e := by rw [← Nat.pow_add, hpe, Nat.pow_add, Nat.mul_div_cancel_left _ (Nat.two_pow_pos sh)] -/-- Two-sided bound on the even Horner accumulator: `0x4e14… ≤ ev < 2^127`. -/ -theorem evTree_facts {x : Nat} (hv : vTree x < 2 ^ 126) : - 0x4e14a45e8ec305e233e11b4174e214ac ≤ evTree x ∧ evTree x < 2 ^ 127 := by +/-- Two-sided bound on the even Horner accumulator: `0x4e14… ≤ ev < 2^127`. The first multiply +`(ev0 + v)·v` is capped by the exact literal sum `(ev0 + 2^120)·2^120 < 2^256` — it has no +power-of-two headroom. -/ +theorem evTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : + 0x4e14a45e5650b506e97f4c5da23861e2 ≤ evTree x ∧ evTree x < 2 ^ 127 := by have hev : evTree x = - evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d (vTree x))) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl + evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e (vTree x)) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl rw [hev] set v := vTree x with hvdef have h0 := ev0_lt hv - set ev0 := evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v) with hev0 - have h1 : evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul ev0 v)) < 2 ^ 121 := by - have := (stage_bounds (c := 0x9a036222e11aee18465042f8ea64c8) (prev := ev0) (v := v) - (P := 2 ^ 113) (V := 2 ^ 126) (sh := 0x82) h0 hv (by norm_num) (by norm_num) - (by rw [pvd 113 126 130 109 (by norm_num)]; norm_num)).2 - rw [pvd 113 126 130 109 (by norm_num)] at this; omega - set ev1 := evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul ev0 v)) with hev1 - have h2 : evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul ev1 v)) < 2 ^ 129 := by - have := (stage_bounds (c := 0x9064d965e1c4863b73604e0ddbec53f9) (prev := ev1) (v := v) - (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x80) h1 hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 128 119 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 128 119 (by norm_num)] at this; omega - set ev2 := evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul ev1 v)) with hev2 - have h3 : evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul ev2 v)) < 2 ^ 129 := by - have := (stage_bounds (c := 0x93f11e65781741b92fa7fc4f4fffcca2) (prev := ev2) (v := v) - (P := 2 ^ 129) (V := 2 ^ 126) (sh := 0x86) h2 hv (by norm_num) (by norm_num) - (by rw [pvd 129 126 134 121 (by norm_num)]; norm_num)).2 - rw [pvd 129 126 134 121 (by norm_num)] at this; omega - set ev3 := evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul ev2 v)) with hev3 - have hfin := stage_bounds (c := 0x4e14a45e8ec305e233e11b4174e214ac) (prev := ev3) (v := v) - (P := 2 ^ 129) (V := 2 ^ 126) (sh := 0x84) h3 hv (by norm_num) (by norm_num) - (by rw [pvd 129 126 132 123 (by norm_num)]; norm_num) - rw [pvd 129 126 132 123 (by norm_num)] at hfin + set ev0 := evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v with hev0 + have h1 : evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul ev0 v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7602053) (prev := ev0) (v := v) + (P := 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) (V := 2 ^ 120) (sh := 0x95) h0 hv + (by norm_num) (by norm_num) (by norm_num)).2 + have hcap : (0x9a036222841f47c6ed6fc3f7602053 : Nat) + + (0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) * 2 ^ 120 / 2 ^ 0x95 < 2 ^ 121 := by + norm_num + omega + set ev1 := evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul ev0 v)) with hev1 + have h2 : evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul ev1 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331c5c3057) (prev := ev1) (v := v) + (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7b) h1 hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 123 118 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 123 118 (by norm_num)] at this; omega + set ev2 := evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul ev1 v)) with hev2 + have h3 : evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul ev2 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf809e) (prev := ev2) (v := v) + (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x81) h2 hv (by norm_num) (by norm_num) + (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 + rw [pvd 129 120 129 120 (by norm_num)] at this; omega + set ev3 := evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul ev2 v)) with hev3 + have hfin := stage_bounds (c := 0x4e14a45e5650b506e97f4c5da23861e2) (prev := ev3) (v := v) + (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x7f) h3 hv (by norm_num) (by norm_num) + (by rw [pvd 129 120 127 122 (by norm_num)]; norm_num) + rw [pvd 129 120 127 122 (by norm_num)] at hfin refine ⟨hfin.1, ?_⟩ - have : (0x4e14a45e8ec305e233e11b4174e214ac : Nat) + 2 ^ 123 < 2 ^ 127 := by norm_num + have : (0x4e14a45e5650b506e97f4c5da23861e2 : Nat) + 2 ^ 122 < 2 ^ 127 := by norm_num omega -theorem evTree_lt {x : Nat} (hv : vTree x < 2 ^ 126) : evTree x < 2 ^ 127 := (evTree_facts hv).2 -theorem evTree_ge {x : Nat} (hv : vTree x < 2 ^ 126) : - 0x4e14a45e8ec305e233e11b4174e214ac ≤ evTree x := (evTree_facts hv).1 +theorem evTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evTree x < 2 ^ 127 := (evTree_facts hv).2 +theorem evTree_ge {x : Nat} (hv : vTree x < 2 ^ 120) : + 0x4e14a45e5650b506e97f4c5da23861e2 ≤ evTree x := (evTree_facts hv).1 /-- Two-sided bound on the odd Horner accumulator: `0x270a… ≤ od < 2^126`. -/ -theorem odTree_facts {x : Nat} (hv : vTree x < 2 ^ 126) : - 0x270a522f476182f119f08da0ba710a56 ≤ odTree x ∧ odTree x < 2 ^ 126 := by +theorem odTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : + 0x270a522f2b285a8374bfa62ed11c30f1 ≤ odTree x ∧ odTree x < 2 ^ 126 := by have hod : odTree x = - evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl + evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl rw [hod] set v := vTree x with hvdef - have h0 : evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb v)) < 2 ^ 121 := by - have := (stage_bounds (c := 0xc926ddbf3830ca5561cc01585402d0) (prev := 0xdc07aff85e5bb5629d0fb64a84bb) (v := v) - (P := 2 ^ 112) (V := 2 ^ 126) (sh := 0x83) (by norm_num) hv (by norm_num) (by norm_num) - (by rw [pvd 112 126 131 107 (by norm_num)]; norm_num)).2 - rw [pvd 112 126 131 107 (by norm_num)] at this; omega - set od0 := evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul 0xdc07aff85e5bb5629d0fb64a84bb v)) with hod0 - have h1 : evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul od0 v)) < 2 ^ 121 := by - have := (stage_bounds (c := 0xad4506b00b1246c7e5b4fd33e1201b) (prev := od0) (v := v) - (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x89) h0 hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 137 110 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 137 110 (by norm_num)] at this; omega - set od1 := evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul od0 v)) with hod1 - have h2 : evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul od1 v)) < 2 ^ 129 := by - have := (stage_bounds (c := 0xaf5662483c4ce783a9ef5fe025f42e9e) (prev := od1) (v := v) - (P := 2 ^ 121) (V := 2 ^ 126) (sh := 0x7f) h1 hv (by norm_num) (by norm_num) - (by rw [pvd 121 126 127 120 (by norm_num)]; norm_num)).2 - rw [pvd 121 126 127 120 (by norm_num)] at this; omega - set od2 := evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul od1 v)) with hod2 - have hfin := stage_bounds (c := 0x270a522f476182f119f08da0ba710a56) (prev := od2) (v := v) - (P := 2 ^ 129) (V := 2 ^ 126) (sh := 0x87) h2 hv (by norm_num) (by norm_num) - (by rw [pvd 129 126 135 120 (by norm_num)]; norm_num) - rw [pvd 129 126 135 120 (by norm_num)] at hfin + have h0 : evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7da8c1) (prev := 0xdc07aff8276bde9a361278df6a10) (v := v) + (P := 2 ^ 112) (V := 2 ^ 120) (sh := 0x7e) (by norm_num) hv (by norm_num) (by norm_num) + (by rw [pvd 112 120 126 106 (by norm_num)]; norm_num)).2 + rw [pvd 112 120 126 106 (by norm_num)] at this; omega + set od0 := evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v)) with hod0 + have h1 : evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul od0 v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0xad4506af99be27419341e1816ff351) (prev := od0) (v := v) + (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x84) h0 hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 132 109 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 132 109 (by norm_num)] at this; omega + set od1 := evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul od0 v)) with hod1 + have h2 : evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul od1 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c6) (prev := od1) (v := v) + (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7a) h1 hv (by norm_num) (by norm_num) + (by rw [pvd 121 120 122 119 (by norm_num)]; norm_num)).2 + rw [pvd 121 120 122 119 (by norm_num)] at this; omega + set od2 := evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul od1 v)) with hod2 + have hfin := stage_bounds (c := 0x270a522f2b285a8374bfa62ed11c30f1) (prev := od2) (v := v) + (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x82) h2 hv (by norm_num) (by norm_num) + (by rw [pvd 129 120 130 119 (by norm_num)]; norm_num) + rw [pvd 129 120 130 119 (by norm_num)] at hfin refine ⟨hfin.1, ?_⟩ - have : (0x270a522f476182f119f08da0ba710a56 : Nat) + 2 ^ 119 < 2 ^ 126 := by norm_num + have : (0x270a522f2b285a8374bfa62ed11c30f1 : Nat) + 2 ^ 119 < 2 ^ 126 := by norm_num omega -theorem odTree_lt {x : Nat} (hv : vTree x < 2 ^ 126) : odTree x < 2 ^ 126 := (odTree_facts hv).2 -theorem odTree_ge {x : Nat} (hv : vTree x < 2 ^ 126) : - 0x270a522f476182f119f08da0ba710a56 ≤ odTree x := (odTree_facts hv).1 +theorem odTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odTree x < 2 ^ 126 := (odTree_facts hv).2 +theorem odTree_ge {x : Nat} (hv : vTree x < 2 ^ 120) : + 0x270a522f2b285a8374bfa62ed11c30f1 ≤ odTree x := (odTree_facts hv).1 end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean index 5afb2f736..aa9869bce 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean @@ -35,8 +35,8 @@ theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hk : int256 (kTree x1) = int256 (kTree x2)) (hadj : int256 x2 = int256 x1 + 1) : int256 (r0Tree x1) ≤ int256 (r0Tree x2) := by - have hv1 : vTree x1 < 2 ^ 126 := (vTree_eq hx1 hC1 hC01).2 - have hv2 : vTree x2 < 2 ^ 126 := (vTree_eq hx2 hC2 hC02).2 + have hv1 : vTree x1 < 2 ^ 120 := (vTree_eq hx1 hC1 hC01).2 + have hv2 : vTree x2 < 2 ^ 120 := (vTree_eq hx2 hC2 hC02).2 obtain ⟨hev1lo, hev1hi⟩ := evTree_int hv1 obtain ⟨hev2lo, hev2hi⟩ := evTree_int hv2 obtain ⟨htod1lo, htod1hi⟩ := todTree_cross_bounds hx1 hC1 hC01 @@ -90,14 +90,14 @@ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hk2w : kTree x2 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ have hseq := closing_shift_eq hk hk1w hk2w obtain ⟨s, hseqx, hslo, hshi, _⟩ := closing_shift hx1 hC1 hC01 - have hr1eq1 : r1Tree x1 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0x9fe769d0fa58e9f) := by + have hr1eq1 : r1Tree x1 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xe17cfd91868d72d) := by unfold r1Tree; rw [hseqx] - have hr1eq2 : r1Tree x2 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0x9fe769d0fa58e9f) := by + have hr1eq2 : r1Tree x2 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xe17cfd91868d72d) := by unfold r1Tree; rw [← hseq, hseqx] rw [hr1eq1, hr1eq2] -- the two shift arguments, transported to `Int`, are ordered (monotone `r0`) - set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0x9fe769d0fa58e9f with harg1 - set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0x9fe769d0fa58e9f with harg2 + set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xe17cfd91868d72d with harg1 + set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xe17cfd91868d72d with harg2 have hargle : int256 arg1 ≤ int256 arg2 := by rw [harg1eq, harg2eq] have hwad : (0 : Int) ≤ 0xde0b6b3a7640000 := by norm_num diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index 259f06c1b..9ef7b40fa 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -176,7 +176,7 @@ theorem run_exp_ray_to_wad_evm_mono_of_seam (hseamstep : SeamStep) (x1 x2 : Nat) /-- **Runtime monotonicity, modulo the octave-seam `r0` doubling bound.** With the seam-step reduction (`Seam.seamStep_of_seamR0`) and all of `range`/`nonneg`/same-octave/ induction discharged, monotonicity over the entire non-reverting domain follows from the single -analytic bound `SeamR0Bound` (`r0Tree x1 < 2·r0Tree x2` across one octave). -/ +analytic bound `SeamR0Bound` (`r0Tree x1 + 2 ≤ 2·r0Tree x2` across one octave). -/ theorem run_exp_ray_to_wad_evm_mono_of_seamR0 (hr0 : SeamR0Bound) (x1 x2 : Nat) (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hle : int256 x1 ≤ int256 x2) (hdom : int256 x2 < int256 C0thresh) : diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean index af89a6959..41d89418a 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -23,7 +23,7 @@ def kTree (x : Nat) : Nat := def tTree (x : Nat) : Nat := evmSar tArgShift (evmSub (evmMul k27Q235 x) (evmMul ln2Q235 (kTree x))) -/-- `v = t^2` in Q128. -/ +/-- `v = t^2` in Q123. -/ def vTree (x : Nat) : Nat := evmShr squareShift (evmMul (tTree x) (tTree x)) /-- `Ev(v)`, the even Horner accumulator. -/ @@ -33,7 +33,7 @@ def evTree (x : Nat) : Nat := (evmAdd ev3 (evmShr evShift3 (evmMul (evmAdd ev2 (evmShr evShift2 (evmMul (evmAdd ev1 (evmShr evShift1 (evmMul - (evmAdd ev0 (evmShr evShift0 v)) v))) v))) v))) v)) + (evmAdd ev0 v) v))) v))) v))) v)) /-- `Od(v)`, the odd Horner accumulator. -/ def odTree (x : Nat) : Nat := diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 2c19e8577..49ee62125 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -417,20 +417,20 @@ theorem call_fun__expRayToWad_80_direct let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x80 (evmMul t t) - let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) - let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let v := evmShr 0x85 (evmMul t t) + let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) + let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -481,20 +481,20 @@ theorem call_fun_expRayToWad_70_direct let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x80 (evmMul t t) - let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) - let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let v := evmShr 0x85 (evmMul t t) + let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) + let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -543,20 +543,20 @@ theorem call_fun_wrap_expRayToWad_direct let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x80 (evmMul t t) - let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) - let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let v := evmShr 0x85 (evmMul t t) + let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) + let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -604,20 +604,20 @@ theorem external_fun_wrap_expRayToWad_calldata_result let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x80 (evmMul t t) - let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) - let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let v := evmShr 0x85 (evmMul t t) + let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) + let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -633,20 +633,20 @@ theorem external_fun_wrap_expRayToWad_calldata_result (let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x80 (evmMul t t) - let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) - let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let v := evmShr 0x85 (evmMul t t) + let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) + let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -734,20 +734,20 @@ theorem external_fun_wrap_expRayToWad_calldata_halts (let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x80 (evmMul t t) - let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) - let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let v := evmShr 0x85 (evmMul t t) + let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) + let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -840,20 +840,20 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x80 (evmMul t t) - let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) - let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let v := evmShr 0x85 (evmMul t t) + let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) + let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -919,20 +919,20 @@ theorem run_exp_ray_to_wad_evm_eq_tree let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x80 (evmMul t t) - let ev := evmAdd 0x4e14a45e8ec305e233e11b4174e214ac (evmShr 0x84 (evmMul - (evmAdd 0x93f11e65781741b92fa7fc4f4fffcca2 (evmShr 0x86 (evmMul - (evmAdd 0x9064d965e1c4863b73604e0ddbec53f9 (evmShr 0x80 (evmMul - (evmAdd 0x9a036222e11aee18465042f8ea64c8 (evmShr 0x82 (evmMul - (evmAdd 0xb9aacfad41060587203a79af0ebc (evmShr 0x1d v)) v))) v))) v))) v)) - let od := evmAdd 0x270a522f476182f119f08da0ba710a56 (evmShr 0x87 (evmMul - (evmAdd 0xaf5662483c4ce783a9ef5fe025f42e9e (evmShr 0x7f (evmMul - (evmAdd 0xad4506b00b1246c7e5b4fd33e1201b (evmShr 0x89 (evmMul - (evmAdd 0xc926ddbf3830ca5561cc01585402d0 (evmShr 0x83 (evmMul - 0xdc07aff85e5bb5629d0fb64a84bb v))) v))) v))) v)) + let v := evmShr 0x85 (evmMul t t) + let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) + let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0x9fe769d0fa58e9f) + let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index dc4f46469..a252c7285 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -96,8 +96,9 @@ example (x1 x2 : Nat) Each bracket is stated on the runtime result `r` (`run_exp_ray_to_wad_evm x = .ok r`) against the target `E = 10¹⁸·exp(x/10²⁷)`. The pre-floor accumulator brackets `E` unconditionally (`accumReal_over`/`accumReal_under`: the cert `Floor.CapsV` against the exact rational -`ê = NUM/DEN`, folded with the octave `2^k`, plus the reduced-argument and Horner-`sdiv` -truncation envelopes the `MARGIN` absorbs), and below the clamp the target satisfies `E < 1` +`ê = NUM/DEN`, folded with the octave `2^k`, plus the argument-granularity, reduced-argument and +Horner-`sdiv` truncation envelopes the `MARGIN` absorbs), and below the clamp the target satisfies +`E < 1` (`belowC_target_lt_one`), so the global brackets hold with no analytic hypothesis. -/ /-- Global floor-or-one-less bracket. -/ @@ -129,8 +130,8 @@ Proved directly and axiom-clean: * `tTree_in_cert_domain` — the runtime reduced argument stays in the certificate domain `|tTree x| ≤ H128`, so the Taylor caps (`Floor.CapsV`) instantiate at `t := tTree x`; * `evTree_bracket` / `odTree_bracket` — the Horner-truncation bridge: the runtime even/odd - accumulators bracket the exact integer polynomials `evNumV`/`odNumV` (in `v = vTree x`) within `2` - units at the cleared scales `2^553`/`2^530`; + accumulators bracket the exact integer polynomials `evNumV`/`odNumV` (in `v = vTree x`) within + `≈1.008`/`≈1.002` units at the cleared scales `2^528`/`2^510`; * `belowC_target_lt_one` — below the clamp boundary the target satisfies `E < 1`; * `accumReal_over` / `accumReal_under` — the pre-floor accumulator never exceeds `E` and lies within one output unit below it. -/ diff --git a/formal/exp/ExpProof/GenExpVLit.lean b/formal/exp/ExpProof/GenExpVLit.lean index f1b98192e..366832170 100644 --- a/formal/exp/ExpProof/GenExpVLit.lean +++ b/formal/exp/ExpProof/GenExpVLit.lean @@ -108,6 +108,14 @@ def numEqTac : String := def denM1EqTac : String := " unfold certDenM1 denExpV evNumVPoly todNumV odNumVPoly mulT2\n decide +kernel" +/-- Tactic block proving `certDOver = certDOverLit`. -/ +def dOverEqTac : String := + " unfold certDOver evVPoly odVPoly\n decide +kernel" + +/-- Tactic block proving `certDUnder = certDUnderLit`. -/ +def dUnderEqTac : String := + " unfold certDUnder evVPoly odVPoly\n decide +kernel" + #eval do let cUp := ptrim certExpUp let cLo := ptrim certExpLo @@ -124,6 +132,8 @@ def denM1EqTac : String := litText "certDenM1Lit" (ptrim certDenM1) ++ litText "certExpUpLit" cUp ++ litText "certExpLoLit" cLo ++ + litText "certDOverLit" (ptrim certDOver) ++ + litText "certDUnderLit" (ptrim certDUnder) ++ "end ExpCertV\n") IO.println "v-form literals written" emit "certExpUpLit" "ExpVUp" "ExpVUpC" "expVUp_cell" "certExpUp_eq" "expVUpLit_nonneg" @@ -134,3 +144,7 @@ def denM1EqTac : String := "numExpV_nonneg" "numExpV" numEqTac (ptrim numExpV) 0 (H128 : Int) emit "certDenM1Lit" "ExpVDenM1" "ExpVDenM1C" "expVDenM1_cell" "certDenM1_eq" "denM1VLit_nonneg" "denM1V_nonneg" "certDenM1" denM1EqTac (ptrim certDenM1) 0 (H128 : Int) + emit "certDOverLit" "ExpVDOver" "ExpVDOverC" "expVDOver_cell" "certDOver_eq" "dOverVLit_nonneg" + "dOverV_nonneg" "certDOver" dOverEqTac (ptrim certDOver) 0 ((vmaxV : Int) + 1) + emit "certDUnderLit" "ExpVDUnder" "ExpVDUnderC" "expVDUnder_cell" "certDUnder_eq" "dUnderVLit_nonneg" + "dUnderV_nonneg" "certDUnder" dUnderEqTac (ptrim certDUnder) 0 ((vmaxV : Int) + 1) From 2eccccacc41f1094c24c12e385b3cb29ec06ccfa Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 15:00:31 +0200 Subject: [PATCH 123/149] Fold the exp output on the 5^18 grid; unsigned close; 32-piece margin The closing fold multiplies the Q126 quotient by 5^18 = 10^18/2^18 and floors with shr(108 - k, ...), folding the wad unit's remaining 2^18 into the output shift; the fold word is nonnegative on every live path and the clamp discards the rest, so outputs are bit-identical (proven by the nested floor identity and a 30,515-input EVM-faithful sweep). The quotient uses div: the dividend is below 2^255 and the denominator positive. Both the 5^18 literal and the margin drop to six bytes; runtime code shrinks 2 bytes at identical gas. The margin is the budget floor on the 2^108 output grid, 0x37c9ed9cabf = floor(5^18 * 1.0050013498897899168) + 1, with the argument granularity certified piecewise over 32 domain pieces (0.3290521163436398582 over, 0.1644901622230542074 under; pointwise supremum 0.3287). k = 63 deficit envelope 0.83538 < 1; every documented property and witness is unchanged (unit suite green). The Lean proof package is re-derived separately. Co-Authored-By: Claude Fable 5 --- src/vendor/Exp.sol | 58 +++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 20be17db7..3d52896e9 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -54,25 +54,27 @@ library Exp { /// v's basis) /// Od Horner up the staircase Q105 → Q102 → Q93 → Q94 → Q87 /// Ev, Od, t⋅Od, and the numerator/denominator: Q87 (the basis the closing quotient shares) - /// quotient: one `sdiv` placing exp(t) at Q126 (the dividend, numerator << 126, stays - /// below 2²⁵⁵: a nonnegative signed word) - /// output: multiplying by 10¹⁸ lands E on the 10¹⁸⋅2¹²⁶ grid; the closing - /// `sar(126 - k, …)` is the single output-rounding floor, with 2ᵏ folded in + /// quotient: one `div` placing exp(t) at Q126 (the dividend, numerator << 126, stays + /// below 2²⁵⁵ and the denominator is positive, so unsigned division is the + /// exact floor) + /// output: multiplying by 5¹⁸ lands E on the 2¹⁰⁸ output grid (the 10¹⁸⋅2¹²⁶ grid + /// with the wad unit's 2¹⁸ pre-folded); the closing `shr(108 - k, …)` — the word + /// is nonnegative — is the single output-rounding floor, with 2ᵏ folded in /// /// Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the /// exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). The budget - /// bounds Δ ≤ 1.0155087723197130681 (each term below carried to its supremum at 19 decimal + /// bounds Δ ≤ 1.0050013498897899168 (each term below carried to its supremum at 19 decimal /// places), the sum of four one-sided contributions: - /// integer Horner + closing `sdiv` truncation: the Ev shared by the numerator Ev + t⋅Od + /// integer Horner + closing `div` truncation: the Ev shared by the numerator Ev + t⋅Od /// and denominator Ev - t⋅Od cancels to first order in the quotient, so its /// truncation barely perturbs e; this jitter stays ≤ 0.6207065163. /// argument granularity: v carries t² on the Q123 grid, and its floor only lowers the /// polynomials' shared argument (by < 2⁻¹²³), which lifts e on the t > 0 half by - /// ≤ 0.3395595387735630095: one v-grain moves the quotient by - /// 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose one-signed numerator is maximal at the - /// domain edge and whose denominator is floored globally (the pointwise - /// supremum is ≈ 0.3287 at t = ln2/2). The t < 0 direction is budgeted on - /// the under side. + /// ≤ 0.3290521163436398582: one v-grain moves the quotient by + /// 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose one-signed numerator is maximal at each + /// piece's upper edge and whose denominator is floored piecewise over 32 domain + /// pieces (the pointwise supremum is ≈ 0.3287 at t = ln2/2). The t < 0 + /// direction is budgeted on the under side. /// rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): /// ≤ 0.0441941739 (its supremum is √2⋅2¹²⁶/(2¹³¹-1)). /// reduced-argument gap: the Q128 floor of t only pushes e downward (that direction @@ -81,36 +83,37 @@ library Exp { /// 2⁻¹³³ of reduced argument, lifting e by ≤ 0.0110485435 /// (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). /// Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1101 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer - /// strictly above 2⁶³⋅S: 0xe17cfd91868d72d = ⌊10¹⁸⋅Δ⌋ + 1 = 1015508772319713069 (worth ≈ S ulp - /// at k = 63; the +1 makes the never-over strict, which the round trip below needs). So + /// S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1090 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least + /// integer on the 2¹⁰⁸ output grid strictly above Δ's image there: + /// 0x37c9ed9cabf = ⌊5¹⁸⋅Δ⌋ + 1 = 3833775901375 (worth ≈ S ulp at k = 63; the +1 makes + /// the never-over strict, which the round trip below needs). So /// 10¹⁸⋅e⋅2ᵏ - margin ≤ E (never overestimates). The under side is bounded to the same /// precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 67/10, where 67/10 bounds the sum of the integer-rational - /// deficit (≤ 6001/1000, the Horner/`sdiv`/floor truncation against the denominator), the `Mp` + /// deficit (≤ 6001/1000, the Horner/`div`/floor truncation against the denominator), the `Mp` /// factor (≤ 1/20, via e ≤ 1.45·2¹²⁶), the under-direction reduced-argument gap (≤ 37/100, /// via exp(t) ≤ √2), and the under-direction argument granularity (≤ 17/100, the same /// one-grain envelope with the negative-half denominator floor). Hence the maximum /// underestimation of the pre-floor accumulator A is - /// E - A ≤ ((67/10)⋅10¹⁸ + margin)/2⁶³ ≈ 0.83652 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the + /// E - A ≤ ((67/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶³ ≈ 0.83538 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1 (the /// 1-ulp underestimate is achieved, ⌊E⌋ - 2 never occurs). The deficit envelope - /// ((67/10)⋅10¹⁸ + margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp + /// ((67/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave, so at k = 64 it exceeds one ulp /// and the floor can fall two below E; that input is reverted. On the central octave k = 0 the - /// margin is margin⋅2⁻¹²⁶ ≈ 1.2⋅10⁻²⁰ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so + /// margin is margin⋅2⁻¹⁰⁸ ≈ 1.2⋅10⁻²⁰ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so /// the round trip floors to ⌊E⌋. `round(x/(10²⁷⋅ln2))` is half-open, so the k = 0 band is /// exactly [-H, H) with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). /// /// This margin is the floor of the bound above: Δ's √2-driven terms and its ln2-edge /// sensitivity supremum are irrational, so Δ itself is irrational and the margin - /// ⌊10¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering Δ. The truncation term (≈0.62, the + /// ⌊5¹⁸⋅Δ⌋ + 1 cannot be reduced without lowering Δ. The truncation term (≈0.62, the /// affine envelope of the integer Horner) is ≈1.6× the empirically observed jitter; /// closing that gap is not reachable by the linear bound and would need either /// round-to-nearest Horner stages (more gas and code) or a number-theoretic bound on the /// fractional part of E, so the margin rests here. /// /// Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves - /// the pre-floor accumulator by at least 10¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 6⋅10²⁸ grid units. The - /// error terms above confine the accumulator to a band of width 10¹⁸⋅(Δ + 67/10) ≈ - /// 7.7⋅10¹⁸ grid units just below E's grid image at every octave (in grid units the band + /// the pre-floor accumulator by at least 5¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 2.3⋅10²³ grid units. The + /// error terms above confine the accumulator to a band of width 5¹⁸⋅(Δ + 67/10) ≈ + /// 2.9⋅10¹³ grid units just below E's grid image at every octave (in grid units the band /// is k-independent; an octave seam rescales E and the band together), so the per-step /// gain exceeds any adverse swing within the band by more than nine orders of magnitude, /// and the pre-floor accumulator strictly increases at every step; its floor @@ -163,12 +166,13 @@ library Exp { let tod := sar(0x80, mul(t, od)) // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁶, the denominator > 0. - r := sdiv(shl(0x7e, add(ev, tod)), sub(ev, tod)) + r := div(shl(0x7e, add(ev, tod)), sub(ev, tod)) - // E in Q126 on the 10¹⁸⋅2¹²⁶ grid, less the one-sided margin - // (0xe17cfd91868d72d = ⌊10¹⁸⋅Δ⌋ + 1; see the budget above), then floored by `sar(126 - k, …)` - // which folds in the 2ᵏ octave scaling (126 - k ∈ [63, 187]). - r := sar(sub(0x7e, k), sub(mul(0xde0b6b3a7640000, r), 0xe17cfd91868d72d)) + // E on the 2¹⁰⁸ output grid (5¹⁸ = 10¹⁸/2¹⁸ multiplies the Q126 quotient), less the + // one-sided margin (0x37c9ed9cabf = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then floored + // by `shr(108 - k, …)` — the word is nonnegative — which folds in the 2ᵏ octave + // scaling and the wad unit's remaining 2¹⁸ (108 - k ∈ [45, 168]). + r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x37c9ed9cabf)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs From 8efdde52d44995211fe9b1253a4edc027919140b Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 16:19:38 +0200 Subject: [PATCH 124/149] Certify the 5^18 fold, unsigned close, and 32-piece granularity The proof package tracks the batched kernel: the closing fold lives on the 5^18*2^108 grid (foldShift 0x6c; shr floor lemmas take the nonnegativity RangeNonneg supplies), the quotient moves from evmSdiv to evmDiv (deleting the int256 sign transports in WordMono/Quot/Cross/Value), and the argument-granularity certificate is piecewise: 32 domain pieces per side, each with its own integer t-cap, K edge value, and one-cell D-floor cover (69 generated cover families, 78 cells), assembled by piece selection over vTree. Budget total 10050013498897899168/10^19 against the margin floor(5^18*B) + 1 = 0x37c9ed9cabf with strictness slack 0.98; k = 63 envelope 0.8354 < 1. The Yul importer expects div for the exp kind. Full lake build is green from scratch; all fifteen gated theorems depend on exactly [propext, Classical.choice, Quot.sound]; every public statement is byte-identical to the previous proof. Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Floor/CertDefsV.lean | 36 +- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 17 +- .../exp/ExpProof/ExpProof/Floor/GranPair.lean | 349 ++++--- formal/exp/ExpProof/ExpProof/Floor/GranV.lean | 877 ++++++++++++++++-- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 2 +- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 60 +- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 63 +- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 16 +- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 74 +- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 91 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 5 +- formal/exp/ExpProof/ExpProof/Mono/Cross.lean | 12 +- formal/exp/ExpProof/ExpProof/Mono/Quot.lean | 49 +- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 151 ++- .../exp/ExpProof/ExpProof/Mono/RunBridge.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 70 +- .../exp/ExpProof/ExpProof/Mono/StepMono.lean | 47 +- formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 10 +- .../exp/ExpProof/ExpProof/Mono/WordMono.lean | 150 +-- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 36 +- formal/exp/ExpProof/ExpProof/Theorems.lean | 2 +- formal/exp/ExpProof/GenExpVLit.lean | 72 +- formal/yul/YulImporter.lean | 2 +- 23 files changed, 1475 insertions(+), 718 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean index 22ddf65a2..ed1395035 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean @@ -26,9 +26,11 @@ Two certificate shapes are declared: * the Taylor cut, the standard `Common.Exp.capUB_of_partial`/`capLB` shape at depth `K = 27`, nudging the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹³¹)`, `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`); the realized envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.019` ulp is inside those margins with 2.3× slack; -* the **denominator floors** over the integer `v`-grid (`certDOver`/`certDUnder`), which pin - `Ev(v)·2^110 ∓ H128·Od(v)` above explicit constants for every `v ∈ [0, vmaxV + 1]`; the - argument-granularity link divides one `v`-grid step of `ê_v` by these floors. +* the **denominator floors** over the integer `v`-grid: the parameterized shapes + `certDOverP`/`certDUnderP` pin `Ev(v)·2^110 ∓ T·Od(v)` above explicit constants, instantiated + once globally (`certDOver`, at the domain edge `T = H128` over all of `[0, vmaxV + 1]`) and once + per granularity piece (32 pieces, each with its own `t`-cap `T` and floor constant over its + `v`-range); the argument-granularity link divides one `v`-grid step of `ê_v` by the piece floors. -/ namespace ExpCertV @@ -145,18 +147,20 @@ def odVPoly : List Int := 0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 126, 0xdc07aff8276bde9a361278df6a10] -/-- Over-half denominator floor: `Ev(v)·2^110 − H128·Od(v) − 554482771859·2^725 ≥ 0` on -`[0, vmaxV + 1]` (so `DEN(v, t) ≥ 554482771859·2^725` for every `0 ≤ t ≤ H128`; the floor constant -is `2^725` times the real-scale minimum `≈ 5.5448·10¹¹`, attained at `v = 0`). -/ -def certDOver : List Int := - polyAdd (polySub (polyScale (2 ^ 110) evVPoly) (polyScale (H128 : Int) odVPoly)) - [-(554482771859 * 2 ^ 725)] - -/-- Under-half denominator floor: `Ev(v)·2^110 + H128·Od(v) − 786932288647·2^725 ≥ 0` on -`[0, vmaxV + 1]` (the `t = −H128` denominator; the granularity lift is monotone in `|t|`, so this -single evaluation floors the whole negative half). -/ -def certDUnder : List Int := - polyAdd (polyAdd (polyScale (2 ^ 110) evVPoly) (polyScale (H128 : Int) odVPoly)) - [-(786932288647 * 2 ^ 725)] +/-- Over-half denominator floor shape: `Ev(v)·2^110 − T·Od(v) − D·2^725 ≥ 0`. Nonnegativity over a +`v`-range gives `DEN(v, t) ≥ D·2^725` there for every `0 ≤ t ≤ T` (the floor constant is `2^725` +times a real-scale minimum). -/ +def certDOverP (T D : Int) : List Int := + polyAdd (polySub (polyScale (2 ^ 110) evVPoly) (polyScale T odVPoly)) [-(D * 2 ^ 725)] + +/-- Under-half (`t = −T`) denominator floor shape: `Ev(v)·2^110 + T·Od(v) − D·2^725 ≥ 0`. The +granularity lift is monotone in `|t|`, so the single cap evaluation floors a whole piece's +negative half. -/ +def certDUnderP (T D : Int) : List Int := + polyAdd (polyAdd (polyScale (2 ^ 110) evVPoly) (polyScale T odVPoly)) [-(D * 2 ^ 725)] + +/-- The global over-half floor at the domain edge: `DEN(v, t) ≥ 554482771859·2^725` on all of +`[0, vmaxV + 1]` for every `0 ≤ t ≤ H128` (real-scale minimum `≈ 5.5448·10¹¹`, attained interior). -/ +def certDOver : List Int := certDOverP (H128 : Int) 554482771859 end ExpCertV diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index 58420da54..88fff7e43 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -3,11 +3,12 @@ import ExpProof.Floor.Spec /-! # The runtime accumulator in closed real form -The real pre-floor accumulator is `accumReal x = (WAD·r0 − MARGIN) / 2^(126 − k)`. This file peels -the runtime plumbing off it: using the proven shift-argument transport (`shiftArg_bounds_of`: +The real pre-floor accumulator is `accumReal x = (WAD·r0 − MARGIN) / 2^(108 − k)` on the `5¹⁸·2¹⁰⁸` +grid (`WAD = 5¹⁸`, the wad unit's `2¹⁸` folded into the closing shift). This file peels the runtime +plumbing off it: using the proven shift-argument transport (`shiftArg_bounds_of`: `int256 (WAD·r0 − MARGIN) = WAD·r0 − MARGIN` as `Int`) and the closing-shift value -(`closing_shift`: the shift word is `126 − int256 k`, nonnegative), the accumulator takes the -closed form `(WAD·(int256 r0) − MARGIN) / 2^s` with `s = 126 − int256 (kTree x)`, the form the +(`closing_shift`: the shift word is `108 − int256 k`, nonnegative), the accumulator takes the +closed form `(WAD·(int256 r0) − MARGIN) / 2^s` with `s = 108 − int256 (kTree x)`, the form the never-over and deficit discharges (`Floor.R0BoundHolds`) fold the octave against. -/ @@ -27,9 +28,9 @@ set_option maxRecDepth 100000 `Real`) is `WAD·(int256 r0) − MARGIN`, and it is nonnegative. -/ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - ∃ s : Nat, (s : Int) = 126 - int256 (kTree x) ∧ + ∃ s : Nat, (s : Int) = 108 - int256 (kTree x) ∧ accumReal x = - ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - (1015508772319713069 : Real)) / + ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - (3833775901375 : Real)) / (2 ^ s : Real) := by obtain ⟨s, hseq, _, _, hsint⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 @@ -38,8 +39,8 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) unfold accumReal rw [hseq] -- the integer shift argument has the closed value `WAD·r0 − MARGIN` - have hwadc : (0xde0b6b3a7640000 : Int) = 1000000000000000000 := by norm_num - have hmarc : (0xe17cfd91868d72d : Int) = 1015508772319713069 := by norm_num + have hwadc : (0x3782dace9d9 : Int) = 3814697265625 := by norm_num + have hmarc : (0x37c9ed9cabf : Int) = 3833775901375 := by norm_num rw [hargeq, hwadc, hmarc] push_cast ring diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean b/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean index 8990c9376..57905fc8b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean @@ -4,9 +4,12 @@ import ExpProof.Floor.GranV # The exported real-level granularity bounds The two per-side packagings of the `Floor.GranV` machinery that the `r0`-vs-`exp` chains consume: -one `v`-grid grain lifts `2¹²⁶·ê` by at most `3395595387735630095/10¹⁹` on the `t ≥ 0` half -(never-over side) and by at most `1685843742692980488/10¹⁹` — `Mp`-factor included — on the -`t ≤ 0` half (deficit side); the respective opposite directions are free. +one `v`-grid grain lifts `2¹²⁶·ê` by at most `3290521163436398582/10¹⁹` on the `t ≥ 0` half +(never-over side) and by at most `1644901622230542074/10¹⁹` — `Mp`-factor included — on the +`t ≤ 0` half (deficit side); the respective opposite directions are free. Each bound is the +piecewise maximum of the 32 certified per-piece envelopes (`piece_select`): the runtime `v` picks +its piece, whose `t`-cap `T` bounds `|t|`, whose floors bound the two step denominators, and whose +budget inequality bounds the one-`K`-step lift. -/ namespace ExpYul @@ -25,7 +28,7 @@ noncomputable section /-- **Granularity, never-over half (`t ≥ 0`)**: the cert rational never exceeds the grid rational, and the grid rational exceeds the cert rational by at most one `K`-step: -`2¹²⁶·(ê(v) − ê(t²)) ≤ 3395595387735630095/10¹⁹`. -/ +`2¹²⁶·(ê(v) − ê(t²)) ≤ 3290521163436398582/10¹⁹` (the piecewise-certified envelope). -/ theorem gran_over_pair {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : @@ -36,21 +39,34 @@ theorem gran_over_pair {x : Nat} (hx : x < 2 ^ 256) (DENv (vTree x) (int256 (tTree x)) : Real)) ≤ (2 ^ 126 : Real) * ((evalPoly ExpCertV.numExpV (int256 (tTree x)) : Real) / (evalPoly ExpCertV.denExpV (int256 (tTree x)) : Real)) + - 3395595387735630095 / 10000000000000000000 := by + 3290521163436398582 / 10000000000000000000 := by obtain ⟨htie1, htie2⟩ := tie_over hx hC hC0 htnn + obtain ⟨T, DO, DU, Khi, hpiece, hT2⟩ := piece_select hx hC hC0 + obtain ⟨hDOpos, _, hKhinn, hTnn, hflO, hflO1, _, _, hK, hbudO, _⟩ := hpiece obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef have htdom : t ≤ (ExpCertV.H128 : Int) := by rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by unfold ExpCertV.H128; norm_num] exact hthi - -- denominators - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi - have hD1 : 554482771859 * 2 ^ 725 ≤ DENv (v + 1) t := DENv_ge_over (by omega) htnn hthi - have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD - have hD1pos : (0:Int) < DENv (v + 1) t := lt_of_lt_of_le (by positivity) hD1 + -- the piece cap dominates on this half: t ≤ T + have htT : t ≤ T := by + by_contra hgt + push_neg at hgt + nlinarith [hT2, htnn, hTnn, hgt] + -- denominator floors at the runtime t + have hOd_nn : (0 : Int) ≤ (odNumV v : Int) := Int.natCast_nonneg _ + have hOd1_nn : (0 : Int) ≤ (odNumV (v + 1) : Int) := Int.natCast_nonneg _ + have hD : DO * 2 ^ 725 ≤ DENv v t := by + have h := mul_le_mul_of_nonneg_right htT hOd_nn + unfold DENv; linarith [hflO, h] + have hD1 : DO * 2 ^ 725 ≤ DENv (v + 1) t := by + have h := mul_le_mul_of_nonneg_right htT hOd1_nn + unfold DENv; linarith [hflO1, h] + have hDO725 : (0:Int) < DO * 2 ^ 725 := mul_pos hDOpos (by positivity) + have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le hDO725 hD + have hD1pos : (0:Int) < DENv (v + 1) t := lt_of_lt_of_le hDO725 hD1 have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos @@ -85,69 +101,62 @@ theorem gran_over_pair {x : Nat} (hx : x < 2 ^ 256) exact hcast -- numerator and denominator bounds for the K-step have hKnn := KpM_nonneg v - have hKle := KpM_le_KVMAX hvle - have hnum_nn : (0:Int) ≤ 2 * t * 2 ^ 110 * KpM v := by positivity - have hnum_le : 2 * t * 2 ^ 110 * KpM v ≤ - 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc := by - have h1 : 2 * t * 2 ^ 110 * KpM v ≤ - 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v := by - have hcoef : 2 * t * 2 ^ 110 ≤ 2 * 117932881612756647068972071382077242199 * 2 ^ 110 := by - nlinarith [hthi] + have hnum_le : 2 * t * 2 ^ 110 * KpM v ≤ 2 * T * 2 ^ 110 * Khi := by + have h1 : 2 * t * 2 ^ 110 * KpM v ≤ 2 * T * 2 ^ 110 * KpM v := by + have hcoef : 2 * t * 2 ^ 110 ≤ 2 * T * 2 ^ 110 := by nlinarith [htT] exact mul_le_mul_of_nonneg_right hcoef hKnn - have h2 : 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v ≤ - 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc := - mul_le_mul_of_nonneg_left hKle (by positivity) + have hTc : (0:Int) ≤ 2 * T * 2 ^ 110 := + mul_nonneg (mul_nonneg (by norm_num) hTnn) (by norm_num) + have h2 : 2 * T * 2 ^ 110 * KpM v ≤ 2 * T * 2 ^ 110 * Khi := + mul_le_mul_of_nonneg_left hK hTc linarith [h1, h2] - have hden_ge : (554482771859 * 2 ^ 725 : Real) * (554482771859 * 2 ^ 725 : Real) ≤ + have hden_ge : ((DO * 2 ^ 725 : Int) : Real) * ((DO * 2 ^ 725 : Int) : Real) ≤ (DENv v t : Real) * (DENv (v + 1) t : Real) := by - have hDRc : (554482771859 * 2 ^ 725 : Real) ≤ (DENv v t : Real) := by exact_mod_cast hD - have hD1Rc : (554482771859 * 2 ^ 725 : Real) ≤ (DENv (v + 1) t : Real) := by exact_mod_cast hD1 - exact mul_le_mul hDRc hD1Rc (by positivity) (le_of_lt hDR) - -- the K-step fraction is inside the budget + have hDRc : ((DO * 2 ^ 725 : Int) : Real) ≤ (DENv v t : Real) := by exact_mod_cast hD + have hD1Rc : ((DO * 2 ^ 725 : Int) : Real) ≤ (DENv (v + 1) t : Real) := by exact_mod_cast hD1 + have hDOR : (0:Real) ≤ ((DO * 2 ^ 725 : Int) : Real) := by + exact_mod_cast le_of_lt hDO725 + exact mul_le_mul hDRc hD1Rc hDOR (le_of_lt hDR) + -- the K-step fraction is inside the piece budget have hfrac : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) / ((DENv v t : Real) * (DENv (v + 1) t : Real)) ≤ - 3395595387735630095 / 10000000000000000000 / 2 ^ 126 := by + 3290521163436398582 / 10000000000000000000 / 2 ^ 126 := by have hdd : (0:Real) < (DENv v t : Real) * (DENv (v + 1) t : Real) := mul_pos hDR hD1R rw [div_le_div_iff₀ hdd (by positivity : (0:Real) < (2:Real) ^ 126)] have hnumR : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) ≤ - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) := by + ((2 * T * 2 ^ 110 * Khi : Int) : Real) := by exact_mod_cast hnum_le have h1 : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) * 2 ^ 126 ≤ - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * 2 ^ 126 := + ((2 * T * 2 ^ 110 * Khi : Int) : Real) * 2 ^ 126 := mul_le_mul_of_nonneg_right hnumR (by positivity) - have h2 : ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * - 2 ^ 126 ≤ (3395595387735630095 / 10000000000000000000 : Real) * - ((554482771859 * 2 ^ 725 : Real) * (554482771859 * 2 ^ 725 : Real)) := by + have h2 : ((2 * T * 2 ^ 110 * Khi : Int) : Real) * 2 ^ 126 ≤ + (3290521163436398582 / 10000000000000000000 : Real) * + (((DO * 2 ^ 725 : Int) : Real) * ((DO * 2 ^ 725 : Int) : Real)) := by rw [div_mul_eq_mul_div, le_div_iff₀ (by norm_num : (0:Real) < 10000000000000000000)] - have hint : (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) * - 2 ^ 126 * 10000000000000000000 ≤ (3395595387735630095 : Int) * - ((554482771859 * 2 ^ 725) * (554482771859 * 2 ^ 725)) := by - unfold KVMAXc - norm_num - exact_mod_cast hint - have h3 : (3395595387735630095 / 10000000000000000000 : Real) * - ((554482771859 * 2 ^ 725 : Real) * (554482771859 * 2 ^ 725 : Real)) ≤ - (3395595387735630095 / 10000000000000000000 : Real) * + exact_mod_cast hbudO + have h3 : (3290521163436398582 / 10000000000000000000 : Real) * + (((DO * 2 ^ 725 : Int) : Real) * ((DO * 2 ^ 725 : Int) : Real)) ≤ + (3290521163436398582 / 10000000000000000000 : Real) * ((DENv v t : Real) * (DENv (v + 1) t : Real)) := mul_le_mul_of_nonneg_left hden_ge (by positivity) exact le_trans h1 (le_trans h2 h3) -- assemble part 2 have hQvQw : (NUMv v t : Real) / (DENv v t : Real) - (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ - 3395595387735630095 / 10000000000000000000 / 2 ^ 126 := by + 3290521163436398582 / 10000000000000000000 / 2 ^ 126 := by linarith [hstep_eq, hfrac, hQv1_le_Qw] have h2126 := mul_le_mul_of_nonneg_left hQvQw (by positivity : (0:Real) ≤ (2:Real) ^ 126) - have hcancel : (2:Real) ^ 126 * (3395595387735630095 / 10000000000000000000 / 2 ^ 126) = - 3395595387735630095 / 10000000000000000000 := by + have hcancel : (2:Real) ^ 126 * (3290521163436398582 / 10000000000000000000 / 2 ^ 126) = + 3290521163436398582 / 10000000000000000000 := by norm_num rw [hcancel] at h2126 linarith [h2126] /-- **Granularity, deficit half (`t ≤ 0`)**: the grid rational never exceeds the cert rational, and the cert rational exceeds the grid rational — `Mp`-factor `2¹³¹/(2¹³¹−1)` included — by at most -`1685843742692980488/10¹⁹` after scaling by `2¹²⁶`. The one-grain lift is monotone in `|t|` -(the sign condition is the over-half denominator floor), so the `t = −H128` denominator floor -`certDUnder` applies for every `t` in the half. -/ +`1644901622230542074/10¹⁹` after scaling by `2¹²⁶` (the piecewise-certified envelope). The +one-grain lift is monotone in `|t|` (the sign condition is the over-half denominator floor), so +each piece's `t = −T` denominator floor applies for every `t` in the half. -/ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnp : int256 (tTree x) ≤ 0) : @@ -158,18 +167,19 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) ((evalPoly ExpCertV.numExpV (int256 (tTree x)) : Real) / (evalPoly ExpCertV.denExpV (int256 (tTree x)) : Real) - (NUMv (vTree x) (int256 (tTree x)) : Real) / (DENv (vTree x) (int256 (tTree x)) : Real)) ≤ - 1685843742692980488 / 10000000000000000000 := by + 1644901622230542074 / 10000000000000000000 := by obtain ⟨htie1, htie2⟩ := tie_under hx hC hC0 htnp + obtain ⟨T, DO, DU, Khi, hpiece, hT2⟩ := piece_select hx hC hC0 + obtain ⟨hDOpos, hDUpos, hKhinn, hTnn, hflO, hflO1, hflU, hflU1, hK, _, hbudU⟩ := hpiece obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hntH : -t ≤ 117932881612756647068972071382077242199 := by linarith [htlo] have htdom : -t ≤ (ExpCertV.H128 : Int) := by rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by unfold ExpCertV.H128; norm_num] - exact hntH - -- denominators + linarith [htlo] + -- denominators (positivity via the global over floor on the nonpositive half) have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htnp have hD1 : 554482771859 * 2 ^ 725 ≤ DENv (v + 1) t := DENv_ge_neg (by omega) htnp have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD @@ -184,7 +194,7 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) rw [div_le_div_iff₀ hDR hDER] exact_mod_cast htie1 refine ⟨hpart1, ?_⟩ - -- part 2: Qw − Qv ≤ Qv1 − Qv = one K-step, |t|-monotone, floored at t = −H128 + -- part 2: Qw − Qv ≤ Qv1 − Qv = one K-step, |t|-monotone, floored at the piece cap t = −T have hQw_le_Qv1 : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) := by rw [div_le_div_iff₀ hDER hD1R] @@ -203,86 +213,67 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) exact_mod_cast (congrArg (fun z : Int => (z : Real)) hswap.symm)] push_cast ring - -- the |t|-monotonicity: u·D(H)·D′(H) ≤ H·D(u)·D′(u) with u = −t ≤ H + -- the |t|-monotonicity: u·D(T)·D′(T) ≤ T·D(u)·D′(u) with u = −t ≤ T (the piece cap) set u : Int := -t with hudef have hu0 : (0:Int) ≤ u := by rw [hudef]; linarith [htnp] + have hntT : u ≤ T := by + by_contra hgt + push_neg at hgt + have hu2 : u ^ 2 = t ^ 2 := by rw [hudef]; ring + nlinarith [hT2, hu0, hTnn, hgt, hu2] set A : Int := (evNumV v : Int) * 2 ^ 110 with hAdef set Bo : Int := (odNumV v : Int) with hBodef set A1 : Int := (evNumV (v + 1) : Int) * 2 ^ 110 with hA1def set Bo1 : Int := (odNumV (v + 1) : Int) with hBo1def have hBo_nn : (0:Int) ≤ Bo := Int.natCast_nonneg _ have hBo1_nn : (0:Int) ≤ Bo1 := Int.natCast_nonneg _ - have hAB : 117932881612756647068972071382077242199 * Bo ≤ A := HOd_le_Ev (by omega) - have hA1B1 : 117932881612756647068972071382077242199 * Bo1 ≤ A1 := HOd_le_Ev (by omega) + have hDO725 : (0:Int) < DO * 2 ^ 725 := mul_pos hDOpos (by positivity) + have hDU725 : (0:Int) < DU * 2 ^ 725 := mul_pos hDUpos (by positivity) + have hAB : T * Bo ≤ A := by linarith [hflO, hDO725] + have hA1B1 : T * Bo1 ≤ A1 := by linarith [hflO1, hDO725] have hDu : DENv v t = A + u * Bo := by unfold DENv; rw [hAdef, hBodef, hudef]; ring have hDu1 : DENv (v + 1) t = A1 + u * Bo1 := by unfold DENv; rw [hA1def, hBo1def, hudef]; ring - have hmono : u * ((A + 117932881612756647068972071382077242199 * Bo) * - (A1 + 117932881612756647068972071382077242199 * Bo1)) ≤ - 117932881612756647068972071382077242199 * ((A + u * Bo) * (A1 + u * Bo1)) := by - have hid : 117932881612756647068972071382077242199 * ((A + u * Bo) * (A1 + u * Bo1)) - - u * ((A + 117932881612756647068972071382077242199 * Bo) * - (A1 + 117932881612756647068972071382077242199 * Bo1)) = - (117932881612756647068972071382077242199 - u) * - (A * A1 - 117932881612756647068972071382077242199 * u * (Bo * Bo1)) := by ring - have hprod : 117932881612756647068972071382077242199 * u * (Bo * Bo1) ≤ A * A1 := by - have h1 : 117932881612756647068972071382077242199 * u * (Bo * Bo1) ≤ - 117932881612756647068972071382077242199 * - 117932881612756647068972071382077242199 * (Bo * Bo1) := by + have hmono : u * ((A + T * Bo) * (A1 + T * Bo1)) ≤ T * ((A + u * Bo) * (A1 + u * Bo1)) := by + have hid : T * ((A + u * Bo) * (A1 + u * Bo1)) - + u * ((A + T * Bo) * (A1 + T * Bo1)) = + (T - u) * (A * A1 - T * u * (Bo * Bo1)) := by ring + have hprod : T * u * (Bo * Bo1) ≤ A * A1 := by + have h1 : T * u * (Bo * Bo1) ≤ T * T * (Bo * Bo1) := by have := mul_le_mul_of_nonneg_right - (mul_le_mul_of_nonneg_left hntH - (by norm_num : (0:Int) ≤ 117932881612756647068972071382077242199)) + (mul_le_mul_of_nonneg_left hntT hTnn) (mul_nonneg hBo_nn hBo1_nn) linarith [this] - have h2 : (117932881612756647068972071382077242199 * - 117932881612756647068972071382077242199 * (Bo * Bo1) : Int) = - (117932881612756647068972071382077242199 * Bo) * - (117932881612756647068972071382077242199 * Bo1) := by ring - have h3 : (117932881612756647068972071382077242199 * Bo) * - (117932881612756647068972071382077242199 * Bo1) ≤ A * A1 := + have h2 : (T * T * (Bo * Bo1) : Int) = (T * Bo) * (T * Bo1) := by ring + have h3 : (T * Bo) * (T * Bo1) ≤ A * A1 := mul_le_mul hAB hA1B1 - (mul_nonneg (by norm_num) hBo1_nn) - (le_trans (mul_nonneg (by norm_num) hBo_nn) hAB) + (mul_nonneg hTnn hBo1_nn) + (le_trans (mul_nonneg hTnn hBo_nn) hAB) linarith [h1, h2 ▸ h1, h3] - have hfac1 : (0:Int) ≤ 117932881612756647068972071382077242199 - u := by - rw [hudef]; linarith [hntH] - have hfac2 : (0:Int) ≤ A * A1 - 117932881612756647068972071382077242199 * u * (Bo * Bo1) := by + have hfac1 : (0:Int) ≤ T - u := by linarith [hntT] + have hfac2 : (0:Int) ≤ A * A1 - T * u * (Bo * Bo1) := by linarith [hprod] linarith only [mul_nonneg hfac1 hfac2, hid] - -- floor the H128-denominators with the under certificate - have hDH : 786932288647 * 2 ^ 725 ≤ A + 117932881612756647068972071382077242199 * Bo := by - have := D_at_H_ge_under (v := v) (by omega) - rw [hAdef, hBodef]; linarith [this] - have hDH1 : 786932288647 * 2 ^ 725 ≤ A1 + 117932881612756647068972071382077242199 * Bo1 := by - have := D_at_H_ge_under (v := v + 1) (by omega) - rw [hA1def, hBo1def]; linarith [this] - have hDHpos : (0:Int) < A + 117932881612756647068972071382077242199 * Bo := - lt_of_lt_of_le (by positivity) hDH - have hDH1pos : (0:Int) < A1 + 117932881612756647068972071382077242199 * Bo1 := - lt_of_lt_of_le (by positivity) hDH1 + -- floor the piece-cap denominators with the under certificate + have hDH : DU * 2 ^ 725 ≤ A + T * Bo := by linarith [hflU] + have hDH1 : DU * 2 ^ 725 ≤ A1 + T * Bo1 := by linarith [hflU1] + have hDHpos : (0:Int) < A + T * Bo := lt_of_lt_of_le hDU725 hDH + have hDH1pos : (0:Int) < A1 + T * Bo1 := lt_of_lt_of_le hDU725 hDH1 have hKnn := KpM_nonneg v - have hKle := KpM_le_KVMAX hvle - -- the fraction chain: u-step ≤ H-step ≤ literal maximum + -- the fraction chain: u-step ≤ T-step ≤ piece maximum have hfracu : ((2 * u * 2 ^ 110 * KpM v : Int) : Real) / ((DENv (v + 1) t : Real) * (DENv v t : Real)) ≤ - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) / - (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) := by + ((2 * T * 2 ^ 110 * KpM v : Int) : Real) / + (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) := by have hdd : (0:Real) < (DENv (v + 1) t : Real) * (DENv v t : Real) := mul_pos hD1R hDR - have hdH : (0:Real) < ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by - have h1 : (0:Real) < ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) := by - exact_mod_cast hDH1pos - have h2 : (0:Real) < ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by - exact_mod_cast hDHpos + have hdH : (0:Real) < ((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real) := by + have h1 : (0:Real) < ((A1 + T * Bo1 : Int) : Real) := by exact_mod_cast hDH1pos + have h2 : (0:Real) < ((A + T * Bo : Int) : Real) := by exact_mod_cast hDHpos exact mul_pos h1 h2 rw [div_le_div_iff₀ hdd hdH] - -- cross-multiplied: (2u·2^110·Kp)·(D1(H)·D(H)) ≤ (2H·2^110·Kp)·(D1(u)·D(u)) - have hint : (2 * u * 2 ^ 110 * KpM v) * - ((A1 + 117932881612756647068972071382077242199 * Bo1) * - (A + 117932881612756647068972071382077242199 * Bo)) ≤ - (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v) * - ((A1 + u * Bo1) * (A + u * Bo)) := by + -- cross-multiplied: (2u·2^110·Kp)·(D1(T)·D(T)) ≤ (2T·2^110·Kp)·(D1(u)·D(u)) + have hint : (2 * u * 2 ^ 110 * KpM v) * ((A1 + T * Bo1) * (A + T * Bo)) ≤ + (2 * T * 2 ^ 110 * KpM v) * ((A1 + u * Bo1) * (A + u * Bo)) := by have hc : (0:Int) ≤ 2 * 2 ^ 110 * KpM v := mul_nonneg (by norm_num) hKnn have hscaled := mul_le_mul_of_nonneg_left hmono hc @@ -292,102 +283,85 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) rw [hDu, hDu1]; push_cast; ring rw [hrw] calc ((2 * u * 2 ^ 110 * KpM v : Int) : Real) * - (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) + (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) = (((2 * u * 2 ^ 110 * KpM v) * - ((A1 + 117932881612756647068972071382077242199 * Bo1) * - (A + 117932881612756647068972071382077242199 * Bo)) : Int) : Real) := by + ((A1 + T * Bo1) * (A + T * Bo)) : Int) : Real) := by push_cast; ring - _ ≤ (((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v) * - ((A1 + u * Bo1) * (A + u * Bo)) : Int) : Real) := by exact_mod_cast hint - _ = ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) * + _ ≤ (((2 * T * 2 ^ 110 * KpM v) * ((A1 + u * Bo1) * (A + u * Bo)) : Int) : Real) := by + exact_mod_cast hint + _ = ((2 * T * 2 ^ 110 * KpM v : Int) : Real) * (((A1 + u * Bo1) * (A + u * Bo) : Int) : Real) := by push_cast; ring - have hfracH : ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) / - (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) ≤ - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) := by - have hdH : (0:Real) < ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by - have h1 : (0:Real) < ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) := by - exact_mod_cast hDH1pos - have h2 : (0:Real) < ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by - exact_mod_cast hDHpos + have hfracH : ((2 * T * 2 ^ 110 * KpM v : Int) : Real) / + (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) ≤ + ((2 * T * 2 ^ 110 * Khi : Int) : Real) / + (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) := by + have hdH : (0:Real) < ((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real) := by + have h1 : (0:Real) < ((A1 + T * Bo1 : Int) : Real) := by exact_mod_cast hDH1pos + have h2 : (0:Real) < ((A + T * Bo : Int) : Real) := by exact_mod_cast hDHpos exact mul_pos h1 h2 + have hDUR : (0:Real) < ((DU * 2 ^ 725 : Int) : Real) := by exact_mod_cast hDU725 rw [div_le_div_iff₀ hdH (by positivity)] - have hnum : ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) ≤ - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) := by - have : (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) ≤ - 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc := - mul_le_mul_of_nonneg_left hKle (by positivity) + have hTc : (0:Int) ≤ 2 * T * 2 ^ 110 := + mul_nonneg (mul_nonneg (by norm_num) hTnn) (by norm_num) + have hnum : ((2 * T * 2 ^ 110 * KpM v : Int) : Real) ≤ + ((2 * T * 2 ^ 110 * Khi : Int) : Real) := by + have : (2 * T * 2 ^ 110 * KpM v : Int) ≤ 2 * T * 2 ^ 110 * Khi := + mul_le_mul_of_nonneg_left hK hTc exact_mod_cast this - have hnum_nn : (0:Real) ≤ - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) := by - have : (0:Int) ≤ 2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v := - mul_nonneg (by norm_num) hKnn + have hnum_nn : (0:Real) ≤ ((2 * T * 2 ^ 110 * KpM v : Int) : Real) := by + have : (0:Int) ≤ 2 * T * 2 ^ 110 * KpM v := mul_nonneg hTc hKnn exact_mod_cast this - have hden : ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) ≤ - ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by - have h1 : (786932288647 * 2 ^ 725 : Real) ≤ - ((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) := by + have hden : (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) ≤ + ((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real) := by + have h1 : ((DU * 2 ^ 725 : Int) : Real) ≤ ((A1 + T * Bo1 : Int) : Real) := by exact_mod_cast hDH1 - have h2 : (786932288647 * 2 ^ 725 : Real) ≤ - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real) := by + have h2 : ((DU * 2 ^ 725 : Int) : Real) ≤ ((A + T * Bo : Int) : Real) := by exact_mod_cast hDH - exact mul_le_mul h1 h2 (by positivity) (by exact_mod_cast le_of_lt hDH1pos) - calc ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) * - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) - ≤ ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) := + exact mul_le_mul h1 h2 (le_of_lt hDUR) (by exact_mod_cast le_of_lt hDH1pos) + calc ((2 * T * 2 ^ 110 * KpM v : Int) : Real) * + (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) + ≤ ((2 * T * 2 ^ 110 * Khi : Int) : Real) * + (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) := mul_le_mul_of_nonneg_right hnum (by positivity) - _ ≤ ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * - (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) := by + _ ≤ ((2 * T * 2 ^ 110 * Khi : Int) : Real) * + (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) := by apply mul_le_mul_of_nonneg_left hden exact le_trans hnum_nn hnum - -- the literal budget, Mp-factor included + -- the piece budget, Mp-factor included have hbudget : (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * - (((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real))) ≤ - 1685843742692980488 / 10000000000000000000 := by + (((2 * T * 2 ^ 110 * Khi : Int) : Real) / + (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real))) ≤ + 1644901622230542074 / 10000000000000000000 := by have hMp1 : (0:Real) < (2 ^ 131 : Real) - 1 := by norm_num - have hDD : (0:Real) < (786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real) := by - positivity - rw [show (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * - (((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real))) = - ((2 ^ 126 * 2 ^ 131 : Real) * - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real)) / - ((((2 ^ 131 : Real) - 1)) * - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real))) from by - field_simp - try ring] - rw [div_le_div_iff₀ (by positivity) (by norm_num : (0:Real) < 10000000000000000000)] - have hint : (2 ^ 126 * 2 ^ 131 : Int) * - (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc) * - 10000000000000000000 ≤ (1685843742692980488 : Int) * - ((2 ^ 131 - 1) * ((786932288647 * 2 ^ 725) * (786932288647 * 2 ^ 725))) := by - unfold KVMAXc - norm_num - calc (2 ^ 126 * 2 ^ 131 : Real) * - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) * + have hDUR : (0:Real) < ((DU * 2 ^ 725 : Int) : Real) := by exact_mod_cast hDU725 + have hDD : (0:Real) < ((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real) := + mul_pos hDUR hDUR + rw [show (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) = + (2 ^ 126 * 2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1) from by rw [mul_div_assoc], + div_mul_div_comm] + rw [div_le_div_iff₀ (mul_pos hMp1 hDD) (by norm_num : (0:Real) < 10000000000000000000)] + have hint : (2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 ≤ + (1644901622230542074 : Int) * + ((2 ^ 131 - 1) * ((DU * 2 ^ 725) * (DU * 2 ^ 725))) := by + calc (2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 + = 2 ^ 126 * 2 ^ 131 * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 := by ring + _ ≤ _ := hbudU + calc (2 ^ 126 * 2 ^ 131 : Real) * ((2 * T * 2 ^ 110 * Khi : Int) : Real) * 10000000000000000000 - = (((2 ^ 126 * 2 ^ 131 : Int) * - (2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc) * + = (((2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 : Int) : Real) := by push_cast; ring - _ ≤ (((1685843742692980488 : Int) * - ((2 ^ 131 - 1) * ((786932288647 * 2 ^ 725) * (786932288647 * 2 ^ 725))) : Int) : Real) := by + _ ≤ (((1644901622230542074 : Int) * + ((2 ^ 131 - 1) * ((DU * 2 ^ 725) * (DU * 2 ^ 725))) : Int) : Real) := by exact_mod_cast hint - _ = (1685843742692980488 : Real) * + _ = (1644901622230542074 : Real) * (((2 ^ 131 : Real) - 1) * - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real))) := by + (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real))) := by push_cast; ring -- assemble part 2 have hgap_le : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) - (NUMv v t : Real) / (DENv v t : Real) ≤ - ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) := by + ((2 * T * 2 ^ 110 * Khi : Int) : Real) / + (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) := by have hu_eq : ((2 * u * 2 ^ 110 * KpM v : Int) : Real) = ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) := by rw [hudef] calc (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) - @@ -398,11 +372,10 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) ((DENv (v + 1) t : Real) * (DENv v t : Real)) := hstep_eq _ = ((2 * u * 2 ^ 110 * KpM v : Int) : Real) / ((DENv (v + 1) t : Real) * (DENv v t : Real)) := by rw [hu_eq] - _ ≤ ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KpM v : Int) : Real) / - (((A1 + 117932881612756647068972071382077242199 * Bo1 : Int) : Real) * - ((A + 117932881612756647068972071382077242199 * Bo : Int) : Real)) := hfracu - _ ≤ ((2 * 117932881612756647068972071382077242199 * 2 ^ 110 * KVMAXc : Int) : Real) / - ((786932288647 * 2 ^ 725 : Real) * (786932288647 * 2 ^ 725 : Real)) := hfracH + _ ≤ ((2 * T * 2 ^ 110 * KpM v : Int) : Real) / + (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) := hfracu + _ ≤ ((2 * T * 2 ^ 110 * Khi : Int) : Real) / + (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) := hfracH have hMpnn : (0:Real) ≤ (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) := by have : (0:Real) < (2 ^ 131 : Real) - 1 := by norm_num positivity diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean index 069ab6813..22a951cd7 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean @@ -1,7 +1,70 @@ import ExpProof.Floor.R0Bound import ExpProof.Floor.CapsV import ExpProof.Cert.ExpVDOver -import ExpProof.Cert.ExpVDUnder +import ExpProof.Cert.ExpVDOvP00 +import ExpProof.Cert.ExpVDUnP00 +import ExpProof.Cert.ExpVDOvP01 +import ExpProof.Cert.ExpVDUnP01 +import ExpProof.Cert.ExpVDOvP02 +import ExpProof.Cert.ExpVDUnP02 +import ExpProof.Cert.ExpVDOvP03 +import ExpProof.Cert.ExpVDUnP03 +import ExpProof.Cert.ExpVDOvP04 +import ExpProof.Cert.ExpVDUnP04 +import ExpProof.Cert.ExpVDOvP05 +import ExpProof.Cert.ExpVDUnP05 +import ExpProof.Cert.ExpVDOvP06 +import ExpProof.Cert.ExpVDUnP06 +import ExpProof.Cert.ExpVDOvP07 +import ExpProof.Cert.ExpVDUnP07 +import ExpProof.Cert.ExpVDOvP08 +import ExpProof.Cert.ExpVDUnP08 +import ExpProof.Cert.ExpVDOvP09 +import ExpProof.Cert.ExpVDUnP09 +import ExpProof.Cert.ExpVDOvP10 +import ExpProof.Cert.ExpVDUnP10 +import ExpProof.Cert.ExpVDOvP11 +import ExpProof.Cert.ExpVDUnP11 +import ExpProof.Cert.ExpVDOvP12 +import ExpProof.Cert.ExpVDUnP12 +import ExpProof.Cert.ExpVDOvP13 +import ExpProof.Cert.ExpVDUnP13 +import ExpProof.Cert.ExpVDOvP14 +import ExpProof.Cert.ExpVDUnP14 +import ExpProof.Cert.ExpVDOvP15 +import ExpProof.Cert.ExpVDUnP15 +import ExpProof.Cert.ExpVDOvP16 +import ExpProof.Cert.ExpVDUnP16 +import ExpProof.Cert.ExpVDOvP17 +import ExpProof.Cert.ExpVDUnP17 +import ExpProof.Cert.ExpVDOvP18 +import ExpProof.Cert.ExpVDUnP18 +import ExpProof.Cert.ExpVDOvP19 +import ExpProof.Cert.ExpVDUnP19 +import ExpProof.Cert.ExpVDOvP20 +import ExpProof.Cert.ExpVDUnP20 +import ExpProof.Cert.ExpVDOvP21 +import ExpProof.Cert.ExpVDUnP21 +import ExpProof.Cert.ExpVDOvP22 +import ExpProof.Cert.ExpVDUnP22 +import ExpProof.Cert.ExpVDOvP23 +import ExpProof.Cert.ExpVDUnP23 +import ExpProof.Cert.ExpVDOvP24 +import ExpProof.Cert.ExpVDUnP24 +import ExpProof.Cert.ExpVDOvP25 +import ExpProof.Cert.ExpVDUnP25 +import ExpProof.Cert.ExpVDOvP26 +import ExpProof.Cert.ExpVDUnP26 +import ExpProof.Cert.ExpVDOvP27 +import ExpProof.Cert.ExpVDUnP27 +import ExpProof.Cert.ExpVDOvP28 +import ExpProof.Cert.ExpVDUnP28 +import ExpProof.Cert.ExpVDOvP29 +import ExpProof.Cert.ExpVDUnP29 +import ExpProof.Cert.ExpVDOvP30 +import ExpProof.Cert.ExpVDUnP30 +import ExpProof.Cert.ExpVDOvP31 +import ExpProof.Cert.ExpVDUnP31 /-! # The argument-granularity link: `ê` at the floored `v` vs `ê` at the exact `t²` @@ -24,14 +87,17 @@ combine: * **the `K` identity** — one grid step is exact algebra: `NUMv(v)·DENv(v+1) − NUMv(v+1)·DENv(v) = 2t·2^110·K(v)` with `K(v) = Od(v)·Ev(v+1) − Ev(v)·Od(v+1)`, a degree-8 polynomial in `v` with all nine coefficients - positive, so `0 ≤ K(v) ≤ K(vmaxV)` on the grid; -* **the denominator floors** — the cover certificates `certDOver`/`certDUnder` pin - `Ev(v)·2^110 ∓ H128·Od(v)` above explicit constants over the whole grid `[0, vmaxV + 1]`; on the - negative half the one-grain lift `2|t|·K/(D·D′)` is additionally monotone in `|t|` (the derivative - sign reduces to the over-half floor `Ev·2^110 − |t|·Od ≥ 0`), so the `t = −H128` floor applies. - -`Floor/GranPair` packages these into the two per-side real-level budget bounds the `r0`-vs-`exp` -chains consume. + positive, so `K` is nonnegative and nondecreasing on the grid; +* **the piecewise denominator floors** — the grid `[0, vmaxV]` is split into 32 pieces, each with a + `t`-cap `T` (`v` in the piece forces `|t| ≤ T` through `v = ⌊t²/2^133⌋`) and cover-certified + floors `Ev(v)·2^110 ∓ T·Od(v) ≥ D·2^725` over the piece (the step looks one cell ahead, so the + certs run to `vhi + 1`); on the negative half the one-grain lift `2|t|·K/(D·D′)` is additionally + monotone in `|t|` (the derivative sign reduces to the over-half floor `Ev·2^110 − |t|·Od ≥ 0`), + so each piece's `t = −T` floor applies. `piece_select` packages the per-piece constants — floors, + `K`-cap, and the certified budget inequalities — for the runtime point. + +`Floor/GranPair` combines these into the two per-side real-level budget bounds the `r0`-vs-`exp` +chains consume, taking the piecewise maximum over the 32 certified per-piece envelopes. -/ namespace ExpYul @@ -226,7 +292,29 @@ theorem odNumV_eq_poly (v : Nat) : (odNumV v : Int) = evalPoly ExpCertV.odVPoly push_cast ring -/-! ## The certified denominator floors over the grid -/ +/-- The over-half floor shape evaluated at a grid point: +`certDOverP T D (v) = Ev(v)·2^110 − T·Od(v) − D·2^725`. -/ +theorem evalDOverP (T D : Int) (v : Nat) : + evalPoly (ExpCertV.certDOverP T D) (v : Int) = + (evNumV v : Int) * 2 ^ 110 - T * (odNumV v : Int) - D * 2 ^ 725 := by + unfold ExpCertV.certDOverP + rw [evalPoly_polyAdd, evalPoly_polySub, evalPoly_polyScale, evalPoly_polyScale, + ← evNumV_eq_poly, ← odNumV_eq_poly] + simp only [evalPoly] + ring + +/-- The under-half floor shape evaluated at a grid point: +`certDUnderP T D (v) = Ev(v)·2^110 + T·Od(v) − D·2^725`. -/ +theorem evalDUnderP (T D : Int) (v : Nat) : + evalPoly (ExpCertV.certDUnderP T D) (v : Int) = + (evNumV v : Int) * 2 ^ 110 + T * (odNumV v : Int) - D * 2 ^ 725 := by + unfold ExpCertV.certDUnderP + rw [evalPoly_polyAdd, evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyScale, + ← evNumV_eq_poly, ← odNumV_eq_poly] + simp only [evalPoly] + ring + +/-! ## The certified global denominator floor over the grid -/ /-- The over-half denominator floor: `DENv(v, t) ≥ 554482771859·2^725` for `0 ≤ t ≤ H128` on the grid `[0, vmaxV + 1]`, from the cover certificate `certDOver`. -/ @@ -245,10 +333,7 @@ theorem DENv_ge_over {v : Nat} {t : Int} (hv : v ≤ ExpCertV.vmaxV + 1) (evNumV v : Int) * 2 ^ 110 - 117932881612756647068972071382077242199 * (odNumV v : Int) - 554482771859 * 2 ^ 725 := by unfold ExpCertV.certDOver - rw [evalPoly_polyAdd, evalPoly_polySub, evalPoly_polyScale, evalPoly_polyScale, - ← evNumV_eq_poly, ← odNumV_eq_poly, hH] - simp only [evalPoly] - ring + rw [evalDOverP, hH] rw [hexp] at hcert have hOd_nn : (0 : Int) ≤ (odNumV v : Int) := Int.natCast_nonneg _ have htOd : t * (odNumV v : Int) ≤ 117932881612756647068972071382077242199 * (odNumV v : Int) := @@ -256,39 +341,6 @@ theorem DENv_ge_over {v : Nat} {t : Int} (hv : v ≤ ExpCertV.vmaxV + 1) unfold DENv linarith [hcert, htOd] -/-- The under-half denominator floor at the domain edge: -`Ev(v)·2^110 + H128·Od(v) ≥ 786932288647·2^725` on the grid, from `certDUnder`. -/ -theorem D_at_H_ge_under {v : Nat} (hv : v ≤ ExpCertV.vmaxV + 1) : - 786932288647 * 2 ^ 725 ≤ - (evNumV v : Int) * 2 ^ 110 + 117932881612756647068972071382077242199 * (odNumV v : Int) := by - have hvI : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ - have hvI2 : (v : Int) ≤ 1277263193518626341050532535110179583 := by - have h : v ≤ 1277263193518626341050532535110179583 := by - unfold ExpCertV.vmaxV at hv; omega - exact_mod_cast h - have hcert := ExpCertV.dUnderV_nonneg hvI hvI2 - have hH : ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 := by - unfold ExpCertV.H128; norm_num - have hexp : evalPoly ExpCertV.certDUnder (v : Int) = - (evNumV v : Int) * 2 ^ 110 + 117932881612756647068972071382077242199 * (odNumV v : Int) - - 786932288647 * 2 ^ 725 := by - unfold ExpCertV.certDUnder - rw [evalPoly_polyAdd, evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyScale, - ← evNumV_eq_poly, ← odNumV_eq_poly, hH] - simp only [evalPoly] - ring - rw [hexp] at hcert - linarith [hcert] - -/-- The scaled even value dominates the whole `H128`-scaled odd value (the over floor is positive): -`H128·Od(v) ≤ Ev(v)·2^110` on the grid. -/ -theorem HOd_le_Ev {v : Nat} (hv : v ≤ ExpCertV.vmaxV + 1) : - 117932881612756647068972071382077242199 * (odNumV v : Int) ≤ (evNumV v : Int) * 2 ^ 110 := by - have h := DENv_ge_over hv (t := 117932881612756647068972071382077242199) (by norm_num) le_rfl - unfold DENv at h - have : (0 : Int) < 554482771859 * 2 ^ 725 := by positivity - linarith [h, this] - /-- The scaled even value alone clears the over floor. -/ theorem Ev_scaled_ge {v : Nat} (hv : v ≤ ExpCertV.vmaxV + 1) : 554482771859 * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 110 := by @@ -323,10 +375,6 @@ def Kpoly : List Int := [ 177702252311948919910468951720184092402653220933754361350350337206870976576, 4462739169817451478086891138411024] -/-- `K(vmaxV)`, the grid maximum of the step polynomial. -/ -def KVMAXc : Int := - 124865332739294834873516593328989107938627445220226415417519301074933005975501368871244922433473497551230403824606042833804361870589257536716807944070843003611163671987701060317587976677928870720398225511779857554302723969319393493947608003945282319951972195880806029003395011394810609114195299961562530515199537076949072909524942387258516947793649920 - theorem Kpoly_coeffs_nonneg : ∀ c ∈ Kpoly, (0 : Int) ≤ c := by unfold Kpoly; intro c hc; fin_cases hc <;> norm_num @@ -340,19 +388,11 @@ theorem KpM_nonneg (v : Nat) : 0 ≤ KpM v := by rw [KpM_eq_poly] exact evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (Int.natCast_nonneg _) -theorem KpM_le_KVMAX {v : Nat} (hv : v ≤ ExpCertV.vmaxV) : KpM v ≤ KVMAXc := by - rw [KpM_eq_poly] - have hvI : (v : Int) ≤ (1277263193518626341050532535110179582 : Int) := by - have h : v ≤ 1277263193518626341050532535110179582 := by - unfold ExpCertV.vmaxV at hv; omega - exact_mod_cast h - have h1 : evalPoly Kpoly (v : Int) ≤ - evalPoly Kpoly (1277263193518626341050532535110179582 : Int) := - evalPoly_mono_of_nonneg Kpoly_coeffs_nonneg (Int.natCast_nonneg _) hvI - have h2 : evalPoly Kpoly (1277263193518626341050532535110179582 : Int) = KVMAXc := by - simp only [Kpoly, evalPoly, KVMAXc] - norm_num - linarith [h1, h2 ▸ h1] +/-- `K` is nondecreasing on the grid (positive coefficients), so a piece's upper edge caps it. -/ +theorem KpM_le_at {v vhi : Nat} (hv : v ≤ vhi) {Khi : Int} + (heval : evalPoly Kpoly (vhi : Int) = Khi) : KpM v ≤ Khi := by + rw [KpM_eq_poly, ← heval] + exact evalPoly_mono_of_nonneg Kpoly_coeffs_nonneg (Int.natCast_nonneg _) (by exact_mod_cast hv) /-- **The discrete quotient identity**: one grid step of the aligned rational is exact algebra. -/ theorem step_identity (v : Nat) (t : Int) : @@ -606,5 +646,714 @@ theorem tie_under {x : Nat} (hx : x < 2 ^ 256) _ = 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) := by ring exact le_of_mul_le_mul_left h2 hp555 +/-! ## The 32-piece granularity certificate -/ + +/-- The per-piece granularity facts at a grid point `v`: positivity of the floors and the cap, +the certified over/under denominator floors at both cells `v` and `v + 1`, the `K` cap, and the +certified budget inequalities of the piece against the two exported envelopes +(`3290521163436398582/10¹⁹` over, `1644901622230542074/10¹⁹` under, `Mp`-folded). -/ +def PieceOK (v : Nat) (T DO DU Khi : Int) : Prop := + 0 < DO ∧ 0 < DU ∧ 0 ≤ Khi ∧ 0 ≤ T ∧ + DO * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 110 - T * (odNumV v : Int) ∧ + DO * 2 ^ 725 ≤ (evNumV (v + 1) : Int) * 2 ^ 110 - T * (odNumV (v + 1) : Int) ∧ + DU * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 110 + T * (odNumV v : Int) ∧ + DU * 2 ^ 725 ≤ (evNumV (v + 1) : Int) * 2 ^ 110 + T * (odNumV (v + 1) : Int) ∧ + KpM v ≤ Khi ∧ + 2 * T * 2 ^ 110 * Khi * 2 ^ 126 * 10000000000000000000 ≤ + 3290521163436398582 * ((DO * 2 ^ 725) * (DO * 2 ^ 725)) ∧ + 2 ^ 126 * 2 ^ 131 * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 ≤ + 1644901622230542074 * ((2 ^ 131 - 1) * ((DU * 2 ^ 725) * (DU * 2 ^ 725))) + +/-- The piece cap dominates the square: from the split `t² < 2^133·v + 2^133`, membership +`v ≤ vhi`, and the cap fact `2^133·(vhi + 1) ≤ T²`. -/ +theorem tsq_lt_capsq {t : Int} {v : Nat} (hsplit : t ^ 2 < 2 ^ 133 * (v : Int) + 2 ^ 133) + {vhi : Nat} (hv : v ≤ vhi) {T : Int} + (hT : 2 ^ 133 * ((vhi : Nat) : Int) + 2 ^ 133 ≤ T ^ 2) : + t ^ 2 < T ^ 2 := by + have hvI : ((v : Nat) : Int) ≤ ((vhi : Nat) : Int) := by exact_mod_cast hv + nlinarith [hsplit, hT, hvI] + +theorem granPiece00 {v : Nat} (hlo : 0 ≤ v) + (hhi : v ≤ 39914474797457073157829141722193111) : + PieceOK v 20847785078312632088902884100098393904 650161701553 691253358954 + 124331295357477641581904138056792287020328920739682114857664357354828442875869025295095260106579486090794973807518308090512373664288724599481183645678243760168249900040574863180675819774653612798639898143210993293324267181199503250600403357996412545035325722827268263235801420237458721567675109488896589057678111549643018134304154993533622467567878144 := by + have hvlo : (0 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (39914474797457073157829141722193111 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP00_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP00_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP00_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP00_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece01 {v : Nat} (hlo : 39914474797457073157829141722193111 ≤ v) + (hhi : v ≤ 79828949594914146315658283444386223) : + PieceOK v 29483220403189161767243017845519310570 641945658278 700065691212 + 124348489536362811569823373638009000631667158096130666095582598399588448399876764381232405323636520833790009233576804961032917177931334727395109926278389044009567787762950649201982921306130024347784555916617412077827586978026950159438110911930706312161198243458825239986622498328512019492013159710459919171534255316797621253672688089454967194376994816 := by + have hvlo : (39914474797457073157829141722193111 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (79828949594914146315658283444386223 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP01_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP01_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP01_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP01_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece02 {v : Nat} (hlo : 79828949594914146315658283444386223 ≤ v) + (hhi : v ≤ 119743424392371219473487425166579335) : + PieceOK v 36109422980913784159270707268699614620 635708060030 706899646710 + 124365685902235707931662185236865182628053618073184713460247915523785590877700978509232142340905979095147288222533178910762560856667920293458238258376258151566628589949793659760772938934721283732147475148813094180263002559134506224431737786068252674285070073042702412156288743997299619998620649343861387292828263704160125292993790052190201592961630208 := by + have hvlo : (79828949594914146315658283444386223 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (119743424392371219473487425166579335 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP02_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP02_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP02_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP02_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece03 {v : Nat} (hlo : 119743424392371219473487425166579335 ≤ v) + (hhi : v ≤ 159657899189828292631316566888772447) : + PieceOK v 41695570156625264177805768200196787807 630494171758 712709960499 + 124382884455293592549521181635541090166983243381366801077634704386449155123538147775095644383601673251595741250522853679574835669070847383007608443452883503401958520975393281340104778870044828386724379056340673155550940420245984273438033970455973764538100904452446937706327654059882649333342250388341747084762611362343708770595139697547437718802268160 := by + have hvlo : (119743424392371219473487425166579335 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (159657899189828292631316566888772447 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP03_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP03_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP03_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP03_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece04 {v : Nat} (hlo : 159657899189828292631316566888772447 ≤ v) + (hhi : v ≤ 199572373987285365789145708610965559) : + PieceOK v 46617064615412821983671927489259435287 625934238048 717866387998 + 124400085195733739761025602560746264278616327664634676182714279775205998993015648254637590643537148550327888188208261194060492726583694561054370906623381684559581344625217362931467757553311495193356235609856263696492370325585701457614481355682705860334329988295937236347726204889864872718037319011296191356466375193232176092864574154432488170961567744 := by + have hvlo : (159657899189828292631316566888772447 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (199572373987285365789145708610965559 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP04_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP04_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP04_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP04_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece05 {v : Nat} (hlo : 199572373987285365789145708610965559 ≤ v) + (hhi : v ≤ 239486848784742438946974850333158671) : + PieceOK v 51066435709074987640046250875008841866 621838651900 722558536211 + 124417288123753436359835347518639131950249764195910712565839043606640499191676068467176975973602845905061591734256371371103126949086855419317934911533825904835688101580924850386714202151580739880884301210530166827007365319166903338988033945677286795960322070677949568801220865415748091974787433067612090788738328422094161653434502497346696847251472384 := by + have hvlo : (199572373987285365789145708610965559 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (239486848784742438946974850333158671 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP05_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP05_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP05_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP05_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece06 {v : Nat} (hlo : 239486848784742438946974850333158671 ≤ v) + (hhi : v ≤ 279401323582199512104803992055351783) : + PieceOK v 55158054703738454765934460694358669515 618094793288 726899025166 + 124434493239549981596155017198872213098454764998568650821632835242999466335788378628546409502791047296403032067730444905302684600204546104057200490811476284704813315263361171252130107427929606736210745667903934480980096706370969525764751373103018335410042751956297398979863880642988644489413669262837966594493347115533922961077511275265630319091449856 := by + have hvlo : (239486848784742438946974850333158671 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (279401323582199512104803992055351783 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP06_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP06_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP06_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP06_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece07 {v : Nat} (hlo : 279401323582199512104803992055351783 ≤ v) + (hhi : v ≤ 319315798379656585262633133777544895) : + PieceOK v 58966440806378323534486035691038621139 614629293866 730961223213 + 124451700543320687177243967447907493738634686713280628775100983611975805202752040889353877413014375516832698931548482651718513021265559009370228602810259469061747536661164515780773577557318528060603071915307121370309066625679902290704035239727413694095262005826377985200395700851400403348591051117166980795442448657546058790199544851673655003010039808 := by + have hvlo : (279401323582199512104803992055351783 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (319315798379656585262633133777544895 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP07_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP07_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP07_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP07_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece08 {v : Nat} (hlo : 319315798379656585262633133777544895 ≤ v) + (hhi : v ≤ 359230273177113658420462275499738007) : + PieceOK v 62543355234937896266708652300295181711 611391198603 734796085384 + 124468910035262877267926375811746527820975306698922635425840511894904787143595947811096724002989298686672217212850128746563838558316488647056623737058434359811261359426985503361599249033910735301816371731468685286395592499639857246867579557693036893681604611310616417652470415124037663243490099281703786843208686442477137477570980613863363719996702720 := by + have hvlo : (319315798379656585262633133777544895 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (359230273177113658420462275499738007 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP08_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP08_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP08_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP08_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece09 {v : Nat} (hlo : 359230273177113658420462275499738007 ≤ v) + (hhi : v ≤ 399144747974570731578291417221931119) : + PieceOK v 65926485017139723075679505829736200590 608343412382 738440706802 + 124486121715573888491101320648219831360978600025531681717397876827306892665309875389393384048481768653425841939803068139643786342072540530559822902480426047209561307177697067146275358391575766288843286569489630219937769323348732794039548321162137129920186263470953090477298031369179281491517916152969142359753029790232869618689856252942753648165781504 := by + have hvlo : (359230273177113658420462275499738007 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (399144747974570731578291417221931119 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP09_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP09_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP09_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP09_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece10 {v : Nat} (hlo : 399144747974570731578291417221931119 ≤ v) + (hhi : v ≤ 439059222772027804736120558944124231) : + PieceOK v 69144280814733066627417644920644591155 605457935097 741923087576 + 124503335584451069928252872808980133651989775186603141404988555934311273225981935990264178352237801072926478468069242743489283246177418736929404644129855308733243265589345733196988586035281255492337370426875119924531347417976092688100894991354677828964594141904176367929784428502523428286373737126082244818656262835605108546925443459326996088449204224 := by + have hvlo : (399144747974570731578291417221931119 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (439059222772027804736120558944124231 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP10_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP10_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP10_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP10_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece11 {v : Nat} (hlo : 439059222772027804736120558944124231 ≤ v) + (hhi : v ≤ 478973697569484877893949700666317343) : + PieceOK v 72218845961827568318541414537399229239 602713016329 745264978126 + 124520551642091783119960199891344051506346033527311875260959727302093972320951315622058263260947483656752103483840493935299413014630172637166451445835836333123354402531969814020920275057050896729991379522855922790213174946038953724627140431546256563282790729321557975220766789962190285045276381221546310035474840890128611108344299521825576877289373696 := by + have hvlo : (439059222772027804736120558944124231 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (478973697569484877893949700666317343 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP11_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP11_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP11_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP11_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece12 {v : Nat} (hlo : 478973697569484877893949700666317343 ≤ v) + (hhi : v ≤ 518888172366941951051778842388510455) : + PieceOK v 75167758079709234538337434275175078691 600091361400 748483673135 + 124537769888693402066407683060126753630994224554535911823544217765065136973421379022289603810616577756414482304042522678965020214723268111737918587829660616124019790143784379899466091486140170232387841381760682133717066154372228166965327582139308493893339685755904415758459311234618014480863534215048472382060547521413140374874865461769524694558507008 := by + have hvlo : (478973697569484877893949700666317343 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (518888172366941951051778842388510455 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP12_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP12_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP12_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP12_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece13 {v : Nat} (hlo : 518888172366941951051778842388510455 ≤ v) + (hhi : v ≤ 558802647164399024209607984110703567) : + PieceOK v 78005269036144011942405564982788931618 597578949702 751593193213 + 124554990324453313227895046439614183402643276463856617860620826667139541778214025095310619045745557140858097807995342065606587337322533394468882240084030263306935213398607214962659659999055128481075083753732139252846167979947868188032272919467882501275172597180793487630740957574925310783905297794170644686405700341432141068220616476957382929185505280 := by + have hvlo : (518888172366941951051778842388510455 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (558802647164399024209607984110703567 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP13_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP13_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP13_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP13_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece14 {v : Nat} (hlo : 558802647164399024209607984110703567 ≤ v) + (hhi : v ≤ 598717121961856097367437125832896679) : + PieceOK v 80743124413616312505576435261721815008 595164227770 754605091830 + 124572212949568915525347499075817409466735988388004451686363063634024838682581974293417926941741606509843226188507680602219637031806014514444459283762049224244872920374774308501649176691013237726857731636612069833000109322912017234062636495543175662919935430568420743292434031610801823061616938660393534826247558241784867596685707613532519179226251264 := by + have hvlo : (558802647164399024209607984110703567 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (598717121961856097367437125832896679 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP14_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP14_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP14_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP14_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece15 {v : Nat} (hlo : 598717121961856097367437125832896679 ≤ v) + (hhi : v ≤ 638631596759313170525266267555089791) : + PieceOK v 83391140313250528355611536400393575614 592837541332 757529023260 + 124589437764237620340825889469153674743743478040514552434825270072062036723231468590650395244014780971823114564072078109181139128465160131976111064838226271169192340088167775554464468086418974592526508495351327534529428960424730857521734109493908231115773540654136507544239294024475729934998271889261575071337487560484493736830994727238304877368049664 := by + have hvlo : (598717121961856097367437125832896679 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (638631596759313170525266267555089791 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP15_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP15_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP15_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP15_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece16 {v : Nat} (hlo : 638631596759313170525266267555089791 ≤ v) + (hhi : v ≤ 678546071556770243683095409277282902) : + PieceOK v 85957619938058733268340145980060814334 590590725148 760373152745 + 124606664768656851518036872677698715585072660242495883986009404890147362516004161739630680550417490341371797531129102305738763492805064552636381614815576193227674230986790052469783804926104175636072026017497532913712764135972392518808738959695402684214634690318526071631420652836377713510044584171075898860077101066298649153619546421349176320735146240 := by + have hvlo : (638631596759313170525266267555089791 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (678546071556770243683095409277282902 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP16_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP16_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP16_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP16_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece17 {v : Nat} (hlo : 678546071556770243683095409277282902 ≤ v) + (hhi : v ≤ 718460546354227316840924550999476014) : + PieceOK v 88449661209567485301729053536557931646 588416800156 763144459353 + 124623893963024045362843089991154923983117161607319595250352276881176522492194884460613602543396335504591097167825116970547969978539214562134291228254489780808179367553929062370966123062130918023648372481946314641375078442083168666134142802373602001339140773737530082849770581207983047544000442080270054092120631736071247951487235378516868923389575424 := by + have hvlo : (678546071556770243683095409277282902 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (718460546354227316840924550999476014 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP17_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP17_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP17_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP17_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece18 {v : Nat} (hlo : 718460546354227316840924550999476014 ≤ v) + (hhi : v ≤ 758375021151684389998753692721669126) : + PieceOK v 90873388353019950250431101958484117810 586309745473 765848963968 + 124641125347536650643773361175679926890136980575009349858406217274206787157703076060760159328132847795954730513979593904465877332579468208634643270080823067198699615091677996267451877154545985645750394641445535218127962690400435113781818788548560000033757028278051636102985402707506385563404221303398065990638629109910072511299669406189628394175746304 := by + have hvlo : (718460546354227316840924550999476014 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (758375021151684389998753692721669126 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP18_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP18_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP18_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP18_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece19 {v : Nat} (hlo : 758375021151684389998753692721669126 ≤ v) + (hhi : v ≤ 798289495949141463156582834443862238) : + PieceOK v 93234129230825643967343854978518870515 584264323835 768491903858 + 124658358922392128592532889289720157874976973585349126591994191589414143318317674249585953939689445877907213043541773343109004895170973418880732978969822834172603369724256116429567360678907949821785338291542213555676264600392085383654932815516512038924179692395697310049431946123044099632008145784092080082008997282395902899780773760707018755557253376 := by + have hvlo : (758375021151684389998753692721669126 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (798289495949141463156582834443862238 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP19_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP19_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP19_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP19_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece20 {v : Nat} (hlo : 798289495949141463156582834443862238 ≤ v) + (hhi : v ≤ 838203970746598536314411976166055350) : + PieceOK v 95536553193538501370371342040089081115 582275945893 771077868376 + 124675594687787952904513478070993997490747165237763127035427566697901602250251952214812407209685403872705846247477937047935221784504131219775890895308710226597840163524000974576243137476334383522428088205286797851946215689878018940255286367216193327977552796517938163227068652880076009442161336421787011377599536749774501652579713675135944281723646208 := by + have hvlo : (798289495949141463156582834443862238 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (838203970746598536314411976166055350 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP20_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP20_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP20_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP20_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece21 {v : Nat} (hlo : 838203970746598536314411976166055350 ≤ v) + (hhi : v ≤ 878118445544055609472241117888248462) : + PieceOK v 97784779688729301059274137358180034302 580340563312 773610905858 + 124692832643921609739303761894769059894869896935808653881092735350101587531430032270103876036884746059379184271665190236600427580654736038041033275582180880754632701237253832037879523775618655172970200553493385481080830204492902307986942299213350413599465132724297678377243046317980489697735516365263070803702961102484141857844356429316185731112812800 := by + have hvlo : (838203970746598536314411976166055350 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (878118445544055609472241117888248462 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP21_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP21_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP21_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP21_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece22 {v : Nat} (hlo : 878118445544055609472241117888248462 ≤ v) + (hhi : v ≤ 918032920341512682630070259610441574) : + PieceOK v 99982464869820254414073625773477941119 578454583528 776094608873 + 124710072790990597721199448303578204419096487383493075972991988236652404616688783744159514396070007044240287824345887307801597044260536584308823059040717802692047418498078277708138651227072800784330541158563593883567212800396557524991247542232380730500213376057729041528063562241291700217040789465713509633913187647063710417510471795210628415965565184 := by + have hvlo : (878118445544055609472241117888248462 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (918032920341512682630070259610441574 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP22_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP22_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP22_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP22_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece23 {v : Nat} (hlo : 918032920341512682630070259610441574 ≤ v) + (hhi : v ≤ 957947395138969755787899401332634686) : + PieceOK v 102132871418149975280092501750017683679 576614801025 778532182941 + 124727315129192427939713573108518851946746355961540412921623053526083995615369518787406156400695076250720100747414363107465415917032881745828700866616473650876388076205731326151647966692684964360547083172536492161275217469372676434156363226735329424653290080027222154454409639118762860054603295412526333649666966810986577471067570715716735210740850944 := by + have hvlo : (918032920341512682630070259610441574 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (957947395138969755787899401332634686 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP23_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP23_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP23_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP23_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece24 {v : Nat} (hlo : 957947395138969755787899401332634686 ≤ v) + (hhi : v ≤ 997861869936426828945728543054827798) : + PieceOK v 104238925391563160444514420500491969466 574818341390 780926502475 + 124744559658724623950086768062280187113640267181028232089748655102248273765009698829204279618836024260322304499496915014301962516688500738379965223716524366256202176396180621776988492113153599027805245602558636322821111864671816950930814484595369147288875282103336550254160949808787471699319045469454297801346819930501072096316219218429756015474831616 := by + have hvlo : (957947395138969755787899401332634686 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (997861869936426828945728543054827798 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP24_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP24_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP24_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP24_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece25 {v : Nat} (hlo : 997861869936426828945728543054827798 ≤ v) + (hhi : v ≤ 1037776344733883902103557684777020910) : + PieceOK v 106303262929504594869818257246985820007 573062615355 783280156749 + 124761806379784721773797541104042828508418061581110710714774372003029423130080663475144885725984487222537025652475264653903117504372851594413000910188341381740535255592335718526729635348334323826293981939499884365304112855169895086556973937458785015484930468250012152902743640195218386165140743123333051189013159768094053531385601709182103604421886208 := by + have hvlo : (997861869936426828945728543054827798 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (1037776344733883902103557684777020910 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP25_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP25_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP25_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP25_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece26 {v : Nat} (hlo : 1037776344733883902103557684777020910 ≤ v) + (hhi : v ≤ 1077690819531340975261386826499214022) : + PieceOK v 108328268942741352477812121806098843808 571345280717 785595487968 + 124779055292570269899072569176395550207149945606838875899620012840469640089953192690680914462253864237586791356793011581725611868132856890861674052417374931958913382272035748078660810463609033602416655977972300619097870804628644144326794634936383430538313658777665592770608423623112584549096894351992861228505372852729716292034044933517264204570415360 := by + have hvlo : (1037776344733883902103557684777020910 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (1077690819531340975261386826499214022 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP26_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP26_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP26_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP26_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece27 {v : Nat} (hlo : 1077690819531340975261386826499214022 ≤ v) + (hhi : v ≤ 1117605294328798048419215968221407134) : + PieceOK v 110316109407476909531868921388717338981 569664210570 787874623042 + 124796306397278829281397003614413639136369120172384195170136650261045884215508512174002585745594261301914147584573874806458850831483230446492832284181686273043379455747210133094758593510660561935119569748541092023013191742059770145448509959312139940918154391044235561210772363529417536390085012612494904915323547482551416688009151037590549562881138944 := by + have hvlo : (1077690819531340975261386826499214022 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (1117605294328798048419215968221407134 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP27_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP27_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP27_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP27_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece28 {v : Nat} (hlo : 1117605294328798048419215968221407134 ≤ v) + (hhi : v ≤ 1157519769126255121577045109943600246) : + PieceOK v 112268758510433036404380164835338032221 568017466591 790119500297 + 124813559694107973344024788107043473917872234784266850263288391783433297169048150877731843676637794092356374813269801556437879061596983545081768014553611911044754174402003345596816607427109899526336836315448152237782498258409790180099419767003797832223547387772496458446073160169102979920523224045308674145374435976269957371998125303322935675350397184 := by + have hvlo : (1117605294328798048419215968221407134 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (1157519769126255121577045109943600246 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP28_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP28_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP28_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP28_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece29 {v : Nat} (hlo : 1157519769126255121577045109943600246 ≤ v) + (hhi : v ≤ 1197434243923712194734874251665793358) : + PieceOK v 114188021614114346553315397742450038434 566403276447 792331892069 + 124830815183255287978488989230937912007852861268485186776484894629691039297391858695676855054821540550988755666246306222922080217137084067125422552803488226467137811892029054090053797255446672981786118025700422746450741633997798018226283790557025622187443712993615360108301740842729954061587078784532601098337144505997415684452821275968171765255782656 := by + have hvlo : (1157519769126255121577045109943600246 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (1197434243923712194734874251665793358 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP29_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP29_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP29_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP29_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece30 {v : Nat} (hlo : 1197434243923712194734874251665793358 ≤ v) + (hhi : v ≤ 1237348718721169267892703393387986470) : + PieceOK v 116075554802968570681645777137735089747 564820014566 794513423933 + 124848072864918371545112139556887073102151888314737992274617563444406384623288591387553293909461112918653868880401685945220431541232626739228028551925510171276514210561293346598405224457657291404585578627906913330891689370353658953641245078501638134388438230868583098903895936536936896771400874658745568736075948590821250687327963145587281512196247808 := by + have hvlo : (1197434243923712194734874251665793358 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (1237348718721169267892703393387986470 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP30_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP30_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP30_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP30_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +theorem granPiece31 {v : Nat} (hlo : 1237348718721169267892703393387986470 ≤ v) + (hhi : v ≤ 1277263193518626341050532535110179582) : + PieceOK v 117932881612756647068972071382077242231 563266185678 796665591163 + 124865332739294834873516593328989107938627445220226415417519301074933005975501368871244922433473497551230403824606042833804361870589257536716807944070843003611163671987701060317587976677928870720398225511779857554302723969319393493947608003945282319951972195880806029003395011394810609114195299961562530515199537076949072909524942387258516947793649920 := by + have hvlo : (1237348718721169267892703393387986470 : Int) ≤ (v : Int) := by exact_mod_cast hlo + have hvhi : (v : Int) ≤ (1277263193518626341050532535110179582 : Int) := by exact_mod_cast hhi + have hOv := ExpCertV.dOvP31_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP31_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP31_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP31_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], + by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + +/-- **Piece selection.** The runtime grid point lies in one of the 32 pieces, whose certified +constants apply, and the piece's `t`-cap dominates the reduced argument: `t² < T²`. -/ +theorem piece_select {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + ∃ T DO DU Khi : Int, + PieceOK (vTree x) T DO DU Khi ∧ (int256 (tTree x)) ^ 2 < T ^ 2 := by + obtain ⟨_, hsplit⟩ := tsq_split hx hC hC0 + have hvmax := vTree_le_vmax hx hC hC0 + have hvmax' : vTree x ≤ 1277263193518626341050532535110179582 := by + unfold ExpCertV.vmaxV at hvmax; omega + rcases le_or_gt (vTree x) 39914474797457073157829141722193111 with h00 | h00 + · exact ⟨_, _, _, _, granPiece00 (Nat.zero_le _) h00, tsq_lt_capsq hsplit h00 (by norm_num)⟩ + rcases le_or_gt (vTree x) 79828949594914146315658283444386223 with h01 | h01 + · exact ⟨_, _, _, _, granPiece01 (Nat.le_of_lt h00) h01, tsq_lt_capsq hsplit h01 (by norm_num)⟩ + rcases le_or_gt (vTree x) 119743424392371219473487425166579335 with h02 | h02 + · exact ⟨_, _, _, _, granPiece02 (Nat.le_of_lt h01) h02, tsq_lt_capsq hsplit h02 (by norm_num)⟩ + rcases le_or_gt (vTree x) 159657899189828292631316566888772447 with h03 | h03 + · exact ⟨_, _, _, _, granPiece03 (Nat.le_of_lt h02) h03, tsq_lt_capsq hsplit h03 (by norm_num)⟩ + rcases le_or_gt (vTree x) 199572373987285365789145708610965559 with h04 | h04 + · exact ⟨_, _, _, _, granPiece04 (Nat.le_of_lt h03) h04, tsq_lt_capsq hsplit h04 (by norm_num)⟩ + rcases le_or_gt (vTree x) 239486848784742438946974850333158671 with h05 | h05 + · exact ⟨_, _, _, _, granPiece05 (Nat.le_of_lt h04) h05, tsq_lt_capsq hsplit h05 (by norm_num)⟩ + rcases le_or_gt (vTree x) 279401323582199512104803992055351783 with h06 | h06 + · exact ⟨_, _, _, _, granPiece06 (Nat.le_of_lt h05) h06, tsq_lt_capsq hsplit h06 (by norm_num)⟩ + rcases le_or_gt (vTree x) 319315798379656585262633133777544895 with h07 | h07 + · exact ⟨_, _, _, _, granPiece07 (Nat.le_of_lt h06) h07, tsq_lt_capsq hsplit h07 (by norm_num)⟩ + rcases le_or_gt (vTree x) 359230273177113658420462275499738007 with h08 | h08 + · exact ⟨_, _, _, _, granPiece08 (Nat.le_of_lt h07) h08, tsq_lt_capsq hsplit h08 (by norm_num)⟩ + rcases le_or_gt (vTree x) 399144747974570731578291417221931119 with h09 | h09 + · exact ⟨_, _, _, _, granPiece09 (Nat.le_of_lt h08) h09, tsq_lt_capsq hsplit h09 (by norm_num)⟩ + rcases le_or_gt (vTree x) 439059222772027804736120558944124231 with h10 | h10 + · exact ⟨_, _, _, _, granPiece10 (Nat.le_of_lt h09) h10, tsq_lt_capsq hsplit h10 (by norm_num)⟩ + rcases le_or_gt (vTree x) 478973697569484877893949700666317343 with h11 | h11 + · exact ⟨_, _, _, _, granPiece11 (Nat.le_of_lt h10) h11, tsq_lt_capsq hsplit h11 (by norm_num)⟩ + rcases le_or_gt (vTree x) 518888172366941951051778842388510455 with h12 | h12 + · exact ⟨_, _, _, _, granPiece12 (Nat.le_of_lt h11) h12, tsq_lt_capsq hsplit h12 (by norm_num)⟩ + rcases le_or_gt (vTree x) 558802647164399024209607984110703567 with h13 | h13 + · exact ⟨_, _, _, _, granPiece13 (Nat.le_of_lt h12) h13, tsq_lt_capsq hsplit h13 (by norm_num)⟩ + rcases le_or_gt (vTree x) 598717121961856097367437125832896679 with h14 | h14 + · exact ⟨_, _, _, _, granPiece14 (Nat.le_of_lt h13) h14, tsq_lt_capsq hsplit h14 (by norm_num)⟩ + rcases le_or_gt (vTree x) 638631596759313170525266267555089791 with h15 | h15 + · exact ⟨_, _, _, _, granPiece15 (Nat.le_of_lt h14) h15, tsq_lt_capsq hsplit h15 (by norm_num)⟩ + rcases le_or_gt (vTree x) 678546071556770243683095409277282902 with h16 | h16 + · exact ⟨_, _, _, _, granPiece16 (Nat.le_of_lt h15) h16, tsq_lt_capsq hsplit h16 (by norm_num)⟩ + rcases le_or_gt (vTree x) 718460546354227316840924550999476014 with h17 | h17 + · exact ⟨_, _, _, _, granPiece17 (Nat.le_of_lt h16) h17, tsq_lt_capsq hsplit h17 (by norm_num)⟩ + rcases le_or_gt (vTree x) 758375021151684389998753692721669126 with h18 | h18 + · exact ⟨_, _, _, _, granPiece18 (Nat.le_of_lt h17) h18, tsq_lt_capsq hsplit h18 (by norm_num)⟩ + rcases le_or_gt (vTree x) 798289495949141463156582834443862238 with h19 | h19 + · exact ⟨_, _, _, _, granPiece19 (Nat.le_of_lt h18) h19, tsq_lt_capsq hsplit h19 (by norm_num)⟩ + rcases le_or_gt (vTree x) 838203970746598536314411976166055350 with h20 | h20 + · exact ⟨_, _, _, _, granPiece20 (Nat.le_of_lt h19) h20, tsq_lt_capsq hsplit h20 (by norm_num)⟩ + rcases le_or_gt (vTree x) 878118445544055609472241117888248462 with h21 | h21 + · exact ⟨_, _, _, _, granPiece21 (Nat.le_of_lt h20) h21, tsq_lt_capsq hsplit h21 (by norm_num)⟩ + rcases le_or_gt (vTree x) 918032920341512682630070259610441574 with h22 | h22 + · exact ⟨_, _, _, _, granPiece22 (Nat.le_of_lt h21) h22, tsq_lt_capsq hsplit h22 (by norm_num)⟩ + rcases le_or_gt (vTree x) 957947395138969755787899401332634686 with h23 | h23 + · exact ⟨_, _, _, _, granPiece23 (Nat.le_of_lt h22) h23, tsq_lt_capsq hsplit h23 (by norm_num)⟩ + rcases le_or_gt (vTree x) 997861869936426828945728543054827798 with h24 | h24 + · exact ⟨_, _, _, _, granPiece24 (Nat.le_of_lt h23) h24, tsq_lt_capsq hsplit h24 (by norm_num)⟩ + rcases le_or_gt (vTree x) 1037776344733883902103557684777020910 with h25 | h25 + · exact ⟨_, _, _, _, granPiece25 (Nat.le_of_lt h24) h25, tsq_lt_capsq hsplit h25 (by norm_num)⟩ + rcases le_or_gt (vTree x) 1077690819531340975261386826499214022 with h26 | h26 + · exact ⟨_, _, _, _, granPiece26 (Nat.le_of_lt h25) h26, tsq_lt_capsq hsplit h26 (by norm_num)⟩ + rcases le_or_gt (vTree x) 1117605294328798048419215968221407134 with h27 | h27 + · exact ⟨_, _, _, _, granPiece27 (Nat.le_of_lt h26) h27, tsq_lt_capsq hsplit h27 (by norm_num)⟩ + rcases le_or_gt (vTree x) 1157519769126255121577045109943600246 with h28 | h28 + · exact ⟨_, _, _, _, granPiece28 (Nat.le_of_lt h27) h28, tsq_lt_capsq hsplit h28 (by norm_num)⟩ + rcases le_or_gt (vTree x) 1197434243923712194734874251665793358 with h29 | h29 + · exact ⟨_, _, _, _, granPiece29 (Nat.le_of_lt h28) h29, tsq_lt_capsq hsplit h29 (by norm_num)⟩ + rcases le_or_gt (vTree x) 1237348718721169267892703393387986470 with h30 | h30 + · exact ⟨_, _, _, _, granPiece30 (Nat.le_of_lt h29) h30, tsq_lt_capsq hsplit h30 (by norm_num)⟩ + exact ⟨_, _, _, _, granPiece31 (Nat.le_of_lt h30) hvmax', + tsq_lt_capsq hsplit hvmax' (by norm_num)⟩ end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index 904b5e834..ff26437b9 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -10,7 +10,7 @@ import Mathlib.Data.Complex.ExponentialBounds # Discharging the runtime `r0` bound The public floor brackets need the Q126 quotient `r0Tree x` bracketed against the target -`E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(126 − k)`. This file builds two +`E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(108 − k)`. This file builds two ingredients of that discharge: * the **Horner-truncation bridge** for the even/odd accumulators — the runtime `evTree x`/`odTree x`, diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index e2a8b4359..8330b1787 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -9,10 +9,10 @@ import ExpProof.Seam.RealExp The per-point `r0`-vs-`exp` brackets (`r0_real_over_within`, `r0_real_under_within`) and the below-clamp bound (`belowC_target_lt_one`) establish the never-over and deficit-under-one facts about the real pre-floor accumulator unconditionally and axiom-clean, via the octave fold -`E·2^s = WAD·2¹²⁶·exp(rt)` (`s = 126 − k`, the closing shift; `k ≤ 63` so `s ≥ 63`). +`E·2^s = WAD·2¹⁰⁸·exp(rt)` (`WAD = 5¹⁸`; `s = 108 − k`, the closing shift; `k ≤ 63` so `s ≥ 45`). -* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 10155087723197130681/10000000000000000000` and `WAD·10155087723197130681/10000000000000000000 ≤ MARGIN`; -* `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 67/10` and `(67/10)·WAD + MARGIN < 2⁶³ ≤ 2^s`. +* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 10050013498897899168/10000000000000000000` and `5¹⁸·10050013498897899168/10000000000000000000 ≤ MARGIN`; +* `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 67/10` and `(67/10)·5¹⁸ + MARGIN < 2⁴⁵ ≤ 2^s`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. -/ @@ -37,16 +37,26 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- WAD·r0 − MARGIN ≤ WAD·2^126·Ert = E·2^s - have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069 ≤ + -- WAD·r0 − MARGIN ≤ 5^18·2^126·Ert = E·2^s + have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 10155087723197130681 / 10000000000000000000 := hover - have hscaled : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) ≤ - (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 10155087723197130681 / 10000000000000000000) := + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 10050013498897899168 / 10000000000000000000 := hover + have hscaled : (3814697265625 : Real) * (int256 (r0Tree x) : Real) ≤ + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 10050013498897899168 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num - rw [hwad]; nlinarith [hscaled] + rw [hwad] + have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by + rw [show (10 ^ 18 : Real) * (2 ^ 108 : Real) = (3814697265625 : Real) * (2 ^ 126 : Real) from by + norm_num] + ring + rw [hconst] + -- 5^18·B = 3833775901374.02… ≤ 3833775901375 = MARGIN + have hBM : (3814697265625 : Real) * (10050013498897899168 / 10000000000000000000) ≤ + 3833775901375 := by norm_num + linarith [hscaled, hBM] rw [hAeq, div_le_iff₀ hps]; linarith [hbound] /-- The target is below the accumulator plus one on the region. -/ @@ -59,26 +69,34 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hunder := r0_real_under_within hx hC hC0 obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- E·2^s = WAD·2^126·Ert < WAD·r0 − MARGIN + 2^s + -- E·2^s = 5^18·2^126·Ert < WAD·r0 − MARGIN + 2^s have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069) + (2 ^ s : Real) := by + ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375) + (2 ^ s : Real) := by rw [hfold] have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 67 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num - have hs63 : (63 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] - have hs63n : 63 ≤ s := by exact_mod_cast hs63 - have hpow : (2 ^ 63 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs63n + have hs45 : (45 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs45n : 45 ≤ s := by exact_mod_cast hs45 + have hpow : (2 ^ 45 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs45n rw [hwad] - have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 67 / 10) := - mul_le_mul_of_nonneg_left (by linarith [hr0R]) (by norm_num) - have hbudget : (10 ^ 18 : Real) * (67 / 10) + 1015508772319713069 < (2 ^ 63 : Real) := by norm_num - nlinarith [h8wad, hbudget, hpow] + have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by + rw [show (10 ^ 18 : Real) * (2 ^ 108 : Real) = (3814697265625 : Real) * (2 ^ 126 : Real) from by + norm_num] + ring + rw [hconst] + have hscaled : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ + (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 67 / 10) := + mul_le_mul_of_nonneg_left hr0R (by norm_num) + -- (67/10)·5^18 + MARGIN < 2^45 + have hbudget : (3814697265625 : Real) * (67 / 10) + 3833775901375 < (2 ^ 45 : Real) := by + norm_num + linarith [hscaled, hbudget, hpow] -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s rw [hAeq] - have hdiv : ((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069) / + have hdiv : ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375) / (2 ^ s : Real) + 1 = - (((10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069) + (2 ^ s : Real)) / + (((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp rw [hdiv, lt_div_iff₀ hps]; linarith [hbound] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index b3bafe710..8c96fd110 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -12,18 +12,18 @@ This module bounds the Q126 quotient `r0Tree x` above by `2¹²⁶·exp(rt)` plu (`rt = X/RAY − k·ln2` the reduced argument), the analytic content the floor brackets (`Floor.R0BoundHolds`) consume. The chain has four links: -1. **`r0` vs `ê(v)`** — Horner stage truncation and the closing `sdiv` floor only: the runtime +1. **`r0` vs `ê(v)`** — Horner stage truncation and the closing `div` floor only: the runtime accumulators bracket the exact integer polynomials (`evTree_bracket`/`odTree_bracket`), and the shared even truncation cancels through the floor, leaving the jitter `≤ 6207065162659510332/10¹⁹`; 2. **`ê(v)` vs `ê(t²)`** — the argument-granularity link (`Floor.GranV`): one `v`-grid grain, - `≤ 3395595387735630095/10¹⁹` on this half; + `≤ 3290521163436398582/10¹⁹` on this half (the 32-piece certified envelope); 3. **`ê(t²)` vs `exp(t/2¹²⁸)`** — the `2⁻¹³¹`-nudged Taylor cut (`Floor.CapsV`), the `Mp` factor `≤ 441941738241592203/10¹⁹`; 4. **`exp(t/2¹²⁸)` vs `exp(rt)`** — the reduced-argument gap (`Floor.Reduce`), `≤ 110485434560398051/10¹⁹`. -The total is the budget `B = 10155087723197130681/10¹⁹`; `MARGIN = ⌊10¹⁸·B⌋ + 1`. On the `t ≤ 0` +The total is the budget `B = 10050013498897899168/10¹⁹`; `MARGIN = ⌊5¹⁸·B⌋ + 1`. On the `t ≤ 0` half link 2 is free (the grain moves `ê` the other way) and links 3–4 shrink (`ê ≤ 1`), so the same `B` covers both halves. -/ @@ -38,7 +38,7 @@ set_option maxRecDepth 100000 set_option maxHeartbeats 1600000 set_option exponentiation.threshold 2000 -/-! ## The `sdiv` floor sandwich -/ +/-! ## The `div` floor sandwich -/ /-- The Q126 quotient is the integer floor: `r0·den_rt ≤ 2¹²⁶·num_rt < (r0+1)·den_rt` with `num_rt = ev + tod`, `den_rt = ev − tod`. -/ @@ -71,12 +71,12 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) nlinarith [this, ht125] have hshl : int256 (evmShl 0x7e num) = 2 ^ 0x7e * int256 num := shl126_transport hnumw (by rw [hnumi]; omega) hnumlt128 - -- r0 = sdiv (shl 126 num) den, with both operands positive - have hr0eq : r0Tree x = evmSdiv (evmShl 0x7e num) den := rfl + -- r0 = div (shl 126 num) den, with both operands positive + have hr0eq : r0Tree x = evmDiv (evmShl 0x7e num) den := rfl have hshlw : evmShl 0x7e num < 2 ^ 256 := evmShl_lt _ _ have hshlpos : 0 ≤ int256 (evmShl 0x7e num) := by rw [hshl, hnumi]; positivity have hdenpos' : 0 < int256 den := by rw [hdeni]; omega - have hdiv := evmSdiv_pos_pos hshlw hdenw hshlpos hdenpos' + have hdiv := evmDiv_pos_pos hshlw hdenw hshlpos hdenpos' rw [← hr0eq] at hdiv -- toNat values have hshl_toNat : (int256 (evmShl 0x7e num)).toNat = (evmShl 0x7e num) := by @@ -674,12 +674,12 @@ theorem Qv_le_14145 {x : Nat} (hx : x < 2 ^ 256) apply mul_le_mul (le_trans hEtsqrt2 hsqrt2_val) hMp_le (by positivity) (by norm_num) have h2 : (14143 / 10000 : Real) * (14144 / 14143) = 14144 / 10000 := by norm_num linarith [hNEDE_le, h1, h2 ▸ h1] - -- add the grain: 2^126·Qv ≤ 2^126·(NE/DE) + 0.34 ⟹ Qv ≤ 14144/10000 + 0.34/2^126 ≤ 14145/10000 + -- add the grain: 2^126·Qv ≤ 2^126·(NE/DE) + 0.33 ⟹ Qv ≤ 14144/10000 + 0.33/2^126 ≤ 14145/10000 have h2126 : (2 ^ 126 : Real) * ((NUMv (vTree x) t : Real) / (DENv (vTree x) t : Real)) ≤ - (2 ^ 126 : Real) * (14144 / 10000) + 3395595387735630095 / 10000000000000000000 := by + (2 ^ 126 : Real) * (14144 / 10000) + 3290521163436398582 / 10000000000000000000 := by have := mul_le_mul_of_nonneg_left hNEDE14144 (by positivity : (0:Real) ≤ (2:Real) ^ 126) linarith [hgran, this] - have hfin : (2 ^ 126 : Real) * (14144 / 10000) + 3395595387735630095 / 10000000000000000000 ≤ + have hfin : (2 ^ 126 : Real) * (14144 / 10000) + 3290521163436398582 / 10000000000000000000 ≤ (2 ^ 126 : Real) * (14145 / 10000) := by norm_num have hp : (0:Real) < (2 ^ 126 : Real) := by positivity exact le_of_mul_le_mul_left (le_trans h2126 hfin) hp @@ -816,13 +816,13 @@ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) mul_le_mul_of_nonneg_left hDENlowR (by norm_num) /-- **The per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + B` with the four-link budget -`B = 10155087723197130681/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3396…`, the `Mp` +`B = 10050013498897899168/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3291…`, the `Mp` factor `≤ √2·2¹²⁶/(2¹³¹−1) ≤ 0.0442…`, and the reduced-argument gap `≤ √2/128 ≤ 0.0111…`. -/ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10155087723197130681 / 10000000000000000000 := by + 10050013498897899168 / 10000000000000000000 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -924,17 +924,17 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + 6207065162659510332 / 10000000000000000000 := hlink1 _ ≤ ((2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - 3395595387735630095 / 10000000000000000000) + + 3290521163436398582 / 10000000000000000000) + 6207065162659510332 / 10000000000000000000 := by linarith [hgran] _ ≤ (((2 ^ 126 : Real) * Et + 441941738241592203 / 10000000000000000000) + - 3395595387735630095 / 10000000000000000000) + + 3290521163436398582 / 10000000000000000000) + 6207065162659510332 / 10000000000000000000 := by linarith [hNEMp, hcMp] _ ≤ ((((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + 441941738241592203 / 10000000000000000000) + - 3395595387735630095 / 10000000000000000000) + + 3290521163436398582 / 10000000000000000000) + 6207065162659510332 / 10000000000000000000 := by linarith [hEtErt] _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10155087723197130681 / 10000000000000000000 := by rw [hErtdef]; ring + 10050013498897899168 / 10000000000000000000 := by rw [hErtdef]; ring /-! ## The per-point never-over (nonpositive half) -/ @@ -1012,7 +1012,7 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10155087723197130681 / 10000000000000000000 := by + 10050013498897899168 / 10000000000000000000 := by have htdom := tdom_neg hx hC hC0 htneg have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -1105,29 +1105,30 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) 441941738241592203 / 10000000000000000000) + 6207065162659510332 / 10000000000000000000 := by linarith [hEtErt] _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10155087723197130681 / 10000000000000000000 := by + 10050013498897899168 / 10000000000000000000 := by rw [hErtdef] have : (110485434560398051 : Real) / 10000000000000000000 + 441941738241592203 / 10000000000000000000 + 6207065162659510332 / 10000000000000000000 ≤ - 10155087723197130681 / 10000000000000000000 := by norm_num + 10050013498897899168 / 10000000000000000000 := by norm_num linarith [this] /-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + B` (`WAD·B < MARGIN`). -/ theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10155087723197130681 / 10000000000000000000 := by + 10050013498897899168 / 10000000000000000000 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_over_tight hx hC hC0 htnn · exact r0_real_over_tight_neg hx hC hC0 (le_of_lt htneg) -/-! ## The octave real identity `E·2^(126−k) = WAD·2¹²⁶·exp(rt)` +/-! ## The octave real identity `E·2^(108−k) = WAD·2¹⁰⁸·exp(rt)` The target `E = WAD·exp(X/RAY)`. With `rt = X/RAY − k·ln2` the reduced argument, `exp(X/RAY) = -exp(rt)·2^k`, so the closing-shift fold `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`. This collapses the -never-over/deficit inequalities (stated against `E·2^s`, `s = 126 − k`) onto the clean -octave-independent relation `r0 ≈ 2¹²⁶·exp(rt)`. -/ +exp(rt)·2^k`, so the closing-shift fold `E·2^(108−k) = WAD·2¹⁰⁸·exp(rt)` (and `WAD·2¹⁰⁸ = 5¹⁸·2¹²⁶`, +the `5¹⁸·2¹⁰⁸` output grid's image of the Q126 quotient). This collapses the never-over/deficit +inequalities (stated against `E·2^s`, `s = 108 − k`) onto the clean octave-independent relation +`r0 ≈ 2¹²⁶·exp(rt)`. -/ /-- `exp(X/RAY) = exp(rt)·2^k` (`k = int256 (kTree x)`, possibly negative; `2^k` is a real `zpow`). -/ theorem exp_X_over_RAY (x : Nat) : @@ -1141,24 +1142,24 @@ theorem exp_X_over_RAY (x : Nat) : unfold reducedArg; ring, Real.exp_add, hlog] -/-- **The octave fold of the target.** `E·2^(126−k) = WAD·2¹²⁶·exp(rt)`, with `s = 126 − k` the +/-- **The octave fold of the target.** `E·2^(108−k) = WAD·2¹⁰⁸·exp(rt)`, with `s = 108 − k` the closing shift. -/ -theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 126 - int256 (kTree x)) : +theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 108 - int256 (kTree x)) : expRayToWadTarget (int256 x) * (2 ^ s : Real) = - (WAD : Real) * (2 ^ 126 : Real) * Real.exp (reducedArg x) := by + (WAD : Real) * (2 ^ 108 : Real) * Real.exp (reducedArg x) := by unfold expRayToWadTarget rw [show (RAY : Real) = (10 ^ 27 : Real) from by unfold RAY; norm_num, exp_X_over_RAY x] - -- 2^k · 2^s = 2^126 with k+s = 126 (k : Int, s : Nat). + -- 2^k · 2^s = 2^108 with k+s = 108 (k : Int, s : Nat). set k := int256 (kTree x) with hkdef - have hks : k + (s : Int) = 126 := by omega - have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (126 : Nat) := by + have hks : k + (s : Int) = 108 := by omega + have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (108 : Nat) := by rw [show ((2 : Real) ^ (s : Nat)) = (2 : Real) ^ (s : Int) from by rw [zpow_natCast], ← zpow_add₀ (by norm_num : (2:Real) ≠ 0), hks] norm_num rw [show ((2 ^ s : Real)) = (2 : Real) ^ (s : Nat) from by norm_num] calc (WAD : Real) * (Real.exp (reducedArg x) * (2 : Real) ^ k) * (2 : Real) ^ (s : Nat) = (WAD : Real) * ((2 : Real) ^ k * (2 : Real) ^ (s : Nat)) * Real.exp (reducedArg x) := by ring - _ = (WAD : Real) * (2 ^ 126 : Real) * Real.exp (reducedArg x) := by + _ = (WAD : Real) * (2 ^ 108 : Real) * Real.exp (reducedArg x) := by rw [hpow] end diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index 9913563d9..cccdeabd5 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -7,12 +7,12 @@ This module contains the counterpart to the never-over `r0_real_over_within`: th `2¹²⁶·exp(rt) ≤ r0 + 67/10` (`r0_real_under_within`), both signs, with the same four-link chain: 1. link-1 deficit against the grid rational, `≤ 6001/1000`; -2. the argument granularity (`Floor.GranV`) — free on the `t ≥ 0` half, `≤ 1685843742692980488/10¹⁹` +2. the argument granularity (`Floor.GranV`) — free on the `t ≥ 0` half, `≤ 1644901622230542074/10¹⁹` (`Mp`-folded) on the `t ≤ 0` half; 3. the `Mp` factor, `≤ 1/20` (via `r0 ≤ 1.45·2¹²⁶`); 4. the under-direction reduced-argument gap, `≤ 37/100` (via `exp(rt) ≤ √2·(1+ε)`). -The sum `6001/1000 + 1/20 + 1685843742692980488/10¹⁹ + 37/100 ≤ 67/10` feeds the `k = 63` deficit +The sum `6001/1000 + 1/20 + 1644901622230542074/10¹⁹ + 37/100 ≤ 67/10` feeds the `k = 63` deficit envelope `((67/10)·10¹⁸ + MARGIN)/2⁶³ < 1`. The module closes with the octave-seam `r0`-doubling bound `r0₁ + 2 ≤ 2·r0₂` (`SeamR0Bound`), where the `1 − exp(−1/RAY)` seam slack (≈ `1.7·10¹¹` grid units against `r0₂ > 2¹²⁴`) dwarfs both per-point budgets and the two integer units. @@ -375,7 +375,7 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) /-! ## The per-point deficit (nonpositive half) -/ /-- **The per-point deficit (nonpositive half).** `2¹²⁶·exp(rt) ≤ r0 + 67/10`: link-1 `≤ 6001/1000`, -the `Mp`-folded granularity `≤ 1685843742692980488/10¹⁹`, the `Mp` factor `≤ 1/20` +the `Mp`-folded granularity `≤ 1644901622230542074/10¹⁹`, the `Mp` factor `≤ 1/20` (via `r0 ≤ 2¹²⁶`), the under gap `≤ 37/100`. -/ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) @@ -424,7 +424,7 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) push_cast at h linarith [h] have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 20 + - 1685843742692980488 / 10000000000000000000 := by + 1644901622230542074 / 10000000000000000000 := by have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := mul_le_mul_of_nonneg_left hEt_le (by positivity) -- split: 2^126·(NE/DE)·Mp = 2^126·Qv + 2^126·Qv·(Mp−1) + 2^126·Mp·(NE/DE − Qv) @@ -466,7 +466,7 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 67 / 10 - have hsum : (6001 : Real) / 1000 + 1 / 20 + 1685843742692980488 / 10000000000000000000 + + have hsum : (6001 : Real) / 1000 + 1 / 20 + 1644901622230542074 / 10000000000000000000 + 37 / 100 ≤ 67 / 10 := by norm_num linarith [hEt_bound, hgap126, hdist, hsum] @@ -542,10 +542,10 @@ theorem r0_seam_double {x1 x2 : Nat} have hE2bound : (2 ^ 126 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + 67 / 10 := hunder2 have hr0_1 : (int256 (r0Tree x1) : Real) ≤ 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y + - 10155087723197130681 / 10000000000000000000 := by + 10050013498897899168 / 10000000000000000000 := by have h1 : (2 ^ 126 : Real) * E1 = 2 * ((2 ^ 126 : Real) * E2) * y := by rw [hseam]; ring have h2 : (int256 (r0Tree x1) : Real) ≤ (2 ^ 126 : Real) * E1 + - 10155087723197130681 / 10000000000000000000 := hover1 + 10050013498897899168 / 10000000000000000000 := hover1 rw [h1] at h2 have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y := mul_le_mul_of_nonneg_right @@ -555,7 +555,7 @@ theorem r0_seam_double {x1 x2 : Nat} have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^124)] have hkey : 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y + - 10155087723197130681 / 10000000000000000000 + 2 < 2 * (int256 (r0Tree x2) : Real) := by + 10050013498897899168 / 10000000000000000000 + 2 < 2 * (int256 (r0Tree x2) : Real) := by -- the seam gap is dominated by `(r0 + 67/10) / RAY`; the quotient exceeds `1562` here have hyb : 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) := diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index 4494e76e5..2d3351724 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -33,13 +33,13 @@ set_option maxRecDepth 100000 /-! ## Strict never-over: the accumulator stays a positive distance below the target -`accumReal_over` gives `accumReal x ≤ E`. With `B = 10155087723197130681/10¹⁹` the never-over envelope, -`MARGIN` is `⌊WAD·B⌋ + 1`, so the inequality is in fact strict — the slack `δ = MARGIN − WAD·B = 9/10` -(worth `δ/2^s` after the closing shift). The round trip needs this strictness to rule out -`accumReal x = w` exactly. -/ +`accumReal_over` gives `accumReal x ≤ E`. With `B = 10050013498897899168/10¹⁹` the never-over envelope, +`MARGIN` is `⌊WAD·B⌋ + 1` (`WAD = 5¹⁸`), so the inequality is in fact strict — the slack +`δ = MARGIN − WAD·B ≈ 0.98` (worth `δ/2^s` after the closing shift). The round trip needs this +strictness to rule out `accumReal x = w` exactly. -/ /-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the target. -The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 10155087723197130681/10000000000000000000` plus `WAD·10155087723197130681/10000000000000000000 < MARGIN` give a strictly +The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 10050013498897899168/10000000000000000000` plus `WAD·10050013498897899168/10000000000000000000 < MARGIN` give a strictly negative residue. -/ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -49,24 +49,32 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- WAD·r0 − MARGIN < WAD·2^126·Ert = E·2^s, using WAD·10155087723197130681/10000000000000000000 < MARGIN - have hbound : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069 < + -- WAD·r0 − MARGIN < 5^18·2^126·Ert = E·2^s, using WAD·10050013498897899168/10000000000000000000 < MARGIN + have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375 < expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 10155087723197130681 / 10000000000000000000 := hover - have hscaled : (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) ≤ - (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert + 10155087723197130681 / 10000000000000000000) := + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 10050013498897899168 / 10000000000000000000 := hover + have hscaled : (3814697265625 : Real) * (int256 (r0Tree x) : Real) ≤ + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 10050013498897899168 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] - -- WAD·B = 1015508772319713068.1 < 1015508772319713069 = MARGIN - nlinarith [hscaled] + have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by + rw [show (10 ^ 18 : Real) * (2 ^ 108 : Real) = (3814697265625 : Real) * (2 ^ 126 : Real) from by + norm_num] + ring + rw [hconst] + -- WAD·B = 3833775901374.02 < 3833775901375 = MARGIN + have hBM : (3814697265625 : Real) * (10050013498897899168 / 10000000000000000000) < + 3833775901375 := by norm_num + linarith [hscaled, hBM] rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] /-- **Accumulator deficit, region-uniform.** On the region the accumulator is below the target by strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 67/10` and the -octave fold give `accumReal x ≥ E − ((67/10)·WAD + MARGIN)/2^s` with `s = 126 − k ≥ 63`, and -`((67/10)·WAD + MARGIN)/2⁶³ ≈ 0.837 < 24/25`. The tightness below one is what closes the round trip +octave fold give `accumReal x ≥ E − ((67/10)·WAD + MARGIN)/2^s` with `s = 108 − k ≥ 45`, and +`((67/10)·WAD + MARGIN)/2⁴⁵ ≈ 0.835 < 24/25`. The tightness below one is what closes the round trip together with `lnWadToRay`'s ≈10⁻⁹ envelope. -/ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -77,30 +85,36 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask have hunder := r0_real_under_within hx hC hC0 obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - have hs63 : (63 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] - have hs63n : 63 ≤ s := by exact_mod_cast hs63 - have hpow : (2 ^ 63 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs63n - -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = WAD·2^126·Ert ≤ WAD·(r0 + 8) - -- and 8·WAD + MARGIN < (24/25)·2^63 ≤ (24/25)·2^s + have hs45 : (45 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs45n : 45 ≤ s := by exact_mod_cast hs45 + have hpow : (2 ^ 45 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs45n + -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = 5^18·2^126·Ert ≤ WAD·(r0 + 67/10) + -- and (67/10)·WAD + MARGIN < (24/25)·2^45 ≤ (24/25)·2^s have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) - 1015508772319713069 := by + (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = - (WAD : Real) * (2 ^ 126 : Real) * Ert := hfold + (WAD : Real) * (2 ^ 108 : Real) * Ert := hfold have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 67 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num - have h8wad : (10 ^ 18 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (10 ^ 18 : Real) * ((int256 (r0Tree x) : Real) + 67 / 10) := + have h8wad : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ + (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 67 / 10) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - have hbudget : (10 ^ 18 : Real) * (67 / 10) + 1015508772319713069 < (24 / 25) * (2 ^ 63 : Real) := by + have hbudget : (3814697265625 : Real) * (67 / 10) + 3833775901375 < (24 / 25) * (2 ^ 45 : Real) := by norm_num rw [hwad] at hkey - have hEs : (10 ^ 18 : Real) * 2 ^ 126 * Ert ≤ - (10 ^ 18 : Real) * (int256 (r0Tree x) : Real) + (10 ^ 18 : Real) * (67 / 10) := by - nlinarith [h8wad] - -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; E·2^s = 10^18·2^126·Ert ; (24/25)·2^s ≥ (24/25)·2^63 - have h2425 : (24 / 25 : Real) * (2 ^ 63 : Real) ≤ (24 / 25) * (2 ^ s : Real) := + have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by + rw [show (10 ^ 18 : Real) * (2 ^ 108 : Real) = (3814697265625 : Real) * (2 ^ 126 : Real) from by + norm_num] + ring + rw [hconst] at hkey + have hEs : expRayToWadTarget (int256 x) * (2 ^ s : Real) ≤ + (3814697265625 : Real) * (int256 (r0Tree x) : Real) + (3814697265625 : Real) * (67 / 10) := by + rw [hkey]; nlinarith [h8wad] + -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; (24/25)·2^s ≥ (24/25)·2^45 + have h2425 : (24 / 25 : Real) * (2 ^ 45 : Real) ≤ (24 / 25) * (2 ^ s : Real) := mul_le_mul_of_nonneg_left hpow (by norm_num) - nlinarith [hkey, hEs, hbudget, hpow, h2425] + nlinarith [hEs, hbudget, hpow, h2425] rw [hAeq, lt_div_iff₀ hps]; linarith [hbound] /-! ## The `lnWadToRay` envelope on the round-trip band diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index c9e80d16b..460b36dab 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -8,20 +8,21 @@ import ExpProof.Mono.RangeNonneg # Floor + branch assembly: the public `Real.exp` brackets `run_exp_ray_to_wad_evm_eq_expTree` returns `expTree x`, the clamp/pin shell around the floored -accumulator `r1Tree x = sar(126 − k, WAD·r0 − MARGIN)`. On the meaningful region the closing shift -`s = 126 − k ∈ [63, 187]` is positive and the shift argument `arg = WAD·r0 − MARGIN` is nonnegative, -so the runtime result is exactly the integer floor `⌊arg / 2^s⌋` of the *real* pre-floor accumulator +accumulator `r1Tree x = shr(108 − k, WAD·r0 − MARGIN)`. On the meaningful region the closing shift +`s = 108 − k ∈ [45, 169]` is positive and the shift argument `arg = WAD·r0 − MARGIN` is a +nonnegative canonical word, so the runtime result is exactly the integer floor `⌊arg / 2^s⌋` of the +*real* pre-floor accumulator ``` -A = (WAD·r0 − MARGIN) / 2^(126 − k). +A = (WAD·r0 − MARGIN) / 2^(108 − k). ``` The two floor facts `(r : Real) ≤ A` and `A < (r : Real) + 1` (i.e. `r = ⌊A⌋`) are established here -from the `evmSar` sandwich. The relation between the *real-valued* runtime accumulator `A` and the -target `E = WAD·exp(x/RAY)` — never-over `A ≤ E` and deficit-under-one `E < A + 1` — is not a -runtime-plumbing fact; it is discharged in `Floor.R0BoundHolds` (`accumReal_over`/`accumReal_under`: -the cert `Floor/CapsV` against the exact rational, plus the argument-granularity, reduced-argument -and Horner-truncation envelopes the `MARGIN` absorbs). +from the plain `Nat` division behind `evmShr`. The relation between the *real-valued* runtime +accumulator `A` and the target `E = WAD·exp(x/RAY)` — never-over `A ≤ E` and deficit-under-one +`E < A + 1` — is not a runtime-plumbing fact; it is discharged in `Floor.R0BoundHolds` +(`accumReal_over`/`accumReal_under`: the cert `Floor/CapsV` against the exact rational, plus the +argument-granularity, reduced-argument and Horner-truncation envelopes the `MARGIN` absorbs). -/ namespace ExpYul @@ -36,34 +37,48 @@ set_option maxRecDepth 100000 /-! ## The closing-shift floor, unconditionally -/ -/-- A nonnegative arithmetic right shift is the integer floor of the division: with `s < 256`, -`W < 2^256` and `0 ≤ int256 W`, `int256 (evmSar s W)` is `⌊int256 W / 2^s⌋`, characterised by the +/-- A logical right shift of a nonnegative canonical word is the integer floor of the division: +with `s < 256`, `W < 2^256` and `0 ≤ int256 W`, `int256 (evmShr s W)` is characterised by the floor sandwich `2^s·R ≤ int256 W < 2^s·R + 2^s`. -/ -theorem sar_floor_sandwich {W s : Nat} (hs : s < 256) (hWw : W < 2 ^ 256) : - (2 ^ s : Int) * int256 (evmSar s W) ≤ int256 W ∧ - int256 W < (2 ^ s : Int) * int256 (evmSar s W) + 2 ^ s := by - obtain ⟨_, hlo, hhi⟩ := evmSar_sandwich hs hWw - exact ⟨hlo, hhi⟩ - -/-- The real pre-floor accumulator `A = arg / 2^s` and the runtime result `r = int256 (evmSar s W)` +theorem shr_floor_sandwich {W s : Nat} (hs : s < 256) (hWw : W < 2 ^ 256) (hWnn : 0 ≤ int256 W) : + (2 ^ s : Int) * int256 (evmShr s W) ≤ int256 W ∧ + int256 W < (2 ^ s : Int) * int256 (evmShr s W) + 2 ^ s := by + obtain ⟨hWi, hW255⟩ := int256_eq_of_nonneg hWw hWnn + rw [evmShr_eq_div hs hWw] + have hps : (0 : Nat) < 2 ^ s := Nat.two_pow_pos s + have hqlt : W / 2 ^ s < 2 ^ 255 := by + have h1 : W / 2 ^ s ≤ W := Nat.div_le_self W (2 ^ s) + omega + have hlo : 2 ^ s * (W / 2 ^ s) ≤ W := by + rw [Nat.mul_comm]; exact Nat.div_mul_le_self W (2 ^ s) + have hhi : W < 2 ^ s * (W / 2 ^ s) + 2 ^ s := by + have hdm := Nat.div_add_mod W (2 ^ s) + have hmod := Nat.mod_lt W hps + omega + rw [int256_of_lt hqlt, hWi] + constructor + · exact_mod_cast hlo + · exact_mod_cast hhi + +/-- The real pre-floor accumulator `A = arg / 2^s` and the runtime result `r = int256 (evmShr s W)` satisfy `(r : Real) ≤ A < (r : Real) + 1`. This is the floor step the bridge reduction takes as a -hypothesis; here it is discharged from the `evmSar` sandwich (`s < 256`). -/ -theorem sar_real_floor {W s : Nat} (hs : s < 256) (hWw : W < 2 ^ 256) : - let r : Int := int256 (evmSar s W) +hypothesis; here it is discharged from the `Nat` floor behind `evmShr` (`s < 256`, the shift +argument nonnegative). -/ +theorem shr_real_floor {W s : Nat} (hs : s < 256) (hWw : W < 2 ^ 256) (hWnn : 0 ≤ int256 W) : + let r : Int := int256 (evmShr s W) let A : Real := (int256 W : Real) / (2 ^ s : Real) (r : Real) ≤ A ∧ A < (r : Real) + 1 := by intro r A - obtain ⟨hlo, hhi⟩ := sar_floor_sandwich hs hWw + obtain ⟨hlo, hhi⟩ := shr_floor_sandwich hs hWw hWnn have hps : (0 : Real) < (2 ^ s : Real) := by positivity - have hpcast : ((2 ^ s : Int) : Real) = (2 ^ s : Real) := by push_cast; ring -- transport the integer sandwich to `Real` have hloR : (2 ^ s : Real) * (r : Real) ≤ (int256 W : Real) := by - have h : ((((2 ^ s : Int) * int256 (evmSar s W)) : Int) : Real) ≤ ((int256 W : Int) : Real) := + have h : ((((2 ^ s : Int) * int256 (evmShr s W)) : Int) : Real) ≤ ((int256 W : Int) : Real) := Int.cast_le.mpr hlo push_cast at h; linarith [h] have hhiR : (int256 W : Real) < (2 ^ s : Real) * (r : Real) + (2 ^ s : Real) := by have h : ((int256 W : Int) : Real) < - ((((2 ^ s : Int) * int256 (evmSar s W) + 2 ^ s) : Int) : Real) := Int.cast_lt.mpr hhi + ((((2 ^ s : Int) * int256 (evmShr s W) + 2 ^ s) : Int) : Real) := Int.cast_lt.mpr hhi push_cast at h; linarith [h] refine ⟨?_, ?_⟩ · rw [le_div_iff₀ hps]; linarith [hloR] @@ -72,17 +87,17 @@ theorem sar_real_floor {W s : Nat} (hs : s < 256) (hWw : W < 2 ^ 256) : /-! ## The runtime accumulator as a real number For `x > 0` in the meaningful region the result is the body word, `expTree x = r1Tree x`, with -`r1Tree x = evmSar (126 − k) (WAD·r0 − MARGIN)`. Its real pre-floor accumulator is +`r1Tree x = evmShr (108 − k) (WAD·r0 − MARGIN)`. Its real pre-floor accumulator is ``` -A x = int256 (WAD·r0 − MARGIN) / 2^(126 − k). +A x = int256 (WAD·r0 − MARGIN) / 2^(108 − k). ``` -/ /-- The real pre-floor accumulator of the runtime body, as an explicit `Real`. -/ def accumReal (x : Nat) : Real := - (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) : Real) / - (2 ^ (evmSub 0x7e (kTree x)) : Real) + (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) : Real) / + (2 ^ (evmSub 0x6c (kTree x)) : Real) /-- On the meaningful region the body word `r1Tree x` is the integer floor of its real accumulator `accumReal x`: `(r1Tree x : Real) ≤ accumReal x < (r1Tree x : Real) + 1`. -/ @@ -91,18 +106,20 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) (int256 (r1Tree x) : Real) ≤ accumReal x ∧ accumReal x < (int256 (r1Tree x) : Real) + 1 := by obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 - have hr1 : r1Tree x = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) := by - have : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) := rfl + obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 + obtain ⟨hargeq, hargnn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi + have hr1 : r1Tree x = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) := by + have : r1Tree x = evmShr (evmSub 0x6c (kTree x)) + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) := rfl rw [this, hseq] - have hWw : evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d < 2 ^ 256 := + have hWw : evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf < 2 ^ 256 := evmSub_lt _ _ - have hfloor := sar_real_floor (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) - (s := s) (by omega) hWw + have hfloor := shr_real_floor (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) + (s := s) (by omega) hWw (by rw [hargeq]; exact hargnn) simp only at hfloor - -- align `accumReal` (shift `evmSub 0x7e (kTree x)`) with the lemma's shift `s` + -- align `accumReal` (shift `evmSub 0x6c (kTree x)`) with the lemma's shift `s` have hAeq : accumReal x = - (int256 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) : Real) / + (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) : Real) / (2 ^ s : Real) := by unfold accumReal; rw [hseq] rw [hAeq, hr1] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index d56be0b35..548e64ed2 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -40,8 +40,9 @@ abbrev odShift4 : Nat := 0x82 abbrev todShift : Nat := 0x80 abbrev expQShift : Nat := 0x7e -abbrev wadWord : Nat := 0xde0b6b3a7640000 -abbrev marginWord : Nat := 0xe17cfd91868d72d +abbrev foldShift : Nat := 0x6c +abbrev wadWord : Nat := 0x3782dace9d9 +abbrev marginWord : Nat := 0x37c9ed9cabf theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by unfold Cmask int256 diff --git a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean index 4dc492073..19f4b6652 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean @@ -62,7 +62,7 @@ theorem shl126_transport {N : Nat} (hNw : N < 2 ^ 256) (hNnn : 0 ≤ int256 N) push_cast; ring /-- Abstract `r0` monotonicity from the `tod·ev` cross inequality, over opaque even/odd words. -Given the numerator/denominator positivity and `tod1·ev2 ≤ tod2·ev1`, the two `sdiv` quotients are +Given the numerator/denominator positivity and `tod1·ev2 ≤ tod2·ev1`, the two `div` quotients are `≤`-ordered. -/ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} (hE1 : E1 < 2 ^ 256) (hTD1 : TD1 < 2 ^ 256) (hE2 : E2 < 2 ^ 256) (hTD2 : TD2 < 2 ^ 256) @@ -75,8 +75,8 @@ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} (htod2_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD2) (htod2_hi : int256 TD2 < 42535295865117307932921825928971026432) (hcross : int256 TD1 * (E2 : Int) ≤ int256 TD2 * (E1 : Int)) : - int256 (evmSdiv (evmShl 0x7e (evmAdd E1 TD1)) (evmSub E1 TD1)) ≤ - int256 (evmSdiv (evmShl 0x7e (evmAdd E2 TD2)) (evmSub E2 TD2)) := by + int256 (evmDiv (evmShl 0x7e (evmAdd E1 TD1)) (evmSub E1 TD1)) ≤ + int256 (evmDiv (evmShl 0x7e (evmAdd E2 TD2)) (evmSub E2 TD2)) := by obtain ⟨hadd1, hsub1, hnum1, hden1⟩ := numden_pos_of hE1 hTD1 hev1_lo hev1_hi htod1_lo htod1_hi obtain ⟨hadd2, hsub2, hnum2, hden2⟩ := numden_pos_of hE2 hTD2 hev2_lo hev2_hi htod2_lo htod2_hi -- bound the tod magnitude by 2^127 (looser, symbolic) to avoid large-literal kernel work @@ -101,9 +101,9 @@ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} rw [hA1]; exact Int.mul_pos (by positivity) (hadd1 ▸ hnum1) have hA2pos : 0 < int256 (evmShl 0x7e (evmAdd E2 TD2)) := by rw [hA2]; exact Int.mul_pos (by positivity) (hadd2 ▸ hnum2) - -- both sdivs are floor divisions of nonnegative magnitudes - rw [evmSdiv_pos_pos (evmShl_lt _ _) (evmSub_lt _ _) (le_of_lt hA1pos) hD1pos, - evmSdiv_pos_pos (evmShl_lt _ _) (evmSub_lt _ _) (le_of_lt hA2pos) hD2pos] + -- both divs are floor divisions of nonnegative magnitudes + rw [evmDiv_pos_pos (evmShl_lt _ _) (evmSub_lt _ _) (le_of_lt hA1pos) hD1pos, + evmDiv_pos_pos (evmShl_lt _ _) (evmSub_lt _ _) (le_of_lt hA2pos) hD2pos] -- cross_to_div with the cross product A1·B2 ≤ A2·B1 have hdd := cross_to_div (le_of_lt hA1pos) (le_of_lt hA2pos) hD1pos hD2pos (by rw [hA1, hA2, hsub1, hsub2, hadd1, hadd2] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean index fdcc25839..8b4a976bc 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean @@ -8,7 +8,8 @@ From the stage bounds this file assembles the closing quotient `r0 = exp(t)·2^1 * `tod = ⌊t·Od / 2^128⌋` transported to `Int`, with `|tod| < 2^125`; * the numerator `num = ev + tod` and denominator `den = ev − tod` are strictly positive (the reduced argument keeps `|tod|` well below `ev`); -* `r0 = sdiv(2^126·num, den)` is at least `2^123` and below `2^128`. +* `r0 = div(2^126·num, den)` — a plain `Nat` floor division — is at least `2^123` and below + `2^128`. These give the range and nonnegativity obligations directly, and (via the cross-multiplication identity) reduce the within-octave monotonicity to a fact about `tod·ev`. @@ -135,7 +136,7 @@ theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD (hNpos : 0 < (N : Int)) (hDpos : 0 < (D : Int)) (hNlo : 2 ^ 125 ≤ N) (hND : (N : Int) < 4 * (D : Int)) : - 2 ^ 123 ≤ int256 (evmSdiv (evmShl 0x7e N) D) ∧ int256 (evmSdiv (evmShl 0x7e N) D) < 2 ^ 128 := by + 2 ^ 123 ≤ int256 (evmDiv (evmShl 0x7e N) D) ∧ int256 (evmDiv (evmShl 0x7e N) D) < 2 ^ 128 := by -- shl(126, N) = N·2^126 (fits: N < 2^128 ⇒ N·2^126 < 2^254) have hshl : evmShl 0x7e N = N * 2 ^ 0x7e := by refine evmShl_eq (by norm_num) ?_ @@ -144,30 +145,12 @@ theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD exact (Nat.mul_lt_mul_right hp).mpr hN rw [show (2:Nat) ^ 128 * 2 ^ 0x7e = 2 ^ 254 by rw [← Nat.pow_add]] at this omega - have hNpos' : 0 < N := by exact_mod_cast hNpos - have hShlLt254 : N * 2 ^ 0x7e < 2 ^ 254 := by - have hp : 0 < 2 ^ 0x7e := Nat.two_pow_pos _ - calc N * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := (Nat.mul_lt_mul_right hp).mpr hN - _ = 2 ^ 254 := by rw [← Nat.pow_add] - have hShlLt255 : N * 2 ^ 0x7e < 2 ^ 255 := by - have : (2:Nat) ^ 254 < 2 ^ 255 := by norm_num - omega - have hdivpos : 0 < int256 (evmShl 0x7e N) := by - rw [hshl, int256_of_lt hShlLt255] - have hpos : 0 < N * 2 ^ 0x7e := Nat.mul_pos hNpos' (Nat.two_pow_pos _) - exact_mod_cast hpos - -- both operands positive ⇒ sdiv = floor division - have hshl_lt : evmShl 0x7e N < 2 ^ 256 := evmShl_lt _ _ - rw [evmSdiv_pos_pos hshl_lt hD (le_of_lt hdivpos) (by rw [hDi]; exact hDpos)] - -- the toNat magnitudes - have hshl_nat : evmShl 0x7e N = N * 2 ^ 0x7e := hshl - have hN_toNat : (int256 (evmShl 0x7e N)).toNat = N * 2 ^ 0x7e := by - rw [hshl, int256_of_lt hShlLt255, Int.toNat_natCast] - have hD_toNat : (int256 D).toNat = D := by rw [hDi, Int.toNat_natCast] - rw [hN_toNat, hD_toNat] - set q := N * 2 ^ 0x7e / D with hq have hDnat_pos : 0 < D := by exact_mod_cast hDpos have hNnat_pos : 0 < N := by exact_mod_cast hNpos + -- the quotient is a plain Nat floor division + have hdiv : evmDiv (evmShl 0x7e N) D = N * 2 ^ 0x7e / D := by + rw [evmDiv_eq (evmShl_lt _ _) hD (by omega), hshl] + set q := N * 2 ^ 0x7e / D with hq have hq_lt : q < 2 ^ 128 := by rw [hq] rw [Nat.div_lt_iff_lt_mul hDnat_pos] @@ -189,9 +172,13 @@ theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD have h2 : (2:Nat) ^ 123 * 2 ^ 128 = 2 ^ 125 * 2 ^ 0x7e := by norm_num have h3 : (2:Nat) ^ 125 * 2 ^ 0x7e ≤ N * 2 ^ 0x7e := Nat.mul_le_mul_right _ hNlo omega - exact ⟨by exact_mod_cast hq_ge, by - have : (q : Int) < 2 ^ 128 := by exact_mod_cast hq_lt - simpa using this⟩ + have hqi : int256 (evmDiv (evmShl 0x7e N) D) = (q : Int) := by + rw [hdiv] + exact int256_of_lt (by + have : (2:Nat) ^ 128 < 2 ^ 255 := by norm_num + omega) + rw [hqi] + exact ⟨by exact_mod_cast hq_ge, by exact_mod_cast hq_lt⟩ /-- For a canonical word with nonnegative signed value, the signed value is the Nat value (and the word lies in the lower half). -/ @@ -204,15 +191,15 @@ theorem int256_eq_of_nonneg {w : Nat} (hw : w < 2 ^ 256) (hnn : 0 ≤ int256 w) simp only [ipow256] at this; omega /-- Abstract `r0` bounds: `2^123 ≤ r0 < 2^128` over opaque even/odd words `E`, `TD` with their -bounds. `r0 = sdiv(2^126·(E+TD), E−TD)`; the numerator and denominator are positive and the +bounds. `r0 = div(2^126·(E+TD), E−TD)`; the numerator and denominator are positive and the quotient lands in `[2^123, 2^128)` (the reduced argument keeps `exp(t) ∈ [1/√2, √2)`). -/ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) (hev_lo : (103786963397729689639908782561058906594 : Int) ≤ (E : Int)) (hev_hi : (E : Int) < 2 ^ 127) (htod_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD) (htod_hi : int256 TD < 42535295865117307932921825928971026432) : - 2 ^ 123 ≤ int256 (evmSdiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) ∧ - int256 (evmSdiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) < 2 ^ 128 := by + 2 ^ 123 ≤ int256 (evmDiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) ∧ + int256 (evmDiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) < 2 ^ 128 := by obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos_of hevw htodw hev_lo hev_hi htod_lo htod_hi have hNwlt : evmAdd E TD < 2 ^ 256 := evmAdd_lt _ _ have hDwlt : evmSub E TD < 2 ^ 256 := evmSub_lt _ _ @@ -248,7 +235,7 @@ theorem r0Tree_bounds {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hev_lo, hev_hi⟩ := evTree_facts hvlt obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 have hr0 : r0Tree x = - evmSdiv (evmShl 0x7e (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) := rfl + evmDiv (evmShl 0x7e (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) := rfl rw [hr0] have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean index d34b971e7..78533036f 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -3,15 +3,15 @@ import ExpProof.Mono.Quot /-! # The range and nonnegativity obligations of `RegionMonotonicityFacts` -`r1Tree x = sar(126 − k, WAD·r0 − MARGIN)` closes the kernel: it scales the Q126 quotient onto the -`10¹⁸·2¹²⁶` grid, subtracts the one-sided margin, and floors with the `2ᵏ` octave scaling folded -into the shift (`126 − k ∈ [63, 187]`). +`r1Tree x = shr(108 − k, WAD·r0 − MARGIN)` closes the kernel: it scales the Q126 quotient onto the +`5¹⁸·2¹⁰⁸` grid, subtracts the one-sided margin, and floors with the `2ᵏ` octave scaling and the +wad unit's remaining `2¹⁸` folded into the shift (`108 − k ∈ [45, 169]`). * **nonneg**: `r0 ≥ 2^123` gives `WAD·r0 > MARGIN` (the margin exceeds one wad unit, so `r0 ≥ 1` - alone would not do), and the shift argument is nonnegative; a nonnegative arithmetic shift - stays nonnegative. -* **range**: `r0 < 2^128` gives `WAD·r0 < 2^188`, so even before the shift the argument is below - `2^188`, and the floor is below `2^125 < 2^254`. + alone would not do), and the shift argument is nonnegative; the logical shift of a canonical + nonnegative word stays nonnegative. +* **range**: `r0 < 2^128` gives `WAD·r0 < 2^170`, so even before the shift the argument is below + `2^170`, and the floor is below `2^125 < 2^254`. -/ namespace ExpYul @@ -21,70 +21,70 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-! ## The closing shift amount `126 − k` -/ +/-! ## The closing shift amount `108 − k` -/ -/-- The shift word `evmSub 0x7e k` equals `126 − int256 k` as a `Nat`, and lies in `[63, 187]` on +/-- The shift word `evmSub 0x6c k` equals `108 − int256 k` as a `Nat`, and lies in `[45, 169]` on the meaningful region (`k ∈ [−61, 63]`). -/ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - ∃ s : Nat, evmSub 0x7e (kTree x) = s ∧ 63 ≤ s ∧ s ≤ 187 ∧ - (s : Int) = 126 - int256 (kTree x) := by + ∃ s : Nat, evmSub 0x6c (kTree x) = s ∧ 45 ≤ s ∧ s ≤ 169 ∧ + (s : Int) = 108 - int256 (kTree x) := by obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 have hkw : kTree x < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ - -- 126 (as int) - int256 k, transported through evmSub - have h126 : int256 (0x7e : Nat) = 126 := by + -- 108 (as int) - int256 k, transported through evmSub + have h108 : int256 (0x6c : Nat) = 108 := by rw [int256_of_lt (by norm_num)]; simp have hip255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by norm_num - have hsub : int256 (evmSub 0x7e (kTree x)) = 126 - int256 (kTree x) := by - have := evmSub_transport (a := 0x7e) (b := kTree x) (by norm_num) hkw - (by rw [h126, hip255]; omega) - (by rw [h126, hip255]; omega) - rw [h126] at this; exact this - -- the result is a small nonnegative word, so its Nat value is 126 - int256 k - have hsublt : evmSub 0x7e (kTree x) < 2 ^ 256 := evmSub_lt _ _ - have hnn : 0 ≤ int256 (evmSub 0x7e (kTree x)) := by rw [hsub]; omega + have hsub : int256 (evmSub 0x6c (kTree x)) = 108 - int256 (kTree x) := by + have := evmSub_transport (a := 0x6c) (b := kTree x) (by norm_num) hkw + (by rw [h108, hip255]; omega) + (by rw [h108, hip255]; omega) + rw [h108] at this; exact this + -- the result is a small nonnegative word, so its Nat value is 108 - int256 k + have hsublt : evmSub 0x6c (kTree x) < 2 ^ 256 := evmSub_lt _ _ + have hnn : 0 ≤ int256 (evmSub 0x6c (kTree x)) := by rw [hsub]; omega obtain ⟨heq, hlt255⟩ := int256_eq_of_nonneg hsublt hnn - refine ⟨evmSub 0x7e (kTree x), rfl, ?_, ?_, ?_⟩ - · -- 63 ≤ s - have : (63 : Int) ≤ ((evmSub 0x7e (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega + refine ⟨evmSub 0x6c (kTree x), rfl, ?_, ?_, ?_⟩ + · -- 45 ≤ s + have : (45 : Int) ≤ ((evmSub 0x6c (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega exact_mod_cast this - · have : ((evmSub 0x7e (kTree x) : Nat) : Int) ≤ 187 := by rw [← heq, hsub]; omega + · have : ((evmSub 0x6c (kTree x) : Nat) : Int) ≤ 169 := by rw [← heq, hsub]; omega exact_mod_cast this · rw [← heq]; exact hsub /-! ## The shift argument `WAD·r0 − MARGIN` -/ /-- Abstract bound on the shift argument `WAD·r0 − MARGIN` over an opaque `r0` word in -`[2^123, 2^128)`: its signed value is in `[WAD·2^123 − MARGIN, 2^188)`, in particular nonnegative -and below `2^188`. -/ +`[2^123, 2^128)`: its signed value is in `[WAD·2^123 − MARGIN, 2^170)`, in particular nonnegative +and below `2^170`. -/ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (hr0_lo : (2 ^ 123 : Int) ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 128) : - int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) = - 0xde0b6b3a7640000 * int256 r0 - 0xe17cfd91868d72d ∧ - 0 ≤ 0xde0b6b3a7640000 * int256 r0 - 0xe17cfd91868d72d ∧ - 0xde0b6b3a7640000 * int256 r0 - 0xe17cfd91868d72d < 2 ^ 188 := by - have hwad : int256 (0xde0b6b3a7640000 : Nat) = 0xde0b6b3a7640000 := by + int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) = + 0x3782dace9d9 * int256 r0 - 0x37c9ed9cabf ∧ + 0 ≤ 0x3782dace9d9 * int256 r0 - 0x37c9ed9cabf ∧ + 0x3782dace9d9 * int256 r0 - 0x37c9ed9cabf < 2 ^ 170 := by + have hwad : int256 (0x3782dace9d9 : Nat) = 0x3782dace9d9 := by rw [int256_of_lt (by norm_num)]; simp - have hwadlt : (0xde0b6b3a7640000 : Nat) < 2 ^ 256 := by norm_num + have hwadlt : (0x3782dace9d9 : Nat) < 2 ^ 256 := by norm_num have hp128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num - have hp188 : (2:Int)^188 = 392318858461667547739736838950479151006397215279002157056 := by norm_num - have hwadc : (0xde0b6b3a7640000 : Int) = 1000000000000000000 := by norm_num - have hmarc : (0xe17cfd91868d72d : Int) = 1015508772319713069 := by norm_num + have hp170 : (2:Int)^170 = 1496577676626844588240573268701473812127674924007424 := by norm_num + have hwadc : (0x3782dace9d9 : Int) = 3814697265625 := by norm_num + have hmarc : (0x37c9ed9cabf : Int) = 3833775901375 := by norm_num rw [hp128] at hr0_hi -- the product WAD·r0 transported - have hmul : int256 (evmMul 0xde0b6b3a7640000 r0) = 0xde0b6b3a7640000 * int256 r0 := by + have hmul : int256 (evmMul 0x3782dace9d9 r0) = 0x3782dace9d9 * int256 r0 := by have := evmMul_transport hwadlt hr0w (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) rw [hwad] at this; exact this - have hmullt : evmMul 0xde0b6b3a7640000 r0 < 2 ^ 256 := evmMul_lt _ _ - have hmarlt : (0xe17cfd91868d72d : Nat) < 2 ^ 256 := by norm_num - have hmari : int256 (0xe17cfd91868d72d : Nat) = 0xe17cfd91868d72d := by + have hmullt : evmMul 0x3782dace9d9 r0 < 2 ^ 256 := evmMul_lt _ _ + have hmarlt : (0x37c9ed9cabf : Nat) < 2 ^ 256 := by norm_num + have hmari : int256 (0x37c9ed9cabf : Nat) = 0x37c9ed9cabf := by rw [int256_of_lt (by norm_num)]; simp -- transport the subtraction - have hsub : int256 (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) = - 0xde0b6b3a7640000 * int256 r0 - 0xe17cfd91868d72d := by + have hsub : int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) = + 0x3782dace9d9 * int256 r0 - 0x37c9ed9cabf := by have := evmSub_transport hmullt hmarlt (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) @@ -94,37 +94,34 @@ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) have hp123 : (2:Int)^123 = 10633823966279326983230456482242756608 := by norm_num rw [hp123] at hr0_lo nlinarith [hr0_lo] - · rw [hwadc, hmarc, hp188]; nlinarith [hr0_hi] + · rw [hwadc, hmarc, hp170]; nlinarith [hr0_hi] /-! ## Abstract floor facts for the closing shift -/ -/-- Abstract closing-shift facts over an opaque shift argument word `W` and shift `s ∈ [63, 187]` -with `int256 W ∈ [0, 2^188)`: the floor `sar(s, W)` is nonnegative and below `2^125`. -/ -theorem closingSar_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 63 ≤ s) (hshi : s ≤ 187) - (hWnn : 0 ≤ int256 W) (hWhi : int256 W < 2 ^ 188) : - 0 ≤ int256 (evmSar s W) ∧ int256 (evmSar s W) < 2 ^ 125 := by - obtain ⟨_, hsl, hsh⟩ := evmSar_sandwich (s := s) (by omega) hWw - have hpow : (0 : Int) < 2 ^ s := by positivity - set R := int256 (evmSar s W) with hR - have hnn : 0 ≤ R := by - by_contra hneg - push_neg at hneg - have h2 : (2 : Int) ^ s * (R + 1) ≤ 0 := by - have : (2:Int)^s * (R + 1) ≤ 2^s * 0 := mul_le_mul_left_nonneg (by omega) (le_of_lt hpow) - simpa using this - nlinarith [hWnn, h2, hsh] - refine ⟨hnn, ?_⟩ - have hp63 : (2 : Int) ^ 63 ≤ 2 ^ s := pow_le_pow_right₀ (by norm_num) hslo - by_contra hge - push_neg at hge - have hp188 : (2:Int)^188 = 392318858461667547739736838950479151006397215279002157056 := by norm_num - have hp125 : (2:Int)^125 = 42535295865117307932921825928971026432 := by norm_num - have hp63v : (2:Int)^63 = 9223372036854775808 := by norm_num - have h1 : (2:Int)^63 * 2^125 ≤ 2^63 * R := mul_le_mul_left_nonneg hge (by positivity) - have h2 : (2:Int)^63 * R ≤ 2^s * R := mul_le_mul_right_nonneg hp63 hnn - rw [hp188] at hWhi - rw [hp63v, hp125] at h1 - nlinarith [hsl, hWhi, h1, h2] +/-- Abstract closing-shift facts over an opaque shift argument word `W` and shift `s ∈ [45, 169]` +with `int256 W ∈ [0, 2^170)`: the floor `shr(s, W)` is nonnegative and below `2^125`. -/ +theorem closingShr_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 45 ≤ s) (hshi : s ≤ 169) + (hWnn : 0 ≤ int256 W) (hWhi : int256 W < 2 ^ 170) : + 0 ≤ int256 (evmShr s W) ∧ int256 (evmShr s W) < 2 ^ 125 := by + obtain ⟨hWi, _⟩ := int256_eq_of_nonneg hWw hWnn + have hWnat : W < 2 ^ 170 := by + have : ((W : Nat) : Int) < 2 ^ 170 := by rw [← hWi]; exact hWhi + exact_mod_cast this + rw [evmShr_eq_div (by omega) hWw] + have hqlt : W / 2 ^ s < 2 ^ 125 := by + have h45 : (2:Nat) ^ 45 ≤ 2 ^ s := Nat.pow_le_pow_right (by norm_num) hslo + have h1 : W / 2 ^ s ≤ W / 2 ^ 45 := Nat.div_le_div_left h45 (Nat.two_pow_pos _) + have h2 : W / 2 ^ 45 < 2 ^ 125 := by + rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] + calc W < 2 ^ 170 := hWnat + _ = 2 ^ 125 * 2 ^ 45 := by rw [← Nat.pow_add] + omega + rw [int256_of_lt (by + have : (2:Nat) ^ 125 < 2 ^ 255 := by norm_num + omega)] + constructor + · positivity + · exact_mod_cast hqlt /-! ## The discharged obligations -/ @@ -139,10 +136,10 @@ theorem r1Tree_int256_nonneg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) := rfl + have hr1 : r1Tree x = evmShr (evmSub 0x6c (kTree x)) + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) := rfl rw [hr1, hseq] - exact (closingSar_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) + exact (closingShr_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi)).1 /-- **`range`**: `r1Tree x < 2^254` on the meaningful region. -/ @@ -152,12 +149,12 @@ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmSar (evmSub 0x7e (kTree x)) - (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) := rfl - obtain ⟨hnn, hlt⟩ := closingSar_facts (W := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d) + have hr1 : r1Tree x = evmShr (evmSub 0x6c (kTree x)) + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) := rfl + obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi) -- int256 (r1Tree x) ∈ [0, 2^125) ⇒ the Nat word is < 2^254 - have hReq : int256 (r1Tree x) = int256 (evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x)) 0xe17cfd91868d72d)) := by + have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf)) := by rw [hr1, hseq] rw [← hReq] at hnn hlt have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x diff --git a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean index e1650adef..4be384abc 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean @@ -26,7 +26,7 @@ theorem run_exp_ray_to_wad_evm_eq_expTree unfold Cmask kRoundShift kHalfShift cInvQ200 k27Q235 ln2Q235 tArgShift squareShift unfold ev0 ev1 ev2 ev3 ev4 evShift1 evShift2 evShift3 evShift4 unfold od0 od1 od2 od3 od4 odShift1 odShift2 odShift3 odShift4 - unfold todShift expQShift wadWord marginWord + unfold todShift expQShift foldShift wadWord marginWord rfl end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean index fc986cde4..efc22f403 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -3,17 +3,17 @@ import ExpProof.Mono.RegionMono /-! # The octave-seam step from the `r0` doubling bound -Across a seam (`k` advances by one, `int256 x2 = int256 x1 + 1`) the closing shift `126 − k` drops +Across a seam (`k` advances by one, `int256 x2 = int256 x1 + 1`) the closing shift `108 − k` drops exactly one bit, so with the same shift argument `arg = WAD·r0 − MARGIN` the floor identity ``` r1Tree x2 = ⌊arg2 / 2^(s−1)⌋ = ⌊2·arg2 / 2^s⌋ ≥ ⌊arg1 / 2^s⌋ = r1Tree x1 ⟸ arg1 ≤ 2·arg2 ``` -reduces the seam step to `arg1 ≤ 2·arg2`, which (since `MARGIN < 2·WAD`) follows from the **`r0` +reduces the seam step to `arg1 ≤ 2·arg2`, which (since `MARGIN ≤ 2·WAD`) follows from the **`r0` doubling bound** `r0Tree x1 + 2 ≤ 2·r0Tree x2` (`SeamR0Bound`; the comparison consumes two integer units of the doubling gap because the margin exceeds one wad unit). The reduction is assembled over the -opaque shift-argument words (`seam_close`), so the deep `evmSar`/`evmSub`/`evmMul` tree behind +opaque shift-argument words (`seam_close`), so the deep `evmShr`/`evmSub`/`evmMul` tree behind `r1Tree` is never forced into whnf. -/ @@ -39,35 +39,48 @@ def SeamR0Bound : Prop := int256 x2 = int256 x1 + 1 → int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) -/-- Abstract seam floor reduction over opaque shift-argument words and shift amounts. With the -closing shift dropping one bit (`s2 + 1 = s1`) and `arg1 ≤ 2·arg2`, the two arithmetic-shift floors -are `≤`-ordered: `⌊arg1 / 2^s1⌋ ≤ ⌊arg2 / 2^(s1−1)⌋`. -/ +/-- Abstract seam floor reduction over opaque nonnegative shift-argument words and shift amounts. +With the closing shift dropping one bit (`s2 + 1 = s1`) and `arg1 ≤ 2·arg2`, the two logical-shift +floors are `≤`-ordered: `⌊arg1 / 2^s1⌋ ≤ ⌊arg2 / 2^(s1−1)⌋`. -/ theorem seam_close {arg1 arg2 s1 s2 : Nat} (ha1 : arg1 < 2 ^ 256) (ha2 : arg2 < 2 ^ 256) (hs1 : s1 < 256) (hs2 : s2 < 256) (hseq : s2 + 1 = s1) + (hnn1 : 0 ≤ int256 arg1) (hnn2 : 0 ≤ int256 arg2) (hle : int256 arg1 ≤ 2 * int256 arg2) : - int256 (evmSar s1 arg1) ≤ int256 (evmSar s2 arg2) := by - obtain ⟨_, hsl1, _⟩ := evmSar_sandwich (s := s1) hs1 ha1 - obtain ⟨_, _, hsh2⟩ := evmSar_sandwich (s := s2) hs2 ha2 - have hpow : (2 : Int) ^ s1 = 2 * 2 ^ s2 := by rw [← hseq, pow_succ]; ring - have hp2 : (0 : Int) < 2 ^ s2 := by positivity - set R1 := int256 (evmSar s1 arg1) - set R2 := int256 (evmSar s2 arg2) - -- `2^s1·R1 ≤ arg1 ≤ 2·arg2 < 2·(2^s2·R2 + 2^s2) = 2^s1·R2 + 2^s1` ⇒ `R1 < R2 + 1` ⇒ `R1 ≤ R2`. - rw [hpow] at hsl1 - nlinarith [hsl1, hsh2, hle, hp2] + int256 (evmShr s1 arg1) ≤ int256 (evmShr s2 arg2) := by + obtain ⟨he1, hlt1⟩ := int256_eq_of_nonneg ha1 hnn1 + obtain ⟨he2, hlt2⟩ := int256_eq_of_nonneg ha2 hnn2 + have hleN : arg1 ≤ 2 * arg2 := by + have : ((arg1 : Nat) : Int) ≤ ((2 * arg2 : Nat) : Int) := by + rw [← he1]; push_cast; rw [← he2]; exact hle + exact_mod_cast this + rw [evmShr_eq_div hs1 ha1, evmShr_eq_div hs2 ha2] + -- ⌊arg1 / 2^s1⌋ ≤ ⌊2·arg2 / 2^s1⌋ = ⌊arg2 / 2^s2⌋ + have hkey : 2 * arg2 / 2 ^ s1 = arg2 / 2 ^ s2 := by + rw [← hseq, pow_succ, Nat.mul_comm (2 ^ s2) 2, Nat.mul_div_mul_left arg2 (2 ^ s2) (by norm_num)] + have hqle : arg1 / 2 ^ s1 ≤ arg2 / 2 ^ s2 := by + rw [← hkey] + exact Nat.div_le_div_right hleN + have hq1lt : arg1 / 2 ^ s1 < 2 ^ 255 := by + have := Nat.div_le_self arg1 (2 ^ s1) + omega + have hq2lt : arg2 / 2 ^ s2 < 2 ^ 255 := by + have := Nat.div_le_self arg2 (2 ^ s2) + omega + rw [int256_of_lt hq1lt, int256_of_lt hq2lt] + exact_mod_cast hqle -/-- The closing shifts at a seam differ by one (`s2 = s1 − 1`), both in `[63, 187]`. -/ +/-- The closing shifts at a seam differ by one (`s2 = s1 − 1`), both in `[45, 169]`. -/ theorem seam_closing_shifts {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hx2 : x2 < 2 ^ 256) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) (hk : int256 (kTree x2) = int256 (kTree x1) + 1) : - ∃ s1 s2 : Nat, evmSub 0x7e (kTree x1) = s1 ∧ evmSub 0x7e (kTree x2) = s2 ∧ + ∃ s1 s2 : Nat, evmSub 0x6c (kTree x1) = s1 ∧ evmSub 0x6c (kTree x2) = s2 ∧ s1 < 256 ∧ s2 < 256 ∧ s2 + 1 = s1 := by obtain ⟨s1, hs1eq, _, hs1hi, hs1int⟩ := closing_shift hx1 hC1 hC01 obtain ⟨s2, hs2eq, hs2lo, _, hs2int⟩ := closing_shift hx2 hC2 hC02 refine ⟨s1, s2, hs1eq, hs2eq, by omega, by omega, ?_⟩ - -- `(s2 : Int) + 1 = 126 − k2 + 1 = 126 − k1 = (s1 : Int)` + -- `(s2 : Int) + 1 = 108 − k2 + 1 = 108 − k1 = (s1 : Int)` have : (s2 : Int) + 1 = (s1 : Int) := by rw [hs1int, hs2int, hk]; ring omega @@ -84,26 +97,27 @@ theorem seamStep_of_r0 (hr0 : SeamR0Bound) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (h seam_closing_shifts hx1 hC1 hC01 hx2 hC2 hC02 hk obtain ⟨hr0lo1, hr0hi1⟩ := r0Tree_bounds hx1 hC1 hC01 obtain ⟨hr0lo2, hr0hi2⟩ := r0Tree_bounds hx2 hC2 hC02 - obtain ⟨harg1eq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 - obtain ⟨harg2eq, _, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 + obtain ⟨harg1eq, harg1nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 + obtain ⟨harg2eq, harg2nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 have hr1eq1 : r1Tree x1 = - evmSar s1 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xe17cfd91868d72d) := by + evmShr s1 (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x37c9ed9cabf) := by unfold r1Tree; rw [hs1eq] have hr1eq2 : r1Tree x2 = - evmSar s2 (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xe17cfd91868d72d) := by + evmShr s2 (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x37c9ed9cabf) := by unfold r1Tree; rw [hs2eq] rw [hr1eq1, hr1eq2] -- name the deep shift arguments opaquely before feeding the floor lemma - set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xe17cfd91868d72d with harg1def - set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xe17cfd91868d72d with harg2def + set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x37c9ed9cabf with harg1def + set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x37c9ed9cabf with harg2def have hr0bound : int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) := hr0 hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hargle : int256 arg1 ≤ 2 * int256 arg2 := by - rw [harg1eq, harg2eq, show (0xde0b6b3a7640000 : Int) = 1000000000000000000 by norm_num, - show (0xe17cfd91868d72d : Int) = 1015508772319713069 by norm_num] + rw [harg1eq, harg2eq, show (0x3782dace9d9 : Int) = 3814697265625 by norm_num, + show (0x37c9ed9cabf : Int) = 3833775901375 by norm_num] -- `WAD·r0a − M ≤ 2·(WAD·r0b − M)` ⟸ `WAD·r0a + M ≤ 2·WAD·r0b` ⟸ `r0a ≤ 2·r0b − 2` and `M ≤ 2·WAD` nlinarith [hr0bound] - exact seam_close (harg1def ▸ evmSub_lt _ _) (harg2def ▸ evmSub_lt _ _) hs1lt hs2lt hseq hargle + exact seam_close (harg1def ▸ evmSub_lt _ _) (harg2def ▸ evmSub_lt _ _) hs1lt hs2lt hseq + (by rw [harg1eq]; exact harg1nn) (by rw [harg2eq]; exact harg2nn) hargle /-- The seam step (`SeamStep`) follows from the `r0` doubling bound. -/ theorem seamStep_of_seamR0 (hr0 : SeamR0Bound) : SeamStep := diff --git a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean index aa9869bce..3cb8ef4b3 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean @@ -7,7 +7,7 @@ import ExpProof.Mono.RangeNonneg For two inputs adjacent in the signed order (`int256 x2 = int256 x1 + 1`) in a common octave, the quotient `r0` is nondecreasing (`r0_mono_adjacent`, via the cross inequality `tod_cross` fed to `r0_mono_of_cross`), and hence so is the closing accumulator `r1` (`r1_mono_adjacent`): with `k` -fixed the closing shift `126 − k` is fixed, and the arithmetic-shift floor of the nondecreasing +fixed the closing shift `108 − k` is fixed, and the logical-shift floor of the nondecreasing `WAD·r0 − MARGIN` is nondecreasing. -/ @@ -47,9 +47,9 @@ theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have htodw2 : todTree x2 < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ have hcross := tod_cross hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hr01 : r0Tree x1 = - evmSdiv (evmShl 0x7e (evmAdd (evTree x1) (todTree x1))) (evmSub (evTree x1) (todTree x1)) := rfl + evmDiv (evmShl 0x7e (evmAdd (evTree x1) (todTree x1))) (evmSub (evTree x1) (todTree x1)) := rfl have hr02 : r0Tree x2 = - evmSdiv (evmShl 0x7e (evmAdd (evTree x2) (todTree x2))) (evmSub (evTree x2) (todTree x2)) := rfl + evmDiv (evmShl 0x7e (evmAdd (evTree x2) (todTree x2))) (evmSub (evTree x2) (todTree x2)) := rfl rw [hr01, hr02] exact r0_mono_of_cross hevw1 htodw1 hevw2 htodw2 hev1lo hev1hi htod1lo htod1hi hev2lo hev2hi htod2lo htod2hi hcross @@ -58,7 +58,7 @@ theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) theorem closing_shift_eq {x1 x2 : Nat} (hk : int256 (kTree x1) = int256 (kTree x2)) (hk1 : kTree x1 < 2 ^ 256) (hk2 : kTree x2 < 2 ^ 256) : - evmSub 0x7e (kTree x1) = evmSub 0x7e (kTree x2) := by + evmSub 0x6c (kTree x1) = evmSub 0x6c (kTree x2) := by -- `int256` is injective on canonical words (`[0, 2^256)`), so `k` words coincide. have hinj : ∀ a b : Nat, a < 2 ^ 256 → b < 2 ^ 256 → int256 a = int256 b → a = b := by intro a b ha hb h @@ -72,7 +72,7 @@ theorem closing_shift_eq {x1 x2 : Nat} rw [hinj _ _ hk1 hk2 hk] /-- **Adjacent `r1` monotonicity** within an octave: with `k` fixed, the closing shift is fixed and -the arithmetic-shift floor of the nondecreasing shift argument is nondecreasing. -/ +the logical-shift floor of the nondecreasing shift argument is nondecreasing. -/ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) @@ -90,28 +90,39 @@ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hk2w : kTree x2 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ have hseq := closing_shift_eq hk hk1w hk2w obtain ⟨s, hseqx, hslo, hshi, _⟩ := closing_shift hx1 hC1 hC01 - have hr1eq1 : r1Tree x1 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xe17cfd91868d72d) := by + have hr1eq1 : r1Tree x1 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x37c9ed9cabf) := by unfold r1Tree; rw [hseqx] - have hr1eq2 : r1Tree x2 = evmSar s (evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xe17cfd91868d72d) := by + have hr1eq2 : r1Tree x2 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x37c9ed9cabf) := by unfold r1Tree; rw [← hseq, hseqx] rw [hr1eq1, hr1eq2] -- the two shift arguments, transported to `Int`, are ordered (monotone `r0`) - set arg1 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x1)) 0xe17cfd91868d72d with harg1 - set arg2 := evmSub (evmMul 0xde0b6b3a7640000 (r0Tree x2)) 0xe17cfd91868d72d with harg2 + set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x37c9ed9cabf with harg1 + set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x37c9ed9cabf with harg2 have hargle : int256 arg1 ≤ int256 arg2 := by rw [harg1eq, harg2eq] - have hwad : (0 : Int) ≤ 0xde0b6b3a7640000 := by norm_num + have hwad : (0 : Int) ≤ 0x3782dace9d9 := by norm_num have := mul_le_mul_left_nonneg hr0mono hwad omega - -- `evmSar s` is monotone in the signed value (the floor of the same shift) + -- the shift arguments are nonnegative canonical words, ordered as Nats have ha1lt : arg1 < 2 ^ 256 := by rw [harg1]; exact evmSub_lt _ _ have ha2lt : arg2 < 2 ^ 256 := by rw [harg2]; exact evmSub_lt _ _ - obtain ⟨_, hsl1, hsh1⟩ := evmSar_sandwich (s := s) (by omega) ha1lt - obtain ⟨_, hsl2, hsh2⟩ := evmSar_sandwich (s := s) (by omega) ha2lt - have hpow : (0 : Int) < 2 ^ s := by positivity - set R1 := int256 (evmSar s arg1) - set R2 := int256 (evmSar s arg2) - -- `2^s·R1 ≤ arg1 ≤ arg2 < 2^s·R2 + 2^s ⇒ R1 < R2 + 1 ⇒ R1 ≤ R2` - nlinarith [hsl1, hsh2, hargle, hpow] + obtain ⟨he1, hlt1⟩ := int256_eq_of_nonneg ha1lt (by rw [harg1eq]; exact harg1nn) + obtain ⟨he2, hlt2⟩ := int256_eq_of_nonneg ha2lt (by rw [harg2eq]; exact harg2nn) + -- the deep tree behind the shift arguments is opaque from here on + clear_value arg1 arg2 + have hargleN : arg1 ≤ arg2 := by + have : ((arg1 : Nat) : Int) ≤ ((arg2 : Nat) : Int) := by rw [← he1, ← he2]; exact hargle + exact_mod_cast this + -- `evmShr s` is the same-shift Nat floor: monotone + rw [evmShr_eq_div (by omega) ha1lt, evmShr_eq_div (by omega) ha2lt] + have hqle : arg1 / 2 ^ s ≤ arg2 / 2 ^ s := Nat.div_le_div_right hargleN + have hq1lt : arg1 / 2 ^ s < 2 ^ 255 := by + have h1 : arg1 / 2 ^ s ≤ arg1 := Nat.div_le_self _ _ + omega + have hq2lt : arg2 / 2 ^ s < 2 ^ 255 := by + have h1 : arg2 / 2 ^ s ≤ arg2 := Nat.div_le_self _ _ + omega + rw [int256_of_lt hq1lt, int256_of_lt hq2lt] + exact_mod_cast hqle end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean index 41d89418a..6b07f7937 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -49,11 +49,11 @@ def todTree (x : Nat) : Nat := evmSar todShift (evmMul (tTree x) (odTree x)) /-- `exp(t)` in Q126. -/ def r0Tree (x : Nat) : Nat := - evmSdiv (evmShl expQShift (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) + evmDiv (evmShl expQShift (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) -/-- The floored, octave-scaled, margin-subtracted accumulator. -/ +/-- The floored, octave-scaled, margin-subtracted accumulator on the `5¹⁸·2¹⁰⁸` grid. -/ def r1Tree (x : Nat) : Nat := - evmSar (evmSub expQShift (kTree x)) (evmSub (evmMul wadWord (r0Tree x)) marginWord) + evmShr (evmSub foldShift (kTree x)) (evmSub (evmMul wadWord (r0Tree x)) marginWord) /-- The clamp/pin shell wrapped around `r1Tree`. -/ def expTree (x : Nat) : Nat := @@ -61,11 +61,11 @@ def expTree (x : Nat) : Nat := theorem r0Tree_lt (x : Nat) : r0Tree x < 2 ^ 256 := by unfold r0Tree - exact evmSdiv_lt _ _ + exact evmDiv_lt _ _ theorem r1Tree_lt (x : Nat) : r1Tree x < 2 ^ 256 := by unfold r1Tree - exact evmSar_lt _ _ + exact evmShr_lt _ _ theorem expTree_lt (x : Nat) : expTree x < 2 ^ 256 := by unfold expTree diff --git a/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean b/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean index 3dfec4d47..c42065e1f 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean @@ -9,8 +9,7 @@ argument needs that the shared `FormalYul.Preservation` does not already provide * general floor sandwiches for `evmSar`/`evmShr` (the arithmetic/logical right shifts), at an arbitrary shift amount, expressed against the signed value; -* the `evmSdiv` sign-pinned transports (one per sign pattern, quotients over `Int.toNat` - magnitudes); +* the in-range `evmDiv`/`evmShr`/`evmShl` evaluations (plain `Nat` division/shift/multiply); * cross-multiplied monotonicity of truncated division; * small `Int` multiplication-monotonicity helpers. @@ -101,13 +100,41 @@ theorem evmSar_lt (s w : Nat) : evmSar s w < 2 ^ 256 := by · exact pow256_pos · exact hdiv -theorem evmSdiv_lt (a b : Nat) : evmSdiv a b < 2 ^ 256 := by - unfold evmSdiv u256 +theorem evmDiv_lt (a b : Nat) : evmDiv a b < 2 ^ 256 := by + unfold evmDiv u256 simp only [word_mod_eq] have ha : a % 2 ^ 256 < 2 ^ 256 := Nat.mod_lt _ pow256_pos - have hb : b % 2 ^ 256 < 2 ^ 256 := Nat.mod_lt _ pow256_pos - repeat' split - all_goals (first | exact Nat.mod_lt _ pow256_pos | omega) + split + · exact pow256_pos + · exact Nat.lt_of_le_of_lt (Nat.div_le_self _ _) ha + +/-- `evmDiv` on canonical words with a nonzero divisor is plain `Nat` floor division. -/ +theorem evmDiv_eq {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) (hb0 : b ≠ 0) : + evmDiv a b = a / b := by + unfold evmDiv u256 + simp only [word_mod_eq, Nat.mod_eq_of_lt ha, Nat.mod_eq_of_lt hb] + rw [if_neg hb0] + +/-- `evmDiv` against the signed view, for a nonnegative dividend and positive divisor: the signed +quotient is the `Nat` floor division of the `Int.toNat` magnitudes. -/ +theorem evmDiv_pos_pos {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) + (h1 : 0 ≤ int256 a) (h2 : 0 < int256 b) : + int256 (evmDiv a b) = (((int256 a).toNat / (int256 b).toNat : Nat) : Int) := by + have hb0 : ¬ b = 0 := by + unfold int256 at h2; split at h2 <;> omega + have hna : ¬ 2 ^ 255 ≤ a := by + unfold int256 at h1; simp only [ipow256] at *; split at h1 <;> omega + have hnb : ¬ 2 ^ 255 ≤ b := by + unfold int256 at h2; simp only [ipow256] at *; split at h2 <;> omega + have ea : (int256 a).toNat = a := by + unfold int256; simp only [ipow256] at *; split <;> omega + have eb : (int256 b).toNat = b := by + unfold int256; simp only [ipow256] at *; split <;> omega + rw [evmDiv_eq ha hb hb0, ea, eb] + have hq : a / b < 2 ^ 255 := by + have := Nat.div_le_self a b + omega + rw [int256_of_lt hq] /-! ## Re-export of the `add`/`sub`/`mul` transports under short names -/ @@ -150,8 +177,7 @@ theorem evmShl_eq {s : Nat} (hs : s < 256) {w : Nat} (h : w * 2 ^ s < 2 ^ 256) : /-- `evmSar s w` is the signed floor of `int256 w / 2^s` for a shift `s < 256`: `2^s · int256 (evmSar s w) ≤ int256 w < 2^s · int256 (evmSar s w) + 2^s`, and the result is a -valid word. This is the single fact the floor step needs (`s = 126 - k` is a runtime value, and -`126 - k ∈ [63, 127]` over the supported octaves). -/ +valid word. The reduced-argument and `t·Od` shifts are the remaining arithmetic-shift sites. -/ theorem evmSar_sandwich {s : Nat} (hs : s < 256) {w : Nat} (h : w < 2 ^ 256) : evmSar s w < 2 ^ 256 ∧ (2 ^ s : Int) * int256 (evmSar s w) ≤ int256 w ∧ @@ -228,112 +254,6 @@ theorem evmSar_sandwich {s : Nat} (hs : s < 256) {w : Nat} (h : w < 2 ^ 256) : have hh : w < 2 ^ s * q + 2 ^ s := by rw [hq, Nat.mul_comm]; exact hfloor2 exact_mod_cast hh -/-! ## `evmSdiv` sign-pinned transports -/ - -theorem toInt_u256_of_small {q : Nat} (h : q < 2 ^ 255) : int256 (u256 q) = (q : Int) := by - unfold int256 u256 - simp only [word_mod_eq, ipow256] at * - split <;> omega - -theorem toInt_u256_neg {q : Nat} (h : q ≤ 2 ^ 255) : - int256 (u256 (WORD_MOD - q)) = -(q : Int) := by - unfold int256 u256 - simp only [word_mod_eq, ipow256] at * - split <;> omega - -theorem evmSdiv_pos_pos {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) - (h1 : 0 ≤ int256 a) (h2 : 0 < int256 b) : - int256 (evmSdiv a b) = (((int256 a).toNat / (int256 b).toNat : Nat) : Int) := by - have hna : ¬ 2 ^ 255 ≤ a := by - unfold int256 at h1; simp only [ipow256] at *; split at h1 <;> omega - have hnb : ¬ 2 ^ 255 ≤ b := by - unfold int256 at h2; simp only [ipow256] at *; split at h2 <;> omega - have hb0 : ¬ b = 0 := by - unfold int256 at h2; split at h2 <;> omega - have ea : (int256 a).toNat = a := by - unfold int256; simp only [ipow256] at *; split <;> omega - have eb : (int256 b).toNat = b := by - unfold int256; simp only [ipow256] at *; split <;> omega - unfold evmSdiv - simp only [u256_of_lt ha, u256_of_lt hb, decide_eq_false hna, decide_eq_false hnb, - Bool.false_eq_true, if_true, if_false, if_neg hb0, ea, eb] - have hq : a / b < 2 ^ 255 := by - have := Nat.div_le_self a b - omega - rw [toInt_u256_of_small hq] - -theorem evmSdiv_neg_pos {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) - (h1 : int256 a < 0) (hmin : -(2 ^ 255) < int256 a) (h2 : 0 < int256 b) : - int256 (evmSdiv a b) = -(((- int256 a).toNat / (int256 b).toNat : Nat) : Int) := by - have hna : 2 ^ 255 ≤ a := by - unfold int256 at h1; simp only [ipow255, ipow256] at *; split at h1 <;> omega - have hnb : ¬ 2 ^ 255 ≤ b := by - unfold int256 at h2; simp only [ipow255, ipow256] at *; split at h2 <;> omega - have hb0 : ¬ b = 0 := by - unfold int256 at h2; split at h2 <;> omega - have ea : (- int256 a).toNat = WORD_MOD - a := by - unfold int256; simp only [word_mod_eq, ipow255, ipow256] at *; split <;> omega - have eb : (int256 b).toNat = b := by - unfold int256; simp only [ipow255, ipow256] at *; split <;> omega - unfold evmSdiv - simp only [u256_of_lt ha, u256_of_lt hb, decide_eq_true hna, decide_eq_false hnb, - Bool.false_eq_true, Bool.true_eq_false, if_true, if_false, if_neg hb0, ea, eb] - have hq : (WORD_MOD - a) / b ≤ 2 ^ 255 := by - have h3 : WORD_MOD - a ≤ 2 ^ 255 := by - unfold int256 at hmin; simp only [word_mod_eq, ipow255, ipow256] at * - split at hmin <;> omega - have := Nat.div_le_self (WORD_MOD - a) b - omega - rw [toInt_u256_neg hq] - -theorem evmSdiv_pos_neg {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) - (h1 : 0 ≤ int256 a) (h2 : int256 b < 0) : - int256 (evmSdiv a b) = -(((int256 a).toNat / (- int256 b).toNat : Nat) : Int) := by - have hna : ¬ 2 ^ 255 ≤ a := by - unfold int256 at h1; simp only [ipow256] at *; split at h1 <;> omega - have hnb : 2 ^ 255 ≤ b := by - unfold int256 at h2; simp only [ipow256] at *; split at h2 <;> omega - have hb0 : ¬ b = 0 := by - intro h; subst h; simp only [] at hnb; omega - have ea : (int256 a).toNat = a := by - unfold int256; simp only [ipow256] at *; split <;> omega - have eb : (- int256 b).toNat = WORD_MOD - b := by - unfold int256; simp only [word_mod_eq, ipow256] at *; split <;> omega - unfold evmSdiv - simp only [u256_of_lt ha, u256_of_lt hb, decide_eq_false hna, decide_eq_true hnb, - Bool.false_eq_true, if_true, if_false, if_neg hb0, ea, eb] - have hq : a / (WORD_MOD - b) ≤ 2 ^ 255 := by - have h3 : a < 2 ^ 255 := by - unfold int256 at h1; simp only [ipow256] at *; split at h1 <;> omega - have := Nat.div_le_self a (WORD_MOD - b) - omega - rw [toInt_u256_neg hq] - -theorem evmSdiv_neg_neg {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) - (h1 : int256 a < 0) (hmin : -(2 ^ 255) < int256 a) (h2 : int256 b < 0) : - int256 (evmSdiv a b) = (((- int256 a).toNat / (- int256 b).toNat : Nat) : Int) := by - have hna : 2 ^ 255 ≤ a := by - unfold int256 at h1; simp only [ipow255, ipow256] at *; split at h1 <;> omega - have hnb : 2 ^ 255 ≤ b := by - unfold int256 at h2; simp only [ipow255, ipow256] at *; split at h2 <;> omega - have hb0 : ¬ b = 0 := by - intro h; subst h; simp only [] at hnb; omega - have ea : (- int256 a).toNat = WORD_MOD - a := by - unfold int256; simp only [word_mod_eq, ipow255, ipow256] at *; split <;> omega - have eb : (- int256 b).toNat = WORD_MOD - b := by - unfold int256; simp only [word_mod_eq, ipow255, ipow256] at *; split <;> omega - unfold evmSdiv - simp only [u256_of_lt ha, u256_of_lt hb, decide_eq_true hna, decide_eq_true hnb, - if_true, if_neg hb0, ea, eb] - have hq : (WORD_MOD - a) / (WORD_MOD - b) < 2 ^ 255 := by - have h3 : WORD_MOD - a ≤ 2 ^ 255 := by - unfold int256 at hmin; simp only [word_mod_eq, ipow255, ipow256] at * - split at hmin <;> omega - have := Nat.div_le_self (WORD_MOD - a) (WORD_MOD - b) - simp only [word_mod_eq, ipow255] at * - omega - rw [toInt_u256_of_small hq] - /-! ## Cross-multiplied monotonicity of `Nat` division -/ theorem nat_div_cross_mono {a b c d : Nat} (hb : 0 < b) (hd : 0 < d) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 49ee62125..8fd124eab 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -429,8 +429,8 @@ theorem call_fun__expRayToWad_80_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) - let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) + let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -456,14 +456,14 @@ theorem call_fun__expRayToWad_80_direct simp only [FormalYul.Preservation.wordNat_shiftRight, FormalYul.Preservation.wordNat_shiftLeft, FormalYul.Preservation.wordNat_add, FormalYul.Preservation.wordNat_sub, FormalYul.Preservation.wordNat_mul, FormalYul.Preservation.wordNat_iszero, - FormalYul.Preservation.wordNat_ofNat, wordNat_sar, wordNat_sdiv, wordNat_slt] + FormalYul.Preservation.wordNat_ofNat, wordNat_sar, wordNat_div, wordNat_slt] simp only [FormalYul.Preservation.evmAdd_u256_left, FormalYul.Preservation.evmAdd_u256_right, FormalYul.Preservation.evmSub_u256_left, FormalYul.Preservation.evmSub_u256_right, FormalYul.Preservation.evmMul_u256_left, FormalYul.Preservation.evmMul_u256_right, FormalYul.Preservation.evmShl_u256_left, FormalYul.Preservation.evmShl_u256_right, FormalYul.Preservation.evmShr_u256_left, FormalYul.Preservation.evmShr_u256_right, FormalYul.Preservation.evmIszero_u256, evmSar_u256_left, evmSar_u256_right, - evmSdiv_u256_left, evmSdiv_u256_right, evmSlt_u256_left, evmSlt_u256_right, + evmDiv_u256_left, evmDiv_u256_right, evmSlt_u256_left, evmSlt_u256_right, u256_idem, FormalYul.Preservation.u256_evmAdd] set_option maxHeartbeats 4000000 in @@ -493,8 +493,8 @@ theorem call_fun_expRayToWad_70_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) - let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) + let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -555,8 +555,8 @@ theorem call_fun_wrap_expRayToWad_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) - let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) + let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -616,8 +616,8 @@ theorem external_fun_wrap_expRayToWad_calldata_result (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) - let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) + let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -645,8 +645,8 @@ theorem external_fun_wrap_expRayToWad_calldata_result (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) - let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) + let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -746,8 +746,8 @@ theorem external_fun_wrap_expRayToWad_calldata_halts (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) - let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) + let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -852,8 +852,8 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) - let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) + let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -931,8 +931,8 @@ theorem run_exp_ray_to_wad_evm_eq_tree (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x80 (evmMul t od) - let r0 := evmSdiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmSar (evmSub 0x7e k) (evmSub (evmMul 0xde0b6b3a7640000 r0) 0xe17cfd91868d72d) + let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index a252c7285..3e1dc6a64 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -97,7 +97,7 @@ Each bracket is stated on the runtime result `r` (`run_exp_ray_to_wad_evm x = .o target `E = 10¹⁸·exp(x/10²⁷)`. The pre-floor accumulator brackets `E` unconditionally (`accumReal_over`/`accumReal_under`: the cert `Floor.CapsV` against the exact rational `ê = NUM/DEN`, folded with the octave `2^k`, plus the argument-granularity, reduced-argument and -Horner-`sdiv` truncation envelopes the `MARGIN` absorbs), and below the clamp the target satisfies +Horner-`div` truncation envelopes the `MARGIN` absorbs), and below the clamp the target satisfies `E < 1` (`belowC_target_lt_one`), so the global brackets hold with no analytic hypothesis. -/ diff --git a/formal/exp/ExpProof/GenExpVLit.lean b/formal/exp/ExpProof/GenExpVLit.lean index 366832170..44bbb905e 100644 --- a/formal/exp/ExpProof/GenExpVLit.lean +++ b/formal/exp/ExpProof/GenExpVLit.lean @@ -110,16 +110,57 @@ def denM1EqTac : String := /-- Tactic block proving `certDOver = certDOverLit`. -/ def dOverEqTac : String := - " unfold certDOver evVPoly odVPoly\n decide +kernel" - -/-- Tactic block proving `certDUnder = certDUnderLit`. -/ -def dUnderEqTac : String := - " unfold certDUnder evVPoly odVPoly\n decide +kernel" + " unfold certDOver certDOverP evVPoly odVPoly\n decide +kernel" + +/-- Tactic block proving `certDOverP T D = certDOvPLit`. -/ +def dOverPEqTac : String := + " unfold certDOverP evVPoly odVPoly\n decide +kernel" + +/-- Tactic block proving `certDUnderP T D = certDUnPLit`. -/ +def dUnderPEqTac : String := + " unfold certDUnderP evVPoly odVPoly\n decide +kernel" + +/-- The 32 granularity pieces: `(vlo, vhi, T, DOver, DUnder)` — the `v`-range, the piece `t`-cap +(`T² ≥ (vhi+1)·2^133`), and the floored denominators for the two halves. Each piece's floors are +certified over `[vlo, vhi + 1]` (the granularity step looks one cell ahead). -/ +def granPieces : List (Int × Int × Int × Int × Int) := [ + (0, 39914474797457073157829141722193111, 20847785078312632088902884100098393904, 650161701553, 691253358954), + (39914474797457073157829141722193111, 79828949594914146315658283444386223, 29483220403189161767243017845519310570, 641945658278, 700065691212), + (79828949594914146315658283444386223, 119743424392371219473487425166579335, 36109422980913784159270707268699614620, 635708060030, 706899646710), + (119743424392371219473487425166579335, 159657899189828292631316566888772447, 41695570156625264177805768200196787807, 630494171758, 712709960499), + (159657899189828292631316566888772447, 199572373987285365789145708610965559, 46617064615412821983671927489259435287, 625934238048, 717866387998), + (199572373987285365789145708610965559, 239486848784742438946974850333158671, 51066435709074987640046250875008841866, 621838651900, 722558536211), + (239486848784742438946974850333158671, 279401323582199512104803992055351783, 55158054703738454765934460694358669515, 618094793288, 726899025166), + (279401323582199512104803992055351783, 319315798379656585262633133777544895, 58966440806378323534486035691038621139, 614629293866, 730961223213), + (319315798379656585262633133777544895, 359230273177113658420462275499738007, 62543355234937896266708652300295181711, 611391198603, 734796085384), + (359230273177113658420462275499738007, 399144747974570731578291417221931119, 65926485017139723075679505829736200590, 608343412382, 738440706802), + (399144747974570731578291417221931119, 439059222772027804736120558944124231, 69144280814733066627417644920644591155, 605457935097, 741923087576), + (439059222772027804736120558944124231, 478973697569484877893949700666317343, 72218845961827568318541414537399229239, 602713016329, 745264978126), + (478973697569484877893949700666317343, 518888172366941951051778842388510455, 75167758079709234538337434275175078691, 600091361400, 748483673135), + (518888172366941951051778842388510455, 558802647164399024209607984110703567, 78005269036144011942405564982788931618, 597578949702, 751593193213), + (558802647164399024209607984110703567, 598717121961856097367437125832896679, 80743124413616312505576435261721815008, 595164227770, 754605091830), + (598717121961856097367437125832896679, 638631596759313170525266267555089791, 83391140313250528355611536400393575614, 592837541332, 757529023260), + (638631596759313170525266267555089791, 678546071556770243683095409277282902, 85957619938058733268340145980060814334, 590590725148, 760373152745), + (678546071556770243683095409277282902, 718460546354227316840924550999476014, 88449661209567485301729053536557931646, 588416800156, 763144459353), + (718460546354227316840924550999476014, 758375021151684389998753692721669126, 90873388353019950250431101958484117810, 586309745473, 765848963968), + (758375021151684389998753692721669126, 798289495949141463156582834443862238, 93234129230825643967343854978518870515, 584264323835, 768491903858), + (798289495949141463156582834443862238, 838203970746598536314411976166055350, 95536553193538501370371342040089081115, 582275945893, 771077868376), + (838203970746598536314411976166055350, 878118445544055609472241117888248462, 97784779688729301059274137358180034302, 580340563312, 773610905858), + (878118445544055609472241117888248462, 918032920341512682630070259610441574, 99982464869820254414073625773477941119, 578454583528, 776094608873), + (918032920341512682630070259610441574, 957947395138969755787899401332634686, 102132871418149975280092501750017683679, 576614801025, 778532182941), + (957947395138969755787899401332634686, 997861869936426828945728543054827798, 104238925391563160444514420500491969466, 574818341390, 780926502475), + (997861869936426828945728543054827798, 1037776344733883902103557684777020910, 106303262929504594869818257246985820007, 573062615355, 783280156749), + (1037776344733883902103557684777020910, 1077690819531340975261386826499214022, 108328268942741352477812121806098843808, 571345280717, 785595487968), + (1077690819531340975261386826499214022, 1117605294328798048419215968221407134, 110316109407476909531868921388717338981, 569664210570, 787874623042), + (1117605294328798048419215968221407134, 1157519769126255121577045109943600246, 112268758510433036404380164835338032221, 568017466591, 790119500297), + (1157519769126255121577045109943600246, 1197434243923712194734874251665793358, 114188021614114346553315397742450038434, 566403276447, 792331892069), + (1197434243923712194734874251665793358, 1237348718721169267892703393387986470, 116075554802968570681645777137735089747, 564820014566, 794513423933), + (1237348718721169267892703393387986470, 1277263193518626341050532535110179582, 117932881612756647068972071382077242231, 563266185678, 796665591163)] #eval do let cUp := ptrim certExpUp let cLo := ptrim certExpLo - IO.FS.writeFile "ExpProof/Cert/ExpVCertLit.lean" + let mut lits := ("/-! Generated v-form cut-certificate literal coefficient lists. -/\n\nnamespace ExpCertV\n\n" ++ litText "numExpVLit" (ptrim numExpV) ++ litText "denExpVLit" (ptrim denExpV) ++ @@ -132,9 +173,12 @@ def dUnderEqTac : String := litText "certDenM1Lit" (ptrim certDenM1) ++ litText "certExpUpLit" cUp ++ litText "certExpLoLit" cLo ++ - litText "certDOverLit" (ptrim certDOver) ++ - litText "certDUnderLit" (ptrim certDUnder) ++ - "end ExpCertV\n") + litText "certDOverLit" (ptrim certDOver)) + for (p, i) in granPieces.zipIdx do + let (_, _, t, dO, dU) := p + lits := lits ++ litText s!"certDOvP{pad2 i}Lit" (ptrim (certDOverP t dO)) + lits := lits ++ litText s!"certDUnP{pad2 i}Lit" (ptrim (certDUnderP t dU)) + IO.FS.writeFile "ExpProof/Cert/ExpVCertLit.lean" (lits ++ "end ExpCertV\n") IO.println "v-form literals written" emit "certExpUpLit" "ExpVUp" "ExpVUpC" "expVUp_cell" "certExpUp_eq" "expVUpLit_nonneg" "expVUp_nonneg" "certExpUp" upEqTac cUp 0 (H128 : Int) @@ -146,5 +190,11 @@ def dUnderEqTac : String := "denM1V_nonneg" "certDenM1" denM1EqTac (ptrim certDenM1) 0 (H128 : Int) emit "certDOverLit" "ExpVDOver" "ExpVDOverC" "expVDOver_cell" "certDOver_eq" "dOverVLit_nonneg" "dOverV_nonneg" "certDOver" dOverEqTac (ptrim certDOver) 0 ((vmaxV : Int) + 1) - emit "certDUnderLit" "ExpVDUnder" "ExpVDUnderC" "expVDUnder_cell" "certDUnder_eq" "dUnderVLit_nonneg" - "dUnderV_nonneg" "certDUnder" dUnderEqTac (ptrim certDUnder) 0 ((vmaxV : Int) + 1) + for (p, i) in granPieces.zipIdx do + let (vlo, vhi, t, dO, dU) := p + emit s!"certDOvP{pad2 i}Lit" s!"ExpVDOvP{pad2 i}" s!"ExpVDOvP{pad2 i}C" s!"dOvP{pad2 i}_cell" + s!"certDOvP{pad2 i}_eq" s!"dOvP{pad2 i}Lit_nonneg" s!"dOvP{pad2 i}_nonneg" + s!"(certDOverP {t} {dO})" dOverPEqTac (ptrim (certDOverP t dO)) vlo (vhi + 1) + emit s!"certDUnP{pad2 i}Lit" s!"ExpVDUnP{pad2 i}" s!"ExpVDUnP{pad2 i}C" s!"dUnP{pad2 i}_cell" + s!"certDUnP{pad2 i}_eq" s!"dUnP{pad2 i}Lit_nonneg" s!"dUnP{pad2 i}_nonneg" + s!"(certDUnderP {t} {dU})" dUnderPEqTac (ptrim (certDUnderP t dU)) vlo (vhi + 1) diff --git a/formal/yul/YulImporter.lean b/formal/yul/YulImporter.lean index 75b817dd1..baa218d5d 100644 --- a/formal/yul/YulImporter.lean +++ b/formal/yul/YulImporter.lean @@ -76,7 +76,7 @@ def requiredCalls : ModelKind → List String | .cbrt => ["clz"] | .cbrt512 => ["clz", "mulmod"] | .ln => ["clz", "sdiv"] - | .exp => ["sdiv"] + | .exp => ["div"] end ModelKind From 1cbda8f2c9007cac02019f6617e1ca578d0d844c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 17:22:45 +0200 Subject: [PATCH 125/149] Cleanup --- src/vendor/Exp.sol | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index d15d31179..721cfd1f3 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -45,17 +45,13 @@ library Exp { // its chosen byte width. A coefficient followed by more multiplies by v tolerates a shorter // basis. Each renormalizing shift lands a value directly at the basis its consumer needs. // t: Q128 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2) - // v = t²: Q123 the widest basis whose monic-stage product stays inside 256 bits, so // Ev(v)'s leading stage consumes v with no renormalizing shift - // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q87 (monic) - // Od(v) Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q87 // Ev, Od, t⋅Od, and the numerator/denominator: Q87 // quotient: one `DIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays // below 2²⁵⁵) - // output: multiplying by 5¹⁸ lands E on the 2¹⁰⁸ output grid (the 10¹⁸⋅2¹²⁶ grid with // the wad unit's 2¹⁸ pre-folded); the closing `shr(108 - k, …)` is the single // output-rounding floor, with 2ᵏ folded in @@ -65,28 +61,22 @@ library Exp { // tightest bound the proof technique can bear, in spite of the fact that the worst-case // error contributions do not co-occur. The budget bounds Δ ≤ 1.0050013498897899168, the sum // of three one-sided contributions: - // integer Horner + closing `DIV` truncation: the Ev shared by the numerator Ev + t⋅Od // and denominator Ev - t⋅Od cancels to first order in the quotient, so its // truncation barely perturbs e; this jitter stays < 0.62071. - // argument granularity: v carries t² on the Q123 grid, and its floor only lowers the // polynomials' shared argument (by < 2⁻¹²³), which lifts e on the t > 0 half by < // 0.32906: one v-grain moves the quotient by 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose - // one-signed numerator maximal at each - // piece's upper edge and whose denominator is floored piecewise over 32 domain - // pieces (the pointwise supremum is ≈ 0.3287 at t = ln2/2). The t < 0 - // direction is budgeted on the under side. - + // one-signed numerator maximal at each piece's upper edge and whose denominator is + // floored piecewise over 32 domain pieces (the pointwise supremum is ≈ 0.3287 at t + // = ln2/2). The t < 0 direction is budgeted on the under side. // rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): // < 0.04420 (its supremum is √2⋅2¹²⁶/(2¹³¹-1)). - // reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is // budgeted on the under side); the over side is the K27/LN2 constant-grid residue // (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = // √2/128). - // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1090 ulp (1 ulp = 10⁻¹⁸ of the result).The margin is the least integer // on the 2¹⁰⁸ output grid strictly above Δ's image: 0x37c9ed9cabf = ⌊5¹⁸⋅Δ⌋ + 1 = From e1b5dcadd181e4b3db1db5a65b5c721116a9a3ca Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 17:27:14 +0200 Subject: [PATCH 126/149] Notation --- src/vendor/Exp.sol | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 721cfd1f3..177a29606 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -14,7 +14,7 @@ library Exp { /// returns w. Reverts with `Panic(17)` when x is large enough to leave the supported range /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256 r) { - // At this input the octave count k = round(x / (10²⁷⋅ln2)) reaches 64. The error in + // At this input the octave count k = round(x / (10²⁷⋅ln(2))) reaches 64. The error in // `_expRayToWad` exceeds 1ulp at that scale. if (x >= 0x8e383a2cdfa1b74a9422d2e1) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); @@ -25,8 +25,8 @@ library Exp { /// @dev The rational polynomial approximation kernel function _expRayToWad(int256 x) private pure returns (int256 r) { // Equivalent pseudocode; fixed-point truncations are accounted for below: - // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln2 + t)⋅10²⁷, |t| ≤ ln2/2 - // t = x/10²⁷ - k⋅ln2; // reduced argument (Q128) + // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln(2) + t)⋅10²⁷, |t| ≤ ln(2)/2 + // t = x/10²⁷ - k⋅ln(2); // reduced argument (Q128) // e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) (Ev Q87; Od Q87; e Q126) // r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; // wad // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 @@ -69,12 +69,12 @@ library Exp { // 0.32906: one v-grain moves the quotient by 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose // one-signed numerator maximal at each piece's upper edge and whose denominator is // floored piecewise over 32 domain pieces (the pointwise supremum is ≈ 0.3287 at t - // = ln2/2). The t < 0 direction is budgeted on the under side. + // = ln(2)/2). The t < 0 direction is budgeted on the under side. // rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): // < 0.04420 (its supremum is √2⋅2¹²⁶/(2¹³¹-1)). // reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is // budgeted on the under side); the over side is the K27/LN2 constant-grid residue - // (the k⋅ln2 grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly + // (the k⋅ln(2) grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = // √2/128). // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at @@ -92,7 +92,7 @@ library Exp { // deficit envelope ((67/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave, so at k = 64 it // exceeds 1ulp. On the central octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 1.2⋅10⁻²⁰ ulp, far // below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. The k = 0 - // band is exactly [-H, H] with H = ⌊10²⁷⋅ln2/2⌋, matching `lnWadToRay`'s image over [1/√2, + // band is exactly [-H, H] with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, // √2). // // Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves the @@ -110,9 +110,10 @@ library Exp { // and `sar(200, …)` round to nearest with ties resolved toward +∞. let k := sar(0xc8, add(shl(0xc7, 0x01), mul(0x724d54edbacbebbb95c52a0f6076, x))) - // t in Q128. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln(2) ⋅ 2²³⁵). Subtracting k ⋅ LN2 - // from K27 ⋅ x at the Q235 product basis (so the k ⋅ ln2 rounding error is ~2⁻²³⁵, far - // below an output ulp) then one `sar(107, …)` leaves the reduced argument at Q128. + // t in Q128. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln(2) ⋅ 2²³⁵). Subtracting k ⋅ + // LN2 from K27 ⋅ x at the Q235 product basis (so the k ⋅ ln(2) rounding error is + // ~2⁻²³⁵, far below an output ulp) then one `sar(107, …)` leaves the reduced argument + // at Q128. let t := sar( 0x6b, From 1773fb9ee9beee5c377b4c7a8fde36867a8bfe43 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 18:03:43 +0200 Subject: [PATCH 127/149] Post-merge cleanup --- src/vendor/Exp.sol | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 177a29606..fc2600935 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -60,16 +60,16 @@ library Exp { // exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the // tightest bound the proof technique can bear, in spite of the fact that the worst-case // error contributions do not co-occur. The budget bounds Δ ≤ 1.0050013498897899168, the sum - // of three one-sided contributions: + // of four one-sided contributions: // integer Horner + closing `DIV` truncation: the Ev shared by the numerator Ev + t⋅Od // and denominator Ev - t⋅Od cancels to first order in the quotient, so its // truncation barely perturbs e; this jitter stays < 0.62071. // argument granularity: v carries t² on the Q123 grid, and its floor only lowers the // polynomials' shared argument (by < 2⁻¹²³), which lifts e on the t > 0 half by < // 0.32906: one v-grain moves the quotient by 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose - // one-signed numerator maximal at each piece's upper edge and whose denominator is - // floored piecewise over 32 domain pieces (the pointwise supremum is ≈ 0.3287 at t - // = ln(2)/2). The t < 0 direction is budgeted on the under side. + // one-signed numerator is maximal at each piece's upper edge and whose denominator + // is floored piecewise over 32 domain pieces (the pointwise supremum is ≈ 0.3287 at + // t = ln(2)/2). The t < 0 direction is budgeted on the under side. // rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): // < 0.04420 (its supremum is √2⋅2¹²⁶/(2¹³¹-1)). // reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is @@ -78,7 +78,7 @@ library Exp { // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = // √2/128). // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1090 ulp (1 ulp = 10⁻¹⁸ of the result).The margin is the least integer + // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1090 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer // on the 2¹⁰⁸ output grid strictly above Δ's image: 0x37c9ed9cabf = ⌊5¹⁸⋅Δ⌋ + 1 = // 3833775901375 (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never // overestimate requirement). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E. The under side is bounded to the @@ -123,7 +123,7 @@ library Exp { ) ) - // v = t² in Q128 (nonnegative; logical shift): the widest basis at which the + // v = t² in Q123 (nonnegative; logical shift): the widest basis at which the // monic-stage product below stays inside 256 bits. let v := shr(0x85, mul(t, t)) @@ -151,9 +151,9 @@ library Exp { r := div(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E on the 2¹⁰⁸ output grid (5¹⁸ = 10¹⁸/2¹⁸ multiplies the Q126 quotient), less the - // one-sided margin (0xe17cfd91868d72d = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then - // floored by `shr(126 - k, …)` which folds in the 2ᵏ octave scaling and the wad unit's - // remaining 2¹⁸ (108 - k ∈ [45, 168]). + // one-sided margin (0x37c9ed9cabf = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then floored by + // `shr(108 - k, …)` which folds in the 2ᵏ octave scaling and the wad unit's remaining + // 2¹⁸ (108 - k ∈ [45, 168]). r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x37c9ed9cabf)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x From cc34ee4c63a8462952db0a469f1c180e1836c542 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 18:41:56 +0200 Subject: [PATCH 128/149] Anchor the Ln runtime model to the Solidity-level guard lnWadToRay guards nonpositive input in Solidity (Panic.panic, code 0x12) before entering the assembly kernel, so the compiled Yul carries the solc-generated guard -- sgt against a cleaned int256 zero, a panic helper -- and renumbered functions (fun_lnWadToRay_65, fun_lnWad_81, wrappers 100 and 113). The runtime-model reductions mirror the expRayToWad guard recipe: sgt_zero_pos/nonpos split the branch, the solc cleanup/convert/constant helpers reduce by dedicated lemmas, and the fuel budgets carry the guard prefix through the wrap and lnWad layers. Every statement outside Seam/RuntimeModel.lean is byte-identical; LnProof and ExpProof both build green from their axiom gates (the exp package, which composes the ln public surface in its round trip, rebuilt with no changes). Co-Authored-By: Claude Fable 5 --- .../ln/LnProof/LnProof/Seam/RuntimeModel.lean | 652 +++++++++++++----- 1 file changed, 475 insertions(+), 177 deletions(-) diff --git a/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean b/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean index 4da5bb83f..60abdfd1b 100644 --- a/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean +++ b/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean @@ -10,9 +10,11 @@ import LnProof.Mono.Top This file contains the arithmetic facts used to show that the compiled `LnWrapper` runtime computes the hand model `Stages.lnWadToRayBody` / -`Stages.lnWadBody`. These facts drive the revert guard -`if iszero(slt(0, x))` in `fun_lnWadToRay_11`: for a positive signed input the -guard is skipped, for a nonpositive one it is taken. +`Stages.lnWadBody`. These facts drive the Solidity-level input guard in +`fun_lnWadToRay_65`, which branches on `iszero(sgt(x, 0))` and calls +`fun_panic_8` (panic code `0x12`, division-by-zero) before the assembly +kernel: for a positive signed input the panic branch is skipped, for a +nonpositive one it is taken. -/ namespace LnYul @@ -46,55 +48,11 @@ theorem u256_pos_bounds {x : Nat} (h : 0 < int256 (u256 x)) : rw [← intPow256]; exact_mod_cast hlt omega -/-- The revert guard `slt(0, x)` is `1` for a positive signed input, so -`iszero(slt(0, x))` is `0` and the guard branch is skipped. -/ -theorem evmSlt_zero_pos {x : Nat} (h1 : 1 ≤ u256 x) (h2 : u256 x < 2 ^ 255) : - evmSlt 0 (u256 x) = 1 := by - unfold evmSlt - have h0 : u256 0 = 0 := by unfold u256 WORD_MOD; simp - have hidem : u256 (u256 x) = u256 x := u256_idem x - rw [h0, hidem] - have hmod1 : (0 + 2 ^ 255) % WORD_MOD = 2 ^ 255 := by - unfold WORD_MOD; omega - have hmod2 : (u256 x + 2 ^ 255) % WORD_MOD = u256 x + 2 ^ 255 := by - unfold WORD_MOD; omega - rw [hmod1, hmod2] - rw [if_pos (by omega)] - -/-- The revert guard `slt(0, x)` is `0` for a nonpositive signed input, so -`iszero(slt(0, x))` is `1` and the guard branch (revert) is taken. -/ -theorem evmSlt_zero_nonpos {x : Nat} (h : int256 (u256 x) ≤ 0) : - evmSlt 0 (u256 x) = 0 := by - have hlt : u256 x < 2 ^ 256 := u256_lt_word x - unfold evmSlt - have h0 : u256 0 = 0 := by unfold u256 WORD_MOD; simp - have hidem : u256 (u256 x) = u256 x := u256_idem x - rw [h0, hidem] - have hmod1 : (0 + 2 ^ 255) % WORD_MOD = 2 ^ 255 := by - unfold WORD_MOD; omega - rw [hmod1] - -- nonpositive int256 ⇒ either u256 x = 0, or u256 x ≥ 2^255 - have hcases : u256 x = 0 ∨ 2 ^ 255 ≤ u256 x := by - by_contra hc - push_neg at hc - obtain ⟨hne, hge⟩ := hc - have hpos : 0 < u256 x := Nat.pos_of_ne_zero hne - unfold int256 at h - simp only [hge, if_true] at h - have : (0 : Int) < u256 x := by exact_mod_cast hpos - omega - rcases hcases with h0x | hge - · rw [h0x]; unfold WORD_MOD; simp - · have hmod2 : (u256 x + 2 ^ 255) % WORD_MOD = u256 x - 2 ^ 255 := by - unfold WORD_MOD; omega - rw [hmod2] - rw [if_neg (by omega)] - -/-- `slt(0, x)` evaluates to the word `1` for a positive signed input, which is -exactly what the interpreter needs to skip the `if iszero(slt(0, x))` revert -guard in `fun_lnWadToRay_11`. -/ -theorem slt_zero_pos {x : Nat} (h1 : 1 ≤ u256 x) (h2 : u256 x < 2 ^ 255) : - EvmYul.UInt256.slt (EvmYul.UInt256.ofNat 0) (EvmYul.UInt256.ofNat x) +/-- `sgt(x, 0)` evaluates to the word `1` for a positive signed input, which is +exactly what the interpreter needs to skip the `if iszero(sgt(x, 0))` panic +branch in `fun_lnWadToRay_65`. -/ +theorem sgt_zero_pos {x : Nat} (h1 : 1 ≤ u256 x) (h2 : u256 x < 2 ^ 255) : + EvmYul.UInt256.sgt (EvmYul.UInt256.ofNat x) (EvmYul.UInt256.ofNat 0) = EvmYul.UInt256.ofNat 1 := by have hx : (EvmYul.UInt256.ofNat x).toNat = u256 x := by have := wordNat_ofNat x; simpa [wordNat] using this @@ -106,14 +64,14 @@ theorem slt_zero_pos {x : Nat} (h1 : 1 ≤ u256 x) (h2 : u256 x < 2 ^ 255) : exact hh have c1 : ¬ ((0 : Nat) ≥ 2 ^ 255) := by omega have c2 : ¬ (u256 x ≥ 2 ^ 255) := by omega - unfold EvmYul.UInt256.slt EvmYul.UInt256.sltBool - rw [hx, h0, if_neg c1, if_neg c2] + unfold EvmYul.UInt256.sgt EvmYul.UInt256.sgtBool + rw [hx, h0, if_neg c2, if_neg c1] simp [EvmYul.UInt256.fromBool, hlt] -/-- `slt(0, x)` evaluates to the word `0` for a nonpositive signed input, so the -interpreter takes the `if iszero(slt(0, x))` revert guard in `fun_lnWadToRay_11`. -/ -theorem slt_zero_nonpos {x : Nat} (hnonpos : int256 (u256 x) ≤ 0) : - EvmYul.UInt256.slt (EvmYul.UInt256.ofNat 0) (EvmYul.UInt256.ofNat x) +/-- `sgt(x, 0)` evaluates to the word `0` for a nonpositive signed input, so the +interpreter takes the `if iszero(sgt(x, 0))` panic branch in `fun_lnWadToRay_65`. -/ +theorem sgt_zero_nonpos {x : Nat} (hnonpos : int256 (u256 x) ≤ 0) : + EvmYul.UInt256.sgt (EvmYul.UInt256.ofNat x) (EvmYul.UInt256.ofNat 0) = EvmYul.UInt256.ofNat 0 := by have hlt256 : u256 x < 2 ^ 256 := u256_lt_word x have hx : (EvmYul.UInt256.ofNat x).toNat = u256 x := by @@ -129,15 +87,17 @@ theorem slt_zero_nonpos {x : Nat} (hnonpos : int256 (u256 x) ≤ 0) : simp only [hge, if_true] at hnonpos have : (0 : Int) < u256 x := by exact_mod_cast hpos omega - unfold EvmYul.UInt256.slt EvmYul.UInt256.sltBool - rw [hx, h0, if_neg (by omega : ¬ ((0 : Nat) ≥ 2 ^ 255))] + unfold EvmYul.UInt256.sgt EvmYul.UInt256.sgtBool + rw [hx, h0] rcases hcases with h0x | hge - · rw [if_neg (by rw [h0x]; omega : ¬ (u256 x ≥ 2 ^ 255))] + · rw [if_neg (by rw [h0x]; omega : ¬ (u256 x ≥ 2 ^ 255)), + if_neg (by omega : ¬ ((0 : Nat) ≥ 2 ^ 255))] have hnlt : ¬ EvmYul.UInt256.ofNat 0 < EvmYul.UInt256.ofNat x := by show ¬ (EvmYul.UInt256.ofNat 0).toNat < (EvmYul.UInt256.ofNat x).toNat rw [h0, hx, h0x]; omega simp [EvmYul.UInt256.fromBool, hnlt] - · rw [if_pos (by omega : u256 x ≥ 2 ^ 255)] + · rw [if_pos (by omega : u256 x ≥ 2 ^ 255), + if_neg (by omega : ¬ ((0 : Nat) ≥ 2 ^ 255))] simp [EvmYul.UInt256.fromBool] /-- `wordNat` of `UInt256.complement` is `evmNot` (the complement equals the @@ -344,7 +304,7 @@ private theorem evmSgt_u256_right (a b : Nat) : evmSgt a (u256 b) = evmSgt a b : /-- `wordNat` of `UInt256.sgt 0 r` matches `evmSgt 0 (wordNat r)`. Only the zero-left case is needed: the `mul(999999999, sgt(0, r))` rounding term in -`fun_lnWad_27`. -/ +`fun_lnWad_81`. -/ theorem wordNat_sgt_zero (r : EvmYul.UInt256) : wordNat (EvmYul.UInt256.sgt (EvmYul.UInt256.ofNat 0) r) = evmSgt 0 (wordNat r) := by have hr : wordNat r < 2 ^ 256 := by @@ -406,26 +366,364 @@ theorem lnWadToRayCoreExpr_eq (x : Nat) : unfold lnWadToRayBody zWord uWord pS4 pS3 pS2 pS1 qS5 qS4 qS3 qS2 qS1 rfl +/-- A Yul `revert(a, b)` primitive call halts with `.error .Revert` (the +`MachineState.evmRevert` op is total, so the `Semantics` dispatch always reaches +the `.ok ⇒ .error .Revert` branch). Mirror of the `primCall_*` lemmas. -/ +private theorem primCall_revert_yul (fuel : Nat) (s : EvmYul.Yul.State) + (a b : EvmYul.UInt256) : + EvmYul.Yul.primCall (fuel + 1) s + (EvmYul.Operation.System EvmYul.Operation.SOp.REVERT : EvmYul.Operation .Yul) [a, b] = + .error EvmYul.Yul.Exception.Revert := by + rw [EvmYul.Yul.primCall.eq_def] + simp only [List.mem_cons, List.not_mem_nil, EvmYul.Operation.System.injEq, + Bool.not_eq_true, reduceCtorEq, or_self, and_false, if_false, + EvmYul.step.eq_def] + rfl + +/-- A one-line identity helper `f(value) -> out { out := value }` returns its +argument. The proof recipe is shared by `identity`, `cleanup_t_int256`, +`cleanup_t_rational_*`, and `cleanup_t_uint256`. -/ +private theorem call_identity_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] (.some "identity") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_identity] + simp only [yulFunction_identity, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +private theorem call_cleanup_t_int256_word_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] (.some "cleanup_t_int256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_int256] + simp only [yulFunction_cleanup_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +private theorem call_cleanup_t_rational_0_by_1_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] + (.some "cleanup_t_rational_0_by_1") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_rational_0_by_1] + simp only [yulFunction_cleanup_t_rational_0_by_1, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +/-- `convert_t_rational_0_by_1_to_t_int256(value) -> converted` is +`cleanup_t_int256(identity(cleanup_t_rational_0_by_1(value)))` — three identity +calls, so it returns its argument. Used to evaluate the input guard +comparison's right-hand side. -/ +private theorem call_convert_0_to_int256_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 120)) [FormalYul.word v] + (.some "convert_t_rational_0_by_1_to_t_int256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 120) = (fuel + extra) + 120 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_convert_t_rational_0_by_1_to_t_int256] + simp only [yulFunction_convert_t_rational_0_by_1_to_t_int256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h1 := + call_cleanup_t_rational_0_by_1_direct (v := v) (fuel := fuel + extra) (extra := 92) + (shared := shared) + (store := Finmap.insert "value" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h2 := + call_identity_direct (v := v) (fuel := fuel + extra) (extra := 94) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h3 := + call_cleanup_t_int256_word_direct (v := v) (fuel := fuel + extra) (extra := 96) + (shared := shared) + (store := Finmap.insert "value" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + simp [FormalYul.word] at h1 h2 h3 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, h1, h2, h3] + +/-- `cleanup_t_uint8(value) -> cleaned { cleaned := and(value, 0xff) }`. +Specialized to the panic code `0x12`, where `and(0x12, 0xff) = 0x12`. -/ +private theorem call_cleanup_t_uint8_18_direct + (fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 20) [FormalYul.word 0x12] (.some "cleanup_t_uint8") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0x12]) := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_uint8] + simp only [yulFunction_cleanup_t_uint8, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +private theorem call_cleanup_t_rational_18_by_1_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] + (.some "cleanup_t_rational_18_by_1") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_rational_18_by_1] + simp only [yulFunction_cleanup_t_rational_18_by_1, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +/-- `convert_t_rational_18_by_1_to_t_uint8(0x12) = 0x12` +(= `cleanup_t_uint8(identity(cleanup_t_rational_18_by_1(0x12)))`). -/ +private theorem call_convert_18_to_uint8_18_direct + (fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + 120) [FormalYul.word 0x12] + (.some "convert_t_rational_18_by_1_to_t_uint8") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0x12]) := by + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_convert_t_rational_18_by_1_to_t_uint8] + simp only [yulFunction_convert_t_rational_18_by_1_to_t_uint8, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h1 := + call_cleanup_t_rational_18_by_1_direct (v := 0x12) (fuel := fuel) (extra := 92) + (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h2 := + call_identity_direct (v := 0x12) (fuel := fuel) (extra := 94) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h3 := + call_cleanup_t_uint8_18_direct (fuel := fuel + 96) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + simp [FormalYul.word] at h1 h2 h3 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, h1, h2, h3] + +private theorem call_cleanup_t_uint256_direct + (v fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] (.some "cleanup_t_uint256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by + rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_cleanup_t_uint256] + simp only [yulFunction_cleanup_t_uint256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word] + +/-- `convert_t_uint8_to_t_uint256(0x12) = 0x12` +(= `cleanup_t_uint256(identity(cleanup_t_uint8(0x12)))`). -/ +private theorem call_convert_uint8_to_uint256_18_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 120)) [FormalYul.word 0x12] + (.some "convert_t_uint8_to_t_uint256") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0x12]) := by + rw [show fuel + (extra + 120) = (fuel + extra) + 120 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_convert_t_uint8_to_t_uint256] + simp only [yulFunction_convert_t_uint8_to_t_uint256, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have h1 := + call_cleanup_t_uint8_18_direct (fuel := fuel + extra + 92) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h2 := + call_identity_direct (v := 0x12) (fuel := fuel + extra) (extra := 94) (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + have h3 := + call_cleanup_t_uint256_direct (v := 0x12) (fuel := fuel + extra) (extra := 96) + (shared := shared) + (store := Finmap.insert "value" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + simp [FormalYul.word] at h1 h2 h3 + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, h1, h2, h3] + +/-- `constant_DIVISION_BY_ZERO_20() = 0x12` — the solc panic-code accessor for +division by zero (`0x12`), used by the nonpositive-input guard. -/ +private theorem call_constant_DIVISION_BY_ZERO_20_direct + (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 160)) [] (.some "constant_DIVISION_BY_ZERO_20") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 0x12]) := by + rw [show fuel + (extra + 160) = (fuel + extra) + 160 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, + lookup_constant_DIVISION_BY_ZERO_20] + simp only [yulFunction_constant_DIVISION_BY_ZERO_20, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + have hconv := + call_convert_18_to_uint8_18_direct (fuel := fuel + extra + 35) (shared := shared) + (store := Finmap.insert "expr_19" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) + (hlookup := hlookup) + simp [FormalYul.word] at hconv + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, hconv] + set_option maxHeartbeats 8000000 in -/-- The compiled `fun_lnWadToRay_11` computes the model `lnWadToRayBody` for a -positive signed input (the leading `if iszero(slt(0,x))` revert guard is skipped). -/ +/-- `fun_panic_8(code)` reverts: its body is +`mstore(0,…); mstore(0x20,code); revert(0x1c,0x24)`. -/ +private theorem call_fun_panic_8_revert_direct + (code fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) + (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = + some (FormalYul.accountFor yulContract)) : + EvmYul.Yul.call (fuel + (extra + 600)) [FormalYul.word code] (.some "fun_panic_8") + (.some yulContract) (EvmYul.Yul.State.Ok shared store) = + .error EvmYul.Yul.Exception.Revert := by + rw [show fuel + (extra + 600) = (fuel + extra) + 600 by omega] + rw [EvmYul.Yul.call.eq_def] + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_panic_8] + simp only [yulFunction_fun_panic_8, + FormalYul.Preservation.functionDefinition_params_def, + FormalYul.Preservation.functionDefinition_rets_def, + FormalYul.Preservation.functionDefinition_body_def, + EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + EvmYul.Yul.evalTail.eq_def, + EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, primCall_revert_yul] + +set_option maxHeartbeats 8000000 in +/-- The compiled `fun_lnWadToRay_65` computes the model `lnWadToRayBody` for a +positive signed input: the leading `if iszero(sgt(x, 0))` panic branch is +skipped (via `sgt_zero_pos`), and the assembly kernel result is returned. -/ theorem call_fun_lnWadToRay_direct (x fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hpos : 1 ≤ FormalYul.u256 x) (hpos2 : FormalYul.u256 x < 2 ^ 255) : - EvmYul.Yul.call (fuel + 600) [FormalYul.word x] (.some yulName_fun_lnWadToRay) + EvmYul.Yul.call (fuel + 900) [FormalYul.word x] (.some yulName_fun_lnWadToRay) (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word (lnWadToRayBody (FormalYul.u256 x))]) := by rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_lnWadToRay] - simp only [yulFunction_fun_lnWadToRay, yulFunction_fun_lnWadToRay_11, + simp only [yulFunction_fun_lnWadToRay, yulFunction_fun_lnWadToRay_65, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execCall.eq_def, + have hconv0 := + call_convert_0_to_int256_direct (v := 0) (fuel := fuel) (extra := 767) + (shared := shared) (hlookup := hlookup) + have hcleanup := + call_cleanup_t_int256_word_direct (v := x) (fuel := fuel) (extra := 865) + (shared := shared) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at hconv0 hcleanup + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, @@ -433,12 +731,10 @@ theorem call_fun_lnWadToRay_direct EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, Finmap.lookup_insert, FormalYul.word, - slt_zero_pos hpos hpos2, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 576) - (shared := shared) - (store := Finmap.insert "var_x_4" (EvmYul.UInt256.ofNat x) - (Inhabited.default : EvmYul.Yul.VarStore)) - (hlookup := hlookup)] + sgt_zero_pos hpos hpos2, + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 876) + (shared := shared) (hlookup := hlookup), + hcleanup, hconv0] apply FormalYul.Preservation.eq_of_wordNat_eq simp only [FormalYul.Preservation.wordNat_shiftRight, FormalYul.Preservation.wordNat_shiftLeft, FormalYul.Preservation.wordNat_add, FormalYul.Preservation.wordNat_sub, @@ -457,49 +753,51 @@ theorem call_fun_lnWadToRay_direct Sc, P4c, P3c, P2c, P1c, C0c, Q4c, Q3c, Q2c, Q1c, Kc, LN2c, BIASc] using lnWadToRayCoreExpr_eq (FormalYul.u256 x) -/-- A Yul `revert(a, b)` primitive call halts with `.error .Revert` (the -`MachineState.evmRevert` op is total, so the `Semantics` dispatch always reaches -the `.ok ⇒ .error .Revert` branch). Mirror of the `primCall_*` lemmas. -/ -private theorem primCall_revert_yul (fuel : Nat) (s : EvmYul.Yul.State) - (a b : EvmYul.UInt256) : - EvmYul.Yul.primCall (fuel + 1) s - (EvmYul.Operation.System EvmYul.Operation.SOp.REVERT : EvmYul.Operation .Yul) [a, b] = - .error EvmYul.Yul.Exception.Revert := by - rw [EvmYul.Yul.primCall.eq_def] - simp only [List.mem_cons, List.not_mem_nil, EvmYul.Operation.System.injEq, - Bool.not_eq_true, reduceCtorEq, or_self, and_false, if_false, - EvmYul.step.eq_def] - rfl - set_option maxHeartbeats 8000000 in +/-- For a nonpositive signed input, `fun_lnWadToRay_65` takes the guard branch +and reverts via `fun_panic_8(DIVISION_BY_ZERO)`. -/ theorem call_fun_lnWadToRay_revert_direct (x fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hnonpos : int256 (FormalYul.u256 x) ≤ 0) : - EvmYul.Yul.call (fuel + 600) [FormalYul.word x] (.some yulName_fun_lnWadToRay) + EvmYul.Yul.call (fuel + 1000) [FormalYul.word x] (.some yulName_fun_lnWadToRay) (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .error EvmYul.Yul.Exception.Revert := by rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_lnWadToRay] - simp only [yulFunction_fun_lnWadToRay, yulFunction_fun_lnWadToRay_11, + simp only [yulFunction_fun_lnWadToRay, yulFunction_fun_lnWadToRay_65, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execCall.eq_def, + have hconv0 := + call_convert_0_to_int256_direct (v := 0) (fuel := fuel) (extra := 867) + (shared := shared) (hlookup := hlookup) + have hcleanup := + call_cleanup_t_int256_word_direct (v := x) (fuel := fuel) (extra := 965) + (shared := shared) (hlookup := hlookup) + have hconvu := + call_convert_uint8_to_uint256_18_direct (fuel := fuel) (extra := 865) + (shared := shared) (hlookup := hlookup) + have hpanic := + call_fun_panic_8_revert_direct (code := 0x12) (fuel := fuel) (extra := 384) + (shared := shared) (hlookup := hlookup) + simp only [Nat.reduceAdd, FormalYul.word] at hconv0 hcleanup hconvu hpanic + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, - EvmYul.Yul.State.setStore, - FormalYul.word, - slt_zero_nonpos hnonpos, primCall_revert_yul, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 576) - (shared := shared) - (store := Finmap.insert "var_x_4" (EvmYul.UInt256.ofNat x) - (Inhabited.default : EvmYul.Yul.VarStore)) - (hlookup := hlookup)] + EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + Finmap.lookup_insert, FormalYul.word, + sgt_zero_nonpos hnonpos, + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 976) + (shared := shared) (hlookup := hlookup), + call_constant_DIVISION_BY_ZERO_20_direct (fuel := fuel) (extra := 826) + (shared := shared) (hlookup := hlookup), + hcleanup, hconv0, hconvu, hpanic] set_option maxHeartbeats 8000000 in theorem call_fun_wrap_lnWadToRay_direct @@ -507,25 +805,25 @@ theorem call_fun_wrap_lnWadToRay_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hpos : 1 ≤ FormalYul.u256 x) (hpos2 : FormalYul.u256 x < 2 ^ 255) : - EvmYul.Yul.call (fuel + 800) [FormalYul.word x] (.some yulName_fun_wrap_lnWadToRay) + EvmYul.Yul.call (fuel + 1100) [FormalYul.word x] (.some yulName_fun_wrap_lnWadToRay) (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word (lnWadToRayBody (FormalYul.u256 x))]) := by rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_lnWadToRay] - simp only [yulFunction_fun_wrap_lnWadToRay, yulFunction_fun_wrap_lnWadToRay_46, + simp only [yulFunction_fun_wrap_lnWadToRay, yulFunction_fun_wrap_lnWadToRay_100, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - have hfuel : fuel + 791 = (fuel + 191) + 600 := by omega + have hfuel : fuel + 1091 = (fuel + 191) + 900 := by omega have hCall := call_fun_lnWadToRay_direct (x := x) (fuel := fuel + 191) (shared := shared) - (store := Finmap.insert "expr_42" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "expr_96" (EvmYul.UInt256.ofNat x) (Finmap.insert "_4" (EvmYul.UInt256.ofNat x) - (Finmap.insert "expr_40_address" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var__38" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "expr_94_address" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "var__92" (EvmYul.UInt256.ofNat 0) (Finmap.insert "zero_t_int256_3" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var_x_35" (EvmYul.UInt256.ofNat x) + (Finmap.insert "var_x_89" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore))))))) (hlookup := hlookup) hpos hpos2 simp only [FormalYul.word, yulName_fun_lnWadToRay] at hCall @@ -537,9 +835,9 @@ theorem call_fun_wrap_lnWadToRay_direct EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.revive, EvmYul.Yul.State.setLeave, EvmYul.Yul.State.overwrite?, Finmap.lookup_insert, FormalYul.word, hfuel, hCall, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 776) + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 1076) (shared := shared) - (store := Finmap.insert "var_x_35" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "var_x_89" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup)] @@ -549,24 +847,24 @@ theorem call_fun_lnWad_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hpos : 1 ≤ FormalYul.u256 x) (hpos2 : FormalYul.u256 x < 2 ^ 255) : - EvmYul.Yul.call (fuel + 900) [FormalYul.word x] (.some yulName_fun_lnWad) + EvmYul.Yul.call (fuel + 1200) [FormalYul.word x] (.some yulName_fun_lnWad) (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word (lnWadBody (FormalYul.u256 x))]) := by rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_lnWad] - simp only [yulFunction_fun_lnWad, yulFunction_fun_lnWad_27, + simp only [yulFunction_fun_lnWad, yulFunction_fun_lnWad_81, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - have hfuel : fuel + 892 = (fuel + 292) + 600 := by omega + have hfuel : fuel + 1192 = (fuel + 292) + 900 := by omega have hCall := call_fun_lnWadToRay_direct (x := x) (fuel := fuel + 292) (shared := shared) - (store := Finmap.insert "expr_21" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "expr_75" (EvmYul.UInt256.ofNat x) (Finmap.insert "_6" (EvmYul.UInt256.ofNat x) - (Finmap.insert "var_r_17" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "var_r_71" (EvmYul.UInt256.ofNat 0) (Finmap.insert "zero_t_int256_5" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var_x_14" (EvmYul.UInt256.ofNat x) + (Finmap.insert "var_x_68" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore)))))) (hlookup := hlookup) hpos hpos2 simp only [FormalYul.word, yulName_fun_lnWadToRay] at hCall @@ -579,9 +877,9 @@ theorem call_fun_lnWad_direct EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, Finmap.lookup_insert, FormalYul.word, hfuel, hCall, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 876) + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 1176) (shared := shared) - (store := Finmap.insert "var_x_14" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "var_x_68" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup)] apply FormalYul.Preservation.eq_of_wordNat_eq @@ -601,25 +899,25 @@ theorem call_fun_wrap_lnWad_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hpos : 1 ≤ FormalYul.u256 x) (hpos2 : FormalYul.u256 x < 2 ^ 255) : - EvmYul.Yul.call (fuel + 1100) [FormalYul.word x] (.some yulName_fun_wrap_lnWad) + EvmYul.Yul.call (fuel + 1400) [FormalYul.word x] (.some yulName_fun_wrap_lnWad) (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word (lnWadBody (FormalYul.u256 x))]) := by rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_lnWad] - simp only [yulFunction_fun_wrap_lnWad, yulFunction_fun_wrap_lnWad_59, + simp only [yulFunction_fun_wrap_lnWad, yulFunction_fun_wrap_lnWad_113, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - have hfuel : fuel + 1091 = (fuel + 191) + 900 := by omega + have hfuel : fuel + 1391 = (fuel + 191) + 1200 := by omega have hCall := call_fun_lnWad_direct (x := x) (fuel := fuel + 191) (shared := shared) - (store := Finmap.insert "expr_55" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "expr_109" (EvmYul.UInt256.ofNat x) (Finmap.insert "_2" (EvmYul.UInt256.ofNat x) - (Finmap.insert "expr_53_address" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var__51" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "expr_107_address" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "var__105" (EvmYul.UInt256.ofNat 0) (Finmap.insert "zero_t_int256_1" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var_x_48" (EvmYul.UInt256.ofNat x) + (Finmap.insert "var_x_102" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore))))))) (hlookup := hlookup) hpos hpos2 simp only [FormalYul.word, yulName_fun_lnWad] at hCall @@ -631,9 +929,9 @@ theorem call_fun_wrap_lnWad_direct EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.revive, EvmYul.Yul.State.setLeave, EvmYul.Yul.State.overwrite?, Finmap.lookup_insert, FormalYul.word, hfuel, hCall, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 1076) + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 1376) (shared := shared) - (store := Finmap.insert "var_x_48" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "var_x_102" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup)] @@ -918,7 +1216,7 @@ private theorem external_fun_wrap_lnWadToRay_calldata_result rw [EvmYul.Yul.call.eq_def] simp only [lnWadToRaySharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_lnWadToRay] - simp only [yulFunction_external_fun_wrap_lnWadToRay, yulFunction_external_fun_wrap_lnWadToRay_46, + simp only [yulFunction_external_fun_wrap_lnWadToRay, yulFunction_external_fun_wrap_lnWadToRay_100, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -945,7 +1243,7 @@ private theorem external_fun_wrap_lnWadToRay_calldata_result (hdata := lnWadToRaySharedAfterFreePtr_calldata x) simp [FormalYul.word] at hdecode have hwrap := - call_fun_wrap_lnWadToRay_direct (x := x) (fuel := 999183) + call_fun_wrap_lnWadToRay_direct (x := x) (fuel := 998883) (shared := lnWadToRaySharedAfterFreePtr x) (store := Finmap.insert "param_0" (FormalYul.word x) (Inhabited.default : EvmYul.Yul.VarStore)) @@ -1004,7 +1302,7 @@ private theorem external_fun_wrap_lnWadToRay_calldata_halts rw [EvmYul.Yul.call.eq_def] simp only [lnWadToRaySharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_lnWadToRay] - simp only [yulFunction_external_fun_wrap_lnWadToRay, yulFunction_external_fun_wrap_lnWadToRay_46, + simp only [yulFunction_external_fun_wrap_lnWadToRay, yulFunction_external_fun_wrap_lnWadToRay_100, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -1031,7 +1329,7 @@ private theorem external_fun_wrap_lnWadToRay_calldata_halts (hdata := lnWadToRaySharedAfterFreePtr_calldata x) simp [FormalYul.word] at hdecode have hwrap := - call_fun_wrap_lnWadToRay_direct (x := x) (fuel := 999183) + call_fun_wrap_lnWadToRay_direct (x := x) (fuel := 998883) (shared := lnWadToRaySharedAfterFreePtr x) (store := Finmap.insert "param_0" (FormalYul.word x) (Inhabited.default : EvmYul.Yul.VarStore)) @@ -1159,13 +1457,13 @@ private theorem selectSwitchCase_lnWadToRay_sharedFor_mk (x : Nat) : (FormalYul.word 224)) [(FormalYul.word 835988157, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_59") [])]), + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_113") [])]), (FormalYul.word 4010811976, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_46") [])])] = + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_100") [])])] = some [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_46") [])] := by + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_100") [])] := by rw [lnWadToRay_selector_sharedFor_mk] rfl @@ -1185,13 +1483,13 @@ private theorem selectSwitchCase_lnWadToRay_sharedFor_mk_raw (x : Nat) : (EvmYul.UInt256.ofNat 224)) [(EvmYul.UInt256.ofNat 835988157, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_59") [])]), + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_113") [])]), (EvmYul.UInt256.ofNat 4010811976, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_46") [])])] = + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_100") [])])] = some [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_46") [])] := by + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_100") [])] := by simpa [FormalYul.word] using selectSwitchCase_lnWadToRay_sharedFor_mk x set_option maxHeartbeats 8000000 in @@ -1449,7 +1747,7 @@ private theorem external_fun_wrap_lnWad_calldata_result rw [EvmYul.Yul.call.eq_def] simp only [lnWadSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_lnWad] - simp only [yulFunction_external_fun_wrap_lnWad, yulFunction_external_fun_wrap_lnWad_59, + simp only [yulFunction_external_fun_wrap_lnWad, yulFunction_external_fun_wrap_lnWad_113, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -1476,7 +1774,7 @@ private theorem external_fun_wrap_lnWad_calldata_result (hdata := lnWadSharedAfterFreePtr_calldata x) simp [FormalYul.word] at hdecode have hwrap := - call_fun_wrap_lnWad_direct (x := x) (fuel := 998883) + call_fun_wrap_lnWad_direct (x := x) (fuel := 998583) (shared := lnWadSharedAfterFreePtr x) (store := Finmap.insert "param_0" (FormalYul.word x) (Inhabited.default : EvmYul.Yul.VarStore)) @@ -1535,7 +1833,7 @@ private theorem external_fun_wrap_lnWad_calldata_halts rw [EvmYul.Yul.call.eq_def] simp only [lnWadSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_lnWad] - simp only [yulFunction_external_fun_wrap_lnWad, yulFunction_external_fun_wrap_lnWad_59, + simp only [yulFunction_external_fun_wrap_lnWad, yulFunction_external_fun_wrap_lnWad_113, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -1562,7 +1860,7 @@ private theorem external_fun_wrap_lnWad_calldata_halts (hdata := lnWadSharedAfterFreePtr_calldata x) simp [FormalYul.word] at hdecode have hwrap := - call_fun_wrap_lnWad_direct (x := x) (fuel := 998883) + call_fun_wrap_lnWad_direct (x := x) (fuel := 998583) (shared := lnWadSharedAfterFreePtr x) (store := Finmap.insert "param_0" (FormalYul.word x) (Inhabited.default : EvmYul.Yul.VarStore)) @@ -1664,13 +1962,13 @@ private theorem selectSwitchCase_lnWad_sharedFor_mk (x : Nat) : (FormalYul.word 224)) [(FormalYul.word 835988157, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_59") [])]), + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_113") [])]), (FormalYul.word 4010811976, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_46") [])])] = + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_100") [])])] = some [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_59") [])] := by + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_113") [])] := by rw [lnWad_selector_sharedFor_mk] rfl @@ -1690,13 +1988,13 @@ private theorem selectSwitchCase_lnWad_sharedFor_mk_raw (x : Nat) : (EvmYul.UInt256.ofNat 224)) [(EvmYul.UInt256.ofNat 835988157, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_59") [])]), + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_113") [])]), (EvmYul.UInt256.ofNat 4010811976, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_46") [])])] = + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWadToRay_100") [])])] = some [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_59") [])] := by + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_lnWad_113") [])] := by simpa [FormalYul.word] using selectSwitchCase_lnWad_sharedFor_mk x set_option maxHeartbeats 8000000 in @@ -1823,24 +2121,24 @@ theorem call_fun_wrap_lnWadToRay_revert_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hnonpos : int256 (FormalYul.u256 x) ≤ 0) : - EvmYul.Yul.call (fuel + 800) [FormalYul.word x] (.some yulName_fun_wrap_lnWadToRay) + EvmYul.Yul.call (fuel + 1200) [FormalYul.word x] (.some yulName_fun_wrap_lnWadToRay) (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .error EvmYul.Yul.Exception.Revert := by rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_lnWadToRay] - simp only [yulFunction_fun_wrap_lnWadToRay, yulFunction_fun_wrap_lnWadToRay_46, + simp only [yulFunction_fun_wrap_lnWadToRay, yulFunction_fun_wrap_lnWadToRay_100, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - have hfuel : fuel + 791 = (fuel + 191) + 600 := by omega + have hfuel : fuel + 1191 = (fuel + 191) + 1000 := by omega have hCall := call_fun_lnWadToRay_revert_direct (x := x) (fuel := fuel + 191) (shared := shared) - (store := Finmap.insert "expr_42" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "expr_96" (EvmYul.UInt256.ofNat x) (Finmap.insert "_4" (EvmYul.UInt256.ofNat x) - (Finmap.insert "expr_40_address" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var__38" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "expr_94_address" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "var__92" (EvmYul.UInt256.ofNat 0) (Finmap.insert "zero_t_int256_3" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var_x_35" (EvmYul.UInt256.ofNat x) + (Finmap.insert "var_x_89" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore))))))) (hlookup := hlookup) hnonpos simp only [FormalYul.word, yulName_fun_lnWadToRay] at hCall @@ -1850,37 +2148,37 @@ theorem call_fun_wrap_lnWadToRay_revert_direct EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.setStore, FormalYul.word, hfuel, hCall, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 776) + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 1176) (shared := shared) - (store := Finmap.insert "var_x_35" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "var_x_89" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup)] -- `call_fun_lnWad_revert_direct`: the wad body reverts (it calls --- `fun_lnWadToRay_11`, which reverts for nonpositive input before the sdiv tail). +-- `fun_lnWadToRay_65`, which reverts for nonpositive input before the sdiv tail). set_option maxHeartbeats 8000000 in theorem call_fun_lnWad_revert_direct (x fuel : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hnonpos : int256 (FormalYul.u256 x) ≤ 0) : - EvmYul.Yul.call (fuel + 900) [FormalYul.word x] (.some yulName_fun_lnWad) + EvmYul.Yul.call (fuel + 1300) [FormalYul.word x] (.some yulName_fun_lnWad) (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .error EvmYul.Yul.Exception.Revert := by rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_lnWad] - simp only [yulFunction_fun_lnWad, yulFunction_fun_lnWad_27, + simp only [yulFunction_fun_lnWad, yulFunction_fun_lnWad_81, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - have hfuel : fuel + 892 = (fuel + 292) + 600 := by omega + have hfuel : fuel + 1292 = (fuel + 292) + 1000 := by omega have hCall := call_fun_lnWadToRay_revert_direct (x := x) (fuel := fuel + 292) (shared := shared) - (store := Finmap.insert "expr_21" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "expr_75" (EvmYul.UInt256.ofNat x) (Finmap.insert "_6" (EvmYul.UInt256.ofNat x) - (Finmap.insert "var_r_17" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "var_r_71" (EvmYul.UInt256.ofNat 0) (Finmap.insert "zero_t_int256_5" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var_x_14" (EvmYul.UInt256.ofNat x) + (Finmap.insert "var_x_68" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore)))))) (hlookup := hlookup) hnonpos simp only [FormalYul.word, yulName_fun_lnWadToRay] at hCall @@ -1890,9 +2188,9 @@ theorem call_fun_lnWad_revert_direct EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.setStore, FormalYul.word, hfuel, hCall, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 876) + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 1276) (shared := shared) - (store := Finmap.insert "var_x_14" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "var_x_68" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup)] @@ -1902,24 +2200,24 @@ theorem call_fun_wrap_lnWad_revert_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hnonpos : int256 (FormalYul.u256 x) ≤ 0) : - EvmYul.Yul.call (fuel + 1100) [FormalYul.word x] (.some yulName_fun_wrap_lnWad) + EvmYul.Yul.call (fuel + 1600) [FormalYul.word x] (.some yulName_fun_wrap_lnWad) (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .error EvmYul.Yul.Exception.Revert := by rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_lnWad] - simp only [yulFunction_fun_wrap_lnWad, yulFunction_fun_wrap_lnWad_59, + simp only [yulFunction_fun_wrap_lnWad, yulFunction_fun_wrap_lnWad_113, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - have hfuel : fuel + 1091 = (fuel + 191) + 900 := by omega - have hCall := call_fun_lnWad_revert_direct (x := x) (fuel := fuel + 191) (shared := shared) - (store := Finmap.insert "expr_55" (EvmYul.UInt256.ofNat x) + have hfuel : fuel + 1591 = (fuel + 291) + 1300 := by omega + have hCall := call_fun_lnWad_revert_direct (x := x) (fuel := fuel + 291) (shared := shared) + (store := Finmap.insert "expr_109" (EvmYul.UInt256.ofNat x) (Finmap.insert "_2" (EvmYul.UInt256.ofNat x) - (Finmap.insert "expr_53_address" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var__51" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "expr_107_address" (EvmYul.UInt256.ofNat 0) + (Finmap.insert "var__105" (EvmYul.UInt256.ofNat 0) (Finmap.insert "zero_t_int256_1" (EvmYul.UInt256.ofNat 0) - (Finmap.insert "var_x_48" (EvmYul.UInt256.ofNat x) + (Finmap.insert "var_x_102" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore))))))) (hlookup := hlookup) hnonpos simp only [FormalYul.word, yulName_fun_lnWad] at hCall @@ -1929,9 +2227,9 @@ theorem call_fun_wrap_lnWad_revert_direct EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.setStore, FormalYul.word, hfuel, hCall, - call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 1076) + call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 1576) (shared := shared) - (store := Finmap.insert "var_x_48" (EvmYul.UInt256.ofNat x) + (store := Finmap.insert "var_x_102" (EvmYul.UInt256.ofNat x) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup)] @@ -1944,7 +2242,7 @@ theorem external_fun_wrap_lnWadToRay_calldata_revert rw [EvmYul.Yul.call.eq_def] simp only [lnWadToRaySharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_lnWadToRay] - simp only [yulFunction_external_fun_wrap_lnWadToRay, yulFunction_external_fun_wrap_lnWadToRay_46, + simp only [yulFunction_external_fun_wrap_lnWadToRay, yulFunction_external_fun_wrap_lnWadToRay_100, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -1957,7 +2255,7 @@ theorem external_fun_wrap_lnWadToRay_calldata_revert (hdata := lnWadToRaySharedAfterFreePtr_calldata x) simp [FormalYul.word] at hdecode have hwrap := - call_fun_wrap_lnWadToRay_revert_direct (x := x) (fuel := 999183) + call_fun_wrap_lnWadToRay_revert_direct (x := x) (fuel := 998783) (shared := lnWadToRaySharedAfterFreePtr x) (store := Finmap.insert "param_0" (FormalYul.word x) (Inhabited.default : EvmYul.Yul.VarStore)) @@ -1985,7 +2283,7 @@ theorem external_fun_wrap_lnWad_calldata_revert rw [EvmYul.Yul.call.eq_def] simp only [lnWadSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_lnWad] - simp only [yulFunction_external_fun_wrap_lnWad, yulFunction_external_fun_wrap_lnWad_59, + simp only [yulFunction_external_fun_wrap_lnWad, yulFunction_external_fun_wrap_lnWad_113, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -1998,7 +2296,7 @@ theorem external_fun_wrap_lnWad_calldata_revert (hdata := lnWadSharedAfterFreePtr_calldata x) simp [FormalYul.word] at hdecode have hwrap := - call_fun_wrap_lnWad_revert_direct (x := x) (fuel := 998883) + call_fun_wrap_lnWad_revert_direct (x := x) (fuel := 998383) (shared := lnWadSharedAfterFreePtr x) (store := Finmap.insert "param_0" (FormalYul.word x) (Inhabited.default : EvmYul.Yul.VarStore)) From 542bb55b6ce0267e04b00aae3d6a0bfd9e6debdc Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 18:46:16 +0200 Subject: [PATCH 129/149] Formatting --- src/vendor/Exp.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index fc2600935..8eba8c23b 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -44,7 +44,7 @@ library Exp { // Mixed fixed-point bases (a staircase): each coefficient takes the widest basis fitting // its chosen byte width. A coefficient followed by more multiplies by v tolerates a shorter // basis. Each renormalizing shift lands a value directly at the basis its consumer needs. - // t: Q128 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2) + // t: Q128 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2) // v = t²: Q123 the widest basis whose monic-stage product stays inside 256 bits, so // Ev(v)'s leading stage consumes v with no renormalizing shift // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q87 (monic) From 431f33b53069c477a38ebe12e24d49d28622f27e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 19:21:51 +0200 Subject: [PATCH 130/149] Style --- formal/README.md | 2 +- src/vendor/Exp.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/formal/README.md b/formal/README.md index 3b041cbeb..ae1b80b93 100644 --- a/formal/README.md +++ b/formal/README.md @@ -16,7 +16,7 @@ Machine-checked Lean 4 correctness proofs for root math libraries in 0x Settler. ## Method 1. **Algebraic lemmas** prove one-step safety and correction logic (Babylonian / Newton-Raphson steps). -2. **Finite domain certificates** (auto-generated by Python scripts) cover all uint256 octaves with `by decide` proofs. +2. **Finite domain certificates** (auto-generated by Lean and Python scripts) cover all uint256 octaves with `by decide` proofs. 3. **The `formal/yul` Lake importer** consumes `forge inspect ... ir` output and emits ignored EVMYulLean runtime/proof modules. 4. **Runtime bridge modules** execute ABI calls through EVMYulLean against the Yul emitted by solc. The implementation is Solidity; Lean proof machinery consumes the generated Yul artifacts rather than a second hand-maintained model. diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 8eba8c23b..8e6fbc7f4 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -13,13 +13,13 @@ library Exp { /// 1414213562373095048, `expRayToWad(lnWadToRay(w)) == w - 1`, except at w = 10¹⁸ where it /// returns w. Reverts with `Panic(17)` when x is large enough to leave the supported range /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). - function expRayToWad(int256 x) internal pure returns (int256 r) { + function expRayToWad(int256 x) internal pure returns (int256) { // At this input the octave count k = round(x / (10²⁷⋅ln(2))) reaches 64. The error in // `_expRayToWad` exceeds 1ulp at that scale. if (x >= 0x8e383a2cdfa1b74a9422d2e1) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } - r = _expRayToWad(x); + return _expRayToWad(x); } /// @dev The rational polynomial approximation kernel From 384f015e2fc2cf877a31c47dd70c1f42dcaa4993 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 19:55:19 +0200 Subject: [PATCH 131/149] Request the Yul IR from every compile in generate_from_forge.sh forge inspect ... ir trusts whatever artifact the compile cache serves for the target; an artifact compiled without the ir extra output makes it fail with "IR output missing from artifact" instead of recompiling. The script's methodIdentifiers inspection compiles such artifacts, so the second generate in a job -- the LnWrapper step of exp-formal.yml, whose sources share Panic.sol with the ExpWrapper step before it -- hit that failure. Setting FOUNDRY_EXTRA_OUTPUT='["ir"]' on every invocation keeps the cache's artifact settings uniform across both inspections and across successive runs, in CI and against a developer's existing cache. The emitted Yul is unchanged: the generated runtime modules are byte-identical for the exp and ln wrappers. Co-Authored-By: Claude Fable 5 --- formal/yul/generate_from_forge.sh | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/formal/yul/generate_from_forge.sh b/formal/yul/generate_from_forge.sh index 20cfbfaef..9a633b185 100755 --- a/formal/yul/generate_from_forge.sh +++ b/formal/yul/generate_from_forge.sh @@ -25,12 +25,20 @@ case "$kind" in *) echo "unknown kind: $kind" >&2; exit 2 ;; esac +# Every compile this script triggers must request the Yul IR artifact. `forge +# inspect ... ir` trusts whatever artifact the compile cache serves for the +# target; once any compile in the same cache has produced an IR-less artifact +# for the target (e.g. the methodIdentifiers inspection, or a prior run of +# this script against another wrapper sharing sources), the ir inspection +# fails with "IR output missing from artifact" instead of recompiling. +# Requesting `ir` on every invocation keeps the cache's artifact settings +# uniform, so that failure mode cannot arise. inspect () { + local -a fenv=(FOUNDRY_EXTRA_OUTPUT='["ir"]') if [[ -n "$solc_version" ]]; then - FOUNDRY_SOLC_VERSION="$solc_version" forge inspect "$target" "$@" - else - forge inspect "$target" "$@" + fenv+=(FOUNDRY_SOLC_VERSION="$solc_version") fi + env "${fenv[@]}" forge inspect "$target" "$@" } actual="$(inspect methodIdentifiers | grep -oiE '\b[0-9a-f]{8}\b' | tr 'A-F' 'a-f' | sort -u | tr '\n' ' ' | sed 's/ $//' || true)" From 3891092bb028784c0c9f74fa50b55f1ebcd35c38 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 19:55:44 +0200 Subject: [PATCH 132/149] Share the exp granularity piece table between the generator and the proof The 32 granularity pieces (vlo, vhi, T, DOver, DUnder) live once, in the tracked leaf module Floor/GranPieces.lean. GenExpVLit.lean instantiates the per-piece certDOverP/certDUnderP cover certificates from that table (output byte-identical), and Floor/GranV proves the per-piece facts over the same entries: granPieces_ok establishes PieceOK for every table entry, the kernel-decided cover and cap facts (granPieces_cover via piecesCover, granPieces_caps) replace the literal piece dispatch, and piece_select picks the runtime point's piece through the cover, keeping its statement unchanged (GranPair and everything downstream are untouched). The K cap is carried as evalPoly Kpoly vhi, derived from the tracked Kpoly at the piece's upper edge rather than restated per piece. The certificate-generation step builds ExpProof.Floor.GranPieces alongside ExpProof.Floor.CertDefsV before running the generator (exp-formal.yml and the README build block). Full lake build is green from scratch through the Theorems.lean axiom gates; every public statement is unchanged. Co-Authored-By: Claude Fable 5 --- .github/workflows/exp-formal.yml | 2 +- formal/README.md | 2 +- .../ExpProof/ExpProof/Floor/GranPieces.lean | 49 + formal/exp/ExpProof/ExpProof/Floor/GranV.lean | 1225 ++++++++--------- formal/exp/ExpProof/GenExpVLit.lean | 46 +- 5 files changed, 599 insertions(+), 725 deletions(-) create mode 100644 formal/exp/ExpProof/ExpProof/Floor/GranPieces.lean diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index 673806282..a1c6f2e61 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -89,7 +89,7 @@ jobs: - name: Generate Lean certificate artifacts working-directory: formal/exp/ExpProof run: | - lake build ExpProof.Floor.CertDefsV Common.Foundation.KroneckerShift + lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces Common.Foundation.KroneckerShift lake env lean GenExpVLit.lean - name: Build Exp proof package diff --git a/formal/README.md b/formal/README.md index 3b041cbeb..d7ded6d50 100644 --- a/formal/README.md +++ b/formal/README.md @@ -148,7 +148,7 @@ cd formal/ln/LnProof && \ cd formal/exp/ExpProof && \ lake build ExpProof.ExpYulRuntime ExpProof.ExpYulProof && \ - lake build ExpProof.Floor.CertDefsV Common.Foundation.KroneckerShift && \ + lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces Common.Foundation.KroneckerShift && \ lake env lean GenExpVLit.lean && \ lake build ``` diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranPieces.lean b/formal/exp/ExpProof/ExpProof/Floor/GranPieces.lean new file mode 100644 index 000000000..ff6ad029c --- /dev/null +++ b/formal/exp/ExpProof/ExpProof/Floor/GranPieces.lean @@ -0,0 +1,49 @@ +/-! +# The 32-piece granularity domain split + +The single tracked source of the per-piece granularity constants. `GenExpVLit.lean` instantiates +and covers one `certDOverP`/`certDUnderP` pair per piece from this table, and `Floor/GranV` proves +the per-piece facts (`PieceOK`) over the same entries, so the generated covers and the proof +consume identical constants by construction. +-/ + +namespace ExpCertV + +/-- The 32 granularity pieces `(vlo, vhi, T, DOver, DUnder)`: the `v`-range, the piece `t`-cap +(`T² ≥ (vhi+1)·2^133`), and the floored denominators for the two halves. Each piece's floors are +certified over `[vlo, vhi + 1]` (the granularity step looks one cell ahead). -/ +def granPieces : List (Int × Int × Int × Int × Int) := [ + (0, 39914474797457073157829141722193111, 20847785078312632088902884100098393904, 650161701553, 691253358954), + (39914474797457073157829141722193111, 79828949594914146315658283444386223, 29483220403189161767243017845519310570, 641945658278, 700065691212), + (79828949594914146315658283444386223, 119743424392371219473487425166579335, 36109422980913784159270707268699614620, 635708060030, 706899646710), + (119743424392371219473487425166579335, 159657899189828292631316566888772447, 41695570156625264177805768200196787807, 630494171758, 712709960499), + (159657899189828292631316566888772447, 199572373987285365789145708610965559, 46617064615412821983671927489259435287, 625934238048, 717866387998), + (199572373987285365789145708610965559, 239486848784742438946974850333158671, 51066435709074987640046250875008841866, 621838651900, 722558536211), + (239486848784742438946974850333158671, 279401323582199512104803992055351783, 55158054703738454765934460694358669515, 618094793288, 726899025166), + (279401323582199512104803992055351783, 319315798379656585262633133777544895, 58966440806378323534486035691038621139, 614629293866, 730961223213), + (319315798379656585262633133777544895, 359230273177113658420462275499738007, 62543355234937896266708652300295181711, 611391198603, 734796085384), + (359230273177113658420462275499738007, 399144747974570731578291417221931119, 65926485017139723075679505829736200590, 608343412382, 738440706802), + (399144747974570731578291417221931119, 439059222772027804736120558944124231, 69144280814733066627417644920644591155, 605457935097, 741923087576), + (439059222772027804736120558944124231, 478973697569484877893949700666317343, 72218845961827568318541414537399229239, 602713016329, 745264978126), + (478973697569484877893949700666317343, 518888172366941951051778842388510455, 75167758079709234538337434275175078691, 600091361400, 748483673135), + (518888172366941951051778842388510455, 558802647164399024209607984110703567, 78005269036144011942405564982788931618, 597578949702, 751593193213), + (558802647164399024209607984110703567, 598717121961856097367437125832896679, 80743124413616312505576435261721815008, 595164227770, 754605091830), + (598717121961856097367437125832896679, 638631596759313170525266267555089791, 83391140313250528355611536400393575614, 592837541332, 757529023260), + (638631596759313170525266267555089791, 678546071556770243683095409277282902, 85957619938058733268340145980060814334, 590590725148, 760373152745), + (678546071556770243683095409277282902, 718460546354227316840924550999476014, 88449661209567485301729053536557931646, 588416800156, 763144459353), + (718460546354227316840924550999476014, 758375021151684389998753692721669126, 90873388353019950250431101958484117810, 586309745473, 765848963968), + (758375021151684389998753692721669126, 798289495949141463156582834443862238, 93234129230825643967343854978518870515, 584264323835, 768491903858), + (798289495949141463156582834443862238, 838203970746598536314411976166055350, 95536553193538501370371342040089081115, 582275945893, 771077868376), + (838203970746598536314411976166055350, 878118445544055609472241117888248462, 97784779688729301059274137358180034302, 580340563312, 773610905858), + (878118445544055609472241117888248462, 918032920341512682630070259610441574, 99982464869820254414073625773477941119, 578454583528, 776094608873), + (918032920341512682630070259610441574, 957947395138969755787899401332634686, 102132871418149975280092501750017683679, 576614801025, 778532182941), + (957947395138969755787899401332634686, 997861869936426828945728543054827798, 104238925391563160444514420500491969466, 574818341390, 780926502475), + (997861869936426828945728543054827798, 1037776344733883902103557684777020910, 106303262929504594869818257246985820007, 573062615355, 783280156749), + (1037776344733883902103557684777020910, 1077690819531340975261386826499214022, 108328268942741352477812121806098843808, 571345280717, 785595487968), + (1077690819531340975261386826499214022, 1117605294328798048419215968221407134, 110316109407476909531868921388717338981, 569664210570, 787874623042), + (1117605294328798048419215968221407134, 1157519769126255121577045109943600246, 112268758510433036404380164835338032221, 568017466591, 790119500297), + (1157519769126255121577045109943600246, 1197434243923712194734874251665793358, 114188021614114346553315397742450038434, 566403276447, 792331892069), + (1197434243923712194734874251665793358, 1237348718721169267892703393387986470, 116075554802968570681645777137735089747, 564820014566, 794513423933), + (1237348718721169267892703393387986470, 1277263193518626341050532535110179582, 117932881612756647068972071382077242231, 563266185678, 796665591163)] + +end ExpCertV diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean index 22a951cd7..2c6908ae2 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean @@ -1,5 +1,6 @@ import ExpProof.Floor.R0Bound import ExpProof.Floor.CapsV +import ExpProof.Floor.GranPieces import ExpProof.Cert.ExpVDOver import ExpProof.Cert.ExpVDOvP00 import ExpProof.Cert.ExpVDUnP00 @@ -389,10 +390,9 @@ theorem KpM_nonneg (v : Nat) : 0 ≤ KpM v := by exact evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (Int.natCast_nonneg _) /-- `K` is nondecreasing on the grid (positive coefficients), so a piece's upper edge caps it. -/ -theorem KpM_le_at {v vhi : Nat} (hv : v ≤ vhi) {Khi : Int} - (heval : evalPoly Kpoly (vhi : Int) = Khi) : KpM v ≤ Khi := by - rw [KpM_eq_poly, ← heval] - exact evalPoly_mono_of_nonneg Kpoly_coeffs_nonneg (Int.natCast_nonneg _) (by exact_mod_cast hv) +theorem KpM_le_at {v : Nat} {vhi : Int} (hv : (v : Int) ≤ vhi) : KpM v ≤ evalPoly Kpoly vhi := by + rw [KpM_eq_poly] + exact evalPoly_mono_of_nonneg Kpoly_coeffs_nonneg (Int.natCast_nonneg _) hv /-- **The discrete quotient identity**: one grid step of the aligned rational is exact algebra. -/ theorem step_identity (v : Nat) (t : Int) : @@ -667,619 +667,537 @@ def PieceOK (v : Nat) (T DO DU Khi : Int) : Prop := /-- The piece cap dominates the square: from the split `t² < 2^133·v + 2^133`, membership `v ≤ vhi`, and the cap fact `2^133·(vhi + 1) ≤ T²`. -/ theorem tsq_lt_capsq {t : Int} {v : Nat} (hsplit : t ^ 2 < 2 ^ 133 * (v : Int) + 2 ^ 133) - {vhi : Nat} (hv : v ≤ vhi) {T : Int} - (hT : 2 ^ 133 * ((vhi : Nat) : Int) + 2 ^ 133 ≤ T ^ 2) : + {vhi : Int} (hv : (v : Int) ≤ vhi) {T : Int} + (hT : 2 ^ 133 * vhi + 2 ^ 133 ≤ T ^ 2) : t ^ 2 < T ^ 2 := by - have hvI : ((v : Nat) : Int) ≤ ((vhi : Nat) : Int) := by exact_mod_cast hv - nlinarith [hsplit, hT, hvI] - -theorem granPiece00 {v : Nat} (hlo : 0 ≤ v) - (hhi : v ≤ 39914474797457073157829141722193111) : - PieceOK v 20847785078312632088902884100098393904 650161701553 691253358954 - 124331295357477641581904138056792287020328920739682114857664357354828442875869025295095260106579486090794973807518308090512373664288724599481183645678243760168249900040574863180675819774653612798639898143210993293324267181199503250600403357996412545035325722827268263235801420237458721567675109488896589057678111549643018134304154993533622467567878144 := by - have hvlo : (0 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (39914474797457073157829141722193111 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP00_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP00_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP00_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP00_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece01 {v : Nat} (hlo : 39914474797457073157829141722193111 ≤ v) - (hhi : v ≤ 79828949594914146315658283444386223) : - PieceOK v 29483220403189161767243017845519310570 641945658278 700065691212 - 124348489536362811569823373638009000631667158096130666095582598399588448399876764381232405323636520833790009233576804961032917177931334727395109926278389044009567787762950649201982921306130024347784555916617412077827586978026950159438110911930706312161198243458825239986622498328512019492013159710459919171534255316797621253672688089454967194376994816 := by - have hvlo : (39914474797457073157829141722193111 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (79828949594914146315658283444386223 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP01_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP01_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP01_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP01_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece02 {v : Nat} (hlo : 79828949594914146315658283444386223 ≤ v) - (hhi : v ≤ 119743424392371219473487425166579335) : - PieceOK v 36109422980913784159270707268699614620 635708060030 706899646710 - 124365685902235707931662185236865182628053618073184713460247915523785590877700978509232142340905979095147288222533178910762560856667920293458238258376258151566628589949793659760772938934721283732147475148813094180263002559134506224431737786068252674285070073042702412156288743997299619998620649343861387292828263704160125292993790052190201592961630208 := by - have hvlo : (79828949594914146315658283444386223 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (119743424392371219473487425166579335 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP02_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP02_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP02_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP02_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece03 {v : Nat} (hlo : 119743424392371219473487425166579335 ≤ v) - (hhi : v ≤ 159657899189828292631316566888772447) : - PieceOK v 41695570156625264177805768200196787807 630494171758 712709960499 - 124382884455293592549521181635541090166983243381366801077634704386449155123538147775095644383601673251595741250522853679574835669070847383007608443452883503401958520975393281340104778870044828386724379056340673155550940420245984273438033970455973764538100904452446937706327654059882649333342250388341747084762611362343708770595139697547437718802268160 := by - have hvlo : (119743424392371219473487425166579335 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (159657899189828292631316566888772447 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP03_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP03_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP03_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP03_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece04 {v : Nat} (hlo : 159657899189828292631316566888772447 ≤ v) - (hhi : v ≤ 199572373987285365789145708610965559) : - PieceOK v 46617064615412821983671927489259435287 625934238048 717866387998 - 124400085195733739761025602560746264278616327664634676182714279775205998993015648254637590643537148550327888188208261194060492726583694561054370906623381684559581344625217362931467757553311495193356235609856263696492370325585701457614481355682705860334329988295937236347726204889864872718037319011296191356466375193232176092864574154432488170961567744 := by - have hvlo : (159657899189828292631316566888772447 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (199572373987285365789145708610965559 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP04_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP04_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP04_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP04_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece05 {v : Nat} (hlo : 199572373987285365789145708610965559 ≤ v) - (hhi : v ≤ 239486848784742438946974850333158671) : - PieceOK v 51066435709074987640046250875008841866 621838651900 722558536211 - 124417288123753436359835347518639131950249764195910712565839043606640499191676068467176975973602845905061591734256371371103126949086855419317934911533825904835688101580924850386714202151580739880884301210530166827007365319166903338988033945677286795960322070677949568801220865415748091974787433067612090788738328422094161653434502497346696847251472384 := by - have hvlo : (199572373987285365789145708610965559 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (239486848784742438946974850333158671 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP05_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP05_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP05_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP05_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece06 {v : Nat} (hlo : 239486848784742438946974850333158671 ≤ v) - (hhi : v ≤ 279401323582199512104803992055351783) : - PieceOK v 55158054703738454765934460694358669515 618094793288 726899025166 - 124434493239549981596155017198872213098454764998568650821632835242999466335788378628546409502791047296403032067730444905302684600204546104057200490811476284704813315263361171252130107427929606736210745667903934480980096706370969525764751373103018335410042751956297398979863880642988644489413669262837966594493347115533922961077511275265630319091449856 := by - have hvlo : (239486848784742438946974850333158671 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (279401323582199512104803992055351783 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP06_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP06_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP06_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP06_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece07 {v : Nat} (hlo : 279401323582199512104803992055351783 ≤ v) - (hhi : v ≤ 319315798379656585262633133777544895) : - PieceOK v 58966440806378323534486035691038621139 614629293866 730961223213 - 124451700543320687177243967447907493738634686713280628775100983611975805202752040889353877413014375516832698931548482651718513021265559009370228602810259469061747536661164515780773577557318528060603071915307121370309066625679902290704035239727413694095262005826377985200395700851400403348591051117166980795442448657546058790199544851673655003010039808 := by - have hvlo : (279401323582199512104803992055351783 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (319315798379656585262633133777544895 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP07_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP07_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP07_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP07_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece08 {v : Nat} (hlo : 319315798379656585262633133777544895 ≤ v) - (hhi : v ≤ 359230273177113658420462275499738007) : - PieceOK v 62543355234937896266708652300295181711 611391198603 734796085384 - 124468910035262877267926375811746527820975306698922635425840511894904787143595947811096724002989298686672217212850128746563838558316488647056623737058434359811261359426985503361599249033910735301816371731468685286395592499639857246867579557693036893681604611310616417652470415124037663243490099281703786843208686442477137477570980613863363719996702720 := by - have hvlo : (319315798379656585262633133777544895 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (359230273177113658420462275499738007 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP08_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP08_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP08_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP08_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece09 {v : Nat} (hlo : 359230273177113658420462275499738007 ≤ v) - (hhi : v ≤ 399144747974570731578291417221931119) : - PieceOK v 65926485017139723075679505829736200590 608343412382 738440706802 - 124486121715573888491101320648219831360978600025531681717397876827306892665309875389393384048481768653425841939803068139643786342072540530559822902480426047209561307177697067146275358391575766288843286569489630219937769323348732794039548321162137129920186263470953090477298031369179281491517916152969142359753029790232869618689856252942753648165781504 := by - have hvlo : (359230273177113658420462275499738007 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (399144747974570731578291417221931119 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP09_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP09_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP09_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP09_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece10 {v : Nat} (hlo : 399144747974570731578291417221931119 ≤ v) - (hhi : v ≤ 439059222772027804736120558944124231) : - PieceOK v 69144280814733066627417644920644591155 605457935097 741923087576 - 124503335584451069928252872808980133651989775186603141404988555934311273225981935990264178352237801072926478468069242743489283246177418736929404644129855308733243265589345733196988586035281255492337370426875119924531347417976092688100894991354677828964594141904176367929784428502523428286373737126082244818656262835605108546925443459326996088449204224 := by - have hvlo : (399144747974570731578291417221931119 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (439059222772027804736120558944124231 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP10_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP10_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP10_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP10_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece11 {v : Nat} (hlo : 439059222772027804736120558944124231 ≤ v) - (hhi : v ≤ 478973697569484877893949700666317343) : - PieceOK v 72218845961827568318541414537399229239 602713016329 745264978126 - 124520551642091783119960199891344051506346033527311875260959727302093972320951315622058263260947483656752103483840493935299413014630172637166451445835836333123354402531969814020920275057050896729991379522855922790213174946038953724627140431546256563282790729321557975220766789962190285045276381221546310035474840890128611108344299521825576877289373696 := by - have hvlo : (439059222772027804736120558944124231 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (478973697569484877893949700666317343 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP11_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP11_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP11_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP11_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece12 {v : Nat} (hlo : 478973697569484877893949700666317343 ≤ v) - (hhi : v ≤ 518888172366941951051778842388510455) : - PieceOK v 75167758079709234538337434275175078691 600091361400 748483673135 - 124537769888693402066407683060126753630994224554535911823544217765065136973421379022289603810616577756414482304042522678965020214723268111737918587829660616124019790143784379899466091486140170232387841381760682133717066154372228166965327582139308493893339685755904415758459311234618014480863534215048472382060547521413140374874865461769524694558507008 := by - have hvlo : (478973697569484877893949700666317343 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (518888172366941951051778842388510455 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP12_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP12_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP12_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP12_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece13 {v : Nat} (hlo : 518888172366941951051778842388510455 ≤ v) - (hhi : v ≤ 558802647164399024209607984110703567) : - PieceOK v 78005269036144011942405564982788931618 597578949702 751593193213 - 124554990324453313227895046439614183402643276463856617860620826667139541778214025095310619045745557140858097807995342065606587337322533394468882240084030263306935213398607214962659659999055128481075083753732139252846167979947868188032272919467882501275172597180793487630740957574925310783905297794170644686405700341432141068220616476957382929185505280 := by - have hvlo : (518888172366941951051778842388510455 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (558802647164399024209607984110703567 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP13_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP13_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP13_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP13_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece14 {v : Nat} (hlo : 558802647164399024209607984110703567 ≤ v) - (hhi : v ≤ 598717121961856097367437125832896679) : - PieceOK v 80743124413616312505576435261721815008 595164227770 754605091830 - 124572212949568915525347499075817409466735988388004451686363063634024838682581974293417926941741606509843226188507680602219637031806014514444459283762049224244872920374774308501649176691013237726857731636612069833000109322912017234062636495543175662919935430568420743292434031610801823061616938660393534826247558241784867596685707613532519179226251264 := by - have hvlo : (558802647164399024209607984110703567 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (598717121961856097367437125832896679 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP14_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP14_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP14_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP14_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece15 {v : Nat} (hlo : 598717121961856097367437125832896679 ≤ v) - (hhi : v ≤ 638631596759313170525266267555089791) : - PieceOK v 83391140313250528355611536400393575614 592837541332 757529023260 - 124589437764237620340825889469153674743743478040514552434825270072062036723231468590650395244014780971823114564072078109181139128465160131976111064838226271169192340088167775554464468086418974592526508495351327534529428960424730857521734109493908231115773540654136507544239294024475729934998271889261575071337487560484493736830994727238304877368049664 := by - have hvlo : (598717121961856097367437125832896679 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (638631596759313170525266267555089791 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP15_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP15_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP15_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP15_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece16 {v : Nat} (hlo : 638631596759313170525266267555089791 ≤ v) - (hhi : v ≤ 678546071556770243683095409277282902) : - PieceOK v 85957619938058733268340145980060814334 590590725148 760373152745 - 124606664768656851518036872677698715585072660242495883986009404890147362516004161739630680550417490341371797531129102305738763492805064552636381614815576193227674230986790052469783804926104175636072026017497532913712764135972392518808738959695402684214634690318526071631420652836377713510044584171075898860077101066298649153619546421349176320735146240 := by - have hvlo : (638631596759313170525266267555089791 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (678546071556770243683095409277282902 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP16_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP16_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP16_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP16_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece17 {v : Nat} (hlo : 678546071556770243683095409277282902 ≤ v) - (hhi : v ≤ 718460546354227316840924550999476014) : - PieceOK v 88449661209567485301729053536557931646 588416800156 763144459353 - 124623893963024045362843089991154923983117161607319595250352276881176522492194884460613602543396335504591097167825116970547969978539214562134291228254489780808179367553929062370966123062130918023648372481946314641375078442083168666134142802373602001339140773737530082849770581207983047544000442080270054092120631736071247951487235378516868923389575424 := by - have hvlo : (678546071556770243683095409277282902 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (718460546354227316840924550999476014 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP17_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP17_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP17_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP17_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece18 {v : Nat} (hlo : 718460546354227316840924550999476014 ≤ v) - (hhi : v ≤ 758375021151684389998753692721669126) : - PieceOK v 90873388353019950250431101958484117810 586309745473 765848963968 - 124641125347536650643773361175679926890136980575009349858406217274206787157703076060760159328132847795954730513979593904465877332579468208634643270080823067198699615091677996267451877154545985645750394641445535218127962690400435113781818788548560000033757028278051636102985402707506385563404221303398065990638629109910072511299669406189628394175746304 := by - have hvlo : (718460546354227316840924550999476014 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (758375021151684389998753692721669126 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP18_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP18_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP18_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP18_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece19 {v : Nat} (hlo : 758375021151684389998753692721669126 ≤ v) - (hhi : v ≤ 798289495949141463156582834443862238) : - PieceOK v 93234129230825643967343854978518870515 584264323835 768491903858 - 124658358922392128592532889289720157874976973585349126591994191589414143318317674249585953939689445877907213043541773343109004895170973418880732978969822834172603369724256116429567360678907949821785338291542213555676264600392085383654932815516512038924179692395697310049431946123044099632008145784092080082008997282395902899780773760707018755557253376 := by - have hvlo : (758375021151684389998753692721669126 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (798289495949141463156582834443862238 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP19_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP19_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP19_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP19_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece20 {v : Nat} (hlo : 798289495949141463156582834443862238 ≤ v) - (hhi : v ≤ 838203970746598536314411976166055350) : - PieceOK v 95536553193538501370371342040089081115 582275945893 771077868376 - 124675594687787952904513478070993997490747165237763127035427566697901602250251952214812407209685403872705846247477937047935221784504131219775890895308710226597840163524000974576243137476334383522428088205286797851946215689878018940255286367216193327977552796517938163227068652880076009442161336421787011377599536749774501652579713675135944281723646208 := by - have hvlo : (798289495949141463156582834443862238 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (838203970746598536314411976166055350 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP20_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP20_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP20_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP20_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece21 {v : Nat} (hlo : 838203970746598536314411976166055350 ≤ v) - (hhi : v ≤ 878118445544055609472241117888248462) : - PieceOK v 97784779688729301059274137358180034302 580340563312 773610905858 - 124692832643921609739303761894769059894869896935808653881092735350101587531430032270103876036884746059379184271665190236600427580654736038041033275582180880754632701237253832037879523775618655172970200553493385481080830204492902307986942299213350413599465132724297678377243046317980489697735516365263070803702961102484141857844356429316185731112812800 := by - have hvlo : (838203970746598536314411976166055350 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (878118445544055609472241117888248462 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP21_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP21_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP21_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP21_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece22 {v : Nat} (hlo : 878118445544055609472241117888248462 ≤ v) - (hhi : v ≤ 918032920341512682630070259610441574) : - PieceOK v 99982464869820254414073625773477941119 578454583528 776094608873 - 124710072790990597721199448303578204419096487383493075972991988236652404616688783744159514396070007044240287824345887307801597044260536584308823059040717802692047418498078277708138651227072800784330541158563593883567212800396557524991247542232380730500213376057729041528063562241291700217040789465713509633913187647063710417510471795210628415965565184 := by - have hvlo : (878118445544055609472241117888248462 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (918032920341512682630070259610441574 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP22_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP22_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP22_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP22_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece23 {v : Nat} (hlo : 918032920341512682630070259610441574 ≤ v) - (hhi : v ≤ 957947395138969755787899401332634686) : - PieceOK v 102132871418149975280092501750017683679 576614801025 778532182941 - 124727315129192427939713573108518851946746355961540412921623053526083995615369518787406156400695076250720100747414363107465415917032881745828700866616473650876388076205731326151647966692684964360547083172536492161275217469372676434156363226735329424653290080027222154454409639118762860054603295412526333649666966810986577471067570715716735210740850944 := by - have hvlo : (918032920341512682630070259610441574 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (957947395138969755787899401332634686 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP23_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP23_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP23_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP23_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece24 {v : Nat} (hlo : 957947395138969755787899401332634686 ≤ v) - (hhi : v ≤ 997861869936426828945728543054827798) : - PieceOK v 104238925391563160444514420500491969466 574818341390 780926502475 - 124744559658724623950086768062280187113640267181028232089748655102248273765009698829204279618836024260322304499496915014301962516688500738379965223716524366256202176396180621776988492113153599027805245602558636322821111864671816950930814484595369147288875282103336550254160949808787471699319045469454297801346819930501072096316219218429756015474831616 := by - have hvlo : (957947395138969755787899401332634686 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (997861869936426828945728543054827798 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP24_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP24_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP24_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP24_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece25 {v : Nat} (hlo : 997861869936426828945728543054827798 ≤ v) - (hhi : v ≤ 1037776344733883902103557684777020910) : - PieceOK v 106303262929504594869818257246985820007 573062615355 783280156749 - 124761806379784721773797541104042828508418061581110710714774372003029423130080663475144885725984487222537025652475264653903117504372851594413000910188341381740535255592335718526729635348334323826293981939499884365304112855169895086556973937458785015484930468250012152902743640195218386165140743123333051189013159768094053531385601709182103604421886208 := by - have hvlo : (997861869936426828945728543054827798 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (1037776344733883902103557684777020910 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP25_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP25_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP25_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP25_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece26 {v : Nat} (hlo : 1037776344733883902103557684777020910 ≤ v) - (hhi : v ≤ 1077690819531340975261386826499214022) : - PieceOK v 108328268942741352477812121806098843808 571345280717 785595487968 - 124779055292570269899072569176395550207149945606838875899620012840469640089953192690680914462253864237586791356793011581725611868132856890861674052417374931958913382272035748078660810463609033602416655977972300619097870804628644144326794634936383430538313658777665592770608423623112584549096894351992861228505372852729716292034044933517264204570415360 := by - have hvlo : (1037776344733883902103557684777020910 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (1077690819531340975261386826499214022 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP26_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP26_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP26_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP26_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece27 {v : Nat} (hlo : 1077690819531340975261386826499214022 ≤ v) - (hhi : v ≤ 1117605294328798048419215968221407134) : - PieceOK v 110316109407476909531868921388717338981 569664210570 787874623042 - 124796306397278829281397003614413639136369120172384195170136650261045884215508512174002585745594261301914147584573874806458850831483230446492832284181686273043379455747210133094758593510660561935119569748541092023013191742059770145448509959312139940918154391044235561210772363529417536390085012612494904915323547482551416688009151037590549562881138944 := by - have hvlo : (1077690819531340975261386826499214022 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (1117605294328798048419215968221407134 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP27_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP27_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP27_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP27_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece28 {v : Nat} (hlo : 1117605294328798048419215968221407134 ≤ v) - (hhi : v ≤ 1157519769126255121577045109943600246) : - PieceOK v 112268758510433036404380164835338032221 568017466591 790119500297 - 124813559694107973344024788107043473917872234784266850263288391783433297169048150877731843676637794092356374813269801556437879061596983545081768014553611911044754174402003345596816607427109899526336836315448152237782498258409790180099419767003797832223547387772496458446073160169102979920523224045308674145374435976269957371998125303322935675350397184 := by - have hvlo : (1117605294328798048419215968221407134 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (1157519769126255121577045109943600246 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP28_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP28_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP28_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP28_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece29 {v : Nat} (hlo : 1157519769126255121577045109943600246 ≤ v) - (hhi : v ≤ 1197434243923712194734874251665793358) : - PieceOK v 114188021614114346553315397742450038434 566403276447 792331892069 - 124830815183255287978488989230937912007852861268485186776484894629691039297391858695676855054821540550988755666246306222922080217137084067125422552803488226467137811892029054090053797255446672981786118025700422746450741633997798018226283790557025622187443712993615360108301740842729954061587078784532601098337144505997415684452821275968171765255782656 := by - have hvlo : (1157519769126255121577045109943600246 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (1197434243923712194734874251665793358 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP29_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP29_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP29_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP29_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece30 {v : Nat} (hlo : 1197434243923712194734874251665793358 ≤ v) - (hhi : v ≤ 1237348718721169267892703393387986470) : - PieceOK v 116075554802968570681645777137735089747 564820014566 794513423933 - 124848072864918371545112139556887073102151888314737992274617563444406384623288591387553293909461112918653868880401685945220431541232626739228028551925510171276514210561293346598405224457657291404585578627906913330891689370353658953641245078501638134388438230868583098903895936536936896771400874658745568736075948590821250687327963145587281512196247808 := by - have hvlo : (1197434243923712194734874251665793358 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (1237348718721169267892703393387986470 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP30_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP30_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP30_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP30_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ - -theorem granPiece31 {v : Nat} (hlo : 1237348718721169267892703393387986470 ≤ v) - (hhi : v ≤ 1277263193518626341050532535110179582) : - PieceOK v 117932881612756647068972071382077242231 563266185678 796665591163 - 124865332739294834873516593328989107938627445220226415417519301074933005975501368871244922433473497551230403824606042833804361870589257536716807944070843003611163671987701060317587976677928870720398225511779857554302723969319393493947608003945282319951972195880806029003395011394810609114195299961562530515199537076949072909524942387258516947793649920 := by - have hvlo : (1237348718721169267892703393387986470 : Int) ≤ (v : Int) := by exact_mod_cast hlo - have hvhi : (v : Int) ≤ (1277263193518626341050532535110179582 : Int) := by exact_mod_cast hhi - have hOv := ExpCertV.dOvP31_nonneg (t := (v : Int)) (by omega) (by omega) - have hOv1 := ExpCertV.dOvP31_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hUn := ExpCertV.dUnP31_nonneg (t := (v : Int)) (by omega) (by omega) - have hUn1 := ExpCertV.dUnP31_nonneg (t := (v : Int) + 1) (by omega) (by omega) - have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring - rw [evalDOverP] at hOv - rw [evalDUnderP] at hUn - rw [hcast, evalDOverP] at hOv1 - rw [hcast, evalDUnderP] at hUn1 - refine ⟨by norm_num, by norm_num, by norm_num, by norm_num, by linarith [hOv], - by linarith [hOv1], by linarith [hUn], by linarith [hUn1], - KpM_le_at hhi (by simp only [Kpoly, evalPoly]; norm_num), by norm_num, by norm_num⟩ + nlinarith [hsplit, hT, hv] + +/-- The per-piece granularity facts for one entry `(vlo, vhi, T, DO, DU)` of the shared table +`ExpCertV.granPieces`, with the `K` cap at the piece's upper edge. -/ +def PieceHolds : Int × Int × Int × Int × Int → Prop + | (vlo, vhi, T, DO, DU) => + ∀ v : Nat, vlo ≤ (v : Int) → (v : Int) ≤ vhi → + PieceOK v T DO DU (evalPoly Kpoly vhi) + +/-- Each piece's `t`-cap dominates its `v`-range: `(vhi + 1)·2^133 ≤ T²`. -/ +theorem granPieces_caps : + ∀ p ∈ ExpCertV.granPieces, 2 ^ 133 * p.2.1 + 2 ^ 133 ≤ p.2.2.1 ^ 2 := by + decide +kernel + +/-- `piecesCover lo hi ps`: the pieces' closed `v`-ranges, in table order, cover `[lo, hi]`. -/ +def piecesCover (lo hi : Int) : List (Int × Int × Int × Int × Int) → Bool + | [] => false + | p :: rest => decide (p.1 ≤ lo) && (decide (hi ≤ p.2.1) || piecesCover (p.2.1 + 1) hi rest) + +/-- A point of `[lo, hi]` lands inside one of the covering pieces' closed ranges. -/ +theorem piecesCover_sound {ps : List (Int × Int × Int × Int × Int)} {hi v : Int} + (hhi : v ≤ hi) : ∀ lo : Int, piecesCover lo hi ps = true → lo ≤ v → + ∃ p ∈ ps, p.1 ≤ v ∧ v ≤ p.2.1 := by + induction ps with + | nil => intro lo h _; simp [piecesCover] at h + | cons p rest ih => + intro lo h hlo + simp only [piecesCover, Bool.and_eq_true, Bool.or_eq_true, decide_eq_true_eq] at h + obtain ⟨h1, h2⟩ := h + rcases le_or_gt v p.2.1 with hv | hv + · exact ⟨p, List.mem_cons_self, le_trans h1 hlo, hv⟩ + · rcases h2 with h2 | h2 + · omega + · obtain ⟨q, hq, hql, hqh⟩ := ih _ h2 (by omega) + exact ⟨q, List.mem_cons_of_mem _ hq, hql, hqh⟩ + +/-- The 32 pieces cover the whole certified grid `[0, vmaxV]`. -/ +theorem granPieces_cover : + piecesCover 0 (ExpCertV.vmaxV : Int) ExpCertV.granPieces = true := by + decide +kernel + +/-- Every entry of the shared table satisfies its per-piece facts: the cover-certified denominator +floors at `v` and `v + 1`, the `K` cap at the piece's upper edge, and the certified budget +inequalities. -/ +theorem granPieces_ok : ∀ p ∈ ExpCertV.granPieces, PieceHolds p := by + intro p hp + simp only [ExpCertV.granPieces, List.mem_cons, List.not_mem_nil, or_false] at hp + rcases hp with rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl + · intro v hlo hhi + have hOv := ExpCertV.dOvP00_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP00_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP00_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP00_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP01_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP01_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP01_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP01_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP02_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP02_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP02_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP02_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP03_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP03_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP03_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP03_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP04_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP04_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP04_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP04_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP05_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP05_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP05_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP05_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP06_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP06_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP06_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP06_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP07_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP07_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP07_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP07_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP08_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP08_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP08_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP08_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP09_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP09_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP09_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP09_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP10_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP10_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP10_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP10_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP11_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP11_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP11_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP11_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP12_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP12_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP12_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP12_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP13_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP13_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP13_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP13_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP14_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP14_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP14_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP14_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP15_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP15_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP15_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP15_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP16_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP16_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP16_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP16_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP17_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP17_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP17_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP17_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP18_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP18_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP18_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP18_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP19_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP19_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP19_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP19_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP20_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP20_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP20_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP20_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP21_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP21_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP21_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP21_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP22_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP22_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP22_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP22_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP23_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP23_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP23_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP23_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP24_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP24_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP24_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP24_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP25_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP25_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP25_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP25_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP26_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP26_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP26_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP26_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP27_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP27_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP27_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP27_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP28_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP28_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP28_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP28_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP29_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP29_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP29_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP29_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP30_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP30_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP30_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP30_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ + · intro v hlo hhi + have hOv := ExpCertV.dOvP31_nonneg (t := (v : Int)) (by omega) (by omega) + have hOv1 := ExpCertV.dOvP31_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hUn := ExpCertV.dUnP31_nonneg (t := (v : Int)) (by omega) (by omega) + have hUn1 := ExpCertV.dUnP31_nonneg (t := (v : Int) + 1) (by omega) (by omega) + have hcast : ((v : Int) + 1) = (((v + 1 : Nat)) : Int) := by push_cast; ring + rw [evalDOverP] at hOv + rw [evalDUnderP] at hUn + rw [hcast, evalDOverP] at hOv1 + rw [hcast, evalDUnderP] at hUn1 + refine ⟨by norm_num, by norm_num, + evalPoly_nonneg_of_nonneg Kpoly_coeffs_nonneg (by norm_num), by norm_num, + by linarith [hOv], by linarith [hOv1], by linarith [hUn], by linarith [hUn1], + KpM_le_at hhi, by simp only [Kpoly, evalPoly]; norm_num, + by simp only [Kpoly, evalPoly]; norm_num⟩ /-- **Piece selection.** The runtime grid point lies in one of the 32 pieces, whose certified constants apply, and the piece's `t`-cap dominates the reduced argument: `t² < T²`. -/ @@ -1288,72 +1206,13 @@ theorem piece_select {x : Nat} (hx : x < 2 ^ 256) ∃ T DO DU Khi : Int, PieceOK (vTree x) T DO DU Khi ∧ (int256 (tTree x)) ^ 2 < T ^ 2 := by obtain ⟨_, hsplit⟩ := tsq_split hx hC hC0 - have hvmax := vTree_le_vmax hx hC hC0 - have hvmax' : vTree x ≤ 1277263193518626341050532535110179582 := by - unfold ExpCertV.vmaxV at hvmax; omega - rcases le_or_gt (vTree x) 39914474797457073157829141722193111 with h00 | h00 - · exact ⟨_, _, _, _, granPiece00 (Nat.zero_le _) h00, tsq_lt_capsq hsplit h00 (by norm_num)⟩ - rcases le_or_gt (vTree x) 79828949594914146315658283444386223 with h01 | h01 - · exact ⟨_, _, _, _, granPiece01 (Nat.le_of_lt h00) h01, tsq_lt_capsq hsplit h01 (by norm_num)⟩ - rcases le_or_gt (vTree x) 119743424392371219473487425166579335 with h02 | h02 - · exact ⟨_, _, _, _, granPiece02 (Nat.le_of_lt h01) h02, tsq_lt_capsq hsplit h02 (by norm_num)⟩ - rcases le_or_gt (vTree x) 159657899189828292631316566888772447 with h03 | h03 - · exact ⟨_, _, _, _, granPiece03 (Nat.le_of_lt h02) h03, tsq_lt_capsq hsplit h03 (by norm_num)⟩ - rcases le_or_gt (vTree x) 199572373987285365789145708610965559 with h04 | h04 - · exact ⟨_, _, _, _, granPiece04 (Nat.le_of_lt h03) h04, tsq_lt_capsq hsplit h04 (by norm_num)⟩ - rcases le_or_gt (vTree x) 239486848784742438946974850333158671 with h05 | h05 - · exact ⟨_, _, _, _, granPiece05 (Nat.le_of_lt h04) h05, tsq_lt_capsq hsplit h05 (by norm_num)⟩ - rcases le_or_gt (vTree x) 279401323582199512104803992055351783 with h06 | h06 - · exact ⟨_, _, _, _, granPiece06 (Nat.le_of_lt h05) h06, tsq_lt_capsq hsplit h06 (by norm_num)⟩ - rcases le_or_gt (vTree x) 319315798379656585262633133777544895 with h07 | h07 - · exact ⟨_, _, _, _, granPiece07 (Nat.le_of_lt h06) h07, tsq_lt_capsq hsplit h07 (by norm_num)⟩ - rcases le_or_gt (vTree x) 359230273177113658420462275499738007 with h08 | h08 - · exact ⟨_, _, _, _, granPiece08 (Nat.le_of_lt h07) h08, tsq_lt_capsq hsplit h08 (by norm_num)⟩ - rcases le_or_gt (vTree x) 399144747974570731578291417221931119 with h09 | h09 - · exact ⟨_, _, _, _, granPiece09 (Nat.le_of_lt h08) h09, tsq_lt_capsq hsplit h09 (by norm_num)⟩ - rcases le_or_gt (vTree x) 439059222772027804736120558944124231 with h10 | h10 - · exact ⟨_, _, _, _, granPiece10 (Nat.le_of_lt h09) h10, tsq_lt_capsq hsplit h10 (by norm_num)⟩ - rcases le_or_gt (vTree x) 478973697569484877893949700666317343 with h11 | h11 - · exact ⟨_, _, _, _, granPiece11 (Nat.le_of_lt h10) h11, tsq_lt_capsq hsplit h11 (by norm_num)⟩ - rcases le_or_gt (vTree x) 518888172366941951051778842388510455 with h12 | h12 - · exact ⟨_, _, _, _, granPiece12 (Nat.le_of_lt h11) h12, tsq_lt_capsq hsplit h12 (by norm_num)⟩ - rcases le_or_gt (vTree x) 558802647164399024209607984110703567 with h13 | h13 - · exact ⟨_, _, _, _, granPiece13 (Nat.le_of_lt h12) h13, tsq_lt_capsq hsplit h13 (by norm_num)⟩ - rcases le_or_gt (vTree x) 598717121961856097367437125832896679 with h14 | h14 - · exact ⟨_, _, _, _, granPiece14 (Nat.le_of_lt h13) h14, tsq_lt_capsq hsplit h14 (by norm_num)⟩ - rcases le_or_gt (vTree x) 638631596759313170525266267555089791 with h15 | h15 - · exact ⟨_, _, _, _, granPiece15 (Nat.le_of_lt h14) h15, tsq_lt_capsq hsplit h15 (by norm_num)⟩ - rcases le_or_gt (vTree x) 678546071556770243683095409277282902 with h16 | h16 - · exact ⟨_, _, _, _, granPiece16 (Nat.le_of_lt h15) h16, tsq_lt_capsq hsplit h16 (by norm_num)⟩ - rcases le_or_gt (vTree x) 718460546354227316840924550999476014 with h17 | h17 - · exact ⟨_, _, _, _, granPiece17 (Nat.le_of_lt h16) h17, tsq_lt_capsq hsplit h17 (by norm_num)⟩ - rcases le_or_gt (vTree x) 758375021151684389998753692721669126 with h18 | h18 - · exact ⟨_, _, _, _, granPiece18 (Nat.le_of_lt h17) h18, tsq_lt_capsq hsplit h18 (by norm_num)⟩ - rcases le_or_gt (vTree x) 798289495949141463156582834443862238 with h19 | h19 - · exact ⟨_, _, _, _, granPiece19 (Nat.le_of_lt h18) h19, tsq_lt_capsq hsplit h19 (by norm_num)⟩ - rcases le_or_gt (vTree x) 838203970746598536314411976166055350 with h20 | h20 - · exact ⟨_, _, _, _, granPiece20 (Nat.le_of_lt h19) h20, tsq_lt_capsq hsplit h20 (by norm_num)⟩ - rcases le_or_gt (vTree x) 878118445544055609472241117888248462 with h21 | h21 - · exact ⟨_, _, _, _, granPiece21 (Nat.le_of_lt h20) h21, tsq_lt_capsq hsplit h21 (by norm_num)⟩ - rcases le_or_gt (vTree x) 918032920341512682630070259610441574 with h22 | h22 - · exact ⟨_, _, _, _, granPiece22 (Nat.le_of_lt h21) h22, tsq_lt_capsq hsplit h22 (by norm_num)⟩ - rcases le_or_gt (vTree x) 957947395138969755787899401332634686 with h23 | h23 - · exact ⟨_, _, _, _, granPiece23 (Nat.le_of_lt h22) h23, tsq_lt_capsq hsplit h23 (by norm_num)⟩ - rcases le_or_gt (vTree x) 997861869936426828945728543054827798 with h24 | h24 - · exact ⟨_, _, _, _, granPiece24 (Nat.le_of_lt h23) h24, tsq_lt_capsq hsplit h24 (by norm_num)⟩ - rcases le_or_gt (vTree x) 1037776344733883902103557684777020910 with h25 | h25 - · exact ⟨_, _, _, _, granPiece25 (Nat.le_of_lt h24) h25, tsq_lt_capsq hsplit h25 (by norm_num)⟩ - rcases le_or_gt (vTree x) 1077690819531340975261386826499214022 with h26 | h26 - · exact ⟨_, _, _, _, granPiece26 (Nat.le_of_lt h25) h26, tsq_lt_capsq hsplit h26 (by norm_num)⟩ - rcases le_or_gt (vTree x) 1117605294328798048419215968221407134 with h27 | h27 - · exact ⟨_, _, _, _, granPiece27 (Nat.le_of_lt h26) h27, tsq_lt_capsq hsplit h27 (by norm_num)⟩ - rcases le_or_gt (vTree x) 1157519769126255121577045109943600246 with h28 | h28 - · exact ⟨_, _, _, _, granPiece28 (Nat.le_of_lt h27) h28, tsq_lt_capsq hsplit h28 (by norm_num)⟩ - rcases le_or_gt (vTree x) 1197434243923712194734874251665793358 with h29 | h29 - · exact ⟨_, _, _, _, granPiece29 (Nat.le_of_lt h28) h29, tsq_lt_capsq hsplit h29 (by norm_num)⟩ - rcases le_or_gt (vTree x) 1237348718721169267892703393387986470 with h30 | h30 - · exact ⟨_, _, _, _, granPiece30 (Nat.le_of_lt h29) h30, tsq_lt_capsq hsplit h30 (by norm_num)⟩ - exact ⟨_, _, _, _, granPiece31 (Nat.le_of_lt h30) hvmax', - tsq_lt_capsq hsplit hvmax' (by norm_num)⟩ + have hvI : ((vTree x : Nat) : Int) ≤ (ExpCertV.vmaxV : Int) := by + exact_mod_cast vTree_le_vmax hx hC hC0 + obtain ⟨p, hp, hplo, hphi⟩ := + piecesCover_sound hvI 0 granPieces_cover (Int.natCast_nonneg _) + obtain ⟨vlo, vhi, T, DO, DU⟩ := p + exact ⟨T, DO, DU, evalPoly Kpoly vhi, + granPieces_ok _ hp (vTree x) hplo hphi, + tsq_lt_capsq hsplit hphi (granPieces_caps _ hp)⟩ end ExpYul diff --git a/formal/exp/ExpProof/GenExpVLit.lean b/formal/exp/ExpProof/GenExpVLit.lean index 44bbb905e..89558c22f 100644 --- a/formal/exp/ExpProof/GenExpVLit.lean +++ b/formal/exp/ExpProof/GenExpVLit.lean @@ -1,4 +1,5 @@ import ExpProof.Floor.CertDefsV +import ExpProof.Floor.GranPieces import Common.Foundation.KroneckerShift /-! @@ -10,9 +11,11 @@ from the symbolic `ExpCertV` definitions, emits the building-block + cert litera in-kernel `checkCoverK` decides — and writes one `Cert/ExpV{Up,Lo,…}C.lean` cell file per sub-cell plus the cover module with the symbolic-cert↔literal equality and the `_nonneg` ladder. -Run with `lake env lean GenExpVLit.lean` after `lake build ExpProof.Floor.CertDefsV`. Output is -deterministic (byte-identical on re-run). Only the generated `Cert/ExpV*` files are machine output; -this generator and the hand-written `Floor/CertDefsV.lean` symbolic definitions are tracked. +Run with `lake env lean GenExpVLit.lean` after +`lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces`. Output is deterministic +(byte-identical on re-run). Only the generated `Cert/ExpV*` files are machine output; this +generator, the hand-written `Floor/CertDefsV.lean` symbolic definitions, and the +`Floor/GranPieces.lean` piece table are tracked. -/ open Common.Poly ExpCertV @@ -120,43 +123,6 @@ def dOverPEqTac : String := def dUnderPEqTac : String := " unfold certDUnderP evVPoly odVPoly\n decide +kernel" -/-- The 32 granularity pieces: `(vlo, vhi, T, DOver, DUnder)` — the `v`-range, the piece `t`-cap -(`T² ≥ (vhi+1)·2^133`), and the floored denominators for the two halves. Each piece's floors are -certified over `[vlo, vhi + 1]` (the granularity step looks one cell ahead). -/ -def granPieces : List (Int × Int × Int × Int × Int) := [ - (0, 39914474797457073157829141722193111, 20847785078312632088902884100098393904, 650161701553, 691253358954), - (39914474797457073157829141722193111, 79828949594914146315658283444386223, 29483220403189161767243017845519310570, 641945658278, 700065691212), - (79828949594914146315658283444386223, 119743424392371219473487425166579335, 36109422980913784159270707268699614620, 635708060030, 706899646710), - (119743424392371219473487425166579335, 159657899189828292631316566888772447, 41695570156625264177805768200196787807, 630494171758, 712709960499), - (159657899189828292631316566888772447, 199572373987285365789145708610965559, 46617064615412821983671927489259435287, 625934238048, 717866387998), - (199572373987285365789145708610965559, 239486848784742438946974850333158671, 51066435709074987640046250875008841866, 621838651900, 722558536211), - (239486848784742438946974850333158671, 279401323582199512104803992055351783, 55158054703738454765934460694358669515, 618094793288, 726899025166), - (279401323582199512104803992055351783, 319315798379656585262633133777544895, 58966440806378323534486035691038621139, 614629293866, 730961223213), - (319315798379656585262633133777544895, 359230273177113658420462275499738007, 62543355234937896266708652300295181711, 611391198603, 734796085384), - (359230273177113658420462275499738007, 399144747974570731578291417221931119, 65926485017139723075679505829736200590, 608343412382, 738440706802), - (399144747974570731578291417221931119, 439059222772027804736120558944124231, 69144280814733066627417644920644591155, 605457935097, 741923087576), - (439059222772027804736120558944124231, 478973697569484877893949700666317343, 72218845961827568318541414537399229239, 602713016329, 745264978126), - (478973697569484877893949700666317343, 518888172366941951051778842388510455, 75167758079709234538337434275175078691, 600091361400, 748483673135), - (518888172366941951051778842388510455, 558802647164399024209607984110703567, 78005269036144011942405564982788931618, 597578949702, 751593193213), - (558802647164399024209607984110703567, 598717121961856097367437125832896679, 80743124413616312505576435261721815008, 595164227770, 754605091830), - (598717121961856097367437125832896679, 638631596759313170525266267555089791, 83391140313250528355611536400393575614, 592837541332, 757529023260), - (638631596759313170525266267555089791, 678546071556770243683095409277282902, 85957619938058733268340145980060814334, 590590725148, 760373152745), - (678546071556770243683095409277282902, 718460546354227316840924550999476014, 88449661209567485301729053536557931646, 588416800156, 763144459353), - (718460546354227316840924550999476014, 758375021151684389998753692721669126, 90873388353019950250431101958484117810, 586309745473, 765848963968), - (758375021151684389998753692721669126, 798289495949141463156582834443862238, 93234129230825643967343854978518870515, 584264323835, 768491903858), - (798289495949141463156582834443862238, 838203970746598536314411976166055350, 95536553193538501370371342040089081115, 582275945893, 771077868376), - (838203970746598536314411976166055350, 878118445544055609472241117888248462, 97784779688729301059274137358180034302, 580340563312, 773610905858), - (878118445544055609472241117888248462, 918032920341512682630070259610441574, 99982464869820254414073625773477941119, 578454583528, 776094608873), - (918032920341512682630070259610441574, 957947395138969755787899401332634686, 102132871418149975280092501750017683679, 576614801025, 778532182941), - (957947395138969755787899401332634686, 997861869936426828945728543054827798, 104238925391563160444514420500491969466, 574818341390, 780926502475), - (997861869936426828945728543054827798, 1037776344733883902103557684777020910, 106303262929504594869818257246985820007, 573062615355, 783280156749), - (1037776344733883902103557684777020910, 1077690819531340975261386826499214022, 108328268942741352477812121806098843808, 571345280717, 785595487968), - (1077690819531340975261386826499214022, 1117605294328798048419215968221407134, 110316109407476909531868921388717338981, 569664210570, 787874623042), - (1117605294328798048419215968221407134, 1157519769126255121577045109943600246, 112268758510433036404380164835338032221, 568017466591, 790119500297), - (1157519769126255121577045109943600246, 1197434243923712194734874251665793358, 114188021614114346553315397742450038434, 566403276447, 792331892069), - (1197434243923712194734874251665793358, 1237348718721169267892703393387986470, 116075554802968570681645777137735089747, 564820014566, 794513423933), - (1237348718721169267892703393387986470, 1277263193518626341050532535110179582, 117932881612756647068972071382077242231, 563266185678, 796665591163)] - #eval do let cUp := ptrim certExpUp let cLo := ptrim certExpLo From ed10526ccf9c107f4d5c7d8d0d3a771ed5aa2007 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 20:17:31 +0200 Subject: [PATCH 133/149] Share the cover-certificate generator helpers in Common.GenCover The trailing-zero trim, greedy checkCoverK cell walk (with its binary width search), zero-padded index, literal-list emitter, and the cover-cell / _nonneg-ladder text templates live once, in Common.GenCover; the four cover-walking generators (GenExpVLit, GenCover, GenErrLit, GenFloorCertLit) consume them instead of carrying per-file copies. GenErrLit keeps only its namespace-wrapping litText variant, expressed over the shared emitter, and GenFloorCertLit's whole-file assembler is renamed fileText to keep the shared name unambiguous. Every certificate-generation build line (exp-formal.yml, build-ln-proof, and the README blocks) builds Common.GenCover before running the generators. All generated certificate files and all four generators' stdout are byte-identical. Co-Authored-By: Claude Fable 5 --- .github/actions/build-ln-proof/action.yml | 2 +- .github/workflows/exp-formal.yml | 2 +- formal/README.md | 4 +- formal/common/Common.lean | 6 ++- formal/common/Common/GenCover.lean | 65 +++++++++++++++++++++++ formal/exp/ExpProof/GenExpVLit.lean | 49 +++-------------- formal/ln/LnProof/GenCover.lean | 42 +++------------ formal/ln/LnProof/GenErrLit.lean | 41 +++----------- formal/ln/LnProof/GenFloorCertLit.lean | 39 ++++++-------- 9 files changed, 109 insertions(+), 141 deletions(-) create mode 100644 formal/common/Common/GenCover.lean diff --git a/.github/actions/build-ln-proof/action.yml b/.github/actions/build-ln-proof/action.yml index f646a8701..949a6bcd6 100644 --- a/.github/actions/build-ln-proof/action.yml +++ b/.github/actions/build-ln-proof/action.yml @@ -25,7 +25,7 @@ runs: shell: bash working-directory: formal/ln/LnProof run: | - lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts + lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts Common.GenCover lake env lean GenFloorCertLit.lean lake build LnProof.Cert.FloorCertLit lake env lean GenCover.lean diff --git a/.github/workflows/exp-formal.yml b/.github/workflows/exp-formal.yml index a1c6f2e61..abab71aae 100644 --- a/.github/workflows/exp-formal.yml +++ b/.github/workflows/exp-formal.yml @@ -89,7 +89,7 @@ jobs: - name: Generate Lean certificate artifacts working-directory: formal/exp/ExpProof run: | - lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces Common.Foundation.KroneckerShift + lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces Common.Foundation.KroneckerShift Common.GenCover lake env lean GenExpVLit.lean - name: Build Exp proof package diff --git a/formal/README.md b/formal/README.md index d3bcf31fd..94f76b95e 100644 --- a/formal/README.md +++ b/formal/README.md @@ -130,7 +130,7 @@ cd formal/cbrt/Cbrt512Proof && \ cd formal/ln/LnProof && \ lake build LnProof.LnYulRuntime LnProof.LnYulProof && \ - lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts && \ + lake build LnProof.Floor.CertDefs Common.Foundation.KroneckerShift LnProof.Floor.Consts Common.GenCover && \ lake env lean GenFloorCertLit.lean && \ lake build LnProof.Cert.FloorCertLit && \ lake env lean GenCover.lean && \ @@ -148,7 +148,7 @@ cd formal/ln/LnProof && \ cd formal/exp/ExpProof && \ lake build ExpProof.ExpYulRuntime ExpProof.ExpYulProof && \ - lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces Common.Foundation.KroneckerShift && \ + lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces Common.Foundation.KroneckerShift Common.GenCover && \ lake env lean GenExpVLit.lean && \ lake build ``` diff --git a/formal/common/Common.lean b/formal/common/Common.lean index 0a324d72f..3ec55faab 100644 --- a/formal/common/Common.lean +++ b/formal/common/Common.lean @@ -4,8 +4,9 @@ -- implementation. It is generic interval-Horner nonnegativity certificates and -- Kronecker identity-testing / packed-shift cell walks (`Common.Poly`), the -- `e^(p/q)` Taylor-cut framework (`Common.Exp`), the `Real.exp` bridge for the --- partial-sum caps (`Common.RealExpBridge`), and the EVM-word op-preservation --- bridges (`Common.Word`). +-- partial-sum caps (`Common.RealExpBridge`), the EVM-word op-preservation +-- bridges (`Common.Word`), and the cover-certificate generator string/IO helpers the +-- `lake env lean Gen*.lean` scripts share (`Common.GenCover`). import Common.Word import Common.Foundation.Poly import Common.Foundation.ExpSum @@ -13,3 +14,4 @@ import Common.Foundation.ShiftCert import Common.Foundation.Kronecker import Common.Foundation.KroneckerShift import Common.Seam.RealExpBridge +import Common.GenCover diff --git a/formal/common/Common/GenCover.lean b/formal/common/Common/GenCover.lean new file mode 100644 index 000000000..251a634d9 --- /dev/null +++ b/formal/common/Common/GenCover.lean @@ -0,0 +1,65 @@ +import Common.Foundation.KroneckerShift + +/-! +# Shared cover-certificate generator helpers + +Helpers common to the `lake env lean Gen*.lean` certificate generators: trailing-zero trimming, +the greedy `checkCoverK` cell walk (binary-searching each cell's maximal width), the literal-list +emitter, and the cover-cell / `_nonneg`-ladder text templates. Everything here is generator-side +string/IO tooling; the in-kernel predicates it targets (`checkCoverK`, `checkCoverK_sound`) live +in `Common.Foundation.KroneckerShift`. +-/ + +namespace Common.GenCover + +open Common.Poly + +/-- Drop trailing zero coefficients. -/ +def ptrim (a : List Int) : List Int := + let r := (a.reverse.dropWhile (· == 0)).reverse + if r.isEmpty then [0] else r + +/-- Largest `w ∈ [0, hiW]` with `0 ≤ (hornerIv S 0 w).1` (non-increasing in `w`). -/ +partial def maxW (S : List Int) (hiW : Int) : Int := + let rec bs (lo hi : Int) : Int := + if lo ≥ hi then lo + else let mid := (lo + hi + 1) / 2 + if 0 ≤ (hornerIv S 0 mid).1 then bs mid hi else bs lo (mid - 1) + bs 0 hiW + +/-- Greedy walk → `(reached?, (anchor, width) list)`. -/ +partial def walk (C : List Int) (lo hi : Int) : Bool × List (Int × Int) := + let rec go (a : Int) (fuel : Nat) (acc : List (Int × Int)) : Bool × List (Int × Int) := + match fuel with + | 0 => (false, acc.reverse) + | fuel + 1 => + if a > hi then (true, acc.reverse) + else + let S := kShiftWitness kB C a + if 0 ≤ (hornerIv S 0 0).1 then + let w := maxW S (hi - a) + go (a + w + 1) fuel ((a, w) :: acc) + else (false, ((a, -1) :: acc).reverse) + go lo 200000 [] + +/-- Zero-padded two-digit index. -/ +def pad2 (i : Nat) : String := (if i < 10 then "0" else "") ++ toString i + +/-- One `def : List Int := [...]` literal block. -/ +def litText (name : String) (c : List Int) : String := + "def " ++ name ++ " : List Int := [\n " ++ + String.intercalate ",\n " (c.map toString) ++ "]\n\n" + +/-- One cover-cell module: the kernel-decided `checkCoverK` theorem for `[a, a + w]`. -/ +def cellText (importMod ns cellName litName : String) (a w : Int) : String := + s!"import {importMod}\nimport Common.Foundation.KroneckerShift\n\nnamespace {ns}\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellName} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend {ns}\n" + +/-- One `_nonneg`-ladder step dispatching variable `x` into cell `cellName`; the final cell +consumes the ladder's upper hypothesis `h2` directly. -/ +def ladderStep (cellName x : String) (a w : Int) (last : Bool) : String := + if last then + s!" exact checkCoverK_sound _ _ _ _ _ {cellName} {x} (by omega) h2\n" + else + s!" rcases Int.lt_or_le {x} ({a + w} + 1) with h | h\n · exact checkCoverK_sound _ _ _ _ _ {cellName} {x} (by omega) (by omega)\n" + +end Common.GenCover diff --git a/formal/exp/ExpProof/GenExpVLit.lean b/formal/exp/ExpProof/GenExpVLit.lean index 89558c22f..c6b31ea38 100644 --- a/formal/exp/ExpProof/GenExpVLit.lean +++ b/formal/exp/ExpProof/GenExpVLit.lean @@ -1,6 +1,7 @@ import ExpProof.Floor.CertDefsV import ExpProof.Floor.GranPieces import Common.Foundation.KroneckerShift +import Common.GenCover /-! # Cert literal + cover generator for the **v-form** reduced-argument Taylor caps @@ -12,46 +13,17 @@ in-kernel `checkCoverK` decides — and writes one `Cert/ExpV{Up,Lo,…}C.le plus the cover module with the symbolic-cert↔literal equality and the `_nonneg` ladder. Run with `lake env lean GenExpVLit.lean` after -`lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces`. Output is deterministic -(byte-identical on re-run). Only the generated `Cert/ExpV*` files are machine output; this +`lake build ExpProof.Floor.CertDefsV ExpProof.Floor.GranPieces Common.GenCover`. Output is +deterministic (byte-identical on re-run). Only the generated `Cert/ExpV*` files are machine +output; this generator, the hand-written `Floor/CertDefsV.lean` symbolic definitions, and the `Floor/GranPieces.lean` piece table are tracked. -/ -open Common.Poly ExpCertV +open Common.Poly ExpCertV Common.GenCover namespace GenExpVLit -/-- Drop trailing zero coefficients. -/ -def ptrim (a : List Int) : List Int := - let r := (a.reverse.dropWhile (· == 0)).reverse - if r.isEmpty then [0] else r - -/-- Largest `w ∈ [0, hiW]` with `0 ≤ (hornerIv S 0 w).1` (non-increasing in `w`). -/ -partial def maxW (S : List Int) (hiW : Int) : Int := - let rec bs (lo hi : Int) : Int := - if lo ≥ hi then lo - else let mid := (lo + hi + 1) / 2 - if 0 ≤ (hornerIv S 0 mid).1 then bs mid hi else bs lo (mid - 1) - bs 0 hiW - -/-- Greedy walk → `(reached?, (anchor, width) list)`. -/ -partial def walk (C : List Int) (lo hi : Int) : Bool × List (Int × Int) := - let rec go (a : Int) (fuel : Nat) (acc : List (Int × Int)) : Bool × List (Int × Int) := - match fuel with - | 0 => (false, acc.reverse) - | fuel + 1 => - if a > hi then (true, acc.reverse) - else - let S := kShiftWitness kB C a - if 0 ≤ (hornerIv S 0 0).1 then - let w := maxW S (hi - a) - go (a + w + 1) fuel ((a, w) :: acc) - else (false, ((a, -1) :: acc).reverse) - go lo 200000 [] - -def pad2 (i : Nat) : String := (if i < 10 then "0" else "") ++ toString i - /-- Walk `[lo, hi]`, write one cell file per sub-cell, then write the cover module. -/ def emit (litName coverMod modPrefix cellPrefix certEqName litNonneg symNonneg symName eqTac : String) (C : List Int) (lo hi : Int) : IO Unit := do @@ -61,7 +33,7 @@ def emit (litName coverMod modPrefix cellPrefix certEqName litNonneg symNonneg s for (aw, i) in cells.zipIdx do let (a, w) := aw IO.FS.writeFile s!"ExpProof/Cert/{modPrefix}{pad2 i}.lean" - s!"import ExpProof.Cert.ExpVCertLit\nimport Common.Foundation.KroneckerShift\n\nnamespace ExpCertV\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{pad2 i} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend ExpCertV\n" + (cellText "ExpProof.Cert.ExpVCertLit" "ExpCertV" s!"{cellPrefix}{pad2 i}" litName a w) let lb := "{"; let rb := "}" let mut s := "import ExpProof.Floor.CertDefsV\nimport ExpProof.Cert.ExpVCertLit\nimport Common.Foundation.KroneckerShift\n" for (_, i) in cells.zipIdx do s := s ++ s!"import ExpProof.Cert.{modPrefix}{pad2 i}\n" @@ -72,19 +44,12 @@ def emit (litName coverMod modPrefix cellPrefix certEqName litNonneg symNonneg s let n := cells.length for (aw, i) in cells.zipIdx do let (a, w) := aw - if i + 1 < n then - s := s ++ s!" rcases Int.lt_or_le t ({a + w} + 1) with h | h\n · exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} t (by omega) (by omega)\n" - else - s := s ++ s!" exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} t (by omega) h2\n" + s := s ++ ladderStep s!"{cellPrefix}{pad2 i}" "t" a w (i + 1 == n) s := s ++ s!"\ntheorem {symNonneg} {lb}t : Int{rb} (h1 : {lo} ≤ t) (h2 : t ≤ {hi}) :\n" s := s ++ s!" 0 ≤ evalPoly {symName} t := by\n rw [{certEqName}]; exact {litNonneg} h1 h2\n" s := s ++ "\nend ExpCertV\n" IO.FS.writeFile s!"ExpProof/Cert/{coverMod}.lean" s -def litText (name : String) (c : List Int) : String := - "def " ++ name ++ " : List Int := [\n " ++ - String.intercalate ",\n " (c.map toString) ++ "]\n\n" - end GenExpVLit open GenExpVLit diff --git a/formal/ln/LnProof/GenCover.lean b/formal/ln/LnProof/GenCover.lean index df9b9b2d5..aa63a13f1 100644 --- a/formal/ln/LnProof/GenCover.lean +++ b/formal/ln/LnProof/GenCover.lean @@ -1,5 +1,6 @@ import LnProof.Cert.FloorCertLit import Common.Foundation.KroneckerShift +import Common.GenCover /-! # Cover generator @@ -11,39 +12,13 @@ covers are guaranteed `decide`-acceptable. Writes one `…C.lean` cell file per sub-cell and prints the `_nonneg` ladder and import block for the cover module. -Run with `lake env lean GenCover.lean` (after `lake build LnProof.Cert.FloorCertLit`). +Run with `lake env lean GenCover.lean` (after `lake build LnProof.Cert.FloorCertLit Common.GenCover`). -/ -open Common.Poly LnFloorCert +open Common.Poly LnFloorCert Common.GenCover namespace GenCover -/-- Largest `w ∈ [0, hiW]` with `0 ≤ (hornerIv S 0 w).1` (non-increasing in `w`). -/ -partial def maxW (S : List Int) (hiW : Int) : Int := - let rec bs (lo hi : Int) : Int := - if lo ≥ hi then lo - else - let mid := (lo + hi + 1) / 2 - if 0 ≤ (hornerIv S 0 mid).1 then bs mid hi else bs lo (mid - 1) - bs 0 hiW - -/-- Greedy walk → `(reached?, (anchor, width) list)`. -/ -partial def walk (C : List Int) (lo hi : Int) : Bool × List (Int × Int) := - let rec go (a : Int) (fuel : Nat) (acc : List (Int × Int)) : Bool × List (Int × Int) := - match fuel with - | 0 => (false, acc.reverse) - | fuel + 1 => - if a > hi then (true, acc.reverse) - else - let S := kShiftWitness kB C a - if 0 ≤ (hornerIv S 0 0).1 then - let w := maxW S (hi - a) - go (a + w + 1) fuel ((a, w) :: acc) - else (false, ((a, -1) :: acc).reverse) - go lo 200000 [] - -def pad2 (i : Nat) : String := (if i < 10 then "0" else "") ++ toString i - /-- Emit cell files `.lean` and return the ladder text. -/ def emit (nm litName symName evalEqName modPrefix cellPrefix nonnegName : String) (C : List Int) (lo hi : Int) : IO Unit := do @@ -56,9 +31,8 @@ def emit (nm litName symName evalEqName modPrefix cellPrefix nonnegName : String for (aw, i) in cells.zipIdx do let (a, w) := aw let nn := pad2 i - let body := - s!"import LnProof.Cert.FloorCertLit\nimport Common.Foundation.KroneckerShift\n\nnamespace LnFloorCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{nn} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend LnFloorCert\n" - IO.FS.writeFile s!"LnProof/Cert/{modPrefix}{nn}.lean" body + IO.FS.writeFile s!"LnProof/Cert/{modPrefix}{nn}.lean" + (cellText "LnProof.Cert.FloorCertLit" "LnFloorCert" s!"{cellPrefix}{nn}" litName a w) -- ladder + imports let mut imps := "" for (_, i) in cells.zipIdx do @@ -75,11 +49,7 @@ def emit (nm litName symName evalEqName modPrefix cellPrefix nonnegName : String let n := cells.length for (aw, i) in cells.zipIdx do let (a, w) := aw - if i + 1 < n then - IO.println s!" rcases Int.lt_or_le m ({a + w} + 1) with h | h" - IO.println s!" · exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} m (by omega) (by omega)" - else - IO.println s!" exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} m (by omega) h2" + IO.print (ladderStep s!"{cellPrefix}{pad2 i}" "m" a w (i + 1 == n)) end GenCover diff --git a/formal/ln/LnProof/GenErrLit.lean b/formal/ln/LnProof/GenErrLit.lean index 930d08c57..b9250f62d 100644 --- a/formal/ln/LnProof/GenErrLit.lean +++ b/formal/ln/LnProof/GenErrLit.lean @@ -1,5 +1,6 @@ import LnProof.Error.Core import Common.Foundation.KroneckerShift +import Common.GenCover /-! Generate the error-bound cert literals (ErrCertLtLit / ErrCertGeLit) and their covers for the current BIASc and `lnErrorBoundNum`. Computes @@ -9,6 +10,7 @@ bridges building, then walks the `checkCoverK` covers (literal signature, as the checked `errLt_nonneg`/`errGe_nonneg` theorems use). -/ open Common.Poly LnFloorCert Common.Exp LnFloor LnYul +open Common.GenCover hiding litText namespace GenErrLit @@ -30,33 +32,6 @@ def cLt : List Int := def cGe : List Int := expMarginPoly 22 geTN2bLit geTD2bLit (polyScale errGeK [1, 1]) errGeW -/-- Drop trailing zero coefficients (mirror gen_cert_literals.ptrim). -/ -def ptrim (a : List Int) : List Int := - let r := (a.reverse.dropWhile (· == 0)).reverse - if r.isEmpty then [0] else r - -partial def maxW (S : List Int) (hiW : Int) : Int := - let rec bs (lo hi : Int) : Int := - if lo ≥ hi then lo - else let mid := (lo + hi + 1) / 2 - if 0 ≤ (hornerIv S 0 mid).1 then bs mid hi else bs lo (mid - 1) - bs 0 hiW -partial def walk (C : List Int) (lo hi : Int) : Bool × List (Int × Int) := - let rec go (a : Int) (fuel : Nat) (acc : List (Int × Int)) : Bool × List (Int × Int) := - match fuel with - | 0 => (false, acc.reverse) - | fuel + 1 => - if a > hi then (true, acc.reverse) - else - let S := kShiftWitness kB C a - if 0 ≤ (hornerIv S 0 0).1 then - let w := maxW S (hi - a) - go (a + w + 1) fuel ((a, w) :: acc) - else (false, ((a, -1) :: acc).reverse) - go lo 200000 [] - -def pad2 (i : Nat) : String := (if i < 10 then "0" else "") ++ toString i - /-- Walk `[lo,hi]`, write one cell file per sub-cell, and write the complete cover module `coverMod` (cell imports + the literal-signature `nonnegName` ladder). The error covers carry no hand-written content, so they are fully @@ -68,7 +43,7 @@ def emit (litFile litName coverMod modPrefix cellPrefix nonnegName : String) (C for (aw, i) in cells.zipIdx do let (a, w) := aw IO.FS.writeFile s!"LnProof/Cert/{modPrefix}{pad2 i}.lean" - s!"import LnProof.Cert.{litFile}\nimport Common.Foundation.KroneckerShift\n\nnamespace LnFloorCert\nopen Common.Poly\n\nset_option maxRecDepth 100000\n\ntheorem {cellPrefix}{pad2 i} : checkCoverK kB {litName} {a} {a + w}\n [{w}] = true := by\n decide +kernel\n\nend LnFloorCert\n" + (cellText s!"LnProof.Cert.{litFile}" "LnFloorCert" s!"{cellPrefix}{pad2 i}" litName a w) let lb := "{"; let rb := "}" let mut s := "" for (_, i) in cells.zipIdx do s := s ++ s!"import LnProof.Cert.{modPrefix}{pad2 i}\n" @@ -77,16 +52,14 @@ def emit (litFile litName coverMod modPrefix cellPrefix nonnegName : String) (C let n := cells.length for (aw, i) in cells.zipIdx do let (a, w) := aw - if i + 1 < n then - s := s ++ s!" rcases Int.lt_or_le m ({a + w} + 1) with h | h\n · exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} m (by omega) (by omega)\n" - else - s := s ++ s!" exact checkCoverK_sound _ _ _ _ _ {cellPrefix}{pad2 i} m (by omega) h2\n" + s := s ++ ladderStep s!"{cellPrefix}{pad2 i}" "m" a w (i + 1 == n) s := s ++ "\nend LnFloorCert\n" IO.FS.writeFile s!"LnProof/Cert/{coverMod}.lean" s +/-- A shared-emitter literal block wrapped in the `LnFloorCert` namespace (each error-cert +literal is written to its own self-contained module). -/ def litText (name : String) (c : List Int) : String := - "namespace LnFloorCert\n\ndef " ++ name ++ " : List Int := [\n " ++ - String.intercalate ",\n " (c.map toString) ++ "]\n\nend LnFloorCert\n" + "namespace LnFloorCert\n\n" ++ Common.GenCover.litText name c ++ "end LnFloorCert\n" end GenErrLit open GenErrLit diff --git a/formal/ln/LnProof/GenFloorCertLit.lean b/formal/ln/LnProof/GenFloorCertLit.lean index 7681f200f..3080d808c 100644 --- a/formal/ln/LnProof/GenFloorCertLit.lean +++ b/formal/ln/LnProof/GenFloorCertLit.lean @@ -1,34 +1,27 @@ import LnProof.Floor.CertDefs +import Common.GenCover -open LnFloorCert +open LnFloorCert Common.GenCover namespace GenFloorCertLit -def ptrim (a : List Int) : List Int := - let r := (a.reverse.dropWhile (· == 0)).reverse - if r.isEmpty then [0] else r - -def litDef (name : String) (coeffs : List Int) : String := - "def " ++ name ++ " : List Int := [\n " ++ - String.intercalate ",\n " (coeffs.map toString) ++ "]\n\n" - -def litText : String := +def fileText : String := "/-! Literal coefficient lists for the floor certificate polynomials. -/\n\n" ++ "namespace LnFloorCert\n\n" ++ - litDef "geTNLit" geTN ++ - litDef "geTDLit" geTD ++ - litDef "geTN2bLit" geTN2b ++ - litDef "geTD2bLit" geTD2b ++ - litDef "ltTNLit" ltTN ++ - litDef "ltTDLit" ltTD ++ - litDef "ltTN2bLit" ltTN2b ++ - litDef "ltTD2bLit" ltTD2b ++ - litDef "certGeUpLit" (ptrim certGeUp) ++ - litDef "certGeLoLit" (ptrim certGeLo) ++ - litDef "certLtUpLit" (ptrim certLtUp) ++ - litDef "certLtLoLit" (ptrim certLtLo) ++ + litText "geTNLit" geTN ++ + litText "geTDLit" geTD ++ + litText "geTN2bLit" geTN2b ++ + litText "geTD2bLit" geTD2b ++ + litText "ltTNLit" ltTN ++ + litText "ltTDLit" ltTD ++ + litText "ltTN2bLit" ltTN2b ++ + litText "ltTD2bLit" ltTD2b ++ + litText "certGeUpLit" (ptrim certGeUp) ++ + litText "certGeLoLit" (ptrim certGeLo) ++ + litText "certLtUpLit" (ptrim certLtUp) ++ + litText "certLtLoLit" (ptrim certLtLo) ++ "end LnFloorCert\n" end GenFloorCertLit -#eval IO.FS.writeFile "LnProof/Cert/FloorCertLit.lean" GenFloorCertLit.litText +#eval IO.FS.writeFile "LnProof/Cert/FloorCertLit.lean" GenFloorCertLit.fileText From f2ecd3171e24c273fbadbdf5f730b751d3c9f7bc Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 22:17:29 +0200 Subject: [PATCH 134/149] Renumber the exp Seam reductions to the current compiled Yul expRayToWad returns the kernel result with a plain return statement, which shifts solc's AST ids: the compiled wrapper's generated functions are now fun_expRayToWad_68, fun__expRayToWad_78, and the wrap/external pair 97, and the kernel body ends in a leave statement rather than a dead let. The Seam reduction layer follows the regenerated artifacts: every generated-name reference is renumbered, and the fun_expRayToWad walk simp sets carry EvmYul.Yul.State.revive and EvmYul.Yul.State.setLeave to reduce the leave, matching the dispatcher walks. The reduction simp sets are also pruned to the lemmas the walks use. The emitted Yul is otherwise identical modulo internal variable ids; no statement outside the Seam layer changes. Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Seam/Dispatcher.lean | 18 +-- formal/exp/ExpProof/ExpProof/Seam/Guard.lean | 2 +- .../exp/ExpProof/ExpProof/Seam/Helpers.lean | 22 ++-- formal/exp/ExpProof/ExpProof/Seam/Revert.lean | 56 +++++---- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 110 +++++++++--------- 5 files changed, 101 insertions(+), 107 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean b/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean index 974501fbd..70310a73d 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Dispatcher.lean @@ -87,14 +87,14 @@ theorem call_validator_revert_t_int256_direct call_cleanup_t_int256_direct (v := v) (fuel := fuel + extra) (extra := 51) (shared := shared) (hlookup := hlookup) simp only [Nat.reduceAdd, FormalYul.word] at hcleanup - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, - EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [EvmYul.Yul.evalCall.eq_def, + EvmYul.Yul.evalPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word, hcleanup] + FormalYul.word, hcleanup] /-- `abi_decode_t_int256(offset, end) := calldataload(offset); validator(value)` — for the `expRayToWad` calldata at offset 4 it reads `x` and validates (no revert). -/ @@ -225,7 +225,7 @@ theorem call_abi_encode_t_int256_to_t_int256_fromStack_direct EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word, hcleanup] + FormalYul.word, hcleanup] /-- `abi_encode_tuple_t_int256__to_t_int256__fromStack(headStart, value)` encodes a single `int256` return value (`value = word v`) and returns the tail pointer `headStart + 32`. -/ @@ -365,10 +365,10 @@ theorem selectSwitchCase_expRayToWad_sharedFor_mk (x : Nat) : (FormalYul.word 224)) [(FormalYul.word 1099384363, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_99") [])])] = + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_97") [])])] = some [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_99") [])] := by + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_97") [])] := by rw [expRayToWad_selector_sharedFor_mk] rfl @@ -388,10 +388,10 @@ theorem selectSwitchCase_expRayToWad_sharedFor_mk_raw (x : Nat) : (EvmYul.UInt256.ofNat 224)) [(EvmYul.UInt256.ofNat 1099384363, [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_99") [])])] = + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_97") [])])] = some [EvmYul.Yul.Ast.Stmt.ExprStmtCall - (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_99") [])] := by + (EvmYul.Yul.Ast.Expr.Call (Sum.inr "external_fun_wrap_expRayToWad_97") [])] := by simpa [FormalYul.word] using selectSwitchCase_expRayToWad_sharedFor_mk x /-- Revert-analogue of `Preservation.runContract_ok_of_dispatcherReturn`: if the bare dispatcher diff --git a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean index 48b0f2f92..ba3f7a5a1 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean @@ -3,7 +3,7 @@ import Common.Word /-! # The overflow-guard comparison -`fun_expRayToWad_70` branches on `iszero(slt(x, C))` with `C = 0x8e383a2cdfa1b74a9422d2e1` +`fun_expRayToWad_68` branches on `iszero(slt(x, C))` with `C = 0x8e383a2cdfa1b74a9422d2e1` (`= 0x8e383a2cdfa1b74a9422d2e1`, the first input whose octave count reaches 64). For a signed input `x ≥ C` (with `u256 x < 2^255`, i.e. `x` a nonnegative signed value at least `C`), the signed comparison `slt(x, C)` is `0`, so the guard `iszero(slt(x, C))` is `1` and the revert diff --git a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean index 8bceb1518..ff2c0aadf 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean @@ -6,7 +6,7 @@ import FormalYul.Preservation # Per-function "direct" reductions for the trivial solc ABI/cleanup helpers These functions (`cleanup_*`, `identity`, `convert_*`, the constant accessor, `zero_value_*`) are -the solc-emitted plumbing called from `fun_expRayToWad_70`'s overflow guard and panic-code path. +the solc-emitted plumbing called from `fun_expRayToWad_68`'s overflow guard and panic-code path. Each is a one-liner; the directs step the interpreter through them. They are branch-agnostic — the value path also evaluates the guard (to decide *not* to revert) — so they live here, shared by both `Seam/Revert.lean` and the value-path seam. @@ -179,9 +179,8 @@ theorem call_convert_44_to_int256_direct (store := Finmap.insert "value" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup) simp [FormalYul.word] at h1 h2 h3 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, - EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, @@ -205,8 +204,8 @@ theorem call_cleanup_t_uint8_17_direct FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, @@ -243,8 +242,8 @@ theorem call_convert_17_to_uint8_17_direct (store := Finmap.insert "value" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup) simp [FormalYul.word] at h1 h2 h3 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, - EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, @@ -275,9 +274,8 @@ theorem call_constant_ARITHMETIC_OVERFLOW_17_direct (store := Finmap.insert "expr_16" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup) simp [FormalYul.word] at hconv - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, - EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, @@ -313,8 +311,8 @@ theorem call_convert_uint8_to_uint256_17_direct (store := Finmap.insert "value" (FormalYul.word 0x11) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup) simp [FormalYul.word] at h1 h2 h3 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, - EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, diff --git a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean index b05c9b4f4..c66a0e642 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean @@ -8,7 +8,7 @@ import FormalYul.Preservation /-! # Revert reduction for the overflow guard -`fun_expRayToWad_70` takes the overflow-guard branch for inputs at/above the threshold and calls +`fun_expRayToWad_68` takes the overflow-guard branch for inputs at/above the threshold and calls `fun_panic_8`, which does `mstore;mstore;revert(0x1c,0x24)`. These per-function "direct" lemmas step the interpreter through that branch; mirrors the `ln` revert path. -/ @@ -49,31 +49,30 @@ theorem call_fun_panic_8_revert_direct FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execCall.eq_def, - EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [ + EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, - EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, - EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word, primCall_revert_yul] + EvmYul.Yul.State.setStore, + FormalYul.word, primCall_revert_yul] set_option maxHeartbeats 8000000 in -/-- For inputs at/above the overflow threshold, `fun_expRayToWad_70` takes the guard branch and +/-- For inputs at/above the overflow threshold, `fun_expRayToWad_68` takes the guard branch and reverts via `fun_panic_8(ARITHMETIC_OVERFLOW)`. -/ -theorem call_fun_expRayToWad_70_revert_direct +theorem call_fun_expRayToWad_68_revert_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : - EvmYul.Yul.call (fuel + (extra + 1000)) [FormalYul.word x] (.some "fun_expRayToWad_70") + EvmYul.Yul.call (fuel + (extra + 1000)) [FormalYul.word x] (.some "fun_expRayToWad_68") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .error EvmYul.Yul.Exception.Revert := by rw [show fuel + (extra + 1000) = (fuel + extra) + 1000 by omega] rw [EvmYul.Yul.call.eq_def] - simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_70] - simp only [yulFunction_fun_expRayToWad_70, + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_68] + simp only [yulFunction_fun_expRayToWad_68, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -96,9 +95,8 @@ theorem call_fun_expRayToWad_70_revert_direct EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, - EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, - EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word, + EvmYul.Yul.State.setStore, + FormalYul.word, slt_thresh_ge h1 h2, call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 976) (shared := shared) (hlookup := hlookup), @@ -107,7 +105,7 @@ theorem call_fun_expRayToWad_70_revert_direct hcleanup, hconv44, hconvu, hpanic] set_option maxHeartbeats 8000000 in -/-- The thin wrapper `fun_wrap_expRayToWad_99` just forwards to `fun_expRayToWad_70`, so it reverts +/-- The thin wrapper `fun_wrap_expRayToWad_97` just forwards to `fun_expRayToWad_68`, so it reverts on the same out-of-range inputs. -/ theorem call_fun_wrap_expRayToWad_revert_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) @@ -115,36 +113,34 @@ theorem call_fun_wrap_expRayToWad_revert_direct some (FormalYul.accountFor yulContract)) (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : - EvmYul.Yul.call (fuel + (extra + 1200)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_99") + EvmYul.Yul.call (fuel + (extra + 1200)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_97") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .error EvmYul.Yul.Exception.Revert := by rw [show fuel + (extra + 1200) = (fuel + extra) + 1200 by omega] rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_expRayToWad] - simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_99, + simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_97, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have h70 := - call_fun_expRayToWad_70_revert_direct (x := x) (fuel := fuel + extra) (extra := 191) + call_fun_expRayToWad_68_revert_direct (x := x) (fuel := fuel + extra) (extra := 191) (shared := shared) (h1 := h1) (h2 := h2) (hlookup := hlookup) simp only [Nat.reduceAdd, FormalYul.word] at h70 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, - EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, - EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, - EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word, + EvmYul.Yul.State.setStore, + FormalYul.word, call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 1176) (shared := shared) (hlookup := hlookup), h70] set_option maxHeartbeats 8000000 in -/-- The external entrypoint `external_fun_wrap_expRayToWad_99` decodes the calldata argument `x` -(`callvalue` is 0, so the value guard is skipped) and forwards to `fun_wrap_expRayToWad_99`, which +/-- The external entrypoint `external_fun_wrap_expRayToWad_97` decodes the calldata argument `x` +(`callvalue` is 0, so the value guard is skipped) and forwards to `fun_wrap_expRayToWad_97`, which reverts for out-of-range `x`. -/ theorem external_fun_wrap_expRayToWad_calldata_revert (x : Nat) (store : EvmYul.Yul.VarStore) @@ -156,7 +152,7 @@ theorem external_fun_wrap_expRayToWad_calldata_revert rw [EvmYul.Yul.call.eq_def] simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_expRayToWad] - simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_97, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -172,8 +168,8 @@ theorem external_fun_wrap_expRayToWad_calldata_revert (shared := expSharedAfterFreePtr x) (hlookup := expSharedAfterFreePtr_lookup x) (h1 := h1) (h2 := h2) simp only [Nat.reduceAdd, FormalYul.word] at hwrap - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, - EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 8fd124eab..8bd10c98e 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -22,25 +22,25 @@ open Common.Word set_option maxRecDepth 100000 set_option maxHeartbeats 8000000 in -/-- The kernel `fun__expRayToWad_80` at the scale point `x = 0`: every `mul` by `x` vanishes, so +/-- The kernel `fun__expRayToWad_78` at the scale point `x = 0`: every `mul` by `x` vanishes, so `k = t = v = 0`, the rational form evaluates to `2^126`, and the final `iszero(0) = 1` fix-up makes the result exactly `10^18`. -/ -theorem call_fun__expRayToWad_80_zero_direct +theorem call_fun__expRayToWad_78_zero_direct (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : - EvmYul.Yul.call (fuel + (extra + 700)) [FormalYul.word 0] (.some "fun__expRayToWad_80") + EvmYul.Yul.call (fuel + (extra + 700)) [FormalYul.word 0] (.some "fun__expRayToWad_78") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 1000000000000000000]) := by rw [show fuel + (extra + 700) = (fuel + extra) + 700 by omega] rw [EvmYul.Yul.call.eq_def] - simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun__expRayToWad_80] - simp only [yulFunction_fun__expRayToWad_80, + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun__expRayToWad_78] + simp only [yulFunction_fun__expRayToWad_78, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, @@ -52,19 +52,19 @@ theorem call_fun__expRayToWad_80_zero_direct (shared := shared) (hlookup := hlookup)] set_option maxHeartbeats 8000000 in -/-- `fun_expRayToWad_70` at `x = 0`: the overflow guard `iszero(slt(0, threshold)) = 0` is false, so +/-- `fun_expRayToWad_68` at `x = 0`: the overflow guard `iszero(slt(0, threshold)) = 0` is false, so the panic branch is skipped and the kernel result `10^18` is forwarded. -/ -theorem call_fun_expRayToWad_70_zero_direct +theorem call_fun_expRayToWad_68_zero_direct (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : - EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word 0] (.some "fun_expRayToWad_70") + EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word 0] (.some "fun_expRayToWad_68") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 1000000000000000000]) := by rw [show fuel + (extra + 900) = (fuel + extra) + 900 by omega] rw [EvmYul.Yul.call.eq_def] - simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_70] - simp only [yulFunction_fun_expRayToWad_70, + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_68] + simp only [yulFunction_fun_expRayToWad_68, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -76,7 +76,7 @@ theorem call_fun_expRayToWad_70_zero_direct call_cleanup_t_int256_direct (v := 0) (fuel := fuel + extra) (extra := 865) (shared := shared) (hlookup := hlookup) have hkernel := - call_fun__expRayToWad_80_zero_direct (fuel := fuel + extra) (extra := 187) + call_fun__expRayToWad_78_zero_direct (fuel := fuel + extra) (extra := 187) (shared := shared) (hlookup := hlookup) simp only [Nat.reduceAdd, FormalYul.word] at hconv44 hcleanup hkernel simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, @@ -85,36 +85,36 @@ theorem call_fun_expRayToWad_70_zero_direct EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, - EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.revive, EvmYul.Yul.State.setLeave, + EvmYul.Yul.State.overwrite?, Finmap.lookup_insert, FormalYul.word, call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 876) (shared := shared) (hlookup := hlookup), hcleanup, hconv44, hkernel] set_option maxHeartbeats 8000000 in -/-- `fun_wrap_expRayToWad_99` at `x = 0` forwards to `fun_expRayToWad_70`, giving `10^18`. -/ +/-- `fun_wrap_expRayToWad_97` at `x = 0` forwards to `fun_expRayToWad_68`, giving `10^18`. -/ theorem call_fun_wrap_expRayToWad_zero_direct (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : - EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word 0] (.some "fun_wrap_expRayToWad_99") + EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word 0] (.some "fun_wrap_expRayToWad_97") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word 1000000000000000000]) := by rw [show fuel + (extra + 1100) = (fuel + extra) + 1100 by omega] rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_expRayToWad] - simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_99, + simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_97, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have h70 := - call_fun_expRayToWad_70_zero_direct (fuel := fuel + extra) (extra := 191) + call_fun_expRayToWad_68_zero_direct (fuel := fuel + extra) (extra := 191) (shared := shared) (hlookup := hlookup) simp only [Nat.reduceAdd, FormalYul.word] at h70 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, - EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, @@ -142,7 +142,7 @@ theorem external_fun_wrap_expRayToWad_zero_calldata_result rw [EvmYul.Yul.call.eq_def] simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_expRayToWad] - simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_97, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -196,7 +196,7 @@ theorem external_fun_wrap_expRayToWad_zero_calldata_result EvmYul.Yul.State.store, EvmYul.Yul.State.toMachineState, FormalYul.returnOf, Finmap.lookup_insert, Finmap.lookup_insert_of_ne, - hdecode, hwrap, halloc, hencode, baseStore, memPos, memShared, encStore] + hdecode, hwrap, halloc, hencode] have hmload : ((expSharedAfterFreePtr 0).mload (EvmYul.UInt256.ofNat 64)).1 = EvmYul.UInt256.ofNat 128 := by @@ -225,7 +225,7 @@ theorem external_fun_wrap_expRayToWad_zero_calldata_halts rw [EvmYul.Yul.call.eq_def] simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_expRayToWad] - simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_97, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -277,9 +277,9 @@ theorem external_fun_wrap_expRayToWad_zero_calldata_halts GetElem?.getElem!, decidableGetElem?, EvmYul.Yul.State.instGetElemIdentifierLiteralMemVarStoreStore, EvmYul.Yul.State.store, - EvmYul.Yul.State.toMachineState, FormalYul.returnOf, + EvmYul.Yul.State.toMachineState, Finmap.lookup_insert, Finmap.lookup_insert_of_ne, - hdecode, hwrap, halloc, hencode, baseStore, memPos, memShared, encStore] + hdecode, hwrap, halloc, hencode] set_option maxHeartbeats 12000000 in /-- Result, starting from the exact state the dispatcher hands the external function. -/ @@ -403,15 +403,15 @@ theorem run_exp_ray_to_wad_evm_zero : (hReturn := hReturn) (by simpa using hresult) set_option maxHeartbeats 4000000 in -/-- General kernel reduction for symbolic `x`: `fun__expRayToWad_80(x)` evaluates to the inline, +/-- General kernel reduction for symbolic `x`: `fun__expRayToWad_78(x)` evaluates to the inline, `let`-shared `evm*` arithmetic tree transcribed from `Exp.sol`'s `_expRayToWad` (constants are the literal hex). No hand model: the RHS is the interpreter's own `evm*` ops. The foundation for the runtime floor and monotonicity claims. -/ -theorem call_fun__expRayToWad_80_direct +theorem call_fun__expRayToWad_78_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : - EvmYul.Yul.call (fuel + (extra + 700)) [FormalYul.word x] (.some "fun__expRayToWad_80") + EvmYul.Yul.call (fuel + (extra + 700)) [FormalYul.word x] (.some "fun__expRayToWad_78") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) @@ -436,13 +436,13 @@ theorem call_fun__expRayToWad_80_direct )]) := by rw [show fuel + (extra + 700) = (fuel + extra) + 700 by omega] rw [EvmYul.Yul.call.eq_def] - simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun__expRayToWad_80] - simp only [yulFunction_fun__expRayToWad_80, + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun__expRayToWad_78] + simp only [yulFunction_fun__expRayToWad_78, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, @@ -457,25 +457,25 @@ theorem call_fun__expRayToWad_80_direct FormalYul.Preservation.wordNat_add, FormalYul.Preservation.wordNat_sub, FormalYul.Preservation.wordNat_mul, FormalYul.Preservation.wordNat_iszero, FormalYul.Preservation.wordNat_ofNat, wordNat_sar, wordNat_div, wordNat_slt] - simp only [FormalYul.Preservation.evmAdd_u256_left, FormalYul.Preservation.evmAdd_u256_right, + simp only [FormalYul.Preservation.evmAdd_u256_left, FormalYul.Preservation.evmSub_u256_left, FormalYul.Preservation.evmSub_u256_right, FormalYul.Preservation.evmMul_u256_left, FormalYul.Preservation.evmMul_u256_right, FormalYul.Preservation.evmShl_u256_left, FormalYul.Preservation.evmShl_u256_right, - FormalYul.Preservation.evmShr_u256_left, FormalYul.Preservation.evmShr_u256_right, - FormalYul.Preservation.evmIszero_u256, evmSar_u256_left, evmSar_u256_right, - evmDiv_u256_left, evmDiv_u256_right, evmSlt_u256_left, evmSlt_u256_right, - u256_idem, FormalYul.Preservation.u256_evmAdd] + FormalYul.Preservation.evmShr_u256_left, + FormalYul.Preservation.evmIszero_u256, evmSar_u256_left, + evmSlt_u256_left, evmSlt_u256_right, + FormalYul.Preservation.u256_evmAdd] set_option maxHeartbeats 4000000 in -/-- `fun_expRayToWad_70(x)` for a signed input strictly below the threshold: the overflow guard +/-- `fun_expRayToWad_68(x)` for a signed input strictly below the threshold: the overflow guard `iszero(slt(x, C)) = 0` is skipped (via `slt_thresh_lt`), so the kernel result — the `evm*` tree — is forwarded. -/ -theorem call_fun_expRayToWad_70_direct +theorem call_fun_expRayToWad_68_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : - EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word x] (.some "fun_expRayToWad_70") + EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word x] (.some "fun_expRayToWad_68") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) @@ -500,8 +500,8 @@ theorem call_fun_expRayToWad_70_direct )]) := by rw [show fuel + (extra + 900) = (fuel + extra) + 900 by omega] rw [EvmYul.Yul.call.eq_def] - simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_70] - simp only [yulFunction_fun_expRayToWad_70, + simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_expRayToWad_68] + simp only [yulFunction_fun_expRayToWad_68, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -513,7 +513,7 @@ theorem call_fun_expRayToWad_70_direct call_cleanup_t_int256_direct (v := x) (fuel := fuel + extra) (extra := 865) (shared := shared) (hlookup := hlookup) have hkernel := - call_fun__expRayToWad_80_direct (x := x) (fuel := fuel + extra) (extra := 187) + call_fun__expRayToWad_78_direct (x := x) (fuel := fuel + extra) (extra := 187) (shared := shared) (hlookup := hlookup) simp only [Nat.reduceAdd, FormalYul.word] at hconv44 hcleanup hkernel simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, @@ -522,7 +522,8 @@ theorem call_fun_expRayToWad_70_direct EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, - EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, + EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.revive, EvmYul.Yul.State.setLeave, + EvmYul.Yul.State.overwrite?, Finmap.lookup_insert, FormalYul.word, slt_thresh_lt hval, call_zero_value_for_split_t_int256_direct (fuel := fuel + extra) (extra := 876) @@ -530,14 +531,14 @@ theorem call_fun_expRayToWad_70_direct hcleanup, hconv44, hkernel] set_option maxHeartbeats 4000000 in -/-- `fun_wrap_expRayToWad_99(x)` for a signed input below the threshold forwards to -`fun_expRayToWad_70`, returning the `evm*` tree. -/ +/-- `fun_wrap_expRayToWad_97(x)` for a signed input below the threshold forwards to +`fun_expRayToWad_68`, returning the `evm*` tree. -/ theorem call_fun_wrap_expRayToWad_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : - EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_99") + EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_97") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) @@ -563,18 +564,17 @@ theorem call_fun_wrap_expRayToWad_direct rw [show fuel + (extra + 1100) = (fuel + extra) + 1100 by omega] rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, lookup_fun_wrap_expRayToWad] - simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_99, + simp only [yulFunction_fun_wrap_expRayToWad, yulFunction_fun_wrap_expRayToWad_97, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have h70 := - call_fun_expRayToWad_70_direct (x := x) (fuel := fuel + extra) (extra := 191) + call_fun_expRayToWad_68_direct (x := x) (fuel := fuel + extra) (extra := 191) (shared := shared) (hlookup := hlookup) (hval := hval) simp only [Nat.reduceAdd, FormalYul.word] at h70 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, - EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, @@ -624,7 +624,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result rw [EvmYul.Yul.call.eq_def] simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_expRayToWad] - simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_97, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -699,7 +699,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result EvmYul.Yul.State.store, EvmYul.Yul.State.toMachineState, FormalYul.returnOf, Finmap.lookup_insert, Finmap.lookup_insert_of_ne, - hdecode, hwrap, halloc, hencode, baseStore, memPos, memShared, encStore] + hdecode, hwrap, halloc, hencode] have hmload : ((expSharedAfterFreePtr x).mload (EvmYul.UInt256.ofNat 64)).1 = EvmYul.UInt256.ofNat 128 := by @@ -725,7 +725,7 @@ theorem external_fun_wrap_expRayToWad_calldata_halts rw [EvmYul.Yul.call.eq_def] simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, lookup_external_fun_wrap_expRayToWad] - simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_99, + simp only [yulFunction_external_fun_wrap_expRayToWad, yulFunction_external_fun_wrap_expRayToWad_97, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -800,7 +800,7 @@ theorem external_fun_wrap_expRayToWad_calldata_halts EvmYul.Yul.State.store, EvmYul.Yul.State.toMachineState, Finmap.lookup_insert, Finmap.lookup_insert_of_ne, - hdecode, hwrap, halloc, hencode, baseStore, memPos, memShared, encStore] + hdecode, hwrap, halloc, hencode] set_option maxHeartbeats 16000000 in /-- Result from the dispatcher-handed state. -/ From e82bfdf38cf4cd12d300716aebd8c65fdf2d0522 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 22:18:50 +0200 Subject: [PATCH 135/149] Remove dead hypotheses, no-op tactics, and unused simp arguments Every fix removes the dead thing itself rather than silencing the linter: unused simp arguments are pruned from the reduction and cap proofs (exp Seam sets were pruned with the renumbering; this covers ln RuntimeModel, Floor/Caps, Error/FactoredCap, Error/LtFactoredCap, Common ExpSum and Word, and exp GranV); hypotheses nothing consumes are dropped from smooth_cross_of, DENv_ge_over, tele_step_frac, t_over_2128_le_half_log2, and exp_t_le_sqrt2, with their call sites updated; four ring calls after closing converts and an unused ipow255 are deleted; and Stages moves off the deprecated Int.ofNat_ediv to Int.natCast_ediv. Co-Authored-By: Claude Fable 5 --- formal/common/Common/Foundation/ExpSum.lean | 2 +- formal/common/Common/Word.lean | 2 +- formal/exp/ExpProof/ExpProof/Floor/GranV.lean | 8 ++--- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 12 +++---- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 18 +++++----- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 4 +-- .../exp/ExpProof/ExpProof/Mono/CrossCert.lean | 13 +++---- formal/exp/ExpProof/ExpProof/Mono/Stages.lean | 4 +-- .../exp/ExpProof/ExpProof/Mono/WordFacts.lean | 2 +- .../ln/LnProof/LnProof/Error/FactoredCap.lean | 2 +- .../LnProof/LnProof/Error/LtFactoredCap.lean | 2 +- formal/ln/LnProof/LnProof/Floor/Caps.lean | 4 +-- .../ln/LnProof/LnProof/Seam/RuntimeModel.lean | 36 +++++++++---------- 13 files changed, 50 insertions(+), 59 deletions(-) diff --git a/formal/common/Common/Foundation/ExpSum.lean b/formal/common/Common/Foundation/ExpSum.lean index 7970a8d41..55a01e71b 100644 --- a/formal/common/Common/Foundation/ExpSum.lean +++ b/formal/common/Common/Foundation/ExpSum.lean @@ -258,7 +258,7 @@ theorem cho_fact : ∀ n i, i ≤ n → cho n i * (fact i * fact (n - i)) = fact -- cho k i * ((i+1)! * (k-i)!) = (i+1) * k! have e1 : cho k i * (fact (i + 1) * fact (k - i)) = (i + 1) * fact k := by rw [hf1, ← h1] - simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + simp only [Nat.mul_assoc, Nat.mul_left_comm] -- cho k (i+1) * ((i+1)! * (k-i)!) = (k-i) * k! have e2 : cho k (i + 1) * (fact (i + 1) * fact (k - i)) = (k - i) * fact k := by rw [hs2, show fact ((k - (i + 1)) + 1) = ((k - (i + 1)) + 1) * fact (k - (i + 1)) diff --git a/formal/common/Common/Word.lean b/formal/common/Common/Word.lean index d5b2a9e97..3eaf0c678 100644 --- a/formal/common/Common/Word.lean +++ b/formal/common/Common/Word.lean @@ -225,7 +225,7 @@ theorem wordNat_slt (a b : EvmYul.UInt256) : if (a.toNat + 2 ^ 255) % 2 ^ 256 < (b.toNat + 2 ^ 255) % 2 ^ 256 then 1 else 0 := by unfold EvmYul.UInt256.slt rw [key] - simp only [EvmYul.fromBool, Bool.toUInt256, decide_eq_true_eq] + simp only [Bool.toUInt256, decide_eq_true_eq] split_ifs <;> decide have hua' : u256 (wordNat a) = a.toNat := hua have hub' : u256 (wordNat b) = b.toNat := hub diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean index 2c6908ae2..11445322f 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean @@ -164,14 +164,14 @@ def Pod : List Int := theorem evNumVPoly_eq_Pev_sq (t : Int) : evalPoly ExpCertV.evNumVPoly t = evalPoly Pev (t ^ 2) := by unfold ExpCertV.evNumVPoly ExpCertV.mulT2 Pev - simp only [evalPoly_polyAdd, evalPoly_polyScale, evalPoly] + simp only [evalPoly_polyAdd, evalPoly] ring /-- `odNumVPoly(t) = Pod(t²)`. -/ theorem odNumVPoly_eq_Pod_sq (t : Int) : evalPoly ExpCertV.odNumVPoly t = evalPoly Pod (t ^ 2) := by unfold ExpCertV.odNumVPoly ExpCertV.mulT2 Pod - simp only [evalPoly_polyAdd, evalPoly_polyScale, evalPoly] + simp only [evalPoly_polyAdd, evalPoly] ring /-- `Pev(2¹³³·v) = evNumV(v)·2⁶⁶⁵` — the `w`-polynomial at the grid point `w = 2¹³³·v` recovers the @@ -320,7 +320,7 @@ theorem evalDUnderP (T D : Int) (v : Nat) : /-- The over-half denominator floor: `DENv(v, t) ≥ 554482771859·2^725` for `0 ≤ t ≤ H128` on the grid `[0, vmaxV + 1]`, from the cover certificate `certDOver`. -/ theorem DENv_ge_over {v : Nat} {t : Int} (hv : v ≤ ExpCertV.vmaxV + 1) - (ht0 : 0 ≤ t) (htH : t ≤ 117932881612756647068972071382077242199) : + (htH : t ≤ 117932881612756647068972071382077242199) : 554482771859 * 2 ^ 725 ≤ DENv v t := by have hvI : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ have hvI2 : (v : Int) ≤ 1277263193518626341050532535110179583 := by @@ -345,7 +345,7 @@ theorem DENv_ge_over {v : Nat} {t : Int} (hv : v ≤ ExpCertV.vmaxV + 1) /-- The scaled even value alone clears the over floor. -/ theorem Ev_scaled_ge {v : Nat} (hv : v ≤ ExpCertV.vmaxV + 1) : 554482771859 * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 110 := by - have h := DENv_ge_over hv (t := 0) le_rfl (by norm_num) + have h := DENv_ge_over hv (t := 0) (by norm_num) unfold DENv at h linarith [h] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index ff26437b9..e22d05dcf 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -59,7 +59,7 @@ theorem stage_exact {c prev v sh : Nat} (hprev : prev < 2^256) (hvw : v < 2^256) with shift `s ≥ 120` (constant `A`, `e1 = A + ⌊e0·v/2^s⌋`, `v < 2^120`) produces the new width `Wnum' = Wnum + 2^(cum+s−p−120)` at exponent `p' = p + 120` and scale `cum' = cum + s`. -/ theorem tele_step_frac (e0 e1 v A cum s p Wnum E0 : Nat) - (hv : v < 2^120) (hs : 120 ≤ s) (hAe1 : A ≤ e1) (hpcum : p + 120 ≤ cum + s) + (hv : v < 2^120) (hAe1 : A ≤ e1) (hpcum : p + 120 ≤ cum + s) (hb0lo : 2^cum * e0 ≤ E0) (hb0hi : E0 < 2^cum * e0 + Wnum * 2^p) (hslo : 2^s * (e1 - A) ≤ e0 * v) (hshi : e0 * v < 2^s * (e1 - A) + 2^s) : 2^(cum+s) * e1 ≤ A * 2^(cum+s) + E0 * v ∧ @@ -162,7 +162,7 @@ theorem horner_stage_frac (c prev v cum sh p Wnum Eprev : Nat) have : evmShr sh (evmMul prev v) = prev*v/2^sh := by rw [hmul]; exact evmShr_eq_div (by omega) hpv rw [this]; omega)] omega - exact tele_step_frac prev ev1 v c cum sh p Wnum Eprev hv hs hge hpcum hElo hEhi hst.1 hst.2 + exact tele_step_frac prev ev1 v c cum sh p Wnum Eprev hv hge hpcum hElo hEhi hst.1 hst.2 /-! ## The even accumulator @@ -282,9 +282,9 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : unfold evNumV constructor · have := s4.1 - convert this using 2 <;> ring + convert this using 2 · have := s4.2 - convert this using 2 <;> ring + convert this using 2 /-- info: 'ExpYul.evTree_bracket' depends on axioms: [propext, Classical.choice, Quot.sound] -/ @@ -392,8 +392,8 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : 1075052609 * 2^480 unfold odNumV constructor - · have := s4.1; convert this using 2 <;> ring - · have := s4.2; convert this using 2 <;> ring + · have := s4.1; convert this using 2 + · have := s4.2; convert this using 2 /-- info: 'ExpYul.odTree_bracket' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 8c96fd110..6b3763b5f 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -557,8 +557,7 @@ theorem tdom_neg {x : Nat} (hx : x < 2 ^ 256) /-- On the nonnegative half of the region the reduced argument is below `ln2/2`: `t/2¹²⁸ ≤ log 2 / 2`. -/ theorem t_over_2128_le_half_log2 {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ Real.log 2 / 2 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hln2lo := ln2_lower @@ -579,10 +578,9 @@ theorem t_over_2128_le_half_log2 {x : Nat} (hx : x < 2 ^ 256) /-- `exp(t/2¹²⁸) ≤ √2` on the nonneg half. -/ theorem exp_t_le_sqrt2 {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) : + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) ≤ Real.sqrt 2 := by - have hle := t_over_2128_le_half_log2 hx hC hC0 htnn + have hle := t_over_2128_le_half_log2 hx hC hC0 calc Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) ≤ Real.exp (Real.log 2 / 2) := Real.exp_le_exp.mpr hle _ = Real.sqrt 2 := by @@ -647,7 +645,7 @@ theorem Qv_le_14145 {x : Nat} (hx : x < 2 ^ 256) -- NE/DE ≤ Et·Mp ≤ √2·(2^131/(2^131−1)) ≤ 14144/10000 have hcertlo := certLo_real htnn htdom set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef - have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn + have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 rw [← hEtdef] at hEtsqrt2 have hNEDE_le : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ Et * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) := by @@ -695,7 +693,7 @@ theorem num_ceiling {x : Nat} (hx : x < 2 ^ 256) have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos -- 10000·NUMv ≤ 14145·DENv (from the real cap) @@ -773,7 +771,7 @@ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos rcases le_or_gt ((r0:Real) - 2^126) 0 with hle0 | hgt0 @@ -832,7 +830,7 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) unfold ExpCertV.H128; norm_num] exact hthi set r0 := int256 (r0Tree x) with hr0def - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom @@ -866,7 +864,7 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef set Mp : Real := (2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1) with hMpdef - have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 htnn + have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 rw [← hEtdef] at hEtsqrt2 have hEtnn : (0 : Real) ≤ Et := le_of_lt (Real.exp_pos _) have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index cccdeabd5..6ab75c7b4 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -39,7 +39,7 @@ theorem exp_reducedArg_le_sqrt2bound {x : Nat} (hx : x < 2 ^ 256) have hclose := abs_lt.mp (reducedArg_close hx hC hC0) have hthalf : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ Real.log 2 / 2 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg - · exact t_over_2128_le_half_log2 hx hC hC0 htnn + · exact t_over_2128_le_half_log2 hx hC hC0 · have htle : (int256 (tTree x) : Real) ≤ 0 := by exact_mod_cast le_of_lt htneg have hlog2 : (0:Real) ≤ Real.log 2 := Real.log_nonneg (by norm_num) have : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ 0 := @@ -292,7 +292,7 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by unfold ExpCertV.H128; norm_num] exact hthi - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) htnn hthi + have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom diff --git a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean index 83dab1fbe..9d8db5eaf 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean @@ -86,15 +86,13 @@ theorem vTree_step_nat {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) dominates the loss `2^128·ev2 + |t1|·|od1·ev2 − od2·ev1|`, where the cross difference is controlled by the Lipschitz near-constancy. -/ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} - (hd1 : (340282366920 : Int) ≤ d) (hd2 : d ≤ 340282366921) + (hd1 : (340282366920 : Int) ≤ d) (ht1lo : -(170141183460469231731687303715884105728 : Int) < t1) (ht1hi : t1 < 170141183460469231731687303715884105728) (hev1lo : (103786963397729689639908782561058906594 : Int) ≤ ev1) (hev1hi : ev1 < 170141183460469231731687303715884105728) (hev2lo : (103786963397729689639908782561058906594 : Int) ≤ ev2) (hev2hi : ev2 < 170141183460469231731687303715884105728) - (hod1lo : (51893481698864844819954391280529453297 : Int) ≤ od1) - (hod1hi : od1 < 85070591730234615865843651857942052864) (hod2lo : (51893481698864844819954391280529453297 : Int) ≤ od2) (hod2hi : od2 < 85070591730234615865843651857942052864) (hevd1 : -(42618413185 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 42618413185) @@ -173,23 +171,22 @@ theorem smooth_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) obtain ⟨hg1, hg2⟩ := vTree_step_nat hx1 hx2 hC1 hC01 hC2 hC02 hk hadj obtain ⟨hev1lo, hev1hi⟩ := evTree_int hv1 obtain ⟨hev2lo, hev2hi⟩ := evTree_int hv2 - obtain ⟨hod1lo, hod1hi⟩ := odTree_int hv1 obtain ⟨hod2lo, hod2hi⟩ := odTree_int hv2 obtain ⟨hevd1, hevd2⟩ := evTree_lip_int hv1 hv2 hg1 hg2 obtain ⟨hodd1, hodd2⟩ := odTree_lip_int hv1 hv2 hg1 hg2 - obtain ⟨htg1, htg2⟩ := tTree_step hx1 hx2 hC1 hC01 hC2 hC02 hk hadj + obtain ⟨htg1, -⟩ := tTree_step hx1 hx2 hC1 hC01 hC2 hC02 hk hadj obtain ⟨htlo1, hthi1⟩ := tTree_bound hx1 hC1 hC01 -- numeric rewrites of the power bounds have hGv : (Gstep : Int) = 340282366920 := by unfold Gstep; norm_num - rw [hGv] at htg1 htg2 + rw [hGv] at htg1 rw [show (2 : Int) ^ 127 = 170141183460469231731687303715884105728 by norm_num] at hev1hi hev2hi htlo1 hthi1 - rw [show (2 : Int) ^ 126 = 85070591730234615865843651857942052864 by norm_num] at hod1hi hod2hi + rw [show (2 : Int) ^ 126 = 85070591730234615865843651857942052864 by norm_num] at hod2hi rw [show (2 : Int) ^ 128 = 340282366920938463463374607431768211456 by norm_num] -- t2 = t1 + d, d ∈ [G, G+1] have ht2eq : int256 (tTree x2) = int256 (tTree x1) + (int256 (tTree x2) - int256 (tTree x1)) := by ring rw [ht2eq] - exact smooth_cross_of htg1 htg2 htlo1 hthi1 hev1lo hev1hi hev2lo hev2hi hod1lo hod1hi hod2lo hod2hi + exact smooth_cross_of htg1 htlo1 hthi1 hev1lo hev1hi hev2lo hev2hi hod2lo hod2hi hevd1 hevd2 hodd1 hodd2 /-- Abstract bridge: from the two `tod` floor sandwiches, the smooth inequality, and `ev1 > 0`, diff --git a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean index 794654998..4364dd6f7 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean @@ -208,7 +208,7 @@ theorem vTree_eq {x : Nat} (hx : x < 2 ^ 256) have hmul_small : evmMul (tTree x) (tTree x) < 2 ^ 255 := by have h := hmul unfold int256 at h - split at h <;> simp only [ipow255, ipow256] at * <;> nlinarith [hsq_nn, hsq_lt] + split at h <;> simp only [ipow256] at * <;> nlinarith [hsq_nn, hsq_lt] have hmul_nat : (evmMul (tTree x) (tTree x) : Int) = t * t := by rw [← hmul]; exact (int256_of_lt hmul_small).symm have hmul_nat_lt : evmMul (tTree x) (tTree x) < 2 ^ 253 := by @@ -220,7 +220,7 @@ theorem vTree_eq {x : Nat} (hx : x < 2 ^ 256) rw [evmShr_eq_div (by norm_num) hmul_lt] have he : ((evmMul (tTree x) (tTree x) / 2 ^ 133 : Nat) : Int) = (evmMul (tTree x) (tTree x) : Int) / 2 ^ 133 := by - rw [Int.ofNat_ediv]; norm_num + rw [Int.natCast_ediv]; norm_num rw [he, hmul_nat, ← sq] · unfold vTree rw [evmShr_eq_div (by norm_num) hmul_lt] diff --git a/formal/exp/ExpProof/ExpProof/Mono/WordFacts.lean b/formal/exp/ExpProof/ExpProof/Mono/WordFacts.lean index 7255fc17f..b02c4894b 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/WordFacts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/WordFacts.lean @@ -32,7 +32,7 @@ theorem evmSlt_eq_ite (a b : Nat) : have key : ((u256 a + 2 ^ 255) % 2 ^ 256 < (u256 b + 2 ^ 255) % 2 ^ 256) ↔ (int256 (u256 a) < int256 (u256 b)) := by unfold int256 - simp only [ipow255, ipow256] at hai hbi + simp only [ipow256] at hai hbi by_cases ha : 2 ^ 255 ≤ u256 a <;> by_cases hb : 2 ^ 255 ≤ u256 b · rw [offneg _ hua ha, offneg _ hub hb, if_neg (by omega : ¬ u256 a < 2 ^ 255), if_neg (by omega : ¬ u256 b < 2 ^ 255)] diff --git a/formal/ln/LnProof/LnProof/Error/FactoredCap.lean b/formal/ln/LnProof/LnProof/Error/FactoredCap.lean index 611bc810b..bdb543dbe 100644 --- a/formal/ln/LnProof/LnProof/Error/FactoredCap.lean +++ b/formal/ln/LnProof/LnProof/Error/FactoredCap.lean @@ -212,7 +212,7 @@ theorem ge_pos_cut_reduced {m c x : Nat} {r : Int} _ = (expNum 22 (evalPoly geTN2b (m : Int)).toNat (evalPoly geTD2b (m : Int)).toNat * biasCapNum * (lnErrQ + minPosAvail) * wadRayStrictDen) * ((10 ^ 40 - 1) ^ (160 - c)) * - 10 ^ 40 := by simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + 10 ^ 40 := by simp only [Nat.mul_comm, Nat.mul_left_comm] -- now assemble `hclose` refine ge_pos_cut_factored h1 h2 hphase ?_ -- lower the RHS phase-availability to the constant `minPosAvail` diff --git a/formal/ln/LnProof/LnProof/Error/LtFactoredCap.lean b/formal/ln/LnProof/LnProof/Error/LtFactoredCap.lean index f6b2df7af..d233fea27 100644 --- a/formal/ln/LnProof/LnProof/Error/LtFactoredCap.lean +++ b/formal/ln/LnProof/LnProof/Error/LtFactoredCap.lean @@ -215,7 +215,7 @@ theorem lt_pos_cut_reduced {m c x : Nat} {r : Int} _ = (biasCapNum * (fact 23 * (evalPoly ltTD (m : Int)).toNat ^ 23) * (lnErrQ + minPosAvail) * wadRayStrictDen) * ((10 ^ 40 - 1) ^ (160 - c)) * - 10 ^ 40 := by simp only [Nat.mul_assoc, Nat.mul_comm, Nat.mul_left_comm] + 10 ^ 40 := by simp only [Nat.mul_comm, Nat.mul_left_comm] -- assemble `hbudget` refine lt_pos_cut_factored h1 h2 hc hneg_le hphase ?_ -- lower the RHS phase-availability to the constant `minPosAvail` diff --git a/formal/ln/LnProof/LnProof/Floor/Caps.lean b/formal/ln/LnProof/LnProof/Floor/Caps.lean index 3bfe286b3..3671f554d 100644 --- a/formal/ln/LnProof/LnProof/Floor/Caps.lean +++ b/formal/ln/LnProof/LnProof/Floor/Caps.lean @@ -161,7 +161,7 @@ theorem capGeUp {m : Nat} (h1 : Sc + 46 ≤ m) (h2 : m < MHI) (23 * evalPoly geTD (m : Int)) = 23 * (expNumI 22 (evalPoly geTN (m : Int)) (evalPoly geTD (m : Int)) * evalPoly geTD (m : Int)) := by - simp only [Int.mul_assoc, Int.mul_comm, Int.mul_left_comm] + simp only [Int.mul_assoc, Int.mul_comm] rw [eS] have eR : (m : Int) * 10000000000000000000000000003382 * (25852016738884976640000 * evalPoly geTD (m : Int) ^ 23) = @@ -280,7 +280,7 @@ theorem capLtLo {m : Nat} (h1 : MLO ≤ m) (h2 : m + 46 ≤ Sc) (23 * evalPoly ltTD (m : Int)) = 23 * (expNumI 22 (evalPoly ltTN (m : Int)) (evalPoly ltTD (m : Int)) * evalPoly ltTD (m : Int)) := by - simp only [Int.mul_assoc, Int.mul_comm, Int.mul_left_comm] + simp only [Int.mul_assoc, Int.mul_comm] rw [eS] have eL : (23 * (expNumI 22 (evalPoly ltTN (m : Int)) (evalPoly ltTD (m : Int)) * evalPoly ltTD (m : Int)) + 2 * evalPoly ltTN (m : Int) ^ 23) * diff --git a/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean b/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean index 60abdfd1b..fad5b0eda 100644 --- a/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean +++ b/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean @@ -480,9 +480,8 @@ private theorem call_convert_0_to_int256_direct (store := Finmap.insert "value" (FormalYul.word v) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup) simp [FormalYul.word] at h1 h2 h3 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.evalCall.eq_def, - EvmYul.Yul.evalPrimCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, @@ -506,8 +505,8 @@ private theorem call_cleanup_t_uint8_18_direct FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, @@ -567,8 +566,8 @@ private theorem call_convert_18_to_uint8_18_direct (store := Finmap.insert "value" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup) simp [FormalYul.word] at h1 h2 h3 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, - EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, @@ -628,8 +627,8 @@ private theorem call_convert_uint8_to_uint256_18_direct (store := Finmap.insert "value" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup) simp [FormalYul.word] at h1 h2 h3 - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, - EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, @@ -660,9 +659,8 @@ private theorem call_constant_DIVISION_BY_ZERO_20_direct (store := Finmap.insert "expr_19" (FormalYul.word 0x12) (Inhabited.default : EvmYul.Yul.VarStore)) (hlookup := hlookup) simp [FormalYul.word] at hconv - simp +decide [EvmYul.Yul.execCall.eq_def, EvmYul.Yul.execPrimCall.eq_def, - EvmYul.Yul.evalCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [EvmYul.Yul.execCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, @@ -687,14 +685,13 @@ private theorem call_fun_panic_8_revert_direct FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] - simp +decide [EvmYul.Yul.execCall.eq_def, - EvmYul.Yul.execPrimCall.eq_def, EvmYul.Yul.evalPrimCall.eq_def, - EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', + simp +decide [ + EvmYul.Yul.execPrimCall.eq_def, + EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, - EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, - EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word, primCall_revert_yul] + EvmYul.Yul.State.setStore, + FormalYul.word, primCall_revert_yul] set_option maxHeartbeats 8000000 in /-- The compiled `fun_lnWadToRay_65` computes the model `lnWadToRayBody` for a @@ -789,9 +786,8 @@ theorem call_fun_lnWadToRay_revert_direct EvmYul.Yul.reverse', EvmYul.Yul.cons', EvmYul.Yul.head', EvmYul.Yul.multifill', EvmYul.Yul.evalTail.eq_def, EvmYul.Yul.State.insert, EvmYul.Yul.State.multifill, - EvmYul.Yul.State.lookup!, EvmYul.Yul.State.setStore, - EvmYul.Yul.State.reviveJump, EvmYul.Yul.State.overwrite?, - Finmap.lookup_insert, FormalYul.word, + EvmYul.Yul.State.setStore, + FormalYul.word, sgt_zero_nonpos hnonpos, call_zero_value_for_split_t_int256_direct (fuel := fuel) (extra := 976) (shared := shared) (hlookup := hlookup), From 7f13c76bde3a35c75d5c674cfac43ae6143c0ae7 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Thu, 2 Jul 2026 22:19:04 +0200 Subject: [PATCH 136/149] Deduplicate the word-level proof machinery into Common.Word The general shift/division floor lemmas live once, in Common.Word: evmShr_lt, evmShl_lt, evmShr_eq_div, evmShl_eq, the signed evmSar floor sandwich at an arbitrary shift, and the truncated-division monotonicity chain (nat_div_cross_mono, toNat_mul_of_nonneg, cross_to_div). exp Mono/WordMono keeps its short names as one-line re-exports (the same shape it already uses for the FormalYul.Preservation transports); its ipow256/ipow255 delegate to intPow256/intPow255 and the dead le_of_mul_le_mul_pos is removed. ln stops re-proving shared facts: Foundation/Word's twelve int256/evm* transports delegate to FormalYul.Preservation, Foundation/WordDiv's seven per-shift evmSar sandwiches and three evmShr floor-division instances derive from the Common.Word general lemmas (statements unchanged, so no call site moves), Mono/Step's cross_to_div and toNat_mul_of_nonneg delegate likewise, Seam/RuntimeModel drops its verbatim copies of the Common.Word u256/wordNat bridge (u256_lt_word through wordNat_sdiv) in favor of the shared module, and Floor/Caps takes eval01 from Common.Foundation.Kronecker. Both proof packages build green through their axiom gates with the generated certificates byte-identical. Co-Authored-By: Claude Fable 5 --- formal/common/Common/Word.lean | 146 +++++++++++++ .../exp/ExpProof/ExpProof/Mono/WordMono.lean | 170 ++------------- formal/ln/LnProof/LnProof/Correct.lean | 1 + .../ln/LnProof/LnProof/ErrorBoundRuntime.lean | 1 + formal/ln/LnProof/LnProof/Floor/Caps.lean | 5 +- .../ln/LnProof/LnProof/Foundation/Word.lean | 57 ++---- .../LnProof/LnProof/Foundation/WordDiv.lean | 102 +++------ formal/ln/LnProof/LnProof/Mono/Step.lean | 13 +- .../ln/LnProof/LnProof/Seam/RuntimeModel.lean | 193 +----------------- 9 files changed, 223 insertions(+), 465 deletions(-) diff --git a/formal/common/Common/Word.lean b/formal/common/Common/Word.lean index 3eaf0c678..96b5a4a97 100644 --- a/formal/common/Common/Word.lean +++ b/formal/common/Common/Word.lean @@ -258,4 +258,150 @@ theorem evmSdiv_u256_left (a b : Nat) : evmSdiv (u256 a) b = evmSdiv a b := by theorem evmSdiv_u256_right (a b : Nat) : evmSdiv a (u256 b) = evmSdiv a b := by simp only [evmSdiv, u256_idem] +/-! ## Shift and division floor lemmas (general shift amounts) -/ + +theorem evmShr_lt (s w : Nat) : evmShr s w < 2 ^ 256 := by + unfold evmShr u256 + simp only [word_mod_eq] + have hv : w % 2 ^ 256 < 2 ^ 256 := Nat.mod_lt _ (Nat.two_pow_pos 256) + split + · exact Nat.lt_of_le_of_lt (Nat.div_le_self _ _) hv + · exact Nat.two_pow_pos 256 + +theorem evmShl_lt (s w : Nat) : evmShl s w < 2 ^ 256 := by + unfold evmShl u256 + simp only [word_mod_eq] + split + · exact Nat.mod_lt _ (Nat.two_pow_pos 256) + · exact Nat.two_pow_pos 256 + +/-- `evmShr` is plain `Nat` floor division for an in-range word and shift. -/ +theorem evmShr_eq_div {s : Nat} (hs : s < 256) {w : Nat} (h : w < 2 ^ 256) : + evmShr s w = w / 2 ^ s := by + have hwm : w % 2 ^ 256 = w := Nat.mod_eq_of_lt h + have hsm : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) + unfold evmShr u256 + simp only [word_mod_eq, hwm, hsm] + rw [if_pos (by omega : s < 256)] + +/-- `evmShl` is plain multiplication when the product fits. -/ +theorem evmShl_eq {s : Nat} (hs : s < 256) {w : Nat} (h : w * 2 ^ s < 2 ^ 256) : + evmShl s w = w * 2 ^ s := by + unfold evmShl u256 + simp only [word_mod_eq] + have hs2 : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) + have hpos : 0 < 2 ^ s := Nat.two_pow_pos s + have hw : w < 2 ^ 256 := by + have h1 : w * 1 ≤ w * 2 ^ s := Nat.mul_le_mul_left w hpos + omega + rw [hs2, if_pos hs, Nat.mod_eq_of_lt hw, Nat.mod_eq_of_lt h] + +/-- `evmSar s w` is the signed floor of `int256 w / 2^s` for a shift `s < 256`: +`2^s · int256 (evmSar s w) ≤ int256 w < 2^s · int256 (evmSar s w) + 2^s`, and the result is a +valid word. -/ +theorem evmSar_sandwich {s : Nat} (hs : s < 256) {w : Nat} (h : w < 2 ^ 256) : + evmSar s w < 2 ^ 256 ∧ + (2 ^ s : Int) * int256 (evmSar s w) ≤ int256 w ∧ + int256 w < (2 ^ s : Int) * int256 (evmSar s w) + (2 ^ s : Int) := by + have hps : (0 : Nat) < 2 ^ s := Nat.two_pow_pos s + have hwm : w % 2 ^ 256 = w := Nat.mod_eq_of_lt h + have hsm : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) + -- `2^256 = 2^s * 2^(256-s)`, so the complement's floor relates to `w`'s floor. + have hsplit : (2 : Nat) ^ 256 = 2 ^ s * 2 ^ (256 - s) := by + rw [← Nat.pow_add]; congr 1; omega + have hsne : ¬ 256 ≤ s := by omega + unfold evmSar u256 int256 + simp only [word_mod_eq, hwm, hsm, hsne, if_false] + by_cases hneg : 2 ^ 255 ≤ w + · rw [if_pos hneg] + -- result word = 2^256 - 1 - (2^256 - 1 - w)/2^s; it is in the negative half. + set m := 2 ^ 256 - 1 - w with hm + set q := m / 2 ^ s with hq + have hmlt : m < 2 ^ 255 := by omega + -- floor facts for q + have hqlo : 2 ^ s * q ≤ m := by rw [Nat.mul_comm]; exact Nat.div_mul_le_self m (2 ^ s) + have hqhi : m < 2 ^ s * q + 2 ^ s := by + have hdm := Nat.div_add_mod m (2 ^ s) + have hmod := Nat.mod_lt m hps + have hc : 2 ^ s * (m / 2 ^ s) = q * 2 ^ s := by rw [← hq]; exact Nat.mul_comm _ _ + have hc2 : 2 ^ s * q = q * 2 ^ s := Nat.mul_comm _ _ + omega + have hqle : q ≤ m := by rw [hq]; exact Nat.div_le_self m (2 ^ s) + have hqlt : q < 2 ^ 255 := by omega + -- the result word `rw = 2^256 - 1 - q` lies in the negative half + have hrwlt : (2 ^ 256 - 1 - q) < 2 ^ 256 := + Nat.lt_of_le_of_lt (Nat.sub_le _ _) (by omega) + have hrwneg : 2 ^ 255 ≤ 2 ^ 256 - 1 - q := by omega + rw [if_neg (Nat.not_lt.mpr hrwneg)] + rw [if_neg (Nat.not_lt.mpr hneg)] + -- Cast the Nat-level floor facts to `Int` once, as relations among `↑q`, `↑w`, `↑(2^s)`. + have hqloI : (2 ^ s : Int) * (q : Int) ≤ (2 ^ 256 : Int) - 1 - (w : Int) := by + have h0 : ((2 ^ s * q : Nat) : Int) ≤ ((m : Nat) : Int) := by exact_mod_cast hqlo + have hmI : ((m : Nat) : Int) = (2 ^ 256 : Int) - 1 - (w : Int) := by + rw [hm]; simp only [intPow256]; push_cast [Nat.sub_sub]; omega + push_cast at h0; rw [hmI] at h0; linarith + have hqhiI : (2 ^ 256 : Int) - 1 - (w : Int) < (2 ^ s : Int) * (q : Int) + (2 ^ s : Int) := by + have h0 : ((m : Nat) : Int) < ((2 ^ s * q + 2 ^ s : Nat) : Int) := by exact_mod_cast hqhi + have hmI : ((m : Nat) : Int) = (2 ^ 256 : Int) - 1 - (w : Int) := by + rw [hm]; simp only [intPow256]; push_cast [Nat.sub_sub]; omega + push_cast at h0; rw [hmI] at h0; linarith + have hresI : ((2 ^ 256 - 1 - q : Nat) : Int) = (2 ^ 256 : Int) - 1 - (q : Int) := by + simp only [intPow256]; push_cast [Nat.sub_sub]; omega + refine ⟨hrwlt, ?_, ?_⟩ + · rw [hresI]; nlinarith [hqloI] + · rw [hresI]; nlinarith [hqhiI] + · rw [if_neg hneg] + -- nonnegative: result word = w / 2^s, both halves nonnegative. + set q := w / 2 ^ s with hq + have hqlt : q < 2 ^ 255 := by + have : w / 2 ^ s ≤ w := Nat.div_le_self w (2 ^ s) + omega + have hqlt2 : q < 2 ^ 256 := by omega + rw [if_pos hqlt, if_pos (by omega : w < 2 ^ 255)] + have hfloor := Nat.div_mul_le_self w (2 ^ s) + have hfloor2 : w < (w / 2 ^ s) * 2 ^ s + 2 ^ s := by + have hdm := Nat.div_add_mod w (2 ^ s) + have hmod := Nat.mod_lt w hps + have hc : 2 ^ s * (w / 2 ^ s) = (w / 2 ^ s) * 2 ^ s := Nat.mul_comm _ _ + omega + refine ⟨hqlt2, ?_, ?_⟩ + · have he : (2 ^ s : Int) * (q : Int) = ((2 ^ s * q : Nat) : Int) := by push_cast; ring + rw [he] + have hh : 2 ^ s * q ≤ w := by rw [hq, Nat.mul_comm]; exact hfloor + exact_mod_cast hh + · have he : (2 ^ s : Int) * (q : Int) + (2 ^ s : Int) = ((2 ^ s * q + 2 ^ s : Nat) : Int) := by + push_cast; ring + rw [he] + have hh : w < 2 ^ s * q + 2 ^ s := by rw [hq, Nat.mul_comm]; exact hfloor2 + exact_mod_cast hh + +/-! ## Cross-multiplied monotonicity of truncated division -/ + +theorem nat_div_cross_mono {a b c d : Nat} (hb : 0 < b) (hd : 0 < d) + (h : a * d ≤ c * b) : a / b ≤ c / d := by + rw [Nat.le_div_iff_mul_le hd] + have h1 : a / b * b ≤ a := Nat.div_mul_le_self a b + have h2 : a / b * b * d ≤ a * d := Nat.mul_le_mul_right d h1 + have h3 : a / b * b * d ≤ c * b := Nat.le_trans h2 h + have h4 : a / b * d * b ≤ c * b := by + have : a / b * b * d = a / b * d * b := by + rw [Nat.mul_assoc, Nat.mul_comm b d, ← Nat.mul_assoc] + omega + exact Nat.le_of_mul_le_mul_right h4 hb + +theorem toNat_mul_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) : + x.toNat * y.toNat = (x * y).toNat := by + obtain ⟨a, rfl⟩ := Int.eq_ofNat_of_zero_le hx + obtain ⟨b, rfl⟩ := Int.eq_ofNat_of_zero_le hy + rfl + +/-- Cross-multiplication to truncated-division monotonicity over signed positive numerators. -/ +theorem cross_to_div {n1 n2 W1 W2 : Int} (hn1 : 0 ≤ n1) (hn2 : 0 ≤ n2) + (hW1 : 0 < W1) (hW2 : 0 < W2) (hcross : n1 * W2 ≤ n2 * W1) : + n1.toNat / W1.toNat ≤ n2.toNat / W2.toNat := by + refine nat_div_cross_mono (by omega) (by omega) ?_ + have e1 := toNat_mul_of_nonneg hn1 (by omega : (0:Int) ≤ W2) + have e2 := toNat_mul_of_nonneg hn2 (by omega : (0:Int) ≤ W1) + omega + end Common.Word diff --git a/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean b/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean index c42065e1f..a85f30c6b 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/WordMono.lean @@ -7,14 +7,12 @@ The `exp` monotonicity argument reasons about `` (an `evm*` Nat expressi two's-complement signed view `int256`. This file collects the contract-agnostic facts the argument needs that the shared `FormalYul.Preservation` does not already provide: -* general floor sandwiches for `evmSar`/`evmShr` (the arithmetic/logical right shifts), at an - arbitrary shift amount, expressed against the signed value; -* the in-range `evmDiv`/`evmShr`/`evmShl` evaluations (plain `Nat` division/shift/multiply); -* cross-multiplied monotonicity of truncated division; +* the in-range `evmDiv` evaluations (plain `Nat` division) and the `evmSar`/`evmDiv` word bounds; * small `Int` multiplication-monotonicity helpers. -`FormalYul.Preservation` already supplies the `int256` transports for `add`/`sub`/`mul` and the -`int256`/`uint256OfInt` round-trips, so those are used directly. +`FormalYul.Preservation` supplies the `int256` transports for `add`/`sub`/`mul` and the +`int256`/`uint256OfInt` round-trips, and `Common.Word` supplies the general shift/division floor +lemmas; both are re-exported under the short names the tree lemmas use. -/ namespace ExpYul @@ -29,13 +27,13 @@ set_option maxRecDepth 100000 theorem ipow256 : (2 : Int) ^ 256 = - 115792089237316195423570985008687907853269984665640564039457584007913129639936 := by - norm_num + 115792089237316195423570985008687907853269984665640564039457584007913129639936 := + intPow256 theorem ipow255 : (2 : Int) ^ 255 = - 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by - norm_num + 57896044618658097711785492504343953926634992332820282019728792003956564819968 := + intPow255 /-! ## `Int` multiplication-monotonicity helpers -/ @@ -45,14 +43,6 @@ theorem mul_le_mul_right_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : a * theorem mul_le_mul_left_nonneg {a b c : Int} (h : a ≤ b) (hc : 0 ≤ c) : c * a ≤ c * b := Int.mul_le_mul_of_nonneg_left h hc -/-- Cancellation of a positive literal factor. -/ -theorem le_of_mul_le_mul_pos {a b c : Int} (h : a * c ≤ b * c) (hc : 0 < c) : a ≤ b := by - rcases Int.lt_or_le b a with hlt | hle - · exfalso - have := Int.mul_lt_mul_of_pos_right hlt hc - omega - · exact hle - /-! ## Magnitude bounds and the signed-`u256` conversions -/ theorem u256_of_lt {w : Nat} (h : w < 2 ^ 256) : u256 w = w := u256_of_lt_pow256 h @@ -70,20 +60,9 @@ theorem evmMul_lt (a b : Nat) : evmMul a b < 2 ^ 256 := evmMul_lt_pow256 a b theorem pow256_pos : (0 : Nat) < 2 ^ 256 := Nat.two_pow_pos 256 -theorem evmShr_lt (s w : Nat) : evmShr s w < 2 ^ 256 := by - unfold evmShr u256 - simp only [word_mod_eq] - have hv : w % 2 ^ 256 < 2 ^ 256 := Nat.mod_lt _ pow256_pos - split - · exact Nat.lt_of_le_of_lt (Nat.div_le_self _ _) hv - · exact pow256_pos +theorem evmShr_lt (s w : Nat) : evmShr s w < 2 ^ 256 := Common.Word.evmShr_lt s w -theorem evmShl_lt (s w : Nat) : evmShl s w < 2 ^ 256 := by - unfold evmShl u256 - simp only [word_mod_eq] - split - · exact Nat.mod_lt _ pow256_pos - · exact pow256_pos +theorem evmShl_lt (s w : Nat) : evmShl s w < 2 ^ 256 := Common.Word.evmShl_lt s w theorem evmSar_lt (s w : Nat) : evmSar s w < 2 ^ 256 := by unfold evmSar u256 @@ -150,137 +129,26 @@ theorem evmMul_transport {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) (h1 : -(2 ^ 255) ≤ int256 a * int256 b) (h2 : int256 a * int256 b < 2 ^ 255) : int256 (evmMul a b) = int256 a * int256 b := evmMul_int256 ha hb h1 h2 -/-! ## `evmShr` as floor division for in-range nonnegative operands -/ +/-! ## Re-exports of the shared shift/division floor lemmas -/ theorem evmShr_eq_div {s : Nat} (hs : s < 256) {w : Nat} (h : w < 2 ^ 256) : - evmShr s w = w / 2 ^ s := by - have hwm : w % 2 ^ 256 = w := Nat.mod_eq_of_lt h - have hsm : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) - unfold evmShr u256 - simp only [word_mod_eq, hwm, hsm] - rw [if_pos (by omega : s < 256)] - -/-! ## `evmShl` as multiplication when the product fits -/ + evmShr s w = w / 2 ^ s := Common.Word.evmShr_eq_div hs h theorem evmShl_eq {s : Nat} (hs : s < 256) {w : Nat} (h : w * 2 ^ s < 2 ^ 256) : - evmShl s w = w * 2 ^ s := by - unfold evmShl u256 - simp only [word_mod_eq] - have hs2 : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) - have hpos : 0 < 2 ^ s := Nat.two_pow_pos s - have hw : w < 2 ^ 256 := by - have h1 : w * 1 ≤ w * 2 ^ s := Nat.mul_le_mul_left w hpos - omega - rw [hs2, if_pos hs, Nat.mod_eq_of_lt hw, Nat.mod_eq_of_lt h] + evmShl s w = w * 2 ^ s := Common.Word.evmShl_eq hs h -/-! ## `evmSar` general floor sandwich (signed value) -/ - -/-- `evmSar s w` is the signed floor of `int256 w / 2^s` for a shift `s < 256`: -`2^s · int256 (evmSar s w) ≤ int256 w < 2^s · int256 (evmSar s w) + 2^s`, and the result is a -valid word. The reduced-argument and `t·Od` shifts are the remaining arithmetic-shift sites. -/ +/-- `evmSar s w` is the signed floor of `int256 w / 2^s` for a shift `s < 256`. The +reduced-argument and `t·Od` shifts are the remaining arithmetic-shift sites. -/ theorem evmSar_sandwich {s : Nat} (hs : s < 256) {w : Nat} (h : w < 2 ^ 256) : evmSar s w < 2 ^ 256 ∧ (2 ^ s : Int) * int256 (evmSar s w) ≤ int256 w ∧ - int256 w < (2 ^ s : Int) * int256 (evmSar s w) + (2 ^ s : Int) := by - have hps : (0 : Nat) < 2 ^ s := Nat.two_pow_pos s - have hwm : w % 2 ^ 256 = w := Nat.mod_eq_of_lt h - have hsm : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) - -- `2^256 = 2^s * 2^(256-s)`, so the complement's floor relates to `w`'s floor. - have hsplit : (2 : Nat) ^ 256 = 2 ^ s * 2 ^ (256 - s) := by - rw [← Nat.pow_add]; congr 1; omega - have hsne : ¬ 256 ≤ s := by omega - unfold evmSar u256 int256 - simp only [word_mod_eq, hwm, hsm, hsne, if_false] - by_cases hneg : 2 ^ 255 ≤ w - · rw [if_pos hneg] - -- result word = 2^256 - 1 - (2^256 - 1 - w)/2^s; it is in the negative half. - set m := 2 ^ 256 - 1 - w with hm - set q := m / 2 ^ s with hq - have hmlt : m < 2 ^ 255 := by omega - -- floor facts for q - have hqlo : 2 ^ s * q ≤ m := by rw [Nat.mul_comm]; exact Nat.div_mul_le_self m (2 ^ s) - have hqhi : m < 2 ^ s * q + 2 ^ s := by - have hdm := Nat.div_add_mod m (2 ^ s) - have hmod := Nat.mod_lt m hps - have hc : 2 ^ s * (m / 2 ^ s) = q * 2 ^ s := by rw [← hq]; exact Nat.mul_comm _ _ - have hc2 : 2 ^ s * q = q * 2 ^ s := Nat.mul_comm _ _ - omega - have hqle : q ≤ m := by rw [hq]; exact Nat.div_le_self m (2 ^ s) - have hqlt : q < 2 ^ 255 := by omega - -- the result word `rw = 2^256 - 1 - q` lies in the negative half - have hrwlt : (2 ^ 256 - 1 - q) < 2 ^ 256 := - Nat.lt_of_le_of_lt (Nat.sub_le _ _) (by omega) - have hrwneg : 2 ^ 255 ≤ 2 ^ 256 - 1 - q := by omega - rw [if_neg (Nat.not_lt.mpr hrwneg)] - rw [if_neg (Nat.not_lt.mpr hneg)] - -- Cast the Nat-level floor facts to `Int` once, as relations among `↑q`, `↑w`, `↑(2^s)`. - have hqloI : (2 ^ s : Int) * (q : Int) ≤ (2 ^ 256 : Int) - 1 - (w : Int) := by - have h0 : ((2 ^ s * q : Nat) : Int) ≤ ((m : Nat) : Int) := by exact_mod_cast hqlo - have hmI : ((m : Nat) : Int) = (2 ^ 256 : Int) - 1 - (w : Int) := by - rw [hm]; simp only [ipow256]; push_cast [Nat.sub_sub]; omega - push_cast at h0; rw [hmI] at h0; linarith - have hqhiI : (2 ^ 256 : Int) - 1 - (w : Int) < (2 ^ s : Int) * (q : Int) + (2 ^ s : Int) := by - have h0 : ((m : Nat) : Int) < ((2 ^ s * q + 2 ^ s : Nat) : Int) := by exact_mod_cast hqhi - have hmI : ((m : Nat) : Int) = (2 ^ 256 : Int) - 1 - (w : Int) := by - rw [hm]; simp only [ipow256]; push_cast [Nat.sub_sub]; omega - push_cast at h0; rw [hmI] at h0; linarith - have hresI : ((2 ^ 256 - 1 - q : Nat) : Int) = (2 ^ 256 : Int) - 1 - (q : Int) := by - simp only [ipow256]; push_cast [Nat.sub_sub]; omega - refine ⟨hrwlt, ?_, ?_⟩ - · rw [hresI]; nlinarith [hqloI] - · rw [hresI]; nlinarith [hqhiI] - · rw [if_neg hneg] - -- nonnegative: result word = w / 2^s, both halves nonnegative. - set q := w / 2 ^ s with hq - have hqlt : q < 2 ^ 255 := by - have : w / 2 ^ s ≤ w := Nat.div_le_self w (2 ^ s) - omega - have hqlt2 : q < 2 ^ 256 := by omega - rw [if_pos hqlt, if_pos (by omega : w < 2 ^ 255)] - have hfloor := Nat.div_mul_le_self w (2 ^ s) - have hfloor2 : w < (w / 2 ^ s) * 2 ^ s + 2 ^ s := by - have hdm := Nat.div_add_mod w (2 ^ s) - have hmod := Nat.mod_lt w hps - have hc : 2 ^ s * (w / 2 ^ s) = (w / 2 ^ s) * 2 ^ s := Nat.mul_comm _ _ - omega - refine ⟨hqlt2, ?_, ?_⟩ - · have he : (2 ^ s : Int) * (q : Int) = ((2 ^ s * q : Nat) : Int) := by push_cast; ring - rw [he] - have hh : 2 ^ s * q ≤ w := by rw [hq, Nat.mul_comm]; exact hfloor - exact_mod_cast hh - · have he : (2 ^ s : Int) * (q : Int) + (2 ^ s : Int) = ((2 ^ s * q + 2 ^ s : Nat) : Int) := by - push_cast; ring - rw [he] - have hh : w < 2 ^ s * q + 2 ^ s := by rw [hq, Nat.mul_comm]; exact hfloor2 - exact_mod_cast hh - -/-! ## Cross-multiplied monotonicity of `Nat` division -/ - -theorem nat_div_cross_mono {a b c d : Nat} (hb : 0 < b) (hd : 0 < d) - (h : a * d ≤ c * b) : a / b ≤ c / d := by - rw [Nat.le_div_iff_mul_le hd] - have h1 : a / b * b ≤ a := Nat.div_mul_le_self a b - have h2 : a / b * b * d ≤ a * d := Nat.mul_le_mul_right d h1 - have h3 : a / b * b * d ≤ c * b := Nat.le_trans h2 h - have h4 : a / b * d * b ≤ c * b := by - have : a / b * b * d = a / b * d * b := by - rw [Nat.mul_assoc, Nat.mul_comm b d, ← Nat.mul_assoc] - omega - exact Nat.le_of_mul_le_mul_right h4 hb - -theorem toNat_mul_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) : - x.toNat * y.toNat = (x * y).toNat := by - obtain ⟨a, rfl⟩ := Int.eq_ofNat_of_zero_le hx - obtain ⟨b, rfl⟩ := Int.eq_ofNat_of_zero_le hy - rfl + int256 w < (2 ^ s : Int) * int256 (evmSar s w) + (2 ^ s : Int) := + Common.Word.evmSar_sandwich hs h /-- Cross-multiplication to truncated-division monotonicity over signed positive numerators. -/ theorem cross_to_div {n1 n2 W1 W2 : Int} (hn1 : 0 ≤ n1) (hn2 : 0 ≤ n2) (hW1 : 0 < W1) (hW2 : 0 < W2) (hcross : n1 * W2 ≤ n2 * W1) : - n1.toNat / W1.toNat ≤ n2.toNat / W2.toNat := by - refine nat_div_cross_mono (by omega) (by omega) ?_ - have e1 := toNat_mul_of_nonneg hn1 (by omega : (0:Int) ≤ W2) - have e2 := toNat_mul_of_nonneg hn2 (by omega : (0:Int) ≤ W1) - omega + n1.toNat / W1.toNat ≤ n2.toNat / W2.toNat := + Common.Word.cross_to_div hn1 hn2 hW1 hW2 hcross end ExpYul diff --git a/formal/ln/LnProof/LnProof/Correct.lean b/formal/ln/LnProof/LnProof/Correct.lean index c1780101e..4728da7e1 100644 --- a/formal/ln/LnProof/LnProof/Correct.lean +++ b/formal/ln/LnProof/LnProof/Correct.lean @@ -18,6 +18,7 @@ namespace LnYul open FormalYul open FormalYul.Preservation +open Common.Word noncomputable section diff --git a/formal/ln/LnProof/LnProof/ErrorBoundRuntime.lean b/formal/ln/LnProof/LnProof/ErrorBoundRuntime.lean index 182511c89..91d85994f 100644 --- a/formal/ln/LnProof/LnProof/ErrorBoundRuntime.lean +++ b/formal/ln/LnProof/LnProof/ErrorBoundRuntime.lean @@ -21,6 +21,7 @@ namespace LnYul open FormalYul open FormalYul.Preservation +open Common.Word noncomputable section diff --git a/formal/ln/LnProof/LnProof/Floor/Caps.lean b/formal/ln/LnProof/LnProof/Floor/Caps.lean index 3671f554d..48132e4b6 100644 --- a/formal/ln/LnProof/LnProof/Floor/Caps.lean +++ b/formal/ln/LnProof/LnProof/Floor/Caps.lean @@ -1,5 +1,6 @@ import LnProof.Floor.Bracket import LnProof.Floor.CertAux +import Common.Foundation.Kronecker open FormalYul open FormalYul.Preservation @@ -18,10 +19,6 @@ open LnYul Common.Poly Common.Exp set_option maxRecDepth 100000 -theorem eval01 (x : Int) : evalPoly ([0, 1] : List Int) x = x := by - show (0 : Int) + x * (1 + x * 0) = x - omega - theorem evalCertGeUp (m : Nat) : evalPoly certGeUp (m : Int) = (EUD + EUN) * KF1 * ((m : Int) * evalPoly geTD (m : Int) ^ 23) + diff --git a/formal/ln/LnProof/LnProof/Foundation/Word.lean b/formal/ln/LnProof/LnProof/Foundation/Word.lean index 26a8d1174..515236d88 100644 --- a/formal/ln/LnProof/LnProof/Foundation/Word.lean +++ b/formal/ln/LnProof/LnProof/Foundation/Word.lean @@ -18,38 +18,30 @@ namespace LnYul /-- `omega` needs numeral divisors for `Int.emod`; these rewrite the powers. -/ theorem ipow256 : (2 : Int) ^ 256 = - 115792089237316195423570985008687907853269984665640564039457584007913129639936 := by - rfl + 115792089237316195423570985008687907853269984665640564039457584007913129639936 := + intPow256 theorem ipow255 : (2 : Int) ^ 255 = - 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by - rfl + 57896044618658097711785492504343953926634992332820282019728792003956564819968 := + intPow255 theorem word_mod_eq : WORD_MOD = 2 ^ 256 := rfl theorem u256_eq (w : Nat) : u256 w = w % 2 ^ 256 := rfl -theorem u256_of_lt {w : Nat} (h : w < 2 ^ 256) : u256 w = w := by - simpa [u256_eq] using Nat.mod_eq_of_lt h +theorem u256_of_lt {w : Nat} (h : w < 2 ^ 256) : u256 w = w := u256_of_lt_pow256 h -theorem toInt_lt {w : Nat} (h : w < 2 ^ 256) : int256 w < 2 ^ 255 := by - unfold int256; simp only [ipow255, ipow256]; split <;> omega +theorem toInt_lt {w : Nat} (h : w < 2 ^ 256) : int256 w < 2 ^ 255 := int256_lt h -theorem toInt_ge {w : Nat} (h : w < 2 ^ 256) : -(2 ^ 255) ≤ int256 w := by - unfold int256; simp only [ipow255, ipow256]; split <;> omega +theorem toInt_ge {w : Nat} (h : w < 2 ^ 256) : -(2 ^ 255) ≤ int256 w := int256_ge h -theorem toInt_of_lt {w : Nat} (h : w < 2 ^ 255) : int256 w = (w : Int) := by - unfold int256; split <;> omega +theorem toInt_of_lt {w : Nat} (h : w < 2 ^ 255) : int256 w = (w : Int) := int256_of_lt h -theorem ofInt_lt (x : Int) : uint256OfInt x < 2 ^ 256 := by - unfold uint256OfInt; simp only [ipow256]; omega +theorem ofInt_lt (x : Int) : uint256OfInt x < 2 ^ 256 := uint256OfInt_lt x theorem toInt_ofInt {x : Int} (h1 : -(2 ^ 255) ≤ x) (h2 : x < 2 ^ 255) : - int256 (uint256OfInt x) = x := by - unfold int256 uint256OfInt - simp only [ipow255, ipow256] at * - split <;> omega + int256 (uint256OfInt x) = x := int256_uint256OfInt h1 h2 theorem ofInt_toInt {w : Nat} (h : w < 2 ^ 256) : uint256OfInt (int256 w) = w := by unfold int256 uint256OfInt @@ -98,39 +90,22 @@ theorem evmMul_eq {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) : unfold evmMul u256; simp only [word_mod_eq] rw [Nat.mod_eq_of_lt ha, Nat.mod_eq_of_lt hb] -theorem evmAdd_lt (a b : Nat) : evmAdd a b < 2 ^ 256 := by - unfold evmAdd u256; simp only [word_mod_eq]; omega +theorem evmAdd_lt (a b : Nat) : evmAdd a b < 2 ^ 256 := evmAdd_lt_pow256 a b -theorem evmSub_lt (a b : Nat) : evmSub a b < 2 ^ 256 := by - unfold evmSub u256; simp only [word_mod_eq]; omega +theorem evmSub_lt (a b : Nat) : evmSub a b < 2 ^ 256 := evmSub_lt_pow256 a b -theorem evmMul_lt (a b : Nat) : evmMul a b < 2 ^ 256 := by - unfold evmMul u256; simp only [word_mod_eq]; omega +theorem evmMul_lt (a b : Nat) : evmMul a b < 2 ^ 256 := evmMul_lt_pow256 a b theorem evmAdd_transport {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) (h1 : -(2 ^ 255) ≤ int256 a + int256 b) (h2 : int256 a + int256 b < 2 ^ 255) : - int256 (evmAdd a b) = int256 a + int256 b := by - rw [evmAdd_eq a b] - refine toInt_wrap ?_ h1 h2 - have hc : ((a + b : Nat) : Int) = (a : Int) + (b : Int) := by omega - rw [hc, Int.add_emod, toInt_mod_cong ha, toInt_mod_cong hb, ← Int.add_emod] + int256 (evmAdd a b) = int256 a + int256 b := evmAdd_int256 ha hb h1 h2 theorem evmSub_transport {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) (h1 : -(2 ^ 255) ≤ int256 a - int256 b) (h2 : int256 a - int256 b < 2 ^ 255) : - int256 (evmSub a b) = int256 a - int256 b := by - rw [evmSub_eq ha hb] - refine toInt_wrap ?_ h1 h2 - have hc : ((a + 2 ^ 256 - b : Nat) : Int) = (a : Int) - (b : Int) + 2 ^ 256 := by - simp only [ipow256]; omega - rw [hc, Int.add_emod_right, Int.sub_emod, toInt_mod_cong ha, toInt_mod_cong hb, - ← Int.sub_emod] + int256 (evmSub a b) = int256 a - int256 b := evmSub_int256 ha hb h1 h2 theorem evmMul_transport {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) (h1 : -(2 ^ 255) ≤ int256 a * int256 b) (h2 : int256 a * int256 b < 2 ^ 255) : - int256 (evmMul a b) = int256 a * int256 b := by - rw [evmMul_eq ha hb] - refine toInt_wrap ?_ h1 h2 - have hc : ((a * b : Nat) : Int) = (a : Int) * (b : Int) := by exact_mod_cast rfl - rw [hc, Int.mul_emod, toInt_mod_cong ha, toInt_mod_cong hb, ← Int.mul_emod] + int256 (evmMul a b) = int256 a * int256 b := evmMul_int256 ha hb h1 h2 end LnYul diff --git a/formal/ln/LnProof/LnProof/Foundation/WordDiv.lean b/formal/ln/LnProof/LnProof/Foundation/WordDiv.lean index e7325e5c8..e4bfbf44e 100644 --- a/formal/ln/LnProof/LnProof/Foundation/WordDiv.lean +++ b/formal/ln/LnProof/LnProof/Foundation/WordDiv.lean @@ -1,4 +1,5 @@ import LnProof.Foundation.Word +import Common.Word open FormalYul open FormalYul.Preservation @@ -25,95 +26,75 @@ theorem evmSar_sandwich_72 {w : Nat} (h : w < 2 ^ 256) : evmSar 72 w < 2 ^ 256 ∧ int256 (evmSar 72 w) * 4722366482869645213696 ≤ int256 w ∧ int256 w < int256 (evmSar 72 w) * 4722366482869645213696 + 4722366482869645213696 := by - unfold evmSar u256 int256 - simp only [word_mod_eq, ipow256, Nat.reducePow, Nat.reduceMod] - repeat' split - all_goals omega + obtain ⟨h1, h2, h3⟩ := Common.Word.evmSar_sandwich (s := 72) (by norm_num) h + norm_num at h2 h3 + exact ⟨h1, by linarith, by linarith⟩ theorem evmSar_sandwich_88 {w : Nat} (h : w < 2 ^ 256) : evmSar 88 w < 2 ^ 256 ∧ int256 (evmSar 88 w) * 309485009821345068724781056 ≤ int256 w ∧ int256 w < int256 (evmSar 88 w) * 309485009821345068724781056 + 309485009821345068724781056 := by - unfold evmSar u256 int256 - simp only [word_mod_eq, ipow256, Nat.reducePow, Nat.reduceMod] - repeat' split - all_goals omega + obtain ⟨h1, h2, h3⟩ := Common.Word.evmSar_sandwich (s := 88) (by norm_num) h + norm_num at h2 h3 + exact ⟨h1, by linarith, by linarith⟩ theorem evmSar_sandwich_90 {w : Nat} (h : w < 2 ^ 256) : evmSar 90 w < 2 ^ 256 ∧ int256 (evmSar 90 w) * 1237940039285380274899124224 ≤ int256 w ∧ int256 w < int256 (evmSar 90 w) * 1237940039285380274899124224 + 1237940039285380274899124224 := by - unfold evmSar u256 int256 - simp only [word_mod_eq, ipow256, Nat.reducePow, Nat.reduceMod] - repeat' split - all_goals omega + obtain ⟨h1, h2, h3⟩ := Common.Word.evmSar_sandwich (s := 90) (by norm_num) h + norm_num at h2 h3 + exact ⟨h1, by linarith, by linarith⟩ theorem evmSar_sandwich_95 {w : Nat} (h : w < 2 ^ 256) : evmSar 95 w < 2 ^ 256 ∧ int256 (evmSar 95 w) * 39614081257132168796771975168 ≤ int256 w ∧ int256 w < int256 (evmSar 95 w) * 39614081257132168796771975168 + 39614081257132168796771975168 := by - unfold evmSar u256 int256 - simp only [word_mod_eq, ipow256, Nat.reducePow, Nat.reduceMod] - repeat' split - all_goals omega + obtain ⟨h1, h2, h3⟩ := Common.Word.evmSar_sandwich (s := 95) (by norm_num) h + norm_num at h2 h3 + exact ⟨h1, by linarith, by linarith⟩ theorem evmSar_sandwich_87 {w : Nat} (h : w < 2 ^ 256) : evmSar 87 w < 2 ^ 256 ∧ int256 (evmSar 87 w) * 154742504910672534362390528 ≤ int256 w ∧ int256 w < int256 (evmSar 87 w) * 154742504910672534362390528 + 154742504910672534362390528 := by - unfold evmSar u256 int256 - simp only [word_mod_eq, ipow256, Nat.reducePow, Nat.reduceMod] - repeat' split - all_goals omega + obtain ⟨h1, h2, h3⟩ := Common.Word.evmSar_sandwich (s := 87) (by norm_num) h + norm_num at h2 h3 + exact ⟨h1, by linarith, by linarith⟩ theorem evmSar_sandwich_97 {w : Nat} (h : w < 2 ^ 256) : evmSar 97 w < 2 ^ 256 ∧ int256 (evmSar 97 w) * 158456325028528675187087900672 ≤ int256 w ∧ int256 w < int256 (evmSar 97 w) * 158456325028528675187087900672 + 158456325028528675187087900672 := by - unfold evmSar u256 int256 - simp only [word_mod_eq, ipow256, Nat.reducePow, Nat.reduceMod] - repeat' split - all_goals omega + obtain ⟨h1, h2, h3⟩ := Common.Word.evmSar_sandwich (s := 97) (by norm_num) h + norm_num at h2 h3 + exact ⟨h1, by linarith, by linarith⟩ theorem evmSar_sandwich_113 {w : Nat} (h : w < 2 ^ 256) : evmSar 113 w < 2 ^ 256 ∧ int256 (evmSar 113 w) * 10384593717069655257060992658440192 ≤ int256 w ∧ int256 w < int256 (evmSar 113 w) * 10384593717069655257060992658440192 + 10384593717069655257060992658440192 := by - unfold evmSar u256 int256 - simp only [word_mod_eq, ipow256, Nat.reducePow, Nat.reduceMod] - repeat' split - all_goals omega + obtain ⟨h1, h2, h3⟩ := Common.Word.evmSar_sandwich (s := 113) (by norm_num) h + norm_num at h2 h3 + exact ⟨h1, by linarith, by linarith⟩ end Sar /-! ## `evmShr` for nonnegative operands at literal shifts -/ -theorem evmShr_eq_div_84 {w : Nat} (h : w < 2 ^ 256) : evmShr 84 w = w / 2 ^ 84 := by - unfold evmShr u256 - simp only [word_mod_eq, Nat.reducePow, Nat.reduceMod] - split <;> omega +theorem evmShr_eq_div_84 {w : Nat} (h : w < 2 ^ 256) : evmShr 84 w = w / 2 ^ 84 := + Common.Word.evmShr_eq_div (by norm_num) h -theorem evmShr_eq_div_104 {w : Nat} (h : w < 2 ^ 256) : evmShr 104 w = w / 2 ^ 104 := by - unfold evmShr u256 - simp only [word_mod_eq, Nat.reducePow, Nat.reduceMod] - split <;> omega +theorem evmShr_eq_div_104 {w : Nat} (h : w < 2 ^ 256) : evmShr 104 w = w / 2 ^ 104 := + Common.Word.evmShr_eq_div (by norm_num) h -theorem evmShr_eq_div_160 {w : Nat} (h : w < 2 ^ 256) : evmShr 160 w = w / 2 ^ 160 := by - unfold evmShr u256 - simp only [word_mod_eq, Nat.reducePow, Nat.reduceMod] - split <;> omega +theorem evmShr_eq_div_160 {w : Nat} (h : w < 2 ^ 256) : evmShr 160 w = w / 2 ^ 160 := + Common.Word.evmShr_eq_div (by norm_num) h -theorem evmShr_lt {s : Nat} {w : Nat} (_h : w < 2 ^ 256) : evmShr s w < 2 ^ 256 := by - unfold evmShr u256 - simp only [word_mod_eq] - split - · exact Nat.lt_of_le_of_lt (Nat.div_le_self _ _) (by omega) - · omega +theorem evmShr_lt {s : Nat} {w : Nat} (_h : w < 2 ^ 256) : evmShr s w < 2 ^ 256 := + Common.Word.evmShr_lt s w -theorem evmShl_lt (s w : Nat) : evmShl s w < 2 ^ 256 := by - unfold evmShl u256 - simp only [word_mod_eq] - split <;> omega +theorem evmShl_lt (s w : Nat) : evmShl s w < 2 ^ 256 := Common.Word.evmShl_lt s w theorem evmSdiv_lt (a b : Nat) : evmSdiv a b < 2 ^ 256 := by unfold evmSdiv u256 @@ -126,15 +107,7 @@ theorem evmSdiv_lt (a b : Nat) : evmSdiv a b < 2 ^ 256 := by /-- Unwrapped left shift when the product genuinely fits (variable shift, used by the clz normalization). -/ theorem evmShl_eq {s : Nat} (hs : s < 256) {w : Nat} (h : w * 2 ^ s < 2 ^ 256) : - evmShl s w = w * 2 ^ s := by - unfold evmShl u256 - simp only [word_mod_eq] - have hs2 : s % 2 ^ 256 = s := Nat.mod_eq_of_lt (by omega) - have hpos : 0 < 2 ^ s := Nat.two_pow_pos s - have hw : w < 2 ^ 256 := by - have h1 : w * 1 ≤ w * 2 ^ s := Nat.mul_le_mul_left w hpos - omega - rw [hs2, if_pos hs, Nat.mod_eq_of_lt hw, Nat.mod_eq_of_lt h] + evmShl s w = w * 2 ^ s := Common.Word.evmShl_eq hs h /-- Signed left shift by 100 (the `z` numerator). -/ theorem evmShl_transport_100 {w : Nat} (hw : w < 2 ^ 256) @@ -267,15 +240,6 @@ theorem evmSdiv_neg_neg {a b : Nat} (ha : a < 2 ^ 256) (hb : b < 2 ^ 256) /-- Cross-multiplied monotonicity of Nat division. -/ theorem nat_div_cross_mono {a b c d : Nat} (hb : 0 < b) (hd : 0 < d) - (h : a * d ≤ c * b) : a / b ≤ c / d := by - rw [Nat.le_div_iff_mul_le hd] - have h1 : a / b * b ≤ a := Nat.div_mul_le_self a b - have h2 : a / b * b * d ≤ a * d := Nat.mul_le_mul_right d h1 - have h3 : a / b * b * d ≤ c * b := Nat.le_trans h2 h - have h4 : a / b * d * b ≤ c * b := by - have : a / b * b * d = a / b * d * b := by - rw [Nat.mul_assoc, Nat.mul_comm b d, ← Nat.mul_assoc] - omega - exact Nat.le_of_mul_le_mul_right h4 hb + (h : a * d ≤ c * b) : a / b ≤ c / d := Common.Word.nat_div_cross_mono hb hd h end LnYul diff --git a/formal/ln/LnProof/LnProof/Mono/Step.lean b/formal/ln/LnProof/LnProof/Mono/Step.lean index 2f555707f..53c64478c 100644 --- a/formal/ln/LnProof/LnProof/Mono/Step.lean +++ b/formal/ln/LnProof/LnProof/Mono/Step.lean @@ -1,4 +1,5 @@ import LnProof.Mono.Certs +import Common.Word open FormalYul open FormalYul.Preservation @@ -109,10 +110,7 @@ theorem uVal_step_nonpos (v : Int) (hv : v ≤ 0) /-! ## Product helpers -/ theorem toNat_mul_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) : - x.toNat * y.toNat = (x * y).toNat := by - obtain ⟨a, rfl⟩ := Int.eq_ofNat_of_zero_le hx - obtain ⟨b, rfl⟩ := Int.eq_ofNat_of_zero_le hy - rfl + x.toNat * y.toNat = (x * y).toNat := Common.Word.toNat_mul_of_nonneg hx hy theorem triple_mono {a1 b1 c1 a2 b2 c2 : Int} (ha : 0 ≤ a1) (hb : 0 ≤ b1) (hc : 0 ≤ c1) (h1 : a1 ≤ a2) (h2 : b1 ≤ b2) (h3 : c1 ≤ c2) : a1 * b1 * c1 ≤ a2 * b2 * c2 := by @@ -209,11 +207,8 @@ theorem g2_step {um1 : Int} (h0 : 0 ≤ um1) (h1 : um1 ≤ UcI - 1) {m : Int} theorem cross_to_div {n1 n2 W1 W2 : Int} (hn1 : 0 ≤ n1) (hn2 : 0 ≤ n2) (hW1 : 0 < W1) (hW2 : 0 < W2) (hcross : n1 * W2 ≤ n2 * W1) : - n1.toNat / W1.toNat ≤ n2.toNat / W2.toNat := by - refine nat_div_cross_mono (by omega) (by omega) ?_ - have e1 := toNat_mul_of_nonneg hn1 (by omega : (0:Int) ≤ W2) - have e2 := toNat_mul_of_nonneg hn2 (by omega : (0:Int) ≤ W1) - omega + n1.toNat / W1.toNat ≤ n2.toNat / W2.toNat := + Common.Word.cross_to_div hn1 hn2 hW1 hW2 hcross /-- `(P * w * W) * (E1 * E2) = (P * E1) * (W * E2) * w`. -/ theorem ident1 (P w W E1 E2 : Int) : diff --git a/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean b/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean index fad5b0eda..c6d5eb2f8 100644 --- a/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean +++ b/formal/ln/LnProof/LnProof/Seam/RuntimeModel.lean @@ -2,6 +2,7 @@ import LnProof.LnYulProof import FormalYul.Preservation import LnProof.Model.Body import LnProof.Foundation.Word +import Common.Word import LnProof.Foundation.WordDiv import LnProof.Mono.Top @@ -21,33 +22,10 @@ namespace LnYul open FormalYul open FormalYul.Preservation +open Common.Word set_option maxRecDepth 100000 -theorem u256_lt_word (x : Nat) : u256 x < 2 ^ 256 := by - unfold u256 WORD_MOD - exact Nat.mod_lt _ (Nat.two_pow_pos 256) - -theorem u256_idem (x : Nat) : u256 (u256 x) = u256 x := by - unfold u256 WORD_MOD - exact Nat.mod_mod_of_dvd x (dvd_refl _) - -/-- A positive signed input has its low 256 bits in `[1, 2^255)`. -/ -theorem u256_pos_bounds {x : Nat} (h : 0 < int256 (u256 x)) : - 1 ≤ u256 x ∧ u256 x < 2 ^ 255 := by - have hlt : u256 x < 2 ^ 256 := u256_lt_word x - unfold int256 at h - by_cases hb : u256 x < 2 ^ 255 - · simp only [hb, if_true] at h - have : 0 < u256 x := by exact_mod_cast h - exact ⟨this, hb⟩ - · exfalso - simp only [hb, if_false] at h - rw [intPow256] at h - have : (u256 x : Int) < 115792089237316195423570985008687907853269984665640564039457584007913129639936 := by - rw [← intPow256]; exact_mod_cast hlt - omega - /-- `sgt(x, 0)` evaluates to the word `1` for a positive signed input, which is exactly what the interpreter needs to skip the `if iszero(sgt(x, 0))` panic branch in `fun_lnWadToRay_65`. -/ @@ -100,173 +78,6 @@ theorem sgt_zero_nonpos {x : Nat} (hnonpos : int256 (u256 x) ≤ 0) : if_neg (by omega : ¬ ((0 : Nat) ≥ 2 ^ 255))] simp [EvmYul.UInt256.fromBool] -/-- `wordNat` of `UInt256.complement` is `evmNot` (the complement equals the -two's-complement bitwise-not at the `Nat` level). -/ -theorem wordNat_complement (a : EvmYul.UInt256) : - wordNat (EvmYul.UInt256.complement a) = evmNot (wordNat a) := by - have hav : a.toNat < 2 ^ 256 := by - simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size] - simp only [wordNat, EvmYul.UInt256.complement, EvmYul.UInt256.toNat, evmNot, u256, WORD_MOD, - Fin.sub_def, Fin.add_def, Fin.val_zero, Fin.val_one, EvmYul.UInt256.size] - omega - -/-- Arithmetic-shift-right bridge: `UInt256.sar` matches `evmSar`. Uses the -decomposition `sar = complement (complement b >>> a)` (for negative `b`) and -`b >>> a` (otherwise), composing `wordNat_complement` + `wordNat_shiftRight`. -/ -theorem wordNat_sar (a b : EvmYul.UInt256) : - wordNat (EvmYul.UInt256.sar a b) = evmSar (wordNat a) (wordNat b) := by - have hb : wordNat b < 2 ^ 256 := by - simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size, wordNat] - have ha : wordNat a < 2 ^ 256 := by - simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size, wordNat] - have huina : u256 (wordNat a) = wordNat a := by - unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt ha - have huinb : u256 (wordNat b) = wordNat b := by - unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt hb - have hbz : ¬ (b < (⟨0⟩ : EvmYul.UInt256)) := by - have hz : (⟨0⟩ : EvmYul.UInt256).toNat = 0 := rfl - show ¬ (b.toNat < (⟨0⟩ : EvmYul.UInt256).toNat) - rw [hz]; omega - have hsltz : EvmYul.UInt256.sltBool b ⟨0⟩ = true ↔ 2 ^ 255 ≤ wordNat b := by - unfold EvmYul.UInt256.sltBool - by_cases hb255 : 2 ^ 255 ≤ wordNat b <;> - simp [hbz, wordNat, show (⟨0⟩ : EvmYul.UInt256).toNat = 0 from rfl] - unfold EvmYul.UInt256.sar - by_cases hneg : EvmYul.UInt256.sltBool b ⟨0⟩ = true - · rw [if_pos hneg] - have hvneg : 2 ^ 255 ≤ wordNat b := hsltz.mp hneg - rw [show (EvmYul.UInt256.complement b) >>> a - = EvmYul.UInt256.shiftRight (EvmYul.UInt256.complement b) a from rfl, - wordNat_complement, wordNat_shiftRight, wordNat_complement] - simp only [evmSar, evmShr, evmNot] - rw [huina, huinb, if_pos hvneg] - have hnotv : u256 (WORD_MOD - 1 - wordNat b) = WORD_MOD - 1 - wordNat b := by - unfold u256 WORD_MOD; apply Nat.mod_eq_of_lt; unfold WORD_MOD at hb; omega - rw [hnotv] - by_cases hs : wordNat a < 256 - · rw [if_pos hs, if_neg (by omega : ¬ 256 ≤ wordNat a)] - have hdiv : u256 ((WORD_MOD - 1 - wordNat b) / 2 ^ wordNat a) - = (WORD_MOD - 1 - wordNat b) / 2 ^ wordNat a := by - unfold u256 WORD_MOD; apply Nat.mod_eq_of_lt - have hle : (2 ^ 256 - 1 - wordNat b) / 2 ^ wordNat a ≤ 2 ^ 256 - 1 - wordNat b := - Nat.div_le_self _ _ - unfold WORD_MOD at hb; omega - rw [hdiv] - · rw [if_neg hs, if_pos (by omega : 256 ≤ wordNat a)] - have : u256 0 = 0 := by unfold u256 WORD_MOD; simp - rw [this]; omega - · rw [if_neg hneg] - have hvpos : wordNat b < 2 ^ 255 := by - by_contra hc; push_neg at hc; exact hneg (hsltz.mpr hc) - rw [show b >>> a = EvmYul.UInt256.shiftRight b a from rfl, wordNat_shiftRight] - simp only [evmSar, evmShr] - rw [huina, huinb, if_neg (by omega : ¬ 2 ^ 255 ≤ wordNat b)] - split_ifs <;> omega - -/-- `UInt256.size = 2^256`, kept in `Nat.pow` form (never the 78-digit literal, -which would force kernel deep-recursion). -/ -theorem size_eq_pow : EvmYul.UInt256.size = 2 ^ 256 := rfl - -/-- `toNat` of the Fin negation `⟨x.val * (-1)⟩`. Routed through Fin -*subtraction* (`0 - x.val`, recursion-free like `complement`) rather than -Fin `Mul`/`Neg`, whose instances force kernel materialization of `2^256`. -/ -private theorem toNat_neg_one (x : EvmYul.UInt256) : - wordNat (⟨x.val * (-1)⟩ : EvmYul.UInt256) - = (EvmYul.UInt256.size - wordNat x) % EvmYul.UInt256.size := by - have hrw : (x.val * (-1)) = (0 - x.val) := by rw [mul_neg_one, zero_sub] - rw [show (⟨x.val * (-1)⟩ : EvmYul.UInt256) = ⟨0 - x.val⟩ from congrArg _ hrw] - simp only [wordNat, EvmYul.UInt256.toNat, Fin.sub_def, Fin.val_zero, EvmYul.UInt256.size] - omega - -/-- `toNat` of `UInt256.abs` (two's-complement absolute value). -/ -private theorem wordNat_abs (a : EvmYul.UInt256) : - wordNat (EvmYul.UInt256.abs a) - = if 2 ^ 255 ≤ wordNat a then (EvmYul.UInt256.size - wordNat a) % EvmYul.UInt256.size - else wordNat a := by - show (EvmYul.UInt256.abs a).toNat - = if 2 ^ 255 ≤ a.toNat then (EvmYul.UInt256.size - a.toNat) % EvmYul.UInt256.size - else a.toNat - unfold EvmYul.UInt256.abs - by_cases h : 2 ^ 255 ≤ a.toNat - · simp only [if_pos h]; exact toNat_neg_one a - · simp only [if_neg h] - -/-- Signed-division bridge: `UInt256.sdiv` matches `evmSdiv`. Four sign cases -(`2^255 ≤ a/b.toNat`), using `wordNat_abs`/`toNat_neg_one` for the abs and -negated arms; all powers kept as `2^n` to avoid kernel literal materialization. -/ -theorem wordNat_sdiv (a b : EvmYul.UInt256) : - wordNat (EvmYul.UInt256.sdiv a b) = evmSdiv (wordNat a) (wordNat b) := by - have ha : wordNat a < 2 ^ 256 := by - simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size, wordNat] - have hb : wordNat b < 2 ^ 256 := by - simp [EvmYul.UInt256.toNat, EvmYul.UInt256.size, wordNat] - have hua : u256 (wordNat a) = wordNat a := by unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt ha - have hub : u256 (wordNat b) = wordNat b := by unfold u256 WORD_MOD; exact Nat.mod_eq_of_lt hb - have hwm : WORD_MOD = 2 ^ 256 := word_mod_eq - have hsz : EvmYul.UInt256.size = 2 ^ 256 := size_eq_pow - simp only [evmSdiv, hua, hub, hwm] - unfold EvmYul.UInt256.sdiv - by_cases hna : 2 ^ 255 ≤ wordNat a <;> by_cases hnb : 2 ^ 255 ≤ wordNat b - · -- a < 0, b < 0 - have dna : decide (2 ^ 255 ≤ wordNat a) = true := decide_eq_true_eq.mpr hna - have dnb : decide (2 ^ 255 ≤ wordNat b) = true := decide_eq_true_eq.mpr hnb - have m1 : (2 ^ 256 - wordNat a) % 2 ^ 256 = 2 ^ 256 - wordNat a := Nat.mod_eq_of_lt (by omega) - have m2 : (2 ^ 256 - wordNat b) % 2 ^ 256 = 2 ^ 256 - wordNat b := Nat.mod_eq_of_lt (by omega) - rw [if_pos (show 2 ^ 255 ≤ a.toNat from hna), if_pos (show 2 ^ 255 ≤ b.toNat from hnb), - wordNat_div, wordNat_abs, wordNat_abs, hsz, if_pos hna, if_pos hnb] - simp only [dna, dnb, if_true] - simp only [evmDiv, u256, WORD_MOD, m1, m2] - have hq : (2 ^ 256 - wordNat a) / (2 ^ 256 - wordNat b) ≤ 2 ^ 256 - wordNat a := Nat.div_le_self _ _ - revert hq - generalize (2 ^ 256 - wordNat a) / (2 ^ 256 - wordNat b) = q - intro hq - split_ifs <;> omega - · -- a < 0, b ≥ 0 - have dna : decide (2 ^ 255 ≤ wordNat a) = true := decide_eq_true_eq.mpr hna - have dnb : decide (2 ^ 255 ≤ wordNat b) = false := decide_eq_false_iff_not.mpr hnb - have m1 : (2 ^ 256 - wordNat a) % 2 ^ 256 = 2 ^ 256 - wordNat a := Nat.mod_eq_of_lt (by omega) - have hmodb : wordNat b % 2 ^ 256 = wordNat b := Nat.mod_eq_of_lt hb - rw [if_pos (show 2 ^ 255 ≤ a.toNat from hna), if_neg (show ¬ 2 ^ 255 ≤ b.toNat from hnb), - toNat_neg_one, hsz, wordNat_div, wordNat_abs, hsz, if_pos hna] - simp only [dna, dnb, Bool.true_eq_false, Bool.false_eq_true, - if_true, if_false] - simp only [evmDiv, u256, WORD_MOD, m1, hmodb] - have hq : (2 ^ 256 - wordNat a) / wordNat b ≤ 2 ^ 256 - wordNat a := Nat.div_le_self _ _ - revert hq - generalize (2 ^ 256 - wordNat a) / wordNat b = q - intro hq - split_ifs <;> omega - · -- a ≥ 0, b < 0 - have dna : decide (2 ^ 255 ≤ wordNat a) = false := decide_eq_false_iff_not.mpr hna - have dnb : decide (2 ^ 255 ≤ wordNat b) = true := decide_eq_true_eq.mpr hnb - have m2 : (2 ^ 256 - wordNat b) % 2 ^ 256 = 2 ^ 256 - wordNat b := Nat.mod_eq_of_lt (by omega) - have hmoda : wordNat a % 2 ^ 256 = wordNat a := Nat.mod_eq_of_lt ha - rw [if_neg (show ¬ 2 ^ 255 ≤ a.toNat from hna), if_pos (show 2 ^ 255 ≤ b.toNat from hnb), - toNat_neg_one, hsz, wordNat_div, wordNat_abs, hsz, if_pos hnb] - simp only [dna, dnb, Bool.false_eq_true, - if_true, if_false] - simp only [evmDiv, u256, WORD_MOD, m2, hmoda] - have hq : wordNat a / (2 ^ 256 - wordNat b) ≤ wordNat a := Nat.div_le_self _ _ - revert hq - generalize wordNat a / (2 ^ 256 - wordNat b) = q - intro hq - split_ifs <;> omega - · -- a ≥ 0, b ≥ 0 - have dna : decide (2 ^ 255 ≤ wordNat a) = false := decide_eq_false_iff_not.mpr hna - have dnb : decide (2 ^ 255 ≤ wordNat b) = false := decide_eq_false_iff_not.mpr hnb - have hmoda : wordNat a % 2 ^ 256 = wordNat a := Nat.mod_eq_of_lt ha - have hmodb : wordNat b % 2 ^ 256 = wordNat b := Nat.mod_eq_of_lt hb - rw [if_neg (show ¬ 2 ^ 255 ≤ a.toNat from hna), if_neg (show ¬ 2 ^ 255 ≤ b.toNat from hnb), - wordNat_div] - simp only [dna, dnb, Bool.false_eq_true, - if_true, if_false] - simp only [evmDiv, u256, WORD_MOD, hmoda, hmodb] - have hq : wordNat a / wordNat b ≤ wordNat a := Nat.div_le_self _ _ - revert hq - generalize wordNat a / wordNat b = q - intro hq - split_ifs <;> omega - /-- The `zero_value_for_split_t_int256()` helper returns the word `0`. -/ private theorem call_zero_value_for_split_t_int256_direct (fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) From 9b7d589935c1c55e69b4b2254e40a5ccee8f349c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Fri, 3 Jul 2026 13:21:04 +0200 Subject: [PATCH 137/149] Carry ev at Q88 and Od at Q89; tighten the margin to the new envelope The closing bases take the two free bits the final coefficients' byte widths and the 256-bit t*Od product leave: Ev closes at Q88 (final stage shr 0x7e) and Od at Q89 (shr 0x80), with the t*Od sar landing at Q88 (0x81) to match Ev; both final coefficients are exact rescalings sharing the 16-byte literal 0x9c2948bcaca16a0dd2fe98bb4470c3c4, so the exact rational and its analytic certificates (the Taylor cut, the 32-piece granularity table, every generated cover) are unchanged. Halving the closing truncations halves the runtime-bridge budget: the Horner/div jitter certifies at 0.21706 (ev bracket width 142941343449089*2^480 at 2^527, od 269746241*2^480 at 2^508, alignment 2^637, tod grid 2^129), the never-over budget at B = 6013505372794194988/10^19, and the under deficit at 31/10 (link-1 5/2). The margin is the budget floor 0x2161b482a02 = floor(5^18*B) + 1 = 2293970250242; the k = 63 deficit envelope is 0.40131 < 1. The supported range stays pinned at k <= 63. Every documented property and test witness is unchanged; the supported-edge result is now certifiably the exact floor and its test asserts equality. Full lake build is green from the Theorems.lean axiom gates with certificate regeneration byte-identical; validated against a 60-digit reference on 8000+ adversarial points and the lnWadToRay round trip. Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 4 +- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 55 +-- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 30 +- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 335 ++++++++++-------- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 208 +++++------ .../ExpProof/ExpProof/Floor/RoundTrip.lean | 40 +-- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 12 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 12 +- formal/exp/ExpProof/ExpProof/Mono/Cross.lean | 30 +- .../exp/ExpProof/ExpProof/Mono/CrossCert.lean | 119 ++++--- .../exp/ExpProof/ExpProof/Mono/EvOdLip.lean | 28 +- formal/exp/ExpProof/ExpProof/Mono/Quot.lean | 111 +++--- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 31 +- formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 14 +- formal/exp/ExpProof/ExpProof/Mono/Stages.lean | 44 +-- .../exp/ExpProof/ExpProof/Mono/StepMono.lean | 18 +- formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 2 +- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 64 ++-- src/vendor/Exp.sol | 51 +-- test/0.8.34/Exp.t.sol | 8 +- 20 files changed, 632 insertions(+), 584 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index 88fff7e43..1bcc795da 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -30,7 +30,7 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : ∃ s : Nat, (s : Int) = 108 - int256 (kTree x) ∧ accumReal x = - ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - (3833775901375 : Real)) / + ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - (2293970250242 : Real)) / (2 ^ s : Real) := by obtain ⟨s, hseq, _, _, hsint⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 @@ -40,7 +40,7 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) rw [hseq] -- the integer shift argument has the closed value `WAD·r0 − MARGIN` have hwadc : (0x3782dace9d9 : Int) = 3814697265625 := by norm_num - have hmarc : (0x37c9ed9cabf : Int) = 3833775901375 := by norm_num + have hmarc : (0x2161b482a02 : Int) = 2293970250242 := by norm_num rw [hargeq, hwadc, hmarc] push_cast ring diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index e22d05dcf..4a91611f2 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -18,7 +18,7 @@ ingredients of that discharge: (degree 5, cleared scale `2^528`) and `odNumV (vTree x)` (degree 4, cleared scale `2^510`): the monic leading stage is an exact add, and the four lossy stages' floor losses telescope with shrinking amplification (each stage shift exceeds `120 = ⌈log₂ v⌉`), leaving widths - `283678831804417·2^480 ≈ 1.0079·2^528` and `1075052609·2^480 ≈ 1.0013·2^510`; + `142941343449089·2^480 ≈ 1.0157·2^527` and `269746241·2^480 ≈ 1.0049·2^508`; * the self-contained **below-clamp bound** — below the clamp boundary the target is under one output unit — directly from a `Real.exp` rational bound. -/ @@ -29,6 +29,7 @@ open FormalYul open FormalYul.Preservation set_option maxRecDepth 100000 +set_option exponentiation.threshold 2000 set_option maxHeartbeats 1000000 /-! ## The Horner accumulators bracket the exact polynomials @@ -167,8 +168,8 @@ theorem horner_stage_frac (c prev v cum sh p Wnum Eprev : Nat) /-! ## The even accumulator The monic leading stage `ev0 = A4 + v` is an exact add (width `1·2^0`); the four `mul/shr` stages -(shifts `0x95, 0x7b, 0x81, 0x7f`, cumulative `149, 272, 401, 528`) telescope the width to -`283678831804417·2^480 ≈ 1.0079·2^528`. -/ +(shifts `0x95, 0x7b, 0x81, 0x7e`, cumulative `149, 272, 401, 527`) telescope the width to +`142941343449089·2^480 ≈ 1.0157·2^527`. -/ /-- Exact integer even-Horner accumulator (degree-5 monic in `v`, cleared scale `2^528`). -/ def evNumV (v : Nat) : Nat := @@ -179,10 +180,10 @@ def evNumV (v : Nat) : Nat := 0x4e14a45e5650b506e97f4c5da23861e2 * 2^528 + e3 * v theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : - 2^528 * evTree x ≤ evNumV (vTree x) ∧ - evNumV (vTree x) < 2^528 * evTree x + 283678831804417 * 2^480 := by + 2^527 * evTree x ≤ evNumV (vTree x) ∧ + evNumV (vTree x) < 2^527 * evTree x + 142941343449089 * 2^480 := by have hev : evTree x = - evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul @@ -259,8 +260,8 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (P := 2^129) (V := 2^120) (sh := 0x81) he2lt hv (by norm_num) (by norm_num) (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 rw [pvd 129 120 129 120 (by norm_num)] at this; omega - -- stage 4: cum 401 -> 528, sh=127; p 360 -> 480; Wnum 2203855093761 -> 283678831804417 - have s4 := horner_stage_frac 0x4e14a45e5650b506e97f4c5da23861e2 e3 v 401 0x7f 360 2203855093761 + -- stage 4: cum 401 -> 527, sh=126; p 360 -> 480; Wnum 2203855093761 -> 142941343449089 + have s4 := horner_stage_frac 0x9c2948bcaca16a0dd2fe98bb4470c3c4 e3 v 401 0x7e 360 2203855093761 (0x93f11e650dd6c64b96ce79065cdf809e * 2^401 + (0x9064d9657e9a21fc16bb69331c5c3057 * 2^272 + (0x9a036222841f47c6ed6fc3f7602053 * 2^149 + @@ -271,14 +272,14 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (by calc e3 * v < 2^129 * 2^120 := Nat.mul_lt_mul'' he3lt hv _ < 2^256 := by norm_num) (by norm_num) (by norm_num) s3.1 s3.2 - rw [show (401:Nat)+0x7f-(360+120) = 48 from by norm_num, - show (2203855093761:Nat)+2^48 = 283678831804417 from by norm_num, - show (360:Nat)+120 = 480 from by norm_num, show (401:Nat)+0x7f = 528 from by norm_num] at s4 + rw [show (401:Nat)+0x7e-(360+120) = 47 from by norm_num, + show (2203855093761:Nat)+2^47 = 142941343449089 from by norm_num, + show (360:Nat)+120 = 480 from by norm_num, show (401:Nat)+0x7e = 527 from by norm_num] at s4 -- assemble: evTree x = e4 (the stage-4 value), evNumV v = the cumulative E4. rw [hev] - show 2^528 * evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul e3 v)) ≤ evNumV v ∧ - evNumV v < 2^528 * evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul e3 v)) + - 283678831804417 * 2^480 + show 2^527 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul e3 v)) ≤ evNumV v ∧ + evNumV v < 2^527 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul e3 v)) + + 142941343449089 * 2^480 unfold evNumV constructor · have := s4.1 @@ -294,8 +295,8 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : /-! ## The odd accumulator The odd accumulator starts at the exact leading constant `B4` (scale `0`) and runs four mul/shr -stages (shifts `0x7e, 0x84, 0x7a, 0x82`, cumulative `126, 258, 380, 510`), telescoping the width to -`1075052609·2^480 ≈ 1.0013·2^510`. -/ +stages (shifts `0x7e, 0x84, 0x7a, 0x80`, cumulative `126, 258, 380, 508`), telescoping the width to +`269746241·2^480 ≈ 1.0049·2^508`. -/ /-- Exact integer odd-Horner accumulator (degree-4 in `v`, cleared scale `2^510`). -/ def odNumV (v : Nat) : Nat := @@ -305,10 +306,10 @@ def odNumV (v : Nat) : Nat := 0x270a522f2b285a8374bfa62ed11c30f1 * 2^510 + o3 * v theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : - 2^510 * odTree x ≤ odNumV (vTree x) ∧ - odNumV (vTree x) < 2^510 * odTree x + 1075052609 * 2^480 := by + 2^508 * odTree x ≤ odNumV (vTree x) ∧ + odNumV (vTree x) < 2^508 * odTree x + 269746241 * 2^480 := by have hod : odTree x = - evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul @@ -372,8 +373,8 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (P := 2^121) (V := 2^120) (sh := 0x7a) ho2lt hv (by norm_num) (by norm_num) (by rw [pvd 121 120 122 119 (by norm_num)]; norm_num)).2 rw [pvd 121 120 122 119 (by norm_num)] at this; omega - -- stage 4: cum 380 -> 510, sh=130; p 360 -> 480; Wnum 1310785 -> 1075052609 - have s4 := horner_stage_frac 0x270a522f2b285a8374bfa62ed11c30f1 o3 v 380 0x82 360 1310785 + -- stage 4: cum 380 -> 508, sh=128; p 360 -> 480; Wnum 1310785 -> 269746241 + have s4 := horner_stage_frac 0x9c2948bcaca16a0dd2fe98bb4470c3c4 o3 v 380 0x80 360 1310785 (0xaf566247c05753b42892f77b67a6b7c6 * 2^380 + (0xad4506af99be27419341e1816ff351 * 2^258 + (0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) * v) * v) hv @@ -383,13 +384,13 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (by calc o3 * v < 2^129 * 2^120 := Nat.mul_lt_mul'' ho3lt hv _ < 2^256 := by norm_num) (by norm_num) (by norm_num) s3.1 s3.2 - rw [show (380:Nat)+0x82-(360+120) = 30 from by norm_num, - show (1310785:Nat)+2^30 = 1075052609 from by norm_num, - show (360:Nat)+120 = 480 from by norm_num, show (380:Nat)+0x82 = 510 from by norm_num] at s4 + rw [show (380:Nat)+0x80-(360+120) = 28 from by norm_num, + show (1310785:Nat)+2^28 = 269746241 from by norm_num, + show (360:Nat)+120 = 480 from by norm_num, show (380:Nat)+0x80 = 508 from by norm_num] at s4 rw [hod] - show 2^510 * evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul o3 v)) ≤ odNumV v ∧ - odNumV v < 2^510 * evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul o3 v)) + - 1075052609 * 2^480 + show 2^508 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul o3 v)) ≤ odNumV v ∧ + odNumV v < 2^508 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul o3 v)) + + 269746241 * 2^480 unfold odNumV constructor · have := s4.1; convert this using 2 diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index 8330b1787..249be87eb 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -11,8 +11,8 @@ below-clamp bound (`belowC_target_lt_one`) establish the never-over and deficit- about the real pre-floor accumulator unconditionally and axiom-clean, via the octave fold `E·2^s = WAD·2¹⁰⁸·exp(rt)` (`WAD = 5¹⁸`; `s = 108 − k`, the closing shift; `k ≤ 63` so `s ≥ 45`). -* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 10050013498897899168/10000000000000000000` and `5¹⁸·10050013498897899168/10000000000000000000 ≤ MARGIN`; -* `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 67/10` and `(67/10)·5¹⁸ + MARGIN < 2⁴⁵ ≤ 2^s`. +* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 6013505372794194988/10000000000000000000` and `5¹⁸·6013505372794194988/10000000000000000000 ≤ MARGIN`; +* `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 31/10` and `(31/10)·5¹⁸ + MARGIN < 2⁴⁵ ≤ 2^s`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. -/ @@ -38,12 +38,12 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt -- WAD·r0 − MARGIN ≤ 5^18·2^126·Ert = E·2^s - have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375 ≤ + have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 10050013498897899168 / 10000000000000000000 := hover + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 6013505372794194988 / 10000000000000000000 := hover have hscaled : (3814697265625 : Real) * (int256 (r0Tree x) : Real) ≤ - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 10050013498897899168 / 10000000000000000000) := + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 6013505372794194988 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] @@ -53,9 +53,9 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 norm_num] ring rw [hconst] - -- 5^18·B = 3833775901374.02… ≤ 3833775901375 = MARGIN - have hBM : (3814697265625 : Real) * (10050013498897899168 / 10000000000000000000) ≤ - 3833775901375 := by norm_num + -- 5^18·B = 3833775901374.02… ≤ 2293970250242 = MARGIN + have hBM : (3814697265625 : Real) * (6013505372794194988 / 10000000000000000000) ≤ + 2293970250242 := by norm_num linarith [hscaled, hBM] rw [hAeq, div_le_iff₀ hps]; linarith [hbound] @@ -71,9 +71,9 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 set Ert := Real.exp (reducedArg x) with hErt -- E·2^s = 5^18·2^126·Ert < WAD·r0 − MARGIN + 2^s have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375) + (2 ^ s : Real) := by + ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242) + (2 ^ s : Real) := by rw [hfold] - have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 67 / 10 := hunder + have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 31 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num have hs45 : (45 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] have hs45n : 45 ≤ s := by exact_mod_cast hs45 @@ -86,17 +86,17 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 ring rw [hconst] have hscaled : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 67 / 10) := + (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 31 / 10) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - -- (67/10)·5^18 + MARGIN < 2^45 - have hbudget : (3814697265625 : Real) * (67 / 10) + 3833775901375 < (2 ^ 45 : Real) := by + -- (31/10)·5^18 + MARGIN < 2^45 + have hbudget : (3814697265625 : Real) * (31 / 10) + 2293970250242 < (2 ^ 45 : Real) := by norm_num linarith [hscaled, hbudget, hpow] -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s rw [hAeq] - have hdiv : ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375) / + have hdiv : ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242) / (2 ^ s : Real) + 1 = - (((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375) + (2 ^ s : Real)) / + (((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp rw [hdiv, lt_div_iff₀ hps]; linarith [hbound] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 6b3763b5f..82afd0b6b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -15,7 +15,7 @@ This module bounds the Q126 quotient `r0Tree x` above by `2¹²⁶·exp(rt)` plu 1. **`r0` vs `ê(v)`** — Horner stage truncation and the closing `div` floor only: the runtime accumulators bracket the exact integer polynomials (`evTree_bracket`/`odTree_bracket`), and the shared even truncation cancels through the floor, leaving the jitter - `≤ 6207065162659510332/10¹⁹`; + `≤ 2170557036555806152/10¹⁹`; 2. **`ê(v)` vs `ê(t²)`** — the argument-granularity link (`Floor.GranV`): one `v`-grid grain, `≤ 3290521163436398582/10¹⁹` on this half (the 32-piece certified envelope); 3. **`ê(t²)` vs `exp(t/2¹²⁸)`** — the `2⁻¹³¹`-nudged Taylor cut (`Floor.CapsV`), the `Mp` factor @@ -23,7 +23,7 @@ This module bounds the Q126 quotient `r0Tree x` above by `2¹²⁶·exp(rt)` plu 4. **`exp(t/2¹²⁸)` vs `exp(rt)`** — the reduced-argument gap (`Floor.Reduce`), `≤ 110485434560398051/10¹⁹`. -The total is the budget `B = 10050013498897899168/10¹⁹`; `MARGIN = ⌊5¹⁸·B⌋ + 1`. On the `t ≤ 0` +The total is the budget `B = 6013505372794194988/10¹⁹`; `MARGIN = ⌊5¹⁸·B⌋ + 1`. On the `t ≤ 0` half link 2 is free (the grain moves `ê` the other way) and links 3–4 shrink (`ê ≤ 1`), so the same `B` covers both halves. -/ @@ -66,9 +66,9 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) obtain ⟨_, hevhi⟩ := evTree_facts (vTree_eq hx hC hC0).2 obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 rw [hnumi] - have : (evTree x : Int) < 2 ^ 127 := by exact_mod_cast hevhi - have ht125 : int256 (todTree x) < 2 ^ 125 := htod_hi - nlinarith [this, ht125] + have : (evTree x : Int) < 3 * 2 ^ 126 := by exact_mod_cast hevhi + have ht126 : int256 (todTree x) < 2 ^ 126 := htod_hi + nlinarith [this, ht126] have hshl : int256 (evmShl 0x7e num) = 2 ^ 0x7e * int256 num := shl126_transport hnumw (by rw [hnumi]; omega) hnumlt128 -- r0 = div (shl 126 num) den, with both operands positive @@ -122,16 +122,53 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) have hInt : (M : Int) < ((q : Int) + 1) * (den : Int) := by exact_mod_cast h rw [heM] at hInt; linarith [hInt] -/-- `den_rt = ev − tod ≥ 0.72·2¹²⁶` on the region (the even accumulator dominates `|tod|`). -/ -theorem den_ge_072 {x : Nat} (hx : x < 2 ^ 256) +/-- The `t·Od` shift stays within `2¹²⁵` on the region: the cert-domain `|t| ≤ H128` against the +odd accumulator cap `Od < 5·2¹²⁵`. -/ +theorem todTree_small {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (61251667532612381706986956632087880162 : Int) ≤ + -(2 ^ 125 : Int) ≤ int256 (todTree x) ∧ int256 (todTree x) < 2 ^ 125 := by + obtain ⟨htlo, hthi⟩ := tTree_in_cert_domain hx hC hC0 + obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 + have hodlt : odTree x < 5 * 2 ^ 125 := odTree_lt hvlt + obtain ⟨_, _, hgrid_lo, hgrid_hi⟩ := todTree_bound hx hC hC0 + have hod_nn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ + have hod_ub : (odTree x : Int) < 5 * 2 ^ 125 := by exact_mod_cast hodlt + have hprod_hi : int256 (tTree x) * (odTree x : Int) ≤ + 117932881612756647068972071382077242199 * (5 * 2 ^ 125) := by + have h1 : int256 (tTree x) * (odTree x : Int) ≤ + 117932881612756647068972071382077242199 * (odTree x : Int) := + mul_le_mul_of_nonneg_right hthi hod_nn + have h2 : (117932881612756647068972071382077242199 : Int) * (odTree x : Int) ≤ + 117932881612756647068972071382077242199 * (5 * 2 ^ 125) := + mul_le_mul_of_nonneg_left (le_of_lt hod_ub) (by norm_num) + linarith + have hprod_lo : -(117932881612756647068972071382077242199 * (5 * 2 ^ 125) : Int) ≤ + int256 (tTree x) * (odTree x : Int) := by + have h1 : -(117932881612756647068972071382077242199 : Int) * (odTree x : Int) ≤ + int256 (tTree x) * (odTree x : Int) := + mul_le_mul_of_nonneg_right htlo hod_nn + have h2 : -(117932881612756647068972071382077242199 * (5 * 2 ^ 125) : Int) ≤ + -(117932881612756647068972071382077242199 : Int) * (odTree x : Int) := by + have := mul_le_mul_of_nonneg_left (le_of_lt hod_ub) + (by norm_num : (0:Int) ≤ 117932881612756647068972071382077242199) + linarith + linarith + have hHcap : (117932881612756647068972071382077242199 : Int) * (5 * 2 ^ 125) < + 2 ^ 125 * 2 ^ 129 := by norm_num + constructor + · nlinarith [hgrid_hi, hprod_lo, hHcap] + · nlinarith [hgrid_lo, hprod_hi, hHcap] + +/-- `den_rt = ev − tod ≥ 1.94·2¹²⁶` on the region (the even accumulator dominates `|tod|`). -/ +theorem den_ge_194 {x : Nat} (hx : x < 2 ^ 256) + (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : + (165038630930342071346895739193146786756 : Int) ≤ (evTree x : Int) - int256 (todTree x) := by obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 - have hev : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + obtain ⟨_, htod_hi⟩ := todTree_small hx hC hC0 + have hev : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo have ht125 : int256 (todTree x) < 2 ^ 125 := htod_hi - rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 from by norm_num] at hev + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 from by norm_num] at hev rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 omega @@ -144,8 +181,8 @@ theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - have hden072 : (61251667532612381706986956632087880162 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hden072 : (165038630930342071346895739193146786756 : Int) ≤ ev - tod := by + have := den_ge_194 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 have htodnp : tod ≤ 0 := by obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 @@ -161,17 +198,17 @@ theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) /-! ## The runtime brackets lifted to the `2^725` alignment `NUMv/DENv = Ev·2^110 ± t·Od` (`Floor.GranV`). The Horner-truncation brackets -(`evTree_bracket`/`odTree_bracket`, widths `Wev = 283678831804417·2^480 ≈ 1.0079·2^528` and -`Wod = 1075052609·2^480 ≈ 1.0013·2^510`) and the `tod` floor (`todTree_bound`) tie them to the -runtime `ev`/`tod` at the common scale `2^638`. -/ +(`evTree_bracket`/`odTree_bracket`, widths `Wev = 142941343449089·2^480 ≈ 1.0079·2^527` and +`Wod = 269746241·2^480 ≈ 1.0013·2^508`) and the `tod` floor (`todTree_bound`) tie them to the +runtime `ev`/`tod` at the common scale `2^637`. -/ /-- The `Int`-cast Horner brackets and `tod` floor collected. -/ theorem bridge_facts {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 2 ^ 528 * (evTree x : Int) ≤ (evNumV (vTree x) : Int) ∧ - (evNumV (vTree x) : Int) < 2 ^ 528 * (evTree x : Int) + 283678831804417 * 2 ^ 480 ∧ - 2 ^ 510 * (odTree x : Int) ≤ (odNumV (vTree x) : Int) ∧ - (odNumV (vTree x) : Int) < 2 ^ 510 * (odTree x : Int) + 1075052609 * 2 ^ 480 := by + 2 ^ 527 * (evTree x : Int) ≤ (evNumV (vTree x) : Int) ∧ + (evNumV (vTree x) : Int) < 2 ^ 527 * (evTree x : Int) + 142941343449089 * 2 ^ 480 ∧ + 2 ^ 508 * (odTree x : Int) ≤ (odNumV (vTree x) : Int) ∧ + (odNumV (vTree x) : Int) < 2 ^ 508 * (odTree x : Int) + 269746241 * 2 ^ 480 := by obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 obtain ⟨hev_lo, hev_hi⟩ := evTree_bracket hvlt obtain ⟨hod_lo, hod_hi⟩ := odTree_bracket hvlt @@ -181,14 +218,14 @@ theorem bridge_facts {x : Nat} (hx : x < 2 ^ 256) · exact_mod_cast hod_lo · exact_mod_cast hod_hi -/-- The `t·Od` product brackets (nonnegative half): `2⁶³⁸·tod ≤ t·Od` and -`t·Od ≤ 2⁶³⁸·tod + 2⁶³⁸ + Wod·2⁴⁸⁰·t`. -/ +/-- The `t·Od` product brackets (nonnegative half): `2⁶³⁷·tod ≤ t·Od` and +`t·Od ≤ 2⁶³⁷·tod + 2⁶³⁷ + Wod·2⁴⁸⁰·t`. -/ theorem tOd_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - 2 ^ 638 * int256 (todTree x) ≤ int256 (tTree x) * (odNumV (vTree x) : Int) ∧ + 2 ^ 637 * int256 (todTree x) ≤ int256 (tTree x) * (odNumV (vTree x) : Int) ∧ int256 (tTree x) * (odNumV (vTree x) : Int) ≤ - 2 ^ 638 * int256 (todTree x) + 2 ^ 638 + 1075052609 * 2 ^ 480 * int256 (tTree x) := by + 2 ^ 637 * int256 (todTree x) + 2 ^ 637 + 269746241 * 2 ^ 480 * int256 (tTree x) := by obtain ⟨_, _, hOp_lo, hOp_hi⟩ := bridge_facts hx hC hC0 obtain ⟨_, _, htod_lo, htod_hi⟩ := todTree_bound hx hC hC0 set t := int256 (tTree x) with htdef @@ -196,25 +233,25 @@ theorem tOd_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) set tod := int256 (todTree x) with htoddef set Op := (odNumV (vTree x) : Int) with hOpdef constructor - · -- t·Op ≥ t·(2^510·od) = 2^510·(t·od) ≥ 2^510·(2^128·tod) = 2^638·tod - have h1 : t * (2 ^ 510 * od) ≤ t * Op := mul_le_mul_of_nonneg_left hOp_lo htnn - have h2 : (2:Int) ^ 510 * (2 ^ 128 * tod) ≤ 2 ^ 510 * (t * od) := + · -- t·Op ≥ t·(2^508·od) = 2^508·(t·od) ≥ 2^508·(2^129·tod) = 2^637·tod + have h1 : t * (2 ^ 508 * od) ≤ t * Op := mul_le_mul_of_nonneg_left hOp_lo htnn + have h2 : (2:Int) ^ 508 * (2 ^ 129 * tod) ≤ 2 ^ 508 * (t * od) := mul_le_mul_of_nonneg_left htod_lo (by positivity) nlinarith [h1, h2] - · -- t·Op ≤ t·(2^510·od + Wod·2^480) ≤ 2^510·(2^128·tod + 2^128) + Wod·2^480·t - have h1 : t * Op ≤ t * (2 ^ 510 * od + 1075052609 * 2 ^ 480) := + · -- t·Op ≤ t·(2^508·od + Wod·2^480) ≤ 2^508·(2^129·tod + 2^129) + Wod·2^480·t + have h1 : t * Op ≤ t * (2 ^ 508 * od + 269746241 * 2 ^ 480) := mul_le_mul_of_nonneg_left (le_of_lt hOp_hi) htnn - have h2 : (2:Int) ^ 510 * (t * od) ≤ 2 ^ 510 * (2 ^ 128 * tod + 2 ^ 128) := + have h2 : (2:Int) ^ 508 * (t * od) ≤ 2 ^ 508 * (2 ^ 129 * tod + 2 ^ 129) := mul_le_mul_of_nonneg_left (le_of_lt htod_hi) (by positivity) nlinarith [h1, h2] -/-- The `t·Od` product brackets (nonpositive half): `t·Od ≤ 2⁶³⁸·tod + 2⁶³⁸` and -`2⁶³⁸·tod − Wod·2⁴⁸⁰·(−t) ≤ t·Od`. -/ +/-- The `t·Od` product brackets (nonpositive half): `t·Od ≤ 2⁶³⁷·tod + 2⁶³⁷` and +`2⁶³⁷·tod − Wod·2⁴⁸⁰·(−t) ≤ t·Od`. -/ theorem tOd_bracket_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - int256 (tTree x) * (odNumV (vTree x) : Int) ≤ 2 ^ 638 * int256 (todTree x) + 2 ^ 638 ∧ - 2 ^ 638 * int256 (todTree x) - 1075052609 * 2 ^ 480 * (-(int256 (tTree x))) ≤ + int256 (tTree x) * (odNumV (vTree x) : Int) ≤ 2 ^ 637 * int256 (todTree x) + 2 ^ 637 ∧ + 2 ^ 637 * int256 (todTree x) - 269746241 * 2 ^ 480 * (-(int256 (tTree x))) ≤ int256 (tTree x) * (odNumV (vTree x) : Int) := by obtain ⟨_, _, hOp_lo, hOp_hi⟩ := bridge_facts hx hC hC0 obtain ⟨_, _, htod_lo, htod_hi⟩ := todTree_bound hx hC hC0 @@ -223,15 +260,15 @@ theorem tOd_bracket_neg {x : Nat} (hx : x < 2 ^ 256) set tod := int256 (todTree x) with htoddef set Op := (odNumV (vTree x) : Int) with hOpdef constructor - · -- t·Op ≤ t·(2^510·od) = 2^510·(t·od) ≤ 2^510·(2^128·tod + 2^128) - have h1 : t * Op ≤ t * (2 ^ 510 * od) := mul_le_mul_of_nonpos_left hOp_lo htneg - have h2 : (2:Int) ^ 510 * (t * od) ≤ 2 ^ 510 * (2 ^ 128 * tod + 2 ^ 128) := + · -- t·Op ≤ t·(2^508·od) = 2^508·(t·od) ≤ 2^508·(2^129·tod + 2^129) + have h1 : t * Op ≤ t * (2 ^ 508 * od) := mul_le_mul_of_nonpos_left hOp_lo htneg + have h2 : (2:Int) ^ 508 * (t * od) ≤ 2 ^ 508 * (2 ^ 129 * tod + 2 ^ 129) := mul_le_mul_of_nonneg_left (le_of_lt htod_hi) (by positivity) nlinarith [h1, h2] - · -- t·Op ≥ t·(2^510·od + Wod·2^480) = 2^510·(t·od) + Wod·2^480·t ≥ 2^638·tod − Wod·2^480·(−t) - have h1 : t * (2 ^ 510 * od + 1075052609 * 2 ^ 480) ≤ t * Op := + · -- t·Op ≥ t·(2^508·od + Wod·2^480) = 2^508·(t·od) + Wod·2^480·t ≥ 2^637·tod − Wod·2^480·(−t) + have h1 : t * (2 ^ 508 * od + 269746241 * 2 ^ 480) ≤ t * Op := mul_le_mul_of_nonpos_left (le_of_lt hOp_hi) htneg - have h2 : (2:Int) ^ 510 * (2 ^ 128 * tod) ≤ 2 ^ 510 * (t * od) := + have h2 : (2:Int) ^ 508 * (2 ^ 129 * tod) ≤ 2 ^ 508 * (t * od) := mul_le_mul_of_nonneg_left htod_lo (by positivity) nlinarith [h1, h2] @@ -244,7 +281,7 @@ theorem link1_over_tight {x : Nat} (hx : x < 2 ^ 256) (htnn : 0 ≤ int256 (tTree x)) (hr0ge : (2:Int) ^ 126 ≤ int256 (r0Tree x)) : int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) ≤ - 283678831804417 * 2 ^ 590 * (int256 (r0Tree x) - 2 ^ 126) := by + 142941343449089 * 2 ^ 590 * (int256 (r0Tree x) - 2 ^ 126) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn @@ -257,17 +294,17 @@ theorem link1_over_tight {x : Nat} (hx : x < 2 ^ 256) set Op := (odNumV (vTree x) : Int) with hOpdef have hr0m : (0:Int) ≤ r0 - 2 ^ 126 := by linarith [hr0ge] have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by linarith [hr0ge] - -- Ep·2^110·(r0−2^126) ≤ (2^638·ev + Wev·2^590)·(r0−2^126) + -- Ep·2^110·(r0−2^126) ≤ (2^637·ev + Wev·2^590)·(r0−2^126) have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ - (2 ^ 638 * ev + 283678831804417 * 2 ^ 590) * (r0 - 2 ^ 126) := by + (2 ^ 637 * ev + 142941343449089 * 2 ^ 590) * (r0 - 2 ^ 126) := by apply mul_le_mul_of_nonneg_right _ hr0m nlinarith [hEp_hi] - -- −(t·Op)·(r0+2^126) ≤ −(2^638·tod)·(r0+2^126) - have hterm2 : 2 ^ 638 * tod * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := + -- −(t·Op)·(r0+2^126) ≤ −(2^637·tod)·(r0+2^126) + have hterm2 : 2 ^ 637 * tod * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := mul_le_mul_of_nonneg_right (by linarith [htOp_lo]) hr0p - -- floor: r0·den − 2^126·num ≤ 0, scaled by 2^638 + -- floor: r0·den − 2^126·num ≤ 0, scaled by 2^637 have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 638 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] @@ -293,14 +330,14 @@ theorem link1_over_small {x : Nat} (hx : x < 2 ^ 256) linarith [hr0lo] have hr0m : r0 - 2 ^ 126 ≤ 0 := by linarith [hr0le] have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by positivity - -- Ep·2^110·(r0−2^126) ≤ 2^638·ev·(r0−2^126) (Ep·2^110 ≥ 2^638·ev, factor ≤ 0) - have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ 2 ^ 638 * ev * (r0 - 2 ^ 126) := by + -- Ep·2^110·(r0−2^126) ≤ 2^637·ev·(r0−2^126) (Ep·2^110 ≥ 2^637·ev, factor ≤ 0) + have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ 2 ^ 637 * ev * (r0 - 2 ^ 126) := by apply mul_le_mul_of_nonpos_right _ hr0m nlinarith [hEp_lo] - have hterm2 : 2 ^ 638 * tod * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := + have hterm2 : 2 ^ 637 * tod * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := mul_le_mul_of_nonneg_right (by linarith [htOp_lo]) hr0p have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 638 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] @@ -311,7 +348,7 @@ theorem link1_over_neg {x : Nat} (hx : x < 2 ^ 256) (htneg : int256 (tTree x) ≤ 0) : int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) ≤ - 1075052609 * 2 ^ 480 * (-(int256 (tTree x))) * (int256 (r0Tree x) + 2 ^ 126) := by + 269746241 * 2 ^ 480 * (-(int256 (tTree x))) * (int256 (r0Tree x) + 2 ^ 126) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨_, htOp_lo⟩ := tOd_bracket_neg hx hC hC0 htneg @@ -329,29 +366,29 @@ theorem link1_over_neg {x : Nat} (hx : x < 2 ^ 256) linarith [hr0lo] have hr0m : r0 - 2 ^ 126 ≤ 0 := by linarith [hr0le] have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by positivity - have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ 2 ^ 638 * ev * (r0 - 2 ^ 126) := by + have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ 2 ^ 637 * ev * (r0 - 2 ^ 126) := by apply mul_le_mul_of_nonpos_right _ hr0m nlinarith [hEp_lo] - -- −(t·Op)·(r0+2^126) ≤ (−2^638·tod + Wod·2^480·(−t))·(r0+2^126) - have hterm2 : (2 ^ 638 * tod - 1075052609 * 2 ^ 480 * (-t)) * (r0 + 2 ^ 126) ≤ + -- −(t·Op)·(r0+2^126) ≤ (−2^637·tod + Wod·2^480·(−t))·(r0+2^126) + have hterm2 : (2 ^ 637 * tod - 269746241 * 2 ^ 480 * (-t)) * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := mul_le_mul_of_nonneg_right htOp_lo hr0p have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 638 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] /-! ## Denominator bounds for the grid rational in runtime terms -/ /-- On the nonneg half `DENv` brackets the runtime denominator: -`2⁶³⁸·(den − 2) ≤ DENv ≤ 2⁶³⁸·den + Wev·2⁵⁹⁰` (`den = ev − tod`). -/ +`2⁶³⁷·(den − 2) ≤ DENv ≤ 2⁶³⁷·den + Wev·2⁵⁹⁰` (`den = ev − tod`). -/ theorem DENv_runtime_bracket {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 638 ≤ + 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 637 ≤ DENv (vTree x) (int256 (tTree x)) ∧ DENv (vTree x) (int256 (tTree x)) ≤ - 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) + 283678831804417 * 2 ^ 590 := by + 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + 142941343449089 * 2 ^ 590 := by obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_lo, htOp_hi⟩ := tOd_bracket_nonneg hx hC hC0 htnn obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 @@ -362,24 +399,24 @@ theorem DENv_runtime_bracket {x : Nat} (hx : x < 2 ^ 256) set Ep := (evNumV (vTree x) : Int) with hEpdef set Op := (odNumV (vTree x) : Int) with hOpdef constructor - · -- lower: Ep·2^110 ≥ 2^638·ev; t·Op ≤ 2^638·tod + 2^638 + Wod·2^480·t, t ≤ H128; - -- Wod·2^480·H128 + 2^638 ≤ 2·2^638 - have h1 : 2 ^ 638 * ev ≤ Ep * 2 ^ 110 := by nlinarith [hEp_lo] - have h2 : 1075052609 * 2 ^ 480 * t ≤ - 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199 := + · -- lower: Ep·2^110 ≥ 2^637·ev; t·Op ≤ 2^637·tod + 2^637 + Wod·2^480·t, t ≤ H128; + -- Wod·2^480·H128 + 2^637 ≤ 2·2^637 + have h1 : 2 ^ 637 * ev ≤ Ep * 2 ^ 110 := by nlinarith [hEp_lo] + have h2 : 269746241 * 2 ^ 480 * t ≤ + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199 := mul_le_mul_of_nonneg_left hthi (by positivity) - have h3 : (1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199 : Int) + 2 ^ 638 ≤ - 2 * 2 ^ 638 := by norm_num + have h3 : (269746241 * 2 ^ 480 * 117932881612756647068972071382077242199 : Int) + 2 ^ 637 ≤ + 2 * 2 ^ 637 := by norm_num linarith [h1, htOp_hi, h2, h3] - · -- upper: Ep·2^110 ≤ 2^638·ev + Wev·2^590; t·Op ≥ 2^638·tod - have h1 : Ep * 2 ^ 110 ≤ 2 ^ 638 * ev + 283678831804417 * 2 ^ 590 := by nlinarith [hEp_hi] + · -- upper: Ep·2^110 ≤ 2^637·ev + Wev·2^590; t·Op ≥ 2^637·tod + have h1 : Ep * 2 ^ 110 ≤ 2 ^ 637 * ev + 142941343449089 * 2 ^ 590 := by nlinarith [hEp_hi] linarith [h1, htOp_lo] -/-- On the nonpositive half `DENv` dominates the scaled even accumulator: `2⁶³⁸·ev ≤ DENv`. -/ +/-- On the nonpositive half `DENv` dominates the scaled even accumulator: `2⁶³⁷·ev ≤ DENv`. -/ theorem DENv_ge_ev_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - 2 ^ 638 * (evTree x : Int) ≤ DENv (vTree x) (int256 (tTree x)) := by + 2 ^ 637 * (evTree x : Int) ≤ DENv (vTree x) (int256 (tTree x)) := by obtain ⟨hEp_lo, _, _, hOp_hi⟩ := bridge_facts hx hC hC0 unfold DENv have hOp_nn : (0:Int) ≤ (odNumV (vTree x) : Int) := Int.natCast_nonneg _ @@ -387,11 +424,11 @@ theorem DENv_ge_ev_neg {x : Nat} (hx : x < 2 ^ 256) mul_nonpos_of_nonpos_of_nonneg htneg hOp_nn nlinarith [hEp_lo, htOp] -/-- On the nonneg half `NUMv` dominates the scaled runtime numerator: `2⁶³⁸·num ≤ NUMv`. -/ +/-- On the nonneg half `NUMv` dominates the scaled runtime numerator: `2⁶³⁷·num ≤ NUMv`. -/ theorem NUMv_ge_num {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - 2 ^ 638 * ((evTree x : Int) + int256 (todTree x)) ≤ NUMv (vTree x) (int256 (tTree x)) := by + 2 ^ 637 * ((evTree x : Int) + int256 (todTree x)) ≤ NUMv (vTree x) (int256 (tTree x)) := by obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn unfold NUMv @@ -704,24 +741,24 @@ theorem num_ceiling {x : Nat} (hx : x < 2 ^ 256) have hR2 : (10000 : Real) * (NUMv v t : Real) ≤ 14145 * (DENv v t : Real) := by nlinarith [hR] exact_mod_cast hR2 - -- pull back through the brackets: 2^638·num ≤ NUMv; DENv ≤ 2^638·den + Wev·2^590 + -- pull back through the brackets: 2^637·num ≤ NUMv; DENv ≤ 2^637·den + Wev·2^590 have hNUM_ge := NUMv_ge_num hx hC hC0 htnn obtain ⟨_, hDEN_le⟩ := DENv_runtime_bracket hx hC hC0 htnn set num := (evTree x : Int) + int256 (todTree x) with hnumdef set den := (evTree x : Int) - int256 (todTree x) with hdendef - -- 10000·2^638·num ≤ 14145·(2^638·den + Wev·2^590) ≤ 2^638·(14145·den + 28290) - have hchain : 10000 * (2 ^ 638 * num) ≤ 2 ^ 638 * (14145 * den + 28290) := by - have h1 : 10000 * (2 ^ 638 * num) ≤ 10000 * NUMv v t := + -- 10000·2^637·num ≤ 14145·(2^637·den + Wev·2^590) ≤ 2^637·(14145·den + 28290) + have hchain : 10000 * (2 ^ 637 * num) ≤ 2 ^ 637 * (14145 * den + 28290) := by + have h1 : 10000 * (2 ^ 637 * num) ≤ 10000 * NUMv v t := mul_le_mul_of_nonneg_left hNUM_ge (by norm_num) - have h2 : 14145 * DENv v t ≤ 14145 * (2 ^ 638 * den + 283678831804417 * 2 ^ 590) := + have h2 : 14145 * DENv v t ≤ 14145 * (2 ^ 637 * den + 142941343449089 * 2 ^ 590) := mul_le_mul_of_nonneg_left hDEN_le (by norm_num) - have h3 : (14145 : Int) * (2 ^ 638 * den + 283678831804417 * 2 ^ 590) ≤ - 2 ^ 638 * (14145 * den + 28290) := by - have hW : (14145 : Int) * (283678831804417 * 2 ^ 590) ≤ 28290 * 2 ^ 638 := by norm_num + have h3 : (14145 : Int) * (2 ^ 637 * den + 142941343449089 * 2 ^ 590) ≤ + 2 ^ 637 * (14145 * den + 28290) := by + have hW : (14145 : Int) * (142941343449089 * 2 ^ 590) ≤ 28290 * 2 ^ 637 := by norm_num nlinarith [hW] linarith [h1, hNUM_le, h2, h3] - have hp : (0:Int) < 2 ^ 638 := by positivity - have h2 : 2 ^ 638 * (10000 * num) ≤ 2 ^ 638 * (14145 * den + 28290) := by linarith [hchain] + have hp : (0:Int) < 2 ^ 637 := by positivity + have h2 : 2 ^ 637 * (10000 * num) ≤ 2 ^ 637 * (14145 * den + 28290) := by linarith [hchain] exact le_of_mul_le_mul_left h2 hp /-- `100·num ≤ 145·den` (`ê ≤ 1.45`) on the nonneg half. -/ @@ -730,7 +767,7 @@ theorem num_le_145_den {x : Nat} (hx : x < 2 ^ 256) (htnn : 0 ≤ int256 (tTree x)) : 100 * ((evTree x : Int) + int256 (todTree x)) ≤ 145 * ((evTree x : Int) - int256 (todTree x)) := by have hceil := num_ceiling hx hC hC0 htnn - have hden := den_ge_072 hx hC hC0 + have hden := den_ge_194 hx hC hC0 set num := (evTree x : Int) + int256 (todTree x) with hnumdef set den := (evTree x : Int) - int256 (todTree x) with hdendef -- 100·(10000·num) ≤ 100·(14145·den + 28290) ≤ 10000·(145·den) since 355·den ≥ 2829000 @@ -743,7 +780,7 @@ theorem r0_cap {x : Nat} (hx : x < 2 ^ 256) 10000 * (int256 (r0Tree x) - 2 ^ 126) ≤ 4146 * 2 ^ 126 := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 have hceil := num_ceiling hx hC hC0 htnn - have hden := den_ge_072 hx hC hC0 + have hden := den_ge_194 hx hC hC0 set r0 := int256 (r0Tree x) with hr0def set num := (evTree x : Int) + int256 (todTree x) with hnumdef set den := (evTree x : Int) - int256 (todTree x) with hdendef @@ -759,13 +796,13 @@ theorem r0_cap {x : Nat} (hx : x < 2 ^ 256) /-! ## The per-point never-over (nonnegative half) -/ /-- The link-1 jitter divided by `DENv` stays inside its budget (nonneg half): -`Wev·2⁵⁹⁰·(r0 − 2¹²⁶)/DENv ≤ 6207065162659510332/10¹⁹`. -/ +`Wev·2⁵⁹⁰·(r0 − 2¹²⁶)/DENv ≤ 2170557036555806152/10¹⁹`. -/ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (283678831804417 : Real) * 2 ^ 590 * ((int256 (r0Tree x) : Real) - 2 ^ 126) / + (142941343449089 : Real) * 2 ^ 590 * ((int256 (r0Tree x) : Real) - 2 ^ 126) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ - 6207065162659510332 / 10000000000000000000 := by + 2170557036555806152 / 10000000000000000000 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set r0 := int256 (r0Tree x) with hr0def @@ -775,52 +812,52 @@ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos rcases le_or_gt ((r0:Real) - 2^126) 0 with hle0 | hgt0 - · have hnumneg : (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ 0 := + · have hnumneg : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hle0 - have : (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) / (DENv v t : Real) ≤ 0 := + have : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) / (DENv v t : Real) ≤ 0 := div_nonpos_of_nonpos_of_nonneg hnumneg (le_of_lt hDR) linarith [this] · rw [div_le_iff₀ hDR] - -- r0 − 2^126 ≤ 4146·2^126/10^4 (r0_cap); DENv ≥ 2^638·(den−2) ≥ 2^638·(den_lo−2) + -- r0 − 2^126 ≤ 4146·2^126/10^4 (r0_cap); DENv ≥ 2^637·(den−2) ≥ 2^637·(den_lo−2) have hcap := r0_cap hx hC hC0 htnn have hcapR : (r0 : Real) - 2 ^ 126 ≤ 4146 * 2 ^ 126 / 10000 := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hcap push_cast at h linarith [h] obtain ⟨hDEN_ge, _⟩ := DENv_runtime_bracket hx hC hC0 htnn - have hden := den_ge_072 hx hC hC0 - have hDENlow : (2:Int) ^ 638 * (61251667532612381706986956632087880162 - 2) ≤ DENv v t := by - have : (2:Int) ^ 638 * (61251667532612381706986956632087880162 - 2) ≤ - 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 638 := by + have hden := den_ge_194 hx hC hC0 + have hDENlow : (2:Int) ^ 637 * (165038630930342071346895739193146786756 - 2) ≤ DENv v t := by + have : (2:Int) ^ 637 * (165038630930342071346895739193146786756 - 2) ≤ + 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 637 := by nlinarith [hden] linarith [this, hDEN_ge] - have hDENlowR : ((2:Real) ^ 638 * (61251667532612381706986956632087880162 - 2)) ≤ + have hDENlowR : ((2:Real) ^ 637 * (165038630930342071346895739193146786756 - 2)) ≤ (DENv v t : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDENlow push_cast at h linarith [h] - have hnum_le : (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ - (283678831804417 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := + have hnum_le : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ + (142941343449089 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := mul_le_mul_of_nonneg_left hcapR (by positivity) - have hbudget : (283678831804417 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) ≤ - (6207065162659510332 / 10000000000000000000) * - ((2:Real) ^ 638 * (61251667532612381706986956632087880162 - 2)) := by + have hbudget : (142941343449089 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) ≤ + (2170557036555806152 / 10000000000000000000) * + ((2:Real) ^ 637 * (165038630930342071346895739193146786756 - 2)) := by norm_num - calc (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) - ≤ (283678831804417 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := hnum_le - _ ≤ (6207065162659510332 / 10000000000000000000) * - ((2:Real) ^ 638 * (61251667532612381706986956632087880162 - 2)) := hbudget - _ ≤ (6207065162659510332 / 10000000000000000000) * (DENv v t : Real) := + calc (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) + ≤ (142941343449089 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := hnum_le + _ ≤ (2170557036555806152 / 10000000000000000000) * + ((2:Real) ^ 637 * (165038630930342071346895739193146786756 - 2)) := hbudget + _ ≤ (2170557036555806152 / 10000000000000000000) * (DENv v t : Real) := mul_le_mul_of_nonneg_left hDENlowR (by norm_num) /-- **The per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + B` with the four-link budget -`B = 10050013498897899168/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3291…`, the `Mp` +`B = 6013505372794194988/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3291…`, the `Mp` factor `≤ √2·2¹²⁶/(2¹³¹−1) ≤ 0.0442…`, and the reduced-argument gap `≤ √2/128 ≤ 0.0111…`. -/ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10050013498897899168 / 10000000000000000000 := by + 6013505372794194988 / 10000000000000000000 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -839,7 +876,7 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) exact_mod_cast this -- link 1: r0 ≤ 2^126·Qv + jitter have hlink1 : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 6207065162659510332 / 10000000000000000000 := by + 2170557036555806152 / 10000000000000000000 := by rcases le_or_gt r0 (2^126) with hsm | hbg · have hi := link1_over_small hx hC hC0 htnn hsm have hiR : (r0 : Real) * (DENv v t : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) := by @@ -849,10 +886,10 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) linarith [hr0le] · have hi := link1_over_tight hx hC hC0 htnn (le_of_lt hbg) have hjointR : (r0 : Real) * (DENv v t : Real) - (2 ^ 126 : Real) * (NUMv v t : Real) ≤ - (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) := by + (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] have hstep : (r0 : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) / (DENv v t : Real) + - (283678831804417 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) / (DENv v t : Real) := by + (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) / (DENv v t : Real) := by rw [div_add_div_same, le_div_iff₀ hDR]; nlinarith [hjointR, hDR] rw [mul_div_assoc] at hstep linarith [hstep, jitter_over_budget hx hC hC0 htnn] @@ -920,30 +957,30 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) 110485434560398051 / 10000000000000000000 := by nlinarith [hcGap1] calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 6207065162659510332 / 10000000000000000000 := hlink1 + 2170557036555806152 / 10000000000000000000 := hlink1 _ ≤ ((2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 3290521163436398582 / 10000000000000000000) + - 6207065162659510332 / 10000000000000000000 := by linarith [hgran] + 2170557036555806152 / 10000000000000000000 := by linarith [hgran] _ ≤ (((2 ^ 126 : Real) * Et + 441941738241592203 / 10000000000000000000) + 3290521163436398582 / 10000000000000000000) + - 6207065162659510332 / 10000000000000000000 := by linarith [hNEMp, hcMp] + 2170557036555806152 / 10000000000000000000 := by linarith [hNEMp, hcMp] _ ≤ ((((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + 441941738241592203 / 10000000000000000000) + 3290521163436398582 / 10000000000000000000) + - 6207065162659510332 / 10000000000000000000 := by linarith [hEtErt] + 2170557036555806152 / 10000000000000000000 := by linarith [hEtErt] _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10050013498897899168 / 10000000000000000000 := by rw [hErtdef]; ring + 6013505372794194988 / 10000000000000000000 := by rw [hErtdef]; ring /-! ## The per-point never-over (nonpositive half) -/ /-- The link-1 jitter budget on the nonpositive half: -`Wod·2⁴⁸⁰·(−t)·(r0 + 2¹²⁶)/DENv ≤ 6207065162659510332/10¹⁹`. -/ +`Wod·2⁴⁸⁰·(−t)·(r0 + 2¹²⁶)/DENv ≤ 2170557036555806152/10¹⁹`. -/ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (1075052609 : Real) * 2 ^ 480 * (-(int256 (tTree x) : Real)) * + (269746241 : Real) * 2 ^ 480 * (-(int256 (tTree x) : Real)) * ((int256 (r0Tree x) : Real) + 2 ^ 126) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ - 6207065162659510332 / 10000000000000000000 := by + 2170557036555806152 / 10000000000000000000 := by obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 have hr0le := r0_le_2126_neg hx hC hC0 htneg obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 @@ -952,18 +989,18 @@ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hev : (103786963397729689639908782561058906594 : Int) ≤ (evTree x : Int) := by - have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 from by norm_num] at this + have hev : (207573926795459379279817565122117813188 : Int) ≤ (evTree x : Int) := by + have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 from by norm_num] at this exact this - have hDEN_low : (2:Int) ^ 638 * 103786963397729689639908782561058906594 ≤ DENv v t := by - have : (2:Int) ^ 638 * 103786963397729689639908782561058906594 ≤ 2 ^ 638 * (evTree x : Int) := + have hDEN_low : (2:Int) ^ 637 * 207573926795459379279817565122117813188 ≤ DENv v t := by + have : (2:Int) ^ 637 * 207573926795459379279817565122117813188 ≤ 2 ^ 637 * (evTree x : Int) := mul_le_mul_of_nonneg_left hev (by positivity) linarith [this, hDEN_ge] have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hDEN_low have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos rw [div_le_iff₀ hDR] - -- numerator ≤ Wod·2^480·H128·2·2^126; DENv ≥ 2^638·A0 + -- numerator ≤ Wod·2^480·H128·2·2^126; DENv ≥ 2^637·A0 have hntR : (0:Real) ≤ -(t : Real) := by have : (t : Real) ≤ 0 := by exact_mod_cast htneg linarith @@ -982,26 +1019,26 @@ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le push_cast at h linarith [h] - have hnum_le : (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) ≤ - (1075052609 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := by - have h1 : (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) ≤ - (1075052609 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 := + have hnum_le : (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) ≤ + (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := by + have h1 : (269746241 : Real) * 2 ^ 480 * (-(t : Real)) ≤ + (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 := mul_le_mul_of_nonneg_left hntH (by positivity) exact mul_le_mul h1 hr0pH hr0pR (by positivity) - have hDENlowR : ((2:Real) ^ 638 * 103786963397729689639908782561058906594) ≤ (DENv v t : Real) := by + have hDENlowR : ((2:Real) ^ 637 * 207573926795459379279817565122117813188) ≤ (DENv v t : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDEN_low push_cast at h linarith [h] - have hbudget : (1075052609 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * - (2 * 2 ^ 126) ≤ (6207065162659510332 / 10000000000000000000) * - ((2:Real) ^ 638 * 103786963397729689639908782561058906594) := by + have hbudget : (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * + (2 * 2 ^ 126) ≤ (2170557036555806152 / 10000000000000000000) * + ((2:Real) ^ 637 * 207573926795459379279817565122117813188) := by norm_num - calc (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) - ≤ (1075052609 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := + calc (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) + ≤ (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := hnum_le - _ ≤ (6207065162659510332 / 10000000000000000000) * - ((2:Real) ^ 638 * 103786963397729689639908782561058906594) := hbudget - _ ≤ (6207065162659510332 / 10000000000000000000) * (DENv v t : Real) := + _ ≤ (2170557036555806152 / 10000000000000000000) * + ((2:Real) ^ 637 * 207573926795459379279817565122117813188) := hbudget + _ ≤ (2170557036555806152 / 10000000000000000000) * (DENv v t : Real) := mul_le_mul_of_nonneg_left hDENlowR (by norm_num) /-- **The per-point never-over (nonpositive half).** The granularity is free here; the `Mp` factor @@ -1010,7 +1047,7 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10050013498897899168 / 10000000000000000000 := by + 6013505372794194988 / 10000000000000000000 := by have htdom := tdom_neg hx hC hC0 htneg have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -1023,13 +1060,13 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos -- link 1: r0 ≤ 2^126·Qv + jitter have hlink1 : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 6207065162659510332 / 10000000000000000000 := by + 2170557036555806152 / 10000000000000000000 := by have hi := link1_over_neg hx hC hC0 htneg have hiR : (r0 : Real) * (DENv v t : Real) - (2 ^ 126 : Real) * (NUMv v t : Real) ≤ - (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) := by + (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] have hstep : (r0 : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) / (DENv v t : Real) + - (1075052609 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) / + (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) / (DENv v t : Real) := by rw [div_add_div_same, le_div_iff₀ hDR]; nlinarith [hiR, hDR] rw [mul_div_assoc] at hstep @@ -1094,28 +1131,28 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_le_mul_of_nonneg_left hgran1 (by positivity) calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 6207065162659510332 / 10000000000000000000 := hlink1 + 2170557036555806152 / 10000000000000000000 := hlink1 _ ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - 6207065162659510332 / 10000000000000000000 := by linarith [hgranR] + 2170557036555806152 / 10000000000000000000 := by linarith [hgranR] _ ≤ ((2 ^ 126 : Real) * Et + 441941738241592203 / 10000000000000000000) + - 6207065162659510332 / 10000000000000000000 := by linarith [hNEMp, hcMp] + 2170557036555806152 / 10000000000000000000 := by linarith [hNEMp, hcMp] _ ≤ (((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + 441941738241592203 / 10000000000000000000) + - 6207065162659510332 / 10000000000000000000 := by linarith [hEtErt] + 2170557036555806152 / 10000000000000000000 := by linarith [hEtErt] _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10050013498897899168 / 10000000000000000000 := by + 6013505372794194988 / 10000000000000000000 := by rw [hErtdef] have : (110485434560398051 : Real) / 10000000000000000000 + 441941738241592203 / 10000000000000000000 + - 6207065162659510332 / 10000000000000000000 ≤ - 10050013498897899168 / 10000000000000000000 := by norm_num + 2170557036555806152 / 10000000000000000000 ≤ + 6013505372794194988 / 10000000000000000000 := by norm_num linarith [this] /-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + B` (`WAD·B < MARGIN`). -/ theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 10050013498897899168 / 10000000000000000000 := by + 6013505372794194988 / 10000000000000000000 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_over_tight hx hC hC0 htnn · exact r0_real_over_tight_neg hx hC hC0 (le_of_lt htneg) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index 6ab75c7b4..a18b5acde 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -4,16 +4,16 @@ import ExpProof.Floor.R0Exp # The deficit (under) side of the per-point `r0`-vs-`exp` bridge, and the seam bound This module contains the counterpart to the never-over `r0_real_over_within`: the per-point deficit -`2¹²⁶·exp(rt) ≤ r0 + 67/10` (`r0_real_under_within`), both signs, with the same four-link chain: +`2¹²⁶·exp(rt) ≤ r0 + 31/10` (`r0_real_under_within`), both signs, with the same four-link chain: -1. link-1 deficit against the grid rational, `≤ 6001/1000`; +1. link-1 deficit against the grid rational, `≤ 5/2`; 2. the argument granularity (`Floor.GranV`) — free on the `t ≥ 0` half, `≤ 1644901622230542074/10¹⁹` (`Mp`-folded) on the `t ≤ 0` half; 3. the `Mp` factor, `≤ 1/20` (via `r0 ≤ 1.45·2¹²⁶`); 4. the under-direction reduced-argument gap, `≤ 37/100` (via `exp(rt) ≤ √2·(1+ε)`). -The sum `6001/1000 + 1/20 + 1644901622230542074/10¹⁹ + 37/100 ≤ 67/10` feeds the `k = 63` deficit -envelope `((67/10)·10¹⁸ + MARGIN)/2⁶³ < 1`. The module closes with the octave-seam `r0`-doubling +The sum `2500/1000 + 1/20 + 1644901622230542074/10¹⁹ + 37/100 ≤ 31/10` feeds the `k = 63` deficit +envelope `((31/10)·5¹⁸·2¹⁸ + 2¹⁸·MARGIN)/2⁶³ < 1`. The module closes with the octave-seam `r0`-doubling bound `r0₁ + 2 ≤ 2·r0₂` (`SeamR0Bound`), where the `1 − exp(−1/RAY)` seam slack (≈ `1.7·10¹¹` grid units against `r0₂ > 2¹²⁴`) dwarfs both per-point budgets and the two integer units. -/ @@ -85,14 +85,14 @@ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - have hden072 : (61251667532612381706986956632087880162 : Int) ≤ ev - tod := by - have := den_ge_072 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this + have hden072 : (165038630930342071346895739193146786756 : Int) ≤ ev - tod := by + have := den_ge_194 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 -- tod ≥ 0 on nonneg half have htodnn : (0:Int) ≤ tod := by obtain ⟨_, _, htodlo, _⟩ := todTree_bound hx hC hC0 have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have htod : (2 ^ 128 : Int) * tod ≤ int256 (tTree x) * (odTree x : Int) := htodlo + have htod : (2 ^ 129 : Int) * tod ≤ int256 (tTree x) * (odTree x : Int) := htodlo have hpos : (0:Int) ≤ int256 (tTree x) * (odTree x : Int) := mul_nonneg htnn hodnn nlinarith [htod, hpos] refine ⟨?_, ?_⟩ @@ -111,26 +111,26 @@ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) /-! ## Link 1 (under side): the grid rational vs `r0` -/ -/-- **Link-1 under (nonneg half)**: `1000·(2¹²⁶·NUMv − r0·DENv) ≤ 6001·DENv`. The floor residual -costs one denominator; the odd-truncation carry `(2⁶³⁸ + Wod·2⁴⁸⁰·t)·(2¹²⁶ + r0)` fits in five -(`t ≤ H128`, `r0 ≤ 1.45·2¹²⁶`, `den ≥ 0.72·2¹²⁶`). -/ +/-- **Link-1 under (nonneg half)**: `1000·(2¹²⁶·NUMv − r0·DENv) ≤ 2500·DENv`. The floor residual +costs one denominator; the odd-truncation carry `(2⁶³⁷ + Wod·2⁴⁸⁰·t)·(2¹²⁶ + r0)` fits in `1.49` +denominators (`t ≤ H128`, `r0 ≤ 1.45·2¹²⁶`, `den ≥ 1.94·2¹²⁶`). -/ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : 1000 * (2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x))) ≤ - 6001 * DENv (vTree x) (int256 (tTree x)) := by + 2500 * DENv (vTree x) (int256 (tTree x)) := by obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨_, htOp_hi⟩ := tOd_bracket_nonneg hx hC hC0 htnn obtain ⟨hr0lo, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn obtain ⟨hDEN_ge, _⟩ := DENv_runtime_bracket hx hC hC0 htnn obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - have hden := den_ge_072 hx hC hC0 + have hden := den_ge_194 hx hC hC0 have hLHS : 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) ≤ - 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) + - (2 ^ 638 + 1075052609 * 2 ^ 480 * int256 (tTree x)) * (2 ^ 126 + int256 (r0Tree x)) := by + 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + + (2 ^ 637 + 269746241 * 2 ^ 480 * int256 (tTree x)) * (2 ^ 126 + int256 (r0Tree x)) := by unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef @@ -140,65 +140,65 @@ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) set Op := (odNumV (vTree x) : Int) with hOpdef have h2126r0_np : (2:Int) ^ 126 - r0 ≤ 0 := by linarith [hr0lo] have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] - -- Ep·2^110·(2^126−r0) ≤ 2^638·ev·(2^126−r0) - have hterm1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ 2 ^ 638 * ev * (2 ^ 126 - r0) := by + -- Ep·2^110·(2^126−r0) ≤ 2^637·ev·(2^126−r0) + have hterm1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ 2 ^ 637 * ev * (2 ^ 126 - r0) := by apply mul_le_mul_of_nonpos_right _ h2126r0_np nlinarith [hEp_lo] - -- t·Op·(2^126+r0) ≤ (2^638·tod + 2^638 + Wod·2^480·t)·(2^126+r0) + -- t·Op·(2^126+r0) ≤ (2^637·tod + 2^637 + Wod·2^480·t)·(2^126+r0) have hterm2 : t * Op * (2 ^ 126 + r0) ≤ - (2 ^ 638 * tod + 2 ^ 638 + 1075052609 * 2 ^ 480 * t) * (2 ^ 126 + r0) := + (2 ^ 637 * tod + 2 ^ 637 + 269746241 * 2 ^ 480 * t) * (2 ^ 126 + r0) := mul_le_mul_of_nonneg_right htOp_hi hr0p_nn - -- floor: 2^126·num − r0·den < den, scaled by 2^638 + -- floor: 2^126·num − r0·den < den, scaled by 2^637 have hfloor : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by linarith [hfloor_hi] - have hfloor638 : (2:Int) ^ 638 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) ≤ - 2 ^ 638 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) + have hfloor638 : (2:Int) ^ 637 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) ≤ + 2 ^ 637 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) nlinarith [hterm1, hterm2, hfloor638] -- budget the two additive pieces against DENv set r0 := int256 (r0Tree x) with hr0def set t := int256 (tTree x) with htdef set den := (evTree x : Int) - int256 (todTree x) with hdendef set D := DENv (vTree x) t with hDdef - have hA : 2 ^ 638 * den ≤ D + 2 * 2 ^ 638 := by rw [hDdef]; linarith [hDEN_ge] - have hDlow : (2:Int) ^ 638 * (61251667532612381706986956632087880162 - 2) ≤ D := by - have h1 : (2:Int) ^ 638 * (61251667532612381706986956632087880162 - 2) ≤ - 2 ^ 638 * den - 2 * 2 ^ 638 := by nlinarith [hden] + have hA : 2 ^ 637 * den ≤ D + 2 * 2 ^ 637 := by rw [hDdef]; linarith [hDEN_ge] + have hDlow : (2:Int) ^ 637 * (165038630930342071346895739193146786756 - 2) ≤ D := by + have h1 : (2:Int) ^ 637 * (165038630930342071346895739193146786756 - 2) ≤ + 2 ^ 637 * den - 2 * 2 ^ 637 := by nlinarith [hden] rw [hDdef]; linarith [h1, hDEN_ge] - have hB : (2 ^ 638 + 1075052609 * 2 ^ 480 * t) * (2 ^ 126 + r0) ≤ 5 * D := by - have hcoef : 2 ^ 638 + 1075052609 * 2 ^ 480 * t ≤ - 2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199 := by - have := mul_le_mul_of_nonneg_left hthi (by positivity : (0:Int) ≤ 1075052609 * 2 ^ 480) + have hB : 100 * ((2 ^ 637 + 269746241 * 2 ^ 480 * t) * (2 ^ 126 + r0)) ≤ 149 * D := by + have hcoef : 2 ^ 637 + 269746241 * 2 ^ 480 * t ≤ + 2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199 := by + have := mul_le_mul_of_nonneg_left hthi (by positivity : (0:Int) ≤ 269746241 * 2 ^ 480) linarith [this] have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [(r0_bracket_nonneg hx hC hC0 htnn).1] - have h1 : (2 ^ 638 + 1075052609 * 2 ^ 480 * t) * (2 ^ 126 + r0) ≤ - (2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199) * + have h1 : (2 ^ 637 + 269746241 * 2 ^ 480 * t) * (2 ^ 126 + r0) ≤ + (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0) := mul_le_mul_of_nonneg_right hcoef hr0p_nn - have h2 : 100 * ((2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199) * + have h2 : 100 * ((2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * (2 ^ 126 + r0)) ≤ - (2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199) * + (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * (245 * 2 ^ 126) := by have hr0cap : 100 * (2 ^ 126 + r0) ≤ 245 * 2 ^ 126 := by linarith [hr0hi145] nlinarith [hr0cap] - have h3 : (2 ^ 638 + 1075052609 * 2 ^ 480 * 117932881612756647068972071382077242199) * - (245 * 2 ^ 126) ≤ 500 * (2 ^ 638 * (61251667532612381706986956632087880162 - 2)) := by + have h3 : (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * + (245 * 2 ^ 126) ≤ 149 * (2 ^ 637 * (165038630930342071346895739193146786756 - 2)) := by norm_num - have h4 : (500 : Int) * (2 ^ 638 * (61251667532612381706986956632087880162 - 2)) ≤ 500 * D := + have h4 : (149 : Int) * (2 ^ 637 * (165038630930342071346895739193146786756 - 2)) ≤ 149 * D := mul_le_mul_of_nonneg_left hDlow (by norm_num) linarith [h1, h2, h3, h4] - have hC2000 : (2000 : Int) * 2 ^ 638 ≤ D := by - have : (2000 : Int) * 2 ^ 638 ≤ 2 ^ 638 * (61251667532612381706986956632087880162 - 2) := by + have hC2000 : (2000 : Int) * 2 ^ 637 ≤ D := by + have : (2000 : Int) * 2 ^ 637 ≤ 2 ^ 637 * (165038630930342071346895739193146786756 - 2) := by norm_num linarith [this, hDlow] linarith [hLHS, hA, hB, hC2000] -/-- **Link-1 under (nonpositive half)**: same `6001/1000` budget; the even-truncation width and the -`tod`-floor unit are absorbed by `DENv ≥ 2⁶³⁸·ev ≥ 2⁶³⁸·A0`. -/ +/-- **Link-1 under (nonpositive half)**: the same `2500/1000` budget; the even-truncation width and +the `tod`-floor unit are absorbed by `DENv ≥ 2⁶³⁷·ev ≥ 2⁶³⁷·A0`. -/ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : 1000 * (2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x))) ≤ - 6001 * DENv (vTree x) (int256 (tTree x)) := by + 2500 * DENv (vTree x) (int256 (tTree x)) := by obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_hi, _⟩ := tOd_bracket_neg hx hC hC0 htneg @@ -206,11 +206,11 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 have hDEN_ge := DENv_ge_ev_neg hx hC hC0 htneg obtain ⟨hev_lo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨htod_lo125, _, _, _⟩ := todTree_bound hx hC hC0 + obtain ⟨htod_lo125, _⟩ := todTree_small hx hC hC0 have hLHS : 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) ≤ - 2 ^ 638 * ((evTree x : Int) - int256 (todTree x)) + - 283678831804417 * 2 ^ 590 * 2 ^ 126 + 2 * 2 ^ 638 * 2 ^ 126 := by + 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + + 142941343449089 * 2 ^ 590 * 2 ^ 126 + 2 * 2 ^ 637 * 2 ^ 126 := by unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef @@ -225,51 +225,51 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) have h2126r0_le : (2:Int) ^ 126 - r0 ≤ 2 ^ 126 := by linarith [hr0nn] have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by positivity have hr0p_le : (2:Int) ^ 126 + r0 ≤ 2 * 2 ^ 126 := by linarith [hr0le] - -- Ep·2^110·(2^126−r0) ≤ 2^638·ev·(2^126−r0) + Wev·2^590·2^126 + -- Ep·2^110·(2^126−r0) ≤ 2^637·ev·(2^126−r0) + Wev·2^590·2^126 have hterm1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ - 2 ^ 638 * ev * (2 ^ 126 - r0) + 283678831804417 * 2 ^ 590 * 2 ^ 126 := by + 2 ^ 637 * ev * (2 ^ 126 - r0) + 142941343449089 * 2 ^ 590 * 2 ^ 126 := by have h1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ - (2 ^ 638 * ev + 283678831804417 * 2 ^ 590) * (2 ^ 126 - r0) := by + (2 ^ 637 * ev + 142941343449089 * 2 ^ 590) * (2 ^ 126 - r0) := by apply mul_le_mul_of_nonneg_right _ h2126r0_nn nlinarith [hEp_hi] - have h2 : (283678831804417 : Int) * 2 ^ 590 * (2 ^ 126 - r0) ≤ - 283678831804417 * 2 ^ 590 * 2 ^ 126 := + have h2 : (142941343449089 : Int) * 2 ^ 590 * (2 ^ 126 - r0) ≤ + 142941343449089 * 2 ^ 590 * 2 ^ 126 := mul_le_mul_of_nonneg_left h2126r0_le (by positivity) nlinarith [h1, h2] - -- t·Op·(2^126+r0) ≤ (2^638·tod + 2^638)·(2^126+r0) ≤ 2^638·tod·(2^126+r0) + 2·2^638·2^126 + -- t·Op·(2^126+r0) ≤ (2^637·tod + 2^637)·(2^126+r0) ≤ 2^637·tod·(2^126+r0) + 2·2^637·2^126 have hterm2 : t * Op * (2 ^ 126 + r0) ≤ - 2 ^ 638 * tod * (2 ^ 126 + r0) + 2 * 2 ^ 638 * 2 ^ 126 := by - have h1 : t * Op * (2 ^ 126 + r0) ≤ (2 ^ 638 * tod + 2 ^ 638) * (2 ^ 126 + r0) := + 2 ^ 637 * tod * (2 ^ 126 + r0) + 2 * 2 ^ 637 * 2 ^ 126 := by + have h1 : t * Op * (2 ^ 126 + r0) ≤ (2 ^ 637 * tod + 2 ^ 637) * (2 ^ 126 + r0) := mul_le_mul_of_nonneg_right htOp_hi hr0p_nn - have h2 : (2:Int) ^ 638 * (2 ^ 126 + r0) ≤ 2 ^ 638 * (2 * 2 ^ 126) := + have h2 : (2:Int) ^ 637 * (2 ^ 126 + r0) ≤ 2 ^ 637 * (2 * 2 ^ 126) := mul_le_mul_of_nonneg_left hr0p_le (by positivity) nlinarith [h1, h2] -- floor: 2^126·num − r0·den ≤ den, scaled have hfloor : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by linarith [hfloor_hi] - have hfloor638 : (2:Int) ^ 638 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) ≤ - 2 ^ 638 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) + have hfloor638 : (2:Int) ^ 637 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) ≤ + 2 ^ 637 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) nlinarith [hterm1, hterm2, hfloor638] - -- budget against DENv ≥ 2^638·ev ≥ 2^638·A0; den ≤ ev + 2^125 + -- budget against DENv ≥ 2^637·ev ≥ 2^637·A0; den ≤ ev + 2^125 set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef set D := DENv (vTree x) (int256 (tTree x)) with hDdef - have hev : (103786963397729689639908782561058906594 : Int) ≤ ev := by - have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ ev := by + have hev : (207573926795459379279817565122117813188 : Int) ≤ ev := by + have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ ev := by rw [hevdef]; exact_mod_cast hev_lo - rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 from by norm_num] at this + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 from by norm_num] at this exact this have hden_le : ev - tod ≤ ev + 2 ^ 125 := by have : -(2 ^ 125 : Int) ≤ tod := htod_lo125 linarith [this] - have hDev : 2 ^ 638 * ev ≤ D := hDEN_ge - -- 1000·(2^638·(ev + 2^125) + Wev·2^590·2^126 + 2·2^638·2^126) ≤ 1000·2^638·ev + 5001·2^638·A0 - have hlit : 1000 * (2 ^ 638 * 2 ^ 125 + 283678831804417 * 2 ^ 590 * 2 ^ 126 + - 2 * 2 ^ 638 * 2 ^ 126) ≤ - (5001 : Int) * (2 ^ 638 * 103786963397729689639908782561058906594) := by + have hDev : 2 ^ 637 * ev ≤ D := hDEN_ge + -- 1000·(2^637·(ev + 2^125) + Wev·2^590·2^126 + 2·2^637·2^126) ≤ 1000·2^637·ev + 1500·2^637·A0 + have hlit : 1000 * (2 ^ 637 * 2 ^ 125 + 142941343449089 * 2 ^ 590 * 2 ^ 126 + + 2 * 2 ^ 637 * 2 ^ 126) ≤ + (1500 : Int) * (2 ^ 637 * 207573926795459379279817565122117813188) := by norm_num - have hAev : (5001 : Int) * (2 ^ 638 * 103786963397729689639908782561058906594) ≤ 5001 * D := by - have h1 : (2:Int) ^ 638 * 103786963397729689639908782561058906594 ≤ 2 ^ 638 * ev := + have hAev : (1500 : Int) * (2 ^ 637 * 207573926795459379279817565122117813188) ≤ 1500 * D := by + have h1 : (2:Int) ^ 637 * 207573926795459379279817565122117813188 ≤ 2 ^ 637 * ev := mul_le_mul_of_nonneg_left hev (by positivity) have := le_trans h1 hDev nlinarith [this] @@ -277,12 +277,12 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) /-! ## The per-point deficit (nonneg half) -/ -/-- **The per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 67/10`: link-1 `≤ 6001/1000`, the +/-- **The per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 31/10`: link-1 `≤ 2500/1000`, the `Mp` factor `≤ 1/20`, the under gap `≤ 37/100`; the granularity is free on this half. -/ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 67 / 10 := by + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 31 / 10 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -299,10 +299,10 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by have : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE exact_mod_cast this - -- link 1: 2^126·Qv ≤ r0 + 6001/1000 + -- link 1: 2^126·Qv ≤ r0 + 2500/1000 have hlink1 := link1_under_int hx hC hC0 htnn have hQv_le : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (r0 : Real) + 6001 / 1000 := by + (r0 : Real) + 2500 / 1000 := by rw [mul_div_assoc', div_le_iff₀ hDR] have hR := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlink1 push_cast at hR @@ -332,7 +332,7 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0hi145 push_cast at h linarith [h] - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 20 := by + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 2500 / 1000 + 1 / 20 := by have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) := mul_le_mul_of_nonneg_left hEt_le_Qv (by positivity) @@ -342,9 +342,9 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) have h3 : ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) ≤ 1 / 20 := by rw [hMpp1] have hcap : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (145 / 100) * (2 ^ 126 : Real) + 6001 / 1000 := by linarith [hQv_le, hr0R] + (145 / 100) * (2 ^ 126 : Real) + 2500 / 1000 := by linarith [hQv_le, hr0R] have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / (2 ^ 131 : Real)) - have hfin : ((145 / 100) * (2 ^ 126 : Real) + 6001 / 1000) * (1 / (2 ^ 131 : Real)) ≤ + have hfin : ((145 / 100) * (2 ^ 126 : Real) + 2500 / 1000) * (1 / (2 ^ 131 : Real)) ≤ 1 / 20 := by norm_num linarith [this, hfin] linarith [h1, h2 ▸ h1, h3, hQv_le] @@ -368,19 +368,19 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) linarith [h1, h2, h3] have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 67 / 10 - have hsum : (6001 : Real) / 1000 + 1 / 20 + 37 / 100 ≤ 67 / 10 := by norm_num + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 31 / 10 + have hsum : (2500 : Real) / 1000 + 1 / 20 + 37 / 100 ≤ 31 / 10 := by norm_num linarith [hEt_bound, hgap126, hdist, hsum] /-! ## The per-point deficit (nonpositive half) -/ -/-- **The per-point deficit (nonpositive half).** `2¹²⁶·exp(rt) ≤ r0 + 67/10`: link-1 `≤ 6001/1000`, +/-- **The per-point deficit (nonpositive half).** `2¹²⁶·exp(rt) ≤ r0 + 31/10`: link-1 `≤ 2500/1000`, the `Mp`-folded granularity `≤ 1644901622230542074/10¹⁹`, the `Mp` factor `≤ 1/20` (via `r0 ≤ 2¹²⁶`), the under gap `≤ 37/100`. -/ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 67 / 10 := by + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 31 / 10 := by have htdom := tdom_neg hx hC hC0 htneg have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -391,10 +391,10 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htneg htdom).2 have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos - -- link 1: 2^126·Qv ≤ r0 + 6001/1000 + -- link 1: 2^126·Qv ≤ r0 + 2500/1000 have hlink1 := link1_under_int_neg hx hC hC0 htneg have hQv_le : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (r0 : Real) + 6001 / 1000 := by + (r0 : Real) + 2500 / 1000 := by rw [mul_div_assoc', div_le_iff₀ hDR] have hR := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlink1 push_cast at hR @@ -423,7 +423,7 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le push_cast at h linarith [h] - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 6001 / 1000 + 1 / 20 + + have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 2500 / 1000 + 1 / 20 + 1644901622230542074 / 10000000000000000000 := by have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := mul_le_mul_of_nonneg_left hEt_le (by positivity) @@ -437,10 +437,10 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) 1 / 20 := by rw [hMp1] have hcap : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (2 ^ 126 : Real) + 6001 / 1000 := by linarith [hQv_le, hr0R] + (2 ^ 126 : Real) + 2500 / 1000 := by linarith [hQv_le, hr0R] have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / ((2 ^ 131 : Real) - 1)) - have hfin : ((2 ^ 126 : Real) + 6001 / 1000) * (1 / ((2 ^ 131 : Real) - 1)) ≤ 1 / 20 := by + have hfin : ((2 ^ 126 : Real) + 2500 / 1000) * (1 / ((2 ^ 131 : Real) - 1)) ≤ 1 / 20 := by rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] norm_num linarith [this, hfin] @@ -465,15 +465,15 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) linarith [h1, h2, h3] have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 67 / 10 - have hsum : (6001 : Real) / 1000 + 1 / 20 + 1644901622230542074 / 10000000000000000000 + - 37 / 100 ≤ 67 / 10 := by norm_num + show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 31 / 10 + have hsum : (2500 : Real) / 1000 + 1 / 20 + 1644901622230542074 / 10000000000000000000 + + 37 / 100 ≤ 31 / 10 := by norm_num linarith [hEt_bound, hgap126, hdist, hsum] -/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 67/10`. -/ +/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 31/10`. -/ theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 67 / 10 := by + (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 31 / 10 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_under_tight hx hC hC0 htnn · exact r0_real_under_tight_neg hx hC hC0 (le_of_lt htneg) @@ -481,7 +481,7 @@ theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) /-! ## The octave-seam `r0`-doubling consequence -/ /-- A lower bound on the quotient: `2¹²⁴ < r0Tree x`. -(`r0 ≥ 2¹²⁶·exp(rt) − 67/10 > 2¹²⁶·(1/2) − 67/10 > 2¹²⁴`.) -/ +(`r0 ≥ 2¹²⁶·exp(rt) − 31/10 > 2¹²⁶·(1/2) − 31/10 > 2¹²⁴`.) -/ theorem r0Tree_gt_2_124 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : (2 : Real) ^ 124 < (int256 (r0Tree x) : Real) := by @@ -490,7 +490,7 @@ theorem r0Tree_gt_2_124 {x : Nat} (hx : x < 2 ^ 256) have h1 : (2 ^ 126 : Real) * (1 / 2) < (2 ^ 126 : Real) * Real.exp (reducedArg x) := mul_lt_mul_of_pos_left hh (by positivity) have h2 : (2 ^ 126 : Real) * (1 / 2) = (2 ^ 125 : Real) := by norm_num - have h3 : (2 : Real) ^ 124 + 67 / 10 < (2 ^ 125 : Real) := by norm_num + have h3 : (2 : Real) ^ 124 + 31 / 10 < (2 ^ 125 : Real) := by norm_num linarith [hu, h1, h2 ▸ h1, h3] /-- **The seam exp relation.** Across a seam (`X2 = X1 + 1`, `k2 = k1 + 1`), @@ -538,32 +538,32 @@ theorem r0_seam_double {x1 x2 : Nat} have h1z : (1 - 1 / (2 * (10 ^ 27 : Real))) * (1 + 1 / (10 ^ 27 : Real)) ≥ 1 := by rw [ge_iff_le]; nlinarith [sq_nonneg (1 / (10 ^ 27 : Real))] nlinarith [hez, h1z, hexppos, mul_pos (by positivity : (0:Real) < 1 - 1/(2*(10^27:Real))) hexppos] - -- 2^126·E1 = 2·(2^126·E2)·y ≤ 2·(r0_2 + 67/10)·y - have hE2bound : (2 ^ 126 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + 67 / 10 := hunder2 + -- 2^126·E1 = 2·(2^126·E2)·y ≤ 2·(r0_2 + 31/10)·y + have hE2bound : (2 ^ 126 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + 31 / 10 := hunder2 have hr0_1 : (int256 (r0Tree x1) : Real) ≤ - 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y + - 10050013498897899168 / 10000000000000000000 := by + 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y + + 6013505372794194988 / 10000000000000000000 := by have h1 : (2 ^ 126 : Real) * E1 = 2 * ((2 ^ 126 : Real) * E2) * y := by rw [hseam]; ring have h2 : (int256 (r0Tree x1) : Real) ≤ (2 ^ 126 : Real) * E1 + - 10050013498897899168 / 10000000000000000000 := hover1 + 6013505372794194988 / 10000000000000000000 := hover1 rw [h1] at h2 - have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y := + have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y := mul_le_mul_of_nonneg_right (by linarith [mul_le_mul_of_nonneg_left hE2bound (by norm_num : (0:Real) ≤ 2)]) (le_of_lt hy_pos) linarith [h2, h3] have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^124)] - have hkey : 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y + - 10050013498897899168 / 10000000000000000000 + 2 < 2 * (int256 (r0Tree x2) : Real) := by - -- the seam gap is dominated by `(r0 + 67/10) / RAY`; the quotient exceeds `1562` here - have hyb : 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * y ≤ - 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) := + have hkey : 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y + + 6013505372794194988 / 10000000000000000000 + 2 < 2 * (int256 (r0Tree x2) : Real) := by + -- the seam gap is dominated by `(r0 + 31/10) / RAY`; the quotient exceeds `1562` here + have hyb : 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y ≤ + 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) := mul_le_mul_of_nonneg_left hy_bound (by linarith [hr0_2nn]) - have hexpand : 2 * ((int256 (r0Tree x2) : Real) + 67 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) = - 2 * (int256 (r0Tree x2) : Real) + 67 / 5 - - ((int256 (r0Tree x2) : Real) + 67 / 10) / (10 ^ 27 : Real) := by field_simp; ring - have hbig : ((int256 (r0Tree x2) : Real) + 67 / 10) / (10 ^ 27 : Real) > 1562 := by + have hexpand : 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) = + 2 * (int256 (r0Tree x2) : Real) + 31 / 5 - + ((int256 (r0Tree x2) : Real) + 31 / 10) / (10 ^ 27 : Real) := by field_simp; ring + have hbig : ((int256 (r0Tree x2) : Real) + 31 / 10) / (10 ^ 27 : Real) > 1562 := by rw [gt_iff_lt, lt_div_iff₀ (by positivity)] nlinarith [hr0_2_big, (by norm_num : (1562:Real) * 10 ^ 27 + 1 < 2 ^ 124)] linarith [hyb, hexpand ▸ hyb, hbig] diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index 2d3351724..d301d06dd 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -33,13 +33,13 @@ set_option maxRecDepth 100000 /-! ## Strict never-over: the accumulator stays a positive distance below the target -`accumReal_over` gives `accumReal x ≤ E`. With `B = 10050013498897899168/10¹⁹` the never-over envelope, +`accumReal_over` gives `accumReal x ≤ E`. With `B = 6013505372794194988/10¹⁹` the never-over envelope, `MARGIN` is `⌊WAD·B⌋ + 1` (`WAD = 5¹⁸`), so the inequality is in fact strict — the slack -`δ = MARGIN − WAD·B ≈ 0.98` (worth `δ/2^s` after the closing shift). The round trip needs this +`δ = MARGIN − WAD·B ≈ 0.07` (worth `δ/2^s` after the closing shift). The round trip needs this strictness to rule out `accumReal x = w` exactly. -/ /-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the target. -The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 10050013498897899168/10000000000000000000` plus `WAD·10050013498897899168/10000000000000000000 < MARGIN` give a strictly +The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 6013505372794194988/10000000000000000000` plus `WAD·6013505372794194988/10000000000000000000 < MARGIN` give a strictly negative residue. -/ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -49,13 +49,13 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- WAD·r0 − MARGIN < 5^18·2^126·Ert = E·2^s, using WAD·10050013498897899168/10000000000000000000 < MARGIN - have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375 < + -- WAD·r0 − MARGIN < 5^18·2^126·Ert = E·2^s, using WAD·6013505372794194988/10000000000000000000 < MARGIN + have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242 < expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 10050013498897899168 / 10000000000000000000 := hover + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 6013505372794194988 / 10000000000000000000 := hover have hscaled : (3814697265625 : Real) * (int256 (r0Tree x) : Real) ≤ - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 10050013498897899168 / 10000000000000000000) := + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 6013505372794194988 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] @@ -65,16 +65,16 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < norm_num] ring rw [hconst] - -- WAD·B = 3833775901374.02 < 3833775901375 = MARGIN - have hBM : (3814697265625 : Real) * (10050013498897899168 / 10000000000000000000) < - 3833775901375 := by norm_num + -- WAD·B = 3833775901374.02 < 2293970250242 = MARGIN + have hBM : (3814697265625 : Real) * (6013505372794194988 / 10000000000000000000) < + 2293970250242 := by norm_num linarith [hscaled, hBM] rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] /-- **Accumulator deficit, region-uniform.** On the region the accumulator is below the target by -strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 67/10` and the -octave fold give `accumReal x ≥ E − ((67/10)·WAD + MARGIN)/2^s` with `s = 108 − k ≥ 45`, and -`((67/10)·WAD + MARGIN)/2⁴⁵ ≈ 0.835 < 24/25`. The tightness below one is what closes the round trip +strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 31/10` and the +octave fold give `accumReal x ≥ E − ((31/10)·WAD + MARGIN)/2^s` with `s = 108 − k ≥ 45`, and +`((31/10)·WAD + MARGIN)/2⁴⁵ ≈ 0.835 < 24/25`. The tightness below one is what closes the round trip together with `lnWadToRay`'s ≈10⁻⁹ envelope. -/ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -88,18 +88,18 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask have hs45 : (45 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] have hs45n : 45 ≤ s := by exact_mod_cast hs45 have hpow : (2 ^ 45 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs45n - -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = 5^18·2^126·Ert ≤ WAD·(r0 + 67/10) - -- and (67/10)·WAD + MARGIN < (24/25)·2^45 ≤ (24/25)·2^s + -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = 5^18·2^126·Ert ≤ WAD·(r0 + 31/10) + -- and (31/10)·WAD + MARGIN < (24/25)·2^45 ≤ (24/25)·2^s have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < - (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 3833775901375 := by + (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = (WAD : Real) * (2 ^ 108 : Real) * Ert := hfold - have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 67 / 10 := hunder + have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 31 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num have h8wad : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 67 / 10) := + (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 31 / 10) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - have hbudget : (3814697265625 : Real) * (67 / 10) + 3833775901375 < (24 / 25) * (2 ^ 45 : Real) := by + have hbudget : (3814697265625 : Real) * (31 / 10) + 2293970250242 < (24 / 25) * (2 ^ 45 : Real) := by norm_num rw [hwad] at hkey have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = @@ -109,7 +109,7 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask ring rw [hconst] at hkey have hEs : expRayToWadTarget (int256 x) * (2 ^ s : Real) ≤ - (3814697265625 : Real) * (int256 (r0Tree x) : Real) + (3814697265625 : Real) * (67 / 10) := by + (3814697265625 : Real) * (int256 (r0Tree x) : Real) + (3814697265625 : Real) * (31 / 10) := by rw [hkey]; nlinarith [h8wad] -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; (24/25)·2^s ≥ (24/25)·2^45 have h2425 : (24 / 25 : Real) * (2 ^ 45 : Real) ≤ (24 / 25) * (2 ^ s : Real) := diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index 460b36dab..5f45ff83c 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -96,7 +96,7 @@ A x = int256 (WAD·r0 − MARGIN) / 2^(108 − k). /-- The real pre-floor accumulator of the runtime body, as an explicit `Real`. -/ def accumReal (x : Nat) : Real := - (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) : Real) / + (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) : Real) / (2 ^ (evmSub 0x6c (kTree x)) : Real) /-- On the meaningful region the body word `r1Tree x` is the integer floor of its real accumulator @@ -108,18 +108,18 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) := by + have hr1 : r1Tree x = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) := by have : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) := rfl + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) := rfl rw [this, hseq] - have hWw : evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf < 2 ^ 256 := + have hWw : evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02 < 2 ^ 256 := evmSub_lt _ _ - have hfloor := shr_real_floor (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) + have hfloor := shr_real_floor (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) (s := s) (by omega) hWw (by rw [hargeq]; exact hargnn) simp only at hfloor -- align `accumReal` (shift `evmSub 0x6c (kTree x)`) with the lemma's shift `s` have hAeq : accumReal x = - (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) : Real) / + (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) : Real) / (2 ^ s : Real) := by unfold accumReal; rw [hseq] rw [hAeq, hr1] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index 548e64ed2..cd357ec25 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -22,27 +22,27 @@ abbrev ev0 : Nat := 0xb9aacfacf3c10b378435f8e22adf48500e abbrev ev1 : Nat := 0x9a036222841f47c6ed6fc3f7602053 abbrev ev2 : Nat := 0x9064d9657e9a21fc16bb69331c5c3057 abbrev ev3 : Nat := 0x93f11e650dd6c64b96ce79065cdf809e -abbrev ev4 : Nat := 0x4e14a45e5650b506e97f4c5da23861e2 +abbrev ev4 : Nat := 0x9c2948bcaca16a0dd2fe98bb4470c3c4 abbrev evShift1 : Nat := 0x95 abbrev evShift2 : Nat := 0x7b abbrev evShift3 : Nat := 0x81 -abbrev evShift4 : Nat := 0x7f +abbrev evShift4 : Nat := 0x7e abbrev od0 : Nat := 0xdc07aff8276bde9a361278df6a10 abbrev od1 : Nat := 0xc926ddbecdeeb42e68cd16db7da8c1 abbrev od2 : Nat := 0xad4506af99be27419341e1816ff351 abbrev od3 : Nat := 0xaf566247c05753b42892f77b67a6b7c6 -abbrev od4 : Nat := 0x270a522f2b285a8374bfa62ed11c30f1 +abbrev od4 : Nat := 0x9c2948bcaca16a0dd2fe98bb4470c3c4 abbrev odShift1 : Nat := 0x7e abbrev odShift2 : Nat := 0x84 abbrev odShift3 : Nat := 0x7a -abbrev odShift4 : Nat := 0x82 +abbrev odShift4 : Nat := 0x80 -abbrev todShift : Nat := 0x80 +abbrev todShift : Nat := 0x81 abbrev expQShift : Nat := 0x7e abbrev foldShift : Nat := 0x6c abbrev wadWord : Nat := 0x3782dace9d9 -abbrev marginWord : Nat := 0x37c9ed9cabf +abbrev marginWord : Nat := 0x2161b482a02 theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by unfold Cmask int256 diff --git a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean index 19f4b6652..e4c31aab0 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean @@ -38,8 +38,8 @@ theorem cross_identity (ev1 ev2 tod1 tod2 : Int) : /-- `num = ev + tod < 2^128` (signed), from the even-accumulator and reduced-argument bounds. Stated as its own lemma so it carries a fresh kernel stack frame. -/ theorem numSum_lt {W : Nat} {ev tod : Int} (hW : int256 W = ev + tod) - (hev : ev < 2 ^ 127) (htod : tod < 2 ^ 127) : int256 W < 2 ^ 128 := by - rw [hW, show (2:Int)^128 = 2^127 + 2^127 from by ring]; omega + (hev : ev < 3 * 2 ^ 126) (htod : tod < 2 ^ 126) : int256 W < 2 ^ 128 := by + rw [hW, show (2:Int)^128 = 3 * 2^126 + 2^126 from by ring]; omega /-- The `shl 0x7e N` dividend transported to `Int` when `N`'s signed value is in `[0, 2^128)`: `int256 (shl 126 N) = 2^126 · int256 N`, and the result is in `[0, 2^255)`. -/ @@ -66,25 +66,25 @@ Given the numerator/denominator positivity and `tod1·ev2 ≤ tod2·ev1`, the tw `≤`-ordered. -/ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} (hE1 : E1 < 2 ^ 256) (hTD1 : TD1 < 2 ^ 256) (hE2 : E2 < 2 ^ 256) (hTD2 : TD2 < 2 ^ 256) - (hev1_lo : (103786963397729689639908782561058906594 : Int) ≤ (E1 : Int)) - (hev1_hi : (E1 : Int) < 2 ^ 127) - (htod1_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD1) - (htod1_hi : int256 TD1 < 42535295865117307932921825928971026432) - (hev2_lo : (103786963397729689639908782561058906594 : Int) ≤ (E2 : Int)) - (hev2_hi : (E2 : Int) < 2 ^ 127) - (htod2_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD2) - (htod2_hi : int256 TD2 < 42535295865117307932921825928971026432) + (hev1_lo : (207573926795459379279817565122117813188 : Int) ≤ (E1 : Int)) + (hev1_hi : (E1 : Int) < 3 * 2 ^ 126) + (htod1_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD1) + (htod1_hi : int256 TD1 < 85070591730234615865843651857942052864) + (hev2_lo : (207573926795459379279817565122117813188 : Int) ≤ (E2 : Int)) + (hev2_hi : (E2 : Int) < 3 * 2 ^ 126) + (htod2_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD2) + (htod2_hi : int256 TD2 < 85070591730234615865843651857942052864) (hcross : int256 TD1 * (E2 : Int) ≤ int256 TD2 * (E1 : Int)) : int256 (evmDiv (evmShl 0x7e (evmAdd E1 TD1)) (evmSub E1 TD1)) ≤ int256 (evmDiv (evmShl 0x7e (evmAdd E2 TD2)) (evmSub E2 TD2)) := by obtain ⟨hadd1, hsub1, hnum1, hden1⟩ := numden_pos_of hE1 hTD1 hev1_lo hev1_hi htod1_lo htod1_hi obtain ⟨hadd2, hsub2, hnum2, hden2⟩ := numden_pos_of hE2 hTD2 hev2_lo hev2_hi htod2_lo htod2_hi - -- bound the tod magnitude by 2^127 (looser, symbolic) to avoid large-literal kernel work - have htod1_hi' : int256 TD1 < 2 ^ 127 := by - have : (42535295865117307932921825928971026432 : Int) < 2 ^ 127 := by norm_num + -- the tod magnitude in the symbolic power form + have htod1_hi' : int256 TD1 < 2 ^ 126 := by + have : (85070591730234615865843651857942052864 : Int) = 2 ^ 126 := by norm_num omega - have htod2_hi' : int256 TD2 < 2 ^ 127 := by - have : (42535295865117307932921825928971026432 : Int) < 2 ^ 127 := by norm_num + have htod2_hi' : int256 TD2 < 2 ^ 126 := by + have : (85070591730234615865843651857942052864 : Int) = 2 ^ 126 := by norm_num omega -- numerator/denominator are positive and below 2^128 (signed) have hN1lt : int256 (evmAdd E1 TD1) < 2 ^ 128 := numSum_lt hadd1 hev1_hi htod1_hi' diff --git a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean index 9d8db5eaf..b399f1e05 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean @@ -26,48 +26,48 @@ set_option maxRecDepth 100000 /-- The even accumulator's signed value is its (nonnegative) Nat value, in `[a0, 2^127)`. -/ theorem evTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : - (103786963397729689639908782561058906594 : Int) ≤ (evTree x : Int) ∧ - (evTree x : Int) < 2 ^ 127 := by + (207573926795459379279817565122117813188 : Int) ≤ (evTree x : Int) ∧ + (evTree x : Int) < 3 * 2 ^ 126 := by obtain ⟨hlo, hhi⟩ := evTree_facts hv constructor - · have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo - rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 by + · have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 by norm_num] at this exact this - · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hhi - rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this + · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hhi + rw [show ((3 * 2 ^ 126 : Nat) : Int) = 3 * 2 ^ 126 by norm_num] at this; exact this -/-- The odd accumulator's signed value is its (nonnegative) Nat value, in `[b0, 2^126)`. -/ +/-- The odd accumulator's signed value is its (nonnegative) Nat value, in `[b0, 5·2^125)`. -/ theorem odTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : - (51893481698864844819954391280529453297 : Int) ≤ (odTree x : Int) ∧ - (odTree x : Int) < 2 ^ 126 := by + (207573926795459379279817565122117813188 : Int) ≤ (odTree x : Int) ∧ + (odTree x : Int) < 5 * 2 ^ 125 := by obtain ⟨hlo, hhi⟩ := odTree_facts hv constructor - · have : (0x270a522f2b285a8374bfa62ed11c30f1 : Int) ≤ (odTree x : Int) := by exact_mod_cast hlo - rw [show (0x270a522f2b285a8374bfa62ed11c30f1 : Int) = 51893481698864844819954391280529453297 by + · have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (odTree x : Int) := by exact_mod_cast hlo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 by norm_num] at this exact this - · have : (odTree x : Int) < (2 ^ 126 : Nat) := by exact_mod_cast hhi - rw [show ((2 ^ 126 : Nat) : Int) = 2 ^ 126 by norm_num] at this; exact this + · have : (odTree x : Int) < ((5 * 2 ^ 125 : Nat) : Int) := by exact_mod_cast hhi + rw [show ((5 * 2 ^ 125 : Nat) : Int) = 5 * 2 ^ 125 by norm_num] at this; exact this /-- The even/odd accumulators' signed difference is bounded by `DEv`/`DOd` (the Lipschitz bound transported to `Int`). -/ theorem evTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - -(42618413185 : Int) ≤ (evTree x1 : Int) - (evTree x2 : Int) ∧ - (evTree x1 : Int) - (evTree x2 : Int) ≤ 42618413185 := by + -(85236826369 : Int) ≤ (evTree x1 : Int) - (evTree x2 : Int) ∧ + (evTree x1 : Int) - (evTree x2 : Int) ≤ 85236826369 := by obtain ⟨h1, h2⟩ := evTree_lip hv1 hv2 hg1 hg2 - have c1 : ((evTree x1 : Nat) : Int) ≤ (evTree x2 : Int) + 42618413185 := by exact_mod_cast h1 - have c2 : ((evTree x2 : Nat) : Int) ≤ (evTree x1 : Int) + 42618413185 := by exact_mod_cast h2 + have c1 : ((evTree x1 : Nat) : Int) ≤ (evTree x2 : Int) + 85236826369 := by exact_mod_cast h1 + have c2 : ((evTree x2 : Nat) : Int) ≤ (evTree x1 : Int) + 85236826369 := by exact_mod_cast h2 omega theorem odTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - -(5322105549 : Int) ≤ (odTree x1 : Int) - (odTree x2 : Int) ∧ - (odTree x1 : Int) - (odTree x2 : Int) ≤ 5322105549 := by + -(21288422193 : Int) ≤ (odTree x1 : Int) - (odTree x2 : Int) ∧ + (odTree x1 : Int) - (odTree x2 : Int) ≤ 21288422193 := by obtain ⟨h1, h2⟩ := odTree_lip hv1 hv2 hg1 hg2 - have c1 : ((odTree x1 : Nat) : Int) ≤ (odTree x2 : Int) + 5322105549 := by exact_mod_cast h1 - have c2 : ((odTree x2 : Nat) : Int) ≤ (odTree x1 : Int) + 5322105549 := by exact_mod_cast h2 + have c1 : ((odTree x1 : Nat) : Int) ≤ (odTree x2 : Int) + 21288422193 := by exact_mod_cast h1 + have c2 : ((odTree x2 : Nat) : Int) ≤ (odTree x1 : Int) + 21288422193 := by exact_mod_cast h2 omega /-- The squared-argument step, as a `Nat` two-sided gap (`vTree x_i ≤ vTree x_j + W`). -/ @@ -89,32 +89,32 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} (hd1 : (340282366920 : Int) ≤ d) (ht1lo : -(170141183460469231731687303715884105728 : Int) < t1) (ht1hi : t1 < 170141183460469231731687303715884105728) - (hev1lo : (103786963397729689639908782561058906594 : Int) ≤ ev1) - (hev1hi : ev1 < 170141183460469231731687303715884105728) - (hev2lo : (103786963397729689639908782561058906594 : Int) ≤ ev2) - (hev2hi : ev2 < 170141183460469231731687303715884105728) - (hod2lo : (51893481698864844819954391280529453297 : Int) ≤ od2) - (hod2hi : od2 < 85070591730234615865843651857942052864) - (hevd1 : -(42618413185 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 42618413185) - (hodd1 : -(5322105549 : Int) ≤ od1 - od2) (hodd2 : od1 - od2 ≤ 5322105549) : - t1 * od1 * ev2 + 340282366920938463463374607431768211456 * ev1 ≤ + (hev1lo : (207573926795459379279817565122117813188 : Int) ≤ ev1) + (hev1hi : ev1 < 255211775190703847597530955573826158592) + (hev2lo : (207573926795459379279817565122117813188 : Int) ≤ ev2) + (hev2hi : ev2 < 255211775190703847597530955573826158592) + (hod2lo : (207573926795459379279817565122117813188 : Int) ≤ od2) + (hod2hi : od2 < 212676479325586539664609129644855132160) + (hevd1 : -(85236826369 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 85236826369) + (hodd1 : -(21288422193 : Int) ≤ od1 - od2) (hodd2 : od1 - od2 ≤ 21288422193) : + t1 * od1 * ev2 + 680564733841876926926749214863536422912 * ev1 ≤ (t1 + d) * od2 * ev1 := by -- cross difference `cd = od1·ev2 − od2·ev1`, bounded by `CB = DOd·2^127 + 2^126·DEv` have hcd_eq : od1 * ev2 - od2 * ev1 = (od1 - od2) * ev2 + od2 * (ev2 - ev1) := by ring -- bound each piece have hev2nn : (0 : Int) ≤ ev2 := by linarith have hod2nn : (0 : Int) ≤ od2 := by linarith - have hp1 : (od1 - od2) * ev2 ≤ 5322105549 * 170141183460469231731687303715884105728 := by + have hp1 : (od1 - od2) * ev2 ≤ 21288422193 * 255211775190703847597530955573826158592 := by nlinarith [hodd2, hodd1, hev2nn, hev2hi] - have hp1' : -(5322105549 * 170141183460469231731687303715884105728 : Int) ≤ (od1 - od2) * ev2 := by + have hp1' : -(21288422193 * 255211775190703847597530955573826158592 : Int) ≤ (od1 - od2) * ev2 := by nlinarith [hodd1, hev2nn, hev2hi] - have hp2 : od2 * (ev2 - ev1) ≤ 85070591730234615865843651857942052864 * 42618413185 := by + have hp2 : od2 * (ev2 - ev1) ≤ 212676479325586539664609129644855132160 * 85236826369 := by nlinarith [hod2nn, hod2hi, hevd1, hevd2] - have hp2' : -(85070591730234615865843651857942052864 * 42618413185 : Int) ≤ od2 * (ev2 - ev1) := by + have hp2' : -(212676479325586539664609129644855132160 * 85236826369 : Int) ≤ od2 * (ev2 - ev1) := by nlinarith [hod2nn, hod2hi, hevd1, hevd2] -- so |cd| ≤ CB - set CB : Int := 5322105549 * 170141183460469231731687303715884105728 + - 85070591730234615865843651857942052864 * 42618413185 with hCB + set CB : Int := 21288422193 * 255211775190703847597530955573826158592 + + 212676479325586539664609129644855132160 * 85236826369 with hCB have hcd_hi : od1 * ev2 - od2 * ev1 ≤ CB := by rw [hcd_eq, hCB]; linarith have hcd_lo : -CB ≤ od1 * ev2 - od2 * ev1 := by rw [hcd_eq, hCB]; linarith -- `t1·(od1·ev2 − od2·ev1) ≤ 2^127·CB` @@ -133,13 +133,13 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} linarith -- gain: d·od2·ev1 ≥ 340282366920·b0·a0 have hev1nn : (0 : Int) ≤ ev1 := by linarith - have hgain : (340282366920 : Int) * 51893481698864844819954391280529453297 * - 103786963397729689639908782561058906594 ≤ d * od2 * ev1 := by - have g1 : (340282366920 : Int) * 51893481698864844819954391280529453297 ≤ d * od2 := by - have := mul_le_mul hd1 hod2lo (by norm_num : (0:Int) ≤ 51893481698864844819954391280529453297) (by linarith) + have hgain : (340282366920 : Int) * 207573926795459379279817565122117813188 * + 207573926795459379279817565122117813188 ≤ d * od2 * ev1 := by + have g1 : (340282366920 : Int) * 207573926795459379279817565122117813188 ≤ d * od2 := by + have := mul_le_mul hd1 hod2lo (by norm_num : (0:Int) ≤ 207573926795459379279817565122117813188) (by linarith) linarith - have g2 : (340282366920 : Int) * 51893481698864844819954391280529453297 * - 103786963397729689639908782561058906594 ≤ (d * od2) * ev1 := + have g2 : (340282366920 : Int) * 207573926795459379279817565122117813188 * + 207573926795459379279817565122117813188 ≤ (d * od2) * ev1 := mul_le_mul g1 hev1lo (by norm_num) (by positivity) linarith [g2] -- assemble: goal `t1·od1·ev2 + 2^128·ev2 ≤ (t1+d)·od2·ev1 = t1·od2·ev1 + d·od2·ev1` @@ -148,23 +148,23 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} have hdecomp : t1 * od1 * ev2 - t1 * od2 * ev1 = t1 * (od1 * ev2 - od2 * ev1) := by ring rw [hexpand] -- numeric closure: 2^128·ev2 + 2^127·CB ≤ gain, and ev2 < 2^127 - have hkey : (340282366920938463463374607431768211456 : Int) * ev1 + + have hkey : (680564733841876926926749214863536422912 : Int) * ev1 + 170141183460469231731687303715884105728 * CB ≤ - (340282366920 : Int) * 51893481698864844819954391280529453297 * - 103786963397729689639908782561058906594 := by + (340282366920 : Int) * 207573926795459379279817565122117813188 * + 207573926795459379279817565122117813188 := by rw [hCB] nlinarith [hev1hi] nlinarith [htcd, hgain, hkey, hdecomp] /-- **The smooth certificate.** For adjacent same-octave inputs, -`t1·od1·ev2 + 2^128·ev2 ≤ t2·od2·ev1`. -/ +`t1·od1·ev2 + 2^129·ev2 ≤ t2·od2·ev1`. -/ theorem smooth_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) (hk : int256 (kTree x1) = int256 (kTree x2)) (hadj : int256 x2 = int256 x1 + 1) : int256 (tTree x1) * (odTree x1 : Int) * (evTree x2 : Int) + - 2 ^ 128 * (evTree x1 : Int) ≤ + 2 ^ 129 * (evTree x1 : Int) ≤ int256 (tTree x2) * (odTree x2 : Int) * (evTree x1 : Int) := by have hv1 : vTree x1 < 2 ^ 120 := (vTree_eq hx1 hC1 hC01).2 have hv2 : vTree x2 < 2 ^ 120 := (vTree_eq hx2 hC2 hC02).2 @@ -179,9 +179,10 @@ theorem smooth_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) -- numeric rewrites of the power bounds have hGv : (Gstep : Int) = 340282366920 := by unfold Gstep; norm_num rw [hGv] at htg1 - rw [show (2 : Int) ^ 127 = 170141183460469231731687303715884105728 by norm_num] at hev1hi hev2hi htlo1 hthi1 - rw [show (2 : Int) ^ 126 = 85070591730234615865843651857942052864 by norm_num] at hod2hi - rw [show (2 : Int) ^ 128 = 340282366920938463463374607431768211456 by norm_num] + rw [show (2 : Int) ^ 127 = 170141183460469231731687303715884105728 by norm_num] at htlo1 hthi1 + rw [show (3 : Int) * 2 ^ 126 = 255211775190703847597530955573826158592 by norm_num] at hev1hi hev2hi + rw [show (5 : Int) * 2 ^ 125 = 212676479325586539664609129644855132160 by norm_num] at hod2hi + rw [show (2 : Int) ^ 129 = 680564733841876926926749214863536422912 by norm_num] -- t2 = t1 + d, d ∈ [G, G+1] have ht2eq : int256 (tTree x2) = int256 (tTree x1) + (int256 (tTree x2) - int256 (tTree x1)) := by ring @@ -192,18 +193,18 @@ theorem smooth_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) /-- Abstract bridge: from the two `tod` floor sandwiches, the smooth inequality, and `ev1 > 0`, the cross inequality `tod1·ev2 ≤ tod2·ev1` follows. -/ theorem tod_cross_of {tod1 tod2 tprod1 tprod2 ev1 ev2 : Int} - (hfl1 : (2 : Int) ^ 128 * tod1 ≤ tprod1) (hfu2 : tprod2 < 2 ^ 128 * tod2 + 2 ^ 128) + (hfl1 : (2 : Int) ^ 129 * tod1 ≤ tprod1) (hfu2 : tprod2 < 2 ^ 129 * tod2 + 2 ^ 129) (hev1pos : 0 < ev1) (hev2nn : 0 ≤ ev2) - (hsmooth : tprod1 * ev2 + 2 ^ 128 * ev1 ≤ tprod2 * ev1) : + (hsmooth : tprod1 * ev2 + 2 ^ 129 * ev1 ≤ tprod2 * ev1) : tod1 * ev2 ≤ tod2 * ev1 := by - -- 2^128·tod1·ev2 ≤ tprod1·ev2 ≤ tprod2·ev1 − 2^128·ev1 < 2^128·tod2·ev1 - have hp : (0 : Int) < 2 ^ 128 := by norm_num - have s1 : 2 ^ 128 * tod1 * ev2 ≤ tprod1 * ev2 := mul_le_mul_right_nonneg hfl1 hev2nn - have s2 : tprod2 * ev1 < (2 ^ 128 * tod2 + 2 ^ 128) * ev1 := + -- 2^129·tod1·ev2 ≤ tprod1·ev2 ≤ tprod2·ev1 − 2^129·ev1 < 2^129·tod2·ev1 + have hp : (0 : Int) < 2 ^ 129 := by norm_num + have s1 : 2 ^ 129 * tod1 * ev2 ≤ tprod1 * ev2 := mul_le_mul_right_nonneg hfl1 hev2nn + have s2 : tprod2 * ev1 < (2 ^ 129 * tod2 + 2 ^ 129) * ev1 := Int.mul_lt_mul_of_pos_right hfu2 hev1pos - -- 2^128·tod1·ev2 ≤ tprod1·ev2 ≤ tprod2·ev1 − 2^128·ev1 < 2^128·tod2·ev1 + 2^128·ev1 − 2^128·ev1 - have hchain : 2 ^ 128 * (tod1 * ev2) < 2 ^ 128 * (tod2 * ev1) := by nlinarith [s1, s2, hsmooth] - exact le_of_lt (lt_of_mul_lt_mul_left hchain (by norm_num : (0:Int) ≤ 2 ^ 128)) + -- 2^129·tod1·ev2 ≤ tprod1·ev2 ≤ tprod2·ev1 − 2^129·ev1 < 2^129·tod2·ev1 + 2^129·ev1 − 2^129·ev1 + have hchain : 2 ^ 129 * (tod1 * ev2) < 2 ^ 129 * (tod2 * ev1) := by nlinarith [s1, s2, hsmooth] + exact le_of_lt (lt_of_mul_lt_mul_left hchain (by norm_num : (0:Int) ≤ 2 ^ 129)) /-- **The same-octave cross inequality.** For adjacent same-octave inputs, `tod1·ev2 ≤ tod2·ev1`. -/ diff --git a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean index e65e389d5..7ecbc2f9b 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean @@ -7,8 +7,8 @@ Telescoping `stage_lip` through the five even / four odd Horner stages, with the gap `|v2 − v1| ≤ W` from `vTree_step`, bounds the change of the accumulators: ``` -|evTree x2 − evTree x1| ≤ DEv = 42618413185, -|odTree x2 − odTree x1| ≤ DOd = 5322105549. +|evTree x2 − evTree x1| ≤ DEv = 85236826369, +|odTree x2 − odTree x1| ≤ DOd = 21288422193. ``` The intermediate per-stage prev bounds reuse the chained ceilings established inside @@ -60,7 +60,7 @@ def evS2 (x : Nat) : Nat := evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x def evS3 (x : Nat) : Nat := evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evS2 x) (vTree x))) theorem evTree_layers (x : Nat) : - evTree x = evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul (evS3 x) (vTree x))) := + evTree x = evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evS3 x) (vTree x))) := rfl theorem evS0_lt {x : Nat} (hv : vTree x < 2 ^ 120) : @@ -94,7 +94,7 @@ def odS1 (x : Nat) : Nat := evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 def odS2 (x : Nat) : Nat := evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (odS1 x) (vTree x))) theorem odTree_layers (x : Nat) : - odTree x = evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul (odS2 x) (vTree x))) := + odTree x = evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (odS2 x) (vTree x))) := rfl theorem odS0_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS0 x < 2 ^ 121 := by @@ -118,10 +118,10 @@ theorem odS2_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS2 x < 2 ^ 129 := by /-! ## Composed Lipschitz bounds -/ /-- **Even accumulator near-constancy.** Under a squared-argument gap `|v2 − v1| ≤ W` the even -accumulator changes by at most `DEv = 42618413185`. -/ +accumulator changes by at most `DEv = 85236826369`. -/ theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - dist_le (evTree x1) (evTree x2) 42618413185 := by + dist_le (evTree x1) (evTree x2) 85236826369 := by -- monic leading stage: distance exactly the argument gap have d0 : dist_le (evS0 x1) (evS0 x2) Wstep := evLead_lip (c := 0xb9aacfacf3c10b378435f8e22adf48500e) (W := Wstep) (by norm_num) hv1 hv2 hg1 hg2 @@ -153,20 +153,20 @@ theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 unfold Wstep; decide rw [he] at h; exact h -- final stage - have hfin := stage_lip_dist (c := 0x4e14a45e5650b506e97f4c5da23861e2) (P := 2 ^ 129) (V := 2 ^ 120) - (sh := 0x7f) (W := Wstep) + have hfin := stage_lip_dist (c := 0x9c2948bcaca16a0dd2fe98bb4470c3c4) (P := 2 ^ 129) (V := 2 ^ 120) + (sh := 0x7e) (W := Wstep) (Dprev := 10639016494) (le_of_lt (evS3_lt hv1)) (le_of_lt (evS3_lt hv2)) hv1 hv2 hg1 hg2 d3 (by norm_num) (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 129 * Wstep + 2 ^ 120 * 10639016494) / 2 ^ 0x7f + 1 = 42618413185 := by + have he : (2 ^ 129 * Wstep + 2 ^ 120 * 10639016494) / 2 ^ 0x7e + 1 = 85236826369 := by unfold Wstep; decide rw [he] at hfin rw [evTree_layers, evTree_layers]; exact hfin /-- **Odd accumulator near-constancy.** Under a squared-argument gap `|v2 − v1| ≤ W` the odd -accumulator changes by at most `DOd = 5322105549`. -/ +accumulator changes by at most `DOd = 21288422193`. -/ theorem odTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - dist_le (odTree x1) (odTree x2) 5322105549 := by + dist_le (odTree x1) (odTree x2) 21288422193 := by -- stage 0: prev is the constant leading coefficient (distance 0) have d0 : dist_le (odS0 x1) (odS0 x2) 649038 := by have h := stage_lip_dist (c := 0xc926ddbecdeeb42e68cd16db7da8c1) (P := 2 ^ 112) (V := 2 ^ 120) @@ -191,11 +191,11 @@ theorem odTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 have he : (2 ^ 121 * Wstep + 2 ^ 120 * 5192456) / 2 ^ 0x7a + 1 = 5318210098 := by unfold Wstep; decide rw [he] at h; exact h - have hfin := stage_lip_dist (c := 0x270a522f2b285a8374bfa62ed11c30f1) (P := 2 ^ 129) (V := 2 ^ 120) - (sh := 0x82) (W := Wstep) + have hfin := stage_lip_dist (c := 0x9c2948bcaca16a0dd2fe98bb4470c3c4) (P := 2 ^ 129) (V := 2 ^ 120) + (sh := 0x80) (W := Wstep) (Dprev := 5318210098) (le_of_lt (odS2_lt hv1)) (le_of_lt (odS2_lt hv2)) hv1 hv2 hg1 hg2 d2 (by norm_num) (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 129 * Wstep + 2 ^ 120 * 5318210098) / 2 ^ 0x82 + 1 = 5322105549 := by + have he : (2 ^ 129 * Wstep + 2 ^ 120 * 5318210098) / 2 ^ 0x80 + 1 = 21288422193 := by unfold Wstep; decide rw [he] at hfin rw [odTree_layers, odTree_layers]; exact hfin diff --git a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean index 8b4a976bc..60c3d4d1d 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean @@ -5,7 +5,7 @@ import ExpProof.Mono.Stages From the stage bounds this file assembles the closing quotient `r0 = exp(t)·2^126`: -* `tod = ⌊t·Od / 2^128⌋` transported to `Int`, with `|tod| < 2^125`; +* `tod = ⌊t·Od / 2^129⌋` transported to `Int`, with `|tod| < 2^126`; * the numerator `num = ev + tod` and denominator `den = ev − tod` are strictly positive (the reduced argument keeps `|tod|` well below `ev`); * `r0 = div(2^126·num, den)` — a plain `Nat` floor division — is at least `2^123` and below @@ -22,75 +22,81 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-! ## `tod = t·Od` in Q87 -/ +/-! ## `tod = t·Od` in Q88 -/ -/-- `tod` transported to `Int`: a signed floor with `|tod| < 2^125`. The product `t·Od` fits a word -(`|t| < 2^127`, `Od < 2^126`, so `|t·Od| < 2^253`). -/ +/-- `tod` transported to `Int`: a signed floor with `|tod| < 2^126`. The product `t·Od` fits a word +(`|t| < 2^127`, `Od < 5·2^125`, so `|t·Od| < 5·2^252`). -/ theorem todTree_bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - -(2 ^ 125 : Int) ≤ int256 (todTree x) ∧ int256 (todTree x) < 2 ^ 125 ∧ - (2 ^ 128 : Int) * int256 (todTree x) ≤ int256 (tTree x) * (odTree x : Int) ∧ + -(2 ^ 126 : Int) ≤ int256 (todTree x) ∧ int256 (todTree x) < 2 ^ 126 ∧ + (2 ^ 129 : Int) * int256 (todTree x) ≤ int256 (tTree x) * (odTree x : Int) ∧ int256 (tTree x) * (odTree x : Int) < - (2 ^ 128 : Int) * int256 (todTree x) + 2 ^ 128 := by + (2 ^ 129 : Int) * int256 (todTree x) + 2 ^ 129 := by obtain ⟨htlo, hthi⟩ := tTree_bound hx hC hC0 obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 - have hodlt : odTree x < 2 ^ 126 := odTree_lt hvlt + have hodlt : odTree x < 5 * 2 ^ 125 := odTree_lt hvlt have htw : tTree x < 2 ^ 256 := by unfold tTree; exact evmSar_lt _ _ have hodw : odTree x < 2 ^ 256 := by unfold odTree; exact evmAdd_lt _ _ set t := int256 (tTree x) with htdef -- od is a small nonnegative word have hodi : int256 (odTree x) = (odTree x : Int) := int256_of_lt (by - have : (2:Nat)^126 < 2 ^ 255 := by norm_num + have : 5 * 2 ^ 125 < (2:Nat) ^ 255 := by norm_num omega) have hod_nn : 0 ≤ (odTree x : Int) := by positivity - have hod_ub : (odTree x : Int) < 2 ^ 126 := by exact_mod_cast hodlt + have hod_ub : (odTree x : Int) < 5 * 2 ^ 125 := by exact_mod_cast hodlt -- the product t·od fits have hp127 : (2:Int)^127 = 170141183460469231731687303715884105728 := by norm_num have hp126 : (2:Int)^126 = 85070591730234615865843651857942052864 := by norm_num - have hp253 : (2:Int)^253 = 14474011154664524427946373126085988481658748083205070504932198000989141204992 := by norm_num + have hp252 : (5:Int) * 2^252 = 36185027886661311069865932815214971204146870208012676262330495002472853012480 := by norm_num have hp255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by norm_num - have hprod_lt : t * (odTree x : Int) < 2 ^ 253 := by - rw [hp127] at htlo hthi; rw [hp126] at hod_ub; rw [hp253]; nlinarith [htlo, hthi, hod_nn, hod_ub] - have hprod_gt : -(2 ^ 253 : Int) < t * (odTree x : Int) := by - rw [hp127] at htlo hthi; rw [hp126] at hod_ub; rw [hp253]; nlinarith [htlo, hthi, hod_nn, hod_ub] + have hprod_lt : t * (odTree x : Int) < 5 * 2 ^ 252 := by + rw [hp127] at htlo hthi + rw [show (5:Int) * 2 ^ 125 = 212676479325586539664609129644855132160 by norm_num] at hod_ub + rw [hp252]; nlinarith [htlo, hthi, hod_nn, hod_ub] + have hprod_gt : -(5 * 2 ^ 252 : Int) < t * (odTree x : Int) := by + rw [hp127] at htlo hthi + rw [show (5:Int) * 2 ^ 125 = 212676479325586539664609129644855132160 by norm_num] at hod_ub + rw [hp252]; nlinarith [htlo, hthi, hod_nn, hod_ub] -- transport the multiply have hmul : int256 (evmMul (tTree x) (odTree x)) = t * (odTree x : Int) := by - have := evmMul_transport htw hodw (by rw [hodi]; simp only [ipow255]; nlinarith [hprod_gt, hp253, hp255]) - (by rw [hodi]; simp only [ipow255]; nlinarith [hprod_lt, hp253, hp255]) + have := evmMul_transport htw hodw (by rw [hodi]; simp only [ipow255]; nlinarith [hprod_gt, hp252, hp255]) + (by rw [hodi]; simp only [ipow255]; nlinarith [hprod_lt, hp252, hp255]) rw [hodi] at this; exact this have hmul_lt : evmMul (tTree x) (odTree x) < 2 ^ 256 := evmMul_lt _ _ -- the `sar 128` floor sandwich - obtain ⟨_, hsl, hsh⟩ := evmSar_sandwich (s := 0x80) (by norm_num) hmul_lt + obtain ⟨_, hsl, hsh⟩ := evmSar_sandwich (s := 0x81) (by norm_num) hmul_lt rw [hmul] at hsl hsh - have hsh128 : (2:Int) ^ 0x80 = 2 ^ 128 := by norm_num - rw [hsh128] at hsl hsh - have htodeq : int256 (todTree x) = int256 (evmSar 0x80 (evmMul (tTree x) (odTree x))) := by + have hsh129 : (2:Int) ^ 0x81 = 2 ^ 129 := by norm_num + rw [hsh129] at hsl hsh + have htodeq : int256 (todTree x) = int256 (evmSar 0x81 (evmMul (tTree x) (odTree x))) := by unfold todTree; rfl rw [htodeq] refine ⟨?_, ?_, hsl, hsh⟩ - · -- lower bound: 2^128·tod ≤ t·od and t·od > -2^253 ⇒ tod > -2^125 - nlinarith [hsl, hprod_gt, hp253] - · -- upper bound: t·od < 2^128·tod + 2^128 and t·od < 2^253 ⇒ tod < 2^125 - nlinarith [hsh, hprod_lt, hp253] + · -- lower bound: 2^129·tod ≤ t·od and t·od > -5·2^252 ⇒ tod > -2^126 + nlinarith [hsl, hprod_gt, hp252] + · -- upper bound: t·od < 2^129·tod + 2^129 and t·od < 5·2^252 ⇒ tod < 2^126 + nlinarith [hsh, hprod_lt, hp252] /-! ## Numerator and denominator -/ /-- Abstract numerator/denominator positivity: stated over opaque words `E` (the even accumulator) and `TD` (the signed `t·Od` shift) with their bounds, so the deep Horner tree is never forced. -/ theorem numden_pos_of {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) - (hev_lo : (103786963397729689639908782561058906594 : Int) ≤ (E : Int)) - (hev_hi : (E : Int) < 2 ^ 127) - (htod_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD) - (htod_hi : int256 TD < 42535295865117307932921825928971026432) : + (hev_lo : (207573926795459379279817565122117813188 : Int) ≤ (E : Int)) + (hev_hi : (E : Int) < 3 * 2 ^ 126) + (htod_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD) + (htod_hi : int256 TD < 85070591730234615865843651857942052864) : int256 (evmAdd E TD) = (E : Int) + int256 TD ∧ int256 (evmSub E TD) = (E : Int) - int256 TD ∧ 0 < (E : Int) + int256 TD ∧ 0 < (E : Int) - int256 TD := by have hevi : int256 E = (E : Int) := int256_of_lt (by - have : (2:Nat)^127 < 2 ^ 255 := by norm_num - omega) - have hp127 : (E : Int) < 170141183460469231731687303715884105728 := by - rw [show (170141183460469231731687303715884105728 : Int) = 2 ^ 127 by norm_num]; exact hev_hi + have hEc : (E : Int) < ((2 ^ 255 : Nat) : Int) := by + have : (3 : Int) * 2 ^ 126 < ((2 ^ 255 : Nat) : Int) := by norm_num + linarith [hev_hi] + exact_mod_cast hEc) + have hp127 : (E : Int) < 255211775190703847597530955573826158592 := by + rw [show (255211775190703847597530955573826158592 : Int) = 3 * 2 ^ 126 by norm_num]; exact hev_hi have hadd : int256 (evmAdd E TD) = (E : Int) + int256 TD := by have := evmAdd_transport hevw htodw (by rw [hevi]; simp only [ipow255]; omega) @@ -117,19 +123,19 @@ theorem numden_pos {x : Nat} (hx : x < 2 ^ 256) have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ refine numden_pos_of hevw htodw ?_ ?_ ?_ ?_ - · have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 by norm_num] at this + · have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 by norm_num] at this exact this - · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hev_hi - rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this - · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact htod_lo - · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact htod_hi + · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hev_hi + rw [show ((3 * 2 ^ 126 : Nat) : Int) = 3 * 2 ^ 126 by norm_num] at this; exact this + · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_lo + · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_hi /-! ## The closing quotient `r0 = exp(t)·2^126` -/ /-- Abstract quotient bounds over opaque numerator/denominator words. `r0 = ⌊2^126·N/D⌋` lies in `[2^123, 2^128)`: the dividend `2^126·N` fits a word, `2^123·D < 2^251 ≤ 2^126·N` keeps the -quotient `≥ 2^123` (which the closing stage needs, since the margin exceeds one wad unit), and +quotient `≥ 2^123` (comfortably clearing the closing stage's `WAD·r0 > MARGIN`), and `N < 4·D` keeps it below `2^128`. -/ theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD : D < 2 ^ 256) (hDi : int256 D = (D : Int)) @@ -194,10 +200,10 @@ theorem int256_eq_of_nonneg {w : Nat} (hw : w < 2 ^ 256) (hnn : 0 ≤ int256 w) bounds. `r0 = div(2^126·(E+TD), E−TD)`; the numerator and denominator are positive and the quotient lands in `[2^123, 2^128)` (the reduced argument keeps `exp(t) ∈ [1/√2, √2)`). -/ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) - (hev_lo : (103786963397729689639908782561058906594 : Int) ≤ (E : Int)) - (hev_hi : (E : Int) < 2 ^ 127) - (htod_lo : -(42535295865117307932921825928971026432 : Int) ≤ int256 TD) - (htod_hi : int256 TD < 42535295865117307932921825928971026432) : + (hev_lo : (207573926795459379279817565122117813188 : Int) ≤ (E : Int)) + (hev_hi : (E : Int) < 3 * 2 ^ 126) + (htod_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD) + (htod_hi : int256 TD < 85070591730234615865843651857942052864) : 2 ^ 123 ≤ int256 (evmDiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) ∧ int256 (evmDiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) < 2 ^ 128 := by obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos_of hevw htodw hev_lo hev_hi htod_lo htod_hi @@ -205,7 +211,7 @@ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 have hDwlt : evmSub E TD < 2 ^ 256 := evmSub_lt _ _ -- numeric forms have h128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num - have h127 : (2:Int)^127 = 170141183460469231731687303715884105728 := by norm_num + have h127 : (3:Int) * 2 ^ 126 = 255211775190703847597530955573826158592 := by norm_num rw [h127] at hev_hi -- canonical Nat values for num and den obtain ⟨hNi, hNlt255⟩ := int256_eq_of_nonneg hNwlt (by rw [hadd]; omega) @@ -219,7 +225,8 @@ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 exact_mod_cast this have hNlo : 2 ^ 125 ≤ evmAdd E TD := by have : (2 ^ 125 : Int) ≤ ((evmAdd E TD : Nat) : Int) := by - rw [← hNi, hadd, show (2:Int)^125 = 42535295865117307932921825928971026432 by norm_num]; omega + rw [← hNi, hadd, show (2:Int)^125 = 42535295865117307932921825928971026432 by norm_num] + omega exact_mod_cast this have hND : ((evmAdd E TD : Nat) : Int) < 4 * ((evmSub E TD : Nat) : Int) := by rw [← hNi, ← hDi, hadd, hsub]; omega @@ -240,12 +247,12 @@ theorem r0Tree_bounds {x : Nat} (hx : x < 2 ^ 256) have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ refine r0Tree_bounds_ofEvTod hevw htodw ?_ ?_ ?_ ?_ - · have : (0x4e14a45e5650b506e97f4c5da23861e2 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x4e14a45e5650b506e97f4c5da23861e2 : Int) = 103786963397729689639908782561058906594 by norm_num] at this + · have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 by norm_num] at this exact this - · have : (evTree x : Int) < (2 ^ 127 : Nat) := by exact_mod_cast hev_hi - rw [show ((2 ^ 127 : Nat) : Int) = 2 ^ 127 by norm_num] at this; exact this - · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact htod_lo - · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact htod_hi + · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hev_hi + rw [show ((3 * 2 ^ 126 : Nat) : Int) = 3 * 2 ^ 126 by norm_num] at this; exact this + · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_lo + · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_hi end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean index 78533036f..bf45f1b08 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -7,9 +7,8 @@ import ExpProof.Mono.Quot `5¹⁸·2¹⁰⁸` grid, subtracts the one-sided margin, and floors with the `2ᵏ` octave scaling and the wad unit's remaining `2¹⁸` folded into the shift (`108 − k ∈ [45, 169]`). -* **nonneg**: `r0 ≥ 2^123` gives `WAD·r0 > MARGIN` (the margin exceeds one wad unit, so `r0 ≥ 1` - alone would not do), and the shift argument is nonnegative; the logical shift of a canonical - nonnegative word stays nonnegative. +* **nonneg**: `r0 ≥ 2^123` gives `WAD·r0 > MARGIN`, and the shift argument is nonnegative; the + logical shift of a canonical nonnegative word stays nonnegative. * **range**: `r0 < 2^128` gives `WAD·r0 < 2^170`, so even before the shift the argument is below `2^170`, and the floor is below `2^125 < 2^254`. -/ @@ -60,17 +59,17 @@ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) and below `2^170`. -/ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (hr0_lo : (2 ^ 123 : Int) ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 128) : - int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) = - 0x3782dace9d9 * int256 r0 - 0x37c9ed9cabf ∧ - 0 ≤ 0x3782dace9d9 * int256 r0 - 0x37c9ed9cabf ∧ - 0x3782dace9d9 * int256 r0 - 0x37c9ed9cabf < 2 ^ 170 := by + int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) = + 0x3782dace9d9 * int256 r0 - 0x2161b482a02 ∧ + 0 ≤ 0x3782dace9d9 * int256 r0 - 0x2161b482a02 ∧ + 0x3782dace9d9 * int256 r0 - 0x2161b482a02 < 2 ^ 170 := by have hwad : int256 (0x3782dace9d9 : Nat) = 0x3782dace9d9 := by rw [int256_of_lt (by norm_num)]; simp have hwadlt : (0x3782dace9d9 : Nat) < 2 ^ 256 := by norm_num have hp128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num have hp170 : (2:Int)^170 = 1496577676626844588240573268701473812127674924007424 := by norm_num have hwadc : (0x3782dace9d9 : Int) = 3814697265625 := by norm_num - have hmarc : (0x37c9ed9cabf : Int) = 3833775901375 := by norm_num + have hmarc : (0x2161b482a02 : Int) = 2293970250242 := by norm_num rw [hp128] at hr0_hi -- the product WAD·r0 transported have hmul : int256 (evmMul 0x3782dace9d9 r0) = 0x3782dace9d9 * int256 r0 := by @@ -79,12 +78,12 @@ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) rw [hwad] at this; exact this have hmullt : evmMul 0x3782dace9d9 r0 < 2 ^ 256 := evmMul_lt _ _ - have hmarlt : (0x37c9ed9cabf : Nat) < 2 ^ 256 := by norm_num - have hmari : int256 (0x37c9ed9cabf : Nat) = 0x37c9ed9cabf := by + have hmarlt : (0x2161b482a02 : Nat) < 2 ^ 256 := by norm_num + have hmari : int256 (0x2161b482a02 : Nat) = 0x2161b482a02 := by rw [int256_of_lt (by norm_num)]; simp -- transport the subtraction - have hsub : int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) = - 0x3782dace9d9 * int256 r0 - 0x37c9ed9cabf := by + have hsub : int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) = + 0x3782dace9d9 * int256 r0 - 0x2161b482a02 := by have := evmSub_transport hmullt hmarlt (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) @@ -137,7 +136,7 @@ theorem r1Tree_int256_nonneg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi have hr1 : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) := rfl + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) := rfl rw [hr1, hseq] exact (closingShr_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi)).1 @@ -150,11 +149,11 @@ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi have hr1 : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) := rfl - obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf) + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) := rfl + obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi) -- int256 (r1Tree x) ∈ [0, 2^125) ⇒ the Nat word is < 2^254 - have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x37c9ed9cabf)) := by + have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02)) := by rw [hr1, hseq] rw [← hReq] at hnn hlt have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean index efc22f403..8e571fb6e 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -11,8 +11,8 @@ r1Tree x2 = ⌊arg2 / 2^(s−1)⌋ = ⌊2·arg2 / 2^s⌋ ≥ ⌊arg1 / 2^s⌋ = ``` reduces the seam step to `arg1 ≤ 2·arg2`, which (since `MARGIN ≤ 2·WAD`) follows from the **`r0` -doubling bound** `r0Tree x1 + 2 ≤ 2·r0Tree x2` (`SeamR0Bound`; the comparison consumes two -integer units of the doubling gap because the margin exceeds one wad unit). The reduction is assembled over the +doubling bound** `r0Tree x1 + 2 ≤ 2·r0Tree x2` (`SeamR0Bound`; two integer units of the doubling +gap cover the margin against `2·WAD`). The reduction is assembled over the opaque shift-argument words (`seam_close`), so the deep `evmShr`/`evmSub`/`evmMul` tree behind `r1Tree` is never forced into whnf. -/ @@ -100,20 +100,20 @@ theorem seamStep_of_r0 (hr0 : SeamR0Bound) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (h obtain ⟨harg1eq, harg1nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 obtain ⟨harg2eq, harg2nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 have hr1eq1 : r1Tree x1 = - evmShr s1 (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x37c9ed9cabf) := by + evmShr s1 (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2161b482a02) := by unfold r1Tree; rw [hs1eq] have hr1eq2 : r1Tree x2 = - evmShr s2 (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x37c9ed9cabf) := by + evmShr s2 (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2161b482a02) := by unfold r1Tree; rw [hs2eq] rw [hr1eq1, hr1eq2] -- name the deep shift arguments opaquely before feeding the floor lemma - set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x37c9ed9cabf with harg1def - set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x37c9ed9cabf with harg2def + set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2161b482a02 with harg1def + set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2161b482a02 with harg2def have hr0bound : int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) := hr0 hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hargle : int256 arg1 ≤ 2 * int256 arg2 := by rw [harg1eq, harg2eq, show (0x3782dace9d9 : Int) = 3814697265625 by norm_num, - show (0x37c9ed9cabf : Int) = 3833775901375 by norm_num] + show (0x2161b482a02 : Int) = 2293970250242 by norm_num] -- `WAD·r0a − M ≤ 2·(WAD·r0b − M)` ⟸ `WAD·r0a + M ≤ 2·WAD·r0b` ⟸ `r0a ≤ 2·r0b − 2` and `M ≤ 2·WAD` nlinarith [hr0bound] exact seam_close (harg1def ▸ evmSub_lt _ _) (harg2def ▸ evmSub_lt _ _) hs1lt hs2lt hseq diff --git a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean index 4364dd6f7..05e70451d 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean @@ -12,7 +12,7 @@ those bounds this file transports the downstream kernel stages to closed `Int`/b stage is a bare add of `v` at its own basis, and its product with `v` is the only stage with no power-of-two headroom — its multiply safety rests on the exact coefficient literal against `v < 2^120`; -* `tod = t·Od` in Q87 (a signed shift, transported to `Int`); +* `tod = t·Od` in Q88 (a signed shift, transported to `Int`); * the numerator `ev + tod` and denominator `ev − tod` are both strictly positive; * `r0 = exp(t)·2^126`, the reciprocal-symmetric quotient, is strictly positive and `< 2^128`. @@ -326,13 +326,13 @@ theorem pvd (pe ve sh e : Nat) (hpe : pe + ve = sh + e) : (2:Nat) ^ pe * 2 ^ ve / 2 ^ sh = 2 ^ e := by rw [← Nat.pow_add, hpe, Nat.pow_add, Nat.mul_div_cancel_left _ (Nat.two_pow_pos sh)] -/-- Two-sided bound on the even Horner accumulator: `0x4e14… ≤ ev < 2^127`. The first multiply +/-- Two-sided bound on the even Horner accumulator: `0x9c29… ≤ ev < 3·2^126`. The first multiply `(ev0 + v)·v` is capped by the exact literal sum `(ev0 + 2^120)·2^120 < 2^256` — it has no power-of-two headroom. -/ theorem evTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x4e14a45e5650b506e97f4c5da23861e2 ≤ evTree x ∧ evTree x < 2 ^ 127 := by + 0x9c2948bcaca16a0dd2fe98bb4470c3c4 ≤ evTree x ∧ evTree x < 3 * 2 ^ 126 := by have hev : evTree x = - evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul @@ -362,23 +362,24 @@ theorem evTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 rw [pvd 129 120 129 120 (by norm_num)] at this; omega set ev3 := evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul ev2 v)) with hev3 - have hfin := stage_bounds (c := 0x4e14a45e5650b506e97f4c5da23861e2) (prev := ev3) (v := v) - (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x7f) h3 hv (by norm_num) (by norm_num) - (by rw [pvd 129 120 127 122 (by norm_num)]; norm_num) - rw [pvd 129 120 127 122 (by norm_num)] at hfin + have hfin := stage_bounds (c := 0x9c2948bcaca16a0dd2fe98bb4470c3c4) (prev := ev3) (v := v) + (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x7e) h3 hv (by norm_num) (by norm_num) + (by rw [pvd 129 120 126 123 (by norm_num)]; norm_num) + rw [pvd 129 120 126 123 (by norm_num)] at hfin refine ⟨hfin.1, ?_⟩ - have : (0x4e14a45e5650b506e97f4c5da23861e2 : Nat) + 2 ^ 122 < 2 ^ 127 := by norm_num + have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Nat) + 2 ^ 123 < 3 * 2 ^ 126 := by norm_num omega -theorem evTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evTree x < 2 ^ 127 := (evTree_facts hv).2 +theorem evTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evTree x < 3 * 2 ^ 126 := + (evTree_facts hv).2 theorem evTree_ge {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x4e14a45e5650b506e97f4c5da23861e2 ≤ evTree x := (evTree_facts hv).1 + 0x9c2948bcaca16a0dd2fe98bb4470c3c4 ≤ evTree x := (evTree_facts hv).1 -/-- Two-sided bound on the odd Horner accumulator: `0x270a… ≤ od < 2^126`. -/ +/-- Two-sided bound on the odd Horner accumulator: `0x9c29… ≤ od < 5·2^125`. -/ theorem odTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x270a522f2b285a8374bfa62ed11c30f1 ≤ odTree x ∧ odTree x < 2 ^ 126 := by + 0x9c2948bcaca16a0dd2fe98bb4470c3c4 ≤ odTree x ∧ odTree x < 5 * 2 ^ 125 := by have hod : odTree x = - evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul @@ -403,16 +404,17 @@ theorem odTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : (by rw [pvd 121 120 122 119 (by norm_num)]; norm_num)).2 rw [pvd 121 120 122 119 (by norm_num)] at this; omega set od2 := evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul od1 v)) with hod2 - have hfin := stage_bounds (c := 0x270a522f2b285a8374bfa62ed11c30f1) (prev := od2) (v := v) - (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x82) h2 hv (by norm_num) (by norm_num) - (by rw [pvd 129 120 130 119 (by norm_num)]; norm_num) - rw [pvd 129 120 130 119 (by norm_num)] at hfin + have hfin := stage_bounds (c := 0x9c2948bcaca16a0dd2fe98bb4470c3c4) (prev := od2) (v := v) + (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x80) h2 hv (by norm_num) (by norm_num) + (by rw [pvd 129 120 128 121 (by norm_num)]; norm_num) + rw [pvd 129 120 128 121 (by norm_num)] at hfin refine ⟨hfin.1, ?_⟩ - have : (0x270a522f2b285a8374bfa62ed11c30f1 : Nat) + 2 ^ 119 < 2 ^ 126 := by norm_num + have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Nat) + 2 ^ 121 < 5 * 2 ^ 125 := by norm_num omega -theorem odTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odTree x < 2 ^ 126 := (odTree_facts hv).2 +theorem odTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odTree x < 5 * 2 ^ 125 := + (odTree_facts hv).2 theorem odTree_ge {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x270a522f2b285a8374bfa62ed11c30f1 ≤ odTree x := (odTree_facts hv).1 + 0x9c2948bcaca16a0dd2fe98bb4470c3c4 ≤ odTree x := (odTree_facts hv).1 end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean index 3cb8ef4b3..6ba60ada6 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean @@ -18,15 +18,15 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-- The `tod`-bound hypotheses of `r0_mono_of_cross`, in the `2^125` form. -/ +/-- The `tod`-bound hypotheses of `r0_mono_of_cross`, in the `2^126` form. -/ theorem todTree_cross_bounds {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - -(42535295865117307932921825928971026432 : Int) ≤ int256 (todTree x) ∧ - int256 (todTree x) < 42535295865117307932921825928971026432 := by + -(85070591730234615865843651857942052864 : Int) ≤ int256 (todTree x) ∧ + int256 (todTree x) < 85070591730234615865843651857942052864 := by obtain ⟨hlo, hhi, _, _⟩ := todTree_bound hx hC hC0 refine ⟨?_, ?_⟩ - · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact hlo - · rw [show (42535295865117307932921825928971026432 : Int) = 2 ^ 125 by norm_num]; exact hhi + · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact hlo + · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact hhi /-- **Adjacent `r0` monotonicity** within an octave. -/ theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) @@ -90,14 +90,14 @@ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hk2w : kTree x2 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ have hseq := closing_shift_eq hk hk1w hk2w obtain ⟨s, hseqx, hslo, hshi, _⟩ := closing_shift hx1 hC1 hC01 - have hr1eq1 : r1Tree x1 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x37c9ed9cabf) := by + have hr1eq1 : r1Tree x1 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2161b482a02) := by unfold r1Tree; rw [hseqx] - have hr1eq2 : r1Tree x2 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x37c9ed9cabf) := by + have hr1eq2 : r1Tree x2 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2161b482a02) := by unfold r1Tree; rw [← hseq, hseqx] rw [hr1eq1, hr1eq2] -- the two shift arguments, transported to `Int`, are ordered (monotone `r0`) - set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x37c9ed9cabf with harg1 - set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x37c9ed9cabf with harg2 + set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2161b482a02 with harg1 + set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2161b482a02 with harg2 have hargle : int256 arg1 ≤ int256 arg2 := by rw [harg1eq, harg2eq] have hwad : (0 : Int) ≤ 0x3782dace9d9 := by norm_num diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean index 6b07f7937..6300573a5 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -44,7 +44,7 @@ def odTree (x : Nat) : Nat := (evmAdd od1 (evmShr odShift1 (evmMul od0 v))) v))) v))) v)) -/-- `t * Od(v)` in Q87. -/ +/-- `t * Od(v)` in Q88. -/ def todTree (x : Nat) : Nat := evmSar todShift (evmMul (tTree x) (odTree x)) /-- `exp(t)` in Q126. -/ diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 8bd10c98e..27f4da64e 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -418,19 +418,19 @@ theorem call_fun__expRayToWad_78_direct let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) - let tod := evmSar 0x80 (evmMul t od) + let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -482,19 +482,19 @@ theorem call_fun_expRayToWad_68_direct let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) - let tod := evmSar 0x80 (evmMul t od) + let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -545,19 +545,19 @@ theorem call_fun_wrap_expRayToWad_direct let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) - let tod := evmSar 0x80 (evmMul t od) + let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -605,19 +605,19 @@ theorem external_fun_wrap_expRayToWad_calldata_result let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) - let tod := evmSar 0x80 (evmMul t od) + let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -634,19 +634,19 @@ theorem external_fun_wrap_expRayToWad_calldata_result let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) - let tod := evmSar 0x80 (evmMul t od) + let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -735,19 +735,19 @@ theorem external_fun_wrap_expRayToWad_calldata_halts let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) - let tod := evmSar 0x80 (evmMul t od) + let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -841,19 +841,19 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) - let tod := evmSar 0x80 (evmMul t od) + let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -920,19 +920,19 @@ theorem run_exp_ray_to_wad_evm_eq_tree let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x4e14a45e5650b506e97f4c5da23861e2 (evmShr 0x7f (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x270a522f2b285a8374bfa62ed11c30f1 (evmShr 0x82 (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) - let tod := evmSar 0x80 (evmMul t od) + let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x37c9ed9cabf) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 8e6fbc7f4..385c44ea9 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -14,8 +14,8 @@ library Exp { /// returns w. Reverts with `Panic(17)` when x is large enough to leave the supported range /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256) { - // At this input the octave count k = round(x / (10²⁷⋅ln(2))) reaches 64. The error in - // `_expRayToWad` exceeds 1ulp at that scale. + // At this input the octave count k = round(x / (10²⁷⋅ln(2))) reaches 64, the first octave + // outside the certified range. if (x >= 0x8e383a2cdfa1b74a9422d2e1) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } @@ -27,7 +27,7 @@ library Exp { // Equivalent pseudocode; fixed-point truncations are accounted for below: // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln(2) + t)⋅10²⁷, |t| ≤ ln(2)/2 // t = x/10²⁷ - k⋅ln(2); // reduced argument (Q128) - // e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) (Ev Q87; Od Q87; e Q126) + // e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) (Ev Q88; Od Q89; e Q126) // r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; // wad // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 // return r + (x == 0); // pin exp(0) = 10¹⁸ exactly @@ -47,9 +47,11 @@ library Exp { // t: Q128 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2) // v = t²: Q123 the widest basis whose monic-stage product stays inside 256 bits, so // Ev(v)'s leading stage consumes v with no renormalizing shift - // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q87 (monic) - // Od(v) Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q87 - // Ev, Od, t⋅Od, and the numerator/denominator: Q87 + // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q88 (monic) + // Od(v) Horner along the staircase Q105 → Q102 → Q93 → Q94 → Q89 + // Ev, t⋅Od, and the numerator/denominator: Q88; Od: Q89. The closing bases are the + // widest at which each final coefficient keeps its byte width and the t⋅Od product + // stays inside 256 bits; the t⋅Od `sar` lands at Q88 directly // quotient: one `DIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays // below 2²⁵⁵) // output: multiplying by 5¹⁸ lands E on the 2¹⁰⁸ output grid (the 10¹⁸⋅2¹²⁶ grid with @@ -59,11 +61,11 @@ library Exp { // Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the // exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the // tightest bound the proof technique can bear, in spite of the fact that the worst-case - // error contributions do not co-occur. The budget bounds Δ ≤ 1.0050013498897899168, the sum - // of four one-sided contributions: + // error contributions do not co-occur. The budget bounds Δ ≤ 0.6013505372794194988, the sum + // of four one-sided contributions (displayed rounded up, so the shown values overshoot Δ): // integer Horner + closing `DIV` truncation: the Ev shared by the numerator Ev + t⋅Od // and denominator Ev - t⋅Od cancels to first order in the quotient, so its - // truncation barely perturbs e; this jitter stays < 0.62071. + // truncation barely perturbs e; this jitter stays < 0.21706. // argument granularity: v carries t² on the Q123 grid, and its floor only lowers the // polynomials' shared argument (by < 2⁻¹²³), which lifts e on the t > 0 half by < // 0.32906: one v-grain moves the quotient by 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose @@ -78,26 +80,27 @@ library Exp { // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = // √2/128). // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.1090 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer - // on the 2¹⁰⁸ output grid strictly above Δ's image: 0x37c9ed9cabf = ⌊5¹⁸⋅Δ⌋ + 1 = - // 3833775901375 (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never + // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0652 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer + // on the 2¹⁰⁸ output grid strictly above Δ's image: 0x2161b482a02 = ⌊5¹⁸⋅Δ⌋ + 1 = + // 2293970250242 (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never // overestimate requirement). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E. The under side is bounded to the - // same precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 67/10, where 67/10 bounds the sum of the - // integer-rational deficit (≤ 6001/1000, the Horner/`DIV`/floor truncation against the + // same precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 31/10, where 31/10 bounds the sum of the + // integer-rational deficit (≤ 5/2, the Horner/`DIV`/floor truncation against the // denominator), the `Mp` factor (≤ 1/20, via e ≤ 1.45·2¹²⁶), the under-direction // reduced-argument gap (≤ 37/100, via exp(t) ≤ √2), and the under-direction argument // granularity (≤ 17/100: the same one-grain envelope with the negative-half denominator // floor). Hence the maximum underestimation of the pre-floor accumulator A is E - A ≤ - // ((67/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶³ ≈ 0.83538 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The - // deficit envelope ((67/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave, so at k = 64 it - // exceeds 1ulp. On the central octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 1.2⋅10⁻²⁰ ulp, far + // ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶³ ≈ 0.40131 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The + // deficit envelope ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave and first + // exceeds 1ulp at k = 65; the guard pins the supported range at k ≤ 63. On the central + // octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 7.1⋅10⁻²¹ ulp, far // below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. The k = 0 // band is exactly [-H, H] with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, // √2). // // Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves the // pre-floor accumulator by at least 5¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 2.3⋅10²³ grid units. The error - // terms above confine the accumulator to a band of width 5¹⁸⋅(Δ + 67/10) ≈ 2.9⋅10¹³ grid + // terms above confine the accumulator to a band of width 5¹⁸⋅(Δ + 31/10) ≈ 1.4⋅10¹³ grid // units just below E's grid image at every octave (in grid units the band is k-independent; // an octave seam rescales E and the band together), so the per-step gain exceeds any // adverse swing within the band by more than 9 orders of magnitude, and the pre-floor @@ -133,28 +136,28 @@ library Exp { ev := add(0x9a036222841f47c6ed6fc3f7602053, shr(0x95, mul(ev, v))) ev := add(0x9064d9657e9a21fc16bb69331c5c3057, shr(0x7b, mul(ev, v))) ev := add(0x93f11e650dd6c64b96ce79065cdf809e, shr(0x81, mul(ev, v))) - ev := add(0x4e14a45e5650b506e97f4c5da23861e2, shr(0x7f, mul(ev, v))) + ev := add(0x9c2948bcaca16a0dd2fe98bb4470c3c4, shr(0x7e, mul(ev, v))) // Od(v), Horner down the staircase. let od := 0xdc07aff8276bde9a361278df6a10 od := add(0xc926ddbecdeeb42e68cd16db7da8c1, shr(0x7e, mul(od, v))) od := add(0xad4506af99be27419341e1816ff351, shr(0x84, mul(od, v))) od := add(0xaf566247c05753b42892f77b67a6b7c6, shr(0x7a, mul(od, v))) - od := add(0x270a522f2b285a8374bfa62ed11c30f1, shr(0x82, mul(od, v))) + od := add(0x9c2948bcaca16a0dd2fe98bb4470c3c4, shr(0x80, mul(od, v))) - // t⋅Od in Q87 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are + // t⋅Od in Q88 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are // both positive. - let tod := sar(0x80, mul(t, od)) + let tod := sar(0x81, mul(t, od)) // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁵, the denominator > // 0. r := div(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E on the 2¹⁰⁸ output grid (5¹⁸ = 10¹⁸/2¹⁸ multiplies the Q126 quotient), less the - // one-sided margin (0x37c9ed9cabf = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then floored by + // one-sided margin (0x2161b482a02 = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then floored by // `shr(108 - k, …)` which folds in the 2ᵏ octave scaling and the wad unit's remaining // 2¹⁸ (108 - k ∈ [45, 168]). - r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x37c9ed9cabf)) + r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x2161b482a02)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 4ff5b3bbe..56acf708c 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -123,13 +123,11 @@ contract ExpTest is Test { } } - /// The largest supported input, one below the revert threshold. frac(E) ~= 0.74, comfortably - /// inside the k = 63 deficit envelope. + /// The largest supported input, one below the revert threshold. frac(E) ~= 0.74 exceeds the + /// k = 63 deficit envelope (~0.40), so the result is exactly floor(E). function testExpRayToWadSupportedEdge() external pure { - int256 r = Exp.expRayToWad(_TOO_BIG - 1); int256 floorE = 13043817825332782212349571798501714341; - assertLe(r, floorE, "overestimates exp"); - assertGe(r, floorE - 1, "below floor minus one"); + assertEq(Exp.expRayToWad(_TOO_BIG - 1), floorE, "supported-edge floor"); } /// The 1-ulp underestimate is achieved: the least x >= 44e27 whose result is floor(E) - 1. From 20012903e0198a55543104d11aa875862c89cbe1 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Fri, 3 Jul 2026 14:24:28 +0200 Subject: [PATCH 138/149] Refit the exp coefficients on the Q88/Q89 grids; halve the cut nudge The joint low-bit refinement re-runs on the finer closing grids (sensitivity curves at 90 digits, LP min-max over the quasi-continuous dimensions, exhaustive search over the two constant-term dimensions, integer polish): six mid-stage coefficients move and the two constant terms move identically, keeping Ev(0) = 2*Od(0) exact. The kernel now binds that shared 16-byte literal once (c0 = 0x9c2948bcaca16a0dd2fe98bb4470c388) and closes both Horner chains from it. The realized relative envelope tightens to <= 0.0075 ulp (~133 of the form's ~135 bits, within 0.1% of the constrained continuous optimum), which carries the Taylor cut at the 2^-132 nudge with 2.1x slack and halves the Mp budget term to 220970869120796102/10^19. The never-over budget is B = 5792534503673398887/10^19 (jitter, granularity, and reduced-argument terms unchanged) and the margin is its exact grid floor 0x2027afc6c05 = floor(5^18*B) + 1 = 2209676553221, with strictness slack 1 - 1381252288818359375/10^19. The under side is unchanged at 31/10; the k = 63 deficit envelope is 0.39891 < 1. The proof re-derives the coefficient-bearing layers: CertDefsV literals and stagings (outer scales 2^1192/2^1040), the 2^132 cut scales through CapsV and the cert-real lemmas, GranV's Kpoly and cross expansion (the 32-piece table and its 2^131-folded budget inequalities are unchanged -- the fold is nudge-independent and the 2^132 amplification it feeds is strictly smaller), den_ge_194, and the margin word. Certificates regenerate with every cover reached; the bracket geometry from the Q88 carry is untouched. Full lake build is green from the Theorems.lean axiom gates; validated against a 60-digit reference on 8000+ adversarial points and the lnWadToRay round trip; all 11 tests and every witness are unchanged. Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/CapsV.lean | 24 +-- .../ExpProof/ExpProof/Floor/CertDefsV.lean | 70 +++---- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 4 +- formal/exp/ExpProof/ExpProof/Floor/GranV.lean | 92 ++++---- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 112 +++++----- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 22 +- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 198 +++++++++--------- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 62 +++--- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 24 +-- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 12 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 18 +- formal/exp/ExpProof/ExpProof/Mono/Cross.lean | 4 +- .../exp/ExpProof/ExpProof/Mono/CrossCert.lean | 34 +-- .../exp/ExpProof/ExpProof/Mono/EvOdLip.lean | 46 ++-- formal/exp/ExpProof/ExpProof/Mono/Quot.lean | 12 +- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 26 +-- formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 10 +- formal/exp/ExpProof/ExpProof/Mono/Stages.lean | 70 +++---- .../exp/ExpProof/ExpProof/Mono/StepMono.lean | 8 +- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 144 ++++++------- src/vendor/Exp.sol | 42 ++-- 21 files changed, 519 insertions(+), 515 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean index 001b19751..a1cf63c26 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean @@ -17,8 +17,8 @@ nonnegativity into the two bare-argument Taylor caps the floor layer folds with implementation's exact **v-form** rational `ê_v(t) = NUM(t)/DEN(t)` (built from the even/odd Horner polynomials in `v = t²`) nudged by the dyadic margin, with `Qexp = 2^128`: -* `capExpUp` — never-over `exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê_v·(1 + 2⁻¹³¹)`; -* `capExpLo` — not-two-below `yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`. +* `capExpUp` — never-over `exp(t/Qexp) ≤ yUB(t)/wUB(t)` with `yUB/wUB = ê_v·(1 + 2⁻¹³²)`; +* `capExpLo` — not-two-below `yLB(t)/wLB(t) ≤ exp(t/Qexp)` with `yLB/wLB = ê_v·(1 − 2⁻¹³²)`. The bridge is the depth-`K = 27` `Common.Exp.capUB_of_partial`/`capLB` shape. -/ @@ -65,16 +65,16 @@ theorem evalExpN27 (t : Int) : evalPoly expN27 t = expNumI 27 t (Qexp : Int) := rw [evalPoly_expPolyNum] congr 1 <;> simp [evalPoly] -theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 131 + 1) * evalPoly numExpV t := by +theorem evalYUB (t : Int) : evalPoly yUB t = (2 ^ 132 + 1) * evalPoly numExpV t := by unfold yUB; rw [evalPoly_polyScale] -theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 131 * evalPoly denExpV t := by +theorem evalWUB (t : Int) : evalPoly wUB t = 2 ^ 132 * evalPoly denExpV t := by unfold wUB; rw [evalPoly_polyScale] -theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 131 - 1) * evalPoly numExpV t := by +theorem evalYLB (t : Int) : evalPoly yLB t = (2 ^ 132 - 1) * evalPoly numExpV t := by unfold yLB; rw [evalPoly_polyScale] -theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 131 * evalPoly denExpV t := by +theorem evalWLB (t : Int) : evalPoly wLB t = 2 ^ 132 * evalPoly denExpV t := by unfold wLB; rw [evalPoly_polyScale] theorem evalTailUp (t : Int) : @@ -121,15 +121,15 @@ theorem Qexp_eq : (Qexp : Int) = 2 ^ 128 := by unfold Qexp; norm_num theorem Qexp_pos : 0 < Qexp := by unfold Qexp; norm_num -/-- **Never-over cap** at the v-form rational `yUB/wUB = ê_v·(1 + 2⁻¹³¹)`: for every reduced argument +/-- **Never-over cap** at the v-form rational `yUB/wUB = ê_v·(1 + 2⁻¹³²)`: for every reduced argument `t ∈ [0, H128]`, `exp(t/Qexp) ≤ yUB(t)/wUB(t)`. -/ theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : capUB t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := by have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 have hden0 : 0 ≤ evalPoly denExpV t := by omega - have hc120 : (0 : Int) ≤ 2 ^ 131 + 1 := by norm_num - have hp120 : (0 : Int) ≤ 2 ^ 131 := by norm_num + have hc120 : (0 : Int) ≤ 2 ^ 132 + 1 := by norm_num + have hp120 : (0 : Int) ≤ 2 ^ 132 := by norm_num have hyub : 0 ≤ evalPoly yUB t := by rw [evalYUB]; exact Int.mul_nonneg hc120 hnum have hwub : 0 ≤ evalPoly wUB t := by @@ -155,15 +155,15 @@ theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : _ ≤ 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := key _ = evalPoly yUB t * (304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28) := by ring -/-- **Not-two-below cap** at the v-form rational `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`: for every reduced +/-- **Not-two-below cap** at the v-form rational `yLB/wLB = ê_v·(1 − 2⁻¹³²)`: for every reduced argument `t ∈ [0, H128]`, `yLB(t)/wLB(t) ≤ exp(t/Qexp)`. -/ theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : capLB t.toNat Qexp (evalPoly yLB t).toNat (evalPoly wLB t).toNat := by have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 have hden0 : 0 ≤ evalPoly denExpV t := by omega - have hc126 : (0 : Int) ≤ 2 ^ 131 - 1 := by norm_num - have hp126 : (0 : Int) ≤ 2 ^ 131 := by norm_num + have hc126 : (0 : Int) ≤ 2 ^ 132 - 1 := by norm_num + have hp126 : (0 : Int) ≤ 2 ^ 132 := by norm_num have hylb : 0 ≤ evalPoly yLB t := by rw [evalYLB]; exact Int.mul_nonneg hc126 hnum have hwlb : 0 ≤ evalPoly wLB t := by diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean index ed1395035..6a98d5b48 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean @@ -17,15 +17,15 @@ polynomials (different shift-clearing), so this module re-derives the cut agains Here `v = t²` is carried symbolically (each Horner stage multiplies by `t²` via `mulT2`, with the runtime per-stage shift cleared into the per-stage scale): `evNumVPoly` accumulates `Ev` to the -cleared scale `2^1193` and `odNumVPoly` accumulates `Od` to `2^1042`; `t·Od` (lifted by `2^23`) joins -`Ev` at the common `2^1193`. The shared scale cancels in `ê_v = NUM/DEN`. As a polynomial in `t` the +cleared scale `2^1192` and `odNumVPoly` accumulates `Od` to `2^1040`; `t·Od` (lifted by `2^23`) joins +`Ev` at the common `2^1192`. The shared scale cancels in `ê_v = NUM/DEN`. As a polynomial in `t` the numerator/denominator are degree 10. Two certificate shapes are declared: * the Taylor cut, the standard `Common.Exp.capUB_of_partial`/`capLB` shape at depth `K = 27`, - nudging the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹³¹)`, `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`); - the realized envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.019` ulp is inside those margins with 2.3× slack; + nudging the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹³²)`, `yLB/wLB = ê_v·(1 − 2⁻¹³²)`); + the realized envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.0075` ulp is inside those margins with 2.1× slack; * the **denominator floors** over the integer `v`-grid: the parameterized shapes `certDOverP`/`certDUnderP` pin `Ev(v)·2^110 ∓ T·Od(v)` above explicit constants, instantiated once globally (`certDOver`, at the domain edge `T = H128` over all of `[0, vmaxV + 1]`) and once @@ -49,38 +49,38 @@ def H128 : Nat := 117932881612756647068972071382077242199 The even/odd Horner accumulators evaluated as exact polynomials in `t` with `v = t²/2^133`, each runtime per-stage shift cleared into the stage scale. `evNumVPoly` is `evNumV(t²)` cleared so its -evaluation is `Ev·2^1193` (`= evNumV(v)·2^665` at grid points `t² = 2^133·v`); `odNumVPoly` -evaluates to `Od·2^1042` (`= odNumV(v)·2^532` at grid points); `t·Od` (lifted by `2^23` to the -common `2^1193`) joins `Ev`. The shared `2^1193` cancels in `ê_v = NUM/DEN`. -/ +evaluation is `Ev·2^1192` (`= evNumV(v)·2^665` at grid points `t² = 2^133·v`); `odNumVPoly` +evaluates to `Od·2^1040` (`= odNumV(v)·2^532` at grid points); `t·Od` (lifted by `2^23` to the +common `2^1192`) joins `Ev`. The shared `2^1192` cancels in `ê_v = NUM/DEN`. -/ /-- `t²·P` at the polynomial level (one Horner `·v` stage, with the runtime per-stage shift cleared into the per-stage constant scale). -/ def mulT2 (P : List Int) : List Int := 0 :: 0 :: P -/-- The even Horner accumulator `Ev` (evaluation `Ev·2^1193`; `evNumV(v)·2^665` at grid points). +/-- The even Horner accumulator `Ev` (evaluation `Ev·2^1192`; `evNumV(v)·2^665` at grid points). The per-stage constants are the even coefficients `A0..A4` lifted by the cleared stage scale; the innermost monic `v` stage clears to `[A4·2^133, 0, 1]` (A4 is carried at v's own Q123 basis). -/ def evNumVPoly : List Int := - polyAdd [0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193] - (mulT2 (polyAdd [0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933] - (mulT2 (polyAdd [0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671] - (mulT2 (polyAdd [0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415] + polyAdd [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192] + (mulT2 (polyAdd [0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933] + (mulT2 (polyAdd [0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671] + (mulT2 (polyAdd [0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415] (mulT2 [0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133, 0, 1]))))))) -/-- The odd Horner accumulator `Od` (evaluation `Od·2^1042`; `odNumV(v)·2^532` at grid points). -/ +/-- The odd Horner accumulator `Od` (evaluation `Od·2^1040`; `odNumV(v)·2^532` at grid points). -/ def odNumVPoly : List Int := - polyAdd [0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042] - (mulT2 (polyAdd [0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779] - (mulT2 (polyAdd [0xad4506af99be27419341e1816ff351 * 2 ^ 524] - (mulT2 [0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259, 0, 0xdc07aff8276bde9a361278df6a10]))))) + polyAdd [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040] + (mulT2 (polyAdd [0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779] + (mulT2 (polyAdd [0xad4506af99be27419341e181693281 * 2 ^ 524] + (mulT2 [0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259, 0, 0xdc07aff8276bde9a361278df6a10]))))) -/-- `t·Od` lifted to the common scale `2^1193` (`= 2^23 · t · odNumVPoly`). -/ +/-- `t·Od` lifted to the common scale `2^1192` (`= 2^23 · t · odNumVPoly`). -/ def todNumV : List Int := polyScale (2 ^ 23) (0 :: odNumVPoly) -/-- `ê_v`-numerator `NUM(t) = Ev(t) + t·Od(t)` (scale `2^1193`). -/ +/-- `ê_v`-numerator `NUM(t) = Ev(t) + t·Od(t)` (scale `2^1192`). -/ def numExpV : List Int := polyAdd evNumVPoly todNumV -/-- `ê_v`-denominator `DEN(t) = Ev(t) − t·Od(t)` (scale `2^1193`). -/ +/-- `ê_v`-denominator `DEN(t) = Ev(t) − t·Od(t)` (scale `2^1192`). -/ def denExpV : List Int := polySub evNumVPoly todNumV /-! ## Taylor partial-sum numerator at the cut argument -/ @@ -90,14 +90,14 @@ def expN27 : List Int := expPolyNum [0, 1] [(Qexp : Int)] 27 /-! ## Margin-nudged rational targets -`yUB/wUB = ê_v·(1 + 2⁻¹³¹)` and `yLB/wLB = ê_v·(1 − 2⁻¹³¹)`. The tight `2⁻¹³¹` margins keep the -`2¹²⁶·(ê_v − exp)` contribution to the runtime over/under budget below `2¹²⁶·exp·2⁻¹³¹ ≈ 0.045` ulp, -inside the `MARGIN`; the realized envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.019` ulp leaves slack. -/ +`yUB/wUB = ê_v·(1 + 2⁻¹³²)` and `yLB/wLB = ê_v·(1 − 2⁻¹³²)`. The tight `2⁻¹³²` margins keep the +`2¹²⁶·(ê_v − exp)` contribution to the runtime over/under budget below `2¹²⁶·exp·2⁻¹³² ≈ 0.022` ulp, +inside the `MARGIN`; the realized envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.0075` ulp leaves slack. -/ -def yUB : List Int := polyScale (2 ^ 131 + 1) numExpV -def wUB : List Int := polyScale (2 ^ 131) denExpV -def yLB : List Int := polyScale (2 ^ 131 - 1) numExpV -def wLB : List Int := polyScale (2 ^ 131) denExpV +def yUB : List Int := polyScale (2 ^ 132 + 1) numExpV +def wUB : List Int := polyScale (2 ^ 132) denExpV +def yLB : List Int := polyScale (2 ^ 132 - 1) numExpV +def wLB : List Int := polyScale (2 ^ 132) denExpV /-! ## The cut certificate polynomials -/ @@ -132,19 +132,19 @@ def vmaxV : Nat := 1277263193518626341050532535110179582 /-- The even integer Horner polynomial `Ev` in `v` (degree 5, monic, cleared scale `2^528`): coefficient list of `evNumV` (`Floor/R0Bound.lean`). -/ def evVPoly : List Int := - [0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 528, - 0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 401, - 0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 272, - 0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 149, + [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 527, + 0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 401, + 0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 272, + 0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 149, 0xb9aacfacf3c10b378435f8e22adf48500e, 1] /-- The odd integer Horner polynomial `Od` in `v` (degree 4, cleared scale `2^510`). -/ def odVPoly : List Int := - [0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 510, - 0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 380, - 0xad4506af99be27419341e1816ff351 * 2 ^ 258, - 0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 126, + [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 508, + 0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 380, + 0xad4506af99be27419341e181693281 * 2 ^ 258, + 0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 126, 0xdc07aff8276bde9a361278df6a10] /-- Over-half denominator floor shape: `Ev(v)·2^110 − T·Od(v) − D·2^725 ≥ 0`. Nonnegativity over a diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index 1bcc795da..12fcdef17 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -30,7 +30,7 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : ∃ s : Nat, (s : Int) = 108 - int256 (kTree x) ∧ accumReal x = - ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - (2293970250242 : Real)) / + ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - (2209676553221 : Real)) / (2 ^ s : Real) := by obtain ⟨s, hseq, _, _, hsint⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 @@ -40,7 +40,7 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) rw [hseq] -- the integer shift argument has the closed value `WAD·r0 − MARGIN` have hwadc : (0x3782dace9d9 : Int) = 3814697265625 := by norm_num - have hmarc : (0x2161b482a02 : Int) = 2293970250242 := by norm_num + have hmarc : (0x2027afc6c05 : Int) = 2209676553221 := by norm_num rw [hargeq, hwadc, hmarc] push_cast ring diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean index 11445322f..04385335b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean @@ -143,21 +143,21 @@ theorem evalPoly_mono_of_nonneg {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) {a b /-! ## The even/odd polynomials in the square argument `w = t²` -/ -/-- The even Horner polynomial in `w` (degree 5, monic), at the cleared scale `2¹¹⁹³`. -/ +/-- The even Horner polynomial in `w` (degree 5, monic), at the cleared scale `2¹¹⁹²`. -/ def Pev : List Int := - [0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193, - 0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933, - 0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671, - 0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415, + [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192, + 0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933, + 0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671, + 0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415, 0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133, 1] -/-- The odd Horner polynomial in `w` (degree 4), at the cleared scale `2¹⁰⁴²`. -/ +/-- The odd Horner polynomial in `w` (degree 4), at the cleared scale `2¹⁰⁴⁰`. -/ def Pod : List Int := - [0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042, - 0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779, - 0xad4506af99be27419341e1816ff351 * 2 ^ 524, - 0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259, + [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040, + 0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779, + 0xad4506af99be27419341e181693281 * 2 ^ 524, + 0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259, 0xdc07aff8276bde9a361278df6a10] /-- `evNumVPoly(t) = Pev(t²)`: the cert even polynomial is `Pev` composed with squaring. -/ @@ -366,14 +366,14 @@ def KpM (v : Nat) : Int := /-- `K` expanded: degree 8 in `v`, all nine coefficients positive. -/ def Kpoly : List Int := [ - 124314103365382948540818484389625511162300300154596353471434559263576710760858295817293092085008263137731720671247221648067596832296011712645000813284745609572799860614715339074429845004953604219102947508964005670501289338774093304568104691068782792841751722685380505527135804513603544359590666402647994177984765095548996198922954351638285344422494208, - 430693347524554794343417296651509686134557738098954307704214627733020390530278276854672725773269273195478624746887483823521915971792313550530664645765146330112240663991043334744169297019302744406385806086948888789809498977224640089404613426031164334553095878029211115721153838092053743221232923214856740321361920, - 686241798384522667273603851832009005832991722966895305486733489217475120780434741578221376750207665260280559483314421737861160359613911796076366378147384024630930905683143857451910151039919766317250012570559885388869355828462187828089296162106016837843019513341114421608448, - 516930441971039446793370708723350125364637202395800871195912177274842681404775759909985132791355705126258878499764647160096038572134699599657143783480012402118176141075234265877953175422112442922930396729118643533020785802714646839296, - 204444652500469654421705147174126797534284466591134372022748954577461360623715926111412069421315335549677153452480685493529231437120364790325762132070320513045724004787419978918913755181249161744, - 41949223685511975480580776931828146057677792415359815945353299890032432268755601779612364142307888289245407764490095148612742616445009325314635169114466368, - 4316880982720124500406644109788966154643851890842252965238156761257284790660493659638039728545632279862302184602720, - 177702252311948919910468951720184092402653220933754361350350337206870976576, + 124314103365382948540818484389625511203399177432453098518846457498424611868718936788294664267508136808084138787208378562630796118598660218488733713108899806680606730056981253470814633029881113238182689516541100092823765499012530288921867233641123804341166654951569367737662827074930978395230903701562235931446223508713572252330288363487742122325442560, + 430693347524554794343417296651509269546471125888783932883213067852427976792830819506154685161681309308421934362957503263238172463597752166322997479007299450300268826360292259046832109312788166610911298114935367705253725341124202899493244774245413341803253389569796633472510432176301708723695054007939636706410496, + 686241798384522667273603851831993255743976479454734108933770660426843907940620907261663442100255837834877719028054685866583528534712652427934848500737241369416125752426578930665894337646314144065132479326417994932879796724838817164446315062770611047713370345511153441964032, + 516930441971039446793370708722985432068498632768666228915957515544832603080870750486884619259761770023519567422223894490006504385081487220640805923736478421507588209150278363775126877525492198473202648229917180375976504407544406474752, + 204444652500469654421705147173882406799000050958223443836506004238012414689803007858846783088053803154580895166740525311062105616502632116907067400682504133082049679601164456670000760158882327056, + 41949223685511975480580776931803214095183058807997891029056426006309309876979761480785120698138076232828037019511000124510823093705593692832111535106926656, + 4316880982720124500406644109790128668229286147770009636876004160726008360785062858879885810687133295792221148970080, + 177702252311948919910468951720197103269093626476374115210152794580320102464, 4462739169817451478086891138411024] theorem Kpoly_coeffs_nonneg : ∀ c ∈ Kpoly, (0 : Int) ≤ c := by @@ -454,50 +454,50 @@ cross `a^j·b^i − a^i·b^j` is nonnegative on `0 ≤ a ≤ b`. -/ theorem pev_pod_cross {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : 0 ≤ evalPoly Pev b * evalPoly Pod a - evalPoly Pev a * evalPoly Pod b := by have hexpand : evalPoly Pev b * evalPoly Pod a - evalPoly Pev a * evalPoly Pod b = - (((0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) + - (((0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) + - (((0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) + - (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) + - (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) + - (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) + - (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) + - (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) + - (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) + - (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) + - (((1) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) + - (((1) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) + - (((1) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) + - (((1) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) + + (((0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) + + (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xad4506af99be27419341e181693281 * 2 ^ 524) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) + + (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xad4506af99be27419341e181693281 * 2 ^ 524) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) + + (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) + + (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) + + (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) + + (((1) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) + + (((1) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) + + (((1) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) + + (((1) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) + (((1) * (0xdc07aff8276bde9a361278df6a10) - (0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0) : Int)) * (a ^ 4 * b ^ 5 - a ^ 5 * b ^ 4) := by simp only [Pev, Pod, evalPoly] ring - have h10 : (0:Int) ≤ (((0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) := + have h10 : (0:Int) ≤ (((0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 1; simpa using this) - have h20 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) := + have h20 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xad4506af99be27419341e181693281 * 2 ^ 524) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 2; simpa using this) - have h21 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) := + have h21 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xad4506af99be27419341e181693281 * 2 ^ 524) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 1; simpa using this) - have h30 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) := + have h30 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 3; simpa using this) - have h31 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) := + have h31 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 2; simpa using this) - have h32 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) := + have h32 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 1; simpa using this) - have h40 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) := + have h40 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 4; simpa using this) - have h41 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) := + have h41 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 3; simpa using this) - have h42 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) := + have h42 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 2; simpa using this) - have h43 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) := + have h43 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 3 1; simpa using this) - have h50 : (0:Int) ≤ (((1) * (0x270a522f2b285a8374bfa62ed11c30f1 * 2 ^ 1042) - (0x4e14a45e5650b506e97f4c5da23861e2 * 2 ^ 1193) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) := + have h50 : (0:Int) ≤ (((1) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 5; simpa using this) - have h51 : (0:Int) ≤ (((1) * (0xaf566247c05753b42892f77b67a6b7c6 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf809e * 2 ^ 933) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) := + have h51 : (0:Int) ≤ (((1) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 4; simpa using this) - have h52 : (0:Int) ≤ (((1) * (0xad4506af99be27419341e1816ff351 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331c5c3057 * 2 ^ 671) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) := + have h52 : (0:Int) ≤ (((1) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 3; simpa using this) - have h53 : (0:Int) ≤ (((1) * (0xc926ddbecdeeb42e68cd16db7da8c1 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7602053 * 2 ^ 415) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) := + have h53 : (0:Int) ≤ (((1) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 3 2; simpa using this) have h54 : (0:Int) ≤ (((1) * (0xdc07aff8276bde9a361278df6a10) - (0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0) : Int)) * (a ^ 4 * b ^ 5 - a ^ 5 * b ^ 4) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 4 1; simpa using this) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index 4a91611f2..d92060268 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -15,7 +15,7 @@ ingredients of that discharge: * the **Horner-truncation bridge** for the even/odd accumulators — the runtime `evTree x`/`odTree x`, which truncate each Horner `>>` stage, bracket the exact integer polynomials `evNumV (vTree x)` - (degree 5, cleared scale `2^528`) and `odNumV (vTree x)` (degree 4, cleared scale `2^510`): the + (degree 5, cleared scale `2^527`) and `odNumV (vTree x)` (degree 4, cleared scale `2^508`): the monic leading stage is an exact add, and the four lossy stages' floor losses telescope with shrinking amplification (each stage shift exceeds `120 = ⌈log₂ v⌉`), leaving widths `142941343449089·2^480 ≈ 1.0157·2^527` and `269746241·2^480 ≈ 1.0049·2^508`; @@ -171,22 +171,22 @@ The monic leading stage `ev0 = A4 + v` is an exact add (width `1·2^0`); the fou (shifts `0x95, 0x7b, 0x81, 0x7e`, cumulative `149, 272, 401, 527`) telescope the width to `142941343449089·2^480 ≈ 1.0157·2^527`. -/ -/-- Exact integer even-Horner accumulator (degree-5 monic in `v`, cleared scale `2^528`). -/ +/-- Exact integer even-Horner accumulator (degree-5 monic in `v`, cleared scale `2^527`). -/ def evNumV (v : Nat) : Nat := let e0 := 0xb9aacfacf3c10b378435f8e22adf48500e + v - let e1 := 0x9a036222841f47c6ed6fc3f7602053 * 2^149 + e0 * v - let e2 := 0x9064d9657e9a21fc16bb69331c5c3057 * 2^272 + e1 * v - let e3 := 0x93f11e650dd6c64b96ce79065cdf809e * 2^401 + e2 * v - 0x4e14a45e5650b506e97f4c5da23861e2 * 2^528 + e3 * v + let e1 := 0x9a036222841f47c6ed6fc3f7599445 * 2^149 + e0 * v + let e2 := 0x9064d9657e9a21fc16bb69331b81ae1e * 2^272 + e1 * v + let e3 := 0x93f11e650dd6c64b96ce79065cdf80f4 * 2^401 + e2 * v + 0x9c2948bcaca16a0dd2fe98bb4470c388 * 2^527 + e3 * v theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : 2^527 * evTree x ≤ evNumV (vTree x) ∧ evNumV (vTree x) < 2^527 * evTree x + 142941343449089 * 2^480 := by have hev : evTree x = - evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e (vTree x)) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl set v := vTree x with hvdef -- stage 0: the monic add is exact; width 1·2^0 @@ -204,7 +204,7 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : rw [he0eq, pow_zero, one_mul, mul_one] omega -- stage 1: cum 0 -> 149, sh=149; p 0 -> 120; Wnum 1 -> 536870913 - have s1 := horner_stage_frac 0x9a036222841f47c6ed6fc3f7602053 e0 v 0 0x95 0 1 + have s1 := horner_stage_frac 0x9a036222841f47c6ed6fc3f7599445 e0 v 0 0x95 0 1 (0xb9aacfacf3c10b378435f8e22adf48500e + v) hv (by norm_num) (by norm_num) (by have : (0xb9aacfacf3c10b378435f8e22adf48500e : Nat) + 2^120 < 2^256 := by norm_num omega) @@ -214,18 +214,18 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (by norm_num) (by norm_num) hE0lo hE0hi rw [show (0:Nat)+0x95-(0+120) = 29 from by norm_num, show (1:Nat)+2^29 = 536870913 from by norm_num, show (0:Nat)+120 = 120 from by norm_num, show (0:Nat)+0x95 = 149 from by norm_num] at s1 - set e1 := evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul e0 v)) with he1 + set e1 := evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul e0 v)) with he1 have he1lt : e1 < 2^121 := by - have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7602053) (prev := e0) (v := v) + have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7599445) (prev := e0) (v := v) (P := 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) (V := 2 ^ 120) (sh := 0x95) he0lt hv (by norm_num) (by norm_num) (by norm_num)).2 - have hcap : (0x9a036222841f47c6ed6fc3f7602053 : Nat) + + have hcap : (0x9a036222841f47c6ed6fc3f7599445 : Nat) + (0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) * 2 ^ 120 / 2 ^ 0x95 < 2 ^ 121 := by norm_num omega -- stage 2: cum 149 -> 272, sh=123; p 120 -> 240; Wnum 536870913 -> 4831838209 - have s2 := horner_stage_frac 0x9064d9657e9a21fc16bb69331c5c3057 e1 v 149 0x7b 120 536870913 - (0x9a036222841f47c6ed6fc3f7602053 * 2^149 + (0xb9aacfacf3c10b378435f8e22adf48500e + v) * v) + have s2 := horner_stage_frac 0x9064d9657e9a21fc16bb69331b81ae1e e1 v 149 0x7b 120 536870913 + (0x9a036222841f47c6ed6fc3f7599445 * 2^149 + (0xb9aacfacf3c10b378435f8e22adf48500e + v) * v) hv (by norm_num) (by norm_num) (by have : (2:Nat)^121 < 2^256 := by norm_num omega) @@ -235,16 +235,16 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : rw [show (149:Nat)+0x7b-(120+120) = 32 from by norm_num, show (536870913:Nat)+2^32 = 4831838209 from by norm_num, show (120:Nat)+120 = 240 from by norm_num, show (149:Nat)+0x7b = 272 from by norm_num] at s2 - set e2 := evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul e1 v)) with he2 + set e2 := evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul e1 v)) with he2 have he2lt : e2 < 2^129 := by - have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331c5c3057) (prev := e1) (v := v) + have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331b81ae1e) (prev := e1) (v := v) (P := 2^121) (V := 2^120) (sh := 0x7b) he1lt hv (by norm_num) (by norm_num) (by rw [pvd 121 120 123 118 (by norm_num)]; norm_num)).2 rw [pvd 121 120 123 118 (by norm_num)] at this; omega -- stage 3: cum 272 -> 401, sh=129; p 240 -> 360; Wnum 4831838209 -> 2203855093761 - have s3 := horner_stage_frac 0x93f11e650dd6c64b96ce79065cdf809e e2 v 272 0x81 240 4831838209 - (0x9064d9657e9a21fc16bb69331c5c3057 * 2^272 + - (0x9a036222841f47c6ed6fc3f7602053 * 2^149 + (0xb9aacfacf3c10b378435f8e22adf48500e + v) * v) * v) + have s3 := horner_stage_frac 0x93f11e650dd6c64b96ce79065cdf80f4 e2 v 272 0x81 240 4831838209 + (0x9064d9657e9a21fc16bb69331b81ae1e * 2^272 + + (0x9a036222841f47c6ed6fc3f7599445 * 2^149 + (0xb9aacfacf3c10b378435f8e22adf48500e + v) * v) * v) hv (by norm_num) (by norm_num) (by have : (2:Nat)^129 < 2^256 := by norm_num omega) @@ -254,17 +254,17 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : rw [show (272:Nat)+0x81-(240+120) = 41 from by norm_num, show (4831838209:Nat)+2^41 = 2203855093761 from by norm_num, show (240:Nat)+120 = 360 from by norm_num, show (272:Nat)+0x81 = 401 from by norm_num] at s3 - set e3 := evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul e2 v)) with he3 + set e3 := evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul e2 v)) with he3 have he3lt : e3 < 2^129 := by - have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf809e) (prev := e2) (v := v) + have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf80f4) (prev := e2) (v := v) (P := 2^129) (V := 2^120) (sh := 0x81) he2lt hv (by norm_num) (by norm_num) (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 rw [pvd 129 120 129 120 (by norm_num)] at this; omega -- stage 4: cum 401 -> 527, sh=126; p 360 -> 480; Wnum 2203855093761 -> 142941343449089 - have s4 := horner_stage_frac 0x9c2948bcaca16a0dd2fe98bb4470c3c4 e3 v 401 0x7e 360 2203855093761 - (0x93f11e650dd6c64b96ce79065cdf809e * 2^401 + - (0x9064d9657e9a21fc16bb69331c5c3057 * 2^272 + - (0x9a036222841f47c6ed6fc3f7602053 * 2^149 + + have s4 := horner_stage_frac 0x9c2948bcaca16a0dd2fe98bb4470c388 e3 v 401 0x7e 360 2203855093761 + (0x93f11e650dd6c64b96ce79065cdf80f4 * 2^401 + + (0x9064d9657e9a21fc16bb69331b81ae1e * 2^272 + + (0x9a036222841f47c6ed6fc3f7599445 * 2^149 + (0xb9aacfacf3c10b378435f8e22adf48500e + v) * v) * v) * v) hv (by norm_num) (by norm_num) (by have : (2:Nat)^129 < 2^256 := by norm_num @@ -277,8 +277,8 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : show (360:Nat)+120 = 480 from by norm_num, show (401:Nat)+0x7e = 527 from by norm_num] at s4 -- assemble: evTree x = e4 (the stage-4 value), evNumV v = the cumulative E4. rw [hev] - show 2^527 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul e3 v)) ≤ evNumV v ∧ - evNumV v < 2^527 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul e3 v)) + + show 2^527 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul e3 v)) ≤ evNumV v ∧ + evNumV v < 2^527 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul e3 v)) + 142941343449089 * 2^480 unfold evNumV constructor @@ -298,21 +298,21 @@ The odd accumulator starts at the exact leading constant `B4` (scale `0`) and ru stages (shifts `0x7e, 0x84, 0x7a, 0x80`, cumulative `126, 258, 380, 508`), telescoping the width to `269746241·2^480 ≈ 1.0049·2^508`. -/ -/-- Exact integer odd-Horner accumulator (degree-4 in `v`, cleared scale `2^510`). -/ +/-- Exact integer odd-Horner accumulator (degree-4 in `v`, cleared scale `2^508`). -/ def odNumV (v : Nat) : Nat := - let o1 := 0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v - let o2 := 0xad4506af99be27419341e1816ff351 * 2^258 + o1 * v - let o3 := 0xaf566247c05753b42892f77b67a6b7c6 * 2^380 + o2 * v - 0x270a522f2b285a8374bfa62ed11c30f1 * 2^510 + o3 * v + let o1 := 0xc926ddbecdeeb42e68cd16db7ed378 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v + let o2 := 0xad4506af99be27419341e181693281 * 2^258 + o1 * v + let o3 := 0xaf566247c05753b42892f77b67a6b7c7 * 2^380 + o2 * v + 0x9c2948bcaca16a0dd2fe98bb4470c388 * 2^508 + o3 * v theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : 2^508 * odTree x ≤ odNumV (vTree x) ∧ odNumV (vTree x) < 2^508 * odTree x + 269746241 * 2^480 := by have hod : odTree x = - evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl set v := vTree x with hvdef -- the leading constant is exact; track it as width 1·2^0 (B4 < B4 + 1) @@ -320,7 +320,7 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : have hB4hi : (0xdc07aff8276bde9a361278df6a10 : Nat) < 2^0 * 0xdc07aff8276bde9a361278df6a10 + 1 * 2^0 := by norm_num -- stage 1: cum 0 -> 126, sh=126; p 0 -> 120; Wnum 1 -> 65 - have s1 := horner_stage_frac 0xc926ddbecdeeb42e68cd16db7da8c1 + have s1 := horner_stage_frac 0xc926ddbecdeeb42e68cd16db7ed378 0xdc07aff8276bde9a361278df6a10 v 0 0x7e 0 1 0xdc07aff8276bde9a361278df6a10 hv (by norm_num) (by norm_num) (by norm_num) (by calc (0xdc07aff8276bde9a361278df6a10 : Nat) * v < 2^112 * 2^120 := @@ -329,17 +329,17 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (by norm_num) (by norm_num) hB4lo hB4hi rw [show (0:Nat)+0x7e-(0+120) = 6 from by norm_num, show (1:Nat)+2^6 = 65 from by norm_num, show (0:Nat)+120 = 120 from by norm_num, show (0:Nat)+0x7e = 126 from by norm_num] at s1 - set o1 := evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 + set o1 := evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v)) with ho1 have ho1lt : o1 < 2^121 := by - have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7da8c1) + have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7ed378) (prev := 0xdc07aff8276bde9a361278df6a10) (v := v) (P := 2^112) (V := 2^120) (sh := 0x7e) (by norm_num) hv (by norm_num) (by norm_num) (by rw [pvd 112 120 126 106 (by norm_num)]; norm_num)).2 rw [pvd 112 120 126 106 (by norm_num)] at this; omega -- stage 2: cum 126 -> 258, sh=132; p 120 -> 240; Wnum 65 -> 262209 - have s2 := horner_stage_frac 0xad4506af99be27419341e1816ff351 o1 v 126 0x84 120 65 - (0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) hv + have s2 := horner_stage_frac 0xad4506af99be27419341e181693281 o1 v 126 0x84 120 65 + (0xc926ddbecdeeb42e68cd16db7ed378 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) hv (by norm_num) (by norm_num) (by have : (2:Nat)^121 < 2^256 := by norm_num omega) @@ -348,16 +348,16 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (by norm_num) (by norm_num) s1.1 s1.2 rw [show (126:Nat)+0x84-(120+120) = 18 from by norm_num, show (65:Nat)+2^18 = 262209 from by norm_num, show (120:Nat)+120 = 240 from by norm_num, show (126:Nat)+0x84 = 258 from by norm_num] at s2 - set o2 := evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul o1 v)) with ho2 + set o2 := evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul o1 v)) with ho2 have ho2lt : o2 < 2^121 := by - have := (stage_bounds (c := 0xad4506af99be27419341e1816ff351) (prev := o1) (v := v) + have := (stage_bounds (c := 0xad4506af99be27419341e181693281) (prev := o1) (v := v) (P := 2^121) (V := 2^120) (sh := 0x84) ho1lt hv (by norm_num) (by norm_num) (by rw [pvd 121 120 132 109 (by norm_num)]; norm_num)).2 rw [pvd 121 120 132 109 (by norm_num)] at this; omega -- stage 3: cum 258 -> 380, sh=122; p 240 -> 360; Wnum 262209 -> 1310785 - have s3 := horner_stage_frac 0xaf566247c05753b42892f77b67a6b7c6 o2 v 258 0x7a 240 262209 - (0xad4506af99be27419341e1816ff351 * 2^258 + - (0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) * v) hv + have s3 := horner_stage_frac 0xaf566247c05753b42892f77b67a6b7c7 o2 v 258 0x7a 240 262209 + (0xad4506af99be27419341e181693281 * 2^258 + + (0xc926ddbecdeeb42e68cd16db7ed378 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) * v) hv (by norm_num) (by norm_num) (by have : (2:Nat)^121 < 2^256 := by norm_num omega) @@ -367,17 +367,17 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : rw [show (258:Nat)+0x7a-(240+120) = 20 from by norm_num, show (262209:Nat)+2^20 = 1310785 from by norm_num, show (240:Nat)+120 = 360 from by norm_num, show (258:Nat)+0x7a = 380 from by norm_num] at s3 - set o3 := evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul o2 v)) with ho3 + set o3 := evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul o2 v)) with ho3 have ho3lt : o3 < 2^129 := by - have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c6) (prev := o2) (v := v) + have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c7) (prev := o2) (v := v) (P := 2^121) (V := 2^120) (sh := 0x7a) ho2lt hv (by norm_num) (by norm_num) (by rw [pvd 121 120 122 119 (by norm_num)]; norm_num)).2 rw [pvd 121 120 122 119 (by norm_num)] at this; omega -- stage 4: cum 380 -> 508, sh=128; p 360 -> 480; Wnum 1310785 -> 269746241 - have s4 := horner_stage_frac 0x9c2948bcaca16a0dd2fe98bb4470c3c4 o3 v 380 0x80 360 1310785 - (0xaf566247c05753b42892f77b67a6b7c6 * 2^380 + - (0xad4506af99be27419341e1816ff351 * 2^258 + - (0xc926ddbecdeeb42e68cd16db7da8c1 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) * v) * v) hv + have s4 := horner_stage_frac 0x9c2948bcaca16a0dd2fe98bb4470c388 o3 v 380 0x80 360 1310785 + (0xaf566247c05753b42892f77b67a6b7c7 * 2^380 + + (0xad4506af99be27419341e181693281 * 2^258 + + (0xc926ddbecdeeb42e68cd16db7ed378 * 2^126 + 0xdc07aff8276bde9a361278df6a10 * v) * v) * v) hv (by norm_num) (by norm_num) (by have : (2:Nat)^129 < 2^256 := by norm_num omega) @@ -388,8 +388,8 @@ theorem odTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : show (1310785:Nat)+2^28 = 269746241 from by norm_num, show (360:Nat)+120 = 480 from by norm_num, show (380:Nat)+0x80 = 508 from by norm_num] at s4 rw [hod] - show 2^508 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul o3 v)) ≤ odNumV v ∧ - odNumV v < 2^508 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul o3 v)) + + show 2^508 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul o3 v)) ≤ odNumV v ∧ + odNumV v < 2^508 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul o3 v)) + 269746241 * 2^480 unfold odNumV constructor diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index 249be87eb..2701625b4 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -11,7 +11,7 @@ below-clamp bound (`belowC_target_lt_one`) establish the never-over and deficit- about the real pre-floor accumulator unconditionally and axiom-clean, via the octave fold `E·2^s = WAD·2¹⁰⁸·exp(rt)` (`WAD = 5¹⁸`; `s = 108 − k`, the closing shift; `k ≤ 63` so `s ≥ 45`). -* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 6013505372794194988/10000000000000000000` and `5¹⁸·6013505372794194988/10000000000000000000 ≤ MARGIN`; +* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 5792534503673398887/10000000000000000000` and `5¹⁸·5792534503673398887/10000000000000000000 ≤ MARGIN`; * `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 31/10` and `(31/10)·5¹⁸ + MARGIN < 2⁴⁵ ≤ 2^s`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. @@ -38,12 +38,12 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt -- WAD·r0 − MARGIN ≤ 5^18·2^126·Ert = E·2^s - have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242 ≤ + have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 6013505372794194988 / 10000000000000000000 := hover + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 5792534503673398887 / 10000000000000000000 := hover have hscaled : (3814697265625 : Real) * (int256 (r0Tree x) : Real) ≤ - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 6013505372794194988 / 10000000000000000000) := + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 5792534503673398887 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] @@ -53,9 +53,9 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 norm_num] ring rw [hconst] - -- 5^18·B = 3833775901374.02… ≤ 2293970250242 = MARGIN - have hBM : (3814697265625 : Real) * (6013505372794194988 / 10000000000000000000) ≤ - 2293970250242 := by norm_num + -- 5^18·B = 3833775901374.02… ≤ 2209676553221 = MARGIN + have hBM : (3814697265625 : Real) * (5792534503673398887 / 10000000000000000000) ≤ + 2209676553221 := by norm_num linarith [hscaled, hBM] rw [hAeq, div_le_iff₀ hps]; linarith [hbound] @@ -71,7 +71,7 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 set Ert := Real.exp (reducedArg x) with hErt -- E·2^s = 5^18·2^126·Ert < WAD·r0 − MARGIN + 2^s have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242) + (2 ^ s : Real) := by + ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221) + (2 ^ s : Real) := by rw [hfold] have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 31 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num @@ -89,14 +89,14 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 31 / 10) := mul_le_mul_of_nonneg_left hr0R (by norm_num) -- (31/10)·5^18 + MARGIN < 2^45 - have hbudget : (3814697265625 : Real) * (31 / 10) + 2293970250242 < (2 ^ 45 : Real) := by + have hbudget : (3814697265625 : Real) * (31 / 10) + 2209676553221 < (2 ^ 45 : Real) := by norm_num linarith [hscaled, hbudget, hpow] -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s rw [hAeq] - have hdiv : ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242) / + have hdiv : ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221) / (2 ^ s : Real) + 1 = - (((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242) + (2 ^ s : Real)) / + (((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp rw [hdiv, lt_div_iff₀ hps]; linarith [hbound] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 82afd0b6b..240e4bb2a 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -18,12 +18,12 @@ This module bounds the Q126 quotient `r0Tree x` above by `2¹²⁶·exp(rt)` plu `≤ 2170557036555806152/10¹⁹`; 2. **`ê(v)` vs `ê(t²)`** — the argument-granularity link (`Floor.GranV`): one `v`-grid grain, `≤ 3290521163436398582/10¹⁹` on this half (the 32-piece certified envelope); -3. **`ê(t²)` vs `exp(t/2¹²⁸)`** — the `2⁻¹³¹`-nudged Taylor cut (`Floor.CapsV`), the `Mp` factor - `≤ 441941738241592203/10¹⁹`; +3. **`ê(t²)` vs `exp(t/2¹²⁸)`** — the `2⁻¹³²`-nudged Taylor cut (`Floor.CapsV`), the `Mp` factor + `≤ 220970869120796102/10¹⁹`; 4. **`exp(t/2¹²⁸)` vs `exp(rt)`** — the reduced-argument gap (`Floor.Reduce`), `≤ 110485434560398051/10¹⁹`. -The total is the budget `B = 6013505372794194988/10¹⁹`; `MARGIN = ⌊5¹⁸·B⌋ + 1`. On the `t ≤ 0` +The total is the budget `B = 5792534503673398887/10¹⁹`; `MARGIN = ⌊5¹⁸·B⌋ + 1`. On the `t ≤ 0` half link 2 is free (the grain moves `ê` the other way) and links 3–4 shrink (`ê ≤ 1`), so the same `B` covers both halves. -/ @@ -162,13 +162,13 @@ theorem todTree_small {x : Nat} (hx : x < 2 ^ 256) /-- `den_rt = ev − tod ≥ 1.94·2¹²⁶` on the region (the even accumulator dominates `|tod|`). -/ theorem den_ge_194 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (165038630930342071346895739193146786756 : Int) ≤ + (165038630930342071346895739193146786696 : Int) ≤ (evTree x : Int) - int256 (todTree x) := by obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 obtain ⟨_, htod_hi⟩ := todTree_small hx hC hC0 - have hev : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + have hev : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo have ht125 : int256 (todTree x) < 2 ^ 125 := htod_hi - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 from by norm_num] at hev + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 from by norm_num] at hev rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 omega @@ -181,7 +181,7 @@ theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - have hden072 : (165038630930342071346895739193146786756 : Int) ≤ ev - tod := by + have hden072 : (165038630930342071346895739193146786696 : Int) ≤ ev - tod := by have := den_ge_194 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 have htodnp : tod ≤ 0 := by @@ -436,7 +436,7 @@ theorem NUMv_ge_num {x : Nat} (hx : x < 2 ^ 256) /-! ## The cert `Real.exp` bounds at the runtime reduced argument -Instantiating the v-form Taylor caps (`ExpCertV.capExpUp`/`capExpLo`, `2⁻¹³¹` nudge) at +Instantiating the v-form Taylor caps (`ExpCertV.capExpUp`/`capExpLo`, `2⁻¹³²` nudge) at `t = int256 (tTree x)` and pushing through the abstract `Common.RealExpBridge` brackets `Real.exp(t/2¹²⁸)` by the margin-nudged rational `ê = NE/DE`. -/ @@ -444,10 +444,10 @@ open ExpRealSpec Real Common.RealExpBridge Common.Exp noncomputable section -/-- **Never-over cert real bound (nonneg half).** `(2¹³¹−1)·NE / (2¹³¹·DE) ≤ exp(t/2¹²⁸)`. -/ +/-- **Never-over cert real bound (nonneg half).** `(2¹³²−1)·NE / (2¹³²·DE) ≤ exp(t/2¹²⁸)`. -/ theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : - ((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ + ((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) := by have hcap := ExpCertV.capExpLo h1 h2 have hwpos : 0 < (evalPoly ExpCertV.wLB t).toNat := by @@ -471,24 +471,24 @@ theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) have := htn; exact_mod_cast this exact this rw [harg] at h - have hynr : ((evalPoly ExpCertV.yLB t).toNat : Real) = ((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by - have : ((evalPoly ExpCertV.yLB t).toNat : Int) = (2 ^ 131 - 1) * evalPoly ExpCertV.numExpV t := by + have hynr : ((evalPoly ExpCertV.yLB t).toNat : Real) = ((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by + have : ((evalPoly ExpCertV.yLB t).toNat : Int) = (2 ^ 132 - 1) * evalPoly ExpCertV.numExpV t := by rw [hyn, ExpCertV.evalYLB] have := congrArg (fun z : Int => (z : Real)) this push_cast at this ⊢; linarith [this] - have hwnr : ((evalPoly ExpCertV.wLB t).toNat : Real) = ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by - have : ((evalPoly ExpCertV.wLB t).toNat : Int) = 2 ^ 131 * evalPoly ExpCertV.denExpV t := by + have hwnr : ((evalPoly ExpCertV.wLB t).toNat : Real) = ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by + have : ((evalPoly ExpCertV.wLB t).toNat : Int) = 2 ^ 132 * evalPoly ExpCertV.denExpV t := by rw [hwn, ExpCertV.evalWLB] have := congrArg (fun z : Int => (z : Real)) this push_cast at this ⊢; linarith [this] rw [hynr, hwnr] at h exact h -/-- **Not-two-below cert real bound (nonneg half).** `exp(t/2¹²⁸) ≤ (2¹³¹+1)·NE / (2¹³¹·DE)`. -/ +/-- **Not-two-below cert real bound (nonneg half).** `exp(t/2¹²⁸) ≤ (2¹³²+1)·NE / (2¹³²·DE)`. -/ theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ - ((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + ((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by have hcap := ExpCertV.capExpUp h1 h2 have hwpos : 0 < (evalPoly ExpCertV.wUB t).toNat := by have hpos : 0 < evalPoly ExpCertV.wUB t := by @@ -511,13 +511,13 @@ theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) have := htn; exact_mod_cast this exact this rw [harg] at h - have hynr : ((evalPoly ExpCertV.yUB t).toNat : Real) = ((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by - have : ((evalPoly ExpCertV.yUB t).toNat : Int) = (2 ^ 131 + 1) * evalPoly ExpCertV.numExpV t := by + have hynr : ((evalPoly ExpCertV.yUB t).toNat : Real) = ((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) := by + have : ((evalPoly ExpCertV.yUB t).toNat : Int) = (2 ^ 132 + 1) * evalPoly ExpCertV.numExpV t := by rw [hyn, ExpCertV.evalYUB] have := congrArg (fun z : Int => (z : Real)) this push_cast at this ⊢; linarith [this] - have hwnr : ((evalPoly ExpCertV.wUB t).toNat : Real) = ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by - have : ((evalPoly ExpCertV.wUB t).toNat : Int) = 2 ^ 131 * evalPoly ExpCertV.denExpV t := by + have hwnr : ((evalPoly ExpCertV.wUB t).toNat : Real) = ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) := by + have : ((evalPoly ExpCertV.wUB t).toNat : Int) = 2 ^ 132 * evalPoly ExpCertV.denExpV t := by rw [hwn, ExpCertV.evalWUB] have := congrArg (fun z : Int => (z : Real)) this push_cast at this ⊢; linarith [this] @@ -525,11 +525,11 @@ theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) exact h /-- **Not-too-below cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: -`exp(t/2¹²⁸) ≤ (2¹³¹·NE) / ((2¹³¹−1)·DE)`. -/ +`exp(t/2¹²⁸) ≤ (2¹³²·NE) / ((2¹³²−1)·DE)`. -/ theorem certUp_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ - ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by have hnt : 0 ≤ -t := by omega have hcl := certLo_real hnt h2 rw [numExpV_neg_eq_denExpV, denExpV_neg_eq_numExpV] at hcl @@ -542,21 +542,21 @@ theorem certUp_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : push_cast; ring, Real.exp_neg] rw [hexpneg] at hcl have hexppos := Real.exp_pos ((t : Real) / (2 ^ 128 : Real)) - have hlhs_pos : (0:Real) < ((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / - (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity + have hlhs_pos : (0:Real) < ((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity rw [le_inv_comm₀ hlhs_pos hexppos] at hcl calc Real.exp ((t : Real) / (2 ^ 128 : Real)) - ≤ (((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / - (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := hcl - _ = ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by + ≤ (((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := hcl + _ = ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by rw [inv_div] /-- **Never-over cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: -`(2¹³¹·NE) / ((2¹³¹+1)·DE) ≤ exp(t/2¹²⁸)`. -/ +`(2¹³²·NE) / ((2¹³²+1)·DE) ≤ exp(t/2¹²⁸)`. -/ theorem certLo_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : - ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ + ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) := by have hnt : 0 ≤ -t := by omega have hcu := certUp_real hnt h2 @@ -570,13 +570,13 @@ theorem certLo_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : push_cast; ring, Real.exp_neg] rw [hexpneg] at hcu have hexppos := Real.exp_pos ((t : Real) / (2 ^ 128 : Real)) - have hrhs_pos : (0:Real) < ((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / - (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity + have hrhs_pos : (0:Real) < ((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity rw [inv_le_comm₀ hexppos hrhs_pos] at hcu - calc ((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) - = (((2 ^ 131 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / - (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := by + calc ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) + = (((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / + (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := by rw [inv_div] _ ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) := hcu @@ -685,26 +685,26 @@ theorem Qv_le_14145 {x : Nat} (hx : x < 2 ^ 256) have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 rw [← hEtdef] at hEtsqrt2 have hNEDE_le : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ - Et * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) := by - have hc : ((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ Et := hcertlo + Et * ((2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1)) := by + have hc : ((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ Et := hcertlo have key : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) = - ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * - (((2 ^ 131 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / - (((2 ^ 131 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real))) := by + ((2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1)) * + (((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / + (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real))) := by push_cast; field_simp; ring rw [key, mul_comm Et _] exact mul_le_mul_of_nonneg_left hc (by positivity) have hsqrt2_val : Real.sqrt 2 ≤ 14143 / 10000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num - have hMp_le : ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) ≤ 14144 / 14143 := by + have hMp_le : ((2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1)) ≤ 14144 / 14143 := by rw [div_le_div_iff₀ (by norm_num) (by norm_num)] - have h131 : (14144 : Real) ≤ 2 ^ 131 := by norm_num + have h131 : (14144 : Real) ≤ 2 ^ 132 := by norm_num nlinarith [h131] have hNEDE14144 : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ 14144 / 10000 := by have hEtnn : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) - have h1 : Et * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) ≤ + have h1 : Et * ((2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1)) ≤ (14143 / 10000) * (14144 / 14143) := by apply mul_le_mul (le_trans hEtsqrt2 hsqrt2_val) hMp_le (by positivity) (by norm_num) have h2 : (14143 / 10000 : Real) * (14144 / 14143) = 14144 / 10000 := by norm_num @@ -826,12 +826,12 @@ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) linarith [h] obtain ⟨hDEN_ge, _⟩ := DENv_runtime_bracket hx hC hC0 htnn have hden := den_ge_194 hx hC hC0 - have hDENlow : (2:Int) ^ 637 * (165038630930342071346895739193146786756 - 2) ≤ DENv v t := by - have : (2:Int) ^ 637 * (165038630930342071346895739193146786756 - 2) ≤ + have hDENlow : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ DENv v t := by + have : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 637 := by nlinarith [hden] linarith [this, hDEN_ge] - have hDENlowR : ((2:Real) ^ 637 * (165038630930342071346895739193146786756 - 2)) ≤ + have hDENlowR : ((2:Real) ^ 637 * (165038630930342071346895739193146786696 - 2)) ≤ (DENv v t : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDENlow push_cast at h @@ -841,23 +841,23 @@ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) mul_le_mul_of_nonneg_left hcapR (by positivity) have hbudget : (142941343449089 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) ≤ (2170557036555806152 / 10000000000000000000) * - ((2:Real) ^ 637 * (165038630930342071346895739193146786756 - 2)) := by + ((2:Real) ^ 637 * (165038630930342071346895739193146786696 - 2)) := by norm_num calc (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ (142941343449089 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := hnum_le _ ≤ (2170557036555806152 / 10000000000000000000) * - ((2:Real) ^ 637 * (165038630930342071346895739193146786756 - 2)) := hbudget + ((2:Real) ^ 637 * (165038630930342071346895739193146786696 - 2)) := hbudget _ ≤ (2170557036555806152 / 10000000000000000000) * (DENv v t : Real) := mul_le_mul_of_nonneg_left hDENlowR (by norm_num) /-- **The per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + B` with the four-link budget -`B = 6013505372794194988/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3291…`, the `Mp` -factor `≤ √2·2¹²⁶/(2¹³¹−1) ≤ 0.0442…`, and the reduced-argument gap `≤ √2/128 ≤ 0.0111…`. -/ +`B = 5792534503673398887/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3291…`, the `Mp` +factor `≤ √2·2¹²⁶/(2¹³²−1) ≤ 0.0442…`, and the reduced-argument gap `≤ √2/128 ≤ 0.0111…`. -/ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 6013505372794194988 / 10000000000000000000 := by + 5792534503673398887 / 10000000000000000000 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -900,32 +900,32 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef - set Mp : Real := (2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1) with hMpdef + set Mp : Real := (2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1) with hMpdef have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 rw [← hEtdef] at hEtsqrt2 have hEtnn : (0 : Real) ≤ Et := le_of_lt (Real.exp_pos _) have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mp := by - have hc : ((2 ^ 131 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 131 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + have hc : ((2 ^ 132 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 132 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo rw [hMpdef] have key : (NE : Real) / (DE : Real) = - ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * - (((2 ^ 131 - 1 : Int) : Real) * (NE : Real) / - (((2 ^ 131 : Int) : Real) * (DE : Real))) := by + ((2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1)) * + (((2 ^ 132 - 1 : Int) : Real) * (NE : Real) / + (((2 ^ 132 : Int) : Real) * (DE : Real))) := by push_cast; field_simp; ring rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) have hsqrt2_hi : Real.sqrt 2 ≤ 141421356237309504880168872421 / 100000000000000000000000000000 := by rw [Real.sqrt_le_iff]; constructor <;> norm_num have hsqrt2_nn : (0:Real) ≤ Real.sqrt 2 := Real.sqrt_nonneg _ - have hMp1 : Mp - 1 = 1 / ((2 ^ 131 : Real) - 1) := by rw [hMpdef]; field_simp - have hcMp : (2 ^ 126 : Real) * Et * (Mp - 1) ≤ 441941738241592203 / 10000000000000000000 := by + have hMp1 : Mp - 1 = 1 / ((2 ^ 132 : Real) - 1) := by rw [hMpdef]; field_simp + have hcMp : (2 ^ 126 : Real) * Et * (Mp - 1) ≤ 220970869120796102 / 10000000000000000000 := by rw [hMp1] - have hb : (2 ^ 126 : Real) * Et * (1 / ((2 ^ 131 : Real) - 1)) ≤ - (2 ^ 126 : Real) * Real.sqrt 2 * (1 / ((2 ^ 131 : Real) - 1)) := by + have hb : (2 ^ 126 : Real) * Et * (1 / ((2 ^ 132 : Real) - 1)) ≤ + (2 ^ 126 : Real) * Real.sqrt 2 * (1 / ((2 ^ 132 : Real) - 1)) := by apply mul_le_mul_of_nonneg_right _ (by positivity) exact mul_le_mul_of_nonneg_left hEtsqrt2 (by positivity) - have hn : (2 ^ 126 : Real) * Real.sqrt 2 * (1 / ((2 ^ 131 : Real) - 1)) ≤ - 441941738241592203 / 10000000000000000000 := by + have hn : (2 ^ 126 : Real) * Real.sqrt 2 * (1 / ((2 ^ 132 : Real) - 1)) ≤ + 220970869120796102 / 10000000000000000000 := by rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] nlinarith [hsqrt2_hi, hsqrt2_nn] linarith [hb, hn] @@ -961,15 +961,15 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) _ ≤ ((2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 3290521163436398582 / 10000000000000000000) + 2170557036555806152 / 10000000000000000000 := by linarith [hgran] - _ ≤ (((2 ^ 126 : Real) * Et + 441941738241592203 / 10000000000000000000) + + _ ≤ (((2 ^ 126 : Real) * Et + 220970869120796102 / 10000000000000000000) + 3290521163436398582 / 10000000000000000000) + 2170557036555806152 / 10000000000000000000 := by linarith [hNEMp, hcMp] _ ≤ ((((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + - 441941738241592203 / 10000000000000000000) + + 220970869120796102 / 10000000000000000000) + 3290521163436398582 / 10000000000000000000) + 2170557036555806152 / 10000000000000000000 := by linarith [hEtErt] _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 6013505372794194988 / 10000000000000000000 := by rw [hErtdef]; ring + 5792534503673398887 / 10000000000000000000 := by rw [hErtdef]; ring /-! ## The per-point never-over (nonpositive half) -/ @@ -989,12 +989,12 @@ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hev : (207573926795459379279817565122117813188 : Int) ≤ (evTree x : Int) := by - have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 from by norm_num] at this + have hev : (207573926795459379279817565122117813128 : Int) ≤ (evTree x : Int) := by + have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 from by norm_num] at this exact this - have hDEN_low : (2:Int) ^ 637 * 207573926795459379279817565122117813188 ≤ DENv v t := by - have : (2:Int) ^ 637 * 207573926795459379279817565122117813188 ≤ 2 ^ 637 * (evTree x : Int) := + have hDEN_low : (2:Int) ^ 637 * 207573926795459379279817565122117813128 ≤ DENv v t := by + have : (2:Int) ^ 637 * 207573926795459379279817565122117813128 ≤ 2 ^ 637 * (evTree x : Int) := mul_le_mul_of_nonneg_left hev (by positivity) linarith [this, hDEN_ge] have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hDEN_low @@ -1025,19 +1025,19 @@ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 := mul_le_mul_of_nonneg_left hntH (by positivity) exact mul_le_mul h1 hr0pH hr0pR (by positivity) - have hDENlowR : ((2:Real) ^ 637 * 207573926795459379279817565122117813188) ≤ (DENv v t : Real) := by + have hDENlowR : ((2:Real) ^ 637 * 207573926795459379279817565122117813128) ≤ (DENv v t : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDEN_low push_cast at h linarith [h] have hbudget : (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) ≤ (2170557036555806152 / 10000000000000000000) * - ((2:Real) ^ 637 * 207573926795459379279817565122117813188) := by + ((2:Real) ^ 637 * 207573926795459379279817565122117813128) := by norm_num calc (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) ≤ (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := hnum_le _ ≤ (2170557036555806152 / 10000000000000000000) * - ((2:Real) ^ 637 * 207573926795459379279817565122117813188) := hbudget + ((2:Real) ^ 637 * 207573926795459379279817565122117813128) := hbudget _ ≤ (2170557036555806152 / 10000000000000000000) * (DENv v t : Real) := mul_le_mul_of_nonneg_left hDENlowR (by norm_num) @@ -1047,7 +1047,7 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 6013505372794194988 / 10000000000000000000 := by + 5792534503673398887 / 10000000000000000000 := by have htdom := tdom_neg hx hC hC0 htneg have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -1078,15 +1078,15 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef2 - set Mpp : Real := ((2 ^ 131 : Real) + 1) / (2 ^ 131 : Real) with hMppdef + set Mpp : Real := ((2 ^ 132 : Real) + 1) / (2 ^ 132 : Real) with hMppdef have hNEDE_le : (NE : Real) / (DE : Real) ≤ Et * Mpp := by - have hc : ((2 ^ 131 : Int) : Real) * (NE : Real) / - (((2 ^ 131 + 1 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo + have hc : ((2 ^ 132 : Int) : Real) * (NE : Real) / + (((2 ^ 132 + 1 : Int) : Real) * (DE : Real)) ≤ Et := hcertlo rw [hMppdef] have key : (NE : Real) / (DE : Real) = - (((2 ^ 131 : Real) + 1) / (2 ^ 131 : Real)) * - (((2 ^ 131 : Int) : Real) * (NE : Real) / - (((2 ^ 131 + 1 : Int) : Real) * (DE : Real))) := by + (((2 ^ 132 : Real) + 1) / (2 ^ 132 : Real)) * + (((2 ^ 132 : Int) : Real) * (NE : Real) / + (((2 ^ 132 + 1 : Int) : Real) * (DE : Real))) := by push_cast; field_simp; ring rw [key, mul_comm Et _]; exact mul_le_mul_of_nonneg_left hc (by positivity) have hEt_le_one : Et ≤ 1 := by @@ -1095,15 +1095,15 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) have htR : (t : Real) ≤ 0 := by exact_mod_cast htneg apply div_nonpos_of_nonpos_of_nonneg htR (by positivity) have hEtnn : (0:Real) ≤ Et := le_of_lt (Real.exp_pos _) - have hMpp1 : Mpp - 1 = 1 / (2 ^ 131 : Real) := by rw [hMppdef]; field_simp - have hcMp : (2 ^ 126 : Real) * Et * (Mpp - 1) ≤ 441941738241592203 / 10000000000000000000 := by + have hMpp1 : Mpp - 1 = 1 / (2 ^ 132 : Real) := by rw [hMppdef]; field_simp + have hcMp : (2 ^ 126 : Real) * Et * (Mpp - 1) ≤ 220970869120796102 / 10000000000000000000 := by rw [hMpp1] - have h1 : (2 ^ 126 : Real) * Et * (1 / (2 ^ 131 : Real)) ≤ - (2 ^ 126 : Real) * 1 * (1 / (2 ^ 131 : Real)) := by + have h1 : (2 ^ 126 : Real) * Et * (1 / (2 ^ 132 : Real)) ≤ + (2 ^ 126 : Real) * 1 * (1 / (2 ^ 132 : Real)) := by apply mul_le_mul_of_nonneg_right _ (by positivity) exact mul_le_mul_of_nonneg_left hEt_le_one (by positivity) - have hn : (2 ^ 126 : Real) * 1 * (1 / (2 ^ 131 : Real)) ≤ - 441941738241592203 / 10000000000000000000 := by norm_num + have hn : (2 ^ 126 : Real) * 1 * (1 / (2 ^ 132 : Real)) ≤ + 220970869120796102 / 10000000000000000000 := by norm_num linarith [h1, hn] -- link 4 with Et ≤ 1 set Ert := Real.exp (reducedArg x) with hErtdef @@ -1134,25 +1134,25 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) 2170557036555806152 / 10000000000000000000 := hlink1 _ ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + 2170557036555806152 / 10000000000000000000 := by linarith [hgranR] - _ ≤ ((2 ^ 126 : Real) * Et + 441941738241592203 / 10000000000000000000) + + _ ≤ ((2 ^ 126 : Real) * Et + 220970869120796102 / 10000000000000000000) + 2170557036555806152 / 10000000000000000000 := by linarith [hNEMp, hcMp] _ ≤ (((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + - 441941738241592203 / 10000000000000000000) + + 220970869120796102 / 10000000000000000000) + 2170557036555806152 / 10000000000000000000 := by linarith [hEtErt] _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 6013505372794194988 / 10000000000000000000 := by + 5792534503673398887 / 10000000000000000000 := by rw [hErtdef] have : (110485434560398051 : Real) / 10000000000000000000 + - 441941738241592203 / 10000000000000000000 + + 220970869120796102 / 10000000000000000000 + 2170557036555806152 / 10000000000000000000 ≤ - 6013505372794194988 / 10000000000000000000 := by norm_num + 5792534503673398887 / 10000000000000000000 := by norm_num linarith [this] /-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + B` (`WAD·B < MARGIN`). -/ theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 6013505372794194988 / 10000000000000000000 := by + 5792534503673398887 / 10000000000000000000 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_over_tight hx hC hC0 htnn · exact r0_real_over_tight_neg hx hC hC0 (le_of_lt htneg) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index a18b5acde..cadffa79b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -85,7 +85,7 @@ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - have hden072 : (165038630930342071346895739193146786756 : Int) ≤ ev - tod := by + have hden072 : (165038630930342071346895739193146786696 : Int) ≤ ev - tod := by have := den_ge_194 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 -- tod ≥ 0 on nonneg half @@ -160,8 +160,8 @@ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) set den := (evTree x : Int) - int256 (todTree x) with hdendef set D := DENv (vTree x) t with hDdef have hA : 2 ^ 637 * den ≤ D + 2 * 2 ^ 637 := by rw [hDdef]; linarith [hDEN_ge] - have hDlow : (2:Int) ^ 637 * (165038630930342071346895739193146786756 - 2) ≤ D := by - have h1 : (2:Int) ^ 637 * (165038630930342071346895739193146786756 - 2) ≤ + have hDlow : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ D := by + have h1 : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ 2 ^ 637 * den - 2 * 2 ^ 637 := by nlinarith [hden] rw [hDdef]; linarith [h1, hDEN_ge] have hB : 100 * ((2 ^ 637 + 269746241 * 2 ^ 480 * t) * (2 ^ 126 + r0)) ≤ 149 * D := by @@ -180,13 +180,13 @@ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) have hr0cap : 100 * (2 ^ 126 + r0) ≤ 245 * 2 ^ 126 := by linarith [hr0hi145] nlinarith [hr0cap] have h3 : (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - (245 * 2 ^ 126) ≤ 149 * (2 ^ 637 * (165038630930342071346895739193146786756 - 2)) := by + (245 * 2 ^ 126) ≤ 149 * (2 ^ 637 * (165038630930342071346895739193146786696 - 2)) := by norm_num - have h4 : (149 : Int) * (2 ^ 637 * (165038630930342071346895739193146786756 - 2)) ≤ 149 * D := + have h4 : (149 : Int) * (2 ^ 637 * (165038630930342071346895739193146786696 - 2)) ≤ 149 * D := mul_le_mul_of_nonneg_left hDlow (by norm_num) linarith [h1, h2, h3, h4] have hC2000 : (2000 : Int) * 2 ^ 637 ≤ D := by - have : (2000 : Int) * 2 ^ 637 ≤ 2 ^ 637 * (165038630930342071346895739193146786756 - 2) := by + have : (2000 : Int) * 2 ^ 637 ≤ 2 ^ 637 * (165038630930342071346895739193146786696 - 2) := by norm_num linarith [this, hDlow] linarith [hLHS, hA, hB, hC2000] @@ -254,10 +254,10 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef set D := DENv (vTree x) (int256 (tTree x)) with hDdef - have hev : (207573926795459379279817565122117813188 : Int) ≤ ev := by - have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ ev := by + have hev : (207573926795459379279817565122117813128 : Int) ≤ ev := by + have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ ev := by rw [hevdef]; exact_mod_cast hev_lo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 from by norm_num] at this + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 from by norm_num] at this exact this have hden_le : ev - tod ≤ ev + 2 ^ 125 := by have : -(2 ^ 125 : Int) ≤ tod := htod_lo125 @@ -266,10 +266,10 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) -- 1000·(2^637·(ev + 2^125) + Wev·2^590·2^126 + 2·2^637·2^126) ≤ 1000·2^637·ev + 1500·2^637·A0 have hlit : 1000 * (2 ^ 637 * 2 ^ 125 + 142941343449089 * 2 ^ 590 * 2 ^ 126 + 2 * 2 ^ 637 * 2 ^ 126) ≤ - (1500 : Int) * (2 ^ 637 * 207573926795459379279817565122117813188) := by + (1500 : Int) * (2 ^ 637 * 207573926795459379279817565122117813128) := by norm_num - have hAev : (1500 : Int) * (2 ^ 637 * 207573926795459379279817565122117813188) ≤ 1500 * D := by - have h1 : (2:Int) ^ 637 * 207573926795459379279817565122117813188 ≤ 2 ^ 637 * ev := + have hAev : (1500 : Int) * (2 ^ 637 * 207573926795459379279817565122117813128) ≤ 1500 * D := by + have h1 : (2:Int) ^ 637 * 207573926795459379279817565122117813128 ≤ 2 ^ 637 * ev := mul_le_mul_of_nonneg_left hev (by positivity) have := le_trans h1 hDev nlinarith [this] @@ -314,19 +314,19 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef - set Mpp : Real := ((2 ^ 131 : Real) + 1) / (2 ^ 131 : Real) with hMppdef + set Mpp : Real := ((2 ^ 132 : Real) + 1) / (2 ^ 132 : Real) with hMppdef have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mpp := by - have hc : Et ≤ ((2 ^ 131 + 1 : Int) : Real) * (NE : Real) / - (((2 ^ 131 : Int) : Real) * (DE : Real)) := hcertup + have hc : Et ≤ ((2 ^ 132 + 1 : Int) : Real) * (NE : Real) / + (((2 ^ 132 : Int) : Real) * (DE : Real)) := hcertup rw [hMppdef] - have key : ((NE : Real) / (DE : Real)) * (((2 ^ 131 : Real) + 1) / (2 ^ 131 : Real)) = - ((2 ^ 131 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 131 : Int) : Real) * (DE : Real)) := by + have key : ((NE : Real) / (DE : Real)) * (((2 ^ 132 : Real) + 1) / (2 ^ 132 : Real)) = + ((2 ^ 132 + 1 : Int) : Real) * (NE : Real) / (((2 ^ 132 : Int) : Real) * (DE : Real)) := by push_cast; field_simp; ring rw [key]; exact hc have hMpp_nn : (0:Real) ≤ Mpp := by rw [hMppdef]; positivity have hEt_le_Qv : Et ≤ ((NUMv v t : Real) / (DENv v t : Real)) * Mpp := le_trans hEt_le (mul_le_mul_of_nonneg_right hgran1 hMpp_nn) - have hMpp1 : Mpp - 1 = 1 / (2 ^ 131 : Real) := by rw [hMppdef]; field_simp + have hMpp1 : Mpp - 1 = 1 / (2 ^ 132 : Real) := by rw [hMppdef]; field_simp obtain ⟨_, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn have hr0R : (r0 : Real) ≤ (145 / 100) * (2 ^ 126 : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0hi145 @@ -343,8 +343,8 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) rw [hMpp1] have hcap : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ (145 / 100) * (2 ^ 126 : Real) + 2500 / 1000 := by linarith [hQv_le, hr0R] - have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / (2 ^ 131 : Real)) - have hfin : ((145 / 100) * (2 ^ 126 : Real) + 2500 / 1000) * (1 / (2 ^ 131 : Real)) ≤ + have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / (2 ^ 132 : Real)) + have hfin : ((145 / 100) * (2 ^ 126 : Real) + 2500 / 1000) * (1 / (2 ^ 132 : Real)) ≤ 1 / 20 := by norm_num linarith [this, hfin] linarith [h1, h2 ▸ h1, h3, hQv_le] @@ -404,20 +404,20 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef - set Mp : Real := (2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1) with hMpdef + set Mp : Real := (2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1) with hMpdef have hEt_le : Et ≤ ((NE : Real) / (DE : Real)) * Mp := by rw [hMpdef] - have key : ((NE : Real) / (DE : Real)) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) = - ((2 ^ 131 : Int) : Real) * (NE : Real) / - (((2 ^ 131 - 1 : Int) : Real) * (DE : Real)) := by + have key : ((NE : Real) / (DE : Real)) * ((2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1)) = + ((2 ^ 132 : Int) : Real) * (NE : Real) / + (((2 ^ 132 - 1 : Int) : Real) * (DE : Real)) := by push_cast; field_simp; ring rw [key]; exact hcertup obtain ⟨_, hgran2⟩ := gran_under_pair hx hC hC0 htneg have hMp_nn : (0:Real) ≤ Mp := by rw [hMpdef] - have : (0:Real) < (2 ^ 131 : Real) - 1 := by norm_num + have : (0:Real) < (2 ^ 132 : Real) - 1 := by norm_num positivity - have hMp1 : Mp - 1 = 1 / ((2 ^ 131 : Real) - 1) := by rw [hMpdef]; field_simp + have hMp1 : Mp - 1 = 1 / ((2 ^ 132 : Real) - 1) := by rw [hMpdef]; field_simp have hr0le := r0_le_2126_neg hx hC hC0 htneg have hr0R : (r0 : Real) ≤ (2 ^ 126 : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le @@ -439,8 +439,8 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) have hcap : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ (2 ^ 126 : Real) + 2500 / 1000 := by linarith [hQv_le, hr0R] have := mul_le_mul_of_nonneg_right hcap - (by positivity : (0:Real) ≤ 1 / ((2 ^ 131 : Real) - 1)) - have hfin : ((2 ^ 126 : Real) + 2500 / 1000) * (1 / ((2 ^ 131 : Real) - 1)) ≤ 1 / 20 := by + (by positivity : (0:Real) ≤ 1 / ((2 ^ 132 : Real) - 1)) + have hfin : ((2 ^ 126 : Real) + 2500 / 1000) * (1 / ((2 ^ 132 : Real) - 1)) ≤ 1 / 20 := by rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] norm_num linarith [this, hfin] @@ -542,10 +542,10 @@ theorem r0_seam_double {x1 x2 : Nat} have hE2bound : (2 ^ 126 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + 31 / 10 := hunder2 have hr0_1 : (int256 (r0Tree x1) : Real) ≤ 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y + - 6013505372794194988 / 10000000000000000000 := by + 5792534503673398887 / 10000000000000000000 := by have h1 : (2 ^ 126 : Real) * E1 = 2 * ((2 ^ 126 : Real) * E2) * y := by rw [hseam]; ring have h2 : (int256 (r0Tree x1) : Real) ≤ (2 ^ 126 : Real) * E1 + - 6013505372794194988 / 10000000000000000000 := hover1 + 5792534503673398887 / 10000000000000000000 := hover1 rw [h1] at h2 have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y := mul_le_mul_of_nonneg_right @@ -555,7 +555,7 @@ theorem r0_seam_double {x1 x2 : Nat} have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^124)] have hkey : 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y + - 6013505372794194988 / 10000000000000000000 + 2 < 2 * (int256 (r0Tree x2) : Real) := by + 5792534503673398887 / 10000000000000000000 + 2 < 2 * (int256 (r0Tree x2) : Real) := by -- the seam gap is dominated by `(r0 + 31/10) / RAY`; the quotient exceeds `1562` here have hyb : 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) := diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index d301d06dd..ed2b69d6a 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -33,13 +33,13 @@ set_option maxRecDepth 100000 /-! ## Strict never-over: the accumulator stays a positive distance below the target -`accumReal_over` gives `accumReal x ≤ E`. With `B = 6013505372794194988/10¹⁹` the never-over envelope, +`accumReal_over` gives `accumReal x ≤ E`. With `B = 5792534503673398887/10¹⁹` the never-over envelope, `MARGIN` is `⌊WAD·B⌋ + 1` (`WAD = 5¹⁸`), so the inequality is in fact strict — the slack -`δ = MARGIN − WAD·B ≈ 0.07` (worth `δ/2^s` after the closing shift). The round trip needs this +`δ = MARGIN − WAD·B ≈ 0.86` (worth `δ/2^s` after the closing shift). The round trip needs this strictness to rule out `accumReal x = w` exactly. -/ /-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the target. -The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 6013505372794194988/10000000000000000000` plus `WAD·6013505372794194988/10000000000000000000 < MARGIN` give a strictly +The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 5792534503673398887/10000000000000000000` plus `WAD·5792534503673398887/10000000000000000000 < MARGIN` give a strictly negative residue. -/ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -49,13 +49,13 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- WAD·r0 − MARGIN < 5^18·2^126·Ert = E·2^s, using WAD·6013505372794194988/10000000000000000000 < MARGIN - have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242 < + -- WAD·r0 − MARGIN < 5^18·2^126·Ert = E·2^s, using WAD·5792534503673398887/10000000000000000000 < MARGIN + have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221 < expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 6013505372794194988 / 10000000000000000000 := hover + have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 5792534503673398887 / 10000000000000000000 := hover have hscaled : (3814697265625 : Real) * (int256 (r0Tree x) : Real) ≤ - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 6013505372794194988 / 10000000000000000000) := + (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 5792534503673398887 / 10000000000000000000) := mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] @@ -65,9 +65,9 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < norm_num] ring rw [hconst] - -- WAD·B = 3833775901374.02 < 2293970250242 = MARGIN - have hBM : (3814697265625 : Real) * (6013505372794194988 / 10000000000000000000) < - 2293970250242 := by norm_num + -- WAD·B = 3833775901374.02 < 2209676553221 = MARGIN + have hBM : (3814697265625 : Real) * (5792534503673398887 / 10000000000000000000) < + 2209676553221 := by norm_num linarith [hscaled, hBM] rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] @@ -91,7 +91,7 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = 5^18·2^126·Ert ≤ WAD·(r0 + 31/10) -- and (31/10)·WAD + MARGIN < (24/25)·2^45 ≤ (24/25)·2^s have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < - (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2293970250242 := by + (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = (WAD : Real) * (2 ^ 108 : Real) * Ert := hfold have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 31 / 10 := hunder @@ -99,7 +99,7 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask have h8wad : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 31 / 10) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - have hbudget : (3814697265625 : Real) * (31 / 10) + 2293970250242 < (24 / 25) * (2 ^ 45 : Real) := by + have hbudget : (3814697265625 : Real) * (31 / 10) + 2209676553221 < (24 / 25) * (2 ^ 45 : Real) := by norm_num rw [hwad] at hkey have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index 5f45ff83c..bfdae241e 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -96,7 +96,7 @@ A x = int256 (WAD·r0 − MARGIN) / 2^(108 − k). /-- The real pre-floor accumulator of the runtime body, as an explicit `Real`. -/ def accumReal (x : Nat) : Real := - (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) : Real) / + (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) : Real) / (2 ^ (evmSub 0x6c (kTree x)) : Real) /-- On the meaningful region the body word `r1Tree x` is the integer floor of its real accumulator @@ -108,18 +108,18 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) := by + have hr1 : r1Tree x = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) := by have : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) := rfl + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) := rfl rw [this, hseq] - have hWw : evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02 < 2 ^ 256 := + have hWw : evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05 < 2 ^ 256 := evmSub_lt _ _ - have hfloor := shr_real_floor (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) + have hfloor := shr_real_floor (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) (s := s) (by omega) hWw (by rw [hargeq]; exact hargnn) simp only at hfloor -- align `accumReal` (shift `evmSub 0x6c (kTree x)`) with the lemma's shift `s` have hAeq : accumReal x = - (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) : Real) / + (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) : Real) / (2 ^ s : Real) := by unfold accumReal; rw [hseq] rw [hAeq, hr1] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index cd357ec25..a274ec639 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -19,20 +19,20 @@ abbrev tArgShift : Nat := 0x6b abbrev squareShift : Nat := 0x85 abbrev ev0 : Nat := 0xb9aacfacf3c10b378435f8e22adf48500e -abbrev ev1 : Nat := 0x9a036222841f47c6ed6fc3f7602053 -abbrev ev2 : Nat := 0x9064d9657e9a21fc16bb69331c5c3057 -abbrev ev3 : Nat := 0x93f11e650dd6c64b96ce79065cdf809e -abbrev ev4 : Nat := 0x9c2948bcaca16a0dd2fe98bb4470c3c4 +abbrev ev1 : Nat := 0x9a036222841f47c6ed6fc3f7599445 +abbrev ev2 : Nat := 0x9064d9657e9a21fc16bb69331b81ae1e +abbrev ev3 : Nat := 0x93f11e650dd6c64b96ce79065cdf80f4 +abbrev ev4 : Nat := 0x9c2948bcaca16a0dd2fe98bb4470c388 abbrev evShift1 : Nat := 0x95 abbrev evShift2 : Nat := 0x7b abbrev evShift3 : Nat := 0x81 abbrev evShift4 : Nat := 0x7e abbrev od0 : Nat := 0xdc07aff8276bde9a361278df6a10 -abbrev od1 : Nat := 0xc926ddbecdeeb42e68cd16db7da8c1 -abbrev od2 : Nat := 0xad4506af99be27419341e1816ff351 -abbrev od3 : Nat := 0xaf566247c05753b42892f77b67a6b7c6 -abbrev od4 : Nat := 0x9c2948bcaca16a0dd2fe98bb4470c3c4 +abbrev od1 : Nat := 0xc926ddbecdeeb42e68cd16db7ed378 +abbrev od2 : Nat := 0xad4506af99be27419341e181693281 +abbrev od3 : Nat := 0xaf566247c05753b42892f77b67a6b7c7 +abbrev od4 : Nat := 0x9c2948bcaca16a0dd2fe98bb4470c388 abbrev odShift1 : Nat := 0x7e abbrev odShift2 : Nat := 0x84 abbrev odShift3 : Nat := 0x7a @@ -42,7 +42,7 @@ abbrev todShift : Nat := 0x81 abbrev expQShift : Nat := 0x7e abbrev foldShift : Nat := 0x6c abbrev wadWord : Nat := 0x3782dace9d9 -abbrev marginWord : Nat := 0x2161b482a02 +abbrev marginWord : Nat := 0x2027afc6c05 theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by unfold Cmask int256 diff --git a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean index e4c31aab0..13412d68e 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean @@ -66,11 +66,11 @@ Given the numerator/denominator positivity and `tod1·ev2 ≤ tod2·ev1`, the tw `≤`-ordered. -/ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} (hE1 : E1 < 2 ^ 256) (hTD1 : TD1 < 2 ^ 256) (hE2 : E2 < 2 ^ 256) (hTD2 : TD2 < 2 ^ 256) - (hev1_lo : (207573926795459379279817565122117813188 : Int) ≤ (E1 : Int)) + (hev1_lo : (207573926795459379279817565122117813128 : Int) ≤ (E1 : Int)) (hev1_hi : (E1 : Int) < 3 * 2 ^ 126) (htod1_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD1) (htod1_hi : int256 TD1 < 85070591730234615865843651857942052864) - (hev2_lo : (207573926795459379279817565122117813188 : Int) ≤ (E2 : Int)) + (hev2_lo : (207573926795459379279817565122117813128 : Int) ≤ (E2 : Int)) (hev2_hi : (E2 : Int) < 3 * 2 ^ 126) (htod2_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD2) (htod2_hi : int256 TD2 < 85070591730234615865843651857942052864) diff --git a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean index b399f1e05..da9429fa3 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean @@ -26,12 +26,12 @@ set_option maxRecDepth 100000 /-- The even accumulator's signed value is its (nonnegative) Nat value, in `[a0, 2^127)`. -/ theorem evTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : - (207573926795459379279817565122117813188 : Int) ≤ (evTree x : Int) ∧ + (207573926795459379279817565122117813128 : Int) ≤ (evTree x : Int) ∧ (evTree x : Int) < 3 * 2 ^ 126 := by obtain ⟨hlo, hhi⟩ := evTree_facts hv constructor - · have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 by + · have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 by norm_num] at this exact this · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hhi @@ -39,12 +39,12 @@ theorem evTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : /-- The odd accumulator's signed value is its (nonnegative) Nat value, in `[b0, 5·2^125)`. -/ theorem odTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : - (207573926795459379279817565122117813188 : Int) ≤ (odTree x : Int) ∧ + (207573926795459379279817565122117813128 : Int) ≤ (odTree x : Int) ∧ (odTree x : Int) < 5 * 2 ^ 125 := by obtain ⟨hlo, hhi⟩ := odTree_facts hv constructor - · have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (odTree x : Int) := by exact_mod_cast hlo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 by + · have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (odTree x : Int) := by exact_mod_cast hlo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 by norm_num] at this exact this · have : (odTree x : Int) < ((5 * 2 ^ 125 : Nat) : Int) := by exact_mod_cast hhi @@ -89,11 +89,11 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} (hd1 : (340282366920 : Int) ≤ d) (ht1lo : -(170141183460469231731687303715884105728 : Int) < t1) (ht1hi : t1 < 170141183460469231731687303715884105728) - (hev1lo : (207573926795459379279817565122117813188 : Int) ≤ ev1) + (hev1lo : (207573926795459379279817565122117813128 : Int) ≤ ev1) (hev1hi : ev1 < 255211775190703847597530955573826158592) - (hev2lo : (207573926795459379279817565122117813188 : Int) ≤ ev2) + (hev2lo : (207573926795459379279817565122117813128 : Int) ≤ ev2) (hev2hi : ev2 < 255211775190703847597530955573826158592) - (hod2lo : (207573926795459379279817565122117813188 : Int) ≤ od2) + (hod2lo : (207573926795459379279817565122117813128 : Int) ≤ od2) (hod2hi : od2 < 212676479325586539664609129644855132160) (hevd1 : -(85236826369 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 85236826369) (hodd1 : -(21288422193 : Int) ≤ od1 - od2) (hodd2 : od1 - od2 ≤ 21288422193) : @@ -133,13 +133,13 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} linarith -- gain: d·od2·ev1 ≥ 340282366920·b0·a0 have hev1nn : (0 : Int) ≤ ev1 := by linarith - have hgain : (340282366920 : Int) * 207573926795459379279817565122117813188 * - 207573926795459379279817565122117813188 ≤ d * od2 * ev1 := by - have g1 : (340282366920 : Int) * 207573926795459379279817565122117813188 ≤ d * od2 := by - have := mul_le_mul hd1 hod2lo (by norm_num : (0:Int) ≤ 207573926795459379279817565122117813188) (by linarith) + have hgain : (340282366920 : Int) * 207573926795459379279817565122117813128 * + 207573926795459379279817565122117813128 ≤ d * od2 * ev1 := by + have g1 : (340282366920 : Int) * 207573926795459379279817565122117813128 ≤ d * od2 := by + have := mul_le_mul hd1 hod2lo (by norm_num : (0:Int) ≤ 207573926795459379279817565122117813128) (by linarith) linarith - have g2 : (340282366920 : Int) * 207573926795459379279817565122117813188 * - 207573926795459379279817565122117813188 ≤ (d * od2) * ev1 := + have g2 : (340282366920 : Int) * 207573926795459379279817565122117813128 * + 207573926795459379279817565122117813128 ≤ (d * od2) * ev1 := mul_le_mul g1 hev1lo (by norm_num) (by positivity) linarith [g2] -- assemble: goal `t1·od1·ev2 + 2^128·ev2 ≤ (t1+d)·od2·ev1 = t1·od2·ev1 + d·od2·ev1` @@ -150,8 +150,8 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} -- numeric closure: 2^128·ev2 + 2^127·CB ≤ gain, and ev2 < 2^127 have hkey : (680564733841876926926749214863536422912 : Int) * ev1 + 170141183460469231731687303715884105728 * CB ≤ - (340282366920 : Int) * 207573926795459379279817565122117813188 * - 207573926795459379279817565122117813188 := by + (340282366920 : Int) * 207573926795459379279817565122117813128 * + 207573926795459379279817565122117813128 := by rw [hCB] nlinarith [hev1hi] nlinarith [htcd, hgain, hkey, hdecomp] diff --git a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean index 7ecbc2f9b..74b32f789 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean @@ -55,62 +55,62 @@ theorem stage_lip_dist {c prev1 prev2 v1 v2 P V Dprev W sh : Nat} /-! ## The even Horner stages as named layers, with their chained ceilings -/ def evS0 (x : Nat) : Nat := evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e (vTree x) -def evS1 (x : Nat) : Nat := evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul (evS0 x) (vTree x))) -def evS2 (x : Nat) : Nat := evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul (evS1 x) (vTree x))) -def evS3 (x : Nat) : Nat := evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul (evS2 x) (vTree x))) +def evS1 (x : Nat) : Nat := evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evS0 x) (vTree x))) +def evS2 (x : Nat) : Nat := evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evS1 x) (vTree x))) +def evS3 (x : Nat) : Nat := evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evS2 x) (vTree x))) theorem evTree_layers (x : Nat) : - evTree x = evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul (evS3 x) (vTree x))) := + evTree x = evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul (evS3 x) (vTree x))) := rfl theorem evS0_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evS0 x < 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120 := ev0_lt hv theorem evS1_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evS1 x < 2 ^ 121 := by - have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7602053) (prev := evS0 x) (v := vTree x) + have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7599445) (prev := evS0 x) (v := vTree x) (P := 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) (V := 2 ^ 120) (sh := 0x95) (evS0_lt hv) hv (by norm_num) (by norm_num) (by norm_num)).2 - have hcap : (0x9a036222841f47c6ed6fc3f7602053 : Nat) + + have hcap : (0x9a036222841f47c6ed6fc3f7599445 : Nat) + (0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) * 2 ^ 120 / 2 ^ 0x95 < 2 ^ 121 := by norm_num unfold evS1; omega theorem evS2_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evS2 x < 2 ^ 129 := by - have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331c5c3057) (prev := evS1 x) (v := vTree x) + have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331b81ae1e) (prev := evS1 x) (v := vTree x) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7b) (evS1_lt hv) hv (by norm_num) (by norm_num) (by rw [pvd 121 120 123 118 (by norm_num)]; norm_num)).2 rw [pvd 121 120 123 118 (by norm_num)] at this; unfold evS2; omega theorem evS3_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evS3 x < 2 ^ 129 := by - have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf809e) (prev := evS2 x) (v := vTree x) + have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf80f4) (prev := evS2 x) (v := vTree x) (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x81) (evS2_lt hv) hv (by norm_num) (by norm_num) (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 rw [pvd 129 120 129 120 (by norm_num)] at this; unfold evS3; omega /-! ## The odd Horner stages as named layers -/ -def odS0 (x : Nat) : Nat := evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 (vTree x))) -def odS1 (x : Nat) : Nat := evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul (odS0 x) (vTree x))) -def odS2 (x : Nat) : Nat := evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul (odS1 x) (vTree x))) +def odS0 (x : Nat) : Nat := evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 (vTree x))) +def odS1 (x : Nat) : Nat := evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul (odS0 x) (vTree x))) +def odS2 (x : Nat) : Nat := evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul (odS1 x) (vTree x))) theorem odTree_layers (x : Nat) : - odTree x = evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul (odS2 x) (vTree x))) := + odTree x = evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul (odS2 x) (vTree x))) := rfl theorem odS0_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS0 x < 2 ^ 121 := by - have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7da8c1) (prev := 0xdc07aff8276bde9a361278df6a10) + have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7ed378) (prev := 0xdc07aff8276bde9a361278df6a10) (v := vTree x) (P := 2 ^ 112) (V := 2 ^ 120) (sh := 0x7e) (by norm_num) hv (by norm_num) (by norm_num) (by rw [pvd 112 120 126 106 (by norm_num)]; norm_num)).2 rw [pvd 112 120 126 106 (by norm_num)] at this; unfold odS0; omega theorem odS1_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS1 x < 2 ^ 121 := by - have := (stage_bounds (c := 0xad4506af99be27419341e1816ff351) (prev := odS0 x) (v := vTree x) + have := (stage_bounds (c := 0xad4506af99be27419341e181693281) (prev := odS0 x) (v := vTree x) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x84) (odS0_lt hv) hv (by norm_num) (by norm_num) (by rw [pvd 121 120 132 109 (by norm_num)]; norm_num)).2 rw [pvd 121 120 132 109 (by norm_num)] at this; unfold odS1; omega theorem odS2_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS2 x < 2 ^ 129 := by - have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c6) (prev := odS1 x) (v := vTree x) + have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c7) (prev := odS1 x) (v := vTree x) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7a) (odS1_lt hv) hv (by norm_num) (by norm_num) (by rw [pvd 121 120 122 119 (by norm_num)]; norm_num)).2 rw [pvd 121 120 122 119 (by norm_num)] at this; unfold odS2; omega @@ -127,7 +127,7 @@ theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 evLead_lip (c := 0xb9aacfacf3c10b378435f8e22adf48500e) (W := Wstep) (by norm_num) hv1 hv2 hg1 hg2 -- stage 1 have d1 : dist_le (evS1 x1) (evS1 x2) 941485 := by - have h := stage_lip_dist (c := 0x9a036222841f47c6ed6fc3f7602053) + have h := stage_lip_dist (c := 0x9a036222841f47c6ed6fc3f7599445) (P := 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) (V := 2 ^ 120) (sh := 0x95) (W := Wstep) (Dprev := Wstep) (le_of_lt (evS0_lt hv1)) (le_of_lt (evS0_lt hv2)) hv1 hv2 hg1 hg2 d0 (by norm_num) (by norm_num) (by norm_num) (by norm_num) @@ -136,7 +136,7 @@ theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 rw [he] at h; exact h -- stage 2 have d2 : dist_le (evS2 x1) (evS2 x2) 2658573678 := by - have h := stage_lip_dist (c := 0x9064d9657e9a21fc16bb69331c5c3057) (P := 2 ^ 121) (V := 2 ^ 120) + have h := stage_lip_dist (c := 0x9064d9657e9a21fc16bb69331b81ae1e) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7b) (W := Wstep) (Dprev := 941485) (le_of_lt (evS1_lt hv1)) (le_of_lt (evS1_lt hv2)) hv1 hv2 hg1 hg2 d1 (by norm_num) (by norm_num) (by norm_num) (by norm_num) @@ -145,7 +145,7 @@ theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 rw [he] at h; exact h -- stage 3 have d3 : dist_le (evS3 x1) (evS3 x2) 10639016494 := by - have h := stage_lip_dist (c := 0x93f11e650dd6c64b96ce79065cdf809e) (P := 2 ^ 129) (V := 2 ^ 120) + have h := stage_lip_dist (c := 0x93f11e650dd6c64b96ce79065cdf80f4) (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x81) (W := Wstep) (Dprev := 2658573678) (le_of_lt (evS2_lt hv1)) (le_of_lt (evS2_lt hv2)) hv1 hv2 hg1 hg2 d2 (by norm_num) (by norm_num) (by norm_num) (by norm_num) @@ -153,7 +153,7 @@ theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 unfold Wstep; decide rw [he] at h; exact h -- final stage - have hfin := stage_lip_dist (c := 0x9c2948bcaca16a0dd2fe98bb4470c3c4) (P := 2 ^ 129) (V := 2 ^ 120) + have hfin := stage_lip_dist (c := 0x9c2948bcaca16a0dd2fe98bb4470c388) (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x7e) (W := Wstep) (Dprev := 10639016494) (le_of_lt (evS3_lt hv1)) (le_of_lt (evS3_lt hv2)) hv1 hv2 hg1 hg2 d3 (by norm_num) (by norm_num) (by norm_num) (by norm_num) @@ -169,7 +169,7 @@ theorem odTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 dist_le (odTree x1) (odTree x2) 21288422193 := by -- stage 0: prev is the constant leading coefficient (distance 0) have d0 : dist_le (odS0 x1) (odS0 x2) 649038 := by - have h := stage_lip_dist (c := 0xc926ddbecdeeb42e68cd16db7da8c1) (P := 2 ^ 112) (V := 2 ^ 120) + have h := stage_lip_dist (c := 0xc926ddbecdeeb42e68cd16db7ed378) (P := 2 ^ 112) (V := 2 ^ 120) (sh := 0x7e) (W := Wstep) (Dprev := 0) (prev1 := 0xdc07aff8276bde9a361278df6a10) (prev2 := 0xdc07aff8276bde9a361278df6a10) (by norm_num) (by norm_num) hv1 hv2 hg1 hg2 (odLead_const _) (by norm_num) (by norm_num) @@ -177,21 +177,21 @@ theorem odTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 have he : (2 ^ 112 * Wstep + 2 ^ 120 * 0) / 2 ^ 0x7e + 1 = 649038 := by unfold Wstep; decide rw [he] at h; exact h have d1 : dist_le (odS1 x1) (odS1 x2) 5192456 := by - have h := stage_lip_dist (c := 0xad4506af99be27419341e1816ff351) (P := 2 ^ 121) (V := 2 ^ 120) + have h := stage_lip_dist (c := 0xad4506af99be27419341e181693281) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x84) (W := Wstep) (Dprev := 649038) (le_of_lt (odS0_lt hv1)) (le_of_lt (odS0_lt hv2)) hv1 hv2 hg1 hg2 d0 (by norm_num) (by norm_num) (by norm_num) (by norm_num) have he : (2 ^ 121 * Wstep + 2 ^ 120 * 649038) / 2 ^ 0x84 + 1 = 5192456 := by unfold Wstep; decide rw [he] at h; exact h have d2 : dist_le (odS2 x1) (odS2 x2) 5318210098 := by - have h := stage_lip_dist (c := 0xaf566247c05753b42892f77b67a6b7c6) (P := 2 ^ 121) (V := 2 ^ 120) + have h := stage_lip_dist (c := 0xaf566247c05753b42892f77b67a6b7c7) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7a) (W := Wstep) (Dprev := 5192456) (le_of_lt (odS1_lt hv1)) (le_of_lt (odS1_lt hv2)) hv1 hv2 hg1 hg2 d1 (by norm_num) (by norm_num) (by norm_num) (by norm_num) have he : (2 ^ 121 * Wstep + 2 ^ 120 * 5192456) / 2 ^ 0x7a + 1 = 5318210098 := by unfold Wstep; decide rw [he] at h; exact h - have hfin := stage_lip_dist (c := 0x9c2948bcaca16a0dd2fe98bb4470c3c4) (P := 2 ^ 129) (V := 2 ^ 120) + have hfin := stage_lip_dist (c := 0x9c2948bcaca16a0dd2fe98bb4470c388) (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x80) (W := Wstep) (Dprev := 5318210098) (le_of_lt (odS2_lt hv1)) (le_of_lt (odS2_lt hv2)) hv1 hv2 hg1 hg2 d2 (by norm_num) (by norm_num) (by norm_num) (by norm_num) diff --git a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean index 60c3d4d1d..06e757e95 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean @@ -82,7 +82,7 @@ theorem todTree_bound {x : Nat} (hx : x < 2 ^ 256) /-- Abstract numerator/denominator positivity: stated over opaque words `E` (the even accumulator) and `TD` (the signed `t·Od` shift) with their bounds, so the deep Horner tree is never forced. -/ theorem numden_pos_of {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) - (hev_lo : (207573926795459379279817565122117813188 : Int) ≤ (E : Int)) + (hev_lo : (207573926795459379279817565122117813128 : Int) ≤ (E : Int)) (hev_hi : (E : Int) < 3 * 2 ^ 126) (htod_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD) (htod_hi : int256 TD < 85070591730234615865843651857942052864) : @@ -123,8 +123,8 @@ theorem numden_pos {x : Nat} (hx : x < 2 ^ 256) have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ refine numden_pos_of hevw htodw ?_ ?_ ?_ ?_ - · have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 by norm_num] at this + · have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 by norm_num] at this exact this · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hev_hi rw [show ((3 * 2 ^ 126 : Nat) : Int) = 3 * 2 ^ 126 by norm_num] at this; exact this @@ -200,7 +200,7 @@ theorem int256_eq_of_nonneg {w : Nat} (hw : w < 2 ^ 256) (hnn : 0 ≤ int256 w) bounds. `r0 = div(2^126·(E+TD), E−TD)`; the numerator and denominator are positive and the quotient lands in `[2^123, 2^128)` (the reduced argument keeps `exp(t) ∈ [1/√2, √2)`). -/ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) - (hev_lo : (207573926795459379279817565122117813188 : Int) ≤ (E : Int)) + (hev_lo : (207573926795459379279817565122117813128 : Int) ≤ (E : Int)) (hev_hi : (E : Int) < 3 * 2 ^ 126) (htod_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD) (htod_hi : int256 TD < 85070591730234615865843651857942052864) : @@ -247,8 +247,8 @@ theorem r0Tree_bounds {x : Nat} (hx : x < 2 ^ 256) have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ refine r0Tree_bounds_ofEvTod hevw htodw ?_ ?_ ?_ ?_ - · have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Int) = 207573926795459379279817565122117813188 by norm_num] at this + · have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 by norm_num] at this exact this · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hev_hi rw [show ((3 * 2 ^ 126 : Nat) : Int) = 3 * 2 ^ 126 by norm_num] at this; exact this diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean index bf45f1b08..430aa0517 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -59,17 +59,17 @@ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) and below `2^170`. -/ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (hr0_lo : (2 ^ 123 : Int) ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 128) : - int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) = - 0x3782dace9d9 * int256 r0 - 0x2161b482a02 ∧ - 0 ≤ 0x3782dace9d9 * int256 r0 - 0x2161b482a02 ∧ - 0x3782dace9d9 * int256 r0 - 0x2161b482a02 < 2 ^ 170 := by + int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) = + 0x3782dace9d9 * int256 r0 - 0x2027afc6c05 ∧ + 0 ≤ 0x3782dace9d9 * int256 r0 - 0x2027afc6c05 ∧ + 0x3782dace9d9 * int256 r0 - 0x2027afc6c05 < 2 ^ 170 := by have hwad : int256 (0x3782dace9d9 : Nat) = 0x3782dace9d9 := by rw [int256_of_lt (by norm_num)]; simp have hwadlt : (0x3782dace9d9 : Nat) < 2 ^ 256 := by norm_num have hp128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num have hp170 : (2:Int)^170 = 1496577676626844588240573268701473812127674924007424 := by norm_num have hwadc : (0x3782dace9d9 : Int) = 3814697265625 := by norm_num - have hmarc : (0x2161b482a02 : Int) = 2293970250242 := by norm_num + have hmarc : (0x2027afc6c05 : Int) = 2209676553221 := by norm_num rw [hp128] at hr0_hi -- the product WAD·r0 transported have hmul : int256 (evmMul 0x3782dace9d9 r0) = 0x3782dace9d9 * int256 r0 := by @@ -78,12 +78,12 @@ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) rw [hwad] at this; exact this have hmullt : evmMul 0x3782dace9d9 r0 < 2 ^ 256 := evmMul_lt _ _ - have hmarlt : (0x2161b482a02 : Nat) < 2 ^ 256 := by norm_num - have hmari : int256 (0x2161b482a02 : Nat) = 0x2161b482a02 := by + have hmarlt : (0x2027afc6c05 : Nat) < 2 ^ 256 := by norm_num + have hmari : int256 (0x2027afc6c05 : Nat) = 0x2027afc6c05 := by rw [int256_of_lt (by norm_num)]; simp -- transport the subtraction - have hsub : int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) = - 0x3782dace9d9 * int256 r0 - 0x2161b482a02 := by + have hsub : int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) = + 0x3782dace9d9 * int256 r0 - 0x2027afc6c05 := by have := evmSub_transport hmullt hmarlt (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) @@ -136,7 +136,7 @@ theorem r1Tree_int256_nonneg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi have hr1 : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) := rfl + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) := rfl rw [hr1, hseq] exact (closingShr_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi)).1 @@ -149,11 +149,11 @@ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi have hr1 : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) := rfl - obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02) + (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) := rfl + obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi) -- int256 (r1Tree x) ∈ [0, 2^125) ⇒ the Nat word is < 2^254 - have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2161b482a02)) := by + have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05)) := by rw [hr1, hseq] rw [← hReq] at hnn hlt have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean index 8e571fb6e..20d074b44 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -100,20 +100,20 @@ theorem seamStep_of_r0 (hr0 : SeamR0Bound) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (h obtain ⟨harg1eq, harg1nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 obtain ⟨harg2eq, harg2nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 have hr1eq1 : r1Tree x1 = - evmShr s1 (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2161b482a02) := by + evmShr s1 (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2027afc6c05) := by unfold r1Tree; rw [hs1eq] have hr1eq2 : r1Tree x2 = - evmShr s2 (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2161b482a02) := by + evmShr s2 (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2027afc6c05) := by unfold r1Tree; rw [hs2eq] rw [hr1eq1, hr1eq2] -- name the deep shift arguments opaquely before feeding the floor lemma - set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2161b482a02 with harg1def - set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2161b482a02 with harg2def + set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2027afc6c05 with harg1def + set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2027afc6c05 with harg2def have hr0bound : int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) := hr0 hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hargle : int256 arg1 ≤ 2 * int256 arg2 := by rw [harg1eq, harg2eq, show (0x3782dace9d9 : Int) = 3814697265625 by norm_num, - show (0x2161b482a02 : Int) = 2293970250242 by norm_num] + show (0x2027afc6c05 : Int) = 2209676553221 by norm_num] -- `WAD·r0a − M ≤ 2·(WAD·r0b − M)` ⟸ `WAD·r0a + M ≤ 2·WAD·r0b` ⟸ `r0a ≤ 2·r0b − 2` and `M ≤ 2·WAD` nlinarith [hr0bound] exact seam_close (harg1def ▸ evmSub_lt _ _) (harg2def ▸ evmSub_lt _ _) hs1lt hs2lt hseq diff --git a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean index 05e70451d..dcd515da4 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean @@ -330,91 +330,91 @@ theorem pvd (pe ve sh e : Nat) (hpe : pe + ve = sh + e) : `(ev0 + v)·v` is capped by the exact literal sum `(ev0 + 2^120)·2^120 < 2^256` — it has no power-of-two headroom. -/ theorem evTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x9c2948bcaca16a0dd2fe98bb4470c3c4 ≤ evTree x ∧ evTree x < 3 * 2 ^ 126 := by + 0x9c2948bcaca16a0dd2fe98bb4470c388 ≤ evTree x ∧ evTree x < 3 * 2 ^ 126 := by have hev : evTree x = - evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e (vTree x)) (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl rw [hev] set v := vTree x with hvdef have h0 := ev0_lt hv set ev0 := evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v with hev0 - have h1 : evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul ev0 v)) < 2 ^ 121 := by - have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7602053) (prev := ev0) (v := v) + have h1 : evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul ev0 v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0x9a036222841f47c6ed6fc3f7599445) (prev := ev0) (v := v) (P := 0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) (V := 2 ^ 120) (sh := 0x95) h0 hv (by norm_num) (by norm_num) (by norm_num)).2 - have hcap : (0x9a036222841f47c6ed6fc3f7602053 : Nat) + + have hcap : (0x9a036222841f47c6ed6fc3f7599445 : Nat) + (0xb9aacfacf3c10b378435f8e22adf48500e + 2 ^ 120) * 2 ^ 120 / 2 ^ 0x95 < 2 ^ 121 := by norm_num omega - set ev1 := evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul ev0 v)) with hev1 - have h2 : evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul ev1 v)) < 2 ^ 129 := by - have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331c5c3057) (prev := ev1) (v := v) + set ev1 := evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul ev0 v)) with hev1 + have h2 : evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul ev1 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0x9064d9657e9a21fc16bb69331b81ae1e) (prev := ev1) (v := v) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7b) h1 hv (by norm_num) (by norm_num) (by rw [pvd 121 120 123 118 (by norm_num)]; norm_num)).2 rw [pvd 121 120 123 118 (by norm_num)] at this; omega - set ev2 := evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul ev1 v)) with hev2 - have h3 : evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul ev2 v)) < 2 ^ 129 := by - have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf809e) (prev := ev2) (v := v) + set ev2 := evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul ev1 v)) with hev2 + have h3 : evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul ev2 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0x93f11e650dd6c64b96ce79065cdf80f4) (prev := ev2) (v := v) (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x81) h2 hv (by norm_num) (by norm_num) (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 rw [pvd 129 120 129 120 (by norm_num)] at this; omega - set ev3 := evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul ev2 v)) with hev3 - have hfin := stage_bounds (c := 0x9c2948bcaca16a0dd2fe98bb4470c3c4) (prev := ev3) (v := v) + set ev3 := evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul ev2 v)) with hev3 + have hfin := stage_bounds (c := 0x9c2948bcaca16a0dd2fe98bb4470c388) (prev := ev3) (v := v) (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x7e) h3 hv (by norm_num) (by norm_num) (by rw [pvd 129 120 126 123 (by norm_num)]; norm_num) rw [pvd 129 120 126 123 (by norm_num)] at hfin refine ⟨hfin.1, ?_⟩ - have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Nat) + 2 ^ 123 < 3 * 2 ^ 126 := by norm_num + have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Nat) + 2 ^ 123 < 3 * 2 ^ 126 := by norm_num omega theorem evTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evTree x < 3 * 2 ^ 126 := (evTree_facts hv).2 theorem evTree_ge {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x9c2948bcaca16a0dd2fe98bb4470c3c4 ≤ evTree x := (evTree_facts hv).1 + 0x9c2948bcaca16a0dd2fe98bb4470c388 ≤ evTree x := (evTree_facts hv).1 /-- Two-sided bound on the odd Horner accumulator: `0x9c29… ≤ od < 5·2^125`. -/ theorem odTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x9c2948bcaca16a0dd2fe98bb4470c3c4 ≤ odTree x ∧ odTree x < 5 * 2 ^ 125 := by + 0x9c2948bcaca16a0dd2fe98bb4470c388 ≤ odTree x ∧ odTree x < 5 * 2 ^ 125 := by have hod : odTree x = - evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 (vTree x)))) (vTree x)))) (vTree x)))) (vTree x))) := rfl rw [hod] set v := vTree x with hvdef - have h0 : evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v)) < 2 ^ 121 := by - have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7da8c1) (prev := 0xdc07aff8276bde9a361278df6a10) (v := v) + have h0 : evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0xc926ddbecdeeb42e68cd16db7ed378) (prev := 0xdc07aff8276bde9a361278df6a10) (v := v) (P := 2 ^ 112) (V := 2 ^ 120) (sh := 0x7e) (by norm_num) hv (by norm_num) (by norm_num) (by rw [pvd 112 120 126 106 (by norm_num)]; norm_num)).2 rw [pvd 112 120 126 106 (by norm_num)] at this; omega - set od0 := evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v)) with hod0 - have h1 : evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul od0 v)) < 2 ^ 121 := by - have := (stage_bounds (c := 0xad4506af99be27419341e1816ff351) (prev := od0) (v := v) + set od0 := evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v)) with hod0 + have h1 : evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul od0 v)) < 2 ^ 121 := by + have := (stage_bounds (c := 0xad4506af99be27419341e181693281) (prev := od0) (v := v) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x84) h0 hv (by norm_num) (by norm_num) (by rw [pvd 121 120 132 109 (by norm_num)]; norm_num)).2 rw [pvd 121 120 132 109 (by norm_num)] at this; omega - set od1 := evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul od0 v)) with hod1 - have h2 : evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul od1 v)) < 2 ^ 129 := by - have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c6) (prev := od1) (v := v) + set od1 := evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul od0 v)) with hod1 + have h2 : evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul od1 v)) < 2 ^ 129 := by + have := (stage_bounds (c := 0xaf566247c05753b42892f77b67a6b7c7) (prev := od1) (v := v) (P := 2 ^ 121) (V := 2 ^ 120) (sh := 0x7a) h1 hv (by norm_num) (by norm_num) (by rw [pvd 121 120 122 119 (by norm_num)]; norm_num)).2 rw [pvd 121 120 122 119 (by norm_num)] at this; omega - set od2 := evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul od1 v)) with hod2 - have hfin := stage_bounds (c := 0x9c2948bcaca16a0dd2fe98bb4470c3c4) (prev := od2) (v := v) + set od2 := evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul od1 v)) with hod2 + have hfin := stage_bounds (c := 0x9c2948bcaca16a0dd2fe98bb4470c388) (prev := od2) (v := v) (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x80) h2 hv (by norm_num) (by norm_num) (by rw [pvd 129 120 128 121 (by norm_num)]; norm_num) rw [pvd 129 120 128 121 (by norm_num)] at hfin refine ⟨hfin.1, ?_⟩ - have : (0x9c2948bcaca16a0dd2fe98bb4470c3c4 : Nat) + 2 ^ 121 < 5 * 2 ^ 125 := by norm_num + have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Nat) + 2 ^ 121 < 5 * 2 ^ 125 := by norm_num omega theorem odTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odTree x < 5 * 2 ^ 125 := (odTree_facts hv).2 theorem odTree_ge {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x9c2948bcaca16a0dd2fe98bb4470c3c4 ≤ odTree x := (odTree_facts hv).1 + 0x9c2948bcaca16a0dd2fe98bb4470c388 ≤ odTree x := (odTree_facts hv).1 end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean index 6ba60ada6..86470252c 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean @@ -90,14 +90,14 @@ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hk2w : kTree x2 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ have hseq := closing_shift_eq hk hk1w hk2w obtain ⟨s, hseqx, hslo, hshi, _⟩ := closing_shift hx1 hC1 hC01 - have hr1eq1 : r1Tree x1 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2161b482a02) := by + have hr1eq1 : r1Tree x1 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2027afc6c05) := by unfold r1Tree; rw [hseqx] - have hr1eq2 : r1Tree x2 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2161b482a02) := by + have hr1eq2 : r1Tree x2 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2027afc6c05) := by unfold r1Tree; rw [← hseq, hseqx] rw [hr1eq1, hr1eq2] -- the two shift arguments, transported to `Int`, are ordered (monotone `r0`) - set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2161b482a02 with harg1 - set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2161b482a02 with harg2 + set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2027afc6c05 with harg1 + set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2027afc6c05 with harg2 have hargle : int256 arg1 ≤ int256 arg2 := by rw [harg1eq, harg2eq] have hwad : (0 : Int) ≤ 0x3782dace9d9 := by norm_num diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 27f4da64e..90ec343f7 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -418,19 +418,19 @@ theorem call_fun__expRayToWad_78_direct let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -482,19 +482,19 @@ theorem call_fun_expRayToWad_68_direct let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -545,19 +545,19 @@ theorem call_fun_wrap_expRayToWad_direct let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) )]) := by @@ -605,19 +605,19 @@ theorem external_fun_wrap_expRayToWad_calldata_result let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -634,19 +634,19 @@ theorem external_fun_wrap_expRayToWad_calldata_result let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -735,19 +735,19 @@ theorem external_fun_wrap_expRayToWad_calldata_halts let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) with htree @@ -841,19 +841,19 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by @@ -920,19 +920,19 @@ theorem run_exp_ray_to_wad_evm_eq_tree let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x7e (evmMul - (evmAdd 0x93f11e650dd6c64b96ce79065cdf809e (evmShr 0x81 (evmMul - (evmAdd 0x9064d9657e9a21fc16bb69331c5c3057 (evmShr 0x7b (evmMul - (evmAdd 0x9a036222841f47c6ed6fc3f7602053 (evmShr 0x95 (evmMul + let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul + (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul + (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul (evmAdd 0xb9aacfacf3c10b378435f8e22adf48500e v) v))) v))) v))) v)) - let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c3c4 (evmShr 0x80 (evmMul - (evmAdd 0xaf566247c05753b42892f77b67a6b7c6 (evmShr 0x7a (evmMul - (evmAdd 0xad4506af99be27419341e1816ff351 (evmShr 0x84 (evmMul - (evmAdd 0xc926ddbecdeeb42e68cd16db7da8c1 (evmShr 0x7e (evmMul + let od := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x80 (evmMul + (evmAdd 0xaf566247c05753b42892f77b67a6b7c7 (evmShr 0x7a (evmMul + (evmAdd 0xad4506af99be27419341e181693281 (evmShr 0x84 (evmMul + (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2161b482a02) + let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) ) := by diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 385c44ea9..9b47747f4 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -36,9 +36,9 @@ library Exp { // t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational that matches // `Od/Ev` to `tanh(√v/2)/√v` on v = t² ∈ [0, (ln(2)/2)²]. Ev(v) is degree 5 and Od(v) // degree 4; in exact arithmetic this (4,5) form approximates exp to ≈135 bits, and the - // integer coefficients realize ≈131 of them: each coefficient's low bits are chosen + // integer coefficients realize ≈133 of them: each coefficient's low bits are chosen // jointly, after rounding at the staircase bases, to re-center the ten quantization - // residuals, holding the realized envelope at ≤ 0.019 ulp. Ev(v) is monic, so its leading + // residuals, holding the realized envelope at ≤ 0.0075 ulp. Ev(v) is monic, so its leading // stage is just an add. // // Mixed fixed-point bases (a staircase): each coefficient takes the widest basis fitting @@ -61,7 +61,7 @@ library Exp { // Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the // exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the // tightest bound the proof technique can bear, in spite of the fact that the worst-case - // error contributions do not co-occur. The budget bounds Δ ≤ 0.6013505372794194988, the sum + // error contributions do not co-occur. The budget bounds Δ ≤ 0.5792534503673398887, the sum // of four one-sided contributions (displayed rounded up, so the shown values overshoot Δ): // integer Horner + closing `DIV` truncation: the Ev shared by the numerator Ev + t⋅Od // and denominator Ev - t⋅Od cancels to first order in the quotient, so its @@ -73,16 +73,16 @@ library Exp { // is floored piecewise over 32 domain pieces (the pointwise supremum is ≈ 0.3287 at // t = ln(2)/2). The t < 0 direction is budgeted on the under side. // rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): - // < 0.04420 (its supremum is √2⋅2¹²⁶/(2¹³¹-1)). + // < 0.02210 (its supremum is √2⋅2¹²⁶/(2¹³²-1)). // reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is // budgeted on the under side); the over side is the K27/LN2 constant-grid residue // (the k⋅ln(2) grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = // √2/128). // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0652 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer - // on the 2¹⁰⁸ output grid strictly above Δ's image: 0x2161b482a02 = ⌊5¹⁸⋅Δ⌋ + 1 = - // 2293970250242 (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never + // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0628 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer + // on the 2¹⁰⁸ output grid strictly above Δ's image: 0x2027afc6c05 = ⌊5¹⁸⋅Δ⌋ + 1 = + // 2209676553221 (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never // overestimate requirement). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E. The under side is bounded to the // same precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 31/10, where 31/10 bounds the sum of the // integer-rational deficit (≤ 5/2, the Horner/`DIV`/floor truncation against the @@ -90,10 +90,10 @@ library Exp { // reduced-argument gap (≤ 37/100, via exp(t) ≤ √2), and the under-direction argument // granularity (≤ 17/100: the same one-grain envelope with the negative-half denominator // floor). Hence the maximum underestimation of the pre-floor accumulator A is E - A ≤ - // ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶³ ≈ 0.40131 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The + // ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶³ ≈ 0.39891 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The // deficit envelope ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave and first // exceeds 1ulp at k = 65; the guard pins the supported range at k ≤ 63. On the central - // octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 7.1⋅10⁻²¹ ulp, far + // octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 6.8⋅10⁻²¹ ulp, far // below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. The k = 0 // band is exactly [-H, H] with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, // √2). @@ -130,20 +130,24 @@ library Exp { // monic-stage product below stays inside 256 bits. let v := shr(0x85, mul(t, t)) + // Shared constant term of Ev and Od: Ev(0) = 2⋅Od(0) by construction, so at closing + // bases one bit apart (Q88/Q89) both constant terms are the same literal. + let c0 := 0x9c2948bcaca16a0dd2fe98bb4470c388 + // Ev(v), monic, Horner down the staircase. The leading v⁵ coefficient is 1, so the // first stage is just an add. let ev := add(0xb9aacfacf3c10b378435f8e22adf48500e, v) - ev := add(0x9a036222841f47c6ed6fc3f7602053, shr(0x95, mul(ev, v))) - ev := add(0x9064d9657e9a21fc16bb69331c5c3057, shr(0x7b, mul(ev, v))) - ev := add(0x93f11e650dd6c64b96ce79065cdf809e, shr(0x81, mul(ev, v))) - ev := add(0x9c2948bcaca16a0dd2fe98bb4470c3c4, shr(0x7e, mul(ev, v))) + ev := add(0x9a036222841f47c6ed6fc3f7599445, shr(0x95, mul(ev, v))) + ev := add(0x9064d9657e9a21fc16bb69331b81ae1e, shr(0x7b, mul(ev, v))) + ev := add(0x93f11e650dd6c64b96ce79065cdf80f4, shr(0x81, mul(ev, v))) + ev := add(c0, shr(0x7e, mul(ev, v))) // Od(v), Horner down the staircase. let od := 0xdc07aff8276bde9a361278df6a10 - od := add(0xc926ddbecdeeb42e68cd16db7da8c1, shr(0x7e, mul(od, v))) - od := add(0xad4506af99be27419341e1816ff351, shr(0x84, mul(od, v))) - od := add(0xaf566247c05753b42892f77b67a6b7c6, shr(0x7a, mul(od, v))) - od := add(0x9c2948bcaca16a0dd2fe98bb4470c3c4, shr(0x80, mul(od, v))) + od := add(0xc926ddbecdeeb42e68cd16db7ed378, shr(0x7e, mul(od, v))) + od := add(0xad4506af99be27419341e181693281, shr(0x84, mul(od, v))) + od := add(0xaf566247c05753b42892f77b67a6b7c7, shr(0x7a, mul(od, v))) + od := add(c0, shr(0x80, mul(od, v))) // t⋅Od in Q88 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are // both positive. @@ -154,10 +158,10 @@ library Exp { r := div(shl(0x7e, add(ev, tod)), sub(ev, tod)) // E on the 2¹⁰⁸ output grid (5¹⁸ = 10¹⁸/2¹⁸ multiplies the Q126 quotient), less the - // one-sided margin (0x2161b482a02 = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then floored by + // one-sided margin (0x2027afc6c05 = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then floored by // `shr(108 - k, …)` which folds in the 2ᵏ octave scaling and the wad unit's remaining // 2¹⁸ (108 - k ∈ [45, 168]). - r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x2161b482a02)) + r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x2027afc6c05)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs From e24c696ba82b8b3fa7d622828ca77a0da96542a6 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Fri, 3 Jul 2026 14:38:53 +0200 Subject: [PATCH 139/149] Comment style; clarity --- src/vendor/Exp.sol | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 9b47747f4..878eb2b35 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -26,7 +26,7 @@ library Exp { function _expRayToWad(int256 x) private pure returns (int256 r) { // Equivalent pseudocode; fixed-point truncations are accounted for below: // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln(2) + t)⋅10²⁷, |t| ≤ ln(2)/2 - // t = x/10²⁷ - k⋅ln(2); // reduced argument (Q128) + // t = x/10²⁷ - k⋅ln(2); // range-reduced argument (Q128) // e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) (Ev Q88; Od Q89; e Q126) // r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; // wad // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 @@ -48,10 +48,9 @@ library Exp { // v = t²: Q123 the widest basis whose monic-stage product stays inside 256 bits, so // Ev(v)'s leading stage consumes v with no renormalizing shift // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q88 (monic) - // Od(v) Horner along the staircase Q105 → Q102 → Q93 → Q94 → Q89 - // Ev, t⋅Od, and the numerator/denominator: Q88; Od: Q89. The closing bases are the - // widest at which each final coefficient keeps its byte width and the t⋅Od product - // stays inside 256 bits; the t⋅Od `sar` lands at Q88 directly + // Od(v) Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q89 + // t⋅Od and the numerator/denominator: Q88. The closing bases are the widest at which + // the t⋅Od intermediate product stays inside 256 bits // quotient: one `DIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays // below 2²⁵⁵) // output: multiplying by 5¹⁸ lands E on the 2¹⁰⁸ output grid (the 10¹⁸⋅2¹²⁶ grid with @@ -62,7 +61,7 @@ library Exp { // exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the // tightest bound the proof technique can bear, in spite of the fact that the worst-case // error contributions do not co-occur. The budget bounds Δ ≤ 0.5792534503673398887, the sum - // of four one-sided contributions (displayed rounded up, so the shown values overshoot Δ): + // of four one-sided contributions: // integer Horner + closing `DIV` truncation: the Ev shared by the numerator Ev + t⋅Od // and denominator Ev - t⋅Od cancels to first order in the quotient, so its // truncation barely perturbs e; this jitter stays < 0.21706. @@ -130,8 +129,8 @@ library Exp { // monic-stage product below stays inside 256 bits. let v := shr(0x85, mul(t, t)) - // Shared constant term of Ev and Od: Ev(0) = 2⋅Od(0) by construction, so at closing - // bases one bit apart (Q88/Q89) both constant terms are the same literal. + // Ev(0) = 2⋅Od(0) by construction, so at closing bases one bit apart (Q88/Q89) the + // constant terms are the same. let c0 := 0x9c2948bcaca16a0dd2fe98bb4470c388 // Ev(v), monic, Horner down the staircase. The leading v⁵ coefficient is 1, so the @@ -163,7 +162,7 @@ library Exp { // 2¹⁸ (108 - k ∈ [45, 168]). r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x2027afc6c05)) - // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x + // Zero the result at and below C = ⌊-18⋅ln(10)⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs // where the reduction would overflow, so it also discards those (otherwise garbage). r := mul(slt(0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7, x), r) From 8b3045d0f3d79a5f2b202419f2ee744b26b72f50 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Fri, 3 Jul 2026 14:40:51 +0200 Subject: [PATCH 140/149] Formatting --- src/vendor/Exp.sol | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 878eb2b35..068a8e65a 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -79,8 +79,8 @@ library Exp { // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = // √2/128). // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0628 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer - // on the 2¹⁰⁸ output grid strictly above Δ's image: 0x2027afc6c05 = ⌊5¹⁸⋅Δ⌋ + 1 = + // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0628 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least + // integer on the 2¹⁰⁸ output grid strictly above Δ's image: 0x2027afc6c05 = ⌊5¹⁸⋅Δ⌋ + 1 = // 2209676553221 (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never // overestimate requirement). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E. The under side is bounded to the // same precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 31/10, where 31/10 bounds the sum of the @@ -92,10 +92,9 @@ library Exp { // ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶³ ≈ 0.39891 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The // deficit envelope ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave and first // exceeds 1ulp at k = 65; the guard pins the supported range at k ≤ 63. On the central - // octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 6.8⋅10⁻²¹ ulp, far - // below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. The k = 0 - // band is exactly [-H, H] with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, - // √2). + // octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 6.8⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap + // `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. The k = 0 band is exactly [-H, H] + // with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). // // Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves the // pre-floor accumulator by at least 5¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 2.3⋅10²³ grid units. The error From 250589390058f2d34a73692d2f60f8435e18fd3e Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Fri, 3 Jul 2026 18:59:09 +0200 Subject: [PATCH 141/149] Extend the supported exp range through the k = 64 octave The revert threshold moves to the k = 65 boundary, 0x907595ccd30708cabec8a9db = ceil((65*2^200 - 2^199)/CINV) ~= 44.71e27 (E up to ~2.61e37): with the refit budget the deficit envelope ((31/10)*10^18 + 2^18*MARGIN)/2^(126-k) is 0.79781 at k = 64 and first exceeds one ulp at k = 65, so the guard now sits exactly where floor-or-one-less stops being certifiable. The octave count spans [-61, 64], the closing shift [44, 168], and the k*ln2 grid-residue and round-trip deficit chains carry the widened bounds (64/2^235 and ((31/10)*WAD + MARGIN)/2^44 respectively, each with ample slack). Every documented property is unchanged in form; the certificate layer is untouched and regeneration is byte-identical. Tests cover the new octave: never-overestimate witnesses with frac(E) > 0.9999 at k = 64, the supported-edge bracket (frac(E) ~= 0.52 inside the 0.80 envelope) beside the exact k = 63 top floor, a k = 64 one-ulp-underestimate witness at the octave's first input, and the boundary-monotonicity loop through the k = 65 seam. Full lake build is green from the Theorems.lean axiom gates (the public revert statement carries the new threshold); validated against a 60-digit reference across the new octave and its seams. Co-Authored-By: Claude Fable 5 --- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 12 ++--- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 4 +- .../exp/ExpProof/ExpProof/Floor/Reduce.lean | 30 ++++++------- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 24 +++++----- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 2 +- .../exp/ExpProof/ExpProof/Floor/TBound.lean | 4 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 4 +- formal/exp/ExpProof/ExpProof/Mono/Octave.lean | 14 +++--- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 34 +++++++------- .../ExpProof/ExpProof/Mono/RegionMono.lean | 2 +- .../exp/ExpProof/ExpProof/Mono/RunBridge.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Top.lean | 6 +-- formal/exp/ExpProof/ExpProof/Seam/Guard.lean | 44 +++++++++---------- .../exp/ExpProof/ExpProof/Seam/Helpers.lean | 12 ++--- formal/exp/ExpProof/ExpProof/Seam/Revert.lean | 12 ++--- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 18 ++++---- formal/exp/ExpProof/ExpProof/Theorems.lean | 6 +-- src/vendor/Exp.sol | 22 +++++----- test/0.8.34/Exp.t.sol | 40 ++++++++++++----- 20 files changed, 157 insertions(+), 137 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index 2701625b4..62c30bf42 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -9,7 +9,7 @@ import ExpProof.Seam.RealExp The per-point `r0`-vs-`exp` brackets (`r0_real_over_within`, `r0_real_under_within`) and the below-clamp bound (`belowC_target_lt_one`) establish the never-over and deficit-under-one facts about the real pre-floor accumulator unconditionally and axiom-clean, via the octave fold -`E·2^s = WAD·2¹⁰⁸·exp(rt)` (`WAD = 5¹⁸`; `s = 108 − k`, the closing shift; `k ≤ 63` so `s ≥ 45`). +`E·2^s = WAD·2¹⁰⁸·exp(rt)` (`WAD = 5¹⁸`; `s = 108 − k`, the closing shift; `k ≤ 64` so `s ≥ 44`). * `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 5792534503673398887/10000000000000000000` and `5¹⁸·5792534503673398887/10000000000000000000 ≤ MARGIN`; * `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 31/10` and `(31/10)·5¹⁸ + MARGIN < 2⁴⁵ ≤ 2^s`. @@ -75,9 +75,9 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 rw [hfold] have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 31 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num - have hs45 : (45 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] - have hs45n : 45 ≤ s := by exact_mod_cast hs45 - have hpow : (2 ^ 45 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs45n + have hs44 : (44 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs44n : 44 ≤ s := by exact_mod_cast hs44 + have hpow : (2 ^ 44 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs44n rw [hwad] have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by @@ -88,8 +88,8 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hscaled : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 31 / 10) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - -- (31/10)·5^18 + MARGIN < 2^45 - have hbudget : (3814697265625 : Real) * (31 / 10) + 2209676553221 < (2 ^ 45 : Real) := by + -- (31/10)·5^18 + MARGIN < 2^44 + have hbudget : (3814697265625 : Real) * (31 / 10) + 2209676553221 < (2 ^ 44 : Real) := by norm_num linarith [hscaled, hbudget, hpow] -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index cadffa79b..e112395db 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -12,8 +12,8 @@ This module contains the counterpart to the never-over `r0_real_over_within`: th 3. the `Mp` factor, `≤ 1/20` (via `r0 ≤ 1.45·2¹²⁶`); 4. the under-direction reduced-argument gap, `≤ 37/100` (via `exp(rt) ≤ √2·(1+ε)`). -The sum `2500/1000 + 1/20 + 1644901622230542074/10¹⁹ + 37/100 ≤ 31/10` feeds the `k = 63` deficit -envelope `((31/10)·5¹⁸·2¹⁸ + 2¹⁸·MARGIN)/2⁶³ < 1`. The module closes with the octave-seam `r0`-doubling +The sum `2500/1000 + 1/20 + 1644901622230542074/10¹⁹ + 37/100 ≤ 31/10` feeds the `k = 64` deficit +envelope `((31/10)·5¹⁸·2¹⁸ + 2¹⁸·MARGIN)/2⁶² < 1`. The module closes with the octave-seam `r0`-doubling bound `r0₁ + 2 ≤ 2·r0₂` (`SeamR0Bound`), where the `1 − exp(−1/RAY)` seam slack (≈ `1.7·10¹¹` grid units against `r0₂ > 2¹²⁴`) dwarfs both per-point budgets and the two integer units. -/ diff --git a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean index 0eddcbcec..c417555df 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean @@ -18,7 +18,7 @@ Decompose `rt − t/2¹²⁸ = P1 + P2 + P3`: * `P1 = X·(1/RAY − K27/2²³⁵)` — the rational coefficient error over `|X| < 2⁹⁶`, below `2⁻¹³³`; * `P2 = k·(LN2/2²³⁵ − ln2)` — the `ln2`-grid error (`0 ≤ ln2 − LN2/2²³⁵ < 2⁻²³⁵`, from `Ln2Bound`) - over `|k| ≤ 63`, below `2⁻²²⁹`; + over `|k| ≤ 64`, below `2⁻²²⁹`; * `P3 = (K27·X − LN2·k)/2²³⁵ − t/2¹²⁸ ∈ [0, 1/2¹²⁸)` — the integer `t`-rounding sandwich. The sum is below `2/2¹²⁸`. @@ -123,23 +123,23 @@ theorem reducedArg_close_over {x : Nat} (hx : x < 2 ^ 256) have hP2_hi : -(1 / N235) ≤ LN2R / N235 - LR := by have : LR ≤ (LN2R + 1) / N235 := hln2hi rw [add_div] at this; linarith [this] - -- |k| ≤ 63 ⇒ |P2| ≤ 63/N235 < 1/N128 + -- |k| ≤ 64 ⇒ |P2| ≤ 64/N235 < 1/N128 have hkloR : -(61 : Real) ≤ kR := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] - have hkhiR : kR ≤ (63 : Real) := by + have hkhiR : kR ≤ (64 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] have hP2_abs : |P2| < 1 / (64 * N128) := by rw [hP2def] - have h1 : |kR| ≤ 63 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h1 : |kR| ≤ 64 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by rw [abs_le] refine ⟨by linarith [hP2_hi], ?_⟩ have hpos : (0:Real) ≤ 1 / N235 := by positivity linarith [hP2_lo, hpos] - have hbound : |kR * (LN2R / N235 - LR)| ≤ 63 * (1 / N235) := by + have hbound : |kR * (LN2R / N235 - LR)| ≤ 64 * (1 / N235) := by rw [abs_mul] exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) - have hlt : 63 * (1 / N235) < 1 / (64 * N128) := by + have hlt : 64 * (1 / N235) < 1 / (64 * N128) := by rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num linarith [hbound, hlt] -- bound P3 ∈ [0, 1/N128) from the integer sandwich @@ -253,20 +253,20 @@ theorem reducedArg_close_under {x : Nat} (hx : x < 2 ^ 256) rw [add_div] at this; linarith [this] have hkloR : -(61 : Real) ≤ kR := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] - have hkhiR : kR ≤ (63 : Real) := by + have hkhiR : kR ≤ (64 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] have hP2_abs : |P2| < 1 / (64 * N128) := by rw [hP2def] - have h1 : |kR| ≤ 63 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h1 : |kR| ≤ 64 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by rw [abs_le] refine ⟨by linarith [hP2_hi], ?_⟩ have hpos : (0:Real) ≤ 1 / N235 := by positivity linarith [hP2_lo, hpos] - have hbound : |kR * (LN2R / N235 - LR)| ≤ 63 * (1 / N235) := by + have hbound : |kR * (LN2R / N235 - LR)| ≤ 64 * (1 / N235) := by rw [abs_mul] exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) - have hlt : 63 * (1 / N235) < 1 / (64 * N128) := by + have hlt : 64 * (1 / N235) < 1 / (64 * N128) := by rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num linarith [hbound, hlt] have hP3int_hi : 55213970774324510299478046898216203619608872 * X - @@ -382,23 +382,23 @@ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) have hP2_hi : -(1 / N235) ≤ LN2R / N235 - LR := by have : LR ≤ (LN2R + 1) / N235 := hln2hi rw [add_div] at this; linarith [this] - -- |k| ≤ 63 ⇒ |P2| ≤ 63/N235 < 1/N128 + -- |k| ≤ 64 ⇒ |P2| ≤ 64/N235 < 1/N128 have hkloR : -(61 : Real) ≤ kR := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] - have hkhiR : kR ≤ (63 : Real) := by + have hkhiR : kR ≤ (64 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] have hP2_abs : |P2| < 1 / (64 * N128) := by rw [hP2def] - have h1 : |kR| ≤ 63 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h1 : |kR| ≤ 64 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by rw [abs_le] refine ⟨by linarith [hP2_hi], ?_⟩ have hpos : (0:Real) ≤ 1 / N235 := by positivity linarith [hP2_lo, hpos] - have hbound : |kR * (LN2R / N235 - LR)| ≤ 63 * (1 / N235) := by + have hbound : |kR * (LN2R / N235 - LR)| ≤ 64 * (1 / N235) := by rw [abs_mul] exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) - have hlt : 63 * (1 / N235) < 1 / (64 * N128) := by + have hlt : 64 * (1 / N235) < 1 / (64 * N128) := by rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num linarith [hbound, hlt] -- bound P3 ∈ [0, 1/N128) from the integer sandwich diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index ed2b69d6a..27bf4f36a 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -73,8 +73,8 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < /-- **Accumulator deficit, region-uniform.** On the region the accumulator is below the target by strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 31/10` and the -octave fold give `accumReal x ≥ E − ((31/10)·WAD + MARGIN)/2^s` with `s = 108 − k ≥ 45`, and -`((31/10)·WAD + MARGIN)/2⁴⁵ ≈ 0.835 < 24/25`. The tightness below one is what closes the round trip +octave fold give `accumReal x ≥ E − ((31/10)·WAD + MARGIN)/2^s` with `s = 108 − k ≥ 44`, and +`((31/10)·WAD + MARGIN)/2⁴⁴ ≈ 0.798 < 24/25`. The tightness below one is what closes the round trip together with `lnWadToRay`'s ≈10⁻⁹ envelope. -/ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -85,11 +85,11 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask have hunder := r0_real_under_within hx hC hC0 obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - have hs45 : (45 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] - have hs45n : 45 ≤ s := by exact_mod_cast hs45 - have hpow : (2 ^ 45 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs45n + have hs44 : (44 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs44n : 44 ≤ s := by exact_mod_cast hs44 + have hpow : (2 ^ 44 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs44n -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = 5^18·2^126·Ert ≤ WAD·(r0 + 31/10) - -- and (31/10)·WAD + MARGIN < (24/25)·2^45 ≤ (24/25)·2^s + -- and (31/10)·WAD + MARGIN < (24/25)·2^44 ≤ (24/25)·2^s have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = @@ -99,7 +99,7 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask have h8wad : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 31 / 10) := mul_le_mul_of_nonneg_left hr0R (by norm_num) - have hbudget : (3814697265625 : Real) * (31 / 10) + 2209676553221 < (24 / 25) * (2 ^ 45 : Real) := by + have hbudget : (3814697265625 : Real) * (31 / 10) + 2209676553221 < (24 / 25) * (2 ^ 44 : Real) := by norm_num rw [hwad] at hkey have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = @@ -111,8 +111,8 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask have hEs : expRayToWadTarget (int256 x) * (2 ^ s : Real) ≤ (3814697265625 : Real) * (int256 (r0Tree x) : Real) + (3814697265625 : Real) * (31 / 10) := by rw [hkey]; nlinarith [h8wad] - -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; (24/25)·2^s ≥ (24/25)·2^45 - have h2425 : (24 / 25 : Real) * (2 ^ 45 : Real) ≤ (24 / 25) * (2 ^ s : Real) := + -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; (24/25)·2^s ≥ (24/25)·2^44 + have h2425 : (24 / 25 : Real) * (2 ^ 44 : Real) ≤ (24 / 25) * (2 ^ s : Real) := mul_le_mul_of_nonneg_left hpow (by norm_num) nlinarith [hEs, hbudget, hpow, h2425] rw [hAeq, lt_div_iff₀ hps]; linarith [hbound] @@ -225,7 +225,7 @@ theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) linarith [hmul, h2wd] -- region membership of r have hCmask : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0 : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh + have hC0 : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh -- L > log(1/2) = −log 2 > −1 ; X = 10^27·L > −10^27 ; r ≥ X − 2 > Cmask have hLgt : -(1 : Real) < L := by have h12 : Real.log ((1:Real)/2) < L := by @@ -249,8 +249,8 @@ theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) · -- r < C0thresh : r ≤ 10^27·L < 10^27 < C0thresh rw [hC0] have hXhi : (10 ^ 27 : Real) * L < (10 ^ 27 : Real) := by nlinarith [hLlt] - have : (r : Real) < (44014845965556527147994239713 : Real) := by - have hc : (10 ^ 27 : Real) < (44014845965556527147994239713 : Real) := by norm_num + have : (r : Real) < (44707993146116472457411471835 : Real) := by + have hc : (10 ^ 27 : Real) < (44707993146116472457411471835 : Real) := by norm_num linarith [hr_le, hXhi, hc] exact_mod_cast this diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index bfdae241e..e55d03d8b 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -9,7 +9,7 @@ import ExpProof.Mono.RangeNonneg `run_exp_ray_to_wad_evm_eq_expTree` returns `expTree x`, the clamp/pin shell around the floored accumulator `r1Tree x = shr(108 − k, WAD·r0 − MARGIN)`. On the meaningful region the closing shift -`s = 108 − k ∈ [45, 169]` is positive and the shift argument `arg = WAD·r0 − MARGIN` is a +`s = 108 − k ∈ [44, 169]` is positive and the shift argument `arg = WAD·r0 − MARGIN` is a nonnegative canonical word, so the runtime result is exactly the integer floor `⌊arg / 2^s⌋` of the *real* pre-floor accumulator diff --git a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean index 531f04d50..76cadeb01 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean @@ -35,7 +35,7 @@ theorem tTree_in_cert_domain {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hkblo, hkbhi⟩ := kTree_bound hx hC hC0 -- region endpoints as decimals have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh + have hC0i : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh rw [hCi] at hC rw [hC0i] at hC0 -- constants as decimals @@ -61,7 +61,7 @@ theorem tTree_in_cert_domain {x : Nat} (hx : x < 2 ^ 256) rw [p107] at htlo hthi rw [p199, p200] at hklo hkhi clear_value k - -- For each fixed integer octave index `k ∈ [−61, 63]` the band of consistent `x` together with + -- For each fixed integer octave index `k ∈ [−61, 64]` the band of consistent `x` together with -- the reduction sandwich pins `t` to the cert domain; `omega` closes each band (the coupling is -- linear in `x` and `t` once `k` is a literal). clear htdef hXdef hkdef hCi hC0i hK27 hLN2 hCINV pH p107 p199 p200 hx hxlo hxhi diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index a274ec639..4330f2510 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -7,7 +7,7 @@ open FormalYul.Preservation /-! Runtime constants used by the generated exp kernel normal form. -/ abbrev Cmask : Nat := 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 -abbrev C0thresh : Nat := 0x8e383a2cdfa1b74a9422d2e1 +abbrev C0thresh : Nat := 0x907595ccd30708cabec8a9db abbrev kRoundShift : Nat := 0xc8 abbrev kHalfShift : Nat := 0xc7 @@ -52,7 +52,7 @@ theorem Cmask_lt : Cmask < 2 ^ 256 := by unfold Cmask norm_num -theorem int256_C0thresh : int256 C0thresh = 44014845965556527147994239713 := by +theorem int256_C0thresh : int256 C0thresh = 44707993146116472457411471835 := by unfold C0thresh int256 norm_num diff --git a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean index d9067668a..41ab077af 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean @@ -10,7 +10,7 @@ bounds, and proves `k` is nondecreasing in `int256 x` and (for a fixed `k`) `t` `int256 x`. Constants and their bit widths (so every product stays below `2^255`): -`CINV` 111 bits, `K27` 146 bits, `LN2` 235 bits, `|int256 x| < 2^96`, `k ∈ [-61, 63]`. +`CINV` 111 bits, `K27` 146 bits, `LN2` 235 bits, `|int256 x| < 2^96`, `k ∈ [-61, 64]`. -/ namespace ExpYul @@ -25,7 +25,7 @@ theorem region_x_bound {x : Nat} (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : -(2 ^ 96 : Int) < int256 x ∧ int256 x < 2 ^ 96 := by rw [int256_Cmask] at hC - have hC0' : int256 x < 44014845965556527147994239713 := by + have hC0' : int256 x < 44707993146116472457411471835 := by rw [int256_C0thresh] at hC0 exact hC0 constructor <;> [skip; skip] <;> simp only [show (2:Int)^96 = 79228162514264337593543950336 from by norm_num] <;> omega @@ -123,13 +123,13 @@ theorem kTree_mono {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hpow : (0 : Int) < 2 ^ 200 := by norm_num nlinarith [hlo1, hhi2, hargle, hpow] -/-- On the meaningful region the octave index is bounded: `-61 ≤ k ≤ 63`. -/ +/-- On the meaningful region the octave index is bounded: `-61 ≤ k ≤ 64`. -/ theorem kTree_bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - -61 ≤ int256 (kTree x) ∧ int256 (kTree x) ≤ 63 := by + -61 ≤ int256 (kTree x) ∧ int256 (kTree x) ≤ 64 := by obtain ⟨hlo, hhi⟩ := kTree_sandwich hx hC hC0 have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh + have hC0i : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh rw [hCi] at hC rw [hC0i] at hC0 have hcinv : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by @@ -139,7 +139,7 @@ theorem kTree_bound {x : Nat} (hx : x < 2 ^ 256) 0x724d54edbacbebbb95c52a0f6076 * (-41446531673892822312323846185) := by rw [hcinv]; nlinarith [hC] have hprod_hi : (0x724d54edbacbebbb95c52a0f6076 : Int) * int256 x < - 0x724d54edbacbebbb95c52a0f6076 * 44014845965556527147994239713 := by + 0x724d54edbacbebbb95c52a0f6076 * 44707993146116472457411471835 := by rw [hcinv]; nlinarith [hC0] constructor · nlinarith [hhi, hprod_lo] @@ -156,7 +156,7 @@ theorem int256_tArg {x : Nat} (hx : x < 2 ^ 256) 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x - 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) := by have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh + have hC0i : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh have hxr := hC; rw [hCi] at hxr have hxr0 := hC0; rw [hC0i] at hxr0 obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean index 430aa0517..01337fc89 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -5,7 +5,7 @@ import ExpProof.Mono.Quot `r1Tree x = shr(108 − k, WAD·r0 − MARGIN)` closes the kernel: it scales the Q126 quotient onto the `5¹⁸·2¹⁰⁸` grid, subtracts the one-sided margin, and floors with the `2ᵏ` octave scaling and the -wad unit's remaining `2¹⁸` folded into the shift (`108 − k ∈ [45, 169]`). +wad unit's remaining `2¹⁸` folded into the shift (`108 − k ∈ [44, 169]`). * **nonneg**: `r0 ≥ 2^123` gives `WAD·r0 > MARGIN`, and the shift argument is nonnegative; the logical shift of a canonical nonnegative word stays nonnegative. @@ -22,11 +22,11 @@ set_option maxRecDepth 100000 /-! ## The closing shift amount `108 − k` -/ -/-- The shift word `evmSub 0x6c k` equals `108 − int256 k` as a `Nat`, and lies in `[45, 169]` on -the meaningful region (`k ∈ [−61, 63]`). -/ +/-- The shift word `evmSub 0x6c k` equals `108 − int256 k` as a `Nat`, and lies in `[44, 169]` on +the meaningful region (`k ∈ [−61, 64]`). -/ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - ∃ s : Nat, evmSub 0x6c (kTree x) = s ∧ 45 ≤ s ∧ s ≤ 169 ∧ + ∃ s : Nat, evmSub 0x6c (kTree x) = s ∧ 44 ≤ s ∧ s ≤ 169 ∧ (s : Int) = 108 - int256 (kTree x) := by obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 have hkw : kTree x < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ @@ -45,8 +45,8 @@ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) have hnn : 0 ≤ int256 (evmSub 0x6c (kTree x)) := by rw [hsub]; omega obtain ⟨heq, hlt255⟩ := int256_eq_of_nonneg hsublt hnn refine ⟨evmSub 0x6c (kTree x), rfl, ?_, ?_, ?_⟩ - · -- 45 ≤ s - have : (45 : Int) ≤ ((evmSub 0x6c (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega + · -- 44 ≤ s + have : (44 : Int) ≤ ((evmSub 0x6c (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega exact_mod_cast this · have : ((evmSub 0x6c (kTree x) : Nat) : Int) ≤ 169 := by rw [← heq, hsub]; omega exact_mod_cast this @@ -97,26 +97,26 @@ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) /-! ## Abstract floor facts for the closing shift -/ -/-- Abstract closing-shift facts over an opaque shift argument word `W` and shift `s ∈ [45, 169]` -with `int256 W ∈ [0, 2^170)`: the floor `shr(s, W)` is nonnegative and below `2^125`. -/ -theorem closingShr_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 45 ≤ s) (hshi : s ≤ 169) +/-- Abstract closing-shift facts over an opaque shift argument word `W` and shift `s ∈ [44, 169]` +with `int256 W ∈ [0, 2^170)`: the floor `shr(s, W)` is nonnegative and below `2^126`. -/ +theorem closingShr_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 44 ≤ s) (hshi : s ≤ 169) (hWnn : 0 ≤ int256 W) (hWhi : int256 W < 2 ^ 170) : - 0 ≤ int256 (evmShr s W) ∧ int256 (evmShr s W) < 2 ^ 125 := by + 0 ≤ int256 (evmShr s W) ∧ int256 (evmShr s W) < 2 ^ 126 := by obtain ⟨hWi, _⟩ := int256_eq_of_nonneg hWw hWnn have hWnat : W < 2 ^ 170 := by have : ((W : Nat) : Int) < 2 ^ 170 := by rw [← hWi]; exact hWhi exact_mod_cast this rw [evmShr_eq_div (by omega) hWw] - have hqlt : W / 2 ^ s < 2 ^ 125 := by - have h45 : (2:Nat) ^ 45 ≤ 2 ^ s := Nat.pow_le_pow_right (by norm_num) hslo - have h1 : W / 2 ^ s ≤ W / 2 ^ 45 := Nat.div_le_div_left h45 (Nat.two_pow_pos _) - have h2 : W / 2 ^ 45 < 2 ^ 125 := by + have hqlt : W / 2 ^ s < 2 ^ 126 := by + have h44 : (2:Nat) ^ 44 ≤ 2 ^ s := Nat.pow_le_pow_right (by norm_num) hslo + have h1 : W / 2 ^ s ≤ W / 2 ^ 44 := Nat.div_le_div_left h44 (Nat.two_pow_pos _) + have h2 : W / 2 ^ 44 < 2 ^ 126 := by rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] calc W < 2 ^ 170 := hWnat - _ = 2 ^ 125 * 2 ^ 45 := by rw [← Nat.pow_add] + _ = 2 ^ 126 * 2 ^ 44 := by rw [← Nat.pow_add] omega rw [int256_of_lt (by - have : (2:Nat) ^ 125 < 2 ^ 255 := by norm_num + have : (2:Nat) ^ 126 < 2 ^ 255 := by norm_num omega)] constructor · positivity @@ -158,7 +158,7 @@ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) rw [← hReq] at hnn hlt have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x obtain ⟨hi, _⟩ := int256_eq_of_nonneg hr1w hnn - have hp254 : (2:Int)^125 < 2^254 := by norm_num + have hp254 : (2:Int)^126 < 2^254 := by norm_num have hcast : ((r1Tree x : Nat) : Int) < 2 ^ 254 := by rw [← hi] generalize int256 (r1Tree x) = V at hlt ⊢ diff --git a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean index 68f1407fc..ae48f6ce0 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean @@ -69,7 +69,7 @@ theorem r1_step (hseamstep : SeamStep) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : /-- A signed value strictly inside the region is a canonical word with that signed value. -/ theorem region_word {v : Int} (hlo : int256 Cmask < v) (hhi : v < int256 C0thresh) : uint256OfInt v < 2 ^ 256 ∧ int256 (uint256OfInt v) = v := by - have hC0 : int256 C0thresh = 44014845965556527147994239713 := int256_C0thresh + have hC0 : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh have hCm : int256 Cmask = -41446531673892822312323846185 := int256_Cmask rw [hCm] at hlo; rw [hC0] at hhi refine ⟨uint256OfInt_lt v, ?_⟩ diff --git a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean index 4be384abc..366ff24d5 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean @@ -19,7 +19,7 @@ set_option maxRecDepth 100000 /-- `expTree x` is the inline value tree. -/ theorem run_exp_ray_to_wad_evm_eq_expTree (x : Nat) - (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : run_exp_ray_to_wad_evm x = .ok (expTree x) := by rw [run_exp_ray_to_wad_evm_eq_tree x hval] unfold expTree r1Tree r0Tree todTree odTree evTree vTree tTree kTree diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean index 20d074b44..640e97d78 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -70,7 +70,7 @@ theorem seam_close {arg1 arg2 s1 s2 : Nat} rw [int256_of_lt hq1lt, int256_of_lt hq2lt] exact_mod_cast hqle -/-- The closing shifts at a seam differ by one (`s2 = s1 − 1`), both in `[45, 169]`. -/ +/-- The closing shifts at a seam differ by one (`s2 = s1 − 1`), both in `[44, 169]`. -/ theorem seam_closing_shifts {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hx2 : x2 < 2 ^ 256) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index 9ef7b40fa..fc228c16e 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -137,15 +137,15 @@ theorem expTree_mono (H : RegionMonotonicityFacts) {x1 x2 : Nat} /-- A canonical word strictly below the supported threshold is in the non-reverting run domain. -/ theorem domain_of_below_C0 {x : Nat} (hx : x < 2 ^ 256) (h : int256 x < int256 C0thresh) : - u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ u256 x := by + u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ u256 x := by rw [u256_id hx] rw [int256_C0thresh] at h by_cases hb : x < 2 ^ 255 · left have : int256 x = (x : Int) := int256_of_lt hb rw [this] at h - have : (x : Int) < 44014845965556527147994239713 := h - have hC0 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) = 44014845965556527147994239713 := by norm_num + have : (x : Int) < 44707993146116472457411471835 := h + have hC0 : (0x907595ccd30708cabec8a9db : Nat) = 44707993146116472457411471835 := by norm_num rw [hC0]; exact_mod_cast h · right; omega diff --git a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean index ba3f7a5a1..948401190 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean @@ -3,8 +3,8 @@ import Common.Word /-! # The overflow-guard comparison -`fun_expRayToWad_68` branches on `iszero(slt(x, C))` with `C = 0x8e383a2cdfa1b74a9422d2e1` -(`= 0x8e383a2cdfa1b74a9422d2e1`, the first input whose octave count reaches 64). For a signed +`fun_expRayToWad_68` branches on `iszero(slt(x, C))` with `C = 0x907595ccd30708cabec8a9db` +(the first input whose octave count reaches 65). For a signed input `x ≥ C` (with `u256 x < 2^255`, i.e. `x` a nonnegative signed value at least `C`), the signed comparison `slt(x, C)` is `0`, so the guard `iszero(slt(x, C))` is `1` and the revert branch is taken. Both `x` and `C` are below `2^255`, so neither is a negative signed value and the @@ -18,31 +18,31 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-- `C = 0x8e383a2cdfa1b74a9422d2e1` is below `2^255` (it is `≈ 2^95`). -/ -theorem thresh_lt_pow : (0x8e383a2cdfa1b74a9422d2e1 : Nat) < 2 ^ 255 := by decide +/-- `C = 0x907595ccd30708cabec8a9db` is below `2^255` (it is `≈ 2^95`). -/ +theorem thresh_lt_pow : (0x907595ccd30708cabec8a9db : Nat) < 2 ^ 255 := by decide /-- The overflow guard `slt(x, C)` is the word `0` for a signed input at or above the threshold, so `iszero(slt(x, C))` is `1` and the revert branch fires. -/ theorem slt_thresh_ge {x : Nat} - (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ u256 x) (h2 : u256 x < 2 ^ 255) : + (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ u256 x) (h2 : u256 x < 2 ^ 255) : EvmYul.UInt256.slt (EvmYul.UInt256.ofNat x) - (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1) + (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db) = EvmYul.UInt256.ofNat 0 := by have hx : (EvmYul.UInt256.ofNat x).toNat = u256 x := by have := wordNat_ofNat x; simpa [wordNat] using this - have hC : (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1).toNat - = 0x8e383a2cdfa1b74a9422d2e1 := by - have := wordNat_ofNat 0x8e383a2cdfa1b74a9422d2e1 + have hC : (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db).toNat + = 0x907595ccd30708cabec8a9db := by + have := wordNat_ofNat 0x907595ccd30708cabec8a9db simpa [wordNat, u256, WORD_MOD] using this - have hCb : (0x8e383a2cdfa1b74a9422d2e1 : Nat) < 2 ^ 255 := thresh_lt_pow + have hCb : (0x907595ccd30708cabec8a9db : Nat) < 2 ^ 255 := thresh_lt_pow unfold EvmYul.UInt256.slt EvmYul.UInt256.sltBool rw [hx, hC] rw [if_neg (by omega : ¬ (u256 x ≥ 2 ^ 255))] - rw [if_neg (by omega : ¬ ((0x8e383a2cdfa1b74a9422d2e1 : Nat) ≥ 2 ^ 255))] + rw [if_neg (by omega : ¬ ((0x907595ccd30708cabec8a9db : Nat) ≥ 2 ^ 255))] have hnlt : ¬ EvmYul.UInt256.ofNat x - < EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1 := by + < EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db := by show ¬ (EvmYul.UInt256.ofNat x).toNat - < (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1).toNat + < (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db).toNat rw [hx, hC]; omega simp [EvmYul.UInt256.fromBool, hnlt] @@ -50,26 +50,26 @@ theorem slt_thresh_ge {x : Nat} (`x` either a negative signed value, `2^255 ≤ u256 x`, or a nonnegative value below `C`), so `iszero(slt(x, C))` is `0` and the panic branch is skipped (value path). -/ theorem slt_thresh_lt {x : Nat} - (hval : u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ u256 x) : + (hval : u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ u256 x) : EvmYul.UInt256.slt (EvmYul.UInt256.ofNat x) - (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1) + (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db) = EvmYul.UInt256.ofNat 1 := by have hx : (EvmYul.UInt256.ofNat x).toNat = u256 x := by have := wordNat_ofNat x; simpa [wordNat] using this - have hC : (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1).toNat - = 0x8e383a2cdfa1b74a9422d2e1 := by - have := wordNat_ofNat 0x8e383a2cdfa1b74a9422d2e1 + have hC : (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db).toNat + = 0x907595ccd30708cabec8a9db := by + have := wordNat_ofNat 0x907595ccd30708cabec8a9db simpa [wordNat, u256, WORD_MOD] using this - have hCb : (0x8e383a2cdfa1b74a9422d2e1 : Nat) < 2 ^ 255 := thresh_lt_pow + have hCb : (0x907595ccd30708cabec8a9db : Nat) < 2 ^ 255 := thresh_lt_pow unfold EvmYul.UInt256.slt EvmYul.UInt256.sltBool rw [hx, hC] - rw [if_neg (by omega : ¬ ((0x8e383a2cdfa1b74a9422d2e1 : Nat) ≥ 2 ^ 255))] + rw [if_neg (by omega : ¬ ((0x907595ccd30708cabec8a9db : Nat) ≥ 2 ^ 255))] rcases hval with hlt | hneg · rw [if_neg (by omega : ¬ (u256 x ≥ 2 ^ 255))] have hlt' : EvmYul.UInt256.ofNat x - < EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1 := by + < EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db := by show (EvmYul.UInt256.ofNat x).toNat - < (EvmYul.UInt256.ofNat 0x8e383a2cdfa1b74a9422d2e1).toNat + < (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db).toNat rw [hx, hC]; omega simp [EvmYul.UInt256.fromBool, hlt'] · rw [if_pos (by omega : u256 x ≥ 2 ^ 255)] diff --git a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean index ff2c0aadf..2f70eb5c5 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean @@ -88,14 +88,14 @@ theorem call_cleanup_t_rational_44_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] - (.some "cleanup_t_rational_44014845965556527147994239713_by_1") + (.some "cleanup_t_rational_44707993146116472457411471835_by_1") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, - lookup_cleanup_t_rational_44014845965556527147994239713_by_1] - simp only [yulFunction_cleanup_t_rational_44014845965556527147994239713_by_1, + lookup_cleanup_t_rational_44707993146116472457411471835_by_1] + simp only [yulFunction_cleanup_t_rational_44707993146116472457411471835_by_1, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -154,14 +154,14 @@ theorem call_convert_44_to_int256_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : EvmYul.Yul.call (fuel + (extra + 120)) [FormalYul.word v] - (.some "convert_t_rational_44014845965556527147994239713_by_1_to_t_int256") + (.some "convert_t_rational_44707993146116472457411471835_by_1_to_t_int256") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by rw [show fuel + (extra + 120) = (fuel + extra) + 120 by omega] rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, - lookup_convert_t_rational_44014845965556527147994239713_by_1_to_t_int256] - simp only [yulFunction_convert_t_rational_44014845965556527147994239713_by_1_to_t_int256, + lookup_convert_t_rational_44707993146116472457411471835_by_1_to_t_int256] + simp only [yulFunction_convert_t_rational_44707993146116472457411471835_by_1_to_t_int256, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, diff --git a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean index c66a0e642..9b4becfc4 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean @@ -64,7 +64,7 @@ theorem call_fun_expRayToWad_68_revert_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) - (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : EvmYul.Yul.call (fuel + (extra + 1000)) [FormalYul.word x] (.some "fun_expRayToWad_68") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = @@ -78,7 +78,7 @@ theorem call_fun_expRayToWad_68_revert_direct FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have hconv44 := - call_convert_44_to_int256_direct (v := 0x8e383a2cdfa1b74a9422d2e1) (fuel := fuel + extra) (extra := 867) + call_convert_44_to_int256_direct (v := 0x907595ccd30708cabec8a9db) (fuel := fuel + extra) (extra := 867) (shared := shared) (hlookup := hlookup) have hcleanup := call_cleanup_t_int256_direct (v := x) (fuel := fuel + extra) (extra := 965) @@ -111,7 +111,7 @@ theorem call_fun_wrap_expRayToWad_revert_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) - (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : EvmYul.Yul.call (fuel + (extra + 1200)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_97") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = @@ -144,7 +144,7 @@ set_option maxHeartbeats 8000000 in reverts for out-of-range `x`. -/ theorem external_fun_wrap_expRayToWad_calldata_revert (x : Nat) (store : EvmYul.Yul.VarStore) - (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) = @@ -187,7 +187,7 @@ set_option maxHeartbeats 8000000 in (free-pointer `mstore` baked into a `SharedState.mk`, with the extracted `selector` in the store). -/ theorem external_fun_wrap_expRayToWad_dispatcher_state_revert (x : Nat) - (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok @@ -228,7 +228,7 @@ set_option maxHeartbeats 8000000 in `expRayToWad` reverts: the EVM run of the `ExpWrapper` returns `.error "revert"`. -/ theorem run_exp_ray_to_wad_evm_revert (x : Nat) - (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : run_exp_ray_to_wad_evm x = .error "revert" := by have hexec : diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 90ec343f7..36fd1e31e 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -70,7 +70,7 @@ theorem call_fun_expRayToWad_68_zero_direct FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have hconv44 := - call_convert_44_to_int256_direct (v := 0x8e383a2cdfa1b74a9422d2e1) (fuel := fuel + extra) (extra := 767) + call_convert_44_to_int256_direct (v := 0x907595ccd30708cabec8a9db) (fuel := fuel + extra) (extra := 767) (shared := shared) (hlookup := hlookup) have hcleanup := call_cleanup_t_int256_direct (v := 0) (fuel := fuel + extra) (extra := 865) @@ -474,7 +474,7 @@ theorem call_fun_expRayToWad_68_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) - (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word x] (.some "fun_expRayToWad_68") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( @@ -507,7 +507,7 @@ theorem call_fun_expRayToWad_68_direct FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have hconv44 := - call_convert_44_to_int256_direct (v := 0x8e383a2cdfa1b74a9422d2e1) (fuel := fuel + extra) (extra := 767) + call_convert_44_to_int256_direct (v := 0x907595ccd30708cabec8a9db) (fuel := fuel + extra) (extra := 767) (shared := shared) (hlookup := hlookup) have hcleanup := call_cleanup_t_int256_direct (v := x) (fuel := fuel + extra) (extra := 865) @@ -537,7 +537,7 @@ theorem call_fun_wrap_expRayToWad_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) - (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_97") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( @@ -590,7 +590,7 @@ set_option maxHeartbeats 16000000 in `evm*` tree. -/ theorem external_fun_wrap_expRayToWad_calldata_result (x : Nat) (store : EvmYul.Yul.VarStore) - (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : ((match EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) @@ -717,7 +717,7 @@ set_option maxHeartbeats 16000000 in /-- The external entrypoint halts (returns) for a signed input below the threshold. -/ theorem external_fun_wrap_expRayToWad_calldata_halts (x : Nat) (store : EvmYul.Yul.VarStore) - (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : ∃ state value, EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) = @@ -806,7 +806,7 @@ set_option maxHeartbeats 16000000 in /-- Result from the dispatcher-handed state. -/ theorem external_fun_wrap_expRayToWad_dispatcher_state_result (x : Nat) - (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : ((match EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok @@ -872,7 +872,7 @@ set_option maxHeartbeats 16000000 in /-- Halt from the dispatcher-handed state. -/ theorem external_fun_wrap_expRayToWad_dispatcher_state_halts (x : Nat) - (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : ∃ state value, EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok @@ -914,7 +914,7 @@ set_option maxHeartbeats 16000000 in the runtime floor and monotonicity claims at the run level. -/ theorem run_exp_ray_to_wad_evm_eq_tree (x : Nat) - (hval : FormalYul.u256 x < 0x8e383a2cdfa1b74a9422d2e1 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : run_exp_ray_to_wad_evm x = .ok ( let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 3e1dc6a64..137da3155 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -20,7 +20,7 @@ stray `sorry` (or any new axiom) breaks the build. | Property | Theorem | |---------------------------------------------------|--------------------------------------------------| -| Reverts on inputs ≥ `0x8e383a2cdfa1b74a9422d2e1` | `run_exp_ray_to_wad_evm_revert` | +| Reverts on inputs ≥ `0x907595ccd30708cabec8a9db` | `run_exp_ray_to_wad_evm_revert` | | Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | | Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | | Never over / floor-or-one-less: `r ≤ E < r + 2` | `run_exp_ray_to_wad_evm_floorOrOneLess_uncond` | @@ -33,7 +33,7 @@ reduced to the octave-seam `r0` doubling bound `SeamR0Bound`) is discharged by `seamR0Bound_holds`; the floor brackets consume the discharged accumulator facts (`accumReal_over`, `accumReal_under`, `belowC_target_lt_one`) directly. -The supported-range threshold is `0x8e383a2cdfa1b74a9422d2e1`; at or above it (and below `2^255`, +The supported-range threshold is `0x907595ccd30708cabec8a9db`; at or above it (and below `2^255`, i.e. for any non-negative `int256` that large) the wrapper run halts with `revert`. At the scale point `x = 0` the run returns the wad unit `10^18` exactly. For any signed input strictly below the threshold the run returns the inline `evm*` arithmetic tree (the handle for the floor/monotone/bound @@ -46,7 +46,7 @@ open FormalYul /-- Reverts above the supported range. -/ example (x : Nat) - (h1 : (0x8e383a2cdfa1b74a9422d2e1 : Nat) ≤ FormalYul.u256 x) + (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : run_exp_ray_to_wad_evm x = .error "revert" := run_exp_ray_to_wad_evm_revert x h1 h2 diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 9b47747f4..245ded0a4 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -12,11 +12,11 @@ library Exp { /// expRayToWad(x₁) ≤ expRayToWad(x₂). For "central" inputs 707106781186547525 ≤ w ≤ /// 1414213562373095048, `expRayToWad(lnWadToRay(w)) == w - 1`, except at w = 10¹⁸ where it /// returns w. Reverts with `Panic(17)` when x is large enough to leave the supported range - /// (x ≥ 0x8e383a2cdfa1b74a9422d2e1 ≈ 44.01 ⋅ 10²⁷, i.e. E ≳ 1.30 ⋅ 10³⁷). + /// (x ≥ 0x907595ccd30708cabec8a9db ≈ 44.71 ⋅ 10²⁷, i.e. E ≳ 2.61 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256) { - // At this input the octave count k = round(x / (10²⁷⋅ln(2))) reaches 64, the first octave - // outside the certified range. - if (x >= 0x8e383a2cdfa1b74a9422d2e1) { + // At this input the octave count k = round(x / (10²⁷⋅ln(2))) reaches 65, where the deficit + // envelope below exceeds 1ulp. + if (x >= 0x907595ccd30708cabec8a9db) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } return _expRayToWad(x); @@ -79,10 +79,10 @@ library Exp { // (the k⋅ln(2) grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = // √2/128). - // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 63 at - // S = 10¹⁸⋅Δ/2⁶³ ≈ 0.0628 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer + // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 64 at + // S = 10¹⁸⋅Δ/2⁶² ≈ 0.1256 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least integer // on the 2¹⁰⁸ output grid strictly above Δ's image: 0x2027afc6c05 = ⌊5¹⁸⋅Δ⌋ + 1 = - // 2209676553221 (worth ≈ S ulp at k = 63; the +1 is needed to meet the strict never + // 2209676553221 (worth ≈ S ulp at k = 64; the +1 is needed to meet the strict never // overestimate requirement). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E. The under side is bounded to the // same precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 31/10, where 31/10 bounds the sum of the // integer-rational deficit (≤ 5/2, the Horner/`DIV`/floor truncation against the @@ -90,9 +90,9 @@ library Exp { // reduced-argument gap (≤ 37/100, via exp(t) ≤ √2), and the under-direction argument // granularity (≤ 17/100: the same one-grain envelope with the negative-half denominator // floor). Hence the maximum underestimation of the pre-floor accumulator A is E - A ≤ - // ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶³ ≈ 0.39891 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The - // deficit envelope ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave and first - // exceeds 1ulp at k = 65; the guard pins the supported range at k ≤ 63. On the central + // ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶² ≈ 0.79781 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The + // deficit envelope ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave and + // exceeds 1ulp at k = 65, where the guard cuts in. On the central // octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 6.8⋅10⁻²¹ ulp, far // below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. The k = 0 // band is exactly [-H, H] with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, @@ -160,7 +160,7 @@ library Exp { // E on the 2¹⁰⁸ output grid (5¹⁸ = 10¹⁸/2¹⁸ multiplies the Q126 quotient), less the // one-sided margin (0x2027afc6c05 = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then floored by // `shr(108 - k, …)` which folds in the 2ᵏ octave scaling and the wad unit's remaining - // 2¹⁸ (108 - k ∈ [45, 168]). + // 2¹⁸ (108 - k ∈ [44, 168]). r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x2027afc6c05)) // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index 56acf708c..ccdc73f46 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -7,7 +7,7 @@ import {Test, stdError} from "@forge-std/Test.sol"; contract ExpTest is Test { // First input whose octave count exceeds the supported range; `expRayToWad` reverts here. - int256 private constant _TOO_BIG = 0x8e383a2cdfa1b74a9422d2e1; + int256 private constant _TOO_BIG = 0x907595ccd30708cabec8a9db; // floor(1e27 * ln(1e-18)): the greatest input whose exact result is < 1 and floors to 0. int256 private constant _ZERO_MAX = -41446531673892822312323846185; // Canonical central wad inputs satisfying 1/sqrt(2) <= w/1e18 < sqrt(2). @@ -69,7 +69,7 @@ contract ExpTest is Test { /// Monotonicity is tightest where the octave count increments and the margin doubles. Check /// every octave boundary in the supported range deterministically. function testExpRayToWadOctaveBoundaryMonotone() external pure { - for (int256 k = -60; k <= 64; ++k) { + for (int256 k = -60; k <= 65; ++k) { int256 xb = _octaveStart(k); for (int256 x = xb - 2; x <= xb + 1; ++x) { if (x + 1 >= _TOO_BIG) continue; @@ -82,17 +82,23 @@ contract ExpTest is Test { /// never-overestimate guarantee, where the over-side envelope (rational approximation plus the /// Horner/sdiv truncation jitter) the margin must cover is largest, scaling as 2ᵏ. function testExpRayToWadNeverOverestimateHighK() external pure { - int256[4] memory xs = [ + int256[7] memory xs = [ int256(44014845965556527147989858478), 43997357674525079384913362454, 43314167405007111804561657812, - 43956299042314536509785490661 + 43956299042314536509785490661, + 44585114869649660801412478168, + 44194124950069992127775717862, + 44183539459288389725181420565 ]; - int256[4] memory floors = [ + int256[7] memory floors = [ int256(13043817825332782212292423780355560294), 12817686828684532031135154053443771706, 6472974441739539356346729565753819877, - 12302067878139647644374925801327210534 + 12302067878139647644374925801327210534, + 23071156379767734423570518961257410973, + 15605029656619514838244041715971750817, + 15440713974442839033966209577600907121 ]; for (uint256 i; i < xs.length; ++i) { int256 r = Exp.expRayToWad(xs[i]); @@ -123,11 +129,19 @@ contract ExpTest is Test { } } - /// The largest supported input, one below the revert threshold. frac(E) ~= 0.74 exceeds the - /// k = 63 deficit envelope (~0.40), so the result is exactly floor(E). + /// The largest supported input, one below the revert threshold: frac(E) ~= 0.52 sits inside + /// the k = 64 deficit envelope (~0.80), so the result floors to E or one under. At the top of + /// k = 63, frac(E) ~= 0.74 exceeds that octave's envelope (~0.40) and the floor is exact. function testExpRayToWadSupportedEdge() external pure { - int256 floorE = 13043817825332782212349571798501714341; - assertEq(Exp.expRayToWad(_TOO_BIG - 1), floorE, "supported-edge floor"); + int256 floorE = 26087635650665564424699143611138320962; + int256 r = Exp.expRayToWad(_TOO_BIG - 1); + assertLe(r, floorE, "overestimates exp"); + assertGe(r, floorE - 1, "below floor minus one"); + assertEq( + Exp.expRayToWad(44014845965556527147994239712), + 13043817825332782212349571798501714341, + "k = 63 top floor" + ); } /// The 1-ulp underestimate is achieved: the least x >= 44e27 whose result is floor(E) - 1. @@ -137,6 +151,12 @@ contract ExpTest is Test { int256 x = 44000000000000000000000000001; int256 floorE = 12851600114359308275809299644994699372; assertEq(Exp.expRayToWad(x), floorE - 1, "not the 1-ulp underestimate"); + // The first input of the k = 64 octave: frac(E) ~= 0.07, again one under the exact floor. + assertEq( + Exp.expRayToWad(44014845965556527147994239713), + 13043817825332782212349571811545532167 - 1, + "k = 64 underestimate" + ); } /// Never negative and monotone at every adjacent pair; oracle-free, so it covers octave From 7c732dc15a0ac178bb13ce429cac5d02ecd3e365 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Fri, 3 Jul 2026 19:43:50 +0200 Subject: [PATCH 142/149] Write the clamp constant as a negation The clamp comparison spells its constant as sub(0x00, 0x85ebc478242540a11f5f1029) -- the 12-byte magnitude ceil(18*ln10*10^27) negated in-line -- rather than the 32-byte two's-complement literal. The representation choice stays with the optimizer: at 2000 runs the constant folds back into the single push, and at low runs settings the negated form gives the constant optimizer a 15-byte encoding to work from (5 gas over the push). The magnitude also states the boundary's derivation directly. The Seam value walks mirror the compiled form (evmSub 0x00 ... in the eight quoted trees); the runtime bridge closes by kernel evaluation, so Cmask and every downstream statement are unchanged. Full lake build green from the axiom gates; tests unchanged. Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 16 ++++++++-------- src/vendor/Exp.sol | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 36fd1e31e..0a927f6cb 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -432,7 +432,7 @@ theorem call_fun__expRayToWad_78_direct let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) - (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by rw [show fuel + (extra + 700) = (fuel + extra) + 700 by omega] rw [EvmYul.Yul.call.eq_def] @@ -496,7 +496,7 @@ theorem call_fun_expRayToWad_68_direct let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) - (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by rw [show fuel + (extra + 900) = (fuel + extra) + 900 by omega] rw [EvmYul.Yul.call.eq_def] @@ -559,7 +559,7 @@ theorem call_fun_wrap_expRayToWad_direct let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) - (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by rw [show fuel + (extra + 1100) = (fuel + extra) + 1100 by omega] rw [EvmYul.Yul.call.eq_def] @@ -619,7 +619,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) - (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by rw [EvmYul.Yul.call.eq_def] simp only [expSharedAfterFreePtr_lookup, Option.getD_some, yulContract_functions, @@ -648,7 +648,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) - (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) + (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1)) with htree let baseStore := Finmap.insert "ret_0" (FormalYul.word tree) @@ -749,7 +749,7 @@ theorem external_fun_wrap_expRayToWad_calldata_halts let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) - (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1)) + (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1)) with htree let baseStore := Finmap.insert "ret_0" (FormalYul.word tree) @@ -855,7 +855,7 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) - (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by rw [sharedFor_inherited_mstore_mk_eq_expSharedAfterFreePtr_raw] exact external_fun_wrap_expRayToWad_calldata_result (x := x) @@ -934,7 +934,7 @@ theorem run_exp_ray_to_wad_evm_eq_tree let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) evmAdd (evmIszero x) - (evmMul (evmSlt 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 x) r1) + (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by obtain ⟨haltState, _haltValue, hhalt⟩ := external_fun_wrap_expRayToWad_dispatcher_state_halts x hval diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 245ded0a4..4243433b4 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -166,7 +166,7 @@ library Exp { // Zero the result at and below C = ⌊-18⋅ln10⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs // where the reduction would overflow, so it also discards those (otherwise garbage). - r := mul(slt(0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7, x), r) + r := mul(slt(sub(0x00, 0x85ebc478242540a11f5f1029), x), r) // exp(0) = 1 is the only input whose exact result is an integer; the construction lands // on 10¹⁸ - 1, so add one back exactly there. From 48e3f29feb41d2d30d66355ab7d072ff2c83685f Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Fri, 3 Jul 2026 19:54:18 +0200 Subject: [PATCH 143/149] Fix comment --- src/vendor/Ln.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vendor/Ln.sol b/src/vendor/Ln.sol index b0a09d599..f0066d14f 100644 --- a/src/vendor/Ln.sol +++ b/src/vendor/Ln.sol @@ -10,9 +10,9 @@ library Ln { /// returns either ⌊L⌋ or ⌊L⌋ - 1; it never overestimates. `lnWadToRay(10**18) == 0` /// exactly, and the result is negative iff `x < 10**18`. The maximum error is less than /// 1.6986ulp. `lnWadToRay` is monotonic; x₁ < x₂ → lnWadToRay(x₁) ≤ - /// lnWadToRay(x₂). Reverts with `Panic(18)` when `x <= 0`. The central-octave round trip - /// documented on `Exp.expRayToWad` consumes this error envelope; the exp formal check - /// re-verifies that round trip on any change to this file. + /// lnWadToRay(x₂). Reverts with `Panic(18)` when `x <= 0`. For "central" inputs + /// 707106781186547525 ≤ w ≤ 1414213562373095048, `expRayToWad(lnWadToRay(w)) == w - 1`, + /// except at w = 10¹⁸ where it returns w. function lnWadToRay(int256 x) internal pure returns (int256 r) { if (x <= 0) { Panic.panic(Panic.DIVISION_BY_ZERO); From 007cbeeef0886db80a04abbf3d74f88539244f1c Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sat, 4 Jul 2026 19:50:39 +0200 Subject: [PATCH 144/149] Fold the exp output scale into the closing division; rebase CINV to 2^192 The closing sequence multiplies the numerator by 10^18*2^68 = 5^18*2^86 before the single DIV, so the quotient lands directly on the 2^68 output grid: one truncation at the finest achievable scale, margin 0x03 (the least grid integer above the never-over image 5^18*B/2^40 < 2.0097), and a closing shift of 68 - k. This saves 6 gas per call versus scaling after the division and strictly improves accuracy: the k = 64 deficit envelope is (33/4 + 3)/2^4 = 45/64 ~= 0.703 ulp, and 26 of 20,524 sampled outputs move from floor(E)-1 to floor(E), none the other way. The octave reciprocal is CINV = round(2^192/(10^27*ln2)), 13 bytes; the computed k is bit-identical for every live input (minimum per-tie safety factor 6.6x, binding at the j = -54 tie), so the guard threshold and all witnesses are unchanged. The proof re-derives the closing layer on the scaleQ68 grid pre-floor: the under deficit is 33/4 grid units including the one-unit DIV floor (link-1 6210/1000, Mp 2/25, reduced-argument gap 1267/1000, negative-half granularity 571/1000), the over side is covered by the margin with 0.99 units of strictness slack, and the k-extraction sandwich sits on the 2^192 basis. Full lake build is green from the Theorems.lean axiom gates. Tests: a central-octave round-trip fuzz test is added; every existing witness value is unchanged; 12/12 pass at 10k fuzz runs; forge fmt clean. Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 24 +- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 4 +- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 71 ++-- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 395 +++++++++--------- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 335 +++++++-------- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 77 ++-- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 30 +- .../exp/ExpProof/ExpProof/Floor/TBound.lean | 10 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 18 +- formal/exp/ExpProof/ExpProof/Mono/Cross.lean | 141 +++++-- formal/exp/ExpProof/ExpProof/Mono/Octave.lean | 62 +-- formal/exp/ExpProof/ExpProof/Mono/Quot.lean | 110 +++-- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 149 +++---- .../ExpProof/ExpProof/Mono/RegionMono.lean | 16 +- .../exp/ExpProof/ExpProof/Mono/RunBridge.lean | 4 +- formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 50 +-- formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean | 10 +- formal/exp/ExpProof/ExpProof/Mono/Stages.lean | 74 ++-- .../exp/ExpProof/ExpProof/Mono/StepMono.lean | 32 +- formal/exp/ExpProof/ExpProof/Mono/Top.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 13 +- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 48 +-- formal/exp/ExpProof/ExpProof/Theorems.lean | 2 +- src/vendor/Exp.sol | 108 ++--- test/0.8.34/Exp.t.sol | 20 +- 25 files changed, 905 insertions(+), 900 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index 12fcdef17..123425914 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -3,12 +3,12 @@ import ExpProof.Floor.Spec /-! # The runtime accumulator in closed real form -The real pre-floor accumulator is `accumReal x = (WAD·r0 − MARGIN) / 2^(108 − k)` on the `5¹⁸·2¹⁰⁸` -grid (`WAD = 5¹⁸`, the wad unit's `2¹⁸` folded into the closing shift). This file peels the runtime +The real pre-floor accumulator is `accumReal x = (r0 − MARGIN) / 2^(68 − k)` on the `2⁶⁸` output +grid (the quotient carries the `10¹⁸·2⁶⁸` scale directly). This file peels the runtime plumbing off it: using the proven shift-argument transport (`shiftArg_bounds_of`: -`int256 (WAD·r0 − MARGIN) = WAD·r0 − MARGIN` as `Int`) and the closing-shift value -(`closing_shift`: the shift word is `108 − int256 k`, nonnegative), the accumulator takes the -closed form `(WAD·(int256 r0) − MARGIN) / 2^s` with `s = 108 − int256 (kTree x)`, the form the +`int256 (r0 − MARGIN) = int256 r0 − MARGIN` as `Int`) and the closing-shift value +(`closing_shift`: the shift word is `68 − int256 k`, nonnegative), the accumulator takes the +closed form `((int256 r0) − MARGIN) / 2^s` with `s = 68 − int256 (kTree x)`, the form the never-over and deficit discharges (`Floor.R0BoundHolds`) fold the octave against. -/ @@ -24,13 +24,13 @@ set_option maxRecDepth 100000 /-! ## The shift-argument value and the closing shift, as real quantities -/ -/-- On the region, the numeric shift argument `WAD·r0 − MARGIN` (transported to `Int` and then to -`Real`) is `WAD·(int256 r0) − MARGIN`, and it is nonnegative. -/ +/-- On the region, the numeric shift argument `r0 − MARGIN` (transported to `Int` and then to +`Real`) is `(int256 r0) − 3`, and it is nonnegative. -/ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - ∃ s : Nat, (s : Int) = 108 - int256 (kTree x) ∧ + ∃ s : Nat, (s : Int) = 68 - int256 (kTree x) ∧ accumReal x = - ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - (2209676553221 : Real)) / + ((int256 (r0Tree x) : Real) - (3 : Real)) / (2 ^ s : Real) := by obtain ⟨s, hseq, _, _, hsint⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 @@ -38,10 +38,8 @@ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) refine ⟨s, hsint, ?_⟩ unfold accumReal rw [hseq] - -- the integer shift argument has the closed value `WAD·r0 − MARGIN` - have hwadc : (0x3782dace9d9 : Int) = 3814697265625 := by norm_num - have hmarc : (0x2027afc6c05 : Int) = 2209676553221 := by norm_num - rw [hargeq, hwadc, hmarc] + -- the integer shift argument has the closed value `r0 − 3` + rw [hargeq] push_cast ring diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index d92060268..c5ea73483 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -9,8 +9,8 @@ import Mathlib.Data.Complex.ExponentialBounds /-! # Discharging the runtime `r0` bound -The public floor brackets need the Q126 quotient `r0Tree x` bracketed against the target -`E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(108 − k)`. This file builds two +The public floor brackets need the scaled quotient `r0Tree x` bracketed against the target +`E = 10¹⁸·exp(int256 x / 10²⁷)` across the octave shift `2^(68 − k)`. This file builds two ingredients of that discharge: * the **Horner-truncation bridge** for the even/odd accumulators — the runtime `evTree x`/`odTree x`, diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index 62c30bf42..b1087490a 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -9,10 +9,12 @@ import ExpProof.Seam.RealExp The per-point `r0`-vs-`exp` brackets (`r0_real_over_within`, `r0_real_under_within`) and the below-clamp bound (`belowC_target_lt_one`) establish the never-over and deficit-under-one facts about the real pre-floor accumulator unconditionally and axiom-clean, via the octave fold -`E·2^s = WAD·2¹⁰⁸·exp(rt)` (`WAD = 5¹⁸`; `s = 108 − k`, the closing shift; `k ≤ 64` so `s ≥ 44`). +`E·2^s = WAD·2⁶⁸·exp(rt)` (`WAD·2⁶⁸ = scaleQ68`; `s = 68 − k`, the closing shift; `k ≤ 64` so +`s ≥ 4`). -* `accumReal_over` ⟸ `r0 ≤ 2¹²⁶·exp(rt) + 5792534503673398887/10000000000000000000` and `5¹⁸·5792534503673398887/10000000000000000000 ≤ MARGIN`; -* `accumReal_under` ⟸ `2¹²⁶·exp(rt) ≤ r0 + 31/10` and `(31/10)·5¹⁸ + MARGIN < 2⁴⁵ ≤ 2^s`. +* `accumReal_over` ⟸ `r0 ≤ scaleQ68·exp(rt) + (5¹⁸/2⁴⁰)·B` and `(5¹⁸/2⁴⁰)·B ≤ MARGIN = 3`; +* `accumReal_under` ⟸ `scaleQ68·exp(rt) ≤ r0 + U` (`U = 33/4`) and + `U + MARGIN < 2⁴ ≤ 2^s`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. -/ @@ -37,27 +39,17 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- WAD·r0 − MARGIN ≤ 5^18·2^126·Ert = E·2^s - have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221 ≤ - expRayToWadTarget (int256 x) * (2 ^ s : Real) := by + -- r0 − MARGIN ≤ scaleQ68·Ert = E·2^s + have hbound : (int256 (r0Tree x) : Real) - 3 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 5792534503673398887 / 10000000000000000000 := hover - have hscaled : (3814697265625 : Real) * (int256 (r0Tree x) : Real) ≤ - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 5792534503673398887 / 10000000000000000000) := - mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] - have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by - rw [show (10 ^ 18 : Real) * (2 ^ 108 : Real) = (3814697265625 : Real) * (2 ^ 126 : Real) from by - norm_num] - ring - rw [hconst] - -- 5^18·B = 3833775901374.02… ≤ 2209676553221 = MARGIN - have hBM : (3814697265625 : Real) * (5792534503673398887 / 10000000000000000000) ≤ - 2209676553221 := by norm_num - linarith [hscaled, hBM] - rw [hAeq, div_le_iff₀ hps]; linarith [hbound] + -- (5¹⁸/2⁴⁰)·B ≤ 3 = MARGIN + have hBM : (3814697265625 : Real) * 5792534503673398887 / + (10000000000000000000 * 1099511627776) ≤ 3 := by norm_num + linarith [hover, hBM] + rw [hAeq, div_le_iff₀ hps] + linarith [hbound] /-- The target is below the accumulator plus one on the region. -/ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) @@ -69,36 +61,25 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hunder := r0_real_under_within hx hC hC0 obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- E·2^s = 5^18·2^126·Ert < WAD·r0 − MARGIN + 2^s + -- E·2^s = scaleQ68·Ert < (r0 − MARGIN) + 2^s have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221) + (2 ^ s : Real) := by + ((int256 (r0Tree x) : Real) - 3) + (2 ^ s : Real) := by rw [hfold] - have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 31 / 10 := hunder have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num - have hs44 : (44 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] - have hs44n : 44 ≤ s := by exact_mod_cast hs44 - have hpow : (2 ^ 44 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs44n + have hs4 : (4 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs4n : 4 ≤ s := by exact_mod_cast hs4 + have hpow : (2 ^ 4 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs4n rw [hwad] - have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by - rw [show (10 ^ 18 : Real) * (2 ^ 108 : Real) = (3814697265625 : Real) * (2 ^ 126 : Real) from by - norm_num] - ring - rw [hconst] - have hscaled : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 31 / 10) := - mul_le_mul_of_nonneg_left hr0R (by norm_num) - -- (31/10)·5^18 + MARGIN < 2^44 - have hbudget : (3814697265625 : Real) * (31 / 10) + 2209676553221 < (2 ^ 44 : Real) := by + -- U + MARGIN < 2⁴ + have hbudget : (33 / 4 : Real) + 3 < (2 ^ 4 : Real) := by norm_num - linarith [hscaled, hbudget, hpow] - -- E < accumReal + 1 ⟺ E·2^s < (WAD·r0 − MARGIN) + 2^s + linarith [hunder, hbudget, hpow] + -- E < accumReal + 1 ⟺ E·2^s < (r0 − MARGIN) + 2^s rw [hAeq] - have hdiv : ((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221) / - (2 ^ s : Real) + 1 = - (((3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221) + (2 ^ s : Real)) / - (2 ^ s : Real) := by field_simp - rw [hdiv, lt_div_iff₀ hps]; linarith [hbound] + have hdiv : ((int256 (r0Tree x) : Real) - 3) / (2 ^ s : Real) + 1 = + (((int256 (r0Tree x) : Real) - 3) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp + rw [hdiv, lt_div_iff₀ hps] + linarith [hbound] /-! ## Hypothesis-free region brackets for the global floor bounds -/ diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index 240e4bb2a..c96275aa0 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -8,7 +8,9 @@ import Mathlib.Analysis.SpecialFunctions.Pow.Real /-! # The per-point `r0`-vs-`exp` bridge (never-over side) -This module bounds the Q126 quotient `r0Tree x` above by `2¹²⁶·exp(rt)` plus the never-over budget +This module bounds the scaled quotient `r0Tree x` above by `(10¹⁸·2⁶⁸)·exp(rt)` plus the +never-over budget (stated `2⁴⁰`-scaled so every constant stays integral: `2⁴⁰·r0 ≤ +5¹⁸·2¹²⁶·exp(rt) + 5¹⁸·B`) (`rt = X/RAY − k·ln2` the reduced argument), the analytic content the floor brackets (`Floor.R0BoundHolds`) consume. The chain has four links: @@ -40,87 +42,94 @@ set_option exponentiation.threshold 2000 /-! ## The `div` floor sandwich -/ -/-- The Q126 quotient is the integer floor: `r0·den_rt ≤ 2¹²⁶·num_rt < (r0+1)·den_rt` with +/-- The scaled quotient is the integer floor: `r0·den_rt ≤ scaleQ68·num_rt < (r0+1)·den_rt` with `num_rt = ev + tod`, `den_rt = ev − tod`. -/ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : int256 (r0Tree x) * ((evTree x : Int) - int256 (todTree x)) ≤ - 2 ^ 126 * ((evTree x : Int) + int256 (todTree x)) ∧ - 2 ^ 126 * ((evTree x : Int) + int256 (todTree x)) < + (0xde0b6b3a764000000000000000000000 : Int) * ((evTree x : Int) + int256 (todTree x)) ∧ + (0xde0b6b3a764000000000000000000000 : Int) * ((evTree x : Int) + int256 (todTree x)) < (int256 (r0Tree x) + 1) * ((evTree x : Int) - int256 (todTree x)) := by obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos hx hC hC0 - obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 set num := evmAdd (evTree x) (todTree x) with hnumdef set den := evmSub (evTree x) (todTree x) with hdendef have hnumw : num < 2 ^ 256 := evmAdd_lt _ _ have hdenw : den < 2 ^ 256 := evmSub_lt _ _ - -- num, den are below 2^128 (signed = Nat value) have hnumi : int256 num = (evTree x : Int) + int256 (todTree x) := hadd have hdeni : int256 den = (evTree x : Int) - int256 (todTree x) := hsub - -- num < 2^128, den < 2^128 obtain ⟨hnumeq, hnum255⟩ := int256_eq_of_nonneg hnumw (by rw [hnumi]; omega) obtain ⟨hdeneq, hden255⟩ := int256_eq_of_nonneg hdenw (by rw [hdeni]; omega) - -- the shl: int256 (shl 126 num) = 2^126·int256 num + obtain ⟨hevlo, hevhi⟩ := evTree_facts (vTree_eq hx hC hC0).2 + obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + have hevloI : (207573926795459379279817565122117813128 : Int) ≤ (evTree x : Int) := by + have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + linarith [this] + have hevhiI : (evTree x : Int) < 3 * 2 ^ 126 := by exact_mod_cast hevhi + have ht126 : int256 (todTree x) < 2 ^ 126 := htod_hi + have hp126 : (2:Int) ^ 126 = 85070591730234615865843651857942052864 := by norm_num have hnumlt128 : int256 num < 2 ^ 128 := by - -- num = ev + tod < 2^127 + 2^125 < 2^128 - obtain ⟨_, hevhi⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 rw [hnumi] - have : (evTree x : Int) < 3 * 2 ^ 126 := by exact_mod_cast hevhi - have ht126 : int256 (todTree x) < 2 ^ 126 := htod_hi - nlinarith [this, ht126] - have hshl : int256 (evmShl 0x7e num) = 2 ^ 0x7e * int256 num := - shl126_transport hnumw (by rw [hnumi]; omega) hnumlt128 - -- r0 = div (shl 126 num) den, with both operands positive - have hr0eq : r0Tree x = evmDiv (evmShl 0x7e num) den := rfl - have hshlw : evmShl 0x7e num < 2 ^ 256 := evmShl_lt _ _ - have hshlpos : 0 ≤ int256 (evmShl 0x7e num) := by rw [hshl, hnumi]; positivity - have hdenpos' : 0 < int256 den := by rw [hdeni]; omega - have hdiv := evmDiv_pos_pos hshlw hdenw hshlpos hdenpos' - rw [← hr0eq] at hdiv - -- toNat values - have hshl_toNat : (int256 (evmShl 0x7e num)).toNat = (evmShl 0x7e num) := by - have h := int256_eq_of_nonneg hshlw hshlpos - rw [h.1, Int.toNat_natCast] - have hden_toNat : (int256 den).toNat = den := by rw [hdeneq, Int.toNat_natCast] - rw [hshl_toNat, hden_toNat] at hdiv - -- the Nat floor: r0 = (shl 126 num) / den + nlinarith [hevhiI, ht126] have hnumnat128 : num < 2 ^ 128 := by have hh : ((num : Nat) : Int) < 2 ^ 128 := by rw [hnumeq] at hnumlt128; exact hnumlt128 exact_mod_cast hh - have hshlval : evmShl 0x7e num = num * 2 ^ 0x7e := by - refine evmShl_eq (by norm_num) ?_ - calc num * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := (Nat.mul_lt_mul_right (Nat.two_pow_pos _)).mpr hnumnat128 - _ = 2 ^ 254 := by rw [← Nat.pow_add] - _ < 2 ^ 256 := by norm_num - -- Nat floor sandwich on the opaque dividend M := num·2^126 + have hsw : scaleQ68 < 2 ^ 256 := by unfold scaleQ68; norm_num + have hfit : scaleQ68 * num < 2 ^ 256 := by + have h1 : scaleQ68 * num ≤ scaleQ68 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hnumnat128) + have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + omega + have hmulval : evmMul scaleQ68 num = scaleQ68 * num := evmMul_eq_nat hsw hnumw hfit have hdennat : 0 < den := by - have hh : (0:Int) < (den:Int) := by rw [hdeneq] at hdenpos'; exact hdenpos' + have hh : (0:Int) < ((den : Nat) : Int) := by rw [← hdeneq, hdeni]; omega exact_mod_cast hh - rw [hshlval] at hdiv - set M := num * 2 ^ 0x7e with hMdef - set q := M / den with hqdef - have hfloor_lo : q * den ≤ M := Nat.div_mul_le_self _ _ - have hfloor_hi : M < (q + 1) * den := by - have hdm : den * q + M % den = M := Nat.div_add_mod M den - have hmod : M % den < den := Nat.mod_lt M hdennat - calc M = den * q + M % den := hdm.symm - _ < den * q + den := Nat.add_lt_add_left hmod _ - _ = (q + 1) * den := by ring - -- transport to Int with the canonical values - have hr0nat : int256 (r0Tree x) = (q : Int) := hdiv - -- canonical: (num:Int) = ev + tod, (den:Int) = ev - tod + have hr0eq : r0Tree x = evmDiv (evmMul scaleQ68 num) den := rfl + have hdivval : evmDiv (evmMul scaleQ68 num) den = scaleQ68 * num / den := by + rw [hmulval, evmDiv_eq hfit hdenw (by omega)] + have hr0q : r0Tree x = scaleQ68 * num / den := by rw [hr0eq, hdivval] + have hfloor_lo : (scaleQ68 * num / den) * den ≤ scaleQ68 * num := Nat.div_mul_le_self _ _ + have hfloor_hi : scaleQ68 * num < (scaleQ68 * num / den + 1) * den := by + have hdm : den * (scaleQ68 * num / den) + (scaleQ68 * num) % den = scaleQ68 * num := + Nat.div_add_mod _ den + have hmod : (scaleQ68 * num) % den < den := Nat.mod_lt _ hdennat + calc scaleQ68 * num = den * (scaleQ68 * num / den) + (scaleQ68 * num) % den := hdm.symm + _ < den * (scaleQ68 * num / den) + den := Nat.add_lt_add_left hmod _ + _ = (scaleQ68 * num / den + 1) * den := by ring + -- the quotient is small: den ≥ 2^126 gives q < 2^130 < 2^255 + have hden126 : 2 ^ 126 ≤ den := by + have h : (2 ^ 126 : Int) ≤ ((den : Nat) : Int) := by + rw [← hdeneq, hdeni, hp126] + rw [hp126] at ht126 + omega + exact_mod_cast h + have hq130 : scaleQ68 * num / den < 2 ^ 130 := by + have h1 : scaleQ68 * num / den ≤ scaleQ68 * num / 2 ^ 126 := + Nat.div_le_div_left hden126 (Nat.two_pow_pos _) + have h2 : scaleQ68 * num / 2 ^ 126 < 2 ^ 130 := by + rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] + calc scaleQ68 * num < 2 ^ 256 := hfit + _ = 2 ^ 130 * 2 ^ 126 := by norm_num + omega + have hr0nat : int256 (r0Tree x) = ((scaleQ68 * num / den : Nat) : Int) := by + rw [hr0q] + exact int256_of_lt (by + have : (2:Nat) ^ 130 < 2 ^ 255 := by norm_num + omega) have hgoalnum : (evTree x : Int) + int256 (todTree x) = (num : Int) := by rw [← hnumi, hnumeq] have hgoalden : (evTree x : Int) - int256 (todTree x) = (den : Int) := by rw [← hdeni, hdeneq] rw [hr0nat, hgoalnum, hgoalden] - have heM : (M : Int) = 2 ^ 126 * (num : Int) := by rw [hMdef]; push_cast; ring + have hscn : scaleQ68 = 0xde0b6b3a764000000000000000000000 := rfl constructor - · have h : (q * den : Nat) ≤ M := hfloor_lo - have hInt : (q : Int) * (den : Int) ≤ (M : Int) := by exact_mod_cast h - rw [heM] at hInt; linarith [hInt] - · have h : M < ((q + 1) * den : Nat) := hfloor_hi - have hInt : (M : Int) < ((q : Int) + 1) * (den : Int) := by exact_mod_cast h - rw [heM] at hInt; linarith [hInt] + · have hInt : ((scaleQ68 * num / den : Nat) : Int) * ((den : Nat) : Int) ≤ + ((scaleQ68 * num : Nat) : Int) := by exact_mod_cast hfloor_lo + rw [hscn] at hInt ⊢ + push_cast at hInt ⊢ + linarith [hInt] + · have hInt : ((scaleQ68 * num : Nat) : Int) < + (((scaleQ68 * num / den : Nat) : Int) + 1) * ((den : Nat) : Int) := by + exact_mod_cast hfloor_hi + rw [hscn] at hInt ⊢ + push_cast at hInt ⊢ + linarith [hInt] /-- The `t·Od` shift stays within `2¹²⁵` on the region: the cert-domain `|t| ≤ H128` against the odd accumulator cap `Od < 5·2¹²⁵`. -/ @@ -172,11 +181,11 @@ theorem den_ge_194 {x : Nat} (hx : x < 2 ^ 256) rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 omega -/-- On the nonpositive half `tod ≤ 0` and hence `r0 ≤ 2¹²⁶` (num ≤ den). -/ -theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) +/-- On the nonpositive half `tod ≤ 0` and hence `r0 ≤ scaleQ68` (num ≤ den). -/ +theorem r0_le_scale_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - int256 (r0Tree x) ≤ 2 ^ 126 := by + int256 (r0Tree x) ≤ (0xde0b6b3a764000000000000000000000 : Int) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef @@ -189,10 +198,11 @@ theorem r0_le_2126_neg {x : Nat} (hx : x < 2 ^ 256) have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn nlinarith [htodlo, this] - -- r0·den ≤ 2^126·num ≤ 2^126·den (num ≤ den) - have hnumden : r0 * (ev - tod) ≤ 2 ^ 126 * (ev - tod) := by - have h1 : r0 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := hfloor_lo - nlinarith [h1, htodnp, (by positivity : (0:Int) ≤ (2:Int)^126)] + -- r0·den ≤ scaleQ68·num ≤ scaleQ68·den (num ≤ den) + have hscnn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) := by positivity + have hnumden : r0 * (ev - tod) ≤ (0xde0b6b3a764000000000000000000000 : Int) * (ev - tod) := by + have h1 : r0 * (ev - tod) ≤ (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) := hfloor_lo + nlinarith [h1, htodnp, hscnn] exact le_of_mul_le_mul_right hnumden hdenpos /-! ## The runtime brackets lifted to the `2^725` alignment @@ -274,14 +284,15 @@ theorem tOd_bracket_neg {x : Nat} (hx : x < 2 ^ 256) /-! ## Link 1 (over side): `r0` vs the grid rational, shared-`Ev` cancellation -/ -/-- **Joint link-1 over (nonneg half, `r0 ≥ 2¹²⁶`)**: the shared even truncation cancels through -the floor, `r0·DENv − 2¹²⁶·NUMv ≤ Wev·2⁵⁹⁰·(r0 − 2¹²⁶)`. -/ +/-- **Joint link-1 over (nonneg half, `r0 ≥ scaleQ68`)**: the shared even truncation cancels through +the floor, `r0·DENv − scaleQ68·NUMv ≤ Wev·2⁵⁹⁰·(r0 − scaleQ68)`. -/ theorem link1_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) (hr0ge : (2:Int) ^ 126 ≤ int256 (r0Tree x)) : + (htnn : 0 ≤ int256 (tTree x)) + (hr0ge : (0xde0b6b3a764000000000000000000000 : Int) ≤ int256 (r0Tree x)) : int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - - 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) ≤ - 142941343449089 * 2 ^ 590 * (int256 (r0Tree x) - 2 ^ 126) := by + (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ + 142941343449089 * 2 ^ 590 * (int256 (r0Tree x) - (0xde0b6b3a764000000000000000000000 : Int)) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn @@ -292,28 +303,29 @@ theorem link1_over_tight {x : Nat} (hx : x < 2 ^ 256) set t := int256 (tTree x) with htdef set Ep := (evNumV (vTree x) : Int) with hEpdef set Op := (odNumV (vTree x) : Int) with hOpdef - have hr0m : (0:Int) ≤ r0 - 2 ^ 126 := by linarith [hr0ge] - have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by linarith [hr0ge] + have hr0m : (0:Int) ≤ r0 - (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0ge] + have hr0p : (0:Int) ≤ r0 + (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0ge] -- Ep·2^110·(r0−2^126) ≤ (2^637·ev + Wev·2^590)·(r0−2^126) - have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ - (2 ^ 637 * ev + 142941343449089 * 2 ^ 590) * (r0 - 2 ^ 126) := by + have hterm1 : Ep * 2 ^ 110 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) ≤ + (2 ^ 637 * ev + 142941343449089 * 2 ^ 590) * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) := by apply mul_le_mul_of_nonneg_right _ hr0m nlinarith [hEp_hi] -- −(t·Op)·(r0+2^126) ≤ −(2^637·tod)·(r0+2^126) - have hterm2 : 2 ^ 637 * tod * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := + have hterm2 : 2 ^ 637 * tod * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) ≤ t * Op * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) := mul_le_mul_of_nonneg_right (by linarith [htOp_lo]) hr0p -- floor: r0·den − 2^126·num ≤ 0, scaled by 2^637 - have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + have hfloor : r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] -/-- **Link-1 over (nonneg half, `r0 ≤ 2¹²⁶`)**: the residue is nonpositive outright. -/ +/-- **Link-1 over (nonneg half, `r0 ≤ scaleQ68`)**: the residue is nonpositive outright. -/ theorem link1_over_small {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htnn : 0 ≤ int256 (tTree x)) (hr0le : int256 (r0Tree x) ≤ (2:Int) ^ 126) : + (htnn : 0 ≤ int256 (tTree x)) + (hr0le : int256 (r0Tree x) ≤ (0xde0b6b3a764000000000000000000000 : Int)) : int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - - 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) ≤ 0 := by + (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ 0 := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn @@ -326,33 +338,33 @@ theorem link1_over_small {x : Nat} (hx : x < 2 ^ 256) set Op := (odNumV (vTree x) : Int) with hOpdef obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 have hr0nn : (0:Int) ≤ r0 := by - have : (0:Int) < 2 ^ 123 := by positivity + have : (0:Int) < 2 ^ 124 := by positivity linarith [hr0lo] - have hr0m : r0 - 2 ^ 126 ≤ 0 := by linarith [hr0le] - have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by positivity + have hr0m : r0 - (0xde0b6b3a764000000000000000000000 : Int) ≤ 0 := by linarith [hr0le] + have hr0p : (0:Int) ≤ r0 + (0xde0b6b3a764000000000000000000000 : Int) := by positivity -- Ep·2^110·(r0−2^126) ≤ 2^637·ev·(r0−2^126) (Ep·2^110 ≥ 2^637·ev, factor ≤ 0) - have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ 2 ^ 637 * ev * (r0 - 2 ^ 126) := by + have hterm1 : Ep * 2 ^ 110 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) ≤ 2 ^ 637 * ev * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) := by apply mul_le_mul_of_nonpos_right _ hr0m nlinarith [hEp_lo] - have hterm2 : 2 ^ 637 * tod * (r0 + 2 ^ 126) ≤ t * Op * (r0 + 2 ^ 126) := + have hterm2 : 2 ^ 637 * tod * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) ≤ t * Op * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) := mul_le_mul_of_nonneg_right (by linarith [htOp_lo]) hr0p - have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + have hfloor : r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] -/-- **Link-1 over (nonpositive half)**: the even truncation drops (`r0 ≤ 2¹²⁶`); the odd truncation -survives attenuated to the `t`-scale: `r0·DENv − 2¹²⁶·NUMv ≤ Wod·2⁴⁸⁰·(−t)·(r0 + 2¹²⁶)`. -/ +/-- **Link-1 over (nonpositive half)**: the even truncation drops (`r0 ≤ scaleQ68`); the odd truncation +survives attenuated to the `t`-scale: `r0·DENv − scaleQ68·NUMv ≤ Wod·2⁴⁸⁰·(−t)·(r0 + scaleQ68)`. -/ theorem link1_over_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - - 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) ≤ - 269746241 * 2 ^ 480 * (-(int256 (tTree x))) * (int256 (r0Tree x) + 2 ^ 126) := by + (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ + 269746241 * 2 ^ 480 * (-(int256 (tTree x))) * (int256 (r0Tree x) + (0xde0b6b3a764000000000000000000000 : Int)) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨_, htOp_lo⟩ := tOd_bracket_neg hx hC hC0 htneg - have hr0le := r0_le_2126_neg hx hC hC0 htneg + have hr0le := r0_le_scale_neg hx hC hC0 htneg unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef @@ -362,19 +374,19 @@ theorem link1_over_neg {x : Nat} (hx : x < 2 ^ 256) set Op := (odNumV (vTree x) : Int) with hOpdef obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 have hr0nn : (0:Int) ≤ r0 := by - have : (0:Int) < 2 ^ 123 := by positivity + have : (0:Int) < 2 ^ 124 := by positivity linarith [hr0lo] - have hr0m : r0 - 2 ^ 126 ≤ 0 := by linarith [hr0le] - have hr0p : (0:Int) ≤ r0 + 2 ^ 126 := by positivity - have hterm1 : Ep * 2 ^ 110 * (r0 - 2 ^ 126) ≤ 2 ^ 637 * ev * (r0 - 2 ^ 126) := by + have hr0m : r0 - (0xde0b6b3a764000000000000000000000 : Int) ≤ 0 := by linarith [hr0le] + have hr0p : (0:Int) ≤ r0 + (0xde0b6b3a764000000000000000000000 : Int) := by positivity + have hterm1 : Ep * 2 ^ 110 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) ≤ 2 ^ 637 * ev * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) := by apply mul_le_mul_of_nonpos_right _ hr0m nlinarith [hEp_lo] -- −(t·Op)·(r0+2^126) ≤ (−2^637·tod + Wod·2^480·(−t))·(r0+2^126) - have hterm2 : (2 ^ 637 * tod - 269746241 * 2 ^ 480 * (-t)) * (r0 + 2 ^ 126) ≤ - t * Op * (r0 + 2 ^ 126) := + have hterm2 : (2 ^ 637 * tod - 269746241 * 2 ^ 480 * (-t)) * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) ≤ + t * Op * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) := mul_le_mul_of_nonneg_right htOp_lo hr0p - have hfloor : r0 * (ev - tod) - 2 ^ 126 * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - 2 ^ 126 * (ev + tod)) ≤ 0 := + have hfloor : r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] @@ -773,11 +785,11 @@ theorem num_le_145_den {x : Nat} (hx : x < 2 ^ 256) -- 100·(10000·num) ≤ 100·(14145·den + 28290) ≤ 10000·(145·den) since 355·den ≥ 2829000 nlinarith [hceil, hden] -/-- The quotient cap: `10⁴·(r0 − 2¹²⁶) ≤ 4146·2¹²⁶` on the nonneg half. -/ +/-- The quotient cap: `10⁴·(r0 − scaleQ68) ≤ 4146·scaleQ68` on the nonneg half. -/ theorem r0_cap {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - 10000 * (int256 (r0Tree x) - 2 ^ 126) ≤ 4146 * 2 ^ 126 := by + 10000 * (int256 (r0Tree x) - (0xde0b6b3a764000000000000000000000 : Int)) ≤ 4146 * (0xde0b6b3a764000000000000000000000 : Int) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 have hceil := num_ceiling hx hC hC0 htnn have hden := den_ge_194 hx hC hC0 @@ -785,24 +797,24 @@ theorem r0_cap {x : Nat} (hx : x < 2 ^ 256) set num := (evTree x : Int) + int256 (todTree x) with hnumdef set den := (evTree x : Int) - int256 (todTree x) with hdendef have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden - -- 10000·(r0−2^126)·den ≤ 2^126·(10000·num − 10000·den) ≤ 2^126·(4145·den + 28290) ≤ 4146·2^126·den - have h1 : 10000 * (r0 - 2 ^ 126) * den ≤ 2 ^ 126 * (4145 * den + 28290) := by + -- 10000·(r0−S)·den ≤ S·(10000·num − 10000·den) ≤ S·(4145·den + 28290) ≤ 4146·S·den + have h1 : 10000 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) * den ≤ (0xde0b6b3a764000000000000000000000 : Int) * (4145 * den + 28290) := by nlinarith [hfloor_lo, hceil] - have h2 : (2:Int) ^ 126 * (4145 * den + 28290) ≤ 4146 * 2 ^ 126 * den := by + have h2 : (0xde0b6b3a764000000000000000000000 : Int) * (4145 * den + 28290) ≤ 4146 * (0xde0b6b3a764000000000000000000000 : Int) * den := by nlinarith [hden] - have hchain : 10000 * (r0 - 2 ^ 126) * den ≤ 4146 * 2 ^ 126 * den := le_trans h1 h2 + have hchain : 10000 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) * den ≤ 4146 * (0xde0b6b3a764000000000000000000000 : Int) * den := le_trans h1 h2 exact le_of_mul_le_mul_right hchain hdenpos /-! ## The per-point never-over (nonnegative half) -/ /-- The link-1 jitter divided by `DENv` stays inside its budget (nonneg half): -`Wev·2⁵⁹⁰·(r0 − 2¹²⁶)/DENv ≤ 2170557036555806152/10¹⁹`. -/ +`Wev·2⁵⁹⁰·(r0 − scaleQ68)/DENv ≤ (5¹⁸/2⁴⁰)·2170557036555806152/10¹⁹`. -/ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (142941343449089 : Real) * 2 ^ 590 * ((int256 (r0Tree x) : Real) - 2 ^ 126) / + (142941343449089 : Real) * 2 ^ 590 * ((int256 (r0Tree x) : Real) - 0xde0b6b3a764000000000000000000000) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ - 2170557036555806152 / 10000000000000000000 := by + 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set r0 := int256 (r0Tree x) with hr0def @@ -811,16 +823,16 @@ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos - rcases le_or_gt ((r0:Real) - 2^126) 0 with hle0 | hgt0 - · have hnumneg : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ 0 := + rcases le_or_gt ((r0:Real) - 0xde0b6b3a764000000000000000000000) 0 with hle0 | hgt0 + · have hnumneg : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hle0 - have : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) / (DENv v t : Real) ≤ 0 := + have : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) / (DENv v t : Real) ≤ 0 := div_nonpos_of_nonpos_of_nonneg hnumneg (le_of_lt hDR) - linarith [this] + have hpos : (0:Real) ≤ 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by positivity + linarith [this, hpos] · rw [div_le_iff₀ hDR] - -- r0 − 2^126 ≤ 4146·2^126/10^4 (r0_cap); DENv ≥ 2^637·(den−2) ≥ 2^637·(den_lo−2) have hcap := r0_cap hx hC hC0 htnn - have hcapR : (r0 : Real) - 2 ^ 126 ≤ 4146 * 2 ^ 126 / 10000 := by + have hcapR : (r0 : Real) - 0xde0b6b3a764000000000000000000000 ≤ 4146 * 0xde0b6b3a764000000000000000000000 / 10000 := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hcap push_cast at h linarith [h] @@ -836,19 +848,19 @@ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDENlow push_cast at h linarith [h] - have hnum_le : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) ≤ - (142941343449089 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := + have hnum_le : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) ≤ + (142941343449089 : Real) * 2 ^ 590 * (4146 * 0xde0b6b3a764000000000000000000000 / 10000) := mul_le_mul_of_nonneg_left hcapR (by positivity) - have hbudget : (142941343449089 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) ≤ - (2170557036555806152 / 10000000000000000000) * + have hbudget : (142941343449089 : Real) * 2 ^ 590 * (4146 * 0xde0b6b3a764000000000000000000000 / 10000) ≤ + (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * ((2:Real) ^ 637 * (165038630930342071346895739193146786696 - 2)) := by norm_num - calc (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) - ≤ (142941343449089 : Real) * 2 ^ 590 * (4146 * 2 ^ 126 / 10000) := hnum_le - _ ≤ (2170557036555806152 / 10000000000000000000) * + calc (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) + ≤ (142941343449089 : Real) * 2 ^ 590 * (4146 * 0xde0b6b3a764000000000000000000000 / 10000) := hnum_le + _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * ((2:Real) ^ 637 * (165038630930342071346895739193146786696 - 2)) := hbudget - _ ≤ (2170557036555806152 / 10000000000000000000) * (DENv v t : Real) := - mul_le_mul_of_nonneg_left hDENlowR (by norm_num) + _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * + (DENv v t : Real) := mul_le_mul_of_nonneg_left hDENlowR (by norm_num) /-- **The per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + B` with the four-link budget `B = 5792534503673398887/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3291…`, the `Mp` @@ -856,8 +868,8 @@ factor `≤ √2·2¹²⁶/(2¹³²−1) ≤ 0.0442…`, and the reduced-argumen theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 5792534503673398887 / 10000000000000000000 := by + (int256 (r0Tree x) : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) + + 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -874,22 +886,23 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by have : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE exact_mod_cast this - -- link 1: r0 ≤ 2^126·Qv + jitter - have hlink1 : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 2170557036555806152 / 10000000000000000000 := by - rcases le_or_gt r0 (2^126) with hsm | hbg + -- link 1: r0 ≤ scaleQ68·Qv + jitter + have hlink1 : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by + rcases le_or_gt r0 (0xde0b6b3a764000000000000000000000 : Int) with hsm | hbg · have hi := link1_over_small hx hC hC0 htnn hsm - have hiR : (r0 : Real) * (DENv v t : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) := by + have hiR : (r0 : Real) * (DENv v t : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] - have hr0le : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) := by + have hr0le : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) := by rw [mul_div_assoc', le_div_iff₀ hDR]; linarith [hiR] - linarith [hr0le] + have hBJnn : (0:Real) ≤ 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by positivity + linarith [hr0le, hBJnn] · have hi := link1_over_tight hx hC hC0 htnn (le_of_lt hbg) - have hjointR : (r0 : Real) * (DENv v t : Real) - (2 ^ 126 : Real) * (NUMv v t : Real) ≤ - (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) := by + have hjointR : (r0 : Real) * (DENv v t : Real) - (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) ≤ + (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] - have hstep : (r0 : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) / (DENv v t : Real) + - (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 2 ^ 126) / (DENv v t : Real) := by + have hstep : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) / (DENv v t : Real) + + (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) / (DENv v t : Real) := by rw [div_add_div_same, le_div_iff₀ hDR]; nlinarith [hjointR, hDR] rw [mul_div_assoc] at hstep linarith [hstep, jitter_over_budget hx hC hC0 htnn] @@ -956,33 +969,21 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000 := by nlinarith [hcGap1] - calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 2170557036555806152 / 10000000000000000000 := hlink1 - _ ≤ ((2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - 3290521163436398582 / 10000000000000000000) + - 2170557036555806152 / 10000000000000000000 := by linarith [hgran] - _ ≤ (((2 ^ 126 : Real) * Et + 220970869120796102 / 10000000000000000000) + - 3290521163436398582 / 10000000000000000000) + - 2170557036555806152 / 10000000000000000000 := by linarith [hNEMp, hcMp] - _ ≤ ((((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + - 220970869120796102 / 10000000000000000000) + - 3290521163436398582 / 10000000000000000000) + - 2170557036555806152 / 10000000000000000000 := by linarith [hEtErt] - _ = (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 5792534503673398887 / 10000000000000000000 := by rw [hErtdef]; ring + rw [hErtdef] at * + linarith [hlink1, hgran, hNEMp, hcMp, hEtErt] /-! ## The per-point never-over (nonpositive half) -/ /-- The link-1 jitter budget on the nonpositive half: -`Wod·2⁴⁸⁰·(−t)·(r0 + 2¹²⁶)/DENv ≤ 2170557036555806152/10¹⁹`. -/ +`Wod·2⁴⁸⁰·(−t)·(r0 + scaleQ68)/DENv ≤ (5¹⁸/2⁴⁰)·2170557036555806152/10¹⁹`. -/ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : (269746241 : Real) * 2 ^ 480 * (-(int256 (tTree x) : Real)) * - ((int256 (r0Tree x) : Real) + 2 ^ 126) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ - 2170557036555806152 / 10000000000000000000 := by + ((int256 (r0Tree x) : Real) + 0xde0b6b3a764000000000000000000000) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ + 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 - have hr0le := r0_le_2126_neg hx hC hC0 htneg + have hr0le := r0_le_scale_neg hx hC hC0 htneg obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 have hDEN_ge := DENv_ge_ev_neg hx hC hC0 htneg obtain ⟨hev_lo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 @@ -1008,19 +1009,20 @@ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo push_cast at h linarith [h] - have hr0pR : (0:Real) ≤ (r0 : Real) + 2 ^ 126 := by + have hr0pR : (0:Real) ≤ (r0 : Real) + 0xde0b6b3a764000000000000000000000 := by have h : (0:Int) ≤ r0 := by - have : (0:Int) < 2 ^ 123 := by positivity + have : (0:Int) < 2 ^ 124 := by positivity linarith [hr0lo] have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr h push_cast at this linarith [this] - have hr0pH : (r0 : Real) + 2 ^ 126 ≤ 2 * 2 ^ 126 := by + have hr0pH : (r0 : Real) + 0xde0b6b3a764000000000000000000000 ≤ + 2 * 0xde0b6b3a764000000000000000000000 := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le push_cast at h linarith [h] - have hnum_le : (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) ≤ - (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := by + have hnum_le : (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0xde0b6b3a764000000000000000000000) ≤ + (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * (0xde0b6b3a764000000000000000000000 : Real)) := by have h1 : (269746241 : Real) * 2 ^ 480 * (-(t : Real)) ≤ (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 := mul_le_mul_of_nonneg_left hntH (by positivity) @@ -1030,15 +1032,15 @@ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) push_cast at h linarith [h] have hbudget : (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * - (2 * 2 ^ 126) ≤ (2170557036555806152 / 10000000000000000000) * + (2 * (0xde0b6b3a764000000000000000000000 : Real)) ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * ((2:Real) ^ 637 * 207573926795459379279817565122117813128) := by norm_num - calc (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) - ≤ (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * 2 ^ 126) := + calc (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0xde0b6b3a764000000000000000000000) + ≤ (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * (0xde0b6b3a764000000000000000000000 : Real)) := hnum_le - _ ≤ (2170557036555806152 / 10000000000000000000) * + _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * ((2:Real) ^ 637 * 207573926795459379279817565122117813128) := hbudget - _ ≤ (2170557036555806152 / 10000000000000000000) * (DENv v t : Real) := + _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * (DENv v t : Real) := mul_le_mul_of_nonneg_left hDENlowR (by norm_num) /-- **The per-point never-over (nonpositive half).** The granularity is free here; the `Mp` factor @@ -1046,8 +1048,8 @@ and reduced-argument gap shrink (`Et ≤ 1`), so the same budget `B` covers the theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 5792534503673398887 / 10000000000000000000 := by + (int256 (r0Tree x) : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) + + 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := by have htdom := tdom_neg hx hC hC0 htneg have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -1058,15 +1060,15 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htneg htdom).2 have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos - -- link 1: r0 ≤ 2^126·Qv + jitter - have hlink1 : (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 2170557036555806152 / 10000000000000000000 := by + -- link 1: r0 ≤ scaleQ68·Qv + jitter + have hlink1 : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by have hi := link1_over_neg hx hC hC0 htneg - have hiR : (r0 : Real) * (DENv v t : Real) - (2 ^ 126 : Real) * (NUMv v t : Real) ≤ - (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) := by + have hiR : (r0 : Real) * (DENv v t : Real) - (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) ≤ + (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0xde0b6b3a764000000000000000000000) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] - have hstep : (r0 : Real) ≤ (2 ^ 126 : Real) * (NUMv v t : Real) / (DENv v t : Real) + - (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 2 ^ 126) / + have hstep : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) / (DENv v t : Real) + + (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0xde0b6b3a764000000000000000000000) / (DENv v t : Real) := by rw [div_add_div_same, le_div_iff₀ hDR]; nlinarith [hiR, hDR] rw [mul_div_assoc] at hstep @@ -1130,40 +1132,25 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) have hgranR : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_le_mul_of_nonneg_left hgran1 (by positivity) - calc (r0 : Real) ≤ (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 2170557036555806152 / 10000000000000000000 := hlink1 - _ ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) + - 2170557036555806152 / 10000000000000000000 := by linarith [hgranR] - _ ≤ ((2 ^ 126 : Real) * Et + 220970869120796102 / 10000000000000000000) + - 2170557036555806152 / 10000000000000000000 := by linarith [hNEMp, hcMp] - _ ≤ (((2 ^ 126 : Real) * Ert + 110485434560398051 / 10000000000000000000) + - 220970869120796102 / 10000000000000000000) + - 2170557036555806152 / 10000000000000000000 := by linarith [hEtErt] - _ ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 5792534503673398887 / 10000000000000000000 := by - rw [hErtdef] - have : (110485434560398051 : Real) / 10000000000000000000 + - 220970869120796102 / 10000000000000000000 + - 2170557036555806152 / 10000000000000000000 ≤ - 5792534503673398887 / 10000000000000000000 := by norm_num - linarith [this] + rw [hErtdef] at * + linarith [hlink1, hgranR, hNEMp, hcMp, hEtErt] -/-- **Per-point never-over (tight, any sign):** `r0 ≤ 2¹²⁶·exp(rt) + B` (`WAD·B < MARGIN`). -/ +/-- **Per-point never-over (tight, any sign):** `r0 ≤ scaleQ68·exp(rt) + (5¹⁸/2⁴⁰)·B` +(the budget's image is strictly below `MARGIN = 3`). -/ theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Real.exp (reducedArg x) + - 5792534503673398887 / 10000000000000000000 := by + (int256 (r0Tree x) : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) + + 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_over_tight hx hC hC0 htnn · exact r0_real_over_tight_neg hx hC hC0 (le_of_lt htneg) -/-! ## The octave real identity `E·2^(108−k) = WAD·2¹⁰⁸·exp(rt)` +/-! ## The octave real identity `E·2^(68−k) = WAD·2⁶⁸·exp(rt)` The target `E = WAD·exp(X/RAY)`. With `rt = X/RAY − k·ln2` the reduced argument, `exp(X/RAY) = -exp(rt)·2^k`, so the closing-shift fold `E·2^(108−k) = WAD·2¹⁰⁸·exp(rt)` (and `WAD·2¹⁰⁸ = 5¹⁸·2¹²⁶`, -the `5¹⁸·2¹⁰⁸` output grid's image of the Q126 quotient). This collapses the never-over/deficit -inequalities (stated against `E·2^s`, `s = 108 − k`) onto the clean octave-independent relation -`r0 ≈ 2¹²⁶·exp(rt)`. -/ +exp(rt)·2^k`, so the closing-shift fold `E·2^(68−k) = WAD·2⁶⁸·exp(rt)` (and `WAD·2⁶⁸ = scaleQ68`, +the quotient's own scale). This collapses the never-over/deficit inequalities (stated against +`E·2^s`, `s = 68 − k`) onto the clean octave-independent relation `r0 ≈ scaleQ68·exp(rt)`. -/ /-- `exp(X/RAY) = exp(rt)·2^k` (`k = int256 (kTree x)`, possibly negative; `2^k` is a real `zpow`). -/ theorem exp_X_over_RAY (x : Nat) : @@ -1177,24 +1164,24 @@ theorem exp_X_over_RAY (x : Nat) : unfold reducedArg; ring, Real.exp_add, hlog] -/-- **The octave fold of the target.** `E·2^(108−k) = WAD·2¹⁰⁸·exp(rt)`, with `s = 108 − k` the +/-- **The octave fold of the target.** `E·2^(68−k) = WAD·2⁶⁸·exp(rt)`, with `s = 68 − k` the closing shift. -/ -theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 108 - int256 (kTree x)) : +theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 68 - int256 (kTree x)) : expRayToWadTarget (int256 x) * (2 ^ s : Real) = - (WAD : Real) * (2 ^ 108 : Real) * Real.exp (reducedArg x) := by + (WAD : Real) * (2 ^ 68 : Real) * Real.exp (reducedArg x) := by unfold expRayToWadTarget rw [show (RAY : Real) = (10 ^ 27 : Real) from by unfold RAY; norm_num, exp_X_over_RAY x] -- 2^k · 2^s = 2^108 with k+s = 108 (k : Int, s : Nat). set k := int256 (kTree x) with hkdef - have hks : k + (s : Int) = 108 := by omega - have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (108 : Nat) := by + have hks : k + (s : Int) = 68 := by omega + have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (68 : Nat) := by rw [show ((2 : Real) ^ (s : Nat)) = (2 : Real) ^ (s : Int) from by rw [zpow_natCast], ← zpow_add₀ (by norm_num : (2:Real) ≠ 0), hks] norm_num rw [show ((2 ^ s : Real)) = (2 : Real) ^ (s : Nat) from by norm_num] calc (WAD : Real) * (Real.exp (reducedArg x) * (2 : Real) ^ k) * (2 : Real) ^ (s : Nat) = (WAD : Real) * ((2 : Real) ^ k * (2 : Real) ^ (s : Nat)) * Real.exp (reducedArg x) := by ring - _ = (WAD : Real) * (2 ^ 108 : Real) * Real.exp (reducedArg x) := by + _ = (WAD : Real) * (2 ^ 68 : Real) * Real.exp (reducedArg x) := by rw [hpow] end diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index e112395db..a1a075caf 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -4,18 +4,18 @@ import ExpProof.Floor.R0Exp # The deficit (under) side of the per-point `r0`-vs-`exp` bridge, and the seam bound This module contains the counterpart to the never-over `r0_real_over_within`: the per-point deficit -`2¹²⁶·exp(rt) ≤ r0 + 31/10` (`r0_real_under_within`), both signs, with the same four-link chain: +`scaleQ68·exp(rt) ≤ r0 + 33/4` (`r0_real_under_within`), both signs, with the same four-link chain: -1. link-1 deficit against the grid rational, `≤ 5/2`; -2. the argument granularity (`Floor.GranV`) — free on the `t ≥ 0` half, `≤ 1644901622230542074/10¹⁹` +1. link-1 deficit against the grid rational including the `div` floor, `≤ 6210/1000`; +2. the argument granularity (`Floor.GranV`) — free on the `t ≥ 0` half, `≤ (5¹⁸/2⁴⁰)·1644901622230542074/10¹⁹` (`Mp`-folded) on the `t ≤ 0` half; -3. the `Mp` factor, `≤ 1/20` (via `r0 ≤ 1.45·2¹²⁶`); -4. the under-direction reduced-argument gap, `≤ 37/100` (via `exp(rt) ≤ √2·(1+ε)`). +3. the `Mp` factor, `≤ 2/25` (via `r0 ≤ 1.45·scaleQ68`); +4. the under-direction reduced-argument gap, `≤ 1267/1000` (via `exp(rt) ≤ √2·(1+ε)`). -The sum `2500/1000 + 1/20 + 1644901622230542074/10¹⁹ + 37/100 ≤ 31/10` feeds the `k = 64` deficit -envelope `((31/10)·5¹⁸·2¹⁸ + 2¹⁸·MARGIN)/2⁶² < 1`. The module closes with the octave-seam `r0`-doubling -bound `r0₁ + 2 ≤ 2·r0₂` (`SeamR0Bound`), where the `1 − exp(−1/RAY)` seam slack (≈ `1.7·10¹¹` grid -units against `r0₂ > 2¹²⁴`) dwarfs both per-point budgets and the two integer units. +The sum `6210/1000 + 2/25 + (5¹⁸/2⁴⁰)·1644901622230542074/10¹⁹ + 1267/1000 ≤ 33/4` feeds the `k = 64` deficit +envelope `(33/4 + MARGIN)/2⁴ < 1`. The module closes with the octave-seam `r0`-doubling +bound `r0₁ + 3 ≤ 2·r0₂` (`SeamR0Bound`), where the `1 − exp(−1/RAY)` seam slack (≈ `8.5·10¹⁰` grid +units against `r0₂ > 2¹²⁶`) dwarfs both per-point budgets and the three integer units. -/ namespace ExpYul @@ -74,12 +74,12 @@ theorem exp_reducedArg_le_sqrt2bound {x : Nat} (hx : x < 2 ^ 256) /-! ## The `r0` bracket on the nonneg half -/ -/-- `r0` is bracketed on the nonneg half: `2¹²⁶ ≤ r0` and `100·r0 ≤ 145·2¹²⁶`. -/ +/-- `r0` is bracketed on the nonneg half: `scaleQ68 ≤ r0` and `100·r0 ≤ 145·scaleQ68`. -/ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (2 : Int) ^ 126 ≤ int256 (r0Tree x) ∧ - 100 * (int256 (r0Tree x)) ≤ 145 * 2 ^ 126 := by + (0xde0b6b3a764000000000000000000000 : Int) ≤ int256 (r0Tree x) ∧ + 100 * (int256 (r0Tree x)) ≤ 145 * (0xde0b6b3a764000000000000000000000 : Int) := by obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 have h145 := num_le_145_den hx hC hC0 htnn set r0 := int256 (r0Tree x) with hr0def @@ -97,29 +97,29 @@ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) nlinarith [htod, hpos] refine ⟨?_, ?_⟩ · -- 2^126 ≤ r0: 2^126·num < (r0+1)·den, num ≥ den ⟹ 2^126·den < (r0+1)·den ⟹ 2^126 < r0+1 - have hnumden : (2:Int)^126 * (ev - tod) ≤ 2 ^ 126 * (ev + tod) := by nlinarith [htodnn] - have h : (2:Int)^126 * (ev - tod) < (r0 + 1) * (ev - tod) := lt_of_le_of_lt hnumden hfloor_hi + have hnumden : (0xde0b6b3a764000000000000000000000 : Int) * (ev - tod) ≤ (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) := by nlinarith [htodnn] + have h : (0xde0b6b3a764000000000000000000000 : Int) * (ev - tod) < (r0 + 1) * (ev - tod) := lt_of_le_of_lt hnumden hfloor_hi have := lt_of_mul_lt_mul_right h (le_of_lt hdenpos) omega · -- 100·r0 ≤ 145·2^126: 100·r0·den ≤ 100·2^126·num ≤ 2^126·145·den - have h1 : 100 * (r0 * (ev - tod)) ≤ 100 * (2 ^ 126 * (ev + tod)) := + have h1 : 100 * (r0 * (ev - tod)) ≤ 100 * ((0xde0b6b3a764000000000000000000000 : Int) * (ev + tod)) := mul_le_mul_of_nonneg_left hfloor_lo (by norm_num) - have h2 : (2:Int)^126 * (100 * (ev + tod)) ≤ 2 ^ 126 * (145 * (ev - tod)) := + have h2 : (0xde0b6b3a764000000000000000000000 : Int) * (100 * (ev + tod)) ≤ (0xde0b6b3a764000000000000000000000 : Int) * (145 * (ev - tod)) := mul_le_mul_of_nonneg_left h145 (by positivity) - have hchain : 100 * r0 * (ev - tod) ≤ 145 * 2 ^ 126 * (ev - tod) := by nlinarith [h1, h2] + have hchain : 100 * r0 * (ev - tod) ≤ 145 * (0xde0b6b3a764000000000000000000000 : Int) * (ev - tod) := by nlinarith [h1, h2] exact le_of_mul_le_mul_right hchain hdenpos /-! ## Link 1 (under side): the grid rational vs `r0` -/ -/-- **Link-1 under (nonneg half)**: `1000·(2¹²⁶·NUMv − r0·DENv) ≤ 2500·DENv`. The floor residual -costs one denominator; the odd-truncation carry `(2⁶³⁷ + Wod·2⁴⁸⁰·t)·(2¹²⁶ + r0)` fits in `1.49` -denominators (`t ≤ H128`, `r0 ≤ 1.45·2¹²⁶`, `den ≥ 1.94·2¹²⁶`). -/ +/-- **Link-1 under (nonneg half)**: `1000·(scaleQ68·NUMv − r0·DENv) ≤ 6210·DENv`. The floor residual +costs one denominator; the odd-truncation carry `(2⁶³⁷ + Wod·2⁴⁸⁰·t)·(scaleQ68 + r0)` fits in `1.49` +denominators (`t ≤ H128`, `r0 ≤ 1.45·scaleQ68`, `den ≥ 1.94·scaleQ68`). -/ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - 1000 * (2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - + 1000 * ((0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x))) ≤ - 2500 * DENv (vTree x) (int256 (tTree x)) := by + 6210 * DENv (vTree x) (int256 (tTree x)) := by obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨_, htOp_hi⟩ := tOd_bracket_nonneg hx hC hC0 htnn @@ -127,10 +127,10 @@ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hDEN_ge, _⟩ := DENv_runtime_bracket hx hC hC0 htnn obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hden := den_ge_194 hx hC hC0 - have hLHS : 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - + have hLHS : (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) ≤ 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + - (2 ^ 637 + 269746241 * 2 ^ 480 * int256 (tTree x)) * (2 ^ 126 + int256 (r0Tree x)) := by + (2 ^ 637 + 269746241 * 2 ^ 480 * int256 (tTree x)) * ((0xde0b6b3a764000000000000000000000 : Int) + int256 (r0Tree x)) := by unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef @@ -138,20 +138,20 @@ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) set t := int256 (tTree x) with htdef set Ep := (evNumV (vTree x) : Int) with hEpdef set Op := (odNumV (vTree x) : Int) with hOpdef - have h2126r0_np : (2:Int) ^ 126 - r0 ≤ 0 := by linarith [hr0lo] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [hr0lo] + have h2126r0_np : (0xde0b6b3a764000000000000000000000 : Int) - r0 ≤ 0 := by linarith [hr0lo] + have hr0p_nn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) + r0 := by linarith [hr0lo] -- Ep·2^110·(2^126−r0) ≤ 2^637·ev·(2^126−r0) - have hterm1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ 2 ^ 637 * ev * (2 ^ 126 - r0) := by + have hterm1 : Ep * 2 ^ 110 * ((0xde0b6b3a764000000000000000000000 : Int) - r0) ≤ 2 ^ 637 * ev * ((0xde0b6b3a764000000000000000000000 : Int) - r0) := by apply mul_le_mul_of_nonpos_right _ h2126r0_np nlinarith [hEp_lo] -- t·Op·(2^126+r0) ≤ (2^637·tod + 2^637 + Wod·2^480·t)·(2^126+r0) - have hterm2 : t * Op * (2 ^ 126 + r0) ≤ - (2 ^ 637 * tod + 2 ^ 637 + 269746241 * 2 ^ 480 * t) * (2 ^ 126 + r0) := + have hterm2 : t * Op * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ + (2 ^ 637 * tod + 2 ^ 637 + 269746241 * 2 ^ 480 * t) * ((0xde0b6b3a764000000000000000000000 : Int) + r0) := mul_le_mul_of_nonneg_right htOp_hi hr0p_nn -- floor: 2^126·num − r0·den < den, scaled by 2^637 - have hfloor : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by + have hfloor : (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by linarith [hfloor_hi] - have hfloor638 : (2:Int) ^ 637 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) ≤ + have hfloor638 : (2:Int) ^ 637 * ((0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod)) ≤ 2 ^ 637 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) nlinarith [hterm1, hterm2, hfloor638] -- budget the two additive pieces against DENv @@ -164,25 +164,25 @@ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) have h1 : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ 2 ^ 637 * den - 2 * 2 ^ 637 := by nlinarith [hden] rw [hDdef]; linarith [h1, hDEN_ge] - have hB : 100 * ((2 ^ 637 + 269746241 * 2 ^ 480 * t) * (2 ^ 126 + r0)) ≤ 149 * D := by + have hB : 100 * ((2 ^ 637 + 269746241 * 2 ^ 480 * t) * ((0xde0b6b3a764000000000000000000000 : Int) + r0)) ≤ 520 * D := by have hcoef : 2 ^ 637 + 269746241 * 2 ^ 480 * t ≤ 2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199 := by have := mul_le_mul_of_nonneg_left hthi (by positivity : (0:Int) ≤ 269746241 * 2 ^ 480) linarith [this] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by linarith [(r0_bracket_nonneg hx hC hC0 htnn).1] - have h1 : (2 ^ 637 + 269746241 * 2 ^ 480 * t) * (2 ^ 126 + r0) ≤ + have hr0p_nn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) + r0 := by linarith [(r0_bracket_nonneg hx hC hC0 htnn).1] + have h1 : (2 ^ 637 + 269746241 * 2 ^ 480 * t) * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - (2 ^ 126 + r0) := mul_le_mul_of_nonneg_right hcoef hr0p_nn + ((0xde0b6b3a764000000000000000000000 : Int) + r0) := mul_le_mul_of_nonneg_right hcoef hr0p_nn have h2 : 100 * ((2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - (2 ^ 126 + r0)) ≤ + ((0xde0b6b3a764000000000000000000000 : Int) + r0)) ≤ (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - (245 * 2 ^ 126) := by - have hr0cap : 100 * (2 ^ 126 + r0) ≤ 245 * 2 ^ 126 := by linarith [hr0hi145] + (245 * (0xde0b6b3a764000000000000000000000 : Int)) := by + have hr0cap : 100 * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ 245 * (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0hi145] nlinarith [hr0cap] have h3 : (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - (245 * 2 ^ 126) ≤ 149 * (2 ^ 637 * (165038630930342071346895739193146786696 - 2)) := by + (245 * (0xde0b6b3a764000000000000000000000 : Int)) ≤ 520 * (2 ^ 637 * (165038630930342071346895739193146786696 - 2)) := by norm_num - have h4 : (149 : Int) * (2 ^ 637 * (165038630930342071346895739193146786696 - 2)) ≤ 149 * D := + have h4 : (520 : Int) * (2 ^ 637 * (165038630930342071346895739193146786696 - 2)) ≤ 520 * D := mul_le_mul_of_nonneg_left hDlow (by norm_num) linarith [h1, h2, h3, h4] have hC2000 : (2000 : Int) * 2 ^ 637 ≤ D := by @@ -191,26 +191,26 @@ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) linarith [this, hDlow] linarith [hLHS, hA, hB, hC2000] -/-- **Link-1 under (nonpositive half)**: the same `2500/1000` budget; the even-truncation width and +/-- **Link-1 under (nonpositive half)**: the same `6210/1000` budget; the even-truncation width and the `tod`-floor unit are absorbed by `DENv ≥ 2⁶³⁷·ev ≥ 2⁶³⁷·A0`. -/ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - 1000 * (2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - + 1000 * ((0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x))) ≤ - 2500 * DENv (vTree x) (int256 (tTree x)) := by + 6210 * DENv (vTree x) (int256 (tTree x)) := by obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_hi, _⟩ := tOd_bracket_neg hx hC hC0 htneg - have hr0le := r0_le_2126_neg hx hC hC0 htneg + have hr0le := r0_le_scale_neg hx hC hC0 htneg obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 have hDEN_ge := DENv_ge_ev_neg hx hC hC0 htneg obtain ⟨hev_lo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 obtain ⟨htod_lo125, _⟩ := todTree_small hx hC hC0 - have hLHS : 2 ^ 126 * NUMv (vTree x) (int256 (tTree x)) - + have hLHS : (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) ≤ 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + - 142941343449089 * 2 ^ 590 * 2 ^ 126 + 2 * 2 ^ 637 * 2 ^ 126 := by + 142941343449089 * 2 ^ 590 * (0xde0b6b3a764000000000000000000000 : Int) + 2 * 2 ^ 637 * (0xde0b6b3a764000000000000000000000 : Int) := by unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef @@ -221,33 +221,33 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) have hr0nn : (0:Int) ≤ r0 := by have : (0:Int) < 2 ^ 123 := by positivity linarith [hr0lo] - have h2126r0_nn : (0:Int) ≤ 2 ^ 126 - r0 := by linarith [hr0le] - have h2126r0_le : (2:Int) ^ 126 - r0 ≤ 2 ^ 126 := by linarith [hr0nn] - have hr0p_nn : (0:Int) ≤ 2 ^ 126 + r0 := by positivity - have hr0p_le : (2:Int) ^ 126 + r0 ≤ 2 * 2 ^ 126 := by linarith [hr0le] + have h2126r0_nn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) - r0 := by linarith [hr0le] + have h2126r0_le : (0xde0b6b3a764000000000000000000000 : Int) - r0 ≤ (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0nn] + have hr0p_nn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) + r0 := by positivity + have hr0p_le : (0xde0b6b3a764000000000000000000000 : Int) + r0 ≤ 2 * (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0le] -- Ep·2^110·(2^126−r0) ≤ 2^637·ev·(2^126−r0) + Wev·2^590·2^126 - have hterm1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ - 2 ^ 637 * ev * (2 ^ 126 - r0) + 142941343449089 * 2 ^ 590 * 2 ^ 126 := by - have h1 : Ep * 2 ^ 110 * (2 ^ 126 - r0) ≤ - (2 ^ 637 * ev + 142941343449089 * 2 ^ 590) * (2 ^ 126 - r0) := by + have hterm1 : Ep * 2 ^ 110 * ((0xde0b6b3a764000000000000000000000 : Int) - r0) ≤ + 2 ^ 637 * ev * ((0xde0b6b3a764000000000000000000000 : Int) - r0) + 142941343449089 * 2 ^ 590 * (0xde0b6b3a764000000000000000000000 : Int) := by + have h1 : Ep * 2 ^ 110 * ((0xde0b6b3a764000000000000000000000 : Int) - r0) ≤ + (2 ^ 637 * ev + 142941343449089 * 2 ^ 590) * ((0xde0b6b3a764000000000000000000000 : Int) - r0) := by apply mul_le_mul_of_nonneg_right _ h2126r0_nn nlinarith [hEp_hi] - have h2 : (142941343449089 : Int) * 2 ^ 590 * (2 ^ 126 - r0) ≤ - 142941343449089 * 2 ^ 590 * 2 ^ 126 := + have h2 : (142941343449089 : Int) * 2 ^ 590 * ((0xde0b6b3a764000000000000000000000 : Int) - r0) ≤ + 142941343449089 * 2 ^ 590 * (0xde0b6b3a764000000000000000000000 : Int) := mul_le_mul_of_nonneg_left h2126r0_le (by positivity) nlinarith [h1, h2] -- t·Op·(2^126+r0) ≤ (2^637·tod + 2^637)·(2^126+r0) ≤ 2^637·tod·(2^126+r0) + 2·2^637·2^126 - have hterm2 : t * Op * (2 ^ 126 + r0) ≤ - 2 ^ 637 * tod * (2 ^ 126 + r0) + 2 * 2 ^ 637 * 2 ^ 126 := by - have h1 : t * Op * (2 ^ 126 + r0) ≤ (2 ^ 637 * tod + 2 ^ 637) * (2 ^ 126 + r0) := + have hterm2 : t * Op * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ + 2 ^ 637 * tod * ((0xde0b6b3a764000000000000000000000 : Int) + r0) + 2 * 2 ^ 637 * (0xde0b6b3a764000000000000000000000 : Int) := by + have h1 : t * Op * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ (2 ^ 637 * tod + 2 ^ 637) * ((0xde0b6b3a764000000000000000000000 : Int) + r0) := mul_le_mul_of_nonneg_right htOp_hi hr0p_nn - have h2 : (2:Int) ^ 637 * (2 ^ 126 + r0) ≤ 2 ^ 637 * (2 * 2 ^ 126) := + have h2 : (2:Int) ^ 637 * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ 2 ^ 637 * (2 * (0xde0b6b3a764000000000000000000000 : Int)) := mul_le_mul_of_nonneg_left hr0p_le (by positivity) nlinarith [h1, h2] -- floor: 2^126·num − r0·den ≤ den, scaled - have hfloor : (2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by + have hfloor : (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by linarith [hfloor_hi] - have hfloor638 : (2:Int) ^ 637 * ((2:Int) ^ 126 * (ev + tod) - r0 * (ev - tod)) ≤ + have hfloor638 : (2:Int) ^ 637 * ((0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod)) ≤ 2 ^ 637 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) nlinarith [hterm1, hterm2, hfloor638] -- budget against DENv ≥ 2^637·ev ≥ 2^637·A0; den ≤ ev + 2^125 @@ -263,12 +263,12 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) have : -(2 ^ 125 : Int) ≤ tod := htod_lo125 linarith [this] have hDev : 2 ^ 637 * ev ≤ D := hDEN_ge - -- 1000·(2^637·(ev + 2^125) + Wev·2^590·2^126 + 2·2^637·2^126) ≤ 1000·2^637·ev + 1500·2^637·A0 - have hlit : 1000 * (2 ^ 637 * 2 ^ 125 + 142941343449089 * 2 ^ 590 * 2 ^ 126 + - 2 * 2 ^ 637 * 2 ^ 126) ≤ - (1500 : Int) * (2 ^ 637 * 207573926795459379279817565122117813128) := by + -- 1000·(2^637·(ev + 2^125) + Wev·2^590·scaleQ68 + 2·2^637·scaleQ68) ≤ 1000·2^637·ev + 5210·2^637·A0 + have hlit : 1000 * (2 ^ 637 * 2 ^ 125 + 142941343449089 * 2 ^ 590 * (0xde0b6b3a764000000000000000000000 : Int) + + 2 * 2 ^ 637 * (0xde0b6b3a764000000000000000000000 : Int)) ≤ + (5210 : Int) * (2 ^ 637 * 207573926795459379279817565122117813128) := by norm_num - have hAev : (1500 : Int) * (2 ^ 637 * 207573926795459379279817565122117813128) ≤ 1500 * D := by + have hAev : (5210 : Int) * (2 ^ 637 * 207573926795459379279817565122117813128) ≤ 5210 * D := by have h1 : (2:Int) ^ 637 * 207573926795459379279817565122117813128 ≤ 2 ^ 637 * ev := mul_le_mul_of_nonneg_left hev (by positivity) have := le_trans h1 hDev @@ -277,12 +277,12 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) /-! ## The per-point deficit (nonneg half) -/ -/-- **The per-point deficit (nonneg half).** `2¹²⁶·exp(rt) ≤ r0 + 31/10`: link-1 `≤ 2500/1000`, the -`Mp` factor `≤ 1/20`, the under gap `≤ 37/100`; the granularity is free on this half. -/ +/-- **The per-point deficit (nonneg half).** `scaleQ68·exp(rt) ≤ r0 + 33/4`: link-1 `≤ 6210/1000`, the +`Mp` factor `≤ 2/25`, the under gap `≤ 1267/1000`; the granularity is free on this half. -/ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 31 / 10 := by + (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 33 / 4 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -299,17 +299,17 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by have : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE exact_mod_cast this - -- link 1: 2^126·Qv ≤ r0 + 2500/1000 + -- link 1: 2^126·Qv ≤ r0 + 6210/1000 have hlink1 := link1_under_int hx hC hC0 htnn - have hQv_le : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (r0 : Real) + 2500 / 1000 := by + have hQv_le : (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (r0 : Real) + 6210 / 1000 := by rw [mul_div_assoc', div_le_iff₀ hDR] have hR := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlink1 push_cast at hR nlinarith [hR, hDR] -- link 2 (free): NE/DE ≤ Qv obtain ⟨hgran1, _⟩ := gran_over_pair hx hC hC0 htnn - -- link 3: Et ≤ (NE/DE)·Mpp ≤ Qv·Mpp; Mpp excess ≤ 1/20 via r0 ≤ 1.45·2^126 + -- link 3: Et ≤ (NE/DE)·Mpp ≤ Qv·Mpp; Mpp excess ≤ 2/25 via r0 ≤ 1.45·2^126 have hcertup := certUp_real htnn htdom set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef @@ -328,59 +328,59 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) le_trans hEt_le (mul_le_mul_of_nonneg_right hgran1 hMpp_nn) have hMpp1 : Mpp - 1 = 1 / (2 ^ 132 : Real) := by rw [hMppdef]; field_simp obtain ⟨_, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn - have hr0R : (r0 : Real) ≤ (145 / 100) * (2 ^ 126 : Real) := by + have hr0R : (r0 : Real) ≤ (145 / 100) * (0xde0b6b3a764000000000000000000000 : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0hi145 push_cast at h linarith [h] - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 2500 / 1000 + 1 / 20 := by - have h1 : (2 ^ 126 : Real) * Et ≤ - (2 ^ 126 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) := + have hEt_bound : (0xde0b6b3a764000000000000000000000 : Real) * Et ≤ (r0 : Real) + 6210 / 1000 + 2 / 25 := by + have h1 : (0xde0b6b3a764000000000000000000000 : Real) * Et ≤ + (0xde0b6b3a764000000000000000000000 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) := mul_le_mul_of_nonneg_left hEt_le_Qv (by positivity) - have h2 : (2 ^ 126 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) = - (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) := by ring - have h3 : ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) ≤ 1 / 20 := by + have h2 : (0xde0b6b3a764000000000000000000000 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) = + (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + ((0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) := by ring + have h3 : ((0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) ≤ 2 / 25 := by rw [hMpp1] - have hcap : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (145 / 100) * (2 ^ 126 : Real) + 2500 / 1000 := by linarith [hQv_le, hr0R] + have hcap : (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (145 / 100) * (0xde0b6b3a764000000000000000000000 : Real) + 6210 / 1000 := by linarith [hQv_le, hr0R] have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / (2 ^ 132 : Real)) - have hfin : ((145 / 100) * (2 ^ 126 : Real) + 2500 / 1000) * (1 / (2 ^ 132 : Real)) ≤ - 1 / 20 := by norm_num + have hfin : ((145 / 100) * (0xde0b6b3a764000000000000000000000 : Real) + 6210 / 1000) * (1 / (2 ^ 132 : Real)) ≤ + 2 / 25 := by norm_num linarith [this, hfin] linarith [h1, h2 ▸ h1, h3, hQv_le] - -- link 4 (under gap): 2^126·(Ert − Et) ≤ 37/100 + -- link 4 (under gap): 2^126·(Ert − Et) ≤ 1267/1000 set Ert := Real.exp (reducedArg x) with hErtdef have hgapunder := reducedArg_close_under hx hC hC0 have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ have hErt_le := exp_reducedArg_le_sqrt2bound hx hC hC0 rw [← hErtdef] at hErt_le have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 37 / 100 := by + have hgap126 : (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) ≤ 1267 / 1000 := by have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) - have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := + have h1 : (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := mul_le_mul_of_nonneg_left hgap (by positivity) - have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ - (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := + have h2 : (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ + (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 37 / 100 := by + have h3 : (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 1267 / 1000 := by norm_num linarith [h1, h2, h3] - have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by + have hdist : (0xde0b6b3a764000000000000000000000 : Real) * Ert = (0xde0b6b3a764000000000000000000000 : Real) * Et + (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 31 / 10 - have hsum : (2500 : Real) / 1000 + 1 / 20 + 37 / 100 ≤ 31 / 10 := by norm_num + show (0xde0b6b3a764000000000000000000000 : Real) * Ert ≤ (r0 : Real) + 33 / 4 + have hsum : (6210 : Real) / 1000 + 2 / 25 + 1267 / 1000 ≤ 33 / 4 := by norm_num linarith [hEt_bound, hgap126, hdist, hsum] /-! ## The per-point deficit (nonpositive half) -/ -/-- **The per-point deficit (nonpositive half).** `2¹²⁶·exp(rt) ≤ r0 + 31/10`: link-1 `≤ 2500/1000`, -the `Mp`-folded granularity `≤ 1644901622230542074/10¹⁹`, the `Mp` factor `≤ 1/20` -(via `r0 ≤ 2¹²⁶`), the under gap `≤ 37/100`. -/ +/-- **The per-point deficit (nonpositive half).** `scaleQ68·exp(rt) ≤ r0 + 33/4`: link-1 `≤ 6210/1000`, +the `Mp`-folded granularity `≤ (5¹⁸/2⁴⁰)·1644901622230542074/10¹⁹`, the `Mp` factor `≤ 2/25` +(via `r0 ≤ scaleQ68`), the under gap `≤ 1267/1000`. -/ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 31 / 10 := by + (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 33 / 4 := by have htdom := tdom_neg hx hC hC0 htneg have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef @@ -391,10 +391,10 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htneg htdom).2 have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos - -- link 1: 2^126·Qv ≤ r0 + 2500/1000 + -- link 1: 2^126·Qv ≤ r0 + 6210/1000 have hlink1 := link1_under_int_neg hx hC hC0 htneg - have hQv_le : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (r0 : Real) + 2500 / 1000 := by + have hQv_le : (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (r0 : Real) + 6210 / 1000 := by rw [mul_div_assoc', div_le_iff₀ hDR] have hR := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlink1 push_cast at hR @@ -418,80 +418,78 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) have : (0:Real) < (2 ^ 132 : Real) - 1 := by norm_num positivity have hMp1 : Mp - 1 = 1 / ((2 ^ 132 : Real) - 1) := by rw [hMpdef]; field_simp - have hr0le := r0_le_2126_neg hx hC hC0 htneg - have hr0R : (r0 : Real) ≤ (2 ^ 126 : Real) := by + have hr0le := r0_le_scale_neg hx hC hC0 htneg + have hr0R : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le push_cast at h linarith [h] - have hEt_bound : (2 ^ 126 : Real) * Et ≤ (r0 : Real) + 2500 / 1000 + 1 / 20 + - 1644901622230542074 / 10000000000000000000 := by - have h1 : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) := + have hEt_bound : (0xde0b6b3a764000000000000000000000 : Real) * Et ≤ (r0 : Real) + 6210 / 1000 + 2 / 25 + + 3814697265625 * 1644901622230542074 / (10000000000000000000 * 1099511627776) := by + have h1 : (0xde0b6b3a764000000000000000000000 : Real) * Et ≤ (0xde0b6b3a764000000000000000000000 : Real) * (((NE : Real) / (DE : Real)) * Mp) := mul_le_mul_of_nonneg_left hEt_le (by positivity) -- split: 2^126·(NE/DE)·Mp = 2^126·Qv + 2^126·Qv·(Mp−1) + 2^126·Mp·(NE/DE − Qv) - have hsplit : (2 ^ 126 : Real) * (((NE : Real) / (DE : Real)) * Mp) = - (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) + - (2 ^ 126 : Real) * Mp * + have hsplit : (0xde0b6b3a764000000000000000000000 : Real) * (((NE : Real) / (DE : Real)) * Mp) = + (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + ((0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) + + (0xde0b6b3a764000000000000000000000 : Real) * Mp * ((NE : Real) / (DE : Real) - (NUMv v t : Real) / (DENv v t : Real)) := by ring - have hMpterm : ((2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) ≤ - 1 / 20 := by + have hMpterm : ((0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) ≤ + 2 / 25 := by rw [hMp1] - have hcap : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (2 ^ 126 : Real) + 2500 / 1000 := by linarith [hQv_le, hr0R] + have hcap : (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (0xde0b6b3a764000000000000000000000 : Real) + 6210 / 1000 := by linarith [hQv_le, hr0R] have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / ((2 ^ 132 : Real) - 1)) - have hfin : ((2 ^ 126 : Real) + 2500 / 1000) * (1 / ((2 ^ 132 : Real) - 1)) ≤ 1 / 20 := by + have hfin : ((0xde0b6b3a764000000000000000000000 : Real) + 6210 / 1000) * (1 / ((2 ^ 132 : Real) - 1)) ≤ 2 / 25 := by rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] norm_num linarith [this, hfin] linarith [h1, hsplit ▸ h1, hMpterm, hgran2, hQv_le] - -- link 4 (under gap): 2^126·(Ert − Et) ≤ 37/100 + -- link 4 (under gap): 2^126·(Ert − Et) ≤ 1267/1000 set Ert := Real.exp (reducedArg x) with hErtdef have hgapunder := reducedArg_close_under hx hC hC0 have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ have hErt_le := exp_reducedArg_le_sqrt2bound hx hC hC0 rw [← hErtdef] at hErt_le have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap126 : (2 ^ 126 : Real) * (Ert - Et) ≤ 37 / 100 := by + have hgap126 : (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) ≤ 1267 / 1000 := by have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) - have h1 : (2 ^ 126 : Real) * (Ert - Et) ≤ (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := + have h1 : (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := mul_le_mul_of_nonneg_left hgap (by positivity) - have h2 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ - (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := + have h2 : (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ + (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le (by positivity)) (by positivity) - have h3 : (2 ^ 126 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 37 / 100 := by + have h3 : (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 1267 / 1000 := by norm_num linarith [h1, h2, h3] - have hdist : (2 ^ 126 : Real) * Ert = (2 ^ 126 : Real) * Et + (2 ^ 126 : Real) * (Ert - Et) := by + have hdist : (0xde0b6b3a764000000000000000000000 : Real) * Ert = (0xde0b6b3a764000000000000000000000 : Real) * Et + (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) := by ring - show (2 ^ 126 : Real) * Ert ≤ (r0 : Real) + 31 / 10 - have hsum : (2500 : Real) / 1000 + 1 / 20 + 1644901622230542074 / 10000000000000000000 + - 37 / 100 ≤ 31 / 10 := by norm_num + show (0xde0b6b3a764000000000000000000000 : Real) * Ert ≤ (r0 : Real) + 33 / 4 + have hsum : (6210 : Real) / 1000 + 2 / 25 + 3814697265625 * 1644901622230542074 / (10000000000000000000 * 1099511627776) + + 1267 / 1000 ≤ 33 / 4 := by norm_num linarith [hEt_bound, hgap126, hdist, hsum] -/-- **Per-point deficit (tight, any sign):** `2¹²⁶·exp(rt) ≤ r0 + 31/10`. -/ +/-- **Per-point deficit (tight, any sign):** `scaleQ68·exp(rt) ≤ r0 + 33/4`. -/ theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 126 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 31 / 10 := by + (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 33 / 4 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_under_tight hx hC hC0 htnn · exact r0_real_under_tight_neg hx hC hC0 (le_of_lt htneg) /-! ## The octave-seam `r0`-doubling consequence -/ -/-- A lower bound on the quotient: `2¹²⁴ < r0Tree x`. -(`r0 ≥ 2¹²⁶·exp(rt) − 31/10 > 2¹²⁶·(1/2) − 31/10 > 2¹²⁴`.) -/ -theorem r0Tree_gt_2_124 {x : Nat} (hx : x < 2 ^ 256) +/-- `2¹²⁶ < r0Tree x` on the region (`r0 ≥ scaleQ68·exp(rt) − 33/4 > scaleQ68/2 − 33/4 > 2¹²⁶`). -/ +theorem r0Tree_gt_2126 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 : Real) ^ 124 < (int256 (r0Tree x) : Real) := by + (2 : Real) ^ 126 < (int256 (r0Tree x) : Real) := by have hu := r0_real_under_within hx hC hC0 have hh := exp_reducedArg_gt_half hx hC hC0 - have h1 : (2 ^ 126 : Real) * (1 / 2) < (2 ^ 126 : Real) * Real.exp (reducedArg x) := + have h1 : (0xde0b6b3a764000000000000000000000 : Real) * (1 / 2) < (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) := mul_lt_mul_of_pos_left hh (by positivity) - have h2 : (2 ^ 126 : Real) * (1 / 2) = (2 ^ 125 : Real) := by norm_num - have h3 : (2 : Real) ^ 124 + 31 / 10 < (2 ^ 125 : Real) := by norm_num - linarith [hu, h1, h2 ▸ h1, h3] + have h2 : (2 : Real) ^ 126 + (33 / 4 : Real) < (0xde0b6b3a764000000000000000000000 : Real) * (1 / 2) := by norm_num + linarith [hu, h1, h2] /-- **The seam exp relation.** Across a seam (`X2 = X1 + 1`, `k2 = k1 + 1`), `exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`. -/ @@ -508,19 +506,20 @@ theorem reducedArg_seam {x1 x2 : Nat} rw [hrel, Real.exp_add, Real.exp_add, Real.exp_log (by norm_num : (0:Real) < 2)] ring -/-- **`r0` at most doubles across a seam, two units short** (the real reduction of `SeamR0Bound`). -The strict slack from `exp(−1/RAY) < 1` (against `r0Tree x2 > 2¹²⁴`, worth ≈ `1.7·10¹¹` grid units) -dwarfs the per-point envelopes and the two integer units. -/ +/-- **`r0` at most doubles across a seam, three units short** (the real reduction of +`SeamR0Bound`). The strict slack from `exp(−1/RAY) < 1` (against `r0Tree x2 > 2¹²⁶`, worth +`≈ 8.5·10¹⁰` grid units) dwarfs the per-point envelopes and the three integer units the +seam-floor comparison consumes. -/ theorem r0_seam_double {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) (hk : int256 (kTree x2) = int256 (kTree x1) + 1) (hadj : int256 x2 = int256 x1 + 1) : - int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) := by + int256 (r0Tree x1) + 3 ≤ 2 * int256 (r0Tree x2) := by have hover1 := r0_real_over_within hx1 hC1 hC01 have hunder2 := r0_real_under_within hx2 hC2 hC02 - have hr0_2_big := r0Tree_gt_2_124 hx2 hC2 hC02 + have hr0_2_big := r0Tree_gt_2126 hx2 hC2 hC02 have hseam := reducedArg_seam hk hadj set E1 := Real.exp (reducedArg x1) with hE1 set E2 := Real.exp (reducedArg x2) with hE2 @@ -538,38 +537,46 @@ theorem r0_seam_double {x1 x2 : Nat} have h1z : (1 - 1 / (2 * (10 ^ 27 : Real))) * (1 + 1 / (10 ^ 27 : Real)) ≥ 1 := by rw [ge_iff_le]; nlinarith [sq_nonneg (1 / (10 ^ 27 : Real))] nlinarith [hez, h1z, hexppos, mul_pos (by positivity : (0:Real) < 1 - 1/(2*(10^27:Real))) hexppos] - -- 2^126·E1 = 2·(2^126·E2)·y ≤ 2·(r0_2 + 31/10)·y - have hE2bound : (2 ^ 126 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + 31 / 10 := hunder2 + -- scaleQ68·E1 = 2·(scaleQ68·E2)·y ≤ 2·(r0_2 + U)·y + have hE2bound : (0xde0b6b3a764000000000000000000000 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + (33 / 4 : Real) := + hunder2 have hr0_1 : (int256 (r0Tree x1) : Real) ≤ - 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y + - 5792534503673398887 / 10000000000000000000 := by - have h1 : (2 ^ 126 : Real) * E1 = 2 * ((2 ^ 126 : Real) * E2) * y := by rw [hseam]; ring - have h2 : (int256 (r0Tree x1) : Real) ≤ (2 ^ 126 : Real) * E1 + - 5792534503673398887 / 10000000000000000000 := hover1 + 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * y + + 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := by + have h1 : (0xde0b6b3a764000000000000000000000 : Real) * E1 = 2 * ((0xde0b6b3a764000000000000000000000 : Real) * E2) * y := by + rw [hseam]; ring + have h2 : (int256 (r0Tree x1) : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * E1 + + 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := hover1 rw [h1] at h2 - have h3 : 2 * ((2 ^ 126 : Real) * E2) * y ≤ 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y := + have h3 : 2 * ((0xde0b6b3a764000000000000000000000 : Real) * E2) * y ≤ + 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * y := mul_le_mul_of_nonneg_right (by linarith [mul_le_mul_of_nonneg_left hE2bound (by norm_num : (0:Real) ≤ 2)]) (le_of_lt hy_pos) linarith [h2, h3] have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by - linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^124)] - have hkey : 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y + - 5792534503673398887 / 10000000000000000000 + 2 < 2 * (int256 (r0Tree x2) : Real) := by - -- the seam gap is dominated by `(r0 + 31/10) / RAY`; the quotient exceeds `1562` here - have hyb : 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * y ≤ - 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) := - mul_le_mul_of_nonneg_left hy_bound (by linarith [hr0_2nn]) - have hexpand : 2 * ((int256 (r0Tree x2) : Real) + 31 / 10) * (1 - 1 / (2 * (10 ^ 27 : Real))) = - 2 * (int256 (r0Tree x2) : Real) + 31 / 5 - - ((int256 (r0Tree x2) : Real) + 31 / 10) / (10 ^ 27 : Real) := by field_simp; ring - have hbig : ((int256 (r0Tree x2) : Real) + 31 / 10) / (10 ^ 27 : Real) > 1562 := by + linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^126)] + have hkey : 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * y + + 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) + 3 < 2 * (int256 (r0Tree x2) : Real) := by + -- the seam gap is dominated by `(r0 + U) / RAY`; the quotient exceeds `8.5·10¹⁰` here + have hyb : 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * y ≤ + 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * (1 - 1 / (2 * (10 ^ 27 : Real))) := by + apply mul_le_mul_of_nonneg_left hy_bound + linarith [hr0_2nn] + have hexpand : 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * + (1 - 1 / (2 * (10 ^ 27 : Real))) = + 2 * (int256 (r0Tree x2) : Real) + 2 * (33 / 4 : Real) - + ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) / (10 ^ 27 : Real) := by + field_simp + ring + have hbig : ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) / (10 ^ 27 : Real) > 30 := by rw [gt_iff_lt, lt_div_iff₀ (by positivity)] - nlinarith [hr0_2_big, (by norm_num : (1562:Real) * 10 ^ 27 + 1 < 2 ^ 124)] - linarith [hyb, hexpand ▸ hyb, hbig] - have hreal : (int256 (r0Tree x1) : Real) + 2 ≤ 2 * (int256 (r0Tree x2) : Real) := by + nlinarith [hr0_2_big, (by norm_num : (30:Real) * 10 ^ 27 + 1 < 2 ^ 126)] + have hUB : 2 * (33 / 4 : Real) + 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) + 3 < 30 := by norm_num + linarith [hyb, hexpand ▸ hyb, hbig, hUB] + have hreal : (int256 (r0Tree x1) : Real) + 3 ≤ 2 * (int256 (r0Tree x2) : Real) := by linarith [hr0_1, hkey] - have hcast : ((int256 (r0Tree x1) + 2 : Int) : Real) ≤ ((2 * int256 (r0Tree x2) : Int) : Real) := by + have hcast : ((int256 (r0Tree x1) + 3 : Int) : Real) ≤ ((2 * int256 (r0Tree x2) : Int) : Real) := by push_cast linarith [hreal] exact_mod_cast hcast diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index 27bf4f36a..b322d33d3 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -33,14 +33,14 @@ set_option maxRecDepth 100000 /-! ## Strict never-over: the accumulator stays a positive distance below the target -`accumReal_over` gives `accumReal x ≤ E`. With `B = 5792534503673398887/10¹⁹` the never-over envelope, -`MARGIN` is `⌊WAD·B⌋ + 1` (`WAD = 5¹⁸`), so the inequality is in fact strict — the slack -`δ = MARGIN − WAD·B ≈ 0.86` (worth `δ/2^s` after the closing shift). The round trip needs this +`accumReal_over` gives `accumReal x ≤ E`. With `B' = (5¹⁸/2⁴⁰)·B ≈ 2.0097` the never-over +envelope's image on the output grid, `MARGIN = 3` exceeds it strictly — the slack +`δ = MARGIN − B' ≈ 0.99` (worth `δ/2^s` after the closing shift). The round trip needs this strictness to rule out `accumReal x = w` exactly. -/ -/-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the target. -The proven over bound `r0 ≤ 2¹²⁶·exp(rt) + 5792534503673398887/10000000000000000000` plus `WAD·5792534503673398887/10000000000000000000 < MARGIN` give a strictly -negative residue. -/ +/-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the +target. The proven over bound `r0 ≤ scaleQ68·exp(rt) + (5¹⁸/2⁴⁰)·B` plus `(5¹⁸/2⁴⁰)·B < MARGIN` +give a strictly negative residue. -/ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : accumReal x < expRayToWadTarget (int256 x) := by @@ -49,33 +49,23 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- WAD·r0 − MARGIN < 5^18·2^126·Ert = E·2^s, using WAD·5792534503673398887/10000000000000000000 < MARGIN - have hbound : (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221 < + -- r0 − MARGIN < scaleQ68·Ert = E·2^s, using (5¹⁸/2⁴⁰)·B < MARGIN + have hbound : (int256 (r0Tree x) : Real) - 3 < expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] - have hr0R : (int256 (r0Tree x) : Real) ≤ (2 ^ 126 : Real) * Ert + 5792534503673398887 / 10000000000000000000 := hover - have hscaled : (3814697265625 : Real) * (int256 (r0Tree x) : Real) ≤ - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert + 5792534503673398887 / 10000000000000000000) := - mul_le_mul_of_nonneg_left hr0R (by norm_num) have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] - have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by - rw [show (10 ^ 18 : Real) * (2 ^ 108 : Real) = (3814697265625 : Real) * (2 ^ 126 : Real) from by - norm_num] - ring - rw [hconst] - -- WAD·B = 3833775901374.02 < 2209676553221 = MARGIN - have hBM : (3814697265625 : Real) * (5792534503673398887 / 10000000000000000000) < - 2209676553221 := by norm_num - linarith [hscaled, hBM] + -- (5¹⁸/2⁴⁰)·B ≈ 2.0097 < 3 = MARGIN, strictly + have hBM : (3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) : Real) < 3 := by norm_num + linarith [hover, hBM] rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] /-- **Accumulator deficit, region-uniform.** On the region the accumulator is below the target by -strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ 2¹²⁶·exp(rt) − 31/10` and the -octave fold give `accumReal x ≥ E − ((31/10)·WAD + MARGIN)/2^s` with `s = 108 − k ≥ 44`, and -`((31/10)·WAD + MARGIN)/2⁴⁴ ≈ 0.798 < 24/25`. The tightness below one is what closes the round trip -together with `lnWadToRay`'s ≈10⁻⁹ envelope. -/ +strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ scaleQ68·exp(rt) − U` +(`U = 33/4`) and the octave fold give +`accumReal x ≥ E − (U + MARGIN)/2^s` with `s = 68 − k ≥ 4`, and `(U + MARGIN)/2⁴ ≈ 0.922 < 24/25`. +The tightness below one is what closes the round trip together with `lnWadToRay`'s ≈10⁻⁹ +envelope. -/ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : expRayToWadTarget (int256 x) - 24 / 25 < accumReal x := by @@ -85,36 +75,21 @@ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask have hunder := r0_real_under_within hx hC hC0 obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - have hs44 : (44 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] - have hs44n : 44 ≤ s := by exact_mod_cast hs44 - have hpow : (2 ^ 44 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs44n - -- (E − 24/25)·2^s < WAD·r0 − MARGIN, since E·2^s = 5^18·2^126·Ert ≤ WAD·(r0 + 31/10) - -- and (31/10)·WAD + MARGIN < (24/25)·2^44 ≤ (24/25)·2^s + have hs4 : (4 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs4n : 4 ≤ s := by exact_mod_cast hs4 + have hpow : (2 ^ 4 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs4n + -- (E − 24/25)·2^s < r0 − MARGIN, since E·2^s = scaleQ68·Ert ≤ r0 + U + -- and U + MARGIN < (24/25)·2⁴ ≤ (24/25)·2^s have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < - (3814697265625 : Real) * (int256 (r0Tree x) : Real) - 2209676553221 := by + (int256 (r0Tree x) : Real) - 3 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = - (WAD : Real) * (2 ^ 108 : Real) * Ert := hfold - have hr0R : (2 ^ 126 : Real) * Ert ≤ (int256 (r0Tree x) : Real) + 31 / 10 := hunder + (WAD : Real) * (2 ^ 68 : Real) * Ert := hfold have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num - have h8wad : (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) ≤ - (3814697265625 : Real) * ((int256 (r0Tree x) : Real) + 31 / 10) := - mul_le_mul_of_nonneg_left hr0R (by norm_num) - have hbudget : (3814697265625 : Real) * (31 / 10) + 2209676553221 < (24 / 25) * (2 ^ 44 : Real) := by - norm_num rw [hwad] at hkey - have hconst : (10 ^ 18 : Real) * (2 ^ 108 : Real) * Ert = - (3814697265625 : Real) * ((2 ^ 126 : Real) * Ert) := by - rw [show (10 ^ 18 : Real) * (2 ^ 108 : Real) = (3814697265625 : Real) * (2 ^ 126 : Real) from by - norm_num] - ring - rw [hconst] at hkey - have hEs : expRayToWadTarget (int256 x) * (2 ^ s : Real) ≤ - (3814697265625 : Real) * (int256 (r0Tree x) : Real) + (3814697265625 : Real) * (31 / 10) := by - rw [hkey]; nlinarith [h8wad] - -- (E − 24/25)·2^s = E·2^s − (24/25)·2^s ; (24/25)·2^s ≥ (24/25)·2^44 - have h2425 : (24 / 25 : Real) * (2 ^ 44 : Real) ≤ (24 / 25) * (2 ^ s : Real) := + have hbudget : (33 / 4 : Real) + 3 < (24 / 25) * (2 ^ 4 : Real) := by norm_num + have h2425 : (24 / 25 : Real) * (2 ^ 4 : Real) ≤ (24 / 25) * (2 ^ s : Real) := mul_le_mul_of_nonneg_left hpow (by norm_num) - nlinarith [hEs, hbudget, hpow, h2425] + nlinarith [hunder, hkey, hbudget, hpow, h2425] rw [hAeq, lt_div_iff₀ hps]; linarith [hbound] /-! ## The `lnWadToRay` envelope on the round-trip band diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index e55d03d8b..f6323b770 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -8,13 +8,13 @@ import ExpProof.Mono.RangeNonneg # Floor + branch assembly: the public `Real.exp` brackets `run_exp_ray_to_wad_evm_eq_expTree` returns `expTree x`, the clamp/pin shell around the floored -accumulator `r1Tree x = shr(108 − k, WAD·r0 − MARGIN)`. On the meaningful region the closing shift -`s = 108 − k ∈ [44, 169]` is positive and the shift argument `arg = WAD·r0 − MARGIN` is a +accumulator `r1Tree x = shr(68 − k, r0 − MARGIN)`. On the meaningful region the closing shift +`s = 68 − k ∈ [4, 129]` is positive and the shift argument `arg = r0 − MARGIN` is a nonnegative canonical word, so the runtime result is exactly the integer floor `⌊arg / 2^s⌋` of the *real* pre-floor accumulator ``` -A = (WAD·r0 − MARGIN) / 2^(108 − k). +A = (r0 − MARGIN) / 2^(68 − k). ``` The two floor facts `(r : Real) ≤ A` and `A < (r : Real) + 1` (i.e. `r = ⌊A⌋`) are established here @@ -87,17 +87,17 @@ theorem shr_real_floor {W s : Nat} (hs : s < 256) (hWw : W < 2 ^ 256) (hWnn : 0 /-! ## The runtime accumulator as a real number For `x > 0` in the meaningful region the result is the body word, `expTree x = r1Tree x`, with -`r1Tree x = evmShr (108 − k) (WAD·r0 − MARGIN)`. Its real pre-floor accumulator is +`r1Tree x = evmShr (68 − k) (r0 − MARGIN)`. Its real pre-floor accumulator is ``` -A x = int256 (WAD·r0 − MARGIN) / 2^(108 − k). +A x = int256 (r0 − MARGIN) / 2^(68 − k). ``` -/ /-- The real pre-floor accumulator of the runtime body, as an explicit `Real`. -/ def accumReal (x : Nat) : Real := - (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) : Real) / - (2 ^ (evmSub 0x6c (kTree x)) : Real) + (int256 (evmSub (r0Tree x) 0x3) : Real) / + (2 ^ (evmSub 0x44 (kTree x)) : Real) /-- On the meaningful region the body word `r1Tree x` is the integer floor of its real accumulator `accumReal x`: `(r1Tree x : Real) ≤ accumReal x < (r1Tree x : Real) + 1`. -/ @@ -108,18 +108,18 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) := by - have : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) := rfl + have hr1 : r1Tree x = evmShr s (evmSub (r0Tree x) 0x3) := by + have : r1Tree x = evmShr (evmSub 0x44 (kTree x)) + (evmSub (r0Tree x) 0x3) := rfl rw [this, hseq] - have hWw : evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05 < 2 ^ 256 := + have hWw : evmSub (r0Tree x) 0x3 < 2 ^ 256 := evmSub_lt _ _ - have hfloor := shr_real_floor (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) - (s := s) (by omega) hWw (by rw [hargeq]; exact hargnn) + have hfloor := shr_real_floor (W := evmSub (r0Tree x) 0x3) + (s := s) (by omega) hWw (by rw [hargeq]; omega) simp only at hfloor - -- align `accumReal` (shift `evmSub 0x6c (kTree x)`) with the lemma's shift `s` + -- align `accumReal` (shift `evmSub 0x44 (kTree x)`) with the lemma's shift `s` have hAeq : accumReal x = - (int256 (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) : Real) / + (int256 (evmSub (r0Tree x) 0x3) : Real) / (2 ^ s : Real) := by unfold accumReal; rw [hseq] rw [hAeq, hr1] diff --git a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean index 76cadeb01..9aedd1b85 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean @@ -43,7 +43,7 @@ theorem tTree_in_cert_domain {x : Nat} (hx : x < 2 ^ 256) 55213970774324510299478046898216203619608872 := by norm_num have hLN2 : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num - have hCINV : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by + have hCINV : (0x724d54edbacbebbb95c52a0f60 : Int) = 9055943544797870567083544809312 := by norm_num rw [hK27, hLN2] at htlo hthi rw [hCINV] at hklo hkhi @@ -52,10 +52,10 @@ theorem tTree_in_cert_domain {x : Nat} (hx : x < 2 ^ 256) set X := int256 x with hXdef -- powers of two as decimals have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num - have p199 : (2 : Int) ^ 199 = - 803469022129495137770981046170581301261101496891396417650688 := by norm_num - have p200 : (2 : Int) ^ 200 = - 1606938044258990275541962092341162602522202993782792835301376 := by norm_num + have p199 : (2 : Int) ^ 191 = + 3138550867693340381917894711603833208051177722232017256448 := by norm_num + have p200 : (2 : Int) ^ 192 = + 6277101735386680763835789423207666416102355444464034512896 := by norm_num have pH : (117932881612756647068972071382077242199 : Int) = 117932881612756647068972071382077242199 := rfl rw [p107] at htlo hthi diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index 4330f2510..0e110fbc3 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -9,9 +9,9 @@ open FormalYul.Preservation abbrev Cmask : Nat := 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 abbrev C0thresh : Nat := 0x907595ccd30708cabec8a9db -abbrev kRoundShift : Nat := 0xc8 -abbrev kHalfShift : Nat := 0xc7 -abbrev cInvQ200 : Nat := 0x724d54edbacbebbb95c52a0f6076 +abbrev kRoundShift : Nat := 0xc0 +abbrev kHalfShift : Nat := 0xbf +abbrev cInvQ192 : Nat := 0x724d54edbacbebbb95c52a0f60 abbrev k27Q235 : Nat := 0x279d346de4781f921dd7a89933d54d1f72928 abbrev ln2Q235 : Nat := 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d @@ -39,10 +39,14 @@ abbrev odShift3 : Nat := 0x7a abbrev odShift4 : Nat := 0x80 abbrev todShift : Nat := 0x81 -abbrev expQShift : Nat := 0x7e -abbrev foldShift : Nat := 0x6c -abbrev wadWord : Nat := 0x3782dace9d9 -abbrev marginWord : Nat := 0x2027afc6c05 +abbrev foldShift : Nat := 0x44 +abbrev scaleQ68 : Nat := 0xde0b6b3a764000000000000000000000 +abbrev marginWord : Nat := 0x3 + +theorem scaleQ68_eq : (scaleQ68 : Int) = 3814697265625 * 2 ^ 86 := by + unfold scaleQ68; norm_num + +theorem scaleQ68_lt_2128 : scaleQ68 < 2 ^ 128 := by unfold scaleQ68; norm_num theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by unfold Cmask int256 diff --git a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean index 13412d68e..96fe48875 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean @@ -4,8 +4,8 @@ import ExpProof.Mono.Quot # Same-octave monotonicity of the quotient `r0` Within a fixed octave (`k` constant) the closing accumulator `r1Tree` is monotone in the input iff -the Q126 quotient `r0Tree` is. With `num = ev + tod`, `den = ev − tod` (both strictly positive), -`r0 = ⌊2^126·num/den⌋`, so +the scaled quotient `r0Tree` is. With `num = ev + tod`, `den = ev − tod` (both strictly positive), +`r0 = ⌊scaleQ68·num/den⌋`, so ``` r0(x1) ≤ r0(x2) ⟸ num1·den2 ≤ num2·den1 (cross-multiply over positive den) @@ -41,25 +41,21 @@ theorem numSum_lt {W : Nat} {ev tod : Int} (hW : int256 W = ev + tod) (hev : ev < 3 * 2 ^ 126) (htod : tod < 2 ^ 126) : int256 W < 2 ^ 128 := by rw [hW, show (2:Int)^128 = 3 * 2^126 + 2^126 from by ring]; omega -/-- The `shl 0x7e N` dividend transported to `Int` when `N`'s signed value is in `[0, 2^128)`: -`int256 (shl 126 N) = 2^126 · int256 N`, and the result is in `[0, 2^255)`. -/ -theorem shl126_transport {N : Nat} (hNw : N < 2 ^ 256) (hNnn : 0 ≤ int256 N) +/-- The `mul scaleQ68 N` dividend as a plain `Nat` product when `N`'s signed value is in +`[0, 2^128)`: `evmMul scaleQ68 N = scaleQ68 * N` (no wrap), and `N` is its own signed value. -/ +theorem mulScale_transport {N : Nat} (hNw : N < 2 ^ 256) (hNnn : 0 ≤ int256 N) (hNlt : int256 N < 2 ^ 128) : - int256 (evmShl 0x7e N) = 2 ^ 0x7e * int256 N := by + evmMul scaleQ68 N = scaleQ68 * N ∧ N < 2 ^ 128 := by obtain ⟨hNi, _⟩ := int256_eq_of_nonneg hNw hNnn have hNnat : N < 2 ^ 128 := by have : ((N : Nat) : Int) < 2 ^ 128 := by rw [← hNi]; exact hNlt exact_mod_cast this - have hfit : N * 2 ^ 0x7e < 2 ^ 256 := by - calc N * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := (Nat.mul_lt_mul_right (Nat.two_pow_pos _)).mpr hNnat - _ = 2 ^ 254 := by rw [← Nat.pow_add] - _ < 2 ^ 256 := by norm_num - have hfit255 : N * 2 ^ 0x7e < 2 ^ 255 := by - calc N * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := (Nat.mul_lt_mul_right (Nat.two_pow_pos _)).mpr hNnat - _ = 2 ^ 254 := by rw [← Nat.pow_add] - _ < 2 ^ 255 := by norm_num - rw [evmShl_eq (by norm_num) hfit, int256_of_lt hfit255, hNi] - push_cast; ring + have hsw : scaleQ68 < 2 ^ 256 := by unfold scaleQ68; norm_num + have hfit : scaleQ68 * N < 2 ^ 256 := by + have h1 : scaleQ68 * N ≤ scaleQ68 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hNnat) + have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + omega + exact ⟨evmMul_eq_nat hsw hNw hfit, hNnat⟩ /-- Abstract `r0` monotonicity from the `tod·ev` cross inequality, over opaque even/odd words. Given the numerator/denominator positivity and `tod1·ev2 ≤ tod2·ev1`, the two `div` quotients are @@ -75,8 +71,8 @@ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} (htod2_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD2) (htod2_hi : int256 TD2 < 85070591730234615865843651857942052864) (hcross : int256 TD1 * (E2 : Int) ≤ int256 TD2 * (E1 : Int)) : - int256 (evmDiv (evmShl 0x7e (evmAdd E1 TD1)) (evmSub E1 TD1)) ≤ - int256 (evmDiv (evmShl 0x7e (evmAdd E2 TD2)) (evmSub E2 TD2)) := by + int256 (evmDiv (evmMul scaleQ68 (evmAdd E1 TD1)) (evmSub E1 TD1)) ≤ + int256 (evmDiv (evmMul scaleQ68 (evmAdd E2 TD2)) (evmSub E2 TD2)) := by obtain ⟨hadd1, hsub1, hnum1, hden1⟩ := numden_pos_of hE1 hTD1 hev1_lo hev1_hi htod1_lo htod1_hi obtain ⟨hadd2, hsub2, hnum2, hden2⟩ := numden_pos_of hE2 hTD2 hev2_lo hev2_hi htod2_lo htod2_hi -- the tod magnitude in the symbolic power form @@ -92,24 +88,95 @@ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} -- denominator positivity in `int256 (evmSub …)` form have hD1pos : 0 < int256 (evmSub E1 TD1) := by rw [hsub1]; exact hden1 have hD2pos : 0 < int256 (evmSub E2 TD2) := by rw [hsub2]; exact hden2 - -- shl dividends transported - have hA1 : int256 (evmShl 0x7e (evmAdd E1 TD1)) = 2 ^ 0x7e * int256 (evmAdd E1 TD1) := - shl126_transport (evmAdd_lt _ _) (le_of_lt (hadd1 ▸ hnum1)) hN1lt - have hA2 : int256 (evmShl 0x7e (evmAdd E2 TD2)) = 2 ^ 0x7e * int256 (evmAdd E2 TD2) := - shl126_transport (evmAdd_lt _ _) (le_of_lt (hadd2 ▸ hnum2)) hN2lt - have hA1pos : 0 < int256 (evmShl 0x7e (evmAdd E1 TD1)) := by - rw [hA1]; exact Int.mul_pos (by positivity) (hadd1 ▸ hnum1) - have hA2pos : 0 < int256 (evmShl 0x7e (evmAdd E2 TD2)) := by - rw [hA2]; exact Int.mul_pos (by positivity) (hadd2 ▸ hnum2) - -- both divs are floor divisions of nonnegative magnitudes - rw [evmDiv_pos_pos (evmShl_lt _ _) (evmSub_lt _ _) (le_of_lt hA1pos) hD1pos, - evmDiv_pos_pos (evmShl_lt _ _) (evmSub_lt _ _) (le_of_lt hA2pos) hD2pos] - -- cross_to_div with the cross product A1·B2 ≤ A2·B1 - have hdd := cross_to_div (le_of_lt hA1pos) (le_of_lt hA2pos) hD1pos hD2pos (by - rw [hA1, hA2, hsub1, hsub2, hadd1, hadd2] - -- 2^126·(E1+TD1)·(E2−TD2) ≤ 2^126·(E2+TD2)·(E1−TD1) ⟺ tod1·ev2 ≤ tod2·ev1 - have hid1 := cross_identity (E1 : Int) (E2 : Int) (int256 TD1) (int256 TD2) - nlinarith [hcross, hid1]) - exact_mod_cast hdd + -- mul dividends as plain Nat products + obtain ⟨hA1, hN1nat⟩ := mulScale_transport (evmAdd_lt _ _) (le_of_lt (hadd1 ▸ hnum1)) hN1lt + obtain ⟨hA2, hN2nat⟩ := mulScale_transport (evmAdd_lt _ _) (le_of_lt (hadd2 ▸ hnum2)) hN2lt + -- canonical Nat values for the numerators and denominators + obtain ⟨hN1i, _⟩ := int256_eq_of_nonneg (evmAdd_lt E1 TD1) (le_of_lt (hadd1 ▸ hnum1)) + obtain ⟨hN2i, _⟩ := int256_eq_of_nonneg (evmAdd_lt E2 TD2) (le_of_lt (hadd2 ▸ hnum2)) + obtain ⟨hD1i, _⟩ := int256_eq_of_nonneg (evmSub_lt E1 TD1) (le_of_lt hD1pos) + obtain ⟨hD2i, _⟩ := int256_eq_of_nonneg (evmSub_lt E2 TD2) (le_of_lt hD2pos) + have hD1posN : 0 < evmSub E1 TD1 := by + have h : (0:Int) < ((evmSub E1 TD1 : Nat) : Int) := by rw [← hD1i]; exact hD1pos + exact_mod_cast h + have hD2posN : 0 < evmSub E2 TD2 := by + have h : (0:Int) < ((evmSub E2 TD2 : Nat) : Int) := by rw [← hD2i]; exact hD2pos + exact_mod_cast h + have hD1nz : evmSub E1 TD1 ≠ 0 := Nat.pos_iff_ne_zero.mp hD1posN + have hD2nz : evmSub E2 TD2 ≠ 0 := Nat.pos_iff_ne_zero.mp hD2posN + have hsw : scaleQ68 < 2 ^ 256 := by unfold scaleQ68; norm_num + have hfit1 : scaleQ68 * evmAdd E1 TD1 < 2 ^ 256 := by + have h1 : scaleQ68 * evmAdd E1 TD1 ≤ scaleQ68 * 2 ^ 128 := + Nat.mul_le_mul_left _ (le_of_lt hN1nat) + have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + omega + have hfit2 : scaleQ68 * evmAdd E2 TD2 < 2 ^ 256 := by + have h1 : scaleQ68 * evmAdd E2 TD2 ≤ scaleQ68 * 2 ^ 128 := + Nat.mul_le_mul_left _ (le_of_lt hN2nat) + have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + omega + -- the two quotients as plain Nat floor divisions + have hq1 : evmDiv (evmMul scaleQ68 (evmAdd E1 TD1)) (evmSub E1 TD1) = + scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 := by + rw [hA1, evmDiv_eq hfit1 (evmSub_lt _ _) hD1nz] + have hq2 : evmDiv (evmMul scaleQ68 (evmAdd E2 TD2)) (evmSub E2 TD2) = + scaleQ68 * evmAdd E2 TD2 / evmSub E2 TD2 := by + rw [hA2, evmDiv_eq hfit2 (evmSub_lt _ _) hD2nz] + -- Nat-level cross monotonicity: q1·D1 ≤ S·N1, S·N1·D2 ≤ S·N2·D1 ⇒ q1·D2 ≤ S·N2 ⇒ q1 ≤ q2 + have hcrossN : evmAdd E1 TD1 * evmSub E2 TD2 ≤ evmAdd E2 TD2 * evmSub E1 TD1 := by + have hInt : ((evmAdd E1 TD1 : Nat) : Int) * ((evmSub E2 TD2 : Nat) : Int) ≤ + ((evmAdd E2 TD2 : Nat) : Int) * ((evmSub E1 TD1 : Nat) : Int) := by + rw [← hN1i, ← hN2i, ← hD1i, ← hD2i, hadd1, hadd2, hsub1, hsub2] + have hid1 := cross_identity (E1 : Int) (E2 : Int) (int256 TD1) (int256 TD2) + nlinarith [hcross, hid1] + exact_mod_cast hInt + have hD1pos' : 0 < evmSub E1 TD1 := Nat.pos_of_ne_zero hD1nz + have hD2pos' : 0 < evmSub E2 TD2 := Nat.pos_of_ne_zero hD2nz + have hqle : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 ≤ + scaleQ68 * evmAdd E2 TD2 / evmSub E2 TD2 := by + rw [Nat.le_div_iff_mul_le hD2pos'] + have hfl : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E1 TD1 ≤ + scaleQ68 * evmAdd E1 TD1 := Nat.div_mul_le_self _ _ + -- (q1·D2)·D1 ≤ S·N1·D2 ≤ S·N2·D1 ⇒ q1·D2 ≤ S·N2 (divide by D1 > 0) + have hstep : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E2 TD2 * evmSub E1 TD1 ≤ + scaleQ68 * evmAdd E2 TD2 * evmSub E1 TD1 := by + calc scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E2 TD2 * evmSub E1 TD1 + = scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E1 TD1 * evmSub E2 TD2 := by ring + _ ≤ scaleQ68 * evmAdd E1 TD1 * evmSub E2 TD2 := Nat.mul_le_mul_right _ hfl + _ = scaleQ68 * (evmAdd E1 TD1 * evmSub E2 TD2) := by ring + _ ≤ scaleQ68 * (evmAdd E2 TD2 * evmSub E1 TD1) := Nat.mul_le_mul_left _ hcrossN + _ = scaleQ68 * evmAdd E2 TD2 * evmSub E1 TD1 := by ring + exact Nat.le_of_mul_le_mul_right hstep hD1pos' + -- transport back to int256 (both quotients are small: den ≥ 2^126) + have hD1ge : 2 ^ 126 ≤ evmSub E1 TD1 := by + have h : (85070591730234615865843651857942052864 : Int) ≤ ((evmSub E1 TD1 : Nat) : Int) := by + rw [← hD1i, hsub1] + linarith [hev1_lo, htod1_hi] + exact_mod_cast h + have hD2ge : 2 ^ 126 ≤ evmSub E2 TD2 := by + have h : (85070591730234615865843651857942052864 : Int) ≤ ((evmSub E2 TD2 : Nat) : Int) := by + rw [← hD2i, hsub2] + linarith [hev2_lo, htod2_hi] + exact_mod_cast h + have hq1small : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 < 2 ^ 255 := by + have h1 : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 ≤ scaleQ68 * evmAdd E1 TD1 / 2 ^ 126 := + Nat.div_le_div_left hD1ge (Nat.two_pow_pos _) + have h2 : scaleQ68 * evmAdd E1 TD1 / 2 ^ 126 < 2 ^ 130 := by + rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] + calc scaleQ68 * evmAdd E1 TD1 < 2 ^ 256 := hfit1 + _ = 2 ^ 130 * 2 ^ 126 := by norm_num + have h3 : (2:Nat) ^ 130 < 2 ^ 255 := by norm_num + omega + have hq2small : scaleQ68 * evmAdd E2 TD2 / evmSub E2 TD2 < 2 ^ 255 := by + have h1 : scaleQ68 * evmAdd E2 TD2 / evmSub E2 TD2 ≤ scaleQ68 * evmAdd E2 TD2 / 2 ^ 126 := + Nat.div_le_div_left hD2ge (Nat.two_pow_pos _) + have h2 : scaleQ68 * evmAdd E2 TD2 / 2 ^ 126 < 2 ^ 130 := by + rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] + calc scaleQ68 * evmAdd E2 TD2 < 2 ^ 256 := hfit2 + _ = 2 ^ 130 * 2 ^ 126 := by norm_num + have h3 : (2:Nat) ^ 130 < 2 ^ 255 := by norm_num + omega + rw [hq1, hq2, int256_of_lt hq1small, int256_of_lt hq2small] + exact_mod_cast hqle end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean index 41ab077af..49b65edc8 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean @@ -30,13 +30,13 @@ theorem region_x_bound {x : Nat} (hC : int256 Cmask < int256 x) exact hC0 constructor <;> [skip; skip] <;> simp only [show (2:Int)^96 = 79228162514264337593543950336 from by norm_num] <;> omega -theorem CINV_lt : (0x724d54edbacbebbb95c52a0f6076 : Nat) < 2 ^ 112 := by norm_num +theorem CINV_lt : (0x724d54edbacbebbb95c52a0f60 : Nat) < 2 ^ 112 := by norm_num theorem K27_lt : (0x279d346de4781f921dd7a89933d54d1f72928 : Nat) < 2 ^ 146 := by norm_num theorem LN2_lt : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Nat) < 2 ^ 235 := by norm_num /-- `int256` of the constant `CINV` (it is below `2^255`, so the signed view is the literal). -/ -theorem int256_CINV : int256 0x724d54edbacbebbb95c52a0f6076 = 0x724d54edbacbebbb95c52a0f6076 := by +theorem int256_CINV : int256 0x724d54edbacbebbb95c52a0f60 = 0x724d54edbacbebbb95c52a0f60 := by unfold int256; norm_num theorem int256_K27 : int256 0x279d346de4781f921dd7a89933d54d1f72928 = 0x279d346de4781f921dd7a89933d54d1f72928 := by @@ -46,61 +46,61 @@ theorem int256_LN2 : 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d := by unfold int256; norm_num -/-- `2^199 = evmShl 0xc7 1`. -/ -theorem evmShl_c7_one : evmShl 0xc7 1 = 2 ^ 199 := by +/-- `2^191 = evmShl 0xbf 1`. -/ +theorem evmShl_bf_one : evmShl 0xbf 1 = 2 ^ 191 := by rw [evmShl_eq (by norm_num) (by norm_num)]; norm_num /-! ## The octave index `k` -/ -/-- The argument of the rounding shift, transported to `Int`: `2^199 + CINV · int256 x`. -/ +/-- The argument of the rounding shift, transported to `Int`: `2^191 + CINV · int256 x`. -/ theorem int256_kArg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - int256 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) = - 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x := by + int256 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) = + 2 ^ 191 + 0x724d54edbacbebbb95c52a0f60 * int256 x := by obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 have hx96 : (-(2 ^ 96 : Int)) < int256 x ∧ int256 x < 2 ^ 96 := ⟨hxlo, hxhi⟩ have hb96 : (2 : Int) ^ 96 = 79228162514264337593543950336 := by norm_num -- the product `CINV * int256 x` fits - have hmul : int256 (evmMul 0x724d54edbacbebbb95c52a0f6076 x) = - 0x724d54edbacbebbb95c52a0f6076 * int256 x := by + have hmul : int256 (evmMul 0x724d54edbacbebbb95c52a0f60 x) = + 0x724d54edbacbebbb95c52a0f60 * int256 x := by rw [evmMul_transport (by norm_num) hx ?_ ?_, int256_CINV] · rw [int256_CINV] simp only [hb96] at hxlo hxhi - have : -(2 ^ 255 : Int) ≤ 0x724d54edbacbebbb95c52a0f6076 * int256 x := by + have : -(2 ^ 255 : Int) ≤ 0x724d54edbacbebbb95c52a0f60 * int256 x := by simp only [ipow255]; nlinarith [hxlo, hxhi] exact this · rw [int256_CINV] simp only [hb96] at hxlo hxhi simp only [ipow255]; nlinarith [hxlo, hxhi] - have hshl : evmShl 0xc7 1 = 2 ^ 199 := evmShl_c7_one + have hshl : evmShl 0xbf 1 = 2 ^ 191 := evmShl_bf_one rw [hshl] - have hpow199 : (2 : Nat) ^ 199 < 2 ^ 256 := by norm_num + have hpow199 : (2 : Nat) ^ 191 < 2 ^ 256 := by norm_num rw [evmAdd_transport hpow199 (evmMul_lt _ _) ?_ ?_] · rw [hmul] - have : int256 (2 ^ 199 : Nat) = (2 ^ 199 : Int) := by + have : int256 (2 ^ 191 : Nat) = (2 ^ 191 : Int) := by rw [int256_of_lt (by norm_num)]; norm_num rw [this] · rw [hmul] - have h199 : int256 (2 ^ 199 : Nat) = (2 ^ 199 : Int) := by + have h199 : int256 (2 ^ 191 : Nat) = (2 ^ 191 : Int) := by rw [int256_of_lt (by norm_num)]; norm_num rw [h199]; simp only [hb96, ipow255] at *; nlinarith [hxlo, hxhi] · rw [hmul] - have h199 : int256 (2 ^ 199 : Nat) = (2 ^ 199 : Int) := by + have h199 : int256 (2 ^ 191 : Nat) = (2 ^ 191 : Int) := by rw [int256_of_lt (by norm_num)]; norm_num rw [h199]; simp only [hb96, ipow255] at *; nlinarith [hxlo, hxhi] /-- The argument of the `k`-rounding shift is a valid word (so the sandwich applies). -/ theorem kArg_lt {x : Nat} : - evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x) < 2 ^ 256 := evmAdd_lt _ _ + evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x) < 2 ^ 256 := evmAdd_lt _ _ -/-- The `k`-floor sandwich on the meaningful region: `2^200·k ≤ 2^199 + CINV·x < 2^200·k + 2^200`. -/ +/-- The `k`-floor sandwich on the meaningful region: `2^192·k ≤ 2^191 + CINV·x < 2^192·k + 2^192`. -/ theorem kTree_sandwich {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 200 : Int) * int256 (kTree x) ≤ 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x ∧ - 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x < - (2 ^ 200 : Int) * int256 (kTree x) + 2 ^ 200 := by + (2 ^ 192 : Int) * int256 (kTree x) ≤ 2 ^ 191 + 0x724d54edbacbebbb95c52a0f60 * int256 x ∧ + 2 ^ 191 + 0x724d54edbacbebbb95c52a0f60 * int256 x < + (2 ^ 192 : Int) * int256 (kTree x) + 2 ^ 192 := by unfold kTree - obtain ⟨_, hlo, hhi⟩ := evmSar_sandwich (s := 0xc8) (by norm_num) (kArg_lt (x := x)) + obtain ⟨_, hlo, hhi⟩ := evmSar_sandwich (s := 0xc0) (by norm_num) (kArg_lt (x := x)) rw [int256_kArg hx hC hC0] at hlo hhi exact ⟨by simpa using hlo, by simpa using hhi⟩ @@ -114,13 +114,13 @@ theorem kTree_mono {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) obtain ⟨hlo1, hhi1⟩ := kTree_sandwich hx1 hC1 hC01 obtain ⟨hlo2, hhi2⟩ := kTree_sandwich hx2 hC2 hC02 -- kArg increases with int256 x (CINV > 0), and floor is monotone. - have hcinv : (0 : Int) < 0x724d54edbacbebbb95c52a0f6076 := by norm_num - have hargle : 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x1 ≤ - 2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x2 := by + have hcinv : (0 : Int) < 0x724d54edbacbebbb95c52a0f60 := by norm_num + have hargle : 2 ^ 191 + 0x724d54edbacbebbb95c52a0f60 * int256 x1 ≤ + 2 ^ 191 + 0x724d54edbacbebbb95c52a0f60 * int256 x2 := by have := mul_le_mul_left_nonneg hle (le_of_lt hcinv) omega - -- from the two sandwiches: 2^200·k1 ≤ arg1 ≤ arg2 < 2^200·k2 + 2^200 ⇒ k1 < k2 + 1 ⇒ k1 ≤ k2 - have hpow : (0 : Int) < 2 ^ 200 := by norm_num + -- from the two sandwiches: 2^192·k1 ≤ arg1 ≤ arg2 < 2^192·k2 + 2^192 ⇒ k1 < k2 + 1 ⇒ k1 ≤ k2 + have hpow : (0 : Int) < 2 ^ 192 := by norm_num nlinarith [hlo1, hhi2, hargle, hpow] /-- On the meaningful region the octave index is bounded: `-61 ≤ k ≤ 64`. -/ @@ -132,14 +132,14 @@ theorem kTree_bound {x : Nat} (hx : x < 2 ^ 256) have hC0i : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh rw [hCi] at hC rw [hC0i] at hC0 - have hcinv : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by + have hcinv : (0x724d54edbacbebbb95c52a0f60 : Int) = 9055943544797870567083544809312 := by norm_num -- bound the rounding-shift argument from the exact region endpoints. - have hprod_lo : (0x724d54edbacbebbb95c52a0f6076 : Int) * int256 x > - 0x724d54edbacbebbb95c52a0f6076 * (-41446531673892822312323846185) := by + have hprod_lo : (0x724d54edbacbebbb95c52a0f60 : Int) * int256 x > + 0x724d54edbacbebbb95c52a0f60 * (-41446531673892822312323846185) := by rw [hcinv]; nlinarith [hC] - have hprod_hi : (0x724d54edbacbebbb95c52a0f6076 : Int) * int256 x < - 0x724d54edbacbebbb95c52a0f6076 * 44707993146116472457411471835 := by + have hprod_hi : (0x724d54edbacbebbb95c52a0f60 : Int) * int256 x < + 0x724d54edbacbebbb95c52a0f60 * 44707993146116472457411471835 := by rw [hcinv]; nlinarith [hC0] constructor · nlinarith [hhi, hprod_lo] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean index 06e757e95..7b58a88f4 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean @@ -22,6 +22,17 @@ open FormalYul.Preservation set_option maxRecDepth 100000 +/-- A word whose signed transport is nonnegative is its own `Int` cast and lies below `2 ^ 255`. -/ +theorem int256_eq_of_nonneg {w : Nat} (hw : w < 2 ^ 256) (hnn : 0 ≤ int256 w) : + int256 w = (w : Int) ∧ w < 2 ^ 255 := by + unfold int256 at hnn ⊢ + by_cases h : w < 2 ^ 255 + · rw [if_pos h] + exact ⟨rfl, h⟩ + · rw [if_neg h] at hnn + exfalso + omega + /-! ## `tod = t·Od` in Q88 -/ /-- `tod` transported to `Int`: a signed floor with `|tod| < 2^126`. The product `t·Od` fits a word @@ -131,92 +142,75 @@ theorem numden_pos {x : Nat} (hx : x < 2 ^ 256) · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_lo · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_hi -/-! ## The closing quotient `r0 = exp(t)·2^126` -/ +/-! ## The runtime quotient `r0 = ⌊(10¹⁸·2⁶⁸)·num/den⌋` -/ -/-- Abstract quotient bounds over opaque numerator/denominator words. `r0 = ⌊2^126·N/D⌋` lies in -`[2^123, 2^128)`: the dividend `2^126·N` fits a word, `2^123·D < 2^251 ≤ 2^126·N` keeps the -quotient `≥ 2^123` (comfortably clearing the closing stage's `WAD·r0 > MARGIN`), and -`N < 4·D` keeps it below `2^128`. -/ +/-- Abstract scaled-quotient bounds over opaque numerator/denominator words: `⌊scaleQ68·N/D⌋` +lies in `[2^124, 2^130)`. The dividend `scaleQ68·N` fits a word (`N < 2^128`, +`scaleQ68 < 2^128`); `2^124·D < 2^252 ≤ scaleQ68·N` keeps the quotient `≥ 2^124` (comfortably +clearing the closing stage's `r0 > MARGIN`), and `N < 4·D` with `4·scaleQ68 ≤ 2^130` keeps it +below `2^130`. -/ theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD : D < 2 ^ 256) (hDi : int256 D = (D : Int)) (hNpos : 0 < (N : Int)) (hDpos : 0 < (D : Int)) (hNlo : 2 ^ 125 ≤ N) (hND : (N : Int) < 4 * (D : Int)) : - 2 ^ 123 ≤ int256 (evmDiv (evmShl 0x7e N) D) ∧ int256 (evmDiv (evmShl 0x7e N) D) < 2 ^ 128 := by - -- shl(126, N) = N·2^126 (fits: N < 2^128 ⇒ N·2^126 < 2^254) - have hshl : evmShl 0x7e N = N * 2 ^ 0x7e := by - refine evmShl_eq (by norm_num) ?_ - have : N * 2 ^ 0x7e < 2 ^ 128 * 2 ^ 0x7e := by - have hp : 0 < 2 ^ 0x7e := Nat.two_pow_pos _ - exact (Nat.mul_lt_mul_right hp).mpr hN - rw [show (2:Nat) ^ 128 * 2 ^ 0x7e = 2 ^ 254 by rw [← Nat.pow_add]] at this + 2 ^ 124 ≤ int256 (evmDiv (evmMul scaleQ68 N) D) ∧ + int256 (evmDiv (evmMul scaleQ68 N) D) < 2 ^ 130 := by + have hNw : N < 2 ^ 256 := by + have : (2:Nat) ^ 128 < 2 ^ 256 := by norm_num + omega + have hsw : scaleQ68 < 2 ^ 256 := by unfold scaleQ68; norm_num + have hfit : scaleQ68 * N < 2 ^ 256 := by + have h1 : scaleQ68 * N ≤ scaleQ68 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hN) + have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num omega + have hmul : evmMul scaleQ68 N = scaleQ68 * N := evmMul_eq_nat hsw hNw hfit have hDnat_pos : 0 < D := by exact_mod_cast hDpos - have hNnat_pos : 0 < N := by exact_mod_cast hNpos - -- the quotient is a plain Nat floor division - have hdiv : evmDiv (evmShl 0x7e N) D = N * 2 ^ 0x7e / D := by - rw [evmDiv_eq (evmShl_lt _ _) hD (by omega), hshl] - set q := N * 2 ^ 0x7e / D with hq - have hq_lt : q < 2 ^ 128 := by - rw [hq] - rw [Nat.div_lt_iff_lt_mul hDnat_pos] - -- N·2^126 < 2^128·D ⟺ N < 4·D + have hdiv : evmDiv (evmMul scaleQ68 N) D = scaleQ68 * N / D := by + rw [hmul, evmDiv_eq hfit hD (by omega)] + set q := scaleQ68 * N / D with hq + have hspos : 0 < scaleQ68 := by unfold scaleQ68; norm_num + have hq_lt : q < 2 ^ 130 := by + rw [hq, Nat.div_lt_iff_lt_mul hDnat_pos] have hND' : N < 4 * D := by - have : (N : Int) < 4 * (D : Int) := hND have h4 : ((4 * D : Nat) : Int) = 4 * (D : Int) := by push_cast; ring - rw [← h4] at this; exact_mod_cast this - calc N * 2 ^ 0x7e < 4 * D * 2 ^ 0x7e := by - have hp : 0 < 2 ^ 0x7e := Nat.two_pow_pos _ - exact (Nat.mul_lt_mul_right hp).mpr hND' - _ = 2 ^ 128 * D := by - rw [show (4:Nat) * D * 2 ^ 0x7e = (4 * 2 ^ 0x7e) * D by ring, - show (4:Nat) * 2 ^ 0x7e = 2 ^ 128 by norm_num] - have hq_ge : 2 ^ 123 ≤ q := by + rw [← h4] at hND; exact_mod_cast hND + have h1 : scaleQ68 * N < scaleQ68 * (4 * D) := (Nat.mul_lt_mul_left hspos).mpr hND' + have h2 : scaleQ68 * (4 * D) = (4 * scaleQ68) * D := by ring + have h3 : (4 * scaleQ68) * D ≤ 2 ^ 130 * D := + Nat.mul_le_mul_right _ (by unfold scaleQ68; norm_num) + omega + have hq_ge : 2 ^ 124 ≤ q := by rw [hq, Nat.le_div_iff_mul_le hDnat_pos] - -- 2^123·D < 2^123·2^128 = 2^125·2^126 ≤ N·2^126 - have h1 : (2:Nat) ^ 123 * D ≤ 2 ^ 123 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hDlt) - have h2 : (2:Nat) ^ 123 * 2 ^ 128 = 2 ^ 125 * 2 ^ 0x7e := by norm_num - have h3 : (2:Nat) ^ 125 * 2 ^ 0x7e ≤ N * 2 ^ 0x7e := Nat.mul_le_mul_right _ hNlo + have h1 : (2:Nat) ^ 124 * D ≤ 2 ^ 124 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hDlt) + have h2 : (2:Nat) ^ 124 * 2 ^ 128 ≤ scaleQ68 * 2 ^ 125 := by unfold scaleQ68; norm_num + have h3 : scaleQ68 * 2 ^ 125 ≤ scaleQ68 * N := Nat.mul_le_mul_left _ hNlo omega - have hqi : int256 (evmDiv (evmShl 0x7e N) D) = (q : Int) := by + have hqi : int256 (evmDiv (evmMul scaleQ68 N) D) = (q : Int) := by rw [hdiv] exact int256_of_lt (by - have : (2:Nat) ^ 128 < 2 ^ 255 := by norm_num + have : (2:Nat) ^ 130 < 2 ^ 255 := by norm_num omega) rw [hqi] exact ⟨by exact_mod_cast hq_ge, by exact_mod_cast hq_lt⟩ -/-- For a canonical word with nonnegative signed value, the signed value is the Nat value (and the -word lies in the lower half). -/ -theorem int256_eq_of_nonneg {w : Nat} (hw : w < 2 ^ 256) (hnn : 0 ≤ int256 w) : - int256 w = (w : Int) ∧ w < 2 ^ 255 := by - unfold int256 at hnn ⊢ - split at hnn - · rename_i h; exact ⟨if_pos h, h⟩ - · rename_i h; exfalso; simp only [ipow256] at hnn; have : (w : Int) < 2 ^ 256 := by exact_mod_cast hw - simp only [ipow256] at this; omega - -/-- Abstract `r0` bounds: `2^123 ≤ r0 < 2^128` over opaque even/odd words `E`, `TD` with their -bounds. `r0 = div(2^126·(E+TD), E−TD)`; the numerator and denominator are positive and the -quotient lands in `[2^123, 2^128)` (the reduced argument keeps `exp(t) ∈ [1/√2, √2)`). -/ +/-- Abstract runtime `r0` bounds over opaque even/odd words: `2^124 ≤ r0 < 2^130` with +`r0 = div(scaleQ68·(E+TD), E−TD)`. -/ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) (hev_lo : (207573926795459379279817565122117813128 : Int) ≤ (E : Int)) (hev_hi : (E : Int) < 3 * 2 ^ 126) (htod_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD) (htod_hi : int256 TD < 85070591730234615865843651857942052864) : - 2 ^ 123 ≤ int256 (evmDiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) ∧ - int256 (evmDiv (evmShl 0x7e (evmAdd E TD)) (evmSub E TD)) < 2 ^ 128 := by + 2 ^ 124 ≤ int256 (evmDiv (evmMul scaleQ68 (evmAdd E TD)) (evmSub E TD)) ∧ + int256 (evmDiv (evmMul scaleQ68 (evmAdd E TD)) (evmSub E TD)) < 2 ^ 130 := by obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos_of hevw htodw hev_lo hev_hi htod_lo htod_hi have hNwlt : evmAdd E TD < 2 ^ 256 := evmAdd_lt _ _ have hDwlt : evmSub E TD < 2 ^ 256 := evmSub_lt _ _ - -- numeric forms have h128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num have h127 : (3:Int) * 2 ^ 126 = 255211775190703847597530955573826158592 := by norm_num rw [h127] at hev_hi - -- canonical Nat values for num and den obtain ⟨hNi, hNlt255⟩ := int256_eq_of_nonneg hNwlt (by rw [hadd]; omega) obtain ⟨hDi, hDlt255⟩ := int256_eq_of_nonneg hDwlt (by rw [hsub]; omega) - -- numerator and denominator Nat bounds have hNlt128 : evmAdd E TD < 2 ^ 128 := by have : ((evmAdd E TD : Nat) : Int) < 2 ^ 128 := by rw [← hNi, hadd, h128]; omega exact_mod_cast this @@ -234,15 +228,15 @@ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 have hDpos : 0 < ((evmSub E TD : Nat) : Int) := by rw [← hDi, hsub]; omega exact r0Tree_bounds_of hNlt128 hDlt128 hDwlt hDi hNpos hDpos hNlo hND -/-- `2^123 ≤ r0Tree x < 2^128` on the meaningful region. -/ +/-- `2^124 ≤ r0Tree x < 2^130` on the meaningful region. -/ theorem r0Tree_bounds {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 2 ^ 123 ≤ int256 (r0Tree x) ∧ int256 (r0Tree x) < 2 ^ 128 := by + 2 ^ 124 ≤ int256 (r0Tree x) ∧ int256 (r0Tree x) < 2 ^ 130 := by obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 obtain ⟨hev_lo, hev_hi⟩ := evTree_facts hvlt obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 have hr0 : r0Tree x = - evmDiv (evmShl 0x7e (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) := rfl + evmDiv (evmMul scaleQ68 (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) := rfl rw [hr0] have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean index 01337fc89..0e8188249 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -3,14 +3,14 @@ import ExpProof.Mono.Quot /-! # The range and nonnegativity obligations of `RegionMonotonicityFacts` -`r1Tree x = shr(108 − k, WAD·r0 − MARGIN)` closes the kernel: it scales the Q126 quotient onto the -`5¹⁸·2¹⁰⁸` grid, subtracts the one-sided margin, and floors with the `2ᵏ` octave scaling and the -wad unit's remaining `2¹⁸` folded into the shift (`108 − k ∈ [44, 169]`). +`r1Tree x = shr(68 − k, r0 − MARGIN)` closes the kernel: the quotient already carries the +`10¹⁸·2⁶⁸` output scale, so the closing stage subtracts the one-sided margin and floors with the +`2ᵏ` octave scaling folded into the shift (`68 − k ∈ [4, 129]`). -* **nonneg**: `r0 ≥ 2^123` gives `WAD·r0 > MARGIN`, and the shift argument is nonnegative; the +* **nonneg**: `r0 ≥ 2^124` gives `r0 > MARGIN`, and the shift argument is nonnegative; the logical shift of a canonical nonnegative word stays nonnegative. -* **range**: `r0 < 2^128` gives `WAD·r0 < 2^170`, so even before the shift the argument is below - `2^170`, and the floor is below `2^125 < 2^254`. +* **range**: `r0 < 2^130` keeps the shift argument below `2^130`, and the `≥ 4` shift floors it + below `2^126 < 2^254`. -/ namespace ExpYul @@ -20,100 +20,83 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-! ## The closing shift amount `108 − k` -/ +/-! ## The closing shift amount `68 − k` -/ -/-- The shift word `evmSub 0x6c k` equals `108 − int256 k` as a `Nat`, and lies in `[44, 169]` on +/-- The shift word `evmSub 0x44 k` equals `68 − int256 k` as a `Nat`, and lies in `[4, 129]` on the meaningful region (`k ∈ [−61, 64]`). -/ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - ∃ s : Nat, evmSub 0x6c (kTree x) = s ∧ 44 ≤ s ∧ s ≤ 169 ∧ - (s : Int) = 108 - int256 (kTree x) := by + ∃ s : Nat, evmSub 0x44 (kTree x) = s ∧ 4 ≤ s ∧ s ≤ 129 ∧ + (s : Int) = 68 - int256 (kTree x) := by obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 have hkw : kTree x < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ - -- 108 (as int) - int256 k, transported through evmSub - have h108 : int256 (0x6c : Nat) = 108 := by + -- 68 (as int) - int256 k, transported through evmSub + have h68 : int256 (0x44 : Nat) = 68 := by rw [int256_of_lt (by norm_num)]; simp have hip255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by norm_num - have hsub : int256 (evmSub 0x6c (kTree x)) = 108 - int256 (kTree x) := by - have := evmSub_transport (a := 0x6c) (b := kTree x) (by norm_num) hkw - (by rw [h108, hip255]; omega) - (by rw [h108, hip255]; omega) - rw [h108] at this; exact this - -- the result is a small nonnegative word, so its Nat value is 108 - int256 k - have hsublt : evmSub 0x6c (kTree x) < 2 ^ 256 := evmSub_lt _ _ - have hnn : 0 ≤ int256 (evmSub 0x6c (kTree x)) := by rw [hsub]; omega + have hsub : int256 (evmSub 0x44 (kTree x)) = 68 - int256 (kTree x) := by + have := evmSub_transport (a := 0x44) (b := kTree x) (by norm_num) hkw + (by rw [h68, hip255]; omega) + (by rw [h68, hip255]; omega) + rw [h68] at this; exact this + -- the result is a small nonnegative word, so its Nat value is 68 - int256 k + have hsublt : evmSub 0x44 (kTree x) < 2 ^ 256 := evmSub_lt _ _ + have hnn : 0 ≤ int256 (evmSub 0x44 (kTree x)) := by rw [hsub]; omega obtain ⟨heq, hlt255⟩ := int256_eq_of_nonneg hsublt hnn - refine ⟨evmSub 0x6c (kTree x), rfl, ?_, ?_, ?_⟩ - · -- 44 ≤ s - have : (44 : Int) ≤ ((evmSub 0x6c (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega + refine ⟨evmSub 0x44 (kTree x), rfl, ?_, ?_, ?_⟩ + · -- 4 ≤ s + have : (4 : Int) ≤ ((evmSub 0x44 (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega exact_mod_cast this - · have : ((evmSub 0x6c (kTree x) : Nat) : Int) ≤ 169 := by rw [← heq, hsub]; omega + · have : ((evmSub 0x44 (kTree x) : Nat) : Int) ≤ 129 := by rw [← heq, hsub]; omega exact_mod_cast this · rw [← heq]; exact hsub -/-! ## The shift argument `WAD·r0 − MARGIN` -/ +/-! ## The shift argument `r0 − MARGIN` -/ -/-- Abstract bound on the shift argument `WAD·r0 − MARGIN` over an opaque `r0` word in -`[2^123, 2^128)`: its signed value is in `[WAD·2^123 − MARGIN, 2^170)`, in particular nonnegative -and below `2^170`. -/ +/-- Abstract bound on the shift argument `r0 − MARGIN` over an opaque `r0` word in +`[2^124, 2^130)`: its signed value is in `[2^124 − MARGIN, 2^130)`, in particular nonnegative +and below `2^130`. -/ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) - (hr0_lo : (2 ^ 123 : Int) ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 128) : - int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) = - 0x3782dace9d9 * int256 r0 - 0x2027afc6c05 ∧ - 0 ≤ 0x3782dace9d9 * int256 r0 - 0x2027afc6c05 ∧ - 0x3782dace9d9 * int256 r0 - 0x2027afc6c05 < 2 ^ 170 := by - have hwad : int256 (0x3782dace9d9 : Nat) = 0x3782dace9d9 := by + (hr0_lo : (2 ^ 124 : Int) ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 130) : + int256 (evmSub r0 0x3) = int256 r0 - 0x3 ∧ + 0 ≤ int256 r0 - 0x3 ∧ + int256 r0 - 0x3 < 2 ^ 130 := by + have hmarlt : (0x3 : Nat) < 2 ^ 256 := by norm_num + have hmari : int256 (0x3 : Nat) = 0x3 := by rw [int256_of_lt (by norm_num)]; simp - have hwadlt : (0x3782dace9d9 : Nat) < 2 ^ 256 := by norm_num - have hp128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num - have hp170 : (2:Int)^170 = 1496577676626844588240573268701473812127674924007424 := by norm_num - have hwadc : (0x3782dace9d9 : Int) = 3814697265625 := by norm_num - have hmarc : (0x2027afc6c05 : Int) = 2209676553221 := by norm_num - rw [hp128] at hr0_hi - -- the product WAD·r0 transported - have hmul : int256 (evmMul 0x3782dace9d9 r0) = 0x3782dace9d9 * int256 r0 := by - have := evmMul_transport hwadlt hr0w - (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) - (by rw [hwad, hwadc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) - rw [hwad] at this; exact this - have hmullt : evmMul 0x3782dace9d9 r0 < 2 ^ 256 := evmMul_lt _ _ - have hmarlt : (0x2027afc6c05 : Nat) < 2 ^ 256 := by norm_num - have hmari : int256 (0x2027afc6c05 : Nat) = 0x2027afc6c05 := by - rw [int256_of_lt (by norm_num)]; simp - -- transport the subtraction - have hsub : int256 (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) = - 0x3782dace9d9 * int256 r0 - 0x2027afc6c05 := by - have := evmSub_transport hmullt hmarlt - (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) - (by rw [hmul, hmari, hwadc, hmarc]; simp only [ipow255]; nlinarith [hr0_lo, hr0_hi]) - rw [hmul, hmari] at this; exact this - refine ⟨hsub, ?_, ?_⟩ - · rw [hwadc, hmarc] - have hp123 : (2:Int)^123 = 10633823966279326983230456482242756608 := by norm_num - rw [hp123] at hr0_lo - nlinarith [hr0_lo] - · rw [hwadc, hmarc, hp170]; nlinarith [hr0_hi] + have hp124 : (2:Int)^124 = 21267647932558653966460912964485513216 := by norm_num + have hp130 : (2:Int)^130 = 1361129467683753853853498429727072845824 := by norm_num + have hip255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by + norm_num + rw [hp124] at hr0_lo + rw [hp130] at hr0_hi + have hsub : int256 (evmSub r0 0x3) = int256 r0 - 0x3 := by + have := evmSub_transport hr0w hmarlt + (by rw [hmari]; simp only [ipow255]; omega) + (by rw [hmari]; simp only [ipow255]; omega) + rw [hmari] at this; exact this + refine ⟨hsub, by omega, by omega⟩ /-! ## Abstract floor facts for the closing shift -/ -/-- Abstract closing-shift facts over an opaque shift argument word `W` and shift `s ∈ [44, 169]` -with `int256 W ∈ [0, 2^170)`: the floor `shr(s, W)` is nonnegative and below `2^126`. -/ -theorem closingShr_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 44 ≤ s) (hshi : s ≤ 169) - (hWnn : 0 ≤ int256 W) (hWhi : int256 W < 2 ^ 170) : +/-- Abstract closing-shift facts over an opaque shift argument word `W` and shift `s ∈ [4, 129]` +with `int256 W ∈ [0, 2^130)`: the floor `shr(s, W)` is nonnegative and below `2^126`. -/ +theorem closingShr_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 4 ≤ s) (hshi : s ≤ 129) + (hWnn : 0 ≤ int256 W) (hWhi : int256 W < 2 ^ 130) : 0 ≤ int256 (evmShr s W) ∧ int256 (evmShr s W) < 2 ^ 126 := by obtain ⟨hWi, _⟩ := int256_eq_of_nonneg hWw hWnn - have hWnat : W < 2 ^ 170 := by - have : ((W : Nat) : Int) < 2 ^ 170 := by rw [← hWi]; exact hWhi + have hWnat : W < 2 ^ 130 := by + have : ((W : Nat) : Int) < 2 ^ 130 := by rw [← hWi]; exact hWhi exact_mod_cast this rw [evmShr_eq_div (by omega) hWw] have hqlt : W / 2 ^ s < 2 ^ 126 := by - have h44 : (2:Nat) ^ 44 ≤ 2 ^ s := Nat.pow_le_pow_right (by norm_num) hslo - have h1 : W / 2 ^ s ≤ W / 2 ^ 44 := Nat.div_le_div_left h44 (Nat.two_pow_pos _) - have h2 : W / 2 ^ 44 < 2 ^ 126 := by + have h4 : (2:Nat) ^ 4 ≤ 2 ^ s := Nat.pow_le_pow_right (by norm_num) hslo + have h1 : W / 2 ^ s ≤ W / 2 ^ 4 := Nat.div_le_div_left h4 (Nat.two_pow_pos _) + have h2 : W / 2 ^ 4 < 2 ^ 126 := by rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] - calc W < 2 ^ 170 := hWnat - _ = 2 ^ 126 * 2 ^ 44 := by rw [← Nat.pow_add] + calc W < 2 ^ 130 := hWnat + _ = 2 ^ 126 * 2 ^ 4 := by rw [← Nat.pow_add] omega rw [int256_of_lt (by have : (2:Nat) ^ 126 < 2 ^ 255 := by norm_num @@ -135,11 +118,10 @@ theorem r1Tree_int256_nonneg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) := rfl + have hr1 : r1Tree x = evmShr (evmSub 0x44 (kTree x)) (evmSub (r0Tree x) 0x3) := rfl rw [hr1, hseq] - exact (closingShr_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) - (by rw [hargeq]; exact harghi)).1 + exact (closingShr_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; omega) + (by rw [hargeq]; omega)).1 /-- **`range`**: `r1Tree x < 2^254` on the meaningful region. -/ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) @@ -148,12 +130,11 @@ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmShr (evmSub 0x6c (kTree x)) - (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) := rfl - obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05) - (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; exact hargnn) (by rw [hargeq]; exact harghi) - -- int256 (r1Tree x) ∈ [0, 2^125) ⇒ the Nat word is < 2^254 - have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x)) 0x2027afc6c05)) := by + have hr1 : r1Tree x = evmShr (evmSub 0x44 (kTree x)) (evmSub (r0Tree x) 0x3) := rfl + obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (r0Tree x) 0x3) + (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; omega) (by rw [hargeq]; omega) + -- int256 (r1Tree x) ∈ [0, 2^126) ⇒ the Nat word is < 2^254 + have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (r0Tree x) 0x3)) := by rw [hr1, hseq] rw [← hReq] at hnn hlt have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x diff --git a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean index ae48f6ce0..878417711 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean @@ -16,7 +16,7 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-- The octave index advances by `0` or `1` per unit input step (`CINV ≪ 2^200`). -/ +/-- The octave index advances by `0` or `1` per unit input step (`CINV ≪ 2^192`). -/ theorem kTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) @@ -25,18 +25,18 @@ theorem kTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) obtain ⟨hlo1, hhi1⟩ := kTree_sandwich hx1 hC1 hC01 obtain ⟨hlo2, hhi2⟩ := kTree_sandwich hx2 hC2 hC02 have hmono := kTree_mono hx1 hx2 hC1 (by omega) hC02 - -- the rounding argument advances by exactly `CINV < 2^200` + -- the rounding argument advances by exactly `CINV < 2^192` set k1 := int256 (kTree x1) set k2 := int256 (kTree x2) - have hcinv : (0x724d54edbacbebbb95c52a0f6076 : Int) < 2 ^ 200 := by norm_num - have hcinvpos : (0 : Int) < 0x724d54edbacbebbb95c52a0f6076 := by norm_num - have hp200 : (0 : Int) < 2 ^ 200 := by norm_num + have hcinv : (0x724d54edbacbebbb95c52a0f60 : Int) < 2 ^ 192 := by norm_num + have hcinvpos : (0 : Int) < 0x724d54edbacbebbb95c52a0f60 := by norm_num + have hp200 : (0 : Int) < 2 ^ 192 := by norm_num -- argument at x2 exceeds that at x1 by exactly CINV - have hstep : (2 ^ 199 : Int) + 0x724d54edbacbebbb95c52a0f6076 * int256 x2 = - (2 ^ 199 + 0x724d54edbacbebbb95c52a0f6076 * int256 x1) + 0x724d54edbacbebbb95c52a0f6076 := by + have hstep : (2 ^ 191 : Int) + 0x724d54edbacbebbb95c52a0f60 * int256 x2 = + (2 ^ 191 + 0x724d54edbacbebbb95c52a0f60 * int256 x1) + 0x724d54edbacbebbb95c52a0f60 := by rw [hadj]; ring rw [hstep] at hlo2 hhi2 - -- 2^200·k2 ≤ A + CINV < 2^200·k1 + 2^200 + CINV < 2^200·(k1 + 2), so k2 < k1 + 2 ⇒ k2 ≤ k1 + 1 + -- 2^192·k2 ≤ A + CINV < 2^192·k1 + 2^192 + CINV < 2^192·(k1 + 2), so k2 < k1 + 2 ⇒ k2 ≤ k1 + 1 have hupper : k2 < k1 + 2 := by nlinarith [hlo2, hhi1, hcinv, hp200] omega diff --git a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean index 366ff24d5..f990489f3 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean @@ -23,10 +23,10 @@ theorem run_exp_ray_to_wad_evm_eq_expTree run_exp_ray_to_wad_evm x = .ok (expTree x) := by rw [run_exp_ray_to_wad_evm_eq_tree x hval] unfold expTree r1Tree r0Tree todTree odTree evTree vTree tTree kTree - unfold Cmask kRoundShift kHalfShift cInvQ200 k27Q235 ln2Q235 tArgShift squareShift + unfold Cmask kRoundShift kHalfShift cInvQ192 k27Q235 ln2Q235 tArgShift squareShift unfold ev0 ev1 ev2 ev3 ev4 evShift1 evShift2 evShift3 evShift4 unfold od0 od1 od2 od3 od4 odShift1 odShift2 odShift3 odShift4 - unfold todShift expQShift foldShift wadWord marginWord + unfold todShift foldShift scaleQ68 marginWord rfl end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean index 640e97d78..fb8d12de4 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -3,16 +3,16 @@ import ExpProof.Mono.RegionMono /-! # The octave-seam step from the `r0` doubling bound -Across a seam (`k` advances by one, `int256 x2 = int256 x1 + 1`) the closing shift `108 − k` drops -exactly one bit, so with the same shift argument `arg = WAD·r0 − MARGIN` the floor identity +Across a seam (`k` advances by one, `int256 x2 = int256 x1 + 1`) the closing shift `68 − k` drops +exactly one bit, so with the same shift argument `arg = r0 − MARGIN` the floor identity ``` r1Tree x2 = ⌊arg2 / 2^(s−1)⌋ = ⌊2·arg2 / 2^s⌋ ≥ ⌊arg1 / 2^s⌋ = r1Tree x1 ⟸ arg1 ≤ 2·arg2 ``` -reduces the seam step to `arg1 ≤ 2·arg2`, which (since `MARGIN ≤ 2·WAD`) follows from the **`r0` -doubling bound** `r0Tree x1 + 2 ≤ 2·r0Tree x2` (`SeamR0Bound`; two integer units of the doubling -gap cover the margin against `2·WAD`). The reduction is assembled over the +reduces the seam step to `arg1 ≤ 2·arg2`, which follows from the **`r0` doubling bound** +`r0Tree x1 + 3 ≤ 2·r0Tree x2` (`SeamR0Bound`; three integer units of the doubling gap cover the +subtracted margin). The reduction is assembled over the opaque shift-argument words (`seam_close`), so the deep `evmShr`/`evmSub`/`evmMul` tree behind `r1Tree` is never forced into whnf. -/ @@ -25,11 +25,11 @@ open FormalYul.Preservation set_option maxRecDepth 100000 /-- **The `r0` doubling bound across a seam.** For adjacent inputs crossing one octave -(`int256 (kTree x2) = int256 (kTree x1) + 1`, `int256 x2 = int256 x1 + 1`), the Q126 quotient at -most doubles, two units short: `r0Tree x1 + 2 ≤ 2·r0Tree x2`. (Across the seam the reduced -argument flips sign `t_b ≈ −t_a`, so `r0_a ≈ exp(t_a)·2^126 ≈ √2·2^126` and -`r0_b ≈ exp(−t_a)·2^126 ≈ 2^126/√2`, hence `r0_a/r0_b ≈ 2·exp(−1/RAY)`, short of doubling by -`≈ 2·r0_b/RAY ≈ 1.7·10^11` grid units — far more than the two units consumed by the seam-floor +(`int256 (kTree x2) = int256 (kTree x1) + 1`, `int256 x2 = int256 x1 + 1`), the scaled quotient at +most doubles, three units short: `r0Tree x1 + 3 ≤ 2·r0Tree x2`. (Across the seam the reduced +argument flips sign `t_b ≈ −t_a`, so `r0_a ≈ exp(t_a)·scaleQ68 ≈ √2·scaleQ68` and +`r0_b ≈ exp(−t_a)·scaleQ68 ≈ scaleQ68/√2`, hence `r0_a/r0_b ≈ 2·exp(−1/RAY)`, short of doubling by +`≈ 2·r0_b/RAY ≈ 4·10^11` grid units — far more than the three units consumed by the seam-floor comparison below.) -/ def SeamR0Bound : Prop := ∀ {x1 x2 : Nat}, x1 < 2 ^ 256 → x2 < 2 ^ 256 → @@ -37,7 +37,7 @@ def SeamR0Bound : Prop := int256 Cmask < int256 x2 → int256 x2 < int256 C0thresh → int256 (kTree x2) = int256 (kTree x1) + 1 → int256 x2 = int256 x1 + 1 → - int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) + int256 (r0Tree x1) + 3 ≤ 2 * int256 (r0Tree x2) /-- Abstract seam floor reduction over opaque nonnegative shift-argument words and shift amounts. With the closing shift dropping one bit (`s2 + 1 = s1`) and `arg1 ≤ 2·arg2`, the two logical-shift @@ -70,17 +70,17 @@ theorem seam_close {arg1 arg2 s1 s2 : Nat} rw [int256_of_lt hq1lt, int256_of_lt hq2lt] exact_mod_cast hqle -/-- The closing shifts at a seam differ by one (`s2 = s1 − 1`), both in `[44, 169]`. -/ +/-- The closing shifts at a seam differ by one (`s2 = s1 − 1`), both in `[4, 129]`. -/ theorem seam_closing_shifts {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hx2 : x2 < 2 ^ 256) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) (hk : int256 (kTree x2) = int256 (kTree x1) + 1) : - ∃ s1 s2 : Nat, evmSub 0x6c (kTree x1) = s1 ∧ evmSub 0x6c (kTree x2) = s2 ∧ + ∃ s1 s2 : Nat, evmSub 0x44 (kTree x1) = s1 ∧ evmSub 0x44 (kTree x2) = s2 ∧ s1 < 256 ∧ s2 < 256 ∧ s2 + 1 = s1 := by obtain ⟨s1, hs1eq, _, hs1hi, hs1int⟩ := closing_shift hx1 hC1 hC01 obtain ⟨s2, hs2eq, hs2lo, _, hs2int⟩ := closing_shift hx2 hC2 hC02 refine ⟨s1, s2, hs1eq, hs2eq, by omega, by omega, ?_⟩ - -- `(s2 : Int) + 1 = 108 − k2 + 1 = 108 − k1 = (s1 : Int)` + -- `(s2 : Int) + 1 = 68 − k2 + 1 = 68 − k1 = (s1 : Int)` have : (s2 : Int) + 1 = (s1 : Int) := by rw [hs1int, hs2int, hk]; ring omega @@ -100,23 +100,25 @@ theorem seamStep_of_r0 (hr0 : SeamR0Bound) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (h obtain ⟨harg1eq, harg1nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 obtain ⟨harg2eq, harg2nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 have hr1eq1 : r1Tree x1 = - evmShr s1 (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2027afc6c05) := by + evmShr s1 (evmSub (r0Tree x1) 0x3) := by unfold r1Tree; rw [hs1eq] have hr1eq2 : r1Tree x2 = - evmShr s2 (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2027afc6c05) := by + evmShr s2 (evmSub (r0Tree x2) 0x3) := by unfold r1Tree; rw [hs2eq] rw [hr1eq1, hr1eq2] -- name the deep shift arguments opaquely before feeding the floor lemma - set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2027afc6c05 with harg1def - set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2027afc6c05 with harg2def - have hr0bound : int256 (r0Tree x1) + 2 ≤ 2 * int256 (r0Tree x2) := + set arg1 := evmSub (r0Tree x1) 0x3 with harg1def + set arg2 := evmSub (r0Tree x2) 0x3 with harg2def + have ha1lt : arg1 < 2 ^ 256 := by rw [harg1def]; exact evmSub_lt _ _ + have ha2lt : arg2 < 2 ^ 256 := by rw [harg2def]; exact evmSub_lt _ _ + clear_value arg1 arg2 + have hr0bound : int256 (r0Tree x1) + 3 ≤ 2 * int256 (r0Tree x2) := hr0 hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hargle : int256 arg1 ≤ 2 * int256 arg2 := by - rw [harg1eq, harg2eq, show (0x3782dace9d9 : Int) = 3814697265625 by norm_num, - show (0x2027afc6c05 : Int) = 2209676553221 by norm_num] - -- `WAD·r0a − M ≤ 2·(WAD·r0b − M)` ⟸ `WAD·r0a + M ≤ 2·WAD·r0b` ⟸ `r0a ≤ 2·r0b − 2` and `M ≤ 2·WAD` - nlinarith [hr0bound] - exact seam_close (harg1def ▸ evmSub_lt _ _) (harg2def ▸ evmSub_lt _ _) hs1lt hs2lt hseq + rw [harg1eq, harg2eq] + -- `r0a − 3 ≤ 2·(r0b − 3)` ⟸ `r0a + 3 ≤ 2·r0b` + linarith [hr0bound] + exact seam_close ha1lt ha2lt hs1lt hs2lt hseq (by rw [harg1eq]; exact harg1nn) (by rw [harg2eq]; exact harg2nn) hargle /-- The seam step (`SeamStep`) follows from the `r0` doubling bound. -/ diff --git a/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean b/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean index 333826673..d3fa6b7b3 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean @@ -4,13 +4,13 @@ import ExpProof.Floor.R0ExpUnder /-! # Discharging the octave-seam `r0`-doubling bound for monotonicity -`SeamR0Bound` (`r0Tree x1 + 2 ≤ 2·r0Tree x2` across one octave seam) is the single analytic +`SeamR0Bound` (`r0Tree x1 + 3 ≤ 2·r0Tree x2` across one octave seam) is the single analytic obligation that `run_exp_ray_to_wad_evm_mono_of_seamR0` carries. The per-point real bracket -`r0Tree x ≈ 2¹²⁶·exp(rt)` (`Floor.R0Exp`/`Floor.R0ExpUnder`, both signs) together with the seam -exp relation +`r0Tree x ≈ scaleQ68·exp(rt)` (`Floor.R0Exp`/`Floor.R0ExpUnder`, both signs) together with the +seam exp relation `rt1 = rt2 + ln2 − 1/RAY` discharges it: `exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`, and the -`1 − exp(−1/RAY) ≈ 1/RAY` slack (against `r0Tree x2 > 2¹²⁴`, worth `≈ 1.7·10¹¹` grid units) -dwarfs both the loose per-point envelope constants and the two integer units the seam-floor +`1 − exp(−1/RAY) ≈ 1/RAY` slack (against `r0Tree x2 > 2¹²⁶`, worth `≈ 8.5·10¹⁰` grid units) +dwarfs both the loose per-point envelope constants and the three integer units the seam-floor comparison consumes. This closes `run_exp_ray_to_wad_evm_mono` without an external monotonicity hypothesis. -/ diff --git a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean index dcd515da4..f9fdc7810 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean @@ -29,7 +29,7 @@ set_option maxRecDepth 100000 /-! ## The reduced-argument bound `|t| < 2^127` -/ /-- On the meaningful region the reduced argument is bounded: `-2^127 < int256 (tTree x) < 2^127`. -The octave reduction couples `k` to `x` (`2^200·k ≈ CINV·x`), so the residual `K27·x − LN2·k` +The octave reduction couples `k` to `x` (`2^192·k ≈ CINV·x`), so the residual `K27·x − LN2·k` stays inside `±ln2/2·2^235`, leaving `|t| < ln2/2·2^128 < 2^127`. -/ theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -45,7 +45,7 @@ theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) 55213970774324510299478046898216203619608872 := by norm_num have hLN2 : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num - have hCINV : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by + have hCINV : (0x724d54edbacbebbb95c52a0f60 : Int) = 9055943544797870567083544809312 := by norm_num rw [hK27, hLN2] at htlo hthi rw [hCINV] at hklo hkhi @@ -55,48 +55,48 @@ theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) -- powers of two as decimals have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num have p127 : (2 : Int) ^ 127 = 170141183460469231731687303715884105728 := by norm_num - have p199 : (2 : Int) ^ 199 = - 803469022129495137770981046170581301261101496891396417650688 := by norm_num - have p200 : (2 : Int) ^ 200 = - 1606938044258990275541962092341162602522202993782792835301376 := by norm_num + have p199 : (2 : Int) ^ 191 = + 3138550867693340381917894711603833208051177722232017256448 := by norm_num + have p200 : (2 : Int) ^ 192 = + 6277101735386680763835789423207666416102355444464034512896 := by norm_num rw [p107] at htlo hthi rw [p199, p200] at hklo hkhi rw [p127] - -- Eliminate `k` by scaling both sandwiches to the common factor `2^200`, then bound `X`. + -- Eliminate `k` by scaling both sandwiches to the common factor `2^192`, then bound `X`. -- LN2 (positive) times the k-sandwich: have hLN2pos : (0 : Int) < 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num have hklo' : 38271408169742254668347313025622401492114385419650052359639581444463709 * - (1606938044258990275541962092341162602522202993782792835301376 * k) ≤ + (6277101735386680763835789423207666416102355444464034512896 * k) ≤ 38271408169742254668347313025622401492114385419650052359639581444463709 * - (803469022129495137770981046170581301261101496891396417650688 + - 2318321547468254865173387471183990 * X) := + (3138550867693340381917894711603833208051177722232017256448 + + 9055943544797870567083544809312 * X) := mul_le_mul_left_nonneg hklo (le_of_lt hLN2pos) have hkhi' : 38271408169742254668347313025622401492114385419650052359639581444463709 * - (803469022129495137770981046170581301261101496891396417650688 + - 2318321547468254865173387471183990 * X) < + (3138550867693340381917894711603833208051177722232017256448 + + 9055943544797870567083544809312 * X) < 38271408169742254668347313025622401492114385419650052359639581444463709 * - (1606938044258990275541962092341162602522202993782792835301376 * k + - 1606938044258990275541962092341162602522202993782792835301376) := + (6277101735386680763835789423207666416102355444464034512896 * k + + 6277101735386680763835789423207666416102355444464034512896) := by have := mul_le_mul_left_nonneg (le_of_lt hkhi) (le_of_lt hLN2pos) rcases lt_or_eq_of_le this with h | h · exact h · exact absurd h.symm (by have := Int.mul_lt_mul_of_pos_left hkhi hLN2pos; omega) - -- 2^200 times the t-sandwich: - have hp200pos : (0 : Int) < 1606938044258990275541962092341162602522202993782792835301376 := by + -- 2^192 times the t-sandwich: + have hp200pos : (0 : Int) < 6277101735386680763835789423207666416102355444464034512896 := by norm_num - have htlo' : 1606938044258990275541962092341162602522202993782792835301376 * + have htlo' : 6277101735386680763835789423207666416102355444464034512896 * (162259276829213363391578010288128 * t) ≤ - 1606938044258990275541962092341162602522202993782792835301376 * + 6277101735386680763835789423207666416102355444464034512896 * (55213970774324510299478046898216203619608872 * X - 38271408169742254668347313025622401492114385419650052359639581444463709 * k) := mul_le_mul_left_nonneg htlo (le_of_lt hp200pos) - have hthi' : 1606938044258990275541962092341162602522202993782792835301376 * + have hthi' : 6277101735386680763835789423207666416102355444464034512896 * (55213970774324510299478046898216203619608872 * X - 38271408169742254668347313025622401492114385419650052359639581444463709 * k) < - 1606938044258990275541962092341162602522202993782792835301376 * + 6277101735386680763835789423207666416102355444464034512896 * (162259276829213363391578010288128 * t + 162259276829213363391578010288128) := by have := mul_le_mul_left_nonneg (le_of_lt hthi) (le_of_lt hp200pos) @@ -125,7 +125,7 @@ theorem tTree_bound_sharp {x : Nat} (hx : x < 2 ^ 256) 55213970774324510299478046898216203619608872 := by norm_num have hLN2 : (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) = 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num - have hCINV : (0x724d54edbacbebbb95c52a0f6076 : Int) = 2318321547468254865173387471183990 := by + have hCINV : (0x724d54edbacbebbb95c52a0f60 : Int) = 9055943544797870567083544809312 := by norm_num rw [hK27, hLN2] at htlo hthi rw [hCINV] at hklo hkhi @@ -133,44 +133,44 @@ theorem tTree_bound_sharp {x : Nat} (hx : x < 2 ^ 256) set k := int256 (kTree x) set X := int256 x have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num - have p199 : (2 : Int) ^ 199 = - 803469022129495137770981046170581301261101496891396417650688 := by norm_num - have p200 : (2 : Int) ^ 200 = - 1606938044258990275541962092341162602522202993782792835301376 := by norm_num + have p199 : (2 : Int) ^ 191 = + 3138550867693340381917894711603833208051177722232017256448 := by norm_num + have p200 : (2 : Int) ^ 192 = + 6277101735386680763835789423207666416102355444464034512896 := by norm_num rw [p107] at htlo hthi rw [p199, p200] at hklo hkhi have hLN2pos : (0 : Int) < 38271408169742254668347313025622401492114385419650052359639581444463709 := by norm_num have hklo' : 38271408169742254668347313025622401492114385419650052359639581444463709 * - (1606938044258990275541962092341162602522202993782792835301376 * k) ≤ + (6277101735386680763835789423207666416102355444464034512896 * k) ≤ 38271408169742254668347313025622401492114385419650052359639581444463709 * - (803469022129495137770981046170581301261101496891396417650688 + - 2318321547468254865173387471183990 * X) := + (3138550867693340381917894711603833208051177722232017256448 + + 9055943544797870567083544809312 * X) := mul_le_mul_left_nonneg hklo (le_of_lt hLN2pos) have hkhi' : 38271408169742254668347313025622401492114385419650052359639581444463709 * - (803469022129495137770981046170581301261101496891396417650688 + - 2318321547468254865173387471183990 * X) < + (3138550867693340381917894711603833208051177722232017256448 + + 9055943544797870567083544809312 * X) < 38271408169742254668347313025622401492114385419650052359639581444463709 * - (1606938044258990275541962092341162602522202993782792835301376 * k + - 1606938044258990275541962092341162602522202993782792835301376) := + (6277101735386680763835789423207666416102355444464034512896 * k + + 6277101735386680763835789423207666416102355444464034512896) := by have := mul_le_mul_left_nonneg (le_of_lt hkhi) (le_of_lt hLN2pos) rcases lt_or_eq_of_le this with h | h · exact h · exact absurd h.symm (by have := Int.mul_lt_mul_of_pos_left hkhi hLN2pos; omega) - have hp200pos : (0 : Int) < 1606938044258990275541962092341162602522202993782792835301376 := by + have hp200pos : (0 : Int) < 6277101735386680763835789423207666416102355444464034512896 := by norm_num - have htlo' : 1606938044258990275541962092341162602522202993782792835301376 * + have htlo' : 6277101735386680763835789423207666416102355444464034512896 * (162259276829213363391578010288128 * t) ≤ - 1606938044258990275541962092341162602522202993782792835301376 * + 6277101735386680763835789423207666416102355444464034512896 * (55213970774324510299478046898216203619608872 * X - 38271408169742254668347313025622401492114385419650052359639581444463709 * k) := mul_le_mul_left_nonneg htlo (le_of_lt hp200pos) - have hthi' : 1606938044258990275541962092341162602522202993782792835301376 * + have hthi' : 6277101735386680763835789423207666416102355444464034512896 * (55213970774324510299478046898216203619608872 * X - 38271408169742254668347313025622401492114385419650052359639581444463709 * k) < - 1606938044258990275541962092341162602522202993782792835301376 * + 6277101735386680763835789423207666416102355444464034512896 * (162259276829213363391578010288128 * t + 162259276829213363391578010288128) := by have := mul_le_mul_left_nonneg (le_of_lt hthi) (le_of_lt hp200pos) diff --git a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean index 86470252c..e3fc7a51a 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean @@ -7,8 +7,8 @@ import ExpProof.Mono.RangeNonneg For two inputs adjacent in the signed order (`int256 x2 = int256 x1 + 1`) in a common octave, the quotient `r0` is nondecreasing (`r0_mono_adjacent`, via the cross inequality `tod_cross` fed to `r0_mono_of_cross`), and hence so is the closing accumulator `r1` (`r1_mono_adjacent`): with `k` -fixed the closing shift `108 − k` is fixed, and the logical-shift floor of the nondecreasing -`WAD·r0 − MARGIN` is nondecreasing. +fixed the closing shift `68 − k` is fixed, and the logical-shift floor of the nondecreasing +`r0 − MARGIN` is nondecreasing. -/ namespace ExpYul @@ -47,9 +47,9 @@ theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have htodw2 : todTree x2 < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ have hcross := tod_cross hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hr01 : r0Tree x1 = - evmDiv (evmShl 0x7e (evmAdd (evTree x1) (todTree x1))) (evmSub (evTree x1) (todTree x1)) := rfl + evmDiv (evmMul scaleQ68 (evmAdd (evTree x1) (todTree x1))) (evmSub (evTree x1) (todTree x1)) := rfl have hr02 : r0Tree x2 = - evmDiv (evmShl 0x7e (evmAdd (evTree x2) (todTree x2))) (evmSub (evTree x2) (todTree x2)) := rfl + evmDiv (evmMul scaleQ68 (evmAdd (evTree x2) (todTree x2))) (evmSub (evTree x2) (todTree x2)) := rfl rw [hr01, hr02] exact r0_mono_of_cross hevw1 htodw1 hevw2 htodw2 hev1lo hev1hi htod1lo htod1hi hev2lo hev2hi htod2lo htod2hi hcross @@ -58,7 +58,7 @@ theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) theorem closing_shift_eq {x1 x2 : Nat} (hk : int256 (kTree x1) = int256 (kTree x2)) (hk1 : kTree x1 < 2 ^ 256) (hk2 : kTree x2 < 2 ^ 256) : - evmSub 0x6c (kTree x1) = evmSub 0x6c (kTree x2) := by + evmSub 0x44 (kTree x1) = evmSub 0x44 (kTree x2) := by -- `int256` is injective on canonical words (`[0, 2^256)`), so `k` words coincide. have hinj : ∀ a b : Nat, a < 2 ^ 256 → b < 2 ^ 256 → int256 a = int256 b → a = b := by intro a b ha hb h @@ -82,7 +82,7 @@ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hr0mono := r0_mono_adjacent hx1 hx2 hC1 hC01 hC2 hC02 hk hadj obtain ⟨hr0lo1, hr0hi1⟩ := r0Tree_bounds hx1 hC1 hC01 obtain ⟨hr0lo2, hr0hi2⟩ := r0Tree_bounds hx2 hC2 hC02 - -- the shift argument `WAD·r0 − MARGIN` is nondecreasing + -- the shift argument `r0 − MARGIN` is nondecreasing obtain ⟨harg1eq, harg1nn, harg1hi⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 obtain ⟨harg2eq, harg2nn, harg2hi⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 -- the closing shift words coincide @@ -90,26 +90,24 @@ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hk2w : kTree x2 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ have hseq := closing_shift_eq hk hk1w hk2w obtain ⟨s, hseqx, hslo, hshi, _⟩ := closing_shift hx1 hC1 hC01 - have hr1eq1 : r1Tree x1 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2027afc6c05) := by + have hr1eq1 : r1Tree x1 = evmShr s (evmSub (r0Tree x1) 0x3) := by unfold r1Tree; rw [hseqx] - have hr1eq2 : r1Tree x2 = evmShr s (evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2027afc6c05) := by + have hr1eq2 : r1Tree x2 = evmShr s (evmSub (r0Tree x2) 0x3) := by unfold r1Tree; rw [← hseq, hseqx] rw [hr1eq1, hr1eq2] -- the two shift arguments, transported to `Int`, are ordered (monotone `r0`) - set arg1 := evmSub (evmMul 0x3782dace9d9 (r0Tree x1)) 0x2027afc6c05 with harg1 - set arg2 := evmSub (evmMul 0x3782dace9d9 (r0Tree x2)) 0x2027afc6c05 with harg2 + set arg1 := evmSub (r0Tree x1) 0x3 with harg1 + set arg2 := evmSub (r0Tree x2) 0x3 with harg2 + have ha1lt : arg1 < 2 ^ 256 := by rw [harg1]; exact evmSub_lt _ _ + have ha2lt : arg2 < 2 ^ 256 := by rw [harg2]; exact evmSub_lt _ _ + -- the deep tree behind the shift arguments is opaque from here on + clear_value arg1 arg2 have hargle : int256 arg1 ≤ int256 arg2 := by rw [harg1eq, harg2eq] - have hwad : (0 : Int) ≤ 0x3782dace9d9 := by norm_num - have := mul_le_mul_left_nonneg hr0mono hwad - omega + exact sub_le_sub_right hr0mono 0x3 -- the shift arguments are nonnegative canonical words, ordered as Nats - have ha1lt : arg1 < 2 ^ 256 := by rw [harg1]; exact evmSub_lt _ _ - have ha2lt : arg2 < 2 ^ 256 := by rw [harg2]; exact evmSub_lt _ _ obtain ⟨he1, hlt1⟩ := int256_eq_of_nonneg ha1lt (by rw [harg1eq]; exact harg1nn) obtain ⟨he2, hlt2⟩ := int256_eq_of_nonneg ha2lt (by rw [harg2eq]; exact harg2nn) - -- the deep tree behind the shift arguments is opaque from here on - clear_value arg1 arg2 have hargleN : arg1 ≤ arg2 := by have : ((arg1 : Nat) : Int) ≤ ((arg2 : Nat) : Int) := by rw [← he1, ← he2]; exact hargle exact_mod_cast this diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index fc228c16e..56a4cd0d6 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -176,7 +176,7 @@ theorem run_exp_ray_to_wad_evm_mono_of_seam (hseamstep : SeamStep) (x1 x2 : Nat) /-- **Runtime monotonicity, modulo the octave-seam `r0` doubling bound.** With the seam-step reduction (`Seam.seamStep_of_seamR0`) and all of `range`/`nonneg`/same-octave/ induction discharged, monotonicity over the entire non-reverting domain follows from the single -analytic bound `SeamR0Bound` (`r0Tree x1 + 2 ≤ 2·r0Tree x2` across one octave). -/ +analytic bound `SeamR0Bound` (`r0Tree x1 + 3 ≤ 2·r0Tree x2` across one octave). -/ theorem run_exp_ray_to_wad_evm_mono_of_seamR0 (hr0 : SeamR0Bound) (x1 x2 : Nat) (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) (hle : int256 x1 ≤ int256 x2) (hdom : int256 x2 < int256 C0thresh) : diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean index 6300573a5..0231b30dd 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -17,7 +17,7 @@ set_option maxRecDepth 100000 /-- Octave index word `k = round(x / (10^27 * ln 2))`. -/ def kTree (x : Nat) : Nat := - evmSar kRoundShift (evmAdd (evmShl kHalfShift 1) (evmMul cInvQ200 x)) + evmSar kRoundShift (evmAdd (evmShl kHalfShift 1) (evmMul cInvQ192 x)) /-- Reduced argument `t` in Q128. -/ def tTree (x : Nat) : Nat := @@ -47,13 +47,15 @@ def odTree (x : Nat) : Nat := /-- `t * Od(v)` in Q88. -/ def todTree (x : Nat) : Nat := evmSar todShift (evmMul (tTree x) (odTree x)) -/-- `exp(t)` in Q126. -/ +/-- `10¹⁸·exp(t)` on the `2⁶⁸` output grid: the numerator is pre-scaled by `10¹⁸·2⁶⁸ = 5¹⁸·2⁸⁶` +before the single `DIV`. -/ def r0Tree (x : Nat) : Nat := - evmDiv (evmShl expQShift (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) + evmDiv (evmMul scaleQ68 (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) -/-- The floored, octave-scaled, margin-subtracted accumulator on the `5¹⁸·2¹⁰⁸` grid. -/ +/-- The floored, octave-scaled, margin-subtracted accumulator on the `2⁶⁸` output grid. -/ def r1Tree (x : Nat) : Nat := - evmShr (evmSub foldShift (kTree x)) (evmSub (evmMul wadWord (r0Tree x)) marginWord) + evmShr (evmSub foldShift (kTree x)) (evmSub (r0Tree x) marginWord) + /-- The clamp/pin shell wrapped around `r1Tree`. -/ def expTree (x : Nat) : Nat := @@ -63,6 +65,7 @@ theorem r0Tree_lt (x : Nat) : r0Tree x < 2 ^ 256 := by unfold r0Tree exact evmDiv_lt _ _ + theorem r1Tree_lt (x : Nat) : r1Tree x < 2 ^ 256 := by unfold r1Tree exact evmShr_lt _ _ diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 0a927f6cb..a43b4e26e 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -414,7 +414,7 @@ theorem call_fun__expRayToWad_78_direct EvmYul.Yul.call (fuel + (extra + 700)) [FormalYul.word x] (.some "fun__expRayToWad_78") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( - let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) @@ -429,8 +429,8 @@ theorem call_fun__expRayToWad_78_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) + let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by @@ -478,7 +478,7 @@ theorem call_fun_expRayToWad_68_direct EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word x] (.some "fun_expRayToWad_68") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( - let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) @@ -493,8 +493,8 @@ theorem call_fun_expRayToWad_68_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) + let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by @@ -541,7 +541,7 @@ theorem call_fun_wrap_expRayToWad_direct EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_97") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( - let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) @@ -556,8 +556,8 @@ theorem call_fun_wrap_expRayToWad_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) + let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by @@ -601,7 +601,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result | .ok (state, _) => FormalYul.resultWord (FormalYul.returnOf state)) : Except String Nat) = .ok ( - let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) @@ -616,8 +616,8 @@ theorem external_fun_wrap_expRayToWad_calldata_result (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) + let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by @@ -630,7 +630,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] set tree : Nat := - (let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + (let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) @@ -645,8 +645,8 @@ theorem external_fun_wrap_expRayToWad_calldata_result (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) + let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1)) with htree @@ -731,7 +731,7 @@ theorem external_fun_wrap_expRayToWad_calldata_halts FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] set tree : Nat := - (let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + (let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) @@ -746,8 +746,8 @@ theorem external_fun_wrap_expRayToWad_calldata_halts (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) + let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1)) with htree @@ -837,7 +837,7 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result | .ok (state, _) => FormalYul.resultWord (FormalYul.returnOf state)) : Except String Nat) = .ok ( - let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) @@ -852,8 +852,8 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) + let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by @@ -916,7 +916,7 @@ theorem run_exp_ray_to_wad_evm_eq_tree (x : Nat) (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : run_exp_ray_to_wad_evm x = .ok ( - let k := evmSar 0xc8 (evmAdd (evmShl 0xc7 1) (evmMul 0x724d54edbacbebbb95c52a0f6076 x)) + let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x85 (evmMul t t) @@ -931,8 +931,8 @@ theorem run_exp_ray_to_wad_evm_eq_tree (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmShl 0x7e (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x6c k) (evmSub (evmMul 0x3782dace9d9 r0) 0x2027afc6c05) + let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 137da3155..7ed565fb6 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -70,7 +70,7 @@ example : run_exp_ray_to_wad_evm 0 = .ok 1000000000000000000 := /-! ## Monotonicity The octave-seam `r0`-doubling bound `SeamR0Bound` is discharged (`seamR0Bound_holds`, via the -per-point real bracket `r0Tree x ≈ 2¹²⁶·exp(rt)` and the seam relation `exp(rt1) = +per-point real bracket `r0Tree x ≈ (10¹⁸·2⁶⁸)·exp(rt)` and the seam relation `exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`), so monotonicity holds over the whole supported domain with no analytic hypothesis. -/ diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 0e74be009..705bd291c 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -27,8 +27,8 @@ library Exp { // Equivalent pseudocode; fixed-point truncations are accounted for below: // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln(2) + t)⋅10²⁷, |t| ≤ ln(2)/2 // t = x/10²⁷ - k⋅ln(2); // range-reduced argument (Q128) - // e = (Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ exp(t) (Ev Q88; Od Q89; e Q126) - // r = ⌊(10¹⁸⋅e)⋅2ᵏ - margin⌋; // wad + // e = 10¹⁸⋅(Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ 10¹⁸⋅exp(t) in Q68 + // r = ⌊(e - margin)⋅2ᵏ⌋; // wad // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 // return r + (x == 0); // pin exp(0) = 10¹⁸ exactly // @@ -51,65 +51,66 @@ library Exp { // Od(v) Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q89 // t⋅Od and the numerator/denominator: Q88. The closing bases are the widest at which // the t⋅Od intermediate product stays inside 256 bits - // quotient: one `DIV` placing exp(t) at Q126 (the dividend, numerator << 126, stays - // below 2²⁵⁵) - // output: multiplying by 5¹⁸ lands E on the 2¹⁰⁸ output grid (the 10¹⁸⋅2¹²⁶ grid with - // the wad unit's 2¹⁸ pre-folded); the closing `shr(108 - k, …)` is the single - // output-rounding floor, with 2ᵏ folded in + // quotient: one `DIV` placing 10¹⁸⋅exp(t) at Q68. The numerator is pre-scaled by + // 10¹⁸⋅2⁶⁸ = 5¹⁸⋅2⁸⁶, the widest such scale at which the dividend stays inside 256 + // bits, and the `DIV` floor is the pipeline's only truncation of the quotient + // output: the closing `shr(68 - k, …)` is the single output-rounding floor, with the 2ᵏ + // octave scaling folded in // - // Error budget. The integer rational `e` lands on the Q126 grid; write its excess over the - // exact quotient as Δ = (e - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the + // Error budget. Let ê = N/D be the exact value of the integer rational (N = Ev + t⋅Od, D = + // Ev - t⋅Od; the closing `DIV` floor is counted on the output grid below) and write its + // excess over exp(t) as Δ = (ê - exp(t))⋅2¹²⁶ (in Q126 units, one unit = 2⁻¹²⁶). Δ is the // tightest bound the proof technique can bear, in spite of the fact that the worst-case // error contributions do not co-occur. The budget bounds Δ ≤ 0.5792534503673398887, the sum // of four one-sided contributions: - // integer Horner + closing `DIV` truncation: the Ev shared by the numerator Ev + t⋅Od - // and denominator Ev - t⋅Od cancels to first order in the quotient, so its - // truncation barely perturbs e; this jitter stays < 0.21706. + // integer Horner truncation: the Ev shared by the numerator Ev + t⋅Od and denominator + // Ev - t⋅Od cancels to first order in the quotient, so its truncation barely + // perturbs ê; this jitter stays < 0.21706. // argument granularity: v carries t² on the Q123 grid, and its floor only lowers the - // polynomials' shared argument (by < 2⁻¹²³), which lifts e on the t > 0 half by < + // polynomials' shared argument (by < 2⁻¹²³), which lifts ê on the t > 0 half by < // 0.32906: one v-grain moves the quotient by 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose // one-signed numerator is maximal at each piece's upper edge and whose denominator // is floored piecewise over 32 domain pieces (the pointwise supremum is ≈ 0.3287 at // t = ln(2)/2). The t < 0 direction is budgeted on the under side. // rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): // < 0.02210 (its supremum is √2⋅2¹²⁶/(2¹³²-1)). - // reduced-argument gap: the Q128 floor of t only pushes e downward (that direction is + // reduced-argument gap: the Q128 floor of t only pushes ê downward (that direction is // budgeted on the under side); the over side is the K27/LN2 constant-grid residue - // (the k⋅ln(2) grid error stays below 2⁻²²⁹), which the proof envelopes one-sidedly - // at 2⁻¹³³ of reduced argument, lifting e by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = - // √2/128). - // Scaling by 10¹⁸⋅2ᵏ, the accumulator's excess over E peaks at the supported edge k = 64 at - // S = 10¹⁸⋅Δ/2⁶² ≈ 0.1256 ulp (1 ulp = 10⁻¹⁸ of the result). The margin is the least - // integer on the 2¹⁰⁸ output grid strictly above Δ's image: 0x2027afc6c05 = ⌊5¹⁸⋅Δ⌋ + 1 = - // 2209676553221 (worth ≈ S ulp at k = 64; the +1 is needed to meet the strict never - // overestimate requirement). So 10¹⁸⋅e⋅2ᵏ - margin ≤ E. The under side is bounded to the - // same precision: e⋅2¹²⁶ ≥ exp(t)⋅2¹²⁶ - 31/10, where 31/10 bounds the sum of the - // integer-rational deficit (≤ 5/2, the Horner/`DIV`/floor truncation against the - // denominator), the `Mp` factor (≤ 1/20, via e ≤ 1.45·2¹²⁶), the under-direction - // reduced-argument gap (≤ 37/100, via exp(t) ≤ √2), and the under-direction argument - // granularity (≤ 17/100: the same one-grain envelope with the negative-half denominator - // floor). Hence the maximum underestimation of the pre-floor accumulator A is E - A ≤ - // ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2⁶² ≈ 0.79781 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The - // deficit envelope ((31/10)⋅10¹⁸ + 2¹⁸⋅margin)/2^(126 - k) doubles each octave and can - // exceed 1ulp at k ≥ 65. On the central octave k = 0 the margin is margin⋅2⁻¹⁰⁸ ≈ 6.8⋅10⁻²¹ - // ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to - // ⌊E⌋. The k = 0 band is exactly [-H, H] with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s - // image over [1/√2, √2). + // (the k⋅ln(2) grid error stays below 2⁻²²⁹), enveloped one-sidedly at 2⁻¹³³ of + // reduced argument, lifting ê by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). + // The quotient carries 10¹⁸⋅ê on the 2⁶⁸ output grid, where one grid unit is worth 2ᵏ⁻⁶⁸ + // ulp (1 ulp = 10⁻¹⁸ of the result) and Δ's image is 5¹⁸⋅Δ/2⁴⁰ < 2.0097 grid units. The + // margin is the least integer strictly above that image: 0x03 (the excess over Δ's image + // meets the strict never-overestimate requirement), worth 3/2⁴ = 0.1875 ulp at the + // supported edge k = 64. The `DIV` floor only lowers the quotient, so the pre-floor + // accumulator A = q - margin satisfies A⋅2ᵏ⁻⁶⁸ ≤ E. The under side is certified directly on + // the output grid: q ≥ 10¹⁸⋅2⁶⁸⋅exp(t) - 33/4, where 33/4 bounds the sum of the + // integer-rational deficit together with the `DIV` floor (≤ 6210/1000; the Horner deficit + // is 3/2 in Q126 units and the floor is one grid unit), the `Mp` factor (≤ 2/25, via ê ≤ + // 1.45), the under-direction reduced-argument gap (≤ 1267/1000, via exp(t) ≤ √2), and the + // under-direction argument granularity (≤ 571/1000: the one-grain envelope with the + // negative-half denominator floor; free on the t > 0 half). Hence the maximum + // underestimation is E - A⋅2ᵏ⁻⁶⁸ ≤ (33/4 + margin)⋅2ᵏ⁻⁶⁸ = (45/4)⋅2ᵏ⁻⁶⁸ ≈ 0.7031 ulp at + // k = 64 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The + // deficit envelope doubles each octave and can exceed 1ulp at k ≥ 65. On the central octave + // k = 0 the margin is 3⋅2⁻⁶⁸ ≈ 1.0⋅10⁻²⁰ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` + // leaves, so the round trip floors to ⌊E⌋. The k = 0 band is exactly [-H, H] with H = + // ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). // // Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves the - // pre-floor accumulator by at least 5¹⁸⋅2¹²⁶⋅10⁻²⁷/√2 ≈ 2.3⋅10²³ grid units. The error - // terms above confine the accumulator to a band of width 5¹⁸⋅(Δ + 31/10) ≈ 1.4⋅10¹³ grid - // units just below E's grid image at every octave (in grid units the band is k-independent; - // an octave seam rescales E and the band together), so the per-step gain exceeds any - // adverse swing within the band by more than 9 orders of magnitude, and the pre-floor - // accumulator strictly increases at every step; its floor is non-decreasing. The zeroing - // clamp and the +1 pin at x = 0 preserve order: below C the result is 0 while just above it - // ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket the pinned scale-point - // value. + // pre-floor accumulator by at least 10¹⁸⋅2⁶⁸⋅10⁻²⁷/√2 ≈ 2.1⋅10¹¹ grid units. The error + // terms above confine the accumulator to a band of width 5¹⁸⋅Δ/2⁴⁰ + 33/4 ≈ 10.3 + // grid units just below E's grid image at every octave (in grid units the band is + // k-independent; an octave seam rescales E and the band together), so the per-step gain + // exceeds any adverse swing within the band by more than 9 orders of magnitude, and the + // pre-floor accumulator strictly increases at every step; its floor is non-decreasing. The + // zeroing clamp and the +1 pin at x = 0 preserve order: below C the result is 0 while just + // above it ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket the pinned + // scale-point value. assembly ("memory-safe") { - // k = round(x / (10²⁷⋅ln(2))), half-open. CINV = round(2²⁰⁰ / (10²⁷⋅ln(2))); the +2¹⁹⁹ - // and `sar(200, …)` round to nearest with ties resolved toward +∞. - let k := sar(0xc8, add(shl(0xc7, 0x01), mul(0x724d54edbacbebbb95c52a0f6076, x))) + // k = round(x / (10²⁷⋅ln(2))), half-open. CINV = round(2¹⁹² / (10²⁷⋅ln(2))); the +2¹⁹¹ + // and `sar(192, …)` round to nearest with ties resolved toward +∞. + let k := sar(0xc0, add(shl(0xbf, 0x01), mul(0x724d54edbacbebbb95c52a0f60, x))) // t in Q128. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln(2) ⋅ 2²³⁵). Subtracting k ⋅ // LN2 from K27 ⋅ x at the Q235 product basis (so the k ⋅ ln(2) rounding error is @@ -151,15 +152,14 @@ library Exp { // both positive. let tod := sar(0x81, mul(t, od)) - // exp(t) in Q126: the dividend (numerator << 126) stays below 2²⁵⁵, the denominator > - // 0. - r := div(shl(0x7e, add(ev, tod)), sub(ev, tod)) + // 10¹⁸⋅exp(t) in Q68: the constant is 10¹⁸⋅2⁶⁸ = 5¹⁸⋅2⁸⁶, so one `DIV` scales, widens, + // and floors at once. The numerator stays below 2¹²⁸ and 10¹⁸⋅2⁶⁸ < 2¹²⁸, so the + // dividend stays inside 256 bits; the denominator > 0. + r := div(mul(0xde0b6b3a764000000000000000000000, add(ev, tod)), sub(ev, tod)) - // E on the 2¹⁰⁸ output grid (5¹⁸ = 10¹⁸/2¹⁸ multiplies the Q126 quotient), less the - // one-sided margin (0x2027afc6c05 = ⌊5¹⁸⋅Δ⌋ + 1; see the budget above), then floored by - // `shr(108 - k, …)` which folds in the 2ᵏ octave scaling and the wad unit's remaining - // 2¹⁸ (108 - k ∈ [44, 168]). - r := shr(sub(0x6c, k), sub(mul(0x3782dace9d9, r), 0x2027afc6c05)) + // Less the one-sided margin (0x03; see the budget above), then floored by + // `shr(68 - k, …)` which folds in the 2ᵏ octave scaling (68 - k ∈ [4, 128]). + r := shr(sub(0x44, k), sub(r, 0x03)) // Zero the result at and below C = ⌊-18⋅ln(10)⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index ccdc73f46..e38a6839f 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -57,12 +57,20 @@ contract ExpTest is Test { assertEq(Exp.expRayToWad(Ln.lnWadToRay(1e18 - 1)), 1e18 - 2); // w-1 } + /// The round trip at fuzzed points of the central octave: `w - 1` everywhere except the exact + /// scale point. + function testFuzzExpRayToWadRoundTripCentral(uint256 w) external pure { + w = bound(w, _W_LO, _W_HI); + int256 expected = w == 1e18 ? int256(w) : int256(w) - 1; + assertEq(Exp.expRayToWad(Ln.lnWadToRay(int256(w))), expected, "central round trip"); + } + /// First input of octave k: the least x with round(x / (10**27 * ln2)) == k, computed as - /// ceil((k*2**200 - 2**199) / CINV) with CINV = round(2**200 / (10**27 * ln2)), the same + /// ceil((k*2**192 - 2**191) / CINV) with CINV = round(2**192 / (10**27 * ln2)), the same /// reciprocal the kernel rounds with. function _octaveStart(int256 k) private pure returns (int256) { - int256 CINV = 0x724d54edbacbebbb95c52a0f6076; - int256 num = k * (int256(1) << 200) - (int256(1) << 199); + int256 CINV = 0x724d54edbacbebbb95c52a0f60; + int256 num = k * (int256(1) << 192) - (int256(1) << 191); return num >= 0 ? (num + CINV - 1) / CINV : num / CINV; } @@ -80,7 +88,7 @@ contract ExpTest is Test { /// High-k inputs whose exact result sits just below an integer: the tightest points for the /// never-overestimate guarantee, where the over-side envelope (rational approximation plus the - /// Horner/sdiv truncation jitter) the margin must cover is largest, scaling as 2ᵏ. + /// Horner truncation jitter) the margin must cover is largest, scaling as 2ᵏ. function testExpRayToWadNeverOverestimateHighK() external pure { int256[7] memory xs = [ int256(44014845965556527147989858478), @@ -130,8 +138,8 @@ contract ExpTest is Test { } /// The largest supported input, one below the revert threshold: frac(E) ~= 0.52 sits inside - /// the k = 64 deficit envelope (~0.80), so the result floors to E or one under. At the top of - /// k = 63, frac(E) ~= 0.74 exceeds that octave's envelope (~0.40) and the floor is exact. + /// the k = 64 deficit envelope (~0.70), so the result floors to E or one under. At the top of + /// k = 63, frac(E) ~= 0.74 exceeds that octave's envelope (~0.35) and the floor is exact. function testExpRayToWadSupportedEdge() external pure { int256 floorE = 26087635650665564424699143611138320962; int256 r = Exp.expRayToWad(_TOO_BIG - 1); From 66aea3af0bbef36a969cea483f3d55e905457be0 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 5 Jul 2026 10:52:46 +0200 Subject: [PATCH 145/149] Extend the supported exp range through the k = 65 octave One bit moves from the output grid into the closing polynomial bases: the numerator closes at Q89 (the even chain's closing constant is exactly twice the odd chain's, ending the shared literal), t is carried at Q129 in the freed t*Od headroom, the quotient pre-scale is 10^18*2^67 = 5^18*2^85, and the margin is the single grid unit 0x01. The revert threshold moves to the k = 66 boundary, 0x92b2f16cc66c5a4ae96e80d4 ~= 45.40e27 (E up to ~5.22e37). Runtime gas is identical; every documented property is unchanged in form. The rebalance was chosen by exact-rational measurement: the truncation deficit is owned by the odd-side closing sites, amplified antisymmetrically through the numerator and denominator, so the widened bases drop the true envelope 2.5x while the margin requantizes from 3/16 to 1/4 ulp at the edge octave. formal/README.md documents the procedure (measure the true envelope, attribute per truncation site, rebalance bases, certify piecewise) for future transcendental kernels, including the dead ends. The proof certifies the under deficit at 2993/1000 grid units (link-1 including the DIV floor <= 2378/1000 via a 32-piece kernel-checked certificate -- global worst-case aggregation provably cannot reach the target -- plus the reduced-argument gap at 307/1000 / 218/1000 per sign half, Mp <= 2/25, negative-half granularity <= 143/500), the over side under the one-unit margin with B-image ~0.99527, and the k = 65 deficit envelope at 3993/4000 ulp. The certificate domain doubles to H129 and all cover cells regenerate; the octave fold, seam, and round-trip chains carry the 2^67 grid. Full lake build is green from the Theorems.lean axiom gates. Tests: the supported-edge and underestimate witnesses re-mined for the new envelope, a k = 65 high-fraction never-over witness added, and the boundary-monotonicity loop extended through the k = 66 seam; 12/12 at 10k fuzz runs; forge fmt clean. Co-Authored-By: Claude Fable 5 --- formal/README.md | 49 ++ formal/exp/ExpProof/ExpProof/Floor/CapsV.lean | 40 +- .../ExpProof/ExpProof/Floor/CertDefsV.lean | 78 +-- formal/exp/ExpProof/ExpProof/Floor/Fold.lean | 14 +- .../exp/ExpProof/ExpProof/Floor/GranPair.lean | 120 ++-- .../ExpProof/ExpProof/Floor/GranPieces.lean | 66 +- formal/exp/ExpProof/ExpProof/Floor/GranV.lean | 306 +++++----- .../exp/ExpProof/ExpProof/Floor/R0Bound.lean | 34 +- .../ExpProof/ExpProof/Floor/R0BoundHolds.lean | 32 +- formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean | 547 ++++++++--------- .../ExpProof/ExpProof/Floor/R0ExpUnder.lean | 562 +++++++++++------- .../exp/ExpProof/ExpProof/Floor/Reduce.lean | 110 ++-- .../ExpProof/ExpProof/Floor/RoundTrip.lean | 72 +-- formal/exp/ExpProof/ExpProof/Floor/Spec.lean | 18 +- .../exp/ExpProof/ExpProof/Floor/TBound.lean | 30 +- formal/exp/ExpProof/ExpProof/Mono/Consts.lean | 24 +- formal/exp/ExpProof/ExpProof/Mono/Cross.lean | 106 ++-- .../exp/ExpProof/ExpProof/Mono/CrossCert.lean | 78 +-- .../exp/ExpProof/ExpProof/Mono/EvOdLip.lean | 14 +- formal/exp/ExpProof/ExpProof/Mono/Gaps.lean | 44 +- .../exp/ExpProof/ExpProof/Mono/Lipschitz.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Octave.lean | 22 +- formal/exp/ExpProof/ExpProof/Mono/Quot.lean | 125 ++-- .../ExpProof/ExpProof/Mono/RangeNonneg.lean | 70 +-- .../ExpProof/ExpProof/Mono/RegionMono.lean | 2 +- .../exp/ExpProof/ExpProof/Mono/RunBridge.lean | 4 +- formal/exp/ExpProof/ExpProof/Mono/Seam.lean | 16 +- formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean | 2 +- formal/exp/ExpProof/ExpProof/Mono/Stages.lean | 68 +-- .../exp/ExpProof/ExpProof/Mono/StepMono.lean | 18 +- formal/exp/ExpProof/ExpProof/Mono/Top.lean | 6 +- formal/exp/ExpProof/ExpProof/Mono/Tree.lean | 2 +- formal/exp/ExpProof/ExpProof/Seam/Guard.lean | 42 +- .../exp/ExpProof/ExpProof/Seam/Helpers.lean | 12 +- formal/exp/ExpProof/ExpProof/Seam/Revert.lean | 12 +- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 98 +-- formal/exp/ExpProof/ExpProof/Theorems.lean | 12 +- formal/exp/ExpProof/GenExpVLit.lean | 8 +- src/vendor/Exp.sol | 102 ++-- test/0.8.34/Exp.t.sol | 37 +- 40 files changed, 1576 insertions(+), 1428 deletions(-) diff --git a/formal/README.md b/formal/README.md index 94f76b95e..282d3f760 100644 --- a/formal/README.md +++ b/formal/README.md @@ -72,6 +72,55 @@ Every step is re-verified against the exact target at ≥60 digits on a dense gr the resulting envelope must clear the proof's cut-certificate nudge with slack before the margin constant is derived from the error budget. +## Widening the certified range: measure, attribute, rebalance + +The supported range of a fixed-point kernel ends at the octave where the deficit envelope +(the certified worst-case underestimation of the pre-floor accumulator, doubling per octave) +reaches one output ulp. When a target octave misses by a few tens of percent, the +coefficients are usually not the lever. The procedure that closes the gap, in order: + +1. **Measure the true envelope.** Run the integer kernel beside its exact-rational shadow + (the same Horner evaluation with every renormalizing floor replaced by exact rational + arithmetic) over adversarial sweeps — every octave seam ±2 plus large random samples — + and compare the supremum against the certified bound. This splits the certified envelope + into real error versus derivational padding. For `expRayToWad` the split is 5.18 true + against 6.21 certified (2⁶⁸-grid units): the bound is nearly tight, so no re-derivation + alone closes a 30% gap — and neither does a coefficient refit, because with ~2¹²¹ + reachable grid arguments, near-worst alignment of the per-stage floor residuals exists + for essentially any choice of coefficient low bits, and re-centering the residuals only + trades under-side deficit for over-side margin one-for-one against an integer-quantized + margin. + +2. **Attribute per truncation site.** Re-run the shadow with each floor exactified one at a + time. The deficit is rarely uniform: in `expRayToWad`, the odd chain's closing stage and + the `t·Od` shift own nearly the whole supremum (5.0 and 4.0 of the 5.18) because odd-side + errors enter the numerator and denominator antisymmetrically and are amplified by + ~2t/den, while the even chain contributes ≤ 1 unit per site and every early stage is + negligible — the staircase already carries more precision there than the closing stages + consume. + +3. **Rebalance bases toward the dominant sites.** The 256-bit fits (the dividend, `t·Od`, + `t²`, and the monic leading stage) form a closed budget of bits; move them from where the + attribution says they are cheap to where they are dear. For `expRayToWad`, one bit moves + from the output grid into the closing bases — numerator at Q89, scale 10¹⁸·2⁶⁷, `t` at + Q129 in the freed `t·Od` headroom — with every coefficient unchanged except the even + closing constant doubling exactly (preserving `Ev(0) = 2·Od(0)`). The true envelope drops + 2.5× and the margin requantizes from 3/16 to 1/4 ulp at the edge octave, at identical + runtime gas: this is what extends the supported range through k = 65. + +4. **Certify piecewise where global worst-cases refuse.** The residual derivational padding + lives in co-occurrence assumptions — the worst floor fraction, the largest |t|, and the + smallest denominator cannot coincide, but a domain-global bound must pretend they do. The + certificate machinery that already bounds the granularity piecewise (`Common.GenCover` + walks over the 32-piece `v` table) extends to the truncation envelope: add per-piece caps + for the amplification factors (|t|, the denominator floor, the even accumulator) and + aggregate the per-stage residuals with per-piece weights. + +The order matters: measurement before design (step 1 rules out the tempting-but-useless +refit), attribution before rebalancing (step 2 finds the bit that buys 2.5× rather than one +that buys nothing), and rebalancing before certification (step 4's piecewise machinery is +only worth building once the true envelope actually fits under the target). + ## Build Generated EVMYulLean artifacts (`*YulRuntime.lean`, `*YulProof.lean`) are `.gitignore`d and regenerated in CI. See `.github/workflows/*-formal.yml` for the canonical build steps. diff --git a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean index a1cf63c26..7fbb0ef99 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CapsV.lean @@ -12,7 +12,7 @@ import ExpProof.Cert.ExpVDenM1 # From cell certificates to the **v-form** reduced-argument Taylor caps The v-form cell covers (`Cert/ExpVUp`, `Cert/ExpVLo`, `Cert/ExpVNum`, `Cert/ExpVDenM1`) certify the -four v-form certificate polynomials nonnegative over `t ∈ [0, H128]`. This module converts that +four v-form certificate polynomials nonnegative over `t ∈ [0, H129]`. This module converts that nonnegativity into the two bare-argument Taylor caps the floor layer folds with `2^k`, targeting the implementation's exact **v-form** rational `ê_v(t) = NUM(t)/DEN(t)` (built from the even/odd Horner polynomials in `v = t²`) nudged by the dyadic margin, with `Qexp = 2^128`: @@ -103,7 +103,7 @@ theorem evalCertExpLo (t : Int) : /-! ## Positivity of the rational over the domain -/ /-- `1 ≤ DEN(t)` over the domain. -/ -theorem denExpV_ge_one {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : +theorem denExpV_ge_one {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H129 : Int)) : 1 ≤ evalPoly denExpV t := by have h := denM1V_nonneg h1 h2 unfold certDenM1 at h @@ -112,18 +112,18 @@ theorem denExpV_ge_one {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : omega /-- `0 ≤ NUM(t)` over the domain. -/ -theorem numExpV_nonneg' {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : +theorem numExpV_nonneg' {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H129 : Int)) : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 /-! ## The bare-argument Taylor caps -/ -theorem Qexp_eq : (Qexp : Int) = 2 ^ 128 := by unfold Qexp; norm_num +theorem Qexp_eq : (Qexp : Int) = 2 ^ 129 := by unfold Qexp; norm_num theorem Qexp_pos : 0 < Qexp := by unfold Qexp; norm_num /-- **Never-over cap** at the v-form rational `yUB/wUB = ê_v·(1 + 2⁻¹³²)`: for every reduced argument -`t ∈ [0, H128]`, `exp(t/Qexp) ≤ yUB(t)/wUB(t)`. -/ -theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : +`t ∈ [0, H129]`, `exp(t/Qexp) ≤ yUB(t)/wUB(t)`. -/ +theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H129 : Int)) : capUB t.toNat Qexp (evalPoly yUB t).toNat (evalPoly wUB t).toNat := by have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 @@ -138,26 +138,26 @@ theorem capExpUp {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : have hyn : ((evalPoly yUB t).toNat : Int) = evalPoly yUB t := Int.toNat_of_nonneg hyub have hwn : ((evalPoly wUB t).toNat : Int) = evalPoly wUB t := Int.toNat_of_nonneg hwub refine capUB27_of_int Qexp_pos ?_ ?_ - · have htle : t.toNat ≤ H128 := by - have : (t.toNat : Int) ≤ (H128 : Int) := by rw [htn]; exact h2 + · have htle : t.toNat ≤ H129 := by + have : (t.toNat : Int) ≤ (H129 : Int) := by rw [htn]; exact h2 exact_mod_cast this - have hHQ : 2 * H128 < 29 * Qexp := by unfold H128 Qexp; norm_num + have hHQ : 2 * H129 < 29 * Qexp := by unfold H129 Qexp; norm_num omega · rw [htn, hyn, hwn, Qexp_eq] have h := expVUp_nonneg h1 h2 rw [evalCertExpUp] at h unfold fact28Q28 at h rw [Qexp_eq] at h - have key : (28 * (2 : Int) ^ 128 * expNumI 27 t (2 ^ 128) + 2 * t ^ 28) * evalPoly wUB t ≤ - 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := by omega - calc (expNumI 27 t (2 ^ 128) * (28 * (2 : Int) ^ 128) + 2 * t ^ 28) * evalPoly wUB t - = (28 * (2 : Int) ^ 128 * expNumI 27 t (2 ^ 128) + 2 * t ^ 28) * evalPoly wUB t := by ring - _ ≤ 304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28 * evalPoly yUB t := key - _ = evalPoly yUB t * (304888344611713860501504000000 * ((2 : Int) ^ 128) ^ 28) := by ring + have key : (28 * (2 : Int) ^ 129 * expNumI 27 t (2 ^ 129) + 2 * t ^ 28) * evalPoly wUB t ≤ + 304888344611713860501504000000 * ((2 : Int) ^ 129) ^ 28 * evalPoly yUB t := by omega + calc (expNumI 27 t (2 ^ 129) * (28 * (2 : Int) ^ 129) + 2 * t ^ 28) * evalPoly wUB t + = (28 * (2 : Int) ^ 129 * expNumI 27 t (2 ^ 129) + 2 * t ^ 28) * evalPoly wUB t := by ring + _ ≤ 304888344611713860501504000000 * ((2 : Int) ^ 129) ^ 28 * evalPoly yUB t := key + _ = evalPoly yUB t * (304888344611713860501504000000 * ((2 : Int) ^ 129) ^ 28) := by ring /-- **Not-two-below cap** at the v-form rational `yLB/wLB = ê_v·(1 − 2⁻¹³²)`: for every reduced -argument `t ∈ [0, H128]`, `yLB(t)/wLB(t) ≤ exp(t/Qexp)`. -/ -theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : +argument `t ∈ [0, H129]`, `yLB(t)/wLB(t) ≤ exp(t/Qexp)`. -/ +theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H129 : Int)) : capLB t.toNat Qexp (evalPoly yLB t).toNat (evalPoly wLB t).toNat := by have hnum : 0 ≤ evalPoly numExpV t := numExpV_nonneg h1 h2 have hden : 1 ≤ evalPoly denExpV t := denExpV_ge_one h1 h2 @@ -177,9 +177,9 @@ theorem capExpLo {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (H128 : Int)) : rw [evalCertExpLo] at h unfold fact27Q27 at h rw [Qexp_eq] at h - calc evalPoly yLB t * (10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27) - = 10888869450418352160768000000 * ((2 : Int) ^ 128) ^ 27 * evalPoly yLB t := by ring - _ ≤ expNumI 27 t (2 ^ 128) * evalPoly wLB t := by omega + calc evalPoly yLB t * (10888869450418352160768000000 * ((2 : Int) ^ 129) ^ 27) + = 10888869450418352160768000000 * ((2 : Int) ^ 129) ^ 27 * evalPoly yLB t := by ring + _ ≤ expNumI 27 t (2 ^ 129) * evalPoly wLB t := by omega /-- info: 'ExpCertV.capExpUp' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in diff --git a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean index 6a98d5b48..a5b595e85 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/CertDefsV.lean @@ -3,10 +3,10 @@ import Common.Foundation.ShiftCert /-! # The v-form reduced-argument rational target and its cut / denominator-floor certificates -The runtime forms `r0 = ⌊ê_v(t)·2^126⌋` with the **v-form** rational +The runtime forms `r0 = ⌊scaleQ67·ê_v(t)⌋` with the **v-form** rational ``` -ê_v(t) = (evNumV(v) · 2^110 + t · odNumV(v)) / (evNumV(v) · 2^110 − t · odNumV(v)), v = t²/2^133, +ê_v(t) = (evNumV(v) · 2^111 + t · odNumV(v)) / (evNumV(v) · 2^111 − t · odNumV(v)), v = t²/2^135, ``` built from the exact integer even/odd Horner polynomials `evNumV`/`odNumV` (defined in @@ -17,8 +17,8 @@ polynomials (different shift-clearing), so this module re-derives the cut agains Here `v = t²` is carried symbolically (each Horner stage multiplies by `t²` via `mulT2`, with the runtime per-stage shift cleared into the per-stage scale): `evNumVPoly` accumulates `Ev` to the -cleared scale `2^1192` and `odNumVPoly` accumulates `Od` to `2^1040`; `t·Od` (lifted by `2^23`) joins -`Ev` at the common `2^1192`. The shared scale cancels in `ê_v = NUM/DEN`. As a polynomial in `t` the +cleared scale `2^1201` and `odNumVPoly` accumulates `Od` to `2^1048`; `t·Od` (lifted by `2^24`) joins +`Ev` at the common `2^1201`. The shared scale cancels in `ê_v = NUM/DEN`. As a polynomial in `t` the numerator/denominator are degree 10. Two certificate shapes are declared: @@ -27,8 +27,8 @@ Two certificate shapes are declared: nudging the rational by a dyadic margin (`yUB/wUB = ê_v·(1 + 2⁻¹³²)`, `yLB/wLB = ê_v·(1 − 2⁻¹³²)`); the realized envelope `2¹²⁶·|ê_v − exp(t/2¹²⁸)| ≤ 0.0075` ulp is inside those margins with 2.1× slack; * the **denominator floors** over the integer `v`-grid: the parameterized shapes - `certDOverP`/`certDUnderP` pin `Ev(v)·2^110 ∓ T·Od(v)` above explicit constants, instantiated - once globally (`certDOver`, at the domain edge `T = H128` over all of `[0, vmaxV + 1]`) and once + `certDOverP`/`certDUnderP` pin `Ev(v)·2^111 ∓ T·Od(v)` above explicit constants, instantiated + once globally (`certDOver`, at the domain edge `T = H129` over all of `[0, vmaxV + 1]`) and once per granularity piece (32 pieces, each with its own `t`-cap `T` and floor constant over its `v`-range); the argument-granularity link divides one `v`-grid step of `ê_v` by the piece floors. -/ @@ -40,47 +40,47 @@ open Common.Poly /-! ## The reduced-argument denominator and the cert domain -/ /-- The reduced-argument denominator `tDen = 2^128`: the runtime carries `t` in Q128. -/ -def Qexp : Nat := 2 ^ 128 +def Qexp : Nat := 2 ^ 129 -/-- The cert variable upper bound `H128 = ⌊ln2/2 · 2^128⌋`. -/ -def H128 : Nat := 117932881612756647068972071382077242199 +/-- The cert variable upper bound `H129 = ⌊ln2/2 · 2^128⌋`. -/ +def H129 : Nat := 235865763225513294137944142764154484399 /-! ## Exact integer `ê_v(t) = NUM(t)/DEN(t)` from the implementation coefficients -The even/odd Horner accumulators evaluated as exact polynomials in `t` with `v = t²/2^133`, each +The even/odd Horner accumulators evaluated as exact polynomials in `t` with `v = t²/2^135`, each runtime per-stage shift cleared into the stage scale. `evNumVPoly` is `evNumV(t²)` cleared so its -evaluation is `Ev·2^1192` (`= evNumV(v)·2^665` at grid points `t² = 2^133·v`); `odNumVPoly` -evaluates to `Od·2^1040` (`= odNumV(v)·2^532` at grid points); `t·Od` (lifted by `2^23` to the -common `2^1192`) joins `Ev`. The shared `2^1192` cancels in `ê_v = NUM/DEN`. -/ +evaluation is `Ev·2^1201` (`= evNumV(v)·2^675` at grid points `t² = 2^135·v`); `odNumVPoly` +evaluates to `Od·2^1048` (`= odNumV(v)·2^540` at grid points); `t·Od` (lifted by `2^24` to the +common `2^1201`) joins `Ev`. The shared `2^1201` cancels in `ê_v = NUM/DEN`. -/ /-- `t²·P` at the polynomial level (one Horner `·v` stage, with the runtime per-stage shift cleared into the per-stage constant scale). -/ def mulT2 (P : List Int) : List Int := 0 :: 0 :: P -/-- The even Horner accumulator `Ev` (evaluation `Ev·2^1192`; `evNumV(v)·2^665` at grid points). +/-- The even Horner accumulator `Ev` (evaluation `Ev·2^1201`; `evNumV(v)·2^675` at grid points). The per-stage constants are the even coefficients `A0..A4` lifted by the cleared stage scale; the innermost monic `v` stage clears to `[A4·2^133, 0, 1]` (A4 is carried at v's own Q123 basis). -/ def evNumVPoly : List Int := - polyAdd [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192] - (mulT2 (polyAdd [0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933] - (mulT2 (polyAdd [0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671] - (mulT2 (polyAdd [0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415] - (mulT2 [0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133, 0, 1]))))))) + polyAdd [0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201] + (mulT2 (polyAdd [0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941] + (mulT2 (polyAdd [0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677] + (mulT2 (polyAdd [0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419] + (mulT2 [0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135, 0, 1]))))))) -/-- The odd Horner accumulator `Od` (evaluation `Od·2^1040`; `odNumV(v)·2^532` at grid points). -/ +/-- The odd Horner accumulator `Od` (evaluation `Od·2^1048`; `odNumV(v)·2^540` at grid points). -/ def odNumVPoly : List Int := - polyAdd [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040] - (mulT2 (polyAdd [0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779] - (mulT2 (polyAdd [0xad4506af99be27419341e181693281 * 2 ^ 524] - (mulT2 [0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259, 0, 0xdc07aff8276bde9a361278df6a10]))))) + polyAdd [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048] + (mulT2 (polyAdd [0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785] + (mulT2 (polyAdd [0xad4506af99be27419341e181693281 * 2 ^ 528] + (mulT2 [0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261, 0, 0xdc07aff8276bde9a361278df6a10]))))) -/-- `t·Od` lifted to the common scale `2^1192` (`= 2^23 · t · odNumVPoly`). -/ -def todNumV : List Int := polyScale (2 ^ 23) (0 :: odNumVPoly) +/-- `t·Od` lifted to the common scale `2^1201` (`= 2^24 · t · odNumVPoly`). -/ +def todNumV : List Int := polyScale (2 ^ 24) (0 :: odNumVPoly) -/-- `ê_v`-numerator `NUM(t) = Ev(t) + t·Od(t)` (scale `2^1192`). -/ +/-- `ê_v`-numerator `NUM(t) = Ev(t) + t·Od(t)` (scale `2^1201`). -/ def numExpV : List Int := polyAdd evNumVPoly todNumV -/-- `ê_v`-denominator `DEN(t) = Ev(t) − t·Od(t)` (scale `2^1192`). -/ +/-- `ê_v`-denominator `DEN(t) = Ev(t) − t·Od(t)` (scale `2^1201`). -/ def denExpV : List Int := polySub evNumVPoly todNumV /-! ## Taylor partial-sum numerator at the cut argument -/ @@ -122,17 +122,17 @@ def certDenM1 : List Int := polyAdd denExpV [-1] The argument-granularity link works on the integer `v`-grid: with `Ev(v)`/`Od(v)` the exact integer Horner polynomials (cleared scales `2^528`/`2^510`; `Floor/R0Bound.lean`), the aligned rational is -`ê_v = (Ev·2^110 + t·Od) / (Ev·2^110 − t·Od)` and one grid step of it is bounded by dividing the +`ê_v = (Ev·2^111 + t·Od) / (Ev·2^111 − t·Od)` and one grid step of it is bounded by dividing the `K`-identity numerator by the two floors below. The grid never leaves `[0, vmaxV + 1]` -(`v = ⌊t²/2^133⌋ ≤ vmaxV` for `|t| ≤ H128`, and the step looks one cell ahead). -/ +(`v = ⌊t²/2^135⌋ ≤ vmaxV` for `|t| ≤ H129`, and the step looks one cell ahead). -/ -/-- The top of the `v`-grid: `vmaxV = ⌊H128²/2^133⌋`. -/ +/-- The top of the `v`-grid: `vmaxV = ⌊H129²/2^133⌋`. -/ def vmaxV : Nat := 1277263193518626341050532535110179582 /-- The even integer Horner polynomial `Ev` in `v` (degree 5, monic, cleared scale `2^528`): coefficient list of `evNumV` (`Floor/R0Bound.lean`). -/ def evVPoly : List Int := - [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 527, + [0x1385291795942d41ba5fd317688e18710 * 2 ^ 526, 0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 401, 0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 272, 0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 149, @@ -147,20 +147,20 @@ def odVPoly : List Int := 0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 126, 0xdc07aff8276bde9a361278df6a10] -/-- Over-half denominator floor shape: `Ev(v)·2^110 − T·Od(v) − D·2^725 ≥ 0`. Nonnegativity over a +/-- Over-half denominator floor shape: `Ev(v)·2^111 − T·Od(v) − D·2^725 ≥ 0`. Nonnegativity over a `v`-range gives `DEN(v, t) ≥ D·2^725` there for every `0 ≤ t ≤ T` (the floor constant is `2^725` times a real-scale minimum). -/ def certDOverP (T D : Int) : List Int := - polyAdd (polySub (polyScale (2 ^ 110) evVPoly) (polyScale T odVPoly)) [-(D * 2 ^ 725)] + polyAdd (polySub (polyScale (2 ^ 111) evVPoly) (polyScale T odVPoly)) [-(D * 2 ^ 725)] -/-- Under-half (`t = −T`) denominator floor shape: `Ev(v)·2^110 + T·Od(v) − D·2^725 ≥ 0`. The +/-- Under-half (`t = −T`) denominator floor shape: `Ev(v)·2^111 + T·Od(v) − D·2^725 ≥ 0`. The granularity lift is monotone in `|t|`, so the single cap evaluation floors a whole piece's negative half. -/ def certDUnderP (T D : Int) : List Int := - polyAdd (polyAdd (polyScale (2 ^ 110) evVPoly) (polyScale T odVPoly)) [-(D * 2 ^ 725)] + polyAdd (polyAdd (polyScale (2 ^ 111) evVPoly) (polyScale T odVPoly)) [-(D * 2 ^ 725)] -/-- The global over-half floor at the domain edge: `DEN(v, t) ≥ 554482771859·2^725` on all of -`[0, vmaxV + 1]` for every `0 ≤ t ≤ H128` (real-scale minimum `≈ 5.5448·10¹¹`, attained interior). -/ -def certDOver : List Int := certDOverP (H128 : Int) 554482771859 +/-- The global over-half floor at the domain edge: `DEN(v, t) ≥ 1108965543718·2^725` on all of +`[0, vmaxV + 1]` for every `0 ≤ t ≤ H129` (real-scale minimum `≈ 1.1090·10¹²`, attained interior). -/ +def certDOver : List Int := certDOverP (H129 : Int) 1108965543718 end ExpCertV diff --git a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean index 123425914..2380f96ed 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Fold.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Fold.lean @@ -3,12 +3,12 @@ import ExpProof.Floor.Spec /-! # The runtime accumulator in closed real form -The real pre-floor accumulator is `accumReal x = (r0 − MARGIN) / 2^(68 − k)` on the `2⁶⁸` output -grid (the quotient carries the `10¹⁸·2⁶⁸` scale directly). This file peels the runtime +The real pre-floor accumulator is `accumReal x = (r0 − MARGIN) / 2^(67 − k)` on the `2⁶⁷` output +grid (the quotient carries the `10¹⁸·2⁶⁷` scale directly). This file peels the runtime plumbing off it: using the proven shift-argument transport (`shiftArg_bounds_of`: `int256 (r0 − MARGIN) = int256 r0 − MARGIN` as `Int`) and the closing-shift value -(`closing_shift`: the shift word is `68 − int256 k`, nonnegative), the accumulator takes the -closed form `((int256 r0) − MARGIN) / 2^s` with `s = 68 − int256 (kTree x)`, the form the +(`closing_shift`: the shift word is `67 − int256 k`, nonnegative), the accumulator takes the +closed form `((int256 r0) − MARGIN) / 2^s` with `s = 67 − int256 (kTree x)`, the form the never-over and deficit discharges (`Floor.R0BoundHolds`) fold the octave against. -/ @@ -25,12 +25,12 @@ set_option maxRecDepth 100000 /-! ## The shift-argument value and the closing shift, as real quantities -/ /-- On the region, the numeric shift argument `r0 − MARGIN` (transported to `Int` and then to -`Real`) is `(int256 r0) − 3`, and it is nonnegative. -/ +`Real`) is `(int256 r0) − 1`, and it is nonnegative. -/ theorem accumReal_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - ∃ s : Nat, (s : Int) = 68 - int256 (kTree x) ∧ + ∃ s : Nat, (s : Int) = 67 - int256 (kTree x) ∧ accumReal x = - ((int256 (r0Tree x) : Real) - (3 : Real)) / + ((int256 (r0Tree x) : Real) - (1 : Real)) / (2 ^ s : Real) := by obtain ⟨s, hseq, _, _, hsint⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean b/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean index 57905fc8b..a9d0dc6f8 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/GranPair.lean @@ -46,9 +46,9 @@ theorem gran_over_pair {x : Nat} (hx : x < 2 ^ 256) obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] + have htdom : t ≤ (ExpCertV.H129 : Int) := by + rw [show ((ExpCertV.H129 : Nat) : Int) = 235865763225513294137944142764154484399 from by + unfold ExpCertV.H129; norm_num] exact hthi -- the piece cap dominates on this half: t ≤ T have htT : t ≤ T := by @@ -85,15 +85,15 @@ theorem gran_over_pair {x : Nat} (hx : x < 2 ^ 256) exact_mod_cast htie2 have hstep_eq : (NUMv v t : Real) / (DENv v t : Real) - (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) = - ((2 * t * 2 ^ 110 * KpM v : Int) : Real) / + ((2 * t * 2 ^ 111 * KpM v : Int) : Real) / ((DENv v t : Real) * (DENv (v + 1) t : Real)) := by rw [div_sub_div _ _ (ne_of_gt hDR) (ne_of_gt hD1R)] congr 1 have hid := step_identity v t have hcast : ((NUMv v t : Int) : Real) * ((DENv (v + 1) t : Int) : Real) - ((DENv v t : Int) : Real) * ((NUMv (v + 1) t : Int) : Real) = - ((2 * t * 2 ^ 110 * KpM v : Int) : Real) := by - rw [show ((2 * t * 2 ^ 110 * KpM v : Int) : Real) = + ((2 * t * 2 ^ 111 * KpM v : Int) : Real) := by + rw [show ((2 * t * 2 ^ 111 * KpM v : Int) : Real) = ((NUMv v t * DENv (v + 1) t - NUMv (v + 1) t * DENv v t : Int) : Real) from by exact_mod_cast (congrArg (fun z : Int => (z : Real)) hid.symm)] push_cast @@ -101,13 +101,13 @@ theorem gran_over_pair {x : Nat} (hx : x < 2 ^ 256) exact hcast -- numerator and denominator bounds for the K-step have hKnn := KpM_nonneg v - have hnum_le : 2 * t * 2 ^ 110 * KpM v ≤ 2 * T * 2 ^ 110 * Khi := by - have h1 : 2 * t * 2 ^ 110 * KpM v ≤ 2 * T * 2 ^ 110 * KpM v := by - have hcoef : 2 * t * 2 ^ 110 ≤ 2 * T * 2 ^ 110 := by nlinarith [htT] + have hnum_le : 2 * t * 2 ^ 111 * KpM v ≤ 2 * T * 2 ^ 111 * Khi := by + have h1 : 2 * t * 2 ^ 111 * KpM v ≤ 2 * T * 2 ^ 111 * KpM v := by + have hcoef : 2 * t * 2 ^ 111 ≤ 2 * T * 2 ^ 111 := by nlinarith [htT] exact mul_le_mul_of_nonneg_right hcoef hKnn - have hTc : (0:Int) ≤ 2 * T * 2 ^ 110 := + have hTc : (0:Int) ≤ 2 * T * 2 ^ 111 := mul_nonneg (mul_nonneg (by norm_num) hTnn) (by norm_num) - have h2 : 2 * T * 2 ^ 110 * KpM v ≤ 2 * T * 2 ^ 110 * Khi := + have h2 : 2 * T * 2 ^ 111 * KpM v ≤ 2 * T * 2 ^ 111 * Khi := mul_le_mul_of_nonneg_left hK hTc linarith [h1, h2] have hden_ge : ((DO * 2 ^ 725 : Int) : Real) * ((DO * 2 ^ 725 : Int) : Real) ≤ @@ -118,18 +118,18 @@ theorem gran_over_pair {x : Nat} (hx : x < 2 ^ 256) exact_mod_cast le_of_lt hDO725 exact mul_le_mul hDRc hD1Rc hDOR (le_of_lt hDR) -- the K-step fraction is inside the piece budget - have hfrac : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) / + have hfrac : ((2 * t * 2 ^ 111 * KpM v : Int) : Real) / ((DENv v t : Real) * (DENv (v + 1) t : Real)) ≤ 3290521163436398582 / 10000000000000000000 / 2 ^ 126 := by have hdd : (0:Real) < (DENv v t : Real) * (DENv (v + 1) t : Real) := mul_pos hDR hD1R rw [div_le_div_iff₀ hdd (by positivity : (0:Real) < (2:Real) ^ 126)] - have hnumR : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) ≤ - ((2 * T * 2 ^ 110 * Khi : Int) : Real) := by + have hnumR : ((2 * t * 2 ^ 111 * KpM v : Int) : Real) ≤ + ((2 * T * 2 ^ 111 * Khi : Int) : Real) := by exact_mod_cast hnum_le - have h1 : ((2 * t * 2 ^ 110 * KpM v : Int) : Real) * 2 ^ 126 ≤ - ((2 * T * 2 ^ 110 * Khi : Int) : Real) * 2 ^ 126 := + have h1 : ((2 * t * 2 ^ 111 * KpM v : Int) : Real) * 2 ^ 126 ≤ + ((2 * T * 2 ^ 111 * Khi : Int) : Real) * 2 ^ 126 := mul_le_mul_of_nonneg_right hnumR (by positivity) - have h2 : ((2 * T * 2 ^ 110 * Khi : Int) : Real) * 2 ^ 126 ≤ + have h2 : ((2 * T * 2 ^ 111 * Khi : Int) : Real) * 2 ^ 126 ≤ (3290521163436398582 / 10000000000000000000 : Real) * (((DO * 2 ^ 725 : Int) : Real) * ((DO * 2 ^ 725 : Int) : Real)) := by rw [div_mul_eq_mul_div, le_div_iff₀ (by norm_num : (0:Real) < 10000000000000000000)] @@ -175,13 +175,13 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have htdom : -t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] + have htdom : -t ≤ (ExpCertV.H129 : Int) := by + rw [show ((ExpCertV.H129 : Nat) : Int) = 235865763225513294137944142764154484399 from by + unfold ExpCertV.H129; norm_num] linarith [htlo] -- denominators (positivity via the global over floor on the nonpositive half) - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htnp - have hD1 : 554482771859 * 2 ^ 725 ≤ DENv (v + 1) t := DENv_ge_neg (by omega) htnp + have hD : 1108965543718 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htnp + have hD1 : 1108965543718 * 2 ^ 725 ≤ DENv (v + 1) t := DENv_ge_neg (by omega) htnp have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hD1pos : (0:Int) < DENv (v + 1) t := lt_of_lt_of_le (by positivity) hD1 have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htnp htdom).2 @@ -201,14 +201,14 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) exact_mod_cast htie2 have hstep_eq : (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) - (NUMv v t : Real) / (DENv v t : Real) = - ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) / + ((2 * (-t) * 2 ^ 111 * KpM v : Int) : Real) / ((DENv (v + 1) t : Real) * (DENv v t : Real)) := by rw [div_sub_div _ _ (ne_of_gt hD1R) (ne_of_gt hDR)] congr 1 have hid := step_identity v t have hswap : NUMv (v + 1) t * DENv v t - DENv (v + 1) t * NUMv v t = - 2 * (-t) * 2 ^ 110 * KpM v := by linear_combination -hid - rw [show ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) = + 2 * (-t) * 2 ^ 111 * KpM v := by linear_combination -hid + rw [show ((2 * (-t) * 2 ^ 111 * KpM v : Int) : Real) = ((NUMv (v + 1) t * DENv v t - DENv (v + 1) t * NUMv v t : Int) : Real) from by exact_mod_cast (congrArg (fun z : Int => (z : Real)) hswap.symm)] push_cast @@ -221,9 +221,9 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) push_neg at hgt have hu2 : u ^ 2 = t ^ 2 := by rw [hudef]; ring nlinarith [hT2, hu0, hTnn, hgt, hu2] - set A : Int := (evNumV v : Int) * 2 ^ 110 with hAdef + set A : Int := (evNumV v : Int) * 2 ^ 111 with hAdef set Bo : Int := (odNumV v : Int) with hBodef - set A1 : Int := (evNumV (v + 1) : Int) * 2 ^ 110 with hA1def + set A1 : Int := (evNumV (v + 1) : Int) * 2 ^ 111 with hA1def set Bo1 : Int := (odNumV (v + 1) : Int) with hBo1def have hBo_nn : (0:Int) ≤ Bo := Int.natCast_nonneg _ have hBo1_nn : (0:Int) ≤ Bo1 := Int.natCast_nonneg _ @@ -261,9 +261,9 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) have hDH1pos : (0:Int) < A1 + T * Bo1 := lt_of_lt_of_le hDU725 hDH1 have hKnn := KpM_nonneg v -- the fraction chain: u-step ≤ T-step ≤ piece maximum - have hfracu : ((2 * u * 2 ^ 110 * KpM v : Int) : Real) / + have hfracu : ((2 * u * 2 ^ 111 * KpM v : Int) : Real) / ((DENv (v + 1) t : Real) * (DENv v t : Real)) ≤ - ((2 * T * 2 ^ 110 * KpM v : Int) : Real) / + ((2 * T * 2 ^ 111 * KpM v : Int) : Real) / (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) := by have hdd : (0:Real) < (DENv (v + 1) t : Real) * (DENv v t : Real) := mul_pos hD1R hDR have hdH : (0:Real) < ((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real) := by @@ -272,9 +272,9 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) exact mul_pos h1 h2 rw [div_le_div_iff₀ hdd hdH] -- cross-multiplied: (2u·2^110·Kp)·(D1(T)·D(T)) ≤ (2T·2^110·Kp)·(D1(u)·D(u)) - have hint : (2 * u * 2 ^ 110 * KpM v) * ((A1 + T * Bo1) * (A + T * Bo)) ≤ - (2 * T * 2 ^ 110 * KpM v) * ((A1 + u * Bo1) * (A + u * Bo)) := by - have hc : (0:Int) ≤ 2 * 2 ^ 110 * KpM v := + have hint : (2 * u * 2 ^ 111 * KpM v) * ((A1 + T * Bo1) * (A + T * Bo)) ≤ + (2 * T * 2 ^ 111 * KpM v) * ((A1 + u * Bo1) * (A + u * Bo)) := by + have hc : (0:Int) ≤ 2 * 2 ^ 111 * KpM v := mul_nonneg (by norm_num) hKnn have hscaled := mul_le_mul_of_nonneg_left hmono hc linarith only [hscaled] @@ -282,18 +282,18 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) (((A1 + u * Bo1) * (A + u * Bo) : Int) : Real) := by rw [hDu, hDu1]; push_cast; ring rw [hrw] - calc ((2 * u * 2 ^ 110 * KpM v : Int) : Real) * + calc ((2 * u * 2 ^ 111 * KpM v : Int) : Real) * (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) - = (((2 * u * 2 ^ 110 * KpM v) * + = (((2 * u * 2 ^ 111 * KpM v) * ((A1 + T * Bo1) * (A + T * Bo)) : Int) : Real) := by push_cast; ring - _ ≤ (((2 * T * 2 ^ 110 * KpM v) * ((A1 + u * Bo1) * (A + u * Bo)) : Int) : Real) := by + _ ≤ (((2 * T * 2 ^ 111 * KpM v) * ((A1 + u * Bo1) * (A + u * Bo)) : Int) : Real) := by exact_mod_cast hint - _ = ((2 * T * 2 ^ 110 * KpM v : Int) : Real) * + _ = ((2 * T * 2 ^ 111 * KpM v : Int) : Real) * (((A1 + u * Bo1) * (A + u * Bo) : Int) : Real) := by push_cast; ring - have hfracH : ((2 * T * 2 ^ 110 * KpM v : Int) : Real) / + have hfracH : ((2 * T * 2 ^ 111 * KpM v : Int) : Real) / (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) ≤ - ((2 * T * 2 ^ 110 * Khi : Int) : Real) / + ((2 * T * 2 ^ 111 * Khi : Int) : Real) / (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) := by have hdH : (0:Real) < ((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real) := by have h1 : (0:Real) < ((A1 + T * Bo1 : Int) : Real) := by exact_mod_cast hDH1pos @@ -301,15 +301,15 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) exact mul_pos h1 h2 have hDUR : (0:Real) < ((DU * 2 ^ 725 : Int) : Real) := by exact_mod_cast hDU725 rw [div_le_div_iff₀ hdH (by positivity)] - have hTc : (0:Int) ≤ 2 * T * 2 ^ 110 := + have hTc : (0:Int) ≤ 2 * T * 2 ^ 111 := mul_nonneg (mul_nonneg (by norm_num) hTnn) (by norm_num) - have hnum : ((2 * T * 2 ^ 110 * KpM v : Int) : Real) ≤ - ((2 * T * 2 ^ 110 * Khi : Int) : Real) := by - have : (2 * T * 2 ^ 110 * KpM v : Int) ≤ 2 * T * 2 ^ 110 * Khi := + have hnum : ((2 * T * 2 ^ 111 * KpM v : Int) : Real) ≤ + ((2 * T * 2 ^ 111 * Khi : Int) : Real) := by + have : (2 * T * 2 ^ 111 * KpM v : Int) ≤ 2 * T * 2 ^ 111 * Khi := mul_le_mul_of_nonneg_left hK hTc exact_mod_cast this - have hnum_nn : (0:Real) ≤ ((2 * T * 2 ^ 110 * KpM v : Int) : Real) := by - have : (0:Int) ≤ 2 * T * 2 ^ 110 * KpM v := mul_nonneg hTc hKnn + have hnum_nn : (0:Real) ≤ ((2 * T * 2 ^ 111 * KpM v : Int) : Real) := by + have : (0:Int) ≤ 2 * T * 2 ^ 111 * KpM v := mul_nonneg hTc hKnn exact_mod_cast this have hden : (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) ≤ ((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real) := by @@ -318,18 +318,18 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) have h2 : ((DU * 2 ^ 725 : Int) : Real) ≤ ((A + T * Bo : Int) : Real) := by exact_mod_cast hDH exact mul_le_mul h1 h2 (le_of_lt hDUR) (by exact_mod_cast le_of_lt hDH1pos) - calc ((2 * T * 2 ^ 110 * KpM v : Int) : Real) * + calc ((2 * T * 2 ^ 111 * KpM v : Int) : Real) * (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) - ≤ ((2 * T * 2 ^ 110 * Khi : Int) : Real) * + ≤ ((2 * T * 2 ^ 111 * Khi : Int) : Real) * (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) := mul_le_mul_of_nonneg_right hnum (by positivity) - _ ≤ ((2 * T * 2 ^ 110 * Khi : Int) : Real) * + _ ≤ ((2 * T * 2 ^ 111 * Khi : Int) : Real) * (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) := by apply mul_le_mul_of_nonneg_left hden exact le_trans hnum_nn hnum -- the piece budget, Mp-factor included have hbudget : (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) * - (((2 * T * 2 ^ 110 * Khi : Int) : Real) / + (((2 * T * 2 ^ 111 * Khi : Int) : Real) / (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real))) ≤ 1644901622230542074 / 10000000000000000000 := by have hMp1 : (0:Real) < (2 ^ 131 : Real) - 1 := by norm_num @@ -340,15 +340,15 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) (2 ^ 126 * 2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1) from by rw [mul_div_assoc], div_mul_div_comm] rw [div_le_div_iff₀ (mul_pos hMp1 hDD) (by norm_num : (0:Real) < 10000000000000000000)] - have hint : (2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 ≤ + have hint : (2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 111 * Khi) * 10000000000000000000 ≤ (1644901622230542074 : Int) * ((2 ^ 131 - 1) * ((DU * 2 ^ 725) * (DU * 2 ^ 725))) := by - calc (2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 - = 2 ^ 126 * 2 ^ 131 * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 := by ring + calc (2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 111 * Khi) * 10000000000000000000 + = 2 ^ 126 * 2 ^ 131 * (2 * T * 2 ^ 111 * Khi) * 10000000000000000000 := by ring _ ≤ _ := hbudU - calc (2 ^ 126 * 2 ^ 131 : Real) * ((2 * T * 2 ^ 110 * Khi : Int) : Real) * + calc (2 ^ 126 * 2 ^ 131 : Real) * ((2 * T * 2 ^ 111 * Khi : Int) : Real) * 10000000000000000000 - = (((2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 110 * Khi) * + = (((2 ^ 126 * 2 ^ 131 : Int) * (2 * T * 2 ^ 111 * Khi) * 10000000000000000000 : Int) : Real) := by push_cast; ring _ ≤ (((1644901622230542074 : Int) * ((2 ^ 131 - 1) * ((DU * 2 ^ 725) * (DU * 2 ^ 725))) : Int) : Real) := by @@ -360,21 +360,21 @@ theorem gran_under_pair {x : Nat} (hx : x < 2 ^ 256) -- assemble part 2 have hgap_le : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) - (NUMv v t : Real) / (DENv v t : Real) ≤ - ((2 * T * 2 ^ 110 * Khi : Int) : Real) / + ((2 * T * 2 ^ 111 * Khi : Int) : Real) / (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) := by - have hu_eq : ((2 * u * 2 ^ 110 * KpM v : Int) : Real) = - ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) := by rw [hudef] + have hu_eq : ((2 * u * 2 ^ 111 * KpM v : Int) : Real) = + ((2 * (-t) * 2 ^ 111 * KpM v : Int) : Real) := by rw [hudef] calc (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) - (NUMv v t : Real) / (DENv v t : Real) ≤ (NUMv (v + 1) t : Real) / (DENv (v + 1) t : Real) - (NUMv v t : Real) / (DENv v t : Real) := by linarith [hQw_le_Qv1] - _ = ((2 * (-t) * 2 ^ 110 * KpM v : Int) : Real) / + _ = ((2 * (-t) * 2 ^ 111 * KpM v : Int) : Real) / ((DENv (v + 1) t : Real) * (DENv v t : Real)) := hstep_eq - _ = ((2 * u * 2 ^ 110 * KpM v : Int) : Real) / + _ = ((2 * u * 2 ^ 111 * KpM v : Int) : Real) / ((DENv (v + 1) t : Real) * (DENv v t : Real)) := by rw [hu_eq] - _ ≤ ((2 * T * 2 ^ 110 * KpM v : Int) : Real) / + _ ≤ ((2 * T * 2 ^ 111 * KpM v : Int) : Real) / (((A1 + T * Bo1 : Int) : Real) * ((A + T * Bo : Int) : Real)) := hfracu - _ ≤ ((2 * T * 2 ^ 110 * Khi : Int) : Real) / + _ ≤ ((2 * T * 2 ^ 111 * Khi : Int) : Real) / (((DU * 2 ^ 725 : Int) : Real) * ((DU * 2 ^ 725 : Int) : Real)) := hfracH have hMpnn : (0:Real) ≤ (2 ^ 126 : Real) * ((2 ^ 131 : Real) / ((2 ^ 131 : Real) - 1)) := by have : (0:Real) < (2 ^ 131 : Real) - 1 := by norm_num diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranPieces.lean b/formal/exp/ExpProof/ExpProof/Floor/GranPieces.lean index ff6ad029c..8a984b4c8 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/GranPieces.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/GranPieces.lean @@ -10,40 +10,40 @@ consume identical constants by construction. namespace ExpCertV /-- The 32 granularity pieces `(vlo, vhi, T, DOver, DUnder)`: the `v`-range, the piece `t`-cap -(`T² ≥ (vhi+1)·2^133`), and the floored denominators for the two halves. Each piece's floors are +(`T² ≥ (vhi+1)·2^135`), and the floored denominators for the two halves. Each piece's floors are certified over `[vlo, vhi + 1]` (the granularity step looks one cell ahead). -/ def granPieces : List (Int × Int × Int × Int × Int) := [ - (0, 39914474797457073157829141722193111, 20847785078312632088902884100098393904, 650161701553, 691253358954), - (39914474797457073157829141722193111, 79828949594914146315658283444386223, 29483220403189161767243017845519310570, 641945658278, 700065691212), - (79828949594914146315658283444386223, 119743424392371219473487425166579335, 36109422980913784159270707268699614620, 635708060030, 706899646710), - (119743424392371219473487425166579335, 159657899189828292631316566888772447, 41695570156625264177805768200196787807, 630494171758, 712709960499), - (159657899189828292631316566888772447, 199572373987285365789145708610965559, 46617064615412821983671927489259435287, 625934238048, 717866387998), - (199572373987285365789145708610965559, 239486848784742438946974850333158671, 51066435709074987640046250875008841866, 621838651900, 722558536211), - (239486848784742438946974850333158671, 279401323582199512104803992055351783, 55158054703738454765934460694358669515, 618094793288, 726899025166), - (279401323582199512104803992055351783, 319315798379656585262633133777544895, 58966440806378323534486035691038621139, 614629293866, 730961223213), - (319315798379656585262633133777544895, 359230273177113658420462275499738007, 62543355234937896266708652300295181711, 611391198603, 734796085384), - (359230273177113658420462275499738007, 399144747974570731578291417221931119, 65926485017139723075679505829736200590, 608343412382, 738440706802), - (399144747974570731578291417221931119, 439059222772027804736120558944124231, 69144280814733066627417644920644591155, 605457935097, 741923087576), - (439059222772027804736120558944124231, 478973697569484877893949700666317343, 72218845961827568318541414537399229239, 602713016329, 745264978126), - (478973697569484877893949700666317343, 518888172366941951051778842388510455, 75167758079709234538337434275175078691, 600091361400, 748483673135), - (518888172366941951051778842388510455, 558802647164399024209607984110703567, 78005269036144011942405564982788931618, 597578949702, 751593193213), - (558802647164399024209607984110703567, 598717121961856097367437125832896679, 80743124413616312505576435261721815008, 595164227770, 754605091830), - (598717121961856097367437125832896679, 638631596759313170525266267555089791, 83391140313250528355611536400393575614, 592837541332, 757529023260), - (638631596759313170525266267555089791, 678546071556770243683095409277282902, 85957619938058733268340145980060814334, 590590725148, 760373152745), - (678546071556770243683095409277282902, 718460546354227316840924550999476014, 88449661209567485301729053536557931646, 588416800156, 763144459353), - (718460546354227316840924550999476014, 758375021151684389998753692721669126, 90873388353019950250431101958484117810, 586309745473, 765848963968), - (758375021151684389998753692721669126, 798289495949141463156582834443862238, 93234129230825643967343854978518870515, 584264323835, 768491903858), - (798289495949141463156582834443862238, 838203970746598536314411976166055350, 95536553193538501370371342040089081115, 582275945893, 771077868376), - (838203970746598536314411976166055350, 878118445544055609472241117888248462, 97784779688729301059274137358180034302, 580340563312, 773610905858), - (878118445544055609472241117888248462, 918032920341512682630070259610441574, 99982464869820254414073625773477941119, 578454583528, 776094608873), - (918032920341512682630070259610441574, 957947395138969755787899401332634686, 102132871418149975280092501750017683679, 576614801025, 778532182941), - (957947395138969755787899401332634686, 997861869936426828945728543054827798, 104238925391563160444514420500491969466, 574818341390, 780926502475), - (997861869936426828945728543054827798, 1037776344733883902103557684777020910, 106303262929504594869818257246985820007, 573062615355, 783280156749), - (1037776344733883902103557684777020910, 1077690819531340975261386826499214022, 108328268942741352477812121806098843808, 571345280717, 785595487968), - (1077690819531340975261386826499214022, 1117605294328798048419215968221407134, 110316109407476909531868921388717338981, 569664210570, 787874623042), - (1117605294328798048419215968221407134, 1157519769126255121577045109943600246, 112268758510433036404380164835338032221, 568017466591, 790119500297), - (1157519769126255121577045109943600246, 1197434243923712194734874251665793358, 114188021614114346553315397742450038434, 566403276447, 792331892069), - (1197434243923712194734874251665793358, 1237348718721169267892703393387986470, 116075554802968570681645777137735089747, 564820014566, 794513423933), - (1237348718721169267892703393387986470, 1277263193518626341050532535110179582, 117932881612756647068972071382077242231, 563266185678, 796665591163)] + (0, 39914474797457073157829141722193111, 41695570156625264177805768200196787808, 1300323403106, 1382506717908), + (39914474797457073157829141722193111, 79828949594914146315658283444386223, 58966440806378323534486035691038621140, 1283891316556, 1400131382424), + (79828949594914146315658283444386223, 119743424392371219473487425166579335, 72218845961827568318541414537399229240, 1271416120060, 1413799293420), + (119743424392371219473487425166579335, 159657899189828292631316566888772447, 83391140313250528355611536400393575614, 1260988343516, 1425419920998), + (159657899189828292631316566888772447, 199572373987285365789145708610965559, 93234129230825643967343854978518870574, 1251868476096, 1435732775996), + (199572373987285365789145708610965559, 239486848784742438946974850333158671, 102132871418149975280092501750017683732, 1243677303800, 1445117072422), + (239486848784742438946974850333158671, 279401323582199512104803992055351783, 110316109407476909531868921388717339030, 1236189586576, 1453798050332), + (279401323582199512104803992055351783, 319315798379656585262633133777544895, 117932881612756647068972071382077242278, 1229258587732, 1461922446426), + (319315798379656585262633133777544895, 359230273177113658420462275499738007, 125086710469875792533417304600590363422, 1222782397206, 1469592170768), + (359230273177113658420462275499738007, 399144747974570731578291417221931119, 131852970034279446151359011659472401180, 1216686824764, 1476881413604), + (399144747974570731578291417221931119, 439059222772027804736120558944124231, 138288561629466133254835289841289182310, 1210915870194, 1483846175152), + (439059222772027804736120558944124231, 478973697569484877893949700666317343, 144437691923655136637082829074798458478, 1205426032658, 1490529956252), + (478973697569484877893949700666317343, 518888172366941951051778842388510455, 150335516159418469076674868550350157382, 1200182722800, 1496967346270), + (518888172366941951051778842388510455, 558802647164399024209607984110703567, 156010538072288023884811129965577863236, 1195157899404, 1503186386426), + (558802647164399024209607984110703567, 598717121961856097367437125832896679, 161486248827232625011152870523443630016, 1190328455540, 1509210183660), + (598717121961856097367437125832896679, 638631596759313170525266267555089791, 166782280626501056711223072800787151228, 1185675082664, 1515058046520), + (638631596759313170525266267555089791, 678546071556770243683095409277282902, 171915239876117466536680291960121628668, 1181181450296, 1520746305490), + (678546071556770243683095409277282902, 718460546354227316840924550999476014, 176899322419134970603458107073115863292, 1176833600312, 1526288918706), + (718460546354227316840924550999476014, 758375021151684389998753692721669126, 181746776706039900500862203916968235620, 1172619490946, 1531697927936), + (758375021151684389998753692721669126, 798289495949141463156582834443862238, 186468258461651287934687709957037741030, 1168528647670, 1536983807716), + (798289495949141463156582834443862238, 838203970746598536314411976166055350, 191073106387077002740742684080178162230, 1164551891786, 1542155736752), + (838203970746598536314411976166055350, 878118445544055609472241117888248462, 195569559377458602118548274716360068604, 1160681126624, 1547221811716), + (878118445544055609472241117888248462, 918032920341512682630070259610441574, 199964929739640508828147251546955882238, 1156909167056, 1552189217746), + (918032920341512682630070259610441574, 957947395138969755787899401332634686, 204265742836299950560185003500035367358, 1153229602050, 1557064365882), + (957947395138969755787899401332634686, 997861869936426828945728543054827798, 208477850783126320889028841000983938932, 1149636682780, 1561853004950), + (997861869936426828945728543054827798, 1037776344733883902103557684777020910, 212606525859009189739636514493971640014, 1146125230710, 1566560313498), + (1037776344733883902103557684777020910, 1077690819531340975261386826499214022, 216656537885482704955624243612197687616, 1142690561434, 1571190975936), + (1077690819531340975261386826499214022, 1117605294328798048419215968221407134, 220632218814953819063737842777434677962, 1139328421140, 1575749246084), + (1117605294328798048419215968221407134, 1157519769126255121577045109943600246, 224537517020866072808760329670676064442, 1136034933182, 1580239000594), + (1157519769126255121577045109943600246, 1197434243923712194734874251665793358, 228376043228228693106630795484900076868, 1132806552894, 1584663784138), + (1197434243923712194734874251665793358, 1237348718721169267892703393387986470, 232151109605937141363291554275470179494, 1129640029132, 1589026847866), + (1237348718721169267892703393387986470, 1277263193518626341050532535110179582, 235865763225513294137944142764154484462, 1126532371356, 1593331182326)] end ExpCertV diff --git a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean index 04385335b..4846bde61 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/GranV.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/GranV.lean @@ -75,7 +75,7 @@ The runtime evaluates the even/odd polynomials at `v = ⌊t²/2^133⌋`, while t the aligned integer rational on the `v`-grid ``` -ê(v, t) = NUMv(v, t) / DENv(v, t), NUMv = Ev(v)·2^110 + t·Od(v), DENv = Ev(v)·2^110 − t·Od(v) +ê(v, t) = NUMv(v, t) / DENv(v, t), NUMv = Ev(v)·2^111 + t·Od(v), DENv = Ev(v)·2^111 − t·Od(v) ``` (scale `2^725 = 2^(528+87+110)`; `Ev`/`Od` are `evNumV`/`odNumV` from `Floor/R0Bound`), three facts @@ -86,14 +86,14 @@ combine: `0 ≤ a ≤ b` holds pairwise on the coefficients, so the cert value `ê(t²)` lies between the two grid values `ê(v, t)` and `ê(v+1, t)`; * **the `K` identity** — one grid step is exact algebra: - `NUMv(v)·DENv(v+1) − NUMv(v+1)·DENv(v) = 2t·2^110·K(v)` with + `NUMv(v)·DENv(v+1) − NUMv(v+1)·DENv(v) = 2t·2^111·K(v)` with `K(v) = Od(v)·Ev(v+1) − Ev(v)·Od(v+1)`, a degree-8 polynomial in `v` with all nine coefficients positive, so `K` is nonnegative and nondecreasing on the grid; * **the piecewise denominator floors** — the grid `[0, vmaxV]` is split into 32 pieces, each with a `t`-cap `T` (`v` in the piece forces `|t| ≤ T` through `v = ⌊t²/2^133⌋`) and cover-certified - floors `Ev(v)·2^110 ∓ T·Od(v) ≥ D·2^725` over the piece (the step looks one cell ahead, so the + floors `Ev(v)·2^111 ∓ T·Od(v) ≥ D·2^725` over the piece (the step looks one cell ahead, so the certs run to `vhi + 1`); on the negative half the one-grain lift `2|t|·K/(D·D′)` is additionally - monotone in `|t|` (the derivative sign reduces to the over-half floor `Ev·2^110 − |t|·Od ≥ 0`), + monotone in `|t|` (the derivative sign reduces to the over-half floor `Ev·2^111 − |t|·Od ≥ 0`), so each piece's `t = −T` floor applies. `piece_select` packages the per-piece constants — floors, `K`-cap, and the certified budget inequalities — for the runtime point. @@ -143,21 +143,21 @@ theorem evalPoly_mono_of_nonneg {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) {a b /-! ## The even/odd polynomials in the square argument `w = t²` -/ -/-- The even Horner polynomial in `w` (degree 5, monic), at the cleared scale `2¹¹⁹²`. -/ +/-- The even Horner polynomial in `w` (degree 5, monic), at the cleared scale `2¹²⁰¹`. -/ def Pev : List Int := - [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192, - 0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933, - 0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671, - 0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415, - 0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133, + [0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201, + 0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941, + 0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677, + 0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419, + 0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135, 1] -/-- The odd Horner polynomial in `w` (degree 4), at the cleared scale `2¹⁰⁴⁰`. -/ +/-- The odd Horner polynomial in `w` (degree 4), at the cleared scale `2¹⁰⁴⁸`. -/ def Pod : List Int := - [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040, - 0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779, - 0xad4506af99be27419341e181693281 * 2 ^ 524, - 0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259, + [0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048, + 0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785, + 0xad4506af99be27419341e181693281 * 2 ^ 528, + 0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261, 0xdc07aff8276bde9a361278df6a10] /-- `evNumVPoly(t) = Pev(t²)`: the cert even polynomial is `Pev` composed with squaring. -/ @@ -174,16 +174,16 @@ theorem odNumVPoly_eq_Pod_sq (t : Int) : simp only [evalPoly_polyAdd, evalPoly] ring -/-- `Pev(2¹³³·v) = evNumV(v)·2⁶⁶⁵` — the `w`-polynomial at the grid point `w = 2¹³³·v` recovers the +/-- `Pev(2¹³⁵·v) = evNumV(v)·2⁶⁶⁵` — the `w`-polynomial at the grid point `w = 2¹³⁵·v` recovers the integer even-Horner accumulator (scaled). -/ -theorem Pev_grid (v : Nat) : evalPoly Pev (2 ^ 133 * (v : Int)) = (evNumV v : Int) * 2 ^ 665 := by +theorem Pev_grid (v : Nat) : evalPoly Pev (2 ^ 135 * (v : Int)) = (evNumV v : Int) * 2 ^ 675 := by unfold Pev evNumV simp only [evalPoly] push_cast ring -/-- `Pod(2¹³³·v) = odNumV(v)·2⁵³²`. -/ -theorem Pod_grid (v : Nat) : evalPoly Pod (2 ^ 133 * (v : Int)) = (odNumV v : Int) * 2 ^ 532 := by +/-- `Pod(2¹³⁵·v) = odNumV(v)·2⁵³²`. -/ +theorem Pod_grid (v : Nat) : evalPoly Pod (2 ^ 135 * (v : Int)) = (odNumV v : Int) * 2 ^ 540 := by unfold Pod odNumV simp only [evalPoly] push_cast @@ -199,9 +199,9 @@ theorem odNumVPoly_nonneg (t : Int) : 0 ≤ evalPoly ExpCertV.odNumVPoly t := by /-! ## Evaluation shapes and the reciprocal symmetry of the cert rational -/ -/-- `evalPoly todNumV t = 2²³ · t · evalPoly odNumVPoly t`. -/ +/-- `evalPoly todNumV t = 2²⁴ · t · evalPoly odNumVPoly t`. -/ theorem evalTodNumV (t : Int) : - evalPoly ExpCertV.todNumV t = 2 ^ 23 * (t * evalPoly ExpCertV.odNumVPoly t) := by + evalPoly ExpCertV.todNumV t = 2 ^ 24 * (t * evalPoly ExpCertV.odNumVPoly t) := by unfold ExpCertV.todNumV rw [evalPoly_polyScale] simp only [evalPoly] @@ -223,7 +223,7 @@ theorem evNumVPoly_even (t : Int) : rw [evNumVPoly_eq_Pev_sq, evNumVPoly_eq_Pev_sq] congr 1; ring -/-- `todNumV` is odd (`= 2²³·t·Pod(t²)`). -/ +/-- `todNumV` is odd (`= 2²⁴·t·Pod(t²)`). -/ theorem todNumV_odd (t : Int) : evalPoly ExpCertV.todNumV (-t) = -evalPoly ExpCertV.todNumV t := by rw [evalTodNumV, evalTodNumV, odNumVPoly_eq_Pod_sq, odNumVPoly_eq_Pod_sq] @@ -239,15 +239,15 @@ theorem denExpV_neg_eq_numExpV (t : Int) : evalPoly ExpCertV.denExpV (-t) = evalPoly ExpCertV.numExpV t := by rw [evalDenExpV, evalNumExpV, evNumVPoly_even, todNumV_odd]; ring -/-- The numerator/denominator cert-polynomial values are nonnegative / positive on `[0, H128]`. -/ -theorem certNE_nonneg {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : +/-- The numerator/denominator cert-polynomial values are nonnegative / positive on `[0, H129]`. -/ +theorem certNE_nonneg {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H129 : Int)) : 0 ≤ evalPoly ExpCertV.numExpV t := ExpCertV.numExpV_nonneg' h1 h2 -theorem certDE_pos {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : +theorem certDE_pos {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H129 : Int)) : 1 ≤ evalPoly ExpCertV.denExpV t := ExpCertV.denExpV_ge_one h1 h2 -/-- For `t ≤ 0` with `−t ∈ [0, H128]` the cert numerator/denominator at `t` are positive. -/ -theorem certNE_pos_neg_aux {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : +/-- For `t ≤ 0` with `−t ∈ [0, H129]` the cert numerator/denominator at `t` are positive. -/ +theorem certNE_pos_neg_aux {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H129 : Int)) : 0 < evalPoly ExpCertV.numExpV t ∧ 0 < evalPoly ExpCertV.denExpV t := by have hnt : 0 ≤ -t := by omega -- numExpV(t) = denExpV(-t) ≥ 1 > 0 @@ -274,11 +274,11 @@ theorem certNE_pos_neg_aux {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H12 /-! ## The aligned integer rational on the `v`-grid -/ -/-- `NUMv(v, t) = Ev(v)·2^110 + t·Od(v)` at the common scale `2^725`. -/ -def NUMv (v : Nat) (t : Int) : Int := (evNumV v : Int) * 2 ^ 110 + t * (odNumV v : Int) +/-- `NUMv(v, t) = Ev(v)·2^111 + t·Od(v)` at the common scale `2^725`. -/ +def NUMv (v : Nat) (t : Int) : Int := (evNumV v : Int) * 2 ^ 111 + t * (odNumV v : Int) -/-- `DENv(v, t) = Ev(v)·2^110 − t·Od(v)` at the common scale `2^725`. -/ -def DENv (v : Nat) (t : Int) : Int := (evNumV v : Int) * 2 ^ 110 - t * (odNumV v : Int) +/-- `DENv(v, t) = Ev(v)·2^111 − t·Od(v)` at the common scale `2^725`. -/ +def DENv (v : Nat) (t : Int) : Int := (evNumV v : Int) * 2 ^ 111 - t * (odNumV v : Int) /-- `evNumV` as an `evalPoly` over the cert coefficient list. -/ theorem evNumV_eq_poly (v : Nat) : (evNumV v : Int) = evalPoly ExpCertV.evVPoly (v : Int) := by @@ -294,10 +294,10 @@ theorem odNumV_eq_poly (v : Nat) : (odNumV v : Int) = evalPoly ExpCertV.odVPoly ring /-- The over-half floor shape evaluated at a grid point: -`certDOverP T D (v) = Ev(v)·2^110 − T·Od(v) − D·2^725`. -/ +`certDOverP T D (v) = Ev(v)·2^111 − T·Od(v) − D·2^725`. -/ theorem evalDOverP (T D : Int) (v : Nat) : evalPoly (ExpCertV.certDOverP T D) (v : Int) = - (evNumV v : Int) * 2 ^ 110 - T * (odNumV v : Int) - D * 2 ^ 725 := by + (evNumV v : Int) * 2 ^ 111 - T * (odNumV v : Int) - D * 2 ^ 725 := by unfold ExpCertV.certDOverP rw [evalPoly_polyAdd, evalPoly_polySub, evalPoly_polyScale, evalPoly_polyScale, ← evNumV_eq_poly, ← odNumV_eq_poly] @@ -305,10 +305,10 @@ theorem evalDOverP (T D : Int) (v : Nat) : ring /-- The under-half floor shape evaluated at a grid point: -`certDUnderP T D (v) = Ev(v)·2^110 + T·Od(v) − D·2^725`. -/ +`certDUnderP T D (v) = Ev(v)·2^111 + T·Od(v) − D·2^725`. -/ theorem evalDUnderP (T D : Int) (v : Nat) : evalPoly (ExpCertV.certDUnderP T D) (v : Int) = - (evNumV v : Int) * 2 ^ 110 + T * (odNumV v : Int) - D * 2 ^ 725 := by + (evNumV v : Int) * 2 ^ 111 + T * (odNumV v : Int) - D * 2 ^ 725 := by unfold ExpCertV.certDUnderP rw [evalPoly_polyAdd, evalPoly_polyAdd, evalPoly_polyScale, evalPoly_polyScale, ← evNumV_eq_poly, ← odNumV_eq_poly] @@ -317,41 +317,41 @@ theorem evalDUnderP (T D : Int) (v : Nat) : /-! ## The certified global denominator floor over the grid -/ -/-- The over-half denominator floor: `DENv(v, t) ≥ 554482771859·2^725` for `0 ≤ t ≤ H128` on the +/-- The over-half denominator floor: `DENv(v, t) ≥ 1108965543718·2^725` for `0 ≤ t ≤ H129` on the grid `[0, vmaxV + 1]`, from the cover certificate `certDOver`. -/ theorem DENv_ge_over {v : Nat} {t : Int} (hv : v ≤ ExpCertV.vmaxV + 1) - (htH : t ≤ 117932881612756647068972071382077242199) : - 554482771859 * 2 ^ 725 ≤ DENv v t := by + (htH : t ≤ 235865763225513294137944142764154484399) : + 1108965543718 * 2 ^ 725 ≤ DENv v t := by have hvI : (0 : Int) ≤ (v : Int) := Int.natCast_nonneg _ have hvI2 : (v : Int) ≤ 1277263193518626341050532535110179583 := by have h : v ≤ 1277263193518626341050532535110179583 := by unfold ExpCertV.vmaxV at hv; omega exact_mod_cast h have hcert := ExpCertV.dOverV_nonneg hvI hvI2 - have hH : ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 := by - unfold ExpCertV.H128; norm_num + have hH : ((ExpCertV.H129 : Nat) : Int) = 235865763225513294137944142764154484399 := by + unfold ExpCertV.H129; norm_num have hexp : evalPoly ExpCertV.certDOver (v : Int) = - (evNumV v : Int) * 2 ^ 110 - 117932881612756647068972071382077242199 * (odNumV v : Int) - - 554482771859 * 2 ^ 725 := by + (evNumV v : Int) * 2 ^ 111 - 235865763225513294137944142764154484399 * (odNumV v : Int) + - 1108965543718 * 2 ^ 725 := by unfold ExpCertV.certDOver rw [evalDOverP, hH] rw [hexp] at hcert have hOd_nn : (0 : Int) ≤ (odNumV v : Int) := Int.natCast_nonneg _ - have htOd : t * (odNumV v : Int) ≤ 117932881612756647068972071382077242199 * (odNumV v : Int) := + have htOd : t * (odNumV v : Int) ≤ 235865763225513294137944142764154484399 * (odNumV v : Int) := mul_le_mul_of_nonneg_right htH hOd_nn unfold DENv linarith [hcert, htOd] /-- The scaled even value alone clears the over floor. -/ theorem Ev_scaled_ge {v : Nat} (hv : v ≤ ExpCertV.vmaxV + 1) : - 554482771859 * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 110 := by + 1108965543718 * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 111 := by have h := DENv_ge_over hv (t := 0) (by norm_num) unfold DENv at h linarith [h] /-- On the nonpositive half the denominator is bounded below by the scaled even value. -/ theorem DENv_ge_neg {v : Nat} {t : Int} (hv : v ≤ ExpCertV.vmaxV + 1) (htnp : t ≤ 0) : - 554482771859 * 2 ^ 725 ≤ DENv v t := by + 1108965543718 * 2 ^ 725 ≤ DENv v t := by have hOd_nn : (0 : Int) ≤ (odNumV v : Int) := Int.natCast_nonneg _ have h := Ev_scaled_ge hv have htOd : t * (odNumV v : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htnp hOd_nn @@ -396,22 +396,22 @@ theorem KpM_le_at {v : Nat} {vhi : Int} (hv : (v : Int) ≤ vhi) : KpM v ≤ eva /-- **The discrete quotient identity**: one grid step of the aligned rational is exact algebra. -/ theorem step_identity (v : Nat) (t : Int) : - NUMv v t * DENv (v + 1) t - NUMv (v + 1) t * DENv v t = 2 * t * 2 ^ 110 * KpM v := by + NUMv v t * DENv (v + 1) t - NUMv (v + 1) t * DENv v t = 2 * t * 2 ^ 111 * KpM v := by unfold NUMv DENv KpM ring /-! ## Grid placement of the exact square -/ -/-- The squared reduced argument splits as `t² = 2¹³³·vTree x + r` with `0 ≤ r < 2¹³³`. -/ +/-- The squared reduced argument splits as `t² = 2¹³⁵·vTree x + r` with `0 ≤ r < 2¹³⁵`. -/ theorem tsq_split {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 2 ^ 133 * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ - (int256 (tTree x)) ^ 2 < 2 ^ 133 * (vTree x : Int) + 2 ^ 133 := by + 2 ^ 135 * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ + (int256 (tTree x)) ^ 2 < 2 ^ 135 * (vTree x : Int) + 2 ^ 135 := by obtain ⟨hveq, _⟩ := vTree_eq hx hC hC0 have hsqnn : (0 : Int) ≤ (int256 (tTree x)) ^ 2 := sq_nonneg _ - have hdm := Int.ediv_add_emod ((int256 (tTree x)) ^ 2) (2 ^ 133) - have hmod_lt := Int.emod_lt_of_pos ((int256 (tTree x)) ^ 2) (by norm_num : (0:Int) < 2 ^ 133) - have hmod_nn := Int.emod_nonneg ((int256 (tTree x)) ^ 2) (by norm_num : (2:Int) ^ 133 ≠ 0) + have hdm := Int.ediv_add_emod ((int256 (tTree x)) ^ 2) (2 ^ 135) + have hmod_lt := Int.emod_lt_of_pos ((int256 (tTree x)) ^ 2) (by norm_num : (0:Int) < 2 ^ 135) + have hmod_nn := Int.emod_nonneg ((int256 (tTree x)) ^ 2) (by norm_num : (2:Int) ^ 135 ≠ 0) rw [hveq] constructor · nlinarith [hdm, hmod_nn] @@ -423,13 +423,13 @@ theorem vTree_le_vmax {x : Nat} (hx : x < 2 ^ 256) vTree x ≤ ExpCertV.vmaxV := by obtain ⟨hlo, _⟩ := tsq_split hx hC hC0 obtain ⟨htlo, hthi⟩ := tTree_in_cert_domain hx hC hC0 - have ht2 : (int256 (tTree x)) ^ 2 ≤ 117932881612756647068972071382077242199 ^ 2 := by + have ht2 : (int256 (tTree x)) ^ 2 ≤ 235865763225513294137944142764154484399 ^ 2 := by nlinarith [htlo, hthi] - have hlt : 2 ^ 133 * (vTree x : Int) < - 2 ^ 133 * (1277263193518626341050532535110179583 : Int) := by - calc 2 ^ 133 * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 := hlo - _ ≤ 117932881612756647068972071382077242199 ^ 2 := ht2 - _ < 2 ^ 133 * 1277263193518626341050532535110179583 := by norm_num + have hlt : 2 ^ 135 * (vTree x : Int) < + 2 ^ 135 * (1277263193518626341050532535110179583 : Int) := by + calc 2 ^ 135 * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 := hlo + _ ≤ 235865763225513294137944142764154484399 ^ 2 := ht2 + _ < 2 ^ 135 * 1277263193518626341050532535110179583 := by norm_num have hvI : (vTree x : Int) < 1277263193518626341050532535110179583 := lt_of_mul_lt_mul_left hlt (by positivity) have hvN : vTree x < 1277263193518626341050532535110179583 := by exact_mod_cast hvI @@ -454,52 +454,52 @@ cross `a^j·b^i − a^i·b^j` is nonnegative on `0 ≤ a ≤ b`. -/ theorem pev_pod_cross {a b : Int} (ha : 0 ≤ a) (hab : a ≤ b) : 0 ≤ evalPoly Pev b * evalPoly Pod a - evalPoly Pev a * evalPoly Pod b := by have hexpand : evalPoly Pev b * evalPoly Pod a - evalPoly Pev a * evalPoly Pod b = - (((0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) + - (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xad4506af99be27419341e181693281 * 2 ^ 524) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) + - (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xad4506af99be27419341e181693281 * 2 ^ 524) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) + - (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) + - (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) + - (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) + - (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) + - (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) + - (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) + - (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) + - (((1) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) + - (((1) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) + - (((1) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) + - (((1) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) + - (((1) * (0xdc07aff8276bde9a361278df6a10) - (0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0) : Int)) * (a ^ 4 * b ^ 5 - a ^ 5 * b ^ 4) := by + (((0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) + + (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0xad4506af99be27419341e181693281 * 2 ^ 528) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) + + (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0xad4506af99be27419341e181693281 * 2 ^ 528) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) + + (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) + + (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) + + (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0xad4506af99be27419341e181693281 * 2 ^ 528) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0xad4506af99be27419341e181693281 * 2 ^ 528) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) + + (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) + + (((1) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) + + (((1) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) + + (((1) * (0xad4506af99be27419341e181693281 * 2 ^ 528) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) + + (((1) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) + + (((1) * (0xdc07aff8276bde9a361278df6a10) - (0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0) : Int)) * (a ^ 4 * b ^ 5 - a ^ 5 * b ^ 4) := by simp only [Pev, Pod, evalPoly] ring - have h10 : (0:Int) ≤ (((0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) := + have h10 : (0:Int) ≤ (((0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) : Int)) * (a ^ 0 * b ^ 1 - a ^ 1 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 1; simpa using this) - have h20 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xad4506af99be27419341e181693281 * 2 ^ 524) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) := + have h20 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0xad4506af99be27419341e181693281 * 2 ^ 528) : Int)) * (a ^ 0 * b ^ 2 - a ^ 2 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 2; simpa using this) - have h21 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xad4506af99be27419341e181693281 * 2 ^ 524) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) := + have h21 : (0:Int) ≤ (((0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0xad4506af99be27419341e181693281 * 2 ^ 528) : Int)) * (a ^ 1 * b ^ 2 - a ^ 2 * b ^ 1) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 1; simpa using this) - have h30 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) := + have h30 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) : Int)) * (a ^ 0 * b ^ 3 - a ^ 3 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 3; simpa using this) - have h31 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) := + have h31 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) : Int)) * (a ^ 1 * b ^ 3 - a ^ 3 * b ^ 1) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 2; simpa using this) - have h32 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) := + have h32 : (0:Int) ≤ (((0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0xad4506af99be27419341e181693281 * 2 ^ 528) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) : Int)) * (a ^ 2 * b ^ 3 - a ^ 3 * b ^ 2) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 1; simpa using this) - have h40 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) := + have h40 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 0 * b ^ 4 - a ^ 4 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 4; simpa using this) - have h41 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) := + have h41 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 1 * b ^ 4 - a ^ 4 * b ^ 1) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 3; simpa using this) - have h42 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) := + have h42 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0xad4506af99be27419341e181693281 * 2 ^ 528) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 2 * b ^ 4 - a ^ 4 * b ^ 2) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 2; simpa using this) - have h43 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) := + have h43 : (0:Int) ≤ (((0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0xdc07aff8276bde9a361278df6a10) : Int)) * (a ^ 3 * b ^ 4 - a ^ 4 * b ^ 3) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 3 1; simpa using this) - have h50 : (0:Int) ≤ (((1) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1040) - (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1192) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) := + have h50 : (0:Int) ≤ (((1) * (0x9c2948bcaca16a0dd2fe98bb4470c388 * 2 ^ 1048) - (0x1385291795942d41ba5fd317688e18710 * 2 ^ 1201) * (0) : Int)) * (a ^ 0 * b ^ 5 - a ^ 5 * b ^ 0) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 0 5; simpa using this) - have h51 : (0:Int) ≤ (((1) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 779) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 933) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) := + have h51 : (0:Int) ≤ (((1) * (0xaf566247c05753b42892f77b67a6b7c7 * 2 ^ 785) - (0x93f11e650dd6c64b96ce79065cdf80f4 * 2 ^ 941) * (0) : Int)) * (a ^ 1 * b ^ 5 - a ^ 5 * b ^ 1) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 1 4; simpa using this) - have h52 : (0:Int) ≤ (((1) * (0xad4506af99be27419341e181693281 * 2 ^ 524) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 671) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) := + have h52 : (0:Int) ≤ (((1) * (0xad4506af99be27419341e181693281 * 2 ^ 528) - (0x9064d9657e9a21fc16bb69331b81ae1e * 2 ^ 677) * (0) : Int)) * (a ^ 2 * b ^ 5 - a ^ 5 * b ^ 2) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 2 3; simpa using this) - have h53 : (0:Int) ≤ (((1) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 259) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 415) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) := + have h53 : (0:Int) ≤ (((1) * (0xc926ddbecdeeb42e68cd16db7ed378 * 2 ^ 261) - (0x9a036222841f47c6ed6fc3f7599445 * 2 ^ 419) * (0) : Int)) * (a ^ 3 * b ^ 5 - a ^ 5 * b ^ 3) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 3 2; simpa using this) - have h54 : (0:Int) ≤ (((1) * (0xdc07aff8276bde9a361278df6a10) - (0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 133) * (0) : Int)) * (a ^ 4 * b ^ 5 - a ^ 5 * b ^ 4) := + have h54 : (0:Int) ≤ (((1) * (0xdc07aff8276bde9a361278df6a10) - (0xb9aacfacf3c10b378435f8e22adf48500e * 2 ^ 135) * (0) : Int)) * (a ^ 4 * b ^ 5 - a ^ 5 * b ^ 4) := mul_nonneg (by norm_num) (by have := pow_pair_mono ha hab 4 1; simpa using this) rw [hexpand] linarith [h10, h20, h21, h30, h31, h32, h40, h41, h42, h43, h50, h51, h52, h53, h54] @@ -521,27 +521,27 @@ theorem tie_cross {a b : Int} (s : Int) (ha : 0 ≤ a) (hab : a ≤ b) (hs : 0 /-- The `w`-polynomials at a grid point recover the aligned rational's numerator (scale `2^555`). -/ theorem grid_num_eq (v : Nat) (t : Int) : - evalPoly Pev (2 ^ 133 * (v : Int)) + 2 ^ 23 * t * evalPoly Pod (2 ^ 133 * (v : Int)) = - 2 ^ 555 * NUMv v t := by + evalPoly Pev (2 ^ 135 * (v : Int)) + 2 ^ 24 * t * evalPoly Pod (2 ^ 135 * (v : Int)) = + 2 ^ 564 * NUMv v t := by rw [Pev_grid, Pod_grid] unfold NUMv ring theorem grid_den_eq (v : Nat) (t : Int) : - evalPoly Pev (2 ^ 133 * (v : Int)) - 2 ^ 23 * t * evalPoly Pod (2 ^ 133 * (v : Int)) = - 2 ^ 555 * DENv v t := by + evalPoly Pev (2 ^ 135 * (v : Int)) - 2 ^ 24 * t * evalPoly Pod (2 ^ 135 * (v : Int)) = + 2 ^ 564 * DENv v t := by rw [Pev_grid, Pod_grid] unfold DENv ring /-- The cert polynomials at `t` are the `w`-polynomials at the exact square. -/ theorem NE_eq_w (t : Int) : - evalPoly ExpCertV.numExpV t = evalPoly Pev (t ^ 2) + 2 ^ 23 * t * evalPoly Pod (t ^ 2) := by + evalPoly ExpCertV.numExpV t = evalPoly Pev (t ^ 2) + 2 ^ 24 * t * evalPoly Pod (t ^ 2) := by rw [evalNumExpV, evalTodNumV, ← evNumVPoly_eq_Pev_sq, ← odNumVPoly_eq_Pod_sq] ring theorem DE_eq_w (t : Int) : - evalPoly ExpCertV.denExpV t = evalPoly Pev (t ^ 2) - 2 ^ 23 * t * evalPoly Pod (t ^ 2) := by + evalPoly ExpCertV.denExpV t = evalPoly Pev (t ^ 2) - 2 ^ 24 * t * evalPoly Pod (t ^ 2) := by rw [evalDenExpV, evalTodNumV, ← evNumVPoly_eq_Pev_sq, ← odNumVPoly_eq_Pod_sq] ring @@ -557,33 +557,33 @@ theorem tie_over {x : Nat} (hx : x < 2 ^ 256) obtain ⟨haw, hwb⟩ := tsq_split hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hs : (0:Int) ≤ 2 ^ 23 * t := by positivity - have ha : (0:Int) ≤ 2 ^ 133 * (v : Int) := by positivity + have hs : (0:Int) ≤ 2 ^ 24 * t := by positivity + have ha : (0:Int) ≤ 2 ^ 135 * (v : Int) := by positivity have hw : (0:Int) ≤ t ^ 2 := sq_nonneg _ - have hb1 : t ^ 2 ≤ 2 ^ 133 * ((v + 1 : Nat) : Int) := by push_cast; linarith [hwb] - have hp555 : (0:Int) < 2 ^ 555 := by positivity + have hb1 : t ^ 2 ≤ 2 ^ 135 * ((v + 1 : Nat) : Int) := by push_cast; linarith [hwb] + have hp555 : (0:Int) < 2 ^ 564 := by positivity constructor · -- a := grid v, b := t²: NE·(2^555·DENv v) ≤ (2^555·NUMv v)·DE - have h1 := tie_cross (a := 2 ^ 133 * (v : Int)) (b := t ^ 2) (2 ^ 23 * t) ha haw hs + have h1 := tie_cross (a := 2 ^ 135 * (v : Int)) (b := t ^ 2) (2 ^ 24 * t) ha haw hs rw [grid_num_eq, grid_den_eq, ← NE_eq_w, ← DE_eq_w] at h1 -- h1 : NE·(2^555·DENv v t) ≤ (2^555·NUMv v t)·DE - have h2 : 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv v t) ≤ - 2 ^ 555 * (NUMv v t * evalPoly ExpCertV.denExpV t) := by - calc 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv v t) - = evalPoly ExpCertV.numExpV t * (2 ^ 555 * DENv v t) := by ring - _ ≤ 2 ^ 555 * NUMv v t * evalPoly ExpCertV.denExpV t := h1 - _ = 2 ^ 555 * (NUMv v t * evalPoly ExpCertV.denExpV t) := by ring + have h2 : 2 ^ 564 * (evalPoly ExpCertV.numExpV t * DENv v t) ≤ + 2 ^ 564 * (NUMv v t * evalPoly ExpCertV.denExpV t) := by + calc 2 ^ 564 * (evalPoly ExpCertV.numExpV t * DENv v t) + = evalPoly ExpCertV.numExpV t * (2 ^ 564 * DENv v t) := by ring + _ ≤ 2 ^ 564 * NUMv v t * evalPoly ExpCertV.denExpV t := h1 + _ = 2 ^ 564 * (NUMv v t * evalPoly ExpCertV.denExpV t) := by ring exact le_of_mul_le_mul_left h2 hp555 · -- a := t², b := grid (v+1): (2^555·NUMv (v+1))·DE ≤ NE·(2^555·DENv (v+1)) - have h1 := tie_cross (a := t ^ 2) (b := 2 ^ 133 * ((v + 1 : Nat) : Int)) (2 ^ 23 * t) hw hb1 hs + have h1 := tie_cross (a := t ^ 2) (b := 2 ^ 135 * ((v + 1 : Nat) : Int)) (2 ^ 24 * t) hw hb1 hs rw [grid_num_eq, grid_den_eq, ← NE_eq_w, ← DE_eq_w] at h1 -- h1 : (2^555·NUMv (v+1) t)·DE ≤ NE·(2^555·DENv (v+1) t) - have h2 : 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) ≤ - 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) := by - calc 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) - = 2 ^ 555 * NUMv (v + 1) t * evalPoly ExpCertV.denExpV t := by ring - _ ≤ evalPoly ExpCertV.numExpV t * (2 ^ 555 * DENv (v + 1) t) := h1 - _ = 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) := by ring + have h2 : 2 ^ 564 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) ≤ + 2 ^ 564 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) := by + calc 2 ^ 564 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) + = 2 ^ 564 * NUMv (v + 1) t * evalPoly ExpCertV.denExpV t := by ring + _ ≤ evalPoly ExpCertV.numExpV t * (2 ^ 564 * DENv (v + 1) t) := h1 + _ = 2 ^ 564 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) := by ring exact le_of_mul_le_mul_left h2 hp555 /-- **The tie at the runtime point (nonpositive half)**: the directions flip. -/ @@ -597,53 +597,53 @@ theorem tie_under {x : Nat} (hx : x < 2 ^ 256) obtain ⟨haw, hwb⟩ := tsq_split hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hs : (0:Int) ≤ 2 ^ 23 * (-t) := by + have hs : (0:Int) ≤ 2 ^ 24 * (-t) := by have : (0:Int) ≤ -t := by linarith [htnp] positivity - have ha : (0:Int) ≤ 2 ^ 133 * (v : Int) := by positivity + have ha : (0:Int) ≤ 2 ^ 135 * (v : Int) := by positivity have hw : (0:Int) ≤ t ^ 2 := sq_nonneg _ - have hb1 : t ^ 2 ≤ 2 ^ 133 * ((v + 1 : Nat) : Int) := by push_cast; linarith [hwb] - have hp555 : (0:Int) < 2 ^ 555 := by positivity + have hb1 : t ^ 2 ≤ 2 ^ 135 * ((v + 1 : Nat) : Int) := by push_cast; linarith [hwb] + have hp555 : (0:Int) < 2 ^ 564 := by positivity -- with σ = −s ≥ 0, the `N`/`D` roles swap: Pev + σ·Pod = DENv-form, Pev − σ·Pod = NUMv-form constructor - · have h1 := tie_cross (a := 2 ^ 133 * (v : Int)) (b := t ^ 2) (2 ^ 23 * (-t)) ha haw hs + · have h1 := tie_cross (a := 2 ^ 135 * (v : Int)) (b := t ^ 2) (2 ^ 24 * (-t)) ha haw hs -- rewrite σ-forms into t-forms: Pev x + 2^23·(−t)·Pod x = Pev x − 2^23·t·Pod x - have e1 : evalPoly Pev (t ^ 2) + 2 ^ 23 * (-t) * evalPoly Pod (t ^ 2) = + have e1 : evalPoly Pev (t ^ 2) + 2 ^ 24 * (-t) * evalPoly Pod (t ^ 2) = evalPoly ExpCertV.denExpV t := by rw [DE_eq_w]; ring - have e2 : evalPoly Pev (2 ^ 133 * (v : Int)) - 2 ^ 23 * (-t) * evalPoly Pod (2 ^ 133 * (v : Int)) = - 2 ^ 555 * NUMv v t := by rw [← grid_num_eq]; ring - have e3 : evalPoly Pev (2 ^ 133 * (v : Int)) + 2 ^ 23 * (-t) * evalPoly Pod (2 ^ 133 * (v : Int)) = - 2 ^ 555 * DENv v t := by rw [← grid_den_eq]; ring - have e4 : evalPoly Pev (t ^ 2) - 2 ^ 23 * (-t) * evalPoly Pod (t ^ 2) = + have e2 : evalPoly Pev (2 ^ 135 * (v : Int)) - 2 ^ 24 * (-t) * evalPoly Pod (2 ^ 135 * (v : Int)) = + 2 ^ 564 * NUMv v t := by rw [← grid_num_eq]; ring + have e3 : evalPoly Pev (2 ^ 135 * (v : Int)) + 2 ^ 24 * (-t) * evalPoly Pod (2 ^ 135 * (v : Int)) = + 2 ^ 564 * DENv v t := by rw [← grid_den_eq]; ring + have e4 : evalPoly Pev (t ^ 2) - 2 ^ 24 * (-t) * evalPoly Pod (t ^ 2) = evalPoly ExpCertV.numExpV t := by rw [NE_eq_w]; ring rw [e1, e2, e3, e4] at h1 -- h1 : DE·(2^555·NUMv v t) ≤ (2^555·DENv v t)·NE - have h2 : 2 ^ 555 * (NUMv v t * evalPoly ExpCertV.denExpV t) ≤ - 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv v t) := by - calc 2 ^ 555 * (NUMv v t * evalPoly ExpCertV.denExpV t) - = evalPoly ExpCertV.denExpV t * (2 ^ 555 * NUMv v t) := by ring - _ ≤ 2 ^ 555 * DENv v t * evalPoly ExpCertV.numExpV t := h1 - _ = 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv v t) := by ring + have h2 : 2 ^ 564 * (NUMv v t * evalPoly ExpCertV.denExpV t) ≤ + 2 ^ 564 * (evalPoly ExpCertV.numExpV t * DENv v t) := by + calc 2 ^ 564 * (NUMv v t * evalPoly ExpCertV.denExpV t) + = evalPoly ExpCertV.denExpV t * (2 ^ 564 * NUMv v t) := by ring + _ ≤ 2 ^ 564 * DENv v t * evalPoly ExpCertV.numExpV t := h1 + _ = 2 ^ 564 * (evalPoly ExpCertV.numExpV t * DENv v t) := by ring exact le_of_mul_le_mul_left h2 hp555 - · have h1 := tie_cross (a := t ^ 2) (b := 2 ^ 133 * ((v + 1 : Nat) : Int)) (2 ^ 23 * (-t)) hw hb1 hs - have e1 : evalPoly Pev (2 ^ 133 * ((v + 1 : Nat) : Int)) + - 2 ^ 23 * (-t) * evalPoly Pod (2 ^ 133 * ((v + 1 : Nat) : Int)) = - 2 ^ 555 * DENv (v + 1) t := by rw [← grid_den_eq]; ring - have e2 : evalPoly Pev (t ^ 2) - 2 ^ 23 * (-t) * evalPoly Pod (t ^ 2) = + · have h1 := tie_cross (a := t ^ 2) (b := 2 ^ 135 * ((v + 1 : Nat) : Int)) (2 ^ 24 * (-t)) hw hb1 hs + have e1 : evalPoly Pev (2 ^ 135 * ((v + 1 : Nat) : Int)) + + 2 ^ 24 * (-t) * evalPoly Pod (2 ^ 135 * ((v + 1 : Nat) : Int)) = + 2 ^ 564 * DENv (v + 1) t := by rw [← grid_den_eq]; ring + have e2 : evalPoly Pev (t ^ 2) - 2 ^ 24 * (-t) * evalPoly Pod (t ^ 2) = evalPoly ExpCertV.numExpV t := by rw [NE_eq_w]; ring - have e3 : evalPoly Pev (t ^ 2) + 2 ^ 23 * (-t) * evalPoly Pod (t ^ 2) = + have e3 : evalPoly Pev (t ^ 2) + 2 ^ 24 * (-t) * evalPoly Pod (t ^ 2) = evalPoly ExpCertV.denExpV t := by rw [DE_eq_w]; ring - have e4 : evalPoly Pev (2 ^ 133 * ((v + 1 : Nat) : Int)) - - 2 ^ 23 * (-t) * evalPoly Pod (2 ^ 133 * ((v + 1 : Nat) : Int)) = - 2 ^ 555 * NUMv (v + 1) t := by rw [← grid_num_eq]; ring + have e4 : evalPoly Pev (2 ^ 135 * ((v + 1 : Nat) : Int)) - + 2 ^ 24 * (-t) * evalPoly Pod (2 ^ 135 * ((v + 1 : Nat) : Int)) = + 2 ^ 564 * NUMv (v + 1) t := by rw [← grid_num_eq]; ring rw [e1, e2, e3, e4] at h1 -- h1 : (2^555·DENv (v+1) t)·NE ≤ DE·(2^555·NUMv (v+1) t) - have h2 : 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) ≤ - 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) := by - calc 2 ^ 555 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) - = 2 ^ 555 * DENv (v + 1) t * evalPoly ExpCertV.numExpV t := by ring - _ ≤ evalPoly ExpCertV.denExpV t * (2 ^ 555 * NUMv (v + 1) t) := h1 - _ = 2 ^ 555 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) := by ring + have h2 : 2 ^ 564 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) ≤ + 2 ^ 564 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) := by + calc 2 ^ 564 * (evalPoly ExpCertV.numExpV t * DENv (v + 1) t) + = 2 ^ 564 * DENv (v + 1) t * evalPoly ExpCertV.numExpV t := by ring + _ ≤ evalPoly ExpCertV.denExpV t * (2 ^ 564 * NUMv (v + 1) t) := h1 + _ = 2 ^ 564 * (NUMv (v + 1) t * evalPoly ExpCertV.denExpV t) := by ring exact le_of_mul_le_mul_left h2 hp555 /-! ## The 32-piece granularity certificate -/ @@ -654,21 +654,21 @@ certified budget inequalities of the piece against the two exported envelopes (`3290521163436398582/10¹⁹` over, `1644901622230542074/10¹⁹` under, `Mp`-folded). -/ def PieceOK (v : Nat) (T DO DU Khi : Int) : Prop := 0 < DO ∧ 0 < DU ∧ 0 ≤ Khi ∧ 0 ≤ T ∧ - DO * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 110 - T * (odNumV v : Int) ∧ - DO * 2 ^ 725 ≤ (evNumV (v + 1) : Int) * 2 ^ 110 - T * (odNumV (v + 1) : Int) ∧ - DU * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 110 + T * (odNumV v : Int) ∧ - DU * 2 ^ 725 ≤ (evNumV (v + 1) : Int) * 2 ^ 110 + T * (odNumV (v + 1) : Int) ∧ + DO * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 111 - T * (odNumV v : Int) ∧ + DO * 2 ^ 725 ≤ (evNumV (v + 1) : Int) * 2 ^ 111 - T * (odNumV (v + 1) : Int) ∧ + DU * 2 ^ 725 ≤ (evNumV v : Int) * 2 ^ 111 + T * (odNumV v : Int) ∧ + DU * 2 ^ 725 ≤ (evNumV (v + 1) : Int) * 2 ^ 111 + T * (odNumV (v + 1) : Int) ∧ KpM v ≤ Khi ∧ - 2 * T * 2 ^ 110 * Khi * 2 ^ 126 * 10000000000000000000 ≤ + 2 * T * 2 ^ 111 * Khi * 2 ^ 126 * 10000000000000000000 ≤ 3290521163436398582 * ((DO * 2 ^ 725) * (DO * 2 ^ 725)) ∧ - 2 ^ 126 * 2 ^ 131 * (2 * T * 2 ^ 110 * Khi) * 10000000000000000000 ≤ + 2 ^ 126 * 2 ^ 131 * (2 * T * 2 ^ 111 * Khi) * 10000000000000000000 ≤ 1644901622230542074 * ((2 ^ 131 - 1) * ((DU * 2 ^ 725) * (DU * 2 ^ 725))) /-- The piece cap dominates the square: from the split `t² < 2^133·v + 2^133`, membership `v ≤ vhi`, and the cap fact `2^133·(vhi + 1) ≤ T²`. -/ -theorem tsq_lt_capsq {t : Int} {v : Nat} (hsplit : t ^ 2 < 2 ^ 133 * (v : Int) + 2 ^ 133) +theorem tsq_lt_capsq {t : Int} {v : Nat} (hsplit : t ^ 2 < 2 ^ 135 * (v : Int) + 2 ^ 135) {vhi : Int} (hv : (v : Int) ≤ vhi) {T : Int} - (hT : 2 ^ 133 * vhi + 2 ^ 133 ≤ T ^ 2) : + (hT : 2 ^ 135 * vhi + 2 ^ 135 ≤ T ^ 2) : t ^ 2 < T ^ 2 := by nlinarith [hsplit, hT, hv] @@ -681,7 +681,7 @@ def PieceHolds : Int × Int × Int × Int × Int → Prop /-- Each piece's `t`-cap dominates its `v`-range: `(vhi + 1)·2^133 ≤ T²`. -/ theorem granPieces_caps : - ∀ p ∈ ExpCertV.granPieces, 2 ^ 133 * p.2.1 + 2 ^ 133 ≤ p.2.2.1 ^ 2 := by + ∀ p ∈ ExpCertV.granPieces, 2 ^ 135 * p.2.1 + 2 ^ 135 ≤ p.2.2.1 ^ 2 := by decide +kernel /-- `piecesCover lo hi ps`: the pieces' closed `v`-ranges, in table order, cover `[lo, hi]`. -/ diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean index c5ea73483..4dacf1728 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Bound.lean @@ -15,10 +15,10 @@ ingredients of that discharge: * the **Horner-truncation bridge** for the even/odd accumulators — the runtime `evTree x`/`odTree x`, which truncate each Horner `>>` stage, bracket the exact integer polynomials `evNumV (vTree x)` - (degree 5, cleared scale `2^527`) and `odNumV (vTree x)` (degree 4, cleared scale `2^508`): the + (degree 5, cleared scale `2^526`) and `odNumV (vTree x)` (degree 4, cleared scale `2^508`): the monic leading stage is an exact add, and the four lossy stages' floor losses telescope with shrinking amplification (each stage shift exceeds `120 = ⌈log₂ v⌉`), leaving widths - `142941343449089·2^480 ≈ 1.0157·2^527` and `269746241·2^480 ≈ 1.0049·2^508`; + `72572599271425·2^480 ≈ 1.0313·2^526` and `269746241·2^480 ≈ 1.0049·2^508`; * the self-contained **below-clamp bound** — below the clamp boundary the target is under one output unit — directly from a `Real.exp` rational bound. -/ @@ -168,22 +168,22 @@ theorem horner_stage_frac (c prev v cum sh p Wnum Eprev : Nat) /-! ## The even accumulator The monic leading stage `ev0 = A4 + v` is an exact add (width `1·2^0`); the four `mul/shr` stages -(shifts `0x95, 0x7b, 0x81, 0x7e`, cumulative `149, 272, 401, 527`) telescope the width to -`142941343449089·2^480 ≈ 1.0157·2^527`. -/ +(shifts `0x95, 0x7b, 0x81, 0x7d`, cumulative `149, 272, 401, 526`) telescope the width to +`72572599271425·2^480 ≈ 1.0313·2^526`. -/ -/-- Exact integer even-Horner accumulator (degree-5 monic in `v`, cleared scale `2^527`). -/ +/-- Exact integer even-Horner accumulator (degree-5 monic in `v`, cleared scale `2^526`). -/ def evNumV (v : Nat) : Nat := let e0 := 0xb9aacfacf3c10b378435f8e22adf48500e + v let e1 := 0x9a036222841f47c6ed6fc3f7599445 * 2^149 + e0 * v let e2 := 0x9064d9657e9a21fc16bb69331b81ae1e * 2^272 + e1 * v let e3 := 0x93f11e650dd6c64b96ce79065cdf80f4 * 2^401 + e2 * v - 0x9c2948bcaca16a0dd2fe98bb4470c388 * 2^527 + e3 * v + 0x1385291795942d41ba5fd317688e18710 * 2^526 + e3 * v theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : - 2^527 * evTree x ≤ evNumV (vTree x) ∧ - evNumV (vTree x) < 2^527 * evTree x + 142941343449089 * 2^480 := by + 2^526 * evTree x ≤ evNumV (vTree x) ∧ + evNumV (vTree x) < 2^526 * evTree x + 72572599271425 * 2^480 := by have hev : evTree x = - evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -260,8 +260,8 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (P := 2^129) (V := 2^120) (sh := 0x81) he2lt hv (by norm_num) (by norm_num) (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 rw [pvd 129 120 129 120 (by norm_num)] at this; omega - -- stage 4: cum 401 -> 527, sh=126; p 360 -> 480; Wnum 2203855093761 -> 142941343449089 - have s4 := horner_stage_frac 0x9c2948bcaca16a0dd2fe98bb4470c388 e3 v 401 0x7e 360 2203855093761 + -- stage 4: cum 401 -> 527, sh=126; p 360 -> 480; Wnum 2203855093761 -> 72572599271425 + have s4 := horner_stage_frac 0x1385291795942d41ba5fd317688e18710 e3 v 401 0x7d 360 2203855093761 (0x93f11e650dd6c64b96ce79065cdf80f4 * 2^401 + (0x9064d9657e9a21fc16bb69331b81ae1e * 2^272 + (0x9a036222841f47c6ed6fc3f7599445 * 2^149 + @@ -272,14 +272,14 @@ theorem evTree_bracket {x : Nat} (hv : vTree x < 2 ^ 120) : (by calc e3 * v < 2^129 * 2^120 := Nat.mul_lt_mul'' he3lt hv _ < 2^256 := by norm_num) (by norm_num) (by norm_num) s3.1 s3.2 - rw [show (401:Nat)+0x7e-(360+120) = 47 from by norm_num, - show (2203855093761:Nat)+2^47 = 142941343449089 from by norm_num, - show (360:Nat)+120 = 480 from by norm_num, show (401:Nat)+0x7e = 527 from by norm_num] at s4 + rw [show (401:Nat)+0x7d-(360+120) = 46 from by norm_num, + show (2203855093761:Nat)+2^46 = 72572599271425 from by norm_num, + show (360:Nat)+120 = 480 from by norm_num, show (401:Nat)+0x7d = 526 from by norm_num] at s4 -- assemble: evTree x = e4 (the stage-4 value), evNumV v = the cumulative E4. rw [hev] - show 2^527 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul e3 v)) ≤ evNumV v ∧ - evNumV v < 2^527 * evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul e3 v)) + - 142941343449089 * 2^480 + show 2^526 * evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul e3 v)) ≤ evNumV v ∧ + evNumV v < 2^526 * evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul e3 v)) + + 72572599271425 * 2^480 unfold evNumV constructor · have := s4.1 diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean index b1087490a..0a6239963 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0BoundHolds.lean @@ -9,11 +9,11 @@ import ExpProof.Seam.RealExp The per-point `r0`-vs-`exp` brackets (`r0_real_over_within`, `r0_real_under_within`) and the below-clamp bound (`belowC_target_lt_one`) establish the never-over and deficit-under-one facts about the real pre-floor accumulator unconditionally and axiom-clean, via the octave fold -`E·2^s = WAD·2⁶⁸·exp(rt)` (`WAD·2⁶⁸ = scaleQ68`; `s = 68 − k`, the closing shift; `k ≤ 64` so +`E·2^s = WAD·2⁶⁸·exp(rt)` (`WAD·2⁶⁸ = scaleQ67`; `s = 68 − k`, the closing shift; `k ≤ 64` so `s ≥ 4`). -* `accumReal_over` ⟸ `r0 ≤ scaleQ68·exp(rt) + (5¹⁸/2⁴⁰)·B` and `(5¹⁸/2⁴⁰)·B ≤ MARGIN = 3`; -* `accumReal_under` ⟸ `scaleQ68·exp(rt) ≤ r0 + U` (`U = 33/4`) and +* `accumReal_over` ⟸ `r0 ≤ scaleQ67·exp(rt) + (5¹⁸/2⁴⁰)·B` and `(5¹⁸/2⁴⁰)·B ≤ MARGIN = 3`; +* `accumReal_under` ⟸ `scaleQ67·exp(rt) ≤ r0 + U` (`U = 2993/1000`) and `U + MARGIN < 2⁴ ≤ 2^s`. These make the global floor-or-one-less and one-unit underestimation brackets hypothesis-free. @@ -39,14 +39,14 @@ theorem accumReal_over (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- r0 − MARGIN ≤ scaleQ68·Ert = E·2^s - have hbound : (int256 (r0Tree x) : Real) - 3 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) := by + -- r0 − MARGIN ≤ scaleQ67·Ert = E·2^s + have hbound : (int256 (r0Tree x) : Real) - 1 ≤ expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] - -- (5¹⁸/2⁴⁰)·B ≤ 3 = MARGIN - have hBM : (3814697265625 : Real) * 5792534503673398887 / - (10000000000000000000 * 1099511627776) ≤ 3 := by norm_num + -- (5¹⁸/2⁴⁰)·B ≤ 1 = MARGIN + have hBM : (3814697265625 : Real) * 5737291786393199862 / + (10000000000000000000 * 2199023255552) ≤ 1 := by norm_num linarith [hover, hBM] rw [hAeq, div_le_iff₀ hps] linarith [hbound] @@ -61,23 +61,23 @@ theorem accumReal_under (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 have hunder := r0_real_under_within hx hC hC0 obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- E·2^s = scaleQ68·Ert < (r0 − MARGIN) + 2^s + -- E·2^s = scaleQ67·Ert < (r0 − MARGIN) + 2^s have hbound : expRayToWadTarget (int256 x) * (2 ^ s : Real) < - ((int256 (r0Tree x) : Real) - 3) + (2 ^ s : Real) := by + ((int256 (r0Tree x) : Real) - 1) + (2 ^ s : Real) := by rw [hfold] have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num - have hs4 : (4 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] - have hs4n : 4 ≤ s := by exact_mod_cast hs4 - have hpow : (2 ^ 4 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs4n + have hs4 : (2 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs4n : 2 ≤ s := by exact_mod_cast hs4 + have hpow : (2 ^ 2 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs4n rw [hwad] -- U + MARGIN < 2⁴ - have hbudget : (33 / 4 : Real) + 3 < (2 ^ 4 : Real) := by + have hbudget : (2993 / 1000 : Real) + 1 < (2 ^ 2 : Real) := by norm_num linarith [hunder, hbudget, hpow] -- E < accumReal + 1 ⟺ E·2^s < (r0 − MARGIN) + 2^s rw [hAeq] - have hdiv : ((int256 (r0Tree x) : Real) - 3) / (2 ^ s : Real) + 1 = - (((int256 (r0Tree x) : Real) - 3) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp + have hdiv : ((int256 (r0Tree x) : Real) - 1) / (2 ^ s : Real) + 1 = + (((int256 (r0Tree x) : Real) - 1) + (2 ^ s : Real)) / (2 ^ s : Real) := by field_simp rw [hdiv, lt_div_iff₀ hps] linarith [hbound] diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean index c96275aa0..43ba5b407 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0Exp.lean @@ -23,9 +23,9 @@ never-over budget (stated `2⁴⁰`-scaled so every constant stays integral: `2 3. **`ê(t²)` vs `exp(t/2¹²⁸)`** — the `2⁻¹³²`-nudged Taylor cut (`Floor.CapsV`), the `Mp` factor `≤ 220970869120796102/10¹⁹`; 4. **`exp(t/2¹²⁸)` vs `exp(rt)`** — the reduced-argument gap (`Floor.Reduce`), - `≤ 110485434560398051/10¹⁹`. + `≤ 55242717280199026/10¹⁹`. -The total is the budget `B = 5792534503673398887/10¹⁹`; `MARGIN = ⌊5¹⁸·B⌋ + 1`. On the `t ≤ 0` +The total is the budget `B = 5737291786393199862/10¹⁹`; `MARGIN = ⌊5¹⁸·B⌋ + 1`. On the `t ≤ 0` half link 2 is free (the grain moves `ê` the other way) and links 3–4 shrink (`ê ≤ 1`), so the same `B` covers both halves. -/ @@ -42,13 +42,13 @@ set_option exponentiation.threshold 2000 /-! ## The `div` floor sandwich -/ -/-- The scaled quotient is the integer floor: `r0·den_rt ≤ scaleQ68·num_rt < (r0+1)·den_rt` with +/-- The scaled quotient is the integer floor: `r0·den_rt ≤ scaleQ67·num_rt < (r0+1)·den_rt` with `num_rt = ev + tod`, `den_rt = ev − tod`. -/ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : int256 (r0Tree x) * ((evTree x : Int) - int256 (todTree x)) ≤ - (0xde0b6b3a764000000000000000000000 : Int) * ((evTree x : Int) + int256 (todTree x)) ∧ - (0xde0b6b3a764000000000000000000000 : Int) * ((evTree x : Int) + int256 (todTree x)) < + (0x6f05b59d3b2000000000000000000000 : Int) * ((evTree x : Int) + int256 (todTree x)) ∧ + (0x6f05b59d3b2000000000000000000000 : Int) * ((evTree x : Int) + int256 (todTree x)) < (int256 (r0Tree x) + 1) * ((evTree x : Int) - int256 (todTree x)) := by obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos hx hC hC0 set num := evmAdd (evTree x) (todTree x) with hnumdef @@ -61,39 +61,39 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hdeneq, hden255⟩ := int256_eq_of_nonneg hdenw (by rw [hdeni]; omega) obtain ⟨hevlo, hevhi⟩ := evTree_facts (vTree_eq hx hC hC0).2 obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 - have hevloI : (207573926795459379279817565122117813128 : Int) ≤ (evTree x : Int) := by - have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + have hevloI : (415147853590918758559635130244235626256 : Int) ≤ (evTree x : Int) := by + have : (0x1385291795942d41ba5fd317688e18710 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo linarith [this] - have hevhiI : (evTree x : Int) < 3 * 2 ^ 126 := by exact_mod_cast hevhi + have hevhiI : (evTree x : Int) < 3 * 2 ^ 127 := by exact_mod_cast hevhi have ht126 : int256 (todTree x) < 2 ^ 126 := htod_hi have hp126 : (2:Int) ^ 126 = 85070591730234615865843651857942052864 := by norm_num - have hnumlt128 : int256 num < 2 ^ 128 := by + have hnumlt128 : int256 num < 2 ^ 129 := by rw [hnumi] nlinarith [hevhiI, ht126] - have hnumnat128 : num < 2 ^ 128 := by - have hh : ((num : Nat) : Int) < 2 ^ 128 := by rw [hnumeq] at hnumlt128; exact hnumlt128 + have hnumnat128 : num < 2 ^ 129 := by + have hh : ((num : Nat) : Int) < 2 ^ 129 := by rw [hnumeq] at hnumlt128; exact hnumlt128 exact_mod_cast hh - have hsw : scaleQ68 < 2 ^ 256 := by unfold scaleQ68; norm_num - have hfit : scaleQ68 * num < 2 ^ 256 := by - have h1 : scaleQ68 * num ≤ scaleQ68 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hnumnat128) - have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + have hsw : scaleQ67 < 2 ^ 256 := by unfold scaleQ67; norm_num + have hfit : scaleQ67 * num < 2 ^ 256 := by + have h1 : scaleQ67 * num ≤ scaleQ67 * 2 ^ 129 := Nat.mul_le_mul_left _ (le_of_lt hnumnat128) + have h2 : scaleQ67 * 2 ^ 129 < 2 ^ 256 := by unfold scaleQ67; norm_num omega - have hmulval : evmMul scaleQ68 num = scaleQ68 * num := evmMul_eq_nat hsw hnumw hfit + have hmulval : evmMul scaleQ67 num = scaleQ67 * num := evmMul_eq_nat hsw hnumw hfit have hdennat : 0 < den := by have hh : (0:Int) < ((den : Nat) : Int) := by rw [← hdeneq, hdeni]; omega exact_mod_cast hh - have hr0eq : r0Tree x = evmDiv (evmMul scaleQ68 num) den := rfl - have hdivval : evmDiv (evmMul scaleQ68 num) den = scaleQ68 * num / den := by + have hr0eq : r0Tree x = evmDiv (evmMul scaleQ67 num) den := rfl + have hdivval : evmDiv (evmMul scaleQ67 num) den = scaleQ67 * num / den := by rw [hmulval, evmDiv_eq hfit hdenw (by omega)] - have hr0q : r0Tree x = scaleQ68 * num / den := by rw [hr0eq, hdivval] - have hfloor_lo : (scaleQ68 * num / den) * den ≤ scaleQ68 * num := Nat.div_mul_le_self _ _ - have hfloor_hi : scaleQ68 * num < (scaleQ68 * num / den + 1) * den := by - have hdm : den * (scaleQ68 * num / den) + (scaleQ68 * num) % den = scaleQ68 * num := + have hr0q : r0Tree x = scaleQ67 * num / den := by rw [hr0eq, hdivval] + have hfloor_lo : (scaleQ67 * num / den) * den ≤ scaleQ67 * num := Nat.div_mul_le_self _ _ + have hfloor_hi : scaleQ67 * num < (scaleQ67 * num / den + 1) * den := by + have hdm : den * (scaleQ67 * num / den) + (scaleQ67 * num) % den = scaleQ67 * num := Nat.div_add_mod _ den - have hmod : (scaleQ68 * num) % den < den := Nat.mod_lt _ hdennat - calc scaleQ68 * num = den * (scaleQ68 * num / den) + (scaleQ68 * num) % den := hdm.symm - _ < den * (scaleQ68 * num / den) + den := Nat.add_lt_add_left hmod _ - _ = (scaleQ68 * num / den + 1) * den := by ring + have hmod : (scaleQ67 * num) % den < den := Nat.mod_lt _ hdennat + calc scaleQ67 * num = den * (scaleQ67 * num / den) + (scaleQ67 * num) % den := hdm.symm + _ < den * (scaleQ67 * num / den) + den := Nat.add_lt_add_left hmod _ + _ = (scaleQ67 * num / den + 1) * den := by ring -- the quotient is small: den ≥ 2^126 gives q < 2^130 < 2^255 have hden126 : 2 ^ 126 ≤ den := by have h : (2 ^ 126 : Int) ≤ ((den : Nat) : Int) := by @@ -101,15 +101,15 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) rw [hp126] at ht126 omega exact_mod_cast h - have hq130 : scaleQ68 * num / den < 2 ^ 130 := by - have h1 : scaleQ68 * num / den ≤ scaleQ68 * num / 2 ^ 126 := + have hq130 : scaleQ67 * num / den < 2 ^ 130 := by + have h1 : scaleQ67 * num / den ≤ scaleQ67 * num / 2 ^ 126 := Nat.div_le_div_left hden126 (Nat.two_pow_pos _) - have h2 : scaleQ68 * num / 2 ^ 126 < 2 ^ 130 := by + have h2 : scaleQ67 * num / 2 ^ 126 < 2 ^ 130 := by rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] - calc scaleQ68 * num < 2 ^ 256 := hfit + calc scaleQ67 * num < 2 ^ 256 := hfit _ = 2 ^ 130 * 2 ^ 126 := by norm_num omega - have hr0nat : int256 (r0Tree x) = ((scaleQ68 * num / den : Nat) : Int) := by + have hr0nat : int256 (r0Tree x) = ((scaleQ67 * num / den : Nat) : Int) := by rw [hr0q] exact int256_of_lt (by have : (2:Nat) ^ 130 < 2 ^ 255 := by norm_num @@ -117,80 +117,43 @@ theorem r0_floor_sandwich {x : Nat} (hx : x < 2 ^ 256) have hgoalnum : (evTree x : Int) + int256 (todTree x) = (num : Int) := by rw [← hnumi, hnumeq] have hgoalden : (evTree x : Int) - int256 (todTree x) = (den : Int) := by rw [← hdeni, hdeneq] rw [hr0nat, hgoalnum, hgoalden] - have hscn : scaleQ68 = 0xde0b6b3a764000000000000000000000 := rfl + have hscn : scaleQ67 = 0x6f05b59d3b2000000000000000000000 := rfl constructor - · have hInt : ((scaleQ68 * num / den : Nat) : Int) * ((den : Nat) : Int) ≤ - ((scaleQ68 * num : Nat) : Int) := by exact_mod_cast hfloor_lo + · have hInt : ((scaleQ67 * num / den : Nat) : Int) * ((den : Nat) : Int) ≤ + ((scaleQ67 * num : Nat) : Int) := by exact_mod_cast hfloor_lo rw [hscn] at hInt ⊢ push_cast at hInt ⊢ linarith [hInt] - · have hInt : ((scaleQ68 * num : Nat) : Int) < - (((scaleQ68 * num / den : Nat) : Int) + 1) * ((den : Nat) : Int) := by + · have hInt : ((scaleQ67 * num : Nat) : Int) < + (((scaleQ67 * num / den : Nat) : Int) + 1) * ((den : Nat) : Int) := by exact_mod_cast hfloor_hi rw [hscn] at hInt ⊢ push_cast at hInt ⊢ linarith [hInt] -/-- The `t·Od` shift stays within `2¹²⁵` on the region: the cert-domain `|t| ≤ H128` against the -odd accumulator cap `Od < 5·2¹²⁵`. -/ -theorem todTree_small {x : Nat} (hx : x < 2 ^ 256) - (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - -(2 ^ 125 : Int) ≤ int256 (todTree x) ∧ int256 (todTree x) < 2 ^ 125 := by - obtain ⟨htlo, hthi⟩ := tTree_in_cert_domain hx hC hC0 - obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 - have hodlt : odTree x < 5 * 2 ^ 125 := odTree_lt hvlt - obtain ⟨_, _, hgrid_lo, hgrid_hi⟩ := todTree_bound hx hC hC0 - have hod_nn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ - have hod_ub : (odTree x : Int) < 5 * 2 ^ 125 := by exact_mod_cast hodlt - have hprod_hi : int256 (tTree x) * (odTree x : Int) ≤ - 117932881612756647068972071382077242199 * (5 * 2 ^ 125) := by - have h1 : int256 (tTree x) * (odTree x : Int) ≤ - 117932881612756647068972071382077242199 * (odTree x : Int) := - mul_le_mul_of_nonneg_right hthi hod_nn - have h2 : (117932881612756647068972071382077242199 : Int) * (odTree x : Int) ≤ - 117932881612756647068972071382077242199 * (5 * 2 ^ 125) := - mul_le_mul_of_nonneg_left (le_of_lt hod_ub) (by norm_num) - linarith - have hprod_lo : -(117932881612756647068972071382077242199 * (5 * 2 ^ 125) : Int) ≤ - int256 (tTree x) * (odTree x : Int) := by - have h1 : -(117932881612756647068972071382077242199 : Int) * (odTree x : Int) ≤ - int256 (tTree x) * (odTree x : Int) := - mul_le_mul_of_nonneg_right htlo hod_nn - have h2 : -(117932881612756647068972071382077242199 * (5 * 2 ^ 125) : Int) ≤ - -(117932881612756647068972071382077242199 : Int) * (odTree x : Int) := by - have := mul_le_mul_of_nonneg_left (le_of_lt hod_ub) - (by norm_num : (0:Int) ≤ 117932881612756647068972071382077242199) - linarith - linarith - have hHcap : (117932881612756647068972071382077242199 : Int) * (5 * 2 ^ 125) < - 2 ^ 125 * 2 ^ 129 := by norm_num - constructor - · nlinarith [hgrid_hi, hprod_lo, hHcap] - · nlinarith [hgrid_lo, hprod_hi, hHcap] - /-- `den_rt = ev − tod ≥ 1.94·2¹²⁶` on the region (the even accumulator dominates `|tod|`). -/ theorem den_ge_194 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (165038630930342071346895739193146786696 : Int) ≤ + (330077261860684142693791478386293573392 : Int) ≤ (evTree x : Int) - int256 (todTree x) := by obtain ⟨hevlo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨_, htod_hi⟩ := todTree_small hx hC hC0 - have hev : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo - have ht125 : int256 (todTree x) < 2 ^ 125 := htod_hi - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 from by norm_num] at hev - rw [show (2:Int)^125 = 42535295865117307932921825928971026432 from by norm_num] at ht125 + obtain ⟨_, htod_hi, _, _⟩ := todTree_bound hx hC hC0 + have hev : (0x1385291795942d41ba5fd317688e18710 : Int) ≤ (evTree x : Int) := by exact_mod_cast hevlo + have ht126 : int256 (todTree x) < 2 ^ 126 := htod_hi + rw [show (0x1385291795942d41ba5fd317688e18710 : Int) = 415147853590918758559635130244235626256 from by norm_num] at hev + rw [show (2:Int)^126 = 85070591730234615865843651857942052864 from by norm_num] at ht126 omega -/-- On the nonpositive half `tod ≤ 0` and hence `r0 ≤ scaleQ68` (num ≤ den). -/ +/-- On the nonpositive half `tod ≤ 0` and hence `r0 ≤ scaleQ67` (num ≤ den). -/ theorem r0_le_scale_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - int256 (r0Tree x) ≤ (0xde0b6b3a764000000000000000000000 : Int) := by + int256 (r0Tree x) ≤ (0x6f05b59d3b2000000000000000000000 : Int) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - have hden072 : (165038630930342071346895739193146786696 : Int) ≤ ev - tod := by + have hden072 : (330077261860684142693791478386293573392 : Int) ≤ ev - tod := by have := den_ge_194 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 have htodnp : tod ≤ 0 := by @@ -198,25 +161,25 @@ theorem r0_le_scale_neg {x : Nat} (hx : x < 2 ^ 256) have hodnn : (0:Int) ≤ (odTree x : Int) := Int.natCast_nonneg _ have : int256 (tTree x) * (odTree x : Int) ≤ 0 := mul_nonpos_of_nonpos_of_nonneg htneg hodnn nlinarith [htodlo, this] - -- r0·den ≤ scaleQ68·num ≤ scaleQ68·den (num ≤ den) - have hscnn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) := by positivity - have hnumden : r0 * (ev - tod) ≤ (0xde0b6b3a764000000000000000000000 : Int) * (ev - tod) := by - have h1 : r0 * (ev - tod) ≤ (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) := hfloor_lo + -- r0·den ≤ scaleQ67·num ≤ scaleQ67·den (num ≤ den) + have hscnn : (0:Int) ≤ (0x6f05b59d3b2000000000000000000000 : Int) := by positivity + have hnumden : r0 * (ev - tod) ≤ (0x6f05b59d3b2000000000000000000000 : Int) * (ev - tod) := by + have h1 : r0 * (ev - tod) ≤ (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) := hfloor_lo nlinarith [h1, htodnp, hscnn] exact le_of_mul_le_mul_right hnumden hdenpos /-! ## The runtime brackets lifted to the `2^725` alignment `NUMv/DENv = Ev·2^110 ± t·Od` (`Floor.GranV`). The Horner-truncation brackets -(`evTree_bracket`/`odTree_bracket`, widths `Wev = 142941343449089·2^480 ≈ 1.0079·2^527` and +(`evTree_bracket`/`odTree_bracket`, widths `Wev = 72572599271425·2^480 ≈ 1.0079·2^527` and `Wod = 269746241·2^480 ≈ 1.0013·2^508`) and the `tod` floor (`todTree_bound`) tie them to the runtime `ev`/`tod` at the common scale `2^637`. -/ /-- The `Int`-cast Horner brackets and `tod` floor collected. -/ theorem bridge_facts {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - 2 ^ 527 * (evTree x : Int) ≤ (evNumV (vTree x) : Int) ∧ - (evNumV (vTree x) : Int) < 2 ^ 527 * (evTree x : Int) + 142941343449089 * 2 ^ 480 ∧ + 2 ^ 526 * (evTree x : Int) ≤ (evNumV (vTree x) : Int) ∧ + (evNumV (vTree x) : Int) < 2 ^ 526 * (evTree x : Int) + 72572599271425 * 2 ^ 480 ∧ 2 ^ 508 * (odTree x : Int) ≤ (odNumV (vTree x) : Int) ∧ (odNumV (vTree x) : Int) < 2 ^ 508 * (odTree x : Int) + 269746241 * 2 ^ 480 := by obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 @@ -284,15 +247,15 @@ theorem tOd_bracket_neg {x : Nat} (hx : x < 2 ^ 256) /-! ## Link 1 (over side): `r0` vs the grid rational, shared-`Ev` cancellation -/ -/-- **Joint link-1 over (nonneg half, `r0 ≥ scaleQ68`)**: the shared even truncation cancels through -the floor, `r0·DENv − scaleQ68·NUMv ≤ Wev·2⁵⁹⁰·(r0 − scaleQ68)`. -/ +/-- **Joint link-1 over (nonneg half, `r0 ≥ scaleQ67`)**: the shared even truncation cancels through +the floor, `r0·DENv − scaleQ67·NUMv ≤ Wev·2⁵⁹⁰·(r0 − scaleQ67)`. -/ theorem link1_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) - (hr0ge : (0xde0b6b3a764000000000000000000000 : Int) ≤ int256 (r0Tree x)) : + (hr0ge : (0x6f05b59d3b2000000000000000000000 : Int) ≤ int256 (r0Tree x)) : int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - - (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ - 142941343449089 * 2 ^ 590 * (int256 (r0Tree x) - (0xde0b6b3a764000000000000000000000 : Int)) := by + (0x6f05b59d3b2000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ + 72572599271425 * 2 ^ 591 * (int256 (r0Tree x) - (0x6f05b59d3b2000000000000000000000 : Int)) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn @@ -303,29 +266,29 @@ theorem link1_over_tight {x : Nat} (hx : x < 2 ^ 256) set t := int256 (tTree x) with htdef set Ep := (evNumV (vTree x) : Int) with hEpdef set Op := (odNumV (vTree x) : Int) with hOpdef - have hr0m : (0:Int) ≤ r0 - (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0ge] - have hr0p : (0:Int) ≤ r0 + (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0ge] + have hr0m : (0:Int) ≤ r0 - (0x6f05b59d3b2000000000000000000000 : Int) := by linarith [hr0ge] + have hr0p : (0:Int) ≤ r0 + (0x6f05b59d3b2000000000000000000000 : Int) := by linarith [hr0ge] -- Ep·2^110·(r0−2^126) ≤ (2^637·ev + Wev·2^590)·(r0−2^126) - have hterm1 : Ep * 2 ^ 110 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) ≤ - (2 ^ 637 * ev + 142941343449089 * 2 ^ 590) * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) := by + have hterm1 : Ep * 2 ^ 111 * (r0 - (0x6f05b59d3b2000000000000000000000 : Int)) ≤ + (2 ^ 637 * ev + 72572599271425 * 2 ^ 591) * (r0 - (0x6f05b59d3b2000000000000000000000 : Int)) := by apply mul_le_mul_of_nonneg_right _ hr0m nlinarith [hEp_hi] -- −(t·Op)·(r0+2^126) ≤ −(2^637·tod)·(r0+2^126) - have hterm2 : 2 ^ 637 * tod * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) ≤ t * Op * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) := + have hterm2 : 2 ^ 637 * tod * (r0 + (0x6f05b59d3b2000000000000000000000 : Int)) ≤ t * Op * (r0 + (0x6f05b59d3b2000000000000000000000 : Int)) := mul_le_mul_of_nonneg_right (by linarith [htOp_lo]) hr0p -- floor: r0·den − 2^126·num ≤ 0, scaled by 2^637 - have hfloor : r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod)) ≤ 0 := + have hfloor : r0 * (ev - tod) - (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] -/-- **Link-1 over (nonneg half, `r0 ≤ scaleQ68`)**: the residue is nonpositive outright. -/ +/-- **Link-1 over (nonneg half, `r0 ≤ scaleQ67`)**: the residue is nonpositive outright. -/ theorem link1_over_small {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) - (hr0le : int256 (r0Tree x) ≤ (0xde0b6b3a764000000000000000000000 : Int)) : + (hr0le : int256 (r0Tree x) ≤ (0x6f05b59d3b2000000000000000000000 : Int)) : int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - - (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ 0 := by + (0x6f05b59d3b2000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ 0 := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_lo, _⟩ := tOd_bracket_nonneg hx hC hC0 htnn @@ -340,27 +303,27 @@ theorem link1_over_small {x : Nat} (hx : x < 2 ^ 256) have hr0nn : (0:Int) ≤ r0 := by have : (0:Int) < 2 ^ 124 := by positivity linarith [hr0lo] - have hr0m : r0 - (0xde0b6b3a764000000000000000000000 : Int) ≤ 0 := by linarith [hr0le] - have hr0p : (0:Int) ≤ r0 + (0xde0b6b3a764000000000000000000000 : Int) := by positivity + have hr0m : r0 - (0x6f05b59d3b2000000000000000000000 : Int) ≤ 0 := by linarith [hr0le] + have hr0p : (0:Int) ≤ r0 + (0x6f05b59d3b2000000000000000000000 : Int) := by positivity -- Ep·2^110·(r0−2^126) ≤ 2^637·ev·(r0−2^126) (Ep·2^110 ≥ 2^637·ev, factor ≤ 0) - have hterm1 : Ep * 2 ^ 110 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) ≤ 2 ^ 637 * ev * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) := by + have hterm1 : Ep * 2 ^ 111 * (r0 - (0x6f05b59d3b2000000000000000000000 : Int)) ≤ 2 ^ 637 * ev * (r0 - (0x6f05b59d3b2000000000000000000000 : Int)) := by apply mul_le_mul_of_nonpos_right _ hr0m nlinarith [hEp_lo] - have hterm2 : 2 ^ 637 * tod * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) ≤ t * Op * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) := + have hterm2 : 2 ^ 637 * tod * (r0 + (0x6f05b59d3b2000000000000000000000 : Int)) ≤ t * Op * (r0 + (0x6f05b59d3b2000000000000000000000 : Int)) := mul_le_mul_of_nonneg_right (by linarith [htOp_lo]) hr0p - have hfloor : r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod)) ≤ 0 := + have hfloor : r0 * (ev - tod) - (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] -/-- **Link-1 over (nonpositive half)**: the even truncation drops (`r0 ≤ scaleQ68`); the odd truncation -survives attenuated to the `t`-scale: `r0·DENv − scaleQ68·NUMv ≤ Wod·2⁴⁸⁰·(−t)·(r0 + scaleQ68)`. -/ +/-- **Link-1 over (nonpositive half)**: the even truncation drops (`r0 ≤ scaleQ67`); the odd truncation +survives attenuated to the `t`-scale: `r0·DENv − scaleQ67·NUMv ≤ Wod·2⁴⁸⁰·(−t)·(r0 + scaleQ67)`. -/ theorem link1_over_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) - - (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ - 269746241 * 2 ^ 480 * (-(int256 (tTree x))) * (int256 (r0Tree x) + (0xde0b6b3a764000000000000000000000 : Int)) := by + (0x6f05b59d3b2000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) ≤ + 269746241 * 2 ^ 480 * (-(int256 (tTree x))) * (int256 (r0Tree x) + (0x6f05b59d3b2000000000000000000000 : Int)) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨_, htOp_lo⟩ := tOd_bracket_neg hx hC hC0 htneg @@ -376,17 +339,17 @@ theorem link1_over_neg {x : Nat} (hx : x < 2 ^ 256) have hr0nn : (0:Int) ≤ r0 := by have : (0:Int) < 2 ^ 124 := by positivity linarith [hr0lo] - have hr0m : r0 - (0xde0b6b3a764000000000000000000000 : Int) ≤ 0 := by linarith [hr0le] - have hr0p : (0:Int) ≤ r0 + (0xde0b6b3a764000000000000000000000 : Int) := by positivity - have hterm1 : Ep * 2 ^ 110 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) ≤ 2 ^ 637 * ev * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) := by + have hr0m : r0 - (0x6f05b59d3b2000000000000000000000 : Int) ≤ 0 := by linarith [hr0le] + have hr0p : (0:Int) ≤ r0 + (0x6f05b59d3b2000000000000000000000 : Int) := by positivity + have hterm1 : Ep * 2 ^ 111 * (r0 - (0x6f05b59d3b2000000000000000000000 : Int)) ≤ 2 ^ 637 * ev * (r0 - (0x6f05b59d3b2000000000000000000000 : Int)) := by apply mul_le_mul_of_nonpos_right _ hr0m nlinarith [hEp_lo] -- −(t·Op)·(r0+2^126) ≤ (−2^637·tod + Wod·2^480·(−t))·(r0+2^126) - have hterm2 : (2 ^ 637 * tod - 269746241 * 2 ^ 480 * (-t)) * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) ≤ - t * Op * (r0 + (0xde0b6b3a764000000000000000000000 : Int)) := + have hterm2 : (2 ^ 637 * tod - 269746241 * 2 ^ 480 * (-t)) * (r0 + (0x6f05b59d3b2000000000000000000000 : Int)) ≤ + t * Op * (r0 + (0x6f05b59d3b2000000000000000000000 : Int)) := mul_le_mul_of_nonneg_right htOp_lo hr0p - have hfloor : r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] - have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod)) ≤ 0 := + have hfloor : r0 * (ev - tod) - (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) ≤ 0 := by linarith [hfloor_lo] + have hfloor638 : (2:Int) ^ 637 * (r0 * (ev - tod) - (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod)) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hfloor nlinarith [hterm1, hterm2, hfloor638] @@ -400,7 +363,7 @@ theorem DENv_runtime_bracket {x : Nat} (hx : x < 2 ^ 256) 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 637 ≤ DENv (vTree x) (int256 (tTree x)) ∧ DENv (vTree x) (int256 (tTree x)) ≤ - 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + 142941343449089 * 2 ^ 590 := by + 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + 72572599271425 * 2 ^ 591 := by obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_lo, htOp_hi⟩ := tOd_bracket_nonneg hx hC hC0 htnn obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 @@ -411,17 +374,17 @@ theorem DENv_runtime_bracket {x : Nat} (hx : x < 2 ^ 256) set Ep := (evNumV (vTree x) : Int) with hEpdef set Op := (odNumV (vTree x) : Int) with hOpdef constructor - · -- lower: Ep·2^110 ≥ 2^637·ev; t·Op ≤ 2^637·tod + 2^637 + Wod·2^480·t, t ≤ H128; - -- Wod·2^480·H128 + 2^637 ≤ 2·2^637 - have h1 : 2 ^ 637 * ev ≤ Ep * 2 ^ 110 := by nlinarith [hEp_lo] + · -- lower: Ep·2^110 ≥ 2^637·ev; t·Op ≤ 2^637·tod + 2^637 + Wod·2^480·t, t ≤ H129; + -- Wod·2^480·H129 + 2^637 ≤ 2·2^637 + have h1 : 2 ^ 637 * ev ≤ Ep * 2 ^ 111 := by nlinarith [hEp_lo] have h2 : 269746241 * 2 ^ 480 * t ≤ - 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199 := + 269746241 * 2 ^ 480 * 235865763225513294137944142764154484399 := mul_le_mul_of_nonneg_left hthi (by positivity) - have h3 : (269746241 * 2 ^ 480 * 117932881612756647068972071382077242199 : Int) + 2 ^ 637 ≤ + have h3 : (269746241 * 2 ^ 480 * 235865763225513294137944142764154484399 : Int) + 2 ^ 637 ≤ 2 * 2 ^ 637 := by norm_num linarith [h1, htOp_hi, h2, h3] · -- upper: Ep·2^110 ≤ 2^637·ev + Wev·2^590; t·Op ≥ 2^637·tod - have h1 : Ep * 2 ^ 110 ≤ 2 ^ 637 * ev + 142941343449089 * 2 ^ 590 := by nlinarith [hEp_hi] + have h1 : Ep * 2 ^ 111 ≤ 2 ^ 637 * ev + 72572599271425 * 2 ^ 591 := by nlinarith [hEp_hi] linarith [h1, htOp_lo] /-- On the nonpositive half `DENv` dominates the scaled even accumulator: `2⁶³⁷·ev ≤ DENv`. -/ @@ -457,10 +420,10 @@ open ExpRealSpec Real Common.RealExpBridge Common.Exp noncomputable section /-- **Never-over cert real bound (nonneg half).** `(2¹³²−1)·NE / (2¹³²·DE) ≤ exp(t/2¹²⁸)`. -/ -theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : +theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H129 : Int)) : ((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ - Real.exp ((t : Real) / (2 ^ 128 : Real)) := by + Real.exp ((t : Real) / (2 ^ 129 : Real)) := by have hcap := ExpCertV.capExpLo h1 h2 have hwpos : 0 < (evalPoly ExpCertV.wLB t).toNat := by have hpos : 0 < evalPoly ExpCertV.wLB t := by @@ -476,8 +439,8 @@ theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) exact Int.mul_nonneg (by norm_num) (by have := certDE_pos h1 h2; omega) have hyn : ((evalPoly ExpCertV.yLB t).toNat : Int) = evalPoly ExpCertV.yLB t := Int.toNat_of_nonneg hylb have hwn : ((evalPoly ExpCertV.wLB t).toNat : Int) = evalPoly ExpCertV.wLB t := Int.toNat_of_nonneg hwlb - have harg : ((t.toNat : Nat) : Real) / ((ExpCertV.Qexp : Nat) : Real) = (t : Real) / (2 ^ 128 : Real) := by - rw [show ((ExpCertV.Qexp : Nat) : Real) = (2 ^ 128 : Real) from by unfold ExpCertV.Qexp; norm_num] + have harg : ((t.toNat : Nat) : Real) / ((ExpCertV.Qexp : Nat) : Real) = (t : Real) / (2 ^ 129 : Real) := by + rw [show ((ExpCertV.Qexp : Nat) : Real) = (2 ^ 129 : Real) from by unfold ExpCertV.Qexp; norm_num] congr 1 have : ((t.toNat : Nat) : Real) = (t : Real) := by have := htn; exact_mod_cast this @@ -497,8 +460,8 @@ theorem certLo_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) exact h /-- **Not-two-below cert real bound (nonneg half).** `exp(t/2¹²⁸) ≤ (2¹³²+1)·NE / (2¹³²·DE)`. -/ -theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) : - Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ +theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H129 : Int)) : + Real.exp ((t : Real) / (2 ^ 129 : Real)) ≤ ((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by have hcap := ExpCertV.capExpUp h1 h2 @@ -516,8 +479,8 @@ theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) exact Int.mul_nonneg (by norm_num) (by have := certDE_pos h1 h2; omega) have hyn : ((evalPoly ExpCertV.yUB t).toNat : Int) = evalPoly ExpCertV.yUB t := Int.toNat_of_nonneg hyub have hwn : ((evalPoly ExpCertV.wUB t).toNat : Int) = evalPoly ExpCertV.wUB t := Int.toNat_of_nonneg hwub - have harg : ((t.toNat : Nat) : Real) / ((ExpCertV.Qexp : Nat) : Real) = (t : Real) / (2 ^ 128 : Real) := by - rw [show ((ExpCertV.Qexp : Nat) : Real) = (2 ^ 128 : Real) from by unfold ExpCertV.Qexp; norm_num] + have harg : ((t.toNat : Nat) : Real) / ((ExpCertV.Qexp : Nat) : Real) = (t : Real) / (2 ^ 129 : Real) := by + rw [show ((ExpCertV.Qexp : Nat) : Real) = (2 ^ 129 : Real) from by unfold ExpCertV.Qexp; norm_num] congr 1 have : ((t.toNat : Nat) : Real) = (t : Real) := by have := htn; exact_mod_cast this @@ -536,10 +499,10 @@ theorem certUp_real {t : Int} (h1 : 0 ≤ t) (h2 : t ≤ (ExpCertV.H128 : Int)) rw [hynr, hwnr] at h exact h -/-- **Not-too-below cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: +/-- **Not-too-below cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H129]`: `exp(t/2¹²⁸) ≤ (2¹³²·NE) / ((2¹³²−1)·DE)`. -/ -theorem certUp_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : - Real.exp ((t : Real) / (2 ^ 128 : Real)) ≤ +theorem certUp_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H129 : Int)) : + Real.exp ((t : Real) / (2 ^ 129 : Real)) ≤ ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / (((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by have hnt : 0 ≤ -t := by omega @@ -548,40 +511,40 @@ theorem certUp_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : obtain ⟨hNEpos, hDEpos⟩ := certNE_pos_neg_aux h1 h2 have hNER : (0 : Real) < (evalPoly ExpCertV.numExpV t : Real) := by exact_mod_cast hNEpos have hDER : (0 : Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos - have hexpneg : Real.exp (((-t) : Int) / (2 ^ 128 : Real)) = - (Real.exp ((t : Real) / (2 ^ 128 : Real)))⁻¹ := by - rw [show (((-t):Int) : Real) / (2 ^ 128 : Real) = -((t : Real) / (2 ^ 128 : Real)) from by + have hexpneg : Real.exp (((-t) : Int) / (2 ^ 129 : Real)) = + (Real.exp ((t : Real) / (2 ^ 129 : Real)))⁻¹ := by + rw [show (((-t):Int) : Real) / (2 ^ 129 : Real) = -((t : Real) / (2 ^ 129 : Real)) from by push_cast; ring, Real.exp_neg] rw [hexpneg] at hcl - have hexppos := Real.exp_pos ((t : Real) / (2 ^ 128 : Real)) + have hexppos := Real.exp_pos ((t : Real) / (2 ^ 129 : Real)) have hlhs_pos : (0:Real) < ((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity rw [le_inv_comm₀ hlhs_pos hexppos] at hcl - calc Real.exp ((t : Real) / (2 ^ 128 : Real)) + calc Real.exp ((t : Real) / (2 ^ 129 : Real)) ≤ (((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := hcl _ = ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / (((2 ^ 132 - 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) := by rw [inv_div] -/-- **Never-over cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H128]`: +/-- **Never-over cert real bound (negative half).** For `t ≤ 0` with `−t ∈ [0, H129]`: `(2¹³²·NE) / ((2¹³²+1)·DE) ≤ exp(t/2¹²⁸)`. -/ -theorem certLo_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : Int)) : +theorem certLo_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H129 : Int)) : ((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real) / (((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real)) ≤ - Real.exp ((t : Real) / (2 ^ 128 : Real)) := by + Real.exp ((t : Real) / (2 ^ 129 : Real)) := by have hnt : 0 ≤ -t := by omega have hcu := certUp_real hnt h2 rw [numExpV_neg_eq_denExpV, denExpV_neg_eq_numExpV] at hcu obtain ⟨hNEpos, hDEpos⟩ := certNE_pos_neg_aux h1 h2 have hNER : (0 : Real) < (evalPoly ExpCertV.numExpV t : Real) := by exact_mod_cast hNEpos have hDER : (0 : Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos - have hexpneg : Real.exp (((-t) : Int) / (2 ^ 128 : Real)) = - (Real.exp ((t : Real) / (2 ^ 128 : Real)))⁻¹ := by - rw [show (((-t):Int) : Real) / (2 ^ 128 : Real) = -((t : Real) / (2 ^ 128 : Real)) from by + have hexpneg : Real.exp (((-t) : Int) / (2 ^ 129 : Real)) = + (Real.exp ((t : Real) / (2 ^ 129 : Real)))⁻¹ := by + rw [show (((-t):Int) : Real) / (2 ^ 129 : Real) = -((t : Real) / (2 ^ 129 : Real)) from by push_cast; ring, Real.exp_neg] rw [hexpneg] at hcu - have hexppos := Real.exp_pos ((t : Real) / (2 ^ 128 : Real)) + have hexppos := Real.exp_pos ((t : Real) / (2 ^ 129 : Real)) have hrhs_pos : (0:Real) < ((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)) := by positivity rw [inv_le_comm₀ hexppos hrhs_pos] at hcu @@ -590,15 +553,15 @@ theorem certLo_real_neg {t : Int} (h1 : t ≤ 0) (h2 : (-t) ≤ (ExpCertV.H128 : = (((2 ^ 132 + 1 : Int) : Real) * (evalPoly ExpCertV.denExpV t : Real) / (((2 ^ 132 : Int) : Real) * (evalPoly ExpCertV.numExpV t : Real)))⁻¹ := by rw [inv_div] - _ ≤ Real.exp ((t : Real) / (2 ^ 128 : Real)) := hcu + _ ≤ Real.exp ((t : Real) / (2 ^ 129 : Real)) := hcu -/-- `t/2¹²⁸ ≤ 0` gives the cert domain `−t ≤ H128` for the negative half. -/ +/-- `t/2¹²⁸ ≤ 0` gives the cert domain `−t ≤ H129` for the negative half. -/ theorem tdom_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (htneg : int256 (tTree x) ≤ 0) : (-(int256 (tTree x))) ≤ (ExpCertV.H128 : Int) := by + (htneg : int256 (tTree x) ≤ 0) : (-(int256 (tTree x))) ≤ (ExpCertV.H129 : Int) := by obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] + rw [show ((ExpCertV.H129 : Nat) : Int) = 235865763225513294137944142764154484399 from by + unfold ExpCertV.H129; norm_num] omega /-! ## Analytic helpers on the reduced argument -/ @@ -607,19 +570,19 @@ theorem tdom_neg {x : Nat} (hx : x < 2 ^ 256) `t/2¹²⁸ ≤ log 2 / 2`. -/ theorem t_over_2128_le_half_log2 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ Real.log 2 / 2 := by + (int256 (tTree x) : Real) / (2 ^ 129 : Real) ≤ Real.log 2 / 2 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hln2lo := ln2_lower rw [LN2c_eq] at hln2lo - have htR : (int256 (tTree x) : Real) ≤ (117932881612756647068972071382077242199 : Real) := by + have htR : (int256 (tTree x) : Real) ≤ (235865763225513294137944142764154484399 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hthi; push_cast at this; linarith [this] - have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity + have hp128 : (0 : Real) < (2 ^ 129 : Real) := by positivity rw [div_le_div_iff₀ hp128 (by norm_num : (0:Real) < 2)] - have hkey : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := by - have h1 : (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) ≤ Real.log 2 * (2 ^ 128 : Real) := by + have hkey : (2 : Real) * (235865763225513294137944142764154484399 : Real) ≤ Real.log 2 * (2 ^ 129 : Real) := by + have h1 : (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 129 : Real) ≤ Real.log 2 * (2 ^ 129 : Real) := by apply mul_le_mul_of_nonneg_right hln2lo (by positivity) - have h2 : (2 : Real) * (117932881612756647068972071382077242199 : Real) ≤ - (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 128 : Real) := by + have h2 : (2 : Real) * (235865763225513294137944142764154484399 : Real) ≤ + (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) * (2 ^ 129 : Real) := by rw [div_mul_eq_mul_div, le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)] norm_num linarith [h1, h2] @@ -628,9 +591,9 @@ theorem t_over_2128_le_half_log2 {x : Nat} (hx : x < 2 ^ 256) /-- `exp(t/2¹²⁸) ≤ √2` on the nonneg half. -/ theorem exp_t_le_sqrt2 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) ≤ Real.sqrt 2 := by + Real.exp ((int256 (tTree x) : Real) / (2 ^ 129 : Real)) ≤ Real.sqrt 2 := by have hle := t_over_2128_le_half_log2 hx hC hC0 - calc Real.exp ((int256 (tTree x) : Real) / (2 ^ 128 : Real)) + calc Real.exp ((int256 (tTree x) : Real) / (2 ^ 129 : Real)) ≤ Real.exp (Real.log 2 / 2) := Real.exp_le_exp.mpr hle _ = Real.sqrt 2 := by rw [Real.sqrt_eq_rpow, Real.rpow_def_of_pos (by norm_num : (0:Real) < 2)]; ring_nf @@ -648,8 +611,8 @@ theorem exp_reducedArg_gt_half {x : Nat} (hx : x < 2 ^ 256) (1 : Real) / 2 < Real.exp (reducedArg x) := by obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 have hclose := abs_lt.mp (reducedArg_close hx hC hC0) - have hp128 : (0 : Real) < (2 ^ 128 : Real) := by positivity - have htR : -(117932881612756647068972071382077242199 : Real) ≤ (int256 (tTree x) : Real) := by + have hp128 : (0 : Real) < (2 ^ 129 : Real) := by positivity + have htR : -(235865763225513294137944142764154484399 : Real) ≤ (int256 (tTree x) : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo; push_cast at this; linarith [this] have hln2 : (0.6931471805 : Real) ≤ Real.log 2 := by have := ln2_lower; rw [LN2c_eq] at this @@ -657,9 +620,9 @@ theorem exp_reducedArg_gt_half {x : Nat} (hx : x < 2 ^ 256) (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) / (2 ^ 235 : Real) := by rw [le_div_iff₀ (by positivity : (0:Real) < 2 ^ 235)]; norm_num linarith [this, h2] - have htdiv : -(0.35 : Real) ≤ (int256 (tTree x) : Real) / (2 ^ 128 : Real) := by + have htdiv : -(0.35 : Real) ≤ (int256 (tTree x) : Real) / (2 ^ 129 : Real) := by rw [le_div_iff₀ hp128]; nlinarith [htR] - have h9 : (9 : Real) / (8 * (2 ^ 128 : Real)) ≤ 0.34 := by + have h9 : (9 : Real) / (8 * (2 ^ 129 : Real)) ≤ 0.34 := by rw [div_le_iff₀ (by positivity)]; norm_num have hrt : -(Real.log 2) < reducedArg x := by linarith [hclose.1, htdiv, h9, hln2] have : Real.exp (-(Real.log 2)) < Real.exp (reducedArg x) := Real.exp_lt_exp.mpr hrt @@ -681,9 +644,9 @@ theorem Qv_le_14145 {x : Nat} (hx : x < 2 ^ 256) obtain ⟨_, hgran⟩ := gran_over_pair hx hC hC0 htnn obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 set t := int256 (tTree x) with htdef - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] + have htdom : t ≤ (ExpCertV.H129 : Int) := by + rw [show ((ExpCertV.H129 : Nat) : Int) = 235865763225513294137944142764154484399 from by + unfold ExpCertV.H129; norm_num] exact hthi have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by @@ -693,7 +656,7 @@ theorem Qv_le_14145 {x : Nat} (hx : x < 2 ^ 256) have := certNE_nonneg htnn htdom; exact_mod_cast this -- NE/DE ≤ Et·Mp ≤ √2·(2^131/(2^131−1)) ≤ 14144/10000 have hcertlo := certLo_real htnn htdom - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Et := Real.exp ((t : Real) / (2 ^ 129 : Real)) with hEtdef have hEtsqrt2 := exp_t_le_sqrt2 hx hC hC0 rw [← hEtdef] at hEtsqrt2 have hNEDE_le : (evalPoly ExpCertV.numExpV t : Real) / (evalPoly ExpCertV.denExpV t : Real) ≤ @@ -742,7 +705,7 @@ theorem num_ceiling {x : Nat} (hx : x < 2 ^ 256) have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi + have hD : 1108965543718 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos -- 10000·NUMv ≤ 14145·DENv (from the real cap) @@ -762,11 +725,11 @@ theorem num_ceiling {x : Nat} (hx : x < 2 ^ 256) have hchain : 10000 * (2 ^ 637 * num) ≤ 2 ^ 637 * (14145 * den + 28290) := by have h1 : 10000 * (2 ^ 637 * num) ≤ 10000 * NUMv v t := mul_le_mul_of_nonneg_left hNUM_ge (by norm_num) - have h2 : 14145 * DENv v t ≤ 14145 * (2 ^ 637 * den + 142941343449089 * 2 ^ 590) := + have h2 : 14145 * DENv v t ≤ 14145 * (2 ^ 637 * den + 72572599271425 * 2 ^ 591) := mul_le_mul_of_nonneg_left hDEN_le (by norm_num) - have h3 : (14145 : Int) * (2 ^ 637 * den + 142941343449089 * 2 ^ 590) ≤ + have h3 : (14145 : Int) * (2 ^ 637 * den + 72572599271425 * 2 ^ 591) ≤ 2 ^ 637 * (14145 * den + 28290) := by - have hW : (14145 : Int) * (142941343449089 * 2 ^ 590) ≤ 28290 * 2 ^ 637 := by norm_num + have hW : (14145 : Int) * (72572599271425 * 2 ^ 591) ≤ 28290 * 2 ^ 637 := by norm_num nlinarith [hW] linarith [h1, hNUM_le, h2, h3] have hp : (0:Int) < 2 ^ 637 := by positivity @@ -785,11 +748,11 @@ theorem num_le_145_den {x : Nat} (hx : x < 2 ^ 256) -- 100·(10000·num) ≤ 100·(14145·den + 28290) ≤ 10000·(145·den) since 355·den ≥ 2829000 nlinarith [hceil, hden] -/-- The quotient cap: `10⁴·(r0 − scaleQ68) ≤ 4146·scaleQ68` on the nonneg half. -/ +/-- The quotient cap: `10⁴·(r0 − scaleQ67) ≤ 4146·scaleQ67` on the nonneg half. -/ theorem r0_cap {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - 10000 * (int256 (r0Tree x) - (0xde0b6b3a764000000000000000000000 : Int)) ≤ 4146 * (0xde0b6b3a764000000000000000000000 : Int) := by + 10000 * (int256 (r0Tree x) - (0x6f05b59d3b2000000000000000000000 : Int)) ≤ 4146 * (0x6f05b59d3b2000000000000000000000 : Int) := by obtain ⟨hfloor_lo, _⟩ := r0_floor_sandwich hx hC hC0 have hceil := num_ceiling hx hC hC0 htnn have hden := den_ge_194 hx hC hC0 @@ -798,111 +761,111 @@ theorem r0_cap {x : Nat} (hx : x < 2 ^ 256) set den := (evTree x : Int) - int256 (todTree x) with hdendef have hdenpos : (0:Int) < den := lt_of_lt_of_le (by norm_num) hden -- 10000·(r0−S)·den ≤ S·(10000·num − 10000·den) ≤ S·(4145·den + 28290) ≤ 4146·S·den - have h1 : 10000 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) * den ≤ (0xde0b6b3a764000000000000000000000 : Int) * (4145 * den + 28290) := by + have h1 : 10000 * (r0 - (0x6f05b59d3b2000000000000000000000 : Int)) * den ≤ (0x6f05b59d3b2000000000000000000000 : Int) * (4145 * den + 28290) := by nlinarith [hfloor_lo, hceil] - have h2 : (0xde0b6b3a764000000000000000000000 : Int) * (4145 * den + 28290) ≤ 4146 * (0xde0b6b3a764000000000000000000000 : Int) * den := by + have h2 : (0x6f05b59d3b2000000000000000000000 : Int) * (4145 * den + 28290) ≤ 4146 * (0x6f05b59d3b2000000000000000000000 : Int) * den := by nlinarith [hden] - have hchain : 10000 * (r0 - (0xde0b6b3a764000000000000000000000 : Int)) * den ≤ 4146 * (0xde0b6b3a764000000000000000000000 : Int) * den := le_trans h1 h2 + have hchain : 10000 * (r0 - (0x6f05b59d3b2000000000000000000000 : Int)) * den ≤ 4146 * (0x6f05b59d3b2000000000000000000000 : Int) * den := le_trans h1 h2 exact le_of_mul_le_mul_right hchain hdenpos /-! ## The per-point never-over (nonnegative half) -/ /-- The link-1 jitter divided by `DENv` stays inside its budget (nonneg half): -`Wev·2⁵⁹⁰·(r0 − scaleQ68)/DENv ≤ (5¹⁸/2⁴⁰)·2170557036555806152/10¹⁹`. -/ +`Wev·2⁵⁹⁰·(r0 − scaleQ67)/DENv ≤ (5¹⁸/2⁴⁰)·2170557036555806152/10¹⁹`. -/ theorem jitter_over_budget {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (142941343449089 : Real) * 2 ^ 590 * ((int256 (r0Tree x) : Real) - 0xde0b6b3a764000000000000000000000) / + (72572599271425 : Real) * 2 ^ 591 * ((int256 (r0Tree x) : Real) - 0x6f05b59d3b2000000000000000000000) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ - 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by + 3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552) := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set r0 := int256 (r0Tree x) with hr0def set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi + have hD : 1108965543718 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos - rcases le_or_gt ((r0:Real) - 0xde0b6b3a764000000000000000000000) 0 with hle0 | hgt0 - · have hnumneg : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) ≤ 0 := + rcases le_or_gt ((r0:Real) - 0x6f05b59d3b2000000000000000000000) 0 with hle0 | hgt0 + · have hnumneg : (72572599271425 : Real) * 2 ^ 591 * ((r0 : Real) - 0x6f05b59d3b2000000000000000000000) ≤ 0 := mul_nonpos_of_nonneg_of_nonpos (by positivity) hle0 - have : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) / (DENv v t : Real) ≤ 0 := + have : (72572599271425 : Real) * 2 ^ 591 * ((r0 : Real) - 0x6f05b59d3b2000000000000000000000) / (DENv v t : Real) ≤ 0 := div_nonpos_of_nonpos_of_nonneg hnumneg (le_of_lt hDR) - have hpos : (0:Real) ≤ 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by positivity + have hpos : (0:Real) ≤ 3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552) := by positivity linarith [this, hpos] · rw [div_le_iff₀ hDR] have hcap := r0_cap hx hC hC0 htnn - have hcapR : (r0 : Real) - 0xde0b6b3a764000000000000000000000 ≤ 4146 * 0xde0b6b3a764000000000000000000000 / 10000 := by + have hcapR : (r0 : Real) - 0x6f05b59d3b2000000000000000000000 ≤ 4146 * 0x6f05b59d3b2000000000000000000000 / 10000 := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hcap push_cast at h linarith [h] obtain ⟨hDEN_ge, _⟩ := DENv_runtime_bracket hx hC hC0 htnn have hden := den_ge_194 hx hC hC0 - have hDENlow : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ DENv v t := by - have : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ + have hDENlow : (2:Int) ^ 637 * (330077261860684142693791478386293573392 - 2) ≤ DENv v t := by + have : (2:Int) ^ 637 * (330077261860684142693791478386293573392 - 2) ≤ 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) - 2 * 2 ^ 637 := by nlinarith [hden] linarith [this, hDEN_ge] - have hDENlowR : ((2:Real) ^ 637 * (165038630930342071346895739193146786696 - 2)) ≤ + have hDENlowR : ((2:Real) ^ 637 * (330077261860684142693791478386293573392 - 2)) ≤ (DENv v t : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDENlow push_cast at h linarith [h] - have hnum_le : (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) ≤ - (142941343449089 : Real) * 2 ^ 590 * (4146 * 0xde0b6b3a764000000000000000000000 / 10000) := + have hnum_le : (72572599271425 : Real) * 2 ^ 591 * ((r0 : Real) - 0x6f05b59d3b2000000000000000000000) ≤ + (72572599271425 : Real) * 2 ^ 591 * (4146 * 0x6f05b59d3b2000000000000000000000 / 10000) := mul_le_mul_of_nonneg_left hcapR (by positivity) - have hbudget : (142941343449089 : Real) * 2 ^ 590 * (4146 * 0xde0b6b3a764000000000000000000000 / 10000) ≤ - (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * - ((2:Real) ^ 637 * (165038630930342071346895739193146786696 - 2)) := by + have hbudget : (72572599271425 : Real) * 2 ^ 591 * (4146 * 0x6f05b59d3b2000000000000000000000 / 10000) ≤ + (3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552)) * + ((2:Real) ^ 637 * (330077261860684142693791478386293573392 - 2)) := by norm_num - calc (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) - ≤ (142941343449089 : Real) * 2 ^ 590 * (4146 * 0xde0b6b3a764000000000000000000000 / 10000) := hnum_le - _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * - ((2:Real) ^ 637 * (165038630930342071346895739193146786696 - 2)) := hbudget - _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * + calc (72572599271425 : Real) * 2 ^ 591 * ((r0 : Real) - 0x6f05b59d3b2000000000000000000000) + ≤ (72572599271425 : Real) * 2 ^ 591 * (4146 * 0x6f05b59d3b2000000000000000000000 / 10000) := hnum_le + _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552)) * + ((2:Real) ^ 637 * (330077261860684142693791478386293573392 - 2)) := hbudget + _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552)) * (DENv v t : Real) := mul_le_mul_of_nonneg_left hDENlowR (by norm_num) /-- **The per-point never-over (nonneg half).** `r0 ≤ 2¹²⁶·exp(rt) + B` with the four-link budget -`B = 5792534503673398887/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3291…`, the `Mp` +`B = 5737291786393199862/10¹⁹`: link-1 jitter `≤ 0.6207…`, granularity `≤ 0.3291…`, the `Mp` factor `≤ √2·2¹²⁶/(2¹³²−1) ≤ 0.0442…`, and the reduced-argument gap `≤ √2/128 ≤ 0.0111…`. -/ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (int256 (r0Tree x) : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) + - 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := by + (int256 (r0Tree x) : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * Real.exp (reducedArg x) + + 3814697265625 * 5737291786393199862 / (10000000000000000000 * 2199023255552) := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] + have htdom : t ≤ (ExpCertV.H129 : Int) := by + rw [show ((ExpCertV.H129 : Nat) : Int) = 235865763225513294137944142764154484399 from by + unfold ExpCertV.H129; norm_num] exact hthi set r0 := int256 (r0Tree x) with hr0def - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi + have hD : 1108965543718 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by have : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE exact_mod_cast this - -- link 1: r0 ≤ scaleQ68·Qv + jitter - have hlink1 : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by - rcases le_or_gt r0 (0xde0b6b3a764000000000000000000000 : Int) with hsm | hbg + -- link 1: r0 ≤ scaleQ67·Qv + jitter + have hlink1 : (r0 : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + 3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552) := by + rcases le_or_gt r0 (0x6f05b59d3b2000000000000000000000 : Int) with hsm | hbg · have hi := link1_over_small hx hC hC0 htnn hsm - have hiR : (r0 : Real) * (DENv v t : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) := by + have hiR : (r0 : Real) * (DENv v t : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * (NUMv v t : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] - have hr0le : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) := by + have hr0le : (r0 : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) := by rw [mul_div_assoc', le_div_iff₀ hDR]; linarith [hiR] - have hBJnn : (0:Real) ≤ 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by positivity + have hBJnn : (0:Real) ≤ 3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552) := by positivity linarith [hr0le, hBJnn] · have hi := link1_over_tight hx hC hC0 htnn (le_of_lt hbg) - have hjointR : (r0 : Real) * (DENv v t : Real) - (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) ≤ - (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) := by + have hjointR : (r0 : Real) * (DENv v t : Real) - (0x6f05b59d3b2000000000000000000000 : Real) * (NUMv v t : Real) ≤ + (72572599271425 : Real) * 2 ^ 591 * ((r0 : Real) - 0x6f05b59d3b2000000000000000000000) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] - have hstep : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) / (DENv v t : Real) + - (142941343449089 : Real) * 2 ^ 590 * ((r0 : Real) - 0xde0b6b3a764000000000000000000000) / (DENv v t : Real) := by + have hstep : (r0 : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * (NUMv v t : Real) / (DENv v t : Real) + + (72572599271425 : Real) * 2 ^ 591 * ((r0 : Real) - 0x6f05b59d3b2000000000000000000000) / (DENv v t : Real) := by rw [div_add_div_same, le_div_iff₀ hDR]; nlinarith [hjointR, hDR] rw [mul_div_assoc] at hstep linarith [hstep, jitter_over_budget hx hC hC0 htnn] @@ -910,7 +873,7 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) obtain ⟨_, hgran⟩ := gran_over_pair hx hC hC0 htnn -- link 3: NE/DE ≤ Et·Mp; Mp excess ≤ √2·2^126/(2^131−1) have hcertlo := certLo_real htnn htdom - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Et := Real.exp ((t : Real) / (2 ^ 129 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef set Mp : Real := (2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1) with hMpdef @@ -945,20 +908,20 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) -- link 4: 2^126·(Et − Ert) ≤ √2/128 set Ert := Real.exp (reducedArg x) with hErtdef have hgapover := reducedArg_close_over hx hC hC0 - have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ - have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 110485434560398051 / 10000000000000000000 := by - have h1 : Et - Ert ≤ (1 / (32 * (2 ^ 128 : Real))) * Et := + have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 129 : Real) - reducedArg x) * Et := exp_diff_le _ _ + have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 55242717280199026 / 10000000000000000000 := by + have h1 : Et - Ert ≤ (1 / (32 * (2 ^ 129 : Real))) * Et := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapover) hEtnn) - have h2 : (2 ^ 126 : Real) * (Et - Ert) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) := + have h2 : (2 ^ 126 : Real) * (Et - Ert) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * Et) := mul_le_mul_of_nonneg_left h1 (by positivity) - have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) ≤ - (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) := + have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * Et) ≤ + (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * Real.sqrt 2) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hEtsqrt2 (by positivity)) (by positivity) - have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) ≤ - 110485434560398051 / 10000000000000000000 := by - rw [show (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Real.sqrt 2) = - Real.sqrt 2 * (2 ^ 126 / (32 * 2 ^ 128)) from by ring] - have : (2 ^ 126 : Real) / (32 * 2 ^ 128) = 1 / 128 := by norm_num + have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * Real.sqrt 2) ≤ + 55242717280199026 / 10000000000000000000 := by + rw [show (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * Real.sqrt 2) = + Real.sqrt 2 * (2 ^ 126 / (32 * 2 ^ 129)) from by ring] + have : (2 ^ 126 : Real) / (32 * 2 ^ 129) = 1 / 256 := by norm_num rw [this]; nlinarith [hsqrt2_hi, hsqrt2_nn] linarith [h2, h3, h4] -- assemble @@ -967,7 +930,7 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) have h := mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real)) nlinarith [h] have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + - 110485434560398051 / 10000000000000000000 := by + 55242717280199026 / 10000000000000000000 := by nlinarith [hcGap1] rw [hErtdef] at * linarith [hlink1, hgran, hNEMp, hcMp, hEtErt] @@ -975,13 +938,13 @@ theorem r0_real_over_tight {x : Nat} (hx : x < 2 ^ 256) /-! ## The per-point never-over (nonpositive half) -/ /-- The link-1 jitter budget on the nonpositive half: -`Wod·2⁴⁸⁰·(−t)·(r0 + scaleQ68)/DENv ≤ (5¹⁸/2⁴⁰)·2170557036555806152/10¹⁹`. -/ +`Wod·2⁴⁸⁰·(−t)·(r0 + scaleQ67)/DENv ≤ (5¹⁸/2⁴⁰)·2170557036555806152/10¹⁹`. -/ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : (269746241 : Real) * 2 ^ 480 * (-(int256 (tTree x) : Real)) * - ((int256 (r0Tree x) : Real) + 0xde0b6b3a764000000000000000000000) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ - 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by + ((int256 (r0Tree x) : Real) + 0x6f05b59d3b2000000000000000000000) / (DENv (vTree x) (int256 (tTree x)) : Real) ≤ + 3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552) := by obtain ⟨htlo, _⟩ := tTree_in_cert_domain hx hC hC0 have hr0le := r0_le_scale_neg hx hC hC0 htneg obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 @@ -990,57 +953,57 @@ theorem jitter_over_budget_neg {x : Nat} (hx : x < 2 ^ 256) set r0 := int256 (r0Tree x) with hr0def set t := int256 (tTree x) with htdef set v := vTree x with hvdef - have hev : (207573926795459379279817565122117813128 : Int) ≤ (evTree x : Int) := by - have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 from by norm_num] at this + have hev : (415147853590918758559635130244235626256 : Int) ≤ (evTree x : Int) := by + have : (0x1385291795942d41ba5fd317688e18710 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x1385291795942d41ba5fd317688e18710 : Int) = 415147853590918758559635130244235626256 from by norm_num] at this exact this - have hDEN_low : (2:Int) ^ 637 * 207573926795459379279817565122117813128 ≤ DENv v t := by - have : (2:Int) ^ 637 * 207573926795459379279817565122117813128 ≤ 2 ^ 637 * (evTree x : Int) := + have hDEN_low : (2:Int) ^ 637 * 415147853590918758559635130244235626256 ≤ DENv v t := by + have : (2:Int) ^ 637 * 415147853590918758559635130244235626256 ≤ 2 ^ 637 * (evTree x : Int) := mul_le_mul_of_nonneg_left hev (by positivity) linarith [this, hDEN_ge] have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hDEN_low have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos rw [div_le_iff₀ hDR] - -- numerator ≤ Wod·2^480·H128·2·2^126; DENv ≥ 2^637·A0 + -- numerator ≤ Wod·2^480·H129·2·2^126; DENv ≥ 2^637·A0 have hntR : (0:Real) ≤ -(t : Real) := by have : (t : Real) ≤ 0 := by exact_mod_cast htneg linarith - have hntH : -(t : Real) ≤ 117932881612756647068972071382077242199 := by + have hntH : -(t : Real) ≤ 235865763225513294137944142764154484399 := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr htlo push_cast at h linarith [h] - have hr0pR : (0:Real) ≤ (r0 : Real) + 0xde0b6b3a764000000000000000000000 := by + have hr0pR : (0:Real) ≤ (r0 : Real) + 0x6f05b59d3b2000000000000000000000 := by have h : (0:Int) ≤ r0 := by have : (0:Int) < 2 ^ 124 := by positivity linarith [hr0lo] have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr h push_cast at this linarith [this] - have hr0pH : (r0 : Real) + 0xde0b6b3a764000000000000000000000 ≤ - 2 * 0xde0b6b3a764000000000000000000000 := by + have hr0pH : (r0 : Real) + 0x6f05b59d3b2000000000000000000000 ≤ + 2 * 0x6f05b59d3b2000000000000000000000 := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le push_cast at h linarith [h] - have hnum_le : (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0xde0b6b3a764000000000000000000000) ≤ - (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * (0xde0b6b3a764000000000000000000000 : Real)) := by + have hnum_le : (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0x6f05b59d3b2000000000000000000000) ≤ + (269746241 : Real) * 2 ^ 480 * 235865763225513294137944142764154484399 * (2 * (0x6f05b59d3b2000000000000000000000 : Real)) := by have h1 : (269746241 : Real) * 2 ^ 480 * (-(t : Real)) ≤ - (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 := + (269746241 : Real) * 2 ^ 480 * 235865763225513294137944142764154484399 := mul_le_mul_of_nonneg_left hntH (by positivity) exact mul_le_mul h1 hr0pH hr0pR (by positivity) - have hDENlowR : ((2:Real) ^ 637 * 207573926795459379279817565122117813128) ≤ (DENv v t : Real) := by + have hDENlowR : ((2:Real) ^ 637 * 415147853590918758559635130244235626256) ≤ (DENv v t : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hDEN_low push_cast at h linarith [h] - have hbudget : (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * - (2 * (0xde0b6b3a764000000000000000000000 : Real)) ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * - ((2:Real) ^ 637 * 207573926795459379279817565122117813128) := by + have hbudget : (269746241 : Real) * 2 ^ 480 * 235865763225513294137944142764154484399 * + (2 * (0x6f05b59d3b2000000000000000000000 : Real)) ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552)) * + ((2:Real) ^ 637 * 415147853590918758559635130244235626256) := by norm_num - calc (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0xde0b6b3a764000000000000000000000) - ≤ (269746241 : Real) * 2 ^ 480 * 117932881612756647068972071382077242199 * (2 * (0xde0b6b3a764000000000000000000000 : Real)) := + calc (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0x6f05b59d3b2000000000000000000000) + ≤ (269746241 : Real) * 2 ^ 480 * 235865763225513294137944142764154484399 * (2 * (0x6f05b59d3b2000000000000000000000 : Real)) := hnum_le - _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * - ((2:Real) ^ 637 * 207573926795459379279817565122117813128) := hbudget - _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776)) * (DENv v t : Real) := + _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552)) * + ((2:Real) ^ 637 * 415147853590918758559635130244235626256) := hbudget + _ ≤ (3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552)) * (DENv v t : Real) := mul_le_mul_of_nonneg_left hDENlowR (by norm_num) /-- **The per-point never-over (nonpositive half).** The granularity is free here; the `Mp` factor @@ -1048,27 +1011,27 @@ and reduced-argument gap shrink (`Et ≤ 1`), so the same budget `B` covers the theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (int256 (r0Tree x) : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) + - 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := by + (int256 (r0Tree x) : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * Real.exp (reducedArg x) + + 3814697265625 * 5737291786393199862 / (10000000000000000000 * 2199023255552) := by have htdom := tdom_neg hx hC hC0 htneg have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef set r0 := int256 (r0Tree x) with hr0def - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htneg + have hD : 1108965543718 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htneg have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htneg htdom).2 have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos - -- link 1: r0 ≤ scaleQ68·Qv + jitter - have hlink1 : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - 3814697265625 * 2170557036555806152 / (10000000000000000000 * 1099511627776) := by + -- link 1: r0 ≤ scaleQ67·Qv + jitter + have hlink1 : (r0 : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + 3814697265625 * 2170557036555806152 / (10000000000000000000 * 2199023255552) := by have hi := link1_over_neg hx hC hC0 htneg - have hiR : (r0 : Real) * (DENv v t : Real) - (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) ≤ - (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0xde0b6b3a764000000000000000000000) := by + have hiR : (r0 : Real) * (DENv v t : Real) - (0x6f05b59d3b2000000000000000000000 : Real) * (NUMv v t : Real) ≤ + (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0x6f05b59d3b2000000000000000000000) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hi; push_cast at this; linarith [this] - have hstep : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * (NUMv v t : Real) / (DENv v t : Real) + - (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0xde0b6b3a764000000000000000000000) / + have hstep : (r0 : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * (NUMv v t : Real) / (DENv v t : Real) + + (269746241 : Real) * 2 ^ 480 * (-(t : Real)) * ((r0 : Real) + 0x6f05b59d3b2000000000000000000000) / (DENv v t : Real) := by rw [div_add_div_same, le_div_iff₀ hDR]; nlinarith [hiR, hDR] rw [mul_div_assoc] at hstep @@ -1077,7 +1040,7 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hgran1, _⟩ := gran_under_pair hx hC hC0 htneg -- link 3: NE/DE ≤ Et·Mpp with Et ≤ 1 have hcertlo := certLo_real_neg htneg htdom - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Et := Real.exp ((t : Real) / (2 ^ 129 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef2 set Mpp : Real := ((2 ^ 132 : Real) + 1) / (2 ^ 132 : Real) with hMppdef @@ -1110,17 +1073,17 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) -- link 4 with Et ≤ 1 set Ert := Real.exp (reducedArg x) with hErtdef have hgapover := reducedArg_close_over hx hC hC0 - have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 128 : Real) - reducedArg x) * Et := exp_diff_le _ _ - have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 110485434560398051 / 10000000000000000000 := by - have h1 : Et - Ert ≤ (1 / (32 * (2 ^ 128 : Real))) * Et := + have hExp_diff : Et - Ert ≤ ((t : Real) / (2 ^ 129 : Real) - reducedArg x) * Et := exp_diff_le _ _ + have hcGap1 : (2 ^ 126 : Real) * (Et - Ert) ≤ 55242717280199026 / 10000000000000000000 := by + have h1 : Et - Ert ≤ (1 / (32 * (2 ^ 129 : Real))) * Et := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapover) hEtnn) - have h2 : (2 ^ 126 : Real) * (Et - Ert) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) := + have h2 : (2 ^ 126 : Real) * (Et - Ert) ≤ (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * Et) := mul_le_mul_of_nonneg_left h1 (by positivity) - have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * Et) ≤ - (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * 1) := + have h3 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * Et) ≤ + (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * 1) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hEt_le_one (by positivity)) (by positivity) - have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 128 : Real))) * 1) ≤ - 110485434560398051 / 10000000000000000000 := by norm_num + have h4 : (2 ^ 126 : Real) * ((1 / (32 * (2 ^ 129 : Real))) * 1) ≤ + 55242717280199026 / 10000000000000000000 := by norm_num linarith [h2, h3, h4] -- assemble have hNEMp : (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) ≤ @@ -1128,19 +1091,19 @@ theorem r0_real_over_tight_neg {x : Nat} (hx : x < 2 ^ 256) have h := mul_le_mul_of_nonneg_left hNEDE_le (by positivity : (0:Real) ≤ (2 ^ 126 : Real)) nlinarith [h] have hEtErt : (2 ^ 126 : Real) * Et ≤ (2 ^ 126 : Real) * Ert + - 110485434560398051 / 10000000000000000000 := by nlinarith [hcGap1] + 55242717280199026 / 10000000000000000000 := by nlinarith [hcGap1] have hgranR : (2 ^ 126 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ (2 ^ 126 : Real) * ((NE : Real) / (DE : Real)) := mul_le_mul_of_nonneg_left hgran1 (by positivity) rw [hErtdef] at * linarith [hlink1, hgranR, hNEMp, hcMp, hEtErt] -/-- **Per-point never-over (tight, any sign):** `r0 ≤ scaleQ68·exp(rt) + (5¹⁸/2⁴⁰)·B` +/-- **Per-point never-over (tight, any sign):** `r0 ≤ scaleQ67·exp(rt) + (5¹⁸/2⁴⁰)·B` (the budget's image is strictly below `MARGIN = 3`). -/ theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (int256 (r0Tree x) : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) + - 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := by + (int256 (r0Tree x) : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * Real.exp (reducedArg x) + + 3814697265625 * 5737291786393199862 / (10000000000000000000 * 2199023255552) := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_over_tight hx hC hC0 htnn · exact r0_real_over_tight_neg hx hC hC0 (le_of_lt htneg) @@ -1148,9 +1111,9 @@ theorem r0_real_over_within {x : Nat} (hx : x < 2 ^ 256) /-! ## The octave real identity `E·2^(68−k) = WAD·2⁶⁸·exp(rt)` The target `E = WAD·exp(X/RAY)`. With `rt = X/RAY − k·ln2` the reduced argument, `exp(X/RAY) = -exp(rt)·2^k`, so the closing-shift fold `E·2^(68−k) = WAD·2⁶⁸·exp(rt)` (and `WAD·2⁶⁸ = scaleQ68`, +exp(rt)·2^k`, so the closing-shift fold `E·2^(68−k) = WAD·2⁶⁸·exp(rt)` (and `WAD·2⁶⁸ = scaleQ67`, the quotient's own scale). This collapses the never-over/deficit inequalities (stated against -`E·2^s`, `s = 68 − k`) onto the clean octave-independent relation `r0 ≈ scaleQ68·exp(rt)`. -/ +`E·2^s`, `s = 68 − k`) onto the clean octave-independent relation `r0 ≈ scaleQ67·exp(rt)`. -/ /-- `exp(X/RAY) = exp(rt)·2^k` (`k = int256 (kTree x)`, possibly negative; `2^k` is a real `zpow`). -/ theorem exp_X_over_RAY (x : Nat) : @@ -1164,24 +1127,24 @@ theorem exp_X_over_RAY (x : Nat) : unfold reducedArg; ring, Real.exp_add, hlog] -/-- **The octave fold of the target.** `E·2^(68−k) = WAD·2⁶⁸·exp(rt)`, with `s = 68 − k` the +/-- **The octave fold of the target.** `E·2^(67−k) = WAD·2⁶⁷·exp(rt)`, with `s = 67 − k` the closing shift. -/ -theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 68 - int256 (kTree x)) : +theorem target_octave_fold {x : Nat} (s : Nat) (hs : (s : Int) = 67 - int256 (kTree x)) : expRayToWadTarget (int256 x) * (2 ^ s : Real) = - (WAD : Real) * (2 ^ 68 : Real) * Real.exp (reducedArg x) := by + (WAD : Real) * (2 ^ 67 : Real) * Real.exp (reducedArg x) := by unfold expRayToWadTarget rw [show (RAY : Real) = (10 ^ 27 : Real) from by unfold RAY; norm_num, exp_X_over_RAY x] - -- 2^k · 2^s = 2^108 with k+s = 108 (k : Int, s : Nat). + -- 2^k · 2^s = 2^67-fold with k+s = 67 (k : Int, s : Nat). set k := int256 (kTree x) with hkdef - have hks : k + (s : Int) = 68 := by omega - have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (68 : Nat) := by + have hks : k + (s : Int) = 67 := by omega + have hpow : (2 : Real) ^ k * (2 : Real) ^ (s : Nat) = (2 : Real) ^ (67 : Nat) := by rw [show ((2 : Real) ^ (s : Nat)) = (2 : Real) ^ (s : Int) from by rw [zpow_natCast], ← zpow_add₀ (by norm_num : (2:Real) ≠ 0), hks] norm_num rw [show ((2 ^ s : Real)) = (2 : Real) ^ (s : Nat) from by norm_num] calc (WAD : Real) * (Real.exp (reducedArg x) * (2 : Real) ^ k) * (2 : Real) ^ (s : Nat) = (WAD : Real) * ((2 : Real) ^ k * (2 : Real) ^ (s : Nat)) * Real.exp (reducedArg x) := by ring - _ = (WAD : Real) * (2 ^ 68 : Real) * Real.exp (reducedArg x) := by + _ = (WAD : Real) * (2 ^ 67 : Real) * Real.exp (reducedArg x) := by rw [hpow] end diff --git a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean index a1a075caf..3b7f8c94f 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/R0ExpUnder.lean @@ -4,18 +4,18 @@ import ExpProof.Floor.R0Exp # The deficit (under) side of the per-point `r0`-vs-`exp` bridge, and the seam bound This module contains the counterpart to the never-over `r0_real_over_within`: the per-point deficit -`scaleQ68·exp(rt) ≤ r0 + 33/4` (`r0_real_under_within`), both signs, with the same four-link chain: +`scaleQ67·exp(rt) ≤ r0 + 2993/1000` (`r0_real_under_within`), both signs, with the same four-link chain: -1. link-1 deficit against the grid rational including the `div` floor, `≤ 6210/1000`; -2. the argument granularity (`Floor.GranV`) — free on the `t ≥ 0` half, `≤ (5¹⁸/2⁴⁰)·1644901622230542074/10¹⁹` +1. link-1 deficit against the grid rational including the `div` floor, `≤ 2378/1000`; +2. the argument granularity (`Floor.GranV`) — free on the `t ≥ 0` half, `≤ (5¹⁸/2⁴¹)·1644901622230542074/10¹⁹` (`Mp`-folded) on the `t ≤ 0` half; -3. the `Mp` factor, `≤ 2/25` (via `r0 ≤ 1.45·scaleQ68`); -4. the under-direction reduced-argument gap, `≤ 1267/1000` (via `exp(rt) ≤ √2·(1+ε)`). +3. the `Mp` factor, `≤ 2/25` (via `r0 ≤ 1.45·scaleQ67`); +4. the under-direction reduced-argument gap, `≤ 307/1000` (via `exp(rt) ≤ √2·(1+ε)`). -The sum `6210/1000 + 2/25 + (5¹⁸/2⁴⁰)·1644901622230542074/10¹⁹ + 1267/1000 ≤ 33/4` feeds the `k = 64` deficit -envelope `(33/4 + MARGIN)/2⁴ < 1`. The module closes with the octave-seam `r0`-doubling +The sum `2378/1000 + 2/25 + (5¹⁸/2⁴¹)·1644901622230542074/10¹⁹ + 307/1000 ≤ 2993/1000` feeds the `k = 64` deficit +envelope `(2993/1000 + MARGIN)/2² < 1`. The module closes with the octave-seam `r0`-doubling bound `r0₁ + 3 ≤ 2·r0₂` (`SeamR0Bound`), where the `1 − exp(−1/RAY)` seam slack (≈ `8.5·10¹⁰` grid -units against `r0₂ > 2¹²⁶`) dwarfs both per-point budgets and the three integer units. +units against `r0₂ > 2¹²³`) dwarfs both per-point budgets and the three integer units. -/ namespace ExpYul @@ -25,7 +25,7 @@ open FormalYul.Preservation open Common.Poly set_option maxRecDepth 100000 -set_option maxHeartbeats 1600000 +set_option maxHeartbeats 8000000 set_option exponentiation.threshold 2000 noncomputable section @@ -37,15 +37,15 @@ theorem exp_reducedArg_le_sqrt2bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : Real.exp (reducedArg x) ≤ 14143 / 10000 := by have hclose := abs_lt.mp (reducedArg_close hx hC hC0) - have hthalf : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ Real.log 2 / 2 := by + have hthalf : (int256 (tTree x) : Real) / (2 ^ 129 : Real) ≤ Real.log 2 / 2 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact t_over_2128_le_half_log2 hx hC hC0 · have htle : (int256 (tTree x) : Real) ≤ 0 := by exact_mod_cast le_of_lt htneg have hlog2 : (0:Real) ≤ Real.log 2 := Real.log_nonneg (by norm_num) - have : (int256 (tTree x) : Real) / (2 ^ 128 : Real) ≤ 0 := + have : (int256 (tTree x) : Real) / (2 ^ 129 : Real) ≤ 0 := div_nonpos_of_nonpos_of_nonneg htle (by positivity) linarith [this, hlog2] - set u : Real := 9 / (8 * (2 ^ 128 : Real)) with hu + set u : Real := 9 / (8 * (2 ^ 129 : Real)) with hu have hupos : (0:Real) < u := by rw [hu]; positivity have husmall : u ≤ 1 / 100000 := by rw [hu, div_le_div_iff₀ (by positivity) (by norm_num)]; norm_num clear_value u @@ -74,18 +74,18 @@ theorem exp_reducedArg_le_sqrt2bound {x : Nat} (hx : x < 2 ^ 256) /-! ## The `r0` bracket on the nonneg half -/ -/-- `r0` is bracketed on the nonneg half: `scaleQ68 ≤ r0` and `100·r0 ≤ 145·scaleQ68`. -/ +/-- `r0` is bracketed on the nonneg half: `scaleQ67 ≤ r0` and `100·r0 ≤ 145·scaleQ67`. -/ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (0xde0b6b3a764000000000000000000000 : Int) ≤ int256 (r0Tree x) ∧ - 100 * (int256 (r0Tree x)) ≤ 145 * (0xde0b6b3a764000000000000000000000 : Int) := by + (0x6f05b59d3b2000000000000000000000 : Int) ≤ int256 (r0Tree x) ∧ + 100 * (int256 (r0Tree x)) ≤ 145 * (0x6f05b59d3b2000000000000000000000 : Int) := by obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 have h145 := num_le_145_den hx hC hC0 htnn set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef - have hden072 : (165038630930342071346895739193146786696 : Int) ≤ ev - tod := by + have hden072 : (330077261860684142693791478386293573392 : Int) ≤ ev - tod := by have := den_ge_194 hx hC hC0; rw [← hevdef, ← htoddef] at this; exact this have hdenpos : (0:Int) < ev - tod := lt_of_lt_of_le (by norm_num) hden072 -- tod ≥ 0 on nonneg half @@ -97,40 +97,103 @@ theorem r0_bracket_nonneg {x : Nat} (hx : x < 2 ^ 256) nlinarith [htod, hpos] refine ⟨?_, ?_⟩ · -- 2^126 ≤ r0: 2^126·num < (r0+1)·den, num ≥ den ⟹ 2^126·den < (r0+1)·den ⟹ 2^126 < r0+1 - have hnumden : (0xde0b6b3a764000000000000000000000 : Int) * (ev - tod) ≤ (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) := by nlinarith [htodnn] - have h : (0xde0b6b3a764000000000000000000000 : Int) * (ev - tod) < (r0 + 1) * (ev - tod) := lt_of_le_of_lt hnumden hfloor_hi + have hnumden : (0x6f05b59d3b2000000000000000000000 : Int) * (ev - tod) ≤ (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) := by nlinarith [htodnn] + have h : (0x6f05b59d3b2000000000000000000000 : Int) * (ev - tod) < (r0 + 1) * (ev - tod) := lt_of_le_of_lt hnumden hfloor_hi have := lt_of_mul_lt_mul_right h (le_of_lt hdenpos) omega · -- 100·r0 ≤ 145·2^126: 100·r0·den ≤ 100·2^126·num ≤ 2^126·145·den - have h1 : 100 * (r0 * (ev - tod)) ≤ 100 * ((0xde0b6b3a764000000000000000000000 : Int) * (ev + tod)) := + have h1 : 100 * (r0 * (ev - tod)) ≤ 100 * ((0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod)) := mul_le_mul_of_nonneg_left hfloor_lo (by norm_num) - have h2 : (0xde0b6b3a764000000000000000000000 : Int) * (100 * (ev + tod)) ≤ (0xde0b6b3a764000000000000000000000 : Int) * (145 * (ev - tod)) := + have h2 : (0x6f05b59d3b2000000000000000000000 : Int) * (100 * (ev + tod)) ≤ (0x6f05b59d3b2000000000000000000000 : Int) * (145 * (ev - tod)) := mul_le_mul_of_nonneg_left h145 (by positivity) - have hchain : 100 * r0 * (ev - tod) ≤ 145 * (0xde0b6b3a764000000000000000000000 : Int) * (ev - tod) := by nlinarith [h1, h2] + have hchain : 100 * r0 * (ev - tod) ≤ 145 * (0x6f05b59d3b2000000000000000000000 : Int) * (ev - tod) := by nlinarith [h1, h2] exact le_of_mul_le_mul_right hchain hdenpos +/-! ## The piecewise link-1 carry table -/ + +/-- Horner evaluation of a nonnegative-coefficient polynomial is nonnegative and monotone on the +nonnegative axis. -/ +theorem evalPoly_nonneg_mono {p : List Int} (hp : ∀ c ∈ p, 0 ≤ c) : + ∀ {a b : Int}, 0 ≤ a → a ≤ b → + 0 ≤ Common.Poly.evalPoly p a ∧ Common.Poly.evalPoly p a ≤ Common.Poly.evalPoly p b := by + induction p with + | nil => intro a b _ _; simp [Common.Poly.evalPoly] + | cons c cs ih => + intro a b ha hab + have hc : 0 ≤ c := hp c List.mem_cons_self + have hcs : ∀ d ∈ cs, (0:Int) ≤ d := fun d hd => hp d (List.mem_cons_of_mem _ hd) + obtain ⟨hnn_a, hmono⟩ := ih hcs ha hab + have hb : 0 ≤ b := le_trans ha hab + refine ⟨?_, ?_⟩ + · simp only [Common.Poly.evalPoly] + have := mul_nonneg ha hnn_a + omega + · simp only [Common.Poly.evalPoly] + have h1 : a * Common.Poly.evalPoly cs a ≤ b * Common.Poly.evalPoly cs a := + mul_le_mul_of_nonneg_right hab hnn_a + have h2 : b * Common.Poly.evalPoly cs a ≤ b * Common.Poly.evalPoly cs b := + mul_le_mul_of_nonneg_left hmono hb + omega + +/-- The odd-accumulator domain cap `odNumV v ≤ odCap` (`= odVPoly` at `vmaxV + 1`): all `odVPoly` +coefficients are nonnegative, so the edge evaluation caps every grid point of the domain. -/ +def odCap : Int := 174678221397644049575777143361928794627879205226578653562590130996770143609877303657406822247010342954119346790867564782461851026886997547906404137068846862087419955814213206609572436845308432 + +theorem odNumV_le_odCap {v : Nat} (hv : (v : Int) ≤ (ExpCertV.vmaxV : Int) + 1) : + (odNumV v : Int) ≤ odCap := by + rw [odNumV_eq_poly] + have hcoeffs : ∀ c ∈ ExpCertV.odVPoly, (0:Int) ≤ c := by + unfold ExpCertV.odVPoly; intro c hc; fin_cases hc <;> positivity + have h := (evalPoly_nonneg_mono hcoeffs (Int.natCast_nonneg v) hv).2 + calc Common.Poly.evalPoly ExpCertV.odVPoly (v : Int) + ≤ Common.Poly.evalPoly ExpCertV.odVPoly ((ExpCertV.vmaxV : Int) + 1) := h + _ = odCap := by unfold ExpCertV.odVPoly ExpCertV.vmaxV odCap; norm_num [Common.Poly.evalPoly] + +/-- The per-piece link-1 carry rows over the shared `granPieces` table, at the common `×100` +integer scale. Positive half (quadratic in the `DO` floor, `r0` bounded through the runtime floor +and the odd cap): the carry fits `1378/1000` of one denominator. Negative half over `DU` with +`r0 ≤ scaleQ67`. -/ +def Link1PieceOK : Int × Int × Int × Int × Int → Prop + | (_, _, T, DO, DU) => + 1000 * ((2 ^ 637 + 269746241 * 2 ^ 480 * T) * + (200 * (0x6f05b59d3b2000000000000000000000 : Int) * (DO * 2 ^ 725) + + 200 * (0x6f05b59d3b2000000000000000000000 : Int) * T * odCap + + 800 * (0x6f05b59d3b2000000000000000000000 : Int) * 2 ^ 637)) + + 200000 * 2 ^ 637 * (DO * 2 ^ 725) ≤ + 137800 * ((DO * 2 ^ 725) * (DO * 2 ^ 725)) ∧ + 1000 * ((2 ^ 637 + 269746241 * 2 ^ 480 * T) * + (200 * (0x6f05b59d3b2000000000000000000000 : Int) * (DU * 2 ^ 725) + + 800 * (0x6f05b59d3b2000000000000000000000 : Int) * 2 ^ 637)) + + 200000 * 2 ^ 637 * (DU * 2 ^ 725) ≤ + 137800 * ((DU * 2 ^ 725) * (DU * 2 ^ 725)) + +set_option maxHeartbeats 8000000 in +set_option maxRecDepth 8000 in +theorem link1Pieces_hold : ∀ p ∈ ExpCertV.granPieces, Link1PieceOK p := by + unfold Link1PieceOK + decide +kernel + /-! ## Link 1 (under side): the grid rational vs `r0` -/ -/-- **Link-1 under (nonneg half)**: `1000·(scaleQ68·NUMv − r0·DENv) ≤ 6210·DENv`. The floor residual -costs one denominator; the odd-truncation carry `(2⁶³⁷ + Wod·2⁴⁸⁰·t)·(scaleQ68 + r0)` fits in `1.49` -denominators (`t ≤ H128`, `r0 ≤ 1.45·scaleQ68`, `den ≥ 1.94·scaleQ68`). -/ +/-- **Link-1 under (nonneg half)**: `1000·(scaleQ67·NUMv − r0·DENv) ≤ 2378·DENv`. The floor residual +costs one denominator; the odd-truncation carry `(2⁶³⁷ + Wod·2⁴⁸⁰·t)·(scaleQ67 + r0)` is aggregated +piecewise over `granPieces` (`t ≤ T` and `DO·2⁷²⁵ ≤ DENv` per piece, the certified +`Link1PieceOK` row closing the quadratic), fitting `1.378` denominators. -/ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - 1000 * ((0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - + 1000 * ((0x6f05b59d3b2000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x))) ≤ - 6210 * DENv (vTree x) (int256 (tTree x)) := by - obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 + 2378 * DENv (vTree x) (int256 (tTree x)) := by + obtain ⟨hfloor_lo, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, _, _, _⟩ := bridge_facts hx hC hC0 - obtain ⟨_, htOp_hi⟩ := tOd_bracket_nonneg hx hC hC0 htnn + obtain ⟨htOp_lo, htOp_hi⟩ := tOd_bracket_nonneg hx hC hC0 htnn obtain ⟨hr0lo, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn - obtain ⟨hDEN_ge, _⟩ := DENv_runtime_bracket hx hC hC0 htnn - obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 - have hden := den_ge_194 hx hC hC0 - have hLHS : (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - + obtain ⟨hDEN_lo, hDEN_up⟩ := DENv_runtime_bracket hx hC hC0 htnn + have hLHS : (0x6f05b59d3b2000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) ≤ 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + - (2 ^ 637 + 269746241 * 2 ^ 480 * int256 (tTree x)) * ((0xde0b6b3a764000000000000000000000 : Int) + int256 (r0Tree x)) := by + (2 ^ 637 + 269746241 * 2 ^ 480 * int256 (tTree x)) * ((0x6f05b59d3b2000000000000000000000 : Int) + int256 (r0Tree x)) := by unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef @@ -138,79 +201,123 @@ theorem link1_under_int {x : Nat} (hx : x < 2 ^ 256) set t := int256 (tTree x) with htdef set Ep := (evNumV (vTree x) : Int) with hEpdef set Op := (odNumV (vTree x) : Int) with hOpdef - have h2126r0_np : (0xde0b6b3a764000000000000000000000 : Int) - r0 ≤ 0 := by linarith [hr0lo] - have hr0p_nn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) + r0 := by linarith [hr0lo] + have h2126r0_np : (0x6f05b59d3b2000000000000000000000 : Int) - r0 ≤ 0 := by linarith [hr0lo] + have hr0p_nn : (0:Int) ≤ (0x6f05b59d3b2000000000000000000000 : Int) + r0 := by linarith [hr0lo] -- Ep·2^110·(2^126−r0) ≤ 2^637·ev·(2^126−r0) - have hterm1 : Ep * 2 ^ 110 * ((0xde0b6b3a764000000000000000000000 : Int) - r0) ≤ 2 ^ 637 * ev * ((0xde0b6b3a764000000000000000000000 : Int) - r0) := by + have hterm1 : Ep * 2 ^ 111 * ((0x6f05b59d3b2000000000000000000000 : Int) - r0) ≤ 2 ^ 637 * ev * ((0x6f05b59d3b2000000000000000000000 : Int) - r0) := by apply mul_le_mul_of_nonpos_right _ h2126r0_np nlinarith [hEp_lo] -- t·Op·(2^126+r0) ≤ (2^637·tod + 2^637 + Wod·2^480·t)·(2^126+r0) - have hterm2 : t * Op * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ - (2 ^ 637 * tod + 2 ^ 637 + 269746241 * 2 ^ 480 * t) * ((0xde0b6b3a764000000000000000000000 : Int) + r0) := + have hterm2 : t * Op * ((0x6f05b59d3b2000000000000000000000 : Int) + r0) ≤ + (2 ^ 637 * tod + 2 ^ 637 + 269746241 * 2 ^ 480 * t) * ((0x6f05b59d3b2000000000000000000000 : Int) + r0) := mul_le_mul_of_nonneg_right htOp_hi hr0p_nn -- floor: 2^126·num − r0·den < den, scaled by 2^637 - have hfloor : (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by + have hfloor : (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by linarith [hfloor_hi] - have hfloor638 : (2:Int) ^ 637 * ((0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod)) ≤ + have hfloor638 : (2:Int) ^ 637 * ((0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod)) ≤ 2 ^ 637 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) nlinarith [hterm1, hterm2, hfloor638] - -- budget the two additive pieces against DENv + -- select the covering piece; its certified facts drive the aggregation + obtain ⟨_, hvsplit⟩ := tsq_split hx hC hC0 + have hvmaxI : ((vTree x : Nat) : Int) ≤ (ExpCertV.vmaxV : Int) := by + exact_mod_cast vTree_le_vmax hx hC hC0 + obtain ⟨p, hp, hplo, hphi⟩ := + piecesCover_sound hvmaxI 0 granPieces_cover (Int.natCast_nonneg (vTree x)) + obtain ⟨vlo, vhi, T, DO, DU⟩ := p + obtain ⟨hDOpos, _, _, hTnn, hDOfl, _, _, _, _, _, _⟩ := + granPieces_ok _ hp (vTree x) hplo hphi + have hrow := (link1Pieces_hold _ hp).1 + have hcaps := granPieces_caps _ hp set r0 := int256 (r0Tree x) with hr0def set t := int256 (tTree x) with htdef set den := (evTree x : Int) - int256 (todTree x) with hdendef set D := DENv (vTree x) t with hDdef - have hA : 2 ^ 637 * den ≤ D + 2 * 2 ^ 637 := by rw [hDdef]; linarith [hDEN_ge] - have hDlow : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ D := by - have h1 : (2:Int) ^ 637 * (165038630930342071346895739193146786696 - 2) ≤ - 2 ^ 637 * den - 2 * 2 ^ 637 := by nlinarith [hden] - rw [hDdef]; linarith [h1, hDEN_ge] - have hB : 100 * ((2 ^ 637 + 269746241 * 2 ^ 480 * t) * ((0xde0b6b3a764000000000000000000000 : Int) + r0)) ≤ 520 * D := by - have hcoef : 2 ^ 637 + 269746241 * 2 ^ 480 * t ≤ - 2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199 := by - have := mul_le_mul_of_nonneg_left hthi (by positivity : (0:Int) ≤ 269746241 * 2 ^ 480) - linarith [this] - have hr0p_nn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) + r0 := by linarith [(r0_bracket_nonneg hx hC hC0 htnn).1] - have h1 : (2 ^ 637 + 269746241 * 2 ^ 480 * t) * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ - (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - ((0xde0b6b3a764000000000000000000000 : Int) + r0) := mul_le_mul_of_nonneg_right hcoef hr0p_nn - have h2 : 100 * ((2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - ((0xde0b6b3a764000000000000000000000 : Int) + r0)) ≤ - (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - (245 * (0xde0b6b3a764000000000000000000000 : Int)) := by - have hr0cap : 100 * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ 245 * (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0hi145] - nlinarith [hr0cap] - have h3 : (2 ^ 637 + 269746241 * 2 ^ 480 * 117932881612756647068972071382077242199) * - (245 * (0xde0b6b3a764000000000000000000000 : Int)) ≤ 520 * (2 ^ 637 * (165038630930342071346895739193146786696 - 2)) := by - norm_num - have h4 : (520 : Int) * (2 ^ 637 * (165038630930342071346895739193146786696 - 2)) ≤ 520 * D := - mul_le_mul_of_nonneg_left hDlow (by norm_num) - linarith [h1, h2, h3, h4] - have hC2000 : (2000 : Int) * 2 ^ 637 ≤ D := by - have : (2000 : Int) * 2 ^ 637 ≤ 2 ^ 637 * (165038630930342071346895739193146786696 - 2) := by - norm_num - linarith [this, hDlow] - linarith [hLHS, hA, hB, hC2000] + set S := (0x6f05b59d3b2000000000000000000000 : Int) with hSdef + set Op := (odNumV (vTree x) : Int) with hOpdef + have hSpos : (0 : Int) < S := by rw [hSdef]; norm_num + have hr0nn : (0 : Int) ≤ r0 := le_trans (le_of_lt hSpos) hr0lo + -- `t ≤ T` on the piece + have htT : t ≤ T := by + have hsq := tsq_lt_capsq hvsplit hphi hcaps + nlinarith [hsq, htnn, hTnn] + have hOpnn : (0 : Int) ≤ Op := by rw [hOpdef]; exact Int.natCast_nonneg _ + have hOple : Op ≤ odCap := by rw [hOpdef]; exact odNumV_le_odCap (by linarith [hvmaxI]) + -- the piece's denominator floor holds at the runtime `t` + have hDO_D : DO * 2 ^ 725 ≤ D := by + have h1 : t * Op ≤ T * Op := mul_le_mul_of_nonneg_right htT hOpnn + have h2 : DO * 2 ^ 725 ≤ (evNumV (vTree x) : Int) * 2 ^ 111 - T * Op := by + rw [hOpdef]; exact hDOfl + rw [hDdef]; unfold DENv; rw [← hOpdef]; linarith [h1, h2] + have hDOpos' : (0 : Int) < DO * 2 ^ 725 := by positivity + -- ×100 floor lift: `100·r0·D ≤ 100·S·NUMv + 145·Wev·2^591·S` + have hEp111 : 2 ^ 637 * (evTree x : Int) ≤ (evNumV (vTree x) : Int) * 2 ^ 111 := by + nlinarith [hEp_lo] + have hnumlift : 2 ^ 637 * ((evTree x : Int) + int256 (todTree x)) ≤ NUMv (vTree x) t := by + unfold NUMv; rw [← hOpdef]; linarith [hEp111, htOp_lo] + have hNUMD : NUMv (vTree x) t = D + 2 * (t * Op) := by + rw [hDdef, hOpdef]; unfold NUMv DENv; ring + have h100 : 100 * (r0 * D) ≤ 100 * (S * NUMv (vTree x) t) + 145 * (72572599271425 * 2 ^ 591) * S := by + have h1 : r0 * D ≤ 2 ^ 637 * (r0 * den) + 72572599271425 * 2 ^ 591 * r0 := by + nlinarith [hDEN_up, hr0nn] + have h2 : 2 ^ 637 * (r0 * den) ≤ 2 ^ 637 * (S * ((evTree x : Int) + int256 (todTree x))) := by + nlinarith [hfloor_lo] + have h3 : 2 ^ 637 * (S * ((evTree x : Int) + int256 (todTree x))) ≤ S * NUMv (vTree x) t := by + nlinarith [hnumlift, hSpos] + have h4 : 100 * (72572599271425 * 2 ^ 591 * r0) ≤ 145 * (72572599271425 * 2 ^ 591) * S := by + nlinarith [hr0hi145] + nlinarith [h1, h2, h3, h4] + -- transfer to the piece floor + have hK : 200 * (S * (t * Op)) + 145 * (72572599271425 * 2 ^ 591) * S ≤ + 200 * S * T * odCap + 800 * S * 2 ^ 637 := by + have htOple : t * Op ≤ T * odCap := by nlinarith [htT, hOple, htnn, hOpnn] + have hW : (145 : Int) * (72572599271425 * 2 ^ 591) ≤ 800 * 2 ^ 637 := by norm_num + nlinarith [htOple, hW, hSpos] + have htransfer : (100 * (S + r0) - 200 * S) * (DO * 2 ^ 725) ≤ + 200 * S * T * odCap + 800 * S * 2 ^ 637 := by + have hnn : (0 : Int) ≤ 100 * (S + r0) - 200 * S := by linarith [hr0lo] + have h1 : (100 * (S + r0) - 200 * S) * (DO * 2 ^ 725) ≤ (100 * (S + r0) - 200 * S) * D := + mul_le_mul_of_nonneg_left hDO_D hnn + nlinarith [h1, h100, hK, hNUMD] + have h100DO : 100 * ((S + r0) * (DO * 2 ^ 725)) ≤ + 200 * S * (DO * 2 ^ 725) + 200 * S * T * odCap + 800 * S * 2 ^ 637 := by + nlinarith [htransfer] + -- feed the certified piece row and cancel one factor of `DO·2^725` + have hcoefT_nn : (0 : Int) ≤ 2 ^ 637 + 269746241 * 2 ^ 480 * T := by nlinarith [hTnn] + have hXY : (100000 * ((2 ^ 637 + 269746241 * 2 ^ 480 * T) * (S + r0)) + 200000 * 2 ^ 637) * + (DO * 2 ^ 725) ≤ (137800 * (DO * 2 ^ 725)) * (DO * 2 ^ 725) := by + have h1 := mul_le_mul_of_nonneg_left h100DO hcoefT_nn + nlinarith [h1, hrow] + have hDIV : 100000 * ((2 ^ 637 + 269746241 * 2 ^ 480 * T) * (S + r0)) + 200000 * 2 ^ 637 ≤ + 137800 * (DO * 2 ^ 725) := + le_of_mul_le_mul_right hXY hDOpos' + -- `coef ≤ coefT`, then assemble + have hcoef_le : 100000 * ((2 ^ 637 + 269746241 * 2 ^ 480 * t) * (S + r0)) ≤ + 100000 * ((2 ^ 637 + 269746241 * 2 ^ 480 * T) * (S + r0)) := by + have hSr0 : (0 : Int) ≤ S + r0 := by linarith [hr0nn, hSpos] + nlinarith [htT, hSr0] + have hfin3 : (1378 : Int) * (DO * 2 ^ 725) ≤ 1378 * D := by linarith [hDO_D] + linarith [hLHS, hDEN_lo, hDIV, hcoef_le, hfin3] -/-- **Link-1 under (nonpositive half)**: the same `6210/1000` budget; the even-truncation width and -the `tod`-floor unit are absorbed by `DENv ≥ 2⁶³⁷·ev ≥ 2⁶³⁷·A0`. -/ +/-- **Link-1 under (nonpositive half)**: the same `2378/1000` budget, with no piece machinery: on +this half `DENv = Ep·2¹¹¹ − t·Op ≥ 2⁶³⁸·ev`, so the even-truncation width and the `tod`-floor unit +are absorbed against `2⁶³⁸·ev ≥ 2⁶³⁸·A0`. -/ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - 1000 * ((0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - + 1000 * ((0x6f05b59d3b2000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x))) ≤ - 6210 * DENv (vTree x) (int256 (tTree x)) := by + 2378 * DENv (vTree x) (int256 (tTree x)) := by obtain ⟨_, hfloor_hi⟩ := r0_floor_sandwich hx hC hC0 obtain ⟨hEp_lo, hEp_hi, _, _⟩ := bridge_facts hx hC hC0 obtain ⟨htOp_hi, _⟩ := tOd_bracket_neg hx hC hC0 htneg have hr0le := r0_le_scale_neg hx hC hC0 htneg obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 - have hDEN_ge := DENv_ge_ev_neg hx hC hC0 htneg obtain ⟨hev_lo, _⟩ := evTree_facts (vTree_eq hx hC hC0).2 - obtain ⟨htod_lo125, _⟩ := todTree_small hx hC hC0 - have hLHS : (0xde0b6b3a764000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - + obtain ⟨htod_lo126, _, _, _⟩ := todTree_bound hx hC hC0 + have hLHS : (0x6f05b59d3b2000000000000000000000 : Int) * NUMv (vTree x) (int256 (tTree x)) - int256 (r0Tree x) * DENv (vTree x) (int256 (tTree x)) ≤ 2 ^ 637 * ((evTree x : Int) - int256 (todTree x)) + - 142941343449089 * 2 ^ 590 * (0xde0b6b3a764000000000000000000000 : Int) + 2 * 2 ^ 637 * (0xde0b6b3a764000000000000000000000 : Int) := by + 72572599271425 * 2 ^ 591 * (0x6f05b59d3b2000000000000000000000 : Int) + 2 * 2 ^ 637 * (0x6f05b59d3b2000000000000000000000 : Int) := by unfold NUMv DENv set r0 := int256 (r0Tree x) with hr0def set ev := (evTree x : Int) with hevdef @@ -221,88 +328,98 @@ theorem link1_under_int_neg {x : Nat} (hx : x < 2 ^ 256) have hr0nn : (0:Int) ≤ r0 := by have : (0:Int) < 2 ^ 123 := by positivity linarith [hr0lo] - have h2126r0_nn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) - r0 := by linarith [hr0le] - have h2126r0_le : (0xde0b6b3a764000000000000000000000 : Int) - r0 ≤ (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0nn] - have hr0p_nn : (0:Int) ≤ (0xde0b6b3a764000000000000000000000 : Int) + r0 := by positivity - have hr0p_le : (0xde0b6b3a764000000000000000000000 : Int) + r0 ≤ 2 * (0xde0b6b3a764000000000000000000000 : Int) := by linarith [hr0le] + have h2126r0_nn : (0:Int) ≤ (0x6f05b59d3b2000000000000000000000 : Int) - r0 := by linarith [hr0le] + have h2126r0_le : (0x6f05b59d3b2000000000000000000000 : Int) - r0 ≤ (0x6f05b59d3b2000000000000000000000 : Int) := by linarith [hr0nn] + have hr0p_nn : (0:Int) ≤ (0x6f05b59d3b2000000000000000000000 : Int) + r0 := by positivity + have hr0p_le : (0x6f05b59d3b2000000000000000000000 : Int) + r0 ≤ 2 * (0x6f05b59d3b2000000000000000000000 : Int) := by linarith [hr0le] -- Ep·2^110·(2^126−r0) ≤ 2^637·ev·(2^126−r0) + Wev·2^590·2^126 - have hterm1 : Ep * 2 ^ 110 * ((0xde0b6b3a764000000000000000000000 : Int) - r0) ≤ - 2 ^ 637 * ev * ((0xde0b6b3a764000000000000000000000 : Int) - r0) + 142941343449089 * 2 ^ 590 * (0xde0b6b3a764000000000000000000000 : Int) := by - have h1 : Ep * 2 ^ 110 * ((0xde0b6b3a764000000000000000000000 : Int) - r0) ≤ - (2 ^ 637 * ev + 142941343449089 * 2 ^ 590) * ((0xde0b6b3a764000000000000000000000 : Int) - r0) := by + have hterm1 : Ep * 2 ^ 111 * ((0x6f05b59d3b2000000000000000000000 : Int) - r0) ≤ + 2 ^ 637 * ev * ((0x6f05b59d3b2000000000000000000000 : Int) - r0) + 72572599271425 * 2 ^ 591 * (0x6f05b59d3b2000000000000000000000 : Int) := by + have h1 : Ep * 2 ^ 111 * ((0x6f05b59d3b2000000000000000000000 : Int) - r0) ≤ + (2 ^ 637 * ev + 72572599271425 * 2 ^ 591) * ((0x6f05b59d3b2000000000000000000000 : Int) - r0) := by apply mul_le_mul_of_nonneg_right _ h2126r0_nn nlinarith [hEp_hi] - have h2 : (142941343449089 : Int) * 2 ^ 590 * ((0xde0b6b3a764000000000000000000000 : Int) - r0) ≤ - 142941343449089 * 2 ^ 590 * (0xde0b6b3a764000000000000000000000 : Int) := - mul_le_mul_of_nonneg_left h2126r0_le (by positivity) + have h2 : (72572599271425 : Int) * 2 ^ 590 * ((0x6f05b59d3b2000000000000000000000 : Int) - r0) ≤ + 72572599271425 * 2 ^ 591 * (0x6f05b59d3b2000000000000000000000 : Int) := by + linarith [h2126r0_le, hr0nn] nlinarith [h1, h2] -- t·Op·(2^126+r0) ≤ (2^637·tod + 2^637)·(2^126+r0) ≤ 2^637·tod·(2^126+r0) + 2·2^637·2^126 - have hterm2 : t * Op * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ - 2 ^ 637 * tod * ((0xde0b6b3a764000000000000000000000 : Int) + r0) + 2 * 2 ^ 637 * (0xde0b6b3a764000000000000000000000 : Int) := by - have h1 : t * Op * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ (2 ^ 637 * tod + 2 ^ 637) * ((0xde0b6b3a764000000000000000000000 : Int) + r0) := + have hterm2 : t * Op * ((0x6f05b59d3b2000000000000000000000 : Int) + r0) ≤ + 2 ^ 637 * tod * ((0x6f05b59d3b2000000000000000000000 : Int) + r0) + 2 * 2 ^ 637 * (0x6f05b59d3b2000000000000000000000 : Int) := by + have h1 : t * Op * ((0x6f05b59d3b2000000000000000000000 : Int) + r0) ≤ (2 ^ 637 * tod + 2 ^ 637) * ((0x6f05b59d3b2000000000000000000000 : Int) + r0) := mul_le_mul_of_nonneg_right htOp_hi hr0p_nn - have h2 : (2:Int) ^ 637 * ((0xde0b6b3a764000000000000000000000 : Int) + r0) ≤ 2 ^ 637 * (2 * (0xde0b6b3a764000000000000000000000 : Int)) := + have h2 : (2:Int) ^ 637 * ((0x6f05b59d3b2000000000000000000000 : Int) + r0) ≤ 2 ^ 637 * (2 * (0x6f05b59d3b2000000000000000000000 : Int)) := mul_le_mul_of_nonneg_left hr0p_le (by positivity) nlinarith [h1, h2] -- floor: 2^126·num − r0·den ≤ den, scaled - have hfloor : (0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by + have hfloor : (0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod) ≤ (ev - tod) := by linarith [hfloor_hi] - have hfloor638 : (2:Int) ^ 637 * ((0xde0b6b3a764000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod)) ≤ + have hfloor638 : (2:Int) ^ 637 * ((0x6f05b59d3b2000000000000000000000 : Int) * (ev + tod) - r0 * (ev - tod)) ≤ 2 ^ 637 * (ev - tod) := mul_le_mul_of_nonneg_left hfloor (by positivity) nlinarith [hterm1, hterm2, hfloor638] - -- budget against DENv ≥ 2^637·ev ≥ 2^637·A0; den ≤ ev + 2^125 + -- budget against DENv = Ep·2^111 − t·Op ≥ 2^638·ev ≥ 2^638·A0; den ≤ ev + 2^126 set ev := (evTree x : Int) with hevdef set tod := int256 (todTree x) with htoddef set D := DENv (vTree x) (int256 (tTree x)) with hDdef - have hev : (207573926795459379279817565122117813128 : Int) ≤ ev := by - have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ ev := by + have hev' : (415147853590918758559635130244235626256 : Int) ≤ ev := by + have : (0x1385291795942d41ba5fd317688e18710 : Int) ≤ ev := by rw [hevdef]; exact_mod_cast hev_lo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 from by norm_num] at this + rw [show (0x1385291795942d41ba5fd317688e18710 : Int) = + 415147853590918758559635130244235626256 from by norm_num] at this exact this - have hden_le : ev - tod ≤ ev + 2 ^ 125 := by - have : -(2 ^ 125 : Int) ≤ tod := htod_lo125 - linarith [this] - have hDev : 2 ^ 637 * ev ≤ D := hDEN_ge - -- 1000·(2^637·(ev + 2^125) + Wev·2^590·scaleQ68 + 2·2^637·scaleQ68) ≤ 1000·2^637·ev + 5210·2^637·A0 - have hlit : 1000 * (2 ^ 637 * 2 ^ 125 + 142941343449089 * 2 ^ 590 * (0xde0b6b3a764000000000000000000000 : Int) + - 2 * 2 ^ 637 * (0xde0b6b3a764000000000000000000000 : Int)) ≤ - (5210 : Int) * (2 ^ 637 * 207573926795459379279817565122117813128) := by + -- pair the runtime `den` against `D` through the `t·Od` bracket: one floor unit of slop + have hOpnn : (0 : Int) ≤ (odNumV (vTree x) : Int) := Int.natCast_nonneg _ + have htOp_np : int256 (tTree x) * (odNumV (vTree x) : Int) ≤ 0 := by + nlinarith [htneg, hOpnn] + have hEp111 : 2 ^ 637 * ev ≤ (evNumV (vTree x) : Int) * 2 ^ 111 := by + rw [hevdef]; nlinarith [hEp_lo] + have hDden : 2 ^ 637 * (ev - tod) ≤ D + 2 ^ 637 := by + rw [hDdef]; unfold DENv + linarith [hEp111, htOp_hi] + have hD_A : 2 ^ 637 * 415147853590918758559635130244235626256 ≤ D := by + have h1 : 2 ^ 637 * 415147853590918758559635130244235626256 ≤ 2 ^ 637 * ev := by + nlinarith [hev'] + rw [hDdef]; unfold DENv + have h2 : 2 ^ 637 * ev ≤ (evNumV (vTree x) : Int) * 2 ^ 111 - + int256 (tTree x) * (odNumV (vTree x) : Int) := by + linarith [hEp111, htOp_np] + linarith [h1, h2] + -- 1000·(2^637 + Wev·2^591·S + 2·2^637·S) ≤ 1378·2^637·A0 + have hlit : 1000 * (2 ^ 637 : Int) + + 1000 * (72572599271425 * 2 ^ 591 * (0x6f05b59d3b2000000000000000000000 : Int) + + 2 * 2 ^ 637 * (0x6f05b59d3b2000000000000000000000 : Int)) ≤ + (1378 : Int) * (2 ^ 637 * 415147853590918758559635130244235626256) := by norm_num - have hAev : (5210 : Int) * (2 ^ 637 * 207573926795459379279817565122117813128) ≤ 5210 * D := by - have h1 : (2:Int) ^ 637 * 207573926795459379279817565122117813128 ≤ 2 ^ 637 * ev := - mul_le_mul_of_nonneg_left hev (by positivity) - have := le_trans h1 hDev - nlinarith [this] - nlinarith [hLHS, hden_le, hDev, hlit, hAev] + linarith [hLHS, hDden, hD_A, hlit] /-! ## The per-point deficit (nonneg half) -/ -/-- **The per-point deficit (nonneg half).** `scaleQ68·exp(rt) ≤ r0 + 33/4`: link-1 `≤ 6210/1000`, the -`Mp` factor `≤ 2/25`, the under gap `≤ 1267/1000`; the granularity is free on this half. -/ +/-- **The per-point deficit (nonneg half).** `scaleQ67·exp(rt) ≤ r0 + 2993/1000`: link-1 `≤ 2378/1000`, the +`Mp` factor `≤ 2/25`, the under gap `≤ 307/1000`; the granularity is free on this half. -/ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htnn : 0 ≤ int256 (tTree x)) : - (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 33 / 4 := by + (0x6f05b59d3b2000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 2993 / 1000 := by obtain ⟨_, hthi⟩ := tTree_in_cert_domain hx hC hC0 have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef set r0 := int256 (r0Tree x) with hr0def - have htdom : t ≤ (ExpCertV.H128 : Int) := by - rw [show ((ExpCertV.H128 : Nat) : Int) = 117932881612756647068972071382077242199 from by - unfold ExpCertV.H128; norm_num] + have htdom : t ≤ (ExpCertV.H129 : Int) := by + rw [show ((ExpCertV.H129 : Nat) : Int) = 235865763225513294137944142764154484399 from by + unfold ExpCertV.H129; norm_num] exact hthi - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi + have hD : 1108965543718 * 2 ^ 725 ≤ DENv v t := DENv_ge_over (by omega) hthi have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDE : (1:Int) ≤ evalPoly ExpCertV.denExpV t := certDE_pos htnn htdom have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by have : (0:Int) < evalPoly ExpCertV.denExpV t := lt_of_lt_of_le one_pos hDE exact_mod_cast this - -- link 1: 2^126·Qv ≤ r0 + 6210/1000 + -- link 1: 2^126·Qv ≤ r0 + 2378/1000 have hlink1 := link1_under_int hx hC hC0 htnn - have hQv_le : (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (r0 : Real) + 6210 / 1000 := by + have hQv_le : (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (r0 : Real) + 2378 / 1000 := by rw [mul_div_assoc', div_le_iff₀ hDR] have hR := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlink1 push_cast at hR @@ -311,7 +428,7 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hgran1, _⟩ := gran_over_pair hx hC hC0 htnn -- link 3: Et ≤ (NE/DE)·Mpp ≤ Qv·Mpp; Mpp excess ≤ 2/25 via r0 ≤ 1.45·2^126 have hcertup := certUp_real htnn htdom - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Et := Real.exp ((t : Real) / (2 ^ 129 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef set Mpp : Real := ((2 ^ 132 : Real) + 1) / (2 ^ 132 : Real) with hMppdef @@ -328,80 +445,80 @@ theorem r0_real_under_tight {x : Nat} (hx : x < 2 ^ 256) le_trans hEt_le (mul_le_mul_of_nonneg_right hgran1 hMpp_nn) have hMpp1 : Mpp - 1 = 1 / (2 ^ 132 : Real) := by rw [hMppdef]; field_simp obtain ⟨_, hr0hi145⟩ := r0_bracket_nonneg hx hC hC0 htnn - have hr0R : (r0 : Real) ≤ (145 / 100) * (0xde0b6b3a764000000000000000000000 : Real) := by + have hr0R : (r0 : Real) ≤ (145 / 100) * (0x6f05b59d3b2000000000000000000000 : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0hi145 push_cast at h linarith [h] - have hEt_bound : (0xde0b6b3a764000000000000000000000 : Real) * Et ≤ (r0 : Real) + 6210 / 1000 + 2 / 25 := by - have h1 : (0xde0b6b3a764000000000000000000000 : Real) * Et ≤ - (0xde0b6b3a764000000000000000000000 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) := + have hEt_bound : (0x6f05b59d3b2000000000000000000000 : Real) * Et ≤ (r0 : Real) + 2378 / 1000 + 2 / 25 := by + have h1 : (0x6f05b59d3b2000000000000000000000 : Real) * Et ≤ + (0x6f05b59d3b2000000000000000000000 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) := mul_le_mul_of_nonneg_left hEt_le_Qv (by positivity) - have h2 : (0xde0b6b3a764000000000000000000000 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) = - (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - ((0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) := by ring - have h3 : ((0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) ≤ 2 / 25 := by + have h2 : (0x6f05b59d3b2000000000000000000000 : Real) * (((NUMv v t : Real) / (DENv v t : Real)) * Mpp) = + (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + ((0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) := by ring + have h3 : ((0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mpp - 1) ≤ 2 / 25 := by rw [hMpp1] - have hcap : (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (145 / 100) * (0xde0b6b3a764000000000000000000000 : Real) + 6210 / 1000 := by linarith [hQv_le, hr0R] + have hcap : (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (145 / 100) * (0x6f05b59d3b2000000000000000000000 : Real) + 2378 / 1000 := by linarith [hQv_le, hr0R] have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / (2 ^ 132 : Real)) - have hfin : ((145 / 100) * (0xde0b6b3a764000000000000000000000 : Real) + 6210 / 1000) * (1 / (2 ^ 132 : Real)) ≤ + have hfin : ((145 / 100) * (0x6f05b59d3b2000000000000000000000 : Real) + 2378 / 1000) * (1 / (2 ^ 132 : Real)) ≤ 2 / 25 := by norm_num linarith [this, hfin] linarith [h1, h2 ▸ h1, h3, hQv_le] - -- link 4 (under gap): 2^126·(Ert − Et) ≤ 1267/1000 + -- link 4 (under gap): 2^126·(Ert − Et) ≤ 307/1000 set Ert := Real.exp (reducedArg x) with hErtdef have hgapunder := reducedArg_close_under hx hC hC0 - have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ + have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 129 : Real)) * Ert := exp_diff_le _ _ have hErt_le := exp_reducedArg_le_sqrt2bound hx hC hC0 rw [← hErtdef] at hErt_le have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap126 : (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) ≤ 1267 / 1000 := by - have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := + have hgap126 : (0x6f05b59d3b2000000000000000000000 : Real) * (Ert - Et) ≤ 307 / 1000 := by + have hgap : Ert - Et ≤ (1025 / (1024 * (2 ^ 129 : Real))) * Ert := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) - have h1 : (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := + have h1 : (0x6f05b59d3b2000000000000000000000 : Real) * (Ert - Et) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * ((1025 / (1024 * (2 ^ 129 : Real))) * Ert) := mul_le_mul_of_nonneg_left hgap (by positivity) - have h2 : (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ - (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := + have h2 : (0x6f05b59d3b2000000000000000000000 : Real) * ((1025 / (1024 * (2 ^ 129 : Real))) * Ert) ≤ + (0x6f05b59d3b2000000000000000000000 : Real) * ((1025 / (1024 * (2 ^ 129 : Real))) * (14143 / 10000)) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le (by positivity)) (by positivity) - have h3 : (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 1267 / 1000 := by + have h3 : (0x6f05b59d3b2000000000000000000000 : Real) * ((1025 / (1024 * (2 ^ 129 : Real))) * (14143 / 10000)) ≤ 307 / 1000 := by norm_num linarith [h1, h2, h3] - have hdist : (0xde0b6b3a764000000000000000000000 : Real) * Ert = (0xde0b6b3a764000000000000000000000 : Real) * Et + (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) := by + have hdist : (0x6f05b59d3b2000000000000000000000 : Real) * Ert = (0x6f05b59d3b2000000000000000000000 : Real) * Et + (0x6f05b59d3b2000000000000000000000 : Real) * (Ert - Et) := by ring - show (0xde0b6b3a764000000000000000000000 : Real) * Ert ≤ (r0 : Real) + 33 / 4 - have hsum : (6210 : Real) / 1000 + 2 / 25 + 1267 / 1000 ≤ 33 / 4 := by norm_num + show (0x6f05b59d3b2000000000000000000000 : Real) * Ert ≤ (r0 : Real) + 2993 / 1000 + have hsum : (2378 : Real) / 1000 + 2 / 25 + 307 / 1000 ≤ 2993 / 1000 := by norm_num linarith [hEt_bound, hgap126, hdist, hsum] /-! ## The per-point deficit (nonpositive half) -/ -/-- **The per-point deficit (nonpositive half).** `scaleQ68·exp(rt) ≤ r0 + 33/4`: link-1 `≤ 6210/1000`, -the `Mp`-folded granularity `≤ (5¹⁸/2⁴⁰)·1644901622230542074/10¹⁹`, the `Mp` factor `≤ 2/25` -(via `r0 ≤ scaleQ68`), the under gap `≤ 1267/1000`. -/ +/-- **The per-point deficit (nonpositive half).** `scaleQ67·exp(rt) ≤ r0 + 2993/1000`: link-1 `≤ 2378/1000`, +the `Mp`-folded granularity `≤ (5¹⁸/2⁴¹)·1644901622230542074/10¹⁹`, the `Mp` factor `≤ 2/25` +(via `r0 ≤ scaleQ67`), the under gap `≤ 307/1000`. -/ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) (htneg : int256 (tTree x) ≤ 0) : - (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 33 / 4 := by + (0x6f05b59d3b2000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 2993 / 1000 := by have htdom := tdom_neg hx hC hC0 htneg have hvle := vTree_le_vmax hx hC hC0 set t := int256 (tTree x) with htdef set v := vTree x with hvdef set r0 := int256 (r0Tree x) with hr0def - have hD : 554482771859 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htneg + have hD : 1108965543718 * 2 ^ 725 ≤ DENv v t := DENv_ge_neg (by omega) htneg have hDpos : (0:Int) < DENv v t := lt_of_lt_of_le (by positivity) hD have hDR : (0:Real) < (DENv v t : Real) := by exact_mod_cast hDpos have hDEpos : (0:Int) < evalPoly ExpCertV.denExpV t := (certNE_pos_neg_aux htneg htdom).2 have hDER : (0:Real) < (evalPoly ExpCertV.denExpV t : Real) := by exact_mod_cast hDEpos - -- link 1: 2^126·Qv ≤ r0 + 6210/1000 + -- link 1: 2^126·Qv ≤ r0 + 2378/1000 have hlink1 := link1_under_int_neg hx hC hC0 htneg - have hQv_le : (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (r0 : Real) + 6210 / 1000 := by + have hQv_le : (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (r0 : Real) + 2378 / 1000 := by rw [mul_div_assoc', div_le_iff₀ hDR] have hR := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hlink1 push_cast at hR nlinarith [hR, hDR] -- links 2+3: Et ≤ (NE/DE)·Mp = Qv·Mp + (NE/DE − Qv)·Mp have hcertup := certUp_real_neg htneg htdom - set Et := Real.exp ((t : Real) / (2 ^ 128 : Real)) with hEtdef + set Et := Real.exp ((t : Real) / (2 ^ 129 : Real)) with hEtdef set NE := evalPoly ExpCertV.numExpV t with hNEdef set DE := evalPoly ExpCertV.denExpV t with hDEdef set Mp : Real := (2 ^ 132 : Real) / ((2 ^ 132 : Real) - 1) with hMpdef @@ -419,77 +536,98 @@ theorem r0_real_under_tight_neg {x : Nat} (hx : x < 2 ^ 256) positivity have hMp1 : Mp - 1 = 1 / ((2 ^ 132 : Real) - 1) := by rw [hMpdef]; field_simp have hr0le := r0_le_scale_neg hx hC hC0 htneg - have hr0R : (r0 : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) := by + have hr0R : (r0 : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hr0le push_cast at h linarith [h] - have hEt_bound : (0xde0b6b3a764000000000000000000000 : Real) * Et ≤ (r0 : Real) + 6210 / 1000 + 2 / 25 + - 3814697265625 * 1644901622230542074 / (10000000000000000000 * 1099511627776) := by - have h1 : (0xde0b6b3a764000000000000000000000 : Real) * Et ≤ (0xde0b6b3a764000000000000000000000 : Real) * (((NE : Real) / (DE : Real)) * Mp) := + have hEt_bound : (0x6f05b59d3b2000000000000000000000 : Real) * Et ≤ (r0 : Real) + 2378 / 1000 + 2 / 25 + + 3814697265625 * 1644901622230542074 / (10000000000000000000 * 2199023255552) := by + have h1 : (0x6f05b59d3b2000000000000000000000 : Real) * Et ≤ (0x6f05b59d3b2000000000000000000000 : Real) * (((NE : Real) / (DE : Real)) * Mp) := mul_le_mul_of_nonneg_left hEt_le (by positivity) -- split: 2^126·(NE/DE)·Mp = 2^126·Qv + 2^126·Qv·(Mp−1) + 2^126·Mp·(NE/DE − Qv) - have hsplit : (0xde0b6b3a764000000000000000000000 : Real) * (((NE : Real) / (DE : Real)) * Mp) = - (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + - ((0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) + - (0xde0b6b3a764000000000000000000000 : Real) * Mp * + have hsplit : (0x6f05b59d3b2000000000000000000000 : Real) * (((NE : Real) / (DE : Real)) * Mp) = + (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) + + ((0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) + + (0x6f05b59d3b2000000000000000000000 : Real) * Mp * ((NE : Real) / (DE : Real) - (NUMv v t : Real) / (DENv v t : Real)) := by ring - have hMpterm : ((0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) ≤ + have hMpterm : ((0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real))) * (Mp - 1) ≤ 2 / 25 := by rw [hMp1] - have hcap : (0xde0b6b3a764000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ - (0xde0b6b3a764000000000000000000000 : Real) + 6210 / 1000 := by linarith [hQv_le, hr0R] + have hcap : (0x6f05b59d3b2000000000000000000000 : Real) * ((NUMv v t : Real) / (DENv v t : Real)) ≤ + (0x6f05b59d3b2000000000000000000000 : Real) + 2378 / 1000 := by linarith [hQv_le, hr0R] have := mul_le_mul_of_nonneg_right hcap (by positivity : (0:Real) ≤ 1 / ((2 ^ 132 : Real) - 1)) - have hfin : ((0xde0b6b3a764000000000000000000000 : Real) + 6210 / 1000) * (1 / ((2 ^ 132 : Real) - 1)) ≤ 2 / 25 := by + have hfin : ((0x6f05b59d3b2000000000000000000000 : Real) + 2378 / 1000) * (1 / ((2 ^ 132 : Real) - 1)) ≤ 2 / 25 := by rw [mul_one_div, div_le_div_iff₀ (by norm_num) (by norm_num)] norm_num linarith [this, hfin] linarith [h1, hsplit ▸ h1, hMpterm, hgran2, hQv_le] - -- link 4 (under gap): 2^126·(Ert − Et) ≤ 1267/1000 + -- link 4 (under gap): 2^126·(Ert − Et) ≤ 307/1000 set Ert := Real.exp (reducedArg x) with hErtdef have hgapunder := reducedArg_close_under hx hC hC0 - have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 128 : Real)) * Ert := exp_diff_le _ _ - have hErt_le := exp_reducedArg_le_sqrt2bound hx hC hC0 - rw [← hErtdef] at hErt_le + have hExp_diff : Ert - Et ≤ (reducedArg x - (t : Real) / (2 ^ 129 : Real)) * Ert := exp_diff_le _ _ have hErt_nn : (0:Real) ≤ Ert := le_of_lt (Real.exp_pos _) - have hgap126 : (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) ≤ 1267 / 1000 := by - have hgap : Ert - Et ≤ (33 / (32 * (2 ^ 128 : Real))) * Ert := + -- on this half `rt ≤ 1025/(1024·2¹²⁹)`, so `Ert ≤ 10001/10000` + have hErt_le : Ert ≤ 10001 / 10000 := by + have htle : (t : Real) ≤ 0 := by exact_mod_cast htneg + have htdivle : (t : Real) / (2 ^ 129 : Real) ≤ 0 := + div_nonpos_of_nonpos_of_nonneg htle (by positivity) + have hrtle : reducedArg x ≤ 1025 / (1024 * (2 ^ 129 : Real)) := by + linarith [hgapunder, htdivle] + set u : Real := 1025 / (1024 * (2 ^ 129 : Real)) with hu + have hupos : (0:Real) < u := by rw [hu]; positivity + have husmall : u ≤ 1 / 100000 := by rw [hu]; norm_num + have h1u : (0:Real) < 1 - u := by rw [hu]; norm_num + have hmono : Ert ≤ Real.exp u := by + rw [hErtdef]; exact Real.exp_le_exp.mpr (by rw [hu]; exact hrtle) + clear_value u + have hexpu : Real.exp u ≤ 1 / (1 - u) := by + have h1 : (1 : Real) - u ≤ Real.exp (-u) := by linarith [Real.add_one_le_exp (-u)] + rw [Real.exp_neg] at h1 + have hep : (0:Real) < Real.exp u := Real.exp_pos u + have h2 : (1 - u) * Real.exp u ≤ 1 := by + have := mul_le_mul_of_nonneg_right h1 (le_of_lt hep) + rwa [inv_mul_cancel₀ (ne_of_gt hep)] at this + rw [le_div_iff₀ h1u]; linarith [h2] + have hfin : (1:Real) / (1 - u) ≤ 10001 / 10000 := by + rw [div_le_div_iff₀ h1u (by norm_num)]; nlinarith [husmall] + linarith [hmono, hexpu, hfin] + have hgap126 : (0x6f05b59d3b2000000000000000000000 : Real) * (Ert - Et) ≤ 218 / 1000 := by + have hgap : Ert - Et ≤ (1025 / (1024 * (2 ^ 129 : Real))) * Ert := le_trans hExp_diff (mul_le_mul_of_nonneg_right (le_of_lt hgapunder) hErt_nn) - have h1 : (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) ≤ (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) := + have h1 : (0x6f05b59d3b2000000000000000000000 : Real) * (Ert - Et) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * ((1025 / (1024 * (2 ^ 129 : Real))) * Ert) := mul_le_mul_of_nonneg_left hgap (by positivity) - have h2 : (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * Ert) ≤ - (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) := + have h2 : (0x6f05b59d3b2000000000000000000000 : Real) * ((1025 / (1024 * (2 ^ 129 : Real))) * Ert) ≤ + (0x6f05b59d3b2000000000000000000000 : Real) * ((1025 / (1024 * (2 ^ 129 : Real))) * (10001 / 10000)) := mul_le_mul_of_nonneg_left (mul_le_mul_of_nonneg_left hErt_le (by positivity)) (by positivity) - have h3 : (0xde0b6b3a764000000000000000000000 : Real) * ((33 / (32 * (2 ^ 128 : Real))) * (14143 / 10000)) ≤ 1267 / 1000 := by + have h3 : (0x6f05b59d3b2000000000000000000000 : Real) * ((1025 / (1024 * (2 ^ 129 : Real))) * (10001 / 10000)) ≤ 218 / 1000 := by norm_num linarith [h1, h2, h3] - have hdist : (0xde0b6b3a764000000000000000000000 : Real) * Ert = (0xde0b6b3a764000000000000000000000 : Real) * Et + (0xde0b6b3a764000000000000000000000 : Real) * (Ert - Et) := by + have hdist : (0x6f05b59d3b2000000000000000000000 : Real) * Ert = (0x6f05b59d3b2000000000000000000000 : Real) * Et + (0x6f05b59d3b2000000000000000000000 : Real) * (Ert - Et) := by ring - show (0xde0b6b3a764000000000000000000000 : Real) * Ert ≤ (r0 : Real) + 33 / 4 - have hsum : (6210 : Real) / 1000 + 2 / 25 + 3814697265625 * 1644901622230542074 / (10000000000000000000 * 1099511627776) + - 1267 / 1000 ≤ 33 / 4 := by norm_num + show (0x6f05b59d3b2000000000000000000000 : Real) * Ert ≤ (r0 : Real) + 2993 / 1000 + have hsum : (2378 : Real) / 1000 + 2 / 25 + 3814697265625 * 1644901622230542074 / (10000000000000000000 * 2199023255552) + + 218 / 1000 ≤ 2993 / 1000 := by norm_num linarith [hEt_bound, hgap126, hdist, hsum] -/-- **Per-point deficit (tight, any sign):** `scaleQ68·exp(rt) ≤ r0 + 33/4`. -/ +/-- **Per-point deficit (tight, any sign):** `scaleQ67·exp(rt) ≤ r0 + 2993/1000`. -/ theorem r0_real_under_within {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 33 / 4 := by + (0x6f05b59d3b2000000000000000000000 : Real) * Real.exp (reducedArg x) ≤ (int256 (r0Tree x) : Real) + 2993 / 1000 := by rcases le_or_gt 0 (int256 (tTree x)) with htnn | htneg · exact r0_real_under_tight hx hC hC0 htnn · exact r0_real_under_tight_neg hx hC hC0 (le_of_lt htneg) /-! ## The octave-seam `r0`-doubling consequence -/ -/-- `2¹²⁶ < r0Tree x` on the region (`r0 ≥ scaleQ68·exp(rt) − 33/4 > scaleQ68/2 − 33/4 > 2¹²⁶`). -/ +/-- `2¹²³ < r0Tree x` on the region, directly from the runtime quotient range. -/ theorem r0Tree_gt_2126 {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 : Real) ^ 126 < (int256 (r0Tree x) : Real) := by - have hu := r0_real_under_within hx hC hC0 - have hh := exp_reducedArg_gt_half hx hC hC0 - have h1 : (0xde0b6b3a764000000000000000000000 : Real) * (1 / 2) < (0xde0b6b3a764000000000000000000000 : Real) * Real.exp (reducedArg x) := - mul_lt_mul_of_pos_left hh (by positivity) - have h2 : (2 : Real) ^ 126 + (33 / 4 : Real) < (0xde0b6b3a764000000000000000000000 : Real) * (1 / 2) := by norm_num - linarith [hu, h1, h2] + (2 : Real) ^ 123 < (int256 (r0Tree x) : Real) := by + obtain ⟨hr0lo, _⟩ := r0Tree_bounds hx hC hC0 + have h : ((2 ^ 124 : Int) : Real) ≤ (int256 (r0Tree x) : Real) := by exact_mod_cast hr0lo + have h2 : (2 : Real) ^ 123 < ((2 ^ 124 : Int) : Real) := by norm_num + linarith [h, h2] /-- **The seam exp relation.** Across a seam (`X2 = X1 + 1`, `k2 = k1 + 1`), `exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`. -/ @@ -507,7 +645,7 @@ theorem reducedArg_seam {x1 x2 : Nat} ring /-- **`r0` at most doubles across a seam, three units short** (the real reduction of -`SeamR0Bound`). The strict slack from `exp(−1/RAY) < 1` (against `r0Tree x2 > 2¹²⁶`, worth +`SeamR0Bound`). The strict slack from `exp(−1/RAY) < 1` (against `r0Tree x2 > 2¹²³`, worth `≈ 8.5·10¹⁰` grid units) dwarfs the per-point envelopes and the three integer units the seam-floor comparison consumes. -/ theorem r0_seam_double {x1 x2 : Nat} @@ -537,42 +675,42 @@ theorem r0_seam_double {x1 x2 : Nat} have h1z : (1 - 1 / (2 * (10 ^ 27 : Real))) * (1 + 1 / (10 ^ 27 : Real)) ≥ 1 := by rw [ge_iff_le]; nlinarith [sq_nonneg (1 / (10 ^ 27 : Real))] nlinarith [hez, h1z, hexppos, mul_pos (by positivity : (0:Real) < 1 - 1/(2*(10^27:Real))) hexppos] - -- scaleQ68·E1 = 2·(scaleQ68·E2)·y ≤ 2·(r0_2 + U)·y - have hE2bound : (0xde0b6b3a764000000000000000000000 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + (33 / 4 : Real) := + -- scaleQ67·E1 = 2·(scaleQ67·E2)·y ≤ 2·(r0_2 + U)·y + have hE2bound : (0x6f05b59d3b2000000000000000000000 : Real) * E2 ≤ (int256 (r0Tree x2) : Real) + (2993 / 1000 : Real) := hunder2 have hr0_1 : (int256 (r0Tree x1) : Real) ≤ - 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * y + - 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := by - have h1 : (0xde0b6b3a764000000000000000000000 : Real) * E1 = 2 * ((0xde0b6b3a764000000000000000000000 : Real) * E2) * y := by + 2 * ((int256 (r0Tree x2) : Real) + (2993 / 1000 : Real)) * y + + 3814697265625 * 5737291786393199862 / (10000000000000000000 * 2199023255552) := by + have h1 : (0x6f05b59d3b2000000000000000000000 : Real) * E1 = 2 * ((0x6f05b59d3b2000000000000000000000 : Real) * E2) * y := by rw [hseam]; ring - have h2 : (int256 (r0Tree x1) : Real) ≤ (0xde0b6b3a764000000000000000000000 : Real) * E1 + - 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) := hover1 + have h2 : (int256 (r0Tree x1) : Real) ≤ (0x6f05b59d3b2000000000000000000000 : Real) * E1 + + 3814697265625 * 5737291786393199862 / (10000000000000000000 * 2199023255552) := hover1 rw [h1] at h2 - have h3 : 2 * ((0xde0b6b3a764000000000000000000000 : Real) * E2) * y ≤ - 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * y := + have h3 : 2 * ((0x6f05b59d3b2000000000000000000000 : Real) * E2) * y ≤ + 2 * ((int256 (r0Tree x2) : Real) + (2993 / 1000 : Real)) * y := mul_le_mul_of_nonneg_right (by linarith [mul_le_mul_of_nonneg_left hE2bound (by norm_num : (0:Real) ≤ 2)]) (le_of_lt hy_pos) linarith [h2, h3] have hr0_2nn : (0:Real) ≤ (int256 (r0Tree x2) : Real) := by linarith [hr0_2_big, (by positivity : (0:Real) ≤ (2:Real)^126)] - have hkey : 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * y + - 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) + 3 < 2 * (int256 (r0Tree x2) : Real) := by + have hkey : 2 * ((int256 (r0Tree x2) : Real) + (2993 / 1000 : Real)) * y + + 3814697265625 * 5737291786393199862 / (10000000000000000000 * 2199023255552) + 3 < 2 * (int256 (r0Tree x2) : Real) := by -- the seam gap is dominated by `(r0 + U) / RAY`; the quotient exceeds `8.5·10¹⁰` here - have hyb : 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * y ≤ - 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * (1 - 1 / (2 * (10 ^ 27 : Real))) := by + have hyb : 2 * ((int256 (r0Tree x2) : Real) + (2993 / 1000 : Real)) * y ≤ + 2 * ((int256 (r0Tree x2) : Real) + (2993 / 1000 : Real)) * (1 - 1 / (2 * (10 ^ 27 : Real))) := by apply mul_le_mul_of_nonneg_left hy_bound linarith [hr0_2nn] - have hexpand : 2 * ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) * + have hexpand : 2 * ((int256 (r0Tree x2) : Real) + (2993 / 1000 : Real)) * (1 - 1 / (2 * (10 ^ 27 : Real))) = - 2 * (int256 (r0Tree x2) : Real) + 2 * (33 / 4 : Real) - - ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) / (10 ^ 27 : Real) := by + 2 * (int256 (r0Tree x2) : Real) + 2 * (2993 / 1000 : Real) - + ((int256 (r0Tree x2) : Real) + (2993 / 1000 : Real)) / (10 ^ 27 : Real) := by field_simp ring - have hbig : ((int256 (r0Tree x2) : Real) + (33 / 4 : Real)) / (10 ^ 27 : Real) > 30 := by + have hbig : ((int256 (r0Tree x2) : Real) + (2993 / 1000 : Real)) / (10 ^ 27 : Real) > 30 := by rw [gt_iff_lt, lt_div_iff₀ (by positivity)] nlinarith [hr0_2_big, (by norm_num : (30:Real) * 10 ^ 27 + 1 < 2 ^ 126)] - have hUB : 2 * (33 / 4 : Real) + 3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) + 3 < 30 := by norm_num + have hUB : 2 * (2993 / 1000 : Real) + 3814697265625 * 5737291786393199862 / (10000000000000000000 * 2199023255552) + 3 < 30 := by norm_num linarith [hyb, hexpand ▸ hyb, hbig, hUB] have hreal : (int256 (r0Tree x1) : Real) + 3 ≤ 2 * (int256 (r0Tree x2) : Real) := by linarith [hr0_1, hkey] diff --git a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean index c417555df..5a30994f3 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Reduce.lean @@ -7,21 +7,21 @@ import ExpProof.Spec.RealExp The runtime forms the reduced argument `t = tTree x` (Q128) and octave index `k = kTree x` so that `exp(x/RAY) = 2^k · exp(rt)` with `rt = X/RAY − k·ln2` (`X = int256 x`). To fold the cert's -`exp(t/2¹²⁸)` bound onto the target, the reduced argument `rt` must coincide with `t/2¹²⁸` up to a +`exp(t/2¹²⁹)` bound onto the target, the reduced argument `rt` must coincide with `t/2¹²⁹` up to a margin the runtime `MARGIN` absorbs: ``` -|rt − t/2¹²⁸| < 2 / 2¹²⁸. +|rt − t/2¹²⁹| < 2 / 2¹²⁹. ``` -Decompose `rt − t/2¹²⁸ = P1 + P2 + P3`: +Decompose `rt − t/2¹²⁹ = P1 + P2 + P3`: * `P1 = X·(1/RAY − K27/2²³⁵)` — the rational coefficient error over `|X| < 2⁹⁶`, below `2⁻¹³³`; * `P2 = k·(LN2/2²³⁵ − ln2)` — the `ln2`-grid error (`0 ≤ ln2 − LN2/2²³⁵ < 2⁻²³⁵`, from `Ln2Bound`) - over `|k| ≤ 64`, below `2⁻²²⁹`; -* `P3 = (K27·X − LN2·k)/2²³⁵ − t/2¹²⁸ ∈ [0, 1/2¹²⁸)` — the integer `t`-rounding sandwich. + over `|k| ≤ 65`, below `2⁻²²⁸`; +* `P3 = (K27·X − LN2·k)/2²³⁵ − t/2¹²⁹ ∈ [0, 1/2¹²⁹)` — the integer `t`-rounding sandwich. -The sum is below `2/2¹²⁸`. +The sum is below `2/2¹²⁹`. -/ namespace ExpYul @@ -41,11 +41,11 @@ def reducedArg (x : Nat) : Real := /-- **Reduced-argument tight over bound (gap-1, one-sided).** On the meaningful region the integer `t`-rounding residual `P3 ≥ 0` makes the over direction strictly tighter than the symmetric bound: -`t/2¹²⁸ − rt < 1/(32·2¹²⁸)` (the `ln2`-grid and rational errors alone, since `P3 ≥ 0` only helps). +`t/2¹²⁹ − rt < 1/(32·2¹²⁹)` (the `ln2`-grid and rational errors alone, since `P3 ≥ 0` only helps). This is the gap-1 contribution the joint never-over budget consumes. -/ theorem reducedArg_close_over {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (int256 (tTree x) : Real) / (2 ^ 128 : Real) - reducedArg x < 1 / (32 * (2 ^ 128 : Real)) := by + (int256 (tTree x) : Real) / (2 ^ 129 : Real) - reducedArg x < 1 / (32 * (2 ^ 129 : Real)) := by obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 @@ -70,14 +70,14 @@ theorem reducedArg_close_over {x : Nat} (hx : x < 2 ^ 256) set tR : Real := (t : Real) with htRdef -- numeric Real names set N235 : Real := (2 ^ 235 : Real) with hN235 - set N128 : Real := (2 ^ 128 : Real) with hN128 + set N128 : Real := (2 ^ 129 : Real) with hN128 set LN2R : Real := (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) with hLN2R set K27R : Real := (55213970774324510299478046898216203619608872 : Real) with hK27R have hp235 : (0 : Real) < N235 := by rw [hN235]; positivity have hp128 : (0 : Real) < N128 := by rw [hN128]; positivity have hpRAY : (0 : Real) < (10 ^ 27 : Real) := by positivity -- 2^235 = 2^128 · 2^107 - have hsplit : N235 = N128 * 2 ^ 107 := by rw [hN235, hN128, ← pow_add] + have hsplit : N235 = N128 * 2 ^ 106 := by rw [hN235, hN128, ← pow_add] -- the three pieces set P1 : Real := XR * (1 / (10 ^ 27 : Real) - K27R / N235) with hP1def set P2 : Real := kR * (LN2R / N235 - LR) with hP2def @@ -123,40 +123,40 @@ theorem reducedArg_close_over {x : Nat} (hx : x < 2 ^ 256) have hP2_hi : -(1 / N235) ≤ LN2R / N235 - LR := by have : LR ≤ (LN2R + 1) / N235 := hln2hi rw [add_div] at this; linarith [this] - -- |k| ≤ 64 ⇒ |P2| ≤ 64/N235 < 1/N128 + -- |k| ≤ 65 ⇒ |P2| ≤ 65/N235 < 1/N128 have hkloR : -(61 : Real) ≤ kR := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] - have hkhiR : kR ≤ (64 : Real) := by + have hkhiR : kR ≤ (65 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] have hP2_abs : |P2| < 1 / (64 * N128) := by rw [hP2def] - have h1 : |kR| ≤ 64 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h1 : |kR| ≤ 65 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by rw [abs_le] refine ⟨by linarith [hP2_hi], ?_⟩ have hpos : (0:Real) ≤ 1 / N235 := by positivity linarith [hP2_lo, hpos] - have hbound : |kR * (LN2R / N235 - LR)| ≤ 64 * (1 / N235) := by + have hbound : |kR * (LN2R / N235 - LR)| ≤ 65 * (1 / N235) := by rw [abs_mul] exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) - have hlt : 64 * (1 / N235) < 1 / (64 * N128) := by + have hlt : 65 * (1 / N235) < 1 / (64 * N128) := by rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num linarith [hbound, hlt] -- bound P3 ∈ [0, 1/N128) from the integer sandwich have hP3int_lo : (0 : Int) ≤ 55213970774324510299478046898216203619608872 * X - - 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t := by omega + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 106 * t := by omega have hP3int_hi : 55213970774324510299478046898216203619608872 * X - - 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t < 2 ^ 107 := by omega + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 106 * t < 2 ^ 106 := by omega -- P3 = (A − 2^107·t)/N235, with the numerator (a Real cast of an Int) in [0, 2^107) - have hnumR_lo : (0 : Real) ≤ K27R * XR - LN2R * kR - 2 ^ 107 * tR := by + have hnumR_lo : (0 : Real) ≤ K27R * XR - LN2R * kR - 2 ^ 106 * tR := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hP3int_lo rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] push_cast at h; linarith [h] - have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 107 * tR < 2 ^ 107 := by + have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 106 * tR < 2 ^ 106 := by have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hP3int_hi rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] push_cast at h; linarith [h] - have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 107 * tR) / N235 := by + have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 106 * tR) / N235 := by rw [hP3def, hsplit]; field_simp; ring have hP3_lo : 0 ≤ P3 := by rw [hP3eq]; exact div_nonneg hnumR_lo (le_of_lt hp235) have hP3_hi : P3 < 1 / N128 := by @@ -179,12 +179,12 @@ theorem reducedArg_close_over {x : Nat} (hx : x < 2 ^ 256) linarith [h12lo, hP3_lo] /-- **Reduced-argument tight under bound (gap-1, one-sided).** The deficit direction: the integer -`t`-rounding residual `P3 ∈ [0, 1/2¹²⁸)` and the `ln2`-grid/rational errors `P1 + P2 < 1/(32·2¹²⁸)` -give `rt − t/2¹²⁸ < 33/(32·2¹²⁸)`. This is the gap-1 contribution the joint deficit budget -consumes (tighter than the symmetric `9/(8·2¹²⁸) = 36/(32·2¹²⁸)`). -/ +`t`-rounding residual `P3 ∈ [0, 1/2¹²⁹)` and the `ln2`-grid/rational errors `P1 + P2 < +1/(1024·2¹²⁹)` give `rt − t/2¹²⁹ < 1025/(1024·2¹²⁹)`. This is the gap-1 contribution the joint +deficit budget consumes (far tighter than the symmetric `9/(8·2¹²⁹)`). -/ theorem reducedArg_close_under {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - reducedArg x - (int256 (tTree x) : Real) / (2 ^ 128 : Real) < 33 / (32 * (2 ^ 128 : Real)) := by + reducedArg x - (int256 (tTree x) : Real) / (2 ^ 129 : Real) < 1025 / (1024 * (2 ^ 129 : Real)) := by obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 @@ -206,13 +206,13 @@ theorem reducedArg_close_under {x : Nat} (hx : x < 2 ^ 256) set kR : Real := (k : Real) with hkRdef set tR : Real := (t : Real) with htRdef set N235 : Real := (2 ^ 235 : Real) with hN235 - set N128 : Real := (2 ^ 128 : Real) with hN128 + set N128 : Real := (2 ^ 129 : Real) with hN128 set LN2R : Real := (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) with hLN2R set K27R : Real := (55213970774324510299478046898216203619608872 : Real) with hK27R have hp235 : (0 : Real) < N235 := by rw [hN235]; positivity have hp128 : (0 : Real) < N128 := by rw [hN128]; positivity have hpRAY : (0 : Real) < (10 ^ 27 : Real) := by positivity - have hsplit : N235 = N128 * 2 ^ 107 := by rw [hN235, hN128, ← pow_add] + have hsplit : N235 = N128 * 2 ^ 106 := by rw [hN235, hN128, ← pow_add] set P1 : Real := XR * (1 / (10 ^ 27 : Real) - K27R / N235) with hP1def set P2 : Real := kR * (LN2R / N235 - LR) with hP2def set P3 : Real := (K27R * XR - LN2R * kR) / N235 - tR / N128 with hP3def @@ -231,7 +231,7 @@ theorem reducedArg_close_under {x : Nat} (hx : x < 2 ^ 256) rw [hK27R, hN235]; field_simp; ring have hcoeff_num : K27R * (10 ^ 27 : Real) - N235 = 222636907558699806209605632 := by rw [hK27R, hN235]; norm_num - have hP1_abs : |P1| < 1 / (64 * N128) := by + have hP1_abs : |P1| < 1 / (2048 * N128) := by rw [hP1def, hcoeff_eq, hcoeff_num, abs_mul] have hden_pos : (0 : Real) < N235 * (10 ^ 27 : Real) := by positivity have hco_abs : |(-(222636907558699806209605632 / (N235 * (10 ^ 27 : Real))))| = @@ -245,7 +245,7 @@ theorem reducedArg_close_under {x : Nat} (hx : x < 2 ^ 256) (mul_lt_mul_right hco_pos).mpr hX_abs _ = 79228162514264337593543950336 * 222636907558699806209605632 / (N235 * (10 ^ 27 : Real)) := by rw [mul_div_assoc] - _ < 1 / (64 * N128) := by + _ < 1 / (2048 * N128) := by rw [hN235, hN128, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num have hP2_lo : LN2R / N235 - LR ≤ 0 := by linarith [hln2lo] have hP2_hi : -(1 / N235) ≤ LN2R / N235 - LR := by @@ -253,58 +253,58 @@ theorem reducedArg_close_under {x : Nat} (hx : x < 2 ^ 256) rw [add_div] at this; linarith [this] have hkloR : -(61 : Real) ≤ kR := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] - have hkhiR : kR ≤ (64 : Real) := by + have hkhiR : kR ≤ (65 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] - have hP2_abs : |P2| < 1 / (64 * N128) := by + have hP2_abs : |P2| < 1 / (2048 * N128) := by rw [hP2def] - have h1 : |kR| ≤ 64 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h1 : |kR| ≤ 65 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by rw [abs_le] refine ⟨by linarith [hP2_hi], ?_⟩ have hpos : (0:Real) ≤ 1 / N235 := by positivity linarith [hP2_lo, hpos] - have hbound : |kR * (LN2R / N235 - LR)| ≤ 64 * (1 / N235) := by + have hbound : |kR * (LN2R / N235 - LR)| ≤ 65 * (1 / N235) := by rw [abs_mul] exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) - have hlt : 64 * (1 / N235) < 1 / (64 * N128) := by + have hlt : 65 * (1 / N235) < 1 / (2048 * N128) := by rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num linarith [hbound, hlt] have hP3int_hi : 55213970774324510299478046898216203619608872 * X - - 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t < 2 ^ 107 := by omega - have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 107 * tR < 2 ^ 107 := by + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 106 * t < 2 ^ 106 := by omega + have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 106 * tR < 2 ^ 106 := by have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hP3int_hi rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] push_cast at h; linarith [h] - have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 107 * tR) / N235 := by + have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 106 * tR) / N235 := by rw [hP3def, hsplit]; field_simp; ring have hP3_hi : P3 < 1 / N128 := by rw [hP3eq, hsplit, div_lt_div_iff₀ (by positivity) (by positivity)] nlinarith [hnumR_hi, hp128] - -- assemble: rt − t/2^128 = P1+P2+P3 < 1/(32 N128) + 1/N128 = 33/(32 N128) + -- assemble: rt − t/2^129 = P1+P2+P3 < 1/(1024 N128) + 1/N128 = 1025/(1024 N128) have hP1 := abs_lt.mp hP1_abs have hP2 := abs_lt.mp hP2_abs clear_value N128 N235 - have he12 : (1 : Real) / (64 * N128) + 1 / (64 * N128) = 1 / (32 * N128) := by + have he12 : (1 : Real) / (2048 * N128) + 1 / (2048 * N128) = 1 / (1024 * N128) := by field_simp; ring - have h1_32N : (1 : Real) / (32 * N128) + 1 / N128 = 33 / (32 * N128) := by + have h1_1024N : (1 : Real) / (1024 * N128) + 1 / N128 = 1025 / (1024 * N128) := by field_simp; ring have hredeq : reducedArg x = XR / (10 ^ 27 : Real) - kR * LR := rfl have hident' : (reducedArg x - tR / N128) = P1 + P2 + P3 := by rw [hredeq]; linarith [hident] rw [hident'] - have h12 : P1 + P2 < 1 / (32 * N128) := by rw [← he12]; linarith [hP1.2, hP2.2] - rw [← h1_32N]; linarith [h12, hP3_hi] + have h12 : P1 + P2 < 1 / (1024 * N128) := by rw [← he12]; linarith [hP1.2, hP2.2] + rw [← h1_1024N]; linarith [h12, hP3_hi] /-- info: 'ExpYul.reducedArg_close_under' depends on axioms: [propext, Classical.choice, Quot.sound] -/ #guard_msgs in #print axioms reducedArg_close_under /-- **Reduced-argument real bound (gap-1).** On the meaningful region the reduced argument `rt` -agrees with `t/2¹²⁸` to within `9/(8·2¹²⁸)` (the integer `t`-rounding sandwich `[0, 1/2¹²⁸)` +agrees with `t/2¹²⁹` to within `9/(8·2¹²⁹)` (the integer `t`-rounding sandwich `[0, 1/2¹²⁹)` dominates; the rational and `ln2`-grid errors are below `2⁻¹³²`). -/ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - |reducedArg x - (int256 (tTree x) : Real) / (2 ^ 128 : Real)| < 9 / (8 * (2 ^ 128 : Real)) := by + |reducedArg x - (int256 (tTree x) : Real) / (2 ^ 129 : Real)| < 9 / (8 * (2 ^ 129 : Real)) := by obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 @@ -329,14 +329,14 @@ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) set tR : Real := (t : Real) with htRdef -- numeric Real names set N235 : Real := (2 ^ 235 : Real) with hN235 - set N128 : Real := (2 ^ 128 : Real) with hN128 + set N128 : Real := (2 ^ 129 : Real) with hN128 set LN2R : Real := (38271408169742254668347313025622401492114385419650052359639581444463709 : Real) with hLN2R set K27R : Real := (55213970774324510299478046898216203619608872 : Real) with hK27R have hp235 : (0 : Real) < N235 := by rw [hN235]; positivity have hp128 : (0 : Real) < N128 := by rw [hN128]; positivity have hpRAY : (0 : Real) < (10 ^ 27 : Real) := by positivity -- 2^235 = 2^128 · 2^107 - have hsplit : N235 = N128 * 2 ^ 107 := by rw [hN235, hN128, ← pow_add] + have hsplit : N235 = N128 * 2 ^ 106 := by rw [hN235, hN128, ← pow_add] -- the three pieces set P1 : Real := XR * (1 / (10 ^ 27 : Real) - K27R / N235) with hP1def set P2 : Real := kR * (LN2R / N235 - LR) with hP2def @@ -382,40 +382,40 @@ theorem reducedArg_close {x : Nat} (hx : x < 2 ^ 256) have hP2_hi : -(1 / N235) ≤ LN2R / N235 - LR := by have : LR ≤ (LN2R + 1) / N235 := hln2hi rw [add_div] at this; linarith [this] - -- |k| ≤ 64 ⇒ |P2| ≤ 64/N235 < 1/N128 + -- |k| ≤ 65 ⇒ |P2| ≤ 65/N235 < 1/N128 have hkloR : -(61 : Real) ≤ kR := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hklo; rw [hkRdef]; push_cast at this; linarith [this] - have hkhiR : kR ≤ (64 : Real) := by + have hkhiR : kR ≤ (65 : Real) := by have := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hkhi; rw [hkRdef]; push_cast at this; linarith [this] have hP2_abs : |P2| < 1 / (64 * N128) := by rw [hP2def] - have h1 : |kR| ≤ 64 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ + have h1 : |kR| ≤ 65 := abs_le.mpr ⟨by linarith [hkloR], hkhiR⟩ have h2 : |LN2R / N235 - LR| ≤ 1 / N235 := by rw [abs_le] refine ⟨by linarith [hP2_hi], ?_⟩ have hpos : (0:Real) ≤ 1 / N235 := by positivity linarith [hP2_lo, hpos] - have hbound : |kR * (LN2R / N235 - LR)| ≤ 64 * (1 / N235) := by + have hbound : |kR * (LN2R / N235 - LR)| ≤ 65 * (1 / N235) := by rw [abs_mul] exact mul_le_mul h1 h2 (abs_nonneg _) (by norm_num) - have hlt : 64 * (1 / N235) < 1 / (64 * N128) := by + have hlt : 65 * (1 / N235) < 1 / (64 * N128) := by rw [hN235, hN128, mul_one_div, div_lt_div_iff₀ (by positivity) (by positivity)]; norm_num linarith [hbound, hlt] -- bound P3 ∈ [0, 1/N128) from the integer sandwich have hP3int_lo : (0 : Int) ≤ 55213970774324510299478046898216203619608872 * X - - 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t := by omega + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 106 * t := by omega have hP3int_hi : 55213970774324510299478046898216203619608872 * X - - 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 107 * t < 2 ^ 107 := by omega + 38271408169742254668347313025622401492114385419650052359639581444463709 * k - 2 ^ 106 * t < 2 ^ 106 := by omega -- P3 = (A − 2^107·t)/N235, with the numerator (a Real cast of an Int) in [0, 2^107) - have hnumR_lo : (0 : Real) ≤ K27R * XR - LN2R * kR - 2 ^ 107 * tR := by + have hnumR_lo : (0 : Real) ≤ K27R * XR - LN2R * kR - 2 ^ 106 * tR := by have h := (@Int.cast_le Real _ _ _ _ _ _ _).mpr hP3int_lo rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] push_cast at h; linarith [h] - have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 107 * tR < 2 ^ 107 := by + have hnumR_hi : K27R * XR - LN2R * kR - 2 ^ 106 * tR < 2 ^ 106 := by have h := (@Int.cast_lt Real _ _ _ _ _ _ _).mpr hP3int_hi rw [hK27R, hLN2R, hXRdef, hkRdef, htRdef] push_cast at h; linarith [h] - have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 107 * tR) / N235 := by + have hP3eq : P3 = (K27R * XR - LN2R * kR - 2 ^ 106 * tR) / N235 := by rw [hP3def, hsplit]; field_simp; ring have hP3_lo : 0 ≤ P3 := by rw [hP3eq]; exact div_nonneg hnumR_lo (le_of_lt hp235) have hP3_hi : P3 < 1 / N128 := by diff --git a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean index b322d33d3..c9ffb796e 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/RoundTrip.lean @@ -39,7 +39,7 @@ envelope's image on the output grid, `MARGIN = 3` exceeds it strictly — the sl strictness to rule out `accumReal x = w` exactly. -/ /-- **Strict never-over.** On the region the real pre-floor accumulator is strictly below the -target. The proven over bound `r0 ≤ scaleQ68·exp(rt) + (5¹⁸/2⁴⁰)·B` plus `(5¹⁸/2⁴⁰)·B < MARGIN` +target. The proven over bound `r0 ≤ scaleQ67·exp(rt) + (5¹⁸/2⁴⁰)·B` plus `(5¹⁸/2⁴⁰)·B < MARGIN` give a strictly negative residue. -/ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : @@ -49,45 +49,45 @@ theorem accumReal_over_strict (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < have hfold := target_octave_fold s hsint have hover := r0_real_over_within hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - -- r0 − MARGIN < scaleQ68·Ert = E·2^s, using (5¹⁸/2⁴⁰)·B < MARGIN - have hbound : (int256 (r0Tree x) : Real) - 3 < + -- r0 − MARGIN < scaleQ67·Ert = E·2^s, using (5¹⁸/2⁴⁰)·B < MARGIN + have hbound : (int256 (r0Tree x) : Real) - 1 < expRayToWadTarget (int256 x) * (2 ^ s : Real) := by rw [hfold] have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] - -- (5¹⁸/2⁴⁰)·B ≈ 2.0097 < 3 = MARGIN, strictly - have hBM : (3814697265625 * 5792534503673398887 / (10000000000000000000 * 1099511627776) : Real) < 3 := by norm_num + -- (5¹⁸/2⁴⁰)·B < 1 = MARGIN, strictly + have hBM : (3814697265625 * 5737291786393199862 / (10000000000000000000 * 2199023255552) : Real) < 1 := by norm_num linarith [hover, hBM] rw [hAeq, div_lt_iff₀ hps]; linarith [hbound] /-- **Accumulator deficit, region-uniform.** On the region the accumulator is below the target by -strictly less than `24/25`: `E − 24/25 < accumReal x`. The deficit `r0 ≥ scaleQ68·exp(rt) − U` -(`U = 33/4`) and the octave fold give -`accumReal x ≥ E − (U + MARGIN)/2^s` with `s = 68 − k ≥ 4`, and `(U + MARGIN)/2⁴ ≈ 0.922 < 24/25`. +strictly less than `39931/40000`: `E − 39931/40000 < accumReal x`. The deficit `r0 ≥ scaleQ67·exp(rt) − U` +(`U = 2993/1000`) and the octave fold give +`accumReal x ≥ E − (U + MARGIN)/2^s` with `s = 68 − k ≥ 4`, and `(U + MARGIN)/2² ≈ 0.998 < 39931/40000`. The tightness below one is what closes the round trip together with `lnWadToRay`'s ≈10⁻⁹ envelope. -/ theorem accumReal_deficit_lt_one (x : Nat) (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - expRayToWadTarget (int256 x) - 24 / 25 < accumReal x := by + expRayToWadTarget (int256 x) - 39931 / 40000 < accumReal x := by obtain ⟨s, hsint, hAeq⟩ := accumReal_eq hx hC hC0 have hps : (0 : Real) < (2 ^ s : Real) := by positivity have hfold := target_octave_fold s hsint have hunder := r0_real_under_within hx hC hC0 obtain ⟨_, hkhi⟩ := kTree_bound hx hC hC0 set Ert := Real.exp (reducedArg x) with hErt - have hs4 : (4 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] - have hs4n : 4 ≤ s := by exact_mod_cast hs4 - have hpow : (2 ^ 4 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs4n - -- (E − 24/25)·2^s < r0 − MARGIN, since E·2^s = scaleQ68·Ert ≤ r0 + U - -- and U + MARGIN < (24/25)·2⁴ ≤ (24/25)·2^s - have hbound : (expRayToWadTarget (int256 x) - 24 / 25) * (2 ^ s : Real) < - (int256 (r0Tree x) : Real) - 3 := by + have hs4 : (2 : Int) ≤ (s : Int) := by rw [hsint]; linarith [hkhi] + have hs4n : 2 ≤ s := by exact_mod_cast hs4 + have hpow : (2 ^ 2 : Real) ≤ (2 ^ s : Real) := pow_le_pow_right₀ (by norm_num) hs4n + -- (E − 39931/40000)·2^s < r0 − MARGIN, since E·2^s = scaleQ67·Ert ≤ r0 + U + -- and U + MARGIN < (39931/40000)·2⁴ ≤ (39931/40000)·2^s + have hbound : (expRayToWadTarget (int256 x) - 39931 / 40000) * (2 ^ s : Real) < + (int256 (r0Tree x) : Real) - 1 := by have hkey : expRayToWadTarget (int256 x) * (2 ^ s : Real) = - (WAD : Real) * (2 ^ 68 : Real) * Ert := hfold + (WAD : Real) * (2 ^ 67 : Real) * Ert := hfold have hwad : (WAD : Real) = (10 ^ 18 : Real) := by unfold WAD; norm_num rw [hwad] at hkey - have hbudget : (33 / 4 : Real) + 3 < (24 / 25) * (2 ^ 4 : Real) := by norm_num - have h2425 : (24 / 25 : Real) * (2 ^ 4 : Real) ≤ (24 / 25) * (2 ^ s : Real) := + have hbudget : (2993 / 1000 : Real) + 1 < (39931 / 40000) * (2 ^ 2 : Real) := by norm_num + have h2425 : (39931 / 40000 : Real) * (2 ^ 2 : Real) ≤ (39931 / 40000) * (2 ^ s : Real) := mul_le_mul_of_nonneg_left hpow (by norm_num) nlinarith [hunder, hkey, hbudget, hpow, h2425] rw [hAeq, lt_div_iff₀ hps]; linarith [hbound] @@ -129,7 +129,7 @@ theorem band_ratio_bounds {w : Nat} (hlo : Wlo ≤ w) (hhi : w ≤ Whi) : theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) (hr_le : (r : Real) ≤ LnRealSpec.lnWadToRayTarget w) (hr_lt : LnRealSpec.lnWadToRayTarget w < ((r + 2 : Int) : Real)) : - ((w : Real) - 1 / 25 < expRayToWadTarget r ∧ expRayToWadTarget r ≤ (w : Real)) ∧ + ((w : Real) - 69 / 40000 < expRayToWadTarget r ∧ expRayToWadTarget r ≤ (w : Real)) ∧ int256 Cmask < r ∧ r < int256 C0thresh := by have hwpos : (0 : Real) < (w : Real) := by have : (0 : Nat) < w := lt_of_lt_of_le (by unfold Wlo; norm_num) hlo @@ -163,7 +163,7 @@ theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) -- deficit: r/10^27 > L − 2/10^27 ⇒ exp > (w/10^18)·exp(−2/10^27) ≥ (w/10^18)·(1 − 2/10^27) have hrgt' : L - 2 / (10 ^ 27 : Real) < (r : Real) / (10 ^ 27 : Real) := by rw [lt_div_iff₀ (by positivity)]; push_cast at hr_lt; nlinarith [hr_lt] - have hElt : (w : Real) - 1 / 25 < expRayToWadTarget r := by + have hElt : (w : Real) - 69 / 40000 < expRayToWadTarget r := by rw [hEeq] -- exp(r/10^27) > exp(L − 2/10^27) = exp(L)·exp(−2/10^27) have hexp_gt : Real.exp (L - 2 / (10 ^ 27 : Real)) < Real.exp ((r : Real) / (10 ^ 27 : Real)) := @@ -180,8 +180,8 @@ theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) have hstep : ((w : Real) / (10 ^ 18 : Real)) * (1 - 2 / (10 ^ 27 : Real)) ≤ ((w : Real) / (10 ^ 18 : Real)) * Real.exp (-(2 / (10 ^ 27 : Real))) := mul_le_mul_of_nonneg_left (by linarith [hone]) hwr_nn - -- 10^18 · (w/10^18)·(1 − 2/10^27) = w − 2w/10^27 > w − 1/25 since 2w·25 < 10^27 - have h2w : 25 * (2 * (w : Real)) < (10 ^ 27 : Real) := by + -- 10^18 · (w/10^18)·(1 − 2/10^27) = w − 2w/10^27 > w − 69/40000 since 2w·40000 < 69·10^27 + have h2w : 40000 * (2 * (w : Real)) < 69 * (10 ^ 27 : Real) := by have : (w : Real) ≤ (Whi : Real) := by exact_mod_cast hhi have hWhi : (Whi : Real) = 1414213562373095048 := by unfold Whi; norm_num rw [hWhi] at this; linarith [this] @@ -194,13 +194,13 @@ theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) have hlhs : (10 ^ 18 : Real) * (((w : Real) / (10 ^ 18 : Real)) * (1 - 2 / (10 ^ 27 : Real))) = (w : Real) - 2 * (w : Real) / (10 ^ 27 : Real) := by field_simp; ring rw [hlhs] at hmul - -- w − 2w/10^27 > w − 1/25 since 2w/10^27 < 1/25 - have h2wd : 2 * (w : Real) / (10 ^ 27 : Real) < 1 / 25 := by + -- w − 2w/10^27 > w − 69/40000 since 2w/10^27 < 69/40000 + have h2wd : 2 * (w : Real) / (10 ^ 27 : Real) < 69 / 40000 := by rw [div_lt_iff₀ (by positivity)]; linarith [h2w] linarith [hmul, h2wd] -- region membership of r have hCmask : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0 : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh + have hC0 : int256 C0thresh = 45401140326676417766828703956 := int256_C0thresh -- L > log(1/2) = −log 2 > −1 ; X = 10^27·L > −10^27 ; r ≥ X − 2 > Cmask have hLgt : -(1 : Real) < L := by have h12 : Real.log ((1:Real)/2) < L := by @@ -224,23 +224,23 @@ theorem expTarget_band {w : Nat} (r : Int) (hlo : Wlo ≤ w) (hhi : w ≤ Whi) · -- r < C0thresh : r ≤ 10^27·L < 10^27 < C0thresh rw [hC0] have hXhi : (10 ^ 27 : Real) * L < (10 ^ 27 : Real) := by nlinarith [hLlt] - have : (r : Real) < (44707993146116472457411471835 : Real) := by - have hc : (10 ^ 27 : Real) < (44707993146116472457411471835 : Real) := by norm_num + have : (r : Real) < (45401140326676417766828703956 : Real) := by + have hc : (10 ^ 27 : Real) < (45401140326676417766828703956 : Real) := by norm_num linarith [hr_le, hXhi, hc] exact_mod_cast this /-! ## Floor pinning: the body returns exactly `w − 1` With strict never-over (`accumReal x < E ≤ w`) and the region-uniform deficit -(`accumReal x > E − 24/25 > w − 1`), the accumulator lies in `(w − 1, w)`, so its floor — the body +(`accumReal x > E − 39931/40000 > w − 1`), the accumulator lies in `(w − 1, w)`, so its floor — the body word `r1Tree x` — is exactly `w − 1`. -/ -/-- **Floor pin.** On the region, if `w − 1/25 < E ≤ w` then the floored body word is exactly +/-- **Floor pin.** On the region, if `w − 69/40000 < E ≤ w` then the floored body word is exactly `w − 1`. The strict never-over puts `accumReal x < E ≤ w`, and the region-uniform deficit puts -`accumReal x > E − 24/25 > w − 1`, so `accumReal x ∈ (w − 1, w)` and its floor is `w − 1`. -/ +`accumReal x > E − 39931/40000 > w − 1`, so `accumReal x ∈ (w − 1, w)` and its floor is `w − 1`. -/ theorem r1Tree_eq_w_sub_one {x w : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) - (hElt : (w : Real) - 1 / 25 < expRayToWadTarget (int256 x)) + (hElt : (w : Real) - 69 / 40000 < expRayToWadTarget (int256 x)) (hEle : expRayToWadTarget (int256 x) ≤ (w : Real)) : int256 (r1Tree x) = (w : Int) - 1 := by set R1 : Int := int256 (r1Tree x) with hR1def @@ -255,7 +255,7 @@ theorem r1Tree_eq_w_sub_one {x w : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < have hRle : R1 ≤ (w : Int) - 1 := by have : R1 < (w : Int) := by exact_mod_cast hRltw omega - -- lower: accum > E − 24/25 > (w − 1/25) − 24/25 = w − 1 ; accum < R1 + 1 ⇒ R1 + 1 > w − 1 + -- lower: accum > E − 39931/40000 > (w − 69/40000) − 39931/40000 = w − 1 ; accum < R1 + 1 ⇒ R1 + 1 > w − 1 have hacc_lo : (w : Real) - 1 < accumReal x := by linarith [hdef, hElt] have hR1_gt : (w : Real) - 2 < (R1 : Real) := by linarith [hacc_lo, hfl1] have hRge : (w : Int) - 1 ≤ R1 := by @@ -344,16 +344,16 @@ theorem run_exp_ray_to_wad_evm_lnWadToRay_roundTrip {w : Nat} (hlo : Wlo ≤ w) intro hw have hx_ne : x ≠ 0 := by intro hx0 - -- x = 0 ⇒ int256 x = 0 ⇒ E = 10^18 ; but E ≤ w and w − 1/25 < E so w ∈ (E, E + 1/25]; w = 10^18 + -- x = 0 ⇒ int256 x = 0 ⇒ E = 10^18 ; but E ≤ w and w − 69/40000 < E so w ∈ (E, E + 69/40000]; w = 10^18 apply hw have hE0 : expRayToWadTarget (int256 x) = (10 ^ 18 : Real) := by rw [hx0]; show expRayToWadTarget (int256 (0 : Nat)) = (10 ^ 18 : Real) have : int256 (0 : Nat) = (0 : Int) := rfl rw [this, expRayToWadTarget_zero]; unfold WAD; norm_num - -- 10^18 ≤ w and w − 1/25 < 10^18 ⇒ w = 10^18 (integers) + -- 10^18 ≤ w and w − 69/40000 < 10^18 ⇒ w = 10^18 (integers) rw [hE0] at hElt hEle have hwge : (10 ^ 18 : Real) ≤ (w : Real) := hEle - have hwlt : (w : Real) < (10 ^ 18 : Real) + 1 / 25 := by linarith [hElt] + have hwlt : (w : Real) < (10 ^ 18 : Real) + 69 / 40000 := by linarith [hElt] have h1 : (10 : Int) ^ 18 ≤ (w : Int) := by exact_mod_cast hwge have h2 : (w : Real) < (10 ^ 18 : Real) + 1 := by linarith [hwlt] have h3 : (w : Int) < (10 : Int) ^ 18 + 1 := by exact_mod_cast h2 diff --git a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean index f6323b770..be96bd75c 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/Spec.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/Spec.lean @@ -96,8 +96,8 @@ A x = int256 (r0 − MARGIN) / 2^(68 − k). /-- The real pre-floor accumulator of the runtime body, as an explicit `Real`. -/ def accumReal (x : Nat) : Real := - (int256 (evmSub (r0Tree x) 0x3) : Real) / - (2 ^ (evmSub 0x44 (kTree x)) : Real) + (int256 (evmSub (r0Tree x) 0x1) : Real) / + (2 ^ (evmSub 0x43 (kTree x)) : Real) /-- On the meaningful region the body word `r1Tree x` is the integer floor of its real accumulator `accumReal x`: `(r1Tree x : Real) ≤ accumReal x < (r1Tree x : Real) + 1`. -/ @@ -108,18 +108,18 @@ theorem r1Tree_floor_accum {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmShr s (evmSub (r0Tree x) 0x3) := by - have : r1Tree x = evmShr (evmSub 0x44 (kTree x)) - (evmSub (r0Tree x) 0x3) := rfl + have hr1 : r1Tree x = evmShr s (evmSub (r0Tree x) 0x1) := by + have : r1Tree x = evmShr (evmSub 0x43 (kTree x)) + (evmSub (r0Tree x) 0x1) := rfl rw [this, hseq] - have hWw : evmSub (r0Tree x) 0x3 < 2 ^ 256 := + have hWw : evmSub (r0Tree x) 0x1 < 2 ^ 256 := evmSub_lt _ _ - have hfloor := shr_real_floor (W := evmSub (r0Tree x) 0x3) + have hfloor := shr_real_floor (W := evmSub (r0Tree x) 0x1) (s := s) (by omega) hWw (by rw [hargeq]; omega) simp only at hfloor - -- align `accumReal` (shift `evmSub 0x44 (kTree x)`) with the lemma's shift `s` + -- align `accumReal` (shift `evmSub 0x43 (kTree x)`) with the lemma's shift `s` have hAeq : accumReal x = - (int256 (evmSub (r0Tree x) 0x3) : Real) / + (int256 (evmSub (r0Tree x) 0x1) : Real) / (2 ^ s : Real) := by unfold accumReal; rw [hseq] rw [hAeq, hr1] diff --git a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean index 9aedd1b85..eb50d676a 100644 --- a/formal/exp/ExpProof/ExpProof/Floor/TBound.lean +++ b/formal/exp/ExpProof/ExpProof/Floor/TBound.lean @@ -2,17 +2,17 @@ import ExpProof.Mono.Octave import Mathlib.Tactic.IntervalCases /-! -# The reduced argument stays in the cert domain `[−H128, H128]` +# The reduced argument stays in the cert domain `[−H129, H129]` -The reduced-argument Taylor caps (`Floor.CapsV`) are certified over `t ∈ [0, H128]` with -`H128 = ⌊ln2/2 · 2¹²⁸⌋`. To instantiate them at the runtime reduced argument `t = tTree x` we -need `|tTree x| ≤ H128` on the meaningful region. +The reduced-argument Taylor caps (`Floor.CapsV`) are certified over `t ∈ [0, H129]` with +`H129 = ⌊ln2/2 · 2¹²⁸⌋`. To instantiate them at the runtime reduced argument `t = tTree x` we +need `|tTree x| ≤ H129` on the meaningful region. This is an integer-`k` fact: a real linear-program relaxation of the octave/reduced-argument sandwiches is unbounded (it decouples `k` from `x`), but the *integer* `k`-rounding sandwich `2²⁰⁰·k ≤ 2¹⁹⁹ + CINV·x < 2²⁰⁰·k + 2²⁰⁰` ties `k` to `x` tightly enough that the maximum of the reduction argument `K27·x − LN2·k` over the integer region is strictly below -`2¹⁰⁷·(H128 + 1)` (and symmetrically above `−2¹⁰⁷·(H128 + 1)`). `omega` discharges the resulting +`2¹⁰⁷·(H129 + 1)` (and symmetrically above `−2¹⁰⁷·(H129 + 1)`). `omega` discharges the resulting linear-integer system — it performs the per-`k`-band case analysis internally. -/ @@ -24,18 +24,18 @@ open FormalYul.Preservation set_option maxRecDepth 100000 /-- On the meaningful region the reduced argument lands in the certificate domain: -`-H128 ≤ tTree x ≤ H128` (as signed integers), where `H128 = ⌊ln2/2 · 2¹²⁸⌋`. -/ +`-H129 ≤ tTree x ≤ H129` (as signed integers), where `H129 = ⌊ln2/2 · 2¹²⁸⌋`. -/ theorem tTree_in_cert_domain {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - -(117932881612756647068972071382077242199 : Int) ≤ int256 (tTree x) ∧ - int256 (tTree x) ≤ 117932881612756647068972071382077242199 := by + -(235865763225513294137944142764154484399 : Int) ≤ int256 (tTree x) ∧ + int256 (tTree x) ≤ 235865763225513294137944142764154484399 := by obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 obtain ⟨hklo, hkhi⟩ := kTree_sandwich hx hC hC0 obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 obtain ⟨hkblo, hkbhi⟩ := kTree_bound hx hC hC0 -- region endpoints as decimals have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh + have hC0i : int256 C0thresh = 45401140326676417766828703956 := int256_C0thresh rw [hCi] at hC rw [hC0i] at hC0 -- constants as decimals @@ -51,20 +51,20 @@ theorem tTree_in_cert_domain {x : Nat} (hx : x < 2 ^ 256) set k := int256 (kTree x) with hkdef set X := int256 x with hXdef -- powers of two as decimals - have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num + have p106 : (2 : Int) ^ 106 = 81129638414606681695789005144064 := by norm_num have p199 : (2 : Int) ^ 191 = 3138550867693340381917894711603833208051177722232017256448 := by norm_num have p200 : (2 : Int) ^ 192 = 6277101735386680763835789423207666416102355444464034512896 := by norm_num - have pH : (117932881612756647068972071382077242199 : Int) = - 117932881612756647068972071382077242199 := rfl - rw [p107] at htlo hthi + have pH : (235865763225513294137944142764154484399 : Int) = + 235865763225513294137944142764154484399 := rfl + rw [p106] at htlo hthi rw [p199, p200] at hklo hkhi clear_value k - -- For each fixed integer octave index `k ∈ [−61, 64]` the band of consistent `x` together with + -- For each fixed integer octave index `k ∈ [−61, 65]` the band of consistent `x` together with -- the reduction sandwich pins `t` to the cert domain; `omega` closes each band (the coupling is -- linear in `x` and `t` once `k` is a literal). - clear htdef hXdef hkdef hCi hC0i hK27 hLN2 hCINV pH p107 p199 p200 hx hxlo hxhi + clear htdef hXdef hkdef hCi hC0i hK27 hLN2 hCINV pH p106 p199 p200 hx hxlo hxhi interval_cases k <;> constructor <;> omega end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean index 0e110fbc3..89444af2c 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Consts.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Consts.lean @@ -7,7 +7,7 @@ open FormalYul.Preservation /-! Runtime constants used by the generated exp kernel normal form. -/ abbrev Cmask : Nat := 0xffffffffffffffffffffffffffffffffffffffff7a143b87dbdabf5ee0a0efd7 -abbrev C0thresh : Nat := 0x907595ccd30708cabec8a9db +abbrev C0thresh : Nat := 0x92b2f16cc66c5a4ae96e80d4 abbrev kRoundShift : Nat := 0xc0 abbrev kHalfShift : Nat := 0xbf @@ -15,18 +15,18 @@ abbrev cInvQ192 : Nat := 0x724d54edbacbebbb95c52a0f60 abbrev k27Q235 : Nat := 0x279d346de4781f921dd7a89933d54d1f72928 abbrev ln2Q235 : Nat := 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d -abbrev tArgShift : Nat := 0x6b -abbrev squareShift : Nat := 0x85 +abbrev tArgShift : Nat := 0x6a +abbrev squareShift : Nat := 0x87 abbrev ev0 : Nat := 0xb9aacfacf3c10b378435f8e22adf48500e abbrev ev1 : Nat := 0x9a036222841f47c6ed6fc3f7599445 abbrev ev2 : Nat := 0x9064d9657e9a21fc16bb69331b81ae1e abbrev ev3 : Nat := 0x93f11e650dd6c64b96ce79065cdf80f4 -abbrev ev4 : Nat := 0x9c2948bcaca16a0dd2fe98bb4470c388 +abbrev ev4 : Nat := 0x1385291795942d41ba5fd317688e18710 abbrev evShift1 : Nat := 0x95 abbrev evShift2 : Nat := 0x7b abbrev evShift3 : Nat := 0x81 -abbrev evShift4 : Nat := 0x7e +abbrev evShift4 : Nat := 0x7d abbrev od0 : Nat := 0xdc07aff8276bde9a361278df6a10 abbrev od1 : Nat := 0xc926ddbecdeeb42e68cd16db7ed378 @@ -39,14 +39,14 @@ abbrev odShift3 : Nat := 0x7a abbrev odShift4 : Nat := 0x80 abbrev todShift : Nat := 0x81 -abbrev foldShift : Nat := 0x44 -abbrev scaleQ68 : Nat := 0xde0b6b3a764000000000000000000000 -abbrev marginWord : Nat := 0x3 +abbrev foldShift : Nat := 0x43 +abbrev scaleQ67 : Nat := 0x6f05b59d3b2000000000000000000000 +abbrev marginWord : Nat := 0x1 -theorem scaleQ68_eq : (scaleQ68 : Int) = 3814697265625 * 2 ^ 86 := by - unfold scaleQ68; norm_num +theorem scaleQ67_eq : (scaleQ67 : Int) = 3814697265625 * 2 ^ 85 := by + unfold scaleQ67; norm_num -theorem scaleQ68_lt_2128 : scaleQ68 < 2 ^ 128 := by unfold scaleQ68; norm_num +theorem scaleQ67_lt_2127 : scaleQ67 < 2 ^ 127 := by unfold scaleQ67; norm_num theorem int256_Cmask : int256 Cmask = -41446531673892822312323846185 := by unfold Cmask int256 @@ -56,7 +56,7 @@ theorem Cmask_lt : Cmask < 2 ^ 256 := by unfold Cmask norm_num -theorem int256_C0thresh : int256 C0thresh = 44707993146116472457411471835 := by +theorem int256_C0thresh : int256 C0thresh = 45401140326676417766828703956 := by unfold C0thresh int256 norm_num diff --git a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean index 96fe48875..058382dd1 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Cross.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Cross.lean @@ -5,7 +5,7 @@ import ExpProof.Mono.Quot Within a fixed octave (`k` constant) the closing accumulator `r1Tree` is monotone in the input iff the scaled quotient `r0Tree` is. With `num = ev + tod`, `den = ev − tod` (both strictly positive), -`r0 = ⌊scaleQ68·num/den⌋`, so +`r0 = ⌊scaleQ67·num/den⌋`, so ``` r0(x1) ≤ r0(x2) ⟸ num1·den2 ≤ num2·den1 (cross-multiply over positive den) @@ -35,25 +35,25 @@ theorem cross_identity (ev1 ev2 tod1 tod2 : Int) : (ev1 + tod1) * (ev2 - tod2) - (ev2 + tod2) * (ev1 - tod1) = 2 * (tod1 * ev2 - tod2 * ev1) := by ring -/-- `num = ev + tod < 2^128` (signed), from the even-accumulator and reduced-argument bounds. Stated +/-- `num = ev + tod < 2^129` (signed), from the even-accumulator and reduced-argument bounds. Stated as its own lemma so it carries a fresh kernel stack frame. -/ theorem numSum_lt {W : Nat} {ev tod : Int} (hW : int256 W = ev + tod) - (hev : ev < 3 * 2 ^ 126) (htod : tod < 2 ^ 126) : int256 W < 2 ^ 128 := by - rw [hW, show (2:Int)^128 = 3 * 2^126 + 2^126 from by ring]; omega + (hev : ev < 3 * 2 ^ 127) (htod : tod < 2 ^ 126) : int256 W < 2 ^ 129 := by + rw [hW, show (2:Int)^129 = 3 * 2^127 + 2^127 from by ring]; omega -/-- The `mul scaleQ68 N` dividend as a plain `Nat` product when `N`'s signed value is in -`[0, 2^128)`: `evmMul scaleQ68 N = scaleQ68 * N` (no wrap), and `N` is its own signed value. -/ +/-- The `mul scaleQ67 N` dividend as a plain `Nat` product when `N`'s signed value is in +`[0, 2^128)`: `evmMul scaleQ67 N = scaleQ67 * N` (no wrap), and `N` is its own signed value. -/ theorem mulScale_transport {N : Nat} (hNw : N < 2 ^ 256) (hNnn : 0 ≤ int256 N) - (hNlt : int256 N < 2 ^ 128) : - evmMul scaleQ68 N = scaleQ68 * N ∧ N < 2 ^ 128 := by + (hNlt : int256 N < 2 ^ 129) : + evmMul scaleQ67 N = scaleQ67 * N ∧ N < 2 ^ 129 := by obtain ⟨hNi, _⟩ := int256_eq_of_nonneg hNw hNnn - have hNnat : N < 2 ^ 128 := by - have : ((N : Nat) : Int) < 2 ^ 128 := by rw [← hNi]; exact hNlt + have hNnat : N < 2 ^ 129 := by + have : ((N : Nat) : Int) < 2 ^ 129 := by rw [← hNi]; exact hNlt exact_mod_cast this - have hsw : scaleQ68 < 2 ^ 256 := by unfold scaleQ68; norm_num - have hfit : scaleQ68 * N < 2 ^ 256 := by - have h1 : scaleQ68 * N ≤ scaleQ68 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hNnat) - have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + have hsw : scaleQ67 < 2 ^ 256 := by unfold scaleQ67; norm_num + have hfit : scaleQ67 * N < 2 ^ 256 := by + have h1 : scaleQ67 * N ≤ scaleQ67 * 2 ^ 129 := Nat.mul_le_mul_left _ (le_of_lt hNnat) + have h2 : scaleQ67 * 2 ^ 129 < 2 ^ 256 := by unfold scaleQ67; norm_num omega exact ⟨evmMul_eq_nat hsw hNw hfit, hNnat⟩ @@ -62,17 +62,17 @@ Given the numerator/denominator positivity and `tod1·ev2 ≤ tod2·ev1`, the tw `≤`-ordered. -/ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} (hE1 : E1 < 2 ^ 256) (hTD1 : TD1 < 2 ^ 256) (hE2 : E2 < 2 ^ 256) (hTD2 : TD2 < 2 ^ 256) - (hev1_lo : (207573926795459379279817565122117813128 : Int) ≤ (E1 : Int)) - (hev1_hi : (E1 : Int) < 3 * 2 ^ 126) + (hev1_lo : (415147853590918758559635130244235626256 : Int) ≤ (E1 : Int)) + (hev1_hi : (E1 : Int) < 3 * 2 ^ 127) (htod1_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD1) (htod1_hi : int256 TD1 < 85070591730234615865843651857942052864) - (hev2_lo : (207573926795459379279817565122117813128 : Int) ≤ (E2 : Int)) - (hev2_hi : (E2 : Int) < 3 * 2 ^ 126) + (hev2_lo : (415147853590918758559635130244235626256 : Int) ≤ (E2 : Int)) + (hev2_hi : (E2 : Int) < 3 * 2 ^ 127) (htod2_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD2) (htod2_hi : int256 TD2 < 85070591730234615865843651857942052864) (hcross : int256 TD1 * (E2 : Int) ≤ int256 TD2 * (E1 : Int)) : - int256 (evmDiv (evmMul scaleQ68 (evmAdd E1 TD1)) (evmSub E1 TD1)) ≤ - int256 (evmDiv (evmMul scaleQ68 (evmAdd E2 TD2)) (evmSub E2 TD2)) := by + int256 (evmDiv (evmMul scaleQ67 (evmAdd E1 TD1)) (evmSub E1 TD1)) ≤ + int256 (evmDiv (evmMul scaleQ67 (evmAdd E2 TD2)) (evmSub E2 TD2)) := by obtain ⟨hadd1, hsub1, hnum1, hden1⟩ := numden_pos_of hE1 hTD1 hev1_lo hev1_hi htod1_lo htod1_hi obtain ⟨hadd2, hsub2, hnum2, hden2⟩ := numden_pos_of hE2 hTD2 hev2_lo hev2_hi htod2_lo htod2_hi -- the tod magnitude in the symbolic power form @@ -83,8 +83,8 @@ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} have : (85070591730234615865843651857942052864 : Int) = 2 ^ 126 := by norm_num omega -- numerator/denominator are positive and below 2^128 (signed) - have hN1lt : int256 (evmAdd E1 TD1) < 2 ^ 128 := numSum_lt hadd1 hev1_hi htod1_hi' - have hN2lt : int256 (evmAdd E2 TD2) < 2 ^ 128 := numSum_lt hadd2 hev2_hi htod2_hi' + have hN1lt : int256 (evmAdd E1 TD1) < 2 ^ 129 := numSum_lt hadd1 hev1_hi htod1_hi' + have hN2lt : int256 (evmAdd E2 TD2) < 2 ^ 129 := numSum_lt hadd2 hev2_hi htod2_hi' -- denominator positivity in `int256 (evmSub …)` form have hD1pos : 0 < int256 (evmSub E1 TD1) := by rw [hsub1]; exact hden1 have hD2pos : 0 < int256 (evmSub E2 TD2) := by rw [hsub2]; exact hden2 @@ -104,23 +104,23 @@ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} exact_mod_cast h have hD1nz : evmSub E1 TD1 ≠ 0 := Nat.pos_iff_ne_zero.mp hD1posN have hD2nz : evmSub E2 TD2 ≠ 0 := Nat.pos_iff_ne_zero.mp hD2posN - have hsw : scaleQ68 < 2 ^ 256 := by unfold scaleQ68; norm_num - have hfit1 : scaleQ68 * evmAdd E1 TD1 < 2 ^ 256 := by - have h1 : scaleQ68 * evmAdd E1 TD1 ≤ scaleQ68 * 2 ^ 128 := + have hsw : scaleQ67 < 2 ^ 256 := by unfold scaleQ67; norm_num + have hfit1 : scaleQ67 * evmAdd E1 TD1 < 2 ^ 256 := by + have h1 : scaleQ67 * evmAdd E1 TD1 ≤ scaleQ67 * 2 ^ 129 := Nat.mul_le_mul_left _ (le_of_lt hN1nat) - have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + have h2 : scaleQ67 * 2 ^ 129 < 2 ^ 256 := by unfold scaleQ67; norm_num omega - have hfit2 : scaleQ68 * evmAdd E2 TD2 < 2 ^ 256 := by - have h1 : scaleQ68 * evmAdd E2 TD2 ≤ scaleQ68 * 2 ^ 128 := + have hfit2 : scaleQ67 * evmAdd E2 TD2 < 2 ^ 256 := by + have h1 : scaleQ67 * evmAdd E2 TD2 ≤ scaleQ67 * 2 ^ 129 := Nat.mul_le_mul_left _ (le_of_lt hN2nat) - have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + have h2 : scaleQ67 * 2 ^ 129 < 2 ^ 256 := by unfold scaleQ67; norm_num omega -- the two quotients as plain Nat floor divisions - have hq1 : evmDiv (evmMul scaleQ68 (evmAdd E1 TD1)) (evmSub E1 TD1) = - scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 := by + have hq1 : evmDiv (evmMul scaleQ67 (evmAdd E1 TD1)) (evmSub E1 TD1) = + scaleQ67 * evmAdd E1 TD1 / evmSub E1 TD1 := by rw [hA1, evmDiv_eq hfit1 (evmSub_lt _ _) hD1nz] - have hq2 : evmDiv (evmMul scaleQ68 (evmAdd E2 TD2)) (evmSub E2 TD2) = - scaleQ68 * evmAdd E2 TD2 / evmSub E2 TD2 := by + have hq2 : evmDiv (evmMul scaleQ67 (evmAdd E2 TD2)) (evmSub E2 TD2) = + scaleQ67 * evmAdd E2 TD2 / evmSub E2 TD2 := by rw [hA2, evmDiv_eq hfit2 (evmSub_lt _ _) hD2nz] -- Nat-level cross monotonicity: q1·D1 ≤ S·N1, S·N1·D2 ≤ S·N2·D1 ⇒ q1·D2 ≤ S·N2 ⇒ q1 ≤ q2 have hcrossN : evmAdd E1 TD1 * evmSub E2 TD2 ≤ evmAdd E2 TD2 * evmSub E1 TD1 := by @@ -132,20 +132,20 @@ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} exact_mod_cast hInt have hD1pos' : 0 < evmSub E1 TD1 := Nat.pos_of_ne_zero hD1nz have hD2pos' : 0 < evmSub E2 TD2 := Nat.pos_of_ne_zero hD2nz - have hqle : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 ≤ - scaleQ68 * evmAdd E2 TD2 / evmSub E2 TD2 := by + have hqle : scaleQ67 * evmAdd E1 TD1 / evmSub E1 TD1 ≤ + scaleQ67 * evmAdd E2 TD2 / evmSub E2 TD2 := by rw [Nat.le_div_iff_mul_le hD2pos'] - have hfl : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E1 TD1 ≤ - scaleQ68 * evmAdd E1 TD1 := Nat.div_mul_le_self _ _ + have hfl : scaleQ67 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E1 TD1 ≤ + scaleQ67 * evmAdd E1 TD1 := Nat.div_mul_le_self _ _ -- (q1·D2)·D1 ≤ S·N1·D2 ≤ S·N2·D1 ⇒ q1·D2 ≤ S·N2 (divide by D1 > 0) - have hstep : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E2 TD2 * evmSub E1 TD1 ≤ - scaleQ68 * evmAdd E2 TD2 * evmSub E1 TD1 := by - calc scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E2 TD2 * evmSub E1 TD1 - = scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E1 TD1 * evmSub E2 TD2 := by ring - _ ≤ scaleQ68 * evmAdd E1 TD1 * evmSub E2 TD2 := Nat.mul_le_mul_right _ hfl - _ = scaleQ68 * (evmAdd E1 TD1 * evmSub E2 TD2) := by ring - _ ≤ scaleQ68 * (evmAdd E2 TD2 * evmSub E1 TD1) := Nat.mul_le_mul_left _ hcrossN - _ = scaleQ68 * evmAdd E2 TD2 * evmSub E1 TD1 := by ring + have hstep : scaleQ67 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E2 TD2 * evmSub E1 TD1 ≤ + scaleQ67 * evmAdd E2 TD2 * evmSub E1 TD1 := by + calc scaleQ67 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E2 TD2 * evmSub E1 TD1 + = scaleQ67 * evmAdd E1 TD1 / evmSub E1 TD1 * evmSub E1 TD1 * evmSub E2 TD2 := by ring + _ ≤ scaleQ67 * evmAdd E1 TD1 * evmSub E2 TD2 := Nat.mul_le_mul_right _ hfl + _ = scaleQ67 * (evmAdd E1 TD1 * evmSub E2 TD2) := by ring + _ ≤ scaleQ67 * (evmAdd E2 TD2 * evmSub E1 TD1) := Nat.mul_le_mul_left _ hcrossN + _ = scaleQ67 * evmAdd E2 TD2 * evmSub E1 TD1 := by ring exact Nat.le_of_mul_le_mul_right hstep hD1pos' -- transport back to int256 (both quotients are small: den ≥ 2^126) have hD1ge : 2 ^ 126 ≤ evmSub E1 TD1 := by @@ -158,21 +158,21 @@ theorem r0_mono_of_cross {E1 TD1 E2 TD2 : Nat} rw [← hD2i, hsub2] linarith [hev2_lo, htod2_hi] exact_mod_cast h - have hq1small : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 < 2 ^ 255 := by - have h1 : scaleQ68 * evmAdd E1 TD1 / evmSub E1 TD1 ≤ scaleQ68 * evmAdd E1 TD1 / 2 ^ 126 := + have hq1small : scaleQ67 * evmAdd E1 TD1 / evmSub E1 TD1 < 2 ^ 255 := by + have h1 : scaleQ67 * evmAdd E1 TD1 / evmSub E1 TD1 ≤ scaleQ67 * evmAdd E1 TD1 / 2 ^ 126 := Nat.div_le_div_left hD1ge (Nat.two_pow_pos _) - have h2 : scaleQ68 * evmAdd E1 TD1 / 2 ^ 126 < 2 ^ 130 := by + have h2 : scaleQ67 * evmAdd E1 TD1 / 2 ^ 126 < 2 ^ 130 := by rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] - calc scaleQ68 * evmAdd E1 TD1 < 2 ^ 256 := hfit1 + calc scaleQ67 * evmAdd E1 TD1 < 2 ^ 256 := hfit1 _ = 2 ^ 130 * 2 ^ 126 := by norm_num have h3 : (2:Nat) ^ 130 < 2 ^ 255 := by norm_num omega - have hq2small : scaleQ68 * evmAdd E2 TD2 / evmSub E2 TD2 < 2 ^ 255 := by - have h1 : scaleQ68 * evmAdd E2 TD2 / evmSub E2 TD2 ≤ scaleQ68 * evmAdd E2 TD2 / 2 ^ 126 := + have hq2small : scaleQ67 * evmAdd E2 TD2 / evmSub E2 TD2 < 2 ^ 255 := by + have h1 : scaleQ67 * evmAdd E2 TD2 / evmSub E2 TD2 ≤ scaleQ67 * evmAdd E2 TD2 / 2 ^ 126 := Nat.div_le_div_left hD2ge (Nat.two_pow_pos _) - have h2 : scaleQ68 * evmAdd E2 TD2 / 2 ^ 126 < 2 ^ 130 := by + have h2 : scaleQ67 * evmAdd E2 TD2 / 2 ^ 126 < 2 ^ 130 := by rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] - calc scaleQ68 * evmAdd E2 TD2 < 2 ^ 256 := hfit2 + calc scaleQ67 * evmAdd E2 TD2 < 2 ^ 256 := hfit2 _ = 2 ^ 130 * 2 ^ 126 := by norm_num have h3 : (2:Nat) ^ 130 < 2 ^ 255 := by norm_num omega diff --git a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean index da9429fa3..7b4aaca14 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/CrossCert.lean @@ -26,16 +26,16 @@ set_option maxRecDepth 100000 /-- The even accumulator's signed value is its (nonnegative) Nat value, in `[a0, 2^127)`. -/ theorem evTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : - (207573926795459379279817565122117813128 : Int) ≤ (evTree x : Int) ∧ - (evTree x : Int) < 3 * 2 ^ 126 := by + (415147853590918758559635130244235626256 : Int) ≤ (evTree x : Int) ∧ + (evTree x : Int) < 3 * 2 ^ 127 := by obtain ⟨hlo, hhi⟩ := evTree_facts hv constructor - · have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 by + · have : (0x1385291795942d41ba5fd317688e18710 : Int) ≤ (evTree x : Int) := by exact_mod_cast hlo + rw [show (0x1385291795942d41ba5fd317688e18710 : Int) = 415147853590918758559635130244235626256 by norm_num] at this exact this - · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hhi - rw [show ((3 * 2 ^ 126 : Nat) : Int) = 3 * 2 ^ 126 by norm_num] at this; exact this + · have : (evTree x : Int) < ((3 * 2 ^ 127 : Nat) : Int) := by exact_mod_cast hhi + rw [show ((3 * 2 ^ 127 : Nat) : Int) = 3 * 2 ^ 127 by norm_num] at this; exact this /-- The odd accumulator's signed value is its (nonnegative) Nat value, in `[b0, 5·2^125)`. -/ theorem odTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : @@ -54,11 +54,11 @@ theorem odTree_int {x : Nat} (hv : vTree x < 2 ^ 120) : transported to `Int`). -/ theorem evTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - -(85236826369 : Int) ≤ (evTree x1 : Int) - (evTree x2 : Int) ∧ - (evTree x1 : Int) - (evTree x2 : Int) ≤ 85236826369 := by + -(170473652738 : Int) ≤ (evTree x1 : Int) - (evTree x2 : Int) ∧ + (evTree x1 : Int) - (evTree x2 : Int) ≤ 170473652738 := by obtain ⟨h1, h2⟩ := evTree_lip hv1 hv2 hg1 hg2 - have c1 : ((evTree x1 : Nat) : Int) ≤ (evTree x2 : Int) + 85236826369 := by exact_mod_cast h1 - have c2 : ((evTree x2 : Nat) : Int) ≤ (evTree x1 : Int) + 85236826369 := by exact_mod_cast h2 + have c1 : ((evTree x1 : Nat) : Int) ≤ (evTree x2 : Int) + 170473652738 := by exact_mod_cast h1 + have c2 : ((evTree x2 : Nat) : Int) ≤ (evTree x1 : Int) + 170473652738 := by exact_mod_cast h2 omega theorem odTree_lip_int {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) @@ -86,16 +86,16 @@ theorem vTree_step_nat {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) dominates the loss `2^128·ev2 + |t1|·|od1·ev2 − od2·ev1|`, where the cross difference is controlled by the Lipschitz near-constancy. -/ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} - (hd1 : (340282366920 : Int) ≤ d) - (ht1lo : -(170141183460469231731687303715884105728 : Int) < t1) - (ht1hi : t1 < 170141183460469231731687303715884105728) - (hev1lo : (207573926795459379279817565122117813128 : Int) ≤ ev1) - (hev1hi : ev1 < 255211775190703847597530955573826158592) - (hev2lo : (207573926795459379279817565122117813128 : Int) ≤ ev2) - (hev2hi : ev2 < 255211775190703847597530955573826158592) + (hd1 : (680564733841 : Int) ≤ d) + (ht1lo : -(340282366920938463463374607431768211456 : Int) < t1) + (ht1hi : t1 < 340282366920938463463374607431768211456) + (hev1lo : (415147853590918758559635130244235626256 : Int) ≤ ev1) + (hev1hi : ev1 < 510423550381407695195061911147652317184) + (hev2lo : (415147853590918758559635130244235626256 : Int) ≤ ev2) + (hev2hi : ev2 < 510423550381407695195061911147652317184) (hod2lo : (207573926795459379279817565122117813128 : Int) ≤ od2) (hod2hi : od2 < 212676479325586539664609129644855132160) - (hevd1 : -(85236826369 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 85236826369) + (hevd1 : -(170473652738 : Int) ≤ ev1 - ev2) (hevd2 : ev1 - ev2 ≤ 170473652738) (hodd1 : -(21288422193 : Int) ≤ od1 - od2) (hodd2 : od1 - od2 ≤ 21288422193) : t1 * od1 * ev2 + 680564733841876926926749214863536422912 * ev1 ≤ (t1 + d) * od2 * ev1 := by @@ -104,42 +104,42 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} -- bound each piece have hev2nn : (0 : Int) ≤ ev2 := by linarith have hod2nn : (0 : Int) ≤ od2 := by linarith - have hp1 : (od1 - od2) * ev2 ≤ 21288422193 * 255211775190703847597530955573826158592 := by + have hp1 : (od1 - od2) * ev2 ≤ 21288422193 * 510423550381407695195061911147652317184 := by nlinarith [hodd2, hodd1, hev2nn, hev2hi] - have hp1' : -(21288422193 * 255211775190703847597530955573826158592 : Int) ≤ (od1 - od2) * ev2 := by + have hp1' : -(21288422193 * 510423550381407695195061911147652317184 : Int) ≤ (od1 - od2) * ev2 := by nlinarith [hodd1, hev2nn, hev2hi] - have hp2 : od2 * (ev2 - ev1) ≤ 212676479325586539664609129644855132160 * 85236826369 := by + have hp2 : od2 * (ev2 - ev1) ≤ 212676479325586539664609129644855132160 * 170473652738 := by nlinarith [hod2nn, hod2hi, hevd1, hevd2] - have hp2' : -(212676479325586539664609129644855132160 * 85236826369 : Int) ≤ od2 * (ev2 - ev1) := by + have hp2' : -(212676479325586539664609129644855132160 * 170473652738 : Int) ≤ od2 * (ev2 - ev1) := by nlinarith [hod2nn, hod2hi, hevd1, hevd2] -- so |cd| ≤ CB - set CB : Int := 21288422193 * 255211775190703847597530955573826158592 + - 212676479325586539664609129644855132160 * 85236826369 with hCB + set CB : Int := 21288422193 * 510423550381407695195061911147652317184 + + 212676479325586539664609129644855132160 * 170473652738 with hCB have hcd_hi : od1 * ev2 - od2 * ev1 ≤ CB := by rw [hcd_eq, hCB]; linarith have hcd_lo : -CB ≤ od1 * ev2 - od2 * ev1 := by rw [hcd_eq, hCB]; linarith -- `t1·(od1·ev2 − od2·ev1) ≤ 2^127·CB` have hCBnn : (0 : Int) ≤ CB := by rw [hCB]; norm_num - have htcd : t1 * (od1 * ev2 - od2 * ev1) ≤ 170141183460469231731687303715884105728 * CB := by + have htcd : t1 * (od1 * ev2 - od2 * ev1) ≤ 340282366920938463463374607431768211456 * CB := by rcases le_total 0 t1 with ht | ht · have h1 : t1 * (od1 * ev2 - od2 * ev1) ≤ t1 * CB := mul_le_mul_left_nonneg hcd_hi ht - have h2 : t1 * CB ≤ 170141183460469231731687303715884105728 * CB := + have h2 : t1 * CB ≤ 340282366920938463463374607431768211456 * CB := mul_le_mul_right_nonneg (le_of_lt ht1hi) hCBnn linarith · have h1 : t1 * (od1 * ev2 - od2 * ev1) ≤ t1 * (-CB) := by have := mul_le_mul_left_nonneg hcd_lo (show (0:Int) ≤ -t1 by linarith) nlinarith [this] - have h2 : t1 * (-CB) ≤ 170141183460469231731687303715884105728 * CB := by nlinarith [ht1lo, hCBnn, ht] + have h2 : t1 * (-CB) ≤ 340282366920938463463374607431768211456 * CB := by nlinarith [ht1lo, hCBnn, ht] linarith - -- gain: d·od2·ev1 ≥ 340282366920·b0·a0 + -- gain: d·od2·ev1 ≥ 680564733841·b0·a0 have hev1nn : (0 : Int) ≤ ev1 := by linarith - have hgain : (340282366920 : Int) * 207573926795459379279817565122117813128 * - 207573926795459379279817565122117813128 ≤ d * od2 * ev1 := by - have g1 : (340282366920 : Int) * 207573926795459379279817565122117813128 ≤ d * od2 := by + have hgain : (680564733841 : Int) * 207573926795459379279817565122117813128 * + 415147853590918758559635130244235626256 ≤ d * od2 * ev1 := by + have g1 : (680564733841 : Int) * 207573926795459379279817565122117813128 ≤ d * od2 := by have := mul_le_mul hd1 hod2lo (by norm_num : (0:Int) ≤ 207573926795459379279817565122117813128) (by linarith) linarith - have g2 : (340282366920 : Int) * 207573926795459379279817565122117813128 * - 207573926795459379279817565122117813128 ≤ (d * od2) * ev1 := + have g2 : (680564733841 : Int) * 207573926795459379279817565122117813128 * + 415147853590918758559635130244235626256 ≤ (d * od2) * ev1 := mul_le_mul g1 hev1lo (by norm_num) (by positivity) linarith [g2] -- assemble: goal `t1·od1·ev2 + 2^128·ev2 ≤ (t1+d)·od2·ev1 = t1·od2·ev1 + d·od2·ev1` @@ -149,9 +149,9 @@ theorem smooth_cross_of {t1 d ev1 ev2 od1 od2 : Int} rw [hexpand] -- numeric closure: 2^128·ev2 + 2^127·CB ≤ gain, and ev2 < 2^127 have hkey : (680564733841876926926749214863536422912 : Int) * ev1 + - 170141183460469231731687303715884105728 * CB ≤ - (340282366920 : Int) * 207573926795459379279817565122117813128 * - 207573926795459379279817565122117813128 := by + 340282366920938463463374607431768211456 * CB ≤ + (680564733841 : Int) * 207573926795459379279817565122117813128 * + 415147853590918758559635130244235626256 := by rw [hCB] nlinarith [hev1hi] nlinarith [htcd, hgain, hkey, hdecomp] @@ -177,10 +177,10 @@ theorem smooth_cross {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) obtain ⟨htg1, -⟩ := tTree_step hx1 hx2 hC1 hC01 hC2 hC02 hk hadj obtain ⟨htlo1, hthi1⟩ := tTree_bound hx1 hC1 hC01 -- numeric rewrites of the power bounds - have hGv : (Gstep : Int) = 340282366920 := by unfold Gstep; norm_num + have hGv : (Gstep : Int) = 680564733841 := by unfold Gstep; norm_num rw [hGv] at htg1 - rw [show (2 : Int) ^ 127 = 170141183460469231731687303715884105728 by norm_num] at htlo1 hthi1 - rw [show (3 : Int) * 2 ^ 126 = 255211775190703847597530955573826158592 by norm_num] at hev1hi hev2hi + rw [show (2 : Int) ^ 128 = 340282366920938463463374607431768211456 by norm_num] at htlo1 hthi1 + rw [show (3 : Int) * 2 ^ 127 = 510423550381407695195061911147652317184 by norm_num] at hev1hi hev2hi rw [show (5 : Int) * 2 ^ 125 = 212676479325586539664609129644855132160 by norm_num] at hod2hi rw [show (2 : Int) ^ 129 = 680564733841876926926749214863536422912 by norm_num] -- t2 = t1 + d, d ∈ [G, G+1] diff --git a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean index 74b32f789..35ee1a6df 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/EvOdLip.lean @@ -7,7 +7,7 @@ Telescoping `stage_lip` through the five even / four odd Horner stages, with the gap `|v2 − v1| ≤ W` from `vTree_step`, bounds the change of the accumulators: ``` -|evTree x2 − evTree x1| ≤ DEv = 85236826369, +|evTree x2 − evTree x1| ≤ DEv = 170473652738, |odTree x2 − odTree x1| ≤ DOd = 21288422193. ``` @@ -60,7 +60,7 @@ def evS2 (x : Nat) : Nat := evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x def evS3 (x : Nat) : Nat := evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evS2 x) (vTree x))) theorem evTree_layers (x : Nat) : - evTree x = evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul (evS3 x) (vTree x))) := + evTree x = evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evS3 x) (vTree x))) := rfl theorem evS0_lt {x : Nat} (hv : vTree x < 2 ^ 120) : @@ -118,10 +118,10 @@ theorem odS2_lt {x : Nat} (hv : vTree x < 2 ^ 120) : odS2 x < 2 ^ 129 := by /-! ## Composed Lipschitz bounds -/ /-- **Even accumulator near-constancy.** Under a squared-argument gap `|v2 − v1| ≤ W` the even -accumulator changes by at most `DEv = 85236826369`. -/ +accumulator changes by at most `DEv = 170473652738`. -/ theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 ^ 120) (hg1 : vTree x1 ≤ vTree x2 + Wstep) (hg2 : vTree x2 ≤ vTree x1 + Wstep) : - dist_le (evTree x1) (evTree x2) 85236826369 := by + dist_le (evTree x1) (evTree x2) 170473652738 := by -- monic leading stage: distance exactly the argument gap have d0 : dist_le (evS0 x1) (evS0 x2) Wstep := evLead_lip (c := 0xb9aacfacf3c10b378435f8e22adf48500e) (W := Wstep) (by norm_num) hv1 hv2 hg1 hg2 @@ -153,11 +153,11 @@ theorem evTree_lip {x1 x2 : Nat} (hv1 : vTree x1 < 2 ^ 120) (hv2 : vTree x2 < 2 unfold Wstep; decide rw [he] at h; exact h -- final stage - have hfin := stage_lip_dist (c := 0x9c2948bcaca16a0dd2fe98bb4470c388) (P := 2 ^ 129) (V := 2 ^ 120) - (sh := 0x7e) (W := Wstep) + have hfin := stage_lip_dist (c := 0x1385291795942d41ba5fd317688e18710) (P := 2 ^ 129) (V := 2 ^ 120) + (sh := 0x7d) (W := Wstep) (Dprev := 10639016494) (le_of_lt (evS3_lt hv1)) (le_of_lt (evS3_lt hv2)) hv1 hv2 hg1 hg2 d3 (by norm_num) (by norm_num) (by norm_num) (by norm_num) - have he : (2 ^ 129 * Wstep + 2 ^ 120 * 10639016494) / 2 ^ 0x7e + 1 = 85236826369 := by + have he : (2 ^ 129 * Wstep + 2 ^ 120 * 10639016494) / 2 ^ 0x7d + 1 = 170473652738 := by unfold Wstep; decide rw [he] at hfin rw [evTree_layers, evTree_layers]; exact hfin diff --git a/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean b/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean index 24f554041..17b948327 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Gaps.lean @@ -7,7 +7,7 @@ For two inputs adjacent in the signed order (`int256 x2 = int256 x1 + 1`) lying (`kTree x1 = kTree x2`), the reduced argument advances by a fixed step: ``` -G ≤ int256 (tTree x2) − int256 (tTree x1) ≤ G + 1, G = ⌊K27 / 2^107⌋ = 340282366920. +G ≤ int256 (tTree x2) − int256 (tTree x1) ≤ G + 1, G = ⌊K27 / 2^106⌋ = 680564733841. ``` From that, the squared argument `v = ⌊t²/2^133⌋` (which drives the even/odd accumulators) moves by @@ -22,15 +22,15 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-- `K27 = G·2^107 + r` with `0 < r < 2^107`: the reduced-argument constant's quotient by the +/-- `K27 = G·2^106 + r` with `0 < r < 2^106`: the reduced-argument constant's quotient by the shift is exactly `G`. -/ theorem K27_decomp : (0x279d346de4781f921dd7a89933d54d1f72928 : Int) = - Gstep * 2 ^ 107 + 152274402897802763547896603683112 := by + Gstep * 2 ^ 106 + 71144764483196081852107598539048 := by unfold Gstep; norm_num -theorem Gstep_rem_pos : (0 : Int) < 152274402897802763547896603683112 := by norm_num -theorem Gstep_rem_lt : (152274402897802763547896603683112 : Int) < 2 ^ 107 := by norm_num +theorem Gstep_rem_pos : (0 : Int) < 71144764483196081852107598539048 := by norm_num +theorem Gstep_rem_lt : (71144764483196081852107598539048 : Int) < 2 ^ 106 := by norm_num /-- The reduced-argument step for adjacent same-octave inputs is `G` or `G + 1`. -/ theorem tTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) @@ -45,7 +45,7 @@ theorem tTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) rw [hk] at hlo1 hhi1 -- the `K27·x − LN2·k` term advances by exactly `K27` from x1 to x2 have hK27 := K27_decomp - have hp107 : (0 : Int) < 2 ^ 107 := by norm_num + have hp107 : (0 : Int) < 2 ^ 106 := by norm_num set K27 := (0x279d346de4781f921dd7a89933d54d1f72928 : Int) with hK27def set LN2 := (0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d : Int) with hLN2def set k := int256 (kTree x2) @@ -56,7 +56,7 @@ theorem tTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) -- the affine value at x2 exceeds that at x1 by exactly K27 have hstep : K27 * X2 - LN2 * k = (K27 * X1 - LN2 * k) + K27 := by rw [hadj]; ring rw [hstep] at hlo2 hhi2 - -- combine: 2^107·t1 ≤ A < 2^107·t1 + 2^107 and 2^107·t2 ≤ A + K27 < 2^107·t2 + 2^107 + -- combine: 2^106·t1 ≤ A < 2^106·t1 + 2^106 and 2^106·t2 ≤ A + K27 < 2^106·t2 + 2^106 set A := K27 * X1 - LN2 * k -- with K27 = G·2^107 + r, 0 < r < 2^107 have hrem_pos := Gstep_rem_pos @@ -65,24 +65,24 @@ theorem tTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) · nlinarith [hlo1, hhi1, hlo2, hhi2, hK27, hrem_pos, hrem_lt, hp107] · nlinarith [hlo1, hhi1, hlo2, hhi2, hK27, hrem_pos, hrem_lt, hp107] -/-- The squared-argument floor sandwich: `2^133·v ≤ t² < 2^133·v + 2^133`, from `vTree_eq`. -/ +/-- The squared-argument floor sandwich: `2^135·v ≤ t² < 2^135·v + 2^135`, from `vTree_eq`. -/ theorem vTree_sandwich {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 133 : Int) * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ - (int256 (tTree x)) ^ 2 < (2 ^ 133 : Int) * (vTree x : Int) + 2 ^ 133 := by + (2 ^ 135 : Int) * (vTree x : Int) ≤ (int256 (tTree x)) ^ 2 ∧ + (int256 (tTree x)) ^ 2 < (2 ^ 135 : Int) * (vTree x : Int) + 2 ^ 135 := by obtain ⟨hveq, _⟩ := vTree_eq hx hC hC0 rw [hveq] set a := (int256 (tTree x)) ^ 2 with ha - have h1 := Int.ediv_add_emod a (2 ^ 133) - have h2 := Int.emod_nonneg a (by norm_num : (2 : Int) ^ 133 ≠ 0) - have h3 := Int.emod_lt_of_pos a (by norm_num : (0 : Int) < 2 ^ 133) + have h1 := Int.ediv_add_emod a (2 ^ 135) + have h2 := Int.emod_nonneg a (by norm_num : (2 : Int) ^ 135 ≠ 0) + have h3 := Int.emod_lt_of_pos a (by norm_num : (0 : Int) < 2 ^ 135) constructor <;> nlinarith [h1, h2, h3] -/-- The squared-argument step width `W = ⌊(G + 1)/2^5⌋ + 1`: one `v` unit is `2^133` of `t²`, so -the reduced-argument step `G + 1` moves `v` by at most `(G + 1)·2^128/2^133` plus one floor unit. -/ +/-- The squared-argument step width `W = ⌊(G + 1)/2^6⌋ + 1`: one `v` unit is `2^135` of `t²`, so +the reduced-argument step `G + 1` moves `v` by at most `(G + 1)·2^129/2^135` plus one floor unit. -/ def Wstep : Nat := 10633823967 -theorem Wstep_eq : Wstep = (Gstep + 1) / 2 ^ 5 + 1 := by unfold Wstep Gstep; rfl +theorem Wstep_eq : Wstep = (Gstep + 1) / 2 ^ 6 + 1 := by unfold Wstep Gstep; rfl /-- The squared-argument step for adjacent same-octave inputs is bounded by `W`. -/ theorem vTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) @@ -98,17 +98,17 @@ theorem vTree_step {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) obtain ⟨hvlo1, hvhi1⟩ := vTree_sandwich hx1 hC1 hC01 obtain ⟨hvlo2, hvhi2⟩ := vTree_sandwich hx2 hC2 hC02 have hGpos : (0 : Int) ≤ Gstep := by unfold Gstep; norm_num - have hp127 : (2 : Int) ^ 127 = 170141183460469231731687303715884105728 := by norm_num - have hp133 : (2 : Int) ^ 133 = 10889035741470030830827987437816582766592 := by norm_num - rw [hp127] at htlo1 hthi1 htlo2 hthi2 - rw [hp133] at hvlo1 hvhi1 hvlo2 hvhi2 + have hp128 : (2 : Int) ^ 128 = 340282366920938463463374607431768211456 := by norm_num + have hp135 : (2 : Int) ^ 135 = 43556142965880123323311949751266331066368 := by norm_num + rw [hp128] at htlo1 hthi1 htlo2 hthi2 + rw [hp135] at hvlo1 hvhi1 hvlo2 hvhi2 set t1 := int256 (tTree x1) set t2 := int256 (tTree x2) set v1 := (vTree x1 : Int) set v2 := (vTree x2 : Int) - -- `t2² − t1² = (t2 − t1)(t2 + t1)`, with `|t2 − t1| ≤ G + 1`, `|t1 + t2| < 2^128`. + -- `t2² − t1² = (t2 − t1)(t2 + t1)`, with `|t2 − t1| ≤ G + 1`, `|t1 + t2| < 2^129`. have hsqdiff : t2 ^ 2 - t1 ^ 2 = (t2 - t1) * (t2 + t1) := by ring - have hGv : (Gstep : Int) = 340282366920 := by unfold Gstep; norm_num + have hGv : (Gstep : Int) = 680564733841 := by unfold Gstep; norm_num have hWv : (Wstep : Int) = 10633823967 := by unfold Wstep; norm_num rw [hGv] at htg1 htg2 rw [hWv] diff --git a/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean b/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean index c2c306b2a..7ca8acf50 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Lipschitz.lean @@ -22,7 +22,7 @@ open FormalYul.Preservation set_option maxRecDepth 100000 /-- The per-step reduced-argument gap `G = ⌊K27 / 2^107⌋`. -/ -def Gstep : Nat := 340282366920 +def Gstep : Nat := 680564733841 /-- Floored sum bound: `⌊(b + n)/d⌋ ≤ ⌊b/d⌋ + ⌊n/d⌋ + 1`. The two truncations of the split lose at most one unit jointly. -/ diff --git a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean index 49b65edc8..c4ec42c56 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Octave.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Octave.lean @@ -25,7 +25,7 @@ theorem region_x_bound {x : Nat} (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : -(2 ^ 96 : Int) < int256 x ∧ int256 x < 2 ^ 96 := by rw [int256_Cmask] at hC - have hC0' : int256 x < 44707993146116472457411471835 := by + have hC0' : int256 x < 45401140326676417766828703956 := by rw [int256_C0thresh] at hC0 exact hC0 constructor <;> [skip; skip] <;> simp only [show (2:Int)^96 = 79228162514264337593543950336 from by norm_num] <;> omega @@ -123,13 +123,13 @@ theorem kTree_mono {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hpow : (0 : Int) < 2 ^ 192 := by norm_num nlinarith [hlo1, hhi2, hargle, hpow] -/-- On the meaningful region the octave index is bounded: `-61 ≤ k ≤ 64`. -/ +/-- On the meaningful region the octave index is bounded: `-61 ≤ k ≤ 65`. -/ theorem kTree_bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - -61 ≤ int256 (kTree x) ∧ int256 (kTree x) ≤ 64 := by + -61 ≤ int256 (kTree x) ∧ int256 (kTree x) ≤ 65 := by obtain ⟨hlo, hhi⟩ := kTree_sandwich hx hC hC0 have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh + have hC0i : int256 C0thresh = 45401140326676417766828703956 := int256_C0thresh rw [hCi] at hC rw [hC0i] at hC0 have hcinv : (0x724d54edbacbebbb95c52a0f60 : Int) = 9055943544797870567083544809312 := by @@ -139,7 +139,7 @@ theorem kTree_bound {x : Nat} (hx : x < 2 ^ 256) 0x724d54edbacbebbb95c52a0f60 * (-41446531673892822312323846185) := by rw [hcinv]; nlinarith [hC] have hprod_hi : (0x724d54edbacbebbb95c52a0f60 : Int) * int256 x < - 0x724d54edbacbebbb95c52a0f60 * 44707993146116472457411471835 := by + 0x724d54edbacbebbb95c52a0f60 * 45401140326676417766828703956 := by rw [hcinv]; nlinarith [hC0] constructor · nlinarith [hhi, hprod_lo] @@ -156,7 +156,7 @@ theorem int256_tArg {x : Nat} (hx : x < 2 ^ 256) 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x - 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) := by have hCi : int256 Cmask = -41446531673892822312323846185 := int256_Cmask - have hC0i : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh + have hC0i : int256 C0thresh = 45401140326676417766828703956 := int256_C0thresh have hxr := hC; rw [hCi] at hxr have hxr0 := hC0; rw [hC0i] at hxr0 obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 @@ -183,17 +183,17 @@ theorem tArg_lt {x : Nat} : (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d (kTree x)) < 2 ^ 256 := evmSub_lt _ _ -/-- `t = sar(107, tArg)` floor sandwich: `2^107·t ≤ K27·x − LN2·k < 2^107·t + 2^107`. -/ +/-- `t = sar(106, tArg)` floor sandwich: `2^106·t ≤ K27·x − LN2·k < 2^106·t + 2^106`. -/ theorem tTree_sandwich {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (2 ^ 107 : Int) * int256 (tTree x) ≤ + (2 ^ 106 : Int) * int256 (tTree x) ≤ 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x - 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) ∧ 0x279d346de4781f921dd7a89933d54d1f72928 * int256 x - 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x) < - (2 ^ 107 : Int) * int256 (tTree x) + 2 ^ 107 := by + (2 ^ 106 : Int) * int256 (tTree x) + 2 ^ 106 := by unfold tTree - obtain ⟨_, hlo, hhi⟩ := evmSar_sandwich (s := 0x6b) (by norm_num) (tArg_lt (x := x)) + obtain ⟨_, hlo, hhi⟩ := evmSar_sandwich (s := 0x6a) (by norm_num) (tArg_lt (x := x)) rw [int256_tArg hx hC hC0] at hlo hhi exact ⟨by simpa using hlo, by simpa using hhi⟩ @@ -214,7 +214,7 @@ theorem tTree_mono_sameOctave {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d * int256 (kTree x2) := by have := mul_le_mul_left_nonneg hle (le_of_lt hk27) omega - have hpow : (0 : Int) < 2 ^ 107 := by norm_num + have hpow : (0 : Int) < 2 ^ 106 := by norm_num nlinarith [hlo1, hhi2, hargle, hpow] end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean index 7b58a88f4..522af4739 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Quot.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Quot.lean @@ -3,7 +3,7 @@ import ExpProof.Mono.Stages /-! # The reciprocal-symmetric quotient stage -From the stage bounds this file assembles the closing quotient `r0 = exp(t)·2^126`: +From the stage bounds this file assembles the closing quotient `r0 = ⌊scaleQ67·exp(t)⌋`: * `tod = ⌊t·Od / 2^129⌋` transported to `Int`, with `|tod| < 2^126`; * the numerator `num = ev + tod` and denominator `den = ev − tod` are strictly positive (the @@ -36,14 +36,14 @@ theorem int256_eq_of_nonneg {w : Nat} (hw : w < 2 ^ 256) (hnn : 0 ≤ int256 w) /-! ## `tod = t·Od` in Q88 -/ /-- `tod` transported to `Int`: a signed floor with `|tod| < 2^126`. The product `t·Od` fits a word -(`|t| < 2^127`, `Od < 5·2^125`, so `|t·Od| < 5·2^252`). -/ +(`|t| < 2.4·10³⁸`, `Od < 5·2^125`, so `|t·Od| < 29·2^250`). -/ theorem todTree_bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : -(2 ^ 126 : Int) ≤ int256 (todTree x) ∧ int256 (todTree x) < 2 ^ 126 ∧ (2 ^ 129 : Int) * int256 (todTree x) ≤ int256 (tTree x) * (odTree x : Int) ∧ int256 (tTree x) * (odTree x : Int) < (2 ^ 129 : Int) * int256 (todTree x) + 2 ^ 129 := by - obtain ⟨htlo, hthi⟩ := tTree_bound hx hC hC0 + obtain ⟨htlo, hthi⟩ := tTree_bound_sharp hx hC hC0 obtain ⟨_, hvlt⟩ := vTree_eq hx hC hC0 have hodlt : odTree x < 5 * 2 ^ 125 := odTree_lt hvlt have htw : tTree x < 2 ^ 256 := by unfold tTree; exact evmSar_lt _ _ @@ -56,16 +56,13 @@ theorem todTree_bound {x : Nat} (hx : x < 2 ^ 256) have hod_nn : 0 ≤ (odTree x : Int) := by positivity have hod_ub : (odTree x : Int) < 5 * 2 ^ 125 := by exact_mod_cast hodlt -- the product t·od fits - have hp127 : (2:Int)^127 = 170141183460469231731687303715884105728 := by norm_num have hp126 : (2:Int)^126 = 85070591730234615865843651857942052864 := by norm_num - have hp252 : (5:Int) * 2^252 = 36185027886661311069865932815214971204146870208012676262330495002472853012480 := by norm_num + have hp252 : (29:Int) * 2^250 = 52468290435658901051305602582061708246012961801618380580379217753585636868096 := by norm_num have hp255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by norm_num - have hprod_lt : t * (odTree x : Int) < 5 * 2 ^ 252 := by - rw [hp127] at htlo hthi + have hprod_lt : t * (odTree x : Int) < 29 * 2 ^ 250 := by rw [show (5:Int) * 2 ^ 125 = 212676479325586539664609129644855132160 by norm_num] at hod_ub rw [hp252]; nlinarith [htlo, hthi, hod_nn, hod_ub] - have hprod_gt : -(5 * 2 ^ 252 : Int) < t * (odTree x : Int) := by - rw [hp127] at htlo hthi + have hprod_gt : -(29 * 2 ^ 250 : Int) < t * (odTree x : Int) := by rw [show (5:Int) * 2 ^ 125 = 212676479325586539664609129644855132160 by norm_num] at hod_ub rw [hp252]; nlinarith [htlo, hthi, hod_nn, hod_ub] -- transport the multiply @@ -83,9 +80,9 @@ theorem todTree_bound {x : Nat} (hx : x < 2 ^ 256) unfold todTree; rfl rw [htodeq] refine ⟨?_, ?_, hsl, hsh⟩ - · -- lower bound: 2^129·tod ≤ t·od and t·od > -5·2^252 ⇒ tod > -2^126 + · -- lower bound: 2^129·tod ≤ t·od and t·od > -29·2^250 ⇒ tod > -2^126 nlinarith [hsl, hprod_gt, hp252] - · -- upper bound: t·od < 2^129·tod + 2^129 and t·od < 5·2^252 ⇒ tod < 2^126 + · -- upper bound: t·od < 2^129·tod + 2^129 and t·od < 29·2^250 ⇒ tod < 2^126 nlinarith [hsh, hprod_lt, hp252] /-! ## Numerator and denominator -/ @@ -93,8 +90,8 @@ theorem todTree_bound {x : Nat} (hx : x < 2 ^ 256) /-- Abstract numerator/denominator positivity: stated over opaque words `E` (the even accumulator) and `TD` (the signed `t·Od` shift) with their bounds, so the deep Horner tree is never forced. -/ theorem numden_pos_of {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) - (hev_lo : (207573926795459379279817565122117813128 : Int) ≤ (E : Int)) - (hev_hi : (E : Int) < 3 * 2 ^ 126) + (hev_lo : (415147853590918758559635130244235626256 : Int) ≤ (E : Int)) + (hev_hi : (E : Int) < 3 * 2 ^ 127) (htod_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD) (htod_hi : int256 TD < 85070591730234615865843651857942052864) : int256 (evmAdd E TD) = (E : Int) + int256 TD ∧ @@ -103,11 +100,11 @@ theorem numden_pos_of {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) 0 < (E : Int) - int256 TD := by have hevi : int256 E = (E : Int) := int256_of_lt (by have hEc : (E : Int) < ((2 ^ 255 : Nat) : Int) := by - have : (3 : Int) * 2 ^ 126 < ((2 ^ 255 : Nat) : Int) := by norm_num + have : (3 : Int) * 2 ^ 127 < ((2 ^ 255 : Nat) : Int) := by norm_num linarith [hev_hi] exact_mod_cast hEc) - have hp127 : (E : Int) < 255211775190703847597530955573826158592 := by - rw [show (255211775190703847597530955573826158592 : Int) = 3 * 2 ^ 126 by norm_num]; exact hev_hi + have hp127 : (E : Int) < 510423550381407695195061911147652317184 := by + rw [show (510423550381407695195061911147652317184 : Int) = 3 * 2 ^ 127 by norm_num]; exact hev_hi have hadd : int256 (evmAdd E TD) = (E : Int) + int256 TD := by have := evmAdd_transport hevw htodw (by rw [hevi]; simp only [ipow255]; omega) @@ -134,59 +131,59 @@ theorem numden_pos {x : Nat} (hx : x < 2 ^ 256) have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ refine numden_pos_of hevw htodw ?_ ?_ ?_ ?_ - · have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 by norm_num] at this + · have : (0x1385291795942d41ba5fd317688e18710 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x1385291795942d41ba5fd317688e18710 : Int) = 415147853590918758559635130244235626256 by norm_num] at this exact this - · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hev_hi - rw [show ((3 * 2 ^ 126 : Nat) : Int) = 3 * 2 ^ 126 by norm_num] at this; exact this + · have : (evTree x : Int) < ((3 * 2 ^ 127 : Nat) : Int) := by exact_mod_cast hev_hi + rw [show ((3 * 2 ^ 127 : Nat) : Int) = 3 * 2 ^ 127 by norm_num] at this; exact this · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_lo · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_hi -/-! ## The runtime quotient `r0 = ⌊(10¹⁸·2⁶⁸)·num/den⌋` -/ +/-! ## The runtime quotient `r0 = ⌊(10¹⁸·2⁶⁷)·num/den⌋` -/ -/-- Abstract scaled-quotient bounds over opaque numerator/denominator words: `⌊scaleQ68·N/D⌋` -lies in `[2^124, 2^130)`. The dividend `scaleQ68·N` fits a word (`N < 2^128`, -`scaleQ68 < 2^128`); `2^124·D < 2^252 ≤ scaleQ68·N` keeps the quotient `≥ 2^124` (comfortably -clearing the closing stage's `r0 > MARGIN`), and `N < 4·D` with `4·scaleQ68 ≤ 2^130` keeps it +/-- Abstract scaled-quotient bounds over opaque numerator/denominator words: `⌊scaleQ67·N/D⌋` +lies in `[2^124, 2^130)`. The dividend `scaleQ67·N` fits a word (`N < 2^129`, +`scaleQ67 < 2^127`); `2^124·D < 2^253 ≤ scaleQ67·N` keeps the quotient `≥ 2^124` (comfortably +clearing the closing stage's `r0 > MARGIN`), and `N < 4·D` with `4·scaleQ67 ≤ 2^130` keeps it below `2^130`. -/ -theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD : D < 2 ^ 256) +theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 129) (hDlt : D < 2 ^ 129) (hD : D < 2 ^ 256) (hDi : int256 D = (D : Int)) (hNpos : 0 < (N : Int)) (hDpos : 0 < (D : Int)) - (hNlo : 2 ^ 125 ≤ N) + (hNlo : 2 ^ 127 ≤ N) (hND : (N : Int) < 4 * (D : Int)) : - 2 ^ 124 ≤ int256 (evmDiv (evmMul scaleQ68 N) D) ∧ - int256 (evmDiv (evmMul scaleQ68 N) D) < 2 ^ 130 := by + 2 ^ 124 ≤ int256 (evmDiv (evmMul scaleQ67 N) D) ∧ + int256 (evmDiv (evmMul scaleQ67 N) D) < 2 ^ 130 := by have hNw : N < 2 ^ 256 := by have : (2:Nat) ^ 128 < 2 ^ 256 := by norm_num omega - have hsw : scaleQ68 < 2 ^ 256 := by unfold scaleQ68; norm_num - have hfit : scaleQ68 * N < 2 ^ 256 := by - have h1 : scaleQ68 * N ≤ scaleQ68 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hN) - have h2 : scaleQ68 * 2 ^ 128 < 2 ^ 256 := by unfold scaleQ68; norm_num + have hsw : scaleQ67 < 2 ^ 256 := by unfold scaleQ67; norm_num + have hfit : scaleQ67 * N < 2 ^ 256 := by + have h1 : scaleQ67 * N ≤ scaleQ67 * 2 ^ 129 := Nat.mul_le_mul_left _ (le_of_lt hN) + have h2 : scaleQ67 * 2 ^ 129 < 2 ^ 256 := by unfold scaleQ67; norm_num omega - have hmul : evmMul scaleQ68 N = scaleQ68 * N := evmMul_eq_nat hsw hNw hfit + have hmul : evmMul scaleQ67 N = scaleQ67 * N := evmMul_eq_nat hsw hNw hfit have hDnat_pos : 0 < D := by exact_mod_cast hDpos - have hdiv : evmDiv (evmMul scaleQ68 N) D = scaleQ68 * N / D := by + have hdiv : evmDiv (evmMul scaleQ67 N) D = scaleQ67 * N / D := by rw [hmul, evmDiv_eq hfit hD (by omega)] - set q := scaleQ68 * N / D with hq - have hspos : 0 < scaleQ68 := by unfold scaleQ68; norm_num + set q := scaleQ67 * N / D with hq + have hspos : 0 < scaleQ67 := by unfold scaleQ67; norm_num have hq_lt : q < 2 ^ 130 := by rw [hq, Nat.div_lt_iff_lt_mul hDnat_pos] have hND' : N < 4 * D := by have h4 : ((4 * D : Nat) : Int) = 4 * (D : Int) := by push_cast; ring rw [← h4] at hND; exact_mod_cast hND - have h1 : scaleQ68 * N < scaleQ68 * (4 * D) := (Nat.mul_lt_mul_left hspos).mpr hND' - have h2 : scaleQ68 * (4 * D) = (4 * scaleQ68) * D := by ring - have h3 : (4 * scaleQ68) * D ≤ 2 ^ 130 * D := - Nat.mul_le_mul_right _ (by unfold scaleQ68; norm_num) + have h1 : scaleQ67 * N < scaleQ67 * (4 * D) := (Nat.mul_lt_mul_left hspos).mpr hND' + have h2 : scaleQ67 * (4 * D) = (4 * scaleQ67) * D := by ring + have h3 : (4 * scaleQ67) * D ≤ 2 ^ 130 * D := + Nat.mul_le_mul_right _ (by unfold scaleQ67; norm_num) omega have hq_ge : 2 ^ 124 ≤ q := by rw [hq, Nat.le_div_iff_mul_le hDnat_pos] - have h1 : (2:Nat) ^ 124 * D ≤ 2 ^ 124 * 2 ^ 128 := Nat.mul_le_mul_left _ (le_of_lt hDlt) - have h2 : (2:Nat) ^ 124 * 2 ^ 128 ≤ scaleQ68 * 2 ^ 125 := by unfold scaleQ68; norm_num - have h3 : scaleQ68 * 2 ^ 125 ≤ scaleQ68 * N := Nat.mul_le_mul_left _ hNlo + have h1 : (2:Nat) ^ 124 * D ≤ 2 ^ 124 * 2 ^ 129 := Nat.mul_le_mul_left _ (le_of_lt hDlt) + have h2 : (2:Nat) ^ 124 * 2 ^ 129 ≤ scaleQ67 * 2 ^ 127 := by unfold scaleQ67; norm_num + have h3 : scaleQ67 * 2 ^ 127 ≤ scaleQ67 * N := Nat.mul_le_mul_left _ hNlo omega - have hqi : int256 (evmDiv (evmMul scaleQ68 N) D) = (q : Int) := by + have hqi : int256 (evmDiv (evmMul scaleQ67 N) D) = (q : Int) := by rw [hdiv] exact int256_of_lt (by have : (2:Nat) ^ 130 < 2 ^ 255 := by norm_num @@ -195,31 +192,31 @@ theorem r0Tree_bounds_of {N D : Nat} (hN : N < 2 ^ 128) (hDlt : D < 2 ^ 128) (hD exact ⟨by exact_mod_cast hq_ge, by exact_mod_cast hq_lt⟩ /-- Abstract runtime `r0` bounds over opaque even/odd words: `2^124 ≤ r0 < 2^130` with -`r0 = div(scaleQ68·(E+TD), E−TD)`. -/ +`r0 = div(scaleQ67·(E+TD), E−TD)`. -/ theorem r0Tree_bounds_ofEvTod {E TD : Nat} (hevw : E < 2 ^ 256) (htodw : TD < 2 ^ 256) - (hev_lo : (207573926795459379279817565122117813128 : Int) ≤ (E : Int)) - (hev_hi : (E : Int) < 3 * 2 ^ 126) + (hev_lo : (415147853590918758559635130244235626256 : Int) ≤ (E : Int)) + (hev_hi : (E : Int) < 3 * 2 ^ 127) (htod_lo : -(85070591730234615865843651857942052864 : Int) ≤ int256 TD) (htod_hi : int256 TD < 85070591730234615865843651857942052864) : - 2 ^ 124 ≤ int256 (evmDiv (evmMul scaleQ68 (evmAdd E TD)) (evmSub E TD)) ∧ - int256 (evmDiv (evmMul scaleQ68 (evmAdd E TD)) (evmSub E TD)) < 2 ^ 130 := by + 2 ^ 124 ≤ int256 (evmDiv (evmMul scaleQ67 (evmAdd E TD)) (evmSub E TD)) ∧ + int256 (evmDiv (evmMul scaleQ67 (evmAdd E TD)) (evmSub E TD)) < 2 ^ 130 := by obtain ⟨hadd, hsub, hnum_pos, hden_pos⟩ := numden_pos_of hevw htodw hev_lo hev_hi htod_lo htod_hi have hNwlt : evmAdd E TD < 2 ^ 256 := evmAdd_lt _ _ have hDwlt : evmSub E TD < 2 ^ 256 := evmSub_lt _ _ - have h128 : (2:Int)^128 = 340282366920938463463374607431768211456 := by norm_num - have h127 : (3:Int) * 2 ^ 126 = 255211775190703847597530955573826158592 := by norm_num + have h128 : (2:Int)^129 = 680564733841876926926749214863536422912 := by norm_num + have h127 : (3:Int) * 2 ^ 127 = 510423550381407695195061911147652317184 := by norm_num rw [h127] at hev_hi obtain ⟨hNi, hNlt255⟩ := int256_eq_of_nonneg hNwlt (by rw [hadd]; omega) obtain ⟨hDi, hDlt255⟩ := int256_eq_of_nonneg hDwlt (by rw [hsub]; omega) - have hNlt128 : evmAdd E TD < 2 ^ 128 := by - have : ((evmAdd E TD : Nat) : Int) < 2 ^ 128 := by rw [← hNi, hadd, h128]; omega + have hNlt128 : evmAdd E TD < 2 ^ 129 := by + have : ((evmAdd E TD : Nat) : Int) < 2 ^ 129 := by rw [← hNi, hadd, h128]; omega exact_mod_cast this - have hDlt128 : evmSub E TD < 2 ^ 128 := by - have : ((evmSub E TD : Nat) : Int) < 2 ^ 128 := by rw [← hDi, hsub, h128]; omega + have hDlt128 : evmSub E TD < 2 ^ 129 := by + have : ((evmSub E TD : Nat) : Int) < 2 ^ 129 := by rw [← hDi, hsub, h128]; omega exact_mod_cast this - have hNlo : 2 ^ 125 ≤ evmAdd E TD := by - have : (2 ^ 125 : Int) ≤ ((evmAdd E TD : Nat) : Int) := by - rw [← hNi, hadd, show (2:Int)^125 = 42535295865117307932921825928971026432 by norm_num] + have hNlo : 2 ^ 127 ≤ evmAdd E TD := by + have : (2 ^ 127 : Int) ≤ ((evmAdd E TD : Nat) : Int) := by + rw [← hNi, hadd, show (2:Int)^127 = 170141183460469231731687303715884105728 by norm_num] omega exact_mod_cast this have hND : ((evmAdd E TD : Nat) : Int) < 4 * ((evmSub E TD : Nat) : Int) := by @@ -236,16 +233,16 @@ theorem r0Tree_bounds {x : Nat} (hx : x < 2 ^ 256) obtain ⟨hev_lo, hev_hi⟩ := evTree_facts hvlt obtain ⟨htod_lo, htod_hi, _, _⟩ := todTree_bound hx hC hC0 have hr0 : r0Tree x = - evmDiv (evmMul scaleQ68 (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) := rfl + evmDiv (evmMul scaleQ67 (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) := rfl rw [hr0] have hevw : evTree x < 2 ^ 256 := by unfold evTree; exact evmAdd_lt _ _ have htodw : todTree x < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ refine r0Tree_bounds_ofEvTod hevw htodw ?_ ?_ ?_ ?_ - · have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo - rw [show (0x9c2948bcaca16a0dd2fe98bb4470c388 : Int) = 207573926795459379279817565122117813128 by norm_num] at this + · have : (0x1385291795942d41ba5fd317688e18710 : Int) ≤ (evTree x : Int) := by exact_mod_cast hev_lo + rw [show (0x1385291795942d41ba5fd317688e18710 : Int) = 415147853590918758559635130244235626256 by norm_num] at this exact this - · have : (evTree x : Int) < ((3 * 2 ^ 126 : Nat) : Int) := by exact_mod_cast hev_hi - rw [show ((3 * 2 ^ 126 : Nat) : Int) = 3 * 2 ^ 126 by norm_num] at this; exact this + · have : (evTree x : Int) < ((3 * 2 ^ 127 : Nat) : Int) := by exact_mod_cast hev_hi + rw [show ((3 * 2 ^ 127 : Nat) : Int) = 3 * 2 ^ 127 by norm_num] at this; exact this · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_lo · rw [show (85070591730234615865843651857942052864 : Int) = 2 ^ 126 by norm_num]; exact htod_hi diff --git a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean index 0e8188249..b673bae42 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RangeNonneg.lean @@ -5,7 +5,7 @@ import ExpProof.Mono.Quot `r1Tree x = shr(68 − k, r0 − MARGIN)` closes the kernel: the quotient already carries the `10¹⁸·2⁶⁸` output scale, so the closing stage subtracts the one-sided margin and floors with the -`2ᵏ` octave scaling folded into the shift (`68 − k ∈ [4, 129]`). +`2ᵏ` octave scaling folded into the shift (`67 − k ∈ [2, 128]`). * **nonneg**: `r0 ≥ 2^124` gives `r0 > MARGIN`, and the shift argument is nonnegative; the logical shift of a canonical nonnegative word stays nonnegative. @@ -20,35 +20,35 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-! ## The closing shift amount `68 − k` -/ +/-! ## The closing shift amount `67 − k` -/ -/-- The shift word `evmSub 0x44 k` equals `68 − int256 k` as a `Nat`, and lies in `[4, 129]` on -the meaningful region (`k ∈ [−61, 64]`). -/ +/-- The shift word `evmSub 0x43 k` equals `67 − int256 k` as a `Nat`, and lies in `[2, 128]` on +the meaningful region (`k ∈ [−61, 65]`). -/ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - ∃ s : Nat, evmSub 0x44 (kTree x) = s ∧ 4 ≤ s ∧ s ≤ 129 ∧ - (s : Int) = 68 - int256 (kTree x) := by + ∃ s : Nat, evmSub 0x43 (kTree x) = s ∧ 2 ≤ s ∧ s ≤ 128 ∧ + (s : Int) = 67 - int256 (kTree x) := by obtain ⟨hklo, hkhi⟩ := kTree_bound hx hC hC0 have hkw : kTree x < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ -- 68 (as int) - int256 k, transported through evmSub - have h68 : int256 (0x44 : Nat) = 68 := by + have h68 : int256 (0x43 : Nat) = 67 := by rw [int256_of_lt (by norm_num)]; simp have hip255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by norm_num - have hsub : int256 (evmSub 0x44 (kTree x)) = 68 - int256 (kTree x) := by - have := evmSub_transport (a := 0x44) (b := kTree x) (by norm_num) hkw + have hsub : int256 (evmSub 0x43 (kTree x)) = 67 - int256 (kTree x) := by + have := evmSub_transport (a := 0x43) (b := kTree x) (by norm_num) hkw (by rw [h68, hip255]; omega) (by rw [h68, hip255]; omega) rw [h68] at this; exact this - -- the result is a small nonnegative word, so its Nat value is 68 - int256 k - have hsublt : evmSub 0x44 (kTree x) < 2 ^ 256 := evmSub_lt _ _ - have hnn : 0 ≤ int256 (evmSub 0x44 (kTree x)) := by rw [hsub]; omega + -- the result is a small nonnegative word, so its Nat value is 67 - int256 k + have hsublt : evmSub 0x43 (kTree x) < 2 ^ 256 := evmSub_lt _ _ + have hnn : 0 ≤ int256 (evmSub 0x43 (kTree x)) := by rw [hsub]; omega obtain ⟨heq, hlt255⟩ := int256_eq_of_nonneg hsublt hnn - refine ⟨evmSub 0x44 (kTree x), rfl, ?_, ?_, ?_⟩ - · -- 4 ≤ s - have : (4 : Int) ≤ ((evmSub 0x44 (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega + refine ⟨evmSub 0x43 (kTree x), rfl, ?_, ?_, ?_⟩ + · -- 2 ≤ s + have : (2 : Int) ≤ ((evmSub 0x43 (kTree x) : Nat) : Int) := by rw [← heq, hsub]; omega exact_mod_cast this - · have : ((evmSub 0x44 (kTree x) : Nat) : Int) ≤ 129 := by rw [← heq, hsub]; omega + · have : ((evmSub 0x43 (kTree x) : Nat) : Int) ≤ 128 := by rw [← heq, hsub]; omega exact_mod_cast this · rw [← heq]; exact hsub @@ -59,11 +59,11 @@ theorem closing_shift {x : Nat} (hx : x < 2 ^ 256) and below `2^130`. -/ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) (hr0_lo : (2 ^ 124 : Int) ≤ int256 r0) (hr0_hi : int256 r0 < 2 ^ 130) : - int256 (evmSub r0 0x3) = int256 r0 - 0x3 ∧ - 0 ≤ int256 r0 - 0x3 ∧ - int256 r0 - 0x3 < 2 ^ 130 := by - have hmarlt : (0x3 : Nat) < 2 ^ 256 := by norm_num - have hmari : int256 (0x3 : Nat) = 0x3 := by + int256 (evmSub r0 0x1) = int256 r0 - 0x1 ∧ + 0 ≤ int256 r0 - 0x1 ∧ + int256 r0 - 0x1 < 2 ^ 130 := by + have hmarlt : (0x1 : Nat) < 2 ^ 256 := by norm_num + have hmari : int256 (0x1 : Nat) = 0x1 := by rw [int256_of_lt (by norm_num)]; simp have hp124 : (2:Int)^124 = 21267647932558653966460912964485513216 := by norm_num have hp130 : (2:Int)^130 = 1361129467683753853853498429727072845824 := by norm_num @@ -71,7 +71,7 @@ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) norm_num rw [hp124] at hr0_lo rw [hp130] at hr0_hi - have hsub : int256 (evmSub r0 0x3) = int256 r0 - 0x3 := by + have hsub : int256 (evmSub r0 0x1) = int256 r0 - 0x1 := by have := evmSub_transport hr0w hmarlt (by rw [hmari]; simp only [ipow255]; omega) (by rw [hmari]; simp only [ipow255]; omega) @@ -82,24 +82,24 @@ theorem shiftArg_bounds_of {r0 : Nat} (hr0w : r0 < 2 ^ 256) /-- Abstract closing-shift facts over an opaque shift argument word `W` and shift `s ∈ [4, 129]` with `int256 W ∈ [0, 2^130)`: the floor `shr(s, W)` is nonnegative and below `2^126`. -/ -theorem closingShr_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 4 ≤ s) (hshi : s ≤ 129) +theorem closingShr_facts {W s : Nat} (hWw : W < 2 ^ 256) (hslo : 2 ≤ s) (hshi : s ≤ 128) (hWnn : 0 ≤ int256 W) (hWhi : int256 W < 2 ^ 130) : - 0 ≤ int256 (evmShr s W) ∧ int256 (evmShr s W) < 2 ^ 126 := by + 0 ≤ int256 (evmShr s W) ∧ int256 (evmShr s W) < 2 ^ 128 := by obtain ⟨hWi, _⟩ := int256_eq_of_nonneg hWw hWnn have hWnat : W < 2 ^ 130 := by have : ((W : Nat) : Int) < 2 ^ 130 := by rw [← hWi]; exact hWhi exact_mod_cast this rw [evmShr_eq_div (by omega) hWw] - have hqlt : W / 2 ^ s < 2 ^ 126 := by - have h4 : (2:Nat) ^ 4 ≤ 2 ^ s := Nat.pow_le_pow_right (by norm_num) hslo - have h1 : W / 2 ^ s ≤ W / 2 ^ 4 := Nat.div_le_div_left h4 (Nat.two_pow_pos _) - have h2 : W / 2 ^ 4 < 2 ^ 126 := by + have hqlt : W / 2 ^ s < 2 ^ 128 := by + have h4 : (2:Nat) ^ 2 ≤ 2 ^ s := Nat.pow_le_pow_right (by norm_num) hslo + have h1 : W / 2 ^ s ≤ W / 2 ^ 2 := Nat.div_le_div_left h4 (Nat.two_pow_pos _) + have h2 : W / 2 ^ 2 < 2 ^ 128 := by rw [Nat.div_lt_iff_lt_mul (Nat.two_pow_pos _)] calc W < 2 ^ 130 := hWnat - _ = 2 ^ 126 * 2 ^ 4 := by rw [← Nat.pow_add] + _ = 2 ^ 128 * 2 ^ 2 := by rw [← Nat.pow_add] omega rw [int256_of_lt (by - have : (2:Nat) ^ 126 < 2 ^ 255 := by norm_num + have : (2:Nat) ^ 128 < 2 ^ 255 := by norm_num omega)] constructor · positivity @@ -118,7 +118,7 @@ theorem r1Tree_int256_nonneg {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmShr (evmSub 0x44 (kTree x)) (evmSub (r0Tree x) 0x3) := rfl + have hr1 : r1Tree x = evmShr (evmSub 0x43 (kTree x)) (evmSub (r0Tree x) 0x1) := rfl rw [hr1, hseq] exact (closingShr_facts (evmSub_lt _ _) hslo hshi (by rw [hargeq]; omega) (by rw [hargeq]; omega)).1 @@ -130,16 +130,16 @@ theorem r1Tree_range {x : Nat} (hx : x < 2 ^ 256) obtain ⟨s, hseq, hslo, hshi, _⟩ := closing_shift hx hC hC0 obtain ⟨hr0lo, hr0hi⟩ := r0Tree_bounds hx hC hC0 obtain ⟨hargeq, hargnn, harghi⟩ := shiftArg_bounds_of (r0 := r0Tree x) (r0Tree_lt x) hr0lo hr0hi - have hr1 : r1Tree x = evmShr (evmSub 0x44 (kTree x)) (evmSub (r0Tree x) 0x3) := rfl - obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (r0Tree x) 0x3) + have hr1 : r1Tree x = evmShr (evmSub 0x43 (kTree x)) (evmSub (r0Tree x) 0x1) := rfl + obtain ⟨hnn, hlt⟩ := closingShr_facts (W := evmSub (r0Tree x) 0x1) (s := s) (evmSub_lt _ _) hslo hshi (by rw [hargeq]; omega) (by rw [hargeq]; omega) -- int256 (r1Tree x) ∈ [0, 2^126) ⇒ the Nat word is < 2^254 - have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (r0Tree x) 0x3)) := by + have hReq : int256 (r1Tree x) = int256 (evmShr s (evmSub (r0Tree x) 0x1)) := by rw [hr1, hseq] rw [← hReq] at hnn hlt have hr1w : r1Tree x < 2 ^ 256 := r1Tree_lt x obtain ⟨hi, _⟩ := int256_eq_of_nonneg hr1w hnn - have hp254 : (2:Int)^126 < 2^254 := by norm_num + have hp254 : (2:Int)^128 < 2^254 := by norm_num have hcast : ((r1Tree x : Nat) : Int) < 2 ^ 254 := by rw [← hi] generalize int256 (r1Tree x) = V at hlt ⊢ diff --git a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean index 878417711..c35ce06b1 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RegionMono.lean @@ -69,7 +69,7 @@ theorem r1_step (hseamstep : SeamStep) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : /-- A signed value strictly inside the region is a canonical word with that signed value. -/ theorem region_word {v : Int} (hlo : int256 Cmask < v) (hhi : v < int256 C0thresh) : uint256OfInt v < 2 ^ 256 ∧ int256 (uint256OfInt v) = v := by - have hC0 : int256 C0thresh = 44707993146116472457411471835 := int256_C0thresh + have hC0 : int256 C0thresh = 45401140326676417766828703956 := int256_C0thresh have hCm : int256 Cmask = -41446531673892822312323846185 := int256_Cmask rw [hCm] at hlo; rw [hC0] at hhi refine ⟨uint256OfInt_lt v, ?_⟩ diff --git a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean index f990489f3..90e9cfa35 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/RunBridge.lean @@ -19,14 +19,14 @@ set_option maxRecDepth 100000 /-- `expTree x` is the inline value tree. -/ theorem run_exp_ray_to_wad_evm_eq_expTree (x : Nat) - (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : run_exp_ray_to_wad_evm x = .ok (expTree x) := by rw [run_exp_ray_to_wad_evm_eq_tree x hval] unfold expTree r1Tree r0Tree todTree odTree evTree vTree tTree kTree unfold Cmask kRoundShift kHalfShift cInvQ192 k27Q235 ln2Q235 tArgShift squareShift unfold ev0 ev1 ev2 ev3 ev4 evShift1 evShift2 evShift3 evShift4 unfold od0 od1 od2 od3 od4 odShift1 odShift2 odShift3 odShift4 - unfold todShift foldShift scaleQ68 marginWord + unfold todShift foldShift scaleQ67 marginWord rfl end ExpYul diff --git a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean index fb8d12de4..5a4a19abb 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Seam.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Seam.lean @@ -3,7 +3,7 @@ import ExpProof.Mono.RegionMono /-! # The octave-seam step from the `r0` doubling bound -Across a seam (`k` advances by one, `int256 x2 = int256 x1 + 1`) the closing shift `68 − k` drops +Across a seam (`k` advances by one, `int256 x2 = int256 x1 + 1`) the closing shift `67 − k` drops exactly one bit, so with the same shift argument `arg = r0 − MARGIN` the floor identity ``` @@ -27,8 +27,8 @@ set_option maxRecDepth 100000 /-- **The `r0` doubling bound across a seam.** For adjacent inputs crossing one octave (`int256 (kTree x2) = int256 (kTree x1) + 1`, `int256 x2 = int256 x1 + 1`), the scaled quotient at most doubles, three units short: `r0Tree x1 + 3 ≤ 2·r0Tree x2`. (Across the seam the reduced -argument flips sign `t_b ≈ −t_a`, so `r0_a ≈ exp(t_a)·scaleQ68 ≈ √2·scaleQ68` and -`r0_b ≈ exp(−t_a)·scaleQ68 ≈ scaleQ68/√2`, hence `r0_a/r0_b ≈ 2·exp(−1/RAY)`, short of doubling by +argument flips sign `t_b ≈ −t_a`, so `r0_a ≈ exp(t_a)·scaleQ67 ≈ √2·scaleQ67` and +`r0_b ≈ exp(−t_a)·scaleQ67 ≈ scaleQ67/√2`, hence `r0_a/r0_b ≈ 2·exp(−1/RAY)`, short of doubling by `≈ 2·r0_b/RAY ≈ 4·10^11` grid units — far more than the three units consumed by the seam-floor comparison below.) -/ def SeamR0Bound : Prop := @@ -75,7 +75,7 @@ theorem seam_closing_shifts {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hC1 : int256 Cmask < int256 x1) (hC01 : int256 x1 < int256 C0thresh) (hx2 : x2 < 2 ^ 256) (hC2 : int256 Cmask < int256 x2) (hC02 : int256 x2 < int256 C0thresh) (hk : int256 (kTree x2) = int256 (kTree x1) + 1) : - ∃ s1 s2 : Nat, evmSub 0x44 (kTree x1) = s1 ∧ evmSub 0x44 (kTree x2) = s2 ∧ + ∃ s1 s2 : Nat, evmSub 0x43 (kTree x1) = s1 ∧ evmSub 0x43 (kTree x2) = s2 ∧ s1 < 256 ∧ s2 < 256 ∧ s2 + 1 = s1 := by obtain ⟨s1, hs1eq, _, hs1hi, hs1int⟩ := closing_shift hx1 hC1 hC01 obtain ⟨s2, hs2eq, hs2lo, _, hs2int⟩ := closing_shift hx2 hC2 hC02 @@ -100,15 +100,15 @@ theorem seamStep_of_r0 (hr0 : SeamR0Bound) {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (h obtain ⟨harg1eq, harg1nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x1) (r0Tree_lt x1) hr0lo1 hr0hi1 obtain ⟨harg2eq, harg2nn, _⟩ := shiftArg_bounds_of (r0 := r0Tree x2) (r0Tree_lt x2) hr0lo2 hr0hi2 have hr1eq1 : r1Tree x1 = - evmShr s1 (evmSub (r0Tree x1) 0x3) := by + evmShr s1 (evmSub (r0Tree x1) 0x1) := by unfold r1Tree; rw [hs1eq] have hr1eq2 : r1Tree x2 = - evmShr s2 (evmSub (r0Tree x2) 0x3) := by + evmShr s2 (evmSub (r0Tree x2) 0x1) := by unfold r1Tree; rw [hs2eq] rw [hr1eq1, hr1eq2] -- name the deep shift arguments opaquely before feeding the floor lemma - set arg1 := evmSub (r0Tree x1) 0x3 with harg1def - set arg2 := evmSub (r0Tree x2) 0x3 with harg2def + set arg1 := evmSub (r0Tree x1) 0x1 with harg1def + set arg2 := evmSub (r0Tree x2) 0x1 with harg2def have ha1lt : arg1 < 2 ^ 256 := by rw [harg1def]; exact evmSub_lt _ _ have ha2lt : arg2 < 2 ^ 256 := by rw [harg2def]; exact evmSub_lt _ _ clear_value arg1 arg2 diff --git a/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean b/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean index d3fa6b7b3..73645d0eb 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/SeamR0.lean @@ -6,7 +6,7 @@ import ExpProof.Floor.R0ExpUnder `SeamR0Bound` (`r0Tree x1 + 3 ≤ 2·r0Tree x2` across one octave seam) is the single analytic obligation that `run_exp_ray_to_wad_evm_mono_of_seamR0` carries. The per-point real bracket -`r0Tree x ≈ scaleQ68·exp(rt)` (`Floor.R0Exp`/`Floor.R0ExpUnder`, both signs) together with the +`r0Tree x ≈ scaleQ67·exp(rt)` (`Floor.R0Exp`/`Floor.R0ExpUnder`, both signs) together with the seam exp relation `rt1 = rt2 + ln2 − 1/RAY` discharges it: `exp(rt1) = 2·exp(rt2)·exp(−1/RAY)`, and the `1 − exp(−1/RAY) ≈ 1/RAY` slack (against `r0Tree x2 > 2¹²⁶`, worth `≈ 8.5·10¹⁰` grid units) diff --git a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean index f9fdc7810..a24044720 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Stages.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Stages.lean @@ -26,14 +26,14 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-! ## The reduced-argument bound `|t| < 2^127` -/ +/-! ## The reduced-argument bound `|t| < 2^128` -/ -/-- On the meaningful region the reduced argument is bounded: `-2^127 < int256 (tTree x) < 2^127`. +/-- On the meaningful region the reduced argument is bounded: `-2^128 < int256 (tTree x) < 2^128`. The octave reduction couples `k` to `x` (`2^192·k ≈ CINV·x`), so the residual `K27·x − LN2·k` -stays inside `±ln2/2·2^235`, leaving `|t| < ln2/2·2^128 < 2^127`. -/ +stays inside `±ln2/2·2^235`, leaving `|t| < ln2/2·2^129 < 2^128`. -/ theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - -(2 ^ 127 : Int) < int256 (tTree x) ∧ int256 (tTree x) < 2 ^ 127 := by + -(2 ^ 128 : Int) < int256 (tTree x) ∧ int256 (tTree x) < 2 ^ 128 := by obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 obtain ⟨hklo, hkhi⟩ := kTree_sandwich hx hC hC0 obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 @@ -53,8 +53,8 @@ theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) set k := int256 (kTree x) set X := int256 x -- powers of two as decimals - have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num - have p127 : (2 : Int) ^ 127 = 170141183460469231731687303715884105728 := by norm_num + have p107 : (2 : Int) ^ 106 = 81129638414606681695789005144064 := by norm_num + have p127 : (2 : Int) ^ 128 = 340282366920938463463374607431768211456 := by norm_num have p199 : (2 : Int) ^ 191 = 3138550867693340381917894711603833208051177722232017256448 := by norm_num have p200 : (2 : Int) ^ 192 = @@ -88,7 +88,7 @@ theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) have hp200pos : (0 : Int) < 6277101735386680763835789423207666416102355444464034512896 := by norm_num have htlo' : 6277101735386680763835789423207666416102355444464034512896 * - (162259276829213363391578010288128 * t) ≤ + (81129638414606681695789005144064 * t) ≤ 6277101735386680763835789423207666416102355444464034512896 * (55213970774324510299478046898216203619608872 * X - 38271408169742254668347313025622401492114385419650052359639581444463709 * k) := @@ -97,7 +97,7 @@ theorem tTree_bound {x : Nat} (hx : x < 2 ^ 256) (55213970774324510299478046898216203619608872 * X - 38271408169742254668347313025622401492114385419650052359639581444463709 * k) < 6277101735386680763835789423207666416102355444464034512896 * - (162259276829213363391578010288128 * t + 162259276829213363391578010288128) := + (81129638414606681695789005144064 * t + 81129638414606681695789005144064) := by have := mul_le_mul_left_nonneg (le_of_lt hthi) (le_of_lt hp200pos) rcases lt_or_eq_of_le this with h | h @@ -114,8 +114,8 @@ Q123 square and the monic-stage multiply safety need. Same sandwich elimination closed against the sharper literal. -/ theorem tTree_bound_sharp {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - -(120000000000000000000000000000000000000 : Int) < int256 (tTree x) ∧ - int256 (tTree x) < 120000000000000000000000000000000000000 := by + -(240000000000000000000000000000000000000 : Int) < int256 (tTree x) ∧ + int256 (tTree x) < 240000000000000000000000000000000000000 := by obtain ⟨htlo, hthi⟩ := tTree_sandwich hx hC hC0 obtain ⟨hklo, hkhi⟩ := kTree_sandwich hx hC hC0 obtain ⟨hxlo, hxhi⟩ := region_x_bound hC hC0 @@ -132,7 +132,7 @@ theorem tTree_bound_sharp {x : Nat} (hx : x < 2 ^ 256) set t := int256 (tTree x) set k := int256 (kTree x) set X := int256 x - have p107 : (2 : Int) ^ 107 = 162259276829213363391578010288128 := by norm_num + have p107 : (2 : Int) ^ 106 = 81129638414606681695789005144064 := by norm_num have p199 : (2 : Int) ^ 191 = 3138550867693340381917894711603833208051177722232017256448 := by norm_num have p200 : (2 : Int) ^ 192 = @@ -162,7 +162,7 @@ theorem tTree_bound_sharp {x : Nat} (hx : x < 2 ^ 256) have hp200pos : (0 : Int) < 6277101735386680763835789423207666416102355444464034512896 := by norm_num have htlo' : 6277101735386680763835789423207666416102355444464034512896 * - (162259276829213363391578010288128 * t) ≤ + (81129638414606681695789005144064 * t) ≤ 6277101735386680763835789423207666416102355444464034512896 * (55213970774324510299478046898216203619608872 * X - 38271408169742254668347313025622401492114385419650052359639581444463709 * k) := @@ -171,7 +171,7 @@ theorem tTree_bound_sharp {x : Nat} (hx : x < 2 ^ 256) (55213970774324510299478046898216203619608872 * X - 38271408169742254668347313025622401492114385419650052359639581444463709 * k) < 6277101735386680763835789423207666416102355444464034512896 * - (162259276829213363391578010288128 * t + 162259276829213363391578010288128) := + (81129638414606681695789005144064 * t + 81129638414606681695789005144064) := by have := mul_le_mul_left_nonneg (le_of_lt hthi) (le_of_lt hp200pos) rcases lt_or_eq_of_le this with h | h @@ -184,18 +184,18 @@ theorem tTree_bound_sharp {x : Nat} (hx : x < 2 ^ 256) /-! ## `v = t²` in Q123 -/ -/-- The Q123 square `v = ⌊t²/2^133⌋` as a `Nat`: nonnegative, and `< 2^120`. The shift argument -`t·t` fits in a word because `|t| < 1.2·10^38` gives `t² < 2^253`. -/ +/-- The Q123 square `v = ⌊t²/2^135⌋` as a `Nat`: nonnegative, and `< 2^120`. The shift argument +`t·t` fits in a word because `|t| < 2.4·10^38` gives `t² < 2^255`. -/ theorem vTree_eq {x : Nat} (hx : x < 2 ^ 256) (hC : int256 Cmask < int256 x) (hC0 : int256 x < int256 C0thresh) : - (vTree x : Int) = (int256 (tTree x))^2 / 2 ^ 133 ∧ vTree x < 2 ^ 120 := by + (vTree x : Int) = (int256 (tTree x))^2 / 2 ^ 135 ∧ vTree x < 2 ^ 120 := by obtain ⟨htlo, hthi⟩ := tTree_bound_sharp hx hC hC0 have htw : tTree x < 2 ^ 256 := by unfold tTree; exact evmSar_lt _ _ -- the signed square equals the unsigned product of the canonical word with itself set t := int256 (tTree x) with htdef - have hsq_lt : t ^ 2 < 2 ^ 253 := by - have hp253 : (2:Int)^253 = 14474011154664524427946373126085988481658748083205070504932198000989141204992 := by norm_num - rw [hp253, sq] + have hsq_lt : t ^ 2 < 2 ^ 255 := by + have hp255 : (2:Int)^255 = 57896044618658097711785492504343953926634992332820282019728792003956564819968 := by norm_num + rw [hp255, sq] nlinarith [htlo, hthi] have hsq_nn : 0 ≤ t ^ 2 := by positivity -- `tTree x · tTree x` as a word equals `t²` (transport), nonneg, `< 2^253`. @@ -211,22 +211,22 @@ theorem vTree_eq {x : Nat} (hx : x < 2 ^ 256) split at h <;> simp only [ipow256] at * <;> nlinarith [hsq_nn, hsq_lt] have hmul_nat : (evmMul (tTree x) (tTree x) : Int) = t * t := by rw [← hmul]; exact (int256_of_lt hmul_small).symm - have hmul_nat_lt : evmMul (tTree x) (tTree x) < 2 ^ 253 := by - have : ((evmMul (tTree x) (tTree x) : Nat) : Int) < 2 ^ 253 := by + have hmul_nat_lt : evmMul (tTree x) (tTree x) < 2 ^ 255 := by + have : ((evmMul (tTree x) (tTree x) : Nat) : Int) < 2 ^ 255 := by rw [hmul_nat, ← sq]; exact hsq_lt exact_mod_cast this refine ⟨?_, ?_⟩ · unfold vTree rw [evmShr_eq_div (by norm_num) hmul_lt] - have he : ((evmMul (tTree x) (tTree x) / 2 ^ 133 : Nat) : Int) = - (evmMul (tTree x) (tTree x) : Int) / 2 ^ 133 := by + have he : ((evmMul (tTree x) (tTree x) / 2 ^ 135 : Nat) : Int) = + (evmMul (tTree x) (tTree x) : Int) / 2 ^ 135 := by rw [Int.natCast_ediv]; norm_num rw [he, hmul_nat, ← sq] · unfold vTree rw [evmShr_eq_div (by norm_num) hmul_lt] - have : evmMul (tTree x) (tTree x) / 2 ^ 133 < 2 ^ 253 / 2 ^ 133 := + have : evmMul (tTree x) (tTree x) / 2 ^ 135 < 2 ^ 255 / 2 ^ 135 := Nat.div_lt_div_of_lt_of_dvd (by norm_num) hmul_nat_lt - have he : (2:Nat) ^ 253 / 2 ^ 133 = 2 ^ 120 := by + have he : (2:Nat) ^ 255 / 2 ^ 135 = 2 ^ 120 := by rw [Nat.pow_div (by norm_num) (by norm_num)] omega @@ -330,9 +330,9 @@ theorem pvd (pe ve sh e : Nat) (hpe : pe + ve = sh + e) : `(ev0 + v)·v` is capped by the exact literal sum `(ev0 + 2^120)·2^120 < 2^256` — it has no power-of-two headroom. -/ theorem evTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x9c2948bcaca16a0dd2fe98bb4470c388 ≤ evTree x ∧ evTree x < 3 * 2 ^ 126 := by + 0x1385291795942d41ba5fd317688e18710 ≤ evTree x ∧ evTree x < 3 * 2 ^ 127 := by have hev : evTree x = - evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -362,18 +362,18 @@ theorem evTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : (by rw [pvd 129 120 129 120 (by norm_num)]; norm_num)).2 rw [pvd 129 120 129 120 (by norm_num)] at this; omega set ev3 := evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul ev2 v)) with hev3 - have hfin := stage_bounds (c := 0x9c2948bcaca16a0dd2fe98bb4470c388) (prev := ev3) (v := v) - (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x7e) h3 hv (by norm_num) (by norm_num) - (by rw [pvd 129 120 126 123 (by norm_num)]; norm_num) - rw [pvd 129 120 126 123 (by norm_num)] at hfin + have hfin := stage_bounds (c := 0x1385291795942d41ba5fd317688e18710) (prev := ev3) (v := v) + (P := 2 ^ 129) (V := 2 ^ 120) (sh := 0x7d) h3 hv (by norm_num) (by norm_num) + (by rw [pvd 129 120 125 124 (by norm_num)]; norm_num) + rw [pvd 129 120 125 124 (by norm_num)] at hfin refine ⟨hfin.1, ?_⟩ - have : (0x9c2948bcaca16a0dd2fe98bb4470c388 : Nat) + 2 ^ 123 < 3 * 2 ^ 126 := by norm_num + have : (0x1385291795942d41ba5fd317688e18710 : Nat) + 2 ^ 124 < 3 * 2 ^ 127 := by norm_num omega -theorem evTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evTree x < 3 * 2 ^ 126 := +theorem evTree_lt {x : Nat} (hv : vTree x < 2 ^ 120) : evTree x < 3 * 2 ^ 127 := (evTree_facts hv).2 theorem evTree_ge {x : Nat} (hv : vTree x < 2 ^ 120) : - 0x9c2948bcaca16a0dd2fe98bb4470c388 ≤ evTree x := (evTree_facts hv).1 + 0x1385291795942d41ba5fd317688e18710 ≤ evTree x := (evTree_facts hv).1 /-- Two-sided bound on the odd Horner accumulator: `0x9c29… ≤ od < 5·2^125`. -/ theorem odTree_facts {x : Nat} (hv : vTree x < 2 ^ 120) : diff --git a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean index e3fc7a51a..6adeda798 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/StepMono.lean @@ -7,7 +7,7 @@ import ExpProof.Mono.RangeNonneg For two inputs adjacent in the signed order (`int256 x2 = int256 x1 + 1`) in a common octave, the quotient `r0` is nondecreasing (`r0_mono_adjacent`, via the cross inequality `tod_cross` fed to `r0_mono_of_cross`), and hence so is the closing accumulator `r1` (`r1_mono_adjacent`): with `k` -fixed the closing shift `68 − k` is fixed, and the logical-shift floor of the nondecreasing +fixed the closing shift `67 − k` is fixed, and the logical-shift floor of the nondecreasing `r0 − MARGIN` is nondecreasing. -/ @@ -47,9 +47,9 @@ theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have htodw2 : todTree x2 < 2 ^ 256 := by unfold todTree; exact evmSar_lt _ _ have hcross := tod_cross hx1 hx2 hC1 hC01 hC2 hC02 hk hadj have hr01 : r0Tree x1 = - evmDiv (evmMul scaleQ68 (evmAdd (evTree x1) (todTree x1))) (evmSub (evTree x1) (todTree x1)) := rfl + evmDiv (evmMul scaleQ67 (evmAdd (evTree x1) (todTree x1))) (evmSub (evTree x1) (todTree x1)) := rfl have hr02 : r0Tree x2 = - evmDiv (evmMul scaleQ68 (evmAdd (evTree x2) (todTree x2))) (evmSub (evTree x2) (todTree x2)) := rfl + evmDiv (evmMul scaleQ67 (evmAdd (evTree x2) (todTree x2))) (evmSub (evTree x2) (todTree x2)) := rfl rw [hr01, hr02] exact r0_mono_of_cross hevw1 htodw1 hevw2 htodw2 hev1lo hev1hi htod1lo htod1hi hev2lo hev2hi htod2lo htod2hi hcross @@ -58,7 +58,7 @@ theorem r0_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) theorem closing_shift_eq {x1 x2 : Nat} (hk : int256 (kTree x1) = int256 (kTree x2)) (hk1 : kTree x1 < 2 ^ 256) (hk2 : kTree x2 < 2 ^ 256) : - evmSub 0x44 (kTree x1) = evmSub 0x44 (kTree x2) := by + evmSub 0x43 (kTree x1) = evmSub 0x43 (kTree x2) := by -- `int256` is injective on canonical words (`[0, 2^256)`), so `k` words coincide. have hinj : ∀ a b : Nat, a < 2 ^ 256 → b < 2 ^ 256 → int256 a = int256 b → a = b := by intro a b ha hb h @@ -90,21 +90,21 @@ theorem r1_mono_adjacent {x1 x2 : Nat} (hx1 : x1 < 2 ^ 256) (hx2 : x2 < 2 ^ 256) have hk2w : kTree x2 < 2 ^ 256 := by unfold kTree; exact evmSar_lt _ _ have hseq := closing_shift_eq hk hk1w hk2w obtain ⟨s, hseqx, hslo, hshi, _⟩ := closing_shift hx1 hC1 hC01 - have hr1eq1 : r1Tree x1 = evmShr s (evmSub (r0Tree x1) 0x3) := by + have hr1eq1 : r1Tree x1 = evmShr s (evmSub (r0Tree x1) 0x1) := by unfold r1Tree; rw [hseqx] - have hr1eq2 : r1Tree x2 = evmShr s (evmSub (r0Tree x2) 0x3) := by + have hr1eq2 : r1Tree x2 = evmShr s (evmSub (r0Tree x2) 0x1) := by unfold r1Tree; rw [← hseq, hseqx] rw [hr1eq1, hr1eq2] -- the two shift arguments, transported to `Int`, are ordered (monotone `r0`) - set arg1 := evmSub (r0Tree x1) 0x3 with harg1 - set arg2 := evmSub (r0Tree x2) 0x3 with harg2 + set arg1 := evmSub (r0Tree x1) 0x1 with harg1 + set arg2 := evmSub (r0Tree x2) 0x1 with harg2 have ha1lt : arg1 < 2 ^ 256 := by rw [harg1]; exact evmSub_lt _ _ have ha2lt : arg2 < 2 ^ 256 := by rw [harg2]; exact evmSub_lt _ _ -- the deep tree behind the shift arguments is opaque from here on clear_value arg1 arg2 have hargle : int256 arg1 ≤ int256 arg2 := by rw [harg1eq, harg2eq] - exact sub_le_sub_right hr0mono 0x3 + exact sub_le_sub_right hr0mono 0x1 -- the shift arguments are nonnegative canonical words, ordered as Nats obtain ⟨he1, hlt1⟩ := int256_eq_of_nonneg ha1lt (by rw [harg1eq]; exact harg1nn) obtain ⟨he2, hlt2⟩ := int256_eq_of_nonneg ha2lt (by rw [harg2eq]; exact harg2nn) diff --git a/formal/exp/ExpProof/ExpProof/Mono/Top.lean b/formal/exp/ExpProof/ExpProof/Mono/Top.lean index 56a4cd0d6..cc5352876 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Top.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Top.lean @@ -137,15 +137,15 @@ theorem expTree_mono (H : RegionMonotonicityFacts) {x1 x2 : Nat} /-- A canonical word strictly below the supported threshold is in the non-reverting run domain. -/ theorem domain_of_below_C0 {x : Nat} (hx : x < 2 ^ 256) (h : int256 x < int256 C0thresh) : - u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ u256 x := by + u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ u256 x := by rw [u256_id hx] rw [int256_C0thresh] at h by_cases hb : x < 2 ^ 255 · left have : int256 x = (x : Int) := int256_of_lt hb rw [this] at h - have : (x : Int) < 44707993146116472457411471835 := h - have hC0 : (0x907595ccd30708cabec8a9db : Nat) = 44707993146116472457411471835 := by norm_num + have : (x : Int) < 45401140326676417766828703956 := h + have hC0 : (0x92b2f16cc66c5a4ae96e80d4 : Nat) = 45401140326676417766828703956 := by norm_num rw [hC0]; exact_mod_cast h · right; omega diff --git a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean index 0231b30dd..586af9d5c 100644 --- a/formal/exp/ExpProof/ExpProof/Mono/Tree.lean +++ b/formal/exp/ExpProof/ExpProof/Mono/Tree.lean @@ -50,7 +50,7 @@ def todTree (x : Nat) : Nat := evmSar todShift (evmMul (tTree x) (odTree x)) /-- `10¹⁸·exp(t)` on the `2⁶⁸` output grid: the numerator is pre-scaled by `10¹⁸·2⁶⁸ = 5¹⁸·2⁸⁶` before the single `DIV`. -/ def r0Tree (x : Nat) : Nat := - evmDiv (evmMul scaleQ68 (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) + evmDiv (evmMul scaleQ67 (evmAdd (evTree x) (todTree x))) (evmSub (evTree x) (todTree x)) /-- The floored, octave-scaled, margin-subtracted accumulator on the `2⁶⁸` output grid. -/ def r1Tree (x : Nat) : Nat := diff --git a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean index 948401190..ef18da487 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Guard.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Guard.lean @@ -3,7 +3,7 @@ import Common.Word /-! # The overflow-guard comparison -`fun_expRayToWad_68` branches on `iszero(slt(x, C))` with `C = 0x907595ccd30708cabec8a9db` +`fun_expRayToWad_68` branches on `iszero(slt(x, C))` with `C = 0x92b2f16cc66c5a4ae96e80d4` (the first input whose octave count reaches 65). For a signed input `x ≥ C` (with `u256 x < 2^255`, i.e. `x` a nonnegative signed value at least `C`), the signed comparison `slt(x, C)` is `0`, so the guard `iszero(slt(x, C))` is `1` and the revert @@ -18,31 +18,31 @@ open FormalYul.Preservation set_option maxRecDepth 100000 -/-- `C = 0x907595ccd30708cabec8a9db` is below `2^255` (it is `≈ 2^95`). -/ -theorem thresh_lt_pow : (0x907595ccd30708cabec8a9db : Nat) < 2 ^ 255 := by decide +/-- `C = 0x92b2f16cc66c5a4ae96e80d4` is below `2^255` (it is `≈ 2^95`). -/ +theorem thresh_lt_pow : (0x92b2f16cc66c5a4ae96e80d4 : Nat) < 2 ^ 255 := by decide /-- The overflow guard `slt(x, C)` is the word `0` for a signed input at or above the threshold, so `iszero(slt(x, C))` is `1` and the revert branch fires. -/ theorem slt_thresh_ge {x : Nat} - (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ u256 x) (h2 : u256 x < 2 ^ 255) : + (h1 : (0x92b2f16cc66c5a4ae96e80d4 : Nat) ≤ u256 x) (h2 : u256 x < 2 ^ 255) : EvmYul.UInt256.slt (EvmYul.UInt256.ofNat x) - (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db) + (EvmYul.UInt256.ofNat 0x92b2f16cc66c5a4ae96e80d4) = EvmYul.UInt256.ofNat 0 := by have hx : (EvmYul.UInt256.ofNat x).toNat = u256 x := by have := wordNat_ofNat x; simpa [wordNat] using this - have hC : (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db).toNat - = 0x907595ccd30708cabec8a9db := by - have := wordNat_ofNat 0x907595ccd30708cabec8a9db + have hC : (EvmYul.UInt256.ofNat 0x92b2f16cc66c5a4ae96e80d4).toNat + = 0x92b2f16cc66c5a4ae96e80d4 := by + have := wordNat_ofNat 0x92b2f16cc66c5a4ae96e80d4 simpa [wordNat, u256, WORD_MOD] using this - have hCb : (0x907595ccd30708cabec8a9db : Nat) < 2 ^ 255 := thresh_lt_pow + have hCb : (0x92b2f16cc66c5a4ae96e80d4 : Nat) < 2 ^ 255 := thresh_lt_pow unfold EvmYul.UInt256.slt EvmYul.UInt256.sltBool rw [hx, hC] rw [if_neg (by omega : ¬ (u256 x ≥ 2 ^ 255))] - rw [if_neg (by omega : ¬ ((0x907595ccd30708cabec8a9db : Nat) ≥ 2 ^ 255))] + rw [if_neg (by omega : ¬ ((0x92b2f16cc66c5a4ae96e80d4 : Nat) ≥ 2 ^ 255))] have hnlt : ¬ EvmYul.UInt256.ofNat x - < EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db := by + < EvmYul.UInt256.ofNat 0x92b2f16cc66c5a4ae96e80d4 := by show ¬ (EvmYul.UInt256.ofNat x).toNat - < (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db).toNat + < (EvmYul.UInt256.ofNat 0x92b2f16cc66c5a4ae96e80d4).toNat rw [hx, hC]; omega simp [EvmYul.UInt256.fromBool, hnlt] @@ -50,26 +50,26 @@ theorem slt_thresh_ge {x : Nat} (`x` either a negative signed value, `2^255 ≤ u256 x`, or a nonnegative value below `C`), so `iszero(slt(x, C))` is `0` and the panic branch is skipped (value path). -/ theorem slt_thresh_lt {x : Nat} - (hval : u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ u256 x) : + (hval : u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ u256 x) : EvmYul.UInt256.slt (EvmYul.UInt256.ofNat x) - (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db) + (EvmYul.UInt256.ofNat 0x92b2f16cc66c5a4ae96e80d4) = EvmYul.UInt256.ofNat 1 := by have hx : (EvmYul.UInt256.ofNat x).toNat = u256 x := by have := wordNat_ofNat x; simpa [wordNat] using this - have hC : (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db).toNat - = 0x907595ccd30708cabec8a9db := by - have := wordNat_ofNat 0x907595ccd30708cabec8a9db + have hC : (EvmYul.UInt256.ofNat 0x92b2f16cc66c5a4ae96e80d4).toNat + = 0x92b2f16cc66c5a4ae96e80d4 := by + have := wordNat_ofNat 0x92b2f16cc66c5a4ae96e80d4 simpa [wordNat, u256, WORD_MOD] using this - have hCb : (0x907595ccd30708cabec8a9db : Nat) < 2 ^ 255 := thresh_lt_pow + have hCb : (0x92b2f16cc66c5a4ae96e80d4 : Nat) < 2 ^ 255 := thresh_lt_pow unfold EvmYul.UInt256.slt EvmYul.UInt256.sltBool rw [hx, hC] - rw [if_neg (by omega : ¬ ((0x907595ccd30708cabec8a9db : Nat) ≥ 2 ^ 255))] + rw [if_neg (by omega : ¬ ((0x92b2f16cc66c5a4ae96e80d4 : Nat) ≥ 2 ^ 255))] rcases hval with hlt | hneg · rw [if_neg (by omega : ¬ (u256 x ≥ 2 ^ 255))] have hlt' : EvmYul.UInt256.ofNat x - < EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db := by + < EvmYul.UInt256.ofNat 0x92b2f16cc66c5a4ae96e80d4 := by show (EvmYul.UInt256.ofNat x).toNat - < (EvmYul.UInt256.ofNat 0x907595ccd30708cabec8a9db).toNat + < (EvmYul.UInt256.ofNat 0x92b2f16cc66c5a4ae96e80d4).toNat rw [hx, hC]; omega simp [EvmYul.UInt256.fromBool, hlt'] · rw [if_pos (by omega : u256 x ≥ 2 ^ 255)] diff --git a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean index 2f70eb5c5..ff00d1b2c 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Helpers.lean @@ -88,14 +88,14 @@ theorem call_cleanup_t_rational_44_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : EvmYul.Yul.call (fuel + (extra + 20)) [FormalYul.word v] - (.some "cleanup_t_rational_44707993146116472457411471835_by_1") + (.some "cleanup_t_rational_45401140326676417766828703956_by_1") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by rw [show fuel + (extra + 20) = (fuel + extra) + 20 by omega] rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, - lookup_cleanup_t_rational_44707993146116472457411471835_by_1] - simp only [yulFunction_cleanup_t_rational_44707993146116472457411471835_by_1, + lookup_cleanup_t_rational_45401140326676417766828703956_by_1] + simp only [yulFunction_cleanup_t_rational_45401140326676417766828703956_by_1, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, @@ -154,14 +154,14 @@ theorem call_convert_44_to_int256_direct (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) : EvmYul.Yul.call (fuel + (extra + 120)) [FormalYul.word v] - (.some "convert_t_rational_44707993146116472457411471835_by_1_to_t_int256") + (.some "convert_t_rational_45401140326676417766828703956_by_1_to_t_int256") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word v]) := by rw [show fuel + (extra + 120) = (fuel + extra) + 120 by omega] rw [EvmYul.Yul.call.eq_def] simp only [hlookup, Option.getD_some, yulContract_functions, - lookup_convert_t_rational_44707993146116472457411471835_by_1_to_t_int256] - simp only [yulFunction_convert_t_rational_44707993146116472457411471835_by_1_to_t_int256, + lookup_convert_t_rational_45401140326676417766828703956_by_1_to_t_int256] + simp only [yulFunction_convert_t_rational_45401140326676417766828703956_by_1_to_t_int256, FormalYul.Preservation.functionDefinition_params_def, FormalYul.Preservation.functionDefinition_rets_def, FormalYul.Preservation.functionDefinition_body_def, diff --git a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean index 9b4becfc4..5a42c6b68 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Revert.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Revert.lean @@ -64,7 +64,7 @@ theorem call_fun_expRayToWad_68_revert_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) - (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) + (h1 : (0x92b2f16cc66c5a4ae96e80d4 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : EvmYul.Yul.call (fuel + (extra + 1000)) [FormalYul.word x] (.some "fun_expRayToWad_68") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = @@ -78,7 +78,7 @@ theorem call_fun_expRayToWad_68_revert_direct FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have hconv44 := - call_convert_44_to_int256_direct (v := 0x907595ccd30708cabec8a9db) (fuel := fuel + extra) (extra := 867) + call_convert_44_to_int256_direct (v := 0x92b2f16cc66c5a4ae96e80d4) (fuel := fuel + extra) (extra := 867) (shared := shared) (hlookup := hlookup) have hcleanup := call_cleanup_t_int256_direct (v := x) (fuel := fuel + extra) (extra := 965) @@ -111,7 +111,7 @@ theorem call_fun_wrap_expRayToWad_revert_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) - (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) + (h1 : (0x92b2f16cc66c5a4ae96e80d4 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : EvmYul.Yul.call (fuel + (extra + 1200)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_97") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = @@ -144,7 +144,7 @@ set_option maxHeartbeats 8000000 in reverts for out-of-range `x`. -/ theorem external_fun_wrap_expRayToWad_calldata_revert (x : Nat) (store : EvmYul.Yul.VarStore) - (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) + (h1 : (0x92b2f16cc66c5a4ae96e80d4 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) = @@ -187,7 +187,7 @@ set_option maxHeartbeats 8000000 in (free-pointer `mstore` baked into a `SharedState.mk`, with the extracted `selector` in the store). -/ theorem external_fun_wrap_expRayToWad_dispatcher_state_revert (x : Nat) - (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) + (h1 : (0x92b2f16cc66c5a4ae96e80d4 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok @@ -228,7 +228,7 @@ set_option maxHeartbeats 8000000 in `expRayToWad` reverts: the EVM run of the `ExpWrapper` returns `.error "revert"`. -/ theorem run_exp_ray_to_wad_evm_revert (x : Nat) - (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) + (h1 : (0x92b2f16cc66c5a4ae96e80d4 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : run_exp_ray_to_wad_evm x = .error "revert" := by have hexec : diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index a43b4e26e..16e2e0c5d 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -70,7 +70,7 @@ theorem call_fun_expRayToWad_68_zero_direct FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have hconv44 := - call_convert_44_to_int256_direct (v := 0x907595ccd30708cabec8a9db) (fuel := fuel + extra) (extra := 767) + call_convert_44_to_int256_direct (v := 0x92b2f16cc66c5a4ae96e80d4) (fuel := fuel + extra) (extra := 767) (shared := shared) (hlookup := hlookup) have hcleanup := call_cleanup_t_int256_direct (v := 0) (fuel := fuel + extra) (extra := 865) @@ -415,10 +415,10 @@ theorem call_fun__expRayToWad_78_direct (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) - let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + let v := evmShr 0x87 (evmMul t t) + let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -429,8 +429,8 @@ theorem call_fun__expRayToWad_78_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) + let r0 := evmDiv (evmMul 0x6f05b59d3b2000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x43 k) (evmSub r0 0x1) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by @@ -474,15 +474,15 @@ theorem call_fun_expRayToWad_68_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) - (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : EvmYul.Yul.call (fuel + (extra + 900)) [FormalYul.word x] (.some "fun_expRayToWad_68") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) - let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + let v := evmShr 0x87 (evmMul t t) + let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -493,8 +493,8 @@ theorem call_fun_expRayToWad_68_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) + let r0 := evmDiv (evmMul 0x6f05b59d3b2000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x43 k) (evmSub r0 0x1) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by @@ -507,7 +507,7 @@ theorem call_fun_expRayToWad_68_direct FormalYul.Preservation.functionDefinition_body_def, EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] have hconv44 := - call_convert_44_to_int256_direct (v := 0x907595ccd30708cabec8a9db) (fuel := fuel + extra) (extra := 767) + call_convert_44_to_int256_direct (v := 0x92b2f16cc66c5a4ae96e80d4) (fuel := fuel + extra) (extra := 767) (shared := shared) (hlookup := hlookup) have hcleanup := call_cleanup_t_int256_direct (v := x) (fuel := fuel + extra) (extra := 865) @@ -537,15 +537,15 @@ theorem call_fun_wrap_expRayToWad_direct (x fuel extra : Nat) (shared : EvmYul.SharedState .Yul) (store : EvmYul.Yul.VarStore) (hlookup : shared.accountMap.find? shared.executionEnv.codeOwner = some (FormalYul.accountFor yulContract)) - (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : EvmYul.Yul.call (fuel + (extra + 1100)) [FormalYul.word x] (.some "fun_wrap_expRayToWad_97") (.some yulContract) (EvmYul.Yul.State.Ok shared store) = .ok (EvmYul.Yul.State.Ok shared store, [FormalYul.word ( let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) - let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + let v := evmShr 0x87 (evmMul t t) + let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -556,8 +556,8 @@ theorem call_fun_wrap_expRayToWad_direct (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) + let r0 := evmDiv (evmMul 0x6f05b59d3b2000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x43 k) (evmSub r0 0x1) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) )]) := by @@ -590,7 +590,7 @@ set_option maxHeartbeats 16000000 in `evm*` tree. -/ theorem external_fun_wrap_expRayToWad_calldata_result (x : Nat) (store : EvmYul.Yul.VarStore) - (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : ((match EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) @@ -602,10 +602,10 @@ theorem external_fun_wrap_expRayToWad_calldata_result Except String Nat) = .ok ( let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) - let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + let v := evmShr 0x87 (evmMul t t) + let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -616,8 +616,8 @@ theorem external_fun_wrap_expRayToWad_calldata_result (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) + let r0 := evmDiv (evmMul 0x6f05b59d3b2000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x43 k) (evmSub r0 0x1) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by @@ -631,10 +631,10 @@ theorem external_fun_wrap_expRayToWad_calldata_result EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] set tree : Nat := (let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) - let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + let v := evmShr 0x87 (evmMul t t) + let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -645,8 +645,8 @@ theorem external_fun_wrap_expRayToWad_calldata_result (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) + let r0 := evmDiv (evmMul 0x6f05b59d3b2000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x43 k) (evmSub r0 0x1) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1)) with htree @@ -717,7 +717,7 @@ set_option maxHeartbeats 16000000 in /-- The external entrypoint halts (returns) for a signed input below the threshold. -/ theorem external_fun_wrap_expRayToWad_calldata_halts (x : Nat) (store : EvmYul.Yul.VarStore) - (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : ∃ state value, EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok (expSharedAfterFreePtr x) store) = @@ -732,10 +732,10 @@ theorem external_fun_wrap_expRayToWad_calldata_halts EvmYul.Yul.State.initcall, EvmYul.Yul.State.mkOk] set tree : Nat := (let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) - let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + let v := evmShr 0x87 (evmMul t t) + let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -746,8 +746,8 @@ theorem external_fun_wrap_expRayToWad_calldata_halts (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) + let r0 := evmDiv (evmMul 0x6f05b59d3b2000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x43 k) (evmSub r0 0x1) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1)) with htree @@ -806,7 +806,7 @@ set_option maxHeartbeats 16000000 in /-- Result from the dispatcher-handed state. -/ theorem external_fun_wrap_expRayToWad_dispatcher_state_result (x : Nat) - (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : ((match EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok @@ -838,10 +838,10 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result Except String Nat) = .ok ( let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) - let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + let v := evmShr 0x87 (evmMul t t) + let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -852,8 +852,8 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) + let r0 := evmDiv (evmMul 0x6f05b59d3b2000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x43 k) (evmSub r0 0x1) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by @@ -872,7 +872,7 @@ set_option maxHeartbeats 16000000 in /-- Halt from the dispatcher-handed state. -/ theorem external_fun_wrap_expRayToWad_dispatcher_state_halts (x : Nat) - (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : ∃ state value, EvmYul.Yul.call 999989 [] (.some yulName_external_fun_wrap_expRayToWad) (.some yulContract) (EvmYul.Yul.State.Ok @@ -914,13 +914,13 @@ set_option maxHeartbeats 16000000 in the runtime floor and monotonicity claims at the run level. -/ theorem run_exp_ray_to_wad_evm_eq_tree (x : Nat) - (hval : FormalYul.u256 x < 0x907595ccd30708cabec8a9db ∨ 2 ^ 255 ≤ FormalYul.u256 x) : + (hval : FormalYul.u256 x < 0x92b2f16cc66c5a4ae96e80d4 ∨ 2 ^ 255 ≤ FormalYul.u256 x) : run_exp_ray_to_wad_evm x = .ok ( let k := evmSar 0xc0 (evmAdd (evmShl 0xbf 1) (evmMul 0x724d54edbacbebbb95c52a0f60 x)) - let t := evmSar 0x6b (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) + let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) - let v := evmShr 0x85 (evmMul t t) - let ev := evmAdd 0x9c2948bcaca16a0dd2fe98bb4470c388 (evmShr 0x7e (evmMul + let v := evmShr 0x87 (evmMul t t) + let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -931,8 +931,8 @@ theorem run_exp_ray_to_wad_evm_eq_tree (evmAdd 0xc926ddbecdeeb42e68cd16db7ed378 (evmShr 0x7e (evmMul 0xdc07aff8276bde9a361278df6a10 v))) v))) v))) v)) let tod := evmSar 0x81 (evmMul t od) - let r0 := evmDiv (evmMul 0xde0b6b3a764000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) - let r1 := evmShr (evmSub 0x44 k) (evmSub r0 0x3) + let r0 := evmDiv (evmMul 0x6f05b59d3b2000000000000000000000 (evmAdd ev tod)) (evmSub ev tod) + let r1 := evmShr (evmSub 0x43 k) (evmSub r0 0x1) evmAdd (evmIszero x) (evmMul (evmSlt (evmSub 0x00 0x85ebc478242540a11f5f1029) x) r1) ) := by diff --git a/formal/exp/ExpProof/ExpProof/Theorems.lean b/formal/exp/ExpProof/ExpProof/Theorems.lean index 7ed565fb6..79940ed6d 100644 --- a/formal/exp/ExpProof/ExpProof/Theorems.lean +++ b/formal/exp/ExpProof/ExpProof/Theorems.lean @@ -20,7 +20,7 @@ stray `sorry` (or any new axiom) breaks the build. | Property | Theorem | |---------------------------------------------------|--------------------------------------------------| -| Reverts on inputs ≥ `0x907595ccd30708cabec8a9db` | `run_exp_ray_to_wad_evm_revert` | +| Reverts on inputs ≥ `0x92b2f16cc66c5a4ae96e80d4` | `run_exp_ray_to_wad_evm_revert` | | Scale point: `expRayToWad(0) = 10^18` | `run_exp_ray_to_wad_evm_zero` | | Value path reduces to the `evm*` tree | `run_exp_ray_to_wad_evm_eq_tree` | | Never over / floor-or-one-less: `r ≤ E < r + 2` | `run_exp_ray_to_wad_evm_floorOrOneLess_uncond` | @@ -33,7 +33,7 @@ reduced to the octave-seam `r0` doubling bound `SeamR0Bound`) is discharged by `seamR0Bound_holds`; the floor brackets consume the discharged accumulator facts (`accumReal_over`, `accumReal_under`, `belowC_target_lt_one`) directly. -The supported-range threshold is `0x907595ccd30708cabec8a9db`; at or above it (and below `2^255`, +The supported-range threshold is `0x92b2f16cc66c5a4ae96e80d4`; at or above it (and below `2^255`, i.e. for any non-negative `int256` that large) the wrapper run halts with `revert`. At the scale point `x = 0` the run returns the wad unit `10^18` exactly. For any signed input strictly below the threshold the run returns the inline `evm*` arithmetic tree (the handle for the floor/monotone/bound @@ -46,7 +46,7 @@ open FormalYul /-- Reverts above the supported range. -/ example (x : Nat) - (h1 : (0x907595ccd30708cabec8a9db : Nat) ≤ FormalYul.u256 x) + (h1 : (0x92b2f16cc66c5a4ae96e80d4 : Nat) ≤ FormalYul.u256 x) (h2 : FormalYul.u256 x < 2 ^ 255) : run_exp_ray_to_wad_evm x = .error "revert" := run_exp_ray_to_wad_evm_revert x h1 h2 @@ -128,7 +128,7 @@ example (x : Nat) (hx : x < 2 ^ 256) Proved directly and axiom-clean: * `tTree_in_cert_domain` — the runtime reduced argument stays in the certificate domain - `|tTree x| ≤ H128`, so the Taylor caps (`Floor.CapsV`) instantiate at `t := tTree x`; + `|tTree x| ≤ H129`, so the Taylor caps (`Floor.CapsV`) instantiate at `t := tTree x`; * `evTree_bracket` / `odTree_bracket` — the Horner-truncation bridge: the runtime even/odd accumulators bracket the exact integer polynomials `evNumV`/`odNumV` (in `v = vTree x`) within `≈1.008`/`≈1.002` units at the cleared scales `2^528`/`2^510`; @@ -138,8 +138,8 @@ Proved directly and axiom-clean: example {x : Nat} (hx : x < 2 ^ 256) (hC : FormalYul.Preservation.int256 Cmask < FormalYul.Preservation.int256 x) (hC0 : FormalYul.Preservation.int256 x < FormalYul.Preservation.int256 C0thresh) : - -(117932881612756647068972071382077242199 : Int) ≤ FormalYul.Preservation.int256 (tTree x) ∧ - FormalYul.Preservation.int256 (tTree x) ≤ 117932881612756647068972071382077242199 := + -(235865763225513294137944142764154484399 : Int) ≤ FormalYul.Preservation.int256 (tTree x) ∧ + FormalYul.Preservation.int256 (tTree x) ≤ 235865763225513294137944142764154484399 := tTree_in_cert_domain hx hC hC0 /-- info: 'ExpYul.tTree_in_cert_domain' depends on axioms: [propext, Classical.choice, Quot.sound] -/ diff --git a/formal/exp/ExpProof/GenExpVLit.lean b/formal/exp/ExpProof/GenExpVLit.lean index c6b31ea38..c67faa9a1 100644 --- a/formal/exp/ExpProof/GenExpVLit.lean +++ b/formal/exp/ExpProof/GenExpVLit.lean @@ -112,13 +112,13 @@ def dUnderPEqTac : String := IO.FS.writeFile "ExpProof/Cert/ExpVCertLit.lean" (lits ++ "end ExpCertV\n") IO.println "v-form literals written" emit "certExpUpLit" "ExpVUp" "ExpVUpC" "expVUp_cell" "certExpUp_eq" "expVUpLit_nonneg" - "expVUp_nonneg" "certExpUp" upEqTac cUp 0 (H128 : Int) + "expVUp_nonneg" "certExpUp" upEqTac cUp 0 (H129 : Int) emit "certExpLoLit" "ExpVLo" "ExpVLoC" "expVLo_cell" "certExpLo_eq" "expVLoLit_nonneg" - "expVLo_nonneg" "certExpLo" loEqTac cLo 0 (H128 : Int) + "expVLo_nonneg" "certExpLo" loEqTac cLo 0 (H129 : Int) emit "numExpVLit" "ExpVNum" "ExpVNumC" "expVNum_cell" "numExpV_eq" "numExpVLit_nonneg" - "numExpV_nonneg" "numExpV" numEqTac (ptrim numExpV) 0 (H128 : Int) + "numExpV_nonneg" "numExpV" numEqTac (ptrim numExpV) 0 (H129 : Int) emit "certDenM1Lit" "ExpVDenM1" "ExpVDenM1C" "expVDenM1_cell" "certDenM1_eq" "denM1VLit_nonneg" - "denM1V_nonneg" "certDenM1" denM1EqTac (ptrim certDenM1) 0 (H128 : Int) + "denM1V_nonneg" "certDenM1" denM1EqTac (ptrim certDenM1) 0 (H129 : Int) emit "certDOverLit" "ExpVDOver" "ExpVDOverC" "expVDOver_cell" "certDOver_eq" "dOverVLit_nonneg" "dOverV_nonneg" "certDOver" dOverEqTac (ptrim certDOver) 0 ((vmaxV : Int) + 1) for (p, i) in granPieces.zipIdx do diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 705bd291c..7dc3bfd72 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -12,11 +12,11 @@ library Exp { /// expRayToWad(x₁) ≤ expRayToWad(x₂). For "central" inputs 707106781186547525 ≤ w ≤ /// 1414213562373095048, `expRayToWad(lnWadToRay(w)) == w - 1`, except at w = 10¹⁸ where it /// returns w. Reverts with `Panic(17)` when x is large enough to leave the supported range - /// (x ≥ 0x907595ccd30708cabec8a9db ≈ 44.71 ⋅ 10²⁷, i.e. E ≳ 2.61 ⋅ 10³⁷). + /// (x ≥ 0x92b2f16cc66c5a4ae96e80d4 ≈ 45.40 ⋅ 10²⁷, i.e. E ≳ 5.22 ⋅ 10³⁷). function expRayToWad(int256 x) internal pure returns (int256) { - // At this input the octave count k = round(x / (10²⁷⋅ln(2))) reaches 65, where the deficit + // At this input the octave count k = round(x / (10²⁷⋅ln(2))) reaches 66, where the deficit // envelope below exceeds 1ulp. - if (x >= 0x907595ccd30708cabec8a9db) { + if (x >= 0x92b2f16cc66c5a4ae96e80d4) { Panic.panic(Panic.ARITHMETIC_OVERFLOW); } return _expRayToWad(x); @@ -26,8 +26,8 @@ library Exp { function _expRayToWad(int256 x) private pure returns (int256 r) { // Equivalent pseudocode; fixed-point truncations are accounted for below: // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln(2) + t)⋅10²⁷, |t| ≤ ln(2)/2 - // t = x/10²⁷ - k⋅ln(2); // range-reduced argument (Q128) - // e = 10¹⁸⋅(Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ 10¹⁸⋅exp(t) in Q68 + // t = x/10²⁷ - k⋅ln(2); // range-reduced argument (Q129) + // e = 10¹⁸⋅(Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ 10¹⁸⋅exp(t) in Q67 // r = ⌊(e - margin)⋅2ᵏ⌋; // wad // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 // return r + (x == 0); // pin exp(0) = 10¹⁸ exactly @@ -44,17 +44,17 @@ library Exp { // Mixed fixed-point bases (a staircase): each coefficient takes the widest basis fitting // its chosen byte width. A coefficient followed by more multiplies by v tolerates a shorter // basis. Each renormalizing shift lands a value directly at the basis its consumer needs. - // t: Q128 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2) + // t: Q129 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2, so t² fits 256 bits) // v = t²: Q123 the widest basis whose monic-stage product stays inside 256 bits, so // Ev(v)'s leading stage consumes v with no renormalizing shift - // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q88 (monic) + // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q89 (monic) // Od(v) Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q89 - // t⋅Od and the numerator/denominator: Q88. The closing bases are the widest at which - // the t⋅Od intermediate product stays inside 256 bits - // quotient: one `DIV` placing 10¹⁸⋅exp(t) at Q68. The numerator is pre-scaled by - // 10¹⁸⋅2⁶⁸ = 5¹⁸⋅2⁸⁶, the widest such scale at which the dividend stays inside 256 - // bits, and the `DIV` floor is the pipeline's only truncation of the quotient - // output: the closing `shr(68 - k, …)` is the single output-rounding floor, with the 2ᵏ + // t⋅Od and the numerator/denominator: Q89. The t and closing bases are the widest at + // which the t⋅Od intermediate product stays inside 256 bits + // quotient: one `DIV` placing 10¹⁸⋅exp(t) at Q67. The numerator stays below 2¹²⁹ and + // the pre-scale 10¹⁸⋅2⁶⁷ < 2¹²⁷, so the dividend stays inside 256 bits, and the + // `DIV` floor is the pipeline's only truncation of the quotient + // output: the closing `shr(67 - k, …)` is the single output-rounding floor, with the 2ᵏ // octave scaling folded in // // Error budget. Let ê = N/D be the exact value of the integer rational (N = Ev + t⋅Od, D = @@ -78,28 +78,31 @@ library Exp { // budgeted on the under side); the over side is the K27/LN2 constant-grid residue // (the k⋅ln(2) grid error stays below 2⁻²²⁹), enveloped one-sidedly at 2⁻¹³³ of // reduced argument, lifting ê by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). - // The quotient carries 10¹⁸⋅ê on the 2⁶⁸ output grid, where one grid unit is worth 2ᵏ⁻⁶⁸ - // ulp (1 ulp = 10⁻¹⁸ of the result) and Δ's image is 5¹⁸⋅Δ/2⁴⁰ < 2.0097 grid units. The - // margin is the least integer strictly above that image: 0x03 (the excess over Δ's image - // meets the strict never-overestimate requirement), worth 3/2⁴ = 0.1875 ulp at the - // supported edge k = 64. The `DIV` floor only lowers the quotient, so the pre-floor - // accumulator A = q - margin satisfies A⋅2ᵏ⁻⁶⁸ ≤ E. The under side is certified directly on - // the output grid: q ≥ 10¹⁸⋅2⁶⁸⋅exp(t) - 33/4, where 33/4 bounds the sum of the - // integer-rational deficit together with the `DIV` floor (≤ 6210/1000; the Horner deficit - // is 3/2 in Q126 units and the floor is one grid unit), the `Mp` factor (≤ 2/25, via ê ≤ - // 1.45), the under-direction reduced-argument gap (≤ 1267/1000, via exp(t) ≤ √2), and the - // under-direction argument granularity (≤ 571/1000: the one-grain envelope with the - // negative-half denominator floor; free on the t > 0 half). Hence the maximum - // underestimation is E - A⋅2ᵏ⁻⁶⁸ ≤ (33/4 + margin)⋅2ᵏ⁻⁶⁸ = (45/4)⋅2ᵏ⁻⁶⁸ ≈ 0.7031 ulp at - // k = 64 < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The - // deficit envelope doubles each octave and can exceed 1ulp at k ≥ 65. On the central octave - // k = 0 the margin is 3⋅2⁻⁶⁸ ≈ 1.0⋅10⁻²⁰ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` - // leaves, so the round trip floors to ⌊E⌋. The k = 0 band is exactly [-H, H] with H = - // ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). + // The quotient carries 10¹⁸⋅ê on the 2⁶⁷ output grid, where one grid unit is worth 2ᵏ⁻⁶⁷ + // ulp (1 ulp = 10⁻¹⁸ of the result) and Δ's image is below one grid unit: the Q89 closing + // bases confine the over-side jitter so that 5¹⁸⋅Δ/2⁴¹ < 1. The margin is the least + // integer strictly above that image: 0x01 (the excess over Δ's image meets the strict + // never-overestimate requirement), worth 1/2² = 0.25 ulp at the supported edge k = 65. The + // `DIV` floor only lowers the quotient, so the pre-floor accumulator A = q - margin + // satisfies A⋅2ᵏ⁻⁶⁷ ≤ E. The under side is certified directly on the output grid, piecewise + // over the 32 domain pieces (the per-piece denominator floors confine the truncation + // amplification): q ≥ 10¹⁸⋅2⁶⁷⋅exp(t) - 2993/1000, where 2993/1000 bounds, on each sign + // half, the sum of the integer-rational deficit together with the `DIV` floor (≤ + // 2378/1000, certified piecewise), the `Mp` factor (≤ 2/25, via ê ≤ 1.45), the + // under-direction reduced-argument gap (≤ 307/1000 on the t > 0 half via exp(t) ≤ √2; ≤ + // 218/1000 on the other, where exp(t) ≤ 1 + ε), and the under-direction argument + // granularity (≤ 143/500: the one-grain envelope with the negative-half denominator floor; + // free on the t > 0 half). Hence the maximum + // underestimation is E - A⋅2ᵏ⁻⁶⁷ ≤ (2993/1000 + margin)⋅2ᵏ⁻⁶⁷ = (3993/4000)⋅2ᵏ⁻⁶⁵ ulp at + // k = 65 < 1, so + // the floor returns ⌊E⌋ or ⌊E⌋ - 1. The deficit envelope doubles each octave and exceeds + // 1ulp at k ≥ 66. On the central octave k = 0 the margin is 2⁻⁶⁷ ≈ 6.8⋅10⁻²¹ ulp, far below + // the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. The k = 0 band is + // exactly [-H, H] with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). // // Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves the - // pre-floor accumulator by at least 10¹⁸⋅2⁶⁸⋅10⁻²⁷/√2 ≈ 2.1⋅10¹¹ grid units. The error - // terms above confine the accumulator to a band of width 5¹⁸⋅Δ/2⁴⁰ + 33/4 ≈ 10.3 + // pre-floor accumulator by at least 10¹⁸⋅2⁶⁷⋅10⁻²⁷/√2 ≈ 1.0⋅10¹¹ grid units. The error + // terms above confine the accumulator to a band of width 5¹⁸⋅Δ/2⁴¹ + 2993/1000 ≈ 4.0 // grid units just below E's grid image at every octave (in grid units the band is // k-independent; an octave seam rescales E and the band together), so the per-step gain // exceeds any adverse swing within the band by more than 9 orders of magnitude, and the @@ -112,13 +115,13 @@ library Exp { // and `sar(192, …)` round to nearest with ties resolved toward +∞. let k := sar(0xc0, add(shl(0xbf, 0x01), mul(0x724d54edbacbebbb95c52a0f60, x))) - // t in Q128. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln(2) ⋅ 2²³⁵). Subtracting k ⋅ + // t in Q129. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln(2) ⋅ 2²³⁵). Subtracting k ⋅ // LN2 from K27 ⋅ x at the Q235 product basis (so the k ⋅ ln(2) rounding error is - // ~2⁻²³⁵, far below an output ulp) then one `sar(107, …)` leaves the reduced argument - // at Q128. + // ~2⁻²³⁵, far below an output ulp) then one `sar(106, …)` leaves the reduced argument + // at Q129. let t := sar( - 0x6b, + 0x6a, sub( mul(0x279d346de4781f921dd7a89933d54d1f72928, x), mul(0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d, k) @@ -127,11 +130,10 @@ library Exp { // v = t² in Q123 (nonnegative; logical shift): the widest basis at which the // monic-stage product below stays inside 256 bits. - let v := shr(0x85, mul(t, t)) + let v := shr(0x87, mul(t, t)) - // Ev(0) = 2⋅Od(0) by construction, so at closing bases one bit apart (Q88/Q89) the - // constant terms are the same. - let c0 := 0x9c2948bcaca16a0dd2fe98bb4470c388 + // Ev(0) = 2⋅Od(0) by construction; with both chains closing at Q89 the even chain's + // constant term is exactly twice the odd chain's. // Ev(v), monic, Horner down the staircase. The leading v⁵ coefficient is 1, so the // first stage is just an add. @@ -139,27 +141,27 @@ library Exp { ev := add(0x9a036222841f47c6ed6fc3f7599445, shr(0x95, mul(ev, v))) ev := add(0x9064d9657e9a21fc16bb69331b81ae1e, shr(0x7b, mul(ev, v))) ev := add(0x93f11e650dd6c64b96ce79065cdf80f4, shr(0x81, mul(ev, v))) - ev := add(c0, shr(0x7e, mul(ev, v))) + ev := add(0x1385291795942d41ba5fd317688e18710, shr(0x7d, mul(ev, v))) // Od(v), Horner down the staircase. let od := 0xdc07aff8276bde9a361278df6a10 od := add(0xc926ddbecdeeb42e68cd16db7ed378, shr(0x7e, mul(od, v))) od := add(0xad4506af99be27419341e181693281, shr(0x84, mul(od, v))) od := add(0xaf566247c05753b42892f77b67a6b7c7, shr(0x7a, mul(od, v))) - od := add(c0, shr(0x80, mul(od, v))) + od := add(0x9c2948bcaca16a0dd2fe98bb4470c388, shr(0x80, mul(od, v))) - // t⋅Od in Q88 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are + // t⋅Od in Q89 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are // both positive. let tod := sar(0x81, mul(t, od)) - // 10¹⁸⋅exp(t) in Q68: the constant is 10¹⁸⋅2⁶⁸ = 5¹⁸⋅2⁸⁶, so one `DIV` scales, widens, - // and floors at once. The numerator stays below 2¹²⁸ and 10¹⁸⋅2⁶⁸ < 2¹²⁸, so the + // 10¹⁸⋅exp(t) in Q67: the constant is 10¹⁸⋅2⁶⁷ = 5¹⁸⋅2⁸⁵, so one `DIV` scales, widens, + // and floors at once. The numerator stays below 2¹²⁹ and 10¹⁸⋅2⁶⁷ < 2¹²⁷, so the // dividend stays inside 256 bits; the denominator > 0. - r := div(mul(0xde0b6b3a764000000000000000000000, add(ev, tod)), sub(ev, tod)) + r := div(mul(0x6f05b59d3b2000000000000000000000, add(ev, tod)), sub(ev, tod)) - // Less the one-sided margin (0x03; see the budget above), then floored by - // `shr(68 - k, …)` which folds in the 2ᵏ octave scaling (68 - k ∈ [4, 128]). - r := shr(sub(0x44, k), sub(r, 0x03)) + // Less the one-sided margin (0x01; see the budget above), then floored by + // `shr(67 - k, …)` which folds in the 2ᵏ octave scaling (67 - k ∈ [3, 127]). + r := shr(sub(0x43, k), sub(r, 0x01)) // Zero the result at and below C = ⌊-18⋅ln(10)⋅10²⁷⌋ = ⌊10²⁷⋅ln(10⁻¹⁸)⌋, the greatest x // with E < 1. This is the exact 0/1 output boundary, and it sits far above the inputs diff --git a/test/0.8.34/Exp.t.sol b/test/0.8.34/Exp.t.sol index e38a6839f..4538fe2c0 100644 --- a/test/0.8.34/Exp.t.sol +++ b/test/0.8.34/Exp.t.sol @@ -7,7 +7,7 @@ import {Test, stdError} from "@forge-std/Test.sol"; contract ExpTest is Test { // First input whose octave count exceeds the supported range; `expRayToWad` reverts here. - int256 private constant _TOO_BIG = 0x907595ccd30708cabec8a9db; + int256 private constant _TOO_BIG = 0x92b2f16cc66c5a4ae96e80d4; // floor(1e27 * ln(1e-18)): the greatest input whose exact result is < 1 and floors to 0. int256 private constant _ZERO_MAX = -41446531673892822312323846185; // Canonical central wad inputs satisfying 1/sqrt(2) <= w/1e18 < sqrt(2). @@ -77,7 +77,7 @@ contract ExpTest is Test { /// Monotonicity is tightest where the octave count increments and the margin doubles. Check /// every octave boundary in the supported range deterministically. function testExpRayToWadOctaveBoundaryMonotone() external pure { - for (int256 k = -60; k <= 65; ++k) { + for (int256 k = -60; k <= 66; ++k) { int256 xb = _octaveStart(k); for (int256 x = xb - 2; x <= xb + 1; ++x) { if (x + 1 >= _TOO_BIG) continue; @@ -90,23 +90,25 @@ contract ExpTest is Test { /// never-overestimate guarantee, where the over-side envelope (rational approximation plus the /// Horner truncation jitter) the margin must cover is largest, scaling as 2ᵏ. function testExpRayToWadNeverOverestimateHighK() external pure { - int256[7] memory xs = [ + int256[8] memory xs = [ int256(44014845965556527147989858478), 43997357674525079384913362454, 43314167405007111804561657812, 43956299042314536509785490661, 44585114869649660801412478168, 44194124950069992127775717862, - 44183539459288389725181420565 + 44183539459288389725181420565, + 44881638328706512051022125121 ]; - int256[7] memory floors = [ + int256[8] memory floors = [ int256(13043817825332782212292423780355560294), 12817686828684532031135154053443771706, 6472974441739539356346729565753819877, 12302067878139647644374925801327210534, 23071156379767734423570518961257410973, 15605029656619514838244041715971750817, - 15440713974442839033966209577600907121 + 15440713974442839033966209577600907121, + 31034722391555079924522474771845545397 ]; for (uint256 i; i < xs.length; ++i) { int256 r = Exp.expRayToWad(xs[i]); @@ -137,29 +139,26 @@ contract ExpTest is Test { } } - /// The largest supported input, one below the revert threshold: frac(E) ~= 0.52 sits inside - /// the k = 64 deficit envelope (~0.70), so the result floors to E or one under. At the top of - /// k = 63, frac(E) ~= 0.74 exceeds that octave's envelope (~0.35) and the floor is exact. + /// The largest supported input, one below the revert threshold: frac(E) ~= 0.79 sits inside + /// the k = 65 deficit envelope (~1.0), so the result floors to E or one under. At the top of + /// k = 64, frac(E) ~= 0.52 exceeds that octave's envelope (~0.50) and the floor is exact. function testExpRayToWadSupportedEdge() external pure { - int256 floorE = 26087635650665564424699143611138320962; + int256 floorE = 52175271301331128849398287198371155181; int256 r = Exp.expRayToWad(_TOO_BIG - 1); assertLe(r, floorE, "overestimates exp"); assertGe(r, floorE - 1, "below floor minus one"); assertEq( - Exp.expRayToWad(44014845965556527147994239712), - 13043817825332782212349571798501714341, - "k = 63 top floor" + Exp.expRayToWad(44707993146116472457411471834), 26087635650665564424699143611138320962, "k = 64 top floor" ); } - /// The 1-ulp underestimate is achieved: the least x >= 44e27 whose result is floor(E) - 1. - /// frac(E) ~= 0.1605 sits below the accumulated deficit at k = 63, so the floored accumulator - /// lands one under the exact floor. + /// The 1-ulp underestimate is achieved: k = 64 inputs whose frac(E) (~0.17 and ~0.07) sits + /// below the accumulated deficit, so the floored accumulator lands one under the exact floor. function testExpRayToWadUnderestimateByOneWitness() external pure { - int256 x = 44000000000000000000000000001; - int256 floorE = 12851600114359308275809299644994699372; + int256 x = 44044505178945024895948687544; + int256 floorE = 13436481464873958299464002666966885694; assertEq(Exp.expRayToWad(x), floorE - 1, "not the 1-ulp underestimate"); - // The first input of the k = 64 octave: frac(E) ~= 0.07, again one under the exact floor. + // The first input of the k = 64 octave, again one under the exact floor. assertEq( Exp.expRayToWad(44014845965556527147994239713), 13043817825332782212349571811545532167 - 1, From b5fe25ac3a65f889b5ae3e411e8d1ae2aa283bc5 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 5 Jul 2026 21:03:02 +0200 Subject: [PATCH 146/149] Express the even closing constant as the doubled odd constant The closing constants share one binding: c0 carries the odd chain's constant term and the even chain's stage doubles it in place with shl(0x01, c0), making Ev(0) = 2*Od(0) visible in the source instead of split across two opaque literals. Semantics, tests, witnesses, and every certified budget are unchanged; runtime gas and deployed bytecode remain with the optimizer, whose constant folding materializes the doubled literal as before. The unoptimized Yul the proof anchors to carries the binding and the shift verbatim, so the eight quoted value walks mirror the compiled form (evmShl 0x1 c0 at the even closing, the same treatment the walks give the k-extraction's shl) and an evaluation lemma discharges the doubling where the walk trees meet the unchanged hand normal forms. Full lake build is green from the Theorems.lean axiom gates; 12/12 forge tests at 10k fuzz runs; forge fmt clean. Co-Authored-By: Claude Fable 5 --- formal/exp/ExpProof/ExpProof/Seam/Value.lean | 22 +++++++++++++------- src/vendor/Exp.sol | 9 ++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/formal/exp/ExpProof/ExpProof/Seam/Value.lean b/formal/exp/ExpProof/ExpProof/Seam/Value.lean index 16e2e0c5d..5f003e973 100644 --- a/formal/exp/ExpProof/ExpProof/Seam/Value.lean +++ b/formal/exp/ExpProof/ExpProof/Seam/Value.lean @@ -21,6 +21,12 @@ open Common.Word set_option maxRecDepth 100000 +/-- The even chain's closing constant: the compiled `shl(0x01, c0)` evaluated. The walk results +carry the `evmShl` node exactly as compiled; consumers fold it with this equation. -/ +theorem evmShl_one_c0 : + evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388 = 0x1385291795942d41ba5fd317688e18710 := by + rw [evmShl_eq (by norm_num) (by norm_num)]; norm_num + set_option maxHeartbeats 8000000 in /-- The kernel `fun__expRayToWad_78` at the scale point `x = 0`: every `mul` by `x` vanishes, so `k = t = v = 0`, the rational form evaluates to `2^126`, and the final `iszero(0) = 1` fix-up makes @@ -418,7 +424,7 @@ theorem call_fun__expRayToWad_78_direct let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x87 (evmMul t t) - let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul + let ev := evmAdd (evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388) (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -482,7 +488,7 @@ theorem call_fun_expRayToWad_68_direct let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x87 (evmMul t t) - let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul + let ev := evmAdd (evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388) (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -545,7 +551,7 @@ theorem call_fun_wrap_expRayToWad_direct let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x87 (evmMul t t) - let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul + let ev := evmAdd (evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388) (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -605,7 +611,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x87 (evmMul t t) - let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul + let ev := evmAdd (evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388) (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -634,7 +640,7 @@ theorem external_fun_wrap_expRayToWad_calldata_result let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x87 (evmMul t t) - let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul + let ev := evmAdd (evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388) (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -735,7 +741,7 @@ theorem external_fun_wrap_expRayToWad_calldata_halts let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x87 (evmMul t t) - let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul + let ev := evmAdd (evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388) (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -841,7 +847,7 @@ theorem external_fun_wrap_expRayToWad_dispatcher_state_result let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x87 (evmMul t t) - let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul + let ev := evmAdd (evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388) (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul @@ -920,7 +926,7 @@ theorem run_exp_ray_to_wad_evm_eq_tree let t := evmSar 0x6a (evmSub (evmMul 0x279d346de4781f921dd7a89933d54d1f72928 x) (evmMul 0x58b90bfbe8e7bcd5e4f1d9cc01f97b57a079a193394c5b16c5068badc5d k)) let v := evmShr 0x87 (evmMul t t) - let ev := evmAdd 0x1385291795942d41ba5fd317688e18710 (evmShr 0x7d (evmMul + let ev := evmAdd (evmShl 0x1 0x9c2948bcaca16a0dd2fe98bb4470c388) (evmShr 0x7d (evmMul (evmAdd 0x93f11e650dd6c64b96ce79065cdf80f4 (evmShr 0x81 (evmMul (evmAdd 0x9064d9657e9a21fc16bb69331b81ae1e (evmShr 0x7b (evmMul (evmAdd 0x9a036222841f47c6ed6fc3f7599445 (evmShr 0x95 (evmMul diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 7dc3bfd72..45a3c4206 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -132,8 +132,9 @@ library Exp { // monic-stage product below stays inside 256 bits. let v := shr(0x87, mul(t, t)) - // Ev(0) = 2⋅Od(0) by construction; with both chains closing at Q89 the even chain's - // constant term is exactly twice the odd chain's. + // Ev(0) = 2⋅Od(0) by construction; both chains close at Q89, the odd on c0 and the + // even on c0 doubled in place. + let c0 := 0x9c2948bcaca16a0dd2fe98bb4470c388 // Ev(v), monic, Horner down the staircase. The leading v⁵ coefficient is 1, so the // first stage is just an add. @@ -141,14 +142,14 @@ library Exp { ev := add(0x9a036222841f47c6ed6fc3f7599445, shr(0x95, mul(ev, v))) ev := add(0x9064d9657e9a21fc16bb69331b81ae1e, shr(0x7b, mul(ev, v))) ev := add(0x93f11e650dd6c64b96ce79065cdf80f4, shr(0x81, mul(ev, v))) - ev := add(0x1385291795942d41ba5fd317688e18710, shr(0x7d, mul(ev, v))) + ev := add(shl(0x01, c0), shr(0x7d, mul(ev, v))) // Od(v), Horner down the staircase. let od := 0xdc07aff8276bde9a361278df6a10 od := add(0xc926ddbecdeeb42e68cd16db7ed378, shr(0x7e, mul(od, v))) od := add(0xad4506af99be27419341e181693281, shr(0x84, mul(od, v))) od := add(0xaf566247c05753b42892f77b67a6b7c7, shr(0x7a, mul(od, v))) - od := add(0x9c2948bcaca16a0dd2fe98bb4470c388, shr(0x80, mul(od, v))) + od := add(c0, shr(0x80, mul(od, v))) // t⋅Od in Q89 (signed via t); the numerator Ev + t⋅Od and denominator Ev - t⋅Od are // both positive. From e99a89acbaed7fb7f4458944d86be35f7e56b464 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Sun, 5 Jul 2026 23:03:48 +0200 Subject: [PATCH 147/149] Document settling negatives with the envelope instruments The measure/attribute/rebalance section gains its converse: the five instruments that drive a "leave it alone" answer to an exact floor (constrained-ideal fitting, the coefficient-count decay law, lattice search under the floored-and-margined objective, linear certificate-floor solves, and sweep suprema as lower bounds), with lnWadToRay as the worked example. Co-Authored-By: Claude Fable 5 --- formal/README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/formal/README.md b/formal/README.md index 282d3f760..1ac7d3cd1 100644 --- a/formal/README.md +++ b/formal/README.md @@ -121,6 +121,55 @@ refit), attribution before rebalancing (step 2 finds the bit that buys 2.5× rat that buys nothing), and rebalancing before certification (step 4's piecewise machinery is only worth building once the true envelope actually fits under the target). +## Settling the negative: the same instruments prove a kernel optimal + +The procedure pays off equally when the answer is "leave it alone" — but only if the +negative is driven to an exact floor, so it stays settled. `lnWadToRay` is the worked +example: approximation-dominated on both budget sides, no amplified truncation site, and +already certified per exponent. Five instruments close it: + +1. **Fit the constrained ideal, not the unconstrained one.** The minimax floor must carry + every structural pin the bytecode does. `Ln.sol`'s (4,5) rational shares its constant + term between numerator and denominator (one 13-byte literal serves both, `p(0) = −q(0)`); + the unconstrained minimax on its domain and weight is 0.2735 ulp, but with the shared + constant pinned it is 0.32346 — and the deployed integer staircase measures 0.32366, + 0.0002 above the floor with its over-side peak on it. A deployed-vs-unconstrained gap + read as "harvestable quantization" can be, as here, the deliberate bytecode price of the + structure. + +2. **Price shorter forms by the decay law.** Adjacent coefficient counts fit on a geometric + decay (~534× per coefficient for this family: 0.2735 → 146 → 7.8·10⁴ for (4,5) → (4,4) → + (3,4)), so measuring two types prices every type — "would a shorter rational fit?" + becomes arithmetic against the freeable budget instead of a fitting project. + +3. **Search the lattice under the deliverable's objective.** Two-sided fit width is the + wrong objective for a floored, margined kernel: what the documented bound consumes is + over-side need plus under-side need at a fixed margin word, and octave-dependent terms + (the mantissa-truncation gap, k > 0 only) attach to wherever the under-peak sits. A + width-optimal coefficient neighbor can worsen the real bound by migrating the under-peak + into the worst octave. Joint optimality is established when multi-start coordinate + descent under the correct objective returns the deployed lattice point exactly. + +4. **Solve the certificate floor where the constant enters linearly.** An envelope constant + that appears linearly in the cover-cell certificates has an exactly computable per-cell + feasibility minimum. In `LnProof`, the floor-side envelope constant sits at that minimum + to the unit — one unit lower and the certificate polynomial goes negative on a plateau + spanning the whole [2⁹⁵, 2⁹⁵ + 2⁶⁰] edge of the mantissa domain — so the margin word is + pinned to the band it occupies, and no cover refinement can move it: the polynomial + fails, not the cover. + +5. **Treat sweep suprema as lower bounds.** Over a plateau of 2⁶⁰ mantissas no sweep is + exhaustive; the true supremum creeps toward the certificate's worst-case truncation + model. The ~0.010-ulp gap between the sampled over-side peak (0.32797) and the + certificate floor (0.3382) is the price of the global truncation model, not padding — + the mirror of step 1's alignment argument: with astronomically many reachable arguments, + near-worst residual alignment exists. + +When the binding constraint is architectural — here, the global per-stage slop model, whose +replacement by per-stage truncation windows would buy a few thousandths of a ulp for a full +re-derivation of the floor proof's bracket and assembly layers — the deliverable is the +recorded reopening condition, not the change. + ## Build Generated EVMYulLean artifacts (`*YulRuntime.lean`, `*YulProof.lean`) are `.gitignore`d and regenerated in CI. See `.github/workflows/*-formal.yml` for the canonical build steps. From 171217449d1e540272f23e6942ec69814385f0f2 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 7 Jul 2026 12:43:26 +0200 Subject: [PATCH 148/149] Add decision-making discipline to the development guide Co-Authored-By: Claude Fable 5 --- AGENTS.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 09e962a64..74b092fcd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -437,6 +437,29 @@ and cannot be replaced by a direct statement of the relevant requirement. A committed progress log, scratchpad, milestone note, or plan document is not a normative source merely because it is present in the repository. +### Decision-Making Discipline + +Agents must not make judgment calls or architectural decisions. Whenever a +juncture calls for professional judgment, taste, external context, or +real-world experience — or whenever no option is clearly superior on technical +merits alone — stop and present every viable option to the user, with the pros +and cons of each clearly spelled out, and ask the user to decide the correct +way forward. An agent may choose on its own only when the correct choice is +obvious and unambiguous from the information available to it. + +Do not spend effort cataloging the reasons a task is too daunting, too +difficult, or too lengthy to complete. Spend that effort instead on determining +concretely why the task *can* be completed: identify the specific techniques, +tools, or enhancements that can be brought to bear to make it more tractable. +When faced with a choice among options where one or more appears substantially +more difficult for only marginal benefit, do not silently take the easier path; +present the trade-off to the user and let the user choose. + +When reasoning about how difficult or feasible a line of inquiry is, do not +rely on assumptions drawn from past experience or general priors. Root every +such judgment in experimentation and quantitative measurement of the actual +system at hand. Do not assume; run the test and measure. + ### Commenting Discipline Comments must be added only where the code cannot speak for itself, and code From 45cc47f499ac07c24cfd5e344982e28c872b50d8 Mon Sep 17 00:00:00 2001 From: Duncan Townsend Date: Tue, 7 Jul 2026 13:48:26 +0200 Subject: [PATCH 149/149] Clean up comments --- src/vendor/Exp.sol | 124 ++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/src/vendor/Exp.sol b/src/vendor/Exp.sol index 45a3c4206..8693d7c6a 100644 --- a/src/vendor/Exp.sol +++ b/src/vendor/Exp.sol @@ -25,12 +25,16 @@ library Exp { /// @dev The rational polynomial approximation kernel function _expRayToWad(int256 x) private pure returns (int256 r) { // Equivalent pseudocode; fixed-point truncations are accounted for below: - // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln(2) + t)⋅10²⁷, |t| ≤ ln(2)/2 - // t = x/10²⁷ - k⋅ln(2); // range-reduced argument (Q129) - // e = 10¹⁸⋅(Ev(t²) + t⋅Od(t²)) / (Ev(t²) - t⋅Od(t²)); // ≈ 10¹⁸⋅exp(t) in Q67 - // r = ⌊(e - margin)⋅2ᵏ⌋; // wad - // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 - // return r + (x == 0); // pin exp(0) = 10¹⁸ exactly + // k = round(x / (10²⁷⋅ln(2))); // x = (k⋅ln(2) + t)⋅10²⁷, |t| ≤ ln(2)/2 + // t = x/10²⁷ - k⋅ln(2); // range-reduced argument; Q129 + // ev = Ev(t²); // polynomial approximation; Q89 + // od = Od(t²); // polynomial approximation; Q89 + // n = ev + t⋅od; // rational numerator; Q89 + // d = ev - t⋅od; // rational denominator; Q89 + // e = 10¹⁸⋅n / d; // ≈ 10¹⁸⋅exp(t); Q67 + // r = ⌊(e - margin)⋅2ᵏ⌋; // wad + // r = r ⋅ (x > C); // C = ⌊-18⋅ln10⋅10²⁷⌋; 0 where E < 1 + // return r + (x == 0); // pin exp(0) = 10¹⁸ exactly // // `exp(t) = (1 + tanh(t/2)) / (1 - tanh(t/2))`, so with the even/odd split N(t) = Ev(t²) + // t⋅Od(t²) the quotient N(t)/N(-t) is the reciprocal-symmetric rational that matches @@ -44,18 +48,18 @@ library Exp { // Mixed fixed-point bases (a staircase): each coefficient takes the widest basis fitting // its chosen byte width. A coefficient followed by more multiplies by v tolerates a shorter // basis. Each renormalizing shift lands a value directly at the basis its consumer needs. - // t: Q129 (from the Q235 reduction K27⋅x - k⋅LN2; |t| ≤ ln(2)/2, so t² fits 256 bits) // v = t²: Q123 the widest basis whose monic-stage product stays inside 256 bits, so - // Ev(v)'s leading stage consumes v with no renormalizing shift - // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q89 (monic) + // Ev(v)'s leading stage consumes v with no renormalizing shift. t's Q129 basis (|t| + // ≤ ln(2)/2) means that pre-reduction t² fits 256 bits. + // Ev(v) Horner down the staircase Q123 → Q97 → Q97 → Q91 → Q89 // Od(v) Horner down the staircase Q105 → Q102 → Q93 → Q94 → Q89 - // t⋅Od and the numerator/denominator: Q89. The t and closing bases are the widest at - // which the t⋅Od intermediate product stays inside 256 bits - // quotient: one `DIV` placing 10¹⁸⋅exp(t) at Q67. The numerator stays below 2¹²⁹ and - // the pre-scale 10¹⁸⋅2⁶⁷ < 2¹²⁷, so the dividend stays inside 256 bits, and the - // `DIV` floor is the pipeline's only truncation of the quotient - // output: the closing `shr(67 - k, …)` is the single output-rounding floor, with the 2ᵏ - // octave scaling folded in + // t and closing bases of Ev and Od are the widest at which the t⋅Od intermediate + // product stays inside 256 bits + // dividend: Q156 the widest basis that fits in 256 bits before the single truncating + // `DIV` by Q89 divisor. < 2¹²⁹ + // r: Q67 implied by the pre-scale 10¹⁸⋅2⁶⁷ < 2¹²⁷ to avoid overflowing the dividend. + // output: the closing `shr(67 - k, …)` is the output-rounding floor, with the 2ᵏ octave + // scaling folded in // // Error budget. Let ê = N/D be the exact value of the integer rational (N = Ev + t⋅Od, D = // Ev - t⋅Od; the closing `DIV` floor is counted on the output grid below) and write its @@ -63,62 +67,60 @@ library Exp { // tightest bound the proof technique can bear, in spite of the fact that the worst-case // error contributions do not co-occur. The budget bounds Δ ≤ 0.5792534503673398887, the sum // of four one-sided contributions: - // integer Horner truncation: the Ev shared by the numerator Ev + t⋅Od and denominator - // Ev - t⋅Od cancels to first order in the quotient, so its truncation barely - // perturbs ê; this jitter stays < 0.21706. + // integer Horner truncation: the shared Ev shared cancels to first order in the + // quotient, so its truncation barely perturbs ê; this jitter stays < 0.21706. // argument granularity: v carries t² on the Q123 grid, and its floor only lowers the - // polynomials' shared argument (by < 2⁻¹²³), which lifts ê on the t > 0 half by < - // 0.32906: one v-grain moves the quotient by 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose - // one-signed numerator is maximal at each piece's upper edge and whose denominator - // is floored piecewise over 32 domain pieces (the pointwise supremum is ≈ 0.3287 at - // t = ln(2)/2). The t < 0 direction is budgeted on the under side. + // polynomials' shared argument, which lifts ê on the t > 0 half by < 0.32906: one + // v-grain moves the quotient by 2t⋅(Od⋅ΔEv - Ev⋅ΔOd)/(D⋅D′), whose one-signed + // numerator is maximal at each piece's upper edge and whose denominator, when + // analyzed over over 32 domain pieces, has pointwise supremum ≈ 0.3287 at t = + // ln(2)/2). The t < 0 direction is budgeted on the under side. // rational `Mp`-factor (the dyadic gap between the reciprocal-symmetric form and exp): // < 0.02210 (its supremum is √2⋅2¹²⁶/(2¹³²-1)). // reduced-argument gap: the Q128 floor of t only pushes ê downward (that direction is // budgeted on the under side); the over side is the K27/LN2 constant-grid residue - // (the k⋅ln(2) grid error stays below 2⁻²²⁹), enveloped one-sidedly at 2⁻¹³³ of - // reduced argument, lifting ê by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). - // The quotient carries 10¹⁸⋅ê on the 2⁶⁷ output grid, where one grid unit is worth 2ᵏ⁻⁶⁷ - // ulp (1 ulp = 10⁻¹⁸ of the result) and Δ's image is below one grid unit: the Q89 closing - // bases confine the over-side jitter so that 5¹⁸⋅Δ/2⁴¹ < 1. The margin is the least - // integer strictly above that image: 0x01 (the excess over Δ's image meets the strict - // never-overestimate requirement), worth 1/2² = 0.25 ulp at the supported edge k = 65. The + // (k⋅ln(2) grid error is below 2⁻²²⁹), enveloped one-sidedly at 2⁻¹³³ of reduced + // argument, lifting ê by < 0.01105 (√2⋅2¹²⁶/(32⋅2¹²⁸) = √2/128). + // + // The quotient `r` carries 10¹⁸⋅ê on the 2⁶⁷ output grid, where one grid unit is worth + // 2ᵏ⁻⁶⁷ ulp (1 ulp = 10⁻¹⁸ of the result) and Δ's image is below one grid unit: the Q89 + // closing bases confine the over-side jitter so that 5¹⁸⋅Δ/2⁴¹ < 1. The margin is the least + // integer strictly above that image: 0x01, worth 0.25 ulp at the supported edge k = 65. The // `DIV` floor only lowers the quotient, so the pre-floor accumulator A = q - margin // satisfies A⋅2ᵏ⁻⁶⁷ ≤ E. The under side is certified directly on the output grid, piecewise - // over the 32 domain pieces (the per-piece denominator floors confine the truncation + // over the 32 domain pieces (per-piece denominator floors confine the truncation // amplification): q ≥ 10¹⁸⋅2⁶⁷⋅exp(t) - 2993/1000, where 2993/1000 bounds, on each sign - // half, the sum of the integer-rational deficit together with the `DIV` floor (≤ - // 2378/1000, certified piecewise), the `Mp` factor (≤ 2/25, via ê ≤ 1.45), the - // under-direction reduced-argument gap (≤ 307/1000 on the t > 0 half via exp(t) ≤ √2; ≤ - // 218/1000 on the other, where exp(t) ≤ 1 + ε), and the under-direction argument - // granularity (≤ 143/500: the one-grain envelope with the negative-half denominator floor; - // free on the t > 0 half). Hence the maximum - // underestimation is E - A⋅2ᵏ⁻⁶⁷ ≤ (2993/1000 + margin)⋅2ᵏ⁻⁶⁷ = (3993/4000)⋅2ᵏ⁻⁶⁵ ulp at - // k = 65 < 1, so - // the floor returns ⌊E⌋ or ⌊E⌋ - 1. The deficit envelope doubles each octave and exceeds - // 1ulp at k ≥ 66. On the central octave k = 0 the margin is 2⁻⁶⁷ ≈ 6.8⋅10⁻²¹ ulp, far below - // the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, so the round trip floors to ⌊E⌋. The k = 0 band is - // exactly [-H, H] with H = ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). + // half, the sum of the integer-rational deficit together with the `DIV` floor (≤ 2378/1000, + // certified piecewise), the `Mp` factor (≤ 2/25, via ê ≤ 1.45), the under-direction + // reduced-argument gap (≤ 307/1000 on the t > 0 half via exp(t) ≤ √2; ≤ 218/1000 on the + // other, where exp(t) ≤ 1 + ε), and the under-direction argument granularity (≤ 143/500: + // the one-grain envelope with the negative-half denominator floor; free on the t > 0 half). + // + // Hence the maximum underestimation is E - A⋅2ᵏ⁻⁶⁷ ≤ (2993/1000 + margin)⋅2ᵏ⁻⁶⁷ = + // (3993/4000)⋅2ᵏ⁻⁶⁵ ulp. At k ≤ 65, this is < 1, so the floor returns ⌊E⌋ or ⌊E⌋ - 1. The + // deficit envelope doubles each octave and exceeds 1ulp at k ≥ 66. On the central octave k + // = 0, the margin is 2⁻⁶⁷ ≈ 6.8⋅10⁻²¹ ulp, far below the ≈10⁻⁹ ulp gap `lnWadToRay` leaves, + // so the round trip floors to ⌊E⌋. The k = 0 band is exactly [-H, H] with H = + // ⌊10²⁷⋅ln(2)/2⌋, matching `lnWadToRay`'s image over [1/√2, √2). // // Monotonicity: one unit step in x multiplies E by exp(10⁻²⁷) ≈ 1 + 10⁻²⁷, which moves the // pre-floor accumulator by at least 10¹⁸⋅2⁶⁷⋅10⁻²⁷/√2 ≈ 1.0⋅10¹¹ grid units. The error - // terms above confine the accumulator to a band of width 5¹⁸⋅Δ/2⁴¹ + 2993/1000 ≈ 4.0 - // grid units just below E's grid image at every octave (in grid units the band is - // k-independent; an octave seam rescales E and the band together), so the per-step gain - // exceeds any adverse swing within the band by more than 9 orders of magnitude, and the - // pre-floor accumulator strictly increases at every step; its floor is non-decreasing. The - // zeroing clamp and the +1 pin at x = 0 preserve order: below C the result is 0 while just - // above it ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket the pinned - // scale-point value. + // terms above confine the accumulator to a band of width 5¹⁸⋅Δ/2⁴¹ + 2993/1000 ≈ 4.0 grid + // units just below E's grid image at every octave (in grid units the band is k-independent; + // an octave seam rescales E and the band together), so the per-step gain exceeds any + // adverse swing within the band by more than 9 orders of magnitude, and the pre-floor + // accumulator strictly increases at every step; its floor is non-decreasing. The zeroing + // clamp and the +1 pin at x = 0 preserve order: below C the result is 0 while just above it + // ⌊E⌋ ≥ 0, and the adjacent runtime values around x = 0 bracket the pinned scale-point + // value. assembly ("memory-safe") { // k = round(x / (10²⁷⋅ln(2))), half-open. CINV = round(2¹⁹² / (10²⁷⋅ln(2))); the +2¹⁹¹ // and `sar(192, …)` round to nearest with ties resolved toward +∞. let k := sar(0xc0, add(shl(0xbf, 0x01), mul(0x724d54edbacbebbb95c52a0f60, x))) - // t in Q129. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln(2) ⋅ 2²³⁵). Subtracting k ⋅ - // LN2 from K27 ⋅ x at the Q235 product basis (so the k ⋅ ln(2) rounding error is - // ~2⁻²³⁵, far below an output ulp) then one `sar(106, …)` leaves the reduced argument - // at Q129. + // t in Q129. K27 = round(2²³⁵ / 10²⁷) and LN2 = round(ln(2) ⋅ 2²³⁵). Subtracting k⋅LN2 + // from K27⋅x at the Q235 product basis (so the k⋅ln(2) rounding error is ~2⁻²³⁵, far + // below an output ulp) then one `sar(106, …)` leaves the reduced argument at Q129. let t := sar( 0x6a, @@ -128,16 +130,14 @@ library Exp { ) ) - // v = t² in Q123 (nonnegative; logical shift): the widest basis at which the - // monic-stage product below stays inside 256 bits. + // v = t² in Q123: the widest basis at which the monic-stage product below stays inside + // 256 bits. let v := shr(0x87, mul(t, t)) - // Ev(0) = 2⋅Od(0) by construction; both chains close at Q89, the odd on c0 and the - // even on c0 doubled in place. + // Ev(0) = 2⋅Od(0) by construction. let c0 := 0x9c2948bcaca16a0dd2fe98bb4470c388 - // Ev(v), monic, Horner down the staircase. The leading v⁵ coefficient is 1, so the - // first stage is just an add. + // Ev(v), monic, Horner down the staircase. let ev := add(0xb9aacfacf3c10b378435f8e22adf48500e, v) ev := add(0x9a036222841f47c6ed6fc3f7599445, shr(0x95, mul(ev, v))) ev := add(0x9064d9657e9a21fc16bb69331b81ae1e, shr(0x7b, mul(ev, v)))