chull 0.2.4

Convex hull approximation
Documentation
use num_traits::{NumOps, Zero};

pub(crate) fn det_correlation_matrix<T: Clone + NumOps + Zero>(mat: &[Vec<T>]) -> T {
    let dim = mat[0].len();
    let num = mat.len();
    let mut cor = Vec::new();
    for i in 0..num {
        let mut column = Vec::new();
        for j in 0..num {
            let mut c = T::zero();
            for k in 0..dim {
                c = c + mat[i][k].clone() * mat[j][k].clone();
            }
            column.push(c);
        }
        cor.push(column);
    }
    det(&cor)
}

pub(crate) fn dot<T: Clone + NumOps + Zero>(x: &[T], y: &[T]) -> T {
    x.iter()
        .zip(y.iter())
        .map(|(a, b)| a.clone() * b.clone())
        .fold(T::zero(), |sum, c| sum + c)
}

pub(crate) fn sub<T: Clone + NumOps + Zero>(x: &[T], y: &[T]) -> Vec<T> {
    x.iter()
        .zip(y.iter())
        .map(|(a, b)| a.clone() - b.clone())
        .collect()
}

pub(crate) fn min_max_index_each_axis<T: Clone + Zero + PartialOrd>(
    points: &[Vec<T>],
) -> Vec<(usize, usize)> {
    let dim = points[0].len();
    let mut min_index = vec![0; dim];
    let mut max_index = vec![0; dim];
    let mut min = vec![T::zero(); dim];
    let mut max = vec![T::zero(); dim];
    for (index, point) in points.iter().enumerate() {
        for (j, element) in point.iter().enumerate() {
            if index == 0 || *element < min[j] {
                min[j] = element.clone();
                min_index[j] = index;
            }
            if index == 0 || *element > max[j] {
                max[j] = element.clone();
                max_index[j] = index;
            }
        }
    }
    min_index.into_iter().zip(max_index.into_iter()).collect()
}

pub(crate) fn is_same_dimension<T>(points: &[Vec<T>]) -> bool {
    if points.len() == 0 {
        return true;
    }
    let dim = points[0].len();
    if points.iter().skip(1).find(|p| p.len() != dim).is_some() {
        false
    } else {
        true
    }
}

pub(crate) fn det<T: NumOps + Clone>(m: &[Vec<T>]) -> T {
    let row_dim = m.len();
    let column_dim = m[0].len();
    assert_eq!(row_dim, column_dim);
    match column_dim {
        1 => m[0][0].clone(),
        2 => det_2x2(m),
        3 => det_3x3(m),
        4 => det_4x4(m),
        _ => {
            unimplemented!("matrix size should be less than 4 dim to calcurate determinant for now")
        }
    }
}

fn det_2x2<T: NumOps + Clone>(m: &[Vec<T>]) -> T {
    m[0][0].clone() * m[1][1].clone() - m[0][1].clone() * m[1][0].clone()
}

#[rustfmt::skip]
fn det_3x3<T: NumOps+Clone>(m: &[Vec<T>]) -> T {
    m[0][0].clone() * (m[1][1].clone() * m[2][2].clone() - m[1][2].clone() * m[2][1].clone())
  - m[1][0].clone() * (m[0][1].clone() * m[2][2].clone() - m[0][2].clone() * m[2][1].clone())
  + m[2][0].clone() * (m[0][1].clone() * m[1][2].clone() - m[0][2].clone() * m[1][1].clone())
}

#[rustfmt::skip]
fn det_4x4<T: NumOps + Clone>(m: &[Vec<T>]) -> T {
    m[0][0].clone()
        * (   m[1][1].clone() * m[2][2].clone() * m[3][3].clone()
            + m[1][2].clone() * m[2][3].clone() * m[3][1].clone()
            + m[1][3].clone() * m[2][1].clone() * m[3][2].clone()
            - m[1][3].clone() * m[2][2].clone() * m[3][1].clone()
            - m[1][2].clone() * m[2][1].clone() * m[3][3].clone()
            - m[1][1].clone() * m[2][3].clone() * m[3][2].clone())
  - m[1][0].clone()
        * (   m[0][1].clone() * m[2][2].clone() * m[3][3].clone()
            + m[0][2].clone() * m[2][3].clone() * m[3][1].clone()
            + m[0][3].clone() * m[2][1].clone() * m[3][2].clone()
            - m[0][3].clone() * m[2][2].clone() * m[3][1].clone()
            - m[0][2].clone() * m[2][1].clone() * m[3][3].clone()
            - m[0][1].clone() * m[2][3].clone() * m[3][2].clone())
  + m[2][0].clone()
        * (   m[0][1].clone() * m[1][2].clone() * m[3][3].clone()
            + m[0][2].clone() * m[1][3].clone() * m[3][1].clone()
            + m[0][3].clone() * m[1][1].clone() * m[3][2].clone()
            - m[0][3].clone() * m[1][2].clone() * m[3][1].clone()
            - m[0][2].clone() * m[1][1].clone() * m[3][3].clone()
            - m[0][1].clone() * m[1][3].clone() * m[3][2].clone())
  - m[3][0].clone()
        * (   m[0][1].clone() * m[1][2].clone() * m[2][3].clone()
            + m[0][2].clone() * m[1][3].clone() * m[2][1].clone()
            + m[0][3].clone() * m[1][1].clone() * m[2][2].clone()
            - m[0][3].clone() * m[1][2].clone() * m[2][1].clone()
            - m[0][2].clone() * m[1][1].clone() * m[2][3].clone()
            - m[0][1].clone() * m[1][3].clone() * m[2][2].clone())
}

#[test]
fn det_4x4_test() {
    let r1 = vec![1., 2., 3., 4.];
    let r2 = vec![5., 6., 7., 8.];
    let r3 = vec![9., 10., 11., 12.];
    let r4 = vec![13., 14., 15., 16.];
    assert_eq!(det(&[r1, r2, r3, r4]), 0.);
    let r1 = vec![1., 2., 3., 1.];
    let r2 = vec![6., 6., 7., 1.];
    let r3 = vec![9., 11., 11., 1.];
    let r4 = vec![15., 14., 15., 1.];
    assert_eq!(det(&[r1, r2, r3, r4]), -4.);
    let r1 = vec![1., 1., 1., 1.];
    let r2 = vec![1., 2., 2., 1.];
    let r3 = vec![1., 2., 3., 1.];
    let r4 = vec![1., 1., 1., 2.];
    assert_eq!(det(&[r1, r2, r3, r4]), 1.);
}