LAL: Linear Arrangement Library 24.10.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
1_eq_thistle_AEF.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#if !defined DEBUG
45#if defined __LAL_DEBUG_DMax_1_thistle
46#error "__LAL_DEBUG_DMax_1_thistle can only be defined when DEBUG is defined"
47#endif
48#endif
49
50// C++ includes
51#include <type_traits>
52#include <algorithm>
53#include <cstdint>
54#include <vector>
55
56#if defined __LAL_DEBUG_DMax_1_thistle
57#include <iostream>
58#endif
59#if defined DEBUG
60#include <cassert>
61#endif
62
63// lal includes
64#include <lal/linear_arrangement.hpp>
65#include <lal/graphs/tree.hpp>
66#include <lal/graphs/free_tree.hpp>
67#include <lal/graphs/rooted_tree.hpp>
68#include <lal/linarr/formal_constraints.hpp>
69#include <lal/linarr/D/D.hpp>
70#if defined DEBUG
71#include <lal/linarr/formal_constraints.hpp>
72#endif
73#if defined __LAL_DEBUG_DMax_1_thistle
74#include <lal/graphs/output.hpp>
75#endif
76
77#include <lal/detail/graphs/traversal.hpp>
78#include <lal/detail/properties/bipartite_graph_colorability.hpp>
79#include <lal/detail/properties/branchless_paths_compute.hpp>
80#include <lal/detail/sorting/counting_sort.hpp>
81#include <lal/detail/macros/basic_convert.hpp>
82#include <lal/detail/linarr/level_signature.hpp>
83
84namespace lal {
85namespace detail {
86namespace DMax {
87namespace thistle_1 {
88
90namespace bits {
91
99template <typename iterator_t>
100[[nodiscard]] inline bool next_binary
101(iterator_t begin, iterator_t end)
102noexcept
103{
104 while (begin != end and *begin == 1) {
105 *begin = 0;
106 ++begin;
107 }
108 // reached the last configuration "1......1"
109 // which now has been turned into a "0......0"
110 if (begin == end) { return false; }
111
112 // the configuration is "0....01x...x"
113 *begin = 1;
114 // there are still more binary configurations
115 return true;
116}
117
122
124static constexpr char LEFT_SIDE = 0;
126static constexpr char RIGHT_SIDE = 1;
128static constexpr char other_side(char side) noexcept {
129 return (side == LEFT_SIDE ? RIGHT_SIDE : LEFT_SIDE);
130}
131// sanity check
132static_assert(other_side(RIGHT_SIDE) == LEFT_SIDE);
133// sanity check
134static_assert(other_side(LEFT_SIDE) == RIGHT_SIDE);
135// sanity check
136static_assert(other_side(RIGHT_SIDE) != RIGHT_SIDE);
137// sanity check
138static_assert(other_side(LEFT_SIDE) != LEFT_SIDE);
139
141template <bool make_arrangement>
142using result_t = std::conditional_t<
143 make_arrangement,
144 std::pair<uint64_t, linear_arrangement>,
145 uint64_t
146>;
147
148#define __LAL_level_position(p) levels_per_vertex[node_t{inv_arr[p]}]
149#define __LAL_level_vertex(u) levels_per_vertex[node_t{u}]
150
151#if defined __LAL_DEBUG_DMax_1_thistle
152inline void print_arrangement(const std::string& msg, const linear_arrangement& arr)
153noexcept
154{
155 const auto dir = arr.direct_as_vector();
156 const auto inv = arr.inverse_as_vector();
157 std::cout << " " << msg << ":\n";
158 std::cout << " Direct: ";
159 for (std::size_t i = 0; i < dir.size(); ++i) { std::cout << ' ' << dir[i]; }
160 std::cout << '\n';
161 std::cout << " Inverse:";
162 for (std::size_t i = 0; i < inv.size(); ++i) { std::cout << ' ' << inv[i]; }
163 std::cout << '\n';
164}
165#endif
166
180(
181 const graphs::free_tree& t,
182 const node thistle,
183 const int64_t thistle_level,
184 const array<char>& thistle_side_per_vertex,
185 level_signature_per_vertex& levels_per_vertex,
186 array<node>& inv_arr
187)
188noexcept
189{
190 const uint64_t n = t.get_num_nodes();
191
192 // The minimum level value in the configuration. There is always
193 // a negative (<0) level value, so the minimum can be initialized at 0.
194 int64_t min_level_value = 0;
195
196 position left = 0;
197 position right = n - 1ull;
198
199 // Calculate the level for each vertex and place them in the inverse
200 // arrangement. The arrangement built at this step is only preliminary.
201 for (node u = 0; u < n; ++u) {
202 if (u == thistle) { continue; }
203 const int64_t d = to_int64(t.get_degree(u));
204 if (thistle_side_per_vertex[u] == LEFT_SIDE) {
205 __LAL_level_vertex(u) = d;
206 inv_arr[left++] = u;
207 }
208 else if (thistle_side_per_vertex[u] == RIGHT_SIDE) {
209 __LAL_level_vertex(u) = -d;
210 inv_arr[right--] = u;
211 min_level_value = std::min(min_level_value, -d);
212 }
213#if defined DEBUG
214 else {
215#if defined __LAL_DEBUG_DMax_1_thistle
216 std::cout << "Vertex " << u << " was not assigned a side\n";
217#endif
218 assert(false);
219 }
220#endif
221 }
222
223 // This function assumes that the thistle will never have negative (<0)
224 // level value.
225 __LAL_level_vertex(thistle) = thistle_level;
226 // The position to place the thistle is either 'left' or 'right' since,
227 // at this point, their values are equal (see next assertion).
228 inv_arr[left] = thistle;
229
230#if defined DEBUG
231 assert(left == right);
232#endif
233
234#if defined __LAL_DEBUG_DMax_1_thistle
235 std::cout << " Level per vertex:\n";
236 for (node u = 0; u < n; ++u) {
237 std::cout
238 << " level[" << u << "]= "
239 << levels_per_vertex[node_t{u}]
240 << '\n';
241 }
242#endif
243
244 // Sort the vertices by level (first, those with positive level. Then, those
245 // with negative level). Independent tasks.
248 (
249 inv_arr.begin(), inv_arr.begin() + left, 2*n, n,
250 [&](const node u) {
251 return to_uint64(__LAL_level_vertex(u) - min_level_value);
252 }
253 );
256 (
257 inv_arr.begin() + right + 1, inv_arr.end(), 2*n, n,
258 [&](const node u) {
259 return to_uint64(__LAL_level_vertex(u) - min_level_value);
260 }
261 );
262}
263
285(
286 const uint64_t n,
287 const node thistle,
288 const array<char>& is_thistle_neighbor,
289 const level_signature_per_vertex& levels_per_vertex,
290 array<node>& inv_arr
291)
292noexcept
293{
294 position p = 0;
295 while (p < n) {
296
297 position q = p;
298 const int64_t current_level = __LAL_level_position(p);
299 while (q < n and __LAL_level_position(q) == current_level) {
300 ++q;
301 }
302
303#if defined __LAL_DEBUG_DMax_1_thistle
304 std::cout << " Sort the interval [" << p << ", " << q << ").\n";
305#endif
306
307 // sort interval [p,q)
310 (
311 inv_arr.begin() + p, inv_arr.begin() + q, 2, q - p,
312 [&](const node u) {
313 // 0, 1, 2
314 if (is_thistle_neighbor[u] == 1) { return 0ull; }
315 if (u == thistle) { return 1ull; }
316 return 2ull;
317 }
318 );
319
320 p = q;
321 }
322}
323
337(
338 const graphs::free_tree& t,
339 const node thistle,
340 position_t p,
342)
343noexcept
344{
345 const auto n = t.get_num_nodes();
346 while (p < n - 1 and arr[p + 1ull] != thistle) {
347 arr.swap(p, p + 1ull);
348 ++p;
349 }
350 arr.swap(p, p + 1ull);
351}
352
367(
368 const graphs::free_tree& t,
369 const int64_t thistle_level,
370 const node thistle,
371 const array<char>& is_thistle_neighbor,
372 const level_signature_per_vertex& levels_per_vertex,
374)
375noexcept
376{
377#if defined DEBUG
378 assert(arr[node_t{thistle}] > 0);
379#endif
380
381 // position of thistle can never be '0'
382 position p = arr[node_t{thistle}] - 1;
383
384#if defined __LAL_DEBUG_DMax_1_thistle
385 std::cout << " Thistle position p= " << p + 1 << '\n';
386#endif
387
388 // number of vertices between the thistle and its first non-neighbor
389 int64_t num_neighbors = 0;
390 // sum of level values between the thistle and its first non-neighbor
391 int64_t total_level_value = 0;
392
393 bool stop = false;
394 while (not stop) {
395#if defined DEBUG
396 // ensure 'p' does not contain an infinite
397 // value caused by possible underflows
398 assert(p <= t.get_num_nodes());
399#endif
400
401#if defined __LAL_DEBUG_DMax_1_thistle
402 std::cout << " __________________________________________\n";
403 std::cout << " Find next non-neighbor starting at p= " << p << '\n';
404#endif
405
406 // find the next non-neighbor of 'thistle'
407 while (p > 0 and is_thistle_neighbor[arr[position_t{p}]] == 1) {
408 total_level_value += __LAL_level_vertex(arr[position_t{p}]);
409 ++num_neighbors;
410
411#if defined __LAL_DEBUG_DMax_1_thistle
412 std::cout << " Vertex " << arr[position_t{p}] << " is a neighbor\n";
413 std::cout << " At position: " << p << '\n';
414 std::cout << " Of level value: " << __LAL_level_vertex(arr[position_t{p}]) << '\n';
415#endif
416
417 --p;
418 }
419
420#if defined __LAL_DEBUG_DMax_1_thistle
421 std::cout << " Sum of level values: " << total_level_value << '\n';
422 std::cout << " Number of neighbors: " << num_neighbors << '\n';
423#endif
424
425 const node to_move = arr[position_t{p}];
426
427 if (is_thistle_neighbor[to_move] == 1) {
428#if defined DEBUG
429 assert(p == 0);
430#endif
431 stop = true;
432 }
433 else {
434#if defined DEBUG
435 assert(is_thistle_neighbor[to_move] == 0);
436#endif
437 const int64_t level_nonneigh = __LAL_level_vertex(to_move);
438
439#if defined __LAL_DEBUG_DMax_1_thistle
440 std::cout << " First non-neighbor: " << to_move << '\n';
441 std::cout << " at position: " << p << '\n';
442 std::cout << " of level: " << level_nonneigh << '\n';
443 std::cout << " Total level values: " << total_level_value << '\n';
444 std::cout << " Number of neighbors: " << num_neighbors << '\n';
445 std::cout << " -(j + 1)*level_nonneigh= " << -(num_neighbors + 1)*level_nonneigh << '\n';
446#endif
447
448 const int64_t gain = -(num_neighbors + 1)*level_nonneigh + total_level_value + thistle_level;
449
450#if defined __LAL_DEBUG_DMax_1_thistle
451 std::cout << " gain= " << gain << '\n';
452#endif
453
454 if (gain > 0) {
455 // move the vertex at position 'q' to the right of the thistle
456 shift_vertex_to_right(t, thistle, p, arr);
457
458 // vertex 'thistle' has been moved one position to the left
459 }
460
461 stop = gain <= 0 or p == 0;
462 // the case "p == 0" triggers "stop = true"
463 p = (p > 0 ? p - 1 : p);
464 }
465
466#if defined __LAL_DEBUG_DMax_1_thistle
467 print_arrangement("After moving vertex '" + std::to_string(to_move) + "'", arr);
468#endif
469 }
470}
471
472/*
473inline void adjust_nonneighbors_of_thistle_exhaustive
474(
475 const graphs::free_tree& t,
476 const node thistle,
477 const array<char>& is_thistle_neighbor,
478 linear_arrangement& arr
479)
480noexcept
481{
482#if defined DEBUG
483 assert(arr[node_t{thistle}] > 0);
484#endif
485
486 linear_arrangement copy = arr;
487 uint64_t D = linarr::sum_edge_lengths(t, copy);
488
489 position_t p = arr[node_t{thistle}];
490
491 bool stop = false;
492 while (not stop) {
493#if defined DEBUG
494 // ensure 'p' does not contain an infinite
495 // value caused by possible underflows
496 assert(p <= t.get_num_nodes());
497#endif
498
499#if defined __LAL_DEBUG_DMax_1_thistle
500 std::cout << " __________________________________________\n";
501 std::cout << " Find next non-neighbor starting at p= " << p << '\n';
502#endif
503
504 // find the next non-neighbor of 'thistle'
505 while (p > 0ull and is_thistle_neighbor[arr[p]] == 1) {
506 --p;
507 }
508
509 const node to_move = arr[p];
510
511 if (is_thistle_neighbor[to_move] == 1) {
512#if defined DEBUG
513 assert(p == 0ull);
514#endif
515 stop = true;
516 }
517 else {
518
519 shift_vertex_to_right(t, thistle, p, copy);
520 uint64_t D_new = linarr::sum_edge_lengths(t, copy);
521
522 if (D_new > D) {
523 arr = copy;
524 D = D_new;
525 }
526
527 stop = p == 0ull;
528 }
529 }
530}
531*/
532
554template <bool make_arrangement>
556(
557 const graphs::free_tree& t,
558 const node thistle,
559 const int64_t thistle_level,
560 const array<char>& is_thistle_neighbor,
561 const array<char>& thistle_side_per_vertex,
563 array<node>& inv_arr,
564 level_signature_per_vertex& levels_per_vertex,
566)
567noexcept
568{
569 const auto n = t.get_num_nodes();
570
571#if defined DEBUG
572#if defined __LAL_DEBUG_DMax_1_thistle
573 std::cout << " Chosen level value: " << thistle_level << '\n';
574#endif
575#endif
576
578 t, thistle, thistle_level, thistle_side_per_vertex,
579 levels_per_vertex, inv_arr
580 );
581
582#if defined DEBUG
583 arr = linear_arrangement::from_inverse(inv_arr.begin(), inv_arr.end());
584#if defined __LAL_DEBUG_DMax_1_thistle
585 print_arrangement("Initial arrangement", arr);
586#endif
587 assert(linarr::is_arrangement(t, arr));
588 // sum of edge lengths prior to adjustments
589 const uint64_t __D1 = linarr::sum_edge_lengths(t, arr);
590#if defined __LAL_DEBUG_DMax_1_thistle
591 std::cout << " __D1= " << __D1 << '\n';
592#endif
593#endif
594
595 // sort the vertices of level value equal to the thistle's so that we find
596 // (N ... N t O ... O)
597 // where
598 // - N denotes the neighbors of the thistle
599 // - t is the thistle
600 // - O are the other vertices
601 sort_level_sequences(n, thistle, is_thistle_neighbor, levels_per_vertex, inv_arr);
602
603 // Construct the arrangement object now, since it is needed for further
604 // operations. Object 'inv_arr' is no longer needed.
605 arr = linear_arrangement::from_inverse(inv_arr.begin(), inv_arr.end());
606
607#if defined DEBUG
608#if defined __LAL_DEBUG_DMax_1_thistle
609 print_arrangement("After sorting all sequences of equal level value", arr);
610#endif
611 assert(linarr::is_arrangement(t, arr));
612 const uint64_t __D2 = linarr::sum_edge_lengths(t, arr);
613#if defined __LAL_DEBUG_DMax_1_thistle
614 std::cout << " __D2= " << __D2 << '\n';
615#endif
616 assert(__D2 == __D1);
617#endif
618
620 (t, thistle_level, thistle, is_thistle_neighbor, levels_per_vertex, arr);
621
622 /*
623 adjust_nonneighbors_of_thistle_exhaustive
624 (t, thistle, is_thistle_neighbor, arr);
625 */
626
627#if defined DEBUG
628#if defined __LAL_DEBUG_DMax_1_thistle
629 print_arrangement("After moving thistle and readjusting other vertices", arr);
630#endif
631 assert(linarr::is_arrangement(t, arr));
632#endif
633
634 const uint64_t D = linarr::sum_edge_lengths(t, arr);
635
636#if defined DEBUG
637#if defined __LAL_DEBUG_DMax_1_thistle
638 std::cout << " D= " << D << '\n';
639#endif
640 assert(D >= __D2);
641#endif
642
643 if constexpr (make_arrangement) {
644 if (res.first < D) {
645 res.first = D;
646 res.second = std::move(arr);
647 }
648 }
649 else {
650 res = std::max(res, D);
651 }
652}
653
674template <bool make_arrangement>
676(
677 const graphs::free_tree& t,
678 const node thistle,
679 const array<char>& is_thistle_neighbor,
680
682 array<node>& inv_arr,
683 level_signature_per_vertex& level_per_vertex,
684 array<char>& thistle_side_per_vertex,
685
687)
688noexcept
689{
690 const auto thistle_deg = t.get_degree(thistle);
691 const neighbourhood& thistle_neighs = t.get_neighbors(thistle);
692
693 array<char> binary_combination(thistle_deg, 0);
694
695#if defined __LAL_DEBUG_DMax_1_thistle
696 std::cout << "Thistle: " << thistle << '\n';
697 int counter = 0;
698#endif
699
700#if defined DEBUG
701 std::size_t num_combinations = 0;
702#endif
703
704 BFS bfs(t);
705 bfs.set_process_neighbour(
706 [&](const auto&, node u, node v, bool) {
707 thistle_side_per_vertex[v] = other_side(thistle_side_per_vertex[u]);
708 }
709 );
710
711 do {
712#if defined __LAL_DEBUG_DMax_1_thistle
713 std::cout << " Binary combination: " << counter++ << '\n';
714 std::cout << " ";
715 for (std::size_t j = 0; j < thistle_deg; ++j) {
716 std::cout << int(binary_combination[j]) << ' ';
717 }
718 std::cout << '\n';
719#endif
720
721#if defined DEBUG
722 ++num_combinations;
723#endif
724
725 // calculate the level of the thistle
726 int64_t thistle_level = 0;
727 for (std::size_t i = 0; i < thistle_neighs.size(); ++i) {
728 if (binary_combination[i] == LEFT_SIDE) {
729 // Neighbour of the thistle goes to the left half of the arrangement.
730 --thistle_level;
731 thistle_side_per_vertex[ thistle_neighs[i] ] = LEFT_SIDE;
732 }
733 else {
734 // Neighbour of the thistle goes to the right half of the arrangement.
735 ++thistle_level;
736 thistle_side_per_vertex[ thistle_neighs[i] ] = RIGHT_SIDE;
737 }
738 }
739
740 // ignore orientations where the root is not a thistle vertex
741 if (thistle_level >= 0 and to_uint64(thistle_level) != thistle_deg) {
742
743 bfs.set_visited(thistle, true);
744 for (std::size_t i = 0; i < thistle_neighs.size(); ++i) {
745 bfs.start_at(thistle_neighs[i]);
746 }
747 bfs.clear_visited();
748 bfs.clear_queue();
749
750 // merge the arrangements and keep track of the maximum
752 t,
753 thistle, thistle_level,
754 is_thistle_neighbor, thistle_side_per_vertex,
755 arr, inv_arr, level_per_vertex,
756 res
757 );
758 }
759#if defined __LAL_DEBUG_DMax_1_thistle
760 else {
761 std::cout << " Ignore negative values and non-thistle configurations.\n";
762 std::cout << " Level value: " << thistle_level << '\n';
763 std::cout << " Degree: " << t.get_degree(thistle) << '\n';
764 }
765#endif
766
767 }
768 while (next_binary(binary_combination.begin(), binary_combination.end()));
769
770#if defined DEBUG
771 assert(num_combinations == 1ull << thistle_deg);
772#endif
773}
774
775} // -- namespace bits
776
790template <bool make_arrangement>
792(
793 const graphs::free_tree& t,
794 const std::vector<properties::branchless_path>& all_paths,
795 const array<std::size_t>& node_to_path
796)
797noexcept
798{
799#if defined DEBUG
800 assert(t.is_tree());
801#endif
802
803 const auto n = t.get_num_nodes();
804
805#if defined __LAL_DEBUG_DMax_1_thistle
806 {
807 std::cout << "Start tree\n";
808 std::cout << t << '\n';
809 const auto hv = t.get_head_vector(0);
810 std::cout << hv[0];
811 for (std::size_t i = 1; i < hv.size(); ++i) {
812 std::cout << ' ' << hv[i];
813 }
814 std::cout << '\n';
815 }
816#endif
817
819 if constexpr (make_arrangement) {
820 res.first = 0;
821 res.second.resize(1);
822 }
823 else {
824 res = 0;
825 }
826
827 // whether or an internal of a branchless path was already used
828 array<char> internal_in_path_was_used(all_paths.size(), 0);
829
830 // actual linear arrangement
831 linear_arrangement arr(n);
832 // simple inverse arrangement
833 array<node> inv_arr(n);
834 // the level value per vertex
835 level_signature_per_vertex level_per_vertex(n);
836 // the side of the thistle at which every vertex is found
837 array<char> thistle_side_per_vertex(n);
838 // used to query whether a vertex is neighbor of the thistle or not
839 array<char> is_thistle_neighbor(n, 0);
840
841 for (node thistle = 0; thistle < n; ++thistle) {
842 const uint64_t deg_thistle = t.get_degree(thistle);
843
844 // ignore leaves
845 if (deg_thistle == 1) { continue; }
846
847 // do we have to use this internal vertex of a branchless path as a thistle?
848 if (deg_thistle == 2) {
849 const std::size_t pidx = node_to_path[thistle];
850 // not in this case
851 if (internal_in_path_was_used[pidx] == 1) {
852#if defined __LAL_DEBUG_DMax_1_thistle
853 std::cout << "Thistle belongs to path " << pidx << " and will not be tested.\n";
854#endif
855 continue;
856 }
857
858 // do not use internal vertices of this branchless path anymore
859 internal_in_path_was_used[pidx] = 1;
860#if defined __LAL_DEBUG_DMax_1_thistle
861 std::cout << "Thistle vertex belongs to path " << pidx << ".\n";
862#endif
863 }
864
865 const neighbourhood& neighs = t.get_neighbors(thistle);
866
867 // set neighbors of thistle
868 for (node u : neighs) { is_thistle_neighbor[u] = 1; }
869
870 // Find best orientation for this thistle.
872 t, thistle, is_thistle_neighbor,
873 arr, inv_arr, level_per_vertex, thistle_side_per_vertex,
874 res
875 );
876
877 // unset neighbors of thistle
878 for (node u : neighs) { is_thistle_neighbor[u] = 0; }
879 }
880
881#if defined __LAL_DEBUG_DMax_1_thistle
882 {
883 std::cout << "Finish tree\n";
884 std::cout << t << '\n';
885 const auto hv = t.get_head_vector(0);
886 std::cout << hv[0];
887 for (std::size_t i = 1; i < hv.size(); ++i) {
888 std::cout << ' ' << hv[i];
889 }
890 std::cout << '\n';
891 }
892#endif
893
894 return res;
895}
896
909template <bool make_arrangement>
910[[nodiscard]] inline std::conditional_t<
911 make_arrangement,
912 std::pair<uint64_t, linear_arrangement>,
913 uint64_t
914>
916 const graphs::free_tree& t,
917 const std::vector<properties::branchless_path>& all_paths
918)
919noexcept
920{
921#if defined DEBUG
922 assert(t.is_tree());
923#endif
924
925 // assign all internal vertices a path index.
926 array<std::size_t> node_to_path(t.get_num_nodes());
927 for (std::size_t i = 0; i < all_paths.size(); ++i) {
928 const properties::branchless_path& p = all_paths[i];
929 const std::vector<node>& seq = p.get_vertex_sequence();
930 for (std::size_t j = 1; j < seq.size() - 1; ++j) {
931 const node u = seq[j];
932 node_to_path[u] = i;
933 }
934 }
935
936 return AEF<make_arrangement>(t, all_paths, node_to_path);
937}
938
939#undef __LAL_level_position
940#undef __LAL_level_vertex
941
942#if defined __LAL_DEBUG_DMax_1_thistle
943#undef __LAL_DEBUG_DMax_1_thistle
944#endif
945
946} // -- namespace thistle_1
947} // -- namespace DMax
948} // -- namespace detail
949} // -- namespace lal
Abstract graph Breadth-First Search traversal.
Definition traversal.hpp:89
A class that implements level signatures of an array.
Definition level_signature.hpp:90
Free tree graph class.
Definition free_tree.hpp:60
Linear arrangement of vertices.
Definition linear_arrangement.hpp:103
static linear_arrangement from_inverse(const std::vector< node > &v) noexcept
Construct a linear arrangement from an inverse arrangement.
Definition linear_arrangement.hpp:245
static constexpr color_t red
A color, called red, of value 0.
Definition bipartite_graph_coloring.hpp:72
static constexpr color_t blue
A color, called blue, of value 1.
Definition bipartite_graph_coloring.hpp:74
Branchless paths in trees.
Definition branchless_path.hpp:73
const std::vector< node > & get_vertex_sequence() const noexcept
Gets the vertex sequence of this path as a vector.
Definition branchless_path.hpp:158
static constexpr char other_side(char side) noexcept
The other side. "Right" if 'side' is "left"; "left" if 'side' is "right".
Definition 1_eq_thistle_AEF.hpp:128
void adjust_nonneighbors_of_thistle_smart(const graphs::free_tree &t, const int64_t thistle_level, const node thistle, const array< char > &is_thistle_neighbor, const level_signature_per_vertex &levels_per_vertex, linear_arrangement &arr) noexcept
Adjust misplaced nonneighbors of the thistle vertex in a smart way.
Definition 1_eq_thistle_AEF.hpp:367
std::conditional_t< make_arrangement, std::pair< uint64_t, linear_arrangement >, uint64_t > result_t
Result type of the function.
Definition 1_eq_thistle_AEF.hpp:142
static constexpr char LEFT_SIDE
Left side of the thistle vertex.
Definition 1_eq_thistle_AEF.hpp:124
void merge_arrangements(const graphs::free_tree &t, const node thistle, const int64_t thistle_level, const array< char > &is_thistle_neighbor, const array< char > &thistle_side_per_vertex, linear_arrangement &arr, array< node > &inv_arr, level_signature_per_vertex &levels_per_vertex, result_t< make_arrangement > &res) noexcept
Tries to make a maximal arrangement with a given thistle vertex of a given level value.
Definition 1_eq_thistle_AEF.hpp:556
bool next_binary(iterator_t begin, iterator_t end) noexcept
Next binary combination of 0's and 1's.
Definition 1_eq_thistle_AEF.hpp:101
static constexpr char RIGHT_SIDE
Right side of the thistle vertex.
Definition 1_eq_thistle_AEF.hpp:126
void choose_orientations_for_thistle_neighbors(const graphs::free_tree &t, const node thistle, const array< char > &is_thistle_neighbor, linear_arrangement &arr, array< node > &inv_arr, level_signature_per_vertex &level_per_vertex, array< char > &thistle_side_per_vertex, result_t< make_arrangement > &res) noexcept
Tries to make a maximal arrangement with a given thistle vertex of a given level value.
Definition 1_eq_thistle_AEF.hpp:676
void shift_vertex_to_right(const graphs::free_tree &t, const node thistle, position_t p, linear_arrangement &arr) noexcept
Moves the vertex at position p to the right of the thistle vertex.
Definition 1_eq_thistle_AEF.hpp:337
void construct_initial_arrangement(const graphs::free_tree &t, const node thistle, const int64_t thistle_level, const array< char > &thistle_side_per_vertex, level_signature_per_vertex &levels_per_vertex, array< node > &inv_arr) noexcept
Construct the initial arrangement that will later be improved.
Definition 1_eq_thistle_AEF.hpp:180
static constexpr auto red
Typedef for properties::bipartite_graph_coloring::red.
Definition 1_eq_thistle_AEF.hpp:121
static constexpr auto blue
Typedef for properties::bipartite_graph_coloring::blue.
Definition 1_eq_thistle_AEF.hpp:119
void sort_level_sequences(const uint64_t n, const node thistle, const array< char > &is_thistle_neighbor, const level_signature_per_vertex &levels_per_vertex, array< node > &inv_arr) noexcept
Sorts the intervals of vertices of equal level value.
Definition 1_eq_thistle_AEF.hpp:285
bits::result_t< make_arrangement > AEF(const graphs::free_tree &t, const std::vector< properties::branchless_path > &all_paths, const array< std::size_t > &node_to_path) noexcept
Maximal non-bipartite Arrangement with exactly 1 thistle vertex.
Definition 1_eq_thistle_AEF.hpp:792
@ non_decreasing
Non-decreasing sort type.
@ non_increasing
Non-increasing sort.
void counting_sort(const value_iterator_t begin, const value_iterator_t end, const std::size_t largest_key_plus_1, const Callable &key, countingsort::memory< value_t > &mem) noexcept
Counting sort algorithm with reusable memory.
Definition counting_sort.hpp:152
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
bool is_arrangement(const graph_t &g, const linear_arrangement &arr) noexcept
Is a given arrangement valid?
Definition formal_constraints.hpp:104
uint64_t sum_edge_lengths(const graphs::directed_graph &g, const linear_arrangement &pi={}) noexcept
Computes the sum of the length of the edges in a linear arrangement.
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
std::vector< node > neighbourhood
List of nodes.
Definition basic_types.hpp:64
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
T * end() noexcept
Non-constant raw pointer to last+1 element.
Definition array.hpp:302
Typesafe node type.
Definition basic_types.hpp:70
Typesafe position type.
Definition basic_types.hpp:244