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

[IMPROVEMENT] Replace DeviceType with EmulatorType #72

Merged
merged 4 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.emulator_types 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():
Expand All @@ -162,23 +161,23 @@ 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.emulator_types import EmulatorType
from sdk.device.configuration import 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.

```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.emulator_types import EmulatorType
from sdk.device.configuration import EmuFreeConfig
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: for convenience for the users, could we export these objects in the sdk.device module ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done


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
Expand Down
12 changes: 6 additions & 6 deletions sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
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.emulator_types import EmulatorType
from sdk.job import Job


Expand Down Expand Up @@ -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,
Expand All @@ -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.
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion sdk/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.

__version__ = "0.1.15"
__version__ = "0.1.16"
9 changes: 5 additions & 4 deletions sdk/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.emulator_types import EmulatorType

RESULT_POLLING_INTERVAL = 2 # seconds

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 0 additions & 11 deletions sdk/device/device_types.py

This file was deleted.

6 changes: 6 additions & 0 deletions sdk/device/emulator_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from sdk.utils.strenum import StrEnum


class EmulatorType(StrEnum):
EMU_FREE = "EMU_FREE"
EMU_TN = "EMU_TN"
4 changes: 2 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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

Expand Down
26 changes: 14 additions & 12 deletions tests/test_batch.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from uuid import uuid4
from unittest.mock import patch
from uuid import uuid4

import pytest
from tests.test_doubles.authentication import FakeAuth0AuthenticationSuccess

from sdk import SDK, DeviceType
from sdk import SDK
from sdk.device.configuration import BaseConfig, EmuFreeConfig, EmuTNConfig
from tests.test_doubles.authentication import FakeAuth0AuthenticationSuccess
from sdk.device.emulator_types import EmulatorType


class TestBatch:
Expand All @@ -21,13 +23,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
Expand Down Expand Up @@ -128,12 +130,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"}),
),
Expand All @@ -144,12 +146,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