mod m2x2;
mod m3x3;
mod m4x4;
use crate::types::sealed::Constants;
use crate::vector::Vector;
use core::fmt::Debug;
use core::mem::MaybeUninit;
use core::ops::{AddAssign, Mul};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Matrix<T, const R: usize, const C: usize> {
columns: [Vector<T, R>; C],
}
impl<T, const R: usize, const C: usize> Matrix<T, R, C> {
pub const UNINIT: Matrix<MaybeUninit<T>, R, C> = Matrix {
columns: [Vector::UNINIT; C],
};
#[inline]
pub const fn new_columns(columns: [Vector<T, R>; C]) -> Self {
Self { columns }
}
#[inline]
pub fn new_rows(rows: [Vector<T, C>; R]) -> Self
where
T: Clone,
{
Matrix::new_columns(rows).transpose()
}
#[inline]
pub fn new_from_array<const L: usize>(arr: [T; L]) -> Self
where
T: Clone,
{
assert_eq!(L, R * C);
let mut columns = [const { MaybeUninit::uninit() }; C];
for c in 0..C {
let mut column = Vector::UNINIT;
for r in 0..R {
column[r] = MaybeUninit::new(arr[r * C + c].clone());
}
let column = unsafe { column.assume_init() };
columns[c] = MaybeUninit::new(column);
}
let arr: [Vector<T, R>; C] = columns.map(|maybe| unsafe { maybe.assume_init() });
Self { columns: arr }
}
#[inline]
pub fn transpose(self) -> Matrix<T, C, R>
where
T: Clone,
{
let mut columns: [MaybeUninit<Vector<T, C>>; R] = [const { MaybeUninit::uninit() }; R];
for (r, item) in columns.iter_mut().enumerate().take(R) {
let mut column = Vector::UNINIT;
for c in 0..C {
column[c] = MaybeUninit::new(self.columns[c][r].clone());
}
let column = unsafe { column.assume_init() };
*item = MaybeUninit::new(column);
}
let arr: [Vector<T, C>; R] =
unsafe { core::ptr::read(columns.as_ptr() as *const [Vector<T, C>; R]) };
Matrix { columns: arr }
}
}
impl<T, const R: usize, const C: usize> Matrix<MaybeUninit<T>, R, C> {
pub unsafe fn assume_init(self) -> Matrix<T, R, C> {
let columns = unsafe { core::ptr::read(self.columns.as_ptr() as *const [Vector<T, R>; C]) };
Matrix { columns }
}
}
impl<T: Constants + Clone + core::ops::Add<Output = T>, const R: usize, const C: usize>
Matrix<T, R, C>
{
#[inline]
pub fn elementwise_add(self, other: Self) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(
self.columns[c]
.clone()
.elementwise_add(other.columns[c].clone()),
);
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T: Constants + Clone + core::ops::Add<Output = T>, const R: usize, const C: usize>
core::ops::Add for Matrix<T, R, C>
{
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
self.elementwise_add(other)
}
}
impl<T: Constants + Clone + core::ops::Sub<Output = T>, const R: usize, const C: usize>
Matrix<T, R, C>
{
#[inline]
pub fn elementwise_sub(self, other: Self) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(
self.columns[c]
.clone()
.elementwise_sub(other.columns[c].clone()),
);
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T: Constants + Clone + core::ops::Sub<Output = T>, const R: usize, const C: usize>
core::ops::Sub for Matrix<T, R, C>
{
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
self.elementwise_sub(other)
}
}
impl<T: Constants + Clone + core::ops::Mul<Output = T>, const R: usize, const C: usize>
Matrix<T, R, C>
{
#[inline]
pub fn elementwise_mul(self, other: Self) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(
self.columns[c]
.clone()
.elementwise_mul(other.columns[c].clone()),
);
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T: Constants + Clone + core::ops::Div<Output = T>, const R: usize, const C: usize>
Matrix<T, R, C>
{
#[inline]
pub fn elementwise_div(self, other: Self) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(
self.columns[c]
.clone()
.elementwise_div(other.columns[c].clone()),
);
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T: Constants, const R: usize, const C: usize> Matrix<T, R, C> {
pub const ZERO: Self = Self {
columns: [Vector::ZERO; C],
};
pub const ONE: Self = Self {
columns: [Vector::ONE; C],
};
}
impl<T: Constants> Matrix<T, 1, 1> {
pub const IDENTITY: Self = Self {
columns: [Vector::ONE],
};
}
impl<T: Constants> Matrix<T, 1, 2> {
pub const IDENTITY: Self = Self {
columns: [Vector::ONE, Vector::ZERO],
};
}
impl<T: Constants> Matrix<T, 1, 3> {
pub const IDENTITY: Self = Self {
columns: [Vector::ONE, Vector::ZERO, Vector::ZERO],
};
}
impl<T: Constants> Matrix<T, 1, 4> {
pub const IDENTITY: Self = Self {
columns: [Vector::ONE, Vector::ZERO, Vector::ZERO, Vector::ZERO],
};
}
impl<T: Constants> Matrix<T, 2, 1> {
pub const IDENTITY: Self = Self {
columns: [Vector::new([T::ONE, T::ZERO])],
};
}
impl<T: Constants> Matrix<T, 2, 2> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO]),
Vector::new([T::ZERO, T::ONE]),
],
};
}
impl<T: Constants> Matrix<T, 2, 3> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO]),
Vector::new([T::ZERO, T::ONE]),
Vector::new([T::ZERO, T::ZERO]),
],
};
}
impl<T: Constants> Matrix<T, 2, 4> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO]),
Vector::new([T::ZERO, T::ONE]),
Vector::new([T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ZERO]),
],
};
}
impl<T: Constants> Matrix<T, 3, 1> {
pub const IDENTITY: Self = Self {
columns: [Vector::new([T::ONE, T::ZERO, T::ZERO])],
};
}
impl<T: Constants> Matrix<T, 3, 2> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ONE, T::ZERO]),
],
};
}
impl<T: Constants> Matrix<T, 3, 3> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ONE, T::ZERO]),
Vector::new([T::ZERO, T::ZERO, T::ONE]),
],
};
}
impl<T: Constants> Matrix<T, 3, 4> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ONE, T::ZERO]),
Vector::new([T::ZERO, T::ZERO, T::ONE]),
Vector::new([T::ZERO, T::ZERO, T::ZERO]),
],
};
}
impl<T: Constants> Matrix<T, 4, 1> {
pub const IDENTITY: Self = Self {
columns: [Vector::new([T::ONE, T::ZERO, T::ZERO, T::ZERO])],
};
}
impl<T: Constants> Matrix<T, 4, 2> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO, T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ONE, T::ZERO, T::ZERO]),
],
};
}
impl<T: Constants> Matrix<T, 4, 3> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO, T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ONE, T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ZERO, T::ONE, T::ZERO]),
],
};
}
impl<T: Constants> Matrix<T, 4, 4> {
pub const IDENTITY: Self = Self {
columns: [
Vector::new([T::ONE, T::ZERO, T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ONE, T::ZERO, T::ZERO]),
Vector::new([T::ZERO, T::ZERO, T::ONE, T::ZERO]),
Vector::new([T::ZERO, T::ZERO, T::ZERO, T::ONE]),
],
};
}
impl<T: Clone + core::ops::AddAssign, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn add_elementwise_assign(&mut self, other: Self) {
for c in 0..C {
self.columns[c] += other.columns[c].clone();
}
}
}
impl<T: Clone + core::ops::AddAssign, const R: usize, const C: usize> core::ops::AddAssign
for Matrix<T, R, C>
{
#[inline]
fn add_assign(&mut self, other: Self) {
self.add_elementwise_assign(other);
}
}
impl<T: Clone + core::ops::SubAssign, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn sub_elementwise_assign(&mut self, other: Self) {
for c in 0..C {
self.columns[c] -= other.columns[c].clone();
}
}
}
impl<T: Clone + core::ops::SubAssign, const R: usize, const C: usize> core::ops::SubAssign
for Matrix<T, R, C>
{
#[inline]
fn sub_assign(&mut self, other: Self) {
self.sub_elementwise_assign(other);
}
}
impl<T: Clone + core::ops::MulAssign, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn mul_elementwise_assign(&mut self, other: Self) {
for c in 0..C {
self.columns[c] *= other.columns[c].clone();
}
}
}
impl<T: Clone + core::ops::MulAssign, const R: usize, const C: usize> core::ops::MulAssign
for Matrix<T, R, C>
{
#[inline]
fn mul_assign(&mut self, other: Self) {
self.mul_elementwise_assign(other);
}
}
impl<T: Clone + core::ops::DivAssign, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn div_elementwise_assign(&mut self, other: Self) {
for c in 0..C {
self.columns[c] /= other.columns[c].clone();
}
}
}
impl<T: Clone + core::ops::DivAssign, const R: usize, const C: usize> core::ops::DivAssign
for Matrix<T, R, C>
{
#[inline]
fn div_assign(&mut self, other: Self) {
self.div_elementwise_assign(other);
}
}
impl<T: Clone + core::ops::Add<Output = T>, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn add_scalar(self, other: T) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(self.columns[c].clone().add_scalar(other.clone()));
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T: Clone + core::ops::Sub<Output = T>, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn sub_scalar(self, other: T) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(self.columns[c].clone().sub_scalar(other.clone()));
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T: Clone + core::ops::Mul<Output = T>, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn mul_scalar(self, other: T) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(self.columns[c].clone().mul_scalar(other.clone()));
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T: Clone + core::ops::Div<Output = T>, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn div_scalar(self, other: T) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(self.columns[c].clone().div_scalar(other.clone()));
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T, const R: usize, const C: usize> core::ops::Add<T> for Matrix<T, R, C>
where
T: core::ops::Add<Output = T> + Clone,
{
type Output = Self;
#[inline]
fn add(self, other: T) -> Self {
self.add_scalar(other)
}
}
impl<T, const R: usize, const C: usize> core::ops::Sub<T> for Matrix<T, R, C>
where
T: core::ops::Sub<Output = T> + Clone,
{
type Output = Self;
#[inline]
fn sub(self, other: T) -> Self {
self.sub_scalar(other)
}
}
impl<T, const R: usize, const C: usize> core::ops::Mul<T> for Matrix<T, R, C>
where
T: core::ops::Mul<Output = T> + Clone,
{
type Output = Self;
#[inline]
fn mul(self, other: T) -> Self {
self.mul_scalar(other)
}
}
impl<T, const R: usize, const C: usize> core::ops::Div<T> for Matrix<T, R, C>
where
T: core::ops::Div<Output = T> + Clone,
{
type Output = Self;
#[inline]
fn div(self, other: T) -> Self {
self.div_scalar(other)
}
}
impl<T, const R: usize, const C: usize> Matrix<T, R, C>
where
T: core::ops::AddAssign + Clone,
{
#[inline]
fn add_scalar_assign(&mut self, other: T) {
for c in 0..C {
self.columns[c] += other.clone();
}
}
}
impl<T, const R: usize, const C: usize> core::ops::AddAssign<T> for Matrix<T, R, C>
where
T: core::ops::AddAssign + Clone,
{
#[inline]
fn add_assign(&mut self, other: T) {
self.add_scalar_assign(other);
}
}
impl<T, const R: usize, const C: usize> Matrix<T, R, C>
where
T: core::ops::SubAssign + Clone,
{
#[inline]
pub fn sub_scalar_assign(&mut self, other: T) {
for c in 0..C {
self.columns[c] -= other.clone();
}
}
}
impl<T, const R: usize, const C: usize> core::ops::SubAssign<T> for Matrix<T, R, C>
where
T: core::ops::SubAssign + Clone,
{
fn sub_assign(&mut self, other: T) {
self.sub_scalar_assign(other);
}
}
impl<T: Clone, const R: usize, const C: usize> Matrix<T, R, C> {
pub fn map<F: FnMut(T) -> T>(self, mut f: F) -> Self {
let mut columns = [const { MaybeUninit::uninit() }; C];
for (c, column_slot) in columns.iter_mut().enumerate().take(C) {
*column_slot = MaybeUninit::new(self.columns[c].clone().map(&mut f));
}
let c = unsafe { columns.map(|c| c.assume_init()) };
Self { columns: c }
}
}
impl<T, const R: usize, const C: usize> Matrix<T, R, C> {
pub fn map_in_place<F: FnMut(&mut T)>(&mut self, mut f: F) {
for c in 0..C {
self.columns[c].map_in_place(|v| f(v));
}
}
}
impl<T, const R: usize, const C: usize> Matrix<T, R, C>
where
T: Clone + crate::types::sealed::Float,
{
pub fn eq_approx(self, other: Self, tolerance: T) -> bool {
for c in 0..C {
if !self.columns[c]
.clone()
.eq_approx(other.columns[c].clone(), tolerance.clone())
{
return false;
}
}
true
}
}
impl<T, const R: usize, const C: usize> Matrix<T, R, C> {
#[inline]
pub fn columns(&self) -> &[Vector<T, R>; C] {
&self.columns
}
#[inline]
pub fn columns_mut(&mut self) -> &mut [Vector<T, R>; C] {
&mut self.columns
}
#[inline]
pub fn element_at(&self, row: usize, col: usize) -> &T {
&self.columns[col][row]
}
#[inline]
pub fn element_at_mut(&mut self, row: usize, col: usize) -> &mut T {
&mut self.columns[col][row]
}
}
impl<T, const R: usize, const C: usize> Matrix<T, R, C>
where
T: Clone,
{
#[inline]
pub fn rows(self) -> [Vector<T, C>; R] {
self.transpose().columns
}
}
impl<T, const R: usize, const C: usize> Debug for Matrix<T, R, C>
where
T: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for row in 0..R {
for col in 0..C {
write!(f, "{:>8.3?}", self.columns[col][row])?;
}
writeln!(f)?;
}
Ok(())
}
}
impl<T, const M: usize, const N: usize> Matrix<T, M, N>
where
T: Clone + core::ops::Mul<Output = T> + core::ops::Add<Output = T>,
{
#[inline]
pub fn mul_matrix<const P: usize>(self, other: Matrix<T, N, P>) -> Matrix<T, M, P> {
let mut out = Matrix::UNINIT;
let mut c = 0;
while c < P {
let mut r = 0;
while r < M {
let mut acc = {
let a = self.columns[0][r].clone();
let b = other.columns[c][0].clone();
a * b
};
let mut k = 1;
while k < N {
let a = self.columns[k][r].clone();
let b = other.columns[c][k].clone();
acc = acc + a * b;
k += 1;
}
out.columns[c][r] = MaybeUninit::new(acc);
r += 1;
}
c += 1;
}
unsafe { out.assume_init() }
}
#[inline]
pub fn mul_matrix_copy<const P: usize>(self, other: Matrix<T, N, P>) -> Matrix<T, M, P>
where
T: Copy + AddAssign + Mul<Output = T> + Default,
{
let mut out = Matrix::UNINIT;
let mut c = 0;
while c < P {
let mut r = 0;
while r < M {
let mut acc = {
let a = self.columns[0][r];
let b = other.columns[c][0];
a * b
};
let mut k = 1;
while k < N {
let a = self.columns[k][r];
let b = other.columns[c][k];
acc += a * b;
k += 1;
}
out.columns[c][r] = MaybeUninit::new(acc);
r += 1;
}
c += 1;
}
unsafe { out.assume_init() }
}
}
impl<T, const M: usize, const N: usize, const P: usize> core::ops::Mul<Matrix<T, N, P>>
for Matrix<T, M, N>
where
T: Clone + core::ops::Mul<Output = T> + core::ops::Add<Output = T>,
{
type Output = Matrix<T, M, P>;
#[inline]
fn mul(self, other: Matrix<T, N, P>) -> Self::Output {
self.mul_matrix(other)
}
}
impl<T, const R: usize, const C: usize> core::ops::Mul<Vector<T, C>> for Matrix<T, R, C>
where
T: Clone + core::ops::Mul<Output = T> + core::ops::Add<Output = T>,
{
type Output = Matrix<T, R, 1>;
#[inline]
fn mul(self, other: Vector<T, C>) -> Self::Output {
self.mul_matrix(other.to_col())
}
}
impl<T: Default, const R: usize, const C: usize> Default for Matrix<T, R, C>
where
T: Copy,
{
fn default() -> Self {
Self::new_columns([Default::default(); C])
}
}
impl<T, const R: usize, const C: usize> From<[Vector<T, R>; C]> for Matrix<T, R, C> {
fn from(arr: [Vector<T, R>; C]) -> Self {
Self::new_columns(arr)
}
}
impl<T, const R: usize, const C: usize> From<Matrix<T, R, C>> for [Vector<T, R>; C] {
fn from(m: Matrix<T, R, C>) -> Self {
m.columns
}
}
impl<T, const R: usize, const C: usize> AsRef<[Vector<T, R>; C]> for Matrix<T, R, C> {
fn as_ref(&self) -> &[Vector<T, R>; C] {
&self.columns
}
}
impl<T, const R: usize, const C: usize> AsMut<[Vector<T, R>; C]> for Matrix<T, R, C> {
fn as_mut(&mut self) -> &mut [Vector<T, R>; C] {
&mut self.columns
}
}
#[cfg(test)]
mod tests {
#[test]
fn test() {
use crate::matrix::Matrix;
use crate::vector::Vector;
let m = Matrix::<f32, 2, 3>::new_rows([
Vector::new([1.0, 2.0, 3.0]),
Vector::new([4.0, 5.0, 6.0]),
]);
assert_eq!(m.columns[0], Vector::new([1.0, 4.0]));
assert_eq!(m.columns[1], Vector::new([2.0, 5.0]));
assert_eq!(m.columns[2], Vector::new([3.0, 6.0]));
}
#[test]
fn test_from_array() {
use crate::matrix::Matrix;
use crate::vector::Vector;
let m = Matrix::<f32, 2, 3>::new_from_array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
assert_eq!(m.columns[0], Vector::new([1.0, 4.0]));
assert_eq!(m.columns[1], Vector::new([2.0, 5.0]));
assert_eq!(m.columns[2], Vector::new([3.0, 6.0]));
}
#[test]
fn test_debug() {
use crate::matrix::Matrix;
use crate::vector::Vector;
let m = Matrix::<f32, 2, 3>::new_rows([
Vector::new([1.0, 2.0, 3.0]),
Vector::new([4.0, 5.0, 6.0]),
]);
use alloc::format;
assert_eq!(
format!("{:?}", m),
" 1.000 2.000 3.000\n 4.000 5.000 6.000\n"
);
}
#[test]
fn test_elementwise() {
use crate::matrix::Matrix;
use crate::vector::Vector;
let m1 = Matrix::<f32, 2, 3>::new_rows([
Vector::new([1.0, 2.0, 3.0]),
Vector::new([4.0, 5.0, 6.0]),
]);
let m2 = Matrix::<f32, 2, 3>::new_rows([
Vector::new([7.0, 8.0, 9.0]),
Vector::new([10.0, 11.0, 12.0]),
]);
let m3 = Matrix::<f32, 2, 3>::new_rows([
Vector::new([8.0, 10.0, 12.0]),
Vector::new([14.0, 16.0, 18.0]),
]);
assert_eq!(m1 + m2, m3);
assert_eq!(m3 - m2, m1);
assert_eq!(
m1.elementwise_mul(m2),
Matrix::new_rows([
Vector::new([7.0, 16.0, 27.0]),
Vector::new([40.0, 55.0, 72.0]),
])
);
assert_eq!(
m3.elementwise_div(m2),
Matrix::new_rows([
Vector::new([8.0 / 7.0, 10.0 / 8.0, 12.0 / 9.0]),
Vector::new([14.0 / 10.0, 16.0 / 11.0, 18.0 / 12.0]),
])
);
}
#[test]
fn map() {
use crate::matrix::Matrix;
use crate::vector::Vector;
let m1 = Matrix::<f32, 2, 3>::new_rows([
Vector::new([1.0, 2.0, 3.0]),
Vector::new([4.0, 5.0, 6.0]),
]);
let m2 = Matrix::<f32, 2, 3>::new_rows([
Vector::new([2.0, 4.0, 6.0]),
Vector::new([8.0, 10.0, 12.0]),
]);
assert_eq!(m1.map(|v| v * 2.0), m2);
}
#[test]
fn rows_cols() {
use crate::matrix::Matrix;
use crate::vector::Vector;
let m1 = Matrix::<f32, 2, 3>::new_rows([
Vector::new([1.0, 2.0, 3.0]),
Vector::new([4.0, 5.0, 6.0]),
]);
assert_eq!(
m1.columns(),
&[
Vector::new([1.0, 4.0]),
Vector::new([2.0, 5.0]),
Vector::new([3.0, 6.0])
]
);
assert_eq!(
m1.rows(),
[Vector::new([1.0, 2.0, 3.0]), Vector::new([4.0, 5.0, 6.0])]
);
}
#[test]
fn test_mul() {
use crate::matrix::Matrix;
use crate::vector::Vector;
let m1 = Matrix::<f32, 2, 3>::new_rows([
Vector::new([1.0, 2.0, 3.0]),
Vector::new([4.0, 5.0, 6.0]),
]);
let m2 = Matrix::<f32, 3, 2>::new_rows([
Vector::new([7.0, 8.0]),
Vector::new([9.0, 10.0]),
Vector::new([11.0, 12.0]),
]);
let m3 =
Matrix::<f32, 2, 2>::new_rows([Vector::new([58.0, 64.0]), Vector::new([139.0, 154.0])]);
assert_eq!(m1.clone() * m2.clone(), m3);
assert_eq!(m1.clone().mul_matrix(m2), m3);
}
}