LAL: Linear Arrangement Library 23.01.00
A library focused on algorithms on linear arrangements of graphs.
Loading...
Searching...
No Matches
C_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 - 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// 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/data_array.hpp>
51#include <lal/detail/identity_arrangement.hpp>
52
53#define idx(i,j, C) ((i)*(C) + (j))
54#define DECIDED_C_GT (upper_bound + 1)
55#define DECIDED_C_LE C
56
57namespace lal {
58namespace detail {
59namespace crossings {
60
62namespace brute_force {
63
64// =============================================================================
65// ACTUAL ALGORITHM
66// =============================================================================
67
82template <bool decide_upper_bound, linarr_type arr_type>
83[[nodiscard]] uint64_t compute(
85 const linarr_wrapper<arr_type>& arr,
86 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_neighbours(*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_neighbours(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, linarr_type arr_type>
157[[nodiscard]] uint64_t inner_compute
158(
159 const graphs::directed_graph& g,
160 position pu, position pv,
161 const linarr_wrapper<arr_type>& arr,
162 uint64_t C,
163 uint64_t upper_bound
164)
165noexcept
166{
167 // 'u' and 'v' is a pair of connected nodes such that 'u'
168 // is "to the left of" 'v' in the linear arrangement 'seq'
169
170 // iterate through the positions between 'u' and 'v'
171 const position begin = pu + 1;
172 const position end = pv - 1;
173
174 for (position_t pw = begin; pw <= end; ++pw) {
175 // 'w' is the node at position 'pw'
176 const node w = arr[pw];
177 const neighbourhood& Nw_out = g.get_out_neighbours(w);
178 for (node_t z : Nw_out) {
179 const position pz = arr[z];
180
181 // if arr[w] < arr[z] then
182 // 'w' and 'z' is a pair of connected nodes such that
183 // 'w' is "to the left of" 'z' in the random seq 'seq'.
184 // Formally: arr[w] < arr[z]
185
186 // Also, by construction: arr[u] < arr[w]
187 C += pw < pz and
188 pu < pw and pw < pv and pv < pz;
189
190 if constexpr (decide_upper_bound) {
191 if (C > upper_bound) { return DECIDED_C_GT; }
192 }
193 }
194 const neighbourhood& Nw_in = g.get_in_neighbours(w);
195 for (node_t z : Nw_in) {
196 const position pz = arr[z];
197
198 // if arr[w] < arr[z] then
199 // 'w' and 'z' is a pair of connected nodes such that
200 // 'w' is "to the left of" 'z' in the random seq 'seq'.
201 // Formally: arr[w] < arr[z]
202
203 // Also, by construction: arr[u] < arr[w]
204 C += pw < pz and
205 pu < pw and pw < pv and pv < pz;
206
207 if constexpr (decide_upper_bound) {
208 if (C > upper_bound) { return DECIDED_C_GT; }
209 }
210 }
211 }
212
213 // none of the conditions above were true, so we must have
214 // C <= upper_bound
215 return C;
216}
217
232template <bool decide_upper_bound, linarr_type arr_type>
233uint64_t compute(
235 uint64_t upper_bound
236)
237noexcept
238{
239 uint64_t C = 0;
240
241 // iterate over the pairs of edges that will potentially cross
242 // using the information given in the linear arrangement
243 for (node_t u = 0ull; u < g.get_num_nodes(); ++u) {
244 // 'pu' is the position of node 'u'
245 const position pu = arr[u];
246 const neighbourhood& Nu_out = g.get_out_neighbours(*u);
247 for (node_t v : Nu_out) {
248 // 'pv' is the position of node 'v'
249 const position pv = arr[v];
250 if (pu >= pv) { continue; }
251 // 'u' and 'v' is a pair of connected nodes such that 'u'
252 // is "to the left of" 'v' in the linear arrangement 'seq'
253
254 C = inner_compute<decide_upper_bound>
255 (g, pu,pv, arr, C, upper_bound);
256
257 if constexpr (decide_upper_bound) {
258 if (C > upper_bound) { return DECIDED_C_GT; }
259 }
260 }
261 const neighbourhood& Nu_in = g.get_in_neighbours(*u);
262 for (node_t v : Nu_in) {
263 // 'pv' is the position of node 'v'
264 const position pv = arr[v];
265 if (pu >= pv) { continue; }
266 // 'u' and 'v' is a pair of connected nodes such that 'u'
267 // is "to the left of" 'v' in the linear arrangement 'seq'
268
269 C = inner_compute<decide_upper_bound>
270 (g, pu,pv, arr, C, upper_bound);
271
272 if constexpr (decide_upper_bound) {
273 if (C > upper_bound) { return DECIDED_C_GT; }
274 }
275 }
276 }
277
278 // none of the conditions above were true, so we must have
279 // C <= upper_bound
280 return C;
281}
282
283} // -- namespace brute_force
284
285// =============================================================================
286// CALLS TO THE ALGORITHM
287// =============================================================================
288
289// ------------------
290// single arrangement
291
300template <class graph_t, class arrangement_t>
301uint64_t n_C_brute_force(const graph_t& g, const arrangement_t& arr)
302noexcept
303{
304 const uint64_t n = g.get_num_nodes();
305
306#if defined DEBUG
307 assert(arr.m_arr.size() == 0 or arr.m_arr.size() == n);
308#endif
309
310 if (n < 4) { return 0; }
311
312 return brute_force::compute<false>(g, arr, 0);
313}
314
315// --------------------
316// list of arrangements
317
325template <class graph_t>
326std::vector<uint64_t> n_C_brute_force
327(const graph_t& g, const std::vector<linear_arrangement>& arrs)
328noexcept
329{
330 const uint64_t n = g.get_num_nodes();
331
332 std::vector<uint64_t> cs(arrs.size());
333 if (n < 4) {
334 // fill only when necessary
335 std::fill(cs.begin(), cs.end(), 0);
336 return cs;
337 }
338
339 /* compute C for every linear arrangement */
340 for (std::size_t i = 0; i < arrs.size(); ++i) {
341
342#if defined DEBUG
343 // ensure that no linear arrangement is empty
344 assert(arrs[i].size() == n);
345#endif
346
347 // compute C
348 cs[i] = brute_force::compute<false>(g, nonident_arr(arrs[i]), 0);
349 }
350
351 return cs;
352}
353
354// -----------------------------------------------------------------------------
355// DECISION
356
357// ------------------
358// single arrangement
359
370template <class graph_t, class arrangement_t>
372(const graph_t& g, const arrangement_t& arr, uint64_t upper_bound)
373noexcept
374{
375 const uint64_t n = g.get_num_nodes();
376
377#if defined DEBUG
378 assert(arr.m_arr.size() == 0 or arr.m_arr.size() == n);
379#endif
380
381 if (n < 4) { return 0; }
382
383 return brute_force::compute<true>(g, arr, upper_bound);
384}
385
386// --------------------
387// list of arrangements
388
398template <class graph_t>
400(const graph_t& g, const std::vector<linear_arrangement>& arrs, uint64_t upper_bound)
401noexcept
402{
403 const uint64_t n = g.get_num_nodes();
404
405 std::vector<uint64_t> cs(arrs.size());
406 if (n < 4) {
407 std::fill(cs.begin(), cs.end(), 0);
408 return cs;
409 }
410
411 /* compute C for every linear arrangement */
412 for (std::size_t i = 0; i < arrs.size(); ++i) {
413#if defined DEBUG
414 // ensure that no linear arrangement is empty
415 assert(arrs[i].size() == n);
416#endif
417
418 // compute C
419 cs[i] = brute_force::compute<true>(g, nonident_arr(arrs[i]), upper_bound);
420 }
421
422 return cs;
423}
424
435template <class graph_t>
436std::vector<uint64_t> is_n_C_brute_force_lesseq_than(
437 const graph_t& g,
438 const std::vector<linear_arrangement>& arrs,
439 const std::vector<uint64_t>& upper_bounds
440)
441noexcept
442{
443#if defined DEBUG
444 // there must be as many arrangements as upper bounds
445 assert(arrs.size() == upper_bounds.size());
446#endif
447 const uint64_t n = g.get_num_nodes();
448
449 std::vector<uint64_t> cs(arrs.size());
450 if (n < 4) {
451 std::fill(cs.begin(), cs.end(), 0);
452 return cs;
453 }
454
455 /* compute C for every linear arrangement */
456 for (std::size_t i = 0; i < arrs.size(); ++i) {
457#if defined DEBUG
458 // ensure that no linear arrangement is empty
459 assert(arrs[i].size() == n);
460#endif
461
462 // compute C
463 cs[i] = brute_force::compute<true>(g, nonident_arr(arrs[i]), upper_bounds[i]);
464 }
465
466 return cs;
467}
468
469} // -- namespace crossings
470} // -- namespace detail
471} // -- namespace lal
Directed graph class.
Definition: directed_graph.hpp:68
uint64_t get_num_nodes() const noexcept
Returns the number of ndoes.
Definition: graph.hpp:198
Undirected graph class.
Definition: undirected_graph.hpp:67
const neighbourhood & get_neighbours(node u) const noexcept
Returns the neighbourhood of node u.
Definition: undirected_graph.hpp:315
uint64_t inner_compute(const graphs::directed_graph &g, position pu, position pv, const linarr_wrapper< arr_type > &arr, uint64_t C, uint64_t upper_bound) noexcept
Brute force computation of for directed graphs.
Definition: C_brute_force.hpp:158
uint64_t compute(const graphs::undirected_graph &g, const linarr_wrapper< arr_type > &arr, uint64_t upper_bound=0) noexcept
Brute force computation of for undirected graphs.
Definition: C_brute_force.hpp:83
uint64_t is_n_C_brute_force_lesseq_than(const graph_t &g, const arrangement_t &arr, uint64_t upper_bound) noexcept
Brute force computation of with early termination.
Definition: C_brute_force.hpp:372
uint64_t n_C_brute_force(const graph_t &g, const arrangement_t &arr) noexcept
Brute force computation of .
Definition: C_brute_force.hpp:301
linarr_wrapper< linarr_type::nonident > nonident_arr(const linear_arrangement &arr) noexcept
Shorthand for a nonidentity arrangement.
Definition: identity_arrangement.hpp:121
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
A wrapper to easily use identity arrangements.
Definition: identity_arrangement.hpp:72
Typesafe node type.
Definition: basic_types.hpp:67
Typesafe position type.
Definition: basic_types.hpp:168