use crate::matrices::{Matrix, Row, Column};
use crate::numeric::{Numeric, NumericRef};
use crate::numeric::extra::{Real, RealRef, Sqrt};
pub fn inverse<T: Numeric>(matrix: &Matrix<T>) -> Option<Matrix<T>>
where for<'a> &'a T: NumericRef<T> {
if matrix.rows() != matrix.columns() {
return None;
}
if matrix.rows() == 1 {
let element = matrix.scalar();
if element == T::zero() {
return None;
}
return Some(Matrix::from_scalar(T::one() / element));
}
match determinant::<T>(matrix) {
Some(det) => {
if det == T::zero() {
return None;
}
let determinant_reciprocal = T::one() / det;
let mut cofactor_matrix = Matrix::empty(T::zero(), matrix.size());
for i in 0..matrix.rows() {
for j in 0..matrix.columns() {
let ij_minor = minor::<T>(matrix, i, j)?;
let sign = i8::pow(-1, (i.rem_euclid(2) + j.rem_euclid(2)) as u32);
let sign = if sign == 1 {
T::one()
} else {
T::zero() - T::one()
};
cofactor_matrix.set(i, j, sign * ij_minor);
}
}
cofactor_matrix.transpose_mut();
cofactor_matrix.map_mut(|element| element * determinant_reciprocal.clone());
Some(cofactor_matrix)
},
None => None
}
}
fn minor<T: Numeric>(matrix: &Matrix<T>, i: Row, j: Column) -> Option<T>
where for<'a> &'a T: NumericRef<T> {
minor_mut::<T>(&mut matrix.clone(), i, j)
}
fn minor_mut<T: Numeric>(matrix: &mut Matrix<T>, i: Row, j: Column) -> Option<T>
where for<'a> &'a T: NumericRef<T> {
if matrix.rows() == 1 || matrix.columns() == 1 {
return None;
}
if matrix.rows() != matrix.columns() {
return None;
}
matrix.remove_row(i);
matrix.remove_column(j);
determinant::<T>(matrix)
}
pub fn determinant<T: Numeric>(matrix: &Matrix<T>) -> Option<T>
where for<'a> &'a T: NumericRef<T> {
if matrix.rows() != matrix.columns() {
return None;
}
let length = matrix.rows();
if length == 0 {
return None;
}
if length == 1 {
return Some(matrix.scalar());
}
let mut sum = T::zero();
with_each_permutation(&mut (0..length).collect(), &mut |permutation, even_swap| {
let signature = if even_swap {
T::one()
} else {
T::zero() - T::one()
};
let mut product = T::one();
for (n, i) in permutation.iter().enumerate() {
let element = matrix.get_reference(n, *i);
product = product * element;
}
sum = sum.clone() + (signature * product);
});
Some(sum)
}
#[allow(dead_code)] fn factorial(n: usize) -> usize {
(1..=n).product()
}
fn heaps_permutations<T: Clone, F>(k: usize, list: &mut Vec<T>, consumer: &mut F)
where F: FnMut(&mut Vec<T>) {
if k == 1 {
consumer(list);
return;
}
for i in 0..k {
heaps_permutations(k - 1, list, consumer);
if i < k - 1 {
if k % 2 == 0 {
list.swap(i, k - 1);
} else {
list.swap(0, k - 1);
}
}
}
}
#[allow(dead_code)] fn generate_permutations<T: Clone>(list: &mut Vec<T>) -> Vec<(Vec<T>, bool)> {
let mut permutations = Vec::with_capacity(factorial(list.len()));
let mut even_swaps = true;
heaps_permutations(list.len(), list, &mut |permuted| {
permutations.push((permuted.clone(), even_swaps));
even_swaps = !even_swaps;
});
permutations
}
fn with_each_permutation<T: Clone, F>(list: &mut Vec<T>, consumer: &mut F)
where F: FnMut(&mut Vec<T>, bool) {
let mut even_swaps = true;
heaps_permutations(list.len(), list, &mut |permuted| {
consumer(permuted, even_swaps);
even_swaps = !even_swaps;
});
}
#[cfg(test)]
#[test]
fn test_permutations() {
let mut list = vec![ 1, 2, 3 ];
let permutations = generate_permutations(&mut list);
assert!(permutations.contains(&(vec![1, 2, 3], true)));
assert!(permutations.contains(&(vec![3, 2, 1], false)));
assert!(permutations.contains(&(vec![2, 3, 1], true)));
assert!(permutations.contains(&(vec![1, 3, 2], false)));
assert!(permutations.contains(&(vec![2, 1, 3], false)));
assert!(permutations.contains(&(vec![3, 1, 2], true)));
assert_eq!(permutations.len(), 6);
let mut list = vec![ 1, 2, 3, 4, 5 ];
let permuted = generate_permutations(&mut list);
assert!(permuted.contains(&(vec![1, 2, 3, 4, 5], true)));
assert!(permuted.contains(&(vec![1, 2, 3, 5, 4], false)));
assert!(permuted.contains(&(vec![1, 2, 5, 3, 4], true)));
let mut list = vec![0, 1];
let permuted = generate_permutations(&mut list);
assert!(permuted.contains(&(vec![0, 1], true)));
assert!(permuted.contains(&(vec![1, 0], false)));
assert_eq!(permuted.len(), 2);
}
pub fn covariance_column_features<T: Numeric>(matrix: &Matrix<T>) -> Matrix<T>
where for<'a> &'a T: NumericRef<T> {
let features = matrix.columns();
let samples = T::from_usize(matrix.rows()).expect(
"The maximum value of the matrix type T cannot represent this many samples");
let mut covariance_matrix = Matrix::empty(T::zero(), (features, features));
covariance_matrix.map_mut_with_index(|_, i, j| {
let feature_i_mean: T = matrix.column_iter(i).sum::<T>() / &samples;
let feature_j_mean: T = matrix.column_iter(j).sum::<T>() / &samples;
matrix.column_reference_iter(i)
.map(|x| x - &feature_i_mean)
.zip(matrix.column_reference_iter(j).map(|y| y - &feature_j_mean))
.map(|(x, y)| x * y)
.sum::<T>() / &samples
});
covariance_matrix
}
pub fn covariance_row_features<T: Numeric>(matrix: &Matrix<T>) -> Matrix<T>
where for<'a> &'a T: NumericRef<T> {
let features = matrix.rows();
let samples = T::from_usize(matrix.columns()).expect(
"The maximum value of the matrix type T cannot represent this many samples");
let mut covariance_matrix = Matrix::empty(T::zero(), (features, features));
covariance_matrix.map_mut_with_index(|_, i, j| {
let feature_i_mean: T = matrix.row_iter(i).sum::<T>() / &samples;
let feature_j_mean: T = matrix.row_iter(j).sum::<T>() / &samples;
matrix.row_reference_iter(i)
.map(|x| x - &feature_i_mean)
.zip(matrix.row_reference_iter(j).map(|y| y - &feature_j_mean))
.map(|(x, y)| x * y)
.sum::<T>() / &samples
});
covariance_matrix
}
pub fn mean<I, T: Numeric>(mut data: I) -> T
where I: Iterator<Item = T> {
let mut next = data.next();
assert!(next.is_some(), "Provided iterator must not be empty");
let mut count = T::zero();
let mut sum = T::zero();
while next.is_some() {
count = count + T::one();
sum = sum + next.unwrap();
next = data.next();
}
sum / count
}
pub fn variance<I, T: Numeric>(data: I) -> T
where I: Iterator<Item = T>, {
let mut list = data.collect::<Vec<T>>();
assert!(!list.is_empty(), "Provided iterator must not be empty");
let m = mean(list.iter().cloned());
mean(list.drain(..).map(|x| (x.clone() - m.clone()) * (x - m.clone())))
}
pub fn softmax<I, T: Numeric + Real>(data: I) -> Vec<T>
where I: Iterator<Item = T>, {
let list = data.collect::<Vec<T>>();
if list.is_empty() {
return Vec::with_capacity(0);
}
let max = list.iter().max_by(|a, b| a.partial_cmp(b).expect("NaN should not be in list")).unwrap();
let denominator: T = list.iter().cloned().map(|x| (x - max).exp()).sum();
list.iter().cloned().map(|x| {
(x - max).exp() / denominator.clone()
}).collect()
}
pub fn f1_score<T: Numeric>(precision: T, recall: T) -> T {
(T::one() + T::one()) * ((precision.clone() * recall.clone()) / (precision + recall))
}
pub fn cholesky_decomposition<T: Numeric + Sqrt<Output = T>>(matrix: &Matrix<T>) -> Option<Matrix<T>>
where for<'a> &'a T: NumericRef<T> {
if matrix.rows() != matrix.columns() {
return None;
}
let mut lower_triangular = Matrix::empty(T::zero(), matrix.size());
for i in 0..lower_triangular.rows() {
for k in 0..lower_triangular.columns() {
if i == k {
let mut sum = T::zero();
for j in 0..k {
sum = &sum + (lower_triangular.get_reference(k, j)
* lower_triangular.get_reference(k, j));
}
lower_triangular.set(i, k, (matrix.get_reference(i, k) - sum).sqrt());
}
if i > k {
let mut sum = T::zero();
for j in 0..k {
sum = &sum + (lower_triangular.get_reference(i, j)
* lower_triangular.get_reference(k, j));
}
lower_triangular.set(i, k,
(T::one() / lower_triangular.get_reference(k, k)) *
(matrix.get_reference(i, k) - sum));
}
}
}
Some(lower_triangular)
}
#[derive(Clone, Debug)]
pub struct QRDecomposition<T> {
pub q: Matrix<T>,
pub r: Matrix<T>,
_private: (),
}
impl <T: std::fmt::Display + Clone> std::fmt::Display for QRDecomposition<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
writeln!(f, "Q:\n{}", &self.q)?;
write!(f, "R:\n{}", &self.r)
}
}
impl <T> QRDecomposition<T> {
pub fn from_unchecked(q: Matrix<T>, r: Matrix<T>) -> QRDecomposition<T> {
QRDecomposition {
q,
r,
_private: (),
}
}
}
fn householder_matrix<T: Numeric + Real>(matrix: Matrix<T>) -> Matrix<T>
where for<'a> &'a T: NumericRef<T> + RealRef<T> {
assert_eq!(matrix.columns(), 1, "Input must be a column vector");
let x = matrix;
let rows = x.rows();
let length = x.euclidean_length();
let a = {
let sign = x.get(0, 0);
if sign > T::zero() {
length
} else {
-length
}
};
let u = {
let mut u = x;
u.set(0, 0, u.get(0, 0) + a);
u
};
let v = {
let length = u.euclidean_length();
u / length
};
let identity = Matrix::diagonal(T::one(), (rows, rows));
let two = T::one() + T::one();
identity - ((&v * v.transpose()) * two)
}
pub fn qr_decomposition<T: Numeric + Real>(matrix: &Matrix<T>) -> Option<QRDecomposition<T>>
where for<'a> &'a T: NumericRef<T> + RealRef<T> {
if matrix.columns() > matrix.rows() {
return None;
}
let iterations = std::cmp::min(matrix.rows() - 1, matrix.columns());
let mut q = None;
let mut r = matrix.clone();
for column in 0..iterations {
let submatrix_first_column = Matrix::column(r.column_iter(column).skip(column).collect());
let h = householder_matrix::<T>(submatrix_first_column);
let h = {
let mut identity = Matrix::diagonal(T::one(), (matrix.rows(), matrix.rows()));
for i in 0..h.rows() {
for j in 0..h.columns() {
identity.set(column + i, column + j, h.get(i, j));
}
}
identity
};
r = &h * r;
match q {
None => q = Some(h),
Some(h_previous) => q = Some(h_previous * h),
}
}
Some(QRDecomposition {
q: q.unwrap(),
r,
_private: (),
})
}