Skip to content

perf: integer-only forward elimination for gauss_solve (#72)#96

Merged
acgetchell merged 3 commits intomainfrom
perf/72-bareiss-hybrid-solve
Apr 21, 2026
Merged

perf: integer-only forward elimination for gauss_solve (#72)#96
acgetchell merged 3 commits intomainfrom
perf/72-bareiss-hybrid-solve

Conversation

@acgetchell
Copy link
Copy Markdown
Owner

@acgetchell acgetchell commented Apr 20, 2026

Replace BigRational-only gauss_solve with a hybrid that runs
Bareiss fraction-free forward elimination in BigInt on the
augmented (A | b) system, then back-substitutes in BigRational.
Eliminates GCD normalization from the O(D^3) phase while keeping
rational overhead limited to the cheaper O(D^2) back-sub.

Scope f64_to_bigrational to cfg(test); production code paths now
use f64_decompose directly (shared with bareiss_det_int).

Closes #72

Co-Authored-By: Oz <oz-agent@warp.dev>

Summary by CodeRabbit

  • Bug Fixes

    • More robust and accurate exact linear-system solving for floating-point inputs, with improved handling of non-finite values and extreme/mixed-magnitude entries.
  • Documentation

    • Updated solver documentation to describe the new exact-solve approach and its invariants.
  • Tests

    • Expanded tests covering solve correctness, edge cases (subnormals, large values), pivot scenarios, and determinant error conditions.

Replace BigRational-only gauss_solve with a hybrid that runs
    Bareiss fraction-free forward elimination in BigInt on the
    augmented (A | b) system, then back-substitutes in BigRational.
    Eliminates GCD normalization from the O(D^3) phase while keeping
    rational overhead limited to the cheaper O(D^2) back-sub.

    Scope f64_to_bigrational to cfg(test); production code paths now
    use f64_decompose directly (shared with bareiss_det_int).

    Closes #72

    Co-Authored-By: Oz <oz-agent@warp.dev>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7405f75a-7144-4d5d-a093-ffb442f5209a

📥 Commits

Reviewing files that changed from the base of the PR and between ecbbe8a and 53a5be6.

📒 Files selected for processing (1)
  • src/exact.rs

📝 Walkthrough

Walkthrough

Replaced the prior BigRational-based exact solve with a hybrid pipeline: IEEE‑754 f64 decomposition → scale to a common 2^e_min → Bareiss fraction-free forward elimination on BigInt (augmented matrix), then lift only necessary entries into BigRational for back-substitution; documentation and tests updated accordingly.

Changes

Cohort / File(s) Summary
Documentation
REFERENCES.md
Rewrote f64_to_bigrational documentation to describe the new exact-solve pipeline: f64_decompose, uniform power-of-two scaling, integer Bareiss elimination core, and BigRational lifting during back-substitution.
Exact solver implementation & tests
src/exact.rs
Implemented shared f64 decomposition and integer-scaling pipeline; added bareiss_det_int-style integer forward elimination for solves (augmented `(A

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller
    participant Decomp as f64_decompose
    participant FwdElim as Forward Elimination<br/>(BigInt Bareiss)
    participant BackSub as Back-Substitution<br/>(BigRational)
    participant Result as Solution

    Caller->>Decomp: Decompose matrix & RHS (IEEE‑754 → mantissa × 2^exp)
    Decomp-->>FwdElim: mantissas, exponents, e_min
    FwdElim->>FwdElim: Scale to common 2^e_min → BigInt augmented matrix
    FwdElim->>FwdElim: Bareiss fraction-free elimination (O(D³)), mirror RHS on row swaps
    FwdElim-->>BackSub: Upper-triangular BigInt matrix + scaled RHS
    BackSub->>BackSub: Convert needed BigInt entries → BigRational
    BackSub->>BackSub: Rational back-substitution (O(D²))
    BackSub-->>Result: Exact `BigRational` solution vector
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related issues

Possibly related PRs

Suggested labels

performance, rust, testing, enhancement, documentation

Poem

🐰 Through bits and powers‑two I hop,

I scale, I Bareiss, I never stop,
Forward crisp in BigInt light,
Back-substitute to rationals right,
A rabbit's dance of numbers bright.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: replacing BigRational-only gauss_solve with integer-only forward elimination, which is the primary performance optimization in this PR.
Linked Issues check ✅ Passed The PR fulfills all core requirements from issue #72: hybrid BigInt/BigRational solve with Bareiss forward elimination, f64 decomposition shared with determinant, RHS synchronization across row swaps, existing tests passing, and documented speedups (-42% to -54% for D=3–4).
Out of Scope Changes check ✅ Passed All changes are scoped to the hybrid solve objective: REFERENCES.md documents the new algorithm, src/exact.rs implements Bareiss forward elimination with shared f64_decompose, validation is centralized, and test-only f64_to_bigrational remains for backward compatibility.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/72-bareiss-hybrid-solve

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 20, 2026

Codecov Report

❌ Patch coverage is 90.24390% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.16%. Comparing base (119bceb) to head (53a5be6).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
src/exact.rs 90.24% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #96      +/-   ##
==========================================
- Coverage   94.74%   93.16%   -1.59%     
==========================================
  Files           5        5              
  Lines         514      512       -2     
==========================================
- Hits          487      477      -10     
- Misses         27       35       +8     
Flag Coverage Δ
unittests 93.16% <90.24%> (-1.59%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Migrate the exact linear solver to a hybrid approach that performs O(D³)
forward elimination using fraction-free Bareiss updates on integers,
limiting BigRational arithmetic to the O(D²) back-substitution phase.
This eliminates per-entry GCD overhead during elimination. Internal f64
decomposition is unified via f64_decompose, and f64_to_bigrational is
moved to test scope.

Refs: #72
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/exact.rs (1)

1650-1709: Consider macro-generating these hybrid edge cases for D=2 through D=5.

These are valuable regressions for the generic solve_exact path, but most are pinned to D=2/D=3. The diagonal, subnormal-RHS, and pivot-block cases can be embedded in larger identity systems so the same hybrid path is covered across D=2–5.

Example shape for extending one case
+    macro_rules! gen_solve_exact_large_finite_entries_tests {
+        ($d:literal) => {
+            paste! {
+                #[test]
+                fn [<solve_exact_large_finite_entries_ $d d>]() {
+                    let big = f64::MAX / 2.0;
+                    assert!(big.is_finite());
+
+                    let mut rows = [[0.0f64; $d]; $d];
+                    let mut b_arr = [0.0f64; $d];
+                    for i in 0..$d {
+                        rows[i][i] = big;
+                        b_arr[i] = if i + 1 == $d { 0.0 } else { big };
+                    }
+
+                    let a = Matrix::<$d>::from_rows(rows);
+                    let b = Vector::<$d>::new(b_arr);
+                    let x = a.solve_exact(b).unwrap();
+                    for i in 0..$d {
+                        let expected = if i + 1 == $d { 0 } else { 1 };
+                        assert_eq!(x[i], BigRational::from_integer(BigInt::from(expected)));
+                    }
+                }
+            }
+        };
+    }
+
+    gen_solve_exact_large_finite_entries_tests!(2);
+    gen_solve_exact_large_finite_entries_tests!(3);
+    gen_solve_exact_large_finite_entries_tests!(4);
+    gen_solve_exact_large_finite_entries_tests!(5);

As per coding guidelines, tests for dimension-generic code must cover D=2 through D=5 whenever possible using macros for per-dimension test generation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/exact.rs` around lines 1650 - 1709, Tests currently only cover specific
dimensions (D=2/3); create macro-generated tests for D=2..=5 to satisfy the
guideline. Add a macro (using macro_rules!) that expands each existing test case
(solve_exact_large_finite_entries, solve_exact_mixed_magnitude_entries,
solve_exact_subnormal_rhs, solve_exact_pivot_swap_with_fractional_result) for
dimensions 2 through 5 by constructing matrices/vectors of generic size: for
diagonal/large/mixed/subnormal cases build a D×D diagonal or identity padded
matrix using Matrix::<D>::from_rows and Vector::<D>::new; for the pivot swap
case embed the 2×2 test block into the top-left of a D×D identity and pad RHS
accordingly so the same expected BigRational results hold in the corresponding
indices; generate distinct test function names per D (e.g.
solve_exact_large_finite_entries_D3) so each expands to a #[test] and uses the
same assertions (adjusting indices where embedded).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/exact.rs`:
- Around line 1650-1709: Tests currently only cover specific dimensions (D=2/3);
create macro-generated tests for D=2..=5 to satisfy the guideline. Add a macro
(using macro_rules!) that expands each existing test case
(solve_exact_large_finite_entries, solve_exact_mixed_magnitude_entries,
solve_exact_subnormal_rhs, solve_exact_pivot_swap_with_fractional_result) for
dimensions 2 through 5 by constructing matrices/vectors of generic size: for
diagonal/large/mixed/subnormal cases build a D×D diagonal or identity padded
matrix using Matrix::<D>::from_rows and Vector::<D>::new; for the pivot swap
case embed the 2×2 test block into the top-left of a D×D identity and pad RHS
accordingly so the same expected BigRational results hold in the corresponding
indices; generate distinct test function names per D (e.g.
solve_exact_large_finite_entries_D3) so each expands to a #[test] and uses the
same assertions (adjusting indices where embedded).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 31d45828-074e-4e3e-ad5e-4e76d786502f

📥 Commits

Reviewing files that changed from the base of the PR and between 119bceb and ecbbe8a.

📒 Files selected for processing (2)
  • REFERENCES.md
  • src/exact.rs

Major refactor of `src/exact.rs`:

- Extract shared Bareiss primitives (`decompose_matrix`, `decompose_vec`,
  `component_to_bigint`, `build_bigint_matrix`, `build_bigint_vec`,
  `bareiss_forward_eliminate`) so `bareiss_det_int` and `gauss_solve`
  share a single integer-Bareiss core.
- Hybrid BigInt/BigRational solve: forward elimination runs entirely in
  `BigInt` with fraction-free Bareiss updates on `(A | b)`; only the
  `O(D²)` back-substitution phase lifts into `BigRational`.
- `mem::take` in back-substitution eliminates per-entry `clone()` calls
  on `rhs[i]`, `a[i][j]`, `a[i][i]`.

Structured errors replace preconditions:

- `decompose_matrix` / `decompose_vec` fold `is_finite()` into the same
  pass that decomposes each entry and return
  `Err(LaError::NonFinite { row, col })` on the first non-finite cell.
- `bareiss_det_int`, `bareiss_det`, `gauss_solve` now return
  `Result<_, LaError>`; error propagates to every public entry point via
  `?`.
- `validate_finite` and `validate_finite_vec` removed (dead after the
  refactor); `det_sign_exact` relies on IEEE 754 NaN/∞ propagation
  through `det_direct()` plus `bareiss_det_int` for Stage-2 validation.

Polish:

- Promote `Component` from tuple alias to `#[derive(Clone, Copy, Default)]`
  struct with named `mantissa`/`exponent`/`is_negative` fields.
- `BareissResult` derives `Debug`.
- Debug-only post-conditions in `bareiss_forward_eliminate` assert
  upper-triangular shape + non-zero pivots (zero cost in release).
- `cold_path()` hints at every rare branch (singular detection inside
  `bareiss_forward_eliminate`, singular match arm in `bareiss_det_int`,
  non-finite detection in `decompose_*`).
- Hoist `core::mem::take` import to module top; use unqualified `take`.
- Refresh module-level docs with a `## Validation` section describing
  the single-pass validate+decompose flow.

Tests:

- Macro-generated D=2..5 coverage for `solve_exact`:
  `large_finite_entries`, `mixed_magnitude_entries`, `subnormal_rhs`,
  `pivot_swap_with_fractional_result`, `mid_pivot_swap` (D=3..5),
  `singular_rank_deficient`, `zero_rhs`.
- Direct `Err(LaError::NonFinite)` assertions for `bareiss_det_int`
  (NaN/∞ input).
- Consolidate four `bareiss_det_int_d1_*` tests into one table-driven
  `bareiss_det_int_d1_cases`.
- Remove three `validate_finite_*` and three `validate_finite_vec_*`
  tests whose coverage is now transitively exercised via the public API
  error-path tests.

Benchmarks (`cargo bench --features "bench exact" --bench exact`):

- exact_d3/solve_exact:       -42% to -43%
- exact_d4/solve_exact:       -53% to -54%
- exact_d3/solve_exact_f64:   -42% to -43%
- exact_d4/solve_exact_f64:   -54% to -55%
- exact_d3/det_sign_exact:    -26% to -27%
- exact_d4/det_sign_exact:    -15% to -16%
- exact_d4/det_exact(_f64):   +2% to +4% (minor; Result propagation)
- exact_d5: no change detected

Verification:

- `cargo test --features exact --lib`: 359 passed, 0 failed.
- `cargo clippy --features exact --all-targets -- -D warnings`: clean.
- `just ci`: passes.

Co-Authored-By: Oz <oz-agent@warp.dev>
@acgetchell acgetchell merged commit 2d49d73 into main Apr 21, 2026
9 checks passed
@acgetchell acgetchell deleted the perf/72-bareiss-hybrid-solve branch April 21, 2026 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant