generic.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign};
  2. use std::ptr::swap;
  3. use crate::{Float, Matrix, Numeric, Primitive, View};
  4. #[cfg(feature = "angular")]
  5. use crate::Angular;
  6. use crate::types::matrix::matrices_are_equal;
  7. /// Struct representing a dense matrix.
  8. #[repr(transparent)]
  9. #[derive(Copy, Clone, Debug)]
  10. pub struct GenericMatrix<T: Numeric, const ROWS: usize, const COLUMNS: usize> {
  11. pub data: [[T; COLUMNS]; ROWS],
  12. }
  13. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Matrix<T, ROWS, COLUMNS> for GenericMatrix<T, ROWS, COLUMNS> {
  14. fn get(&self, row: usize, col: usize) -> T {
  15. self.data[row][col]
  16. }
  17. fn set(&mut self, row: usize, col: usize, value: T) {
  18. self.data[row][col] = value;
  19. }
  20. }
  21. /// Special kind of `GenericMatrix` where both dimensions are equal.
  22. pub type SquareMatrix<T, const DIMENSION: usize> = GenericMatrix<T, DIMENSION, DIMENSION>;
  23. /// Special kind of `GenericMatrix` with just one column.
  24. pub type ColumnVector<T, const ROWS: usize> = GenericMatrix<T, ROWS, 1>;
  25. /// Special kind of `GenericMatrix` with just one row.
  26. pub type RowVector<T, const COLUMNS: usize> = GenericMatrix<T, 1, COLUMNS>;
  27. /// A macro for easier creation of row vectors.
  28. ///
  29. /// # Example
  30. ///
  31. /// ```rust
  32. /// # use lineal::{RowVector, rvec};
  33. /// let a = rvec![1.0, 2.0, 3.0];
  34. /// // is the same as
  35. /// let b = RowVector {
  36. /// data: [[1.0, 2.0, 3.0]],
  37. /// };
  38. /// ```
  39. #[macro_export]
  40. macro_rules! rvec {
  41. ($($value:expr),* $(,)?) => {
  42. {
  43. RowVector {
  44. data: [[$( $value, )*]],
  45. }
  46. }
  47. }
  48. }
  49. /// A macro for easier creation of column vectors.
  50. ///
  51. /// # Example
  52. ///
  53. /// ```rust
  54. /// # use lineal::{ColumnVector, cvec};
  55. /// let a = cvec![1.0, 2.0, 3.0];
  56. /// // is the same as
  57. /// let b = ColumnVector {
  58. /// data: [[1.0], [2.0], [3.0]],
  59. /// };
  60. /// ```
  61. #[macro_export]
  62. macro_rules! cvec {
  63. ($($value:expr),* $(,)?) => {
  64. {
  65. ColumnVector {
  66. data: [$( [$value], )*],
  67. }
  68. }
  69. }
  70. }
  71. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Default for GenericMatrix<T, ROWS, COLUMNS> {
  72. /// Create a matrix with all cells being zero.
  73. fn default() -> Self {
  74. let zero = T::whole(0);
  75. Self {
  76. data: [[zero; COLUMNS]; ROWS],
  77. }
  78. }
  79. }
  80. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> GenericMatrix<T, ROWS, COLUMNS> {
  81. /// Create a matrix with all cells being zero.
  82. pub fn new() -> Self {
  83. Self::default()
  84. }
  85. pub fn view<const VIEW_ROWS: usize, const VIEW_COLUMNS: usize>(&self, origin: (usize, usize)) -> View<T, VIEW_ROWS, VIEW_COLUMNS, ROWS, COLUMNS, Self> {
  86. View::new(self, origin)
  87. }
  88. /// Create a transpose of the input matrix.
  89. ///
  90. /// # Example
  91. ///
  92. /// ```rust
  93. /// # use lineal::{ColumnVector, RowVector, cvec, rvec};
  94. /// let a = cvec![1, 2, 3];
  95. /// let b = rvec![1, 2, 3];
  96. /// assert_eq!(a.transposed(), b);
  97. /// ```
  98. pub fn transposed(&self) -> GenericMatrix<T, COLUMNS, ROWS> {
  99. let mut result = GenericMatrix::default();
  100. for r in 0..ROWS {
  101. for c in 0..COLUMNS {
  102. result.data[c][r] = self.data[r][c];
  103. }
  104. }
  105. result
  106. }
  107. }
  108. impl<T: Numeric, const DIMENSION: usize> SquareMatrix<T, DIMENSION> {
  109. /// Create a square identity matrix.
  110. ///
  111. /// In an identity matrix the main diagonal is filled with ones,
  112. /// while the rest if the cells are zero.
  113. ///
  114. /// # Example
  115. ///
  116. /// ```rust
  117. /// # use lineal::{SquareMatrix};
  118. /// let a: SquareMatrix<f32, 3> = SquareMatrix::identity();
  119. /// // is the same as
  120. /// let b: SquareMatrix<f32, 3> = SquareMatrix {
  121. /// data: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
  122. /// };
  123. /// ```
  124. pub fn identity() -> Self {
  125. let mut mat = Self::default();
  126. let one = T::whole(1);
  127. for i in 0..DIMENSION {
  128. mat.data[i][i] = one;
  129. }
  130. mat
  131. }
  132. /// Create a square matrix with its main diagonal filled with the given values.
  133. ///
  134. /// # Example
  135. ///
  136. /// ```rust
  137. /// # use lineal::{SquareMatrix};
  138. /// let a = SquareMatrix::diagonal(&[1, 2, 3]);
  139. /// // is the same as
  140. /// let b = SquareMatrix {
  141. /// data: [
  142. /// [1, 0, 0],
  143. /// [0, 2, 0],
  144. /// [0, 0, 3],
  145. /// ],
  146. /// };
  147. /// ```
  148. pub fn diagonal(values: &[T; DIMENSION]) -> Self {
  149. let mut mat = Self::default();
  150. for i in 0..DIMENSION {
  151. mat.data[i][i] = values[i];
  152. }
  153. mat
  154. }
  155. }
  156. impl<T: Numeric + Float + PartialOrd, const DIMENSION: usize> SquareMatrix<T, DIMENSION> {
  157. /// Apply an LUP decomposition to the matrix.
  158. ///
  159. /// # Safety
  160. ///
  161. /// This function is unsafe, because even when the result is false,
  162. /// the matrix may already have been modified.
  163. pub unsafe fn lup_decompose(&mut self, pivot: &mut Vec<usize>, tolerance: T) -> bool {
  164. pivot.clear();
  165. pivot.reserve(DIMENSION + 1);
  166. for i in 0..(DIMENSION + 1) {
  167. pivot.push(i);
  168. }
  169. let zero = T::whole(0);
  170. for i in 0..DIMENSION {
  171. let mut max_a = zero;
  172. let mut max_i = i;
  173. for k in i..DIMENSION {
  174. let abs_a = self[(k, i)].abs();
  175. if abs_a > max_a {
  176. max_a = abs_a;
  177. max_i = k;
  178. }
  179. }
  180. if max_a <= tolerance {
  181. return false;
  182. }
  183. if max_i != i {
  184. pivot.swap(i, max_i);
  185. let p_a: *mut [T; DIMENSION] = (&mut self.data[i]) as *mut [T; DIMENSION];
  186. let p_a_max: *mut [T; DIMENSION] = (&mut self.data[max_i]) as *mut [T; DIMENSION];
  187. swap(p_a, p_a_max);
  188. pivot[DIMENSION] += 1;
  189. }
  190. for j in (i + 1)..DIMENSION {
  191. let divisor = self[(i, i)];
  192. self[(j, i)] /= divisor;
  193. for k in (i + 1)..DIMENSION {
  194. let a = self[(j, i)];
  195. let b = self[(i, k)];
  196. self[(j, k)] -= a * b;
  197. }
  198. }
  199. }
  200. true
  201. }
  202. /// Calculate the determinant of the input matrix.
  203. pub fn determinant(mut self, tolerance: T) -> Option<T> {
  204. let mut pivot = Vec::new();
  205. if !unsafe { self.lup_decompose(&mut pivot, tolerance) } {
  206. return None;
  207. }
  208. debug_assert_eq!(pivot.len(), DIMENSION + 1);
  209. let mut result = self[(0, 0)];
  210. for i in 1..DIMENSION {
  211. result *= self[(i, i)];
  212. }
  213. if (pivot[DIMENSION] - DIMENSION) % 2 == 0 {
  214. Some(result)
  215. } else {
  216. Some(-result)
  217. }
  218. }
  219. /// Solve the equation `self` * `x` = `b` for `x`.
  220. pub fn solve(mut self, b: &ColumnVector<T, DIMENSION>, tolerance: T) -> Option<RowVector<T, DIMENSION>> {
  221. let mut pivot = Vec::new();
  222. if !unsafe { self.lup_decompose(&mut pivot, tolerance) } {
  223. return None;
  224. }
  225. debug_assert_eq!(pivot.len(), DIMENSION + 1);
  226. let mut result = RowVector::new();
  227. for i in 0..DIMENSION {
  228. result[(0, i)] = b[(pivot[i], 0)];
  229. for k in 0..i {
  230. let factor = result[(0, k)];
  231. result[(0, i)] -= self[(i, k)] * factor;
  232. }
  233. }
  234. for i in (0..DIMENSION).rev() {
  235. for k in (i + 1)..DIMENSION {
  236. let factor = result[(0, k)];
  237. result[(0, i)] -= self[(i, k)] * factor;
  238. }
  239. result[(0, i)] /= self[(i, i)];
  240. }
  241. Some(result)
  242. }
  243. /// Calculate the inverse of the input matrix.
  244. pub fn inverted(mut self, tolerance: T) -> Option<Self> {
  245. let mut pivot = Vec::new();
  246. if !unsafe { self.lup_decompose(&mut pivot, tolerance) } {
  247. return None;
  248. }
  249. debug_assert_eq!(pivot.len(), DIMENSION + 1);
  250. let mut result = Self::new();
  251. let zero = T::whole(0);
  252. let one = T::whole(1);
  253. for j in 0..DIMENSION {
  254. for i in 0..DIMENSION {
  255. result[(i, j)] = if pivot[i] == j { one } else { zero };
  256. for k in 0..i {
  257. let factor = result[(k, j)];
  258. result[(i, j)] -= self[(i, k)] * factor;
  259. }
  260. }
  261. for i in (0..DIMENSION).rev() {
  262. for k in (i + 1)..DIMENSION {
  263. let factor = result[(k, j)];
  264. result[(i, j)] -= self[(i, k)] * factor;
  265. }
  266. result[(i, j)] /= self[(i, i)];
  267. }
  268. }
  269. Some(result)
  270. }
  271. }
  272. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> From<[[T; COLUMNS]; ROWS]> for GenericMatrix<T, ROWS, COLUMNS> {
  273. fn from(data: [[T; COLUMNS]; ROWS]) -> Self {
  274. Self {
  275. data,
  276. }
  277. }
  278. }
  279. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Index<(usize, usize)> for GenericMatrix<T, ROWS, COLUMNS> {
  280. type Output = T;
  281. fn index(&self, index: (usize, usize)) -> &Self::Output {
  282. let (row, column) = index;
  283. &self.data[row][column]
  284. }
  285. }
  286. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> IndexMut<(usize, usize)> for GenericMatrix<T, ROWS, COLUMNS> {
  287. fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
  288. let (row, column) = index;
  289. &mut self.data[row][column]
  290. }
  291. }
  292. impl<T: Numeric + Neg<Output=T>, const ROWS: usize, const COLUMNS: usize> Neg for GenericMatrix<T, ROWS, COLUMNS> {
  293. type Output = Self;
  294. fn neg(self) -> Self::Output {
  295. let mut result = Self::default();
  296. for r in 0..ROWS {
  297. for c in 0..COLUMNS {
  298. result.data[r][c] = -self.data[r][c];
  299. }
  300. }
  301. result
  302. }
  303. }
  304. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Add for GenericMatrix<T, ROWS, COLUMNS> {
  305. type Output = Self;
  306. fn add(mut self, rhs: Self) -> Self::Output {
  307. self += rhs;
  308. self
  309. }
  310. }
  311. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> AddAssign for GenericMatrix<T, ROWS, COLUMNS> {
  312. fn add_assign(&mut self, rhs: Self) {
  313. for r in 0..ROWS {
  314. for c in 0..COLUMNS {
  315. self.data[r][c] += rhs.data[r][c];
  316. }
  317. }
  318. }
  319. }
  320. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Sub for GenericMatrix<T, ROWS, COLUMNS> {
  321. type Output = Self;
  322. fn sub(mut self, rhs: Self) -> Self::Output {
  323. self -= rhs;
  324. self
  325. }
  326. }
  327. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> SubAssign for GenericMatrix<T, ROWS, COLUMNS> {
  328. fn sub_assign(&mut self, rhs: Self) {
  329. for r in 0..ROWS {
  330. for c in 0..COLUMNS {
  331. self.data[r][c] -= rhs.data[r][c];
  332. }
  333. }
  334. }
  335. }
  336. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Mul<T> for GenericMatrix<T, ROWS, COLUMNS> {
  337. type Output = Self;
  338. fn mul(mut self, rhs: T) -> Self::Output {
  339. self *= rhs;
  340. self
  341. }
  342. }
  343. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> MulAssign<T> for GenericMatrix<T, ROWS, COLUMNS> {
  344. fn mul_assign(&mut self, rhs: T) {
  345. for r in 0..ROWS {
  346. for c in 0..COLUMNS {
  347. self.data[r][c] *= rhs;
  348. }
  349. }
  350. }
  351. }
  352. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> Div<T> for GenericMatrix<T, ROWS, COLUMNS> {
  353. type Output = Self;
  354. fn div(mut self, rhs: T) -> Self::Output {
  355. self /= rhs;
  356. self
  357. }
  358. }
  359. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize> DivAssign<T> for GenericMatrix<T, ROWS, COLUMNS> {
  360. fn div_assign(&mut self, rhs: T) {
  361. for r in 0..ROWS {
  362. for c in 0..COLUMNS {
  363. self.data[r][c] /= rhs;
  364. }
  365. }
  366. }
  367. }
  368. impl<T: Numeric + Float + PartialOrd, const DIMENSION: usize> Div<SquareMatrix<T, DIMENSION>> for ColumnVector<T, DIMENSION> {
  369. type Output = RowVector<T, DIMENSION>;
  370. fn div(self, rhs: SquareMatrix<T, DIMENSION>) -> Self::Output {
  371. rhs.solve(&self, T::value(1e-9)).unwrap()
  372. }
  373. }
  374. impl<T: Numeric, const ROWS: usize, const COMMON: usize, const COLUMNS: usize> Mul<GenericMatrix<T, COMMON, COLUMNS>> for GenericMatrix<T, ROWS, COMMON> {
  375. type Output = GenericMatrix<T, ROWS, COLUMNS>;
  376. fn mul(self, rhs: GenericMatrix<T, COMMON, COLUMNS>) -> Self::Output {
  377. let mut result = Self::Output::default();
  378. for i in 0..ROWS {
  379. for j in 0..COLUMNS {
  380. for k in 0..COMMON {
  381. result.data[i][j] += self.data[i][k] * rhs.data[k][j];
  382. }
  383. }
  384. }
  385. result
  386. }
  387. }
  388. /// Apply a transformation matrix to a column vector.
  389. impl<T: Numeric + Float + Primitive> Mul<ColumnVector<T, 3>> for SquareMatrix<T, 4> {
  390. type Output = RowVector<T, 3>;
  391. fn mul(self, rhs: ColumnVector<T, 3>) -> Self::Output {
  392. let x_old = rhs[(0, 0)];
  393. let y_old = rhs[(1, 0)];
  394. let z_old = rhs[(2, 0)];
  395. rvec![
  396. self[(0,0)] * x_old + self[(0, 1)] * y_old + self[(0, 2)] * z_old + self[(0, 3)],
  397. self[(1,0)] * x_old + self[(1, 1)] * y_old + self[(1, 2)] * z_old + self[(1, 3)],
  398. self[(2,0)] * x_old + self[(2, 1)] * y_old + self[(2, 2)] * z_old + self[(2, 3)],
  399. ]
  400. }
  401. }
  402. impl<T: Numeric + Float + Primitive> SquareMatrix<T, 4> {
  403. /// Create a 3D translation matrix.
  404. pub fn translation(x: T, y: T, z: T) -> Self {
  405. let mut result = SquareMatrix::identity();
  406. result[(0, 3)] = x;
  407. result[(1, 3)] = y;
  408. result[(2, 3)] = z;
  409. result
  410. }
  411. /// Create a 3D scale matrix.
  412. pub fn scale(x: T, y: T, z: T) -> Self {
  413. let one = T::whole(1);
  414. SquareMatrix::diagonal(&[x, y, z, one])
  415. }
  416. fn rotation_impl(angle: T, x: T, y: T, z: T) -> Self {
  417. let zero = T::whole(0);
  418. let one = T::whole(1);
  419. let c = angle.cos();
  420. let s = angle.sin();
  421. let omc = one - c;
  422. Self::from([
  423. [x * x * omc + c, x * y * omc - z * s, x * z * omc + y * s, zero],
  424. [y * x * omc + z * s, y * y * omc + c, y * z * omc - x * s, zero],
  425. [x * z * omc - y * s, y * z * omc + x * s, z * z * omc + c, zero],
  426. [zero, zero, zero, one],
  427. ])
  428. }
  429. /// Create a 3D rotation matrix.
  430. ///
  431. /// `angle` is expected to be in radians.
  432. #[cfg(not(feature = "angular"))]
  433. pub fn rotation(angle: T, x: T, y: T, z: T) -> Self {
  434. Self::rotation_impl(angle, x, y, z)
  435. }
  436. /// Create a 3D rotation matrix.
  437. #[cfg(feature = "angular")]
  438. pub fn rotation<A: Angular<T>>(angle: A, x: T, y: T, z: T) -> Self {
  439. Self::rotation_impl(angle.radiant(), x, y, z)
  440. }
  441. }
  442. impl<T: Numeric, const ROWS: usize, const COLUMNS: usize, RHS: Matrix<T, ROWS, COLUMNS>> PartialEq<RHS> for GenericMatrix<T, ROWS, COLUMNS> {
  443. fn eq(&self, other: &RHS) -> bool {
  444. matrices_are_equal(self, other, T::epsilon())
  445. }
  446. fn ne(&self, other: &RHS) -> bool {
  447. !matrices_are_equal(self, other, T::epsilon())
  448. }
  449. }
  450. #[cfg(test)]
  451. mod tests {
  452. use crate::{ColumnVector, Complex, cplx, GenericMatrix, Matrix, RowVector, SquareMatrix};
  453. #[test]
  454. fn identity_matrix() {
  455. let mat: SquareMatrix<f64, 3> = SquareMatrix::identity();
  456. let expected = SquareMatrix::from([
  457. [1.0, 0.0, 0.0],
  458. [0.0, 1.0, 0.0],
  459. [0.0, 0.0, 1.0],
  460. ]);
  461. assert_eq!(mat, expected);
  462. }
  463. #[test]
  464. fn diagonal_matrix() {
  465. let mat: SquareMatrix<f32, 3> = SquareMatrix::diagonal(&[1.0, 2.0, 3.0]);
  466. let expected = SquareMatrix {
  467. data: [[1.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 3.0]],
  468. };
  469. assert_eq!(mat, expected);
  470. }
  471. #[test]
  472. #[should_panic = "index out of bounds"]
  473. fn out_of_bounds_access() {
  474. let mat: SquareMatrix<f32, 1> = SquareMatrix::identity();
  475. mat[(1, 0)];
  476. }
  477. #[test]
  478. fn transposing_matrix() {
  479. let mat = GenericMatrix {
  480. data: [[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]],
  481. }.transposed();
  482. let expected = GenericMatrix {
  483. data: [[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]],
  484. };
  485. assert_eq!(mat, expected);
  486. }
  487. #[test]
  488. fn negating_matrix() {
  489. let mat = -GenericMatrix {
  490. data: [[1, -1], [2, -2]],
  491. };
  492. let expected = GenericMatrix {
  493. data: [[-1, 1], [-2, 2]],
  494. };
  495. assert_eq!(mat, expected);
  496. }
  497. #[test]
  498. fn dot_product_of_vectors() {
  499. let a = rvec![1, 3, -5];
  500. let b = cvec![4, -2, -1];
  501. let product = a * b;
  502. assert_eq!(product[(0, 0)], 3);
  503. }
  504. #[test]
  505. fn matrix_product_of_vectors() {
  506. let a = cvec![1, 3, -5];
  507. let b = rvec![4, -2, -1];
  508. let product = a * b;
  509. let expected = SquareMatrix {
  510. data: [
  511. [4, -2, -1],
  512. [12, -6, -3],
  513. [-20, 10, 5],
  514. ],
  515. };
  516. assert_eq!(product, expected);
  517. }
  518. #[test]
  519. fn complex_matrix_multiplication() {
  520. let a = SquareMatrix {
  521. data: [
  522. [cplx!(2.0, 1.0), cplx!(i = 5.0,)],
  523. [cplx!(3.0), cplx!(3.0, -4.0)],
  524. ],
  525. };
  526. let b = SquareMatrix {
  527. data: [
  528. [cplx!(1.0, -1.0), cplx!(4.0, 2.0)],
  529. [cplx!(1.0, -6.0), cplx!(3.0)],
  530. ],
  531. };
  532. let mat = a * b;
  533. let expected = SquareMatrix::from([
  534. [cplx!(33.0, 4.0), cplx!(6.0, 23.0)],
  535. [cplx!(-18.0, -25.0), cplx!(21.0, -6.0)],
  536. ]);
  537. assert_eq!(mat, expected);
  538. }
  539. #[test]
  540. fn invert_matrix() {
  541. let tolerance = 1e-9;
  542. let mat = SquareMatrix::from([
  543. [2.0, 1.0],
  544. [6.0, 4.0],
  545. ]);
  546. let inverted = mat.inverted(tolerance).unwrap();
  547. let expected = SquareMatrix::from([
  548. [2.0, -0.5],
  549. [-3.0, 1.0],
  550. ]);
  551. assert_eq!(inverted, expected);
  552. assert_eq!(inverted * mat, SquareMatrix::identity());
  553. }
  554. #[test]
  555. #[should_panic = "index out of bounds"]
  556. fn out_of_range_get() {
  557. let mat = SquareMatrix::from([[1]]);
  558. mat.get(1, 1);
  559. }
  560. #[test]
  561. #[should_panic = "index out of bounds"]
  562. fn out_of_range_set() {
  563. let mut mat = SquareMatrix::from([[1]]);
  564. mat.set(1, 1, 2);
  565. }
  566. }