Skip to content

cirq.measure - accept list arguments #5411

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

Conversation

pavoljuhas
Copy link
Collaborator

@pavoljuhas pavoljuhas commented May 26, 2022

Allow passing qubits for cirq.measure and cirq.measure_each in
a single iterable argument.
Keep accepting them as variable-length arguments as before.

Fixes #2408.

ndarray docstring advises to use np.array for array creation.
Not yet ready, expecting test failure.
Allow variable-length arguments as well as iterables.

Resolve quantumlib#2408
@pavoljuhas pavoljuhas requested review from a team, vtomole and cduck as code owners May 26, 2022 22:22
@pavoljuhas pavoljuhas requested a review from dabacon May 26, 2022 22:22
@CirqBot CirqBot added the size: S 10< lines changed <50 label May 26, 2022
@maffoo
Copy link
Contributor

maffoo commented May 26, 2022

I think allowing arbitrarily nested lists of Qids is probably more flexibility than we want to allow. I'd suggest that we accept either Qids as varargs, or a single iterable arg containins Qids. It should be possible to use @overload types to express this to mypy in addition to the runtime handling of different args.

@pavoljuhas
Copy link
Collaborator Author

I think allowing arbitrarily nested lists of Qids is probably more flexibility than we want to allow. I'd suggest that we accept either Qids as varargs, or a single iterable arg containins Qids. ...

Sounds good to me, but Gate.on_each() already accepts a mix of varargs and possibly nested sequences.
The issue at hand (#2408) asks for a similar interface in cirq.measure().
If we leave it as is we'll get a consistent behavior in what those 2 functions can digest.

for target in targets:
if isinstance(target, Qid):
operations.append(self.on(target))
elif isinstance(target, Iterable) and not isinstance(target, str):
operations.extend(self.on_each(*target))
else:

@maffoo
Copy link
Contributor

maffoo commented May 27, 2022

The Gate.on_each implementation is a bit confused because how it behaves depends on the number of qubits the gate expects. For single-qubit gates, it allows combinations of varargs and arbitrarily-nested sequences, as you point out:

In [1]: a, b, c, d = cirq.LineQubit.range(4)

In [2]: cirq.H.on_each([[[[a]]]], b, [[c], [[d]]])
Out[2]: 
[cirq.H(cirq.LineQubit(0)),
 cirq.H(cirq.LineQubit(1)),
 cirq.H(cirq.LineQubit(2)),
 cirq.H(cirq.LineQubit(3))]

but for multi-qubit gates it only allows either varargs or a single sequence of sequences of qids:

n [3]: cirq.CZ.on_each((a, b), (c, d))
Out[3]: 
[cirq.CZ(cirq.LineQubit(0), cirq.LineQubit(1)),
 cirq.CZ(cirq.LineQubit(2), cirq.LineQubit(3))]

In [4]: cirq.CZ.on_each([(a, b), (c, d)])
Out[4]: 
[cirq.CZ(cirq.LineQubit(0), cirq.LineQubit(1)),
 cirq.CZ(cirq.LineQubit(2), cirq.LineQubit(3))]

In [5]: cirq.CZ.on_each([(a, b)], [(c, d)])
...
ValueError: All values in sequence should be Qids, but got [(cirq.LineQubit(0), cirq.LineQubit(1))]

I'm not sure if this behavior for single-qubit gates was intentional, but I'd be surprised if it were. I think just accepting gate.on_each(a, b, c, d) or gate.on_each([a, b, c, d]) would be sufficient, and calling with some deeply nested list is more likely an unintentional error on the part of the caller that we should flag rather than allow.

For cirq.measure I'd suggest that rather than emulating the current behavior of Gate.on_each, we should take the more conservative approach and just allow cirq.measure(a, b, c, d) or cirq.measure([a, b, c, d]), but not arbitrarily nested sequences.

Whatever we decide to do, we should probably also modify cirq.measure_each (which produces separate single-qubit measure gates for each qubit, rather than one measure gate for all of them) in the same way, so that it stays consistent with cirq.measure.

@pavoljuhas
Copy link
Collaborator Author

@maffoo - sounds good, I will adjust it that way.
Thanks for pointing out measure_each needs the same change.

Simplify arguments handling - qubits must be either passed
in a single iterable argument or as multiple scalar arguments.
Not yet ready, expecting test failure.
Accept qubits in variable-length arguments or as a single
argument which must be an iterable of qubits.
@pavoljuhas
Copy link
Collaborator Author

Ready for next review. I am not entirely sure if I got right the typing in function implementations after @overload.

Copy link
Contributor

@maffoo maffoo left a comment

Choose a reason for hiding this comment

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

One minor comment, then LGTM.

pavoljuhas and others added 2 commits May 28, 2022 16:36
Accept exactly one argument when it is an iterable of qubits.

Co-authored-by: Matthew Neeley <[email protected]>
Accept exactly one argument when it is an iterable of qubits.
@pavoljuhas
Copy link
Collaborator Author

nit: Could modify this slightly to accept exactly one arg

Done. Thank you for the mypy tip on double underscore!

@pavoljuhas
Copy link
Collaborator Author

@dabacon, @cduck, @vtomole - PTAL.

Copy link
Collaborator

@dabacon dabacon left a comment

Choose a reason for hiding this comment

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

LGTM

@dabacon dabacon added the automerge Tells CirqBot to sync and merge this PR. (If it's running.) label Jun 6, 2022
@CirqBot CirqBot added the front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. label Jun 6, 2022
@CirqBot CirqBot merged commit 35a6b60 into quantumlib:master Jun 6, 2022
@CirqBot CirqBot removed automerge Tells CirqBot to sync and merge this PR. (If it's running.) front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. labels Jun 6, 2022
@pavoljuhas pavoljuhas deleted the cirq-measure-accept-list-arguments branch June 6, 2022 22:40
rht pushed a commit to rht/Cirq that referenced this pull request May 1, 2023
Allow passing qubits for `cirq.measure` and `cirq.measure_each` in
a single iterable argument.  
Keep accepting them as variable-length arguments as before.

Fixes quantumlib#2408.
harry-phasecraft pushed a commit to PhaseCraft/Cirq that referenced this pull request Oct 31, 2024
Allow passing qubits for `cirq.measure` and `cirq.measure_each` in
a single iterable argument.  
Keep accepting them as variable-length arguments as before.

Fixes quantumlib#2408.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size: S 10< lines changed <50
Projects
None yet
Development

Successfully merging this pull request may close these issues.

cirq.measure should accept List[Qid] the same way "on_each" does.
5 participants