Skip to content

Instantly share code, notes, and snippets.

@BerriJ
Created November 25, 2022 08:29
Show Gist options
  • Select an option

  • Save BerriJ/6a0e91554ca5c02f941538eee655a79e to your computer and use it in GitHub Desktop.

Select an option

Save BerriJ/6a0e91554ca5c02f941538eee655a79e to your computer and use it in GitHub Desktop.
In R: Draw sample from a grid without creating it (without replacement)
library(microbenchmark)
library(Rcpp)
library(inline)
src <- "int n = as<int>(N);
std::vector<int> s = as< std::vector<int> >(sizes);
std::vector<int> epsilon (s.size());
std::vector<int>::iterator it;
it = s.begin();
it = s.insert ( it , 1 );
int G[s.size()];
std::partial_sum (s.begin(), s.end(), G, std::multiplies<int>());
int k;
while(n>0){
k=1;
while(G[k]<=n){
k=k+1;
}
epsilon[k-1] = (int)n / G[k-1];
n = n % G[k-1];
}
return wrap(epsilon); "
intToCantor <- cxxfunction(signature(
N = "integer",
sizes = "integer"
),
body = src, plugin = "Rcpp"
)
CantorToInt <- function(epsilon, sizes) {
sum(epsilon * c(1, cumprod(sizes[1:(length(epsilon) - 1)])))
}
x <- 1:1000
y <- 1:1000
z <- 1:1000
sizes <- c(length(x), length(y), length(z))
N <- prod(sizes)
n <- 10000
idx <- sample(1:N, n, replace = FALSE)
result <- matrix(NA_real_, nrow = n, ncol = length(sizes))
for (i in 1:n) {
indices <- 1 + intToCantor(idx[i] - 1, sizes = sizes)
result[i, ] <- c(x[indices[1]], y[indices[2]], z[indices[3]])
}
X <- list(x, y, z)
microbenchmark(A = {
for (i in 1:n) {
indices <- 1 + intToCantor(idx[i] - 1, sizes = sizes)
result[i, ] <- c(x[indices[1]], y[indices[2]], z[indices[3]])
}
}, B = {
X.len <- sapply(X, length)
# modify '%%' to return values 1..n instead of 0..(n-1)
mod2 <- function(x, y) (x - 1) %% y + 1
result <- sapply(seq_along(X), function(i) {
X[[i]][mod2(
ceiling(idx / prod(X.len[seq_len(i - 1)])),
X.len[i]
)]
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment