-
Notifications
You must be signed in to change notification settings - Fork 9
feat!: add named measurements #479
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
4be14f1
feat!: add optional `!name` to `MEASURE`
antalsz d827767
feat!: add optional `!name` to `DEFCAL MEASURE` and update calibratio…
antalsz 1d5fd19
feat: make Python change to `MeasureCalibrationIdentifier` nonbreaking
antalsz 4023589
fix: make the linter happy
asaites 0554cdf
fix: use `__getnewargs_ex__`
antalsz 5422de1
feat: same changes for `Measurement`
antalsz f2124bb
test: fix test
antalsz 129f562
docs: use specific stub type for __getnewargs_ex__
asaites File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
...alibration__test_measure_calibration_definition__display@Named Effect Variable Qubit.snap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| source: quil-rs/src/instruction/calibration.rs | ||
| expression: measure_cal_def.to_quil_or_debug() | ||
| --- | ||
| DEFCAL MEASURE!midcircuit q: | ||
| X(pi) q |
6 changes: 6 additions & 0 deletions
6
...ibration__test_measure_calibration_definition__display@Named Effect With Fixed Qubit.snap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| source: quil-rs/src/instruction/calibration.rs | ||
| expression: measure_cal_def.to_quil_or_debug() | ||
| --- | ||
| DEFCAL MEASURE!midcircuit 0: | ||
| X(pi) 0 |
6 changes: 6 additions & 0 deletions
6
...on__calibration__test_measure_calibration_definition__display@Named With Fixed Qubit.snap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| source: quil-rs/src/instruction/calibration.rs | ||
| expression: measure_cal_def.to_quil_or_debug() | ||
| --- | ||
| DEFCAL MEASURE!midcircuit 0 theta: | ||
| X(%theta) 0 |
6 changes: 6 additions & 0 deletions
6
..._calibration__test_measure_calibration_definition__display@Named With Variable Qubit.snap
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| source: quil-rs/src/instruction/calibration.rs | ||
| expression: measure_cal_def.to_quil_or_debug() | ||
| --- | ||
| DEFCAL MEASURE!midcircuit q theta: | ||
| X(%theta) q |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Since the
Qubitis no longer optional, I don't think there's a way for this to not be a breaking change forPyQuil, as I see no obvious "default" qubit to supply.And based on what I've read of your proposed changes to the Quil spec, I'm guessing it probably should always have been required? I don't see a way to make sense of "measure this qubit" without knowing which one.
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, this is just a bug – somebody had a thinko, and instead of "required qubit and optional memory location" implemented "optional qubit and required memory location", which as you say makes no sense – and isn't even compatible with
MEASURE, which correctly takes a required qubit and an optional memory location. And if you look at the parser, you'll see some very strange code which could for instance result in aDEFCAL MEASUREthat (a) measures no qubits, but (b) puts the result into the memory location named"0".I wonder if we should move this fix back with the
CalibrationDefinitionname change, if you think that'll help things go more smoothly? My thinking was thatMeasureCalibrationDefinitionhad to change anyway, to accommodate the new!name, but if you think it would make for a softer landing I could pull this fix out.Uh oh!
There was an error while loading. Please reload this page.
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'm inclined to say "yes" specifically to the change for making
qubitrequired andparameteroptional. That part has to be a breaking change forpyQuil, but the rest we could work-around; I've detailed some of that below and am interested in your thoughts with respect to how wellquil-rs,quil, andpyQuilshould match with respect to constructor signatures.My thought is about the effect on
pyQuilusers specifically, avoiding 2 major version bumps back-to-back. We should be able to prevent that by simply not releasing a newpyQuilright away, though I think we need to change the version specifier forquilin its dependency list to prevent it from trying to grab the newer release before we're ready (given that this project is currently pre-1.0, that probably should have always been the case).pyQuildoesn't actually have its own notion of aMeasureCalibrationIdentifier-- it just hasDefMeasureCalibration(corresponding toMeasureCalibrationDefinition), with (roughly) this constructor:So the breaking change is here:
class DefMeasureCalibration(quil_rs.MeasureCalibrationDefinition, AbstractInstruction): def __new__( cls, - qubit: Qubit | FormalArgument | None, + qubit: Qubit | FormalArgument, memory_reference: MemoryReference, instrs: list[AbstractInstruction], ) -> Self: """Initialize a new measure calibration definition.""" - rs_qubit = None if not qubit else _convert_to_rs_qubit(qubit) + rs_qubit = _convert_to_rs_qubit(qubit) ident = quil_rs.MeasureCalibrationIdentifier(rs_qubit, str(memory_reference)) return super().__new__(cls, ident, _convert_to_rs_instructions(instrs))And then to add support for named measurements, we could make this non-breaking change (assuming the constructor signature for
MeasureCalibrationIdentifieryou've proposed in this PR):class DefMeasureCalibration(quil_rs.MeasureCalibrationDefinition, AbstractInstruction): def __new__( cls, qubit: Qubit | FormalArgument, memory_reference: MemoryReference, instrs: list[AbstractInstruction], + name: str | None = None, ) -> Self: """Initialize a new measure calibration definition.""" rs_qubit = _convert_to_rs_qubit(qubit) - ident = quil_rs.MeasureCalibrationIdentifier(rs_qubit, str(memory_reference)) + ident = quil_rs.MeasureCalibrationIdentifier(name, rs_qubit, str(memory_reference)) return super().__new__(cls, ident, _convert_to_rs_instructions(instrs))As a point of interest, we could essentially make the same sort of transition within
quilto avoid two breaking changes. First we'd make this breaking change:pickleable_new! { impl MeasureCalibrationIdentifier { - pub fn new(qubit: Option<Qubit>, parameter: String); + pub fn new(qubit: Qubit, target: Option<String>); } }With that, this wouldn't be a breaking change:
pickleable_new! { impl MeasureCalibrationIdentifier { - pub fn new(qubit: Qubit, target: Option<String>); + #[pyo3(signature = (qubit, target, name=None))] + pub new(qubit: Qubit, target: Option<String>, name: Option<String>); } }Of course, this requires we add the
nameparameter to the end in order to give it a default value.We could have a separate constructor specifically for
quil, if you really wanted the Rust constructor's parameter order to match their order within the Quil language construct. It would also be possible (though more complex) to write out an overloaded signature and sort out the details of which version you meant ourselves, but that wouldn't be my recommendation in the face of the above options.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.
Two separate thoughts:
Re the existing
DEFCAL MEASUREbug: sounds like, due to the way Python works, the breaking change if any will actually be pretty small. I'll move it back along with the other change regardless, though, it'll be nice to be uniform.I thought about this issue with defaults, and I'm torn. On the Rust side, I think putting the name first is a win – you have to write
Noneanyway, so you might as well put it in the logical order. On the Python side… I don't know! I think there's also a good argument forfor this and for
MEASURE, since that lets you create the simple case simply. Perhaps the move is to leave this a breaking change in quil-py, and have the pyQuil wrapper do the default-parameter dance?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 included the
DEFCAL MEASUREfix in #482. The discussion about point 2 can continue though!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.
In this particular case, it's moot:
pyQuildoesn't have its ownMeasureCalibrationIdentifier, and its signature forDefMeasureCalibrationalready diverges fromMeasureCalibrationDefinition(to say nothing of the name difference). Handling the parameter ordering is no burden for this instance, and makingqubitrequired is a breaking change no matter what.In the bigger picture, we want Python users to have an ergonomic experience working with
quil-rs. It's been fuzzy whether that responsibility falls onquilor should be handled in a higher-level wrapper likepyQuil. Right now,pyQuil's subclasses mostly exist to support things like "accept a Python number where anExpression.Numberis expected". That's the kind of ergonomics we want, but having all those extra classes has proven itself a significant maintenance burden. Moving forward, our goal should be getting rid of those subclasses and havingpyQuilmanipulatequil's constructs directly when appropriate.Doing that initially will, of course, be a major breaking change. Then, without the layer in between,
quilwill be more responsible for avoiding breaking changes. It might sound like that gets a lot harder without the extra layer, but the reality is thatquil-pyis precisely the compatibility layer betweenquilandquil-rs! Then the question becomes how far we want to let the Python version of things diverge from their Rust counterparts, as for example having a constructor with different parameter ordering. I don't know offhand how heavy a burden divergence there will create, but my instinct is that we should minimize differences whenever possible.So with respect to adding the new constructor parameter (necessarily a breaking change for
quil-rs), the options are:quil, with the newnameparameter at the beginning of the list, making it a breaking change forquil(and potentiallypyQuil, depending on when it lands).quil, but add the newnameparameter to the end of the list, potentially at the cost of making it less ergonomic for Rust users or those very familiar with Quil. Use thepyo3signature to avoid a breaking change forquil.quil, using thepyo3signature to avoid a breaking change, and deal with the consequences the divergence may entail.Putting it in these terms makes me think (2) is the right way forward. Do you think I'm on the right track?
Uh oh!
There was an error while loading. Please reload this page.
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 that’s convincing, yeah! I’d amend it very slightly: make the gate name parameter last but named-only, as in my snippet above. This gives us multiple virtues:
I can make that change to
MEASUREandDEFCAL MEASURE.