diff --git a/src/stim/dem/detector_error_model.cc b/src/stim/dem/detector_error_model.cc index 6f663dbf..2e3167c7 100644 --- a/src/stim/dem/detector_error_model.cc +++ b/src/stim/dem/detector_error_model.cc @@ -16,9 +16,11 @@ #include "stim/dem/detector_error_model.h" +#include #include #include #include +#include #include "stim/util_bot/str_util.h" @@ -793,3 +795,30 @@ DetectorErrorModel DetectorErrorModel::without_tags() const { } return result; } + +bool DetectorErrorModel::equal_up_to_instruction_ordering(const DetectorErrorModel &other) const { + if (instructions.size() != other.instructions.size()) { + return false; + } + + auto get_sorted_indices = [](const std::vector &ins) { + std::vector indices(ins.size()); + std::iota(indices.begin(), indices.end(), 0); + std::sort(indices.begin(), indices.end(), [&ins](size_t i, size_t j) { + return ins[i] < ins[j]; + }); + return indices; + }; + + // sort the indices to avoid copying instructions + auto sorted_lhs_indices = get_sorted_indices(instructions); + auto sorted_rhs_indices = get_sorted_indices(other.instructions); + + for (size_t i = 0; i < sorted_lhs_indices.size(); i++) { + if (!(instructions[sorted_lhs_indices[i]] == other.instructions[sorted_rhs_indices[i]])) { + return false; + } + } + + return true; +} diff --git a/src/stim/dem/detector_error_model.h b/src/stim/dem/detector_error_model.h index 0f5d53d5..2f4edc80 100644 --- a/src/stim/dem/detector_error_model.h +++ b/src/stim/dem/detector_error_model.h @@ -135,6 +135,13 @@ struct DetectorErrorModel { /// Returns an equivalent detector error model with no repeat blocks or detector_shift instructions. DetectorErrorModel flattened() const; + + /// Returns true if the detector error model is equal to the other detector error model up to instruction ordering. + /// + /// For example, error(0.01) D0 error(0.002) D1 L0 is considered the same as error(0.002) D1 L0 error(0.01) D0. + /// + /// Note: requires O(n log n) time due to sorting. Prefer `==` when you know the instructions are in the same order. + bool equal_up_to_instruction_ordering(const DetectorErrorModel &other) const; }; void print_detector_error_model(std::ostream &out, const DetectorErrorModel &v, size_t indent); diff --git a/src/stim/dem/detector_error_model.test.cc b/src/stim/dem/detector_error_model.test.cc index 429642c9..484ad1e9 100644 --- a/src/stim/dem/detector_error_model.test.cc +++ b/src/stim/dem/detector_error_model.test.cc @@ -894,3 +894,21 @@ TEST(detector_error_model, parse_windows_newlines) { DetectorErrorModel("error(0.125) D0\r\ndetector(5) D10\r\n"), DetectorErrorModel("error(0.125) D0\r\ndetector(5) D10\r\n")); } + +TEST(detector_error_model, equal_up_to_instruction_ordering) { + DetectorErrorModel lhs(R"MODEL( + error(0.01) D0 + error(0.002) D1 L0 + detector(5, 10) D0 + detector(5, 15) D1 + logical_observable L0 + )MODEL"); + DetectorErrorModel rhs(R"MODEL( + error(0.002) D1 L0 + error(0.01) D0 + detector(5, 15) D1 + detector(5, 10) D0 + logical_observable L0 + )MODEL"); + EXPECT_TRUE(lhs.equal_up_to_instruction_ordering(rhs)); +}