Skip to content

Commit 2132757

Browse files
authored
Add stimcirq support for feedback controlled by sympy Xor expressions (#1058)
Fixes #1053
1 parent df52166 commit 2132757

2 files changed

Lines changed: 57 additions & 22 deletions

File tree

glue/cirq/stimcirq/_cirq_to_stim.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import cirq
77
import stim
8+
import sympy
89

910
from ._ii_gate import IIGate
1011

@@ -152,10 +153,15 @@ def _stim_append_classically_controlled_gate(
152153

153154
if len(op.classical_controls) != 1:
154155
raise NotImplementedError(f'Stim only supports single-control Pauli feedback, but got {op=}')
155-
control, = op.classical_controls
156-
if not isinstance(control, cirq.KeyCondition):
157-
raise NotImplementedError(f'Stim only supports single-control Pauli feedback (i.e. a `cirq.KeyCondition` control), but got {control=}')
158-
control: cirq.KeyCondition
156+
controls: list[cirq.KeyCondition] = []
157+
single_control, = op.classical_controls
158+
if isinstance(single_control, cirq.KeyCondition):
159+
controls.append(single_control)
160+
elif isinstance(single_control, cirq.SympyCondition) and isinstance(single_control.expr, sympy.Xor) and all(isinstance(e, sympy.Symbol) for e in single_control.expr.args):
161+
for symbol in single_control.expr.args:
162+
controls.append(cirq.KeyCondition(key=cirq.MeasurementKey(str(symbol)), index=-1))
163+
else:
164+
raise NotImplementedError(f'Stim only supports single-control Pauli feedback (i.e. a `cirq.KeyCondition` control), but got {single_control=}')
159165
gate = op.without_classical_controls().gate
160166

161167
if gate == cirq.X:
@@ -168,24 +174,25 @@ def _stim_append_classically_controlled_gate(
168174
raise NotImplementedError(f'Stim only supports Pauli feedback, but got {op=}')
169175
assert len(targets) == 1
170176

171-
skips_left = control.index
172-
for offset in range(len(measurement_key_lengths)):
173-
m_key, m_len = measurement_key_lengths[-1 - offset]
174-
if m_len != 1:
175-
raise NotImplementedError(f"multi-qubit measurement {m_key!r}")
176-
if m_key == control.key:
177-
if skips_left > 0:
178-
skips_left -= 1
179-
else:
180-
rec_target = stim.target_rec(-1 - offset)
181-
break
182-
else:
183-
raise ValueError(
184-
f"{control!r} was processed before the measurement it referenced."
185-
f" Make sure the referenced measurements keys are actually in the circuit, and come"
186-
f" in an earlier moment (or earlier in the same moment's operation order)."
187-
)
188-
circuit.append(f"C{stim_gate}", [rec_target, targets[0]], tag=tag)
177+
for control in controls:
178+
skips_left = control.index
179+
for offset in range(len(measurement_key_lengths)):
180+
m_key, m_len = measurement_key_lengths[-1 - offset]
181+
if m_len != 1:
182+
raise NotImplementedError(f"multi-qubit measurement {m_key!r}")
183+
if m_key == control.key:
184+
if skips_left > 0:
185+
skips_left -= 1
186+
else:
187+
rec_target = stim.target_rec(-1 - offset)
188+
break
189+
else:
190+
raise ValueError(
191+
f"{control!r} was processed before the measurement it referenced."
192+
f" Make sure the referenced measurements keys are actually in the circuit, and come"
193+
f" in an earlier moment (or earlier in the same moment's operation order)."
194+
)
195+
circuit.append(f"C{stim_gate}", [rec_target, targets[0]], tag=tag)
189196

190197

191198
@functools.lru_cache(maxsize=1)

glue/cirq/stimcirq/_cirq_to_stim_test.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pytest
77
import stim
88
import stimcirq
9+
import sympy
910
from stimcirq._cirq_to_stim import cirq_circuit_to_stim_data, gate_to_stim_append_func
1011

1112

@@ -425,3 +426,30 @@ def test_round_trip_example_circuit():
425426
cirq_circuit = stimcirq.stim_circuit_to_cirq_circuit(stim_circuit.flattened())
426427
circuit_back = stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)
427428
assert len(circuit_back.shortest_graphlike_error()) == 3
429+
430+
431+
def test_xor_feedback():
432+
a, b, c, d, e = cirq.LineQubit.range(5)
433+
cirq_circuit = cirq.Circuit([
434+
cirq.Moment(
435+
cirq.measure(a, key='a'),
436+
cirq.measure(b, key='b'),
437+
cirq.measure(c, key='c'),
438+
cirq.measure(d, key='d'),
439+
),
440+
cirq.Moment(
441+
cirq.X(e).with_classical_controls(cirq.SympyCondition(sympy.Xor(
442+
sympy.Symbol('a'),
443+
sympy.Symbol('b'),
444+
sympy.Symbol('c'),
445+
sympy.Symbol('d'),
446+
))),
447+
),
448+
])
449+
stim_circuit = stimcirq.cirq_circuit_to_stim_circuit(cirq_circuit)
450+
assert stim_circuit == stim.Circuit("""
451+
M 0 1 2 3
452+
TICK
453+
CX rec[-4] 4 rec[-3] 4 rec[-2] 4 rec[-1] 4
454+
TICK
455+
""")

0 commit comments

Comments
 (0)