Add timestamp parameters and reset to beginning of breakage
This commit is contained in:
parent
d429485f0c
commit
70703c39f3
@ -99,6 +99,15 @@ void RouteParameters::addHint(const std::string &hint)
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::addTimestamp(const unsigned timestamp)
|
||||
{
|
||||
timestamps.resize(coordinates.size());
|
||||
if (!timestamps.empty())
|
||||
{
|
||||
timestamps.back() = timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
void RouteParameters::setLanguage(const std::string &language_string)
|
||||
{
|
||||
language = language_string;
|
||||
|
@ -63,6 +63,8 @@ struct RouteParameters
|
||||
|
||||
void addHint(const std::string &hint);
|
||||
|
||||
void addTimestamp(const unsigned timestamp);
|
||||
|
||||
void setLanguage(const std::string &language);
|
||||
|
||||
void setGeometryFlag(const bool flag);
|
||||
@ -85,6 +87,7 @@ struct RouteParameters
|
||||
std::string jsonp_parameter;
|
||||
std::string language;
|
||||
std::vector<std::string> hints;
|
||||
std::vector<unsigned> timestamps;
|
||||
std::vector<bool> uturns;
|
||||
std::vector<FixedPointCoordinate> coordinates;
|
||||
};
|
||||
|
@ -172,6 +172,11 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
|
||||
std::vector<double> sub_trace_lengths;
|
||||
Matching::CandidateLists candidates_lists;
|
||||
const auto& input_coords = route_parameters.coordinates;
|
||||
const auto& input_timestamps = route_parameters.timestamps;
|
||||
if (input_timestamps.size() > 0 && input_coords.size() != input_timestamps.size())
|
||||
{
|
||||
return 400;
|
||||
}
|
||||
bool found_candidates = get_candiates(input_coords, sub_trace_lengths, candidates_lists);
|
||||
if (!found_candidates)
|
||||
{
|
||||
@ -181,7 +186,7 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
|
||||
// call the actual map matching
|
||||
JSON::Object debug_info;
|
||||
Matching::SubMatchingList sub_matchings;
|
||||
search_engine_ptr->map_matching(candidates_lists, input_coords, sub_matchings, debug_info);
|
||||
search_engine_ptr->map_matching(candidates_lists, input_coords, input_timestamps, sub_matchings, debug_info);
|
||||
|
||||
if (1 > sub_matchings.size())
|
||||
{
|
||||
|
@ -86,8 +86,8 @@ constexpr static const unsigned max_number_of_candidates = 10;
|
||||
constexpr static const double IMPOSSIBLE_LOG_PROB = -std::numeric_limits<double>::infinity();
|
||||
constexpr static const double MINIMAL_LOG_PROB = -std::numeric_limits<double>::max();
|
||||
constexpr static const unsigned INVALID_STATE = std::numeric_limits<unsigned>::max();
|
||||
// FIXME that should be a time threshold.
|
||||
constexpr static const unsigned MAX_BROKEN_STATES = 6;
|
||||
constexpr static const unsigned MAX_BROKEN_TIME = 180;
|
||||
}
|
||||
|
||||
// implements a hidden markov model map matching algorithm
|
||||
@ -252,14 +252,14 @@ template <class DataFacadeT> class MapMatching final
|
||||
std::vector<std::vector<bool>> pruned;
|
||||
std::vector<bool> breakage;
|
||||
|
||||
const Matching::CandidateLists& timestamp_list;
|
||||
const Matching::CandidateLists& candidates_list;
|
||||
|
||||
|
||||
HiddenMarkovModel(const Matching::CandidateLists& timestamp_list)
|
||||
: breakage(timestamp_list.size())
|
||||
, timestamp_list(timestamp_list)
|
||||
HiddenMarkovModel(const Matching::CandidateLists& candidates_list)
|
||||
: breakage(candidates_list.size())
|
||||
, candidates_list(candidates_list)
|
||||
{
|
||||
for (const auto& l : timestamp_list)
|
||||
for (const auto& l : candidates_list)
|
||||
{
|
||||
viterbi.emplace_back(l.size());
|
||||
parents.emplace_back(l.size());
|
||||
@ -289,13 +289,13 @@ template <class DataFacadeT> class MapMatching final
|
||||
|
||||
unsigned initialize(unsigned initial_timestamp)
|
||||
{
|
||||
BOOST_ASSERT(initial_timestamp < timestamp_list.size());
|
||||
BOOST_ASSERT(initial_timestamp < candidates_list.size());
|
||||
|
||||
do
|
||||
{
|
||||
for (auto s = 0u; s < viterbi[initial_timestamp].size(); ++s)
|
||||
{
|
||||
viterbi[initial_timestamp][s] = log_emission_probability(timestamp_list[initial_timestamp][s].second);
|
||||
viterbi[initial_timestamp][s] = log_emission_probability(candidates_list[initial_timestamp][s].second);
|
||||
parents[initial_timestamp][s] = std::make_pair(initial_timestamp, s);
|
||||
pruned[initial_timestamp][s] = viterbi[initial_timestamp][s] < Matching::MINIMAL_LOG_PROB;
|
||||
|
||||
@ -328,14 +328,15 @@ template <class DataFacadeT> class MapMatching final
|
||||
}
|
||||
|
||||
|
||||
void operator()(const Matching::CandidateLists ×tamp_list,
|
||||
const std::vector<FixedPointCoordinate> coordinate_list,
|
||||
void operator()(const Matching::CandidateLists &candidates_list,
|
||||
const std::vector<FixedPointCoordinate>& trace_coordinates,
|
||||
const std::vector<unsigned>& trace_timestamps,
|
||||
Matching::SubMatchingList& sub_matchings,
|
||||
JSON::Object& _debug_info) const
|
||||
{
|
||||
BOOST_ASSERT(timestamp_list.size() > 0);
|
||||
BOOST_ASSERT(candidates_list.size() > 0);
|
||||
|
||||
HiddenMarkovModel model(timestamp_list);
|
||||
HiddenMarkovModel model(candidates_list);
|
||||
|
||||
unsigned initial_timestamp = model.initialize(0);
|
||||
if (initial_timestamp == Matching::INVALID_STATE)
|
||||
@ -344,15 +345,15 @@ template <class DataFacadeT> class MapMatching final
|
||||
}
|
||||
|
||||
JSON::Array _debug_states;
|
||||
for (unsigned t = 0; t < timestamp_list.size(); t++)
|
||||
for (unsigned t = 0; t < candidates_list.size(); t++)
|
||||
{
|
||||
JSON::Array _debug_timestamps;
|
||||
for (unsigned s = 0; s < timestamp_list[t].size(); s++)
|
||||
for (unsigned s = 0; s < candidates_list[t].size(); s++)
|
||||
{
|
||||
JSON::Object _debug_state;
|
||||
_debug_state.values["transitions"] = JSON::Array();
|
||||
_debug_state.values["coordinate"] = makeJSONArray(timestamp_list[t][s].first.location.lat / COORDINATE_PRECISION,
|
||||
timestamp_list[t][s].first.location.lon / COORDINATE_PRECISION);
|
||||
_debug_state.values["coordinate"] = makeJSONArray(candidates_list[t][s].first.location.lat / COORDINATE_PRECISION,
|
||||
candidates_list[t][s].first.location.lon / COORDINATE_PRECISION);
|
||||
if (t < initial_timestamp)
|
||||
{
|
||||
_debug_state.values["viterbi"] = makeJSONSafe(Matching::IMPOSSIBLE_LOG_PROB);
|
||||
@ -368,24 +369,25 @@ template <class DataFacadeT> class MapMatching final
|
||||
_debug_states.values.push_back(_debug_timestamps);
|
||||
}
|
||||
|
||||
unsigned breakage_begin = std::numeric_limits<unsigned>::max();
|
||||
std::vector<unsigned> split_points;
|
||||
std::vector<unsigned> prev_unbroken_timestamps;
|
||||
prev_unbroken_timestamps.reserve(timestamp_list.size());
|
||||
prev_unbroken_timestamps.reserve(candidates_list.size());
|
||||
prev_unbroken_timestamps.push_back(initial_timestamp);
|
||||
for (auto t = initial_timestamp + 1; t < timestamp_list.size(); ++t)
|
||||
for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
|
||||
{
|
||||
unsigned prev_unbroken_timestamp = prev_unbroken_timestamps.back();
|
||||
const auto& prev_viterbi = model.viterbi[prev_unbroken_timestamp];
|
||||
const auto& prev_pruned = model.pruned[prev_unbroken_timestamp];
|
||||
const auto& prev_unbroken_timestamps_list = timestamp_list[prev_unbroken_timestamp];
|
||||
const auto& prev_coordinate = coordinate_list[prev_unbroken_timestamp];
|
||||
const auto& prev_unbroken_timestamps_list = candidates_list[prev_unbroken_timestamp];
|
||||
const auto& prev_coordinate = trace_coordinates[prev_unbroken_timestamp];
|
||||
|
||||
auto& current_viterbi = model.viterbi[t];
|
||||
auto& current_pruned = model.pruned[t];
|
||||
auto& current_parents = model.parents[t];
|
||||
auto& current_lengths = model.path_lengths[t];
|
||||
const auto& current_timestamps_list = timestamp_list[t];
|
||||
const auto& current_coordinate = coordinate_list[t];
|
||||
const auto& current_timestamps_list = candidates_list[t];
|
||||
const auto& current_coordinate = trace_coordinates[t];
|
||||
|
||||
// compute d_t for this timestamp and the next one
|
||||
for (auto s = 0u; s < prev_viterbi.size(); ++s)
|
||||
@ -396,7 +398,7 @@ template <class DataFacadeT> class MapMatching final
|
||||
for (auto s_prime = 0u; s_prime < current_viterbi.size(); ++s_prime)
|
||||
{
|
||||
// how likely is candidate s_prime at time t to be emitted?
|
||||
const double emission_pr = log_emission_probability(timestamp_list[t][s_prime].second);
|
||||
const double emission_pr = log_emission_probability(candidates_list[t][s_prime].second);
|
||||
double new_value = prev_viterbi[s] + emission_pr;
|
||||
if (current_viterbi[s_prime] > new_value)
|
||||
continue;
|
||||
@ -456,23 +458,47 @@ template <class DataFacadeT> class MapMatching final
|
||||
{
|
||||
BOOST_ASSERT(prev_unbroken_timestamps.size() > 0);
|
||||
|
||||
// save start of breakage -> we need this as split point
|
||||
if (t < breakage_begin)
|
||||
{
|
||||
breakage_begin = t;
|
||||
}
|
||||
|
||||
// remove both ends of the breakage
|
||||
prev_unbroken_timestamps.pop_back();
|
||||
|
||||
bool trace_split = prev_unbroken_timestamps.size() < 1;
|
||||
|
||||
// use temporal information to determine a split if available
|
||||
if (trace_timestamps.size() > 0)
|
||||
{
|
||||
trace_split = trace_split || (trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] > Matching::MAX_BROKEN_TIME);
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_split = trace_split || (t - prev_unbroken_timestamps.back() > Matching::MAX_BROKEN_STATES);
|
||||
}
|
||||
|
||||
// we reached the beginning of the trace and it is still broken
|
||||
// -> split the trace here
|
||||
if (prev_unbroken_timestamps.size() < 1 || t - prev_unbroken_timestamps.back() > Matching::MAX_BROKEN_STATES)
|
||||
if (trace_split)
|
||||
{
|
||||
split_points.push_back(t);
|
||||
split_points.push_back(breakage_begin);
|
||||
// note this preserves everything before t
|
||||
model.clear(t);
|
||||
unsigned new_start = model.initialize(t);
|
||||
model.clear(breakage_begin);
|
||||
unsigned new_start = model.initialize(breakage_begin);
|
||||
// no new start was found -> stop viterbi calculation
|
||||
if (new_start == Matching::INVALID_STATE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
prev_unbroken_timestamps.clear();
|
||||
prev_unbroken_timestamps.push_back(new_start);
|
||||
// Important: We potentially go back here!
|
||||
// However since t+1 > new_start >= breakge_begin
|
||||
// we can only reset trace_coordindates.size() times.
|
||||
t = new_start;
|
||||
breakage_begin = std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -540,7 +566,7 @@ template <class DataFacadeT> class MapMatching final
|
||||
auto location_index = reconstructed_indices[i].second;
|
||||
|
||||
matching.indices[i] = timestamp_index;
|
||||
matching.nodes[i] = timestamp_list[timestamp_index][location_index].first;
|
||||
matching.nodes[i] = candidates_list[timestamp_index][location_index].first;
|
||||
matching.length += model.path_lengths[timestamp_index][location_index];
|
||||
|
||||
_debug_states.values[timestamp_index]
|
||||
|
@ -40,7 +40,7 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
|
||||
{
|
||||
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >>
|
||||
*(query) >> -(uturns);
|
||||
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | u | cmp |
|
||||
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | timestamp | u | cmp |
|
||||
language | instruction | geometry | alt_route | old_API | num_results));
|
||||
|
||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
|
||||
@ -62,6 +62,8 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
|
||||
qi::double_)[boost::bind(&HandlerT::addCoordinate, handler, ::_1)];
|
||||
hint = (-qi::lit('&')) >> qi::lit("hint") >> '=' >>
|
||||
stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
|
||||
timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
|
||||
qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
|
||||
u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
|
||||
qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
|
||||
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
|
||||
@ -83,7 +85,7 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
|
||||
|
||||
qi::rule<Iterator> api_call, query;
|
||||
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
|
||||
hint, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
|
||||
hint, timestamp, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
|
||||
uturns, old_API, num_results;
|
||||
|
||||
HandlerT *handler;
|
||||
|
Loading…
Reference in New Issue
Block a user