Skip to content

Commit

Permalink
Deprecate execute_experiments()
Browse files Browse the repository at this point in the history
Fixes #405.

The last sentence in this PR's release note will become true as soon
as #404 is merged.
  • Loading branch information
garrison committed Sep 11, 2023
1 parent 48f1e04 commit 38e7c77
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 26 deletions.
4 changes: 2 additions & 2 deletions circuit_knitting/cutting/cutting_decomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def cut_gates(
"""
if len(circuit.cregs) != 0 or circuit.num_clbits != 0:
raise ValueError(
"Circuits input to execute_experiments should contain no classical registers or bits."
"Circuits input to cut_gates should contain no classical registers or bits."
)
# Replace specified gates with TwoQubitQPDGates
if not inplace:
Expand Down Expand Up @@ -218,7 +218,7 @@ def partition_problem(

if len(circuit.cregs) != 0 or circuit.num_clbits != 0:
raise ValueError(
"Circuits input to execute_experiments should contain no classical registers or bits."
"Circuits input to partition_problem should contain no classical registers or bits."
)

# Determine partition labels from connectivity (ignoring TwoQubitQPDGates)
Expand Down
11 changes: 11 additions & 0 deletions circuit_knitting/cutting/cutting_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from qiskit.circuit import QuantumCircuit
from qiskit.quantum_info import PauliList
from qiskit.primitives import BaseSampler, Sampler as TerraSampler, SamplerResult
from qiskit.utils import deprecate_func
from qiskit_aer.primitives import Sampler as AerSampler

from .qpd import WeightType
Expand All @@ -32,6 +33,16 @@ class CuttingExperimentResults(NamedTuple):
coeffs: Sequence[tuple[float, WeightType]]


@deprecate_func(
since="0.4.0",
package_name="circuit-knitting-toolbox",
removal_timeline="no earlier than v0.5.0",
additional_msg=(
"Going forward, users should first call ``generate_cutting_experiments()`` "
"to generate the subexperiment circuits and then submit these "
"circuits directly to the desired Sampler(s)."
),
)
def execute_experiments(
circuits: QuantumCircuit | dict[Hashable, QuantumCircuit],
subobservables: PauliList | dict[Hashable, PauliList],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
deprecations:
- |
The :func:`.execute_experiments` function has been deprecated.
Going forward, users should first call
:func:`.generate_cutting_experiments` to generate the
subexperiment circuits and then submit these circuits directly to
the desired Sampler(s). The :ref:`tutorials <circuit cutting
tutorials>` have been updated with this new workflow.
4 changes: 2 additions & 2 deletions test/cutting/test_cutting_decomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def test_partition_problem(self):
partition_problem(circuit, partition_labels, observables=observable)
assert (
e_info.value.args[0]
== "Circuits input to execute_experiments should contain no classical registers or bits."
== "Circuits input to partition_problem should contain no classical registers or bits."
)
with self.subTest("Unsupported phase"):
# Split 4q HWEA in middle of qubits
Expand Down Expand Up @@ -273,7 +273,7 @@ def test_cut_gates(self):
cut_gates(qc, [0])
assert (
e_info.value.args[0]
== "Circuits input to execute_experiments should contain no classical registers or bits."
== "Circuits input to cut_gates should contain no classical registers or bits."
)

def test_unused_qubits(self):
Expand Down
14 changes: 1 addition & 13 deletions test/cutting/test_cutting_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def setUp(self):
self.observable = PauliList(["ZZ"])
self.sampler = ExactSampler()

@pytest.mark.filterwarnings("ignore::DeprecationWarning")
def test_execute_experiments(self):
with self.subTest("Basic test"):
quasi_dists, coefficients = execute_experiments(
Expand Down Expand Up @@ -315,16 +316,3 @@ def test_execute_experiments(self):
e_info.value.args[0]
== "Circuits input to execute_experiments should contain no classical registers or bits."
)

def test_workflow_with_unused_qubits(self):
"""Issue #218"""
qc = QuantumCircuit(2)
subcircuits, _, subobservables = partition_problem(
circuit=qc, partition_labels="AB", observables=PauliList(["XX"])
)
execute_experiments(
subcircuits,
subobservables,
num_samples=1,
samplers=AerSampler(),
)
25 changes: 16 additions & 9 deletions test/cutting/test_cutting_roundtrip.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
from circuit_knitting.utils.simulation import ExactSampler
from circuit_knitting.cutting import (
partition_problem,
execute_experiments,
generate_cutting_experiments,
reconstruct_expectation_values,
)
from circuit_knitting.cutting.instructions import Move
Expand Down Expand Up @@ -154,18 +154,25 @@ def test_cutting_exact_reconstruction(example_circuit):
subcircuits, bases, subobservables = partition_problem(
qc, "AAB", observables=observables_nophase
)
subexperiments, coefficients = generate_cutting_experiments(
subcircuits, subobservables, num_samples=np.inf
)
if np.random.randint(2):
samplers = ExactSampler()
# Re-use a single sample
sampler = ExactSampler()
samplers = {label: sampler for label in subcircuits.keys()}
else:
# One sampler per partition
samplers = {label: ExactSampler() for label in subcircuits.keys()}
quasi_dists, coefficients = execute_experiments(
circuits=subcircuits,
subobservables=subobservables,
num_samples=np.inf,
samplers=samplers,
)
results = {
label: sampler.run(subexperiments[label]).result()
for label, sampler in samplers.items()
}
for label in results:
for i, subexperiment in enumerate(subexperiments[label]):
results[label].metadata[i]["num_qpd_bits"] = len(subexperiment.cregs[0])
simulated_expvals = reconstruct_expectation_values(
quasi_dists, coefficients, subobservables
results, coefficients, subobservables
)
simulated_expvals *= phases

Expand Down
14 changes: 14 additions & 0 deletions test/cutting/test_cutting_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import pytest
from copy import deepcopy

from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import EfficientSU2, CXGate
from qiskit.quantum_info import PauliList
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
Expand Down Expand Up @@ -99,3 +100,16 @@ def test_exotic_labels(label1, label2):
subobservables,
)
assert len(simulated_expvals) == len(observables)


def test_workflow_with_unused_qubits():
"""Issue #218"""
qc = QuantumCircuit(2)
subcircuits, _, subobservables = partition_problem(
circuit=qc, partition_labels="AB", observables=PauliList(["XX"])
)
generate_cutting_experiments(
subcircuits,
subobservables,
num_samples=10,
)

0 comments on commit 38e7c77

Please sign in to comment.