R3BROOT
R3B analysis software
Loading...
Searching...
No Matches
ClusteringEngine.h
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) 2019 GSI Helmholtzzentrum für Schwerionenforschung GmbH *
3 * Copyright (C) 2019-2025 Members of R3B Collaboration *
4 * *
5 * This software is distributed under the terms of the *
6 * GNU General Public Licence (GPL) version 3, *
7 * copied verbatim in the file "LICENSE". *
8 * *
9 * In applying this license GSI does not waive the privileges and immunities *
10 * granted to it by virtue of its status as an Intergovernmental Organization *
11 * or submit itself to any jurisdiction. *
12 ******************************************************************************/
13
14#ifndef NEULANDCLUSTERINGENGINEH
15#define NEULANDCLUSTERINGENGINEH
16
17#include <algorithm>
18#include <functional>
19#include <vector>
20
21namespace Neuland
22{
23
24 template <typename T>
26 {
27 using Tit = typename std::vector<T>::iterator;
28 using BinaryPredicate = std::function<bool(const T&, const T&)>;
29
30 private:
31 BinaryPredicate f;
32
33 /* Partitions an already divided range by clustering both the items in the first part AND the items added to the
34 * first part during this process with the items in the second part.
35 * Takes the begin of a range of interest that acts as reference/seed, the end of that range which is the
36 * divider to the range to be analyzed, the end of the container, and the clustering function.
37 * Returns the new divider between cluster and non-cluster */
38 Tit moving_partition(const Tit begin, Tit moving_divider, const Tit end) const
39 {
40 // The end of the iteration will change if matching objects are found, such that these will be iterated over
41 // as well
42 for (Tit a = begin; a != moving_divider; a++)
43 {
44 // Partition returns iterator to the first element of the non-clustered rest of the container
45 moving_divider = std::partition(moving_divider, end, [&](const T& b) { return f(*a, b); });
46 }
47 return moving_divider;
48 }
49
50 public:
51 /* Default Constructor. Note: If the clustering condition is not set, a "bad_function_call" will be thrown upon
52 * calling clusterize. This seems better than providing a default function which might produce hard-to-track
53 * unwanted results. */
54 ClusteringEngine() = default;
55 ClusteringEngine(const BinaryPredicate& _f)
56 : f(_f)
57 {
58 }
59
60 void SetClusteringCondition(const BinaryPredicate& _f) { f = _f; }
61
62 bool SatisfiesClusteringCondition(const T& a, const T& b) const { return f(a, b); }
63
64 std::vector<std::vector<T>> Clusterize(std::vector<T>& from) const
65 {
66 std::vector<std::vector<T>> out;
67
68 /* Three iterators (read: markers for positions in the input vector) are required:
69 * Begin is the start of the clustered part of the vector
70 * Divider separates the clustered part from the unclustered part, and
71 * end is the end of the vector*/
72 Tit begin;
73 Tit divider = from.begin();
74 const Tit end = from.end();
75
76 /* While the end of the input vector has not been reached, start a new cluster containing one element from
77 * the unclustered part and then move all objects that match the clustering condition in that range.
78 * This part of the input vector can then be move-constructed into a new vector = cluster */
79 while (divider != end)
80 {
81 begin = divider;
82 divider++;
83 divider = moving_partition(begin, divider, end);
84 out.push_back(
85 std::move(std::vector<T>(std::make_move_iterator(begin), std::make_move_iterator(divider))));
86 }
87 return out;
88 }
89 };
90
91}; // namespace Neuland
92
93#endif // NEULANDCLUSTERINGENGINEH
void SetClusteringCondition(const BinaryPredicate &_f)
bool SatisfiesClusteringCondition(const T &a, const T &b) const
std::vector< std::vector< T > > Clusterize(std::vector< T > &from) const
ClusteringEngine(const BinaryPredicate &_f)
Simulation of NeuLAND Bar/Paddle.