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