From 59bd90ff552c91914c7da402ddef90996600917e Mon Sep 17 00:00:00 2001 From: Sid Madhuk Date: Wed, 9 Jul 2025 20:53:49 +0000 Subject: [PATCH 1/2] throw on decomposed errors with hyperedge components --- .../sparse_blossom/driver/user_graph.h | 4 +++- .../sparse_blossom/driver/user_graph.test.cc | 20 +++++++------------ 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/pymatching/sparse_blossom/driver/user_graph.h b/src/pymatching/sparse_blossom/driver/user_graph.h index 68269cf94..be076071c 100644 --- a/src/pymatching/sparse_blossom/driver/user_graph.h +++ b/src/pymatching/sparse_blossom/driver/user_graph.h @@ -272,7 +272,9 @@ void iter_dem_instructions_include_correlations( } else if (target.is_separator()) { // If the previous error in the decomposition had 3 or more components, we ignore it. if (component->node1 == SIZE_MAX) { - decomposed_err.components.pop_back(); + throw std::invalid_argument( + "Encountered a decomposed error instruction with a hyperedge component (3 or more detectors). " + "This is not supported."); } else if (p > 0) { handle_dem_error(p, {component->node1, component->node2}, component->observable_indices); } diff --git a/src/pymatching/sparse_blossom/driver/user_graph.test.cc b/src/pymatching/sparse_blossom/driver/user_graph.test.cc index 95053a0eb..3964bc6ff 100644 --- a/src/pymatching/sparse_blossom/driver/user_graph.test.cc +++ b/src/pymatching/sparse_blossom/driver/user_graph.test.cc @@ -282,15 +282,13 @@ TEST(IterDemInstructionsTest, DecomposedError) { EXPECT_EQ(handler.handled_errors[2], (HandledError{0.1, 4, SIZE_MAX, {}})); } -// Test a decomposed error where one of the components is a hyperedge and should be ignored. -TEST(IterDemInstructionsTest, DecomposedErrorWithIgnoredComponent) { +// Test that a decomposed error with a hyperedge component throws an exception. +TEST(IterDemInstructionsTest, DecomposedErrorWithHyperedgeThrows) { stim::DetectorErrorModel dem("error(0.15) D0 D1 ^ D2 D3 D4 ^ D5 D6 L2"); TestHandler handler; - pm::iter_dem_instructions_include_correlations(dem, handler); - ASSERT_EQ(handler.handled_errors.size(), 2); - std::vector expected = {{0.15, 0, 1, {}}, {0.15, 5, 6, {2}}}; - EXPECT_EQ(handler.handled_errors, expected); + // Assert that the function throws std::invalid_argument when processing the DEM. + ASSERT_THROW(pm::iter_dem_instructions_include_correlations(dem, handler), std::invalid_argument); } // Test a complex DEM with multiple instruction types and edge cases combined. @@ -298,21 +296,17 @@ TEST(IterDemInstructionsTest, CombinedComplexDem) { stim::DetectorErrorModel dem(R"DEM( error(0.1) D0 # Instruction 1: Simple error(0.2) D1 D2 L0 # Instruction 2: Two detectors, one observable - error(0.3) D3 D4 D5 ^ D6 # Instruction 3: Hyperedge ignored, second component handled + error(0.3) D3 D4 D5 # Instruction 3: Hyperedge ignored, second component handled error(0.0) D7 # Instruction 4: Zero probability, ignored error(0.4) D8 ^ D9 L1 # Instruction 5: Decomposed )DEM"); TestHandler handler; pm::iter_dem_instructions_include_correlations(dem, handler); - ASSERT_EQ(handler.handled_errors.size(), 5); + ASSERT_EQ(handler.handled_errors.size(), 4); std::vector expected = { - {0.1, 0, SIZE_MAX, {}}, - {0.2, 1, 2, {0}}, - {0.3, 6, SIZE_MAX, {}}, - {0.4, 8, SIZE_MAX, {}}, - {0.4, 9, SIZE_MAX, {1}}}; + {0.1, 0, SIZE_MAX, {}}, {0.2, 1, 2, {0}}, {0.4, 8, SIZE_MAX, {}}, {0.4, 9, SIZE_MAX, {1}}}; EXPECT_EQ(handler.handled_errors, expected); } From 4fff65aae8fd999aa78789e3dacdbf06dcb5dcbb Mon Sep 17 00:00:00 2001 From: Sid Madhuk Date: Wed, 9 Jul 2025 22:55:38 +0000 Subject: [PATCH 2/2] extend: throw on probabilities greater than half --- src/pymatching/sparse_blossom/driver/user_graph.h | 5 +++++ src/pymatching/sparse_blossom/driver/user_graph.test.cc | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/src/pymatching/sparse_blossom/driver/user_graph.h b/src/pymatching/sparse_blossom/driver/user_graph.h index be076071c..511dffc03 100644 --- a/src/pymatching/sparse_blossom/driver/user_graph.h +++ b/src/pymatching/sparse_blossom/driver/user_graph.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "pymatching/rand/rand_gen.h" @@ -246,6 +247,10 @@ void iter_dem_instructions_include_correlations( double p = instruction.arg_data[0]; pm::DecomposedDemError decomposed_err; decomposed_err.probability = p; + if (p > 0.5) { + throw ::std::invalid_argument( + "Errors with probability greater than 0.5 are not supported with correlations enabled"); + } decomposed_err.components = {}; decomposed_err.components.push_back({}); UserEdge* component = &decomposed_err.components.back(); diff --git a/src/pymatching/sparse_blossom/driver/user_graph.test.cc b/src/pymatching/sparse_blossom/driver/user_graph.test.cc index 3964bc6ff..a3043c265 100644 --- a/src/pymatching/sparse_blossom/driver/user_graph.test.cc +++ b/src/pymatching/sparse_blossom/driver/user_graph.test.cc @@ -16,6 +16,7 @@ #include #include +#include #include "pymatching/sparse_blossom/driver/mwpm_decoding.h" @@ -310,3 +311,10 @@ TEST(IterDemInstructionsTest, CombinedComplexDem) { EXPECT_EQ(handler.handled_errors, expected); } + +// Test that an error greater than 0.5 results in a throw. +TEST(IterDemInstructionsTest, ProbabilityGreaterThanHalfThrows) { + stim::DetectorErrorModel dem("error(0.51) D0 D2"); + TestHandler handler; + ASSERT_THROW(pm::iter_dem_instructions_include_correlations(dem, handler), std::invalid_argument); +}