diff --git a/README.md b/README.md index 9fab503..927bcab 100644 --- a/README.md +++ b/README.md @@ -409,6 +409,7 @@ for current release planning. - [Performance reports](https://github.com/acgetchell/la-stack/blob/main/docs/performance.md) — release-to-release measurement results and provenance. - [Releasing](https://github.com/acgetchell/la-stack/blob/main/docs/RELEASING.md) — release preparation, validation, and publication. - [Roadmap](https://github.com/acgetchell/la-stack/blob/main/docs/roadmap.md) — release planning, future directions, and non-goals. +- [Validation records](https://github.com/acgetchell/la-stack/blob/main/docs/validation/README.md) — numerical contracts, evidence, and decisions. ## 📋 Examples diff --git a/docs/archive/performance/studies/README.md b/docs/archive/performance/studies/README.md index 005b625..69d78ba 100644 --- a/docs/archive/performance/studies/README.md +++ b/docs/archive/performance/studies/README.md @@ -4,6 +4,7 @@ Completed optimization investigations and their decisions are retained here. These are historical experiments, with the environment and limitations stated in each report. +- [Algebraic floating-point reduction evaluation (#250)](algebraic-float.md) - [Interval and certified-reduction optimization (#247, #248)](interval-reductions.md) - [Rational row-clearing allocation study (#233)](rational-row-clearing.md) - [Rust 1.99 compiler migration (#251)](rust-1.99.md) diff --git a/docs/archive/performance/studies/algebraic-float.md b/docs/archive/performance/studies/algebraic-float.md new file mode 100644 index 0000000..db7a590 --- /dev/null +++ b/docs/archive/performance/studies/algebraic-float.md @@ -0,0 +1,257 @@ +# Algebraic Floating-Point Reduction Evaluation + +The local evaluation for [#250](https://github.com/acgetchell/la-stack/issues/250) +records the decision to **retain strict arithmetic**. The selected algebraic reduction +can suppress a required overflow error on finite inputs, including D=4 and +D=5. This is a negative adoption decision; no library API, arithmetic policy, +or Semgrep exception changes are proposed. + +The decision is supported by a native macOS counterexample and compiler-contract +analysis. On 2026-10-15 the maintainer rejected adoption and ended the evaluation, +including unperformed native Linux/Windows prototype runs. The +[validation decision](../../../validation/algebraic-floating-point.md) records +that scope closure; no claim is made that those runs passed. + +## Contents + +- [Candidate selection](#candidate-selection) +- [Numerical findings](#numerical-findings) +- [Measurement method and results](#measurement-method-and-results) +- [Provenance and reproduction](#provenance-and-reproduction) +- [Validation and scope closure](#validation-and-scope-closure) +- [Decision](#decision) + +## Candidate selection + +Select one existing kernel: the positive row-sum reduction in +`Matrix::norm_inf`. This fits #250's reductions category without changing an +FMA-based algorithm. The complete operation takes absolute values, sums each +row, checks overflow, and selects the largest sum. No certified rounding bound +is promised, but computed non-finite values must retain typed error provenance. + +The [existing performance record](../../../performance.md) puts strict D=2–5 +matrix infinity norms at roughly 0.6–3.5 ns, increasing to about 8.4 ns at D=8. +These historical measurements justify investigating the addition dependency +chain; they are **not** the baseline for this experiment. The public operation +already has a comparison fixture in `benches/vs_linalg.rs`, and its ordinary +additions offer a more direct candidate than an FMA substitution. + +The disposable prototype changes only the success-path row additions to +`algebraic_add`. It accepts an already-validated `Matrix`, retains absolute +values, finite-result checks and maximum selection, and delegates a non-finite +completed row to the original strict method for error recovery. That fallback +is deliberately conservative but cannot catch an incorrectly finite result. +Both versions return the complete `Result` in timed closures. + +Other plausible candidates are excluded before implementation: + +- **Dot products and squared norms:** the current APIs explicitly accumulate + with ordered `mul_add`. The [compiler migration study](rust-1.99.md) observes + the same scalar FMA chain in generated code. Breaking that chain by replacing + FMA with algebraic multiplication/addition violates this issue's exclusion. +- **General matrix multiplication and matrix-vector multiplication:** these + are not existing APIs at the captured source revision. +- **Predicates, certified/interval reductions, exact fallbacks, tolerance and + branch decisions:** excluded by the issue. The candidate is not substituted + into those paths or into a downstream classifier. + +## Numerical findings + +### A finite result hides required overflow + +Let `a = 2^969` and `M = f64::MAX = 2^1024 - 2^971`. Use the row +`[a, a, M, 0]`, or append another zero for D=5. All entries are finite. + +The strict recurrence first obtains `a + a = 2^970`, then adds `M`. The exact +sum is the rounding midpoint `2^1024 - 2^970`; round-to-nearest, ties-to-even +overflows. The original API returns: + +```text +LaError::NonFinite + origin: Computation { operation: MatrixInfinityNorm } + location: MatrixCell { row: 0, col: 2 } +``` + +The optimized algebraic prototype instead returns the finite bit pattern +`0x7fefffffffffffff`, or `f64::MAX`, in both dimensions. Reassociation can absorb +each `a` separately when added to `M`, avoiding the overflowing strict prefix. +The retained inlined experiment demonstrates the changed classification; an +out-of-line probe need not choose the same association. A final `is_finite` +check and a strict fallback triggered by non-finite results cannot detect this +failure. No input validation or exact fallback was removed to produce it. + +### Finite accuracy and boundary checks + +An independent `BigRational` oracle sums the absolute values of the exact binary64 +inputs and selects the largest rational row sum. The experiment covers D=0, 1, +2, 3, 4, 5, 8 and 16. There is no finite maximum supported dimension for the +const-generic API; D=0 and D=1 cover its lower boundaries, while D=8 and D=16 +supplement the primary D=2–5 scope. + +Explicit cases cover signed zero, minimum subnormals, minimum normal values, +mixed and extreme magnitudes, absorption, definite overflow, and near-overflow +permutations. NaN and both infinities are rejected at construction with exact +input origin and coordinates. Cancellation of signed terms is not applicable: +this kernel sums absolute values. Underflow from multiplication or division is +also absent; subnormal addition is exercised directly. + +For `[2^53, 1, -1, 1]`, the exact absolute row sum is `2^53 + 3`. Strict +accumulation returns `2^53`, whereas the algebraic prototype returns `2^53 + 2`. +The latter is closer to the exact sum, but changes the ordered result already +protected by `matrix_norm_inf_preserves_left_to_right_row_sum_order`. The +overflow counterexample is stronger evidence against adoption than a bitwise +difference alone. + +A deterministic xorshift corpus with seed 250 adds 1,000 matrices per dimension, +spanning finite exponent fields, signs and mantissas. It reports no random +classification changes, but 2 value changes at D=8 and 9 at D=16. Random success +does not erase the explicit D=4/D=5 failure. The archive retains all explicit +case outputs, random differences, exact-oracle relative errors, and the source +that reconstructs every input. + +### Compiler guarantees + +[Rust 1.99's algebraic-operator contract][algebraic-contract] allows +reassociation and unspecified precision, permits unexpected special-value +behavior, and does not promise repeatable results even within one run. Finite +inputs, an output range check, and successful observed tests therefore cannot +establish a portable accuracy guarantee for this candidate. The absence of a +certified bound on the existing API does not waive its ordered arithmetic or +typed overflow contract. + +Generated LLVM IR for the prototype uses `reassoc nsz arcp contract` additions. +The native D=4 probe groups additions into pairs, whereas the strict probe +retains the ordered chain. These probes explain available transformations, not +the exact schedule of every inlined call or a causal timing proof. + +[algebraic-contract]: https://doc.rust-lang.org/std/primitive.f32.html#algebraic-operators + +## Measurement method and results + +Measurements compare the captured strict public method and the isolated +prototype in the same optimized executable. The shared fixture reproduces +`benches/common/vs_linalg.rs::matrix_entry`, including its diagonal `mul_add`; +an additional dense signed-integer fixture has exactly representable sums. +Both use the same preconstructed matrix per pair. + +Before timing, both results must be finite and agree with the independent exact +reference within the ordinary summation envelope `γ_D × exact_norm`, where +`γ_D = D u / (1 - D u)` and `u = 2^-53`. This is an empirical fixture gate, +**not** a guarantee supplied by algebraic operations. Adversarial failing cases +are never timed as successful workloads. + +Criterion uses `iter`, 100 samples, 100,000 resamples, a one-second warmup, +three-second measurement target, 95% confidence intervals and a 1% noise +threshold. The first pass runs strict then algebraic; the second reverses that +order. All ten dimension/fixture pairs are repeated, with no selection based on +favorable results. Builds and validation finish before measurement; timing jobs +run sequentially. Other desktop activity is uncontrolled. + +All 20 comparisons are retained in +[measurements.csv](algebraic-float/measurements.csv), including unrounded means, +mean confidence intervals and medians. The shared-fixture results below report +mean nanoseconds with marginal 95% confidence intervals. Negative changes mean +less time. Changes are descriptive point-estimate ratios, not paired confidence +intervals or application-level speedups. + +| D | Forward strict ns [95% CI] | Forward algebraic ns [95% CI] | Forward change | Reverse change | +|---|---------------------------|------------------------------|----------------|----------------| +| 2 | 0.928 [0.923, 0.932] | 0.952 [0.949, 0.954] | +2.6% | +1.4% | +| 3 | 1.387 [1.386, 1.389] | 1.766 [1.757, 1.776] | +27.3% | +28.0% | +| 4 | 2.413 [2.409, 2.420] | 1.856 [1.849, 1.864] | -23.1% | -21.6% | +| 5 | 3.529 [3.524, 3.535] | 2.633 [2.630, 2.636] | -25.4% | -25.0% | +| 8 | 8.737 [8.713, 8.764] | 5.281 [5.272, 5.294] | -39.6% | -39.6% | + +The D=4/D=5 reductions save roughly 0.5–0.9 ns per measured operation in both +orders; D=8 saves about 3.4 ns. The integer fixtures confirm the direction: +D=4 improves 23.5–23.6%, D=5 about 25%, and D=8 about 39–40%. The unfavorable +results also repeat: D=2 slows roughly 1–3%, and D=3 about 27–29%, across both +fixtures and orders. Thus algebraic arithmetic does unlock a material local +timing benefit at some dimensions, but not uniformly. These are throughput +measurements in Criterion's loop, not isolated-call latency. + +These timings characterize an **ineligible prototype on the checked fixtures**. +They cannot support a claim of a correctness-preserving library optimization, +and are not promoted into the release performance record. + +## Provenance and reproduction + +The strict source is commit `d1f85bb606735d5213a2fa5bd2692e5685a9adc4`, which +includes PR #278 / #246. The worktree was clean before the study. This captures +the landed strict candidate rather than the older #251 source; subsequent +release changes would require a refreshed baseline before any future adoption. + +- Compiler: Rust 1.99.0, commit + `b940084d7eb6a299eb4bfeb8e34901bc051e7ac4`, LLVM 23.1.1. +- Machine: Apple M4 Max, `aarch64-apple-darwin`, macOS 27.0.1 (26A434). +- Profile: optimized release, fat LTO, one codegen unit; no target-CPU override + or global floating-point flags. +- Library features: no default or optional features. Criterion 0.8.2 and the + rational oracle are isolated harness dependencies, not library dependencies. +- Source/benchmark inventory SHA-256: + `eec58161929f41d1a2d183aacca2b83f7af1fcfca9abe0c899fc9dd7a8961b30`. +- Repository Cargo.lock SHA-256: + `0cd6cc2d847bca04695955c4907d0a61550d4148f5f0568d514d27bf0c8e2c13`. +- Harness Cargo.lock SHA-256: + `28dea92b824d7856d83a6d68e40fbdb1ded51a947e54c8d8293a038563c7acdf`. + +The [evidence archive](algebraic-float/evidence.tar.gz) retains the disposable +harness and its dependency lock, a captured strict-source build tree, numerical +results, complete raw Criterion samples/estimates, assembly/IR, validation logs, +and downstream lockfile. Its SHA-256 is +`5d03f40ecf6df8d73733e79b69d44dbbbb7bec599dac6a566637573942c5cce0`. +The [provenance record](algebraic-float/provenance.json) also records experimental +source hashes and exact validation commands. +Extract the archive **outside** repository-owned Rust. From the +extracted directory, `bash measure.sh` rebuilds, checks the fixtures, and runs +both measurement orders. Offline reproduction requires the locked dependencies +already in Cargo's cache. `summarize.py`, run through this repository's locked +`uv` environment, validates the raw samples and produces the CSV. + +## Validation and scope closure + +The unchanged strict baseline passed 18 focused unit tests and 5 matrix property +tests selected by `norm_inf`, with `PROPTEST_CASES=256` and +`PROPTEST_RNG_SEED=250`. The isolated numerical experiment ran in release mode +on the native macOS host. + +An isolated copy of Delaunay commit +`bde38f4826cc248b425c4300cadd233417f7646c`, patched to the captured la-stack +implementation, passed 728 geometry unit tests, 26 geometry property tests and +18 predicate property tests under the same seed/case settings. These exercise +the **retained strict baseline**. They do not validate algebraic adoption: +the rejected candidate was never installed in a predicate or topology path. +The sibling checkout remained unchanged. + +The strict library and algebraic library probes also cross-compiled for +`x86_64-unknown-linux-gnu` and `x86_64-pc-windows-msvc`. Assembly/IR is retained. +Cross-compilation is not native numerical validation or performance evidence. +Native Linux/Windows execution remains unperformed; no suitable native runner +was available in this local session. + +Documentation validation passed `just markdown-fix` and `just markdown-ci` +(including spelling). Because ordinary archive content is excluded from the +active-document recipe, the new report and index also passed explicit rumdl +checks with exclusions disabled; the report/provenance passed explicit spelling +and JSON checks. The summary parser verified all 40 saved measurements have +100 positive finite samples and valid mean/median estimates. + +The original remaining work was native Linux/Windows execution of the prototype. +The maintainer discontinued it when accepting rejection and requesting closure +of #250 on 2026-10-15. It is not required for an adoption that will not proceed, +and is not transferred to a follow-up issue. The original native-platform +criterion remains unperformed. The archived provenance retains its measurement- +time status; the [validation decision](../../../validation/algebraic-floating-point.md) +owns the final scope disposition. + +## Decision + +| Function | Performance observation | Numerical result | Disposition | +|----------|-------------------------|------------------|-------------| +| `Matrix::norm_inf` | D=4/5 improves about 22–25%; D=2/3 regresses | D=4/D=5 overflow becomes a finite success; portable accuracy and error guarantees are unsupported | **Retain strict** | + +The experiment establishes that algebraic reassociation is not a scientifically +compatible replacement for this kernel, regardless of its fixture timing. +An opt-in name or feature flag would avoid changing old callers but would not +repair the missing numerical contract. No algebraic API or feature is planned. +Keep existing APIs and policy intact. diff --git a/docs/archive/performance/studies/algebraic-float/evidence.tar.gz b/docs/archive/performance/studies/algebraic-float/evidence.tar.gz new file mode 100644 index 0000000..e2058a0 Binary files /dev/null and b/docs/archive/performance/studies/algebraic-float/evidence.tar.gz differ diff --git a/docs/archive/performance/studies/algebraic-float/measurements.csv b/docs/archive/performance/studies/algebraic-float/measurements.csv new file mode 100644 index 0000000..c78ca5b --- /dev/null +++ b/docs/archive/performance/studies/algebraic-float/measurements.csv @@ -0,0 +1,21 @@ +phase,case,strict_mean_ns,strict_lower_ns,strict_upper_ns,algebraic_mean_ns,algebraic_lower_ns,algebraic_upper_ns,mean_change_percent,strict_median_ns,algebraic_median_ns,samples +forward,norm_inf_d2/shared,0.927597865128772,0.9225836922172839,0.9323582522273522,0.9515640139265816,0.9494430034392521,0.9537625570532765,2.5836787360956848,0.9292945036395077,0.9500016402758525,100 +forward,norm_inf_d2/integer,0.9349375212083778,0.930107884498767,0.9396870407085638,0.9560559452659273,0.9538743965734671,0.9582096355234785,2.258805917881501,0.9354991806398851,0.9552087613013167,100 +forward,norm_inf_d3/shared,1.3871946812693776,1.3856483004280225,1.3889656352716937,1.76570499042756,1.756612475335224,1.7763733414079341,27.28602655914305,1.38665833313528,1.7571839917819179,100 +forward,norm_inf_d3/integer,1.3905094775102262,1.3880460740754788,1.39340800498964,1.7799800754921946,1.771637068777385,1.7888164754404146,28.009201251855842,1.3877044565133312,1.762268332685367,100 +forward,norm_inf_d4/shared,2.4132471337423897,2.4085222241772772,2.4195705577418574,1.856497906577304,1.8491511314989089,1.8641650825242493,-23.07054339278116,2.4089200664087587,1.8448957560126424,100 +forward,norm_inf_d4/integer,2.4063748969667746,2.402932105562944,2.409925919103226,1.837877889328795,1.8329036132815382,1.8431650702453102,-23.624623426489688,2.4056620662819115,1.8328560465630865,100 +forward,norm_inf_d5/shared,3.5289677713664873,3.5239631952227044,3.5347245801207348,2.632891577435505,2.6296566061705837,2.6363979004749045,-25.39201976287824,3.527394536826784,2.629583734160991,100 +forward,norm_inf_d5/integer,3.5172594269750674,3.5116215685968677,3.5231849294900566,2.6346908578124557,2.6310124216186983,2.6385236008900126,-25.092507035275556,3.505466429066429,2.6323242947987584,100 +forward,norm_inf_d8/shared,8.73706870441741,8.71285949519179,8.763966300324524,5.281489738875437,5.271745932153643,5.293637760321763,-39.55078164596386,8.734600079178882,5.272242569731691,100 +forward,norm_inf_d8/integer,8.65637992563164,8.637456162010754,8.679160492865531,5.258937324819767,5.25033139441089,5.26844807298881,-39.24784528867554,8.629260877586036,5.250880334936356,100 +reverse,norm_inf_d2/shared,0.9425461034268335,0.9373741215899809,0.9471872840318858,0.9554231271157932,0.9537267891648213,0.9571666016369471,1.3661956314012125,0.9486026243273091,0.9539823000608195,100 +reverse,norm_inf_d2/integer,0.9296623137825241,0.9238814182107947,0.9351866360969971,0.9563853914461187,0.9544171431975277,0.9585272411750821,2.8744929494739058,0.9350992358364376,0.9538923943042279,100 +reverse,norm_inf_d3/shared,1.3877125767255543,1.3857238991733356,1.389909278485807,1.7768732386796726,1.7695909548136708,1.784744889372845,28.04331880254207,1.3877148679306686,1.7646823339630338,100 +reverse,norm_inf_d3/integer,1.3890700383301393,1.3860640538556819,1.393396245749414,1.7933097118914063,1.7855760248890569,1.801686073600065,29.101460862781316,1.3873014589787513,1.7828011056376776,100 +reverse,norm_inf_d4/shared,2.3890022923853396,2.3862304338594083,2.3920234190373417,1.874098769833389,1.8651764506934398,1.88350358021097,-21.55307779289891,2.38796717120237,1.853616553663022,100 +reverse,norm_inf_d4/integer,2.414249686674337,2.4105041195866135,2.418282094700567,1.8473851446526834,1.8409961672611663,1.8543029310617984,-23.4799467988134,2.4094111529682403,1.838171577887771,100 +reverse,norm_inf_d5/shared,3.5380318664021875,3.5314161444711596,3.5451103066386254,2.6548732182719137,2.651242855810126,2.6588054051503005,-24.96186245570351,3.533788815220764,2.6535135305046413,100 +reverse,norm_inf_d5/integer,3.527840392410189,3.5241911552273444,3.531559416588533,2.649187547141422,2.645269607510161,2.653556559456728,-24.9062527646972,3.527848751149211,2.647135803791846,100 +reverse,norm_inf_d8/shared,8.670552737716498,8.655313501963194,8.68865360867166,5.240989795212561,5.2333593697570455,5.249639725800309,-39.554144311763416,8.662874458926629,5.230901747808618,100 +reverse,norm_inf_d8/integer,8.680187905363274,8.664440134488656,8.696320487733631,5.231214597535335,5.225728607718562,5.236687453569558,-39.73385536615981,8.686163608369727,5.234872770316961,100 diff --git a/docs/archive/performance/studies/algebraic-float/provenance.json b/docs/archive/performance/studies/algebraic-float/provenance.json new file mode 100644 index 0000000..e1e30a8 --- /dev/null +++ b/docs/archive/performance/studies/algebraic-float/provenance.json @@ -0,0 +1,52 @@ +{ + "issue": "https://github.com/acgetchell/la-stack/issues/250", + "date": "2026-10-15", + "decision": "retain-strict", + "candidate": "Matrix::norm_inf", + "library_commit": "d1f85bb606735d5213a2fa5bd2692e5685a9adc4", + "strict_source": "strict-source", + "repository_cargo_lock_sha256": "0cd6cc2d847bca04695955c4907d0a61550d4148f5f0568d514d27bf0c8e2c13", + "source_benchmark_inventory_sha256": "eec58161929f41d1a2d183aacca2b83f7af1fcfca9abe0c899fc9dd7a8961b30", + "inventory_command": "rg --files src benches | LC_ALL=C sort | xargs shasum -a 256 | shasum -a 256", + "harness_cargo_lock_sha256": "28dea92b824d7856d83a6d68e40fbdb1ded51a947e54c8d8293a038563c7acdf", + "harness_library_sha256": "439102aceec0592a69a569547553b3343520a9c88b14feb17597c0bccd08c8dd", + "harness_main_sha256": "a340bca04dc59e7cac1ce034a07b10c08d30dc0afcea226b1f813c2b3b1757f0", + "rustc": "1.99.0", + "rustc_commit": "b940084d7eb6a299eb4bfeb8e34901bc051e7ac4", + "llvm": "23.1.1", + "host": "aarch64-apple-darwin", + "cpu": "Apple M4 Max", + "os": "macOS 27.0.1 (26A434)", + "profile": { "opt-level": 3, "lto": "fat", "codegen-units": 1 }, + "library_features": [], + "target_cpu_override": null, + "global_float_flags": [], + "criterion": { "version": "0.8.2", "samples": 100, "resamples": 100000, "warmup_seconds": 1, "measurement_seconds": 3, "confidence_level": 0.95, "noise_threshold": 0.01 }, + "benchmark_dimensions": [2, 3, 4, 5, 8], + "numerical_dimensions": [0, 1, 2, 3, 4, 5, 8, 16], + "measurement_command": "bash measure.sh", + "numerical_command": "target/release/algebraic-norm-study check", + "summarize_command": "uv run --locked --no-sync --group dev python /absolute/path/to/summarize.py", + "orders": { "forward": ["strict", "algebraic"], "reverse": ["algebraic", "strict"] }, + "numerical_oracle": "num-rational 0.4.2 exact rational sum of absolute binary64 inputs", + "random_seed": 250, + "random_matrices_per_dimension": 1000, + "validation": { + "environment": { "PROPTEST_CASES": "256", "PROPTEST_RNG_SEED": "250" }, + "upstream_command": "cargo +1.99.0 test --release --locked --offline norm_inf", + "upstream_unit_passed": 18, + "upstream_property_passed": 5, + "downstream_commit": "bde38f4826cc248b425c4300cadd233417f7646c", + "downstream_lock_sha256": "173cde045cd224bb6e8083242e517ce3171abca1ef1828f7693e36bc958508b8", + "downstream_geometry_command": "cargo +1.99.0 test --offline --locked --release --manifest-path /private/tmp/la-stack-250-downstream-20261015/Cargo.toml --config 'patch.crates-io.la-stack.path=\"/Users/adam/projects/la-stack\"' --lib geometry::", + "downstream_properties_command": "cargo +1.99.0 test --offline --locked --release --manifest-path /private/tmp/la-stack-250-downstream-20261015/Cargo.toml --config 'patch.crates-io.la-stack.path=\"/Users/adam/projects/la-stack\"' --test proptest_predicates --test proptest_geometry", + "downstream_geometry_passed": 728, + "downstream_geometry_property_passed": 26, + "downstream_predicate_property_passed": 18, + "downstream_candidate_installed": false, + "native_execution": ["aarch64-apple-darwin"], + "cross_compile_only": ["x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"], + "native_outstanding": ["Linux", "Windows"] + }, + "qualification": "Timing data describes an ineligible prototype on independently checked fixtures; it is not evidence of a correctness-preserving optimization or release-performance input." +} diff --git a/docs/code_organization.md b/docs/code_organization.md index d113aa4..9ddad17 100644 --- a/docs/code_organization.md +++ b/docs/code_organization.md @@ -233,6 +233,15 @@ The [vector-angle study](archive/performance/studies/vector-angles.md) owns the #249 formulation decision, comparative timings, and retained source provenance. The [triangular rational solve study](archive/performance/studies/rational-triangular.md) owns the #246 Rust 1.99 baseline, adapter/kernel comparisons, and retained evidence. +The [algebraic floating-point study](archive/performance/studies/algebraic-float.md) +owns the #250 numerical/performance experiment and its raw evidence. + +The [validation index](validation/README.md) maps arithmetic contracts +to independent tests and owns dated validation decisions and their limitations. +The [algebraic floating-point decision](validation/algebraic-floating-point.md) +records rejection and the maintainer's closure of unperformed prototype work. +Mathematical guarantees remain in `mathematical_basis.md`; performance archives +retain measurement data and experimental sources. When adding, removing, renaming, or moving files, update the applicable ownership rows here. Prefer links to the detailed owner over copying its procedure into diff --git a/docs/mathematical_basis.md b/docs/mathematical_basis.md index 4d918b3..7d9981e 100644 --- a/docs/mathematical_basis.md +++ b/docs/mathematical_basis.md @@ -85,6 +85,16 @@ finite. Arithmetic can still overflow, underflow, or round; computed non-finite values are reported through `LaError::NonFinite` rather than stored in a public matrix, vector, or factorization. +The floating-point arithmetic model uses ordinary `f64` operators and deliberate +`f64::mul_add` with defined single-rounding semantics. Here, **strict** means +preserving those operation contracts and each algorithm's documented evaluation +order; it does not mean exact real arithmetic or a universal bitwise +reproducibility guarantee across all platforms and library functions. +Rust's algebraic floating-point operations are not used. The +[validation decision](validation/algebraic-floating-point.md) records why their +measured speedups do not justify changed overflow behavior or unsupported +numerical guarantees. + Every finite binary64 value is a dyadic rational with an exact representation ```text @@ -112,6 +122,9 @@ error bounds. This includes plain `Vector::dot`, Euclidean and squared norms, matrix norms, factorizations, and solves. Some kernels use FMA to reduce rounding steps, but that does not make them exact. +The [validation index](validation/README.md#arithmetic-contracts-and-evidence) +connects these arithmetic contracts to independent tests and retained studies. + ## Tolerances and typed errors `Tolerance::try_new` accepts finite values greater than or equal to zero. diff --git a/docs/roadmap.md b/docs/roadmap.md index fec5488..8d23d48 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -269,14 +269,15 @@ Completed work included in this release: and representable subnormal angles. Results remain rounded without a certified error bound. -A bounded algebraic floating-point evaluation -([#250](https://github.com/acgetchell/la-stack/issues/250)) also targets `v0.5.0`. -Evaluate one or two promising kernels against the final strict implementation -under the Rust 1.99 / LLVM 23 baseline. A retained study and a justified -adopt, retain-strict, or defer decision are the outcome; adoption is conditional. -Ship a distinct opt-in API in `v0.5.0` only if its numerical contract, independent -correctness evidence, material performance benefit, and review are complete. -Existing APIs stay strict, and unresolved broader work must not delay the release. +The bounded algebraic floating-point evaluation +([#250](https://github.com/acgetchell/la-stack/issues/250)) concluded with a +**retain-strict** decision on 2026-10-15. The selected matrix-norm reduction +improved local timing at D=4/5 but hid a required overflow error. The maintainer +rejected adoption and ended the remaining prototype investigation; no algebraic +API or feature is planned. The +[validation record](validation/algebraic-floating-point.md) documents the +decision, executed checks, and unperformed native Linux/Windows runs; the +[study](archive/performance/studies/algebraic-float.md) retains the raw evidence. Remaining release sequence: @@ -305,10 +306,8 @@ and generated release artifacts are updated during dedicated release preparation ### v0.5.1 Follow-Up Work (planned) The [v0.5.1 milestone](https://github.com/acgetchell/la-stack/milestone/10) -holds compatible follow-up work after `v0.5.0`. If #250 establishes a promising -opt-in design that is not ready for `v0.5.0`, link a bounded adoption issue and -choose its release from the resulting contract and evidence. Adoption is not -presumed, and retaining strict arithmetic after a negative evaluation is valid. +holds compatible follow-up work after `v0.5.0`. The negative #250 decision +does not transfer an algebraic floating-point adoption task to this milestone. Changes incompatible with a published `v0.5` API require an appropriate later minor release. diff --git a/docs/validation/README.md b/docs/validation/README.md new file mode 100644 index 0000000..a1df6a7 --- /dev/null +++ b/docs/validation/README.md @@ -0,0 +1,53 @@ +# Scientific Validation Records + +This directory records scientific validation outcomes, decisions, and known +limits. The [mathematical basis](../mathematical_basis.md) owns the numerical +contracts and derivations; the records here link those contracts to retained +evidence. A passing test corpus supplements a contract or proof, rather than +establishing a guarantee for every representable input. + +## Contents + +- [Arithmetic contracts and evidence](#arithmetic-contracts-and-evidence) +- [Decision records](#decision-records) +- [Record scope](#record-scope) + +## Arithmetic contracts and evidence + +The distinction between rounded values, certified bounds, and exact results is +part of the public contract. The table maps those distinctions to existing +documentation and tests; it is not a claim that every suite was rerun for the +latest decision record. + +| Arithmetic path | Contract and limitation | Representative evidence | +|-----------------|-------------------------|-------------------------| +| Certified floating reductions and determinants | [Bounds apply under documented assumptions](../mathematical_basis.md#certified-fixed-vector-reductions); an inconclusive filter requires fallback | [Independent rational bound/sign oracles](../../tests/proptest_exact.rs) | +| Exact arithmetic over binary64 inputs | [Exact for the stored values](../mathematical_basis.md#exact-arithmetic-over-binary64-inputs); earlier rounding cannot be recovered | [Exact determinants, residuals, and mixed-scale properties](../../tests/proptest_exact.rs) | +| Exact arithmetic over rational inputs | [Coefficients enter the exact domain directly](../mathematical_basis.md#exact-arithmetic-over-rational-inputs) | [Rational Gaussian and residual oracles](../../tests/proptest_rational.rs), [structured solves](../../tests/rational_structured_solve.rs) | +| Exact-to-binary64 conversion | [Strict conversion rejects required rounding](../mathematical_basis.md#exact-to-binary64-conversion); explicit rounded conversion opts into ties-to-even | [Rounding, signed-zero, subnormal, and overflow boundaries](../../tests/exact_conversion_boundaries.rs) | +| Outward-rounded interval arithmetic | [Encloses the expression assembled with interval operations](../mathematical_basis.md#outward-rounded-interval-expressions); not an exact point value | [Rational containment and sign checks](../../tests/proptest_interval.rs) | +| Strict `f64` arithmetic | [Defined binary64 operations and deliberate FMA](../mathematical_basis.md#represented-values-and-arithmetic-model); ordinary rounded APIs are not exact or automatically certified | [Matrix properties](../../tests/proptest_matrix.rs), [integer vector oracles](../../tests/proptest_vector.rs), [compiler migration study](../archive/performance/studies/rust-1.99.md) | + +`strict f64` describes the arithmetic model. `strict exact-to-f64 conversion` +describes whether an exact value can be returned without rounding. These are +different contracts: a strict floating-point algorithm can accumulate rounding +error, while a successful strict exact conversion preserves the exact result. + +## Decision records + +- [Algebraic floating-point rejection (#250)](algebraic-floating-point.md): + retained timing benefits do not justify a demonstrated overflow-contract + violation; keep strict arithmetic and end the evaluation. + +## Record scope + +Each record identifies the source revision, environment, independent reference, +executed checks, observed failures, decision, and unperformed work. Raw +performance samples and experimental source remain with their +[archived study](../archive/performance/studies/README.md) rather than being +copied here. Cross-compilation is distinct from native execution, and downstream +tests of unchanged code do not validate a rejected prototype. + +Test-design policy belongs in [testing guidance](../dev/testing.md); current +validation commands belong in the +[contributor workflow](../../CONTRIBUTING.md#validation-workflow). diff --git a/docs/validation/algebraic-floating-point.md b/docs/validation/algebraic-floating-point.md new file mode 100644 index 0000000..bb846e7 --- /dev/null +++ b/docs/validation/algebraic-floating-point.md @@ -0,0 +1,77 @@ +# Algebraic Floating-Point Decision + +**Decision, 2026-10-15:** reject algebraic floating-point operations and retain +strict arithmetic. The maintainer ended the investigation and requested closure +of [#250](https://github.com/acgetchell/la-stack/issues/250) with this negative +result. The [closing decision](https://github.com/acgetchell/la-stack/issues/250#issuecomment-6196794247) +records the evidence and scope disposition. No algebraic API, feature, or +adoption follow-up is planned. + +## Contents + +- [Reason for rejection](#reason-for-rejection) +- [Recorded validation](#recorded-validation) +- [Evidence and scope closure](#evidence-and-scope-closure) + +## Reason for rejection + +The isolated `Matrix::norm_inf` prototype changed positive row additions to +`algebraic_add`. For a D=4 row `[2^969, 2^969, f64::MAX, 0]`, strict accumulation +reports `LaError::NonFinite`, with operation `MatrixInfinityNorm` and location +`MatrixCell { row: 0, col: 2 }`. The algebraic version instead returns the finite +value `f64::MAX`. Appending a zero reproduces the failure in D=5. A final +finite-result check cannot catch an overflow hidden by reassociation. + +The prototype reduced measured runtime about 22–25% at D=4/5 and 39–40% at D=8, +with both measurement orders confirming the direction. D=2/3 regressed. Those +timings describe an ineligible prototype on independently checked fixtures; +they do not establish a correctness-preserving optimization. The +[study](../archive/performance/studies/algebraic-float.md) retains absolute +timings, uncertainty, the mathematical counterexample, and compiler analysis. + +Rust's [algebraic-operator semantics][algebraic-contract] also provide no +portable accuracy or repeatability guarantee for these operations. An opt-in +API would not repair the unsupported scientific contract. Existing ordinary +operators, deliberate single-rounding `mul_add`, certified bounds, and exact +fallbacks remain the supported arithmetic model; see the +[arithmetic contracts](README.md#arithmetic-contracts-and-evidence). + +[algebraic-contract]: https://doc.rust-lang.org/std/primitive.f32.html#algebraic-operators + +## Recorded validation + +The la-stack source was +`d1f85bb606735d5213a2fa5bd2692e5685a9adc4`, including PR #278. Native execution +used Rust 1.99.0 / LLVM 23.1.1 on an Apple M4 Max with macOS 27.0.1, +`aarch64-apple-darwin`. Measurements used optimized release builds with fat LTO +and one codegen unit. No library behavior changed. + +| Evidence | Observed outcome | Scope | +|----------|------------------|-------| +| Independent exact rational summation | Explicit D=4/5 overflow classification failures; finite-value differences also retained | Prototype compared with the strict method and exact binary64-value reference | +| Adversarial and random inputs | Signed zero, subnormals, mixed/extreme magnitudes, range boundaries, input rejection, and 1,000 random matrices per dimension | D=0, 1, 2, 3, 4, 5, 8, 16; cancellation is inapplicable to absolute row sums | +| Upstream norm checks | 18 unit tests and 5 matrix property tests passed | Unchanged strict implementation; 256 property cases, seed 250 | +| Downstream Delaunay checks | 728 geometry unit tests, 26 geometry properties, and 18 predicate properties passed | Unchanged strict la-stack patched into Delaunay commit `bde38f4826cc248b425c4300cadd233417f7646c`; prototype not installed | +| Criterion measurements | 40 saved measurements, each with 100 samples; all ten dimension/fixture pairs repeated in reverse order | D=2–5 and D=8; exact fixture checks outside timing | +| Linux and Windows targets | Strict library and prototype probes cross-compiled | No native numerical execution or performance measurement | + +These are historical results for the recorded revisions, not a full validation +of every arithmetic API or a cross-platform reproducibility promise. + +## Evidence and scope closure + +The [full study](../archive/performance/studies/algebraic-float.md), +[measurements](../archive/performance/studies/algebraic-float/measurements.csv), +[provenance](../archive/performance/studies/algebraic-float/provenance.json), and +[evidence archive](../archive/performance/studies/algebraic-float/evidence.tar.gz) +retain the sources, locks, raw samples, numerical outputs, compiler probes, and +test logs. Experimental Rust must be extracted outside repository-owned source. + +The original plan called for native Linux and Windows prototype execution. +Those runs were not performed. On 2026-10-15 the maintainer accepted rejection +and discontinued that remaining experimental work: there is no candidate to +ship and no adoption decision awaiting those runs. This is an explicit scope +closure, not a claim that the original native-platform criterion passed. +The archived provenance preserves the earlier execution status; this record +owns the final disposition. Normal cross-platform validation of the strict +library continues independently. diff --git a/pyproject.toml b/pyproject.toml index 1d2aef6..f6b05ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -146,7 +146,7 @@ exclude = [ "docs/archive/**", "docs/performance/**", "docs/performance.md" ] path = "README.md" pattern = 'https://(?:github\.com/acgetchell/la-stack/(?:blob|raw|tree)/|raw\.githubusercontent\.com/acgetchell/la-stack/)(?Pmain|v[0-9]+\.[0-9]+\.[0-9]+|[0-9a-f]{7,40})/[^\s)\]>"?]+' value = "main" -count = 31 +count = 32 exclude = '/docs/assets/bench/' [[tool.research-repo-tools.release.rules]]