LAL: Linear Arrangement Library 24.10.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
utils.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 * Juan Luis Esteban (esteban@cs.upc.edu)
34 * LOGPROG: Logics and Programming Research Group
35 * Office 110, Omega building
36 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
37 * Webpage: https://www.cs.upc.edu/~esteban/
38 *
39 * Ramon Ferrer i Cancho (rferrericancho@cs.upc.edu)
40 * LQMC (Quantitative, Mathematical, and Computational Linguisitcs)
41 * CQL (Complexity and Quantitative Linguistics Lab)
42 * Office 220, Omega building
43 * Jordi Girona St 1-3, Campus Nord UPC, 08034 Barcelona. CATALONIA, SPAIN
44 * Webpage: https://cqllab.upc.edu/people/rferrericancho/
45 *
46 ********************************************************************/
47
48#pragma once
49
50// C++ includes
51#if defined DEBUG
52#include <optional>
53#include <cassert>
54#endif
55#include <vector>
56
57// lal includes
58#include <lal/linear_arrangement.hpp>
59#include <lal/graphs/rooted_tree.hpp>
60#include <lal/detail/array.hpp>
61#include <lal/iterators/E_iterator.hpp>
62#include <lal/detail/graphs/size_subtrees.hpp>
63#include <lal/detail/sorting/counting_sort.hpp>
64#include <lal/detail/properties/tree_centroid.hpp>
65#include <lal/detail/macros/basic_convert.hpp>
66#include <lal/detail/linarr/D/Dopt_utils.hpp>
67
68namespace lal {
69namespace detail {
70
72namespace Dmin_utils {
73
74/* ************************************************************************** */
75/* ---------------------- INTERVAL-based methods ---------------------------- */
76
77/* The following namespace contains functions for the interval-based algorithms
78 * to calculate the planar and projective minimum sum of edge lengths.
79 */
80
109template <bool make_arrangement>
110[[nodiscard]] uint64_t arrange
111(
112 const std::vector<std::vector<node_size>>& L,
113 const node r,
114 const Dopt_utils::place r_place,
115 position ini,
116 position fin,
118)
119noexcept
120{
121#if defined DEBUG
122 assert(ini <= fin);
123#endif
124
125 // the children and the sizes of the subtrees of 'r'
126 const auto& children_size_of_r = L[r];
127
128 // -- place the children --
129
130 // work out the starting side of the first-largest subtree
131 Dopt_utils::side roots_side =
132 r_place == Dopt_utils::PLACE_RIGHT_OF ?
135
136 // size of the intervals from the root to the left end
137 uint64_t acc_size_left = 0;
138 // size of the intervals from the root to the right end
139 uint64_t acc_size_right = 0;
140
141 // number of intervals to the left of the root
142 uint64_t n_intervals_left = 0;
143 // number of intervals to the right of the root
144 uint64_t n_intervals_right = 0;
145
146 // sum of the optimal D for every subtree +
147 // the length of the edge from 'r' to its parent (if any)
148 uint64_t D = 0;
149 // total sum of lengths of edges from 'r' to 'vi' without the anchor
150 uint64_t d = 0;
151
152#if defined DEBUG
153 // store the size of the previous subtree (previous in the lists's sorted)
154 std::optional<uint64_t> previous_size;
155#endif
156
157 // while placing the children calculate the
158 // length of the edge from 'r' to vertex 'vi'
159 // LARGEST to SMALLEST
160 for (const auto& [vi, ni] : children_size_of_r) {
161
162#if defined DEBUG
163 // ensure that the list is sorted non-increasingly
164 if (previous_size) {
165 assert(*previous_size >= ni);
166 }
167 previous_size = {ni};
168#endif
169
170 // recursive call: make the interval of 'vi'
171 D +=
173 L, vi,
175 (make_arrangement ? (roots_side == Dopt_utils::LEFT_SIDE ? ini : fin - ni + 1) : 0),
176 (make_arrangement ? (roots_side == Dopt_utils::LEFT_SIDE ? ini + ni - 1 : fin) : 0),
177 arr
178 );
179
180 // accumulate size of interval
181 d += ni*(roots_side == Dopt_utils::LEFT_SIDE ? n_intervals_left : n_intervals_right);
182 // add length of edge over root 'r'
183 d += 1;
184
185 // number of intervals to the left and right of the root
186 n_intervals_left += roots_side;
187 n_intervals_right += Dopt_utils::other_side(roots_side);
188
189 // accumulate size of subtree rooted at vi
190 acc_size_left += roots_side*ni;
191 acc_size_right += Dopt_utils::other_side(roots_side)*ni;
192
193 // update limits of the embedding
194 if constexpr (make_arrangement) {
195 ini += roots_side*ni;
196 fin -= Dopt_utils::other_side(roots_side)*ni;
197 }
198
199 // change side
200 roots_side = Dopt_utils::other_side(roots_side);
201 }
202
203#if defined DEBUG
204 if constexpr (make_arrangement) {
205 assert(ini == fin);
206 }
207#endif
208 if constexpr (make_arrangement) {
209 arr.assign(r, ini);
210 }
211
212 // accumulate the length of the edge from 'r' to its parent (if any)
213 D +=
214 (r_place == Dopt_utils::PLACE_NONE_OF ? 0 :
215 r_place == Dopt_utils::PLACE_LEFT_OF ? acc_size_right : acc_size_left);
216
217 return D + d;
218}
219
234template <bool make_arrangement>
235[[nodiscard]] inline uint64_t arrange_projective
236(
237 const uint64_t n,
238 const std::vector<std::vector<node_size>>& L,
239 const node r,
241)
242noexcept
243{
244 return arrange<make_arrangement>(L, r, Dopt_utils::PLACE_NONE_OF, 0, n-1, arr);
245}
246
247/* ************************************************************************** */
248/* ----------------- DISPLACEMENT-based methods namespace ------------------- */
249
250/* The following namespace contains functions for the interval-based algorithms
251 * to calculate the planar and projective minimum sum of edge lengths.
252 */
253
254
273template <bool make_arrangement>
274[[nodiscard]] uint64_t embed_branch
275(
276 const std::vector<std::vector<node_size>>& L,
277 const node v,
278 int64_t base,
279 const int64_t dir,
280 array<int64_t>& rel_pos
281)
282noexcept
283{
284 const auto& Cv = L[v];
285 uint64_t cost_branch = 0;
286
287 uint64_t before = 0;
288 uint64_t after = 0;
289 uint64_t under_anchor = 0;
290
291 // LARGEST to SMALLEST
292 // (only at even positions of the list, which are indexed at odd values...)
293 for (std::size_t i = 1; i < Cv.size(); i += 2) {
294 under_anchor += Cv[i].size;
295 }
296
297 if constexpr (make_arrangement) {
298 base += dir*(to_int64(under_anchor) + 1);
299 }
300
301 cost_branch += under_anchor;
302
303 // Index of the positions of Cv. The interval it iterates is [Cv.size(), 1]
304 // (and not the usual [Cv.size()-1, 0]) to ensure we are using the right
305 // parities (even/odd).
306 uint64_t i = Cv.size();
307
308 // SMALLEST to LARGEST
309 for (auto it = Cv.rbegin(); it != Cv.rend(); ++it, --i) {
310#if defined DEBUG
311 assert(i <= Cv.size());
312#endif
313
314 const auto& [vi, ni] = *it;
315
316 cost_branch +=
318 L, vi,
319 make_arrangement ?
320 Dopt_utils::is_even(i) ? base - dir*to_int64(before) : base + dir*to_int64(after)
321 : 0
322 ,
323 make_arrangement ?
324 Dopt_utils::is_even(i) ? -dir : dir
325 : 0
326 ,
327 rel_pos
328 );
329 cost_branch += ( Dopt_utils::is_even(i) ? before : after );
330
331 before += (Dopt_utils::is_even(i) ? ni : 0);
332 after += (Dopt_utils::is_even(i) ? 0 : ni);
333
334 cost_branch += 1;
335 }
336
337 if constexpr (make_arrangement) {
338 rel_pos[v] = base;
339 }
340 return cost_branch;
341}
342
358template <bool make_arrangement>
359[[nodiscard]] uint64_t embed
360(
361 const std::vector<std::vector<node_size>>& L,
362 const node r,
364)
365noexcept
366{
367 const uint64_t n = L.size();
368 uint64_t D = 0;
369
370 array<int64_t> rel_pos(n, 0);
371 uint64_t left_sum = 0;
372 uint64_t right_sum = 0;
373
374 uint64_t i = L[r].size();
375
376 // SMALLEST to LARGEST
377 for (auto it = L[r].rbegin(); it != L[r].rend(); ++it, --i) {
378 const auto& [vi, ni] = *it;
379#if defined DEBUG
380 assert(i <= L[r].size());
381#endif
382
383 D +=
385 L, vi,
386 make_arrangement ?
387 Dopt_utils::is_even(i) ? to_int64(right_sum) : -to_int64(left_sum)
388 : 0
389 ,
390 make_arrangement ?
392 : 0
393 ,
394 rel_pos
395 );
396 D += ( Dopt_utils::is_even(i) ? right_sum : left_sum );
397
398 right_sum += (Dopt_utils::is_even(i) ? ni : 0);
399 left_sum += (Dopt_utils::is_even(i) ? 0 : ni);
400
401 D += 1;
402 }
403
404 // the '-1' is used to offset the positions from [1,n] to [0,n-1]
405 if constexpr (make_arrangement) {
406 arr.assign(r, left_sum + 1 - 1);
407 rel_pos[r] = 0;
408 for (node v = 0; v < n; ++v) {
409 const int64_t pos = to_int64(arr[node_t{r}]) + rel_pos[v];
410#if defined DEBUG
411 assert(pos >= 0);
412#endif
413 arr.assign(v, to_uint64(pos));
414 }
415 }
416
417 return D;
418}
419
420} // -- namespcae Dmin_utils
421} // -- namespace detail
422} // -- namespace lal
Linear arrangement of vertices.
Definition linear_arrangement.hpp:103
uint64_t arrange_projective(const uint64_t n, const std::vector< std::vector< node_size > > &L, const node r, linear_arrangement &arr) noexcept
Wrapper method for the recursive method arrange.
Definition utils.hpp:236
uint64_t arrange(const std::vector< std::vector< node_size > > &L, const node r, const Dopt_utils::place r_place, position ini, position fin, linear_arrangement &arr) noexcept
Make a minimum projective arrangement using the sorted, rooted adjacency list L.
Definition utils.hpp:111
uint64_t embed_branch(const std::vector< std::vector< node_size > > &L, const node v, int64_t base, const int64_t dir, array< int64_t > &rel_pos) noexcept
Embed a tree's branch.
Definition utils.hpp:275
uint64_t embed(const std::vector< std::vector< node_size > > &L, const node r, linear_arrangement &arr) noexcept
Embed a tree's branch.
Definition utils.hpp:360
unsigned char side
Useful typedef to denote relative position.
Definition Dopt_utils.hpp:74
static constexpr side other_side(side s) noexcept
Other side of a vertex. If s is RIGHT_SIDE, returns LEFT_SIDE.
Definition Dopt_utils.hpp:91
static constexpr place PLACE_RIGHT_OF
A vertex is to be placed to the right of a vertex.
Definition Dopt_utils.hpp:79
static constexpr side LEFT_SIDE
Left side of a vertex.
Definition Dopt_utils.hpp:86
static constexpr side RIGHT_SIDE
Right side of a vertex.
Definition Dopt_utils.hpp:84
static constexpr bool is_even(uint64_t i) noexcept
Is an integer number even?
Definition Dopt_utils.hpp:94
static constexpr place PLACE_LEFT_OF
A vertex is to be placed to the left of a vertex.
Definition Dopt_utils.hpp:77
static constexpr place PLACE_NONE_OF
There is no vertex to use as reference to determine the side.
Definition Dopt_utils.hpp:81
unsigned char place
Useful typedef to denote relative position.
Definition Dopt_utils.hpp:72
constexpr int64_t to_int64(const T &t) noexcept
Conversion to int64_t.
Definition basic_convert.hpp:57
constexpr uint64_t to_uint64(const T &t) noexcept
Conversion to uint64_t.
Definition basic_convert.hpp:52
Main namespace of the library.
Definition basic_types.hpp:48
uint64_t position
Node's position type.
Definition basic_types.hpp:53
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
Typesafe node type.
Definition basic_types.hpp:70