diff --git a/doc/python_api_reference_vDev.md b/doc/python_api_reference_vDev.md index 4e73e8d49..daba31e16 100644 --- a/doc/python_api_reference_vDev.md +++ b/doc/python_api_reference_vDev.md @@ -5236,7 +5236,7 @@ def rounded( # (in class stim.DetectorErrorModel) def shortest_graphlike_error( self, - ignore_ungraphlike_errors: bool = False, + ignore_ungraphlike_errors: bool = True, ) -> stim.DetectorErrorModel: """Finds a minimum set of graphlike errors to produce an undetected logical error. diff --git a/doc/stim.pyi b/doc/stim.pyi index dd7928692..c97e165e6 100644 --- a/doc/stim.pyi +++ b/doc/stim.pyi @@ -3929,7 +3929,7 @@ class DetectorErrorModel: """ def shortest_graphlike_error( self, - ignore_ungraphlike_errors: bool = False, + ignore_ungraphlike_errors: bool = True, ) -> stim.DetectorErrorModel: """Finds a minimum set of graphlike errors to produce an undetected logical error. diff --git a/glue/python/src/stim/__init__.pyi b/glue/python/src/stim/__init__.pyi index dd7928692..c97e165e6 100644 --- a/glue/python/src/stim/__init__.pyi +++ b/glue/python/src/stim/__init__.pyi @@ -3929,7 +3929,7 @@ class DetectorErrorModel: """ def shortest_graphlike_error( self, - ignore_ungraphlike_errors: bool = False, + ignore_ungraphlike_errors: bool = True, ) -> stim.DetectorErrorModel: """Finds a minimum set of graphlike errors to produce an undetected logical error. diff --git a/src/stim/circuit/circuit_instruction.pybind.cc b/src/stim/circuit/circuit_instruction.pybind.cc index 92f64b239..41f39cf90 100644 --- a/src/stim/circuit/circuit_instruction.pybind.cc +++ b/src/stim/circuit/circuit_instruction.pybind.cc @@ -71,7 +71,7 @@ std::vector CircuitInstruction::raw_targets() const { result.push_back(t.data); } return result; -}; +} std::vector CircuitInstruction::targets_copy() const { return targets; diff --git a/src/stim/circuit/circuit_pybind_test.py b/src/stim/circuit/circuit_pybind_test.py index b4f97a101..dc7c2884c 100644 --- a/src/stim/circuit/circuit_pybind_test.py +++ b/src/stim/circuit/circuit_pybind_test.py @@ -708,6 +708,20 @@ def test_shortest_graphlike_error(): }""" +def test_shortest_graphlike_error_empty(): + with pytest.raises(ValueError, match="Failed to find"): + stim.Circuit().shortest_graphlike_error() + + +def test_search_for_undetectable_logical_errors_empty(): + with pytest.raises(ValueError, match="Failed to find"): + stim.Circuit().search_for_undetectable_logical_errors( + dont_explore_edges_increasing_symptom_degree=True, + dont_explore_edges_with_degree_above=4, + dont_explore_detection_event_sets_with_size_above=4, + ) + + def test_shortest_graphlike_error_ignore(): c = stim.Circuit(""" TICK diff --git a/src/stim/dem/detector_error_model.pybind.cc b/src/stim/dem/detector_error_model.pybind.cc index e4de1ed71..46f3f17cc 100644 --- a/src/stim/dem/detector_error_model.pybind.cc +++ b/src/stim/dem/detector_error_model.pybind.cc @@ -742,7 +742,7 @@ void stim_pybind::pybind_detector_error_model_methods( c.def( "shortest_graphlike_error", &shortest_graphlike_undetectable_logical_error, - pybind11::arg("ignore_ungraphlike_errors") = false, + pybind11::arg("ignore_ungraphlike_errors") = true, clean_doc_string(u8R"DOC( Finds a minimum set of graphlike errors to produce an undetected logical error. diff --git a/src/stim/dem/detector_error_model_pybind_test.py b/src/stim/dem/detector_error_model_pybind_test.py index be1353d3e..9a6367da8 100644 --- a/src/stim/dem/detector_error_model_pybind_test.py +++ b/src/stim/dem/detector_error_model_pybind_test.py @@ -461,3 +461,39 @@ def test_diagram(): assert dem.diagram(type="match-graph-svg") is not None assert dem.diagram(type="match-graph-3d") is not None assert dem.diagram(type="match-graph-3d-html") is not None + + +def test_shortest_graphlike_error_remnant(): + c = stim.Circuit(""" + X_ERROR(0.125) 0 1 2 3 4 5 6 7 10 + E(0.125) X2 X3 X10 + M 0 1 2 3 4 5 6 7 10 + OBSERVABLE_INCLUDE(0) rec[-2] + DETECTOR rec[-1] + DETECTOR rec[-2] rec[-3] + DETECTOR rec[-3] rec[-4] + DETECTOR rec[-4] rec[-5] + DETECTOR rec[-5] rec[-6] + DETECTOR rec[-6] rec[-7] + DETECTOR rec[-7] rec[-8] + DETECTOR rec[-8] rec[-9] + """) + d = stim.DetectorErrorModel(""" + error(0.125) D0 + error(0.125) D0 ^ D4 D6 + error(0.125) D1 D2 + error(0.125) D1 L0 + error(0.125) D2 D3 + error(0.125) D3 D4 + error(0.125) D4 D5 + error(0.125) D5 D6 + error(0.125) D6 D7 + error(0.125) D7 + """) + assert c.detector_error_model(decompose_errors=True) == d + assert len(c.shortest_graphlike_error(ignore_ungraphlike_errors=False)) == 7 + assert len(d.shortest_graphlike_error(ignore_ungraphlike_errors=False)) == 7 + assert len(c.shortest_graphlike_error(ignore_ungraphlike_errors=True)) == 8 + assert len(d.shortest_graphlike_error(ignore_ungraphlike_errors=True)) == 8 + assert len(c.shortest_graphlike_error()) == 8 + assert len(d.shortest_graphlike_error()) == 8 diff --git a/src/stim/search/graphlike/graph.cc b/src/stim/search/graphlike/graph.cc index 6eaa4f0d0..171d0119a 100644 --- a/src/stim/search/graphlike/graph.cc +++ b/src/stim/search/graphlike/graph.cc @@ -82,6 +82,9 @@ void Graph::add_edges_from_separable_targets(ConstPointerRange target const DemTarget *cur = targets.begin(); while (true) { if (cur == targets.end() || cur->is_separator()) { + if (ignore_ungraphlike_errors && cur != targets.end()) { + return; + } add_edges_from_targets_with_no_separators({prev, cur}, ignore_ungraphlike_errors); prev = cur + 1; } diff --git a/src/stim/search/graphlike/graph.test.cc b/src/stim/search/graphlike/graph.test.cc index 76bd595c4..e2dfa4f7a 100644 --- a/src/stim/search/graphlike/graph.test.cc +++ b/src/stim/search/graphlike/graph.test.cc @@ -229,3 +229,19 @@ TEST(search_graphlike, DemAdjGraph_from_dem) { }, 0)); } + +TEST(search_graphlike, add_edges_from_separable_targets_ignore) { + Graph actual(10); + Graph expected(10); + DetectorErrorModel d(R"DEM( + error(0.125) D0 ^ D4 D6 + )DEM"); + ASSERT_EQ(actual, expected); + actual.add_edges_from_separable_targets(d.instructions[0].target_data, true); + ASSERT_EQ(actual, expected); + actual.add_edges_from_separable_targets(d.instructions[0].target_data, false); + expected.add_outward_edge(4, 6, 0); + expected.add_outward_edge(6, 4, 0); + expected.add_outward_edge(0, NO_NODE_INDEX, 0); + ASSERT_EQ(actual, expected); +} diff --git a/src/stim/search/hyper/algo.cc b/src/stim/search/hyper/algo.cc index 62e5f7e73..53cec0265 100644 --- a/src/stim/search/hyper/algo.cc +++ b/src/stim/search/hyper/algo.cc @@ -101,5 +101,5 @@ DetectorErrorModel stim::find_undetectable_logical_error( } } - throw std::invalid_argument("Failed to find any decaying logical errors."); + throw std::invalid_argument("Failed to find any logical errors."); } diff --git a/src/stim/simulators/error_analyzer.test.cc b/src/stim/simulators/error_analyzer.test.cc index 2982c7323..e6d64f078 100644 --- a/src/stim/simulators/error_analyzer.test.cc +++ b/src/stim/simulators/error_analyzer.test.cc @@ -3246,3 +3246,19 @@ TEST(ErrorAnalyzer, else_correlated_error_block) { { ErrorAnalyzer::circuit_to_detector_error_model(c, true, true, false, 1, false, false); }, std::invalid_argument); } + +TEST(ErrorAnalyzer, measurement_before_beginning) { + Circuit c(R"CIRCUIT( + DETECTOR rec[-1] + )CIRCUIT"); + ASSERT_THROW( + { ErrorAnalyzer::circuit_to_detector_error_model(c, false, false, false, false, false, false); }, + std::invalid_argument); + + c = Circuit(R"CIRCUIT( + OBSERVABLE_INCLUDE(0) rec[-1] + )CIRCUIT"); + ASSERT_THROW( + { ErrorAnalyzer::circuit_to_detector_error_model(c, false, false, false, false, false, false); }, + std::invalid_argument); +} diff --git a/src/stim/simulators/sparse_rev_frame_tracker.cc b/src/stim/simulators/sparse_rev_frame_tracker.cc index 6d92b627d..9928fb92c 100644 --- a/src/stim/simulators/sparse_rev_frame_tracker.cc +++ b/src/stim/simulators/sparse_rev_frame_tracker.cc @@ -507,14 +507,22 @@ void SparseUnsignedRevFrameTracker::undo_DETECTOR(const OperationData &dat) { num_detectors_in_past--; auto det = DemTarget::relative_detector_id(num_detectors_in_past); for (auto t : dat.targets) { - rec_bits[num_measurements_in_past + t.rec_offset()].xor_item(det); + int64_t index = t.rec_offset() + (int64_t)num_measurements_in_past; + if (index < 0) { + throw std::invalid_argument("Referred to a measurement result before the beginning of time."); + } + rec_bits[(size_t)index].xor_item(det); } } void SparseUnsignedRevFrameTracker::undo_OBSERVABLE_INCLUDE(const OperationData &dat) { auto obs = DemTarget::observable_id((int32_t)dat.args[0]); for (auto t : dat.targets) { - rec_bits[num_measurements_in_past + t.rec_offset()].xor_item(obs); + int64_t index = t.rec_offset() + (int64_t)num_measurements_in_past; + if (index < 0) { + throw std::invalid_argument("Referred to a measurement result before the beginning of time."); + } + rec_bits[index].xor_item(obs); } }