Skip to content
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

Fix backend_util.py and test cases to support Aer 0.13 #11172

Merged
merged 14 commits into from
Nov 20, 2023
Merged
6 changes: 6 additions & 0 deletions qiskit/utils/backend_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ def is_simulator_backend(backend):
backend_interface_version = _get_backend_interface_version(backend)
if backend_interface_version <= 1:
return backend.configuration().simulator
else:
if "simulator" in backend.name:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My concern with this would the that the remote simulator "ibmq_qasm_simulator" would now be treated as local simulator wouldn't it. There is logic in run_circuits that dealt with max circuits around whether things were being run locally or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that with the upcoming changes in runtime simulators we shouldn't worry about this too much.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙈

return True
return False


Expand All @@ -246,6 +249,9 @@ def is_local_backend(backend):
backend_interface_version = _get_backend_interface_version(backend)
if backend_interface_version <= 1:
return backend.configuration().local
else:
if "simulator" in backend.name:
return True
return False


Expand Down
6 changes: 6 additions & 0 deletions releasenotes/notes/fix_sim_backend-f3971b1ed4d0c4e6.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fixes:
- |
Fix `backend_utils.py` for simulator backends with BackendV2.
`is_simulator_backend` and `is_local_backend` returns `True`
if backend name that contains `simulator`.
44 changes: 27 additions & 17 deletions test/python/circuit/test_controlled_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1021,12 +1021,13 @@ def test_standard_base_gate_setting(self, gate_class):
"""
if gate_class in {SingletonControlledGate, _SingletonControlledGateOverrides}:
self.skipTest("SingletonControlledGate isn't directly instantiated.")
num_free_params = len(_get_free_params(gate_class.__init__, ignore=["self"]))
gate_params = _get_free_params(gate_class.__init__, ignore=["self"])
num_free_params = len(gate_params)
free_params = [0.1 * i for i in range(num_free_params)]
if gate_class in [MCU1Gate, MCPhaseGate]:
free_params[1] = 3
elif gate_class in [MCXGate]:
free_params[0] = 3
# set number of control qubits
for i in range(num_free_params):
if gate_params[i] == "num_ctrl_qubits":
free_params[i] = 3
Comment on lines +1027 to +1030
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that this change is to make the code a bit general and not only work for MCU1Gate, MCPhaseGate and MCXGate, but I was wondering, why did this fail with the new Aer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test discovery attempts to discover every registered subclass of ControlledGate (Python makes that information easily accessible), without restriction to the Qiskit standard library, where it would make sense.

We ideally should probably fix the test discovery to limit it only to controlled gates defined in qiskit.circuit.library.standard_gates.

Copy link
Contributor

@ElePT ElePT Nov 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you are suggesting changing the current code on line 1017:
@data(*ControlledGate.__subclasses__())
with something like:
@data([cls for cls in allGates.__dict__.values() if isinstance(cls,type) and issubclass(cls,ControlledGate)])?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a huge fan of the automatic discovery in its current form at all, but given the current file, yeah, something like that would be fine. Something a little less magic would be

from qiskit.circuit.library.standard_gates import get_standard_gate_name_mapping

standard_controlled_types = [x.base_class for x in get_standard_gate_name_mapping().values() if isinstance(x, ControlledGate)]

That would exclude the multi-controlled gates, which imo should be handled specially if they're not going to follow the conventions of standard-library gates.

(really, I don't think the mcx etc gates should be in standard_gates at all, they should be in generalized_gates, but that's an argument for another time)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that it looks like there is a lot of room for improvement in these tests, let's keep the current fix as-is and consider improving the tests in a follow-up.


base_gate = gate_class(*free_params)
cgate = base_gate.control()
Expand Down Expand Up @@ -1153,12 +1154,13 @@ def test_base_gate_params_reference(self):
with self.subTest(i=repr(gate_class)):
if gate_class in {SingletonControlledGate, _SingletonControlledGateOverrides}:
self.skipTest("Singleton class isn't intended to be created directly.")
num_free_params = len(_get_free_params(gate_class.__init__, ignore=["self"]))
free_params = [0.1 * (i + 1) for i in range(num_free_params)]
if gate_class in [MCU1Gate, MCPhaseGate]:
free_params[1] = 3
elif gate_class in [MCXGate]:
free_params[0] = 3
gate_params = _get_free_params(gate_class.__init__, ignore=["self"])
num_free_params = len(gate_params)
free_params = [0.1 * i for i in range(num_free_params)]
# set number of control qubits
for i in range(num_free_params):
if gate_params[i] == "num_ctrl_qubits":
free_params[i] = 3

base_gate = gate_class(*free_params)
if base_gate.params:
Expand Down Expand Up @@ -1379,12 +1381,13 @@ def test_open_controlled_to_matrix(self, gate_class, ctrl_state):
"""Test open controlled to_matrix."""
if gate_class in {SingletonControlledGate, _SingletonControlledGateOverrides}:
self.skipTest("SingletonGateClass isn't intended for direct initalization")
num_free_params = len(_get_free_params(gate_class.__init__, ignore=["self"]))
gate_params = _get_free_params(gate_class.__init__, ignore=["self"])
num_free_params = len(gate_params)
free_params = [0.1 * i for i in range(1, num_free_params + 1)]
if gate_class in [MCU1Gate, MCPhaseGate]:
free_params[1] = 3
elif gate_class in [MCXGate]:
free_params[0] = 3
# set number of control qubits
for i in range(num_free_params):
if gate_params[i] == "num_ctrl_qubits":
free_params[i] = 3
cgate = gate_class(*free_params)
cgate.ctrl_state = ctrl_state

Expand Down Expand Up @@ -1487,14 +1490,21 @@ def test_controlled_standard_gates(self, num_ctrl_qubits, gate_class):
ctrl_state_zeros = 0
ctrl_state_mixed = ctrl_state_ones >> int(num_ctrl_qubits / 2)

numargs = len(_get_free_params(gate_class))
gate_params = _get_free_params(gate_class)
numargs = len(gate_params)
args = [theta] * numargs
if gate_class in [MSGate, Barrier]:
args[0] = 2
elif gate_class in [MCU1Gate, MCPhaseGate]:
args[1] = 2
elif issubclass(gate_class, MCXGate):
args = [5]
else:
# set number of control qubits
for i in range(numargs):
if gate_params[i] == "num_ctrl_qubits":
args[i] = 2

gate = gate_class(*args)

for ctrl_state in (ctrl_state_ones, ctrl_state_zeros, ctrl_state_mixed):
Expand Down
3 changes: 3 additions & 0 deletions test/python/providers/test_fake_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,9 @@ def __init__(self, num_ctrl_qubits, ctrl_state=None):
from qiskit_aer.noise.noise_model import QuantumErrorLocation

sim = AerSimulator()
# test only if simulator's backend is V1
if sim.version > 1:
return
phi = Parameter("phi")
lam = Parameter("lam")
backend = BackendV2Converter(
Expand Down
18 changes: 1 addition & 17 deletions test/python/pulse/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@

"""Test cases for the pulse schedule block."""
import re
import unittest
from typing import List, Any
from qiskit import pulse, circuit
from qiskit.pulse import transforms
from qiskit.pulse.exceptions import PulseError
from qiskit.test import QiskitTestCase
from qiskit.providers.fake_provider import FakeOpenPulse2Q, FakeArmonk
from qiskit.utils import has_aer
from qiskit.providers.fake_provider import FakeOpenPulse2Q


class BaseTestBlock(QiskitTestCase):
Expand Down Expand Up @@ -372,20 +370,6 @@ def test_inherit_from(self):
self.assertEqual(new_sched.name, ref_name)
self.assertDictEqual(new_sched.metadata, ref_metadata)

@unittest.skipUnless(has_aer(), "qiskit-aer doesn't appear to be installed.")
def test_execute_block(self):
"""Test executing a ScheduleBlock on a Pulse backend"""

with pulse.build(name="test_block") as sched_block:
pulse.play(pulse.Constant(160, 1.0), pulse.DriveChannel(0))
pulse.acquire(50, pulse.AcquireChannel(0), pulse.MemorySlot(0))

backend = FakeArmonk()
# TODO: Rewrite test to simulate with qiskit-dynamics
with self.assertWarns(DeprecationWarning):
test_result = backend.run(sched_block).result()
self.assertDictEqual(test_result.get_counts(), {"0": 1024})


class TestBlockEquality(BaseTestBlock):
"""Test equality of blocks.
Expand Down