Skip to content

feat!(api): make Matrix and Vector finite by construction#147

Merged
acgetchell merged 1 commit into
mainfrom
feat/137-finite-api
Jun 7, 2026
Merged

feat!(api): make Matrix and Vector finite by construction#147
acgetchell merged 1 commit into
mainfrom
feat/137-finite-api

Conversation

@acgetchell

@acgetchell acgetchell commented Jun 7, 2026

Copy link
Copy Markdown
Owner
  • Parse raw matrix and vector storage through Matrix::try_from_rows and Vector::try_new, with private storage carrying the finite-entry invariant through downstream kernels.
  • Rename LU and LDLT solves to solve, and remove compatibility aliases that weaken the finite-proof API model.
  • Add Semgrep guardrails for the finite API contract and public-documentation unwrap/expect usage.
  • Update benchmarks, examples, docs, and tooling pins for the new API and current Markdown/spelling lint behavior.

BREAKING CHANGE: Matrix::from_rows is no longer a public raw constructor; use Matrix::try_from_rows for raw row-major input.

BREAKING CHANGE: Vector::new is no longer a public raw constructor; use Vector::try_new for raw vector input.

BREAKING CHANGE: Lu::solve_vec and Ldlt::solve_vec are removed; use solve.

BREAKING CHANGE: DEFAULT_PIVOT_TOL is removed; use DEFAULT_SINGULAR_TOL.

Closes #137

Summary by CodeRabbit

  • Breaking Changes

    • Renamed LU and LDLT solver method from solve_vec to solve
    • Removed deprecated DEFAULT_PIVOT_TOL constant; use DEFAULT_SINGULAR_TOL instead
  • Documentation

    • Updated all examples and API references to use the new solve method name
  • Chores

    • Updated development tooling versions (rumdl 0.2.6→0.2.9, typos 1.47.1→1.47.2)

- Parse raw matrix and vector storage through Matrix::try_from_rows and
  Vector::try_new, with private storage carrying the finite-entry invariant
  through downstream kernels.
- Rename LU and LDLT solves to solve, and remove compatibility aliases that
  weaken the finite-proof API model.
- Add Semgrep guardrails for the finite API contract and public-documentation
  unwrap/expect usage.
- Update benchmarks, examples, docs, and tooling pins for the new API and
  current Markdown/spelling lint behavior.

BREAKING CHANGE: Matrix::from_rows is no longer a public raw constructor; use
Matrix::try_from_rows for raw row-major input.

BREAKING CHANGE: Vector::new is no longer a public raw constructor; use
Vector::try_new for raw vector input.

BREAKING CHANGE: Lu::solve_vec and Ldlt::solve_vec are removed; use solve.

BREAKING CHANGE: DEFAULT_PIVOT_TOL is removed; use DEFAULT_SINGULAR_TOL.

Closes #137
@acgetchell acgetchell enabled auto-merge June 7, 2026 06:20
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR consolidates the finite-by-construction invariant introduced in v0.4.2 by removing the public solve_vec API, eliminating DEFAULT_PIVOT_TOL, making FiniteMatrix/FiniteVector public with simplified APIs, and refactoring public compute methods to assume finite inputs via unchecked construction. All examples, tests, benchmarks, and documentation are updated accordingly. New Semgrep rules enforce the API contract boundaries.

Changes

Finite-by-Construction Invariant and Solve API Consolidation

Layer / File(s) Summary
Matrix visibility and field privatization
src/matrix.rs, tests/semgrep/..., tests/matrix/*
Matrix.rows is now private; FiniteMatrix becomes fully public with reduced API surface (removed validation constructors, trait impls, convenience methods). All public Matrix compute methods (lu, ldlt, det, inf_norm, is_symmetric, first_asymmetry) use FiniteMatrix::new_unchecked to assume finite inputs.
Vector visibility and field privatization
src/vector.rs, tests/vector/*
Vector.data becomes private; FiniteVector is fully public but removes validation constructors (new, from_array, zero), trait impls (Default, From/TryFrom). Vector::dot and Vector::norm2_sq now use unchecked finite paths with cold-path hints on overflow.
Exact arithmetic boundary refactoring
src/exact.rs, tests/exact/*
Matrix::det_exact, det_exact_f64, solve_exact, solve_exact_f64, and det_sign_exact wrap inputs with FiniteMatrix::new_unchecked and FiniteVector::new_unchecked instead of validating. Macro-generated revalidation test coverage is removed.
LU solve API consolidation
src/lu.rs, tests/lu/*
Remove public solve_vec method; solve becomes the main entry point, assuming RHS is already finite via FiniteVector::new_unchecked. Rename internal solve_finite_vec to solve_finite. Refactor factor_finite loop to use cached row view. Update solver documentation and examples.
LDLT solve API consolidation
src/ldlt.rs, tests/ldlt/*
Remove public solve_vec method; solve assumes finite RHS and routes through FiniteVector::new_unchecked to solve_finite. Refactor factor_symmetric to use unchecked row views. Update solver documentation and examples.
Tolerance API cleanup
src/lib.rs, src/*.rs, benches/*, examples/*, tests/*
Remove public DEFAULT_PIVOT_TOL constant. Migrate all usages across the codebase to DEFAULT_SINGULAR_TOL.
Prelude and core library tests
src/lib.rs
Update prelude documentation, re-exports, and compile-and-work test to use Vector::try_new, solve() with ?, and DEFAULT_SINGULAR_TOL. Refactor exact feature prelude test to avoid unwrap-heavy BigRational construction.
Property tests and unit tests
tests/proptest_*.rs, tests/matrix.rs, tests/lu.rs, tests/ldlt.rs
Update tolerance constants, rename test macros/functions to solve variants, call solve() instead of solve_vec(), convert results to arrays. Update const-eval tests to construct factors via from_rows_unchecked.
Examples and benchmarks
examples/*.rs, benches/vs_linalg.rs
Update all example files to use solve() instead of solve_vec(), DEFAULT_SINGULAR_TOL instead of DEFAULT_PIVOT_TOL.
Semgrep enforcement rules
semgrep.yaml, tests/semgrep/src/project_rules/*
Add rules to block public unchecked constructors, public storage fields, public re-exports of finite wrappers, public raw LA modules, solve_vec identifier, and unwrap/expect in README doctest mirrors. Include fixture test files demonstrating patterns.
Documentation and guidance
AGENTS.md, README.md, docs/roadmap.md, CHANGELOG.md
Update to reflect finite-by-construction invariant, new solver API, tolerance naming, and tooling changes.
Tooling and changelog processing
.github/workflows/ci.yml, justfile, scripts/postprocess_changelog.py, scripts/tests/test_postprocess_changelog.py
Bump rumdl (0.2.6 → 0.2.9) and typos (1.47.1 → 1.47.2). Enhance changelog postprocessing with list continuation normalization, email autolink handling, and peer-item blank-line logic.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • acgetchell/la-stack#137: Investigate checked vector kernel performance for v0.4.3 — this PR's refactoring of Vector::dot, Vector::norm2_sq, and the removal of duplicate stored-entry revalidation directly supports the optimization investigation via the new unchecked finite-vector paths.

Possibly related PRs

  • acgetchell/la-stack#135: Overlapping LU/LDLT public compute-entry boundary logic and finiteness validation strategy.
  • acgetchell/la-stack#136: Overlapping changes to src/lu.rs/src/ldlt.rs internal factor-row access and factorization/solve finiteness paths.
  • acgetchell/la-stack#131: Directly related; refactors LU/LDLT public solving API around the finite-proof flow and eliminates solve_vec.

Suggested labels

api, breaking change, rust, testing, documentation, performance

Poem

🐰 Vectors once revalidated twice,
Now trust the proof at the slice,
Solve unified, no more vec,
Finite by construction—check!
Tolerance named clear and precise.

🚥 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 PR title 'feat!(api): make Matrix and Vector finite by construction' clearly and concisely describes the primary API change: refactoring Matrix and Vector to validate storage at construction, creating an invariant where internal storage is guaranteed finite. This aligns directly with the main objective of the PR.
Linked Issues check ✅ Passed The PR fully addresses issue #137 objectives: it measures and optimizes vector-kernel performance with unchecked finite paths, adds cold-path hints to error exits, preserves private proof-bearing wrappers, validates public APIs reject NaN/∞, and improves LU/LDLT solve semantics through the solve API while maintaining correctness invariants.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the PR objectives: API refactoring (removing solve_vec, pivoting to solve, removing DEFAULT_PIVOT_TOL), documentation updates reflecting new invariants, test/example migrations to the new API, and Semgrep rule additions enforcing the new contract. No unrelated cleanup or scope creep detected.
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 feat/137-finite-api

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

@codecov

codecov Bot commented Jun 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.58%. Comparing base (eeeb1e7) to head (1fa2f55).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #147      +/-   ##
==========================================
- Coverage   99.61%   99.58%   -0.03%     
==========================================
  Files           5        5              
  Lines        2846     2664     -182     
==========================================
- Hits         2835     2653     -182     
  Misses         11       11              
Flag Coverage Δ
unittests 99.58% <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 coderabbitai Bot left a comment

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.

Actionable comments posted: 1

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)

12-573: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not edit CHANGELOG.md directly; regenerate it via the release tooling.

This file has direct manual edits, which breaks the repo’s changelog generation contract and risks drift from commit-derived release notes. Please move these edits into commits/messages as needed and regenerate with just changelog (or just changelog-unreleased <version> for prepend flow).
As per coding guidelines: “CHANGELOG.md: 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 12 - 573, The PR modified CHANGELOG.md directly,
which violates the repo contract; revert any manual edits to CHANGELOG.md, move
the intended release notes into proper commit messages or commits, then
regenerate the changelog using the release tooling (run just changelog for
standard regeneration or just changelog-unreleased <version> to prepend an
unreleased entry). Ensure the final change is produced by the tooling rather
than hand-editing CHANGELOG.md so the file remains commit-derived and consistent
with the release pipeline.

Source: Coding guidelines

🤖 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 `@tests/semgrep/src/project_rules/readme_doctest_mirrors.rs`:
- Around line 5-35: The file declares the module name readme_doctests three
times causing E0428; rename each module to a unique identifier (e.g.,
readme_doctests_unwrap, readme_doctests_expect, readme_doctests_result) so that
the three modules (the ones containing the tests readme_mirror_uses_unwrap,
readme_mirror_uses_expect, and
readme_mirror_uses_result/ordinary_internal_tests_may_use_unwrap) no longer
collide; ensure any internal references to the old module name are updated
accordingly.

---

Outside diff comments:
In `@CHANGELOG.md`:
- Around line 12-573: The PR modified CHANGELOG.md directly, which violates the
repo contract; revert any manual edits to CHANGELOG.md, move the intended
release notes into proper commit messages or commits, then regenerate the
changelog using the release tooling (run just changelog for standard
regeneration or just changelog-unreleased <version> to prepend an unreleased
entry). Ensure the final change is produced by the tooling rather than
hand-editing CHANGELOG.md so the file remains commit-derived and consistent with
the release pipeline.
🪄 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: f565d7e5-06fe-4522-827e-ddd9ebdd272b

📥 Commits

Reviewing files that changed from the base of the PR and between eeeb1e7 and 1fa2f55.

📒 Files selected for processing (25)
  • .github/workflows/ci.yml
  • AGENTS.md
  • CHANGELOG.md
  • README.md
  • benches/vs_linalg.rs
  • docs/roadmap.md
  • examples/det_5x5.rs
  • examples/exact_solve_3x3.rs
  • examples/ldlt_solve_3x3.rs
  • examples/solve_5x5.rs
  • justfile
  • scripts/postprocess_changelog.py
  • scripts/tests/test_postprocess_changelog.py
  • semgrep.yaml
  • src/exact.rs
  • src/ldlt.rs
  • src/lib.rs
  • src/lu.rs
  • src/matrix.rs
  • src/vector.rs
  • tests/proptest_factorizations.rs
  • tests/proptest_matrix.rs
  • tests/semgrep/src/project_rules/finite_api_contract.rs
  • tests/semgrep/src/project_rules/readme_doctest_mirrors.rs
  • tests/vs_linalg_inputs.rs

Comment on lines +5 to +35
mod readme_doctests {
#[test]
fn readme_mirror_uses_unwrap() {
let _ = Some(1_u32).unwrap();
}
}

// ruleid: la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors
mod readme_doctests {
#[test]
fn readme_mirror_uses_expect() {
let _ = Ok::<u32, &'static str>(1).expect("README mirrors should use ?");
}
}

// ok: la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors
mod tests {
#[test]
fn ordinary_internal_tests_may_use_unwrap() {
let _ = Some(1_u32).unwrap();
}
}

// ok: la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors
mod readme_doctests {
#[test]
fn readme_mirror_uses_result() -> Result<(), &'static str> {
let _ = Ok::<u32, &'static str>(1)?;
Ok(())
}
}

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 | 🔴 Critical | ⚡ Quick win

Fix duplicate module names.

Rust does not permit multiple modules with the same name in the same scope. This file defines mod readme_doctests three times (lines 5, 13, 29), which will cause compilation error E0428.

🔧 Proposed fix

Rename the modules to have unique names:

-// ruleid: la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors
-mod readme_doctests {
+// ruleid: la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors  
+mod readme_doctests_unwrap {
     #[test]
     fn readme_mirror_uses_unwrap() {
         let _ = Some(1_u32).unwrap();
     }
 }
 
 // ruleid: la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors
-mod readme_doctests {
+mod readme_doctests_expect {
     #[test]
     fn readme_mirror_uses_expect() {
         let _ = Ok::<u32, &'static str>(1).expect("README mirrors should use ?");
     }
 }
 
 // ok: la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors
 mod tests {
     #[test]
     fn ordinary_internal_tests_may_use_unwrap() {
         let _ = Some(1_u32).unwrap();
     }
 }
 
 // ok: la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors
-mod readme_doctests {
+mod readme_doctests_result {
     #[test]
     fn readme_mirror_uses_result() -> Result<(), &'static str> {
         let _ = Ok::<u32, &'static str>(1)?;
         Ok(())
     }
 }
🧰 Tools
🪛 OpenGrep (1.22.0)

[WARNING] 5-8: Use fallible flow instead of unwrap() or expect() in src/lib.rs README doctest mirrors.

(la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors)


[WARNING] 13-16: Use fallible flow instead of unwrap() or expect() in src/lib.rs README doctest mirrors.

(la-stack.rust.no-unwrap-expect-in-readme-doctest-mirrors)

🤖 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 `@tests/semgrep/src/project_rules/readme_doctest_mirrors.rs` around lines 5 -
35, The file declares the module name readme_doctests three times causing E0428;
rename each module to a unique identifier (e.g., readme_doctests_unwrap,
readme_doctests_expect, readme_doctests_result) so that the three modules (the
ones containing the tests readme_mirror_uses_unwrap, readme_mirror_uses_expect,
and readme_mirror_uses_result/ordinary_internal_tests_may_use_unwrap) no longer
collide; ensure any internal references to the old module name are updated
accordingly.

@acgetchell acgetchell merged commit 9008c48 into main Jun 7, 2026
18 checks passed
@acgetchell acgetchell deleted the feat/137-finite-api branch June 7, 2026 06:37
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.

Investigate checked vector kernel performance for v0.4.3

1 participant