LAL: Linear Arrangement Library 21.07.01
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
size_subtrees.hpp
1/*********************************************************************
2 *
3 * Linear Arrangement Library - A library that implements a collection
4 * algorithms for linear arrangments of graphs.
5 *
6 * Copyright (C) 2019 - 2021
7 *
8 * This file is part of Linear Arrangement Library. To see the full code
9 * visit the webpage:
10 * https://github.com/lluisalemanypuig/linear-arrangement-library.git
11 *
12 * Linear Arrangement Library is free software: you can redistribute it
13 * and/or modify it under the terms of the GNU Affero General Public License
14 * as published by the Free Software Foundation, either version 3 of the
15 * License, or (at your option) any later version.
16 *
17 * Linear Arrangement Library is distributed in the hope that it will be
18 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Affero General Public License for more details.
21 *
22 * You should have received a copy of the GNU Affero General Public License
23 * along with Linear Arrangement Library. If not, see <http://www.gnu.org/licenses/>.
24 *
25 * Contact:
26 *
27 * LluĂ­s Alemany Puig (lalemany@cs.upc.edu)
28 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
29 * CQL (Complexity and Quantitative Linguistics Lab)
30 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
31 * Webpage: https://cqllab.upc.edu/people/lalemany/
32 *
33 * Ramon Ferrer i Cancho (rferrericancho@cs.upc.edu)
34 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
35 * CQL (Complexity and Quantitative Linguistics Lab)
36 * Office S124, Omega building
37 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
38 * Webpage: https://cqllab.upc.edu/people/rferrericancho/
39 *
40 ********************************************************************/
41
42#pragma once
43
44// C++ includes
45#if defined DEBUG
46#include <cassert>
47#endif
48#include <functional>
49
50// lal includes
51#include <lal/graphs/rooted_tree.hpp>
52#include <lal/graphs/free_tree.hpp>
53#include <lal/internal/macros.hpp>
54
55namespace lal {
56namespace internal {
57
58namespace __lal {
59
60/*
61 * @brief Calculate the size of every subtree of the tree @e t.
62 *
63 * @param t Input tree.
64 * @param u Parent node (the first call should be an invalid value (e.g., n+1)).
65 * @param v Next node in the exploration of the tree.
66 * @param sizes The size of the subtree rooted at every reachable node
67 * from @e r.
68 * @pre Parameter @e sizes has size the number of vertices.
69 */
70template<
71 class T,
72 std::enable_if_t<
73 std::is_base_of_v<graphs::rooted_tree, T> ||
74 std::is_base_of_v<graphs::free_tree, T>,
75 bool> = true
76>
77void get_size_subtrees
78(const T& t, const node u, const node v, uint32_t * const sizes)
79{
80 sizes[v] = 1;
81
82 if constexpr (std::is_base_of_v<graphs::rooted_tree, T>) {
83 for (const node w : t.get_out_neighbours(v)) {
84 if (w == u) { continue; }
85 get_size_subtrees(t, v, w, sizes);
86 sizes[v] += sizes[w];
87 }
88 for (const node w : t.get_in_neighbours(v)) {
89 if (w == u) { continue; }
90 get_size_subtrees(t, v, w, sizes);
91 sizes[v] += sizes[w];
92 }
93 }
94 else {
95 for (const node w : t.get_neighbours(v)) {
96 if (w == u) { continue; }
97 get_size_subtrees(t, v, w, sizes);
98 sizes[v] += sizes[w];
99 }
100 }
101}
102
103} // -- namespace __lal
104
105/*
106 * @brief Calculate the size of every subtree of tree @e t.
107 *
108 * The method starts calculating the sizes at node @e r. Since rooted trees
109 * have directed edges, starting at a node different from the tree's root
110 * may not calculate every subtree's size.
111 * @param t Input rooted tree.
112 * @param r Start calculating sizes of subtrees at this node.
113 * @param vis Mark nodes as visited as the algorithm goes on.
114 * @param sizes The size of the subtree rooted at every reachable node from @e r.
115 * @pre Parameter @e sizes has size the number of vertices.
116 */
117template<
118 class T,
119 std::enable_if_t<
120 std::is_base_of_v<graphs::rooted_tree, T> ||
121 std::is_base_of_v<graphs::free_tree, T>,
122 bool> = true
123>
124void get_size_subtrees
125(const T& t, node r, uint32_t * const sizes)
126{
127#if defined DEBUG
128 assert(sizes != nullptr);
129#endif
130 __lal::get_size_subtrees(t, t.get_num_nodes(), r, sizes);
131}
132
133namespace __lal {
134
135/*
136 * @brief Calculates the values \f$s(u,v)\f$ for the edges \f$(s,t)\f$ reachable
137 * from \f$v\f$ in the subtree \f$T^u_v\f$.
138 *
139 * This function calculates the 'map' relating each edge \f$(u, v)\f$ with the
140 * size of the subtree rooted at \f$v\f$ with respect to the hypothetical root
141 * \f$u\f$. This is an implementation of the algorithm described in
142 * \cite Hochberg2003a (proof of lemma 8 (page 63), and the beginning of
143 * section 6 (page 65)).
144 *
145 * Notice that the values are not stored in an actual map (std::map, or similar),
146 * but in a vector.
147 * @tparam tree_type Type of the tree. Must be 'rooted_tree' or 'free_tree'.
148 * @tparam Iterated_Type The type that will store the sizes.
149 * @tparam Iterator_Type Iterator type on a container of Iterated_Type that stores
150 * the list of bidirectional sizes.
151 * @param t Input tree.
152 * @param n Size of the connected component to which edge \f$(u,v)\f$ belongs to.
153 * @param u First vertex of the edge.
154 * @param v Second vertex of the edge.
155 * @param it An iterator to the container that holds the size values. Such
156 * container must have size equal to twice the number of edges in the connected
157 * component of @e u and @e v.
158 * @pre Vertices @e u and @e v belong to the same connected component.
159 */
160template<
161 class tree_type,
162 typename Iterator_Type,
163 std::enable_if_t<
164 (
165 std::is_base_of_v<graphs::rooted_tree, tree_type> ||
166 std::is_base_of_v<graphs::free_tree, tree_type>
167 )
168 && is_pointer_iterator_v<std::pair<edge,uint32_t>, Iterator_Type>
169 ,
170 bool
171 > = true
172>
173uint32_t calculate_bidirectional_sizes
174(const tree_type& t, const uint32_t n, const node u, const node v, Iterator_Type& it)
175{
176 uint32_t s = 1;
177 if constexpr (std::is_base_of_v<graphs::rooted_tree, tree_type>) {
178 for (const node w : t.get_out_neighbours(v)) {
179 if (w == u) { continue; }
180 s += calculate_bidirectional_sizes(t,n, v, w, it);
181 }
182 for (const node w : t.get_in_neighbours(v)) {
183 if (w == u) { continue; }
184 s += calculate_bidirectional_sizes(t,n, v, w, it);
185 }
186 }
187 else {
188 for (const node w : t.get_neighbours(v)) {
189 if (w == u) { continue; }
190 s += calculate_bidirectional_sizes(t,n, v, w, it);
191 }
192 }
193
194 *it++ = std::make_pair(edge(u,v), s);
195 *it++ = std::make_pair(edge(v,u), n - s);
196 return s;
197}
198
199/*
200 * @brief Calculates the values \f$s(u,v)\f$ for the edges \f$(s,t)\f$ reachable
201 * from \f$v\f$ in the subtree \f$T^u_v\f$.
202 *
203 * This function calculates the 'map' relating each edge \f$(u, v)\f$ with the
204 * size of the subtree rooted at \f$v\f$ with respect to the hypothetical root
205 * \f$u\f$. This is an implementation of the algorithm described in
206 * \cite Hochberg2003a (proof of lemma 8 (page 63), and the beginning of
207 * section 6 (page 65)).
208 *
209 * Notice that the values are not stored in an actual map (std::map, or similar),
210 * but in a vector.
211 * @tparam tree_type Type of the tree. Must be 'rooted_tree' or 'free_tree'.
212 * @tparam Iterated_Type The type that will store the sizes.
213 * @tparam Iterator_Type Iterator type on a container of Iterated_Type that stores
214 * the list of bidirectional sizes.
215 * @param t Input tree.
216 * @param n Size of the connected component to which edge \f$(u,v)\f$ belongs to.
217 * @param u First vertex of the edge.
218 * @param v Second vertex of the edge.
219 * @param F Function to assign the edge and the size to the Iterated_Type pointed
220 * by @e it.
221 * @param it An iterator to the container that holds the size values. Such
222 * container must have size equal to twice the number of edges in the connected
223 * component of @e u and @e v.
224 * @pre Vertices @e u and @e v belong to the same connected component.
225 */
226template<
227 class tree_type,
228 typename Iterated_Type,
229 typename Iterator_Type,
230 std::enable_if_t<
231 (
232 std::is_base_of_v<graphs::rooted_tree, tree_type> ||
233 std::is_base_of_v<graphs::free_tree, tree_type>
234 )
235 &&
236 is_pointer_iterator_v<Iterated_Type, Iterator_Type>
237 ,
238 bool
239 > = true
240>
241uint32_t calculate_bidirectional_sizes(
242 const tree_type& t,
243 const uint32_t n,
244 const node u, const node v,
245 const std::function<void (Iterated_Type&, const edge&, uint32_t)> F,
246 Iterator_Type& it
247)
248{
249 uint32_t s = 1;
250 if constexpr (std::is_base_of_v<graphs::rooted_tree, tree_type>) {
251 for (const node w : t.get_out_neighbours(v)) {
252 if (w == u) { continue; }
253 s += calculate_bidirectional_sizes(t,n, v, w, F, it);
254 }
255 for (const node w : t.get_in_neighbours(v)) {
256 if (w == u) { continue; }
257 s += calculate_bidirectional_sizes(t,n, v, w, F, it);
258 }
259 }
260 else {
261 for (const node w : t.get_neighbours(v)) {
262 if (w == u) { continue; }
263 s += calculate_bidirectional_sizes(t,n, v, w, F, it);
264 }
265 }
266
267 F(*it, edge(u,v), s);
268 ++it;
269 F(*it, edge(v,u), n - s);
270 ++it;
271 return s;
272}
273
274} // -- namespace __lal
275
276/*
277 * @brief Calculates the values \f$s(u,v)\f$ for the edges \f$(u,v)\f$ reachable
278 * from vertex @e x.
279 *
280 * Calculates the values \f$s(u,v)\f$ for all edges \f$(u,v)\f$ in linear time.
281 * This is an implementation of the algorithm described in \cite Hochberg2003a
282 * (proof of lemma 8 (page 63), and the beginning of section 6 (page 65)).
283 *
284 * For any edge \f$(u,v)\f$ let \f$T^u\f$ be the tree \f$T\f$ rooted at \f$u\f$.
285 * The value \f$s(u,v)\f$ is the size of the subtree of \f$T^u\f$ rooted at \f$v\f$,
286 * i.e., \f$|V(T^u_v)|\f$.
287 *
288 * Example of usage (mind the vector! its initial size is \f$2*m\f$).
289 *
290 @code
291 const free_tree t = ... ;
292 vector<pair<edge,uint32_t>> sizes_edges(2*t.get_num_edges());
293 auto it = sizes_edges.begin();
294 internal::calculate_bidirectional_sizes(t, t.get_num_nodes(), 0, it);
295 @endcode
296 *
297 * @tparam tree_type Type of the tree. Must be 'rooted_tree' or 'free_tree'.
298 * @tparam Iterated_Type The type that will store the sizes.
299 * @tparam Iterator_Type Iterator type on a container of Iterated_Type that stores
300 * the list of bidirectional sizes.
301 * @param t Input tree
302 * @param n Number of nodes in the connected component of vertex @e x
303 * @param x Node of the connected component for which we want to calculate the
304 * bidirectional sizes
305 * @param it An iterator to the container that holds the size values. Such
306 * container must have size equal to twice the number of edges in the connected
307 * component of @e u and @e v.
308 */
309template<
310 class tree_type,
311 typename Iterator_Type,
312 std::enable_if_t<
313 (
314 std::is_base_of_v<graphs::rooted_tree, tree_type> ||
315 std::is_base_of_v<graphs::free_tree, tree_type>
316 )
317 && is_pointer_iterator_v<std::pair<edge,uint32_t>, Iterator_Type>
318 ,
319 bool
320 > = true
321>
322void calculate_bidirectional_sizes
323(const tree_type& t, const uint32_t n, const node x, Iterator_Type& it)
324{
325 if constexpr (std::is_base_of_v<graphs::rooted_tree, tree_type>) {
326 for (node y : t.get_out_neighbours(x)) {
327 __lal::calculate_bidirectional_sizes<tree_type, Iterator_Type>
328 (t,n, x, y, it);
329 }
330 for (node y : t.get_in_neighbours(x)) {
331 __lal::calculate_bidirectional_sizes<tree_type, Iterator_Type>
332 (t,n, x, y, it);
333 }
334 }
335 else {
336 for (node y : t.get_neighbours(x)) {
337 __lal::calculate_bidirectional_sizes<tree_type, Iterator_Type>
338 (t,n, x, y, it);
339 }
340 }
341}
342
343/*
344 * @brief Calculates the values \f$s(u,v)\f$ for the edges \f$(u,v)\f$ reachable
345 * from vertex @e x.
346 *
347 * Calculates the values \f$s(u,v)\f$ for all edges \f$(u,v)\f$ in linear time.
348 * This is an implementation of the algorithm described in \cite Hochberg2003a
349 * (proof of lemma 8 (page 63), and the beginning of section 6 (page 65)).
350 *
351 * For any edge \f$(u,v)\f$ let \f$T^u\f$ be the tree \f$T\f$ rooted at \f$u\f$.
352 * The value \f$s(u,v)\f$ is the size of the subtree of \f$T^u\f$ rooted at \f$v\f$,
353 * i.e., \f$|V(T^u_v)|\f$.
354 *
355 * Example of usage (mind the vector! its initial size is \f$2*m\f$).
356 *
357 @code
358 const free_tree t = ... ;
359 vector<pair<edge,uint32_t>> sizes_edges(2*t.get_num_edges());
360 auto it = sizes_edges.begin();
361 internal::calculate_bidirectional_sizes(t, t.get_num_nodes(), 0, it);
362 @endcode
363 *
364 * @tparam tree_type Type of the tree. Must be 'rooted_tree' or 'free_tree'.
365 * @tparam Iterated_Type The type that will store the sizes.
366 * @tparam Iterator_Type Iterator type on a container of Iterated_Type that stores
367 * the list of bidirectional sizes.
368 * @param t Input tree
369 * @param n Number of nodes in the connected component of vertex @e x
370 * @param x Node of the connected component for which we want to calculate the
371 * bidirectional sizes
372 * @param F Function to assign the edge and the size to the Iterated_Type pointed
373 * by @e it.
374 * @param it An iterator to the container that holds the size values. Such
375 * container must have size equal to twice the number of edges in the connected
376 * component of @e u and @e v.
377 */
378template<
379 class tree_type,
380 typename Iterated_Type,
381 typename Iterator_Type,
382 std::enable_if_t<
383 (
384 std::is_base_of_v<graphs::rooted_tree, tree_type> ||
385 std::is_base_of_v<graphs::free_tree, tree_type>
386 )
387 && is_pointer_iterator_v<Iterated_Type, Iterator_Type>
388 ,
389 bool
390 > = true
391>
392void calculate_bidirectional_sizes(
393 const tree_type& t,
394 const uint32_t n, const node x,
395 const std::function<void (Iterated_Type&, const edge&, uint32_t)> F,
396 Iterator_Type& it
397)
398{
399 if constexpr (std::is_base_of_v<graphs::rooted_tree, tree_type>) {
400 for (node y : t.get_out_neighbours(x)) {
401 __lal::calculate_bidirectional_sizes<tree_type, Iterated_Type, Iterator_Type>
402 (t,n, x, y, F, it);
403 }
404 for (node y : t.get_in_neighbours(x)) {
405 __lal::calculate_bidirectional_sizes<tree_type, Iterated_Type, Iterator_Type>
406 (t,n, x, y, F, it);
407 }
408 }
409 else {
410 for (node y : t.get_neighbours(x)) {
411 __lal::calculate_bidirectional_sizes<tree_type, Iterated_Type, Iterator_Type>
412 (t,n, x, y, F, it);
413 }
414 }
415}
416
417} // -- namespace internal
418} // -- namespace lal
tree_type
Enumeration of several types of trees.
Definition tree_type.hpp:55
Main namespace of the library.
Definition definitions.hpp:48
std::pair< node, node > edge
Edge type.
Definition definitions.hpp:75
uint32_t node
Node type.
Definition definitions.hpp:51