-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
InstructionDurations from BackendV2 #11528
base: main
Are you sure you want to change the base?
Changes from 9 commits
f40808e
1c736b0
cf7fbd9
c60f8ae
7f3f763
2868b41
7828930
8dd3fb4
795bf61
a02ad0c
5ccc547
37229f8
e91f71c
55aca1c
bdbe82d
2fe1a4f
7e357f1
41ac00b
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,21 @@ | ||||
--- | ||||
features: | ||||
- | | ||||
Support for :class:`.BackendV2` in :meth:`.InstructionDurations.from_backend` is added. | ||||
|
||||
Users can have an object of :class:`.InstructionDurations` using :class:`.BackendV2` | ||||
from :meth:`.from_backend` with followig code. | ||||
|
||||
.. code-block:: python | ||||
|
||||
from qiskit.providers.fake_provider import FakePerth | ||||
from qiskit.transpiler import InstructionDurations | ||||
backendV2 = FakePerth() | ||||
|
||||
inst_dur = InstructionDurations.from_backend(backendV2) | ||||
|
||||
upgrade: | ||||
- | | ||||
Given :code:`dt` and :code:`dtm` for a :class:`.BackendV1` or :class:`.BackendV2` are unequal, | ||||
:meth:`~.InstructionDurations.from_backend` does not raise any error. | ||||
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. Is there any change in code behavior with this PR? 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. @nkanazawa1989 ,
I should get 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. The document should be wrong. See p.33 of https://arxiv.org/abs/1809.03452. dtm defines the sampling rate of digitizer, which can be independent of dt that defines the sampling rate of AWG. 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. I think this upgrade note is not necessary because |
||||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -13,17 +13,17 @@ | |||
# pylint: disable=missing-function-docstring | ||||
|
||||
"""Test InstructionDurations class.""" | ||||
|
||||
from copy import deepcopy | ||||
from qiskit.circuit import Delay, Parameter | ||||
from qiskit.providers.fake_provider import FakeParis, FakeTokyo | ||||
from qiskit.providers.fake_provider import FakeParis, FakePerth | ||||
from qiskit.transpiler.exceptions import TranspilerError | ||||
from qiskit.transpiler.instruction_durations import InstructionDurations | ||||
|
||||
from qiskit.test.base import QiskitTestCase | ||||
|
||||
|
||||
class TestInstructionDurationsClass(QiskitTestCase): | ||||
"""Test Test InstructionDurations class.""" | ||||
class TestInstructionDurations(QiskitTestCase): | ||||
"""Test InstructionDurations class.""" | ||||
|
||||
def test_empty(self): | ||||
durations = InstructionDurations() | ||||
|
@@ -36,41 +36,13 @@ def test_fail_if_invalid_dict_is_supplied_when_construction(self): | |||
with self.assertRaises(TranspilerError): | ||||
InstructionDurations(invalid_dic) | ||||
|
||||
def test_from_backend_for_backend_with_dt(self): | ||||
backend = FakeParis() | ||||
gate = self._find_gate_with_length(backend) | ||||
durations = InstructionDurations.from_backend(backend) | ||||
self.assertGreater(durations.dt, 0) | ||||
self.assertGreater(durations.get(gate, 0), 0) | ||||
|
||||
def test_from_backend_for_backend_without_dt(self): | ||||
backend = FakeTokyo() | ||||
gate = self._find_gate_with_length(backend) | ||||
durations = InstructionDurations.from_backend(backend) | ||||
self.assertIsNone(durations.dt) | ||||
self.assertGreater(durations.get(gate, 0, "s"), 0) | ||||
with self.assertRaises(TranspilerError): | ||||
durations.get(gate, 0) | ||||
|
||||
def test_update_with_parameters(self): | ||||
durations = InstructionDurations( | ||||
[("rzx", (0, 1), 150, (0.5,)), ("rzx", (0, 1), 300, (1.0,))] | ||||
) | ||||
|
||||
self.assertEqual(durations.get("rzx", [0, 1], parameters=[0.5]), 150) | ||||
self.assertEqual(durations.get("rzx", [0, 1], parameters=[1.0]), 300) | ||||
|
||||
def _find_gate_with_length(self, backend): | ||||
"""Find a gate that has gate length.""" | ||||
props = backend.properties() | ||||
for gate in props.gates: | ||||
try: | ||||
if props.gate_length(gate.gate, 0): | ||||
return gate.gate | ||||
except Exception: # pylint: disable=broad-except | ||||
pass | ||||
raise ValueError("Unable to find a gate with gate length.") | ||||
|
||||
def test_can_get_unbounded_duration_without_unit_conversion(self): | ||||
param = Parameter("t") | ||||
parameterized_delay = Delay(param, "dt") | ||||
|
@@ -88,3 +60,113 @@ def test_fail_if_get_unbounded_duration_with_unit_conversion_when_dt_is_not_prov | |||
parameterized_delay = Delay(param, "s") | ||||
with self.assertRaises(TranspilerError): | ||||
InstructionDurations().get(parameterized_delay, 0) | ||||
|
||||
|
||||
class TestInstrctionDurationsFromBackendV1(QiskitTestCase): | ||||
"""Test :meth:`~.from_backend` of :class:`.InstructionDurations` with | ||||
:class:`.BackendV1`""" | ||||
|
||||
def setUp(self): | ||||
super().setUp() | ||||
|
||||
self.backend = FakeParis() | ||||
self.backend_config = self.backend.configuration() | ||||
self.backend_props = self.backend.properties() | ||||
MozammilQ marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
self.example_qubit = (0,) | ||||
self.example_gate = "x" | ||||
|
||||
# Setting dt for the copy of backend to be None | ||||
self.backend_cpy = deepcopy(self.backend) | ||||
self.backend_cpy.configuration().dt = None | ||||
|
||||
def test_backend_dt_equals_inst_dur_dt(self): | ||||
durations = InstructionDurations.from_backend(self.backend) | ||||
self.assertEqual(durations.dt, self.backend_config.dt) | ||||
|
||||
def test_backend_gate_length_equals_inst_dur(self): | ||||
durations = InstructionDurations.from_backend(self.backend) | ||||
inst_dur_duration = durations.get(self.example_gate, self.example_qubit[0], "s") | ||||
backend_inst_dur = self.backend_props.gate_length( | ||||
gate=self.example_gate, qubits=self.example_qubit | ||||
) | ||||
self.assertEqual(inst_dur_duration, backend_inst_dur) | ||||
|
||||
def test_backend_without_dt_sets_inst_dur_None(self): | ||||
durations = InstructionDurations.from_backend(self.backend_cpy) | ||||
self.assertIsNone(durations.dt) | ||||
|
||||
def test_get_dur_s_with_dt_None(self): | ||||
durations = InstructionDurations.from_backend(self.backend_cpy) | ||||
self.assertEqual( | ||||
durations.get(self.example_gate, self.example_qubit[0], "s"), 3.5555555555555554e-08 | ||||
) | ||||
|
||||
def test_raise_dur_get_dt_with_backend_dt_None(self): | ||||
durations = InstructionDurations.from_backend(self.backend_cpy) | ||||
with self.assertRaises(TranspilerError): | ||||
durations.get(self.example_gate, self.example_qubit[0]) | ||||
|
||||
def test_works_unequal_dt_dtm(self): | ||||
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. What is the purpose of this test? 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. @nkanazawa1989 , This line was the motivation:
Am I missing something |
||||
self.backend_cpy.configuration().dt = 1.0 | ||||
|
||||
# This is expcted to fail | ||||
InstructionDurations.from_backend(self.backend_cpy) | ||||
|
||||
self.backend_cpy.configuration().dt = None # Resetting to None | ||||
MozammilQ marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
# Check if dt and dtm were indeed unequal | ||||
self.assertNotEqual(self.backend_cpy.configuration().dtm, 1.0) | ||||
|
||||
|
||||
class TestInstrctionDurationsFromBackendV2(QiskitTestCase): | ||||
"""Test :meth:`~.from_backend` of :class:`.InstructionDurations` with | ||||
:class:`.BackendV2`""" | ||||
|
||||
def setUp(self): | ||||
super().setUp() | ||||
|
||||
self.backend = FakePerth() | ||||
self.example_gate = "x" | ||||
self.example_qubit = (0,) | ||||
|
||||
# Setting dt for the copy for BackendV2 to None | ||||
self.backend_cpy = deepcopy(self.backend) | ||||
self.backend_cpy.target.dt = None | ||||
|
||||
def test_backend_dt_equals_inst_dur_dt(self): | ||||
durations = InstructionDurations.from_backend(self.backend) | ||||
self.assertEqual(durations.dt, self.backend.dt) | ||||
|
||||
def test_backend_gate_length_equals_inst_dur(self): | ||||
durations = InstructionDurations.from_backend(self.backend) | ||||
inst_dur_duration = durations.get( | ||||
inst=self.example_gate, qubits=self.example_qubit[0], unit="s" | ||||
) | ||||
backend_inst_dur = self.backend.target._gate_map[self.example_gate][ | ||||
self.example_qubit | ||||
].duration | ||||
self.assertEqual(inst_dur_duration, backend_inst_dur) | ||||
|
||||
def test_backend_without_dt_sets_inst_dur_None(self): | ||||
durations = InstructionDurations.from_backend(self.backend_cpy) | ||||
self.assertIsNone(durations.dt) | ||||
|
||||
def test_get_dur_s_with_dt_None(self): | ||||
durations = InstructionDurations.from_backend(self.backend_cpy) | ||||
self.assertEqual( | ||||
durations.get(self.example_gate, self.example_qubit[0], "s"), 3.5555555555555554e-08 | ||||
) | ||||
|
||||
def test_raise_dur_get_dt_with_backend_dt_None(self): | ||||
durations = InstructionDurations.from_backend(self.backend_cpy) | ||||
with self.assertRaises(TranspilerError): | ||||
durations.get(self.example_gate, self.example_qubit[0]) | ||||
|
||||
def test_works_unequal_dt_dtm(self): | ||||
self.backend_cpy.target.dt = 1.0 | ||||
|
||||
# This is expcted to fail | ||||
InstructionDurations.from_backend(self.backend_cpy) | ||||
|
||||
self.backend_cpy.target.dt = None # Resetting to None | ||||
MozammilQ marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
# Check if dt and dtm were indeed unequal | ||||
self.assertNotEqual(self.backend_cpy.dtm, 1.0) |
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.
to fix doc error