-
Notifications
You must be signed in to change notification settings - Fork 347
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
Fix spurious PHASE and conditional in exponential_map #1182
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,7 +24,7 @@ | |
import numpy as np | ||
import pytest | ||
|
||
from pyquil.gates import RX, RZ, CNOT, H, X, PHASE | ||
from pyquil.gates import RX, RZ, CNOT, H | ||
from pyquil.paulis import ( | ||
PauliTerm, | ||
PauliSum, | ||
|
@@ -421,15 +421,21 @@ def test_exponentiate_identity(): | |
generator = PauliTerm("I", 1, 1.0) | ||
para_prog = exponential_map(generator) | ||
prog = para_prog(1) | ||
result_prog = Program().inst([X(0), PHASE(-1.0, 0), X(0), PHASE(-1.0, 0)]) | ||
result_prog = Program() | ||
assert prog == result_prog | ||
|
||
generator = PauliTerm("I", 10, 0.08) | ||
para_prog = exponential_map(generator) | ||
prog = para_prog(1) | ||
result_prog = Program().inst([X(0), PHASE(-0.08, 0), X(0), PHASE(-0.08, 0)]) | ||
result_prog = Program() | ||
assert prog == result_prog | ||
|
||
pop = 0.0 * sX(0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: since this term is no longer Also, a short comment explaining the "why" of this test would be nice. If someone ever changes the implementation and this test breaks, they'll be left wondering whether it's ok to delete the test, etc. Just a short note like "This is testing an implementation detail. Users are not expected to do this. blah blah blah." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re: the section. Oh yeah, I was tired, will fix that.
Great point. I'll add a comment. |
||
expprog = exponential_map(pop) | ||
assert expprog(0.5) == Program() | ||
pop.coefficient = 1.0 | ||
assert expprog(0.5) == Program() | ||
|
||
|
||
def test_trotterize(): | ||
term_one = PauliTerm("X", 0, 1.0) | ||
|
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 don't have a good sense for how likely it is that anyone depended on the old behavior. Do you think it's worth calling out in the changelog here that this is a potentially user visible / breaking change?
Likewise, should this go under the "Improvements and Changes" section, or is this more of a bugfix?
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
qc.compiler.native_quil_to_executable(Program())
will fail with an error about an empty program.exponential_map
, with the PHASE instructions etc, was correct in that the corresponding quantum operation was the identity.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.
Agreed.
That's a good point. There are two issues. The one about the empty program only concerns removing
PHASE
, not the inside-outside the closure one. The more I think about it, the more I think these should not both be changed in the same PR. Each one separately could break code.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 brings up the (somewhat painful now that we've been through multiple rounds of code review already :D) question of whether these changes are really worth it, since they might break user code, however unlikely.
I don't have a strong opinion either way. I agree it seems pretty unlikely anyone was depending on the old behavior, but you'd be surprised.
I also admit that I don't understand the use cases well enough to understand why the phase thing in the identity case is annoying / undesirable, so I defer to others on that one.
As for the inside-out closure change, I agree the new version is an improvement, but in the absence of any users complaining about it, I'd be inclined to let a sleeping dog lie. I also won't make a stink though if others feel like it's a minor enough breakage that it shouldn't matter... Maybe we should have a label for github issues that introduce breaking changes, to mark them for inclusion on some bright future day when we do a major version bump?
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.
Well, this is certainly not urgent, and it's somewhat contentious. The closure thing is just about code quality and clarity, not user experience.
AFAICT it was put there for some kind of testing or debugging purpose. It has no business being there in the production code. It is not even documented! You could debate like this though
Pro PHASE:
If the user asked for
exponential_map
of the identity, then we should not second guess the motive. We should return a function that does something non-trivial with it's parameter (phase angle) and still gives the correct behavior. Rotating back and forth is probably the simplest thing you can do. And, I guess do it on qubit zero, because... why put it on a different one ?Anti PHASE:
exponential_map
will be called on gates that were generated programmatically, not literally. The user would expect that it does the economic thing, eliding the operation on the identity. And certainly would expect that it does not do something arbitrary like play with the first qubit. Furthermore, if a nontrivial program is returned, It will later be elided by the compiler in any case.