Skip to content

fix(mps): guard variational tol cast against overflow to infinity - #487

Merged
ultimatile merged 2 commits into
mainfrom
fix/472-tol-cast-overflow
Jul 18, 2026
Merged

fix(mps): guard variational tol cast against overflow to infinity#487
ultimatile merged 2 commits into
mainfrom
fix/472-tol-cast-overflow

Conversation

@ultimatile

Copy link
Copy Markdown
Owner

Summary

The variational (fit) MPO-MPS apply path cast its f64 tolerance into the scalar's real type with a bare NumCast::from(tol).expect(...) and no post-cast finiteness check. For f32-family scalars, NumCast::from maps an out-of-range but finite f64 (e.g. 1e300) to Some(inf) rather than None, so the convergence comparison |current - prev| <= tol * current becomes trivially true and the fit reports convergence after one sweep with an arbitrarily bad result. Two hardened copies of the same cast already existed (successive-randomized apply and an algorithms-crate helper); this consolidates all three into one shared primitive and closes the gap on the variational path.

Closes #472

Changes

  • ariadnetor-core: new try_real_from_f64<T: Scalar>(f64) -> Option<T::Real> (NumCast::from then an is_finite() filter), exported at the crate root next to the existing scale-safe norm helpers.
  • ariadnetor-algorithms: delete the crate-local copy and repoint every consumer (DMRG heff / heff_block_sparse validation / sweep, Krylov lanczos and lanczos_kernels, including a #[cfg(test)] helper) onto the core primitive.
  • ariadnetor-mps successive-randomized apply: real_from_f64 now delegates to the core primitive, preserving its panic message.
  • ariadnetor-mps variational apply: both the Dense and BlockSparse tolerance casts gain the finiteness check via the core primitive; the now-unused NumCast import is dropped.

Impact

  • ariadnetor-core gains exactly one new public symbol, try_real_from_f64 (confirmed via cargo public-api).
  • Variational apply with a tolerance that is finite in f64 but overflows the scalar's real type now panics at the cast instead of silently casting to infinity and mis-converging. Callers passing a representable tolerance are unaffected; the change only converts a previously-silent numerical fault into a fail-fast.

Test plan

  • Moved the cast's unit tests into ariadnetor-core, covering f32, f64, and Complex against overflow, NaN, and infinity inputs.
  • Added a Dense f32 #[should_panic] regression test on the variational path, mirroring the successive-randomized one, driving a 2-site f32 MPS with a 1e300 tolerance.
  • cargo test across ariadnetor-core, ariadnetor-algorithms, and ariadnetor-mps passes; cargo make clippy (warnings denied, all targets) is clean.

Notes

The BlockSparse variational cast has no dedicated f32 regression test: both cast sites are the identical one-line construct and try_real_from_f64 monomorphizes independently of tensor storage, so the Dense test covers the shared finiteness-check-then-expect wiring, and the BlockSparse site's reachability is already exercised by the existing f64 BlockSparse variational tests.

@coderabbitai ignore

The variational apply path cast its f64 tolerance into the scalar's
real type with a bare NumCast::from(tol).expect(...) and no post-cast
finiteness check. For f32-family scalars NumCast::from maps an
out-of-range but finite f64 (e.g. 1e300) to Some(inf) rather than None,
so the convergence comparison becomes trivially true and the fit reports
convergence after one sweep with an arbitrarily bad result.

Consolidate the three copies of this cast into one shared helper,
try_real_from_f64, at the core layer where Scalar lives, migrate the
successive-randomized apply and the algorithms tolerance casts onto it,
and add the finiteness check to the variational path. A new f32
should_panic regression test mirrors the successive-randomized one.

Closes #472

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 hardens tolerance handling across MPO–MPS algorithms by centralizing the f64 -> T::Real cast behind a shared ariadnetor-core helper that rejects non-finite results (notably f64 values that overflow to ±inf when cast to f32). This prevents spurious “converged” reports in variational apply paths for f32-family scalars and removes duplicated cast logic across crates.

Changes:

  • Add ariadnetor_core::try_real_from_f64::<T: Scalar>(f64) -> Option<T::Real> and re-export it from the core crate root.
  • Migrate ariadnetor-algorithms (DMRG + Krylov/Lanczos) and ariadnetor-mps (successive-randomized + variational apply) to use the shared helper.
  • Add a variational Dense f32 regression test ensuring unrepresentable tolerances panic instead of silently becoming inf.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
crates/ariadnetor-core/src/numeric.rs Introduces the shared, finiteness-checked try_real_from_f64 conversion + unit tests.
crates/ariadnetor-core/src/lib.rs Wires the new numeric module and re-exports try_real_from_f64 at the crate root.
crates/ariadnetor-algorithms/src/lib.rs Removes the crate-local numeric module entry point.
crates/ariadnetor-algorithms/src/krylov/lanczos.rs Switches tolerance casting to ariadnetor_core::try_real_from_f64.
crates/ariadnetor-algorithms/src/krylov/lanczos_kernels.rs Uses the core helper for RNG-derived real/imag conversions and test helpers.
crates/ariadnetor-algorithms/src/dmrg/sweep.rs Imports try_real_from_f64 from core instead of the removed local helper.
crates/ariadnetor-algorithms/src/dmrg/heff.rs Uses the core helper for eigensolver tolerance representability validation.
crates/ariadnetor-algorithms/src/dmrg/heff_block_sparse/validation.rs Same validation change for the block-sparse DMRG heff path.
crates/ariadnetor-mps/src/apply/successive_randomized.rs Delegates the SRC cutoff cast to the core helper (preserving panic semantics).
crates/ariadnetor-mps/src/apply/variational.rs Fixes variational tolerance casting (Dense + BlockSparse) to reject overflow-to-inf.
crates/ariadnetor-mps/tests/mps/apply_variational.rs Adds a Dense f32 #[should_panic] regression test for unrepresentable tolerances.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/ariadnetor-mps/src/apply/variational.rs
Comment thread crates/ariadnetor-mps/src/apply/variational.rs
Move the tolerance cast ahead of canonicalize and BraketEnvs::build in
both the Dense and BlockSparse variational paths. The cast is independent
of the environments, so an unrepresentable tolerance now fails fast
instead of panicking after that setup work, matching the up-front cutoff
validation the successive-randomized path already does.

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

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

@ultimatile
ultimatile merged commit 01fe8d5 into main Jul 18, 2026
2 checks passed
@ultimatile
ultimatile deleted the fix/472-tol-cast-overflow branch July 18, 2026 15:47
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.

Guard f64-to-real tolerance casts against overflow to infinity

2 participants