Style/speed improvements in my code

I thought I'd implement a toy simulation that I use to get to grips with different languages (see here for other implementations: https://gist.github.com/sdwfrost/7c660322c6c33961297a826df4cbc30d). A Gist of my Rust code is here - how does this look in terms of style/performance?

A few things off the top;

  • Don't inline many things, let the compiler decide when to do that, and even then, you usually only apply an inline marker when your function is really small.

  • Cool down on the type annotations, Rust has great type inference and should be taken advantage of.

  • You should make sure to use a --release flag when running or building:

    cargo run --release
    
  • You don't need to say extern crate unless the compiler specifically asks you for it in certain niche cases with weird macro edge cases

  • You could use std::time for timing, but I'm not 100% sure on the precision of the values you get, so perhaps someone else can answer about that


Also, now that I've taken a look at your other implementations here's a few things you can do:

  • rand is the goto crate for random numbers and other things
  • You can use non-ascii symbols in rust for names like you happen to do so in Julia
  • let S: i64 = u[0];
    let I: i64 = u[1];
    let R: i64 = u[2];
    let Y: i64 = u[3];
    

    I might write

    let [S, I, R, Y] = *u;
    
  • sir doesn't mutate u.

  • 1.0 - f64::exp(x) can be expressed more accurately as -f64::exp_m1(x)

3 Likes

Some comments:

  • use rustfmt if possible
  • use std::... not needed for f64 and such (it is already in the prelude)
  • you can replace the while loops with simpler for loop for _ in 0..nsims, for _ in 0..tf (not sure why you're using (1..=tf)
  • no need to have both u and du and you don't need a mut rng: &mut ...:
  fn sir(u: &[i64; 4], parms: &[f64; 5], rng: &mut Xorshift128) -> [i64; 4] {
      // ...
      let infection: i64 = randbn(S, ifrac, rng);
      let recovery: i64 = randbn(I, rfrac, rng);
      // ...
  }
  // ...
  u = sir(&u, &parms, &mut rng);

... and now that we're at it we can optionally simplify numerator calculation:

    let numerator: i64 = (0..nsims)
          .map(|_| (1..tf).fold([60, 1, 342, 0], |u, _nxt| sir(&u, &parms, &mut rng))[3])
          .sum();
  • In randbn, you're dividing by n - x but I think will be 0 after n iteration (if n>0), is it ok?
1 Like

To avoid confusion - this feature is currently only available on the nightly compiler with the #![feature(non_ascii_idents)] feature flag. Without that, identifiers have to be ASCII (matching the pattern [a-zA-Z][a-zA-Z0-9_]* | _[a-zA-Z0-9_]+, to be more precise).

1 Like