GraphColoring.hpp
Go to the documentation of this file.
1/*
2 Copyright 2018 Equinor
3
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#ifndef OPM_GRAPHCOLORING_HEADER_INCLUDED
20#define OPM_GRAPHCOLORING_HEADER_INCLUDED
21
22#include <opm/common/TimingMacros.hpp>
23
24#include <opm/grid/utility/SparseTable.hpp>
25
26#include <algorithm>
27#include <cstddef>
28#include <deque>
29#include <limits>
30#include <numeric>
31#include <queue>
32#include <string>
33#include <tuple>
34#include <vector>
35
36namespace Opm {
37namespace Detail {
38template <class Graph>
39std::size_t colorGraphWelshPowell(const Graph& graph,
40 std::deque<typename Graph::VertexDescriptor>& orderedVertices,
41 std::vector<int>& colors,
42 int color,
43 int noVertices)
44{
45 std::vector<int> forbidden(noVertices, false);
46 std::size_t noColored = 0;
47
48 for (auto vertex = orderedVertices.begin(),
49 vertexEnd = orderedVertices.end(); vertex != vertexEnd; ++vertex) {
50 // Skip forbidden vertices
51 while (vertex != vertexEnd && forbidden[*vertex])
52 ++vertex;
53 if (vertex == vertexEnd) {
54 break;
55 }
56
57 // Color Vertex
58 colors[*vertex] = color;
59 ++noColored;
60 // Forbid neighors
61 for (auto edge = graph.beginEdges(*vertex),
62 endEdge = graph.endEdges(*vertex); edge != endEdge; ++edge) {
63 forbidden[edge.target()] = true;
64 }
65 }
66 // forbidden vertices will be colored next for coloring
67 using Vertex = typename Graph::VertexDescriptor;
68 auto newEnd = std::remove_if(orderedVertices.begin(),
69 orderedVertices.end(),
70 [&forbidden](const Vertex& vertex) { return !forbidden[vertex]; });
71 orderedVertices.resize(newEnd - orderedVertices.begin());
72 return noColored;
73}
74
75template <class Graph, class Functor>
76std::size_t breadthFirstSearch(const Graph& graph,
77 typename Graph::VertexDescriptor root,
78 Functor functor)
79{
80 std::vector<int> visited(graph.maxVertex() + 1, false);
81 using Vertex = typename Graph::VertexDescriptor;
82 std::queue<Vertex> nextVertices;
83 std::size_t noVisited = 0;
84 nextVertices.push(root);
85 visited[root] = true; // We do not visit root.
86
87 while (!nextVertices.empty()) {
88 auto current = nextVertices.front();
89 for (auto edge = graph.beginEdges(current),
90 endEdge = graph.endEdges(current); edge != endEdge; ++edge) {
91 if (!visited[edge.target()]) {
92 visited[edge.target()] = true;
93 nextVertices.push(edge.target());
94 functor(edge.target());
95 ++noVisited;
96 }
97 }
98 nextVertices.pop();
99 }
100 return noVisited;
101}
102} // end namespace Detail
103
104
111template <class Graph>
112std::tuple<std::vector<int>, int, std::vector<std::size_t>>
113colorVerticesWelshPowell(const Graph& graph)
114{
115 using Vertex = typename Graph::VertexDescriptor;
116 std::deque<Vertex> orderedVertices;
117 auto noVertices = graph.maxVertex() + 1;
118 std::vector<int> degrees(noVertices, 0);
119 int maxDegree = 0;
120 std::ptrdiff_t firstDegreeChange = 0;
121
122 // populate deque
123 for (auto vertex = graph.begin(),
124 endVertex = graph.end(); vertex != endVertex; ++vertex) {
125 auto currentVertex = *vertex;
126 auto& degree = degrees[currentVertex];
127
128 for (auto edge = graph.beginEdges(currentVertex),
129 endEdge = graph.endEdges(currentVertex); edge != endEdge; ++edge) {
130 ++degree;
131 }
132
133 if (degree >= maxDegree) {
134 orderedVertices.emplace_front(currentVertex);
135 ++firstDegreeChange;
136 if (degree > maxDegree) {
137 firstDegreeChange = 1;
138 maxDegree = degree;
139 }
140 } else {
141 orderedVertices.emplace_back(currentVertex);
142 }
143 }
144
145 // order deque by descending degree
146 std::stable_sort(orderedVertices.begin() + firstDegreeChange,
147 orderedVertices.end(),
148 [&degrees](const Vertex& v1, const Vertex& v2)
149 { return degrees[v1] > degrees[v2]; });
150
151 // Overwrite degree with color
152 auto& colors = degrees;
153 std::fill(colors.begin(), colors.end(), -1);
154
155 int color = 0;
156 std::vector<std::size_t> verticesPerColor;
157 verticesPerColor.reserve(10);
158
159 while (!orderedVertices.empty()) {
160 verticesPerColor.push_back(Detail::colorGraphWelshPowell(graph, orderedVertices,
161 colors, color++, noVertices));
162 }
163 return std::make_tuple(colors, color, verticesPerColor);
164}
165
167template <class Graph>
168std::vector<std::size_t>
169reorderVerticesPreserving(const std::vector<int>& colors,
170 int noColors,
171 const std::vector<std::size_t>& verticesPerColor,
172 const Graph& graph)
173{
174 std::vector<std::size_t> colorIndex(noColors, 0);
175 std::vector<std::size_t> indices(graph.maxVertex() + 1);
176 std::partial_sum(verticesPerColor.begin(),
177 verticesPerColor.begin() + verticesPerColor.size() - 1,
178 colorIndex.begin() + 1);
179
180 for (const auto& vertex : graph) {
181 indices[vertex] = colorIndex[colors[vertex]]++;
182 }
183 return indices;
184}
185
187template <class Graph>
188std::vector<std::size_t>
189reorderVerticesSpheres(const std::vector<int>& colors,
190 int noColors,
191 const std::vector<std::size_t>& verticesPerColor,
192 const Graph& graph,
193 typename Graph::VertexDescriptor root)
194{
195 std::vector<std::size_t> colorIndex(noColors, 0);
196 const auto notVisitedTag = std::numeric_limits<std::size_t>::max();
197 std::vector<std::size_t> indices(graph.maxVertex() + 1, notVisitedTag);
198 using Vertex = typename Graph::VertexDescriptor;
199 std::partial_sum(verticesPerColor.begin(),
200 verticesPerColor.begin() + verticesPerColor.size() - 1,
201 colorIndex.begin() + 1);
202 std::size_t noVisited = 0;
203 auto numberer = [&colorIndex, &colors, &indices](Vertex vertex)
204 {
205 indices[vertex] = colorIndex[colors[vertex]]++;
206 };
207
208 while (noVisited < graph.maxVertex() + 1) {
209 numberer(root);
210 ++noVisited; // root node already visited and not visited in BFS
211 noVisited += Detail::breadthFirstSearch(graph, root, numberer);
212 if (noVisited < graph.maxVertex() + 1) {
213 // Graph is disconnected search for not yet visited node
214 for (auto vertex : graph) {
215 if (indices[vertex] == notVisitedTag) {
216 // \todo make sure that this is a peripheral node!
217 root = vertex;
218 break;
219 }
220 }
221 }
222 }
223 return indices;
224}
225
235
246template <class M>
247Opm::SparseTable<std::size_t>
248getMatrixRowColoring(const M& matrix, ColoringType coloringType)
249{
250 OPM_TIMEBLOCK(createMatrix);
251
252 std::vector<std::size_t> color(matrix.N(), 0);
253 std::vector<std::size_t> rowIndices(matrix.N(), 0);
254
255 std::iota(rowIndices.begin(), rowIndices.end(), 0);
256
257 std::vector<std::size_t> colorCnt;
258 // These dynamic programming computations only rely on the following observation:
259 // level[row_i] = 1 + max{level[row_j]} for all j which i depend on
260 // This minimizes the level of each row, and every rows dependencies belong to a lower level set.
261 if (coloringType == ColoringType::SYMMETRIC) {
262 for (auto i = matrix.begin(); i != matrix.end(); ++i) {
263 for (auto a_ij = i->begin(); a_ij.index() != i.index(); ++a_ij) {
264 auto a_ji = matrix[a_ij.index()].find(i.index());
265 if (a_ji != matrix[a_ij.index()].end()) {
266 color[i.index()] = std::max({color[i.index()], color[a_ij.index()] + 1});
267 }
268 }
269 if (color[i.index()] >= colorCnt.size()) {
270 colorCnt.push_back(1);
271 } else {
272 ++colorCnt[color[i.index()]];
273 }
274 }
275 } else if (coloringType == ColoringType::UPPER) {
276 for (auto i = matrix.beforeEnd(); i != matrix.beforeBegin(); --i) {
277 for (auto a_ij = ++(i->find(i.index())); a_ij != i->end(); ++a_ij) {
278 color[i.index()] = std::max({color[i.index()], color[a_ij.index()] + 1});
279 }
280 if (color[i.index()] >= colorCnt.size()) {
281 colorCnt.push_back(1);
282 } else {
283 ++colorCnt[color[i.index()]];
284 }
285 }
286 } else if (coloringType == ColoringType::LOWER) {
287 for (auto i = matrix.begin(); i != matrix.end(); ++i) {
288 for (auto a_ij = i->begin(); a_ij.index() != i.index(); ++a_ij) {
289 color[i.index()] = std::max({color[i.index()], color[a_ij.index()] + 1});
290 }
291 if (color[i.index()] >= colorCnt.size()) {
292 colorCnt.push_back(1);
293 } else {
294 ++colorCnt[color[i.index()]];
295 }
296 }
297 }
298
299 std::stable_sort(rowIndices.begin(),
300 rowIndices.end(),
301 [&color](const std::size_t a, const std::size_t b)
302 { return color[a] < color[b]; });
303
304 return {rowIndices.data(), rowIndices.data() + rowIndices.size(),
305 colorCnt.data(), colorCnt.data() + colorCnt.size()};
306}
307
308} // end namespace Opm
309
310#endif
std::size_t breadthFirstSearch(const Graph &graph, typename Graph::VertexDescriptor root, Functor functor)
Definition: GraphColoring.hpp:76
std::size_t colorGraphWelshPowell(const Graph &graph, std::deque< typename Graph::VertexDescriptor > &orderedVertices, std::vector< int > &colors, int color, int noVertices)
Definition: GraphColoring.hpp:39
Definition: BlackoilPhases.hpp:27
std::vector< std::size_t > reorderVerticesPreserving(const std::vector< int > &colors, int noColors, const std::vector< std::size_t > &verticesPerColor, const Graph &graph)
! Reorder colored graph preserving order of vertices with the same color.
Definition: GraphColoring.hpp:169
ColoringType
Specify coloring type.
Definition: GraphColoring.hpp:234
Opm::SparseTable< std::size_t > getMatrixRowColoring(const M &matrix, ColoringType coloringType)
Given a matrix and dependecy type, returns a SparseTable grouping the rows by which can be executed i...
Definition: GraphColoring.hpp:248
std::vector< std::size_t > reorderVerticesSpheres(const std::vector< int > &colors, int noColors, const std::vector< std::size_t > &verticesPerColor, const Graph &graph, typename Graph::VertexDescriptor root)
! Reorder Vetrices in spheres
Definition: GraphColoring.hpp:189
std::tuple< std::vector< int >, int, std::vector< std::size_t > > colorVerticesWelshPowell(const Graph &graph)
Color the vertices of graph.
Definition: GraphColoring.hpp:113