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: add qubit discard/measure methods #580

Merged
merged 5 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
128 changes: 128 additions & 0 deletions guppylang/prelude/quantum.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,84 +26,209 @@ def __new__() -> "qubit":
reset(q)
return q

@guppy
@no_type_check
def h(self: "qubit") -> None:
h(self)

@guppy
@no_type_check
def cz(self: "qubit", target: "qubit") -> None:
cz(self, target)

@guppy
@no_type_check
def cx(self: "qubit", target: "qubit") -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would suggesttarget.cx(control) instead,
so the n-controlled cases keep the same structure.

target.toffoli(control0, control1)
target.ncx(*controls)

Copy link
Contributor

Choose a reason for hiding this comment

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

Whichever way round it is, I see a lot of potential for bugs caused by people getting it the wrong way round.
In general I'm not so keen on forcing multi-qubit operations to have a "distinguished" qubit in this way: in general there's no natural way to select which qubit it should be.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that's very valid. How about we restrict it a specific set of special single qubit operations: alloc (already the case), discard, measure (non destructive), reset, and any variants of those above (e.g. measure_reset, destructive measure). These special set can be implemented in terms of the existing inout functions as in this PR currently.

Copy link
Contributor

Choose a reason for hiding this comment

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

Happy with that.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

cx(self, target)

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

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

@guppy
@no_type_check
def measure_reset(self: "qubit") -> bool:
res = self.measure_return()
if res:
self.x()
return res

@guppy
@no_type_check
def discard(self: "qubit" @ owned) -> None:
discard(self)

@guppy
@no_type_check
def x(self: "qubit") -> None:
x(self)

@guppy
@no_type_check
def y(self: "qubit") -> None:
y(self)

@guppy
@no_type_check
def z(self: "qubit") -> None:
z(self)

@guppy
@no_type_check
def t(self: "qubit") -> None:
t(self)

@guppy
@no_type_check
def s(self: "qubit") -> None:
s(self)

@guppy
@no_type_check
def tdg(self: "qubit") -> None:
tdg(self)

@guppy
@no_type_check
def sdg(self: "qubit") -> None:
sdg(self)

@guppy
@no_type_check
def rz(self: "qubit", angle: angle) -> None:
rz(self, angle)

@guppy
@no_type_check
def rx(self: "qubit", angle: angle) -> None:
rx(self, angle)

@guppy
@no_type_check
def ry(self: "qubit", angle: angle) -> None:
ry(self, angle)

@guppy
@no_type_check
def crz(self: "qubit", target: "qubit", angle: angle) -> None:
crz(self, target, angle)

# TODO toffoli doesn't make much sense with two controls

# @guppy
# @no_type_check
# def toffoli(self: "qubit", control2: "qubit", target: "qubit") -> None:
# toffoli(self, control2, target)

@guppy
@no_type_check
def zz_max(self: "qubit", q2: "qubit") -> None:
zz_max(self, q2)


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


@guppy.hugr_op(quantum_op("CZ"))
@no_type_check
def cz(control: qubit, target: qubit) -> None: ...


@guppy.hugr_op(quantum_op("CY"))
@no_type_check
def cy(control: qubit, target: qubit) -> None: ...


@guppy.hugr_op(quantum_op("CX"))
@no_type_check
def cx(control: qubit, target: qubit) -> None: ...


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


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


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


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


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


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


@guppy.hugr_op(quantum_op("Sdg"))
@no_type_check
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: ...


@guppy.custom(RotationCompiler("Rx"))
@no_type_check
def rx(q: qubit, angle: angle) -> None: ...


@guppy.custom(RotationCompiler("Ry"))
@no_type_check
def ry(q: qubit, angle: angle) -> None: ...


@guppy.custom(RotationCompiler("CRz"))
@no_type_check
def crz(control: qubit, target: qubit, angle: angle) -> None: ...


@guppy.hugr_op(quantum_op("Toffoli"))
@no_type_check
def toffoli(control1: qubit, control2: qubit, target: qubit) -> None: ...


@guppy.hugr_op(quantum_op("QAlloc"))
@no_type_check
def dirty_qubit() -> qubit: ...


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


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


Expand Down Expand Up @@ -131,6 +256,7 @@ def zz_phase(q1: qubit, q2: qubit, angle: angle) -> None:


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


Expand All @@ -140,6 +266,7 @@ def reset(q: qubit) -> None: ...


@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.

Expand All @@ -149,6 +276,7 @@ def _phased_x(q: qubit, angle1: float, angle2: float) -> None:


@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.

Expand Down
Loading
Loading