reduction to 2x2 clusters for general clusters

This commit is contained in:
2025-08-18 18:23:15 +02:00
parent 9a3694b980
commit cb163c79b4
5 changed files with 205 additions and 106 deletions

View File

@@ -8,6 +8,7 @@
#pragma once #pragma once
#include "logger.hpp"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstdint> #include <cstdint>
@@ -74,104 +75,149 @@ struct Cluster {
} }
}; };
template<typename T> /**
Cluster<T, 2, 2, uint16_t> reduce_3x3_to_2x2(const Cluster<T, 3, 3, uint16_t> &c) { * @brief Reduce a cluster to a 2x2 cluster by selecting the 2x2 block with the
Cluster<T, 2, 2, uint16_t> result; * highest sum.
* @param c Cluster to reduce
auto [s, i] = c.max_sum_2x2(); * @return Cluster<T, 2, 2, uint16_t> reduced cluster
switch (i) { */
case 0: template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
result.x = c.x-1; typename CoordType = int16_t>
result.y = c.y+1; Cluster<T, 2, 2, CoordType>
result.data = {c.data[0], c.data[1], c.data[3], c.data[4]}; reduce_to_2x2(const Cluster<T, ClusterSizeX, ClusterSizeY, CoordType> &c) {
break;
case 1:
result.x = c.x;
result.y = c.y + 1;
result.data = {c.data[1], c.data[2], c.data[4], c.data[5]};
break;
case 2:
result.x = c.x -1;
result.y = c.y;
result.data = {c.data[3], c.data[4], c.data[6], c.data[7]};
break;
case 3:
result.x = c.x;
result.y = c.y;
result.data = {c.data[4], c.data[5], c.data[7], c.data[8]};
break;
}
// do some stuff static_assert(ClusterSizeX >= 2 && ClusterSizeY >= 2,
"Cluster sizes must be at least 2x2 for reduction to 2x2");
Cluster<T, 2, 2, CoordType> result;
auto [sum, index] = c.max_sum_2x2();
int16_t cluster_center_index =
(ClusterSizeX / 2) + (ClusterSizeY / 2) * ClusterSizeX;
int16_t index_bottom_left_max_2x2_subcluster =
(int(index / (ClusterSizeX - 1))) * ClusterSizeX +
index % (ClusterSizeX - 1);
result.x =
c.x + (index_bottom_left_max_2x2_subcluster - cluster_center_index) %
ClusterSizeX;
result.y =
c.y - (index_bottom_left_max_2x2_subcluster - cluster_center_index) /
ClusterSizeX;
result.data = {
c.data[index_bottom_left_max_2x2_subcluster],
c.data[index_bottom_left_max_2x2_subcluster + 1],
c.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX],
c.data[index_bottom_left_max_2x2_subcluster + ClusterSizeX + 1]};
return result; return result;
} }
template<typename T> template <typename T>
Cluster<T, 3, 3, uint16_t> reduce_5x5_to_3x3(const Cluster<T, 5, 5, uint16_t> &c) { Cluster<T, 3, 3, uint16_t>
reduce_5x5_to_3x3(const Cluster<T, 5, 5, uint16_t> &c) {
Cluster<T, 3, 3, uint16_t> result; Cluster<T, 3, 3, uint16_t> result;
// Reduce the 5x5 cluster to a 3x3 cluster by selecting the 3x3 block with the highest sum // Reduce the 5x5 cluster to a 3x3 cluster by selecting the 3x3 block with
// the highest sum
std::array<T, 9> sum_3x3_subclusters; std::array<T, 9> sum_3x3_subclusters;
//Write out the sums in the hope that the compiler can optimize this // Write out the sums in the hope that the compiler can optimize this
sum_3x3_subclusters[0] = c.data[0] + c.data[1] + c.data[2] + c.data[5] + c.data[6] + c.data[7] + c.data[10] + c.data[11] + c.data[12]; sum_3x3_subclusters[0] = c.data[0] + c.data[1] + c.data[2] + c.data[5] +
sum_3x3_subclusters[1] = c.data[1] + c.data[2] + c.data[3] + c.data[6] + c.data[7] + c.data[8] + c.data[11] + c.data[12] + c.data[13]; c.data[6] + c.data[7] + c.data[10] + c.data[11] +
sum_3x3_subclusters[2] = c.data[2] + c.data[3] + c.data[4] + c.data[7] + c.data[8] + c.data[9] + c.data[12] + c.data[13] + c.data[14]; c.data[12];
sum_3x3_subclusters[3] = c.data[5] + c.data[6] + c.data[7] + c.data[10] + c.data[11] + c.data[12] + c.data[15] + c.data[16] + c.data[17]; sum_3x3_subclusters[1] = c.data[1] + c.data[2] + c.data[3] + c.data[6] +
sum_3x3_subclusters[4] = c.data[6] + c.data[7] + c.data[8] + c.data[11] + c.data[12] + c.data[13] + c.data[16] + c.data[17] + c.data[18]; c.data[7] + c.data[8] + c.data[11] + c.data[12] +
sum_3x3_subclusters[5] = c.data[7] + c.data[8] + c.data[9] + c.data[12] + c.data[13] + c.data[14] + c.data[17] + c.data[18] + c.data[19]; c.data[13];
sum_3x3_subclusters[6] = c.data[10] + c.data[11] + c.data[12] + c.data[15] + c.data[16] + c.data[17] + c.data[20] + c.data[21] + c.data[22]; sum_3x3_subclusters[2] = c.data[2] + c.data[3] + c.data[4] + c.data[7] +
sum_3x3_subclusters[7] = c.data[11] + c.data[12] + c.data[13] + c.data[16] + c.data[17] + c.data[18] + c.data[21] + c.data[22] + c.data[23]; c.data[8] + c.data[9] + c.data[12] + c.data[13] +
sum_3x3_subclusters[8] = c.data[12] + c.data[13] + c.data[14] + c.data[17] + c.data[18] + c.data[19] + c.data[22] + c.data[23] + c.data[24]; c.data[14];
sum_3x3_subclusters[3] = c.data[5] + c.data[6] + c.data[7] + c.data[10] +
c.data[11] + c.data[12] + c.data[15] + c.data[16] +
c.data[17];
sum_3x3_subclusters[4] = c.data[6] + c.data[7] + c.data[8] + c.data[11] +
c.data[12] + c.data[13] + c.data[16] + c.data[17] +
c.data[18];
sum_3x3_subclusters[5] = c.data[7] + c.data[8] + c.data[9] + c.data[12] +
c.data[13] + c.data[14] + c.data[17] + c.data[18] +
c.data[19];
sum_3x3_subclusters[6] = c.data[10] + c.data[11] + c.data[12] + c.data[15] +
c.data[16] + c.data[17] + c.data[20] + c.data[21] +
c.data[22];
sum_3x3_subclusters[7] = c.data[11] + c.data[12] + c.data[13] + c.data[16] +
c.data[17] + c.data[18] + c.data[21] + c.data[22] +
c.data[23];
sum_3x3_subclusters[8] = c.data[12] + c.data[13] + c.data[14] + c.data[17] +
c.data[18] + c.data[19] + c.data[22] + c.data[23] +
c.data[24];
auto index = std::max_element(sum_3x3_subclusters.begin(), sum_3x3_subclusters.end()) - sum_3x3_subclusters.begin(); auto index = std::max_element(sum_3x3_subclusters.begin(),
sum_3x3_subclusters.end()) -
sum_3x3_subclusters.begin();
switch (index) { switch (index) {
case 0: case 0:
result.x = c.x - 1; result.x = c.x - 1;
result.y = c.y + 1; result.y = c.y + 1;
result.data = {c.data[0], c.data[1], c.data[2], c.data[5], c.data[6], c.data[7], c.data[10], c.data[11], c.data[12]}; result.data = {c.data[0], c.data[1], c.data[2], c.data[5], c.data[6],
break; c.data[7], c.data[10], c.data[11], c.data[12]};
case 1: break;
result.x = c.x; case 1:
result.y = c.y + 1; result.x = c.x;
result.data = {c.data[1], c.data[2], c.data[3], c.data[6], c.data[7], c.data[8], c.data[11], c.data[12], c.data[13]}; result.y = c.y + 1;
break; result.data = {c.data[1], c.data[2], c.data[3], c.data[6], c.data[7],
case 2: c.data[8], c.data[11], c.data[12], c.data[13]};
result.x = c.x + 1; break;
result.y = c.y + 1; case 2:
result.data = {c.data[2], c.data[3], c.data[4], c.data[7], c.data[8], c.data[9], c.data[12], c.data[13], c.data[14]}; result.x = c.x + 1;
break; result.y = c.y + 1;
case 3: result.data = {c.data[2], c.data[3], c.data[4], c.data[7], c.data[8],
result.x = c.x - 1; c.data[9], c.data[12], c.data[13], c.data[14]};
result.y = c.y; break;
result.data = {c.data[5], c.data[6], c.data[7], c.data[10], c.data[11], c.data[12], c.data[15], c.data[16], c.data[17]}; case 3:
break; result.x = c.x - 1;
case 4: result.y = c.y;
result.x = c.x + 1; result.data = {c.data[5], c.data[6], c.data[7],
result.y = c.y; c.data[10], c.data[11], c.data[12],
result.data = {c.data[6], c.data[7], c.data[8], c.data[11], c.data[12], c.data[13], c.data[16], c.data[17], c.data[18]}; c.data[15], c.data[16], c.data[17]};
break; break;
case 5: case 4:
result.x = c.x + 1; result.x = c.x + 1;
result.y = c.y; result.y = c.y;
result.data = {c.data[7], c.data[8], c.data[9], c.data[12], c.data[13], c.data[14], c.data[17], c.data[18], c.data[19]}; result.data = {c.data[6], c.data[7], c.data[8],
break; c.data[11], c.data[12], c.data[13],
case 6: c.data[16], c.data[17], c.data[18]};
result.x = c.x + 1; break;
result.y = c.y -1; case 5:
result.data = {c.data[10], c.data[11], c.data[12], c.data[15], c.data[16], c.data[17], c.data[20], c.data[21], c.data[22]}; result.x = c.x + 1;
break; result.y = c.y;
case 7: result.data = {c.data[7], c.data[8], c.data[9],
result.x = c.x + 1; c.data[12], c.data[13], c.data[14],
result.y = c.y-1; c.data[17], c.data[18], c.data[19]};
result.data = {c.data[11], c.data[12], c.data[13], c.data[16], c.data[17], c.data[18], c.data[21], c.data[22], c.data[23]}; break;
break; case 6:
case 8: result.x = c.x + 1;
result.x = c.x + 1; result.y = c.y - 1;
result.y = c.y-1; result.data = {c.data[10], c.data[11], c.data[12],
result.data = {c.data[12], c.data[13], c.data[14], c.data[17], c.data[18], c.data[19], c.data[22], c.data[23], c.data[24]}; c.data[15], c.data[16], c.data[17],
break; c.data[20], c.data[21], c.data[22]};
break;
case 7:
result.x = c.x + 1;
result.y = c.y - 1;
result.data = {c.data[11], c.data[12], c.data[13],
c.data[16], c.data[17], c.data[18],
c.data[21], c.data[22], c.data[23]};
break;
case 8:
result.x = c.x + 1;
result.y = c.y - 1;
result.data = {c.data[12], c.data[13], c.data[14],
c.data[17], c.data[18], c.data[19],
c.data[22], c.data[23], c.data[24]};
break;
} }
// do some stuff // do some stuff

View File

@@ -32,8 +32,7 @@ class ClusterVector; // Forward declaration
*/ */
template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY, template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
typename CoordType> typename CoordType>
class ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> class ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> {
{
std::vector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> m_data{}; std::vector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>> m_data{};
int32_t m_frame_number{0}; // TODO! Check frame number size and type int32_t m_frame_number{0}; // TODO! Check frame number size and type
@@ -173,17 +172,21 @@ class ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>
} }
}; };
template<typename T> template <typename T, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
ClusterVector<Cluster<T, 2, 2, uint16_t>> reduce_3x3_to_2x2(const ClusterVector<Cluster<T, 3, 3, uint16_t>> &cv) { typename CoordType>
ClusterVector<Cluster<T, 2, 2, uint16_t>> result; ClusterVector<Cluster<T, 2, 2, CoordType>> reduce_to_2x2(
const ClusterVector<Cluster<T, ClusterSizeX, ClusterSizeY, CoordType>>
&cv) {
ClusterVector<Cluster<T, 2, 2, CoordType>> result;
for (const auto &c : cv) { for (const auto &c : cv) {
result.push_back(reduce_3x3_to_2x2(c)); result.push_back(reduce_to_2x2(c));
} }
return result; return result;
} }
template<typename T> template <typename T>
ClusterVector<Cluster<T, 3, 3, uint16_t>> reduce_5x5_to_3x3(const ClusterVector<Cluster<T, 5, 5, uint16_t>> &cv) { ClusterVector<Cluster<T, 3, 3, uint16_t>>
reduce_5x5_to_3x3(const ClusterVector<Cluster<T, 5, 5, uint16_t>> &cv) {
ClusterVector<Cluster<T, 3, 3, uint16_t>> result; ClusterVector<Cluster<T, 3, 3, uint16_t>> result;
for (const auto &c : cv) { for (const auto &c : cv) {
result.push_back(reduce_5x5_to_3x3(c)); result.push_back(reduce_5x5_to_3x3(c));

View File

@@ -104,14 +104,23 @@ void define_ClusterVector(py::module &m, const std::string &typestr) {
}); });
} }
template <typename Type, uint8_t ClusterSizeX, uint8_t ClusterSizeY,
typename CoordType = uint16_t>
void define_reduction(py::module &m) { void define_reduction(py::module &m) {
m.def("reduce_3x3_to_2x2", [](const ClusterVector<Cluster<int, 3, 3, uint16_t>> &cv) { m.def("reduce_to_2x2",
return new ClusterVector<Cluster<int, 2, 2, uint16_t>>(reduce_3x3_to_2x2(cv)); [](const ClusterVector<
// return new ClusterVector<Cluster<int, 3, 3>>(); Cluster<Type, ClusterSizeX, ClusterSizeY, CoordType>> &cv) {
}) return new ClusterVector<Cluster<Type, 2, 2, CoordType>>(
.def("reduce_5x5_to_3x3", [](const ClusterVector<Cluster<int, 5, 5, uint16_t>> &cv) { reduce_to_2x2(cv));
return new ClusterVector<Cluster<int, 3, 3, uint16_t>>(reduce_5x5_to_3x3(cv)); });
}); }
void define_3x3_reduction(py::module &m) {
m.def("reduce_5x5_to_3x3",
[](const ClusterVector<Cluster<int, 5, 5, uint16_t>> &cv) {
return new ClusterVector<Cluster<int, 3, 3, uint16_t>>(
reduce_5x5_to_3x3(cv));
});
} }
#pragma GCC diagnostic pop #pragma GCC diagnostic pop

View File

@@ -47,7 +47,8 @@ double, 'f' for float)
define_ClusterFileSink<T, N, M, U>(m, "Cluster" #N "x" #M #TYPE_CODE); \ define_ClusterFileSink<T, N, M, U>(m, "Cluster" #N "x" #M #TYPE_CODE); \
define_ClusterCollector<T, N, M, U>(m, "Cluster" #N "x" #M #TYPE_CODE); \ define_ClusterCollector<T, N, M, U>(m, "Cluster" #N "x" #M #TYPE_CODE); \
define_Cluster<T, N, M, U>(m, #N "x" #M #TYPE_CODE); \ define_Cluster<T, N, M, U>(m, #N "x" #M #TYPE_CODE); \
register_calculate_eta<T, N, M, U>(m); register_calculate_eta<T, N, M, U>(m); \
define_reduction<T, N, M, U>(m);
PYBIND11_MODULE(_aare, m) { PYBIND11_MODULE(_aare, m) {
define_file_io_bindings(m); define_file_io_bindings(m);
@@ -85,7 +86,5 @@ PYBIND11_MODULE(_aare, m) {
DEFINE_CLUSTER_BINDINGS(double, 9, 9, uint16_t, d); DEFINE_CLUSTER_BINDINGS(double, 9, 9, uint16_t, d);
DEFINE_CLUSTER_BINDINGS(float, 9, 9, uint16_t, f); DEFINE_CLUSTER_BINDINGS(float, 9, 9, uint16_t, f);
define_3x3_reduction(m);
define_reduction(m);
} }

View File

@@ -18,4 +18,46 @@ TEST_CASE("Test sum of Cluster", "[.cluster]") {
Cluster<int, 2, 2> cluster{0, 0, {1, 2, 3, 4}}; Cluster<int, 2, 2> cluster{0, 0, {1, 2, 3, 4}};
CHECK(cluster.sum() == 10); CHECK(cluster.sum() == 10);
}
using ClusterTypes = std::variant<Cluster<int, 2, 2>, Cluster<int, 3, 3>,
Cluster<int, 5, 5>, Cluster<int, 2, 3>>;
TEST_CASE("Test reduce to 2x2 Cluster", "[.cluster]") {
auto [cluster, expected_reduced_cluster] = GENERATE(
std::make_tuple(ClusterTypes{Cluster<int, 2, 2>{5, 5, {1, 2, 3, 4}}},
Cluster<int, 2, 2>{4, 6, {1, 2, 3, 4}}),
std::make_tuple(
ClusterTypes{Cluster<int, 3, 3>{5, 5, {1, 1, 1, 1, 3, 2, 1, 2, 2}}},
Cluster<int, 2, 2>{5, 5, {3, 2, 2, 2}}),
std::make_tuple(
ClusterTypes{Cluster<int, 3, 3>{5, 5, {1, 1, 1, 2, 3, 1, 2, 2, 1}}},
Cluster<int, 2, 2>{4, 5, {2, 3, 2, 2}}),
std::make_tuple(
ClusterTypes{Cluster<int, 3, 3>{5, 5, {2, 2, 1, 2, 3, 1, 1, 1, 1}}},
Cluster<int, 2, 2>{4, 6, {2, 2, 2, 3}}),
std::make_tuple(
ClusterTypes{Cluster<int, 3, 3>{5, 5, {1, 2, 2, 1, 3, 2, 1, 1, 1}}},
Cluster<int, 2, 2>{5, 6, {2, 2, 3, 2}}),
std::make_tuple(ClusterTypes{Cluster<int, 5, 5>{
5, 5, {1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 3,
2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}},
Cluster<int, 2, 2>{5, 6, {2, 2, 3, 2}}),
std::make_tuple(ClusterTypes{Cluster<int, 5, 5>{
5, 5, {1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 3,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}},
Cluster<int, 2, 2>{4, 6, {2, 2, 2, 3}}),
std::make_tuple(
ClusterTypes{Cluster<int, 2, 3>{5, 5, {2, 2, 3, 2, 1, 1}}},
Cluster<int, 2, 2>{4, 6, {2, 2, 3, 2}}));
auto reduced_cluster = std::visit(
[](const auto &clustertype) { return reduce_to_2x2(clustertype); },
cluster);
CHECK(reduced_cluster.x == expected_reduced_cluster.x);
CHECK(reduced_cluster.y == expected_reduced_cluster.y);
CHECK(std::equal(reduced_cluster.data.begin(),
reduced_cluster.data.begin() + 4,
expected_reduced_cluster.data.begin()));
} }