38 const tGraphAdjFunctor &GraphAdjFunctor;
43 : GraphAdjFunctor(graphAdjFunctor), nVertices(nVertices) {}
47 [[nodiscard]]
int CheckAdj(
bool checkParallel =
true,
bool checkSymmetry =
true)
const
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++)
61 edges.insert(std::make_pair(k, l));
62 edgesDirected.insert(std::make_pair(i,
index(j)));
66 for (
auto e : edgesDirected)
67 if (edgesDirected.count(e) != 1)
68 throw std::runtime_error(
"Graph not having unique directed edges");
71 if (edges.count(e) != 2)
72 throw std::runtime_error(
"Graph not having symmetric edge pairs");
79 template <
typename iter0,
typename iter1,
typename TFInLayerCompare,
typename TLayer>
81 std::is_same_v<std::remove_reference_t<TFInLayerCompare>,
int>>
static inlayer_sort(iter0 &&begin, iter1 &&end, TFInLayerCompare &&comp, TLayer &&layer)
85 template <
typename iter0,
typename iter1,
typename TFInLayerCompare,
typename TLayer>
87 !std::is_same_v<std::remove_reference_t<TFInLayerCompare>,
int>>
static inlayer_sort(iter0 &&begin, iter1 &&end, TFInLayerCompare &&comp, TLayer &&layer)
89 std::stable_sort(std::forward<iter0>(begin), std::forward<iter1>(end),
91 {
return comp(i, j, std::forward<TLayer>(layer)); });
95 template <
typename TFNode,
typename TFInLayerCompare =
int>
98 if (root >= nVertices || root < 0)
99 throw std::range_error(
"Invalid root vertex");
100 std::vector<index> layer(nVertices, -1);
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++)
108 if (curLayerQueue.empty())
110 for (
auto i : curLayerQueue)
113 auto nextLayerQueueSiz0 = nextLayerQueue.size();
116 if (layer.at(j) == -1)
117 nextLayerQueue.push_back(j), layer.at(j) = iLayer + 1;
119 inlayer_sort(nextLayerQueue.begin() + nextLayerQueueSiz0, nextLayerQueue.end(),
120 std::forward<TFInLayerCompare>(FInLayerCompare), layer);
122 std::swap(curLayerQueue, nextLayerQueue);
123 nextLayerQueue.clear();
130 void CuthillMcKeeOrdering(TGraph &&G, TFFiller &&FFiller, TIndex &&root, std::optional<std::reference_wrapper<std::ostream>> os = {})
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++)
140 index nextRoot = root;
142 for (index iIter = 0; iIter < G.GetNVertices(); iIter++)
144 auto cRootDegree = G.GetAdj(nextRoot).size();
146 G.BreadthFirstSearch(
147 [&](
auto i,
auto iLayer)
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;
155 std::forward<TIndex>(nextRoot));
157 G.BreadthFirstSearch(
158 [&](
auto i,
auto iLayer)
161 if (unvisited.erase(i) != 1)
162 throw std::logic_error(
"unvisited set not correct");
164 std::forward<TIndex>(nextRoot),
165 [&](
index i,
index j,
const std::vector<index> &layer) ->
bool
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;
179 os.value().get() <<
" Part [" << iIter <<
"], " <<
"processed [" << cTop <<
"/" << G.GetNVertices() <<
"]" << std::endl;
180 if (unvisited.empty())
182 nextRoot = *unvisited.begin();
185 os.value().get() <<
"CorrectRCM::CuthillMcKeeOrdering: Finished" << std::endl;