Merge branch 'TheMarex-boost-test' into develop

This commit is contained in:
Dennis Luxen 2014-07-22 18:55:33 +02:00
commit 0c3713f7e5
17 changed files with 1272 additions and 92 deletions

View File

@ -0,0 +1,118 @@
#include "../DataStructures/OriginalEdgeData.h"
#include "../DataStructures/QueryNode.h"
#include "../DataStructures/SharedMemoryVectorWrapper.h"
#include "../DataStructures/StaticRTree.h"
#include "../Util/BoostFileSystemFix.h"
#include "../DataStructures/EdgeBasedNode.h"
#include <osrm/Coordinate.h>
#include <random>
// Choosen by a fair W20 dice roll (this value is completely arbitrary)
constexpr unsigned RANDOM_SEED = 13;
constexpr int32_t WORLD_MIN_LAT = -90*COORDINATE_PRECISION;
constexpr int32_t WORLD_MAX_LAT = 90*COORDINATE_PRECISION;
constexpr int32_t WORLD_MIN_LON = -180*COORDINATE_PRECISION;
constexpr int32_t WORLD_MAX_LON = 180*COORDINATE_PRECISION;
typedef EdgeBasedNode RTreeLeaf;
typedef std::shared_ptr<std::vector<FixedPointCoordinate>> FixedPointCoordinateListPtr;
typedef StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false> BenchStaticRTree;
FixedPointCoordinateListPtr LoadCoordinates(const boost::filesystem::path& nodes_file)
{
boost::filesystem::ifstream nodes_input_stream(nodes_file, std::ios::binary);
NodeInfo current_node;
unsigned number_of_coordinates = 0;
nodes_input_stream.read((char *)&number_of_coordinates, sizeof(unsigned));
auto coords = std::make_shared<std::vector<FixedPointCoordinate>>(number_of_coordinates);
for (unsigned i = 0; i < number_of_coordinates; ++i)
{
nodes_input_stream.read((char *)&current_node, sizeof(NodeInfo));
coords->at(i) = FixedPointCoordinate(current_node.lat, current_node.lon);
BOOST_ASSERT((std::abs(coords->at(i).lat) >> 30) == 0);
BOOST_ASSERT((std::abs(coords->at(i).lon) >> 30) == 0);
}
nodes_input_stream.close();
return coords;
}
void Benchmark(BenchStaticRTree& rtree, unsigned num_queries)
{
std::mt19937 g(RANDOM_SEED);
std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
std::vector<FixedPointCoordinate> queries;
for (unsigned i = 0; i < num_queries; i++)
{
queries.emplace_back(
FixedPointCoordinate(lat_udist(g), lon_udist(g))
);
}
const unsigned num_results = 5;
std::cout << "#### IncrementalFindPhantomNodeForCoordinate : " << num_results << " phantom nodes" << std::endl;
TIMER_START(query_phantom);
std::vector<PhantomNode> resulting_phantom_node_vector;
for (const auto& q : queries)
{
resulting_phantom_node_vector.clear();
rtree.IncrementalFindPhantomNodeForCoordinate(q, resulting_phantom_node_vector, 3, num_results);
resulting_phantom_node_vector.clear();
rtree.IncrementalFindPhantomNodeForCoordinate(q, resulting_phantom_node_vector, 17, num_results);
}
TIMER_STOP(query_phantom);
std::cout << "Took " << TIMER_MSEC(query_phantom) << " msec for " << num_queries << " queries." << std::endl;
std::cout << TIMER_MSEC(query_phantom)/((double) num_queries) << " msec/query." << std::endl;
std::cout << "#### LocateClosestEndPointForCoordinate" << std::endl;
TIMER_START(query_endpoint);
FixedPointCoordinate result;
for (const auto& q : queries)
{
rtree.LocateClosestEndPointForCoordinate(q, result, 3);
}
TIMER_STOP(query_endpoint);
std::cout << "Took " << TIMER_MSEC(query_endpoint) << " msec for " << num_queries << " queries." << std::endl;
std::cout << TIMER_MSEC(query_endpoint)/((double) num_queries) << " msec/query." << std::endl;
std::cout << "#### FindPhantomNodeForCoordinate" << std::endl;
TIMER_START(query_phantomnode);
for (const auto& q : queries)
{
PhantomNode phantom;
rtree.FindPhantomNodeForCoordinate(q, phantom, 3);
}
TIMER_STOP(query_phantomnode);
std::cout << "Took " << TIMER_MSEC(query_phantomnode) << " msec for " << num_queries << " queries." << std::endl;
std::cout << TIMER_MSEC(query_phantomnode)/((double) num_queries) << " msec/query." << std::endl;
}
int main(int argc, char** argv)
{
if (argc < 4)
{
std::cout << "./rtree-bench file.ramIndex file.fileIndx file.nodes" << std::endl;
return 1;
}
const char* ramPath = argv[1];
const char* filePath = argv[2];
const char* nodesPath = argv[3];
auto coords = LoadCoordinates(nodesPath);
BenchStaticRTree rtree(ramPath, filePath, coords);
Benchmark(rtree, 10000);
return 0;
}

View File

@ -41,8 +41,10 @@ add_custom_command(OUTPUT ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp FingerPrint.c
VERBATIM)
add_custom_target(FingerPrintConfigure DEPENDS ${CMAKE_SOURCE_DIR}/Util/FingerPrint.cpp)
add_custom_target(tests DEPENDS datastructure-tests)
add_custom_target(benchmarks DEPENDS rtree-bench)
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread)
set(BOOST_COMPONENTS date_time filesystem iostreams program_options regex system thread unit_test_framework)
configure_file(
${CMAKE_SOURCE_DIR}/Util/GitDescription.cpp.in
@ -65,6 +67,7 @@ file(GLOB CoordinateGlob DataStructures/Coordinate.cpp)
file(GLOB AlgorithmGlob Algorithms/*.cpp)
file(GLOB HttpGlob Server/Http/*.cpp)
file(GLOB LibOSRMGlob Library/*.cpp)
file(GLOB DataStructureTestsGlob UnitTests/DataStructures/*.cpp DataStructures/HilbertValue.cpp)
set(
OSRMSources
@ -84,6 +87,12 @@ add_dependencies(FINGERPRINT FingerPrintConfigure)
add_executable(osrm-routed routed.cpp ${ServerGlob})
add_executable(osrm-datastore datastore.cpp)
# Unit tests
add_executable(datastructure-tests EXCLUDE_FROM_ALL UnitTests/datastructure_tests.cpp ${DataStructureTestsGlob})
# Benchmarks
add_executable(rtree-bench EXCLUDE_FROM_ALL Benchmarks/StaticRTreeBench.cpp)
# Check the release mode
if(NOT CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_BUILD_TYPE Release)
@ -114,6 +123,10 @@ if(CMAKE_BUILD_TYPE MATCHES Release)
endif (HAS_LTO_FLAG)
endif()
if (NOT WIN32)
add_definitions(-DBOOST_TEST_DYN_LINK)
endif()
# Configuring compilers
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# using Clang
@ -189,12 +202,16 @@ target_link_libraries(osrm-extract ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION
target_link_libraries(osrm-prepare ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB IMPORT)
target_link_libraries(osrm-routed ${Boost_LIBRARIES} ${OPTIONAL_SOCKET_LIBS} OSRM FINGERPRINT GITDESCRIPTION)
target_link_libraries(osrm-datastore ${Boost_LIBRARIES} FINGERPRINT GITDESCRIPTION COORDLIB)
target_link_libraries(datastructure-tests ${Boost_LIBRARIES} COORDLIB)
target_link_libraries(rtree-bench ${Boost_LIBRARIES} COORDLIB)
find_package(Threads REQUIRED)
target_link_libraries(osrm-extract ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(osrm-datastore ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(osrm-prepare ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(OSRM ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(datastructure-tests ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(rtree-bench ${CMAKE_THREAD_LIBS_INIT})
find_package(TBB REQUIRED)
if(WIN32 AND CMAKE_BUILD_TYPE MATCHES Debug)
@ -204,6 +221,8 @@ target_link_libraries(osrm-datastore ${TBB_LIBRARIES})
target_link_libraries(osrm-extract ${TBB_LIBRARIES})
target_link_libraries(osrm-prepare ${TBB_LIBRARIES})
target_link_libraries(osrm-routed ${TBB_LIBRARIES})
target_link_libraries(datastructure-tests ${TBB_LIBRARIES})
target_link_libraries(rtree-bench ${TBB_LIBRARIES})
include_directories(${TBB_INCLUDE_DIR})
find_package(Lua52)

View File

@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <type_traits>
#include <unordered_map>
#include <vector>
#include <cstring>
template <typename NodeID, typename Key> class ArrayStorage
{

View File

@ -159,10 +159,10 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
// initialize values
const float x_value = lat2y(point.lat / COORDINATE_PRECISION);
const float y_value = point.lon / COORDINATE_PRECISION;
const float a = lat2y(source_coordinate.lat / COORDINATE_PRECISION);
const float b = source_coordinate.lon / COORDINATE_PRECISION;
const float c = lat2y(target_coordinate.lat / COORDINATE_PRECISION);
const float d = target_coordinate.lon / COORDINATE_PRECISION;
float a = lat2y(source_coordinate.lat / COORDINATE_PRECISION);
float b = source_coordinate.lon / COORDINATE_PRECISION;
float c = lat2y(target_coordinate.lat / COORDINATE_PRECISION);
float d = target_coordinate.lon / COORDINATE_PRECISION;
float p, q;
if (std::abs(a - c) > std::numeric_limits<float>::epsilon())
{
@ -178,15 +178,35 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
q = y_value;
}
float nY = (d * p - c * q) / (a * d - b * c);
// discretize the result to coordinate precision. it's a hack!
if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
float ratio;
bool inverse_ratio = false;
// straight line segment on equator
if (std::abs(c) < std::numeric_limits<float>::epsilon() && std::abs(a) < std::numeric_limits<float>::epsilon())
{
nY = 0.f;
ratio = (q - b) / (d - b);
}
else
{
if (std::abs(c) < std::numeric_limits<float>::epsilon())
{
// swap start/end
std::swap(a, c);
std::swap(b, d);
inverse_ratio = true;
}
float nY = (d * p - c * q) / (a * d - b * c);
// discretize the result to coordinate precision. it's a hack!
if (std::abs(nY) < (1.f / COORDINATE_PRECISION))
{
nY = 0.f;
}
// compute ratio
ratio = (p - nY * a) / c;
}
// compute ratio
float ratio = (p - nY * a) / c;
if (std::isnan(ratio))
{
ratio = (target_coordinate == point ? 1.f : 0.f);
@ -200,6 +220,12 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
ratio = 1.f;
}
// we need to do this, if we switched start/end coordinates
if (inverse_ratio)
{
ratio = 1.0f - ratio;
}
//compute the nearest location
FixedPointCoordinate nearest_location;
BOOST_ASSERT(!std::isnan(ratio));
@ -216,6 +242,7 @@ FixedPointCoordinate::ComputePerpendicularDistance(const FixedPointCoordinate &s
nearest_location.lat = static_cast<int>(y2lat(p) * COORDINATE_PRECISION);
nearest_location.lon = static_cast<int>(q * COORDINATE_PRECISION);
}
BOOST_ASSERT(nearest_location.isValid());
return FixedPointCoordinate::ApproximateEuclideanDistance(point, nearest_location);
}

View File

@ -117,7 +117,8 @@ public:
{
// the last value is used as sentinel
block_offsets.push_back(lengths_prefix_sum);
block_idx = (block_idx + 1) % BLOCK_SIZE;
block_idx = 1;
last_length = 0;
}
while (0 != block_idx)

View File

@ -162,11 +162,11 @@ template <typename EdgeDataT, bool UseSharedMemory = false> class StaticGraph
#endif
}
unsigned GetNumberOfNodes() const { return number_of_nodes -1; }
unsigned GetNumberOfNodes() const { return number_of_nodes; }
unsigned GetNumberOfEdges() const { return number_of_edges; }
unsigned GetOutDegree(const NodeIterator n) const { return BeginEdges(n) - EndEdges(n) - 1; }
unsigned GetOutDegree(const NodeIterator n) const { return EndEdges(n) - BeginEdges(n); }
inline NodeIterator GetTarget(const EdgeIterator e) const
{

View File

@ -60,16 +60,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <vector>
// tuning parameters
const static uint32_t RTREE_BRANCHING_FACTOR = 64;
const static uint32_t RTREE_LEAF_NODE_SIZE = 1024;
static boost::thread_specific_ptr<boost::filesystem::ifstream> thread_local_rtree_stream;
// Implements a static, i.e. packed, R-tree
template <class EdgeDataT,
class CoordinateListT = std::vector<FixedPointCoordinate>,
bool UseSharedMemory = false>
bool UseSharedMemory = false,
uint32_t BRANCHING_FACTOR=64,
uint32_t LEAF_NODE_SIZE=1024>
class StaticRTree
{
public:
@ -80,7 +76,7 @@ class StaticRTree
int32_t min_lon, max_lon;
int32_t min_lat, max_lat;
inline void InitializeMBRectangle(const std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> &objects,
inline void InitializeMBRectangle(const std::array<EdgeDataT, LEAF_NODE_SIZE> &objects,
const uint32_t element_count,
const std::vector<NodeInfo> &coordinate_list)
{
@ -147,19 +143,64 @@ class StaticRTree
return 0.;
}
enum Direction
{
INVALID = 0,
NORTH = 1,
SOUTH = 2,
EAST = 4,
NORTH_EAST = 5,
SOUTH_EAST = 6,
WEST = 8,
NORTH_WEST = 9,
SOUTH_WEST = 10
};
Direction d = INVALID;
if (location.lat > max_lat)
d = (Direction) (d | NORTH);
else if (location.lat < min_lat)
d = (Direction) (d | SOUTH);
if (location.lon > max_lon)
d = (Direction) (d | EAST);
else if (location.lon < min_lon)
d = (Direction) (d | WEST);
BOOST_ASSERT(d != INVALID);
float min_dist = std::numeric_limits<float>::max();
min_dist = std::min(min_dist,
FixedPointCoordinate::ApproximateEuclideanDistance(
location.lat, location.lon, max_lat, min_lon));
min_dist = std::min(min_dist,
FixedPointCoordinate::ApproximateEuclideanDistance(
location.lat, location.lon, max_lat, max_lon));
min_dist = std::min(min_dist,
FixedPointCoordinate::ApproximateEuclideanDistance(
location.lat, location.lon, min_lat, max_lon));
min_dist = std::min(min_dist,
FixedPointCoordinate::ApproximateEuclideanDistance(
location.lat, location.lon, min_lat, min_lon));
switch (d)
{
case NORTH:
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon));
break;
case SOUTH:
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon));
break;
case WEST:
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon));
break;
case EAST:
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon));
break;
case NORTH_EAST:
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon));
break;
case NORTH_WEST:
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon));
break;
case SOUTH_EAST:
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon));
break;
case SOUTH_WEST:
min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon));
break;
default:
break;
}
BOOST_ASSERT(min_dist != std::numeric_limits<float>::max());
return min_dist;
}
@ -167,10 +208,10 @@ class StaticRTree
{
float min_max_dist = std::numeric_limits<float>::max();
// Get minmax distance to each of the four sides
FixedPointCoordinate upper_left(max_lat, min_lon);
FixedPointCoordinate upper_right(max_lat, max_lon);
FixedPointCoordinate lower_right(min_lat, max_lon);
FixedPointCoordinate lower_left(min_lat, min_lon);
const FixedPointCoordinate upper_left(max_lat, min_lon);
const FixedPointCoordinate upper_right(max_lat, max_lon);
const FixedPointCoordinate lower_right(min_lat, max_lon);
const FixedPointCoordinate lower_left(min_lat, min_lon);
min_max_dist = std::min(
min_max_dist,
@ -198,8 +239,8 @@ class StaticRTree
inline bool Contains(const FixedPointCoordinate &location) const
{
const bool lats_contained = (location.lat > min_lat) && (location.lat < max_lat);
const bool lons_contained = (location.lon > min_lon) && (location.lon < max_lon);
const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat);
const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon);
return lats_contained && lons_contained;
}
@ -220,7 +261,7 @@ class StaticRTree
RectangleT minimum_bounding_rectangle;
uint32_t child_count : 31;
bool child_is_on_disk : 1;
uint32_t children[RTREE_BRANCHING_FACTOR];
uint32_t children[BRANCHING_FACTOR];
};
private:
@ -244,9 +285,9 @@ class StaticRTree
struct LeafNode
{
LeafNode() : object_count(0) {}
LeafNode() : object_count(0), objects() {}
uint32_t object_count;
std::array<EdgeDataT, RTREE_LEAF_NODE_SIZE> objects;
std::array<EdgeDataT, LEAF_NODE_SIZE> objects;
};
struct QueryCandidate
@ -304,6 +345,7 @@ class StaticRTree
uint64_t m_element_count;
const std::string m_leaf_node_filename;
std::shared_ptr<CoordinateListT> m_coordinate_list;
boost::filesystem::ifstream leaves_stream;
public:
StaticRTree() = delete;
@ -369,7 +411,7 @@ class StaticRTree
TreeNode current_node;
// SimpleLogger().Write() << "reading " << tree_size << " tree nodes in " <<
// (sizeof(TreeNode)*tree_size) << " bytes";
for (uint32_t current_element_index = 0; RTREE_LEAF_NODE_SIZE > current_element_index;
for (uint32_t current_element_index = 0; LEAF_NODE_SIZE > current_element_index;
++current_element_index)
{
if (m_element_count > (processed_objects_count + current_element_index))
@ -406,9 +448,9 @@ class StaticRTree
while (processed_tree_nodes_in_level < tree_nodes_in_level.size())
{
TreeNode parent_node;
// pack RTREE_BRANCHING_FACTOR elements into tree_nodes each
// pack BRANCHING_FACTOR elements into tree_nodes each
for (uint32_t current_child_node_index = 0;
RTREE_BRANCHING_FACTOR > current_child_node_index;
BRANCHING_FACTOR > current_child_node_index;
++current_child_node_index)
{
if (processed_tree_nodes_in_level < tree_nodes_in_level.size())
@ -507,9 +549,8 @@ class StaticRTree
throw OSRMException("mem index file is empty");
}
boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
leaf_node_file.close();
leaves_stream.open(leaf_file, std::ios::binary);
leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
// SimpleLogger().Write() << tree_size << " nodes in search tree";
// SimpleLogger().Write() << m_element_count << " elements in leafs";
@ -532,14 +573,8 @@ class StaticRTree
throw OSRMException("mem index file is empty");
}
boost::filesystem::ifstream leaf_node_file(leaf_file, std::ios::binary);
leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
leaf_node_file.close();
if (thread_local_rtree_stream.get())
{
thread_local_rtree_stream->close();
}
leaves_stream.open(leaf_file, std::ios::binary);
leaves_stream.read((char *)&m_element_count, sizeof(uint64_t));
// SimpleLogger().Write() << tree_size << " nodes in search tree";
// SimpleLogger().Write() << m_element_count << " elements in leafs";
@ -628,7 +663,7 @@ class StaticRTree
std::vector<PhantomNode> &result_phantom_node_vector,
const unsigned zoom_level,
const unsigned number_of_results,
const unsigned max_checked_segments = 4*RTREE_LEAF_NODE_SIZE)
const unsigned max_checked_segments = 4*LEAF_NODE_SIZE)
{
// TIMER_START(samet);
// SimpleLogger().Write(logDEBUG) << "searching for " << number_of_results << " results";
@ -988,22 +1023,21 @@ class StaticRTree
inline void LoadLeafFromDisk(const uint32_t leaf_id, LeafNode &result_node)
{
if (!thread_local_rtree_stream.get() || !thread_local_rtree_stream->is_open())
if (!leaves_stream.is_open())
{
thread_local_rtree_stream.reset(new boost::filesystem::ifstream(
m_leaf_node_filename, std::ios::in | std::ios::binary));
leaves_stream.open(m_leaf_node_filename, std::ios::in | std::ios::binary);
}
if (!thread_local_rtree_stream->good())
if (!leaves_stream.good())
{
thread_local_rtree_stream->clear(std::ios::goodbit);
leaves_stream.clear(std::ios::goodbit);
SimpleLogger().Write(logDEBUG) << "Resetting stale filestream";
}
const uint64_t seek_pos = sizeof(uint64_t) + leaf_id * sizeof(LeafNode);
thread_local_rtree_stream->seekg(seek_pos);
BOOST_ASSERT_MSG(thread_local_rtree_stream->good(),
leaves_stream.seekg(seek_pos);
BOOST_ASSERT_MSG(leaves_stream.good(),
"Seeking to position in leaf file failed.");
thread_local_rtree_stream->read((char *)&result_node, sizeof(LeafNode));
BOOST_ASSERT_MSG(thread_local_rtree_stream->good(), "Reading from leaf file failed.");
leaves_stream.read((char *)&result_node, sizeof(LeafNode));
BOOST_ASSERT_MSG(leaves_stream.good(), "Reading from leaf file failed.");
}
inline bool EdgesAreEquivalent(const FixedPointCoordinate &a,

View File

@ -95,16 +95,16 @@ template <class EdgeDataT> class BaseDataFacade
virtual bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
const unsigned zoom_level = 18) const = 0;
const unsigned zoom_level = 18) = 0;
virtual bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &resulting_phantom_node,
const unsigned zoom_level) const = 0;
const unsigned zoom_level) = 0;
virtual bool IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &resulting_phantom_node_vector,
const unsigned zoom_level,
const unsigned number_of_results) const = 0;
const unsigned number_of_results) = 0;
virtual unsigned GetCheckSum() const = 0;

View File

@ -71,8 +71,10 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
ShM<unsigned, false>::vector m_geometry_indices;
ShM<unsigned, false>::vector m_geometry_list;
std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>>
boost::thread_specific_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, false>::vector, false>>
m_static_rtree;
boost::filesystem::path ram_index_path;
boost::filesystem::path file_index_path;
RangeTable<16, false> m_name_table;
void LoadTimestamp(const boost::filesystem::path &timestamp_path)
@ -192,13 +194,13 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
geometry_stream.close();
}
void LoadRTree(const boost::filesystem::path &ram_index_path,
const boost::filesystem::path &file_index_path)
void LoadRTree()
{
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
m_static_rtree = std::make_shared<StaticRTree<RTreeLeaf>>(
ram_index_path, file_index_path, m_coordinate_list);
m_static_rtree.reset(
new StaticRTree<RTreeLeaf>(ram_index_path, file_index_path, m_coordinate_list)
);
}
void LoadStreetNames(const boost::filesystem::path &names_file)
@ -266,10 +268,10 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
const boost::filesystem::path &timestamp_path = paths_iterator->second;
paths_iterator = server_paths.find("ramindex");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &ram_index_path = paths_iterator->second;
ram_index_path = paths_iterator->second;
paths_iterator = server_paths.find("fileindex");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &file_index_path = paths_iterator->second;
file_index_path = paths_iterator->second;
paths_iterator = server_paths.find("nodesdata");
BOOST_ASSERT(server_paths.end() != paths_iterator);
const boost::filesystem::path &nodes_data_path = paths_iterator->second;
@ -297,7 +299,6 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
SimpleLogger().Write() << "loading r-tree";
AssertPathExists(ram_index_path);
AssertPathExists(file_index_path);
LoadRTree(ram_index_path, file_index_path);
SimpleLogger().Write() << "loading timestamp";
LoadTimestamp(timestamp_path);
SimpleLogger().Write() << "loading street names";
@ -358,16 +359,26 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
const unsigned zoom_level = 18) const
const unsigned zoom_level = 18)
{
if (!m_static_rtree.get())
{
LoadRTree();
}
return m_static_rtree->LocateClosestEndPointForCoordinate(
input_coordinate, result, zoom_level);
}
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &resulting_phantom_node,
const unsigned zoom_level) const
const unsigned zoom_level)
{
if (!m_static_rtree.get())
{
LoadRTree();
}
return m_static_rtree->FindPhantomNodeForCoordinate(
input_coordinate, resulting_phantom_node, zoom_level);
}
@ -376,8 +387,13 @@ template <class EdgeDataT> class InternalDataFacade : public BaseDataFacade<Edge
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &resulting_phantom_node_vector,
const unsigned zoom_level,
const unsigned number_of_results) const
const unsigned number_of_results)
{
if (!m_static_rtree.get())
{
LoadRTree();
}
return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
}

View File

@ -83,8 +83,9 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
ShM<unsigned, true>::vector m_geometry_indices;
ShM<unsigned, true>::vector m_geometry_list;
std::shared_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>
boost::thread_specific_ptr<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>
m_static_rtree;
boost::filesystem::path file_index_path;
std::shared_ptr<RangeTable<16, true>> m_name_table;
@ -105,18 +106,19 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
m_timestamp.begin());
}
void LoadRTree(const boost::filesystem::path &file_index_path)
void LoadRTree()
{
BOOST_ASSERT_MSG(!m_coordinate_list->empty(), "coordinates must be loaded before r-tree");
RTreeNode *tree_ptr =
data_layout->GetBlockPtr<RTreeNode>(shared_memory, SharedDataLayout::R_SEARCH_TREE);
m_static_rtree =
std::make_shared<StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>>(
m_static_rtree.reset(
new StaticRTree<RTreeLeaf, ShM<FixedPointCoordinate, true>::vector, true>(
tree_ptr,
data_layout->num_entries[SharedDataLayout::R_SEARCH_TREE],
file_index_path,
m_coordinate_list);
m_coordinate_list)
);
}
void LoadGraph()
@ -248,7 +250,7 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
const char *file_index_ptr =
data_layout->GetBlockPtr<char>(shared_memory, SharedDataLayout::FILE_INDEX_PATH);
boost::filesystem::path file_index_path(file_index_ptr);
file_index_path = boost::filesystem::path(file_index_ptr);
if (!boost::filesystem::exists(file_index_path))
{
SimpleLogger().Write(logDEBUG) << "Leaf file name " << file_index_path.string();
@ -260,7 +262,6 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
LoadChecksum();
LoadNodeAndEdgeInformation();
LoadGeometries();
LoadRTree(file_index_path);
LoadTimestamp();
LoadViaNodeList();
LoadNames();
@ -349,16 +350,26 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result,
const unsigned zoom_level = 18) const
const unsigned zoom_level = 18)
{
if (!m_static_rtree.get())
{
LoadRTree();
}
return m_static_rtree->LocateClosestEndPointForCoordinate(
input_coordinate, result, zoom_level);
}
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &resulting_phantom_node,
const unsigned zoom_level) const
const unsigned zoom_level)
{
if (!m_static_rtree.get())
{
LoadRTree();
}
return m_static_rtree->FindPhantomNodeForCoordinate(
input_coordinate, resulting_phantom_node, zoom_level);
}
@ -367,8 +378,13 @@ template <class EdgeDataT> class SharedDataFacade : public BaseDataFacade<EdgeDa
IncrementalFindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
std::vector<PhantomNode> &resulting_phantom_node_vector,
const unsigned zoom_level,
const unsigned number_of_results) const
const unsigned number_of_results)
{
if (!m_static_rtree.get())
{
LoadRTree();
}
return m_static_rtree->IncrementalFindPhantomNodeForCoordinate(
input_coordinate, resulting_phantom_node_vector, zoom_level, number_of_results);
}

View File

@ -0,0 +1,154 @@
#include "../../DataStructures/BinaryHeap.h"
#include "../../typedefs.h"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/list.hpp>
#include <random>
BOOST_AUTO_TEST_SUITE(binary_heap)
struct TestData
{
unsigned value;
};
typedef NodeID TestNodeID;
typedef int TestKey;
typedef int TestWeight;
typedef boost::mpl::list<ArrayStorage<TestNodeID, TestKey>,
MapStorage<TestNodeID, TestKey>,
UnorderedMapStorage<TestNodeID, TestKey>> storage_types;
template<unsigned NUM_ELEM>
struct RandomDataFixture
{
RandomDataFixture()
{
for (unsigned i = 0; i < NUM_ELEM; i++)
{
data.push_back(TestData {i*3});
weights.push_back((i+1)*100);
ids.push_back(i);
order.push_back(i);
}
// Choosen by a fair W20 dice roll
std::mt19937 g(15);
std::shuffle(order.begin(), order.end(), g);
}
std::vector<TestData> data;
std::vector<TestWeight> weights;
std::vector<TestNodeID> ids;
std::vector<unsigned> order;
};
constexpr unsigned NUM_NODES = 100;
BOOST_FIXTURE_TEST_CASE_TEMPLATE(insert_test, T, storage_types, RandomDataFixture<NUM_NODES>)
{
BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
TestWeight min_weight = std::numeric_limits<TestWeight>::max();
TestNodeID min_id;
for (unsigned idx : order)
{
BOOST_CHECK(!heap.WasInserted(ids[idx]));
heap.Insert(ids[idx], weights[idx], data[idx]);
BOOST_CHECK(heap.WasInserted(ids[idx]));
if (weights[idx] < min_weight)
{
min_weight = weights[idx];
min_id = ids[idx];
}
BOOST_CHECK_EQUAL(min_id, heap.Min());
}
for (auto id : ids)
{
const auto& d = heap.GetData(id);
BOOST_CHECK_EQUAL(d.value, data[id].value);
const auto& w = heap.GetKey(id);
BOOST_CHECK_EQUAL(w, weights[id]);
}
}
BOOST_FIXTURE_TEST_CASE_TEMPLATE(delete_min_test, T, storage_types, RandomDataFixture<NUM_NODES>)
{
BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
for (unsigned idx : order)
{
heap.Insert(ids[idx], weights[idx], data[idx]);
}
for (auto id : ids)
{
BOOST_CHECK(!heap.WasRemoved(id));
BOOST_CHECK_EQUAL(heap.Min(), id);
BOOST_CHECK_EQUAL(id, heap.DeleteMin());
if (id+1 < NUM_NODES)
BOOST_CHECK_EQUAL(heap.Min(), id+1);
BOOST_CHECK(heap.WasRemoved(id));
}
}
BOOST_FIXTURE_TEST_CASE_TEMPLATE(delete_all_test, T, storage_types, RandomDataFixture<NUM_NODES>)
{
BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(NUM_NODES);
for (unsigned idx : order)
{
heap.Insert(ids[idx], weights[idx], data[idx]);
}
heap.DeleteAll();
BOOST_CHECK(heap.Empty());
}
BOOST_FIXTURE_TEST_CASE_TEMPLATE(decrease_key_test, T, storage_types, RandomDataFixture<10>)
{
BinaryHeap<TestNodeID, TestKey, TestWeight, TestData, T> heap(10);
for (unsigned idx : order)
{
heap.Insert(ids[idx], weights[idx], data[idx]);
}
std::vector<TestNodeID> rids(ids);
std::reverse(rids.begin(), rids.end());
for (auto id : rids)
{
TestNodeID min_id = heap.Min();
TestWeight min_weight = heap.GetKey(min_id);
// decrease weight until we reach min weight
while (weights[id] > min_weight)
{
heap.DecreaseKey(id, weights[id]);
BOOST_CHECK_EQUAL(heap.Min(), min_id);
weights[id]--;
}
// make weight smaller than min
weights[id] -= 2;
heap.DecreaseKey(id, weights[id]);
BOOST_CHECK_EQUAL(heap.Min(), id);
}
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,103 @@
#include "../../DataStructures/RangeTable.h"
#include "../../typedefs.h"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <numeric>
constexpr unsigned BLOCK_SIZE = 16;
typedef RangeTable<BLOCK_SIZE, false> TestRangeTable;
BOOST_AUTO_TEST_SUITE(range_table)
void ConstructionTest(std::vector<unsigned> lengths, std::vector<unsigned> offsets)
{
BOOST_ASSERT(lengths.size() == offsets.size() - 1);
TestRangeTable table(lengths);
for (unsigned i = 0; i < lengths.size(); i++)
{
auto range = table.GetRange(i);
BOOST_CHECK_EQUAL(range.front(), offsets[i]);
BOOST_CHECK_EQUAL(range.back()+1, offsets[i+1]);
}
}
void ComputeLengthsOffsets(std::vector<unsigned>& lengths, std::vector<unsigned>& offsets, unsigned num)
{
lengths.resize(num);
offsets.resize(num+1);
std::iota(lengths.begin(), lengths.end(), 1);
offsets[0] = 0;
std::partial_sum(lengths.begin(), lengths.end(), offsets.begin()+1);
std::stringstream l_ss;
l_ss << "Lengths: ";
for (auto l : lengths)
l_ss << l << ", ";
BOOST_TEST_MESSAGE(l_ss.str());
std::stringstream o_ss;
o_ss << "Offsets: ";
for (auto o : offsets)
o_ss << o << ", ";
BOOST_TEST_MESSAGE(o_ss.str());
}
BOOST_AUTO_TEST_CASE(serialization_test)
{
std::vector<unsigned> lengths;
std::vector<unsigned> offsets;
ComputeLengthsOffsets(lengths, offsets, (BLOCK_SIZE+1)*10);
TestRangeTable in_table(lengths);
TestRangeTable out_table;
std::stringstream ss;
ss << in_table;
ss >> out_table;
for (unsigned i = 0; i < lengths.size(); i++)
{
auto range = out_table.GetRange(i);
BOOST_CHECK_EQUAL(range.front(), offsets[i]);
BOOST_CHECK_EQUAL(range.back()+1, offsets[i+1]);
}
}
BOOST_AUTO_TEST_CASE(construction_test)
{
// only offset empty block
ConstructionTest({1}, {0, 1});
// first block almost full => sentinel is last element of block
// [0] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, (16)}
std::vector<unsigned> almost_full_lengths;
std::vector<unsigned> almost_full_offsets;
ComputeLengthsOffsets(almost_full_lengths, almost_full_offsets, BLOCK_SIZE);
ConstructionTest(almost_full_lengths, almost_full_offsets);
// first block full => sentinel is offset of new block, next block empty
// [0] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
// [(153)] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
std::vector<unsigned> full_lengths;
std::vector<unsigned> full_offsets;
ComputeLengthsOffsets(full_lengths, full_offsets, BLOCK_SIZE+1);
ConstructionTest(full_lengths, full_offsets);
// first block full and offset of next block not sentinel, but the first differential value
// [0] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
// [153] {(17), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
std::vector<unsigned> over_full_lengths;
std::vector<unsigned> over_full_offsets;
ComputeLengthsOffsets(over_full_lengths, over_full_offsets, BLOCK_SIZE+2);
ConstructionTest(over_full_lengths, over_full_offsets);
// test multiple blocks
std::vector<unsigned> multiple_lengths;
std::vector<unsigned> multiple_offsets;
ComputeLengthsOffsets(multiple_lengths, multiple_offsets, (BLOCK_SIZE+1)*10);
ConstructionTest(multiple_lengths, multiple_offsets);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,175 @@
#include "../../DataStructures/StaticGraph.h"
#include "../../typedefs.h"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/list.hpp>
#include <random>
#include <unordered_map>
BOOST_AUTO_TEST_SUITE(static_graph)
struct TestData
{
EdgeID id;
bool shortcut;
unsigned distance;
};
struct TestEdge
{
unsigned source;
unsigned target;
unsigned distance;
};
typedef StaticGraph<TestData> TestStaticGraph;
typedef TestStaticGraph::NodeArrayEntry TestNodeArrayEntry;
typedef TestStaticGraph::EdgeArrayEntry TestEdgeArrayEntry;
typedef TestStaticGraph::InputEdge TestInputEdge;
constexpr unsigned TEST_NUM_NODES = 100;
constexpr unsigned TEST_NUM_EDGES = 500;
// Choosen by a fair W20 dice roll (this value is completely arbitrary)
constexpr unsigned RANDOM_SEED = 15;
template<unsigned NUM_NODES, unsigned NUM_EDGES>
struct RandomArrayEntryFixture
{
RandomArrayEntryFixture()
{
std::mt19937 g(RANDOM_SEED);
std::uniform_int_distribution<> edge_udist(0, NUM_EDGES-1);
std::vector<unsigned> offsets;
for (unsigned i = 0; i < NUM_NODES; i++)
{
offsets.push_back(edge_udist(g));
}
std::sort(offsets.begin(), offsets.end());
// add sentinel
offsets.push_back(offsets.back());
// extract interval lengths
for(unsigned i = 0; i < offsets.size()-1; i++)
{
lengths.push_back(offsets[i+1] - offsets[i]);
}
lengths.push_back(NUM_EDGES - offsets[NUM_NODES-1]);
for (auto offset : offsets)
{
nodes.emplace_back(TestNodeArrayEntry {offset});
}
std::uniform_int_distribution<> lengths_udist(0, 100000);
std::uniform_int_distribution<> node_udist(0, NUM_NODES-1);
for (unsigned i = 0; i < NUM_EDGES; i++)
{
edges.emplace_back(
TestEdgeArrayEntry {
static_cast<unsigned>(node_udist(g)),
TestData {i, false, static_cast<unsigned>(lengths_udist(g))}
}
);
}
for (unsigned i = 0; i < NUM_NODES; i++)
order.push_back(i);
std::shuffle(order.begin(), order.end(), g);
}
typename ShM<TestNodeArrayEntry, false>::vector nodes;
typename ShM<TestEdgeArrayEntry, false>::vector edges;
std::vector<unsigned> lengths;
std::vector<unsigned> order;
};
typedef RandomArrayEntryFixture<TEST_NUM_NODES, TEST_NUM_EDGES> TestRandomArrayEntryFixture;
BOOST_FIXTURE_TEST_CASE(array_test, TestRandomArrayEntryFixture)
{
auto nodes_copy = nodes;
TestStaticGraph graph(nodes, edges);
BOOST_CHECK_EQUAL(graph.GetNumberOfEdges(), TEST_NUM_EDGES);
BOOST_CHECK_EQUAL(graph.GetNumberOfNodes(), TEST_NUM_NODES);
for (auto idx : order)
{
BOOST_CHECK_EQUAL(graph.BeginEdges((NodeID) idx), nodes_copy[idx].first_edge);
BOOST_CHECK_EQUAL(graph.EndEdges((NodeID) idx), nodes_copy[idx+1].first_edge);
BOOST_CHECK_EQUAL(graph.GetOutDegree((NodeID) idx), lengths[idx]);
}
}
TestStaticGraph GraphFromEdgeList(const std::vector<TestEdge>& edges)
{
std::vector<TestInputEdge> input_edges;
unsigned i = 0;
unsigned num_nodes = 0;
for (const auto& e : edges)
{
input_edges.push_back(TestInputEdge {
e.source,
e.target,
TestData {i++, false, e.distance}
});
num_nodes = std::max(num_nodes, std::max(e.source, e.target));
}
return TestStaticGraph(num_nodes, input_edges);
}
BOOST_AUTO_TEST_CASE(find_test)
{
/*
* (0) -1-> (1)
* ^ ^
* 2 1
* | |
* (3) -4-> (4)
* <-3-
*/
TestStaticGraph simple_graph = GraphFromEdgeList({
TestEdge {0, 1, 1},
TestEdge {3, 0, 2},
TestEdge {3, 4, 4},
TestEdge {4, 3, 3},
TestEdge {3, 0, 1}
});
auto eit = simple_graph.FindEdge(0, 1);
BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
eit = simple_graph.FindEdge(1, 0);
BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
eit = simple_graph.FindEdgeInEitherDirection(1, 0);
BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
bool reverse = false;
eit = simple_graph.FindEdgeIndicateIfReverse(1, 0, reverse);
BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 0);
BOOST_CHECK(reverse);
eit = simple_graph.FindEdge(3, 1);
BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
eit = simple_graph.FindEdge(0, 4);
BOOST_CHECK_EQUAL(eit, SPECIAL_EDGEID);
eit = simple_graph.FindEdge(3, 4);
BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
eit = simple_graph.FindEdgeInEitherDirection(3, 4);
// I think this is wrong behaviour! Should be 3.
BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 2);
eit = simple_graph.FindEdge(3, 0);
BOOST_CHECK_EQUAL(simple_graph.GetEdgeData(eit).id, 4);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,503 @@
#include "../../DataStructures/StaticRTree.h"
#include "../../DataStructures/QueryNode.h"
#include "../../DataStructures/EdgeBasedNode.h"
#include "../../Include/osrm/Coordinate.h"
#include "../../typedefs.h"
#include <boost/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/list.hpp>
#include <random>
#include <unordered_set>
BOOST_AUTO_TEST_SUITE(static_rtree)
constexpr uint32_t TEST_BRANCHING_FACTOR = 8;
constexpr uint32_t TEST_LEAF_NODE_SIZE = 64;
typedef EdgeBasedNode TestData;
typedef StaticRTree<TestData,
std::vector<FixedPointCoordinate>,
false,
TEST_BRANCHING_FACTOR,
TEST_LEAF_NODE_SIZE>
TestStaticRTree;
// Choosen by a fair W20 dice roll (this value is completely arbitrary)
constexpr unsigned RANDOM_SEED = 15;
static const int32_t WORLD_MIN_LAT = -90*COORDINATE_PRECISION;
static const int32_t WORLD_MAX_LAT = 90*COORDINATE_PRECISION;
static const int32_t WORLD_MIN_LON = -180*COORDINATE_PRECISION;
static const int32_t WORLD_MAX_LON = 180*COORDINATE_PRECISION;
class LinearSearchNN
{
public:
LinearSearchNN(const std::shared_ptr<std::vector<FixedPointCoordinate>>& coords,
const std::vector<TestData>& edges)
: coords(coords)
, edges(edges)
{ }
bool LocateClosestEndPointForCoordinate(const FixedPointCoordinate &input_coordinate,
FixedPointCoordinate &result_coordinate,
const unsigned zoom_level)
{
bool ignore_tiny_components = (zoom_level <= 14);
float min_dist = std::numeric_limits<float>::max();
FixedPointCoordinate min_coord;
for (const TestData& e : edges)
{
if (ignore_tiny_components && e.is_in_tiny_cc)
continue;
const FixedPointCoordinate& start = coords->at(e.u);
const FixedPointCoordinate& end = coords->at(e.v);
float distance = FixedPointCoordinate::ApproximateEuclideanDistance(
input_coordinate.lat,
input_coordinate.lon,
start.lat,
start.lon);
if (distance < min_dist)
{
min_coord = start;
min_dist = distance;
}
distance = FixedPointCoordinate::ApproximateEuclideanDistance(
input_coordinate.lat,
input_coordinate.lon,
end.lat,
end.lon);
if (distance < min_dist)
{
min_coord = end;
min_dist = distance;
}
}
result_coordinate = min_coord;
return result_coordinate.isValid();
}
bool FindPhantomNodeForCoordinate(const FixedPointCoordinate &input_coordinate,
PhantomNode &result_phantom_node,
const unsigned zoom_level)
{
bool ignore_tiny_components = (zoom_level <= 14);
float min_dist = std::numeric_limits<float>::max();
TestData nearest_edge;
for (const TestData& e : edges)
{
if (ignore_tiny_components && e.is_in_tiny_cc)
continue;
float current_ratio = 0.;
FixedPointCoordinate nearest;
const float current_perpendicular_distance =
FixedPointCoordinate::ComputePerpendicularDistance(
coords->at(e.u),
coords->at(e.v),
input_coordinate,
nearest,
current_ratio);
if ((current_perpendicular_distance < min_dist) &&
!EpsilonCompare(current_perpendicular_distance, min_dist))
{ // found a new minimum
min_dist = current_perpendicular_distance;
result_phantom_node = { e.forward_edge_based_node_id,
e.reverse_edge_based_node_id,
e.name_id,
e.forward_weight,
e.reverse_weight,
e.forward_offset,
e.reverse_offset,
e.packed_geometry_id,
nearest,
e.fwd_segment_position};
nearest_edge = e;
}
}
if (result_phantom_node.location.isValid())
{
// Hack to fix rounding errors and wandering via nodes.
if (1 == std::abs(input_coordinate.lon - result_phantom_node.location.lon))
{
result_phantom_node.location.lon = input_coordinate.lon;
}
if (1 == std::abs(input_coordinate.lat - result_phantom_node.location.lat))
{
result_phantom_node.location.lat = input_coordinate.lat;
}
const float distance_1 = FixedPointCoordinate::ApproximateEuclideanDistance(
coords->at(nearest_edge.u),
result_phantom_node.location);
const float distance_2 = FixedPointCoordinate::ApproximateEuclideanDistance(
coords->at(nearest_edge.u),
coords->at(nearest_edge.v));
const float ratio = std::min(1.f, distance_1 / distance_2);
if (SPECIAL_NODEID != result_phantom_node.forward_node_id)
{
result_phantom_node.forward_weight *= ratio;
}
if (SPECIAL_NODEID != result_phantom_node.reverse_node_id)
{
result_phantom_node.reverse_weight *= (1. - ratio);
}
}
return result_phantom_node.location.isValid();
}
template<typename FloatT>
inline bool EpsilonCompare(const FloatT d1, const FloatT d2) const
{
return (std::abs(d1 - d2) < std::numeric_limits<FloatT>::epsilon());
}
private:
const std::shared_ptr<std::vector<FixedPointCoordinate>>& coords;
const std::vector<TestData>& edges;
};
template<unsigned NUM_NODES, unsigned NUM_EDGES>
struct RandomGraphFixture
{
struct TupleHash
{
typedef std::pair<unsigned, unsigned> argument_type;
typedef std::size_t result_type;
result_type operator()(const argument_type & t) const
{
std::size_t val { 0 };
boost::hash_combine(val, t.first);
boost::hash_combine(val, t.second);
return val;
}
};
RandomGraphFixture()
: coords(std::make_shared<std::vector<FixedPointCoordinate>>())
{
BOOST_TEST_MESSAGE("Constructing " << NUM_NODES << " nodes and " << NUM_EDGES << " edges.");
std::mt19937 g(RANDOM_SEED);
std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
for (unsigned i = 0; i < NUM_NODES; i++)
{
int lat = lat_udist(g);
int lon = lon_udist(g);
nodes.emplace_back(NodeInfo(lat, lon, i));
coords->emplace_back(FixedPointCoordinate(lat, lon));
}
std::uniform_int_distribution<> edge_udist(0, nodes.size() - 1);
std::unordered_set<std::pair<unsigned, unsigned>, TupleHash> used_edges;
while(edges.size() < NUM_EDGES)
{
TestData data;
data.u = edge_udist(g);
data.v = edge_udist(g);
if (used_edges.find(std::pair<unsigned, unsigned>(std::min(data.u, data.v), std::max(data.u, data.v))) == used_edges.end())
{
data.is_in_tiny_cc = false;
edges.emplace_back(data);
used_edges.emplace(std::min(data.u, data.v), std::max(data.u, data.v));
}
}
}
std::vector<NodeInfo> nodes;
std::shared_ptr<std::vector<FixedPointCoordinate>> coords;
std::vector<TestData> edges;
};
struct GraphFixture
{
GraphFixture(const std::vector<std::pair<float, float>>& input_coords,
const std::vector<std::pair<unsigned, unsigned>>& input_edges)
: coords(std::make_shared<std::vector<FixedPointCoordinate>>())
{
for (unsigned i = 0; i < input_coords.size(); i++)
{
FixedPointCoordinate c(input_coords[i].first * COORDINATE_PRECISION, input_coords[i].second * COORDINATE_PRECISION);
coords->emplace_back(c);
nodes.emplace_back(NodeInfo(c.lat, c.lon, i));
}
for (const auto& pair : input_edges)
{
TestData d;
d.u = pair.first;
d.v = pair.second;
edges.emplace_back(d);
}
}
std::vector<NodeInfo> nodes;
std::shared_ptr<std::vector<FixedPointCoordinate>> coords;
std::vector<TestData> edges;
};
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE*3, TEST_LEAF_NODE_SIZE/2> TestRandomGraphFixture_LeafHalfFull;
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE*5, TEST_LEAF_NODE_SIZE> TestRandomGraphFixture_LeafFull;
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE*10, TEST_LEAF_NODE_SIZE*2> TestRandomGraphFixture_TwoLeaves;
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE*TEST_BRANCHING_FACTOR*3,
TEST_LEAF_NODE_SIZE*TEST_BRANCHING_FACTOR> TestRandomGraphFixture_Branch;
typedef RandomGraphFixture<TEST_LEAF_NODE_SIZE*TEST_BRANCHING_FACTOR*3,
TEST_LEAF_NODE_SIZE*TEST_BRANCHING_FACTOR*2> TestRandomGraphFixture_MultipleLevels;
template<typename RTreeT>
void simple_verify_rtree(RTreeT& rtree, const std::shared_ptr<std::vector<FixedPointCoordinate>>& coords, const std::vector<TestData>& edges)
{
BOOST_TEST_MESSAGE("Verify end points");
for (const auto& e : edges)
{
FixedPointCoordinate result_u, result_v;
const FixedPointCoordinate& pu = coords->at(e.u);
const FixedPointCoordinate& pv = coords->at(e.v);
bool found_u = rtree.LocateClosestEndPointForCoordinate(pu, result_u, 1);
bool found_v = rtree.LocateClosestEndPointForCoordinate(pv, result_v, 1);
BOOST_CHECK(found_u && found_v);
float dist_u = FixedPointCoordinate::ApproximateEuclideanDistance(
result_u.lat,
result_u.lon,
pu.lat,
pu.lon);
BOOST_CHECK_LE(dist_u, std::numeric_limits<float>::epsilon());
float dist_v = FixedPointCoordinate::ApproximateEuclideanDistance(
result_v.lat,
result_v.lon,
pv.lat,
pv.lon);
BOOST_CHECK_LE(dist_v, std::numeric_limits<float>::epsilon());
}
}
template<typename RTreeT>
void sampling_verify_rtree(RTreeT& rtree, LinearSearchNN& lsnn, unsigned num_samples)
{
std::mt19937 g(RANDOM_SEED);
std::uniform_int_distribution<> lat_udist(WORLD_MIN_LAT, WORLD_MAX_LAT);
std::uniform_int_distribution<> lon_udist(WORLD_MIN_LON, WORLD_MAX_LON);
std::vector<FixedPointCoordinate> queries;
for (unsigned i = 0; i < num_samples; i++)
{
queries.emplace_back(
FixedPointCoordinate(lat_udist(g), lon_udist(g))
);
}
BOOST_TEST_MESSAGE("Sampling queries");
for (const auto& q : queries)
{
FixedPointCoordinate result_rtree;
rtree.LocateClosestEndPointForCoordinate(q, result_rtree, 1);
FixedPointCoordinate result_ln;
lsnn.LocateClosestEndPointForCoordinate(q, result_ln, 1);
BOOST_CHECK_EQUAL(result_ln, result_rtree);
PhantomNode phantom_rtree;
rtree.FindPhantomNodeForCoordinate(q, phantom_rtree, 1);
PhantomNode phantom_ln;
lsnn.FindPhantomNodeForCoordinate(q, phantom_ln, 1);
BOOST_CHECK_EQUAL(phantom_rtree, phantom_ln);
}
}
template<typename FixtureT, typename RTreeT=TestStaticRTree>
void build_rtree(const std::string& prefix, FixtureT* fixture, std::string& leaves_path, std::string& nodes_path)
{
nodes_path = prefix + ".ramIndex";
leaves_path = prefix + ".fileIndex";
const std::string coords_path = prefix + ".nodes";
boost::filesystem::ofstream node_stream(coords_path, std::ios::binary);
const unsigned num_nodes = fixture->nodes.size();
node_stream.write((char *)&num_nodes, sizeof(unsigned));
node_stream.write((char *)&(fixture->nodes[0]), num_nodes * sizeof(NodeInfo));
node_stream.close();
RTreeT r(fixture->edges, nodes_path, leaves_path, fixture->nodes);
}
template<typename FixtureT, typename RTreeT=TestStaticRTree>
void construction_test(const std::string& prefix, FixtureT* fixture)
{
std::string leaves_path;
std::string nodes_path;
build_rtree<FixtureT, RTreeT>(prefix, fixture, leaves_path, nodes_path);
RTreeT rtree(nodes_path, leaves_path, fixture->coords);
LinearSearchNN lsnn(fixture->coords, fixture->edges);
simple_verify_rtree(rtree, fixture->coords, fixture->edges);
sampling_verify_rtree(rtree, lsnn, 100);
}
BOOST_FIXTURE_TEST_CASE(construct_half_leaf_test, TestRandomGraphFixture_LeafHalfFull)
{
construction_test("test_1", this);
}
BOOST_FIXTURE_TEST_CASE(construct_full_leaf_test, TestRandomGraphFixture_LeafFull)
{
construction_test("test_2", this);
}
BOOST_FIXTURE_TEST_CASE(construct_two_leaves_test, TestRandomGraphFixture_TwoLeaves)
{
construction_test("test_3", this);
}
BOOST_FIXTURE_TEST_CASE(construct_branch_test, TestRandomGraphFixture_Branch)
{
construction_test("test_4", this);
}
BOOST_FIXTURE_TEST_CASE(construct_multiple_levels_test, TestRandomGraphFixture_MultipleLevels)
{
construction_test("test_5", this);
}
/*
* Bug: If you querry a point that lies between two BBs that have a gap,
* one BB will be pruned, even if it could contain a nearer match.
*/
BOOST_AUTO_TEST_CASE(regression_test)
{
typedef std::pair<float, float> Coord;
typedef std::pair<unsigned, unsigned> Edge;
GraphFixture fixture({
Coord(40.0, 0.0),
Coord(35.0, 5.0),
Coord(5.0, 5.0),
Coord(0.0, 10.0),
Coord(20.0, 10.0),
Coord(20.0, 5.0),
Coord(40.0, 100.0),
Coord(35.0, 105.0),
Coord(5.0, 105.0),
Coord(0.0, 110.0),
},
{
Edge(0, 1),
Edge(2, 3),
Edge(4, 5),
Edge(6, 7),
Edge(8, 9)
}
);
typedef StaticRTree<TestData,
std::vector<FixedPointCoordinate>,
false,
2,
3> MiniStaticRTree;
std::string leaves_path;
std::string nodes_path;
build_rtree<GraphFixture, MiniStaticRTree>("test_regression", &fixture, leaves_path, nodes_path);
MiniStaticRTree rtree(nodes_path, leaves_path, fixture.coords);
// query a node just right of the center of the gap
FixedPointCoordinate input(20.0 * COORDINATE_PRECISION, 55.1 * COORDINATE_PRECISION);
FixedPointCoordinate result;
rtree.LocateClosestEndPointForCoordinate(input, result, 1);
FixedPointCoordinate result_ln;
LinearSearchNN lsnn(fixture.coords, fixture.edges);
lsnn.LocateClosestEndPointForCoordinate(input, result_ln, 1);
BOOST_CHECK_EQUAL(result_ln, result);
}
void TestRectangle(double width, double height, double center_lat, double center_lon)
{
FixedPointCoordinate center(center_lat*COORDINATE_PRECISION, center_lon*COORDINATE_PRECISION);
TestStaticRTree::RectangleT rect;
rect.min_lat = center.lat - height/2.0 * COORDINATE_PRECISION;
rect.max_lat = center.lat + height/2.0 * COORDINATE_PRECISION;
rect.min_lon = center.lon - width/2.0 * COORDINATE_PRECISION;
rect.max_lon = center.lon + width/2.0 * COORDINATE_PRECISION;
unsigned offset = 5*COORDINATE_PRECISION;
FixedPointCoordinate north(rect.max_lat + offset, center.lon);
FixedPointCoordinate south(rect.min_lat - offset, center.lon);
FixedPointCoordinate west(center.lat, rect.min_lon - offset);
FixedPointCoordinate east(center.lat, rect.max_lon + offset);
FixedPointCoordinate north_east(rect.max_lat + offset, rect.max_lon + offset);
FixedPointCoordinate north_west(rect.max_lat + offset, rect.min_lon - offset);
FixedPointCoordinate south_east(rect.min_lat - offset, rect.max_lon + offset);
FixedPointCoordinate south_west(rect.min_lat - offset, rect.min_lon - offset);
/* Distance to line segments of rectangle */
BOOST_CHECK_EQUAL(
rect.GetMinDist(north),
FixedPointCoordinate::ApproximateEuclideanDistance(north, FixedPointCoordinate(rect.max_lat, north.lon))
);
BOOST_CHECK_EQUAL(
rect.GetMinDist(south),
FixedPointCoordinate::ApproximateEuclideanDistance(south, FixedPointCoordinate(rect.min_lat, south.lon))
);
BOOST_CHECK_EQUAL(
rect.GetMinDist(west),
FixedPointCoordinate::ApproximateEuclideanDistance(west, FixedPointCoordinate(west.lat, rect.min_lon))
);
BOOST_CHECK_EQUAL(
rect.GetMinDist(east),
FixedPointCoordinate::ApproximateEuclideanDistance(east, FixedPointCoordinate(east.lat, rect.max_lon))
);
/* Distance to corner points */
BOOST_CHECK_EQUAL(
rect.GetMinDist(north_east),
FixedPointCoordinate::ApproximateEuclideanDistance(north_east, FixedPointCoordinate(rect.max_lat, rect.max_lon))
);
BOOST_CHECK_EQUAL(
rect.GetMinDist(north_west),
FixedPointCoordinate::ApproximateEuclideanDistance(north_west, FixedPointCoordinate(rect.max_lat, rect.min_lon))
);
BOOST_CHECK_EQUAL(
rect.GetMinDist(south_east),
FixedPointCoordinate::ApproximateEuclideanDistance(south_east, FixedPointCoordinate(rect.min_lat, rect.max_lon))
);
BOOST_CHECK_EQUAL(
rect.GetMinDist(south_west),
FixedPointCoordinate::ApproximateEuclideanDistance(south_west, FixedPointCoordinate(rect.min_lat, rect.min_lon))
);
}
BOOST_AUTO_TEST_CASE(rectangle_test)
{
TestRectangle(10, 10, 5, 5);
TestRectangle(10, 10, -5, 5);
TestRectangle(10, 10, 5, -5);
TestRectangle(10, 10, -5, -5);
TestRectangle(10, 10, 0, 0);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,8 @@
#define BOOST_TEST_MODULE datastructure tests
#include <boost/test/unit_test.hpp>
/*
* This file will contain an automatically generated main function.
*/

View File

@ -417,7 +417,7 @@ unsigned readHSGRFromStream(const boost::filesystem::path &hsgr_file,
<< ", number_of_edges: " << number_of_edges;
// BOOST_ASSERT_MSG( 0 != number_of_edges, "number of edges is zero");
node_list.resize(number_of_nodes + 1);
node_list.resize(number_of_nodes);
hsgr_input_stream.read((char *)&(node_list[0]), number_of_nodes * sizeof(NodeT));
edge_list.resize(number_of_edges);

View File

@ -38,7 +38,12 @@ build_script:
- set TBB_ARCH_PLATFORM=intel64/vc12
- cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=%Configuration% -DBZIP2_INCLUDE_DIR=%P%/libs/include -DBZIP2_LIBRARIES=%P%/libs/lib/libbz2.lib -DCMAKE_INSTALL_PREFIX=%P%/libs -DBOOST_ROOT=%P%/boost_min -DBoost_USE_STATIC_LIBS=ON
- nmake
- nmake tests
- nmake benchmarks
- if "%APPVEYOR_REPO_BRANCH%"=="develop" (7z a %P%/osrm_%Configuration%.zip *.exe *.pdb %P%/libs/bin/*.dll -tzip)
- set PATH=%PATH%;c:/projects/osrm/libs/bin
- cd c:/projects/osrm/build
- datastructure-tests.exe
test: off