Skip to content

feat(core): add shared scale-safe norm accumulation primitive - #482

Merged
ultimatile merged 2 commits into
mainfrom
refactor/478-scale-safe-accumulation
Jul 17, 2026
Merged

feat(core): add shared scale-safe norm accumulation primitive#482
ultimatile merged 2 commits into
mainfrom
refactor/478-scale-safe-accumulation

Conversation

@ultimatile

Copy link
Copy Markdown
Owner

Summary

The workspace carried four independent overflow-safe sum-of-squares accumulations: the dlassq-style scaled kernel behind ariadnetor-tensor's Frobenius norm, chained hypot in the incremental QR's R^-1 row norms, and two more chained-hypot accumulations in the SRC apply path (the leave-one-out estimator and the sketch-norm accumulation). This PR extracts one scale-safe kernel into ariadnetor-core and 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>) and combine_norms(a, b) for combining two finished norms.
  • crates/ariadnetor-tensor/src/norm.rs: frobenius_norm becomes 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_norm and the Pythagorean combine of grown row norms route through the kernel.
  • crates/ariadnetor-mps/src/apply/successive_randomized.rs: leave_one_out_estimate and the sketch-norm accumulation route through the kernel; the positivity debug_assert moves ahead of the norm call so its coverage does not depend on how the kernel consumes the iterator.
  • Test assertions on relative error unify on approx::assert_relative_eq! (approx was already a workspace dependency; added to core and tensor dev-dependencies).

Impact

  • frobenius_norm consumers (dense / block-sparse storage): unchanged signatures; the kernel is the same algorithm relocated, so results are identical.
  • The SRC adaptive loop and r_inverse_row_norms consumers see rounding-level perturbation only; every observing test compares with relative tolerances.
  • Intentional behavior change on non-finite data: the hypot-chain sites returned inf when NaN and inf both entered an accumulation (IEEE hypot(inf, NaN) = inf); they now propagate NaN, matching frobenius_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

  • Kernel tests in core: 3-4-5 exactness, empty/zero input, f32/f64 extreme magnitudes, reciprocal extremes, NaN alongside infinity in both orders, infinities, and combine_norms.
  • Migration safety net: inverse_row_norms_survive_extreme_scales (incremental QR) and src_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

@coderabbitai ignore

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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_norm and ariadnetor_core::combine_norms as 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 adding approx as 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.

@ultimatile
ultimatile merged commit 04d73ea into main Jul 17, 2026
2 checks passed
@ultimatile
ultimatile deleted the refactor/478-scale-safe-accumulation branch July 17, 2026 05:27
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.

Extract a shared scale-safe accumulation primitive

2 participants