39 const tGraphAdjFunctor &GraphAdjFunctor;
44 : GraphAdjFunctor(graphAdjFunctor), nVertices(nVertices) {}
48 [[nodiscard]]
int CheckAdj(
bool checkParallel =
true,
bool checkSymmetry =
true)
const
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++)
62 edges.insert(std::make_pair(k, l));
63 edgesDirected.insert(std::make_pair(
i,
index(
j)));
67 for (
auto e : edgesDirected)
68 if (edgesDirected.count(e) != 1)
69 throw std::runtime_error(
"Graph not having unique directed edges");
72 if (edges.count(e) != 2)
73 throw std::runtime_error(
"Graph not having symmetric edge pairs");
80 template <
typename iter0,
typename iter1,
typename TFInLayerCompare,
typename TLayer>
82 std::is_same_v<std::remove_reference_t<TFInLayerCompare>,
int>>
static inlayer_sort(iter0 &&begin, iter1 &&end, TFInLayerCompare &&comp, TLayer &&layer)
86 template <
typename iter0,
typename iter1,
typename TFInLayerCompare,
typename TLayer>
88 !std::is_same_v<std::remove_reference_t<TFInLayerCompare>,
int>>
static inlayer_sort(iter0 &&begin, iter1 &&end, TFInLayerCompare &&comp, TLayer &&layer)
90 std::stable_sort(std::forward<iter0>(begin), std::forward<iter1>(end),
92 {
return comp(
i,
j, std::forward<TLayer>(layer)); });
96 template <
typename TFNode,
typename TFInLayerCompare =
int>
99 if (root >= nVertices || root < 0)
100 throw std::range_error(
"Invalid root vertex");
101 std::vector<index> layer(nVertices, -1);
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++)
109 if (curLayerQueue.empty())
111 for (
auto i : curLayerQueue)
114 auto nextLayerQueueSiz0 = nextLayerQueue.size();
117 if (layer.at(
j) == -1)
118 nextLayerQueue.push_back(
j), layer.at(
j) = iLayer + 1;
120 inlayer_sort(nextLayerQueue.begin() + nextLayerQueueSiz0, nextLayerQueue.end(),
121 std::forward<TFInLayerCompare>(FInLayerCompare), layer);
123 std::swap(curLayerQueue, nextLayerQueue);
124 nextLayerQueue.clear();
131 void CuthillMcKeeOrdering(TGraph &&G, TFFiller &&FFiller, TIndex &&root, std::optional<std::reference_wrapper<std::ostream>> os = {})
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++)
141 index nextRoot = root;
143 for (index iIter = 0; iIter < G.GetNVertices(); iIter++)
145 auto cRootDegree = G.GetAdj(nextRoot).size();
147 G.BreadthFirstSearch(
148 [&](
auto i,
auto iLayer)
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;
156 std::forward<TIndex>(nextRoot));
158 G.BreadthFirstSearch(
159 [&](
auto i,
auto iLayer)
162 if (unvisited.erase(
i) != 1)
163 throw std::logic_error(
"unvisited set not correct");
165 std::forward<TIndex>(nextRoot),
166 [&](
index i,
index j,
const std::vector<index> &layer) ->
bool
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;
180 os.value().get() <<
" Part [" << iIter <<
"], " <<
"processed [" << cTop <<
"/" << G.GetNVertices() <<
"]" << std::endl;
181 if (unvisited.empty())
183 nextRoot = *unvisited.begin();
186 os.value().get() <<
"CorrectRCM::CuthillMcKeeOrdering: Finished" << std::endl;