Skip to main content

numr/runtime/cpu/linalg/
mod.rs

1//! CPU implementation of linear algebra algorithms
2//!
3//! This module implements the [`LinearAlgebraAlgorithms`] trait for CPU.
4//! All algorithms follow the exact specification in the trait documentation
5//! to ensure backend parity with CUDA/WebGPU implementations.
6
7mod advanced_decompositions;
8mod banded;
9mod decompositions;
10mod eig_general;
11mod eig_symmetric;
12mod matrix_functions;
13mod matrix_ops;
14mod schur;
15mod solvers;
16mod statistics;
17mod svd;
18mod tensor_decompose;
19
20#[cfg(test)]
21mod tests;
22
23use super::{CpuClient, CpuRuntime};
24use crate::algorithm::linalg::{
25    CholeskyDecomposition, ComplexSchurDecomposition, EigenDecomposition,
26    GeneralEigenDecomposition, GeneralizedSchurDecomposition, LinearAlgebraAlgorithms,
27    LuDecomposition, MatrixFunctionsAlgorithms, MatrixNormOrder, PolarDecomposition,
28    QrDecomposition, SchurDecomposition, SvdDecomposition,
29};
30use crate::error::Result;
31use crate::tensor::Tensor;
32
33impl LinearAlgebraAlgorithms<CpuRuntime> for CpuClient {
34    fn lu_decompose(&self, a: &Tensor<CpuRuntime>) -> Result<LuDecomposition<CpuRuntime>> {
35        decompositions::lu_decompose_impl(self, a)
36    }
37
38    fn cholesky_decompose(
39        &self,
40        a: &Tensor<CpuRuntime>,
41    ) -> Result<CholeskyDecomposition<CpuRuntime>> {
42        decompositions::cholesky_decompose_impl(self, a)
43    }
44
45    fn qr_decompose(&self, a: &Tensor<CpuRuntime>) -> Result<QrDecomposition<CpuRuntime>> {
46        decompositions::qr_decompose_impl(self, a, false)
47    }
48
49    fn qr_decompose_thin(&self, a: &Tensor<CpuRuntime>) -> Result<QrDecomposition<CpuRuntime>> {
50        decompositions::qr_decompose_impl(self, a, true)
51    }
52
53    fn solve(&self, a: &Tensor<CpuRuntime>, b: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
54        solvers::solve_impl(self, a, b)
55    }
56
57    fn solve_triangular_lower(
58        &self,
59        l: &Tensor<CpuRuntime>,
60        b: &Tensor<CpuRuntime>,
61        unit_diagonal: bool,
62    ) -> Result<Tensor<CpuRuntime>> {
63        solvers::solve_triangular_lower_impl(self, l, b, unit_diagonal)
64    }
65
66    fn solve_triangular_upper(
67        &self,
68        u: &Tensor<CpuRuntime>,
69        b: &Tensor<CpuRuntime>,
70    ) -> Result<Tensor<CpuRuntime>> {
71        solvers::solve_triangular_upper_impl(self, u, b)
72    }
73
74    fn lstsq(&self, a: &Tensor<CpuRuntime>, b: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
75        solvers::lstsq_impl(self, a, b)
76    }
77
78    fn solve_banded(
79        &self,
80        ab: &Tensor<CpuRuntime>,
81        b: &Tensor<CpuRuntime>,
82        kl: usize,
83        ku: usize,
84    ) -> Result<Tensor<CpuRuntime>> {
85        banded::solve_banded_impl(self, ab, b, kl, ku)
86    }
87
88    fn inverse(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
89        matrix_ops::inverse_impl(self, a)
90    }
91
92    fn det(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
93        matrix_ops::det_impl(self, a)
94    }
95
96    fn trace(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
97        matrix_ops::trace_impl(self, a)
98    }
99
100    fn diag(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
101        matrix_ops::diag_impl(self, a)
102    }
103
104    fn diagflat(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
105        matrix_ops::diagflat_impl(self, a)
106    }
107
108    fn kron(&self, a: &Tensor<CpuRuntime>, b: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
109        matrix_ops::kron_impl(self, a, b)
110    }
111
112    fn triu(&self, a: &Tensor<CpuRuntime>, diagonal: i64) -> Result<Tensor<CpuRuntime>> {
113        matrix_ops::triu_impl(self, a, diagonal)
114    }
115
116    fn tril(&self, a: &Tensor<CpuRuntime>, diagonal: i64) -> Result<Tensor<CpuRuntime>> {
117        matrix_ops::tril_impl(self, a, diagonal)
118    }
119
120    fn slogdet(
121        &self,
122        a: &Tensor<CpuRuntime>,
123    ) -> Result<crate::algorithm::linalg::SlogdetResult<CpuRuntime>> {
124        matrix_ops::slogdet_impl(self, a)
125    }
126
127    fn khatri_rao(
128        &self,
129        a: &Tensor<CpuRuntime>,
130        b: &Tensor<CpuRuntime>,
131    ) -> Result<Tensor<CpuRuntime>> {
132        matrix_ops::khatri_rao_impl(self, a, b)
133    }
134
135    fn matrix_rank(&self, a: &Tensor<CpuRuntime>, tol: Option<f64>) -> Result<Tensor<CpuRuntime>> {
136        matrix_ops::matrix_rank_impl(self, a, tol)
137    }
138
139    fn matrix_norm(
140        &self,
141        a: &Tensor<CpuRuntime>,
142        ord: MatrixNormOrder,
143    ) -> Result<Tensor<CpuRuntime>> {
144        matrix_ops::matrix_norm_impl(self, a, ord)
145    }
146
147    fn svd_decompose(&self, a: &Tensor<CpuRuntime>) -> Result<SvdDecomposition<CpuRuntime>> {
148        svd::svd_decompose_impl(self, a)
149    }
150
151    fn eig_decompose_symmetric(
152        &self,
153        a: &Tensor<CpuRuntime>,
154    ) -> Result<EigenDecomposition<CpuRuntime>> {
155        eig_symmetric::eig_decompose_symmetric_impl(self, a)
156    }
157
158    fn pinverse(&self, a: &Tensor<CpuRuntime>, rcond: Option<f64>) -> Result<Tensor<CpuRuntime>> {
159        statistics::pinverse_impl(self, a, rcond)
160    }
161
162    fn cond(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
163        statistics::cond_impl(self, a)
164    }
165
166    fn cov(&self, a: &Tensor<CpuRuntime>, ddof: Option<usize>) -> Result<Tensor<CpuRuntime>> {
167        statistics::cov_impl(self, a, ddof)
168    }
169
170    fn corrcoef(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
171        statistics::corrcoef_impl(self, a)
172    }
173
174    fn schur_decompose(&self, a: &Tensor<CpuRuntime>) -> Result<SchurDecomposition<CpuRuntime>> {
175        schur::schur_decompose_impl(self, a)
176    }
177
178    fn eig_decompose(
179        &self,
180        a: &Tensor<CpuRuntime>,
181    ) -> Result<GeneralEigenDecomposition<CpuRuntime>> {
182        eig_general::eig_decompose_impl(self, a)
183    }
184
185    fn rsf2csf(
186        &self,
187        schur: &SchurDecomposition<CpuRuntime>,
188    ) -> Result<ComplexSchurDecomposition<CpuRuntime>> {
189        advanced_decompositions::rsf2csf_impl(self, schur)
190    }
191
192    fn qz_decompose(
193        &self,
194        a: &Tensor<CpuRuntime>,
195        b: &Tensor<CpuRuntime>,
196    ) -> Result<GeneralizedSchurDecomposition<CpuRuntime>> {
197        advanced_decompositions::qz_decompose_impl(self, a, b)
198    }
199
200    fn polar_decompose(&self, a: &Tensor<CpuRuntime>) -> Result<PolarDecomposition<CpuRuntime>> {
201        advanced_decompositions::polar_decompose_impl(self, a)
202    }
203}
204
205impl MatrixFunctionsAlgorithms<CpuRuntime> for CpuClient {
206    fn expm(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
207        matrix_functions::expm_impl(self, a)
208    }
209
210    fn logm(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
211        matrix_functions::logm_impl(self, a)
212    }
213
214    fn sqrtm(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
215        matrix_functions::sqrtm_impl(self, a)
216    }
217
218    fn signm(&self, a: &Tensor<CpuRuntime>) -> Result<Tensor<CpuRuntime>> {
219        matrix_functions::signm_impl(self, a)
220    }
221
222    fn fractional_matrix_power(
223        &self,
224        a: &Tensor<CpuRuntime>,
225        p: f64,
226    ) -> Result<Tensor<CpuRuntime>> {
227        matrix_functions::fractional_matrix_power_impl(self, a, p)
228    }
229
230    fn funm<F>(&self, a: &Tensor<CpuRuntime>, f: F) -> Result<Tensor<CpuRuntime>>
231    where
232        F: Fn(f64) -> f64 + Send + Sync,
233    {
234        matrix_functions::funm_impl(self, a, f)
235    }
236}