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///
1056/// A nested child cannot also take its borrowed parent:
1057///
1058/// ```compile_fail,E0505
1059/// use faer::Par;
1060///
1061/// fn nested_work(_child: Par<'_>, _parent: Par<'_>) {}
1062///
1063/// fn main() {
1064///     let mut parent = Par::Seq;
1065///     let child = parent.reborrow();
1066///     nested_work(child, parent);
1067/// }
1068/// ```
1069#[derive(Debug)]
1070pub enum Par<'team> {
1071	/// sequential, non portable across different platforms
1072	Seq,
1073	/// parallelized on the reserved members of a threadteam team. The value is the exclusive
1074	/// authority over them for as long as it lives; the number of participants is the size of the
1075	/// team. This is the only parallel route: see [`Par::Team`], [`team::with_team`] and
1076	/// `utils::team`.
1077	#[cfg(feature = "threadteam")]
1078	Team(threadteam::TeamExec<'team>),
1079	/// owns the lifetime when the parallel route is not compiled (no `threadteam` feature): a
1080	/// build without it has no way to make a team, so this variant is never constructed
1081	#[cfg(not(feature = "threadteam"))]
1082	#[doc(hidden)]
1083	__Lifetime(core::convert::Infallible, core::marker::PhantomData<&'team ()>),
1084}
1085/// the shape of a [`Par`]: which kind of parallelism and how many threads, without the
1086/// right to run anything. `Copy`, so workspace queries and thresholds can use it freely; it
1087/// cannot be passed to any function that executes work.
1088#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1089pub enum ParShape {
1090	/// sequential
1091	Seq,
1092	/// a threadteam team of this many participants, with the dispatch costs of the pool it
1093	/// belongs to (see [`ParShape::dispatch_cost`])
1094	#[cfg(feature = "threadteam")]
1095	Team(NonZeroUsize, threadteam::DispatchCosts),
1096}
1097impl ParShape {
1098	/// sequential
1099	#[inline]
1100	pub const fn seq() -> Self {
1101		Self::Seq
1102	}
1103
1104	/// `Team(nthreads)` with the host default dispatch costs, zero treated as one
1105	#[cfg(feature = "threadteam")]
1106	#[inline]
1107	pub fn team(nthreads: usize) -> Self {
1108		#[cfg(feature = "threadteam")]
1109		Self::Team(
1110			NonZeroUsize::new(nthreads.max(1)).unwrap(),
1111			threadteam::DispatchCosts::host_default(),
1112		)
1113	}
1114
1115	/// the number of threads that should ideally execute an operation of this shape
1116	#[inline]
1117	pub fn degree(self) -> usize {
1118		match self {
1119			Self::Seq => 1,
1120			#[cfg(feature = "threadteam")]
1121			Self::Team(n, _) => n.get(),
1122		}
1123	}
1124}
1125impl Par<'_> {
1126	/// lends the parallelism for one phase. The parent is exclusively borrowed and unusable
1127	/// while the lent value lives, so a phase sequence never holds the authority twice.
1128	#[inline]
1129	pub fn reborrow(&mut self) -> Par<'_> {
1130		match self {
1131			Par::Seq => Par::Seq,
1132			#[cfg(feature = "threadteam")]
1133			Par::Team(team) => Par::Team(team.reborrow()),
1134			#[cfg(not(feature = "threadteam"))]
1135			Par::__Lifetime(x, _) => match *x {},
1136		}
1137	}
1138
1139	/// the shape of this parallelism, without the right to execute with it
1140	#[inline]
1141	pub fn shape(&self) -> ParShape {
1142		match self {
1143			Par::Seq => ParShape::Seq,
1144			#[cfg(feature = "threadteam")]
1145			Par::Team(team) => ParShape::Team(team.size(), team.dispatch_costs()),
1146			#[cfg(not(feature = "threadteam"))]
1147			Par::__Lifetime(x, _) => match *x {},
1148		}
1149	}
1150
1151	/// the number of threads that should ideally execute an operation with the
1152	/// given parallelism
1153	#[inline]
1154	pub fn degree(&self) -> usize {
1155		match self {
1156			Par::Seq => 1,
1157			#[cfg(feature = "threadteam")]
1158			Par::Team(team) => team.size().get(),
1159			#[cfg(not(feature = "threadteam"))]
1160			Par::__Lifetime(x, _) => match *x {},
1161		}
1162	}
1163}
1164#[allow(non_camel_case_types)]
1165/// `Complex<f32>`
1166pub type c32 = traits::c32;
1167#[allow(non_camel_case_types)]
1168/// `Complex<f64>`
1169pub type c64 = traits::c64;
1170#[allow(non_camel_case_types)]
1171/// `Complex<f64>`
1172pub type cx128 = traits::cx128;
1173#[allow(non_camel_case_types)]
1174/// `Complex<f64>`
1175pub type fx128 = traits::fx128;
1176pub use col::{Col, ColMut, ColRef};
1177pub use mat::{Mat, MatMut, MatRef, MatUninitMut};
1178pub use row::{Row, RowMut, RowRef};
1179#[allow(unused_imports, dead_code)]
1180mod internal_prelude {
1181	pub use crate::simd_iter;
1182
1183	pub trait DivCeil: Sized {
1184		fn msrv_div_ceil(self, rhs: Self) -> Self;
1185		fn msrv_next_multiple_of(self, rhs: Self) -> Self;
1186		fn msrv_checked_next_multiple_of(self, rhs: Self) -> Option<Self>;
1187	}
1188	impl DivCeil for usize {
1189		#[inline]
1190		fn msrv_div_ceil(self, rhs: Self) -> Self {
1191			let d = self / rhs;
1192			let r = self % rhs;
1193			if r > 0 { d + 1 } else { d }
1194		}
1195
1196		#[inline]
1197		fn msrv_next_multiple_of(self, rhs: Self) -> Self {
1198			match self % rhs {
1199				0 => self,
1200				r => self + (rhs - r),
1201			}
1202		}
1203
1204		#[inline]
1205		fn msrv_checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
1206			{
1207				match self.checked_rem(rhs)? {
1208					0 => Some(self),
1209					r => self.checked_add(rhs - r),
1210				}
1211			}
1212		}
1213	}
1214	pub(crate) use crate::col::{Col, ColMut, ColRef};
1215	pub(crate) use crate::diag::{Diag, DiagMut, DiagRef};
1216	pub(crate) use crate::hacks::transmute;
1217	pub(crate) use crate::linalg::{
1218		self, temp_mat_scratch, temp_mat_uninit, temp_mat_zeroed,
1219	};
1220	pub(crate) use crate::mat::{
1221		AsMat, AsMatMut, AsMatRef, Mat, MatMut, MatRef,
1222	};
1223	pub(crate) use crate::perm::{Perm, PermRef};
1224	pub(crate) use crate::prelude::*;
1225	pub(crate) use crate::row::{AsRowMut, AsRowRef, Row, RowMut, RowRef};
1226	pub(crate) use crate::utils::bound::{Array, Dim, Idx, IdxInc, MaybeIdx};
1227	pub(crate) use crate::utils::simd::SimdCtx;
1228	pub(crate) use crate::{Auto, NonExhaustive, Side, Spec};
1229	pub use faer_traits::ext::*;
1230	pub use faer_traits::math_utils::*;
1231	pub use faer_traits::{
1232		ComplexField, ComplexImpl, ComplexImplConj, Conjugate, Index,
1233		IndexCore, Real, RealField, SignedIndex, SimdArch, Symbolic,
1234	};
1235	pub use num_complex::Complex;
1236	#[cfg(test)]
1237	pub(crate) use std::dbg;
1238	#[cfg(test)]
1239	pub(crate) use {alloc::boxed::Box, alloc::vec, alloc::vec::Vec};
1240	#[inline]
1241	pub fn simd_align(i: usize) -> usize {
1242		i.wrapping_neg()
1243	}
1244	pub(crate) use self::{unzip as uz, zip as z};
1245	pub(crate) use crate::{
1246		Accum, Conj, ContiguousBwd, ContiguousFwd, DiagStatus, Par, ParShape,
1247		Shape, Stride, Unbind, make_guard, unzip, zip,
1248	};
1249	pub use dyn_stack::{MemStack, StackReq, alloc as alloca};
1250	pub use equator::{
1251		assert, assert as Assert, debug_assert, debug_assert as DebugAssert,
1252	};
1253	pub use reborrow::*;
1254}
1255#[allow(unused_imports)]
1256pub(crate) mod internal_prelude_sp {
1257	pub(crate) use crate::internal_prelude::*;
1258	pub(crate) use crate::sparse::{
1259		FaerError, NONE, Pair, SparseColMat, SparseColMatMut, SparseColMatRef,
1260		SparseRowMat, SparseRowMatMut, SparseRowMatRef, SymbolicSparseColMat,
1261		SymbolicSparseColMatRef, SymbolicSparseRowMat, SymbolicSparseRowMatRef,
1262		Triplet, csc_numeric, csc_symbolic, csr_numeric, csr_symbolic,
1263		linalg as linalg_sp, try_collect, try_zeroed, windows2,
1264	};
1265	pub(crate) use core::cell::Cell;
1266	pub(crate) use core::iter;
1267	pub(crate) use dyn_stack::MemBuffer;
1268}
1269/// useful imports for general usage of the library
1270pub mod prelude {
1271	#[cfg(feature = "linalg")]
1272	pub use super::linalg::solvers::{DenseSolve, Solve, SolveLstsq};
1273	#[cfg(feature = "sparse")]
1274	pub use super::prelude_sp::*;
1275	pub use super::{Par, ParShape, Scale, c32, c64, col, mat, row, unzip, zip};
1276	pub use col::{Col, ColMut, ColRef};
1277	pub use mat::{Mat, MatMut, MatRef, MatUninitMut};
1278	pub use reborrow::{IntoConst, Reborrow, ReborrowMut};
1279	pub use row::{Row, RowMut, RowRef};
1280	/// see [`Default`]
1281	#[inline]
1282	pub fn default<T: Default>() -> T {
1283		Default::default()
1284	}
1285}
1286#[cfg(feature = "sparse")]
1287mod prelude_sp {
1288	use crate::sparse;
1289	pub use sparse::{
1290		SparseColMat, SparseColMatMut, SparseColMatRef, SparseRowMat,
1291		SparseRowMatMut, SparseRowMatRef,
1292	};
1293}
1294/// scaling factor for multiplying matrices.
1295#[derive(Copy, Clone, Debug)]
1296#[repr(transparent)]
1297pub struct Scale<T>(pub T);
1298impl<T> Scale<T> {
1299	/// create a reference to a scaling factor from a reference to a value.
1300	#[inline(always)]
1301	pub fn from_ref(value: &T) -> &Self {
1302		unsafe { &*(value as *const T as *const Self) }
1303	}
1304
1305	/// create a mutable reference to a scaling factor from a mutable reference
1306	/// to a value.
1307	#[inline(always)]
1308	pub fn from_mut(value: &mut T) -> &mut Self {
1309		unsafe { &mut *(value as *mut T as *mut Self) }
1310	}
1311}
1312#[doc(hidden)]
1313pub mod hacks;
1314/// statistics and randomness functionality
1315pub mod stats;
1316mod non_exhaustive {
1317	#[doc(hidden)]
1318	#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1319	#[repr(transparent)]
1320	pub struct NonExhaustive(pub(crate) ());
1321}
1322pub(crate) use non_exhaustive::NonExhaustive;
1323/// like `Default`, but with an extra type parameter so that algorithm
1324/// hyperparameters can be tuned per scalar type.
1325pub trait Auto<T> {
1326	/// returns the default value for the type `T`
1327	fn auto() -> Self;
1328}
1329/// implements [`Default`] based on `Config`'s [`Auto`] implementation for the
1330/// type `T`.
1331pub struct Spec<Config, T> {
1332	/// wrapped config value
1333	pub config: Config,
1334	__marker: core::marker::PhantomData<fn() -> T>,
1335}
1336impl<Config, T> core::ops::Deref for Spec<Config, T> {
1337	type Target = Config;
1338
1339	#[inline]
1340	fn deref(&self) -> &Self::Target {
1341		&self.config
1342	}
1343}
1344impl<Config, T> core::ops::DerefMut for Spec<Config, T> {
1345	#[inline]
1346	fn deref_mut(&mut self) -> &mut Self::Target {
1347		&mut self.config
1348	}
1349}
1350impl<Config: Copy, T> Copy for Spec<Config, T> {}
1351impl<Config: Clone, T> Clone for Spec<Config, T> {
1352	#[inline]
1353	fn clone(&self) -> Self {
1354		Self::new(self.config.clone())
1355	}
1356}
1357impl<Config: core::fmt::Debug, T> core::fmt::Debug for Spec<Config, T> {
1358	#[inline]
1359	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1360		self.config.fmt(f)
1361	}
1362}
1363impl<Config, T> Spec<Config, T> {
1364	/// wraps the given config value
1365	#[inline]
1366	pub fn new(config: Config) -> Self {
1367		Spec {
1368			config,
1369			__marker: core::marker::PhantomData,
1370		}
1371	}
1372}
1373impl<T, Config> From<Config> for Spec<Config, T> {
1374	#[inline]
1375	fn from(config: Config) -> Self {
1376		Spec {
1377			config,
1378			__marker: core::marker::PhantomData,
1379		}
1380	}
1381}
1382impl<T, Config: Auto<T>> Default for Spec<Config, T> {
1383	#[inline]
1384	fn default() -> Self {
1385		Spec {
1386			config: Auto::<T>::auto(),
1387			__marker: core::marker::PhantomData,
1388		}
1389	}
1390}
1391mod into_range {
1392	use super::*;
1393	pub trait IntoRange<I> {
1394		type Len<N: Shape>: Shape;
1395		fn into_range(self, min: I, max: I) -> core::ops::Range<I>;
1396	}
1397	impl<I> IntoRange<I> for core::ops::Range<I> {
1398		type Len<N: Shape> = usize;
1399
1400		#[inline]
1401		fn into_range(self, _: I, _: I) -> core::ops::Range<I> {
1402			self
1403		}
1404	}
1405	impl<I> IntoRange<I> for core::ops::RangeFrom<I> {
1406		type Len<N: Shape> = usize;
1407
1408		#[inline]
1409		fn into_range(self, _: I, max: I) -> core::ops::Range<I> {
1410			self.start..max
1411		}
1412	}
1413	impl<I> IntoRange<I> for core::ops::RangeTo<I> {
1414		type Len<N: Shape> = usize;
1415
1416		#[inline]
1417		fn into_range(self, min: I, _: I) -> core::ops::Range<I> {
1418			min..self.end
1419		}
1420	}
1421	impl<I> IntoRange<I> for core::ops::RangeFull {
1422		type Len<N: Shape> = N;
1423
1424		#[inline]
1425		fn into_range(self, min: I, max: I) -> core::ops::Range<I> {
1426			min..max
1427		}
1428	}
1429}
1430mod sort;
1431pub extern crate dyn_stack;
1432pub extern crate faer_traits as traits;
1433#[doc(hidden)]
1434pub extern crate generativity;
1435pub extern crate num_complex as complex;
1436#[cfg(feature = "rand")]
1437#[cfg_attr(docs_rs, doc(cfg(feature = "rand")))]
1438pub extern crate rand;
1439pub extern crate reborrow;
1440
1441extern crate self as faer;
1442
1443#[macro_export]
1444#[doc(hidden)]
1445macro_rules! simd_iter {
1446	(for ($batch_id:tt, $i:pat $(,)?) in [$indices:expr; $batch_size:expr] $b:block $(,)?) => {#[allow(non_upper_case_globals, unconditional_panic)] 'out:{
1447		let (__head__, __body_batch__, __body_item__, __tail__) = &$indices;
1448		let __body_batch__ = __body_batch__.clone();
1449		let mut __body_item__ = __body_item__.clone();
1450		const {
1451			::core::assert!($batch_size > 0);
1452			::core::assert!($batch_size <= 8);
1453		}
1454		{
1455		if const { $batch_size == 1 } {if $batch_size == 1 { const $batch_id: usize = 0; if let &Some($i) = __head__ $b; }}
1456		if const { $batch_size == 2 } {if $batch_size == 2 { const $batch_id: usize = 1; if let &Some($i) = __head__ $b; }}
1457		if const { $batch_size == 3 } {if $batch_size == 3 { const $batch_id: usize = 2; if let &Some($i) = __head__ $b; }}
1458		if const { $batch_size == 4 } {if $batch_size == 4 { const $batch_id: usize = 3; if let &Some($i) = __head__ $b; }}
1459		if const { $batch_size == 5 } {if $batch_size == 5 { const $batch_id: usize = 4; if let &Some($i) = __head__ $b; }}
1460		if const { $batch_size == 6 } {if $batch_size == 6 { const $batch_id: usize = 5; if let &Some($i) = __head__ $b; }}
1461		if const { $batch_size == 7 } {if $batch_size == 7 { const $batch_id: usize = 6; if let &Some($i) = __head__ $b; }}
1462		if const { $batch_size == 8 } {if $batch_size == 8 { const $batch_id: usize = 7; if let &Some($i) = __head__ $b; }}
1463		}
1464		for __i__ in __body_batch__ {
1465			let __i__: [_; $batch_size] = __i__;
1466			let __i__ = __i__.as_slice();
1467			::core::assert!(__i__.len() == $batch_size);
1468
1469			{
1470			if const { $batch_size > 0 } {if __i__.len() > 0 { const $batch_id: usize = 0; let $i = __i__[0]; $b }}
1471			if const { $batch_size > 1 } {if __i__.len() > 1 { const $batch_id: usize = 1; let $i = __i__[1]; $b }}
1472			if const { $batch_size > 2 } {if __i__.len() > 2 { const $batch_id: usize = 2; let $i = __i__[2]; $b }}
1473			if const { $batch_size > 3 } {if __i__.len() > 3 { const $batch_id: usize = 3; let $i = __i__[3]; $b }}
1474			if const { $batch_size > 4 } {if __i__.len() > 4 { const $batch_id: usize = 4; let $i = __i__[4]; $b }}
1475			if const { $batch_size > 5 } {if __i__.len() > 5 { const $batch_id: usize = 5; let $i = __i__[5]; $b }}
1476			if const { $batch_size > 6 } {if __i__.len() > 6 { const $batch_id: usize = 6; let $i = __i__[6]; $b }}
1477			if const { $batch_size > 7 } {if __i__.len() > 7 { const $batch_id: usize = 7; let $i = __i__[7]; $b }}
1478			}
1479		};
1480
1481		{
1482		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; } } }
1483		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; } } }
1484		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; } } }
1485		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; } } }
1486		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; } } }
1487		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; } } }
1488		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; } } }
1489		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; } } }
1490		}
1491	}};
1492	(for $i:pat in [$indices:expr] $b:block $(,)?) => {#[allow(non_upper_case_globals)]{
1493		let (__head__, __body__, __tail__) = &$indices;
1494		if let &Some($i) = __head__ $b;
1495		for $i in __body__.clone() $b;
1496		if let &Some($i) = __tail__ $b;
1497	}};
1498}