Evolutors

Evolutors are the high-level managers of quantum circuit simulation in MPSTAB. They orchestrate the flow through a quantum circuit, deciding when to use stabilizer methods versus tensor network methods for maximum efficiency.

Key Concept: Evolutors handle the temporal evolution of quantum states through circuit gates, managing the hybrid representation.

HSMPO: Hybrid Stabilizer MPO

The main HSMPO class combines stabilizer states with tensor network representations.

class mpstab.evolutors.hsmpo.HSMPO(ansatz: Ansatz | Circuit, max_bond_dimension: int = None, initial_state: Circuit = None)[source]

Bases: object

Construct an hybrid stabilizer MPO surrogate of a given quantum circuit.

The tensor-network part is now engine-pluggable via the TensorNetworkEngine API.

ansatz: Ansatz | Circuit
expectation(observable: str | SymbolicHamiltonian, return_fidelity: bool = False)[source]

Compute the expectation value of an observable with respect to the full ansatz circuit (no partitioning).

expectation_from_partition(observable: str | SymbolicHamiltonian, replacement_probability: float, replacement_method: str = 'closest', return_partitions: bool = False)[source]

Sample a lower-magic circuit from the ansatz, and compute its expectation value w.r.t. the observable.

initial_state: Circuit = None
max_bond_dimension: int = None
property nqubits
set_engines(stab_engine: StabilizersEngine | None = None, tn_engine: TensorNetworkEngine | None = None)[source]

Set both stabilizers and tensor-network engines.

  • stab_engine: instance of StabilizersEngine (if None, StimEngine is used)

  • tn_engine: instance of TensorNetworkEngine (if None, NativeTensorNetworkEngine is used)

truncation_fidelity(replacement_probability: float = 0.0, replacement_method: str = 'closest') float[source]

Truncation fidelity between truncated and original state :math:`|\langle\Psi_t|Psi_t

angle|^2/|\langle\Psi|Psi angle|^2 = |\langle\Psi_t|Psi_t angle|^2`, being Ψ normalized.

property truncation_fidelity_pure_tn: float

Key Methods:

  • __init__(ansatz, max_bond_dimension, initial_state): Initialize the simulator

  • expectation(observable, return_fidelity=False): Compute expectation value of a Pauli observable

  • truncation_fidelity(): Compute truncation fidelity of current state

  • set_engines(): Configure stabilizer and tensor network engines

Usage Example:

from mpstab import HSMPO
from qibo import Circuit, gates

# Create a circuit
circuit = Circuit(5)
circuit.add(gates.H(0))
circuit.add(gates.CNOT(0, 1))

# Simulate with HSMPO
simulator = HSMPO(ansatz=circuit, max_bond_dimension=32)
result, fidelity = simulator.expectation("Z" * 5, return_fidelity=True)
print(f"Expectation value: {result}")
print(f"Fidelity: {fidelity}")

Utilities

Helper functions for evolutor operations.

mpstab.evolutors.utils.sample_random_pauli_gate(qubit)[source]

Sample a random one-qubit gate applyed to a given qubit.

mpstab.evolutors.utils.validate_pauli_observable(observable: str, nqubits: int) None[source]

Validate that a Pauli observable string is well-formed.

Parameters:
  • observable – Pauli observable string (e.g., “ZZZZZ”, “XYZIX”)

  • nqubits – Number of qubits in the system

Raises:

ValueError – If observable contains invalid characters or has incorrect length

Stabilizer Evolution Tools

Low-level stabilizer state management and evolution.

Tensor Network Evolution Tools

Low-level tensor network (MPS/MPO) management and operations.

class mpstab.evolutors.tensor_network.tensor_network.TensorNetwork[source]

Bases: object

Flexible tensor-network implementation, allowing complex tensor manipulations at an abstract level.

Tensors are implemented as numpy arrays, while contractions paths are implemented as a directed graph, specifically a NetworkX MultiDiGraph.

add_copy_tensor(id: str, n: int)[source]
add_edge(node_in: str, node_out: str, edge_id: str, directions: tuple[int, int], **edge_metadata)[source]

Add an edge between two tensors, representing a potential contaction. Edges are directed, meaning the order of node_in and node_out does matter during the contraction, i.e. the same order must be used.

Parameters:
  • node_in (str) – first tensor to be connected

  • node_out (str) – second tensor to be connected

  • edge_id (str) – name of the contraction path

  • directions (tuple[int, int]) – pair of integers representing which of the tensor axes (indices) are to be connected by this edge.

Raises:

ValueError – When attempting to connect already connected tensors, or when connecting indices with incompatible dimensions.

add_measurement(id: str, alpha: float = 1.0, beta: float = 0.0)[source]
add_pauli_pair(id: str, p0: str, p1: str)[source]
add_tensor(id: str, tensor: ndarray)[source]
complex_conjugate()[source]

Return the complex conjugate of the network.

After this procedure, node names are updated according to the following convention: ‘nodename’ -> ‘nodename_dg’. Edges are left unchanged.

contract(node_in: str, node_out: str, edge_ids: str | list[str], new_node_id: str)[source]
draw(show_labels=False, title='')[source]
property n_tensors
remove_edge(node_in, node_out, edge_id)[source]
svd_decomposition(node: str, left_node_id: str, left_node_edges: str | list[str], right_node_id: str, right_node_edges: str | list[str], middle_node_id: str = 'Lambda', middle_edge_left: str = 'chi', middle_edge_right: str = 'chi', max_bond_dimension: int | None = None)[source]

Perform the SVD decomposition (T=ULV*) to a tensor (T), splitting it into two child tensors (U and V*), each retaining a certain subset of the original tensor’s connections, and connected to each other by a diagonal middle node (L). By default the middle tensor is named ‘Lambda’ and the edge connections to the child nodes are named ‘chi’.

Edges across the TensorNetwork are updated to preserve the validity of the connections (i.e. the old indices are updated to match those of the new tensors). All tensor indices must be assigned to an edge before this decomposition takes place.

When specified, can perform a cut in the bond dimension, by discarding the smallest singular values exeeding the specified number, hence limiting the scaling of the cost of computation. Otherwise the full rank child tensors are kept, discarding only the zeros.

Parameters:
  • node (str) – tensor to undergo SVD decomposition

  • left_node_id (strg) – name of the ‘left unitary’ child tensor, i.e. U

  • left_node_edges (Union[str, list[str]]) – edges pertaining to U

  • right_node_id (str) – name of the ‘right unitary’ child tensor, i.e. V*

  • right_node_edges (Union[str, list[str]]) – edges pertaining to V*

  • middle_node_id (str) – diagonal tensor, i.e. L

  • middle_edge_left (str) – edge representing the matrix multiplication ‘UL’

  • middle_edge_right (str) – edge representing the matrix multiplication ‘LV*’

  • max_bond_dimension (Optional[int]) – maximum number of singular values to be kept after performing the SVD

Raises:

ValueError – if either too many or too few edges are assigned to the child tensors.

mpstab.evolutors.tensor_network.tensor_network.merge_tns(tn1: TensorNetwork, tn2: TensorNetwork)[source]

For more practical examples, see: