Skip to content

refactor(invariants): simplify finite proof wrappers#134

Merged
acgetchell merged 1 commit into
mainfrom
refactor/finite-proof-simplification
Jun 3, 2026
Merged

refactor(invariants): simplify finite proof wrappers#134
acgetchell merged 1 commit into
mainfrom
refactor/finite-proof-simplification

Conversation

@acgetchell
Copy link
Copy Markdown
Owner

@acgetchell acgetchell commented Jun 3, 2026

  • Use the checked proof-wrapper constructors as the single internal path for finite matrices and vectors.
  • Remove exact-arithmetic tests that duplicated the matrix and vector non-finite boundary checks.

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened validation of matrix solve operations to detect non-finite solutions earlier.
    • Improved error handling for overflow and invalid symmetry tolerance scaling.
    • Enhanced finiteness validation in LU and LDLT decomposition solvers.
  • Refactor

    • Simplified finite-value wrapper construction and centralized invariant checks at initialization.

- Use the checked proof-wrapper constructors as the single internal path for finite matrices and vectors.
- Remove exact-arithmetic tests that duplicated the matrix and vector non-finite boundary checks.
@acgetchell acgetchell self-assigned this Jun 3, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR enforces validated construction of finite-proof wrappers by removing internal unchecked constructors and routing all FiniteVector and FiniteMatrix instances through checked new(...) paths. LU and LDLT solve operations now return validated finite vectors, and obsolete error-path tests are removed.

Changes

Finite-proof validation enforcement

Layer / File(s) Summary
FiniteVector construction refactoring
src/vector.rs
Removes crate-internal new_unchecked constructor; FiniteVector::new now directly wraps vectors, and from_array and zero use the validated path.
FiniteMatrix construction alignment
src/matrix.rs
FiniteMatrix::new, from_rows, and zero now route through the checked new(...) constructor instead of unchecked wrappers.
Solve paths use validated construction
src/lu.rs, src/ldlt.rs, src/exact.rs
LU and LDLT solve_finite_vec methods now return FiniteVector via the checked constructor; minor formatting adjustment in exact solve.
Test coverage adjustments
src/exact.rs
Removes error-path tests for NaN/∞ inputs to determinant and solve functions; those invariant checks now occur at FiniteVector construction.
Changelog documentation
CHANGELOG.md
Documents finite-proof enforcement, determinant tolerance-free API, exact decomposition changes, solve validation with LaError::NonFinite metadata, and tolerance overflow handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • acgetchell/la-stack#133: Main PR enforces checked construction paths for FiniteMatrix/FiniteVector wrappers, directly aligning with PR #133's goal of enforcing finite invariants at construction boundaries.
  • acgetchell/la-stack#131: Main PR's removal of new_unchecked and routing through validated paths directly refines the finite-proof wrapper API surface introduced in PR #131.
  • acgetchell/la-stack#130: Both PRs touch exact-arithmetic decomposition work in src/exact.rs, including determinant documentation, SPD proptest adjustments, and test coverage changes.

Suggested labels

rust, testing, enhancement

Poem

🐰 With unchecked paths removed, the wrappers now stand tall,
Every finite vector and matrix validated through the checked call,
Invariants guarded at construction's door,
Tests that drift away—they're needed no more,
A stronger foundation, more proof than before! 🎯

🚥 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 and concisely describes the main objective of the PR: simplifying the proof wrappers for finite matrices/vectors by consolidating construction paths through checked constructors.
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 refactor/finite-proof-simplification

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

@acgetchell acgetchell enabled auto-merge June 3, 2026 21:50
@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.29%. Comparing base (ed7dc46) to head (54b603c).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #134      +/-   ##
==========================================
- Coverage   99.31%   99.29%   -0.02%     
==========================================
  Files           5        5              
  Lines        2757     2707      -50     
==========================================
- Hits         2738     2688      -50     
  Misses         19       19              
Flag Coverage Δ
unittests 99.29% <100.00%> (-0.02%) ⬇️

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.

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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CHANGELOG.md (1)

14-97: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not edit CHANGELOG.md manually; regenerate it via project tooling.

This block appears to be directly edited in CHANGELOG.md, which violates the repo rule for changelog generation. Please revert manual edits and regenerate with just changelog (or just changelog-unreleased <version> for unreleased prepends).

As per coding guidelines: "Never edit CHANGELOG.md directly - it's auto-generated from git commits. Use just changelog to regenerate or just changelog-unreleased <version> to prepend unreleased changes."

🤖 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 `@CHANGELOG.md` around lines 14 - 97, The PR contains a manual edit to
CHANGELOG.md (don't edit changelogs by hand); revert the manual changes to
CHANGELOG.md (undo the commit or remove the file modification from the branch)
and regenerate the changelog using the project tooling: run just changelog to
rebuild from commits or just changelog-unreleased <version> if you need to
prepend an unreleased entry, then commit the generated file instead of the
manual edits.
🤖 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 `@src/matrix.rs`:
- Around line 32-33: FiniteMatrix::new currently accepts a raw Matrix and thus
silently allows unchecked (possibly non-finite) storage; change the API so new
is a checked constructor (validate finiteness) and restore an explicit private
unchecked constructor for internal use. Specifically: make
FiniteMatrix::new(Matrix<D>) perform the finiteness check and return a
Result<FiniteMatrix, LaError> that emits LaError::NonFinite { row, col } (with
source-location metadata) on NaN/±∞, and add a clearly named private fn
new_unchecked(matrix: Matrix<D>) -> Self for internal callers that already prove
finiteness; update call sites that relied on the old unchecked behavior to call
new_unchecked only when a local proof exists and call new(...) everywhere else.

In `@src/vector.rs`:
- Around line 28-29: FiniteVector::new currently just wraps Vector<D> and
removes the finiteness check, allowing Vector::new_unchecked(...) to silently
pass non-finite values; restore a checked public constructor that validates all
entries and returns LaError::NonFinite with source-location metadata on failure,
and keep a clearly named private bypass (e.g., FiniteVector::new_unchecked) for
internal use where you have a local proof. Update call sites in LU/LDLT/exact
solve paths to use the public checked constructor (or explicitly call the
private unchecked where justified) and ensure any creation that can fail
surfaces LaError::NonFinite { row, col } rather than panicking or producing NaN.

---

Outside diff comments:
In `@CHANGELOG.md`:
- Around line 14-97: The PR contains a manual edit to CHANGELOG.md (don't edit
changelogs by hand); revert the manual changes to CHANGELOG.md (undo the commit
or remove the file modification from the branch) and regenerate the changelog
using the project tooling: run just changelog to rebuild from commits or just
changelog-unreleased <version> if you need to prepend an unreleased entry, then
commit the generated file instead of the manual edits.
🪄 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: 4913b7f8-21b0-4176-a587-4510d1faa97f

📥 Commits

Reviewing files that changed from the base of the PR and between ed7dc46 and 54b603c.

📒 Files selected for processing (6)
  • CHANGELOG.md
  • src/exact.rs
  • src/ldlt.rs
  • src/lu.rs
  • src/matrix.rs
  • src/vector.rs

Comment thread src/matrix.rs
Comment on lines 32 to +33
pub const fn new(matrix: Matrix<D>) -> Self {
Self::new_unchecked(matrix)
Self { matrix }
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 | 🟠 Major | 🏗️ Heavy lift

FiniteMatrix::new no longer distinguishes checked from unchecked construction.

Matrix::from_rows_unchecked(...) still exists, but FiniteMatrix::new(...) now just wraps the raw matrix. So the proof wrapper can still be built from unchecked storage, and the public algorithm helpers below (inf_norm, lu, ldlt, det*) are not actually entering through a validated boundary.

Suggested direction
- pub const fn new(matrix: Matrix<D>) -> Self {
-     Self { matrix }
+ pub const fn new(matrix: Matrix<D>) -> Result<Self, LaError> {
+     if let Some((row, col)) = Matrix::<D>::first_non_finite_cell_in(&matrix.rows) {
+         return Err(LaError::non_finite_cell(row, col));
+     }
+     Ok(Self { matrix })
  }

If some internal paths genuinely have a local finiteness proof, keep an explicitly named private unchecked constructor for those sites rather than making new(...) silently unchecked.

As per coding guidelines, "Non-finite values (NaN, ±∞) always surface as LaError::NonFinite { row, col } with source-location metadata. No silent NaN propagation, no unwrap_or(f64::NAN)."

🤖 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 32 - 33, FiniteMatrix::new currently accepts a
raw Matrix and thus silently allows unchecked (possibly non-finite) storage;
change the API so new is a checked constructor (validate finiteness) and restore
an explicit private unchecked constructor for internal use. Specifically: make
FiniteMatrix::new(Matrix<D>) perform the finiteness check and return a
Result<FiniteMatrix, LaError> that emits LaError::NonFinite { row, col } (with
source-location metadata) on NaN/±∞, and add a clearly named private fn
new_unchecked(matrix: Matrix<D>) -> Self for internal callers that already prove
finiteness; update call sites that relied on the old unchecked behavior to call
new_unchecked only when a local proof exists and call new(...) everywhere else.

Comment thread src/vector.rs
Comment on lines 28 to +29
pub const fn new(vector: Vector<D>) -> Self {
Self::new_unchecked(vector)
Self { vector }
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 | 🟠 Major | 🏗️ Heavy lift

FiniteVector::new is still an unchecked proof constructor.

This now just rewraps Vector<D>, so every call site switched from new_unchecked(...) to new(...) still accepts Vector::new_unchecked(...) without surfacing LaError::NonFinite. That means the validated-construction invariant is not actually enforced in the updated LU/LDLT/exact solve paths.

Suggested direction
- pub const fn new(vector: Vector<D>) -> Self {
-     Self { vector }
+ pub const fn new(vector: Vector<D>) -> Result<Self, LaError> {
+     let mut i = 0;
+     while i < D {
+         if !vector.data[i].is_finite() {
+             return Err(LaError::non_finite_at(i));
+         }
+         i += 1;
+     }
+     Ok(Self { vector })
  }

If you still need a bypass for locally-proven outputs, keep a clearly named private new_unchecked(...) alongside the checked constructor instead of collapsing them into one infallible new(...).

As per coding guidelines, "Non-finite values (NaN, ±∞) always surface as LaError::NonFinite { row, col } with source-location metadata. No silent NaN propagation, no unwrap_or(f64::NAN)."

🤖 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/vector.rs` around lines 28 - 29, FiniteVector::new currently just wraps
Vector<D> and removes the finiteness check, allowing Vector::new_unchecked(...)
to silently pass non-finite values; restore a checked public constructor that
validates all entries and returns LaError::NonFinite with source-location
metadata on failure, and keep a clearly named private bypass (e.g.,
FiniteVector::new_unchecked) for internal use where you have a local proof.
Update call sites in LU/LDLT/exact solve paths to use the public checked
constructor (or explicitly call the private unchecked where justified) and
ensure any creation that can fail surfaces LaError::NonFinite { row, col }
rather than panicking or producing NaN.

@acgetchell acgetchell merged commit c6cde72 into main Jun 3, 2026
18 checks passed
@acgetchell acgetchell deleted the refactor/finite-proof-simplification branch June 3, 2026 21:56
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