Skip to content

Commit

Permalink
Release v0.14.0
Browse files Browse the repository at this point in the history
**Main changes:**
- Creation of backends as a uniform interface for sequence execution
- Deprecation of `Simulation` in favour of `QutipEmulator.from_sequence()`
- Addition of extra configuration parameters to the device and channel classes
- Reduction of the overhead when adding measurement errors to emulation results
- Adding a new realistic device for analog quantum computation: `AnalogDevice`
  • Loading branch information
HGSilveri authored Jul 13, 2023
2 parents 1cf1b6e + 523e916 commit 838c521
Show file tree
Hide file tree
Showing 75 changed files with 3,736 additions and 693 deletions.
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.13.3
0.14.0
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/core.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ which when associated with a :class:`pulser.Sequence` condition its development.

.. autodata:: pulser.devices.Chadoq2

.. autodata:: pulser.devices.IroiseMVP
.. autodata:: pulser.devices.AnalogDevice


Channels
Expand Down
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
11 changes: 9 additions & 2 deletions docs/source/apidoc/simulation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ Classical Simulation
Since version 0.6.0, all simulation classes (previously under the ``pulser.simulation`` module)
are in the ``pulser-simulation`` extension and should be imported from ``pulser_simulation``.

Simulation
QutipEmulator
----------------------

.. automodule:: pulser_simulation.simulation
:class:`QutipEmulator` is the class to simulate :class:`SequenceSamples`, that are samples of a :class:`Sequence`.
It is possible to simulate directly a :class:`Sequence` object by using the class method
``QutipEmulator.from_sequence``. Since version 0.14.0, the :class:`Simulation` class is deprecated
in favour of :class:`QutipEmulator`.

.. autoclass:: pulser_simulation.simulation.QutipEmulator
:members:

.. autoclass:: pulser_simulation.simulation.Simulation

SimConfig
----------------------

Expand Down
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
18 changes: 18 additions & 0 deletions pulser-core/pulser/backend/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright 2023 Pulser Development Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# 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
45 changes: 45 additions & 0 deletions pulser-core/pulser/backend/abc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright 2023 Pulser Development Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Base class for the backend interface."""
from __future__ import annotations

import typing
from abc import ABC, abstractmethod

from pulser.result import Result
from pulser.sequence import Sequence

Results = typing.Sequence[Result]


class Backend(ABC):
"""The backend abstract base class."""

def __init__(self, sequence: Sequence) -> None:
"""Starts a new backend instance."""
self.validate_sequence(sequence)
self._sequence = sequence

@abstractmethod
def run(self) -> Results | typing.Sequence[Results]:
"""Executes the sequence on the backend."""
pass

def validate_sequence(self, sequence: Sequence) -> None:
"""Validates a sequence prior to submission."""
if not isinstance(sequence, Sequence):
raise TypeError(
"'sequence' should be a `Sequence` instance"
f", not {type(sequence)}."
)
125 changes: 125 additions & 0 deletions pulser-core/pulser/backend/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Copyright 2023 Pulser Development Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Defines the backend configuration classes."""
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Literal, Sequence, get_args

import numpy as np

from pulser.backend.noise_model import NoiseModel

EVAL_TIMES_LITERAL = Literal["Full", "Minimal", "Final"]


@dataclass(frozen=True)
class BackendConfig:
"""The base backend configuration.
Attributes:
backend_options: A dictionary of backend specific options.
"""

backend_options: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class EmulatorConfig(BackendConfig):
"""The configuration for emulator backends.
Attributes:
backend_options: A dictionary of backend-specific options.
sampling_rate: The fraction of samples to extract from the pulse
sequence for emulation.
evaluation_times: The times at which results are returned. Choose
between:
- "Full": The times are set to be the ones used to define the
Hamiltonian to the solver.
- "Minimal": The times are set to only include initial and final
times.
- "Final": Returns only the result at the end of the sequence.
- A list of times in µs if you wish to only include those specific
times.
- A float to act as a sampling rate for the resulting state.
initial_state: The initial state from which emulation starts.
Choose between:
- "all-ground" for all atoms in the ground state
- An array of floats with a shape compatible with the system
with_modulation: Whether to emulate the sequence with the programmed
input or the expected output.
noise_model: An optional noise model to emulate the sequence with.
"""

sampling_rate: float = 1.0
evaluation_times: float | Sequence[float] | EVAL_TIMES_LITERAL = "Full"
initial_state: Literal["all-ground"] | Sequence[complex] = "all-ground"
with_modulation: bool = False
noise_model: NoiseModel = field(default_factory=NoiseModel)

def __post_init__(self) -> None:
if not (0 < self.sampling_rate <= 1.0):
raise ValueError(
"The sampling rate (`sampling_rate` = "
f"{self.sampling_rate}) must be greater than 0 and "
"less than or equal to 1."
)

if isinstance(self.evaluation_times, str):
if self.evaluation_times not in get_args(EVAL_TIMES_LITERAL):
raise ValueError(
"If provided as a string, 'evaluation_times' must be one "
f"of the following options: {get_args(EVAL_TIMES_LITERAL)}"
)
elif isinstance(self.evaluation_times, float):
if not (0 < self.evaluation_times <= 1.0):
raise ValueError(
"If provided as a float, 'evaluation_times' must be"
" greater than 0 and less than or equal to 1."
)
elif isinstance(self.evaluation_times, (list, tuple, np.ndarray)):
if np.min(self.evaluation_times, initial=0) < 0:
raise ValueError(
"If provided as a sequence of values, "
"'evaluation_times' must not contain negative values."
)
else:
raise TypeError(
f"'{type(self.evaluation_times)}' is not a valid"
" type for 'evaluation_times'."
)

if isinstance(self.initial_state, str):
if self.initial_state != "all-ground":
raise ValueError(
"If provided as a string, 'initial_state' must be"
" 'all-ground'."
)
elif not isinstance(self.initial_state, (tuple, list, np.ndarray)):
raise TypeError(
f"'{type(self.initial_state)}' is not a valid type for"
" 'initial_state'."
)

if not isinstance(self.noise_model, NoiseModel):
raise TypeError(
"'noise_model' must be a NoiseModel instance,"
f" not {type(self.noise_model)}."
)
Loading

0 comments on commit 838c521

Please sign in to comment.