Skip to content

Backends and simulator

dynamiqs

compiler

DiscreteVariableState

Bases: AbstractPureState

A pure quantum state for a discrete variable system.

\(|\psi\rangle = \sum_{i} a_i |i\rangle\) where \(a_i\) are amplitudes and \(|i\rangle\) are basis states.

Source code in src/squint/interface/dv.py
class DiscreteVariableState(AbstractPureState):
    r"""
    A pure quantum state for a discrete variable system.

    $|\psi\rangle = \sum_{i} a_i |i\rangle$ where $a_i$ are amplitudes and $|i\rangle$ are basis states.
    """

    n: Sequence[
        tuple[complex, Sequence[int]]
    ]  # todo: add superposition as n, using second typehint

    @beartype
    def __init__(
        self,
        wires: Sequence[Wire],
        n: Sequence[int] | Sequence[tuple[complex | float, Sequence[int]]] = None,
    ):
        super().__init__(wires=wires)
        if n is None:
            n = [(1.0, (0,) * len(wires))]  # initialize to |0, 0, ...> state
        elif is_bearable(n, Sequence[int]):
            n = [(1.0, n)]
        elif is_bearable(n, Sequence[tuple[complex | float, Sequence[int]]]):
            norm = jnp.sum(jnp.abs(jnp.array([i[0] for i in n])) ** 2)
            n = [((amp / jnp.sqrt(norm)).item(), basis) for amp, basis in n]
        self.n = paramax.non_trainable(n)
        return


    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        return sum(
            [
                jnp.zeros(
                    # shape=(dim,) * len(self.wires)
                    shape=[wire.dim for wire in self.wires]
                )
                .at[*term[1]]
                .set(term[0])
                for term in self.n
            ]
        )
MaximallyMixedState

Bases: AbstractMixedState

The maximally mixed state for discrete variable systems.

Represents the completely mixed density matrix \(\rho = I/d\) where \(d\) is the total Hilbert space dimension. This state has maximum von Neumann entropy and represents complete ignorance about the quantum state.

The density matrix is constructed as: \(\(\rho = \frac{1}{d} \sum_{i=0}^{d-1} |i\rangle\langle i|\)\)

where \(d = \prod_i d_i\) is the product of all wire dimensions.

Example
wire = Wire(dim=2, idx=0)
state = MaximallyMixedState(wires=(wire,))
# Creates rho = [[0.5, 0], [0, 0.5]]
Note

This state requires the "mixed" backend in the circuit.

Source code in src/squint/interface/dv.py
class MaximallyMixedState(AbstractMixedState):
    r"""
    The maximally mixed state for discrete variable systems.

    Represents the completely mixed density matrix $\rho = I/d$ where $d$ is the
    total Hilbert space dimension. This state has maximum von Neumann entropy
    and represents complete ignorance about the quantum state.

    The density matrix is constructed as:
    $$\rho = \frac{1}{d} \sum_{i=0}^{d-1} |i\rangle\langle i|$$

    where $d = \prod_i d_i$ is the product of all wire dimensions.

    Example:
        ```python
        wire = Wire(dim=2, idx=0)
        state = MaximallyMixedState(wires=(wire,))
        # Creates rho = [[0.5, 0], [0, 0.5]]
        ```

    Note:
        This state requires the "mixed" backend in the circuit.
    """

    @beartype
    def __init__(
        self,
        wires: Sequence[Wire],
    ):
        super().__init__(wires=wires)

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        dims = [wire.dim for wire in self.wires]
        d = math.prod(dims)
        identity = jnp.eye(d, dtype=jnp.complex128) / d
        tensor = identity.reshape(tuple(dim for dim in dims for _ in range(2)))
        return tensor
XGate

Bases: AbstractGate

The generalized shift operator, which when dim = 2 corresponds to the standard \(X\) gate.

\(U = \sum_{k=0}^{d-1} |k\rangle \langle (k+1) \mod d|\)

Source code in src/squint/interface/dv.py
class XGate(AbstractGate):
    r"""
    The generalized shift operator, which when `dim = 2` corresponds to the standard $X$ gate.

    $U = \sum_{k=0}^{d-1} |k\rangle \langle (k+1) \mod d|$
    """

    @beartype
    def __init__(
        self,
        wires: tuple[Wire] = (0,),
    ):
        super().__init__(wires=wires)
        return

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        return x(self.wires[0].dim)
ZGate

Bases: AbstractGate

The generalized phase operator, which when dim = 2 corresponds to the standard \(Z\) gate.

\(U = \sum_{k=0}^{d-1} e^{2\pi i k / d} |k\rangle\langle k|\)

Source code in src/squint/interface/dv.py
class ZGate(AbstractGate):
    r"""
    The generalized phase operator, which when `dim = 2` corresponds to the standard $Z$ gate.

    $U = \sum_{k=0}^{d-1} e^{2\pi i k / d} |k\rangle\langle k|$
    """

    @beartype
    def __init__(
        self,
        wires: tuple[Wire] = (0,),
    ):
        super().__init__(wires=wires)
        return

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        return z(self.wires[0].dim)
HGate

Bases: AbstractGate

The generalized discrete Fourier operator, which when dim = 2 corresponds to the standard \(H\) gate.

\(U = \frac{1}{\sqrt{d}} \sum_{j,k=0}^{d-1} e^{2\pi i jk / d} |j\rangle\langle k|\)

Source code in src/squint/interface/dv.py
class HGate(AbstractGate):
    r"""
    The generalized discrete Fourier operator, which when `dim = 2` corresponds to the standard $H$ gate.

    $U = \frac{1}{\sqrt{d}} \sum_{j,k=0}^{d-1} e^{2\pi i jk / d} |j\rangle\langle k|$
    """

    @beartype
    def __init__(
        self,
        wires: tuple[Wire] = (0,),
    ):
        super().__init__(wires=wires)
        return

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        dim = self.wires[0].dim
        return jnp.exp(
            1j
            * 2
            * jnp.pi
            / dim
            * jnp.einsum("a,b->ab", jnp.arange(dim), jnp.arange(dim))
        ) / jnp.sqrt(dim)
Conditional

Bases: AbstractGate

The generalized conditional operator. Applies gate \(U\) raised to a power conditional on the control state: \(U = \sum_{k=0}^{d-1} |k\rangle\langle k| \otimes U^k\)

Source code in src/squint/interface/dv.py
class Conditional(AbstractGate):
    r"""
    The generalized conditional operator.
    Applies gate $U$ raised to a power conditional on the control state:
    $U = \sum_{k=0}^{d-1} |k\rangle\langle k| \otimes U^k$
    """

    # gate: Union[XGate, ZGate]  # type: ignore
    ufunc: Callable

    @beartype
    def __init__(
        self,
        # gate: Union[Type[XGate], Type[ZGate]],
        ufunc: Callable = eye,
        wires: tuple[Wire, Wire] = (0, 1),
    ):
        super().__init__(wires=wires)
        self.ufunc = ufunc
        # self.gate = gate(wires=(wires[1],))
        return

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        u = sum(
            [
                jnp.einsum(
                    "ac,bd -> abcd",
                    jnp.zeros(shape=(self.wires[0].dim, self.wires[0].dim))
                    .at[i, i]
                    .set(1.0),
                    # jnp.linalg.matrix_power(self.gate(), i),
                    jnp.linalg.matrix_power(self.ufunc(self.wires[1].dim), i),
                )
                for i in range(self.wires[0].dim)
            ]
        )

        return u
RZGate

Bases: AbstractGate

Rotation gate around the Z-axis for qubits and qudits.

For qubits (dim=2), this implements the standard RZ rotation: \(\(R_Z(\phi) = \begin{pmatrix} 1 & 0 \\ 0 & e^{i\phi} \end{pmatrix}\)\)

For qudits (dim>2), this generalizes to: \(\(R_Z(\phi) = \sum_{k=0}^{d-1} e^{ik\phi} |k\rangle\langle k|\)\)

Attributes:

Name Type Description
phi ArrayLike

The rotation angle in radians.

Example
wire = Wire(dim=2, idx=0)
rz = RZGate(wires=(wire,), phi=jnp.pi/4)
Source code in src/squint/interface/dv.py
class RZGate(AbstractGate):
    r"""
    Rotation gate around the Z-axis for qubits and qudits.

    For qubits (dim=2), this implements the standard RZ rotation:
    $$R_Z(\phi) = \begin{pmatrix} 1 & 0 \\ 0 & e^{i\phi} \end{pmatrix}$$

    For qudits (dim>2), this generalizes to:
    $$R_Z(\phi) = \sum_{k=0}^{d-1} e^{ik\phi} |k\rangle\langle k|$$

    Attributes:
        phi (ArrayLike): The rotation angle in radians.

    Example:
        ```python
        wire = Wire(dim=2, idx=0)
        rz = RZGate(wires=(wire,), phi=jnp.pi/4)
        ```
    """

    phi: ArrayLike

    @beartype
    def __init__(
        self,
        wires: tuple[Wire] = (0,),
        # phi: float | int = 0.0,
        phi: float | int | Float[Scalar, ""] = 0.0,
    ):
        super().__init__(wires=wires)
        self.phi = jnp.array(phi)
        return

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        return jnp.diag(jnp.exp(1j * bases(self.wires[0].dim) * self.phi))
RXGate

Bases: AbstractGate

Rotation gate around the X-axis for qubits.

Implements the standard RX rotation: \(\(R_X(\phi) = \cos(\phi/2) I - i \sin(\phi/2) X = \begin{pmatrix} \cos(\phi/2) & -i\sin(\phi/2) \\ -i\sin(\phi/2) & \cos(\phi/2) \end{pmatrix}\)\)

Attributes:

Name Type Description
phi ArrayLike

The rotation angle in radians.

Note

This gate is only defined for qubits (dim=2).

Example
wire = Wire(dim=2, idx=0)
rx = RXGate(wires=(wire,), phi=jnp.pi/2)
Source code in src/squint/interface/dv.py
class RXGate(AbstractGate):
    r"""
    Rotation gate around the X-axis for qubits.

    Implements the standard RX rotation:
    $$R_X(\phi) = \cos(\phi/2) I - i \sin(\phi/2) X = \begin{pmatrix} \cos(\phi/2) & -i\sin(\phi/2) \\ -i\sin(\phi/2) & \cos(\phi/2) \end{pmatrix}$$

    Attributes:
        phi (ArrayLike): The rotation angle in radians.

    Note:
        This gate is only defined for qubits (dim=2).

    Example:
        ```python
        wire = Wire(dim=2, idx=0)
        rx = RXGate(wires=(wire,), phi=jnp.pi/2)
        ```
    """

    phi: ArrayLike

    @beartype
    def __init__(
        self,
        wires: tuple[Wire] = (0,),
        phi: float | int = 0.0,
        # phi: Inexact[Scalar] = 0.0
    ):
        assert wires[0].dim == 2, "RXGate only defined for dim=2."
        super().__init__(wires=wires)
        self.phi = jnp.array(phi)
        return

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        return (
            jnp.cos(self.phi / 2) * basis_operators(self.wires[0].dim)[3]  # identity
            - 1j * jnp.sin(self.phi / 2) * basis_operators(self.wires[0].dim)[2]  # X
        )
RYGate

Bases: AbstractGate

Rotation gate around the Y-axis for qubits.

Implements the standard RY rotation: \(\(R_Y(\phi) = \cos(\phi/2) I - i \sin(\phi/2) Y = \begin{pmatrix} \cos(\phi/2) & -\sin(\phi/2) \\ \sin(\phi/2) & \cos(\phi/2) \end{pmatrix}\)\)

Attributes:

Name Type Description
phi ArrayLike

The rotation angle in radians.

Note

This gate is only defined for qubits (dim=2).

Example
wire = Wire(dim=2, idx=0)
ry = RYGate(wires=(wire,), phi=jnp.pi/2)
Source code in src/squint/interface/dv.py
class RYGate(AbstractGate):
    r"""
    Rotation gate around the Y-axis for qubits.

    Implements the standard RY rotation:
    $$R_Y(\phi) = \cos(\phi/2) I - i \sin(\phi/2) Y = \begin{pmatrix} \cos(\phi/2) & -\sin(\phi/2) \\ \sin(\phi/2) & \cos(\phi/2) \end{pmatrix}$$

    Attributes:
        phi (ArrayLike): The rotation angle in radians.

    Note:
        This gate is only defined for qubits (dim=2).

    Example:
        ```python
        wire = Wire(dim=2, idx=0)
        ry = RYGate(wires=(wire,), phi=jnp.pi/2)
        ```
    """

    phi: ArrayLike

    @beartype
    def __init__(
        self,
        wires: tuple[Wire] = (0,),
        phi: float | int = 0.0,
    ):
        assert wires[0].dim == 2, "RYGate only defined for dim=2."

        super().__init__(wires=wires)
        self.phi = jnp.array(phi)
        return

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        return (
            jnp.cos(self.phi / 2) * basis_operators(self.wires[0].dim)[3]  # identity
            - 1j * jnp.sin(self.phi / 2) * basis_operators(self.wires[0].dim)[1]  # Y
        )
TwoLocalHermitianBasisGate

Bases: AbstractGate

Two-qubit/qudit gate generated by a tensor product of Gell-Mann basis operators.

Implements gates of the form: \(\(U(\theta) = \exp(-i \theta \cdot G_i \otimes G_j)\)\)

where \(G_i\) and \(G_j\) are Gell-Mann basis operators (generalized Pauli matrices) acting on the first and second wire respectively. For qubits (dim=2), the Gell-Mann operators reduce to the Pauli matrices.

This is the base class for specific two-qubit interaction gates like RXXGate and RZZGate.

Attributes:

Name Type Description
angles ArrayLike

The rotation angle(s) in radians.

_basis_op_indices tuple[int, int]

Indices of the Gell-Mann basis operators to use on each wire. For dim=2: 0=Z, 1=Y, 2=X, 3=I.

Example
wire0 = Wire(dim=2, idx=0)
wire1 = Wire(dim=2, idx=1)
# Create an XX interaction gate
gate = TwoLocalHermitianBasisGate(
    wires=(wire0, wire1),
    angles=jnp.pi/4,
    _basis_op_indices=(2, 2)  # X tensor X
)
Source code in src/squint/interface/dv.py
class TwoLocalHermitianBasisGate(AbstractGate):
    r"""
    Two-qubit/qudit gate generated by a tensor product of Gell-Mann basis operators.

    Implements gates of the form:
    $$U(\theta) = \exp(-i \theta \cdot G_i \otimes G_j)$$

    where $G_i$ and $G_j$ are Gell-Mann basis operators (generalized Pauli matrices)
    acting on the first and second wire respectively. For qubits (dim=2), the
    Gell-Mann operators reduce to the Pauli matrices.

    This is the base class for specific two-qubit interaction gates like RXXGate
    and RZZGate.

    Attributes:
        angles (ArrayLike): The rotation angle(s) in radians.
        _basis_op_indices (tuple[int, int]): Indices of the Gell-Mann basis operators
            to use on each wire. For dim=2: 0=Z, 1=Y, 2=X, 3=I.

    Example:
        ```python
        wire0 = Wire(dim=2, idx=0)
        wire1 = Wire(dim=2, idx=1)
        # Create an XX interaction gate
        gate = TwoLocalHermitianBasisGate(
            wires=(wire0, wire1),
            angles=jnp.pi/4,
            _basis_op_indices=(2, 2)  # X tensor X
        )
        ```
    """

    angles: ArrayLike
    _basis_op_indices: tuple[
        int, int
    ]  # index of basis (Gell-Mann) ops to apply on the first and second wires, respectively

    @beartype
    def __init__(
        self,
        wires: tuple[Wire, Wire],
        angles: Union[float, int, Sequence[int], Sequence[float], ArrayLike],
        _basis_op_indices: tuple[int, int] = (2, 2),
    ):
        super().__init__(wires=wires)

        self.angles = jnp.array(angles)
        self._basis_op_indices = _basis_op_indices
        return

    def _hermitian_op(self):
        return jnp.kron(
            basis_operators(self.wires[0].dim)[self._basis_op_indices[0]],
            basis_operators(self.wires[1].dim)[self._basis_op_indices[1]],
        )

    def _rearrange(self, tensor: ArrayLike):
        return tensor.reshape(
            self.wires[0].dim,
            self.wires[1].dim,
            self.wires[0].dim,
            self.wires[1].dim,
        )

    # def _dim_check(self, dim: int):
    # raise NotImplementedError()

    @dispatch
    def lower(self, backend: TensorNetworkBackend):
        # return self._rearrange(self._hermitian_op(dim), dim)
        # return self._hermitian_op(dim)
        # self._dim_check(dim)
        return self._rearrange(
            jsp.linalg.expm(-1j * self.angles * self._hermitian_op())
        )

tensornetwork

compiler

MapTensorIndicesMixed

Bases: ConversionRule, TensorNetworkBackend

Maps a symbolic circuit object to a string of input/output tensor leg indices

Source code in src/squint/backends/tensornetwork/compiler.py
class MapTensorIndicesMixed(ConversionRule, TensorNetworkBackend):
    """
    Maps a symbolic circuit object to a string of input/output tensor leg indices
    """

    def __init__(
        self,
    ):
        super().__init__()
        self.types = ("ket", "bra", "channel", "prob")
        self._wires_curr_leg = {"ket": {}, "bra": {}, "channel": {}, "prob": {}}

        self._count = {
            "ket": itertools.count(0),
            "bra": itertools.count(0),
            "channel": itertools.count(0),
            "prob": itertools.count(0),
        }

        self.get_next_character = {
            "ket": self.get_next_character_ket,
            "bra": self.get_next_character_bra,
            "channel": self.get_next_character_channel,
            "prob": self.get_next_character_channel,
        }

        self._subscripts_left = []
        self._subscripts_right = []

    def get_next_character_ket(self):
        return get_symbol(2 * next(self._count["ket"]))

    def get_next_character_bra(self):
        return get_symbol(2 * next(self._count["bra"]) + 1)

    def get_next_character_channel(self):
        return get_symbol(next(self._count["channel"]) + 50000)

    def get_next_character_prob(self):
        return get_symbol(next(self._count["prob"]) + 25000)

    def map_Circuit(self, model, operands):
        # print(self._wires_curr_leg)
        rhs = "".join(
            leg
            for leg in itertools.chain(
                self._wires_curr_leg["ket"].values(),
                self._wires_curr_leg["bra"].values(),
                self._wires_curr_leg["prob"].values(),
            )
            if leg is not None
        )
        return (Circuit(**operands), rhs)

    def map_AbstractMixedState(self, model, operands):
        legs_out = {"ket": [], "bra": []}
        for wire in model.wires:
            for t in ("ket", "bra"):
                leg_out = self.get_next_character[t]()

                legs_out[t].append(leg_out)
                self._wires_curr_leg[t][wire.idx] = leg_out

        subscripts = "".join(legs_out["ket"] + legs_out["bra"])
        self._subscripts_left.append(subscripts)

        object.__setattr__(model, "subscripts", subscripts)
        return model 

    def map_AbstractPureState(self, model, operands):
        legs_out = {"ket": [], "bra": []}
        for wire in model.wires:
            for t in ("ket", "bra"):
                leg_out = self.get_next_character[t]()

                legs_out[t].append(leg_out)
                self._wires_curr_leg[t][wire.idx] = leg_out

        subscripts = "".join(legs_out["ket"]) + "," + "".join(legs_out["bra"])
        self._subscripts_left.append(subscripts)

        object.__setattr__(model, "subscripts", subscripts)
        return model 

    def map_AbstractProjectiveMeasurement(self, model, operands):
        legs_in, legs_out = {"ket": [], "bra": []}, {"ket": [], "bra": []}
        for wire in model.wires:
            for t in ("ket", "bra"):
                leg_in = self._wires_curr_leg[t][wire.idx]
                # leg_out = self.get_next_character[t]()

                legs_in[t].append(leg_in)
                # legs_out[t].append(None)

                self._wires_curr_leg[t][wire.idx] = None


        leg_out_prob = self.get_next_character["prob"]()
        self._wires_curr_leg["prob"][model.out.idx] = leg_out_prob

        subscripts = (
            "".join([leg_out_prob] + legs_in["ket"] + legs_in["bra"])
        )
        self._subscripts_left.append(subscripts)

        object.__setattr__(model, "subscripts", subscripts)
        return model 

    def map_AbstractGate(self, model, operands):
        legs_in, legs_out = {"ket": [], "bra": []}, {"ket": [], "bra": []}
        for wire in model.wires:
            for t in ("ket", "bra"):
                leg_in = self._wires_curr_leg[t][wire.idx]
                leg_out = self.get_next_character[t]()

                legs_in[t].append(leg_in)
                legs_out[t].append(leg_out)

                self._wires_curr_leg[t][wire.idx] = leg_out

        subscripts = (
            "".join(legs_in["ket"] + legs_out["ket"])
            + ","
            + "".join(legs_in["bra"] + legs_out["bra"])
        )
        self._subscripts_left.append(subscripts)

        object.__setattr__(model, "subscripts", subscripts)
        return model     

    def map_AbstractKrausChannel(self, model, operands):
        legs_in, legs_out = {"ket": [], "bra": []}, {"ket": [], "bra": []}
        for wire in model.wires:
            for t in ("ket", "bra"):
                leg_in = self._wires_curr_leg[t][wire.idx]
                leg_out = self.get_next_character[t]()

                legs_in[t].append(leg_in)
                legs_out[t].append(leg_out)

                self._wires_curr_leg[t][wire.idx] = leg_out

        # the leg index that represents the contraction between the Kraus operator tensors
        # canonically, this is the last index - therefore all AbstractKrausOperators should stack along axis=-1 
        leg_ch = self.get_next_character["channel"]()

        subscripts = (
            "".join(legs_in["ket"] + legs_out["ket"] + [leg_ch])
            + ","
            + "".join(legs_in["bra"] + legs_out["bra"] + [leg_ch])  
        )
        self._subscripts_left.append(subscripts)

        object.__setattr__(model, "subscripts", subscripts)
        return model 

    def map_AbstractErasureChannel(self, model, operands):
        legs_in = {"ket": [], "bra": []}
        for wire in model.wires:
            for t in ("ket", "bra"):
                leg_in = self._wires_curr_leg[t][wire.idx]
                legs_in[t].append(leg_in)

                self._wires_curr_leg[t][wire.idx] = None

        leg_ch = self.get_next_character["channel"]()

        subscripts = (
            "".join(legs_in["ket"] + [leg_ch])
            + ","
            + "".join(legs_in["bra"] + [leg_ch])
        )
        self._subscripts_left.append(subscripts)

        object.__setattr__(model, "subscripts", subscripts)
        return model 
MapTensorIndicesPure

Bases: ConversionRule, TensorNetworkBackend

Source code in src/squint/backends/tensornetwork/compiler.py
class MapTensorIndicesPure(ConversionRule, TensorNetworkBackend):
    """ """

    def __init__(
        self,
    ):
        super().__init__()
        self._wires_curr_leg = {}
        self._count = itertools.count(0)

        self._subscripts_left = []
        self._subscripts_right = []

    def get_next_character(self):
        return get_symbol(next(self._count))

    # TODO: Wires may not be in a canonical order - we need to output the wire order that defines the state obj
    # TODO: Need to accomodate classical probability wires

    def map_Circuit(self, model, operands):
        rhs = "".join(
            self._wires_curr_leg.values()
        )  # RHS subscripts for the tensor contraction
        return (Circuit(**operands), rhs)

    def map_AbstractState(self, model, operands):
        legs_in, legs_out = [], []
        for wire in model.wires:
            # get new char and set as current index
            leg_out = self.get_next_character()
            self._wires_curr_leg[wire.idx] = leg_out
            legs_out.append(leg_out)
        subscripts = "".join(legs_in + legs_out)
        self._subscripts_left.append(subscripts)

        object.__setattr__(model, "subscripts", subscripts)
        return model 


    def map_AbstractGate(self, model, operands):
        legs_in, legs_out = [], []
        for wire in model.wires:
            leg_in = self._wires_curr_leg[wire.idx]
            legs_in.append(leg_in)
            leg_out = self.get_next_character()
            self._wires_curr_leg[wire.idx] = leg_out
            legs_out.append(leg_out)
        subscripts = "".join(legs_in + legs_out)
        self._subscripts_left.append(subscripts)

        object.__setattr__(model, "subscripts", subscripts)
        return model
GeneratePureTensors

Bases: ConversionRule, TensorNetworkBackend

Source code in src/squint/backends/tensornetwork/compiler.py
class GeneratePureTensors(ConversionRule, TensorNetworkBackend):
    """
    """
    def __init__(self, ):
        super().__init__()
        self.tensors = []

    def map_Circuit(self, model, operands):
        return self.tensors

    def map_Block(self, model, operands):
        return operands

    def map_AbstractGate(self, model, operands):
        tensor = model(self)
        self.tensors += [tensor]
        return [tensor]

    def map_AbstractPureState(self, model, operands):
        tensor = model(self)
        self.tensors += [tensor]
        return [tensor]