From 018a743312312e0bcce0aaabd9bf7c7331d6af42 Mon Sep 17 00:00:00 2001 From: Maxim Pimenov Date: Fri, 9 Dec 2016 17:08:27 +0300 Subject: [PATCH 1/3] [traffic] Added python bindings for traffic serialization. --- traffic/pytraffic/CMakeLists.txt | 15 +++- traffic/pytraffic/bindings.cpp | 129 ++++++++++++++++++++++++++++--- traffic/pytraffic/example.py | 34 ++++++++ traffic/traffic_info.cpp | 5 +- 4 files changed, 168 insertions(+), 15 deletions(-) create mode 100644 traffic/pytraffic/example.py diff --git a/traffic/pytraffic/CMakeLists.txt b/traffic/pytraffic/CMakeLists.txt index b8ec31abf4..987eadf89c 100644 --- a/traffic/pytraffic/CMakeLists.txt +++ b/traffic/pytraffic/CMakeLists.txt @@ -43,12 +43,23 @@ endif() omim_link_libraries( ${PROJECT_NAME} - ${PYTHON_LIBRARIES} - ${Boost_LIBRARIES} + editor + routing + indexer traffic platform geometry + coding base + stats_client + jansson + oauthcpp + protobuf + pugixml + opening_hours + ${PYTHON_LIBRARIES} + ${Boost_LIBRARIES} + ${LIBZ} ) set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") diff --git a/traffic/pytraffic/bindings.cpp b/traffic/pytraffic/bindings.cpp index 7d31ee2e27..02c261358a 100644 --- a/traffic/pytraffic/bindings.cpp +++ b/traffic/pytraffic/bindings.cpp @@ -1,35 +1,133 @@ #include "traffic/traffic_info.hpp" #include "traffic/speed_groups.hpp" +#include "indexer/classificator_loader.hpp" + +#include "platform/platform.hpp" + +#include "base/assert.hpp" +#include "base/logging.hpp" +#include "base/math.hpp" + +#include "std/cstdint.hpp" +#include "std/map.hpp" +#include "std/sstream.hpp" +#include "std/string.hpp" +#include "std/vector.hpp" + #include "pyhelpers/vector_uint8.hpp" #include #include +#include namespace { using namespace boost::python; -vector Serialize(traffic::TrafficInfo::Coloring const & coloring) +struct SegmentSpeeds { - vector data; - traffic::TrafficInfo::SerializeTrafficData(coloring, data); - return data; + SegmentSpeeds() = default; + SegmentSpeeds(double weightedSpeed, double weightedRefSpeed, double weight) + : m_weightedSpeed(weightedSpeed), m_weightedRefSpeed(weightedRefSpeed), m_weight(weight) + { + } + + double m_weightedSpeed = 0; + double m_weightedRefSpeed = 0; + double m_weight = 0; +}; + +using SegmentMapping = map; + +string SegmentSpeedsRepr(SegmentSpeeds const & v) +{ + ostringstream ss; + ss << "SegmentSpeeds(" + << " weighted_speed=" << v.m_weightedSpeed << " weighted_ref_speed=" << v.m_weightedRefSpeed + << " weight=" << v.m_weight << " )"; + return ss.str(); } -traffic::TrafficInfo::Coloring Deserialize(vector const & data) +traffic::TrafficInfo::Coloring TransformToSpeedGroups(SegmentMapping const & segmentMapping) { - traffic::TrafficInfo::Coloring coloring; - traffic::TrafficInfo::DeserializeTrafficData(data, coloring); - return coloring; + double const kEps = 1e-9; + traffic::TrafficInfo::Coloring result; + for (auto const & kv : segmentMapping) + { + double const ws = kv.second.m_weightedSpeed; + double const wrs = kv.second.m_weightedRefSpeed; + double const w = kv.second.m_weight; + if (my::AlmostEqualAbs(w, 0.0, kEps)) + { + LOG(LWARNING, ("A traffic segment has zero weight.")); + continue; + } + double const u = ws / w; + double const v = wrs / w; + bool const uz = my::AlmostEqualAbs(u, 0.0, kEps); + bool const vz = my::AlmostEqualAbs(v, 0.0, kEps); + if (uz && vz) + { + result[kv.first] = traffic::SpeedGroup::TempBlock; + } + else if (vz) + { + LOG(LWARNING, ("A traffic segment has zero reference speed.")); + continue; + } + else + { + double p = 100.0 * u / v; + p = my::clamp(p, 0.0, 100.0); + result[kv.first] = traffic::GetSpeedGroupByPercentage(p); + } + } + return result; } string RoadSegmentIdRepr(traffic::TrafficInfo::RoadSegmentId const & v) { - stringstream ss; + ostringstream ss; ss << "RoadSegmentId(" << v.m_fid << ", " << v.m_idx << ", " << int(v.m_dir) << ")"; return ss.str(); } + +vector GenerateTrafficKeys(string const & mwmPath) +{ + vector result; + traffic::TrafficInfo::ExtractTrafficKeys(mwmPath, result); + return result; +} + +vector GenerateTrafficValues(vector const & keys, + SegmentMapping const & segmentMapping) +{ + traffic::TrafficInfo::Coloring const knownColors = TransformToSpeedGroups(segmentMapping); + traffic::TrafficInfo::Coloring coloring; + traffic::TrafficInfo::CombineColorings(keys, knownColors, coloring); + + vector values(coloring.size()); + + size_t i = 0; + for (auto const & kv : coloring) + { + ASSERT_EQUAL(kv.first, keys[i], ()); + values[i] = kv.second; + ++i; + } + ASSERT_EQUAL(i, values.size(), ()); + + vector buf; + traffic::TrafficInfo::SerializeTrafficValues(values, buf); + return buf; +} + +void LoadClassificator(string const & classifPath) +{ + GetPlatform().SetResourceDir(classifPath); + classificator::Load(); +} } // namespace BOOST_PYTHON_MODULE(pytraffic) @@ -40,10 +138,16 @@ BOOST_PYTHON_MODULE(pytraffic) to_python_converter, vector_uint8t_to_str>(); vector_uint8t_from_python_str(); + class_("SegmentSpeeds", init()) + .def("__repr__", &SegmentSpeedsRepr); + class_("RoadSegmentId", init()) .def("__repr__", &RoadSegmentIdRepr) ; + class_>("RoadSegmentIdVec") + .def(vector_indexing_suite>()); + enum_("SpeedGroup") .value("G0", traffic::SpeedGroup::G0) .value("G1", traffic::SpeedGroup::G1) @@ -59,6 +163,9 @@ BOOST_PYTHON_MODULE(pytraffic) .def(map_indexing_suite()) ; - def("dumps", Serialize); - def("loads", Deserialize); + class_("SegmentMapping").def(map_indexing_suite()); + + def("load_classificator", LoadClassificator); + def("generate_traffic_keys", GenerateTrafficKeys); + def("generate_traffic_values", GenerateTrafficValues); } diff --git a/traffic/pytraffic/example.py b/traffic/pytraffic/example.py new file mode 100644 index 0000000000..6e7493cedb --- /dev/null +++ b/traffic/pytraffic/example.py @@ -0,0 +1,34 @@ +from pytraffic import * +import argparse + +parser = argparse.ArgumentParser(description='Example usage of pytraffic.') +parser.add_argument("--path_to_classificator", dest="path_to_classificator", help="Path to the directory that contains classificator.txt.") +parser.add_argument("--path_to_mwm", dest="path_to_mwm", help="Path to the target mwm file.") + +options = parser.parse_args() +if not options.path_to_classificator or not options.path_to_mwm: + parser.print_help() + exit() + +load_classificator(options.path_to_classificator) + +keys_list = [ + RoadSegmentId(0, 0, 0), + RoadSegmentId(1, 0, 0), + RoadSegmentId(1, 0, 1), +] +keys_vec = RoadSegmentIdVec() +for k in keys_list: + keys_vec.append(k) + +keys_from_mwm = generate_traffic_keys(options.path_to_mwm) + +mapping = { + RoadSegmentId(0, 0, 0):SegmentSpeeds(1.0, 2.0, 3.0), + RoadSegmentId(1, 0, 1):SegmentSpeeds(4.0, 5.0, 6.0), +} +seg_map = SegmentMapping() +for k, v in mapping.iteritems(): + seg_map[k] = v + +buf = generate_traffic_values(keys_vec, seg_map) diff --git a/traffic/traffic_info.cpp b/traffic/traffic_info.cpp index d8ba284675..75b452c12c 100644 --- a/traffic/traffic_info.cpp +++ b/traffic/traffic_info.cpp @@ -193,8 +193,9 @@ void TrafficInfo::ExtractTrafficKeys(string const & mwmPath, vector const & keys, - TrafficInfo::Coloring const & knownColors, TrafficInfo::Coloring & result) +void TrafficInfo::CombineColorings(vector const & keys, + TrafficInfo::Coloring const & knownColors, + TrafficInfo::Coloring & result) { result.clear(); size_t numKnown = 0; From 7a549c17c184e6d76495aa453c2a4273340c7d3a Mon Sep 17 00:00:00 2001 From: Maxim Pimenov Date: Fri, 9 Dec 2016 19:23:40 +0300 Subject: [PATCH 2/3] A cleaner interface for bindings. --- pyhelpers/vector_list_conversion.hpp | 24 +++++++++++++++++++++ traffic/pytraffic/bindings.cpp | 32 +++++++++++++++++----------- traffic/pytraffic/example.py | 12 +++-------- 3 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 pyhelpers/vector_list_conversion.hpp diff --git a/pyhelpers/vector_list_conversion.hpp b/pyhelpers/vector_list_conversion.hpp new file mode 100644 index 0000000000..44ecfa24d3 --- /dev/null +++ b/pyhelpers/vector_list_conversion.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "std/vector.hpp" + +#include + +namespace +{ +using namespace boost::python; + +template +inline vector python_list_to_std_vector(boost::python::object const & iterable) +{ + return vector(boost::python::stl_input_iterator(iterable), + boost::python::stl_input_iterator()); +} + +template +boost::python::list std_vector_to_python_list(vector const & v) +{ + boost::python::object get_iter = boost::python::iterator>(); + return boost::python::list(get_iter(v)); +} +} // namespace diff --git a/traffic/pytraffic/bindings.cpp b/traffic/pytraffic/bindings.cpp index 02c261358a..aacf206f95 100644 --- a/traffic/pytraffic/bindings.cpp +++ b/traffic/pytraffic/bindings.cpp @@ -15,6 +15,7 @@ #include "std/string.hpp" #include "std/vector.hpp" +#include "pyhelpers/vector_list_conversion.hpp" #include "pyhelpers/vector_uint8.hpp" #include @@ -93,26 +94,39 @@ string RoadSegmentIdRepr(traffic::TrafficInfo::RoadSegmentId const & v) return ss.str(); } -vector GenerateTrafficKeys(string const & mwmPath) +boost::python::list GenerateTrafficKeys(string const & mwmPath) { vector result; traffic::TrafficInfo::ExtractTrafficKeys(mwmPath, result); - return result; + return std_vector_to_python_list(result); } -vector GenerateTrafficValues(vector const & keys, - SegmentMapping const & segmentMapping) +vector GenerateTrafficValues(boost::python::list const & keys, + boost::python::dict const & segmentMappingDict) { + vector keysVec = + python_list_to_std_vector(keys); + SegmentMapping segmentMapping; + + boost::python::list mappingKeys = segmentMappingDict.keys(); + for (size_t i = 0; i < len(mappingKeys); ++i) + { + object curArg = segmentMappingDict[mappingKeys[i]]; + if (curArg) + segmentMapping[extract(mappingKeys[i])] = + extract(segmentMappingDict[mappingKeys[i]]); + } + traffic::TrafficInfo::Coloring const knownColors = TransformToSpeedGroups(segmentMapping); traffic::TrafficInfo::Coloring coloring; - traffic::TrafficInfo::CombineColorings(keys, knownColors, coloring); + traffic::TrafficInfo::CombineColorings(keysVec, knownColors, coloring); vector values(coloring.size()); size_t i = 0; for (auto const & kv : coloring) { - ASSERT_EQUAL(kv.first, keys[i], ()); + ASSERT_EQUAL(kv.first, keysVec[i], ()); values[i] = kv.second; ++i; } @@ -159,12 +173,6 @@ BOOST_PYTHON_MODULE(pytraffic) .value("Unknown", traffic::SpeedGroup::Unknown) ; - class_("Coloring") - .def(map_indexing_suite()) - ; - - class_("SegmentMapping").def(map_indexing_suite()); - def("load_classificator", LoadClassificator); def("generate_traffic_keys", GenerateTrafficKeys); def("generate_traffic_values", GenerateTrafficValues); diff --git a/traffic/pytraffic/example.py b/traffic/pytraffic/example.py index 6e7493cedb..79c2e8ff73 100644 --- a/traffic/pytraffic/example.py +++ b/traffic/pytraffic/example.py @@ -1,4 +1,4 @@ -from pytraffic import * +from pytraffic import RoadSegmentId, SegmentSpeeds, load_classificator, generate_traffic_keys, generate_traffic_values import argparse parser = argparse.ArgumentParser(description='Example usage of pytraffic.') @@ -12,14 +12,11 @@ if not options.path_to_classificator or not options.path_to_mwm: load_classificator(options.path_to_classificator) -keys_list = [ +keys = [ RoadSegmentId(0, 0, 0), RoadSegmentId(1, 0, 0), RoadSegmentId(1, 0, 1), ] -keys_vec = RoadSegmentIdVec() -for k in keys_list: - keys_vec.append(k) keys_from_mwm = generate_traffic_keys(options.path_to_mwm) @@ -27,8 +24,5 @@ mapping = { RoadSegmentId(0, 0, 0):SegmentSpeeds(1.0, 2.0, 3.0), RoadSegmentId(1, 0, 1):SegmentSpeeds(4.0, 5.0, 6.0), } -seg_map = SegmentMapping() -for k, v in mapping.iteritems(): - seg_map[k] = v -buf = generate_traffic_values(keys_vec, seg_map) +buf = generate_traffic_values(keys, mapping) From c2918c055d2fbb9a8c3b0d2c347d9962a02ff781 Mon Sep 17 00:00:00 2001 From: Maxim Pimenov Date: Fri, 9 Dec 2016 19:32:34 +0300 Subject: [PATCH 3/3] Review fixes. --- pyhelpers/vector_list_conversion.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyhelpers/vector_list_conversion.hpp b/pyhelpers/vector_list_conversion.hpp index 44ecfa24d3..d39bc91a0c 100644 --- a/pyhelpers/vector_list_conversion.hpp +++ b/pyhelpers/vector_list_conversion.hpp @@ -6,10 +6,8 @@ namespace { -using namespace boost::python; - template -inline vector python_list_to_std_vector(boost::python::object const & iterable) +vector python_list_to_std_vector(boost::python::object const & iterable) { return vector(boost::python::stl_input_iterator(iterable), boost::python::stl_input_iterator());