r2rs-nmath 0.1.1

Statistics programming for Rust based on R's nmath package
Documentation
// "Whatever you do, work at it with all your heart, as working for the Lord,
// not for human masters, since you know that you will receive an inheritance
// from the Lord as a reward. It is the Lord Christ you are serving."
// (Col 3:23-24)

use std::str::FromStr;

use strafe_testing::{
    r::{RString, RTester},
    r_assert_relative_equal, r_assert_relative_equal_result,
};
use strafe_type::FloatConstraint;

use crate::{
    distribution::f::FBuilder,
    reset_statics,
    rng::MarsagliaMulticarry,
    traits::{Distribution, RNG},
};

pub fn density_inner(x: f64, df1: f64, df2: f64) {
    let mut builder = FBuilder::new();
    builder.with_df1(df1);
    builder.with_df2(df2);
    let f = builder.build();

    let rust_ans = f.density(x);
    let r_ans = RTester::new()
        .set_display(&RString::from_string(format!(
            "df({}, {}, {}, log={})",
            RString::from_f64(x),
            RString::from_f64(df1),
            RString::from_f64(df2),
            RString::from_bool(false),
        )))
        .run()
        .expect("R running error")
        .as_f64();

    r_assert_relative_equal_result!(r_ans, &rust_ans);
}

pub fn log_density_inner(x: f64, df1: f64, df2: f64) {
    let mut builder = FBuilder::new();
    builder.with_df1(df1);
    builder.with_df2(df2);
    let f = builder.build();

    let rust_ans = f.log_density(x);
    let r_ans = RTester::new()
        .set_display(&RString::from_string(format!(
            "df({}, {}, {}, log={})",
            RString::from_f64(x),
            RString::from_f64(df1),
            RString::from_f64(df2),
            RString::from_bool(true),
        )))
        .run()
        .expect("R running error")
        .as_f64();

    r_assert_relative_equal_result!(r_ans, &rust_ans);
}

pub fn probability_inner(q: f64, df1: f64, df2: f64, lower_tail: bool) {
    let mut builder = FBuilder::new();
    builder.with_df1(df1);
    builder.with_df2(df2);
    let f = builder.build();

    let rust_ans = f.probability(q, lower_tail);
    let r_ans = RTester::new()
        .set_display(&RString::from_string(format!(
            "pf({}, {}, {}, lower.tail={}, log={})",
            RString::from_f64(q),
            RString::from_f64(df1),
            RString::from_f64(df2),
            RString::from_bool(lower_tail),
            RString::from_bool(false),
        )))
        .run()
        .expect("R running error")
        .as_f64();

    r_assert_relative_equal_result!(r_ans, &rust_ans);
}

pub fn log_probability_inner(q: f64, df1: f64, df2: f64, lower_tail: bool) {
    let mut builder = FBuilder::new();
    builder.with_df1(df1);
    builder.with_df2(df2);
    let f = builder.build();

    let rust_ans = f.log_probability(q, lower_tail);
    let r_ans = RTester::new()
        .set_display(&RString::from_string(format!(
            "pf({}, {}, {}, lower.tail={}, log={})",
            RString::from_f64(q),
            RString::from_f64(df1),
            RString::from_f64(df2),
            RString::from_bool(lower_tail),
            RString::from_bool(true),
        )))
        .run()
        .expect("R running error")
        .as_f64();

    r_assert_relative_equal_result!(r_ans, &rust_ans);
}

pub fn quantile_inner(p: f64, df1: f64, df2: f64, lower_tail: bool) {
    let mut builder = FBuilder::new();
    builder.with_df1(df1);
    builder.with_df2(df2);
    let f = builder.build();

    let rust_ans = f.quantile(p, lower_tail);
    let r_ans = RTester::new()
        .set_display(&RString::from_string(format!(
            "qf({}, {}, {}, lower.tail={}, log={})",
            RString::from_f64(p),
            RString::from_f64(df1),
            RString::from_f64(df2),
            RString::from_bool(lower_tail),
            RString::from_bool(false),
        )))
        .run()
        .expect("R running error")
        .as_f64();

    r_assert_relative_equal_result!(r_ans, &rust_ans);
}

pub fn log_quantile_inner(p: f64, df1: f64, df2: f64, lower_tail: bool) {
    let mut builder = FBuilder::new();
    builder.with_df1(df1);
    builder.with_df2(df2);
    let f = builder.build();

    let rust_ans = f.log_quantile(p, lower_tail);
    let r_ans = RTester::new()
        .set_display(&RString::from_string(format!(
            "qf({}, {}, {}, lower.tail={}, log={})",
            RString::from_f64(p),
            RString::from_f64(df1),
            RString::from_f64(df2),
            RString::from_bool(lower_tail),
            RString::from_bool(true),
        )))
        .run()
        .expect("R running error")
        .as_f64();

    r_assert_relative_equal_result!(r_ans, &rust_ans);
}

pub fn random_inner(seed: u16, df1: f64, df2: f64) {
    let num = 50;

    let r_state = RTester::new()
        .set_seed(seed)
        .set_display(&RString::from_str(".Random.seed").unwrap())
        .run()
        .unwrap()
        .as_f64_vec()
        .unwrap()
        .into_iter()
        .skip(1)
        .map(|i| i as i32)
        .collect::<Vec<_>>();

    let mut rust_rng = MarsagliaMulticarry::new();
    rust_rng.set_seed(seed as u32);

    let rust_state = rust_rng.get_state();

    for (r, rust) in r_state.iter().zip(rust_state.iter()) {
        assert_eq!(r, rust, "States not equal!");
    }

    let r_ret = RTester::new()
        .set_seed(seed)
        .set_display(&RString::from_string(format!(
            "rf({}, {}, {})",
            RString::from_f64(num as f64),
            RString::from_f64(df1),
            RString::from_f64(df2),
        )))
        .run()
        .unwrap()
        .as_f64_vec()
        .unwrap();

    let mut builder = FBuilder::new();
    builder.with_df1(df1);
    builder.with_df2(df2);
    let f = builder.build();
    reset_statics();
    let rust_ret = (0..num)
        .map(|_| f.random_sample(&mut rust_rng))
        .collect::<Vec<_>>();

    for (r, rust) in r_ret.iter().zip(rust_ret.iter()) {
        r_assert_relative_equal!(*r, rust.unwrap());
    }
}