Skip to content

Commit

Permalink
Place coding examples with legacy-like structure (#19)
Browse files Browse the repository at this point in the history
* add expressions and IR

* update IR and Expressions

* update ir and expressions

* update expression

* add platforms

* add examples

* add examples

* add git submodule command on readme

* add minor project changes

* improve README

* add first docs pages

* add small version fixes

* add qadence legacy code

* fix parametric value
add example

* fix parametric value
add example

* small fixes

* lint

* lint

Signed-off-by: Doomsk <[email protected]>

* improve code prototype examples

* improve and fix code for code prototypes examples

* fix examples
add legacy operations

Signed-off-by: Doomsk <[email protected]>

* add independent tests code prototypes

Signed-off-by: Doomsk <[email protected]>

* fix pre-commit

Signed-off-by: Doomsk <[email protected]>

* fix examples

Signed-off-by: Doomsk <[email protected]>

* improve tests

Signed-off-by: Doomsk <[email protected]>

* fix code for ruff

Signed-off-by: Doomsk <[email protected]>

* fix analog & fresnel1 puzzles
add docstrings

Signed-off-by: Doomsk <[email protected]>

* Add code prototypes for puzzles.

* add code prototype examples in the test

Signed-off-by: Doomsk <[email protected]>

---------

Signed-off-by: Doomsk <[email protected]>
Co-authored-by: Kaonan Micadiei <[email protected]>
Co-authored-by: Roland Guichard <[email protected]>
  • Loading branch information
3 people authored Jan 14, 2025
1 parent 7f20dbf commit 1a7f171
Show file tree
Hide file tree
Showing 20 changed files with 1,038 additions and 66 deletions.
318 changes: 318 additions & 0 deletions examples/code_prototype.ipynb

Large diffs are not rendered by default.

22 changes: 12 additions & 10 deletions examples/pulser_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@

import numpy as np
from qadence2_expressions import RX, RY, add_qpu_directives, compile_to_model, parameter
from qadence2_platforms import OnEnum
from qadence2_platforms.compiler import compile_to_backend

a = parameter("a")
expr = RX(1.57 * a)(0) * RY(0.707 * a**2)(0)
print(f"expression: {str(expr)}")
if __name__ == "__main__":
a = parameter("a")
expr = RX(1.57 * a)(0) * RY(0.707 * a**2)(0)
print(f"expression: {str(expr)}")

add_qpu_directives({"digital": True})
model = compile_to_model(expr)
print(f"model: {model}\n")
add_qpu_directives({"digital": True})
model = compile_to_model(expr)
print(f"model: {model}\n")

f_params = {"a": np.array([1.0])}
compiled_model = compile_to_backend(model, "fresnel1")
res = compiled_model.sample(values=f_params, shots=10_000, on="emulator")
print(f"sample result: {res}")
f_params = {"a": np.array([1.0])}
compiled_model = compile_to_backend(model, "fresnel1")
res = compiled_model.sample(values=f_params, shots=10_000, on=OnEnum.EMULATOR)
print(f"sample result: {res}")
29 changes: 15 additions & 14 deletions examples/pyq_compiler.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
from __future__ import annotations

import pyqtorch as pyq
import torch
from qadence2_expressions import RX, RY, add_qpu_directives, compile_to_model, parameter
from qadence2_platforms import OnEnum
from qadence2_platforms.compiler import compile_to_backend

a = parameter("a")
expr = RX(1.57 * a)(0) * RY(0.707 * a**2)(0)
print(f"expression: {str(expr)}")
if __name__ == "__main__":
a = parameter("a")
expr = RX(1.57 * a)(0) * RY(0.707 * a**2)(0)
print(f"expression: {str(expr)}")

add_qpu_directives({"digital": True})
model = compile_to_model(expr)
print(f"model: {model}\n")
add_qpu_directives({"digital": True})
model = compile_to_model(expr)
print(f"model: {model}\n")

f_params = {"a": torch.tensor(1.0, requires_grad=True)}
compiled_model = compile_to_backend(model, "pyqtorch")
res = compiled_model.sample(values=f_params, shots=10_000)
print(f"sample result: {res}")
f_params = {"a": torch.tensor(1.0, requires_grad=True)}
compiled_model = compile_to_backend(model, "pyqtorch")
res = compiled_model.sample(values=f_params, shots=10_000, on=OnEnum.EMULATOR)
print(f"sample result: {res}")

wf = compiled_model.run(state=pyq.zero_state(2), values=f_params)
dfdx = torch.autograd.grad(wf, f_params["a"], torch.ones_like(wf))[0]
print(f"{dfdx = }\n")
wf = compiled_model.run(values=f_params)
dfdx = torch.autograd.grad(wf, f_params["a"], torch.ones_like(wf))[0]
print(f"{dfdx = }\n")
15 changes: 6 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ classifiers = [
# always specify a version for each package
# to maintain consistency
dependencies = [
"qadence2-expressions~=0.3.0",
"qadence2-ir~=0.2.0",
"qadence2_platforms~=0.2.0",
"qadence2-expressions",
"qadence2-ir",
"qadence2_platforms",
"pyqtorch",
]

[tool.hatch.metadata]
Expand All @@ -51,6 +52,7 @@ Source = "https://github.com/pasqal-io/qadence2-core"
[tool.hatch.envs.default]
features = ["extras"]
dependencies = [
"hypothesis",
"pytest",
"pytest-cov",
"pytest-xdist",
Expand Down Expand Up @@ -108,6 +110,7 @@ exclude = [
"/tests",
"/docs",
"/examples",
"/code_prototypes",
]

[tool.hatch.build.targets.wheel]
Expand All @@ -116,12 +119,6 @@ packages = ["qadence2"]
[tool.coverage.run]
branch = true
parallel = true
# uncomment to omit any file from the
# coverage. Regexps can be used
# to select all files from a folder
#omit = [
# "template_python/to_omit.py",
#]

[tool.coverage.report]
exclude_lines = [
Expand Down
10 changes: 10 additions & 0 deletions qadence2/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from __future__ import annotations

from .compiler import Directives, Register, Settings, code_compile

__all__ = [
"code_compile",
"Register",
"Directives",
"Settings",
]
111 changes: 111 additions & 0 deletions qadence2/compiler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any, Literal, Union

from qadence2_expressions import (
add_grid_options,
add_qpu_directives,
compile_to_model,
reset_ir_options,
set_grid_scale,
set_grid_type,
set_number_qubits,
set_qubits_positions,
)
from qadence2_platforms import AbstractInterface
from qadence2_platforms.compiler import compile_to_backend


def code_compile(
expr: Any,
backend_name: str,
register: Register | dict | None = None,
directives: Directives | dict | None = None,
settings: Settings | dict | None = None,
**kwargs: Any,
) -> AbstractInterface:
set_config_compiler(register, directives, settings)
model = compile_to_model(expr)
reset_ir_options()
return compile_to_backend(model, backend_name)


@dataclass
class Register:
"""
Register class to handle register related data. It can be used instead
of pure dictionary to enforce some necessary arguments and validate them.
Args
* grid_type (`Literal["linear", "square", "triangular"]`)
* grid_scale (`float`). Default is `1.0`
* qubit_positions (`list[tuple[int, int]]`). Default is empty `list`
* number_qubits (`int` or `None`). Default is `None`
* grid_options (`dict`). Default is empty `dict`
"""

grid_type: Literal["linear", "square", "triangular"]
grid_scale: float = field(default=1.0)
qubit_positions: list = field(default_factory=list)
number_qubits: Union[int, None] = field(default=None)
grid_options: dict = field(default_factory=dict)

def add_configs(self) -> None:
set_grid_scale(self.grid_scale)
set_grid_type(self.grid_type)
if self.qubit_positions:
set_qubits_positions(self.qubit_positions)
else:
set_number_qubits(self.number_qubits)

if self.grid_options:
add_grid_options(self.grid_options)


class Directives(dict):
def add_configs(self) -> None:
add_qpu_directives(self)


class Settings(dict):
def add_configs(self) -> None:
add_qpu_directives(self)


def set_config_register(register: Register | dict) -> None:
"""
It is assumed to have all the values to pass to the IR register.
Args:
register: a Register class or a dict containing register data such as
grid type, grid scale, qubit positions, and additional configs.
"""
if not isinstance(register, Register):
register = Register(**register)
register.add_configs()


def set_config_directives(directives: Directives | dict) -> None:
if not isinstance(directives, Directives):
directives = Directives(**directives)
directives.add_configs()


def set_config_settings(settings: Settings | dict) -> None:
if not isinstance(settings, Settings):
settings = Settings(**settings)
settings.add_configs()


def set_config_compiler(
register: Register | dict | None = None,
directives: Directives | dict | None = None,
settings: Settings | dict | None = None,
) -> None:
if register:
set_config_register(register)
if directives:
set_config_directives(directives)
if settings:
set_config_settings(settings)
Empty file added qadence2/extensions/__init__.py
Empty file.
25 changes: 25 additions & 0 deletions qadence2/extensions/legacy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from __future__ import annotations

from qadence2_expressions.operators import CZ, X, Y, Z

from .model import QuantumModel
from .operators import CNOT, RX, RY, RZ, N
from .utils import add, chain, kron, mul, pow

__all__ = [
"QuantumModel",
"add",
"mul",
"chain",
"kron",
"pow",
"RX",
"RY",
"RZ",
"CNOT",
"X",
"Y",
"Z",
"CZ",
"N",
]
11 changes: 11 additions & 0 deletions qadence2/extensions/legacy/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from __future__ import annotations

from typing import Any

from qadence2_platforms import AbstractInterface

from qadence2.compiler import code_compile


def QuantumModel(expr: Any, backend: str, **settings: Any) -> AbstractInterface:
return code_compile(expr, backend, **settings)
31 changes: 31 additions & 0 deletions qadence2/extensions/legacy/operators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from __future__ import annotations

import qadence2_expressions.operators as ops
from qadence2_expressions import variable
from qadence2_expressions.core.expression import Expression

# The N = (1/2)(I-Z) operator
N = ops.Z1


def CNOT(target: int, control: int) -> Expression:
return ops.NOT(target=(target,), control=(control,))


def RX(target: int, parameters: Expression | str | float) -> Expression:
return ops.RX(angle=_get_variable(parameters))(target)


def RY(target: int, parameters: Expression | str | float) -> Expression:
return ops.RY(angle=_get_variable(parameters))(target)


def RZ(target: int, parameters: Expression | str | float) -> Expression:
return ops.RZ(angle=_get_variable(parameters))(target)


def _get_variable(expr: Expression | str | float) -> Expression:
if isinstance(expr, str):
return variable(expr)
if isinstance(expr, (Expression, float)):
return expr
34 changes: 34 additions & 0 deletions qadence2/extensions/legacy/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from __future__ import annotations

from enum import Enum, auto
from typing import Generator

from qadence2_expressions.core.expression import Expression


class ParadigmStrategy(Enum):
DIGITAL = auto()
ANALOG = auto()
SDAQC = auto()
BDAQC = auto()
RYDBERG = auto()


def add(expr: Generator | list[Expression]) -> Expression:
return Expression.add(*tuple(expr))


def mul(expr: Generator | list[Expression]) -> Expression:
return Expression.mul(*tuple(expr))


def chain(expr: Generator | list[Expression]) -> Expression:
return mul(expr)


def kron(expr: Generator | list[Expression]) -> Expression:
return Expression.kron(*tuple(expr))


def pow(expr: Generator | list[Expression]) -> Expression:
return Expression.pow(*tuple(expr))
15 changes: 0 additions & 15 deletions qadence2/main.py

This file was deleted.

1 change: 1 addition & 0 deletions qadence2/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from __future__ import annotations
21 changes: 21 additions & 0 deletions tests/code_prototypes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from __future__ import annotations

from .implementation import (
pulser_basic_mis_pulse_v1,
pulser_basic_ramp_v2,
pulser_basic_rx_v1,
pyq_basic_diff_v1,
pyq_basic_rx_v1,
pyq_basic_training_v1,
pyq_basic_training_v2,
)

__all__ = [
"pulser_basic_rx_v1",
"pyq_basic_diff_v1",
"pyq_basic_training_v2",
"pyq_basic_training_v1",
"pyq_basic_rx_v1",
"pulser_basic_ramp_v2",
"pulser_basic_mis_pulse_v1",
]
Loading

0 comments on commit 1a7f171

Please sign in to comment.