pub mod operations;
pub mod csv;
mod macro_matrix;
mod add_impl;
mod sub_impl;
mod mul_impl;
mod div_impl;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::ops::{Index, IndexMut, Range};
use crate::operations::*;
pub struct Matrix<T> {
pub(crate) data: Vec<T>,
pub(crate) shape: (usize, usize),
}
impl<T> Index<usize> for Matrix<T> {
type Output = [T];
fn index(&self, index: usize) -> &Self::Output {
let start = index * self.shape.1;
let end = start + self.shape.1;
&self.data[start..end]
}
}
impl<T: Copy + Default> Index<Range<usize>> for Matrix<T> {
type Output = [T];
fn index(&self, index: Range<usize>) -> &Self::Output {
let start = index.start * self.shape.1;
let end = index.end * self.shape.1;
&self.data[start..end]
}
}
impl<T: Copy> Clone for Matrix<T> where T: Clone {
fn clone(&self) -> Self {
Matrix {
data: self.data.clone(),
shape: self.shape,
}
}
}
impl<T> PartialEq for Matrix<T> where T: Eq {
fn eq(&self, other: &Self) -> bool {
self.data == other.data && self.shape == other.shape
}
}
impl<T> IndexMut<usize> for Matrix<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
let start = index * self.shape.1;
let end = start + self.shape.1;
&mut self.data[start..end]
}
}
impl<T: Debug> Debug for Matrix<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut s = String::from(format!("({}, {}) : ", self.shape.0, self.shape.1));
s.push_str("[");
for i in 0..self.shape.0 {
s.push_str("[");
for j in 0..self.shape.1 {
s.push_str(&format!("{:?}, ", self[i][j]));
}
s.remove(s.len() - 1);
s.remove(s.len() - 1);
s.push_str("], ");
}
s.remove(s.len() - 1);
s.remove(s.len() - 1);
s.push_str("]");
write!(f, "{}", s)
}
}
impl<T> Display for Matrix<T> where T: Display {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut s = String::new();
for i in 0..self.shape.0 {
for j in 0..self.shape.1 {
s.push_str(&format!("{} ", self[i][j]));
}
s.push_str("\n");
}
write!(f, "{}", s)
}
}
impl<T: Default + Copy> Matrix<T> {
pub fn new(data: Vec<T>, shape: (usize, usize)) -> Result<Matrix<T>, Box<dyn Error>> {
if data.len() != shape.0 * shape.1 {
return Err("Data length does not match shape".into());
}
Ok(Matrix { data, shape })
}
pub fn new_default(shape: (usize, usize)) -> Matrix<T> {
Matrix {
data: vec![T::default(); shape.0 * shape.1],
shape,
}
}
pub fn new_initialised(shape: (usize, usize), value: T) -> Matrix<T> {
Matrix {
data: vec![value; shape.0 * shape.1],
shape,
}
}
pub fn from_slice(data: &[T], shape: (usize, usize)) -> Result<Matrix<T>, Box<dyn Error>> {
if data.len() != shape.0 * shape.1 {
return Err("Data length does not match shape".into());
}
Ok(Matrix {
data: data.to_vec(),
shape,
})
}
pub fn from_vec(data: Vec<T>, shape: (usize, usize)) -> Result<Matrix<T>, Box<dyn Error>> {
if data.len() != shape.0 * shape.1 {
return Err("Data length does not match shape".into());
}
Ok(Matrix { data, shape })
}
pub fn from_2d_vec(data: Vec<Vec<T>>) -> Result<Matrix<T>, Box<dyn Error>> {
let shape = (data.len(), data[0].len());
for i in 1..shape.0 {
if data[i].len() != shape.1 {
return Err("Data length does not match shape".into());
}
}
let mut matrix = Matrix::new_default(shape);
for i in 0..shape.0 {
for j in 0..shape.1 {
matrix[i][j] = data[i][j];
}
}
Ok(matrix)
}
pub fn as_slice(&self) -> &[T] {
&self.data
}
pub fn as_vec(&self) -> Vec<T> {
self.data.clone()
}
pub fn as_2d_vec(&self) -> Vec<Vec<T>> {
let mut vec = Vec::new();
for i in 0..self.shape.0 {
let mut row = Vec::new();
for j in 0..self.shape.1 {
row.push(self[i][j]);
}
vec.push(row);
}
vec
}
pub fn shape(&self) -> (usize, usize) {
self.shape
}
pub fn get_column(&self, column: usize) -> Result<Vec<T>, Box<dyn Error>> {
if column >= self.shape.1 {
return Err("Column index out of bounds".into());
}
let mut column_vec = Vec::new();
for i in 0..self.shape.0 {
column_vec.push(self.data[i * self.shape.1 + column]);
}
Ok(column_vec)
}
pub fn get_columns(&self, start: usize, end: usize) -> Result<Matrix<T>, Box<dyn Error>> {
if start >= self.shape.1 || end >= self.shape.1 {
return Err("Column index out of bounds".into());
}
let mut data = Vec::new();
for i in 0..self.shape.0 {
for j in start..end {
data.push(self.data[i * self.shape.1 + j]);
}
}
Ok(Matrix::new(data, (self.shape.0, end - start))?)
}
pub fn get_row(&self, row: usize) -> Result<Vec<T>, Box<dyn Error>> {
if row >= self.shape.0 {
return Err("Row index out of bounds".into());
}
Ok(self[row].to_vec())
}
pub fn get_rows(&self, start: usize, end: usize) -> Result<Matrix<T>, Box<dyn Error>> {
if start >= self.shape.0 || end > self.shape.0 {
return Err("Row index out of bounds".into());
}
let mut data = Vec::new();
for i in start..end {
data.extend_from_slice(&self[i]);
}
Ok(Matrix::new(data, (end - start, self.shape.1))?)
}
pub fn add_column(&mut self, index: usize) -> Result<(), Box<dyn Error>> {
if index > self.shape.1 {
return Err("Column index out of bounds".into());
}
if self.shape.0 == 0 {
self.shape.0 = 1;
self.shape.1 = 1;
self.data.push(T::default());
return Ok(());
}
self.shape.1 += 1;
for i in 0..self.shape.0 {
self.data.insert(i * self.shape.1 + index, T::default());
}
Ok(())
}
pub fn add_column_initialized(&mut self, index: usize, value: T) -> Result<(), Box<dyn Error>> {
if index > self.shape.1 {
return Err("Column index out of bounds".into());
}
if self.shape.0 == 0 {
self.shape.0 = 1;
self.shape.1 = 1;
self.data.push(value);
return Ok(());
}
self.shape.1 += 1;
for i in 0..self.shape.0 {
self.data.insert((i * self.shape.1) + index, value);
}
Ok(())
}
pub fn add_column_from_vec(&mut self, index: usize, values: Vec<T>) -> Result<(), Box<dyn Error>> {
if index > self.shape.1 {
return Err("Column index out of bounds".into());
}
if self.shape.0 == 0 {
self.shape.0 = values.len();
self.shape.1 = 1;
self.data = values;
return Ok(());
}
if values.len() != self.shape.0 {
return Err("Values length does not match matrix height".into());
}
self.shape.1 += 1;
for i in 0..self.shape.0 {
self.data.insert((i * self.shape.1) + index, values[i]);
}
Ok(())
}
pub fn add_columns_from_matrix(&mut self, matrix: &Matrix<T>) -> Result<(), Box<dyn Error>> {
if self.shape.0 == 0 {
self.shape.0 = matrix.shape.0;
self.shape.1 = matrix.shape.1;
self.data = matrix.data.clone();
return Ok(());
}
if self.shape.0 != matrix.shape().0 {
return Err("Matrix rows does not match".into());
}
self.shape.1 += matrix.shape().1;
for i in 0..self.shape.0 {
for j in 0..matrix.shape().1 {
self.data.insert((i * self.shape.1) + self.shape.1 - matrix.shape().1 + j, matrix.data[i * matrix.shape().1 + j]);
}
}
Ok(())
}
pub fn remove_column(&mut self, index: usize) -> Result<(), Box<dyn Error>> {
if index >= self.shape.1 {
return Err("Column index out of bounds".into());
}
self.shape.1 -= 1;
for i in 0..self.shape.0 {
self.data.remove((i * self.shape.1) + index);
}
Ok(())
}
pub fn add_row(&mut self, index: usize) -> Result<(), Box<dyn Error>> {
if index > self.shape.0 {
return Err("Row index out of bounds".into());
}
if self.shape.0 == 0 {
self.shape.0 = 1;
self.shape.1 = 1;
self.data.push(T::default());
return Ok(());
}
self.shape.0 += 1;
for _ in 0..self.shape.1 {
self.data.insert(index * self.shape.1, T::default());
}
Ok(())
}
pub fn add_row_initialized(&mut self, index: usize, value: T) -> Result<(), Box<dyn Error>> {
if index > self.shape.0 {
return Err("Row index out of bounds".into());
}
if self.shape.0 == 0 {
self.shape.0 = 1;
self.shape.1 = 1;
self.data.push(value);
return Ok(());
}
self.shape.0 += 1;
for _ in 0..self.shape.1 {
self.data.insert(index * self.shape.1, value);
}
Ok(())
}
pub fn add_row_from_vec(&mut self, index: usize, values: Vec<T>) -> Result<(), Box<dyn Error>> {
if index > self.shape.0 {
return Err("Row index out of bounds".into());
}
if self.shape.0 == 0 {
self.shape.0 = 1;
self.shape.1 = values.len();
self.data = values;
return Ok(());
}
self.shape.0 += 1;
for i in (0..self.shape.1).rev() {
self.data.insert(index * self.shape.1, values[i]);
}
Ok(())
}
pub fn add_rows_from_matrix(&mut self, matrix: &Matrix<T>) -> Result<(), Box<dyn Error>> {
if self.shape.1 != matrix.shape().1 && self.shape != (0, 0) {
return Err("Matrices must have the same number of columns".into());
}
for i in 0..matrix.shape().0 {
self.add_row_from_vec(self.shape.0, matrix.get_row(i).unwrap().to_vec())?;
}
Ok(())
}
pub fn remove_row(&mut self, index: usize) -> Result<(), Box<dyn Error>> {
if index >= self.shape.0 {
return Err("Row index out of bounds".into());
}
self.shape.0 -= 1;
for _ in 0..self.shape.1 {
self.data.remove(index * self.shape.1);
}
Ok(())
}
pub fn as_type<U: From<T> + Copy + Default>(&mut self) -> Matrix<U> {
let mut data: Vec<U> = Vec::new();
for i in 0..self.data.len() {
data.push(U::from(self.data[i]));
}
Matrix::new(data, self.shape).unwrap()
}
}