r2rs-stats 0.1.1

Statistics programming for Rust based on R's stats 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)

pub fn fmingr(
    n: usize,
    p: &[f64],
    ndeps: &[f64],
    parscale: &[f64],
    fnscale: f64,
    bounds: Option<(Vec<f64>, Vec<f64>)>,
    min_func: &dyn Fn(Vec<f64>) -> f64,
    grad_func: Option<&dyn Fn(Vec<f64>) -> Vec<f64>>,
) -> (Vec<f64>, Vec<f64>) {
    if let Some(gfunc) = grad_func {
        // Analytical Derivatives
        let mut beta = vec![0.0; n];
        for i in 0..n {
            beta[i] = p[i] * parscale[i];
        }
        let s = gfunc(beta.clone());
        let mut df = vec![0.0; n];
        for i in 0..n {
            df[i] = s[i] * parscale[i] / fnscale;
        }
        (beta, df)
    } else {
        // Numerical Derivatives
        let mut beta = vec![0.0; n];
        let mut df = vec![0.0; n];

        for i in 0..n {
            beta[i] = p[i] * parscale[i];
        }

        for i in 0..n {
            let mut bounded = false;
            if let Some((upper, lower)) = &bounds {
                if upper[i].is_finite() && lower[i].is_finite() {
                    let mut eps = ndeps[i];
                    let mut epsused = eps;
                    let mut tmp = p[i] + eps;

                    if tmp > upper[i] {
                        tmp = upper[i];
                        epsused = tmp - p[i];
                    }

                    beta[i] = tmp * parscale[i];
                    let s_1: f64 = min_func(beta.clone()) / fnscale;

                    tmp = p[i] - eps;
                    if tmp < lower[i] {
                        tmp = lower[i];
                        eps = p[i] - tmp;
                    }

                    beta[i] = tmp * parscale[i];
                    let s_2: f64 = min_func(beta.clone()) / fnscale;

                    df[i] = (s_1 - s_2) / (epsused - eps);
                    beta[i] = p[i] * parscale[i];

                    bounded = true;
                }
            }

            if !bounded {
                let mut eps = ndeps[i];

                beta[i] = (p[i] + eps) * parscale[i];
                let s_1: f64 = min_func(beta.clone()) / fnscale;

                beta[i] = (p[i] - eps) * parscale[i];
                let s_2: f64 = min_func(beta.clone()) / fnscale;

                df[i] = (s_1 - s_2) / (2.0 * eps);
                beta[i] = p[i] * parscale[i];
            }
        }
        (beta, df)
    }
}