1#![allow(
2 clippy::erasing_op,
3 clippy::identity_op,
4 clippy::suspicious_op_assign_impl,
5 clippy::suspicious_arithmetic_impl
6)]
7
8use std::fmt;
9
10use super::{Matrix, MatrixError, TransformVector};
11use crate::fraction::Fraction;
12use crate::vector::{ VectorError, vector2d::Vector2D };
13
14pub struct Matrix2x2 {
15 pub data: [Fraction; 2 * 2],
17}
18
19impl Matrix for Matrix2x2 {
20 type Data = Fraction;
21
22 fn new() -> Self {
25 Matrix2x2 {
26 data: [
27 Fraction::new_denom(0, 1),
28 Fraction::new_denom(0, 1),
29 Fraction::new_denom(0, 1),
30 Fraction::new_denom(0, 1),
31 ],
32 }
33 }
34
35 fn from(value: Self::Data) -> Self {
38 Matrix2x2 {
39 data: [value, value, value, value],
40 }
41 }
42
43 fn from_slice(values: &[Self::Data]) -> Self {
46 let mut new_matrix = Matrix2x2::new();
47
48 new_matrix.data[0] = values[0];
49 new_matrix.data[1] = values[1];
50 new_matrix.data[2] = values[2];
51 new_matrix.data[3] = values[3];
52
53 new_matrix
54 }
55
56 fn scale(&self, scale: Self::Data) -> Self {
59 let mut scaled_matrix = Matrix2x2::new();
60
61 for i in 0..2 {
62 for j in 0..2 {
63 scaled_matrix.data[2 * i + j] = self.data[2 * i + j] * scale;
64 }
65 }
66
67 scaled_matrix
68 }
69
70 fn determinant(&self) -> Result<Self::Data, MatrixError> {
73 Ok(self.data[2 * 0 + 0] * self.data[2 * 1 + 1]
74 - self.data[2 * 0 + 1] * self.data[2 * 1 + 0])
75 }
76
77 fn transpose(&self) -> Self {
80 let mut transposed_matrix = Matrix2x2::new();
81
82 for i in 0..2 {
83 for j in 0..2 {
84 transposed_matrix.data[2 * i + j] = self.data[i + 2 * j];
85 }
86 }
87
88 transposed_matrix
89 }
90
91 fn cofactor(&self) -> Result<Self, MatrixError> {
94 let mut cofactor_matrix = Matrix2x2::new();
95
96 cofactor_matrix.data[2 * 0 + 0] = self.data[2 * 1 + 1];
97 cofactor_matrix.data[2 * 0 + 1] = -self.data[2 * 1 + 0];
98 cofactor_matrix.data[2 * 1 + 0] = -self.data[2 * 0 + 1];
99 cofactor_matrix.data[2 * 1 + 1] = self.data[2 * 0 + 0];
100
101 Ok(cofactor_matrix)
102 }
103
104 fn adjugate(&self) -> Result<Self, MatrixError> {
108 Ok(self.cofactor().unwrap().transpose())
109 }
110
111 fn inverse(&self) -> Result<Self, MatrixError>
118 where
119 Self: Sized,
120 {
121 let determinant = self.determinant().unwrap();
122 if determinant == Self::Data::from(0_i16) {
123 return Err(MatrixError::ZeroDeterminantError);
124 }
125
126 let inverse_matrix = self.adjugate().unwrap();
127
128 Ok(inverse_matrix.scale(Self::Data::from(1_i16) / determinant))
129 }
130}
131
132impl TransformVector<Vector2D> for Matrix2x2 {
133 fn transform_vector(&self, other: Vector2D) -> Result<Vector2D, VectorError> {
134 Ok(crate::vector::vector2d::Vector2D {
135 data: [other[0] * self.data[2 * 0 + 0] + other[1] * self.data[2 * 0 + 1],
136 other[0] * self.data[2 * 1 + 0] + other[1] * self.data[2 * 1 + 1],]
137 })
138 }
139}
140
141impl std::cmp::PartialEq for Matrix2x2 {
142 fn eq(&self, other: &Matrix2x2) -> bool {
143 self.data.into_iter().eq(other.data.into_iter())
144 }
145}
146
147impl std::cmp::Eq for Matrix2x2 {}
148
149impl std::ops::Add for Matrix2x2 {
150 type Output = Matrix2x2;
151 fn add(self, other: Matrix2x2) -> Matrix2x2 {
152 let mut sum_matrix = Matrix2x2::new();
153
154 for i in 0..4 {
155 sum_matrix[i] = self.data[i] + other[i];
156 }
157
158 sum_matrix
159 }
160}
161
162impl std::ops::AddAssign for Matrix2x2 {
163 fn add_assign(&mut self, other: Matrix2x2) {
164 self.data[0] += other[0];
165 self.data[1] += other[1];
166 self.data[2] += other[2];
167 self.data[3] += other[3];
168 }
169}
170
171impl std::ops::Sub for Matrix2x2 {
172 type Output = Matrix2x2;
173 fn sub(self, other: Matrix2x2) -> Matrix2x2 {
174 let mut difference_matrix = Matrix2x2::new();
175
176 for i in 0..4 {
177 difference_matrix[i] = self.data[i] - other[i];
178 }
179
180 difference_matrix
181 }
182}
183
184impl std::ops::SubAssign for Matrix2x2 {
185 fn sub_assign(&mut self, other: Matrix2x2) {
186 self.data[0] -= other[0];
187 self.data[1] -= other[1];
188 self.data[2] -= other[2];
189 self.data[3] -= other[3];
190 }
191}
192
193impl std::ops::Mul for Matrix2x2 {
194 type Output = Matrix2x2;
195 fn mul(self, other: Matrix2x2) -> Matrix2x2 {
196 let mut product_matrix = Matrix2x2::new();
197
198 for i in 0..2 {
199 for j in 0..2 {
200 for m in 0..2 {
201 product_matrix[2 * i + j] += self.data[2 * i + m] * other[2 * m + j];
202 }
203 }
204 }
205
206 product_matrix
207 }
208}
209
210impl std::ops::MulAssign for Matrix2x2 {
211 fn mul_assign(&mut self, other: Matrix2x2) {
212 let mut product_matrix = Matrix2x2::new();
213
214 for i in 0..2 {
215 for j in 0..2 {
216 for m in 0..2 {
217 product_matrix[2 * i + j] += self.data[2 * i + m] * other[2 * m + j];
218 }
219 }
220 }
221
222 self.data[0..4].clone_from_slice(&product_matrix.data[0..4]);
223 }
224}
225
226impl std::ops::Neg for Matrix2x2 {
227 type Output = Matrix2x2;
228 fn neg(self) -> Matrix2x2 {
229 let mut negated_matrix = Matrix2x2::new();
230
231 negated_matrix[0] = -self.data[0];
232 negated_matrix[1] = -self.data[1];
233 negated_matrix[2] = -self.data[2];
234 negated_matrix[3] = -self.data[3];
235
236 negated_matrix
237 }
238}
239
240impl std::ops::Index<usize> for Matrix2x2 {
241 type Output = Fraction;
242 fn index(&self, index: usize) -> &Fraction {
243 &self.data[index]
244 }
245}
246
247impl std::ops::IndexMut<usize> for Matrix2x2 {
248 fn index_mut(&mut self, index: usize) -> &mut Fraction {
249 &mut self.data[index]
250 }
251}
252
253impl Copy for Matrix2x2 {}
254
255impl Clone for Matrix2x2 {
256 fn clone(&self) -> Matrix2x2 {
257 *self
258 }
259}
260
261impl fmt::Debug for Matrix2x2 {
262 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
263 write!(
264 f,
265 "\n[{}, {}]\n[{}, {}]",
266 self.data[2 * 0 + 0],
267 self.data[2 * 0 + 1],
268 self.data[2 * 1 + 0],
269 self.data[2 * 1 + 1]
270 )
271 }
272}
273
274impl fmt::Display for Matrix2x2 {
275 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276 write!(
277 f,
278 "\n({}, {})\n({}, {})",
279 self.data[2 * 0 + 0],
280 self.data[2 * 0 + 1],
281 self.data[2 * 1 + 0],
282 self.data[2 * 1 + 1]
283 )
284 }
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test]
292 fn new_test() {
293 let values: [Fraction; 4] = [
294 Fraction::new_denom(0, 1),
295 Fraction::new_denom(0, 1),
296 Fraction::new_denom(0, 1),
297 Fraction::new_denom(0, 1),
298 ];
299
300 let matrix1: Matrix2x2 = Matrix2x2 {
301 data: [
302 Fraction::new_denom(0, 1),
303 Fraction::new_denom(0, 1),
304 Fraction::new_denom(0, 1),
305 Fraction::new_denom(0, 1),
306 ],
307 };
308
309 let matrix2 = Matrix2x2::new();
310 let matrix3 = Matrix::from(Fraction::new_denom(0, 1));
311 let matrix4 = Matrix2x2::from_slice(&values);
312
313 assert_eq!(matrix1, matrix2);
314 assert_eq!(matrix2, matrix3);
315 assert_eq!(matrix3, matrix4);
316 }
317
318 #[test]
319 fn addition_test() {
320 let matrix1: Matrix2x2 = Matrix::from(Fraction::new_denom(5, 1));
321 let matrix2 = Matrix::from(Fraction::new_denom(6, 1));
322
323 let result_matrix = Matrix::from(Fraction::new_denom(11, 1));
324
325 assert_eq!(matrix1 + matrix2, result_matrix);
326 assert_eq!(matrix2 + matrix1, result_matrix);
327 }
328
329 #[test]
330 fn subtraction_test() {
331 let matrix1: Matrix2x2 = Matrix::from(Fraction::new_denom(5, 1));
332 let matrix2 = Matrix::from(Fraction::new_denom(6, 1));
333
334 let result_matrix1 = Matrix::from(Fraction::new_denom(-1, 1));
335 let result_matrix2 = Matrix::from(Fraction::new_denom(1, 1));
336
337 assert_eq!(matrix1 - matrix2, result_matrix1);
338 assert_eq!(matrix2 - matrix1, result_matrix2);
339 }
340
341 #[test]
342 fn multiplication_test() {
343 let values1: [Fraction; 4] = [
344 Fraction::new_denom(4, 1),
345 Fraction::new_denom(2, 1),
346 Fraction::new_denom(5, 1),
347 Fraction::new_denom(1, 1),
348 ];
349
350 let values2: [Fraction; 4] = [
351 Fraction::new_denom(5, 1),
352 Fraction::new_denom(2, 1),
353 Fraction::new_denom(6, 1),
354 Fraction::new_denom(3, 1),
355 ];
356
357 let result_values1: [Fraction; 4] = [
358 Fraction::new_denom(32, 1),
359 Fraction::new_denom(14, 1),
360 Fraction::new_denom(31, 1),
361 Fraction::new_denom(13, 1),
362 ];
363
364 let result_values2: [Fraction; 4] = [
365 Fraction::new_denom(30, 1),
366 Fraction::new_denom(12, 1),
367 Fraction::new_denom(39, 1),
368 Fraction::new_denom(15, 1),
369 ];
370
371 let matrix1: Matrix2x2 = Matrix2x2::from_slice(&values1);
372 let matrix2 = Matrix2x2::from_slice(&values2);
373 let result_matrix1 = Matrix2x2::from_slice(&result_values1);
374 let result_matrix2 = Matrix2x2::from_slice(&result_values2);
375
376 assert_eq!(matrix1 * matrix2, result_matrix1);
377 assert_eq!(matrix2 * matrix1, result_matrix2);
378 }
379
380 #[test]
381 fn scale_test() {
382 let scale = Fraction::new_denom(5, 1);
383 let values: [Fraction; 4] = [
384 Fraction::new_denom(4, 1),
385 Fraction::new_denom(2, 1),
386 Fraction::new_denom(5, 1),
387 Fraction::new_denom(1, 1),
388 ];
389
390 let result_values: [Fraction; 4] = [
391 Fraction::new_denom(4 * 5, 1),
392 Fraction::new_denom(2 * 5, 1),
393 Fraction::new_denom(5 * 5, 1),
394 Fraction::new_denom(1 * 5, 1),
395 ];
396
397 let matrix = Matrix2x2::from_slice(&values);
398 let result_matrix = Matrix2x2::from_slice(&result_values);
399
400 assert_eq!(matrix.scale(scale), result_matrix);
401 }
402
403 #[test]
404 fn transpose_test() {
405 let values1: [Fraction; 4] = [
406 Fraction::new_denom(2, 1),
407 Fraction::new_denom(6, 1),
408 Fraction::new_denom(5, 1),
409 Fraction::new_denom(1, 1),
410 ];
411
412 let result_values: [Fraction; 4] = [
413 Fraction::new_denom(2, 1),
414 Fraction::new_denom(5, 1),
415 Fraction::new_denom(6, 1),
416 Fraction::new_denom(1, 1),
417 ];
418
419 let matrix = Matrix2x2::from_slice(&values1);
420 let result_matrix = Matrix2x2::from_slice(&result_values);
421
422 assert_eq!(matrix.transpose(), result_matrix);
423 }
424
425 #[test]
426 fn cofactor_test() {
427 let values: [Fraction; 4] = [
428 Fraction::new_denom(5, 1),
429 Fraction::new_denom(2, 1),
430 Fraction::new_denom(7, 1),
431 Fraction::new_denom(2, 1),
432 ];
433
434 let result_values: [Fraction; 4] = [
435 Fraction::new_denom(2, 1),
436 Fraction::new_denom(-7, 1),
437 Fraction::new_denom(-2, 1),
438 Fraction::new_denom(5, 1),
439 ];
440
441 let matrix = Matrix2x2::from_slice(&values);
442 let result_matrix = Matrix2x2::from_slice(&result_values);
443
444 assert_eq!(matrix.cofactor().unwrap(), result_matrix);
445 }
446
447 #[test]
448 fn adjugate_test() {
449 let values: [Fraction; 4] = [
450 Fraction::new_denom(5, 1),
451 Fraction::new_denom(2, 1),
452 Fraction::new_denom(7, 1),
453 Fraction::new_denom(2, 1),
454 ];
455
456 let result_values: [Fraction; 4] = [
457 Fraction::new_denom(2, 1),
458 Fraction::new_denom(-2, 1),
459 Fraction::new_denom(-7, 1),
460 Fraction::new_denom(5, 1),
461 ];
462
463 let matrix = Matrix2x2::from_slice(&values);
464 let result_matrix = Matrix2x2::from_slice(&result_values);;
465
466 assert_eq!(matrix.adjugate().unwrap(), result_matrix);
467 }
468
469 #[test]
470 fn determinant_test() {
471 let values: [Fraction; 4] = [
472 Fraction::new_denom(4, 1),
473 Fraction::new_denom(2, 1),
474 Fraction::new_denom(5, 1),
475 Fraction::new_denom(1, 1),
476 ];
477
478 let matrix = Matrix2x2::from_slice(&values);
479
480 let determinant = Fraction::new_denom(-6, 1);
481
482 assert_eq!(matrix.determinant().unwrap(), determinant);
483 }
484
485 #[test]
486 fn inverse_test() {
487 let values: [Fraction; 4] = [
488 Fraction::new_denom(5, 1),
489 Fraction::new_denom(2, 1),
490 Fraction::new_denom(4, 1),
491 Fraction::new_denom(7, 1),
492 ];
493
494 let result_values: [Fraction; 4] = [
495 Fraction::new_denom(7, 27),
496 Fraction::new_denom(-2, 27),
497 Fraction::new_denom(-4, 27),
498 Fraction::new_denom(5, 27),
499 ];
500
501 let matrix = Matrix2x2::from_slice(&values);
502 let result_matrix = Matrix2x2::from_slice(&result_values);
503
504 assert_eq!(matrix.inverse().unwrap(), result_matrix);
505 }
506}