Skip to content

Commit

Permalink
Add analog backend (#36)
Browse files Browse the repository at this point in the history
Closes #33 

Adding a more broad analog backend for prototyping, testing and fully
using `pulser` functionalities. Additionally, it includes an abstract
base analog backend (`_base_analog`) to be used for `pulser`-based
backends (in current case, `fresnel1` and `analog`).

It also addresses the points to make the code prototypes on
`qadence2-core` tests to be successfully executed.

---------

Signed-off-by: Doomsk <[email protected]>
  • Loading branch information
Doomsk authored Dec 16, 2024
1 parent 981212e commit 764e0e0
Show file tree
Hide file tree
Showing 31 changed files with 1,404 additions and 627 deletions.
4 changes: 3 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
args: [ '--maxkb=600' ]

- repo: https://github.com/ambv/black
rev: 24.8.0
Expand All @@ -22,6 +23,7 @@ repos:
rev: v1.11.0
hooks:
- id: mypy
args: [--install-types, --non-interactive]
exclude: examples|docs|qadence2_platforms.utils.templates

- repo: https://github.com/DanielNoord/pydocstringformatter
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Qadence 2 Platforms


!!! node
!!! note
Qadence 2 Platforms is currently a *work in progress* and is under active development.

Please be aware that the software is in an early stage, and frequent updates, including breaking changes, are to be expected. This means that:
Expand Down Expand Up @@ -141,7 +141,8 @@ dfdx = torch.autograd.grad(wf, f_params["x"], torch.ones_like(wf))[0]

## Documentation

**Notice**: Documentation in progress.
!!! note
Documentation in progress.


## Contribute
Expand Down
16 changes: 7 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,30 @@ build-backend = "hatchling.build"
name = "qadence2-platforms"
description = "Platform-dependent engines and model to execute compiled expressions with common set of methods."
readme = "README.md"
version = "0.1.2"
requires-python = ">=3.10"
version = "0.2.0"
requires-python = ">=3.10,<3.12"
license = {text = "Proprietary"}
keywords = ["quantum"]
authors = [
{ name = "Eduardo Maschio", email = "[email protected]" },
{ name = "Kaonan Micadei", email = "[email protected]" },
{ name = "Dominik Seitz", email = "[email protected]" },
{ name = "Pim Venderbosch", email= "[email protected]" },
{ name = "Dominik Seitz", email = "[email protected]" }
]
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]

# always specify a version for each package
# to maintain consistency
dependencies = [
"qadence2-ir~=0.1",
"pulser~=1.1",
"pyqtorch~=1.4",
"qadence2-ir>=0.2",
"pulser>=1.1",
"pyqtorch",
]

[tool.hatch.metadata]
Expand Down Expand Up @@ -98,7 +96,7 @@ serve = "mkdocs serve --dev-addr localhost:8000"
test = "mkdocs build --clean --strict"

[[tool.hatch.envs.test.matrix]]
python = ["310", "311", "312"]
python = ["310", "311"]

[tool.hatch.build.targets.sdist]
exclude = [
Expand Down
8 changes: 3 additions & 5 deletions qadence2_platforms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
from __future__ import annotations

from torch import float64, set_default_dtype

from .abstracts import AbstractInterface

set_default_dtype(float64)
from .abstracts import AbstractInterface, OnEnum

PACKAGE_NAME = __name__
BACKEND_FOLDER_NAME = "backends"
Expand All @@ -14,3 +10,5 @@

BASE_BACKEND_MODULE = f"{PACKAGE_NAME}.{BACKEND_FOLDER_NAME}"
USER_BACKEND_MODULE = f"{PACKAGE_NAME}.{USER_BACKENDS_FOLDER_NAME}"

__all__ = ["AbstractInterface", "OnEnum", "BASE_BACKEND_MODULE", "USER_BACKEND_MODULE"]
46 changes: 23 additions & 23 deletions qadence2_platforms/abstracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@

class RunEnum(Enum):
"""
Enum class to be used whenever an Interface class method need to specify.
Enum class to be used whenever an Interface class method need to specify
how to execute the expression: through `run`, `sample`, or `expectation`.
"""

Expand All @@ -26,8 +25,7 @@ class RunEnum(Enum):

class OnEnum(Enum):
"""
Enum class to be used whenever an Interface class method (such as `run`) needs to.
Enum class to be used whenever an Interface class method (such as `run`) needs to
specify where to run the code: on emulator or qpu.
"""

Expand All @@ -49,19 +47,17 @@ class AbstractInterface(
"""
An abstract base class that defines interface essential methods.
It should be
inherited by any class that needs to implement a backend, for instance `pyqtorch`
and `fresnel1` (`pulser` using `qutip` emulator). It is not only used by the package
itself, but users who want to implement or test new backends should also make use
of it.
It should be inherited by any class that needs to implement a backend, for instance
`pyqtorch` and `fresnel1` (`pulser` using `qutip` emulator). It is not only used by
the package itself, but users who want to implement or test new backends should
also make use of it.
"""

@property
@abstractmethod
def info(self) -> dict[str, Any]:
"""
Gives any relevant information about the interface data, such as `device`,.
Gives any relevant information about the interface data, such as `device`,
`register`, etc.
:return: dictionary with the relevant information.
Expand Down Expand Up @@ -97,19 +93,27 @@ def set_parameters(self, params: dict[str, ParameterType]) -> None:
"""
pass

@abstractmethod
def draw(self, values: dict[str, Any]) -> None:
"""
May draw the current sequence with the given values.
Args:
values (dict[str, Any]): the values to be drawn
"""
pass

@abstractmethod
def run(
self,
values: dict[str, ArrayType] | None = None,
**kwargs: Any,
) -> RunResultType:
"""
Gets the results from the expression computation given the parameters (values),.
callback function (if applicable), and extra arguments.
Gets the results from the expression computation given the parameters (values),
and extra arguments.
:param values: dictionary of user-input parameters
:param callback: a callback function if necessary to run some extra processing
:param kwargs: any extra argument that are backends specific can be included in the
child method.
:return: any result type according to what is expected by the backends `run` method
Expand All @@ -124,13 +128,11 @@ def sample(
**kwargs: Any,
) -> SampleResultType:
"""
Samples the computed result given the expression, the parameters (values), number of.
shots, callback function (if applicable), and extra arguments.
Samples the computed result given the expression, the parameters (values), number of
shots, and extra arguments.
:param values: dictionary of user-input parameters
:param shots: number of shots
:param callback: a callback function if necessary to run some extra processing
:param kwargs: any extra argument that are backends specific can be included in the
child method
:return: any result type according to what is expected by the backends `sample` method
Expand All @@ -145,13 +147,11 @@ def expectation(
**kwargs: Any,
) -> ExpectationResultType:
"""
Computes the expectation value for observable(s) given the parameters (values),.
callback function (if applicable), and extra arguments.
Computes the expectation value for observable(s) given the parameters (values),
and extra arguments.
:param values: dictionary of user-input parameters
:param observable: list of observables
:param callback: a callback function if necessary to run some extra processing
:param kwargs: any extra argument that are backends specific can be included in the
child method
:return: any result type according to what is expected by the backends `expectation` method
Expand Down
6 changes: 6 additions & 0 deletions qadence2_platforms/backends/_base_analog/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""
This backend is not intended to be used directly, but rather using as the abstract
module when building Pulser-based backends.
"""

from __future__ import annotations
66 changes: 66 additions & 0 deletions qadence2_platforms/backends/_base_analog/device_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from __future__ import annotations

from abc import ABC

from pulser.devices import Device


class DeviceSettings(ABC):
"""
Device settings to ease the building of sequence, register and interface logic
name (str): the name of the device, ex: `Analog Device`
name_short (str): a shorter name version, ex: `analog`
device (pulser.devices.Device): the pulser device
grid_scale_range (tuple[float, float]): a tuple of min and max values for the
grid scale, ex: `(1.0, 1.0)` (should not scale), `(1.0, 10.0)` (up to
10.0, included)
available_grid_types (tuple[str]): a tuple of all the possible grid types
for the device, ex: `("triangular",)`, `("linear", "square")`
available_directives (tuple[str], optional): a tuple of available directives,
ex: `("enable_digital_analog")`
"""

_name: str
_name_short: str
_device: Device
_grid_scale_range: tuple[float, float]
_available_grid_types: tuple[str, ...]
_available_directives: tuple[str, ...] | tuple | None

@property
def name(self) -> str:
return self._name

@property
def name_short(self) -> str:
return self._name_short

@property
def device(self) -> Device:
return self._device

@property
def grid_scale_range(self) -> tuple[float, float]:
return self._grid_scale_range

@property
def available_grid_types(self) -> tuple[str, ...]:
return self._available_grid_types

@property
def available_directives(self) -> tuple[str, ...] | tuple | None:
return self._available_directives

def scale_in_range(self, grid_scale: float) -> bool:
"""
Check whether the grid scale is within device's range.
Args:
grid_scale (float): the grid scale. For a normal grid, the scale is 1.0
Returns:
A boolean to whether the grid scale is within device's range.
"""

return self._grid_scale_range[0] <= grid_scale <= self._grid_scale_range[1]
Loading

0 comments on commit 764e0e0

Please sign in to comment.