Skip to content

Commit

Permalink
Fix inconsistency between shortest_graphlike_error in dem and circuits (
Browse files Browse the repository at this point in the history
#429)

BREAKING CHANGE: change default value of stim.DetectorErrorModel.shortest_graphlike_error(ignore_ungraphlike_errors) to ignore_ungraphlike_errors=True

Fixes #391
  • Loading branch information
Strilanc authored Nov 19, 2022
1 parent fb83dba commit 626f208
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 8 deletions.
2 changes: 1 addition & 1 deletion doc/python_api_reference_vDev.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion doc/stim.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion glue/python/src/stim/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/stim/circuit/circuit_instruction.pybind.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ std::vector<uint32_t> CircuitInstruction::raw_targets() const {
result.push_back(t.data);
}
return result;
};
}

std::vector<GateTarget> CircuitInstruction::targets_copy() const {
return targets;
Expand Down
14 changes: 14 additions & 0 deletions src/stim/circuit/circuit_pybind_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/stim/dem/detector_error_model.pybind.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
36 changes: 36 additions & 0 deletions src/stim/dem/detector_error_model_pybind_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions src/stim/search/graphlike/graph.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ void Graph::add_edges_from_separable_targets(ConstPointerRange<DemTarget> 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;
}
Expand Down
16 changes: 16 additions & 0 deletions src/stim/search/graphlike/graph.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
2 changes: 1 addition & 1 deletion src/stim/search/hyper/algo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
}
16 changes: 16 additions & 0 deletions src/stim/simulators/error_analyzer.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
12 changes: 10 additions & 2 deletions src/stim/simulators/sparse_rev_frame_tracker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down

0 comments on commit 626f208

Please sign in to comment.