extendr / extendr-examples

This example shows how to interact with R datatypes.
MIT License
3 stars 0 forks source link

Add examples of efficient numerics #1

Open dcnorris opened 3 years ago

dcnorris commented 3 years ago

Thanks for this wonderful project. In under 24h, never having written any Rust code before, I have achieved a 2.5x speedup of an objective function that is invoked by base::integrate().

FYI, here is the original function from package dfcrm ...

crmh = function(a,x,y,w,s) {  ## posterior
  v = exp(-a^2/2/s^2) 
  for (i in 1:length(x)) {
    v = v * ((x[i]^exp(a))^y[i])*(((1-w[i]*x[i]^exp(a))^(1-y[i])))
  }
  return(v)
}

and here is my initial direct translation into Rust:

/// A Rust implementation of the dfcrm::crmh posterior,
/// which I hope will prove faster to integrate().
/// @export
#[extendr]
fn rcrmh(a: &[f64],
     x: &[f64],
     y: &[f64],
     w: &[f64],
     s: &[f64]) -> Robj {
    // TODO: Assert that x, y and w all have same length?
    let v = a.iter().map(|a| {
    let mut v_ = (-0.5*a/s[0]).exp();
    for i in 0 .. y.len() {
        let p_i = x[i].powf(a.exp()); // 'power model' CRM
        v_ = v_ * if y[i] == 0.0 { 1.0 - w[i] * p_i } else { p_i };
    }
    v_
    });
    v.collect_robj()
}

Speaking from the POV of the Rust novice, the sort of example I would find most helpful would show a cascade of performance improvements that start with 'elegant' or 'default' wrappings and proceed step-wise through a series of tuning steps that exploit language features like borrowing, etc. Alluding to equivalent constructs in C would help orient users who are familiar with performance-tuning tricks in that language.

andy-thomason commented 3 years ago

Wow, thanks @dcnorris I do have a very fast vectorised exp/log that I hope to roll out in due course as part of another long term project.

It is worth looking at the rayon package for parallel iterators if your vectors are large.