implemented partition function

This commit is contained in:
2026-08-04 15:56:21 +02:00
parent 4078893f1e
commit b10ac73e9b
2 changed files with 131 additions and 0 deletions
+54
View File
@@ -125,4 +125,58 @@ inline double linear_interpolation(const std::pair<double, double> &bin_edge,
bin_values.second * (coord - bin_edge.first) / bin_width;
}
/// @brief XOR operator
inline bool XOR(const bool a, const bool b) { return (a || b) && !(a && b); }
/// @brief range struct
template <typename Iterator> struct range {
/// @brief start of the range
Iterator start{};
/// @brief end of the range
Iterator end{};
};
/**
* @brief partition range of elements into contiguous subranges for which the
* partition criteria is the same.
* @param start pointer to the first element of the range
* @param end pointer to the last element of the range
* @param partition_criteria function that returns true or false for a given
* element
* @return vector of ranges that are contiguous and have the same partition
* criteria
*/
template <typename Iterator>
std::vector<range<Iterator>> partition(
Iterator start, Iterator end,
std::function<bool(const typename std::iterator_traits<Iterator>::value_type
&)> &partition_criteria) {
std::vector<range<Iterator>> partitions;
partitions.reserve(std::distance(start, end));
auto partition_start = start;
auto partition_end = end;
bool chunk_fulfills_criteria = partition_criteria(
*partition_start); // starts with range fulfilling criteria
auto chunk_criteria =
[&partition_criteria, &chunk_fulfills_criteria](
const typename std::iterator_traits<Iterator>::value_type &value) {
return XOR(partition_criteria(value), chunk_fulfills_criteria);
}; // exclusive or
while (partition_start < end) {
partition_end = std::find_if(partition_start, end, chunk_criteria);
partitions.push_back({partition_start, partition_end});
partition_start = partition_end;
chunk_fulfills_criteria =
!chunk_fulfills_criteria; // flip criteria for next chunk
}
return partitions;
}
} // namespace aare
+77
View File
@@ -232,3 +232,80 @@ TEST_CASE("Bilinear interpolation", "[algorithm]") {
REQUIRE(interpolated_value == 5.25);
}
}
TEST_CASE("partition range for vector", "[algorithm]") {
std::function<bool(const bool &)> partition_criteria =
[](const bool &value) { return value; };
SECTION("partition criteria is always false") {
std::vector<bool> vec = {false, false, false, false, false};
auto partitions =
aare::partition(vec.begin(), vec.end(), partition_criteria);
REQUIRE(partitions.size() == 1);
REQUIRE(partitions[0].start == vec.begin());
REQUIRE(partitions[0].end == vec.end());
}
SECTION("partition criteria is always true") {
std::vector<bool> vec = {true, true, true, true, true};
auto partitions =
aare::partition(vec.begin(), vec.end(), partition_criteria);
REQUIRE(partitions.size() == 1);
REQUIRE(partitions[0].start == vec.begin());
REQUIRE(partitions[0].end == vec.end());
}
SECTION("range starts with partition criteria true") {
std::vector<bool> vec = {true, true, false, false, true, true};
auto partitions =
aare::partition(vec.begin(), vec.end(), partition_criteria);
REQUIRE(partitions.size() == 3);
REQUIRE(partitions[0].start == vec.begin());
REQUIRE(partitions[0].end == vec.begin() + 2);
REQUIRE(partitions[1].start == vec.begin() + 2);
REQUIRE(partitions[1].end == vec.begin() + 4);
REQUIRE(partitions[2].start == vec.begin() + 4);
REQUIRE(partitions[2].end == vec.end());
}
SECTION("range starts with partition criteria false") {
std::vector<bool> vec = {false, false, true, true, false};
auto partitions =
aare::partition(vec.begin(), vec.end(), partition_criteria);
REQUIRE(partitions.size() == 3);
REQUIRE(partitions[0].start == vec.begin());
REQUIRE(partitions[0].end == vec.begin() + 2);
REQUIRE(partitions[1].start == vec.begin() + 2);
REQUIRE(partitions[1].end == vec.begin() + 4);
REQUIRE(partitions[2].start == vec.begin() + 4);
REQUIRE(partitions[2].end == vec.end());
}
SECTION("empty vector") {
std::vector<bool> vec = {};
auto partitions =
aare::partition(vec.begin(), vec.end(), partition_criteria);
REQUIRE(partitions.size() == 0);
}
}
TEST_CASE("partition range for NDArray", "[algorithm]") {
std::function<bool(const bool &)> partition_criteria =
[](const bool &value) { return value; };
aare::NDArray<bool, 1> array(
std::array<bool, 7>{true, true, false, true, true, false, false});
auto partitions =
aare::partition(array.begin(), array.end(), partition_criteria);
REQUIRE(partitions.size() == 4);
REQUIRE(partitions[0].start == array.begin());
REQUIRE(partitions[0].end == array.begin() + 2);
REQUIRE(partitions[1].start == array.begin() + 2);
REQUIRE(partitions[1].end == array.begin() + 3);
REQUIRE(partitions[2].start == array.begin() + 3);
REQUIRE(partitions[2].end == array.begin() + 5);
REQUIRE(partitions[3].start == array.begin() + 5);
REQUIRE(partitions[3].end == array.end());
}