llml 0.2.3

Implementation of basic math data types with high level frontend and low level backend
use llml::{others::{Complxd, Complxf, ComplexSqrt}, vec::EucVecd2};
use rand::{random, distributions::Uniform, thread_rng, Rng};

#[test]
fn eq () {
    assert_eq!(Complxd::new(1., 2.), Complxd::new(1., 2.));
    assert_ne!(Complxd::new(1., 2.), Complxd::new(3., 3.))
}

#[test]
fn into () {
    assert_eq!(Into::<Complxf>::into(Complxd::new(1., 2.)), Complxf::new(1., 2.))
}

#[test]
fn add () {
    let alpha : Complxd = random();
    let beta : Complxd = random();

    assert_eq!(alpha + beta, Complxd::new(alpha.re() + beta.re(), alpha.im() + beta.im()))
}

#[test]
fn sub () {
    let alpha : Complxd = random();
    let beta : Complxd = random();

    assert_eq!(alpha - beta, Complxd::new(alpha.re() - beta.re(), alpha.im() - beta.im()))
}

#[test]
fn mul () {
    let alpha : Complxd = random();
    let beta : Complxd = random();

    assert_eq!(alpha * beta, Complxd::new(
        alpha.re() * beta.re() - alpha.im() * beta.im(),
        alpha.re() * beta.im() + alpha.im() * beta.re()
    ))
}

#[test]
fn div () {
    let alpha : Complxd = Complxd::new(1., 2.);
    let beta : Complxd = Complxd::new(2., 1.);

    let div = beta.re() * beta.re() + beta.im() * beta.im();
    let naive = Complxd::new(
        (alpha.re() * beta.re() + alpha.im() * beta.im()) / div,
        (-alpha.re() * beta.im() + alpha.im() * beta.re()) / div
    );

    let simd = alpha / beta;
    assert!((naive.re() - simd.re()).abs() <= f64::EPSILON);
    assert!((naive.im() - simd.im()).abs() <= f64::EPSILON)
}

#[test]
fn conj () {
    let alpha : Complxd = random();
    assert_eq!(alpha.conj(), Complxd::new(alpha.re(), -alpha.im()))
}

#[test]
fn sqrt () {
    let alpha = Complxd::new(-3., 4.);
    assert_eq!(alpha.sqrt(), Complxd::new(1., 2.));
    
}

#[test]
fn exp () {
    let alpha : Complxd = random();
    assert_eq!(alpha.exp(), Complxd::new(alpha.re().exp() * alpha.im().cos(), alpha.re().exp() * alpha.im().sin()));
}

#[test]
fn ln () {
    let alpha : Complxd = random();
    let (radius, angle) = alpha.polar();
    assert_eq!(alpha.ln(), Complxd::new(radius.ln(), angle));
}

#[test]
fn powi () {
    let alpha : Complxd = random();
    let beta : i32 = thread_rng().gen_range(-10..=10);

    let diff : EucVecd2 = (alpha.powi(beta as i32) - Complxd::exp((beta as f64) * alpha.ln())).into();
    assert!(diff.abs().sum() <= f64::EPSILON * 2.);
}

#[test]
fn powf () {
    let alpha : Complxd = random();
    let beta : f64 = random();

    let diff : EucVecd2 = (alpha.powf(beta) - Complxd::exp(beta * alpha.ln())).into();
    assert!(diff.abs().sum() <= f64::EPSILON * 2.);
}

#[test]
fn powc () {
    let alpha : Complxd = random();
    let beta : Complxd = random();

    let diff : EucVecd2 = (alpha.powc(beta) - Complxd::exp(beta * alpha.ln())).into();
    assert!(diff.abs().sum() <= f64::EPSILON * 2.);
}

#[test]
fn sin () {
    let alpha : Complxd = random();
    assert_eq!(alpha.sin(), Complxd::new(alpha.re().sin() * alpha.im().cosh(), alpha.re().cos() * alpha.im().sinh()));
}

#[test]
fn cos () {
    let alpha : Complxd = random();
    assert_eq!(alpha.cos(), Complxd::new(alpha.re().cos() * alpha.im().cosh(), -alpha.re().sin() * alpha.im().sinh()));
}

#[test]
fn tan () {
    let alpha : Complxd = random();
    let beta = Complxd::new(2. * alpha.re(), 2. * alpha.im());

    let div = beta.re().cos() + beta.im().cosh();
    assert_eq!(alpha.tan(), Complxd::new(
        beta.re().sin() / div,
        beta.im().sinh() / div
    ));
}
#[test]
fn expi () {
    let alpha : f64 = random();
    assert_eq!(Complxd::expi(alpha), Complxd::new(alpha.cos(), alpha.sin()))
}

#[test]
fn sqrtc () {
    let alpha : f64 = random();
    assert_eq!(alpha.sqrtc(), Complxd::new(alpha.sqrt(), 0.));
    assert_eq!((-alpha).sqrtc(), Complxd::new(0., alpha.sqrt()))
}