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

Implement FABLE as a Template (issue #4848) #5107

Merged
merged 95 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
139bbd4
Fable tests implemented. Doc strings
Jan 25, 2024
f9111bc
changelog edit
Jan 25, 2024
74695a9
Merge branch 'master' into fable
austingmhuang Jan 25, 2024
642a7f4
Update doc/releases/changelog-dev.md
austingmhuang Feb 1, 2024
1cfd590
Removed pennylane-venv from gitignore
Feb 1, 2024
7f1793d
Added copyright header
Feb 1, 2024
64942b8
Added copyright header again for test_fable.py
Feb 1, 2024
35fc907
Added citation for FABLE
Feb 1, 2024
b4239c8
Reordering of code in comments
Feb 1, 2024
4a45898
Added definition of tolerance
Feb 1, 2024
4d00652
definition of A includes that dimension should equal 2^n
Feb 1, 2024
fab4792
Update pennylane/templates/subroutines/fable.py
austingmhuang Feb 1, 2024
efb45ea
Rewrote definition of tolerance
Feb 1, 2024
7317c28
Merge branch 'master' into fable
Jaybsoni Feb 6, 2024
aab2531
Zeroes padding for non-square matrices
Feb 9, 2024
463fb24
Zeroes padding for matrices that have a shape not a power of 2
Feb 9, 2024
cbce56b
docstring update subnormalization
Feb 9, 2024
ec90086
small changes
Feb 9, 2024
73aa070
solve conflicts
Feb 9, 2024
5e1e133
Author name
Feb 9, 2024
a2ac3c2
added fable.png to templates
Feb 9, 2024
259fcd7
Merge branch 'master' into fable
austingmhuang Feb 9, 2024
17863dd
Merge branch 'master' into fable
austingmhuang Feb 11, 2024
656c87e
make format
austingmhuang Feb 11, 2024
d4222a7
build docs properly
austingmhuang Feb 11, 2024
283cad7
Added tests for flatten, unflatten, standard_validity, padding, jax_g…
Feb 12, 2024
950db53
Merge branch 'master' into fable
Jaybsoni Feb 12, 2024
a744313
Merge branch 'fable' of https://github.com/austingmhuang/pennylane in…
Feb 13, 2024
c90d7c4
Merge branch 'master' into fable
austingmhuang Feb 13, 2024
f783b62
Merge branch 'master' into fable
austingmhuang Feb 17, 2024
7da2987
Tests for autograd and jax gradients
Feb 17, 2024
2a0044c
Merge branch 'fable' of https://github.com/austingmhuang/pennylane in…
Feb 17, 2024
28664c8
Added comments for tests
Feb 17, 2024
4b4b6d8
Edited comments for tests
Feb 19, 2024
c022edc
Update pennylane/templates/subroutines/fable.py
austingmhuang Feb 25, 2024
7ff56c5
Update pennylane/templates/subroutines/fable.py
austingmhuang Feb 25, 2024
3e9be67
Update pennylane/templates/subroutines/fable.py
austingmhuang Feb 25, 2024
3fc664d
Update pennylane/templates/subroutines/fable.py
austingmhuang Feb 25, 2024
1cf3ab1
Changed to integers
Feb 26, 2024
2b66f7e
Merge branch 'master' into fable
austingmhuang Feb 26, 2024
63a1e7e
Merge branch 'master' into fable
Jaybsoni Feb 27, 2024
782e4bb
Update pennylane/templates/subroutines/fable.py
austingmhuang Apr 1, 2024
6a5e9d1
Light fixes to documentation
austingmhuang Apr 1, 2024
80b42f4
Merge branch 'master' into fable
austingmhuang Apr 1, 2024
a071432
Jittable
austingmhuang Apr 1, 2024
0fdbd9f
Lightning device test
austingmhuang Apr 1, 2024
2fe2673
Lightning qubit device test
austingmhuang Apr 1, 2024
f839834
Fix documentation
austingmhuang Apr 2, 2024
06a410d
Merge branch 'master' into fable
austingmhuang Apr 2, 2024
c3020c5
Fix lightning test
austingmhuang Apr 2, 2024
4bc286e
Update pennylane/templates/subroutines/fable.py
austingmhuang Apr 5, 2024
29cc3cf
Update tests/templates/test_subroutines/test_fable.py
austingmhuang Apr 5, 2024
3d0d708
Changed FABLE to qml.FABLE
austingmhuang Apr 5, 2024
a2947cb
jittable with qml.FABLE
austingmhuang Apr 5, 2024
2155e1f
Naming
austingmhuang Apr 5, 2024
110dc72
documentation and character limit within 100
austingmhuang Apr 5, 2024
e846a01
Check example
austingmhuang Apr 5, 2024
4a57337
Fixed edge case of 2x2 array
austingmhuang Apr 5, 2024
8342d52
Merge branch 'master' into fable
austingmhuang Apr 5, 2024
3ca0302
Fixed documentation some more
austingmhuang Apr 5, 2024
527a82a
Additional tests
austingmhuang Apr 5, 2024
f58a30c
Rework FABLE so that it takes a range of wires
austingmhuang Apr 5, 2024
21cbf68
Added additional test for when # of wires is incorrect
austingmhuang Apr 5, 2024
48e234a
Update docs
austingmhuang Apr 5, 2024
7235973
Fix docs
austingmhuang Apr 5, 2024
eabd16d
Merge branch 'master' into fable
austingmhuang Apr 8, 2024
3710922
Additional test
austingmhuang Apr 8, 2024
938864d
Edit test case
austingmhuang Apr 8, 2024
7d97c4c
Edited example in docstring
austingmhuang Apr 8, 2024
45d6316
tol != 0 jit error
austingmhuang Apr 8, 2024
f0d87b0
tol != 0 jit error
austingmhuang Apr 8, 2024
62c5795
Additional tests fixed edge case 1x1
austingmhuang Apr 8, 2024
7cefb20
Merge branch 'master' into fable
austingmhuang Apr 8, 2024
929e1d8
Fixed gradient tests
austingmhuang Apr 9, 2024
2cead4b
Wire ordering is ascending by default
austingmhuang Apr 9, 2024
14ae812
Delete notebook
austingmhuang Apr 9, 2024
f90c266
Merge branch 'master' into fable
austingmhuang Apr 9, 2024
2eb70ec
Merge branch 'master' into fable
austingmhuang Apr 9, 2024
b6c5252
Merge branch 'master' into fable
austingmhuang Apr 10, 2024
67c8450
Update pennylane/templates/subroutines/fable.py
austingmhuang Apr 10, 2024
e0036aa
Address comments
austingmhuang Apr 10, 2024
05cf8fb
fixed test
austingmhuang Apr 10, 2024
e7ba864
Update pennylane/templates/subroutines/fable.py
austingmhuang Apr 10, 2024
a7a2057
Update pennylane/templates/subroutines/fable.py
austingmhuang Apr 10, 2024
52bd4c9
docs
austingmhuang Apr 10, 2024
e93379c
docs
austingmhuang Apr 10, 2024
aa63f7f
Update pennylane/templates/subroutines/fable.py
austingmhuang Apr 10, 2024
c0ca019
Update pennylane/templates/subroutines/fable.py
austingmhuang Apr 10, 2024
0e108f2
Update pennylane/templates/subroutines/fable.py
austingmhuang Apr 10, 2024
f50370e
Merge branch 'master' into fable
austingmhuang Apr 10, 2024
a28df93
Change fable image
austingmhuang Apr 11, 2024
4e06b19
Merge branch 'master' into fable
austingmhuang Apr 11, 2024
5caf786
Merge branch 'master' into fable
austingmhuang Apr 11, 2024
ce684b1
fix image
austingmhuang Apr 11, 2024
245a6f5
fable fix
austingmhuang Apr 11, 2024
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
Binary file added doc/_static/fable.png
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 doc/_static/templates/subroutines/fable.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 @@ -295,6 +295,10 @@ Other useful templates which do not belong to the previous categories can be fou
:description: :doc:`ControlledSequence<../code/api/pennylane.ControlledSequence>`
:figure: _static/templates/subroutines/small_ctrl.png

.. gallery-item::
:description: :doc:`FABLE <../code/api/pennylane.FABLE>`
:figure: _static/templates/subroutines/fable.png

.. raw:: html

<div style='clear:both'></div>
Expand Down
4 changes: 4 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

<h3>New features since last release</h3>

* The `FABLE` template is added for efficient block encoding of matrices. Users can now call FABLE to efficiently construct circuits according to a user-set approximation level.
[(#5107)](https://github.com/PennyLaneAI/pennylane/pull/5107)

* The `QubitDevice` class and children classes support the `dynamic_one_shot` transform provided that they support `MidMeasureMP` operations natively.
[(#5317)](https://github.com/PennyLaneAI/pennylane/pull/5317)

Expand Down Expand Up @@ -402,6 +405,7 @@ Isaac De Vlugt,
Amintor Dusko,
Pietropaolo Frisoni,
Lillian M. A. Frederiksen,
Austin Huang,
Soran Jahangiri,
Korbinian Kottmann,
Christina Lee,
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 @@ -39,5 +39,6 @@
from .controlled_sequence import ControlledSequence
from .trotter import TrotterProduct
from .aqft import AQFT
from .fable import FABLE
from .reflection import Reflection
from .amplitude_amplification import AmplitudeAmplification
186 changes: 186 additions & 0 deletions pennylane/templates/subroutines/fable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
# 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.
"""
austingmhuang marked this conversation as resolved.
Show resolved Hide resolved
This module contains the template for the Fast Approximate BLock Encoding (FABLE) technique.
"""
import warnings
import numpy as np
import pennylane as qml
from pennylane.templates.state_preparations.mottonen import compute_theta, gray_code
from pennylane.operation import AnyWires, Operation
from pennylane.wires import Wires


class FABLE(Operation):
austingmhuang marked this conversation as resolved.
Show resolved Hide resolved
r"""
Construct a unitary with the fast approximate block encoding method.

The FABLE method allows to simplify block encoding circuits without reducing accuracy,
for matrices of specific structure [`arXiv:2205.00081 <https://arxiv.org/abs/2205.00081>`_].


Args:
input_matrix (tensor_like): a :math:`(2^n \times 2^n)` matrix to be encoded,
where :math:`n` is the number of wires used
tol (float): rotation gates that have an angle value smaller than this tolerance are removed
id (str or None): string representing the operation (optional)

Raises:
ValueError: if the number of wires doesn't fit the dimensions of the matrix

**Example**

We can define a matrix and a block-encoding circuit as follows:

.. code-block:: python
austingmhuang marked this conversation as resolved.
Show resolved Hide resolved

input_matrix= np.array([[0.1, 0.2],[0.3, -0.2]])
dev = qml.device('default.qubit', wires=3)
@qml.qnode(dev)
def example_circuit():
qml.FABLE(input_matrix, wires=range(3), tol=0)
return qml.state()

We can see that the input matrix has been block encoded in the matrix of the circuit:

>>> s = int(qml.math.ceil(qml.math.log2(max(len(input_matrix), len(input_matrix[0])))))
>>> expected = 2**s * qml.matrix(example_circuit)().real[0 : 2**s, 0 : 2**s]
>>> print(f"Block-encoded matrix:\n{expected}")
Block-encoded matrix:
[[0.1 0.2]
[0.3 -0.2]]

.. note::
austingmhuang marked this conversation as resolved.
Show resolved Hide resolved
FABLE can be implemented for matrices of arbitrary shape and size.
When given a :math:`(N \times M)` matrix, the matrix is padded with zeroes
until it is of :math:`(N \times N)` dimension, where :math:`N` is equal to :math:`2^n`,
and :math:`n` is an integer. It is also assumed that the values
of the input matrix are within [-1, 1]. Apply a subnormalization factor if needed.
"""

num_wires = AnyWires
"""int: Number of wires that the operator acts on."""

num_params = 1
"""int: Number of trainable parameters that the operator depends on."""
austingmhuang marked this conversation as resolved.
Show resolved Hide resolved

grad_method = None
"""Gradient computation method."""

def __init__(self, input_matrix, wires, tol=0, id=None):
wires = Wires(wires)

if not qml.math.is_abstract(input_matrix):
if qml.math.any(qml.math.iscomplex(input_matrix)):
raise ValueError("Support for imaginary values has not been implemented.")

alpha = qml.math.linalg.norm(qml.math.ravel(input_matrix), np.inf)
if alpha > 1:
raise ValueError(
"The subnormalization factor should be lower than 1."
+ "Ensure that the values of the input matrix are within [-1, 1]."
)
else:
if tol != 0:
raise ValueError(
"JIT is not supported for tolerance values greater than 0. Set tol = 0 to run."
)

row, col = qml.math.shape(input_matrix)
if row != col:
warnings.warn(
f"The input matrix should be of shape NxN, got {input_matrix.shape}."
+ "Zeroes were padded automatically."
)
dimension = max(row, col)
input_matrix = qml.math.pad(input_matrix, ((0, dimension - row), (0, dimension - col)))
row, col = qml.math.shape(input_matrix)
n = int(qml.math.ceil(qml.math.log2(col)))
if n == 0: ### For edge case where someone puts a 1x1 array.
n = 1
if col < 2**n:
input_matrix = qml.math.pad(input_matrix, ((0, 2**n - col), (0, 2**n - col)))
col = 2**n
warnings.warn(
"The input matrix should be of shape NxN, where N is a power of 2."
+ f"Zeroes were padded automatically. Input is now of shape {input_matrix.shape}."
)

if len(wires) != 2 * n + 1:
raise ValueError(f"Number of wires is incorrect, expected {2*n+1} but got {len(wires)}")

self._hyperparameters = {"tol": tol}

super().__init__(input_matrix, wires=wires, id=id)

@staticmethod
def compute_decomposition(input_matrix, wires, tol=0): # pylint:disable=arguments-differ
r"""Sequence of gates that represents the efficient circuit produced by the FABLE technique

Args:
input_matrix (tensor_like): an :math:`(N \times N)` matrix to be encoded
wires (Any or Iterable[Any]): wires that the operator acts on
tol (float): rotation gates that have an angle value smaller than this tolerance are removed

Returns:
list[.Operator]: list of gates for efficient circuit
"""
op_list = []
alphas = qml.math.arccos(input_matrix).flatten()
thetas = compute_theta(alphas)

ancilla = [wires[0]]
wires_i = wires[1 : 1 + len(wires) // 2][::-1]
wires_j = wires[1 + len(wires) // 2 : len(wires)][::-1]

code = gray_code((2 * qml.math.log2(len(input_matrix))))
n_selections = len(code)

control_wires = [
int(qml.math.log2(int(code[i], 2) ^ int(code[(i + 1) % n_selections], 2)))
for i in range(n_selections)
]
wire_map = dict(enumerate(wires_j + wires_i))

for w in wires_i:
op_list.append(qml.Hadamard(w))

nots = {}
for theta, control_index in zip(thetas, control_wires):
if qml.math.is_abstract(theta):
for c_wire in nots:
op_list.append(qml.CNOT(wires=[c_wire] + ancilla))
op_list.append(qml.RY(2 * theta, wires=ancilla))
nots[wire_map[control_index]] = 1
else:
if abs(2 * theta) > tol:
for c_wire in nots:
op_list.append(qml.CNOT(wires=[c_wire] + ancilla))
op_list.append(qml.RY(2 * theta, wires=ancilla))
nots = {}
if wire_map[control_index] in nots:
del nots[wire_map[control_index]]
else:
nots[wire_map[control_index]] = 1

for c_wire in nots:
op_list.append(qml.CNOT([c_wire] + ancilla))

for w_i, w_j in zip(wires_i, wires_j):
op_list.append(qml.SWAP(wires=[w_i, w_j]))

for w in wires_i:
op_list.append(qml.Hadamard(w))

return op_list
Loading
Loading