-
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
Tape expansion reserves value of the is_sampled attribute #1027
Conversation
…e ret type doesn't get queued)
Hello. You may have forgotten to update the changelog!
|
Codecov Report
@@ Coverage Diff @@
## master #1027 +/- ##
=======================================
Coverage 97.93% 97.93%
=======================================
Files 153 153
Lines 11392 11394 +2
=======================================
+ Hits 11157 11159 +2
Misses 235 235
Continue to review full report at Codecov.
|
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 fix @antalszava. 💯 Now the demo works with tape mode!
pennylane/tape/qnode.py
Outdated
# Check the observables without needing to create the circuit graph | ||
self.qtape.is_sampled = any(obs.return_type == Sample for obs in self.qtape.observables) |
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 catch @antalszava! 💯
I'm just wondering why the is_sampled
method was changed to an attribute. Maybe this is nicer (and a bit more effective) to have it this way rather than always checking for Sample
return types in the observables. 🤔
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.
Hmm, so is_sampled
is an attribute of QuantumTape
, but a property of the CircuitGraph
. Here at times, the circuit graph was not constructed, so simply checking the observables directly avoids the overhead of constructing the circuit graph
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 mean, an option would be to have QuantumTape.is_sampled
a property instead of an attribute, as is the case for CircuitGraph
. No need to create the graph in either case; it would be a small change. I'm not really advocating for either though, just a bit curious about the reasoning. 🙂
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.
Hmm, so is_sampled is an attribute of QuantumTape, but a property of the CircuitGraph.
This was likely my fault, I didn't check that it was a property on the graph and just made it an attribute on the tape. However,
-
this is probably not too much of an issue, since the tape is designed to be (mostly) non-mutable, whereas the circuit graph was very mutable.
-
It was mostly a temporary fix, I needed the tape to 'look' like a CircuitGraph from a duck-typing perspective, so that existing devices would accept it. With the thinking that soon we would be able to drop this backward compatibility :)
@@ -840,6 +840,26 @@ def test_expand_tape_multiple_wires_non_commuting(self, ret): | |||
with pytest.raises(qml.QuantumFunctionError, match="Only observables that are qubit-wise"): | |||
tape.expand(expand_measurements=True) | |||
|
|||
def test_is_sampled_reserved_after_expansion(self, monkeypatch, mocker): |
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.
(thinking aloud) I think this test looks good, but I'm contemplating whether this is too broad of a test (not unit-test-like enough), but I'm not sure how to do it otherwise.
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, think that's a fair point. One thing I found challenging with creating more of a unit test is that a tape is created and expanded in QNode.construct
along with other updates (perhaps later down the line we could think about separating these into different methods).
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.
Without being to familiar with writing tests, etc. I would say a good option could simply be to be better at separating the unit tests and the integration tests (and this could perhaps be part of the latter, right?). Then no unit test would be needed for this case at all.
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.
Hmm, it seems that integration tests were not too separated so far for tapes. Might just leave it here for now and we could move it if we start the separation into a new file.
pennylane/tape/operation.py
Outdated
# TODO: rename the following usage of JacobianTape to better describe that | ||
# it's used for operation expansion |
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 you mean simply renaming it to e.g. op_expansion_tape
? I'm not against it per se, but I'm thinking it's quite clear already from the method + docstring, and it's only restricted to this quite small method. Maybe this is just something that can be done in this PR (since it's a very small, cosmetic change only) in that case instead of leaving it as a future TODO? 🙂
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 comment more so implies that we are creating a JacobianTape
which is not necessarily used for jacobian computations. Perhaps we could a) rename JacobianTape
or b) create a new type of tape that is more specific to tape expansions.
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.
Oh, I see. In that case, this is a bit more complex. I though you meant renaming the name tape
and not the tape Jacobiantape
. 😆
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.
Oh good catch @antalszava! I just had a look at the source code for QuantumTape.expand()
, and it looks like this doesn't need to be a JacobianTape
, you should be able to replace it with a simple QuantumTape
with no side effect.
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.
Thanks Antal for finding this! 💯
Happy for it to be merged as is. One (minor) question though: would it be better to have this at the end of tape expansion, rather than in the QNode? E.g., around here?
pennylane/pennylane/tape/tapes/tape.py
Line 150 in 2ae0263
new_tape._measurements += expanded_tape._measurements |
pennylane/tape/operation.py
Outdated
# TODO: rename the following usage of JacobianTape to better describe that | ||
# it's used for operation expansion |
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.
Oh good catch @antalszava! I just had a look at the source code for QuantumTape.expand()
, and it looks like this doesn't need to be a JacobianTape
, you should be able to replace it with a simple QuantumTape
with no side effect.
pennylane/tape/qnode.py
Outdated
# Check the observables without needing to create the circuit graph | ||
self.qtape.is_sampled = any(obs.return_type == Sample for obs in self.qtape.observables) |
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.
Hmm, so is_sampled is an attribute of QuantumTape, but a property of the CircuitGraph.
This was likely my fault, I didn't check that it was a property on the graph and just made it an attribute on the tape. However,
-
this is probably not too much of an issue, since the tape is designed to be (mostly) non-mutable, whereas the circuit graph was very mutable.
-
It was mostly a temporary fix, I needed the tape to 'look' like a CircuitGraph from a duck-typing perspective, so that existing devices would accept it. With the thinking that soon we would be able to drop this backward compatibility :)
Co-authored-by: Josh Izaac <josh146@gmail.com>
…nylane into tape_expand_sampled
Thanks so much for the suggestions!
|
Context:
Devices that do not support an operation try to apply its decomposition. In tape mode this triggers tape expansion. However, in such cases, new tapes are being created and information for the
is_sampled
attribute is lost.This causes problems when
analytic=True
is set under the hood and the QNode returns samples:Description of the Change:
is_sampled
attribute after tape expansion.Benefits:
CircuitGraph
object can be queried to get this information. However, as the circuit graph is not necessarily constructed after circuit expansion, it is less costly to simply iterate over the observables without constructing the circuit graph.Possible Drawbacks:
N/A
Related GitHub Issues:
Demo using the Cirq plugin.