Skip to content

Commit 6513314

Browse files
Move which_within_distance to C++ (#102)
* First attempt * Don't coerce matrix to vector * Use writable namespace * Try this I guess * Use cpp11 classes throughout * Use STL instead New commit instead of revert to also fix whitespace * Suggestions from code review
1 parent c2f99d9 commit 6513314

8 files changed

+78
-13
lines changed

DESCRIPTION

+3
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,6 @@ Encoding: UTF-8
5757
LazyData: true
5858
Roxygen: list(markdown = TRUE)
5959
RoxygenNote: 7.2.0
60+
LinkingTo:
61+
cpp11
62+
SystemRequirements: C++11

NAMESPACE

+1
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,4 @@ importFrom(stats,cutree)
7878
importFrom(stats,dist)
7979
importFrom(stats,hclust)
8080
importFrom(stats,kmeans)
81+
useDynLib(spatialsample, .registration = TRUE)

R/0_imports.R

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"_PACKAGE"
33

44
## usethis namespace: start
5+
#' @useDynLib spatialsample, .registration = TRUE
56
## usethis namespace: end
67
NULL
78

R/buffer.R

+4-13
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ buffered_complement <- function(ind, buff_ind, n) {
4444

4545
row_ids_within_dist <- function(distmat, indices, dist) {
4646
if (units::set_units(dist, NULL) > 0) {
47+
# c++ won't implicitly cast, so do it in R
48+
mode(distmat) <- "numeric"
49+
dist <- as.numeric(dist)
4750
purrr::map(
4851
# indices is the output of split_unnamed
4952
indices,
@@ -55,22 +58,10 @@ row_ids_within_dist <- function(distmat, indices, dist) {
5558
# not sorted in
5659
#
5760
# So here we append the new indices to the old and de-duplicate them
58-
~ unique(c(.x, which_within_dist(distmat, .x, dist)))
61+
~ unique(c(.x, which_within_dist(distmat, as.numeric(.x), dist)))
5962
)
6063
} else {
6164
# initialize to integer(0) in case buffer is <= 0:
6265
lapply(seq_along(indices), function(x) integer(0))
6366
}
6467
}
65-
66-
# Return row IDs for which elements of `data` are within `dist` of `data[idx, ]`
67-
# Note that data[idx, ] are within any positive distance of themselves
68-
# and as such are returned by this function
69-
which_within_dist <- function(distmat, idx, dist) {
70-
unlist(
71-
purrr::map(
72-
idx,
73-
~ which(distmat[.x, ] <= dist)
74-
)
75-
)
76-
}

R/cpp11.R

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Generated by cpp11: do not edit by hand
2+
3+
which_within_dist <- function(distmat, idx, dist) {
4+
.Call(`_spatialsample_which_within_dist`, distmat, idx, dist)
5+
}

src/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
*.o
2+
*.so
3+
*.dll

src/code.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <cpp11.hpp>
2+
#include <vector>
3+
using namespace cpp11;
4+
5+
[[cpp11::register]]
6+
cpp11::writable::integers which_within_dist(doubles_matrix<> distmat, doubles idx, double dist) {
7+
8+
int n_idx = idx.size();
9+
int n_matrix = distmat.ncol();
10+
std::vector<bool> comparisons(n_matrix);
11+
int cur_row;
12+
13+
for (int i = 0; i < n_idx; i++) {
14+
cur_row = idx[i] - 1;
15+
for (int j = 0; j < n_matrix; j++) {
16+
if (distmat(cur_row, j) <= dist) {
17+
comparisons[j] = true;
18+
}
19+
}
20+
}
21+
22+
auto n_pos = std::count(comparisons.begin(), comparisons.end(), true);
23+
std::vector<int> out(n_pos);
24+
int cur_idx = 0;
25+
for (int i = 0; i < n_matrix; i++) {
26+
if (comparisons[i]) {
27+
out[cur_idx] = i + 1;
28+
++cur_idx;
29+
}
30+
}
31+
32+
return out;
33+
34+
}

src/cpp11.cpp

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Generated by cpp11: do not edit by hand
2+
// clang-format off
3+
4+
5+
#include "cpp11/declarations.hpp"
6+
#include <R_ext/Visibility.h>
7+
8+
// code.cpp
9+
cpp11::writable::integers which_within_dist(doubles_matrix<> distmat, doubles idx, double dist);
10+
extern "C" SEXP _spatialsample_which_within_dist(SEXP distmat, SEXP idx, SEXP dist) {
11+
BEGIN_CPP11
12+
return cpp11::as_sexp(which_within_dist(cpp11::as_cpp<cpp11::decay_t<doubles_matrix<>>>(distmat), cpp11::as_cpp<cpp11::decay_t<doubles>>(idx), cpp11::as_cpp<cpp11::decay_t<double>>(dist)));
13+
END_CPP11
14+
}
15+
16+
extern "C" {
17+
static const R_CallMethodDef CallEntries[] = {
18+
{"_spatialsample_which_within_dist", (DL_FUNC) &_spatialsample_which_within_dist, 3},
19+
{NULL, NULL, 0}
20+
};
21+
}
22+
23+
extern "C" attribute_visible void R_init_spatialsample(DllInfo* dll){
24+
R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
25+
R_useDynamicSymbols(dll, FALSE);
26+
R_forceSymbols(dll, TRUE);
27+
}

0 commit comments

Comments
 (0)