Sequoia
Loading...
Searching...
No Matches
DynamicTree.hpp
Go to the documentation of this file.
1
2// Copyright Oliver J. Rosten 2021. //
3// Distributed under the GNU GENERAL PUBLIC LICENSE, Version 3.0. //
4// (See accompanying file LICENSE.md or copy at //
5// https://www.gnu.org/licenses/gpl-3.0.en.html) //
7
8#pragma once
9
15
16namespace sequoia::maths
17{
18 template
19 <
20 graph_flavour Flavour,
21 tree_link_direction TreeLinkDir,
22 class EdgeWeight,
23 class NodeWeight,
24 class EdgeMetaData,
25 class EdgeStorageConfig = bucketed_edge_storage_config,
26 class NodeWeightStorage = node_storage<NodeWeight>
27 >
28 requires ((TreeLinkDir == tree_link_direction::symmetric) || (Flavour == graph_flavour::directed))
29 class tree_base : public
31 <
32 Flavour,
33 EdgeWeight,
34 NodeWeight,
35 EdgeMetaData,
36 EdgeStorageConfig,
37 NodeWeightStorage
38 >
39 {
40 using base_type =
42 <
43 Flavour,
44 EdgeWeight,
45 NodeWeight,
46 EdgeMetaData,
47 EdgeStorageConfig,
48 NodeWeightStorage
49 >;
50 public:
51 using size_type = typename base_type::size_type;
52
53 constexpr static tree_link_direction link_dir{TreeLinkDir};
54
55 tree_base() = default;
56
57 tree_base(const tree_base&) = default;
58 tree_base& operator=(const tree_base&) = default;
59
60 // TO DO: think about depth-like vs breadth-like initialization
63 {}
64
65 template<class... Args>
66 requires is_initializable_v<NodeWeight, Args...>
67 size_type add_node(const size_type parent, Args&&... args)
68 {
69 return base_type::add_node_to_tree(tree_link_direction_constant<TreeLinkDir>{}, parent, std::forward<Args>(args)...);
70 }
71
72 template<class... Args>
73 requires is_initializable_v<NodeWeight, Args...>
74 size_type insert_node(const size_type pos, const size_type parent, Args&&... args)
75 {
76 return base_type::insert_node_to_tree(tree_link_direction_constant<TreeLinkDir>{}, pos, parent, std::forward<Args>(args)...);
77 }
78
79 void prune(const size_type node)
80 {
82 }
83
84 using base_type::swap_edges;
85 using base_type::sort_edges;
86 using base_type::stable_sort_edges;
87 using base_type::swap_nodes;
88 using base_type::sort_nodes;
89 protected:
90 ~tree_base() = default;
91
92 tree_base(tree_base&&) noexcept = default;
93 tree_base& operator=(tree_base&&) noexcept = default;
94 private:
95 void prune(const size_type node, forward_tree_type ftt)
96 {
97 while(std::ranges::distance(this->crbegin_edges(node), this->crend_edges(node)))
98 {
99 const auto target{this->crbegin_edges(node)->target_node()};
100 prune(target, ftt);
101 }
102
103 this->erase_node(node);
104 }
105
106 void prune(const size_type node, symmetric_tree_type stt)
107 {
108 const std::ptrdiff_t offset{node == 0 ? 0 : 1};
109
110 while(std::ranges::distance(this->crbegin_edges(node), this->crend_edges(node)) > offset)
111 {
112 const auto target{this->crbegin_edges(node)->target_node()};
113 prune(target, stt);
114 }
115
116 this->erase_node(node);
117 }
118
119 void prune(const size_type node, backward_tree_type btt)
120 {
121 if(node >= this->order()) return;
122
123 std::vector<bool> toDelete(this->order(), false);
124 toDelete[node] = true;
125
126 for(size_type i{}; i < this->order(); ++i)
127 {
128 if(!toDelete[i]) prune(i, toDelete, btt);
129 }
130
131 for(size_type i{}; i < toDelete.size(); ++i)
132 {
133 // Erase nodes with the highest indicies first
134 const auto j{toDelete.size() - 1 - i};
135 if(toDelete[j]) this->erase_node(j);
136 }
137 }
138
139 void prune(const size_type node, std::vector<bool>& toDelete, backward_tree_type btt)
140 {
141 if(auto begin{this->cbegin_edges(node)}; begin != this->cend_edges(node))
142 {
143 const auto target{begin->target_node()};
144 if(toDelete[target])
145 {
146 toDelete[node] = true;
147 }
148 else
149 {
150 prune(target, toDelete, btt);
151 if(toDelete[target]) toDelete[node] = true;
152 }
153 }
154 }
155 };
156
157 template
158 <
159 tree_link_direction TreeLinkDir,
160 class EdgeWeight,
161 class NodeWeight,
162 class EdgeStorageConfig = bucketed_edge_storage_config,
163 class NodeWeightStorage = node_storage<NodeWeight>
164 >
165 class directed_tree final : public
167 <
168 graph_flavour::directed,
169 TreeLinkDir,
170 EdgeWeight,
171 NodeWeight,
172 null_meta_data,
173 EdgeStorageConfig,
174 NodeWeightStorage
175 >
176 {
177 public:
178 using tree_base<
179 graph_flavour::directed,
180 TreeLinkDir,
181 EdgeWeight,
182 NodeWeight,
184 EdgeStorageConfig,
185 NodeWeightStorage
186 >::tree_base;
187 };
188
189 template
190 <
191 tree_link_direction TreeLinkDir,
192 class EdgeWeight,
193 class NodeWeight,
194 class EdgeMetaData = null_meta_data,
195 class EdgeStorageConfig = bucketed_edge_storage_config,
196 class NodeWeightStorage = node_storage<NodeWeight>
197 >
198 requires (TreeLinkDir == tree_link_direction::symmetric)
199 class undirected_tree final : public
201 <
202 graph_flavour::undirected,
203 TreeLinkDir,
204 EdgeWeight,
205 NodeWeight,
206 EdgeMetaData,
207 EdgeStorageConfig,
208 NodeWeightStorage
209 >
210 {
211 public:
212 using tree_base<
213 graph_flavour::undirected,
214 TreeLinkDir,
215 EdgeWeight,
216 NodeWeight,
217 EdgeMetaData,
218 EdgeStorageConfig,
219 NodeWeightStorage
220 >::tree_base;
221 };
222
223 template<class Tree>
225 {
226 public:
227 using value_type = Tree;
228
229 using size_type = typename Tree::size_type;
230
231 basic_tree_adaptor() = default;
232
233 basic_tree_adaptor(Tree& tree, size_type node)
234 : m_pTree{&tree}
235 , m_Node{node}
236 {};
237
238 [[nodiscard]]
239 Tree& tree()
240 requires (!std::is_const_v<Tree>)
241 {
242 if(!m_pTree) throw std::logic_error{"Tree not found"};
243
244 return *m_pTree;
245 }
246
247 [[nodiscard]]
248 const Tree& tree() const
249 {
250 if(!m_pTree) throw std::logic_error{"Tree not found"};
251
252 return *m_pTree;
253 }
254
255 [[nodiscard]]
256 size_type node() const noexcept
257 {
258 return m_Node;
259 }
260
261 [[nodiscard]]
262 bool empty() const noexcept
263 {
264 return m_pTree == nullptr;
265 }
266
267 [[nodiscard]]
268 explicit operator bool() const noexcept
269 {
270 return !empty() && (m_Node < m_pTree->order());
271 }
272
273 [[nodiscard]]
274 friend bool operator==(const basic_tree_adaptor& lhs, const basic_tree_adaptor& rhs) noexcept = default;
275 private:
276 Tree* m_pTree{};
277 size_type m_Node{Tree::npos};
278 };
279
280 template<class Tree>
282
283 template<class Tree>
285
286 template<dynamic_tree T>
287 [[nodiscard]]
288 auto root_weight_iter(const basic_tree_adaptor<T>& adaptor)
289 {
290 return adaptor.tree().cbegin_node_weights() + adaptor.node();
291 }
292
293 template<dynamic_tree T>
294 [[nodiscard]]
295 const auto& root_weight(const basic_tree_adaptor<T>& adaptor)
296 {
297 return adaptor.tree().cbegin_node_weights()[adaptor.node()];
298 }
299
300 template<dynamic_tree T, std::invocable<typename T::node_weight_type&> Fn>
301 void mutate_root_weight(basic_tree_adaptor<T>& adaptor, Fn fn)
302 {
303 adaptor.tree().mutate_node_weight(root_weight_iter(adaptor), fn);
304 }
305
306 template<std::input_or_output_iterator Iterator, class TreeAdaptor>
308 {
309 public:
310 using proxy = TreeAdaptor;
311 using value_type = proxy;
312 using reference = proxy;
313 using tree_reference_type = typename TreeAdaptor::value_type&;
314
315 constexpr forest_from_tree_dereference_policy() = default;
316 constexpr forest_from_tree_dereference_policy(tree_reference_type tree) : m_pTree{&tree} {}
318
319 [[nodiscard]]
320 constexpr proxy get(Iterator i) const
321 {
322 return {*m_pTree, i->target_node()};
323 }
324
325 [[nodiscard]]
326 friend constexpr bool operator==(const forest_from_tree_dereference_policy&, const forest_from_tree_dereference_policy&) noexcept = default;
327 protected:
329
331
334 private:
335 using tree_pointer_type = std::remove_reference_t<tree_reference_type>*;
336
337 tree_pointer_type m_pTree{};
338 };
339
340 template<std::input_or_output_iterator Iterator, class Adaptor>
342
343
344 template<std::input_or_output_iterator Iterator, class TreeAdaptor>
346 {
347 public:
348 using proxy = TreeAdaptor;
349 using value_type = proxy;
350 using reference = proxy;
351
352 constexpr forest_dereference_policy() = default;
353 constexpr forest_dereference_policy(const forest_dereference_policy&) = default;
354
355 [[nodiscard]]
356 constexpr static proxy get(Iterator i)
357 {
358 return {*i, 0};
359 }
360
361 [[nodiscard]]
362 friend constexpr bool operator==(const forest_dereference_policy&, const forest_dereference_policy&) noexcept = default;
363 protected:
365
366 ~forest_dereference_policy() = default;
367
368 constexpr forest_dereference_policy& operator=(const forest_dereference_policy&) = default;
369 constexpr forest_dereference_policy& operator=(forest_dereference_policy&&) = default;
370 };
371
372 template<std::input_or_output_iterator Iterator, class Adaptor>
374}
Edge & Node storage traits, base class and final classes for dynamic graphs.
Definition: DynamicTree.hpp:225
Definition: DynamicTree.hpp:176
Definition: DynamicTree.hpp:346
Definition: DynamicGraph.hpp:56
Definition: NodeStorage.hpp:272
Definition: DynamicTree.hpp:39
Definition: DynamicTree.hpp:210
An iterator with policies controlling dereferencing and auxiliary data.
Definition: Iterator.hpp:234
Definition: DynamicGraph.hpp:29
Definition: Edge.hpp:287
Definition: GraphPrimitive.hpp:84