Skip to content
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

feat!: qsystem std functions with updated primitives #679

Merged
merged 8 commits into from
Dec 2, 2024
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions guppylang/std/_internal/compiler/quantum.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
from __future__ import annotations

from hugr import Wire, ops
from hugr import ext as he
from hugr import tys as ht
from hugr.std.float import FLOAT_T
from tket2_exts import futures, hseries, quantum, result, rotation
from tket2_exts import futures, qsystem, quantum, result, rotation

from guppylang.definition.custom import CustomInoutCallCompiler
from guppylang.definition.value import CallReturnWires
Expand All @@ -17,7 +18,7 @@
# ----------------------------------------------

FUTURES_EXTENSION = futures()
HSERIES_EXTENSION = hseries()
QSYSTEM_EXTENSION = qsystem()
QUANTUM_EXTENSION = quantum()
RESULT_EXTENSION = result()
ROTATION_EXTENSION = rotation()
Expand All @@ -27,7 +28,7 @@

TKET2_EXTENSIONS = [
FUTURES_EXTENSION,
HSERIES_EXTENSION,
QSYSTEM_EXTENSION,
QUANTUM_EXTENSION,
RESULT_EXTENSION,
ROTATION_EXTENSION,
Expand All @@ -46,15 +47,25 @@ def from_halfturns_unchecked() -> ops.ExtOp:
# ------------------------------------------------------


class MeasureReturnCompiler(CustomInoutCallCompiler):
"""Compiler for the `measure_return` function."""
class InoutMeasureCompiler(CustomInoutCallCompiler):
"""Compiler for the measure functions with an inout qubit
such as the `project_z` function."""

opname: str
ext: he.Extension

def __init__(self, opname: str | None = None, ext: he.Extension | None = None):
self.opname = opname or "Measure"
self.ext = ext or QUANTUM_EXTENSION

def compile_with_inouts(self, args: list[Wire]) -> CallReturnWires:
from guppylang.std._internal.util import quantum_op

[q] = args
[q, bit] = self.builder.add_op(
quantum_op("Measure")(ht.FunctionType([ht.Qubit], [ht.Qubit, ht.Bool]), []),
quantum_op(self.opname, ext=self.ext)(
ht.FunctionType([ht.Qubit], [ht.Qubit, ht.Bool]), []
),
q,
)
return CallReturnWires(regular_returns=[bit], inout_returns=[q])
Expand Down
108 changes: 108 additions & 0 deletions guppylang/std/qsystem/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from typing import no_type_check

from guppylang.decorator import guppy
from guppylang.module import GuppyModule
from guppylang.std import angles
from guppylang.std._internal.compiler.quantum import (
QSYSTEM_EXTENSION,
InoutMeasureCompiler,
)
from guppylang.std._internal.util import quantum_op
from guppylang.std.angles import angle
from guppylang.std.builtins import owned
from guppylang.std.quantum import qubit

qsystem = GuppyModule("qsystem")

qsystem.load(qubit)
qsystem.load_all(angles)


@guppy(qsystem)
@no_type_check
def phased_x(q: qubit, angle1: angle, angle2: angle) -> None:
f1 = float(angle1)
f2 = float(angle2)
_phased_x(q, f1, f2)


@guppy.hugr_op(quantum_op("ZZMax", ext=QSYSTEM_EXTENSION), module=qsystem)
@no_type_check
def zz_max(q1: qubit, q2: qubit) -> None: ...


@guppy(qsystem)
@no_type_check
def zz_phase(q1: qubit, q2: qubit, angle: angle) -> None:
f = float(angle)
_zz_phase(q1, q2, f)


@guppy(qsystem)
@no_type_check
def rz(q: qubit, angle: angle) -> None:
f1 = float(angle)
_rz(q, f1)


@guppy.hugr_op(quantum_op("Measure", ext=QSYSTEM_EXTENSION), module=qsystem)
@no_type_check
def measure(q: qubit @ owned) -> bool: ...


@guppy.custom(InoutMeasureCompiler("MeasureReset", QSYSTEM_EXTENSION), module=qsystem)
@no_type_check
def measure_and_reset(q: qubit) -> bool:
"""MeasureReset operation from the qsystem extension."""


@guppy.hugr_op(quantum_op("Reset", ext=QSYSTEM_EXTENSION), module=qsystem)
@no_type_check
def reset(q: qubit) -> None: ...


# TODO
# @guppy.hugr_op(quantum_op("TryQAlloc", ext=QSYSTEM_EXTENSION), module=qsystem)
# @no_type_check
# def _try_qalloc() -> Option[qubit]:
# ..


@guppy.hugr_op(quantum_op("QFree", ext=QSYSTEM_EXTENSION), module=qsystem)
@no_type_check
def qfree(q: qubit @ owned) -> None: ...


# ------------------------------------------------------
# --------- Internal definitions -----------------------
# ------------------------------------------------------


@guppy.hugr_op(quantum_op("PhasedX", ext=QSYSTEM_EXTENSION), module=qsystem)
@no_type_check
def _phased_x(q: qubit, angle1: float, angle2: float) -> None:
"""PhasedX operation from the qsystem extension.

See `guppylang.std.qsystem.phased_x` for a public definition that
accepts angle parameters.
"""


@guppy.hugr_op(quantum_op("ZZPhase", ext=QSYSTEM_EXTENSION), module=qsystem)
@no_type_check
def _zz_phase(q1: qubit, q2: qubit, angle: float) -> None:
"""ZZPhase operation from the qsystem extension.

See `guppylang.std.qsystem.phased_x` for a public definition that
accepts angle parameters.
"""


@guppy.hugr_op(quantum_op("Rz", ext=QSYSTEM_EXTENSION), module=qsystem)
@no_type_check
def _rz(q: qubit, angle: float) -> None:
"""Rz operation from the qsystem extension.

See `guppylang.std.qsystem.rz` for a public definition that
accepts angle parameters.
"""
68 changes: 68 additions & 0 deletions guppylang/std/qsystem/functional.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from typing import no_type_check

from guppylang.decorator import guppy
from guppylang.module import GuppyModule
from guppylang.std import angles, qsystem
from guppylang.std.angles import angle
from guppylang.std.builtins import owned
from guppylang.std.quantum import qubit

qsystem_functional = GuppyModule("qsystem_functional")

qsystem_functional.load(qubit, qsystem)
qsystem_functional.load_all(angles)


@guppy(qsystem_functional)
@no_type_check
def phased_x(q: qubit @ owned, angle1: angle, angle2: angle) -> qubit:
qsystem.phased_x(q, angle1, angle2)
return q


@guppy(qsystem_functional)
@no_type_check
def zz_phase(q1: qubit @ owned, q2: qubit @ owned, angle: angle) -> tuple[qubit, qubit]:
qsystem.zz_phase(q1, q2, angle)
return q1, q2


@guppy(qsystem_functional)
@no_type_check
def measure_and_reset(q: qubit @ owned) -> tuple[qubit, bool]:
b = qsystem.measure_and_reset(q)
return q, b


@guppy(qsystem_functional)
@no_type_check
def zz_max(q1: qubit @ owned, q2: qubit @ owned) -> tuple[qubit, qubit]:
qsystem.zz_max(q1, q2)
return q1, q2


@guppy(qsystem_functional)
@no_type_check
def rz(q: qubit @ owned, angle: angle) -> qubit:
qsystem.rz(q, angle)
return q


@guppy(qsystem_functional)
@no_type_check
def measure(q: qubit @ owned) -> bool:
result = qsystem.measure(q)
return result


@guppy(qsystem_functional)
@no_type_check
def qfree(q: qubit @ owned) -> None:
qsystem.qfree(q)


@guppy(qsystem_functional)
@no_type_check
def reset(q: qubit @ owned) -> qubit:
qsystem.reset(q)
return q
72 changes: 7 additions & 65 deletions guppylang/std/quantum.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

from guppylang.decorator import guppy
from guppylang.std._internal.compiler.quantum import (
HSERIES_EXTENSION,
MeasureReturnCompiler,
InoutMeasureCompiler,
RotationCompiler,
)
from guppylang.std._internal.util import quantum_op
Expand All @@ -33,17 +32,8 @@ def measure(self: "qubit" @ owned) -> bool:

@guppy
@no_type_check
def measure_return(self: "qubit") -> bool:
return measure_return(self)

@guppy
@no_type_check
def measure_reset(self: "qubit") -> bool:
"""Projective measure and reset without discarding the qubit."""
res = self.measure_return()
if res:
x(self)
return res
def project_z(self: "qubit") -> bool:
return project_z(self)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a comment, no change needed. From this wrapper, it looks like project_z is not exposed directly to the user, so I think it's a nice rename. I wouldn't want users to have to use project_z call for measurements.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh this has been overlooked, measure_return should be removed really. measure_return is a confusing name, so I wanted to replace with project_z. measure is still there as the standard user facing measure function, but it consumes the qubit.


@guppy
@no_type_check
Expand Down Expand Up @@ -106,11 +96,6 @@ def tdg(q: qubit) -> None: ...
def sdg(q: qubit) -> None: ...


@guppy.hugr_op(quantum_op("ZZMax", ext=HSERIES_EXTENSION))
@no_type_check
def zz_max(q1: qubit, q2: qubit) -> None: ...


@guppy.custom(RotationCompiler("Rz"))
@no_type_check
def rz(q: qubit, angle: angle) -> None: ...
Expand Down Expand Up @@ -141,64 +126,21 @@ def toffoli(control1: qubit, control2: qubit, target: qubit) -> None: ...
def dirty_qubit() -> qubit: ...


@guppy.custom(MeasureReturnCompiler())
@guppy.custom(InoutMeasureCompiler())
@no_type_check
def measure_return(q: qubit) -> bool: ...
def project_z(q: qubit) -> bool: ...


@guppy.hugr_op(quantum_op("QFree"))
@no_type_check
def discard(q: qubit @ owned) -> None: ...


@guppy
@no_type_check
def measure(q: qubit @ owned) -> bool:
res = measure_return(q)
discard(q)
return res


@guppy
@no_type_check
def phased_x(q: qubit, angle1: angle, angle2: angle) -> None:
f1 = float(angle1)
f2 = float(angle2)
_phased_x(q, f1, f2)


@guppy
@guppy.hugr_op(quantum_op("MeasureFree"))
@no_type_check
def zz_phase(q1: qubit, q2: qubit, angle: angle) -> None:
f = float(angle)
_zz_phase(q1, q2, f)
def measure(q: qubit @ owned) -> bool: ...


@guppy.hugr_op(quantum_op("Reset"))
@no_type_check
def reset(q: qubit) -> None: ...


# ------------------------------------------------------
# --------- Internal definitions -----------------------
# ------------------------------------------------------


@guppy.hugr_op(quantum_op("PhasedX", ext=HSERIES_EXTENSION))
@no_type_check
def _phased_x(q: qubit, angle1: float, angle2: float) -> None:
"""PhasedX operation from the hseries extension.

See `guppylang.prelude.quantum.phased_x` for a public definition that
accepts angle parameters.
"""


@guppy.hugr_op(quantum_op("ZZPhase", ext=HSERIES_EXTENSION))
@no_type_check
def _zz_phase(q1: qubit, q2: qubit, angle: float) -> None:
"""ZZPhase operation from the hseries extension.

See `guppylang.prelude.quantum.phased_x` for a public definition that
accepts angle parameters.
"""
25 changes: 2 additions & 23 deletions guppylang/std/quantum_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,6 @@ def sdg(q: qubit @ owned) -> qubit:
return q


@guppy(quantum_functional)
@no_type_check
def zz_max(q1: qubit @ owned, q2: qubit @ owned) -> tuple[qubit, qubit]:
quantum.zz_max(q1, q2)
return q1, q2


@guppy(quantum_functional)
@no_type_check
def rz(q: qubit @ owned, angle: angle) -> qubit:
Expand Down Expand Up @@ -141,20 +134,6 @@ def toffoli(
return control1, control2, target


@guppy(quantum_functional)
@no_type_check
def phased_x(q: qubit @ owned, angle1: angle, angle2: angle) -> qubit:
quantum.phased_x(q, angle1, angle2)
return q


@guppy(quantum_functional)
@no_type_check
def zz_phase(q1: qubit @ owned, q2: qubit @ owned, angle: angle) -> tuple[qubit, qubit]:
quantum.zz_phase(q1, q2, angle)
return q1, q2


@guppy(quantum_functional)
@no_type_check
def reset(q: qubit @ owned) -> qubit:
Expand All @@ -164,6 +143,6 @@ def reset(q: qubit @ owned) -> qubit:

@guppy(quantum_functional)
@no_type_check
def measure_return(q: qubit @ owned) -> tuple[qubit, bool]:
b = quantum.measure_return(q)
def project_z(q: qubit @ owned) -> tuple[qubit, bool]:
b = quantum.project_z(q)
return q, b
Loading
Loading