Skip to content

Commit

Permalink
Merge branch 'master' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Sep 18, 2024
2 parents f3831d0 + c833d18 commit 1d8bb22
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 0 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions demonstrations/tutorial_qsvt_hardware.metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"title": "How to implement QSVT on hardware",
"authors": [
{
"username": "KetPuntoG"
}
],
"dateOfPublication": "2024-09-18T00:00:00+00:00",
"dateOfLastModification": "2024-09-18T00:00:00+00:00",
"categories": [
"Algorithms",
"Quantum Computing",
"How-to"
],
"tags": [],
"previewImages": [
{
"type": "thumbnail",
"uri": "/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_qsvt_hardware.png"
},
{
"type": "large_thumbnail",
"uri": "/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_qsvt_hardware.png"
}
],
"seoDescription": "Learn how to implement QSVT on hardware.",
"doi": "",
"canonicalURL": "/qml/demos/tutorial_qsvt_hardware",
"references": [
],
"basedOnPapers": [],
"referencedByPapers": [],
"relatedContent": [
{
"type": "demonstration",
"id": "tutorial_intro_qsvt",
"weight": 1.0
},
{
"type": "demonstration",
"id": "tutorial_apply_qsvt",
"weight": 1.0
}

]
}
167 changes: 167 additions & 0 deletions demonstrations/tutorial_qsvt_hardware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
r"""How to implement QSVT on hardware
=======================================
The :doc:`quantum singular value transform (QSVT) </demos/tutorial_intro_qsvt>`
is a quantum algorithm that allows us to perform polynomial
transformations on matrices or operators, and it is rapidly becoming
a go-to algorithm for :doc:`quantum application research </demos/tutorial_apply_qsvt>`
in the `ISQ era <https://pennylane.ai/blog/2023/06/from-nisq-to-isq/>`__.
In this how-to guide, we will show how we can implement the QSVT
subroutine in a hardware-compatible way, taking your application research
to the next level.
.. figure:: ../_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_qsvt_hardware.png
:align: center
:width: 50%
:target: javascript:void(0)
Calculating angles
------------------
Our goal is to apply a polynomial transformation to a given Hamiltonian, i.e., :math:`p(\mathcal{H})`. To achieve this, we must consider the two
fundamental components of the QSVT algorithm:
- **Projection angles**: A list of angles that will determine the coefficients of the polynomial to be applied.
- **Block encoding**: The strategy used to encode the Hamiltonian. We will use the :doc:`linear combinations of unitaries <demos/tutorial_lcu_blockencoding>` approach via the PennyLane :class:`~.qml.PrepSelPrep` operation.
Calculating angles is not a trivial task, but there are tools such as `pyqsp <https://github.com/ichuang/pyqsp/tree/master/pyqsp>`_ that do the job for us.
For instance, to find the angles to apply the polynomial :math:`p(x) = -x + \frac{x^3}{2}+ \frac{x^5}{2}`, we can run this code:
.. code-block:: python
from pyqsp.angle_sequence import QuantumSignalProcessingPhases
import numpy as np
# Define the polynomial, the coefficients are in the order of the polynomial degree.
poly = np.array([0,-1, 0, 0.5, 0 , 0.5])
ang_seq = QuantumSignalProcessingPhases(poly, signal_operator="Wx")
The angles obtained after execution are as follows:
"""

ang_seq = [
-1.5115007723754004,
0.6300762184670975,
0.8813995564082947,
-2.2601930971815003,
3.7716688720568885,
0.059295554419495855,
]

######################################################################
# We use these angles to apply the polynomial transformation.
# However, we are not finished yet: these angles have been calculated following the "Wx"
# convention [#unification]_, while :class:`~.qml.PrepSelPrep` follows a different one. Moreover, the angles obtained in the
# context of QSP (the ones given by ``pyqsp``) are not the same as the ones we have to use in QSVT. That is why
# we must transform the angles:

import numpy as np


def convert_angles(angles):
num_angles = len(angles)
update_vals = np.zeros(num_angles)

update_vals[0] = 3 * np.pi / 4 - (3 + len(angles) % 4) * np.pi / 2
update_vals[1:-1] = np.pi / 2
update_vals[-1] = -np.pi / 4

return angles + update_vals


angles = convert_angles(ang_seq)
print(angles)

######################################################################
# Using these angles, we can now start working with the template.
#
# QSVT on hardware
# -----------------
#
# The :class:`~.qml.QSVT` template expects two inputs. The first one is the block encoding operator, :class:`~.qml.PrepSelPrep`,
# and the second one is a set of projection operators, :class:`~.qml.PCPhase`, that encode the angles properly.
# We will see how to apply them later, but first let's define
# a Hamiltonian and manually apply the polynomial of interest:

import pennylane as qml
from numpy.linalg import matrix_power as mpow

coeffs = np.array([0.2, -0.7, -0.6])
coeffs /= np.linalg.norm(coeffs, ord=1) # Normalize the coefficients

obs = [qml.X(3), qml.X(3) @ qml.Z(4), qml.Z(3) @ qml.Y(4)]

H = qml.dot(coeffs, obs)

H_mat = qml.matrix(H, wire_order=[3, 4])

# We calculate p(H) = -H + 0.5 * H^3 + 0.5 * H^5
H_poly = -H_mat + 0.5 * mpow(H_mat, 3) + 0.5 * mpow(H_mat, 5)

print(np.round(H_poly, 4))

######################################################################
# Now that we know what the target result is, let's see how to apply the polynomial with a quantum circuit instead.
# We start by defining the proper input operators for the :class:`~.qml.QSVT` template.

# We need |log2(len(coeffs))| = 2 control wires to encode the Hamiltonian
control_wires = [1, 2]
block_encode = qml.PrepSelPrep(H, control=control_wires)

projectors = [
qml.PCPhase(angles[i], dim=2 ** len(H.wires), wires=control_wires + H.wires)
for i in range(len(angles))
]


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

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

qml.Hadamard(0)
qml.ctrl(qml.QSVT, control=0, control_values=[1])(block_encode, projectors)
qml.ctrl(qml.adjoint(qml.QSVT), control=0, control_values=[0])(block_encode, projectors)
qml.Hadamard(0)

return qml.state()


matrix = qml.matrix(circuit, wire_order=[0] + control_wires + H.wires)()
print(np.round(matrix[: 2 ** len(H.wires), : 2 ** len(H.wires)], 4))

######################################################################
# The matrix obtained using QSVT is the same as the one obtained by applying the polynomial
# directly to the Hamiltonian! That means the circuit is encoding :math:`p(\mathcal{H})` correctly.
# The great advantage of this approach is that all the building blocks used in the circuit can be
# decomposed into basic gates easily, allowing this circuit
# to be easily executed on hardware devices with PennyLane.
#
# Please also note that QSVT encodes the desired polynomial :math:`p(\mathcal{H})` as well as
# a polynomial :math:`i q(\mathcal{H})`. To isolate :math:`p(\mathcal{H})`, we have used an auxiliary qubit and considered that
# the sum of a complex number and its conjugate gives us twice its real part. We
# recommend :doc:`this demo </demos/tutorial_apply_qsvt>` to learn more about the structure
# of the circuit.
#
# Conclusion
# ----------
# In this brief how-to we demonstrated applying QSVT on a sample Hamiltonian. Note that the algorithm is sensitive to
# the block-encoding method, so please make sure that the projection angles are converted to the proper format.
# This how-to serves as a guide for running your own workflows and experimenting with more advanced Hamiltonians and polynomial functions.
#
# References
# ----------
#
# .. [#unification]
#
# John M. Martyn, Zane M. Rossi, Andrew K. Tan, Isaac L. Chuang.
# "A Grand Unification of Quantum Algorithms".
# `arXiv preprint arXiv:2105.02859 <https://arxiv.org/abs/2105.02859>`__.
#
# About the author
# ----------------
#

0 comments on commit 1d8bb22

Please sign in to comment.