use std::ops::{Mul, Add, Div, Sub, Index, Neg};
use libnum::{One, Zero, Float, FromPrimitive};
use std::cmp::{PartialEq, min};
use linalg::Metric;
use linalg::vector::Vector;
use linalg::utils;
mod decomposition;
pub struct Matrix<T> {
rows: usize,
cols: usize,
data: Vec<T>,
}
impl<T> Matrix<T> {
pub fn new(rows: usize, cols: usize, data: Vec<T>) -> Matrix<T> {
assert!(cols * rows == data.len(),
"Data does not match given dimensions.");
Matrix {
cols: cols,
rows: rows,
data: data,
}
}
pub fn rows(&self) -> usize {
self.rows
}
pub fn cols(&self) -> usize {
self.cols
}
pub fn data(&self) -> &Vec<T> {
&self.data
}
pub fn into_vec(self) -> Vec<T> {
self.data
}
}
impl<T: Clone> Clone for Matrix<T> {
fn clone(&self) -> Matrix<T> {
Matrix {
rows: self.rows,
cols: self.cols,
data: self.data.clone(),
}
}
}
impl<T: Copy> Matrix<T> {
pub fn select_rows(&self, rows: &[usize]) -> Matrix<T> {
let mut mat_vec = Vec::with_capacity(rows.len() * self.cols);
for row in rows {
assert!(*row < self.rows,
"Row index is greater than number of rows.");
}
unsafe {
for row in rows {
for i in 0..self.cols {
mat_vec.push(*self.data.get_unchecked(*row * self.cols + i));
}
}
}
Matrix {
cols: self.cols,
rows: rows.len(),
data: mat_vec,
}
}
pub fn select_cols(&self, cols: &[usize]) -> Matrix<T> {
let mut mat_vec = Vec::with_capacity(cols.len() * self.rows);
for col in cols {
assert!(*col < self.cols,
"Column index is greater than number of columns.");
}
unsafe {
for i in 0..self.rows {
for col in cols.into_iter() {
mat_vec.push(*self.data.get_unchecked(i * self.cols + col));
}
}
}
Matrix {
cols: cols.len(),
rows: self.rows,
data: mat_vec,
}
}
pub fn select(&self, rows: &[usize], cols: &[usize]) -> Matrix<T> {
let mut mat_vec = Vec::with_capacity(cols.len() * rows.len());
for col in cols {
assert!(*col < self.cols,
"Column index is greater than number of columns.");
}
for row in rows {
assert!(*row < self.rows,
"Row index is greater than number of columns.");
}
unsafe {
for row in rows.into_iter() {
for col in cols.into_iter() {
mat_vec.push(*self.data.get_unchecked(row * self.cols + col));
}
}
}
Matrix {
cols: cols.len(),
rows: rows.len(),
data: mat_vec,
}
}
pub fn hcat(&self, m: &Matrix<T>) -> Matrix<T> {
assert!(self.rows == m.rows, "Matrix row counts are not equal.");
let mut new_data = Vec::with_capacity((self.cols + m.cols) * self.rows);
unsafe {
for i in 0..self.rows {
for j in 0..self.cols {
new_data.push(*self.data.get_unchecked(i * self.cols + j));
}
for j in 0..m.cols {
new_data.push(*m.data.get_unchecked(i * m.cols + j));
}
}
}
Matrix {
cols: (self.cols + m.cols),
rows: self.rows,
data: new_data,
}
}
pub fn vcat(&self, m: &Matrix<T>) -> Matrix<T> {
assert!(self.cols == m.cols, "Matrix column counts are not equal.");
let mut new_data = Vec::with_capacity((self.rows + m.rows) * self.cols);
unsafe {
for i in 0..self.rows {
for j in 0..self.cols {
new_data.push(*self.data.get_unchecked(i * self.cols + j));
}
}
for i in 0..m.rows {
for j in 0..m.cols {
new_data.push(*m.data.get_unchecked(i * m.cols + j));
}
}
}
Matrix {
cols: self.cols,
rows: (self.rows + m.rows),
data: new_data,
}
}
pub fn diag(&self) -> Vector<T> {
let mat_min = min(self.rows, self.cols);
let mut diagonal = Vec::with_capacity(mat_min);
unsafe {
for i in 0..mat_min {
diagonal.push(*self.data.get_unchecked(i * self.cols + i));
}
}
Vector::new(diagonal)
}
pub fn apply(self, f: &Fn(T) -> T) -> Matrix<T> {
let new_data = self.data.into_iter().map(f).collect();
Matrix {
rows: self.rows,
cols: self.cols,
data: new_data,
}
}
}
impl<T: Zero + One + Copy> Matrix<T> {
pub fn zeros(rows: usize, cols: usize) -> Matrix<T> {
Matrix {
cols: cols,
rows: rows,
data: vec![T::zero(); cols*rows],
}
}
pub fn ones(rows: usize, cols: usize) -> Matrix<T> {
Matrix {
cols: cols,
rows: rows,
data: vec![T::one(); cols*rows],
}
}
pub fn identity(size: usize) -> Matrix<T> {
let mut data = vec![T::zero(); size * size];
for i in 0..size {
data[(i * (size + 1)) as usize] = T::one();
}
Matrix {
cols: size,
rows: size,
data: data,
}
}
pub fn from_diag(diag: &[T]) -> Matrix<T> {
let size = diag.len();
let mut data = vec![T::zero(); size * size];
for (i, item) in diag.into_iter().enumerate().take(size) {
data[i * (size + 1)] = *item;
}
Matrix {
cols: size,
rows: size,
data: data,
}
}
pub fn transpose(&self) -> Matrix<T> {
let mut new_data = vec![T::zero(); self.cols * self.rows];
for i in 0..self.cols {
for j in 0..self.rows {
new_data[i * self.rows + j] = self.data[j * self.cols + i];
}
}
Matrix {
cols: self.rows,
rows: self.cols,
data: new_data,
}
}
}
impl<T: Copy + Zero + One + PartialEq> Matrix<T> {
pub fn is_diag(&self) -> bool {
unsafe {
for i in 0..self.rows {
for j in 0..self.cols {
if (i != j) && (*self.data.get_unchecked(i * self.cols + j) != T::zero()) {
return false;
}
}
}
}
true
}
}
impl<T: Copy + Zero + One + Add<T, Output = T>> Matrix<T> {
pub fn sum_rows(&self) -> Vector<T> {
let mut row_sum = vec![T::zero(); self.cols];
unsafe {
for i in 0..self.rows {
for (j, item) in row_sum.iter_mut().enumerate().take(self.cols) {
*item = *item + *self.data.get_unchecked(i * self.cols + j);
}
}
}
Vector::new(row_sum)
}
pub fn sum_cols(&self) -> Vector<T> {
let mut col_sum = Vec::with_capacity(self.rows);
for i in 0..self.rows {
col_sum.push(utils::unrolled_sum(&self.data[i * self.cols..(i + 1) * self.cols]));
}
Vector::new(col_sum)
}
pub fn sum(&self) -> T {
utils::unrolled_sum(&self.data[..])
}
}
impl<T: Copy + Zero + Mul<T, Output = T>> Matrix<T> {
pub fn elemul(&self, m: &Matrix<T>) -> Matrix<T> {
assert!(self.rows == m.rows, "Matrix row counts not equal.");
assert!(self.cols == m.cols, "Matrix column counts not equal.");
Matrix::new(self.rows, self.cols, utils::ele_mul(&self.data, &m.data))
}
}
impl<T: Copy + Zero + Div<T, Output = T>> Matrix<T> {
pub fn elediv(&self, m: &Matrix<T>) -> Matrix<T> {
assert!(self.rows == m.rows, "Matrix row counts not equal.");
assert!(self.cols == m.cols, "Matrix column counts not equal.");
Matrix::new(self.rows, self.cols, utils::ele_div(&self.data, &m.data))
}
}
impl<T: Copy + Zero + Float + FromPrimitive> Matrix<T> {
pub fn mean(&self, axis: usize) -> Vector<T> {
let m: Vector<T>;
let n: T;
match axis {
0 => {
m = self.sum_rows();
n = FromPrimitive::from_usize(self.rows).unwrap();
}
1 => {
m = self.sum_cols();
n = FromPrimitive::from_usize(self.cols).unwrap();
}
_ => panic!("Axis must be 0 or 1."),
}
m / n
}
pub fn variance(&self, axis: usize) -> Vector<T> {
let mean = self.mean(axis);
let n: usize;
let m: usize;
match axis {
0 => {
n = self.rows;
m = self.cols;
}
1 => {
n = self.cols;
m = self.rows;
}
_ => panic!("Axis must be 0 or 1."),
}
let mut variance = Vector::new(vec![T::zero(); m]);
for i in 0..n {
let mut t = Vec::<T>::with_capacity(m);
unsafe {
for j in 0..m {
match axis {
0 => t.push(*self.data.get_unchecked(i * m + j)),
1 => t.push(*self.data.get_unchecked(j * n + i)),
_ => panic!("Axis must be 0 or 1."),
}
}
}
let v = Vector::new(t);
variance = variance + &(&v - &mean).elemul(&(&v - &mean));
}
let var_size: T = FromPrimitive::from_usize(n - 1).unwrap();
variance / var_size
}
}
impl<T> Matrix<T> where T: Copy + One + Zero + Neg<Output=T> +
Add<T, Output=T> + Mul<T, Output=T> +
Sub<T, Output=T> + Div<T, Output=T> +
PartialOrd {
fn solve_u_triangular(&self, y: Vector<T>) -> Vector<T> {
assert!(self.cols == y.size(), "Matrix and Vector dimensions do not agree.");
let mut x = vec![T::zero(); y.size()];
x[y.size()-1] = y[y.size()-1] / self[[y.size()-1,y.size()-1]];
unsafe {
for i in (0..y.size()-1).rev() {
let mut holding_u_sum = T::zero();
for j in (i+1..y.size()).rev() {
holding_u_sum = holding_u_sum + *self.data.get_unchecked(i * self.cols + j) * x[j];
}
x[i] = (y[i] - holding_u_sum) / *self.data.get_unchecked(i*(self.cols+1));
}
}
Vector::new(x)
}
fn solve_l_triangular(&self, y: Vector<T>) -> Vector<T> {
assert!(self.cols == y.size(), "Matrix and Vector dimensions do not agree.");
let mut x = Vec::with_capacity(y.size());
x.push(y[0] / self[[0,0]]);
unsafe {
for (i,y_item) in y.data().iter().enumerate().take(y.size()).skip(1) {
let mut holding_l_sum = T::zero();
for (j, x_item) in x.iter().enumerate().take(i) {
holding_l_sum = holding_l_sum + *self.data.get_unchecked(i * self.cols + j) * *x_item;
}
x.push((*y_item - holding_l_sum) / *self.data.get_unchecked(i*(self.cols+1)));
}
}
Vector::new(x)
}
fn parity(&self) -> T {
let mut visited = vec![false; self.rows];
let mut sgn = T::one();
for k in 0..self.rows {
if !visited[k] {
let mut next = k;
let mut len = 0;
while !visited[next] {
len += 1;
visited[next] = true;
next = utils::find(&self.data[next*self.cols..(next+1)*self.cols], T::one());
}
if len % 2 == 0 {
sgn = -sgn;
}
}
}
sgn
}
pub fn solve(&self, y: Vector<T>) -> Vector<T> {
let (l,u,p) = self.lup_decomp();
let b = l.solve_l_triangular(p * y);
u.solve_u_triangular(b)
}
pub fn inverse(&self) -> Matrix<T> {
assert!(self.rows==self.cols, "Matrix is not square.");
let mut new_t_data = Vec::<T>::new();
let (l,u,p) = self.lup_decomp();
let mut d = T::one();
unsafe {
for i in 0..l.cols {
d = d * *l.data.get_unchecked(i*(l.cols+1));
d = d * *u.data.get_unchecked(i*(u.cols+1));
}
}
if d == T::zero() {
panic!("Matrix has zero determinant.")
}
for i in 0..self.rows {
let mut id_col = vec![T::zero(); self.cols];
id_col[i] = T::one();
let b = l.solve_l_triangular(&p * Vector::new(id_col));
new_t_data.append(&mut u.solve_u_triangular(b).into_vec());
}
Matrix::new(self.rows, self.cols, new_t_data).transpose()
}
pub fn det(&self) -> T {
assert!(self.rows==self.cols, "Matrix is not square.");
let n = self.cols;
if self.is_diag() {
let mut d = T::one();
unsafe {
for i in 0..n {
d = d * *self.data.get_unchecked(i*(self.cols+1));
}
}
return d;
}
if n == 2 {
return (self[[0,0]] * self[[1,1]]) - (self[[0,1]] * self[[1,0]]);
}
if n == 3 {
return (self[[0,0]] * self[[1,1]] * self[[2,2]]) + (self[[0,1]] * self[[1,2]] * self[[2,0]])
+ (self[[0,2]] * self[[1,0]] * self[[2,1]]) - (self[[0,0]] * self[[1,2]] * self[[2,1]])
- (self[[0,1]] * self[[1,0]] * self[[2,2]]) - (self[[0,2]] * self[[1,1]] * self[[2,0]]);
}
let (l,u,p) = self.lup_decomp();
let mut d = T::one();
unsafe {
for i in 0..l.cols {
d = d * *l.data.get_unchecked(i*(l.cols+1));
d = d * *u.data.get_unchecked(i*(u.cols+1));
}
}
let sgn = p.parity();
sgn * d
}
}
impl<T: Copy + One + Zero + Mul<T, Output = T>> Mul<T> for Matrix<T> {
type Output = Matrix<T>;
fn mul(self, f: T) -> Matrix<T> {
(&self) * (&f)
}
}
impl<'a, T: Copy + One + Zero + Mul<T, Output = T>> Mul<&'a T> for Matrix<T> {
type Output = Matrix<T>;
fn mul(self, f: &T) -> Matrix<T> {
(&self) * f
}
}
impl<'a, T: Copy + One + Zero + Mul<T, Output = T>> Mul<T> for &'a Matrix<T> {
type Output = Matrix<T>;
fn mul(self, f: T) -> Matrix<T> {
self * (&f)
}
}
impl<'a, 'b, T: Copy + One + Zero + Mul<T, Output = T>> Mul<&'b T> for &'a Matrix<T> {
type Output = Matrix<T>;
fn mul(self, f: &T) -> Matrix<T> {
let new_data: Vec<T> = self.data.iter().map(|v| (*v) * (*f)).collect();
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
impl<T: Copy + Zero + One + Mul<T, Output = T> + Add<T, Output = T>> Mul<Matrix<T>> for Matrix<T> {
type Output = Matrix<T>;
fn mul(self, m: Matrix<T>) -> Matrix<T> {
(&self) * (&m)
}
}
impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<Matrix<T>> for &'a Matrix<T> {
type Output = Matrix<T>;
fn mul(self, m: Matrix<T>) -> Matrix<T> {
self * (&m)
}
}
impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'a Matrix<T>> for Matrix<T> {
type Output = Matrix<T>;
fn mul(self, m: &Matrix<T>) -> Matrix<T> {
(&self) * m
}
}
impl<'a, 'b, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'b Matrix<T>> for &'a Matrix<T> {
type Output = Matrix<T>;
fn mul(self, m: &Matrix<T>) -> Matrix<T> {
assert!(self.cols == m.rows, "Matrix dimensions do not agree.");
let mut new_data = vec![T::zero(); self.rows * m.cols];
unsafe {
for i in 0..self.rows
{
for k in 0..m.rows
{
for j in 0..m.cols
{
new_data[i*m.cols() + j] = *new_data.get_unchecked(i*m.cols() + j) + *self.data.get_unchecked(i * self.cols + k) * *m.data.get_unchecked(k*m.cols + j);
}
}
}
}
Matrix {
rows: self.rows,
cols: m.cols,
data: new_data
}
}
}
impl<T: Copy + Zero + One + Mul<T, Output = T> + Add<T, Output = T>> Mul<Vector<T>> for Matrix<T> {
type Output = Vector<T>;
fn mul(self, m: Vector<T>) -> Vector<T> {
(&self) * (&m)
}
}
impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<Vector<T>> for &'a Matrix<T> {
type Output = Vector<T>;
fn mul(self, m: Vector<T>) -> Vector<T> {
self * (&m)
}
}
impl <'a, T: Copy + Zero + One + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'a Vector<T>> for Matrix<T> {
type Output = Vector<T>;
fn mul(self, m: &Vector<T>) -> Vector<T> {
(&self) * m
}
}
impl<'a, 'b, T: Copy + One + Zero + Mul<T, Output=T> + Add<T, Output=T>> Mul<&'b Vector<T>> for &'a Matrix<T> {
type Output = Vector<T>;
fn mul(self, v: &Vector<T>) -> Vector<T> {
assert!(v.size() == self.cols, "Matrix and Vector dimensions do not agree.");
let mut new_data = Vec::with_capacity(self.rows);
for i in 0..self.rows
{
new_data.push(utils::dot(&self.data[i*self.cols..(i+1)*self.cols], v.data()));
}
Vector::new(new_data)
}
}
impl<T: Copy + One + Zero + Add<T, Output = T>> Add<T> for Matrix<T> {
type Output = Matrix<T>;
fn add(self, f: T) -> Matrix<T> {
(&self) + (&f)
}
}
impl<'a, T: Copy + One + Zero + Add<T, Output = T>> Add<T> for &'a Matrix<T> {
type Output = Matrix<T>;
fn add(self, f: T) -> Matrix<T> {
self + (&f)
}
}
impl<'a, T: Copy + One + Zero + Add<T, Output = T>> Add<&'a T> for Matrix<T> {
type Output = Matrix<T>;
fn add(self, f: &T) -> Matrix<T> {
(&self) + f
}
}
impl<'a, 'b, T: Copy + One + Zero + Add<T, Output = T>> Add<&'b T> for &'a Matrix<T> {
type Output = Matrix<T>;
fn add(self, f: &T) -> Matrix<T> {
let new_data: Vec<T> = self.data.iter().map(|v| (*v) + (*f)).collect();
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
impl<T: Copy + One + Zero + Add<T, Output = T>> Add<Matrix<T>> for Matrix<T> {
type Output = Matrix<T>;
fn add(self, f: Matrix<T>) -> Matrix<T> {
(&self) + (&f)
}
}
impl<'a, T: Copy + One + Zero + Add<T, Output = T>> Add<Matrix<T>> for &'a Matrix<T> {
type Output = Matrix<T>;
fn add(self, f: Matrix<T>) -> Matrix<T> {
self + (&f)
}
}
impl<'a, T: Copy + One + Zero + Add<T, Output = T>> Add<&'a Matrix<T>> for Matrix<T> {
type Output = Matrix<T>;
fn add(self, f: &Matrix<T>) -> Matrix<T> {
(&self) + f
}
}
impl<'a, 'b, T: Copy + One + Zero + Add<T, Output = T>> Add<&'b Matrix<T>> for &'a Matrix<T> {
type Output = Matrix<T>;
fn add(self, m: &Matrix<T>) -> Matrix<T> {
assert!(self.cols == m.cols, "Column dimensions do not agree.");
assert!(self.rows == m.rows, "Row dimensions do not agree.");
let new_data = utils::vec_sum(&self.data, &m.data);
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
impl<T: Copy + One + Zero + Sub<T, Output = T>> Sub<T> for Matrix<T> {
type Output = Matrix<T>;
fn sub(self, f: T) -> Matrix<T> {
(&self) - (&f)
}
}
impl<'a, T: Copy + One + Zero + Sub<T, Output = T>> Sub<&'a T> for Matrix<T> {
type Output = Matrix<T>;
fn sub(self, f: &T) -> Matrix<T> {
(&self) - f
}
}
impl<'a, T: Copy + One + Zero + Sub<T, Output = T>> Sub<T> for &'a Matrix<T> {
type Output = Matrix<T>;
fn sub(self, f: T) -> Matrix<T> {
self - (&f)
}
}
impl<'a, 'b, T: Copy + One + Zero + Sub<T, Output = T>> Sub<&'b T> for &'a Matrix<T> {
type Output = Matrix<T>;
fn sub(self, f: &T) -> Matrix<T> {
let new_data = self.data.iter().map(|v| *v - *f).collect();
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
impl<T: Copy + One + Zero + Sub<T, Output = T>> Sub<Matrix<T>> for Matrix<T> {
type Output = Matrix<T>;
fn sub(self, f: Matrix<T>) -> Matrix<T> {
(&self) - (&f)
}
}
impl<'a, T: Copy + One + Zero + Sub<T, Output = T>> Sub<Matrix<T>> for &'a Matrix<T> {
type Output = Matrix<T>;
fn sub(self, f: Matrix<T>) -> Matrix<T> {
self - (&f)
}
}
impl<'a, T: Copy + One + Zero + Sub<T, Output = T>> Sub<&'a Matrix<T>> for Matrix<T> {
type Output = Matrix<T>;
fn sub(self, f: &Matrix<T>) -> Matrix<T> {
(&self) - f
}
}
impl<'a, 'b, T: Copy + One + Zero + Sub<T, Output = T>> Sub<&'b Matrix<T>> for &'a Matrix<T> {
type Output = Matrix<T>;
fn sub(self, m: &Matrix<T>) -> Matrix<T> {
assert!(self.cols == m.cols, "Column dimensions do not agree.");
assert!(self.rows == m.rows, "Row dimensions do not agree.");
let new_data = utils::vec_sub(&self.data, &m.data);
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
impl<T: Copy + One + Zero + PartialEq + Div<T, Output = T>> Div<T> for Matrix<T> {
type Output = Matrix<T>;
fn div(self, f: T) -> Matrix<T> {
(&self) / (&f)
}
}
impl<'a, T: Copy + One + Zero + PartialEq + Div<T, Output = T>> Div<T> for &'a Matrix<T> {
type Output = Matrix<T>;
fn div(self, f: T) -> Matrix<T> {
self / (&f)
}
}
impl<'a, T: Copy + One + Zero + PartialEq + Div<T, Output = T>> Div<&'a T> for Matrix<T> {
type Output = Matrix<T>;
fn div(self, f: &T) -> Matrix<T> {
(&self) / f
}
}
impl<'a, 'b, T: Copy + One + Zero + PartialEq + Div<T, Output = T>> Div<&'b T> for &'a Matrix<T> {
type Output = Matrix<T>;
fn div(self, f: &T) -> Matrix<T> {
assert!(*f != T::zero());
let new_data = self.data.iter().map(|v| *v / *f).collect();
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
impl<T: Neg<Output = T> + Copy> Neg for Matrix<T> {
type Output = Matrix<T>;
fn neg(self) -> Matrix<T> {
let new_data = self.data.iter().map(|v| -*v).collect();
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
impl<'a, T: Neg<Output = T> + Copy> Neg for &'a Matrix<T> {
type Output = Matrix<T>;
fn neg(self) -> Matrix<T> {
let new_data = self.data.iter().map(|v| -*v).collect();
Matrix {
cols: self.cols,
rows: self.rows,
data: new_data,
}
}
}
impl<T> Index<[usize; 2]> for Matrix<T> {
type Output = T;
fn index(&self, idx: [usize; 2]) -> &T {
assert!(idx[0] < self.rows,
"Row index is greater than row dimension.");
assert!(idx[1] < self.cols,
"Column index is greater than column dimension.");
unsafe { &self.data.get_unchecked(idx[0] * self.cols + idx[1]) }
}
}
impl<T: Float> Metric<T> for Matrix<T> {
fn norm(&self) -> T {
let s = utils::dot(&self.data[..], &self.data[..]);
s.sqrt()
}
}