1717import numpy as np
1818import stim
1919import shutil
20+ from sinter ._decoding ._decoding import sample_decode
2021
21- from src import tesseract_sinter_compat as tesseract_module
22+ from src .tesseract_decoder import tesseract_sinter_compat as tesseract_module
23+ from src import tesseract_decoder
2224
2325
2426def test_tesseract_sinter_obj_exists ():
@@ -30,11 +32,12 @@ def test_tesseract_sinter_obj_exists():
3032 assert hasattr (decoder , 'compile_decoder_for_dem' )
3133 assert hasattr (decoder , 'decode_via_files' )
3234
33- def test_compile_decoder_for_dem ():
35+ @pytest .mark .parametrize ("use_custom_config" , [False , True ])
36+ def test_compile_decoder_for_dem (use_custom_config ):
3437 """
35- Test the 'compile_decoder_for_dem' method with a specific DEM .
38+ Test the 'compile_decoder_for_dem' method with and without a custom config .
3639 """
37-
40+
3841 dem = stim .DetectorErrorModel ("""
3942 detector(0, 0, 0) D0
4043 detector(0, 0, 1) D1
@@ -44,17 +47,26 @@ def test_compile_decoder_for_dem():
4447 error(0.1) D1 D2 L1
4548 error(0.1) D2 D3 L0
4649 """ )
50+
51+ if use_custom_config :
52+ config = tesseract_decoder .tesseract .TesseractConfig ()
53+ config .verbose = True
54+ decoder = tesseract_module .TesseractSinterDecoder (config = config )
55+ else :
56+ decoder = tesseract_module .TesseractSinterDecoder ()
4757
48- decoder = tesseract_module .TesseractSinterDecoder ()
4958 compiled_decoder = decoder .compile_decoder_for_dem (dem = dem )
50-
59+
5160 assert compiled_decoder is not None
5261 assert hasattr (compiled_decoder , 'decode_shots_bit_packed' )
53-
62+
5463 # Verify the detector and observable counts are correct
5564 assert compiled_decoder .num_detectors == dem .num_detectors
5665 assert compiled_decoder .num_observables == dem .num_observables
5766
67+ # Verify the config was correctly applied
68+ assert compiled_decoder .decoder .config .verbose == use_custom_config
69+
5870def test_decode_shots_bit_packed ():
5971 """
6072 Tests the 'decode_shots_bit_packed' method with a specific DEM and detection event.
@@ -176,7 +188,8 @@ def test_decode_via_files_sanity_check():
176188 if temp_dir .exists ():
177189 shutil .rmtree (temp_dir )
178190
179- def test_decode_via_files ():
191+ @pytest .mark .parametrize ("use_custom_config" , [False , True ])
192+ def test_decode_via_files (use_custom_config ):
180193 """
181194 Tests the 'decode_via_files' method with a specific DEM and detection event.
182195 """
@@ -222,7 +235,14 @@ def test_decode_via_files():
222235 with open (dets_in_path , 'wb' ) as f :
223236 f .write (detection_events_np .tobytes ())
224237
225- tesseract_module .TesseractSinterDecoder ().decode_via_files (
238+ if use_custom_config :
239+ config = tesseract_decoder .tesseract .TesseractConfig ()
240+ config .verbose = True
241+ decoder = tesseract_module .TesseractSinterDecoder (config = config )
242+ else :
243+ decoder = tesseract_module .TesseractSinterDecoder ()
244+
245+ decoder .decode_via_files (
226246 num_shots = num_shots ,
227247 num_dets = num_detectors ,
228248 num_obs = dem .num_observables ,
@@ -248,6 +268,9 @@ def test_decode_via_files():
248268 # Clean up temporary files
249269 if temp_dir .exists ():
250270 shutil .rmtree (temp_dir )
271+
272+ assert decoder .config .verbose == use_custom_config
273+
251274
252275def test_decode_via_files_multi_shot ():
253276 """
@@ -325,5 +348,152 @@ def test_decode_via_files_multi_shot():
325348 if temp_dir .exists ():
326349 shutil .rmtree (temp_dir )
327350
351+ def construct_tesseract_decoder_for_sinter ():
352+ return {"tesseract" : tesseract_module .TesseractSinterDecoder ()}
353+
354+
355+ def test_sinter_decode_repetition_code ():
356+ """
357+ Tests the 'tesseract' decoder on a repetition code circuit.
358+ """
359+ circuit = stim .Circuit .generated ('repetition_code:memory' ,
360+ rounds = 3 ,
361+ distance = 3 ,
362+ after_clifford_depolarization = 0.05 )
363+
364+ result = sample_decode (
365+ circuit_obj = circuit ,
366+ circuit_path = None ,
367+ dem_obj = circuit .detector_error_model (decompose_errors = True ),
368+ dem_path = None ,
369+ num_shots = 1000 ,
370+ decoder = "tesseract" ,
371+ custom_decoders = construct_tesseract_decoder_for_sinter (),
372+ )
373+ assert result .discards == 0
374+ assert 0 <= result .errors <= 100
375+ assert result .shots == 1000
376+
377+
378+ def test_sinter_decode_surface_code ():
379+ """
380+ Tests the 'tesseract' decoder on a more complex surface code circuit.
381+ """
382+ circuit = stim .Circuit .generated (
383+ "surface_code:rotated_memory_x" ,
384+ distance = 3 ,
385+ rounds = 15 ,
386+ after_clifford_depolarization = 0.001 ,
387+ )
388+ result = sample_decode (
389+ num_shots = 1000 ,
390+ circuit_obj = circuit ,
391+ circuit_path = None ,
392+ dem_obj = circuit .detector_error_model (decompose_errors = True ),
393+ dem_path = None ,
394+ decoder = "tesseract" ,
395+ custom_decoders = construct_tesseract_decoder_for_sinter (),
396+ )
397+ assert result .discards == 0
398+ assert 0 <= result .errors <= 50
399+ assert result .shots == 1000
400+
401+ def test_sinter_empty ():
402+ """
403+ Tests the 'tesseract' decoder on an empty circuit.
404+ """
405+ circuit = stim .Circuit ()
406+ result = sample_decode (
407+ circuit_obj = circuit ,
408+ circuit_path = None ,
409+ dem_obj = circuit .detector_error_model (decompose_errors = True ),
410+ dem_path = None ,
411+ num_shots = 1000 ,
412+ decoder = "tesseract" ,
413+ custom_decoders = construct_tesseract_decoder_for_sinter (),
414+ )
415+ assert result .discards == 0
416+ assert result .shots == 1000
417+ assert result .errors == 0
418+
419+ def test_sinter_no_observables ():
420+ """
421+ Tests the decoder on a circuit with detectors but no logical observables.
422+ """
423+ circuit = stim .Circuit ("""
424+ X_ERROR(0.1) 0
425+ M 0
426+ DETECTOR rec[-1]
427+ """ )
428+ result = sample_decode (
429+ circuit_obj = circuit ,
430+ circuit_path = None ,
431+ dem_obj = circuit .detector_error_model (decompose_errors = True ),
432+ dem_path = None ,
433+ num_shots = 1000 ,
434+ decoder = "tesseract" ,
435+ custom_decoders = construct_tesseract_decoder_for_sinter (),
436+ )
437+ assert result .discards == 0
438+ assert result .shots == 1000
439+ assert result .errors == 0
440+
441+ def test_sinter_invincible_observables ():
442+ """
443+ Tests the decoder on a circuit where an observable is not affected by errors.
444+ """
445+ circuit = stim .Circuit ("""
446+ X_ERROR(0.1) 0
447+ M 0 1
448+ DETECTOR rec[-2]
449+ OBSERVABLE_INCLUDE(1) rec[-1]
450+ """ )
451+ result = sample_decode (
452+ circuit_obj = circuit ,
453+ circuit_path = None ,
454+ dem_obj = circuit .detector_error_model (decompose_errors = True ),
455+ dem_path = None ,
456+ num_shots = 1000 ,
457+ decoder = "tesseract" ,
458+ custom_decoders = construct_tesseract_decoder_for_sinter (),
459+ )
460+ assert result .discards == 0
461+ assert result .shots == 1000
462+ assert result .errors == 0
463+
464+
465+
466+ def test_sinter_detector_counting ():
467+ """
468+ Tests 'that the decoder's detector count is correctly reported via Sinter'.
469+ """
470+ circuit = stim .Circuit ("""
471+ X_ERROR(0.1) 0
472+ X_ERROR(0.2) 1
473+ M 0 1
474+ DETECTOR rec[-1]
475+ DETECTOR rec[-2]
476+ OBSERVABLE_INCLUDE(0) rec[-1]
477+ OBSERVABLE_INCLUDE(1) rec[-1] rec[-2]
478+ """ )
479+ result = sample_decode (
480+ circuit_obj = circuit ,
481+ circuit_path = None ,
482+ dem_obj = circuit .detector_error_model (decompose_errors = True ),
483+ dem_path = None ,
484+ post_mask = None ,
485+ num_shots = 10000 ,
486+ decoder = "tesseract" ,
487+ count_detection_events = True ,
488+ custom_decoders = construct_tesseract_decoder_for_sinter (),
489+ )
490+ assert result .discards == 0
491+ assert result .custom_counts ['detectors_checked' ] == 20000
492+ assert 0.3 * 10000 * 0.5 <= result .custom_counts ['detection_events' ] <= 0.3 * 10000 * 2.0
493+ assert set (result .custom_counts .keys ()) == {'detectors_checked' , 'detection_events' }
494+
495+
496+
497+
328498if __name__ == "__main__" :
329499 raise SystemExit (pytest .main ([__file__ ]))
0 commit comments