Resurrect Flat Map + Binary Search commit from PR 2412

This commit is contained in:
Daniel J. Hofmann 2016-05-20 13:20:12 -04:00 committed by Patrick Niklaus
parent d1bc32fb31
commit ce5ae411c1
No known key found for this signature in database
GPG Key ID: E426891B5F978B1B

View File

@ -29,7 +29,9 @@
#include <tbb/parallel_for_each.h> #include <tbb/parallel_for_each.h>
#include <tbb/parallel_invoke.h> #include <tbb/parallel_invoke.h>
#include <tbb/parallel_sort.h> #include <tbb/parallel_sort.h>
#include <tbb/spin_mutex.h>
#include <algorithm>
#include <bitset> #include <bitset>
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
@ -148,12 +150,45 @@ int Contractor::Run()
namespace namespace
{ {
// Convenience aliases. TODO: make actual types at some point in time. struct Segment final
{
OSMNodeID from, to;
};
using Segment = std::pair<OSMNodeID, OSMNodeID>; struct SpeedSource final
using SegmentHasher = std::hash<Segment>; {
using SpeedSource = std::pair<unsigned, std::uint8_t>; unsigned speed;
using SegmentSpeedSourceMap = tbb::concurrent_unordered_map<Segment, SpeedSource, SegmentHasher>; std::uint8_t source;
};
struct SegmentSpeedSource final
{
Segment segment;
SpeedSource speed_source;
};
using SegmentSpeedSourceFlatMap = std::vector<SegmentSpeedSource>;
// Binary Search over a flattened key,val Segment storage
SegmentSpeedSourceFlatMap::iterator find(SegmentSpeedSourceFlatMap &map, const Segment &key)
{
const auto last = end(map);
const auto by_segment = [](const SegmentSpeedSource &lhs, const SegmentSpeedSource &rhs) {
return std::tie(lhs.segment.from, lhs.segment.to) >
std::tie(rhs.segment.from, rhs.segment.to);
};
auto it = std::lower_bound(begin(map), last, SegmentSpeedSource{key, {0, 0}}, by_segment);
if (it != last && (std::tie(it->segment.from, it->segment.to) == std::tie(key.from, key.to)))
return it;
return last;
}
// Convenience aliases. TODO: make actual types at some point in time.
// TODO: turn penalties need flat map + binary search optimization, take a look at segment speeds
using Turn = std::tuple<OSMNodeID, OSMNodeID, OSMNodeID>; using Turn = std::tuple<OSMNodeID, OSMNodeID, OSMNodeID>;
using TurnHasher = std::hash<Turn>; using TurnHasher = std::hash<Turn>;
@ -162,11 +197,16 @@ using TurnPenaltySourceMap = tbb::concurrent_unordered_map<Turn, PenaltySource,
// Functions for parsing files and creating lookup tables // Functions for parsing files and creating lookup tables
SegmentSpeedSourceMap SegmentSpeedSourceFlatMap
parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_speed_filenames) parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_speed_filenames)
{ {
// TODO: shares code with turn penalty lookup parse function // TODO: shares code with turn penalty lookup parse function
SegmentSpeedSourceMap map;
using Mutex = tbb::spin_mutex;
// Loaded and parsed in parallel, at the end we combine results in a flattened map-ish view
SegmentSpeedSourceFlatMap flatten;
Mutex flatten_mutex;
const auto parse_segment_speed_file = [&](const std::size_t idx) { const auto parse_segment_speed_file = [&](const std::size_t idx) {
const auto file_id = idx + 1; // starts at one, zero means we assigned the weight const auto file_id = idx + 1; // starts at one, zero means we assigned the weight
@ -176,6 +216,8 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
if (!segment_speed_file) if (!segment_speed_file)
throw util::exception{"Unable to open segment speed file " + filename}; throw util::exception{"Unable to open segment speed file " + filename};
SegmentSpeedSourceFlatMap local;
std::uint64_t from_node_id{}; std::uint64_t from_node_id{};
std::uint64_t to_node_id{}; std::uint64_t to_node_id{};
unsigned speed{}; unsigned speed{};
@ -195,14 +237,43 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
if (!ok || it != last) if (!ok || it != last)
throw util::exception{"Segment speed file " + filename + " malformed"}; throw util::exception{"Segment speed file " + filename + " malformed"};
map[std::make_pair(OSMNodeID(from_node_id), OSMNodeID(to_node_id))] = SegmentSpeedSource val{
std::make_pair(speed, file_id); {static_cast<OSMNodeID>(from_node_id), static_cast<OSMNodeID>(to_node_id)},
{speed, static_cast<std::uint8_t>(file_id)}};
local.push_back(std::move(val));
}
{
Mutex::scoped_lock _{flatten_mutex};
flatten.insert(end(flatten), std::make_move_iterator(begin(local)),
std::make_move_iterator(end(local)));
} }
}; };
tbb::parallel_for(std::size_t{0}, segment_speed_filenames.size(), parse_segment_speed_file); tbb::parallel_for(std::size_t{0}, segment_speed_filenames.size(), parse_segment_speed_file);
return map; // With flattened map-ish view of all the files, sort and unique them on from,to,source
// The greater '>' is used here since we want to give files later on higher precedence
const auto sort_by = [](const SegmentSpeedSource &lhs, const SegmentSpeedSource &rhs) {
return std::tie(lhs.segment.from, lhs.segment.to, lhs.speed_source.source) >
std::tie(rhs.segment.from, rhs.segment.to, rhs.speed_source.source);
};
std::stable_sort(begin(flatten), end(flatten), sort_by);
// Unique only on from,to to take the source precedence into account and remove duplicates
const auto unique_by = [](const SegmentSpeedSource &lhs, const SegmentSpeedSource &rhs) {
return std::tie(lhs.segment.from, lhs.segment.to) ==
std::tie(rhs.segment.from, rhs.segment.to);
};
const auto it = std::unique(begin(flatten), end(flatten), unique_by);
flatten.erase(it, end(flatten));
return flatten;
} }
TurnPenaltySourceMap TurnPenaltySourceMap
@ -305,7 +376,7 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
util::SimpleLogger().Write() << "Reading " << number_of_edges util::SimpleLogger().Write() << "Reading " << number_of_edges
<< " edges from the edge based graph"; << " edges from the edge based graph";
SegmentSpeedSourceMap segment_speed_lookup; SegmentSpeedSourceFlatMap segment_speed_lookup;
TurnPenaltySourceMap turn_penalty_lookup; TurnPenaltySourceMap turn_penalty_lookup;
const auto parse_segment_speeds = [&] { const auto parse_segment_speeds = [&] {
@ -446,18 +517,18 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat}); util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
auto forward_speed_iter = auto forward_speed_iter =
segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id)); find(segment_speed_lookup, Segment{u->node_id, v->node_id});
if (forward_speed_iter != segment_speed_lookup.end()) if (forward_speed_iter != segment_speed_lookup.end())
{ {
int new_segment_weight = std::max( int new_segment_weight =
1, std::max(1, static_cast<int>(std::floor(
static_cast<int>(std::floor( (segment_length * 10.) /
(segment_length * 10.) / (forward_speed_iter->second.first / 3.6) + (forward_speed_iter->speed_source.speed / 3.6) +
.5))); .5)));
m_geometry_list[forward_begin + leaf_object.fwd_segment_position].weight = m_geometry_list[forward_begin + leaf_object.fwd_segment_position].weight =
new_segment_weight; new_segment_weight;
m_geometry_datasource[forward_begin + leaf_object.fwd_segment_position] = m_geometry_datasource[forward_begin + leaf_object.fwd_segment_position] =
forward_speed_iter->second.second; forward_speed_iter->speed_source.source;
} }
} }
if (leaf_object.reverse_packed_geometry_id != SPECIAL_EDGEID) if (leaf_object.reverse_packed_geometry_id != SPECIAL_EDGEID)
@ -488,18 +559,18 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat}); util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
auto reverse_speed_iter = auto reverse_speed_iter =
segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id)); find(segment_speed_lookup, Segment{u->node_id, v->node_id});
if (reverse_speed_iter != segment_speed_lookup.end()) if (reverse_speed_iter != segment_speed_lookup.end())
{ {
int new_segment_weight = std::max( int new_segment_weight =
1, std::max(1, static_cast<int>(std::floor(
static_cast<int>(std::floor( (segment_length * 10.) /
(segment_length * 10.) / (reverse_speed_iter->second.first / 3.6) + (reverse_speed_iter->speed_source.speed / 3.6) +
.5))); .5)));
m_geometry_list[reverse_begin + rev_segment_position].weight = m_geometry_list[reverse_begin + rev_segment_position].weight =
new_segment_weight; new_segment_weight;
m_geometry_datasource[reverse_begin + rev_segment_position] = m_geometry_datasource[reverse_begin + rev_segment_position] =
reverse_speed_iter->second.second; reverse_speed_iter->speed_source.source;
} }
} }
} }
@ -594,16 +665,17 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_weight), edge_segment_input_stream.read(reinterpret_cast<char *>(&segment_weight),
sizeof(segment_weight)); sizeof(segment_weight));
auto speed_iter = segment_speed_lookup.find( auto speed_iter =
std::make_pair(previous_osm_node_id, this_osm_node_id)); find(segment_speed_lookup, Segment{previous_osm_node_id, this_osm_node_id});
if (speed_iter != segment_speed_lookup.end()) if (speed_iter != segment_speed_lookup.end())
{ {
// This sets the segment weight using the same formula as the // This sets the segment weight using the same formula as the
// EdgeBasedGraphFactory for consistency. The *why* of this formula // EdgeBasedGraphFactory for consistency. The *why* of this formula
// is lost in the annals of time. // is lost in the annals of time.
int new_segment_weight = std::max( int new_segment_weight = std::max(
1, static_cast<int>(std::floor( 1,
(segment_length * 10.) / (speed_iter->second.first / 3.6) + .5))); static_cast<int>(std::floor(
(segment_length * 10.) / (speed_iter->speed_source.speed / 3.6) + .5)));
new_weight += new_segment_weight; new_weight += new_segment_weight;
} }
else else