use crate::prelude::{Matrix, Vector};
use std::fmt::Debug;
use std::ops::{Add, Sub, Index, AddAssign, IndexMut, SubAssign, Mul, MulAssign, Neg};
use conv::{ConvUtil, ValueFrom};
use itertools::Itertools;
impl<const T: usize, const N: usize, L: Copy + Debug> Add for Matrix<T, N, L> where L: Add + AddAssign {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let mut out = self;
out += rhs;
out
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> AddAssign for Matrix<T, N, L> where L: Add + AddAssign {
fn add_assign(&mut self, rhs: Self) {
for i in 0..N {
for n in 0..T {
self[(i, n)] += rhs[(i, n)]
}
}
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> Sub for Matrix<T, N, L> where L: Sub + SubAssign {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let mut out = self;
out -= rhs;
out
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> SubAssign for Matrix<T, N, L> where L: Sub + SubAssign {
fn sub_assign(&mut self, rhs: Self) {
for i in 0..N {
for n in 0..T {
self[(i, n)] -= rhs[(i, n)]
}
}
}
}
impl<const T: usize, const N: usize, L: Copy + Debug + ValueFrom<isize>> MulAssign<Matrix<N, N, L>> for Matrix<T, N, L> where L: Add<Output=L> + AddAssign + Mul<Output=L> + ValueFrom<isize> {
fn mul_assign(&mut self, rhs: Matrix<N, N, L>) {
let mut data = [[0.value_as().unwrap(); N]; T];
for i in 0..N {
for j in 0..T {
let mut res: L = 0.value_as().unwrap();
for k in 0..N {
res = res + self[(i, k)] * rhs[(k, j)];
}
data[i][j] = res;
}
}
self.0 = data;
}
}
impl<const T: usize, const N: usize, const P: usize, L: Copy + Debug + ValueFrom<isize>> Mul<Matrix<N, P, L>> for Matrix<T, N, L> where L: Add<Output=L> + AddAssign + Mul<Output=L> + ValueFrom<isize> {
type Output = Matrix<T, P, L>;
fn mul(self, rhs: Matrix<N, P, L>) -> Self::Output {
let mut data = [[0.value_as().unwrap(); P]; T];
for i in 0..P {
for j in 0..T {
let mut res: L = 0.value_as().unwrap();
for k in 0..N {
res = res + (self.0[i][k] * rhs.0[k][j]);
}
data[i][j] = res;
}
}
Matrix::new(data)
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> Neg for Matrix<T, N, L> where L: Add<Output=L> + AddAssign + ValueFrom<isize> + Mul<Output=L> {
type Output = Self;
fn neg(self) -> Self::Output {
let mut data = self.0.clone();
for i in 0..T {
for j in 0..N {
data[i][j] = data[i][j] * (-1).value_as::<L>().unwrap();
}
}
Matrix::new(data)
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> Index<(usize, usize)> for Matrix<T, N, L> {
type Output = L;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&self.0[index.0][index.1]
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> IndexMut<(usize, usize)> for Matrix<T, N, L> {
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
&mut self.0[index.0][index.1]
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> PartialEq for Matrix<T, N, L> where L: PartialEq {
fn eq(&self, other: &Self) -> bool {
for i in 0..N {
for n in 0..T {
if self.0[n][i] != other.0[n][i] { return false }
}
}
true
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> Matrix<T, N, L> {
pub fn new(data: [[L; N]; T]) -> Self {
Self(data)
}
}
impl<const T: usize, const N: usize, L: Copy + Debug> Matrix<T, N, L> {
pub fn dtype<Q>(self) -> Matrix<T, N, Q> where Q: Copy + Debug + ValueFrom<L> + ValueFrom<isize> {
let mut out= [[0.value_as().unwrap(); N]; T];
for i in 0..T {
for n in 0..N {
out[i][n] = self[(i, n)].value_as::<Q>().unwrap()
}
}
Matrix::new(out)
}
pub fn transpose(&self) -> Matrix<N, T, L> where L: ValueFrom<isize> {
let mut data = [[0.value_as().unwrap(); T]; N];
for i in 0..T {
for j in 0..N {
data[j][i] = self.0[i][j];
}
}
Matrix::new(data)
}
pub fn scale<V>(&self, v: V) -> Matrix<T, N, L> where L: Clone + Mul<Output=L> + ValueFrom<V> {
let mut data = self.0.clone();
let multiplier: L = v.value_as().unwrap();
for i in 0..T {
for j in 0..N {
data[i][j] = data[i][j] * multiplier;
}
}
Matrix::new(data)
}
pub fn scale_set<V>(&mut self, v: V) where L: Clone + Mul<Output=L> + ValueFrom<V> {
let multiplier: L = v.value_as().unwrap();
for i in 0..T {
for j in 0..N {
self.0[i][j] = self.0[i][j] * multiplier;
}
}
}
}
impl<const T: usize, L: Copy + Debug> Matrix<T, T, L> {
pub fn determinant(&self) -> L where L: Add<Output=L> + Mul<Output=L> + ValueFrom<isize> {
fn perm_sign(p: Vec<&usize>) -> isize {
let mut out = 0;
for i in 0..p.len() {
for n in i+1..p.len() {
if p[i] > p[n] { out += 1 }
}
}
if out % 2 == 0 { 1 } else { -1 }
}
let mut out = 0.value_as().unwrap();
let permutation = (0..T).collect::<Vec<usize>>();
for p in permutation.iter().permutations(T) {
let mut temp: L = 1.value_as().unwrap();
for (r, c) in p.iter().enumerate() {
temp = temp * self[(r, **c)];
}
out = out + perm_sign(p).value_as::<L>().unwrap() * temp;
}
out
}
pub fn diag(&self) -> Vector<T, L> where L: ValueFrom<isize> {
let mut data = [0.value_as().unwrap(); T];
for i in 0..T {
data[i] = self[(i, i)];
}
Vector::new([data])
}
pub fn transpose_set(&mut self) {
for i in 0..T {
for j in i+1..T {
let temp = self.0[i][j];
self.0[i][j] = self.0[j][i];
self.0[j][i] = temp
}
}
}
}