From f5963075dd9522495dbf10cdd6b83eeef3492398 Mon Sep 17 00:00:00 2001 From: Jim Garrison Date: Mon, 9 Oct 2023 21:27:38 -0400 Subject: [PATCH] Provide a workaround to #422, Sampler failing when no measurements (#426) * Provide a workaround to #422, Sampler failing when no measurements * Add test for workaround to Issue #422. * Redo previous commit after running tox. * Fix tox error from previous build. * Fix tox error from last build. * Un-modify the metadata in a notebook With this, the current PR will touch one fewer file * Update test/cutting/test_cutting_roundtrip.py Co-authored-by: Jim Garrison * Update test/cutting/test_cutting_roundtrip.py Co-authored-by: Jim Garrison * black --------- Co-authored-by: Ibrahim Co-authored-by: Ibrahim Shehzad <75153717+Ibrahim-Shehzad@users.noreply.github.com> --- .../cutting/cutting_experiments.py | 11 ++++++-- test/cutting/test_cutting_roundtrip.py | 28 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/circuit_knitting/cutting/cutting_experiments.py b/circuit_knitting/cutting/cutting_experiments.py index e8ebdc41c..a2d5f46a4 100644 --- a/circuit_knitting/cutting/cutting_experiments.py +++ b/circuit_knitting/cutting/cutting_experiments.py @@ -276,14 +276,21 @@ def _append_measurement_circuit( if not inplace: qc = qc.copy() + # If the circuit has no measurements, the Sampler will fail. So, we + # measure one qubit as a temporary workaround to + # https://github.com/Qiskit-Extensions/circuit-knitting-toolbox/issues/422 + pauli_indices = cog.pauli_indices + if not pauli_indices: + pauli_indices = [0] + # Append the appropriate measurements to qc - obs_creg = ClassicalRegister(len(cog.pauli_indices), name="observable_measurements") + obs_creg = ClassicalRegister(len(pauli_indices), name="observable_measurements") qc.add_register(obs_creg) # Implement the necessary basis rotations and measurements, as # in BackendEstimator._measurement_circuit(). genobs_x = cog.general_observable.x genobs_z = cog.general_observable.z - for clbit, subqubit in enumerate(cog.pauli_indices): + for clbit, subqubit in enumerate(pauli_indices): # subqubit is the index of the qubit in the subsystem. # actual_qubit is its index in the system of interest (if different). actual_qubit = qubit_locations[subqubit] diff --git a/test/cutting/test_cutting_roundtrip.py b/test/cutting/test_cutting_roundtrip.py index 867ff6fdc..30acacb1f 100644 --- a/test/cutting/test_cutting_roundtrip.py +++ b/test/cutting/test_cutting_roundtrip.py @@ -42,6 +42,7 @@ from qiskit.extensions import UnitaryGate from qiskit.quantum_info import PauliList, random_unitary from qiskit.primitives import Estimator +from qiskit_aer.primitives import Sampler from circuit_knitting.utils.simulation import ExactSampler from circuit_knitting.cutting import ( @@ -179,3 +180,30 @@ def test_cutting_exact_reconstruction(example_circuit): logger.info("Max error: %f", np.max(np.abs(exact_expvals - simulated_expvals))) assert np.allclose(exact_expvals, simulated_expvals, atol=1e-8) + + +def test_sampler_with_identity_subobservable(example_circuit): + """This test ensures that the sampler does not throw an error if you pass it a subcircuit with no observable measurements. + + Tests temporary workaround to Issue #422. + + This test passes if no exceptions are raised. + + """ + + qc = example_circuit + observable_to_test = PauliList( + ["IIZ"] + ) # Without the workaround to Issue #422, this observable causes a Sampler error. + subcircuits, bases, subobservables = partition_problem( + qc, "AAB", observables=observable_to_test + ) + subexperiments, coefficients = generate_cutting_experiments( + subcircuits, subobservables, num_samples=np.inf + ) + samplers = {label: Sampler() for label in subexperiments.keys()} + results = { + label: sampler.run(subexperiments[label]).result() + for label, sampler in samplers.items() + } + _ = results