Skip to content
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 cirq.Simulator assuming a reset is safe to cache before sampling #3093

Merged
merged 7 commits into from
Jun 17, 2020

Conversation

Strilanc
Copy link
Contributor

  • This resulted in some circuits with random behavior giving long lists of identical samples when repeated
  • Change the general strategy used by the simulator to one of extracting a unitary prefix that can be cached, and then looking at the rest to decide whether sampling can be done efficiently or not

- This resulted in some circuits with random behavior giving long lists of identical samples when repeated
- Change the general strategy used by the simulator to one of extracting a unitary prefix that can be cached, and then looking at the rest to decide whether sampling can be done efficiently or not
@Strilanc Strilanc requested review from dabacon and viathor June 16, 2020 00:03
@googlebot googlebot added the cla: yes Makes googlebot stop complaining. label Jun 16, 2020
@Strilanc Strilanc requested a review from dstrain115 June 16, 2020 02:57
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 only one minor comment.

general_ops = list(general_suffix.all_operations())
if all(isinstance(op.gate, ops.MeasurementGate) for op in general_ops):
return step_result.sample_measurement_ops(measurement_ops=cast(
List[ops.GateOperation], general_ops),
Copy link
Collaborator

Choose a reason for hiding this comment

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

autoformat is on drugs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We cannot question it, we can only follow.

@@ -331,3 +336,27 @@ def sample(self,
self, None),
repetitions=repetitions,
seed=seed)


def _split_into_unitary_then_general(circuit: 'cirq.Circuit'
Copy link
Collaborator

Choose a reason for hiding this comment

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

There is probably a case to be made for a good way to handle this sort of splitting of circuits by disjoint filter as part of Cirq. No need to do now but maybe we should have an issue for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Acknowledged.

initial_state=0,
perform_measurements=False):
qubit_order = sorted(resolved_circuit.all_qubits())

Copy link
Collaborator

Choose a reason for hiding this comment

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

just to make sure I understand: the bug was that intermediate channel ops that could be monte carlo sampled were allowed to not be terminal, and the new way this works it splits into the biggest possible unitary chunk and if then "others" to figure out whether this is possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that was the issue.

seen_qubits: Set[cirq.Qid] = set()
for op in measurement_ops:
for q in op.qubits:
if q not in seen_qubits:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can't you just do something like this?

for op in measurement_ops:
  for q in op.qubits:
    seen_qubits.add(q)
measured_qubits = list(seen_qubits)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is what I initially did, and it resulted in several fixed-seed tests being flaky. The problem is it results in a non-deterministic ordering because set doesn't guarantee insertion order ordering.


def _run_sweep_repeat(self, initial_state: np.ndarray,
circuit: circuits.Circuit,
qubit_order: 'cirq.QubitOrderOrList',
repetitions: int) -> Dict[str, np.ndarray]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it worth adding a developer-centric docstring? It's a private method, so probably not mandatory, but might be nice to have.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Also renamed it.



def _split_into_unitary_then_general(circuit: 'cirq.Circuit'
) -> Tuple['cirq.Circuit', 'cirq.Circuit']:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ditto. I would either expand on the comment above "Simulate as many unitary operations as possible..." or write a docstring to explain what this is doing and returning.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Acknowledged. In this case I think the method name is pretty descriptive.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a docstring.

@@ -147,7 +147,7 @@ def test_run_invert_mask_measure_not_terminal(dtype):
np.testing.assert_equal(result.measurements,
{'m': [[1 - b0, b1]] * 3})
assert result.repetitions == 3
assert mock_sim.call_count == 12
assert mock_sim.call_count > 4
Copy link
Collaborator

Choose a reason for hiding this comment

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

For this and below, would it be worth a line comment to explain what the assertion is testing and/or why ">4" is expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added comments



def test_entangled_reset_does_not_break_randomness():
# A previous version made the mistake of assuming that it was okay to cache
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you think this should use the triple quote doc string instead of the line comments?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Huh. I never considered putting a doc string on a test method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Made it a doc string.

@Strilanc Strilanc added the automerge Tells CirqBot to sync and merge this PR. (If it's running.) label Jun 17, 2020
@CirqBot CirqBot added the front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. label Jun 17, 2020
@Strilanc Strilanc 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 17, 2020
@Strilanc Strilanc added the automerge Tells CirqBot to sync and merge this PR. (If it's running.) label Jun 17, 2020
@CirqBot CirqBot added the front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. label Jun 17, 2020
@CirqBot CirqBot merged commit 037afff into master Jun 17, 2020
@CirqBot CirqBot removed the automerge Tells CirqBot to sync and merge this PR. (If it's running.) label Jun 17, 2020
@CirqBot CirqBot deleted the fix_sparse_random branch June 17, 2020 21:31
@CirqBot CirqBot removed the front_of_queue_automerge CirqBot uses this label to indicate (and remember) what's being merged next. label Jun 17, 2020
tonybruguier pushed a commit to tonybruguier/Cirq that referenced this pull request Aug 23, 2020
…uantumlib#3093)

- This resulted in some circuits with random behavior giving long lists of identical samples when repeated
- Change the general strategy used by the simulator to one of extracting a unitary prefix that can be cached, and then looking at the rest to decide whether sampling can be done efficiently or not
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Makes googlebot stop complaining.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants