Skip to content

Commit 75d9cb1

Browse files
Optimize backtrack_path to use unordered_map (#1041)
d25, 25 rounds: 83ms -> 39ms d11, 1000 rounds: 640ms -> 300ms This addresses issue #1004, although probably doesn't completely resolve it. Also, the new benchmark introduces didn't reproduce the 60 seconds in the original issue; it took only ~640ms on my machine.
1 parent 12a10a8 commit 75d9cb1

4 files changed

Lines changed: 45 additions & 3 deletions

File tree

src/stim/search/graphlike/algo.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include "stim/search/graphlike/algo.h"
1616

1717
#include <algorithm>
18-
#include <map>
18+
#include <unordered_map>
1919
#include <queue>
2020
#include <sstream>
2121

@@ -27,7 +27,7 @@
2727
using namespace stim;
2828
using namespace stim::impl_search_graphlike;
2929

30-
DetectorErrorModel backtrack_path(const std::map<SearchState, SearchState> &back_map, const SearchState &final_state) {
30+
DetectorErrorModel backtrack_path(const std::unordered_map<SearchState, SearchState, SearchStateHash> &back_map, const SearchState &final_state) {
3131
DetectorErrorModel out;
3232
auto cur_state = final_state;
3333
while (true) {
@@ -55,7 +55,7 @@ DetectorErrorModel stim::shortest_graphlike_undetectable_logical_error(
5555
}
5656

5757
std::queue<SearchState> queue;
58-
std::map<SearchState, SearchState> back_map;
58+
std::unordered_map<SearchState, SearchState, SearchStateHash> back_map;
5959
// Mark the vacuous dead-end state as already seen.
6060
back_map.emplace(empty_search_state, empty_search_state);
6161

src/stim/search/graphlike/algo.perf.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,21 @@ BENCHMARK(find_graphlike_logical_error_surface_code_d25) {
3636
std::cout << "bad";
3737
}
3838
}
39+
40+
BENCHMARK(find_graphlike_logical_error_surface_code_d11_r1000) {
41+
CircuitGenParameters params(1000, 11, "rotated_memory_x");
42+
params.after_clifford_depolarization = 0.001;
43+
params.before_measure_flip_probability = 0.001;
44+
params.after_reset_flip_probability = 0.001;
45+
params.before_round_data_depolarization = 0.001;
46+
auto circuit = generate_surface_code_circuit(params).circuit;
47+
auto model = ErrorAnalyzer::circuit_to_detector_error_model(circuit, true, true, false, 0.0, false, true);
48+
49+
size_t total = 0;
50+
benchmark_go([&]() {
51+
total += stim::shortest_graphlike_undetectable_logical_error(model, false).instructions.size();
52+
}).goal_millis(100);
53+
if (total % 11 != 0 || total == 0) {
54+
std::cout << "bad";
55+
}
56+
}

src/stim/search/graphlike/search_state.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,22 @@ struct SearchState {
4242
};
4343
std::ostream &operator<<(std::ostream &out, const SearchState &v);
4444

45+
inline void hash_combine(size_t &h, uint64_t x) {
46+
h ^= std::hash<uint64_t>{}(x) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2); // mimic Boost's hash-combine function
47+
}
48+
49+
struct SearchStateHash {
50+
size_t operator()(const SearchState &s) const {
51+
SearchState c = s.canonical();
52+
size_t h = std::hash<uint64_t>{}(c.det_active);
53+
hash_combine(h, c.det_held);
54+
for (size_t i = 0; i < c.obs_mask.num_u64_padded(); i++) {
55+
hash_combine(h, c.obs_mask.u64[i]);
56+
}
57+
return h;
58+
}
59+
};
60+
4561
} // namespace impl_search_graphlike
4662
} // namespace stim
4763

src/stim/search/graphlike/search_state.test.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,11 @@ TEST(search_graphlike, DemAdjGraphSearchState_canonical_ordering) {
148148
TEST(search_graphlike, DemAdjGraphSearchState_str) {
149149
ASSERT_EQ(SearchState(1, 2, obs_mask(3)).str(), "D1 D2 L0 L1 ");
150150
}
151+
152+
TEST(search_graphlike, SearchStateHash_operator) {
153+
ASSERT_EQ(SearchStateHash{}(SearchState(1, 2, obs_mask(3))), SearchStateHash{}(SearchState(2, 1, obs_mask(3))));
154+
ASSERT_EQ(SearchStateHash{}(SearchState(1, 2, obs_mask(3))), SearchStateHash{}(SearchState(1, 2, obs_mask(3))));
155+
156+
ASSERT_NE(SearchStateHash{}(SearchState(1, 2, obs_mask(3))), SearchStateHash{}(SearchState(2, 2, obs_mask(3))));
157+
ASSERT_NE(SearchStateHash{}(SearchState(1, 2, obs_mask(3))), SearchStateHash{}(SearchState(1, 2, obs_mask(4))));
158+
}

0 commit comments

Comments
 (0)