Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion guppylang/src/guppylang/emulator/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from __future__ import annotations

from dataclasses import dataclass, replace
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Any

import selene_sim
from typing_extensions import Self
Expand Down Expand Up @@ -39,6 +39,7 @@ class EmulatorBuilder:
_progress_bar: bool = False
_strict: bool = False
_save_planner: bool = False
_custom_args: dict[str, Any] | None = None

@property
def name(self) -> str | None:
Expand All @@ -56,6 +57,11 @@ def verbose(self) -> bool:
"""Whether to print verbose output during the build process."""
return self._verbose

@property
def custom_args(self) -> dict[str, Any] | None:
"""Custom build arguments passed to selene_sim.build."""
return dict(self._custom_args) if self._custom_args is not None else None

def with_name(self, value: str | None) -> Self:
"""Set the name for the emulator instance."""
return replace(self, _name=value)
Expand All @@ -69,6 +75,31 @@ def with_verbose(self, value: bool) -> Self:
"""Set whether to print verbose output during the build process."""
return replace(self, _verbose=value)

def with_build_arg(self, key: str, value: Any) -> Self:
"""Selene builds may support additional customisable arguments,
e.g. to override the choice of compilation route. This is passed
to selene_sim.build as kwargs.

For example:

.. code-block:: python

.with_build_arg("build_method", "via-llvm_ir")

is equivalent to

.. code-block:: python

selene_sim.build(..., build_method="via-llvm_ir")

which saves LLVM IR into the build directory rather than
saving bitcode.
"""
if self._custom_args is None:
return replace(self, _custom_args={key: value})
else:
return replace(self, _custom_args=self._custom_args | {key: value})

def build(self, package: Package, n_qubits: int) -> EmulatorInstance:
"""Build an EmulatorInstance from a compiled package.

Expand All @@ -91,6 +122,7 @@ def build(self, package: Package, n_qubits: int) -> EmulatorInstance:
progress_bar=self._progress_bar,
strict=self._strict,
save_planner=self._save_planner,
**self._custom_args or {},
)

return EmulatorInstance(_instance=instance, _n_qubits=n_qubits)
7 changes: 7 additions & 0 deletions tests/emulator/test_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def test_emulator_builder_default_initialization():
assert builder._progress_bar is False
assert builder._strict is False
assert builder._save_planner is False
assert builder._custom_args is None


@patch("guppylang.emulator.builder.selene_sim")
Expand Down Expand Up @@ -86,6 +87,7 @@ def test_emulator_builder_build_with_custom_parameters(
.with_name("custom_emulator")
.with_build_dir(build_dir)
.with_verbose(True)
.with_build_arg("build_method", "via-llvm-ir")
)

n_qubits = 10
Expand All @@ -104,6 +106,7 @@ def test_emulator_builder_build_with_custom_parameters(
progress_bar=False,
strict=False,
save_planner=False,
build_method="via-llvm-ir",
)

# Check that EmulatorInstance was created correctly
Expand Down Expand Up @@ -138,18 +141,22 @@ def test_emulator_builder_immutability():
new_builder1 = builder.with_name("test1")
new_builder2 = builder.with_build_dir(Path("./build"))
new_builder3 = builder.with_verbose(True)
new_builder4 = builder.with_build_arg("custom_arg", 42)

# All should be different objects
assert new_builder1 is not builder
assert new_builder2 is not builder
assert new_builder3 is not builder
assert new_builder4 is not builder
assert new_builder1 is not new_builder2
assert new_builder2 is not new_builder3
assert new_builder3 is not new_builder4

# Original should be unchanged
assert builder.name is None
assert builder.build_dir is None
assert builder.verbose is False
assert builder.custom_args is None


def test_emulator_builder_reuse():
Expand Down
Loading