Implement exclude flags on CH using shared core

The core is fully contracted for each exclude flag
and stored in a merged graph data structure.
This commit is contained in:
Patrick Niklaus
2017-08-20 23:24:05 +00:00
committed by Patrick Niklaus
parent 4b75cb8b0e
commit 61c430c098
42 changed files with 1468 additions and 418 deletions
@@ -0,0 +1,87 @@
#ifndef OSRM_CONTRACTOR_CONTRACT_EXCLUDABLE_GRAPH_HPP
#define OSRM_CONTRACTOR_CONTRACT_EXCLUDABLE_GRAPH_HPP
#include "contractor/contracted_edge_container.hpp"
#include "contractor/contractor_graph.hpp"
#include "contractor/graph_contractor.hpp"
#include "contractor/graph_contractor_adaptors.hpp"
#include "contractor/query_graph.hpp"
namespace osrm
{
namespace contractor
{
using GraphFilterAndCore =
std::tuple<QueryGraph, std::vector<std::vector<bool>>, std::vector<std::vector<bool>>>;
inline auto contractExcludableGraph(ContractorGraph contractor_graph_,
std::vector<EdgeWeight> node_weights,
const std::vector<std::vector<bool>> &filters,
const float core_factor = 1.0)
{
auto num_nodes = contractor_graph_.GetNumberOfNodes();
ContractedEdgeContainer edge_container;
ContractorGraph shared_core_graph;
std::vector<bool> is_shared_core;
{
ContractorGraph contractor_graph = std::move(contractor_graph_);
std::vector<bool> always_allowed(num_nodes, true);
for (const auto &filter : filters)
{
for (const auto node : util::irange<NodeID>(0, num_nodes))
{
always_allowed[node] = always_allowed[node] && filter[node];
}
}
// By not contracting all contractable nodes we avoid creating
// a very dense core. This increases the overall graph sizes a little bit
// but increases the final CH quality and contraction speed.
constexpr float BASE_CORE = 0.9;
is_shared_core = contractGraph(contractor_graph,
std::move(always_allowed),
node_weights,
std::min<float>(BASE_CORE, core_factor));
// Add all non-core edges to container
{
auto non_core_edges = toEdges<QueryEdge>(contractor_graph);
auto new_end =
std::remove_if(non_core_edges.begin(), non_core_edges.end(), [&](const auto &edge) {
return is_shared_core[edge.source] && is_shared_core[edge.target];
});
non_core_edges.resize(new_end - non_core_edges.begin());
edge_container.Insert(std::move(non_core_edges));
}
// Extract core graph for further contraction
shared_core_graph = contractor_graph.Filter(
[&is_shared_core](const NodeID node) { return is_shared_core[node]; });
}
std::vector<std::vector<bool>> cores;
for (const auto &filter : filters)
{
auto filtered_core_graph =
shared_core_graph.Filter([&filter](const NodeID node) { return filter[node]; });
auto core = contractGraph(
filtered_core_graph, is_shared_core, is_shared_core, node_weights, core_factor);
if (core_factor == 1.0)
{
core.clear();
}
cores.push_back(std::move(core));
edge_container.Merge(toEdges<QueryEdge>(std::move(filtered_core_graph)));
}
return GraphFilterAndCore{QueryGraph{num_nodes, std::move(edge_container.edges)},
edge_container.MakeEdgeFilters(),
std::move(cores)};
}
}
}
#endif
@@ -0,0 +1,153 @@
#ifndef OSRM_CONTRACTOR_CONTRACTED_EDGE_CONTAINER_HPP
#define OSRM_CONTRACTOR_CONTRACTED_EDGE_CONTAINER_HPP
#include "contractor/query_edge.hpp"
#include "util/deallocating_vector.hpp"
#include <climits>
namespace osrm
{
namespace contractor
{
struct ContractedEdgeContainer
{
private:
using MergedFlags = std::uint8_t;
static constexpr auto ALL_FLAGS = 0xFF;
static bool mergeCompare(const QueryEdge &lhs, const QueryEdge &rhs)
{
return std::tie(lhs.source,
lhs.target,
lhs.data.shortcut,
lhs.data.turn_id,
lhs.data.weight,
lhs.data.duration,
lhs.data.forward,
lhs.data.backward) < std::tie(rhs.source,
rhs.target,
rhs.data.shortcut,
rhs.data.turn_id,
rhs.data.weight,
rhs.data.duration,
rhs.data.forward,
rhs.data.backward);
}
static bool mergable(const QueryEdge &lhs, const QueryEdge &rhs)
{
// only true if both are equal
return !mergeCompare(lhs, rhs) && !mergeCompare(rhs, lhs);
}
public:
void Insert(util::DeallocatingVector<QueryEdge> new_edges)
{
BOOST_ASSERT(edges.size() == 0);
BOOST_ASSERT(flags.empty());
edges = std::move(new_edges);
flags.resize(edges.size(), ALL_FLAGS);
}
void Merge(util::DeallocatingVector<QueryEdge> new_edges)
{
BOOST_ASSERT(index < sizeof(MergedFlags) * CHAR_BIT);
const MergedFlags flag = 1 << index++;
std::vector<MergedFlags> merged_flags;
merged_flags.reserve(flags.size() * 1.1);
util::DeallocatingVector<QueryEdge> merged_edges;
merged_edges.reserve(edges.size() * 1.1);
auto flags_iter = flags.begin();
// destructive iterators, this is single-pass only
// FIXME using dbegin() dend() will result in segfaults.
auto edges_iter = edges.dbegin();
auto edges_end = edges.dend();
auto new_edges_iter = new_edges.dbegin();
auto new_edges_end = new_edges.dend();
while (edges_iter != edges_end && new_edges_iter != new_edges_end)
{
while (edges_iter != edges_end && mergeCompare(*edges_iter, *new_edges_iter))
{
merged_edges.push_back(*edges_iter);
merged_flags.push_back(*flags_iter);
edges_iter++;
flags_iter++;
}
if (edges_iter == edges_end)
{
break;
}
while (new_edges_iter != new_edges_end && mergeCompare(*new_edges_iter, *edges_iter))
{
merged_edges.push_back(*new_edges_iter);
merged_flags.push_back(flag);
new_edges_iter++;
}
if (new_edges_iter == new_edges_end)
{
break;
}
while (edges_iter != edges_end && new_edges_iter != new_edges_end &&
mergable(*edges_iter, *new_edges_iter))
{
merged_edges.push_back(*edges_iter);
merged_flags.push_back(*flags_iter | flag);
edges_iter++;
flags_iter++;
new_edges_iter++;
}
}
while (edges_iter != edges_end)
{
BOOST_ASSERT(new_edges_iter == new_edges_end);
merged_edges.push_back(*edges_iter++);
merged_flags.push_back(*flags_iter++);
}
while (new_edges_iter != new_edges_end)
{
BOOST_ASSERT(edges_iter == edges_end);
merged_edges.push_back(*new_edges_iter++);
merged_flags.push_back(flag);
}
flags = std::move(merged_flags);
edges = std::move(merged_edges);
}
auto MakeEdgeFilters() const
{
std::vector<std::vector<bool>> filters(index);
for (const auto flag_index : util::irange<std::size_t>(0, index))
{
MergedFlags mask = 1 << flag_index;
for (const auto flag : flags)
{
filters[flag_index].push_back(flag & mask);
}
}
return filters;
}
std::size_t index = 0;
std::vector<MergedFlags> flags;
util::DeallocatingVector<QueryEdge> edges;
};
}
}
#endif
+3 -6
View File
@@ -43,12 +43,9 @@ namespace contractor
struct ContractorConfig final : storage::IOConfig
{
ContractorConfig()
: IOConfig(
{
".osrm.ebg",
},
{},
{".osrm.level", ".osrm.core", ".osrm.hsgr", ".osrm.enw"}),
: IOConfig({".osrm.ebg", ".osrm.ebg_nodes", ".osrm.properties"},
{},
{".osrm.level", ".osrm.core", ".osrm.hsgr", ".osrm.enw"}),
requested_num_threads(0)
{
}
@@ -1,50 +0,0 @@
#ifndef OSRM_CONTRACTOR_DIJKSTRA_HPP
#define OSRM_CONTRACTOR_DIJKSTRA_HPP
#include "contractor/contractor_graph.hpp"
#include "contractor/contractor_heap.hpp"
#include "util/typedefs.hpp"
#include <cstddef>
namespace osrm
{
namespace contractor
{
// allow access to the heap itself, add Dijkstra functionality on top
class ContractorDijkstra
{
public:
ContractorDijkstra(std::size_t heap_size);
// search the graph up
void Run(const unsigned number_of_targets,
const int node_limit,
const int weight_limit,
const NodeID forbidden_node,
const ContractorGraph &graph);
// adaption of the heap interface
void Clear();
bool WasInserted(const NodeID node) const;
void Insert(const NodeID node,
const ContractorHeap::WeightType weight,
const ContractorHeap::DataType &data);
// cannot be const due to node-hash access in the binary heap :(
ContractorHeap::WeightType GetKey(const NodeID node);
private:
void RelaxNode(const NodeID node,
const int node_weight,
const NodeID forbidden_node,
const ContractorGraph &graph);
ContractorHeap heap;
};
} // namespace contractor
} // namespace osrm
#endif // OSRM_CONTRACTOR_DIJKSTRA_HPP
+26
View File
@@ -0,0 +1,26 @@
#ifndef OSRM_CONTRACTOR_SEARCH_HPP
#define OSRM_CONTRACTOR_SEARCH_HPP
#include "contractor/contractor_graph.hpp"
#include "contractor/contractor_heap.hpp"
#include "util/typedefs.hpp"
#include <cstddef>
namespace osrm
{
namespace contractor
{
void search(ContractorHeap &heap,
const ContractorGraph &graph,
const unsigned number_of_targets,
const int node_limit,
const EdgeWeight weight_limit,
const NodeID forbidden_node);
} // namespace contractor
} // namespace osrm
#endif // OSRM_CONTRACTOR_DIJKSTRA_HPP
+42 -11
View File
@@ -16,54 +16,85 @@ namespace files
{
// reads .osrm.core
template <typename CoreVectorT>
void readCoreMarker(const boost::filesystem::path &path, CoreVectorT &is_core_node)
void readCoreMarker(const boost::filesystem::path &path, std::vector<CoreVectorT> &cores)
{
static_assert(util::is_view_or_vector<bool, CoreVectorT>::value,
"is_core_node must be a vector");
"cores must be a vector of boolean vectors");
storage::io::FileReader reader(path, storage::io::FileReader::VerifyFingerprint);
storage::serialization::read(reader, is_core_node);
auto num_cores = reader.ReadElementCount64();
cores.resize(num_cores);
for (const auto index : util::irange<std::size_t>(0, num_cores))
{
storage::serialization::read(reader, cores[index]);
}
}
// writes .osrm.core
template <typename CoreVectorT>
void writeCoreMarker(const boost::filesystem::path &path, const CoreVectorT &is_core_node)
void writeCoreMarker(const boost::filesystem::path &path, const std::vector<CoreVectorT> &cores)
{
static_assert(util::is_view_or_vector<bool, CoreVectorT>::value,
"is_core_node must be a vector");
"cores must be a vector of boolean vectors");
storage::io::FileWriter writer(path, storage::io::FileWriter::GenerateFingerprint);
storage::serialization::write(writer, is_core_node);
writer.WriteElementCount64(cores.size());
for (const auto &core : cores)
{
storage::serialization::write(writer, core);
}
}
// reads .osrm.hsgr file
template <typename QueryGraphT>
inline void readGraph(const boost::filesystem::path &path, unsigned &checksum, QueryGraphT &graph)
template <typename QueryGraphT, typename EdgeFilterT>
inline void readGraph(const boost::filesystem::path &path,
unsigned &checksum,
QueryGraphT &graph,
std::vector<EdgeFilterT> &edge_filter)
{
static_assert(std::is_same<QueryGraphView, QueryGraphT>::value ||
std::is_same<QueryGraph, QueryGraphT>::value,
"graph must be of type QueryGraph<>");
static_assert(std::is_same<EdgeFilterT, std::vector<bool>>::value ||
std::is_same<EdgeFilterT, util::vector_view<bool>>::value,
"edge_filter must be a container of vector<bool> or vector_view<bool>");
const auto fingerprint = storage::io::FileReader::VerifyFingerprint;
storage::io::FileReader reader{path, fingerprint};
reader.ReadInto(checksum);
util::serialization::read(reader, graph);
auto count = reader.ReadElementCount64();
edge_filter.resize(count);
for (const auto index : util::irange<std::size_t>(0, count))
{
storage::serialization::read(reader, edge_filter[index]);
}
}
// writes .osrm.hsgr file
template <typename QueryGraphT>
inline void
writeGraph(const boost::filesystem::path &path, unsigned checksum, const QueryGraphT &graph)
template <typename QueryGraphT, typename EdgeFilterT>
inline void writeGraph(const boost::filesystem::path &path,
unsigned checksum,
const QueryGraphT &graph,
const std::vector<EdgeFilterT> &edge_filter)
{
static_assert(std::is_same<QueryGraphView, QueryGraphT>::value ||
std::is_same<QueryGraph, QueryGraphT>::value,
"graph must be of type QueryGraph<>");
static_assert(std::is_same<EdgeFilterT, std::vector<bool>>::value ||
std::is_same<EdgeFilterT, util::vector_view<bool>>::value,
"edge_filter must be a container of vector<bool> or vector_view<bool>");
const auto fingerprint = storage::io::FileWriter::GenerateFingerprint;
storage::io::FileWriter writer{path, fingerprint};
writer.WriteOne(checksum);
util::serialization::write(writer, graph);
writer.WriteElementCount64(edge_filter.size());
for (const auto &filter : edge_filter)
{
storage::serialization::write(writer, filter);
}
}
// reads .levels file
+21 -11
View File
@@ -3,6 +3,8 @@
#include "contractor/contractor_graph.hpp"
#include "util/filtered_graph.hpp"
#include <tuple>
#include <vector>
@@ -11,21 +13,29 @@ namespace osrm
namespace contractor
{
using LevelAndCore = std::tuple<std::vector<float>, std::vector<bool>>;
std::vector<bool> contractGraph(ContractorGraph &graph,
std::vector<bool> node_is_uncontracted,
std::vector<bool> node_is_contractable,
std::vector<EdgeWeight> node_weights,
double core_factor = 1.0);
LevelAndCore contractGraph(ContractorGraph &graph,
std::vector<float> cached_node_levels,
std::vector<EdgeWeight> node_weights,
double core_factor = 1.0);
// Overload for contracting withcout cache
inline LevelAndCore contractGraph(ContractorGraph &graph,
std::vector<EdgeWeight> node_weights,
double core_factor = 1.0)
// Overload for contracting all nodes
inline auto contractGraph(ContractorGraph &graph,
std::vector<EdgeWeight> node_weights,
double core_factor = 1.0)
{
return contractGraph(graph, {}, std::move(node_weights), core_factor);
return contractGraph(graph, {}, {}, std::move(node_weights), core_factor);
}
// Overload no contracted nodes
inline auto contractGraph(ContractorGraph &graph,
std::vector<bool> node_is_contractable,
std::vector<EdgeWeight> node_weights,
double core_factor = 1.0)
{
return contractGraph(
graph, {}, std::move(node_is_contractable), std::move(node_weights), core_factor);
}
} // namespace contractor
} // namespace osrm
@@ -23,7 +23,8 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
for (const auto &input_edge : input_edge_list)
{
BOOST_ASSERT(input_edge.data.weight < INVALID_EDGE_WEIGHT);
if (input_edge.data.weight == INVALID_EDGE_WEIGHT)
continue;
#ifndef NDEBUG
const unsigned int constexpr DAY_IN_DECI_SECONDS = 24 * 60 * 60 * 10;
@@ -124,7 +125,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp
return ContractorGraph{number_of_nodes, edges};
}
template <class Edge> inline util::DeallocatingVector<Edge> toEdges(ContractorGraph graph)
template <class Edge, typename GraphT> inline util::DeallocatingVector<Edge> toEdges(GraphT graph)
{
util::DeallocatingVector<Edge> edges;
+11
View File
@@ -21,6 +21,17 @@ struct QueryEdge
{
}
EdgeData(const NodeID turn_id,
const bool shortcut,
const EdgeWeight weight,
const EdgeWeight duration,
const bool forward,
const bool backward)
: turn_id(turn_id), shortcut(shortcut), weight(weight), duration(duration),
forward(forward), backward(backward)
{
}
template <class OtherT> EdgeData(const OtherT &other)
{
weight = other.weight;
+6
View File
@@ -79,6 +79,9 @@ template <> struct HasManyToManySearch<ch::Algorithm> final : std::true_type
template <> struct HasGetTileTurns<ch::Algorithm> final : std::true_type
{
};
template <> struct HasExcludeFlags<ch::Algorithm> final : std::true_type
{
};
// Algorithms supported by Contraction Hierarchies with core
// the rest is disabled because of performance reasons
@@ -94,6 +97,9 @@ template <> struct HasMapMatching<corech::Algorithm> final : std::true_type
template <> struct HasGetTileTurns<corech::Algorithm> final : std::true_type
{
};
template <> struct HasExcludeFlags<corech::Algorithm> final : std::true_type
{
};
// Algorithms supported by Multi-Level Dijkstra
template <> struct HasAlternativePathSearch<mld::Algorithm> final : std::true_type
@@ -8,6 +8,7 @@
#include "partition/cell_storage.hpp"
#include "partition/multi_level_partition.hpp"
#include "util/filtered_graph.hpp"
#include "util/integer_range.hpp"
namespace osrm
@@ -22,14 +23,13 @@ using CH = routing_algorithms::ch::Algorithm;
using CoreCH = routing_algorithms::corech::Algorithm;
using MLD = routing_algorithms::mld::Algorithm;
using EdgeRange = util::range<EdgeID>;
template <typename AlgorithmT> class AlgorithmDataFacade;
template <> class AlgorithmDataFacade<CH>
{
public:
using EdgeData = contractor::QueryEdge::EdgeData;
using EdgeRange = util::filtered_range<EdgeID, util::vector_view<bool>>;
// search graph access
virtual unsigned GetNumberOfNodes() const = 0;
@@ -42,10 +42,6 @@ template <> class AlgorithmDataFacade<CH>
virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0;
virtual EdgeID BeginEdges(const NodeID n) const = 0;
virtual EdgeID EndEdges(const NodeID n) const = 0;
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
// searches for a specific edge
@@ -73,6 +69,7 @@ template <> class AlgorithmDataFacade<MLD>
{
public:
using EdgeData = extractor::EdgeBasedEdge::EdgeData;
using EdgeRange = util::range<EdgeID>;
// search graph access
virtual unsigned GetNumberOfNodes() const = 0;
@@ -85,10 +82,6 @@ template <> class AlgorithmDataFacade<MLD>
virtual const EdgeData &GetEdgeData(const EdgeID e) const = 0;
virtual EdgeID BeginEdges(const NodeID n) const = 0;
virtual EdgeID EndEdges(const NodeID n) const = 0;
virtual EdgeRange GetAdjacentEdgeRange(const NodeID node) const = 0;
virtual const partition::MultiLevelPartitionView &GetMultiLevelPartition() const = 0;
@@ -31,6 +31,7 @@
#include "util/exception.hpp"
#include "util/exception_utils.hpp"
#include "util/filtered_graph.hpp"
#include "util/guidance/bearing_class.hpp"
#include "util/guidance/entry_class.hpp"
#include "util/guidance/turn_bearing.hpp"
@@ -68,7 +69,7 @@ template <>
class ContiguousInternalMemoryAlgorithmDataFacade<CH> : public datafacade::AlgorithmDataFacade<CH>
{
private:
using QueryGraph = contractor::QueryGraphView;
using QueryGraph = util::FilteredGraphView<contractor::QueryGraphView>;
using GraphNode = QueryGraph::NodeArrayEntry;
using GraphEdge = QueryGraph::EdgeArrayEntry;
@@ -77,7 +78,9 @@ class ContiguousInternalMemoryAlgorithmDataFacade<CH> : public datafacade::Algor
// allocator that keeps the allocation data
std::shared_ptr<ContiguousBlockAllocator> allocator;
void InitializeGraphPointer(storage::DataLayout &data_layout, char *memory_block)
void InitializeGraphPointer(storage::DataLayout &data_layout,
char *memory_block,
const std::size_t exclude_index)
{
auto graph_nodes_ptr = data_layout.GetBlockPtr<GraphNode>(
memory_block, storage::DataLayout::CH_GRAPH_NODE_LIST);
@@ -85,24 +88,34 @@ class ContiguousInternalMemoryAlgorithmDataFacade<CH> : public datafacade::Algor
auto graph_edges_ptr = data_layout.GetBlockPtr<GraphEdge>(
memory_block, storage::DataLayout::CH_GRAPH_EDGE_LIST);
auto filter_block_id = static_cast<storage::DataLayout::BlockID>(
storage::DataLayout::CH_EDGE_FILTER_0 + exclude_index);
auto edge_filter_ptr = data_layout.GetBlockPtr<unsigned>(memory_block, filter_block_id);
util::vector_view<GraphNode> node_list(
graph_nodes_ptr, data_layout.num_entries[storage::DataLayout::CH_GRAPH_NODE_LIST]);
util::vector_view<GraphEdge> edge_list(
graph_edges_ptr, data_layout.num_entries[storage::DataLayout::CH_GRAPH_EDGE_LIST]);
m_query_graph = QueryGraph(node_list, edge_list);
util::vector_view<bool> edge_filter(edge_filter_ptr,
data_layout.num_entries[filter_block_id]);
m_query_graph = QueryGraph({node_list, edge_list}, edge_filter);
}
public:
ContiguousInternalMemoryAlgorithmDataFacade(
std::shared_ptr<ContiguousBlockAllocator> allocator_)
std::shared_ptr<ContiguousBlockAllocator> allocator_, std::size_t exclude_index)
: allocator(std::move(allocator_))
{
InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory());
InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory(), exclude_index);
}
void InitializeInternalPointers(storage::DataLayout &data_layout, char *memory_block)
void InitializeInternalPointers(storage::DataLayout &data_layout,
char *memory_block,
const std::size_t exclude_index)
{
InitializeGraphPointer(data_layout, memory_block);
InitializeGraphPointer(data_layout, memory_block, exclude_index);
}
// search graph access
@@ -122,10 +135,6 @@ class ContiguousInternalMemoryAlgorithmDataFacade<CH> : public datafacade::Algor
return m_query_graph.GetEdgeData(e);
}
EdgeID BeginEdges(const NodeID n) const override final { return m_query_graph.BeginEdges(n); }
EdgeID EndEdges(const NodeID n) const override final { return m_query_graph.EndEdges(n); }
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
{
return m_query_graph.GetAdjacentEdgeRange(node);
@@ -166,32 +175,37 @@ class ContiguousInternalMemoryAlgorithmDataFacade<CoreCH>
// allocator that keeps the allocation data
std::shared_ptr<ContiguousBlockAllocator> allocator;
void InitializeCoreInformationPointer(storage::DataLayout &data_layout, char *memory_block)
void InitializeCoreInformationPointer(storage::DataLayout &data_layout,
char *memory_block,
const std::size_t exclude_index)
{
auto core_marker_ptr =
data_layout.GetBlockPtr<unsigned>(memory_block, storage::DataLayout::CH_CORE_MARKER);
util::vector_view<bool> is_core_node(
core_marker_ptr, data_layout.num_entries[storage::DataLayout::CH_CORE_MARKER]);
auto core_block_id = static_cast<storage::DataLayout::BlockID>(
storage::DataLayout::CH_CORE_MARKER_0 + exclude_index);
auto core_marker_ptr = data_layout.GetBlockPtr<unsigned>(memory_block, core_block_id);
util::vector_view<bool> is_core_node(core_marker_ptr,
data_layout.num_entries[core_block_id]);
m_is_core_node = std::move(is_core_node);
}
public:
ContiguousInternalMemoryAlgorithmDataFacade(
std::shared_ptr<ContiguousBlockAllocator> allocator_)
std::shared_ptr<ContiguousBlockAllocator> allocator_, const std::size_t exclude_index)
: allocator(std::move(allocator_))
{
InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory());
InitializeInternalPointers(allocator->GetLayout(), allocator->GetMemory(), exclude_index);
}
void InitializeInternalPointers(storage::DataLayout &data_layout, char *memory_block)
void InitializeInternalPointers(storage::DataLayout &data_layout,
char *memory_block,
const std::size_t exclude_index)
{
InitializeCoreInformationPointer(data_layout, memory_block);
InitializeCoreInformationPointer(data_layout, memory_block, exclude_index);
}
bool IsCoreNode(const NodeID id) const override final
{
BOOST_ASSERT(id < m_is_core_node.size());
return m_is_core_node[id];
BOOST_ASSERT(m_is_core_node.empty() || id < m_is_core_node.size());
return !m_is_core_node.empty() || m_is_core_node[id];
}
};
@@ -942,7 +956,7 @@ class ContiguousInternalMemoryDataFacade<CH>
ContiguousInternalMemoryDataFacade(std::shared_ptr<ContiguousBlockAllocator> allocator,
const std::size_t exclude_index)
: ContiguousInternalMemoryDataFacadeBase(allocator, exclude_index),
ContiguousInternalMemoryAlgorithmDataFacade<CH>(allocator)
ContiguousInternalMemoryAlgorithmDataFacade<CH>(allocator, exclude_index)
{
}
@@ -957,7 +971,7 @@ class ContiguousInternalMemoryDataFacade<CoreCH> final
ContiguousInternalMemoryDataFacade(std::shared_ptr<ContiguousBlockAllocator> allocator,
const std::size_t exclude_index)
: ContiguousInternalMemoryDataFacade<CH>(allocator, exclude_index),
ContiguousInternalMemoryAlgorithmDataFacade<CoreCH>(allocator)
ContiguousInternalMemoryAlgorithmDataFacade<CoreCH>(allocator, exclude_index)
{
}
@@ -1130,10 +1144,6 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public Algo
return query_graph.GetEdgeData(e);
}
EdgeID BeginEdges(const NodeID n) const override final { return query_graph.BeginEdges(n); }
EdgeID EndEdges(const NodeID n) const override final { return query_graph.EndEdges(n); }
EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
{
return query_graph.GetAdjacentEdgeRange(node);
+4 -3
View File
@@ -176,7 +176,7 @@ bool Engine<routing_algorithms::corech::Algorithm>::CheckCompability(const Engin
auto mem = storage::makeSharedMemory(barrier.data().region);
auto layout = reinterpret_cast<storage::DataLayout *>(mem->Ptr());
return layout->GetBlockSize(storage::DataLayout::CH_CORE_MARKER) >
return layout->GetBlockSize(storage::DataLayout::CH_CORE_MARKER_0) >
sizeof(std::uint64_t) + sizeof(util::FingerPrint);
}
else
@@ -185,9 +185,10 @@ bool Engine<routing_algorithms::corech::Algorithm>::CheckCompability(const Engin
return false;
storage::io::FileReader in(config.storage_config.GetPath(".osrm.core"),
storage::io::FileReader::VerifyFingerprint);
in.ReadElementCount64(); // number of core markers
const auto number_of_core_markers = in.ReadElementCount64();
auto size = in.GetSize();
return size > sizeof(std::uint64_t);
return number_of_core_markers > 0;
}
}
+5 -3
View File
@@ -28,11 +28,13 @@ class BisectionGraphView
// Construction either for a subrange, or for a full range
BisectionGraphView(const BisectionGraph &graph);
BisectionGraphView(const BisectionGraph &graph,
const ConstNodeIterator begin,
const ConstNodeIterator end);
const ConstNodeIterator begin,
const ConstNodeIterator end);
// construction from a different view, no need to keep the graph around
BisectionGraphView(const BisectionGraphView &view, const ConstNodeIterator begin, const ConstNodeIterator end);
BisectionGraphView(const BisectionGraphView &view,
const ConstNodeIterator begin,
const ConstNodeIterator end);
// Number of nodes _in this sub-graph.
std::size_t NumberOfNodes() const;
+3 -2
View File
@@ -83,8 +83,9 @@ class DinicMaxFlow
const SourceSinkNodes &source_nodes) const;
// Builds an actual cut result from a level graph
MinCut
MakeCut(const BisectionGraphView &view, const LevelGraph &levels, const std::size_t flow_value) const;
MinCut MakeCut(const BisectionGraphView &view,
const LevelGraph &levels,
const std::size_t flow_value) const;
};
} // namespace partition
+1 -1
View File
@@ -1,8 +1,8 @@
#ifndef OSRM_PARTITION_INERTIAL_FLOW_HPP_
#define OSRM_PARTITION_INERTIAL_FLOW_HPP_
#include "partition/dinic_max_flow.hpp"
#include "partition/bisection_graph_view.hpp"
#include "partition/dinic_max_flow.hpp"
namespace osrm
{
+33 -3
View File
@@ -26,6 +26,14 @@ const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA",
"CLASSES_LIST",
"CH_GRAPH_NODE_LIST",
"CH_GRAPH_EDGE_LIST",
"CH_EDGE_FILTER_0",
"CH_EDGE_FILTER_1",
"CH_EDGE_FILTER_2",
"CH_EDGE_FILTER_3",
"CH_EDGE_FILTER_4",
"CH_EDGE_FILTER_5",
"CH_EDGE_FILTER_6",
"CH_EDGE_FILTER_7",
"COORDINATE_LIST",
"OSM_NODE_ID_LIST",
"TURN_INSTRUCTION",
@@ -43,7 +51,14 @@ const constexpr char *block_id_to_name[] = {"NAME_CHAR_DATA",
"HSGR_CHECKSUM",
"TIMESTAMP",
"FILE_INDEX_PATH",
"CH_CORE_MARKER",
"CH_CORE_MARKER_0",
"CH_CORE_MARKER_1",
"CH_CORE_MARKER_2",
"CH_CORE_MARKER_3",
"CH_CORE_MARKER_4",
"CH_CORE_MARKER_5",
"CH_CORE_MARKER_6",
"CH_CORE_MARKER_7",
"DATASOURCES_NAMES",
"PROPERTIES",
"BEARING_CLASSID",
@@ -98,6 +113,14 @@ struct DataLayout
CLASSES_LIST,
CH_GRAPH_NODE_LIST,
CH_GRAPH_EDGE_LIST,
CH_EDGE_FILTER_0,
CH_EDGE_FILTER_1,
CH_EDGE_FILTER_2,
CH_EDGE_FILTER_3,
CH_EDGE_FILTER_4,
CH_EDGE_FILTER_5,
CH_EDGE_FILTER_6,
CH_EDGE_FILTER_7,
COORDINATE_LIST,
OSM_NODE_ID_LIST,
TURN_INSTRUCTION,
@@ -115,7 +138,14 @@ struct DataLayout
HSGR_CHECKSUM,
TIMESTAMP,
FILE_INDEX_PATH,
CH_CORE_MARKER,
CH_CORE_MARKER_0,
CH_CORE_MARKER_1,
CH_CORE_MARKER_2,
CH_CORE_MARKER_3,
CH_CORE_MARKER_4,
CH_CORE_MARKER_5,
CH_CORE_MARKER_6,
CH_CORE_MARKER_7,
DATASOURCES_NAMES,
PROPERTIES,
BEARING_CLASSID,
@@ -179,7 +209,7 @@ struct DataLayout
inline uint64_t GetBlockSize(BlockID bid) const
{
// special bit encoding
if (bid == CH_CORE_MARKER)
if (bid >= CH_CORE_MARKER_0 && bid <= CH_CORE_MARKER_7)
{
return (num_entries[bid] / 32 + 1) * entry_size[bid];
}
+63 -15
View File
@@ -33,6 +33,27 @@ template <typename EdgeDataT, bool UseSharedMemory>
void write(storage::io::FileWriter &writer, const DynamicGraph<EdgeDataT> &graph);
}
namespace detail
{
// These types need to live outside of DynamicGraph
// to be not dependable. We need this for transforming graphs
// with different data.
template <typename EdgeIterator> struct DynamicNode
{
// index of the first edge
EdgeIterator first_edge;
// amount of edges
unsigned edges;
};
template <typename NodeIterator, typename EdgeDataT> struct DynamicEdge
{
NodeIterator target;
EdgeDataT data;
};
}
template <typename EdgeDataT> class DynamicGraph
{
public:
@@ -41,6 +62,11 @@ template <typename EdgeDataT> class DynamicGraph
using EdgeIterator = std::uint32_t;
using EdgeRange = range<EdgeIterator>;
using Node = detail::DynamicNode<EdgeIterator>;
using Edge = detail::DynamicEdge<NodeIterator, EdgeDataT>;
template <typename E> friend class DynamicGraph;
class InputEdge
{
public:
@@ -120,6 +146,9 @@ template <typename EdgeDataT> class DynamicGraph
}
}
// Copy&move for the same data
//
DynamicGraph(const DynamicGraph &other)
{
number_of_nodes = other.number_of_nodes;
@@ -130,7 +159,7 @@ template <typename EdgeDataT> class DynamicGraph
edge_list = other.edge_list;
}
DynamicGraph&operator=(const DynamicGraph &other)
DynamicGraph &operator=(const DynamicGraph &other)
{
auto copy_other = other;
*this = std::move(other);
@@ -159,6 +188,38 @@ template <typename EdgeDataT> class DynamicGraph
return *this;
}
// Removes all edges to and from nodes for which filter(node_id) returns false
template <typename Pred> auto Filter(Pred filter) const &
{
DynamicGraph other;
other.number_of_nodes = number_of_nodes;
other.number_of_edges = static_cast<std::uint32_t>(number_of_edges);
other.edge_list.reserve(edge_list.size());
other.node_array.resize(node_array.size());
NodeID node_id = 0;
std::transform(
node_array.begin(), node_array.end(), other.node_array.begin(), [&](const Node &node) {
const EdgeIterator first_edge = other.edge_list.size();
if (filter(node_id++))
{
std::copy_if(edge_list.begin() + node.first_edge,
edge_list.begin() + node.first_edge + node.edges,
std::back_inserter(other.edge_list),
[&](const auto &edge) { return filter(edge.target); });
const unsigned num_edges = other.edge_list.size() - first_edge;
return Node{first_edge, num_edges};
}
else
{
return Node{first_edge, 0};
}
});
return other;
}
unsigned GetNumberOfNodes() const { return number_of_nodes; }
unsigned GetNumberOfEdges() const { return number_of_edges; }
@@ -366,6 +427,7 @@ template <typename EdgeDataT> class DynamicGraph
for (auto edge : GetAdjacentEdgeRange(node))
{
edge_list[edge].target = old_to_new_node[edge_list[edge].target];
BOOST_ASSERT(edge_list[edge].target != SPECIAL_NODEID);
old_to_new_edge[edge] = new_edge_index++;
}
node_array[node].first_edge = new_first_edge;
@@ -400,20 +462,6 @@ template <typename EdgeDataT> class DynamicGraph
edge_list[edge].target = (std::numeric_limits<NodeIterator>::max)();
}
struct Node
{
// index of the first edge
EdgeIterator first_edge;
// amount of edges
unsigned edges;
};
struct Edge
{
NodeIterator target;
EdgeDataT data;
};
NodeIterator number_of_nodes;
std::atomic_uint number_of_edges;
+35
View File
@@ -0,0 +1,35 @@
#ifndef OSRM_UTIL_EXCLUDE_FLAG_HPP
#define OSRM_UTIL_EXCLUDE_FLAG_HPP
#include "extractor/node_data_container.hpp"
#include "extractor/profile_properties.hpp"
namespace osrm
{
namespace util
{
inline std::vector<std::vector<bool>>
excludeFlagsToNodeFilter(const NodeID number_of_nodes,
const extractor::EdgeBasedNodeDataContainer &node_data,
const extractor::ProfileProperties &properties)
{
std::vector<std::vector<bool>> filters;
for (auto mask : properties.excludable_classes)
{
if (mask != extractor::INAVLID_CLASS_DATA)
{
std::vector<bool> allowed_nodes(number_of_nodes);
for (const auto node : util::irange<NodeID>(0, number_of_nodes))
{
allowed_nodes[node] = (node_data.GetClassData(node) & mask) == 0;
}
filters.push_back(std::move(allowed_nodes));
}
}
return filters;
}
}
}
#endif
+165
View File
@@ -0,0 +1,165 @@
#ifndef OSRM_UTIL_FILTERED_GRAPH_HPP
#define OSRM_UTIL_FILTERED_GRAPH_HPP
#include "storage/shared_memory_ownership.hpp"
#include "util/dynamic_graph.hpp"
#include "util/filtered_integer_range.hpp"
#include "util/static_graph.hpp"
#include "util/vector_view.hpp"
namespace osrm
{
namespace util
{
namespace detail
{
template <typename GraphT, storage::Ownership Ownership> class FilteredGraphImpl;
// For static graphs we can save the filters as a static vector since
// we don't modify the structure of the graph. This also makes it easy to
// swap out the filter.
template <typename EdgeDataT, storage::Ownership Ownership>
class FilteredGraphImpl<util::StaticGraph<EdgeDataT, Ownership>, Ownership>
{
template <typename T> using Vector = util::ViewOrVector<T, Ownership>;
public:
using Graph = util::StaticGraph<EdgeDataT, Ownership>;
using EdgeIterator = typename Graph::EdgeIterator;
using NodeIterator = typename Graph::NodeIterator;
using NodeArrayEntry = typename Graph::NodeArrayEntry;
using EdgeArrayEntry = typename Graph::EdgeArrayEntry;
using EdgeRange = util::filtered_range<EdgeIterator, Vector<bool>>;
unsigned GetNumberOfNodes() const { return graph.GetNumberOfNodes(); }
unsigned GetNumberOfEdges() const { return graph.GetNumberOfEdges(); }
unsigned GetOutDegree(const NodeIterator n) const
{
auto range = graph.GetAdjacentEdgeRange(n);
return std::count_if(range.begin(), range.end(), [this](const EdgeIterator edge) {
return edge_filter[edge];
});
}
inline NodeIterator GetTarget(const EdgeIterator e) const
{
BOOST_ASSERT(edge_filter[e]);
return graph.GetTarget(e);
}
auto &GetEdgeData(const EdgeIterator e)
{
BOOST_ASSERT(edge_filter[e]);
return graph.GetEdgeData(e);
}
const auto &GetEdgeData(const EdgeIterator e) const
{
BOOST_ASSERT(edge_filter[e]);
return graph.GetEdgeData(e);
}
auto GetAdjacentEdgeRange(const NodeIterator n) const
{
return EdgeRange{graph.BeginEdges(n), graph.EndEdges(n), edge_filter};
}
// searches for a specific edge
EdgeIterator FindEdge(const NodeIterator from, const NodeIterator to) const
{
for (const auto edge : GetAdjacentEdgeRange(from))
{
if (to == GetTarget(edge))
{
return edge;
}
}
return SPECIAL_EDGEID;
}
template <typename FilterFunction>
EdgeIterator
FindSmallestEdge(const NodeIterator from, const NodeIterator to, FilterFunction &&filter) const
{
static_assert(traits::HasDataMember<typename Graph::EdgeArrayEntry>::value,
"Filtering on .data not possible without .data member attribute");
EdgeIterator smallest_edge = SPECIAL_EDGEID;
EdgeWeight smallest_weight = INVALID_EDGE_WEIGHT;
for (auto edge : GetAdjacentEdgeRange(from))
{
const NodeID target = GetTarget(edge);
const auto &data = GetEdgeData(edge);
if (target == to && data.weight < smallest_weight &&
std::forward<FilterFunction>(filter)(data))
{
smallest_edge = edge;
smallest_weight = data.weight;
}
}
return smallest_edge;
}
EdgeIterator FindEdgeInEitherDirection(const NodeIterator from, const NodeIterator to) const
{
EdgeIterator tmp = FindEdge(from, to);
return (SPECIAL_NODEID != tmp ? tmp : FindEdge(to, from));
}
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)
{
result = true;
}
}
return current_iterator;
}
FilteredGraphImpl() = default;
FilteredGraphImpl(Graph graph, Vector<bool> edge_filter_)
: graph(std::move(graph)), edge_filter(std::move(edge_filter_))
{
BOOST_ASSERT(edge_filter.empty() || edge_filter.size() == graph.GetNumberOfEdges());
}
// Takes a graph and a function that maps EdgeID to true
// if the edge should be included in the graph.
template <typename Pred>
FilteredGraphImpl(Graph graph, Pred filter)
: graph(std::move(graph)), edge_filter(graph.GetNumberOfEdges())
{
auto edge_ids = util::irange<EdgeID>(0, graph.GetNumberOfEdges());
std::transform(edge_ids.begin(), edge_ids.end(), edge_filter.begin(), filter);
}
void Renumber(const std::vector<NodeID> &old_to_new_node)
{
graph.Renumber(old_to_new_node);
// FIXME the edge filter needs to be renumbered with a different permutation
// util::inplacePermutation(edge_filter.begin(), edge_filter.end(), old_to_new_node);
}
private:
Graph graph;
Vector<bool> edge_filter;
};
}
template <typename GraphT>
using FilteredGraphContainer = detail::FilteredGraphImpl<GraphT, storage::Ownership::Container>;
template <typename GraphT>
using FilteredGraphView = detail::FilteredGraphImpl<GraphT, storage::Ownership::View>;
}
}
#endif
+101
View File
@@ -0,0 +1,101 @@
#ifndef FILTERED_INTEGER_RANGE_HPP
#define FILTERED_INTEGER_RANGE_HPP
#include <boost/assert.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <type_traits>
#include <cstdint>
namespace osrm
{
namespace util
{
// This implements a single-pass integer range.
// We need our own implementation here because using boost::adaptor::filtered() has
// the problem that the return-type depends on the lambda-type you pass into the function.
// That makes it unsuitable to use in interface where we would expect all filtered ranges
// to be off the same type.
template <typename Integer, typename Filter>
class filtered_integer_iterator
: public boost::iterator_facade<filtered_integer_iterator<Integer, Filter>,
Integer,
boost::single_pass_traversal_tag,
Integer>
{
typedef boost::iterator_facade<filtered_integer_iterator<Integer, Filter>,
Integer,
boost::single_pass_traversal_tag,
Integer>
base_t;
public:
typedef typename base_t::value_type value_type;
typedef typename base_t::difference_type difference_type;
typedef typename base_t::reference reference;
typedef std::random_access_iterator_tag iterator_category;
filtered_integer_iterator() : value(), filter(nullptr) {}
explicit filtered_integer_iterator(value_type x, value_type end_value, const Filter *filter)
: value(x), end_value(end_value), filter(filter)
{
}
private:
void increment()
{
do
{
++value;
} while (value < end_value && !(*filter)[value]);
}
bool equal(const filtered_integer_iterator &other) const { return value == other.value; }
reference dereference() const { return value; }
friend class ::boost::iterator_core_access;
value_type value;
value_type end_value;
const Filter *filter;
};
template <typename Integer, typename Filter> class filtered_range
{
public:
typedef filtered_integer_iterator<Integer, Filter> const_iterator;
typedef filtered_integer_iterator<Integer, Filter> iterator;
filtered_range(Integer begin, Integer end, const Filter &filter) : last(end, end, &filter)
{
while (begin < end && !filter[begin])
{
begin++;
}
iter = iterator(begin, end, &filter);
}
iterator begin() const noexcept { return iter; }
iterator end() const noexcept { return last; }
private:
iterator iter;
iterator last;
};
// convenience function to construct an integer range with type deduction
template <typename Integer, typename Filter>
filtered_range<Integer, Filter>
filtered_irange(const Integer first,
const Integer last,
const Filter &filter,
typename std::enable_if<std::is_integral<Integer>::value>::type * = 0) noexcept
{
return filtered_range<Integer, Filter>(first, last, filter);
}
}
}
#endif // INTEGER_RANGE_HPP
+1
View File
@@ -152,6 +152,7 @@ class QueryHeap
void Insert(NodeID node, Weight weight, const Data &data)
{
BOOST_ASSERT(node < std::numeric_limits<NodeID>::max());
const auto index = static_cast<Key>(inserted_nodes.size());
const auto handle = heap.push(std::make_pair(weight, index));
inserted_nodes.emplace_back(HeapNode{handle, node, weight, data});