diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1456412ae..337d8f01b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -327,7 +327,7 @@ jobs: - run: diff <(dev/regen_crumble_to_cpp_string_write_to_stdout.sh) src/stim/diagram/crumble_data.cc - run: pip install -e glue/sample - run: diff <(python dev/gen_sinter_api_reference.py -dev) doc/sinter_api.md - - run: diff <(python -c "import stim; stim.main(command_line_args=['help', 'gates'])" | grep " " | sed 's/^ *//g') glue/crumble/test/generated_gate_name_list.txt + - run diff <(dev/gen_known_gates_for_js.sh) glue/crumble/test/generated_gate_name_list.test.js test_generated_file_lists_are_fresh: runs-on: ubuntu-latest steps: diff --git a/dev/gen_known_gates_for_js.sh b/dev/gen_known_gates_for_js.sh new file mode 100755 index 000000000..90b0b5503 --- /dev/null +++ b/dev/gen_known_gates_for_js.sh @@ -0,0 +1,12 @@ +#!/bin/bash +set -e + +######################################################################### +# Generates javascript exporting a string KNOWN_GATE_NAMES_FROM_STIM. +######################################################################### + +echo "const KNOWN_GATE_NAMES_FROM_STIM = \`" +python -c "import stim; stim.main(command_line_args=['help', 'gates'])" | grep " " | sed 's/^ *//g' +echo "\`" +echo +echo "export {KNOWN_GATE_NAMES_FROM_STIM};" diff --git a/dev/regen_docs.sh b/dev/regen_docs.sh index 8246a5c90..3f2266ead 100755 --- a/dev/regen_docs.sh +++ b/dev/regen_docs.sh @@ -16,4 +16,4 @@ python dev/gen_sinter_api_reference.py -dev > doc/sinter_api.md python -c "import stim; stim.main(command_line_args=['help', 'gates_markdown'])" > doc/gates.md python -c "import stim; stim.main(command_line_args=['help', 'formats_markdown'])" > doc/result_formats.md python -c "import stim; stim.main(command_line_args=['help', 'commands_markdown'])" > doc/usage_command_line.md -python -c "import stim; stim.main(command_line_args=['help', 'gates'])" | grep " " | sed 's/^ *//g' > glue/crumble/test/generated_gate_name_list.txt +dev/gen_known_gates_for_js.sh > glue/crumble/test/generated_gate_name_list.test.js diff --git a/doc/python_api_reference_vDev.md b/doc/python_api_reference_vDev.md index 4a197b909..517845184 100644 --- a/doc/python_api_reference_vDev.md +++ b/doc/python_api_reference_vDev.md @@ -35,7 +35,6 @@ API references for stable versions are kept on the [stim github wiki](https://gi - [`stim.Circuit.generated`](#stim.Circuit.generated) - [`stim.Circuit.get_detector_coordinates`](#stim.Circuit.get_detector_coordinates) - [`stim.Circuit.get_final_qubit_coordinates`](#stim.Circuit.get_final_qubit_coordinates) - - [`stim.Circuit.has_all_flows`](#stim.Circuit.has_all_flows) - [`stim.Circuit.has_flow`](#stim.Circuit.has_flow) - [`stim.Circuit.inverse`](#stim.Circuit.inverse) - [`stim.Circuit.num_detectors`](#stim.Circuit.num_detectors) @@ -189,15 +188,6 @@ API references for stable versions are kept on the [stim github wiki](https://gi - [`stim.FlippedMeasurement.__init__`](#stim.FlippedMeasurement.__init__) - [`stim.FlippedMeasurement.observable`](#stim.FlippedMeasurement.observable) - [`stim.FlippedMeasurement.record_index`](#stim.FlippedMeasurement.record_index) -- [`stim.Flow`](#stim.Flow) - - [`stim.Flow.__eq__`](#stim.Flow.__eq__) - - [`stim.Flow.__init__`](#stim.Flow.__init__) - - [`stim.Flow.__ne__`](#stim.Flow.__ne__) - - [`stim.Flow.__repr__`](#stim.Flow.__repr__) - - [`stim.Flow.__str__`](#stim.Flow.__str__) - - [`stim.Flow.input_copy`](#stim.Flow.input_copy) - - [`stim.Flow.measurements_copy`](#stim.Flow.measurements_copy) - - [`stim.Flow.output_copy`](#stim.Flow.output_copy) - [`stim.GateData`](#stim.GateData) - [`stim.GateData.__eq__`](#stim.GateData.__eq__) - [`stim.GateData.__init__`](#stim.GateData.__init__) @@ -395,11 +385,9 @@ API references for stable versions are kept on the [stim github wiki](https://gi - [`stim.gate_data`](#stim.gate_data) - [`stim.main`](#stim.main) - [`stim.read_shot_data_file`](#stim.read_shot_data_file) -- [`stim.target_combined_paulis`](#stim.target_combined_paulis) - [`stim.target_combiner`](#stim.target_combiner) - [`stim.target_inv`](#stim.target_inv) - [`stim.target_logical_observable_id`](#stim.target_logical_observable_id) -- [`stim.target_pauli`](#stim.target_pauli) - [`stim.target_rec`](#stim.target_rec) - [`stim.target_relative_detector_id`](#stim.target_relative_detector_id) - [`stim.target_separator`](#stim.target_separator) @@ -1897,66 +1885,6 @@ def get_final_qubit_coordinates( """ ``` - -```python -# stim.Circuit.has_all_flows - -# (in class stim.Circuit) -def has_all_flows( - self, - flows: Iterable[stim.Flow], - *, - unsigned: bool = False, -) -> bool: - """Determines if the circuit has all the given stabilizer flow or not. - - This is a faster version of `all(c.has_flow(f) for f in flows)`. It's faster - because, behind the scenes, the circuit can be iterated once instead of once - per flow. - - Args: - flows: An iterable of `stim.Flow` instances representing the flows to check. - unsigned: Defaults to False. When False, the flows must be correct including - the sign of the Pauli strings. When True, only the Pauli terms need to - be correct; the signs are permitted to be inverted. In effect, this - requires the circuit to be correct up to Pauli gates. - - Returns: - True if the circuit has the given flow; False otherwise. - - Examples: - >>> import stim - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> Y'), - ... stim.Flow('Z -> X'), - ... ]) - False - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> -Y'), - ... stim.Flow('Z -> X'), - ... ]) - True - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> Y'), - ... stim.Flow('Z -> X'), - ... ], unsigned=True) - True - - Caveats: - Currently, the unsigned=False version of this method is implemented by - performing 256 randomized tests. Each test has a 50% chance of a false - positive, and a 0% chance of a false negative. So, when the method returns - True, there is technically still a 2^-256 chance the circuit doesn't have - the flow. This is lower than the chance of a cosmic ray flipping the result. - """ -``` - ```python # stim.Circuit.has_flow @@ -1964,11 +1892,14 @@ def has_all_flows( # (in class stim.Circuit) def has_flow( self, - flow: stim.Flow, + shorthand: Optional[str] = None, *, + start: Union[None, str, stim.PauliString] = None, + end: Union[None, str, stim.PauliString] = None, + measurements: Optional[Iterable[Union[int, stim.GateTarget]]] = None, unsigned: bool = False, ) -> bool: - """Determines if the circuit has the given stabilizer flow or not. + """Determines if the circuit has a stabilizer flow or not. A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer P at the start of the circuit to the instantaneous stabilizer Q at the end of @@ -1982,7 +1913,26 @@ def has_flow( A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR). Args: - flow: The flow to check for. + shorthand: Specifies the flow as a short string like "X1 -> -YZ xor rec[1]". + The text must contain "->" to separate the input pauli string from the + output pauli string. Measurements are included by appending + " xor rec[k]" for each measurement index k. Indexing uses the python + convention where non-negative indices index from the start and negative + indices index from the end. The pauli strings are parsed as if by + `stim.PauliString.__init__`. + start: The input into the flow at the start of the circuit. Defaults to None + (the identity Pauli string). When specified, this should be a + `stim.PauliString`, or a `str` (which will be parsed using + `stim.PauliString.__init__`). + end: The output from the flow at the end of the circuit. Defaults to None + (the identity Pauli string). When specified, this should be a + `stim.PauliString`, or a `str` (which will be parsed using + `stim.PauliString.__init__`). + measurements: Defaults to None (empty). The indices of measurements to + include in the flow. This should be a collection of integers and/or + stim.GateTarget instances. Indexing uses the python convention where + non-negative indices index from the start and negative indices index + from the end. unsigned: Defaults to False. When False, the flows must be correct including the sign of the Pauli strings. When True, only the Pauli terms need to be correct; the signs are permitted to be inverted. In effect, this @@ -1991,49 +1941,56 @@ def has_flow( Returns: True if the circuit has the given flow; False otherwise. + References: + Stim's gate documentation includes the stabilizer flows of each gate. + + Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are + defined and provides a circuit construction for experimentally verifying + their presence. + Examples: >>> import stim >>> m = stim.Circuit('M 0') - >>> m.has_flow(stim.Flow('Z -> Z')) + >>> m.has_flow('Z -> Z') True - >>> m.has_flow(stim.Flow('X -> X')) + >>> m.has_flow('X -> X') False - >>> m.has_flow(stim.Flow('Z -> I')) + >>> m.has_flow('Z -> I') False - >>> m.has_flow(stim.Flow('Z -> I xor rec[-1]')) + >>> m.has_flow('Z -> I xor rec[-1]') True - >>> m.has_flow(stim.Flow('Z -> rec[-1]')) + >>> m.has_flow('Z -> rec[-1]') True >>> cx58 = stim.Circuit('CX 5 8') - >>> cx58.has_flow(stim.Flow('X5 -> X5*X8')) + >>> cx58.has_flow('X5 -> X5*X8') True - >>> cx58.has_flow(stim.Flow('X_ -> XX')) + >>> cx58.has_flow('X_ -> XX') False - >>> cx58.has_flow(stim.Flow('_____X___ -> _____X__X')) + >>> cx58.has_flow('_____X___ -> _____X__X') True >>> stim.Circuit(''' ... RY 0 - ... ''').has_flow(stim.Flow( - ... output=stim.PauliString("Y"), - ... )) + ... ''').has_flow( + ... end=stim.PauliString("Y"), + ... ) True >>> stim.Circuit(''' ... RY 0 - ... ''').has_flow(stim.Flow( - ... output=stim.PauliString("X"), - ... )) + ... ''').has_flow( + ... end=stim.PauliString("X"), + ... ) False >>> stim.Circuit(''' ... CX 0 1 - ... ''').has_flow(stim.Flow( - ... input=stim.PauliString("+X_"), - ... output=stim.PauliString("+XX"), - ... )) + ... ''').has_flow( + ... start=stim.PauliString("+X_"), + ... end=stim.PauliString("+XX"), + ... ) True >>> stim.Circuit(''' @@ -2042,29 +1999,22 @@ def has_flow( ... MXX 0 1 ... MZZ 1 2 ... MX 1 - ... ''').has_flow(stim.Flow( - ... input=stim.PauliString("+X_X"), - ... output=stim.PauliString("+__X"), + ... ''').has_flow( + ... start=stim.PauliString("+X_X"), + ... end=stim.PauliString("+__X"), ... measurements=[0, 2], - ... )) + ... ) True >>> stim.Circuit(''' ... H 0 ... ''').has_flow( - ... stim.Flow("Y -> Y"), + ... start=stim.PauliString("Y"), + ... end=stim.PauliString("Y"), ... unsigned=True, ... ) True - >>> stim.Circuit(''' - ... H 0 - ... ''').has_flow( - ... stim.Flow("Y -> Y"), - ... unsigned=False, - ... ) - False - Caveats: Currently, the unsigned=False version of this method is implemented by performing 256 randomized tests. Each test has a 50% chance of a false @@ -6798,219 +6748,6 @@ def record_index( """ ``` - -```python -# stim.Flow - -# (at top-level in the stim module) -class Flow: - """A stabilizer flow (e.g. "XI -> XX xor rec[-1]"). - - Stabilizer circuits implement, and can be defined by, how they turn input - stabilizers into output stabilizers mediated by measurements. These - relationships are called stabilizer flows, and `stim.Flow` is a representation - of such a flow. For example, a `stim.Flow` can be given to - `stim.Circuit.has_flow` to verify that a circuit implements the flow. - - A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer - P at the start of the circuit to the instantaneous stabilizer Q at the end of - the circuit. The flow may be mediated by certain measurements. For example, - a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and - the CNOT flows implemented by the circuit involve these measurements. - - A flow like P -> Q means the circuit transforms P into Q. - A flow like 1 -> P means the circuit prepares P. - A flow like P -> 1 means the circuit measures P. - A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR). - - References: - Stim's gate documentation includes the stabilizer flows of each gate. - - Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are - defined and provides a circuit construction for experimentally verifying - their presence. - - Examples: - >>> import stim - >>> c = stim.Circuit("CNOT 2 4") - - >>> c.has_flow(stim.Flow("__X__ -> __X_X")) - True - - >>> c.has_flow(stim.Flow("X2*X4 -> X2")) - True - - >>> c.has_flow(stim.Flow("Z4 -> Z4")) - False - """ -``` - - -```python -# stim.Flow.__eq__ - -# (in class stim.Flow) -def __eq__( - self, - arg0: stim.Flow, -) -> bool: - """Determines if two flows have identical contents. - """ -``` - - -```python -# stim.Flow.__init__ - -# (in class stim.Flow) -def __init__( - self, - arg: Union[None, str, stim.Flow] = None, - /, - *, - input: Optional[stim.PauliString] = None, - output: Optional[stim.PauliString] = None, - measurements: Optional[Iterable[Union[int, GateTarget]]] = None, -) -> None: - """Initializes a stim.Flow. - - When given a string, the string is parsed as flow shorthand. For example, - the string "X_ -> ZZ xor rec[-1]" will result in a flow with input pauli string - "X_", output pauli string "ZZ", and measurement indices [-1]. - - Arguments: - arg [position-only]: Defaults to None. Must be specified by itself if used. - str: Initializes a flow by parsing the given shorthand text. - stim.Flow: Initializes a copy of the given flow. - None (default): Initializes an empty flow. - input: Defaults to None. Can be set to a stim.PauliString to directly - specify the flow's input stabilizer. - output: Defaults to None. Can be set to a stim.PauliString to directly - specify the flow's output stabilizer. - measurements: Can be set to a list of integers or gate targets like - `stim.target_rec(-1)`, to specify the measurements that mediate the - flow. Negative and positive measurement indices are allowed. Indexes - follow the python convention where -1 is the last measurement in a - circuit and 0 is the first measurement in a circuit. - - Examples: - >>> import stim - - >>> stim.Flow("X2 -> -Y2*Z4 xor rec[-1]") - stim.Flow("__X -> -__Y_Z xor rec[-1]") - - >>> stim.Flow("Z -> 1 xor rec[-1]") - stim.Flow("Z -> rec[-1]") - - >>> stim.Flow( - ... input=stim.PauliString("XX"), - ... output=stim.PauliString("_X"), - ... measurements=[], - ... ) - stim.Flow("XX -> _X") - """ -``` - - -```python -# stim.Flow.__ne__ - -# (in class stim.Flow) -def __ne__( - self, - arg0: stim.Flow, -) -> bool: - """Determines if two flows have non-identical contents. - """ -``` - - -```python -# stim.Flow.__repr__ - -# (in class stim.Flow) -def __repr__( - self, -) -> str: - """Returns valid python code evaluating to an equivalent `stim.Flow`. - """ -``` - - -```python -# stim.Flow.__str__ - -# (in class stim.Flow) -def __str__( - self, -) -> str: - """Returns a shorthand description of the flow. - """ -``` - - -```python -# stim.Flow.input_copy - -# (in class stim.Flow) -def input_copy( - self, -) -> stim.PauliString: - """Returns a copy of the flow's input stabilizer. - - Examples: - >>> import stim - >>> f = stim.Flow(input=stim.PauliString('XX')) - >>> f.input_copy() - stim.PauliString("+XX") - - >>> f.input_copy() is f.input_copy() - False - """ -``` - - -```python -# stim.Flow.measurements_copy - -# (in class stim.Flow) -def measurements_copy( - self, -) -> List[int]: - """Returns a copy of the flow's measurement indices. - - Examples: - >>> import stim - >>> f = stim.Flow(measurements=[-1, 2]) - >>> f.measurements_copy() - [-1, 2] - - >>> f.measurements_copy() is f.measurements_copy() - False - """ -``` - - -```python -# stim.Flow.output_copy - -# (in class stim.Flow) -def output_copy( - self, -) -> stim.PauliString: - """Returns a copy of the flow's output stabilizer. - - Examples: - >>> import stim - >>> f = stim.Flow(output=stim.PauliString('XX')) - >>> f.output_copy() - stim.PauliString("+XX") - - >>> f.output_copy() is f.output_copy() - False - """ -``` - ```python # stim.GateData @@ -13709,40 +13446,6 @@ def read_shot_data_file( """ ``` - -```python -# stim.target_combined_paulis - -# (at top-level in the stim module) -def target_combined_paulis( - paulis: Union[stim.PauliString, List[stim.GateTarget]], - invert: bool = False, -) -> stim.GateTarget: - """Returns a list of targets encoding a pauli product for instructions like MPP. - - Args: - paulis: The paulis to encode into the targets. This can be a - `stim.PauliString` or a list of pauli targets from `stim.target_x`, - `stim.target_pauli`, etc. - invert: Defaults to False. If True, the product is inverted (like "!X2*Y3"). - Note that this is in addition to any inversions specified by the - `paulis` argument. - - Examples: - >>> import stim - >>> circuit = stim.Circuit() - >>> circuit.append("MPP", [ - ... *stim.target_combined_paulis(stim.PauliString("-XYZ")), - ... *stim.target_combined_paulis([stim.target_x(2), stim.target_y(5)]), - ... *stim.target_combined_paulis([stim.target_z(9)], invert=True), - ... ]) - >>> circuit - stim.Circuit(''' - MPP !X0*Y1*Z2 X2*Y5 !Z9 - ''') - """ -``` - ```python # stim.target_combiner @@ -13827,52 +13530,6 @@ def target_logical_observable_id( """ ``` - -```python -# stim.target_pauli - -# (at top-level in the stim module) -def target_pauli( - qubit_index: int, - pauli: Union[str, int], - invert: bool = False, -) -> stim.GateTarget: - """Returns a pauli target that can be passed into `stim.Circuit.append`. - - Args: - qubit_index: The qubit that the Pauli applies to. - pauli: The pauli gate to use. This can either be a string identifying the - pauli by name ("x", "X", "y", "Y", "z", or "Z") or an integer following - the convention (1=X, 2=Y, 3=Z). Setting this argument to "I" or to - 0 will return a qubit target instead of a pauli target. - invert: Defaults to False. If True, the target is inverted (like "!X10"), - indicating that, for example, measurement results should be inverted). - - Examples: - >>> import stim - >>> circuit = stim.Circuit() - >>> circuit.append("MPP", [ - ... stim.target_pauli(2, "X"), - ... stim.target_combiner(), - ... stim.target_pauli(3, "y", invert=True), - ... stim.target_pauli(5, 3), - ... ]) - >>> circuit - stim.Circuit(''' - MPP X2*!Y3 Z5 - ''') - - >>> circuit.append("M", [ - ... stim.target_pauli(7, "I"), - ... ]) - >>> circuit - stim.Circuit(''' - MPP X2*!Y3 Z5 - M 7 - ''') - """ -``` - ```python # stim.target_rec diff --git a/doc/stim.pyi b/doc/stim.pyi index 7e476efcc..f6a6d5105 100644 --- a/doc/stim.pyi +++ b/doc/stim.pyi @@ -1311,66 +1311,16 @@ class Circuit: >>> circuit.get_final_qubit_coordinates() {1: [1.0, 2.0, 3.0]} """ - def has_all_flows( - self, - flows: Iterable[stim.Flow], - *, - unsigned: bool = False, - ) -> bool: - """Determines if the circuit has all the given stabilizer flow or not. - - This is a faster version of `all(c.has_flow(f) for f in flows)`. It's faster - because, behind the scenes, the circuit can be iterated once instead of once - per flow. - - Args: - flows: An iterable of `stim.Flow` instances representing the flows to check. - unsigned: Defaults to False. When False, the flows must be correct including - the sign of the Pauli strings. When True, only the Pauli terms need to - be correct; the signs are permitted to be inverted. In effect, this - requires the circuit to be correct up to Pauli gates. - - Returns: - True if the circuit has the given flow; False otherwise. - - Examples: - >>> import stim - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> Y'), - ... stim.Flow('Z -> X'), - ... ]) - False - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> -Y'), - ... stim.Flow('Z -> X'), - ... ]) - True - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> Y'), - ... stim.Flow('Z -> X'), - ... ], unsigned=True) - True - - Caveats: - Currently, the unsigned=False version of this method is implemented by - performing 256 randomized tests. Each test has a 50% chance of a false - positive, and a 0% chance of a false negative. So, when the method returns - True, there is technically still a 2^-256 chance the circuit doesn't have - the flow. This is lower than the chance of a cosmic ray flipping the result. - """ def has_flow( self, - flow: stim.Flow, + shorthand: Optional[str] = None, *, + start: Union[None, str, stim.PauliString] = None, + end: Union[None, str, stim.PauliString] = None, + measurements: Optional[Iterable[Union[int, stim.GateTarget]]] = None, unsigned: bool = False, ) -> bool: - """Determines if the circuit has the given stabilizer flow or not. + """Determines if the circuit has a stabilizer flow or not. A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer P at the start of the circuit to the instantaneous stabilizer Q at the end of @@ -1384,7 +1334,26 @@ class Circuit: A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR). Args: - flow: The flow to check for. + shorthand: Specifies the flow as a short string like "X1 -> -YZ xor rec[1]". + The text must contain "->" to separate the input pauli string from the + output pauli string. Measurements are included by appending + " xor rec[k]" for each measurement index k. Indexing uses the python + convention where non-negative indices index from the start and negative + indices index from the end. The pauli strings are parsed as if by + `stim.PauliString.__init__`. + start: The input into the flow at the start of the circuit. Defaults to None + (the identity Pauli string). When specified, this should be a + `stim.PauliString`, or a `str` (which will be parsed using + `stim.PauliString.__init__`). + end: The output from the flow at the end of the circuit. Defaults to None + (the identity Pauli string). When specified, this should be a + `stim.PauliString`, or a `str` (which will be parsed using + `stim.PauliString.__init__`). + measurements: Defaults to None (empty). The indices of measurements to + include in the flow. This should be a collection of integers and/or + stim.GateTarget instances. Indexing uses the python convention where + non-negative indices index from the start and negative indices index + from the end. unsigned: Defaults to False. When False, the flows must be correct including the sign of the Pauli strings. When True, only the Pauli terms need to be correct; the signs are permitted to be inverted. In effect, this @@ -1393,49 +1362,56 @@ class Circuit: Returns: True if the circuit has the given flow; False otherwise. + References: + Stim's gate documentation includes the stabilizer flows of each gate. + + Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are + defined and provides a circuit construction for experimentally verifying + their presence. + Examples: >>> import stim >>> m = stim.Circuit('M 0') - >>> m.has_flow(stim.Flow('Z -> Z')) + >>> m.has_flow('Z -> Z') True - >>> m.has_flow(stim.Flow('X -> X')) + >>> m.has_flow('X -> X') False - >>> m.has_flow(stim.Flow('Z -> I')) + >>> m.has_flow('Z -> I') False - >>> m.has_flow(stim.Flow('Z -> I xor rec[-1]')) + >>> m.has_flow('Z -> I xor rec[-1]') True - >>> m.has_flow(stim.Flow('Z -> rec[-1]')) + >>> m.has_flow('Z -> rec[-1]') True >>> cx58 = stim.Circuit('CX 5 8') - >>> cx58.has_flow(stim.Flow('X5 -> X5*X8')) + >>> cx58.has_flow('X5 -> X5*X8') True - >>> cx58.has_flow(stim.Flow('X_ -> XX')) + >>> cx58.has_flow('X_ -> XX') False - >>> cx58.has_flow(stim.Flow('_____X___ -> _____X__X')) + >>> cx58.has_flow('_____X___ -> _____X__X') True >>> stim.Circuit(''' ... RY 0 - ... ''').has_flow(stim.Flow( - ... output=stim.PauliString("Y"), - ... )) + ... ''').has_flow( + ... end=stim.PauliString("Y"), + ... ) True >>> stim.Circuit(''' ... RY 0 - ... ''').has_flow(stim.Flow( - ... output=stim.PauliString("X"), - ... )) + ... ''').has_flow( + ... end=stim.PauliString("X"), + ... ) False >>> stim.Circuit(''' ... CX 0 1 - ... ''').has_flow(stim.Flow( - ... input=stim.PauliString("+X_"), - ... output=stim.PauliString("+XX"), - ... )) + ... ''').has_flow( + ... start=stim.PauliString("+X_"), + ... end=stim.PauliString("+XX"), + ... ) True >>> stim.Circuit(''' @@ -1444,29 +1420,22 @@ class Circuit: ... MXX 0 1 ... MZZ 1 2 ... MX 1 - ... ''').has_flow(stim.Flow( - ... input=stim.PauliString("+X_X"), - ... output=stim.PauliString("+__X"), + ... ''').has_flow( + ... start=stim.PauliString("+X_X"), + ... end=stim.PauliString("+__X"), ... measurements=[0, 2], - ... )) + ... ) True >>> stim.Circuit(''' ... H 0 ... ''').has_flow( - ... stim.Flow("Y -> Y"), + ... start=stim.PauliString("Y"), + ... end=stim.PauliString("Y"), ... unsigned=True, ... ) True - >>> stim.Circuit(''' - ... H 0 - ... ''').has_flow( - ... stim.Flow("Y -> Y"), - ... unsigned=False, - ... ) - False - Caveats: Currently, the unsigned=False version of this method is implemented by performing 256 randomized tests. Each test has a 50% chance of a false @@ -5190,156 +5159,6 @@ class FlippedMeasurement: For example, the fifth measurement in a circuit has a measurement record index of 4. """ -class Flow: - """A stabilizer flow (e.g. "XI -> XX xor rec[-1]"). - - Stabilizer circuits implement, and can be defined by, how they turn input - stabilizers into output stabilizers mediated by measurements. These - relationships are called stabilizer flows, and `stim.Flow` is a representation - of such a flow. For example, a `stim.Flow` can be given to - `stim.Circuit.has_flow` to verify that a circuit implements the flow. - - A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer - P at the start of the circuit to the instantaneous stabilizer Q at the end of - the circuit. The flow may be mediated by certain measurements. For example, - a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and - the CNOT flows implemented by the circuit involve these measurements. - - A flow like P -> Q means the circuit transforms P into Q. - A flow like 1 -> P means the circuit prepares P. - A flow like P -> 1 means the circuit measures P. - A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR). - - References: - Stim's gate documentation includes the stabilizer flows of each gate. - - Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are - defined and provides a circuit construction for experimentally verifying - their presence. - - Examples: - >>> import stim - >>> c = stim.Circuit("CNOT 2 4") - - >>> c.has_flow(stim.Flow("__X__ -> __X_X")) - True - - >>> c.has_flow(stim.Flow("X2*X4 -> X2")) - True - - >>> c.has_flow(stim.Flow("Z4 -> Z4")) - False - """ - def __eq__( - self, - arg0: stim.Flow, - ) -> bool: - """Determines if two flows have identical contents. - """ - def __init__( - self, - arg: Union[None, str, stim.Flow] = None, - /, - *, - input: Optional[stim.PauliString] = None, - output: Optional[stim.PauliString] = None, - measurements: Optional[Iterable[Union[int, GateTarget]]] = None, - ) -> None: - """Initializes a stim.Flow. - - When given a string, the string is parsed as flow shorthand. For example, - the string "X_ -> ZZ xor rec[-1]" will result in a flow with input pauli string - "X_", output pauli string "ZZ", and measurement indices [-1]. - - Arguments: - arg [position-only]: Defaults to None. Must be specified by itself if used. - str: Initializes a flow by parsing the given shorthand text. - stim.Flow: Initializes a copy of the given flow. - None (default): Initializes an empty flow. - input: Defaults to None. Can be set to a stim.PauliString to directly - specify the flow's input stabilizer. - output: Defaults to None. Can be set to a stim.PauliString to directly - specify the flow's output stabilizer. - measurements: Can be set to a list of integers or gate targets like - `stim.target_rec(-1)`, to specify the measurements that mediate the - flow. Negative and positive measurement indices are allowed. Indexes - follow the python convention where -1 is the last measurement in a - circuit and 0 is the first measurement in a circuit. - - Examples: - >>> import stim - - >>> stim.Flow("X2 -> -Y2*Z4 xor rec[-1]") - stim.Flow("__X -> -__Y_Z xor rec[-1]") - - >>> stim.Flow("Z -> 1 xor rec[-1]") - stim.Flow("Z -> rec[-1]") - - >>> stim.Flow( - ... input=stim.PauliString("XX"), - ... output=stim.PauliString("_X"), - ... measurements=[], - ... ) - stim.Flow("XX -> _X") - """ - def __ne__( - self, - arg0: stim.Flow, - ) -> bool: - """Determines if two flows have non-identical contents. - """ - def __repr__( - self, - ) -> str: - """Returns valid python code evaluating to an equivalent `stim.Flow`. - """ - def __str__( - self, - ) -> str: - """Returns a shorthand description of the flow. - """ - def input_copy( - self, - ) -> stim.PauliString: - """Returns a copy of the flow's input stabilizer. - - Examples: - >>> import stim - >>> f = stim.Flow(input=stim.PauliString('XX')) - >>> f.input_copy() - stim.PauliString("+XX") - - >>> f.input_copy() is f.input_copy() - False - """ - def measurements_copy( - self, - ) -> List[int]: - """Returns a copy of the flow's measurement indices. - - Examples: - >>> import stim - >>> f = stim.Flow(measurements=[-1, 2]) - >>> f.measurements_copy() - [-1, 2] - - >>> f.measurements_copy() is f.measurements_copy() - False - """ - def output_copy( - self, - ) -> stim.PauliString: - """Returns a copy of the flow's output stabilizer. - - Examples: - >>> import stim - >>> f = stim.Flow(output=stim.PauliString('XX')) - >>> f.output_copy() - stim.PauliString("+XX") - - >>> f.output_copy() is f.output_copy() - False - """ class GateData: """Details about a gate supported by stim. @@ -5416,22 +5235,22 @@ class GateData: >>> for e in stim.gate_data('H').__unstable_flows: ... print(e) - X -> Z - Z -> X + +X -> +Z + +Z -> +X >>> for e in stim.gate_data('ISWAP').__unstable_flows: ... print(e) - X_ -> ZY - Z_ -> _Z - _X -> YZ - _Z -> Z_ + +X_ -> +ZY + +Z_ -> +_Z + +_X -> +YZ + +_Z -> +Z_ >>> for e in stim.gate_data('MXX').__unstable_flows: ... print(e) - X_ -> X_ - _X -> _X - ZZ -> ZZ - XX -> rec[-1] + +X_ -> +X_ + +_X -> +_X + +ZZ -> +ZZ + +XX -> rec[-1] """ @property def aliases( @@ -10706,33 +10525,6 @@ def read_shot_data_file( array([[False, False, False, False], [False, True, False, True]]) """ -def target_combined_paulis( - paulis: Union[stim.PauliString, List[stim.GateTarget]], - invert: bool = False, -) -> stim.GateTarget: - """Returns a list of targets encoding a pauli product for instructions like MPP. - - Args: - paulis: The paulis to encode into the targets. This can be a - `stim.PauliString` or a list of pauli targets from `stim.target_x`, - `stim.target_pauli`, etc. - invert: Defaults to False. If True, the product is inverted (like "!X2*Y3"). - Note that this is in addition to any inversions specified by the - `paulis` argument. - - Examples: - >>> import stim - >>> circuit = stim.Circuit() - >>> circuit.append("MPP", [ - ... *stim.target_combined_paulis(stim.PauliString("-XYZ")), - ... *stim.target_combined_paulis([stim.target_x(2), stim.target_y(5)]), - ... *stim.target_combined_paulis([stim.target_z(9)], invert=True), - ... ]) - >>> circuit - stim.Circuit(''' - MPP !X0*Y1*Z2 X2*Y5 !Z9 - ''') - """ def target_combiner( ) -> stim.GateTarget: """Returns a target combiner that can be used to build Pauli products. @@ -10796,45 +10588,6 @@ def target_logical_observable_id( error(0.25) L13 ''') """ -def target_pauli( - qubit_index: int, - pauli: Union[str, int], - invert: bool = False, -) -> stim.GateTarget: - """Returns a pauli target that can be passed into `stim.Circuit.append`. - - Args: - qubit_index: The qubit that the Pauli applies to. - pauli: The pauli gate to use. This can either be a string identifying the - pauli by name ("x", "X", "y", "Y", "z", or "Z") or an integer following - the convention (1=X, 2=Y, 3=Z). Setting this argument to "I" or to - 0 will return a qubit target instead of a pauli target. - invert: Defaults to False. If True, the target is inverted (like "!X10"), - indicating that, for example, measurement results should be inverted). - - Examples: - >>> import stim - >>> circuit = stim.Circuit() - >>> circuit.append("MPP", [ - ... stim.target_pauli(2, "X"), - ... stim.target_combiner(), - ... stim.target_pauli(3, "y", invert=True), - ... stim.target_pauli(5, 3), - ... ]) - >>> circuit - stim.Circuit(''' - MPP X2*!Y3 Z5 - ''') - - >>> circuit.append("M", [ - ... stim.target_pauli(7, "I"), - ... ]) - >>> circuit - stim.Circuit(''' - MPP X2*!Y3 Z5 - M 7 - ''') - """ def target_rec( lookback_index: int, ) -> stim.GateTarget: diff --git a/glue/crumble/gates/gateset.test.js b/glue/crumble/gates/gateset.test.js index 70b5d2958..b38f10adc 100644 --- a/glue/crumble/gates/gateset.test.js +++ b/glue/crumble/gates/gateset.test.js @@ -1,14 +1,11 @@ import {GATE_MAP, GATE_ALIAS_MAP} from "./gateset.js" import {test, assertThat, skipRestOfTestIfHeadless} from "../test/test_util.js"; import {Operation} from '../circuit/operation.js'; +import {KNOWN_GATE_NAMES_FROM_STIM} from '../test/generated_gate_name_list.test.js'; -test("gateset.expected_gates", async () => { - let gateNamesFile = await fetch("generated_gate_name_list.txt"); - assertThat(gateNamesFile.ok).withInfo(gateNamesFile.url).isEqualTo(true); - let gateNamesText = await gateNamesFile.text(); - +test("gateset.expected_gates", () => { let expectedGates = new Set(); - for (let e of gateNamesText.split("\n")) { + for (let e of KNOWN_GATE_NAMES_FROM_STIM.split("\n")) { if (e.length > 0) { expectedGates.add(e); } diff --git a/glue/crumble/test/generated_gate_name_list.txt b/glue/crumble/test/generated_gate_name_list.test.js similarity index 87% rename from glue/crumble/test/generated_gate_name_list.txt rename to glue/crumble/test/generated_gate_name_list.test.js index 9e5db2612..014f45523 100644 --- a/glue/crumble/test/generated_gate_name_list.txt +++ b/glue/crumble/test/generated_gate_name_list.test.js @@ -1,3 +1,4 @@ +const KNOWN_GATE_NAMES_FROM_STIM = ` I X Y @@ -77,3 +78,6 @@ OBSERVABLE_INCLUDE QUBIT_COORDS SHIFT_COORDS TICK +` + +export {KNOWN_GATE_NAMES_FROM_STIM}; diff --git a/glue/python/src/stim/__init__.pyi b/glue/python/src/stim/__init__.pyi index 7e476efcc..f6a6d5105 100644 --- a/glue/python/src/stim/__init__.pyi +++ b/glue/python/src/stim/__init__.pyi @@ -1311,66 +1311,16 @@ class Circuit: >>> circuit.get_final_qubit_coordinates() {1: [1.0, 2.0, 3.0]} """ - def has_all_flows( - self, - flows: Iterable[stim.Flow], - *, - unsigned: bool = False, - ) -> bool: - """Determines if the circuit has all the given stabilizer flow or not. - - This is a faster version of `all(c.has_flow(f) for f in flows)`. It's faster - because, behind the scenes, the circuit can be iterated once instead of once - per flow. - - Args: - flows: An iterable of `stim.Flow` instances representing the flows to check. - unsigned: Defaults to False. When False, the flows must be correct including - the sign of the Pauli strings. When True, only the Pauli terms need to - be correct; the signs are permitted to be inverted. In effect, this - requires the circuit to be correct up to Pauli gates. - - Returns: - True if the circuit has the given flow; False otherwise. - - Examples: - >>> import stim - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> Y'), - ... stim.Flow('Z -> X'), - ... ]) - False - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> -Y'), - ... stim.Flow('Z -> X'), - ... ]) - True - - >>> stim.Circuit('H 0').has_all_flows([ - ... stim.Flow('X -> Z'), - ... stim.Flow('Y -> Y'), - ... stim.Flow('Z -> X'), - ... ], unsigned=True) - True - - Caveats: - Currently, the unsigned=False version of this method is implemented by - performing 256 randomized tests. Each test has a 50% chance of a false - positive, and a 0% chance of a false negative. So, when the method returns - True, there is technically still a 2^-256 chance the circuit doesn't have - the flow. This is lower than the chance of a cosmic ray flipping the result. - """ def has_flow( self, - flow: stim.Flow, + shorthand: Optional[str] = None, *, + start: Union[None, str, stim.PauliString] = None, + end: Union[None, str, stim.PauliString] = None, + measurements: Optional[Iterable[Union[int, stim.GateTarget]]] = None, unsigned: bool = False, ) -> bool: - """Determines if the circuit has the given stabilizer flow or not. + """Determines if the circuit has a stabilizer flow or not. A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer P at the start of the circuit to the instantaneous stabilizer Q at the end of @@ -1384,7 +1334,26 @@ class Circuit: A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR). Args: - flow: The flow to check for. + shorthand: Specifies the flow as a short string like "X1 -> -YZ xor rec[1]". + The text must contain "->" to separate the input pauli string from the + output pauli string. Measurements are included by appending + " xor rec[k]" for each measurement index k. Indexing uses the python + convention where non-negative indices index from the start and negative + indices index from the end. The pauli strings are parsed as if by + `stim.PauliString.__init__`. + start: The input into the flow at the start of the circuit. Defaults to None + (the identity Pauli string). When specified, this should be a + `stim.PauliString`, or a `str` (which will be parsed using + `stim.PauliString.__init__`). + end: The output from the flow at the end of the circuit. Defaults to None + (the identity Pauli string). When specified, this should be a + `stim.PauliString`, or a `str` (which will be parsed using + `stim.PauliString.__init__`). + measurements: Defaults to None (empty). The indices of measurements to + include in the flow. This should be a collection of integers and/or + stim.GateTarget instances. Indexing uses the python convention where + non-negative indices index from the start and negative indices index + from the end. unsigned: Defaults to False. When False, the flows must be correct including the sign of the Pauli strings. When True, only the Pauli terms need to be correct; the signs are permitted to be inverted. In effect, this @@ -1393,49 +1362,56 @@ class Circuit: Returns: True if the circuit has the given flow; False otherwise. + References: + Stim's gate documentation includes the stabilizer flows of each gate. + + Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are + defined and provides a circuit construction for experimentally verifying + their presence. + Examples: >>> import stim >>> m = stim.Circuit('M 0') - >>> m.has_flow(stim.Flow('Z -> Z')) + >>> m.has_flow('Z -> Z') True - >>> m.has_flow(stim.Flow('X -> X')) + >>> m.has_flow('X -> X') False - >>> m.has_flow(stim.Flow('Z -> I')) + >>> m.has_flow('Z -> I') False - >>> m.has_flow(stim.Flow('Z -> I xor rec[-1]')) + >>> m.has_flow('Z -> I xor rec[-1]') True - >>> m.has_flow(stim.Flow('Z -> rec[-1]')) + >>> m.has_flow('Z -> rec[-1]') True >>> cx58 = stim.Circuit('CX 5 8') - >>> cx58.has_flow(stim.Flow('X5 -> X5*X8')) + >>> cx58.has_flow('X5 -> X5*X8') True - >>> cx58.has_flow(stim.Flow('X_ -> XX')) + >>> cx58.has_flow('X_ -> XX') False - >>> cx58.has_flow(stim.Flow('_____X___ -> _____X__X')) + >>> cx58.has_flow('_____X___ -> _____X__X') True >>> stim.Circuit(''' ... RY 0 - ... ''').has_flow(stim.Flow( - ... output=stim.PauliString("Y"), - ... )) + ... ''').has_flow( + ... end=stim.PauliString("Y"), + ... ) True >>> stim.Circuit(''' ... RY 0 - ... ''').has_flow(stim.Flow( - ... output=stim.PauliString("X"), - ... )) + ... ''').has_flow( + ... end=stim.PauliString("X"), + ... ) False >>> stim.Circuit(''' ... CX 0 1 - ... ''').has_flow(stim.Flow( - ... input=stim.PauliString("+X_"), - ... output=stim.PauliString("+XX"), - ... )) + ... ''').has_flow( + ... start=stim.PauliString("+X_"), + ... end=stim.PauliString("+XX"), + ... ) True >>> stim.Circuit(''' @@ -1444,29 +1420,22 @@ class Circuit: ... MXX 0 1 ... MZZ 1 2 ... MX 1 - ... ''').has_flow(stim.Flow( - ... input=stim.PauliString("+X_X"), - ... output=stim.PauliString("+__X"), + ... ''').has_flow( + ... start=stim.PauliString("+X_X"), + ... end=stim.PauliString("+__X"), ... measurements=[0, 2], - ... )) + ... ) True >>> stim.Circuit(''' ... H 0 ... ''').has_flow( - ... stim.Flow("Y -> Y"), + ... start=stim.PauliString("Y"), + ... end=stim.PauliString("Y"), ... unsigned=True, ... ) True - >>> stim.Circuit(''' - ... H 0 - ... ''').has_flow( - ... stim.Flow("Y -> Y"), - ... unsigned=False, - ... ) - False - Caveats: Currently, the unsigned=False version of this method is implemented by performing 256 randomized tests. Each test has a 50% chance of a false @@ -5190,156 +5159,6 @@ class FlippedMeasurement: For example, the fifth measurement in a circuit has a measurement record index of 4. """ -class Flow: - """A stabilizer flow (e.g. "XI -> XX xor rec[-1]"). - - Stabilizer circuits implement, and can be defined by, how they turn input - stabilizers into output stabilizers mediated by measurements. These - relationships are called stabilizer flows, and `stim.Flow` is a representation - of such a flow. For example, a `stim.Flow` can be given to - `stim.Circuit.has_flow` to verify that a circuit implements the flow. - - A circuit has a stabilizer flow P -> Q if it maps the instantaneous stabilizer - P at the start of the circuit to the instantaneous stabilizer Q at the end of - the circuit. The flow may be mediated by certain measurements. For example, - a lattice surgery CNOT involves an MXX measurement and an MZZ measurement, and - the CNOT flows implemented by the circuit involve these measurements. - - A flow like P -> Q means the circuit transforms P into Q. - A flow like 1 -> P means the circuit prepares P. - A flow like P -> 1 means the circuit measures P. - A flow like 1 -> 1 means the circuit contains a check (could be a DETECTOR). - - References: - Stim's gate documentation includes the stabilizer flows of each gate. - - Appendix A of https://arxiv.org/abs/2302.02192 describes how flows are - defined and provides a circuit construction for experimentally verifying - their presence. - - Examples: - >>> import stim - >>> c = stim.Circuit("CNOT 2 4") - - >>> c.has_flow(stim.Flow("__X__ -> __X_X")) - True - - >>> c.has_flow(stim.Flow("X2*X4 -> X2")) - True - - >>> c.has_flow(stim.Flow("Z4 -> Z4")) - False - """ - def __eq__( - self, - arg0: stim.Flow, - ) -> bool: - """Determines if two flows have identical contents. - """ - def __init__( - self, - arg: Union[None, str, stim.Flow] = None, - /, - *, - input: Optional[stim.PauliString] = None, - output: Optional[stim.PauliString] = None, - measurements: Optional[Iterable[Union[int, GateTarget]]] = None, - ) -> None: - """Initializes a stim.Flow. - - When given a string, the string is parsed as flow shorthand. For example, - the string "X_ -> ZZ xor rec[-1]" will result in a flow with input pauli string - "X_", output pauli string "ZZ", and measurement indices [-1]. - - Arguments: - arg [position-only]: Defaults to None. Must be specified by itself if used. - str: Initializes a flow by parsing the given shorthand text. - stim.Flow: Initializes a copy of the given flow. - None (default): Initializes an empty flow. - input: Defaults to None. Can be set to a stim.PauliString to directly - specify the flow's input stabilizer. - output: Defaults to None. Can be set to a stim.PauliString to directly - specify the flow's output stabilizer. - measurements: Can be set to a list of integers or gate targets like - `stim.target_rec(-1)`, to specify the measurements that mediate the - flow. Negative and positive measurement indices are allowed. Indexes - follow the python convention where -1 is the last measurement in a - circuit and 0 is the first measurement in a circuit. - - Examples: - >>> import stim - - >>> stim.Flow("X2 -> -Y2*Z4 xor rec[-1]") - stim.Flow("__X -> -__Y_Z xor rec[-1]") - - >>> stim.Flow("Z -> 1 xor rec[-1]") - stim.Flow("Z -> rec[-1]") - - >>> stim.Flow( - ... input=stim.PauliString("XX"), - ... output=stim.PauliString("_X"), - ... measurements=[], - ... ) - stim.Flow("XX -> _X") - """ - def __ne__( - self, - arg0: stim.Flow, - ) -> bool: - """Determines if two flows have non-identical contents. - """ - def __repr__( - self, - ) -> str: - """Returns valid python code evaluating to an equivalent `stim.Flow`. - """ - def __str__( - self, - ) -> str: - """Returns a shorthand description of the flow. - """ - def input_copy( - self, - ) -> stim.PauliString: - """Returns a copy of the flow's input stabilizer. - - Examples: - >>> import stim - >>> f = stim.Flow(input=stim.PauliString('XX')) - >>> f.input_copy() - stim.PauliString("+XX") - - >>> f.input_copy() is f.input_copy() - False - """ - def measurements_copy( - self, - ) -> List[int]: - """Returns a copy of the flow's measurement indices. - - Examples: - >>> import stim - >>> f = stim.Flow(measurements=[-1, 2]) - >>> f.measurements_copy() - [-1, 2] - - >>> f.measurements_copy() is f.measurements_copy() - False - """ - def output_copy( - self, - ) -> stim.PauliString: - """Returns a copy of the flow's output stabilizer. - - Examples: - >>> import stim - >>> f = stim.Flow(output=stim.PauliString('XX')) - >>> f.output_copy() - stim.PauliString("+XX") - - >>> f.output_copy() is f.output_copy() - False - """ class GateData: """Details about a gate supported by stim. @@ -5416,22 +5235,22 @@ class GateData: >>> for e in stim.gate_data('H').__unstable_flows: ... print(e) - X -> Z - Z -> X + +X -> +Z + +Z -> +X >>> for e in stim.gate_data('ISWAP').__unstable_flows: ... print(e) - X_ -> ZY - Z_ -> _Z - _X -> YZ - _Z -> Z_ + +X_ -> +ZY + +Z_ -> +_Z + +_X -> +YZ + +_Z -> +Z_ >>> for e in stim.gate_data('MXX').__unstable_flows: ... print(e) - X_ -> X_ - _X -> _X - ZZ -> ZZ - XX -> rec[-1] + +X_ -> +X_ + +_X -> +_X + +ZZ -> +ZZ + +XX -> rec[-1] """ @property def aliases( @@ -10706,33 +10525,6 @@ def read_shot_data_file( array([[False, False, False, False], [False, True, False, True]]) """ -def target_combined_paulis( - paulis: Union[stim.PauliString, List[stim.GateTarget]], - invert: bool = False, -) -> stim.GateTarget: - """Returns a list of targets encoding a pauli product for instructions like MPP. - - Args: - paulis: The paulis to encode into the targets. This can be a - `stim.PauliString` or a list of pauli targets from `stim.target_x`, - `stim.target_pauli`, etc. - invert: Defaults to False. If True, the product is inverted (like "!X2*Y3"). - Note that this is in addition to any inversions specified by the - `paulis` argument. - - Examples: - >>> import stim - >>> circuit = stim.Circuit() - >>> circuit.append("MPP", [ - ... *stim.target_combined_paulis(stim.PauliString("-XYZ")), - ... *stim.target_combined_paulis([stim.target_x(2), stim.target_y(5)]), - ... *stim.target_combined_paulis([stim.target_z(9)], invert=True), - ... ]) - >>> circuit - stim.Circuit(''' - MPP !X0*Y1*Z2 X2*Y5 !Z9 - ''') - """ def target_combiner( ) -> stim.GateTarget: """Returns a target combiner that can be used to build Pauli products. @@ -10796,45 +10588,6 @@ def target_logical_observable_id( error(0.25) L13 ''') """ -def target_pauli( - qubit_index: int, - pauli: Union[str, int], - invert: bool = False, -) -> stim.GateTarget: - """Returns a pauli target that can be passed into `stim.Circuit.append`. - - Args: - qubit_index: The qubit that the Pauli applies to. - pauli: The pauli gate to use. This can either be a string identifying the - pauli by name ("x", "X", "y", "Y", "z", or "Z") or an integer following - the convention (1=X, 2=Y, 3=Z). Setting this argument to "I" or to - 0 will return a qubit target instead of a pauli target. - invert: Defaults to False. If True, the target is inverted (like "!X10"), - indicating that, for example, measurement results should be inverted). - - Examples: - >>> import stim - >>> circuit = stim.Circuit() - >>> circuit.append("MPP", [ - ... stim.target_pauli(2, "X"), - ... stim.target_combiner(), - ... stim.target_pauli(3, "y", invert=True), - ... stim.target_pauli(5, 3), - ... ]) - >>> circuit - stim.Circuit(''' - MPP X2*!Y3 Z5 - ''') - - >>> circuit.append("M", [ - ... stim.target_pauli(7, "I"), - ... ]) - >>> circuit - stim.Circuit(''' - MPP X2*!Y3 Z5 - M 7 - ''') - """ def target_rec( lookback_index: int, ) -> stim.GateTarget: