NDEVR
API Documentation
TreeSorter.h
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Tree
28File: TreeSorter
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/Buffer.h>
34#include <NDEVR/Vector.h>
35#include <NDEVR/Bounds.h>
36#include <NDEVR/Median.h>
37#include <NDEVR/TypeInfo.h>
38#include <NDEVR/Dictionary.h>
39#include <NDEVR/InfoPipe.h>
40#include <NDEVR/StringView.h>
41#include <algorithm>
42
43#include <NDEVR/OpenMP.h>
44#ifdef _WIN32
45 #include <execution>
46#endif
47#if NDEVR_SUPPORTS_THREADING
48#define TREE_SORTER_USE_THREAD 0
49#ifdef TREE_SORTER_USE_THREAD
50 #include <NDEVR/BasicThread.h>
51#endif
52#else
53#define TREE_SORTER_USE_THREAD 0
54#endif
55namespace NDEVR
56{
60 template<uint01 t_dims, class t_type>
62 {
63 public:
70 void getList(uint01 dimension, uint04 start, uint04 end, Buffer<uint04>& values, uint04 index_offset)
71 {
72 uint04 size = end - start;
73 values.setAll(center_ordered[dimension], index_offset, start, size);
74 }
75 protected:
82 static void _sortList(const Buffer<bool>& list_sorter, Buffer<uint04>& list, Buffer<uint04>& temp, uint04 start, uint04 end)
83 {
84 temp.clear();
85 temp.setSize(end - start);
86 uint04 temp_location = 0;
87 uint04 left_location = start;
88 for (uint04 i = start; i < end; i++)
89 {
90 if (list_sorter[list[i]])
91 {
92 list[left_location++] = list[i];
93 }
94 else
95 {
96 temp[temp_location++] = list[i];
97 }
98 }
99 list.setAll(temp, left_location, temp_location);
100
101 }
102 protected:
106 };
107
111 template<uint01 t_dims, class t_type>
112 class TreeBoundarySorter : public TreeSorterBase<t_dims, t_type>
113 {
114 public:
118 template<bool t_has_nans, class t_list_type>
119 void createCenterSortList(const Buffer<uint04>& indices, const t_list_type& locations)
120 {
121 uint04 size = indices.size();
122 TreeSorterBase<t_dims, t_type>::temp_memory.setSize(locations.size());
123 TreeSorterBase<t_dims, t_type>::temp_array.ensureCapacity((size / 2) + 1);
125
126 for(uint04 i = 0; i < size; i++)
127 {
129 }
130 m_uses_boundary = false;
131 for (uint01 dimension = 1; dimension < t_dims; ++dimension)
133 for (uint01 dimension = 0; dimension < t_dims; ++dimension)
134 sortList<t_has_nans>(dimension, locations, Buffer<Bounds<t_dims, t_type>>());
135 }
136
139 template<bool t_has_nans, class t_list_type>
140 void createBoundarySortList(const Buffer<uint04>& indices, const t_list_type& locations)
141 {
142 uint04 size = indices.size();
143 TreeSorterBase<t_dims, t_type>::temp_memory.setSize(locations.size());
144 TreeSorterBase<t_dims, t_type>::temp_array.ensureCapacity((size / 2) + 1);
146
149 centers.setSize(locations.size());
150 bounds.setSize(locations.size());
151 memmove(TreeSorterBase<t_dims, t_type>::center_ordered[0].begin(), indices.begin(), size * sizeof(uint04));
152 m_uses_boundary = true;
153 for (uint04 i = 0; i < locations.size(); i++)
154 {
155 auto value = locations[i].template as<t_dims, t_type>();
156 centers[i] = value.center();
157 bounds[i] = Bounds<t_dims, t_type>(value);
158 lib_assert(IsInvalid(centers[i]) || bounds[i].contains(centers[i]), "Tree Sorter: Bounds did not contain center");
159 }
160 for (uint01 dimension = 1; dimension < t_dims; ++dimension)
162 for (uint01 dimension = 0; dimension < t_dims; ++dimension)
163 sortList<t_has_nans>(dimension, centers, bounds);
164 }
165
168 template<bool t_has_nans, class t_list_type>
169 void createHashSortList(const Buffer<uint04>& indices, const t_list_type& locations)
170 {
171 uint04 size = indices.size();
173 TreeSorterBase<t_dims, t_type>::temp_array.ensureCapacity((size / 2) + 1);
175
178 for (uint04 i = 0; i < size; i++)
179 {
181 }
182 m_uses_boundary = true;
183 for (uint04 i = 0; i < indices.size(); i++)
184 {
185 auto value = locations[indices[i]].template as<t_dims, t_type>();
186 centers[indices[i]] = value.center();
187 bounds[indices[i]] = Bounds<t_dims, t_type>(value);
188 }
189 for (uint01 dimension = 1; dimension < t_dims; ++dimension)
191 for (uint01 dimension = 0; dimension < t_dims; ++dimension)
192 {
193 sortList<t_has_nans>(dimension, centers, bounds);
194 }
195 }
196
200 template<bool t_has_nans, class t_center_buffer, class t_bounds_buffer>
201 void sortList(uint01 dimension, const t_center_buffer& centers, const t_bounds_buffer& bounds)
202 {
203#ifdef _WIN32
204 std::sort(std::execution::par_unseq, TreeSorterBase<t_dims, t_type>::center_ordered[dimension].begin(), TreeSorterBase<t_dims, t_type>::center_ordered[dimension].end(), [&centers, dimension](uint04 a, uint04 b)
205#else
206 std::sort(TreeSorterBase<t_dims, t_type>::center_ordered[dimension].begin(), TreeSorterBase<t_dims, t_type>::center_ordered[dimension].end(), [&centers, dimension](uint04 a, uint04 b)
207#endif
208 {
209 const auto a_val = centers[a][dimension];
210 const auto b_val = centers[b][dimension];
211 if(t_has_nans)
212 {
213 if (IsInvalid(a_val) != IsInvalid(b_val))
214 return IsInvalid(a_val);
215 }
216 return (a_val < b_val);
217 });
218 if (m_uses_boundary)
219 {
222#ifdef _WIN32
223 std::sort(std::execution::par_unseq, min_ordered[dimension].begin(), min_ordered[dimension].end(), [&bounds, dimension](uint04 a, uint04 b)
224#else
225 std::sort(min_ordered[dimension].begin(), min_ordered[dimension].end(), [&bounds, dimension](uint04 a, uint04 b)
226#endif
227 {
228 const auto& a_val = bounds[a][MIN][dimension];
229 const auto& b_val = bounds[b][MIN][dimension];
230 if constexpr (t_has_nans)
231 {
232 if (IsInvalid(a_val) != IsInvalid(b_val))
233 return IsInvalid(a_val);
234 }
235 return (a_val < b_val);
236 });
237#ifdef _WIN32
238 std::sort(std::execution::par_unseq, max_ordered[dimension].begin(), max_ordered[dimension].end(), [&bounds, dimension](uint04 a, uint04 b)
239#else
240 std::sort(max_ordered[dimension].begin(), max_ordered[dimension].end(), [&bounds, dimension](uint04 a, uint04 b)
241#endif
242 {
243 auto a_val = bounds[a][MAX][dimension];
244 auto b_val = bounds[b][MAX][dimension];
245 if constexpr (t_has_nans)
246 {
247 if (IsInvalid(a_val) != IsInvalid(b_val))
248 return IsInvalid(a_val);
249 }
250 return (a_val < b_val);
251 });
252 }
253 }
254
255
261 template<class t_list_type>
262 Bounds<t_dims, t_type> getBounds(uint04 start, uint04 finish, const t_list_type& locations) const
263 {
265 if (m_uses_boundary)
266 {
267 for (uint01 dim = 0; dim < t_dims; ++dim)
268 {
269 box[MIN][dim] = Bounds<t_dims, t_type>(locations[min_ordered[dim][start]].template as<t_dims, t_type>())[MIN][dim];
270 box[MAX][dim] = Bounds<t_dims, t_type>(locations[max_ordered[dim][finish - 1]].template as<t_dims, t_type>())[MAX][dim];
271 }
272 }
273 else
274 {
275 for (uint01 dim = 0; dim < t_dims; ++dim)
276 {
277 box[MIN][dim] = locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][start]].template as<t_dims, t_type>().center()[dim];
278 box[MAX][dim] = locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][finish - 1]].template as<t_dims, t_type>().center()[dim];
279 }
280 }
281 return box;
282 }
283
289 template<class t_list_type>
290 Vector<2, Bounds<t_dims, t_type>> getMedianBounds(uint01 dimension, uint04 start, uint04 end, const t_list_type& locations)
291 {
292 Vector<2, Bounds<t_dims, t_type>> bounds;//The bounds on each side of the median
293 const uint04 median_location = ((end - start) / 2) + start;
294 for(uint04 i = start; i < median_location; ++i)
295 {
297 }
298 for (uint04 i = median_location; i < end; ++i)
299 {
301 }
302 for (uint01 dim = 0; dim < t_dims; ++dim)
303 {
304 if (m_uses_boundary)
305 {
307 {
308 bounds[0][MIN][dim] = Bounds<t_dims, t_type>(locations[min_ordered[dim][start]].template as<t_dims, t_type>())[MIN][dim];
309 for (uint04 n = start + 1; n < end; ++n)
310 {
312 {
313 bounds[1][MIN][dim] = Bounds<t_dims, t_type>(locations[min_ordered[dim][n]].template as<t_dims, t_type>())[MIN][dim];
314 break;
315 }
316 }
317 }
318 else
319 {
320 bounds[1][MIN][dim] = Bounds<t_dims, t_type>(locations[min_ordered[dim][start]].template as<t_dims, t_type>())[MIN][dim];
321 for (uint04 n = start + 1; n < end; ++n)
322 {
324 {
325 bounds[0][MIN][dim] = Bounds<t_dims, t_type>(locations[min_ordered[dim][n]].template as<t_dims, t_type>())[MIN][dim];
326 break;
327 }
328 }
329 }
331 {
332 bounds[0][MAX][dim] = Bounds<t_dims, t_type>(locations[max_ordered[dim][end - 1]].template as<t_dims, t_type>())[MAX][dim];
333 for (uint04 n = end - 2; n >= start && IsValid(n); --n)
334 {
336 {
337 bounds[1][MAX][dim] = Bounds<t_dims, t_type>(locations[max_ordered[dim][n]].template as<t_dims, t_type>())[MAX][dim];
338 break;
339 }
340 }
341 }
342 else
343 {
344 bounds[1][MAX][dim] = Bounds<t_dims, t_type>(locations[max_ordered[dim][end - 1]].template as<t_dims, t_type>())[MAX][dim];
345 for (uint04 n = end - 2; n >= start && IsValid(n); --n)
346 {
348 {
349 bounds[0][MAX][dim] = Bounds<t_dims, t_type>(locations[max_ordered[dim][n]].template as<t_dims, t_type>())[MAX][dim];
350 break;
351 }
352 }
353 }
354 }
355 else
356 {
358 {
359 bounds[0][MIN][dim] = Bounds<t_dims, t_type>(locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][start]].template as<t_dims, t_type>())[MIN][dim];
360 for (uint04 n = start + 1; n < end; ++n)
361 {
363 {
364 bounds[1][MIN][dim] = Bounds<t_dims, t_type>(locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][n]].template as<t_dims, t_type>())[MIN][dim];
365 break;
366 }
367 }
368 }
369 else
370 {
371 bounds[1][MIN][dim] = Bounds<t_dims, t_type>(locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][start]].template as<t_dims, t_type>())[MIN][dim];
372 for (uint04 n = start + 1; n < end; ++n)
373 {
375 {
376 bounds[0][MIN][dim] = Bounds<t_dims, t_type>(locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][n]].template as<t_dims, t_type>())[MIN][dim];
377 break;
378 }
379 }
380 }
382 {
383 bounds[0][MAX][dim] = Bounds<t_dims, t_type>(locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][end - 1]].template as<t_dims, t_type>())[MAX][dim];
384 for (uint04 n = end - 2; n >= start && IsValid(n); --n)
385 {
387 {
388 bounds[1][MAX][dim] = Bounds<t_dims, t_type>(locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][n]].template as<t_dims, t_type>())[MAX][dim];
389 break;
390 }
391 }
392 }
393 else
394 {
395 bounds[1][MAX][dim] = Bounds<t_dims, t_type>(locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][end - 1]].template as<t_dims, t_type>())[MAX][dim];
396 for (uint04 n = end - 2; n >= start && IsValid(n); --n)
397 {
399 {
400 bounds[0][MAX][dim] = Bounds<t_dims, t_type>(locations[TreeSorterBase<t_dims, t_type>::center_ordered[dim][n]].template as<t_dims, t_type>())[MAX][dim];
401 break;
402 }
403 }
404 }
405 }
406 }
407 return bounds;
408 }
409
415 uint04 getMedian(uint01 dimension, uint04 start, uint04 end)
416 {
417 const uint04 median_location = ((end - start) / 2) + start;
418 for (uint04 i = start; i < median_location; i++)
419 {
421 }
422 for (uint04 i = median_location; i < end; i++)
423 {
425 }
426 for (uint01 dim = 0; dim < t_dims; ++dim)
427 {
428 if (dimension != dim)
429 {
431 }
432 if (m_uses_boundary)
433 {
436 }
437 }
438 return TreeSorterBase<t_dims, t_type>::center_ordered[dimension][median_location];
439 }
440
441 protected:
444 bool m_uses_boundary = true;
445 };
446
447 template<class t_type>
448 class TreeSorter;
449
450}
A specification of upper and lower bounds in N-dimensions.
Definition Bounds.hpp:54
constexpr t_vertex center() const
Returns the center of the bounds.
Definition Bounds.hpp:129
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
A hash-based key-value store, useful for quick associative lookups.
Definition Dictionary.h:64
A tree sorter that supports both center-based and boundary-based spatial partitioning.
Definition TreeSorter.h:113
void createCenterSortList(const Buffer< uint04 > &indices, const t_list_type &locations)
Creates sorted index lists based on element centers.
Definition TreeSorter.h:119
bool m_uses_boundary
Whether boundary-based sorting is enabled.
Definition TreeSorter.h:444
Vector< 2, Bounds< t_dims, t_type > > getMedianBounds(uint01 dimension, uint04 start, uint04 end, const t_list_type &locations)
Computes the bounding boxes for both sides of a median split.
Definition TreeSorter.h:290
Buffer< uint04 > max_ordered[t_dims]
Pre-sorted index arrays by maximum bound for each dimension.
Definition TreeSorter.h:443
Bounds< t_dims, t_type > getBounds(uint04 start, uint04 finish, const t_list_type &locations) const
Computes the tight bounding box for a range of sorted elements.
Definition TreeSorter.h:262
Buffer< uint04 > min_ordered[t_dims]
Pre-sorted index arrays by minimum bound for each dimension.
Definition TreeSorter.h:442
uint04 getMedian(uint01 dimension, uint04 start, uint04 end)
Finds the median element and partitions all sorted lists accordingly.
Definition TreeSorter.h:415
void createBoundarySortList(const Buffer< uint04 > &indices, const t_list_type &locations)
Creates sorted index lists based on element bounding boxes.
Definition TreeSorter.h:140
void createHashSortList(const Buffer< uint04 > &indices, const t_list_type &locations)
Creates sorted index lists using a hash-based lookup for sparse element sets.
Definition TreeSorter.h:169
void sortList(uint01 dimension, const t_center_buffer &centers, const t_bounds_buffer &bounds)
Sorts the index lists for a given dimension by center, min, and max values.
Definition TreeSorter.h:201
Base class for tree sorters that maintain pre-sorted index arrays for efficient spatial partitioning.
Definition TreeSorter.h:62
void getList(uint01 dimension, uint04 start, uint04 end, Buffer< uint04 > &values, uint04 index_offset)
Copies a range of the center-ordered index list into the output buffer.
Definition TreeSorter.h:70
Buffer< uint04 > temp_array
Temporary index buffer for partitioning operations.
Definition TreeSorter.h:104
static void _sortList(const Buffer< bool > &list_sorter, Buffer< uint04 > &list, Buffer< uint04 > &temp, uint04 start, uint04 end)
Partitions a list into two halves based on a boolean mask.
Definition TreeSorter.h:82
Buffer< uint04 > center_ordered[t_dims]
Pre-sorted index arrays by center value for each dimension.
Definition TreeSorter.h:105
Buffer< bool > temp_memory
Temporary boolean buffer for partitioning operations.
Definition TreeSorter.h:103
A fixed-size array with N dimensions used as the basis for geometric and mathematical types.
Definition Vector.hpp:62
The primary namespace for the NDEVR SDK.
static constexpr bool IsValid(const Angle< t_type > &value)
Checks whether the given Angle holds a valid value.
Definition Angle.h:398
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
static constexpr bool IsInvalid(const Angle< t_type > &value)
Checks whether the given Angle holds an invalid value.
Definition Angle.h:388