Mantid
Loading...
Searching...
No Matches
ClusterRegister.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
10#include <boost/functional/hash.hpp>
11#include <list>
12#include <memory>
13#include <unordered_set>
14
15namespace {
16template <typename T> std::pair<T, T> ordered_pair(const T &a, const T &b) {
17 T min = std::min(a, b);
18 T max = std::max(a, b);
19 return std::pair<T, T>(min, max);
20}
21} // namespace
22
23namespace Mantid::Crystal {
24
26public:
29
32
34 using GroupType = std::list<std::unordered_set<size_t>>;
35
38
40 using LabelHash = std::unordered_set<size_t>;
41
44
46 boost::hash<std::pair<int, int>> m_labelHasher;
47
55 bool insert(const DisjointElement &a, const DisjointElement &b) {
56 const size_t &aLabel = a.getRoot();
57 const size_t &bLabel = b.getRoot();
58 bool newItem = true;
59
60 GroupType containingAny;
61 GroupType containingNone;
62 // ------------- Find equivalent sets
63 for (auto &cluster : m_groups) {
64 if (cluster.find(aLabel) != cluster.end()) {
65 containingAny.emplace_back(cluster);
66 } else if (cluster.find(bLabel) != cluster.end()) {
67 containingAny.emplace_back(cluster);
68 } else {
69 containingNone.emplace_back(cluster); // Current iterated set contains
70 // NEITHER of these labels. It can
71 // therfore be ignored.
72 }
73 }
74 // ------------ Process equivalent sets
75 if (containingAny.empty()) {
76 // Neither label is yet known to any set. We must add a new set for these
77 GroupType::value_type newSet;
78 newSet.insert(aLabel);
79 newSet.insert(bLabel);
80 m_groups.emplace_back(newSet);
81 } else {
82 // At least one set already contains at least one label. We merge all such
83 // sets into a master set.
84
85 // implement copy and swap. Rebuild the sets.
86 GroupType temp = containingNone;
87 GroupType::value_type masterSet;
88 masterSet.insert(aLabel); // Incase it doesn't already contain a
89 masterSet.insert(bLabel); // Incase it doesn't already contain b
90 for (auto &childSet : containingAny) {
91 masterSet.insert(childSet.begin(),
92 childSet.end()); // Build the master set.
93 }
94 temp.emplace_back(masterSet);
95 m_groups = temp; // Swap.
96 newItem = false;
97 }
98 return newItem;
99 }
100
105 std::list<std::shared_ptr<CompositeCluster>> makeCompositeClusters() {
106 std::list<std::shared_ptr<CompositeCluster>> composites;
107 for (auto &labelSet : m_groups) {
108 auto composite = std::make_shared<CompositeCluster>();
109 for (auto j : labelSet) {
110 std::shared_ptr<ICluster> &cluster = m_register[j];
111 composite->add(cluster);
112 }
113 composites.emplace_back(composite);
114 }
115 return composites;
116 }
117};
118
119//----------------------------------------------------------------------------------------------
123
127
133void ClusterRegister::add(const size_t &label, const std::shared_ptr<ICluster> &cluster) {
134 m_Impl->m_register.emplace(label, cluster);
135 m_Impl->m_unique.emplace(label, cluster);
136}
137
144 if (!a.isEmpty() && !b.isEmpty()) {
145 const int &aId = a.getId();
146 const int &bId = b.getId();
147
148 size_t hash = m_Impl->m_labelHasher(ordered_pair(aId, bId));
149 if (m_Impl->m_labelHash.find(hash) == m_Impl->m_labelHash.end()) // Only if this pair combination has not
150 // already been processed
151 {
152 m_Impl->insert(a, b);
153 m_Impl->m_unique.erase(aId);
154 m_Impl->m_unique.erase(bId);
155 m_Impl->m_labelHash.insert(hash); // So that we don't process this pair again.
156 }
157 }
158}
159
165 MapCluster temp;
166 temp.insert(m_Impl->m_unique.begin(), m_Impl->m_unique.end());
167 auto mergedClusters = m_Impl->makeCompositeClusters();
168 for (const auto &merged : mergedClusters) {
169 temp.emplace(merged->getLabel(), merged);
170 }
171 return temp;
172}
173
180ClusterRegister::MapCluster ClusterRegister::clusters(std::vector<DisjointElement> &elements) const {
181 MapCluster temp;
182 temp.insert(m_Impl->m_unique.begin(), m_Impl->m_unique.end());
183 auto mergedClusters = m_Impl->makeCompositeClusters();
184 for (auto &merged : mergedClusters) {
185 merged->toUniformMinimum(elements);
186 temp.emplace(merged->getLabel(), merged);
187 }
188 return temp;
189}
190
191} // namespace Mantid::Crystal
void add(const size_t &label, const std::shared_ptr< ICluster > &cluster)
Add clusters.
MapCluster clusters() const
Get all combined clusters.
std::map< size_t, std::shared_ptr< ICluster > > MapCluster
Cluster map.
virtual ~ClusterRegister()
Destructor.
boost::scoped_ptr< ImplClusterRegister > m_Impl
Pointer to implementation.
void merge(const DisjointElement &a, const DisjointElement &b) const
Merge clusters on the basis of known pairs of disjoint elements.
DisjointElement : Cluster item used in a disjoint-set data structure.
int getRoot() const
Get root id.
GroupType m_groups
Groups of labels to maintain.
boost::hash< std::pair< int, int > > m_labelHasher
Label hasher.
bool insert(const DisjointElement &a, const DisjointElement &b)
Inserts a pair of disjoint elements.
ClusterRegister::MapCluster m_unique
Clusters that do not need merging.
LabelHash m_labelHash
Hash of labels merged.
std::unordered_set< size_t > LabelHash
Type for identifying labels already seen.
std::list< std::shared_ptr< CompositeCluster > > makeCompositeClusters()
Make composite clusters from the merged groups.
ClusterRegister::MapCluster m_register
All registered input clusters.
std::list< std::unordered_set< size_t > > GroupType
Type for identifying label groups.