Skip to content

Commit b22a278

Browse files
CynocracyTakishima
andauthored
Add support for dynamic backends for IonQ (#428)
* Add support for dynamic backends for IonQ Using the backends endpoint, add available backends to the list. * Review comments * Formatting fixes * changelog * Remove unnecessary element in docstring Co-authored-by: Nguyen Damien <[email protected]>
1 parent 6f2c2be commit b22a278

File tree

5 files changed

+92
-20
lines changed

5 files changed

+92
-20
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
- Added IonQ dynamic backends fetch.
12+
1013
### Repository
1114

1215
- Fix issues with building on CentOS 7 & 8

projectq/backends/_ionq/_ionq_http_client.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ def __init__(self, verbose=False):
4747

4848
def update_devices_list(self):
4949
"""Update the list of devices this backend can support."""
50+
self.authenticate(self.token)
51+
req = super().get(urljoin(_API_URL, 'backends'))
52+
req.raise_for_status()
53+
r_json = req.json()
54+
# Legacy backends, kept for backward compatibility.
5055
self.backends = {
5156
'ionq_simulator': {
5257
'nq': 29,
@@ -57,6 +62,8 @@ def update_devices_list(self):
5762
'target': 'qpu',
5863
},
5964
}
65+
for backend in r_json:
66+
self.backends[backend["backend"]] = {"nq": backend["qubits"], "target": backend["backend"]}
6067
if self._verbose: # pragma: no cover
6168
print('- List of IonQ devices available:')
6269
print(self.backends)
@@ -240,19 +247,14 @@ def _handle_sigint_during_get_result(*_): # pragma: no cover
240247

241248
raise RequestTimeoutError("Timeout. The ID of your submitted job is {}.".format(execution_id))
242249

250+
def show_devices(self):
251+
"""Show the currently available device list for the IonQ provider.
243252
244-
def show_devices(verbose=False):
245-
"""Show the currently available device list for the IonQ provider.
246-
247-
Args:
248-
verbose (bool): If True, additional information is printed
249-
250-
Returns:
251-
list: list of available devices and their properties.
252-
"""
253-
ionq_session = IonQ(verbose=verbose)
254-
ionq_session.update_devices_list()
255-
return ionq_session.backends
253+
Returns:
254+
list: list of available devices and their properties.
255+
"""
256+
self.update_devices_list()
257+
return self.backends
256258

257259

258260
def retrieve(
@@ -398,6 +400,5 @@ def send(
398400
__all__ = [
399401
'send',
400402
'retrieve',
401-
'show_devices',
402403
'IonQ',
403404
]

projectq/backends/_ionq/_ionq_http_client_test.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,74 @@ def user_password_input(prompt):
5353
assert str(excinfo.value) == 'An authentication token is required!'
5454

5555

56-
def test_is_online():
56+
def test_is_online(monkeypatch):
57+
def mock_get(_self, path, *args, **kwargs):
58+
assert urljoin(_api_url, 'backends') == path
59+
mock_response = mock.MagicMock()
60+
mock_response.json = mock.MagicMock(
61+
return_value=[
62+
{
63+
"backend": "qpu.s11",
64+
"status": "available",
65+
"qubits": 11,
66+
"average_queue_time": 3253287,
67+
"last_updated": 1647863473555,
68+
"characterization_url": "/characterizations/48ccd423-2913-45e0-a669-e0f676abeb82",
69+
},
70+
{
71+
"backend": "simulator",
72+
"status": "available",
73+
"qubits": 19,
74+
"average_queue_time": 1499,
75+
"last_updated": 1627065490042,
76+
},
77+
],
78+
)
79+
return mock_response
80+
81+
monkeypatch.setattr('requests.sessions.Session.get', mock_get)
82+
5783
ionq_session = _ionq_http_client.IonQ()
5884
ionq_session.authenticate('not none')
5985
ionq_session.update_devices_list()
6086
assert ionq_session.is_online('ionq_simulator')
6187
assert ionq_session.is_online('ionq_qpu')
88+
assert ionq_session.is_online('qpu.s11')
6289
assert not ionq_session.is_online('ionq_unknown')
6390

6491

65-
def test_show_devices():
66-
device_list = _ionq_http_client.show_devices()
92+
def test_show_devices(monkeypatch):
93+
def mock_get(_self, path, *args, **kwargs):
94+
assert urljoin(_api_url, 'backends') == path
95+
mock_response = mock.MagicMock()
96+
mock_response.json = mock.MagicMock(
97+
return_value=[
98+
{
99+
"backend": "qpu.s11",
100+
"status": "available",
101+
"qubits": 11,
102+
"average_queue_time": 3253287,
103+
"last_updated": 1647863473555,
104+
"characterization_url": "/characterizations/48ccd423-2913-45e0-a669-e0f676abeb82",
105+
},
106+
{
107+
"backend": "simulator",
108+
"status": "available",
109+
"qubits": 19,
110+
"average_queue_time": 1499,
111+
"last_updated": 1627065490042,
112+
},
113+
],
114+
)
115+
return mock_response
116+
117+
monkeypatch.setattr('requests.sessions.Session.get', mock_get)
118+
119+
ionq_session = _ionq_http_client.IonQ()
120+
ionq_session.authenticate('not none')
121+
device_list = ionq_session.show_devices()
67122
assert isinstance(device_list, dict)
123+
assert len(device_list) == 4
68124
for info in device_list.values():
69125
assert 'nq' in info
70126
assert 'target' in info

projectq/setups/ionq.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
->The 29 qubits simulator
2222
"""
2323
from projectq.backends._exceptions import DeviceOfflineError
24-
from projectq.backends._ionq._ionq_http_client import show_devices
24+
from projectq.backends._ionq._ionq_http_client import IonQ
2525
from projectq.backends._ionq._ionq_mapper import BoundedQubitMapper
2626
from projectq.ops import (
2727
Barrier,
@@ -47,7 +47,10 @@
4747

4848
def get_engine_list(token=None, device=None):
4949
"""Return the default list of compiler engine for the IonQ platform."""
50-
devices = show_devices(token)
50+
service = IonQ()
51+
if token is not None:
52+
service.authenticate(token=token)
53+
devices = service.show_devices()
5154
if not device or device not in devices:
5255
raise DeviceOfflineError("Error checking engine list: no '{}' devices available".format(device))
5356

projectq/setups/ionq_test.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import pytest
1818

1919
from projectq.backends._exceptions import DeviceOfflineError
20+
from projectq.backends._ionq._ionq_http_client import IonQ
2021
from projectq.backends._ionq._ionq_mapper import BoundedQubitMapper
2122

2223

@@ -26,7 +27,11 @@ def test_basic_ionq_mapper(monkeypatch):
2627
def mock_show_devices(*args, **kwargs):
2728
return {'dummy': {'nq': 3, 'target': 'dummy'}}
2829

29-
monkeypatch.setattr(projectq.setups.ionq, 'show_devices', mock_show_devices)
30+
monkeypatch.setattr(
31+
IonQ,
32+
'show_devices',
33+
mock_show_devices,
34+
)
3035
engine_list = projectq.setups.ionq.get_engine_list(device='dummy')
3136
assert len(engine_list) > 1
3237
mapper = engine_list[-1]
@@ -41,7 +46,11 @@ def test_ionq_errors(monkeypatch):
4146
def mock_show_devices(*args, **kwargs):
4247
return {'dummy': {'nq': 3, 'target': 'dummy'}}
4348

44-
monkeypatch.setattr(projectq.setups.ionq, 'show_devices', mock_show_devices)
49+
monkeypatch.setattr(
50+
IonQ,
51+
'show_devices',
52+
mock_show_devices,
53+
)
4554

4655
with pytest.raises(DeviceOfflineError):
4756
projectq.setups.ionq.get_engine_list(device='simulator')

0 commit comments

Comments
 (0)