NDEVR
API Documentation
ThreadedRTree.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: ThreadedRTree
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/RTree.h>
34#include <NDEVR/Thread.h>
35#include <NDEVR/BasicThread.h>
36#include <NDEVR/RWLock.h>
37namespace NDEVR
38{
42 template<uint01 t_dims, class t_type>
43 class ThreadedRTree : public RTree<t_dims, t_type>
44 {
45
46 public:
49 explicit ThreadedRTree<t_dims, t_type>(uint04 bucket_size)
50 : RTree<t_dims, t_type>(bucket_size)
52 {
53 m_indices.allocateSpace<false>(bucket_size);
54 }
57 ThreadedRTree<t_dims, t_type>(const RTree<t_dims, t_type>& tree)
58 : RTree<t_dims, t_type>(tree)
59 , m_number_of_threads(tree.m_number_of_threads)
60 {}
63 ThreadedRTree<t_dims, t_type>(RTree<t_dims, t_type>&& tree)
64 : RTree<t_dims, t_type, t_bucket_size>(std::move(tree))
65 , m_number_of_threads(tree.m_number_of_threads)
66 {}
67
72 template<class t_node_type>
73 bool addAllThreaded(const Buffer<t_node_type>& elements, InfoPipe* progress = nullptr)
74 {
75 Buffer<uint04> indices = prepareAddAll(0, elements.size());
76
77 m_nodes[root_node].clear(m_nodes[root_node].begin(), _getBoundingBoxThreaded(0, indices, elements, 0, indices.size()));
78
79 if (progress != nullptr) progress->allowCancel(true);//if you change this, be ready to catch the exception that gets thrown when you cancel
80 bool did_balance = _balanceLeafNodeThreaded(root_node, 0, elements, indices, 0, indices.size(), progress);
81 if (progress != nullptr) progress->allowCancel(false);
82
83 m_indices.ensureCapacity(cast<uint04>(1.1 * (m_indices.size())), true, true);
84 m_nodes.ensureCapacity(cast<uint04>(1.1 * (m_nodes.size())), true, true);
85
86 return did_balance;
87
88 }
89
96 template<class t_node_type>
97 bool addAllThreaded(const Buffer<t_node_type>& elements, uint04 start_index, uint04 end_index, InfoPipe* progress = nullptr)
98 {
99 Buffer<uint04> indices = prepareAddAll(start_index, end_index);
100
101 m_nodes[root_node].clear(m_nodes[root_node].begin(), bounds);
102
103 if (progress != nullptr) progress->allowCancel(true);//if you change this, be ready to catch the exception that gets thrown when you cancel
104 bool did_balance = _balanceLeafNodeThreaded(root_node, 1, elements, indices, 0, indices.size(), progress);
105 if (progress != nullptr) progress->allowCancel(false);
106
107 m_indices.ensureCapacity(cast<uint04>(1.1 * (m_indices.size())), true, true);
108 m_nodes.ensureCapacity(cast<uint04>(1.1 * (m_nodes.size())), true, true);
109
110 return did_balance;
111 }
112
113
114
124 template<class t_node_type>
125 bool _balanceLeafNodeThreaded(uint04 level, const uint04 node_index, const Buffer<t_node_type>& elements, Buffer<uint04>& indices, uint04 start, uint04 end, ProgressInfo& progress)
126 {
127 uint04 level_value = pow(2U, level);
128 if (m_number_of_threads <= level_value || (end - start) < 1000)
129 {
130 _balanceLeafNode(node_index, elements, indices, start, end, progress);
131 }
132 else
133 {
134 const uint04 new_left = _calculateAndSplit(node_index, elements, indices, start, end);
135 splitThread(
136 [this, level, start, new_left, node_index, &progress, &indices, &elements] {
137 //uint08 start_time = Time::SystemTime();
138 _balanceLeafNodeThreaded(level + 1, m_nodes[node_index].left(), elements, indices, start, new_left, progress);
139 //if (progress != nullptr) progress->addMessage(String("Finished: Level = ") + level + " Time: " + (Time::SystemTime() - start_time));
140 },
141 [this, level, end, new_left, node_index, &progress, &indices, &elements] {
142 //uint08 start_time = Time::SystemTime();
143 _balanceLeafNodeThreaded(level + 1, m_nodes[node_index].right(), elements, indices, new_left, end, progress);
144 //if (progress != nullptr) progress->addMessage(String("Finished: Level = ") + level + " Time: " + (Time::SystemTime() - start_time));
145 });
146 }
147 return true;
148 }
149
156 template<class t_node_type>
158 {
159 if (m_number_of_threads <= pow(2U, top_level) || end - start < 100)
160 {
161 return _getBounds(indices, elements, start, end);
162 }
163 else
164 {
165 const uint04 middle = start + (end - start) / 2;
168 splitThread(
169 [this, &left, &indices, &elements, start, middle, top_level] {
170 left = _getBoundingBoxThreaded(top_level + 1, indices, elements, start, middle);
171 },
172 [this, &right, &indices, &elements, end, middle, top_level] {
173 right = _getBoundingBoxThreaded(top_level + 1, indices, elements, middle, end);
174 });
175 return Bounds<t_dims, t_type>(left, right);
176 }
177 }
178
181 void splitLeafNode(uint04 index) final override
182 {
183 m_split_lock.lock();
184 RTree<t_dims, t_type, t_bucket_size>::splitLeafNode(index);
185 m_split_lock.unlock();
186
187 }
188 std::mutex m_split_lock;
190 };
191};
A specification of upper and lower bounds in N-dimensions.
Definition Bounds.hpp:54
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
A light-weight base class for Log that allows processes to update, without the need for additional in...
Used with InfoPipe to signal that the system will be using progress.
bool addAllThreaded(const Buffer< t_node_type > &elements, InfoPipe *progress=nullptr)
Adds all elements to the tree using multi-threaded balancing.
std::mutex m_split_lock
Mutex protecting leaf node splits during multi-threaded construction.
bool addAllThreaded(const Buffer< t_node_type > &elements, uint04 start_index, uint04 end_index, InfoPipe *progress=nullptr)
Adds a range of elements to the tree using multi-threaded balancing.
Bounds< t_dims, t_type > _getBoundingBoxThreaded(uint04 top_level, const Buffer< uint04 > &indices, const Buffer< t_node_type > &elements, uint04 start, uint04 end)
Computes the bounding box of elements using multi-threaded divide and conquer.
ThreadedRTree(uint04 bucket_size)
Constructs a ThreadedRTree with the given bucket size.
void splitLeafNode(uint04 index) final override
Thread-safe override that splits a leaf node using a mutex lock.
bool _balanceLeafNodeThreaded(uint04 level, const uint04 node_index, const Buffer< t_node_type > &elements, Buffer< uint04 > &indices, uint04 start, uint04 end, ProgressInfo &progress)
Recursively balances leaf nodes using thread splitting when beneficial.
uint04 m_number_of_threads
The number of threads to use for parallel operations.
The primary namespace for the NDEVR SDK.
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408