Skip to content

Commit fddbb3f

Browse files
authored
fix typo (#29)
1 parent 90d326b commit fddbb3f

File tree

11 files changed

+188
-20
lines changed

11 files changed

+188
-20
lines changed

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ A Search-Based Decoder for Quantum Error Correction.
1919
Tesseract is a Most Likely Error decoder designed for Low Density Parity Check (LDPC) quantum
2020
error-correcting codes. It applies pruning heuristics and manifold orientation techniques during a
2121
search over the error subsets to identify the most likely error configuration consistent with the
22-
observed syndrome. Tesseract archives significant speed improvements over traditional integer
22+
observed syndrome. Tesseract achieves significant speed improvements over traditional integer
2323
programming-based decoders while maintaining comparable accuracy at moderate physical error rates.
2424

2525
We tested the Tesseract decoder for:
@@ -37,7 +37,8 @@ We tested the Tesseract decoder for:
3737
* **Stim and DEM Support:** processes [Stim](https://github.com/quantumlib/stim) circuit files and
3838
[Detector Error Model
3939
(DEM)](https://github.com/quantumlib/Stim/blob/main/doc/file_format_dem_detector_error_model.md)
40-
files with arbitrary error models.
40+
files with arbitrary error models. Zero-probability error instructions are
41+
automatically removed when a DEM is loaded.
4142
* **Parallel Decoding:** uses multithreading to accelerate the decoding process, making it
4243
suitable for large-scale simulations.
4344
* **Efficient Beam Search:** implements a [beam search](https://en.wikipedia.org/wiki/Beam_search)
@@ -68,6 +69,19 @@ Tesseract uses [Bazel](https://bazel.build/) as its build system. To build the d
6869
bazel build src:all
6970
```
7071

72+
## Running Tests
73+
74+
Unit tests are executed with Bazel. Run the quick test suite using:
75+
```bash
76+
bazel test //src:all
77+
```
78+
By default the tests use reduced parameters and finish in under 30 seconds.
79+
To run a more exhaustive suite with additional shots and larger distances, set:
80+
```bash
81+
TESSERACT_LONG_TESTS=1 bazel test //src:all
82+
```
83+
84+
7185
## Usage
7286

7387
The file `tesseract_main.cc` provides the main entry point for Tesseract Decoder. It can decode

src/BUILD

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ OPT_COPTS = select({
2727
"//conditions:default": [
2828
"-Ofast",
2929
"-fno-fast-math",
30-
"-flto",
3130
"-march=native",
3231
],
3332
":debug": ["-Og"],
@@ -42,7 +41,6 @@ OPT_LINKOPTS = select({
4241
"//conditions:default": [
4342
"-Ofast",
4443
"-fno-fast-math",
45-
"-flto",
4644
"-march=native",
4745
],
4846
":debug": [],
@@ -141,6 +139,9 @@ cc_test(
141139
cc_test(
142140
name = "common_tests",
143141
srcs = ["common.test.cc"],
142+
copts = OPT_COPTS,
143+
linkopts = OPT_LINKOPTS,
144+
linkstatic = True,
144145
deps = [
145146
":libcommon",
146147
"@gtest",

src/common.cc

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,29 @@ stim::DetectorErrorModel common::merge_identical_errors(
113113
return out_dem;
114114
}
115115

116+
stim::DetectorErrorModel common::remove_zero_probability_errors(
117+
const stim::DetectorErrorModel& dem) {
118+
stim::DetectorErrorModel out_dem;
119+
for (const stim::DemInstruction& instruction : dem.flattened().instructions) {
120+
switch (instruction.type) {
121+
case stim::DemInstructionType::DEM_SHIFT_DETECTORS:
122+
assert(false && "unreachable");
123+
break;
124+
case stim::DemInstructionType::DEM_ERROR:
125+
if (instruction.arg_data[0] > 0) {
126+
out_dem.append_dem_instruction(instruction);
127+
}
128+
break;
129+
case stim::DemInstructionType::DEM_DETECTOR:
130+
out_dem.append_dem_instruction(instruction);
131+
break;
132+
default:
133+
assert(false && "unreachable");
134+
}
135+
}
136+
return out_dem;
137+
}
138+
116139
stim::DetectorErrorModel common::dem_from_counts(
117140
stim::DetectorErrorModel& orig_dem, const std::vector<size_t>& error_counts,
118141
size_t num_shots) {
@@ -121,6 +144,17 @@ stim::DetectorErrorModel common::dem_from_counts(
121144
"Error hits array must be the same size as the number of errors in the "
122145
"original DEM.");
123146
}
147+
148+
for (const stim::DemInstruction& instruction :
149+
orig_dem.flattened().instructions) {
150+
if (instruction.type == stim::DemInstructionType::DEM_ERROR &&
151+
instruction.arg_data[0] == 0) {
152+
throw std::invalid_argument(
153+
"dem_from_counts requires DEMs without zero-probability errors. Use"
154+
" remove_zero_probability_errors first.");
155+
}
156+
}
157+
124158
stim::DetectorErrorModel out_dem;
125159
size_t ei = 0;
126160
for (const stim::DemInstruction& instruction :
@@ -130,14 +164,11 @@ stim::DetectorErrorModel common::dem_from_counts(
130164
assert(false && "unreachable");
131165
break;
132166
case stim::DemInstructionType::DEM_ERROR: {
133-
// Ignore zero-probability errors
134-
if (instruction.arg_data[0] > 0) {
135-
double est_probability =
136-
double(error_counts.at(ei)) / double(num_shots);
137-
out_dem.append_error_instruction(est_probability,
138-
instruction.target_data, /*tag=*/"");
139-
++ei;
140-
}
167+
double est_probability =
168+
double(error_counts.at(ei)) / double(num_shots);
169+
out_dem.append_error_instruction(est_probability,
170+
instruction.target_data, /*tag=*/"");
171+
++ei;
141172
break;
142173
}
143174
case stim::DemInstructionType::DEM_DETECTOR: {

src/common.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,15 @@ struct Error {
7171
stim::DetectorErrorModel merge_identical_errors(
7272
const stim::DetectorErrorModel& dem);
7373

74+
// Returns a copy of the given error model with any zero-probability DEM_ERROR
75+
// instructions removed.
76+
stim::DetectorErrorModel remove_zero_probability_errors(
77+
const stim::DetectorErrorModel& dem);
78+
7479
// Makes a new dem where the probabilities of errors are estimated from the
7580
// fraction of shots they were used in.
81+
// Throws std::invalid_argument if `orig_dem` contains zero-probability errors;
82+
// call remove_zero_probability_errors first.
7683
stim::DetectorErrorModel dem_from_counts(
7784
stim::DetectorErrorModel& orig_dem, const std::vector<size_t>& error_counts,
7885
size_t num_shots);

src/common.test.cc

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,83 @@ TEST(common, ErrorsStructFromDemInstruction) {
2525
EXPECT_EQ(ES.symptom.detectors, std::vector<int>{1});
2626
EXPECT_EQ(ES.symptom.observables, 0b01);
2727
}
28+
29+
TEST(common, DemFromCountsRejectsZeroProbabilityErrors) {
30+
stim::DetectorErrorModel dem(R"DEM(
31+
error(0.1) D0
32+
error(0) D1
33+
error(0.2) D2
34+
detector(0, 0, 0) D0
35+
detector(0, 0, 0) D1
36+
detector(0, 0, 0) D2
37+
)DEM");
38+
39+
std::vector<size_t> counts{1, 7, 4};
40+
size_t num_shots = 10;
41+
EXPECT_THROW({
42+
common::dem_from_counts(dem, counts, num_shots);
43+
}, std::invalid_argument);
44+
45+
stim::DetectorErrorModel cleaned = common::remove_zero_probability_errors(dem);
46+
stim::DetectorErrorModel out_dem =
47+
common::dem_from_counts(cleaned, std::vector<size_t>{1, 4}, num_shots);
48+
49+
auto flat = out_dem.flattened();
50+
ASSERT_EQ(out_dem.count_errors(), 2);
51+
ASSERT_GE(flat.instructions.size(), 2);
52+
53+
EXPECT_EQ(flat.instructions[0].type,
54+
stim::DemInstructionType::DEM_ERROR);
55+
EXPECT_NEAR(flat.instructions[0].arg_data[0], 0.1, 1e-9);
56+
ASSERT_EQ(flat.instructions[1].type,
57+
stim::DemInstructionType::DEM_ERROR);
58+
EXPECT_NEAR(flat.instructions[1].arg_data[0], 0.4, 1e-9);
59+
}
60+
61+
TEST(common, DemFromCountsSimpleTwoErrors) {
62+
stim::DetectorErrorModel dem(R"DEM(
63+
error(0.25) D0
64+
error(0.35) D1
65+
detector(0, 0, 0) D0
66+
detector(0, 0, 0) D1
67+
)DEM");
68+
69+
std::vector<size_t> counts{5, 7};
70+
size_t num_shots = 20;
71+
stim::DetectorErrorModel out_dem =
72+
common::dem_from_counts(dem, counts, num_shots);
73+
74+
auto flat = out_dem.flattened();
75+
ASSERT_EQ(out_dem.count_errors(), 2);
76+
77+
ASSERT_GE(flat.instructions.size(), 2);
78+
EXPECT_EQ(flat.instructions[0].type,
79+
stim::DemInstructionType::DEM_ERROR);
80+
EXPECT_NEAR(flat.instructions[0].arg_data[0], 0.25, 1e-9);
81+
EXPECT_EQ(flat.instructions[1].type,
82+
stim::DemInstructionType::DEM_ERROR);
83+
EXPECT_NEAR(flat.instructions[1].arg_data[0], 0.35, 1e-9);
84+
}
85+
86+
TEST(common, RemoveZeroProbabilityErrors) {
87+
stim::DetectorErrorModel dem(R"DEM(
88+
error(0.1) D0
89+
error(0) D1
90+
error(0.2) D2
91+
detector(0, 0, 0) D0
92+
detector(0, 0, 0) D1
93+
detector(0, 0, 0) D2
94+
)DEM");
95+
96+
stim::DetectorErrorModel cleaned =
97+
common::remove_zero_probability_errors(dem);
98+
99+
EXPECT_EQ(cleaned.count_errors(), 2);
100+
auto flat = cleaned.flattened();
101+
ASSERT_EQ(flat.instructions[0].type,
102+
stim::DemInstructionType::DEM_ERROR);
103+
EXPECT_NEAR(flat.instructions[0].arg_data[0], 0.1, 1e-9);
104+
ASSERT_EQ(flat.instructions[1].type,
105+
stim::DemInstructionType::DEM_ERROR);
106+
EXPECT_NEAR(flat.instructions[1].arg_data[0], 0.2, 1e-9);
107+
}

src/simplex.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
constexpr size_t T_COORD = 2;
2323

2424
SimplexDecoder::SimplexDecoder(SimplexConfig _config) : config(_config) {
25+
config.dem = common::remove_zero_probability_errors(config.dem);
2526
std::vector<double> detector_t_coords(config.dem.count_detectors());
2627
for (const stim::DemInstruction& instruction :
2728
config.dem.flattened().instructions) {
@@ -30,10 +31,8 @@ SimplexDecoder::SimplexDecoder(SimplexConfig _config) : config(_config) {
3031
assert(false && "unreachable");
3132
break;
3233
case stim::DemInstructionType::DEM_ERROR: {
33-
// Ignore zero-probability errors
34-
if (instruction.arg_data[0] > 0) {
35-
errors.emplace_back(instruction);
36-
}
34+
assert(instruction.arg_data[0] > 0);
35+
errors.emplace_back(instruction);
3736
break;
3837
}
3938
case stim::DemInstructionType::DEM_DETECTOR:

src/simplex_main.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ struct Args {
175175
if (!no_merge_errors) {
176176
config.dem = common::merge_identical_errors(config.dem);
177177
}
178+
config.dem = common::remove_zero_probability_errors(config.dem);
178179

179180
if (sample_num_shots > 0) {
180181
assert(!circuit_path.empty());

src/tesseract.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ double TesseractDecoder::get_detcost(size_t d,
3737
}
3838

3939
TesseractDecoder::TesseractDecoder(TesseractConfig config_) : config(config_) {
40+
config.dem = common::remove_zero_probability_errors(config.dem);
4041
if (config.det_orders.empty()) {
4142
config.det_orders.emplace_back(config.dem.count_detectors());
4243
std::iota(config.det_orders[0].begin(), config.det_orders[0].end(), 0);

src/tesseract.perf.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ void benchmark_tesseract(std::string circuit_path, size_t num_shots) {
7777
/*approximate_disjoint_errors_threshold=*/1,
7878
/*ignore_decomposition_failures=*/false,
7979
/*block_decomposition_from_introducing_remnant_edges=*/false);
80+
dem = common::remove_zero_probability_errors(dem);
8081
TesseractConfig config{dem};
8182
config.det_beam = 20;
8283
config.pqlimit = 10'000'000;
@@ -99,6 +100,7 @@ void benchmark_simplex(std::string circuit_path, size_t num_shots) {
99100
/*approximate_disjoint_errors_threshold=*/1,
100101
/*ignore_decomposition_failures=*/false,
101102
/*block_decomposition_from_introducing_remnant_edges=*/false);
103+
dem = common::remove_zero_probability_errors(dem);
102104
SimplexConfig config{dem};
103105
config.parallelize = true;
104106
SimplexDecoder decoder(config);

src/tesseract.test.cc

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "tesseract.h"
1616

1717
#include <vector>
18+
#include <cstdlib>
1819

1920
#include "gtest/gtest.h"
2021
#include "simplex.h"
@@ -79,10 +80,19 @@ bool simplex_test_compare(stim::DetectorErrorModel& dem,
7980
}
8081

8182
TEST(tesseract, Tesseract_simplex_test) {
82-
for (float p_err : {0.001, 0.003, 0.005}) {
83-
for (size_t distance : {3, 5}) {
84-
for (const size_t num_rounds : {2, 5, 10}) {
85-
const size_t num_shots = 1000 / num_rounds / distance;
83+
bool long_tests = std::getenv("TESSERACT_LONG_TESTS") != nullptr;
84+
auto p_errs = long_tests ? std::vector<float>{0.001f, 0.003f, 0.005f}
85+
: std::vector<float>{0.003f};
86+
auto distances = long_tests ? std::vector<size_t>{3, 5, 7}
87+
: std::vector<size_t>{3};
88+
auto rounds = long_tests ? std::vector<size_t>{2, 5, 10}
89+
: std::vector<size_t>{2};
90+
size_t base_shots = long_tests ? 1000 : 100;
91+
92+
for (float p_err : p_errs) {
93+
for (size_t distance : distances) {
94+
for (const size_t num_rounds : rounds) {
95+
const size_t num_shots = base_shots / num_rounds / distance;
8696
std::cout << "p_err = " << p_err << " distance = " << distance
8797
<< " num_rounds = " << num_rounds
8898
<< " num_shots = " << num_shots << std::endl;
@@ -195,3 +205,24 @@ TEST(tesseract, Tesseract_simplex_DEM_exhaustive_test) {
195205
ASSERT_TRUE(return_val);
196206
}
197207
}
208+
209+
TEST(tesseract, DecodersStripZeroProbabilityErrors) {
210+
stim::DetectorErrorModel dem(R"DEM(
211+
error(0.1) D0
212+
error(0) D1
213+
error(0.2) D2
214+
detector(0,0,0) D0
215+
detector(0,0,0) D1
216+
detector(0,0,0) D2
217+
)DEM");
218+
219+
TesseractConfig t_config{dem};
220+
TesseractDecoder t_dec(t_config);
221+
EXPECT_EQ(t_dec.config.dem.count_errors(), 2);
222+
EXPECT_EQ(t_dec.errors.size(), 2);
223+
224+
SimplexConfig s_config{dem};
225+
SimplexDecoder s_dec(s_config);
226+
EXPECT_EQ(s_dec.config.dem.count_errors(), 2);
227+
EXPECT_EQ(s_dec.errors.size(), 2);
228+
}

0 commit comments

Comments
 (0)