Models & Methods¶
The models subpackage contains quantum circuit templates (ansätze), error mitigation techniques, and analysis tools.
Ansätze: Quantum Circuit Templates¶
Ansätze are pre-built quantum circuit patterns used as templates for quantum algorithms.
- class mpstab.models.ansatze.Ansatz(nqubits: int, density_matrix: bool = False)[source]¶
Bases:
ABCAbstract ansatz to generate quantum states.
- property circuit¶
- density_matrix: bool = False¶
- execute(nshots: int = None, initial_state: Circuit = None, with_noise: bool = False)[source]¶
Execute the circuit and return the outcome.
- property nparams¶
- nqubits: int¶
- partitionate_circuit(replacement_probability: float, replacement_method: str)[source]¶
Partitionate the circuit replacing non-Clifford (magic) gates with a given probability.
For each gate in the original circuit:
If the gate is non-Clifford, with probability replacement_probability it is replaced by a Clifford gate via replace_non_clifford_gate.
The processed gate (whether replaced or not) is added to the overall circuit.
Simultaneously, consecutive gates of the same type (Clifford or non-Clifford) are collected into blocks.
- Returns:
the complete processed circuit. clifford_blocks (List[Circuit]): list of circuits, each a block of consecutive Clifford gates. non_clifford_blocks (List[Circuit]): list of circuits, each a block of consecutive non-Clifford gates.
- Return type:
partitioned_circuit (Circuit)
- class mpstab.models.ansatze.CircuitAnsatz(density_matrix: bool = False, *, qibo_circuit: Circuit)[source]¶
Bases:
AnsatzA simple wrapper that converts a Qibo Circuit into an Ansatz object.
- Parameters:
input_circuit (Circuit) – The Qibo circuit to wrap.
- property circuit¶
- nqubits: int¶
- qibo_circuit: Circuit¶
- class mpstab.models.ansatze.FloquetAnsatz(nqubits: int, density_matrix: bool = False, nlayers: int = 2, b: float = 1.2566370614359172, theta: float = 1.5707963267948966, target_qubit: int = 1, decompose_rzz: bool = True)[source]¶
Bases:
AnsatzFloquet echo: U = (FL)^t · Rz(theta) on qubit q · (FL^t)†.
- Parameters:
nlayers (int) – number of Floquet layers.
b (float) – parameter controlling the magic in the circuit;
theta (float) – controls the signal;
target_qubit (int) – this is the qubit, in the circuit, on which we perform the final local measurement (and the one on which we apply H and RZ).
decompose_rzz (bool) – if
True, RZZ is decomposed into CNOTs and RZ.
- b: float = 1.2566370614359172¶
- decompose_rzz: bool = True¶
- nlayers: int = 2¶
- partitionate_circuit(replacement_probability: float, replacement_method: str)[source]¶
Partitionate the full Floquet circuit U = H · half_sandwich · RZ · (half_sandwich)†, but only sweep the half_sandwich for magic gates. Returns ((magic_gates, clifford_only_circuit), full_circuit).
- partitionate_sub_circuit(circuit: Circuit, replacement_probability: float, replacement_method: str)[source]¶
Partitionate a sub-circuit replacing non-Clifford (magic) gates with a given probability. Returns ((magic_gates, clifford_only_circuit), full_circuit) where magic_gates is List of (local_bp, gate) with local_bp starting at 0.
- target_qubit: int = 1¶
- theta: float = 1.5707963267948966¶
- class mpstab.models.ansatze.HammingWeightPreserving(nqubits: int, density_matrix: bool = False, nlayers: int = 1)[source]¶
Bases:
AnsatzHamming-weight-preserving ansatz built from decomposed RBS gates.
Each RBS gate rotates within the {|01⟩, |10⟩} subspace of a qubit pair, leaving |00⟩ and |11⟩ unchanged:
RBS(θ)|01⟩ = cos(θ)|01⟩ + sin(θ)|10⟩ RBS(θ)|10⟩ = -sin(θ)|01⟩ + cos(θ)|10⟩
RBS is decomposed into gates mpstab supports natively:
CNOT(ctrl=q1, tgt=q0) RY(q1, θ) ← magic gate CNOT(ctrl=q0, tgt=q1) RY(q1, -θ) ← magic gate CNOT(ctrl=q0, tgt=q1) CNOT(ctrl=q1, tgt=q0)
The circuit always starts with n//2 X gates to prepare the half-filling state |1…10…0⟩, giving a fixed Hamming weight of n//2.
Within each layer the connectivity pattern mirrors hw_preserving from Qibo examples: four connect_qubits passes with jump sizes 1 and 2 and different starting offsets to explore both nearest- and next-nearest- neighbour correlations with circular boundary conditions.
- Parameters:
nqubits – Number of qubits (must be even).
nlayers – Number of RBS layers.
- nlayers: int = 1¶
- class mpstab.models.ansatze.HardwareEfficient(nqubits: int, density_matrix: bool = False, nlayers: int = 1, entangling: bool = True)[source]¶
Bases:
AnsatzHardware Efficient ansatz.
- entanglement_layer()[source]¶
Construct an entanglement layer compatible with the target quantum circuit.
- entangling: bool = True¶
- nlayers: int = 1¶
- property parameters_per_layers¶
- class mpstab.models.ansatze.HardwareEfficientBrickwork(nqubits: int, density_matrix: bool = False, nlayers: int = 1)[source]¶
Bases:
AnsatzHardware Efficient ansatz with a full brickwork entanglement pattern.
Each layer applies two sublayers of single-qubit RY+RZ rotations interleaved with CZ entanglement:
sublayer 1: RY+RZ on all qubits → CZ on even bonds (0-1, 2-3, …) sublayer 2: RY+RZ on all qubits → CZ on odd bonds (1-2, 3-4, …) + CZ(0, n-1)
A final layer of RY rotations closes the circuit. The ring-closing CZ(0, n-1) in the odd sublayer creates long-range entanglement.
- Parameters:
nqubits – Number of qubits.
nlayers – Number of full brickwork layers.
- nlayers: int = 1¶
- class mpstab.models.ansatze.TranspiledAnsatz(density_matrix: bool = False, *, original_circuit: Circuit, native_gates: List | None = <factory>, connectivity: Graph | None = None)[source]¶
Bases:
AnsatzAny ansatz which is also transpiled into native gates of a given quantum device presenting a given connectivity.
- Parameters:
original_circuit – The circuit to be transpiled.
native_gates – Optional[List]: list of native gates of the used device. Default is [gates.GPI2, gates.RZ, gates.Z, gates.CZ].
connectivity – Optional[nx.Graph]: graph representing the topology of the used device. Default is None and in this case the transpilation does not take into account any connectivity constraint.
- property circuit¶
- connectivity: Graph | None = None¶
- native_gates: List | None¶
- nqubits: int¶
- original_circuit: Circuit¶
Available Ansätze:
Ansatz: Abstract base class for all ansätzeCircuitAnsatz: Wrapper for Qibo circuitsHardwareEfficient: Industry-standard pattern for NISQ devices
Key Methods:
execute(nshots, initial_state, with_noise): Execute the circuitupdate_noise_model(noise_model): Add noise to simulationpartitionate_circuit(replacement_probability, replacement_method): Partition circuitnparams: Number of circuit parameterscircuit: Access the underlying QiboCircuit
Example Usage:
from mpstab.models.ansatze import HardwareEfficient
from mpstab import HSMPO
# Create ansatz
ansatz = HardwareEfficient(nqubits=5, nlayers=3)
# Use with HSMPO
simulator = HSMPO(ansatz=ansatz, max_bond_dimension=32)
result = simulator.expectation("ZZZZZ")
See Using Ansätze for detailed examples.
Error Mitigation¶
Techniques for reducing approximation errors and improving simulation accuracy.
- mpstab.models.mitigation_methods.TNCDR(observable: str, ansatz: Ansatz, noise_model: NoiseModel, replacement_probability: float, initial_state: Circuit = None, replacement_method: str = 'closest', ncircuits: int = 50, nshots: int | None = None, random_seed: int = 42, fit_map=<function <lambda>>, expval_threshold: float = 1e-07, max_bond_dimension: int | None = None)[source]¶
Entanglement Metrics & Analysis¶
Tools for analyzing entanglement and state properties.
- mpstab.models.entropies.generate_pauli_strings(n: int) list[str][source]¶
Generate all possible n-qubit Pauli strings.
- mpstab.models.entropies.stabilizer_renyi_entropy(state: ndarray, alpha: int) float[source]¶
Compute the exact Stabilizer Rényi Entropy of order alpha for a dense state vector. Implementation follows Eq. (1) of https://arxiv.org/pdf/2207.13076.
Cost is O(4^n) — only suitable for n ≲ 12.
- mpstab.models.entropies.stabilizer_renyi_entropy_mps(hsmpo: HSMPO, alpha: int = 2, n_samples: int = 1000, seed: int | None = None) float[source]¶
Stochastic estimate of the Stabilizer Rényi Entropy of order alpha, using importance-free uniform Pauli sampling over the MPS representation.
Follows the estimator of Lami & Collura (PRL 2023):
S_α ≈ (1/(1-α)) * log( (4^n / K) * Σ_{k=1}^{K} |⟨P_k⟩|^{2α} / 2^n )
where P_k are sampled uniformly at random from the 4^n Pauli strings. This is an unbiased Monte Carlo estimate of the exact sum.
Exploits the precomputed MPS cache in HSMPO (original_circuit_mps, clifford_circuit), so no MPS re-initialization is performed.
- Parameters:
hsmpo (HSMPO) – The hybrid stabilizer MPO object with a precomputed MPS cache.
alpha (int) – Rényi order, must be ≥ 2.
n_samples (int) – Number of random Pauli strings to sample. Higher gives lower variance. As a rough guide, n_samples ~ 1000–5000 is sufficient for n ≲ 25.
seed (int or None) – Random seed for reproducibility.
- Returns:
Stochastic estimate of SRE_α.
- Return type:
float
Available Functions:
stabilizer_renyi_entropy(state, alpha): Stabilizer Renyi entropy for a given state and order
Additional Utilities¶
- mpstab.models.utils.build_noise_model(nqubits: int, local_pauli_noise_sigma: float, readout_bit_flip_prob: float = None)[source]¶
Costruct noise model as a local Pauli noise channel + readout noise.
- mpstab.models.utils.get_closest_angle(old_angle, candidates)[source]¶
Return the closest angle to old_angle among some candidates.
- mpstab.models.utils.hardware_compatible_circuit(circuit: ~qibo.models.circuit.Circuit, native_gates: ~typing.List | None = [<class 'qibo.gates.gates.GPI2'>, <class 'qibo.gates.gates.RZ'>, <class 'qibo.gates.gates.Z'>, <class 'qibo.gates.gates.CZ'>], connectivity: ~networkx.classes.graph.Graph | None = None)[source]¶
- mpstab.models.utils.obs_string_to_qibo_hamiltonian(observable: str, backend: Backend = None) SymbolicHamiltonian[source]¶
Convert a string representation of a Pauli observable to a Qibo symbolic Hamiltonian.
- Parameters:
observable (str) – A string representing the Pauli observable, e.g., “XZIY”.
- Returns:
The corresponding Qibo symbolic Hamiltonian.
- Return type:
hamiltonians.SymbolicHamiltonian