use rand::random;
use std::ops;
#[derive(Clone)]
pub struct Matrix {
nrows: i16,
ncols: i16,
data: Vec<Vec<f64>>
}
impl Matrix {
#[allow(dead_code)]
pub fn nrows(&self) -> i16 {
self.nrows
}
#[allow(dead_code)]
pub fn ncols(&self) -> i16 {
self.ncols
}
#[allow(dead_code)]
pub fn set(&mut self, x: i16, y: i16, v: f64) {
assert!(x >= 0 && x <= (self.data.len() as i16 -1), "{}", format!("Row Index out of bounds! {} but got Index:{}", self.get_shape_string(), x));
assert!(y >= 0 && y <= (self.data[0].len() as i16 -1), "{}", format!("Column Index out of bounds! {} but got Index:{}", self.get_shape_string(), y));
self.data[x as usize][y as usize] = v;
}
#[allow(dead_code)]
pub fn get(&self, x: i16, y: i16) -> f64 {
assert!(x >= 0 && x <= (self.data.len() as i16 -1), "{}", format!("Row Index out of bounds! {} but got Index:{}", self.get_shape_string(), x));
assert!(y >= 0 && y <= (self.data[0].len() as i16 -1), "{}", format!("Column Index out of bounds! {} but got Index:{}", self.get_shape_string(), y));
return self.data[x as usize][y as usize];
}
#[allow(dead_code)]
pub fn add(a: &Matrix, b: &Matrix) -> Matrix {
assert!(a.ncols() == b.nrows(), "{}", format!("Dimensional mismatch! A: [{}, {}] | B: [{}, {}]", a.nrows(), a.ncols(), b.nrows(), b.ncols()));
let mut data = Vec::<Vec<f64>>::new();
for i in 0..(a.nrows) {
let mut row = Vec::<f64>::new();
for j in 0..(a.ncols) {
row.push(a.data[i as usize][j as usize] + b.data[i as usize][j as usize])
}
data.push(row);
}
Matrix {
nrows: a.nrows,
ncols: a.ncols,
data: data
}
}
#[allow(dead_code)]
pub fn sub(a: &Matrix, b: &Matrix) -> Matrix {
assert!(a.ncols() == b.nrows(), "{}", format!("Dimensional mismatch! A: [{}, {}] | B: [{}, {}]", a.nrows(), a.ncols(), b.nrows(), b.ncols()));
let mut data = Vec::<Vec<f64>>::new();
for i in 0..(a.nrows) {
let mut row = Vec::<f64>::new();
for j in 0..(a.ncols) {
row.push(a.data[i as usize][j as usize] - b.data[i as usize][j as usize])
}
data.push(row);
}
Matrix {
nrows: a.nrows,
ncols: a.ncols,
data: data
}
}
#[allow(dead_code)]
pub fn mul(a: &Matrix, b: &Matrix) -> Matrix {
assert!(a.ncols() == b.nrows(), "{}", format!("Dimensional mismatch! A: [{}, {}] | B: [{}, {}]", a.nrows(), a.ncols(), b.nrows(), b.ncols()));
let mut data = Vec::<Vec<f64>>::new();
for i in 0..(a.nrows) {
let mut row = Vec::<f64>::new();
for j in 0..(a.ncols) {
row.push(a.data[i as usize][j as usize] * b.data[i as usize][j as usize])
}
data.push(row);
}
Matrix {
nrows: a.nrows,
ncols: a.ncols,
data: data
}
}
#[allow(dead_code)]
pub fn div(a: &Matrix, b: &Matrix) -> Matrix {
assert!(a.ncols() == b.nrows(), "{}", format!("Dimensional mismatch! A: [{}, {}] | B: [{}, {}]", a.nrows(), a.ncols(), b.nrows(), b.ncols()));
let mut data = Vec::<Vec<f64>>::new();
for i in 0..(a.nrows) {
let mut row = Vec::<f64>::new();
for j in 0..(a.ncols) {
row.push(a.data[i as usize][j as usize] / b.data[i as usize][j as usize])
}
data.push(row);
}
Matrix {
nrows: a.nrows,
ncols: a.ncols,
data: data
}
}
#[allow(dead_code)]
pub fn dot(a: &Matrix, b: &Matrix) -> Matrix {
assert!(a.ncols() == b.nrows(), "{}", format!("Dimensional mismatch! A: [{}, {}] | B: [{}, {}]", a.nrows(), a.ncols(), b.nrows(), b.ncols()));
let mut mat = Matrix::create_matrix(a.nrows(), b.ncols());
for i in 0..(mat.nrows()) {
for k in 0..(mat.ncols()) {
for j in 0..(a.ncols()) {
mat.set(i, k, mat.get(i, k) + a.get(i, j) * b.get(j, k))
}
}
}
mat
}
#[allow(dead_code)]
pub fn transpose(a: &Matrix) -> Matrix {
let mut data = Matrix::create_matrix(a.ncols, a.nrows);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
data.set(j, i, a.get(i, j));
}
}
data
}
#[allow(dead_code)]
pub fn map(&self, f: fn(f64) -> f64) -> Matrix {
let mut data = Matrix::create_matrix(self.nrows, self.ncols);
for i in 0..(self.nrows) {
for j in 0..(self.ncols) {
data.set(i, j, f(self.data[i as usize][j as usize]));
}
}
data
}
#[allow(dead_code)]
pub fn scalar_add(a: &Matrix, v: f64) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows, a.ncols);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
data.set(i, j, a.get(i, j) + v);
}
}
data
}
#[allow(dead_code)]
pub fn scalar_sub(a: &Matrix, v: f64) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows, a.ncols);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
data.set(i, j, a.get(i, j) - v);
}
}
data
}
#[allow(dead_code)]
pub fn scalar_sub_first(a: &Matrix, v: f64) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows, a.ncols);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
data.set(i, j, v - a.get(i, j));
}
}
data
}
#[allow(dead_code)]
pub fn scalar_mult(a: &Matrix, v: f64) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows, a.ncols);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
data.set(i, j, a.get(i, j) * v);
}
}
data
}
#[allow(dead_code)]
pub fn scalar_div(a: &Matrix, v: f64) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows, a.ncols);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
data.set(i, j, a.get(i, j) / v);
}
}
data
}
#[allow(dead_code)]
pub fn inverse(a: &Matrix) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows, a.ncols);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
data.set(i, j, -a.get(i, j));
}
}
data
}
#[allow(dead_code)]
pub fn sum_rows(a: &Matrix) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows(), 1);
for i in 0..(a.nrows()) {
let mut sum: f64 = 0.0;
for j in 0..(a.ncols()) {
sum += a.get(i, j);
}
data.set(i, 0, sum);
}
return data;
}
#[allow(dead_code)]
pub fn pow(a: &Matrix, v: f64) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows, a.ncols);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
data.set(i, j, a.get(i, j).powf(v));
}
}
data
}
#[allow(dead_code)]
pub fn filter_by_function(a: &Matrix, f: fn(f64) -> bool, v: f64) -> Matrix {
let mut data = Matrix::create_matrix(a.nrows, a.ncols);
for i in 0..(a.nrows) {
for j in 0..(a.ncols) {
let temp = a.get(i, j);
match f(temp) {
false => data.set(i, j, v),
true => data.set(i, j, temp)
}
}
}
data
}
#[allow(dead_code)]
fn get_digits(&self, i: &f64) -> i32 {
i.to_string().chars().count() as i32
}
#[allow(dead_code)]
pub fn get_shape_string(&self) -> String {
format!("Shape:({}, {})", self.nrows(), self.ncols())
}
#[allow(dead_code)]
fn get_most_digits(&self) -> i32 {
let mut cnt: i32 = 0;
for i in 0..(self.data.len()) {
for j in 0..(self.data[i].len()) {
let digits = self.get_digits(&self.data[i][j]);
if digits > cnt {
cnt = digits;
}
}
}
cnt
}
#[allow(dead_code)]
fn to_append(&self, i: &f64, cnt: i32) -> String {
let mut appendix = String::new();
for _ in 0..(cnt - self.get_digits(i)) {
appendix = format!("{}{}", appendix, " ");
}
appendix
}
#[allow(dead_code)]
fn before_print(&self, cnt: i32) -> String {
let mut appendix = String::new();
for _ in 0..(cnt * (self.ncols() as i32) + 3 + (self.ncols() as i32) ) {
appendix = format!("{}{}", appendix, "-");
}
appendix
}
#[allow(dead_code)]
pub fn print(&self) {
let most_digits: i32 = self.get_most_digits();
println!("\t{}", self.before_print(most_digits));
for i in 0..(self.data.len()) {
for j in 0..(self.data[i].len()) {
if j == 0 && j == self.data[i].len() - 1 {
let current = self.get(i as i16, j as i16);
print!("\t| {}{} |\n", current, self.to_append(¤t, most_digits));
}
else if j == 0 {
let current = self.get(i as i16, j as i16);
print!("\t| {}{}", current, self.to_append(¤t, most_digits));
} else if j == self.data[i].len() - 1 {
let current = self.get(i as i16, j as i16);
print!(" {}{} |\n", current, self.to_append(¤t, most_digits));
} else {
let current = self.get(i as i16, j as i16);
print!(" {}{}", current, self.to_append(¤t, most_digits));
}
}
}
println!("\t{}", self.before_print(most_digits));
println!("\t{}", self.get_shape_string());
}
#[allow(dead_code)]
pub fn create_matrix(nrows: i16, ncols: i16) -> Matrix {
let mut data = Vec::<Vec<f64>>::new();
for _ in 0..nrows {
let mut row = Vec::<f64>::new();
for _ in 0..ncols {
row.push(0.0);
}
data.push(row);
}
Matrix {
nrows: nrows,
ncols: ncols,
data: data
}
}
#[allow(dead_code)]
pub fn create_random_matrix(nrows: i16, ncols: i16) -> Matrix {
let mut data = Vec::<Vec<f64>>::new();
for _ in 0..nrows {
let mut row = Vec::<f64>::new();
for _ in 0..ncols {
row.push(random());
}
data.push(row);
}
Matrix {
nrows: nrows,
ncols: ncols,
data: data
}
}
#[allow(dead_code)]
pub fn create_matrix_by_float(nrows: i16, ncols: i16, v: f64) -> Matrix {
let mut data = Vec::<Vec<f64>>::new();
for _ in 0..nrows {
let mut row = Vec::<f64>::new();
for _ in 0..ncols {
row.push(v);
}
data.push(row);
}
Matrix {
nrows: nrows,
ncols: ncols,
data: data
}
}
#[allow(dead_code)]
pub fn create_matrix_from_nested_float_array(v: &[&[f64]]) -> Matrix {
assert!(v.len() != 0, "Please provide filled Arrays");
let mut mat: Matrix = Matrix::create_matrix(v.len() as i16, v[0].len() as i16);
for i in 0..(v.len()) {
for j in 0..(v[i].len()) {
mat.set(i as i16, j as i16, v[i][j]);
}
}
mat
}
}
impl ops::Index<ops::Range<usize>> for Matrix {
type Output = f64;
fn index(&self, l: ops::Range<usize>) -> &f64 {
let i = &l.start;
let j = &l.end;
&self.data[ *i as usize][ *j as usize]
}
}
impl ops::Not for Matrix {
type Output = Matrix;
fn not(self) -> Self::Output {
Matrix::inverse(&self)
}
}
impl ops::Add<Matrix> for Matrix {
type Output = Matrix;
fn add(self, _rhs: Matrix) -> Matrix {
Matrix::add(&self, &_rhs)
}
}
impl ops::Mul<Matrix> for Matrix {
type Output = Matrix;
fn mul(self, _rhs: Matrix) -> Matrix {
Matrix::mul(&self, &_rhs)
}
}
impl ops::Sub<Matrix> for Matrix {
type Output = Matrix;
fn sub(self, _rhs: Matrix) -> Matrix {
Matrix::sub(&self, &_rhs)
}
}
impl ops::Div<Matrix> for Matrix {
type Output = Matrix;
fn div(self, _rhs: Matrix) -> Matrix {
Matrix::div(&self, &_rhs)
}
}
impl ops::BitOr<Matrix> for Matrix {
type Output = Matrix;
fn bitor(self, rhs: Matrix) -> Matrix {
Matrix::dot(&self, &rhs)
}
}
impl ops::AddAssign<Matrix> for Matrix {
fn add_assign(&mut self, _rhs: Matrix) {
*self = Matrix::add(self, &_rhs);
}
}
impl ops::MulAssign<Matrix> for Matrix {
fn mul_assign(&mut self, _rhs: Matrix) {
*self = Matrix::mul(self, &_rhs);
}
}
impl ops::DivAssign<Matrix> for Matrix {
fn div_assign(&mut self, _rhs: Matrix) {
*self = Matrix::div(self, &_rhs);
}
}
impl ops::SubAssign<Matrix> for Matrix {
fn sub_assign(&mut self, _rhs: Matrix) {
*self = Matrix::sub(self, &_rhs);
}
}