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

Improved documentation for Quantum Arithmetic #6136

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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 .github/workflows/rc_sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,4 @@ jobs:
pr_body: "Automatic sync from the release candidate to master during a feature freeze."
pr_allow_empty: false
pr_draft: false
pr_reviewer: "astralcai,albi3ro"
pr_reviewer: "mudit2812,albi3ro"
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
Binary file added doc/_static/templates/arithmetic/adder.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.
Binary file added doc/_static/templates/arithmetic/modexp.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/arithmetic/multiplier.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/arithmetic/outadder.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.
Binary file added doc/_static/templates/arithmetic/phaseadder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions doc/development/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Release notes

This page contains the release notes for PennyLane.

.. mdinclude:: ../releases/changelog-dev.md

.. mdinclude:: ../releases/changelog-0.38.0.md

.. mdinclude:: ../releases/changelog-0.37.0.md
Expand Down
39 changes: 39 additions & 0 deletions doc/introduction/templates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,45 @@ state preparation is typically used as the first operation.

.. _intro_ref_temp_subroutines:

Arithmetic templates
--------------------

Quantum arithmetic templates to perform in-place and out-place modular operations such
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
as addition, multiplication and exponentiation.

.. gallery-item::
:description: :doc:`PhaseAdder <../code/api/pennylane.PhaseAdder>`
:figure: _static/templates/arithmetic/phaseadder.png

.. gallery-item::
:description: :doc:`Adder <../code/api/pennylane.Adder>`
:figure: _static/templates/arithmetic/adder.png

.. gallery-item::
:description: :doc:`OutAdder <../code/api/pennylane.OutAdder>`
:figure: _static/templates/arithmetic/outadder.png

.. gallery-item::
:description: :doc:`Multiplier <../code/api/pennylane.Multiplier>`
:figure: _static/templates/arithmetic/multiplier.png

.. gallery-item::
:description: :doc:`OutMultiplier <../code/api/pennylane.OutMultiplier>`
:figure: _static/templates/arithmetic/outmultiplier.png

.. gallery-item::
:description: :doc:`ModExp <../code/api/pennylane.ModExp>`
:figure: _static/templates/arithmetic/modexp.png

gmlejarza marked this conversation as resolved.
Show resolved Hide resolved
.. gallery-item::
:description: :doc:`IntegerComparator <../code/api/pennylane.IntegerComparator>`
:figure: _static/templates/arithmetic/integercomparator.png


.. raw:: html

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

Quantum Chemistry templates
---------------------------

Expand Down
24 changes: 24 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
:orphan:

# Release 0.39.0-dev (development release)

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

<h3>Improvements 🛠</h3>

<h3>Breaking changes 💔</h3>

<h3>Deprecations 👋</h3>

<h3>Documentation 📝</h3>

<h3>Bug fixes 🐛</h3>

* Fix Pytree serialization of operators with empty shot vectors:
[(#6155)](https://github.com/PennyLaneAI/pennylane/pull/6155)

<h3>Contributors ✍️</h3>

This release contains contributions from (in alphabetical order):

Jack Brown
2 changes: 1 addition & 1 deletion pennylane/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.38.0"
__version__ = "0.39.0-dev1"
3 changes: 3 additions & 0 deletions pennylane/pytrees/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ def _wires_to_json(obj: Wires) -> JSON:

def _shots_to_json(obj: Shots) -> JSON:
"""JSON handler for serializing ``Shots``."""
if obj.total_shots is None:
return None

return obj.shot_vector


Expand Down
89 changes: 60 additions & 29 deletions pennylane/templates/subroutines/adder.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,54 +22,83 @@
class Adder(Operation):
r"""Performs the in-place modular addition operation.

This operator performs the modular addition by an integer :math:`k` modulo :math:`mod` in the
computational basis:
This operator performs the modular addition by an integer :math:`k` modulo :math:`mod` in the
computational basis:

.. math::
.. math::

\text{Adder}(k, mod) |x \rangle = | x+k \; \text{modulo} \; mod \rangle.
\text{Adder}(k, mod) |x \rangle = | x+k \; (mod) \rangle.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this is changed?


The implementation is based on the quantum Fourier transform method presented in
`arXiv:2311.08555 <https://arxiv.org/abs/2311.08555>`_.
This operation can be represented in a quantum circuit as:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure adding the image here is helpful. The equation is clear enough.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would leave it if possible. Although in the equation it is clear, it seems to me more visual the in-place / out-place difference seen in this way


.. figure:: ../../_static/templates/arithmetic/adder.png
:align: center
:width: 60%
:target: javascript:void(0);

The implementation is based on the quantum Fourier transform method presented in
`arXiv:2311.08555 <https://arxiv.org/abs/2311.08555>`_.

.. note::

Note that :math:`x` must be smaller than :math:`mod` to get the correct result.
:math:`x` must be smaller than :math:`mod` to get the correct result.
Comment on lines -37 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that "Note that" sounded repititive here but starting with a math symbol, x, is also not ideal.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed to: "To obtain the correct result, :math:x must be smaller than :math:mod"


.. seealso:: :class:`~.PhaseAdder` and :class:`~.OutAdder`.

Args:
k (int): the number that needs to be added
x_wires (Sequence[int]): the wires the operation acts on
mod (int): the modulus for performing the addition, default value is :math:`2^{len(x\_wires)}`
work_wires (Sequence[int]): the auxiliary wires to be used for performing the addition
Args:
k (int): the number that needs to be added
x_wires (Sequence[int]): the wires the operation acts on
mod (int): the modulus for performing the addition, default value is :math:`2^{\text{len(x_wires)}}`
work_wires (Sequence[int]): the two auxiliary wires to be used for performing the addition when :math:`mod \neq 2^{\text{len(x_wires)}}`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest mentioning the default, instead of the math equation and referring the user to check "usage details".


**Example**
gmlejarza marked this conversation as resolved.
Show resolved Hide resolved

This example computes the sum of two integers :math:`x=8` and :math:`k=5` modulo :math:`mod=15`.

.. code-block::
.. code-block::

x = 8
k = 5
mod = 15
x = 8
k = 5
mod = 15

x_wires =[0,1,2,3]
work_wires=[4,5]
x_wires =[0,1,2,3]
work_wires=[4,5]

dev = qml.device("default.qubit", shots=1)
@qml.qnode(dev)
def circuit(x, k, mod, x_wires, work_wires):
qml.BasisEmbedding(x, wires=x_wires)
qml.Adder(k, x_wires, mod, work_wires)
return qml.sample(wires=x_wires)
dev = qml.device("default.qubit", shots=1)
@qml.qnode(dev)
def circuit():
qml.BasisEmbedding(x, wires=x_wires)
qml.Adder(k, x_wires, mod, work_wires)
return qml.sample(wires=x_wires)

.. code-block:: pycon
.. code-block:: pycon

>>> print(circuit(x, k, mod,x_wires, work_wires))
[1 1 0 1]
>>> print(circuit())
[1 1 0 1]

The result, :math:`[1 1 0 1]`, is the ket representation of
:math:`8 + 5 \, \text{modulo} \, 15 = 13`.

.. details::
:title: Usage Details

This template takes as input two different sets of wires.

The first one is ``x_wires`` which is used
to encode the integer :math:`x < mod` in the computational basis. Therefore, we need at least
:math:`\lceil \log_2(x)\rceil` ``x_wires`` to represent :math:`x`. After performing the modular addition operation, the resulting integer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
:math:`\lceil \log_2(x)\rceil` ``x_wires`` to represent :math:`x`. After performing the modular addition operation, the resulting integer
:math:`\lceil \log_2(x)\rceil` ``x_wires`` to represent :math:`x`. However, after performing the modular addition operation, the resulting integer

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've rewritten this paragraph to be more concise and clear

encoded in the computational basis can be as large as :math:`mod-1`. Hence, we need at least
:math:`\lceil \log_2(mod)\rceil` ``x_wires``
to represent all the possible results. Since :math:`x < mod` by definition, we just need at least :math:`\lceil \log_2(mod)\rceil` ``x_wires``.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
to represent all the possible results. Since :math:`x < mod` by definition, we just need at least :math:`\lceil \log_2(mod)\rceil` ``x_wires``.
to represent all the possible results. Since :math:`x < mod` by definition, we need at least :math:`\lceil \log_2(mod)\rceil` ``x_wires``.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've rewritten this paragraph to be more concise and clear


The second set of wires is ``work_wires`` which consist of the auxiliary qubits used to perform the modular addition operation.

- If :math:`mod = 2^{\text{len(x_wires)}}`, there will be no need for ``work_wires``, hence ``work_wires=None``. This is the case by default.

- If :math:`mod \neq 2^{\text{len(x_wires)}}`, two ``work_wires`` have to be provided.

Note that the ``Adder`` template allows us to perform modular addition in the computational basis. However if one just wants to perform standard addition (with no modulo), the modulo
:math:`mod` has to be set large enough to ensure that :math:`x+k < mod`.
"""

grad_method = None
Expand Down Expand Up @@ -135,11 +164,13 @@ def _primitive_bind_call(cls, *args, **kwargs):
@staticmethod
def compute_decomposition(k, x_wires, mod, work_wires): # pylint: disable=arguments-differ
r"""Representation of the operator as a product of other operators.

Args:
k (int): the number that needs to be added
x_wires (Sequence[int]): the wires the operation acts on
mod (int): the modulus for performing the addition, default value is :math:`2^{len(x\_wires)}`
work_wires (Sequence[int]): the auxiliary wires to be used for performing the addition
mod (int): the modulus for performing the addition, default value is :math:`2^{\text{len(x_wires)}}`
work_wires (Sequence[int]): the two auxiliary wires to be used for performing the addition
when :math:`mod \neq 2^{\text{len(x_wires)}}`
Returns:
list[.Operator]: Decomposition of the operator

Expand Down
62 changes: 49 additions & 13 deletions pennylane/templates/subroutines/mod_exp.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,44 +26,53 @@ class ModExp(Operation):

.. math::

\text{ModExp}(base,mod) |x \rangle |k \rangle = |x \rangle |k*base^x \, \text{mod} \, mod \rangle,
\text{ModExp}(base,mod) |x \rangle |b \rangle = |x \rangle |b \cdot base^x \, (mod) \rangle,

This operation can be represented in a quantum circuit as:

.. figure:: ../../_static/templates/arithmetic/modexp.png
:align: center
:width: 60%
:target: javascript:void(0);

The implementation is based on the quantum Fourier transform method presented in
`arXiv:2311.08555 <https://arxiv.org/abs/2311.08555>`_.

.. note::

Note that :math:`x` must be smaller than :math:`mod` to get the correct result.
Also, it is required that :math:`base` has inverse, :math:`base^-1` modulo :math:`mod`.
That means :math:`base*base^-1 modulo mod = 1`, which will only be possible if :math:`base`
:math:`x` must be smaller than :math:`mod` to get the correct result.
Also, it is required that :math:`base` has inverse, :math:`base^{-1}` modulo :math:`mod`.
That means :math:`base \cdot base^{-1}` modulo :math:`mod` is equal to 1, which will only be possible if :math:`base`
and :math:`mod` are coprime.

.. seealso:: :class:`~.Multiplier`.

Args:
x_wires (Sequence[int]): the wires that store the integer :math:`x`
output_wires (Sequence[int]): the wires that store the exponentiation result
base (int): integer that needs to be exponentiated
mod (int): the modulus for performing the exponentiation, default value is :math:`2^{len(output\_wires)}`
work_wires (Sequence[int]): the auxiliary wires to be used for the exponentiation. There
must be as many as ``output_wires`` and if :math:`mod \neq 2^{len(x\_wires)}`, two more
wires must be added.
mod (int): the modulus for performing the exponentiation, default value is :math:`2^{\text{len(output_wires)}}`
work_wires (Sequence[int]): the auxiliary wires to be used for the exponentiation. There must be as many as ``output_wires`` and if :math:`mod \neq 2^{\text{len(output_wires)}}`, two more wires must be added.

**Example**

This example performs the exponentiation of :math:`base=2` to the power :math:`x=3` modulo :math:`mod=7`.

.. code-block::

x, k = 3, 1
x, b = 3, 1
base = 2
mod = 7

x_wires = [0, 1]
output_wires = [2, 3, 4]
work_wires = [5, 6, 7, 8, 9]

dev = qml.device("default.qubit", shots=1)
@qml.qnode(dev)
def circuit():
qml.BasisEmbedding(x, wires = x_wires)
qml.BasisEmbedding(k, wires = output_wires)
qml.BasisEmbedding(b, wires = output_wires)
qml.ModExp(x_wires, output_wires, base, mod, work_wires)
return qml.sample(wires = output_wires)

Expand All @@ -74,6 +83,33 @@ def circuit():

The result :math:`[0 0 1]`, is the ket representation of
:math:`2^3 \, \text{modulo} \, 7 = 1`.

.. details::
:title: Usage Details

This template takes as input three different sets of wires.

The first one is ``x_wires`` which is used
to encode the integer :math:`x < mod` in the computational basis. Therefore, we need at least
:math:`\lceil \log_2(x)\rceil` ``x_wires`` to represent :math:`x`.

The second one is ``output_wires`` which is used
to encode the integer :math:`b \cdot base^x (mod)` in the computational basis. Therefore, we need at least
:math:`\lceil \log_2(mod)\rceil` ``output_wires`` to represent :math:`b \cdot base^x (mod)`. Note that these wires can be initialized with any integer
:math:`b`, but the most common choice is :math:`b=1` to obtain as a final result :math:`base^x (mod)`.

The third set of wires is ``work_wires`` which consist of the auxiliary qubits used to perform the modular exponentiation operation.

- If :math:`mod = 2^{\text{len(output_wires)}}`, we will need as many as ``output_wires``.

- If :math:`mod \neq 2^{\text{len(output_wires)}}`, we will need as many as ``output_wires`` plus two extra that have to be provided.

Note that the ``ModExp`` template allows us to perform modular exponentiation in the computational basis. However if one just wants to perform standard exponentiation (with no modulo), the modulo
:math:`mod` has to be set large enough to ensure that :math:`base^x < mod`.

Also, to perform the out-place modular exponentiation operator it is required that :math:`base` has inverse, :math:`base^{-1} (mod)`. That means
:math:`base \cdot base^{-1}` modulo :math:`mod` is equal to 1, which will only be possible if :math:`base` and
:math:`mod` are coprime. In other words, :math:`base` and :math:`mod` should not have any common factors other than 1.
"""

grad_method = None
Expand Down Expand Up @@ -161,13 +197,13 @@ def compute_decomposition(
x_wires, output_wires, base, mod, work_wires
): # pylint: disable=arguments-differ
r"""Representation of the operator as a product of other operators.

Args:
x_wires (Sequence[int]): the wires that store the integer :math:`x`
output_wires (Sequence[int]): the wires that store the exponentiation result
base (int): integer that needs to be exponentiated
mod (int): the modulus for performing the exponentiation, default value is :math:`2^{len(output\_wires)}`
work_wires (Sequence[int]): the auxiliary wires to be used for the exponentiation. There must be as many as ``output_wires`` and if :math:`mod \neq 2^{len(x\_wires)}`, two more wires must be added.

mod (int): the modulus for performing the exponentiation, default value is :math:`2^{\text{len(output_wires)}}`
work_wires (Sequence[int]): the auxiliary wires to be used for the exponentiation. There must be as many as ``output_wires`` and if :math:`mod \neq 2^{\text{len(output_wires)}}`, two more wires must be added.
Returns:
list[.Operator]: Decomposition of the operator

Expand Down
Loading
Loading