50#include <lal/linear_arrangement.hpp>
51#include <lal/detail/pairs_utils.hpp>
52#include <lal/detail/graphs/traversal.hpp>
53#include <lal/detail/properties/tree_centroid.hpp>
54#include <lal/detail/graphs/size_subtrees.hpp>
55#include <lal/detail/sorting/counting_sort.hpp>
56#include <lal/detail/data_array.hpp>
57#include <lal/detail/macros/basic_convert.hpp>
58#include <lal/detail/linarr/Dopt_utils.hpp>
63namespace unconstrained {
72using namespace Dopt_utils;
118 assert(ord.size() > 0);
121 const uint64_t k = ord.size() - 1;
122 const uint64_t t_0 = ord[0].size;
127 for (uint64_t i = 0; i <= 2*q; ++i) {
131 uint64_t z = n - sum;
132 uint64_t tricky_formula = (t_0 + 2)/2 + (z + 2)/2;
134 uint64_t t_2q = ord[2*q].size;
136 while (t_2q <= tricky_formula) {
139 if (q > 0) { z += ord[2*q - 1].size; }
140 tricky_formula = (t_0 + 2)/2 + (z + 2)/2;
142 if (q == 0) {
return {}; }
144 t_2q = ord[2*q].size;
191 if (ord.size() < 2) {
return {}; }
194 const uint64_t k = ord.size() - 1;
195 const uint64_t t_0 = ord[0].size;
197 uint64_t p = (k - 1)/2;
200 for (uint64_t i = 0; i <= 2*p + 1; ++i) {
204 uint64_t y = n - sum;
205 uint64_t tricky_formula = (t_0 + 2)/2 + (y + 2)/2;
206 uint64_t t_2p_plus_1 = ord[2*p + 1].size;
208 while (t_2p_plus_1 <= tricky_formula) {
209 y = y + ord[2*p + 1].size + ord[2*p].size;
210 tricky_formula = (t_0 + 2)/2 + (y + 2)/2;
212 if (p == 0) {
return {}; }
214 t_2p_plus_1 = ord[2*p + 1].size;
229 uint64_t pos = v.
size() - 1;
230 uint64_t right_pos = pos;
231 uint64_t left_pos = 1;
234 while (j <= 2*p + 1) {
240 if (pos > left_pos) {
265 uint64_t pos = v.
size() - 1;
266 uint64_t right_pos = pos;
267 uint64_t left_pos = 1;
276 if (pos > left_pos) {
311 for (std::size_t i = 0; i < u_neighs.size(); ++i) {
313 const node ui = u_neighs[i];
315 const uint64_t s_ui = s[ui];
320 M = std::max(M, s_ui);
326 [](
const node_size& p) {
return p.size; }
344template <
char root,
bool make_arrangement>
352 std::vector<node> reachable(t.get_num_nodes_component(one_node));
354 auto it = reachable.begin();
359 const uint64_t size_tree = t.get_num_nodes_component(one_node);
364 assert(size_tree > 0);
368 if (size_tree == 1) {
370 assert(one_node == reachable[0]);
371 assert(start <= t.get_num_nodes());
373 if constexpr (make_arrangement) {
374 mla.assign(one_node, start);
387 const uint64_t n_0 = ord[0].
size;
388 const node t_0 = ord[0].v;
390 t.remove_edge(u, t_0,
false,
false);
393 calculate_mla<RIGHT_ANCHOR, make_arrangement>(t, t_0, start, mla, c1);
396 calculate_mla<LEFT_ANCHOR, make_arrangement>(t, u, start + n_0, mla, c2);
400 t.add_edge(u, t_0,
false,
false);
404 const uint64_t uq = *q;
405 cost = std::numeric_limits<uint64_t>::max();
407 std::vector<edge> edges(2*uq + 1);
408 for (uint64_t i = 0; i <= 2*uq; ++i) {
409 edges[i] = {u, ord[i].v};
413 t.remove_edges(edges,
false,
false);
416 uint64_t size_rest_of_trees = 0;
417 for (uint64_t i = 2*uq + 1; i < ord.
size(); ++i) {
418 size_rest_of_trees += ord[i].
size;
421 for (uint64_t i = 0; i <= 2*uq; ++i) {
422 const auto Q_i =
get_Q(uq, i);
424 t.add_edge(u, ord[i].v);
428 uint64_t start_aux = start;
431 for (uint64_t j = 1; j <= uq; ++j) {
435 calculate_mla<RIGHT_ANCHOR, make_arrangement>(
437 ord[pos_in_ord].v, start_aux,
440 start_aux += ord[pos_in_ord].
size;
446 calculate_mla<NO_ANCHOR, make_arrangement>(t, u, start_aux, arr_aux, c_i_j);
450 start_aux += ord[i].
size + 1 + size_rest_of_trees;
451 for (uint64_t j = uq + 1; j <= 2*uq; ++j) {
454 uint64_t c_i_j_in = 0;
455 calculate_mla<LEFT_ANCHOR, make_arrangement>(
457 ord[pos_in_ord].v, start_aux,
460 start_aux += ord[pos_in_ord].
size;
468 for (uint64_t j = 1; j <= uq; ++j) {
469 subs += (uq - j + 1)*(ord[Q_i[j]].size + ord[Q_i[2*uq - j + 1]].size);
476 if constexpr (make_arrangement) {
477 mla = std::move(arr_aux);
481 assert(u != ord[i].v);
483 t.remove_edge(u, ord[i].v,
false,
false);
487 t.add_edges(edges,
false,
false);
495 const uint64_t n_0 = ord[0].
size;
496 const node t_0 = ord[0].v;
498 assert(one_node != t_0);
501 t.remove_edge(one_node, t_0,
false,
false);
507 calculate_mla<NO_ANCHOR, make_arrangement>
508 (t, one_node, start, mla, c1);
510 calculate_mla<LEFT_ANCHOR, make_arrangement>
511 (t, t_0, start + size_tree - ord[0].size, mla, c2);
514 calculate_mla<RIGHT_ANCHOR, make_arrangement>
515 (t, t_0, start, mla, c1);
517 calculate_mla<NO_ANCHOR, make_arrangement>
518 (t, one_node, start + n_0, mla, c2);
521 cost = c1 + c2 + size_tree - ord[0].
size;
522 t.add_edge(one_node, t_0,
false,
false);
539 const uint64_t up = *p;
540 cost = std::numeric_limits<uint64_t>::max();
542 std::vector<edge> edges(2*up + 2);
543 for (uint64_t i = 0; i <= 2*up + 1; ++i) {
544 edges[i] = {one_node, ord[i].v};
548 t.remove_edges(edges,
false,
false);
551 uint64_t size_rest_of_trees= 0;
552 for (uint64_t i = 2*up + 2; i < ord.
size() ;++i) {
553 size_rest_of_trees += ord[i].
size;
556 for (uint64_t i = 0; i <= 2*up + 1; ++i) {
557 const auto P_i =
get_P(up, i);
558 t.add_edge(one_node, ord[i].v,
false,
false);
562 uint64_t start_aux = start;
567 for (uint64_t j = 1; j <= up; ++j) {
570 uint64_t c_i_j_in = 0;
571 calculate_mla<RIGHT_ANCHOR, make_arrangement>(
573 ord[pos_in_ord].v, start_aux,
576 start_aux += ord[pos_in_ord].
size;
582 calculate_mla<NO_ANCHOR, make_arrangement>
583 (t, one_node, start_aux, arr_aux, c_i_j);
585 start_aux += ord[i].
size + 1 + size_rest_of_trees;
589 for (uint64_t j = up + 1; j <= 2*up + 1; ++j) {
592 uint64_t c_i_j_in = 0;
593 calculate_mla<LEFT_ANCHOR, make_arrangement>(
595 ord[pos_in_ord].v, start_aux,
598 start_aux += ord[pos_in_ord].
size;
605 for (uint64_t j = 2*up + 1; j >= up + 1; --j) {
608 uint64_t c_i_j_in = 0;
609 calculate_mla<RIGHT_ANCHOR, make_arrangement>(
611 ord[pos_in_ord].v, start_aux,
614 start_aux += ord[pos_in_ord].
size;
620 calculate_mla<NO_ANCHOR, make_arrangement>
621 (t, one_node, start_aux, arr_aux, c_i_j);
623 start_aux += ord[i].
size + 1 + size_rest_of_trees;
627 for (uint64_t j = up; j >= 1; --j) {
630 uint64_t c_i_j_in = 0;
631 calculate_mla<LEFT_ANCHOR, make_arrangement>(
633 ord[pos_in_ord].v, start_aux,
636 start_aux += ord[pos_in_ord].
size;
643 c_i += size_tree*(up + 1);
644 c_i -= (up + 1)*ord[P_i[P_i.size()-1]].
size;
647 for (uint64_t j = 1; j <= up; ++j) {
648 subs += (up - j + 1)*(ord[P_i[j]].size + ord[P_i[2*up - j + 1]].size);
658 assert(one_node != ord[i].v);
660 t.remove_edge(one_node, ord[i].v,
false,
false);
664 t.add_edges(edges,
false,
false);
681template <
bool make_arrangement>
684 std::pair<uint64_t, linear_arrangement>,
697 Chung::calculate_mla<Chung::NO_ANCHOR, make_arrangement>(T, 0, 0, arr, Dmin);
699 if constexpr (make_arrangement) {
700 return {Dmin, std::move(arr)};
Abstract graph Breadth-First Search traversal.
Definition: traversal.hpp:89
void set_process_current(const BFS_process_one &f) noexcept
Set the function that controls the processing of the current node.
Definition: traversal.hpp:186
void start_at(node source) noexcept
Start traversal at a given node.
Definition: traversal.hpp:152
Free tree graph class.
Definition: free_tree.hpp:60
Linear arrangement of vertices.
Definition: linear_arrangement.hpp:103
ordering get_ordering(const graphs::free_tree &t, node u) noexcept
Sort the children of u in the rooted tree .
Definition: Dmin_Unconstrained_FC.hpp:298
std::optional< uint64_t > calculate_q(uint64_t n, const ordering &ord) noexcept
Calculate .
Definition: Dmin_Unconstrained_FC.hpp:116
void calculate_mla(graphs::free_tree &t, node one_node, position start, linear_arrangement &mla, uint64_t &cost) noexcept
Calculate a minimum linear arrangment using Fan Chung's algorithm.
Definition: Dmin_Unconstrained_FC.hpp:345
data_array< uint64_t > get_P(uint64_t p, uint64_t i) noexcept
Calculate .
Definition: Dmin_Unconstrained_FC.hpp:227
std::optional< uint64_t > calculate_p(uint64_t n, const ordering &ord) noexcept
Calculate .
Definition: Dmin_Unconstrained_FC.hpp:190
data_array< uint64_t > get_Q(uint64_t q, uint64_t i) noexcept
Calculate .
Definition: Dmin_Unconstrained_FC.hpp:263
lal::detail::data_array< node_size > ordering
Typedef for a useful type.
Definition: Dmin_Unconstrained_FC.hpp:75
std::conditional_t< make_arrangement, std::pair< uint64_t, linear_arrangement >, uint64_t > FanChung_2(const graphs::free_tree &t) noexcept
Calculates a minimum linear arrangment using Fan Chung's algorithm.
Definition: Dmin_Unconstrained_FC.hpp:687
constexpr char NO_ANCHOR
The tree is not anchored.
Definition: Dopt_utils.hpp:92
constexpr char RIGHT_ANCHOR
The tree is right-anchored.
Definition: Dopt_utils.hpp:90
constexpr char LEFT_ANCHOR
The tree is left-anchored.
Definition: Dopt_utils.hpp:88
void counting_sort(const value_iterator_t begin, const value_iterator_t end, const std::size_t largest_key_plus_1, const std::function< std::size_t(const value_t &)> &key, countingsort::memory< value_t > &mem) noexcept
Counting sort algorithm with reusable memory.
Definition: counting_sort.hpp:155
void get_size_subtrees(const tree_t &t, const node u, const node v, uint64_t *const sizes) noexcept
Calculate the size of every subtree of the tree t.
Definition: size_subtrees.hpp:74
std::pair< node, node > retrieve_centroid(const tree_t &t, const node x) noexcept
Calculate the centroid of the connected component that has node x.
Definition: tree_centroid.hpp:396
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
std::vector< node > neighbourhood
List of nodes.
Definition: basic_types.hpp:62
Wrapper of a C array for autmatic deallocation of memory.
Definition: data_array.hpp:59
std::size_t size() const noexcept
Size of the array.
Definition: data_array.hpp:204
T * end() noexcept
Non-constant raw pointer to last+1 element.
Definition: data_array.hpp:293
T * begin() noexcept
Non-constant raw pointer to first element.
Definition: data_array.hpp:291
Struct used in many algorithms to sort vertices according to some integer value.
Definition: pairs_utils.hpp:54
Non-increasing sort.
Definition: sorting_types.hpp:51