Skip to content

Commit

Permalink
test: Add adaptive quantum phase estimation examples (#352)
Browse files Browse the repository at this point in the history
Closes #299
  • Loading branch information
mark-koch authored Aug 5, 2024
1 parent 1b64cd6 commit 60d921a
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 1 deletion.
Empty file added examples/__init__.py
Empty file.
107 changes: 107 additions & 0 deletions examples/random_walk_qpe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""
Implementation of the adaptive random walk phase estimation algorithm from
https://arxiv.org/abs/2208.04526.
The example Hamiltonian and numbers are taken from https://arxiv.org/abs/2206.12950.
"""

import math
from collections.abc import Callable

from guppylang.decorator import guppy
from guppylang.module import GuppyModule
from guppylang.prelude.builtins import result, py
from guppylang.prelude.quantum import qubit

import guppylang.prelude.quantum as quantum
from guppylang.prelude.quantum import h, discard, cx, x, measure, rz

module = GuppyModule("test")
module.load(quantum)

sqrt_e = math.sqrt(math.e)
sqrt_e_div = math.sqrt((math.e - 1) / math.e)


@guppy(module)
def random_walk_phase_estimation(
eigenstate: Callable[[], qubit],
controlled_oracle: Callable[[qubit, qubit, float], tuple[qubit, qubit]],
num_iters: int,
reset_rate: int,
mu: float,
sigma: float,
) -> float:
"""Performs the random walk phase estimation algorithm on a single qubit for
some Hamiltonian H.
Arguments:
eigenstate: Function preparing the eigenstate of e^itH
controlled_oracle: The oracle circuit for a controlled e^itH
num_iters: Number of iterations to run the algorithm for
reset_rate: Reset the eigenstate every x iterations
mu: Initial mean for the eigenvalue estimate
sigma: Initial standard deviation for the eigenvalue estimate
"""
tgt = eigenstate()
i = 0
while i < num_iters:
aux = h(qubit())
t = 1 / sigma
aux = rz(h(aux), (sigma - mu) * t)
aux, tgt = controlled_oracle(aux, tgt, t)
if measure(h(aux)):
mu += sigma / py(sqrt_e)
else:
mu -= sigma / py(sqrt_e)
sigma *= py(sqrt_e_div)

# Reset the eigenstate every few iterations to increase the fidelity of
# the algorithm
if i % reset_rate == 0:
discard(tgt)
tgt = eigenstate()
i += 1
discard(tgt)
return mu


@guppy(module)
def example_controlled_oracle(
q1: qubit, q2: qubit, t: float
) -> tuple[qubit, qubit]:
"""A controlled e^itH gate for the example Hamiltonian H = -0.5 * Z"""
# This is just a controlled rz gate
angle = -0.5 * t
q2 = rz(q2, angle / 2)
q1, q2 = cx(q1, q2)
q2 = rz(q2, -angle / 2)
return cx(q1, q2)


@guppy(module)
def example_eigenstate() -> qubit:
"""The eigenstate of e^itH for the example Hamiltonian H = -0.5 * Z"""
# This is just |1>
return x(qubit())


@guppy(module)
def main() -> int:
num_iters = 24 # To avoid underflows
reset_rate = 8
mu = py(sqrt_e)
sigma = py(sqrt_e_div)
eigenvalue = random_walk_phase_estimation(
example_eigenstate,
example_controlled_oracle,
num_iters,
reset_rate,
mu,
sigma,
)
result(0, eigenvalue) # Expected outcome is 0.5
return 0


hugr = module.compile()
2 changes: 1 addition & 1 deletion guppylang/prelude/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ def __nat__(self: float) -> nat: ...
def __ne__(self: float, other: float) -> bool: ...

@guppy.hugr_op(builtins, float_op("fneg"), CoercingChecker())
def __neg__(self: float, other: float) -> float: ...
def __neg__(self: float) -> float: ...

@guppy.custom(
builtins, checker=DunderChecker("__float__"), higher_order_value=False
Expand Down
7 changes: 7 additions & 0 deletions tests/integration/test_examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""Tests validating the files in the `examples` directory."""


def test_random_walk_qpe(validate):
from examples.random_walk_qpe import hugr

validate(hugr)

0 comments on commit 60d921a

Please sign in to comment.