Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precomputes linestring's segments intervals #51

Merged
merged 12 commits into from
Feb 9, 2023

Conversation

francocipollone
Copy link
Contributor

@francocipollone francocipollone commented Feb 2, 2023

🎉 New feature

Related to #50 #47

Summary

  • LineString's constructor conforms internally a map with <Interval, Segment> where the interval contains the minimum and maximum value of the interval for each one of the segments.
    • So getting the correspondent segment for a given parameter p of the linestring is quite quick.
  • Other improvements:
    • For-loops for the GetClosestPoint methods were replaced by for_each with parallel execution
    • Minor improvements also to avoid copying and relying on references.

Speed up

Benchmark name cpu time[us] cpu time[us] speed up map
main francocipollone/segments_interval
MaliputOsmQueryTime/GetLane/0 0.025 0.022 1.14 SingleLane.osm
MaliputOsmQueryTime/GetLane/1 0.023 0.023 1.00 ArcLane.osm
MaliputOsmQueryTime/GetLane/2 0.024 0.025 0.96 ArcLaneDense.osm
MaliputOsmQueryTime/GetLane/3 0.024 0.022 1.09 Circuit.osm
MaliputOsmQueryTime/Length/0 0.003 0.003 1.00 SingleLane.osm
MaliputOsmQueryTime/Length/1 0.003 0.003 1.00 ArcLane.osm
MaliputOsmQueryTime/Length/2 0.003 0.003 1.00 ArcLaneDense.osm
MaliputOsmQueryTime/Length/3 0.003 0.003 1.00 Circuit.osm
MaliputOsmQueryTime/ToLanePosition/0 5.22 3.15 1.66 SingleLane.osm
MaliputOsmQueryTime/ToLanePosition/1 36 17.8 2.02 ArcLane.osm
MaliputOsmQueryTime/ToLanePosition/2 1447 568 2.55 ArcLaneDense.osm
MaliputOsmQueryTime/ToLanePosition/3 107 35.8 2.99 Circuit.osm
MaliputOsmQueryTime/ToInertialPosition/0 1.68 1.09 1.54 SingleLane.osm
MaliputOsmQueryTime/ToInertialPosition/1 10.2 4.05 2.52 ArcLane.osm
MaliputOsmQueryTime/ToInertialPosition/2 318 117 2.72 ArcLaneDense.osm
MaliputOsmQueryTime/ToInertialPosition/3 20.9 8.09 2.58 Circuit.osm
MaliputOsmQueryTime/GetOrientation/0 1.52 0.935 1.63 SingleLane.osm
MaliputOsmQueryTime/GetOrientation/1 8.81 4.07 2.16 ArcLane.osm
MaliputOsmQueryTime/GetOrientation/2 341 126 2.71 ArcLaneDense.osm
MaliputOsmQueryTime/GetOrientation/3 20.3 7.68 2.64 Circuit.osm
MaliputOsmQueryTime/ToRoadPosition/0 12.5 8.64 1.45 SingleLane.osm
MaliputOsmQueryTime/ToRoadPosition/1 94.1 42 2.24 ArcLane.osm
MaliputOsmQueryTime/ToRoadPosition/2 3532 1354 2.61 ArcLaneDense.osm
MaliputOsmQueryTime/ToRoadPosition/3 1836 665 2.76 Circuit.osm
MaliputOsmQueryTime/FindRoadPositions/0 10.1 7.53 1.34 SingleLane.osm
MaliputOsmQueryTime/FindRoadPositions/1 82 34.9 2.35 ArcLane.osm
MaliputOsmQueryTime/FindRoadPositions/2 2897 1224 2.37 ArcLaneDense.osm
MaliputOsmQueryTime/FindRoadPositions/3 1753 577 3.04 Circuit.osm

Test it

Checklist

  • Signed all commits for DCO
  • Added tests
  • Added example and/or tutorial
  • Updated documentation (as needed)
  • Updated migration guide (as needed)
  • Consider updating Python bindings (if it affects the public API)

Note to maintainers: Remember to use Squash-Merge and edit the commit message to match the pull request summary while retaining Signed-off-by messages.

Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
@francocipollone
Copy link
Contributor Author

@agalbachicar PTAL, still missing some minor docstrings. In the PR's description there is stated the speed ups in query times.

Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
@francocipollone
Copy link
Contributor Author

francocipollone commented Feb 3, 2023

Locally it is building correctly while in GhAction CI it is failing cause using <execution> header and a failed dependency:

  In file included from /usr/include/c++/9/pstl/parallel_backend.h:14,
                   from /usr/include/c++/9/pstl/algorithm_impl.h:25,
                   from /usr/include/c++/9/pstl/glue_execution_defs.h:52,
                   from /usr/include/c++/9/execution:32,
                   from /__w/maliput_sparse/maliput_sparse/ros_ws/src/q0ggbncasvb/maliput_sparse/src/geometry/utility/geometry.cc:65:
  /usr/include/c++/9/pstl/parallel_backend_tbb.h:19:10: fatal error: tbb/blocked_range.h: No such file or directory
     19 | #include <tbb/blocked_range.h>
        |          ^~~~~~~~~~~~~~~~~~~~~

In GCC 9 we need to link against tbb, in GCC 10 it isn't required. (Not sure why it is working locally)

Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
@francocipollone francocipollone marked this pull request as ready for review February 3, 2023 14:32
Copy link
Contributor

@agalbachicar agalbachicar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great improvement! PTAL to some minor comments.

/// A segment of a LineString.
/// A segment is defined by a:
/// - start index: index of the first coordinate of the segment.
/// - end index: index of the last coordinate of the segment, in general it is the start index + 1.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why in general it is the start index + 1 ? Can we add that to the docstring.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this comment edit was not effective. I wanted to say that we should explicitly mention that start_index + 1 is generally used within the LineString constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/// - start index: index of the first coordinate of the segment.
/// - end index: index of the last coordinate of the segment, in general it is the start index + 1.
struct Segment {
/// Defines an interval in the P value of the parametrized LineString.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Defines an interval in the P value of the parametrized LineString.
/// Defines an interval in the @f$ p @f$ value of the parametrized LineString.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/// Defines an interval in the P value of the parametrized LineString.
/// The Less than operator is defined to allow the use of this struct as a key in a collection like std::map.
struct Interval {
// Interval() = default;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should delete.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:D
Done

/// @param min_max Is the minimum and maximum value of the interval.
Interval(double min_max) : min(min_max), max(min_max) {}

// Less than operator.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Less than operator.
/// Less than operator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines 294 to 297
if (remaining_distance < kEpsilon) {
return *line_string_points_length.first;
return start;
}
return *line_string_points_length.first +
remaining_distance / partial_length * (*line_string_points_length.second - *line_string_points_length.first);
return start + d_segment.normalized() * remaining_distance;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we merge this into the following?

return remaining_distance < kEpsilon ? start : start + d_segment.normalized() * remaining_distance;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed
Done.

return {line_string.end() - 1, line_string.end() - 2, line_string.length()};
BoundPointsResult GetBoundPointsAtP(const LineString<CoordinateT>& line_string, double p, double tolerance) {
p = maliput::common::RangeValidator::GetAbsoluteEpsilonValidator(0., line_string.length(), tolerance, kEpsilon)(p);
const auto segment = line_string.segments().at(typename LineString<CoordinateT>::Segment::Interval{p});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the compiler understand the right type conversion if we did?

const auto segment = line_string.segments().at({p});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it does.
Done

Comment on lines 357 to 364
std::for_each(std::execution::par, segments.begin(), segments.end(), [&](const auto& segment) {
const auto& start = line_string[segment.second.idx_start];
const auto& end = line_string[segment.second.idx_end];
const auto current_closest_point_res = GetClosestPointToSegment(Segment3d{start, end}, xyz, tolerance);
if (current_closest_point_res.distance < segment_closest_point_result.distance) {
segment_closest_point_result = current_closest_point_res;
closest_segment = {segment.second.idx_start, segment.second.idx_end, segment.second.p_interval};
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, this is not aligned with parallel execution as there might be race conditions, so I will remove the parallel execution here and use a regular for_each statement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done at 9f81200

Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
agalbachicar
agalbachicar previously approved these changes Feb 7, 2023
Copy link
Contributor

@agalbachicar agalbachicar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
@francocipollone
Copy link
Contributor Author

@agalbachicar , please take a look at 8d2d32b

I found this case when trying to create the meshes for the arc_lane_dense map(The last point of the map is the same at the right before). Even though it reflects a possible wrong creation of the map adding that could solve the issue

Copy link
Contributor

@agalbachicar agalbachicar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to create a unit test for that?

Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
@francocipollone
Copy link
Contributor Author

Is it possible to create a unit test for that?

Check f48371a
Not only did I create the unit test but also provided a logic to remove the duplicated points. There is no point on keep duplicated coordinates.

Signed-off-by: Franco Cipollone <franco.c@ekumenlabs.com>
Copy link
Contributor

@agalbachicar agalbachicar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@francocipollone francocipollone merged commit 1e5e203 into main Feb 9, 2023
@francocipollone francocipollone deleted the francocipollone/segments_interval branch February 9, 2023 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

2 participants