Skip to content

Commit a1a42f3

Browse files
Added CLI example, and made make_tesseract_sinter_decoders_dic and
TesseractSinterDecoder visible from the root module.
1 parent 2168aa5 commit a1a42f3

File tree

3 files changed

+51
-32
lines changed

3 files changed

+51
-32
lines changed

README.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,18 +214,18 @@ for i in predicted_errors:
214214
```
215215
## Using Tesseract with Sinter
216216

217-
Tesseract can be easily integrated into [Sinter](https://github.com/quantumlib/Sinter) workflows. Sinter is a tool for running and organizing quantum error correction simulations. The `tesseract_sinter_compat` module provides the necessary interface.
217+
Tesseract can be easily integrated into [Sinter](https://github.com/quantumlib/Stim/tree/main/glue/sample) workflows. Sinter is a tool for running and organizing quantum error correction simulations.
218218

219219
Here's an example of how to use Tesseract as a decoder for multiple Sinter tasks:
220220

221221
```python
222222
import stim
223223
import sinter
224-
from tesseract_decoder import tesseract_sinter_compat
224+
from tesseract_decoder import make_tesseract_sinter_decoders_dict
225225

226226
# Define a list of Sinter task(s) with different circuits/decoders.
227227
tasks = []
228-
# These are the sensible defaults given by tesseract_module.make_tesseract_sinter_decoders_dict().
228+
# These are the sensible defaults given by make_tesseract_sinter_decoders_dict().
229229
decoders = ['tesseract', 'tesseract-long-beam', 'tesseract-short-beam']
230230
for i, distance in enumerate([3, 5, 7]):
231231
circuit = stim.Circuit.generated(
@@ -270,7 +270,22 @@ for result in results:
270270
# Logical error rate: 0.0153
271271
```
272272

273-
This example runs simulations for a repetition code with different distances [3, 5, 7] with different Tesseract default decoders. Sinter efficiently manages the execution of these tasks, and Tesseract is used for decoding. For more usage examples, see the tests in `src/py/tesseract_sinter_compat_test.py`.
273+
This example runs simulations for a repetition code with different distances [3, 5, 7] with different Tesseract default decoders.
274+
275+
Sinter can also be used at the command line. Here is an example of this using Tesseract:
276+
277+
```bash
278+
sinter collect \
279+
--circuits "example_circuit.stim" \
280+
--decoders tesseract \
281+
--custom_decoders_module_function "tesseract_decoder:make_tesseract_sinter_decoders_dict" \
282+
--max_shots 100_000 \
283+
--max_errors 100
284+
--processes auto \
285+
--save_resume_filepath "stats.csv" \
286+
```
287+
288+
Sinter efficiently manages the execution of these tasks, and Tesseract is used for decoding. For more usage examples, see the tests in `src/py/tesseract_sinter_compat_test.py`.
274289

275290
## Good Starting Points for Tesseract Configurations:
276291
The [Tesseract paper](https://arxiv.org/pdf/2503.10988) recommends two setup for starting your exploration with tesseract:

src/py/tesseract_sinter_compat_test.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import shutil
2020
from sinter._decoding._decoding import sample_decode
2121

22-
from src.tesseract_decoder import tesseract_sinter_compat as tesseract_module
22+
from src.tesseract_decoder import TesseractSinterDecoder, make_tesseract_sinter_decoders_dict
2323
from src import tesseract_decoder
2424
import sinter
2525

@@ -29,7 +29,7 @@ def test_tesseract_sinter_obj_exists():
2929
Sanity check to ensure the decoder object exists and has the required methods.
3030
"""
3131

32-
decoder = tesseract_module.TesseractSinterDecoder()
32+
decoder = TesseractSinterDecoder()
3333
assert hasattr(decoder, 'compile_decoder_for_dem')
3434
assert hasattr(decoder, 'decode_via_files')
3535

@@ -51,11 +51,11 @@ def test_compile_decoder_for_dem(use_custom_config):
5151
""")
5252

5353
if use_custom_config:
54-
decoder = tesseract_module.TesseractSinterDecoder(
54+
decoder = TesseractSinterDecoder(
5555
verbose=True,
5656
)
5757
else:
58-
decoder = tesseract_module.TesseractSinterDecoder()
58+
decoder = TesseractSinterDecoder()
5959

6060
compiled_decoder = decoder.compile_decoder_for_dem(dem=dem)
6161

@@ -83,7 +83,7 @@ def test_decode_shots_bit_packed():
8383
error(0.1) D1 D2 L1
8484
""")
8585

86-
decoder = tesseract_module.TesseractSinterDecoder()
86+
decoder = TesseractSinterDecoder()
8787
compiled_decoder = decoder.compile_decoder_for_dem(dem=dem)
8888

8989
num_shots = 1
@@ -119,7 +119,7 @@ def test_decode_shots_bit_packed_multi_shot():
119119
error(0.1) D1 D2 L1
120120
""")
121121

122-
decoder = tesseract_module.TesseractSinterDecoder()
122+
decoder = TesseractSinterDecoder()
123123
compiled_decoder = decoder.compile_decoder_for_dem(dem=dem)
124124

125125
num_shots = 3
@@ -184,7 +184,7 @@ def test_decode_via_files_sanity_check():
184184
with open(dets_in_path, 'wb') as f:
185185
f.write(detection_events.tobytes())
186186

187-
tesseract_module.TesseractSinterDecoder().decode_via_files(
187+
TesseractSinterDecoder().decode_via_files(
188188
num_shots=num_shots,
189189
num_dets=dem.num_detectors,
190190
num_obs=dem.num_observables,
@@ -247,11 +247,11 @@ def test_decode_via_files(use_custom_config):
247247
f.write(detection_events_np.tobytes())
248248

249249
if use_custom_config:
250-
decoder = tesseract_module.TesseractSinterDecoder(
250+
decoder = TesseractSinterDecoder(
251251
verbose=True,
252252
)
253253
else:
254-
decoder = tesseract_module.TesseractSinterDecoder()
254+
decoder = TesseractSinterDecoder()
255255

256256
decoder.decode_via_files(
257257
num_shots=num_shots,
@@ -332,7 +332,7 @@ def test_decode_via_files_multi_shot():
332332
with open(dets_in_path, 'wb') as f:
333333
f.write(detection_events_np.tobytes())
334334

335-
tesseract_module.TesseractSinterDecoder().decode_via_files(
335+
TesseractSinterDecoder().decode_via_files(
336336
num_shots=num_shots,
337337
num_dets=num_detectors,
338338
num_obs=dem.num_observables,
@@ -378,7 +378,7 @@ def test_sinter_decode_repetition_code():
378378
dem_path=None,
379379
num_shots=1000,
380380
decoder="tesseract",
381-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict(),
381+
custom_decoders=make_tesseract_sinter_decoders_dict(),
382382
)
383383
assert result.discards == 0
384384
assert 0 <= result.errors <= 100
@@ -402,7 +402,7 @@ def test_sinter_decode_surface_code():
402402
dem_obj=circuit.detector_error_model(decompose_errors=True),
403403
dem_path=None,
404404
decoder="tesseract",
405-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict(),
405+
custom_decoders=make_tesseract_sinter_decoders_dict(),
406406
)
407407
assert result.discards == 0
408408
assert 0 <= result.errors <= 50
@@ -421,7 +421,7 @@ def test_sinter_empty():
421421
dem_path=None,
422422
num_shots=1000,
423423
decoder="tesseract",
424-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict(),
424+
custom_decoders=make_tesseract_sinter_decoders_dict(),
425425
)
426426
assert result.discards == 0
427427
assert result.shots == 1000
@@ -444,7 +444,7 @@ def test_sinter_no_observables():
444444
dem_path=None,
445445
num_shots=1000,
446446
decoder="tesseract",
447-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict(),
447+
custom_decoders=make_tesseract_sinter_decoders_dict(),
448448
)
449449
assert result.discards == 0
450450
assert result.shots == 1000
@@ -468,7 +468,7 @@ def test_sinter_invincible_observables():
468468
dem_path=None,
469469
num_shots=1000,
470470
decoder="tesseract",
471-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict(),
471+
custom_decoders=make_tesseract_sinter_decoders_dict(),
472472
)
473473
assert result.discards == 0
474474
assert result.shots == 1000
@@ -497,7 +497,7 @@ def test_sinter_detector_counting():
497497
num_shots=10000,
498498
decoder="tesseract",
499499
count_detection_events=True,
500-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict(),
500+
custom_decoders=make_tesseract_sinter_decoders_dict(),
501501
)
502502
assert result.discards == 0
503503
assert result.custom_counts['detectors_checked'] == 20000
@@ -513,7 +513,7 @@ def test_full_scale():
513513
tasks=[sinter.Task(circuit=stim.Circuit())],
514514
decoders=["tesseract"],
515515
max_shots=1000,
516-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict(),
516+
custom_decoders=make_tesseract_sinter_decoders_dict(),
517517
)
518518
assert result.discards == 0
519519
assert result.shots == 1000
@@ -535,7 +535,7 @@ def test_full_scale_one_worker():
535535
tasks=[sinter.Task(circuit=circuit)],
536536
decoders=["tesseract"],
537537
max_shots=1000,
538-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict(),
538+
custom_decoders=make_tesseract_sinter_decoders_dict(),
539539
)
540540

541541
assert result.discards == 0
@@ -597,7 +597,7 @@ def test_decode_shots_bit_packed_vs_decode_batch(det_beam, beam_climbing, no_rev
597597
dem = circuit.detector_error_model()
598598

599599
# 2. Compile the Sinter-compatible decoder with the parameterized values for the DEM.
600-
sinter_decoder = tesseract_module.TesseractSinterDecoder(
600+
sinter_decoder = TesseractSinterDecoder(
601601
det_beam=det_beam,
602602
beam_climbing=beam_climbing,
603603
no_revisit_dets=no_revisit_dets,
@@ -661,7 +661,7 @@ def test_sinter_collect_different_dems():
661661
tasks=tasks,
662662
decoders=["tesseract-long-beam"],
663663
max_shots=100, # Reduced max_shots for testing
664-
custom_decoders=tesseract_module.make_tesseract_sinter_decoders_dict()
664+
custom_decoders=make_tesseract_sinter_decoders_dict()
665665
)
666666

667667
assert len(all_results) == len(tasks)

src/tesseract_sinter_compat.pybind.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,20 +377,24 @@ void pybind_sinter_compat(py::module& root) {
377377
[]() -> py::object {
378378
auto result = py::dict();
379379
result["tesseract"] = TesseractSinterDecoder{};
380-
result["tesseract-short-beam"] = TesseractSinterDecoder(
381-
/*det_beam=*/10, /*beam_climbing=*/false, /*no_revisit_dets=*/true,
382-
/*verbose=*/false, /*merge_errors=*/true, /*pqlimit=*/DEFAULT_PQLIMIT,
383-
/*det_penalty=*/0.0, /*create_visualization=*/false,
384-
/*num_det_orders=*/0, /*det_order_method=*/DetOrder::DetBFS, /*seed=*/2384753);
385380
result["tesseract-long-beam"] = TesseractSinterDecoder(
386-
/*det_beam=*/1000, /*beam_climbing=*/false, /*no_revisit_dets=*/true,
387-
/*verbose=*/false, /*merge_errors=*/true, /*pqlimit=*/DEFAULT_PQLIMIT,
381+
/*det_beam=*/20, /*beam_climbing=*/true, /*no_revisit_dets=*/true,
382+
/*verbose=*/false, /*merge_errors=*/true, /*pqlimit=*/1000000,
388383
/*det_penalty=*/0.0, /*create_visualization=*/false,
389-
/*num_det_orders=*/0, /*det_order_method=*/DetOrder::DetBFS, /*seed=*/2384753);
384+
/*num_det_orders=*/21, /*det_order_method=*/DetOrder::DetIndex, /*seed=*/2384753);
385+
result["tesseract-short-beam"] = TesseractSinterDecoder(
386+
/*det_beam=*/15, /*beam_climbing=*/true, /*no_revisit_dets=*/true,
387+
/*verbose=*/false, /*merge_errors=*/true, /*pqlimit=*/200000,
388+
/*det_penalty=*/0.0, /*create_visualization=*/false,
389+
/*num_det_orders=*/16, /*det_order_method=*/DetOrder::DetIndex, /*seed=*/2384753);
390390
return result;
391391
},
392392
R"pbdoc(
393393
Returns a dictionary mapping decoder names to sinter.Decoder-style objects.
394394
This allows Sinter to easily discover and use Tesseract as a custom decoder.
395395
)pbdoc");
396+
397+
// Aliases that are visible from the root module.
398+
root.attr("TesseractSinterDecoder") = m.attr("TesseractSinterDecoder");
399+
root.attr("make_tesseract_sinter_decoders_dict") = m.attr("make_tesseract_sinter_decoders_dict");
396400
}

0 commit comments

Comments
 (0)