LAL: Linear Arrangement Library 24.10.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
dependency_flux.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#include <optional>
46
47// lal includes
48#include <lal/graphs/free_tree.hpp>
49#include <lal/iterators/E_iterator.hpp>
50#include <lal/detail/arrangement_wrapper.hpp>
51#include <lal/detail/sorting/counting_sort.hpp>
52#include <lal/detail/sorting/sorted_vector.hpp>
53#include <lal/detail/array.hpp>
54
55#define max_pos(u,v) (std::max(arr[u], arr[v]))
56
57namespace lal {
58namespace detail {
59
71template <class depflux, class arrangement_t>
73(
74 const graphs::free_tree& t,
75 const arrangement_t& arr,
76 const std::vector<std::pair<edge_t,uint64_t>>& edge_with_max_pos_at,
77 const position cur_pos,
78 std::vector<depflux>& flux,
79 std::vector<edge>& cur_deps
80)
81noexcept
82{
83 const node u = arr[position_t{cur_pos}];
84
85 if (cur_pos > 0) {
86 // copy previous dependencies
87 cur_deps = flux[cur_pos - 1].get_dependencies();
88 }
89
90 // find those edges ending at position 'p' ...
91 if (edge_with_max_pos_at[cur_pos].second > 0) {
92 const auto [first, last] =
93 std::equal_range(
94 cur_deps.begin(), cur_deps.end(),
95 edge_with_max_pos_at[cur_pos].first, // this ends at position p-1
96 [&](const edge_t& e1, const edge_t& e2) -> bool {
97 const auto pos_e1 = max_pos(e1.first, e1.second);
98 const auto pos_e2 = max_pos(e2.first, e2.second);
99 return pos_e1 < pos_e2;
100 }
101 );
102 if (first != cur_deps.end()) {
103 cur_deps.erase(first, last);
104 }
105 }
106
107 // add the new dependencies
108 for (const node_t v : t.get_neighbors(u)) {
109 if (arr[v] > cur_pos) {
110 cur_deps.push_back({u,*v});
111 }
112 }
113
115 for (const auto& [v,w] : cur_deps) {
116 set_endpoints.insert_sorted(v);
117 set_endpoints.insert_sorted(w);
118 }
119 for (node_t v : set_endpoints) {
120 flux[cur_pos].get_left_span() += (arr[v] <= cur_pos);
121 flux[cur_pos].get_right_span() += (arr[v] > cur_pos);
122 }
123}
124
131[[nodiscard]] inline uint64_t calculate_weight
132(const std::vector<edge>& dependencies, graphs::undirected_graph& ug)
133noexcept
134{
135 if (dependencies.size() <= 1) { return dependencies.size(); }
136
137 // build graph
138 ug.set_edges(dependencies);
139
140 // ------------------------------------------
141 // apply the "algorithm", see what happens...
142 // step 1. while we can find a leaf
143 // step 2. put incident edge in the set of disjoint dependencies
144 // step 3. delete edges incident to the other vertex
145
146 const auto find_leaf =
147 [](const graphs::undirected_graph& g) -> std::optional<node> {
148 for (node u = 0; u < g.get_num_nodes(); ++u) {
149 if (g.get_degree(u) == 1) { return u; }
150 }
151 return {};
152 };
153
154 uint64_t weight = 0;
155 // step 1
156 while (const auto leaf = find_leaf(ug)) {
157 const node u = *leaf;
158 const node v = ug.get_neighbors(u)[0];
159 // step 2
160 ++weight;
161 // step 3 -- remove edges incident to the only neighbour of the leaf
162 ug.remove_edges_incident_to(v);
163 }
164
165 return weight;
166}
167
168/*
169 * @brief Calculate fluxes in a linear arrangement.
170 * @tparam arrangement_t Type of arrangement.
171 * @param t Input free tree.
172 * @param arr Input linear arrangement.
173 * @returns The set of dependency fluxes in the arrangement.
174 */
175template <class depflux, class arrangement_t>
176[[nodiscard]] std::vector<depflux> dependency_flux_compute
177(const graphs::free_tree& t, const arrangement_t& arr)
178noexcept
179{
180 const uint64_t n = t.get_num_nodes();
181 if (n == 1) { return {}; }
182
183 // one edge entering each position
184 std::vector<std::pair<edge_t,uint64_t>> edge_with_max_pos_at(n, {{}, 0});
185 for (iterators::E_iterator e_it(t); not e_it.end(); e_it.next()) {
186 const auto [u, v] = e_it.get_edge_t();
187 const position max = max_pos(u, v);
188 edge_with_max_pos_at[max].first = {u,v};
189 ++edge_with_max_pos_at[max].second;
190 }
191
192 // the graph (of n vertices) used to calculate the weight
193 graphs::undirected_graph ug(n);
194
195 // the reusable memory for the sorting algorithm
196 sorting::countingsort::memory<edge> mem(n, n);
197
198 // declare the result to be returned
199 std::vector<depflux> flux(n - 1);
200
201 for (position cur_pos = 0; cur_pos < n - 1; ++cur_pos) {
202 // current dependencies
203 std::vector<edge> cur_deps;
204
205 // ----------------------
206 // calculate dependencies
208 (t, arr, edge_with_max_pos_at, cur_pos, flux, cur_deps);
209
210 // -------------------------------------------------
211 // calculate the weight of the flux at this position
212 // (read the paper for an "algorithm")
213 flux[cur_pos].set_weight(calculate_weight(cur_deps, ug));
214
215 // sort the dependencies by ending position so that edges
216 // can be erased more efficiently in the next iteration
219 (
220 // iterators to the container to be sorted
221 cur_deps.begin(), cur_deps.end(),
222 // largest key possible + 1
223 n,
224 // key
225 [&](const edge_t& e) -> std::size_t
226 { return max_pos(e.first, e.second); },
227 // reusable memory
228 mem
229 );
230 mem.reset_count();
231
232 flux[cur_pos].set_dependencies(std::move(cur_deps));
233 }
234
235 return flux;
236}
237
238} // -- namespace detail
239} // -- namespace lal
Sorted vector class.
Definition sorted_vector.hpp:65
iterator_t insert_sorted(const T &x) noexcept
Insert an element to the vector.
Definition sorted_vector.hpp:94
Free tree graph class.
Definition free_tree.hpp:60
Undirected graph class.
Definition undirected_graph.hpp:66
@ non_decreasing
Non-decreasing sort type.
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
uint64_t calculate_weight(const std::vector< edge > &dependencies, graphs::undirected_graph &ug) noexcept
Calculates the weight of a set of dependencies in a flux.
Definition dependency_flux.hpp:132
void calculate_dependencies_and_span(const graphs::free_tree &t, const arrangement_t &arr, const std::vector< std::pair< edge_t, uint64_t > > &edge_with_max_pos_at, const position cur_pos, std::vector< depflux > &flux, std::vector< edge > &cur_deps) noexcept
Calculate the dependencies and their span.
Definition dependency_flux.hpp:73
Main namespace of the library.
Definition basic_types.hpp:48
std::pair< node, node > edge
See Edge page for further details.
Definition basic_types.hpp:56
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::pair< node_t, node_t > edge_t
Similar to edge.
Definition basic_types.hpp:239
Typesafe node type.
Definition basic_types.hpp:70
Typesafe position type.
Definition basic_types.hpp:244