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