-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Primitives support the dynamic circuits with control flow #9231
Changes from 7 commits
ce4df59
83b9158
e82577a
3b9e5f9
aaacaa2
eaa5f4b
b7e3ebc
6623b99
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
features: | ||
- | | ||
Primitives may now support dynamic circuits with control flow, if the particular | ||
provider's implementation can support them. Previously, the | ||
:class:`~BaseSampler` and :class:`~BaseEstimator` base classes could not correctly | ||
normalize such circuits. This change does not automatically make all | ||
primitives support dynamic circuits, but it does make it possible for them | ||
to be supported by downstream providers. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2022. | ||
# (C) Copyright IBM 2022, 2023. | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
|
@@ -12,12 +12,16 @@ | |
|
||
"""Tests for BasePrimitive.""" | ||
|
||
from ddt import ddt, data, unpack | ||
import json | ||
|
||
from numpy import array, int32, int64, float32, float64 | ||
from ddt import data, ddt, unpack | ||
from numpy import array, float32, float64, int32, int64 | ||
|
||
from qiskit import QuantumCircuit, pulse, transpile | ||
from qiskit.circuit.random import random_circuit | ||
from qiskit.primitives.base.base_primitive import BasePrimitive | ||
from qiskit.primitives.utils import _circuit_key | ||
from qiskit.providers.fake_provider import FakeAlmaden | ||
from qiskit.test import QiskitTestCase | ||
|
||
|
||
|
@@ -110,3 +114,48 @@ def test_value_error(self): | |
"""Test value error if no parameter_values or default are provided.""" | ||
with self.assertRaises(ValueError): | ||
BasePrimitive._validate_parameter_values(None) | ||
|
||
|
||
class TestCircuitKey(QiskitTestCase): | ||
"""Tests for _circuit_key function""" | ||
|
||
def test_different_circuits(self): | ||
"""Test collision of quantum circuits.""" | ||
|
||
with self.subTest("Ry circuit"): | ||
|
||
def test_func(n): | ||
qc = QuantumCircuit(1, 1, name="foo") | ||
qc.ry(n, 0) | ||
return qc | ||
|
||
keys = [_circuit_key(test_func(i)) for i in range(5)] | ||
self.assertEqual(len(keys), len(set(keys))) | ||
|
||
with self.subTest("pulse circuit"): | ||
|
||
def test_with_scheduling(n): | ||
custom_gate = pulse.Schedule(name="custom_x_gate") | ||
custom_gate.insert( | ||
0, pulse.Play(pulse.Constant(160 * n, 0.1), pulse.DriveChannel(0)), inplace=True | ||
) | ||
qc = QuantumCircuit(1) | ||
qc.x(0) | ||
qc.add_calibration("x", qubits=(0,), schedule=custom_gate) | ||
return transpile(qc, FakeAlmaden(), scheduling_method="alap") | ||
|
||
keys = [_circuit_key(test_with_scheduling(i)) for i in range(1, 5)] | ||
self.assertEqual(len(keys), len(set(keys))) | ||
|
||
def test_circuit_key_controlflow(self): | ||
"""Test for a circuit with control flow.""" | ||
qc = QuantumCircuit(2, 1) | ||
|
||
with qc.for_loop(range(5)): | ||
qc.h(0) | ||
qc.cx(0, 1) | ||
qc.measure(0, 0) | ||
qc.break_loop().c_if(0, True) | ||
|
||
self.assertIsInstance(hash(_circuit_key(qc)), int) | ||
self.assertIsInstance(json.dumps(_circuit_key(qc)), str) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This Using a dummy primitive whose |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan of these tests of internal features, because generally they make it harder for the internal implementation to evolve without changing the tests. Ideally we should only be testing the outward public behaviour, and not the particulars of how that's achieved. If the tests are too tightly coupled, then any change to the internal implementation has to change the tests, and that makes it much easier for bugs and regressions to sneak in; we have to verify that the new tests are equivalent, and cover the same ground.
That said, this is a single function, and if you think it's much better to test this way, I won't block this PR on it.
I'd potentially attempt to rewrite the tests by using a custom subclass of the primitives for testing that has its
_run
(or whatever it's called) method defined to make assertions about the normalised circuits it gets back from the base class's handling. That's testing public parts of the subclassing API, rather than this internal detail of how that's done.edit: I also see now that these tests are just moved from one file to another, rather than actually written new. I'm still not a fan, but it does move this change out-of-scope of this PR.