diff --git a/include/engine/api/match_api.hpp b/include/engine/api/match_api.hpp index 9016f3b60..1211e2b05 100644 --- a/include/engine/api/match_api.hpp +++ b/include/engine/api/match_api.hpp @@ -101,6 +101,9 @@ class MatchAPI final : public RouteAPI auto waypoint = BaseAPI::MakeWaypoint(phantom); waypoint.values["matchings_index"] = matching_index.sub_matching_index; waypoint.values["waypoint_index"] = matching_index.point_index; + waypoint.values["alternatives_count"] = + sub_matchings[matching_index.sub_matching_index] + .alternatives_count[matching_index.point_index]; waypoints.values.push_back(std::move(waypoint)); } diff --git a/include/engine/map_matching/hidden_markov_model.hpp b/include/engine/map_matching/hidden_markov_model.hpp index 6957240f4..8f1e4d1ff 100644 --- a/include/engine/map_matching/hidden_markov_model.hpp +++ b/include/engine/map_matching/hidden_markov_model.hpp @@ -51,6 +51,7 @@ struct TransitionLogProbability template struct HiddenMarkovModel { std::vector> viterbi; + std::vector> viterbi_reachable; std::vector>> parents; std::vector> path_distances; std::vector> pruned; @@ -65,6 +66,7 @@ template struct HiddenMarkovModel emission_log_probabilities(emission_log_probabilities) { viterbi.resize(candidates_list.size()); + viterbi_reachable.resize(candidates_list.size()); parents.resize(candidates_list.size()); path_distances.resize(candidates_list.size()); pruned.resize(candidates_list.size()); @@ -76,6 +78,7 @@ template struct HiddenMarkovModel if (num_candidates > 0) { viterbi[i].resize(num_candidates); + viterbi_reachable[i].resize(num_candidates); parents[i].resize(num_candidates); path_distances[i].resize(num_candidates); pruned[i].resize(num_candidates); @@ -93,6 +96,7 @@ template struct HiddenMarkovModel for (const auto t : util::irange(initial_timestamp, viterbi.size())) { std::fill(viterbi[t].begin(), viterbi[t].end(), IMPOSSIBLE_LOG_PROB); + std::fill(viterbi_reachable[t].begin(), viterbi_reachable[t].end(), false); std::fill(parents[t].begin(), parents[t].end(), std::make_pair(0u, 0u)); std::fill(path_distances[t].begin(), path_distances[t].end(), 0); std::fill(pruned[t].begin(), pruned[t].end(), true); diff --git a/include/engine/map_matching/sub_matching.hpp b/include/engine/map_matching/sub_matching.hpp index 22c180312..e272423e7 100644 --- a/include/engine/map_matching/sub_matching.hpp +++ b/include/engine/map_matching/sub_matching.hpp @@ -16,6 +16,7 @@ struct SubMatching { std::vector nodes; std::vector indices; + std::vector alternatives_count; double confidence; }; } diff --git a/src/engine/routing_algorithms/map_matching.cpp b/src/engine/routing_algorithms/map_matching.cpp index 421cc9aa2..84f649222 100644 --- a/src/engine/routing_algorithms/map_matching.cpp +++ b/src/engine/routing_algorithms/map_matching.cpp @@ -300,6 +300,7 @@ operator()(const std::shared_ptr facade, { ++sub_matching_begin; } + const auto sub_matching_last_timestamp = parent_timestamp_index; // matchings that only consist of one candidate are invalid if (parent_timestamp_index - sub_matching_begin + 1 < 2) @@ -319,12 +320,8 @@ operator()(const std::shared_ptr facade, std::deque> reconstructed_indices; while (parent_timestamp_index > sub_matching_begin) { - if (model.breakage[parent_timestamp_index]) - { - continue; - } - reconstructed_indices.emplace_front(parent_timestamp_index, parent_candidate_index); + model.viterbi_reachable[parent_timestamp_index][parent_candidate_index] = true; const auto &next = model.parents[parent_timestamp_index][parent_candidate_index]; // make sure we can never get stuck in this loop if (parent_timestamp_index == next.first) @@ -335,12 +332,34 @@ operator()(const std::shared_ptr facade, parent_candidate_index = next.second; } reconstructed_indices.emplace_front(parent_timestamp_index, parent_candidate_index); + model.viterbi_reachable[parent_timestamp_index][parent_candidate_index] = true; if (reconstructed_indices.size() < 2) { sub_matching_begin = sub_matching_end; continue; } + // fill viterbi reachability matrix + for (const auto s_last : + util::irange(0UL, model.viterbi[sub_matching_last_timestamp].size())) + { + parent_timestamp_index = sub_matching_last_timestamp; + parent_candidate_index = s_last; + while (parent_timestamp_index > sub_matching_begin) + { + if (model.viterbi_reachable[parent_timestamp_index][parent_candidate_index] || + model.pruned[parent_timestamp_index][parent_candidate_index]) + { + break; + } + model.viterbi_reachable[parent_timestamp_index][parent_candidate_index] = true; + const auto &next = model.parents[parent_timestamp_index][parent_candidate_index]; + parent_timestamp_index = next.first; + parent_candidate_index = next.second; + } + model.viterbi_reachable[parent_timestamp_index][parent_candidate_index] = true; + } + auto matching_distance = 0.0; auto trace_distance = 0.0; matching.nodes.reserve(reconstructed_indices.size()); @@ -352,6 +371,10 @@ operator()(const std::shared_ptr facade, matching.indices.push_back(timestamp_index); matching.nodes.push_back(candidates_list[timestamp_index][location_index].phantom_node); + matching.alternatives_count.push_back( + std::accumulate(model.viterbi_reachable[timestamp_index].begin(), + model.viterbi_reachable[timestamp_index].end(), + 0)); matching_distance += model.path_distances[timestamp_index][location_index]; } util::for_each_pair(