LAL: Linear Arrangement Library 24.10.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
brute_force.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// C++ includes
43#if defined DEBUG
44#include <cassert>
45#endif
46#include <vector>
47
48// lal includes
49#include <lal/iterators/Q_iterator.hpp>
50#include <lal/detail/array.hpp>
51#include <lal/detail/arrangement_wrapper.hpp>
52
53#define idx(i,j, C) ((i)*(C) + (j))
54#define DECIDED_C_GT (upper_bound + 1)
55
56namespace lal {
57namespace detail {
58namespace crossings {
59
61namespace brute_force {
62
63// =============================================================================
64// ACTUAL ALGORITHM
65// =============================================================================
66
81template <bool decide_upper_bound, class arrangement_t>
82[[nodiscard]] uint64_t compute
83(
85 const arrangement_t& arr,
86 const uint64_t upper_bound = 0
87)
88noexcept
89{
90 uint64_t C = 0;
91
92 // iterate over the pairs of edges that will potentially cross
93 // using the information given in the linear arrangement
94 for (node_t u = 0ull; u < g.get_num_nodes(); ++u) {
95 // 'pu' is the position of node 'u'
96 const position pu = arr[u];
97 const neighbourhood& Nu = g.get_neighbors(*u);
98 for (node_t v : Nu) {
99 // 'pv' is the position of node 'v'
100 const position pv = arr[v];
101 if (pu >= pv) { continue; }
102
103 // 'u' and 'v' is a pair of connected nodes such that 'u'
104 // is "to the left of" 'v' in the linear arrangement 'seq'
105
106 // iterate through the positions between 'u' and 'v'
107 const position begin = pu + 1;
108 const position end = pv - 1;
109
110 for (position_t pw = begin; pw <= end; ++pw) {
111 // 'w' is the node at position 'pw'
112 const node w = arr[pw];
113 const neighbourhood& Nw = g.get_neighbors(w);
114 for (node_t z : Nw) {
115 const position pz = arr[z];
116
117 // if arr[w] < arr[z] then
118 // 'w' and 'z' is a pair of connected nodes such that
119 // 'w' is "to the left of" 'z' in the random seq 'seq'.
120 // Formally: arr[w] < arr[z]
121
122 // Also, by construction: arr[u] < arr[w]
123 C += pw < pz and
124 pu < pw and pw < pv and pv < pz;
125
126 if constexpr (decide_upper_bound) {
127 if (C > upper_bound) { return DECIDED_C_GT; }
128 }
129 }
130 }
131 }
132 }
133
134 // none of the conditions above were true, so we must have
135 // C <= upper_bound
136 return C;
137}
138
156template <bool decide_upper_bound, class arrangement_t>
157[[nodiscard]] uint64_t inner_compute
158(
159 const graphs::directed_graph& g,
160 const position pu,
161 const position pv,
162 const arrangement_t& arr,
163 uint64_t C,
164 const uint64_t upper_bound
165)
166noexcept
167{
168 // 'u' and 'v' is a pair of connected nodes such that 'u'
169 // is "to the left of" 'v' in the linear arrangement 'seq'
170
171 // iterate through the positions between 'u' and 'v'
172 const position begin = pu + 1;
173 const position end = pv - 1;
174
175 for (position_t pw = begin; pw <= end; ++pw) {
176 // 'w' is the node at position 'pw'
177 const node w = arr[pw];
178 const neighbourhood& Nw_out = g.get_out_neighbors(w);
179 for (node_t z : Nw_out) {
180 const position pz = arr[z];
181
182 // if arr[w] < arr[z] then
183 // 'w' and 'z' is a pair of connected nodes such that
184 // 'w' is "to the left of" 'z' in the random seq 'seq'.
185 // Formally: arr[w] < arr[z]
186
187 // Also, by construction: arr[u] < arr[w]
188 C += pw < pz and
189 pu < pw and pw < pv and pv < pz;
190
191 if constexpr (decide_upper_bound) {
192 if (C > upper_bound) { return DECIDED_C_GT; }
193 }
194 }
195 const neighbourhood& Nw_in = g.get_in_neighbors(w);
196 for (node_t z : Nw_in) {
197 const position pz = arr[z];
198
199 // if arr[w] < arr[z] then
200 // 'w' and 'z' is a pair of connected nodes such that
201 // 'w' is "to the left of" 'z' in the random seq 'seq'.
202 // Formally: arr[w] < arr[z]
203
204 // Also, by construction: arr[u] < arr[w]
205 C += pw < pz and
206 pu < pw and pw < pv and pv < pz;
207
208 if constexpr (decide_upper_bound) {
209 if (C > upper_bound) { return DECIDED_C_GT; }
210 }
211 }
212 }
213
214 // none of the conditions above were true, so we must have
215 // C <= upper_bound
216 return C;
217}
218
233template <bool decide_upper_bound, class arrangement_t>
234[[nodiscard]] uint64_t compute
235(
236 const graphs::directed_graph& g,
237 const arrangement_t& arr,
238 const uint64_t upper_bound
239)
240noexcept
241{
242 uint64_t C = 0;
243
244 // iterate over the pairs of edges that will potentially cross
245 // using the information given in the linear arrangement
246 for (node_t u = 0ull; u < g.get_num_nodes(); ++u) {
247 // 'pu' is the position of node 'u'
248 const position pu = arr[u];
249 const neighbourhood& Nu_out = g.get_out_neighbors(*u);
250 for (node_t v : Nu_out) {
251 // 'pv' is the position of node 'v'
252 const position pv = arr[v];
253 if (pu >= pv) { continue; }
254 // 'u' and 'v' is a pair of connected nodes such that 'u'
255 // is "to the left of" 'v' in the linear arrangement 'seq'
256
258 (g, pu,pv, arr, C, upper_bound);
259
260 if constexpr (decide_upper_bound) {
261 if (C > upper_bound) { return DECIDED_C_GT; }
262 }
263 }
264 const neighbourhood& Nu_in = g.get_in_neighbors(*u);
265 for (node_t v : Nu_in) {
266 // 'pv' is the position of node 'v'
267 const position pv = arr[v];
268 if (pu >= pv) { continue; }
269 // 'u' and 'v' is a pair of connected nodes such that 'u'
270 // is "to the left of" 'v' in the linear arrangement 'seq'
271
273 (g, pu,pv, arr, C, upper_bound);
274
275 if constexpr (decide_upper_bound) {
276 if (C > upper_bound) { return DECIDED_C_GT; }
277 }
278 }
279 }
280
281 // none of the conditions above were true, so we must have
282 // C <= upper_bound
283 return C;
284}
285
286} // -- namespace brute_force
287
288// =============================================================================
289// CALLS TO THE ALGORITHM
290// =============================================================================
291
292// ------------------
293// single arrangement
294
303template <class graph_t, class arrangement_t>
304[[nodiscard]] uint64_t n_C_brute_force
305(const graph_t& g, const arrangement_t& arr)
306noexcept
307{
308 const uint64_t n = g.get_num_nodes();
309
310#if defined DEBUG
311 assert(arr.size() == 0 or arr.size() == n);
312#endif
313
314 if (n < 4) { return 0; }
315
316 return brute_force::compute<false>(g, arr, 0);
317}
318
319// --------------------
320// list of arrangements
321
329template <class graph_t>
330[[nodiscard]] std::vector<uint64_t> n_C_brute_force
331(const graph_t& g, const std::vector<linear_arrangement>& arrs)
332noexcept
333{
334 const uint64_t n = g.get_num_nodes();
335
336 std::vector<uint64_t> cs(arrs.size());
337 if (n < 4) {
338 // fill only when necessary
339 std::fill(cs.begin(), cs.end(), 0);
340 return cs;
341 }
342
343 /* compute C for every linear arrangement */
344 for (std::size_t i = 0; i < arrs.size(); ++i) {
345
346#if defined DEBUG
347 // ensure that no linear arrangement is empty
348 assert(arrs[i].size() == n);
349#endif
350
351 // compute C
352 cs[i] = brute_force::compute<false>(g, nonidentity_arr(arrs[i]), 0);
353 }
354
355 return cs;
356}
357
358// -----------------------------------------------------------------------------
359// DECISION
360
361// ------------------
362// single arrangement
363
374template <class graph_t, class arrangement_t>
375[[nodiscard]] uint64_t is_n_C_brute_force_lesseq_than
376(const graph_t& g, const arrangement_t& arr, const uint64_t upper_bound)
377noexcept
378{
379 const uint64_t n = g.get_num_nodes();
380
381#if defined DEBUG
382 assert(arr.size() == 0 or arr.size() == n);
383#endif
384
385 if (n < 4) { return 0; }
386
387 return brute_force::compute<true>(g, arr, upper_bound);
388}
389
390// --------------------
391// list of arrangements
392
402template <class graph_t>
403[[nodiscard]] std::vector<uint64_t> is_n_C_brute_force_lesseq_than(
404 const graph_t& g,
405 const std::vector<linear_arrangement>& arrs,
406 const uint64_t upper_bound
407)
408noexcept
409{
410 const uint64_t n = g.get_num_nodes();
411
412 std::vector<uint64_t> cs(arrs.size());
413 if (n < 4) {
414 std::fill(cs.begin(), cs.end(), 0);
415 return cs;
416 }
417
418 /* compute C for every linear arrangement */
419 for (std::size_t i = 0; i < arrs.size(); ++i) {
420#if defined DEBUG
421 // ensure that no linear arrangement is empty
422 assert(arrs[i].size() == n);
423#endif
424
425 // compute C
426 cs[i] = brute_force::compute<true>(g, nonidentity_arr(arrs[i]), upper_bound);
427 }
428
429 return cs;
430}
431
442template <class graph_t>
443[[nodiscard]] std::vector<uint64_t> is_n_C_brute_force_lesseq_than
444(
445 const graph_t& g,
446 const std::vector<linear_arrangement>& arrs,
447 const std::vector<uint64_t>& upper_bounds
448)
449noexcept
450{
451#if defined DEBUG
452 // there must be as many arrangements as upper bounds
453 assert(arrs.size() == upper_bounds.size());
454#endif
455 const uint64_t n = g.get_num_nodes();
456
457 std::vector<uint64_t> cs(arrs.size());
458 if (n < 4) {
459 std::fill(cs.begin(), cs.end(), 0);
460 return cs;
461 }
462
463 /* compute C for every linear arrangement */
464 for (std::size_t i = 0; i < arrs.size(); ++i) {
465#if defined DEBUG
466 // ensure that no linear arrangement is empty
467 assert(arrs[i].size() == n);
468#endif
469
470 // compute C
471 cs[i] = brute_force::compute<true>(g, nonidentity_arr(arrs[i]), upper_bounds[i]);
472 }
473
474 return cs;
475}
476
477} // -- namespace crossings
478} // -- namespace detail
479} // -- namespace lal
Directed graph class.
Definition directed_graph.hpp:67
uint64_t get_num_nodes() const noexcept
Returns the number of ndoes.
Definition graph.hpp:207
Undirected graph class.
Definition undirected_graph.hpp:66
const neighbourhood & get_neighbors(const node u) const noexcept
Returns the neighbourhood of node u.
Definition undirected_graph.hpp:372
uint64_t compute(const graphs::undirected_graph &g, const arrangement_t &arr, const uint64_t upper_bound=0) noexcept
Brute force computation of for undirected graphs.
Definition brute_force.hpp:83
uint64_t inner_compute(const graphs::directed_graph &g, const position pu, const position pv, const arrangement_t &arr, uint64_t C, const uint64_t upper_bound) noexcept
Brute force computation of for directed graphs.
Definition brute_force.hpp:158
uint64_t is_n_C_brute_force_lesseq_than(const graph_t &g, const arrangement_t &arr, const uint64_t upper_bound) noexcept
Brute force computation of with early termination.
Definition brute_force.hpp:376
uint64_t n_C_brute_force(const graph_t &g, const arrangement_t &arr) noexcept
Brute force computation of .
Definition brute_force.hpp:305
arrangement_wrapper< arrangement_type::nonidentity > nonidentity_arr(const linear_arrangement &arr) noexcept
Shorthand for a nonidentity arrangement.
Definition arrangement_wrapper.hpp:133
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
Typesafe node type.
Definition basic_types.hpp:70
Typesafe position type.
Definition basic_types.hpp:244