Skip to content

Make stimcirq.stim_circuit_to_cirq_circuit linear in operations per TICK - #1124

Open
andbe91 wants to merge 1 commit into
quantumlib:mainfrom
andbe91:linear-time-stim-to-cirq
Open

andbe91 wants to merge 1 commit into
quantumlib:mainfrom
andbe91:linear-time-stim-to-cirq

Conversation

@andbe91

@andbe91 andbe91 commented Oct 20, 2026

Copy link
Copy Markdown

CircuitTranslationTracker.append_operation appended every operation with cirq.Circuit.append(op, strategy=cirq.InsertStrategy.INLINE), which rebuilds the current moment on each append, so converting a TICK with n operations took O(n^2) time. TICKs and REPEAT blocks were also accumulated by growing a cirq.Circuit.

Track the moment being filled as a list of operations plus the qubits, measurement keys and control keys it uses, and build each cirq.Moment once. An operation starts a new moment under the same conditions as cirq.Circuit's INLINE placement in cirq >= 1.7: a shared qubit, or a measurement key that clashes with the moment's measurement or control keys. Older cirq only checked qubits there, so with those versions, measurements that share a key (only possible with single_measure_key) are now put in separate moments, matching newer cirq. Moments are built with cirq.Moment.from_ops when available, falling back to with_operations for operations that list a qubit more than once (e.g. OBSERVABLE_INCLUDE X0 Z0), which cirq.Moment(...) rejects but the old append path accepted. Completed moments are collected in a list and turned into a circuit once at the end.

Checked against the previous implementation with cirq 1.8.0.dev: identical reprs for 5,000 random circuits x 4 option sets (default, flatten, single_measure_key, both), covering nested/tagged/count-1 REPEAT blocks, MPP, MXX/MYY/MZZ, SPP, feedback and sweep controls, noise channels, QUBIT_COORDS (with collisions), SHIFT_COORDS, tags and repeated qubits within a TICK, plus 66 conversions of generated surface, repetition and color codes. With cirq 1.6.1 the only differences are the same-key measurement splits described above.

Benchmark (best of 5):
surface code d=9, 12 rounds 48.2 ms -> 25.8 ms
surface code d=9, 12 rounds, flat 231.0 ms -> 116.7 ms
surface code d=15, 30 rounds, flat 1823.6 ms -> 911.3 ms
1000 H gates in one TICK 21.1 ms -> 6.1 ms
4000 H gates in one TICK 159.1 ms -> 24.7 ms

`CircuitTranslationTracker.append_operation` appended every operation with
`cirq.Circuit.append(op, strategy=cirq.InsertStrategy.INLINE)`, which
rebuilds the current moment on each append, so converting a TICK with n
operations took O(n^2) time. TICKs and REPEAT blocks were also accumulated
by growing a `cirq.Circuit`.

Track the moment being filled as a list of operations plus the qubits,
measurement keys and control keys it uses, and build each `cirq.Moment`
once. An operation starts a new moment under the same conditions as
`cirq.Circuit`'s INLINE placement in cirq >= 1.7: a shared qubit, or a
measurement key that clashes with the moment's measurement or control
keys. Older cirq only checked qubits there, so with those versions,
measurements that share a key (only possible with `single_measure_key`)
are now put in separate moments, matching newer cirq. Moments are built
with `cirq.Moment.from_ops` when available, falling back to
`with_operations` for operations that list a qubit more than once (e.g.
`OBSERVABLE_INCLUDE X0 Z0`), which `cirq.Moment(...)` rejects but the old
append path accepted. Completed moments are collected in a list and turned
into a circuit once at the end.

Checked against the previous implementation with cirq 1.8.0.dev: identical
`repr`s for 5,000 random circuits x 4 option sets (default, `flatten`,
`single_measure_key`, both), covering nested/tagged/count-1 REPEAT blocks,
MPP, MXX/MYY/MZZ, SPP, feedback and sweep controls, noise channels,
QUBIT_COORDS (with collisions), SHIFT_COORDS, tags and repeated qubits
within a TICK, plus 66 conversions of generated surface, repetition and
color codes. With cirq 1.6.1 the only differences are the same-key
measurement splits described above.

Benchmark (best of 5):
  surface code d=9, 12 rounds          48.2 ms ->  25.8 ms
  surface code d=9, 12 rounds, flat   231.0 ms -> 116.7 ms
  surface code d=15, 30 rounds, flat 1823.6 ms -> 911.3 ms
  1000 H gates in one TICK             21.1 ms ->   6.1 ms
  4000 H gates in one TICK            159.1 ms ->  24.7 ms
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant