-
Notifications
You must be signed in to change notification settings - Fork 0
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
[Draft] Add generic logic structure and backends functionalities #11
base: main
Are you sure you want to change the base?
Changes from 18 commits
df067bf
0a3fed0
c8c9f0a
b26cad0
3bbb78a
a4a93a8
f9e85f1
bfc60e4
2b7a3b0
0c32dd4
961a67a
137053b
1ab1bc3
578ed5f
38b7835
1aa7e1b
ffaad21
173dfd7
f9206fb
da4f33c
c226300
49b675c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +0,0 @@ | ||
This is just a sample notebook to showcase the rendering of Jupyter notebooks in the documentation. | ||
|
||
```python exec="on" source="material-block" session="main" | ||
from qadence2_platforms.main import main | ||
|
||
msg = main() | ||
print(msg) | ||
``` | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,9 @@ classifiers = [ | |
|
||
# always specify a version for each package | ||
# to maintain consistency | ||
dependencies = ["pyqtorch", | ||
dependencies = [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do these dependencies have to be installed by default ? Or could they be added as extra ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll change it once refactoring parts of the Embedding |
||
"pulser", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
"pyqtorch", | ||
] | ||
|
||
[tool.hatch.metadata] | ||
|
@@ -109,25 +111,25 @@ exclude_lines = [ | |
] | ||
|
||
[tool.ruff] | ||
select = ["E", "F", "I", "Q"] | ||
extend-ignore = ["F841"] | ||
lint.select = ["E", "F", "I", "Q"] | ||
lint.extend-ignore = ["F841"] | ||
line-length = 100 | ||
|
||
[tool.ruff.isort] | ||
[tool.ruff.lint.isort] | ||
required-imports = ["from __future__ import annotations"] | ||
|
||
[tool.ruff.per-file-ignores] | ||
[tool.ruff.lint.per-file-ignores] | ||
"__init__.py" = ["F401"] | ||
|
||
[tool.ruff.mccabe] | ||
[tool.ruff.lint.mccabe] | ||
max-complexity = 15 | ||
|
||
[tool.ruff.flake8-quotes] | ||
[tool.ruff.lint.flake8-quotes] | ||
docstring-quotes = "double" | ||
|
||
[tool.mypy] | ||
python_version = "3.10" | ||
warn_return_any = true | ||
warn_return_any = false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it doesn't like when certain types of returns happen, namely if you do a function factory |
||
warn_unused_configs = true | ||
disallow_untyped_defs = true | ||
no_implicit_optional = false | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from __future__ import annotations | ||
|
||
from abc import ABC, abstractmethod | ||
from typing import Any, Callable, Generic, Iterator, Optional | ||
|
||
from qadence2_platforms.types import ( | ||
BytecodeInstructType, | ||
DeviceType, | ||
EmbeddingType, | ||
InstructionsObjectType, | ||
) | ||
|
||
|
||
class BytecodeApi( | ||
Iterator, Generic[BytecodeInstructType, EmbeddingType, InstructionsObjectType], ABC | ||
): | ||
""" | ||
An iterator class to be used by the runtime function. It contains which backend | ||
to invoke, sequence instance and an iterable of instructions' partial functions | ||
to be filled with user input (if necessary) or called directly, as well as the | ||
device, if applicable. | ||
""" | ||
|
||
def __init__( | ||
self, | ||
backend: str, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't that be a backend name ? |
||
sequence: InstructionsObjectType, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is highly confusing that |
||
instructions: BytecodeInstructType, | ||
variables: EmbeddingType, | ||
device: DeviceType | None = None, | ||
): | ||
self.backend: str = backend | ||
self.device: Optional[DeviceType] = device | ||
self.sequence: InstructionsObjectType = sequence | ||
self.variables: EmbeddingType = variables | ||
self.instructions: BytecodeInstructType = instructions | ||
|
||
@abstractmethod | ||
def __call__(self, *args: Any, **kwargs: Any) -> Callable: | ||
raise NotImplementedError() | ||
|
||
@abstractmethod | ||
def __next__(self) -> Callable: | ||
raise NotImplementedError() |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,85 @@ | ||||||||||
from __future__ import annotations | ||||||||||
|
||||||||||
from abc import ABC, abstractmethod | ||||||||||
from importlib import import_module | ||||||||||
from types import ModuleType | ||||||||||
from typing import Callable, Generic, Optional | ||||||||||
|
||||||||||
from qadence2_platforms.backend.bytecode import BytecodeApi | ||||||||||
from qadence2_platforms.backend.interface import RuntimeInterfaceApi | ||||||||||
from qadence2_platforms.backend.sequence import SequenceApi | ||||||||||
from qadence2_platforms.backend.utils import ( | ||||||||||
get_backend_module, | ||||||||||
get_backend_register_fn, | ||||||||||
get_device_instance, | ||||||||||
get_embedding_instance, | ||||||||||
get_native_seq_instance, | ||||||||||
) | ||||||||||
from qadence2_platforms.qadence_ir import Model | ||||||||||
from qadence2_platforms.types import DeviceType, EmbeddingType, RegisterType | ||||||||||
|
||||||||||
|
||||||||||
class DialectApi(ABC, Generic[RegisterType, DeviceType, EmbeddingType]): | ||||||||||
""" | ||||||||||
<Add the `Dialect` description here> | ||||||||||
|
||||||||||
It is an intermediate resolver class that must be called by the compile function. | ||||||||||
By invoking its `compile` method, it generates a `Bytecode` iterator instance, which | ||||||||||
is necessary for the runtime functionalities, such as `sample`, `expectation`, etc., | ||||||||||
with arguments such as number of shots, feature parameters input, error mitigation | ||||||||||
options, result types, and so on. | ||||||||||
|
||||||||||
Here it is assumed that `Model`'s `inputs` attribute (a dictionary) will contain the | ||||||||||
feature parameters (data provided by the user), and, subsequently, the inputs and all | ||||||||||
the SSA form variables will be located in a single source, now called `embedding`. | ||||||||||
""" | ||||||||||
|
||||||||||
def __init__(self, backend: str, model: Model, device: Optional[str] = None): | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
self.model: Model = model | ||||||||||
self.device_name: str = device or "" | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make type optional. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. which type? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a type mismatch between |
||||||||||
self.backend_name: str = backend | ||||||||||
|
||||||||||
self.device: DeviceType = get_device_instance( | ||||||||||
backend=self.backend_name, device=self.device_name | ||||||||||
) | ||||||||||
|
||||||||||
register_fn: Callable = get_backend_register_fn(self.backend_name) | ||||||||||
self.register: RegisterType = register_fn(self.model, self.device) | ||||||||||
|
||||||||||
self.interface_backend: ModuleType = get_backend_module( | ||||||||||
backend=self.backend_name | ||||||||||
) | ||||||||||
self.native_backend: ModuleType = import_module(self.backend_name) | ||||||||||
|
||||||||||
embedding_instance: Callable = get_embedding_instance(self.backend_name) | ||||||||||
self.embedding: EmbeddingType = embedding_instance(self.model) | ||||||||||
|
||||||||||
native_seq_instance: Callable = get_native_seq_instance( | ||||||||||
backend=self.backend_name, device=self.device_name | ||||||||||
) | ||||||||||
self.native_sequence: SequenceApi = native_seq_instance( | ||||||||||
model=self.model, register=self.register, device=self.device | ||||||||||
) | ||||||||||
|
||||||||||
@abstractmethod | ||||||||||
def compile_bytecode(self) -> BytecodeApi: | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
And similar for the next method
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, something along these lines. |
||||||||||
""" | ||||||||||
It resolves `QuInstruct` into appropriate backend's sequence type, creates the | ||||||||||
appropriate backend's `Register` instance, addresses and converts the directives, | ||||||||||
sets the appropriate data settings, and generates the `Bytecode` instance. | ||||||||||
|
||||||||||
:return: the `Bytecode` instance. | ||||||||||
""" | ||||||||||
raise NotImplementedError() | ||||||||||
|
||||||||||
@abstractmethod | ||||||||||
def compile(self) -> RuntimeInterfaceApi: | ||||||||||
""" | ||||||||||
It resolves `Model` into an appropriate backend's runtime object. It must load | ||||||||||
the desired backend and device, if available, and use the backend's implementation | ||||||||||
to provide the correct interface for the expression to be converted into native | ||||||||||
instructions and thus be runnable into the backends specifications. | ||||||||||
|
||||||||||
:return: a `RuntimeInterface` instance. | ||||||||||
""" | ||||||||||
raise NotImplementedError() |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,52 @@ | ||||||
from __future__ import annotations | ||||||
|
||||||
from abc import ABC, abstractmethod | ||||||
from typing import Any, Generic, Optional | ||||||
|
||||||
from qadence2_platforms import Model | ||||||
from qadence2_platforms.types import ( | ||||||
DType, | ||||||
EmbeddingMappingResultType, | ||||||
EmbeddingType, | ||||||
ParameterType, | ||||||
) | ||||||
|
||||||
|
||||||
class ParameterBufferApi(ABC, Generic[DType, ParameterType]): | ||||||
""" | ||||||
A generic parameter class to hold all root parameters passed by the user or | ||||||
trainable variational parameters. | ||||||
""" | ||||||
|
||||||
_dtype: DType | ||||||
vparams: dict[str, ParameterType] | ||||||
fparams: dict[str, Optional[ParameterType]] | ||||||
|
||||||
@property | ||||||
def dtype(self) -> DType: | ||||||
return self._dtype | ||||||
|
||||||
@abstractmethod | ||||||
def from_model(self, model: Model) -> ParameterBufferApi: | ||||||
raise NotImplementedError() | ||||||
|
||||||
|
||||||
class EmbeddingModuleApi(ABC, Generic[EmbeddingType, EmbeddingMappingResultType]): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
""" | ||||||
A generic module class to hold and handle the parameters and expressions | ||||||
functions coming from the `Model`. It may contain the list of user input | ||||||
parameters, as well as the trainable variational parameters and the | ||||||
evaluated functions from the data types being used, i.e. torch, numpy, etc. | ||||||
""" | ||||||
|
||||||
model: Model | ||||||
param_buffer: ParameterBufferApi | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
mapped_vars: EmbeddingMappingResultType | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
@abstractmethod | ||||||
def __call__(self, *args: Any, **kwargs: Any) -> dict[str, EmbeddingType]: | ||||||
raise NotImplementedError() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it necessary to call it ? |
||||||
|
||||||
@abstractmethod | ||||||
def name_mapping(self) -> EmbeddingMappingResultType: | ||||||
raise NotImplementedError() |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,60 @@ | ||||||
from __future__ import annotations | ||||||
|
||||||
from abc import ABC, abstractmethod | ||||||
from typing import Any, Generic | ||||||
|
||||||
from qadence2_platforms.types import ( | ||||||
EmbeddingType, | ||||||
ExpectationResultType, | ||||||
InterfaceCallResultType, | ||||||
NativeBackendType, | ||||||
NativeSequenceType, | ||||||
RegisterType, | ||||||
RunResultType, | ||||||
SampleResultType, | ||||||
) | ||||||
|
||||||
|
||||||
class RuntimeInterfaceApi( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Interface is redundant. |
||||||
ABC, | ||||||
Generic[ | ||||||
RegisterType, | ||||||
EmbeddingType, | ||||||
NativeSequenceType, | ||||||
NativeBackendType, | ||||||
RunResultType, | ||||||
SampleResultType, | ||||||
ExpectationResultType, | ||||||
InterfaceCallResultType, | ||||||
], | ||||||
): | ||||||
""" | ||||||
Interface generic class to be used to build runtime classes for backends. | ||||||
It may run with the qadence-core runtime functions when post-processing, | ||||||
statistical analysis, etc. | ||||||
""" | ||||||
|
||||||
register: RegisterType | ||||||
embedding: EmbeddingType | ||||||
engine: NativeBackendType | ||||||
sequence: NativeSequenceType | ||||||
|
||||||
@abstractmethod | ||||||
def __call__(self, *args: Any, **kwargs: Any) -> InterfaceCallResultType: | ||||||
raise NotImplementedError() | ||||||
|
||||||
@abstractmethod | ||||||
def forward(self, *args: Any, **kwargs: Any) -> InterfaceCallResultType: | ||||||
raise NotImplementedError() | ||||||
|
||||||
@abstractmethod | ||||||
def run(self, *args: Any, **kwargs: Any) -> RunResultType: | ||||||
raise NotImplementedError() | ||||||
|
||||||
@abstractmethod | ||||||
def sample(self, *args: Any, **kwargs: Any) -> SampleResultType: | ||||||
raise NotImplementedError() | ||||||
|
||||||
@abstractmethod | ||||||
def expectation(self, *args: Any, **kwargs: Any) -> ExpectationResultType: | ||||||
raise NotImplementedError() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from __future__ import annotations | ||
|
||
from .dialect import Dialect | ||
from .embedding import EmbeddingModule | ||
from .interface import RuntimeInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please check if the template-python-project is up-to-date with pre-commits ?