Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I call a rust function from R that returns Vec<Vec<f64>>?

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.

like image 504
GBPU Avatar asked Jan 26 '26 08:01

GBPU


1 Answers

You cannot return something like Vec<Vec<T>> because R does not really understand such things. I suspect that your best options are

  • Some sort of a 2d matrix if the output is rectangular
    • There is an Rmatrix type just for that
    • There is limited support for ndarray, which is also translated into R matrix
  • A List containing Vec<T> elements if the output is a jagged array
like image 114
Ilia Avatar answered Jan 28 '26 21:01

Ilia



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!