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_invoke.h>
#include <tbb/parallel_sort.h>
#include <tbb/spin_mutex.h>
#include <algorithm>
#include <bitset>
#include <cstdint>
#include <fstream>
@ -148,12 +150,45 @@ int Contractor::Run()
namespace
{
// Convenience aliases. TODO: make actual types at some point in time.
struct Segment final
{
OSMNodeID from, to;
};
using Segment = std::pair<OSMNodeID, OSMNodeID>;
using SegmentHasher = std::hash<Segment>;
using SpeedSource = std::pair<unsigned, std::uint8_t>;
using SegmentSpeedSourceMap = tbb::concurrent_unordered_map<Segment, SpeedSource, SegmentHasher>;
struct SpeedSource final
{
unsigned speed;
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 TurnHasher = std::hash<Turn>;
@ -162,11 +197,16 @@ using TurnPenaltySourceMap = tbb::concurrent_unordered_map<Turn, PenaltySource,
// Functions for parsing files and creating lookup tables
SegmentSpeedSourceMap
SegmentSpeedSourceFlatMap
parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_speed_filenames)
{
// 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 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)
throw util::exception{"Unable to open segment speed file " + filename};
SegmentSpeedSourceFlatMap local;
std::uint64_t from_node_id{};
std::uint64_t to_node_id{};
unsigned speed{};
@ -195,14 +237,43 @@ parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_spee
if (!ok || it != last)
throw util::exception{"Segment speed file " + filename + " malformed"};
map[std::make_pair(OSMNodeID(from_node_id), OSMNodeID(to_node_id))] =
std::make_pair(speed, file_id);
SegmentSpeedSource val{
{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);
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
@ -305,7 +376,7 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
util::SimpleLogger().Write() << "Reading " << number_of_edges
<< " edges from the edge based graph";
SegmentSpeedSourceMap segment_speed_lookup;
SegmentSpeedSourceFlatMap segment_speed_lookup;
TurnPenaltySourceMap turn_penalty_lookup;
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});
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())
{
int new_segment_weight = std::max(
1,
static_cast<int>(std::floor(
(segment_length * 10.) / (forward_speed_iter->second.first / 3.6) +
.5)));
int new_segment_weight =
std::max(1, static_cast<int>(std::floor(
(segment_length * 10.) /
(forward_speed_iter->speed_source.speed / 3.6) +
.5)));
m_geometry_list[forward_begin + leaf_object.fwd_segment_position].weight =
new_segment_weight;
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)
@ -488,18 +559,18 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});
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())
{
int new_segment_weight = std::max(
1,
static_cast<int>(std::floor(
(segment_length * 10.) / (reverse_speed_iter->second.first / 3.6) +
.5)));
int new_segment_weight =
std::max(1, static_cast<int>(std::floor(
(segment_length * 10.) /
(reverse_speed_iter->speed_source.speed / 3.6) +
.5)));
m_geometry_list[reverse_begin + rev_segment_position].weight =
new_segment_weight;
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),
sizeof(segment_weight));
auto speed_iter = segment_speed_lookup.find(
std::make_pair(previous_osm_node_id, this_osm_node_id));
auto speed_iter =
find(segment_speed_lookup, Segment{previous_osm_node_id, this_osm_node_id});
if (speed_iter != segment_speed_lookup.end())
{
// This sets the segment weight using the same formula as the
// EdgeBasedGraphFactory for consistency. The *why* of this formula
// is lost in the annals of time.
int new_segment_weight = std::max(
1, static_cast<int>(std::floor(
(segment_length * 10.) / (speed_iter->second.first / 3.6) + .5)));
1,
static_cast<int>(std::floor(
(segment_length * 10.) / (speed_iter->speed_source.speed / 3.6) + .5)));
new_weight += new_segment_weight;
}
else