Skip to content

Commit

Permalink
qml.AmplitudeAmplification (#5160)
Browse files Browse the repository at this point in the history
Second block of the Amplitude amplification algorithm toolkit project

Some use-examples:

https://colab.research.google.com/drive/1EUy9aRPAll7plaIBopbDkTQVo4hCGFs_?authuser=1#scrollTo=Bh0r7LMOiyCt

---------

Co-authored-by: soranjh <[email protected]>
Co-authored-by: Thomas R. Bromley <[email protected]>
Co-authored-by: Jay Soni <[email protected]>
Co-authored-by: Diego <[email protected]>
Co-authored-by: soranjh <[email protected]>
  • Loading branch information
6 people authored Mar 15, 2024
1 parent d42f5ee commit c2f9670
Show file tree
Hide file tree
Showing 6 changed files with 558 additions and 9 deletions.
Binary file added doc/_static/templates/subroutines/ampamp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions doc/introduction/templates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ Other useful templates which do not belong to the previous categories can be fou
:description: :doc:`Reflection Operator <../code/api/pennylane.Reflection>`
:figure: _static/templates/subroutines/reflection.png

.. gallery-item::
:description: :doc:`Amplitude Amplification <../code/api/pennylane.AmplitudeAmplification>`
:figure: _static/templates/subroutines/ampamp.png

.. gallery-item::
:description: :doc:`Interferometer <../code/api/pennylane.Interferometer>`
:figure: _static/templates/subroutines/interferometer.png
Expand Down
48 changes: 39 additions & 9 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,8 @@
* Added new function `qml.operation.convert_to_legacy_H` to convert `Sum`, `SProd`, and `Prod` to `Hamiltonian` instances.
[(#5309)](https://github.com/PennyLaneAI/pennylane/pull/5309)

<h3>Improvements 🛠</h3>

* The `qml.is_commuting` function now accepts `Sum`, `SProd`, and `Prod` instances.
[(#5351)](https://github.com/PennyLaneAI/pennylane/pull/5351)

* Operators can now be left multiplied `x * op` by numpy arrays.
[(#5361)](https://github.com/PennyLaneAI/pennylane/pull/5361)

* Create the `qml.Reflection` operator, useful for amplitude amplification and its variants.
[(##5159)](https://github.com/PennyLaneAI/pennylane/pull/5159)
[(#5159)](https://github.com/PennyLaneAI/pennylane/pull/5159)

```python
@qml.prod
Expand All @@ -94,6 +86,44 @@
>>> circuit()
tensor([1.+6.123234e-17j, 0.-6.123234e-17j], requires_grad=True)
```

* The `qml.AmplitudeAmplification` operator is introduced, which is a high-level interface for amplitude amplification and its variants.
[(#5160)](https://github.com/PennyLaneAI/pennylane/pull/5160)

```python
@qml.prod
def generator(wires):
for wire in wires:
qml.Hadamard(wires=wire)

U = generator(wires=range(3))
O = qml.FlipSign(2, wires=range(3))

dev = qml.device("default.qubit")

@qml.qnode(dev)
def circuit():

generator(wires=range(3))
qml.AmplitudeAmplification(U, O, iters=5, fixed_point=True, work_wire=3)

return qml.probs(wires=range(3))

```

```pycon
>>> print(np.round(circuit(), 3))
[0.013, 0.013, 0.91, 0.013, 0.013, 0.013, 0.013, 0.013]

```

<h3>Improvements 🛠</h3>

* The `qml.is_commuting` function now accepts `Sum`, `SProd`, and `Prod` instances.
[(#5351)](https://github.com/PennyLaneAI/pennylane/pull/5351)

* Operators can now be left multiplied `x * op` by numpy arrays.
[(#5361)](https://github.com/PennyLaneAI/pennylane/pull/5361)

* The `molecular_hamiltonian` function calls `PySCF` directly when `method='pyscf'` is selected.
[(#5118)](https://github.com/PennyLaneAI/pennylane/pull/5118)
Expand Down
1 change: 1 addition & 0 deletions pennylane/templates/subroutines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@
from .trotter import TrotterProduct
from .aqft import AQFT
from .reflection import Reflection
from .amplitude_amplification import AmplitudeAmplification
179 changes: 179 additions & 0 deletions pennylane/templates/subroutines/amplitude_amplification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# Copyright 2018-2024 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
This submodule contains the template for Amplitude Amplification.
"""

# pylint: disable-msg=too-many-arguments
import numpy as np
from pennylane.operation import Operation
import pennylane as qml


def _get_fixed_point_angles(iters, p_min):
"""
Returns the angles needed for the fixed-point amplitude amplification algorithm.
The angles are computed using equation (11) of `arXiv:1409.3305v2 <https://arxiv.org/abs/1409.3305>`__.
"""

delta = np.sqrt(1 - p_min)
gamma = np.cos(np.arccos(1 / delta, dtype=np.complex128) / iters, dtype=np.complex128) ** -1

alphas = [
2 * np.arctan(1 / (np.tan(2 * np.pi * j / iters) * np.sqrt(1 - gamma**2)))
for j in range(1, iters // 2 + 1)
]
betas = [-alphas[-j] for j in range(1, iters // 2 + 1)]
return alphas[: iters // 2], betas[: iters // 2]


class AmplitudeAmplification(Operation):
r"""Applies amplitude amplification.
Given a state :math:`|\Psi\rangle = \alpha |\phi\rangle + \beta|\phi^{\perp}\rangle`, this
subroutine amplifies the amplitude of the state :math:`|\phi\rangle` such that
.. math::
\text{A}(U, O)|\Psi\rangle \sim |\phi\rangle.
The implementation of the algorithm is based on [`arXiv:quant-ph/0005055 <https://arxiv.org/abs/quant-ph/0005055>`__].
The template also unlocks advanced techniques such as fixed-point quantum search
[`arXiv:1409.3305 <https://arxiv.org/abs/1409.3305>`__] and oblivious amplitude amplification
[`arXiv:1312.1414 <https://arxiv.org/abs/1312.1414>`__], by reflecting on a subset of wires.
Args:
U (Operator): the operator that prepares the state :math:`|\Psi\rangle`
O (Operator): the oracle that flips the sign of the state :math:`|\phi\rangle` and does nothing to the state :math:`|\phi^{\perp}\rangle`
iters (int): the number of iterations of the amplitude amplification subroutine, default is ``1``
fixed_point (bool): whether to use the fixed-point amplitude amplification algorithm, default is ``False``
work_wire (int): the auxiliary wire to use for the fixed-point amplitude amplification algorithm, default is ``None``
reflection_wires (Wires): the wires to reflect on, default is the wires of ``U``
p_min (int): the lower bound for the probability of success in fixed-point amplitude amplification, default is ``0.9``
Raises:
ValueError: ``work_wire`` must be specified if ``fixed_point == True``.
ValueError: ``work_wire`` must be different from the wires of the oracle ``O``.
**Example**
Amplification of state :math:`|2\rangle` using Grover's algorithm with 3 qubits.
The state :math:`|\Psi\rangle` is constructed as a uniform superposition of basis states.
.. code-block::
@qml.prod
def generator(wires):
for wire in wires:
qml.Hadamard(wires=wire)
U = generator(wires=range(3))
O = qml.FlipSign(2, wires=range(3))
dev = qml.device("default.qubit")
@qml.qnode(dev)
def circuit():
generator(wires=range(3))
qml.AmplitudeAmplification(U, O, iters=5, fixed_point=True, work_wire=3)
return qml.probs(wires=range(3))
.. code-block:: pycon
>>> print(np.round(circuit(),3))
[0.013, 0.013, 0.91, 0.013, 0.013, 0.013, 0.013, 0.013]
"""

def _flatten(self):
data = (self.hyperparameters["U"], self.hyperparameters["O"])
metadata = tuple(
(key, value) for key, value in self.hyperparameters.items() if key not in ["O", "U"]
)
return data, metadata

@classmethod
def _unflatten(cls, data, metadata):
U, O = (data[0], data[1])
hyperparams_dict = dict(metadata)
return cls(U, O, **hyperparams_dict)

def __init__(
self, U, O, iters=1, fixed_point=False, work_wire=None, p_min=0.9, reflection_wires=None
):
self._name = "AmplitudeAmplification"
if reflection_wires is None:
reflection_wires = U.wires

if fixed_point and work_wire is None:
raise qml.wires.WireError("work_wire must be specified if fixed_point == True.")

if fixed_point and len(O.wires + qml.wires.Wires(work_wire)) == len(O.wires):
raise ValueError("work_wire must be different from the wires of O.")

if fixed_point:
wires = U.wires + qml.wires.Wires(work_wire)
else:
wires = U.wires

self.hyperparameters["U"] = U
self.hyperparameters["O"] = O
self.hyperparameters["iters"] = iters
self.hyperparameters["fixed_point"] = fixed_point
self.hyperparameters["work_wire"] = work_wire
self.hyperparameters["p_min"] = p_min
self.hyperparameters["reflection_wires"] = qml.wires.Wires(reflection_wires)

super().__init__(wires=wires)

# pylint:disable=arguments-differ
@staticmethod
def compute_decomposition(**kwargs):
U = kwargs["U"]
O = kwargs["O"]
iters = kwargs["iters"]
fixed_point = kwargs["fixed_point"]
work_wire = kwargs["work_wire"]
p_min = kwargs["p_min"]
reflection_wires = kwargs["reflection_wires"]

ops = []

if fixed_point:
alphas, betas = _get_fixed_point_angles(iters, p_min)

for iter in range(iters // 2):
ops.append(qml.Hadamard(wires=work_wire))
ops.append(qml.ctrl(O, control=work_wire))
ops.append(qml.Hadamard(wires=work_wire))
ops.append(qml.PhaseShift(betas[iter], wires=work_wire))
ops.append(qml.Hadamard(wires=work_wire))
ops.append(qml.ctrl(O, control=work_wire))
ops.append(qml.Hadamard(wires=work_wire))

ops.append(qml.Reflection(U, -alphas[iter], reflection_wires=reflection_wires))
else:
for _ in range(iters):
ops.append(O)
ops.append(qml.Reflection(U, np.pi, reflection_wires=reflection_wires))

return ops

def queue(self, context=qml.QueuingManager):
for op in [self.hyperparameters["U"], self.hyperparameters["O"]]:
context.remove(op)
context.append(self)
return self
Loading

0 comments on commit c2f9670

Please sign in to comment.