Added MomentumBlockTensor and compatibilities upgrades#142
Merged
Conversation
Introduce MomentumBlockTensor as a momentum-pair-resolved tensor type for block-matrix operations in momentum space, along with its specialized matmul rules and constrained transpose behavior. This change adds: - MomentumBlockTensor and MomentumBlockSpace support for pair-labelled momentum block algebra - specialized matmul dispatch for: - MomentumBlockTensor @ Tensor - Tensor @ MomentumBlockTensor - MomentumBlockTensor @ MomentumBlockTensor - specialized permute/transpose handling for matrix-leg swaps - factorized band helpers: - get_band_transform(...) - get_band_fold(...) - bandtransform(...) and bandfold(...) rewritten in terms of T_g @ H @ T_g.h(-2, -1) - side selection via side: Literal["left", "right"] for sampled Hilbert legs - top-level export of MomentumBlockTensor from qten - expanded documentation for momentum block semantics and band helper APIs - focused tests covering custom matmul behavior, transpose constraints, fold/transform factorization, side selection, and alignment validation Also includes cleanup: - remove obsolete internal anchor metadata from MomentumBlockTensor - promote dtypes in block matmul paths where needed - rename the private implementation module to _mb_tensor.py - update doc links to the new public qten.MomentumBlockTensor path
- make band transform/fold helpers work one side at a time and support asymmetric left/right Hilbert spaces - extend region_restrict with side-aware behavior and MomentumBlockSpace left/right momentum projections - add a strict_dims policy for structured tensor subclasses so rank/layout-changing generic ops downgrade to plain Tensor - preserve the left operand subtype in generic Tensor + Tensor when the resulting dims still satisfy its invariants - expand docs, stubs, and regression tests for MomentumBlockTensor and strict-dims behavior
There was a problem hiding this comment.
Pull request overview
This PR introduces momentum-pair “block” tensor infrastructure to factorize band-space transforms/folds via explicit momentum-block operators, and updates the band helper APIs and tests accordingly.
Changes:
- Added
MomentumBlockTensor(rank-3 structured tensor) with specializedpermute/transposeand@rules for momentum-pair block contraction/composition. - Added
MomentumBlockSpace(momentum-pair state space) and updatedbands.bandtransform/bandfoldto useget_band_transform/get_band_fold+ block-conjugation factoring. - Added/updated tests to cover factorization equivalence and momentum-block matmul semantics; bumped package version to
0.4.0.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/qten/linalg/_mb_tensor.py |
New MomentumBlockTensor implementation + specialized @/axis-reordering semantics. |
src/qten/bands.py |
Adds get_band_transform/get_band_fold and refactors bandtransform/bandfold to use them. |
src/qten/symbolics/state_space.py |
Adds MomentumBlockSpace runtime implementation. |
src/qten/symbolics/state_space.pyi |
Adds MomentumBlockSpace stub. |
src/qten/linalg/tensors.py |
Makes permute/transpose multimethods to allow subtype-specific behavior. |
src/qten/symbolics/__init__.py |
Re-exports MomentumBlockSpace. |
src/qten/__init__.py |
Re-exports MomentumBlockTensor. |
tests/test_momentum_block_tensor.py |
New tests for transpose and momentum-block @ behavior. |
tests/test_basis_transform.py |
Adds tests for get_band_fold factorization and side sampling. |
tests/test_abelian.py |
Adds tests for get_band_transform factorization and side sampling. |
pyproject.toml |
Version bump to 0.4.0. |
Comments suppressed due to low confidence (1)
src/qten/linalg/tensors.py:3199
- permute()/transpose() were switched to
@multimethodand now have runtime signatures returning plain Tensor, but their docstrings still claim they return TensorType (preserving wrapper type). This also conflicts with the Tensor.permute/transpose methods being typed as -> Self and the stubs in tensors.pyi still declaring TensorType. Consider updating the annotations/docstrings (or adding overloads/casts) so the public typing contract continues to reflect subtype-preserving behavior.
right : Tensor
The tensor.
Returns
-------
Tensor
A new tensor with each element multiplied by the scalar.
"""
return Tensor(data=left * right.data, dims=right.dims)
@Operable.__mul__.register
def _(left: Tensor, right: Number) -> Tensor:
"""
Perform element-wise multiplication of a tensor and a number.
Parameters
----------
left : Tensor
The tensor.
right : Number
The scalar value.
Returns
-------
Tensor
A new tensor with each element multiplied by the scalar.
"""
return Tensor(data=left.data * right, dims=left.dims)
@Operable.__add__.register
def _(left: Number, right: Tensor) -> Tensor:
r"""
Add a number to the diagonal of the tensor (broadcasting over batch dimensions).
This treats the tensor as a batch of matrices defined by the last two
dimensions. The scalar is added to the diagonal elements of each matrix.
For rank-2 tensors this is equivalent to \(cI + M\).
Parameters
----------
left : Number
The scalar value to add to the diagonal.
right : Tensor
The target tensor (must be at least rank 2).
Returns
-------
Tensor
The result of adding the scalar to the diagonal.
"""
iden = eye(right.dims)
return left * iden + right
@Operable.__add__.register
def _(left: Tensor, right: Number) -> Tensor:
r"""
Add a number to the diagonal of the tensor (broadcasting over batch dimensions).
This treats the tensor as a batch of matrices defined by the last two
dimensions. The scalar is added to the diagonal elements of each matrix.
For rank-2 tensors this is equivalent to \(M + cI\).
Parameters
----------
left : Tensor
The target tensor (must be at least rank 2).
right : Number
The scalar value to add to the diagonal.
Returns
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Refactor get_band_transform and get_band_fold around shared space-based helpers, then register multimethod overloads that accept explicit symbolic spaces. This adds public overload support for: - get_band_transform(Opr, MomentumSpace, HilbertSpace) - get_band_fold(BasisTransform, MomentumSpace, HilbertSpace) It also updates the API docs to follow the existing multimethod style by adding overload stubs, Supported forms sections, and notes explaining how the generated docs render the main implementation docstring.
all(..., keepdim=True) was incorrectly preserving strict-dims subclasses even though reduced axes are rewritten to BroadcastSpace(). For MomentumBlockTensor, that caused _wrap_tensor_result() to rebuild the subclass with invalid dims and fail validation instead of downgrading to a plain Tensor. This change makes all() always pass preserve_strict=False, matching the strict-dims policy used by other structure-changing reductions. It also adds a regression test covering MomentumBlockTensor.all(dim=1, keepdim=True).
The tensors stub declared dim_types as a module-level function even though the runtime API implements it as Tensor.dim_types(). This made the .pyi inconsistent with the implementation and could break type checking and editor autocomplete for tensor.dim_types(). This change moves dim_types(self) -> tuple[type, ...] onto the Tensor class in tensors.pyi and removes the invalid module-level declaration.
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
This PR extends the momentum-block workflow so Fourier and band-space helpers can work cleanly with asymmetric left/right Hilbert spaces and block-space momentum projections.
It also introduces a stricter subtype policy for structured tensor wrappers like
MomentumBlockTensor: layout-preserving operations keep the subtype, while rank/layout-changing generic tensor operations downgrade to plainTensor.What changed
One-sided momentum-block band helpers
Updated the band-transform and band-fold factorization APIs to work one side at a time:
get_band_transform(t, tensor, side="left")get_band_fold(transform, tensor, side="left")bandtransform(t, tensor, opt="left" | "right" | "both")bandfold(transform, tensor, opt="left" | "right" | "both")These helpers no longer require the last two Hilbert-space legs to span the same rays. Instead, the selected
sidedetermines which Hilbert-space leg is sampled when constructing the block transform/fold.This makes rectangular and left/right-asymmetric band tensors first-class in the factorized workflow.
region_restrict(..., side=...)and block-space momentum projectionExtended
region_restrictto accept:for both runtime and stub signatures.
Behavior now is:
side="left"usestensor.dims[1]andside="right"usestensor.dims[2]MomentumBlockSpace,region_restrictprojects that pair axis to a uniqueMomentumSpacethrough:MomentumBlockSpace.left()MomentumBlockSpace.right()The return value is still a plain Fourier
Tensor, which is exactly the object needed for products such as:To support that,
MomentumBlockSpacenow provides:left() -> MomentumSpaceright() -> MomentumSpaceand also defines a proper structure-based hash so these spaces work reliably in cached alignment/union code.
Strict-dims tensor subtype policy
Added a new decorator and runtime policy in
qten.linalg.tensors:@strict_dimsSubclasses marked with
@strict_dimsdeclare that their symbolic dimension layout is part of their semantic invariant.For these subclasses:
TensorThis is implemented through a shared helper:
_wrap_tensor_result(...)and a class marker:
Tensor._strict_dims: ClassVar[bool] = FalseMomentumBlockTensoris now marked with@strict_dims.This fixes the previous issue where generic methods like
mean(dim=0)attempted to preserveMomentumBlockTensoreven after destroying its defining layout:The generic downgrade behavior was applied to rank/layout-changing operations such as:
unsqueezesqueezeallmeannormargmaxargminfactorize_dimproduct_dimsTensor addition preserves left subtype
Updated generic
Tensor + Tensorso it preserves the concrete type of the left operand by usingreplace(left, ...)instead of always constructing a fresh baseTensor.This keeps subtype-preserving additions working naturally for structured wrappers whose output dims still satisfy their invariants.
The
tensors.pyistubs were updated accordingly for__add__.Documentation and stubs
Expanded and updated documentation for:
MomentumBlockTensorget_band_transformget_band_foldbandtransformbandfoldregion_restrictMomentumBlockSpace.left/rightstrict_dimsTensor._strict_dimsAlso updated the relevant
.pyifiles for:fourier.region_restrictMomentumBlockSpace.left/rightTensor.__add__strict_dimsTensor._strict_dimsTests
Updated and added tests covering:
bandtransformbandfoldMomentumBlockSpaceprojection behavior throughregion_restrictMomentumBlockTensorsubtype preservation through generic additionmeanunsqueezeargmaxNotes
Two important semantic points in this PR:
region_restrict(MomentumBlockTensor, ...)still returns a plain FourierTensor, not a block tensor. That is intentional: it is meant to produce the left/right Fourier factor that can act on a block tensor.Validation
Validated with:
uv run pytest -q tests/test_momentum_block_tensor.py tests/test_tensors.pypython -m py_compile