osrm-backend/include/extractor/tarjan_scc.hpp

183 lines
6.2 KiB
C++
Raw Normal View History

2015-08-19 04:04:36 -04:00
#ifndef TARJAN_SCC_HPP
#define TARJAN_SCC_HPP
2014-11-28 04:07:06 -05:00
#include "extractor/node_based_edge.hpp"
2016-01-02 11:13:44 -05:00
#include "extractor/query_node.hpp"
2016-05-27 15:05:04 -04:00
#include "util/deallocating_vector.hpp"
2016-01-02 11:13:44 -05:00
#include "util/percent.hpp"
2016-05-27 15:05:04 -04:00
#include "util/typedefs.hpp"
2014-11-28 04:07:06 -05:00
2016-01-02 11:13:44 -05:00
#include "util/integer_range.hpp"
#include "util/log.hpp"
2016-01-02 11:13:44 -05:00
#include "util/std_hash.hpp"
#include "util/timing_util.hpp"
2014-11-28 04:07:06 -05:00
2016-01-02 11:13:44 -05:00
#include "osrm/coordinate.hpp"
2014-11-28 04:07:06 -05:00
#include <boost/assert.hpp>
#include <cstdint>
2015-08-31 12:02:07 -04:00
#include <algorithm>
#include <climits>
2016-05-27 15:05:04 -04:00
#include <memory>
2014-11-28 04:07:06 -05:00
#include <stack>
#include <vector>
2016-01-05 10:51:13 -05:00
namespace osrm
{
namespace extractor
{
2015-01-27 11:44:46 -05:00
template <typename GraphT> class TarjanSCC
2014-11-28 04:07:06 -05:00
{
struct TarjanStackFrame
{
explicit TarjanStackFrame(NodeID v, NodeID parent) : v(v), parent(parent) {}
NodeID v;
NodeID parent;
};
2014-11-28 04:07:06 -05:00
struct TarjanNode
{
TarjanNode() : index(SPECIAL_NODEID), low_link(SPECIAL_NODEID), on_stack(false) {}
unsigned index;
unsigned low_link;
bool on_stack;
};
std::vector<unsigned> components_index;
std::vector<NodeID> component_size_vector;
const GraphT &m_graph;
std::size_t size_one_counter;
2014-11-28 04:07:06 -05:00
public:
TarjanSCC(const GraphT &graph)
: components_index(graph.GetNumberOfNodes(), SPECIAL_NODEID), m_graph(graph),
size_one_counter(0)
2014-11-28 04:07:06 -05:00
{
BOOST_ASSERT(m_graph.GetNumberOfNodes() > 0);
2014-11-28 04:07:06 -05:00
}
2016-04-28 18:39:59 -04:00
void Run()
2014-11-28 04:07:06 -05:00
{
TIMER_START(SCC_RUN);
const NodeID max_node_id = m_graph.GetNumberOfNodes();
2014-11-28 04:07:06 -05:00
// The following is a hack to distinguish between stuff that happens
// before the recursive call and stuff that happens after
std::stack<TarjanStackFrame> recursion_stack;
// true = stuff before, false = stuff after call
std::stack<NodeID> tarjan_stack;
std::vector<TarjanNode> tarjan_node_list(max_node_id);
2014-11-28 04:07:06 -05:00
unsigned component_index = 0, size_of_current_component = 0;
unsigned index = 0;
std::vector<bool> processing_node_before_recursion(max_node_id, true);
2016-01-05 10:51:13 -05:00
for (const NodeID node : util::irange(0u, max_node_id))
2014-11-28 04:07:06 -05:00
{
if (SPECIAL_NODEID == components_index[node])
{
recursion_stack.emplace(TarjanStackFrame(node, node));
}
while (!recursion_stack.empty())
{
TarjanStackFrame currentFrame = recursion_stack.top();
2014-12-23 05:47:19 -05:00
const NodeID u = currentFrame.parent;
2014-11-28 04:07:06 -05:00
const NodeID v = currentFrame.v;
recursion_stack.pop();
2014-12-23 05:47:19 -05:00
2014-11-28 04:07:06 -05:00
const bool before_recursion = processing_node_before_recursion[v];
if (before_recursion && tarjan_node_list[v].index != UINT_MAX)
{
continue;
}
if (before_recursion)
{
// Mark frame to handle tail of recursion
recursion_stack.emplace(currentFrame);
processing_node_before_recursion[v] = false;
// Mark essential information for SCC
tarjan_node_list[v].index = index;
tarjan_node_list[v].low_link = index;
tarjan_stack.push(v);
tarjan_node_list[v].on_stack = true;
++index;
for (const auto current_edge : m_graph.GetAdjacentEdgeRange(v))
2014-11-28 04:07:06 -05:00
{
const auto vprime = m_graph.GetTarget(current_edge);
2014-12-23 05:47:19 -05:00
2014-11-28 04:07:06 -05:00
if (SPECIAL_NODEID == tarjan_node_list[vprime].index)
{
recursion_stack.emplace(TarjanStackFrame(vprime, v));
}
else
{
if (tarjan_node_list[vprime].on_stack &&
tarjan_node_list[vprime].index < tarjan_node_list[v].low_link)
{
tarjan_node_list[v].low_link = tarjan_node_list[vprime].index;
}
}
}
}
else
{
processing_node_before_recursion[v] = true;
tarjan_node_list[u].low_link =
std::min(tarjan_node_list[u].low_link, tarjan_node_list[v].low_link);
2014-11-28 04:07:06 -05:00
// after recursion, lets do cycle checking
// Check if we found a cycle. This is the bottom part of the recursion
if (tarjan_node_list[v].low_link == tarjan_node_list[v].index)
{
NodeID vprime;
do
{
vprime = tarjan_stack.top();
tarjan_stack.pop();
tarjan_node_list[vprime].on_stack = false;
components_index[vprime] = component_index;
++size_of_current_component;
} while (v != vprime);
component_size_vector.emplace_back(size_of_current_component);
if (size_of_current_component > 1000)
{
util::Log() << "large component [" << component_index
<< "]=" << size_of_current_component;
2014-11-28 04:07:06 -05:00
}
++component_index;
size_of_current_component = 0;
}
}
}
}
TIMER_STOP(SCC_RUN);
util::Log() << "SCC run took: " << TIMER_MSEC(SCC_RUN) / 1000. << "s";
2014-11-28 04:07:06 -05:00
2016-05-27 15:05:04 -04:00
size_one_counter = std::count_if(component_size_vector.begin(),
component_size_vector.end(),
[](unsigned value) { return 1 == value; });
}
2014-11-28 04:07:06 -05:00
2016-04-28 18:39:59 -04:00
std::size_t GetNumberOfComponents() const { return component_size_vector.size(); }
2016-04-28 18:39:59 -04:00
std::size_t GetSizeOneCount() const { return size_one_counter; }
2016-04-28 18:39:59 -04:00
unsigned GetComponentSize(const unsigned component_id) const
{
return component_size_vector[component_id];
2014-11-28 04:07:06 -05:00
}
2016-04-28 18:39:59 -04:00
unsigned GetComponentID(const NodeID node) const { return components_index[node]; }
2014-11-28 04:07:06 -05:00
};
2016-01-05 10:51:13 -05:00
}
}
2015-08-19 04:04:36 -04:00
#endif /* TARJAN_SCC_HPP */