From 9776627db7821627314e40d86be59b52de4a5ee0 Mon Sep 17 00:00:00 2001 From: Noah Shutty Date: Sun, 3 Aug 2025 13:23:54 -0700 Subject: [PATCH 1/7] Expose detector order creation --- src/py/utils_test.py | 12 ++++++ src/tesseract_main.cc | 90 ++----------------------------------------- src/utils.cc | 89 +++++++++++++++++++++++++++++++++++++++++- src/utils.h | 6 ++- src/utils.pybind.h | 8 ++++ 5 files changed, 116 insertions(+), 89 deletions(-) diff --git a/src/py/utils_test.py b/src/py/utils_test.py index e9d9cfd..1e9ba31 100644 --- a/src/py/utils_test.py +++ b/src/py/utils_test.py @@ -44,6 +44,18 @@ def test_build_detector_graph(): ] +def test_build_det_orders(): + assert tesseract_decoder.utils.build_det_orders( + _DETECTOR_ERROR_MODEL, num_det_orders=1, seed=0 + ) == [[0, 1]] + + +def test_build_det_orders_no_bfs(): + assert tesseract_decoder.utils.build_det_orders( + _DETECTOR_ERROR_MODEL, num_det_orders=1, det_order_bfs=False, seed=0 + ) == [[0, 1]] + + def test_get_errors_from_dem(): expected = "Error{cost=1.945910, symptom=Symptom{D0 }}, Error{cost=0.510826, symptom=Symptom{D0 D1 }}, Error{cost=1.098612, symptom=Symptom{D1 }}" assert ( diff --git a/src/tesseract_main.cc b/src/tesseract_main.cc index bd33a9a..1689743 100644 --- a/src/tesseract_main.cc +++ b/src/tesseract_main.cc @@ -170,12 +170,8 @@ struct Args { // Sample orientations of the error model to use for the det priority { - config.det_orders.resize(num_det_orders); - std::mt19937_64 rng(det_order_seed); - std::normal_distribution dist(/*mean=*/0, /*stddev=*/1); - - std::vector> detector_coords = get_detector_coords(config.dem); if (verbose) { + auto detector_coords = get_detector_coords(config.dem); for (size_t d = 0; d < detector_coords.size(); ++d) { std::cout << "Detector D" << d << " coordinate ("; size_t e = std::min(3ul, detector_coords[d].size()); @@ -186,88 +182,8 @@ struct Args { std::cout << ")" << std::endl; } } - - if (det_order_bfs) { - auto graph = build_detector_graph(config.dem); - std::uniform_int_distribution dist_det(0, graph.size() - 1); - for (size_t det_order = 0; det_order < num_det_orders; ++det_order) { - std::vector perm; - perm.reserve(graph.size()); - std::vector visited(graph.size(), false); - std::queue q; - size_t start = dist_det(rng); - while (perm.size() < graph.size()) { - if (!visited[start]) { - visited[start] = true; - q.push(start); - perm.push_back(start); - } - while (!q.empty()) { - size_t cur = q.front(); - q.pop(); - auto neigh = graph[cur]; - std::shuffle(neigh.begin(), neigh.end(), rng); - for (size_t n : neigh) { - if (!visited[n]) { - visited[n] = true; - q.push(n); - perm.push_back(n); - } - } - } - if (perm.size() < graph.size()) { - do { - start = dist_det(rng); - } while (visited[start]); - } - } - std::vector inv_perm(graph.size()); - for (size_t i = 0; i < perm.size(); ++i) { - inv_perm[perm[i]] = i; - } - config.det_orders[det_order] = inv_perm; - } - } else { - std::vector inner_products(config.dem.count_detectors()); - - if (!detector_coords.size() || !detector_coords.at(0).size()) { - // If there are no detector coordinates, just use the standard - // ordering of the indices. - for (size_t det_order = 0; det_order < num_det_orders; ++det_order) { - config.det_orders[det_order].resize(config.dem.count_detectors()); - std::iota(config.det_orders[det_order].begin(), config.det_orders[det_order].end(), 0); - } - - } else { - // Use the coordinates to order the detectors based on a random - // orientation - for (size_t det_order = 0; det_order < num_det_orders; ++det_order) { - // Sample a direction - std::vector orientation_vector; - for (size_t i = 0; i < detector_coords.at(0).size(); ++i) { - orientation_vector.push_back(dist(rng)); - } - - for (size_t i = 0; i < detector_coords.size(); ++i) { - inner_products[i] = 0; - for (size_t j = 0; j < orientation_vector.size(); ++j) { - inner_products[i] += detector_coords[i][j] * orientation_vector[j]; - } - } - std::vector perm(config.dem.count_detectors()); - std::iota(perm.begin(), perm.end(), 0); - std::sort(perm.begin(), perm.end(), [&](const size_t& i, const size_t& j) { - return inner_products[i] > inner_products[j]; - }); - // Invert the permutation - std::vector inv_perm(config.dem.count_detectors()); - for (size_t i = 0; i < perm.size(); ++i) { - inv_perm[perm[i]] = i; - } - config.det_orders[det_order] = inv_perm; - } - } - } + config.det_orders = + build_det_orders(config.dem, num_det_orders, det_order_bfs, det_order_seed); } if (sample_num_shots > 0) { diff --git a/src/utils.cc b/src/utils.cc index c4c6edd..c73d770 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -19,13 +19,15 @@ #include #include #include +#include +#include #include #include #include "common.h" #include "stim.h" -std::vector> get_detector_coords(stim::DetectorErrorModel& dem) { +std::vector> get_detector_coords(const stim::DetectorErrorModel& dem) { std::vector> detector_coords; for (const stim::DemInstruction& instruction : dem.flattened().instructions) { switch (instruction.type) { @@ -79,6 +81,91 @@ std::vector> build_detector_graph(const stim::DetectorErrorM return neighbors; } +std::vector> build_det_orders(const stim::DetectorErrorModel& dem, + size_t num_det_orders, bool det_order_bfs, + uint64_t seed) { + std::vector> det_orders(num_det_orders); + std::mt19937_64 rng(seed); + std::normal_distribution dist(0, 1); + + auto detector_coords = get_detector_coords(dem); + + if (det_order_bfs) { + auto graph = build_detector_graph(dem); + std::uniform_int_distribution dist_det(0, graph.size() - 1); + for (size_t det_order = 0; det_order < num_det_orders; ++det_order) { + std::vector perm; + perm.reserve(graph.size()); + std::vector visited(graph.size(), false); + std::queue q; + size_t start = dist_det(rng); + while (perm.size() < graph.size()) { + if (!visited[start]) { + visited[start] = true; + q.push(start); + perm.push_back(start); + } + while (!q.empty()) { + size_t cur = q.front(); + q.pop(); + auto neigh = graph[cur]; + std::shuffle(neigh.begin(), neigh.end(), rng); + for (size_t n : neigh) { + if (!visited[n]) { + visited[n] = true; + q.push(n); + perm.push_back(n); + } + } + } + if (perm.size() < graph.size()) { + do { + start = dist_det(rng); + } while (visited[start]); + } + } + std::vector inv_perm(graph.size()); + for (size_t i = 0; i < perm.size(); ++i) { + inv_perm[perm[i]] = i; + } + det_orders[det_order] = inv_perm; + } + } else { + std::vector inner_products(dem.count_detectors()); + if (!detector_coords.size() || !detector_coords.at(0).size()) { + for (size_t det_order = 0; det_order < num_det_orders; ++det_order) { + det_orders[det_order].resize(dem.count_detectors()); + std::iota(det_orders[det_order].begin(), det_orders[det_order].end(), 0); + } + } else { + for (size_t det_order = 0; det_order < num_det_orders; ++det_order) { + std::vector orientation_vector; + for (size_t i = 0; i < detector_coords.at(0).size(); ++i) { + orientation_vector.push_back(dist(rng)); + } + + for (size_t i = 0; i < detector_coords.size(); ++i) { + inner_products[i] = 0; + for (size_t j = 0; j < orientation_vector.size(); ++j) { + inner_products[i] += detector_coords[i][j] * orientation_vector[j]; + } + } + std::vector perm(dem.count_detectors()); + std::iota(perm.begin(), perm.end(), 0); + std::sort(perm.begin(), perm.end(), [&](const size_t& i, const size_t& j) { + return inner_products[i] > inner_products[j]; + }); + std::vector inv_perm(dem.count_detectors()); + for (size_t i = 0; i < perm.size(); ++i) { + inv_perm[perm[i]] = i; + } + det_orders[det_order] = inv_perm; + } + } + } + return det_orders; +} + bool sampling_from_dem(uint64_t seed, size_t num_shots, stim::DetectorErrorModel dem, std::vector& shots) { stim::DemSampler sampler(dem, std::mt19937_64{seed}, num_shots); diff --git a/src/utils.h b/src/utils.h index 5fe82be..03d3c24 100644 --- a/src/utils.h +++ b/src/utils.h @@ -28,12 +28,16 @@ constexpr const double EPSILON = 1e-7; -std::vector> get_detector_coords(stim::DetectorErrorModel& dem); +std::vector> get_detector_coords(const stim::DetectorErrorModel& dem); // Builds an adjacency list graph where two detectors share an edge iff an error // in the model activates them both. std::vector> build_detector_graph(const stim::DetectorErrorModel& dem); +std::vector> build_det_orders(const stim::DetectorErrorModel& dem, + size_t num_det_orders, bool det_order_bfs = true, + uint64_t seed = 0); + const double INF = std::numeric_limits::infinity(); bool sampling_from_dem(uint64_t seed, size_t num_shots, stim::DetectorErrorModel dem, diff --git a/src/utils.pybind.h b/src/utils.pybind.h index 8b3f0f9..653e2ce 100644 --- a/src/utils.pybind.h +++ b/src/utils.pybind.h @@ -42,6 +42,14 @@ void add_utils_module(py::module &root) { return build_detector_graph(input_dem); }, py::arg("dem")); + m.def( + "build_det_orders", + [](py::object dem, size_t num_det_orders, bool det_order_bfs, uint64_t seed) { + auto input_dem = parse_py_object(dem); + return build_det_orders(input_dem, num_det_orders, det_order_bfs, seed); + }, + py::arg("dem"), py::arg("num_det_orders"), py::arg("det_order_bfs") = true, + py::arg("seed") = 0); m.def( "get_errors_from_dem", [](py::object dem) { From b950ae01c5a63a73e86ba0573d6ef893add882c3 Mon Sep 17 00:00:00 2001 From: Noah Shutty Date: Tue, 5 Aug 2025 23:05:07 -0700 Subject: [PATCH 2/7] Make init_ilp private and drop binding --- src/py/simplex_test.py | 2 -- src/simplex.h | 5 +++-- src/simplex.pybind.h | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/py/simplex_test.py b/src/py/simplex_test.py index 70cfe2e..1d42d23 100644 --- a/src/py/simplex_test.py +++ b/src/py/simplex_test.py @@ -41,7 +41,6 @@ def test_create_simplex_decoder(): decoder = tesseract_decoder.simplex.SimplexDecoder( tesseract_decoder.simplex.SimplexConfig(_DETECTOR_ERROR_MODEL, window_length=5) ) - decoder.init_ilp() decoder.decode_to_errors([1]) assert decoder.get_observables_from_errors([1]) == [] assert decoder.cost_from_errors([2]) == pytest.approx(1.0986123) @@ -67,7 +66,6 @@ def test_simplex_decoder_predicts_various_observable_flips(): # Initialize SimplexConfig and SimplexDecoder with the generated DEM config = tesseract_decoder.simplex.SimplexConfig(dem, window_length=1) # window_length must be set decoder = tesseract_decoder.simplex.SimplexDecoder(config) - decoder.init_ilp() # Initialize the ILP solver # Simulate a detection event on D0. # The decoder should identify the most likely error causing D0, diff --git a/src/simplex.h b/src/simplex.h index ecf795e..f953493 100644 --- a/src/simplex.h +++ b/src/simplex.h @@ -56,8 +56,6 @@ struct SimplexDecoder { SimplexDecoder(SimplexConfig config); - void init_ilp(); - // Clears the predicted_errors_buffer and fills it with the decoded errors for // these detection events. void decode_to_errors(const std::vector& detections); @@ -73,6 +71,9 @@ struct SimplexDecoder { std::vector>& obs_predicted); ~SimplexDecoder(); + + private: + void init_ilp(); }; #endif // SIMPLEX_HPP diff --git a/src/simplex.pybind.h b/src/simplex.pybind.h index 6dd2c0a..f7928a0 100644 --- a/src/simplex.pybind.h +++ b/src/simplex.pybind.h @@ -62,7 +62,6 @@ void add_simplex_module(py::module& root) { .def_readwrite("start_time_to_errors", &SimplexDecoder::start_time_to_errors) .def_readwrite("end_time_to_errors", &SimplexDecoder::end_time_to_errors) .def_readonly("low_confidence_flag", &SimplexDecoder::low_confidence_flag) - .def("init_ilp", &SimplexDecoder::init_ilp) .def("decode_to_errors", &SimplexDecoder::decode_to_errors, py::arg("detections")) .def( "get_observables_from_errors", From eab206235759a718cac3ec9e1717b0e780ca8254 Mon Sep 17 00:00:00 2001 From: Noah Shutty Date: Tue, 5 Aug 2025 23:10:06 -0700 Subject: [PATCH 3/7] Add CMake build system --- CMakeLists.txt | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..bc3111b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,101 @@ +cmake_minimum_required(VERSION 3.16) +project(tesseract_decoder LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include(FetchContent) +find_package(Threads REQUIRED) + +# === External dependencies === +# Stim +FetchContent_Declare( + stim + GIT_REPOSITORY https://github.com/quantumlib/stim.git + GIT_TAG bd60b73525fd5a9b30839020eb7554ad369e4337 +) +FetchContent_MakeAvailable(stim) + +# HiGHS +FetchContent_Declare( + highs + URL https://github.com/ERGO-Code/HiGHS/archive/refs/tags/v1.9.0.tar.gz + URL_HASH SHA256=dff575df08d88583c109702c7c5c75ff6e51611e6eacca8b5b3fdfba8ecc2cb4 +) +FetchContent_MakeAvailable(highs) + +# argparse (header only) +FetchContent_Declare( + argparse + URL https://github.com/p-ranav/argparse/archive/refs/tags/v3.1.zip + URL_HASH SHA256=3e5a59ab7688dcd1f918bc92051a10564113d4f36c3bbed3ef596c25e519a062 +) +FetchContent_MakeAvailable(argparse) + +# nlohmann_json (header only) +FetchContent_Declare( + nlohmann_json + URL https://github.com/nlohmann/json/archive/9cca280a4d0ccf0c08f47a99aa71d1b0e52f8d03.zip +) +FetchContent_MakeAvailable(nlohmann_json) + +# Boost headers +FetchContent_Declare( + boost + URL https://archives.boost.io/release/1.83.0/source/boost_1_83_0.tar.gz + URL_HASH SHA256=c0685b68dd44cc46574cce86c4e17c0f611b15e195be9848dfd0769a0a207628 +) +FetchContent_MakeAvailable(boost) +add_library(boost_headers INTERFACE) +target_include_directories(boost_headers INTERFACE ${boost_SOURCE_DIR}) + +# pybind11 +FetchContent_Declare( + pybind11 + GIT_REPOSITORY https://github.com/pybind/pybind11.git + GIT_TAG v2.11.1 +) +set(PYBIND11_TEST OFF CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(pybind11) + +set(OPT_COPTS -Ofast -fno-fast-math -march=native) + +set(TESSERACT_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) + +# === Libraries === +add_library(common ${TESSERACT_SRC_DIR}/common.cc ${TESSERACT_SRC_DIR}/common.h) +target_include_directories(common PUBLIC ${TESSERACT_SRC_DIR}) +target_compile_options(common PRIVATE ${OPT_COPTS}) +target_link_libraries(common PUBLIC libstim Threads::Threads) + +add_library(utils ${TESSERACT_SRC_DIR}/utils.cc ${TESSERACT_SRC_DIR}/utils.h) +target_include_directories(utils PUBLIC ${TESSERACT_SRC_DIR}) +target_compile_options(utils PRIVATE ${OPT_COPTS}) +target_link_libraries(utils PUBLIC common libstim Threads::Threads) + +add_library(tesseract_lib ${TESSERACT_SRC_DIR}/tesseract.cc ${TESSERACT_SRC_DIR}/tesseract.h) +target_include_directories(tesseract_lib PUBLIC ${TESSERACT_SRC_DIR}) +target_compile_options(tesseract_lib PRIVATE ${OPT_COPTS}) +target_link_libraries(tesseract_lib PUBLIC utils boost_headers) + +add_library(simplex ${TESSERACT_SRC_DIR}/simplex.cc ${TESSERACT_SRC_DIR}/simplex.h) +target_include_directories(simplex PUBLIC ${TESSERACT_SRC_DIR}) +target_compile_options(simplex PRIVATE ${OPT_COPTS}) +target_link_libraries(simplex PUBLIC common utils tesseract_lib highs libstim Threads::Threads) + +# === Executables === +add_executable(tesseract ${TESSERACT_SRC_DIR}/tesseract_main.cc) +target_compile_options(tesseract PRIVATE ${OPT_COPTS}) +target_link_libraries(tesseract PRIVATE tesseract_lib argparse::argparse nlohmann_json::nlohmann_json) + +add_executable(simplex_bin ${TESSERACT_SRC_DIR}/simplex_main.cc) +set_target_properties(simplex_bin PROPERTIES OUTPUT_NAME simplex) +target_compile_options(simplex_bin PRIVATE ${OPT_COPTS}) +target_link_libraries(simplex_bin PRIVATE common simplex argparse::argparse nlohmann_json::nlohmann_json) + +# === Python module === +pybind11_add_module(tesseract_decoder MODULE ${TESSERACT_SRC_DIR}/tesseract.pybind.cc) +target_compile_options(tesseract_decoder PRIVATE ${OPT_COPTS}) +target_include_directories(tesseract_decoder PRIVATE ${TESSERACT_SRC_DIR}) +target_link_libraries(tesseract_decoder PRIVATE common utils simplex tesseract_lib) + From d4d00402a2c703a115cd57304d32321780e50669 Mon Sep 17 00:00:00 2001 From: Noah Shutty Date: Wed, 6 Aug 2025 08:45:21 -0700 Subject: [PATCH 4/7] refactor: remove verbose flag in favor of log stream --- src/py/common_test.py | 2 +- src/py/simplex_test.py | 18 ++++++- src/py/tesseract_test.py | 18 ++++++- src/py/utils_test.py | 2 +- src/simplex.cc | 70 +++++++++++++++++--------- src/simplex.h | 5 +- src/simplex.pybind.h | 25 ++++++++-- src/simplex_main.cc | 6 ++- src/tesseract.cc | 105 ++++++++++++++++++++------------------- src/tesseract.h | 4 +- src/tesseract.pybind.h | 36 +++++++++++--- src/tesseract_main.cc | 24 +++++---- src/utils.h | 51 +++++++++++++++++++ 13 files changed, 260 insertions(+), 106 deletions(-) diff --git a/src/py/common_test.py b/src/py/common_test.py index 0a537a9..0c440a8 100644 --- a/src/py/common_test.py +++ b/src/py/common_test.py @@ -15,7 +15,7 @@ import pytest import stim -from src import tesseract_decoder +import tesseract_decoder def get_set_bits(n): """ diff --git a/src/py/simplex_test.py b/src/py/simplex_test.py index 1d42d23..7683165 100644 --- a/src/py/simplex_test.py +++ b/src/py/simplex_test.py @@ -16,7 +16,7 @@ import pytest import stim -from src import tesseract_decoder +import tesseract_decoder _DETECTOR_ERROR_MODEL = stim.DetectorErrorModel( """ @@ -33,7 +33,7 @@ def test_create_simplex_config(): assert sc.window_length == 5 assert ( str(sc) - == "SimplexConfig(dem=DetectorErrorModel_Object, window_length=5, window_slide_length=0, verbose=0)" + == "SimplexConfig(dem=DetectorErrorModel_Object, window_length=5, window_slide_length=0)" ) @@ -46,6 +46,20 @@ def test_create_simplex_decoder(): assert decoder.cost_from_errors([2]) == pytest.approx(1.0986123) assert decoder.decode([1]) == [] + +def test_simplex_verbose_callback_receives_output(): + lines = [] + + def cb(s: str) -> None: + lines.append(s) + + config = tesseract_decoder.simplex.SimplexConfig( + _DETECTOR_ERROR_MODEL, window_length=5, verbose_callback=cb + ) + decoder = tesseract_decoder.simplex.SimplexDecoder(config) + decoder.decode_to_errors([1]) + assert any(lines) + def test_simplex_decoder_predicts_various_observable_flips(): """ Tests that the Simplex decoder correctly predicts a logical observable diff --git a/src/py/tesseract_test.py b/src/py/tesseract_test.py index 5a131a4..e253d94 100644 --- a/src/py/tesseract_test.py +++ b/src/py/tesseract_test.py @@ -16,7 +16,7 @@ import pytest import stim -from src import tesseract_decoder +import tesseract_decoder _DETECTOR_ERROR_MODEL = stim.DetectorErrorModel( """ @@ -30,7 +30,7 @@ def test_create_config(): assert ( str(tesseract_decoder.tesseract.TesseractConfig(_DETECTOR_ERROR_MODEL)) - == "TesseractConfig(dem=DetectorErrorModel_Object, det_beam=65535, no_revisit_dets=0, at_most_two_errors_per_detector=0, verbose=0, pqlimit=18446744073709551615, det_orders=[], det_penalty=0)" + == "TesseractConfig(dem=DetectorErrorModel_Object, det_beam=65535, no_revisit_dets=0, at_most_two_errors_per_detector=0, pqlimit=18446744073709551615, det_orders=[], det_penalty=0)" ) assert ( tesseract_decoder.tesseract.TesseractConfig(_DETECTOR_ERROR_MODEL).dem @@ -52,6 +52,20 @@ def test_create_decoder(): assert decoder.cost_from_errors([1]) == pytest.approx(0.5108256237659907) assert decoder.decode([0]) == [] + +def test_tesseract_verbose_callback_receives_output(): + lines = [] + + def cb(s: str) -> None: + lines.append(s) + + config = tesseract_decoder.tesseract.TesseractConfig( + _DETECTOR_ERROR_MODEL, verbose_callback=cb + ) + decoder = tesseract_decoder.tesseract.TesseractDecoder(config) + decoder.decode_to_errors([0]) + assert any(lines) + def test_tesseract_decoder_predicts_various_observable_flips(): """ Tests that the Tesseract decoder correctly predicts a logical observable diff --git a/src/py/utils_test.py b/src/py/utils_test.py index 1e9ba31..6c3dbae 100644 --- a/src/py/utils_test.py +++ b/src/py/utils_test.py @@ -16,7 +16,7 @@ import pytest import stim -from src import tesseract_decoder +import tesseract_decoder _DETECTOR_ERROR_MODEL = stim.DetectorErrorModel( diff --git a/src/simplex.cc b/src/simplex.cc index f67f4d6..7edae46 100644 --- a/src/simplex.cc +++ b/src/simplex.cc @@ -15,24 +15,36 @@ #include "simplex.h" #include +#include #include "Highs.h" #include "io/HMPSIO.h" constexpr size_t T_COORD = 2; +namespace { +void highs_log_cb(HighsLogType, const char* msg, void* user_data) { + CallbackStream* stream = static_cast(user_data); + (*stream) << msg; + stream->flush(); +} +} // namespace + std::string SimplexConfig::str() { auto& self = *this; std::stringstream ss; ss << "SimplexConfig("; ss << "dem=" << "DetectorErrorModel_Object" << ", "; ss << "window_length=" << self.window_length << ", "; - ss << "window_slide_length=" << self.window_slide_length << ", "; - ss << "verbose=" << self.verbose << ")"; + ss << "window_slide_length=" << self.window_slide_length << ")"; return ss.str(); } SimplexDecoder::SimplexDecoder(SimplexConfig _config) : config(_config) { + if (!config.verbose_callback) { + config.verbose_callback = [](const std::string& s) { std::cout << s; }; + } + config.log_stream.callback = config.verbose_callback; config.dem = common::remove_zero_probability_errors(config.dem); std::vector detector_t_coords(config.dem.count_detectors()); for (const stim::DemInstruction& instruction : config.dem.flattened().instructions) { @@ -152,7 +164,11 @@ void SimplexDecoder::init_ilp() { // Disabled presolve entirely after encountering bugs similar to this one: // https://github.com/ERGO-Code/HiGHS/issues/1273 highs->setOptionValue("presolve", "off"); - highs->setOptionValue("output_flag", config.verbose); + highs->setOptionValue("output_flag", config.log_stream.active); + highs->setOptionValue("log_to_console", false); + if (config.log_stream.active) { + highs->setLogCallback(highs_log_cb, &config.log_stream); + } } void SimplexDecoder::decode_to_errors(const std::vector& detections) { @@ -197,9 +213,7 @@ void SimplexDecoder::decode_to_errors(const std::vector& detections) { add_costs_for_time(t1); ++t1; } - if (config.verbose) { - std::cout << "t0 = " << t0 << " t1 = " << t1 << std::endl; - } + config.log_stream << "t0 = " << t0 << " t1 = " << t1 << std::endl; // Pass the model to HiGHS *return_status = highs->passModel(*model); @@ -235,16 +249,20 @@ void SimplexDecoder::decode_to_errors(const std::vector& detections) { } assert(*return_status == HighsStatus::kOk); - if (config.verbose) { - // Get the solution information + if (config.log_stream.active) { const HighsInfo& info = highs->getInfo(); - std::cout << "Simplex iteration count: " << info.simplex_iteration_count << std::endl; - std::cout << "Objective function value: " << info.objective_function_value << std::endl; - std::cout << "Primal solution status: " - << highs->solutionStatusToString(info.primal_solution_status) << std::endl; - std::cout << "Dual solution status: " - << highs->solutionStatusToString(info.dual_solution_status) << std::endl; - std::cout << "Basis: " << highs->basisValidityToString(info.basis_validity) << std::endl; + config.log_stream << "Simplex iteration count: " << info.simplex_iteration_count + << std::endl; + config.log_stream << "Objective function value: " << info.objective_function_value + << std::endl; + config.log_stream << "Primal solution status: " + << highs->solutionStatusToString(info.primal_solution_status) + << std::endl; + config.log_stream << "Dual solution status: " + << highs->solutionStatusToString(info.dual_solution_status) + << std::endl; + config.log_stream << "Basis: " + << highs->basisValidityToString(info.basis_validity) << std::endl; } // Get the model status @@ -286,16 +304,20 @@ void SimplexDecoder::decode_to_errors(const std::vector& detections) { *return_status = highs->run(); assert(*return_status == HighsStatus::kOk); - if (config.verbose) { - // Get the solution information + if (config.log_stream.active) { const HighsInfo& info = highs->getInfo(); - std::cout << "Simplex iteration count: " << info.simplex_iteration_count << std::endl; - std::cout << "Objective function value: " << info.objective_function_value << std::endl; - std::cout << "Primal solution status: " - << highs->solutionStatusToString(info.primal_solution_status) << std::endl; - std::cout << "Dual solution status: " - << highs->solutionStatusToString(info.dual_solution_status) << std::endl; - std::cout << "Basis: " << highs->basisValidityToString(info.basis_validity) << std::endl; + config.log_stream << "Simplex iteration count: " << info.simplex_iteration_count + << std::endl; + config.log_stream << "Objective function value: " << info.objective_function_value + << std::endl; + config.log_stream << "Primal solution status: " + << highs->solutionStatusToString(info.primal_solution_status) + << std::endl; + config.log_stream << "Dual solution status: " + << highs->solutionStatusToString(info.dual_solution_status) + << std::endl; + config.log_stream << "Basis: " + << highs->basisValidityToString(info.basis_validity) << std::endl; } // Get the model status diff --git a/src/simplex.h b/src/simplex.h index f953493..8d74348 100644 --- a/src/simplex.h +++ b/src/simplex.h @@ -14,11 +14,13 @@ #ifndef SIMPLEX_HPP #define SIMPLEX_HPP +#include #include #include #include "common.h" #include "stim.h" +#include "utils.h" struct HighsModel; struct Highs; @@ -29,7 +31,8 @@ struct SimplexConfig { bool parallelize = false; size_t window_length = 0; size_t window_slide_length = 0; - bool verbose = false; + std::function verbose_callback; + CallbackStream log_stream; bool windowing_enabled() { return (window_length != 0); } diff --git a/src/simplex.pybind.h b/src/simplex.pybind.h index f7928a0..1bd94db 100644 --- a/src/simplex.pybind.h +++ b/src/simplex.pybind.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "common.h" #include "simplex.h" @@ -28,9 +29,26 @@ namespace py = pybind11; namespace { SimplexConfig simplex_config_maker(py::object dem, bool parallelize = false, size_t window_length = 0, size_t window_slide_length = 0, - bool verbose = false) { + py::object verbose_callback = py::none()) { stim::DetectorErrorModel input_dem = parse_py_object(dem); - return SimplexConfig({input_dem, parallelize, window_length, window_slide_length, verbose}); + SimplexConfig cfg; + cfg.dem = input_dem; + cfg.parallelize = parallelize; + cfg.window_length = window_length; + cfg.window_slide_length = window_slide_length; + std::function cb; + bool active = false; + if (!verbose_callback.is_none()) { + py::function f = verbose_callback; + cb = [f](const std::string& s) { + py::gil_scoped_acquire gil; + f(s); + }; + active = true; + } + cfg.verbose_callback = cb; + cfg.log_stream = CallbackStream(active, cfg.verbose_callback); + return cfg; } }; // namespace @@ -42,12 +60,11 @@ void add_simplex_module(py::module& root) { py::class_(m, "SimplexConfig") .def(py::init(&simplex_config_maker), py::arg("dem"), py::arg("parallelize") = false, py::arg("window_length") = 0, py::arg("window_slide_length") = 0, - py::arg("verbose") = false) + py::arg("verbose_callback") = py::none()) .def_property("dem", &dem_getter, &dem_setter) .def_readwrite("parallelize", &SimplexConfig::parallelize) .def_readwrite("window_length", &SimplexConfig::window_length) .def_readwrite("window_slide_length", &SimplexConfig::window_slide_length) - .def_readwrite("verbose", &SimplexConfig::verbose) .def("windowing_enabled", &SimplexConfig::windowing_enabled) .def("__str__", &SimplexConfig::str); diff --git a/src/simplex_main.cc b/src/simplex_main.cc index 68ebe49..aea18af 100644 --- a/src/simplex_main.cc +++ b/src/simplex_main.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -134,6 +135,8 @@ struct Args { void extract(SimplexConfig& config, std::vector& shots, std::unique_ptr& writer) { + config.verbose_callback = [](const std::string& s) { std::cout << s; }; + config.log_stream = CallbackStream(verbose, config.verbose_callback); // Get a circuit, if available stim::Circuit circuit; if (!circuit_path.empty()) { @@ -261,7 +264,8 @@ struct Args { config.parallelize = enable_ilp_solver_parallelism; config.window_length = window_length; config.window_slide_length = window_slide_length; - config.verbose = verbose; + config.log_stream.active = verbose; + config.log_stream.callback = config.verbose_callback; } }; diff --git a/src/tesseract.cc b/src/tesseract.cc index 25fabbc..2f36a38 100644 --- a/src/tesseract.cc +++ b/src/tesseract.cc @@ -19,6 +19,7 @@ #include #include // For std::hash (though not strictly necessary here, but good practice) #include +#include namespace { @@ -58,7 +59,6 @@ std::string TesseractConfig::str() { ss << "det_beam=" << config.det_beam << ", "; ss << "no_revisit_dets=" << config.no_revisit_dets << ", "; ss << "at_most_two_errors_per_detector=" << config.at_most_two_errors_per_detector << ", "; - ss << "verbose=" << config.verbose << ", "; ss << "pqlimit=" << config.pqlimit << ", "; ss << "det_orders=" << config.det_orders << ", "; ss << "det_penalty=" << config.det_penalty << ")"; @@ -103,6 +103,10 @@ double TesseractDecoder::get_detcost( } TesseractDecoder::TesseractDecoder(TesseractConfig config_) : config(config_) { + if (!config.verbose_callback) { + config.verbose_callback = [](const std::string& s) { std::cout << s; }; + } + config.log_stream.callback = config.verbose_callback; config.dem = common::remove_zero_probability_errors(config.dem); if (config.det_orders.empty()) { config.det_orders.emplace_back(config.dem.count_detectors()); @@ -114,10 +118,8 @@ TesseractDecoder::TesseractDecoder(TesseractConfig config_) : config(config_) { } assert(config.det_orders.size()); errors = get_errors_from_dem(config.dem.flattened()); - if (config.verbose) { - for (auto& error : errors) { - std::cout << error.str() << std::endl; - } + for (auto& error : errors) { + config.log_stream << error.str() << std::endl; } num_detectors = config.dem.count_detectors(); num_errors = config.dem.count_errors(); @@ -181,12 +183,17 @@ void TesseractDecoder::decode_to_errors(const std::vector& detections) best_errors = predicted_errors_buffer; best_cost = local_cost; } - if (config.verbose) { - std::cout << "for detector_order " << detector_order << " beam " << beam - << " got low confidence " << low_confidence_flag << " and cost " << local_cost - << " and obs_mask " << get_flipped_observables(predicted_errors_buffer) - << ". Best cost so far: " << best_cost << std::endl; + auto obs_mask_vec = get_flipped_observables(predicted_errors_buffer); + config.log_stream << "for detector_order " << detector_order << " beam " << beam + << " got low confidence " << low_confidence_flag << " and cost " + << local_cost << " and obs_mask "; + config.log_stream << "["; + for (size_t i = 0; i < obs_mask_vec.size(); ++i) { + config.log_stream << obs_mask_vec[i]; + if (i + 1 < obs_mask_vec.size()) config.log_stream << ", "; } + config.log_stream << "]"; + config.log_stream << ". Best cost so far: " << best_cost << std::endl; } } else { for (size_t detector_order = 0; detector_order < config.det_orders.size(); ++detector_order) { @@ -196,12 +203,17 @@ void TesseractDecoder::decode_to_errors(const std::vector& detections) best_errors = predicted_errors_buffer; best_cost = local_cost; } - if (config.verbose) { - std::cout << "for detector_order " << detector_order << " beam " << config.det_beam - << " got low confidence " << low_confidence_flag << " and cost " << local_cost - << " and obs_mask " << get_flipped_observables(predicted_errors_buffer) - << ". Best cost so far: " << best_cost << std::endl; + auto obs_mask_vec = get_flipped_observables(predicted_errors_buffer); + config.log_stream << "for detector_order " << detector_order << " beam " << config.det_beam + << " got low confidence " << low_confidence_flag << " and cost " + << local_cost << " and obs_mask "; + config.log_stream << "["; + for (size_t i = 0; i < obs_mask_vec.size(); ++i) { + config.log_stream << obs_mask_vec[i]; + if (i + 1 < obs_mask_vec.size()) config.log_stream << ", "; } + config.log_stream << "]"; + config.log_stream << ". Best cost so far: " << best_cost << std::endl; } } predicted_errors_buffer = best_errors; @@ -285,23 +297,20 @@ void TesseractDecoder::decode_to_errors(const std::vector& detections, flip_detectors_and_block_errors(detector_order, node.errors, detectors, detector_cost_tuples); if (node.num_detectors == 0) { - if (config.verbose) { - std::cout << "activated_errors = "; - for (size_t oei : node.errors) { - std::cout << oei << ", "; - } - std::cout << std::endl; - std::cout << "activated_detectors = "; - for (size_t d = 0; d < num_detectors; ++d) { - if (detectors[d]) { - std::cout << d << ", "; - } + config.log_stream << "activated_errors = "; + for (size_t oei : node.errors) { + config.log_stream << oei << ", "; + } + config.log_stream << std::endl; + config.log_stream << "activated_detectors = "; + for (size_t d = 0; d < num_detectors; ++d) { + if (detectors[d]) { + config.log_stream << d << ", "; } - std::cout << std::endl; - std::cout.precision(13); - std::cout << "Decoding complete. Cost: " << node.cost - << " num_pq_pushed = " << num_pq_pushed << std::endl; } + config.log_stream << std::endl; + config.log_stream << "Decoding complete. Cost: " << node.cost + << " num_pq_pushed = " << num_pq_pushed << std::endl; predicted_errors_buffer = node.errors; return; } @@ -309,25 +318,23 @@ void TesseractDecoder::decode_to_errors(const std::vector& detections, if (config.no_revisit_dets && !visited_detectors[node.num_detectors].insert(detectors).second) continue; - if (config.verbose) { - std::cout.precision(13); - std::cout << "len(pq) = " << pq.size() << " num_pq_pushed = " << num_pq_pushed << std::endl; - std::cout << "num_detectors = " << node.num_detectors - << " max_num_detectors = " << max_num_detectors << " cost = " << node.cost - << std::endl; - std::cout << "activated_errors = "; - for (size_t oei : node.errors) { - std::cout << oei << ", "; - } - std::cout << std::endl; - std::cout << "activated_detectors = "; - for (size_t d = 0; d < num_detectors; ++d) { - if (detectors[d]) { - std::cout << d << ", "; - } + config.log_stream << "len(pq) = " << pq.size() << " num_pq_pushed = " << num_pq_pushed + << std::endl; + config.log_stream << "num_detectors = " << node.num_detectors + << " max_num_detectors = " << max_num_detectors + << " cost = " << node.cost << std::endl; + config.log_stream << "activated_errors = "; + for (size_t oei : node.errors) { + config.log_stream << oei << ", "; + } + config.log_stream << std::endl; + config.log_stream << "activated_detectors = "; + for (size_t d = 0; d < num_detectors; ++d) { + if (detectors[d]) { + config.log_stream << d << ", "; } - std::cout << std::endl; } + config.log_stream << std::endl; if (node.num_detectors < min_num_detectors) { min_num_detectors = node.num_detectors; @@ -450,9 +457,7 @@ void TesseractDecoder::decode_to_errors(const std::vector& detections, } assert(pq.empty()); - if (config.verbose) { - std::cout << "Decoding failed to converge within beam limit." << std::endl; - } + config.log_stream << "Decoding failed to converge within beam limit." << std::endl; low_confidence_flag = true; } diff --git a/src/tesseract.h b/src/tesseract.h index 1d63618..d9f83b2 100644 --- a/src/tesseract.h +++ b/src/tesseract.h @@ -16,6 +16,7 @@ #define TESSERACT_DECODER_H #include +#include #include #include #include @@ -34,10 +35,11 @@ struct TesseractConfig { bool beam_climbing = false; bool no_revisit_dets = false; bool at_most_two_errors_per_detector = false; - bool verbose; size_t pqlimit = std::numeric_limits::max(); std::vector> det_orders; double det_penalty = 0; + std::function verbose_callback; + CallbackStream log_stream; std::string str(); }; diff --git a/src/tesseract.pybind.h b/src/tesseract.pybind.h index e33df6e..6f7ad21 100644 --- a/src/tesseract.pybind.h +++ b/src/tesseract.pybind.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "stim_utils.pybind.h" #include "tesseract.h" @@ -28,13 +29,32 @@ namespace { TesseractConfig tesseract_config_maker( py::object dem, int det_beam = INF_DET_BEAM, bool beam_climbing = false, bool no_revisit_dets = false, bool at_most_two_errors_per_detector = false, - bool verbose = false, size_t pqlimit = std::numeric_limits::max(), + size_t pqlimit = std::numeric_limits::max(), std::vector> det_orders = std::vector>(), - double det_penalty = 0.0) { + double det_penalty = 0.0, py::object verbose_callback = py::none()) { stim::DetectorErrorModel input_dem = parse_py_object(dem); - return TesseractConfig({input_dem, det_beam, beam_climbing, no_revisit_dets, - at_most_two_errors_per_detector, verbose, pqlimit, det_orders, - det_penalty}); + TesseractConfig cfg; + cfg.dem = input_dem; + cfg.det_beam = det_beam; + cfg.beam_climbing = beam_climbing; + cfg.no_revisit_dets = no_revisit_dets; + cfg.at_most_two_errors_per_detector = at_most_two_errors_per_detector; + cfg.pqlimit = pqlimit; + cfg.det_orders = det_orders; + cfg.det_penalty = det_penalty; + std::function cb; + bool active = false; + if (!verbose_callback.is_none()) { + py::function f = verbose_callback; + cb = [f](const std::string& s) { + py::gil_scoped_acquire gil; + f(s); + }; + active = true; + } + cfg.verbose_callback = cb; + cfg.log_stream = CallbackStream(active, cfg.verbose_callback); + return cfg; } }; // namespace void add_tesseract_module(py::module& root) { @@ -44,15 +64,15 @@ void add_tesseract_module(py::module& root) { py::class_(m, "TesseractConfig") .def(py::init(&tesseract_config_maker), py::arg("dem"), py::arg("det_beam") = INF_DET_BEAM, py::arg("beam_climbing") = false, py::arg("no_revisit_dets") = false, - py::arg("at_most_two_errors_per_detector") = false, py::arg("verbose") = false, + py::arg("at_most_two_errors_per_detector") = false, py::arg("pqlimit") = std::numeric_limits::max(), - py::arg("det_orders") = std::vector>(), py::arg("det_penalty") = 0.0) + py::arg("det_orders") = std::vector>(), + py::arg("det_penalty") = 0.0, py::arg("verbose_callback") = py::none()) .def_property("dem", &dem_getter, &dem_setter) .def_readwrite("det_beam", &TesseractConfig::det_beam) .def_readwrite("no_revisit_dets", &TesseractConfig::no_revisit_dets) .def_readwrite("at_most_two_errors_per_detector", &TesseractConfig::at_most_two_errors_per_detector) - .def_readwrite("verbose", &TesseractConfig::verbose) .def_readwrite("pqlimit", &TesseractConfig::pqlimit) .def_readwrite("det_orders", &TesseractConfig::det_orders) .def_readwrite("det_penalty", &TesseractConfig::det_penalty) diff --git a/src/tesseract_main.cc b/src/tesseract_main.cc index 0d3be51..778a427 100644 --- a/src/tesseract_main.cc +++ b/src/tesseract_main.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,8 @@ struct Args { void extract(TesseractConfig& config, std::vector& shots, std::unique_ptr& writer) { + config.verbose_callback = [](const std::string& s) { std::cout << s; }; + config.log_stream = CallbackStream(verbose, config.verbose_callback); // Get a circuit, if available stim::Circuit circuit; if (!circuit_path.empty()) { @@ -171,17 +174,15 @@ struct Args { // Sample orientations of the error model to use for the det priority { - if (verbose) { - auto detector_coords = get_detector_coords(config.dem); - for (size_t d = 0; d < detector_coords.size(); ++d) { - std::cout << "Detector D" << d << " coordinate ("; - size_t e = std::min(3ul, detector_coords[d].size()); - for (size_t i = 0; i < e; ++i) { - std::cout << detector_coords[d][i]; - if (i + 1 < e) std::cout << ", "; - } - std::cout << ")" << std::endl; + auto detector_coords = get_detector_coords(config.dem); + for (size_t d = 0; d < detector_coords.size(); ++d) { + config.log_stream << "Detector D" << d << " coordinate ("; + size_t e = std::min(3ul, detector_coords[d].size()); + for (size_t i = 0; i < e; ++i) { + config.log_stream << detector_coords[d][i]; + if (i + 1 < e) config.log_stream << ", "; } + config.log_stream << ")" << std::endl; } config.det_orders = build_det_orders(config.dem, num_det_orders, det_order_bfs, det_order_seed); @@ -281,7 +282,8 @@ struct Args { config.no_revisit_dets = no_revisit_dets; config.at_most_two_errors_per_detector = at_most_two_errors_per_detector; config.pqlimit = pqlimit; - config.verbose = verbose; + config.log_stream.active = verbose; + config.log_stream.callback = config.verbose_callback; } }; diff --git a/src/utils.h b/src/utils.h index e7ab214..630b3cf 100644 --- a/src/utils.h +++ b/src/utils.h @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -52,4 +54,53 @@ std::vector get_files_recursive(const std::string& directory_path); uint64_t vector_to_u64_mask(const std::vector& v); +struct CallbackStream { + bool active = false; + std::function callback; + std::stringstream buffer; + + CallbackStream() = default; + CallbackStream(bool active_, std::function cb) + : active(active_), callback(std::move(cb)) {} + + CallbackStream(const CallbackStream& other) + : active(other.active), callback(other.callback) {} + CallbackStream& operator=(const CallbackStream& other) { + active = other.active; + callback = other.callback; + buffer.str(""); + buffer.clear(); + return *this; + } + CallbackStream(CallbackStream&&) = default; + CallbackStream& operator=(CallbackStream&&) = default; + + template + CallbackStream& operator<<(const T& value) { + if (active) buffer << value; + return *this; + } + + CallbackStream& operator<<(std::ostream& (*manip)(std::ostream&)) { + if (active) { + manip(buffer); + if (manip == static_cast(std::endl) || + manip == static_cast(std::flush)) { + flush(); + } + } + return *this; + } + + void flush() { + if (active && callback && buffer.tellp() > 0) { + callback(buffer.str()); + buffer.str(""); + buffer.clear(); + } + } + + ~CallbackStream() { flush(); } +}; + #endif // __TESSERACT_UTILS_H__ From b59be9ef08b3ada2c8c9dd622dbcb9654f63051b Mon Sep 17 00:00:00 2001 From: noajshu Date: Wed, 6 Aug 2025 16:19:17 +0000 Subject: [PATCH 5/7] fix the logging of highs --- src/simplex.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simplex.cc b/src/simplex.cc index 7edae46..47b2e33 100644 --- a/src/simplex.cc +++ b/src/simplex.cc @@ -165,7 +165,7 @@ void SimplexDecoder::init_ilp() { // https://github.com/ERGO-Code/HiGHS/issues/1273 highs->setOptionValue("presolve", "off"); highs->setOptionValue("output_flag", config.log_stream.active); - highs->setOptionValue("log_to_console", false); + highs->setOptionValue("log_to_console", config.log_stream.active); if (config.log_stream.active) { highs->setLogCallback(highs_log_cb, &config.log_stream); } From 8d325040b139f24071880050411cadba4dc54da3 Mon Sep 17 00:00:00 2001 From: noajshu Date: Wed, 6 Aug 2025 20:13:40 +0000 Subject: [PATCH 6/7] ran clang-format -i src/*.cc src/*.h --- src/simplex.cc | 16 ++++++---------- src/simplex.pybind.h | 1 + src/tesseract.cc | 5 ++--- src/tesseract.pybind.h | 5 +++-- src/utils.h | 7 ++++--- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/simplex.cc b/src/simplex.cc index 47b2e33..b189bcc 100644 --- a/src/simplex.cc +++ b/src/simplex.cc @@ -259,10 +259,9 @@ void SimplexDecoder::decode_to_errors(const std::vector& detections) { << highs->solutionStatusToString(info.primal_solution_status) << std::endl; config.log_stream << "Dual solution status: " - << highs->solutionStatusToString(info.dual_solution_status) + << highs->solutionStatusToString(info.dual_solution_status) << std::endl; + config.log_stream << "Basis: " << highs->basisValidityToString(info.basis_validity) << std::endl; - config.log_stream << "Basis: " - << highs->basisValidityToString(info.basis_validity) << std::endl; } // Get the model status @@ -306,18 +305,15 @@ void SimplexDecoder::decode_to_errors(const std::vector& detections) { if (config.log_stream.active) { const HighsInfo& info = highs->getInfo(); - config.log_stream << "Simplex iteration count: " << info.simplex_iteration_count - << std::endl; + config.log_stream << "Simplex iteration count: " << info.simplex_iteration_count << std::endl; config.log_stream << "Objective function value: " << info.objective_function_value << std::endl; config.log_stream << "Primal solution status: " - << highs->solutionStatusToString(info.primal_solution_status) - << std::endl; + << highs->solutionStatusToString(info.primal_solution_status) << std::endl; config.log_stream << "Dual solution status: " - << highs->solutionStatusToString(info.dual_solution_status) + << highs->solutionStatusToString(info.dual_solution_status) << std::endl; + config.log_stream << "Basis: " << highs->basisValidityToString(info.basis_validity) << std::endl; - config.log_stream << "Basis: " - << highs->basisValidityToString(info.basis_validity) << std::endl; } // Get the model status diff --git a/src/simplex.pybind.h b/src/simplex.pybind.h index 1bd94db..bc8ce4e 100644 --- a/src/simplex.pybind.h +++ b/src/simplex.pybind.h @@ -18,6 +18,7 @@ #include #include #include + #include #include "common.h" diff --git a/src/tesseract.cc b/src/tesseract.cc index 2f36a38..9ab4e69 100644 --- a/src/tesseract.cc +++ b/src/tesseract.cc @@ -19,7 +19,6 @@ #include #include // For std::hash (though not strictly necessary here, but good practice) #include -#include namespace { @@ -321,8 +320,8 @@ void TesseractDecoder::decode_to_errors(const std::vector& detections, config.log_stream << "len(pq) = " << pq.size() << " num_pq_pushed = " << num_pq_pushed << std::endl; config.log_stream << "num_detectors = " << node.num_detectors - << " max_num_detectors = " << max_num_detectors - << " cost = " << node.cost << std::endl; + << " max_num_detectors = " << max_num_detectors << " cost = " << node.cost + << std::endl; config.log_stream << "activated_errors = "; for (size_t oei : node.errors) { config.log_stream << oei << ", "; diff --git a/src/tesseract.pybind.h b/src/tesseract.pybind.h index 6f7ad21..7d0a8b5 100644 --- a/src/tesseract.pybind.h +++ b/src/tesseract.pybind.h @@ -18,6 +18,7 @@ #include #include #include + #include #include "stim_utils.pybind.h" @@ -66,8 +67,8 @@ void add_tesseract_module(py::module& root) { py::arg("beam_climbing") = false, py::arg("no_revisit_dets") = false, py::arg("at_most_two_errors_per_detector") = false, py::arg("pqlimit") = std::numeric_limits::max(), - py::arg("det_orders") = std::vector>(), - py::arg("det_penalty") = 0.0, py::arg("verbose_callback") = py::none()) + py::arg("det_orders") = std::vector>(), py::arg("det_penalty") = 0.0, + py::arg("verbose_callback") = py::none()) .def_property("dem", &dem_getter, &dem_setter) .def_readwrite("det_beam", &TesseractConfig::det_beam) .def_readwrite("no_revisit_dets", &TesseractConfig::no_revisit_dets) diff --git a/src/utils.h b/src/utils.h index 630b3cf..1e24f74 100644 --- a/src/utils.h +++ b/src/utils.h @@ -63,8 +63,7 @@ struct CallbackStream { CallbackStream(bool active_, std::function cb) : active(active_), callback(std::move(cb)) {} - CallbackStream(const CallbackStream& other) - : active(other.active), callback(other.callback) {} + CallbackStream(const CallbackStream& other) : active(other.active), callback(other.callback) {} CallbackStream& operator=(const CallbackStream& other) { active = other.active; callback = other.callback; @@ -100,7 +99,9 @@ struct CallbackStream { } } - ~CallbackStream() { flush(); } + ~CallbackStream() { + flush(); + } }; #endif // __TESSERACT_UTILS_H__ From 0995f46afd0aba27d43526f272d5b4d8e5372d7e Mon Sep 17 00:00:00 2001 From: noajshu Date: Wed, 6 Aug 2025 20:57:27 +0000 Subject: [PATCH 7/7] undo change to import path --- src/py/common_test.py | 2 +- src/py/simplex_test.py | 2 +- src/py/tesseract_test.py | 2 +- src/py/utils_test.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/py/common_test.py b/src/py/common_test.py index 0c440a8..0a537a9 100644 --- a/src/py/common_test.py +++ b/src/py/common_test.py @@ -15,7 +15,7 @@ import pytest import stim -import tesseract_decoder +from src import tesseract_decoder def get_set_bits(n): """ diff --git a/src/py/simplex_test.py b/src/py/simplex_test.py index 7683165..a67dd90 100644 --- a/src/py/simplex_test.py +++ b/src/py/simplex_test.py @@ -16,7 +16,7 @@ import pytest import stim -import tesseract_decoder +from src import tesseract_decoder _DETECTOR_ERROR_MODEL = stim.DetectorErrorModel( """ diff --git a/src/py/tesseract_test.py b/src/py/tesseract_test.py index e253d94..f62261d 100644 --- a/src/py/tesseract_test.py +++ b/src/py/tesseract_test.py @@ -16,7 +16,7 @@ import pytest import stim -import tesseract_decoder +from src import tesseract_decoder _DETECTOR_ERROR_MODEL = stim.DetectorErrorModel( """ diff --git a/src/py/utils_test.py b/src/py/utils_test.py index 6c3dbae..1e9ba31 100644 --- a/src/py/utils_test.py +++ b/src/py/utils_test.py @@ -16,7 +16,7 @@ import pytest import stim -import tesseract_decoder +from src import tesseract_decoder _DETECTOR_ERROR_MODEL = stim.DetectorErrorModel(