Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed
- Added IonQ dynamic backends fetch.

### Repository

- Fix issues with building on CentOS 7 & 8
Expand Down
27 changes: 14 additions & 13 deletions projectq/backends/_ionq/_ionq_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ def __init__(self, verbose=False):

def update_devices_list(self):
"""Update the list of devices this backend can support."""
self.authenticate(self.token)
req = super().get(urljoin(_API_URL, 'backends'))
req.raise_for_status()
r_json = req.json()
# Legacy backends, kept for backward compatibility.
self.backends = {
'ionq_simulator': {
'nq': 29,
Expand All @@ -57,6 +62,8 @@ def update_devices_list(self):
'target': 'qpu',
},
}
for backend in r_json:
self.backends[backend["backend"]] = {"nq": backend["qubits"], "target": backend["backend"]}
if self._verbose: # pragma: no cover
print('- List of IonQ devices available:')
print(self.backends)
Expand Down Expand Up @@ -240,19 +247,14 @@ def _handle_sigint_during_get_result(*_): # pragma: no cover

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

def show_devices(self):
"""Show the currently available device list for the IonQ provider.

def show_devices(verbose=False):
"""Show the currently available device list for the IonQ provider.

Args:
verbose (bool): If True, additional information is printed

Returns:
list: list of available devices and their properties.
"""
ionq_session = IonQ(verbose=verbose)
ionq_session.update_devices_list()
return ionq_session.backends
Returns:
list: list of available devices and their properties.
"""
self.update_devices_list()
return self.backends


def retrieve(
Expand Down Expand Up @@ -398,6 +400,5 @@ def send(
__all__ = [
'send',
'retrieve',
'show_devices',
'IonQ',
]
62 changes: 59 additions & 3 deletions projectq/backends/_ionq/_ionq_http_client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,74 @@ def user_password_input(prompt):
assert str(excinfo.value) == 'An authentication token is required!'


def test_is_online():
def test_is_online(monkeypatch):
def mock_get(_self, path, *args, **kwargs):
assert urljoin(_api_url, 'backends') == path
mock_response = mock.MagicMock()
mock_response.json = mock.MagicMock(
return_value=[
{
"backend": "qpu.s11",
"status": "available",
"qubits": 11,
"average_queue_time": 3253287,
"last_updated": 1647863473555,
"characterization_url": "/characterizations/48ccd423-2913-45e0-a669-e0f676abeb82",
},
{
"backend": "simulator",
"status": "available",
"qubits": 19,
"average_queue_time": 1499,
"last_updated": 1627065490042,
},
],
)
return mock_response

monkeypatch.setattr('requests.sessions.Session.get', mock_get)

ionq_session = _ionq_http_client.IonQ()
ionq_session.authenticate('not none')
ionq_session.update_devices_list()
assert ionq_session.is_online('ionq_simulator')
assert ionq_session.is_online('ionq_qpu')
assert ionq_session.is_online('qpu.s11')
assert not ionq_session.is_online('ionq_unknown')


def test_show_devices():
device_list = _ionq_http_client.show_devices()
def test_show_devices(monkeypatch):
def mock_get(_self, path, *args, **kwargs):
assert urljoin(_api_url, 'backends') == path
mock_response = mock.MagicMock()
mock_response.json = mock.MagicMock(
return_value=[
{
"backend": "qpu.s11",
"status": "available",
"qubits": 11,
"average_queue_time": 3253287,
"last_updated": 1647863473555,
"characterization_url": "/characterizations/48ccd423-2913-45e0-a669-e0f676abeb82",
},
{
"backend": "simulator",
"status": "available",
"qubits": 19,
"average_queue_time": 1499,
"last_updated": 1627065490042,
},
],
)
return mock_response

monkeypatch.setattr('requests.sessions.Session.get', mock_get)

ionq_session = _ionq_http_client.IonQ()
ionq_session.authenticate('not none')
device_list = ionq_session.show_devices()
assert isinstance(device_list, dict)
assert len(device_list) == 4
for info in device_list.values():
assert 'nq' in info
assert 'target' in info
Expand Down
7 changes: 5 additions & 2 deletions projectq/setups/ionq.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
->The 29 qubits simulator
"""
from projectq.backends._exceptions import DeviceOfflineError
from projectq.backends._ionq._ionq_http_client import show_devices
from projectq.backends._ionq._ionq_http_client import IonQ
from projectq.backends._ionq._ionq_mapper import BoundedQubitMapper
from projectq.ops import (
Barrier,
Expand All @@ -47,7 +47,10 @@

def get_engine_list(token=None, device=None):
"""Return the default list of compiler engine for the IonQ platform."""
devices = show_devices(token)
service = IonQ()
if token is not None:
service.authenticate(token=token)
devices = service.show_devices()
if not device or device not in devices:
raise DeviceOfflineError("Error checking engine list: no '{}' devices available".format(device))

Expand Down
13 changes: 11 additions & 2 deletions projectq/setups/ionq_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import pytest

from projectq.backends._exceptions import DeviceOfflineError
from projectq.backends._ionq._ionq_http_client import IonQ
from projectq.backends._ionq._ionq_mapper import BoundedQubitMapper


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

monkeypatch.setattr(projectq.setups.ionq, 'show_devices', mock_show_devices)
monkeypatch.setattr(
IonQ,
'show_devices',
mock_show_devices,
)
engine_list = projectq.setups.ionq.get_engine_list(device='dummy')
assert len(engine_list) > 1
mapper = engine_list[-1]
Expand All @@ -41,7 +46,11 @@ def test_ionq_errors(monkeypatch):
def mock_show_devices(*args, **kwargs):
return {'dummy': {'nq': 3, 'target': 'dummy'}}

monkeypatch.setattr(projectq.setups.ionq, 'show_devices', mock_show_devices)
monkeypatch.setattr(
IonQ,
'show_devices',
mock_show_devices,
)

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