I have implemented a function for sampling from M different normal distributions N times in Rust because my R code was too slow. It is also parallelized. Here is the pure Rust code:
use rand_distr::{Normal, Distribution};
use rayon::prelude::*;
fn rust_rprednorm(n: i32, means: Vec<f64>, sds: Vec<f64>) -> Vec<Vec<f64>> {
let mut preds = vec![vec![0.0; n as usize]; means.len()];
preds.par_iter_mut().enumerate().for_each(|(i, e)| {
let mut rng = rand::thread_rng();
(0..n).into_iter().for_each(|j| {
let normal = Normal::new(means[i], sds[i]).unwrap();
e[j as usize] = normal.sample(&mut rng);
})
});
preds
}
Which I am trying to call from R using the rextendr library. The code is inside a utils.R file I import using source():
code <- r"(
use rand_distr::{Normal, Distribution};
use rayon::prelude::*;
#[extendr]
fn rust_rprednorm(n: i32, means: Vec<f64>, sds: Vec<f64>) -> Vec<Vec<f64>> {
let mut preds = vec![vec![0.0; n as usize]; means.len()];
preds.par_iter_mut().enumerate().for_each(|(i, e)| {
let mut rng = rand::thread_rng();
(0..n).into_iter().for_each(|j| {
let normal = Normal::new(means[i], sds[i]).unwrap();
e[j as usize] = normal.sample(&mut rng);
})
});
preds
}
)"
rust_source(code = code, dependencies = list(`rand` = "0.8.5", `rand_distr` ="0.4.3", `rayon` = "1.6.1"))
The error is:
Error in `invoke_cargo()`:
! Rust code could not be compiled successfully. Aborting.
✖ error[E0277]: the trait bound `Robj: From<Vec<Vec<f64>>>` is not satisfied
--> src\lib.rs:6:5
|
6 | #[extendr]
| ^^^^^^^^^^ the trait `From<Vec<Vec<f64>>>` is not implemented for `Robj`
|
= help: the following other types implement trait `From<T>`:
<Robj as From<&'a [T]>>
<Robj as From<&Altrep>>
<Robj as From<&Primitive>>
<Robj as From<&Robj>>
<Robj as From<&Vec<T>>>
<Robj as From<&extendr_api::Complexes>>
<Robj as From<&extendr_api::Doubles>>
<Robj as From<&extendr_api::Environment>>
and 71 others
= note: this error originates in the attribute macro `extendr` (in Nightly builds, run with -Z macro-backtrace for more info)
✖ error: aborting due to previous error
Traceback:
1. source("inla_predictive_distribution_utils.R")
2. withVisible(eval(ei, envir))
3. eval(ei, envir)
4. eval(ei, envir)
5. rust_source(code = code, dependencies = list(rand = "0.8.5",
. rand_distr = "0.4.3", rayon = "1.6.1"))
6. invoke_cargo(toolchain = toolchain, specific_target = specific_target,
. dir = dir, profile = profile, quiet = quiet, use_rtools = use_rtools)
7. check_cargo_output(compilation_result, message_buffer, tty_has_colors(),
. quiet)
8. ui_throw("Rust code could not be compiled successfully. Aborting.",
. error_messages, call = call, glue_open = "{<{", glue_close = "}>}")
9. withr::with_options(list(warning.length = message_limit_bytes),
. rlang::abort(message, class = "rextendr_error", call = call))
10. force(code)
11. rlang::abort(message, class = "rextendr_error", call = call)
12. signal_abort(cnd, .file)
I figured a nested vector would be supported since a regular vector is, but it appears not, do I need to implement this trait for Robj, or is there another way to go about it? I am also not sure if this is the recommended way to call Rust code from R.
You cannot return something like Vec<Vec<T>> because R does not really understand such things. I suspect that your best options are
Rmatrix type just for thatndarray, which is also translated into R matrixList containing Vec<T> elements if the output is a jagged arrayIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With