DNDSR 0.1.0.dev1+gcd065ad
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 const tGraphAdjFunctor &GraphAdjFunctor;
39 index nVertices;
40
41 public:
42 UndirectedGraphProxy(const tGraphAdjFunctor &graphAdjFunctor, index nVertices)
43 : GraphAdjFunctor(graphAdjFunctor), nVertices(nVertices) {}
44
45 [[nodiscard]] index GetNVertices() const { return nVertices; }
46
47 [[nodiscard]] int CheckAdj(bool checkParallel = true, bool checkSymmetry = true) const
48 {
49 std::unordered_multiset<std::pair<index, index>, hash_pair> edges;
50 std::unordered_multiset<std::pair<index, index>, hash_pair> edgesDirected;
51 edges.reserve(2 * nVertices);
52 edgesDirected.reserve(2 * nVertices);
53 for (index i = 0; i < nVertices; i++)
54 {
55 auto adj = GetAdj(i);
56 for (auto j : adj)
57 {
58 if (i == j)
59 continue;
60 index k = std::min(index(j), i), l = std::max(index(j), i);
61 edges.insert(std::make_pair(k, l));
62 edgesDirected.insert(std::make_pair(i, index(j)));
63 }
64 }
65 if (checkParallel)
66 for (auto e : edgesDirected)
67 if (edgesDirected.count(e) != 1)
68 throw std::runtime_error("Graph not having unique directed edges");
69 if (checkSymmetry)
70 for (auto e : edges)
71 if (edges.count(e) != 2)
72 throw std::runtime_error("Graph not having symmetric edge pairs");
73 return 0;
74 }
75
76 auto GetAdj(index i) const { return GraphAdjFunctor(i); }
77
78 private:
79 template <typename iter0, typename iter1, typename TFInLayerCompare, typename TLayer>
80 std::enable_if_t<
81 std::is_same_v<std::remove_reference_t<TFInLayerCompare>, int>> static inlayer_sort(iter0 &&begin, iter1 &&end, TFInLayerCompare &&comp, TLayer &&layer)
82 {
83 }
84
85 template <typename iter0, typename iter1, typename TFInLayerCompare, typename TLayer>
86 std::enable_if_t<
87 !std::is_same_v<std::remove_reference_t<TFInLayerCompare>, int>> static inlayer_sort(iter0 &&begin, iter1 &&end, TFInLayerCompare &&comp, TLayer &&layer)
88 {
89 std::stable_sort(std::forward<iter0>(begin), std::forward<iter1>(end),
90 [&](index i, index j)
91 { return comp(i, j, std::forward<TLayer>(layer)); });
92 }
93
94 public:
95 template <typename TFNode, typename TFInLayerCompare = int>
96 std::vector<index> BreadthFirstSearch(TFNode &&FNode, index root = 0, TFInLayerCompare &&FInLayerCompare = int(0)) const
97 {
98 if (root >= nVertices || root < 0)
99 throw std::range_error("Invalid root vertex");
100 std::vector<index> layer(nVertices, -1);
101 layer.at(root) = 0;
102 std::vector<index> curLayerQueue;
103 std::vector<index> nextLayerQueue;
104 curLayerQueue.reserve(32), curLayerQueue.push_back(root);
105 nextLayerQueue.reserve(32);
106 for (index iLayer = 0; iLayer < nVertices; iLayer++)
107 {
108 if (curLayerQueue.empty())
109 break;
110 for (auto i : curLayerQueue)
111 {
112 FNode(i, iLayer);
113 auto nextLayerQueueSiz0 = nextLayerQueue.size();
114 for (auto j : GetAdj(i))
115 {
116 if (layer.at(j) == -1)
117 nextLayerQueue.push_back(j), layer.at(j) = iLayer + 1;
118 }
119 inlayer_sort(nextLayerQueue.begin() + nextLayerQueueSiz0, nextLayerQueue.end(),
120 std::forward<TFInLayerCompare>(FInLayerCompare), layer);
121 }
122 std::swap(curLayerQueue, nextLayerQueue);
123 nextLayerQueue.clear();
124 }
125 return layer;
126 }
127 };
128
129 template <typename TGraph, typename TFFiller, typename TIndex>
130 void CuthillMcKeeOrdering(TGraph &&G, TFFiller &&FFiller, TIndex &&root, std::optional<std::reference_wrapper<std::ostream>> os = {})
131 {
132 if (os.has_value())
133 os.value().get() << "CorrectRCM::CuthillMcKeeOrdering: Start" << std::endl;
134 using index = typename std::remove_reference_t<TGraph>::index;
135 std::set<index> unvisited;
136 for (index i = 0; i < G.GetNVertices(); i++)
137 unvisited.insert(i);
138
139 index cTop{0};
140 index nextRoot = root;
141
142 for (index iIter = 0; iIter < G.GetNVertices(); iIter++)
143 {
144 auto cRootDegree = G.GetAdj(nextRoot).size();
145 auto cRootLayer = 0;
146 G.BreadthFirstSearch(
147 [&](auto i, auto iLayer)
148 {
149 if (iLayer > cRootLayer)
150 cRootDegree = G.GetAdj(i).size(), cRootLayer = iLayer, nextRoot = i;
151 if (iLayer == cRootLayer)
152 if (G.GetAdj(i).size() < cRootDegree)
153 cRootDegree = G.GetAdj(i).size(), nextRoot = i;
154 },
155 std::forward<TIndex>(nextRoot));
156
157 G.BreadthFirstSearch(
158 [&](auto i, auto iLayer)
159 {
160 FFiller(i) = cTop++;
161 if (unvisited.erase(i) != 1)
162 throw std::logic_error("unvisited set not correct");
163 },
164 std::forward<TIndex>(nextRoot),
165 [&](index i, index j, const std::vector<index> &layer) -> bool
166 {
167 index iPredMin = G.GetNVertices();
168 index jPredMin = G.GetNVertices();
169 for (auto in : G.GetAdj(i))
170 if (layer.at(in) >= 0)
171 iPredMin = std::min(iPredMin, index(FFiller(in)));
172 for (auto jn : G.GetAdj(j))
173 if (layer.at(jn) >= 0)
174 jPredMin = std::min(jPredMin, index(FFiller(jn)));
175 return iPredMin == jPredMin ? G.GetAdj(i).size() < G.GetAdj(j).size()
176 : iPredMin < jPredMin;
177 });
178 if (os.has_value())
179 os.value().get() << " Part [" << iIter << "], " << "processed [" << cTop << "/" << G.GetNVertices() << "]" << std::endl;
180 if (unvisited.empty())
181 break;
182 nextRoot = *unvisited.begin(); // we handle disjoint graphs
183 }
184 if (os.has_value())
185 os.value().get() << "CorrectRCM::CuthillMcKeeOrdering: Finished" << std::endl;
186 }
187
188} // namespace CorrectRCM
189
190#endif
std::vector< index > BreadthFirstSearch(TFNode &&FNode, index root=0, TFInLayerCompare &&FInLayerCompare=int(0)) const
int CheckAdj(bool checkParallel=true, bool checkSymmetry=true) const
UndirectedGraphProxy(const tGraphAdjFunctor &graphAdjFunctor, index nVertices)
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:107
size_t operator()(const std::pair< T1, T2 > &p) const
auto adj