From 5327f8da4ea1676a86b53b7dbaff2c0fd4964ba9 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Mon, 29 Oct 2018 21:40:23 -0700 Subject: [PATCH 1/3] Timer script should error properly if something goes wrong, and print out what happened. --- scripts/timer.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/timer.js b/scripts/timer.js index 47fb280a9..894310d6f 100755 --- a/scripts/timer.js +++ b/scripts/timer.js @@ -6,8 +6,12 @@ var fs = require('fs'); var name = process.argv[2]; var cmd = process.argv.slice(3).join(' '); var start = Date.now(); -exec(cmd, (err) => { - if (err) return console.log(err); +exec(cmd, (err, stdout, stderr) => { + if (err) { + console.log(stdout); + console.log(stderr); + return process.exit(err.code); + } var stop = +new Date(); var time = (stop - start) / 1000.; fs.appendFileSync('/tmp/osrm.timings', `${name}\t${time}`, 'utf-8'); From 498259b220b74d33609fce8504aecb7b6837ebed Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Mon, 29 Oct 2018 21:47:49 -0700 Subject: [PATCH 2/3] Replace dynamic distance calculation for table plugin with pre-calculated distances on shortcuts, avoiding unpacking cost. Adds approx 10% to total data size. Speeds up large table requests by 2 orders of magnitude. Co-authored-by: Kajari Ghosh --- CHANGELOG.md | 4 +- features/testbot/distance_matrix.feature | 298 +++++----- features/testbot/multi_level_routing.feature | 106 ++-- include/contractor/contractor_graph.hpp | 7 +- .../contractor/graph_contractor_adaptors.hpp | 8 + include/contractor/query_edge.hpp | 11 +- include/customizer/cell_customizer.hpp | 48 +- include/customizer/cell_metric.hpp | 1 + include/customizer/edge_based_graph.hpp | 13 +- include/customizer/serialization.hpp | 4 + .../datafacade/algorithm_datafacade.hpp | 2 + .../contiguous_internalmem_datafacade.hpp | 5 + .../routing_algorithms/many_to_many.hpp | 11 +- .../routing_algorithms/routing_base.hpp | 16 +- .../routing_algorithms/routing_base_ch.hpp | 11 +- .../routing_algorithms/routing_base_mld.hpp | 84 --- include/engine/search_engine_data.hpp | 18 +- include/extractor/edge_based_edge.hpp | 17 +- .../extractor/edge_based_graph_factory.hpp | 2 + include/extractor/extractor.hpp | 1 + include/extractor/files.hpp | 36 +- include/extractor/internal_extractor_edge.hpp | 2 +- include/extractor/node_based_edge.hpp | 24 +- include/partitioner/cell_storage.hpp | 47 +- .../partitioner/edge_based_graph_reader.hpp | 2 + include/storage/view_factory.hpp | 13 +- include/updater/updater.hpp | 16 +- include/util/debug.hpp | 19 + include/util/node_based_graph.hpp | 14 +- include/util/typedefs.hpp | 1 + src/contractor/graph_contractor.cpp | 4 + src/customize/customizer.cpp | 14 +- .../alternative_path_ch.cpp | 2 +- .../routing_algorithms/many_to_many_ch.cpp | 213 +------ .../routing_algorithms/many_to_many_mld.cpp | 519 ++++-------------- src/extractor/edge_based_graph_factory.cpp | 38 +- src/extractor/extraction_containers.cpp | 4 + src/extractor/extractor.cpp | 10 +- src/extractor/extractor_callbacks.cpp | 2 + src/extractor/graph_compressor.cpp | 17 + src/partitioner/partitioner.cpp | 7 +- .../contractor/contracted_edge_container.cpp | 55 +- unit_tests/contractor/graph_contractor.cpp | 2 +- unit_tests/contractor/helper.hpp | 8 +- unit_tests/customizer/cell_customization.cpp | 17 +- unit_tests/extractor/graph_compressor.cpp | 1 + .../extractor/intersection_analysis_tests.cpp | 4 +- unit_tests/partitioner/renumber.cpp | 4 +- 48 files changed, 767 insertions(+), 995 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb8b8a19f..9ed1826aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # UNRELEASED - Changes from 5.19.0: + - Table: + - CHANGED: switch to pre-calculated distances for table responses for large speedup and 10% memory increase. [#5251](https://github.com/Project-OSRM/osrm-backend/pull/5251) - Features: - - ADDED: direct mmapping of datafiles is now supported via the `-mmap` switch. [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242) + - ADDED: direct mmapping of datafiles is now supported via the `--mmap` switch. [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242) - REMOVED: the previous `--memory_file` switch is now deprecated and will fallback to `--mmap` [#5242](https://github.com/Project-OSRM/osrm-backend/pull/5242) - Windows: - FIXED: Windows builds again. [#5249](https://github.com/Project-OSRM/osrm-backend/pull/5249) diff --git a/features/testbot/distance_matrix.feature b/features/testbot/distance_matrix.feature index d97f50924..0b9e7c733 100644 --- a/features/testbot/distance_matrix.feature +++ b/features/testbot/distance_matrix.feature @@ -5,21 +5,49 @@ Feature: Basic Distance Matrix Background: Given the profile "testbot" And the partition extra arguments "--small-component-size 1 --max-cell-sizes 2,4,8,16" - - Scenario: Testbot - Travel distance matrix of minimal network + Scenario: Testbot - Travel distance matrix of small grid Given the node map """ - a b + a b c + d e f """ And the ways | nodes | - | ab | + | abc | + | def | + | ad | + | be | + | cf | When I request a travel distance matrix I should get - | | a | b | - | a | 0 | 100+-1 | - | b | 100+-1 | 0 | + | | a | b | e | f | + | a | 0 | 100.1 | 199.5 | 299.5 | + | b | 100.1 | 0 | 99.4 | 199.5 | + | e | 199.5 | 99.4 | 0 | 100.1 | + | f | 299.5 | 199.5 | 100.1 | 0 | + + Scenario: Testbot - Travel distance matrix of minimal network exact distances + Given the node map + """ + a z + b + c + d + """ + + And the ways + | nodes | + | az | + | zbcd | + + When I request a travel distance matrix I should get + | | a | z | b | c | d | + | a | 0 | 100.1 | 199.5 | 298.9 | 398.3 | + | z | 100.1 | 0 | 99.4 | 198.8 | 298.2 | + | b | 199.5 | 99.4 | 0 | 99.4 | 198.8 | + | c | 298.9 | 198.8 | 99.4 | 0 | 99.4 | + | d | 398.3 | 298.2 | 198.8 | 99.4 | 0 | Scenario: Testbot - Travel distance matrix of minimal network with toll exclude Given the query options @@ -39,11 +67,11 @@ Feature: Basic Distance Matrix | bd | motorway | yes | not drivable for exclude=toll and exclude=motorway,toll | When I request a travel distance matrix I should get - | | a | b | c | d | - | a | 0 | 100+-1 | | | - | b | 100+-1 | 0 | | | - | c | | | 0 | 100+-1 | - | d | | | 100+-1 | 0 | + | | a | b | c | d | + | a | 0 | 100.1 | | | + | b | 100.1 | 0 | | | + | c | | | 0 | 100.1 | + | d | | | 100.1 | 0 | Scenario: Testbot - Travel distance matrix of minimal network with motorway exclude Given the query options @@ -63,8 +91,8 @@ Feature: Basic Distance Matrix | bd | residential | | When I request a travel distance matrix I should get - | | a | b | c | d | - | a | 0 | 300+-2 | 100+-2 | 200+-2 | + | | a | b | c | d | + | a | 0 | 298.9 | 99.4 | 199.5 | Scenario: Testbot - Travel distance matrix of minimal network disconnected motorway exclude Given the query options @@ -84,8 +112,8 @@ Feature: Basic Distance Matrix | efgh | residential | | When I request a travel distance matrix I should get - | | a | b | e | - | a | 0 | 50+-1 | | + | | a | b | e | + | a | 0 | 50.1 | | Scenario: Testbot - Travel distance matrix of minimal network with motorway and toll excludes Given the query options @@ -106,7 +134,7 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | e | g | - | a | 0 | 100+-1 | | | + | a | 0 | 100.1 | | | Scenario: Testbot - Travel distance matrix with different way speeds Given the node map @@ -121,22 +149,22 @@ Feature: Basic Distance Matrix | cd | tertiary | When I request a travel distance matrix I should get - | | a | b | c | d | - | a | 0 | 100+-1 | 200+-1 | 300+-1 | - | b | 100+-1 | 0 | 100+-1 | 200+-1 | - | c | 200+-1 | 100+-1 | 0 | 100+-1 | - | d | 300+-1 | 200+-1 | 100+-1 | 0 | + | | a | b | c | d | + | a | 0 | 100.1 | 200.1 | 300.2 | + | b | 100.1 | 0 | 100.1 | 200.1 | + | c | 200.1 | 100.1 | 0 | 100.1 | + | d | 300.2 | 200.1 | 100.1 | 0 | When I request a travel distance matrix I should get - | | a | b | c | d | - | a | 0 | 100+-1 | 200+-1 | 300+-1 | + | | a | b | c | d | + | a | 0 | 100.1 | 200.1 | 300.2 | When I request a travel distance matrix I should get - | | a | - | a | 0 | - | b | 100+-1 | - | c | 200+-1 | - | d | 300+-1 | + | | a | + | a | 0 | + | b | 100.1 | + | c | 200.1 | + | d | 300.2 | Scenario: Testbot - Travel distance matrix of small grid Given the node map @@ -154,11 +182,11 @@ Feature: Basic Distance Matrix | cf | When I request a travel distance matrix I should get - | | a | b | e | f | - | a | 0 | 100+-1 | 200+-1 | 300+-1 | - | b | 100+-1 | 0 | 100+-1 | 200+-1 | - | e | 200+-1 | 100+-1 | 0 | 100+-1 | - | f | 300+-1 | 200+-1 | 100+-1 | 0 | + | | a | b | e | f | + | a | 0 | 100.1 | 199.5 | 299.5 | + | b | 100.1 | 0 | 99.4 | 199.5 | + | e | 199.5 | 99.4 | 0 | 100.1 | + | f | 299.5 | 199.5 | 100.1 | 0 | Scenario: Testbot - Travel distance matrix of network with unroutable parts Given the node map @@ -172,7 +200,7 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get | | a | b | - | a | 0 | 100+-1 | + | a | 0 | 100.1 | | b | | 0 | Scenario: Testbot - Travel distance matrix of network with oneways @@ -189,11 +217,11 @@ Feature: Basic Distance Matrix | by | | When I request a travel distance matrix I should get - | | x | y | d | e | - | x | 0 | 300+-2 | 400+-2 | 300+-2 | - | y | 500+-2 | 0 | 300+-2 | 200+-2 | - | d | 200+-2 | 300+-2 | 0 | 300+-2 | - | e | 300+-2 | 400+-2 | 100+-2 | 0 | + | | x | y | d | e | + | x | 0 | 300.2 | 399.6 | 299.5 | + | y | 499 | 0 | 299.5 | 199.5 | + | d | 199.5 | 299.5 | 0 | 298.9 | + | e | 299.5 | 399.6 | 100.1 | 0 | Scenario: Testbot - Rectangular travel distance matrix Given the node map @@ -212,53 +240,53 @@ Feature: Basic Distance Matrix When I route I should get | from | to | distance | - | e | a | 200m +- 1 | - | e | b | 100m +- 1 | - | f | a | 300m +- 1 | - | f | b | 200m +- 1 | + | e | a | 200m | + | e | b | 100m | + | f | a | 299.9m | + | f | b | 200m | When I request a travel distance matrix I should get | | a | b | e | f | - | a | 0 | 100+-1 | 200+-1 | 300+-1 | + | a | 0 | 100.1 | 199.5 | 299.5 | When I request a travel distance matrix I should get - | | a | - | a | 0 | - | b | 100+-1 | - | e | 200+-1 | - | f | 300+-1 | + | | a | + | a | 0 | + | b | 100.1 | + | e | 199.5 | + | f | 299.5 | When I request a travel distance matrix I should get - | | a | b | e | f | - | a | 0 | 100+-1 | 200+-1 | 300+-1 | - | b | 100+-1 | 0 | 100+-1 | 200+-1 | + | | a | b | e | f | + | a | 0 | 100.1 | 199.5 | 299.5 | + | b | 100.1 | 0 | 99.4 | 199.5 | When I request a travel distance matrix I should get - | | a | b | - | a | 0 | 100+-1 | - | b | 100+-1 | 0 | - | e | 200+-1 | 100+-1 | - | f | 300+-1 | 200+-1 | + | | a | b | + | a | 0 | 100.1 | + | b | 100.1 | 0 | + | e | 199.5 | 99.4 | + | f | 299.5 | 199.5 | When I request a travel distance matrix I should get - | | a | b | e | f | - | a | 0 | 100+-1 | 200+-1 | 300+-1 | - | b | 100+-1 | 0 | 100+-1 | 200+-1 | - | e | 200+-1 | 100+-1 | 0 | 100+-1 | + | | a | b | e | f | + | a | 0 | 100.1 | 199.5 | 299.5 | + | b | 100.1 | 0 | 99.4 | 199.5 | + | e | 199.5 | 99.4 | 0 | 100.1 | When I request a travel distance matrix I should get - | | a | b | e | - | a | 0 | 100+-1 | 200+-1 | - | b | 100+-1 | 0 | 100+-1 | - | e | 200+-1 | 100+-1 | 0 | - | f | 300+-1 | 200+-1 | 100+-1 | + | | a | b | e | + | a | 0 | 100.1 | 199.5 | + | b | 100.1 | 0 | 99.4 | + | e | 199.5 | 99.4 | 0 | + | f | 299.5 | 199.5 | 100.1 | When I request a travel distance matrix I should get - | | a | b | e | f | - | a | 0 | 100+-1 | 200+-1 | 300+-1 | - | b | 100+-1 | 0 | 100+-1 | 200+-1 | - | e | 200+-1 | 100+-1 | 0 | 100+-1 | - | f | 300+-1 | 200+-1 | 100+-1 | 0 | + | | a | b | e | f | + | a | 0 | 100.1 | 199.5 | 299.5 | + | b | 100.1 | 0 | 99.4 | 199.5 | + | e | 199.5 | 99.4 | 0 | 100.1 | + | f | 299.5 | 199.5 | 100.1 | 0 | Scenario: Testbot - Travel distance 3x2 matrix Given the node map @@ -277,9 +305,9 @@ Feature: Basic Distance Matrix When I request a travel distance matrix I should get - | | b | e | f | - | a | 100+-1 | 200+-1 | 300+-1 | - | b | 0 | 100+-1 | 200+-1 | + | | b | e | f | + | a | 100.1 | 199.5 | 299.5 | + | b | 0 | 99.4 | 199.5 | Scenario: Testbot - All coordinates are from same small component Given a grid size of 300 meters @@ -299,9 +327,9 @@ Feature: Basic Distance Matrix | fg | When I request a travel distance matrix I should get - | | f | g | - | f | 0 | 300+-2 | - | g | 300+-2 | 0 | + | | f | g | + | f | 0 | 298.2 | + | g | 298.2 | 0 | Scenario: Testbot - Coordinates are from different small component and snap to big CC Given a grid size of 300 meters @@ -333,11 +361,11 @@ Feature: Basic Distance Matrix | i | h | 300m | When I request a travel distance matrix I should get - | | f | g | h | i | - | f | 0 | 300+-2 | 0 | 300+-2 | - | g | 300+-2 | 0 | 300+-2 | 0 | - | h | 0 | 300+-2 | 0 | 300+-2 | - | i | 300+-2 | 0 | 300+-2 | 0 | + | | f | g | h | i | + | f | 0 | 298.2 | 0 | 298.2 | + | g | 298.2 | 0 | 298.2 | 0 | + | h | 0 | 298.2 | 0 | 298.2 | + | i | 298.2 | 0 | 298.2 | 0 | Scenario: Testbot - Travel distance matrix with loops Given the node map @@ -354,11 +382,11 @@ Feature: Basic Distance Matrix | da | yes | When I request a travel distance matrix I should get - | | 1 | 2 | 3 | 4 | - | 1 | 0 | 100+-1 | 400+-1 | 500+-1 | - | 2 | 700+-1 | 0 | 300+-1 | 400+-1 | - | 3 | 400+-1 | 500+-1 | 0 | 100+-1 | - | 4 | 300+-1 | 400+-1 | 700+-1 | 0 | + | | 1 | 2 | 3 | 4 | + | 1 | 0 | 100.1 | 399.6 | 499.7 | + | 2 | 699.1 | 0 | 299.5 | 399.6 | + | 3 | 399.6 | 499.7 | 0 | 100.1 | + | 4 | 299.5 | 399.6 | 699.1 | 0 | Scenario: Testbot - Travel distance matrix based on segment durations @@ -395,12 +423,12 @@ Feature: Basic Distance Matrix | ce | When I request a travel distance matrix I should get - | | a | b | c | d | e | - | a | 0 | 100+-2 | 200+-2 | 300+-2 | 400+-2 | - | b | 100+-2 | 0 | 100+-2 | 200+-2 | 300+-2 | - | c | 200+-2 | 100+-2 | 0 | 100+-2 | 200+-2 | - | d | 300+-2 | 200+-2 | 100+-2 | 0 | 300+-2 | - | e | 400+-2 | 300+-2 | 200+-2 | 300+-2 | 0 | + | | a | b | c | d | e | + | a | 0 | 100.1 | 200.1 | 300.2 | 398.9 | + | b | 100.1 | 0 | 100.1 | 200.1 | 298.9 | + | c | 200.1 | 100.1 | 0 | 100.1 | 198.8 | + | d | 300.2 | 200.1 | 100.1 | 0 | 298.9 | + | e | 398.9 | 298.9 | 198.8 | 298.9 | 0 | Scenario: Testbot - Travel distance matrix for alternative loop paths Given the profile file @@ -439,26 +467,26 @@ Feature: Basic Distance Matrix | ca | yes | When I request a travel distance matrix I should get - | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | - | 1 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | - | 2 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | - | 3 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | - | 4 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | - | 5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 | 300+-5 | 200+-5 | - | 6 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 | 400+-5 | 300+-5 | - | 7 | 300+-5 | 200+-5 | 600+-5 | 500+-5 | 900+-5 | 800+-5 | 0 | 1100+-5 | - | 8 | 400+-5 | 300+-5 | 700+-5 | 600+-5 | 1000+-5 | 900+-5 | 100+-5 | 0 | + | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | + | 1 | 0 | 1096.7 | 298.9 | 199.5 | 598.4 | 498.3 | 897.3 | 797.9 | + | 2 | 100.1 | 0 | 398.9 | 299.5 | 698.5 | 598.4 | 997.3 | 897.9 | + | 3 | 897.9 | 797.9 | 0 | 1097.4 | 299.5 | 199.5 | 598.4 | 499 | + | 4 | 997.3 | 897.3 | 99.4 | 0 | 398.9 | 298.9 | 697.8 | 598.4 | + | 5 | 598.4 | 498.3 | 897.3 | 797.9 | 0 | 1096.7 | 298.9 | 199.5 | + | 6 | 698.5 | 598.4 | 997.3 | 897.9 | 100.1 | 0 | 398.9 | 299.5 | + | 7 | 299.5 | 199.5 | 598.4 | 499 | 897.9 | 797.9 | 0 | 1097.4 | + | 8 | 398.9 | 298.9 | 697.8 | 598.4 | 997.3 | 897.3 | 99.4 | 0 | When I request a travel distance matrix I should get - | | 1 | - | 1 | 0 | - | 2 | 100+-5 | - | 3 | 900+-5 | - | 4 | 1000+-5 | - | 5 | 600+-5 | - | 6 | 700+-5 | - | 7 | 300+-5 | - | 8 | 400+-5 | + | | 1 | + | 1 | 0 | + | 2 | 100.1 | + | 3 | 897.9 | + | 4 | 997.3 | + | 5 | 598.4 | + | 6 | 698.5 | + | 7 | 299.5 | + | 8 | 398.9 | Scenario: Testbot - Travel distance matrix with ties Given the node map @@ -480,26 +508,26 @@ Feature: Basic Distance Matrix | a | c | ac,ac | 200m | 20s | 20 | When I route I should get - | from | to | route | distance | - | a | b | ab,ab | 450m | - | a | c | ac,ac | 200m | - | a | d | ac,dc,dc | 500m +- 1 | + | from | to | route | distance | + | a | b | ab,ab | 450m | + | a | c | ac,ac | 200m | + | a | d | ac,dc,dc | 499.9m | When I request a travel distance matrix I should get - | | a | b | c | d | - | a | 0 | 450+-2 | 200+-2 | 500+-2 | + | | a | b | c | d | + | a | 0 | 450.3 | 198.8 | 499 | When I request a travel distance matrix I should get - | | a | - | a | 0 | - | b | 450+-2 | - | c | 200+-2 | - | d | 500+-2 | + | | a | + | a | 0 | + | b | 450.3 | + | c | 198.8 | + | d | 499 | When I request a travel distance matrix I should get - | | a | c | - | a | 0 | 200+-2 | - | c | 200+-2 | 0 | + | | a | c | + | a | 0 | 198.8 | + | c | 198.8 | 0 | # Check rounding errors @@ -515,8 +543,8 @@ Feature: Basic Distance Matrix | abcd | When I request a travel distance matrix I should get - | | a | b | c | d | - | a | 0 | 1000+-3 | 2000+-3 | 3000+-3 | + | | a | b | c | d | + | a | 0 | 1000.7 | 2001.4 | 3002.1 | Scenario: Testbot - OneToMany vs ManyToOne @@ -560,10 +588,10 @@ Feature: Basic Distance Matrix | fd | | When I request a travel distance matrix I should get - | | a | b | c | d | e | f | - | a | 0 | 100+-1 | 300+-1 | 650+-1 | 1930+-1 | 1533+-1 | - | b | 760+-1 | 0 | 200+-1 | 550+-1 | 1830+-1 | 1433+-1 | - | c | 560+-2 | 660+-2 | 0 | 350+-1 | 1630+-1 | 1233+-1 | - | d | 1480+-2 | 1580+-1 | 1780+-1 | 0 | 1280+-1 | 883+-1 | - | e | 200+-2 | 300+-2 | 500+-1 | 710+-1 | 0 | 1593+-1 | - | f | 597+-1 | 696+-1 | 896+-1 | 1108+-1 | 400+-3 | 0 | + | | a | b | c | d | e | f | + | a | 0 | 100.1 | 300.2 | 650.5 | 1930.6 | 1533 | + | b | 759 | 0 | 200.1 | 550.4 | 1830.5 | 1432.9 | + | c | 558.8 | 658.9 | 0 | 350.3 | 1630.4 | 1232.8 | + | d | 1478.9 | 1579 | 1779.1 | 0 | 1280.1 | 882.5 | + | e | 198.8 | 298.9 | 499 | 710.3 | 0 | 1592.8 | + | f | 596.4 | 696.5 | 896.6 | 1107.9 | 397.6 | 0 | diff --git a/features/testbot/multi_level_routing.feature b/features/testbot/multi_level_routing.feature index 1fd0ab399..35e0408bc 100644 --- a/features/testbot/multi_level_routing.feature +++ b/features/testbot/multi_level_routing.feature @@ -38,15 +38,15 @@ Feature: Multi level routing Scenario: Testbot - Multi level routing Given the node map """ - a───b e───f - │ │ │ │ + a────b e─────f + \ │ │ / d───c h───g ╲ ╱ ╳ ╱ ╲ i───j m───n - │ │ │ │ - l───k───p───o + / │ │ \ + l─────k───p─────o """ And the nodes @@ -67,78 +67,76 @@ Feature: Multi level routing When I route I should get | from | to | route | time | - | a | b | abcda,abcda | 20s | - | a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 229.4s | - | a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 144.7s | - | a | o | abcda,cm,mnopm,mnopm,mnopm | 124.7s | - | f | l | efghe,hj,ijkli,ijkli,ijkli | 124.7s | - | f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 144.7s | - | l | o | ijkli,kp,mnopm,mnopm | 60s | + | a | b | abcda,abcda | 25s | + | a | f | abcda,cm,mnopm,kp,ijkli,hj,efghe,efghe | 239.2s | + | a | l | abcda,cm,mnopm,kp,ijkli,ijkli | 157.1s | + | a | o | abcda,cm,mnopm,mnopm,mnopm | 137.1s | + | f | l | efghe,hj,ijkli,ijkli | 136.7s | + | f | o | efghe,hj,ijkli,kp,mnopm,mnopm | 162.1s | + | l | o | ijkli,kp,mnopm,mnopm | 80s | | c | m | cm,cm | 44.7s | + | f | a | efghe,hj,ijkli,kp,mnopm,cm,abcda,abcda | 239.2s | + | l | a | ijkli,kp,mnopm,cm,abcda,abcda | 157.1s | When I request a travel time matrix I should get - | | a | f | l | o | - | a | 0 | 229.4 | 144.7 | 124.7 | - | f | 229.4 | 0 | 124.7 | 144.7 | - | l | 144.7 | 124.7 | 0 | 60 | - | o | 124.7 | 144.7 | 60 | 0 | + | | a | f | l | o | + | a | 0 | 239.2 | 157.1 | 137.1 | + | f | 239.2 | 0 | 136.7 | 162.1 | + | l | 157.1 | 136.7 | 0 | 80 | + | o | 137.1 | 162.1 | 80 | 0 | When I request a travel time matrix I should get - | | a | f | l | o | - | a | 0 | 229.4 | 144.7 | 124.7 | + | | a | f | l | o | + | a | 0 | 239.2 | 157.1 | 137.1 | When I request a travel time matrix I should get - | | a | - | a | 0 | - | f | 229.4 | - | l | 144.7 | - | o | 124.7 | + | | a | + | a | 0 | + | f | 239.2 | + | l | 157.1 | + | o | 137.1 | When I request a travel time matrix I should get - | | a | f | l | o | - | a | 0 | 229.4 | 144.7 | 124.7 | - | o | 124.7 | 144.7 | 60 | 0 | + | | a | f | l | o | + | a | 0 | 239.2 | 157.1 | 137.1 | + | o | 137.1 | 162.1 | 80 | 0 | When I request a travel time matrix I should get | | a | o | - | a | 0 | 124.7 | - | f | 229.4 | 144.7 | - | l | 144.7 | 60 | - | o | 124.7 | 0 | - + | a | 0 | 137.1 | + | f | 239.2 | 162.1 | + | l | 157.1 | 80 | + | o | 137.1 | 0 | When I request a travel distance matrix I should get - | | a | f | l | o | - | a | 0+-2 | 2287+-2 | 1443+-2 | 1243+-2 | - | f | 2284+-2 | 0+-2 | 1241+-2 | 1443+-2 | - | l | 1443+-2 | 1244+-2 | 0+-2 | 600+-2 | - | o | 1243+-2 | 1444+-2 | 600+-2 | 0+-2 | + | | a | f | l | o | + | a | 0 | 2383.7 | 1566.9 | 1366.8 | + | f | 2339.9 | 0 | 1198.1 | 1522.1 | + | l | 1618.3 | 1293.3 | 0 | 800.5 | + | o | 1418.2 | 1617.3 | 800.5 | 0 | When I request a travel distance matrix I should get - | | a | f | l | o | - | a | 0 | 2287.2+-2 | 1443+-2 | 1243+-2 | + | | a | f | l | o | + | a | 0 | 2383.7 | 1566.9 | 1366.8 | When I request a travel distance matrix I should get - | | a | - | a | 0 | - | f | 2284.5+-2 | - | l | 1443.1 | - | o | 1243 | + | | a | + | a | 0 | + | f | 2339.9 | + | l | 1618.3 | + | o | 1418.2 | When I request a travel distance matrix I should get - | | a | f | l | o | - | a | 0 | 2287+-2 | 1443+-2 | 1243+-2 | - | o | 1243 | 1444+-2 | 600+-2 | 0+-2 | - + | | a | f | l | o | + | a | 0 | 2383.7 | 1566.9 | 1366.8 | + | f | 2339.9 | 0 | 1198.1 | 1522.1 | When I request a travel distance matrix I should get - | | a | o | - | a | 0+-2 | 1243+-2 | - | f | 2284+-2 | 1443+-2 | - | l | 1443+-2 | 600+-2 | - | o | 1243+-2 | 0+-2 | - - + | | a | o | + | a | 0 | 1366.8 | + | f | 2339.9 | 1522.1 | + | l | 1618.3 | 800.5 | + | o | 1418.2 | 0 | Scenario: Testbot - Multi level routing: horizontal road Given the node map diff --git a/include/contractor/contractor_graph.hpp b/include/contractor/contractor_graph.hpp index 3424568a6..02cad2e08 100644 --- a/include/contractor/contractor_graph.hpp +++ b/include/contractor/contractor_graph.hpp @@ -12,23 +12,26 @@ namespace contractor struct ContractorEdgeData { ContractorEdgeData() - : weight(0), duration(0), id(0), originalEdges(0), shortcut(0), forward(0), backward(0) + : weight(0), duration(0), distance(0), id(0), originalEdges(0), shortcut(0), forward(0), + backward(0) { } ContractorEdgeData(EdgeWeight weight, EdgeWeight duration, + EdgeDistance distance, unsigned original_edges, unsigned id, bool shortcut, bool forward, bool backward) - : weight(weight), duration(duration), id(id), + : weight(weight), duration(duration), distance(distance), id(id), originalEdges(std::min((1u << 29) - 1u, original_edges)), shortcut(shortcut), forward(forward), backward(backward) { } EdgeWeight weight; EdgeWeight duration; + EdgeDistance distance; unsigned id; unsigned originalEdges : 29; bool shortcut : 1; diff --git a/include/contractor/graph_contractor_adaptors.hpp b/include/contractor/graph_contractor_adaptors.hpp index 11d96af58..94dc7e62b 100644 --- a/include/contractor/graph_contractor_adaptors.hpp +++ b/include/contractor/graph_contractor_adaptors.hpp @@ -41,6 +41,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp input_edge.target, std::max(input_edge.data.weight, 1), input_edge.data.duration, + input_edge.data.distance, 1, input_edge.data.turn_id, false, @@ -51,6 +52,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp input_edge.source, std::max(input_edge.data.weight, 1), input_edge.data.duration, + input_edge.data.distance, 1, input_edge.data.turn_id, false, @@ -82,6 +84,7 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp forward_edge.data.originalEdges = reverse_edge.data.originalEdges = 1; forward_edge.data.weight = reverse_edge.data.weight = INVALID_EDGE_WEIGHT; forward_edge.data.duration = reverse_edge.data.duration = MAXIMAL_EDGE_DURATION; + forward_edge.data.distance = reverse_edge.data.distance = MAXIMAL_EDGE_DISTANCE; // remove parallel edges while (i < edges.size() && edges[i].source == source && edges[i].target == target) { @@ -90,12 +93,16 @@ ContractorGraph toContractorGraph(NodeID number_of_nodes, InputEdgeContainer inp forward_edge.data.weight = std::min(edges[i].data.weight, forward_edge.data.weight); forward_edge.data.duration = std::min(edges[i].data.duration, forward_edge.data.duration); + forward_edge.data.distance = + std::min(edges[i].data.distance, forward_edge.data.distance); } if (edges[i].data.backward) { reverse_edge.data.weight = std::min(edges[i].data.weight, reverse_edge.data.weight); reverse_edge.data.duration = std::min(edges[i].data.duration, reverse_edge.data.duration); + reverse_edge.data.distance = + std::min(edges[i].data.distance, reverse_edge.data.distance); } ++i; } @@ -151,6 +158,7 @@ template inline std::vector toEdges(GraphT g BOOST_ASSERT_MSG(SPECIAL_NODEID != new_edge.target, "Target id invalid"); new_edge.data.weight = data.weight; new_edge.data.duration = data.duration; + new_edge.data.distance = data.distance; new_edge.data.shortcut = data.shortcut; new_edge.data.turn_id = data.id; BOOST_ASSERT_MSG(new_edge.data.turn_id != INT_MAX, // 2^31 diff --git a/include/contractor/query_edge.hpp b/include/contractor/query_edge.hpp index a1d24f861..74d38e79e 100644 --- a/include/contractor/query_edge.hpp +++ b/include/contractor/query_edge.hpp @@ -17,7 +17,8 @@ struct QueryEdge struct EdgeData { explicit EdgeData() - : turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false) + : turn_id(0), shortcut(false), weight(0), duration(0), forward(false), backward(false), + distance(0) { } @@ -25,10 +26,11 @@ struct QueryEdge const bool shortcut, const EdgeWeight weight, const EdgeWeight duration, + const EdgeDistance distance, const bool forward, const bool backward) : turn_id(turn_id), shortcut(shortcut), weight(weight), duration(duration), - forward(forward), backward(backward) + forward(forward), backward(backward), distance(distance) { } @@ -40,6 +42,7 @@ struct QueryEdge turn_id = other.id; forward = other.forward; backward = other.backward; + distance = other.distance; } // this ID is either the middle node of the shortcut, or the ID of the edge based node (node // based edge) storing the appropriate data. If `shortcut` is set to true, we get the middle @@ -50,6 +53,7 @@ struct QueryEdge EdgeWeight duration : 30; std::uint32_t forward : 1; std::uint32_t backward : 1; + EdgeDistance distance; } data; QueryEdge() : source(SPECIAL_NODEID), target(SPECIAL_NODEID) {} @@ -69,7 +73,8 @@ struct QueryEdge return (source == right.source && target == right.target && data.weight == right.data.weight && data.duration == right.data.duration && data.shortcut == right.data.shortcut && data.forward == right.data.forward && - data.backward == right.data.backward && data.turn_id == right.data.turn_id); + data.backward == right.data.backward && data.turn_id == right.data.turn_id && + data.distance == right.data.distance); } }; } diff --git a/include/customizer/cell_customizer.hpp b/include/customizer/cell_customizer.hpp index 01e65e582..df5499579 100644 --- a/include/customizer/cell_customizer.hpp +++ b/include/customizer/cell_customizer.hpp @@ -22,6 +22,7 @@ class CellCustomizer { bool from_clique; EdgeDuration duration; + EdgeDistance distance; }; public: @@ -60,7 +61,7 @@ class CellCustomizer } } heap.Clear(); - heap.Insert(source, 0, {false, 0}); + heap.Insert(source, 0, {false, 0, 0}); // explore search space while (!heap.Empty() && !destinations_set.empty()) @@ -68,8 +69,18 @@ class CellCustomizer const NodeID node = heap.DeleteMin(); const EdgeWeight weight = heap.GetKey(node); const EdgeDuration duration = heap.GetData(node).duration; + const EdgeDistance distance = heap.GetData(node).distance; - RelaxNode(graph, cells, allowed_nodes, metric, heap, level, node, weight, duration); + RelaxNode(graph, + cells, + allowed_nodes, + metric, + heap, + level, + node, + weight, + duration, + distance); destinations_set.erase(node); } @@ -77,21 +88,27 @@ class CellCustomizer // fill a map of destination nodes to placeholder pointers auto weights = cell.GetOutWeight(source); auto durations = cell.GetOutDuration(source); + auto distances = cell.GetOutDistance(source); for (auto &destination : destinations) { BOOST_ASSERT(!weights.empty()); BOOST_ASSERT(!durations.empty()); + BOOST_ASSERT(!distances.empty()); const bool inserted = heap.WasInserted(destination); weights.front() = inserted ? heap.GetKey(destination) : INVALID_EDGE_WEIGHT; durations.front() = inserted ? heap.GetData(destination).duration : MAXIMAL_EDGE_DURATION; + distances.front() = + inserted ? heap.GetData(destination).distance : INVALID_EDGE_DISTANCE; weights.advance_begin(1); durations.advance_begin(1); + distances.advance_begin(1); } BOOST_ASSERT(weights.empty()); BOOST_ASSERT(durations.empty()); + BOOST_ASSERT(distances.empty()); } } @@ -128,7 +145,8 @@ class CellCustomizer LevelID level, NodeID node, EdgeWeight weight, - EdgeDuration duration) const + EdgeDuration duration, + EdgeDistance distance) const { auto first_level = level == 1; BOOST_ASSERT(heap.WasInserted(node)); @@ -149,6 +167,7 @@ class CellCustomizer auto subcell = cells.GetCell(metric, level - 1, subcell_id); auto subcell_destination = subcell.GetDestinationNodes().begin(); auto subcell_duration = subcell.GetOutDuration(node).begin(); + auto subcell_distance = subcell.GetOutDistance(node).begin(); for (auto subcell_weight : subcell.GetOutWeight(node)) { if (subcell_weight != INVALID_EDGE_WEIGHT) @@ -161,20 +180,24 @@ class CellCustomizer const EdgeWeight to_weight = weight + subcell_weight; const EdgeDuration to_duration = duration + *subcell_duration; + const EdgeDistance to_distance = distance + *subcell_distance; if (!heap.WasInserted(to)) { - heap.Insert(to, to_weight, {true, to_duration}); + heap.Insert(to, to_weight, {true, to_duration, to_distance}); } - else if (std::tie(to_weight, to_duration) < - std::tie(heap.GetKey(to), heap.GetData(to).duration)) + else if (std::tie(to_weight, to_duration, to_distance) < + std::tie(heap.GetKey(to), + heap.GetData(to).duration, + heap.GetData(to).distance)) { heap.DecreaseKey(to, to_weight); - heap.GetData(to) = {true, to_duration}; + heap.GetData(to) = {true, to_duration, to_distance}; } } ++subcell_destination; ++subcell_duration; + ++subcell_distance; } } } @@ -195,15 +218,18 @@ class CellCustomizer { const EdgeWeight to_weight = weight + data.weight; const EdgeDuration to_duration = duration + data.duration; + const EdgeDistance to_distance = distance + data.distance; if (!heap.WasInserted(to)) { - heap.Insert(to, to_weight, {false, duration + data.duration}); + heap.Insert( + to, to_weight, {false, duration + data.duration, distance + data.distance}); } - else if (std::tie(to_weight, to_duration) < - std::tie(heap.GetKey(to), heap.GetData(to).duration)) + else if (std::tie(to_weight, to_duration, to_distance) < + std::tie( + heap.GetKey(to), heap.GetData(to).duration, heap.GetData(to).distance)) { heap.DecreaseKey(to, to_weight); - heap.GetData(to) = {false, to_duration}; + heap.GetData(to) = {false, to_duration, to_distance}; } } } diff --git a/include/customizer/cell_metric.hpp b/include/customizer/cell_metric.hpp index 530a18559..7674174fe 100644 --- a/include/customizer/cell_metric.hpp +++ b/include/customizer/cell_metric.hpp @@ -20,6 +20,7 @@ template struct CellMetricImpl Vector weights; Vector durations; + Vector distances; }; } diff --git a/include/customizer/edge_based_graph.hpp b/include/customizer/edge_based_graph.hpp index 8414c5942..840a84299 100644 --- a/include/customizer/edge_based_graph.hpp +++ b/include/customizer/edge_based_graph.hpp @@ -58,8 +58,10 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph node_weights_, - Vector node_durations_) - : node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)) + Vector node_durations_, + Vector node_distances_) + : node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)), + node_distances(std::move(node_distances_)) { util::ViewOrVector original_edge_array; @@ -83,11 +85,13 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph node_to_edge_offset_, Vector node_weights_, Vector node_durations_, + Vector node_distances_, Vector is_forward_edge_, Vector is_backward_edge_) : SuperT(std::move(node_array_), std::move(edge_array_), std::move(node_to_edge_offset_)), node_weights(std::move(node_weights_)), node_durations(std::move(node_durations_)), - is_forward_edge(is_forward_edge_), is_backward_edge(is_backward_edge_) + node_distances(std::move(node_distances_)), is_forward_edge(is_forward_edge_), + is_backward_edge(is_backward_edge_) { } @@ -95,6 +99,8 @@ class MultiLevelGraph : public partitioner::MultiLevelGraph node_weights; Vector node_durations; + Vector node_distances; Vector is_forward_edge; Vector is_backward_edge; }; diff --git a/include/customizer/serialization.hpp b/include/customizer/serialization.hpp index c5c5fdee2..afe23cf9b 100644 --- a/include/customizer/serialization.hpp +++ b/include/customizer/serialization.hpp @@ -23,6 +23,7 @@ inline void read(storage::tar::FileReader &reader, { storage::serialization::read(reader, name + "/weights", metric.weights); storage::serialization::read(reader, name + "/durations", metric.durations); + storage::serialization::read(reader, name + "/distances", metric.distances); } template @@ -32,6 +33,7 @@ inline void write(storage::tar::FileWriter &writer, { storage::serialization::write(writer, name + "/weights", metric.weights); storage::serialization::write(writer, name + "/durations", metric.durations); + storage::serialization::write(writer, name + "/distances", metric.distances); } template @@ -42,6 +44,7 @@ inline void read(storage::tar::FileReader &reader, storage::serialization::read(reader, name + "/node_array", graph.node_array); storage::serialization::read(reader, name + "/node_weights", graph.node_weights); storage::serialization::read(reader, name + "/node_durations", graph.node_durations); + storage::serialization::read(reader, name + "/node_distances", graph.node_distances); storage::serialization::read(reader, name + "/edge_array", graph.edge_array); storage::serialization::read(reader, name + "/is_forward_edge", graph.is_forward_edge); storage::serialization::read(reader, name + "/is_backward_edge", graph.is_backward_edge); @@ -56,6 +59,7 @@ inline void write(storage::tar::FileWriter &writer, storage::serialization::write(writer, name + "/node_array", graph.node_array); storage::serialization::write(writer, name + "/node_weights", graph.node_weights); storage::serialization::write(writer, name + "/node_durations", graph.node_durations); + storage::serialization::write(writer, name + "/node_distances", graph.node_distances); storage::serialization::write(writer, name + "/edge_array", graph.edge_array); storage::serialization::write(writer, name + "/is_forward_edge", graph.is_forward_edge); storage::serialization::write(writer, name + "/is_backward_edge", graph.is_backward_edge); diff --git a/include/engine/datafacade/algorithm_datafacade.hpp b/include/engine/datafacade/algorithm_datafacade.hpp index ef910d4ac..a83a5340c 100644 --- a/include/engine/datafacade/algorithm_datafacade.hpp +++ b/include/engine/datafacade/algorithm_datafacade.hpp @@ -78,6 +78,8 @@ template <> class AlgorithmDataFacade virtual EdgeWeight GetNodeDuration(const NodeID node) const = 0; // TODO: to be removed + virtual EdgeDistance GetNodeDistance(const NodeID node) const = 0; + virtual bool IsForwardEdge(EdgeID edge) const = 0; virtual bool IsBackwardEdge(EdgeID edge) const = 0; diff --git a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp index 6befce6d0..936d40f99 100644 --- a/include/engine/datafacade/contiguous_internalmem_datafacade.hpp +++ b/include/engine/datafacade/contiguous_internalmem_datafacade.hpp @@ -697,6 +697,11 @@ template <> class ContiguousInternalMemoryAlgorithmDataFacade : public Algo return query_graph.GetNodeDuration(node); } + EdgeDistance GetNodeDistance(const NodeID node) const override final + { + return query_graph.GetNodeDistance(node); + } + bool IsForwardEdge(const NodeID node) const override final { return query_graph.IsForwardEdge(node); diff --git a/include/engine/routing_algorithms/many_to_many.hpp b/include/engine/routing_algorithms/many_to_many.hpp index 281844abd..23c8902df 100644 --- a/include/engine/routing_algorithms/many_to_many.hpp +++ b/include/engine/routing_algorithms/many_to_many.hpp @@ -25,15 +25,17 @@ struct NodeBucket unsigned from_clique_arc : 1; EdgeWeight weight; EdgeDuration duration; + EdgeDistance distance; NodeBucket(NodeID middle_node, NodeID parent_node, bool from_clique_arc, unsigned column_index, EdgeWeight weight, - EdgeDuration duration) + EdgeDuration duration, + EdgeDistance distance) : middle_node(middle_node), parent_node(parent_node), column_index(column_index), - from_clique_arc(from_clique_arc), weight(weight), duration(duration) + from_clique_arc(from_clique_arc), weight(weight), duration(duration), distance(distance) { } @@ -41,9 +43,10 @@ struct NodeBucket NodeID parent_node, unsigned column_index, EdgeWeight weight, - EdgeDuration duration) + EdgeDuration duration, + EdgeDistance distance) : middle_node(middle_node), parent_node(parent_node), column_index(column_index), - from_clique_arc(false), weight(weight), duration(duration) + from_clique_arc(false), weight(weight), duration(duration), distance(distance) { } diff --git a/include/engine/routing_algorithms/routing_base.hpp b/include/engine/routing_algorithms/routing_base.hpp index 0c0808a3f..4afaae71f 100644 --- a/include/engine/routing_algorithms/routing_base.hpp +++ b/include/engine/routing_algorithms/routing_base.hpp @@ -85,13 +85,17 @@ void insertSourceInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no { heap.Insert(phantom_node.forward_segment_id.id, -phantom_node.GetForwardWeightPlusOffset(), - {phantom_node.forward_segment_id.id, -phantom_node.GetForwardDuration()}); + {phantom_node.forward_segment_id.id, + -phantom_node.GetForwardDuration(), + -phantom_node.GetForwardDistance()}); } if (phantom_node.IsValidReverseSource()) { heap.Insert(phantom_node.reverse_segment_id.id, -phantom_node.GetReverseWeightPlusOffset(), - {phantom_node.reverse_segment_id.id, -phantom_node.GetReverseDuration()}); + {phantom_node.reverse_segment_id.id, + -phantom_node.GetReverseDuration(), + -phantom_node.GetReverseDistance()}); } } @@ -102,13 +106,17 @@ void insertTargetInHeap(ManyToManyQueryHeap &heap, const PhantomNode &phantom_no { heap.Insert(phantom_node.forward_segment_id.id, phantom_node.GetForwardWeightPlusOffset(), - {phantom_node.forward_segment_id.id, phantom_node.GetForwardDuration()}); + {phantom_node.forward_segment_id.id, + phantom_node.GetForwardDuration(), + phantom_node.GetForwardDistance()}); } if (phantom_node.IsValidReverseTarget()) { heap.Insert(phantom_node.reverse_segment_id.id, phantom_node.GetReverseWeightPlusOffset(), - {phantom_node.reverse_segment_id.id, phantom_node.GetReverseDuration()}); + {phantom_node.reverse_segment_id.id, + phantom_node.GetReverseDuration(), + phantom_node.GetReverseDistance()}); } } diff --git a/include/engine/routing_algorithms/routing_base_ch.hpp b/include/engine/routing_algorithms/routing_base_ch.hpp index 051b5f8c4..79044c8d6 100644 --- a/include/engine/routing_algorithms/routing_base_ch.hpp +++ b/include/engine/routing_algorithms/routing_base_ch.hpp @@ -186,9 +186,10 @@ void routingStep(const DataFacade &facade, } template -EdgeWeight getLoopWeight(const DataFacade &facade, NodeID node) +std::tuple getLoopWeight(const DataFacade &facade, NodeID node) { EdgeWeight loop_weight = UseDuration ? MAXIMAL_EDGE_DURATION : INVALID_EDGE_WEIGHT; + EdgeDistance loop_distance = MAXIMAL_EDGE_DISTANCE; for (auto edge : facade.GetAdjacentEdgeRange(node)) { const auto &data = facade.GetEdgeData(edge); @@ -198,11 +199,15 @@ EdgeWeight getLoopWeight(const DataFacade &facade, NodeID node) if (to == node) { const auto value = UseDuration ? data.duration : data.weight; - loop_weight = std::min(loop_weight, value); + if (value < loop_weight) + { + loop_weight = value; + loop_distance = data.distance; + } } } } - return loop_weight; + return std::make_tuple(loop_weight, loop_distance); } /** diff --git a/include/engine/routing_algorithms/routing_base_mld.hpp b/include/engine/routing_algorithms/routing_base_mld.hpp index ce9b23d70..c3462039c 100644 --- a/include/engine/routing_algorithms/routing_base_mld.hpp +++ b/include/engine/routing_algorithms/routing_base_mld.hpp @@ -509,90 +509,6 @@ UnpackedPath search(SearchEngineData &engine_working_data, return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges)); } -// With (s, middle, t) we trace back the paths middle -> s and middle -> t. -// This gives us a packed path (node ids) from the base graph around s and t, -// and overlay node ids otherwise. We then have to unpack the overlay clique -// edges by recursively descending unpacking the path down to the base graph. - -using UnpackedNodes = std::vector; -using UnpackedEdges = std::vector; -using UnpackedPath = std::tuple; - -template -UnpackedPath -unpackPathAndCalculateDistance(SearchEngineData &engine_working_data, - const DataFacade &facade, - typename SearchEngineData::QueryHeap &forward_heap, - typename SearchEngineData::QueryHeap &reverse_heap, - const bool force_loop_forward, - const bool force_loop_reverse, - EdgeWeight weight_upper_bound, - PackedPath packed_path, - NodeID middle, - Args... args) -{ - EdgeWeight weight = weight_upper_bound; - const auto &partition = facade.GetMultiLevelPartition(); - const NodeID source_node = !packed_path.empty() ? std::get<0>(packed_path.front()) : middle; - - // Unpack path - std::vector unpacked_nodes; - std::vector unpacked_edges; - unpacked_nodes.reserve(packed_path.size()); - unpacked_edges.reserve(packed_path.size()); - - unpacked_nodes.push_back(source_node); - - for (auto const &packed_edge : packed_path) - { - NodeID source, target; - bool overlay_edge; - std::tie(source, target, overlay_edge) = packed_edge; - if (!overlay_edge) - { // a base graph edge - unpacked_nodes.push_back(target); - unpacked_edges.push_back(facade.FindEdge(source, target)); - } - else - { // an overlay graph edge - LevelID level = getNodeQueryLevel(partition, source, args...); - CellID parent_cell_id = partition.GetCell(level, source); - BOOST_ASSERT(parent_cell_id == partition.GetCell(level, target)); - - LevelID sublevel = level - 1; - - // Here heaps can be reused, let's go deeper! - forward_heap.Clear(); - reverse_heap.Clear(); - forward_heap.Insert(source, 0, {source}); - reverse_heap.Insert(target, 0, {target}); - - // TODO: when structured bindings will be allowed change to - // auto [subpath_weight, subpath_source, subpath_target, subpath] = ... - EdgeWeight subpath_weight; - std::vector subpath_nodes; - std::vector subpath_edges; - std::tie(subpath_weight, subpath_nodes, subpath_edges) = search(engine_working_data, - facade, - forward_heap, - reverse_heap, - force_loop_forward, - force_loop_reverse, - weight_upper_bound, - sublevel, - parent_cell_id); - BOOST_ASSERT(!subpath_edges.empty()); - BOOST_ASSERT(subpath_nodes.size() > 1); - BOOST_ASSERT(subpath_nodes.front() == source); - BOOST_ASSERT(subpath_nodes.back() == target); - unpacked_nodes.insert( - unpacked_nodes.end(), std::next(subpath_nodes.begin()), subpath_nodes.end()); - unpacked_edges.insert(unpacked_edges.end(), subpath_edges.begin(), subpath_edges.end()); - } - } - return std::make_tuple(weight, std::move(unpacked_nodes), std::move(unpacked_edges)); -} - // Alias to be compatible with the CH-based search template inline void search(SearchEngineData &engine_working_data, diff --git a/include/engine/search_engine_data.hpp b/include/engine/search_engine_data.hpp index db2c51224..353076162 100644 --- a/include/engine/search_engine_data.hpp +++ b/include/engine/search_engine_data.hpp @@ -30,7 +30,11 @@ struct HeapData struct ManyToManyHeapData : HeapData { EdgeWeight duration; - ManyToManyHeapData(NodeID p, EdgeWeight duration) : HeapData(p), duration(duration) {} + EdgeDistance distance; + ManyToManyHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance) + : HeapData(p), duration(duration), distance(distance) + { + } }; template <> struct SearchEngineData @@ -75,12 +79,16 @@ struct MultiLayerDijkstraHeapData struct ManyToManyMultiLayerDijkstraHeapData : MultiLayerDijkstraHeapData { EdgeWeight duration; - ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration) - : MultiLayerDijkstraHeapData(p), duration(duration) + EdgeDistance distance; + ManyToManyMultiLayerDijkstraHeapData(NodeID p, EdgeWeight duration, EdgeDistance distance) + : MultiLayerDijkstraHeapData(p), duration(duration), distance(distance) { } - ManyToManyMultiLayerDijkstraHeapData(NodeID p, bool from, EdgeWeight duration) - : MultiLayerDijkstraHeapData(p, from), duration(duration) + ManyToManyMultiLayerDijkstraHeapData(NodeID p, + bool from, + EdgeWeight duration, + EdgeDistance distance) + : MultiLayerDijkstraHeapData(p, from), duration(duration), distance(distance) { } }; diff --git a/include/extractor/edge_based_edge.hpp b/include/extractor/edge_based_edge.hpp index 1a58fc2b7..28ebf934a 100644 --- a/include/extractor/edge_based_edge.hpp +++ b/include/extractor/edge_based_edge.hpp @@ -15,20 +15,25 @@ struct EdgeBasedEdge public: struct EdgeData { - EdgeData() : turn_id(0), weight(0), duration(0), forward(false), backward(false) {} + EdgeData() + : turn_id(0), weight(0), distance(0), duration(0), forward(false), backward(false) + { + } EdgeData(const NodeID turn_id, const EdgeWeight weight, + const EdgeDistance distance, const EdgeWeight duration, const bool forward, const bool backward) - : turn_id(turn_id), weight(weight), duration(duration), forward(forward), - backward(backward) + : turn_id(turn_id), weight(weight), distance(distance), duration(duration), + forward(forward), backward(backward) { } NodeID turn_id; // ID of the edge based node (node based edge) EdgeWeight weight; + EdgeDistance distance; EdgeWeight duration : 30; std::uint32_t forward : 1; std::uint32_t backward : 1; @@ -43,6 +48,7 @@ struct EdgeBasedEdge const NodeID edge_id, const EdgeWeight weight, const EdgeWeight duration, + const EdgeDistance distance, const bool forward, const bool backward); EdgeBasedEdge(const NodeID source, const NodeID target, const EdgeBasedEdge::EdgeData &data); @@ -53,7 +59,7 @@ struct EdgeBasedEdge NodeID target; EdgeData data; }; -static_assert(sizeof(extractor::EdgeBasedEdge) == 20, +static_assert(sizeof(extractor::EdgeBasedEdge) == 24, "Size of extractor::EdgeBasedEdge type is " "bigger than expected. This will influence " "memory consumption."); @@ -67,9 +73,10 @@ inline EdgeBasedEdge::EdgeBasedEdge(const NodeID source, const NodeID turn_id, const EdgeWeight weight, const EdgeWeight duration, + const EdgeDistance distance, const bool forward, const bool backward) - : source(source), target(target), data{turn_id, weight, duration, forward, backward} + : source(source), target(target), data{turn_id, weight, distance, duration, forward, backward} { } diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index d8e8aeedc..388e0d75e 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -92,6 +92,7 @@ class EdgeBasedGraphFactory void GetStartPointMarkers(std::vector &node_is_startpoint); void GetEdgeBasedNodeWeights(std::vector &output_node_weights); void GetEdgeBasedNodeDurations(std::vector &output_node_durations); + void GetEdgeBasedNodeDistances(std::vector &output_node_distances); std::uint32_t GetConnectivityChecksum() const; std::uint64_t GetNumberOfEdgeBasedNodes() const; @@ -119,6 +120,7 @@ class EdgeBasedGraphFactory //! edge-based node std::vector m_edge_based_node_weights; std::vector m_edge_based_node_durations; + std::vector m_edge_based_node_distances; //! list of edge based nodes (compressed segments) std::vector m_edge_based_node_segments; diff --git a/include/extractor/extractor.hpp b/include/extractor/extractor.hpp index 31b157658..db571475b 100644 --- a/include/extractor/extractor.hpp +++ b/include/extractor/extractor.hpp @@ -88,6 +88,7 @@ class Extractor std::vector &node_is_startpoint, std::vector &edge_based_node_weights, std::vector &edge_based_node_durations, + std::vector &edge_based_node_distances, util::DeallocatingVector &edge_based_edge_list, std::uint32_t &connectivity_checksum); diff --git a/include/extractor/files.hpp b/include/extractor/files.hpp index 91f98825a..0807e5c56 100644 --- a/include/extractor/files.hpp +++ b/include/extractor/files.hpp @@ -453,8 +453,8 @@ void writeNames(const boost::filesystem::path &path, const NameTableT &table) serialization::write(writer, "/common/names", table); } -template -void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVectorT &weights) +template +void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeightsVectorT &weights) { const auto fingerprint = storage::tar::FileReader::VerifyFingerprint; storage::tar::FileReader reader{path, fingerprint}; @@ -462,9 +462,33 @@ void readEdgeBasedNodeWeights(const boost::filesystem::path &path, NodeWeigtsVec storage::serialization::read(reader, "/extractor/edge_based_node_weights", weights); } -template +template +void readEdgeBasedNodeDistances(const boost::filesystem::path &path, + NodeDistancesVectorT &distances) +{ + const auto fingerprint = storage::tar::FileReader::VerifyFingerprint; + storage::tar::FileReader reader{path, fingerprint}; + + storage::serialization::read(reader, "/extractor/edge_based_node_distances", distances); +} + +template +void writeEdgeBasedNodeWeightsDurationsDistances(const boost::filesystem::path &path, + const NodeWeightsVectorT &weights, + const NodeDurationsVectorT &durations, + const NodeDistancesVectorT &distances) +{ + const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint; + storage::tar::FileWriter writer{path, fingerprint}; + + storage::serialization::write(writer, "/extractor/edge_based_node_weights", weights); + storage::serialization::write(writer, "/extractor/edge_based_node_durations", durations); + storage::serialization::write(writer, "/extractor/edge_based_node_distances", distances); +} + +template void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path, - NodeWeigtsVectorT &weights, + NodeWeightsVectorT &weights, NodeDurationsVectorT &durations) { const auto fingerprint = storage::tar::FileReader::VerifyFingerprint; @@ -474,9 +498,9 @@ void readEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path, storage::serialization::read(reader, "/extractor/edge_based_node_durations", durations); } -template +template void writeEdgeBasedNodeWeightsDurations(const boost::filesystem::path &path, - const NodeWeigtsVectorT &weights, + const NodeWeightsVectorT &weights, const NodeDurationsVectorT &durations) { const auto fingerprint = storage::tar::FileWriter::GenerateFingerprint; diff --git a/include/extractor/internal_extractor_edge.hpp b/include/extractor/internal_extractor_edge.hpp index ef296b4f9..7ba4a9bf2 100644 --- a/include/extractor/internal_extractor_edge.hpp +++ b/include/extractor/internal_extractor_edge.hpp @@ -63,7 +63,7 @@ struct InternalExtractorEdge WeightData weight_data, DurationData duration_data, util::Coordinate source_coordinate) - : result(source, target, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)), + : result(source, target, 0, 0, 0, {}, -1, {}), weight_data(std::move(weight_data)), duration_data(std::move(duration_data)), source_coordinate(std::move(source_coordinate)) { } diff --git a/include/extractor/node_based_edge.hpp b/include/extractor/node_based_edge.hpp index 6ac0d0343..5abcd08d3 100644 --- a/include/extractor/node_based_edge.hpp +++ b/include/extractor/node_based_edge.hpp @@ -97,6 +97,7 @@ struct NodeBasedEdge NodeID target, EdgeWeight weight, EdgeDuration duration, + EdgeDistance distance, GeometryID geometry_id, AnnotationID annotation_data, NodeBasedEdgeClassification flags); @@ -107,6 +108,7 @@ struct NodeBasedEdge NodeID target; // 32 4 EdgeWeight weight; // 32 4 EdgeDuration duration; // 32 4 + EdgeDistance distance; // 32 4 GeometryID geometry_id; // 32 4 AnnotationID annotation_data; // 32 4 NodeBasedEdgeClassification flags; // 32 4 @@ -120,6 +122,7 @@ struct NodeBasedEdgeWithOSM : NodeBasedEdge OSMNodeID target, EdgeWeight weight, EdgeDuration duration, + EdgeDistance distance, GeometryID geometry_id, AnnotationID annotation_data, NodeBasedEdgeClassification flags); @@ -137,7 +140,8 @@ inline NodeBasedEdgeClassification::NodeBasedEdgeClassification() } inline NodeBasedEdge::NodeBasedEdge() - : source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), annotation_data(-1) + : source(SPECIAL_NODEID), target(SPECIAL_NODEID), weight(0), duration(0), distance(0), + annotation_data(-1) { } @@ -145,11 +149,12 @@ inline NodeBasedEdge::NodeBasedEdge(NodeID source, NodeID target, EdgeWeight weight, EdgeDuration duration, + EdgeDistance distance, GeometryID geometry_id, AnnotationID annotation_data, NodeBasedEdgeClassification flags) - : source(source), target(target), weight(weight), duration(duration), geometry_id(geometry_id), - annotation_data(annotation_data), flags(flags) + : source(source), target(target), weight(weight), duration(duration), distance(distance), + geometry_id(geometry_id), annotation_data(annotation_data), flags(flags) { } @@ -175,11 +180,18 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM(OSMNodeID source, OSMNodeID target, EdgeWeight weight, EdgeDuration duration, + EdgeDistance distance, GeometryID geometry_id, AnnotationID annotation_data, NodeBasedEdgeClassification flags) - : NodeBasedEdge( - SPECIAL_NODEID, SPECIAL_NODEID, weight, duration, geometry_id, annotation_data, flags), + : NodeBasedEdge(SPECIAL_NODEID, + SPECIAL_NODEID, + weight, + duration, + distance, + geometry_id, + annotation_data, + flags), osm_source_id(std::move(source)), osm_target_id(std::move(target)) { } @@ -189,7 +201,7 @@ inline NodeBasedEdgeWithOSM::NodeBasedEdgeWithOSM() { } -static_assert(sizeof(extractor::NodeBasedEdge) == 28, +static_assert(sizeof(extractor::NodeBasedEdge) == 32, "Size of extractor::NodeBasedEdge type is " "bigger than expected. This will influence " "memory consumption."); diff --git a/include/partitioner/cell_storage.hpp b/include/partitioner/cell_storage.hpp index b3ad7d7bc..b28393319 100644 --- a/include/partitioner/cell_storage.hpp +++ b/include/partitioner/cell_storage.hpp @@ -75,28 +75,35 @@ template class CellStorageImpl // Implementation of the cell view. We need a template parameter here // because we need to derive a read-only and read-write view from this. - template class CellImpl + template + class CellImpl { private: using WeightPtrT = WeightValueT *; using DurationPtrT = DurationValueT *; + using DistancePtrT = DistanceValueT *; BoundarySize num_source_nodes; BoundarySize num_destination_nodes; WeightPtrT const weights; DurationPtrT const durations; + DistancePtrT const distances; const NodeID *const source_boundary; const NodeID *const destination_boundary; using RowIterator = WeightPtrT; // Possibly replace with // http://www.boost.org/doc/libs/1_55_0/libs/range/doc/html/range/reference/adaptors/reference/strided.html - class ColumnIterator : public boost::iterator_facade + class ColumnIterator : public boost::iterator_facade, + decltype(*std::declval()), boost::random_access_traversal_tag> { - typedef boost::iterator_facade()); + typedef boost::iterator_facade, + ValueT, boost::random_access_traversal_tag> base_t; @@ -108,7 +115,7 @@ template class CellStorageImpl explicit ColumnIterator() : current(nullptr), stride(1) {} - explicit ColumnIterator(WeightPtrT begin, std::size_t row_length) + explicit ColumnIterator(ValuePtrT begin, std::size_t row_length) : current(begin), stride(row_length) { BOOST_ASSERT(begin != nullptr); @@ -126,7 +133,7 @@ template class CellStorageImpl } friend class ::boost::iterator_core_access; - WeightPtrT current; + ValuePtrT current; const std::size_t stride; }; @@ -147,12 +154,13 @@ template class CellStorageImpl auto iter = std::find(destination_boundary, destination_boundary + num_destination_nodes, node); if (iter == destination_boundary + num_destination_nodes) - return boost::make_iterator_range(ColumnIterator{}, ColumnIterator{}); + return boost::make_iterator_range(ColumnIterator{}, + ColumnIterator{}); auto column = std::distance(destination_boundary, iter); - auto begin = ColumnIterator{ptr + column, num_destination_nodes}; - auto end = ColumnIterator{ptr + column + num_source_nodes * num_destination_nodes, - num_destination_nodes}; + auto begin = ColumnIterator{ptr + column, num_destination_nodes}; + auto end = ColumnIterator{ + ptr + column + num_source_nodes * num_destination_nodes, num_destination_nodes}; return boost::make_iterator_range(begin, end); } @@ -165,6 +173,10 @@ template class CellStorageImpl auto GetInDuration(NodeID node) const { return GetInRange(durations, node); } + auto GetInDistance(NodeID node) const { return GetInRange(distances, node); } + + auto GetOutDistance(NodeID node) const { return GetOutRange(distances, node); } + auto GetSourceNodes() const { return boost::make_iterator_range(source_boundary, source_boundary + num_source_nodes); @@ -179,17 +191,20 @@ template class CellStorageImpl CellImpl(const CellData &data, WeightPtrT const all_weights, DurationPtrT const all_durations, + DistancePtrT const all_distances, const NodeID *const all_sources, const NodeID *const all_destinations) : num_source_nodes{data.num_source_nodes}, num_destination_nodes{data.num_destination_nodes}, weights{all_weights + data.value_offset}, durations{all_durations + data.value_offset}, + distances{all_distances + data.value_offset}, source_boundary{all_sources + data.source_boundary_offset}, destination_boundary{all_destinations + data.destination_boundary_offset} { BOOST_ASSERT(all_weights != nullptr); BOOST_ASSERT(all_durations != nullptr); + BOOST_ASSERT(all_distances != nullptr); BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr); BOOST_ASSERT(num_destination_nodes == 0 || all_destinations != nullptr); } @@ -201,7 +216,8 @@ template class CellStorageImpl const NodeID *const all_destinations) : num_source_nodes{data.num_source_nodes}, num_destination_nodes{data.num_destination_nodes}, weights{nullptr}, - durations{nullptr}, source_boundary{all_sources + data.source_boundary_offset}, + durations{nullptr}, distances{nullptr}, + source_boundary{all_sources + data.source_boundary_offset}, destination_boundary{all_destinations + data.destination_boundary_offset} { BOOST_ASSERT(num_source_nodes == 0 || all_sources != nullptr); @@ -212,8 +228,8 @@ template class CellStorageImpl std::size_t LevelIDToIndex(LevelID level) const { return level - 1; } public: - using Cell = CellImpl; - using ConstCell = CellImpl; + using Cell = CellImpl; + using ConstCell = CellImpl; CellStorageImpl() {} @@ -361,6 +377,7 @@ template class CellStorageImpl metric.weights.resize(total_size + 1, INVALID_EDGE_WEIGHT); metric.durations.resize(total_size + 1, MAXIMAL_EDGE_DURATION); + metric.distances.resize(total_size + 1, INVALID_EDGE_DISTANCE); return metric; } @@ -388,6 +405,7 @@ template class CellStorageImpl return ConstCell{cells[cell_index], metric.weights.data(), metric.durations.data(), + metric.distances.data(), source_boundary.empty() ? nullptr : source_boundary.data(), destination_boundary.empty() ? nullptr : destination_boundary.data()}; } @@ -415,6 +433,7 @@ template class CellStorageImpl return Cell{cells[cell_index], metric.weights.data(), metric.durations.data(), + metric.distances.data(), source_boundary.data(), destination_boundary.data()}; } diff --git a/include/partitioner/edge_based_graph_reader.hpp b/include/partitioner/edge_based_graph_reader.hpp index 9480112d0..bc5ba8b96 100644 --- a/include/partitioner/edge_based_graph_reader.hpp +++ b/include/partitioner/edge_based_graph_reader.hpp @@ -43,6 +43,7 @@ splitBidirectionalEdges(const std::vector &edges) edge.data.turn_id, std::max(edge.data.weight, 1), edge.data.duration, + edge.data.distance, edge.data.forward, edge.data.backward); @@ -51,6 +52,7 @@ splitBidirectionalEdges(const std::vector &edges) edge.data.turn_id, std::max(edge.data.weight, 1), edge.data.duration, + edge.data.distance, edge.data.backward, edge.data.forward); } diff --git a/include/storage/view_factory.hpp b/include/storage/view_factory.hpp index f6c8e2137..b04e3026e 100644 --- a/include/storage/view_factory.hpp +++ b/include/storage/view_factory.hpp @@ -294,11 +294,14 @@ inline auto make_filtered_cell_metric_view(const SharedDataIndex &index, auto prefix = name + "/exclude/" + std::to_string(exclude_index); auto weights_block_id = prefix + "/weights"; auto durations_block_id = prefix + "/durations"; + auto distances_block_id = prefix + "/distances"; auto weights = make_vector_view(index, weights_block_id); auto durations = make_vector_view(index, durations_block_id); + auto distances = make_vector_view(index, distances_block_id); - return customizer::CellMetricView{std::move(weights), std::move(durations)}; + return customizer::CellMetricView{ + std::move(weights), std::move(durations), std::move(distances)}; } inline auto make_cell_metric_view(const SharedDataIndex &index, const std::string &name) @@ -311,12 +314,14 @@ inline auto make_cell_metric_view(const SharedDataIndex &index, const std::strin { auto weights_block_id = prefix + "/weights"; auto durations_block_id = prefix + "/durations"; + auto distances_block_id = prefix + "/distances"; auto weights = make_vector_view(index, weights_block_id); auto durations = make_vector_view(index, durations_block_id); + auto distances = make_vector_view(index, distances_block_id); - cell_metric_excludes.push_back( - customizer::CellMetricView{std::move(weights), std::move(durations)}); + cell_metric_excludes.push_back(customizer::CellMetricView{ + std::move(weights), std::move(durations), std::move(distances)}); } return cell_metric_excludes; @@ -332,6 +337,7 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std: index, name + "/node_to_edge_offset"); auto node_weights = make_vector_view(index, name + "/node_weights"); auto node_durations = make_vector_view(index, name + "/node_durations"); + auto node_distances = make_vector_view(index, name + "/node_distances"); auto is_forward_edge = make_vector_view(index, name + "/is_forward_edge"); auto is_backward_edge = make_vector_view(index, name + "/is_backward_edge"); @@ -340,6 +346,7 @@ inline auto make_multi_level_graph_view(const SharedDataIndex &index, const std: std::move(node_to_offset), std::move(node_weights), std::move(node_durations), + std::move(node_distances), std::move(is_forward_edge), std::move(is_backward_edge)); } diff --git a/include/updater/updater.hpp b/include/updater/updater.hpp index dcaf5f638..565b293cb 100644 --- a/include/updater/updater.hpp +++ b/include/updater/updater.hpp @@ -22,11 +22,17 @@ class Updater std::vector &node_weights, std::uint32_t &connectivity_checksum) const; - EdgeID - LoadAndUpdateEdgeExpandedGraph(std::vector &edge_based_edge_list, - std::vector &node_weights, - std::vector &node_durations, // TODO: to be deleted - std::uint32_t &connectivity_checksum) const; + EdgeID LoadAndUpdateEdgeExpandedGraph( + std::vector &edge_based_edge_list, + std::vector &node_weights, + std::vector &node_durations, // TODO: remove when optional + std::uint32_t &connectivity_checksum) const; + EdgeID LoadAndUpdateEdgeExpandedGraph( + std::vector &edge_based_edge_list, + std::vector &node_weights, + std::vector &node_durations, // TODO: remove when optional + std::vector &node_distances, // TODO: remove when optional + std::uint32_t &connectivity_checksum) const; private: UpdaterConfig config; diff --git a/include/util/debug.hpp b/include/util/debug.hpp index 9c6582dad..001e31e82 100644 --- a/include/util/debug.hpp +++ b/include/util/debug.hpp @@ -1,9 +1,11 @@ #ifndef OSRM_UTIL_DEBUG_HPP_ #define OSRM_UTIL_DEBUG_HPP_ +#include "extractor/edge_based_edge.hpp" #include "extractor/node_data_container.hpp" #include "extractor/query_node.hpp" #include "guidance/intersection.hpp" +#include "guidance/turn_instruction.hpp" #include "guidance/turn_lane_data.hpp" #include "engine/guidance/route_step.hpp" #include "util/node_based_graph.hpp" @@ -186,6 +188,23 @@ inline std::ostream &operator<<(std::ostream &out, const LaneDataVector &turn_la } } } + +namespace extractor +{ +inline std::ostream &operator<<(std::ostream &out, const EdgeBasedEdge &edge) +{ + out << " EdgeBasedEdge {"; + out << " source " << edge.source << ", target: " << edge.target; + out << " EdgeBasedEdgeData data {"; + out << " turn_id: " << edge.data.turn_id << ", weight: " << edge.data.weight; + out << " distance: " << edge.data.distance << ", duration: " << edge.data.duration; + out << " forward: " << (edge.data.forward == 0 ? "false" : "true") + << ", backward: " << (edge.data.backward == 0 ? "false" : "true"); + out << " }"; + out << "}"; + return out; +} +} } #endif /*OSRM_ENGINE_GUIDANCE_DEBUG_HPP_*/ diff --git a/include/util/node_based_graph.hpp b/include/util/node_based_graph.hpp index 587bb8ab4..1c31f8f7d 100644 --- a/include/util/node_based_graph.hpp +++ b/include/util/node_based_graph.hpp @@ -9,6 +9,7 @@ #include +#include #include #include @@ -20,24 +21,27 @@ namespace util struct NodeBasedEdgeData { NodeBasedEdgeData() - : weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), geometry_id({0, false}), - reversed(false), annotation_data(-1) + : weight(INVALID_EDGE_WEIGHT), duration(INVALID_EDGE_WEIGHT), + distance(INVALID_EDGE_DISTANCE), geometry_id({0, false}), reversed(false), + annotation_data(-1) { } NodeBasedEdgeData(EdgeWeight weight, EdgeWeight duration, + EdgeDistance distance, GeometryID geometry_id, bool reversed, extractor::NodeBasedEdgeClassification flags, AnnotationID annotation_data) - : weight(weight), duration(duration), geometry_id(geometry_id), reversed(reversed), - flags(flags), annotation_data(annotation_data) + : weight(weight), duration(duration), distance(distance), geometry_id(geometry_id), + reversed(reversed), flags(flags), annotation_data(annotation_data) { } EdgeWeight weight; EdgeWeight duration; + EdgeDistance distance; GeometryID geometry_id; bool reversed : 1; extractor::NodeBasedEdgeClassification flags; @@ -80,11 +84,13 @@ NodeBasedDynamicGraphFromEdges(NodeID number_of_nodes, const extractor::NodeBasedEdge &input_edge) { output_edge.data.weight = input_edge.weight; output_edge.data.duration = input_edge.duration; + output_edge.data.distance = input_edge.distance; output_edge.data.flags = input_edge.flags; output_edge.data.annotation_data = input_edge.annotation_data; BOOST_ASSERT(output_edge.data.weight > 0); BOOST_ASSERT(output_edge.data.duration > 0); + BOOST_ASSERT(output_edge.data.distance >= 0); }); tbb::parallel_sort(edges_list.begin(), edges_list.end()); diff --git a/include/util/typedefs.hpp b/include/util/typedefs.hpp index f0104e7b2..afe8350b4 100644 --- a/include/util/typedefs.hpp +++ b/include/util/typedefs.hpp @@ -113,6 +113,7 @@ static const SegmentWeight MAX_SEGMENT_WEIGHT = INVALID_SEGMENT_WEIGHT - 1; static const SegmentDuration MAX_SEGMENT_DURATION = INVALID_SEGMENT_DURATION - 1; static const EdgeWeight INVALID_EDGE_WEIGHT = std::numeric_limits::max(); static const EdgeDuration MAXIMAL_EDGE_DURATION = std::numeric_limits::max(); +static const EdgeDistance MAXIMAL_EDGE_DISTANCE = std::numeric_limits::max(); static const TurnPenalty INVALID_TURN_PENALTY = std::numeric_limits::max(); static const EdgeDistance INVALID_EDGE_DISTANCE = std::numeric_limits::max(); diff --git a/src/contractor/graph_contractor.cpp b/src/contractor/graph_contractor.cpp index 221e629e9..8615156dd 100644 --- a/src/contractor/graph_contractor.cpp +++ b/src/contractor/graph_contractor.cpp @@ -215,6 +215,7 @@ void ContractNode(ContractorThreadData *data, target, path_weight, in_data.duration + out_data.duration, + in_data.distance + out_data.distance, out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC, @@ -225,6 +226,7 @@ void ContractNode(ContractorThreadData *data, source, path_weight, in_data.duration + out_data.duration, + in_data.distance + out_data.distance, out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC, @@ -280,6 +282,7 @@ void ContractNode(ContractorThreadData *data, target, path_weight, in_data.duration + out_data.duration, + in_data.distance + out_data.distance, out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC, @@ -290,6 +293,7 @@ void ContractNode(ContractorThreadData *data, source, path_weight, in_data.duration + out_data.duration, + in_data.distance + out_data.distance, out_data.originalEdges + in_data.originalEdges, node, SHORTCUT_ARC, diff --git a/src/customize/customizer.cpp b/src/customize/customizer.cpp index 2c4f57ab8..d7e2af90d 100644 --- a/src/customize/customizer.cpp +++ b/src/customize/customizer.cpp @@ -76,6 +76,7 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config, const partitioner::MultiLevelPartition &mlp, std::vector &node_weights, std::vector &node_durations, + std::vector &node_distances, std::uint32_t &connectivity_checksum) { updater::Updater updater(config.updater_config); @@ -84,6 +85,8 @@ auto LoadAndUpdateEdgeExpandedGraph(const CustomizationConfig &config, EdgeID num_nodes = updater.LoadAndUpdateEdgeExpandedGraph( edge_based_edge_list, node_weights, node_durations, connectivity_checksum); + extractor::files::readEdgeBasedNodeDistances(config.GetPath(".osrm.enw"), node_distances); + auto directed = partitioner::splitBidirectionalEdges(edge_based_edge_list); auto tidied = partitioner::prepareEdgesForUsageInGraph< @@ -124,10 +127,11 @@ int Customizer::Run(const CustomizationConfig &config) partitioner::files::readPartition(config.GetPath(".osrm.partition"), mlp); std::vector node_weights; - std::vector node_durations; // TODO: to be removed later + std::vector node_durations; // TODO: remove when durations are optional + std::vector node_distances; // TODO: remove when distances are optional std::uint32_t connectivity_checksum = 0; auto graph = LoadAndUpdateEdgeExpandedGraph( - config, mlp, node_weights, node_durations, connectivity_checksum); + config, mlp, node_weights, node_durations, node_distances, connectivity_checksum); BOOST_ASSERT(graph.GetNumberOfNodes() == node_weights.size()); std::for_each(node_weights.begin(), node_weights.end(), [](auto &w) { w &= 0x7fffffff; }); util::Log() << "Loaded edge based graph: " << graph.GetNumberOfEdges() << " edges, " @@ -166,8 +170,10 @@ int Customizer::Run(const CustomizationConfig &config) util::Log() << "MLD customization writing took " << TIMER_SEC(writing_mld_data) << " seconds"; TIMER_START(writing_graph); - MultiLevelEdgeBasedGraph shaved_graph{ - std::move(graph), std::move(node_weights), std::move(node_durations)}; + MultiLevelEdgeBasedGraph shaved_graph{std::move(graph), + std::move(node_weights), + std::move(node_durations), + std::move(node_distances)}; customizer::files::writeGraph( config.GetPath(".osrm.mldgr"), shaved_graph, connectivity_checksum); TIMER_STOP(writing_graph); diff --git a/src/engine/routing_algorithms/alternative_path_ch.cpp b/src/engine/routing_algorithms/alternative_path_ch.cpp index 0fafa2447..2efd6fe19 100644 --- a/src/engine/routing_algorithms/alternative_path_ch.cpp +++ b/src/engine/routing_algorithms/alternative_path_ch.cpp @@ -90,7 +90,7 @@ void alternativeRoutingStep(const DataFacade &facade, else { // check whether there is a loop present at the node - const auto loop_weight = getLoopWeight(facade, node); + const auto loop_weight = std::get<0>(getLoopWeight(facade, node)); const EdgeWeight new_weight_with_loop = new_weight + loop_weight; if (loop_weight != INVALID_EDGE_WEIGHT && new_weight_with_loop <= *upper_bound_to_shortest_path_weight) diff --git a/src/engine/routing_algorithms/many_to_many_ch.cpp b/src/engine/routing_algorithms/many_to_many_ch.cpp index 8ee02b5ec..1b8e90ca6 100644 --- a/src/engine/routing_algorithms/many_to_many_ch.cpp +++ b/src/engine/routing_algorithms/many_to_many_ch.cpp @@ -21,18 +21,21 @@ namespace ch inline bool addLoopWeight(const DataFacade &facade, const NodeID node, EdgeWeight &weight, - EdgeDuration &duration) + EdgeDuration &duration, + EdgeDistance &distance) { // Special case for CH when contractor creates a loop edge node->node BOOST_ASSERT(weight < 0); const auto loop_weight = ch::getLoopWeight(facade, node); - if (loop_weight != INVALID_EDGE_WEIGHT) + if (std::get<0>(loop_weight) != INVALID_EDGE_WEIGHT) { - const auto new_weight_with_loop = weight + loop_weight; + const auto new_weight_with_loop = weight + std::get<0>(loop_weight); if (new_weight_with_loop >= 0) { weight = new_weight_with_loop; - duration += ch::getLoopWeight(facade, node); + auto result = ch::getLoopWeight(facade, node); + duration += std::get<0>(result); + distance += std::get<1>(result); return true; } } @@ -46,6 +49,7 @@ void relaxOutgoingEdges(const DataFacade &facade, const NodeID node, const EdgeWeight weight, const EdgeDuration duration, + const EdgeDistance distance, typename SearchEngineData::ManyToManyQueryHeap &query_heap, const PhantomNode &) { @@ -63,21 +67,23 @@ void relaxOutgoingEdges(const DataFacade &facade, const auto edge_weight = data.weight; const auto edge_duration = data.duration; + const auto edge_distance = data.distance; BOOST_ASSERT_MSG(edge_weight > 0, "edge_weight invalid"); const auto to_weight = weight + edge_weight; const auto to_duration = duration + edge_duration; + const auto to_distance = distance + edge_distance; // New Node discovered -> Add to Heap + Node Info Storage if (!query_heap.WasInserted(to)) { - query_heap.Insert(to, to_weight, {node, to_duration}); + query_heap.Insert(to, to_weight, {node, to_duration, to_distance}); } // Found a shorter Path -> Update weight and set new parent else if (std::tie(to_weight, to_duration) < std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration)) { - query_heap.GetData(to) = {node, to_duration}; + query_heap.GetData(to) = {node, to_duration, to_distance}; query_heap.DecreaseKey(to, to_weight); } } @@ -91,12 +97,14 @@ void forwardRoutingStep(const DataFacade &facade, const std::vector &search_space_with_buckets, std::vector &weights_table, std::vector &durations_table, + std::vector &distances_table, std::vector &middle_nodes_table, const PhantomNode &phantom_node) { const auto node = query_heap.DeleteMin(); const auto source_weight = query_heap.GetKey(node); const auto source_duration = query_heap.GetData(node).duration; + const auto source_distance = query_heap.GetData(node).distance; // Check if each encountered node has an entry const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(), @@ -109,20 +117,24 @@ void forwardRoutingStep(const DataFacade &facade, const auto column_index = current_bucket.column_index; const auto target_weight = current_bucket.weight; const auto target_duration = current_bucket.duration; + const auto target_distance = current_bucket.distance; auto ¤t_weight = weights_table[row_index * number_of_targets + column_index]; auto ¤t_duration = durations_table[row_index * number_of_targets + column_index]; + auto ¤t_distance = distances_table[row_index * number_of_targets + column_index]; // Check if new weight is better auto new_weight = source_weight + target_weight; auto new_duration = source_duration + target_duration; + auto new_distance = source_distance + target_distance; if (new_weight < 0) { - if (addLoopWeight(facade, node, new_weight, new_duration)) + if (addLoopWeight(facade, node, new_weight, new_duration, new_distance)) { current_weight = std::min(current_weight, new_weight); current_duration = std::min(current_duration, new_duration); + current_distance = std::min(current_distance, new_distance); middle_nodes_table[row_index * number_of_targets + column_index] = node; } } @@ -130,12 +142,13 @@ void forwardRoutingStep(const DataFacade &facade, { current_weight = new_weight; current_duration = new_duration; + current_distance = new_distance; middle_nodes_table[row_index * number_of_targets + column_index] = node; } } relaxOutgoingEdges( - facade, node, source_weight, source_duration, query_heap, phantom_node); + facade, node, source_weight, source_duration, source_distance, query_heap, phantom_node); } void backwardRoutingStep(const DataFacade &facade, @@ -147,172 +160,19 @@ void backwardRoutingStep(const DataFacade &facade, const auto node = query_heap.DeleteMin(); const auto target_weight = query_heap.GetKey(node); const auto target_duration = query_heap.GetData(node).duration; + const auto target_distance = query_heap.GetData(node).distance; const auto parent = query_heap.GetData(node).parent; // Store settled nodes in search space bucket search_space_with_buckets.emplace_back( - node, parent, column_index, target_weight, target_duration); + node, parent, column_index, target_weight, target_duration, target_distance); relaxOutgoingEdges( - facade, node, target_weight, target_duration, query_heap, phantom_node); + facade, node, target_weight, target_duration, target_distance, query_heap, phantom_node); } } // namespace ch -void retrievePackedPathFromSearchSpace(const NodeID middle_node_id, - const unsigned column_index, - const std::vector &search_space_with_buckets, - std::vector &packed_leg) -{ - auto bucket_list = std::equal_range(search_space_with_buckets.begin(), - search_space_with_buckets.end(), - middle_node_id, - NodeBucket::ColumnCompare(column_index)); - - NodeID current_node_id = middle_node_id; - - BOOST_ASSERT_MSG(std::distance(bucket_list.first, bucket_list.second) == 1, - "The pointers are not pointing to the same element."); - - while (bucket_list.first->parent_node != current_node_id && - bucket_list.first != search_space_with_buckets.end()) - { - current_node_id = bucket_list.first->parent_node; - - packed_leg.emplace_back(current_node_id); - - bucket_list = std::equal_range(search_space_with_buckets.begin(), - search_space_with_buckets.end(), - current_node_id, - NodeBucket::ColumnCompare(column_index)); - } -} - -void calculateDistances(typename SearchEngineData::ManyToManyQueryHeap &query_heap, - const DataFacade &facade, - const std::vector &phantom_nodes, - const std::vector &target_indices, - const std::size_t row_index, - const std::size_t source_index, - const PhantomNode &source_phantom, - const std::size_t number_of_targets, - const std::vector &search_space_with_buckets, - std::vector &distances_table, - const std::vector &middle_nodes_table) -{ - std::vector packed_leg; - - for (auto column_index : util::irange(0, number_of_targets)) - { - const auto target_index = target_indices[column_index]; - const auto &target_phantom = phantom_nodes[target_index]; - - if (source_index == target_index) - { - distances_table[row_index * number_of_targets + column_index] = 0.0; - continue; - } - - NodeID middle_node_id = middle_nodes_table[row_index * number_of_targets + column_index]; - - if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways - { - distances_table[row_index * number_of_targets + column_index] = INVALID_EDGE_DISTANCE; - continue; - } - - // Step 1: Find path from source to middle node - ch::retrievePackedPathFromSingleManyToManyHeap(query_heap, middle_node_id, packed_leg); - std::reverse(packed_leg.begin(), packed_leg.end()); - - packed_leg.push_back(middle_node_id); - - // Step 2: Find path from middle to target node - retrievePackedPathFromSearchSpace( - middle_node_id, column_index, search_space_with_buckets, packed_leg); - - if (packed_leg.size() == 1 && (needsLoopForward(source_phantom, target_phantom) || - needsLoopBackwards(source_phantom, target_phantom))) - { - auto weight = ch::getLoopWeight(facade, packed_leg.front()); - if (weight != INVALID_EDGE_WEIGHT) - packed_leg.push_back(packed_leg.front()); - } - if (!packed_leg.empty()) - { - auto annotation = - ch::calculateEBGNodeAnnotations(facade, packed_leg.begin(), packed_leg.end()); - - distances_table[row_index * number_of_targets + column_index] = annotation; - - // check the direction of travel to figure out how to calculate the offset to/from - // the source/target - if (source_phantom.forward_segment_id.id == packed_leg.front()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // -->s <-- subtract offset to start at source - // ......... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = source_phantom.GetForwardDistance(); - distances_table[row_index * number_of_targets + column_index] -= offset; - } - else if (source_phantom.reverse_segment_id.id == packed_leg.front()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // s<------- <-- subtract offset to start at source - // ... <-- want this distance - // entry 0---1---2---3 <-- 3 is exit node - EdgeDistance offset = source_phantom.GetReverseDistance(); - distances_table[row_index * number_of_targets + column_index] -= offset; - } - if (target_phantom.forward_segment_id.id == packed_leg.back()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // ++>t <-- add offset to get to target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = target_phantom.GetForwardDistance(); - distances_table[row_index * number_of_targets + column_index] += offset; - } - else if (target_phantom.reverse_segment_id.id == packed_leg.back()) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // <++t <-- add offset to get from target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = target_phantom.GetReverseDistance(); - distances_table[row_index * number_of_targets + column_index] += offset; - } - } - else - { - // there is no shortcut to unpack. source and target are on the same EBG Node. - // if the offset of the target is greater than the offset of the source, subtract it - if (target_phantom.GetForwardDistance() > source_phantom.GetForwardDistance()) - { - // --------->t <-- offsets - // ->s <-- subtract source offset from target offset - // ......... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = - target_phantom.GetForwardDistance() - source_phantom.GetForwardDistance(); - distances_table[row_index * number_of_targets + column_index] = offset; - } - else - { - // s<--- <-- offsets - // t<--------- <-- subtract source offset from target offset - // ...... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - EdgeDistance offset = - target_phantom.GetReverseDistance() - source_phantom.GetReverseDistance(); - distances_table[row_index * number_of_targets + column_index] = offset; - } - } - packed_leg.clear(); - } -} - template <> std::pair, std::vector> manyToManySearch(SearchEngineData &engine_working_data, @@ -320,18 +180,16 @@ manyToManySearch(SearchEngineData &engine_working_data, const std::vector &phantom_nodes, const std::vector &source_indices, const std::vector &target_indices, - const bool calculate_distance, - const bool calculate_duration) + const bool /* calculate_distance */, + const bool /* calculate_duration */) { - (void)calculate_duration; // TODO: stub to use when computing durations become optional - const auto number_of_sources = source_indices.size(); const auto number_of_targets = target_indices.size(); const auto number_of_entries = number_of_sources * number_of_targets; std::vector weights_table(number_of_entries, INVALID_EDGE_WEIGHT); std::vector durations_table(number_of_entries, MAXIMAL_EDGE_DURATION); - std::vector distances_table; + std::vector distances_table(number_of_entries, MAXIMAL_EDGE_DISTANCE); std::vector middle_nodes_table(number_of_entries, SPECIAL_NODEID); std::vector search_space_with_buckets; @@ -380,25 +238,10 @@ manyToManySearch(SearchEngineData &engine_working_data, search_space_with_buckets, weights_table, durations_table, + distances_table, middle_nodes_table, source_phantom); } - - if (calculate_distance) - { - distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE); - calculateDistances(query_heap, - facade, - phantom_nodes, - target_indices, - row_index, - source_index, - source_phantom, - number_of_targets, - search_space_with_buckets, - distances_table, - middle_nodes_table); - } } return std::make_pair(durations_table, distances_table); diff --git a/src/engine/routing_algorithms/many_to_many_mld.cpp b/src/engine/routing_algorithms/many_to_many_mld.cpp index 91033abd7..b8521df9f 100644 --- a/src/engine/routing_algorithms/many_to_many_mld.cpp +++ b/src/engine/routing_algorithms/many_to_many_mld.cpp @@ -41,6 +41,7 @@ void relaxOutgoingEdges(const DataFacade &facade, const NodeID node, const EdgeWeight weight, const EdgeDuration duration, + const EdgeDistance distance, typename SearchEngineData::ManyToManyQueryHeap &query_heap, Args... args) { @@ -65,65 +66,77 @@ void relaxOutgoingEdges(const DataFacade &facade, { // Shortcuts in forward direction auto destination = cell.GetDestinationNodes().begin(); auto shortcut_durations = cell.GetOutDuration(node); + auto shortcut_distances = cell.GetOutDistance(node); for (auto shortcut_weight : cell.GetOutWeight(node)) { BOOST_ASSERT(destination != cell.GetDestinationNodes().end()); BOOST_ASSERT(!shortcut_durations.empty()); + BOOST_ASSERT(!shortcut_distances.empty()); const NodeID to = *destination; if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to) { const auto to_weight = weight + shortcut_weight; const auto to_duration = duration + shortcut_durations.front(); + const auto to_distance = distance + shortcut_distances.front(); if (!query_heap.WasInserted(to)) { - query_heap.Insert(to, to_weight, {node, true, to_duration}); + query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance}); } - else if (std::tie(to_weight, to_duration, node) < + else if (std::tie(to_weight, to_duration, to_distance, node) < std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration, + query_heap.GetData(to).distance, query_heap.GetData(to).parent)) { - query_heap.GetData(to) = {node, true, to_duration}; + query_heap.GetData(to) = {node, true, to_duration, to_distance}; query_heap.DecreaseKey(to, to_weight); } } ++destination; shortcut_durations.advance_begin(1); + shortcut_distances.advance_begin(1); } BOOST_ASSERT(shortcut_durations.empty()); + BOOST_ASSERT(shortcut_distances.empty()); } else { // Shortcuts in backward direction auto source = cell.GetSourceNodes().begin(); auto shortcut_durations = cell.GetInDuration(node); + auto shortcut_distances = cell.GetInDistance(node); for (auto shortcut_weight : cell.GetInWeight(node)) { BOOST_ASSERT(source != cell.GetSourceNodes().end()); BOOST_ASSERT(!shortcut_durations.empty()); + BOOST_ASSERT(!shortcut_distances.empty()); const NodeID to = *source; if (shortcut_weight != INVALID_EDGE_WEIGHT && node != to) { const auto to_weight = weight + shortcut_weight; const auto to_duration = duration + shortcut_durations.front(); + const auto to_distance = distance + shortcut_distances.front(); if (!query_heap.WasInserted(to)) { - query_heap.Insert(to, to_weight, {node, true, to_duration}); + query_heap.Insert(to, to_weight, {node, true, to_duration, to_distance}); } - else if (std::tie(to_weight, to_duration, node) < + else if (std::tie(to_weight, to_duration, to_distance, node) < std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration, + query_heap.GetData(to).distance, query_heap.GetData(to).parent)) { - query_heap.GetData(to) = {node, true, to_duration}; + query_heap.GetData(to) = {node, true, to_duration, to_distance}; query_heap.DecreaseKey(to, to_weight); } } ++source; shortcut_durations.advance_begin(1); + shortcut_distances.advance_begin(1); } BOOST_ASSERT(shortcut_durations.empty()); + BOOST_ASSERT(shortcut_distances.empty()); } } @@ -143,25 +156,28 @@ void relaxOutgoingEdges(const DataFacade &facade, const auto node_id = DIRECTION == FORWARD_DIRECTION ? node : facade.GetTarget(edge); const auto node_weight = facade.GetNodeWeight(node_id); const auto node_duration = facade.GetNodeDuration(node_id); + const auto node_distance = facade.GetNodeDistance(node_id); const auto turn_weight = node_weight + facade.GetWeightPenaltyForEdgeID(turn_id); const auto turn_duration = node_duration + facade.GetDurationPenaltyForEdgeID(turn_id); BOOST_ASSERT_MSG(node_weight + turn_weight > 0, "edge weight is invalid"); const auto to_weight = weight + turn_weight; const auto to_duration = duration + turn_duration; + const auto to_distance = distance + node_distance; // New Node discovered -> Add to Heap + Node Info Storage if (!query_heap.WasInserted(to)) { - query_heap.Insert(to, to_weight, {node, false, to_duration}); + query_heap.Insert(to, to_weight, {node, false, to_duration, to_distance}); } // Found a shorter Path -> Update weight and set new parent - else if (std::tie(to_weight, to_duration, node) < + else if (std::tie(to_weight, to_duration, to_distance, node) < std::tie(query_heap.GetKey(to), query_heap.GetData(to).duration, + query_heap.GetData(to).distance, query_heap.GetData(to).parent)) { - query_heap.GetData(to) = {node, false, to_duration}; + query_heap.GetData(to) = {node, false, to_duration, to_distance}; query_heap.DecreaseKey(to, to_weight); } } @@ -177,16 +193,15 @@ oneToManySearch(SearchEngineData &engine_working_data, const DataFacade &facade, const std::vector &phantom_nodes, std::size_t phantom_index, - const std::vector &phantom_indices, - const bool calculate_distance) + const std::vector &phantom_indices) { std::vector weights(phantom_indices.size(), INVALID_EDGE_WEIGHT); std::vector durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION); - std::vector distances_table; + std::vector distances_table(phantom_indices.size(), MAXIMAL_EDGE_DISTANCE); std::vector middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID); // Collect destination (source) nodes into a map - std::unordered_multimap> + std::unordered_multimap> target_nodes_index; target_nodes_index.reserve(phantom_indices.size()); for (std::size_t index = 0; index < phantom_indices.size(); ++index) @@ -201,13 +216,15 @@ oneToManySearch(SearchEngineData &engine_working_data, {phantom_node.forward_segment_id.id, std::make_tuple(index, phantom_node.GetForwardWeightPlusOffset(), - phantom_node.GetForwardDuration())}); + phantom_node.GetForwardDuration(), + phantom_node.GetForwardDistance())}); if (phantom_node.IsValidReverseTarget()) target_nodes_index.insert( {phantom_node.reverse_segment_id.id, std::make_tuple(index, phantom_node.GetReverseWeightPlusOffset(), - phantom_node.GetReverseDuration())}); + phantom_node.GetReverseDuration(), + phantom_node.GetReverseDistance())}); } else if (DIRECTION == REVERSE_DIRECTION) { @@ -216,13 +233,15 @@ oneToManySearch(SearchEngineData &engine_working_data, {phantom_node.forward_segment_id.id, std::make_tuple(index, -phantom_node.GetForwardWeightPlusOffset(), - -phantom_node.GetForwardDuration())}); + -phantom_node.GetForwardDuration(), + -phantom_node.GetForwardDistance())}); if (phantom_node.IsValidReverseSource()) target_nodes_index.insert( {phantom_node.reverse_segment_id.id, std::make_tuple(index, -phantom_node.GetReverseWeightPlusOffset(), - -phantom_node.GetReverseDuration())}); + -phantom_node.GetReverseDuration(), + -phantom_node.GetReverseDistance())}); } } @@ -232,44 +251,51 @@ oneToManySearch(SearchEngineData &engine_working_data, auto &query_heap = *(engine_working_data.many_to_many_heap); // Check if node is in the destinations list and update weights/durations - auto update_values = [&](NodeID node, EdgeWeight weight, EdgeDuration duration) { - auto candidates = target_nodes_index.equal_range(node); - for (auto it = candidates.first; it != candidates.second;) - { - std::size_t index; - EdgeWeight target_weight; - EdgeDuration target_duration; - std::tie(index, target_weight, target_duration) = it->second; - - const auto path_weight = weight + target_weight; - if (path_weight >= 0) + auto update_values = + [&](NodeID node, EdgeWeight weight, EdgeDuration duration, EdgeDistance distance) { + auto candidates = target_nodes_index.equal_range(node); + for (auto it = candidates.first; it != candidates.second;) { - const auto path_duration = duration + target_duration; + std::size_t index; + EdgeWeight target_weight; + EdgeDuration target_duration; + EdgeDistance target_distance; + std::tie(index, target_weight, target_duration, target_distance) = it->second; - if (std::tie(path_weight, path_duration) < - std::tie(weights[index], durations[index])) + const auto path_weight = weight + target_weight; + if (path_weight >= 0) { - weights[index] = path_weight; - durations[index] = path_duration; - middle_nodes_table[index] = node; + const auto path_duration = duration + target_duration; + const auto path_distance = distance + target_distance; + + if (std::tie(path_weight, path_duration, path_distance) < + std::tie(weights[index], durations[index], distances_table[index])) + { + weights[index] = path_weight; + durations[index] = path_duration; + distances_table[index] = path_distance; + middle_nodes_table[index] = node; + } + + // Remove node from destinations list + it = target_nodes_index.erase(it); + } + else + { + ++it; } - - // Remove node from destinations list - it = target_nodes_index.erase(it); } - else - { - ++it; - } - } - }; + }; - auto insert_node = [&](NodeID node, EdgeWeight initial_weight, EdgeDuration initial_duration) { + auto insert_node = [&](NodeID node, + EdgeWeight initial_weight, + EdgeDuration initial_duration, + EdgeDistance initial_distance) { // Update single node paths - update_values(node, initial_weight, initial_duration); + update_values(node, initial_weight, initial_duration, initial_distance); - query_heap.Insert(node, initial_weight, {node, initial_duration}); + query_heap.Insert(node, initial_weight, {node, initial_duration, initial_distance}); // Place adjacent nodes into heap for (auto edge : facade.GetAdjacentEdgeRange(node)) @@ -292,8 +318,9 @@ oneToManySearch(SearchEngineData &engine_working_data, facade.GetWeightPenaltyForEdgeID(turn_id); const auto edge_duration = initial_duration + facade.GetNodeDuration(node_id) + facade.GetDurationPenaltyForEdgeID(turn_id); + const auto edge_distance = initial_distance + facade.GetNodeDistance(node_id); - query_heap.Insert(to, edge_weight, {node, edge_duration}); + query_heap.Insert(to, edge_weight, {node, edge_duration, edge_distance}); } } }; @@ -307,14 +334,16 @@ oneToManySearch(SearchEngineData &engine_working_data, { insert_node(phantom_node.forward_segment_id.id, -phantom_node.GetForwardWeightPlusOffset(), - -phantom_node.GetForwardDuration()); + -phantom_node.GetForwardDuration(), + -phantom_node.GetForwardDistance()); } if (phantom_node.IsValidReverseSource()) { insert_node(phantom_node.reverse_segment_id.id, -phantom_node.GetReverseWeightPlusOffset(), - -phantom_node.GetReverseDuration()); + -phantom_node.GetReverseDuration(), + -phantom_node.GetReverseDistance()); } } else if (DIRECTION == REVERSE_DIRECTION) @@ -323,14 +352,16 @@ oneToManySearch(SearchEngineData &engine_working_data, { insert_node(phantom_node.forward_segment_id.id, phantom_node.GetForwardWeightPlusOffset(), - phantom_node.GetForwardDuration()); + phantom_node.GetForwardDuration(), + phantom_node.GetForwardDistance()); } if (phantom_node.IsValidReverseTarget()) { insert_node(phantom_node.reverse_segment_id.id, phantom_node.GetReverseWeightPlusOffset(), - phantom_node.GetReverseDuration()); + phantom_node.GetReverseDuration(), + phantom_node.GetReverseDistance()); } } } @@ -341,141 +372,23 @@ oneToManySearch(SearchEngineData &engine_working_data, const auto node = query_heap.DeleteMin(); const auto weight = query_heap.GetKey(node); const auto duration = query_heap.GetData(node).duration; + const auto distance = query_heap.GetData(node).distance; // Update values - update_values(node, weight, duration); + update_values(node, weight, duration, distance); // Relax outgoing edges relaxOutgoingEdges(facade, node, weight, duration, + distance, query_heap, phantom_nodes, phantom_index, phantom_indices); } - if (calculate_distance) - { - // Initialize unpacking heaps - engine_working_data.InitializeOrClearFirstThreadLocalStorage( - facade.GetNumberOfNodes(), facade.GetMaxBorderNodeID() + 1); - - distances_table.resize(phantom_indices.size(), INVALID_EDGE_DISTANCE); - - for (unsigned location = 0; location < phantom_indices.size(); ++location) - { - // Get the "middle" node that is the last node of a path - const NodeID middle_node_id = middle_nodes_table[location]; - if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways - { - continue; - } - - // Retrieve the packed path from the heap - PackedPath packed_path = mld::retrievePackedPathFromSingleManyToManyHeap( - query_heap, middle_node_id); - - // ... and reverse it to have packed edges in the correct order, - if (DIRECTION == FORWARD_DIRECTION) - { - std::reverse(packed_path.begin(), packed_path.end()); - } - - // ... unpack path - auto &forward_heap = *engine_working_data.forward_heap_1; - auto &reverse_heap = *engine_working_data.reverse_heap_1; - EdgeWeight weight = INVALID_EDGE_WEIGHT; - std::vector unpacked_nodes; - std::vector unpacked_edges; - - std::tie(weight, unpacked_nodes, unpacked_edges) = - unpackPathAndCalculateDistance(engine_working_data, - facade, - forward_heap, - reverse_heap, - DO_NOT_FORCE_LOOPS, - DO_NOT_FORCE_LOOPS, - INVALID_EDGE_WEIGHT, - packed_path, - middle_node_id, - phantom_nodes, - phantom_index, - phantom_indices); - - // Accumulate the path length without the last node - auto annotation = 0.0; - - BOOST_ASSERT(!unpacked_nodes.empty()); - for (auto node = unpacked_nodes.begin(), last_node = std::prev(unpacked_nodes.end()); - node != last_node; - ++node) - { - annotation += computeEdgeDistance(facade, *node); - } - - // ... and add negative source and positive target offsets - // ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped - // Get source and target phantom nodes - // * 1-to-N: source is a single index, target is the corresponding from the indices list - // * N-to-1: source is the corresponding from the indices list, target is a single index - auto source_phantom_index = phantom_index; - auto target_phantom_index = phantom_indices[location]; - if (DIRECTION == REVERSE_DIRECTION) - { - std::swap(source_phantom_index, target_phantom_index); - } - const auto &source_phantom = phantom_nodes[source_phantom_index]; - const auto &target_phantom = phantom_nodes[target_phantom_index]; - const NodeID source_node = unpacked_nodes.front(); - const NodeID target_node = unpacked_nodes.back(); - - EdgeDistance source_offset = 0., target_offset = 0.; - if (source_phantom.IsValidForwardSource() && - source_phantom.forward_segment_id.id == source_node) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 - // to 3 - // -->s <-- subtract offset to start at source - // ......... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - source_offset = source_phantom.GetForwardDistance(); - } - else if (source_phantom.IsValidReverseSource() && - source_phantom.reverse_segment_id.id == source_node) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // s<------- <-- subtract offset to start at source - // ... <-- want this distance - // entry 0---1---2---3 <-- 3 is exit node - source_offset = source_phantom.GetReverseDistance(); - } - if (target_phantom.IsValidForwardTarget() && - target_phantom.forward_segment_id.id == target_node) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 - // to 3 - // ++>t <-- add offset to get to target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - target_offset = target_phantom.GetForwardDistance(); - } - else if (target_phantom.IsValidReverseTarget() && - target_phantom.reverse_segment_id.id == target_node) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 - // to 3 - // <++t <-- add offset to get from target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - target_offset = target_phantom.GetReverseDistance(); - } - - distances_table[location] = -source_offset + annotation + target_offset; - } - } - return std::make_pair(durations, distances_table); } @@ -491,12 +404,14 @@ void forwardRoutingStep(const DataFacade &facade, const std::vector &search_space_with_buckets, std::vector &weights_table, std::vector &durations_table, + std::vector &distances_table, std::vector &middle_nodes_table, const PhantomNode &phantom_node) { const auto node = query_heap.DeleteMin(); const auto source_weight = query_heap.GetKey(node); const auto source_duration = query_heap.GetData(node).duration; + const auto source_distance = query_heap.GetData(node).distance; // Check if each encountered node has an entry const auto &bucket_list = std::equal_range(search_space_with_buckets.begin(), @@ -509,6 +424,7 @@ void forwardRoutingStep(const DataFacade &facade, const auto column_idx = current_bucket.column_index; const auto target_weight = current_bucket.weight; const auto target_duration = current_bucket.duration; + const auto target_distance = current_bucket.distance; // Get the value location in the results tables: // * row-major direct (row_idx, column_idx) index for forward direction @@ -518,22 +434,26 @@ void forwardRoutingStep(const DataFacade &facade, : row_idx + column_idx * number_of_sources; auto ¤t_weight = weights_table[location]; auto ¤t_duration = durations_table[location]; + auto ¤t_distance = distances_table[location]; // Check if new weight is better auto new_weight = source_weight + target_weight; auto new_duration = source_duration + target_duration; + auto new_distance = source_distance + target_distance; if (new_weight >= 0 && - std::tie(new_weight, new_duration) < std::tie(current_weight, current_duration)) + std::tie(new_weight, new_duration, new_distance) < + std::tie(current_weight, current_duration, current_distance)) { current_weight = new_weight; current_duration = new_duration; + current_distance = new_distance; middle_nodes_table[location] = node; } } relaxOutgoingEdges( - facade, node, source_weight, source_duration, query_heap, phantom_node); + facade, node, source_weight, source_duration, source_distance, query_heap, phantom_node); } template @@ -546,18 +466,25 @@ void backwardRoutingStep(const DataFacade &facade, const auto node = query_heap.DeleteMin(); const auto target_weight = query_heap.GetKey(node); const auto target_duration = query_heap.GetData(node).duration; + const auto target_distance = query_heap.GetData(node).distance; const auto parent = query_heap.GetData(node).parent; const auto from_clique_arc = query_heap.GetData(node).from_clique_arc; // Store settled nodes in search space bucket search_space_with_buckets.emplace_back( - node, parent, from_clique_arc, column_idx, target_weight, target_duration); + node, parent, from_clique_arc, column_idx, target_weight, target_duration, target_distance); const auto &partition = facade.GetMultiLevelPartition(); const auto maximal_level = partition.GetNumberOfLevels() - 1; - relaxOutgoingEdges( - facade, node, target_weight, target_duration, query_heap, phantom_node, maximal_level); + relaxOutgoingEdges(facade, + node, + target_weight, + target_duration, + target_distance, + query_heap, + phantom_node, + maximal_level); } template @@ -596,190 +523,13 @@ void retrievePackedPathFromSearchSpace(NodeID middle_node_id, } } -template -void calculateDistances(typename SearchEngineData::ManyToManyQueryHeap &query_heap, - const DataFacade &facade, - const std::vector &phantom_nodes, - const std::vector &target_indices, - const unsigned row_idx, - const std::size_t source_index, - const unsigned number_of_sources, - const unsigned number_of_targets, - const std::vector &search_space_with_buckets, - std::vector &distances_table, - const std::vector &middle_nodes_table, - SearchEngineData &engine_working_data) -{ - engine_working_data.InitializeOrClearFirstThreadLocalStorage(facade.GetNumberOfNodes(), - facade.GetMaxBorderNodeID() + 1); - - for (unsigned column_idx = 0; column_idx < number_of_targets; ++column_idx) - { - // Step 1: Get source and target phantom nodes that were used in the bucketed search - auto source_phantom_index = source_index; - auto target_phantom_index = target_indices[column_idx]; - const auto &source_phantom = phantom_nodes[source_phantom_index]; - const auto &target_phantom = phantom_nodes[target_phantom_index]; - - const auto location = DIRECTION == FORWARD_DIRECTION - ? row_idx * number_of_targets + column_idx - : row_idx + column_idx * number_of_sources; - - if (source_phantom_index == target_phantom_index) - { - distances_table[location] = 0.0; - continue; - } - - NodeID middle_node_id = middle_nodes_table[location]; - - if (middle_node_id == SPECIAL_NODEID) // takes care of one-ways - { - distances_table[location] = INVALID_EDGE_DISTANCE; - continue; - } - - // Step 2: Find path from source to middle node - PackedPath packed_path = - mld::retrievePackedPathFromSingleManyToManyHeap(query_heap, middle_node_id); - - if (DIRECTION == FORWARD_DIRECTION) - { - std::reverse(packed_path.begin(), packed_path.end()); - } - - auto &forward_heap = *engine_working_data.forward_heap_1; - auto &reverse_heap = *engine_working_data.reverse_heap_1; - EdgeWeight weight = INVALID_EDGE_WEIGHT; - std::vector unpacked_nodes_from_source; - std::vector unpacked_edges; - std::tie(weight, unpacked_nodes_from_source, unpacked_edges) = - unpackPathAndCalculateDistance(engine_working_data, - facade, - forward_heap, - reverse_heap, - DO_NOT_FORCE_LOOPS, - DO_NOT_FORCE_LOOPS, - INVALID_EDGE_WEIGHT, - packed_path, - middle_node_id, - source_phantom); - - // Step 3: Find path from middle to target node - packed_path.clear(); - retrievePackedPathFromSearchSpace( - middle_node_id, column_idx, search_space_with_buckets, packed_path); - - if (DIRECTION == REVERSE_DIRECTION) - { - std::reverse(packed_path.begin(), packed_path.end()); - } - - std::vector unpacked_nodes_to_target; - std::tie(weight, unpacked_nodes_to_target, unpacked_edges) = - unpackPathAndCalculateDistance(engine_working_data, - facade, - forward_heap, - reverse_heap, - DO_NOT_FORCE_LOOPS, - DO_NOT_FORCE_LOOPS, - INVALID_EDGE_WEIGHT, - packed_path, - middle_node_id, - target_phantom); - - if (DIRECTION == REVERSE_DIRECTION) - { - std::swap(unpacked_nodes_to_target, unpacked_nodes_from_source); - } - - // Step 4: Compute annotation value along the path nodes without the target node - auto annotation = 0.0; - - for (auto node = unpacked_nodes_from_source.begin(), - last_node = std::prev(unpacked_nodes_from_source.end()); - node != last_node; - ++node) - { - annotation += computeEdgeDistance(facade, *node); - } - - for (auto node = unpacked_nodes_to_target.begin(), - last_node = std::prev(unpacked_nodes_to_target.end()); - node != last_node; - ++node) - { - annotation += computeEdgeDistance(facade, *node); - } - - // Step 5: Get phantom node offsets and compute the annotation value - EdgeDistance source_offset = 0., target_offset = 0.; - { - // ⚠ for REVERSE_DIRECTION original source and target phantom nodes are swapped - if (DIRECTION == REVERSE_DIRECTION) - { - std::swap(source_phantom_index, target_phantom_index); - } - const auto &source_phantom = phantom_nodes[source_phantom_index]; - const auto &target_phantom = phantom_nodes[target_phantom_index]; - - NodeID source_node = unpacked_nodes_from_source.front(); - NodeID target_node = unpacked_nodes_to_target.back(); - - if (source_phantom.IsValidForwardSource() && - source_phantom.forward_segment_id.id == source_node) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 - // to 3 - // -->s <-- subtract offset to start at source - // ......... <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - source_offset = source_phantom.GetForwardDistance(); - } - else if (source_phantom.IsValidReverseSource() && - source_phantom.reverse_segment_id.id == source_node) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 to 3 - // s<------- <-- subtract offset to start at source - // ... <-- want this distance - // entry 0---1---2---3 <-- 3 is exit node - source_offset = source_phantom.GetReverseDistance(); - } - - if (target_phantom.IsValidForwardTarget() && - target_phantom.forward_segment_id.id == target_node) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 - // to 3 - // ++>t <-- add offset to get to target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - target_offset = target_phantom.GetForwardDistance(); - } - else if (target_phantom.IsValidReverseTarget() && - target_phantom.reverse_segment_id.id == target_node) - { - // ............ <-- calculateEGBAnnotation returns distance from 0 - // to 3 - // <++t <-- add offset to get from target - // ................ <-- want this distance as result - // entry 0---1---2---3--- <-- 3 is exit node - target_offset = target_phantom.GetReverseDistance(); - } - } - - distances_table[location] = -source_offset + annotation + target_offset; - } -} - template std::pair, std::vector> manyToManySearch(SearchEngineData &engine_working_data, const DataFacade &facade, const std::vector &phantom_nodes, const std::vector &source_indices, - const std::vector &target_indices, - const bool calculate_distance) + const std::vector &target_indices) { const auto number_of_sources = source_indices.size(); const auto number_of_targets = target_indices.size(); @@ -787,7 +537,7 @@ manyToManySearch(SearchEngineData &engine_working_data, std::vector weights_table(number_of_entries, INVALID_EDGE_WEIGHT); std::vector durations_table(number_of_entries, MAXIMAL_EDGE_DURATION); - std::vector distances_table; + std::vector distances_table(number_of_entries, INVALID_EDGE_DISTANCE); std::vector middle_nodes_table(number_of_entries, SPECIAL_NODEID); std::vector search_space_with_buckets; @@ -846,25 +596,9 @@ manyToManySearch(SearchEngineData &engine_working_data, search_space_with_buckets, weights_table, durations_table, - middle_nodes_table, - source_phantom); - } - - if (calculate_distance) - { - distances_table.resize(number_of_entries, INVALID_EDGE_DISTANCE); - calculateDistances(query_heap, - facade, - phantom_nodes, - target_indices, // source_indices - row_idx, - source_index, - number_of_sources, - number_of_targets, - search_space_with_buckets, distances_table, middle_nodes_table, - engine_working_data); + source_phantom); } } @@ -892,48 +626,29 @@ manyToManySearch(SearchEngineData &engine_working_data, const std::vector &phantom_nodes, const std::vector &source_indices, const std::vector &target_indices, - const bool calculate_distance, - const bool calculate_duration) + const bool /* calculate_distance */, + const bool /* calculate_duration */) { - (void)calculate_duration; // flag stub to use for calculating distances in matrix in mld in the - // future - if (source_indices.size() == 1) { // TODO: check if target_indices.size() == 1 and do a bi-directional search - return mld::oneToManySearch(engine_working_data, - facade, - phantom_nodes, - source_indices.front(), - target_indices, - calculate_distance); + return mld::oneToManySearch( + engine_working_data, facade, phantom_nodes, source_indices.front(), target_indices); } if (target_indices.size() == 1) { - return mld::oneToManySearch(engine_working_data, - facade, - phantom_nodes, - target_indices.front(), - source_indices, - calculate_distance); + return mld::oneToManySearch( + engine_working_data, facade, phantom_nodes, target_indices.front(), source_indices); } if (target_indices.size() < source_indices.size()) { - return mld::manyToManySearch(engine_working_data, - facade, - phantom_nodes, - target_indices, - source_indices, - calculate_distance); + return mld::manyToManySearch( + engine_working_data, facade, phantom_nodes, target_indices, source_indices); } - return mld::manyToManySearch(engine_working_data, - facade, - phantom_nodes, - source_indices, - target_indices, - calculate_distance); + return mld::manyToManySearch( + engine_working_data, facade, phantom_nodes, source_indices, target_indices); } } // namespace routing_algorithms diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index 8d77e2074..a5d5b605b 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -114,6 +114,13 @@ void EdgeBasedGraphFactory::GetEdgeBasedNodeDurations( swap(m_edge_based_node_durations, output_node_durations); } +void EdgeBasedGraphFactory::GetEdgeBasedNodeDistances( + std::vector &output_node_distances) +{ + using std::swap; // Koenig swap + swap(m_edge_based_node_distances, output_node_distances); +} + std::uint32_t EdgeBasedGraphFactory::GetConnectivityChecksum() const { return m_connectivity_checksum; @@ -291,8 +298,12 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes() { // heuristic: node-based graph node is a simple intersection with four edges // (edge-based nodes) - m_edge_based_node_weights.reserve(4 * m_node_based_graph.GetNumberOfNodes()); - m_edge_based_node_durations.reserve(4 * m_node_based_graph.GetNumberOfNodes()); + constexpr std::size_t ESTIMATED_EDGE_COUNT = 4; + m_edge_based_node_weights.reserve(ESTIMATED_EDGE_COUNT * m_node_based_graph.GetNumberOfNodes()); + m_edge_based_node_durations.reserve(ESTIMATED_EDGE_COUNT * + m_node_based_graph.GetNumberOfNodes()); + m_edge_based_node_distances.reserve(ESTIMATED_EDGE_COUNT * + m_node_based_graph.GetNumberOfNodes()); nbe_to_ebn_mapping.resize(m_node_based_graph.GetEdgeCapacity(), SPECIAL_NODEID); // renumber edge based node of outgoing edges @@ -310,6 +321,7 @@ unsigned EdgeBasedGraphFactory::LabelEdgeBasedNodes() m_edge_based_node_weights.push_back(edge_data.weight); m_edge_based_node_durations.push_back(edge_data.duration); + m_edge_based_node_distances.push_back(edge_data.distance); BOOST_ASSERT(numbered_edges_count < m_node_based_graph.GetNumberOfEdges()); nbe_to_ebn_mapping[current_edge] = numbered_edges_count; @@ -407,6 +419,8 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re m_edge_based_node_weights.push_back(ebn_weight); m_edge_based_node_durations.push_back( m_edge_based_node_durations[nbe_to_ebn_mapping[eid]]); + m_edge_based_node_distances.push_back( + m_edge_based_node_distances[nbe_to_ebn_mapping[eid]]); edge_based_node_id++; progress.PrintStatus(progress_counter++); @@ -416,6 +430,7 @@ EdgeBasedGraphFactory::GenerateEdgeExpandedNodes(const WayRestrictionMap &way_re BOOST_ASSERT(m_edge_based_node_segments.size() == m_edge_based_node_is_startpoint.size()); BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_weights.size()); BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_durations.size()); + BOOST_ASSERT(m_number_of_edge_based_nodes == m_edge_based_node_distances.size()); util::Log() << "Generated " << m_number_of_edge_based_nodes << " nodes (" << way_restriction_map.NumberOfDuplicatedNodes() @@ -652,16 +667,17 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // auto turn_id = m_edge_based_edge_list.size(); auto weight = boost::numeric_cast(edge_data1.weight + weight_penalty); auto duration = boost::numeric_cast(edge_data1.duration + duration_penalty); + auto distance = boost::numeric_cast(edge_data1.distance); - EdgeBasedEdge edge_based_edge = { - edge_based_node_from, - edge_based_node_to, - SPECIAL_NODEID, // This will be updated once the main loop - // completes! - weight, - duration, - true, - false}; + EdgeBasedEdge edge_based_edge = {edge_based_node_from, + edge_based_node_to, + SPECIAL_NODEID, // This will be updated once the main + // loop completes! + weight, + duration, + distance, + true, + false}; // We write out the mapping between the edge-expanded edges and the original nodes. // Since each edge represents a possible maneuver, external programs can use this to diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index 6f5668bb3..be4264825 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -387,12 +387,16 @@ void ExtractionContainers::PrepareEdges(ScriptingEnvironment &scripting_environm const auto weight = edge_iterator->weight_data(distance); const auto duration = edge_iterator->duration_data(distance); + const auto accurate_distance = + util::coordinate_calculation::fccApproximateDistance(source_coord, target_coord); + ExtractionSegment segment(source_coord, target_coord, distance, weight, duration); scripting_environment.ProcessSegment(segment); auto &edge = edge_iterator->result; edge.weight = std::max(1, std::round(segment.weight * weight_multiplier)); edge.duration = std::max(1, std::round(segment.duration * 10.)); + edge.distance = accurate_distance; // assign new node id const auto node_id = mapExternalToInternalNodeID( diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index f62bb1b39..dc92f7011 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -242,6 +242,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) std::vector node_is_startpoint; std::vector edge_based_node_weights; std::vector edge_based_node_durations; + std::vector edge_based_node_distances; std::uint32_t ebg_connectivity_checksum = 0; // Create a node-based graph from the OSRM file @@ -322,6 +323,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) node_is_startpoint, edge_based_node_weights, edge_based_node_durations, + edge_based_node_distances, edge_based_edge_list, ebg_connectivity_checksum); @@ -345,8 +347,10 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) util::Log() << "Saving edge-based node weights to file."; TIMER_START(timer_write_node_weights); - extractor::files::writeEdgeBasedNodeWeightsDurations( - config.GetPath(".osrm.enw"), edge_based_node_weights, edge_based_node_durations); + extractor::files::writeEdgeBasedNodeWeightsDurationsDistances(config.GetPath(".osrm.enw"), + edge_based_node_weights, + edge_based_node_durations, + edge_based_node_distances); TIMER_STOP(timer_write_node_weights); util::Log() << "Done writing. (" << TIMER_SEC(timer_write_node_weights) << ")"; @@ -736,6 +740,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph( std::vector &node_is_startpoint, std::vector &edge_based_node_weights, std::vector &edge_based_node_durations, + std::vector &edge_based_node_distances, util::DeallocatingVector &edge_based_edge_list, std::uint32_t &connectivity_checksum) { @@ -786,6 +791,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph( edge_based_graph_factory.GetStartPointMarkers(node_is_startpoint); edge_based_graph_factory.GetEdgeBasedNodeWeights(edge_based_node_weights); edge_based_graph_factory.GetEdgeBasedNodeDurations(edge_based_node_durations); + edge_based_graph_factory.GetEdgeBasedNodeDistances(edge_based_node_distances); connectivity_checksum = edge_based_graph_factory.GetConnectivityChecksum(); return number_of_edge_based_nodes; diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index c34f67ded..cfe983106 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -415,6 +415,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti OSMNodeID{static_cast(last_node.ref())}, 0, // weight 0, // duration + 0, // distance {}, // geometry id static_cast(annotation_data_id), {true, @@ -450,6 +451,7 @@ void ExtractorCallbacks::ProcessWay(const osmium::Way &input_way, const Extracti OSMNodeID{static_cast(last_node.ref())}, 0, // weight 0, // duration + 0, // distance {}, // geometry id static_cast(annotation_data_id), {false, diff --git a/src/extractor/graph_compressor.cpp b/src/extractor/graph_compressor.cpp index fefda38e1..737006006 100644 --- a/src/extractor/graph_compressor.cpp +++ b/src/extractor/graph_compressor.cpp @@ -259,6 +259,7 @@ void GraphCompressor::Compress( const auto forward_weight2 = fwd_edge_data2.weight; const auto forward_duration1 = fwd_edge_data1.duration; const auto forward_duration2 = fwd_edge_data2.duration; + const auto forward_distance2 = fwd_edge_data2.distance; BOOST_ASSERT(0 != forward_weight1); BOOST_ASSERT(0 != forward_weight2); @@ -267,6 +268,17 @@ void GraphCompressor::Compress( const auto reverse_weight2 = rev_edge_data2.weight; const auto reverse_duration1 = rev_edge_data1.duration; const auto reverse_duration2 = rev_edge_data2.duration; + const auto reverse_distance2 = rev_edge_data2.distance; + +#ifndef NDEBUG + // Because distances are symmetrical, we only need one + // per edge - here we double-check that they match + // their mirrors. + const auto reverse_distance1 = rev_edge_data1.distance; + const auto forward_distance1 = fwd_edge_data1.distance; + BOOST_ASSERT(forward_distance1 == reverse_distance2); + BOOST_ASSERT(forward_distance2 == reverse_distance1); +#endif BOOST_ASSERT(0 != reverse_weight1); BOOST_ASSERT(0 != reverse_weight2); @@ -279,6 +291,10 @@ void GraphCompressor::Compress( graph.GetEdgeData(forward_e1).duration += forward_duration2; graph.GetEdgeData(reverse_e1).duration += reverse_duration2; + // add distance of e2's to e1 + graph.GetEdgeData(forward_e1).distance += forward_distance2; + graph.GetEdgeData(reverse_e1).distance += reverse_distance2; + if (node_weight_penalty != INVALID_EDGE_WEIGHT && node_duration_penalty != MAXIMAL_EDGE_DURATION) { @@ -286,6 +302,7 @@ void GraphCompressor::Compress( graph.GetEdgeData(reverse_e1).weight += node_weight_penalty; graph.GetEdgeData(forward_e1).duration += node_duration_penalty; graph.GetEdgeData(reverse_e1).duration += node_duration_penalty; + // Note: no penalties for distances } // extend e1's to targets of e2's diff --git a/src/partitioner/partitioner.cpp b/src/partitioner/partitioner.cpp index c18089386..bac7e6d66 100644 --- a/src/partitioner/partitioner.cpp +++ b/src/partitioner/partitioner.cpp @@ -147,12 +147,15 @@ int Partitioner::Run(const PartitionerConfig &config) { std::vector node_weights; std::vector node_durations; + std::vector node_distances; extractor::files::readEdgeBasedNodeWeightsDurations( config.GetPath(".osrm.enw"), node_weights, node_durations); + extractor::files::readEdgeBasedNodeDistances(config.GetPath(".osrm.enw"), node_distances); util::inplacePermutation(node_weights.begin(), node_weights.end(), permutation); util::inplacePermutation(node_durations.begin(), node_durations.end(), permutation); - extractor::files::writeEdgeBasedNodeWeightsDurations( - config.GetPath(".osrm.enw"), node_weights, node_durations); + util::inplacePermutation(node_distances.begin(), node_distances.end(), permutation); + extractor::files::writeEdgeBasedNodeWeightsDurationsDistances( + config.GetPath(".osrm.enw"), node_weights, node_durations, node_distances); } { const auto &filename = config.GetPath(".osrm.maneuver_overrides"); diff --git a/unit_tests/contractor/contracted_edge_container.cpp b/unit_tests/contractor/contracted_edge_container.cpp index 04f8a3523..9418f73a4 100644 --- a/unit_tests/contractor/contracted_edge_container.cpp +++ b/unit_tests/contractor/contracted_edge_container.cpp @@ -17,7 +17,8 @@ bool operator!=(const QueryEdge &lhs, const QueryEdge &rhs) { return !(lhs == rh std::ostream &operator<<(std::ostream &out, const QueryEdge::EdgeData &data) { out << "{" << data.turn_id << ", " << data.shortcut << ", " << data.duration << ", " - << data.weight << ", " << data.forward << ", " << data.backward << "}"; + << data.distance << ", " << data.weight << ", " << data.forward << ", " << data.backward + << "}"; return out; } @@ -36,31 +37,31 @@ BOOST_AUTO_TEST_CASE(merge_edge_of_multiple_graph) ContractedEdgeContainer container; std::vector edges; - edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}}); - edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}}); - edges.push_back(QueryEdge{2, 0, {3, false, 3, 6, false, true}}); - edges.push_back(QueryEdge{2, 1, {4, false, 3, 6, false, true}}); + edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}}); + edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}}); + edges.push_back(QueryEdge{2, 0, {3, false, 3, 3, 6, false, true}}); + edges.push_back(QueryEdge{2, 1, {4, false, 3, 3, 6, false, true}}); container.Insert(edges); edges.clear(); - edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}}); - edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}}); - edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}}); - edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}}); + edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}}); + edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}}); + edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}}); + edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}}); container.Merge(edges); edges.clear(); - edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}}); + edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}}); container.Merge(edges); std::vector reference_edges; - reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}}); - reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}}); - reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}}); - reference_edges.push_back(QueryEdge{2, 0, {3, false, 3, 6, false, true}}); - reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}}); - reference_edges.push_back(QueryEdge{2, 1, {4, false, 3, 6, false, true}}); - reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}}); + reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}}); + reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}}); + reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}}); + reference_edges.push_back(QueryEdge{2, 0, {3, false, 3, 3, 6, false, true}}); + reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}}); + reference_edges.push_back(QueryEdge{2, 1, {4, false, 3, 3, 6, false, true}}); + reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}}); CHECK_EQUAL_COLLECTIONS(container.edges, reference_edges); auto filters = container.MakeEdgeFilters(); @@ -78,22 +79,22 @@ BOOST_AUTO_TEST_CASE(merge_edge_of_multiple_disjoint_graph) ContractedEdgeContainer container; std::vector edges; - edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}}); - edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}}); - edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}}); - edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}}); + edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}}); + edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}}); + edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}}); + edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}}); container.Merge(edges); edges.clear(); - edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}}); + edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}}); container.Merge(edges); std::vector reference_edges; - reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 6, true, false}}); - reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 6, true, false}}); - reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 6, true, false}}); - reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 24, false, true}}); - reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 24, false, true}}); + reference_edges.push_back(QueryEdge{0, 1, {1, false, 3, 3, 6, true, false}}); + reference_edges.push_back(QueryEdge{1, 2, {2, false, 3, 3, 6, true, false}}); + reference_edges.push_back(QueryEdge{1, 4, {5, false, 3, 3, 6, true, false}}); + reference_edges.push_back(QueryEdge{2, 0, {3, false, 12, 12, 24, false, true}}); + reference_edges.push_back(QueryEdge{2, 1, {4, false, 12, 12, 24, false, true}}); CHECK_EQUAL_COLLECTIONS(container.edges, reference_edges); auto filters = container.MakeEdgeFilters(); diff --git a/unit_tests/contractor/graph_contractor.cpp b/unit_tests/contractor/graph_contractor.cpp index f1aeb7752..1993d1e5f 100644 --- a/unit_tests/contractor/graph_contractor.cpp +++ b/unit_tests/contractor/graph_contractor.cpp @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(contract_graph) reference_graph.DeleteEdgesTo(1, 3); reference_graph.DeleteEdgesTo(4, 3); // Insert shortcut - reference_graph.InsertEdge(4, 1, {2, 4, 3, 0, true, true, false}); + reference_graph.InsertEdge(4, 1, {2, 4, 1.0, 3, 0, true, true, false}); /* After contracting 4: * diff --git a/unit_tests/contractor/helper.hpp b/unit_tests/contractor/helper.hpp index 7ea6c4a51..de9f6b618 100644 --- a/unit_tests/contractor/helper.hpp +++ b/unit_tests/contractor/helper.hpp @@ -20,15 +20,19 @@ inline contractor::ContractorGraph makeGraph(const std::vector &edges) unsigned target; int weight; std::tie(start, target, weight) = edge; + int duration = weight * 2; + float distance = 1.0; max_id = std::max(std::max(start, target), max_id); input_edges.push_back(contractor::ContractorEdge{ start, target, - contractor::ContractorEdgeData{weight, weight * 2, id++, 0, false, true, false}}); + contractor::ContractorEdgeData{ + weight, duration, distance, id++, 0, false, true, false}}); input_edges.push_back(contractor::ContractorEdge{ target, start, - contractor::ContractorEdgeData{weight, weight * 2, id++, 0, false, false, true}}); + contractor::ContractorEdgeData{ + weight, duration, distance, id++, 0, false, false, true}}); } std::sort(input_edges.begin(), input_edges.end()); diff --git a/unit_tests/customizer/cell_customization.cpp b/unit_tests/customizer/cell_customization.cpp index b51e36797..d5a3f9eb8 100644 --- a/unit_tests/customizer/cell_customization.cpp +++ b/unit_tests/customizer/cell_customization.cpp @@ -27,6 +27,7 @@ auto makeGraph(const MultiLevelPartition &mlp, const std::vector &mock { EdgeWeight weight; EdgeDuration duration; + EdgeDistance distance; bool forward; bool backward; }; @@ -36,8 +37,20 @@ auto makeGraph(const MultiLevelPartition &mlp, const std::vector &mock for (const auto &m : mock_edges) { max_id = std::max(max_id, std::max(m.start, m.target)); - edges.push_back(Edge{m.start, m.target, m.weight, 2 * m.weight, true, false}); - edges.push_back(Edge{m.target, m.start, m.weight, 2 * m.weight, false, true}); + edges.push_back(Edge{m.start, + m.target, + m.weight, + 2 * m.weight, + static_cast(1.0), + true, + false}); + edges.push_back(Edge{m.target, + m.start, + m.weight, + 2 * m.weight, + static_cast(1.0), + false, + true}); } std::sort(edges.begin(), edges.end()); return partitioner::MultiLevelGraph( diff --git a/unit_tests/extractor/graph_compressor.cpp b/unit_tests/extractor/graph_compressor.cpp index b402d795c..ec2f93dd6 100644 --- a/unit_tests/extractor/graph_compressor.cpp +++ b/unit_tests/extractor/graph_compressor.cpp @@ -31,6 +31,7 @@ inline InputEdge MakeUnitEdge(const NodeID from, const NodeID to) to, // target 1, // weight 1, // duration + 1, // distance GeometryID{0, false}, // geometry_id false, // reversed NodeBasedEdgeClassification(), // default flags diff --git a/unit_tests/extractor/intersection_analysis_tests.cpp b/unit_tests/extractor/intersection_analysis_tests.cpp index e655c93ab..8d8fd7d78 100644 --- a/unit_tests/extractor/intersection_analysis_tests.cpp +++ b/unit_tests/extractor/intersection_analysis_tests.cpp @@ -47,6 +47,7 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity) to, 1, 1, + 1, GeometryID{0, false}, !allowed, NodeBasedEdgeClassification(), @@ -174,6 +175,7 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity) to, 1, 1, + 1, GeometryID{0, false}, !allowed, NodeBasedEdgeClassification{ @@ -277,7 +279,7 @@ BOOST_AUTO_TEST_CASE(skip_degree_two_nodes) // const auto unit_edge = [](const NodeID from, const NodeID to, bool allowed) { return InputEdge{ - from, to, 1, 1, GeometryID{0, false}, !allowed, NodeBasedEdgeClassification{}, 0}; + from, to, 1, 1, 1, GeometryID{0, false}, !allowed, NodeBasedEdgeClassification{}, 0}; }; std::vector edges = {unit_edge(0, 1, true), // 0 unit_edge(1, 0, true), diff --git a/unit_tests/partitioner/renumber.cpp b/unit_tests/partitioner/renumber.cpp index b070e5371..391220eae 100644 --- a/unit_tests/partitioner/renumber.cpp +++ b/unit_tests/partitioner/renumber.cpp @@ -32,9 +32,9 @@ auto makeGraph(const std::vector &mock_edges) max_id = std::max(max_id, std::max(m.start, m.target)); edges.push_back(InputEdge{ - m.start, m.target, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, true, false}}); + m.start, m.target, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, 1, true, false}}); edges.push_back(InputEdge{ - m.target, m.start, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, false, true}}); + m.target, m.start, EdgeBasedGraphEdgeData{SPECIAL_NODEID, 1, 1, 1, false, true}}); } std::sort(edges.begin(), edges.end()); return DynamicEdgeBasedGraph(max_id + 1, edges); From a67c4bf84d47836113ac639b94b50e85e911b447 Mon Sep 17 00:00:00 2001 From: Daniel Patterson Date: Tue, 30 Oct 2018 15:09:19 -0700 Subject: [PATCH 3/3] Calculating durations is unavoidable due to tie-breaking minimums, but we can avoid accumulating distances if they're not requested. --- include/engine/routing_algorithms.hpp | 12 ++-- .../routing_algorithms/many_to_many.hpp | 3 +- src/engine/plugins/table.cpp | 2 +- src/engine/plugins/trip.cpp | 5 +- .../routing_algorithms/many_to_many_ch.cpp | 13 ++-- .../routing_algorithms/many_to_many_mld.cpp | 59 +++++++++++++------ 6 files changed, 58 insertions(+), 36 deletions(-) diff --git a/include/engine/routing_algorithms.hpp b/include/engine/routing_algorithms.hpp index aec19f753..5d4a8a956 100644 --- a/include/engine/routing_algorithms.hpp +++ b/include/engine/routing_algorithms.hpp @@ -34,8 +34,7 @@ class RoutingAlgorithmsInterface ManyToManySearch(const std::vector &phantom_nodes, const std::vector &source_indices, const std::vector &target_indices, - const bool calculate_distance, - const bool calculate_duration) const = 0; + const bool calculate_distance) const = 0; virtual routing_algorithms::SubMatchingList MapMatching(const routing_algorithms::CandidateLists &candidates_list, @@ -88,8 +87,7 @@ template class RoutingAlgorithms final : public RoutingAlgo ManyToManySearch(const std::vector &phantom_nodes, const std::vector &source_indices, const std::vector &target_indices, - const bool calculate_distance, - const bool calculate_duration) const final override; + const bool calculate_distance) const final override; routing_algorithms::SubMatchingList MapMatching(const routing_algorithms::CandidateLists &candidates_list, @@ -198,8 +196,7 @@ std::pair, std::vector> RoutingAlgorithms::ManyToManySearch(const std::vector &phantom_nodes, const std::vector &_source_indices, const std::vector &_target_indices, - const bool calculate_distance, - const bool calculate_duration) const + const bool calculate_distance) const { BOOST_ASSERT(!phantom_nodes.empty()); @@ -222,8 +219,7 @@ RoutingAlgorithms::ManyToManySearch(const std::vector &p phantom_nodes, std::move(source_indices), std::move(target_indices), - calculate_distance, - calculate_duration); + calculate_distance); } template diff --git a/include/engine/routing_algorithms/many_to_many.hpp b/include/engine/routing_algorithms/many_to_many.hpp index 23c8902df..ddd861f06 100644 --- a/include/engine/routing_algorithms/many_to_many.hpp +++ b/include/engine/routing_algorithms/many_to_many.hpp @@ -97,8 +97,7 @@ manyToManySearch(SearchEngineData &engine_working_data, const std::vector &phantom_nodes, const std::vector &source_indices, const std::vector &target_indices, - const bool calculate_distance, - const bool calculate_duration); + const bool calculate_distance); } // namespace routing_algorithms } // namespace engine diff --git a/src/engine/plugins/table.cpp b/src/engine/plugins/table.cpp index e10b5461a..3d89bc25a 100644 --- a/src/engine/plugins/table.cpp +++ b/src/engine/plugins/table.cpp @@ -86,7 +86,7 @@ Status TablePlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, bool request_duration = params.annotations & api::TableParameters::AnnotationsType::Duration; auto result_tables_pair = algorithms.ManyToManySearch( - snapped_phantoms, params.sources, params.destinations, request_distance, request_duration); + snapped_phantoms, params.sources, params.destinations, request_distance); if ((request_duration && result_tables_pair.first.empty()) || (request_distance && result_tables_pair.second.empty())) diff --git a/src/engine/plugins/trip.cpp b/src/engine/plugins/trip.cpp index 8914c3e48..f402a0c06 100644 --- a/src/engine/plugins/trip.cpp +++ b/src/engine/plugins/trip.cpp @@ -217,10 +217,7 @@ Status TripPlugin::HandleRequest(const RoutingAlgorithmsInterface &algorithms, // compute the duration table of all phantom nodes auto result_duration_table = util::DistTableWrapper( - algorithms - .ManyToManySearch( - snapped_phantoms, {}, {}, /*requestDistance*/ false, /*requestDuration*/ true) - .first, + algorithms.ManyToManySearch(snapped_phantoms, {}, {}, /*requestDistance*/ false).first, number_of_locations); if (result_duration_table.size() == 0) diff --git a/src/engine/routing_algorithms/many_to_many_ch.cpp b/src/engine/routing_algorithms/many_to_many_ch.cpp index 1b8e90ca6..f9fa8e509 100644 --- a/src/engine/routing_algorithms/many_to_many_ch.cpp +++ b/src/engine/routing_algorithms/many_to_many_ch.cpp @@ -120,8 +120,13 @@ void forwardRoutingStep(const DataFacade &facade, const auto target_distance = current_bucket.distance; auto ¤t_weight = weights_table[row_index * number_of_targets + column_index]; + + EdgeDistance nulldistance = 0; + auto ¤t_duration = durations_table[row_index * number_of_targets + column_index]; - auto ¤t_distance = distances_table[row_index * number_of_targets + column_index]; + auto ¤t_distance = + distances_table.empty() ? nulldistance + : distances_table[row_index * number_of_targets + column_index]; // Check if new weight is better auto new_weight = source_weight + target_weight; @@ -180,8 +185,7 @@ manyToManySearch(SearchEngineData &engine_working_data, const std::vector &phantom_nodes, const std::vector &source_indices, const std::vector &target_indices, - const bool /* calculate_distance */, - const bool /* calculate_duration */) + const bool calculate_distance) { const auto number_of_sources = source_indices.size(); const auto number_of_targets = target_indices.size(); @@ -189,7 +193,8 @@ manyToManySearch(SearchEngineData &engine_working_data, std::vector weights_table(number_of_entries, INVALID_EDGE_WEIGHT); std::vector durations_table(number_of_entries, MAXIMAL_EDGE_DURATION); - std::vector distances_table(number_of_entries, MAXIMAL_EDGE_DISTANCE); + std::vector distances_table(calculate_distance ? number_of_entries : 0, + MAXIMAL_EDGE_DISTANCE); std::vector middle_nodes_table(number_of_entries, SPECIAL_NODEID); std::vector search_space_with_buckets; diff --git a/src/engine/routing_algorithms/many_to_many_mld.cpp b/src/engine/routing_algorithms/many_to_many_mld.cpp index b8521df9f..55544c4bb 100644 --- a/src/engine/routing_algorithms/many_to_many_mld.cpp +++ b/src/engine/routing_algorithms/many_to_many_mld.cpp @@ -193,11 +193,13 @@ oneToManySearch(SearchEngineData &engine_working_data, const DataFacade &facade, const std::vector &phantom_nodes, std::size_t phantom_index, - const std::vector &phantom_indices) + const std::vector &phantom_indices, + const bool calculate_distance) { std::vector weights(phantom_indices.size(), INVALID_EDGE_WEIGHT); std::vector durations(phantom_indices.size(), MAXIMAL_EDGE_DURATION); - std::vector distances_table(phantom_indices.size(), MAXIMAL_EDGE_DISTANCE); + std::vector distances_table(calculate_distance ? phantom_indices.size() : 0, + MAXIMAL_EDGE_DISTANCE); std::vector middle_nodes_table(phantom_indices.size(), SPECIAL_NODEID); // Collect destination (source) nodes into a map @@ -268,12 +270,16 @@ oneToManySearch(SearchEngineData &engine_working_data, const auto path_duration = duration + target_duration; const auto path_distance = distance + target_distance; + EdgeDistance nulldistance = 0; + auto ¤t_distance = + distances_table.empty() ? nulldistance : distances_table[index]; + if (std::tie(path_weight, path_duration, path_distance) < - std::tie(weights[index], durations[index], distances_table[index])) + std::tie(weights[index], durations[index], current_distance)) { weights[index] = path_weight; durations[index] = path_duration; - distances_table[index] = path_distance; + current_distance = path_distance; middle_nodes_table[index] = node; } @@ -434,7 +440,9 @@ void forwardRoutingStep(const DataFacade &facade, : row_idx + column_idx * number_of_sources; auto ¤t_weight = weights_table[location]; auto ¤t_duration = durations_table[location]; - auto ¤t_distance = distances_table[location]; + + EdgeDistance nulldistance = 0; + auto ¤t_distance = distances_table.empty() ? nulldistance : distances_table[location]; // Check if new weight is better auto new_weight = source_weight + target_weight; @@ -529,7 +537,8 @@ manyToManySearch(SearchEngineData &engine_working_data, const DataFacade &facade, const std::vector &phantom_nodes, const std::vector &source_indices, - const std::vector &target_indices) + const std::vector &target_indices, + const bool calculate_distance) { const auto number_of_sources = source_indices.size(); const auto number_of_targets = target_indices.size(); @@ -537,7 +546,8 @@ manyToManySearch(SearchEngineData &engine_working_data, std::vector weights_table(number_of_entries, INVALID_EDGE_WEIGHT); std::vector durations_table(number_of_entries, MAXIMAL_EDGE_DURATION); - std::vector distances_table(number_of_entries, INVALID_EDGE_DISTANCE); + std::vector distances_table(calculate_distance ? number_of_entries : 0, + INVALID_EDGE_DISTANCE); std::vector middle_nodes_table(number_of_entries, SPECIAL_NODEID); std::vector search_space_with_buckets; @@ -626,29 +636,44 @@ manyToManySearch(SearchEngineData &engine_working_data, const std::vector &phantom_nodes, const std::vector &source_indices, const std::vector &target_indices, - const bool /* calculate_distance */, - const bool /* calculate_duration */) + const bool calculate_distance) { if (source_indices.size() == 1) { // TODO: check if target_indices.size() == 1 and do a bi-directional search - return mld::oneToManySearch( - engine_working_data, facade, phantom_nodes, source_indices.front(), target_indices); + return mld::oneToManySearch(engine_working_data, + facade, + phantom_nodes, + source_indices.front(), + target_indices, + calculate_distance); } if (target_indices.size() == 1) { - return mld::oneToManySearch( - engine_working_data, facade, phantom_nodes, target_indices.front(), source_indices); + return mld::oneToManySearch(engine_working_data, + facade, + phantom_nodes, + target_indices.front(), + source_indices, + calculate_distance); } if (target_indices.size() < source_indices.size()) { - return mld::manyToManySearch( - engine_working_data, facade, phantom_nodes, target_indices, source_indices); + return mld::manyToManySearch(engine_working_data, + facade, + phantom_nodes, + target_indices, + source_indices, + calculate_distance); } - return mld::manyToManySearch( - engine_working_data, facade, phantom_nodes, source_indices, target_indices); + return mld::manyToManySearch(engine_working_data, + facade, + phantom_nodes, + source_indices, + target_indices, + calculate_distance); } } // namespace routing_algorithms