Skip to content

Commit f6d7fdf

Browse files
remove verbose doc added during testing
Signed-off-by: vedika-saravanan <vsaravanan@nvidia.com>
1 parent 9c24245 commit f6d7fdf

9 files changed

Lines changed: 21 additions & 95 deletions

File tree

libs/qec/include/cudaq/qec/decoder.h

Lines changed: 11 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,10 @@ using float_t = CUDAQX_QEC_FLOAT_TYPE;
3030
using float_t = double;
3131
#endif
3232

33-
/// @brief Construction input for a decoder: either an explicit parity-check
34-
/// matrix (`cudaq::qec::sparse_binary_matrix`) or a Stim detector error model
35-
/// string (`std::string`).
36-
///
37-
/// Parity-check-matrix-based decoders (LUT, sliding_window, TRT, PyMatching,
38-
/// nv-qldpc, ...) accept either alternative: a DEM string is parsed into a
39-
/// parity-check matrix via `dem_from_stim_text`. Decoders that require the raw
40-
/// DEM (e.g. Chromobius, which needs detector color/basis annotations) require
41-
/// the string alternative and reject a bare matrix.
42-
///
43-
/// @note The factory input owns the DEM text. Public overloads accept
44-
/// `std::string`, `const char *`, and `std::string_view` and copy into this
45-
/// variant before dispatching to decoder plugins.
46-
using decoder_init =
47-
std::variant<cudaq::qec::sparse_binary_matrix, std::string>;
33+
/// Decoder construction input: either a parity-check matrix or raw Stim DEM
34+
/// text. PCM-based decoders can accept both; DEM-native decoders can require
35+
/// the string alternative via `require_dem_text`.
36+
using decoder_init = std::variant<sparse_binary_matrix, std::string>;
4837

4938
/// @brief Validates that all keys in a heterogeneous map are found in a list of
5039
/// acceptable types
@@ -195,10 +184,7 @@ class decoder
195184

196185
/// @brief Construct a registered decoder by name.
197186
/// @param name The registered decoder name.
198-
/// @param init Either a parity-check matrix or a Stim DEM string (see
199-
/// `decoder_init`). The variant is forwarded to the decoder's creator, so
200-
/// parity-check-matrix-based decoders and DEM-native decoders (Chromobius)
201-
/// share a single entry point.
187+
/// @param init A parity-check matrix or raw Stim DEM string.
202188
/// @param param_map Optional decoder-specific parameters.
203189
static std::unique_ptr<decoder>
204190
get(const std::string &name, const decoder_init &init,
@@ -530,39 +516,22 @@ get_decoder(const std::string &name, std::string_view stim_dem_text,
530516
return get_decoder(name, decoder_init{std::string{stim_dem_text}}, options);
531517
}
532518

533-
/// @brief DEM-derived defaults; pointers alias into the source `dem`.
519+
/// DEM-derived defaults; pointers alias into the source `dem`.
534520
struct dem_default_values {
535521
const cudaqx::tensor<uint8_t> *O = nullptr;
536522
const std::vector<double> *error_rate_vec = nullptr;
537523
};
538524

539-
/// @brief Return DEM defaults for any key not already supplied by the user.
540-
/// Shared by `make_pcm_decoder` and the Python binding.
525+
/// Return DEM defaults for keys not already supplied by the user.
541526
dem_default_values dem_defaults_for_missing_keys(
542527
const std::function<bool(const std::string &)> &contains_user_key,
543528
const detector_error_model &dem);
544529

545-
/// @brief Extract the Stim DEM text from a `decoder_init`, throwing if it
546-
/// holds a parity-check matrix instead. Use this in the create() function of
547-
/// decoders that require a raw DEM (e.g. Chromobius), which cannot be
548-
/// reconstructed from a bare parity-check matrix.
530+
/// Extract raw Stim DEM text for DEM-native decoders.
549531
std::string_view require_dem_text(const decoder_init &init);
550532

551-
/// @brief Build a parity-check-matrix-based decoder from a `decoder_init`.
552-
///
553-
/// If `init` holds a sparse matrix, it is used directly as the parity-check
554-
/// matrix. If it holds a Stim DEM string, it is parsed via
555-
/// `dem_from_stim_text` and the derived observables (`"O"`) and per-error
556-
/// rates (`"error_rate_vec"`) are injected into `params` unless the user
557-
/// already supplied them (user values win). This is the shared implementation
558-
/// behind the create() function of every parity-check-matrix-based decoder,
559-
/// giving them DEM-string support for free.
560-
///
561-
/// @note The DEM parse is lossy: detector annotations, decomposition
562-
/// separators, and `error_ids` are dropped. Sufficient for matching-style /
563-
/// parity-check-matrix decoders (LUT, NV, sliding_window, TRT, PyMatching).
564-
/// Decoders that need full DEM metadata (e.g. Chromobius detector color/basis)
565-
/// must consume the string directly via `require_dem_text`.
533+
/// Build a PCM-based decoder. If `init` holds DEM text, it is parsed into a PCM
534+
/// and DEM-derived `"O"` / `"error_rate_vec"` defaults are added when absent.
566535
template <typename DecoderT>
567536
std::unique_ptr<decoder>
568537
make_pcm_decoder(const decoder_init &init,
@@ -582,10 +551,8 @@ make_pcm_decoder(const decoder_init &init,
582551
cudaq::qec::sparse_binary_matrix(dem.detector_error_matrix), merged);
583552
}
584553

585-
/// @brief Construct a decoder by name from a Stim detector error model string.
586-
///
587554
/// @deprecated Prefer `get_decoder`, which now accepts a Stim DEM string
588-
/// directly via `decoder_init`. Retained as a thin convenience alias.
555+
/// directly.
589556
std::unique_ptr<decoder>
590557
get_decoder_from_stim_dem(const std::string &name,
591558
const std::string &stim_dem_text,

libs/qec/include/cudaq/qec/detector_error_model.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,8 @@ struct detector_error_model {
6666
void canonicalize_for_rounds(uint32_t num_syndromes_per_round);
6767
};
6868

69-
/// @brief Parse a Stim detector error model text into a
70-
/// `cudaq::qec::detector_error_model`. Each `error` instruction in the DEM
71-
/// becomes a single column in `detector_error_matrix` and
72-
/// `observables_flips_matrix`; suggested decomposition separators are
73-
/// folded into the same column.
74-
///
75-
/// @note Lossy: only detector/observable flips and error probabilities
76-
/// are extracted. Annotations (`detector`, `logical_observable`),
77-
/// suggested-decomposition separators, and `error_ids` are dropped.
78-
/// Decoders that need full DEM metadata (e.g. Chromobius detector
79-
/// color/basis) should consume the raw Stim DEM string via `decoder_init`
80-
/// and `require_dem_text` instead of this lossy representation.
69+
/// Parse Stim DEM text into detector/observable flip matrices and error rates.
70+
/// This is lossy; DEM-native decoders should consume raw DEM text instead.
8171
detector_error_model dem_from_stim_text(const std::string &dem_text);
8272

8373
} // namespace cudaq::qec

libs/qec/lib/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ add_library(${LIBRARY_NAME} SHARED ${QEC_SOURCES})
6262
add_subdirectory(decoders/plugins/example)
6363
add_subdirectory(decoders/plugins/pymatching)
6464

65-
# libstim comes from the parent build (CUDA-Q).
6665
if(NOT TARGET libstim)
6766
message(FATAL_ERROR
6867
"libstim target not available; required by cudaq-qec for Stim DEM parsing.")

libs/qec/lib/decoder_stim_dem.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ std::unique_ptr<decoder>
3737
get_decoder_from_stim_dem(const std::string &name,
3838
const std::string &stim_dem_text,
3939
const cudaqx::heterogeneous_map &options) {
40-
// Retained for backward compatibility: get_decoder now accepts a Stim DEM
41-
// string directly via decoder_init.
4240
return get_decoder(name, decoder_init{stim_dem_text}, options);
4341
}
4442

libs/qec/lib/detector_error_model.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ detector_error_model dem_from_stim_text(const std::string &dem_text) {
3434
std::size_t instruction_index = 0;
3535

3636
dem.iter_flatten_error_instructions([&](const stim::DemInstruction &inst) {
37-
if (inst.arg_data.size() == 0)
37+
if (inst.arg_data.empty())
3838
throw std::runtime_error(
3939
"Stim DEM error instruction missing probability argument (index " +
4040
std::to_string(instruction_index) + ")");
@@ -54,9 +54,6 @@ detector_error_model dem_from_stim_text(const std::string &dem_text) {
5454
} else if (target.is_observable_id()) {
5555
obs.push_back(static_cast<std::size_t>(target.val()));
5656
} else {
57-
// Forward-compat tripwire; unreachable today (stim's three
58-
// DemTarget categories are exhaustive -- pinned by
59-
// StimDemTargetCategoriesAreExhaustive).
6057
throw std::runtime_error(
6158
"Stim DEM error instruction (index " +
6259
std::to_string(instruction_index) +
@@ -71,8 +68,6 @@ detector_error_model dem_from_stim_text(const std::string &dem_text) {
7168
});
7269

7370
const std::size_t num_errors = rates.size();
74-
// Reject zero-column H at the boundary instead of letting decoders
75-
// crash with block_size == 0.
7671
if (num_errors == 0)
7772
throw std::runtime_error(
7873
"Stim DEM contains no error mechanisms after flattening");

libs/qec/python/bindings/py_decoder.cpp

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -339,16 +339,14 @@ makeBatchDecoderResult(const std::vector<decoder_result> &results) {
339339
};
340340
}
341341

342-
// Wrap a borrowed cudaqx buffer in a NumPy array and force a Python-side copy,
343-
// so the returned object owns its data.
344-
nb::object toPyArray(const cudaqx::tensor<uint8_t> &t) {
342+
nb::object copyToPyArray(const cudaqx::tensor<uint8_t> &t) {
345343
size_t shape[2] = {t.shape()[0], t.shape()[1]};
346344
auto arr = nb::ndarray<nb::numpy, uint8_t>(const_cast<uint8_t *>(t.data()), 2,
347345
shape, nb::none());
348346
return nb::cast(arr).attr("copy")();
349347
}
350348

351-
nb::object toPyArray(const std::vector<double> &v) {
349+
nb::object copyToPyArray(const std::vector<double> &v) {
352350
size_t shape[1] = {v.size()};
353351
auto arr = nb::ndarray<nb::numpy, double>(const_cast<double *>(v.data()), 1,
354352
shape, nb::none());
@@ -735,25 +733,21 @@ void bindDecoder(nb::module_ &mod) {
735733
});
736734
});
737735

738-
// Shared implementation for constructing a decoder from a Stim DEM string,
739-
// used by both get_decoder overload paths and the (deprecated)
740-
// get_decoder_from_stim_dem entry point.
741736
auto get_decoder_from_dem_text = [](const std::string &name,
742737
const std::string &dem_text,
743738
nb::kwargs options)
744739
-> std::variant<nb::object, std::unique_ptr<decoder>> {
745740
if (PyDecoderRegistry::contains(name)) {
746741
auto dem = dem_from_stim_text(dem_text);
747742

748-
// Keep in sync with make_pcm_decoder in decoder.h.
749743
auto defaults = dem_defaults_for_missing_keys(
750744
[&](const std::string &key) { return options.contains(key); }, dem);
751745
if (defaults.O)
752-
options["O"] = toPyArray(*defaults.O);
746+
options["O"] = copyToPyArray(*defaults.O);
753747
if (defaults.error_rate_vec)
754-
options["error_rate_vec"] = toPyArray(*defaults.error_rate_vec);
748+
options["error_rate_vec"] = copyToPyArray(*defaults.error_rate_vec);
755749

756-
nb::object H_obj = toPyArray(dem.detector_error_matrix);
750+
nb::object H_obj = copyToPyArray(dem.detector_error_matrix);
757751
return PyDecoderRegistry::get_decoder(name, H_obj, options);
758752
}
759753

@@ -824,7 +818,7 @@ void bindDecoder(nb::module_ &mod) {
824818
qecmod.def(
825819
"get_decoder_from_stim_dem", get_decoder_from_dem_text,
826820
"Deprecated: prefer get_decoder, which now accepts a Stim detector error "
827-
"model string directly. Retained as a thin alias.");
821+
"model string directly.");
828822

829823
qecmod.def(
830824
"get_sorted_pcm_column_indices",

libs/qec/python/tests/test_decoder.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -763,9 +763,6 @@ def test_generate_random_pcm_signed_weight_rejects_negative():
763763

764764

765765
def test_get_decoder_from_stim_dem():
766-
# 2 detectors, 1 observable, 3 errors. Matches the C++
767-
# StimDemDecoderFactory.ConstructsLutDecoderFromStimDemText DEM so the
768-
# truth-data assertions stay in sync across language bindings.
769766
dem_text = ("error(0.1) D0 L0\n"
770767
"error(0.1) D1 L0\n"
771768
"error(0.05) D0 D1\n")
@@ -788,8 +785,6 @@ def test_get_decoder_from_stim_dem():
788785

789786

790787
def test_get_decoder_accepts_stim_dem_string():
791-
# get_decoder dispatches on the second argument: a str is treated as a Stim
792-
# DEM, an ndarray as a parity-check matrix.
793788
dem_text = ("error(0.1) D0 L0\n"
794789
"error(0.1) D1 L0\n"
795790
"error(0.05) D0 D1\n")
@@ -833,8 +828,6 @@ def test_get_decoder_from_stim_dem_rejects_unknown_decoder():
833828

834829

835830
def test_get_decoder_from_stim_dem_user_O_wins_over_dem_derived():
836-
# Wrong-shape user O trips PyMatching's validation; silent overwrite
837-
# by the DEM-derived O would suppress the throw.
838831
dem_text = ("error(0.1) D0 L0\n"
839832
"error(0.1) D1 L0\n"
840833
"error(0.05) D0 D1\n")

libs/qec/unittests/CMakeLists.txt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ find_package(CUDAToolkit REQUIRED)
3535
add_compile_options(-Wno-attributes)
3636

3737
add_executable(test_decoders test_decoders.cpp decoders/sample_decoder.cpp)
38-
# Direct libstim link for StimDemTargetCategoriesAreExhaustive;
39-
# cudaq-qec hides stim symbols via --exclude-libs.
4038
target_link_libraries(test_decoders PRIVATE GTest::gtest_main cudaq-qec cudaq-qec-realtime-decoding cudaq::cudaq libstim)
4139
add_dependencies(CUDAQXQECUnitTests test_decoders)
4240
gtest_discover_tests(test_decoders)
@@ -511,4 +509,3 @@ add_subdirectory(decoders/pymatching)
511509
if(CUDAQX_QEC_ENABLE_HOLOLINK_TOOLS)
512510
add_subdirectory(utils)
513511
endif()
514-

libs/qec/unittests/test_decoders.cpp

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -779,8 +779,6 @@ error(0.05) D0 D1
779779
}
780780

781781
TEST(StimDemDecoderFactory, UnifiedGetDecoderAcceptsStimDemString) {
782-
// get_decoder and decoder::get accept a Stim DEM string directly via
783-
// decoder_init, matching the (deprecated) get_decoder_from_stim_dem path.
784782
const std::string dem_text = R"(error(0.1) D0 L0
785783
error(0.1) D1 L0
786784
error(0.05) D0 D1
@@ -800,7 +798,6 @@ error(0.05) D0 D1
800798
}
801799

802800
TEST(StimDemDecoderFactory, UnifiedGetDecoderStillAcceptsParityCheckMatrix) {
803-
// Dense tensor inputs still convert to sparse PCM storage unchanged.
804801
cudaqx::tensor<uint8_t> H({2, 3});
805802
H.copy(std::vector<uint8_t>{1, 0, 1, 0, 1, 1}.data(), {2, 3});
806803
auto d = cudaq::qec::get_decoder("single_error_lut", H);
@@ -845,17 +842,13 @@ TEST(StimDemDecoderFactory, ThrowsOnUnknownDecoderName) {
845842
}
846843

847844
TEST(StimDemDecoderFactory, ThrowsOnEmptyErrorMechanisms) {
848-
// A bare detector(...) line parses but yields zero error mechanisms.
849845
const std::string dem_text = "detector(0, 0, 0)\n";
850846
EXPECT_THROW(
851847
cudaq::qec::get_decoder_from_stim_dem("single_error_lut", dem_text),
852848
std::runtime_error);
853849
}
854850

855851
TEST(StimDemDecoderFactory, StimDemTargetCategoriesAreExhaustive) {
856-
// Pins the invariant that keeps the defensive throw in
857-
// dem_from_stim_text unreachable. Fires first if stim's encoding
858-
// changes.
859852
const std::vector<stim::DemTarget> samples = {
860853
stim::DemTarget::separator(),
861854
stim::DemTarget::relative_detector_id(0),
@@ -878,7 +871,7 @@ error(0.1) D1 L0
878871
error(0.05) D0 D1
879872
)";
880873
cudaqx::heterogeneous_map opts;
881-
opts.insert("error_rate_vec", std::vector<double>{0.5}); // wrong size
874+
opts.insert("error_rate_vec", std::vector<double>{0.5});
882875
EXPECT_THROW(
883876
cudaq::qec::get_decoder_from_stim_dem("single_error_lut", dem_text, opts),
884877
std::runtime_error);

0 commit comments

Comments
 (0)