Skip to content

Commit

Permalink
Add stim.Circuit.time_reversed_with_flows (#725)
Browse files Browse the repository at this point in the history
- Change the generalized inverse of `R{X,Y,Z}` from `MR{X,Y,Z}` to
`M{X,Y,Z}`

- Split `src/stim/util_top/simplified_circuit.{h,...}` out of
`src/stim/circuit/gate_decomposition.{h,...}`
- Add `stim::PauliStringRef<W>::for_each_active_pauli` (from a
previously-private method)
- Add `stim::for_each_disjoint_target_segment_in_instruction_reversed`
- Add `stim::Circuit::safe_append_reversed_targets`
  • Loading branch information
Strilanc authored Mar 20, 2024
1 parent e5a348d commit 264d32d
Show file tree
Hide file tree
Showing 37 changed files with 2,498 additions and 716 deletions.
213 changes: 212 additions & 1 deletion doc/python_api_reference_vDev.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
- [`stim.Circuit.search_for_undetectable_logical_errors`](#stim.Circuit.search_for_undetectable_logical_errors)
- [`stim.Circuit.shortest_error_sat_problem`](#stim.Circuit.shortest_error_sat_problem)
- [`stim.Circuit.shortest_graphlike_error`](#stim.Circuit.shortest_graphlike_error)
- [`stim.Circuit.time_reversed_for_flows`](#stim.Circuit.time_reversed_for_flows)
- [`stim.Circuit.to_file`](#stim.Circuit.to_file)
- [`stim.Circuit.to_qasm`](#stim.Circuit.to_qasm)
- [`stim.Circuit.to_tableau`](#stim.Circuit.to_tableau)
Expand Down Expand Up @@ -2887,6 +2888,216 @@ def shortest_graphlike_error(
"""
```

<a name="stim.Circuit.time_reversed_for_flows"></a>
```python
# stim.Circuit.time_reversed_for_flows

# (in class stim.Circuit)
def time_reversed_for_flows(
self,
flows: Iterable[stim.Flow],
*,
dont_turn_measurements_into_resets: bool = False,
) -> Tuple[stim.Circuit, List[stim.Flow]]:
"""Time-reverses the circuit while preserving error correction structure.
This method returns a circuit that has the same internal detecting regions
as the given circuit, as well as the same internal-to-external flows given
in the `flows` argument, except they are all time-reversed. For example, if
you pass a fault tolerant preparation circuit into this method (1 -> Z), the
result will be a fault tolerant *measurement* circuit (Z -> 1). Or, if you
pass a fault tolerant C_XYZ circuit into this method (X->Y, Y->Z, and Z->X),
the result will be a fault tolerant C_ZYX circuit (X->Z, Y->X, and Z->Y).
Note that this method doesn't guarantee that it will preserve the *sign* of the
detecting regions or stabilizer flows. For example, inverting a memory circuit
that preserves a logical observable (X->X and Z->Z) may produce a
memory circuit that always bit flips the logical observable (X->X and Z->-Z) or
that dynamically adjusts the logical observable in response to measurements
(like "X -> X xor rec[-1]" and "Z -> Z xor rec[-2]").
This method will turn time-reversed resets into measurements, and attempts to
turn time-reversed measurements into resets. A measurement will time-reverse
into a reset if some annotated detectors, annotated observables, or given flows
have detecting regions with sensitivity just before the measurement but none
have detecting regions with sensitivity after the measurement.
In some cases this method will have to introduce new operations. In particular,
when a measurement-reset operation has a noisy result, time-reversing this
measurement noise produces reset noise. But the measure-reset operations don't
have built-in reset noise, so the reset noise is specified by adding an X_ERROR
or Z_ERROR noise instruction after the time-reversed measure-reset operation.
Args:
flows: Flows you care about, that reach past the start/end of the given
circuit. The result will contain an inverted flow for each of these
given flows. You need this information because it reveals the
measurements needed to produce the inverted flows that you care
about.
An exception will be raised if the circuit doesn't have all these
flows. The inverted circuit will have the inverses of these flows
(ignoring sign).
dont_turn_measurements_into_resets: Defaults to False. When set to
True, measurements will time-reverse into measurements even if
nothing is sensitive to the measured qubit after the measurement
completes. This guarantees the output circuit has *all* flows
that the input circuit has (up to sign and feedback), even ones
that aren't annotated.
Returns:
An (inverted_circuit, inverted_flows) tuple.
inverted_circuit is the qec inverse of the given circuit.
inverted_flows is a list of flows, matching up by index with the flows
given as arguments to the method. The input, output, and sign fields
of these flows are boring. The useful field is measurement_indices,
because it's difficult to predict which measurements are needed for
the inverted flow due to effects such as implicitly-included resets
inverting into explicitly-included measurements.
Caveats:
Currently, this method doesn't compute the sign of the inverted flows.
It unconditionally sets the sign to False.
Examples:
>>> import stim
>>> inv_circuit, inv_flows = stim.Circuit('''
... R 0
... H 0
... S 0
... MY 0
... DETECTOR rec[-1]
... ''').time_reversed_for_flows([])
>>> inv_circuit
stim.Circuit('''
RY 0
S_DAG 0
H 0
M 0
DETECTOR rec[-1]
''')
>>> inv_flows
[]
>>> inv_circuit, inv_flows = stim.Circuit('''
... M 0
... ''').time_reversed_for_flows([
... stim.Flow("Z -> rec[-1]"),
... ])
>>> inv_circuit
stim.Circuit('''
R 0
''')
>>> inv_flows
[stim.Flow("1 -> Z")]
>>> inv_circuit.has_all_flows(inv_flows, unsigned=True)
True
>>> inv_circuit, inv_flows = stim.Circuit('''
... R 0
... ''').time_reversed_for_flows([
... stim.Flow("1 -> Z"),
... ])
>>> inv_circuit
stim.Circuit('''
M 0
''')
>>> inv_flows
[stim.Flow("Z -> rec[-1]")]
>>> inv_circuit, inv_flows = stim.Circuit('''
... M 0
... ''').time_reversed_for_flows([
... stim.Flow("1 -> Z xor rec[-1]"),
... ])
>>> inv_circuit
stim.Circuit('''
M 0
''')
>>> inv_flows
[stim.Flow("Z -> rec[-1]")]
>>> inv_circuit, inv_flows = stim.Circuit('''
... M 0
... ''').time_reversed_for_flows(
... flows=[stim.Flow("Z -> rec[-1]")],
... dont_turn_measurements_into_resets=True,
... )
>>> inv_circuit
stim.Circuit('''
M 0
''')
>>> inv_flows
[stim.Flow("1 -> Z xor rec[-1]")]
>>> inv_circuit, inv_flows = stim.Circuit('''
... MR(0.125) 0
... ''').time_reversed_for_flows([])
>>> inv_circuit
stim.Circuit('''
MR 0
X_ERROR(0.125) 0
''')
>>> inv_flows
[]
>>> inv_circuit, inv_flows = stim.Circuit('''
... MXX 0 1
... H 0
... ''').time_reversed_for_flows([
... stim.Flow("ZZ -> YY xor rec[-1]"),
... stim.Flow("ZZ -> XZ"),
... ])
>>> inv_circuit
stim.Circuit('''
H 0
MXX 0 1
''')
>>> inv_flows
[stim.Flow("YY -> ZZ xor rec[-1]"), stim.Flow("XZ -> ZZ")]
>>> stim.Circuit.generated(
... "surface_code:rotated_memory_x",
... distance=2,
... rounds=1,
... ).time_reversed_for_flows([])[0]
stim.Circuit('''
QUBIT_COORDS(1, 1) 1
QUBIT_COORDS(2, 0) 2
QUBIT_COORDS(3, 1) 3
QUBIT_COORDS(1, 3) 6
QUBIT_COORDS(2, 2) 7
QUBIT_COORDS(3, 3) 8
QUBIT_COORDS(2, 4) 12
RX 8 6 3 1
MR 12 7 2
TICK
H 12 2
TICK
CX 1 7 12 6
TICK
CX 6 7 12 8
TICK
CX 3 7 2 1
TICK
CX 8 7 2 3
TICK
H 12 2
TICK
M 12 7 2
DETECTOR(2, 0, 1) rec[-1]
DETECTOR(2, 4, 1) rec[-3]
MX 8 6 3 1
DETECTOR(2, 0, 0) rec[-5] rec[-2] rec[-1]
DETECTOR(2, 4, 0) rec[-7] rec[-4] rec[-3]
OBSERVABLE_INCLUDE(0) rec[-3] rec[-1]
''')
"""
```

<a name="stim.Circuit.to_file"></a>
```python
# stim.Circuit.to_file
Expand Down Expand Up @@ -7587,7 +7798,7 @@ def generalized_inverse(
stim.gate_data('MRY')
>>> stim.gate_data('R').generalized_inverse
stim.gate_data('MR')
stim.gate_data('M')
>>> stim.gate_data('DETECTOR').generalized_inverse
stim.gate_data('DETECTOR')
Expand Down
Loading

0 comments on commit 264d32d

Please sign in to comment.