soco 1.0.0

Algorithms for Smoothed Online Convex Optimization
Documentation
//! Differentiation.

use crate::numerics::{ApplicablePrecision, TOLERANCE};
use bacon_sci_1::differentiate::{
    derivative as derivative_, second_derivative as second_derivative_,
};
use finitediff::FiniteDiff;
use log::warn;
use noisy_float::prelude::*;

pub fn derivative(f: impl Fn(f64) -> f64, x: f64) -> N64 {
    if f(x).is_infinite() {
        return n64(f64::INFINITY);
    }

    let result = derivative_(f, x, TOLERANCE).apply_precision();
    if result.is_nan() {
        warn!(
            "First-order finite difference returned NaN. Assuming result `0`."
        );
        return n64(0.);
    }
    n64(result)
}

pub fn second_derivative(f: impl Fn(f64) -> f64, x: f64) -> N64 {
    if f(x).is_infinite() {
        return n64(f64::INFINITY);
    }
    let result =
        second_derivative_(f, x, TOLERANCE.powf(-0.25)).apply_precision();
    if result.is_nan() {
        warn!(
            "Second-order finite difference returned NaN. Assuming result `0`."
        );
        return n64(0.);
    }
    n64(result)
}

pub fn gradient(f: &impl Fn(&Vec<f64>) -> f64, xs: Vec<f64>) -> Vec<f64> {
    let result = xs.central_diff(f);
    result.iter().map(|&d| {
        if d.is_nan() {
            warn!(
                "First-order finite difference returned NaN. Assuming result `0`."
            );
            return 0.;
        }
        d
    }).collect()
}