use std::fmt::Display;
use std::iter::zip;
use std::ops::{Add, AddAssign, BitOr, Index, IndexMut, Mul, Sub, SubAssign};
use crate::{Matrix, Element};
impl <T> Display for Matrix<T>
where T: Element<T>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut output = String::new();
let r = self.rows - 1;
let c = self.cols - 1;
for i in 0..r
{
for j in 0..c
{
output += format!("{}, ", self[(i, j)]).as_str();
}
output += format!("{}; ", self[(i, c)]).as_str();
}
for j in 0..c
{
output += format!("{}, ", self[(r, j)]).as_str();
}
output += format!("{}]", self[(r, c)]).as_str();
write!(f, "{}", output)
}
}
impl <T> BitOr for &Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn bitor(self, rhs: Self) -> Self::Output
{
self.augment_with(rhs).unwrap()
}
}
impl <T> Add for Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn add(self, rhs: Self) -> Self::Output
{
&self + &rhs
}
}
impl <T> Add<Matrix<T>> for &Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn add(self, rhs: Matrix<T>) -> Self::Output
{
self + &rhs
}
}
impl <T> Add<&Matrix<T>> for Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn add(self, rhs: &Matrix<T>) -> Self::Output
{
&self + rhs
}
}
impl <T> Add<&Matrix<T>> for &Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn add(self, rhs: &Matrix<T>) -> Self::Output
{
if self.rows != rhs.rows ||
self.cols != rhs.cols
{
panic!("cannot add elements of matrices with different sizes")
}
let mut ret_val = Matrix::new(self.rows, self.cols);
ret_val.vals = Vec::from_iter(
zip(&self.vals, &rhs.vals)
.map(|(l, r)| *l + *r)
);
ret_val
}
}
impl <T> AddAssign for Matrix<T>
where T: Element<T>
{
fn add_assign(&mut self, rhs: Self)
{
if self.rows != rhs.rows ||
self.cols != rhs.cols
{
panic!("cannot add elements of matrices with different sizes")
}
for (i, elem) in rhs.iter().enumerate()
{
self.vals[i] += *elem;
}
}
}
impl <T> Sub<Matrix<T>> for Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn sub(self, rhs: Matrix<T>) -> Self::Output {
&self - &rhs
}
}
impl <T> Sub<Matrix<T>> for &Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn sub(self, rhs: Matrix<T>) -> Self::Output {
self - &rhs
}
}
impl <T> Sub<&Matrix<T>> for Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn sub(self, rhs: &Matrix<T>) -> Self::Output {
&self - rhs
}
}
impl <T> Sub<&Matrix<T>> for &Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn sub(self, rhs: &Matrix<T>) -> Self::Output
{
if self.rows != rhs.rows ||
self.cols != rhs.cols
{
panic!("cannot subtract elements of matrices with different sizes")
}
let mut ret_val = Matrix::new(self.rows, self.cols);
ret_val.vals = Vec::from_iter(
zip(&self.vals, &rhs.vals)
.map(|(l, r)| *l - *r)
);
ret_val
}
}
impl <T> SubAssign for Matrix<T>
where T: Element<T>
{
fn sub_assign(&mut self, rhs: Self)
{
if self.rows != rhs.rows ||
self.cols != rhs.cols
{
panic!("cannot subtract elements of matrices with different sizes")
}
for (i, elem) in rhs.iter().enumerate()
{
self.vals[i] -= *elem;
}
}
}
impl <T> Mul for Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
#[inline]
fn mul(self, rhs: Self) -> Self::Output
{
self.multiply_matrix(&rhs).unwrap()
}
}
impl <T> Mul<Matrix<T>> for &Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn mul(self, rhs: Matrix<T>) -> Self::Output
{
self.multiply_matrix(&rhs).unwrap()
}
}
impl <T> Mul<&Matrix<T>> for Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn mul(self, rhs: &Matrix<T>) -> Self::Output
{
self.multiply_matrix(rhs).unwrap()
}
}
impl <T> Mul<&Matrix<T>> for &Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn mul(self, rhs: &Matrix<T>) -> Self::Output
{
self.multiply_matrix(rhs).unwrap()
}
}
impl <T> Mul<T> for Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn mul(self, rhs: T) -> Self::Output {
let mut result = self.clone();
result.inplace_scale(rhs);
result
}
}
impl <T> Mul<T> for &Matrix<T>
where T: Element<T>
{
type Output = Matrix<T>;
fn mul(self, rhs: T) -> Self::Output {
let mut result = self.clone();
result.inplace_scale(rhs);
result
}
}
impl <T> From<Matrix<T>> for Vec<T>
where T: Element<T>
{
fn from(value: Matrix<T>) -> Self {
value.vals
}
}
impl <T> Index<(usize, usize)> for Matrix<T>
where T: Element<T>
{
type Output = T;
#[inline]
fn index(&self, index: (usize, usize)) -> &T
{
if index.0 >= self.rows || index.1 >= self.cols
{
panic!("index out of bounds: the matrix has {} rows and {} cols but the index was [({}, {})]", self.rows, self.cols, index.0, index.1)
}
&(self.vals[index.0 * self.cols + index.1])
}
}
impl <T> IndexMut<(usize, usize)> for Matrix<T>
where T: Element<T>
{
#[inline]
fn index_mut(&mut self, index: (usize, usize)) -> &mut T
{
&mut (self.vals[index.0 * self.cols + index.1])
}
}