LAL: Linear Arrangement Library 21.07.01
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
conversions.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// C++ includes
43#if defined DEBUG
44#include <cassert>
45#endif
46#include <optional>
47
48// lal includes
49#include <lal/definitions.hpp>
50#include <lal/graphs/free_tree.hpp>
51#include <lal/graphs/rooted_tree.hpp>
52#include <lal/internal/data_array.hpp>
53
54namespace lal {
55namespace internal {
56
57// -----------------------------------------------------------------------------
58// -- HEAD VECTOR --
59
60/* Constructs the head vector representation of a tree.
61 */
62inline head_vector from_tree_to_head_vector(const graphs::rooted_tree& t)
63noexcept
64{
65#if defined DEBUG
66 assert(t.is_rooted_tree());
67#endif
68
69 const uint32_t n = t.get_num_nodes();
70 head_vector hv(n);
71 for (node u = 0; u < n; ++u) {
72 if (u == t.get_root()) {
73 hv[u] = 0;
74 }
75 else {
76 // this is guaranteed to be a legal access (within bounds).
77 hv[u] = t.get_in_neighbours(u)[0] + 1;
78 }
79 }
80 return hv;
81}
82
83/* Constructs the head vector representation of a tree.
84 */
85inline head_vector from_tree_to_head_vector(const graphs::free_tree& t, node r)
86noexcept
87{
88#if defined DEBUG
89 assert(t.is_tree());
90#endif
91 return from_tree_to_head_vector(graphs::rooted_tree(t,r));
92}
93
94/* Converts a head vector into a tree
95 */
96template<
97 class tree_type,
98 bool is_rooted = std::is_base_of_v<graphs::rooted_tree, tree_type>
99>
100std::conditional_t<
101 is_rooted,
102 graphs::rooted_tree,
103 std::pair<graphs::free_tree,node>
104>
105from_head_vector_to_tree
106(const head_vector& hv, bool normalise, bool check)
107noexcept
108{
109 if (hv.size() == 0) {
110 if constexpr (is_rooted) {
111 return graphs::rooted_tree(0);
112 }
113 else {
114 return std::make_pair(graphs::free_tree(0), 0);
115 }
116 }
117 if (hv.size() == 1) {
118#if defined DEBUG
119 // the only vertex can only be the root
120 assert(hv[0] == 0);
121#endif
122 if constexpr (is_rooted) {
123 return graphs::rooted_tree(1);
124 }
125 else {
126 return std::make_pair(graphs::free_tree(1), 0);
127 }
128 }
129
130 const uint32_t n = static_cast<uint32_t>(hv.size());
131
132 // output tree
133 tree_type t(n);
134
135 // root node of the tree
136 std::optional<node> r;
137
138#if defined DEBUG
139 uint32_t num_edges_added = 0;
140#endif
141
142 for (uint32_t i = 0; i < n; ++i) {
143 if (hv[i] == 0) {
144 // root, do nothing
145 r = i;
146 }
147 else {
148 // note:
149 // * i ranges in [0,n-1]
150 // * L[i] ranges in [1,n] (hence the '-1')
151
152 // In the head vector the edge (i, hv[i] - 1) is an edge of an
153 // anti-arborescence. Since for our rooted trees we need the edge
154 // of an arborescence, then we add the edge as (hv[i] - 1, i).
155 // For free trees the order of vertices does not matter.
156 t.add_edge_bulk(hv[i] - 1, i);
157
158#if defined DEBUG
159 ++num_edges_added;
160#endif
161 }
162 }
163
164#if defined DEBUG
165 // root must have been set
166 assert(r);
167 // amount of edges added must be 'n-1'
168 assert(num_edges_added == n - 1);
169#endif
170
171 t.finish_bulk_add(normalise, check);
172
173 if constexpr (is_rooted) {
174 t.set_root(*r);
175 t.set_valid_orientation(true);
176#if defined DEBUG
177 assert(t.is_rooted_tree());
178#endif
179
180 return t;
181 }
182 else {
183#if defined DEBUG
184 assert(t.is_tree());
185#endif
186
187 return std::make_pair(t, *r);
188 }
189}
190
191// -----------------------------------------------------------------------------
192// -- LEVEL SEQUENCE --
193
194/*
195 * @brief Converts the level sequence of a tree into a graph structure.
196 *
197 * Examples of level sequences:
198 * -- linear tree of n nodes:
199 * 0 1 2 3 4 ... (n-1) n
200 * -- star tree of n nodes
201 * 0 1 2 2 2 .... 2 2
202 * |------------| > (n-1) two's
203 *
204 * @param L The level sequence, in preorder.
205 * @param n Number of nodes of the tree.
206 * @returns The tree built with the sequence level @e L.
207 * @pre n >= 2.
208 * @pre The size of L is exactly @e n + 1.
209 * @pre The first value of a sequence must be a zero.
210 * @pre The second value of a sequence must be a one.
211 */
212inline graphs::free_tree level_sequence_to_ftree
213(const uint32_t * const L, uint32_t n, bool normalise = true, bool check = true)
214noexcept
215{
216#if defined DEBUG
217 // a little sanity check
218 assert(L[0] == 0);
219 assert(L[1] == 1);
220#endif
221
222 // output tree
223 graphs::free_tree t(n);
224
225 // 'stack' of root candidates: node at every level in {1,...,N}.
226 // at position j, lev[j] contains the last node added at level j.
227 data_array<node> lev(n+1, 0);
228 uint32_t stack_it = 0;
229
230 // evidently,
231 lev[0] = 1;
232
233 for (node i = 2; i <= n; ++i) {
234 // find in the stack the node which
235 // has to be connected to node 'i'.
236 if (lev[stack_it] + 2 > L[i]) {
237 stack_it = L[i] - 2 + 1;
238 }
239
240 // the top of the stack is the parent of this node
241 const node r = lev[stack_it];
242
243 // add the edge...
244 const auto [u,v] = (r == 0 ? edge(r, i - 1) : edge(r - 1, i - 1));
245 t.add_edge_bulk(u, v);
246
247 // the last node added at level L[i] is i.
248 ++stack_it;
249#if defined DEBUG
250 assert(stack_it == L[i]);
251#endif
252 lev[stack_it] = i;
253 }
254
255 t.finish_bulk_add(normalise, check);
256 return t;
257}
258
259inline graphs::free_tree level_sequence_to_ftree
260(const std::vector<uint32_t>& L, uint32_t n, bool normalise = true, bool check = true)
261noexcept
262{ return level_sequence_to_ftree(&L[0], n, normalise, check); }
263
264// -----------------------------------------------------------------------------
265// -- PRUFER SEQUENCE --
266
267/*
268 * @brief Converts the Prüfer sequence of a labelled tree into a tree structure.
269 *
270 * For details on Prüfer sequences, see \cite Pruefer1918a.
271 *
272 * The algorithm used to decode the sequence is the one presented in
273 * \cite Alonso1995a.
274 * @param S The Prufer sequence sequence.
275 * @param n Number of nodes of the tree.
276 * @returns The tree built with @e L.
277 */
278inline graphs::free_tree Prufer_sequence_to_ftree
279(const uint32_t * const seq, uint32_t n, bool normalise = true, bool check = true)
280noexcept
281{
282 // initialisation
283 const uint32_t L = n - 2;
284 data_array<uint32_t> degree(n, 1);
285 for (uint32_t i = 0; i < L; ++i) {
286 degree[ seq[i] ] += 1;
287 }
288
289 // the output tree
290 graphs::free_tree t(n);
291
292 // for each number in the sequence seq[i], find the first
293 // lowest-numbered node, j, with degree equal to 1, add
294 // the edge (j, seq[i]) to the tree, and decrement the degrees
295 // of j and seq[i].
296 for (uint32_t v = 0; v < L; ++v) {
297 const auto value = seq[v];
298 bool node_found = false;
299 node w = 0;
300 while (w < n and not node_found) {
301 if (degree[w] == 1) {
302 t.add_edge_bulk(value, w);
303
304 degree[value] -= 1;
305 degree[w] -= 1;
306 node_found = true;
307 }
308 ++w;
309 }
310 }
311
312 // two nodes u,v with degree 1 remain. Find them
313 node u, v;
314 u = v = n;
315 for (node w = 0; w < n; ++w) {
316 if (degree[w] == 1) {
317 if (u == n) {
318 u = w;
319 }
320 else {
321 v = w;
322 }
323 }
324 }
325
326 // add edge (u,v) to the tree
327 t.add_edge_bulk(u, v);
328 t.finish_bulk_add(normalise, check);
329 return t;
330}
331
332inline graphs::free_tree Prufer_sequence_to_ftree
333(const std::vector<uint32_t>& S, uint32_t n, bool normalise = true, bool check = true)
334noexcept
335{ return Prufer_sequence_to_ftree(&S[0], n, normalise, check); }
336
337
338} // -- namespace internal
339} // -- 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
std::vector< uint32_t > head_vector
A head vector representation of a (usually) rooted tree.
Definition definitions.hpp:114