diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 4f0fabf18..f9048cb6b 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -122,6 +122,7 @@ add_library(cuspatial src/spatial/haversine.cu src/spatial/hausdorff.cu src/spatial/linestring_distance.cu + src/spatial/point_distance.cu src/spatial/lonlat_to_cartesian.cu src/trajectory/derive_trajectories.cu src/trajectory/trajectory_bounding_boxes.cu diff --git a/cpp/benchmarks/hausdorff_benchmark.cpp b/cpp/benchmarks/hausdorff_benchmark.cpp index 6f59f042d..8ff80c331 100644 --- a/cpp/benchmarks/hausdorff_benchmark.cpp +++ b/cpp/benchmarks/hausdorff_benchmark.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include diff --git a/cpp/include/cuspatial/hausdorff.hpp b/cpp/include/cuspatial/distance/hausdorff.hpp similarity index 100% rename from cpp/include/cuspatial/hausdorff.hpp rename to cpp/include/cuspatial/distance/hausdorff.hpp diff --git a/cpp/include/cuspatial/haversine.hpp b/cpp/include/cuspatial/distance/haversine.hpp similarity index 100% rename from cpp/include/cuspatial/haversine.hpp rename to cpp/include/cuspatial/distance/haversine.hpp diff --git a/cpp/include/cuspatial/distances/linestring_distance.hpp b/cpp/include/cuspatial/distance/linestring_distance.hpp similarity index 100% rename from cpp/include/cuspatial/distances/linestring_distance.hpp rename to cpp/include/cuspatial/distance/linestring_distance.hpp diff --git a/cpp/include/cuspatial/distance/point_distance.hpp b/cpp/include/cuspatial/distance/point_distance.hpp new file mode 100644 index 000000000..82c6fc520 --- /dev/null +++ b/cpp/include/cuspatial/distance/point_distance.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace cuspatial { + +/** + * @ingroup distance + * @brief Compute pairwise point-to-point Cartesian distance + * + * @param points1_x Column of x-coordinates of the first point in each pair + * @param points1_y Column of y-coordinates of the first point in each pair + * @param points2_x Column of x-coordinates of the second point in each pair + * @param points2_y Column of y-coordinates of the second point in each pair + * @param stream The CUDA stream to use for device memory operations and kernel launches + * @return Column of distances between each pair of input points + */ +std::unique_ptr pairwise_point_distance( + cudf::column_view const& points1_x, + cudf::column_view const& points1_y, + cudf::column_view const& points2_x, + cudf::column_view const& points2_y, + rmm::mr::device_memory_resource* mr = rmm::mr::get_current_device_resource()); + +} // namespace cuspatial diff --git a/cpp/include/cuspatial/experimental/detail/linestring_distance.cuh b/cpp/include/cuspatial/experimental/detail/linestring_distance.cuh index a67dc55c1..b3882419d 100644 --- a/cpp/include/cuspatial/experimental/detail/linestring_distance.cuh +++ b/cpp/include/cuspatial/experimental/detail/linestring_distance.cuh @@ -152,15 +152,13 @@ void pairwise_linestring_distance(OffsetIterator linestring1_offsets_first, typename std::iterator_traits::value_type>(), "Inputs and output must have floating point value type."); - static_assert(detail::is_same::value_type::value_type, - typename std::iterator_traits::value_type>(), + static_assert(detail::is_same::value_type>(), "Inputs and output must have the same value type."); static_assert(detail::is_same, typename std::iterator_traits::value_type, typename std::iterator_traits::value_type>(), - "Inputs must be cuspatial::cartesian_2d"); + "All input types must be cuspatial::cartesian_2d with the same value type"); auto const num_linestring_pairs = thrust::distance(linestring1_offsets_first, linestring1_offsets_last); diff --git a/cpp/include/cuspatial/experimental/detail/point_distance.cuh b/cpp/include/cuspatial/experimental/detail/point_distance.cuh new file mode 100644 index 000000000..ce9d03819 --- /dev/null +++ b/cpp/include/cuspatial/experimental/detail/point_distance.cuh @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include + +namespace cuspatial { + +template +OutputIt pairwise_point_distance(Cart2dItA points1_first, + Cart2dItA points1_last, + Cart2dItB points2_first, + OutputIt distances_first, + rmm::cuda_stream_view stream) +{ + using T = typename std::iterator_traits::value_type::value_type; + + static_assert( + detail::is_floating_point::value_type::value_type, + typename std::iterator_traits::value_type>(), + "Inputs and output must be floating point types."); + + static_assert(detail::is_same::value_type>(), + "Inputs and output must be the same types."); + + static_assert(detail::is_same, + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type>(), + "All Input types must be cuspatial::cartesian_2d with the same value type"); + + return thrust::transform(rmm::exec_policy(stream), + points1_first, + points1_last, + points2_first, + distances_first, + [] __device__(auto p1, auto p2) { + auto v = p1 - p2; + return std::sqrt(dot(v, v)); + }); +} + +} // namespace cuspatial diff --git a/cpp/include/cuspatial/experimental/linestring_distance.cuh b/cpp/include/cuspatial/experimental/linestring_distance.cuh index 9000e090b..563a0a771 100644 --- a/cpp/include/cuspatial/experimental/linestring_distance.cuh +++ b/cpp/include/cuspatial/experimental/linestring_distance.cuh @@ -21,6 +21,7 @@ namespace cuspatial { /** + * @ingroup distance * @copybrief cuspatial::pairwise_linestring_distance * * The shortest distance between two linestrings is defined as the shortest distance diff --git a/cpp/include/cuspatial/experimental/point_distance.cuh b/cpp/include/cuspatial/experimental/point_distance.cuh new file mode 100644 index 000000000..51260df8c --- /dev/null +++ b/cpp/include/cuspatial/experimental/point_distance.cuh @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace cuspatial { + +/** + * @ingroup distance + * @copybrief cuspatial::pairwise_point_distance + * + * @tparam Cart2dItA iterator type for point array of the first point of each pair. Must meet + * the requirements of [LegacyRandomAccessIterator][LinkLRAI] and be device-accessible. + * @tparam Cart2dItB iterator type for point array of the second point of each pair. Must meet + * the requirements of [LegacyRandomAccessIterator][LinkLRAI] and be device-accessible. + * @tparam OutputIt iterator type for output array. Must meet the requirements of + * [LegacyRandomAccessIterator][LinkLRAI], be mutable and be device-accessible. + * + * @param points1_first beginning of range of the first point of each pair + * @param points1_last end of range of the first point of each pair + * @param points2_first beginning of range of the second point of each pair + * @param distances_first beginning iterator to output + * @param stream The CUDA stream to use for device memory operations and kernel launches + * @return Output iterator to one past the last element in the output range + * + * @pre all input iterators for coordinates must have a `value_type` of `cuspatial::cartesian_2d`. + * @pre all scalar types must be floating point types, and must be the same type for all input + * iterators and output iterators. + * + * [LinkLRAI]: https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator + * "LegacyRandomAccessIterator" + */ +template +OutputIt pairwise_point_distance(Cart2dItA points1_first, + Cart2dItA points1_last, + Cart2dItB points2_first, + OutputIt distances_first, + rmm::cuda_stream_view stream = rmm::cuda_stream_default); + +} // namespace cuspatial + +#include diff --git a/cpp/include/doxygen_groups.h b/cpp/include/doxygen_groups.h index e552cfa01..3aa55c48e 100644 --- a/cpp/include/doxygen_groups.h +++ b/cpp/include/doxygen_groups.h @@ -48,6 +48,7 @@ * @{ * @brief Distance computation APIs * + * @file point_distance.hpp * @file linestring_distance.hpp * @file linestring_distance.cuh * @file hausdorff.hpp diff --git a/cpp/src/spatial/point_distance.cu b/cpp/src/spatial/point_distance.cu new file mode 100644 index 000000000..b42d22ae5 --- /dev/null +++ b/cpp/src/spatial/point_distance.cu @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace cuspatial { +namespace detail { +struct pairwise_point_distance_functor { + template + std::enable_if_t::value, std::unique_ptr> operator()( + cudf::column_view const& points1_x, + cudf::column_view const& points1_y, + cudf::column_view const& points2_x, + cudf::column_view const& points2_y, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) + { + auto distances = cudf::make_numeric_column(cudf::data_type{cudf::type_to_id()}, + points1_x.size(), + cudf::mask_state::UNALLOCATED, + stream, + mr); + + auto points1_it = make_cartesian_2d_iterator(points1_x.begin(), points1_y.begin()); + auto points2_it = make_cartesian_2d_iterator(points2_x.begin(), points2_y.begin()); + + pairwise_point_distance(points1_it, + points1_it + points1_x.size(), + points2_it, + distances->mutable_view().begin(), + stream); + + return distances; + } + + template + std::enable_if_t::value, std::unique_ptr> operator()( + Args&&...) + { + CUSPATIAL_FAIL("Point distances only supports floating point coordinates."); + } +}; + +std::unique_ptr pairwise_point_distance(cudf::column_view const& points1_x, + cudf::column_view const& points1_y, + cudf::column_view const& points2_x, + cudf::column_view const& points2_y, + rmm::cuda_stream_view stream, + rmm::mr::device_memory_resource* mr) +{ + CUSPATIAL_EXPECTS(points1_x.size() == points1_y.size() and + points2_x.size() == points2_y.size() and points1_x.size() == points2_x.size(), + "Mismatch number of coordinate or number of points."); + + CUSPATIAL_EXPECTS(points1_x.type() == points1_y.type() and + points2_x.type() == points2_y.type() and points1_x.type() == points2_x.type(), + "The types of point coordinates arrays mismatch."); + CUSPATIAL_EXPECTS(not points1_x.has_nulls() and not points1_y.has_nulls() and + not points2_x.has_nulls() and not points2_y.has_nulls(), + "The coordinate columns cannot have nulls."); + + if (points1_x.size() == 0) { return cudf::empty_like(points1_x); } + + return cudf::type_dispatcher(points1_x.type(), + pairwise_point_distance_functor{}, + points1_x, + points1_y, + points2_x, + points2_y, + stream, + mr); +} + +} // namespace detail + +std::unique_ptr pairwise_point_distance(cudf::column_view const& points1_x, + cudf::column_view const& points1_y, + cudf::column_view const& points2_x, + cudf::column_view const& points2_y, + rmm::mr::device_memory_resource* mr) +{ + return detail::pairwise_point_distance( + points1_x, points1_y, points2_x, points2_y, rmm::cuda_stream_default, mr); +} + +} // namespace cuspatial diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 0299491de..dab1ee9b8 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -77,6 +77,9 @@ ConfigureTest(POLYLINE_BBOX_TEST ConfigureTest(POLYGON_BBOX_TEST spatial/polygon_bbox_test.cu) +ConfigureTest(POINT_DISTANCE_TEST + spatial/point_distance_test.cpp) + ConfigureTest(LINESTRING_DISTANCE_TEST spatial/linestring_distance_test.cpp spatial/linestring_distance_test_medium.cpp) @@ -105,6 +108,9 @@ ConfigureTest(SPATIAL_WINDOW_POINT_TEST ConfigureTest(HAVERSINE_TEST_EXP experimental/spatial/haversine_test.cu) +ConfigureTest(POINT_DISTANCE_TEST_EXP + experimental/spatial/point_distance_test.cu) + ConfigureTest(HAUSDORFF_TEST_EXP experimental/spatial/hausdorff_test.cu) diff --git a/cpp/tests/experimental/spatial/point_distance_test.cu b/cpp/tests/experimental/spatial/point_distance_test.cu new file mode 100644 index 000000000..c80efcfcc --- /dev/null +++ b/cpp/tests/experimental/spatial/point_distance_test.cu @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace cuspatial { + +template +struct PairwisePointDistanceTest : public ::testing::Test { +}; + +template +auto compute_point_distance_host(Cart2DVec const& point1, Cart2DVec const& point2) +{ + using Cart2D = typename Cart2DVec::value_type; + using T = typename Cart2D::value_type; + thrust::host_vector h_point1(point1); + thrust::host_vector h_point2(point2); + auto pair_iter = + thrust::make_zip_iterator(thrust::make_tuple(h_point1.begin(), h_point2.begin())); + auto result_iter = thrust::make_transform_iterator(pair_iter, [](auto p) { + auto p0 = thrust::get<0>(p); + auto p1 = thrust::get<1>(p); + return std::sqrt(dot(p0 - p1, p0 - p1)); + }); + + return thrust::host_vector(result_iter, result_iter + point1.size()); +} + +using TestTypes = ::testing::Types; + +TYPED_TEST_CASE(PairwisePointDistanceTest, TestTypes); + +TYPED_TEST(PairwisePointDistanceTest, Empty) +{ + using T = TypeParam; + using Cart2D = cartesian_2d; + using Cart2DVec = std::vector; + + rmm::device_vector points1{}; + rmm::device_vector points2{}; + + rmm::device_vector expected{}; + rmm::device_vector got(points1.size()); + + auto ret_it = + pairwise_point_distance(points1.begin(), points1.end(), points2.begin(), got.begin()); + + EXPECT_EQ(expected, got); + EXPECT_EQ(expected.size(), std::distance(got.begin(), ret_it)); +} + +TYPED_TEST(PairwisePointDistanceTest, OnePair) +{ + using T = TypeParam; + using Cart2D = cartesian_2d; + using Cart2DVec = std::vector; + + rmm::device_vector points1{Cart2DVec{{1.0, 1.0}}}; + rmm::device_vector points2{Cart2DVec{{0.0, 0.0}}}; + + rmm::device_vector expected{std::vector{std::sqrt(T{2.0})}}; + rmm::device_vector got(points1.size()); + + auto ret_it = + pairwise_point_distance(points1.begin(), points1.end(), points2.begin(), got.begin()); + + EXPECT_EQ(expected, got); + EXPECT_EQ(expected.size(), std::distance(got.begin(), ret_it)); +} + +template +struct RandomPointGenerator { + using Cart2D = cartesian_2d; + thrust::minstd_rand rng{}; + thrust::random::normal_distribution norm_dist{}; + + Cart2D __device__ operator()(size_t const& i) + { + rng.discard(i); + return Cart2D{norm_dist(rng), norm_dist(rng)}; + } +}; + +TYPED_TEST(PairwisePointDistanceTest, ManyRandom) +{ + using T = TypeParam; + using Cart2D = cartesian_2d; + using Cart2DVec = std::vector; + + std::size_t constexpr num_points = 1000; + + rmm::device_vector points1(num_points); + rmm::device_vector points2(num_points); + + auto counting_iter1 = thrust::make_counting_iterator(0); + auto counting_iter2 = thrust::make_counting_iterator(num_points); + + thrust::transform( + counting_iter1, counting_iter1 + num_points, points1.begin(), RandomPointGenerator{}); + thrust::transform( + counting_iter2, counting_iter2 + num_points, points2.begin(), RandomPointGenerator{}); + + auto expected = compute_point_distance_host(points1, points2); + rmm::device_vector got(points1.size()); + + auto ret_it = + pairwise_point_distance(points1.begin(), points1.end(), points2.begin(), got.begin()); + thrust::host_vector hgot(got); + + if constexpr (std::is_same_v) { + EXPECT_THAT(expected, ::testing::Pointwise(::testing::FloatEq(), hgot)); + } else { + EXPECT_THAT(expected, ::testing::Pointwise(::testing::DoubleEq(), hgot)); + } + EXPECT_EQ(expected.size(), std::distance(got.begin(), ret_it)); +} + +TYPED_TEST(PairwisePointDistanceTest, CompareWithShapely) +{ + using T = TypeParam; + using Cart2D = cartesian_2d; + using Cart2DVec = std::vector; + + std::vector x1{ + -12.309831056315302, -7.927059559371418, -49.95705839647165, -1.0512464476733485, + -89.39777525663895, -32.460148393873666, -20.64749623324501, 74.88373211296442, + -3.566633537053898, -91.4320392524529, 1.68283845329249, 30.90993923507801, + 2.5208716416609267, -47.13990142514067, -89.60387010381702, 15.799301259524867, + -22.8887289692815, 81.6430657985936, 28.324072604115624, -43.3201792789866, + 31.15072850958005, -90.9256331022774, -17.077973750390452, -88.54243712973691, + -83.67679143413889, -78.86701538797912, 60.11416346218348, 38.38679261335849, + 86.29202143733288, 90.51425714428673, -72.13954336543273, -29.909309579787713, + -72.27943372189681, 49.182311914851205, -84.50393600760954, -94.33250533960667, + -9.932568319346647, 36.99556837875937, -24.20862704113279, -50.442042319693705, + -59.14098804172897, 30.673225738449172, 48.67403790478693, -63.207315558126545, + 29.52859942242645, 26.173903500998197, 47.79243983907904, -99.38850933058964, + -83.31147453301942, 5.8413331217636255, -47.87029604603307, 95.82254403897923, + -55.52829900834991, 74.87973107553039, -84.05457104705182, -95.87736100367613, + -6.480112617573386, -78.09036923042659, 62.14707651291427, -43.34499838125344, + 77.42752654240155, 12.530763429172254, 97.98997832862835, -51.389571363066, + 59.66745813871337, 65.98475889051292, 30.40020778235388, -49.595509308751595, + 9.930123176564942, -19.283736893878867, -78.06236247946624, 63.68142858698178, + 79.46252260195803, 54.24426311960122, 30.458402886352822, 70.7820673095687, + -15.306354680748024, 91.01665772140062, -32.765892351019666, -72.46623073604916, + 58.863272100444334, -41.35480445335994, -61.06943341086172, 81.15104128608479, + -77.69660768219927, 95.47462923834442, -97.46155919360085, -81.54704046899158, + 84.9228534190681, -16.082575320922533, 52.509864091786355, 63.78396723518307, + 13.605239448412032, -63.70301611378514, -63.10763374202178, -61.108649551804895, + 57.266357913172385, -46.96569013769979, -43.636365011489566, -29.306746287827558}; + std::vector y1{ + -18.051875936208862, -72.61500308351708, -23.919317289360777, 74.04449323147637, + 27.003656419402276, 5.131923603252009, 14.381495553187262, -44.998590378882795, + 66.15308743061799, 31.82686362809011, 60.19621369406618, 36.02100660419922, + -18.164297228344505, 23.06381468579426, -34.39959102364766, -80.65093614662105, + -50.66614351982265, 30.696539385917852, -62.06159838829518, -55.67574678891346, + 2.2570284921564987, 49.260913129155036, -69.70290379728544, -14.168007892316037, + 87.743587998508, -88.40683092249026, -78.23312582934655, 18.950081576813904, + -13.001178290210335, -88.72165572783072, 29.13236030074242, 0.9643364439866353, + -58.14148269328302, 98.23977047259831, 87.65596263514071, -68.42627074347195, + -61.49539737381592, 95.22412232012014, -71.3663413078797, -87.93028627383005, + -63.70741871892348, 1.83023166369769, -44.184879390345245, -29.212266921068498, + 36.63070498793903, 90.55120945758097, 35.40957933073132, -53.484664102448285, + 85.05271776288717, 80.18938384135001, -21.313832146230382, -64.49346600820266, + -72.18007667511924, 50.73463806168728, 7.319811593578507, -56.54419097667299, + -80.58912509276239, 6.9148441008914485, -22.67913193215382, 75.95466324740005, + 69.60650343179027, 27.61785095385285, -17.798865714702472, -78.36406107867042, + 6.59132839160077, 64.32222103875719, 55.24725933014744, -53.49018275541756, + -71.57964472201111, -9.671216230543001, -29.999576747551593, -54.15829040618368, + 29.253521698849028, 57.83102910157538, 76.77316185511351, -54.755703196886174, + 58.71741301597688, -89.00648352439477, -62.572264098389354, 55.118081589496626, + -72.80219811987917, 56.12298345685937, -9.073644079329679, 87.3857422229443, + 16.65929971566098, -91.77505633845232, -99.4775802747735, 6.657482305470497, + 19.82536215719839, -22.918311016363912, 30.170484267010387, 83.6666865961853, + -91.70882742463144, 78.70726479431833, 86.04667133973348, -83.58460594914955, + 84.27888264842167, 6.374228239422575, 62.58260784755962, -87.64421055779096}; + + std::vector x2{ + -69.89840831561355, 78.8460456024616, 39.85341596822734, -24.391223974913235, + 13.303395979112231, -12.113621295331923, 65.76955972393912, 32.88000233887396, + 75.15679902070009, 70.42968479275325, -70.48373074669782, -67.41906709787041, + 24.0317463752441, 15.6825064869063, 22.786346338534358, -20.418849974209763, + 34.82105661248487, 38.24867453316148, -25.835471974453984, -99.8181927392706, + 89.84785718125181, 92.62449528299297, -15.692938009982782, 42.32594734729251, + -60.14762773795758, 74.97034158301297, 49.83345296858048, -8.799811548418369, + 35.12809596314472, 93.18344995215058, -94.67426883200939, 52.863378156989384, + 80.55592370229223, -9.708518300250157, 58.19902373613033, 94.71328595396487, + -41.956496383879006, -99.23900353260521, -96.8820547539014, -61.540850851797046, + 10.60351610840815, -86.06663137958869, -19.76183018904282, -52.98140516951296, + -60.77170988936312, -67.64765557651907, 45.61193823583003, 56.92515530750559, + -33.35973933318071, -51.94527984432248, -14.582250347543601, -96.83073470861669, + -47.25698648583708, 48.904375839188006, 14.554162511314495, 38.237373081363344, + -32.7325518620032, 57.537241341535015, -70.50257367880944, -83.11435173667108, + 1.3843207970826832, -61.35647094743536, 43.70708320820875, -81.93488230360825, + -53.098660448910465, 70.16656087048054, 0.7197864636628637, 92.59459361315123, + -77.37226816319428, -32.66885376463454, 34.32370196646004, 71.72963476414482, + 1.5234779242439433, 3.0626652169396085, -1.600973288116736, -1.875116500268692, + 24.115900341387686, -6.818007491235834, -37.57206985691543, 46.48919986671669, + 99.81587509298548, 26.961573147884856, -57.411420876126954, -78.90146907605978, + 37.2322492476274, 67.99231943510561, 64.95985406157519, -21.195261701977287, + 78.89518238318205, -95.50952525706322, 76.75637507677297, -63.30961059551444, + 88.07294705390709, 12.963110252847354, -59.3400766172247, 18.016669829562915, + 0.024732013514316975, -47.68463698812436, -16.12846919710843, 57.85570255646779}; + + std::vector y2{ + 96.98573446222625, -58.675433421313485, -15.58533007526851, -14.697644147821276, + 85.96236693008059, 38.92770099339309, 19.791693980620906, 27.483461653596166, + 53.91447892576453, 75.83100042363395, 17.73746513670771, 51.50105094020323, + 33.83904611309756, -9.59805189545494, 27.567402061211244, 33.72816965802343, + 48.98821930718205, -14.861794980690213, 0.13287706149869294, 35.05682115680253, + 88.14369170856402, -20.655621067301244, -36.15962607484525, 23.463908856814932, + 95.93206680397306, 10.936188747304243, -76.64604957338365, -44.27118733203363, + -17.066191002518682, 51.827990165726675, -55.472330987826744, 82.31391457552668, + -99.25207116240846, -8.9622361202783, -14.764596152666753, 35.51101965248979, + -7.515215371057382, -12.734669471901016, -76.18168200736743, -58.82174033449078, + -64.55998759489724, -66.29491004534883, 96.90488209719925, -42.97997451919843, + -31.865981559056365, -96.36343702487376, -84.20827193890962, 26.79428452012931, + 62.912038904465774, -87.227673692568, 11.2934368901489, -65.442146916886, + 85.68799018964843, 61.94678236143925, 83.46238187197174, 21.333768673112008, + 61.8718601660381, -35.70805034839669, 68.43167377857928, -18.400251392936294, + 25.277688476279536, -74.94714347783905, 2.391028130810602, -78.06742777647494, + 73.16329191776757, -5.425513550228256, -17.11543472509981, -21.571671681683625, + 60.95981137578463, -87.30779120172515, 46.07464276698177, -26.735186694206213, + 77.34113840661823, -10.89097657623882, -7.483005212073712, -24.163324686785494, + 66.03877277717585, 46.514678630068175, 86.52324722682492, 23.88758093704468, + 32.70460360118328, 47.3873043949026, -40.72743971179719, 96.60257606822059, + -93.1284937647867, -70.26297209791194, 94.52718104748459, 68.27804048047095, + -74.27404656785302, -21.16650114972075, -34.93847763736745, 66.55335171298651, + -88.44856487882186, -23.53818606503958, -29.02780534888051, -29.346481830318815, + 74.28318391238213, -38.37789665677865, 56.28623833724116, -81.09317815145866}; + + std::vector expected{ + 128.64717656028176, 87.88562670763609, 90.19632281028372, 91.76013021796666, + 118.4215357030851, 39.44788631062081, 86.58624490836462, 83.77327247860025, + 79.6690804001798, 167.7366440763836, 83.73027552297903, 99.54006861093508, + 56.276686562837135, 70.80573751073386, 128.34122090714868, 119.97639069191793, + 115.15820154183437, 62.91768450568626, 82.47065566268454, 106.88509910638807, + 104.02822613477268, 196.4153033352887, 33.57186030542483, 136.17156536458378, + 24.91330426477482, 183.12555244130633, 10.402491013960068, 78.8891909881514, + 51.325155608916646, 140.57498906651185, 87.55436962189877, 116.056329846112, + 158.26789618636312, 122.3127143880106, 175.65336769339257, 215.7342613973661, + 62.764576137605516, 173.82450721651924, 72.83278521088664, 31.152704497923047, + 69.74971493014701, 135.16371248533227, 156.8113160405468, 17.14989841904493, + 113.33993969348232, 209.1400727201678, 119.63772368951071, 175.72328059917774, + 54.63868144260578, 177.1094683844075, 46.59751045319419, 192.6556145241176, + 158.08460123131488, 28.29189388239395, 124.5848038188644, 155.08622923365692, + 144.85966618486546, 142.16736573734084, 160.92578604203126, 102.39361006963875, + 88.02052587541618, 126.40767969785988, 57.91601260573419, 30.546751247397513, + 130.95046326396607, 69.87298439379285, 78.21308650467851, 145.7285720718672, + 158.70858501146054, 78.78197209323828, 135.71261679147338, 28.579717281106852, + 91.58009372078648, 85.68704702725647, 90.14934991196503, 78.83501748640491, + 40.09634022929284, 167.14546691120552, 149.17295612658907, 122.98674172809133, + 113.17597316247064, 68.87263271597341, 31.86446035391618, 160.31767244865998, + 158.94024585517036, 34.900531808173085, 253.01889830507722, 86.25213267010419, + 94.2922665997649, 79.44626620532313, 69.47712008431841, 128.24056985459816, + 74.53904203761351, 127.79603731531678, 115.13613538697125, 95.93013225849919, + 58.10781125509778, 44.75789949605465, 28.21929483784659, 87.40828630126103}; + + rmm::device_vector dx1(x1), dy1(y1), dx2(x2), dy2(y2); + rmm::device_vector got(dx1.size()); + + auto p1_begin = make_cartesian_2d_iterator(dx1.begin(), dy1.begin()); + auto p2_begin = make_cartesian_2d_iterator(dx2.begin(), dy2.begin()); + + auto ret_it = pairwise_point_distance(p1_begin, p1_begin + dx1.size(), p2_begin, got.begin()); + + thrust::host_vector hgot(got); + + if constexpr (std::is_same_v) { + EXPECT_THAT(expected, ::testing::Pointwise(::testing::FloatEq(), hgot)); + } else { + EXPECT_THAT(expected, ::testing::Pointwise(::testing::DoubleEq(), hgot)); + } + EXPECT_EQ(expected.size(), std::distance(got.begin(), ret_it)); +} + +} // namespace cuspatial diff --git a/cpp/tests/spatial/hausdorff_test.cpp b/cpp/tests/spatial/hausdorff_test.cpp index 665619285..9a165a652 100644 --- a/cpp/tests/spatial/hausdorff_test.cpp +++ b/cpp/tests/spatial/hausdorff_test.cpp @@ -15,8 +15,8 @@ */ #include +#include #include -#include #include #include diff --git a/cpp/tests/spatial/haversine_test.cpp b/cpp/tests/spatial/haversine_test.cpp index 80fa38d1b..373dea484 100644 --- a/cpp/tests/spatial/haversine_test.cpp +++ b/cpp/tests/spatial/haversine_test.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ +#include #include -#include #include #include diff --git a/cpp/tests/spatial/linestring_distance_test.cpp b/cpp/tests/spatial/linestring_distance_test.cpp index 87d77e6e9..80edf1b6e 100644 --- a/cpp/tests/spatial/linestring_distance_test.cpp +++ b/cpp/tests/spatial/linestring_distance_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include diff --git a/cpp/tests/spatial/linestring_distance_test_medium.cpp b/cpp/tests/spatial/linestring_distance_test_medium.cpp index d99433f1d..0f0752d3d 100644 --- a/cpp/tests/spatial/linestring_distance_test_medium.cpp +++ b/cpp/tests/spatial/linestring_distance_test_medium.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include diff --git a/cpp/tests/spatial/point_distance_test.cpp b/cpp/tests/spatial/point_distance_test.cpp new file mode 100644 index 000000000..76588a4a1 --- /dev/null +++ b/cpp/tests/spatial/point_distance_test.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include + +#include +#include + +namespace cuspatial { + +using namespace cudf; +using namespace cudf::test; + +template +struct PairwisePointDistanceTest : public ::testing::Test { +}; + +using TestTypes = ::testing::Types; + +TYPED_TEST_CASE(PairwisePointDistanceTest, TestTypes); + +TYPED_TEST(PairwisePointDistanceTest, Empty) +{ + using T = TypeParam; + + auto x1 = fixed_width_column_wrapper{}; + auto y1 = fixed_width_column_wrapper{}; + auto x2 = fixed_width_column_wrapper{}; + auto y2 = fixed_width_column_wrapper{}; + + auto expect = fixed_width_column_wrapper{}; + + auto got = pairwise_point_distance(x1, y1, x2, y2); + + CUDF_TEST_EXPECT_COLUMNS_EQUIVALENT(expect, *got); +} + +struct PairwisePointDistanceTestThrow : public ::testing::Test { +}; + +TEST_F(PairwisePointDistanceTestThrow, SizeMismatch) +{ + auto x1 = fixed_width_column_wrapper{1, 2, 3}; + auto y1 = fixed_width_column_wrapper{1, 2, 3}; + auto x2 = fixed_width_column_wrapper{}; + auto y2 = fixed_width_column_wrapper{}; + + auto expect = fixed_width_column_wrapper{}; + + EXPECT_THROW(pairwise_point_distance(x1, y1, x2, y2), cuspatial::logic_error); +} + +TEST_F(PairwisePointDistanceTestThrow, SizeMismatch2) +{ + auto x1 = fixed_width_column_wrapper{}; + auto y1 = fixed_width_column_wrapper{1, 2, 3}; + auto x2 = fixed_width_column_wrapper{1, 2, 3}; + auto y2 = fixed_width_column_wrapper{1, 2, 3}; + + auto expect = fixed_width_column_wrapper{}; + + EXPECT_THROW(pairwise_point_distance(x1, y1, x2, y2), cuspatial::logic_error); +} + +TEST_F(PairwisePointDistanceTestThrow, TypeMismatch) +{ + auto x1 = fixed_width_column_wrapper{1, 2, 3}; + auto y1 = fixed_width_column_wrapper{1, 2, 3}; + auto x2 = fixed_width_column_wrapper{1, 2, 3}; + auto y2 = fixed_width_column_wrapper{1, 2, 3}; + + auto expect = fixed_width_column_wrapper{}; + + EXPECT_THROW(pairwise_point_distance(x1, y1, x2, y2), cuspatial::logic_error); +} + +TEST_F(PairwisePointDistanceTestThrow, TypeMismatch2) +{ + auto x1 = fixed_width_column_wrapper{1, 2, 3}; + auto y1 = fixed_width_column_wrapper{1, 2, 3}; + auto x2 = fixed_width_column_wrapper{1, 2, 3}; + auto y2 = fixed_width_column_wrapper{1, 2, 3}; + + auto expect = fixed_width_column_wrapper{}; + + EXPECT_THROW(pairwise_point_distance(x1, y1, x2, y2), cuspatial::logic_error); +} + +TEST_F(PairwisePointDistanceTestThrow, ContainsNull) +{ + auto x1 = fixed_width_column_wrapper{{1, 2, 3}, {1, 0, 1}}; + auto y1 = fixed_width_column_wrapper{1, 2, 3}; + auto x2 = fixed_width_column_wrapper{1, 2, 3}; + auto y2 = fixed_width_column_wrapper{1, 2, 3}; + + auto expect = fixed_width_column_wrapper{}; + + EXPECT_THROW(pairwise_point_distance(x1, y1, x2, y2), cuspatial::logic_error); +} + +} // namespace cuspatial diff --git a/python/cuspatial/cuspatial/_lib/cpp/distance/__init__.pxd b/python/cuspatial/cuspatial/_lib/cpp/distance/__init__.pxd new file mode 100644 index 000000000..e69de29bb diff --git a/python/cuspatial/cuspatial/_lib/cpp/distance/__init__.pyx b/python/cuspatial/cuspatial/_lib/cpp/distance/__init__.pyx new file mode 100644 index 000000000..e69de29bb diff --git a/python/cuspatial/cuspatial/_lib/cpp/hausdorff.pxd b/python/cuspatial/cuspatial/_lib/cpp/distance/hausdorff.pxd similarity index 80% rename from python/cuspatial/cuspatial/_lib/cpp/hausdorff.pxd rename to python/cuspatial/cuspatial/_lib/cpp/distance/hausdorff.pxd index 90fd80da1..6f5fc69e3 100644 --- a/python/cuspatial/cuspatial/_lib/cpp/hausdorff.pxd +++ b/python/cuspatial/cuspatial/_lib/cpp/distance/hausdorff.pxd @@ -6,7 +6,8 @@ from cudf._lib.cpp.column.column cimport column from cudf._lib.cpp.column.column_view cimport column_view -cdef extern from "cuspatial/hausdorff.hpp" namespace "cuspatial" nogil: +cdef extern from "cuspatial/distance/hausdorff.hpp" \ + namespace "cuspatial" nogil: cdef unique_ptr[column] directed_hausdorff_distance( const column_view& xs, diff --git a/python/cuspatial/cuspatial/_lib/cpp/spatial.pxd b/python/cuspatial/cuspatial/_lib/cpp/distance/haversine.pxd similarity index 78% rename from python/cuspatial/cuspatial/_lib/cpp/spatial.pxd rename to python/cuspatial/cuspatial/_lib/cpp/distance/haversine.pxd index 764458f05..4e39c6ad5 100644 --- a/python/cuspatial/cuspatial/_lib/cpp/spatial.pxd +++ b/python/cuspatial/cuspatial/_lib/cpp/distance/haversine.pxd @@ -5,7 +5,8 @@ from libcpp.memory cimport unique_ptr from cudf._lib.column cimport column, column_view -cdef extern from "cuspatial/haversine.hpp" namespace "cuspatial" nogil: +cdef extern from "cuspatial/distance/haversine.hpp" \ + namespace "cuspatial" nogil: cdef unique_ptr[column] haversine_distance( const column_view& a_lon, const column_view& a_lat, diff --git a/python/cuspatial/cuspatial/_lib/cpp/linestring_distance.pxd b/python/cuspatial/cuspatial/_lib/cpp/distance/linestring_distance.pxd similarity index 91% rename from python/cuspatial/cuspatial/_lib/cpp/linestring_distance.pxd rename to python/cuspatial/cuspatial/_lib/cpp/distance/linestring_distance.pxd index 4523cf045..0a0b1a6b9 100644 --- a/python/cuspatial/cuspatial/_lib/cpp/linestring_distance.pxd +++ b/python/cuspatial/cuspatial/_lib/cpp/distance/linestring_distance.pxd @@ -8,7 +8,7 @@ from cudf._lib.cpp.column.column_view cimport column_view from cudf._lib.cpp.types cimport size_type -cdef extern from "cuspatial/distances/linestring_distance.hpp" \ +cdef extern from "cuspatial/distance/linestring_distance.hpp" \ namespace "cuspatial" nogil: cdef unique_ptr[column] pairwise_linestring_distance( const column_view linestring1_offsets, diff --git a/python/cuspatial/cuspatial/_lib/hausdorff.pyx b/python/cuspatial/cuspatial/_lib/hausdorff.pyx index ca9497813..7465efc7a 100644 --- a/python/cuspatial/cuspatial/_lib/hausdorff.pyx +++ b/python/cuspatial/cuspatial/_lib/hausdorff.pyx @@ -5,7 +5,7 @@ from libcpp.utility cimport move from cudf._lib.column cimport Column, column, column_view -from cuspatial._lib.cpp.hausdorff cimport ( +from cuspatial._lib.cpp.distance.hausdorff cimport ( directed_hausdorff_distance as directed_cpp_hausdorff_distance, ) diff --git a/python/cuspatial/cuspatial/_lib/linestring_distance.pyx b/python/cuspatial/cuspatial/_lib/linestring_distance.pyx index 36589810b..49ed7beeb 100644 --- a/python/cuspatial/cuspatial/_lib/linestring_distance.pyx +++ b/python/cuspatial/cuspatial/_lib/linestring_distance.pyx @@ -5,7 +5,7 @@ from cudf._lib.column cimport Column from cudf._lib.cpp.column.column cimport column from cudf._lib.cpp.column.column_view cimport column_view -from cuspatial._lib.cpp.linestring_distance cimport ( +from cuspatial._lib.cpp.distance.linestring_distance cimport ( pairwise_linestring_distance as cpp_pairwise_linestring_distance, ) diff --git a/python/cuspatial/cuspatial/_lib/spatial.pyx b/python/cuspatial/cuspatial/_lib/spatial.pyx index f18eaadd1..06a64014c 100644 --- a/python/cuspatial/cuspatial/_lib/spatial.pyx +++ b/python/cuspatial/cuspatial/_lib/spatial.pyx @@ -13,7 +13,7 @@ from cudf._lib.cpp.column.column_view cimport column_view from cuspatial._lib.cpp.coordinate_transform cimport ( lonlat_to_cartesian as cpp_lonlat_to_cartesian, ) -from cuspatial._lib.cpp.spatial cimport ( +from cuspatial._lib.cpp.distance.haversine cimport ( haversine_distance as cpp_haversine_distance, )