LAL: Linear Arrangement Library 23.01.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
linear_arrangement.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 * 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#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/basic_types.hpp>
52#include <lal/detail/data_array.hpp>
53
54namespace lal {
55
104public:
106 linear_arrangement() noexcept = default;
111 linear_arrangement(std::size_t n) noexcept
112 : m_memory(2*n, n+1),
113 m_n(n),
114 m_direct(m_memory.begin()),
115 m_inverse(m_memory.begin() + m_n)
116 { }
117
127 linear_arrangement(const std::vector<position>& dir_arr) noexcept
128 : m_memory(2*dir_arr.size()),
129 m_n(dir_arr.size()),
132 {
133 // construct m_direct and m_inverse
134 from_data<true>(dir_arr.begin(), dir_arr.end());
135 }
136
139 : m_memory(arr.m_memory),
140 m_n(arr.m_n),
143 { }
146 m_memory = arr.m_memory;
147 m_n = arr.m_n;
150 return *this;
151 }
152
154 linear_arrangement& operator= (const std::vector<position>& dir_arr) noexcept {
155 m_memory.resize(2*dir_arr.size());
156 m_n = dir_arr.size();
159 // construct m_direct and m_inverse
160 from_data<true>(dir_arr.begin(), dir_arr.end());
161 return *this;
162 }
163
166 : m_memory(std::move(arr.m_memory)),
167 m_n(arr.m_n),
168 m_direct(std::move(arr.m_direct)),
169 m_inverse(std::move(arr.m_inverse))
170 {
171 // invalidate data
172 arr.m_n = 0;
173 arr.m_direct = nullptr;
174 arr.m_inverse = nullptr;
175 }
178 // steal data
179 m_memory = std::move(arr.m_memory);
180 m_n = arr.m_n;
181 m_direct = std::move(arr.m_direct);
182 m_inverse = std::move(arr.m_inverse);
183 // invalidate data
184 arr.m_n = 0;
185 arr.m_direct = nullptr;
186 arr.m_inverse = nullptr;
187 return *this;
188 }
189
191 virtual ~linear_arrangement() noexcept = default;
192
200 static linear_arrangement from_direct(const std::vector<position>& v) noexcept {
201 return from_direct(v.begin(), v.end(), v.size());
202 }
203
204#ifndef SWIG
213 template <typename It>
214 static linear_arrangement from_direct(It begin, It end) noexcept {
215 return from_direct(begin, end, std::distance(begin, end));
216 }
217
227 template <typename It>
228 static linear_arrangement from_direct(It begin, It end, std::size_t size) noexcept {
230 arr.from_data<true>(begin, end);
231 return arr;
232 }
233#endif
234
240 static linear_arrangement from_inverse(const std::vector<node>& v) noexcept {
241 return from_inverse(v.begin(), v.end(), v.size());
242 }
243
244#ifndef SWIG
253 template <typename It>
254 static linear_arrangement from_inverse(It begin, It end) noexcept {
255 return from_inverse(begin, end, std::distance(begin, end));
256 }
257
267 template <typename It>
268 static linear_arrangement from_inverse(It begin, It end, std::size_t size) noexcept {
270 arr.from_data<false>(begin, end);
271 return arr;
272 }
273#endif
274
276 bool operator< (const linear_arrangement& arr) const noexcept {
277 if (size() != arr.size()) { return size() < arr.size(); }
278
279 for (std::size_t i = 0; i < size() - 1; ++i) {
280 if (m_direct[i] != arr.m_direct[i]) {
281 return m_direct[i] < arr.m_direct[i];
282 }
283 }
284 return m_direct[size() - 1] < arr.m_direct[size() - 1];
285 }
286
288 node operator[] (const node_t& u) const noexcept
289 { return get_position_of(*u); }
290
292 position operator[] (const position_t& p) const noexcept
293 { return get_node_at(*p); }
294
296 void clear() noexcept {
297 m_memory.clear();
298 m_n = 0;
299 m_direct = nullptr;
300 m_inverse = nullptr;
301 }
302
304 position get_position_of(const node u) const noexcept
305 { return m_direct[u]; }
306
308 node get_node_at(const position p) const noexcept
309 { return m_inverse[p]; }
310
317 void resize(std::size_t n) noexcept {
318 m_memory.resize(2*n, n + 1);
319 m_n = n;
320 set_pointers();
321 }
322
332 template <
333 typename NODE, typename POSITION,
334 std::enable_if_t<
335 (std::is_integral_v<NODE> or std::is_same_v<NODE, node_t>)
336 and
337 (std::is_integral_v<POSITION> or std::is_same_v<POSITION, position_t>)
338 ,
339 bool> = true
340 >
341 void assign(const NODE u, const POSITION p) noexcept {
342#if defined DEBUG
343 assert(u < m_n);
344 assert(p < m_n);
345#endif
346 if constexpr (std::is_same_v<NODE, node_t> and std::is_same_v<POSITION, position_t>) {
347 m_direct[*u] = *p;
348 m_inverse[*p] = *u;
349 }
350 else if constexpr (std::is_same_v<NODE, node_t>) {
351 m_direct[*u] = p;
352 m_inverse[p] = *u;
353 }
354 else if constexpr (std::is_same_v<POSITION, position_t>) {
355 m_direct[u] = *p;
356 m_inverse[*p] = u;
357 }
358 else {
359 m_direct[u] = p;
360 m_inverse[p] = u;
361 }
362 }
363
376 template <
377 typename what,
378 std::enable_if_t<
379 std::is_same_v<what, node_t> or std::is_same_v<what, position_t>
380 ,
381 bool> = true
382 >
383 void swap(const what u_t, const what v_t) noexcept {
384 if constexpr (std::is_same_v<what, node_t>) {
385 // swap vertices
386 const position pu = m_direct[*u_t];
387 const position pv = m_direct[*v_t];
388 assign(u_t, pv);
389 assign(v_t, pu);
390 }
391 else {
392 // swap positions
393 const node u = m_inverse[*u_t];
394 const node v = m_inverse[*v_t];
395 assign(u, v_t);
396 assign(v, u_t);
397 }
398 }
399
401 void shift_left() noexcept {
402 const node_t u0 = m_inverse[0];
403 // shift every vertex one position to the left
404 for (position pu = 0; pu < m_n - 1; ++pu) {
405 const node u = get_node_at(pu + 1);
406 assign(u, pu);
407 }
408 // put the first vertex at the last position
409 assign(u0, m_n - 1);
410 }
411
413 void shift_right() noexcept {
414 const node_t ulast = m_inverse[m_n - 1];
415 // shift every vertex one position to the left
416 for (position pu = m_n - 1; pu > 0; --pu) {
417 const node u = get_node_at(pu - 1);
418 assign(u, pu);
419 }
420 // put the last vertex at the first position
421 assign(ulast, 0ull);
422 }
423
431 void mirror() noexcept {
432 for (position_t i = 0ull; i < m_n/2; ++i) {
433 swap(i, m_n - 1ull - i);
434 }
435 }
436
438 std::size_t size() const noexcept { return m_n; }
439
444 static linear_arrangement identity(std::size_t n) noexcept
445 {
446 linear_arrangement arr(n);
447 arr.identity();
448 return arr;
449 }
450
452 void identity() noexcept {
453 for (std::size_t i = 0; i < m_n; ++i) { assign(i,i); }
454 }
455
462 void update_direct() noexcept {
463 for (position pu = 0; pu < m_n; ++pu) {
464 m_direct[ m_inverse[pu] ] = pu;
465 }
466 }
467
474 void update_inverse() noexcept {
475 for (node u = 0; u < m_n; ++u) {
476 m_inverse[ m_direct[u] ] = u;
477 }
478 }
479
481 node *begin_direct() noexcept { return m_direct; }
483 const node *begin_direct() const noexcept { return m_direct; }
485 node *end_direct() noexcept { return m_direct + m_n; }
487 const node *end_direct() const noexcept { return m_direct + m_n; }
488
490 node *begin_inverse() noexcept { return m_inverse; }
492 const node *begin_inverse() const noexcept { return m_inverse; }
494 node *end_inverse() noexcept { return m_inverse + m_n; }
496 const node *end_inverse() const noexcept { return m_inverse + m_n; }
497
499 std::vector<position> direct_as_vector() const noexcept
500 { return {begin_direct(), end_direct()}; }
501
503 std::vector<node> inverse_as_vector() const noexcept
504 { return {begin_inverse(), end_inverse()}; }
505
506private:
507
510 void set_pointers() noexcept {
513 }
514
524 template <bool from_direct_arr, typename It>
525 void from_data(const It begin, const It end) noexcept
526 {
527#if defined DEBUG
528 assert(m_direct != nullptr);
529 assert(m_inverse != nullptr);
530#endif
531 std::size_t i = 0;
532 if constexpr (from_direct_arr) {
533 for (It it = begin; it != end; ++it, ++i) {
534 m_direct[i] = *it;
535 m_inverse[*it] = i;
536 }
537 }
538 else {
539 for (It it = begin; it != end; ++it, ++i) {
540 m_direct[*it] = i;
541 m_inverse[i] = *it;
542 }
543 }
544 }
545
546protected:
551 std::size_t m_n = 0;
552
554 position *m_direct = nullptr;
556 node *m_inverse = nullptr;
557};
558
559} // -- namespace lal
Linear arrangement of vertices.
Definition: linear_arrangement.hpp:103
std::vector< position > direct_as_vector() const noexcept
Constructs a std::vector from the direct arrangement.
Definition: linear_arrangement.hpp:499
std::size_t m_n
Size of the arrangement (number of nodes in the arrangement).
Definition: linear_arrangement.hpp:551
void swap(const what u_t, const what v_t) noexcept
Swaps the position of two vertices or of two positions.
Definition: linear_arrangement.hpp:383
node * m_inverse
Pointer to the inverse arrangement values.
Definition: linear_arrangement.hpp:556
position get_position_of(const node u) const noexcept
Returns the position of node u.
Definition: linear_arrangement.hpp:304
void clear() noexcept
Frees the memory used by the linear arrangement.
Definition: linear_arrangement.hpp:296
void mirror() noexcept
Mirror the arrangement.
Definition: linear_arrangement.hpp:431
node operator[](const node_t &u) const noexcept
Access to linear arrangement using a type-safe node.
Definition: linear_arrangement.hpp:288
void from_data(const It begin, const It end) noexcept
Initializes this arrangement from a direct or inverse arrangement.
Definition: linear_arrangement.hpp:525
std::vector< node > inverse_as_vector() const noexcept
Constructs a std::vector from the inverse arrangement.
Definition: linear_arrangement.hpp:503
std::size_t size() const noexcept
Size of the arrangement (number of nodes in the arrangement).
Definition: linear_arrangement.hpp:438
linear_arrangement & operator=(const linear_arrangement &arr) noexcept
Copy assignment operator.
Definition: linear_arrangement.hpp:145
linear_arrangement(linear_arrangement &&arr) noexcept
Move constructor.
Definition: linear_arrangement.hpp:165
static linear_arrangement from_inverse(const std::vector< node > &v) noexcept
Construct a linear arrangement from an inverse arrangement.
Definition: linear_arrangement.hpp:240
void assign(const NODE u, const POSITION p) noexcept
Assigns a node u to position p.
Definition: linear_arrangement.hpp:341
static linear_arrangement identity(std::size_t n) noexcept
Constructs a linear arrangement from an inverse arrangement.
Definition: linear_arrangement.hpp:444
detail::data_array< uint64_t > m_memory
Definition: linear_arrangement.hpp:549
const node * begin_direct() const noexcept
Pointer to beginning of direct arrangement.
Definition: linear_arrangement.hpp:483
linear_arrangement(const std::vector< position > &dir_arr) noexcept
Constructor with direct arrangement.
Definition: linear_arrangement.hpp:127
static linear_arrangement from_inverse(It begin, It end) noexcept
Construct a linear arrangement from an inverse arrangement.
Definition: linear_arrangement.hpp:254
void update_inverse() noexcept
Updates the inverse arrangement using the direct arrangement.
Definition: linear_arrangement.hpp:474
void resize(std::size_t n) noexcept
Changes the size of the arrangement.
Definition: linear_arrangement.hpp:317
static linear_arrangement from_direct(It begin, It end) noexcept
Construct a linear arrangement from a direct arrangement.
Definition: linear_arrangement.hpp:214
static linear_arrangement from_direct(const std::vector< position > &v) noexcept
Construct a linear arrangement from a direct arrangement.
Definition: linear_arrangement.hpp:200
void shift_right() noexcept
Shifts the vertices one position to the right.
Definition: linear_arrangement.hpp:413
node * end_inverse() noexcept
Pointer to end of inverse arrangement.
Definition: linear_arrangement.hpp:494
node get_node_at(const position p) const noexcept
Returns the node at position p.
Definition: linear_arrangement.hpp:308
static linear_arrangement from_direct(It begin, It end, std::size_t size) noexcept
Construct a linear arrangement from a direct arrangement.
Definition: linear_arrangement.hpp:228
void identity() noexcept
Makes this arrangement an identity arrangement.
Definition: linear_arrangement.hpp:452
virtual ~linear_arrangement() noexcept=default
Default destructor.
const node * begin_inverse() const noexcept
Pointer to beginning of inverse arrangement.
Definition: linear_arrangement.hpp:492
bool operator<(const linear_arrangement &arr) const noexcept
Lexicographic comparison of two linear arrangements.
Definition: linear_arrangement.hpp:276
linear_arrangement(const linear_arrangement &arr) noexcept
Copy constructor.
Definition: linear_arrangement.hpp:138
node * begin_inverse() noexcept
Pointer to beginning of inverse arrangement.
Definition: linear_arrangement.hpp:490
linear_arrangement() noexcept=default
Default constructor.
static linear_arrangement from_inverse(It begin, It end, std::size_t size) noexcept
Construct a linear arrangement from an inverse arrangement.
Definition: linear_arrangement.hpp:268
const node * end_inverse() const noexcept
Pointer to end of inverse arrangement.
Definition: linear_arrangement.hpp:496
void shift_left() noexcept
Shifts the vertices one position to the left.
Definition: linear_arrangement.hpp:401
void set_pointers() noexcept
Definition: linear_arrangement.hpp:510
position * m_direct
Pointer to the direct arrangement values.
Definition: linear_arrangement.hpp:554
node * begin_direct() noexcept
Pointer to beginning of direct arrangement.
Definition: linear_arrangement.hpp:481
const node * end_direct() const noexcept
Pointer to end of direct arrangement.
Definition: linear_arrangement.hpp:487
void update_direct() noexcept
Updates the direct arrangement using the inverse arrangement.
Definition: linear_arrangement.hpp:462
node * end_direct() noexcept
Pointer to end of direct arrangement.
Definition: linear_arrangement.hpp:485
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
void resize(std::size_t new_size) noexcept
Resize the array.
Definition: data_array.hpp:175
void clear() noexcept
Clear the contents of the array.
Definition: data_array.hpp:162
T * begin() noexcept
Non-constant raw pointer to first element.
Definition: data_array.hpp:291
Typesafe node type.
Definition: basic_types.hpp:67
Typesafe position type.
Definition: basic_types.hpp:168