Qdislib — 05 · Observables¶
So far we measured <ZZZZZ>. Qdislib accepts any per-qubit Pauli string over I, X, Y, Z, and weighted sums of them (a Hamiltonian).
[ ]:
from qibo import models, gates
def example_circuit():
"""A small 5-qubit circuit: cuttable (CZ chain), non-trivial <ZZZZZ> ~= 0.44."""
circuit = models.Circuit(5)
circuit.add(gates.RY(0, 0.8))
circuit.add(gates.CZ(0, 1))
circuit.add(gates.RY(1, 0.5))
circuit.add(gates.CZ(1, 2))
circuit.add(gates.RY(2, 0.6))
circuit.add(gates.CZ(2, 3))
circuit.add(gates.RY(3, 0.4))
circuit.add(gates.CZ(3, 4))
circuit.add(gates.RX(4, 0.3))
return circuit
circuit = example_circuit()
print(circuit.draw())
[ ]:
import Qdislib as qd
circuit = example_circuit()
cut = qd.find_cut(circuit, gate_cut=True, wire_cut=False)
Pauli strings¶
Z measures in the computational basis; I ignores a qubit (including one on a cut — the reconstruction handles it); X/Y apply the basis rotation for you. Compare each to the exact value.
[ ]:
for obs in ["ZZZZZ", "ZIZIZ", "XZIZI", "XZZZY"]:
value = qd.gate_cutting(example_circuit(), cut, observables=obs, shots=20000)
exact = qd.analytical_solution(example_circuit(), obs)
print(f"{obs}: cut={value:+.3f} exact={exact:+.3f}")
Sampling variance. Each cut multiplies the estimator’s variance (the quasiprobability sampling overhead), and
X/Yobservables add more on top, so measurements involving them need more shots to converge — the estimate stays unbiased, it just gets noisier. Bumpshots(or make fewer cuts) if a value looks off.
Identity on a cut qubit. An
Ion a qubit that a gate cut passes through is the subtle case: there is no basis measurement on that qubit to fix the sign of each reconstruction term, so Qdislib recovers the sign from the cut’s own mid-circuit measurement. You don’t do anything special — it still returns the exact value — but it’s why measuring identities across a cut works at all.
Weighted sums (Hamiltonians)¶
Pass a list of (coefficient, pauli) pairs or a {pauli: coefficient} mapping; Qdislib evaluates <Σ cᵢ Pᵢ> = Σ cᵢ <Pᵢ> term by term.
[ ]:
hamiltonian = [(0.5, "ZZIII"), (-1.0, "IIZZI"), (0.25, "ZIZII")]
value = qd.gate_cutting(example_circuit(), cut, observables=hamiltonian, shots=20000)
exact = qd.analytical_solution(example_circuit(), hamiltonian)
print(f"<H>: cut={value:+.3f} exact={exact:+.3f}")
The same observables= argument works for wire_cutting, estimate and the three-step *_subcircuits workflow.
Next: 06 · Sampling the output distribution.