LAL: Linear Arrangement Library 24.10.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
tree_centroid.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 - 2024
7 *
8 * This file is part of Linear Arrangement Library. The full code is available
9 * at:
10 * https://github.com/LAL-project/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 (lluis.alemany.puig@upc.edu)
28 * LQMC (Quantitative, Mathematical, and Computational Linguisitcs)
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 * LQMC (Quantitative, Mathematical, and Computational Linguisitcs)
35 * CQL (Complexity and Quantitative Linguistics Lab)
36 * Office 220, 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 <vector>
49
50// lal includes
51#include <lal/graphs/output.hpp>
52#include <lal/basic_types.hpp>
53#include <lal/graphs/rooted_tree.hpp>
54#include <lal/detail/graphs/size_subtrees.hpp>
55#include <lal/detail/sorting/counting_sort.hpp>
56#include <lal/detail/pairs_utils.hpp>
57#include <lal/detail/queue_array.hpp>
58#include <lal/detail/graphs/traversal.hpp>
59#include <lal/detail/type_traits/conditional_list.hpp>
60
61namespace lal {
62namespace detail {
63
79
81inline constexpr bool is_m1(const centroid_results& m) noexcept {
83}
85inline constexpr bool is_m2(const centroid_results& m) noexcept {
87}
89inline constexpr bool is_m3(const centroid_results& m) noexcept {
91}
93inline constexpr bool is_m4(const centroid_results& m) noexcept {
95}
96
123template <
124 centroid_results mode,
125 class tree_t,
126 std::enable_if_t<std::is_base_of_v<graphs::tree, tree_t>, bool> = true
127>
128[[nodiscard]]
130 bool_sequence<
131 is_m1(mode),
132 is_m2(mode),
133 is_m3(mode),
134 is_m4(mode)
135 >,
136 type_sequence<
137 node,
138 std::pair<node, node>,
139 std::pair<std::pair<node, node>, array<uint64_t>>,
140 std::pair<std::pair<node, node>, array<edge_size>>
141 >
142>
143find_centroidal_vertex(const tree_t& t, const node x) noexcept
144{
145 const auto n = t.get_num_nodes();
146 const auto size_cc_x = t.get_num_nodes_component(x);
147
148 if (size_cc_x == 1) {
149 if constexpr (is_m1(mode)) {
150 return x;
151 }
152 else if constexpr (is_m2(mode)) {
153 return {x,2};
154 }
155 else if constexpr (is_m3(mode)) {
156 array<uint64_t> s(n, 0);
157 s[x] = 1;
158 return {{x,2}, std::move(s)};
159 }
160 else if constexpr (is_m4(mode)) {
161 return {{x,2}, array<edge_size>{}};
162 }
163 }
164 if (size_cc_x == 2) {
165 auto only_neigh = [&]() {
166 if constexpr (std::is_base_of_v<graphs::free_tree, tree_t>) {
167 return t.get_neighbors(x)[0];
168 }
169 else {
170 if (t.get_out_degree(x) == 0) { return t.get_in_neighbors(x)[0]; }
171 else { return t.get_out_neighbors(x)[0]; }
172 }
173 }();
174
175 const node u = (x < only_neigh ? x : only_neigh);
176 const node v = is_m1(mode) ? 0 : (x < only_neigh ? only_neigh : x);
177
178 if constexpr (is_m1(mode)) {
179 return u;
180 }
181 else if constexpr (is_m2(mode)) {
182 return {u, v};
183 }
184 else if constexpr (is_m3(mode)) {
185 array<uint64_t> s(n, 0);
186 s[u] = 2;
187 s[v] = 1;
188 return {{u, v}, std::move(s)};
189 }
190 else if constexpr (is_m4(mode)) {
191 return {
192 {u, v},
193 array<edge_size>{ {{u, v}, 1} }
194 };
195 }
196 }
197
198 const auto ndiv2 = size_cc_x/2 + size_cc_x%2;
199
200 // the centroidal vertices, initialized to invalid values
201 node c1 = n + 1;
202 node c2 = n + 1;
203
204 // weight of every node: needed to detect the centroid.
205 array<uint64_t> weight(n, 1);
206 // degree of every vertex: needed to find leaves
207 array<uint64_t> degree(n, 0);
208 // array of pairs of edge and directional size
209 array<edge_size> edge_sizes;
210 std::size_t idx_edge_sizes = 0;
211 if constexpr (is_m4(mode)) {
212 edge_sizes.resize(size_cc_x - 1);
213 }
214
215 // queue of the traversal
216 queue_array<node> queue;
217 queue.init(size_cc_x);
218
219 // push leaves of the connected component into the queue.
220 if (size_cc_x < n/2) {
221 BFS<tree_t> bfs(t);
222 bfs.set_use_rev_edges(std::is_base_of_v<graphs::rooted_tree, tree_t>);
223 bfs.set_process_current(
224 [&](const auto&, const node u) {
225 degree[u] = t.get_degree(u);
226 // fill queue
227 if (t.get_degree(u) == 1) {
228 queue.push(u);
229 }
230 }
231 );
232 bfs.start_at(x);
233 }
234 else {
235 for (node u = 0; u < n; ++u) {
236 if (t.get_component_representative(u) == t.get_component_representative(x)) {
237 degree[u] = t.get_degree(u);
238 if (t.get_degree(u) == 1) {
239 queue.push(u);
240 }
241 }
242 }
243 }
244
245 // find centroid.
246 while (queue.size() > 0) {
247 // current node
248 const node u = queue.pop();
249
250 if (weight[u] >= ndiv2) {
251 if (c1 >= size_cc_x) {
252 // if the user requested just one centroidal vertex,
253 // stop now, there is no need to go on.
254 if constexpr (is_m1(mode)) { return u; }
255
256 c1 = u;
257 }
258 else {
259 c2 = u;
260 }
261 continue;
262 }
263
264 // "delete" vertex u
265 --degree[u];
266#if defined DEBUG
267 assert(degree[u] == 0);
268#endif
269
270 // append a new leaf to the queue
271 if constexpr (std::is_base_of_v<graphs::free_tree, tree_t>) {
272 for (const node v : t.get_neighbors(u)) {
273 if (degree[v] == 0) { continue; }
274
275 --degree[v];
276 weight[v] += weight[u];
277 if (degree[v] == 1) {
278 queue.push(v);
279 }
280
281 if constexpr (is_m4(mode)) {
282 edge_sizes[idx_edge_sizes++] = {{v,u}, weight[u]};
283 }
284 }
285 }
286 else {
287 for (const node v : t.get_in_neighbors(u)) {
288 if (degree[v] == 0) { continue; }
289
290 --degree[v];
291 weight[v] += weight[u];
292 if (degree[v] == 1) {
293 queue.push(v);
294 }
295
296 if constexpr (is_m4(mode)) {
297 edge_sizes[idx_edge_sizes++] = {{v,u}, weight[u]};
298 }
299 }
300 for (const node v : t.get_out_neighbors(u)) {
301 if (degree[v] == 0) { continue; }
302
303 --degree[v];
304 weight[v] += weight[u];
305 if (degree[v] == 1) {
306 queue.push(v);
307 }
308
309 if constexpr (is_m4(mode)) {
310 edge_sizes[idx_edge_sizes++] = {{v,u}, weight[u]};
311 }
312 }
313 }
314 }
315
316 if (c2 < n) {
317 if (c1 > c2) {
318 std::swap(c1, c2);
319 }
320 weight[c1] += weight[c2];
321
322 if constexpr (is_m4(mode)) {
323 edge_sizes[idx_edge_sizes++] = {{c1,c2}, weight[c2]};
324 }
325 }
326
327#if defined DEBUG
328 if constexpr (is_m4(mode)) {
329 assert(idx_edge_sizes == edge_sizes.size());
330 }
331#endif
332
333 if constexpr (is_m2(mode)) {
334 return {c1, c2};
335 }
336 else if constexpr (is_m3(mode)) {
337 return {{c1, c2}, std::move(weight)};
338 }
339 else if constexpr (is_m4(mode)) {
340 return {{c1, c2}, std::move(edge_sizes)};
341 }
342}
343
355template <
356 class tree_t,
357 std::enable_if_t<std::is_base_of_v<graphs::tree, tree_t>, bool> = true
358>
359[[nodiscard]] std::pair<node,node> centroidal_vertex_plus_adjacency_list
360(
361 const tree_t& t,
362 const node x,
363 std::vector< std::vector<node_size> >& L
364)
365noexcept
366{
367 // retrieve centroid and set of edges and directional size
368 std::pair< std::pair<node,node>, array<edge_size> >
369 centroid_subtree_sizes =
371
372 const uint64_t n = t.get_num_nodes();
373
374 // sort the edges by directional size
377 (
378 centroid_subtree_sizes.second.begin(),
379 centroid_subtree_sizes.second.end(),
380 n,
381 centroid_subtree_sizes.second.size(),
382 [](const edge_size& edge_pair) -> std::size_t
383 { return edge_pair.size; }
384 );
385
386 // fill (already-rooted) adjacency matrix
387 L.resize(n);
388 for (const auto& [uv, suv] : centroid_subtree_sizes.second) {
389 const auto [u, v] = uv;
390 L[u].push_back({v, suv});
391 }
392
393 return centroid_subtree_sizes.first;
394}
395
396// -----------------------------------------------------------------------------
397
411template <
412 class tree_t,
413 std::enable_if_t< std::is_base_of_v<graphs::tree, tree_t>, bool > = true
414>
415[[nodiscard]] std::pair<node, node> retrieve_centroid
416(const tree_t& t, const node x = 0)
417noexcept
418{
420}
421
422} // -- namespace detail
423} // -- namespace lal
Abstract graph Breadth-First Search traversal.
Definition traversal.hpp:89
Simple array-like fixed-size queue.
Definition queue_array.hpp:69
void init(const std::size_t n) noexcept
Initializes the queue to hold n elements.
Definition queue_array.hpp:72
std::size_t size() const noexcept
Returns the size of the queue.
Definition queue_array.hpp:121
value_t && pop() noexcept
Pops the first element of the queue.
Definition queue_array.hpp:98
void push(const value_t &v) noexcept
Insert a new element to the queue.
Definition queue_array.hpp:79
@ non_increasing
Non-increasing sort.
void counting_sort(const value_iterator_t begin, const value_iterator_t end, const std::size_t largest_key_plus_1, const Callable &key, countingsort::memory< value_t > &mem) noexcept
Counting sort algorithm with reusable memory.
Definition counting_sort.hpp:152
constexpr bool is_m1(const centroid_results &m) noexcept
Is mode m equal to lal::detail::centroid_results::only_one_centroidal.
Definition tree_centroid.hpp:81
std::pair< node, node > retrieve_centroid(const tree_t &t, const node x=0) noexcept
Calculate the centroid of the connected component that has node x.
Definition tree_centroid.hpp:416
constexpr bool is_m3(const centroid_results &m) noexcept
Is mode m equal to lal::detail::centroid_results::full_centroid_plus_subtree_sizes.
Definition tree_centroid.hpp:89
centroid_results
The different types of results.
Definition tree_centroid.hpp:65
@ full_centroid_plus_edge_sizes
Returns the full centroid of the tree. Also returns the edge_size array.
@ full_centroid
Returns the full centroid of the tree. No weights.
@ only_one_centroidal
Returns only one centroidal vertex. No weights.
@ full_centroid_plus_subtree_sizes
Returns the full centroid of the tree. Also returns the weights.
constexpr bool is_m2(const centroid_results &m) noexcept
Is mode m equal to lal::detail::centroid_results::full_centroid.
Definition tree_centroid.hpp:85
typename conditional_list< bool_seq, type_seq >::type conditional_list_t
Shorthand for conditional_list.
Definition conditional_list.hpp:78
std::pair< node, node > centroidal_vertex_plus_adjacency_list(const tree_t &t, const node x, std::vector< std::vector< node_size > > &L) noexcept
Calculates the centroid and the corresponding rooted adjacency list.
Definition tree_centroid.hpp:360
constexpr bool is_m4(const centroid_results &m) noexcept
Is mode m equal to lal::detail::centroid_results::full_centroid_plus_edge_sizes.
Definition tree_centroid.hpp:93
conditional_list_t< bool_sequence< is_m1(mode), is_m2(mode), is_m3(mode), is_m4(mode) >, type_sequence< node, std::pair< node, node >, std::pair< std::pair< node, node >, array< uint64_t > >, std::pair< std::pair< node, node >, array< edge_size > > > > find_centroidal_vertex(const tree_t &t, const node x) noexcept
Calculates the centroid of a tree.
Definition tree_centroid.hpp:143
Main namespace of the library.
Definition basic_types.hpp:48
std::pair< edge, edge > edge_pair
Edge pair type.
Definition basic_types.hpp:62
uint64_t node
Node type. See Node / Vertex page for further details.
Definition basic_types.hpp:51
Wrapper of a C array for automatic deallocation of memory.
Definition array.hpp:59
std::size_t size() const noexcept
Size of the array.
Definition array.hpp:215
void resize(const std::size_t new_size) noexcept
Resize the array.
Definition array.hpp:187
Struct used in many algorithms to sort edges according to some integer value.
Definition pairs_utils.hpp:65