LAL: Linear Arrangement Library 24.10.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 - 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#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/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},
116 { }
117
128 linear_arrangement(const std::vector<position>& dir_arr) noexcept
129 : m_memory(2*dir_arr.size()),
130 m_n{dir_arr.size()},
133 {
134 // construct m_direct and m_inverse
135 from_data<true>(dir_arr.begin(), dir_arr.end());
136 }
137
140 : m_memory(arr.m_memory),
141 m_n{arr.m_n},
144 { }
147 m_memory = arr.m_memory;
148 m_n = arr.m_n;
151 return *this;
152 }
153
155 linear_arrangement& operator= (const std::vector<position>& dir_arr) noexcept {
156 m_memory.resize(2*dir_arr.size());
157 m_n = dir_arr.size();
160 // construct m_direct and m_inverse
161 from_data<true>(dir_arr.begin(), dir_arr.end());
162 return *this;
163 }
164
167 : m_memory(std::move(arr.m_memory)),
168 m_n{arr.m_n},
169 m_direct{std::move(arr.m_direct)},
170 m_inverse{std::move(arr.m_inverse)}
171 {
172 // invalidate data
173 arr.m_n = 0;
174 arr.m_direct = nullptr;
175 arr.m_inverse = nullptr;
176 }
179 // steal data
180 m_memory = std::move(arr.m_memory);
181 m_n = arr.m_n;
182 m_direct = arr.m_direct;
183 m_inverse = arr.m_inverse;
184 // invalidate data
185 arr.m_n = 0;
186 arr.m_direct = nullptr;
187 arr.m_inverse = nullptr;
188 return *this;
189 }
190
192 virtual ~linear_arrangement() noexcept = default;
193
202 static linear_arrangement from_direct(const std::vector<position>& v) noexcept {
203 return from_direct(v.begin(), v.end(), v.size());
204 }
205
206#if !defined __LAL_SWIG_PYTHON
216 template <typename It>
217 static linear_arrangement from_direct(It begin, It end) noexcept {
218 return from_direct(begin, end, std::distance(begin, end));
219 }
220
231 template <typename It>
232 static linear_arrangement from_direct(It begin, It end, std::size_t size) noexcept {
234 arr.from_data<true>(begin, end);
235 return arr;
236 }
237#endif
238
245 static linear_arrangement from_inverse(const std::vector<node>& v) noexcept {
246 return from_inverse(v.begin(), v.end(), v.size());
247 }
248
249#if !defined __LAL_SWIG_PYTHON
259 template <typename It>
260 static linear_arrangement from_inverse(It begin, It end) noexcept {
261 return from_inverse(
262 begin, end,
263 static_cast<std::size_t>(std::distance(begin, end))
264 );
265 }
266
277 template <typename It>
278 static linear_arrangement from_inverse(It begin, It end, std::size_t size) noexcept {
280 arr.from_data<false>(begin, end);
281 return arr;
282 }
283#endif
284
286 bool operator< (const linear_arrangement& arr) const noexcept {
287 if (size() != arr.size()) { return size() < arr.size(); }
288
289 for (std::size_t i = 0; i < size() - 1; ++i) {
290 if (m_direct[i] != arr.m_direct[i]) {
291 return m_direct[i] < arr.m_direct[i];
292 }
293 }
294 return m_direct[size() - 1] < arr.m_direct[size() - 1];
295 }
296
305 position operator[] (const node_t& u) const noexcept
306 { return get_position_of(*u); }
307
316 node operator[] (const position_t& p) const noexcept
317 { return get_node_at(*p); }
318
320 void clear() noexcept {
321 m_memory.clear();
322 m_n = 0;
323 m_direct = nullptr;
324 m_inverse = nullptr;
325 }
326
335 position get_position_of(const node u) const noexcept
336 { return m_direct[u]; }
337
346 node get_node_at(const position p) const noexcept
347 { return m_inverse[p]; }
348
355 void resize(std::size_t n) noexcept {
356 m_memory.resize(2*n, n + 1);
357 m_n = n;
358 set_pointers();
359 }
360
370 template <
371 typename NODE, typename POSITION,
372 std::enable_if_t<
373 (std::is_integral_v<NODE> or std::is_same_v<NODE, node_t>)
374 and
375 (std::is_integral_v<POSITION> or std::is_same_v<POSITION, position_t>)
376 ,
377 bool> = true
378 >
379 void assign(const NODE u, const POSITION p) noexcept {
380#if defined DEBUG
381 assert(u < m_n);
382 assert(p < m_n);
383#endif
384 if constexpr (std::is_same_v<NODE, node_t> and std::is_same_v<POSITION, position_t>) {
385 m_direct[*u] = *p;
386 m_inverse[*p] = *u;
387 }
388 else if constexpr (std::is_same_v<NODE, node_t>) {
389 m_direct[*u] = p;
390 m_inverse[p] = *u;
391 }
392 else if constexpr (std::is_same_v<POSITION, position_t>) {
393 m_direct[u] = *p;
394 m_inverse[*p] = u;
395 }
396 else {
397 m_direct[u] = p;
398 m_inverse[p] = u;
399 }
400 }
401
416 template <
417 typename what,
418 std::enable_if_t<
419 std::is_same_v<what, node_t> or std::is_same_v<what, position_t>
420 ,
421 bool> = true
422 >
423 void swap(const what u_t, const what v_t) noexcept {
424 if constexpr (std::is_same_v<what, node_t>) {
425 // swap vertices
426 const position pu = m_direct[*u_t];
427 const position pv = m_direct[*v_t];
428 assign(u_t, pv);
429 assign(v_t, pu);
430 }
431 else {
432 // swap positions
433 const node u = m_inverse[*u_t];
434 const node v = m_inverse[*v_t];
435 assign(u, v_t);
436 assign(v, u_t);
437 }
438 }
439
444 void shift_left() noexcept {
445 const node_t u0 = m_inverse[0];
446 // shift every vertex one position to the left
447 for (position pu = 0; pu < m_n - 1; ++pu) {
448 const node u = get_node_at(pu + 1);
449 assign(u, pu);
450 }
451 // put the first vertex at the last position
452 assign(u0, m_n - 1);
453 }
454
459 void shift_right() noexcept {
460 const node_t ulast = m_inverse[m_n - 1];
461 // shift every vertex one position to the left
462 for (position pu = m_n - 1; pu > 0; --pu) {
463 const node u = get_node_at(pu - 1);
464 assign(u, pu);
465 }
466 // put the last vertex at the first position
467 assign(ulast, 0ull);
468 }
469
478 void mirror() noexcept {
479 for (position_t i = 0ull; i < m_n/2; ++i) {
480 swap(i, m_n - 1ull - i);
481 }
482 }
483
485 std::size_t size() const noexcept { return m_n; }
486
494 static linear_arrangement identity(std::size_t n) noexcept
495 {
496 linear_arrangement arr(n);
497 arr.identity();
498 return arr;
499 }
500
507 void identity() noexcept {
508 for (std::size_t i = 0; i < m_n; ++i) { assign(i,i); }
509 }
510
517 void update_direct() noexcept {
518 for (position pu = 0; pu < m_n; ++pu) {
519 m_direct[ m_inverse[pu] ] = pu;
520 }
521 }
522
529 void update_inverse() noexcept {
530 for (node u = 0; u < m_n; ++u) {
531 m_inverse[ m_direct[u] ] = u;
532 }
533 }
534
536 node *begin_direct() noexcept { return m_direct; }
538 const node *begin_direct() const noexcept { return m_direct; }
540 node *end_direct() noexcept { return m_direct + m_n; }
542 const node *end_direct() const noexcept { return m_direct + m_n; }
543
545 node *begin_inverse() noexcept { return m_inverse; }
547 const node *begin_inverse() const noexcept { return m_inverse; }
549 node *end_inverse() noexcept { return m_inverse + m_n; }
551 const node *end_inverse() const noexcept { return m_inverse + m_n; }
552
554 std::vector<position> direct_as_vector() const noexcept
555 { return {begin_direct(), end_direct()}; }
556
558 std::vector<node> inverse_as_vector() const noexcept
559 { return {begin_inverse(), end_inverse()}; }
560
561private:
562
569 void set_pointers() noexcept {
572 }
573
583 template <bool from_direct_arr, typename It>
584 void from_data(const It begin, const It end) noexcept
585 {
586#if defined DEBUG
587 assert(m_direct != nullptr);
588 assert(m_inverse != nullptr);
589#endif
590 std::size_t i = 0;
591 if constexpr (from_direct_arr) {
592 for (It it = begin; it != end; ++it, ++i) {
593 m_direct[i] = *it;
594 m_inverse[*it] = i;
595 }
596 }
597 else {
598 for (It it = begin; it != end; ++it, ++i) {
599 m_direct[*it] = i;
600 m_inverse[i] = *it;
601 }
602 }
603 }
604
605protected:
610 std::size_t m_n = 0;
611
613 position *m_direct = nullptr;
615 node *m_inverse = nullptr;
616};
617
618} // -- 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:554
std::size_t m_n
Size of the arrangement (number of nodes in the arrangement).
Definition linear_arrangement.hpp:610
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:423
node * m_inverse
Pointer to the inverse arrangement values.
Definition linear_arrangement.hpp:615
position get_position_of(const node u) const noexcept
Returns the position of node u.
Definition linear_arrangement.hpp:335
void clear() noexcept
Frees the memory used by the linear arrangement.
Definition linear_arrangement.hpp:320
void mirror() noexcept
Mirror the arrangement.
Definition linear_arrangement.hpp:478
void from_data(const It begin, const It end) noexcept
Initializes this arrangement from a direct or inverse arrangement.
Definition linear_arrangement.hpp:584
std::vector< node > inverse_as_vector() const noexcept
Constructs a std::vector from the inverse arrangement.
Definition linear_arrangement.hpp:558
std::size_t size() const noexcept
Size of the arrangement (number of nodes in the arrangement).
Definition linear_arrangement.hpp:485
linear_arrangement & operator=(const linear_arrangement &arr) noexcept
Copy assignment operator.
Definition linear_arrangement.hpp:146
linear_arrangement(linear_arrangement &&arr) noexcept
Move constructor.
Definition linear_arrangement.hpp:166
static linear_arrangement from_inverse(const std::vector< node > &v) noexcept
Construct a linear arrangement from an inverse arrangement.
Definition linear_arrangement.hpp:245
void assign(const NODE u, const POSITION p) noexcept
Assigns a node u to position p.
Definition linear_arrangement.hpp:379
static linear_arrangement identity(std::size_t n) noexcept
Constructs an identity linear arrangement.
Definition linear_arrangement.hpp:494
const node * begin_direct() const noexcept
Pointer to beginning of direct arrangement.
Definition linear_arrangement.hpp:538
detail::array< uint64_t > m_memory
Definition linear_arrangement.hpp:608
linear_arrangement(const std::vector< position > &dir_arr) noexcept
Constructor with direct arrangement.
Definition linear_arrangement.hpp:128
static linear_arrangement from_inverse(It begin, It end) noexcept
Construct a linear arrangement from an inverse arrangement.
Definition linear_arrangement.hpp:260
void update_inverse() noexcept
Updates the inverse arrangement using the direct arrangement.
Definition linear_arrangement.hpp:529
void resize(std::size_t n) noexcept
Changes the size of the arrangement.
Definition linear_arrangement.hpp:355
position operator[](const node_t &u) const noexcept
Returns the position of node u.
Definition linear_arrangement.hpp:305
static linear_arrangement from_direct(It begin, It end) noexcept
Construct a linear arrangement from a direct arrangement.
Definition linear_arrangement.hpp:217
static linear_arrangement from_direct(const std::vector< position > &v) noexcept
Construct a linear arrangement from a direct arrangement.
Definition linear_arrangement.hpp:202
void shift_right() noexcept
Shifts the vertices one position to the right.
Definition linear_arrangement.hpp:459
node * end_inverse() noexcept
Pointer to end of inverse arrangement.
Definition linear_arrangement.hpp:549
node get_node_at(const position p) const noexcept
Returns the node at position p.
Definition linear_arrangement.hpp:346
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:232
void identity() noexcept
Makes this arrangement an identity arrangement.
Definition linear_arrangement.hpp:507
virtual ~linear_arrangement() noexcept=default
Default destructor.
const node * begin_inverse() const noexcept
Pointer to beginning of inverse arrangement.
Definition linear_arrangement.hpp:547
bool operator<(const linear_arrangement &arr) const noexcept
Lexicographic comparison of two linear arrangements.
Definition linear_arrangement.hpp:286
linear_arrangement(const linear_arrangement &arr) noexcept
Copy constructor.
Definition linear_arrangement.hpp:139
node * begin_inverse() noexcept
Pointer to beginning of inverse arrangement.
Definition linear_arrangement.hpp:545
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:278
const node * end_inverse() const noexcept
Pointer to end of inverse arrangement.
Definition linear_arrangement.hpp:551
void shift_left() noexcept
Shifts the vertices one position to the left.
Definition linear_arrangement.hpp:444
void set_pointers() noexcept
Sets m_direct and m_inverse appropriately.
Definition linear_arrangement.hpp:569
position * m_direct
Pointer to the direct arrangement values.
Definition linear_arrangement.hpp:613
node * begin_direct() noexcept
Pointer to beginning of direct arrangement.
Definition linear_arrangement.hpp:536
const node * end_direct() const noexcept
Pointer to end of direct arrangement.
Definition linear_arrangement.hpp:542
void update_direct() noexcept
Updates the direct arrangement using the inverse arrangement.
Definition linear_arrangement.hpp:517
node * end_direct() noexcept
Pointer to end of direct arrangement.
Definition linear_arrangement.hpp:540
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
T * begin() noexcept
Non-constant raw pointer to first element.
Definition array.hpp:300
std::size_t size() const noexcept
Size of the array.
Definition array.hpp:215
void resize(const std::size_t new_size) noexcept
Resize the array.
Definition array.hpp:187
void clear() noexcept
Clear the contents of the array.
Definition array.hpp:174
Typesafe node type.
Definition basic_types.hpp:70
Typesafe position type.
Definition basic_types.hpp:244