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

How-to: Quantum Arithmetic #1229

Closed
wants to merge 45 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
d29d6d7
first commit howto arithmetic
gmlejarza Oct 4, 2024
6e89bb1
Update demonstrations/tutorial_how_to_use_arithmetic_operators.py
KetpuntoG Oct 4, 2024
eabb5e8
cleaning code
KetpuntoG Oct 4, 2024
d7c6117
Apply suggestions from code review
KetpuntoG Oct 4, 2024
464cb64
suggestions from code review
gmlejarza Oct 7, 2024
56fc617
some suggestions
KetpuntoG Oct 7, 2024
b8997a1
Update tutorial_how_to_use_arithmetic_operators.py
KetpuntoG Oct 7, 2024
5893c0b
style and rendering changes
gmlejarza Oct 7, 2024
ca722ae
typo
KetpuntoG Oct 7, 2024
c3fdbbc
link for OutPoly
gmlejarza Oct 9, 2024
513a1a5
Immediate suggestions from code review
gmlejarza Oct 10, 2024
c8725b9
adressing first suggestions from code review
gmlejarza Oct 10, 2024
0ca2526
feedback from JM
gmlejarza Oct 14, 2024
ddb8b06
typo code
gmlejarza Oct 14, 2024
ddc8a90
adding plot of Adder
gmlejarza Oct 15, 2024
937f8a7
fix wires for Poly
gmlejarza Oct 15, 2024
8aad2e2
modulo explanation
gmlejarza Oct 15, 2024
a5b4540
suggestions from code review
gmlejarza Oct 17, 2024
d16d951
typo work_wires
gmlejarza Oct 17, 2024
9b8f24f
fixing adder with prepare state
gmlejarza Oct 17, 2024
0a176f8
typo circuit draw
gmlejarza Oct 17, 2024
006891c
suggestions from code review
gmlejarza Oct 24, 2024
30ba6a7
Apply suggestions from code review
gmlejarza Oct 28, 2024
e49d8c8
suggestions from code review
gmlejarza Oct 28, 2024
749cfa7
undo changes in Makefile
gmlejarza Oct 28, 2024
c10af36
fix rendering
gmlejarza Oct 29, 2024
3c7299a
suggestions and thumbnails
gmlejarza Oct 30, 2024
e5aa5b2
fix rendering
gmlejarza Oct 30, 2024
d5ca1a0
fix one reference
gmlejarza Oct 30, 2024
0357693
fix references
gmlejarza Oct 30, 2024
1b4a19d
new image and change w
KetpuntoG Oct 30, 2024
0e20b08
Apply suggestions from code review
gmlejarza Oct 31, 2024
e700f12
more suggestions
gmlejarza Oct 31, 2024
4b8e675
Apply suggestions from code review
gmlejarza Nov 4, 2024
a0ea1c4
adding related demo
gmlejarza Nov 4, 2024
cbfd3a5
renaming files and small wording
gmlejarza Nov 4, 2024
b27cf8f
bug in json name
gmlejarza Nov 4, 2024
213a955
small rename json
gmlejarza Nov 4, 2024
0dd30d6
tutorial_
KetpuntoG Nov 4, 2024
fbddd21
Merge branch 'dev' into arith_howto
ikurecic Nov 5, 2024
5c913ca
updating metadata
ikurecic Nov 5, 2024
5574357
cropping main file
ikurecic Nov 5, 2024
573a077
adjusting title
ikurecic Nov 5, 2024
3628c7a
adjusting formatting
ikurecic Nov 5, 2024
17c2f32
empty commit
KetpuntoG Nov 5, 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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,6 @@ environment:
$$PYTHON_VENV_PATH/bin/python -m pip install --upgrade git+https://github.com/PennyLaneAI/pennylane-qulacs.git#egg=pennylane-qulacs;\
$$PYTHON_VENV_PATH/bin/python -m pip install --extra-index-url https://test.pypi.org/simple/ PennyLane-Catalyst --pre --upgrade;\
$$PYTHON_VENV_PATH/bin/python -m pip install --extra-index-url https://test.pypi.org/simple/ PennyLane-Lightning --pre --upgrade;\
$$PYTHON_VENV_PATH/bin/python -m pip install --upgrade git+https://github.com/PennyLaneAI/pennylane.git#egg=pennylane;\
$$PYTHON_VENV_PATH/bin/python -m pip install --upgrade git+https://github.com/PennyLaneAI/pennylane.git@qml_outpoly#egg=pennylane;\
fi;\
fi
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"title": "How-to use Quantum Arithmetic Operators",
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
"authors": [
{
"id": "gmlejarza"
},
{
"id": "KetPuntoG"
}
],
"dateOfPublication": "2024-10-01T00:00:00+00:00",
"dateOfLastModification": "2024-10-01T00:00:00+00:00",
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
"categories": [
"Quantum Computing",
"Algorithms"
],
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
"tags": [],
"previewImages": [
{
"type": "thumbnail",
"uri": "/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_qnn_multivariate_regression.png"
},
{
"type": "large_thumbnail",
"uri": "/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_qnn_multivariate_regression.png"
}
],
"seoDescription": "Learn how to use the quantum arithmetic operators of Pennylane.",
"doi": "",
"canonicalURL": "/qml/demos/tutorial_how_to_use_arithmetic_operators",
ikurecic marked this conversation as resolved.
Show resolved Hide resolved
"references": [
{
"id": "demo_qft_arith",
"type": "other",
"title": "Basic arithmetic with the quantum Fourier transform (QFT)",
"authors": "Guillermo Alonso",
"year": "2024",
"publisher": "",
"url": "https://pennylane.ai/qml/demos/tutorial_qft_arithmetics/"
}
],
"basedOnPapers": [],
"referencedByPapers": [],
"relatedContent": [
{
"type": "demonstration",
"id": "tutorial_qft_arithmetics",
"weight": 1.0
}
]
}
249 changes: 249 additions & 0 deletions demonstrations/tutorial_how_to_use_arithmetic_operators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
r"""
How-to use Quantum Arithmetic Operators
=======================================
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

Classical computers handle arithmetic operations like addition, subtraction, multiplication, and exponentiation with ease.
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
For instance, you can multiply two numbers on your phone in milliseconds!
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
Quantum computers, however, aren't as efficient at basic arithmetic. So why do we need quantum arithmetic?
While it's not "better" for basic operations, it's essential in more complex quantum algorithms. For example:
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

1. In Shor's algorithm quantum arithmetic is crucial for performing modular exponentiation.
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

2. Grover's algorithm might need to use quantum arithmetic to construct oracles, as shown in [#demo_qft_arith]_.

3. Loading functions into quantum computers, which often requires several quantum arithmetic operations.
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

These arithmetic operations act as building blocks that enable powerful quantum computations when integrated into larger algorithms.
With PennyLane, you'll see how easy it is to build these operations as subroutines for your quantum algorithms!


Loading a function :math:`f(x, y)`
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
----------------------------------

gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
In this how-to guide, we will show how we can apply a polynomial function in a quantum computer using basic arithmetic.
We will use as an example the function :math:`f(x,y)= 4 + 3xy + 5 x+ 3 y` where the variables :math:`x` and :math:`y`
are integer values. Therefore, the operator we want to build is:

.. math::

U|x\rangle |y\rangle |0\rangle = |x\rangle |y\rangle |4 + 3xy + 5x + 3y\rangle,

where :math:`x` and :math:`y` are the binary representations of the integers on which we want to apply the function.

gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
We will show how to load this function in two different ways: first, by concatenating simple arithmetic operators,
and finally, using the `qml.OutPoly` operator.

InPlace and OutPlace Operations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

We can load the target function into the quantum computer using different quantum arithmetic operations.
We will break down into pieces. We'll do a step by step load of the function :math:`f(x, y)`.
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

The first thing to do is to define the `registers of wires <https://pennylane.ai/qml/demos/tutorial_how_to_use_registers/>`_
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
we will work with:"""

import pennylane as qml

# we indicate the name of the registers and their number of qubits
wires = qml.registers({"x": 4, "y":4, "output":5,"work_wires": 4})

######################################################################
# Before we start applying our arithmetic operators, we can initialize specific values to :math:`x` and :math:`y`
# which will help us to check that the results obtained are correct.
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

def prepare_initial_state(x,y):
ikurecic marked this conversation as resolved.
Show resolved Hide resolved
qml.BasisState(x, wires=wires["x"])
qml.BasisState(y, wires=wires["y"])


dev = qml.device("default.qubit", shots=1)
@qml.qnode(dev)
def circuit(x,y):
prepare_initial_state(x, y)
return [qml.sample(wires=wires[name]) for name in ["x", "y", "output"]]
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

output = circuit(x=1,y=4)

gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
print("x register: ", output[0])
print("y register: ", output[1])
print("output register: ", output[2])

######################################################################
# In this example we are setting :math:`x=1` and :math:`y=4` whose binary representation are :math:`[0 0 0 1]` and :math:`[0 1 0 0]` respectively.
#
# Now, the first step to load :math:`f(x, y) =4 + 3xy + 5 x+ 3 y` will be
# to add the constant :math:`4` by using the Inplace addition operator :class:`~.pennylane.Adder` directly on the output wires:
#
# .. math::
#
# \text{Adder}(k) |w \rangle = | w+k \rangle.
#
# In our example, we are considering the input :math:`|w\rangle = |0\rangle` and :math:`k = 4`.
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
# Let's see how it looks like in code:

@qml.qnode(dev)
def circuit(x,y):

prepare_initial_state(x, y) # |x> |y> |0>
qml.Adder(4, wires["output"]) # |x> |y> |4>

return qml.sample(wires=wires["output"])

print(circuit(x=1,y=4))

######################################################################
# We obtained the state [0 0 1 0 0], i.e. :math:`4`, as expected.
# Note that we have not used the :math:`x` and :math:`y` wires for the moment since the constant term does not depend on these values.
#
# The next step will be to add the term :math:`3xy` by using the
# `Inplace multiplication <https://docs.pennylane.ai/en/stable/code/api/pennylane.Multiplier.html>`_
#
# .. math::
#
# \text{Multiplier}(k) |w \rangle = | kw \rangle,
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
#
# and the `Outplace multiplication <https://docs.pennylane.ai/en/stable/code/api/pennylane.OutMultiplier.html>`_
#
# .. math::
#
# \text{OutMultiplier} |w \rangle |z \rangle |0 \rangle = |w \rangle |z \rangle |wz \rangle.
#
# To do this, we first turn :math:`|x\rangle` into :math:`|3x\rangle` with the Inplace multiplication. After that
# we will multiply the result by :math:`|y\rangle`
# using the Outplace operator:

def adding_3xy():
# |x> ---> |3x>
qml.Multiplier(3, wires["x"], work_wires=wires["work_wires"])

# |3x>|y>|0> ---> |3x>|y>|3xy>
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
qml.OutMultiplier(wires["x"], wires["y"], wires["output"])

# We return the x-register to its original value
# |3x>|y>|3xy> ---> |x>|y>|3xy>
qml.adjoint(qml.Multiplier)(3, wires["x"], work_wires=wires["work_wires"])

@qml.qnode(dev)
def circuit(x,y):

prepare_initial_state(x, y) # |x> |y> |0>
qml.Adder(4, wires["output"]) # |x> |y> |4>
adding_3xy() # |x> |y> |4 + 3xy>

return qml.sample(wires=wires["output"])

print(circuit(x=1,y=4))

######################################################################
# Nice! The state [1 0 0 0 0] represents :math:`4+3xy = 4 + 12 =16`.
#
# The final step to compute :math:`f(x, y)` is to generate the monomial terms :math:`5x` and :math:`3y` using the previously employed
# :class:`~.pennylane.Multiplier`. These terms are then added to the output register using the :class:`~.pennylane.OutAdder` operator:
#
# .. math::
#
# \text{OutAdder} |w \rangle |z \rangle |0 \rangle = |w \rangle |z \rangle |w + z \rangle,
#
# where in our case, :math:`|w\rangle` and :math:`|z\rangle` are :math:`|5x\rangle` and :math:`|3y\rangle` respectively.
#

def adding_5x_3y():

# |x>|y> ---> |5x>|3y>
qml.Multiplier(5, wires["x"], work_wires=wires["work_wires"])
qml.Multiplier(3, wires["y"], work_wires=wires["work_wires"])

# |5x>|3y>|0> ---> |5x>|3y>|5x + 3y>
qml.OutAdder(wires["x"], wires["y"], wires["output"])

# We return the x and y registers to its original value
# |5x>|3y>|5x + 3y> ---> |x>|y>|5x + 3y>
qml.adjoint(qml.Multiplier)(5, wires["x"], work_wires=wires["work_wires"])
qml.adjoint(qml.Multiplier)(3, wires["y"], work_wires=wires["work_wires"])


@qml.qnode(dev)
def circuit(x,y):

prepare_initial_state(x, y) # |x> |y> |0>
qml.Adder(4, wires["output"]) # |x> |y> |4>
adding_3xy() # |x> |y> |4 + 3xy>
adding_5x_3y() # |x> |y> |4 + 3xy + 5x + 3y>


return qml.sample(wires=wires["output"])

print(circuit(x=1,y=4))

######################################################################
# The result doesn't seem right, as we expect to get :math:`f(x=1, y=4) = 33`. Can you guess why?
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
#
# The issue is overflow. The number 33 exceeds what can be represented with the 5 wires defined in `wires["output"]`.
# With 5 wires, we can only represent numbers up to :math:`2^5 = 32`. Anything larger is reduced modulo :math:`2^5`.
# Quantum arithmetic is modular, so every operation is mod-based.
#
# To fix this and get :math:`f(x=1, y=4) = 33`, we could just add one more wire to the output register.
#

wires = qml.registers({"x": 4, "y": 4, "output": 6,"work_wires": 4})
print(circuit(x=1, y=4))

######################################################################
# Now we get the correct result where :math:`[1 0 0 0 0 1]` is the binary representation of :math:`33`.

######################################################################
# Using OutPoly
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
# ~~~~~~~~~~~~~
# In the last section, we showed how to use different arithmetic operations to load
# a function onto a quantum computer. But what if I told you there's an easier way to do all this using just one
# PennyLane function that handles the arithmetic for you? Pretty cool, right? I'm talking about :class:`~.pennylane.OutPoly`.
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
# This handy operator lets you load polynomials directly into quantum states, taking care of all the arithmetic in one go.
# Let's check out how to load a function like :math:`f(x, y)` using :class:`~.pennylane.OutPoly`.
#
# Let's first start by explicitly defining our function:

def f(x, y):
return 4 + 3*x*y + 5*x + 3*y

######################################################################
# Now, we load it into a quantum circuit.
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

######################################################################

@qml.qnode(dev)
def circuit_with_Poly(x,y):

prepare_initial_state(x, y)
qml.OutPoly(f, registers_wires=[wires["x"], wires["y"], wires["output"]])
KetpuntoG marked this conversation as resolved.
Show resolved Hide resolved

return qml.sample(wires = wires["output"])

print(circuit_with_Poly(x=1,y=4))
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

######################################################################
# Eureka! We've just seen how much easier it can be to implement arithmetic operations in one step.
# Now, it's up to you to decide, depending on the problem you're tackling, whether to go for the versatility
# of defining your own arithmetic operations or the convenience of using the :class:`~.pennylane.OutPoly` function.

######################################################################
# Conclusion
# ------------------------------------------
# Understanding and implementing quantum arithmetic is a key step toward unlocking the full potential
# of quantum computing. While it may not replace classical efficiency for simple tasks, its role in complex algorithms
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
# is undeniable. By leveraging tools like `qml.OutPoly`, you can streamline the coding of your quantum algorithms. So,
# whether you choose to customize your arithmetic operations or take advantage of the built-in convenience offered by PennyLane
# operators, you're now equipped to tackle the exciting quantum challenges ahead.
#
# References
# ----------
#
# .. [#demo_qft_arith]
#
# Guillermo Alonso
# "Basic arithmetic with the quantum Fourier transform (QFT)",
# `Pennylane: Basic arithmetic with the quantum Fourier transform (QFT) <https://pennylane.ai/qml/demos/tutorial_qft_arithmetics/>`__, 2024
#
# About the authors
# -----------------

Loading