diff --git a/pdm.lock b/pdm.lock index 56552ad54..cd1229283 100644 --- a/pdm.lock +++ b/pdm.lock @@ -6,7 +6,7 @@ groups = ["default", "dev", "doc"] cross_platform = true static_urls = false lock_version = "4.3" -content_hash = "sha256:c2995ea995ac3393ea3e9e41bfe2ecbb41d84836e2f0c6aaa3dc81d93c727adc" +content_hash = "sha256:e46096370f188b9383b4e9e8c42fa15ba66ff934140d0fb301a6372e5dc7b56e" [[package]] name = "amazon-braket-default-simulator" @@ -853,7 +853,7 @@ files = [ [[package]] name = "ipython" -version = "8.15.0" +version = "8.16.0" requires_python = ">=3.9" summary = "IPython: Productive Interactive Computing" dependencies = [ @@ -873,8 +873,8 @@ dependencies = [ "typing-extensions; python_version < \"3.10\"", ] files = [ - {file = "ipython-8.15.0-py3-none-any.whl", hash = "sha256:45a2c3a529296870a97b7de34eda4a31bee16bc7bf954e07d39abe49caf8f887"}, - {file = "ipython-8.15.0.tar.gz", hash = "sha256:2baeb5be6949eeebf532150f81746f8333e2ccce02de1c7eedde3f23ed5e9f1e"}, + {file = "ipython-8.16.0-py3-none-any.whl", hash = "sha256:dba644376826a532e362da945a672865be7efda76ecf999219e6021bda85d702"}, + {file = "ipython-8.16.0.tar.gz", hash = "sha256:7a1b2e1e6a3ec5baa466163c451335081f31859883889ff0289c6b21f7a095e2"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 347473eb2..ff2226f28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ classifiers = [ dependencies = [ "juliacall>=0.9.14", "numpy>=1.25.2", - "pydantic>=1.10.12", + "pydantic>=1.10.13", "scipy>=1.9.3", "pandas>=2.1.0", "bokeh>=3.2.2", diff --git a/src/bloqade/__init__.py b/src/bloqade/__init__.py index 7be52e800..2e9085733 100644 --- a/src/bloqade/__init__.py +++ b/src/bloqade/__init__.py @@ -1,11 +1,13 @@ from bloqade.ir import var, cast, Variable, Literal, start +from bloqade.ir import to_waveform as waveform from bloqade.serialize import load, save, loads, dumps -from bloqade.builder.factory import ( +from bloqade.factory import ( piecewise_linear, piecewise_constant, linear, constant, + rydberg_h, ) import bloqade.ir as _ir from bloqade.constants import RB_C6 @@ -44,4 +46,6 @@ def tree_depth(depth: int = None): "save", "loads", "dumps", + "rydberg_h", + "waveform", ] diff --git a/src/bloqade/builder/assign.py b/src/bloqade/builder/assign.py index af43e6945..879fdb122 100644 --- a/src/bloqade/builder/assign.py +++ b/src/bloqade/builder/assign.py @@ -93,6 +93,10 @@ def __init__( super().__init__(parent) + if len(assignments) == 0: + self._batch_params = [] + return + circuit = self.parse_circuit() variables = ScanVariablesAnalogCircuit().emit(circuit) diff --git a/src/bloqade/builder/backend/quera.py b/src/bloqade/builder/backend/quera.py index 574154b1c..208789797 100644 --- a/src/bloqade/builder/backend/quera.py +++ b/src/bloqade/builder/backend/quera.py @@ -100,7 +100,7 @@ def cloud_mock(self): """ return self.parse().quera.cloud_mock() - def mock(self, state_file: str = ".mock_state.txt"): + def mock(self, state_file: str = ".mock_state.txt", submission_error: bool = False): """ Specify mock, testing locally. @@ -123,4 +123,6 @@ def mock(self, state_file: str = ".mock_state.txt"): """ - return self.parse().quera.mock(state_file) + return self.parse().quera.mock( + state_file=state_file, submission_error=submission_error + ) diff --git a/src/bloqade/builder/factory.py b/src/bloqade/builder/factory.py deleted file mode 100644 index 91843aeee..000000000 --- a/src/bloqade/builder/factory.py +++ /dev/null @@ -1,42 +0,0 @@ -from bloqade.ir.control.waveform import Waveform, Linear, Constant -from bloqade.builder.typing import ScalarType -from beartype import beartype -from beartype.typing import List - -# this part only for manually build sequences. - - -@beartype -def linear(duration: ScalarType, start: ScalarType, stop: ScalarType): - return Linear(start, stop, duration) - - -@beartype -def constant(duration: ScalarType, value: ScalarType): - return Constant(value, duration) - - -@beartype -def piecewise_linear(durations: List[ScalarType], values: List[ScalarType]) -> Waveform: - pwl_wf = None - for duration, start, stop in zip(durations, values[:-1], values[1:]): - if pwl_wf is None: - pwl_wf = Linear(start, stop, duration) - else: - pwl_wf = pwl_wf.append(Linear(start, stop, duration)) - - return pwl_wf - - -@beartype -def piecewise_constant( - durations: List[ScalarType], values: List[ScalarType] -) -> Waveform: - pwc_wf = None - for duration, value in zip(durations, values): - if pwc_wf is None: - pwc_wf = Constant(value, duration) - else: - pwc_wf = pwc_wf.append(Constant(value, duration)) - - return pwc_wf diff --git a/src/bloqade/factory.py b/src/bloqade/factory.py new file mode 100644 index 000000000..f79115a76 --- /dev/null +++ b/src/bloqade/factory.py @@ -0,0 +1,166 @@ +from bloqade.ir.routine.base import Routine +from bloqade.ir.control.waveform import Waveform, Linear, Constant +from bloqade.builder.typing import ScalarType +from beartype import beartype +from beartype.typing import List, Optional, Union, Dict, Any + + +@beartype +def linear(duration: ScalarType, start: ScalarType, stop: ScalarType) -> Linear: + """Create a Linear waveform. + + Args: + duration (ScalarType): duration of linear waveform + start (ScalarType): starting value of linear waveform + stop (ScalarType): ending value of linear waveform + + Returns: + Linear: Linear waveform + """ + return Linear(start, stop, duration) + + +@beartype +def constant(duration: ScalarType, value: ScalarType) -> Constant: + """Create a Constant waveform. + + Args: + duration (ScalarType): _description_ + value (ScalarType): _description_ + + Returns: + Constant: A Constant waveform. + """ + return Constant(value, duration) + + +@beartype +def piecewise_linear(durations: List[ScalarType], values: List[ScalarType]) -> Waveform: + """Create a piecewise linear waveform. + + Create a piecewise linear waveform from a list of durations and values. The + value `duration[i]` is of the linear segment between `values[i]` and `values[i+1]`. + + Args: + durations (List[ScalarType]): The duration of each segment + values (List[ScalarType]): The values for each segment + + Raises: + ValueError: If the length of `values` is not one greater than the length of + `durations`. + + Returns: + Waveform: The piecewise linear waveform. + """ + + if len(durations) + 1 != len(values): + raise ValueError( + "The length of values must be one greater than the length of durations" + ) + + pwl_wf = None + for duration, start, stop in zip(durations, values[:-1], values[1:]): + if pwl_wf is None: + pwl_wf = Linear(start, stop, duration) + else: + pwl_wf = pwl_wf.append(Linear(start, stop, duration)) + + return pwl_wf + + +@beartype +def piecewise_constant( + durations: List[ScalarType], values: List[ScalarType] +) -> Waveform: + """Create a piecewise linear waveform. + + Create a piecewise constant waveform from a list of durations and values. The + value `duration[i]` corresponds to the length of time for the i'th segment + with a value of `values[i]`. + + Args: + durations (List[ScalarType]): The duration of each segment + values (List[ScalarType]): The values for each segment + + Raises: + ValueError: If the length of `values` is not the same as the length of + `durations`. + + Returns: + Waveform: The piecewise linear waveform. + """ + if len(durations) != len(values): + raise ValueError( + "The length of values must be the same as the length of durations" + ) + + pwc_wf = None + for duration, value in zip(durations, values): + if pwc_wf is None: + pwc_wf = Constant(value, duration) + else: + pwc_wf = pwc_wf.append(Constant(value, duration)) + + return pwc_wf + + +@beartype +def rydberg_h( + atoms_positions: Any, + detuning: Optional[Waveform] = None, + amplitude: Optional[Waveform] = None, + phase: Optional[Waveform] = None, + static_params: Dict[str, Any] = {}, + batch_params: Union[List[Dict[str, Any]], Dict[str, Any]] = [], + args: List[str] = [], +) -> Routine: + """Create a rydberg program with uniform detuning, amplitude, and phase. + + Args: + atoms_positions (Any): Description of geometry of atoms in system. + detuning (Optional[Waveform], optional): Waveform for detuning. + Defaults to None. + amplitude (Optional[Waveform], optional): Waveform describing the amplitude of + the rabi term. Defaults to None. + phase (Optional[Waveform], optional): Waveform describing the phase of rabi + term. Defaults to None. + static_params (Dict[str, Any], optional): Define static parameters of your + program. Defaults to {}. + batch_params (Union[List[Dict[str, Any]], Dict[str, Any]], optional): + Parmaters for a batch of tasks. Defaults to []. + args (List[str], optional): List of arguments to leave till runtime. + Defaults to []. + + Returns: + Routine: An object that can be used to dispatch a rydberg program to + multiple backends. + """ + from bloqade import start + from bloqade.atom_arrangement import AtomArrangement + + print(type(atoms_positions)) + + if isinstance(atoms_positions, AtomArrangement): + prog = atoms_positions + else: + prog = start.add_position(atoms_positions) + + if detuning is not None: + prog = prog.rydberg.detuning.uniform.apply(detuning) + + if amplitude is not None: + prog = prog.amplitude.uniform.apply(amplitude) + + if phase is not None: + prog = prog.phase.uniform.apply(phase) + + prog = prog.assign(**static_params) + + if isinstance(batch_params, dict): + prog = prog.batch_assign(**batch_params) + else: + prog = prog.batch_assign(batch_params) + + prog = prog.args(args) + + return prog.parse() diff --git a/src/bloqade/ir/__init__.py b/src/bloqade/ir/__init__.py index 7ce494ec8..3a5db739b 100644 --- a/src/bloqade/ir/__init__.py +++ b/src/bloqade/ir/__init__.py @@ -11,7 +11,7 @@ Interpolation, Sample, PythonFn, - instruction, + to_waveform, GaussianKernel, LogisticKernel, SigmoidKernel, @@ -68,7 +68,7 @@ "Sample", "Interpolation", "PythonFn", - "instruction", + "to_waveform", "GaussianKernel", "LogisticKernel", "SigmoidKernel", diff --git a/src/bloqade/ir/control/waveform.py b/src/bloqade/ir/control/waveform.py index 7525694f5..244aef3f2 100644 --- a/src/bloqade/ir/control/waveform.py +++ b/src/bloqade/ir/control/waveform.py @@ -1,4 +1,5 @@ from numbers import Real +from bloqade.builder.typing import ScalarType from bloqade.ir.tree_print import Printer from bloqade.ir.scalar import ( Scalar, @@ -14,6 +15,7 @@ from decimal import Decimal from pydantic.dataclasses import dataclass from beartype.typing import Any, Tuple, Union, List, Callable, Dict +from beartype import beartype from enum import Enum import numpy as np @@ -23,7 +25,8 @@ from bloqade.visualization import display_ir -def instruction(duration: Any) -> "PythonFn": +@beartype +def to_waveform(duration: ScalarType) -> Callable[[Callable], "PythonFn"]: # turn python function into a waveform instruction.""" def waveform_wrapper(fn: Callable) -> "PythonFn": @@ -486,6 +489,11 @@ def print_node(self): def children(self): return {"duration": self.duration, **{p.name: p for p in self.parameters}} + def sample( + self, dt: ScalarType, interpolation: Union[str, "Interpolation"] + ) -> "Sample": + return Sample(self, interpolation, cast(dt)) + @dataclass class SmoothingKernel: diff --git a/src/bloqade/ir/routine/base.py b/src/bloqade/ir/routine/base.py index 56338a889..ff0bde798 100644 --- a/src/bloqade/ir/routine/base.py +++ b/src/bloqade/ir/routine/base.py @@ -5,8 +5,8 @@ from bloqade.builder.base import Builder from bloqade.ir.routine.params import Params - -from dataclasses import dataclass +from pydantic import ConfigDict +from pydantic.dataclasses import dataclass from typing import TYPE_CHECKING, Union if TYPE_CHECKING: @@ -29,7 +29,10 @@ def parse(self: "RoutineBase") -> "Routine": return self -@dataclass(frozen=True) +__pydantic_dataclass_config__ = ConfigDict(arbitrary_types_allowed=True) + + +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class RoutineBase(RoutineParse): source: Builder circuit: AnalogCircuit @@ -43,7 +46,7 @@ def __str__(self): return out -@dataclass(frozen=True) +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class Routine(RoutineBase): """Result of parsing a completed Builder string.""" diff --git a/src/bloqade/ir/routine/bloqade.py b/src/bloqade/ir/routine/bloqade.py index 51a09a258..da87a5ec1 100644 --- a/src/bloqade/ir/routine/bloqade.py +++ b/src/bloqade/ir/routine/bloqade.py @@ -1,19 +1,19 @@ from collections import OrderedDict -from bloqade.ir.routine.base import RoutineBase +from bloqade.ir.routine.base import RoutineBase, __pydantic_dataclass_config__ from bloqade.builder.typing import LiteralType from bloqade.task.batch import LocalBatch from beartype import beartype from beartype.typing import Optional, Tuple -from dataclasses import dataclass +from pydantic.dataclasses import dataclass -@dataclass(frozen=True) +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class BloqadeServiceOptions(RoutineBase): def python(self): return BloqadePythonRoutine(self.source, self.circuit, self.params) -@dataclass(frozen=True) +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class BloqadePythonRoutine(RoutineBase): def _compile( self, diff --git a/src/bloqade/ir/routine/braket.py b/src/bloqade/ir/routine/braket.py index c2c718b4b..271d5c8ff 100644 --- a/src/bloqade/ir/routine/braket.py +++ b/src/bloqade/ir/routine/braket.py @@ -1,17 +1,17 @@ from collections import OrderedDict -from dataclasses import dataclass +from pydantic.dataclasses import dataclass from beartype import beartype from beartype.typing import Optional, Tuple from bloqade.builder.typing import LiteralType -from bloqade.ir.routine.base import RoutineBase +from bloqade.ir.routine.base import RoutineBase, __pydantic_dataclass_config__ from bloqade.submission.braket import BraketBackend from bloqade.task.batch import LocalBatch, RemoteBatch from bloqade.task.braket_simulator import BraketEmulatorTask from bloqade.task.braket import BraketTask -@dataclass(frozen=True) +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class BraketServiceOptions(RoutineBase): def aquila(self) -> "BraketHardwareRoutine": backend = BraketBackend( @@ -23,7 +23,7 @@ def local_emulator(self): return BraketLocalEmulatorRoutine(self.source, self.circuit, self.params) -@dataclass(frozen=True) +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class BraketHardwareRoutine(RoutineBase): backend: BraketBackend @@ -163,7 +163,7 @@ def __call__( return self.run(shots, args, name, shuffle, **kwargs) -@dataclass(frozen=True) +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class BraketLocalEmulatorRoutine(RoutineBase): def _compile( self, shots: int, args: Tuple[LiteralType, ...] = (), name: Optional[str] = None diff --git a/src/bloqade/ir/routine/quera.py b/src/bloqade/ir/routine/quera.py index 5f6c9fa23..4d1ad6076 100644 --- a/src/bloqade/ir/routine/quera.py +++ b/src/bloqade/ir/routine/quera.py @@ -1,9 +1,9 @@ from collections import OrderedDict -from dataclasses import dataclass +from pydantic.dataclasses import dataclass import json from bloqade.builder.typing import LiteralType -from bloqade.ir.routine.base import RoutineBase +from bloqade.ir.routine.base import RoutineBase, __pydantic_dataclass_config__ from bloqade.submission.quera import QuEraBackend from bloqade.submission.mock import MockBackend from bloqade.submission.quera_api_client.load_config import load_config @@ -14,7 +14,7 @@ from beartype import beartype -@dataclass(frozen=True) +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class QuEraServiceOptions(RoutineBase): @beartype def device(self, config_file: Optional[str], **api_config): @@ -35,12 +35,14 @@ def cloud_mock(self) -> "QuEraHardwareRoutine": return QuEraHardwareRoutine(self.source, self.circuit, self.params, backend) @beartype - def mock(self, state_file: str = ".mock_state.txt") -> "QuEraHardwareRoutine": - backend = MockBackend(state_file=state_file) + def mock( + self, state_file: str = ".mock_state.txt", submission_error: bool = False + ) -> "QuEraHardwareRoutine": + backend = MockBackend(state_file=state_file, submission_error=submission_error) return QuEraHardwareRoutine(self.source, self.circuit, self.params, backend) -@dataclass(frozen=True) +@dataclass(frozen=True, config=__pydantic_dataclass_config__) class QuEraHardwareRoutine(RoutineBase): backend: Union[QuEraBackend, MockBackend] diff --git a/src/bloqade/submission/mock.py b/src/bloqade/submission/mock.py index a638a1d4f..017a35b87 100644 --- a/src/bloqade/submission/mock.py +++ b/src/bloqade/submission/mock.py @@ -46,8 +46,12 @@ def simulate_task_results(task: QuEraTaskSpecification, p_full=0.99, p_empty=0.0 class MockBackend(SubmissionBackend): state_file: str = ".mock_state.txt" + submission_error: bool = False def submit_task(self, task: QuEraTaskSpecification) -> str: + if self.submission_error: + raise ValueError("mock submission error") + task_id = str(uuid.uuid4()) task_results = simulate_task_results(task) with open(self.state_file, "a") as IO: diff --git a/tests/test_builder.py b/tests/test_builder.py index d133cac8f..f78f0b935 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -15,7 +15,7 @@ import bloqade.ir.routine.braket as braket from plum import NotFoundLookupError -from bloqade.ir.control.waveform import instruction +from bloqade.ir.control.waveform import to_waveform from bloqade.ir import rydberg, detuning, hyperfine, rabi from bloqade import start, cast, var @@ -33,7 +33,7 @@ def test_assign_checks(): delta = var("delta") / (2 * np.pi) omega_max = var("omega_max") * 2 * np.pi - @instruction(t_2) + @to_waveform(t_2) def detuning(t, u): return np.abs(t) * u diff --git a/tests/test_builder_factory.py b/tests/test_builder_factory.py deleted file mode 100644 index ae24fad47..000000000 --- a/tests/test_builder_factory.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -from bloqade.builder.factory import ( - piecewise_linear, - piecewise_constant, - constant, - linear, -) -from bloqade import cast - - -def test_ir_piecewise_linear(): - A = piecewise_linear([0.1, 3.8, 0.2], [-10, -7, "a", "b"]) - - ## Append type ir node - assert len(A.waveforms) == 3 - assert A.waveforms[0].duration == cast(0.1) - assert A.waveforms[0].start == cast(-10) - assert A.waveforms[0].stop == cast(-7) - - assert A.waveforms[1].duration == cast(3.8) - assert A.waveforms[1].start == cast(-7) - assert A.waveforms[1].stop == cast("a") - - assert A.waveforms[2].duration == cast(0.2) - assert A.waveforms[2].start == cast("a") - assert A.waveforms[2].stop == cast("b") - - -def test_ir_const(): - A = constant(value=3.415, duration=0.55) - - ## Constant type ir node: - assert A.value == cast(3.415) - assert A.duration == cast(0.55) - - -def test_ir_linear(): - A = linear(start=0.5, stop=3.2, duration=0.76) - - ## Linear type ir node: - assert A.start == cast(0.5) - assert A.stop == cast(3.2) - assert A.duration == cast(0.76) - - -def test_ir_piecewise_constant(): - A = piecewise_constant(durations=[0.1, 3.8, 0.2], values=[-10, "a", "b"]) - - assert A.waveforms[0].duration == cast(0.1) - assert A.waveforms[0].value == cast(-10) - - assert A.waveforms[1].duration == cast(3.8) - assert A.waveforms[1].value == cast("a") - - assert A.waveforms[2].duration == cast(0.2) - assert A.waveforms[2].value == cast("b") -""" diff --git a/tests/test_factory.py b/tests/test_factory.py new file mode 100644 index 000000000..165f20b28 --- /dev/null +++ b/tests/test_factory.py @@ -0,0 +1,165 @@ +import pytest +from bloqade import ( + waveform, + rydberg_h, + piecewise_linear, + piecewise_constant, + constant, + linear, + var, + cast, + start, +) +from bloqade.atom_arrangement import Chain +from bloqade.ir import ( + AnalogCircuit, + Sequence, + rydberg, + Pulse, + rabi, + detuning, + Field, + Uniform, +) +from bloqade.ir.routine.base import Routine +from bloqade.ir.routine.params import Params +import numpy as np + + +def test_ir_piecewise_linear(): + A = piecewise_linear([0.1, 3.8, 0.2], [-10, -7, "a", "b"]) + + ## Append type ir node + assert len(A.waveforms) == 3 + assert A.waveforms[0].duration == cast(0.1) + assert A.waveforms[0].start == cast(-10) + assert A.waveforms[0].stop == cast(-7) + + assert A.waveforms[1].duration == cast(3.8) + assert A.waveforms[1].start == cast(-7) + assert A.waveforms[1].stop == cast("a") + + assert A.waveforms[2].duration == cast(0.2) + assert A.waveforms[2].start == cast("a") + assert A.waveforms[2].stop == cast("b") + + with pytest.raises(ValueError): + piecewise_linear([0.1, 3.8, 0.2], [-10, -7, "a", "b", "c"]) + + +def test_ir_const(): + A = constant(value=3.415, duration=0.55) + + ## Constant type ir node: + assert A.value == cast(3.415) + assert A.duration == cast(0.55) + + +def test_ir_linear(): + A = linear(start=0.5, stop=3.2, duration=0.76) + + ## Linear type ir node: + assert A.start == cast(0.5) + assert A.stop == cast(3.2) + assert A.duration == cast(0.76) + + +def test_ir_piecewise_constant(): + A = piecewise_constant(durations=[0.1, 3.8, 0.2], values=[-10, "a", "b"]) + + assert A.waveforms[0].duration == cast(0.1) + assert A.waveforms[0].value == cast(-10) + + assert A.waveforms[1].duration == cast(3.8) + assert A.waveforms[1].value == cast("a") + + assert A.waveforms[2].duration == cast(0.2) + assert A.waveforms[2].value == cast("b") + + with pytest.raises(ValueError): + piecewise_constant([0.1, 3.8, 0.2], [-10, -7, "a", "b"]) + + +def test_rydberg_h(): + run_time = var("run_time") + + @waveform(run_time + 0.2) + def delta(t, amp, omega): + return np.sin(omega * t) * amp + + delta = delta.sample(0.05, "linear") + ampl = piecewise_linear([0.1, run_time, 0.1], [0, 10, 10, 0]) + phase = piecewise_constant([2, 2], [0, np.pi]) + register = Chain(11, lattice_spacing=6.1) + + static_params = {"amp": 1.0} + batch_params = [{"omega": omega} for omega in [1, 2, 4, 8]] + args = ["run_time"] + + routine = rydberg_h( + register, + detuning=delta, + amplitude=ampl, + phase=phase, + batch_params=batch_params, + static_params=static_params, + args=args, + ) + + detuning_field = Field({Uniform: delta}) + ampl_field = Field({Uniform: ampl}) + phase_field = Field({Uniform: phase}) + + pulse = Pulse( + {detuning: detuning_field, rabi.amplitude: ampl_field, rabi.phase: phase_field} + ) + sequence = Sequence({rydberg: pulse}) + + source = ( + register.rydberg.detuning.uniform.apply(delta) + .amplitude.uniform.apply(ampl) + .phase.uniform.apply(phase) + .assign(**static_params) + .batch_assign(batch_params) + .args(args) + ) + + circuit = AnalogCircuit(register, sequence) + params = Params(static_params, batch_params, args) + expected_routine = Routine(source, circuit, params) + + # ignore because no equality implemented + # assert routine.source == expected_routine.source + assert routine.circuit == expected_routine.circuit + assert routine.params == expected_routine.params + + +def test_rydberg_h_2(): + run_time = var("run_time") + + @waveform(run_time + 0.2) + def delta(t, amp, omega): + return np.sin(omega * t) * amp + + delta = delta.sample(0.05, "linear") + ampl = piecewise_linear([0.1, run_time, 0.1], [0, 10, 10, 0]) + phase = piecewise_constant([2, 2], [0, np.pi]) + register = start.add_position((0, 0)) + + prog = rydberg_h( + (0, 0), detuning=delta, amplitude=ampl, phase=phase, batch_params={} + ) + + detuning_field = Field({Uniform: delta}) + ampl_field = Field({Uniform: ampl}) + phase_field = Field({Uniform: phase}) + + pulse = Pulse( + {detuning: detuning_field, rabi.amplitude: ampl_field, rabi.phase: phase_field} + ) + sequence = Sequence({rydberg: pulse}) + + print(prog.parse_circuit()) + print(AnalogCircuit(register, sequence)) + + assert prog.parse_circuit() == AnalogCircuit(register, sequence) diff --git a/tests/test_task.py b/tests/test_task.py index 4b04ba6a3..d78b9eb2d 100644 --- a/tests/test_task.py +++ b/tests/test_task.py @@ -1,25 +1,16 @@ from bloqade.atom_arrangement import Chain -from unittest.mock import patch -import bloqade.ir.routine.quera from bloqade.task.batch import RemoteBatch import glob import os - import pytest -@patch("bloqade.ir.routine.quera.MockBackend") def test_batch_error(*args): - backend = bloqade.ir.routine.quera.MockBackend() - - backend.submit_task.side_effect = ValueError("some random error") - backend.dict.return_value = {"state_file": ".mock_state.txt"} - with pytest.raises(RemoteBatch.SubmissionException): ( Chain(5, 6.1) .rydberg.detuning.uniform.linear(-10, 10, 3.0) - .quera.mock() + .quera.mock(submission_error=True) .run_async(100) ) @@ -34,18 +25,12 @@ def test_batch_error(*args): assert len(batch_files) == 1 -@patch("bloqade.ir.routine.quera.MockBackend") -def test_batch_warn(*args): - backend = bloqade.ir.routine.quera.MockBackend() - - backend.submit_task.side_effect = ValueError("some random error") - backend.dict.return_value = {"state_file": ".mock_state.txt"} - +def test_batch_warn(): with pytest.warns(): ( Chain(5, 6.1) .rydberg.detuning.uniform.linear(-10, 10, 3.0) - .quera.mock() + .quera.mock(submission_error=True) .run_async(100, ignore_submission_error=True) ) diff --git a/tests/test_variable_scan.py b/tests/test_variable_scan.py index fe8f05799..d250e4d07 100644 --- a/tests/test_variable_scan.py +++ b/tests/test_variable_scan.py @@ -6,7 +6,7 @@ ) import numpy as np -from bloqade.ir.control.waveform import instruction +from bloqade.ir.control.waveform import to_waveform def test_1(): @@ -42,7 +42,7 @@ def test_2(): delta = var("delta") / (2 * np.pi) omega_max = var("omega_max") * 2 * np.pi - @instruction(t_2) + @to_waveform(t_2) def detuning(t, u): return np.abs(t) * u diff --git a/tests/test_waveform.py b/tests/test_waveform.py index 711bee54b..746b95244 100644 --- a/tests/test_waveform.py +++ b/tests/test_waveform.py @@ -6,7 +6,7 @@ AlignedWaveform, Alignment, AlignedValue, - instruction, + to_waveform, Interpolation, GaussianKernel, LogisticKernel, @@ -81,7 +81,7 @@ def my_func(time, *, omega, phi=0, amplitude): return amplitude * np.cos(omega * time + phi) - @instruction(duration=1.0) + @to_waveform(duration=1.0) def annot_my_func(time, *, omega, phi=0, amplitude): import numpy as np