Precompute accumulated segment data

This commit is contained in:
Patrick Niklaus 2017-03-15 01:03:55 +00:00 committed by Patrick Niklaus
parent 864543b023
commit 4684a498c4

View File

@ -345,12 +345,6 @@ updateSegmentData(const UpdaterConfig &config,
} }
} }
tbb::parallel_sort(updated_segments.begin(),
updated_segments.end(),
[](const GeometryID lhs, const GeometryID rhs) {
return std::tie(lhs.id, lhs.forward) < std::tie(rhs.id, rhs.forward);
});
return updated_segments; return updated_segments;
} }
@ -543,17 +537,78 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
util::Log() << "Updating segment data took " << TIMER_MSEC(segment) << "ms."; util::Log() << "Updating segment data took " << TIMER_MSEC(segment) << "ms.";
} }
std::vector<std::uint64_t> updated_turn_penalties;
if (update_turn_penalties) if (update_turn_penalties)
{ {
auto turn_penalty_lookup = csv::readTurnValues(config.turn_penalty_lookup_paths); auto turn_penalty_lookup = csv::readTurnValues(config.turn_penalty_lookup_paths);
updated_turn_penalties = updateTurnPenalties(config, auto updated_turn_penalties = updateTurnPenalties(config,
profile_properties, profile_properties,
turn_penalty_lookup, turn_penalty_lookup,
turn_weight_penalties, turn_weight_penalties,
turn_duration_penalties); turn_duration_penalties);
// we need to re-compute all edges that have updated turn penalties.
// this marks it for re-computation
std::transform(updated_turn_penalties.begin(),
updated_turn_penalties.end(),
std::back_inserter(updated_segments),
[&edge_data](const std::uint64_t edge_index) {
return edge_data[edge_index].via_geometry;
});
} }
tbb::parallel_sort(updated_segments.begin(),
updated_segments.end(),
[](const GeometryID lhs, const GeometryID rhs) {
return std::tie(lhs.id, lhs.forward) < std::tie(rhs.id, rhs.forward);
});
using WeightAndDuration = std::tuple<EdgeWeight, EdgeWeight>;
const auto compute_new_weight_and_duration =
[&](const GeometryID geometry_id) -> WeightAndDuration {
EdgeWeight new_weight = 0;
EdgeWeight new_duration = 0;
if (geometry_id.forward)
{
const auto weights = segment_data.GetForwardWeights(geometry_id.id);
for (const auto weight : weights)
{
if (weight == INVALID_EDGE_WEIGHT)
{
new_weight = INVALID_EDGE_WEIGHT;
break;
}
new_weight += weight;
}
const auto durations = segment_data.GetForwardDurations(geometry_id.id);
new_duration = std::accumulate(durations.begin(), durations.end(), 0);
}
else
{
const auto weights = segment_data.GetReverseWeights(geometry_id.id);
for (const auto weight : weights)
{
if (weight == INVALID_EDGE_WEIGHT)
{
new_weight = INVALID_EDGE_WEIGHT;
break;
}
new_weight += weight;
}
const auto durations = segment_data.GetReverseDurations(geometry_id.id);
new_duration = std::accumulate(durations.begin(), durations.end(), 0);
}
return std::make_tuple(new_weight, new_duration);
};
std::vector<WeightAndDuration> accumulated_segment_data(updated_segments.size());
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, updated_segments.size()),
[&](const tbb::blocked_range<std::size_t> &range) {
for (auto index = range.begin(); index < range.end(); ++index)
{
accumulated_segment_data[index] =
compute_new_weight_and_duration(updated_segments[index]);
}
});
// Mapped file pointers for edge-based graph edges // Mapped file pointers for edge-based graph edges
auto edge_based_edge_ptr = reinterpret_cast<const extractor::EdgeBasedEdge *>( auto edge_based_edge_ptr = reinterpret_cast<const extractor::EdgeBasedEdge *>(
reinterpret_cast<char *>(edge_based_graph_region.get_address()) + reinterpret_cast<char *>(edge_based_graph_region.get_address()) +
@ -564,9 +619,8 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
{ {
// Make a copy of the data from the memory map // Make a copy of the data from the memory map
extractor::EdgeBasedEdge inbuffer = edge_based_edge_ptr[edge_index]; extractor::EdgeBasedEdge inbuffer = edge_based_edge_ptr[edge_index];
bool needs_update = update_turn_penalties;
if (update_edge_weights) if (updated_segments.size() > 0)
{ {
const auto geometry_id = edge_data[edge_index].via_geometry; const auto geometry_id = edge_data[edge_index].via_geometry;
auto updated_iter = std::lower_bound(updated_segments.begin(), auto updated_iter = std::lower_bound(updated_segments.begin(),
@ -576,91 +630,51 @@ Updater::LoadAndUpdateEdgeExpandedGraph(std::vector<extractor::EdgeBasedEdge> &e
return std::tie(lhs.id, lhs.forward) < return std::tie(lhs.id, lhs.forward) <
std::tie(rhs.id, rhs.forward); std::tie(rhs.id, rhs.forward);
}); });
if (updated_iter == updated_segments.end() || updated_iter->id != geometry_id.id || if (updated_iter != updated_segments.end() && updated_iter->id == geometry_id.id &&
updated_iter->forward != geometry_id.forward) updated_iter->forward == geometry_id.forward)
{ {
needs_update = update_turn_penalties; // Find a segment with zero speed and simultaneously compute the new edge weight
} EdgeWeight new_weight;
else EdgeWeight new_duration;
{ std::tie(new_weight, new_duration) =
needs_update = true; accumulated_segment_data[updated_iter - updated_segments.begin()];
}
}
if (needs_update) // Update the node-weight cache. This is the weight of the edge-based-node only,
{ // it doesn't include the turn. We may visit the same node multiple times, but
// Find a segment with zero speed and simultaneously compute the new edge weight // we should always assign the same value here.
EdgeWeight new_weight = 0; if (node_weights.size() > 0)
EdgeWeight new_duration = 0; node_weights[inbuffer.source] = new_weight;
bool skip_edge = false;
const auto geometry_id = edge_data[edge_index].via_geometry; // We found a zero-speed edge, so we'll skip this whole edge-based-edge which
if (geometry_id.forward) // effectively removes it from the routing network.
{ if (new_weight == INVALID_EDGE_WEIGHT)
const auto weights = segment_data.GetForwardWeights(geometry_id.id); continue;
for (const auto weight : weights)
// Get the turn penalty and update to the new value if required
auto turn_weight_penalty = turn_weight_penalties[edge_index];
auto turn_duration_penalty = turn_duration_penalties[edge_index];
const auto num_nodes = segment_data.GetForwardGeometry(geometry_id.id).size();
const auto weight_min_value = static_cast<EdgeWeight>(num_nodes);
if (turn_weight_penalty + new_weight < weight_min_value)
{ {
if (weight == INVALID_EDGE_WEIGHT) if (turn_weight_penalty < 0)
{ {
skip_edge = true; util::Log(logWARNING) << "turn penalty " << turn_weight_penalty
break; << " is too negative: clamping turn weight to "
<< weight_min_value;
turn_weight_penalty = weight_min_value - new_weight;
turn_weight_penalties[edge_index] = turn_weight_penalty;
} }
new_weight += weight; else
}
const auto durations = segment_data.GetForwardDurations(geometry_id.id);
new_duration = std::accumulate(durations.begin(), durations.end(), 0);
}
else
{
const auto weights = segment_data.GetReverseWeights(geometry_id.id);
for (const auto weight : weights)
{
if (weight == INVALID_EDGE_WEIGHT)
{ {
skip_edge = true; new_weight = weight_min_value;
break;
} }
new_weight += weight;
} }
const auto durations = segment_data.GetReverseDurations(geometry_id.id);
new_duration = std::accumulate(durations.begin(), durations.end(), 0); // Update edge weight
inbuffer.data.weight = new_weight + turn_weight_penalty;
inbuffer.data.duration = new_duration + turn_duration_penalty;
} }
// Update the node-weight cache. This is the weight of the edge-based-node only,
// it doesn't include the turn. We may visit the same node multiple times, but
// we should always assign the same value here.
if (node_weights.size() > 0)
node_weights[inbuffer.source] = new_weight;
// We found a zero-speed edge, so we'll skip this whole edge-based-edge which
// effectively removes it from the routing network.
if (skip_edge)
continue;
// Get the turn penalty and update to the new value if required
auto turn_weight_penalty = turn_weight_penalties[edge_index];
auto turn_duration_penalty = turn_duration_penalties[edge_index];
const auto num_nodes = segment_data.GetForwardGeometry(geometry_id.id).size();
const auto weight_min_value = static_cast<EdgeWeight>(num_nodes);
if (turn_weight_penalty + new_weight < weight_min_value)
{
if (turn_weight_penalty < 0)
{
util::Log(logWARNING) << "turn penalty " << turn_weight_penalty
<< " is too negative: clamping turn weight to "
<< weight_min_value;
turn_weight_penalty = weight_min_value - new_weight;
turn_weight_penalties[edge_index] = turn_weight_penalty;
}
else
{
new_weight = weight_min_value;
}
}
// Update edge weight
inbuffer.data.weight = new_weight + turn_weight_penalty;
inbuffer.data.duration = new_duration + turn_duration_penalty;
} }
edge_based_edge_list.emplace_back(std::move(inbuffer)); edge_based_edge_list.emplace_back(std::move(inbuffer));