1#![no_std]
44#![forbid(unsafe_code)]
45#![warn(missing_docs)]
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum MatrixError {
50 SingularMatrix,
52}
53#[derive(Debug, Clone, Copy, PartialEq)]
63pub struct Matrix2x2 {
64 data: [[f32; 2]; 2],
65}
66
67impl Matrix2x2 {
68 #[inline]
72 pub const fn new(data: [[f32; 2]; 2]) -> Self {
73 Self { data }
74 }
75
76 #[inline]
78 pub const fn identity() -> Self {
79 Self::new([[1.0, 0.0], [0.0, 1.0]])
80 }
81
82 #[inline]
84 pub const fn zero() -> Self {
85 Self::new([[0.0, 0.0], [0.0, 0.0]])
86 }
87
88 #[inline]
91 pub fn get(&self, row: usize, col: usize) -> f32 {
92 self.data[row][col]
93 }
94
95 #[inline]
97 pub fn as_array(&self) -> &[[f32; 2]; 2] {
98 &self.data
99 }
100
101 #[inline]
104 pub fn add(&self, rhs: &Self) -> Self {
105 Self::new([
106 [self.data[0][0] + rhs.data[0][0], self.data[0][1] + rhs.data[0][1]],
107 [self.data[1][0] + rhs.data[1][0], self.data[1][1] + rhs.data[1][1]],
108 ])
109 }
110
111 #[inline]
113 pub fn sub(&self, rhs: &Self) -> Self {
114 Self::new([
115 [self.data[0][0] - rhs.data[0][0], self.data[0][1] - rhs.data[0][1]],
116 [self.data[1][0] - rhs.data[1][0], self.data[1][1] - rhs.data[1][1]],
117 ])
118 }
119
120 #[inline]
122 pub fn mul(&self, rhs: &Self) -> Self {
123 let a = &self.data;
124 let b = &rhs.data;
125 Self::new([
126 [
127 a[0][0] * b[0][0] + a[0][1] * b[1][0],
128 a[0][0] * b[0][1] + a[0][1] * b[1][1],
129 ],
130 [
131 a[1][0] * b[0][0] + a[1][1] * b[1][0],
132 a[1][0] * b[0][1] + a[1][1] * b[1][1],
133 ],
134 ])
135 }
136
137 #[inline]
139 pub fn scale(&self, s: f32) -> Self {
140 Self::new([
141 [self.data[0][0] * s, self.data[0][1] * s],
142 [self.data[1][0] * s, self.data[1][1] * s],
143 ])
144 }
145
146 #[inline]
149 pub fn transpose(&self) -> Self {
150 Self::new([
151 [self.data[0][0], self.data[1][0]],
152 [self.data[0][1], self.data[1][1]],
153 ])
154 }
155
156 #[inline]
158 pub fn det(&self) -> f32 {
159 self.data[0][0] * self.data[1][1] - self.data[0][1] * self.data[1][0]
160 }
161
162 #[inline]
164 pub fn trace(&self) -> f32 {
165 self.data[0][0] + self.data[1][1]
166 }
167
168 pub fn inv(&self) -> Result<Self, MatrixError> {
173 let d = self.det();
174 if (if d < 0.0 { -d } else { d }) < 1e-7 {
175 return Err(MatrixError::SingularMatrix);
176 }
177 let inv_d = 1.0 / d;
178 Ok(Self::new([
179 [ self.data[1][1] * inv_d, -self.data[0][1] * inv_d],
180 [-self.data[1][0] * inv_d, self.data[0][0] * inv_d],
181 ]))
182 }
183}
184
185impl core::ops::Add for Matrix2x2 {
188 type Output = Self;
189 #[inline]
190 fn add(self, rhs: Self) -> Self {
191 Matrix2x2::add(&self, &rhs)
192 }
193}
194
195impl core::ops::Sub for Matrix2x2 {
197 type Output = Self;
198 #[inline]
199 fn sub(self, rhs: Self) -> Self {
200 Matrix2x2::sub(&self, &rhs)
201 }
202}
203
204impl core::ops::Mul for Matrix2x2 {
206 type Output = Self;
207 #[inline]
208 fn mul(self, rhs: Self) -> Self {
209 Matrix2x2::mul(&self, &rhs)
210 }
211}
212
213impl core::ops::Mul<f32> for Matrix2x2 {
215 type Output = Self;
216 #[inline]
217 fn mul(self, s: f32) -> Self {
218 self.scale(s)
219 }
220}
221
222impl core::ops::Neg for Matrix2x2 {
224 type Output = Self;
225 #[inline]
226 fn neg(self) -> Self {
227 self.scale(-1.0)
228 }
229}
230
231
232#[derive(Debug, Clone, Copy, PartialEq)]
243pub struct Matrix3x3 {
244 data: [[f32; 3]; 3],
245}
246
247impl Matrix3x3 {
248 #[inline]
252 pub const fn new(data: [[f32; 3]; 3]) -> Self {
253 Self { data }
254 }
255
256 #[inline]
258 pub const fn identity() -> Self {
259 Self::new([
260 [1.0, 0.0, 0.0],
261 [0.0, 1.0, 0.0],
262 [0.0, 0.0, 1.0],
263 ])
264 }
265
266 #[inline]
268 pub const fn zero() -> Self {
269 Self::new([[0.0; 3]; 3])
270 }
271
272 #[inline]
275 pub fn get(&self, row: usize, col: usize) -> f32 {
276 self.data[row][col]
277 }
278
279 #[inline]
281 pub fn as_array(&self) -> &[[f32; 3]; 3] {
282 &self.data
283 }
284
285 #[inline]
296 pub fn add(&self, rhs: &Self) -> Self {
297 let mut out = [[0.0f32; 3]; 3];
298 for i in 0..3 {
299 for j in 0..3 {
300 out[i][j] = self.data[i][j] + rhs.data[i][j];
301 }
302 }
303 Self::new(out)
304 }
305
306 #[inline]
308 pub fn sub(&self, rhs: &Self) -> Self {
309 let mut out = [[0.0f32; 3]; 3];
310 for i in 0..3 {
311 for j in 0..3 {
312 out[i][j] = self.data[i][j] - rhs.data[i][j];
313 }
314 }
315 Self::new(out)
316 }
317
318 #[inline]
320 pub fn mul(&self, rhs: &Self) -> Self {
321 let mut out = [[0.0f32; 3]; 3];
322 for i in 0..3 {
323 for j in 0..3 {
324 for k in 0..3 {
325 out[i][j] += self.data[i][k] * rhs.data[k][j];
326 }
327 }
328 }
329 Self::new(out)
330 }
331
332 #[inline]
334 pub fn scale(&self, s: f32) -> Self {
335 let mut out = [[0.0f32; 3]; 3];
336 for i in 0..3 {
337 for j in 0..3 {
338 out[i][j] = self.data[i][j] * s;
339 }
340 }
341 Self::new(out)
342 }
343
344 #[inline]
347 pub fn transpose(&self) -> Self {
348 let mut out = [[0.0f32; 3]; 3];
349 for i in 0..3 {
350 for j in 0..3 {
351 out[j][i] = self.data[i][j];
352 }
353 }
354 Self::new(out)
355 }
356
357 #[inline]
359 pub fn det(&self) -> f32 {
360 let d = &self.data;
361 d[0][0] * (d[1][1] * d[2][2] - d[1][2] * d[2][1])
362 - d[0][1] * (d[1][0] * d[2][2] - d[1][2] * d[2][0])
363 + d[0][2] * (d[1][0] * d[2][1] - d[1][1] * d[2][0])
364 }
365
366 #[inline]
368 pub fn trace(&self) -> f32 {
369 self.data[0][0] + self.data[1][1] + self.data[2][2]
370 }
371
372 pub fn inv(&self) -> Result<Self, MatrixError> {
376 let det = self.det();
377 if (if det < 0.0 { -det } else { det }) < 1e-7 {
378 return Err(MatrixError::SingularMatrix);
379 }
380 let d = &self.data;
381 let inv_det = 1.0 / det;
382
383 Ok(Self::new([
385 [
386 (d[1][1] * d[2][2] - d[1][2] * d[2][1]) * inv_det,
387 (d[0][2] * d[2][1] - d[0][1] * d[2][2]) * inv_det,
388 (d[0][1] * d[1][2] - d[0][2] * d[1][1]) * inv_det,
389 ],
390 [
391 (d[1][2] * d[2][0] - d[1][0] * d[2][2]) * inv_det,
392 (d[0][0] * d[2][2] - d[0][2] * d[2][0]) * inv_det,
393 (d[0][2] * d[1][0] - d[0][0] * d[1][2]) * inv_det,
394 ],
395 [
396 (d[1][0] * d[2][1] - d[1][1] * d[2][0]) * inv_det,
397 (d[0][1] * d[2][0] - d[0][0] * d[2][1]) * inv_det,
398 (d[0][0] * d[1][1] - d[0][1] * d[1][0]) * inv_det,
399 ],
400 ]))
401 }
402}
403
404impl core::ops::Add for Matrix3x3 {
408 type Output = Self;
409 #[inline]
410 fn add(self, rhs: Self) -> Self {
411 Matrix3x3::add(&self, &rhs)
412 }
413}
414
415impl core::ops::Sub for Matrix3x3 {
417 type Output = Self;
418 #[inline]
419 fn sub(self, rhs: Self) -> Self {
420 Matrix3x3::sub(&self, &rhs)
421 }
422}
423
424impl core::ops::Mul for Matrix3x3 {
426 type Output = Self;
427 #[inline]
428 fn mul(self, rhs: Self) -> Self {
429 Matrix3x3::mul(&self, &rhs)
430 }
431}
432
433impl core::ops::Mul<f32> for Matrix3x3 {
435 type Output = Self;
436 #[inline]
437 fn mul(self, s: f32) -> Self {
438 self.scale(s)
439 }
440}
441
442impl core::ops::Neg for Matrix3x3 {
444 type Output = Self;
445 #[inline]
446 fn neg(self) -> Self {
447 self.scale(-1.0)
448 }
449}
450
451
452#[cfg(test)]
455mod tests {
456 use super::*;
457
458 #[test]
460 fn m2_identity_det() {
461 assert!((Matrix2x2::identity().det() - 1.0).abs() < 1e-6);
462 }
463
464 #[test]
465 fn m2_det() {
466 let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
467 assert!((m.det() - (-2.0)).abs() < 1e-6);
468 }
469
470 #[test]
471 fn m2_trace() {
472 let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
473 assert!((m.trace() - 5.0).abs() < 1e-6);
474 }
475
476 #[test]
477 fn m2_add_sub() {
478 let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
479 let b = Matrix2x2::new([[5.0, 6.0], [7.0, 8.0]]);
480 let s = a.add(&b);
481 assert!((s.get(0, 0) - 6.0).abs() < 1e-6);
482 assert!((s.get(1, 1) - 12.0).abs() < 1e-6);
483 let d = b.sub(&a);
484 assert!((d.get(0, 0) - 4.0).abs() < 1e-6);
485 }
486
487 #[test]
488 fn m2_mul_identity() {
489 let m = Matrix2x2::new([[3.0, 1.0], [2.0, 4.0]]);
490 let r = m.mul(&Matrix2x2::identity());
491 assert!((r.get(0, 0) - m.get(0, 0)).abs() < 1e-6);
492 assert!((r.get(1, 1) - m.get(1, 1)).abs() < 1e-6);
493 }
494
495 #[test]
496 fn m2_mul() {
497 let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
498 let b = Matrix2x2::new([[2.0, 0.0], [1.0, 3.0]]);
499 let c = a.mul(&b);
500 assert!((c.get(0, 0) - 4.0).abs() < 1e-6);
503 assert!((c.get(0, 1) - 6.0).abs() < 1e-6);
504 assert!((c.get(1, 0) - 10.0).abs() < 1e-6);
505 assert!((c.get(1, 1) - 12.0).abs() < 1e-6);
506 }
507
508 #[test]
509 fn m2_scale() {
510 let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
511 let s = m.scale(2.0);
512 assert!((s.get(0, 0) - 2.0).abs() < 1e-6);
513 assert!((s.get(1, 1) - 8.0).abs() < 1e-6);
514 }
515
516 #[test]
517 fn m2_transpose() {
518 let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
519 let t = m.transpose();
520 assert!((t.get(0, 1) - 3.0).abs() < 1e-6);
521 assert!((t.get(1, 0) - 2.0).abs() < 1e-6);
522 }
523
524 #[test]
525 fn m2_inv_ok() {
526 let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
527 let inv = m.inv().unwrap();
528 let i = m.mul(&inv);
530 assert!((i.get(0, 0) - 1.0).abs() < 1e-5);
531 assert!((i.get(1, 1) - 1.0).abs() < 1e-5);
532 assert!(i.get(0, 1).abs() < 1e-5);
533 assert!(i.get(1, 0).abs() < 1e-5);
534 }
535
536 #[test]
537 fn m2_inv_singular() {
538 let m = Matrix2x2::new([[1.0, 2.0], [2.0, 4.0]]); assert_eq!(m.inv(), Err(MatrixError::SingularMatrix));
540 }
541
542 #[test]
545 fn m3_identity_det() {
546 assert!((Matrix3x3::identity().det() - 1.0).abs() < 1e-6);
547 }
548
549 #[test]
550 fn m3_identity_trace() {
551 assert!((Matrix3x3::identity().trace() - 3.0).abs() < 1e-6);
552 }
553
554 #[test]
555 fn m3_det() {
556 let m = Matrix3x3::new([
557 [1.0, 2.0, 3.0],
558 [4.0, 5.0, 6.0],
559 [7.0, 8.0, 9.0],
560 ]);
561 assert!(m.det().abs() < 1e-4);
563 }
564
565 #[test]
566 fn m3_det_nonzero() {
567 let m = Matrix3x3::new([
568 [2.0, -1.0, 0.0],
569 [-1.0, 2.0, -1.0],
570 [0.0, -1.0, 2.0],
571 ]);
572 assert!((m.det() - 4.0).abs() < 1e-5);
573 }
574
575 #[test]
576 fn m3_add_sub() {
577 let a = Matrix3x3::identity();
578 let b = Matrix3x3::identity();
579 let s = a.add(&b);
580 assert!((s.get(0, 0) - 2.0).abs() < 1e-6);
581 let d = s.sub(&a);
582 assert!((d.get(0, 0) - 1.0).abs() < 1e-6);
583 }
584
585 #[test]
586 fn m3_mul_identity() {
587 let m = Matrix3x3::new([
588 [1.0, 2.0, 3.0],
589 [0.0, 1.0, 4.0],
590 [5.0, 6.0, 0.0],
591 ]);
592 let r = m.mul(&Matrix3x3::identity());
593 for i in 0..3 {
594 for j in 0..3 {
595 assert!((r.get(i, j) - m.get(i, j)).abs() < 1e-6);
596 }
597 }
598 }
599
600 #[test]
601 fn m3_transpose() {
602 let m = Matrix3x3::new([
603 [1.0, 2.0, 3.0],
604 [4.0, 5.0, 6.0],
605 [7.0, 8.0, 9.0],
606 ]);
607 let t = m.transpose();
608 assert!((t.get(0, 1) - 4.0).abs() < 1e-6);
609 assert!((t.get(1, 0) - 2.0).abs() < 1e-6);
610 assert!((t.get(2, 0) - 3.0).abs() < 1e-6);
611 }
612
613 #[test]
614 fn m3_inv_ok() {
615 let m = Matrix3x3::new([
616 [2.0, -1.0, 0.0],
617 [-1.0, 2.0, -1.0],
618 [0.0, -1.0, 2.0],
619 ]);
620 let inv = m.inv().unwrap();
621 let i = m.mul(&inv);
622 for r in 0..3 {
623 for c in 0..3 {
624 let expected = if r == c { 1.0 } else { 0.0 };
625 assert!((i.get(r, c) - expected).abs() < 1e-5,
626 "i[{r}][{c}] = {} expected {expected}", i.get(r, c));
627 }
628 }
629 }
630
631 #[test]
632 fn m3_inv_singular() {
633 let m = Matrix3x3::new([
634 [1.0, 2.0, 3.0],
635 [4.0, 5.0, 6.0],
636 [7.0, 8.0, 9.0],
637 ]);
638 assert_eq!(m.inv(), Err(MatrixError::SingularMatrix));
639 }
640
641 #[test]
642 fn m3_scale() {
643 let m = Matrix3x3::identity();
644 let s = m.scale(3.0);
645 assert!((s.get(0, 0) - 3.0).abs() < 1e-6);
646 assert!((s.get(0, 1)).abs() < 1e-6);
647 }
648
649 #[test]
651 fn m2_ops_add() {
652 let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
653 let b = Matrix2x2::new([[1.0, 0.0], [0.0, 1.0]]);
654 let c = a + b;
655 assert!((c.get(0, 0) - 2.0).abs() < 1e-6);
656 assert!((c.get(1, 1) - 5.0).abs() < 1e-6);
657 }
658
659 #[test]
660 fn m2_ops_sub() {
661 let a = Matrix2x2::new([[3.0, 2.0], [1.0, 4.0]]);
662 let b = Matrix2x2::new([[1.0, 1.0], [1.0, 1.0]]);
663 let c = a - b;
664 assert!((c.get(0, 0) - 2.0).abs() < 1e-6);
665 assert!((c.get(1, 1) - 3.0).abs() < 1e-6);
666 }
667
668 #[test]
669 fn m2_ops_mul_matrix() {
670 let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
671 let b = Matrix2x2::new([[2.0, 0.0], [1.0, 3.0]]);
672 let c = a * b;
673 assert!((c.get(0, 0) - 4.0).abs() < 1e-6);
674 assert!((c.get(0, 1) - 6.0).abs() < 1e-6);
675 }
676
677 #[test]
678 fn m2_ops_mul_scalar() {
679 let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
680 let b = a * 3.0;
681 assert!((b.get(0, 0) - 3.0).abs() < 1e-6);
682 assert!((b.get(1, 1) - 12.0).abs() < 1e-6);
683 }
684
685 #[test]
686 fn m2_ops_neg() {
687 let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
688 let b = -a;
689 assert!((b.get(0, 0) + 1.0).abs() < 1e-6);
690 assert!((b.get(1, 1) + 4.0).abs() < 1e-6);
691 }
692
693 #[test]
696 fn m3_ops_add() {
697 let a = Matrix3x3::identity();
698 let b = Matrix3x3::identity();
699 let c = a + b;
700 assert!((c.get(0, 0) - 2.0).abs() < 1e-6);
701 assert!((c.get(0, 1)).abs() < 1e-6);
702 }
703
704 #[test]
705 fn m3_ops_sub() {
706 let a = Matrix3x3::identity();
707 let b = Matrix3x3::identity();
708 let c = a - b;
709 assert!(c.get(0, 0).abs() < 1e-6);
710 }
711
712 #[test]
713 fn m3_ops_mul_matrix() {
714 let a = Matrix3x3::new([
715 [1.0, 2.0, 3.0],
716 [0.0, 1.0, 4.0],
717 [5.0, 6.0, 0.0],
718 ]);
719 let i = Matrix3x3::identity();
720 let c = a * i;
721 for r in 0..3 {
722 for col in 0..3 {
723 assert!((c.get(r, col) - a.get(r, col)).abs() < 1e-6);
724 }
725 }
726 }
727
728 #[test]
729 fn m3_ops_mul_scalar() {
730 let a = Matrix3x3::identity();
731 let b = a * 5.0;
732 assert!((b.get(0, 0) - 5.0).abs() < 1e-6);
733 assert!((b.get(0, 1)).abs() < 1e-6);
734 }
735
736 #[test]
737 fn m3_ops_neg() {
738 let a = Matrix3x3::identity();
739 let b = -a;
740 assert!((b.get(0, 0) + 1.0).abs() < 1e-6);
741 assert!((b.get(1, 1) + 1.0).abs() < 1e-6);
742 }
743}