Resurrect Flat Map + Binary Search commit from PR 2412
This commit is contained in:
parent
d1bc32fb31
commit
ce5ae411c1
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user