MeshLib C++ Docs
Loading...
Searching...
No Matches
MRUnionFind.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRVector.h"
4#include "MRTimer.h"
5#include "MRId.h"
6#include <atomic>
7#include <utility>
8
9namespace MR
10{
13
14
21template <typename I>
23{
24public:
26 using SizeType = typename I::ValueType;
27
28 BaseUnionFind() = default;
29 BaseUnionFind( const BaseUnionFind & ) = default;
30 BaseUnionFind( BaseUnionFind && ) noexcept = default;
31 BaseUnionFind & operator =( const BaseUnionFind & ) = default;
32 BaseUnionFind & operator =( BaseUnionFind && ) noexcept = default;
33
35 auto size() const { return parents_.size(); }
36
38 void reset( size_t size )
39 {
41 parents_.clear();
42 parents_.reserve( size );
43 for ( I i{ size_t( 0 ) }; i < size; ++i )
44 parents_.push_back( i );
45 }
46
51 std::pair<I, bool> uniteUnbalanced( I first, I second )
52 {
53 auto firstRoot = updateRoot_( first );
54 auto secondRoot = updateRoot_( second );
55 if ( firstRoot == secondRoot )
56 return { firstRoot, false };
57 parents_[firstRoot] = secondRoot;
58 return { secondRoot, true };
59 }
60
62 bool united( I first, I second )
63 {
64 return updateRoot_( first ) == updateRoot_( second );
65 }
66
68 bool isRoot( I a ) const { return parents_[a] == a; }
69
71 I parent( I a ) const { return parents_[a]; }
72
74 I find( I a ) { return updateRoot_( a ); }
75
78 {
80 }
81
84 {
85 for ( I i{ size_t( 0 ) }; i < parents_.size(); ++i )
87 return parents_;
88 }
89
91 const Vector<I, I> & parents() const { return parents_; }
92
93protected:
96 {
97 I r = parents_[a];
98 for ( I e = a; e != r; r = parents_[e = r] ) {}
99 return r;
100 }
101
103 I updateRoot_( I a, const I r )
104 {
106 while ( a != r )
107 {
108 I b = r;
109 std::swap( parents_[a], b );
110 a = b;
111 }
112 return r;
113 }
114
116 I updateRoot_( I a ) { return updateRoot_( a, findRootNoUpdate_( a ) ); }
117
119 I updateRootInRange_( I a, const I r, I begin, I end )
120 {
121 assert( begin < end );
123 while ( a != r )
124 {
125 if ( a >= begin && a < end )
126 {
127 I b = r;
128 std::swap( parents_[a], b );
129 a = b;
130 }
131 else
132 a = parents_[a];
133 }
134 return r;
135 }
136
139};
140
150template <typename I>
151class UnionFind : public BaseUnionFind<I>
152{
153public:
155 using SizeType = typename I::ValueType;
156
157 UnionFind() = default;
158
160 explicit UnionFind( size_t size ) { reset( size ); }
161
164 explicit UnionFind( BaseUnionFind<I> && base ) : BaseUnionFind<I>( std::move( base ) )
165 {
166 sizes_.resize( this->parents_.size(), SizeType( 0 ) );
167 for ( I i{ size_t( 0 ) }; i < this->parents_.size(); ++i )
168 ++sizes_[ this->findRootNoUpdate_( i ) ];
169 }
170
172 void reset( size_t size )
173 {
175 sizes_.clear();
176 sizes_.resize( size, 1 );
177 }
178
181 std::pair<I,bool> unite( I first, I second )
182 {
183 auto firstRoot = this->updateRoot_( first );
184 auto secondRoot = this->updateRoot_( second );
185 if ( firstRoot == secondRoot )
186 return { firstRoot, false };
188 if ( sizes_[firstRoot] < sizes_[secondRoot] )
189 {
190 this->parents_[firstRoot] = secondRoot;
191 sizes_[secondRoot] += sizes_[firstRoot];
192 return { secondRoot, true };
193 }
194 else
195 {
196 this->parents_[secondRoot] = firstRoot;
197 sizes_[firstRoot] += sizes_[secondRoot];
198 return { firstRoot, true };
199 }
200 }
201
203 SizeType sizeOfComp( I a ) { return sizes_[ this->find( a ) ]; }
204
205private:
207 Vector<SizeType, I> sizes_;
208};
209
217template <typename I>
219{
220public:
221 ParallelUnionFind() = default;
222
224 explicit ParallelUnionFind( size_t size ) { this->reset( size ); }
225
228 void uniteAtomic( I first, I second )
229 {
230 for ( ;; )
231 {
232 first = findAtomic_( first );
233 second = findAtomic_( second );
234 if ( first == second )
235 return;
237 if ( first < second )
238 std::swap( first, second );
240 if ( casStrong_( this->parents_[first], first, second ) )
241 return;
243 }
244 }
245
246private:
250
252 static I loadAtomic_( I& slot )
253 {
254#ifdef __cpp_lib_atomic_ref
255 return I( std::atomic_ref<typename I::ValueType>( slot.get() ).load( std::memory_order_relaxed ) );
256#else
257 return I( __atomic_load_n( &slot.get(), __ATOMIC_RELAXED ) );
258#endif
259 }
260
262 static void casWeak_( I& slot, I expected, I desired )
263 {
264 using T = typename I::ValueType;
265 T exp = expected.get();
266#ifdef __cpp_lib_atomic_ref
267 std::atomic_ref<T>( slot.get() ).compare_exchange_weak( exp, desired.get(), std::memory_order_relaxed );
268#else
269 __atomic_compare_exchange_n( &slot.get(), &exp, desired.get(), true, __ATOMIC_RELAXED, __ATOMIC_RELAXED );
270#endif
271 }
272
274 static bool casStrong_( I& slot, I expected, I desired )
275 {
276 using T = typename I::ValueType;
277 T exp = expected.get();
278#ifdef __cpp_lib_atomic_ref
279 return std::atomic_ref<T>( slot.get() ).compare_exchange_strong( exp, desired.get(), std::memory_order_acq_rel, std::memory_order_relaxed );
280#else
281 return __atomic_compare_exchange_n( &slot.get(), &exp, desired.get(), false, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED );
282#endif
283 }
284
286 I findAtomic_( I a )
287 {
288 for ( ;; )
289 {
290 I p = loadAtomic_( this->parents_[a] );
291 if ( p == a )
292 return a;
293 I gp = loadAtomic_( this->parents_[p] );
294 if ( p == gp )
295 return p;
297 casWeak_( this->parents_[a], p, gp );
298 a = gp;
299 }
300 }
301};
302
306template<typename T>
307static std::pair<Vector<RegionId, Id<T>>, int> getUniqueRootIds( const Vector<Id<T>, Id<T>>& allRoots, const TaggedBitSet<T>& region )
308{
309 MR_TIMER;
310 Vector<RegionId, Id<T>> uniqueRootsMap( allRoots.size() );
311 int k = 0;
312 for ( auto f : region )
313 {
314 auto& uniqIndex = uniqueRootsMap[allRoots[f]];
315 if ( uniqIndex < 0 )
316 {
317 uniqIndex = RegionId( k );
318 ++k;
319 }
320 uniqueRootsMap[f] = uniqIndex;
321 }
322 return { std::move( uniqueRootsMap ), k };
323}
324
325}
#define MR_TIMER
FUNCTION in GCC/Clang returns only short function name without class name and template parameters
Definition MRTimer.h:56
stores index of some element, it is made as template class to avoid mixing faces, edges and vertices
Definition MRId.h:20
std::vector<T>-like container that requires specific indexing type,
Definition MRVector.h:23
SizeType sizeOfComp(I a)
returns the number of elements in the set containing given element
Definition MRUnionFind.h:203
std::pair< I, bool > unite(I first, I second)
Definition MRUnionFind.h:181
I updateRootInRange_(I a, const I r, I begin, I end)
sets new root
Definition MRUnionFind.h:119
ParallelUnionFind(size_t size)
creates union-find with given number of elements, each element is the only one in its disjoint set
Definition MRUnionFind.h:224
BaseUnionFind(BaseUnionFind &&) noexcept=default
BaseUnionFind()=default
I updateRoot_(I a, const I r)
sets new root
Definition MRUnionFind.h:103
auto size() const
returns the number of elements in union-find
Definition MRUnionFind.h:35
bool isRoot(I a) const
returns true if given element is the root of some set
Definition MRUnionFind.h:68
const Vector< I, I > & parents() const
gets the parents of all elements as is
Definition MRUnionFind.h:91
std::pair< I, bool > uniteUnbalanced(I first, I second)
Definition MRUnionFind.h:51
I updateRoot_(I a)
find the root of given element, and set it as parent for it and other parents
Definition MRUnionFind.h:116
const Vector< I, I > & roots()
sets the root of corresponding set as the parent of each element, then returns the vector
Definition MRUnionFind.h:83
ParallelUnionFind()=default
UnionFind(BaseUnionFind< I > &&base)
Definition MRUnionFind.h:164
UnionFind(size_t size)
creates union-find with given number of elements, each element is the only one in its disjoint set
Definition MRUnionFind.h:160
UnionFind()=default
BaseUnionFind(const BaseUnionFind &)=default
void reset(size_t size)
resets union-find to represent given number of elements, each element is the only one in its disjoint...
Definition MRUnionFind.h:172
class MRMESH_CLASS I
Definition MRMeshFwd.h:141
bool united(I first, I second)
returns true if given two elements are from one set
Definition MRUnionFind.h:62
TypedBitSet< Id< T > > TaggedBitSet
Definition MRMeshFwd.h:174
I find(I a)
finds the root of the set containing given element with optimizing data structure updates
Definition MRUnionFind.h:74
typename I::ValueType SizeType
the type that can hold the number of elements of the maximal set (e.g. int for FaceId and size_t for ...
Definition MRUnionFind.h:26
void uniteAtomic(I first, I second)
Definition MRUnionFind.h:228
I parent(I a) const
return parent element of this element, which is equal to given element only for set's root
Definition MRUnionFind.h:71
typename I::ValueType SizeType
the type that can hold the number of elements of the maximal set (e.g. int for FaceId and size_t for ...
Definition MRUnionFind.h:155
Vector< I, I > parents_
parent element of each element
Definition MRUnionFind.h:138
I findRootNoUpdate_(I a) const
finds the root of the set containing given element without optimizing data structure updates
Definition MRUnionFind.h:95
I findUpdateRange(I a, I begin, I end)
finds the root of the set containing given element with optimizing data structure in the range [begin...
Definition MRUnionFind.h:77
void reset(size_t size)
resets union-find to represent given number of elements, each element is the only one in its disjoint...
Definition MRUnionFind.h:38
auto begin(ViewportMask mask)
Definition MRViewportId.h:122
auto end(ViewportMask)
Definition MRViewportId.h:124
only for bindings generation
Definition MRCameraOrientationPlugin.h:8