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

LCU + Block encoding demo #888

Merged
merged 49 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
50fe29c
First draft of text sans code
ixfoduap Aug 11, 2023
53cd64b
fix typo to build preview
DSGuala Aug 17, 2023
9c250eb
Merge branch 'master' into lcu_blockencoding
DSGuala Aug 17, 2023
40f3537
Apply suggestions from code review
ixfoduap Aug 17, 2023
cc63a4a
First complete draft sans images
ixfoduap Aug 22, 2023
32e0de7
Update demonstrations/tutorial_lcu_blockencoding.py
ixfoduap Aug 23, 2023
e6b79cc
small edits
ixfoduap Aug 28, 2023
78c0ad2
Merge branch 'lcu_blockencoding' of https://github.com/PennyLaneAI/qm…
ixfoduap Aug 28, 2023
d15aa5b
First polished draft
ixfoduap Aug 28, 2023
cfad768
Merge branch 'master' into lcu_blockencoding
DSGuala Aug 29, 2023
4c64eea
update code to work with latest release
DSGuala Aug 29, 2023
6036659
change PL version, add placeholder images
DSGuala Aug 31, 2023
fae6234
update poetry.lock as suggested by CI
DSGuala Aug 31, 2023
1dfbb7c
Fix image paths
DSGuala Aug 31, 2023
bc5a30a
fix image paths again
DSGuala Aug 31, 2023
1271fe4
Merge branch 'master' into lcu_blockencoding
DSGuala Aug 31, 2023
1e00920
Apply suggestions from code review
DSGuala Sep 7, 2023
21717cc
don't steal credit
DSGuala Sep 7, 2023
e4d352a
add new images
DSGuala Sep 7, 2023
e42db64
Merge branch 'master' into lcu_blockencoding
DSGuala Sep 7, 2023
0db85b3
move images and change paths
DSGuala Sep 7, 2023
f301af9
Merge branch 'master' into lcu_blockencoding
DSGuala Sep 8, 2023
82cc912
Apply suggestions from code review
DSGuala Sep 8, 2023
a9cbb9a
address review comments
DSGuala Sep 8, 2023
dfa3644
Merge branch 'master' into lcu_blockencoding
Jaybsoni Sep 28, 2023
5d67fc1
Added projector LCU
Jaybsoni Sep 28, 2023
bed99c4
Merge branch 'dev' into lcu_blockencoding
DSGuala Oct 4, 2023
a92e1c5
revert changes to poetry.lock
DSGuala Oct 4, 2023
cf6f7d7
fix example to build
Jaybsoni Oct 5, 2023
df6ab35
updates, address comments
DSGuala Oct 11, 2023
47c6e7f
fixes and copyediting
DSGuala Oct 11, 2023
fc7fc72
Merge branch 'lcu_blockencoding' of https://github.com/PennyLaneAI/qm…
DSGuala Oct 11, 2023
0a910c2
update equations
DSGuala Oct 13, 2023
75ecf85
add small corrections
soranjh Oct 13, 2023
4da576a
update applications
soranjh Oct 17, 2023
096b8c7
add review comments
soranjh Oct 17, 2023
fd9c61f
add review comments
soranjh Oct 17, 2023
82840af
add review comments
soranjh Oct 19, 2023
7214065
add review comments
soranjh Oct 19, 2023
8c3fc6d
Update demonstrations/tutorial_lcu_blockencoding.py
KetpuntoG Oct 20, 2023
fdb3dd5
Update demonstrations/tutorial_lcu_blockencoding.py
KetpuntoG Oct 20, 2023
71da7cd
Update demonstrations/tutorial_lcu_blockencoding.py
KetpuntoG Oct 20, 2023
5bb2737
Update demonstrations/tutorial_lcu_blockencoding.py
KetpuntoG Oct 20, 2023
a129a3f
Update demonstrations/tutorial_lcu_blockencoding.metadata.json
KetpuntoG Oct 20, 2023
1835bb7
Merge branch 'dev' into lcu_blockencoding
KetpuntoG Oct 20, 2023
131e367
Merge branch 'dev' into lcu_blockencoding
KetpuntoG Oct 20, 2023
b53172a
links to codebook + remove meta in .py
KetpuntoG Oct 20, 2023
f9eab6e
correct typos
soranjh Oct 23, 2023
82ee2bf
update date + small typo in other demo
KetpuntoG Oct 26, 2023
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demonstrations/lcu_blockencoding/schematic.png
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.
60 changes: 60 additions & 0 deletions demonstrations/tutorial_lcu_blockencoding.metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"title": "Linear combination of unitaries and block encodings",
"authors": [
{
"id": "juan_miguel_arrazola"
},
{
"id": "diego_guala"
},
{
"id": "jay_soni"
}
],
"dateOfPublication": "2023-08-31T00:00:00+00:00",
"dateOfLastModification": "2023-08-31T00:00:00+00:00",
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
"categories": [
"Algorithms",
"Quantum Computing"
],
"tags": [],
"previewImages": [
{
"type": "thumbnail",
"uri": "/_images/thumbnail_lcu_blockencoding.png"
},
{
"type": "large_thumbnail",
"uri": "/_static/large_demo_thumbnails/thumbnail_large_lcu_blockencoding.png"
}
],
"seoDescription": "Master the basics of LCUs and their applications",
"doi": "",
"canonicalURL": "/qml/demos/tutorial_lcu_blockencoding",
"references": [
{
"id": "qsvt",
"type": "article",
"title": "Quantum singular value transformation and beyond: exponential improvements for quantum matrix arithmetics",
"authors": "András Gilyén, Yuan Su, Guang Hao Low, Nathan Wiebe",
"year": "2019",
"publisher": "",
"journal": "",
"url": "https://dl.acm.org/doi/abs/10.1145/3313276.3316366"
}
],
"basedOnPapers": [],
"referencedByPapers": [],
"relatedContent": [
{
"type": "demonstration",
"id": "tutorial_intro_qsvt",
"weight": 1.0
},
{
"type": "demonstration",
"id": "tutorial_apply_qsvt",
"weight": 1.0
}
]
}
287 changes: 287 additions & 0 deletions demonstrations/tutorial_lcu_blockencoding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
r"""Linear combination of unitaries and block encodings
=============================================================

.. meta::
:property="og:description": Master the basics of LCUs and their applications
:property="og:image": https://pennylane.ai/qml/_images/thumbnail_lcu_blockencoding.png

.. related::

tutorial_intro_qsvt Intro to QSVT

*Author: Juan Miguel Arrazola, Diego Guala, and Jay Soni — Posted: August, 2023.*
soranjh marked this conversation as resolved.
Show resolved Hide resolved

If I (Juan Miguel) had to summarize quantum computing in one sentence, it would be this: information is
soranjh marked this conversation as resolved.
Show resolved Hide resolved
encoded in quantum states and processed using `unitary operations <https://en.wikipedia.org/wiki/Unitary_operator>`_.
soranjh marked this conversation as resolved.
Show resolved Hide resolved
The challenge of quantum algorithms is to design and build these unitaries to perform interesting and
useful tasks. My colleague `Nathan Wiebe <https://scholar.google.ca/citations?user=DSgKHOQAAAAJ&hl=en>`_
soranjh marked this conversation as resolved.
Show resolved Hide resolved
once told me that some of his early research was motivated by a simple
question: Quantum computers can implement products of unitaries --- after all
soranjh marked this conversation as resolved.
Show resolved Hide resolved
soranjh marked this conversation as resolved.
Show resolved Hide resolved
that's how we build circuits from a `universal gate set <https://en.wikipedia.org/wiki/Quantum_logic_gate#Universal_quantum_gates>`_.
soranjh marked this conversation as resolved.
Show resolved Hide resolved
What about **sums of unitaries**? 🤔
soranjh marked this conversation as resolved.
Show resolved Hide resolved

In this tutorial you will learn the basics of one of the most versatile tools in quantum algorithms:
soranjh marked this conversation as resolved.
Show resolved Hide resolved
linear combinations of unitaries; or LCUs for short. You will also understand how to
soranjh marked this conversation as resolved.
Show resolved Hide resolved
use LCUs to create another powerful building block of quantum algorithms: block encodings.
Among their many uses, they allow us to transform quantum states by non-unitary operators.
Block encodings are useful in a variety of contexts, perhaps most famously in
soranjh marked this conversation as resolved.
Show resolved Hide resolved
`qubitization <https://arxiv.org/abs/1610.06546>`_ and the `quantum
singular value transformation (QSVT) <https://pennylane.ai/qml/demos/tutorial_intro_qsvt>`_.

|

.. figure:: ../demonstrations/lcu_blockencoding/thumbnail_lcu_blockencoding.png
:align: center
:width: 50%
:target: javascript:void(0)

|

LCUs
----
Linear combinations of unitaries are straightforward --- it’s already explained in the name: we
decompose operators as a weighted sum of unitaries. Mathematically, this means expresssing
soranjh marked this conversation as resolved.
Show resolved Hide resolved
an operator :math:`A` in terms of coefficients :math:`\alpha_{k}` and unitaries :math:`U_{k}` as

.. math:: A = \sum_{k=0}^{N-1} \alpha_k U_k.

A general way to build LCUs is to employ properties of the **Pauli basis**.
This is the set of all products of Pauli matrices :math:`{I, X, Y, Z}`. It forms a complete basis
soranjh marked this conversation as resolved.
Show resolved Hide resolved
for the space of operators acting on :math:`n` qubits. Thus any operator can be expressed in the Pauli basis,
soranjh marked this conversation as resolved.
Show resolved Hide resolved
which immediately gives an LCU decomposition. PennyLane allows you to decompose any matrix in the Pauli basis using the
soranjh marked this conversation as resolved.
Show resolved Hide resolved
:func:`~.pennylane.pauli_decompose` function. The coefficients :math:`\alpha_k` and the unitaries
ikurecic marked this conversation as resolved.
Show resolved Hide resolved
:math:`U_k` from the decomposition can be accessed directly from the result. We show how to do this
in the code below for a simple example.

"""
import numpy as np
import pennylane as qml

a = 0.25
b = 0.75

# matrix to be decomposed
A = np.array(
[[a, 0, 0, b],
[0, -a, b, 0],
[0, b, a, 0],
[b, 0, 0, -a]]
)

LCU = qml.pauli_decompose(A)

print(f"LCU decomposition:\n {LCU}")
print(f"Coefficients:\n {LCU.coeffs}")
print(f"Unitaries:\n {LCU.ops}")


##############################################################################
# PennyLane uses a smart Pauli decomposition based on vectorizing the matrix and exploiting properties of
# the `Walsh-Hadamard transform <https://en.wikipedia.org/wiki/Hadamard_transform>`_,
soranjh marked this conversation as resolved.
Show resolved Hide resolved
# but the cost still scales as ~ :math:`O(n 4^n)` for :math:`n` qubits. Be careful.
soranjh marked this conversation as resolved.
Show resolved Hide resolved
#
# It's good to remember that many types of Hamiltonians are already compactly expressed
# in the Pauli basis, for example in various `Ising models <https://en.wikipedia.org/wiki/Ising_model>`_
# and molecular Hamiltonians using the `Jordan-Wigner transformation <https://en.wikipedia.org/wiki/Jordan%E2%80%93Wigner_transformation>`_.
soranjh marked this conversation as resolved.
Show resolved Hide resolved
# This is very useful since we get an LCU decomposition for free.
#
# Block Encodings
# ---------------
# Going from an LCU to a quantum circuit that applies the associated operator is also straightforward
# once you know the trick: to prepare, select, and unprepare.
#
# Starting from the LCU decomposition :math:`A = \sum_{k=0}^{N-1} \alpha_k U_k` with positive, real coefficients, we define the prepare
# (PREP) operator:
#
# .. math:: \text{PREP}|0\rangle = \sum_k \sqrt{\frac{|\alpha|_k}{\lambda}}|k\rangle,
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved
#
# and the select (SEL) operator:
#
# .. math:: \text{SEL}|k\rangle |\psi\rangle = |k\rangle U_k |\psi\rangle.
#
# They are aptly named: PREP prepares a state whose amplitudes
# are determined by the coefficients of the LCU, and SEL selects which unitary is applied.
#
# .. note::
#
# Some important details about the equations above:
#
# * :math:`\lambda` is a normalization constant, defined as :math:`\lambda = \sum_k |\alpha_k|`.
soranjh marked this conversation as resolved.
Show resolved Hide resolved
# * :math:`SEL` acts this way on any state :math:`|\psi\rangle`
# * We are using :math:`|0\rangle` as shorthand to denote the all-zero state for multiple qubits.
#
# The final trick is to combine PREP and SEL to make :math:`A` appear 🪄:
soranjh marked this conversation as resolved.
Show resolved Hide resolved
#
# .. math:: \langle 0| \text{PREP}^\dagger \cdot \text{SEL} \cdot \text{PREP} |0\rangle|\psi\rangle = A/\lambda |\psi\rangle.
soranjh marked this conversation as resolved.
Show resolved Hide resolved
#
# If you're up for it, it's illuminating to go through the math and show how :math:`A` comes out on the right
# side of the equation.
# (Tip: calculate the action of :math:`\text{PREP}^\dagger` on :math:`\langle 0|`, not on the output
# state after :math:`\text{SEL} \cdot \text{PREP}`).
#
# Otherwise, the intuitive way to understand this equation is that we apply PREP, SEL, and then invert PREP. If
# we measure :math:`|0\rangle` in the auxiliary qubits, the input state :math:`|\psi\rangle` will be transformed by
# :math:`A` (up to normalization). The figure below shows this as a circuit with four unitaries in SEL.
#
# |
#
# .. figure:: ../demonstrations/lcu_blockencoding/schematic.png
# :align: center
# :width: 50%
# :target: javascript:void(0)
#
# |
#
# The circuit
#
# .. math:: U = \text{PREP}^\dagger \cdot \text{SEL} \cdot \text{PREP},
soranjh marked this conversation as resolved.
Show resolved Hide resolved
#
# is a **block encoding** of :math:`A`, up to normalization. The reason for this name is that if we write :math:`U`
# as a matrix, the operator :math:`A` is encoded inside a block of :math:`U` as
#
# .. math:: U = \begin{bmatrix} A & \cdot \\ \cdot & \cdot \end{bmatrix}.
#
# This block is defined by the subspace of all states where the auxiliary qubits are in state
# :math:`|0\rangle`.
#
#
# PennyLane supports direct implementation of `prepare <https://docs.pennylane.ai/en/stable/code/api/pennylane.StatePrep.html>`_
# and `select <https://docs.pennylane.ai/en/stable/code/api/pennylane.Select.html>`_
soranjh marked this conversation as resolved.
Show resolved Hide resolved
# operators. We'll go through them individually and use them to construct a block encoding circuit.
# Prepare circuits can be constructed using the :class:`~.pennylane.StatePrep` operation, which takes
ikurecic marked this conversation as resolved.
Show resolved Hide resolved
# the normalized target state as input:

dev1 = qml.device("default.qubit", wires=1)

# normalized square roots of coefficients
alphas = (np.sqrt(LCU.coeffs) / np.linalg.norm(np.sqrt(LCU.coeffs)))


@qml.qnode(dev1)
def prep_circuit():
qml.StatePrep(alphas, wires=0)
return qml.state()


print("Target state: ", alphas)
print("Output state: ", np.real(prep_circuit()))

##############################################################################
# Similarly, select circuits can be implemented using :class:`~.pennylane.Select`, which takes the
# target unitaries as input. We specify the control wires directly, but the system wires are inherited
# from the unitaries. Since :func:`~.pennylane.pauli_decompose` uses a canonical wire ordering, we
soranjh marked this conversation as resolved.
Show resolved Hide resolved
# first map the wires to those used for the system register in our circuit:

dev2 = qml.device("default.qubit", wires=3)
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

# unitaries
ops = LCU.ops
# relabeling wires 0 --> 1, and 1 --> 2
soranjh marked this conversation as resolved.
Show resolved Hide resolved
unitaries = [qml.map_wires(op, {0: 1, 1: 2}) for op in ops]


@qml.qnode(dev2)
DSGuala marked this conversation as resolved.
Show resolved Hide resolved
def sel_circuit(qubit_value):
qml.BasisState(qubit_value, wires=0)
qml.Select(unitaries, control=0)
return qml.expval(qml.PauliZ(2))

print(qml.draw(sel_circuit)([0]))
soranjh marked this conversation as resolved.
Show resolved Hide resolved
##############################################################################
# Based on the controlled operations, the circuit above will flip the measured qubit
# if the input is :math:`|1\rangle` and leave it unchanged if the
# input is :math:`|0\rangle`. The output expecation values correspond to these states:
soranjh marked this conversation as resolved.
Show resolved Hide resolved

print('Expectation value for input |0>:', sel_circuit([0]))
print('Expectation value for input |1>:', sel_circuit([1]))

##############################################################################
# We can now combine these to construct a full LCU circuit. Here we make use of the
# :func:`~.pennylane.adjoint` function as a convenient way to invert the prepare circuit. We have
# chosen an input matrix that is already normalized, so it can be seen appearing directly in the
# top-left block of the unitary describing the full circuit --- the mark of a successful block
# encoding.


@qml.qnode(dev2)
def lcu_circuit(): # block_encode
# PREP
qml.StatePrep(alphas, wires=0)

# SEL
qml.Select(unitaries, control=0)

# PREP_dagger
qml.adjoint(qml.StatePrep(alphas, wires=0))
return qml.state()


output_matrix = qml.matrix(lcu_circuit)()
print("A:\n", A, "\n")
print("Block-encoded A:\n")
print(np.real(np.round(output_matrix,2)))

##############################################################################
soranjh marked this conversation as resolved.
Show resolved Hide resolved
# Application: projectors
soranjh marked this conversation as resolved.
Show resolved Hide resolved
# -----------------------
# Suppose we wanted to project our quantum state :math:`|\psi\rangle` onto the state
# :math:`|\phi\rangle`. We could accomplish this by applying the projector
# :math:`| \phi \rangle\langle \phi |` to :math:`|\psi\rangle`. However, we cannot directly apply
# projectors as gates in our quantum circuits because they are **not** unitary operations by
# construction. We can instead use a simple LCU decomposition which holds for any projector:
soranjh marked this conversation as resolved.
Show resolved Hide resolved
#
# .. math::
# | \phi \rangle\langle \phi | = \frac{1}{2} \cdot (\mathbb{I}) + \frac{1}{2} \cdot (2 \cdot | \phi \rangle\langle \phi | - \mathbb{I})
soranjh marked this conversation as resolved.
Show resolved Hide resolved
#
# Both terms in the expression above are unitary (try proving it for yourself). We can now use this
# LCU decomposition to block-encode the projector! As an example, let's block-encode the projector
# :math:`| 0 \rangle\langle 0 |` that projects a state to the :math:`|0\rangle` state:
#
# .. math:: | 0 \rangle\langle 0 | = \begin{bmatrix}
# 1 & 0 \\
# 0 & 0 \\
# \end{bmatrix}.
#

coeffs = np.array([1/2, 1/2])
alphas = np.sqrt(coeffs) / np.linalg.norm(np.sqrt(coeffs))

proj_unitaries = [qml.Identity(0), qml.PauliZ(0)]

##############################################################################
# Note that the second term in our LCU simplifies to a Pauli :math:`Z` operation. We can now
# construct a full LCU circuit and verify that :math:`| 0 \rangle\langle 0 |` is block-encoded.
soranjh marked this conversation as resolved.
Show resolved Hide resolved

def lcu_circuit(): # block_encode
# PREP
qml.StatePrep(alphas, wires="ancilla")

# SEL
qml.Select(proj_unitaries, control="ancilla")

# PREP_dagger
qml.adjoint(qml.StatePrep(alphas, wires="ancilla"))
return qml.state()


output_matrix = qml.matrix(lcu_circuit)()
print("Block-encoded projector:\n")
print(np.real(np.round(output_matrix,2)))


##############################################################################
# Final thoughts
# -------------------
# LCUs and block encodings are often associated with advanced algorithms that require the full power
# of fault-tolerant quantum computers. The truth is that they are basic constructions with
# broad applicability that can be useful for all kinds of hardware and simulators. If you're working
# on quantum algorithms and applications in any capacity, these are techniques that you should
# master. PennyLane is equipped with the tools to help you get there.
soranjh marked this conversation as resolved.
Show resolved Hide resolved


##############################################################################
# About the authors
# -----------------
# .. include:: ../_static/authors/juan_miguel_arrazola.txt
# .. include:: ../_static/authors/jay_soni.txt
# .. include:: ../_static/authors/diego_guala.txt
7 changes: 7 additions & 0 deletions demos_quantum-computing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ such as benchmarking and characterizing quantum processors.
:figure: demonstrations/apply_qsvt/thumbnail_tutorial_QSVT_for_Matrix_Inversion.png
:description: :doc:`demos/tutorial_apply_qsvt`
:tags: quantumcomputing qsvt optimization

.. gallery-item::
:tooltip: Linear combinations of unitaries and block encodings
:figure: demonstrations/lcu_blockencoding/thumbnail_lcu_blockencoding.png
:description: :doc:`demos/tutorial_lcu_blockencoding`
:tags: quantumcomputing LCU algorithms qsvt

:html:`</div></div><div style='clear:both'>`

Expand Down Expand Up @@ -205,5 +211,6 @@ such as benchmarking and characterizing quantum processors.
demos/tutorial_intro_qsvt
demos/tutorial_grovers_algorithm
demos/tutorial_apply_qsvt
demos/tutorial_lcu_blockencoding