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

[TEMPLATES] Rewrite subroutines as operations #1192

Merged
merged 11 commits into from
Apr 8, 2021
Merged

Conversation

mariaschuld
Copy link
Contributor

@mariaschuld mariaschuld commented Apr 7, 2021

This is the fourth PR to refactor the templates (following 1156, 1163 and 1190).

Changes:

  • Templates are turned into operations, so that the decomposition is executed in the expand function.
  • The pre-processing was moved into the __init__ function.
  • The tests were moved into a separate file and extended. Usually, the tests for custom wire labels, shape method and gradients are new, the rest is ported and adapted.
  • Docstrings were improved.
  • If the template takes weights, a method to return the shape of the weights was added.

Drawbacks:
Interferometer was not refactored, because an operation of that name already exists. Will make a separate PR with a deprecation warning!

@mariaschuld mariaschuld marked this pull request as draft April 7, 2021 08:46
Hadamard(wires=r)
RX(-np.pi / 2, wires=q)
Hadamard(wires=p)
qml.Hadamard(wires=s)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just to be consistent...trying to import as little as possible.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if this matters here, but having objects in a more local namespace improves speed slightly.

For example, calling CNOT(wires=0,1) is 4% faster than qml.CNOT(wires=(0,1)), but that is a difference of 3.85 microseconds to 4.01 microseconds. It can add up if something gets called many times, but we usually have bigger things to worry about.

wires1 (Iterable or Wires): Wires of the qubits representing the subset of occupied orbitals
in the interval ``[s, r]``. Accepts an iterable of numbers or strings, or a Wires object,
with minimum length 2. The first wire is interpreted as ``s`` and the last wire as ``r``.
weight (float or tensor_like): angle :math:`\theta` entering the Z rotation acting on wire ``p``
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added tensor_like, because the scalar could also be a 0-dim tensor...

the last wire is interpreted as ``p``. Wires in between are acted on with CNOT gates
to compute the parity of the set of qubits.

Raises:
ValueError: if inputs do not have the correct format

Copy link
Contributor Author

Choose a reason for hiding this comment

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

PL does not declare "Raises" anywhere else, so removing them from docstrings


self.wires1 = list(wires1)
self.wires2 = list(wires2)
wires = wires1 + wires2
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here I am trying to parse to wires as late as possible (i.e. in the parent function called by super). This is a result of the insight that parsing to Wires is costly...

import pennylane as qml
from pennylane.wires import Wires


Copy link
Contributor Author

@mariaschuld mariaschuld Apr 7, 2021

Choose a reason for hiding this comment

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

These tests were just moved for now...

@mariaschuld mariaschuld changed the title [WIP] [TEMPLATES] Rewrite subroutines as operations [TEMPLATES] Rewrite subroutines as operations Apr 7, 2021
@mariaschuld mariaschuld marked this pull request as ready for review April 7, 2021 12:27
@codecov
Copy link

codecov bot commented Apr 7, 2021

Codecov Report

Merging #1192 (146ec84) into master (8480ab7) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #1192   +/-   ##
=======================================
  Coverage   98.12%   98.13%           
=======================================
  Files         145      145           
  Lines       10903    10941   +38     
=======================================
+ Hits        10699    10737   +38     
  Misses        204      204           
Impacted Files Coverage Δ
...ane/templates/subroutines/approx_time_evolution.py 100.00% <100.00%> (ø)
...nnylane/templates/subroutines/arbitrary_unitary.py 100.00% <100.00%> (ø)
...templates/subroutines/double_excitation_unitary.py 100.00% <100.00%> (ø)
pennylane/templates/subroutines/permute.py 100.00% <100.00%> (ø)
pennylane/templates/subroutines/qmc.py 100.00% <100.00%> (ø)
pennylane/templates/subroutines/qpe.py 100.00% <100.00%> (ø)
...templates/subroutines/single_excitation_unitary.py 100.00% <100.00%> (ø)
pennylane/templates/subroutines/uccsd.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8480ab7...146ec84. Read the comment docs.

Copy link
Contributor

@albi3ro albi3ro left a comment

Choose a reason for hiding this comment

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

Looks good!

I left some minor feedback, but nothing that would block merging.

I stopped looking at the tests with as much detail at some point, so I'll trust you on some of that.

from `Operation`, and define the ansatz in their `expand()` method. This
change does not affect the user interface.
[(#1138)](https://github.com/PennyLaneAI/pennylane/pull/1138)
[(#1156)](https://github.com/PennyLaneAI/pennylane/pull/1156)

For convenience, `BasicEntanglerLayers` has a method that returns the shape of the
trainable parameter tensor, i.e.,
For convenience, some templates now have a method that returns the expected
Copy link
Contributor

Choose a reason for hiding this comment

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

enumerate which ones?


# Apply the seventh layer
_layer7(weight, s, r, q, p, set_cnot_wires)
_layer1(weight, s, r, q, p, set_cnot_wires)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we make the layer functions members of the class?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's fine this way - they are not user facing anyways.

Actually, these templates may be deprecated soon!

Hadamard(wires=r)
RX(-np.pi / 2, wires=q)
Hadamard(wires=p)
qml.Hadamard(wires=s)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if this matters here, but having objects in a more local namespace improves speed slightly.

For example, calling CNOT(wires=0,1) is 4% faster than qml.CNOT(wires=(0,1)), but that is a difference of 3.85 microseconds to 4.01 microseconds. It can add up if something gets called many times, but we usually have bigger things to worry about.

pennylane/templates/subroutines/qpe.py Show resolved Hide resolved
def test_jax(self, tol):
"""Tests the jax interface."""

jax = pytest.importorskip("jax")
Copy link
Contributor

Choose a reason for hiding this comment

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

👍 got that this time :)


res = circuit(weights)
res2 = circuit2(weights)
assert qml.math.allclose(res, res2, atol=tol, rtol=0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Says list_and_tuples but only tests for weights as a list. I remember seeing a similar test before that then executed the circuits with:

weights = tuple(weights)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right - renamed the test to check a scalar float.


res = circuit(weights)
res2 = circuit2(weights)
assert qml.math.allclose(res, res2, atol=tol, rtol=0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do some use qml.math.allclose but other use np.allclose?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because the results of the circuits are tensor objects in the interface that the test used :/

@mariaschuld
Copy link
Contributor Author

Thanks @albi3ro.

About this comment, I did not know about the speed difference. Will keep that in mind!

@mariaschuld mariaschuld merged commit 4ece39a into master Apr 8, 2021
@mariaschuld mariaschuld deleted the rewrite-subroutines branch April 8, 2021 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants