osrm-backend/include/util/static_graph.hpp

340 lines
11 KiB
C++
Raw Normal View History

#ifndef STATIC_GRAPH_HPP
#define STATIC_GRAPH_HPP
#include "util/graph_traits.hpp"
2016-05-27 15:05:04 -04:00
#include "util/integer_range.hpp"
2016-01-02 11:13:44 -05:00
#include "util/percent.hpp"
#include "util/permutation.hpp"
2016-01-02 11:13:44 -05:00
#include "util/typedefs.hpp"
2017-04-04 19:01:00 -04:00
#include "util/vector_view.hpp"
2017-04-04 19:54:30 -04:00
#include "storage/io_fwd.hpp"
#include "storage/shared_memory_ownership.hpp"
2018-03-15 16:10:21 -04:00
#include "storage/tar_fwd.hpp"
2014-05-23 08:32:28 -04:00
#include <boost/assert.hpp>
#include <algorithm>
2014-05-05 11:19:47 -04:00
#include <limits>
#include <type_traits>
#include <utility>
#include <vector>
2016-01-05 10:51:13 -05:00
namespace osrm
{
namespace util
{
2017-04-02 13:15:20 -04:00
template <typename EdgeDataT, storage::Ownership Ownership> class StaticGraph;
namespace serialization
{
template <typename EdgeDataT, storage::Ownership Ownership>
void read(storage::io::FileReader &reader, StaticGraph<EdgeDataT, Ownership> &graph);
template <typename EdgeDataT, storage::Ownership Ownership>
void write(storage::io::FileWriter &writer, const StaticGraph<EdgeDataT, Ownership> &graph);
2018-03-15 16:10:21 -04:00
template <typename EdgeDataT, storage::Ownership Ownership>
void read(storage::tar::FileReader &reader,
const std::string &name,
StaticGraph<EdgeDataT, Ownership> &graph);
template <typename EdgeDataT, storage::Ownership Ownership>
void write(storage::tar::FileWriter &writer,
const std::string &name,
const StaticGraph<EdgeDataT, Ownership> &graph);
2017-04-02 13:15:20 -04:00
}
2016-01-05 10:51:13 -05:00
namespace static_graph_details
{
using NodeIterator = NodeID;
using EdgeIterator = NodeID;
struct NodeArrayEntry
{
// index of the first edge
EdgeIterator first_edge;
};
template <typename EdgeDataT> struct EdgeArrayEntry;
template <typename EdgeDataT> struct EdgeArrayEntry
{
NodeID target;
EdgeDataT data;
};
template <> struct EdgeArrayEntry<void>
{
NodeID target;
};
template <typename EdgeDataT> struct SortableEdgeWithData;
template <> struct SortableEdgeWithData<void>
2014-05-05 11:19:47 -04:00
{
NodeIterator source;
NodeIterator target;
2014-08-05 11:19:09 -04:00
SortableEdgeWithData() = default;
SortableEdgeWithData(NodeIterator source, NodeIterator target) : source(source), target(target)
2014-05-05 11:19:47 -04:00
{
}
bool operator<(const SortableEdgeWithData &right) const
{
return std::tie(source, target) < std::tie(right.source, right.target);
}
bool operator==(const SortableEdgeWithData &right) const
{
return std::tie(source, target) == std::tie(right.source, right.target);
}
};
template <typename EdgeDataT> struct SortableEdgeWithData : SortableEdgeWithData<void>
{
using Base = SortableEdgeWithData<void>;
EdgeDataT data;
SortableEdgeWithData() = default;
template <typename... Ts>
SortableEdgeWithData(NodeIterator source, NodeIterator target, Ts &&... data)
: Base{source, target}, data{std::forward<Ts>(data)...}
{
}
};
2017-03-06 22:09:18 -05:00
template <typename EntryT, typename OtherEdge>
EntryT edgeToEntry(const OtherEdge &from, std::true_type)
{
return EntryT{from.target, from.data};
}
template <typename EntryT, typename OtherEdge>
EntryT edgeToEntry(const OtherEdge &from, std::false_type)
{
return EntryT{from.target};
}
} // namespace static_graph_details
template <typename EdgeDataT, storage::Ownership Ownership = storage::Ownership::Container>
2017-03-29 08:07:03 -04:00
class StaticGraph
{
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
2017-04-02 13:15:20 -04:00
public:
using InputEdge = static_graph_details::SortableEdgeWithData<EdgeDataT>;
using NodeIterator = static_graph_details::NodeIterator;
using EdgeIterator = static_graph_details::EdgeIterator;
using EdgeRange = range<EdgeIterator>;
2017-02-07 04:26:29 -05:00
using NodeArrayEntry = static_graph_details::NodeArrayEntry;
using EdgeArrayEntry = static_graph_details::EdgeArrayEntry<EdgeDataT>;
EdgeRange GetAdjacentEdgeRange(const NodeID node) const
{
2016-01-05 10:51:13 -05:00
return irange(BeginEdges(node), EndEdges(node));
}
StaticGraph() {}
template <typename ContainerT> StaticGraph(const std::uint32_t nodes, const ContainerT &edges)
2014-05-05 11:19:47 -04:00
{
2017-03-06 22:09:18 -05:00
BOOST_ASSERT(std::is_sorted(const_cast<ContainerT &>(edges).begin(),
const_cast<ContainerT &>(edges).end()));
2017-03-06 22:09:18 -05:00
InitializeFromSortedEdgeRange(nodes, edges.begin(), edges.end());
}
2017-04-02 13:15:20 -04:00
StaticGraph(Vector<NodeArrayEntry> node_array_, Vector<EdgeArrayEntry> edge_array_)
: node_array(std::move(node_array_)), edge_array(std::move(edge_array_))
2014-05-05 11:19:47 -04:00
{
BOOST_ASSERT(!node_array.empty());
number_of_nodes = static_cast<decltype(number_of_nodes)>(node_array.size() - 1);
number_of_edges = static_cast<decltype(number_of_edges)>(node_array.back().first_edge);
BOOST_ASSERT(number_of_edges <= edge_array.size());
BOOST_ASSERT(number_of_nodes == node_array.size() - 1);
}
2014-06-24 18:20:58 -04:00
unsigned GetNumberOfNodes() const { return number_of_nodes; }
2014-05-05 11:19:47 -04:00
unsigned GetNumberOfEdges() const { return number_of_edges; }
2014-06-24 18:20:58 -04:00
unsigned GetOutDegree(const NodeIterator n) const { return EndEdges(n) - BeginEdges(n); }
inline NodeIterator GetTarget(const EdgeIterator e) const
2014-05-05 11:19:47 -04:00
{
return NodeIterator(edge_array[e].target);
}
auto &GetEdgeData(const EdgeIterator e) { return edge_array[e].data; }
2011-04-15 12:39:44 -04:00
const auto &GetEdgeData(const EdgeIterator e) const { return edge_array[e].data; }
2014-05-05 11:19:47 -04:00
EdgeIterator BeginEdges(const NodeIterator n) const
{
return EdgeIterator(node_array.at(n).first_edge);
}
2014-05-05 11:19:47 -04:00
EdgeIterator EndEdges(const NodeIterator n) const
{
return EdgeIterator(node_array.at(n + 1).first_edge);
}
2014-05-05 11:19:47 -04:00
// searches for a specific edge
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
{
2016-01-05 10:51:13 -05:00
for (const auto i : irange(BeginEdges(from), EndEdges(from)))
{
if (to == edge_array[i].target)
{
return i;
}
}
return SPECIAL_EDGEID;
}
/**
* Finds the edge with the smallest `.weight` going from `from` to `to`
* @param from the source node ID
* @param to the target node ID
* @param filter a functor that returns a `bool` that determines whether an edge should be
* tested or not.
* Takes `EdgeData` as a parameter.
* @return the ID of the smallest edge if any were found that satisfied *filter*, or
* `SPECIAL_EDGEID` if no
* matching edge is found.
*/
template <typename FilterFunction>
2016-09-30 08:33:43 -04:00
EdgeIterator
FindSmallestEdge(const NodeIterator from, const NodeIterator to, FilterFunction &&filter) const
2014-05-05 11:19:47 -04:00
{
2017-02-07 04:26:29 -05:00
static_assert(traits::HasDataMember<EdgeArrayEntry>::value,
"Filtering on .data not possible without .data member attribute");
2014-05-05 11:19:47 -04:00
EdgeIterator smallest_edge = SPECIAL_EDGEID;
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
for (auto edge : GetAdjacentEdgeRange(from))
2014-05-05 11:19:47 -04:00
{
const NodeID target = GetTarget(edge);
2016-09-30 08:33:43 -04:00
const auto &data = GetEdgeData(edge);
if (target == to && data.weight < smallest_weight &&
2016-09-30 08:33:43 -04:00
std::forward<FilterFunction>(filter)(data))
2014-05-05 11:19:47 -04:00
{
smallest_edge = edge;
smallest_weight = data.weight;
}
}
2014-05-05 11:19:47 -04:00
return smallest_edge;
}
2014-05-05 11:19:47 -04:00
EdgeIterator FindEdgeInEitherDirection(const NodeIterator from, const NodeIterator to) const
{
EdgeIterator tmp = FindEdge(from, to);
return (SPECIAL_NODEID != tmp ? tmp : FindEdge(to, from));
2011-07-21 10:30:36 -04:00
}
2014-05-05 11:19:47 -04:00
EdgeIterator
FindEdgeIndicateIfReverse(const NodeIterator from, const NodeIterator to, bool &result) const
{
EdgeIterator current_iterator = FindEdge(from, to);
if (SPECIAL_NODEID == current_iterator)
{
current_iterator = FindEdge(to, from);
if (SPECIAL_NODEID != current_iterator)
{
2011-07-18 11:50:08 -04:00
result = true;
2013-09-18 11:49:49 -04:00
}
2011-07-18 11:50:08 -04:00
}
2014-05-05 11:19:47 -04:00
return current_iterator;
2011-07-18 11:50:08 -04:00
}
void Renumber(const std::vector<NodeID> &old_to_new_node)
{
std::vector<NodeID> new_to_old_node(number_of_nodes);
for (auto node : util::irange<NodeID>(0, number_of_nodes))
new_to_old_node[old_to_new_node[node]] = node;
Vector<NodeArrayEntry> new_node_array(node_array.size());
// Build up edge permutation
auto new_edge_index = 0;
std::vector<EdgeID> old_to_new_edge(edge_array.size(), SPECIAL_EDGEID);
for (auto node : util::irange<NodeID>(0, number_of_nodes))
{
auto new_first_edge = new_edge_index;
for (auto edge : GetAdjacentEdgeRange(new_to_old_node[node]))
{
edge_array[edge].target = old_to_new_node[edge_array[edge].target];
old_to_new_edge[edge] = new_edge_index++;
}
new_node_array[node].first_edge = new_first_edge;
}
new_node_array.back().first_edge = new_edge_index;
node_array = std::move(new_node_array);
BOOST_ASSERT(std::find(old_to_new_edge.begin(), old_to_new_edge.end(), SPECIAL_EDGEID) ==
old_to_new_edge.end());
util::inplacePermutation(edge_array.begin(), edge_array.end(), old_to_new_edge);
}
2017-04-02 13:15:20 -04:00
friend void serialization::read<EdgeDataT, Ownership>(storage::io::FileReader &reader,
StaticGraph<EdgeDataT, Ownership> &graph);
friend void
serialization::write<EdgeDataT, Ownership>(storage::io::FileWriter &writer,
const StaticGraph<EdgeDataT, Ownership> &graph);
2018-03-15 16:10:21 -04:00
friend void serialization::read<EdgeDataT, Ownership>(storage::tar::FileReader &reader,
const std::string &name,
StaticGraph<EdgeDataT, Ownership> &graph);
friend void
serialization::write<EdgeDataT, Ownership>(storage::tar::FileWriter &writer,
const std::string &name,
const StaticGraph<EdgeDataT, Ownership> &graph);
protected:
2017-03-06 22:09:18 -05:00
template <typename IterT>
void InitializeFromSortedEdgeRange(const std::uint32_t nodes, IterT begin, IterT end)
{
2017-03-06 22:09:18 -05:00
number_of_nodes = nodes;
number_of_edges = static_cast<EdgeIterator>(std::distance(begin, end));
node_array.reserve(number_of_nodes + 1);
node_array.push_back(NodeArrayEntry{0u});
auto iter = begin;
for (auto node : util::irange(0u, nodes))
{
iter =
std::find_if(iter, end, [node](const auto &edge) { return edge.source != node; });
unsigned offset = std::distance(begin, iter);
node_array.push_back(NodeArrayEntry{offset});
}
2017-04-04 19:01:00 -04:00
BOOST_ASSERT_MSG(
iter == end,
("Still " + std::to_string(std::distance(iter, end)) + " edges left.").c_str());
2017-03-06 22:09:18 -05:00
BOOST_ASSERT(node_array.size() == number_of_nodes + 1);
edge_array.resize(number_of_edges);
std::transform(begin, end, edge_array.begin(), [](const auto &from) {
return static_graph_details::edgeToEntry<EdgeArrayEntry>(
from, traits::HasDataMember<EdgeArrayEntry>{});
});
}
// private:
2014-05-05 11:19:47 -04:00
NodeIterator number_of_nodes;
EdgeIterator number_of_edges;
2017-04-02 13:15:20 -04:00
Vector<NodeArrayEntry> node_array;
Vector<EdgeArrayEntry> edge_array;
};
2017-02-07 04:26:29 -05:00
} // namespace util
} // namespace osrm
2016-01-05 10:51:13 -05:00
#endif // STATIC_GRAPH_HPP