20#ifndef OPM_TARJAN_HEADER_INCLUDED
21#define OPM_TARJAN_HEADER_INCLUDED
79 return static_cast<int>(
offsets.size()) - 1;
88 const auto first =
static_cast<std::size_t
>(
offsets[k]);
89 const auto last =
static_cast<std::size_t
>(
offsets[k + 1]);
90 return std::span<const int> {
vertices}.subspan(first, last - first);
99 | std::views::transform([
this](
int k) {
return (*
this)[k]; });
114template <
class Graph>
115StronglyConnectedComponents
118 using Row =
decltype(graph[std::size_t {}]);
119 using Iterator = std::ranges::iterator_t<Row>;
120 static_assert(std::ranges::forward_range<Row>,
"A graph row must be a forward range");
121 static_assert(std::is_integral_v<std::ranges::range_value_t<Row>>,
122 "A graph row must hold integer vertex indices");
131 constexpr int unvisited = -1;
132 const int numVertices =
static_cast<int>(std::ranges::size(graph));
135 result.
vertices.reserve(numVertices);
141 std::vector<int> order(numVertices, unvisited);
142 std::vector<int> low(numVertices, 0);
143 std::vector<int> pending;
144 std::vector<Frame> search;
147 const auto discover = [&](
int vertex) {
148 order[vertex] = low[vertex] = discovered++;
149 pending.push_back(vertex);
150 auto&& row = graph[
static_cast<std::size_t
>(vertex)];
151 search.push_back({vertex, std::ranges::begin(row), std::ranges::end(row)});
154 for (
int root = 0; root < numVertices; ++root) {
155 if (order[root] != unvisited) {
160 while (!search.empty()) {
162 const int v = search.back().vertex;
164 if (search.back().next != search.back().end) {
165 const auto target = *search.back().next++;
166 if (std::cmp_less(target, 0) || std::cmp_greater_equal(target, numVertices)) {
167 throw std::out_of_range(
"Opm::tarjan: edge from vertex " +
std::to_string(v)
172 const int w =
static_cast<int>(target);
174 if (order[w] == unvisited) {
178 low[v] = std::min(low[v], order[w]);
186 if (low[v] == order[v]) {
190 member = pending.back();
194 }
while (member != v);
199 if (!search.empty()) {
200 const int parent = search.back().vertex;
201 low[parent] = std::min(low[parent], low[v]);
Definition: blackoilbioeffectsmodules.hh:45
StronglyConnectedComponents tarjan(const Graph &graph)
Compute the strongly connected components of a directed graph with Tarjan's algorithm.
Definition: Tarjan.hpp:116
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
The strongly connected components of a directed graph, as computed by tarjan().
Definition: Tarjan.hpp:62
int numComponents() const
The number of components.
Definition: Tarjan.hpp:77
auto components() const
All components in order, for use in a range-based for loop.
Definition: Tarjan.hpp:96
std::vector< int > componentOf
The component each vertex belongs to.
Definition: Tarjan.hpp:72
std::span< const int > operator[](int k) const
The vertices of a component.
Definition: Tarjan.hpp:86
std::vector< int > vertices
Definition: Tarjan.hpp:65
std::vector< int > offsets
Definition: Tarjan.hpp:69