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

[WIP] Adds decomposition to DoubleExcitation operator (and update gradient recipes) #1303

Merged
merged 16 commits into from
May 14, 2021

Conversation

glassnotes
Copy link
Contributor

@glassnotes glassnotes commented May 12, 2021

Context: Currently DoubleExcitation is decomposed into DoubleExcitationPlus and DoubleExcitationMinus, neither of which are decomposed into elementary gates, such that DoubleExcitation cannot be implemented on all devices.

Description of the Change: Adds the decomposition into elementary gates based on this paper to DoubleExcitation. Furthermore, updates the gradient recipe of both SingleExcitation and DoubleExcitation to use the four-term parameter-shift rule of the aforementioned paper.

Benefits: DoubleExcitation can now run on any device; Single and Double excitation gradients are improved.

Possible Drawbacks: None

Related GitHub Issues: #1275 #1278

@codecov
Copy link

codecov bot commented May 13, 2021

Codecov Report

Merging #1303 (0554aea) into master (9687c13) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master    #1303   +/-   ##
=======================================
  Coverage   98.15%   98.15%           
=======================================
  Files         148      148           
  Lines       11357    11359    +2     
=======================================
+ Hits        11147    11149    +2     
  Misses        210      210           
Impacted Files Coverage Δ
pennylane/ops/qubit.py 98.36% <100.00%> (+<0.01%) ⬆️

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 9687c13...0554aea. Read the comment docs.

@glassnotes glassnotes marked this pull request as ready for review May 13, 2021 14:53
@glassnotes glassnotes changed the title [WIP] Adds decomposition to DoubleExcitation operator. [WIP] Adds decomposition to DoubleExcitation operator (and update gradient recipes) May 13, 2021
@@ -1707,14 +1707,13 @@ class SingleExcitation(Operation):

* Number of wires: 2
* Number of parameters: 1
* Gradient recipe: Obtained from its decomposition in terms of the
:class:`~.SingleExcitationPlus` and :class:`~.SingleExcitationMinus` operations
* Gradient recipe: The SingleExcitation operator satisfies a four-term parameter-shift rule
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dwierichs just to confirm, this is what you had in mind for enabling both operations to use the four-term shift rules?

Copy link
Contributor

Choose a reason for hiding this comment

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

yes, exactly :)

Copy link
Contributor

@antalszava antalszava 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 to me! 💯 🥇 this is very helpful, thank you for going so far to get this one! 🎉

Comment on lines +159 to +162
* The `qml.SingleExcitation` and `qml.DoubleExcitation` operations now
have decompositions over elementary gates, and their gradient recipes
have been updated to use the four-term parameter-shift rules.
[(#1303)](https://github.com/PennyLaneAI/pennylane/pull/1303)
Copy link
Contributor

Choose a reason for hiding this comment

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

🥳 🥳 🥳

pennylane/ops/qubit.py Outdated Show resolved Hide resolved
pennylane/ops/qubit.py Outdated Show resolved Hide resolved
mats = []
for i in reversed(decomp):
if i.wires.tolist() == [1, 0] and isinstance(i, qml.CRY):
new_mat = np.array(
Copy link
Contributor

Choose a reason for hiding this comment

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

(minor): We could potentially have a separate function e.g., cry_target_first in the gate_data.py file that could be called here and in the other test cases. This is out of scope, as it means a bit of organization also for test_single_excitation_plus_decomp and test_single_excitation_minus_decomp.

This would just be a step towards making this file slightly more organized, as the matrix representation of controlled-operations where the wires are in a non-ascending order start coming up in the tests for decompositions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would be super useful to have just in general. We could actually have something very generic, like:

def non_adjacent_controlled_mat(U, wires, num_wires):
    ...

And then return the matrix where C-U is applied to wires in a num_wires-qubit system. (Basically, what I have implemented in the DoubleExcitation test; and similarly for a random single-qubit gate sitting on a qubit amidst other qubits, if that doesn't already exist somewhere).

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 will make an issue for this so we don't forget to address it in the future 👍

tests/ops/test_qubit_ops.py Outdated Show resolved Hide resolved
tests/ops/test_qubit_ops.py Outdated Show resolved Hide resolved
tests/ops/test_qubit_ops.py Outdated Show resolved Hide resolved
Comment on lines 1283 to 1284
P0 = np.array([[1, 0], [0, 0]])
P1 = np.array([[0, 0], [0, 1]])
Copy link
Contributor

Choose a reason for hiding this comment

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

How about moving these into gate_data and maybe naming them state_zero_projector and state_one_projector?

The pro is that it'll make the test shorter, although it will also be less explicit. So if it would look less readable (as the names are not descriptive enough), then leaving this as is the way to go.

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 didn't know about gate_data 😅 that's a good idea. These projectors are quite commonly used, so I think it's worth having them in there. I will call them perhaps StateZeroProjector and StateOneProjector to match the existing capitalization conventions if that works.

Copy link
Contributor

@ixfoduap ixfoduap left a comment

Choose a reason for hiding this comment

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

Looks great! @glassnotes: you make this look so easy! 🧙

decomp_ops = [
DoubleExcitationPlus(theta / 2, wires=wires),
DoubleExcitationMinus(theta / 2, wires=wires),
qml.CNOT(wires=[wires[2], wires[3]]),
Copy link
Contributor

Choose a reason for hiding this comment

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

Yikes! Makes this building block look less like a fundamental one 😅
Still, not too bad in the end!

decomposed_matrix = mats[0] @ mats[1]
"""Tests that the SingleExcitation operation calculates the correct decomposition.

Need to consider the matrix of CRY separately, as the control is wire 1
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this change to the single excitation gate being done in this PR? Just sneaking it in?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's because we are updating the gradient recipes for both gates to the four-term shift rules; so the SingleExcitation decomposition is adjusted accordingly.

tests/ops/test_qubit_ops.py Outdated Show resolved Hide resolved

from functools import reduce

# To compute the matrix for CX on an arbitrary number of qubits, use the fact that
Copy link
Contributor

Choose a reason for hiding this comment

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

🧠

Co-authored-by: ixfoduap <40441298+ixfoduap@users.noreply.github.com>
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

4 participants