45#if defined __LAL_DEBUG_DMax_1_thistle
46#error "__LAL_DEBUG_DMax_1_thistle can only be defined when DEBUG is defined"
56#if defined __LAL_DEBUG_DMax_1_thistle
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>
71#include <lal/linarr/formal_constraints.hpp>
73#if defined __LAL_DEBUG_DMax_1_thistle
74#include <lal/graphs/output.hpp>
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>
99template <
typename iterator_t>
101(iterator_t begin, iterator_t end)
104 while (begin != end and *begin == 1) {
110 if (begin == end) {
return false; }
141template <
bool make_arrangement>
144 std::pair<uint64_t, linear_arrangement>,
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}]
151#if defined __LAL_DEBUG_DMax_1_thistle
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]; }
161 std::cout <<
" Inverse:";
162 for (std::size_t i = 0; i < inv.size(); ++i) { std::cout <<
' ' << inv[i]; }
183 const int64_t thistle_level,
190 const uint64_t n = t.get_num_nodes();
194 int64_t min_level_value = 0;
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;
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);
215#if defined __LAL_DEBUG_DMax_1_thistle
216 std::cout <<
"Vertex " << u <<
" was not assigned a side\n";
225 __LAL_level_vertex(thistle) = thistle_level;
228 inv_arr[left] = thistle;
231 assert(left == right);
234#if defined __LAL_DEBUG_DMax_1_thistle
235 std::cout <<
" Level per vertex:\n";
236 for (
node u = 0; u < n; ++u) {
238 <<
" level[" << u <<
"]= "
239 << levels_per_vertex[
node_t{u}]
249 inv_arr.begin(), inv_arr.begin() + left, 2*n, n,
251 return to_uint64(__LAL_level_vertex(u) - min_level_value);
257 inv_arr.begin() + right + 1, inv_arr.end(), 2*n, n,
259 return to_uint64(__LAL_level_vertex(u) - min_level_value);
298 const int64_t current_level = __LAL_level_position(p);
299 while (q < n and __LAL_level_position(q) == current_level) {
303#if defined __LAL_DEBUG_DMax_1_thistle
304 std::cout <<
" Sort the interval [" << p <<
", " << q <<
").\n";
311 inv_arr.begin() + p, inv_arr.begin() + q, 2, q - p,
314 if (is_thistle_neighbor[u] == 1) {
return 0ull; }
315 if (u == thistle) {
return 1ull; }
345 const auto n = t.get_num_nodes();
346 while (p < n - 1 and arr[p + 1ull] != thistle) {
347 arr.swap(p, p + 1ull);
350 arr.swap(p, p + 1ull);
369 const int64_t thistle_level,
378 assert(arr[
node_t{thistle}] > 0);
384#if defined __LAL_DEBUG_DMax_1_thistle
385 std::cout <<
" Thistle position p= " << p + 1 <<
'\n';
389 int64_t num_neighbors = 0;
391 int64_t total_level_value = 0;
398 assert(p <= t.get_num_nodes());
401#if defined __LAL_DEBUG_DMax_1_thistle
402 std::cout <<
" __________________________________________\n";
403 std::cout <<
" Find next non-neighbor starting at p= " << p <<
'\n';
407 while (p > 0 and is_thistle_neighbor[arr[
position_t{p}]] == 1) {
408 total_level_value += __LAL_level_vertex(arr[
position_t{p}]);
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';
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';
427 if (is_thistle_neighbor[to_move] == 1) {
435 assert(is_thistle_neighbor[to_move] == 0);
437 const int64_t level_nonneigh = __LAL_level_vertex(to_move);
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';
448 const int64_t gain = -(num_neighbors + 1)*level_nonneigh + total_level_value + thistle_level;
450#if defined __LAL_DEBUG_DMax_1_thistle
451 std::cout <<
" gain= " << gain <<
'\n';
461 stop = gain <= 0 or p == 0;
463 p = (p > 0 ? p - 1 : p);
466#if defined __LAL_DEBUG_DMax_1_thistle
467 print_arrangement(
"After moving vertex '" + std::to_string(to_move) +
"'", arr);
554template <
bool make_arrangement>
559 const int64_t thistle_level,
569 const auto n = t.get_num_nodes();
572#if defined __LAL_DEBUG_DMax_1_thistle
573 std::cout <<
" Chosen level value: " << thistle_level <<
'\n';
578 t, thistle, thistle_level, thistle_side_per_vertex,
579 levels_per_vertex, inv_arr
584#if defined __LAL_DEBUG_DMax_1_thistle
585 print_arrangement(
"Initial arrangement", arr);
590#if defined __LAL_DEBUG_DMax_1_thistle
591 std::cout <<
" __D1= " << __D1 <<
'\n';
608#if defined __LAL_DEBUG_DMax_1_thistle
609 print_arrangement(
"After sorting all sequences of equal level value", arr);
613#if defined __LAL_DEBUG_DMax_1_thistle
614 std::cout <<
" __D2= " << __D2 <<
'\n';
616 assert(__D2 == __D1);
620 (t, thistle_level, thistle, is_thistle_neighbor, levels_per_vertex, arr);
628#if defined __LAL_DEBUG_DMax_1_thistle
629 print_arrangement(
"After moving thistle and readjusting other vertices", arr);
637#if defined __LAL_DEBUG_DMax_1_thistle
638 std::cout <<
" D= " << D <<
'\n';
643 if constexpr (make_arrangement) {
646 res.second = std::move(arr);
650 res = std::max(res, D);
674template <
bool make_arrangement>
690 const auto thistle_deg = t.get_degree(thistle);
691 const neighbourhood& thistle_neighs = t.get_neighbors(thistle);
695#if defined __LAL_DEBUG_DMax_1_thistle
696 std::cout <<
"Thistle: " << thistle <<
'\n';
701 std::size_t num_combinations = 0;
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]);
712#if defined __LAL_DEBUG_DMax_1_thistle
713 std::cout <<
" Binary combination: " << counter++ <<
'\n';
715 for (std::size_t j = 0; j < thistle_deg; ++j) {
716 std::cout << int(binary_combination[j]) <<
' ';
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) {
731 thistle_side_per_vertex[ thistle_neighs[i] ] =
LEFT_SIDE;
736 thistle_side_per_vertex[ thistle_neighs[i] ] =
RIGHT_SIDE;
741 if (thistle_level >= 0 and
to_uint64(thistle_level) != thistle_deg) {
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]);
753 thistle, thistle_level,
754 is_thistle_neighbor, thistle_side_per_vertex,
755 arr, inv_arr, level_per_vertex,
759#if defined __LAL_DEBUG_DMax_1_thistle
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';
771 assert(num_combinations == 1ull << thistle_deg);
790template <
bool make_arrangement>
794 const std::vector<properties::branchless_path>& all_paths,
803 const auto n = t.get_num_nodes();
805#if defined __LAL_DEBUG_DMax_1_thistle
807 std::cout <<
"Start tree\n";
808 std::cout << t <<
'\n';
809 const auto hv = t.get_head_vector(0);
811 for (std::size_t i = 1; i < hv.size(); ++i) {
812 std::cout <<
' ' << hv[i];
819 if constexpr (make_arrangement) {
821 res.second.resize(1);
828 array<char> internal_in_path_was_used(all_paths.size(), 0);
841 for (
node thistle = 0; thistle < n; ++thistle) {
842 const uint64_t deg_thistle = t.get_degree(thistle);
845 if (deg_thistle == 1) {
continue; }
848 if (deg_thistle == 2) {
849 const std::size_t pidx = node_to_path[thistle];
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";
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";
868 for (
node u : neighs) { is_thistle_neighbor[u] = 1; }
872 t, thistle, is_thistle_neighbor,
873 arr, inv_arr, level_per_vertex, thistle_side_per_vertex,
878 for (
node u : neighs) { is_thistle_neighbor[u] = 0; }
881#if defined __LAL_DEBUG_DMax_1_thistle
883 std::cout <<
"Finish tree\n";
884 std::cout << t <<
'\n';
885 const auto hv = t.get_head_vector(0);
887 for (std::size_t i = 1; i < hv.size(); ++i) {
888 std::cout <<
' ' << hv[i];
909template <
bool make_arrangement>
910[[nodiscard]]
inline std::conditional_t<
912 std::pair<uint64_t, linear_arrangement>,
917 const std::vector<properties::branchless_path>& all_paths
927 for (std::size_t i = 0; i < all_paths.size(); ++i) {
930 for (std::size_t j = 1; j < seq.size() - 1; ++j) {
931 const node u = seq[j];
939#undef __LAL_level_position
940#undef __LAL_level_vertex
942#if defined __LAL_DEBUG_DMax_1_thistle
943#undef __LAL_DEBUG_DMax_1_thistle
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