tesseract-decoder

Python Interface

tesseract_decoder.tesseract Module

The tesseract_decoder.tesseract module provides the Tesseract decoder, which employs the A* search to decode a most-likely error configuration from the measured syndrome.

Class tesseract.TesseractConfig

This class holds the configuration parameters that control the behavior of the Tesseract decoder.

Explanation of configuration arguments:

Example Usage:

import tesseract_decoder.tesseract as tesseract
import stim
import sys

dem = stim.DetectorErrorModel("""
    error(0.1) D0 D1
    error(0.2) D1 D2 L0
    detector(0, 0, 0) D0
    detector(1, 0, 0) D1
    detector(2, 0, 0) D2
""")

# Basic configuration
config1 = tesseract.TesseractConfig(dem=dem)
print(f"Basic configuration detection beam: {config1.det_beam}")
print(f"Basic configuration beam climbing: {config1.det_beam}")
print(f"Basic configuration no-revisit detection events: {config1.det_beam}")
print(f"Basic configuration pqlimit: {config1.det_beam}")
print(f"Basic configuration verbose: {config1.det_beam}")
print(f"Basic configuration detection penalty: {config1.det_beam}")

# Configuration with custom parameters
config2 = tesseract.TesseractConfig(
    dem=dem,
    det_beam=50,
    beam_climbing=True,
    no_revisit_dets=True,
    pqlimit=10000,
    verbose=True,
    det_penalty=0.1
)
print(f"Custom configuration detection beam: {config2.det_beam}")
print(f"Custom configuration beam climbing: {config2.det_beam}")
print(f"Custom configuration no-revisit detection events: {config2.det_beam}")
print(f"Custom configuration pqlimit: {config2.det_beam}")
print(f"Custom configuration verbose: {config2.det_beam}")
print(f"Custom configuration detection penalty: {config2.det_beam}")

Class tesseract.TesseractDecoder

This is the main class that implements the Tesseract decoding logic.

Explanation of each method:

decode_to_errors(syndrome: np.ndarray)

Decodes a single measurement shot to predict a list of errors.

decode_to_errors(syndrome: np.ndarray, det_order: int, det_beam: int)

An overloaded version of the decode_to_errors method that allows for a different decoding strategy.

get_observables_from_errors(predicted_errors: list[int]) -> list[bool]

Converts a list of predicted error indices into a list of flipped logical observables.

cost_from_errors(predicted_errors: list[int]) -> float

Calculates the total logarithmic probability cost for a given set of predicted errors. The cost is a measure of how likely a set of errors is.

decode_from_detection_events(detections: list[int]) -> numpy.ndarray

This method decodes a single shot from a list of detection events. This is an alternative to the decode method that takes a NumPy array.

decode(syndrome: numpy.ndarray) -> numpy.ndarray

A convenience function that decodes a single shot and returns the flipped logical observables directly. It combines the functionality of decode_to_errors and get_observables_from_errors.

decode_batch(syndromes: numpy.ndarray) -> numpy.ndarray

Decodes a batch of shots at once.

Example Usage:

import tesseract_decoder.tesseract as tesseract
import stim
import numpy as np

# Create a DEM and a configuration
dem = stim.DetectorErrorModel("""
    error(0.1) D0
    error(0.2) D1 L0
    detector(0, 0, 0) D0
    detector(1, 0, 0) D1
""")
config = tesseract.TesseractConfig(dem=dem)

# Create the decoder
decoder = tesseract.TesseractDecoder(config)

# --- Decode a single shot using detection events (list of integers) ---
detections = [1]
flipped_observables_events = decoder.decode_from_detection_events(detections)
print(f"Decoded (from events) flipped observables for detections {detections}: {flipped_observables_events}")

# Access predicted errors
predicted_errors = decoder.predicted_errors_buffer
print(f"\nPredicted errors after single-shot decode: {predicted_errors}")

# Calculate cost for predicted errors
cost = decoder.cost_from_errors(predicted_errors)
print(f"Cost of predicted errors: {cost}")

# Check the low confidence flag
print(f"Decoder low confidence: {decoder.low_confidence_flag}")

# --- Decode a single shot using a syndrome array (NumPy array of booleans) ---
syndrome_array = np.array([False, True])
flipped_observables_syndrome = decoder.decode(syndrome_array)
print(f"Decoded (from syndrome) flipped observables for syndrome {syndrome_array}: {flipped_observables_syndrome}")

# --- Decode a batch of shots using a syndrome array (2D NumPy array of booleans) ---
syndromes_batch = np.array([[False, True], [True, False]])
flipped_observables_batch = decoder.decode_batch(syndromes_batch)
print(f"Decoded (batch) flipped observables for syndromes:\n{syndromes_batch}\nResult:\n{flipped_observables_batch}")

tesseract_decoder.simplex Module

The tesseract_decoder.simplex module provides the Simplex-based decoder, which solves the decoding problem using an integer linear program.

Class simplex.SimplexConfig

This class holds the configuration parameters that control the behavior of the Simplex decoder.

Example Usage:

import tesseract_decoder.simplex as simplex
import stim

dem = stim.DetectorErrorModel("""
    # Example DEM
    error(0.1) D0
    error(0.2) D1 L0
""")

config = simplex.SimplexConfig(
    dem=dem,
    parallelize=False,
    window_length=10,
    window_slide_length=5,
    verbose=True
)

print(f"Configuration parallelize enabled: {config.parallelize}");
print(f"Configuration window length: {config.window_length}")
print(f"Configuration window slide length: {config.window_length}")
print(f"Configuration windowing enabled: {config.windowing_enabled()}")
print(f"Configuration verbose enabled: {config.verbose}")

Class simplex.SimplexDecoder

This is the main class for performing decoding using the Simplex algorithm.

Example Usage:

import tesseract_decoder.simplex as simplex
import stim
import tesseract_decoder.common as common
import numpy as np

# Create a DEM and a configuration
dem = stim.DetectorErrorModel("""
    error(0.1) D0
    error(0.2) D1 L0
    detector(0, 0, 0) D0
    detector(1, 0, 0) D1
""")
config = simplex.SimplexConfig(dem=dem)

# Create and initialize the decoder
decoder = simplex.SimplexDecoder(config)
decoder.init_ilp()

# Decode a shot where detector D1 fired
syndrome = np.array([0, 1], dtype=bool)
flipped_observables = decoder.decode(syndrome)
print(f"Flipped observables for syndrome {syndrome.tolist()}: {flipped_observables}")

# Access predicted errors
predicted_error_indices = decoder.predicted_errors_buffer
print(f"Predicted error indices: {predicted_error_indices}")

# Calculate cost from the predicted errors
cost = decoder.cost_from_errors(predicted_error_indices)
print(f"Cost of predicted errors: {cost}")

tesseract_decoder.utils Module

The tesseract_decoder.utils module provides various helper functions used throughout the entire project.

Functions

Example Usage:

import tesseract_decoder.utils as utils
import stim

dem = stim.DetectorErrorModel("""
    detector(0, 0, 0) D0
    detector(1, 0, 0) D1
    detector(0, 1, 0) D2
""")
coords = utils.get_detector_coords(dem)
print("Detector Coordinates:")
for i, coord in enumerate(coords):
    print(f"D{i}: ({coord[0]:.2f}, {coord[1]:.2f}, {coord[2]:.2f})")

Example Usage:

import tesseract_decoder.utils as utils
import stim

dem = stim.DetectorErrorModel("""
    error(0.1) D0 D1
    error(0.2) D1 D2
    error(0.3) D0 D2
    detector(0, 0, 0) D0
    detector(1, 0, 0) D1
    detector(0, 1, 0) D2
""")
graph = utils.build_detector_graph(dem)
print("Detector Graph Adjacency List:")
for i, neighbors in enumerate(graph):
    print(f"D{i}: {neighbors}")

Example Usage:

import tesseract_decoder.utils as utils
import tesseract_decoder.common as common
import stim

dem = stim.DetectorErrorModel("""
    error(0.1) D0 L0
    error(0.05) D1
    error(0) D2
""")
errors = utils.get_errors_from_dem(dem)
print("Errors extracted from DEM:")
for error in errors:
    print(f"Error likelihood cost: {error.likelihood_cost}")
    print(f"Error symptom detectors: {error.symptom.detectors}")

tesseract_decoder.common Module

The tesseract_decoder.common module provides fundamental data structures and utility functions used for decoding quantum circuit shots inside Tessereact. It exposes classes Symptom and Error, which represent error effects and complete error mechanisms, respectively. Additionally, it includes functions for manipulating stim.DetectorErrorModel objects, such as merging identical errors, removing zero-probability errors, and estimating error probabilities from shot counts.

Class common.Symptom

A Python class representing the effect of an error mechanism.

Example Usage:

import tesseract_decoder.common as common
import stim

# Create a symptom with two detectors and one observable
s = common.Symptom(detectors=[0, 1], observables=[2])

# Access detectors
print(f"Detectors: {s.detectors}")
# Access observables
print(f"Observables: {s.observables}")

# Use as_dem_instruction_targets
targets = s.as_dem_instruction_targets()
print(f"DEM targets: {targets}")

# Demonstrate equality and inequality
s2 = common.Symptom(detectors=[0, 1], observables=[2])
s3 = common.Symptom(detectors=[0, 1, 3], observables=[2])
print(f"s == s2: {s == s2}")
print(f"s != s3: {s != s3}")

Class common.Error

A Python class representing a complete error mechanism.

Example Usage:

import tesseract_decoder.common as common
import stim
import math

# Create an empty Error
error = common.Error()
print(f"Error likelihood cost: {error.likelihood_cost}")
print(f"Error symptom detectors: {error.symptom.detectors}")

# Create an Error from a stim.DemInstruction
dem_instruction = stim.DemInstruction(type='error', arg_data=[0.1], target_data=[stim.DemTarget(is_relative_detector_id=True, val=1)])
error2 = common.Error(error=dem_instruction)
print(f"Error likelihood cost: {error2.likelihood_cost}")
print(f"Error symptom detectors: {error2.symptom.detectors}")

# Create an Error with explicit parameters
error3 = common.Error(
    likelihood_cost=-math.log(0.2 / (1 - 0.2)),
    detectors=[1, 2],
    observables=[0],
)
print(f"Error likelihood cost: {error3.likelihood_cost}")
print(f"Error symptom detectors: {error3.symptom.detectors}")

Functions

Example Usage:

import tesseract_decoder.common as common
import stim

original_dem = stim.DetectorErrorModel("""
    error(0.1) D0 D1
    error(0.05) D0 D1
    error(0.2) D2
""")
print("Original DEM:")
print(original_dem)
# This DEM has 3 error instructions.
# Two have the same symptom (D0 D1) with probabilities 0.1 and 0.05.
# The third has a different symptom (D2) with probability 0.2.

merged_dem = common.merge_indistinguishable_errors(original_dem)
print("\nMerged DEM:")
print(merged_dem)
# This merged DEM has 2 error instructions.
# The two errors with the same symptom D0 D1 have been combined into a single instruction.
# The new probability for the D0 D1 error is 0.1+0.05−(0.1×0.05)=0.145.
# The error with symptom D2 remains unchanged.

Example Usage:

import tesseract_decoder.common as common
import stim

original_dem = stim.DetectorErrorModel("""
    error(0.1) D0
    error(0) D1
    error(0.2) D2
""")
print("Original DEM:")
print(original_dem)
# This DEM has 3 error instructions, one of them has probability of zero.

cleaned_dem = common.remove_zero_probability_errors(original_dem)
print("\Cleaned DEM:")
print(cleaned_dem)
# This DEM has 2 error instructions, none of them have probability of zero.

Example Usage:

import tesseract_decoder.common as common
import stim

# Original DEM
original_dem = stim.DetectorErrorModel("""
    error(0.1) D0
    error(0.2) D1
    error(0.05) D2
""")
print("Original DEM:")
print(original_dem)

# Simulate some error counts from 1000 shots
# Error at D0 occurred 100 times, D1 occurred 250 times, D2 occurred 40 times
error_counts = [100, 250, 40]
num_shots = 1000

estimated_dem = common.dem_from_counts(original_dem, error_counts, num_shots)
print("\nEstimated DEM:")
print(estimated_dem)
# Expected probabilities: D0 -> 100/1000 = 0.1, D1 -> 250/1000 = 0.25, D2 -> 40/1000 = 0.04

Sinter Integration

The Tesseract Python interface is compatible with the Sinter framework, which is a powerful tool for large-scale decoding, benchmarking, and error-rate estimation.

The TesseractSinterDecoder Object

All Sinter examples rely on this utility function to provide the Sinter-compatible Tesseract decoder.

import sinter
import stim
from sinter._decoding._decoding import sample_decode

from src.tesseract_decoder import tesseract_sinter_compat as tesseract_module
from src import tesseract_decoder

# Define a function that returns a dictionary mapping a decoder name to its
# Sinter-compatible decoder object.
def get_tesseract_decoder_for_sinter():
    return tesseract_module.make_tesseract_sinter_decoders_dict()

Decoding with sinter.collect

sinter.collect is a powerful function for running many decoding jobs in parallel and collecting the results for large-scale benchmarking.

# Create a repetition code circuit to test the decoder.
circuit = stim.Circuit.generated(
    'repetition_code:memory',
    distance=3,
    rounds=3,
    after_clifford_depolarization=0.01
)

# Use sinter.collect to run the decoding task.
results, = sinter.collect(
    num_workers=1,
    tasks=[sinter.Task(circuit=circuit)],
    decoders=["tesseract"],
    max_shots=1000,
    custom_decoders=get_tesseract_decoder_for_sinter(),
)

# Print a summary of the decoding results.
print("Basic Repetition Code Decoding Results:")
print(f"Shots run: {results.shots}")
print(f"Observed errors: {results.errors}")
print(f"Logical error rate: {results.errors / results.shots}")

Running with multiple workers

This example demonstrates how to use multiple worker threads to speed up the simulation.

# Use sinter.collect with multiple workers for faster decoding.
results, = sinter.collect(
    num_workers=4,
    tasks=[sinter.Task(circuit=circuit)],
    decoders=["tesseract"],
    max_shots=10000,
    custom_decoders=get_tesseract_decoder_for_sinter(),
)

print("\nDecoding with 4 worker threads:")
print(f"Shots run: {results.shots}")
print(f"Observed errors: {results.errors}")
print(f"Logical error rate: {results.errors / results.shots}")

Decoding with sinter.sample_decode

sinter.sample_decode is a simpler, non-parallel function for directly decoding a single circuit. It’s useful for quick tests and debugging without the overhead of the sinter.collect framework.

# Create a repetition code circuit.
circuit = stim.Circuit.generated('repetition_code:memory', distance=5, rounds=5)

# Use sinter.sample_decode for a direct decoding run.
result = sample_decode(
    circuit_obj=circuit,
    dem_obj=circuit.detector_error_model(),
    num_shots=1000,
    decoder="tesseract",
    custom_decoders=get_tesseract_decoder_for_sinter(),
)

print("Basic sample_decode Results:")
print(f"Shots run: {result.shots}")
print(f"Observed errors: {result.errors}")
print(f"Logical error rate: {result.errors / result.shots}")