feat(core): add shared scale-safe norm accumulation primitive - #482
Merged
Conversation
Extract the dlassq-style scaled sum-of-squares kernel into ariadnetor-core as NormAccumulator plus combine_norms, and migrate the workspace's independent overflow-safe accumulations onto it: the Frobenius-norm kernel in ariadnetor-tensor, the R^-1 row norms and their Pythagorean combine in the incremental QR, and the leave-one-out estimate and sketch-norm accumulation in the SRC apply path. The NaN contract is unified on NaN propagation: chained hypot lets an infinity dominate a NaN (hypot(inf, NaN) = inf), so the migrated sites now report NaN instead of inf when an accumulation sees both. Closes #478
Replace the public NormAccumulator + push/finish surface with scale_safe_norm(impl IntoIterator) and keep combine_norms; the accumulator struct stays private. The three consumer loops collapse into one-line iterator calls, removing the duplicated map-abs-push-finish fold and putting the magnitude-mapping convention in one place. Review-driven cleanups: test assertions unify on approx's assert_relative_eq (dev-dependency already in the workspace); the positivity debug_assert in the leave-one-out estimator moves out of the map closure so its coverage is independent of how the kernel consumes the iterator; call-site docstrings delegate the overflow rationale to the kernel doc instead of restating it.
There was a problem hiding this comment.
Pull request overview
This PR extracts a shared, scale-safe sum-of-squares accumulation kernel into ariadnetor-core and migrates existing norm-like accumulations across the workspace to use it, unifying overflow behavior and NaN propagation semantics.
Changes:
- Added
ariadnetor_core::scale_safe_normandariadnetor_core::combine_normsas the shared scale-safe accumulation primitives (with pinned NaN/∞ behavior via tests). - Refactored Frobenius/row-norm and SRC-related accumulations to route through the shared kernel (
ariadnetor-tensor,ariadnetor-linalg,ariadnetor-mps). - Standardized relative-error assertions onto
approx::assert_relative_eq!by addingapproxas a dev-dependency where needed.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| crates/ariadnetor-core/src/norm.rs | Introduces the shared scale-safe accumulation kernel + tests, including NaN/∞ contract. |
| crates/ariadnetor-core/src/lib.rs | Wires the new norm module and re-exports scale_safe_norm / combine_norms. |
| crates/ariadnetor-core/Cargo.toml | Adds approx for core’s kernel tests. |
| crates/ariadnetor-tensor/src/norm.rs | Replaces the local scaled kernel with a thin wrapper over scale_safe_norm (magnitude mapping). |
| crates/ariadnetor-tensor/Cargo.toml | Adds approx for updated test assertions. |
| crates/ariadnetor-linalg/src/incremental_qr.rs | Migrates row-norm accumulation and norm-combination to scale_safe_norm / combine_norms. |
| crates/ariadnetor-mps/src/apply/successive_randomized.rs | Migrates SRC reciprocal and sketch-norm accumulations to the shared kernel; moves positivity debug_assert ahead of iteration. |
| Cargo.lock | Records the new dev-dependency edges for approx. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The workspace carried four independent overflow-safe sum-of-squares accumulations: the dlassq-style scaled kernel behind
ariadnetor-tensor's Frobenius norm, chainedhypotin the incremental QR'sR^-1row norms, and two more chained-hypotaccumulations in the SRC apply path (the leave-one-out estimator and the sketch-norm accumulation). This PR extracts one scale-safe kernel intoariadnetor-coreand migrates all four sites onto it, unifying the NaN contract on NaN propagation. Closes #478.Changes
crates/ariadnetor-core/src/norm.rs(new): the dlassq-style scaled accumulator, kept private behind two public functions —scale_safe_norm(impl IntoIterator<Item = R>)andcombine_norms(a, b)for combining two finished norms.crates/ariadnetor-tensor/src/norm.rs:frobenius_normbecomes a thin wrapper mapping elements to their magnitudes; kernel-level tests move to core, the complex-modulus mapping test stays.crates/ariadnetor-linalg/src/incremental_qr.rs:row_normand the Pythagorean combine of grown row norms route through the kernel.crates/ariadnetor-mps/src/apply/successive_randomized.rs:leave_one_out_estimateand the sketch-norm accumulation route through the kernel; the positivitydebug_assertmoves ahead of the norm call so its coverage does not depend on how the kernel consumes the iterator.approx::assert_relative_eq!(approxwas already a workspace dependency; added to core and tensor dev-dependencies).Impact
frobenius_normconsumers (dense / block-sparse storage): unchanged signatures; the kernel is the same algorithm relocated, so results are identical.r_inverse_row_normsconsumers see rounding-level perturbation only; every observing test compares with relative tolerances.hypot-chain sites returnedinfwhen NaN and inf both entered an accumulation (IEEEhypot(inf, NaN) = inf); they now propagate NaN, matchingfrobenius_norm, and the core tests pin both orderings. On such (already poisoned) inputs the adaptive loop now grows to its bond cap instead of breaking early — bounded either way; Surface non-finite sketch state in SRC apply as an error #481 tracks surfacing the poisoned state as an error instead.Test plan
combine_norms.inverse_row_norms_survive_extreme_scales(incremental QR) andsrc_adaptive_is_scale_invariant(SRC) — the two tests that would catch an unscaled replacement kernel — pass.cargo make gate(fmt-check, clippy with denied warnings on all targets, workspace tests) passes.Notes
trunc_svd, its block-sparse twin, and themps/truncate.rssweep sums) still accumulates squared singular values / errors naively; Migrate truncation-error accumulations onto the scale-safe kernel #480 tracks migrating it — the squares are embedded in the rank-selection logic, so it is not a call swap.NonFiniteerror variant the Lanczos driver inariadnetor-algorithmsalready uses.@coderabbitai ignore