graphix.sim package¶
Submodules¶
- graphix.sim.base_backend module
tensordot()kron()outer()vdot()matmul()NodeIndexNoiseNotSupportedErrorDenseStateBackendDenseStateBackendKwargsDenseStateBackendDenseStateBackend.node_indexDenseStateBackend.branch_selectorDenseStateBackend.symbolicDenseStateBackend.add_nodes()DenseStateBackend.entangle_nodes()DenseStateBackend.measure()DenseStateBackend.correct_byproduct()DenseStateBackend.apply_noise()DenseStateBackend.apply_single()DenseStateBackend.apply_clifford()DenseStateBackend.finalize()DenseStateBackend.nqubitDenseStateBackend.__init__()
- graphix.sim.data module
- graphix.sim.density_matrix module
DensityMatrixDensityMatrix.__init__()DensityMatrix.rhoDensityMatrix.nqubitDensityMatrix.draw()DensityMatrix.add_nodes()DensityMatrix.evolve_single()DensityMatrix.evolve()DensityMatrix.expectation_single()DensityMatrix.dims()DensityMatrix.tensor()DensityMatrix.cnot()DensityMatrix.swap()DensityMatrix.permute()DensityMatrix.entangle()DensityMatrix.normalize()DensityMatrix.remove_qubit()DensityMatrix.ptrace()DensityMatrix.fidelity()DensityMatrix.flatten()DensityMatrix.apply_channel()DensityMatrix.apply_noise()DensityMatrix.replace_parameter()DensityMatrix.replace_parameters()
DensityMatrixBackend
- graphix.sim.statevec module
NUM_QUBIT_PARALLELStatevectorStatevector._psiStatevector._nqubitStatevector._max_qubitsStatevector.__init__()Statevector.psiStatevector.nqubitStatevector.max_qubitsStatevector.ensure_capacity()Statevector.flatten()Statevector.add_nodes()Statevector.entangle()Statevector.evolve_single()Statevector.expectation_single()Statevector.evolve()Statevector.expectation_value()Statevector.remove_qubit()Statevector.project_qubit()Statevector.swap()Statevector.tensor()Statevector.permute()Statevector.fidelity()Statevector.isclose()Statevector.to_dict()Statevector.to_prob_dict()Statevector.draw()
StatevectorBackend
- graphix.sim.tensornet module
MBQCTensorNetMBQCTensorNet.__init__()MBQCTensorNet.open_tensor()MBQCTensorNet.add_qubit()MBQCTensorNet.evolve_single()MBQCTensorNet.add_qubits()MBQCTensorNet.measure_single()MBQCTensorNet.prepare_graph_state()MBQCTensorNet.basis_coefficient()MBQCTensorNet.basis_amplitude()MBQCTensorNet.to_statevector()MBQCTensorNet.flatten()MBQCTensorNet.norm()MBQCTensorNet.expectation_value()MBQCTensorNet.evolve()MBQCTensorNet.copy()
TensorNetworkBackendgen_str()outer_product()
Module contents¶
Simulation backends.
- class Backend[source]¶
Bases:
Generic[_StateT_co]Abstract base class for all quantum backends.
A backend is responsible for managing a quantum system, including the set of active qubits (nodes), their initialization, evolution, and measurement. It defines the interface through which high-level quantum programs interact with the underlying simulation or hardware model.
Concrete subclasses implement specific state representations and simulation strategies, such as dense state vectors, density matrices, or tensor networks.
Responsibilities of a backend typically include: - Managing a dynamic set of qubits (nodes) and their state - Applying quantum gates or operations - Performing measurements and returning classical outcomes - Tracking and exposing the underlying quantum state
Examples of concrete subclasses include: -
StatevectorBackend(pure states via state vectors) -DensityMatrixBackend(mixed states via density matrices) -TensorNetworkBackend(compressed states via tensor networks)- Parameters:
state (BackendState) – internal state of the backend: instance of
Statevector,DensityMatrix, orMBQCTensorNet.
See also
BackendState, :class:`DenseStateBackend,StatevectorBackend,DensityMatrixBackend,TensorNetworkBackendNotes
This class is abstract and should not be instantiated directly.
The class hierarchy of states mirrors the class hierarchy of backends: -
DenseStateBackendandTensorNetworkBackendare subclasses ofBackend,and
DenseStateandMBQCTensorNetare subclasses ofBackendState.StatevectorBackendandDensityMatrixBackendare subclasses ofDenseStateBackend, andStatevectorandDensityMatrixare subclasses ofDenseState.
The type variable
_StateT_cospecifies the type of thestatefield, so that subclasses provide a precise type for this field: -StatevectorBackendis a subtype ofBackend[Statevector]. -DensityMatrixBackendis a subtype ofBackend[DensityMatrix]. -TensorNetworkBackendis a subtype ofBackend[MBQCTensorNet].The type variables
_StateT_coand_DenseStateT_coare declared as covariant. That is,Backend[T1]is a subtype ofBackend[T2]ifT1is a subtype ofT2. This means thatStatevectorBackend,DensityMatrixBackend, andTensorNetworkBackendare all subtypes ofBackend[BackendState]. This covariance is sound because backends are frozen dataclasses; thus, the type ofstatecannot be changed after instantiation.The interface expected from a backend includes the following methods: -
add_nodes: which executesNcommands. -apply_channel: used for noisy simulations.The class
Backendprovides a default implementation that raisesNoiseNotSupportedError, indicating that the backend does not support noise. Backends that support noise (e.g.,DensityMatrixBackend) override this method to implement the effect of noise.apply_clifford: executesCcommands.correct_byproduct: executesXandZcommands.entangle_nodes: executesEcommands.finalize: called at the end of pattern simulation to convey the order of output nodes.
- state: _StateT_co¶
- abstractmethod add_nodes(nodes: Sequence[int], data: Data = graphix.states.PlanarState(Plane.XY, 0)) None[source]¶
Add new nodes (qubits) to the backend and initialize them in a specified state.
- Parameters:
nodes (Sequence[int]) – A list of node indices to add to the backend. These indices can be any integer values but must be fresh: each index must be distinct from all previously added nodes.
data (Data, optional) –
The state in which to initialize the newly added nodes. The supported forms of state specification depend on the backend implementation.
All backends must support the basic predefined states in
BasicStates.If a single basic state is provided, all new nodes are initialized in that state.
If a list of basic states is provided, it must match the length of
nodes, and each node is initialized with its corresponding state.
Some backends support other forms of state specification.
StatevectorBackendsupports arbitrary state vectors:A single-qubit state vector will be broadcast to all nodes.
A multi-qubit state vector of dimension \(2^n\), where \(n = \mathrm{len}(nodes)\), initializes the new nodes jointly.
DensityMatrixBackendsupports both state vectors and density matrices:State vectors are handled as in
StatevectorBackend, and converted to density matrices.A density matrix must have shape \(2^n \times 2^n\), where \(n = \mathrm{len}(nodes)\), and is used to jointly initialize the new nodes.
Notes
Previously existing nodes remain unchanged.
- apply_noise(cmd: ApplyNoise) None[source]¶
Apply noise.
The default implementation of this method raises
NoiseNotSupportedError, indicating that the backend does not support noise. Backends that support noise (e.g.,DensityMatrixBackend) override this method to implement the effect of noise.Note: the simulator is responsible for checking that the measurement outcomes match the domain condition before calling this method.
- Parameters:
nodes (sequence of ints.) – Target qubits
noise (Noise) – Noise to apply
- abstractmethod apply_clifford(node: int, clifford: Clifford) None[source]¶
Apply single-qubit Clifford gate, specified by vop index specified in graphix.clifford.CLIFFORD.
- abstractmethod correct_byproduct(cmd: command.X | command.Z) None[source]¶
Byproduct correction correct for the X or Z byproduct operators, by applying the X or Z gate.
Note: the simulator is responsible for checking that the measurement outcomes match the domain condition before calling this method.
- abstractmethod entangle_nodes(edge: tuple[int, int]) None[source]¶
Apply CZ gate to two connected nodes.
- Parameters:
edge (tuple (i, j)) – a pair of node indices
- abstractmethod finalize(output_nodes: Sequence[int]) None[source]¶
To be run at the end of pattern simulation to convey the order of output nodes.
- abstractmethod measure(node: int, measurement: Measurement, rng: Generator | None = None, *, stacklevel: int = 1) Outcome[source]¶
Perform measurement of a node and trace out the qubit.
- Parameters:
node (int)
measurement (Measurement)
rng (Generator, optional) – Random-number generator for measurements. This generator is used only in case of random branch selection (see
RandomBranchSelector).
- class DensityMatrix(data: Data = graphix.states.PlanarState(Plane.XY, 0), nqubit: int | None = None)[source]¶
Bases:
DenseState,InplaceParameterizableDensityMatrix object.
- __init__(data: Data = graphix.states.PlanarState(Plane.XY, 0), nqubit: int | None = None) None[source]¶
Initialize density matrix objects.
The behaviour builds on the one of graphix.statevec.Statevector.
datacan be: - a singlegraphix.states.State(classical description of a quantum state) - an iterable ofgraphix.states.Stateobjects - an iterable of iterable of scalars (A 2**n x 2**n numerical density matrix) - a graphix.statevec.DensityMatrix object - a graphix.statevec.Statevector objectIf
nqubitis not provided, the number of qubit is inferred fromdataand checked for consistency. If only onegraphix.states.Stateis provided and nqubit is a valid integer, initialize the statevector in the tensor product state. If bothnqubitanddataare provided, consistency of the dimensions is checked. If a graphix.statevec.Statevector or graphix.statevec.DensityMatrix is passed, returns a copy.- Parameters:
data (Data) – input data to prepare the state. Can be a classical description or a numerical input, defaults to graphix.states.BasicStates.PLUS
nqubit (int, optional) – number of qubits to prepare, defaults to None
- draw(output: OutputFormat = OutputFormat.Unicode, *, max_denominator: int = 1000, atol: float = 1e-09, rtol: float = 0.0, precision: int = 4) str[source]¶
Return a pretty-printed matrix representation of the density matrix.
Each entry is rendered with
graphix.pretty_print.complex_to_str(), so common values appear as exact expressions (e.g.1/2) rather than floating-point numbers.- Parameters:
output (OutputFormat, optional) – Desired formatting style. Defaults to
OutputFormat.Unicode.max_denominator (int, optional) – Maximum denominator used by the entry recognition (default:
1000).atol (float, optional) – Absolute tolerance for the recognition heuristics (default:
1e-9).rtol (float, optional) – Relative tolerance for the recognition heuristics (default:
0.0).precision (int, optional) – Number of significant digits to use for entries that fall back to a decimal representation (default:
4).
- Returns:
The formatted density matrix.
- Return type:
- add_nodes(nqubit: int, data: Data) None[source]¶
Add nodes (qubits) to the density matrix and initialize them in a specified state.
- Parameters:
nqubit (int) – The number of qubits to add to the density matrix.
data (Data, optional) –
The state in which to initialize the newly added nodes.
If a single basic state is provided, all new nodes are initialized in that state.
If a list of basic states is provided, it must match the length of
nodes, and each node is initialized with its corresponding state.A single-qubit state vector will be broadcast to all nodes.
A multi-qubit state vector of dimension \(2^n\) initializes the new nodes jointly.
A density matrix must have shape \(2^n \times 2^n\), and is used to jointly initialize the new nodes.
The type of nodes to be added is inferred from the type of the existing
DensityMatrix.
Notes
Previously existing nodes remain unchanged.
- evolve_single(op: NDArray[object_ | complex128], qubit: int) None[source]¶
Single-qubit operation.
- Parameters:
op (np.ndarray) – 2*2 matrix.
qubit (int) – Index of qubit to apply operator.
- evolve(op: Matrix, qubits: Sequence[int]) None[source]¶
Multi-qubit operation.
- Parameters:
op (np.array) – 2^n*2^n matrix
qubits (list of ints) – target qubits’ indexes
- expectation_single(op: NDArray[object_ | complex128], qubit: int) complex[source]¶
Return the expectation value of single-qubit operator.
- Parameters:
op (np.array) – 2*2 Hermite operator
qubit (int) – Index of qubit on which to apply operator.
- Returns:
complex
- Return type:
expectation value (real for hermitian ops!).
- tensor(other: DensityMatrix) None[source]¶
Tensor product state with other density matrix.
Results in self \(\otimes\) other.
- Parameters:
other – DensityMatrix object to be tensored with self.
- permute(permutation: Sequence[int]) None[source]¶
Reorder the qubits.
- Parameters:
permutation (Sequence[int]) – The permutation to apply. For each position in the resulting order, the value gives the index of the qubit in the original ordering.
- fidelity(statevec: Statevector) Expression | float[source]¶
Calculate the fidelity against reference statevector.
- Parameters:
statevec (numpy array) – statevector (flattened numpy array) to compare with
- apply_channel(channel: KrausChannel, qargs: Sequence[int]) None[source]¶
Apply a channel to a density matrix.
:param : :type : rho: density matrix. :param channel: KrausChannel to be applied to the density matrix :type channel:
graphix.channel.KrausChannelobject :param qargs: :type qargs: target qubit indices- Return type:
nothing
- Raises:
ValueError – If the final density matrix is not normalized after application of the channel. This shouldn’t happen since
graphix.channel.KrausChannelobjects are normalized by construction..... –
- apply_noise(qubits: Sequence[int], noise: Noise) None[source]¶
Apply noise.
- Parameters:
qubits (sequence of ints.) – Target qubits
noise (Noise) – Noise to apply
- replace_parameter(variable: Parameter, substitute: ExpressionOrSupportsFloat, *, copy: bool = False) DensityMatrix[source]¶
Substitute all occurrences of the given variable in measurement angles by the given value.
- Parameters:
variable (Parameter) – The symbolic expression to be replaced within the measurement angles.
substitute (ExpressionOrSupportsFloat) – The value or symbolic expression to substitute in place of
variable.copy (bool, optional) – If
True, the current object remains unchanged and a new object is returned. The default isFalse, meaning that changes are performed in place.
- Returns:
The object with the updated measurement parameters. Equal to
selfifcopyisFalse.- Return type:
Self
- replace_parameters(assignment: Mapping[Parameter, ExpressionOrSupportsFloat], *, copy: bool = False) DensityMatrix[source]¶
Substitute all occurrences of the given keys in measurement angles by the given values in parallel.
- Parameters:
assignment (Mapping[Parameter, ExpressionOrSupportsFloat]) – A dictionary-like mapping where keys are the
Parameterobjects to be replaced and values are the new expressions or numerical values.copy (bool, optional) – If
True, the current object remains unchanged and a new object is returned. The default isFalse, meaning that changes are performed in place.
- Returns:
The object with the updated measurement parameters. Equal to
selfifcopyisFalse.- Return type:
Self
- class DensityMatrixBackend(*, node_index: NodeIndex = <factory>, branch_selector: BranchSelector = <factory>, symbolic: bool = False)[source]¶
Bases:
DenseStateBackend[DensityMatrix]MBQC simulator with density matrix method.
- __init__(*, node_index: NodeIndex = <factory>, branch_selector: BranchSelector = <factory>, symbolic: bool = False) None¶
- state: DensityMatrix¶
- class MBQCTensorNet(branch_selector: BranchSelector, graph_nodes: Iterable[int] | None = None, graph_edges: Iterable[tuple[int, int]] | None = None, default_output_nodes: Iterable[int] | None = None, ts: list[TensorNetwork] | TensorNetwork | None = None, virtual: bool = False)[source]¶
Bases:
TensorNetworkTensor Network Simulator interface for MBQC patterns, using quimb.tensor.core.TensorNetwork.
- __init__(branch_selector: BranchSelector, graph_nodes: Iterable[int] | None = None, graph_edges: Iterable[tuple[int, int]] | None = None, default_output_nodes: Iterable[int] | None = None, ts: list[TensorNetwork] | TensorNetwork | None = None, virtual: bool = False) None[source]¶
Initialize MBQCTensorNet.
- open_tensor(index: int | str) NDArray[complex128][source]¶
Get tensor specified by node index. The tensor has a dangling edge.
- Parameters:
index (str) – node index
- Returns:
Specified tensor
- Return type:
- add_qubit(index: int, state: str | NDArray[complex128] = 'plus') None[source]¶
Add a single qubit to the network.
- evolve_single(index: int, arr: NDArray[complex128], label: str = 'U') None[source]¶
Apply single-qubit operator to a qubit with the given index.
- Parameters:
index (int) – qubit index.
arr (2*2 numpy.ndarray) – single-qubit operator.
(optional) (label) – label for the gate.
- add_qubits(indices: Sequence[int], states: PrepareState | Iterable[PrepareState] = 'plus') None[source]¶
Add qubits to the network.
- Parameters:
indices (iterator of int) – indices of the new qubits.
(optional) (states) – initial state or list of initial states of the new qubits.
- measure_single(index: int, basis: str | npt.NDArray[np.complex128] = 'Z', bypass_probability_calculation: bool = True, outcome: Outcome | None = None, rng: Generator | None = None, *, stacklevel: int = 1) Outcome[source]¶
Measure a node in specified basis. Note this does not perform the partial trace.
- Parameters:
index (int) – index of the node to be measured.
basis (str or np.ndarray) – default “Z”. measurement basis, “Z” or “X” or “Y” for Pauli basis measurements. 1*2 numpy.ndarray for arbitrary measurement bases.
bypass_probability_calculation (bool) – default True. if True, skip the calculation of the probability of the measurement result and use equal probability for each result. if False, calculate the probability of the measurement result from the state.
outcome (int (0 or 1)) – User-chosen measurement result, giving the outcome of (-1)^{outcome}.
- Returns:
measurement result.
- Return type:
- prepare_graph_state(nodes: Iterable[int], edges: Iterable[tuple[int, int]]) None[source]¶
Prepare the graph state without directly applying CZ gates.
- Parameters:
nodes (iterator of int) – set of the nodes
edges (iterator of tuple) – set of the edges
seealso: (..) –
__init__():
- basis_coefficient(basis: int | str, normalize: bool = True, indices: Sequence[int] | None = None) complex[source]¶
Calculate the coefficient of a given computational basis.
- Parameters:
basis (int or str) – computational basis expressed in binary (str) or integer, e.g. 101 or 5.
(optional) (indices) – if True, normalize the coefficient by the norm of the entire state.
(optional) – target qubit indices to compute the coefficients, default is the MBQC output nodes (self.default_output_nodes).
- Returns:
coef – coefficient
- Return type:
- basis_amplitude(basis: str | int) float[source]¶
Calculate the probability amplitude of the specified computational basis state.
- to_statevector(indices: Sequence[int] | None = None) npt.NDArray[np.complex128][source]¶
Retrieve the statevector from the tensornetwork.
This method tends to be slow however we plan to parallelize this.
- Parameters:
(optional) (indices) – target qubit indices. Default is the MBQC output nodes (self.default_output_nodes).
- Returns:
statevector
- Return type:
- norm(optimize: str | PathOptimizer | None = None) float[source]¶
Calculate the norm of the state.
- Returns:
norm of the state
- Return type:
- expectation_value(op: npt.NDArray[np.complex128], qubit_indices: Sequence[int], output_node_indices: Iterable[int] | None = None, optimize: str | PathOptimizer | None = None) float[source]¶
Calculate expectation value of the given operator.
- Parameters:
op (numpy.ndarray) – single- or multi-qubit Hermitian operator
qubit_indices (list of int) – Applied positions of logical qubits.
(optional) (output_node_indices) – Indices of nodes in the entire TN, that remain unmeasured after MBQC operations. Default is the output nodes specified in measurement pattern (self.default_output_nodes).
- Returns:
Expectation value
- Return type:
- evolve(operator: NDArray[complex128], qubit_indices: list[int], decompose: bool = True) None[source]¶
Apply an arbitrary operator to the state.
- Parameters:
operator (numpy.ndarray) – operator.
qubit_indices (list of int) – Applied positions of logical qubits.
decompose (bool, optional) – default True whether a given operator will be decomposed or not. If True, operator is decomposed into Matrix Product Operator(MPO)
- class Statevector(data: Data = graphix.states.PlanarState(Plane.XY, 0), nqubit: int | None = None, max_qubits: int | None = None)[source]¶
Bases:
DenseStateStatevector object.
- _psi¶
Complex-valued 1-dimensional array representing the quantum statevector. Only the first
2**nqubitcomplex values have meaning.- Type:
npt.NDArray[np.complex128]
- _max_qubits¶
Maximum Hilbert space size allowed for internal computations. It determines the size of
self._psi. For circuit simulations, it corresponds to the number of qubits, while for pattern simulations it corresponds to the pattern’s maximum space. The methodStatevector.ensure_capacity()allows to increase this number.- Type:
Notes
The internal representation of the quantum state is guaranteed to be normalized after initialization, and it is assumed to remain normalized thereafter.
Using
evolve_single(),expectation_single(),evolve(), orexpectation_value()with non-unitary operators does not preserve the norm of the statevector and may lead to unexpected behavior.In pattern simulation, node measurements call
evolve_single()with a projector (a non-unitary operator). However, the measured qubit is immediately removed viaremove_qubit(), which restores the unit norm of the internal quantum state. Seegraphix.sim.base_backend.DenseStateBackend.measure()for additional details.- __init__(data: Data = graphix.states.PlanarState(Plane.XY, 0), nqubit: int | None = None, max_qubits: int | None = None) None[source]¶
Initialize a statevector object.
datacan be: - a singlegraphix.states.State(classical description of a quantum state) - an iterable ofgraphix.states.Stateobjects - an iterable of scalars (a \(2^n\) numerical statevector) - a singlegraphix.sim.statevec.StatevectorIf
nqubitis not provided, it is inferred fromdata. Ifmax_qubitsis not provided, it is set to match the inferredmax_qubits. If only onegraphix.states.Stateis provided andnqubitis a valid integer, the statevector is initialized in the tensor product state. If a class:graphix.sim.statevec.Statevectoris provided, a copy is returned. Consistency between providednqubit,max_qubitsanddatais checked.- Parameters:
data (Data, optional) – Input data to prepare the state. Can be a classical description or a numerical input, defaults to
graphix.states.BasicStates.PLUS.nqubit (int | None, optional) – Number of qubits to prepare. If
None(default), it’s inferred fromdata.max_qubits (int | None, optional.) – Maximum Hilbert space size for array preallocation. If
None(default), it’s set equal tonqubit.
- Raises:
ValueError – If
nqubit,max_qubitsordataare not consistent with each other.
- property psi: NDArray[complex128]¶
View of the meaningful elements in
self._psi.These are the first
2**self.nqubitelements.
- ensure_capacity(required_qubits: int) None[source]¶
Extend the state vector if the required qubit capacity exceeds the current one.
It copies the full state vector if
required_qubits > self.max_qubits, otherwise does nothing.- Parameters:
required_qubits (int) – Minimum number of qubits the state vector must support. If expansion is needed,
self._psiis extended to size2**required_qubits.
- flatten() NDArray[object_ | complex128][source]¶
Return flattened state vector.
A view of only the first
2**self.nqubitelements ofself._psiis returned.
- add_nodes(nqubit: int, data: Data) None[source]¶
Add nodes (qubits) to the state vector and initialize them in a specified state.
Previously existing nodes remain unchanged.
- Parameters:
nqubit (int) – The number of qubits to add to the state vector.
data (Data) –
The state in which to initialize the newly added nodes.
If a single basic state is provided, all new nodes are initialized in that state.
If a list of basic states is provided, it must match the length of
nodes, and each node is initialized with its corresponding state.A single-qubit state vector will be broadcast to all nodes.
A multi-qubit state vector of dimension \(2^n\), where \(n = \mathrm{len}(nodes)\), initializes the new nodes jointly.
Notes
This method can extend the size of
self._psifor convenience, but this requires allocating a full new array.
- evolve_single(op: NDArray[object_ | complex128], qubit: int) None[source]¶
Apply a single-qubit operator.
- Parameters:
op (npt.NDArray[np.complex128]) – Complex-valued matrix of shape \((2, 2)\) representing the operator to apply.
qubit (int) – Target qubit index.
- expectation_single(op: NDArray[object_ | complex128], qubit: int) complex[source]¶
Return the expectation value of a single-qubit operator.
- Parameters:
op (npt.NDArray[np.complex128]) – Complex-valued matrix of shape \((2, 2)\) representing the operator to measure.
qubit (int) – Target qubit index.
- Returns:
Expectation value.
- Return type:
Notes
This method assumes that quantum state represented by
self.psiis normalized. See the class docstring for details.
- evolve(op: Matrix, qubits: Sequence[int]) None[source]¶
Apply a multi-qubit operator.
- Parameters:
op (npt.NDArray[np.complex128]) – Complex-valued matrix of shape \((2^n, 2^n)\) representing the operator to apply.
qubits (Sequence[int]) – Target qubit indices.
Notes
This method is a fallback for circuit simulation and it’s not required for pattern simulation. It does not have an efficient JIT-compiled implementation.
- expectation_value(op: Matrix, qubits: Sequence[int]) complex[source]¶
Return the expectation value of a multi-qubit operator.
- Parameters:
op (npt.NDArray[np.complex128]) – Complex-valued matrix of shape \((2^n, 2^n)\) representing the operator to measure.
qubits (Sequence[int]) – Target qubit indices.
Notes
This method assumes that quantum state represented by
self.psiis normalized. See the class docstring for details.
- remove_qubit(qubit: int) None[source]¶
Remove a separable qubit from the system and assemble the statevector of the remaining qubits.
This method is deprecated. See
self.project_qubit().- Parameters:
qubit (int) – Target qubit index.
- project_qubit(op: NDArray[object_ | complex128], qubit: int) None[source]¶
Project out a qubit from the system and assemble the statevector of the remaining qubits.
This method evolves the statevector with
opand removesqubit. It assumes that after the application ofop,qubitis a separable qubit.Let \(P \ket{\psi} = \sum c_i \ket{i}\) be the statevector after the application of the projector \(P\) (
op), with sum taken over \(i \in [ 0 \dots 00,\ 0\dots 01,\ \dots,\ 1 \dots 11 ]\), this method returns\[\begin{split}\ket{\psi}' =& c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 00} \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 00} \\ & + c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 01} \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 01} \\ & + c_{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k}}0_{\mathrm{k+1}} \dots 10} \ket{0 \dots 0_{\mathrm{k-1}}0_{\mathrm{k+1}} \dots 10} \\ & + \dots \\ & + c_{1 \dots 1_{\mathrm{k-1}}0_{\mathrm{k}}1_{\mathrm{k+1}} \dots 11} \ket{1 \dots 1_{\mathrm{k-1}}1_{\mathrm{k+1}} \dots 11},\end{split}\](after normalization) for \(k =\)
qubit. If the \(k\) th qubit is in the \(\ket{1}\) state, all the amplitudes above will be zero. In that case the returned state will be the one above with \(0_{\mathrm{k}}\) replaced with \(1_{\mathrm{k}}\).Warning
This method assumes that
opis a projector, and therefore thatqubitis a separablequbitafter applyingop. It is implemented as a significantly faster alternative for partial trace to be used after single-qubit measurements. Separability is not checked.- Parameters:
op (npt.NDArray[np.complex128]) – Complex-valued matrix of shape \((2, 2)\) representing the projector to apply.
qubit (int) – Target qubit index.
Notes
This method combines
evolve_single()andremove_qubit().First, the relevant entries of
self.psiare partitioned into two disjoint subvectors. The partition depends on the value ofq. For a three-qubit statevector[a0, a1, a2, a3, a4, a5, a6, a7]:q = 0: sv0 = [a0, a1, a2, a3], sv1 = [a4, a5, a6, a7] q = 1: sv0 = [a0, a1, a4, a5], sv1 = [a2, a3, a6, a7] q = 2: sv0 = [a0, a2, a4, a6], sv1 = [a1, a3, a5, a7]
The statevector is then iterated over as in
evolve_single(), updatingself.psiin place while computing the norm of each partition separately.If both resulting subvectors have nonzero norm, they are guaranteed to be identical. The subvector
sv0is normalized and written to the first2**(nqubit - 1)entries ofself.psi.If exactly one subvector has nonzero norm, that subvector is selected. If both have zero norm, a
RuntimeErroris raised.
- tensor(other: Statevector) None[source]¶
Tensor product state with other qubits.
Results in
self\(\otimes\)other.- Parameters:
other (
graphix.sim.statevec.Statevector) – Statevector to be tensored withself.
Notes
This method is used internally by
add_nodes().
- permute(permutation: Sequence[int]) None[source]¶
Reorder the qubits.
- Parameters:
permutation (Sequence[int]) – The permutation to apply. For each position in the resulting order, the value gives the index of the qubit in the original ordering.
- fidelity(other: Statevector | NDArray[object_ | complex128]) float[source]¶
Calculate the fidelity against another statevector.
The fidelity is defined as \(|\langle\psi_1|\psi_2\rangle|^2\).
- Parameters:
other (
graphix.sim.statevec.Statevector) – Statevector to compare with.- Returns:
Fidelity between the two statevectors.
- Return type:
- isclose(other: Statevector | NDArray[object_ | complex128], *, rtol: float = 1e-09, atol: float = 0.0) bool[source]¶
Check if two quantum states are equal up to global phase.
Two states are considered close if their fidelity is close to 1.
- Parameters:
other (
graphix.sim.statevec.Statevector) – Statevector to compare with.rtol (float) – Relative tolerance for
math.isclose().atol (float) – Absolute tolerance for
math.isclose().
- Returns:
Trueif the states are equal up to global phase.- Return type:
- to_dict(encoding: _ENCODING = 'MSB', *, rtol: float = 0.0, atol: float = 1e-08) dict[str, np.object_ | np.complex128][source]¶
Convert the statevector to dictionary form.
This dictionary representation uses a ket-like notation where the dictionary
keysare qubit strings for the basis vectors andvaluesare the corresponding complex amplitudes. Amplitudes below a certain threshold are filtered out.- Parameters:
encoding (Literal["LSB", "MSB"], default="MSB") – Encoding for the basis kets. See notes for additional information.
rtol (float, default=0.0) – Relative tolerance used when deciding whether a coefficient should be treated as zero. Values whose magnitude is within this relative tolerance of zero are omitted from the resulting dictionary.
atol (float, default=1e-8) – Absolute tolerance used when deciding whether a coefficient should be treated as zero. Values whose magnitude is within this relative tolerance of zero are omitted from the resulting dictionary.
- Returns:
The statevector in dictionary form.
- Return type:
Notes
The encoding determines the bit ordering convention used when mapping basis states to dictionary keys. Consider a tensor product of three qubits:
\[\]lvertpsirangle = q_0 otimes q_1 otimes q_2.
If
encoding == "MSB"the first qubit is represented in the Most Significant Bit ->q0q1q2. This is the default representation in Graphix. Ifencoding == "LSB"the first qubit is represented in the Least Significant Bit ->q2q1q0. This is the default representation in other software packages such as Qiskit.Example
>>> from graphix.states import BasicStates >>> from graphix.sim.statevec import Statevector >>> sv = Statevector(data=[BasicStates.ZERO, BasicStates.ONE]) >>> sv.to_dict() {'01': np.complex128(1+0j)} >>> sv.to_dict(encoding="LSB") {'10': np.complex128(1+0j)}
- to_prob_dict(encoding: _ENCODING = 'MSB', *, rtol: float = 0.0, atol: float = 1e-08) dict[str, np.object_ | np.float64][source]¶
Convert the statevector to a probability distirbution in a dictionary form.
This dictionary representation uses a ket-like notation where the dictionary
keysare qubit strings for the basis vectors andvaluesare the corresponding probabilities. Basis vector whose amplitude is below a certain threshold are filtered out.- Parameters:
encoding (Literal["LSB", "MSB"], default="MSB") – Encoding for the basis kets. See
to_dict()for additional information.rtol (float, default=0.0) – Relative tolerance used when deciding whether a coefficient should be treated as zero. Values whose magnitude is within this relative tolerance of zero are omitted from the resulting dictionary.
atol (float, default=1e-8) – Absolute tolerance used when deciding whether a coefficient should be treated as zero. Values whose magnitude is within this relative tolerance of zero are omitted from the resulting dictionary.
- Returns:
The probability distribution associated to the statevector in dictionary form.
- Return type:
See also
meth:
to_dict
- draw(output: OutputFormat | None = None, *, encoding: _ENCODING = 'MSB', max_denominator: int = 1000, atol: float = 1e-09, rtol: float = 0.0, precision: int = 4) str[source]¶
Return a pretty-printed ket-notation representation of the statevector.
Amplitudes are rendered with
graphix.pretty_print.complex_to_str(), so common values appear as exact expressions (e.g.√2/2) rather than floating-point numbers.- Parameters:
output (OutputFormat, optional) – Desired formatting style. Defaults to
OutputFormat.Unicode.encoding ({"LSB", "MSB"}, optional) – Bit-ordering convention for the basis kets (default:
"MSB"). Seeto_dict().max_denominator (int, optional) – Maximum denominator used by the amplitude recognition (default:
1000).atol (float, optional) – Absolute tolerance for dropping near-zero amplitudes and for the recognition heuristics (default:
1e-9).rtol (float, optional) – Relative tolerance for dropping near-zero amplitudes (default:
0.0).precision (int, optional) – Number of significant digits to use for amplitudes that fall back to a decimal representation (default:
4).
- Returns:
The formatted statevector.
- Return type:
Examples
>>> from graphix.transpiler import Circuit >>> circuit = Circuit(2) >>> circuit.h(0) >>> circuit.cz(0, 1) >>> print(circuit.simulate().state.draw()) sqrt(2)/2(|00> + |01>)
- class StatevectorBackend(state: Statevector = <factory>, *, node_index: NodeIndex = <factory>, branch_selector: BranchSelector = <factory>, symbolic: bool = False)[source]¶
Bases:
DenseStateBackend[Statevector]Numba JIT-compiled MBQC statevector backend simulator based on Ref. [1].
See also
graphix.sim.base_backend.DenseStateBackendBase class describing available parameters and shared behavior.
Notes
By default, the backend is initialized with a 0-dimensional statevector (a scalar
1) andmax_qubits = 0.The internal state representation can be expanded using
StatevectorBackend.add_nodes, but this is inefficient since it requires copying the full quantum state array.To preallocate memory for a fixed system size, use
StatevectorBackend.with_capacity().References
[1] McGuffin, M. J., Robert J-M., and Ikeda K. “How to Write a Simulator for Quantum Circuits from Scratch: A Tutorial.”, 2025 (arXiv:2506.08142).
- state: Statevector¶
- classmethod with_capacity(max_qubits: int, state: Statevector | None = None, **kwargs: Unpack[DenseStateBackendKwargs]) Self[source]¶
Initialize the backend with preallocated statevector capacity.
- Parameters:
max_qubits (int) – Maximum number of qubits supported by the statevector. For pattern simulation this corresponds to
Pattern.max_space().state (Statevector | None = None) – Initial backend state. If
None, the backend is initialized with a 0-dimensional statevector (scalar1).**kwargs – Options for
graphix.sim.base_backend.DenseStateBackend. Seegraphix.sim.base_backend.DenseStateBackendKwargs.
- Returns:
Backend instance with capacity for up to
max_qubitsqubits.- Return type:
Self
- __init__(state: Statevector = <factory>, *, node_index: NodeIndex = <factory>, branch_selector: BranchSelector = <factory>, symbolic: bool = False) None¶
- class TensorNetworkBackend(pattern: Pattern, graph_prep: str = 'auto', input_state: Data | None = None, branch_selector: BranchSelector | None = None)[source]¶
Bases:
_AbstractTensorNetworkBackendTensor Network Simulator for MBQC.
Executes the measurement pattern using TN expression of graph states.
- Parameters:
pattern (graphix.Pattern)
graph_prep (str) –
- ‘parallel’ :
Faster method for preparing a graph state. The expression of a graph state can be obtained from the graph geometry. See https://journals.aps.org/pra/abstract/10.1103/PhysRevA.76.052315 for detail calculation. Note that ‘N’ and ‘E’ commands in the measurement pattern are ignored.
- ’sequential’ :
Sequentially execute N and E commands, strictly following the measurement pattern. In this strategy, All N and E commands executed sequentially.
- ’auto’(default) :
Automatically select a preparation strategy based on the max degree of a graph
input_state (preparation for input states (only BasicStates.PLUS is supported for tensor networks yet),)
branch_selector (
graphix.branch_selector.BranchSelector, optional) – Branch selector to be used for measurements.
- __init__(pattern: Pattern, graph_prep: str = 'auto', input_state: Data | None = None, branch_selector: BranchSelector | None = None) None[source]¶
Construct a tensor network backend.
- add_nodes(nodes: Sequence[int], data: Data = graphix.states.PlanarState(Plane.XY, 0)) None[source]¶
Add new nodes (qubits) to the network and initialize them in a specified state.
- Parameters:
nodes (Sequence[int]) – A list of node indices to add to the backend. These indices can be any integer values but must be fresh: each index must be distinct from all previously added nodes.
data (Data, optional) –
The state in which to initialize the newly added nodes.
If a single basic state is provided, all new nodes are initialized in that state.
If a list of basic states is provided, it must match the length of
nodes, and each node is initialized with its corresponding state.
Notes
Previously existing nodes remain unchanged.
- entangle_nodes(edge: tuple[int, int]) None[source]¶
Make entanglement between nodes specified by edge.
- measure(node: int, measurement: Measurement, rng: Generator | None = None, *, stacklevel: int = 1) Outcome[source]¶
Perform measurement of the node.
In the context of tensornetwork, performing measurement equals to applying measurement operator to the tensor. Here, directly contracted with the projected state.
- Parameters:
node (int) – index of the node to measure
measurement (Measurement) – measure plane and angle
- correct_byproduct(cmd: X | Z) None[source]¶
Byproduct correction correct for the X or Z byproduct operators, by applying the X or Z gate.
Note: the simulator is responsible for checking that the measurement outcomes match the domain condition before calling this method.