ProductGroup¶
Combine multiple symmetry groups into a single product group, enforcing all constituent conservation laws simultaneously. Charges are tuples of component charges.
ProductGroup
dataclass
¶
Bases: SymmetryGroup
Product of multiple independent symmetry groups.
Represents the direct product of multiple symmetry groups, enabling tensors with multiple independent conserved quantities. Charges are tuples where each component corresponds to one component group.
Supports Abelian groups and at most one UnitaryGroup (non-Abelian) component. If a UnitaryGroup is present, it must be the last component.
Attributes:
| Name | Type | Description |
|---|---|---|
components |
Tuple[SymmetryGroup, ...]
|
Tuple of component SymmetryGroup instances. Can contain AbelianGroup instances and at most one UnitaryGroup instance (placed at the end). |
Examples:
>>> # U(1) particle number × U(1) spin (all Abelian)
>>> group = ProductGroup([U1Group(), U1Group()])
>>> group.neutral
(0, 0)
>>> group.fuse_unique((2, 1), (1, -1))
(3, 0)
>>> # U(1) × Z(2) (all Abelian)
>>> group = ProductGroup([U1Group(), Z2Group()])
>>> group.neutral
(0, 0)
>>> group.fuse_unique((3, 1), (-1, 0))
(2, 1)
>>> # U(1) × SU(2) (mixed: has UnitaryGroup)
>>> group = ProductGroup([U1Group(), SU2Group()])
>>> group.fuse_channels((1, 1), (0, 1))
((1, 0), (1, 2)) # Two fusion channels from SU(2) (spin-1/2 ⊗ spin-1/2)
Initialize ProductGroup with component symmetry groups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
components
|
Sequence[SymmetryGroup]
|
Sequence of SymmetryGroup instances. Must contain at least one group. Can include AbelianGroup instances and at most one UnitaryGroup instance. Nested ProductGroups are not allowed. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If components is empty, contains multiple UnitaryGroups, or has UnitaryGroup not at the last position. |
TypeError
|
If components contains non-SymmetryGroup instances or nested ProductGroups. |
Attributes¶
neutral
property
¶
Return the neutral element as a tuple of component neutrals.
is_abelian
property
¶
Return True if all components are Abelian, False if any is non-Abelian.
A ProductGroup is Abelian only when all its components are Abelian groups. If it contains a UnitaryGroup component, it is non-Abelian.
Functions¶
irrep_dim
¶
Return dimension of the irreducible representation.
For ProductGroup, the irrep dimension is the product of constituent irrep dimensions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q
|
Tuple[Any, ...]
|
Charge tuple. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Product of component irrep dimensions. |
dual
¶
Return the dual (contragredient) of a charge tuple.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q
|
Tuple[Any, ...]
|
Charge tuple. |
required |
Returns:
| Type | Description |
|---|---|
Tuple
|
Tuple of dual charges. |
fuse_unique
¶
Fuse multiple charge tuples component-wise (Abelian-only).
This method is only available when all components are Abelian groups.
For ProductGroups containing a UnitaryGroup, use fuse_channels instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*qs
|
Tuple[Any, ...]
|
Variable number of charge tuples to fuse. |
()
|
Returns:
| Type | Description |
|---|---|
Tuple
|
The unique fused charge tuple. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If this ProductGroup contains a UnitaryGroup component. |
Examples:
fuse_channels
¶
Fuse multiple charge tuples, returning all achievable fusion channels.
When all components are Abelian, returns a single-element tuple. When a UnitaryGroup component is present (must be at the end), returns multiple channels corresponding to the UnitaryGroup's fusion outcomes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*qs
|
Tuple[Any, ...]
|
One or more charge tuples to fuse. |
()
|
Returns:
| Type | Description |
|---|---|
Tuple[Tuple[Any, ...], ...]
|
Tuple of all achievable fusion channel tuples, independent of the fusion tree structure. |
Examples:
>>> # All Abelian: single channel
>>> group = ProductGroup([U1Group(), Z2Group()])
>>> group.fuse_channels((2, 1), (1, 0))
((3, 1),)
equal
¶
Check if two charge tuples are equal component-wise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
Tuple[Any, ...]
|
Charge tuples to compare. |
required |
b
|
Tuple[Any, ...]
|
Charge tuples to compare. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if all components are equal. |
validate_charge
¶
Validate that a charge is a tuple of correct length with valid components.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
q
|
Any
|
Charge to validate. |
required |
Raises:
| Type | Description |
|---|---|
TypeError
|
If charge is not a tuple. |
ValueError
|
If charge has incorrect length or invalid component charges. |
Description¶
Combines multiple independent symmetry groups. Charges are tuples with one component per group.
Abelian and Non-Abelian Components¶
ProductGroup supports both Abelian and non-Abelian component groups. When an SU2Group is included, it must be the last component:
from nicole import ProductGroup, U1Group, Z2Group, SU2Group
# Abelian only
group = ProductGroup([U1Group(), Z2Group()])
print(group.is_abelian) # True
# With SU(2) as last component — non-Abelian
group = ProductGroup([U1Group(), SU2Group()])
print(group.is_abelian) # False
print(group.name) # "U1×SU2"
print(group.neutral) # (0, 0)
Charge Operations¶
For Abelian-only products, all operations are component-wise:
- Fusion:
(q1_a, q1_b) ⊕ (q2_a, q2_b) = (q1_a ⊕ q2_a, q1_b ⊕ q2_b) - Dual: Component-wise dual
- Identity: Tuple of component identities
For products containing SU2Group, use fuse_channels instead of fuse_unique — SU(2) fusion is multi-channel:
# Abelian: fuse_unique gives a single result
group = ProductGroup([U1Group(), Z2Group()])
group.fuse_unique((2, 1), (1, 1)) # (3, 0) — U1: 2+1=3, Z2: 1⊕1=0
# Non-Abelian: fuse_channels gives multiple result channels
group = ProductGroup([U1Group(), SU2Group()])
# (1, 1) ⊗ (1, 1): charge 1+1=2 for U1, 1⊗1=(0,2) for SU2
group.fuse_channels((1, 1), (1, 1)) # ((2, 0), (2, 2))
irrep_dim¶
irrep_dim is the product of the component irrep_dim values — always 1 for Abelian factors, 2j+1 for SU(2):
# Abelian: always 1
group = ProductGroup([U1Group(), Z2Group()])
group.irrep_dim((3, 1)) # 1 × 1 = 1
# Non-Abelian: SU(2) factor contributes 2j+1
group = ProductGroup([U1Group(), SU2Group()])
group.irrep_dim((2, 1)) # 1 × 2 = 2 (U1 contributes 1, SU2 spin-1/2 contributes 2)
group.irrep_dim((0, 2)) # 1 × 3 = 3 (triplet)
Physical Applications¶
- U(1) × U(1): Particle number and spin magnetization (two separate U(1) charges)
- U(1) × Z(2): Particle number and fermion parity
- U(1)ᴺ: Multiple particle species
- U(1) × SU(2): Particle number + full spin-rotation symmetry (Hubbard/band models)
- Z(2) × SU(2): Parity + full spin-rotation symmetry
See Also¶
- U1Group: Abelian component group
- Z2Group: Abelian component group
- SU2Group: Non-Abelian component group
- Overview: Symmetry system introduction
- Examples: Product Groups
Notes¶
SU2Group, if present, must be the last component ofProductGroup.- When
SU2Groupis a component,is_abelianreturnsFalseand tensors carry intertwiner (Bridge) data. - Charges are tuples matching the number of component groups.