Skip to content

feat: const-ify Lu/Ldlt det + solve_vec and Matrix inf_norm + det_err…#95

Merged
acgetchell merged 3 commits intomainfrom
feat/86-const-ify-methods
Apr 20, 2026
Merged

feat: const-ify Lu/Ldlt det + solve_vec and Matrix inf_norm + det_err…#95
acgetchell merged 3 commits intomainfrom
feat/86-const-ify-methods

Conversation

@acgetchell
Copy link
Copy Markdown
Owner

@acgetchell acgetchell commented Apr 20, 2026

…bound

Make six public methods const fn, completing const-evaluation parity with Matrix::det_direct and Vector::dot now that MSRV 1.95 exposes f64::mul_add as const (1.94) and core::hint::cold_path as const (1.95):

  • Lu::det, Lu::solve_vec
  • Ldlt::det, Ldlt::solve_vec
  • Matrix::inf_norm, Matrix::det_errbound

Iterator chains (.iter().map().sum(), .enumerate().take(i), .enumerate().skip(i + 1), .iter_mut().enumerate().take(D)) were rewritten as while loops since they are not const-stable.

Fix error-variant correctness in both solve_vec paths:

  • A corrupt stored U / D diagonal at (i, i) now surfaces as LaError::NonFinite { row: Some(i), col: i }, matching the convention used by Matrix::det, Lu::factor, and Ldlt::factor.
  • A computed-intermediate overflow keeps row: None, col: i.
  • Previously both were conflated into row: None, col: i, defeating debuggability for callers who construct factorizations directly.

Sharpen LaError::NonFinite variant docs and the # Errors sections of Lu::solve_vec / Ldlt::solve_vec to spell out the (row, col) contract for each failure mode.

Cleanup:

  • Import ERR_COEFF_{2,3,4} at src/matrix.rs top; drop crate:: prefixes inside Matrix::det_errbound.
  • Rename intermediate bindings q / vquotient to stay under clippy::many_single_char_names.
  • Rename const-evaluability tests from *_is_const_evaluable_* to *_const_eval_* for a concise, consistent style.

Tests:

  • Added {lu,ldlt,inf_norm,det_errbound}_const_eval_* tests that force compile-time evaluation inside const { … } initializers.
  • Added solve_vec_defensive_non_finite_diagonal_{2,3,4,5}d in src/lu.rs covering the new split error path (previously only the Singular defensive path was exercised).
  • Updated matching Ldlt defensive tests to assert the new row: Some(D - 1), col: D - 1 payload.

Validation: just ci passes — 164 unit tests, 324 integration/feature tests, 28 doctests; clippy pedantic + nursery as errors; all examples.

Summary by CodeRabbit

  • New Features

    • Several math APIs (determinant, solve/vector-solve, inf-norm, error-bound) are now const-evaluable so they can be used at compile time.
  • Bug Fixes

    • More precise non-finite/NaN error reporting now returns exact row/column coordinates for matrix and vector issues.
  • Documentation

    • Expanded determinant error‑bound docs and clarified non-finite coordinate conventions; README and reference docs updated.
  • Tests

    • Added compile-time tests to validate const-evaluation of key math paths.

…bound

Make six public methods `const fn`, completing const-evaluation parity
with `Matrix::det_direct` and `Vector::dot` now that MSRV 1.95 exposes
`f64::mul_add` as const (1.94) and `core::hint::cold_path` as const
(1.95):

- `Lu::det`, `Lu::solve_vec`
- `Ldlt::det`, `Ldlt::solve_vec`
- `Matrix::inf_norm`, `Matrix::det_errbound`

Iterator chains (`.iter().map().sum()`, `.enumerate().take(i)`,
`.enumerate().skip(i + 1)`, `.iter_mut().enumerate().take(D)`) were
rewritten as `while` loops since they are not const-stable.

Fix error-variant correctness in both solve_vec paths:

- A corrupt stored `U` / `D` diagonal at `(i, i)` now surfaces as
  `LaError::NonFinite { row: Some(i), col: i }`, matching the
  convention used by `Matrix::det`, `Lu::factor`, and `Ldlt::factor`.
- A computed-intermediate overflow keeps `row: None, col: i`.
- Previously both were conflated into `row: None, col: i`, defeating
  debuggability for callers who construct factorizations directly.

Sharpen `LaError::NonFinite` variant docs and the `# Errors` sections of
`Lu::solve_vec` / `Ldlt::solve_vec` to spell out the `(row, col)`
contract for each failure mode.

Cleanup:

- Import `ERR_COEFF_{2,3,4}` at `src/matrix.rs` top; drop `crate::`
  prefixes inside `Matrix::det_errbound`.
- Rename intermediate bindings `q` / `v` → `quotient` to stay under
  `clippy::many_single_char_names`.
- Rename const-evaluability tests from `*_is_const_evaluable_*` to
  `*_const_eval_*` for a concise, consistent style.

Tests:

- Added `{lu,ldlt,inf_norm,det_errbound}_const_eval_*` tests that force
  compile-time evaluation inside `const { … }` initializers.
- Added `solve_vec_defensive_non_finite_diagonal_{2,3,4,5}d` in
  `src/lu.rs` covering the new split error path (previously only the
  `Singular` defensive path was exercised).
- Updated matching `Ldlt` defensive tests to assert the new
  `row: Some(D - 1), col: D - 1` payload.

Validation: `just ci` passes — 164 unit tests, 324 integration/feature
tests, 28 doctests; clippy pedantic + nursery as errors; all examples.

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

coderabbitai Bot commented Apr 20, 2026

Warning

Rate limit exceeded

@acgetchell has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 49 minutes and 2 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 49 minutes and 2 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 352deba1-fd3a-4bab-afa2-8a25290f47c5

📥 Commits

Reviewing files that changed from the base of the PR and between 0b98d3f and f8d80a0.

📒 Files selected for processing (2)
  • src/ldlt.rs
  • src/matrix.rs
📝 Walkthrough

Walkthrough

Converts several linear-algebra routines to const fn (Ldlt.det/solve_vec, Lu.det/solve_vec, Matrix.inf_norm, Matrix.det_errbound), rewrites iterator-based loops to index-based while loops for const-evaluation, adds two LaError helper constructors and standardizes NonFinite error coordinate conventions, plus updated tests and documentation.

Changes

Cohort / File(s) Summary
LDLT Factorization
src/ldlt.rs
Made det and solve_vec pub const fn; rewrote loops to index-based while loops; switched NonFinite construction to LaError::non_finite_cell/at; added const-evaluability tests and adjusted defensive error expectations.
LU Factorization
src/lu.rs
Made det and solve_vec pub const fn; replaced iterator-based loops with index while loops; refined NonFinite reporting (stored-diagonal → non_finite_cell, computed intermediates → non_finite_at); added const-eval tests and defensive coverage.
Matrix Operations
src/matrix.rs
Made inf_norm and det_errbound pub const fn; replaced iterator sums with explicit index loops while preserving NaN short-circuiting; updated tests for const-eval and adjusted det error reporting to use non_finite_*.
Exact / Validation
src/exact.rs
Replaced direct LaError::NonFinite { .. } constructions with LaError::non_finite_cell and LaError::non_finite_at in finite validators; behavior unchanged aside from error-constructor calls.
Errors & Docs
src/lib.rs
Added impl LaError helpers: pub const fn non_finite_cell(row, col) and pub const fn non_finite_at(col); expanded docs to define (row, col) conventions for stored cells vs computed/vector positions.
Tests & Changelog / Docs / Config
CHANGELOG.md, README.md, REFERENCES.md, tests under src/..., typos.toml
Added/updated const-evaluability tests for det/solve_vec/inf_norm/det_errbound; updated CHANGELOG, README (replaced benchmarks with AI Agents section), REFERENCES; excluded CHANGELOG.md in typos.toml.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested labels

documentation, enhancement, rust, testing, api

Poem

🐰
I hopped through loops both short and long,
Replaced iter chains with a steady song;
Now constants hum at build-time bright,
Errors point where NaNs took flight —
A rabbit's cheer for compile-time light!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 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: making Lu/Ldlt det/solve_vec and Matrix inf_norm/det_errbound const functions.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/86-const-ify-methods

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 97.70115% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.74%. Comparing base (aba1dc7) to head (f8d80a0).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
src/lu.rs 94.59% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #95      +/-   ##
==========================================
+ Coverage   90.96%   94.74%   +3.78%     
==========================================
  Files           5        5              
  Lines         498      514      +16     
==========================================
+ Hits          453      487      +34     
+ Misses         45       27      -18     
Flag Coverage Δ
unittests 94.74% <97.70%> (+3.78%) ⬆️

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.

Synchronize the CHANGELOG, README, and REFERENCES for the upcoming release.
This includes documenting the new absolute error bound coefficients for
determinants, adding a dedicated section for AI agent governance, and
refining internal error helpers to use a more consistent coordinate
convention for non-finite values.

Refs: #86
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 (2)
src/ldlt.rs (1)

561-610: Consider extending const-eval tests across D=2..5 via a macro.

The const-evaluability tests here (ldlt_det_const_eval_d2, _d3, and ldlt_solve_vec_const_eval_d2) only cover a subset of dimensions, whereas the existing gen_public_api_ldlt_* and gen_solve_vec_defensive_tests macros in this file already cover D=2..5. Since the const fn lowering is identical across D, a gen_ldlt_const_eval_tests! macro would keep coverage consistent with the rest of the module and the project convention without adding meaningful maintenance cost.

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/ldlt.rs` around lines 561 - 610, The const-eval tests only exercise D=2
and D=3 (and one solve_vec at D=2) but should cover D=2..5 like the other
dimension-generic tests; add a macro (e.g., gen_ldlt_const_eval_tests!) that
generates const-evaluability tests for Ldlt::<D>::det() and
Ldlt::<D>::solve_vec(...) for D = 2..5, reuse the same test patterns in the
existing ldlt_det_const_eval_d2/3 and ldlt_solve_vec_const_eval_d2 tests, and
invoke the macro for the range 2..=5 so coverage matches the other macros
(gen_public_api_ldlt_* / gen_solve_vec_defensive_tests) and ensures Ldlt and its
const fns are exercised across dimensions.
src/matrix.rs (1)

912-950: Consider extending const-eval tests to D=4 and D=5 (where applicable).

det_errbound_const_eval_* covers D=2,3 and inf_norm_const_eval_* covers D=2,3; det_direct_const_eval_* likewise. det_errbound additionally has a meaningful D=4 branch (and D=5 → None) worth exercising under const { … }, and inf_norm is dimension-agnostic so macro-generated D=2..5 coverage would match the convention used by gen_public_api_matrix_tests! and gen_inf_norm_nonfinite_tests! elsewhere in this file.

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/matrix.rs` around lines 912 - 950, Add const-eval tests for dimensions 4
and 5 to match guidelines: extend the det_errbound_const_eval_* and
inf_norm_const_eval_* coverage to include Matrix::<4> and Matrix::<5> cases
(noting det_errbound has a meaningful D=4 branch and returns None for D=5),
using the same const { ... } pattern or the existing test-generation macro
pattern (e.g., mirror gen_public_api_matrix_tests!/gen_inf_norm_nonfinite_tests!
approach) so det_errbound(), inf_norm(), and det_direct_const_eval_* are
exercised for D=2..5; update or add macro-driven tests that call
Matrix::<4>::from_rows/... and Matrix::<5>::from_rows/... (or identity() where
appropriate) and assert the expected Option or numeric results.
🤖 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/ldlt.rs`:
- Around line 561-610: The const-eval tests only exercise D=2 and D=3 (and one
solve_vec at D=2) but should cover D=2..5 like the other dimension-generic
tests; add a macro (e.g., gen_ldlt_const_eval_tests!) that generates
const-evaluability tests for Ldlt::<D>::det() and Ldlt::<D>::solve_vec(...) for
D = 2..5, reuse the same test patterns in the existing ldlt_det_const_eval_d2/3
and ldlt_solve_vec_const_eval_d2 tests, and invoke the macro for the range 2..=5
so coverage matches the other macros (gen_public_api_ldlt_* /
gen_solve_vec_defensive_tests) and ensures Ldlt and its const fns are exercised
across dimensions.

In `@src/matrix.rs`:
- Around line 912-950: Add const-eval tests for dimensions 4 and 5 to match
guidelines: extend the det_errbound_const_eval_* and inf_norm_const_eval_*
coverage to include Matrix::<4> and Matrix::<5> cases (noting det_errbound has a
meaningful D=4 branch and returns None for D=5), using the same const { ... }
pattern or the existing test-generation macro pattern (e.g., mirror
gen_public_api_matrix_tests!/gen_inf_norm_nonfinite_tests! approach) so
det_errbound(), inf_norm(), and det_direct_const_eval_* are exercised for
D=2..5; update or add macro-driven tests that call Matrix::<4>::from_rows/...
and Matrix::<5>::from_rows/... (or identity() where appropriate) and assert the
expected Option or numeric results.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b1830124-f85b-4b2f-9338-3d9a673ea0d6

📥 Commits

Reviewing files that changed from the base of the PR and between 81ecb35 and 0b98d3f.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • README.md
  • REFERENCES.md
  • src/exact.rs
  • src/ldlt.rs
  • src/lib.rs
  • src/lu.rs
  • src/matrix.rs
  • typos.toml
✅ Files skipped from review due to trivial changes (4)
  • typos.toml
  • README.md
  • REFERENCES.md
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib.rs
  • src/lu.rs

Refactor manual const-evaluation tests in `Ldlt` and `Matrix` into macros
to standardize coverage across matrix dimensions 2 through 5. This
ensures all determinant and norm variants are fully exercised at compile
time.

Refs: #86
@acgetchell acgetchell self-assigned this Apr 20, 2026
@acgetchell acgetchell merged commit 119bceb into main Apr 20, 2026
9 checks passed
@acgetchell acgetchell deleted the feat/86-const-ify-methods branch April 20, 2026 22:31
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