diff --git a/doc/python_api_reference_vDev.md b/doc/python_api_reference_vDev.md index 65d29fbf2..87fabcd96 100644 --- a/doc/python_api_reference_vDev.md +++ b/doc/python_api_reference_vDev.md @@ -62,6 +62,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi - [`stim.Circuit.to_tableau`](#stim.Circuit.to_tableau) - [`stim.Circuit.with_inlined_feedback`](#stim.Circuit.with_inlined_feedback) - [`stim.Circuit.without_noise`](#stim.Circuit.without_noise) + - [`stim.Circuit.without_tags`](#stim.Circuit.without_tags) - [`stim.CircuitErrorLocation`](#stim.CircuitErrorLocation) - [`stim.CircuitErrorLocation.__init__`](#stim.CircuitErrorLocation.__init__) - [`stim.CircuitErrorLocation.flipped_measurement`](#stim.CircuitErrorLocation.flipped_measurement) @@ -187,6 +188,7 @@ API references for stable versions are kept on the [stim github wiki](https://gi - [`stim.DetectorErrorModel.rounded`](#stim.DetectorErrorModel.rounded) - [`stim.DetectorErrorModel.shortest_graphlike_error`](#stim.DetectorErrorModel.shortest_graphlike_error) - [`stim.DetectorErrorModel.to_file`](#stim.DetectorErrorModel.to_file) + - [`stim.DetectorErrorModel.without_tags`](#stim.DetectorErrorModel.without_tags) - [`stim.ExplainedError`](#stim.ExplainedError) - [`stim.ExplainedError.__init__`](#stim.ExplainedError.__init__) - [`stim.ExplainedError.circuit_error_locations`](#stim.ExplainedError.circuit_error_locations) @@ -3593,6 +3595,33 @@ def without_noise( """ ``` + +```python +# stim.Circuit.without_tags + +# (in class stim.Circuit) +def without_tags( + self, +) -> stim.Circuit: + """Returns a copy of the circuit with all tags removed. + + Returns: + A `stim.Circuit` with the same instructions except all tags have been + removed. + + Examples: + >>> import stim + >>> stim.Circuit(''' + ... X[test-tag] 0 + ... M[test-tag-2](0.125) 0 + ... ''').without_tags() + stim.Circuit(''' + X 0 + M(0.125) 0 + ''') + """ +``` + ```python # stim.CircuitErrorLocation @@ -7589,6 +7618,31 @@ def to_file( """ ``` + +```python +# stim.DetectorErrorModel.without_tags + +# (in class stim.DetectorErrorModel) +def without_tags( + self, +) -> stim.DetectorErrorModel: + """Returns a copy of the detector error model with all tags removed. + + Returns: + A `stim.DetectorErrorModel` with the same instructions except all tags have + been removed. + + Examples: + >>> import stim + >>> stim.DetectorErrorModel(''' + ... error[test-tag](0.25) D0 + ... ''').without_tags() + stim.DetectorErrorModel(''' + error(0.25) D0 + ''') + """ +``` + ```python # stim.ExplainedError diff --git a/doc/stim.pyi b/doc/stim.pyi index 328ece885..abce4a1ab 100644 --- a/doc/stim.pyi +++ b/doc/stim.pyi @@ -2792,6 +2792,26 @@ class Circuit: M 0 ''') """ + def without_tags( + self, + ) -> stim.Circuit: + """Returns a copy of the circuit with all tags removed. + + Returns: + A `stim.Circuit` with the same instructions except all tags have been + removed. + + Examples: + >>> import stim + >>> stim.Circuit(''' + ... X[test-tag] 0 + ... M[test-tag-2](0.125) 0 + ... ''').without_tags() + stim.Circuit(''' + X 0 + M(0.125) 0 + ''') + """ class CircuitErrorLocation: """Describes the location of an error mechanism from a stim circuit. @@ -5969,6 +5989,24 @@ class DetectorErrorModel: >>> contents 'error(0.25) D2 D3\n' """ + def without_tags( + self, + ) -> stim.DetectorErrorModel: + """Returns a copy of the detector error model with all tags removed. + + Returns: + A `stim.DetectorErrorModel` with the same instructions except all tags have + been removed. + + Examples: + >>> import stim + >>> stim.DetectorErrorModel(''' + ... error[test-tag](0.25) D0 + ... ''').without_tags() + stim.DetectorErrorModel(''' + error(0.25) D0 + ''') + """ class ExplainedError: """Describes the location of an error mechanism from a stim circuit. diff --git a/glue/python/src/stim/__init__.pyi b/glue/python/src/stim/__init__.pyi index 328ece885..abce4a1ab 100644 --- a/glue/python/src/stim/__init__.pyi +++ b/glue/python/src/stim/__init__.pyi @@ -2792,6 +2792,26 @@ class Circuit: M 0 ''') """ + def without_tags( + self, + ) -> stim.Circuit: + """Returns a copy of the circuit with all tags removed. + + Returns: + A `stim.Circuit` with the same instructions except all tags have been + removed. + + Examples: + >>> import stim + >>> stim.Circuit(''' + ... X[test-tag] 0 + ... M[test-tag-2](0.125) 0 + ... ''').without_tags() + stim.Circuit(''' + X 0 + M(0.125) 0 + ''') + """ class CircuitErrorLocation: """Describes the location of an error mechanism from a stim circuit. @@ -5969,6 +5989,24 @@ class DetectorErrorModel: >>> contents 'error(0.25) D2 D3\n' """ + def without_tags( + self, + ) -> stim.DetectorErrorModel: + """Returns a copy of the detector error model with all tags removed. + + Returns: + A `stim.DetectorErrorModel` with the same instructions except all tags have + been removed. + + Examples: + >>> import stim + >>> stim.DetectorErrorModel(''' + ... error[test-tag](0.25) D0 + ... ''').without_tags() + stim.DetectorErrorModel(''' + error(0.25) D0 + ''') + """ class ExplainedError: """Describes the location of an error mechanism from a stim circuit. diff --git a/src/stim/circuit/circuit.cc b/src/stim/circuit/circuit.cc index b158069e1..225acf44d 100644 --- a/src/stim/circuit/circuit.cc +++ b/src/stim/circuit/circuit.cc @@ -802,6 +802,22 @@ const Circuit Circuit::aliased_noiseless_circuit() const { return result; } +Circuit Circuit::without_tags() const { + Circuit result; + for (CircuitInstruction inst : operations) { + if (inst.gate_type == GateType::REPEAT) { + result.append_repeat_block( + inst.repeat_block_rep_count(), + inst.repeat_block_body(*this).without_tags(), + ""); + } else { + inst.tag = ""; + result.safe_append(inst); + } + } + return result; +} + Circuit Circuit::without_noise() const { Circuit result; for (const auto &op : operations) { diff --git a/src/stim/circuit/circuit.h b/src/stim/circuit/circuit.h index 35d1361e2..1785ff689 100644 --- a/src/stim/circuit/circuit.h +++ b/src/stim/circuit/circuit.h @@ -147,6 +147,8 @@ struct Circuit { /// Returns a copy of the circuit with all noise processes removed. Circuit without_noise() const; + /// Returns a copy of the circuit with all tags removed. + Circuit without_tags() const; /// Returns an equivalent circuit without REPEAT or SHIFT_COORDS instructions. Circuit flattened() const; diff --git a/src/stim/circuit/circuit.pybind.cc b/src/stim/circuit/circuit.pybind.cc index 772a7d9f7..06cb84c04 100644 --- a/src/stim/circuit/circuit.pybind.cc +++ b/src/stim/circuit/circuit.pybind.cc @@ -2236,6 +2236,29 @@ void stim_pybind::pybind_circuit_methods(pybind11::module &, pybind11::class_>> import stim + >>> stim.Circuit(''' + ... X[test-tag] 0 + ... M[test-tag-2](0.125) 0 + ... ''').without_tags() + stim.Circuit(''' + X 0 + M(0.125) 0 + ''') + )DOC") + .data()); + c.def( "flattened", &Circuit::flattened, diff --git a/src/stim/circuit/circuit.test.cc b/src/stim/circuit/circuit.test.cc index 4ef0e1e8f..bfe081a6a 100644 --- a/src/stim/circuit/circuit.test.cc +++ b/src/stim/circuit/circuit.test.cc @@ -1985,3 +1985,22 @@ TEST(circuit, insert_instruction) { X 1 )CIRCUIT")); } + +TEST(circuit, without_tags) { + Circuit initial(R"CIRCUIT( + H[test-1] 0 + REPEAT[test-2] 100 { + REPEAT[test-3] 100 { + M[test-4](0.125) 0 + } + } + )CIRCUIT"); + ASSERT_EQ(initial.without_tags(), Circuit(R"CIRCUIT( + H 0 + REPEAT 100 { + REPEAT 100 { + M(0.125) 0 + } + } + )CIRCUIT")); +} diff --git a/src/stim/circuit/circuit_pybind_test.py b/src/stim/circuit/circuit_pybind_test.py index 2bf84480d..effb05b1b 100644 --- a/src/stim/circuit/circuit_pybind_test.py +++ b/src/stim/circuit/circuit_pybind_test.py @@ -2351,3 +2351,12 @@ def test_append_pauli_string(): c.append("MPP", object()) with pytest.raises(ValueError, match="Don't know how to target"): c.append("MPP", object()) + + +def test_without_tags(): + circuit = stim.Circuit(""" + H[tag] 5 + """) + assert circuit.without_tags() == stim.Circuit(""" + H 5 + """) diff --git a/src/stim/dem/detector_error_model.cc b/src/stim/dem/detector_error_model.cc index 0ac4e5063..a0f8071c4 100644 --- a/src/stim/dem/detector_error_model.cc +++ b/src/stim/dem/detector_error_model.cc @@ -774,3 +774,19 @@ std::map> DetectorErrorModel::get_detector_coordin return out; } + +DetectorErrorModel DetectorErrorModel::without_tags() const { + DetectorErrorModel result; + for (DemInstruction inst : instructions) { + if (inst.type == DemInstructionType::DEM_REPEAT_BLOCK) { + result.append_repeat_block( + inst.repeat_block_rep_count(), + inst.repeat_block_body(*this).without_tags(), + ""); + } else { + inst.tag = ""; + result.append_dem_instruction(inst); + } + } + return result; +} diff --git a/src/stim/dem/detector_error_model.h b/src/stim/dem/detector_error_model.h index 72c0eb432..1e0e09871 100644 --- a/src/stim/dem/detector_error_model.h +++ b/src/stim/dem/detector_error_model.h @@ -63,6 +63,8 @@ struct DetectorErrorModel { bool approx_equals(const DetectorErrorModel &other, double atol) const; std::string str() const; + DetectorErrorModel without_tags() const; + uint64_t total_detector_shift() const; uint64_t count_detectors() const; uint64_t count_observables() const; diff --git a/src/stim/dem/detector_error_model.pybind.cc b/src/stim/dem/detector_error_model.pybind.cc index 4aed906b9..b2729c070 100644 --- a/src/stim/dem/detector_error_model.pybind.cc +++ b/src/stim/dem/detector_error_model.pybind.cc @@ -1204,4 +1204,25 @@ void stim_pybind::pybind_detector_error_model_methods( ... print(diagram, file=f) )DOC") .data()); + + c.def( + "without_tags", + &DetectorErrorModel::without_tags, + clean_doc_string(R"DOC( + Returns a copy of the detector error model with all tags removed. + + Returns: + A `stim.DetectorErrorModel` with the same instructions except all tags have + been removed. + + Examples: + >>> import stim + >>> stim.DetectorErrorModel(''' + ... error[test-tag](0.25) D0 + ... ''').without_tags() + stim.DetectorErrorModel(''' + error(0.25) D0 + ''') + )DOC") + .data()); } diff --git a/src/stim/dem/detector_error_model_pybind_test.py b/src/stim/dem/detector_error_model_pybind_test.py index 25fc80ad2..3ebc6c0b7 100644 --- a/src/stim/dem/detector_error_model_pybind_test.py +++ b/src/stim/dem/detector_error_model_pybind_test.py @@ -540,3 +540,12 @@ def test_shortest_graphlike_error_remnant(): def test_init_parse(): assert stim.DemInstruction("error(0.125) D0 D1") == stim.DemInstruction("error", [0.125], [stim.DemTarget("D0"), stim.DemTarget("D1")]) + + +def test_without_tags(): + dem = stim.DetectorErrorModel(""" + error[tag](0.25) D5 + """) + assert dem.without_tags() == stim.DetectorErrorModel(""" + error(0.25) D5 + """)