Skip to main content

faer/mat/
mod.rs

1use crate::{Shape, Stride, Unbind};
2use core::marker::PhantomData;
3use core::ptr::NonNull;
4use faer_traits::{ComplexField, Conjugate};
5use reborrow::*;
6
7pub(crate) struct MatView<T: ?Sized, Rows, Cols, RStride, CStride> {
8	ptr: NonNull<T>,
9	nrows: Rows,
10	ncols: Cols,
11	row_stride: RStride,
12	col_stride: CStride,
13}
14/// represents a type that can be used to slice a matrix, such as an index or a
15/// range of indices
16pub trait MatIndex<RowRange, ColRange> {
17	/// sliced view type
18	type Target;
19	/// slice `this` using `row` and `col`
20	fn get(this: Self, row: RowRange, col: ColRange) -> Self::Target;
21	/// slice `this` using `row` and `col` without bound checks
22	unsafe fn get_unchecked(
23		this: Self,
24		row: RowRange,
25		col: ColRange,
26	) -> Self::Target;
27}
28impl<T: ?Sized, Rows: Copy, Cols: Copy, RStride: Copy, CStride: Copy> Copy
29	for MatView<T, Rows, Cols, RStride, CStride>
30{
31}
32impl<T: ?Sized, Rows: Copy, Cols: Copy, RStride: Copy, CStride: Copy> Clone
33	for MatView<T, Rows, Cols, RStride, CStride>
34{
35	#[inline]
36	fn clone(&self) -> Self {
37		*self
38	}
39}
40#[inline]
41#[track_caller]
42fn from_slice_assert(nrows: usize, ncols: usize, len: usize) {
43	let size = usize::checked_mul(nrows, ncols);
44	assert!(size == Some(len));
45}
46mod mat_index;
47pub(crate) mod matmut;
48pub(crate) mod matown;
49pub(crate) mod matref;
50pub use matmut::Mut;
51pub use matown::Own;
52pub use matref::Ref;
53/// heap allocated resizable matrix, similar to a 2d [`alloc::vec::Vec`]
54///
55/// # note
56///
57/// the memory layout of `Own` is guaranteed to be column-major, meaning that it
58/// has a row stride of `1`, and an unspecified column stride that can be
59/// queried with [`Mat::col_stride`]
60///
61/// this implies that while each individual column is stored contiguously in
62/// memory, the matrix as a whole may not necessarily be contiguous. the
63/// implementation may add padding at the end of each column when overaligning
64/// each column can provide a performance gain
65///
66/// let us consider a 3×4 matrix
67///
68/// ```notcode
69///  0 │ 3 │ 6 │  9
70/// ───┼───┼───┼───
71///  1 │ 4 │ 7 │ 10
72/// ───┼───┼───┼───
73///  2 │ 5 │ 8 │ 11
74/// ```
75/// the memory representation of the data held by such a matrix could look like
76/// the following:
77///
78/// ```notcode
79/// [0, 1, 2, x, 3, 4, 5, x, 6, 7, 8, x, 9, 10, 11, x]
80/// ```
81///
82/// where `x` represents padding elements
83pub type Mat<T, Rows = usize, Cols = usize> = generic::Mat<Own<T, Rows, Cols>>;
84
85/// immutable view over a matrix, similar to an immutable reference to a 2d
86/// strided [prim@slice]
87///
88/// # Note
89///
90/// unlike a slice, the data pointed to by `MatRef<'_, T>` is allowed to be
91/// partially or fully uninitialized under certain conditions. in this case,
92/// care must be taken to not perform any operations that read the uninitialized
93/// values, either directly or indirectly through any of the numerical library
94/// routines, unless it is explicitly permitted
95pub type MatRef<
96	'a,
97	T,
98	Rows = usize,
99	Cols = usize,
100	RStride = isize,
101	CStride = isize,
102> = generic::Mat<Ref<'a, T, Rows, Cols, RStride, CStride>>;
103/// mutable view over a matrix, similar to a mutable reference to a 2d strided
104/// [prim@slice]
105///
106/// # note
107///
108/// unlike a slice, the data pointed to by `MatMut<'_, T>` is allowed to be
109/// partially or fully uninitialized under certain conditions. In this case,
110/// care must be taken to not perform any operations that read the uninitialized
111/// values, either directly or indirectly through any of the numerical library
112/// routines, unless it is explicitly permitted
113///
114/// # move semantics
115/// since `MatMut` mutably borrows data, it cannot be [`Copy`]. this means that
116/// if we pass a `MatMut` to a function that takes it by value, or use a method
117/// that consumes `self` like [`MatMut::transpose_mut`], this renders the
118/// original variable unusable
119///
120/// ```compile_fail
121/// use faer::{Mat, MatMut};
122///
123/// fn takes_matmut(view: MatMut<'_, f64>) {}
124///
125/// let mut matrix = Mat::new();
126/// let view = matrix.as_mut();
127///
128/// takes_matmut(view); // `view` is moved (passed by value)
129/// takes_matmut(view); // this fails to compile since `view` was moved
130/// ```
131/// the way to get around it is to use the [`reborrow::ReborrowMut`] trait,
132/// which allows us to mutably borrow a `MatMut` to obtain another `MatMut` for
133/// the lifetime of the borrow. it's also similarly possible to immutably borrow
134/// a `MatMut` to obtain a `MatRef` for the lifetime of the borrow, using
135/// [`reborrow::Reborrow`] ```
136/// use faer::{Mat, MatMut, MatRef};
137/// use reborrow::*;
138/// fn takes_matmut(view: MatMut<'_, f64>) {}
139/// fn takes_matref(view: MatRef<'_, f64>) {}
140/// let mut matrix = Mat::new();
141/// let mut view = matrix.as_mut();
142/// takes_matmut(view.rb_mut());
143/// takes_matmut(view.rb_mut());
144/// takes_matref(view.rb());
145/// // view is still usable here
146/// ```
147pub type MatMut<
148	'a,
149	T,
150	Rows = usize,
151	Cols = usize,
152	RStride = isize,
153	CStride = isize,
154> = generic::Mat<Mut<'a, T, Rows, Cols, RStride, CStride>>;
155
156#[doc(hidden)]
157/// generic `Mat` wrapper
158pub mod generic {
159	use crate::{Idx, Shape, Stride};
160	use core::fmt::Debug;
161	use core::ops::{Index, IndexMut};
162	use reborrow::*;
163
164	/// generic `Mat` wrapper
165	#[derive(Copy, Clone)]
166	#[repr(transparent)]
167	pub struct Mat<Inner>(pub Inner);
168
169	impl<Inner: Debug> Debug for Mat<Inner> {
170		#[inline(always)]
171		fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
172			self.0.fmt(f)
173		}
174	}
175	impl<Inner> Mat<Inner> {
176		/// wrap by reference
177		#[inline(always)]
178		pub fn from_inner_ref(inner: &Inner) -> &Self {
179			unsafe { &*(inner as *const Inner as *const Self) }
180		}
181
182		/// wrap by mutable reference
183		#[inline(always)]
184		pub fn from_inner_mut(inner: &mut Inner) -> &mut Self {
185			unsafe { &mut *(inner as *mut Inner as *mut Self) }
186		}
187	}
188	impl<Inner> core::ops::Deref for Mat<Inner> {
189		type Target = Inner;
190
191		#[inline(always)]
192		fn deref(&self) -> &Self::Target {
193			&self.0
194		}
195	}
196	impl<Inner> core::ops::DerefMut for Mat<Inner> {
197		#[inline(always)]
198		fn deref_mut(&mut self) -> &mut Self::Target {
199			&mut self.0
200		}
201	}
202	impl<'short, Inner: Reborrow<'short>> Reborrow<'short> for Mat<Inner> {
203		type Target = Mat<Inner::Target>;
204
205		#[inline(always)]
206		fn rb(&'short self) -> Self::Target {
207			Mat(self.0.rb())
208		}
209	}
210	impl<'short, Inner: ReborrowMut<'short>> ReborrowMut<'short> for Mat<Inner> {
211		type Target = Mat<Inner::Target>;
212
213		#[inline(always)]
214		fn rb_mut(&'short mut self) -> Self::Target {
215			Mat(self.0.rb_mut())
216		}
217	}
218	impl<Inner: IntoConst> IntoConst for Mat<Inner> {
219		type Target = Mat<Inner::Target>;
220
221		#[inline(always)]
222		fn into_const(self) -> Self::Target {
223			Mat(self.0.into_const())
224		}
225	}
226	impl<
227		T,
228		Rows: Shape,
229		Cols: Shape,
230		RStride: Stride,
231		CStride: Stride,
232		Inner: for<'short> Reborrow<
233				'short,
234				Target = super::Ref<'short, T, Rows, Cols, RStride, CStride>,
235			>,
236	> Index<(Idx<Rows>, Idx<Cols>)> for Mat<Inner>
237	{
238		type Output = T;
239
240		#[inline]
241		#[track_caller]
242		fn index(&self, (row, col): (Idx<Rows>, Idx<Cols>)) -> &Self::Output {
243			self.rb().at(row, col)
244		}
245	}
246	impl<
247		T,
248		Rows: Shape,
249		Cols: Shape,
250		RStride: Stride,
251		CStride: Stride,
252		Inner: for<'short> Reborrow<
253				'short,
254				Target = super::Ref<'short, T, Rows, Cols, RStride, CStride>,
255			> + for<'short> ReborrowMut<
256				'short,
257				Target = super::Mut<'short, T, Rows, Cols, RStride, CStride>,
258			>,
259	> IndexMut<(Idx<Rows>, Idx<Cols>)> for Mat<Inner>
260	{
261		#[inline]
262		#[track_caller]
263		fn index_mut(
264			&mut self,
265			(row, col): (Idx<Rows>, Idx<Cols>),
266		) -> &mut Self::Output {
267			self.rb_mut().at_mut(row, col)
268		}
269	}
270}
271/// trait for types that can be converted to a matrix view
272pub trait AsMatRef {
273	/// scalar type
274	type T;
275	/// row dimension type
276	type Rows: Shape;
277	/// column dimension type
278	type Cols: Shape;
279	/// owned matrix type
280	type Owned: AsMat<
281			Self::T,
282			T = Self::T,
283			Rows = Self::Rows,
284			Cols = Self::Cols,
285			Owned = Self::Owned,
286		>;
287	/// returns a view over `self`
288	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols>;
289}
290/// trait for types that can be converted to a matrix view
291pub trait AsMatMut: AsMatRef {
292	/// returns a view over `self`
293	fn as_mat_mut(&mut self) -> MatMut<'_, Self::T, Self::Rows, Self::Cols>;
294}
295/// trait for owning matrix types
296pub trait AsMat<T>: AsMatMut {
297	/// returns a matrix with dimensions `(rows, cols)` filled with zeros
298	fn zeros(rows: Self::Rows, cols: Self::Cols) -> Self
299	where
300		T: ComplexField;
301	/// returns a matrix with dimensions `(rows, cols)` filled with zeros
302	fn truncate(&mut self, rows: Self::Rows, cols: Self::Cols);
303}
304impl<M: AsMatRef> AsMatRef for &M {
305	type Cols = M::Cols;
306	type Owned = M::Owned;
307	type Rows = M::Rows;
308	type T = M::T;
309
310	#[inline]
311	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols> {
312		(**self).as_mat_ref()
313	}
314}
315impl<M: AsMatRef> AsMatRef for &mut M {
316	type Cols = M::Cols;
317	type Owned = M::Owned;
318	type Rows = M::Rows;
319	type T = M::T;
320
321	#[inline]
322	fn as_mat_ref(&self) -> MatRef<'_, Self::T, Self::Rows, Self::Cols> {
323		(**self).as_mat_ref()
324	}
325}
326impl<M: AsMatMut> AsMatMut for &mut M {
327	#[inline]
328	fn as_mat_mut(&mut self) -> MatMut<'_, Self::T, Self::Rows, Self::Cols> {
329		(**self).as_mat_mut()
330	}
331}
332impl<T, Rows: Shape, Cols: Shape, RStride: Stride, CStride: Stride> AsMatRef
333	for MatRef<'_, T, Rows, Cols, RStride, CStride>
334{
335	type Cols = Cols;
336	type Owned = Mat<T, Rows, Cols>;
337	type Rows = Rows;
338	type T = T;
339
340	#[inline]
341	fn as_mat_ref(&self) -> MatRef<'_, T, Rows, Cols> {
342		self.as_dyn_stride()
343	}
344}
345impl<T, Rows: Shape, Cols: Shape, RStride: Stride, CStride: Stride> AsMatRef
346	for MatMut<'_, T, Rows, Cols, RStride, CStride>
347{
348	type Cols = Cols;
349	type Owned = Mat<T, Rows, Cols>;
350	type Rows = Rows;
351	type T = T;
352
353	#[inline]
354	fn as_mat_ref(&self) -> MatRef<'_, T, Rows, Cols> {
355		self.rb().as_dyn_stride()
356	}
357}
358impl<T, Rows: Shape, Cols: Shape, RStride: Stride, CStride: Stride> AsMatMut
359	for MatMut<'_, T, Rows, Cols, RStride, CStride>
360{
361	#[inline]
362	fn as_mat_mut(&mut self) -> MatMut<'_, T, Rows, Cols> {
363		self.rb_mut().as_dyn_stride_mut()
364	}
365}
366impl<T, Rows: Shape, Cols: Shape> AsMatRef for Mat<T, Rows, Cols> {
367	type Cols = Cols;
368	type Owned = Mat<T, Rows, Cols>;
369	type Rows = Rows;
370	type T = T;
371
372	#[inline]
373	fn as_mat_ref(&self) -> MatRef<'_, T, Rows, Cols> {
374		self.as_dyn_stride()
375	}
376}
377impl<T, Rows: Shape, Cols: Shape> AsMat<T> for Mat<T, Rows, Cols> {
378	#[inline]
379	fn zeros(rows: Rows, cols: Cols) -> Self
380	where
381		T: ComplexField,
382	{
383		Mat::zeros(rows, cols)
384	}
385
386	#[track_caller]
387	#[inline]
388	fn truncate(&mut self, rows: Self::Rows, cols: Self::Cols) {
389		self.truncate(rows, cols)
390	}
391}
392impl<T, Rows: Shape, Cols: Shape> AsMatMut for Mat<T, Rows, Cols> {
393	#[inline]
394	fn as_mat_mut(&mut self) -> MatMut<'_, T, Rows, Cols> {
395		self.as_dyn_stride_mut()
396	}
397}
398#[cfg(test)]
399mod tests {
400	use super::*;
401	use crate::prelude::*;
402	#[test]
403	fn test_mat() {
404		let _x = crate::mat![[0.0, 1.0]];
405		let mat = Mat::from_fn(3, 4, |i, j| i as f64 + j as f64);
406		let mat = mat.as_ref().cloned();
407		let mat = mat.as_ref();
408		for i in 0..3 {
409			for j in 0..4 {
410				zip!(&mat).map(|x| x).as_ref().at(i, j);
411			}
412		}
413	}
414	#[test]
415	fn test_mat_complex() {
416		let _x = mat![[c64::new(0.0, 0.0), c64::new(1.0, 0.0)]];
417		let mat = Mat::from_fn(3, 4, |i, j| c64::new(i as f64 + j as f64, 0.0));
418		{
419			let _conj = mat.as_ref().conjugate();
420		}
421		let mat = mat.as_ref().cloned();
422		let mat = mat.as_ref();
423		for i in 0..3 {
424			for j in 0..4 {
425				zip!(&mat).map(|x| x).as_ref().at(i, j);
426			}
427		}
428	}
429}