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

Allow repeated measurements in deferred transformer #5857

Merged
merged 48 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
b4849ca
Add handling for sympy conditions in deferred measurement transformer
daxfohl Aug 12, 2022
c88df71
docstring
daxfohl Aug 12, 2022
d9f2776
mypy
daxfohl Aug 12, 2022
48c5736
mypy
daxfohl Aug 12, 2022
17f5e80
cover
daxfohl Aug 12, 2022
d74a699
Make this more generic, covers all kinds of conditions.
daxfohl Aug 12, 2022
d37cbad
Better docs
daxfohl Aug 13, 2022
2c1d003
Sympy can also be CX
daxfohl Aug 13, 2022
27ff43d
docs
daxfohl Aug 13, 2022
78ef78d
docs
daxfohl Aug 13, 2022
4dcb564
Merge branch 'master' into sympy-deferred
tanujkhattar Aug 25, 2022
6ffe765
Merge branch 'master' into sympy-deferred
tanujkhattar Aug 25, 2022
0292f3c
Allow repeated measurements in deferred transformer
daxfohl Sep 4, 2022
773e660
Coverage
daxfohl Sep 5, 2022
ed1257d
Merge branch 'master' into sympy-deferred
daxfohl Sep 5, 2022
6bcc71c
Add mixed tests, simplify loop, add simplification in ControlledGate
daxfohl Sep 5, 2022
8f045bc
Fix error message
daxfohl Sep 5, 2022
1c32404
Simplify error message
daxfohl Sep 6, 2022
9fd971b
Inline variable
daxfohl Sep 14, 2022
4a484b0
Merge branch 'master' into sympy-deferred
daxfohl Sep 21, 2022
96aff58
Merge branch 'master' into deferred-repeated
daxfohl Sep 21, 2022
30b9121
Merge branch 'master' into sympy-deferred
daxfohl Oct 11, 2022
9d1f5ef
fix merge
daxfohl Oct 11, 2022
d4c80b9
qudit sympy test
daxfohl Oct 11, 2022
dd06a75
Merge branch 'master' into deferred-repeated
daxfohl Oct 11, 2022
480849c
Merge branch 'master' into deferred-repeated
daxfohl Oct 12, 2022
2d1cabf
Merge branch 'master' into sympy-deferred
daxfohl Oct 12, 2022
f033b39
fix build
daxfohl Oct 13, 2022
72388ce
Merge branch 'master' into sympy-deferred
daxfohl Oct 13, 2022
f7f2825
Merge branch 'master' into deferred-repeated
daxfohl Oct 13, 2022
8e8dfc1
Fix test
daxfohl Oct 16, 2022
e733e89
Fix test
daxfohl Oct 16, 2022
46cceef
Merge branch 'deferred-repeated' into deferred-all
daxfohl Oct 16, 2022
0e9dede
Merge branch 'master' into deferred-repeated
daxfohl Oct 31, 2022
29bc38d
Merge branch 'deferred-all' into deferred-repeated
daxfohl Nov 4, 2022
4f9be93
Merge branch 'master' into deferred-repeated
daxfohl Nov 4, 2022
a9df6c9
nits
daxfohl Nov 4, 2022
b86c411
mypy
daxfohl Nov 4, 2022
b873c31
mypy
daxfohl Nov 4, 2022
4920118
mypy
daxfohl Nov 4, 2022
922f827
Add some code comments
daxfohl Nov 4, 2022
4a40c99
Add test for repeated measurement diagram
daxfohl Nov 4, 2022
fb5d11f
change test back
daxfohl Nov 12, 2022
fc93a6f
Merge branch 'master' into deferred-repeated
daxfohl Nov 12, 2022
6fcf183
Merge branch 'master' into deferred-repeated
daxfohl Dec 16, 2022
2d67649
Merge branch 'master' into deferred-repeated
tanujkhattar Dec 19, 2022
90d9ab8
Merge branch 'master' into deferred-repeated
tanujkhattar Dec 19, 2022
4c7a1cd
Merge branch 'master' into deferred-repeated
tanujkhattar Dec 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Make this more generic, covers all kinds of conditions.
  • Loading branch information
daxfohl committed Aug 12, 2022
commit d74a699cba998fc81d63342edbb97953c86d3e07
75 changes: 34 additions & 41 deletions cirq-core/cirq/transformers/measurement_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

import itertools
from typing import Any, Dict, List, Optional, Sequence, TYPE_CHECKING, Union
from typing import Any, Dict, Iterable, List, Mapping, Optional, TYPE_CHECKING, Union

from cirq import ops, protocols, value
from cirq.transformers import transformer_api, transformer_primitives
Expand Down Expand Up @@ -82,7 +82,6 @@ def defer_measurements(
A circuit with equivalent logic, but all measurements at the end of the
circuit.
Raises:
ValueError: If custom classical conditions classes are used.
NotImplementedError: When attempting to defer a measurement with a
confusion map. (https://github.com/quantumlib/Cirq/issues/5482)
"""
Expand Down Expand Up @@ -112,46 +111,24 @@ def defer(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
elif op.classical_controls:
new_op = op.without_classical_controls()
for c in op.classical_controls:
if isinstance(c, value.KeyCondition):
if c.key not in measurement_qubits:
raise ValueError(f'Deferred measurement for key={c.key} not found.')
qs = measurement_qubits[c.key]
if len(qs) == 1:
control_values: Any = range(1, qs[0].dimension)
else:
all_values = itertools.product(*[range(q.dimension) for q in qs])
anything_but_all_zeros = tuple(itertools.islice(all_values, 1, None))
control_values = ops.SumOfProducts(anything_but_all_zeros)
new_op = new_op.controlled_by(*qs, control_values=control_values)
elif isinstance(c, value.SympyCondition):
all_values = itertools.product(
*[
tuple(
itertools.product(
*[range(q.dimension) for q in measurement_qubits[k]]
)
)
for k in c.keys
]
)

def matches(digits_list: Sequence[Sequence[int]]) -> bool:
replacements = {
str(k): value.big_endian_digits_to_int(
digits, base=[q.dimension for q in measurement_qubits[k]]
)
for k, digits in zip(c.keys, digits_list)
}
# ignore typing because c is SympyCondition
return bool(c.expr.subs(replacements)) # type: ignore

matching_values = [v for v in all_values if matches(v)]
matching_controls = [[i for j in k for i in j] for k in matching_values]
qs = [q for k in c.keys for q in measurement_qubits[k]]
control_values = ops.SumOfProducts(matching_controls)
new_op = new_op.controlled_by(*qs, control_values=control_values)
missing_keys = [k for k in c.keys if k not in measurement_qubits]
if missing_keys:
raise ValueError(f'Deferred measurement for key={missing_keys[0]} not found.')
qs = [q for k in c.keys for q in measurement_qubits[k]]
if isinstance(c, value.KeyCondition) and len(qs) == 1:
# Convenience: control_values=range(...) renders more nicely.
new_op = new_op.controlled_by(*qs, control_values=range(1, qs[0].dimension))
else:
raise ValueError('Only KeyConditions and SympyConditions are allowed.')
# Try every option against the condition, and the ones that work are the
# control values for the new op.
datastores = _all_possible_values(c.keys, measurement_qubits)
compatible_datastores = [store for store in datastores if c.resolve(store)]
products = [
[i for k in c.keys for i in store.records[k][0]]
for store in compatible_datastores
]
control_values = ops.SumOfProducts(products)
new_op = new_op.controlled_by(*qs, control_values=control_values)
return new_op
return op

Expand All @@ -166,6 +143,22 @@ def matches(digits_list: Sequence[Sequence[int]]) -> bool:
return circuit


def _all_possible_values(
keys: Iterable['cirq.MeasurementKey'],
measurement_qubits: Mapping['cirq.MeasurementKey', Iterable['cirq.Qid']],
) -> Iterable['cirq.ClassicalDataStoreReader']:
"""The full product of possible DatsStores for the keys and qubits."""
all_values = itertools.product(
*[
tuple(itertools.product(*[range(q.dimension) for q in measurement_qubits[k]]))
for k in keys
]
)
for sequences in all_values:
lookup = {k: [sequence] for k, sequence in zip(keys, sequences)}
yield value.ClassicalDataDictionaryStore(_records=lookup)


@transformer_api.transformer
def dephase_measurements(
circuit: 'cirq.AbstractCircuit',
Expand Down
11 changes: 0 additions & 11 deletions cirq-core/cirq/transformers/measurement_transformers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from unittest import mock

import numpy as np
import pytest
import sympy
Expand Down Expand Up @@ -371,15 +369,6 @@ def test_repr(qid: _MeasurementQid):
test_repr(_MeasurementQid('0:1:a', cirq.LineQid(9, 4)))


def test_custom_control():
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
cirq.measure(q0, q1, key='a'), cirq.X(q1).with_classical_controls(mock.MagicMock())
)
with pytest.raises(ValueError, match='Only KeyConditions and SympyConditions are allowed'):
_ = cirq.defer_measurements(circuit)


def test_confusion_map():
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
Expand Down