openCARP
Doxygen code documentation for the open cardiac electrophysiology simulator openCARP
test_sf_cuthill_mckee.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (c) NumeriCor GmbH
2 // SPDX-License-Identifier: Apache-2.0
3 
4 #include "SF_numbering.h"
5 #include "basics.h"
6 
7 #include <iostream>
8 #include <string>
9 #include <vector>
10 
11 namespace {
12 
13 using SF::vector;
15 
16 int failures = 0;
17 
18 void check(bool ok, const std::string& what)
19 {
20  if (!ok) {
21  std::cerr << "FAILED: " << what << '\n';
22  failures++;
23  }
24 }
25 
27 void make_graph(const std::vector<std::vector<SF_int>>& adj,
28  vector<SF_int>& cnt, vector<SF_int>& dsp, vector<SF_int>& con)
29 {
30  cnt.resize(adj.size());
31  for (size_t i = 0; i < adj.size(); i++) {
32  cnt[i] = SF_int(adj[i].size());
33  for (const SF_int c : adj[i]) con.push_back(c);
34  }
35  SF::dsp_from_cnt(cnt, dsp);
36 }
37 
40 bool is_permutation(const perm_map& old2new, size_t n)
41 {
42  if (old2new.size() != n) return false;
43 
44  std::vector<bool> seen(n, false);
45  for (size_t i = 0; i < n; i++) {
46  const SF_int key = SF_int(i);
47  if (!old2new.count(key)) return false;
48  const SF_int val = old2new.at(key);
49  if (val < 0 || size_t(val) >= n || seen[val]) return false;
50  seen[val] = true;
51  }
52  return true;
53 }
54 
56 std::vector<std::vector<SF_int>> path_graph(size_t n)
57 {
58  std::vector<std::vector<SF_int>> adj(n);
59  for (size_t i = 0; i < n; i++) {
60  if (i > 0) adj[i].push_back(SF_int(i - 1));
61  adj[i].push_back(SF_int(i));
62  if (i + 1 < n) adj[i].push_back(SF_int(i + 1));
63  }
64  return adj;
65 }
66 
67 void test_path_reverse()
68 {
69  const size_t n = 5;
70  vector<SF_int> cnt, dsp, con;
71  perm_map old2new;
72  make_graph(path_graph(n), cnt, dsp, con);
73 
74  SF::reindex_cuthill_mckee(cnt, dsp, con, true, old2new);
75 
76  check(is_permutation(old2new, n), "path graph, reverse: result is a permutation");
77  // seeded at node 0, a chain is traversed in order, so reversing maps i to n-1-i
78  for (size_t i = 0; i < n; i++)
79  check(old2new.at(SF_int(i)) == SF_int(n - 1 - i), "path graph, reverse: expected index");
80 }
81 
82 void test_path_forward()
83 {
84  const size_t n = 5;
85  vector<SF_int> cnt, dsp, con;
86  perm_map old2new;
87  make_graph(path_graph(n), cnt, dsp, con);
88 
89  SF::reindex_cuthill_mckee(cnt, dsp, con, false, old2new);
90 
91  check(is_permutation(old2new, n), "path graph, forward: result is a permutation");
92  for (size_t i = 0; i < n; i++)
93  check(old2new.at(SF_int(i)) == SF_int(i), "path graph, forward: expected index");
94 }
95 
97 void test_empty_graph()
98 {
99  vector<SF_int> cnt, dsp, con;
100  perm_map old2new;
101 
102  SF::reindex_cuthill_mckee(cnt, dsp, con, true, old2new);
103 
104  check(old2new.empty(), "empty graph: no indices produced");
105 }
106 
109 void test_disconnected_components()
110 {
111  const size_t n = 4;
112  std::vector<std::vector<SF_int>> adj(n);
113  adj[0].push_back(1); adj[1].push_back(0);
114  adj[2].push_back(3); adj[3].push_back(2);
115 
116  vector<SF_int> cnt, dsp, con;
117  perm_map old2new;
118  make_graph(adj, cnt, dsp, con);
119 
120  SF::reindex_cuthill_mckee(cnt, dsp, con, true, old2new);
121 
122  check(is_permutation(old2new, n), "disconnected components: result is a permutation");
123 }
124 
128 void test_isolated_node()
129 {
130  const size_t n = 4;
131  std::vector<std::vector<SF_int>> adj(n);
132  adj[0].push_back(0); adj[0].push_back(1);
133  adj[1].push_back(0); adj[1].push_back(1);
134  // node 2 is isolated
135  adj[3].push_back(3);
136 
137  vector<SF_int> cnt, dsp, con;
138  perm_map old2new;
139  make_graph(adj, cnt, dsp, con);
140 
141  SF::reindex_cuthill_mckee(cnt, dsp, con, true, old2new);
142 
143  check(is_permutation(old2new, n), "isolated node: result is a permutation");
144 }
145 
146 } // namespace
147 
148 int main()
149 {
150  test_path_reverse();
151  test_path_forward();
152  test_empty_graph();
153  test_disconnected_components();
154  test_isolated_node();
155 
156  return failures ? 1 : 0;
157 }
opencarp::global_index_t SF_int
Global algebraic index type.
Definition: SF_globals.h:17
Classes related to mesh node renumbering.
Basic utility structs and functions, mostly IO related.
A vector storing arbitrary data.
Definition: SF_vector.h:28
void dsp_from_cnt(const vector< T > &cnt, vector< T > &dsp)
Compute displacements from counts.
Definition: SF_vector.h:295
void reindex_cuthill_mckee(const vector< T > &n2n_cnt, const vector< T > &n2n_dsp, const vector< T > &n2n_con, const bool reverse, hashmap::unordered_map< T, T > &old2new)
Definition: SF_numbering.h:148
int main()