LAL: Linear Arrangement Library 24.10.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
tree_maximum_caterpillar.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#include <tuple>
46
47// lal includes
48#include <lal/graphs/tree_type.hpp>
49#include <lal/graphs/tree.hpp>
50#include <lal/detail/graphs/traversal.hpp>
51#include <lal/detail/array.hpp>
52#include <lal/detail/queue_array.hpp>
53#include <lal/detail/type_traits/conditional_list.hpp>
54
55namespace lal {
56namespace detail {
57namespace maximum_subtrees {
58namespace caterpillar {
59
83
97template <class tree_t>
99(
100 const tree_t& t,
101 const node start_at,
102 BFS<tree_t>& bfs,
103 array<uint64_t>& num_vertices_in_path,
104 array<uint64_t>& weight
105)
106noexcept
107{
108 const auto n = t.get_num_nodes();
109
110 bfs.reset();
111 bfs.set_use_rev_edges( BFS<tree_t>::is_graph_directed );
112
113 num_vertices_in_path.fill(0);
114 num_vertices_in_path[start_at] = 1;
115 uint64_t max_num_vertices = 0;
116
117 node farthest = n + 1;
118
119 bfs.set_process_neighbour(
120 [&](const auto&, node u, node v, bool) {
121 num_vertices_in_path[v] = num_vertices_in_path[u] + weight[u] + 1;
122 if (max_num_vertices < num_vertices_in_path[v]) {
123 max_num_vertices = num_vertices_in_path[v];
124 farthest = v;
125 }
126 }
127 );
128 bfs.start_at(start_at);
129
130 return farthest;
131}
132
147template <
148 result ret_type,
149 class tree_t,
150 std::enable_if_t< std::is_base_of_v<graphs::tree, tree_t>, bool > = true
151>
152[[nodiscard]]
155 ret_type == result::distance,
156 ret_type == result::distance_vertices,
158 >,
160 uint64_t,
161 std::tuple<uint64_t, std::vector<char>>,
162 std::tuple<uint64_t, std::vector<node>, std::vector<char>>
163 >
164>
165max_subtree(const tree_t& t) noexcept
166{
167 typedef std::vector<node> path;
168
169 const auto n = t.get_num_nodes();
170
171 // the easiest case: we know the tree is a caterpillar
172 if (t.is_tree_type_valid() and t.is_of_tree_type(graphs::tree_type::caterpillar)) {
173 if constexpr (ret_type == result::distance) {
174 return 0;
175 }
176 else if constexpr (ret_type == result::distance_vertices) {
177 return {0, std::vector<char>(n, 1)};
178 }
179
180 // if the value to return contains the caterpillar's backbone, then
181 // we basically need to repeat the code below.
182 }
183
184 // more difficult case: we have no clue what the input tree is.
185
186 if (n == 1) {
187 if constexpr (ret_type == result::distance) {
188 return 0;
189 }
190 else if constexpr (ret_type == result::distance_vertices) {
191 return {0, {1}};
192 }
193 else {
194 return {0, {0}, {1}};
195 }
196 }
197 if (n == 2) {
198 if constexpr (ret_type == result::distance) {
199 return 0;
200 }
201 else if constexpr (ret_type == result::distance_vertices) {
202 return {0, {1,1}};
203 }
204 else {
205 return {0, {0,1}, {1,1}};
206 }
207 }
208
209 // -------------------------------------------------------------------------
210 // initialize data
211
212 array<uint64_t> weight(n);
213 for (node u = 0; u < n; ++u) {
214 weight[u] = (t.get_degree(u) == 1 ? 0 : t.get_degree(u) - 2);
215 }
216
217 // the traversal object
218 BFS bfs(t);
219
220 // distance to every vertex from source
221 array<uint64_t> num_vertices_in_path(n, 0);
222
223 // -------------------------------------------------------------------------
224 // do the two traversals
225
226 // v_star: farthest from source
227 // w_star: farthest from v_star
228
229 // traverse the tree and find the first 'farthest' vertex (v_star)
230 const node v_star = find_farthest_vertex(t, 0, bfs, num_vertices_in_path, weight);
231
232 // traverse the tree again and find the second 'farthest' vertex (w_star)
233 const node w_star = find_farthest_vertex(t, v_star, bfs, num_vertices_in_path, weight);
234
235 // calculate the caterpillar distance
236 const auto caterpillar_distance = n - num_vertices_in_path[w_star];
237
238 // The result is just the caterpillar distance.
239 // Regardless of the type of input tree, return 'caterpillar_distance'
240 if constexpr (ret_type == result::distance) {
241 return caterpillar_distance;
242 }
243
244 // We detected that the input tree is a caterpillar tree.
245 // In case the caterpillar distance is 0, the return result
246 // may be easy to calculate.
247 if (caterpillar_distance == 0) {
248 if constexpr (ret_type == result::distance_vertices) {
249 return {caterpillar_distance, std::vector<char>(n,1)};
250 }
251
252 // Unfortunately, when (ret_type == max_caterpillar_result::distance_structure)
253 // we have to compute the backbone
254 }
255
256 /* We have to do all of this even if
257 *
258 * (ret_type == max_caterpillar_result::distance_vertices)
259 */
260
261 // sequence of vertices that define the caterpillar's backbone
262 path maximum_caterpillar_backbone;
263
264 // the set of nodes in the maximum spanning caterpillar
265 std::vector<char> is_node_in_maximum_caterpillar(n, 0);
266
267 // path to the current vertex in the traversal
268 path path_to_current;
269
270 // initialize the queue
271 queue_array<path> path_queue;
272 path_queue.init(n);
273 path_queue.push({w_star});
274
275 // set up the BFS
276 bfs.reset();
277 bfs.set_use_rev_edges( BFS<tree_t>::is_graph_directed );
278
279 bfs.set_process_current(
280 [&](const auto&, node) {
281 path_to_current = path_queue.pop();
282 });
283
284 bfs.set_terminate(
285 [&](const auto&, node u) {
286 if (u == v_star) {
287 maximum_caterpillar_backbone = std::move(path_to_current);
288 }
289 return u == v_star;
290 });
291
292 bfs.set_process_neighbour(
293 [&](const auto&, node, node v, bool) {
294 auto path_to_v = path_to_current;
295 path_to_v.push_back(v);
296 path_queue.push(std::move(path_to_v));
297 });
298
299 // retrieve the backbone
300 bfs.start_at(w_star);
301
302 // find all vertices in the caterpillar by traversing the backbone
303 for (node u : maximum_caterpillar_backbone) {
304 is_node_in_maximum_caterpillar[u] = 1;
305 if constexpr (not BFS<tree_t>::is_graph_directed) {
306 for (node v : t.get_neighbors(u)) {
307 is_node_in_maximum_caterpillar[v] = 1;
308 }
309 }
310 else {
311 for (node v : t.get_in_neighbors(u)) {
312 is_node_in_maximum_caterpillar[v] = 1;
313 }
314 for (node v : t.get_out_neighbors(u)) {
315 is_node_in_maximum_caterpillar[v] = 1;
316 }
317 }
318 }
319
320 if constexpr (ret_type == result::distance_vertices) {
321 return {
322 caterpillar_distance,
323 std::move(is_node_in_maximum_caterpillar)
324 };
325 }
326 else if constexpr (ret_type == result::distance_structure) {
327 return {
328 caterpillar_distance,
329 std::move(maximum_caterpillar_backbone),
330 std::move(is_node_in_maximum_caterpillar)
331 };
332 }
333 else {
334 // never reached;
335#if defined DEBUG
336 assert(false);
337#endif
338 return 0;
339 }
340}
341
342} // -- namespace caterpillar
343} // -- namespace maximum_subtrees
344} // -- namespace detail
345} // -- 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
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
conditional_list_t< bool_sequence< ret_type==result::distance, ret_type==result::distance_vertices, ret_type==result::distance_structure >, type_sequence< uint64_t, std::tuple< uint64_t, std::vector< char > >, std::tuple< uint64_t, std::vector< node >, std::vector< char > > > > max_subtree(const tree_t &t) noexcept
Calculate the maximum spanning caterpillar of a tree.
Definition tree_maximum_caterpillar.hpp:165
result
What is to be calculated when finding the maximum spanning caterpillar.
Definition tree_maximum_caterpillar.hpp:61
@ distance_structure
Caterpillar distance plus the caterpillar's structure.
Definition tree_maximum_caterpillar.hpp:81
@ distance
Only the caterpillar distance.
Definition tree_maximum_caterpillar.hpp:63
@ distance_vertices
Caterpillar distance plus caterpillar structure's nodes.
Definition tree_maximum_caterpillar.hpp:70
node find_farthest_vertex(const tree_t &t, const node start_at, BFS< tree_t > &bfs, array< uint64_t > &num_vertices_in_path, array< uint64_t > &weight) noexcept
Find the farthest vertex from start_at in the tree.
Definition tree_maximum_caterpillar.hpp:99
typename conditional_list< bool_seq, type_seq >::type conditional_list_t
Shorthand for conditional_list.
Definition conditional_list.hpp:78
@ caterpillar
Caterpillar trees.
Main namespace of the library.
Definition basic_types.hpp:48
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
A sequence of Boolean values.
Definition bool_sequence.hpp:52
A sequence of types.
Definition type_sequence.hpp:51