Skip to content

Nicole 0.3.5

Choose a tag to compare

@Phy-David-Zhang Phy-David-Zhang released this 25 Apr 22:31
· 19 commits to stable since this release

Nicole 0.3.5 — New Arithmetics and SVD Diagnostics

Release Date: April 26, 2026

Version 0.3.5 completes the Tensor arithmetic surface with equality operators, numerical near-equality via allclose, unary negation, and scalar division. The svd function gains an optional requires_info parameter that exposes truncation-loss diagnostics without changing the default return signature. A set of documentation and test-coverage improvements round out the release.

✨ New Features

Equality — Tensor.__eq__ and Bridge.__eq__

Tensor and Bridge now implement the Python equality operator ==.

Tensor.__eq__ performs a staged comparison: index count and full index structure first; then block key sets; then exact element-wise comparison of every dense block via torch.equal; and — for non-Abelian tensors — intertwiner equality via Bridge.__eq__.

Bridge.__eq__ checks structural compatibility (same charge keys and edge structure) then compares the weights tensor of each Clebsch–Gordan entry exactly.

allclose — Numerical Near-Equality

A new allclose(A, B, rtol=1e-5, atol=1e-8) function tests numerical equality within floating-point tolerances. For Abelian tensors each dense block is compared with torch.allclose. For SU(2) tensors the physical tensor R @ W is compared block-by-block, making the check gauge-invariant: two tensors that represent the same physical content but differ in their internal (R, W) factorization still compare as equal.

Structural mismatches (different tensor order, incompatible symmetry groups or index directions) raise ValueError; differing block key sets return False without raising.

Unary Negation and Scalar Division

Tensor.__neg__ adds the unary minus operator -T, negating every dense block. Tensor.__truediv__ adds scalar division T / scalar, dividing every dense block by the given scalar. Both are implemented through the existing __mul__ path and therefore support autograd and all device and dtype combinations.

SVD requires_info — Truncation-Loss Monitoring

svd now accepts a keyword-only parameter requires_info: bool = False. When True, the return value is a 4-tuple whose last element is an info dict; when False (the default), the usual 3-tuple is returned. The dict currently contains one key, "discarded_weight", recording the sum of all singular values truncated away across all charge sectors — zero when no truncation was applied.

🧪 Test Suite (1603 tests)

  • 1593 tests pass, 10 skipped (accelerator-only tests on CPU-only CI)
  • New tests in tests/operations/test_arithmetic.py covering Tensor.__eq__ for Abelian and SU(2) tensors (including mismatched structure, intertwiner presence, and non-tensor operands), unary negation, and scalar division
  • New tests in tests/operations/test_maneuver.py covering allclose for Abelian and SU(2) tensors, tolerance boundaries, structural mismatch errors, and gauge-invariance under regularize
  • New tests in tests/symmetry/test_delegate.py for Bridge.__eq__ covering identical, same-content, and structurally differing bridges
  • New tests in tests/operations/test_factorize.py for SVD requires_info and "discarded_weight" values against known nkeep, thresh, and combined truncations
  • New tests in tests/support/test_display.py for index_summary output across U(1), Z2, SU(2), and ProductGroup indices

📖 Documentation

  • allclose API page (docs/api/arithmetic/allclose.md): New reference covering the function signature, SU(2) gauge-invariance guarantee, and behaviour on structural mismatches; cross-links to Tensor.__eq__ and Bridge
  • SVD page (docs/api/decomposition/svd.md): Documents the requires_info parameter and the "discarded_weight" entry in the returned info dict
  • Decomposition examples (docs/examples/operations/decomposition-examples.md): Extended with a worked example demonstrating truncation-loss monitoring via requires_info=True
  • Addition page (docs/api/arithmetic/addition.md): Added cross-link to allclose for numerical equality

📊 Statistics

Code Changes

  • 43 commits since v0.3.4
  • 32 files changed: 1,028 insertions, 105 deletions
  • Source modules touched: src/nicole/tensor.py, src/nicole/maneuver.py, src/nicole/decomp.py, src/nicole/symmetry/delegate.py, src/nicole/__init__.py
  • Dead code removed: _axes_from_names helper in decomp.py, superseded since v0.3.2
  • einsum subscript convention standardized in bench/conductor.py, bench/network.py, iter_diag_ferm, and iter_diag_spin

✅ Compatibility

Breaking Changes: None. All previously valid calls continue to work unchanged.

The new __eq__ operator performs value-based comparison rather than identity comparison. Code that relied on == returning True by object identity will now receive the correct value-based result instead.

Requirements:

  • Python ≥ 3.11
  • PyTorch ≥ 2.5
  • Yuzuha ≥ 0.1.5

📝 Notes

allclose and Tensor.__eq__ serve complementary roles: __eq__ tests exact equality of the internal representation while allclose tests approximate equality of the physical tensor. For SU(2) tensors the distinction matters — __eq__ returns False for two physically identical tensors that differ in gauge, while allclose is gauge-invariant and returns True. Use __eq__ to verify that an operation is a pure permutation or relabelling; use allclose after numerical manipulations.