Skip to content

qten.symbolics

Package reference for qten.symbolics.

symbolics

Symbolic basis, operator, and state-space layer for QTen.

This package hosts the symbolic objects that give QTen tensors their semantic axis metadata: basis states, Hilbert spaces, abstract operators, state spaces, and helper constructors acting on those structures.

Core symbolic values

Multiple is the scalar-times-object wrapper used for factored symbolic coefficients. U1Basis is the atomic symbolic basis state, U1Span is an ordered span of basis states, and HilbertSpace stores symbolic basis sectors as a state space.

Operators

Opr is the base symbolic operator class. FuncOpr lifts a Python callable on one irrep type. Convenience constructors include translate_opr, rebase_opr, and fractional_opr.

State-space utilities

State-space types include StateSpace, MomentumSpace, BroadcastSpace, IndexSpace, StateSpaceFactorization, and BzPath. Helper functions include brillouin_zone, embedding_order, permutation_order, restructure, and same_rays.

Hilbert-space helpers

Hilbert-space helper functions include region_hilbert, hilbert_opr_repr, match_indices, and interpolate_reciprocal_path.

Exported API

Multiple dataclass

Multiple(coef: Number, base: BaseType)

Bases: Generic[BaseType]

Represent a scalar coefficient multiplied by an arbitrary base object.

The class is intentionally minimal: it stores the coefficient and base separately so higher-level symbolic routines can postpone expansion or simplification until needed. This avoids unnecessary SymPy work in hot paths where the structured form is more efficient than immediately building a combined symbolic expression.

Attributes:

Name Type Description
coef Number

Numeric SymPy coefficient applied to base.

base BaseType

The symbolic or scalar object being multiplied by coef.

coef instance-attribute

coef: Number

Numeric SymPy coefficient applied to base, kept separate so callers can accumulate scalar factors without eagerly rebuilding symbolic expressions.

base instance-attribute

base: BaseType

The symbolic or scalar object being multiplied by coef, preserved in structured form for later operator application or simplification.

BzPath dataclass

BzPath(
    k_space: MomentumSpace,
    labels: tuple,
    waypoint_indices: tuple,
    path_order: tuple,
    path_positions: tuple,
)

A Brillouin-zone path through high-symmetry waypoints.

Attributes:

Name Type Description
k_space MomentumSpace

Unique momentum points sampled along the path.

labels tuple

Labels for the waypoints in path order.

waypoint_indices tuple

Indices into the dense path where each waypoint occurs.

path_order tuple

For each dense path sample, index of the corresponding unique momentum in k_space.

path_positions tuple

Cumulative Cartesian arc-length coordinate for each dense path sample.

k_space instance-attribute

k_space: MomentumSpace

Unique momentum points sampled along the path, with duplicates across segments removed while preserving the path's effective traversal order.

labels instance-attribute

labels: tuple

Labels for the waypoints in path order, typically high-symmetry point names used for plotting.

waypoint_indices instance-attribute

waypoint_indices: tuple

Indices into the dense path where each waypoint occurs, suitable for axis ticks or segment markers in band-structure plots.

path_order instance-attribute

path_order: tuple

For each dense path sample, index of the corresponding unique momentum in k_space. This maps the full piecewise-linear path back onto the unique momentum list.

path_positions instance-attribute

path_positions: tuple

Cumulative Cartesian arc-length coordinate for each dense path sample, used as the continuous x-axis parameter along the path.

BroadcastSpace dataclass

BroadcastSpace(structure: OrderedDict[T, int])

Bases: StateSpace[_BAxis]

Metadata marker for singleton/broadcast tensor axes.

Design intent

BroadcastSpace represents an axis that behaves like a size-1 axis under tensor broadcasting. It is used to model dimensions introduced by unsqueeze, None indexing, or other operations where data may be expanded without introducing a concrete physical basis.

Structure semantics

BroadcastSpace stores a private singleton marker in structure: OrderedDict({_BAxis(): 0}). This keeps the axis dimension at 1 while still providing a stable coordinate for structure-based index mapping helpers.

Implication for index mapping

For BroadcastSpace -> BroadcastSpace, embedding_order(...) resolves to (0,). This is intentional and allows consumers that build runtime index coordinates from structure mappings to treat broadcast axes as a singleton axis at position 0.

The _BAxis marker is internal implementation detail. It is not a physical basis element and should not be relied on outside broadcast-axis plumbing.

Compatibility rules

Multimethod rules in this module treat BroadcastSpace as compatible with any StateSpace in same_rays(...), and as neutral in __add__(...). The neutral-addition behavior is BroadcastSpace + X -> X, X + BroadcastSpace -> X, and BroadcastSpace + BroadcastSpace -> BroadcastSpace.

This makes it suitable as a placeholder axis that can be promoted to a concrete state space during alignment/broadcast operations.

Attributes:

Name Type Description
structure OrderedDict

Private singleton mapping OrderedDict({_BAxis(): 0}) used to encode a size-1 broadcast axis.

dim property

dim: int

The total size of the vector space.

structure class-attribute instance-attribute

structure: OrderedDict[_BAxis, int] = field(
    default_factory=lambda: OrderedDict({_BAxis(): 0}),
    init=False,
)

Private singleton mapping OrderedDict({_BAxis(): 0}) used to encode a size-1 broadcast axis. The stored marker is internal and exists only so structure-based helpers can consistently refer to the unique broadcast slot.

__str__ class-attribute instance-attribute

__str__ = __repr__

register_plot_method classmethod

register_plot_method(name: str, backend: str = 'plotly')

Register a backend plotting function for this plottable class.

The returned decorator stores the function in the global plotting registry. Registered functions receive the object being plotted as their first argument, followed by any extra positional and keyword arguments supplied to plot().

Parameters:

Name Type Description Default
name str

User-facing plot method name, such as scatter, structure, or heatmap.

required
backend str

Backend name that selects the implementation. The qten-plots extension currently uses plotly and matplotlib.

'plotly'

Returns:

Type Description
Callable

Decorator that registers the provided plotting function and returns it unchanged.

Source code in src/qten/plottings/_plottings.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@classmethod
def register_plot_method(cls, name: str, backend: str = "plotly"):
    """
    Register a backend plotting function for this plottable class.

    The returned decorator stores the function in the global plotting
    registry. Registered functions receive the object being plotted as their
    first argument, followed by any extra positional and keyword arguments
    supplied to [`plot()`][qten.plottings.Plottable.plot].

    Parameters
    ----------
    name : str
        User-facing plot method name, such as `scatter`, `structure`, or
        `heatmap`.
    backend : str
        Backend name that selects the implementation. The `qten-plots`
        extension currently uses `plotly` and `matplotlib`.

    Returns
    -------
    Callable
        Decorator that registers the provided plotting function and returns
        it unchanged.
    """

    def decorator(func: Callable):
        # We register against 'cls' - the class this method was called on.
        Plottable._registry[(cls, name, backend)] = func
        return func

    return decorator

plot

plot(method: str, backend: str = 'plotly', *args, **kwargs)

Dispatch a named plot method to a registered backend implementation.

The dispatcher first loads plotting entry points, then searches the instance type and its base classes for a matching (type, method, backend) registration. Additional arguments are forwarded unchanged to the selected backend function.

Parameters:

Name Type Description Default
method str

Plot method name registered for this object's type.

required
backend str

Backend implementation to use. The qten-plots extension currently registers plotly and matplotlib.

'plotly'
args

Positional arguments forwarded to the registered plotting function.

()
kwargs

Keyword arguments forwarded to the registered plotting function.

{}

Returns:

Type Description
object

Backend-specific figure object returned by the registered plotting function, such as a Plotly or Matplotlib figure.

Raises:

Type Description
ValueError

If no plotting function is registered for the requested method and backend on this object.

See Also

qten_plots.plottables.PointCloud Public plottable helper object provided by the plotting extension.

Source code in src/qten/plottings/_plottings.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def plot(self, method: str, backend: str = "plotly", *args, **kwargs):
    """
    Dispatch a named plot method to a registered backend implementation.

    The dispatcher first loads plotting entry points, then searches the
    instance type and its base classes for a matching `(type, method,
    backend)` registration. Additional arguments are forwarded unchanged to
    the selected backend function.

    Parameters
    ----------
    method : str
        Plot method name registered for this object's type.
    backend : str
        Backend implementation to use. The `qten-plots` extension currently
        registers `plotly` and `matplotlib`.
    args
        Positional arguments forwarded to the registered plotting function.
    kwargs
        Keyword arguments forwarded to the registered plotting function.

    Returns
    -------
    object
        Backend-specific figure object returned by the registered plotting
        function, such as a Plotly or Matplotlib figure.

    Raises
    ------
    ValueError
        If no plotting function is registered for the requested method and
        backend on this object.

    See Also
    --------
    qten_plots.plottables.PointCloud
        Public plottable helper object provided by the plotting extension.
    """
    Plottable._ensure_backends_loaded()

    # Iterate over the MRO (Method Resolution Order) of the instance
    for class_in_hierarchy in type(self).__mro__:
        key = (class_in_hierarchy, method, backend)

        # Check the central registry
        if key in Plottable._registry:
            plot_func = Plottable._registry[key]
            return plot_func(self, *args, **kwargs)

    # If we reach here, no method was found. Provide a helpful error.
    self._raise_method_not_found(method, backend)

elements

elements() -> tuple[T, ...]

Return the spatial elements as a tuple.

Source code in src/qten/symbolics/state_space.py
83
84
85
86
@override
def elements(self) -> Tuple[T, ...]:
    """Return the spatial elements as a tuple."""
    return tuple(self.structure.keys())

add_conversion classmethod

add_conversion(
    T: type[B],
) -> Callable[[Callable[[A], B]], Callable[[A], B]]

Register a conversion from cls to T.

The decorated function is stored under (cls, T). When an instance of cls later calls convert(T), that function is used to produce the converted object.

Parameters:

Name Type Description Default
T Type[B]

Destination type produced by the registered conversion function.

required

Returns:

Type Description
Callable[[Callable[[A], B]], Callable[[A], B]]

Decorator that stores the conversion function and returns it unchanged.

Examples:

@MyType.add_conversion(TargetType)
def to_target(x: MyType) -> TargetType:
    ...
Source code in src/qten/abstracts.py
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
@classmethod
def add_conversion(
    cls: Type[A], T: Type[B]
) -> Callable[[Callable[[A], B]], Callable[[A], B]]:
    """
    Register a conversion from `cls` to `T`.

    The decorated function is stored under `(cls, T)`. When an instance of
    `cls` later calls [`convert(T)`][qten.abstracts.Convertible.convert],
    that function is used to produce the converted object.

    Parameters
    ----------
    T : Type[B]
        Destination type produced by the registered conversion function.

    Returns
    -------
    Callable[[Callable[[A], B]], Callable[[A], B]]
        Decorator that stores the conversion function and returns it
        unchanged.

    Examples
    --------
    ```python
    @MyType.add_conversion(TargetType)
    def to_target(x: MyType) -> TargetType:
        ...
    ```
    """

    def decorator(func: Callable[[A], B]) -> Callable[[A], B]:
        _type_conversion_table[(cls, T)] = cast(Callable[[Any], Any], func)
        return func

    return decorator

convert

convert(T: type[B]) -> B

Convert this instance to the requested target type.

Parameters:

Name Type Description Default
T Type[B]

Destination type to convert into.

required

Returns:

Type Description
B

Converted object produced by the registered conversion function.

Raises:

Type Description
NotImplementedError

If no conversion function has been registered for (type(self), T) or any source supertype via add_conversion().

Source code in src/qten/abstracts.py
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
@final
def convert(self, T: Type[B]) -> B:
    """
    Convert this instance to the requested target type.

    Parameters
    ----------
    T : Type[B]
        Destination type to convert into.

    Returns
    -------
    B
        Converted object produced by the registered conversion function.

    Raises
    ------
    NotImplementedError
        If no conversion function has been registered for
        `(type(self), T)` or any source supertype via
        [`add_conversion()`][qten.abstracts.Convertible.add_conversion].
    """
    source_type = type(self)
    table_get = _type_conversion_table.get

    convertor = table_get((source_type, T))
    if convertor is None:
        for super_type in source_type.__mro__[1:]:
            convertor = table_get((super_type, T))
            if convertor is not None:
                # Cache resolved parent conversion under the concrete source type.
                _type_conversion_table[(source_type, T)] = convertor
                break

    if convertor is None:
        raise NotImplementedError(
            f"No conversion from {source_type.__name__} to {T.__name__}!"
        )
    return cast(Callable[["Convertible"], B], convertor)(self)

__len__

__len__() -> int

Return the number of spatial elements.

Source code in src/qten/symbolics/state_space.py
88
89
90
def __len__(self) -> int:
    """Return the number of spatial elements."""
    return len(self.structure)

__iter__

__iter__() -> Iterator[T]

Iterate over spatial elements.

Source code in src/qten/symbolics/state_space.py
92
93
94
def __iter__(self) -> Iterator[T]:
    """Iterate over spatial elements."""
    return iter(self.structure.keys())

__getitem__

__getitem__(v: int) -> T
__getitem__(v: slice | range) -> Self
__getitem__(v: Sequence[int]) -> Self

Index into the state-space by element position.

Supported forms

space[i] returns a single spatial element by position, including negative indices. space[start:stop:step] returns a new space with the selected elements in slice order. space[range(...)] returns a new space with the range-selected elements. space[[i, j, ...]] returns a new space with elements in explicit index order.

Parameters:

Name Type Description Default
key Union[int, slice, range, Sequence[int]]

Index selector. Sequences must contain unique integers; negative integers are normalized relative to len(self).

required

Returns:

Type Description
Spatial or StateSpace

A spatial element for int indexing, otherwise a new instance of the same class containing the selected elements. Any extra dataclass fields on subclasses are preserved in the returned instance.

Raises:

Type Description
IndexError

If an integer index is out of bounds.

TypeError

If key is not an int, slice, range, or sequence of integers.

ValueError

If a sequence selector contains duplicate indices.

Source code in src/qten/symbolics/state_space.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def __getitem__(
    self, key: Union[int, slice, range, Sequence[int]]
) -> Union[T, "StateSpace[T]"]:
    """
    Index into the state-space by element position.

    Supported forms
    ---------------
    `space[i]` returns a single spatial element by position, including
    negative indices. `space[start:stop:step]` returns a new space with the
    selected elements in slice order. `space[range(...)]` returns a new
    space with the range-selected elements. `space[[i, j, ...]]` returns a
    new space with elements in explicit index order.

    Parameters
    ----------
    key : Union[int, slice, range, Sequence[int]]
        Index selector. Sequences must contain unique integers; negative
        integers are normalized relative to `len(self)`.

    Returns
    -------
    Spatial or StateSpace
        A spatial element for `int` indexing, otherwise a new instance of the
        same class containing the selected elements. Any extra dataclass fields
        on subclasses are preserved in the returned instance.

    Raises
    ------
    IndexError
        If an integer index is out of bounds.
    TypeError
        If `key` is not an `int`, `slice`, `range`, or sequence of integers.
    ValueError
        If a sequence selector contains duplicate indices.
    """
    if isinstance(key, int):
        if key < 0:
            key += len(self.structure)
        if key < 0 or key >= len(self.structure):
            raise IndexError("StateSpace index out of range")
        return next(islice(self.structure.keys(), key, None))
    if isinstance(key, slice):
        keys = tuple(self.structure.keys())[key]
        new_structure = OrderedDict((k, self.structure[k]) for k in keys)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, range):
        keys = tuple(self.structure.keys())
        new_structure = OrderedDict((keys[i], self.structure[keys[i]]) for i in key)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, Sequence) and not isinstance(key, (str, bytes)):
        keys = tuple(self.structure.keys())
        indices: list[int] = []
        seen = set()
        for idx in key:
            if isinstance(idx, bool) or not isinstance(idx, int):
                raise TypeError(
                    "StateSpace sequence indices must contain only integers"
                )
            normalized = idx
            if normalized < 0:
                normalized += len(keys)
            if normalized < 0 or normalized >= len(keys):
                raise IndexError("StateSpace index out of range")
            if normalized in seen:
                raise ValueError("StateSpace sequence indices must be unique")
            seen.add(normalized)
            indices.append(normalized)
        new_structure = OrderedDict(
            (keys[i], self.structure[keys[i]]) for i in indices
        )
        return replace(self, structure=restructure(new_structure))
    raise TypeError(
        "StateSpace indices must be int, slice, range, or a sequence of ints, "
        f"not {type(key)}"
    )

same_rays

same_rays(other: StateSpace) -> bool

Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

Parameters:

Name Type Description Default
other StateSpace

The other state space to compare against.

required

Returns:

Type Description
bool

True if both state spaces have the same rays, False otherwise.

Source code in src/qten/symbolics/state_space.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def same_rays(self, other: "StateSpace") -> bool:
    """
    Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

    Parameters
    ----------
    other : StateSpace
        The other state space to compare against.

    Returns
    -------
    bool
        True if both state spaces have the same rays, `False` otherwise.
    """
    return same_rays(self, other)

map

map(func: Callable[[T], T]) -> Self

Map the spatial elements of this state space using a provided function.

Parameters:

Name Type Description Default
func Callable[[T], T]

A function that takes a spatial element and returns a transformed spatial element.

required

Returns:

Type Description
Self

A new state space with the transformed spatial elements.

Source code in src/qten/symbolics/state_space.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
def map(self, func: Callable[[T], T]) -> "Self":
    """
    Map the spatial elements of this state space using a provided function.

    Parameters
    ----------
    func : Callable[[T], T]
        A function that takes a spatial element and returns a transformed spatial element.

    Returns
    -------
    Self
        A new state space with the transformed spatial elements.
    """
    new_structure = OrderedDict()
    for k, s in self.structure.items():
        new_k = func(k)
        new_structure[new_k] = s
    return replace(self, structure=restructure(new_structure))

filter

filter(pred: Callable[[T], bool]) -> Self

Return the subspace containing elements where pred(element) is True.

Parameters:

Name Type Description Default
pred Callable[[T], bool]

Predicate applied to each element in basis order.

required

Returns:

Type Description
Self

A new state space of the same concrete type containing only the selected elements, with indices repacked contiguously.

Source code in src/qten/symbolics/state_space.py
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
def filter(self, pred: Callable[[T], bool]) -> "Self":
    """
    Return the subspace containing elements where `pred(element)` is `True`.

    Parameters
    ----------
    pred : Callable[[T], bool]
        Predicate applied to each element in basis order.

    Returns
    -------
    Self
        A new state space of the same concrete type containing only the
        selected elements, with indices repacked contiguously.
    """
    new_structure = OrderedDict(
        (k, s) for k, s in self.structure.items() if pred(k)
    )
    return replace(self, structure=restructure(new_structure))

tensor_product

tensor_product(other: Self) -> Self

Return the tensor-product state space of this space and another space.

This method defines the protocol used by the @ operator on StateSpace instances. The base class cannot construct a generic product because it does not know how to combine two elements of type T. Concrete subclasses must implement the element-level product and rebuild a contiguous structure for the resulting basis.

Implementations should preserve deterministic product ordering. The convention used by concrete tensor-product spaces in QTen is the Cartesian product order of self.elements() and other.elements(), where elements from self vary slowest and elements from other vary fastest. The returned space should be the same concrete state-space family when the operation is closed over that family.

Parameters:

Name Type Description Default
other StateSpace

Right-hand tensor factor. Implementations may require other to be the same concrete state-space type as self.

required

Returns:

Type Description
StateSpace

New state space representing self ⊗ other, with contiguous integer indices in the implementation-defined product order.

Raises:

Type Description
NotImplementedError

Always raised by the base class. Subclasses that support tensor products must override this method.

Source code in src/qten/symbolics/state_space.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def tensor_product(self, other: Self) -> Self:
    """
    Return the tensor-product state space of this space and another space.

    This method defines the protocol used by the `@` operator on
    [`StateSpace`][qten.symbolics.state_space.StateSpace] instances. The
    base class cannot construct a generic product because it does not know
    how to combine two elements of type `T`. Concrete subclasses must
    implement the element-level product and rebuild a contiguous
    `structure` for the resulting basis.

    Implementations should preserve deterministic product ordering. The
    convention used by concrete tensor-product spaces in QTen is the
    Cartesian product order of `self.elements()` and `other.elements()`,
    where elements from `self` vary slowest and elements from `other` vary
    fastest. The returned space should be the same concrete state-space
    family when the operation is closed over that family.

    Parameters
    ----------
    other : StateSpace
        Right-hand tensor factor. Implementations may require `other` to be
        the same concrete state-space type as `self`.

    Returns
    -------
    StateSpace
        New state space representing `self ⊗ other`, with contiguous
        integer indices in the implementation-defined product order.

    Raises
    ------
    NotImplementedError
        Always raised by the base class. Subclasses that support tensor
        products must override this method.
    """
    raise NotImplementedError(f"Tensor product not implemented for {type(self)}!")

extract

extract(info_type: type[Any]) -> Any

Extract an object implied by the elements of this state space.

Subclasses may register specialized implementations for supported target types.

Parameters:

Name Type Description Default
info_type type[Any]

Type of metadata or object to extract from this state space.

required

Returns:

Type Description
Any

Extracted object produced by a registered specialization.

Raises:

Type Description
NotImplementedError

If no extraction rule is registered for info_type.

Source code in src/qten/symbolics/state_space.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
@multimethod
def extract(self, info_type: type[Any]) -> Any:
    """
    Extract an object implied by the elements of this state space.

    Subclasses may register specialized implementations for supported
    target types.

    Parameters
    ----------
    info_type : type[Any]
        Type of metadata or object to extract from this state space.

    Returns
    -------
    Any
        Extracted object produced by a registered specialization.

    Raises
    ------
    NotImplementedError
        If no extraction rule is registered for `info_type`.
    """
    raise NotImplementedError(
        f"Extraction of {info_type} from {type(self)} is not supported!"
    )

__hash__

__hash__() -> int

Return a hash for the singleton broadcast-axis structure.

BroadcastSpace hashes the same ordered structure snapshot as StateSpace. Because the structure always contains one private _BAxis marker at index 0, the hash represents this singleton broadcast dimension rather than a physical basis element.

Returns:

Type Description
int

Hash value for the ordered singleton (_BAxis(), 0) mapping.

Source code in src/qten/symbolics/state_space.py
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
def __hash__(self) -> int:
    """
    Return a hash for the singleton broadcast-axis structure.

    [`BroadcastSpace`][qten.symbolics.state_space.BroadcastSpace] hashes the
    same ordered structure snapshot as
    [`StateSpace`][qten.symbolics.state_space.StateSpace]. Because the
    structure always contains one private `_BAxis` marker at index `0`, the
    hash represents this singleton broadcast dimension rather than a
    physical basis element.

    Returns
    -------
    int
        Hash value for the ordered singleton `(_BAxis(), 0)` mapping.
    """
    return StateSpace.__hash__(self)

__repr__

__repr__()

Return the broadcast-axis marker representation.

Returns:

Type Description
str

The literal string "BroadcastSpace".

Source code in src/qten/symbolics/state_space.py
771
772
773
774
775
776
777
778
779
780
def __repr__(self):
    """
    Return the broadcast-axis marker representation.

    Returns
    -------
    str
        The literal string `"BroadcastSpace"`.
    """
    return "BroadcastSpace"

IndexSpace dataclass

IndexSpace(structure: OrderedDict[T, int])

Bases: StateSpace[int]

A simple state space where the spatial elements are just integer indices. This can be useful for representing generic tensor dimensions that don't have a specific physical interpretation, such as the virtual bond dimension in a TNS.

dim property

dim: int

The total size of the vector space.

structure instance-attribute

structure: OrderedDict[T, int]

An ordered dictionary mapping each spatial component (e.g., Offset, Momentum) to its single flattened index.

register_plot_method classmethod

register_plot_method(name: str, backend: str = 'plotly')

Register a backend plotting function for this plottable class.

The returned decorator stores the function in the global plotting registry. Registered functions receive the object being plotted as their first argument, followed by any extra positional and keyword arguments supplied to plot().

Parameters:

Name Type Description Default
name str

User-facing plot method name, such as scatter, structure, or heatmap.

required
backend str

Backend name that selects the implementation. The qten-plots extension currently uses plotly and matplotlib.

'plotly'

Returns:

Type Description
Callable

Decorator that registers the provided plotting function and returns it unchanged.

Source code in src/qten/plottings/_plottings.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@classmethod
def register_plot_method(cls, name: str, backend: str = "plotly"):
    """
    Register a backend plotting function for this plottable class.

    The returned decorator stores the function in the global plotting
    registry. Registered functions receive the object being plotted as their
    first argument, followed by any extra positional and keyword arguments
    supplied to [`plot()`][qten.plottings.Plottable.plot].

    Parameters
    ----------
    name : str
        User-facing plot method name, such as `scatter`, `structure`, or
        `heatmap`.
    backend : str
        Backend name that selects the implementation. The `qten-plots`
        extension currently uses `plotly` and `matplotlib`.

    Returns
    -------
    Callable
        Decorator that registers the provided plotting function and returns
        it unchanged.
    """

    def decorator(func: Callable):
        # We register against 'cls' - the class this method was called on.
        Plottable._registry[(cls, name, backend)] = func
        return func

    return decorator

plot

plot(method: str, backend: str = 'plotly', *args, **kwargs)

Dispatch a named plot method to a registered backend implementation.

The dispatcher first loads plotting entry points, then searches the instance type and its base classes for a matching (type, method, backend) registration. Additional arguments are forwarded unchanged to the selected backend function.

Parameters:

Name Type Description Default
method str

Plot method name registered for this object's type.

required
backend str

Backend implementation to use. The qten-plots extension currently registers plotly and matplotlib.

'plotly'
args

Positional arguments forwarded to the registered plotting function.

()
kwargs

Keyword arguments forwarded to the registered plotting function.

{}

Returns:

Type Description
object

Backend-specific figure object returned by the registered plotting function, such as a Plotly or Matplotlib figure.

Raises:

Type Description
ValueError

If no plotting function is registered for the requested method and backend on this object.

See Also

qten_plots.plottables.PointCloud Public plottable helper object provided by the plotting extension.

Source code in src/qten/plottings/_plottings.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def plot(self, method: str, backend: str = "plotly", *args, **kwargs):
    """
    Dispatch a named plot method to a registered backend implementation.

    The dispatcher first loads plotting entry points, then searches the
    instance type and its base classes for a matching `(type, method,
    backend)` registration. Additional arguments are forwarded unchanged to
    the selected backend function.

    Parameters
    ----------
    method : str
        Plot method name registered for this object's type.
    backend : str
        Backend implementation to use. The `qten-plots` extension currently
        registers `plotly` and `matplotlib`.
    args
        Positional arguments forwarded to the registered plotting function.
    kwargs
        Keyword arguments forwarded to the registered plotting function.

    Returns
    -------
    object
        Backend-specific figure object returned by the registered plotting
        function, such as a Plotly or Matplotlib figure.

    Raises
    ------
    ValueError
        If no plotting function is registered for the requested method and
        backend on this object.

    See Also
    --------
    qten_plots.plottables.PointCloud
        Public plottable helper object provided by the plotting extension.
    """
    Plottable._ensure_backends_loaded()

    # Iterate over the MRO (Method Resolution Order) of the instance
    for class_in_hierarchy in type(self).__mro__:
        key = (class_in_hierarchy, method, backend)

        # Check the central registry
        if key in Plottable._registry:
            plot_func = Plottable._registry[key]
            return plot_func(self, *args, **kwargs)

    # If we reach here, no method was found. Provide a helpful error.
    self._raise_method_not_found(method, backend)

elements

elements() -> tuple[T, ...]

Return the spatial elements as a tuple.

Source code in src/qten/symbolics/state_space.py
83
84
85
86
@override
def elements(self) -> Tuple[T, ...]:
    """Return the spatial elements as a tuple."""
    return tuple(self.structure.keys())

add_conversion classmethod

add_conversion(
    T: type[B],
) -> Callable[[Callable[[A], B]], Callable[[A], B]]

Register a conversion from cls to T.

The decorated function is stored under (cls, T). When an instance of cls later calls convert(T), that function is used to produce the converted object.

Parameters:

Name Type Description Default
T Type[B]

Destination type produced by the registered conversion function.

required

Returns:

Type Description
Callable[[Callable[[A], B]], Callable[[A], B]]

Decorator that stores the conversion function and returns it unchanged.

Examples:

@MyType.add_conversion(TargetType)
def to_target(x: MyType) -> TargetType:
    ...
Source code in src/qten/abstracts.py
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
@classmethod
def add_conversion(
    cls: Type[A], T: Type[B]
) -> Callable[[Callable[[A], B]], Callable[[A], B]]:
    """
    Register a conversion from `cls` to `T`.

    The decorated function is stored under `(cls, T)`. When an instance of
    `cls` later calls [`convert(T)`][qten.abstracts.Convertible.convert],
    that function is used to produce the converted object.

    Parameters
    ----------
    T : Type[B]
        Destination type produced by the registered conversion function.

    Returns
    -------
    Callable[[Callable[[A], B]], Callable[[A], B]]
        Decorator that stores the conversion function and returns it
        unchanged.

    Examples
    --------
    ```python
    @MyType.add_conversion(TargetType)
    def to_target(x: MyType) -> TargetType:
        ...
    ```
    """

    def decorator(func: Callable[[A], B]) -> Callable[[A], B]:
        _type_conversion_table[(cls, T)] = cast(Callable[[Any], Any], func)
        return func

    return decorator

convert

convert(T: type[B]) -> B

Convert this instance to the requested target type.

Parameters:

Name Type Description Default
T Type[B]

Destination type to convert into.

required

Returns:

Type Description
B

Converted object produced by the registered conversion function.

Raises:

Type Description
NotImplementedError

If no conversion function has been registered for (type(self), T) or any source supertype via add_conversion().

Source code in src/qten/abstracts.py
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
@final
def convert(self, T: Type[B]) -> B:
    """
    Convert this instance to the requested target type.

    Parameters
    ----------
    T : Type[B]
        Destination type to convert into.

    Returns
    -------
    B
        Converted object produced by the registered conversion function.

    Raises
    ------
    NotImplementedError
        If no conversion function has been registered for
        `(type(self), T)` or any source supertype via
        [`add_conversion()`][qten.abstracts.Convertible.add_conversion].
    """
    source_type = type(self)
    table_get = _type_conversion_table.get

    convertor = table_get((source_type, T))
    if convertor is None:
        for super_type in source_type.__mro__[1:]:
            convertor = table_get((super_type, T))
            if convertor is not None:
                # Cache resolved parent conversion under the concrete source type.
                _type_conversion_table[(source_type, T)] = convertor
                break

    if convertor is None:
        raise NotImplementedError(
            f"No conversion from {source_type.__name__} to {T.__name__}!"
        )
    return cast(Callable[["Convertible"], B], convertor)(self)

__len__

__len__() -> int

Return the number of spatial elements.

Source code in src/qten/symbolics/state_space.py
88
89
90
def __len__(self) -> int:
    """Return the number of spatial elements."""
    return len(self.structure)

__iter__

__iter__() -> Iterator[T]

Iterate over spatial elements.

Source code in src/qten/symbolics/state_space.py
92
93
94
def __iter__(self) -> Iterator[T]:
    """Iterate over spatial elements."""
    return iter(self.structure.keys())

__getitem__

__getitem__(v: int) -> T
__getitem__(v: slice | range) -> Self
__getitem__(v: Sequence[int]) -> Self

Index into the state-space by element position.

Supported forms

space[i] returns a single spatial element by position, including negative indices. space[start:stop:step] returns a new space with the selected elements in slice order. space[range(...)] returns a new space with the range-selected elements. space[[i, j, ...]] returns a new space with elements in explicit index order.

Parameters:

Name Type Description Default
key Union[int, slice, range, Sequence[int]]

Index selector. Sequences must contain unique integers; negative integers are normalized relative to len(self).

required

Returns:

Type Description
Spatial or StateSpace

A spatial element for int indexing, otherwise a new instance of the same class containing the selected elements. Any extra dataclass fields on subclasses are preserved in the returned instance.

Raises:

Type Description
IndexError

If an integer index is out of bounds.

TypeError

If key is not an int, slice, range, or sequence of integers.

ValueError

If a sequence selector contains duplicate indices.

Source code in src/qten/symbolics/state_space.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def __getitem__(
    self, key: Union[int, slice, range, Sequence[int]]
) -> Union[T, "StateSpace[T]"]:
    """
    Index into the state-space by element position.

    Supported forms
    ---------------
    `space[i]` returns a single spatial element by position, including
    negative indices. `space[start:stop:step]` returns a new space with the
    selected elements in slice order. `space[range(...)]` returns a new
    space with the range-selected elements. `space[[i, j, ...]]` returns a
    new space with elements in explicit index order.

    Parameters
    ----------
    key : Union[int, slice, range, Sequence[int]]
        Index selector. Sequences must contain unique integers; negative
        integers are normalized relative to `len(self)`.

    Returns
    -------
    Spatial or StateSpace
        A spatial element for `int` indexing, otherwise a new instance of the
        same class containing the selected elements. Any extra dataclass fields
        on subclasses are preserved in the returned instance.

    Raises
    ------
    IndexError
        If an integer index is out of bounds.
    TypeError
        If `key` is not an `int`, `slice`, `range`, or sequence of integers.
    ValueError
        If a sequence selector contains duplicate indices.
    """
    if isinstance(key, int):
        if key < 0:
            key += len(self.structure)
        if key < 0 or key >= len(self.structure):
            raise IndexError("StateSpace index out of range")
        return next(islice(self.structure.keys(), key, None))
    if isinstance(key, slice):
        keys = tuple(self.structure.keys())[key]
        new_structure = OrderedDict((k, self.structure[k]) for k in keys)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, range):
        keys = tuple(self.structure.keys())
        new_structure = OrderedDict((keys[i], self.structure[keys[i]]) for i in key)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, Sequence) and not isinstance(key, (str, bytes)):
        keys = tuple(self.structure.keys())
        indices: list[int] = []
        seen = set()
        for idx in key:
            if isinstance(idx, bool) or not isinstance(idx, int):
                raise TypeError(
                    "StateSpace sequence indices must contain only integers"
                )
            normalized = idx
            if normalized < 0:
                normalized += len(keys)
            if normalized < 0 or normalized >= len(keys):
                raise IndexError("StateSpace index out of range")
            if normalized in seen:
                raise ValueError("StateSpace sequence indices must be unique")
            seen.add(normalized)
            indices.append(normalized)
        new_structure = OrderedDict(
            (keys[i], self.structure[keys[i]]) for i in indices
        )
        return replace(self, structure=restructure(new_structure))
    raise TypeError(
        "StateSpace indices must be int, slice, range, or a sequence of ints, "
        f"not {type(key)}"
    )

same_rays

same_rays(other: StateSpace) -> bool

Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

Parameters:

Name Type Description Default
other StateSpace

The other state space to compare against.

required

Returns:

Type Description
bool

True if both state spaces have the same rays, False otherwise.

Source code in src/qten/symbolics/state_space.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def same_rays(self, other: "StateSpace") -> bool:
    """
    Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

    Parameters
    ----------
    other : StateSpace
        The other state space to compare against.

    Returns
    -------
    bool
        True if both state spaces have the same rays, `False` otherwise.
    """
    return same_rays(self, other)

map

map(func: Callable[[T], T]) -> Self

Map the spatial elements of this state space using a provided function.

Parameters:

Name Type Description Default
func Callable[[T], T]

A function that takes a spatial element and returns a transformed spatial element.

required

Returns:

Type Description
Self

A new state space with the transformed spatial elements.

Source code in src/qten/symbolics/state_space.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
def map(self, func: Callable[[T], T]) -> "Self":
    """
    Map the spatial elements of this state space using a provided function.

    Parameters
    ----------
    func : Callable[[T], T]
        A function that takes a spatial element and returns a transformed spatial element.

    Returns
    -------
    Self
        A new state space with the transformed spatial elements.
    """
    new_structure = OrderedDict()
    for k, s in self.structure.items():
        new_k = func(k)
        new_structure[new_k] = s
    return replace(self, structure=restructure(new_structure))

filter

filter(pred: Callable[[T], bool]) -> Self

Return the subspace containing elements where pred(element) is True.

Parameters:

Name Type Description Default
pred Callable[[T], bool]

Predicate applied to each element in basis order.

required

Returns:

Type Description
Self

A new state space of the same concrete type containing only the selected elements, with indices repacked contiguously.

Source code in src/qten/symbolics/state_space.py
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
def filter(self, pred: Callable[[T], bool]) -> "Self":
    """
    Return the subspace containing elements where `pred(element)` is `True`.

    Parameters
    ----------
    pred : Callable[[T], bool]
        Predicate applied to each element in basis order.

    Returns
    -------
    Self
        A new state space of the same concrete type containing only the
        selected elements, with indices repacked contiguously.
    """
    new_structure = OrderedDict(
        (k, s) for k, s in self.structure.items() if pred(k)
    )
    return replace(self, structure=restructure(new_structure))

tensor_product

tensor_product(other: Self) -> Self

Return the tensor-product state space of this space and another space.

This method defines the protocol used by the @ operator on StateSpace instances. The base class cannot construct a generic product because it does not know how to combine two elements of type T. Concrete subclasses must implement the element-level product and rebuild a contiguous structure for the resulting basis.

Implementations should preserve deterministic product ordering. The convention used by concrete tensor-product spaces in QTen is the Cartesian product order of self.elements() and other.elements(), where elements from self vary slowest and elements from other vary fastest. The returned space should be the same concrete state-space family when the operation is closed over that family.

Parameters:

Name Type Description Default
other StateSpace

Right-hand tensor factor. Implementations may require other to be the same concrete state-space type as self.

required

Returns:

Type Description
StateSpace

New state space representing self ⊗ other, with contiguous integer indices in the implementation-defined product order.

Raises:

Type Description
NotImplementedError

Always raised by the base class. Subclasses that support tensor products must override this method.

Source code in src/qten/symbolics/state_space.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def tensor_product(self, other: Self) -> Self:
    """
    Return the tensor-product state space of this space and another space.

    This method defines the protocol used by the `@` operator on
    [`StateSpace`][qten.symbolics.state_space.StateSpace] instances. The
    base class cannot construct a generic product because it does not know
    how to combine two elements of type `T`. Concrete subclasses must
    implement the element-level product and rebuild a contiguous
    `structure` for the resulting basis.

    Implementations should preserve deterministic product ordering. The
    convention used by concrete tensor-product spaces in QTen is the
    Cartesian product order of `self.elements()` and `other.elements()`,
    where elements from `self` vary slowest and elements from `other` vary
    fastest. The returned space should be the same concrete state-space
    family when the operation is closed over that family.

    Parameters
    ----------
    other : StateSpace
        Right-hand tensor factor. Implementations may require `other` to be
        the same concrete state-space type as `self`.

    Returns
    -------
    StateSpace
        New state space representing `self ⊗ other`, with contiguous
        integer indices in the implementation-defined product order.

    Raises
    ------
    NotImplementedError
        Always raised by the base class. Subclasses that support tensor
        products must override this method.
    """
    raise NotImplementedError(f"Tensor product not implemented for {type(self)}!")

extract

extract(info_type: type[Any]) -> Any

Extract an object implied by the elements of this state space.

Subclasses may register specialized implementations for supported target types.

Parameters:

Name Type Description Default
info_type type[Any]

Type of metadata or object to extract from this state space.

required

Returns:

Type Description
Any

Extracted object produced by a registered specialization.

Raises:

Type Description
NotImplementedError

If no extraction rule is registered for info_type.

Source code in src/qten/symbolics/state_space.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
@multimethod
def extract(self, info_type: type[Any]) -> Any:
    """
    Extract an object implied by the elements of this state space.

    Subclasses may register specialized implementations for supported
    target types.

    Parameters
    ----------
    info_type : type[Any]
        Type of metadata or object to extract from this state space.

    Returns
    -------
    Any
        Extracted object produced by a registered specialization.

    Raises
    ------
    NotImplementedError
        If no extraction rule is registered for `info_type`.
    """
    raise NotImplementedError(
        f"Extraction of {info_type} from {type(self)} is not supported!"
    )

__hash__

__hash__() -> int

Return a hash derived from the ordered integer-index structure.

IndexSpace uses the same structure-based hash as StateSpace. The hash includes each integer element and its stored basis index in order. For spaces produced by linear(size), this is the hash of the canonical mapping 0 -> 0, 1 -> 1, and so on.

Returns:

Type Description
int

Hash value for the ordered (int, index) mapping.

Source code in src/qten/symbolics/state_space.py
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
def __hash__(self) -> int:
    """
    Return a hash derived from the ordered integer-index structure.

    [`IndexSpace`][qten.symbolics.state_space.IndexSpace] uses the same
    structure-based hash as
    [`StateSpace`][qten.symbolics.state_space.StateSpace]. The hash includes
    each integer element and its stored basis index in order. For spaces
    produced by [`linear(size)`][qten.symbolics.state_space.IndexSpace.linear],
    this is the hash of the canonical mapping `0 -> 0`, `1 -> 1`, and so on.

    Returns
    -------
    int
        Hash value for the ordered `(int, index)` mapping.
    """
    return StateSpace.__hash__(self)

linear staticmethod

linear(size: int) -> IndexSpace

Build a contiguous index space of length size.

The resulting space contains integer keys 0..size-1, each mapped to the same integer index.

Parameters:

Name Type Description Default
size int

Number of indices in the space.

required

Returns:

Type Description
IndexSpace

A contiguous IndexSpace with canonical linear ordering.

Raises:

Type Description
ValueError

If size is negative.

Source code in src/qten/symbolics/state_space.py
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
@staticmethod
def linear(size: int) -> "IndexSpace":
    """
    Build a contiguous index space of length [`size`][qten.geometries.spatials.ReciprocalLattice.size].

    The resulting space contains integer keys `0..size-1`, each mapped to
    the same integer index.

    Parameters
    ----------
    size : int
        Number of indices in the space.

    Returns
    -------
    IndexSpace
        A contiguous [`IndexSpace`][qten.symbolics.state_space.IndexSpace] with canonical linear ordering.

    Raises
    ------
    ValueError
        If [`size`][qten.geometries.spatials.ReciprocalLattice.size] is negative.
    """
    if size < 0:
        raise ValueError("IndexSpace size must be non-negative.")
    return IndexSpace(OrderedDict((i, i) for i in range(size)))

__str__

__str__()

Return a compact index-space summary.

Returns:

Type Description
str

Summary containing the index-space size.

Source code in src/qten/symbolics/state_space.py
870
871
872
873
874
875
876
877
878
879
def __str__(self):
    """
    Return a compact index-space summary.

    Returns
    -------
    str
        Summary containing the index-space size.
    """
    return f"IndexSpace(size={self.dim})"

__repr__

__repr__()

Return the developer representation of this index space.

Returns:

Type Description
str

Same value as str(self).

Source code in src/qten/symbolics/state_space.py
881
882
883
884
885
886
887
888
889
890
def __repr__(self):
    """
    Return the developer representation of this index space.

    Returns
    -------
    str
        Same value as `str(self)`.
    """
    return str(self)

MomentumSpace dataclass

MomentumSpace(structure: OrderedDict[T, int])

Bases: StateSpace[Momentum]

Ordered state space of momentum points over one reciprocal lattice.

MomentumSpace is the reciprocal-space specialization of StateSpace. Its structure keys are Momentum objects and its values are the corresponding integer basis indices.

Notes

The class inherits the custom hashing behavior from StateSpace so instances remain hashable despite storing an OrderedDict.

dim property

dim: int

The total size of the vector space.

structure instance-attribute

structure: OrderedDict[T, int]

An ordered dictionary mapping each spatial component (e.g., Offset, Momentum) to its single flattened index.

register_plot_method classmethod

register_plot_method(name: str, backend: str = 'plotly')

Register a backend plotting function for this plottable class.

The returned decorator stores the function in the global plotting registry. Registered functions receive the object being plotted as their first argument, followed by any extra positional and keyword arguments supplied to plot().

Parameters:

Name Type Description Default
name str

User-facing plot method name, such as scatter, structure, or heatmap.

required
backend str

Backend name that selects the implementation. The qten-plots extension currently uses plotly and matplotlib.

'plotly'

Returns:

Type Description
Callable

Decorator that registers the provided plotting function and returns it unchanged.

Source code in src/qten/plottings/_plottings.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@classmethod
def register_plot_method(cls, name: str, backend: str = "plotly"):
    """
    Register a backend plotting function for this plottable class.

    The returned decorator stores the function in the global plotting
    registry. Registered functions receive the object being plotted as their
    first argument, followed by any extra positional and keyword arguments
    supplied to [`plot()`][qten.plottings.Plottable.plot].

    Parameters
    ----------
    name : str
        User-facing plot method name, such as `scatter`, `structure`, or
        `heatmap`.
    backend : str
        Backend name that selects the implementation. The `qten-plots`
        extension currently uses `plotly` and `matplotlib`.

    Returns
    -------
    Callable
        Decorator that registers the provided plotting function and returns
        it unchanged.
    """

    def decorator(func: Callable):
        # We register against 'cls' - the class this method was called on.
        Plottable._registry[(cls, name, backend)] = func
        return func

    return decorator

plot

plot(method: str, backend: str = 'plotly', *args, **kwargs)

Dispatch a named plot method to a registered backend implementation.

The dispatcher first loads plotting entry points, then searches the instance type and its base classes for a matching (type, method, backend) registration. Additional arguments are forwarded unchanged to the selected backend function.

Parameters:

Name Type Description Default
method str

Plot method name registered for this object's type.

required
backend str

Backend implementation to use. The qten-plots extension currently registers plotly and matplotlib.

'plotly'
args

Positional arguments forwarded to the registered plotting function.

()
kwargs

Keyword arguments forwarded to the registered plotting function.

{}

Returns:

Type Description
object

Backend-specific figure object returned by the registered plotting function, such as a Plotly or Matplotlib figure.

Raises:

Type Description
ValueError

If no plotting function is registered for the requested method and backend on this object.

See Also

qten_plots.plottables.PointCloud Public plottable helper object provided by the plotting extension.

Source code in src/qten/plottings/_plottings.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def plot(self, method: str, backend: str = "plotly", *args, **kwargs):
    """
    Dispatch a named plot method to a registered backend implementation.

    The dispatcher first loads plotting entry points, then searches the
    instance type and its base classes for a matching `(type, method,
    backend)` registration. Additional arguments are forwarded unchanged to
    the selected backend function.

    Parameters
    ----------
    method : str
        Plot method name registered for this object's type.
    backend : str
        Backend implementation to use. The `qten-plots` extension currently
        registers `plotly` and `matplotlib`.
    args
        Positional arguments forwarded to the registered plotting function.
    kwargs
        Keyword arguments forwarded to the registered plotting function.

    Returns
    -------
    object
        Backend-specific figure object returned by the registered plotting
        function, such as a Plotly or Matplotlib figure.

    Raises
    ------
    ValueError
        If no plotting function is registered for the requested method and
        backend on this object.

    See Also
    --------
    qten_plots.plottables.PointCloud
        Public plottable helper object provided by the plotting extension.
    """
    Plottable._ensure_backends_loaded()

    # Iterate over the MRO (Method Resolution Order) of the instance
    for class_in_hierarchy in type(self).__mro__:
        key = (class_in_hierarchy, method, backend)

        # Check the central registry
        if key in Plottable._registry:
            plot_func = Plottable._registry[key]
            return plot_func(self, *args, **kwargs)

    # If we reach here, no method was found. Provide a helpful error.
    self._raise_method_not_found(method, backend)

elements

elements() -> tuple[T, ...]

Return the spatial elements as a tuple.

Source code in src/qten/symbolics/state_space.py
83
84
85
86
@override
def elements(self) -> Tuple[T, ...]:
    """Return the spatial elements as a tuple."""
    return tuple(self.structure.keys())

add_conversion classmethod

add_conversion(
    T: type[B],
) -> Callable[[Callable[[A], B]], Callable[[A], B]]

Register a conversion from cls to T.

The decorated function is stored under (cls, T). When an instance of cls later calls convert(T), that function is used to produce the converted object.

Parameters:

Name Type Description Default
T Type[B]

Destination type produced by the registered conversion function.

required

Returns:

Type Description
Callable[[Callable[[A], B]], Callable[[A], B]]

Decorator that stores the conversion function and returns it unchanged.

Examples:

@MyType.add_conversion(TargetType)
def to_target(x: MyType) -> TargetType:
    ...
Source code in src/qten/abstracts.py
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
@classmethod
def add_conversion(
    cls: Type[A], T: Type[B]
) -> Callable[[Callable[[A], B]], Callable[[A], B]]:
    """
    Register a conversion from `cls` to `T`.

    The decorated function is stored under `(cls, T)`. When an instance of
    `cls` later calls [`convert(T)`][qten.abstracts.Convertible.convert],
    that function is used to produce the converted object.

    Parameters
    ----------
    T : Type[B]
        Destination type produced by the registered conversion function.

    Returns
    -------
    Callable[[Callable[[A], B]], Callable[[A], B]]
        Decorator that stores the conversion function and returns it
        unchanged.

    Examples
    --------
    ```python
    @MyType.add_conversion(TargetType)
    def to_target(x: MyType) -> TargetType:
        ...
    ```
    """

    def decorator(func: Callable[[A], B]) -> Callable[[A], B]:
        _type_conversion_table[(cls, T)] = cast(Callable[[Any], Any], func)
        return func

    return decorator

convert

convert(T: type[B]) -> B

Convert this instance to the requested target type.

Parameters:

Name Type Description Default
T Type[B]

Destination type to convert into.

required

Returns:

Type Description
B

Converted object produced by the registered conversion function.

Raises:

Type Description
NotImplementedError

If no conversion function has been registered for (type(self), T) or any source supertype via add_conversion().

Source code in src/qten/abstracts.py
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
@final
def convert(self, T: Type[B]) -> B:
    """
    Convert this instance to the requested target type.

    Parameters
    ----------
    T : Type[B]
        Destination type to convert into.

    Returns
    -------
    B
        Converted object produced by the registered conversion function.

    Raises
    ------
    NotImplementedError
        If no conversion function has been registered for
        `(type(self), T)` or any source supertype via
        [`add_conversion()`][qten.abstracts.Convertible.add_conversion].
    """
    source_type = type(self)
    table_get = _type_conversion_table.get

    convertor = table_get((source_type, T))
    if convertor is None:
        for super_type in source_type.__mro__[1:]:
            convertor = table_get((super_type, T))
            if convertor is not None:
                # Cache resolved parent conversion under the concrete source type.
                _type_conversion_table[(source_type, T)] = convertor
                break

    if convertor is None:
        raise NotImplementedError(
            f"No conversion from {source_type.__name__} to {T.__name__}!"
        )
    return cast(Callable[["Convertible"], B], convertor)(self)

__len__

__len__() -> int

Return the number of spatial elements.

Source code in src/qten/symbolics/state_space.py
88
89
90
def __len__(self) -> int:
    """Return the number of spatial elements."""
    return len(self.structure)

__iter__

__iter__() -> Iterator[T]

Iterate over spatial elements.

Source code in src/qten/symbolics/state_space.py
92
93
94
def __iter__(self) -> Iterator[T]:
    """Iterate over spatial elements."""
    return iter(self.structure.keys())

__getitem__

__getitem__(v: int) -> T
__getitem__(v: slice | range) -> Self
__getitem__(v: Sequence[int]) -> Self

Index into the state-space by element position.

Supported forms

space[i] returns a single spatial element by position, including negative indices. space[start:stop:step] returns a new space with the selected elements in slice order. space[range(...)] returns a new space with the range-selected elements. space[[i, j, ...]] returns a new space with elements in explicit index order.

Parameters:

Name Type Description Default
key Union[int, slice, range, Sequence[int]]

Index selector. Sequences must contain unique integers; negative integers are normalized relative to len(self).

required

Returns:

Type Description
Spatial or StateSpace

A spatial element for int indexing, otherwise a new instance of the same class containing the selected elements. Any extra dataclass fields on subclasses are preserved in the returned instance.

Raises:

Type Description
IndexError

If an integer index is out of bounds.

TypeError

If key is not an int, slice, range, or sequence of integers.

ValueError

If a sequence selector contains duplicate indices.

Source code in src/qten/symbolics/state_space.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def __getitem__(
    self, key: Union[int, slice, range, Sequence[int]]
) -> Union[T, "StateSpace[T]"]:
    """
    Index into the state-space by element position.

    Supported forms
    ---------------
    `space[i]` returns a single spatial element by position, including
    negative indices. `space[start:stop:step]` returns a new space with the
    selected elements in slice order. `space[range(...)]` returns a new
    space with the range-selected elements. `space[[i, j, ...]]` returns a
    new space with elements in explicit index order.

    Parameters
    ----------
    key : Union[int, slice, range, Sequence[int]]
        Index selector. Sequences must contain unique integers; negative
        integers are normalized relative to `len(self)`.

    Returns
    -------
    Spatial or StateSpace
        A spatial element for `int` indexing, otherwise a new instance of the
        same class containing the selected elements. Any extra dataclass fields
        on subclasses are preserved in the returned instance.

    Raises
    ------
    IndexError
        If an integer index is out of bounds.
    TypeError
        If `key` is not an `int`, `slice`, `range`, or sequence of integers.
    ValueError
        If a sequence selector contains duplicate indices.
    """
    if isinstance(key, int):
        if key < 0:
            key += len(self.structure)
        if key < 0 or key >= len(self.structure):
            raise IndexError("StateSpace index out of range")
        return next(islice(self.structure.keys(), key, None))
    if isinstance(key, slice):
        keys = tuple(self.structure.keys())[key]
        new_structure = OrderedDict((k, self.structure[k]) for k in keys)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, range):
        keys = tuple(self.structure.keys())
        new_structure = OrderedDict((keys[i], self.structure[keys[i]]) for i in key)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, Sequence) and not isinstance(key, (str, bytes)):
        keys = tuple(self.structure.keys())
        indices: list[int] = []
        seen = set()
        for idx in key:
            if isinstance(idx, bool) or not isinstance(idx, int):
                raise TypeError(
                    "StateSpace sequence indices must contain only integers"
                )
            normalized = idx
            if normalized < 0:
                normalized += len(keys)
            if normalized < 0 or normalized >= len(keys):
                raise IndexError("StateSpace index out of range")
            if normalized in seen:
                raise ValueError("StateSpace sequence indices must be unique")
            seen.add(normalized)
            indices.append(normalized)
        new_structure = OrderedDict(
            (keys[i], self.structure[keys[i]]) for i in indices
        )
        return replace(self, structure=restructure(new_structure))
    raise TypeError(
        "StateSpace indices must be int, slice, range, or a sequence of ints, "
        f"not {type(key)}"
    )

same_rays

same_rays(other: StateSpace) -> bool

Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

Parameters:

Name Type Description Default
other StateSpace

The other state space to compare against.

required

Returns:

Type Description
bool

True if both state spaces have the same rays, False otherwise.

Source code in src/qten/symbolics/state_space.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def same_rays(self, other: "StateSpace") -> bool:
    """
    Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

    Parameters
    ----------
    other : StateSpace
        The other state space to compare against.

    Returns
    -------
    bool
        True if both state spaces have the same rays, `False` otherwise.
    """
    return same_rays(self, other)

map

map(func: Callable[[T], T]) -> Self

Map the spatial elements of this state space using a provided function.

Parameters:

Name Type Description Default
func Callable[[T], T]

A function that takes a spatial element and returns a transformed spatial element.

required

Returns:

Type Description
Self

A new state space with the transformed spatial elements.

Source code in src/qten/symbolics/state_space.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
def map(self, func: Callable[[T], T]) -> "Self":
    """
    Map the spatial elements of this state space using a provided function.

    Parameters
    ----------
    func : Callable[[T], T]
        A function that takes a spatial element and returns a transformed spatial element.

    Returns
    -------
    Self
        A new state space with the transformed spatial elements.
    """
    new_structure = OrderedDict()
    for k, s in self.structure.items():
        new_k = func(k)
        new_structure[new_k] = s
    return replace(self, structure=restructure(new_structure))

filter

filter(pred: Callable[[T], bool]) -> Self

Return the subspace containing elements where pred(element) is True.

Parameters:

Name Type Description Default
pred Callable[[T], bool]

Predicate applied to each element in basis order.

required

Returns:

Type Description
Self

A new state space of the same concrete type containing only the selected elements, with indices repacked contiguously.

Source code in src/qten/symbolics/state_space.py
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
def filter(self, pred: Callable[[T], bool]) -> "Self":
    """
    Return the subspace containing elements where `pred(element)` is `True`.

    Parameters
    ----------
    pred : Callable[[T], bool]
        Predicate applied to each element in basis order.

    Returns
    -------
    Self
        A new state space of the same concrete type containing only the
        selected elements, with indices repacked contiguously.
    """
    new_structure = OrderedDict(
        (k, s) for k, s in self.structure.items() if pred(k)
    )
    return replace(self, structure=restructure(new_structure))

tensor_product

tensor_product(other: Self) -> Self

Return the tensor-product state space of this space and another space.

This method defines the protocol used by the @ operator on StateSpace instances. The base class cannot construct a generic product because it does not know how to combine two elements of type T. Concrete subclasses must implement the element-level product and rebuild a contiguous structure for the resulting basis.

Implementations should preserve deterministic product ordering. The convention used by concrete tensor-product spaces in QTen is the Cartesian product order of self.elements() and other.elements(), where elements from self vary slowest and elements from other vary fastest. The returned space should be the same concrete state-space family when the operation is closed over that family.

Parameters:

Name Type Description Default
other StateSpace

Right-hand tensor factor. Implementations may require other to be the same concrete state-space type as self.

required

Returns:

Type Description
StateSpace

New state space representing self ⊗ other, with contiguous integer indices in the implementation-defined product order.

Raises:

Type Description
NotImplementedError

Always raised by the base class. Subclasses that support tensor products must override this method.

Source code in src/qten/symbolics/state_space.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def tensor_product(self, other: Self) -> Self:
    """
    Return the tensor-product state space of this space and another space.

    This method defines the protocol used by the `@` operator on
    [`StateSpace`][qten.symbolics.state_space.StateSpace] instances. The
    base class cannot construct a generic product because it does not know
    how to combine two elements of type `T`. Concrete subclasses must
    implement the element-level product and rebuild a contiguous
    `structure` for the resulting basis.

    Implementations should preserve deterministic product ordering. The
    convention used by concrete tensor-product spaces in QTen is the
    Cartesian product order of `self.elements()` and `other.elements()`,
    where elements from `self` vary slowest and elements from `other` vary
    fastest. The returned space should be the same concrete state-space
    family when the operation is closed over that family.

    Parameters
    ----------
    other : StateSpace
        Right-hand tensor factor. Implementations may require `other` to be
        the same concrete state-space type as `self`.

    Returns
    -------
    StateSpace
        New state space representing `self ⊗ other`, with contiguous
        integer indices in the implementation-defined product order.

    Raises
    ------
    NotImplementedError
        Always raised by the base class. Subclasses that support tensor
        products must override this method.
    """
    raise NotImplementedError(f"Tensor product not implemented for {type(self)}!")

extract

extract(info_type: type[Any]) -> Any

Extract an object implied by the elements of this state space.

Subclasses may register specialized implementations for supported target types.

Parameters:

Name Type Description Default
info_type type[Any]

Type of metadata or object to extract from this state space.

required

Returns:

Type Description
Any

Extracted object produced by a registered specialization.

Raises:

Type Description
NotImplementedError

If no extraction rule is registered for info_type.

Source code in src/qten/symbolics/state_space.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
@multimethod
def extract(self, info_type: type[Any]) -> Any:
    """
    Extract an object implied by the elements of this state space.

    Subclasses may register specialized implementations for supported
    target types.

    Parameters
    ----------
    info_type : type[Any]
        Type of metadata or object to extract from this state space.

    Returns
    -------
    Any
        Extracted object produced by a registered specialization.

    Raises
    ------
    NotImplementedError
        If no extraction rule is registered for `info_type`.
    """
    raise NotImplementedError(
        f"Extraction of {info_type} from {type(self)} is not supported!"
    )

__hash__

__hash__() -> int

Return a hash derived from the ordered momentum structure.

MomentumSpace uses the same structure-based hash as StateSpace. The hash includes every Momentum key and its stored integer basis index in insertion order. This means two momentum spaces with the same momentum set but different basis order hash differently.

Returns:

Type Description
int

Hash value for the ordered (Momentum, index) mapping.

Source code in src/qten/symbolics/state_space.py
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
def __hash__(self) -> int:
    """
    Return a hash derived from the ordered momentum structure.

    [`MomentumSpace`][qten.symbolics.state_space.MomentumSpace] uses the
    same structure-based hash as
    [`StateSpace`][qten.symbolics.state_space.StateSpace]. The hash includes
    every [`Momentum`][qten.geometries.spatials.Momentum] key and its stored
    integer basis index in insertion order. This means two momentum spaces
    with the same momentum set but different basis order hash differently.

    Returns
    -------
    int
        Hash value for the ordered `(Momentum, index)` mapping.
    """
    return StateSpace.__hash__(self)

__str__

__str__()

Return a compact momentum-space summary.

Returns:

Type Description
str

Summary containing the momentum-space dimension.

Source code in src/qten/symbolics/state_space.py
535
536
537
538
539
540
541
542
543
544
def __str__(self):
    """
    Return a compact momentum-space summary.

    Returns
    -------
    str
        Summary containing the momentum-space dimension.
    """
    return f"MomentumSpace({self.dim})"

__repr__

__repr__()

Return a multiline representation with indexed momentum elements.

Returns:

Type Description
str

Header plus one line per momentum element in basis order.

Source code in src/qten/symbolics/state_space.py
546
547
548
549
550
551
552
553
554
555
556
557
558
559
def __repr__(self):
    """
    Return a multiline representation with indexed momentum elements.

    Returns
    -------
    str
        Header plus one line per momentum element in basis order.
    """
    header = f"{str(self)}:\n"
    body = "\t" + "\n\t".join(
        [f"{n}: {k}" for n, k in enumerate(self.structure.keys())]
    )
    return header + body

StateSpace dataclass

StateSpace(structure: OrderedDict[T, int])

Bases: Spatial, Convertible, Generic[T], Span[T]

StateSpace is a collection of indices with additional information attached to the elements, for the case of TNS there are only two types of state spaces: MomentumSpace and HilbertSpace. MomentumSpace is needed because some tensors are better represented in momentum space, e.g. Hamiltonians with translational symmetry, while HilbertSpace is needed to represent local degrees of freedom, e.g. spin or fermionic modes.

Attributes:

Name Type Description
structure OrderedDict[Spatial, int]

An ordered dictionary mapping each spatial component (e.g., Offset, Momentum) to its single flattened index.

dim int

The total dimension of the state space, calculated as the count of elements regardless of their lengths.

structure instance-attribute

structure: OrderedDict[T, int]

An ordered dictionary mapping each spatial component (e.g., Offset, Momentum) to its single flattened index.

dim property

dim: int

The total size of the vector space.

register_plot_method classmethod

register_plot_method(name: str, backend: str = 'plotly')

Register a backend plotting function for this plottable class.

The returned decorator stores the function in the global plotting registry. Registered functions receive the object being plotted as their first argument, followed by any extra positional and keyword arguments supplied to plot().

Parameters:

Name Type Description Default
name str

User-facing plot method name, such as scatter, structure, or heatmap.

required
backend str

Backend name that selects the implementation. The qten-plots extension currently uses plotly and matplotlib.

'plotly'

Returns:

Type Description
Callable

Decorator that registers the provided plotting function and returns it unchanged.

Source code in src/qten/plottings/_plottings.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@classmethod
def register_plot_method(cls, name: str, backend: str = "plotly"):
    """
    Register a backend plotting function for this plottable class.

    The returned decorator stores the function in the global plotting
    registry. Registered functions receive the object being plotted as their
    first argument, followed by any extra positional and keyword arguments
    supplied to [`plot()`][qten.plottings.Plottable.plot].

    Parameters
    ----------
    name : str
        User-facing plot method name, such as `scatter`, `structure`, or
        `heatmap`.
    backend : str
        Backend name that selects the implementation. The `qten-plots`
        extension currently uses `plotly` and `matplotlib`.

    Returns
    -------
    Callable
        Decorator that registers the provided plotting function and returns
        it unchanged.
    """

    def decorator(func: Callable):
        # We register against 'cls' - the class this method was called on.
        Plottable._registry[(cls, name, backend)] = func
        return func

    return decorator

plot

plot(method: str, backend: str = 'plotly', *args, **kwargs)

Dispatch a named plot method to a registered backend implementation.

The dispatcher first loads plotting entry points, then searches the instance type and its base classes for a matching (type, method, backend) registration. Additional arguments are forwarded unchanged to the selected backend function.

Parameters:

Name Type Description Default
method str

Plot method name registered for this object's type.

required
backend str

Backend implementation to use. The qten-plots extension currently registers plotly and matplotlib.

'plotly'
args

Positional arguments forwarded to the registered plotting function.

()
kwargs

Keyword arguments forwarded to the registered plotting function.

{}

Returns:

Type Description
object

Backend-specific figure object returned by the registered plotting function, such as a Plotly or Matplotlib figure.

Raises:

Type Description
ValueError

If no plotting function is registered for the requested method and backend on this object.

See Also

qten_plots.plottables.PointCloud Public plottable helper object provided by the plotting extension.

Source code in src/qten/plottings/_plottings.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def plot(self, method: str, backend: str = "plotly", *args, **kwargs):
    """
    Dispatch a named plot method to a registered backend implementation.

    The dispatcher first loads plotting entry points, then searches the
    instance type and its base classes for a matching `(type, method,
    backend)` registration. Additional arguments are forwarded unchanged to
    the selected backend function.

    Parameters
    ----------
    method : str
        Plot method name registered for this object's type.
    backend : str
        Backend implementation to use. The `qten-plots` extension currently
        registers `plotly` and `matplotlib`.
    args
        Positional arguments forwarded to the registered plotting function.
    kwargs
        Keyword arguments forwarded to the registered plotting function.

    Returns
    -------
    object
        Backend-specific figure object returned by the registered plotting
        function, such as a Plotly or Matplotlib figure.

    Raises
    ------
    ValueError
        If no plotting function is registered for the requested method and
        backend on this object.

    See Also
    --------
    qten_plots.plottables.PointCloud
        Public plottable helper object provided by the plotting extension.
    """
    Plottable._ensure_backends_loaded()

    # Iterate over the MRO (Method Resolution Order) of the instance
    for class_in_hierarchy in type(self).__mro__:
        key = (class_in_hierarchy, method, backend)

        # Check the central registry
        if key in Plottable._registry:
            plot_func = Plottable._registry[key]
            return plot_func(self, *args, **kwargs)

    # If we reach here, no method was found. Provide a helpful error.
    self._raise_method_not_found(method, backend)

add_conversion classmethod

add_conversion(
    T: type[B],
) -> Callable[[Callable[[A], B]], Callable[[A], B]]

Register a conversion from cls to T.

The decorated function is stored under (cls, T). When an instance of cls later calls convert(T), that function is used to produce the converted object.

Parameters:

Name Type Description Default
T Type[B]

Destination type produced by the registered conversion function.

required

Returns:

Type Description
Callable[[Callable[[A], B]], Callable[[A], B]]

Decorator that stores the conversion function and returns it unchanged.

Examples:

@MyType.add_conversion(TargetType)
def to_target(x: MyType) -> TargetType:
    ...
Source code in src/qten/abstracts.py
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
@classmethod
def add_conversion(
    cls: Type[A], T: Type[B]
) -> Callable[[Callable[[A], B]], Callable[[A], B]]:
    """
    Register a conversion from `cls` to `T`.

    The decorated function is stored under `(cls, T)`. When an instance of
    `cls` later calls [`convert(T)`][qten.abstracts.Convertible.convert],
    that function is used to produce the converted object.

    Parameters
    ----------
    T : Type[B]
        Destination type produced by the registered conversion function.

    Returns
    -------
    Callable[[Callable[[A], B]], Callable[[A], B]]
        Decorator that stores the conversion function and returns it
        unchanged.

    Examples
    --------
    ```python
    @MyType.add_conversion(TargetType)
    def to_target(x: MyType) -> TargetType:
        ...
    ```
    """

    def decorator(func: Callable[[A], B]) -> Callable[[A], B]:
        _type_conversion_table[(cls, T)] = cast(Callable[[Any], Any], func)
        return func

    return decorator

convert

convert(T: type[B]) -> B

Convert this instance to the requested target type.

Parameters:

Name Type Description Default
T Type[B]

Destination type to convert into.

required

Returns:

Type Description
B

Converted object produced by the registered conversion function.

Raises:

Type Description
NotImplementedError

If no conversion function has been registered for (type(self), T) or any source supertype via add_conversion().

Source code in src/qten/abstracts.py
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
@final
def convert(self, T: Type[B]) -> B:
    """
    Convert this instance to the requested target type.

    Parameters
    ----------
    T : Type[B]
        Destination type to convert into.

    Returns
    -------
    B
        Converted object produced by the registered conversion function.

    Raises
    ------
    NotImplementedError
        If no conversion function has been registered for
        `(type(self), T)` or any source supertype via
        [`add_conversion()`][qten.abstracts.Convertible.add_conversion].
    """
    source_type = type(self)
    table_get = _type_conversion_table.get

    convertor = table_get((source_type, T))
    if convertor is None:
        for super_type in source_type.__mro__[1:]:
            convertor = table_get((super_type, T))
            if convertor is not None:
                # Cache resolved parent conversion under the concrete source type.
                _type_conversion_table[(source_type, T)] = convertor
                break

    if convertor is None:
        raise NotImplementedError(
            f"No conversion from {source_type.__name__} to {T.__name__}!"
        )
    return cast(Callable[["Convertible"], B], convertor)(self)

elements

elements() -> tuple[T, ...]

Return the spatial elements as a tuple.

Source code in src/qten/symbolics/state_space.py
83
84
85
86
@override
def elements(self) -> Tuple[T, ...]:
    """Return the spatial elements as a tuple."""
    return tuple(self.structure.keys())

__len__

__len__() -> int

Return the number of spatial elements.

Source code in src/qten/symbolics/state_space.py
88
89
90
def __len__(self) -> int:
    """Return the number of spatial elements."""
    return len(self.structure)

__iter__

__iter__() -> Iterator[T]

Iterate over spatial elements.

Source code in src/qten/symbolics/state_space.py
92
93
94
def __iter__(self) -> Iterator[T]:
    """Iterate over spatial elements."""
    return iter(self.structure.keys())

__hash__

__hash__()

Return a hash derived from the ordered state-space structure.

The hash is computed from tuple(self.structure.items()), so it depends on both the spatial elements and their stored integer indices in insertion order. Two state spaces with the same elements but a different order, or with the same elements mapped to different integer positions, intentionally produce different hashes.

This custom implementation is required because structure is an OrderedDict, which is mutable and unhashable by itself. The state-space dataclasses are frozen, so the tuple snapshot is stable as long as the contained spatial elements are themselves hashable and immutable.

Returns:

Type Description
int

Hash value for the ordered (element, index) mapping.

Source code in src/qten/symbolics/state_space.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def __hash__(self) -> int:
    """
    Return a hash derived from the ordered state-space structure.

    The hash is computed from `tuple(self.structure.items())`, so it
    depends on both the spatial elements and their stored integer indices in
    insertion order. Two state spaces with the same elements but a different
    order, or with the same elements mapped to different integer positions,
    intentionally produce different hashes.

    This custom implementation is required because `structure` is an
    `OrderedDict`, which is mutable and unhashable by itself. The state-space
    dataclasses are frozen, so the tuple snapshot is stable as long as the
    contained spatial elements are themselves hashable and immutable.

    Returns
    -------
    int
        Hash value for the ordered `(element, index)` mapping.
    """
    return hash(tuple(self.structure.items()))

__getitem__

__getitem__(v: int) -> T
__getitem__(v: slice | range) -> Self
__getitem__(v: Sequence[int]) -> Self

Index into the state-space by element position.

Supported forms

space[i] returns a single spatial element by position, including negative indices. space[start:stop:step] returns a new space with the selected elements in slice order. space[range(...)] returns a new space with the range-selected elements. space[[i, j, ...]] returns a new space with elements in explicit index order.

Parameters:

Name Type Description Default
key Union[int, slice, range, Sequence[int]]

Index selector. Sequences must contain unique integers; negative integers are normalized relative to len(self).

required

Returns:

Type Description
Spatial or StateSpace

A spatial element for int indexing, otherwise a new instance of the same class containing the selected elements. Any extra dataclass fields on subclasses are preserved in the returned instance.

Raises:

Type Description
IndexError

If an integer index is out of bounds.

TypeError

If key is not an int, slice, range, or sequence of integers.

ValueError

If a sequence selector contains duplicate indices.

Source code in src/qten/symbolics/state_space.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def __getitem__(
    self, key: Union[int, slice, range, Sequence[int]]
) -> Union[T, "StateSpace[T]"]:
    """
    Index into the state-space by element position.

    Supported forms
    ---------------
    `space[i]` returns a single spatial element by position, including
    negative indices. `space[start:stop:step]` returns a new space with the
    selected elements in slice order. `space[range(...)]` returns a new
    space with the range-selected elements. `space[[i, j, ...]]` returns a
    new space with elements in explicit index order.

    Parameters
    ----------
    key : Union[int, slice, range, Sequence[int]]
        Index selector. Sequences must contain unique integers; negative
        integers are normalized relative to `len(self)`.

    Returns
    -------
    Spatial or StateSpace
        A spatial element for `int` indexing, otherwise a new instance of the
        same class containing the selected elements. Any extra dataclass fields
        on subclasses are preserved in the returned instance.

    Raises
    ------
    IndexError
        If an integer index is out of bounds.
    TypeError
        If `key` is not an `int`, `slice`, `range`, or sequence of integers.
    ValueError
        If a sequence selector contains duplicate indices.
    """
    if isinstance(key, int):
        if key < 0:
            key += len(self.structure)
        if key < 0 or key >= len(self.structure):
            raise IndexError("StateSpace index out of range")
        return next(islice(self.structure.keys(), key, None))
    if isinstance(key, slice):
        keys = tuple(self.structure.keys())[key]
        new_structure = OrderedDict((k, self.structure[k]) for k in keys)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, range):
        keys = tuple(self.structure.keys())
        new_structure = OrderedDict((keys[i], self.structure[keys[i]]) for i in key)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, Sequence) and not isinstance(key, (str, bytes)):
        keys = tuple(self.structure.keys())
        indices: list[int] = []
        seen = set()
        for idx in key:
            if isinstance(idx, bool) or not isinstance(idx, int):
                raise TypeError(
                    "StateSpace sequence indices must contain only integers"
                )
            normalized = idx
            if normalized < 0:
                normalized += len(keys)
            if normalized < 0 or normalized >= len(keys):
                raise IndexError("StateSpace index out of range")
            if normalized in seen:
                raise ValueError("StateSpace sequence indices must be unique")
            seen.add(normalized)
            indices.append(normalized)
        new_structure = OrderedDict(
            (keys[i], self.structure[keys[i]]) for i in indices
        )
        return replace(self, structure=restructure(new_structure))
    raise TypeError(
        "StateSpace indices must be int, slice, range, or a sequence of ints, "
        f"not {type(key)}"
    )

same_rays

same_rays(other: StateSpace) -> bool

Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

Parameters:

Name Type Description Default
other StateSpace

The other state space to compare against.

required

Returns:

Type Description
bool

True if both state spaces have the same rays, False otherwise.

Source code in src/qten/symbolics/state_space.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def same_rays(self, other: "StateSpace") -> bool:
    """
    Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

    Parameters
    ----------
    other : StateSpace
        The other state space to compare against.

    Returns
    -------
    bool
        True if both state spaces have the same rays, `False` otherwise.
    """
    return same_rays(self, other)

map

map(func: Callable[[T], T]) -> Self

Map the spatial elements of this state space using a provided function.

Parameters:

Name Type Description Default
func Callable[[T], T]

A function that takes a spatial element and returns a transformed spatial element.

required

Returns:

Type Description
Self

A new state space with the transformed spatial elements.

Source code in src/qten/symbolics/state_space.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
def map(self, func: Callable[[T], T]) -> "Self":
    """
    Map the spatial elements of this state space using a provided function.

    Parameters
    ----------
    func : Callable[[T], T]
        A function that takes a spatial element and returns a transformed spatial element.

    Returns
    -------
    Self
        A new state space with the transformed spatial elements.
    """
    new_structure = OrderedDict()
    for k, s in self.structure.items():
        new_k = func(k)
        new_structure[new_k] = s
    return replace(self, structure=restructure(new_structure))

filter

filter(pred: Callable[[T], bool]) -> Self

Return the subspace containing elements where pred(element) is True.

Parameters:

Name Type Description Default
pred Callable[[T], bool]

Predicate applied to each element in basis order.

required

Returns:

Type Description
Self

A new state space of the same concrete type containing only the selected elements, with indices repacked contiguously.

Source code in src/qten/symbolics/state_space.py
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
def filter(self, pred: Callable[[T], bool]) -> "Self":
    """
    Return the subspace containing elements where `pred(element)` is `True`.

    Parameters
    ----------
    pred : Callable[[T], bool]
        Predicate applied to each element in basis order.

    Returns
    -------
    Self
        A new state space of the same concrete type containing only the
        selected elements, with indices repacked contiguously.
    """
    new_structure = OrderedDict(
        (k, s) for k, s in self.structure.items() if pred(k)
    )
    return replace(self, structure=restructure(new_structure))

tensor_product

tensor_product(other: Self) -> Self

Return the tensor-product state space of this space and another space.

This method defines the protocol used by the @ operator on StateSpace instances. The base class cannot construct a generic product because it does not know how to combine two elements of type T. Concrete subclasses must implement the element-level product and rebuild a contiguous structure for the resulting basis.

Implementations should preserve deterministic product ordering. The convention used by concrete tensor-product spaces in QTen is the Cartesian product order of self.elements() and other.elements(), where elements from self vary slowest and elements from other vary fastest. The returned space should be the same concrete state-space family when the operation is closed over that family.

Parameters:

Name Type Description Default
other StateSpace

Right-hand tensor factor. Implementations may require other to be the same concrete state-space type as self.

required

Returns:

Type Description
StateSpace

New state space representing self ⊗ other, with contiguous integer indices in the implementation-defined product order.

Raises:

Type Description
NotImplementedError

Always raised by the base class. Subclasses that support tensor products must override this method.

Source code in src/qten/symbolics/state_space.py
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def tensor_product(self, other: Self) -> Self:
    """
    Return the tensor-product state space of this space and another space.

    This method defines the protocol used by the `@` operator on
    [`StateSpace`][qten.symbolics.state_space.StateSpace] instances. The
    base class cannot construct a generic product because it does not know
    how to combine two elements of type `T`. Concrete subclasses must
    implement the element-level product and rebuild a contiguous
    `structure` for the resulting basis.

    Implementations should preserve deterministic product ordering. The
    convention used by concrete tensor-product spaces in QTen is the
    Cartesian product order of `self.elements()` and `other.elements()`,
    where elements from `self` vary slowest and elements from `other` vary
    fastest. The returned space should be the same concrete state-space
    family when the operation is closed over that family.

    Parameters
    ----------
    other : StateSpace
        Right-hand tensor factor. Implementations may require `other` to be
        the same concrete state-space type as `self`.

    Returns
    -------
    StateSpace
        New state space representing `self ⊗ other`, with contiguous
        integer indices in the implementation-defined product order.

    Raises
    ------
    NotImplementedError
        Always raised by the base class. Subclasses that support tensor
        products must override this method.
    """
    raise NotImplementedError(f"Tensor product not implemented for {type(self)}!")

extract

extract(info_type: type[Any]) -> Any

Extract an object implied by the elements of this state space.

Subclasses may register specialized implementations for supported target types.

Parameters:

Name Type Description Default
info_type type[Any]

Type of metadata or object to extract from this state space.

required

Returns:

Type Description
Any

Extracted object produced by a registered specialization.

Raises:

Type Description
NotImplementedError

If no extraction rule is registered for info_type.

Source code in src/qten/symbolics/state_space.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
@multimethod
def extract(self, info_type: type[Any]) -> Any:
    """
    Extract an object implied by the elements of this state space.

    Subclasses may register specialized implementations for supported
    target types.

    Parameters
    ----------
    info_type : type[Any]
        Type of metadata or object to extract from this state space.

    Returns
    -------
    Any
        Extracted object produced by a registered specialization.

    Raises
    ------
    NotImplementedError
        If no extraction rule is registered for `info_type`.
    """
    raise NotImplementedError(
        f"Extraction of {info_type} from {type(self)} is not supported!"
    )

StateSpaceFactorization

Bases: NamedTuple

Ruleset for factorizing one StateSpace-like tensor dimension.

Attributes:

Name Type Description
factorized Tuple[StateSpace, ...]

Target factor spaces in torch.Tensor.reshape ordering.

align_dim StateSpace

A permutation of the original dimension whose flattened order is compatible with reshaping into factorized.

factorized instance-attribute

factorized: tuple[StateSpace, ...]

align_dim instance-attribute

align_dim: StateSpace

brillouin_zone cached

brillouin_zone(lattice: ReciprocalLattice) -> MomentumSpace

Enumerate the discrete Brillouin-zone momenta of a reciprocal lattice.

Parameters:

Name Type Description Default
lattice ReciprocalLattice

Reciprocal lattice whose Cartesian momentum samples should be collected.

required

Returns:

Type Description
MomentumSpace

Momentum space whose ordering follows ReciprocalLattice.cartes().

Source code in src/qten/symbolics/state_space.py
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
@lru_cache
def brillouin_zone(lattice: ReciprocalLattice) -> MomentumSpace:
    """
    Enumerate the discrete Brillouin-zone momenta of a reciprocal lattice.

    Parameters
    ----------
    lattice : ReciprocalLattice
        Reciprocal lattice whose Cartesian momentum samples should be
        collected.

    Returns
    -------
    MomentumSpace
        Momentum space whose ordering follows
        [`ReciprocalLattice.cartes()`][qten.geometries.spatials.ReciprocalLattice.cartes].
    """
    elements = lattice.cartes()
    structure = OrderedDict((el, n) for n, el in enumerate(elements))
    return MomentumSpace(structure=structure)

embedding_order cached

embedding_order(
    sub: StateSpace, sup: StateSpace
) -> tuple[int, ...]

Return the positions of sub elements inside sup.

The returned tuple has one integer for each element of sub, in sub.elements() order. Each integer is the stored basis index of that same element in sup.structure. This is useful when a tensor axis represents a smaller state space and its data must be scattered into, gathered from, or aligned against a larger state space.

For example, if sup contains elements (a, b, c) with indices (0, 1, 2) and sub contains (c, a), then this function returns (2, 0). The result follows the order of sub, not the order of sup.

Parameters:

Name Type Description Default
sub StateSpace

State space whose elements should be located in sup.

required
sup StateSpace

State space providing the reference element-to-index mapping.

required

Returns:

Type Description
Tuple[int, ...]

Indices in sup corresponding to each element of sub, ordered like sub.elements().

Raises:

Type Description
ValueError

If any element of sub is not present as a key in sup.structure.

Source code in src/qten/symbolics/state_space.py
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
@lru_cache
def embedding_order(sub: StateSpace, sup: StateSpace) -> Tuple[int, ...]:
    """
    Return the positions of `sub` elements inside `sup`.

    The returned tuple has one integer for each element of `sub`, in
    `sub.elements()` order. Each integer is the stored basis index of that same
    element in `sup.structure`. This is useful when a tensor axis represents a
    smaller state space and its data must be scattered into, gathered from, or
    aligned against a larger state space.

    For example, if `sup` contains elements `(a, b, c)` with indices
    `(0, 1, 2)` and `sub` contains `(c, a)`, then this function returns
    `(2, 0)`. The result follows the order of `sub`, not the order of `sup`.

    Parameters
    ----------
    sub : StateSpace
        State space whose elements should be located in `sup`.
    sup : StateSpace
        State space providing the reference element-to-index mapping.

    Returns
    -------
    Tuple[int, ...]
        Indices in `sup` corresponding to each element of `sub`, ordered like
        `sub.elements()`.

    Raises
    ------
    ValueError
        If any element of `sub` is not present as a key in `sup.structure`.
    """
    indices: list[int] = []
    sup_indices = sup.structure
    for key, _ in sub.structure.items():
        if key not in sup_indices:
            raise ValueError(f"Key {key} not found in superspace")
        indices.append(sup_indices[key])
    return tuple(indices)

permutation_order cached

permutation_order(
    src: StateSpace, dest: StateSpace
) -> tuple[int, ...]

Return the permutation of src sectors needed to match dest sector order.

This returns a per-sector permutation: each entry corresponds to a key in dest.structure and gives the index of the same key in src.structure. The mapping is directly index-based on the current StateSpace structure and can be used to reorder sector-aligned data.

Parameters:

Name Type Description Default
src StateSpace

The source state space defining the original ordering.

required
dest StateSpace

The destination state space defining the target ordering.

required

Returns:

Type Description
Tuple[int, ...]

Sector indices mapping each key in dest to its position in src.

Raises:

Type Description
ValueError

If a destination sector key is missing from the source state space.

Source code in src/qten/symbolics/state_space.py
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
@lru_cache
def permutation_order(src: "StateSpace", dest: "StateSpace") -> Tuple[int, ...]:
    """
    Return the permutation of `src` sectors needed to match `dest` sector order.

    This returns a per-sector permutation: each entry corresponds to a key in
    `dest.structure` and gives the index of the same key in `src.structure`.
    The mapping is directly index-based on the current [`StateSpace`][qten.symbolics.state_space.StateSpace] structure
    and can be used to reorder sector-aligned data.

    Parameters
    ----------
    src : StateSpace
        The source state space defining the original ordering.
    dest : StateSpace
        The destination state space defining the target ordering.

    Returns
    -------
    Tuple[int, ...]
        Sector indices mapping each key in `dest` to its position in `src`.

    Raises
    ------
    ValueError
        If a destination sector key is missing from the source state space.
    """
    src_indices = src.structure
    dest_keys = dest.structure.keys()
    try:
        return tuple(src_indices[k] for k in dest_keys)
    except KeyError:
        missing = [k for k in dest_keys if k not in src_indices]
        raise ValueError(
            "Cannot build permutation order: destination contains keys not present "
            f"in source: {missing}"
        ) from None

restructure

restructure(
    structure: OrderedDict[T, int],
) -> OrderedDict[T, int]

Return a new OrderedDict with contiguous, ordered integer indices.

Parameters:

Name Type Description Default
structure OrderedDict[Spatial, int]

The original structure with possibly non-contiguous indices.

required

Returns:

Type Description
OrderedDict[Spatial, int]

The restructured OrderedDict with contiguous, ordered indices.

Source code in src/qten/symbolics/state_space.py
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
def restructure(
    structure: OrderedDict[T, int],
) -> OrderedDict[T, int]:
    """
    Return a new `OrderedDict` with contiguous, ordered integer indices.

    Parameters
    ----------
    structure : OrderedDict[Spatial, int]
        The original structure with possibly non-contiguous indices.

    Returns
    -------
    OrderedDict[Spatial, int]
        The restructured `OrderedDict` with contiguous, ordered indices.
    """
    return OrderedDict((k, i) for i, k in enumerate(structure.keys()))

same_rays

same_rays(a: HilbertSpace, b: HilbertSpace) -> bool

Check whether two state spaces span the same ray representatives.

Parameters:

Name Type Description Default
a StateSpace

First state space.

required
b StateSpace

Second state space.

required

Returns:

Type Description
bool

True when the two state spaces contain the same set of basis keys, ignoring ordering and stored integer indices.

Source code in src/qten/symbolics/state_space.py
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
@multimethod
def same_rays(a: StateSpace, b: StateSpace) -> bool:
    """
    Check whether two state spaces span the same ray representatives.

    Parameters
    ----------
    a : StateSpace
        First state space.
    b : StateSpace
        Second state space.

    Returns
    -------
    bool
        `True` when the two state spaces contain the same set of basis keys,
        ignoring ordering and stored integer indices.
    """
    return set(a.structure.keys()) == set(b.structure.keys())

FuncOpr dataclass

FuncOpr(
    T: type[_IrrepType],
    func: Callable[
        [_IrrepType], _IrrepType | Multiple[_IrrepType]
    ],
)

Bases: Generic[_IrrepType], Opr

Symbolic operator induced by applying a Python callable to one irrep type.

FuncOpr lifts a plain callable acting on a single irrep/component into an Opr that acts on the symbolic Hilbert-space objects defined in this module. The operator is parameterized by:

T is the concrete runtime type of the irrep/component to target. func is a callable mapping T -> T | Multiple[T].

Registered actions

FuncOpr defines a specialized registration on:

U1Basis. The handler finds the unique irrep in psi.base whose exact runtime type is T, applies func to it, and rebuilds the basis state with that component replaced.

For U1Span and HilbertSpace, FuncOpr relies on the inherited generic Opr lifting in this module, which maps the operator over contained U1Basis elements.

Semantics

This class is intended for structure-preserving symbolic rewrites such as "replace each Offset by Offset.fractional()" or "apply a transformation to each irrep of a basis state". It is not a general-purpose map over arbitrary Python objects: dispatch exists only for the symbolic container types registered below.

The callable func is expected to return either a transformed object of the same concrete type T, or Multiple(coef, value) where value has type T.

Return plain T when the transformation only changes the irrep/component itself. Return Multiple when the transformation also contributes an explicit scalar factor, such as a phase or gauge coefficient, that should be accumulated symbolically rather than absorbed into the object.

FuncOpr does not itself validate the semantic correctness of func, but the surrounding symbolic code assumes the transformation stays within the same representation family.

Interaction with @

Because FuncOpr is an Opr, it participates in the overloaded @ syntax:

f @ x applies the operator to an object x. f @ g forms a ComposedOpr.

With the current ComposedOpr semantics, operator composition follows the standard algebraic order:

(f @ g) @ x == f(g(x)).

So f @ g means "apply g, then apply f".

Interaction with Multiple

If v is Multiple(coef, base), then f(v) applies f to base.

If the result is a plain object base', the output is Multiple(coef, base'). If the result is Multiple(coef', base'), the coefficients are multiplied and simplified, producing Multiple(simplify(coef * coef'), base').

This behavior is provided centrally by Opr.invoke, so FuncOpr inherits the same coefficient-lifting semantics as every other operator subclass.

Interaction with Symbolic Containers

FuncOpr treats U1Basis specially: it targets the unique irrep of type T via psi.irrep_of(T) rather than iterating over all components with allows(...). This is why FuncOpr keeps a dedicated U1Basis registration even though U1Span and HilbertSpace can be handled by the generic Opr lifting.

Examples:

Use FuncOpr(Offset, Offset.fractional) to normalize every Offset appearing inside a U1Basis, U1Span, or HilbertSpace.

In particular:

fractional @ psi rewrites one basis state. fractional @ space rewrites every basis state in a Hilbert space. fractional @ t @ space means fractional(t(space)).

Attributes:

Name Type Description
T Type[_IrrepType]

Exact runtime type of the irrep/component targeted by this operator.

func Callable[[_IrrepType], _IrrepType | Multiple[_IrrepType]]

Callable applied to the targeted irrep.

func instance-attribute

func: Callable[
    [_IrrepType], _IrrepType | Multiple[_IrrepType]
]

Callable applied to the targeted irrep. It may return either a transformed irrep directly or a Multiple carrying an additional scalar factor.

register classmethod

register(obj_type: type)

Register a function defining the action of the Functional on a specific object type.

This method returns a decorator. The decorated function should accept the functional instance as its first argument and an object of obj_type as its second argument. Any keyword arguments passed to invoke() are forwarded to the decorated function.

Dispatch is resolved at call time via MRO, so only the exact (obj_type, cls) key is stored here. Resolution later searches both:

  • the MRO of the runtime object type,
  • the MRO of the runtime functional type.

This means registrations on a functional superclass are inherited by subclass functionals unless a more specific registration overrides them.

Parameters:

Name Type Description Default
obj_type type

The type of object the function applies to.

required

Returns:

Type Description
Callable

A decorator that registers the function for the specified object type.

Examples:

@MyFunctional.register(MyObject)
def _(functional: MyFunctional, obj: MyObject) -> MyObject:
    ...
Source code in src/qten/abstracts.py
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
@classmethod
def register(cls, obj_type: type):
    """
    Register a function defining the action of the [`Functional`][qten.abstracts.Functional] on a specific object type.

    This method returns a decorator. The decorated function should accept
    the functional instance as its first argument and an object of
    `obj_type` as its second argument. Any keyword arguments passed to
    [`invoke()`][qten.abstracts.Functional.invoke] are forwarded to the
    decorated function.

    Dispatch is resolved at call time via MRO, so only the exact
    `(obj_type, cls)` key is stored here. Resolution later searches both:

    - the MRO of the runtime object type,
    - the MRO of the runtime functional type.

    This means registrations on a functional superclass are inherited by
    subclass functionals unless a more specific registration overrides them.

    Parameters
    ----------
    obj_type : type
        The type of object the function applies to.

    Returns
    -------
    Callable
        A decorator that registers the function for the specified object type.

    Examples
    --------
    ```python
    @MyFunctional.register(MyObject)
    def _(functional: MyFunctional, obj: MyObject) -> MyObject:
        ...
    ```
    """

    def decorator(func: Callable):
        cls._registered_methods[(obj_type, cls)] = func
        cls._invalidate_resolved_methods(obj_type)
        return func

    return decorator

get_applicable_types staticmethod

get_applicable_types() -> tuple[type, ...]

Get all object types that can be applied by this Functional.

Parameters:

Name Type Description Default
cls Type[Functional]

Functional class whose direct registrations should be inspected.

required

Returns:

Type Description
Tuple[Type, ...]

A tuple of all registered object types that this Functional can handle.

Source code in src/qten/abstracts.py
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
@staticmethod
def get_applicable_types(cls) -> Tuple[Type, ...]:
    """
    Get all object types that can be applied by this [`Functional`][qten.abstracts.Functional].

    Parameters
    ----------
    cls : Type[Functional]
        Functional class whose direct registrations should be inspected.

    Returns
    -------
    Tuple[Type, ...]
        A tuple of all registered object types that this [`Functional`][qten.abstracts.Functional] can handle.
    """
    types = set()
    for obj_type, functional_type in cls._registered_methods.keys():
        if functional_type is cls:
            types.add(obj_type)
    return tuple(types)

allows

allows(obj: Any) -> bool

Check if this Functional can be applied on the given object.

Parameters:

Name Type Description Default
obj Any

The object to check for applicability.

required

Returns:

Type Description
bool

True if this Functional can be applied on the object, False otherwise.

Notes

Applicability is checked using the same inherited dispatch rules as invoke(): both the object's MRO and the functional-class MRO are searched.

Source code in src/qten/abstracts.py
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
def allows(self, obj: Any) -> bool:
    """
    Check if this [`Functional`][qten.abstracts.Functional] can be applied on the given object.

    Parameters
    ----------
    obj : Any
        The object to check for applicability.

    Returns
    -------
    bool
        True if this [`Functional`][qten.abstracts.Functional] can be applied on the object, False otherwise.

    Notes
    -----
    Applicability is checked using the same inherited dispatch rules as
    [`invoke()`][qten.abstracts.Functional.invoke]: both the object's MRO
    and the functional-class MRO are searched.
    """
    return self._resolve_method(type(obj), type(self)) is not None

invoke

invoke(v: _T, **kwargs: Any) -> _T | Multiple[_T]

Apply the operator while preserving QTen's symbolic output invariants.

Parameters:

Name Type Description Default
v _T

Input object to transform.

required
**kwargs Any

Extra keyword arguments forwarded to the resolved registration.

{}

Returns:

Type Description
_T | Multiple[_T]

Transformed object, or a factored result carrying an explicit scalar coefficient.

Raises:

Type Description
AssertionError

If a registered implementation returns a value outside the expected same-type / Multiple[same-type] contract.

Source code in src/qten/symbolics/hilbert_space.py
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
@override
def invoke(  # type: ignore[override]
    self, v: _T, **kwargs
) -> Union[_T, Multiple[_T]]:
    """
    Apply the operator while preserving QTen's symbolic output invariants.

    Parameters
    ----------
    v : _T
        Input object to transform.
    **kwargs : Any
        Extra keyword arguments forwarded to the resolved registration.

    Returns
    -------
    _T | Multiple[_T]
        Transformed object, or a factored result carrying an explicit
        scalar coefficient.

    Raises
    ------
    AssertionError
        If a registered implementation returns a value outside the expected
        same-type / `Multiple[same-type]` contract.
    """
    if type(v) is Multiple:
        result = super().invoke(v.base, **kwargs)
        if type(result) is Multiple:
            return Multiple((v.coef * result.coef).simplify(), result.base)
        return Multiple(v.coef, result)
    result = super().invoke(v, **kwargs)
    if isinstance(v, (U1Basis, U1Span, HilbertSpace)):
        assert type(result) is not Multiple, (
            f"Operator {type(self)} acting on {type(v).__name__} should not yield a Multiple!"
        )
    assert isinstance(result, type(v)) or (
        type(result) is Multiple and isinstance(result.base, type(v))
    ), (
        f"Operator {type(self)} acting on {type(v).__name__} should yield same typed object"
        f"or Multiple[{type(v).__name__}]"
    )
    return result

__call__

__call__(obj: Any, **kwargs) -> Any

Apply this functional to obj.

This is a thin wrapper around invoke().

Parameters:

Name Type Description Default
obj Any

Runtime object to dispatch on.

required
**kwargs Any

Additional keyword arguments forwarded to the resolved implementation.

{}

Returns:

Type Description
Any

Result produced by the resolved registered method.

Raises:

Type Description
NotImplementedError

If no registration exists for the runtime pair after MRO fallback.

See Also

invoke(obj, **kwargs) Full dispatch method used by this call wrapper.

Source code in src/qten/abstracts.py
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
def __call__(self, obj: Any, **kwargs) -> Any:
    """
    Apply this functional to `obj`.

    This is a thin wrapper around [`invoke()`][qten.abstracts.Functional.invoke].

    Parameters
    ----------
    obj : Any
        Runtime object to dispatch on.
    **kwargs : Any
        Additional keyword arguments forwarded to the resolved
        implementation.

    Returns
    -------
    Any
        Result produced by the resolved registered method.

    Raises
    ------
    NotImplementedError
        If no registration exists for the runtime pair after MRO fallback.

    See Also
    --------
    [`invoke(obj, **kwargs)`][qten.abstracts.Functional.invoke]
        Full dispatch method used by this call wrapper.
    """
    return self.invoke(obj, **kwargs)

HilbertSpace dataclass

HilbertSpace(structure: OrderedDict[T, int])

Bases: HasRays, StateSpace[U1Basis], Span[U1Basis]

Composite local Hilbert space built from states and state spans.

HilbertSpace is the symbolic basis container used by tensor-network style operators in this module. It extends StateSpace with U1Basis sectors. The inherited structure mapping stores each sector together with its integer index in basis order.

Mathematical convention

A Hilbert space is an ordered finite basis \(\mathcal{H} = \mathrm{span}\{|e_0\rangle,\ldots,|e_{d-1}\rangle\}\), where each \(|e_i\rangle\) is a U1Basis. The code-level structure mapping stores the correspondence U1Basis -> i. That index \(i\) is the coordinate used by Tensor axes.

Ray normalization removes U(1) prefactors from the labels: \(\mathrm{ray}(c\,|\rho\rangle) = |\rho\rangle\). Phase information is not lost when constructing overlap maps: it is stored in the matrix entries produced by cross_gram.

The class provides helpers for common basis-management workflows: elements() returns the flattened basis states as Tuple[U1Basis, ...]. lookup(query) retrieves a unique basis state by exact typed-irrep match. group(**groups) partitions basis elements into labeled grouped HilbertSpace values.

As a Span, HilbertSpace supports overlap/mapping computations through cross_gram, which builds a Tensor map between two spaces using U1Basis overlap (U1Span.cross_gram). As a HasRays, rays() keeps basis structure while replacing each element by its canonical ray representative.

Parameters:

Name Type Description Default
structure OrderedDict[U1Basis, int]

Ordered sector mapping inherited from StateSpace, where each key is a U1Basis and each value is the sector index in basis coordinates.

required
Notes

dim is inherited from StateSpace and equals the total flattened basis size, i.e. the number of indexed basis sectors. group() requires disjoint selectors; overlapping grouped spans raise ValueError. permutation_order and embedding_order operate on current structure keys.

dim property

dim: int

The total size of the vector space.

structure instance-attribute

structure: OrderedDict[T, int]

An ordered dictionary mapping each spatial component (e.g., Offset, Momentum) to its single flattened index.

register_plot_method classmethod

register_plot_method(name: str, backend: str = 'plotly')

Register a backend plotting function for this plottable class.

The returned decorator stores the function in the global plotting registry. Registered functions receive the object being plotted as their first argument, followed by any extra positional and keyword arguments supplied to plot().

Parameters:

Name Type Description Default
name str

User-facing plot method name, such as scatter, structure, or heatmap.

required
backend str

Backend name that selects the implementation. The qten-plots extension currently uses plotly and matplotlib.

'plotly'

Returns:

Type Description
Callable

Decorator that registers the provided plotting function and returns it unchanged.

Source code in src/qten/plottings/_plottings.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@classmethod
def register_plot_method(cls, name: str, backend: str = "plotly"):
    """
    Register a backend plotting function for this plottable class.

    The returned decorator stores the function in the global plotting
    registry. Registered functions receive the object being plotted as their
    first argument, followed by any extra positional and keyword arguments
    supplied to [`plot()`][qten.plottings.Plottable.plot].

    Parameters
    ----------
    name : str
        User-facing plot method name, such as `scatter`, `structure`, or
        `heatmap`.
    backend : str
        Backend name that selects the implementation. The `qten-plots`
        extension currently uses `plotly` and `matplotlib`.

    Returns
    -------
    Callable
        Decorator that registers the provided plotting function and returns
        it unchanged.
    """

    def decorator(func: Callable):
        # We register against 'cls' - the class this method was called on.
        Plottable._registry[(cls, name, backend)] = func
        return func

    return decorator

plot

plot(method: str, backend: str = 'plotly', *args, **kwargs)

Dispatch a named plot method to a registered backend implementation.

The dispatcher first loads plotting entry points, then searches the instance type and its base classes for a matching (type, method, backend) registration. Additional arguments are forwarded unchanged to the selected backend function.

Parameters:

Name Type Description Default
method str

Plot method name registered for this object's type.

required
backend str

Backend implementation to use. The qten-plots extension currently registers plotly and matplotlib.

'plotly'
args

Positional arguments forwarded to the registered plotting function.

()
kwargs

Keyword arguments forwarded to the registered plotting function.

{}

Returns:

Type Description
object

Backend-specific figure object returned by the registered plotting function, such as a Plotly or Matplotlib figure.

Raises:

Type Description
ValueError

If no plotting function is registered for the requested method and backend on this object.

See Also

qten_plots.plottables.PointCloud Public plottable helper object provided by the plotting extension.

Source code in src/qten/plottings/_plottings.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def plot(self, method: str, backend: str = "plotly", *args, **kwargs):
    """
    Dispatch a named plot method to a registered backend implementation.

    The dispatcher first loads plotting entry points, then searches the
    instance type and its base classes for a matching `(type, method,
    backend)` registration. Additional arguments are forwarded unchanged to
    the selected backend function.

    Parameters
    ----------
    method : str
        Plot method name registered for this object's type.
    backend : str
        Backend implementation to use. The `qten-plots` extension currently
        registers `plotly` and `matplotlib`.
    args
        Positional arguments forwarded to the registered plotting function.
    kwargs
        Keyword arguments forwarded to the registered plotting function.

    Returns
    -------
    object
        Backend-specific figure object returned by the registered plotting
        function, such as a Plotly or Matplotlib figure.

    Raises
    ------
    ValueError
        If no plotting function is registered for the requested method and
        backend on this object.

    See Also
    --------
    qten_plots.plottables.PointCloud
        Public plottable helper object provided by the plotting extension.
    """
    Plottable._ensure_backends_loaded()

    # Iterate over the MRO (Method Resolution Order) of the instance
    for class_in_hierarchy in type(self).__mro__:
        key = (class_in_hierarchy, method, backend)

        # Check the central registry
        if key in Plottable._registry:
            plot_func = Plottable._registry[key]
            return plot_func(self, *args, **kwargs)

    # If we reach here, no method was found. Provide a helpful error.
    self._raise_method_not_found(method, backend)

elements

elements() -> tuple[T, ...]

Return the spatial elements as a tuple.

Source code in src/qten/symbolics/state_space.py
83
84
85
86
@override
def elements(self) -> Tuple[T, ...]:
    """Return the spatial elements as a tuple."""
    return tuple(self.structure.keys())

add_conversion classmethod

add_conversion(
    T: type[B],
) -> Callable[[Callable[[A], B]], Callable[[A], B]]

Register a conversion from cls to T.

The decorated function is stored under (cls, T). When an instance of cls later calls convert(T), that function is used to produce the converted object.

Parameters:

Name Type Description Default
T Type[B]

Destination type produced by the registered conversion function.

required

Returns:

Type Description
Callable[[Callable[[A], B]], Callable[[A], B]]

Decorator that stores the conversion function and returns it unchanged.

Examples:

@MyType.add_conversion(TargetType)
def to_target(x: MyType) -> TargetType:
    ...
Source code in src/qten/abstracts.py
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
@classmethod
def add_conversion(
    cls: Type[A], T: Type[B]
) -> Callable[[Callable[[A], B]], Callable[[A], B]]:
    """
    Register a conversion from `cls` to `T`.

    The decorated function is stored under `(cls, T)`. When an instance of
    `cls` later calls [`convert(T)`][qten.abstracts.Convertible.convert],
    that function is used to produce the converted object.

    Parameters
    ----------
    T : Type[B]
        Destination type produced by the registered conversion function.

    Returns
    -------
    Callable[[Callable[[A], B]], Callable[[A], B]]
        Decorator that stores the conversion function and returns it
        unchanged.

    Examples
    --------
    ```python
    @MyType.add_conversion(TargetType)
    def to_target(x: MyType) -> TargetType:
        ...
    ```
    """

    def decorator(func: Callable[[A], B]) -> Callable[[A], B]:
        _type_conversion_table[(cls, T)] = cast(Callable[[Any], Any], func)
        return func

    return decorator

convert

convert(T: type[B]) -> B

Convert this instance to the requested target type.

Parameters:

Name Type Description Default
T Type[B]

Destination type to convert into.

required

Returns:

Type Description
B

Converted object produced by the registered conversion function.

Raises:

Type Description
NotImplementedError

If no conversion function has been registered for (type(self), T) or any source supertype via add_conversion().

Source code in src/qten/abstracts.py
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
@final
def convert(self, T: Type[B]) -> B:
    """
    Convert this instance to the requested target type.

    Parameters
    ----------
    T : Type[B]
        Destination type to convert into.

    Returns
    -------
    B
        Converted object produced by the registered conversion function.

    Raises
    ------
    NotImplementedError
        If no conversion function has been registered for
        `(type(self), T)` or any source supertype via
        [`add_conversion()`][qten.abstracts.Convertible.add_conversion].
    """
    source_type = type(self)
    table_get = _type_conversion_table.get

    convertor = table_get((source_type, T))
    if convertor is None:
        for super_type in source_type.__mro__[1:]:
            convertor = table_get((super_type, T))
            if convertor is not None:
                # Cache resolved parent conversion under the concrete source type.
                _type_conversion_table[(source_type, T)] = convertor
                break

    if convertor is None:
        raise NotImplementedError(
            f"No conversion from {source_type.__name__} to {T.__name__}!"
        )
    return cast(Callable[["Convertible"], B], convertor)(self)

__len__

__len__() -> int

Return the number of spatial elements.

Source code in src/qten/symbolics/state_space.py
88
89
90
def __len__(self) -> int:
    """Return the number of spatial elements."""
    return len(self.structure)

__iter__

__iter__() -> Iterator[T]

Iterate over spatial elements.

Source code in src/qten/symbolics/state_space.py
92
93
94
def __iter__(self) -> Iterator[T]:
    """Iterate over spatial elements."""
    return iter(self.structure.keys())

__getitem__

__getitem__(v: int) -> T
__getitem__(v: slice | range) -> Self
__getitem__(v: Sequence[int]) -> Self

Index into the state-space by element position.

Supported forms

space[i] returns a single spatial element by position, including negative indices. space[start:stop:step] returns a new space with the selected elements in slice order. space[range(...)] returns a new space with the range-selected elements. space[[i, j, ...]] returns a new space with elements in explicit index order.

Parameters:

Name Type Description Default
key Union[int, slice, range, Sequence[int]]

Index selector. Sequences must contain unique integers; negative integers are normalized relative to len(self).

required

Returns:

Type Description
Spatial or StateSpace

A spatial element for int indexing, otherwise a new instance of the same class containing the selected elements. Any extra dataclass fields on subclasses are preserved in the returned instance.

Raises:

Type Description
IndexError

If an integer index is out of bounds.

TypeError

If key is not an int, slice, range, or sequence of integers.

ValueError

If a sequence selector contains duplicate indices.

Source code in src/qten/symbolics/state_space.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
def __getitem__(
    self, key: Union[int, slice, range, Sequence[int]]
) -> Union[T, "StateSpace[T]"]:
    """
    Index into the state-space by element position.

    Supported forms
    ---------------
    `space[i]` returns a single spatial element by position, including
    negative indices. `space[start:stop:step]` returns a new space with the
    selected elements in slice order. `space[range(...)]` returns a new
    space with the range-selected elements. `space[[i, j, ...]]` returns a
    new space with elements in explicit index order.

    Parameters
    ----------
    key : Union[int, slice, range, Sequence[int]]
        Index selector. Sequences must contain unique integers; negative
        integers are normalized relative to `len(self)`.

    Returns
    -------
    Spatial or StateSpace
        A spatial element for `int` indexing, otherwise a new instance of the
        same class containing the selected elements. Any extra dataclass fields
        on subclasses are preserved in the returned instance.

    Raises
    ------
    IndexError
        If an integer index is out of bounds.
    TypeError
        If `key` is not an `int`, `slice`, `range`, or sequence of integers.
    ValueError
        If a sequence selector contains duplicate indices.
    """
    if isinstance(key, int):
        if key < 0:
            key += len(self.structure)
        if key < 0 or key >= len(self.structure):
            raise IndexError("StateSpace index out of range")
        return next(islice(self.structure.keys(), key, None))
    if isinstance(key, slice):
        keys = tuple(self.structure.keys())[key]
        new_structure = OrderedDict((k, self.structure[k]) for k in keys)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, range):
        keys = tuple(self.structure.keys())
        new_structure = OrderedDict((keys[i], self.structure[keys[i]]) for i in key)
        return replace(self, structure=restructure(new_structure))
    if isinstance(key, Sequence) and not isinstance(key, (str, bytes)):
        keys = tuple(self.structure.keys())
        indices: list[int] = []
        seen = set()
        for idx in key:
            if isinstance(idx, bool) or not isinstance(idx, int):
                raise TypeError(
                    "StateSpace sequence indices must contain only integers"
                )
            normalized = idx
            if normalized < 0:
                normalized += len(keys)
            if normalized < 0 or normalized >= len(keys):
                raise IndexError("StateSpace index out of range")
            if normalized in seen:
                raise ValueError("StateSpace sequence indices must be unique")
            seen.add(normalized)
            indices.append(normalized)
        new_structure = OrderedDict(
            (keys[i], self.structure[keys[i]]) for i in indices
        )
        return replace(self, structure=restructure(new_structure))
    raise TypeError(
        "StateSpace indices must be int, slice, range, or a sequence of ints, "
        f"not {type(key)}"
    )

same_rays

same_rays(other: StateSpace) -> bool

Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

Parameters:

Name Type Description Default
other StateSpace

The other state space to compare against.

required

Returns:

Type Description
bool

True if both state spaces have the same rays, False otherwise.

Source code in src/qten/symbolics/state_space.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def same_rays(self, other: "StateSpace") -> bool:
    """
    Check if this state space has the same rays as another, i.e., they have the same set of spatial keys regardless of order.

    Parameters
    ----------
    other : StateSpace
        The other state space to compare against.

    Returns
    -------
    bool
        True if both state spaces have the same rays, `False` otherwise.
    """
    return same_rays(self, other)

map

map(func: Callable[[T], T]) -> Self

Map the spatial elements of this state space using a provided function.

Parameters:

Name Type Description Default
func Callable[[T], T]

A function that takes a spatial element and returns a transformed spatial element.

required

Returns:

Type Description
Self

A new state space with the transformed spatial elements.

Source code in src/qten/symbolics/state_space.py
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
def map(self, func: Callable[[T], T]) -> "Self":
    """
    Map the spatial elements of this state space using a provided function.

    Parameters
    ----------
    func : Callable[[T], T]
        A function that takes a spatial element and returns a transformed spatial element.

    Returns
    -------
    Self
        A new state space with the transformed spatial elements.
    """
    new_structure = OrderedDict()
    for k, s in self.structure.items():
        new_k = func(k)
        new_structure[new_k] = s
    return replace(self, structure=restructure(new_structure))

filter

filter(pred: Callable[[T], bool]) -> Self

Return the subspace containing elements where pred(element) is True.

Parameters:

Name Type Description Default
pred Callable[[T], bool]

Predicate applied to each element in basis order.

required

Returns:

Type Description
Self

A new state space of the same concrete type containing only the selected elements, with indices repacked contiguously.

Source code in src/qten/symbolics/state_space.py
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
def filter(self, pred: Callable[[T], bool]) -> "Self":
    """
    Return the subspace containing elements where `pred(element)` is `True`.

    Parameters
    ----------
    pred : Callable[[T], bool]
        Predicate applied to each element in basis order.

    Returns
    -------
    Self
        A new state space of the same concrete type containing only the
        selected elements, with indices repacked contiguously.
    """
    new_structure = OrderedDict(
        (k, s) for k, s in self.structure.items() if pred(k)
    )
    return replace(self, structure=restructure(new_structure))

extract

extract(info_type: type[Any]) -> Any

Extract an object implied by the elements of this state space.

Subclasses may register specialized implementations for supported target types.

Parameters:

Name Type Description Default
info_type type[Any]

Type of metadata or object to extract from this state space.

required

Returns:

Type Description
Any

Extracted object produced by a registered specialization.

Raises:

Type Description
NotImplementedError

If no extraction rule is registered for info_type.

Source code in src/qten/symbolics/state_space.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
@multimethod
def extract(self, info_type: type[Any]) -> Any:
    """
    Extract an object implied by the elements of this state space.

    Subclasses may register specialized implementations for supported
    target types.

    Parameters
    ----------
    info_type : type[Any]
        Type of metadata or object to extract from this state space.

    Returns
    -------
    Any
        Extracted object produced by a registered specialization.

    Raises
    ------
    NotImplementedError
        If no extraction rule is registered for `info_type`.
    """
    raise NotImplementedError(
        f"Extraction of {info_type} from {type(self)} is not supported!"
    )

__hash__

__hash__() -> int

Return a hash derived from the ordered Hilbert-space basis structure.

HilbertSpace uses the same structure-based hash as StateSpace. The hash includes each U1Basis sector and its stored integer basis index in insertion order. Consequently, two Hilbert spaces with the same sectors but different basis order hash differently.

Returns:

Type Description
int

Hash value for the ordered (U1Basis, index) mapping.

Source code in src/qten/symbolics/hilbert_space.py
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
def __hash__(self) -> int:
    """
    Return a hash derived from the ordered Hilbert-space basis structure.

    [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] uses the
    same structure-based hash as
    [`StateSpace`][qten.symbolics.state_space.StateSpace]. The hash includes
    each [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] sector and its
    stored integer basis index in insertion order. Consequently, two
    Hilbert spaces with the same sectors but different basis order hash
    differently.

    Returns
    -------
    int
        Hash value for the ordered `(U1Basis, index)` mapping.
    """
    return StateSpace.__hash__(self)

new staticmethod

new(itr: Iterable[U1Basis]) -> HilbertSpace

Build a HilbertSpace from an ordered basis iterable.

Parameters:

Name Type Description Default
itr Iterable[U1Basis]

Basis elements to insert into the space in iteration order. Each element is assigned its zero-based sector index according to its position in itr.

required

Returns:

Type Description
HilbertSpace

A new space whose structure maps each basis element from itr to its enumerated sector index.

Notes

Later duplicate keys in itr overwrite earlier entries in the backing OrderedDict, while preserving insertion order for the surviving key.

Source code in src/qten/symbolics/hilbert_space.py
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
@staticmethod
def new(itr: Iterable[U1Basis]) -> "HilbertSpace":
    """
    Build a [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] from an ordered basis iterable.

    Parameters
    ----------
    itr : Iterable[U1Basis]
        Basis elements to insert into the space in iteration order. Each
        element is assigned its zero-based sector index according to its
        position in `itr`.

    Returns
    -------
    HilbertSpace
        A new space whose `structure` maps each basis element from `itr` to
        its enumerated sector index.

    Notes
    -----
    Later duplicate keys in `itr` overwrite earlier entries in the backing
    `OrderedDict`, while preserving insertion order for the surviving key.
    """
    structure: OrderedDict[U1Basis, int] = OrderedDict()
    for i, el in enumerate(itr):
        structure[el] = i
    return HilbertSpace(structure=structure)

__str__

__str__() -> str

Return a compact Hilbert-space summary.

Returns:

Type Description
str

Summary containing total dimension and sector count.

Source code in src/qten/symbolics/hilbert_space.py
712
713
714
715
716
717
718
719
720
721
def __str__(self) -> str:
    """
    Return a compact Hilbert-space summary.

    Returns
    -------
    str
        Summary containing total dimension and sector count.
    """
    return f"HilbertSpace(dim={self.dim}, sectors={len(self.structure)})"

__repr__

__repr__() -> str

Return a multiline representation of indexed basis sectors.

Returns:

Type Description
str

Summary header plus one line per basis sector. Empty spaces are marked as <empty>.

Source code in src/qten/symbolics/hilbert_space.py
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
def __repr__(self) -> str:
    """
    Return a multiline representation of indexed basis sectors.

    Returns
    -------
    str
        Summary header plus one line per basis sector. Empty spaces are
        marked as `<empty>`.
    """
    if not self.structure:
        return f"{self}: <empty>"

    body = "\n".join(
        f"\t{n}: {idx} {str(el)}"
        for n, (el, idx) in enumerate(self.structure.items())
    )
    return f"{self}:\n{body}"

lookup

lookup(query: dict[type[Any], Any]) -> U1Basis

Return the unique element that exactly matches all typed-irrep query entries.

Parameters:

Name Type Description Default
query Dict[Type[Any], Any]

Mapping from irrep runtime type to expected irrep value. A candidate element matches only if, for every (T, value) pair, it contains an irrep of exact type T and irrep == value.

required

Returns:

Type Description
U1Basis

The unique matching element.

Raises:

Type Description
ValueError

If no element matches, if multiple elements match, or if query is empty.

Source code in src/qten/symbolics/hilbert_space.py
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
def lookup(self, query: Dict[Type[Any], Any]) -> U1Basis:
    """
    Return the unique element that exactly matches all typed-irrep query entries.

    Parameters
    ----------
    query : Dict[Type[Any], Any]
        Mapping from irrep runtime type to expected irrep value.
        A candidate element matches only if, for every `(T, value)` pair,
        it contains an irrep of exact type `T` and `irrep == value`.

    Returns
    -------
    U1Basis
        The unique matching element.

    Raises
    ------
    ValueError
        If no element matches, if multiple elements match, or if `query` is empty.
    """
    if not query:
        raise ValueError("lookup query cannot be empty.")

    matches: list[U1Basis] = []
    for el in self.elements():
        is_match = True
        for T, expected in query.items():
            try:
                actual = el.irrep_of(T)
            except ValueError:
                is_match = False
                break
            if actual != expected:
                is_match = False
                break
        if is_match:
            matches.append(el)

    if not matches:
        raise ValueError(f"No state found for query={query}.")
    if len(matches) > 1:
        raise ValueError(
            f"Multiple states found for query={query}; expected a unique match."
        )
    return matches[0]

group

group(
    **groups: Callable[[U1Basis], bool] | Any,
) -> FrozenDict[str, HilbertSpace]
Group basis elements into labeled subspaces.
Supported selectors

A Callable[[U1Basis], bool] selector includes states for which the predicate returns True. An irrep-object selector includes states whose irrep of the same exact runtime type equals the selector.

Parameters
**groups : Union[Callable[[U1Basis], bool], Any]
    Label-to-selector mapping used to build grouped subspaces.
Returns
FrozenDict[str, HilbertSpace]
    Frozen mapping from labels to grouped [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] values.
    Each grouped subspace is sorted in ascending [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] order.
Raises
ValueError
    If two selectors include the same basis state.
Source code in src/qten/symbolics/hilbert_space.py
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
def group(
    self, **groups: Union[Callable[[U1Basis], bool], Any]
) -> FrozenDict[str, "HilbertSpace"]:
    """
        Group basis elements into labeled subspaces.

    Supported selectors
    -------------------
    A `Callable[[U1Basis], bool]` selector includes states for which the
    predicate returns `True`. An irrep-object selector includes states whose
    irrep of the same exact runtime type equals the selector.

        Parameters
        ----------
        **groups : Union[Callable[[U1Basis], bool], Any]
            Label-to-selector mapping used to build grouped subspaces.

        Returns
        -------
        FrozenDict[str, HilbertSpace]
            Frozen mapping from labels to grouped [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] values.
            Each grouped subspace is sorted in ascending [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] order.

        Raises
        ------
        ValueError
            If two selectors include the same basis state.
    """
    elements = self.elements()

    grouped_by_label: OrderedDict[str, HilbertSpace] = OrderedDict()
    grouped_union: set[U1Basis] = set()

    for label, selector in groups.items():
        if callable(selector):
            pred = cast(Callable[[U1Basis], bool], selector)
            selected = tuple(el for el in elements if pred(el))
        else:
            target = selector
            target_type = type(target)
            selected_list: list[U1Basis] = []
            for el in elements:
                try:
                    if el.irrep_of(target_type) == target:
                        selected_list.append(el)
                except ValueError:
                    continue
            selected = tuple(selected_list)
        grouped_elements = tuple(sorted(selected))
        overlap = tuple(el for el in grouped_elements if el in grouped_union)
        if overlap:
            raise ValueError(
                f"grouped spans overlap: state {overlap[0]!r} appears in multiple groups (including {label!r})."
            )

        grouped_union.update(grouped_elements)
        grouped_by_label[label] = HilbertSpace.new(grouped_elements)

    return FrozenDict(grouped_by_label)

group_by

group_by(*T: type) -> tuple[HilbertSpace, ...]

Form groups by matching irrep types keyed by the irreps.

This function will try to group the basis by the irrep in order specified by the types in T.

Parameters:

Name Type Description Default
*T Type

The irrep types to group by. The grouping will be performed in the order of the types specified. For example group_by(A, B) will group the basis by (A, B), and basis states with the same irrep of A and B will be in the same grouped subspace.

()

Returns:

Type Description
Tuple[HilbertSpace, ...]

Grouped subspaces in the order their irrep keys first appear in the current basis order.

Source code in src/qten/symbolics/hilbert_space.py
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
def group_by(self, *T: Type) -> Tuple["HilbertSpace", ...]:
    """
    Form groups by matching irrep types keyed by the irreps.

    This function will try to group the basis by the irrep in order specified by the types in `T`.

    Parameters
    ----------
    *T : Type
        The irrep types to group by. The grouping will be performed in the order of the types specified.
        For example [`group_by(A, B)`][qten.symbolics.hilbert_space.HilbertSpace.group_by] will group the basis by `(A, B)`, and
        basis states with the same irrep of `A` and `B` will be in the same
        grouped subspace.

    Returns
    -------
    Tuple[HilbertSpace, ...]
        Grouped subspaces in the order their irrep keys first appear in the
        current basis order.
    """
    keys: OrderedDict[Tuple[Any, ...], None] = OrderedDict()
    for el in self.elements():
        keys[tuple(el.irrep_of(t) for t in T)] = None

    def make_selector(key: Tuple[Any, ...]) -> Callable[[U1Basis], bool]:
        def selector(el: U1Basis) -> bool:
            return all(el.irrep_of(t) == target for t, target in zip(T, key))

        return selector

    selectors: OrderedDict[str, Callable[[U1Basis], bool]] = OrderedDict()
    for i, key in enumerate(keys):
        selectors[f"_{i}"] = make_selector(key)

    result = self.group(**selectors)
    return tuple(result[label] for label in selectors)

is_homogeneous

is_homogeneous() -> bool

Check if this HilbertSpace is homogeneous, i.e., all basis states share the same irrep types.

Returns:

Type Description
bool

True if all basis states in this HilbertSpace have the same set of irrep types, False otherwise.

Source code in src/qten/symbolics/hilbert_space.py
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
def is_homogeneous(self) -> bool:
    """
    Check if this [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] is homogeneous, i.e., all basis states share the same irrep types.

    Returns
    -------
    bool
        True if all basis states in this [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] have the same set of irrep types, `False` otherwise.
    """
    elements = self.elements()
    if not elements:  # An empty Hilbert space is considered homogeneous.
        return True
    irrep_types = elements[0].repr_types()
    for el in elements[1:]:
        if el.repr_types() != irrep_types:
            return False
    return True

canonical_basis_types

canonical_basis_types() -> tuple[type[Any], ...]

Return the canonical irrep-type order shared by this HilbertSpace basis.

A homogeneous Hilbert space has one consistent irrep-type layout across all basis states (for example (int, str) for every element). This method returns that layout in canonical order.

For an empty space, the result is the empty tuple ().

Returns:

Type Description
Tuple[Type[Any], ...]

The canonical irrep-type sequence of the basis representation.

Raises:

Type Description
ValueError

If this space is not homogeneous, i.e. basis states do not share the same canonical irrep-type order.

Source code in src/qten/symbolics/hilbert_space.py
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
def canonical_basis_types(self) -> Tuple[Type[Any], ...]:
    """
    Return the canonical irrep-type order shared by this [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] basis.

    A homogeneous Hilbert space has one consistent irrep-type layout across all
    basis states (for example `(int, str)` for every element). This method
    returns that layout in canonical order.

    For an empty space, the result is the empty tuple `()`.

    Returns
    -------
    Tuple[Type[Any], ...]
        The canonical irrep-type sequence of the basis representation.

    Raises
    ------
    ValueError
        If this space is not homogeneous, i.e. basis states do not share the
        same canonical irrep-type order.
    """
    if not self.is_homogeneous():
        raise ValueError(
            "Cannot get basis irrep types of a non-homogeneous HilbertSpace."
        )
    elements = self.elements()
    if not elements:
        return ()
    return elements[0].repr_types()

irrep_of

irrep_of(T: Type[_IrrepType]) -> Tuple[_IrrepType, ...]

Return the irrep of type T for each basis state in this space.

This is the HilbertSpace analogue of U1Basis.irrep_of(T), lifted across the ordered basis of the space.

Parameters:

Name Type Description Default
T Type[_IrrepType]

Concrete irrep type to retrieve.

required

Returns:

Type Description
Tuple[_IrrepType, ...]

The irrep instance of type T for each basis state, in basis order.

Raises:

Type Description
ValueError

If any basis state does not contain an irrep of type T.

Source code in src/qten/symbolics/hilbert_space.py
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
def irrep_of(self, T: Type[_IrrepType]) -> Tuple[_IrrepType, ...]:
    """
    Return the irrep of type `T` for each basis state in this space.

    This is the [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] analogue of `U1Basis.irrep_of(T)`, lifted
    across the ordered basis of the space.

    Parameters
    ----------
    T : Type[_IrrepType]
        Concrete irrep type to retrieve.

    Returns
    -------
    Tuple[_IrrepType, ...]
        The irrep instance of type `T` for each basis state, in basis order.

    Raises
    ------
    ValueError
        If any basis state does not contain an irrep of type `T`.
    """
    return tuple(el.irrep_of(T) for el in self.elements())

factorize

factorize(
    *irrep_types: tuple[type, ...],
    coef_on: int | None = None,
) -> StateSpaceFactorization

Factorize a homogeneous Hilbert space into irrep-type tensor factors.

Each argument in irrep_types defines one output factor as a tuple of irrep types to group together. Across all groups, every irrep type in this space must appear exactly once. The result describes both the factor spaces and the basis reindexing needed to move between the original basis order and the factorized tensor-product structure.

Mathematical convention

For a homogeneous basis whose labels split into groups \(a\) and \(b\), factorization checks that the basis is a complete Cartesian product: \(\mathcal{H} \cong \mathcal{H}_a \otimes \mathcal{H}_b\), with \(|a_i,b_j\rangle \leftrightarrow |a_i\rangle \otimes |b_j\rangle\). More generally, the requested irrep_types define factors \(\mathcal{H}_0,\ldots,\mathcal{H}_{m-1}\). The returned align_dim is the original basis reordered so that its flattened order matches factorized[0] @ ... @ factorized[m-1] in code.

Notes

The input space must be homogeneous, meaning every U1Basis element has the same canonical irrep-type layout. The basis must also be a complete Cartesian product for the requested groups. For example, if factors are (int,) and (str,), then every observed integer label must appear with every observed string label.

coef_on controls which output factor receives the original U1Basis.coef. All other factors are built with coefficient 1. This is valid only when the chosen factor uniquely determines each original coefficient.

Parameters:

Name Type Description Default
*irrep_types Tuple[Type, ...]

Factor specification. Each tuple is one output factor containing the irrep types assigned to that factor. Every irrep type present in this homogeneous space must appear exactly once across all factor specifications.

()
coef_on Optional[int]

Index of the factor that inherits the original U1Basis.coef. None defaults to the leftmost factor (0). Negative indices are interpreted using normal Python indexing. All other factors are built with coefficient 1.

None

Returns:

Type Description
StateSpaceFactorization

Factorization metadata. factorized contains the output factor spaces in the same order as irrep_types. align_dim is a permutation of the original Hilbert space whose flattened order is compatible with reshaping into the tensor product of factorized.

Raises:

Type Description
ValueError

If the space is not homogeneous.

ValueError

If the space is empty and non-empty factor groups were requested.

ValueError

If any requested factor group is empty.

ValueError

If an irrep type is missing, duplicated, or not present in the homogeneous basis.

ValueError

If coef_on is out of range.

ValueError

If the chosen coef_on factor does not determine a unique coefficient.

ValueError

If the basis is not a complete Cartesian product for the requested groups.

Examples:

Suppose a Hilbert-space basis is labeled by two independent pieces of information: a site index (int) and an orbital label (str). The four basis states below form a complete product of two sites and two orbitals:

import sympy as sy
from qten.symbolics import HilbertSpace, U1Basis

space = HilbertSpace.new(
    U1Basis(sy.Integer(1), (i, label))
    for i in (1, 2)
    for label in ("a", "b")
)

factorization = space.factorize((int,), (str,))

The first factor contains the unique site labels. The second factor contains the unique orbital labels:

site_factor, orbital_factor = factorization.factorized

assert tuple(state.base for state in site_factor.elements()) == (
    (1,),
    (2,),
)
assert tuple(state.base for state in orbital_factor.elements()) == (
    ("a",),
    ("b",),
)

align_dim records the original basis order arranged so it can be reshaped as site_factor @ orbital_factor. In this example the input was already in product order, so align_dim has the same basis labels:

assert tuple(state.base for state in factorization.align_dim.elements()) == (
    (1, "a"),
    (1, "b"),
    (2, "a"),
    (2, "b"),
)

Factorization fails if the space is not homogeneous, if the requested groups omit or add irrep types, if coef_on is out of range, if coefficient assignment is ambiguous, or if the basis is not a complete Cartesian product for the requested groups. For example, a basis with (1, "a"), (1, "b"), (2, "a"), (2, "b"), and (2, "c") cannot factorize by (int,) and (str,) because the product would also require (1, "c").

Source code in src/qten/symbolics/hilbert_space.py
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
def factorize(
    self, *irrep_types: Tuple[Type, ...], coef_on: Optional[int] = None
) -> StateSpaceFactorization:
    r"""
    Factorize a homogeneous Hilbert space into irrep-type tensor factors.

    Each argument in `irrep_types` defines one output factor as a tuple of
    irrep types to group together. Across all groups, every irrep type in
    this space must appear exactly once. The result describes both the
    factor spaces and the basis reindexing needed to move between the
    original basis order and the factorized tensor-product structure.

    Mathematical convention
    -----------------------
    For a homogeneous basis whose labels split into groups \(a\) and \(b\),
    factorization checks that the basis is a complete Cartesian product:
    \(\mathcal{H} \cong \mathcal{H}_a \otimes \mathcal{H}_b\), with
    \(|a_i,b_j\rangle \leftrightarrow |a_i\rangle \otimes |b_j\rangle\).
    More generally, the requested `irrep_types` define factors
    \(\mathcal{H}_0,\ldots,\mathcal{H}_{m-1}\). The returned `align_dim`
    is the original basis reordered so that its flattened order matches
    `factorized[0] @ ... @ factorized[m-1]` in code.

    Notes
    -----
    The input space must be homogeneous, meaning every
    [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] element has the same
    canonical irrep-type layout. The basis must also be a complete
    Cartesian product for the requested groups. For example, if factors are
    `(int,)` and `(str,)`, then every observed integer label must appear
    with every observed string label.

    `coef_on` controls which output factor receives the original
    [`U1Basis.coef`][qten.symbolics.hilbert_space.U1Basis.coef]. All other
    factors are built with coefficient `1`. This is valid only when the
    chosen factor uniquely determines each original coefficient.

    Parameters
    ----------
    *irrep_types : Tuple[Type, ...]
        Factor specification. Each tuple is one output factor containing
        the irrep types assigned to that factor. Every irrep type present
        in this homogeneous space must appear exactly once across all
        factor specifications.
    coef_on : Optional[int], optional
        Index of the factor that inherits the original `U1Basis.coef`.
        `None` defaults to the leftmost factor (`0`). Negative indices are
        interpreted using normal Python indexing. All other factors are
        built with coefficient `1`.

    Returns
    -------
    StateSpaceFactorization
        Factorization metadata. `factorized` contains the output factor
        spaces in the same order as `irrep_types`. `align_dim` is a
        permutation of the original Hilbert space whose flattened order is
        compatible with reshaping into the tensor product of `factorized`.

    Raises
    ------
    ValueError
        If the space is not homogeneous.
    ValueError
        If the space is empty and non-empty factor groups were requested.
    ValueError
        If any requested factor group is empty.
    ValueError
        If an irrep type is missing, duplicated, or not present in the
        homogeneous basis.
    ValueError
        If `coef_on` is out of range.
    ValueError
        If the chosen `coef_on` factor does not determine a unique
        coefficient.
    ValueError
        If the basis is not a complete Cartesian product for the requested
        groups.

    Examples
    --------
    Suppose a Hilbert-space basis is labeled by two independent pieces of
    information: a site index (`int`) and an orbital label (`str`). The
    four basis states below form a complete product of two sites and two
    orbitals:

    ```python
    import sympy as sy
    from qten.symbolics import HilbertSpace, U1Basis

    space = HilbertSpace.new(
        U1Basis(sy.Integer(1), (i, label))
        for i in (1, 2)
        for label in ("a", "b")
    )

    factorization = space.factorize((int,), (str,))
    ```

    The first factor contains the unique site labels. The second factor
    contains the unique orbital labels:

    ```python
    site_factor, orbital_factor = factorization.factorized

    assert tuple(state.base for state in site_factor.elements()) == (
        (1,),
        (2,),
    )
    assert tuple(state.base for state in orbital_factor.elements()) == (
        ("a",),
        ("b",),
    )
    ```

    `align_dim` records the original basis order arranged so it can be
    reshaped as `site_factor @ orbital_factor`. In this example the input
    was already in product order, so `align_dim` has the same basis labels:

    ```python
    assert tuple(state.base for state in factorization.align_dim.elements()) == (
        (1, "a"),
        (1, "b"),
        (2, "a"),
        (2, "b"),
    )
    ```

    Factorization fails if the space is not homogeneous, if the requested
    groups omit or add irrep types, if `coef_on` is out of range, if
    coefficient assignment is ambiguous, or if the basis is not a complete
    Cartesian product for the requested groups. For example, a basis with
    `(1, "a")`, `(1, "b")`, `(2, "a")`, `(2, "b")`, and `(2, "c")` cannot
    factorize by `(int,)` and `(str,)` because the product would also
    require `(1, "c")`.
    """
    if not self.is_homogeneous():
        raise ValueError("Cannot factorize a non-homogeneous HilbertSpace.")

    elements = self.elements()
    if not elements:
        if irrep_types:
            raise ValueError(
                "Cannot factorize an empty HilbertSpace with non-empty irrep groups."
            )
        return StateSpaceFactorization(factorized=(), align_dim=self)

    if any(not group for group in irrep_types):
        raise ValueError("Each irrep group in factorize must be non-empty.")

    if coef_on is None:
        coef_factor = 0
    else:
        coef_factor = coef_on
        if coef_factor < 0:
            coef_factor += len(irrep_types)
        if coef_factor < 0 or coef_factor >= len(irrep_types):
            raise ValueError(
                f"`coef_on` index {coef_on} is out of range for {len(irrep_types)} factors."
            )

    canonical_types = elements[0].repr_types()
    requested_types = tuple(T for group in irrep_types for T in group)
    requested_set = set(requested_types)
    canonical_set = set(canonical_types)

    if len(requested_set) != len(requested_types):
        raise ValueError(
            "Each irrep type must appear exactly once in `irrep_types`."
        )

    missing_types = tuple(
        T.__name__ for T in canonical_types if T not in requested_set
    )
    extra_types = tuple(
        T.__name__ for T in requested_types if T not in canonical_set
    )
    if missing_types or extra_types:
        details = []
        if missing_types:
            details.append(f"missing types: {missing_types}")
        if extra_types:
            details.append(f"extra types: {extra_types}")
        raise ValueError(
            f"`irrep_types` does not match space irrep types ({', '.join(details)})."
        )

    factor_keys: list[Tuple[Tuple[Any, ...], ...]] = []
    factorized: list[HilbertSpace] = []
    for group_idx, group in enumerate(irrep_types):
        keys: OrderedDict[Tuple[Any, ...], sy.Expr] = OrderedDict()
        for el in elements:
            key = tuple(el.irrep_of(T) for T in group)
            coef = el.coef if group_idx == coef_factor else sy.Integer(1)
            if key in keys and keys[key] != coef:
                raise ValueError(
                    "Requested factorization is not valid: "
                    "the requested `coef_on` factor does not determine a unique coefficient."
                )
            keys[key] = coef
        grouped_basis = tuple(
            U1Basis(coef, tuple(key)) for key, coef in keys.items()
        )
        factor_keys.append(tuple(keys.keys()))
        factorized.append(HilbertSpace.new(grouped_basis))

    # Map each basis state to its grouped-irrep key tuple.
    combo_to_element: OrderedDict[Tuple[Tuple[Any, ...], ...], U1Basis] = (
        OrderedDict()
    )
    for el in elements:
        combo = tuple(tuple(el.irrep_of(T) for T in group) for group in irrep_types)
        combo_to_element[combo] = el

    expected_size = 1
    for group_keys in factor_keys:
        expected_size *= len(group_keys)
    if expected_size != len(combo_to_element):
        raise ValueError(
            "Requested factorization is not valid: basis is not a complete Cartesian product."
        )

    # Build reshape-compatible order: first factor varies slowest, last varies fastest.
    align_elements: list[U1Basis] = []
    for combo in product(*factor_keys):
        if combo not in combo_to_element:
            raise ValueError(
                "Requested factorization is not valid: basis is not a complete Cartesian product."
            )
        align_elements.append(combo_to_element[combo])

    return StateSpaceFactorization(
        factorized=tuple(factorized),
        align_dim=HilbertSpace.new(align_elements),
    )

tensor_product

tensor_product(other: HilbertSpace) -> HilbertSpace

Build the tensor-product space of this space with another HilbertSpace.

The resulting basis is generated by taking every ordered pair (a, b) from self.elements() and other.elements(), then forming the basis-level tensor product a @ b for each pair.

Mathematically, if \(\mathcal{H}_L = \mathrm{span}\{|a_i\rangle\}\) and \(\mathcal{H}_R = \mathrm{span}\{|b_j\rangle\}\), then the result is ordered as \(\mathcal{H}_L \otimes \mathcal{H}_R = \mathrm{span}\{|a_i\rangle \otimes |b_j\rangle\}_{i,j}\). Ordering follows itertools.product(self.elements(), other.elements()): basis elements from self vary slowest, and basis elements from other vary fastest. This deterministic order is important for tensor reshape and alignment logic that depends on stable axis conventions.

Parameters:

Name Type Description Default
other HilbertSpace

Right-hand tensor factor.

required

Returns:

Type Description
HilbertSpace

A new space whose basis spans self ⊗ other.

Source code in src/qten/symbolics/hilbert_space.py
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
@override
def tensor_product(self, other: "HilbertSpace") -> "HilbertSpace":
    r"""
    Build the tensor-product space of this space with another [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace].

    The resulting basis is generated by taking every ordered pair
    `(a, b)` from `self.elements()` and `other.elements()`, then forming the
    basis-level tensor product `a @ b` for each pair.

    Mathematically, if
    \(\mathcal{H}_L = \mathrm{span}\{|a_i\rangle\}\) and
    \(\mathcal{H}_R = \mathrm{span}\{|b_j\rangle\}\), then the result is
    ordered as \(\mathcal{H}_L \otimes \mathcal{H}_R
    = \mathrm{span}\{|a_i\rangle \otimes |b_j\rangle\}_{i,j}\).
    Ordering follows `itertools.product(self.elements(), other.elements())`:
    basis elements from `self` vary slowest, and basis elements from `other`
    vary fastest. This deterministic order is important for tensor reshape
    and alignment logic that depends on stable axis conventions.

    Parameters
    ----------
    other : HilbertSpace
        Right-hand tensor factor.

    Returns
    -------
    HilbertSpace
        A new space whose basis spans `self ⊗ other`.
    """
    elements = []
    for a, b in product(self.elements(), other.elements()):
        elements.append(a @ b)
    return HilbertSpace.new(elements)

rays

rays() -> HilbertSpace

Return the Hilbert space obtained by ray-normalizing every basis state.

The output keeps the same basis order after converting each U1Basis element to element.rays(). This removes U(1) coefficients from the symbolic basis labels while preserving the projective sector structure.

In formula form: \(\{c_i|\rho_i\rangle\}_i \longmapsto \{|\rho_i\rangle\}_i\).

Returns:

Type Description
HilbertSpace

Hilbert space built from the ray representatives of this space's basis elements.

Examples:

import sympy as sy
from sympy import ImmutableDenseMatrix
from qten.geometries import AffineSpace, Offset
from qten.symbolics import HilbertSpace, U1Basis

affine = AffineSpace(ImmutableDenseMatrix.eye(1))
r0 = Offset(ImmutableDenseMatrix([0]), affine)
hilbert = HilbertSpace.new((U1Basis(sy.Integer(5), (r0,)),))
ray_space = hilbert.rays()

assert ray_space.elements()[0].coef == 1
Source code in src/qten/symbolics/hilbert_space.py
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
@override
def rays(self) -> "HilbertSpace":
    r"""
    Return the Hilbert space obtained by ray-normalizing every basis state.

    The output keeps the same basis order after converting each
    [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] element to
    `element.rays()`. This removes U(1) coefficients from the symbolic
    basis labels while preserving the projective sector structure.

    In formula form:
    \(\{c_i|\rho_i\rangle\}_i \longmapsto \{|\rho_i\rangle\}_i\).

    Returns
    -------
    HilbertSpace
        Hilbert space built from the ray representatives of this space's
        basis elements.

    Examples
    --------
    ```python
    import sympy as sy
    from sympy import ImmutableDenseMatrix
    from qten.geometries import AffineSpace, Offset
    from qten.symbolics import HilbertSpace, U1Basis

    affine = AffineSpace(ImmutableDenseMatrix.eye(1))
    r0 = Offset(ImmutableDenseMatrix([0]), affine)
    hilbert = HilbertSpace.new((U1Basis(sy.Integer(5), (r0,)),))
    ray_space = hilbert.rays()

    assert ray_space.elements()[0].coef == 1
    ```
    """
    return HilbertSpace.new(el.rays() for el in self)

cross_gram

cross_gram(
    another: HilbertSpace, *, device: Device | None = None
) -> Tensor

Build the cross-Gram overlap matrix between this basis and another basis.

Matrix entries are computed from concrete basis overlaps \(G_{ij} = \langle \mathrm{self}_i \mid \mathrm{another}_j \rangle\), so any nontrivial U(1) irrep phase in basis vectors is encoded in data.

Output dimension convention

The returned tensor uses dims (self, another.rays()). The target (column) dimension is intentionally replaced by its canonical ray representative (phase removed) so the codomain metadata is gauge-fixed, while phase information remains in matrix elements.

This is equivalent to using a representative of the same ray space (projective Hilbert space) for the target basis labels.

Parameters:

Name Type Description Default
another HilbertSpace

Right-hand basis supplying ket states.

required
device Optional[Device]

Device on which to allocate the returned tensor data.

None

Returns:

Type Description
Tensor

Matrix tensor with dims (self, another.rays()).

Source code in src/qten/symbolics/hilbert_space.py
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
def cross_gram(
    self, another: "HilbertSpace", *, device: Optional[Device] = None
) -> Tensor:
    r"""
    Build the cross-Gram overlap matrix between this basis and another basis.

    Matrix entries are computed from concrete basis overlaps
    \(G_{ij} = \langle \mathrm{self}_i \mid \mathrm{another}_j \rangle\),
    so any nontrivial U(1) irrep phase in basis vectors is encoded in
    `data`.

    Output dimension convention
    ---------------------------
    The returned tensor uses dims `(self, another.rays())`.
    The target (column) dimension is intentionally replaced by its canonical
    ray representative (phase removed)
    so the codomain metadata is gauge-fixed, while phase information remains
    in matrix elements.

    This is equivalent to using a representative of the same ray space
    (projective Hilbert space) for the target basis labels.

    Parameters
    ----------
    another : HilbertSpace
        Right-hand basis supplying ket states.
    device : Optional[Device], optional
        Device on which to allocate the returned tensor data.

    Returns
    -------
    Tensor
        Matrix tensor with dims `(self, another.rays())`.
    """
    span = U1Span(cast(Tuple[U1Basis, ...], self.elements()))
    new_span = U1Span(cast(Tuple[U1Basis, ...], another.elements()))
    irrep = span.cross_gram(new_span)
    precision = get_precision_config()
    torch_device = device.torch_device() if device is not None else None
    data = torch.from_numpy(
        np.asarray(irrep.tolist(), dtype=precision.np_complex)
    ).to(device=torch_device, dtype=precision.torch_complex)
    return Tensor(data=data, dims=(self, another.rays()))

Opr dataclass

Opr()

Bases: Functional, Operable, ABC

A composable operator that acts on observable-compatible objects.

Operator combines two core behaviors:

The first behavior is Functional dispatch and chaining. Implementations are registered via Functional.register for pairs of (input_type, operator_subclass). At runtime, invoke resolves the function chain for the concrete input object and executes each function in order.

The second behavior is Operable matrix-application syntax. Because Operator is Operable, it participates in the overloaded @ operator. This module defines Operable.__matmul__(Operator, U1Basis), so op @ value applies the operator and returns only the transformed value component.

Conceptually, an operator application returns either a transformed object of the same runtime type as the input, or Multiple(coef, transformed_object) when the action also contributes a scalar prefactor.

The Multiple form is used when the operator naturally decomposes into a scalar factor times an object in the same representation family. Typical examples include phase factors, characters, gauge coefficients, and other symbolic amplitudes that should stay factored instead of being folded directly into the transformed object.

Implementation Guidelines

A registered handler should return a plain transformed object when the operator acts without producing an extra scalar factor. It should return Multiple(coef, value) when the action produces a scalar prefactor that should remain explicit. In both cases, the underlying transformed value must stay in the same representation family as the input: plain returns should have type(result) is type(input) or a compatible subclass, while multiple returns should have type(result.base) is type(input) or a compatible subclass.

Opr.invoke automatically lifts operators over Multiple. If op(base) -> y, then op(Multiple(c, base)) -> Multiple(c, y). If op(base) -> Multiple(c2, y), the coefficients are multiplied to produce Multiple(simplify(c * c2), y).

For symbolic container inputs such as U1Basis, U1Span, and HilbertSpace, the generic Opr lifting in this module expects the final result to stay in-kind and not return Multiple at the top level. Scalar factors should instead be attached to the contained irreps/components and accumulated into the container's internal coefficient structure.

This module provides generic Opr registrations for U1Basis, U1Span, and HilbertSpace. Subclasses inherit those handlers through Functional MRO fallback unless they define more specific registrations. If no registration exists for (type(input), type(operator)) after MRO fallback on both the input type and the operator type, Functional.invoke raises NotImplementedError.

Usage Pattern

Define an Operator subclass, register behavior with @YourOperatorSubclass.register(InputType), and apply it either as out = op(input_obj) to receive the transformed value or as out = op @ input_obj using infix syntax.

Return-value Guidance

Return value when the operator only changes the representation/object itself. Return Multiple(coef, value) when the operator contributes a symbolic scalar prefactor that should remain factored.

In particular, for atomic irreps or basis-function-like objects, returning Multiple is often appropriate. For higher-level symbolic containers such as U1Basis, U1Span, and HilbertSpace, prefer returning the same container type directly and let the generic lifting logic accumulate scalar factors internally.

register classmethod

register(obj_type: type)

Register a function defining the action of the Functional on a specific object type.

This method returns a decorator. The decorated function should accept the functional instance as its first argument and an object of obj_type as its second argument. Any keyword arguments passed to invoke() are forwarded to the decorated function.

Dispatch is resolved at call time via MRO, so only the exact (obj_type, cls) key is stored here. Resolution later searches both:

  • the MRO of the runtime object type,
  • the MRO of the runtime functional type.

This means registrations on a functional superclass are inherited by subclass functionals unless a more specific registration overrides them.

Parameters:

Name Type Description Default
obj_type type

The type of object the function applies to.

required

Returns:

Type Description
Callable

A decorator that registers the function for the specified object type.

Examples:

@MyFunctional.register(MyObject)
def _(functional: MyFunctional, obj: MyObject) -> MyObject:
    ...
Source code in src/qten/abstracts.py
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
@classmethod
def register(cls, obj_type: type):
    """
    Register a function defining the action of the [`Functional`][qten.abstracts.Functional] on a specific object type.

    This method returns a decorator. The decorated function should accept
    the functional instance as its first argument and an object of
    `obj_type` as its second argument. Any keyword arguments passed to
    [`invoke()`][qten.abstracts.Functional.invoke] are forwarded to the
    decorated function.

    Dispatch is resolved at call time via MRO, so only the exact
    `(obj_type, cls)` key is stored here. Resolution later searches both:

    - the MRO of the runtime object type,
    - the MRO of the runtime functional type.

    This means registrations on a functional superclass are inherited by
    subclass functionals unless a more specific registration overrides them.

    Parameters
    ----------
    obj_type : type
        The type of object the function applies to.

    Returns
    -------
    Callable
        A decorator that registers the function for the specified object type.

    Examples
    --------
    ```python
    @MyFunctional.register(MyObject)
    def _(functional: MyFunctional, obj: MyObject) -> MyObject:
        ...
    ```
    """

    def decorator(func: Callable):
        cls._registered_methods[(obj_type, cls)] = func
        cls._invalidate_resolved_methods(obj_type)
        return func

    return decorator

get_applicable_types staticmethod

get_applicable_types() -> tuple[type, ...]

Get all object types that can be applied by this Functional.

Parameters:

Name Type Description Default
cls Type[Functional]

Functional class whose direct registrations should be inspected.

required

Returns:

Type Description
Tuple[Type, ...]

A tuple of all registered object types that this Functional can handle.

Source code in src/qten/abstracts.py
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
@staticmethod
def get_applicable_types(cls) -> Tuple[Type, ...]:
    """
    Get all object types that can be applied by this [`Functional`][qten.abstracts.Functional].

    Parameters
    ----------
    cls : Type[Functional]
        Functional class whose direct registrations should be inspected.

    Returns
    -------
    Tuple[Type, ...]
        A tuple of all registered object types that this [`Functional`][qten.abstracts.Functional] can handle.
    """
    types = set()
    for obj_type, functional_type in cls._registered_methods.keys():
        if functional_type is cls:
            types.add(obj_type)
    return tuple(types)

allows

allows(obj: Any) -> bool

Check if this Functional can be applied on the given object.

Parameters:

Name Type Description Default
obj Any

The object to check for applicability.

required

Returns:

Type Description
bool

True if this Functional can be applied on the object, False otherwise.

Notes

Applicability is checked using the same inherited dispatch rules as invoke(): both the object's MRO and the functional-class MRO are searched.

Source code in src/qten/abstracts.py
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
def allows(self, obj: Any) -> bool:
    """
    Check if this [`Functional`][qten.abstracts.Functional] can be applied on the given object.

    Parameters
    ----------
    obj : Any
        The object to check for applicability.

    Returns
    -------
    bool
        True if this [`Functional`][qten.abstracts.Functional] can be applied on the object, False otherwise.

    Notes
    -----
    Applicability is checked using the same inherited dispatch rules as
    [`invoke()`][qten.abstracts.Functional.invoke]: both the object's MRO
    and the functional-class MRO are searched.
    """
    return self._resolve_method(type(obj), type(self)) is not None

__call__

__call__(obj: Any, **kwargs) -> Any

Apply this functional to obj.

This is a thin wrapper around invoke().

Parameters:

Name Type Description Default
obj Any

Runtime object to dispatch on.

required
**kwargs Any

Additional keyword arguments forwarded to the resolved implementation.

{}

Returns:

Type Description
Any

Result produced by the resolved registered method.

Raises:

Type Description
NotImplementedError

If no registration exists for the runtime pair after MRO fallback.

See Also

invoke(obj, **kwargs) Full dispatch method used by this call wrapper.

Source code in src/qten/abstracts.py
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
def __call__(self, obj: Any, **kwargs) -> Any:
    """
    Apply this functional to `obj`.

    This is a thin wrapper around [`invoke()`][qten.abstracts.Functional.invoke].

    Parameters
    ----------
    obj : Any
        Runtime object to dispatch on.
    **kwargs : Any
        Additional keyword arguments forwarded to the resolved
        implementation.

    Returns
    -------
    Any
        Result produced by the resolved registered method.

    Raises
    ------
    NotImplementedError
        If no registration exists for the runtime pair after MRO fallback.

    See Also
    --------
    [`invoke(obj, **kwargs)`][qten.abstracts.Functional.invoke]
        Full dispatch method used by this call wrapper.
    """
    return self.invoke(obj, **kwargs)

invoke

invoke(v: _T, **kwargs: Any) -> _T | Multiple[_T]

Apply the operator while preserving QTen's symbolic output invariants.

Parameters:

Name Type Description Default
v _T

Input object to transform.

required
**kwargs Any

Extra keyword arguments forwarded to the resolved registration.

{}

Returns:

Type Description
_T | Multiple[_T]

Transformed object, or a factored result carrying an explicit scalar coefficient.

Raises:

Type Description
AssertionError

If a registered implementation returns a value outside the expected same-type / Multiple[same-type] contract.

Source code in src/qten/symbolics/hilbert_space.py
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
@override
def invoke(  # type: ignore[override]
    self, v: _T, **kwargs
) -> Union[_T, Multiple[_T]]:
    """
    Apply the operator while preserving QTen's symbolic output invariants.

    Parameters
    ----------
    v : _T
        Input object to transform.
    **kwargs : Any
        Extra keyword arguments forwarded to the resolved registration.

    Returns
    -------
    _T | Multiple[_T]
        Transformed object, or a factored result carrying an explicit
        scalar coefficient.

    Raises
    ------
    AssertionError
        If a registered implementation returns a value outside the expected
        same-type / `Multiple[same-type]` contract.
    """
    if type(v) is Multiple:
        result = super().invoke(v.base, **kwargs)
        if type(result) is Multiple:
            return Multiple((v.coef * result.coef).simplify(), result.base)
        return Multiple(v.coef, result)
    result = super().invoke(v, **kwargs)
    if isinstance(v, (U1Basis, U1Span, HilbertSpace)):
        assert type(result) is not Multiple, (
            f"Operator {type(self)} acting on {type(v).__name__} should not yield a Multiple!"
        )
    assert isinstance(result, type(v)) or (
        type(result) is Multiple and isinstance(result.base, type(v))
    ), (
        f"Operator {type(self)} acting on {type(v).__name__} should yield same typed object"
        f"or Multiple[{type(v).__name__}]"
    )
    return result

U1Basis dataclass

U1Basis(coef: Number, base: BaseType)

Bases: Spatial, Multiple[Tuple[Any, ...]], AbstractKet[Expr], HasRays, Convertible

Immutable single-particle basis state built from typed irreps.

U1Basis is a symbolic tensor-product state with U(1) irreducible representation presented as an ordered tuple of irreps. This object is intentionally symbolic: it stores basis labels only and does not store amplitudes or coefficients.

A key invariant is enforced at construction time: for each concrete irrep type, the state must contain exactly one ket of that type. In other words, irrep multiplicities must be unity. This guarantees that type-based updates via replace are unambiguous and fast.

Mathematical convention

A basis state is represented symbolically as \(|\psi\rangle = c\,|\rho_1,\rho_2,\ldots,\rho_m\rangle\), where coef stores \(c\), base stores the construction-order tuple \((\rho_1,\rho_2,\ldots,\rho_m)\), and rep stores the canonical type-sorted tuple used for equality, hashing, and lookup. The object is a basis label with a U(1) prefactor, not a dense state vector.

Attributes:

Name Type Description
coef Expr

Symbolic U(1) coefficient carried by this basis state.

base Tuple[Any, ...]

Immutable tuple of irrep labels before canonical sorting.

rep Tuple[Any, ...]

Immutable canonical irrep order sorted by concrete irrep type name (module.qualname).

Notes

dim is always 1; this type represents one basis vector. Irrep order is canonicalized at construction, so permutations of the same typed irreps produce the same internal rep tuple. replace(irrep) substitutes the unique irrep with the same concrete runtime type as irrep.

The @ dispatch overload combines two basis states as a symbolic tensor product. For a @ b, the output coefficient is simplify(a.coef * b.coef) and the output base tuple is a.base + b.base in tensor-product construction order. __post_init__ then computes rep by sorting that base tuple by fully-qualified runtime type name (module.qualname). The original base order is retained for display and construction semantics, while rep is the canonical sorted representation used for type-order-sensitive behavior. If either operand has an empty base, that operand acts as the tensor-product identity and the other operand is returned unchanged. The resulting U1Basis is still validated by __post_init__, so combining states that contain the same concrete irrep type is rejected by the unity-multiplicity invariant.

In coefficient notation, tensor-product composition multiplies the U(1) weights as \(c_{a \otimes b} = c_a c_b\). Equivalently, \((c_a|\alpha\rangle) \otimes (c_b|\beta\rangle) = c_a c_b\,|\alpha,\beta\rangle\). In code, this is a @ b and is implemented as U1Basis(simplify(a.coef * b.coef), a.base + b.base).

The | dispatch overloads build a U1Span of distinct U1Basis values. Ordering (<, >) compares the number of irreps, then the tuple of fully-qualified irrep type names (module.qualname) from self.rep, then the canonical irrep-value tuple itself. If irrep values of matching types are not orderable, the comparison raises from the underlying irrep objects.

Raises:

Type Description
ValueError

Raised in __post_init__ when any irrep type appears with multiplicity different from 1.

coef instance-attribute

coef: Number

Numeric SymPy coefficient applied to base, kept separate so callers can accumulate scalar factors without eagerly rebuilding symbolic expressions.

base instance-attribute

base: BaseType

The symbolic or scalar object being multiplied by coef, preserved in structured form for later operator application or simplification.

dim property

dim: int

The dimension of a single particle state is always 1.

add_conversion classmethod

add_conversion(
    T: type[B],
) -> Callable[[Callable[[A], B]], Callable[[A], B]]

Register a conversion from cls to T.

The decorated function is stored under (cls, T). When an instance of cls later calls convert(T), that function is used to produce the converted object.

Parameters:

Name Type Description Default
T Type[B]

Destination type produced by the registered conversion function.

required

Returns:

Type Description
Callable[[Callable[[A], B]], Callable[[A], B]]

Decorator that stores the conversion function and returns it unchanged.

Examples:

@MyType.add_conversion(TargetType)
def to_target(x: MyType) -> TargetType:
    ...
Source code in src/qten/abstracts.py
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
@classmethod
def add_conversion(
    cls: Type[A], T: Type[B]
) -> Callable[[Callable[[A], B]], Callable[[A], B]]:
    """
    Register a conversion from `cls` to `T`.

    The decorated function is stored under `(cls, T)`. When an instance of
    `cls` later calls [`convert(T)`][qten.abstracts.Convertible.convert],
    that function is used to produce the converted object.

    Parameters
    ----------
    T : Type[B]
        Destination type produced by the registered conversion function.

    Returns
    -------
    Callable[[Callable[[A], B]], Callable[[A], B]]
        Decorator that stores the conversion function and returns it
        unchanged.

    Examples
    --------
    ```python
    @MyType.add_conversion(TargetType)
    def to_target(x: MyType) -> TargetType:
        ...
    ```
    """

    def decorator(func: Callable[[A], B]) -> Callable[[A], B]:
        _type_conversion_table[(cls, T)] = cast(Callable[[Any], Any], func)
        return func

    return decorator

convert

convert(T: type[B]) -> B

Convert this instance to the requested target type.

Parameters:

Name Type Description Default
T Type[B]

Destination type to convert into.

required

Returns:

Type Description
B

Converted object produced by the registered conversion function.

Raises:

Type Description
NotImplementedError

If no conversion function has been registered for (type(self), T) or any source supertype via add_conversion().

Source code in src/qten/abstracts.py
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
@final
def convert(self, T: Type[B]) -> B:
    """
    Convert this instance to the requested target type.

    Parameters
    ----------
    T : Type[B]
        Destination type to convert into.

    Returns
    -------
    B
        Converted object produced by the registered conversion function.

    Raises
    ------
    NotImplementedError
        If no conversion function has been registered for
        `(type(self), T)` or any source supertype via
        [`add_conversion()`][qten.abstracts.Convertible.add_conversion].
    """
    source_type = type(self)
    table_get = _type_conversion_table.get

    convertor = table_get((source_type, T))
    if convertor is None:
        for super_type in source_type.__mro__[1:]:
            convertor = table_get((super_type, T))
            if convertor is not None:
                # Cache resolved parent conversion under the concrete source type.
                _type_conversion_table[(source_type, T)] = convertor
                break

    if convertor is None:
        raise NotImplementedError(
            f"No conversion from {source_type.__name__} to {T.__name__}!"
        )
    return cast(Callable[["Convertible"], B], convertor)(self)

register_plot_method classmethod

register_plot_method(name: str, backend: str = 'plotly')

Register a backend plotting function for this plottable class.

The returned decorator stores the function in the global plotting registry. Registered functions receive the object being plotted as their first argument, followed by any extra positional and keyword arguments supplied to plot().

Parameters:

Name Type Description Default
name str

User-facing plot method name, such as scatter, structure, or heatmap.

required
backend str

Backend name that selects the implementation. The qten-plots extension currently uses plotly and matplotlib.

'plotly'

Returns:

Type Description
Callable

Decorator that registers the provided plotting function and returns it unchanged.

Source code in src/qten/plottings/_plottings.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@classmethod
def register_plot_method(cls, name: str, backend: str = "plotly"):
    """
    Register a backend plotting function for this plottable class.

    The returned decorator stores the function in the global plotting
    registry. Registered functions receive the object being plotted as their
    first argument, followed by any extra positional and keyword arguments
    supplied to [`plot()`][qten.plottings.Plottable.plot].

    Parameters
    ----------
    name : str
        User-facing plot method name, such as `scatter`, `structure`, or
        `heatmap`.
    backend : str
        Backend name that selects the implementation. The `qten-plots`
        extension currently uses `plotly` and `matplotlib`.

    Returns
    -------
    Callable
        Decorator that registers the provided plotting function and returns
        it unchanged.
    """

    def decorator(func: Callable):
        # We register against 'cls' - the class this method was called on.
        Plottable._registry[(cls, name, backend)] = func
        return func

    return decorator

plot

plot(method: str, backend: str = 'plotly', *args, **kwargs)

Dispatch a named plot method to a registered backend implementation.

The dispatcher first loads plotting entry points, then searches the instance type and its base classes for a matching (type, method, backend) registration. Additional arguments are forwarded unchanged to the selected backend function.

Parameters:

Name Type Description Default
method str

Plot method name registered for this object's type.

required
backend str

Backend implementation to use. The qten-plots extension currently registers plotly and matplotlib.

'plotly'
args

Positional arguments forwarded to the registered plotting function.

()
kwargs

Keyword arguments forwarded to the registered plotting function.

{}

Returns:

Type Description
object

Backend-specific figure object returned by the registered plotting function, such as a Plotly or Matplotlib figure.

Raises:

Type Description
ValueError

If no plotting function is registered for the requested method and backend on this object.

See Also

qten_plots.plottables.PointCloud Public plottable helper object provided by the plotting extension.

Source code in src/qten/plottings/_plottings.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def plot(self, method: str, backend: str = "plotly", *args, **kwargs):
    """
    Dispatch a named plot method to a registered backend implementation.

    The dispatcher first loads plotting entry points, then searches the
    instance type and its base classes for a matching `(type, method,
    backend)` registration. Additional arguments are forwarded unchanged to
    the selected backend function.

    Parameters
    ----------
    method : str
        Plot method name registered for this object's type.
    backend : str
        Backend implementation to use. The `qten-plots` extension currently
        registers `plotly` and `matplotlib`.
    args
        Positional arguments forwarded to the registered plotting function.
    kwargs
        Keyword arguments forwarded to the registered plotting function.

    Returns
    -------
    object
        Backend-specific figure object returned by the registered plotting
        function, such as a Plotly or Matplotlib figure.

    Raises
    ------
    ValueError
        If no plotting function is registered for the requested method and
        backend on this object.

    See Also
    --------
    qten_plots.plottables.PointCloud
        Public plottable helper object provided by the plotting extension.
    """
    Plottable._ensure_backends_loaded()

    # Iterate over the MRO (Method Resolution Order) of the instance
    for class_in_hierarchy in type(self).__mro__:
        key = (class_in_hierarchy, method, backend)

        # Check the central registry
        if key in Plottable._registry:
            plot_func = Plottable._registry[key]
            return plot_func(self, *args, **kwargs)

    # If we reach here, no method was found. Provide a helpful error.
    self._raise_method_not_found(method, backend)

__post_init__

__post_init__() -> None
Source code in src/qten/symbolics/hilbert_space.py
162
163
164
165
166
167
168
169
170
171
172
def __post_init__(self) -> None:
    object.__setattr__(
        self,
        "rep",
        tuple(
            sorted(
                self.base,
                key=lambda irrep: full_typename(type(irrep)),
            )
        ),
    )

new staticmethod

new(*rep: Any) -> U1Basis

Build a U1Basis with the given reps and a default U(1) value of 1.

Parameters:

Name Type Description Default
rep Any

Irreps to build the state from. Input order is canonicalized in __post_init__ by sorting on full_typename(type(irrep)).

()

Returns:

Type Description
U1Basis

A U1Basis instance with the given reps and a default U(1) value of 1.

Source code in src/qten/symbolics/hilbert_space.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
@staticmethod
def new(*rep: Any) -> "U1Basis":
    """
    Build a [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] with the given reps and a default U(1) value of `1`.

    Parameters
    ----------
    rep : Any
        Irreps to build the state from. Input order is canonicalized in
        `__post_init__` by sorting on [`full_typename(type(irrep))`][qten.utils.types_ext.full_typename].

    Returns
    -------
    U1Basis
        A [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] instance with the given reps and a default U(1) value of `1`.
    """
    return U1Basis(coef=sy.Integer(1), base=tuple(rep))

replace

replace(irrep: Any) -> U1Basis

Return a new state where the irrep of the same concrete type is replaced.

The method searches this state's irrep tuple for the unique irrep whose type has the same exact runtime type as irrep (using type(x) is type(y)), then returns a new U1Basis with that irrep substituted. The original instance is not modified.

Parameters:

Name Type Description Default
irrep Any

Replacement irrep instance. Its concrete type must already exist in this state exactly once (enforced by U1Basis.__post_init__).

required

Returns:

Type Description
U1Basis

A new U1Basis with one irrep replaced.

Raises:

Type Description
ValueError

If this state does not contain any irrep with the same concrete type as irrep.

Examples:

from sympy import ImmutableDenseMatrix
from qten.geometries import AffineSpace, Offset
from qten.symbolics import U1Basis

space = AffineSpace(ImmutableDenseMatrix.eye(1))
r0 = Offset(ImmutableDenseMatrix([0]), space)
r1 = Offset(ImmutableDenseMatrix([1]), space)
psi = U1Basis.new(r0, "spin-up")
out = psi.replace(r1)

assert out.irrep_of(Offset) == r1
assert out.irrep_of(str) == "spin-up"
Source code in src/qten/symbolics/hilbert_space.py
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
def replace(self, irrep: Any) -> "U1Basis":
    """
    Return a new state where the irrep of the same concrete type is replaced.

    The method searches this state's irrep tuple for the unique irrep whose type has
    the same *exact* runtime type as `irrep` (using `type(x) is type(y)`), then
    returns a new [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] with that irrep substituted. The original instance is
    not modified.

    Parameters
    ----------
    irrep : Any
        Replacement irrep instance. Its concrete type must already exist in this
        state exactly once (enforced by `U1Basis.__post_init__`).

    Returns
    -------
    U1Basis
        A new [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] with one irrep replaced.

    Raises
    ------
    ValueError
        If this state does not contain any irrep with the same concrete
        type as `irrep`.

    Examples
    --------
    ```python
    from sympy import ImmutableDenseMatrix
    from qten.geometries import AffineSpace, Offset
    from qten.symbolics import U1Basis

    space = AffineSpace(ImmutableDenseMatrix.eye(1))
    r0 = Offset(ImmutableDenseMatrix([0]), space)
    r1 = Offset(ImmutableDenseMatrix([1]), space)
    psi = U1Basis.new(r0, "spin-up")
    out = psi.replace(r1)

    assert out.irrep_of(Offset) == r1
    assert out.irrep_of(str) == "spin-up"
    ```
    """
    target_type = type(irrep)
    reps = self.base
    for i, x in enumerate(reps):
        if type(x) is target_type:
            return replace(self, base=reps[:i] + (irrep,) + reps[i + 1 :])
    raise ValueError(
        f"U1Basis has no irrep of type {target_type.__name__} to replace."
    )

without

without(*T: type[Any]) -> U1Basis

Return a new state with irreps of the requested concrete types removed.

Parameters:

Name Type Description Default
*T Type[Any]

Concrete irrep types to remove. Matching uses exact runtime type identity (type(x) is T), not subclass checks.

()

Returns:

Type Description
U1Basis

A new U1Basis with all irreps whose concrete types are in T removed. If none of the requested types are present, self is returned unchanged.

Examples:

from sympy import ImmutableDenseMatrix
from qten.geometries import AffineSpace, Offset
from qten.symbolics import U1Basis

space = AffineSpace(ImmutableDenseMatrix.eye(1))
r0 = Offset(ImmutableDenseMatrix([0]), space)
psi = U1Basis.new(r0, "spin-up")
local_label = psi.without(Offset)

assert local_label.irrep_of(str) == "spin-up"
Source code in src/qten/symbolics/hilbert_space.py
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
def without(self, *T: Type[Any]) -> "U1Basis":
    """
    Return a new state with irreps of the requested concrete types removed.

    Parameters
    ----------
    *T : Type[Any]
        Concrete irrep types to remove. Matching uses exact runtime type
        identity (`type(x) is T`), not subclass checks.

    Returns
    -------
    U1Basis
        A new [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] with all irreps whose concrete types are in `T`
        removed. If none of the requested types are present, `self` is
        returned unchanged.

    Examples
    --------
    ```python
    from sympy import ImmutableDenseMatrix
    from qten.geometries import AffineSpace, Offset
    from qten.symbolics import U1Basis

    space = AffineSpace(ImmutableDenseMatrix.eye(1))
    r0 = Offset(ImmutableDenseMatrix([0]), space)
    psi = U1Basis.new(r0, "spin-up")
    local_label = psi.without(Offset)

    assert local_label.irrep_of(str) == "spin-up"
    ```
    """
    if not T:
        return self
    targets = frozenset(T)
    filtered = tuple(irrep for irrep in self.base if type(irrep) not in targets)
    if len(filtered) == len(self.base):
        return self
    return replace(self, base=filtered)

irrep_of

irrep_of(T: type[_IrrepType]) -> _IrrepType

Return the unique irrep in this state whose concrete type is T.

This method performs a direct scan over self.rep and returns the first irrep satisfying type(irrep) is T. Because U1Basis.__post_init__ enforces unity multiplicity for each irrep type, the match is unique whenever it exists.

Parameters:

Name Type Description Default
T Type[_IrrepType]

Concrete irrep type to retrieve.

required

Returns:

Type Description
_IrrepType

The irrep instance of type T contained in this state.

Raises:

Type Description
ValueError

If no irrep with concrete type T exists in this state.

Examples:

from sympy import ImmutableDenseMatrix
from qten.geometries import AffineSpace, Offset
from qten.symbolics import U1Basis

space = AffineSpace(ImmutableDenseMatrix.eye(1))
r0 = Offset(ImmutableDenseMatrix([0]), space)
psi = U1Basis.new(r0, "spin-up")

assert psi.irrep_of(Offset) == r0
assert psi.irrep_of(str) == "spin-up"
Notes

Matching uses exact runtime type identity (type(x) is T), not subclass checks. Runtime is linear in the number of irreps (O(n)), with no temporary mapping allocations.

Source code in src/qten/symbolics/hilbert_space.py
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
def irrep_of(self, T: Type[_IrrepType]) -> _IrrepType:
    """
    Return the unique irrep in this state whose concrete type is `T`.

    This method performs a direct scan over `self.rep` and returns the
    first irrep satisfying `type(irrep) is T`. Because
    `U1Basis.__post_init__` enforces unity multiplicity for each irrep
    type, the match is unique whenever it exists.

    Parameters
    ----------
    T : Type[_IrrepType]
        Concrete irrep type to retrieve.

    Returns
    -------
    _IrrepType
        The irrep instance of type `T` contained in this state.

    Raises
    ------
    ValueError
        If no irrep with concrete type `T` exists in this state.

    Examples
    --------
    ```python
    from sympy import ImmutableDenseMatrix
    from qten.geometries import AffineSpace, Offset
    from qten.symbolics import U1Basis

    space = AffineSpace(ImmutableDenseMatrix.eye(1))
    r0 = Offset(ImmutableDenseMatrix([0]), space)
    psi = U1Basis.new(r0, "spin-up")

    assert psi.irrep_of(Offset) == r0
    assert psi.irrep_of(str) == "spin-up"
    ```

    Notes
    -----
    Matching uses exact runtime type identity (`type(x) is T`), not subclass
    checks. Runtime is linear in the number of irreps (`O(n)`), with no
    temporary mapping allocations.
    """
    for irrep in self.base:
        if type(irrep) is T:
            return cast(_IrrepType, irrep)
    raise ValueError(f"U1Basis {self} has no irrep of type {T.__name__}.")

ket

ket(psi: U1Basis) -> sy.Expr

Return the overlap of this state with another state.

Parameters:

Name Type Description Default
psi U1Basis

The state to compute the overlap with.

required

Returns:

Type Description
Expr

The symbolic overlap of this state with psi. If the irreps of the two states do not match, the overlap is 0. If the irreps match, the overlap is the product of this state's U(1) value and the conjugate of psi's U(1) value.

Source code in src/qten/symbolics/hilbert_space.py
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
@override
def ket(self, psi: "U1Basis") -> sy.Expr:
    """
    Return the overlap of this state with another state.

    Parameters
    ----------
    psi : U1Basis
        The state to compute the overlap with.

    Returns
    -------
    sy.Expr
        The symbolic overlap of this state with `psi`. If the irreps of the
        two states do not match, the overlap is `0`. If the irreps match, the
        overlap is the product of this state's U(1) value and the conjugate of
        psi's U(1) value.
    """
    if self.base != psi.base:
        return sy.Integer(0)
    return cast(sy.Expr, (sy.conjugate(self.coef) * psi.coef).simplify())

__str__

__str__() -> str

Return a compact ket-style label for this basis state.

Returns:

Type Description
str

Tensor-product ket label. If coef != 1, the coefficient is prepended as a symbolic scalar factor.

Source code in src/qten/symbolics/hilbert_space.py
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
def __str__(self) -> str:
    """
    Return a compact ket-style label for this basis state.

    Returns
    -------
    str
        Tensor-product ket label. If `coef != 1`, the coefficient is
        prepended as a symbolic scalar factor.
    """
    ket_repr = "⊗".join(
        f"|{irrep_repr}⟩"
        if len(irrep_repr := repr(irrep)) <= 32
        else f"|{type(irrep).__name__}⟩"
        for irrep in self.base
    )
    if self.coef != sy.Integer(1):
        ket_repr = f"({self.coef}) * " + ket_repr
    return ket_repr

__repr__

__repr__() -> str

Return the developer representation of this basis state.

Returns:

Type Description
str

Same value as str(self).

Source code in src/qten/symbolics/hilbert_space.py
381
382
383
384
385
386
387
388
389
390
def __repr__(self) -> str:
    """
    Return the developer representation of this basis state.

    Returns
    -------
    str
        Same value as `str(self)`.
    """
    return self.__str__()

rays

rays() -> U1Basis

Return the canonical ray representative with U(1) coefficient 1.

A U1Basis ray ignores the scalar coef and keeps only the basis labels. This method returns a new basis state with the same base tuple and coefficient 1. The original object is unchanged.

Returns:

Type Description
U1Basis

Basis state with the same irrep labels and coef = 1.

Examples:

import sympy as sy
from sympy import ImmutableDenseMatrix
from qten.geometries import AffineSpace, Offset
from qten.symbolics import U1Basis

space = AffineSpace(ImmutableDenseMatrix.eye(1))
r0 = Offset(ImmutableDenseMatrix([0]), space)
psi = U1Basis(sy.Integer(3), (r0,))
ray = psi.rays()

assert ray.coef == 1
assert ray.base == psi.base
Source code in src/qten/symbolics/hilbert_space.py
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
@override
def rays(self) -> "U1Basis":
    """
    Return the canonical ray representative with U(1) coefficient `1`.

    A [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] ray ignores the
    scalar `coef` and keeps only the basis labels. This method returns a new
    basis state with the same `base` tuple and coefficient `1`. The original
    object is unchanged.

    Returns
    -------
    U1Basis
        Basis state with the same irrep labels and `coef = 1`.

    Examples
    --------
    ```python
    import sympy as sy
    from sympy import ImmutableDenseMatrix
    from qten.geometries import AffineSpace, Offset
    from qten.symbolics import U1Basis

    space = AffineSpace(ImmutableDenseMatrix.eye(1))
    r0 = Offset(ImmutableDenseMatrix([0]), space)
    psi = U1Basis(sy.Integer(3), (r0,))
    ray = psi.rays()

    assert ray.coef == 1
    assert ray.base == psi.base
    ```
    """
    return replace(self, coef=sy.Integer(1))

repr_types

repr_types() -> tuple[type, ...]

Get a tuple of concrete irrep types in this U1Basis in canonical order.

This is the same order as self.rep, which is determined by sorting on full_typename(type(irrep)).

Returns:

Type Description
Tuple[Type, ...]

Tuple of concrete irrep types in deterministic type-name order.

Source code in src/qten/symbolics/hilbert_space.py
426
427
428
429
430
431
432
433
434
435
436
437
438
def repr_types(self) -> Tuple[Type, ...]:
    """
    Get a tuple of concrete irrep types in this [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] in canonical order.

    This is the same order as `self.rep`, which is determined by
    sorting on [`full_typename(type(irrep))`][qten.utils.types_ext.full_typename].

    Returns
    -------
    Tuple[Type, ...]
        Tuple of concrete irrep types in deterministic type-name order.
    """
    return tuple(type(irrep) for irrep in self.base)

U1Span dataclass

U1Span(span: tuple[U1Basis, ...])

Bases: Span[U1Basis], Spatial, HasRays, Convertible

Finite span of distinct single-particle basis states.

U1Span is the additive container used by U1Basis's * operator. It stores an ordered tuple of basis states and represents the symbolic span generated by those states. The object is immutable (frozen=True) and preserves insertion order.

This type is intentionally lightweight: it does not store amplitudes, coefficients, or perform linear-algebra simplification. Duplicate handling is implemented in __or__ overloads, which keep only one copy of an existing state when building a span.

Mathematical convention

If the span contains basis labels \(\psi_0,\ldots,\psi_{n-1}\), it represents the ordered symbolic basis \(\mathrm{span}\{|\psi_0\rangle,\ldots,|\psi_{n-1}\rangle\}\). The order is part of the object: it determines row/column ordering in Gram matrices and tensor dimensions.

Parameters:

Name Type Description Default
span Tuple[U1Basis, ...]

Ordered tuple of U1Basis elements contained in this span.

required

Attributes:

Name Type Description
span Tuple[U1Basis, ...]

The underlying immutable sequence of basis states.

Notes

The dim property returns len(span), i.e., the number of basis states currently tracked by this symbolic span.

span instance-attribute

span: tuple[U1Basis, ...]

Ordered tuple of U1Basis elements contained in this span.

dim property

dim: int

Get the length of this single particle state span.

add_conversion classmethod

add_conversion(
    T: type[B],
) -> Callable[[Callable[[A], B]], Callable[[A], B]]

Register a conversion from cls to T.

The decorated function is stored under (cls, T). When an instance of cls later calls convert(T), that function is used to produce the converted object.

Parameters:

Name Type Description Default
T Type[B]

Destination type produced by the registered conversion function.

required

Returns:

Type Description
Callable[[Callable[[A], B]], Callable[[A], B]]

Decorator that stores the conversion function and returns it unchanged.

Examples:

@MyType.add_conversion(TargetType)
def to_target(x: MyType) -> TargetType:
    ...
Source code in src/qten/abstracts.py
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
@classmethod
def add_conversion(
    cls: Type[A], T: Type[B]
) -> Callable[[Callable[[A], B]], Callable[[A], B]]:
    """
    Register a conversion from `cls` to `T`.

    The decorated function is stored under `(cls, T)`. When an instance of
    `cls` later calls [`convert(T)`][qten.abstracts.Convertible.convert],
    that function is used to produce the converted object.

    Parameters
    ----------
    T : Type[B]
        Destination type produced by the registered conversion function.

    Returns
    -------
    Callable[[Callable[[A], B]], Callable[[A], B]]
        Decorator that stores the conversion function and returns it
        unchanged.

    Examples
    --------
    ```python
    @MyType.add_conversion(TargetType)
    def to_target(x: MyType) -> TargetType:
        ...
    ```
    """

    def decorator(func: Callable[[A], B]) -> Callable[[A], B]:
        _type_conversion_table[(cls, T)] = cast(Callable[[Any], Any], func)
        return func

    return decorator

convert

convert(T: type[B]) -> B

Convert this instance to the requested target type.

Parameters:

Name Type Description Default
T Type[B]

Destination type to convert into.

required

Returns:

Type Description
B

Converted object produced by the registered conversion function.

Raises:

Type Description
NotImplementedError

If no conversion function has been registered for (type(self), T) or any source supertype via add_conversion().

Source code in src/qten/abstracts.py
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
@final
def convert(self, T: Type[B]) -> B:
    """
    Convert this instance to the requested target type.

    Parameters
    ----------
    T : Type[B]
        Destination type to convert into.

    Returns
    -------
    B
        Converted object produced by the registered conversion function.

    Raises
    ------
    NotImplementedError
        If no conversion function has been registered for
        `(type(self), T)` or any source supertype via
        [`add_conversion()`][qten.abstracts.Convertible.add_conversion].
    """
    source_type = type(self)
    table_get = _type_conversion_table.get

    convertor = table_get((source_type, T))
    if convertor is None:
        for super_type in source_type.__mro__[1:]:
            convertor = table_get((super_type, T))
            if convertor is not None:
                # Cache resolved parent conversion under the concrete source type.
                _type_conversion_table[(source_type, T)] = convertor
                break

    if convertor is None:
        raise NotImplementedError(
            f"No conversion from {source_type.__name__} to {T.__name__}!"
        )
    return cast(Callable[["Convertible"], B], convertor)(self)

register_plot_method classmethod

register_plot_method(name: str, backend: str = 'plotly')

Register a backend plotting function for this plottable class.

The returned decorator stores the function in the global plotting registry. Registered functions receive the object being plotted as their first argument, followed by any extra positional and keyword arguments supplied to plot().

Parameters:

Name Type Description Default
name str

User-facing plot method name, such as scatter, structure, or heatmap.

required
backend str

Backend name that selects the implementation. The qten-plots extension currently uses plotly and matplotlib.

'plotly'

Returns:

Type Description
Callable

Decorator that registers the provided plotting function and returns it unchanged.

Source code in src/qten/plottings/_plottings.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@classmethod
def register_plot_method(cls, name: str, backend: str = "plotly"):
    """
    Register a backend plotting function for this plottable class.

    The returned decorator stores the function in the global plotting
    registry. Registered functions receive the object being plotted as their
    first argument, followed by any extra positional and keyword arguments
    supplied to [`plot()`][qten.plottings.Plottable.plot].

    Parameters
    ----------
    name : str
        User-facing plot method name, such as `scatter`, `structure`, or
        `heatmap`.
    backend : str
        Backend name that selects the implementation. The `qten-plots`
        extension currently uses `plotly` and `matplotlib`.

    Returns
    -------
    Callable
        Decorator that registers the provided plotting function and returns
        it unchanged.
    """

    def decorator(func: Callable):
        # We register against 'cls' - the class this method was called on.
        Plottable._registry[(cls, name, backend)] = func
        return func

    return decorator

plot

plot(method: str, backend: str = 'plotly', *args, **kwargs)

Dispatch a named plot method to a registered backend implementation.

The dispatcher first loads plotting entry points, then searches the instance type and its base classes for a matching (type, method, backend) registration. Additional arguments are forwarded unchanged to the selected backend function.

Parameters:

Name Type Description Default
method str

Plot method name registered for this object's type.

required
backend str

Backend implementation to use. The qten-plots extension currently registers plotly and matplotlib.

'plotly'
args

Positional arguments forwarded to the registered plotting function.

()
kwargs

Keyword arguments forwarded to the registered plotting function.

{}

Returns:

Type Description
object

Backend-specific figure object returned by the registered plotting function, such as a Plotly or Matplotlib figure.

Raises:

Type Description
ValueError

If no plotting function is registered for the requested method and backend on this object.

See Also

qten_plots.plottables.PointCloud Public plottable helper object provided by the plotting extension.

Source code in src/qten/plottings/_plottings.py
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def plot(self, method: str, backend: str = "plotly", *args, **kwargs):
    """
    Dispatch a named plot method to a registered backend implementation.

    The dispatcher first loads plotting entry points, then searches the
    instance type and its base classes for a matching `(type, method,
    backend)` registration. Additional arguments are forwarded unchanged to
    the selected backend function.

    Parameters
    ----------
    method : str
        Plot method name registered for this object's type.
    backend : str
        Backend implementation to use. The `qten-plots` extension currently
        registers `plotly` and `matplotlib`.
    args
        Positional arguments forwarded to the registered plotting function.
    kwargs
        Keyword arguments forwarded to the registered plotting function.

    Returns
    -------
    object
        Backend-specific figure object returned by the registered plotting
        function, such as a Plotly or Matplotlib figure.

    Raises
    ------
    ValueError
        If no plotting function is registered for the requested method and
        backend on this object.

    See Also
    --------
    qten_plots.plottables.PointCloud
        Public plottable helper object provided by the plotting extension.
    """
    Plottable._ensure_backends_loaded()

    # Iterate over the MRO (Method Resolution Order) of the instance
    for class_in_hierarchy in type(self).__mro__:
        key = (class_in_hierarchy, method, backend)

        # Check the central registry
        if key in Plottable._registry:
            plot_func = Plottable._registry[key]
            return plot_func(self, *args, **kwargs)

    # If we reach here, no method was found. Provide a helpful error.
    self._raise_method_not_found(method, backend)

__iter__

__iter__() -> Iterator[U1Basis]

Iterate over states in this span preserving insertion order.

Source code in src/qten/symbolics/hilbert_space.py
521
522
523
def __iter__(self) -> Iterator["U1Basis"]:
    """Iterate over states in this span preserving insertion order."""
    return iter(self.span)

elements

elements() -> tuple[U1Basis, ...]

Return the basis states contained in this span.

Returns:

Type Description
Tuple[U1Basis, ...]

Ordered immutable tuple of basis states.

Source code in src/qten/symbolics/hilbert_space.py
525
526
527
528
529
530
531
532
533
534
535
@override
def elements(self) -> Tuple["U1Basis", ...]:
    """
    Return the basis states contained in this span.

    Returns
    -------
    Tuple[U1Basis, ...]
        Ordered immutable tuple of basis states.
    """
    return self.span

rays

rays() -> U1Span

Return the span obtained by ray-normalizing each basis state.

The output preserves span order and replaces every U1Basis by basis.rays(), which sets that basis state's coefficient to 1.

Returns:

Type Description
U1Span

Span with the same number of basis states, each replaced by its ray representative.

Examples:

import sympy as sy
from sympy import ImmutableDenseMatrix
from qten.geometries import AffineSpace, Offset
from qten.symbolics import U1Basis, U1Span

space = AffineSpace(ImmutableDenseMatrix.eye(1))
r0 = Offset(ImmutableDenseMatrix([0]), space)
span = U1Span((U1Basis(sy.Integer(2), (r0,)),))
ray_span = span.rays()

assert ray_span.elements()[0].coef == 1
Source code in src/qten/symbolics/hilbert_space.py
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
@override
def rays(self) -> "U1Span":
    """
    Return the span obtained by ray-normalizing each basis state.

    The output preserves span order and replaces every
    [`U1Basis`][qten.symbolics.hilbert_space.U1Basis] by
    `basis.rays()`, which sets that basis state's coefficient to `1`.

    Returns
    -------
    U1Span
        Span with the same number of basis states, each replaced by its ray
        representative.

    Examples
    --------
    ```python
    import sympy as sy
    from sympy import ImmutableDenseMatrix
    from qten.geometries import AffineSpace, Offset
    from qten.symbolics import U1Basis, U1Span

    space = AffineSpace(ImmutableDenseMatrix.eye(1))
    r0 = Offset(ImmutableDenseMatrix([0]), space)
    span = U1Span((U1Basis(sy.Integer(2), (r0,)),))
    ray_span = span.rays()

    assert ray_span.elements()[0].coef == 1
    ```
    """
    return U1Span(tuple(m.rays() for m in self.span))

cross_gram

cross_gram(ket: U1Span) -> sy.ImmutableDenseMatrix

Compute the overlap matrix between this span and another span.

For left span states \(\psi_i\) and right span states \(\phi_j\), the returned SymPy matrix has entries \(G_{ij} = \langle \psi_i \mid \phi_j \rangle\). The implementation only emits a nonzero entry when the two symbolic states have the same ray; the stored U(1) coefficients supply the overlap phase.

Parameters:

Name Type Description Default
ket U1Span

Right-hand span supplying the ket states.

required

Returns:

Type Description
ImmutableDenseMatrix

Matrix whose (i, j) entry is the inner product between the ith basis state of self and the jth basis state of ket whenever the two states lie on the same ray, and 0 otherwise.

Source code in src/qten/symbolics/hilbert_space.py
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
def cross_gram(self, ket: "U1Span") -> sy.ImmutableDenseMatrix:
    r"""
    Compute the overlap matrix between this span and another span.

    For left span states \(\psi_i\) and right span states \(\phi_j\), the
    returned SymPy matrix has entries
    \(G_{ij} = \langle \psi_i \mid \phi_j \rangle\). The implementation only emits a nonzero entry when the two symbolic
    states have the same ray; the stored U(1) coefficients supply the
    overlap phase.

    Parameters
    ----------
    ket : U1Span
        Right-hand span supplying the ket states.

    Returns
    -------
    sy.ImmutableDenseMatrix
        Matrix whose `(i, j)` entry is the inner product between the `i`th
        basis state of `self` and the `j`th basis state of `ket` whenever
        the two states lie on the same ray, and `0` otherwise.
    """
    tbl: Dict["U1Basis", Tuple[int, "U1Basis"]] = {
        psi.rays(): (n, psi) for n, psi in enumerate(ket.span)
    }
    out = sy.zeros(self.dim, ket.dim)
    for n, psi in enumerate(self.span):
        rays = psi.rays()
        if rays not in tbl:
            continue
        m, kpsi = tbl[rays]
        out[n, m] = psi.ket(kpsi)
    return sy.ImmutableDenseMatrix(out)

fractional_opr

fractional_opr() -> FuncOpr[Offset]
fractional_opr(T: type[OffsetType]) -> FuncOpr[OffsetType]

Build an operator that replaces a spatial irrep by its fractional form.

Parameters:

Name Type Description Default
T type[Offset] | type[Momentum] | None

Exact irrep type to target. Because FuncOpr matches exact runtime types, reciprocal-space basis states should use fractional_opr(Momentum). If omitted, Offset is targeted.

None

Returns:

Type Description
FuncOpr

Operator replacing matching spatial irreps by r.fractional().

Source code in src/qten/symbolics/ops.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
def fractional_opr(
    T: type[OffsetType] | None = None,
) -> FuncOpr[Offset] | FuncOpr[OffsetType]:
    """
    Build an operator that replaces a spatial irrep by its fractional form.

    Parameters
    ----------
    T : type[Offset] | type[Momentum] | None, optional
        Exact irrep type to target. Because [`FuncOpr`][qten.symbolics.hilbert_space.FuncOpr] matches exact runtime
        types, reciprocal-space basis states should use
        [`fractional_opr(Momentum)`][qten.symbolics.ops.fractional_opr]. If omitted, [`Offset`][qten.geometries.spatials.Offset] is targeted.

    Returns
    -------
    FuncOpr
        Operator replacing matching spatial irreps by `r.fractional()`.
    """
    if T is None:
        return FuncOpr(Offset, Offset.fractional)
    return FuncOpr(T, lambda r: cast(OffsetType, r.fractional()))

hilbert_opr_repr

hilbert_opr_repr(
    opr: Opr,
    space: HilbertSpace,
    *,
    device: Optional[Device] = None,
) -> Tensor

Return the matrix representation of an operator on a Hilbert-space basis.

Let \(\mathrm{space} = \mathrm{span}\{|e_i\rangle\}\) be the input HilbertSpace and let opr act on each basis state to produce \(\mathrm{span}\{\mathrm{opr}\,|e_j\rangle\}\). In code, the transformed basis is produced by opr @ space. This function constructs the corresponding representation matrix \(M_{ij} = \langle e_i | \mathrm{opr} | e_j \rangle\), implemented as the cross-Gram matrix between the original basis and its transformed image. The resulting Tensor therefore represents opr in the basis supplied by space.

Parameters:

Name Type Description Default
opr Opr

Operator whose representation is to be computed.

required
space HilbertSpace

Basis in which the operator is represented.

required

Returns:

Type Description
Tensor

Square tensor whose entries are the matrix elements of opr in the basis space.

Raises:

Type Description
ValueError

If opr does not preserve the ray structure of space, so no representation internal to the same projective Hilbert space exists.

Notes

The output dimensions are relabeled back onto space, so the returned tensor can be interpreted directly as an endomorphism of that Hilbert space.

Source code in src/qten/symbolics/ops.py
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
def hilbert_opr_repr(
    opr: Opr, space: HilbertSpace, *, device: Optional[Device] = None
) -> Tensor:
    r"""
    Return the matrix representation of an operator on a Hilbert-space basis.

    Let \(\mathrm{space} = \mathrm{span}\{|e_i\rangle\}\) be the input
    [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] and let `opr`
    act on each basis state to produce
    \(\mathrm{span}\{\mathrm{opr}\,|e_j\rangle\}\). In code, the transformed
    basis is produced by `opr @ space`. This function constructs the
    corresponding representation matrix
    \(M_{ij} = \langle e_i | \mathrm{opr} | e_j \rangle\), implemented as the
    cross-Gram matrix between the original basis and its
    transformed image. The resulting [`Tensor`][qten.linalg.tensors.Tensor] therefore represents `opr` in the
    basis supplied by `space`.

    Parameters
    ----------
    opr : Opr
        Operator whose representation is to be computed.
    space : HilbertSpace
        Basis in which the operator is represented.

    Returns
    -------
    Tensor
        Square tensor whose entries are the matrix elements of `opr` in the
        basis `space`.

    Raises
    ------
    ValueError
        If `opr` does not preserve the ray structure of `space`, so no
        representation internal to the same projective Hilbert space exists.

    Notes
    -----
    The output dimensions are relabeled back onto `space`, so the returned
    tensor can be interpreted directly as an endomorphism of that Hilbert
    space.
    """
    new_space = opr @ space
    if not space.same_rays(new_space):
        raise ValueError("opr does not preserve the ray structure of space.")
    return space.cross_gram(new_space, device=device).replace_dim(1, space)

interpolate_reciprocal_path

interpolate_reciprocal_path(
    recip: ReciprocalLattice,
    waypoints: Sequence[Union[tuple[float, ...], str]],
    n_points: int = 100,
    labels: Optional[Sequence[str]] = None,
    points: Optional[Dict[str, tuple[float, ...]]] = None,
) -> BzPath

Build a dense reciprocal-space sample along a piecewise-linear path.

Waypoints are interpreted as fractional reciprocal coordinates unless they are strings. String waypoints are resolved through points and also supply default labels when labels is omitted.

Parameters:

Name Type Description Default
recip ReciprocalLattice

Reciprocal lattice whose basis converts fractional waypoints to Cartesian coordinates for distance allocation.

required
waypoints Sequence[tuple[float, ...] | str]

At least two waypoint coordinates or names. Named waypoints must appear in points.

required
n_points int

Total number of dense path samples, including all waypoints.

100
labels Optional[Sequence[str]]

Labels for waypoints. If omitted, names or coordinate strings are used.

None
points Optional[Dict[str, tuple[float, ...]]]

Mapping used to resolve string waypoints to fractional coordinates.

None

Returns:

Type Description
BzPath

Path metadata containing the unique momentum space, waypoint labels, dense-sample-to-momentum mapping, and cumulative path positions.

Raises:

Type Description
ValueError

If fewer than two waypoints are supplied, a named waypoint is missing, waypoint dimensions do not match the reciprocal lattice, n_points is too small, all waypoints are identical, or labels has the wrong length.

Source code in src/qten/symbolics/ops.py
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
def interpolate_reciprocal_path(
    recip: ReciprocalLattice,
    waypoints: Sequence[Union[tuple[float, ...], str]],
    n_points: int = 100,
    labels: Optional[Sequence[str]] = None,
    points: Optional[Dict[str, tuple[float, ...]]] = None,
) -> BzPath:
    """
    Build a dense reciprocal-space sample along a piecewise-linear path.

    Waypoints are interpreted as fractional reciprocal coordinates unless they
    are strings. String waypoints are resolved through `points` and also supply
    default labels when `labels` is omitted.

    Parameters
    ----------
    recip : ReciprocalLattice
        Reciprocal lattice whose basis converts fractional waypoints to
        Cartesian coordinates for distance allocation.
    waypoints : Sequence[tuple[float, ...] | str]
        At least two waypoint coordinates or names. Named waypoints must appear
        in `points`.
    n_points : int, default 100
        Total number of dense path samples, including all waypoints.
    labels : Optional[Sequence[str]], optional
        Labels for waypoints. If omitted, names or coordinate strings are used.
    points : Optional[Dict[str, tuple[float, ...]]], optional
        Mapping used to resolve string waypoints to fractional coordinates.

    Returns
    -------
    BzPath
        Path metadata containing the unique momentum space, waypoint labels,
        dense-sample-to-momentum mapping, and cumulative path positions.

    Raises
    ------
    ValueError
        If fewer than two waypoints are supplied, a named waypoint is missing,
        waypoint dimensions do not match the reciprocal lattice, `n_points` is
        too small, all waypoints are identical, or `labels` has the wrong
        length.
    """
    if len(waypoints) < 2:
        raise ValueError("At least two waypoints are required to define a path.")

    _points: Dict[str, tuple[float, ...]] = points or {}

    resolved_wp: list[tuple[float, ...]] = []
    auto_labels: list[str] = []
    for i, wp in enumerate(waypoints):
        if isinstance(wp, str):
            if wp not in _points:
                raise ValueError(
                    f"Waypoint {i} is the name '{wp}' but it was not found in "
                    f"the points dictionary. Available names: "
                    f"{sorted(_points.keys()) if _points else '(empty)'}."
                )
            resolved_wp.append(_points[wp])
            auto_labels.append(wp)
        else:
            resolved_wp.append(tuple(wp))
            auto_labels.append(str(tuple(wp)))

    dim = recip.dim
    for i, wp in enumerate(resolved_wp):
        if len(wp) != dim:
            raise ValueError(f"Waypoint {i} has {len(wp)} components, expected {dim}.")
    if n_points < len(resolved_wp):
        raise ValueError(
            f"n_points ({n_points}) must be >= number of waypoints ({len(resolved_wp)})."
        )

    basis_mat = np.array(recip.basis.evalf(), dtype=float)
    wp_frac = np.array(resolved_wp, dtype=float)
    wp_cart = wp_frac @ basis_mat.T

    seg_lengths = np.array(
        [
            np.linalg.norm(wp_cart[i + 1] - wp_cart[i])
            for i in range(len(resolved_wp) - 1)
        ]
    )
    total_length = seg_lengths.sum()
    n_segments = len(resolved_wp) - 1

    if total_length < 1e-15:
        raise ValueError("All waypoints are identical; path has zero length.")

    remaining = n_points - n_segments - 1
    interior_per_seg = np.zeros(n_segments, dtype=int)
    if remaining > 0:
        ideal = (seg_lengths / total_length) * remaining
        interior_per_seg = np.floor(ideal).astype(int)
        deficit = remaining - interior_per_seg.sum()
        fracs = ideal - interior_per_seg
        for idx in np.argsort(-fracs)[:deficit]:
            interior_per_seg[idx] += 1

    all_fracs: list[np.ndarray] = []
    waypoint_indices: list[int] = []

    for seg in range(n_segments):
        n_interior = int(interior_per_seg[seg])
        n_seg_points = n_interior + 1
        t_vals = np.linspace(0.0, 1.0, n_seg_points, endpoint=False)
        start = wp_frac[seg]
        end = wp_frac[seg + 1]
        waypoint_indices.append(len(all_fracs))
        for t in t_vals:
            all_fracs.append(start + t * (end - start))

    waypoint_indices.append(len(all_fracs))
    all_fracs.append(wp_frac[-1])

    seen: dict[Momentum, int] = {}
    unique_momenta: list[Momentum] = []
    path_order: list[int] = []

    for frac in all_fracs:
        rep = ImmutableDenseMatrix(
            [sy.Rational(f).limit_denominator(10**9) for f in frac]
        )
        k = Momentum(rep=rep, space=recip)
        if k not in seen:
            seen[k] = len(unique_momenta)
            unique_momenta.append(k)
        path_order.append(seen[k])

    structure: OrderedDict[Momentum, int] = OrderedDict(
        (k, i) for i, k in enumerate(unique_momenta)
    )
    k_space = MomentumSpace(structure=structure)

    all_cart = np.stack(all_fracs) @ basis_mat.T
    diffs = np.diff(all_cart, axis=0)
    dists = np.linalg.norm(diffs, axis=1)
    positions = np.concatenate(([0.0], np.cumsum(dists)))

    if labels is None:
        labels = tuple(auto_labels)
    else:
        if len(labels) != len(resolved_wp):
            raise ValueError(
                f"Number of labels ({len(labels)}) must match number of waypoints ({len(resolved_wp)})."
            )
        labels = tuple(labels)

    return BzPath(
        k_space=k_space,
        labels=labels,
        waypoint_indices=tuple(waypoint_indices),
        path_order=tuple(path_order),
        path_positions=tuple(float(p) for p in positions),
    )

match_indices

match_indices(
    src: StateSpace[T],
    dest: StateSpace[T],
    matching_func: Callable[[T], T],
    *,
    device: Optional[Device] = None,
) -> Tensor[torch.LongTensor]

Build destination indices for matching elements of src into dest.

This helper is intended for indexed accumulation patterns such as index_add, where each element of src is matched to exactly one element of dest and multiple source elements may map to the same destination.

Parameters:

Name Type Description Default
src StateSpace[T]

Source state space whose element order defines the output index order.

required
dest StateSpace[T]

Destination state space whose integer positions are used as the returned indices.

required
matching_func Callable[[T], T]

Function mapping each source element to its matching destination element.

required
device Optional[Device]

Device to place the returned index tensor on, by default None (CPU).

None

Returns:

Type Description
Tensor[LongTensor]

Rank-1 integer tensor with dims (src,), where each entry is the destination index of the corresponding source element.

Raises:

Type Description
ValueError

If any source element maps to an element that is not present in dest.

Source code in src/qten/symbolics/ops.py
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
def match_indices(
    src: StateSpace[T],
    dest: StateSpace[T],
    matching_func: Callable[[T], T],
    *,
    device: Optional[Device] = None,
) -> Tensor[torch.LongTensor]:
    """
    Build destination indices for matching elements of `src` into `dest`.

    This helper is intended for indexed accumulation patterns such as
    `index_add`, where each element of `src` is matched to exactly one element
    of `dest` and multiple source elements may map to the same destination.

    Parameters
    ----------
    src : StateSpace[T]
        Source state space whose element order defines the output index order.
    dest : StateSpace[T]
        Destination state space whose integer positions are used as the
        returned indices.
    matching_func : Callable[[T], T]
        Function mapping each source element to its matching destination
        element.
    device : Optional[Device], optional
        Device to place the returned index tensor on, by default `None` (CPU).

    Returns
    -------
    Tensor[torch.LongTensor]
        Rank-1 integer tensor with dims `(src,)`, where each entry is the
        destination index of the corresponding source element.

    Raises
    ------
    ValueError
        If any source element maps to an element that is not present in `dest`.
    """
    indices: list[int] = []
    for source_element in src:
        matched = matching_func(source_element)
        if matched not in dest.structure:
            raise ValueError(
                f"Source element {source_element} maps to {matched}, which is not present in destination."
            )
        indices.append(dest.structure[matched])

    return Tensor(
        data=cast(
            torch.LongTensor,
            torch.tensor(
                indices,
                dtype=torch.long,
                device=device.torch_device() if device is not None else None,
            ),
        ),
        dims=(src,),
    )

rebase_opr

rebase_opr(space: S) -> FuncOpr[OffsetType]

Build an operator that rebases spatial irreps into space.

For affine spaces this targets Offset irreps. For reciprocal lattices it targets Momentum irreps.

Parameters:

Name Type Description Default
space AffineSpace | ReciprocalLattice

Target space into which matching spatial irreps are rebased.

required

Returns:

Type Description
FuncOpr

Operator applying \(r \mapsto r.\mathrm{rebase}(\mathrm{space})\) to matching spatial irreps. In code, this calls r.rebase(space).

Source code in src/qten/symbolics/ops.py
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def rebase_opr(space: S) -> FuncOpr[OffsetType]:
    r"""
    Build an operator that rebases spatial irreps into `space`.

    For affine spaces this targets [`Offset`][qten.geometries.spatials.Offset] irreps. For reciprocal lattices it
    targets [`Momentum`][qten.geometries.spatials.Momentum] irreps.

    Parameters
    ----------
    space : AffineSpace | ReciprocalLattice
        Target space into which matching spatial irreps are rebased.

    Returns
    -------
    FuncOpr
        Operator applying \(r \mapsto r.\mathrm{rebase}(\mathrm{space})\) to
        matching spatial irreps. In code, this calls `r.rebase(space)`.
    """
    point_type = cast(
        type[OffsetType], Momentum if isinstance(space, ReciprocalLattice) else Offset
    )
    return FuncOpr(point_type, lambda r: cast(OffsetType, r.rebase(space)))

region_hilbert

region_hilbert(
    bloch_space: HilbertSpace, region: Sequence[Offset]
) -> HilbertSpace

Expand a Bloch HilbertSpace across a real-space region by unit-cell subgroup.

The input bloch_space is first partitioned by the fractional part of each basis state's Offset irrep, so all sub-basis states that occupy the same position within the unit cell stay grouped together. Each offset in region is treated as a full target-site offset that already includes its unit-cell position. A region site r therefore selects the subgroup whose fractional offset equals r.fractional(), and every state in that subgroup is copied with its Offset replaced by r.

Parameters:

Name Type Description Default
bloch_space HilbertSpace

Source basis to replicate. Each basis element must contain an Offset irrep. Elements with the same fractional offset are treated as the sub-basis of one unit-cell site and are replicated together.

required
region Sequence[Offset]

Full target offsets where the matching unit-cell sub-basis should be placed.

required

Returns:

Type Description
HilbertSpace

A Hilbert space containing one copied basis state for each compatible pair of region offset and unit-cell subgroup, with output offsets taken from region after rebasing into the Bloch offset space when needed.

Raises:

Type Description
ValueError

Propagated if a basis element in bloch_space does not contain an Offset irrep to inspect or replace, or if region contains a fractional offset that does not exist in bloch_space.

Notes

Grouping is done by fractional Offset, preserving the original basis order inside each subgroup. Output order follows region.

Source code in src/qten/symbolics/ops.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
def region_hilbert(bloch_space: HilbertSpace, region: Sequence[Offset]) -> HilbertSpace:
    """
    Expand a Bloch [`HilbertSpace`][qten.symbolics.hilbert_space.HilbertSpace] across a real-space region by unit-cell subgroup.

    The input `bloch_space` is first partitioned by the fractional part of each
    basis state's [`Offset`][qten.geometries.spatials.Offset] irrep, so all sub-basis states that occupy the same
    position within the unit cell stay grouped together. Each offset in
    `region` is treated as a full target-site offset that already includes its
    unit-cell position. A region site `r` therefore selects the subgroup whose
    fractional offset equals `r.fractional()`, and every state in that subgroup
    is copied with its [`Offset`][qten.geometries.spatials.Offset] replaced by `r`.

    Parameters
    ----------
    bloch_space : HilbertSpace
        Source basis to replicate. Each basis element must contain an [`Offset`][qten.geometries.spatials.Offset]
        irrep. Elements with the same fractional offset are treated as the
        sub-basis of one unit-cell site and are replicated together.
    region : Sequence[Offset]
        Full target offsets where the matching unit-cell sub-basis should be
        placed.

    Returns
    -------
    HilbertSpace
        A Hilbert space containing one copied basis state for each compatible
        pair of region offset and unit-cell subgroup, with output offsets taken
        from `region` after rebasing into the Bloch offset space when needed.

    Raises
    ------
    ValueError
        Propagated if a basis element in `bloch_space` does not contain an
        Offset irrep to inspect or replace, or if `region` contains a
        fractional offset that does not exist in `bloch_space`.

    Notes
    -----
    Grouping is done by fractional [`Offset`][qten.geometries.spatials.Offset], preserving the original basis
    order inside each subgroup. Output order follows `region`.
    """
    grouped_basis: dict[Offset, list] = {}
    bloch_offset_space = None
    for psi in bloch_space:
        offset = psi.irrep_of(Offset)
        if bloch_offset_space is None:
            bloch_offset_space = offset.space
        offset = offset.fractional()
        grouped_basis.setdefault(offset, []).append(psi)

    def iter_region_basis():
        for region_offset in region:
            if (
                bloch_offset_space is not None
                and region_offset.space != bloch_offset_space
            ):
                region_offset = region_offset.rebase(bloch_offset_space)
            group = grouped_basis.get(region_offset.fractional())
            if group is None:
                raise ValueError(
                    "region contains an offset whose fractional part is not present in bloch_space."
                )
            for psi in group:
                yield psi.replace(region_offset)

    return HilbertSpace.new(iter_region_basis())

translate_opr

translate_opr(d: OffsetType) -> FuncOpr[OffsetType]

Build an operator that translates irreps of the same concrete type by d.

Parameters:

Name Type Description Default
d Offset | Momentum

Translation to add to the targeted irrep.

required

Returns:

Type Description
FuncOpr

Operator applying \(x \mapsto x + d\) to irreps whose concrete type matches type(d).

Source code in src/qten/symbolics/ops.py
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
def translate_opr(d: OffsetType) -> FuncOpr[OffsetType]:
    r"""
    Build an operator that translates irreps of the same concrete type by `d`.

    Parameters
    ----------
    d : Offset | Momentum
        Translation to add to the targeted irrep.

    Returns
    -------
    FuncOpr
        Operator applying \(x \mapsto x + d\) to irreps whose concrete type
        matches `type(d)`.
    """
    point_type = cast(type[OffsetType], type(d))
    return FuncOpr(point_type, lambda r: cast(OffsetType, r + d))