@@ -43,6 +43,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
4343 - [`stim.Circuit.insert`](#stim.Circuit.insert)
4444 - [`stim.Circuit.inverse`](#stim.Circuit.inverse)
4545 - [`stim.Circuit.likeliest_error_sat_problem`](#stim.Circuit.likeliest_error_sat_problem)
46+ - [`stim.Circuit.missing_detectors`](#stim.Circuit.missing_detectors)
4647 - [`stim.Circuit.num_detectors`](#stim.Circuit.num_detectors)
4748 - [`stim.Circuit.num_measurements`](#stim.Circuit.num_measurements)
4849 - [`stim.Circuit.num_observables`](#stim.Circuit.num_observables)
@@ -197,6 +198,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi
197198 - [`stim.ExplainedError.dem_error_terms`](#stim.ExplainedError.dem_error_terms)
198199- [`stim.FlipSimulator`](#stim.FlipSimulator)
199200 - [`stim.FlipSimulator.__init__`](#stim.FlipSimulator.__init__)
201+ - [`stim.FlipSimulator.append_measurement_flips`](#stim.FlipSimulator.append_measurement_flips)
200202 - [`stim.FlipSimulator.batch_size`](#stim.FlipSimulator.batch_size)
201203 - [`stim.FlipSimulator.broadcast_pauli_errors`](#stim.FlipSimulator.broadcast_pauli_errors)
202204 - [`stim.FlipSimulator.clear`](#stim.FlipSimulator.clear)
@@ -1249,6 +1251,8 @@ def copy(
12491251# (in class stim.Circuit)
12501252def count_determined_measurements(
12511253 self,
1254+ *,
1255+ unknown_input: bool = False,
12521256) -> int:
12531257 """Counts the number of predictable measurements in the circuit.
12541258
@@ -1280,6 +1284,13 @@ def count_determined_measurements(
12801284 the Z basis. Typically this relationship is not declared as a detector, because
12811285 it's not local, or as an observable, because it doesn't store a qubit.
12821286
1287+ Args:
1288+ unknown_input: Defaults to False (inputs assumed to be in the |0> state).
1289+ When set to True, the inputs are instead treated as being in unknown
1290+ random states. For example, this means that Z-basis measurements at
1291+ the very beginning of the circuit will be considered random rather
1292+ than determined.
1293+
12831294 Returns:
12841295 The number of measurements that were predictable.
12851296
@@ -1299,6 +1310,24 @@ def count_determined_measurements(
12991310 ... ''').count_determined_measurements()
13001311 0
13011312
1313+ >>> stim.Circuit('''
1314+ ... M 0
1315+ ... ''').count_determined_measurements()
1316+ 1
1317+
1318+ >>> stim.Circuit('''
1319+ ... M 0
1320+ ... ''').count_determined_measurements(unknown_input=True)
1321+ 0
1322+
1323+ >>> stim.Circuit('''
1324+ ... M 0
1325+ ... M 0 1
1326+ ... M 0 1 2
1327+ ... M 0 1 2 3
1328+ ... ''').count_determined_measurements(unknown_input=True)
1329+ 6
1330+
13021331 >>> stim.Circuit('''
13031332 ... R 0 1
13041333 ... MZZ 0 1
@@ -2542,6 +2571,72 @@ def likeliest_error_sat_problem(
25422571 """
25432572```
25442573
2574+ <a name="stim.Circuit.missing_detectors"></a>
2575+ ```python
2576+ # stim.Circuit.missing_detectors
2577+
2578+ # (in class stim.Circuit)
2579+ def missing_detectors(
2580+ self,
2581+ *,
2582+ unknown_input: bool = False,
2583+ ) -> int:
2584+ """Finds deterministic measurements independent of declared detectors/observables.
2585+
2586+ This method is useful for debugging missing detectors in a circuit, because it
2587+ identifies generators for uncovered degrees of freedom.
2588+
2589+ It's not recommended to use this method to solve for the detectors of a circuit.
2590+ The returned detectors are not guaranteed to be stable across versions, and
2591+ aren't optimized to be "good" (e.g. form a low weight basis or be matchable
2592+ if possible). It will also identify things that are technically determined
2593+ but that the user may not want to use as a detector, such as the fact that
2594+ in the first round after transversal Z basis initialization of a toric code
2595+ the product of all X stabilizer measurements is deterministic even though the
2596+ individual measurements are all random.
2597+
2598+ Args:
2599+ unknown_input: Defaults to False (inputs assumed to be in the |0> state).
2600+ When set to True, the inputs are instead treated as being in unknown
2601+ random states. For example, this means that Z-basis measurements at
2602+ the very beginning of the circuit will be considered random rather
2603+ than determined.
2604+
2605+ Returns:
2606+ A circuit containing DETECTOR instructions that specify the uncovered
2607+ degrees of freedom in the deterministic measurement sets of the input
2608+ circuit. The returned circuit can be appended to the input circuit to
2609+ get a circuit with no missing detectors.
2610+
2611+ Examples:
2612+ >>> import stim
2613+
2614+ >>> stim.Circuit('''
2615+ ... R 0
2616+ ... M 0
2617+ ... ''').missing_detectors()
2618+ stim.Circuit('''
2619+ DETECTOR rec[-1]
2620+ ''')
2621+
2622+ >>> stim.Circuit('''
2623+ ... MZZ 0 1
2624+ ... MYY 0 1
2625+ ... MXX 0 1
2626+ ... DEPOLARIZE1(0.1) 0 1
2627+ ... MZZ 0 1
2628+ ... MYY 0 1
2629+ ... MXX 0 1
2630+ ... DETECTOR rec[-1] rec[-4]
2631+ ... DETECTOR rec[-2] rec[-5]
2632+ ... DETECTOR rec[-3] rec[-6]
2633+ ... ''').missing_detectors(unknown_input=True)
2634+ stim.Circuit('''
2635+ DETECTOR rec[-3] rec[-2] rec[-1]
2636+ ''')
2637+ """
2638+ ```
2639+
25452640<a name="stim.Circuit.num_detectors"></a>
25462641```python
25472642# stim.Circuit.num_detectors
@@ -8050,6 +8145,86 @@ def __init__(
80508145 """
80518146```
80528147
8148+ <a name="stim.FlipSimulator.append_measurement_flips"></a>
8149+ ```python
8150+ # stim.FlipSimulator.append_measurement_flips
8151+
8152+ # (in class stim.FlipSimulator)
8153+ def append_measurement_flips(
8154+ self,
8155+ measurement_flip_data: np.ndarray,
8156+ ) -> None:
8157+ """Appends measurement flip data to the simulator's measurement record.
8158+
8159+ Args:
8160+ measurement_flip_data: The flip data to append. The following shape/dtype
8161+ combinations are supported.
8162+
8163+ Single measurement without bit packing:
8164+ shape=(self.batch_size,)
8165+ dtype=np.bool_
8166+
8167+ Single measurement with bit packing:
8168+ shape=(math.ceil(self.batch_size / 8),)
8169+ dtype=np.uint8
8170+
8171+ Multiple measurements without bit packing:
8172+ shape=(num_measurements, self.batch_size)
8173+ dtype=np.bool_
8174+
8175+ Multiple measurements with bit packing:
8176+ shape=(num_measurements, math.ceil(self.batch_size / 8))
8177+ dtype=np.uint8
8178+
8179+ Examples:
8180+ >>> import stim
8181+ >>> import numpy as np
8182+ >>> sim = stim.FlipSimulator(batch_size=9)
8183+ >>> sim.append_measurement_flips(np.array(
8184+ ... [0, 1, 0, 0, 1, 0, 0, 1, 1],
8185+ ... dtype=np.bool_,
8186+ ... ))
8187+
8188+ >>> sim.get_measurement_flips()
8189+ array([[False, True, False, False, True, False, False, True, True]])
8190+
8191+ >>> sim.append_measurement_flips(np.array(
8192+ ... [0b11001001, 0],
8193+ ... dtype=np.uint8,
8194+ ... ))
8195+
8196+ >>> sim.get_measurement_flips()
8197+ array([[False, True, False, False, True, False, False, True, True],
8198+ [ True, False, False, True, False, False, True, True, False]])
8199+
8200+ >>> sim.append_measurement_flips(np.array(
8201+ ... [[0b11111111, 0b1], [0b00000000, 0b0], [0b11111111, 0b1]],
8202+ ... dtype=np.uint8,
8203+ ... ))
8204+
8205+ >>> sim.get_measurement_flips()
8206+ array([[False, True, False, False, True, False, False, True, True],
8207+ [ True, False, False, True, False, False, True, True, False],
8208+ [ True, True, True, True, True, True, True, True, True],
8209+ [False, False, False, False, False, False, False, False, False],
8210+ [ True, True, True, True, True, True, True, True, True]])
8211+
8212+ >>> sim.append_measurement_flips(np.array(
8213+ ... [[1, 0, 1, 0, 1, 0, 1, 0, 1], [0, 1, 0, 1, 0, 1, 0, 1, 0]],
8214+ ... dtype=np.bool_,
8215+ ... ))
8216+
8217+ >>> sim.get_measurement_flips()
8218+ array([[False, True, False, False, True, False, False, True, True],
8219+ [ True, False, False, True, False, False, True, True, False],
8220+ [ True, True, True, True, True, True, True, True, True],
8221+ [False, False, False, False, False, False, False, False, False],
8222+ [ True, True, True, True, True, True, True, True, True],
8223+ [ True, False, True, False, True, False, True, False, True],
8224+ [False, True, False, True, False, True, False, True, False]])
8225+ """
8226+ ```
8227+
80538228<a name="stim.FlipSimulator.batch_size"></a>
80548229```python
80558230# stim.FlipSimulator.batch_size
@@ -10911,6 +11086,14 @@ def __init__(
1091111086 Iterable: initializes by interpreting each item as a Pauli.
1091211087 Each item can be a single-qubit Pauli string (like "X"),
1091311088 or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.
11089+ Dict[int, Union[int, str]]: initializes by interpreting keys as
11090+ the qubit index and values as the Pauli for that index.
11091+ Each value can be a single-qubit Pauli string (like "X"),
11092+ or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.
11093+ Dict[Union[int, str], Iterable[int]]: initializes by interpreting keys
11094+ as Pauli operators and values as the qubit indices for that Pauli.
11095+ Each key can be a single-qubit Pauli string (like "X"),
11096+ or an integer. Integers use the convention 0=I, 1=X, 2=Y, 3=Z.
1091411097
1091511098 Examples:
1091611099 >>> import stim
@@ -10938,6 +11121,15 @@ def __init__(
1093811121
1093911122 >>> stim.PauliString("X6*Y6")
1094011123 stim.PauliString("+i______Z")
11124+
11125+ >>> stim.PauliString({0: "X", 2: "Y", 3: "X"})
11126+ stim.PauliString("+X_YX")
11127+
11128+ >>> stim.PauliString({0: "X", 2: 2, 3: 1})
11129+ stim.PauliString("+X_YX")
11130+
11131+ >>> stim.PauliString({"X": [1], 2: [4], "Z": [0, 3]})
11132+ stim.PauliString("+ZX_ZY")
1094111133 """
1094211134```
1094311135
0 commit comments