Skip to content

Commit

Permalink
Updates to the backend interfaces (#541)
Browse files Browse the repository at this point in the history
* Upgrade pasqal-cloud and add convenience imports

* Make job_params required + Recover jobs order

* Implement PasqalCloud.fetch_available_devices()

* Updates for new pasqal-cloud version

* Type hinting

* Finish UTs

* Adding convenience imports

* Adding tutorial on backends

* Import sorting and formating

* Update API referencee

* Fix UTs

* Update pasqal-cloud version

* Avoiding mutable defaults

* Use backoff on cloud interactions

* Add link to the API reference in the tutorial

* Fix typo in tutorial
  • Loading branch information
HGSilveri authored Jul 13, 2023
1 parent 031523b commit 87ee5be
Show file tree
Hide file tree
Showing 19 changed files with 704 additions and 99 deletions.
32 changes: 32 additions & 0 deletions docs/source/apidoc/backend.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
************************
Backend Interfaces
************************

QPU
----

.. autoclass:: pulser.QPUBackend
:members:


Emulators
----------

Local
^^^^^^^
.. autoclass:: pulser_simulation.QutipBackend
:members:

Remote
^^^^^^^^^^
.. autoclass:: pulser_pasqal.EmuTNBackend
:members:

.. autoclass:: pulser_pasqal.EmuFreeBackend
:members:


Remote backend connection
---------------------------

.. autoclass:: pulser_pasqal.PasqalCloud
9 changes: 0 additions & 9 deletions docs/source/apidoc/cloud.rst

This file was deleted.

2 changes: 1 addition & 1 deletion docs/source/apidoc/pulser.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ API Reference

core
simulation
cloud
backend
6 changes: 6 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ computers and simulators, check the pages in :doc:`review`.

review

.. toctree::
:maxdepth: 2
:caption: Backend Execution

tutorials/backends

.. toctree::
:maxdepth: 2
:caption: Classical Simulation
Expand Down
3 changes: 3 additions & 0 deletions docs/source/tutorials/backends.nblink
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"path": "../../../tutorials/advanced_features/Backends for Sequence Execution.ipynb"
}
2 changes: 2 additions & 0 deletions pulser-core/pulser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
from pulser.pulse import Pulse
from pulser.register import Register, Register3D
from pulser.sequence import Sequence

from pulser.backend import QPUBackend # isort: skip
4 changes: 4 additions & 0 deletions pulser-core/pulser/backend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Classes for backend execution."""

from pulser.backend.config import EmulatorConfig
from pulser.backend.noise_model import NoiseModel
from pulser.backend.qpu import QPUBackend
4 changes: 2 additions & 2 deletions pulser-core/pulser/backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
EVAL_TIMES_LITERAL = Literal["Full", "Minimal", "Final"]


@dataclass
@dataclass(frozen=True)
class BackendConfig:
"""The base backend configuration.
Expand All @@ -35,7 +35,7 @@ class BackendConfig:
backend_options: dict[str, Any] = field(default_factory=dict)


@dataclass
@dataclass(frozen=True)
class EmulatorConfig(BackendConfig):
"""The configuration for emulator backends.
Expand Down
2 changes: 1 addition & 1 deletion pulser-core/pulser/backend/noise_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
]


@dataclass
@dataclass(frozen=True)
class NoiseModel:
"""Specifies the noise model parameters for emulation.
Expand Down
2 changes: 1 addition & 1 deletion pulser-core/pulser/backend/qpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
class QPUBackend(RemoteBackend):
"""Backend for sequence execution on a QPU."""

def run(self, job_params: list[JobParams] = []) -> RemoteResults:
def run(self, job_params: list[JobParams] | None = None) -> RemoteResults:
"""Runs the sequence on the remote QPU and returns the result.
Args:
Expand Down
22 changes: 17 additions & 5 deletions pulser-core/pulser/backend/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,20 @@ class RemoteResults(Results):
the results.
connection: The remote connection over which to get the submission's
status and fetch the results.
jobs_order: An optional list of job IDs (as stored by the connection)
used to order the results.
"""

def __init__(self, submission_id: str, connection: RemoteConnection):
def __init__(
self,
submission_id: str,
connection: RemoteConnection,
jobs_order: list[str] | None = None,
):
"""Instantiates a new collection of remote results."""
self._submission_id = submission_id
self._connection = connection
self._jobs_order = jobs_order

@property
def results(self) -> tuple[Result, ...]:
Expand All @@ -79,7 +87,9 @@ def __getattr__(self, name: str) -> Any:
status = self.get_status()
if status == SubmissionStatus.DONE:
self._results = tuple(
self._connection._fetch_result(self._submission_id)
self._connection._fetch_result(
self._submission_id, self._jobs_order
)
)
return self._results
raise RemoteResultsError(
Expand All @@ -102,7 +112,9 @@ def submit(
pass

@abstractmethod
def _fetch_result(self, submission_id: str) -> typing.Sequence[Result]:
def _fetch_result(
self, submission_id: str, jobs_order: list[str] | None
) -> typing.Sequence[Result]:
"""Fetches the results of a completed submission."""
pass

Expand All @@ -116,8 +128,8 @@ def _get_submission_status(self, submission_id: str) -> SubmissionStatus:
pass

def fetch_available_devices(self) -> dict[str, Device]:
"""Fetches the available devices through this connection."""
raise NotImplementedError(
"""Fetches the devices available through this connection."""
raise NotImplementedError( # pragma: no cover
"Unable to fetch the available devices through this "
"remote connection."
)
Expand Down
1 change: 1 addition & 0 deletions pulser-pasqal/pulser_pasqal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
from pasqal_cloud import BaseConfig, EmulatorType, Endpoints

from pulser_pasqal._version import __version__
from pulser_pasqal.backends import EmuFreeBackend, EmuTNBackend
from pulser_pasqal.job_parameters import JobParameters, JobVariables
from pulser_pasqal.pasqal_cloud import PasqalCloud
39 changes: 16 additions & 23 deletions pulser-pasqal/pulser_pasqal/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
from pulser.backend.remote import JobParams, RemoteBackend, RemoteResults
from pulser_pasqal.pasqal_cloud import PasqalCloud

DEFAULT_CONFIG_EMU_TN = EmulatorConfig(
evaluation_times="Final", sampling_rate=0.1
)
DEFAULT_CONFIG_EMU_TN = EmulatorConfig(evaluation_times="Final")
DEFAULT_CONFIG_EMU_FREE = EmulatorConfig(
evaluation_times="Final", sampling_rate=0.25
)
Expand Down Expand Up @@ -62,29 +60,24 @@ def run(
"""Executes on the emulator backend through the Pasqal Cloud.
Args:
job_params: An optional list of parameters for each job to execute.
Must be provided only when the sequence is parametrized as
a list of mappings, where each mapping contains one mapping
of variable names to values under the 'variables' field.
job_params: A list of parameters for each job to execute. Each
mapping must contain a defined 'runs' field specifying
the number of times to run the same sequence. If the sequence
is parametrized, the values for all the variables necessary
to build the sequence must be given in it's own mapping, for
each job, under the 'variables' field.
Returns:
The results, which can be accessed once all sequences have been
successfully executed.
"""
needs_build = (
self._sequence.is_parametrized()
or self._sequence.is_register_mappable()
)
if job_params is None and needs_build:
raise ValueError(
"When running a sequence that requires building, "
"'job_params' must be provided."
)
elif job_params and not needs_build:
suffix = f" when executing a sequence on {self.__class__.__name__}."
if not job_params:
raise ValueError("'job_params' must be specified" + suffix)
if any("runs" not in j for j in job_params):
raise ValueError(
"'job_params' cannot be provided when running built "
"sequences on an emulator backend."
"All elements of 'job_params' must specify 'runs'" + suffix
)

return self._connection.submit(
Expand Down Expand Up @@ -119,9 +112,9 @@ class EmuTNBackend(PasqalEmulator):
- sampling_rate
- backend_options:
- precision (str): The precision of the simulation. Can be "low",
"normal" or "high". Defaults to "normal".
"normal" or "high". Defaults to "normal".
- max_bond_dim (int): The maximum bond dimension of the Matrix
Product State (MPS). Defaults to 500.
Product State (MPS). Defaults to 500.
All other parameters should not be changed from their default values.
Expand All @@ -142,8 +135,8 @@ class EmuFreeBackend(PasqalEmulator):
Configurable fields in EmulatorConfig:
- backend_options:
- with_noise (bool): Whether to add noise to the simulation.
Defaults to False.
- with_noise (bool): Whether to add noise to the simulation.
Defaults to False.
All other parameters should not be changed from their default values.
Expand Down
Loading

0 comments on commit 87ee5be

Please sign in to comment.