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_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
|
||||||
|
Loading…
Reference in New Issue
Block a user