How to perform a cutting workflow with multiple observables¶
Create a circuit to cut¶
[1]:
from qiskit.circuit.library import EfficientSU2
qc = EfficientSU2(4, entanglement="linear", reps=2).decompose()
qc.assign_parameters([0.4] * len(qc.parameters), inplace=True)
qc.draw("mpl", scale=0.8)
[1]:

Specify the observables of interest¶
[2]:
from qiskit.quantum_info import Pauli, SparsePauliOp
observables = [
Pauli("-XZII"),
SparsePauliOp(["ZZII", "IZZI", "-IIZZ", "XIXI", "ZIZZ", "IXIX"]),
]
Gather unique observable terms¶
[3]:
from qiskit_addon_cutting.utils.observable_terms import gather_unique_observable_terms
unique_observable_terms = gather_unique_observable_terms(observables)
Perform cutting workflow¶
[4]:
from qiskit_addon_cutting import partition_problem
partitioned_problem = partition_problem(
circuit=qc, partition_labels="AABB", observables=unique_observable_terms
)
subcircuits = partitioned_problem.subcircuits
subobservables = partitioned_problem.subobservables
[5]:
import numpy as np
from qiskit_addon_cutting import generate_cutting_experiments
subexperiments, coefficients = generate_cutting_experiments(
circuits=subcircuits, observables=subobservables, num_samples=np.inf
)
[6]:
from qiskit_ibm_runtime.fake_provider import FakeManilaV2
backend = FakeManilaV2()
[7]:
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
# Transpile the subexperiments to ISA circuits
pass_manager = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_subexperiments = {
label: pass_manager.run(partition_subexpts)
for label, partition_subexpts in subexperiments.items()
}
[8]:
from qiskit_ibm_runtime import SamplerV2, Batch
# Submit each partition's subexperiments as a single batch
with Batch(backend=backend) as batch:
sampler = SamplerV2(mode=batch)
jobs = {
label: sampler.run(subsystem_subexpts, shots=2**12)
for label, subsystem_subexpts in isa_subexperiments.items()
}
[9]:
# Retrieve results
results = {label: job.result() for label, job in jobs.items()}
Reconstruct the expectation value of each unique term¶
[10]:
from qiskit_addon_cutting import reconstruct_expectation_values
# Get expectation values for each observable term
reconstructed_term_expvals = reconstruct_expectation_values(
results,
coefficients,
subobservables, # or unique_observable_terms if the circuit did not separate
)
Reconstruct the expectation value of the original operators¶
[11]:
from qiskit_addon_cutting.utils.observable_terms import (
reconstruct_observable_expvals_from_terms,
)
reconstructed_expvals = reconstruct_observable_expvals_from_terms(
observables, dict(zip(unique_observable_terms, reconstructed_term_expvals))
)
Compare the reconstructed expectation values with the exact expectation value from the original circuit and observables¶
[12]:
from qiskit_aer.primitives import EstimatorV2
estimator = EstimatorV2()
exact_expvals = estimator.run([(qc, observables)]).result()[0].data.evs
print(
f"Reconstructed expectation values: {np.real(np.round(reconstructed_expvals, 8))}"
)
print(f"Exact expectation values: {np.round(exact_expvals, 8)}")
print(
f"Error in estimation: {np.real(np.round(reconstructed_expvals-exact_expvals, 8))}"
)
print(
f"Relative error in estimation: {np.real(np.round((reconstructed_expvals-exact_expvals) / exact_expvals, 8))}"
)
Reconstructed expectation values: [-0.20063001 0.48694563]
Exact expectation values: [-0.17994235 0.56254612]
Error in estimation: [-0.02068766 -0.07560049]
Relative error in estimation: [ 0.11496824 -0.13438986]