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

Add Header Only API pairwise_linestring_intersection #852

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
12ce052
Initial port from feature/intersection_dev
isVoid Nov 22, 2022
7310405
More porting from range/ref objects and passing compilation
isVoid Nov 22, 2022
727a51f
header cleanup
isVoid Nov 22, 2022
4b2edee
style
isVoid Nov 22, 2022
01bc3a0
initial porting
isVoid Nov 23, 2022
6a7c0d2
rename with find
isVoid Nov 23, 2022
dfa1ce9
initial port from dev branch
isVoid Nov 23, 2022
bb5e0d4
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Nov 27, 2022
99ed507
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Nov 28, 2022
4d6617b
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Nov 28, 2022
50e56ee
add docs for range
isVoid Nov 29, 2022
41da8e0
add docs for properties and methods
isVoid Nov 29, 2022
c6dc62c
update with constant integer range usage
isVoid Nov 29, 2022
8666629
use array access operator instead of pointer arithmetic
isVoid Nov 29, 2022
3cdf65c
Revert "update with constant integer range usage"
isVoid Nov 29, 2022
3d3b312
use unique_ptr for all non-temporary, owning objects
isVoid Dec 2, 2022
8534f17
style
isVoid Dec 2, 2022
7aa0aa0
add error handling
isVoid Dec 2, 2022
eaf22b4
add error handling
isVoid Dec 2, 2022
2482d25
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Dec 5, 2022
f1731fe
address reviews
isVoid Dec 5, 2022
403b890
add more basic tests
isVoid Dec 5, 2022
279a50b
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Dec 6, 2022
25e3496
apply review comments
isVoid Dec 7, 2022
500de19
address reviews
isVoid Dec 7, 2022
736c3f1
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Dec 8, 2022
3450882
use segment methods
isVoid Dec 8, 2022
c9a7e89
zero initialize array in kernel
isVoid Dec 8, 2022
83f9b1a
simplify tests
isVoid Dec 8, 2022
2170e84
undef test macro
isVoid Dec 8, 2022
16c6a42
Use new macro
isVoid Dec 8, 2022
bfdd6bb
remove duplicate definition of segment arrays
isVoid Dec 8, 2022
877a12f
adding new bottom-up traverse helper; use ephemeral atomic_ref object
isVoid Dec 8, 2022
44b68de
add enumerate_range
isVoid Dec 9, 2022
975bda9
more adding to the enumerate range
isVoid Dec 9, 2022
c58cd33
a new zero data helper
isVoid Dec 9, 2022
bb1d792
Update cpp/include/doxygen_groups.h
isVoid Dec 9, 2022
9a82805
refactor tests to remove duplicates
isVoid Dec 9, 2022
8aef773
initial port from dev branch
isVoid Dec 10, 2022
a5ab622
replace wording: stencil with flag
isVoid Dec 10, 2022
40ee156
compile intersection tests
isVoid Dec 10, 2022
2bb7d7b
Merge branch 'feature/merge_segment_pr' into feature/header_only_inte…
isVoid Dec 10, 2022
6bbf858
Merge branch 'feature/merge_point_on_segment_pr' into feature/header_…
isVoid Dec 10, 2022
8ee7d5a
refactor tests to make simpler
isVoid Dec 10, 2022
5e490ba
revert comments https://github.com/rapidsai/cuspatial/pull/819#discus…
isVoid Dec 12, 2022
ba55a15
Merge branch 'feature/merge_point_on_segment_pr' into feature/header_…
isVoid Dec 12, 2022
ed85fac
fix bug in count
isVoid Dec 12, 2022
8f800a8
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Dec 13, 2022
5c0ecc2
Revert "fix bug in count"
isVoid Dec 13, 2022
42c9b6f
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Dec 13, 2022
8a9e70e
Update docstrings
isVoid Dec 14, 2022
3e4bcc1
Update cpp/tests/experimental/spatial/linestring_intersection_interme…
isVoid Dec 14, 2022
0c239dd
Merge branch 'feature/header_only_intersection/pr' of github.com:isVo…
isVoid Dec 14, 2022
eb4f767
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Dec 14, 2022
c1efe0e
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Dec 14, 2022
7613da1
remove bad merge function
isVoid Dec 15, 2022
fec6bef
remove bad merge function
isVoid Dec 15, 2022
3b11670
Add sorting function to intersection results
isVoid Dec 15, 2022
44faadf
rename find_point->find_points
isVoid Dec 15, 2022
30cfe9b
add more combinations to test and refactors
isVoid Dec 15, 2022
4472a7a
Merge branch 'branch-23.02' of https://github.com/rapidsai/cuspatial …
isVoid Dec 15, 2022
45a1f0f
fix broken builds
isVoid Dec 15, 2022
0de15d3
fix typo in intersection_util
isVoid Dec 16, 2022
9d14f27
remove stale include
isVoid Dec 16, 2022
3404d55
some print utility updates
isVoid Dec 16, 2022
940674c
remove synchronize
isVoid Dec 16, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions cpp/include/cuspatial/detail/utility/linestring.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -259,21 +259,5 @@ thrust::optional<segment<T>> __device__ maybe_merge_segments(segment<T> const& s
return segment<T>{e0, e1}.translate(center);
}

/*
* @brief Given a point and a segment, returns true if point is on the segment.
*/
template <typename T>
bool __device__ is_point_on_segment(segment<T> const& segment, vec_2d<T> const& c)
{
auto [a, b] = segment;
auto ab = b - a;
auto ac = c - a;

if (not float_equal(det(ab, ac), T{0})) return false;

if (b < a) thrust::swap(a, b);
return a <= c && c <= b;
}

} // namespace detail
} // namespace cuspatial
Original file line number Diff line number Diff line change
Expand Up @@ -174,22 +174,6 @@ struct linestring_intersection_intermediates {
{
}

linestring_intersection_intermediates(
std::unique_ptr<rmm::device_uvector<index_t>> offsets,
std::unique_ptr<rmm::device_uvector<GeomType>> geoms,
std::unique_ptr<rmm::device_uvector<index_t>> lhs_linestring_ids,
std::unique_ptr<rmm::device_uvector<index_t>> lhs_segment_ids,
std::unique_ptr<rmm::device_uvector<index_t>> rhs_linestring_ids,
std::unique_ptr<rmm::device_uvector<index_t>> rhs_segment_ids)
: offsets(std::move(offsets)),
geoms(std::move(geoms)),
lhs_linestring_ids(std::move(lhs_linestring_ids)),
lhs_segment_ids(std::move(lhs_segment_ids)),
rhs_linestring_ids(std::move(rhs_linestring_ids)),
rhs_segment_ids(std::move(rhs_segment_ids))
{
}

linestring_intersection_intermediates(std::size_t num_pairs,
std::size_t num_geoms,
rmm::device_uvector<IndexType> const& num_geoms_per_pair,
Expand Down
60 changes: 60 additions & 0 deletions cpp/tests/experimental/spatial/intersection_test_utils.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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 <cuspatial/cuda_utils.hpp>
#include <cuspatial/experimental/geometry/segment.cuh>

#include <thrust/tuple.h>

namespace cuspatial {
namespace test {

// Custom order for two segments
template <typename T>
bool CUSPATIAL_HOST_DEVICE operator<(segment<T> lhs, segment<T> rhs)
{
return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
}

/**
* @brief Functor for segmented sorting a geometry array
*
* Using a label array and a geometry array as keys, this functor defines that
* all keys with smaller labels should precede keys with larger labels; and that
* the order with the same label should be determined by the natural order of the
* geometries.
*
* Example:
* Labels: {0, 0, 0, 1}
* Points: {(0, 0), (5, 5), (1, 1), (3, 3)}
* Result: {(0, 0), (1, 1), (5, 5), (3, 3)}
*/
template <typename KeyType, typename GeomType>
struct order_key_value_pairs {
using key_value_t = thrust::tuple<KeyType, GeomType>;

bool CUSPATIAL_HOST_DEVICE operator()(key_value_t lhs, key_value_t rhs)
{
return thrust::get<0>(lhs) < thrust::get<0>(rhs) ||
(thrust::get<0>(lhs) == thrust::get<0>(rhs) &&
thrust::get<1>(lhs) < thrust::get<1>(rhs));
}
};

} // namespace test
} // namespace cuspatial
125 changes: 124 additions & 1 deletion cpp/tests/experimental/spatial/linestring_intersection_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
* limitations under the License.
*/

#include "intersection_test_utils.cuh"
#include <cuspatial_test/test_util.cuh>

#include <cuspatial_test/vector_equality.hpp>
#include <cuspatial_test/vector_factories.cuh>

#include <cuspatial/detail/iterator.hpp>
#include <cuspatial/error.hpp>
#include <cuspatial/experimental/iterator_factory.cuh>
#include <cuspatial/experimental/linestring_intersection.cuh>
Expand All @@ -30,12 +34,126 @@
#include <rmm/exec_policy.hpp>
#include <rmm/mr/device/pool_memory_resource.hpp>

#include <thrust/binary_search.h>
#include <thrust/sort.h>

#include <initializer_list>
#include <type_traits>

using namespace cuspatial;
using namespace cuspatial::test;

/**
* @brief Perform sorting to the intersection result
*
* The result of intersection result is non-determinisitc. This algorithm sorts
* the geometries of the same types and the same list and makes the result deterministic.
*
* The example below contains 2 rows and 4 geometries. The order of the first
* and second point is non-deterministic.
* [
* [Point(1.0, 1.5), Point(0.0, -0.3), Segment((0.0, 0.0), (1.0, 1.0))]
* ^ ^
* [Point(-3, -5)]
* ]
*
* After sorting, the result is deterministic:
* [
* [Point(0.0, -0.3), Point(1.0, 1.5), Segment((0.0, 0.0), (1.0, 1.0))]
* ^ ^
* [Point(-3, -5)]
* ]
*
* This function invalidates the input @p result and return a copy of sorted results.
*/
template <typename T, typename IndexType, typename type_t>
linestring_intersection_result<T, IndexType> segment_sort_intersection_result(
isVoid marked this conversation as resolved.
Show resolved Hide resolved
linestring_intersection_result<T, IndexType>& result,
rmm::mr::device_memory_resource* mr,
rmm::cuda_stream_view stream)
{
auto const num_points = result.points_coords->size();
auto const num_segments = result.segments_coords->size();
auto const num_geoms = num_points + num_segments;

rmm::device_uvector<IndexType> scatter_map(num_geoms, stream);
thrust::sequence(rmm::exec_policy(stream), scatter_map.begin(), scatter_map.end());

// Compute keys for each row in the union column. Rows of the same list
// are assigned the same label.
rmm::device_uvector<IndexType> geometry_collection_keys(num_geoms, stream);
auto geometry_collection_keys_begin = detail::make_counting_transform_iterator(
0,
detail::intersection_functors::offsets_to_keys_functor{
result.geometry_collection_offset->begin(), result.geometry_collection_offset->end()});
thrust::copy(rmm::exec_policy(stream),
geometry_collection_keys_begin,
geometry_collection_keys_begin + num_geoms,
geometry_collection_keys.begin());

// Perform "group-by" based on the list label and type of the row -
// This makes the geometry of the same type and of the same list neighbor.

// Make a copy of types buffer so that the sorting does not affect the original.
auto types_buffer = rmm::device_uvector<type_t>(*result.types_buffer, stream);
auto keys_begin =
thrust::make_zip_iterator(types_buffer.begin(), geometry_collection_keys.begin());
auto value_begin = thrust::make_zip_iterator(scatter_map.begin(),
result.lhs_linestring_id->begin(),
result.lhs_segment_id->begin(),
result.rhs_linestring_id->begin(),
result.rhs_segment_id->begin());

thrust::sort_by_key(rmm::exec_policy(stream), keys_begin, keys_begin + num_geoms, value_begin);

// Segment-sort the point array
auto keys_points_begin = thrust::make_zip_iterator(keys_begin, result.points_coords->begin());
thrust::sort_by_key(rmm::exec_policy(stream),
keys_points_begin,
keys_points_begin + num_points,
scatter_map.begin(),
order_key_value_pairs<thrust::tuple<IndexType, IndexType>, vec_2d<T>>{});

// Segment-sort the segment array
auto keys_segment_begin =
thrust::make_zip_iterator(keys_begin + num_points, result.segments_coords->begin());

thrust::sort_by_key(rmm::exec_policy(stream),
keys_segment_begin,
keys_segment_begin + num_segments,
scatter_map.begin() + num_points,
order_key_value_pairs<thrust::tuple<IndexType, IndexType>, segment<T>>{});

// Restore the order of indices
auto lhs_linestring_id = std::make_unique<rmm::device_uvector<IndexType>>(num_geoms, stream, mr);
auto lhs_segment_id = std::make_unique<rmm::device_uvector<IndexType>>(num_geoms, stream, mr);
auto rhs_linestring_id = std::make_unique<rmm::device_uvector<IndexType>>(num_geoms, stream, mr);
auto rhs_segment_id = std::make_unique<rmm::device_uvector<IndexType>>(num_geoms, stream, mr);

auto input_it = thrust::make_zip_iterator(result.lhs_linestring_id->begin(),
result.lhs_segment_id->begin(),
result.rhs_linestring_id->begin(),
result.rhs_segment_id->begin());

auto output_it = thrust::make_zip_iterator(lhs_linestring_id->begin(),
lhs_segment_id->begin(),
rhs_linestring_id->begin(),
rhs_segment_id->begin());

thrust::scatter(
rmm::exec_policy(stream), input_it, input_it + num_geoms, scatter_map.begin(), output_it);

return {std::move(result.geometry_collection_offset),
std::move(result.types_buffer),
std::move(result.offset_buffer),
std::move(result.points_coords),
std::move(result.segments_coords),
std::move(lhs_linestring_id),
std::move(lhs_segment_id),
std::move(rhs_linestring_id),
std::move(rhs_segment_id)};
}

template <typename T,
typename IndexType,
typename types_t,
Expand Down Expand Up @@ -87,7 +205,12 @@ struct LinestringIntersectionTest : public ::testing::Test {
MultiLinestringRange rhs,
IntersectionResult const& expected)
{
auto got = pairwise_linestring_intersection<T, IndexType>(lhs, rhs, this->mr(), this->stream());
using types_t = typename IntersectionResult::types_t;

auto unsorted =
pairwise_linestring_intersection<T, IndexType>(lhs, rhs, this->mr(), this->stream());
auto got =
segment_sort_intersection_result<T, IndexType, types_t>(unsorted, this->mr(), this->stream());

CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(*std::move(expected.geometry_collection_offset),
*std::move(got.geometry_collection_offset));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
* limitations under the License.
*/

#include "intersection_test_utils.cuh"

#include <cuspatial_test/vector_equality.hpp>
#include <cuspatial_test/vector_factories.cuh>

Expand Down Expand Up @@ -43,38 +45,6 @@
using namespace cuspatial;
using namespace cuspatial::test;

// Custom order for two segments
template <typename T>
bool CUSPATIAL_HOST_DEVICE operator<(segment<T> lhs, segment<T> rhs)
{
return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second);
}

/**
* @brief Functor for segmented sorting a geometry array
*
* Using a label array and a geometry array as keys, this functor defines that
* all keys with smaller labels should precede keys with larger labels; and that
* the order with the same label should be determined by the natural order of the
* geometries.
*
* Example:
* Labels: {0, 0, 0, 1}
* Points: {(0, 0), (5, 5), (1, 1), (3, 3)}
* Result: {(0, 0), (1, 1), (5, 5), (3, 3)}
*/
template <typename KeyType, typename GeomType>
struct order_key_value_pairs {
using key_value_t = thrust::tuple<KeyType, GeomType>;

bool CUSPATIAL_HOST_DEVICE operator()(key_value_t lhs, key_value_t rhs)
{
return thrust::get<0>(lhs) < thrust::get<0>(rhs) ||
(thrust::get<0>(lhs) == thrust::get<0>(rhs) &&
thrust::get<1>(lhs) < thrust::get<1>(rhs));
}
};

/**
* @brief Sort geometries in `intersection_intermediates` by segments
*
Expand Down