-
Notifications
You must be signed in to change notification settings - Fork 575
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
Add OrbitalRotation operation #1665
Add OrbitalRotation operation #1665
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Amazing job!
I didn't find any issues, so I'm happy to approve from my side once a small change in the docstrings is made and we have confirmation that the tests are passing.
pennylane/ops/qubit/qchem_ops.py
Outdated
This operation performs a Givens rotation between the orbital bases in the Jordan-Wigner basis using a pair | ||
of parallel Givens gates :math:`G(\phi)`, which are equivalent to :class:`~.SingleExcitation()` operation. | ||
More precisely, for two neighbouring spatial orbitals :math:`\{|\Phi_{0}\rangle, |\Phi_{1}\rangle\}`, | ||
it performs the following transformation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This operation performs a Givens rotation between the orbital bases in the Jordan-Wigner basis using a pair | |
of parallel Givens gates :math:`G(\phi)`, which are equivalent to :class:`~.SingleExcitation()` operation. | |
More precisely, for two neighbouring spatial orbitals :math:`\{|\Phi_{0}\rangle, |\Phi_{1}\rangle\}`, | |
it performs the following transformation | |
For two neighbouring spatial orbitals :math:`\{|\Phi_{0}\rangle, |\Phi_{1}\rangle\}`, this operation | |
performs the following transformation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in the docstring.
More precisely, for two neighbouring spatial orbitals :math:`\{|\Phi_{0}\rangle, |\Phi_{1}\rangle\}`, | ||
it performs the following transformation | ||
|
||
.. math:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really clever way to summarize what the operation is doing! 🎉 🧠
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree!! really nice docstring 🙂
One suggestion: it would be nice to briefly describe the image (in this case, I wasn't originally sure what G(theta)
referred to, I assume givens rotations?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, now that I look at it again: it might be clearer to remove the single-excitation image, and in the text below, simply say
:math:`G(\phi)` represents a single-excitation Given's rotation,
implemented in PennyLane as the :class:`~.SingleExcitation` operation.
This way a reader can easily click on the link to read more about the SingleExcitation
operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I have added this to the documentation now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love it!
pennylane/ops/qubit/qchem_ops.py
Outdated
|
||
* Number of wires: 4 | ||
* Number of parameters: 1 | ||
* Gradient recipe: The ``OrbitalRotation`` operator satisfies a four-term parameter-shift rule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Gradient recipe: The ``OrbitalRotation`` operator satisfies a four-term parameter-shift rule | |
* Gradient recipe: The ``OrbitalRotation`` operator satisfies the four-term parameter-shift rule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated in the docstring.
# Additionally, there was a typo in the sign of a matrix element "s" at [2, 8], which is fixed here. | ||
|
||
phi = params[0] | ||
c = qml.math.cos(phi / 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great to see qml.math
in action!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same! it is really nice not needing to modify tf_ops.py
etc.
tests/ops/test_qubit_ops.py
Outdated
pytest.importorskip("autograd") | ||
|
||
dev = qml.device("default.qubit.autograd", wires=4) | ||
state = np.array( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did you compute this state as to avoid using the OrbitalRotation
operation? i.e., how do you know it's the correct state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd computed this state manually using the matrix definition of the gate (and cross-checked it with the mentioned transformation).
Codecov Report
@@ Coverage Diff @@
## master #1665 +/- ##
=======================================
Coverage 99.19% 99.19%
=======================================
Files 199 199
Lines 14835 14857 +22
=======================================
+ Hits 14715 14737 +22
Misses 120 120
Continue to review full report at Codecov.
|
pennylane/ops/qubit/qchem_ops.py
Outdated
|
||
>>> @qml.qnode(dev) | ||
... def circuit(phi): | ||
... qml.BasisState([1, 1, 0, 0], wires=[0, 1, 2, 3]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be:
qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I have fixed it now.
tests/ops/test_qubit_ops.py
Outdated
(0.1), | ||
], | ||
) | ||
def test_autograd_grad(self, phi): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to test different diff_method
s here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should. I have now added the diff_method
for this unit test as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR looks good to me @obliviateandsurrender, just left two comments. I am approving as I have already reviewed the new addition in a previous PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really nice PR @obliviateandsurrender! Left a small comment regarding adding a pytorch gradient test. Apart from that, don't forget to add an entry to the changelog!
More precisely, for two neighbouring spatial orbitals :math:`\{|\Phi_{0}\rangle, |\Phi_{1}\rangle\}`, | ||
it performs the following transformation | ||
|
||
.. math:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree!! really nice docstring 🙂
One suggestion: it would be nice to briefly describe the image (in this case, I wasn't originally sure what G(theta)
referred to, I assume givens rotations?)
More precisely, for two neighbouring spatial orbitals :math:`\{|\Phi_{0}\rangle, |\Phi_{1}\rangle\}`, | ||
it performs the following transformation | ||
|
||
.. math:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, now that I look at it again: it might be clearer to remove the single-excitation image, and in the text below, simply say
:math:`G(\phi)` represents a single-excitation Given's rotation,
implemented in PennyLane as the :class:`~.SingleExcitation` operation.
This way a reader can easily click on the link to read more about the SingleExcitation
operation.
pennylane/ops/qubit/qchem_ops.py
Outdated
>>> dev = qml.device('default.qubit', wires=4) | ||
|
||
>>> @qml.qnode(dev) | ||
... def circuit(phi): | ||
... qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3]) | ||
... qml.OrbitalRotation(phi, wires=[0, 1, 2, 3]) | ||
... return qml.state() | ||
|
||
>>> circuit(0.1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
>>> dev = qml.device('default.qubit', wires=4) | |
>>> @qml.qnode(dev) | |
... def circuit(phi): | |
... qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3]) | |
... qml.OrbitalRotation(phi, wires=[0, 1, 2, 3]) | |
... return qml.state() | |
>>> circuit(0.1) | |
>>> dev = qml.device('default.qubit', wires=4) | |
>>> @qml.qnode(dev) | |
... def circuit(phi): | |
... qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3]) | |
... qml.OrbitalRotation(phi, wires=[0, 1, 2, 3]) | |
... return qml.state() | |
>>> circuit(0.1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
# Additionally, there was a typo in the sign of a matrix element "s" at [2, 8], which is fixed here. | ||
|
||
phi = params[0] | ||
c = qml.math.cos(phi / 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same! it is really nice not needing to modify tf_ops.py
etc.
tests/ops/test_qubit_ops.py
Outdated
qml.OrbitalRotation(phi, wires=[0, 1, 2, 3]) | ||
return qml.expval(qml.PauliZ(0)) | ||
|
||
assert np.allclose(jax.grad(circuit)(phi), np.sin(phi)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@obliviateandsurrender could you add a PyTorch test here as well? Aside from that, great tests!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As requested I have added the PyTorch test cases. However, while doing so I faced a problem that the gradient results were returned as None
. After spending quite a good amount of time on this and also looking at torch_ops.py
, I concluded that defining the matrix for the operations as a single tensor
prevents torch
to calculate gradients during the backpropagation due to unavailability of the computation graph (as grad_fn
was coming out to be None
as well). To fix this, I decomposed the matrix definition into the summation of type func(phi)*matrix
. Do you think doing this is fine? Let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @obliviateandsurrender, nice catch -- pytorch can be very finicky with how matrices are defined.
No need to modify, but I'm curious if using qml.math.stack
to first stack each row of the array, and then stack all rows, would have worked with PyTorch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @josh146, you're right. Using qml.math.stack
indeed works! I think it would be much better to use this instead of the full decomposition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! let me know when the master merge conflict is resolved, and I will give it another review :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! The merge conflict with the master is resolved now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to go from my end @obliviateandsurrender, once @ixfoduap and @Jaybsoni also approve!
-0.04991671+0.j, 0. +0.j, 0. +0.j, | ||
0.99750208+0.j, 0. +0.j, 0. +0.j, | ||
0. +0.j]) | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changelog entry looks 💯
More precisely, for two neighbouring spatial orbitals :math:`\{|\Phi_{0}\rangle, |\Phi_{1}\rangle\}`, | ||
it performs the following transformation | ||
|
||
.. math:: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love it!
Co-authored-by: Josh Izaac <josh146@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Context:
This is the first part of the PRs aimed at adding the
GateFabric
template, which is based on the local, expressive, and quantum number preserving ansatz presented in arXiv:2104.05695.Description of the Change:
Function
OrbitalRotation
provides the implementation for the spin-adapted spatial orbital rotation gate which constitutes the gate required for developing the aforementioned template.Relevant UnitTests for
OrbitalRotation
operation.Benefits:
This operation will be required in the implementation of the
GateFabric
template.Possible Drawbacks:
No specific drawbacks.
Related GitHub Issues:
No related issues.