Skip to content

Nicole 0.3.6

Choose a tag to compare

@Phy-David-Zhang Phy-David-Zhang released this 30 Apr 18:47
· 9 commits to stable since this release

Nicole 0.3.6 — API Versioning and Hot-path Optimization

Release Date: April 30, 2026

Version 0.3.6 exposes the package version as nicole.__version__ and tightens the symmetry group internals: redundant validate_charge guard calls are removed from hot paths across SU2Group and ProductGroup, fuse_unique implementations in U1Group and Z2Group are simplified to built-in expressions, and ProductGroup caches its neutral element at construction time. No public API is changed.

✨ New Features

nicole.__version__

__version__ is now a public attribute of the nicole package, set at import time via importlib.metadata.version("nicole"):

import nicole
print(nicole.__version__)  # e.g. "0.3.6"

This follows the standard Python convention for installed packages and makes it easy to verify the running version in scripts, notebooks, and bug reports.

🚀 Enhancements

Symmetry group hot-path cleanup

Several symmetry group methods carried redundant validate_charge calls that re-checked types and ranges on charges that are already known to be valid at the call site (they came from internal tensor operations, not from user input). Those guards have been removed:

Location Removed guards
U1Group.fuse_unique validation loop over qs
Z2Group.fuse_unique validation loop over qs
SU2Group.dual validate_charge(two_j) before returning
SU2Group.irrep_dim validate_charge(two_j) before returning
SU2Group.fuse_channels per-element validate_charge loop over two_js
ProductGroup methods per-element validate_charge loops in several methods

Validation still runs at tensor construction time (when charges originate from user input) and through the public validate_charge method. The removal eliminates repeated type and range checks in code paths that execute once per block per operation.

U1Group.fuse_unique is simplified to return sum(qs) and Z2Group.fuse_unique to a single XOR accumulation, replacing loops that also contained the now-removed guards. ProductGroup.equal is simplified to return a == b, delegating to built-in tuple equality instead of a manual component-wise loop.

ProductGroup neutral-element cache

ProductGroup.__init__ now precomputes the neutral element and stores it as a private _neutral tuple. The neutral property returns this cached value directly:

# before: tuple(comp.neutral for comp in self.components) on every access
# after:  self._neutral  (computed once at __init__)

This is a minor but zero-cost improvement for code that accesses neutral repeatedly (e.g., inside fuse_unique and fuse_channels loops over many blocks).

🧪 Test Suite (1603 tests)

  • 1593 tests pass, 10 skipped (accelerator-only tests on CPU-only CI)
  • No new tests added in this release

📊 Statistics

Code Changes

  • 7 commits since v0.3.5
  • 4 files changed: 10 insertions, 29 deletions
  • Source modules touched: src/nicole/__init__.py, src/nicole/symmetry/abelian.py, src/nicole/symmetry/unitary.py, src/nicole/symmetry/product.py

✅ Compatibility

Breaking Changes: None. All previously valid calls continue to work unchanged. The new __version__ attribute does not conflict with any existing public name.

Requirements:

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

📝 Notes

The validate_charge removals affect only internal method paths — dual, irrep_dim, fuse_unique, fuse_channels, and equal — which are not part of the documented public API. Code that calls symmetry group methods directly with out-of-range or wrong-type charges was already in undefined territory; the only change is that some of those paths will now propagate further before raising a Python-level error rather than being caught early. The public validate_charge method is untouched and remains the correct tool for validating user-supplied charges before passing them to a symmetry group.

nicole.__version__ reads from the installed package metadata via importlib.metadata.version. In an editable install (uv pip install -e .), the reported version reflects the value of version in pyproject.toml at the time the package was last (re-)installed, not at import time. Run uv pip install -e . again after bumping the version in pyproject.toml to keep __version__ in sync.