-
Notifications
You must be signed in to change notification settings - Fork 18
feat: add qsystem op for measure leaked #1057
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
Changes from 18 commits
605c8d5
c5c4c39
9aa4d5a
6778c5c
c906c22
7dfbb67
05a903a
9f374c1
a5cb8c9
058e1bf
5ff08b3
a119f37
b8f47c9
0c2834c
b4a0ffe
fcc05dc
2ea4732
fc83207
46f6dbd
f481c4c
769eda7
4b31cb9
8ff7e20
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 |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| from collections.abc import Callable, Sequence | ||
|
|
||
| from hugr import ops | ||
| from hugr import tys as ht | ||
|
|
||
| from guppylang.error import InternalGuppyError | ||
| from guppylang.std._internal.compiler.tket2_exts import FUTURES_EXTENSION | ||
| from guppylang.tys.arg import Argument, TypeArg | ||
| from guppylang.tys.subst import Inst | ||
|
|
||
|
|
||
| def future_to_hugr(type_args: Sequence[Argument]) -> ht.Type: | ||
| match type_args: | ||
| case [TypeArg(ty)]: | ||
| type_def = FUTURES_EXTENSION.get_type("Future") | ||
| return type_def.instantiate([ht.TypeTypeArg(ty.to_hugr())]) | ||
| case _: | ||
| raise InternalGuppyError("Invalid type args for Future type") | ||
|
|
||
|
|
||
| def future_op(op_name: str) -> Callable[[ht.FunctionType, Inst], ops.DataflowOp]: | ||
| op_def = FUTURES_EXTENSION.get_op(op_name) | ||
|
|
||
| def op(concrete: ht.FunctionType, args: Inst) -> ops.DataflowOp: | ||
| return op_def.instantiate([arg.to_hugr() for arg in args], concrete) | ||
|
|
||
| return op |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| from typing import Generic, no_type_check | ||
|
|
||
| from guppylang.decorator import guppy | ||
| from guppylang.std._internal.compiler.futures import future_op, future_to_hugr | ||
| from guppylang.std.lang import owned | ||
| from guppylang.tys.param import TypeParam | ||
|
|
||
| T = guppy.type_var("T", copyable=False, droppable=False) | ||
|
|
||
| _future_params = [TypeParam(0, "T", must_be_copyable=False, must_be_droppable=False)] | ||
|
|
||
|
|
||
| @guppy.type(future_to_hugr, copyable=False, droppable=False, params=_future_params) | ||
| class Future(Generic[T]): # type: ignore[misc] | ||
| """A value of type `T` that is computed asynchronously.""" | ||
|
|
||
| @guppy.hugr_op(future_op("Read")) | ||
| @no_type_check | ||
| def read(self: "Future[T]" @ owned) -> T: | ||
| """Reads a value from a future, consuming it.""" | ||
|
|
||
| @guppy.hugr_op(future_op("Dup")) | ||
| @no_type_check | ||
| def copy(self: "Future[T]") -> "Future[T]": | ||
| """Duplicate a future.""" | ||
|
|
||
| @guppy.hugr_op(future_op("Free")) | ||
| @no_type_check | ||
| def discard(self: "Future[T]" @ owned) -> None: | ||
| """Discards a future without reading it.""" |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,8 @@ | |||||
| from guppylang.std._internal.util import quantum_op | ||||||
| from guppylang.std.angles import angle, pi | ||||||
| from guppylang.std.builtins import owned | ||||||
| from guppylang.std.futures import Future | ||||||
| from guppylang.std.option import Option, nothing, some | ||||||
| from guppylang.std.quantum import qubit | ||||||
|
|
||||||
|
|
||||||
|
|
@@ -74,6 +76,52 @@ def reset(q: qubit) -> None: ... | |||||
| def qfree(q: qubit @ owned) -> None: ... | ||||||
|
|
||||||
|
|
||||||
| @guppy.hugr_op(quantum_op("LazyMeasureLeaked", ext=QSYSTEM_EXTENSION)) | ||||||
| @no_type_check | ||||||
| def _measure_leaked(q: qubit @ owned) -> Future[int]: | ||||||
| """Measure the quibit or return 2 if it is leaked.""" | ||||||
|
|
||||||
|
|
||||||
| @guppy | ||||||
| @no_type_check | ||||||
| def measure_leaked(q: qubit @ owned) -> "MaybeLeaked": | ||||||
|
Collaborator
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. Could you add a dosctring here? |
||||||
| fm = _measure_leaked(q) | ||||||
| return MaybeLeaked(fm) | ||||||
|
|
||||||
|
|
||||||
| @guppy.struct | ||||||
| @no_type_check | ||||||
| class MaybeLeaked: | ||||||
| """A class representing a measurement that may have leaked. | ||||||
|
|
||||||
| This is used to represent the result of `measure_leaked`, which can either | ||||||
| return a boolean measurement result or indicate that the qubit has leaked. | ||||||
| """ | ||||||
|
|
||||||
| _measurement: Future[int] # type: ignore[type-arg] | ||||||
|
|
||||||
| @guppy | ||||||
| @no_type_check | ||||||
| def is_leaked(self: "MaybeLeaked") -> bool: | ||||||
| """Check if the measurement indicates a leak.""" | ||||||
| return self._measurement.copy().read() == 2 | ||||||
|
|
||||||
| @guppy | ||||||
| @no_type_check | ||||||
| def to_result(self: "MaybeLeaked @ owned") -> Option[bool]: | ||||||
| """Get the measurement result if not leaked.""" | ||||||
|
||||||
| """Get the measurement result if not leaked.""" | |
| """Returns the measurement result or `nothing` if leaked.""" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,7 +88,7 @@ miette-py = { workspace = true } | |
|
|
||
| # Uncomment these to test the latest dependency version during development | ||
| # hugr = { git = "https://github.com/CQCL/hugr", subdirectory = "hugr-py", tag = "hugr-v0.20.2" } | ||
| # tket2-exts = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-exts", rev = "652a7d0" } | ||
| tket2-exts = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-exts", rev = "38d1c6f" } | ||
|
||
| # tket2 = { git = "https://github.com/CQCL/tket2", subdirectory = "tket2-py", rev = "fcb2131" } | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from guppylang.decorator import guppy | ||
| from guppylang.std.futures import Future | ||
| from guppylang.std.lang import owned | ||
|
|
||
|
|
||
| def test_read(validate): | ||
| @guppy | ||
| def main(x: Future[int], y: Future[bool] @ owned) -> int: | ||
| z = x.copy() | ||
| if y.read(): | ||
| return z.read() | ||
| z.discard() | ||
| return 0 | ||
|
|
||
| validate(guppy.compile(main)) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,10 @@ | |
| from guppylang.decorator import guppy | ||
| from guppylang.std.angles import angle | ||
| from guppylang.std.builtins import owned, array | ||
| from guppylang.std.option import Option | ||
| from guppylang.std.qsystem.random import make_discrete_distribution, RNG | ||
|
|
||
| from guppylang.std.qsystem import MaybeLeaked, measure_leaked | ||
| from guppylang.std.qsystem.utils import get_current_shot | ||
| from guppylang.std.quantum import qubit, measure_array | ||
| from guppylang.std.qsystem.functional import ( | ||
|
|
@@ -59,3 +62,20 @@ def test() -> tuple[int, float, int, int, angle, angle]: | |
| return rint, rfloat, rint_bnd, rint_discrete, rangle, rcangle | ||
|
|
||
| validate(guppy.compile(test)) | ||
|
|
||
|
|
||
| def test_measure_leaked(validate): # type: ignore[no-untyped-def] | ||
| """Compile the measure_leaked operation.""" | ||
|
|
||
| @guppy | ||
| def test(q: qubit @ owned) -> bool: | ||
narmlu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ml: MaybeLeaked = measure_leaked(q) | ||
| if ml.is_leaked(): | ||
| ml.discard() | ||
| q = qubit() | ||
| m = measure(q) | ||
| return m | ||
|
||
| b: bool = ml.to_result().unwrap() | ||
| return b | ||
|
|
||
| validate(guppy.compile(test)) | ||
Uh oh!
There was an error while loading. Please reload this page.
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.
These are Marks changes in #1075. I'm happy to rebase to that branch if you want, but I'm inclined to just wait until that's merged.