Skip to content
Merged
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
* text=auto

**/tests/snapshots/** linguist-generated=true
**/tests/resources/from_guppy/** linguist-generated=true
36 changes: 26 additions & 10 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ def get_platform_suffix() -> str:
"x86_64-unknown-linux-gnu",
"x86_64-windows-gnu",
]
SUPPORTED_QIS_PLATFORMS = [
"helios",
"sol",
]


def _compile_inline_guppy_source_to_hugr_bytes(guppy_source: str) -> bytes:
Expand Down Expand Up @@ -82,24 +86,30 @@ def _compile_inline_guppy_source_to_hugr_bytes(guppy_source: str) -> bytes:
return (Path(temp_dir) / "output.hugr").read_bytes()


def _compile_hugr_to_llvm_ir_for_target(hugr_bytes: bytes, target: str) -> str:
def _compile_hugr_to_llvm_ir_for_target(
hugr_bytes: bytes, qis_platform: str, target: str
) -> str:
try:
from selene_hugr_qis_compiler import compile_to_llvm_ir
except ImportError as exc:
raise RuntimeError(
"--compile-guppy requires selene_hugr_qis_compiler and guppylang to be installed."
) from exc

return compile_to_llvm_ir(hugr_bytes, target_triple=target)
return compile_to_llvm_ir(hugr_bytes, platform=qis_platform, target_triple=target)


def _hash_guppy(guppy_source: str) -> str:
return hashlib.sha256(guppy_source.encode()).hexdigest()


def _compile_inline_guppy_source_to_llvm_ir(guppy_source: str, *, target: str) -> str:
def _compile_inline_guppy_source_to_llvm_ir(
guppy_source: str, *, qis_platform: str, target: str
) -> str:
hugr_bytes = _compile_inline_guppy_source_to_hugr_bytes(guppy_source)
return _compile_hugr_to_llvm_ir_for_target(hugr_bytes, target=target)
return _compile_hugr_to_llvm_ir_for_target(
hugr_bytes, qis_platform=qis_platform, target=target
)


@pytest.fixture
Expand All @@ -108,25 +118,31 @@ def _resolve(
*,
program_name: str,
guppy_source: str,
qis_platform: str = "helios",
Comment thread
jake-arkinstall marked this conversation as resolved.
) -> Path | bytes:
test_name = request.node.name
test_path = Path(request.node.fspath)

resources_dir = (
test_path.parent / "resources" / "from_guppy" / test_path.stem / test_name
)
platform_file = resources_dir / f"{program_name}-{get_platform_suffix()}.ll"
platform_file = (
resources_dir / f"{program_name}-{qis_platform}-{get_platform_suffix()}.ll"
)
sha_file = resources_dir / f"{program_name}.sha256"
input_sha256 = _hash_guppy(guppy_source)

if compile_guppy:
resources_dir.mkdir(parents=True, exist_ok=True)
sha_file.write_text(input_sha256)
for target in SUPPORTED_TARGETS:
llvm_ir = _compile_inline_guppy_source_to_llvm_ir(
guppy_source, target=target
)
(resources_dir / f"{program_name}-{target}.ll").write_text(llvm_ir)
for qis_platform_it in SUPPORTED_QIS_PLATFORMS:
for target in SUPPORTED_TARGETS:
llvm_ir = _compile_inline_guppy_source_to_llvm_ir(
guppy_source, qis_platform=qis_platform_it, target=target
)
(
resources_dir / f"{program_name}-{qis_platform_it}-{target}.ll"
).write_text(llvm_ir)
else:
if not sha_file.exists():
raise FileNotFoundError(
Expand Down
6 changes: 5 additions & 1 deletion devenv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@
extraPackages = with pkgs.python3Packages; [
types-pyyaml
];
excludes = ["selene-sim/python/tests"];
excludes = [
"selene-sim/python/tests"
"selene-ext/simulators/quest/python/gate_definitions.py"
"selene-ext/simulators/stim/python/gate_definitions.py"
];
};
};
};
Expand Down
21 changes: 13 additions & 8 deletions hatch_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ def initialize(self, version: str, build_data: dict) -> None:
cargo_runner = CargoWorkspaceBuild(self)
cargo_runner.run()
self.build_selene_c_interface()
self.build_helios_qis()
self.build_platform_qis("helios")
self.build_platform_qis("sol")

packages = [Path("selene-sim/python/selene_sim")]
for topic_dir in Path("selene-ext").iterdir():
Expand Down Expand Up @@ -246,6 +247,10 @@ def distribute_cargo_artifacts(self):
self.app.display_info(f"Copying {lib} to {self.install_lib_dir}")
shutil.copy(lib, self.install_lib_dir)
lib_paths.append(lib)
for lib in self.find_release_files("sol_selene_interface"):
self.app.display_info(f"Copying {lib} to {self.install_lib_dir}")
shutil.copy(lib, self.install_lib_dir)
lib_paths.append(lib)

return lib_paths

Expand Down Expand Up @@ -314,13 +319,13 @@ def build_selene_c_interface(self):

self.app.display_success("C interface build completed successfully")

def build_helios_qis(self):
self.app.display_mini_header("Building Helios QIS")
helios_qis_dir = Path(self.root) / "selene-ext/interfaces/helios_qis"
cmake_source_dir = helios_qis_dir / "c"
cmake_build_dir = Path(self.root) / "target" / "helios_qis_build"
def build_platform_qis(self, platform: str):
self.app.display_mini_header(f"Building QIS: {platform}")
platform_qis_dir = Path(self.root) / f"selene-ext/interfaces/{platform}_qis"
cmake_source_dir = platform_qis_dir / "c"
cmake_build_dir = Path(self.root) / f"target/{platform}_qis_build"
cmake_build_dir.mkdir(parents=True, exist_ok=True)
dist_dir = helios_qis_dir / "python/selene_helios_qis_plugin/_dist"
dist_dir = platform_qis_dir / f"python/selene_{platform}_qis_plugin/_dist"
dist_dir.mkdir(parents=True, exist_ok=True)
selene_sim_dist_dir = Path(self.root) / "selene-sim/python/selene_sim/_dist"
cmake_configure_cmd = [
Expand Down Expand Up @@ -382,4 +387,4 @@ def build_helios_qis(self):
self.app.display_error(f"cmake build failed: {e.stderr.decode()}")
sys.exit(1)

self.app.display_success("Helios QIS build completed successfully")
self.app.display_success(f"{platform} QIS build completed successfully")
40 changes: 18 additions & 22 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ dependencies = [
"numpy>=2.2.6",
"pyyaml>=6.0.2",
"selene-core~=0.3.0a0",
"selene-hugr-qis-compiler~=0.2.6",
"tqdm>=4.67.1",
# temporarily an optional dependency until a release provides the lowerings we need.
# CI doesn't make use of the compiler, so this is only needed when using local
# compilations. For this I recommend a uv pip install on a wheel generated from a PR
# with the relevant changes.
#
#"selene-hugr-qis-compiler~=0.2.6",
]
authors = [
{ name = "Jake Arkinstall", email = "jake.arkinstall@quantinuum.com" },
Expand Down Expand Up @@ -43,20 +48,18 @@ classifiers = [
repository = "https://github.com/quantinuum/selene"

[dependency-groups]
test = [
"pytest-snapshot~=0.9.0",
"pytest>=8.3.5",
"pytket~=2.16",
]
dev = [
"auditwheel>=6.3.0",
"cibuildwheel>=2.23.3",
#"guppylang~=0.21.11", # temporary workaround for libtket.so compatibility issues
"hugr~=0.16.0",
"mypy>=1.14.1",
"pip>=24.2",
"pytest-snapshot~=0.9.0",
"pytest>=8.3.5",
"pytket>=2.0.1",
"pytket~=2.9.1",
"qir-qis~=0.1.2",
"ruff>=0.8.0",
"qir-qis~=0.1.2",
"types-pyyaml>=6.0.12.20250402",
{ include-group = "test" },
]

[tool.uv.sources]
Expand All @@ -78,6 +81,7 @@ packages = [
"selene-ext/error-models/ideal/python/selene_ideal_error_model_plugin",
"selene-ext/error-models/simple-leakage/python/selene_simple_leakage_error_model_plugin",
"selene-ext/interfaces/helios_qis/python/selene_helios_qis_plugin",
"selene-ext/interfaces/sol_qis/python/selene_sol_qis_plugin",
"selene-ext/runtimes/simple/python/selene_simple_runtime_plugin",
"selene-ext/runtimes/soft_rz/python/selene_soft_rz_runtime_plugin",
"selene-ext/simulators/classical-replay/python/selene_classical_replay_plugin",
Expand Down Expand Up @@ -106,13 +110,12 @@ cache-keys = [
{ file = "selene-ext/*/*/rust/**/*.rs" },
{ file = "selene-ext/**/Cargo.toml" },
{ file = "selene-ext/**/Cargo.lock" },
{ file = "selene-core/rust/**/*.rs" },
]

[tool.ruff]
# exclude any external code (e.g. stim) fetched in the build process
extend-exclude = [
"target",
]
extend-exclude = ["target"]
[tool.ruff.lint.per-file-ignores]
"**/python/tests/*.py" = ["F821", "F841"] # ^

Expand Down Expand Up @@ -143,10 +146,7 @@ known_first_party = [
"selene_quest_plugin",
"selene_stim_plugin",
]
extend_exclude = [
"target",
"selene-core/python/selene_core",
]
extend_exclude = ["target", "selene-core/python/selene_core"]

[tool.deptry.package_module_name_map]
pyyaml = "yaml"
Expand Down Expand Up @@ -178,11 +178,7 @@ build = "cp310-*"
skip = "*-win32 *-manylinux_i686 *-musllinux*"
build-frontend = { name = "build[uv]", args = ["-C--profile=release"] }
environment-pass = ["UV_EXTRA_INDEX_URL", "PIP_EXTRA_INDEX_URL", "CACHE_CARGO"]
test-requires = [
"pytest",
"pytest-snapshot",
"pytket~=2.9.1",
]
test-groups = ["test"]
test-command = "pytest {project}/selene-sim {project}/selene-ext {project}/selene-core"
[tool.cibuildwheel.linux]
environment = { PATH = "$PATH:$HOME/.cargo/bin" }
Expand Down
33 changes: 22 additions & 11 deletions selene-core/c/include/selene/core_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,6 @@ typedef void *SeleneRuntimeGetOperationInstance;
* first parameter.
*/
typedef struct SeleneRuntimeGetOperationInterface {
void (*rzz_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
uint64_t,
double);
void (*rxy_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
double,
double);
void (*rz_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
double);
void (*measure_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
uint64_t);
Expand All @@ -130,6 +119,28 @@ typedef struct SeleneRuntimeGetOperationInterface {
void (*set_batch_time_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
uint64_t);
void (*rzz_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
uint64_t,
double);
void (*rxy_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
double,
double);
void (*rz_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
double);
void (*rpp_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
uint64_t,
double,
double);
void (*tk2_fn)(SeleneRuntimeGetOperationInstance,
uint64_t,
uint64_t,
double,
double,
double);
} SeleneRuntimeGetOperationInterface;

typedef void *SeleneRuntimeExtractOperationInstance;
Expand Down
43 changes: 43 additions & 0 deletions selene-core/c/include/selene/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ int32_t selene_runtime_global_barrier(RuntimeInstance instance,

/**
* Instruct the runtime to apply an RXY gate to the qubit with the given ID.
* It might not be supported by all runtimes, and an error will be returned
* if it is used on a runtime that does not support it, or if the runtime
* is unable to apply it for any reason.
*
* Note that it is up to the runtime whether or not this gate is applied immediately:
* The runtime might act lazily and apply the gate at a later time when an observable
* outcome is requested.
Expand All @@ -197,6 +201,10 @@ int32_t selene_runtime_rxy_gate(RuntimeInstance instance,

/**
* Instruct the runtime to apply an RZZ gate to the qubits with the given IDs.
* It might not be supported by all runtimes, and an error will be returned
* if it is used on a runtime that does not support it, or if the runtime
* is unable to apply it for any reason.
*
* Note that it is up to the runtime whether or not this gate is applied
* immediately: The runtime might act lazily and apply the gate at a later time.
*/
Expand All @@ -207,6 +215,10 @@ int32_t selene_runtime_rzz_gate(RuntimeInstance instance,

/**
* Instruct the runtime to apply an RZ gate to the qubit with the given ID.
* It might not be supported by all runtimes, and an error will be returned
* if it is used on a runtime that does not support it, or if the runtime
* is unable to apply it for any reason.
*
* Note that it is up to the runtime whether or not this gate is applied
* immediately: The runtime might act lazily and apply the gate at a later time.
* It might not apply it at all, as RZ may be elided in code.
Expand All @@ -215,6 +227,37 @@ int32_t selene_runtime_rz_gate(RuntimeInstance instance,
uint64_t qubit_id,
double theta);

/**
* Instruct the runtime to apply an RPP gate to the qubits with the given IDs.
* It might not be supported by all runtimes, and an error will be returned
* if it is used on a runtime that does not support it, or if the runtime
* is unable to apply it for any reason.
*
* Note that it is up to the runtime whether or not this gate is applied
* immediately: The runtime might act lazily and apply the gate at a later time.
*/
int32_t selene_runtime_rpp_gate(RuntimeInstance instance,
uint64_t qubit_id_1,
uint64_t qubit_id_2,
double theta,
double phi);

/**
* Instruct the runtime to apply a TK2 gate to the qubits with the given IDs.
* It might not be supported by all runtimes, and an error will be returned
* if it is used on a runtime that does not support it, or if the runtime
* is unable to apply it for any reason.
*
* Note that it is up to the runtime whether or not this gate is applied
* immediately: The runtime might act lazily and apply the gate at a later time.
*/
int32_t selene_runtime_tk2_gate(RuntimeInstance instance,
uint64_t qubit_id_1,
uint64_t qubit_id_2,
double alpha,
double beta,
double gamma);

/**
* Instruct the runtime that a measurement is to be requested and to write
* a reference ID to the result to the `result` pointer.
Expand Down
22 changes: 22 additions & 0 deletions selene-core/c/include/selene/simulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,28 @@ int32_t selene_simulator_operation_rz(SeleneSimulatorInstance instance,
uint64_t qubit,
double theta);

/**
* Apply a TK2 (aka SU(4)) gate to the qubits at the requested indices,
* with the provided angles. This gate performs the canonical two-qubit
* interaction characterized by the three angles alpha, beta, and gamma.
*/
int32_t selene_simulator_operation_tk2(SeleneSimulatorInstance instance,
uint64_t qubit1,
uint64_t qubit2,
double alpha,
double beta,
double gamma);

/**
* Apply an RPP gate to the qubits at the requested indices, with the
* provided angles.
*/
int32_t selene_simulator_operation_rpp(SeleneSimulatorInstance instance,
uint64_t qubit1,
uint64_t qubit2,
double theta,
double phi);

/**
* Measure the qubit at the requested index. This is a destructive
* operation.
Expand Down
2 changes: 1 addition & 1 deletion selene-core/examples/error_model/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading