#![allow(
clippy::erasing_op,
clippy::identity_op,
clippy::suspicious_op_assign_impl,
clippy::suspicious_arithmetic_impl
)]
use std::fmt;
use super::{Matrix, MatrixError, TransformVector};
use crate::fraction::Fraction;
use crate::vector::{vector2d::Vector2D, vector3d::Vector3D, VectorError};
pub struct Matrix3x3 {
pub data: [Fraction; 3 * 3],
}
impl Matrix for Matrix3x3 {
type Data = Fraction;
fn new() -> Self {
Matrix3x3 {
data: [
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
],
}
}
fn from(value: Self::Data) -> Self {
Matrix3x3 {
data: [
value, value, value, value, value, value, value, value, value,
],
}
}
fn from_slice(values: &[Self::Data]) -> Self {
let mut new_matrix = Matrix3x3::new();
new_matrix.data[0] = values[0];
new_matrix.data[1] = values[1];
new_matrix.data[2] = values[2];
new_matrix.data[3] = values[3];
new_matrix.data[4] = values[4];
new_matrix.data[5] = values[5];
new_matrix.data[6] = values[6];
new_matrix.data[7] = values[7];
new_matrix.data[8] = values[8];
new_matrix
}
fn scale(&self, scale: Self::Data) -> Self {
let mut scaled_matrix = Matrix3x3::new();
for i in 0..3 {
for j in 0..3 {
scaled_matrix.data[3 * i + j] = self.data[3 * i + j] * scale;
}
}
scaled_matrix
}
fn determinant(&self) -> Result<Self::Data, MatrixError> {
Ok(self.data[3 * 0 + 0]
* (self.data[3 * 1 + 1] * self.data[3 * 2 + 2]
- self.data[3 * 1 + 2] * self.data[3 * 2 + 1])
- self.data[3 * 0 + 1]
* (self.data[3 * 1 + 0] * self.data[3 * 2 + 2]
- self.data[3 * 1 + 2] * self.data[3 * 2 + 0])
+ self.data[3 * 0 + 2]
* (self.data[3 * 1 + 0] * self.data[3 * 2 + 1]
- self.data[3 * 1 + 1] * self.data[3 * 2 + 0]))
}
fn transpose(&self) -> Self {
let mut transposed_matrix = Matrix3x3::new();
for i in 0..3 {
for j in 0..3 {
transposed_matrix.data[3 * i + j] = self.data[i + 3 * j];
}
}
transposed_matrix
}
fn cofactor(&self) -> Result<Self, MatrixError> {
let mut cofactor_matrix = Matrix3x3::new();
cofactor_matrix.data[3 * 0 + 0] = self.data[3 * 1 + 1] * self.data[3 * 2 + 2]
- self.data[3 * 1 + 2] * self.data[3 * 2 + 1];
cofactor_matrix.data[3 * 0 + 1] = -(self.data[3 * 1 + 0] * self.data[3 * 2 + 2]
- self.data[3 * 1 + 2] * self.data[3 * 2 + 0]);
cofactor_matrix.data[3 * 0 + 2] = self.data[3 * 1 + 0] * self.data[3 * 2 + 1]
- self.data[3 * 1 + 1] * self.data[3 * 2 + 0];
cofactor_matrix.data[3 * 1 + 0] = -(self.data[3 * 0 + 1] * self.data[3 * 2 + 2]
- self.data[3 * 0 + 2] * self.data[3 * 2 + 1]);
cofactor_matrix.data[3 * 1 + 1] = self.data[3 * 0 + 0] * self.data[3 * 2 + 2]
- self.data[3 * 0 + 2] * self.data[3 * 2 + 0];
cofactor_matrix.data[3 * 1 + 2] = -(self.data[3 * 0 + 0] * self.data[3 * 2 + 1]
- self.data[3 * 0 + 1] * self.data[3 * 2 + 0]);
cofactor_matrix.data[3 * 2 + 0] = self.data[3 * 0 + 1] * self.data[3 * 1 + 2]
- self.data[3 * 0 + 2] * self.data[3 * 1 + 1];
cofactor_matrix.data[3 * 2 + 1] = -(self.data[3 * 0 + 0] * self.data[3 * 1 + 2]
- self.data[3 * 0 + 2] * self.data[3 * 1 + 0]);
cofactor_matrix.data[3 * 2 + 2] = self.data[3 * 0 + 0] * self.data[3 * 1 + 1]
- self.data[3 * 0 + 1] * self.data[3 * 1 + 0];
Ok(cofactor_matrix)
}
fn adjugate(&self) -> Result<Self, MatrixError> {
Ok(self.cofactor().unwrap().transpose())
}
fn inverse(&self) -> Result<Self, MatrixError>
where
Self: Sized,
{
let determinant = self.determinant().unwrap();
if determinant == Self::Data::from(0_i16) {
return Err(MatrixError::ZeroDeterminantError);
}
let inverse_matrix = self.adjugate().unwrap();
Ok(inverse_matrix.scale(Self::Data::from(1_i16) / determinant))
}
}
impl TransformVector<Vector2D> for Matrix3x3 {
fn transform_vector(&self, other: Vector2D) -> Result<Vector2D, VectorError> {
Ok(Vector2D {
data: [
other[0] * self.data[3 * 0 + 0] + other[1] * self.data[3 * 0 + 1] + self.data[3 * 0 + 2],
other[0] * self.data[3 * 1 + 0] + other[1] * self.data[3 * 1 + 1] + self.data[3 * 1 + 2],
],
})
}
}
impl TransformVector<Vector3D> for Matrix3x3 {
fn transform_vector(&self, other: Vector3D) -> Result<Vector3D, VectorError> {
Ok(Vector3D {
data: [
other[0] * self.data[3 * 0 + 0] + other[1] * self.data[3 * 0 + 1] + other[2] * self.data[3 * 0 + 2],
other[0] * self.data[3 * 1 + 0] + other[1] * self.data[3 * 1 + 1] + other[2] * self.data[3 * 1 + 2],
other[0] * self.data[3 * 2 + 0] + other[1] * self.data[3 * 2 + 1] + other[2] * self.data[3 * 2 + 2],
],
})
}
}
impl std::cmp::PartialEq for Matrix3x3 {
fn eq(&self, other: &Matrix3x3) -> bool {
for i in 0..3 {
for j in 0..3 {
if self.data[3 * i + j] != other[3 * i + j] {
return false;
}
}
}
true
}
}
impl std::cmp::Eq for Matrix3x3 {}
impl std::ops::Add for Matrix3x3 {
type Output = Matrix3x3;
fn add(self, other: Matrix3x3) -> Matrix3x3 {
let mut sum_matrix = Matrix3x3::new();
for i in 0..3 {
for j in 0..3 {
sum_matrix[3 * i + j] = self.data[3 * i + j] + other[3 * i + j];
}
}
sum_matrix
}
}
impl std::ops::AddAssign for Matrix3x3 {
fn add_assign(&mut self, other: Matrix3x3) {
for i in 0..3 {
for j in 0..3 {
self.data[3 * i + j] += other[3 * i + j];
}
}
}
}
impl std::ops::Sub for Matrix3x3 {
type Output = Matrix3x3;
fn sub(self, other: Matrix3x3) -> Matrix3x3 {
let mut difference_matrix = Matrix3x3::new();
for i in 0..3 {
for j in 0..3 {
difference_matrix[3 * i + j] = self.data[3 * i + j] - other[3 * i + j];
}
}
difference_matrix
}
}
impl std::ops::SubAssign for Matrix3x3 {
fn sub_assign(&mut self, other: Matrix3x3) {
for i in 0..3 {
for j in 0..3 {
self.data[3 * i + j] -= other[3 * i + j];
}
}
}
}
impl std::ops::Mul for Matrix3x3 {
type Output = Matrix3x3;
fn mul(self, other: Matrix3x3) -> Matrix3x3 {
let mut product_matrix = Matrix3x3::new();
for i in 0..3 {
for j in 0..3 {
for m in 0..3 {
product_matrix[3 * i + j] += self.data[3 * i + m] * other[3 * m + j];
}
}
}
product_matrix
}
}
impl std::ops::MulAssign for Matrix3x3 {
fn mul_assign(&mut self, other: Matrix3x3) {
let mut product_matrix = Matrix3x3::new();
for i in 0..3 {
for j in 0..3 {
for m in 0..3 {
product_matrix[3 * i + j] += self.data[3 * i + m] * other[3 * m + j];
}
}
}
self.data[0..9].clone_from_slice(&product_matrix.data[0..9]);
}
}
impl std::ops::Neg for Matrix3x3 {
type Output = Matrix3x3;
fn neg(self) -> Matrix3x3 {
let mut negated_matrix = Matrix3x3::new();
for i in 0..3 {
for j in 0..3 {
negated_matrix[i + j * 3] = -self.data[i + j * 3];
}
}
negated_matrix
}
}
impl std::ops::Index<usize> for Matrix3x3 {
type Output = Fraction;
fn index(&self, index: usize) -> &Fraction {
&self.data[index]
}
}
impl std::ops::IndexMut<usize> for Matrix3x3 {
fn index_mut(&mut self, index: usize) -> &mut Fraction {
&mut self.data[index]
}
}
impl Copy for Matrix3x3 {}
impl Clone for Matrix3x3 {
fn clone(&self) -> Matrix3x3 {
*self
}
}
impl fmt::Debug for Matrix3x3 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"\n[{}, {}, {}]\n[{}, {}, {}]\n[{}, {}, {}]",
self.data[3 * 0 + 0],
self.data[3 * 0 + 1],
self.data[3 * 0 + 2],
self.data[3 * 1 + 0],
self.data[3 * 1 + 1],
self.data[3 * 1 + 2],
self.data[3 * 2 + 0],
self.data[3 * 2 + 1],
self.data[3 * 2 + 2]
)
}
}
impl fmt::Display for Matrix3x3 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"\n({}, {}, {})\n({}, {}, {})\n({}, {}, {})",
self.data[3 * 0 + 0],
self.data[3 * 0 + 1],
self.data[3 * 0 + 2],
self.data[3 * 1 + 0],
self.data[3 * 1 + 1],
self.data[3 * 1 + 2],
self.data[3 * 2 + 0],
self.data[3 * 2 + 1],
self.data[3 * 2 + 2]
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_test() {
let values: [Fraction; 9] = [
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
];
let matrix1: Matrix3x3 = Matrix3x3 {
data: [
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(0, 1),
],
};
let matrix2 = Matrix3x3::new();
let matrix3 = Matrix::from(Fraction::new_denom(0, 1));
let matrix4 = Matrix3x3::from_slice(&values);
assert_eq!(matrix1, matrix2);
assert_eq!(matrix2, matrix3);
assert_eq!(matrix3, matrix4);
}
#[test]
fn addition_test() {
let matrix1: Matrix3x3 = Matrix::from(Fraction::new_denom(5, 1));
let matrix2 = Matrix::from(Fraction::new_denom(6, 1));
let result_matrix = Matrix::from(Fraction::new_denom(11, 1));
assert_eq!(matrix1 + matrix2, result_matrix);
assert_eq!(matrix2 + matrix1, result_matrix);
}
#[test]
fn subtraction_test() {
let matrix1: Matrix3x3 = Matrix::from(Fraction::new_denom(5, 1));
let matrix2 = Matrix::from(Fraction::new_denom(6, 1));
let result_matrix1 = Matrix::from(Fraction::new_denom(-1, 1));
let result_matrix2 = Matrix::from(Fraction::new_denom(1, 1));
assert_eq!(matrix1 - matrix2, result_matrix1);
assert_eq!(matrix2 - matrix1, result_matrix2);
}
#[test]
fn multiplication_test() {
let values1: [Fraction; 9] = [
Fraction::new_denom(4, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(6, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(1, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(1, 1),
];
let values2: [Fraction; 9] = [
Fraction::new_denom(5, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(6, 1),
Fraction::new_denom(3, 1),
Fraction::new_denom(3, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(7, 1),
];
let result_values1: [Fraction; 9] = [
Fraction::new_denom(62, 1),
Fraction::new_denom(38, 1),
Fraction::new_denom(64, 1),
Fraction::new_denom(51, 1),
Fraction::new_denom(29, 1),
Fraction::new_denom(51, 1),
Fraction::new_denom(52, 1),
Fraction::new_denom(24, 1),
Fraction::new_denom(41, 1),
];
let result_values2: [Fraction; 9] = [
Fraction::new_denom(58, 1),
Fraction::new_denom(20, 1),
Fraction::new_denom(42, 1),
Fraction::new_denom(60, 1),
Fraction::new_denom(21, 1),
Fraction::new_denom(51, 1),
Fraction::new_denom(89, 1),
Fraction::new_denom(28, 1),
Fraction::new_denom(53, 1),
];
let matrix1: Matrix3x3 = Matrix3x3::from_slice(&values1);
let matrix2 = Matrix3x3::from_slice(&values2);
let result_matrix1 = Matrix3x3::from_slice(&result_values1);
let result_matrix2 = Matrix3x3::from_slice(&result_values2);
assert_eq!(matrix1 * matrix2, result_matrix1);
assert_eq!(matrix2 * matrix1, result_matrix2);
}
#[test]
fn scale_test() {
let scale = Fraction::new_denom(5, 1);
let values: [Fraction; 9] = [
Fraction::new_denom(4, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(6, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(1, 1),
Fraction::new_denom(3, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(2, 1),
];
let result_values: [Fraction; 9] = [
Fraction::new_denom(4 * 5, 1),
Fraction::new_denom(2 * 5, 1),
Fraction::new_denom(6 * 5, 1),
Fraction::new_denom(5 * 5, 1),
Fraction::new_denom(1 * 5, 1),
Fraction::new_denom(3 * 5, 1),
Fraction::new_denom(7 * 5, 1),
Fraction::new_denom(4 * 5, 1),
Fraction::new_denom(2 * 5, 1),
];
let matrix = Matrix3x3::from_slice(&values);
let result_matrix = Matrix3x3::from_slice(&result_values);
assert_eq!(matrix.scale(scale), result_matrix);
}
#[test]
fn transpose_test() {
let values1: [Fraction; 9] = [
Fraction::new_denom(2, 1),
Fraction::new_denom(6, 1),
Fraction::new_denom(3, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(1, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(8, 1),
Fraction::new_denom(9, 1),
Fraction::new_denom(4, 1),
];
let result_values: [Fraction; 9] = [
Fraction::new_denom(2, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(8, 1),
Fraction::new_denom(6, 1),
Fraction::new_denom(1, 1),
Fraction::new_denom(9, 1),
Fraction::new_denom(3, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(4, 1),
];
let matrix = Matrix3x3::from_slice(&values1);
let result_matrix = Matrix3x3::from_slice(&result_values);
assert_eq!(matrix.transpose(), result_matrix);
}
#[test]
fn cofactor_test() {
let values: [Fraction; 9] = [
Fraction::new_denom(5, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(4, 1),
];
let result_values: [Fraction; 9] = [
Fraction::new_denom(-2, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(6, 1),
Fraction::new_denom(-29, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(-4, 1),
Fraction::new_denom(24, 1),
Fraction::new_denom(-4, 1),
];
let matrix = Matrix3x3::from_slice(&values);
let result_matrix = Matrix3x3::from_slice(&result_values);
assert_eq!(matrix.cofactor().unwrap(), result_matrix);
}
#[test]
fn adjugate_test() {
let values: [Fraction; 9] = [
Fraction::new_denom(5, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(4, 1),
];
let result_values: [Fraction; 9] = [
Fraction::new_denom(-2, 1),
Fraction::new_denom(6, 1),
Fraction::new_denom(-4, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(-29, 1),
Fraction::new_denom(24, 1),
Fraction::new_denom(0, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(-4, 1),
];
let matrix = Matrix3x3::from_slice(&values);
let result_matrix = Matrix3x3::from_slice(&result_values);
assert_eq!(matrix.adjugate().unwrap(), result_matrix);
}
#[test]
fn determinant_test() {
let values: [Fraction; 9] = [
Fraction::new_denom(4, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(5, 1),
Fraction::new_denom(1, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(5, 1),
];
let matrix = Matrix3x3::from_slice(&values);
let determinant = Fraction::new_denom(9, 1);
assert_eq!(matrix.determinant().unwrap(), determinant);
}
#[test]
fn inverse_test() {
let values: [Fraction; 9] = [
Fraction::new_denom(5, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(1, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(7, 1),
Fraction::new_denom(2, 1),
Fraction::new_denom(4, 1),
Fraction::new_denom(3, 1),
Fraction::new_denom(6, 1),
];
let result_values: [Fraction; 9] = [
Fraction::new_denom(3, 11),
Fraction::new_denom(-3, 44),
Fraction::new_denom(-1, 44),
Fraction::new_denom(-4, 33),
Fraction::new_denom(13, 66),
Fraction::new_denom(-1, 22),
Fraction::new_denom(-4, 33),
Fraction::new_denom(-7, 132),
Fraction::new_denom(9, 44),
];
let matrix = Matrix3x3::from_slice(&values);
let result_matrix = Matrix3x3::from_slice(&result_values);
assert_eq!(matrix.inverse().unwrap(), result_matrix);
}
}