LAL: Linear Arrangement Library 23.01.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
Dmin_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 - 2023
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 (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 * 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 * LARCA (Laboratory for Relational Algorithmics, Complexity and Learning)
41 * CQL (Complexity and Quantitative Linguistics Lab)
42 * Office S124, 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/data_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/Dopt_utils.hpp>
67
68namespace lal {
69namespace detail {
70
72namespace Dmin_utils {
73
74using namespace Dopt_utils;
75
76/* ************************************************************************** */
77/* ---------------------- INTERVAL-based methods ---------------------------- */
78
79/* The following namespace contains functions for the interval-based algorithms
80 * to calculate the planar and projective minimum sum of edge lengths.
81 */
82
111template <bool make_arrangement>
112uint64_t arrange
113(
114 const std::vector<std::vector<node_size>>& L,
115 const node r,
116 const place r_place,
117 position ini, position fin,
119)
120noexcept
121{
122#if defined DEBUG
123 assert(ini <= fin);
124#endif
125
126 // sizes of the subtrees
127 const auto& children = L[r];
128
129 // -- place the children --
130
131 // work out the starting side of the first-largest subtree
132 side roots_side = (r_place == PLACE_RIGHT_OF ? RIGHT_SIDE : LEFT_SIDE);
133
134 // size of the intervals from the root to the left end
135 uint64_t acc_size_left = 0;
136 // size of the intervals from the root to the right end
137 uint64_t acc_size_right = 0;
138
139 // number of intervals to the left of the root
140 uint64_t n_intervals_left = 0;
141 // number of intervals to the right of the root
142 uint64_t n_intervals_right = 0;
143
144 // sum of the optimal D for every subtree +
145 // the length of the edge from 'r' to its parent (if any)
146 uint64_t D = 0;
147 // total sum of lengths of edges from 'r' to 'vi' without the anchor
148 uint64_t d = 0;
149
150#if defined DEBUG
151 // store the size of the previous subtree (previous in the lists's sorted)
152 std::optional<uint64_t> previous_size;
153#endif
154
155 // while placing the children calculate the
156 // length of the edge from 'r' to vertex 'vi'
157 // LARGEST to SMALLEST
158 for (const auto& [vi, ni] : children) {
159
160#if defined DEBUG
161 // ensure that the list is sorted non-increasingly
162 if (previous_size) {
163 assert(*previous_size >= ni);
164 }
165 previous_size = {ni};
166#endif
167
168 // recursive call: make the interval of 'vi'
169 D +=
170 arrange<make_arrangement>(
171 L, vi,
172 (roots_side == LEFT_SIDE ? PLACE_LEFT_OF : PLACE_RIGHT_OF),
173 (make_arrangement ? (roots_side == LEFT_SIDE ? ini : fin - ni + 1) : 0),
174 (make_arrangement ? (roots_side == LEFT_SIDE ? ini + ni - 1 : fin) : 0),
175 arr
176 );
177
178 // accumulate size of interval
179 d += ni*(roots_side == LEFT_SIDE ? n_intervals_left : n_intervals_right);
180 // add length of edge over root 'r'
181 d += 1;
182
183 // number of intervals to the left and right of the root
184 n_intervals_left += roots_side;
185 n_intervals_right += other_side(roots_side);
186
187 // accumulate size of subtree rooted at vi
188 acc_size_left += roots_side*ni;
189 acc_size_right += other_side(roots_side)*ni;
190
191 // update limits of the embedding
192 if constexpr (make_arrangement) {
193 ini += roots_side*ni;
194 fin -= other_side(roots_side)*ni;
195 }
196
197 // change side
198 roots_side = other_side(roots_side);
199 }
200
201#if defined DEBUG
202 if constexpr (make_arrangement) {
203 assert(ini == fin);
204 }
205#endif
206 if constexpr (make_arrangement) {
207 arr.assign(r, ini);
208 }
209
210 // accumulate the length of the edge from 'r' to its parent (if any)
211 D +=
212 (r_place == PLACE_NONE_OF ? 0 :
213 r_place == PLACE_LEFT_OF ? acc_size_right : acc_size_left);
214
215 return D + d;
216}
217
231inline uint64_t arrange_projective
232(
233 uint64_t n, const std::vector<std::vector<node_size>>& L,
235)
236noexcept
237{
238 return arrange<true>(L, r, PLACE_NONE_OF, 0, n-1, arr);
239}
240
254inline uint64_t arrange_projective
255(uint64_t n, const std::vector<std::vector<node_size>>& L, node r)
256noexcept
257{
259 return arrange<false>(L, r, PLACE_NONE_OF, 0, n-1, arr);
260}
261
262
263/* ************************************************************************** */
264/* ----------------- DISPLACEMENT-based methods namespace ------------------- */
265
266/* The following namespace contains functions for the interval-based algorithms
267 * to calculate the planar and projective minimum sum of edge lengths.
268 */
269
270
289template <bool make_arrangement>
291 const std::vector<std::vector<node_size>>& L,
292 node v,
293 int64_t base, int64_t dir,
294 data_array<int64_t>& rel_pos
295)
296noexcept
297{
298 const auto& Cv = L[v];
299 uint64_t cost_branch = 0;
300
301 uint64_t before = 0;
302 uint64_t after = 0;
303 uint64_t under_anchor = 0;
304
305 // LARGEST to SMALLEST
306 for (std::size_t i = 1; i < Cv.size(); i += 2) {
307 //const auto [vi, ni] = Cv[i];
308 //ni := Cv[i].second
309 under_anchor += Cv[i].size;
310 }
311
312 if constexpr (make_arrangement) {
313 base += dir*(to_int64(under_anchor) + 1);
314 }
315
316 cost_branch += under_anchor;
317
318 // SMALLEST to LARGEST
319 uint64_t i = Cv.size();
320 for (auto it = Cv.rbegin(); it != Cv.rend(); ++it, --i) {
321#if defined DEBUG
322 assert(i <= Cv.size());
323#endif
324
325 const auto [vi, ni] = *it;
326
327 cost_branch +=
328 embed_branch<make_arrangement>(
329 L, vi,
330 make_arrangement ?
331 (i&0x1) == 0 ? base - dir*to_int64(before) : base + dir*to_int64(after)
332 : 0
333 ,
334 make_arrangement ?
335 (i&0x1) == 0 ? -dir : dir
336 : 0
337 ,
338 rel_pos
339 );
340 cost_branch += ( (i&0x1) == 0 ? before : after );
341
342 before += ((i&0x1) == 0 ? ni : 0);
343 after += ((i&0x1) == 0 ? 0 : ni);
344
345 cost_branch += 1;
346 }
347
348 if constexpr (make_arrangement) {
349 rel_pos[v] = base;
350 }
351 return cost_branch;
352}
353
369template <bool make_arrangement>
370uint64_t embed(
371 const std::vector<std::vector<node_size>>& L,
372 const node r,
374)
375noexcept
376{
377 const uint64_t n = L.size();
378 uint64_t D = 0;
379
380 data_array<int64_t> rel_pos(n, 0);
381 uint64_t left_sum = 0;
382 uint64_t right_sum = 0;
383
384 uint64_t i = L[r].size();
385
386 // SMALLEST to LARGEST
387 for (auto it = L[r].rbegin(); it != L[r].rend(); ++it, --i) {
388 const auto [vi, ni] = *it;
389#if defined DEBUG
390 assert(i <= L[r].size());
391#endif
392
393 D +=
394 embed_branch<make_arrangement>(
395 L, vi,
396 make_arrangement ?
397 (i&0x1) == 0 ? to_int64(right_sum) : -to_int64(left_sum)
398 : 0
399 ,
400 make_arrangement ?
401 (i&0x1) == 0 ? to_int64(1) : to_int64(-1)
402 : 0
403 ,
404 rel_pos
405 );
406 D += ( (i&0x1) == 0 ? right_sum : left_sum );
407
408 right_sum += ((i&0x1) == 0 ? ni : 0);
409 left_sum += ((i&0x1) == 0 ? 0 : ni);
410
411 D += 1;
412 }
413
414 // the '-1' is used to offset the positions from [1,n] to [0,n-1]
415 if constexpr (make_arrangement) {
416 arr.assign(r, left_sum + 1 - 1);
417 rel_pos[r] = 0;
418 for (node v = 0; v < n; ++v) {
419 const int64_t pos = to_int64(arr[node_t{r}]) + rel_pos[v];
420#if defined DEBUG
421 assert(pos >= 0);
422#endif
423 arr.assign(v, to_uint64(pos));
424 }
425 }
426
427 return D;
428}
429
430} // -- namespcae Dmin_utils
431} // -- namespace detail
432} // -- namespace lal
Linear arrangement of vertices.
Definition: linear_arrangement.hpp:103
uint64_t embed_branch(const std::vector< std::vector< node_size > > &L, node v, int64_t base, int64_t dir, data_array< int64_t > &rel_pos) noexcept
Embed a tree's branch.
Definition: Dmin_utils.hpp:290
uint64_t arrange(const std::vector< std::vector< node_size > > &L, const node r, const place r_place, position ini, position fin, linear_arrangement &arr) noexcept
Make a minimum projective arrangement using the sorted, rooted adjacency list L.
Definition: Dmin_utils.hpp:113
uint64_t arrange_projective(uint64_t n, const std::vector< std::vector< node_size > > &L, node r, linear_arrangement &arr) noexcept
Wrapper method for the recursive method arrange.
Definition: Dmin_utils.hpp:232
uint64_t embed(const std::vector< std::vector< node_size > > &L, const node r, linear_arrangement &arr) noexcept
Embed a tree's branch.
Definition: Dmin_utils.hpp:370
unsigned char side
Useful typedef to denote relative position.
Definition: Dopt_utils.hpp:74
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:52
constexpr uint64_t to_uint64(const T &t) noexcept
Conversion to uint64_t.
Definition: basic_convert.hpp:57
Main namespace of the library.
Definition: basic_types.hpp:50
uint64_t position
Node's position type.
Definition: basic_types.hpp:55
uint64_t node
Node type. See Node / Vertex page for further details.
Definition: basic_types.hpp:53
Wrapper of a C array for autmatic deallocation of memory.
Definition: data_array.hpp:59
Typesafe node type.
Definition: basic_types.hpp:67