From da2da8e93f6494a9f7441a79c86aff01515cb3f5 Mon Sep 17 00:00:00 2001 From: Augustinio <68018064+Augustinio@users.noreply.github.com> Date: Tue, 18 Apr 2023 18:43:43 +0200 Subject: [PATCH] [IMPROVEMENT] Replace DeviceType with EmulatorType (#72) * :recycle: remove qpu * :recycle: export device stuff to device for convenience * :pencil: bump major * :alembic: push again --- CHANGELOG.md | 14 ++++++++++++++ README.md | 19 ++++++++----------- sdk/__init__.py | 16 ++++++++-------- sdk/_version.py | 2 +- sdk/batch.py | 9 +++++---- sdk/client.py | 2 +- sdk/device/__init__.py | 13 +++++++++++++ sdk/device/device_types.py | 11 ----------- sdk/device/emulator_types.py | 6 ++++++ tests/conftest.py | 4 ++-- tests/test_batch.py | 27 ++++++++++++++------------- tests/test_config.py | 6 +++--- 12 files changed, 75 insertions(+), 54 deletions(-) delete mode 100644 sdk/device/device_types.py create mode 100644 sdk/device/emulator_types.py diff --git a/CHANGELOG.md b/CHANGELOG.md index a9279957..ebc01c37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,17 +2,31 @@ All notable changes to this project will be documented in this file. +## [0.1.16] 2023-04-06 + +### Changed + + - `device_type` argument replace by `emulator` in sdk create_batch + - `DeviceType` replaced with `EmulatorType` + +### Deleted + + - QPU device type and related logic + ## [0.1.15] 2023-03-27 ### Added + - Added tests to check the login behavior. - Added tests to check the override Endpoints behavior. ### Changed + - The authentication now directly connects to the Auth0 platform instead of connecting through PasqalCloud. - Small refactor of files, with the authentication modules in the `authentication.py` file, instead of `client.py`. ### Deleted + - Account endpoint, we now use Auth0. ## [0.1.14] diff --git a/README.md b/README.md index 589b7c94..a755697a 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,6 @@ sdk = SDK(..., endpoints=endpoints, auth0=auth0) This enables you to target backend services running locally on your machine, or other environment like preprod or dev. - ## Basic usage The package main component is a python object called `SDK` which can be used to create a `Batch` and send it automatically @@ -141,10 +140,10 @@ job2 = {"runs": 50, "variables": {"omega_max": 10.5} } # Send the batch of jobs to the QPU and wait for the results batch = sdk.create_batch(serialized_sequence, [job1,job2], wait=True) -# You can also choose to run your batch on an emulator using the optional argument 'device_type' -# For using a basic single-threaded QPU emulator that can go up to 10 qubits, you can specify the "EMU_FREE" device type. -from sdk import DeviceType -batch = sdk.create_batch(serialized_sequence, [job1,job2], device_type=DeviceType.EMU_FREE) +# You can also choose to run your batch on an emulator using the optional argument 'emulator' +# For using a basic single-threaded QPU emulator that can go up to 10 qubits, you can specify the "EMU_FREE" emulator. +from sdk.device import EmulatorType +batch = sdk.create_batch(serialized_sequence, [job1,job2], emulator=EmulatorType.EMU_FREE) # Once the QPU has returned the results, you can access them with the following: for job in batch.jobs.values(): @@ -162,11 +161,10 @@ For EMU_TN you may add the integrator timestep in nanoseconds, the numerical acc ```python # replace the corresponding section in the above code example with this to # add further configuration -from sdk.device.device_types import DeviceType -from sdk.device.configuration import EmuTNConfig +from sdk.device import EmulatorType, EmuTNConfig configuration = EmuTNConfig(dt = 10.0, precision = "normal", max_bond_dim = 100) -batch = sdk.create_batch(serialized_sequence, [job1,job2], device_type=DeviceType.EMU_TN, configuration=configuration) +batch = sdk.create_batch(serialized_sequence, [job1,job2], emulator=EmulatorType.EMU_TN, configuration=configuration) ``` For EMU_FREE you may add some default SPAM noise. Beware this makes your job take much longer. @@ -174,11 +172,10 @@ For EMU_FREE you may add some default SPAM noise. Beware this makes your job tak ```python # replace the corresponding section in the above code example with this to # add further configuration -from sdk.device.device_types import DeviceType -from sdk.device.configuration import EmuFreeConfig +from sdk.device import EmulatorType, EmuFreeConfig configuration = EmuFreeConfig(with_noise=True) -batch = sdk.create_batch(serialized_sequence, [job1,job2], device_type=DeviceType.EMU_FREE, configuration=configuration) +batch = sdk.create_batch(serialized_sequence, [job1,job2], emulator=EmulatorType.EMU_FREE, configuration=configuration) ``` ### List of supported device specifications diff --git a/sdk/__init__.py b/sdk/__init__.py index 0de73e5a..5ade7445 100644 --- a/sdk/__init__.py +++ b/sdk/__init__.py @@ -18,9 +18,9 @@ from sdk.authentication import TokenProvider from sdk.batch import Batch, RESULT_POLLING_INTERVAL from sdk.client import Client -from sdk.endpoints import Endpoints, Auth0Conf -from sdk.device.configuration import BaseConfig -from sdk.device.device_types import DeviceType +from sdk.device import BaseConfig +from sdk.device import EmulatorType +from sdk.endpoints import Auth0Conf, Endpoints from sdk.job import Job @@ -58,7 +58,7 @@ def create_batch( self, serialized_sequence: str, jobs: List[Dict[str, Any]], - device_type: DeviceType = DeviceType.QPU, + emulator: Optional[EmulatorType] = None, configuration: Optional[BaseConfig] = None, wait: bool = False, fetch_results: bool = False, @@ -71,8 +71,8 @@ def create_batch( serialized_sequence: Serialized pulser sequence. jobs: List of jobs to be added to the batch at creation. (#TODO: Make optional after Iroise MVP) - device_type: The type of device to use, either an emulator or a QPU - If set to QPU, the device_type will be set to the one + emulator: The type of emulator to use, + If set to None, the device_type will be set to the one stored in the serialized sequence configuration: A dictionary with extra configuration for the emulators that accept it. @@ -93,8 +93,8 @@ def create_batch( # the emulator field is only added in the case # an emulator job is requested otherwise it's left empty - if device_type != DeviceType.QPU: - req.update({"emulator": device_type}) + if emulator: + req.update({"emulator": emulator}) # The configuration field is only added in the case # it's requested diff --git a/sdk/_version.py b/sdk/_version.py index 6ee3982d..6ab431d5 100644 --- a/sdk/_version.py +++ b/sdk/_version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.1.15" +__version__ = "0.2.0" diff --git a/sdk/batch.py b/sdk/batch.py index 82a189f9..5060cb10 100644 --- a/sdk/batch.py +++ b/sdk/batch.py @@ -5,7 +5,7 @@ from sdk.client import Client from sdk.job import Job from sdk.device.configuration import BaseConfig, EmuTNConfig, EmuFreeConfig -from sdk.device.device_types import DeviceType +from sdk.device import EmulatorType RESULT_POLLING_INTERVAL = 2 # seconds @@ -65,9 +65,9 @@ def __post_init__(self) -> None: if not isinstance(self.configuration, dict): return conf_class: Type[BaseConfig] = BaseConfig - if self.device_type == DeviceType.EMU_TN.value: + if self.device_type == EmulatorType.EMU_TN.value: conf_class = EmuTNConfig - elif self.device_type == DeviceType.EMU_FREE.value: + elif self.device_type == EmulatorType.EMU_FREE.value: conf_class = EmuFreeConfig self.configuration = conf_class.from_dict(self.configuration) @@ -108,7 +108,8 @@ def declare_complete( Args: wait: Whether to wait for the batch to be done - fetch_results: Whether to download the results. Implies waiting for the batch. + fetch_results: Whether to download the results. Implies + waiting for the batch. A batch that is complete awaits no extra jobs. All jobs previously added will be executed before the batch is terminated. When all its jobs are done, diff --git a/sdk/client.py b/sdk/client.py index 37276106..e2aea53b 100644 --- a/sdk/client.py +++ b/sdk/client.py @@ -16,8 +16,8 @@ from getpass import getpass from typing import Any, Dict, List, Optional, Tuple -from requests.auth import AuthBase import requests +from requests.auth import AuthBase from sdk.authentication import ( TokenProvider, diff --git a/sdk/device/__init__.py b/sdk/device/__init__.py index e69de29b..7e06fc53 100644 --- a/sdk/device/__init__.py +++ b/sdk/device/__init__.py @@ -0,0 +1,13 @@ +from sdk.device.configuration import ( + BaseConfig, + EmuFreeConfig, + EmuTNConfig, +) +from sdk.device.emulator_types import EmulatorType + +__all__ = [ + "BaseConfig", + "EmuFreeConfig", + "EmuTNConfig", + "EmulatorType", +] diff --git a/sdk/device/device_types.py b/sdk/device/device_types.py deleted file mode 100644 index 90646264..00000000 --- a/sdk/device/device_types.py +++ /dev/null @@ -1,11 +0,0 @@ -from sdk.utils.strenum import StrEnum - - -class DeviceType(StrEnum): - QPU = "QPU" - EMU_FREE = "EMU_FREE" - EMU_TN = "EMU_TN" - - @property - def configurable(self) -> bool: - return self in (DeviceType.EMU_FREE, DeviceType.EMU_TN) diff --git a/sdk/device/emulator_types.py b/sdk/device/emulator_types.py new file mode 100644 index 00000000..ebae08a0 --- /dev/null +++ b/sdk/device/emulator_types.py @@ -0,0 +1,6 @@ +from sdk.utils.strenum import StrEnum + + +class EmulatorType(StrEnum): + EMU_FREE = "EMU_FREE" + EMU_TN = "EMU_TN" diff --git a/tests/conftest.py b/tests/conftest.py index c1dd9829..64ceb7e7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,8 +1,8 @@ import json import os + import pytest import requests_mock -from sdk.device.device_types import DeviceType from sdk.endpoints import Endpoints @@ -26,7 +26,7 @@ def mock_core_response(request): if data.get("emulator"): result["data"]["device_type"] = data["emulator"] else: - result["data"]["device_type"] = DeviceType.QPU + result["data"]["device_type"] = "FRESNEL" result["data"]["configuration"] = None return result diff --git a/tests/test_batch.py b/tests/test_batch.py index 28c64999..10a2af0e 100644 --- a/tests/test_batch.py +++ b/tests/test_batch.py @@ -1,11 +1,12 @@ -from uuid import uuid4 from unittest.mock import patch -import pytest +from uuid import uuid4 -from sdk import SDK, DeviceType -from sdk.device.configuration import BaseConfig, EmuFreeConfig, EmuTNConfig +import pytest from tests.test_doubles.authentication import FakeAuth0AuthenticationSuccess +from sdk import SDK +from sdk.device import BaseConfig, EmuFreeConfig, EmulatorType, EmuTNConfig + class TestBatch: @pytest.fixture(autouse=True) @@ -21,13 +22,13 @@ def init_sdk(self, start_mock_request): self.job_id = "00000000-0000-0000-0000-000000022010" self.job_variables = {"Omega_max": 14.4, "last_target": "q1", "ts": [200, 500]} - @pytest.mark.parametrize("device_type", [d.value for d in DeviceType]) - def test_create_batch(self, device_type): + @pytest.mark.parametrize("emulator", [None] + [e.value for e in EmulatorType]) + def test_create_batch(self, emulator): job = {"runs": self.n_job_runs, "variables": self.job_variables} batch = self.sdk.create_batch( serialized_sequence=self.pulser_sequence, jobs=[job], - device_type=device_type, + emulator=emulator, ) assert batch.id == self.batch_id assert batch.sequence_builder == self.pulser_sequence @@ -128,12 +129,12 @@ def test_batch_declare_complete_and_wait_for_results(self, request_mock): assert batch.jobs[self.job_id].result == self.job_result @pytest.mark.parametrize( - "device_type, configuration, expected", + "emulator, configuration, expected", [ - (DeviceType.EMU_TN, EmuTNConfig(), EmuTNConfig()), - (DeviceType.QPU, None, None), + (EmulatorType.EMU_TN, EmuTNConfig(), EmuTNConfig()), + (None, None, None), ( - DeviceType.EMU_FREE, + EmulatorType.EMU_FREE, EmuFreeConfig(), EmuFreeConfig(extra_config={"dt": 10.0, "precision": "normal"}), ), @@ -144,12 +145,12 @@ def test_batch_declare_complete_and_wait_for_results(self, request_mock): ), ], ) - def test_create_batch_configuration(self, device_type, configuration, expected): + def test_create_batch_configuration(self, emulator, configuration, expected): job = {"runs": self.n_job_runs, "variables": self.job_variables} batch = self.sdk.create_batch( serialized_sequence=self.pulser_sequence, jobs=[job], - device_type=device_type, + emulator=emulator, configuration=configuration, ) assert batch.configuration == expected diff --git a/tests/test_config.py b/tests/test_config.py index ceb71650..3a60aec0 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -2,15 +2,15 @@ import pytest +from sdk.device import EmuFreeConfig from sdk.device.configuration.base_config import ( BaseConfig, - InvalidConfiguration, INVALID_KEY_ERROR_MSG, + InvalidConfiguration, ) -from sdk.device.configuration import EmuFreeConfig from sdk.device.configuration.emu_tn import ( - EmuTNConfig, DT_VALUE_NOT_VALID, + EmuTNConfig, PRECISION_NOT_VALID, )