1mod basic;
6mod blas;
7mod cholesky;
8mod eigen;
9mod element;
10mod exact;
11mod functions;
12mod gemm;
13mod hermitian;
14mod householder;
15mod lu;
16mod ops;
17mod properties;
18mod qr;
19mod schur;
20mod svd;
21mod tridiagonal;
22
23pub use cholesky::Cholesky;
24pub use eigen::{Eigen, HermitianEigen};
25pub use element::{Element, Scalar};
26pub use lu::Lu;
27pub use properties::Norm;
28pub use qr::Qr;
29pub use schur::Schur;
30pub use svd::Svd;
31
32use core::fmt;
33use core::ops::{Index, IndexMut};
34
35#[derive(Clone, PartialEq, Eq, Hash, Default)]
49pub struct Matrix<T> {
50 rows: usize,
52 cols: usize,
54 data: Vec<T>,
56}
57
58#[track_caller]
65fn size(rows: usize, cols: usize) -> usize {
66 rows.checked_mul(cols)
67 .expect("the matrix has more elements than a vector can hold")
68}
69
70impl<T> Matrix<T> {
71 #[track_caller]
77 pub fn from_column_major(rows: usize, cols: usize, data: Vec<T>) -> Self {
78 assert_eq!(
79 Some(data.len()),
80 rows.checked_mul(cols),
81 "the data doesn't hold rows × cols elements"
82 );
83 Matrix { rows, cols, data }
84 }
85
86 #[track_caller]
92 pub fn from_row_major(rows: usize, cols: usize, data: Vec<T>) -> Self {
93 Matrix::from_column_major(cols, rows, data).into_transpose()
94 }
95
96 #[track_caller]
103 pub fn from_fn(rows: usize, cols: usize, mut f: impl FnMut(usize, usize) -> T) -> Self {
104 let mut data = Vec::with_capacity(size(rows, cols));
105 for j in 0..cols {
106 data.extend((0..rows).map(|i| f(i, j)));
109 }
110 Matrix { rows, cols, data }
111 }
112
113 #[inline]
115 pub fn rows(&self) -> usize {
116 self.rows
117 }
118
119 #[inline]
121 pub fn cols(&self) -> usize {
122 self.cols
123 }
124
125 #[inline]
127 pub fn shape(&self) -> (usize, usize) {
128 (self.rows, self.cols)
129 }
130
131 #[inline]
133 pub fn is_square(&self) -> bool {
134 self.rows == self.cols
135 }
136
137 #[inline]
139 pub fn is_empty(&self) -> bool {
140 self.data.is_empty()
141 }
142
143 #[inline]
145 pub fn get(&self, i: usize, j: usize) -> Option<&T> {
146 if i < self.rows && j < self.cols {
147 Some(&self.data[i + j * self.rows])
148 } else {
149 None
150 }
151 }
152
153 #[inline]
155 pub fn get_mut(&mut self, i: usize, j: usize) -> Option<&mut T> {
156 if i < self.rows && j < self.cols {
157 Some(&mut self.data[i + j * self.rows])
158 } else {
159 None
160 }
161 }
162
163 #[inline]
169 #[track_caller]
170 pub fn column(&self, j: usize) -> &[T] {
171 assert!(j < self.cols, "the column is outside the matrix");
172 &self.data[j * self.rows..(j + 1) * self.rows]
173 }
174
175 #[inline]
181 #[track_caller]
182 pub fn column_mut(&mut self, j: usize) -> &mut [T] {
183 assert!(j < self.cols, "the column is outside the matrix");
184 &mut self.data[j * self.rows..(j + 1) * self.rows]
185 }
186
187 #[track_caller]
193 pub fn row(&self, i: usize) -> impl ExactSizeIterator<Item = &T> + '_ {
194 assert!(i < self.rows, "the row is outside the matrix");
195 (0..self.cols).map(move |j| &self.data[i + j * self.rows])
196 }
197
198 #[inline]
200 pub fn as_slice(&self) -> &[T] {
201 &self.data
202 }
203
204 #[inline]
206 pub fn as_mut_slice(&mut self) -> &mut [T] {
207 &mut self.data
208 }
209
210 #[inline]
212 pub fn into_vec(self) -> Vec<T> {
213 self.data
214 }
215
216 pub fn map<U>(&self, f: impl FnMut(&T) -> U) -> Matrix<U> {
218 Matrix {
219 rows: self.rows,
220 cols: self.cols,
221 data: self.data.iter().map(f).collect(),
222 }
223 }
224
225 fn into_transpose(self) -> Self {
227 let (rows, cols) = (self.rows, self.cols);
228 if rows <= 1 || cols <= 1 {
229 return Matrix {
230 rows: cols,
231 cols: rows,
232 data: self.data,
233 };
234 }
235 let mut slots: Vec<Option<T>> = self.data.into_iter().map(Some).collect();
236 Matrix::from_fn(cols, rows, |i, j| slots[j + i * rows].take().unwrap())
237 }
238}
239
240impl<T: Clone> Matrix<T> {
241 #[track_caller]
247 pub fn from_rows<R: AsRef<[T]>>(rows: &[R]) -> Self {
248 let cols = rows.first().map_or(0, |r| r.as_ref().len());
249 assert!(
250 rows.iter().all(|r| r.as_ref().len() == cols),
251 "the rows are not all of the same length"
252 );
253 Matrix::from_fn(rows.len(), cols, |i, j| rows[i].as_ref()[j].clone())
254 }
255
256 #[track_caller]
262 pub fn from_columns<C: AsRef<[T]>>(columns: &[C]) -> Self {
263 let rows = columns.first().map_or(0, |c| c.as_ref().len());
264 assert!(
265 columns.iter().all(|c| c.as_ref().len() == rows),
266 "the columns are not all of the same length"
267 );
268 let data = columns
269 .iter()
270 .flat_map(|c| c.as_ref().iter().cloned())
271 .collect();
272 Matrix {
273 rows,
274 cols: columns.len(),
275 data,
276 }
277 }
278
279 pub fn diagonal(&self) -> Vec<T> {
281 (0..self.rows.min(self.cols))
282 .map(|i| self.data[i + i * self.rows].clone())
283 .collect()
284 }
285}
286
287impl<T: Element> Matrix<T> {
288 #[track_caller]
294 pub fn zeros(rows: usize, cols: usize) -> Self {
295 Matrix {
298 rows,
299 cols,
300 data: vec![T::zero(); size(rows, cols)],
301 }
302 }
303
304 pub fn identity(n: usize) -> Self {
306 Matrix::from_diagonal(&vec![T::one(); n])
307 }
308
309 pub fn from_diagonal(diagonal: &[T]) -> Self {
311 let n = diagonal.len();
312 let mut a = Matrix::zeros(n, n);
313 for (i, d) in diagonal.iter().enumerate() {
314 a.data[i + i * n] = d.clone();
315 }
316 a
317 }
318}
319
320impl<T> Index<(usize, usize)> for Matrix<T> {
321 type Output = T;
322
323 #[inline]
329 #[track_caller]
330 fn index(&self, (i, j): (usize, usize)) -> &T {
331 assert!(
332 i < self.rows && j < self.cols,
333 "the index is outside the matrix"
334 );
335 &self.data[i + j * self.rows]
336 }
337}
338
339impl<T> IndexMut<(usize, usize)> for Matrix<T> {
340 #[inline]
346 #[track_caller]
347 fn index_mut(&mut self, (i, j): (usize, usize)) -> &mut T {
348 assert!(
349 i < self.rows && j < self.cols,
350 "the index is outside the matrix"
351 );
352 &mut self.data[i + j * self.rows]
353 }
354}
355
356impl<T: fmt::Display> fmt::Display for Matrix<T> {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 let text: Vec<String> = self
361 .data
362 .iter()
363 .map(|x| match f.precision() {
364 Some(p) => format!("{x:.p$}"),
365 None => format!("{x}"),
366 })
367 .collect();
368 let widths: Vec<usize> = (0..self.cols)
369 .map(|j| {
370 let column = &text[j * self.rows..(j + 1) * self.rows];
371 column.iter().map(|s| s.chars().count()).max().unwrap_or(0)
372 })
373 .collect();
374 for i in 0..self.rows {
375 if i > 0 {
376 writeln!(f)?;
377 }
378 for (j, width) in widths.iter().enumerate() {
379 let gap = if j == 0 { "" } else { " " };
380 write!(f, "{gap}{:>width$}", text[i + j * self.rows])?;
381 }
382 }
383 Ok(())
384 }
385}
386
387impl<T: fmt::Debug> fmt::Debug for Matrix<T> {
388 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390 f.debug_list()
391 .entries((0..self.rows).map(|i| DebugRow(self, i)))
392 .finish()
393 }
394}
395
396struct DebugRow<'a, T>(&'a Matrix<T>, usize);
398
399impl<T: fmt::Debug> fmt::Debug for DebugRow<'_, T> {
400 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401 f.debug_list().entries(self.0.row(self.1)).finish()
402 }
403}