Bridge¶
Storage container for the SU(2) Clebsch–Gordan intertwiner data attached to each block of a non-Abelian tensor.
Bridge
dataclass
¶
Storage container for SU(2) CG tensor data using yuzuha canonical bases.
The Bridge class stores a CGSpec (Clebsch-Gordan specification) that identifies the canonical bases for the outer multiplicity (OM) space, along with a weight matrix that represents coefficients expanded according to these canonical bases.
Attributes:
| Name | Type | Description |
|---|---|---|
cgspec |
CGSpec
|
Identifies the canonical bases for the OM space. Encapsulates:
|
weights |
Tensor
|
Coefficient matrix with shape (num_components, om_dimension). Each row represents coefficients expanded in the canonical basis. The canonical bases are normalized with respect to the OM space. num_components can be any positive integer (typically starts at 1). om_dimension is obtained from cgspec.om_dimension(). |
device |
device
|
Device where the weight matrix is stored. |
om_dimension |
int
|
Dimension of the outer multiplicity space (number of fusion tree configurations). |
num_components |
int
|
Number of component rows in the weight matrix (weights.shape[0]). |
num_external |
int
|
Number of external edges in the CGSpec. |
Examples:
Create a Bridge for a simple three-edge SU(2) tensor:
>>> import yuzuha
>>> import torch
>>> from nicole.symmetry.delegate import Bridge
>>>
>>> # Define edges: two incoming spin-1/2, one outgoing spin-1
>>> j_half = yuzuha.Spin(1) # 2j=1 for j=1/2
>>> j_one = yuzuha.Spin(2) # 2j=2 for j=1
>>> edges = [
... yuzuha.Edge.incoming(j_half),
... yuzuha.Edge.incoming(j_half),
... yuzuha.Edge.outgoing(j_one),
... ]
>>>
>>> # Create CGSpec
>>> cgspec = yuzuha.CGSpec.from_edges(edges)
>>>
>>> # Initialize weight matrix (1 component)
>>> om_dim = cgspec.om_dimension()
>>> weights = torch.zeros(1, om_dim, dtype=torch.float64)
>>>
>>> # Create Bridge
>>> bridge = Bridge(cgspec, weights)
>>> bridge.om_dimension
1
>>> bridge.num_components
1
>>> bridge.num_external
3
Notes
- The OM space and canonical bases are fully managed by yuzuha.
- Nicole's Direction.IN (value +1) maps to yuzuha.Edge.incoming (+1).
- Nicole's Direction.OUT (value -1) maps to yuzuha.Edge.outgoing (-1).
- Both Nicole and yuzuha use the 2j integer convention for SU(2) spins.
Attributes¶
num_components
property
¶
Return the number of component rows in the weight matrix.
Functions¶
from_block
staticmethod
¶
from_block(
group: SymmetryGroup,
key: Tuple[Charge, ...],
directions: Sequence[Direction],
weights: Optional[Tensor] = None,
dtype: dtype = torch.float64,
device: Optional[device] = None,
) -> Bridge
Construct a Bridge from a BlockKey and corresponding directions.
This factory method creates a Bridge by extracting SU(2) charges from a BlockKey and creating the corresponding yuzuha CGSpec. Useful for converting Nicole tensor blocks into the yuzuha canonical basis representation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
group
|
SymmetryGroup
|
The symmetry group. Must be either SU2Group or ProductGroup with SU2Group as the last component. |
required |
key
|
Tuple[Charge, ...]
|
BlockKey containing one charge per edge. For SU2Group, charges are integers (2j values). For ProductGroup with SU(2), charges are tuples where the last element is the 2j value. |
required |
directions
|
Sequence[Direction]
|
One direction per edge in the BlockKey. Length must match len(key). |
required |
weights
|
Tensor
|
Pre-initialized weight matrix. If provided, must have shape (num_components, om_dimension). If None, weights are initialized with shape (1, om_dimension) with the first element set to 1 and all other elements set to 0. |
None
|
dtype
|
dtype
|
Data type for the weight matrix. Only used if weights is None. Defaults to torch.float64. |
float64
|
device
|
device or str
|
Device for the weight matrix. Only used if weights is None.
If None, defaults to |
None
|
Returns:
| Type | Description |
|---|---|
Bridge
|
New Bridge instance with CGSpec constructed from the block key and weights either provided or initialized with first element as 1. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If group is not SU2Group or ProductGroup with SU2Group, or if provided weights is not a torch.Tensor (via Bridge.post_init). |
ValueError
|
If the number of directions doesn't match the number of charges, if provided weights has incorrect shape (via Bridge.post_init), or if yuzuha rejects the edge configuration. |
Examples:
>>> from nicole import SU2Group, Direction
>>> from nicole.symmetry.delegate import Bridge
>>>
>>> # Pure SU(2) group with default weights
>>> group = SU2Group()
>>> key = (1, 1, 2) # Three edges: spin-1/2, spin-1/2, spin-1
>>> directions = [Direction.IN, Direction.IN, Direction.OUT]
>>> bridge = Bridge.from_block(group, key, directions)
>>> bridge.weights[0, 0] # First element is 1
tensor(1.)
>>>
>>> # ProductGroup with SU(2) and custom weights
>>> import torch
>>> from nicole import ProductGroup, U1Group
>>> group = ProductGroup([U1Group(), SU2Group()])
>>> key = ((0, 1), (-1, 1), (1, 2)) # Three edges with U1 and SU(2) charges
>>> custom_weights = torch.randn(3, 1)
>>> bridge = Bridge.from_block(group, key, directions, weights=custom_weights)
>>> bridge.num_components
3
to
¶
Move Bridge to a new device and optionally convert dtype.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
device
|
str or device
|
Target device ('cpu', 'cuda', 'mps', etc.) |
required |
dtype
|
dtype
|
Target dtype. If None, preserves current dtype. |
None
|
Returns:
| Type | Description |
|---|---|
Bridge
|
New Bridge instance with weights on the target device/dtype. If already on target device with target dtype, returns self. |
Examples:
clone
¶
Create a deep copy of this Bridge with cloned weights.
Returns:
| Type | Description |
|---|---|
Bridge
|
New Bridge instance with cloned weight matrix. |
Examples:
conj
¶
Return a new Bridge with flipped edge directions (conjugation).
Creates a new Bridge instance where all edge directions in the CGSpec are
flipped (incoming <-> outgoing). The cumulated Frobenius-Schur phase
returned by yuzuha.compute_conjugate is multiplied into the weight
matrix, so the resulting weights may differ from the original by a
global factor of ±1.
Returns:
| Type | Description |
|---|---|
Bridge
|
New Bridge instance with flipped edge directions and weights scaled by the cumulated FS phase (±1). |
Examples:
conj_phase
¶
Return the conjugation phase for this Bridge.
Computes and returns the cumulated Frobenius-Schur phase (±1) between the conjugate of a CG basis and the canonical basis. This phase arises from the coupling tree structure and is essential for correct scalar contractions of SU(2) tensors.
Returns:
| Type | Description |
|---|---|
float
|
The cumulated FS phase, either +1.0 or -1.0. |
Examples:
Description¶
Every block of an SU(2) or non-Abelian ProductGroup tensor carries a Bridge alongside its reduced-tensor data. The Bridge encodes the outer multiplicity (OM) structure of the block's Clebsch–Gordan decomposition using the yuzuha canonical basis:
cgspec(yuzuha.CGSpec) — identifies the canonical OM basis. It records the external edges (spins and their in/out directions) and all valid left-associative fusion trees (internal-spin tuples α). The OM dimension is the number of such trees.weights(torch.Tensor, shape(num_components, om_dimension)) — coefficient matrix expanded in the canonical basis. Each row corresponds to one component of the outer multiplicity; the number of rows grows as blocks mix under operations such as contraction.
Nicole manages Bridge objects internally. Users typically inspect them when examining tensor blocks or implementing custom SU(2)-aware routines.
Role in the R-W-C Decomposition¶
Each SU(2) tensor block is stored as a three-factor product R · W · C:
- R (reduced tensor,
Tensor.data[key]): the dense array of reduced tensor elements, indexed over the multiplet space of each index (Sector.dim). - W (weight matrix,
Bridge.weights, shape(dim(r), dim(α))): expands the component in the canonical OM basis. Each row is a vector in the OM space. - C (CG basis): the Clebsch–Gordan basis tensor with one axis per external edge and one OM axis (α), in a canonical orthonormal basis, computed on demand by the Yuzuha engine.
The connecting index between R and W is r (component); between W and C is α (outer multiplicity). See the Yuzuha Protocol for the full derivation and diagrams.
Accessing Bridge Data¶
from nicole import Tensor, SU2Group, Index, Sector, Direction
group = SU2Group()
idx = Index(Direction.OUT, group, sectors=(Sector(0, 1), Sector(1, 2), Sector(2, 1)))
T = Tensor.random([idx, idx.flip(), idx], itags=["i", "j", "k"], seed=42)
# Iterate over blocks
for key, block in T.data.items():
bridge = T.intw[key] # Bridge for this block
print(key, bridge.om_dimension) # OM dimension for this charge sector
print(bridge.weights.shape) # (num_components, om_dimension)
Constructing a Bridge¶
The from_block factory is the standard way to create a Bridge from a charge key and direction list:
from nicole import SU2Group, Direction
from nicole.symmetry.delegate import Bridge
group = SU2Group()
# Three-edge block: spin-1/2 ⊗ spin-1/2 → spin-1
key = (1, 1, 2) # charges in 2j convention
dirs = [Direction.IN, Direction.IN, Direction.OUT]
bridge = Bridge.from_block(group, key, dirs)
print(bridge.om_dimension) # 1 — only one valid fusion tree for j=1/2 ⊗ j=1/2 → j=1
print(bridge.num_components) # 1 — single component by default
print(bridge.weights) # tensor([[1.]])
For ProductGroup tensors the key contains tuples and the SU(2) charge is always the last element:
from nicole import ProductGroup, U1Group, SU2Group, Direction
from nicole.symmetry.delegate import Bridge
import torch
group = ProductGroup([U1Group(), SU2Group()])
key = ((0, 1), (-1, 1), (-1, 2)) # three edges: (U1, SU2) charges
dirs = [Direction.IN, Direction.IN, Direction.OUT]
bridge = Bridge.from_block(group, key, dirs)
print(bridge.num_external) # 3
Device and dtype¶
A Bridge's weights tensor lives on the same device as the corresponding data block. Use .to() to move it:
bridge_gpu = bridge.to('cuda')
bridge_gpu = bridge.to('cuda', dtype=torch.float32) # also cast dtype
OM Dimension¶
om_dimension is the number of linearly independent ways to couple the given spins to the target spin via a left-associative binary fusion tree. 2nd- and 3rd-order blocks always have OM = 1. OM > 1 first appears at 4th order, where multiple intermediate spin paths may be valid, and generally grows with both the tensor order and the spin magnitudes.
from nicole import SU2Group, Direction
from nicole.symmetry.delegate import Bridge
group = SU2Group()
# Four edges: j=1/2 ⊗ j=1/2 ⊗ j=1/2 → j=1/2
# Two intermediate couplings: intermediate spin can be 0 or 1
key = (1, 1, 1, 1)
dirs = [Direction.IN, Direction.IN, Direction.IN, Direction.OUT]
bridge = Bridge.from_block(group, key, dirs)
print(bridge.om_dimension) # 2
See Also¶
- SU2Group: Non-Abelian symmetry group that generates Bridge-carrying tensors
- ProductGroup: Non-Abelian product groups
- Yuzuha Protocol: Full explanation of the R-W-C decomposition and outer multiplicity
- Examples: SU(2)
Notes¶
Bridgeis a@dataclass; all fields are set at construction time and validated by__post_init__.cgspecis shared betweenBridgeinstances produced by non-mutating operations such as.clone(). Onlyweightsis copied.