Skip to content

fix(invariants): revalidate public compute inputs#135

Merged
acgetchell merged 1 commit into
mainfrom
fix/finite-proof-revalidation
Jun 3, 2026
Merged

fix(invariants): revalidate public compute inputs#135
acgetchell merged 1 commit into
mainfrom
fix/finite-proof-revalidation

Conversation

@acgetchell
Copy link
Copy Markdown
Owner

@acgetchell acgetchell commented Jun 3, 2026

  • Parse Matrix and Vector storage into private finite proof-bearing types at public compute boundaries.
  • Reject unchecked non-finite storage before LU, LDLT, determinant, norm, dot, and exact-arithmetic paths can proceed.
  • Keep unchecked proof-wrapper constructors crate-private for internal paths with local finiteness proofs.
  • Document the private proof-bearing invariant model in the API overview and roadmap.

Summary by CodeRabbit

Release Notes

  • Documentation

    • Updated README, CHANGELOG, and roadmap to clarify API validation requirements and behavior
  • Bug Fixes

    • Enhanced validation at API boundaries to detect and report non-finite values (NaN/infinity) in matrices and vectors with specific error coordinates

- Parse Matrix and Vector storage into private finite proof-bearing types at public compute boundaries.
- Reject unchecked non-finite storage before LU, LDLT, determinant, norm, dot, and exact-arithmetic paths can proceed.
- Keep unchecked proof-wrapper constructors crate-private for internal paths with local finiteness proofs.
- Document the private proof-bearing invariant model in the API overview and roadmap.
@acgetchell acgetchell self-assigned this Jun 3, 2026
@acgetchell acgetchell enabled auto-merge June 3, 2026 23:18
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.33%. Comparing base (c6cde72) to head (ffca00e).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #135      +/-   ##
==========================================
+ Coverage   99.29%   99.33%   +0.03%     
==========================================
  Files           5        5              
  Lines        2707     2844     +137     
==========================================
+ Hits         2688     2825     +137     
  Misses         19       19              
Flag Coverage Δ
unittests 99.33% <100.00%> (+0.03%) ⬆️

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

☔ View full report in Codecov by Harness.
📢 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.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors the internal finite-invariant boundary by introducing validated (checked) and unchecked constructor paths for FiniteMatrix and FiniteVector, then updating all public APIs to revalidate stored entries at entry points before internal operations. Unchecked storage from factory methods is now systematically rejected if operations are attempted without passing through validation.

Changes

Finite-Proof Boundary Refactor

Layer / File(s) Summary
FiniteMatrix and FiniteVector constructor split
src/matrix.rs, src/vector.rs
FiniteMatrix::new and FiniteVector::new now return Result<Self, LaError> and validate stored entries for NaN/infinity at construction. New unchecked constructors skip validation for proven-finite internal code paths. Related constructors (from_rows, zero, into_vector) delegate to the new unchecked wrapper. TryFrom implementations simplified to call the validating constructors.
Vector arithmetic revalidation
src/vector.rs
Vector::dot and Vector::norm2_sq now construct a FiniteVector from raw storage first, rejecting non-finite entries before arithmetic begins. Crate-internal FiniteVector::dot and norm2_sq operate on proven-finite storage and only check accumulation overflow.
Public Matrix compute methods revalidate
src/matrix.rs
All public compute methods (inf_norm, is_symmetric, first_asymmetry, lu, ldlt, det_direct, det, det_errbound) now call FiniteMatrix::new(*self)? at entry to revalidate before delegating to crate-internal implementations. Unchecked storage created via from_rows_unchecked is rejected at operation boundaries.
Crate-internal compute and solve helpers
src/matrix.rs, src/lu.rs, src/ldlt.rs
FiniteMatrix methods (inf_norm, is_symmetric, lu, ldlt, det, det_errbound) changed to pub(crate) visibility. Lu::solve_finite_vec and Ldlt::solve_finite_vec use FiniteVector::new_unchecked after algorithm-internal overflow checks prove finiteness. Similar helpers switched to new_unchecked for known-finite test inputs.
Exact-feature public methods validate
src/exact.rs
Public exact methods (det_exact, det_exact_f64, solve_exact, solve_exact_f64, det_sign_exact) now validate via FiniteMatrix::new(*self)? and FiniteVector::new(b)? before reaching the Bareiss core. Docs explicitly enumerate LaError::NonFinite as a possible error for stored entries containing NaN/infinity.
LU and LDLT solve_vec boundaries
src/lu.rs, src/ldlt.rs
Lu::solve_vec and Ldlt::solve_vec now revalidate RHS finiteness by matching on FiniteVector::new(b), returning LaError::NonFinite early on non-finite entries before substitution begins.
Test revalidation and unchecked input rejection
src/exact.rs, src/lu.rs, src/ldlt.rs, src/matrix.rs, src/vector.rs
New test macros verify all public compute methods reject unchecked inputs containing NaN/∞ with LaError::NonFinite at correct coordinates. Internal finite-only test paths switch to new_unchecked constructors. Boundary tests added for solve_vec and vector arithmetic to confirm early rejection.
Documentation and changelog
CHANGELOG.md, README.md, docs/roadmap.md, src/lib.rs
Updated to document the finite-proof boundary pattern: raw public Matrix/Vector remain unchecked storage types; crate-private FiniteMatrix/FiniteVector carry the finite-entry proof through all computations. Rustdoc clarified to state parsing into proof occurs before arithmetic begins.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

This PR involves coordinated changes across multiple computation layers (matrix, vector, factorization, exact arithmetic, and test infrastructure) with a consistent but non-trivial architectural pattern: splitting checked and unchecked constructor paths, then systematically revalidating at public boundaries. Understanding the pattern across one or two layers transfers well, but verifying consistent application throughout the codebase and ensuring no false-positive rejections is logic-dense work. The heterogeneous mix of constructors, boundary validations, and test macro coverage increases review complexity.

Possibly related PRs

  • acgetchell/la-stack#131: Implements the same finite-proof boundary refactor by introducing checked/unchecked constructor paths and revalidating at public entry points for matrix/vector operations, overlapping substantially in code changes and architectural intent.
  • acgetchell/la-stack#130: Modifies the exact-arithmetic pipeline in src/exact.rs to refactor internal decomposition Component mantissa representation and conversion, overlapping with this PR's exact-method boundary revalidation changes.
  • acgetchell/la-stack#133: Implements the same core finite-invariant API shift by changing constructor/mutation boundaries (Matrix::try_from_rows, Vector::try_new) and adjusting algorithms to rely on validated finite wrappers rather than unchecked raw storage.

Suggested labels

documentation, rust, testing, breaking change, api

Poem

🐰 Proof bounds held firm and clear,
Unchecked slips are caught right here,
Finite types now guard the door,
Stable paths forevermore! ✨

🚥 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 'fix(invariants): revalidate public compute inputs' directly and precisely summarizes the main change: adding revalidation of public compute inputs to ensure the finite-invariant model is enforced at API boundaries.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 fix/finite-proof-revalidation

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

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.

Actionable comments posted: 4

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

846-847: ⚡ Quick win

Exercise the unchecked internal wrapper path here.

This macro is supposed to cover the crate-internal finite path, but Lines 846-847 re-enter the validating constructors instead. Switching these fixtures to new_unchecked(...) would keep this test focused on the internal proof-bearing contract introduced by this PR.

♻️ Proposed fixture change
-                    let a = FiniteMatrix::<$d>::new(Matrix::<$d>::identity()).unwrap();
-                    let b = FiniteVector::<$d>::new(Vector::<$d>::new([1.0; $d])).unwrap();
+                    let a = FiniteMatrix::<$d>::new_unchecked(Matrix::<$d>::identity());
+                    let b = FiniteVector::<$d>::new_unchecked(
+                        Vector::<$d>::new_unchecked([1.0; $d]),
+                    );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/exact.rs` around lines 846 - 847, The test currently constructs
FiniteMatrix::<$d> and FiniteVector::<$d> via the validating constructors
FiniteMatrix::new(...) and FiniteVector::new(...); change those calls to the
internal unchecked constructors FiniteMatrix::new_unchecked(...) and
FiniteVector::new_unchecked(...) so the fixtures use the crate-internal
unchecked wrapper path (wrap Matrix::<$d>::identity() and
Vector::<$d>::new([1.0; $d]) with new_unchecked instead of new).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Around line 45-48: The CHANGELOG.md was edited manually (the "Simplify finite
proof wrappers" entry / commit 54b603c appears hand-modified); revert any manual
edits to CHANGELOG.md (restore from the branch/main or last-generated version)
and regenerate the changelog using the project tooling—run just changelog (or
just changelog-unreleased <version> if prepping a release) to recreate the file,
verify the generated entry for "Simplify finite proof wrappers" is present and
accurate, then commit the regenerated CHANGELOG.md.

In `@src/ldlt.rs`:
- Around line 190-194: The doc comment for solve_vec currently lists error cases
but omits any statement about rounding error bounds; update the doc for the
solve_vec method to explicitly state that it performs floating-point
substitution and does not provide a certified absolute/rounding error bound
(unless you intend to provide one), e.g. add a sentence like “This method
performs floating-point substitution and does not guarantee a certified absolute
rounding-error bound.” Keep the existing error notes (e.g. LaError::NonFinite)
and follow the same phrasing used in other modules (matrix/lu/ldlt) for
consistency.

In `@src/lu.rs`:
- Around line 142-146: Update the doc comment for the solve_vec method to
explicitly state that no certified rounding/absolute error bound is provided for
the floating-point forward/back substitution it performs; reference the function
name solve_vec and mention that callers should not expect an absolute error
bound (unlike det_errbound/ERR_COEFF_*), and keep existing clarification about
failure returning LaError::NonFinite and the revalidation via Vector::try_new.

In `@src/matrix.rs`:
- Around line 670-671: Update the inf_norm documentation to remove the outdated
claim that non-finite values are rejected before storage and instead state that
stored NaN/∞ may be encountered due to the crate's unchecked-storage model;
explicitly mention that inf_norm will return LaError::NonFinite when it
encounters stored NaN/∞ or when a row sum overflows to non-finite, and keep the
existing # Errors section consistent with this behavior (refer to inf_norm and
LaError::NonFinite in the text).

---

Nitpick comments:
In `@src/exact.rs`:
- Around line 846-847: The test currently constructs FiniteMatrix::<$d> and
FiniteVector::<$d> via the validating constructors FiniteMatrix::new(...) and
FiniteVector::new(...); change those calls to the internal unchecked
constructors FiniteMatrix::new_unchecked(...) and
FiniteVector::new_unchecked(...) so the fixtures use the crate-internal
unchecked wrapper path (wrap Matrix::<$d>::identity() and
Vector::<$d>::new([1.0; $d]) with new_unchecked instead of new).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 51045dbd-5a49-44df-8e06-83c5c9f64e47

📥 Commits

Reviewing files that changed from the base of the PR and between c6cde72 and ffca00e.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • README.md
  • docs/roadmap.md
  • src/exact.rs
  • src/ldlt.rs
  • src/lib.rs
  • src/lu.rs
  • src/matrix.rs
  • src/vector.rs

Comment thread CHANGELOG.md
Comment thread src/ldlt.rs
Comment on lines +190 to +194
/// Returns [`LaError::NonFinite`] if the right-hand side contains
/// NaN/infinity or a computed substitution intermediate overflows to NaN or
/// infinity. The right-hand side is revalidated at this boundary before
/// entering substitution; public callers normally encounter the same
/// rejection earlier through [`Vector::try_new`](crate::Vector::try_new).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document that solve_vec has no certified rounding bound.

This method performs floating-point substitution, but the docs still only describe error cases. Please add the usual note that no certified absolute error bound is provided unless you want to document one explicitly. As per coding guidelines, src/{matrix,lu,ldlt}.rs: "Any f64 operation that can accumulate rounding error either documents its absolute bound (det_errbound, ERR_COEFF_*) or explicitly states that no bound is provided."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ldlt.rs` around lines 190 - 194, The doc comment for solve_vec currently
lists error cases but omits any statement about rounding error bounds; update
the doc for the solve_vec method to explicitly state that it performs
floating-point substitution and does not provide a certified absolute/rounding
error bound (unless you intend to provide one), e.g. add a sentence like “This
method performs floating-point substitution and does not guarantee a certified
absolute rounding-error bound.” Keep the existing error notes (e.g.
LaError::NonFinite) and follow the same phrasing used in other modules
(matrix/lu/ldlt) for consistency.

Comment thread src/lu.rs
Comment on lines +142 to +146
/// Returns [`LaError::NonFinite`] if the right-hand side contains
/// NaN/infinity or a computed substitution intermediate overflows to NaN or
/// infinity. The right-hand side is revalidated at this boundary before
/// entering substitution; public callers normally encounter the same
/// rejection earlier through [`Vector::try_new`](crate::Vector::try_new).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document that solve_vec has no certified rounding bound.

This path does floating-point forward/back substitution, but the docs still only describe failure cases. The repo guideline requires these methods to either state an absolute bound or explicitly say none is provided. As per coding guidelines, src/{matrix,lu,ldlt}.rs: "Any f64 operation that can accumulate rounding error either documents its absolute bound (det_errbound, ERR_COEFF_*) or explicitly states that no bound is provided."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lu.rs` around lines 142 - 146, Update the doc comment for the solve_vec
method to explicitly state that no certified rounding/absolute error bound is
provided for the floating-point forward/back substitution it performs; reference
the function name solve_vec and mention that callers should not expect an
absolute error bound (unlike det_errbound/ERR_COEFF_*), and keep existing
clarification about failure returning LaError::NonFinite and the revalidation
via Vector::try_new.

Comment thread src/matrix.rs
Comment on lines +670 to +671
/// Returns [`LaError::NonFinite`] when stored entries are NaN/infinity or a
/// row sum overflows to NaN or infinity.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the inf_norm docs to match the unchecked-storage model.

The # Errors section now correctly says stored NaN/∞ can reach this method, but the earlier “Non-finite handling” paragraph still says those values are rejected before storage. Please reconcile those two statements so the public docs reflect the new crate-internal unchecked path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/matrix.rs` around lines 670 - 671, Update the inf_norm documentation to
remove the outdated claim that non-finite values are rejected before storage and
instead state that stored NaN/∞ may be encountered due to the crate's
unchecked-storage model; explicitly mention that inf_norm will return
LaError::NonFinite when it encounters stored NaN/∞ or when a row sum overflows
to non-finite, and keep the existing # Errors section consistent with this
behavior (refer to inf_norm and LaError::NonFinite in the text).

@acgetchell acgetchell merged commit db5bcd4 into main Jun 3, 2026
18 checks passed
@acgetchell acgetchell deleted the fix/finite-proof-revalidation branch June 3, 2026 23:34
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