API Documentation
Loading...
Searching...
No Matches
Median.hpp
Go to the documentation of this file.
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: Base
28File: Median
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/Buffer.h>
34#include <NDEVR/BinaryHeap.h>
35namespace NDEVR
36{
37 // return the median value in a vector
38 template<class t_container_type>
39 uint04 median(const t_container_type& elements, Buffer<uint04>& indices, const uint04 start, const uint04 end, uint01 dimension)
40 {
41 uint04* middle = indices.begin(start + ((end - start) / 2));
42 std::nth_element(indices.begin(start), middle, indices.begin(end), [&elements, dimension](uint04 i, uint04 j)
43 {
44 return elements[i].center()[dimension] < elements[j].center()[dimension];
45 });
46 return start + ((end - start) / 2);
47 }
48
49 // return the median value in a vector
50 template<class t_node_type, class t_container_type>
51 uint04 dynamicHeapMedian(uint04 size, const Buffer<t_node_type>& points, const t_container_type& indices, const uint04 start, const uint04 step, uint01 dimension)
52 {
53 const sint04 half_heap = cast<sint04>(size / 2);
54 const sint04 max_heap = cast<sint04>(size / 2);
57 sint04 nLeft = 1;
58 sint04 nRight = 1;
59 sint04 index = start;
60 // pick first value as median candidate
61 sint04 median = index;
62 index += step;
63
64 for (;;)
65 {
66 // get next value
67 sint04 val = index;
68 sint04 child = nLeft++, parent = (child - 1) / 2;
69 index += step;
70 // if value is smaller than median, append to left heap
71 if (points[indices[val]][dimension] < points[indices[median]][dimension])
72 {
73 // move biggest value to the heap top
74 left.insert(points[indices[val]][dimension], val);
75
76 // if left heap is full
77 if (left.size() == max_heap)
78 {
79 // for each remaining value
80 for (; nRight != max_heap; nRight++)
81 {
82 // get next value
83 val = index;
84 index += step;
85 // if value is to be inserted in the left heap
86 if (points[indices[val]][dimension] < points[indices[median]][dimension])
87 {
88
89 child = points[indices[left[2]]][dimension] > points[indices[left[1]]][dimension] ? 2 : 1;
90 if (points[indices[val]][dimension] >= points[indices[left[child]]][dimension])
91 median = val;
92 else
93 {
94 median = left[child];
95 parent = child;
96 child = parent * 2 + 1;
97 while (child < max_heap)
98 {
99 if (child < half_heap
100 && points[indices[left[child + 1]]][dimension] > points[indices[left[child]]][dimension])
101 ++child;
102 if (points[indices[val]][dimension] >= points[indices[left[child]]][dimension])
103 break;
104 left[parent] = left[child];
105 parent = child;
106 child = parent * 2 + 1;
107 }
108 left[parent] = val;
109 }
110 }
111 }
112 return median;
113 }
114 }
115
116 // else append to right heap
117 else
118 {
119 // move smallest value to the heap top
120 sint04 child = nRight++, parent = (child - 1) / 2;
121 while (parent && points[indices[val]][dimension] < points[indices[right[parent]]][dimension])
122 {
123 right[child] = right[parent];
124 child = parent;
125 parent = (parent - 1) / 2;
126 }
127 right[child] = val;
128
129 // if right heap is full
130 if (nRight == max_heap)
131 {
132 // for each remaining value
133 for (; nLeft != max_heap; nLeft++)
134 {
135 // get next value
136 val = index;
137 index += step;
138 // if value is to be inserted in the right heap
139 if (points[indices[val]][dimension] > points[indices[median]][dimension])
140 {
141 child = points[indices[right[2]]][dimension] < points[indices[right[1]]][dimension] ? 2 : 1;
142 if (points[indices[val]][dimension] <= points[indices[right[child]]][dimension])
143 median = val;
144 else
145 {
146 median = right[child];
147 parent = child;
148 child = parent * 2 + 1;
149 while (child < max_heap)
150 {
151 if (child < half_heap
152 && points[indices[right[child + 1]]][dimension] < points[indices[right[child]]][dimension])
153 ++child;
154 if (points[indices[val]][dimension] <= points[indices[right[child]]][dimension])
155 break;
156 right[parent] = right[child];
157 parent = child;
158 child = parent * 2 + 1;
159 }
160 right[parent] = val;
161 }
162 }
163 }
164 return median;
165 }
166 }
167 }
168 }
169
170 // return the median value in a vector
171 template<uint01 t_bucket_size, class t_buffer_type, class t_container_type>
172 uint04 staticHeapMedian(const t_buffer_type& points, const t_container_type& indices, uint04 start, uint04 step, uint01 dimension)
173 {
174 const uint04 half_heap = t_bucket_size / 2;
175 const uint04 max_heap = t_bucket_size / 2 + 1;
176 uint04 left[t_bucket_size / 2 + 1];
177 uint04 right[t_bucket_size / 2 + 1];
178 sint04 nLeft = 1;
179 sint04 nRight = 1;
180 sint04 index = start;
181 // pick first value as median candidate
182 sint04 median = index;
183 index += step;
184
185 for (;;)
186 {
187 // get next value
188 sint04 val = index;
189 index += step;
190 // if value is smaller than median, append to left heap
191 if (points[indices[val]][dimension] < points[indices[median]][dimension])
192 {
193 // move biggest value to the heap top
194 sint04 child = nLeft++, parent = (child - 1) / 2;
195 while (parent && points[indices[val]][dimension] > points[indices[left[parent]]][dimension])
196 {
197 left[child] = left[parent];
198 child = parent;
199 parent = (parent - 1) / 2;
200 }
201 left[child] = val;
202
203 // if left heap is full
204 if (nLeft == max_heap)
205 {
206 // for each remaining value
207 for (; nRight != max_heap; nRight++)
208 {
209 // get next value
210 val = index;
211 index += step;
212 // if value is to be inserted in the left heap
213 if (points[indices[val]][dimension] < points[indices[median]][dimension])
214 {
215 child = points[indices[left[2]]][dimension] > points[indices[left[1]]][dimension] ? 2 : 1;
216 if (points[indices[val]][dimension] >= points[indices[left[child]]][dimension])
217 median = val;
218 else
219 {
220 median = left[child];
221 parent = child;
222 child = parent * 2 + 1;
223 while (child < max_heap)
224 {
225 if (child < half_heap
226 && points[indices[left[child + 1]]][dimension] > points[indices[left[child]]][dimension])
227 ++child;
228 if (points[indices[val]][dimension] >= points[indices[left[child]]][dimension])
229 break;
230 left[parent] = left[child];
231 parent = child;
232 child = parent * 2 + 1;
233 }
234 left[parent] = val;
235 }
236 }
237 }
238 return median;
239 }
240 }
241
242 // else append to right heap
243 else
244 {
245 // move smallest value to the heap top
246 sint04 child = nRight++, parent = (child - 1) / 2;
247 while (parent && points[indices[val]][dimension] < points[indices[right[parent]]][dimension])
248 {
249 right[child] = right[parent];
250 child = parent;
251 parent = (parent - 1) / 2;
252 }
253 right[child] = val;
254
255 // if right heap is full
256 if (nRight == max_heap)
257 {
258 // for each remaining value
259 for (; nLeft != max_heap; nLeft++)
260 {
261 // get next value
262 val = index;
263 index += step;
264 // if value is to be inserted in the right heap
265 if (points[indices[val]][dimension] > points[indices[median]][dimension])
266 {
267 child = points[indices[right[2]]][dimension] < points[indices[right[1]]][dimension] ? 2 : 1;
268 if (points[indices[val]][dimension] <= points[indices[right[child]]][dimension])
269 median = val;
270 else
271 {
272 median = right[child];
273 parent = child;
274 child = parent * 2 + 1;
275 while (child < max_heap)
276 {
277 if (child < half_heap
278 && points[indices[right[child + 1]]][dimension] < points[indices[right[child]]][dimension])
279 ++child;
280 if (points[indices[val]][dimension] <= points[indices[right[child]]][dimension])
281 break;
282 right[parent] = right[child];
283 parent = child;
284 child = parent * 2 + 1;
285 }
286 right[parent] = val;
287 }
288 }
289 }
290 return median;
291 }
292 }
293 }
294 }
295
296 // return the median value in a vector
297 template<class t_buffer_type>
298 uint04 apxMedian(const t_buffer_type& elements, const Buffer<uint04>& indices, uint04 start, uint04 end, uint01 dimension)
299 {
300 uint04 skip = (end - start) / 64;
301 if (skip == 0)
302 {
303 if (end - start > 32) return staticHeapMedian<31>(elements, indices, start, 1, dimension);
304 if (end - start > 16) return staticHeapMedian<15>(elements, indices, start, 1, dimension);
305 if (end - start > 8) return staticHeapMedian<7>(elements, indices, start, 1, dimension);
306 if (end - start > 4) return staticHeapMedian<3>(elements, indices, start, 1, dimension);
307 else
308 return indices[start];
309 }
310 uint04 number_value;
311 if (skip > 64) number_value = 64;
312 else if (skip > 32) number_value = 32;
313 else if (skip > 16) number_value = 16;
314 else if (skip > 8) number_value = 8;
315 else return staticHeapMedian<63>(elements, indices, start, skip, dimension);
316 uint04 median_locations[64];
317 uint04 median_values[64];
318 for (uint04 i = 0; i < number_value; i++)
319 {
320 uint04 median_loc = staticHeapMedian<63>(elements, indices, start + i, skip, dimension);
321 median_locations[i] = (indices[median_loc]);
322 median_values[i] = median_loc;
323 }
324 switch (number_value)
325 {
326 case 64: return median_values[staticHeapMedian<63>(elements, median_locations, 0, 1, dimension)];
327 case 32: return median_values[staticHeapMedian<31>(elements, median_locations, 0, 1, dimension)];
328 case 16: return median_values[staticHeapMedian<15>(elements, median_locations, 0, 1, dimension)];
329 case 8: return median_values[staticHeapMedian<7>(elements, median_locations, 0, 1, dimension)];
330 default: lib_assert(false, "Unknown number_value in roughHeapMedian");
331 }
333 }
334
335
336 template<class t_type, class t_node_type>
337 uint04 sortAboutValue(uint04 value_index, const Buffer<t_node_type>& points, Buffer<uint04>& indices, uint04 start, uint04 end, uint01 dimension)
338 {
339 const t_type value = points[indices[value_index]][dimension];
340
341 std::swap(indices[--end], indices[value_index]);
342 uint04 store = start;
343 for (uint04 idx = start; idx < end; idx++)
344 {
345 if (points[indices[idx]][dimension] <= value)
346 {
347 std::swap(indices[idx], indices[store]);
348 store++;
349 }
350 }
351 std::swap(indices[end], indices[store]);
352 return store;
353 }
354 template<class t_type, class t_node_type>
355 uint04 apxNthElement(const Buffer<t_node_type>& points, Buffer<uint04>& indices, uint04 start, uint04 end, uint01 dimension)
356 {
357 const uint04 median_loc = apxMedian(points, indices, start, end, dimension);
358 return sortAboutValue<t_type>(median_loc, points, indices, start, end, dimension);
359 }
360 template<class t_type, class t_buffer_type, class t_bounds_type>
361 uint04 sortAboutValue(uint04 value_index, const t_buffer_type& points, Buffer<uint04>& indices, uint04 start, uint04 end, uint01 dimension, t_bounds_type& bounds_left, t_bounds_type& bounds_right)
362 {
363 const t_type value = points[indices[value_index]].center()[dimension];
364 bounds_right.addToBounds(points[indices[value_index]]);
365
366 std::swap(indices[--end], indices[value_index]);
367 uint04 store = start;
368 for (uint04 idx = start; idx < end; idx++)
369 {
370 auto element = points[indices[idx]];
371 if (element.center()[dimension] == value)
372 {
373 if ((store - start) <= (idx - start) / 2)
374 {
375 bounds_left.addToBounds(element);
376 std::swap(indices[idx], indices[store]);
377 store++;
378 }
379 else
380 {
381 bounds_right.addToBounds(element);
382 }
383 }
384 else if (element.center()[dimension] < value)
385 {
386 bounds_left.addToBounds(element);
387 std::swap(indices[idx], indices[store]);
388 store++;
389 }
390 else
391 {
392 bounds_right.addToBounds(element);
393 }
394 }
395 std::swap(indices[end], indices[store]);
396 return store;
397 }
398};
399
#define lib_assert(expression, message)
Asserts some logic in the code. Disabled in non debug mode by default. Can be re-enabled in release u...
Definition LibAssert.h:70
Definition BinaryHeap.hpp:39
void insert(t_comp_type comparison, t_value_type value)
Definition BinaryHeap.hpp:44
uint04 size() const
Definition BinaryHeap.hpp:71
The equivelent of std::vector but with a bit more control. The basic array unit of the library.
Definition Buffer.hpp:64
decltype(auto) begin()
Definition Buffer.hpp:504
Definition ACIColor.h:37
int32_t sint04
-Defines an alias representing a 4 byte, signed integer. -Can represent exact integer values -2147483...
Definition BaseValues.hpp:76
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:98
uint04 apxNthElement(const Buffer< t_node_type > &points, Buffer< uint04 > &indices, uint04 start, uint04 end, uint01 dimension)
Definition Median.hpp:355
uint04 apxMedian(const t_buffer_type &elements, const Buffer< uint04 > &indices, uint04 start, uint04 end, uint01 dimension)
Definition Median.hpp:298
uint04 dynamicHeapMedian(uint04 size, const Buffer< t_node_type > &points, const t_container_type &indices, const uint04 start, const uint04 step, uint01 dimension)
Definition Median.hpp:51
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:120
constexpr t_to cast(const Angle< t_from > &value)
Definition Angle.h:514
uint04 staticHeapMedian(const t_buffer_type &points, const t_container_type &indices, uint04 start, uint04 step, uint01 dimension)
Definition Median.hpp:172
uint04 sortAboutValue(uint04 value_index, const Buffer< t_node_type > &points, Buffer< uint04 > &indices, uint04 start, uint04 end, uint01 dimension)
Definition Median.hpp:337
uint04 median(const t_container_type &elements, Buffer< uint04 > &indices, const uint04 start, const uint04 end, uint01 dimension)
Definition Median.hpp:39
Definition BaseValues.hpp:272