DNDSR 0.2.1
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
CorrectRCM.hpp
Go to the documentation of this file.
1#pragma once
2
3#ifndef CORRECTRCM_H
4# define CORRECTRCM_H
5
6# include <iostream>
7# include <map>
8# include <set>
9# include <unordered_set>
10# include <exception>
11# include <cstdint>
12# include <vector>
13# include <utility>
14# include <algorithm>
15# include <type_traits>
16# include <optional>
17
18namespace CorrectRCM
19{
20 struct hash_pair
21 {
22 template <class T1, class T2>
23 size_t operator()(const std::pair<T1, T2> &p) const
24 {
25 size_t hash1 = std::hash<T1>{}(p.first);
26 size_t hash2 = std::hash<T2>{}(p.second);
27 return hash1 ^ (hash2 + 0x9e3779b9 + (hash1 << 6) + (hash1 >> 2));
28 }
29 };
30
31 template <typename tGraphAdjFunctor>
33 {
34 public:
35 using index = int64_t;
36
37 private:
38 // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
39 const tGraphAdjFunctor &GraphAdjFunctor;
40 index nVertices;
41
42 public:
43 UndirectedGraphProxy(const tGraphAdjFunctor &graphAdjFunctor, index nVertices)
44 : GraphAdjFunctor(graphAdjFunctor), nVertices(nVertices) {}
45
46 [[nodiscard]] index GetNVertices() const { return nVertices; }
47
48 [[nodiscard]] int CheckAdj(bool checkParallel = true, bool checkSymmetry = true) const
49 {
50 std::unordered_multiset<std::pair<index, index>, hash_pair> edges;
51 std::unordered_multiset<std::pair<index, index>, hash_pair> edgesDirected;
52 edges.reserve(2 * nVertices);
53 edgesDirected.reserve(2 * nVertices);
54 for (index i = 0; i < nVertices; i++)
55 {
56 auto adj = GetAdj(i);
57 for (auto j : adj)
58 {
59 if (i == j)
60 continue;
61 index k = std::min(index(j), i), l = std::max(index(j), i);
62 edges.insert(std::make_pair(k, l));
63 edgesDirected.insert(std::make_pair(i, index(j)));
64 }
65 }
66 if (checkParallel)
67 for (auto e : edgesDirected)
68 if (edgesDirected.count(e) != 1)
69 throw std::runtime_error("Graph not having unique directed edges");
70 if (checkSymmetry)
71 for (auto e : edges)
72 if (edges.count(e) != 2)
73 throw std::runtime_error("Graph not having symmetric edge pairs");
74 return 0;
75 }
76
77 [[nodiscard]] auto GetAdj(index i) const { return GraphAdjFunctor(i); }
78
79 private:
80 template <typename iter0, typename iter1, typename TFInLayerCompare, typename TLayer>
81 std::enable_if_t<
82 std::is_same_v<std::remove_reference_t<TFInLayerCompare>, int>> static inlayer_sort(iter0 &&begin, iter1 &&end, TFInLayerCompare &&comp, TLayer &&layer)
83 {
84 }
85
86 template <typename iter0, typename iter1, typename TFInLayerCompare, typename TLayer>
87 std::enable_if_t<
88 !std::is_same_v<std::remove_reference_t<TFInLayerCompare>, int>> static inlayer_sort(iter0 &&begin, iter1 &&end, TFInLayerCompare &&comp, TLayer &&layer)
89 {
90 std::stable_sort(std::forward<iter0>(begin), std::forward<iter1>(end),
91 [&](index i, index j)
92 { return comp(i, j, std::forward<TLayer>(layer)); });
93 }
94
95 public:
96 template <typename TFNode, typename TFInLayerCompare = int>
97 std::vector<index> BreadthFirstSearch(TFNode &&FNode, index root = 0, TFInLayerCompare &&FInLayerCompare = 0) const
98 {
99 if (root >= nVertices || root < 0)
100 throw std::range_error("Invalid root vertex");
101 std::vector<index> layer(nVertices, -1);
102 layer.at(root) = 0;
103 std::vector<index> curLayerQueue;
104 std::vector<index> nextLayerQueue;
105 curLayerQueue.reserve(32), curLayerQueue.push_back(root);
106 nextLayerQueue.reserve(32);
107 for (index iLayer = 0; iLayer < nVertices; iLayer++)
108 {
109 if (curLayerQueue.empty())
110 break;
111 for (auto i : curLayerQueue)
112 {
113 FNode(i, iLayer);
114 auto nextLayerQueueSiz0 = nextLayerQueue.size();
115 for (auto j : GetAdj(i))
116 {
117 if (layer.at(j) == -1)
118 nextLayerQueue.push_back(j), layer.at(j) = iLayer + 1;
119 }
120 inlayer_sort(nextLayerQueue.begin() + nextLayerQueueSiz0, nextLayerQueue.end(),
121 std::forward<TFInLayerCompare>(FInLayerCompare), layer);
122 }
123 std::swap(curLayerQueue, nextLayerQueue);
124 nextLayerQueue.clear();
125 }
126 return layer;
127 }
128 };
129
130 template <typename TGraph, typename TFFiller, typename TIndex>
131 void CuthillMcKeeOrdering(TGraph &&G, TFFiller &&FFiller, TIndex &&root, std::optional<std::reference_wrapper<std::ostream>> os = {})
132 {
133 if (os.has_value())
134 os.value().get() << "CorrectRCM::CuthillMcKeeOrdering: Start" << std::endl;
135 using index = typename std::remove_reference_t<TGraph>::index;
136 std::set<index> unvisited;
137 for (index i = 0; i < G.GetNVertices(); i++)
138 unvisited.insert(i);
139
140 index cTop{0};
141 index nextRoot = root;
142
143 for (index iIter = 0; iIter < G.GetNVertices(); iIter++)
144 {
145 auto cRootDegree = G.GetAdj(nextRoot).size();
146 auto cRootLayer = 0;
147 G.BreadthFirstSearch(
148 [&](auto i, auto iLayer)
149 {
150 if (iLayer > cRootLayer)
151 cRootDegree = G.GetAdj(i).size(), cRootLayer = iLayer, nextRoot = i;
152 if (iLayer == cRootLayer)
153 if (G.GetAdj(i).size() < cRootDegree)
154 cRootDegree = G.GetAdj(i).size(), nextRoot = i;
155 },
156 std::forward<TIndex>(nextRoot));
157
158 G.BreadthFirstSearch(
159 [&](auto i, auto iLayer)
160 {
161 FFiller(i) = cTop++;
162 if (unvisited.erase(i) != 1)
163 throw std::logic_error("unvisited set not correct");
164 },
165 std::forward<TIndex>(nextRoot),
166 [&](index i, index j, const std::vector<index> &layer) -> bool
167 {
168 index iPredMin = G.GetNVertices();
169 index jPredMin = G.GetNVertices();
170 for (auto in : G.GetAdj(i))
171 if (layer.at(in) >= 0)
172 iPredMin = std::min(iPredMin, index(FFiller(in)));
173 for (auto jn : G.GetAdj(j))
174 if (layer.at(jn) >= 0)
175 jPredMin = std::min(jPredMin, index(FFiller(jn)));
176 return iPredMin == jPredMin ? G.GetAdj(i).size() < G.GetAdj(j).size()
177 : iPredMin < jPredMin;
178 });
179 if (os.has_value())
180 os.value().get() << " Part [" << iIter << "], " << "processed [" << cTop << "/" << G.GetNVertices() << "]" << std::endl;
181 if (unvisited.empty())
182 break;
183 nextRoot = *unvisited.begin(); // we handle disjoint graphs
184 }
185 if (os.has_value())
186 os.value().get() << "CorrectRCM::CuthillMcKeeOrdering: Finished" << std::endl;
187 }
188
189} // namespace CorrectRCM
190
191#endif
int CheckAdj(bool checkParallel=true, bool checkSymmetry=true) const
UndirectedGraphProxy(const tGraphAdjFunctor &graphAdjFunctor, index nVertices)
std::vector< index > BreadthFirstSearch(TFNode &&FNode, index root=0, TFInLayerCompare &&FInLayerCompare=0) const
void CuthillMcKeeOrdering(TGraph &&G, TFFiller &&FFiller, TIndex &&root, std::optional< std::reference_wrapper< std::ostream > > os={})
int64_t index
Global row / DOF index type (signed 64-bit; handles multi-billion-cell meshes).
Definition Defines.hpp:112
size_t operator()(const std::pair< T1, T2 > &p) const
if(DEFINED ENV{DNDS_TEST_NP_LIST}) set(DNDS_TEST_NP_LIST "$ENV
auto adj
const tPoint const tPoint const tPoint & p