Skip to main content

faer/
lib.rs

1//! `faer` is a general-purpose linear algebra library for rust, with a focus on
2//! high performance for algebraic operations on medium/large matrices, as well
3//! as matrix decompositions
4//!
5//! most of the high-level functionality in this library is provided through
6//! associated functions in its vocabulary types: [`Mat`]/[`MatRef`]/[`MatMut`]
7//!
8//! `faer` is recommended for applications that handle medium to large dense
9//! matrices, and its design is not well suited for applications that operate
10//! mostly on low dimensional vectors and matrices such as computer graphics or
11//! game development. for such applications, `nalgebra` and `cgmath` may be
12//! better suited
13//!
14//! # basic usage
15//!
16//! [`Mat`] is a resizable matrix type with dynamic capacity, which can be
17//! created using [`Mat::new`] to produce an empty $0\times 0$ matrix,
18//! [`Mat::zeros`] to create a rectangular matrix filled with zeros,
19//! [`Mat::identity`] to create an identity matrix, or [`Mat::from_fn`]
20//! for the more general case
21//!
22//! Given a `&Mat<T>` (resp. `&mut Mat<T>`), a [`MatRef<'_, T>`](MatRef) (resp.
23//! [`MatMut<'_, T>`](MatMut)) can be created by calling [`Mat::as_ref`] (resp.
24//! [`Mat::as_mut`]), which allow for more flexibility than `Mat` in that they
25//! allow slicing ([`MatRef::get`]) and splitting ([`MatRef::split_at`])
26//!
27//! `MatRef` and `MatMut` are lightweight view objects. the former can be copied
28//! freely while the latter has move and reborrow semantics, as described in its
29//! documentation
30//!
31//! most of the matrix operations can be used through the corresponding math
32//! operators: `+` for matrix addition, `-` for subtraction, `*` for either
33//! scalar or matrix multiplication depending on the types of the operands.
34//!
35//! ## example
36//! ```
37//! use faer::{Mat, Scale, mat};
38//! let a = mat![
39//! 	[1.0, 5.0, 9.0], //
40//! 	[2.0, 6.0, 10.0],
41//! 	[3.0, 7.0, 11.0],
42//! 	[4.0, 8.0, 12.0f64],
43//! ];
44//! let b = Mat::from_fn(4, 3, |i, j| (i + j) as f64);
45//! let add = &a + &b;
46//! let sub = &a - &b;
47//! let scale = Scale(3.0) * &a;
48//! let mul = &a * b.transpose();
49//! let a00 = a[(0, 0)];
50//! ```
51//!
52//! # matrix decompositions
53//! `faer` provides a variety of matrix factorizations, each with its own
54//! advantages and drawbacks:
55//!
56//! ## $LL^\top$ decomposition
57//! [`Mat::llt`] decomposes a self-adjoint positive definite matrix $A$ such
58//! that $$A = LL^H,$$
59//! where $L$ is a lower triangular matrix. this decomposition is highly
60//! efficient and has good stability properties
61//!
62//! [an implementation for sparse matrices is also
63//! available](sparse::linalg::solvers::Llt)
64//!
65//! ## $LBL^\top$ decomposition
66//! [`Mat::lblt`] decomposes a self-adjoint (possibly indefinite) matrix $A$
67//! such that $$P A P^\top = LBL^H,$$
68//! where $P$ is a permutation matrix, $L$ is a lower triangular matrix, and $B$
69//! is a block diagonal matrix, with $1 \times 1$ or $2 \times 2$ diagonal
70//! blocks. this decomposition is efficient and has good stability properties
71//!
72//! ## $LU$ decomposition with partial pivoting
73//! [`Mat::partial_piv_lu`] decomposes a square invertible matrix $A$ into a
74//! lower triangular matrix $L$, a unit upper triangular matrix $U$, and a
75//! permutation matrix $P$, such that $$PA = LU$$
76//! it is used by default for computing the determinant, and is generally the
77//! recommended method for solving a square linear system or computing the
78//! inverse of a matrix (although we generally recommend using a
79//! [`faer::linalg::solvers::Solve`](crate::linalg::solvers::Solve) instead of
80//! computing the inverse explicitly)
81//!
82//! [an implementation for sparse matrices is also
83//! available](sparse::linalg::solvers::Lu)
84//!
85//! ## $LU$ decomposition with full pivoting
86//! [`Mat::full_piv_lu`] decomposes a generic rectangular matrix $A$ into a
87//! lower triangular matrix $L$, a unit upper triangular matrix $U$, and
88//! permutation matrices $P$ and $Q$, such that $$PAQ^\top = LU$$
89//! it can be more stable than the LU decomposition with partial pivoting, in
90//! exchange for being more computationally expensive
91//!
92//! ## $QR$ decomposition
93//! [`Mat::qr`] decomposes a matrix $A$ into the product $$A = QR,$$
94//! where $Q$ is a unitary matrix, and $R$ is an upper trapezoidal matrix. it is
95//! often used for solving least squares problems
96//!
97//! [an implementation for sparse matrices is also
98//! available](sparse::linalg::solvers::Qr)
99//!
100//! ## $QR$ decomposition with column pivoting
101//! ([`Mat::col_piv_qr`]) decomposes a matrix $A$ into the product $$AP^\top =
102//! QR,$$ where $P$ is a permutation matrix, $Q$ is a unitary matrix, and $R$ is
103//! an upper trapezoidal matrix
104//!
105//! it is slower than the version with no pivoting, in exchange for being more
106//! numerically stable for rank-deficient matrices
107//!
108//! ## singular value decomposition
109//! the SVD of a matrix $A$ of shape $(m, n)$ is a decomposition into three
110//! components $U$, $S$, and $V$, such that:
111//!
112//! - $U$ has shape $(m, m)$ and is a unitary matrix,
113//! - $V$ has shape $(n, n)$ and is a unitary matrix,
114//! - $S$ has shape $(m, n)$ and is zero everywhere except the main diagonal,
115//!   with nonnegative
116//! diagonal values in nonincreasing order,
117//! - and finally:
118//!
119//! $$A = U S V^H$$
120//!
121//! the SVD is provided in two forms: either the full matrices $U$ and $V$ are
122//! computed, using [`Mat::svd`], or only their first $\min(m, n)$ columns are
123//! computed, using [`Mat::thin_svd`]
124//!
125//! if only the singular values (elements of $S$) are desired, they can be
126//! obtained in nonincreasing order using [`Mat::singular_values`]
127//!
128//! ## eigendecomposition
129//! **note**: the order of the eigenvalues is currently unspecified and may be
130//! changed in a future release
131//!
132//! the eigenvalue decomposition of a square matrix $A$ of shape $(n, n)$ is a
133//! decomposition into two components $U$, $S$:
134//!
135//! - $U$ has shape $(n, n)$ and is invertible,
136//! - $S$ has shape $(n, n)$ and is a diagonal matrix,
137//! - and finally:
138//!
139//! $$A = U S U^{-1}$$
140//!
141//! if $A$ is self-adjoint, then $U$ can be made unitary ($U^{-1} = U^H$), and
142//! $S$ is real valued. additionally, the eigenvalues are sorted in
143//! nondecreasing order
144//!
145//! Depending on the domain of the input matrix and whether it is self-adjoint,
146//! multiple methods are provided to compute the eigendecomposition:
147//! * [`Mat::self_adjoint_eigen`] can be used with either real or complex
148//!   matrices,
149//! producing an eigendecomposition of the same type,
150//! * [`Mat::eigen`] can be used with real or complex matrices, but always
151//!   produces complex values.
152//!
153//! if only the eigenvalues (elements of $S$) are desired, they can be obtained
154//! using [`Mat::self_adjoint_eigenvalues`] (nondecreasing order),
155//! [`Mat::eigenvalues`] with the same conditions described above.
156//!
157//! # parallelism
158//! there is no process wide parallelism setting and no global threadpool. Every function that can
159//! run in parallel takes a [`Par`] argument, the high level ones included ([`Mat::svd`],
160//! [`Mat::llt`], [`Mat::singular_values`], the `solve` family of
161//! [`linalg::solvers::Solve`], ...). Pass [`Par::Seq`] for sequential execution, or own a team for
162//! the calls that should use one:
163//!
164//! ```
165//! use faer::{Accum, Mat};
166//! let a = Mat::<f64>::from_fn(16, 16, |i, j| (i == j) as u8 as f64 + 0.5);
167//! let mut dst = Mat::<f64>::zeros(16, 16);
168//! faer::team::with_team(4, |par| {
169//!     faer::linalg::matmul::matmul(
170//!         dst.as_mut(),
171//!         Accum::Replace,
172//!         a.as_ref(),
173//!         a.as_ref(),
174//!         1.0,
175//!         par,
176//!     );
177//! });
178//! ```
179//!
180//! The operator overloads (`&a * &b`, `&a + &b`, ...) have no room for the argument and always run
181//! sequentially; use [`linalg::matmul::matmul`] for a parallel product.
182//!
183//! with the `threadteam` feature (on by default) a team is a reservation the caller owns: its members spin while the reservation is held,
184//! instead of being woken for every region, and the token hands each region the authority to
185//! place work on them. That is what makes a sequence of short regions cheap: the
186//! bidiagonalization behind the SVD issues two vector products per step, and at `n = 512` on
187//! eight threads it costs 25.5 ms with the members woken per region and 19.2 ms with the team
188//! held (`docs/worklogs/2026-10-23-blocked-bidiag.md`), which is where the values-only SVD
189//! reaches the vendor's time. `with_team` takes the reservation once, so a caller with a thread
190//! budget wraps its work rather than handing a number to every call:
191//!
192//! ```
193//! use faer::dyn_stack::{MemBuffer, MemStack};
194//! use faer::{Mat, Par};
195//! let a = Mat::<f64>::from_fn(64, 64, |i, j| ((i * 7 + j * 13) % 11) as f64 + 0.5);
196//! let mut s = Mat::<f64>::zeros(64, 1);
197//! let mut mem = MemBuffer::new(faer::linalg::svd::svd_scratch::<f64>(
198//!     64,
199//!     64,
200//!     faer::linalg::svd::ComputeSvdVectors::No,
201//!     faer::linalg::svd::ComputeSvdVectors::No,
202//!     faer::ParShape::team(4),
203//!     Default::default(),
204//! ));
205//! faer::team::with_team(4, |par| {
206//!     // every faer call in here with `par` runs its regions on 4 participants: the calling
207//!     // thread and 3 reserved workers
208//!     faer::linalg::svd::svd(
209//!         a.as_ref(),
210//!         s.as_mut().col_mut(0).as_diagonal_mut(),
211//!         None,
212//!         None,
213//!         par,
214//!         MemStack::new(&mut mem),
215//!         Default::default(),
216//!     )
217//!     .unwrap();
218//! });
219//! ```
220//!
221//! the members busy-wait for a bounded time between regions, then sleep; the width is the one the
222//! caller asked `with_team` for, and there is no process-wide setting to override it.
223//!
224//! `with_team` is for a one-off call: each call builds a new pool and acquires its members again;
225//! the threads themselves come from threadteam's cache of idle pools, so repeated calls at one
226//! width reuse running threads. Code that runs parallel work repeatedly should build a
227//! [`threadteam::Pool`] and [`threadteam::Team`] once and lend a `Par` from the team to each call
228//! (see the example on [`team::with_team`]).
229//!
230//! # crate features
231//!
232//! - `std`: enabled by default. links with the standard library to enable
233//!   additional features such as cpu feature detection at runtime
234//! - `rayon`: enabled by default. selects the `rayon` backend of the `gemm` dependency; the
235//!   parallel route itself (`Par::Team`, `team::with_team`) always uses `rayon`'s iterator
236//!   plumbing, so the dependency is not optional
237//! - `threadteam`: enabled by default. the name the consumers pass; it pulls in `rayon`
238//! - `npy`: enables conversions to/from numpy's matrix file format
239//! - `perf-warn`: produces performance warnings when matrix operations are
240//!   called with suboptimal
241//! data layout
242//! - `nightly`: requires the nightly compiler. enables experimental simd
243//!   features such as avx512
244#![cfg_attr(not(feature = "std"), no_std)]
245#![allow(non_snake_case)]
246#![warn(rustdoc::broken_intra_doc_links)]
247extern crate alloc;
248#[cfg(feature = "std")]
249extern crate std;
250/// see: [`generativity::make_guard`]
251#[macro_export]
252macro_rules! make_guard {
253    ($($name:ident),* $(,)?) => {
254        $(#[allow(unused_unsafe)] let $name = unsafe { $crate::generativity::Id::new() };
255        #[allow(unused, unused_unsafe)] let lifetime_brand = unsafe {
256        $crate::generativity::LifetimeBrand::new(&$name) }; #[allow(unused_unsafe)] let
257        $name = unsafe { $crate::generativity::Guard::new($name) };)*
258    };
259}
260macro_rules! repeat_n {
261	($e:expr, $n:expr) => {
262		iter::repeat_n($e, $n)
263	};
264}
265use core::num::NonZeroUsize;
266use equator::{assert, debug_assert};
267use faer_traits::*;
268/// shorthand for `<_ as Auto::<T>>::auto()`
269#[macro_export]
270macro_rules! auto {
271	($ty:ty $(,)?) => {
272		$crate::Auto::<$ty>::auto()
273	};
274}
275macro_rules! dispatch {
276	($imp:expr, $ty:ident, $T:ty $(,)?) => {
277		if const { <$T>::IS_NATIVE_C32 } {
278			unsafe {
279				transmute(
280					<ComplexImpl<f32> as ComplexField>::Arch::default()
281						.dispatch(transmute::<_, $ty<ComplexImpl<f32>>>($imp)),
282				)
283			}
284		} else if const { <$T>::IS_NATIVE_C64 } {
285			unsafe {
286				transmute(
287					<ComplexImpl<f64> as ComplexField>::Arch::default()
288						.dispatch(transmute::<_, $ty<ComplexImpl<f64>>>($imp)),
289				)
290			}
291		} else {
292			<$T>::Arch::default().dispatch($imp)
293		}
294	};
295}
296macro_rules! stack_mat {
297	($name:ident, $m:expr, $n:expr, $A:expr, $N:expr, $T:ty $(,)?) => {
298		let mut __tmp = {
299			#[repr(align(64))]
300			struct __Col<T, const A: usize>([T; A]);
301			struct __Mat<T, const A: usize, const N: usize>([__Col<T, A>; N]);
302			core::mem::MaybeUninit::<__Mat<$T, $A, $N>>::uninit()
303		};
304		let __stack = MemStack::new_any(core::slice::from_mut(&mut __tmp));
305		let mut $name =
306			$crate::linalg::temp_mat_zeroed::<$T, _, _>($m, $n, __stack).0;
307		let mut $name = $crate::mat::AsMatMut::as_mat_mut(&mut $name);
308	};
309	($name:ident, $m:expr, $n:expr, $T:ty $(,)?) => {
310		stack_mat!($name, $m, $n, $m, $n, $T)
311	};
312}
313#[macro_export]
314#[doc(hidden)]
315macro_rules! __dbg {
316    () => {
317        std::eprintln!("[{}:{}:{}]", std::file!(), std::line!(), std::column!())
318    };
319    ($val:expr $(,)?) => {
320        match $val { tmp => { std::eprintln!("[{}:{}:{}] {} = {:20?}", std::file!(),
321        std::line!(), std::column!(), std::stringify!($val), & tmp); tmp } }
322    };
323    ($($val:expr),+ $(,)?) => {
324        ($($crate::__dbg!($val)),+,)
325    };
326}
327#[cfg(feature = "perf-warn")]
328#[macro_export]
329#[doc(hidden)]
330macro_rules! __perf_warn {
331	($name:ident) => {{
332		#[inline(always)]
333		#[allow(non_snake_case)]
334		fn $name() -> &'static ::core::sync::atomic::AtomicBool {
335			static $name: ::core::sync::atomic::AtomicBool =
336				::core::sync::atomic::AtomicBool::new(false);
337			&$name
338		}
339		::core::matches!(
340			$name().compare_exchange(
341				false,
342				true,
343				::core::sync::atomic::Ordering::Relaxed,
344				::core::sync::atomic::Ordering::Relaxed,
345			),
346			Ok(_)
347		)
348	}};
349}
350#[doc(hidden)]
351#[macro_export]
352macro_rules! with_dim {
353    ($name:ident, $value:expr $(,)?) => {
354        let __val__ = $value; $crate::make_guard!($name); let $name =
355        $crate::utils::bound::Dim::new(__val__, $name);
356    };
357    ({ $(let $name:ident = $value:expr;)* }) => {
358        $(let __val__ = $value; $crate::make_guard!($name); let $name =
359        $crate::utils::bound::Dim::new(__val__, $name);)*
360    };
361}
362/// zips together matrix of the same size, so that coefficient-wise operations
363/// can be performed on their elements.
364///
365/// # note
366/// the order in which the matrix elements are traversed is unspecified.
367///
368/// # example
369/// ```
370/// use faer::{Mat, mat, unzip, zip};
371/// let nrows = 2;
372/// let ncols = 3;
373/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
374/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
375/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
376/// zip!(&mut sum, &a, &b).for_each(|unzip!(sum, a, b)| {
377/// 	*sum = a + b;
378/// });
379/// for i in 0..nrows {
380/// 	for j in 0..ncols {
381/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
382/// 	}
383/// }
384/// ```
385#[macro_export]
386macro_rules! zip {
387    ($head:expr $(,)?) => {
388        $crate::linalg::zip::LastEq($crate::linalg::zip::IntoView::into_view($head),
389        ::core::marker::PhantomData)
390    };
391    ($head:expr, $($tail:expr),* $(,)?) => {
392        $crate::linalg::zip::ZipEq::new($crate::linalg::zip::IntoView::into_view($head),
393        $crate::zip!($($tail,)*))
394    };
395}
396/// expands to the type of zipped items.
397///
398/// # example
399/// ```
400/// use faer::{Mat, Zip, mat, unzip, zip};
401/// let nrows = 2;
402/// let ncols = 3;
403/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
404/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
405/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
406/// zip!(&mut sum, &a, &b).for_each(
407/// 	|unzip!(sum, a, b): Zip!(&mut f64, &f64, &f64)| {
408/// 		*sum = a + b;
409/// 	},
410/// );
411/// for i in 0..nrows {
412/// 	for j in 0..ncols {
413/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
414/// 	}
415/// }
416/// ```
417#[macro_export]
418macro_rules! Zip {
419    (..$(,)?) => {
420        _
421    };
422    ($head:ty $(,)?) => {
423        $crate::linalg::zip::Last::<$head >
424    };
425    ($head:ty, $($tail:tt)*) => {
426        $crate::linalg::zip::Zip::<$head, $crate::Zip!($($tail)*) >
427    };
428}
429/// used to undo the zipping by the [`zip!`] macro.
430///
431/// # example
432/// ```
433/// use faer::{Mat, mat, unzip, zip};
434/// let nrows = 2;
435/// let ncols = 3;
436/// let a = mat![[1.0, 3.0, 5.0], [2.0, 4.0, 6.0]];
437/// let b = mat![[7.0, 9.0, 11.0], [8.0, 10.0, 12.0]];
438/// let mut sum = Mat::<f64>::zeros(nrows, ncols);
439/// zip!(&mut sum, &a, &b).for_each(|unzip!(sum, a, b)| {
440/// 	*sum = a + b;
441/// });
442/// for i in 0..nrows {
443/// 	for j in 0..ncols {
444/// 		assert_eq!(sum[(i, j)], a[(i, j)] + b[(i, j)]);
445/// 	}
446/// }
447/// ```
448#[macro_export]
449macro_rules! unzip {
450    (..$(,)?) => {
451        _
452    };
453    ($head:pat $(,)?) => {
454        $crate::linalg::zip::Last($head)
455    };
456    ($head:pat, $($tail:tt)*) => {
457        $crate::linalg::zip::Zip($head, $crate::unzip!($($tail)*))
458    };
459}
460#[macro_export]
461#[doc(hidden)]
462macro_rules! __transpose_impl {
463    ([$([$($col:expr),*])*] $($v:expr;)*) => {
464        [$([$($col,)*],)* [$($v,)*]]
465    };
466    ([$([$($col:expr),*])*] $($v0:expr, $($v:expr),*;)*) => {
467        $crate::__transpose_impl!([$([$($col),*])* [$($v0),*]] $($($v),*;)*)
468    };
469}
470/// creates a [`Mat`] containing the arguments.
471///
472/// ```
473/// use faer::mat;
474/// let matrix = mat![
475/// 	[1.0, 5.0, 9.0], //
476/// 	[2.0, 6.0, 10.0],
477/// 	[3.0, 7.0, 11.0],
478/// 	[4.0, 8.0, 12.0f64],
479/// ];
480/// assert_eq!(matrix[(0, 0)], 1.0);
481/// assert_eq!(matrix[(1, 0)], 2.0);
482/// assert_eq!(matrix[(2, 0)], 3.0);
483/// assert_eq!(matrix[(3, 0)], 4.0);
484/// assert_eq!(matrix[(0, 1)], 5.0);
485/// assert_eq!(matrix[(1, 1)], 6.0);
486/// assert_eq!(matrix[(2, 1)], 7.0);
487/// assert_eq!(matrix[(3, 1)], 8.0);
488/// assert_eq!(matrix[(0, 2)], 9.0);
489/// assert_eq!(matrix[(1, 2)], 10.0);
490/// assert_eq!(matrix[(2, 2)], 11.0);
491/// assert_eq!(matrix[(3, 2)], 12.0);
492/// ```
493#[macro_export]
494macro_rules! mat {
495    () => {
496        { compile_error!("number of columns in the matrix is ambiguous"); }
497    };
498    ($([$($v:expr),* $(,)?]),* $(,)?) => {
499        { let __data = ::core::mem::ManuallyDrop::new($crate::__transpose_impl!([]
500        $($($v),*;)*)); let __data = &* __data; let __ncols = __data.len(); let __nrows =
501        (* __data.get(0).unwrap()).len(); #[allow(unused_unsafe)] unsafe {
502        $crate::mat::Mat::from_fn(__nrows, __ncols, | i, j | ::core::ptr::from_ref(&
503        __data[j] [i]).read()) } }
504    };
505    (
506        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (uninit::<$ty:ty >, $($arg:expr),+
507        $(,)?)
508    ) => {
509        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_uninit::<$ty, _, _
510        > ($($arg,)* $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__);
511    };
512    (
513        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (zero::<$ty:ty >, $($arg:expr),+
514        $(,)?)
515    ) => {
516        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_zeroed::<$ty, _, _
517        > ($($arg,)* $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__);
518    };
519}
520/// creates a [`col::Col`] containing the arguments
521///
522/// ```
523/// use faer::col;
524/// let col_vec = col![3.0, 5.0, 7.0, 9.0];
525/// assert_eq!(col_vec[0], 3.0);
526/// assert_eq!(col_vec[1], 5.0);
527/// assert_eq!(col_vec[2], 7.0);
528/// assert_eq!(col_vec[3], 9.0);
529/// ```
530#[macro_export]
531macro_rules! col {
532    ($($v:expr),* $(,)?) => {
533        { let __data = ::core::mem::ManuallyDrop::new([$($v,)*]); let __data = &* __data;
534        let __len = __data.len(); #[allow(unused_unsafe)] unsafe {
535        $crate::col::Col::from_fn(__len, | i | ::core::ptr::from_ref(& __data[i]).read())
536        } }
537    };
538    (
539        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (uninit::<$ty:ty >, $($arg:expr),+
540        $(,)?)
541    ) => {
542        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_uninit::<$ty, _, _
543        > ($($arg,)* 1, $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__).col_mut(0);
544    };
545
546    (
547        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (zero::<$ty:ty >, $($arg:expr),+
548        $(,)?)
549    ) => {
550        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_zeroed::<$ty, _, _
551        > ($($arg,)* 1, $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__).col_mut(0);
552    };
553}
554/// creates a [`row::Row`] containing the arguments
555///
556/// ```
557/// use faer::row;
558/// let row_vec = row![3.0, 5.0, 7.0, 9.0];
559/// assert_eq!(row_vec[0], 3.0);
560/// assert_eq!(row_vec[1], 5.0);
561/// assert_eq!(row_vec[2], 7.0);
562/// assert_eq!(row_vec[3], 9.0);
563/// ```
564#[macro_export]
565macro_rules! row {
566    ($($v:expr),* $(,)?) => {
567        { let __data = ::core::mem::ManuallyDrop::new([$($v,)*]); let __data = &* __data;
568        let __len = __data.len(); #[allow(unused_unsafe)] unsafe {
569        $crate::row::Row::from_fn(__len, | i | ::core::ptr::from_ref(& __data[i]).read())
570        } }
571    };
572    (
573        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (uninit::<$ty:ty >, $($arg:expr),+
574        $(,)?)
575    ) => {
576        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_uninit::<$ty, _, _
577        > ($($arg,)* 1, $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__).col_mut(0).transpose_mut();
578    };
579
580    (
581        @ alloc $($unsafe:ident)? ($stack:ident) ($var:pat) (zero::<$ty:ty >, $($arg:expr),+
582        $(,)?)
583    ) => {
584        let (mut __mat__, $stack) = $($unsafe)? { $crate::linalg::temp_mat_zeroed::<$ty, _, _
585        > ($($arg,)* 1, $stack,) }; let $var = $crate::mat::AsMatMut::as_mat_mut(&mut __mat__).col_mut(0).transpose_mut();
586    };
587}
588/// convenience function to concatenate a nested list of matrices into a single
589/// big ['Mat']. concatonation pattern follows the numpy.block convention that
590/// each sub-list must have an equal number of columns (net) but the boundaries
591/// do not need to align. in other words, this sort of thing:
592/// ```notcode
593///   AAAbb
594///   AAAbb
595///   cDDDD
596/// ```
597/// is perfectly acceptable
598#[doc(hidden)]
599#[track_caller]
600pub fn concat_impl<T: ComplexField>(
601	blocks: &[&[(mat::MatRef<'_, T>, Conj)]],
602) -> mat::Mat<T> {
603	#[inline(always)]
604	fn count_total_columns<T: ComplexField>(
605		block_row: &[(mat::MatRef<'_, T>, Conj)],
606	) -> usize {
607		let mut out: usize = 0;
608		for (elem, _) in block_row.iter() {
609			out += elem.ncols();
610		}
611		out
612	}
613	#[inline(always)]
614	#[track_caller]
615	fn count_rows<T: ComplexField>(
616		block_row: &[(mat::MatRef<'_, T>, Conj)],
617	) -> usize {
618		let mut out: usize = 0;
619		for (i, (e, _)) in block_row.iter().enumerate() {
620			if i == 0 {
621				out = e.nrows();
622			} else {
623				assert!(e.nrows() == out);
624			}
625		}
626		out
627	}
628	let mut n: usize = 0;
629	let mut m: usize = 0;
630	for row in blocks.iter() {
631		n += count_rows(row);
632	}
633	for (i, row) in blocks.iter().enumerate() {
634		let cols = count_total_columns(row);
635		if i == 0 {
636			m = cols;
637		} else {
638			assert!(cols == m);
639		}
640	}
641	let mut mat = mat::Mat::<T>::zeros(n, m);
642	let mut ni: usize = 0;
643	let mut mj: usize;
644	for row in blocks.iter() {
645		mj = 0;
646		for (elem, conj) in row.iter() {
647			let mut dst =
648				mat.as_mut()
649					.submatrix_mut(ni, mj, elem.nrows(), elem.ncols());
650			if *conj == Conj::No {
651				dst.copy_from(elem);
652			} else {
653				dst.copy_from(elem.conjugate());
654			}
655			mj += elem.ncols();
656		}
657		ni += row[0].0.nrows();
658	}
659	mat
660}
661/// concatenates the matrices in each row horizontally,
662/// then concatenates the results vertically
663///
664/// `concat![[a0, a1, a2], [b1, b2]]` results in the matrix
665/// ```notcode
666/// [a0 | a1 | a2][b0 | b1]
667/// ```
668#[macro_export]
669macro_rules! concat {
670    () => {
671        { compile_error!("number of columns in the matrix is ambiguous"); }
672    };
673    ($([$($v:expr),* $(,)?]),* $(,)?) => {
674        { $crate::concat_impl(& [$(& [$(($v).as_ref().__canonicalize(),)*],)*]) }
675    };
676}
677/// column vector
678pub mod col;
679/// diagonal matrix
680pub mod diag;
681/// de-serialization from common matrix file formats
682#[cfg(feature = "std")]
683pub mod io;
684pub mod linalg;
685/// rectangular matrix
686pub mod mat;
687#[path = "./operator/mod.rs"]
688pub mod matrix_free;
689/// permutation matrix
690pub mod perm;
691/// row vector
692pub mod row;
693pub mod sparse;
694/// helper utilities
695pub mod utils;
696/// the parallel route: owns a threadteam team and hands out `Par::Team` for a closure
697#[cfg(feature = "threadteam")]
698pub use utils::team;
699/// native unsigned integer type
700pub trait Index: traits::IndexCore + traits::Index + seal::Seal {}
701impl<T: faer_traits::Index<Signed: seal::Seal> + seal::Seal> Index for T {}
702mod seal {
703	pub trait Seal {}
704	impl<T: faer_traits::Seal> Seal for T {}
705	impl Seal for crate::utils::bound::Dim<'_> {}
706	impl<I: crate::Index> Seal for crate::utils::bound::Idx<'_, I> {}
707	impl<I: crate::Index> Seal for crate::utils::bound::IdxInc<'_, I> {}
708	impl<I: crate::Index> Seal for crate::utils::bound::MaybeIdx<'_, I> {}
709	impl<I: crate::Index> Seal for crate::utils::bound::IdxIncOne<I> {}
710	impl<I: crate::Index> Seal for crate::utils::bound::MaybeIdxOne<I> {}
711	impl Seal for crate::utils::bound::One {}
712	impl Seal for crate::utils::bound::Zero {}
713	impl Seal for crate::ContiguousFwd {}
714	impl Seal for crate::ContiguousBwd {}
715}
716/// sealed trait for types that can be created from "unbound" values, as long as
717/// their struct preconditions are upheld
718pub trait Unbind<I = usize>:
719	Send + Sync + Copy + core::fmt::Debug + seal::Seal
720{
721	/// creates new value
722	/// # safety
723	/// safety invariants must be upheld
724	unsafe fn new_unbound(idx: I) -> Self;
725	/// returns the unbound value, unconstrained by safety invariants
726	fn unbound(self) -> I;
727}
728/// type that can be used to index into a range
729pub type Idx<Dim, I = usize> = <Dim as ShapeIdx>::Idx<I>;
730/// type that can be used to partition a range
731pub type IdxInc<Dim, I = usize> = <Dim as ShapeIdx>::IdxInc<I>;
732/// either an index or a negative value
733pub type MaybeIdx<Dim, I = usize> = <Dim as ShapeIdx>::MaybeIdx<I>;
734/// base trait for [`Shape`]
735pub trait ShapeIdx {
736	/// type that can be used to index into a range
737	type Idx<I: Index>: Unbind<I> + Ord + Eq;
738	/// type that can be used to partition a range
739	type IdxInc<I: Index>: Unbind<I> + Ord + Eq + From<Idx<Self, I>>;
740	/// either an index or a negative value
741	type MaybeIdx<I: Index>: Unbind<I::Signed> + Ord + Eq;
742}
743/// matrix dimension
744pub trait Shape:
745	Unbind
746	+ Ord
747	+ ShapeIdx<
748		Idx<usize>: Ord + Eq + PartialOrd<Self>,
749		IdxInc<usize>: Ord + Eq + PartialOrd<Self>,
750	>
751{
752	/// whether the types involved have any safety invariants
753	const IS_BOUND: bool = true;
754	/// bind the current value using a invariant lifetime guard
755	#[inline]
756	fn bind<'n>(self, guard: generativity::Guard<'n>) -> utils::bound::Dim<'n> {
757		utils::bound::Dim::new(self.unbound(), guard)
758	}
759	/// cast a slice of bound values to unbound values
760	#[inline]
761	fn cast_idx_slice<I: Index>(slice: &[Idx<Self, I>]) -> &[I] {
762		unsafe { core::slice::from_raw_parts(slice.as_ptr() as _, slice.len()) }
763	}
764	/// cast a slice of bound values to unbound values
765	#[inline]
766	fn cast_idx_inc_slice<I: Index>(slice: &[IdxInc<Self, I>]) -> &[I] {
767		unsafe { core::slice::from_raw_parts(slice.as_ptr() as _, slice.len()) }
768	}
769	/// returns the index `0`, which is always valid
770	#[inline(always)]
771	fn start() -> IdxInc<Self> {
772		unsafe { IdxInc::<Self>::new_unbound(0) }
773	}
774	/// returns the incremented value, as an inclusive index
775	#[inline(always)]
776	fn next(idx: Idx<Self>) -> IdxInc<Self> {
777		unsafe { IdxInc::<Self>::new_unbound(idx.unbound() + 1) }
778	}
779	/// returns the last value, equal to the dimension
780	#[inline(always)]
781	fn end(self) -> IdxInc<Self> {
782		unsafe { IdxInc::<Self>::new_unbound(self.unbound()) }
783	}
784	/// checks if the index is valid, returning `Some(_)` in that case
785	#[inline(always)]
786	fn idx(self, idx: usize) -> Option<Idx<Self>> {
787		if idx < self.unbound() {
788			Some(unsafe { Idx::<Self>::new_unbound(idx) })
789		} else {
790			None
791		}
792	}
793	/// checks if the index is valid, returning `Some(_)` in that case
794	#[inline(always)]
795	fn idx_inc(self, idx: usize) -> Option<IdxInc<Self>> {
796		if idx <= self.unbound() {
797			Some(unsafe { IdxInc::<Self>::new_unbound(idx) })
798		} else {
799			None
800		}
801	}
802	/// checks if the index is valid, and panics otherwise
803	#[inline(always)]
804	fn checked_idx(self, idx: usize) -> Idx<Self> {
805		equator::assert!(idx < self.unbound());
806		unsafe { Idx::<Self>::new_unbound(idx) }
807	}
808	/// checks if the index is valid, and panics otherwise
809	#[inline(always)]
810	fn checked_idx_inc(self, idx: usize) -> IdxInc<Self> {
811		equator::assert!(idx <= self.unbound());
812		unsafe { IdxInc::<Self>::new_unbound(idx) }
813	}
814	/// assumes the index is valid
815	/// # safety
816	/// the index must be valid
817	#[inline(always)]
818	unsafe fn unchecked_idx(self, idx: usize) -> Idx<Self> {
819		equator::debug_assert!(idx < self.unbound());
820		unsafe { Idx::<Self>::new_unbound(idx) }
821	}
822	/// assumes the index is valid
823	/// # safety
824	/// the index must be valid
825	#[inline(always)]
826	unsafe fn unchecked_idx_inc(self, idx: usize) -> IdxInc<Self> {
827		equator::debug_assert!(idx <= self.unbound());
828		unsafe { IdxInc::<Self>::new_unbound(idx) }
829	}
830	/// returns an iterator over the indices between `from` and `to`
831	#[inline(always)]
832	fn indices(
833		from: IdxInc<Self>,
834		to: IdxInc<Self>,
835	) -> impl Clone + ExactSizeIterator + DoubleEndedIterator<Item = Idx<Self>>
836	{
837		(from.unbound()..to.unbound()).map(
838			#[inline(always)]
839			|i| unsafe { Idx::<Self>::new_unbound(i) },
840		)
841	}
842}
843impl<T: Send + Sync + Copy + core::fmt::Debug + faer_traits::Seal> Unbind<T>
844	for T
845{
846	#[inline(always)]
847	unsafe fn new_unbound(idx: T) -> Self {
848		idx
849	}
850
851	#[inline(always)]
852	fn unbound(self) -> T {
853		self
854	}
855}
856impl ShapeIdx for usize {
857	type Idx<I: Index> = I;
858	type IdxInc<I: Index> = I;
859	type MaybeIdx<I: Index> = I::Signed;
860}
861impl Shape for usize {
862	const IS_BOUND: bool = false;
863}
864/// stride distance between two consecutive elements along a given dimension
865pub trait Stride:
866	seal::Seal + core::fmt::Debug + Copy + Send + Sync + 'static
867{
868	/// the reversed stride type
869	type Rev: Stride<Rev = Self>;
870	/// returns the reversed stride
871	fn rev(self) -> Self::Rev;
872	/// returns the stride in elements
873	fn element_stride(self) -> isize;
874}
875impl Stride for isize {
876	type Rev = Self;
877
878	#[inline(always)]
879	fn rev(self) -> Self::Rev {
880		-self
881	}
882
883	#[inline(always)]
884	fn element_stride(self) -> isize {
885		self
886	}
887}
888/// contiguous stride equal to `+1`
889#[derive(Copy, Clone, Debug)]
890pub struct ContiguousFwd;
891/// contiguous stride equal to `-1`
892#[derive(Copy, Clone, Debug)]
893pub struct ContiguousBwd;
894impl Stride for ContiguousFwd {
895	type Rev = ContiguousBwd;
896
897	#[inline(always)]
898	fn rev(self) -> Self::Rev {
899		ContiguousBwd
900	}
901
902	#[inline(always)]
903	fn element_stride(self) -> isize {
904		1
905	}
906}
907impl Stride for ContiguousBwd {
908	type Rev = ContiguousFwd;
909
910	#[inline(always)]
911	fn rev(self) -> Self::Rev {
912		ContiguousFwd
913	}
914
915	#[inline(always)]
916	fn element_stride(self) -> isize {
917		-1
918	}
919}
920/// memory allocation error
921#[derive(Copy, Clone, Debug, PartialEq, Eq)]
922pub enum TryReserveError {
923	///rRequired allocation does not fit within `isize` bytes
924	CapacityOverflow,
925	/// allocator could not provide an allocation with the requested layout
926	AllocError {
927		/// requested layout
928		layout: core::alloc::Layout,
929	},
930}
931/// determines whether the input should be implicitly conjugated or not
932#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
933pub enum Conj {
934	/// no implicit conjugation
935	No,
936	/// implicit conjugation
937	Yes,
938}
939#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
940pub(crate) enum DiagStatus {
941	Unit,
942	Generic,
943}
944/// determines whether to replace or add to the result of a matmul operatio
945#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
946pub enum Accum {
947	/// overwrites the output buffer
948	Replace,
949	/// adds the result to the output buffer
950	Add,
951}
952/// determines which side of a self-adjoint matrix should be accessed
953#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
954pub enum Side {
955	/// lower triangular half
956	Lower,
957	/// upper triangular half
958	Upper,
959}
960impl Conj {
961	/// returns `self == Conj::Yes`
962	#[inline]
963	pub const fn is_conj(self) -> bool {
964		matches!(self, Conj::Yes)
965	}
966
967	/// returns the composition of `self` and `other`
968	#[inline]
969	pub const fn compose(self, other: Self) -> Self {
970		match (self, other) {
971			(Conj::No, Conj::No) => Conj::No,
972			(Conj::Yes, Conj::Yes) => Conj::No,
973			(Conj::No, Conj::Yes) => Conj::Yes,
974			(Conj::Yes, Conj::No) => Conj::Yes,
975		}
976	}
977
978	/// returns `Conj::No` if `T` is the canonical representation, otherwise
979	/// `Conj::Yes`
980	#[inline]
981	pub const fn get<T: Conjugate>() -> Self {
982		if T::IS_CANONICAL { Self::No } else { Self::Yes }
983	}
984
985	#[inline]
986	pub(crate) fn apply<T: Conjugate>(value: &T) -> T::Canonical {
987		let value = unsafe { &*(value as *const T as *const T::Canonical) };
988		if const { matches!(Self::get::<T>(), Conj::Yes) } {
989			T::Canonical::conj_impl(value)
990		} else {
991			T::Canonical::copy_impl(value)
992		}
993	}
994
995	#[inline]
996	pub(crate) fn apply_rt<T: ComplexField>(self, value: &T) -> T {
997		if self.is_conj() {
998			T::conj_impl(value)
999		} else {
1000			T::copy_impl(value)
1001		}
1002	}
1003}
1004/// determines the parallelization configuration, and carries the right to execute with it
1005///
1006/// `Par` is neither `Copy` nor `Clone`: a `Team` owns exclusive authority over reserved
1007/// threads, so a duplicate could hand the same threads to two concurrent children. Every
1008/// function that runs work takes `Par` by value; a caller that needs another phase lends the
1009/// parallelism with [`Par::reborrow`], and concurrent children are created by splitting
1010/// (see `utils::thread::split`), never by copying. Queries that only need the size (workspace
1011/// requirements, thresholds) use [`ParShape`] or [`Par::degree`].
1012///
1013/// ```
1014/// use faer::{Par, ParShape};
1015/// // sizes are plain values
1016/// fn is_copy<T: Copy>() {}
1017/// is_copy::<ParShape>();
1018/// // phases lend, they do not copy
1019/// fn phase(_: Par<'_>) {}
1020/// let mut par = Par::Seq;
1021/// phase(par.reborrow());
1022/// phase(par);
1023/// ```
1024///
1025/// Not `Copy`:
1026///
1027/// ```compile_fail
1028/// fn is_copy<T: Copy>() {}
1029/// is_copy::<faer::Par<'static>>();
1030/// ```
1031///
1032/// Not `Clone`:
1033///
1034/// ```compile_fail
1035/// fn is_clone<T: Clone>() {}
1036/// is_clone::<faer::Par<'static>>();
1037/// ```
1038///
1039/// A phase that takes the parallelism consumes it:
1040///
1041/// ```compile_fail
1042/// fn phase(_: faer::Par<'_>) {}
1043/// let par = faer::Par::Seq;
1044/// phase(par);
1045/// phase(par);
1046/// ```
1047///
1048/// Concurrent children cannot both use the parent:
1049///
1050/// ```compile_fail
1051/// fn phase(_: faer::Par<'_>) {}
1052/// let par = faer::Par::Seq;
1053/// faer::utils::thread::join_raw(|_| phase(par), |_| phase(par), faer::Par::Seq);
1054/// ```
1055#[derive(Debug)]
1056pub enum Par<'team> {
1057	/// sequential, non portable across different platforms
1058	Seq,
1059	/// parallelized on the reserved members of a threadteam team. The value is the exclusive
1060	/// authority over them for as long as it lives; the number of participants is the size of the
1061	/// team. This is the only parallel route: see [`Par::Team`], [`team::with_team`] and
1062	/// `utils::team`.
1063	#[cfg(feature = "threadteam")]
1064	Team(threadteam::TeamExec<'team>),
1065	/// owns the lifetime when the parallel route is not compiled (no `threadteam` feature): a
1066	/// build without it has no way to make a team, so this variant is never constructed
1067	#[cfg(not(feature = "threadteam"))]
1068	#[doc(hidden)]
1069	__Lifetime(core::convert::Infallible, core::marker::PhantomData<&'team ()>),
1070}
1071/// the shape of a [`Par`]: which kind of parallelism and how many threads, without the
1072/// right to run anything. `Copy`, so workspace queries and thresholds can use it freely; it
1073/// cannot be passed to any function that executes work.
1074#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1075pub enum ParShape {
1076	/// sequential
1077	Seq,
1078	/// a threadteam team of this many participants, with the dispatch costs of the pool it
1079	/// belongs to (see [`ParShape::dispatch_cost`])
1080	#[cfg(feature = "threadteam")]
1081	Team(NonZeroUsize, threadteam::DispatchCosts),
1082}
1083impl ParShape {
1084	/// sequential
1085	#[inline]
1086	pub const fn seq() -> Self {
1087		Self::Seq
1088	}
1089
1090	/// `Team(nthreads)` with the host default dispatch costs, zero treated as one
1091	#[cfg(feature = "threadteam")]
1092	#[inline]
1093	pub fn team(nthreads: usize) -> Self {
1094		#[cfg(feature = "threadteam")]
1095		Self::Team(
1096			NonZeroUsize::new(nthreads.max(1)).unwrap(),
1097			threadteam::DispatchCosts::host_default(),
1098		)
1099	}
1100
1101	/// the number of threads that should ideally execute an operation of this shape
1102	#[inline]
1103	pub fn degree(self) -> usize {
1104		match self {
1105			Self::Seq => 1,
1106			#[cfg(feature = "threadteam")]
1107			Self::Team(n, _) => n.get(),
1108		}
1109	}
1110}
1111impl Par<'_> {
1112	/// lends the parallelism for one phase. The parent is exclusively borrowed and unusable
1113	/// while the lent value lives, so a phase sequence never holds the authority twice.
1114	#[inline]
1115	pub fn reborrow(&mut self) -> Par<'_> {
1116		match self {
1117			Par::Seq => Par::Seq,
1118			#[cfg(feature = "threadteam")]
1119			Par::Team(team) => Par::Team(team.reborrow()),
1120			#[cfg(not(feature = "threadteam"))]
1121			Par::__Lifetime(x, _) => match *x {},
1122		}
1123	}
1124
1125	/// the shape of this parallelism, without the right to execute with it
1126	#[inline]
1127	pub fn shape(&self) -> ParShape {
1128		match self {
1129			Par::Seq => ParShape::Seq,
1130			#[cfg(feature = "threadteam")]
1131			Par::Team(team) => ParShape::Team(team.size(), team.dispatch_costs()),
1132			#[cfg(not(feature = "threadteam"))]
1133			Par::__Lifetime(x, _) => match *x {},
1134		}
1135	}
1136
1137	/// the number of threads that should ideally execute an operation with the
1138	/// given parallelism
1139	#[inline]
1140	pub fn degree(&self) -> usize {
1141		match self {
1142			Par::Seq => 1,
1143			#[cfg(feature = "threadteam")]
1144			Par::Team(team) => team.size().get(),
1145			#[cfg(not(feature = "threadteam"))]
1146			Par::__Lifetime(x, _) => match *x {},
1147		}
1148	}
1149}
1150#[allow(non_camel_case_types)]
1151/// `Complex<f32>`
1152pub type c32 = traits::c32;
1153#[allow(non_camel_case_types)]
1154/// `Complex<f64>`
1155pub type c64 = traits::c64;
1156#[allow(non_camel_case_types)]
1157/// `Complex<f64>`
1158pub type cx128 = traits::cx128;
1159#[allow(non_camel_case_types)]
1160/// `Complex<f64>`
1161pub type fx128 = traits::fx128;
1162pub use col::{Col, ColMut, ColRef};
1163pub use mat::{Mat, MatMut, MatRef, MatUninitMut};
1164pub use row::{Row, RowMut, RowRef};
1165#[allow(unused_imports, dead_code)]
1166mod internal_prelude {
1167	pub use crate::simd_iter;
1168
1169	pub trait DivCeil: Sized {
1170		fn msrv_div_ceil(self, rhs: Self) -> Self;
1171		fn msrv_next_multiple_of(self, rhs: Self) -> Self;
1172		fn msrv_checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
1173	}
1174	impl DivCeil for usize {
1175		#[inline]
1176		fn msrv_div_ceil(self, rhs: Self) -> Self {
1177			let d = self / rhs;
1178			let r = self % rhs;
1179			if r > 0 { d + 1 } else { d }
1180		}
1181
1182		#[inline]
1183		fn msrv_next_multiple_of(self, rhs: Self) -> Self {
1184			match self % rhs {
1185				0 => self,
1186				r => self + (rhs - r),
1187			}
1188		}
1189
1190		#[inline]
1191		fn msrv_checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1192			{
1193				match self.checked_rem(rhs)? {
1194					0 => Some(self),
1195					r => self.checked_add(rhs - r),
1196				}
1197			}
1198		}
1199	}
1200	pub(crate) use crate::col::{Col, ColMut, ColRef};
1201	pub(crate) use crate::diag::{Diag, DiagMut, DiagRef};
1202	pub(crate) use crate::hacks::transmute;
1203	pub(crate) use crate::linalg::{
1204		self, temp_mat_scratch, temp_mat_uninit, temp_mat_zeroed,
1205	};
1206	pub(crate) use crate::mat::{
1207		AsMat, AsMatMut, AsMatRef, Mat, MatMut, MatRef,
1208	};
1209	pub(crate) use crate::perm::{Perm, PermRef};
1210	pub(crate) use crate::prelude::*;
1211	pub(crate) use crate::row::{AsRowMut, AsRowRef, Row, RowMut, RowRef};
1212	pub(crate) use crate::utils::bound::{Array, Dim, Idx, IdxInc, MaybeIdx};
1213	pub(crate) use crate::utils::simd::SimdCtx;
1214	pub(crate) use crate::{Auto, NonExhaustive, Side, Spec};
1215	pub use faer_traits::ext::*;
1216	pub use faer_traits::math_utils::*;
1217	pub use faer_traits::{
1218		ComplexField, ComplexImpl, ComplexImplConj, Conjugate, Index,
1219		IndexCore, Real, RealField, SignedIndex, SimdArch, Symbolic,
1220	};
1221	pub use num_complex::Complex;
1222	#[cfg(test)]
1223	pub(crate) use std::dbg;
1224	#[cfg(test)]
1225	pub(crate) use {alloc::boxed::Box, alloc::vec, alloc::vec::Vec};
1226	#[inline]
1227	pub fn simd_align(i: usize) -> usize {
1228		i.wrapping_neg()
1229	}
1230	pub(crate) use self::{unzip as uz, zip as z};
1231	pub(crate) use crate::{
1232		Accum, Conj, ContiguousBwd, ContiguousFwd, DiagStatus, Par, ParShape,
1233		Shape, Stride, Unbind, make_guard, unzip, zip,
1234	};
1235	pub use dyn_stack::{MemStack, StackReq, alloc as alloca};
1236	pub use equator::{
1237		assert, assert as Assert, debug_assert, debug_assert as DebugAssert,
1238	};
1239	pub use reborrow::*;
1240}
1241#[allow(unused_imports)]
1242pub(crate) mod internal_prelude_sp {
1243	pub(crate) use crate::internal_prelude::*;
1244	pub(crate) use crate::sparse::{
1245		FaerError, NONE, Pair, SparseColMat, SparseColMatMut, SparseColMatRef,
1246		SparseRowMat, SparseRowMatMut, SparseRowMatRef, SymbolicSparseColMat,
1247		SymbolicSparseColMatRef, SymbolicSparseRowMat, SymbolicSparseRowMatRef,
1248		Triplet, csc_numeric, csc_symbolic, csr_numeric, csr_symbolic,
1249		linalg as linalg_sp, try_collect, try_zeroed, windows2,
1250	};
1251	pub(crate) use core::cell::Cell;
1252	pub(crate) use core::iter;
1253	pub(crate) use dyn_stack::MemBuffer;
1254}
1255/// useful imports for general usage of the library
1256pub mod prelude {
1257	#[cfg(feature = "linalg")]
1258	pub use super::linalg::solvers::{DenseSolve, Solve, SolveLstsq};
1259	#[cfg(feature = "sparse")]
1260	pub use super::prelude_sp::*;
1261	pub use super::{Par, ParShape, Scale, c32, c64, col, mat, row, unzip, zip};
1262	pub use col::{Col, ColMut, ColRef};
1263	pub use mat::{Mat, MatMut, MatRef, MatUninitMut};
1264	pub use reborrow::{IntoConst, Reborrow, ReborrowMut};
1265	pub use row::{Row, RowMut, RowRef};
1266	/// see [`Default`]
1267	#[inline]
1268	pub fn default<T: Default>() -> T {
1269		Default::default()
1270	}
1271}
1272#[cfg(feature = "sparse")]
1273mod prelude_sp {
1274	use crate::sparse;
1275	pub use sparse::{
1276		SparseColMat, SparseColMatMut, SparseColMatRef, SparseRowMat,
1277		SparseRowMatMut, SparseRowMatRef,
1278	};
1279}
1280/// scaling factor for multiplying matrices.
1281#[derive(Copy, Clone, Debug)]
1282#[repr(transparent)]
1283pub struct Scale<T>(pub T);
1284impl<T> Scale<T> {
1285	/// create a reference to a scaling factor from a reference to a value.
1286	#[inline(always)]
1287	pub fn from_ref(value: &T) -> &Self {
1288		unsafe { &*(value as *const T as *const Self) }
1289	}
1290
1291	/// create a mutable reference to a scaling factor from a mutable reference
1292	/// to a value.
1293	#[inline(always)]
1294	pub fn from_mut(value: &mut T) -> &mut Self {
1295		unsafe { &mut *(value as *mut T as *mut Self) }
1296	}
1297}
1298#[doc(hidden)]
1299pub mod hacks;
1300/// statistics and randomness functionality
1301pub mod stats;
1302mod non_exhaustive {
1303	#[doc(hidden)]
1304	#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1305	#[repr(transparent)]
1306	pub struct NonExhaustive(pub(crate) ());
1307}
1308pub(crate) use non_exhaustive::NonExhaustive;
1309/// like `Default`, but with an extra type parameter so that algorithm
1310/// hyperparameters can be tuned per scalar type.
1311pub trait Auto<T> {
1312	/// returns the default value for the type `T`
1313	fn auto() -> Self;
1314}
1315/// implements [`Default`] based on `Config`'s [`Auto`] implementation for the
1316/// type `T`.
1317pub struct Spec<Config, T> {
1318	/// wrapped config value
1319	pub config: Config,
1320	__marker: core::marker::PhantomData<fn() -> T>,
1321}
1322impl<Config, T> core::ops::Deref for Spec<Config, T> {
1323	type Target = Config;
1324
1325	#[inline]
1326	fn deref(&self) -> &Self::Target {
1327		&self.config
1328	}
1329}
1330impl<Config, T> core::ops::DerefMut for Spec<Config, T> {
1331	#[inline]
1332	fn deref_mut(&mut self) -> &mut Self::Target {
1333		&mut self.config
1334	}
1335}
1336impl<Config: Copy, T> Copy for Spec<Config, T> {}
1337impl<Config: Clone, T> Clone for Spec<Config, T> {
1338	#[inline]
1339	fn clone(&self) -> Self {
1340		Self::new(self.config.clone())
1341	}
1342}
1343impl<Config: core::fmt::Debug, T> core::fmt::Debug for Spec<Config, T> {
1344	#[inline]
1345	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1346		self.config.fmt(f)
1347	}
1348}
1349impl<Config, T> Spec<Config, T> {
1350	/// wraps the given config value
1351	#[inline]
1352	pub fn new(config: Config) -> Self {
1353		Spec {
1354			config,
1355			__marker: core::marker::PhantomData,
1356		}
1357	}
1358}
1359impl<T, Config> From<Config> for Spec<Config, T> {
1360	#[inline]
1361	fn from(config: Config) -> Self {
1362		Spec {
1363			config,
1364			__marker: core::marker::PhantomData,
1365		}
1366	}
1367}
1368impl<T, Config: Auto<T>> Default for Spec<Config, T> {
1369	#[inline]
1370	fn default() -> Self {
1371		Spec {
1372			config: Auto::<T>::auto(),
1373			__marker: core::marker::PhantomData,
1374		}
1375	}
1376}
1377mod into_range {
1378	use super::*;
1379	pub trait IntoRange<I> {
1380		type Len<N: Shape>: Shape;
1381		fn into_range(self, min: I, max: I) -> core::ops::Range<I>;
1382	}
1383	impl<I> IntoRange<I> for core::ops::Range<I> {
1384		type Len<N: Shape> = usize;
1385
1386		#[inline]
1387		fn into_range(self, _: I, _: I) -> core::ops::Range<I> {
1388			self
1389		}
1390	}
1391	impl<I> IntoRange<I> for core::ops::RangeFrom<I> {
1392		type Len<N: Shape> = usize;
1393
1394		#[inline]
1395		fn into_range(self, _: I, max: I) -> core::ops::Range<I> {
1396			self.start..max
1397		}
1398	}
1399	impl<I> IntoRange<I> for core::ops::RangeTo<I> {
1400		type Len<N: Shape> = usize;
1401
1402		#[inline]
1403		fn into_range(self, min: I, _: I) -> core::ops::Range<I> {
1404			min..self.end
1405		}
1406	}
1407	impl<I> IntoRange<I> for core::ops::RangeFull {
1408		type Len<N: Shape> = N;
1409
1410		#[inline]
1411		fn into_range(self, min: I, max: I) -> core::ops::Range<I> {
1412			min..max
1413		}
1414	}
1415}
1416mod sort;
1417pub extern crate dyn_stack;
1418pub extern crate faer_traits as traits;
1419#[doc(hidden)]
1420pub extern crate generativity;
1421pub extern crate num_complex as complex;
1422#[cfg(feature = "rand")]
1423#[cfg_attr(docs_rs, doc(cfg(feature = "rand")))]
1424pub extern crate rand;
1425pub extern crate reborrow;
1426
1427extern crate self as faer;
1428
1429#[macro_export]
1430#[doc(hidden)]
1431macro_rules! simd_iter {
1432	(for ($batch_id:tt, $i:pat $(,)?) in [$indices:expr; $batch_size:expr] $b:block $(,)?) => {#[allow(non_upper_case_globals, unconditional_panic)] 'out:{
1433		let (__head__, __body_batch__, __body_item__, __tail__) = &$indices;
1434		let __body_batch__ = __body_batch__.clone();
1435		let mut __body_item__ = __body_item__.clone();
1436		const {
1437			::core::assert!($batch_size > 0);
1438			::core::assert!($batch_size <= 8);
1439		}
1440		{
1441		if const { $batch_size == 1 } {if $batch_size == 1 { const $batch_id: usize = 0; if let &Some($i) = __head__ $b; }}
1442		if const { $batch_size == 2 } {if $batch_size == 2 { const $batch_id: usize = 1; if let &Some($i) = __head__ $b; }}
1443		if const { $batch_size == 3 } {if $batch_size == 3 { const $batch_id: usize = 2; if let &Some($i) = __head__ $b; }}
1444		if const { $batch_size == 4 } {if $batch_size == 4 { const $batch_id: usize = 3; if let &Some($i) = __head__ $b; }}
1445		if const { $batch_size == 5 } {if $batch_size == 5 { const $batch_id: usize = 4; if let &Some($i) = __head__ $b; }}
1446		if const { $batch_size == 6 } {if $batch_size == 6 { const $batch_id: usize = 5; if let &Some($i) = __head__ $b; }}
1447		if const { $batch_size == 7 } {if $batch_size == 7 { const $batch_id: usize = 6; if let &Some($i) = __head__ $b; }}
1448		if const { $batch_size == 8 } {if $batch_size == 8 { const $batch_id: usize = 7; if let &Some($i) = __head__ $b; }}
1449		}
1450		for __i__ in __body_batch__ {
1451			let __i__: [_; $batch_size] = __i__;
1452			let __i__ = __i__.as_slice();
1453			::core::assert!(__i__.len() == $batch_size);
1454
1455			{
1456			if const { $batch_size > 0 } {if __i__.len() > 0 { const $batch_id: usize = 0; let $i = __i__[0]; $b }}
1457			if const { $batch_size > 1 } {if __i__.len() > 1 { const $batch_id: usize = 1; let $i = __i__[1]; $b }}
1458			if const { $batch_size > 2 } {if __i__.len() > 2 { const $batch_id: usize = 2; let $i = __i__[2]; $b }}
1459			if const { $batch_size > 3 } {if __i__.len() > 3 { const $batch_id: usize = 3; let $i = __i__[3]; $b }}
1460			if const { $batch_size > 4 } {if __i__.len() > 4 { const $batch_id: usize = 4; let $i = __i__[4]; $b }}
1461			if const { $batch_size > 5 } {if __i__.len() > 5 { const $batch_id: usize = 5; let $i = __i__[5]; $b }}
1462			if const { $batch_size > 6 } {if __i__.len() > 6 { const $batch_id: usize = 6; let $i = __i__[6]; $b }}
1463			if const { $batch_size > 7 } {if __i__.len() > 7 { const $batch_id: usize = 7; let $i = __i__[7]; $b }}
1464			}
1465		};
1466
1467		{
1468		if const { $batch_size > 0 } { if $batch_size > 0 { const $batch_id: usize = 0; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1469		if const { $batch_size > 1 } { if $batch_size > 1 { const $batch_id: usize = 1; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1470		if const { $batch_size > 2 } { if $batch_size > 2 { const $batch_id: usize = 2; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1471		if const { $batch_size > 3 } { if $batch_size > 3 { const $batch_id: usize = 3; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1472		if const { $batch_size > 4 } { if $batch_size > 4 { const $batch_id: usize = 4; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1473		if const { $batch_size > 5 } { if $batch_size > 5 { const $batch_id: usize = 5; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1474		if const { $batch_size > 6 } { if $batch_size > 6 { const $batch_id: usize = 6; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1475		if const { $batch_size > 7 } { if $batch_size > 7 { const $batch_id: usize = 7; if let Some($i) = __body_item__.next() $b else { if let &Some($i) = __tail__ $b; break 'out; } } }
1476		}
1477	}};
1478	(for $i:pat in [$indices:expr] $b:block $(,)?) => {#[allow(non_upper_case_globals)]{
1479		let (__head__, __body__, __tail__) = &$indices;
1480		if let &Some($i) = __head__ $b;
1481		for $i in __body__.clone() $b;
1482		if let &Some($i) = __tail__ $b;
1483	}};
1484}