From 57a34d7a94b7c05e0b780f5c914d7df34400ebe2 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:42:49 -0800 Subject: [PATCH] Ensure Cython bindings only interact with pylibcudf objects (#1523) Follow up to https://github.com/rapidsai/cuspatial/pull/1514 Addressing the review in https://github.com/rapidsai/cuspatial/pull/1514#discussion_r1927600686 by ensuring the Cython bindings return pylibcudf objects where possible instead of python objects (like cudf Python columns) so we can also have better return annotations for these methods where appropriate. Subsequently, the conversion from pylibcudf to cudf Python has been moved to the cuspatial Python layer. Additionally, this PR will be necessary for https://github.com/rapidsai/cudf/pull/17760 not to break cuspatial Authors: - Matthew Roeschke (https://github.com/mroeschke) - Michael Wang (https://github.com/isVoid) - Bradley Dice (https://github.com/bdice) Approvers: - Michael Wang (https://github.com/isVoid) - Bradley Dice (https://github.com/bdice) URL: https://github.com/rapidsai/cuspatial/pull/1523 --- python/cuspatial/cuspatial/_lib/distance.pyx | 26 +++--- .../cuspatial/cuspatial/_lib/intersection.pyx | 45 +++------ .../_lib/linestring_bounding_boxes.pyx | 15 ++- .../cuspatial/_lib/nearest_points.pyx | 19 ++-- .../_lib/pairwise_multipoint_equals_count.pyx | 3 +- .../_lib/pairwise_point_in_polygon.pyx | 3 +- .../cuspatial/_lib/point_in_polygon.pyx | 3 +- .../cuspatial/_lib/points_in_range.pyx | 13 +-- .../cuspatial/_lib/polygon_bounding_boxes.pyx | 15 ++- python/cuspatial/cuspatial/_lib/quadtree.pyx | 36 +++----- python/cuspatial/cuspatial/_lib/spatial.pyx | 5 +- .../cuspatial/cuspatial/_lib/spatial_join.pyx | 91 +++++++------------ .../cuspatial/cuspatial/_lib/trajectory.pyx | 53 ++++------- .../core/binops/distance_dispatch.py | 4 +- .../cuspatial/core/binops/equals_count.py | 3 +- .../cuspatial/core/binops/intersection.py | 28 ++++-- .../cuspatial/core/binpreds/contains.py | 8 +- .../cuspatial/core/spatial/bounding.py | 24 +++-- .../cuspatial/core/spatial/distance.py | 60 +++++++----- .../cuspatial/core/spatial/filtering.py | 10 +- .../cuspatial/core/spatial/indexing.py | 13 ++- .../cuspatial/cuspatial/core/spatial/join.py | 90 +++++++++++------- .../cuspatial/core/spatial/nearest_points.py | 12 ++- .../cuspatial/core/spatial/projection.py | 6 +- python/cuspatial/cuspatial/core/trajectory.py | 35 +++++-- 25 files changed, 313 insertions(+), 307 deletions(-) diff --git a/python/cuspatial/cuspatial/_lib/distance.pyx b/python/cuspatial/cuspatial/_lib/distance.pyx index 6b4b6073f..4a21cfb81 100644 --- a/python/cuspatial/cuspatial/_lib/distance.pyx +++ b/python/cuspatial/cuspatial/_lib/distance.pyx @@ -3,7 +3,6 @@ from libcpp.memory cimport make_shared, shared_ptr, unique_ptr from libcpp.utility cimport move, pair -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column, Table as plc_Table from pylibcudf.libcudf.column.column cimport column from pylibcudf.libcudf.column.column_view cimport column_view @@ -26,7 +25,7 @@ from cuspatial._lib.cpp.types cimport collection_type_id, geometry_type_id from cuspatial._lib.types cimport collection_type_py_to_c -cpdef haversine_distance( +cpdef plc_Column haversine_distance( plc_Column x1, plc_Column y1, plc_Column x2, @@ -42,7 +41,7 @@ cpdef haversine_distance( with nogil: c_result = move(cpp_haversine_distance(c_x1, c_y1, c_x2, c_y2)) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(c_result))) + return plc_Column.from_libcudf(move(c_result)) def directed_hausdorff_distance( @@ -65,17 +64,14 @@ def directed_hausdorff_distance( ) ) - owner_col = Column.from_pylibcudf( - plc_Column.from_libcudf(move(result.first)), - data_ptr_exposed=True - ) + cdef plc_Column owner_col = plc_Column.from_libcudf(move(result.first)) cdef plc_Table plc_owner_table = plc_Table( - [owner_col.to_pylibcudf(mode="read")] * result.second.num_columns() + [owner_col] * result.second.num_columns() ) cdef plc_Table plc_result_table = plc_Table.from_table_view( result.second, plc_owner_table ) - return [Column.from_pylibcudf(col) for col in plc_result_table.columns()] + return plc_result_table.columns() def pairwise_point_distance( @@ -108,7 +104,7 @@ def pairwise_point_distance( c_multipoints_lhs.get()[0], c_multipoints_rhs.get()[0], )) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(c_result))) + return plc_Column.from_libcudf(move(c_result)) def pairwise_linestring_distance( @@ -134,7 +130,7 @@ def pairwise_linestring_distance( c_multilinestring_rhs.get()[0], )) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(c_result))) + return plc_Column.from_libcudf(move(c_result)) def pairwise_point_linestring_distance( @@ -164,7 +160,7 @@ def pairwise_point_linestring_distance( c_multilinestrings.get()[0], )) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(c_result))) + return plc_Column.from_libcudf(move(c_result)) def pairwise_point_polygon_distance( @@ -195,7 +191,7 @@ def pairwise_point_polygon_distance( c_multipoints.get()[0], c_multipolygons.get()[0] )) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(c_result))) + return plc_Column.from_libcudf(move(c_result)) def pairwise_linestring_polygon_distance( @@ -221,7 +217,7 @@ def pairwise_linestring_polygon_distance( c_multilinestrings.get()[0], c_multipolygons.get()[0] )) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(c_result))) + return plc_Column.from_libcudf(move(c_result)) def pairwise_polygon_distance(plc_Column lhs, plc_Column rhs): @@ -244,4 +240,4 @@ def pairwise_polygon_distance(plc_Column lhs, plc_Column rhs): c_lhs.get()[0], c_rhs.get()[0] )) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(c_result))) + return plc_Column.from_libcudf(move(c_result)) diff --git a/python/cuspatial/cuspatial/_lib/intersection.pyx b/python/cuspatial/cuspatial/_lib/intersection.pyx index 9b99cb46a..9935f548c 100644 --- a/python/cuspatial/cuspatial/_lib/intersection.pyx +++ b/python/cuspatial/cuspatial/_lib/intersection.pyx @@ -3,7 +3,6 @@ from libcpp.memory cimport make_shared, shared_ptr from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column from cuspatial._lib.types import CollectionType, GeometryType @@ -26,8 +25,6 @@ def pairwise_linestring_intersection(plc_Column lhs, plc_Column rhs): """ Compute the intersection of two (multi)linestrings. """ - from cuspatial.core._column.geometa import Feature_Enum - cdef linestring_intersection_column_result c_result cdef collection_type_id multi_type = ( (CollectionType.MULTI.value) @@ -52,39 +49,21 @@ def pairwise_linestring_intersection(plc_Column lhs, plc_Column rhs): c_lhs.get()[0], c_rhs.get()[0] )) - geometry_collection_offset = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.geometry_collection_offset)) - ) - - types_buffer = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.types_buffer)) - ) - offset_buffer = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.offset_buffer)) - ) - points = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.points)) + geometry_collection_offset = plc_Column.from_libcudf( + move(c_result.geometry_collection_offset) ) - segments = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.segments)) + types_buffer = plc_Column.from_libcudf(move(c_result.types_buffer)) + offset_buffer = plc_Column.from_libcudf(move(c_result.offset_buffer)) + points = plc_Column.from_libcudf(move(c_result.points)) + segments = plc_Column.from_libcudf(move(c_result.segments)) + lhs_linestring_id = plc_Column.from_libcudf( + move(c_result.lhs_linestring_id) ) - lhs_linestring_id = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.lhs_linestring_id)) - ) - lhs_segment_id = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.lhs_segment_id)) - ) - rhs_linestring_id = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.rhs_linestring_id)) - ) - rhs_segment_id = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.rhs_segment_id)) - ) - - # Map linestring type codes from libcuspatial to cuspatial - types_buffer[types_buffer == GeometryType.LINESTRING.value] = ( - Feature_Enum.LINESTRING.value + lhs_segment_id = plc_Column.from_libcudf(move(c_result.lhs_segment_id)) + rhs_linestring_id = plc_Column.from_libcudf( + move(c_result.rhs_linestring_id) ) + rhs_segment_id = plc_Column.from_libcudf(move(c_result.rhs_segment_id)) return ((geometry_collection_offset, types_buffer, diff --git a/python/cuspatial/cuspatial/_lib/linestring_bounding_boxes.pyx b/python/cuspatial/cuspatial/_lib/linestring_bounding_boxes.pyx index e5bc8e983..d63714019 100644 --- a/python/cuspatial/cuspatial/_lib/linestring_bounding_boxes.pyx +++ b/python/cuspatial/cuspatial/_lib/linestring_bounding_boxes.pyx @@ -3,7 +3,6 @@ from libcpp.memory cimport unique_ptr from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column, Table as plc_Table from pylibcudf.libcudf.column.column_view cimport column_view from pylibcudf.libcudf.table.table cimport table @@ -13,9 +12,12 @@ from cuspatial._lib.cpp.linestring_bounding_boxes cimport ( ) -cpdef linestring_bounding_boxes(plc_Column poly_offsets, - plc_Column x, plc_Column y, - double R): +cpdef list linestring_bounding_boxes( + plc_Column poly_offsets, + plc_Column x, + plc_Column y, + double R +): cdef column_view c_poly_offsets = poly_offsets.view() cdef column_view c_x = x.view() cdef column_view c_y = y.view() @@ -25,7 +27,4 @@ cpdef linestring_bounding_boxes(plc_Column poly_offsets, c_poly_offsets, c_x, c_y, R )) cdef plc_Table plc_table = plc_Table.from_libcudf(move(result)) - return [ - Column.from_pylibcudf(col) - for col in plc_table.columns() - ] + return plc_table.columns() diff --git a/python/cuspatial/cuspatial/_lib/nearest_points.pyx b/python/cuspatial/cuspatial/_lib/nearest_points.pyx index 82f3931c5..a8b7423ac 100644 --- a/python/cuspatial/cuspatial/_lib/nearest_points.pyx +++ b/python/cuspatial/cuspatial/_lib/nearest_points.pyx @@ -2,7 +2,6 @@ from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column from pylibcudf.libcudf.column.column_view cimport column_view @@ -42,22 +41,18 @@ def pairwise_point_linestring_nearest_points( multipoint_geometry_id = None if multipoint_geometry_offset is not None: - multipoint_geometry_id = Column.from_pylibcudf(plc_Column.from_libcudf( - move(c_result.nearest_point_geometry_id.value()))) + multipoint_geometry_id = plc_Column.from_libcudf( + move(c_result.nearest_point_geometry_id.value())) multilinestring_geometry_id = None if multilinestring_geometry_offset is not None: - multilinestring_geometry_id = Column.from_pylibcudf( - plc_Column.from_libcudf( - move(c_result.nearest_linestring_geometry_id.value()) - ) + multilinestring_geometry_id = plc_Column.from_libcudf( + move(c_result.nearest_linestring_geometry_id.value()) ) - segment_id = Column.from_pylibcudf( - plc_Column.from_libcudf(move(c_result.nearest_segment_id)) - ) - point_on_linestring_xy = Column.from_pylibcudf(plc_Column.from_libcudf( - move(c_result.nearest_point_on_linestring_xy))) + segment_id = plc_Column.from_libcudf(move(c_result.nearest_segment_id)) + point_on_linestring_xy = plc_Column.from_libcudf( + move(c_result.nearest_point_on_linestring_xy)) return ( multipoint_geometry_id, diff --git a/python/cuspatial/cuspatial/_lib/pairwise_multipoint_equals_count.pyx b/python/cuspatial/cuspatial/_lib/pairwise_multipoint_equals_count.pyx index b23eab808..f20be58ed 100644 --- a/python/cuspatial/cuspatial/_lib/pairwise_multipoint_equals_count.pyx +++ b/python/cuspatial/cuspatial/_lib/pairwise_multipoint_equals_count.pyx @@ -3,7 +3,6 @@ from libcpp.memory cimport make_shared, shared_ptr, unique_ptr from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column from pylibcudf.libcudf.column.column cimport column @@ -42,4 +41,4 @@ def pairwise_multipoint_equals_count( ) ) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(result))) + return plc_Column.from_libcudf(move(result)) diff --git a/python/cuspatial/cuspatial/_lib/pairwise_point_in_polygon.pyx b/python/cuspatial/cuspatial/_lib/pairwise_point_in_polygon.pyx index 2d8941692..a5456e69b 100644 --- a/python/cuspatial/cuspatial/_lib/pairwise_point_in_polygon.pyx +++ b/python/cuspatial/cuspatial/_lib/pairwise_point_in_polygon.pyx @@ -3,7 +3,6 @@ from libcpp.memory cimport unique_ptr from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column from pylibcudf.libcudf.column.column cimport column from pylibcudf.libcudf.column.column_view cimport column_view @@ -42,4 +41,4 @@ def pairwise_point_in_polygon( ) ) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(result))) + return plc_Column.from_libcudf(move(result)) diff --git a/python/cuspatial/cuspatial/_lib/point_in_polygon.pyx b/python/cuspatial/cuspatial/_lib/point_in_polygon.pyx index 52e89d1e3..790c7e1c8 100644 --- a/python/cuspatial/cuspatial/_lib/point_in_polygon.pyx +++ b/python/cuspatial/cuspatial/_lib/point_in_polygon.pyx @@ -3,7 +3,6 @@ from libcpp.memory cimport unique_ptr from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column from pylibcudf.libcudf.column.column cimport column from pylibcudf.libcudf.column.column_view cimport column_view @@ -42,4 +41,4 @@ def point_in_polygon( ) ) - return Column.from_pylibcudf(plc_Column.from_libcudf(move(result))) + return plc_Column.from_libcudf(move(result)) diff --git a/python/cuspatial/cuspatial/_lib/points_in_range.pyx b/python/cuspatial/cuspatial/_lib/points_in_range.pyx index 181525eae..e9d4a504b 100644 --- a/python/cuspatial/cuspatial/_lib/points_in_range.pyx +++ b/python/cuspatial/cuspatial/_lib/points_in_range.pyx @@ -3,7 +3,6 @@ from libcpp.memory cimport unique_ptr from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column, Table as plc_Table from pylibcudf.libcudf.column.column_view cimport column_view from pylibcudf.libcudf.table.table cimport table @@ -13,7 +12,7 @@ from cuspatial._lib.cpp.points_in_range cimport ( ) -cpdef points_in_range( +cpdef plc_Table points_in_range( double range_min_x, double range_max_x, double range_min_y, @@ -37,12 +36,4 @@ cpdef points_in_range( y_v ) ) - - cdef plc_Table plc_table = plc_Table.from_libcudf(move(c_result)) - return ( - { - name: Column.from_pylibcudf(col) - for name, col in zip(["x", "y"], plc_table.columns()) - }, - None - ) + return plc_Table.from_libcudf(move(c_result)) diff --git a/python/cuspatial/cuspatial/_lib/polygon_bounding_boxes.pyx b/python/cuspatial/cuspatial/_lib/polygon_bounding_boxes.pyx index d3bdf3422..c3923e00e 100644 --- a/python/cuspatial/cuspatial/_lib/polygon_bounding_boxes.pyx +++ b/python/cuspatial/cuspatial/_lib/polygon_bounding_boxes.pyx @@ -3,7 +3,6 @@ from libcpp.memory cimport unique_ptr from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column, Table as plc_Table from pylibcudf.libcudf.column.column_view cimport column_view from pylibcudf.libcudf.table.table cimport table @@ -13,9 +12,12 @@ from cuspatial._lib.cpp.polygon_bounding_boxes cimport ( ) -cpdef polygon_bounding_boxes(plc_Column poly_offsets, - plc_Column ring_offsets, - plc_Column x, plc_Column y): +cpdef list polygon_bounding_boxes( + plc_Column poly_offsets, + plc_Column ring_offsets, + plc_Column x, + plc_Column y, +): cdef column_view c_poly_offsets = poly_offsets.view() cdef column_view c_ring_offsets = ring_offsets.view() cdef column_view c_x = x.view() @@ -26,7 +28,4 @@ cpdef polygon_bounding_boxes(plc_Column poly_offsets, c_poly_offsets, c_ring_offsets, c_x, c_y )) cdef plc_Table table_result = plc_Table.from_libcudf(move(result)) - return [ - Column.from_pylibcudf(col) - for col in table_result.columns() - ] + return table_result.columns() diff --git a/python/cuspatial/cuspatial/_lib/quadtree.pyx b/python/cuspatial/cuspatial/_lib/quadtree.pyx index 0fd6e9da4..d9d84d66b 100644 --- a/python/cuspatial/cuspatial/_lib/quadtree.pyx +++ b/python/cuspatial/cuspatial/_lib/quadtree.pyx @@ -5,7 +5,6 @@ from libcpp.memory cimport unique_ptr from libcpp.pair cimport pair from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column, Table as plc_Table from pylibcudf.libcudf.column.column cimport column from pylibcudf.libcudf.column.column_view cimport column_view @@ -17,12 +16,17 @@ from cuspatial._lib.cpp.quadtree cimport ( ) -cpdef quadtree_on_points(plc_Column x, plc_Column y, - double x_min, double x_max, - double y_min, double y_max, - double scale, - int8_t max_depth, - size_type min_size): +cpdef tuple quadtree_on_points( + plc_Column x, + plc_Column y, + double x_min, + double x_max, + double y_min, + double y_max, + double scale, + int8_t max_depth, + size_type min_size, +): cdef column_view c_x = x.view() cdef column_view c_y = y.view() cdef pair[unique_ptr[column], unique_ptr[table]] result @@ -30,21 +34,7 @@ cpdef quadtree_on_points(plc_Column x, plc_Column y, result = move(cpp_quadtree_on_points( c_x, c_y, x_min, x_max, y_min, y_max, scale, max_depth, min_size )) - cdef plc_Table plc_table = plc_Table.from_libcudf(move(result.second)) - result_names = [ - "key", - "level", - "is_internal_node", - "length", - "offset" - ] return ( - Column.from_pylibcudf(plc_Column.from_libcudf(move(result.first))), - ( - { - name: Column.from_pylibcudf(col) - for name, col in zip(result_names, plc_table.columns()) - }, - None - ) + plc_Column.from_libcudf(move(result.first)), + plc_Table.from_libcudf(move(result.second)) ) diff --git a/python/cuspatial/cuspatial/_lib/spatial.pyx b/python/cuspatial/cuspatial/_lib/spatial.pyx index 473d6408d..20a7fff0d 100644 --- a/python/cuspatial/cuspatial/_lib/spatial.pyx +++ b/python/cuspatial/cuspatial/_lib/spatial.pyx @@ -4,7 +4,6 @@ from libcpp.memory cimport unique_ptr from libcpp.pair cimport pair from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column from pylibcudf.libcudf.column.column cimport column from pylibcudf.libcudf.column.column_view cimport column_view @@ -36,6 +35,6 @@ def sinusoidal_projection( ) return ( - Column.from_pylibcudf(plc_Column.from_libcudf(move(result.first))), - Column.from_pylibcudf(plc_Column.from_libcudf(move(result.second))) + plc_Column.from_libcudf(move(result.first)), + plc_Column.from_libcudf(move(result.second)) ) diff --git a/python/cuspatial/cuspatial/_lib/spatial_join.pyx b/python/cuspatial/cuspatial/_lib/spatial_join.pyx index 61168a10b..50a0993a7 100644 --- a/python/cuspatial/cuspatial/_lib/spatial_join.pyx +++ b/python/cuspatial/cuspatial/_lib/spatial_join.pyx @@ -4,7 +4,6 @@ from libc.stdint cimport int8_t from libcpp.memory cimport unique_ptr from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column, Table as plc_Table from pylibcudf.libcudf.column.column_view cimport column_view from pylibcudf.libcudf.table.table cimport table, table_view @@ -16,14 +15,16 @@ from cuspatial._lib.cpp.spatial_join cimport ( ) -cpdef join_quadtree_and_bounding_boxes(object quadtree, - object bounding_boxes, - double x_min, - double x_max, - double y_min, - double y_max, - double scale, - int8_t max_depth): +cpdef plc_Table join_quadtree_and_bounding_boxes( + object quadtree, + object bounding_boxes, + double x_min, + double x_max, + double y_min, + double y_max, + double scale, + int8_t max_depth +): cdef plc_Table plc_quadtree = plc_Table( [col.to_pylibcudf(mode="read") for col in quadtree._columns] ) @@ -39,27 +40,20 @@ cpdef join_quadtree_and_bounding_boxes(object quadtree, c_bounding_boxes, x_min, x_max, y_min, y_max, scale, max_depth )) - cdef plc_Table plc_table = plc_Table.from_libcudf(move(result)) - return ( - { - name: Column.from_pylibcudf(col) - for name, col in zip( - ["bbox_offset", "quad_offset"], plc_table.columns() - ) - }, - None - ) + return plc_Table.from_libcudf(move(result)) -cpdef quadtree_point_in_polygon(object poly_quad_pairs, - object quadtree, - plc_Column point_indices, - plc_Column points_x, - plc_Column points_y, - plc_Column poly_offsets, - plc_Column ring_offsets, - plc_Column poly_points_x, - plc_Column poly_points_y): +cpdef plc_Table quadtree_point_in_polygon( + object poly_quad_pairs, + object quadtree, + plc_Column point_indices, + plc_Column points_x, + plc_Column points_y, + plc_Column poly_offsets, + plc_Column ring_offsets, + plc_Column poly_points_x, + plc_Column poly_points_y +): cdef plc_Table plc_poly_quad_pairs = plc_Table( [col.to_pylibcudf(mode="read") for col in poly_quad_pairs._columns] ) @@ -88,26 +82,19 @@ cpdef quadtree_point_in_polygon(object poly_quad_pairs, c_poly_points_x, c_poly_points_y )) - cdef plc_Table plc_table = plc_Table.from_libcudf(move(result)) - return ( - { - name: Column.from_pylibcudf(col) - for name, col in zip( - ["polygon_index", "point_index"], plc_table.columns() - ) - }, - None - ) + return plc_Table.from_libcudf(move(result)) -cpdef quadtree_point_to_nearest_linestring(object linestring_quad_pairs, - object quadtree, - plc_Column point_indices, - plc_Column points_x, - plc_Column points_y, - plc_Column linestring_offsets, - plc_Column linestring_points_x, - plc_Column linestring_points_y): +cpdef plc_Table quadtree_point_to_nearest_linestring( + object linestring_quad_pairs, + object quadtree, + plc_Column point_indices, + plc_Column points_x, + plc_Column points_y, + plc_Column linestring_offsets, + plc_Column linestring_points_x, + plc_Column linestring_points_y +): cdef plc_Table plc_quad_pairs = plc_Table( [ col.to_pylibcudf(mode="read") @@ -137,14 +124,4 @@ cpdef quadtree_point_to_nearest_linestring(object linestring_quad_pairs, c_linestring_points_x, c_linestring_points_y )) - cdef plc_Table plc_table = plc_Table.from_libcudf(move(result)) - return ( - { - name: Column.from_pylibcudf(col) - for name, col in zip( - ["point_index", "linestring_index", "distance"], - plc_table.columns() - ) - }, - None - ) + return plc_Table.from_libcudf(move(result)) diff --git a/python/cuspatial/cuspatial/_lib/trajectory.pyx b/python/cuspatial/cuspatial/_lib/trajectory.pyx index 0b4f28ba6..0730b0c11 100644 --- a/python/cuspatial/cuspatial/_lib/trajectory.pyx +++ b/python/cuspatial/cuspatial/_lib/trajectory.pyx @@ -4,7 +4,6 @@ from libcpp.memory cimport unique_ptr from libcpp.pair cimport pair from libcpp.utility cimport move -from cudf.core.column.column import Column from pylibcudf cimport Column as plc_Column, Table as plc_Table from pylibcudf.libcudf.column.column cimport column from pylibcudf.libcudf.column.column_view cimport column_view @@ -18,8 +17,12 @@ from cuspatial._lib.cpp.trajectory cimport ( ) -cpdef derive_trajectories(plc_Column object_id, plc_Column x, - plc_Column y, plc_Column timestamp): +cpdef tuple derive_trajectories( + plc_Column object_id, + plc_Column x, + plc_Column y, + plc_Column timestamp, +): cdef column_view c_id = object_id.view() cdef column_view c_x = x.view() cdef column_view c_y = y.view() @@ -27,23 +30,13 @@ cpdef derive_trajectories(plc_Column object_id, plc_Column x, cdef pair[unique_ptr[table], unique_ptr[column]] result with nogil: result = move(cpp_derive_trajectories(c_id, c_x, c_y, c_ts)) - cdef plc_Table plc_table = plc_Table.from_libcudf(move(result.first)) - first_result = ( - { - name: Column.from_pylibcudf(col) - for name, col in zip( - ["object_id", "x", "y", "timestamp"], plc_table.columns() - ) - }, - None - ) return ( - first_result, - Column.from_pylibcudf(plc_Column.from_libcudf(move(result.second))) + plc_Table.from_libcudf(move(result.first)), + plc_Column.from_libcudf(move(result.second)) ) -cpdef trajectory_bounding_boxes( +cpdef plc_Table trajectory_bounding_boxes( size_type num_trajectories, plc_Column object_id, plc_Column x, @@ -57,21 +50,14 @@ cpdef trajectory_bounding_boxes( result = move(cpp_trajectory_bounding_boxes( num_trajectories, c_id, c_x, c_y )) - cdef plc_Table plc_table = plc_Table.from_libcudf(move(result)) - return ( - { - name: Column.from_pylibcudf(col) - for name, col in zip( - ["x_min", "y_min", "x_max", "y_max"], plc_table.columns() - ) - }, - None - ) + return plc_Table.from_libcudf(move(result)) -cpdef trajectory_distances_and_speeds(size_type num_trajectories, - plc_Column object_id, plc_Column x, - plc_Column y, plc_Column timestamp): +cpdef plc_Table trajectory_distances_and_speeds( + size_type num_trajectories, + plc_Column object_id, plc_Column x, + plc_Column y, plc_Column timestamp +): cdef column_view c_id = object_id.view() cdef column_view c_x = x.view() cdef column_view c_y = y.view() @@ -81,11 +67,4 @@ cpdef trajectory_distances_and_speeds(size_type num_trajectories, result = move(cpp_trajectory_distances_and_speeds( num_trajectories, c_id, c_x, c_y, c_ts )) - cdef plc_Table plc_table = plc_Table.from_libcudf(move(result)) - return ( - { - name: Column.from_pylibcudf(col) - for name, col in zip(["distance", "speed"], plc_table.columns()) - }, - None - ) + return plc_Table.from_libcudf(move(result)) diff --git a/python/cuspatial/cuspatial/core/binops/distance_dispatch.py b/python/cuspatial/cuspatial/core/binops/distance_dispatch.py index a4e9c0c17..868f7a844 100644 --- a/python/cuspatial/cuspatial/core/binops/distance_dispatch.py +++ b/python/cuspatial/cuspatial/core/binops/distance_dispatch.py @@ -1,7 +1,7 @@ # Copyright (c) 2024-2025, NVIDIA CORPORATION import cudf -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column from cuspatial._lib.distance import ( pairwise_linestring_distance, @@ -205,7 +205,7 @@ def __call__(self): range(len(self._res_index)), dtype="int32" ).apply_boolean_mask(self._non_null_mask) - result[scatter_map] = dist + result[scatter_map] = ColumnBase.from_pylibcudf(dist) # If `align==False`, geopandas preserves lhs index. index = None if self._align else self._res_index diff --git a/python/cuspatial/cuspatial/core/binops/equals_count.py b/python/cuspatial/cuspatial/core/binops/equals_count.py index b2d2dd1cd..cb3ebbd68 100644 --- a/python/cuspatial/cuspatial/core/binops/equals_count.py +++ b/python/cuspatial/cuspatial/core/binops/equals_count.py @@ -1,6 +1,7 @@ # Copyright (c) 2023-2025, NVIDIA CORPORATION. import cudf +from cudf.core.column import ColumnBase from cuspatial._lib.pairwise_multipoint_equals_count import ( pairwise_multipoint_equals_count as c_pairwise_multipoint_equals_count, @@ -76,4 +77,4 @@ def pairwise_multipoint_equals_count(lhs, rhs): rhs_column = rhs._column.mpoints._column.to_pylibcudf(mode="read") result = c_pairwise_multipoint_equals_count(lhs_column, rhs_column) - return cudf.Series._from_column(result) + return cudf.Series._from_column(ColumnBase.from_pylibcudf(result)) diff --git a/python/cuspatial/cuspatial/core/binops/intersection.py b/python/cuspatial/cuspatial/core/binops/intersection.py index 67e5ceed6..94dc381d0 100644 --- a/python/cuspatial/cuspatial/core/binops/intersection.py +++ b/python/cuspatial/cuspatial/core/binops/intersection.py @@ -3,11 +3,12 @@ from typing import TYPE_CHECKING import cudf -from cudf.core.column import ListColumn, as_column +from cudf.core.column import ColumnBase, ListColumn, as_column from cuspatial._lib.intersection import ( pairwise_linestring_intersection as c_pairwise_linestring_intersection, ) +from cuspatial._lib.types import GeometryType from cuspatial.core._column.geocolumn import GeoColumn from cuspatial.core._column.geometa import Feature_Enum, GeoMeta from cuspatial.utils.column_utils import ( @@ -83,15 +84,30 @@ def pairwise_linestring_intersection( points, segments, ) = geoms + geometry_collection_offset = ColumnBase.from_pylibcudf( + geometry_collection_offset + ) + types_buffer = ColumnBase.from_pylibcudf(types_buffer) + # Map linestring type codes from libcuspatial to cuspatial + types_buffer[ + types_buffer == GeometryType.LINESTRING.value + ] = Feature_Enum.LINESTRING.value + offset_buffer = ColumnBase.from_pylibcudf(offset_buffer) + points = ColumnBase.from_pylibcudf(points) + segments = ColumnBase.from_pylibcudf(segments) # Organize the look back ids into list column - (lhs_linestring_id, lhs_segment_id, rhs_linestring_id, rhs_segment_id,) = [ - ListColumn( + def id_from_pylibcudf(id_, offset_col): + col = ColumnBase.from_pylibcudf(id_) + return ListColumn( data=None, - dtype=cudf.ListDtype(id_.dtype), - size=len(geometry_collection_offset) - 1, - children=(geometry_collection_offset, id_), + dtype=cudf.ListDtype(col.dtype), + size=len(offset_col) - 1, + children=(offset_col, col), ) + + lhs_linestring_id, lhs_segment_id, rhs_linestring_id, rhs_segment_id = [ + id_from_pylibcudf(id_, geometry_collection_offset) for id_ in look_back_ids ] diff --git a/python/cuspatial/cuspatial/core/binpreds/contains.py b/python/cuspatial/cuspatial/core/binpreds/contains.py index ba330e98b..0b85e6e35 100644 --- a/python/cuspatial/cuspatial/core/binpreds/contains.py +++ b/python/cuspatial/cuspatial/core/binpreds/contains.py @@ -4,7 +4,7 @@ import cudf from cudf import DataFrame, Series -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column import cuspatial from cuspatial._lib.pairwise_point_in_polygon import ( @@ -106,7 +106,7 @@ def _brute_force_contains_properly(points, polygons): ) result = DataFrame( pip_bitmap_column_to_binary_array( - polygon_bitmap_column=pip_result, + polygon_bitmap_column=ColumnBase.from_pylibcudf(pip_result), width=len(polygons.polygons.part_offset) - 1, ) ) @@ -155,7 +155,9 @@ def _pairwise_contains_properly(points, polygons): # point) pair where the point is contained properly by the polygon. We can # use this to create a dataframe with only (polygon, point) pairs that # satisfy the relationship. - pip_result = cudf.Series._from_column(result_column).astype("bool") + pip_result = cudf.Series._from_column( + ColumnBase.from_pylibcudf(result_column) + ).astype("bool") trues = pip_result[pip_result].index true_pairs = cudf.DataFrame( { diff --git a/python/cuspatial/cuspatial/core/spatial/bounding.py b/python/cuspatial/cuspatial/core/spatial/bounding.py index ab06bfd55..82eb77320 100644 --- a/python/cuspatial/cuspatial/core/spatial/bounding.py +++ b/python/cuspatial/cuspatial/core/spatial/bounding.py @@ -1,7 +1,7 @@ # Copyright (c) 2022-2025, NVIDIA CORPORATION. from cudf import DataFrame -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column from cuspatial._lib.linestring_bounding_boxes import ( linestring_bounding_boxes as cpp_linestring_bounding_boxes, @@ -66,11 +66,14 @@ def polygon_bounding_boxes(polygons: GeoSeries): dict( zip( column_names, - cpp_polygon_bounding_boxes( - as_column(poly_offsets).to_pylibcudf(mode="read"), - as_column(ring_offsets).to_pylibcudf(mode="read"), - as_column(x).to_pylibcudf(mode="read"), - as_column(y).to_pylibcudf(mode="read"), + ( + ColumnBase.from_pylibcudf(col) + for col in cpp_polygon_bounding_boxes( + as_column(poly_offsets).to_pylibcudf(mode="read"), + as_column(ring_offsets).to_pylibcudf(mode="read"), + as_column(x).to_pylibcudf(mode="read"), + as_column(y).to_pylibcudf(mode="read"), + ) ), ) ) @@ -127,4 +130,11 @@ def linestring_bounding_boxes(linestrings: GeoSeries, expansion_radius: float): expansion_radius, ) - return DataFrame._from_data(dict(zip(column_names, results))) + return DataFrame._from_data( + dict( + zip( + column_names, + (ColumnBase.from_pylibcudf(col) for col in results), + ) + ) + ) diff --git a/python/cuspatial/cuspatial/core/spatial/distance.py b/python/cuspatial/cuspatial/core/spatial/distance.py index 23a74ec00..dc5864886 100644 --- a/python/cuspatial/cuspatial/core/spatial/distance.py +++ b/python/cuspatial/cuspatial/core/spatial/distance.py @@ -2,7 +2,7 @@ import cudf from cudf import DataFrame, Series -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column from cuspatial._lib.distance import ( directed_hausdorff_distance as cpp_directed_hausdorff_distance, @@ -95,7 +95,9 @@ def directed_hausdorff_distance(multipoints: GeoSeries): # the column label of each column in result should be its int position # e.g. a dict of {0: result[0], 1, result[1], ...} - return DataFrame._from_data(dict(enumerate(result))) + return DataFrame._from_data( + dict(enumerate(ColumnBase.from_pylibcudf(col) for col in result)) + ) def haversine_distance(p1: GeoSeries, p2: GeoSeries): @@ -152,15 +154,15 @@ def haversine_distance(p1: GeoSeries, p2: GeoSeries): p2_lon = p2.points.x._column p2_lat = p2.points.y._column - return cudf.Series._from_data( - { - "None": cpp_haversine_distance( + return cudf.Series._from_column( + ColumnBase.from_pylibcudf( + cpp_haversine_distance( p1_lon.to_pylibcudf(mode="read"), p1_lat.to_pylibcudf(mode="read"), p2_lon.to_pylibcudf(mode="read"), p2_lat.to_pylibcudf(mode="read"), ) - } + ) ) @@ -227,11 +229,13 @@ def pairwise_point_distance(points1: GeoSeries, points2: GeoSeries): ) = _extract_point_column_and_collection_type(points2) return Series._from_column( - cpp_pairwise_point_distance( - lhs_point_collection_type, - rhs_point_collection_type, - lhs_column.to_pylibcudf(mode="read"), - rhs_column.to_pylibcudf(mode="read"), + ColumnBase.from_pylibcudf( + cpp_pairwise_point_distance( + lhs_point_collection_type, + rhs_point_collection_type, + lhs_column.to_pylibcudf(mode="read"), + rhs_column.to_pylibcudf(mode="read"), + ) ) ) @@ -301,9 +305,11 @@ def pairwise_linestring_distance( return cudf.Series(dtype="float64") return Series._from_column( - cpp_pairwise_linestring_distance( - multilinestrings1.lines.column().to_pylibcudf(mode="read"), - multilinestrings2.lines.column().to_pylibcudf(mode="read"), + ColumnBase.from_pylibcudf( + cpp_pairwise_linestring_distance( + multilinestrings1.lines.column().to_pylibcudf(mode="read"), + multilinestrings2.lines.column().to_pylibcudf(mode="read"), + ) ) ) @@ -418,14 +424,14 @@ def pairwise_point_linestring_distance( point_collection_type, ) = _extract_point_column_and_collection_type(points) - return Series._from_data( - { - None: c_pairwise_point_linestring_distance( + return Series._from_column( + ColumnBase.from_pylibcudf( + c_pairwise_point_linestring_distance( point_collection_type, point_column.to_pylibcudf(mode="read"), linestrings.lines.column().to_pylibcudf(mode="read"), ) - } + ) ) @@ -503,14 +509,14 @@ def pairwise_point_polygon_distance(points: GeoSeries, polygons: GeoSeries): ) = _extract_point_column_and_collection_type(points) polygon_column = polygons.polygons.column() - return Series._from_data( - { - None: c_pairwise_point_polygon_distance( + return Series._from_column( + ColumnBase.from_pylibcudf( + c_pairwise_point_polygon_distance( point_collection_type, points_column.to_pylibcudf(mode="read"), polygon_column.to_pylibcudf(mode="read"), ) - } + ) ) @@ -591,7 +597,9 @@ def pairwise_linestring_polygon_distance( polygon_column = polygons.polygons.column().to_pylibcudf(mode="read") return Series._from_column( - c_pairwise_line_poly_dist(linestrings_column, polygon_column) + ColumnBase.from_pylibcudf( + c_pairwise_line_poly_dist(linestrings_column, polygon_column) + ) ) @@ -663,8 +671,10 @@ def pairwise_polygon_distance(polygons1: GeoSeries, polygons2: GeoSeries): polygon1_column = polygons1.polygons.column().to_pylibcudf(mode="read") polygon2_column = polygons2.polygons.column().to_pylibcudf(mode="read") - return Series._from_data( - {None: c_pairwise_polygon_distance(polygon1_column, polygon2_column)} + return Series._from_column( + ColumnBase.from_pylibcudf( + c_pairwise_polygon_distance(polygon1_column, polygon2_column) + ) ) diff --git a/python/cuspatial/cuspatial/core/spatial/filtering.py b/python/cuspatial/cuspatial/core/spatial/filtering.py index 2e10af0ee..5e47c5eee 100644 --- a/python/cuspatial/cuspatial/core/spatial/filtering.py +++ b/python/cuspatial/cuspatial/core/spatial/filtering.py @@ -1,7 +1,7 @@ # Copyright (c) 2022-2025, NVIDIA CORPORATION. from cudf import DataFrame -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column from cuspatial._lib import points_in_range from cuspatial.core.geoseries import GeoSeries @@ -51,7 +51,13 @@ def points_in_spatial_window(points: GeoSeries, min_x, max_x, min_y, max_y): xs = as_column(points.points.x).to_pylibcudf(mode="read") ys = as_column(points.points.y).to_pylibcudf(mode="read") + plc_table = points_in_range.points_in_range( + min_x, max_x, min_y, max_y, xs, ys + ) res_xy = DataFrame._from_data( - *points_in_range.points_in_range(min_x, max_x, min_y, max_y, xs, ys) + { + name: ColumnBase.from_pylibcudf(col) + for name, col in zip(["x", "y"], plc_table.columns()) + } ).interleave_columns() return GeoSeries.from_points_xy(res_xy) diff --git a/python/cuspatial/cuspatial/core/spatial/indexing.py b/python/cuspatial/cuspatial/core/spatial/indexing.py index 9bab115c0..199c03d49 100644 --- a/python/cuspatial/cuspatial/core/spatial/indexing.py +++ b/python/cuspatial/cuspatial/core/spatial/indexing.py @@ -3,7 +3,7 @@ import warnings from cudf import DataFrame, Series -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column from cuspatial import GeoSeries from cuspatial._lib.quadtree import ( @@ -187,4 +187,13 @@ def quadtree_on_points( max_depth, max_size, ) - return Series._from_column(key_to_point), DataFrame._from_data(*quadtree) + result_names = ["key", "level", "is_internal_node", "length", "offset"] + return ( + Series._from_column(ColumnBase.from_pylibcudf(key_to_point)), + DataFrame._from_data( + { + name: ColumnBase.from_pylibcudf(col) + for name, col in zip(result_names, quadtree.columns()) + } + ), + ) diff --git a/python/cuspatial/cuspatial/core/spatial/join.py b/python/cuspatial/cuspatial/core/spatial/join.py index f9323d367..6353ae88b 100644 --- a/python/cuspatial/cuspatial/core/spatial/join.py +++ b/python/cuspatial/cuspatial/core/spatial/join.py @@ -3,7 +3,7 @@ import warnings from cudf import DataFrame -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column from cuspatial import GeoSeries from cuspatial._lib import spatial_join @@ -86,7 +86,8 @@ def point_in_polygon(points: GeoSeries, polygons: GeoSeries): ) result = DataFrame( pip_bitmap_column_to_binary_array( - polygon_bitmap_column=result, width=len(poly_offsets) - 1 + polygon_bitmap_column=ColumnBase.from_pylibcudf(result), + width=len(poly_offsets) - 1, ) ) @@ -152,17 +153,23 @@ def join_quadtree_and_bounding_boxes( + "scale {}. Clamping to minimum scale".format(min_scale) ) + plc_result = spatial_join.join_quadtree_and_bounding_boxes( + quadtree, + bounding_boxes, + x_min, + x_max, + y_min, + y_max, + max(scale, min_scale), + max_depth, + ) return DataFrame._from_data( - *spatial_join.join_quadtree_and_bounding_boxes( - quadtree, - bounding_boxes, - x_min, - x_max, - y_min, - y_max, - max(scale, min_scale), - max_depth, - ) + { + name: ColumnBase.from_pylibcudf(col) + for name, col in zip( + ["bbox_offset", "quad_offset"], plc_result.columns() + ) + } ) @@ -232,18 +239,24 @@ def quadtree_point_in_polygon( poly_points_x = as_column(polygon_data.x).to_pylibcudf(mode="read") poly_points_y = as_column(polygon_data.y).to_pylibcudf(mode="read") + plc_result = spatial_join.quadtree_point_in_polygon( + poly_quad_pairs, + quadtree, + point_indices._column.to_pylibcudf(mode="read"), + points_x, + points_y, + poly_offsets, + ring_offsets, + poly_points_x, + poly_points_y, + ) return DataFrame._from_data( - *spatial_join.quadtree_point_in_polygon( - poly_quad_pairs, - quadtree, - point_indices._column.to_pylibcudf(mode="read"), - points_x, - points_y, - poly_offsets, - ring_offsets, - poly_points_x, - poly_points_y, - ) + { + name: ColumnBase.from_pylibcudf(col) + for name, col in zip( + ["polygon_index", "point_index"], plc_result.columns() + ) + } ) @@ -315,17 +328,24 @@ def quadtree_point_to_nearest_linestring( ) linestring_offsets = as_column(linestrings.lines.part_offset) + plc_result = spatial_join.quadtree_point_to_nearest_linestring( + linestring_quad_pairs, + quadtree, + as_column(point_indices, dtype="uint32").to_pylibcudf(mode="read"), + points_x, + points_y, + as_column(linestring_offsets, dtype="uint32").to_pylibcudf( + mode="read" + ), + linestring_points_x, + linestring_points_y, + ) return DataFrame._from_data( - *spatial_join.quadtree_point_to_nearest_linestring( - linestring_quad_pairs, - quadtree, - as_column(point_indices, dtype="uint32").to_pylibcudf(mode="read"), - points_x, - points_y, - as_column(linestring_offsets, dtype="uint32").to_pylibcudf( - mode="read" - ), - linestring_points_x, - linestring_points_y, - ) + { + name: ColumnBase.from_pylibcudf(col) + for name, col in zip( + ["point_index", "linestring_index", "distance"], + plc_result.columns(), + ) + } ) diff --git a/python/cuspatial/cuspatial/core/spatial/nearest_points.py b/python/cuspatial/cuspatial/core/spatial/nearest_points.py index 0aaf65b25..4c72bdb08 100644 --- a/python/cuspatial/cuspatial/core/spatial/nearest_points.py +++ b/python/cuspatial/cuspatial/core/spatial/nearest_points.py @@ -1,7 +1,7 @@ # Copyright (c) 2024-2025, NVIDIA CORPORATION. import cudf -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column import cuspatial._lib.nearest_points as nearest_points from cuspatial.core._column.geocolumn import GeoColumn @@ -100,16 +100,20 @@ def pairwise_point_linestring_nearest_points( ) nearest_points_on_linestring = GeoColumn._from_points_xy( - point_on_linestring_xy + ColumnBase.from_pylibcudf(point_on_linestring_xy) ) if not point_geometry_id: point_geometry_id = as_column(0, length=len(points), dtype="int32") + else: + point_geometry_id = ColumnBase.from_pylibcudf(point_geometry_id) data = { "point_geometry_id": point_geometry_id, - "linestring_geometry_id": linestring_geometry_id, - "segment_id": segment_id, + "linestring_geometry_id": ColumnBase.from_pylibcudf( + linestring_geometry_id + ), + "segment_id": ColumnBase.from_pylibcudf(segment_id), "geometry": nearest_points_on_linestring, } diff --git a/python/cuspatial/cuspatial/core/spatial/projection.py b/python/cuspatial/cuspatial/core/spatial/projection.py index 6f3ccc595..c522720f2 100644 --- a/python/cuspatial/cuspatial/core/spatial/projection.py +++ b/python/cuspatial/cuspatial/core/spatial/projection.py @@ -1,6 +1,7 @@ # Copyright (c) 2022-2025, NVIDIA CORPORATION. from cudf import DataFrame +from cudf.core.column import ColumnBase from cuspatial._lib.spatial import ( sinusoidal_projection as cpp_sinusoidal_projection, @@ -55,6 +56,9 @@ def sinusoidal_projection(origin_lon, origin_lat, lonlat: GeoSeries): lonlat.points.y._column.to_pylibcudf(mode="read"), ) lonlat_transformed = DataFrame( - {"x": result[0], "y": result[1]} + { + "x": ColumnBase.from_pylibcudf(result[0]), + "y": ColumnBase.from_pylibcudf(result[1]), + } ).interleave_columns() return GeoSeries.from_points_xy(lonlat_transformed) diff --git a/python/cuspatial/cuspatial/core/trajectory.py b/python/cuspatial/cuspatial/core/trajectory.py index cac055513..faa4f56c1 100644 --- a/python/cuspatial/cuspatial/core/trajectory.py +++ b/python/cuspatial/cuspatial/core/trajectory.py @@ -3,7 +3,7 @@ import numpy as np from cudf import DataFrame, Series -from cudf.core.column import as_column +from cudf.core.column import ColumnBase, as_column from cuspatial import GeoSeries from cuspatial._lib.trajectory import ( @@ -75,7 +75,18 @@ def derive_trajectories(object_ids, points: GeoSeries, timestamps): objects, traj_offsets = cpp_derive_trajectories( object_ids, xs, ys, timestamps ) - return DataFrame._from_data(*objects), Series._from_column(traj_offsets) + objects_df = DataFrame._from_data( + { + name: ColumnBase.from_pylibcudf(col) + for name, col in zip( + ["object_id", "x", "y", "timestamp"], objects.columns() + ) + } + ) + traj_offsets_ser = Series._from_column( + ColumnBase.from_pylibcudf(traj_offsets) + ) + return objects_df, traj_offsets_ser def trajectory_bounding_boxes(num_trajectories, object_ids, points: GeoSeries): @@ -144,8 +155,16 @@ def trajectory_bounding_boxes(num_trajectories, object_ids, points: GeoSeries): ) xs = as_column(points.points.x).to_pylibcudf(mode="read") ys = as_column(points.points.y).to_pylibcudf(mode="read") + plc_result = cpp_trajectory_bounding_boxes( + num_trajectories, object_ids, xs, ys + ) return DataFrame._from_data( - *cpp_trajectory_bounding_boxes(num_trajectories, object_ids, xs, ys) + { + name: ColumnBase.from_pylibcudf(col) + for name, col in zip( + ["x_min", "y_min", "x_max", "y_max"], plc_result.columns() + ) + } ) @@ -204,10 +223,14 @@ def trajectory_distances_and_speeds( timestamps = normalize_timestamp_column( as_column(timestamps) ).to_pylibcudf(mode="read") + plc_result = cpp_trajectory_distances_and_speeds( + num_trajectories, object_ids, xs, ys, timestamps + ) df = DataFrame._from_data( - *cpp_trajectory_distances_and_speeds( - num_trajectories, object_ids, xs, ys, timestamps - ) + { + name: ColumnBase.from_pylibcudf(col) + for name, col in zip(["distance", "speed"], plc_result.columns()) + } ) df.index.name = "trajectory_id" return df