mdarray_linalg_lapack/lib.rs
1//! # mdarray_linalg_lapack
2//!
3//! LAPACK backend for [`mdarray_linalg`].
4//!
5//! This crate provides the [`Lapack`] struct that implements the decomposition and
6//! solver traits defined by [`mdarray_linalg`], delegating computations to a LAPACK
7//! implementation (e.g. OpenBLAS) via the `lapack-sys` and `cblas-sys` crates.
8//!
9//! Backend implementation modules are private. Use [`Lapack`] together with the
10//! operation traits from `mdarray_linalg::prelude::*`.
11//!
12//! ## Scope
13//!
14//! The LAPACK backend covers:
15//!
16//! - **Eigenvalue decomposition** — `eig`, `eig_full`, `eig_values`, `eigh`
17//! - **Schur decomposition** — `schur`, `schur_complex`
18//! - **SVD** — `svd`, `svd_thin`, `svd_s`
19//! - **LU decomposition** — `lu`, `det`, `inv`
20//! - **Cholesky decomposition** — `cholesky`
21//! - **QR decomposition** — `qr`
22//! - **Linear system solving** — `solve`
23//!
24//! For basic matrix/vector operations (Level 1–3 BLAS) and tensor contractions,
25//! use the [`mdarray_linalg_blas`] or [`mdarray_linalg_faer`] backends instead.
26//!
27//! ## Setup
28//!
29//! This crate binds to the LAPACK/BLAS ABI but does not choose a native library to link against.
30//! This is left to the user. For example, to use a system OpenBLAS installation:
31//!
32//! ```bash
33//! cargo add mdarray mdarray-linalg mdarray-linalg-lapack
34//! cargo add lapack-src --features openblas
35//! cargo add openblas-src --features system
36//! ```
37//!
38//! In one of your Rust crates, reference the provider so its link directives are
39//! included:
40//!
41//! ```rust
42//! extern crate lapack_src as _;
43//! ```
44//!
45//! Other LAPACK providers may be used if they expose the symbols required by
46//! `lapack-sys` and `cblas-sys`.
47//!
48//! ## Example
49//!
50//! All operations are accessed through the [`Lapack`] backend via the traits from
51//! `mdarray_linalg::prelude::*`:
52//!
53//! ```rust
54//! # extern crate lapack_src as _;
55//! use mdarray::array;
56//! use mdarray_linalg::prelude::*;
57//! use mdarray_linalg::eig::EigDecomp;
58//! use mdarray_linalg::solve::Solve;
59//! use mdarray_linalg::svd::SVDDecomp;
60//! use mdarray_linalg_lapack::Lapack;
61//!
62//! // ----- Eigenvalue decomposition -----
63//! let mut a = array![[1., 2.], [3., 4.]];
64//! let EigDecomp {
65//! eigenvalues: lambda,
66//! right_eigenvectors,
67//! ..
68//! } = Lapack::new().eig(&mut a.clone()).expect("Eigenvalue decomposition failed");
69//!
70//! println!("Eigenvalues: {:?}", lambda);
71//! if let Some(v) = right_eigenvectors {
72//! println!("Right eigenvectors: {:?}", v);
73//! }
74//!
75//! // ----- SVD -----
76//! let mut a = array![[1., 2.], [3., 4.]];
77//! let SVDDecomp { s, u, vt } = Lapack::new().svd_thin(&mut a).expect("SVD failed");
78//! println!("Singular values: {:?}", s);
79//!
80//! // ----- QR decomposition -----
81//! let mut a = array![[12., -51., 4.], [6., 167., -68.], [-4., 24., -41.]];
82//! let (q, r) = Lapack::new().qr(&mut a);
83//! println!("Q: {:?}", q);
84//! println!("R: {:?}", r);
85//!
86//! // ----- Solve linear system Ax = b -----
87//! let mut a = array![[2., 1., 0.], [1., 3., 1.], [0., 1., 2.]];
88//! let b = array![[1., 0., 0.], [2., 0., 0.], [1., 0., 0.]];
89//! let x = Lapack::new().solve(&mut a, &b).expect("Solve failed");
90//! println!("x = {:?}", x);
91//! ```
92//!
93//! > **Note:** Decomposition routines (eig, svd, lu, etc.) **destroy the input matrix**.
94//! > Always pass a clone if you need the original data.
95//!
96//! ## Currently supported types
97//!
98//! `f32`, `f64`, `Complex<f32>`, `Complex<f64>`.
99//!
100//! ## Troubleshooting
101//!
102//! Linking errors usually mean that no LAPACK/BLAS implementation was linked
103//! into the final binary, or that the selected libraries are not in the
104//! linker/runtime search path. Add a source crate such as `lapack-src`,
105//! reference it from Rust code, or provide equivalent link flags from your
106//! application `build.rs`.
107//!
108// Keep the doc-comment blank line above: these reference definitions must start
109// a separate Markdown block from the preceding paragraph.
110#![cfg_attr(docsrs, doc = concat!(
111 "[`mdarray_linalg`]: https://docs.rs/mdarray-linalg/", env!("CARGO_PKG_VERSION"), "/mdarray_linalg/\n",
112 "[`mdarray_linalg_blas`]: https://docs.rs/mdarray-linalg-blas/", env!("CARGO_PKG_VERSION"), "/mdarray_linalg_blas/\n",
113 "[`mdarray_linalg_faer`]: https://docs.rs/mdarray-linalg-faer/", env!("CARGO_PKG_VERSION"), "/mdarray_linalg_faer/",
114))]
115#![cfg_attr(not(docsrs), doc = "\
116[`mdarray_linalg`]: ../mdarray_linalg/index.html
117[`mdarray_linalg_blas`]: ../mdarray_linalg_blas/index.html
118[`mdarray_linalg_faer`]: ../mdarray_linalg_faer/index.html
119")]
120
121#[cfg(test)]
122extern crate lapack_src as _;
123
124mod eig;
125mod lu;
126mod qr;
127mod solve;
128mod svd;
129
130/// Configuration for the SVD algorithm.
131///
132/// This is hidden while backend configuration is being reconsidered.
133#[doc(hidden)]
134#[derive(Default, Debug, Clone, Copy, PartialEq)]
135pub enum SVDConfig {
136 /// Let the backend choose the best algorithm.
137 #[default]
138 Auto,
139 /// Divide-and-conquer algorithm (faster for large matrices).
140 DivideConquer,
141 /// Standard LAPACK SVD driver.
142 Jacobi,
143}
144
145/// Configuration for the QR decomposition.
146///
147/// This is hidden while backend configuration is being reconsidered.
148#[doc(hidden)]
149#[derive(Default, Debug, Clone, Copy)]
150pub enum QRConfig {
151 /// Reduced QR: Q is M×K, R is K×N (where K = min(M, N)).
152 #[default]
153 Reduced,
154 /// Complete QR: Q is M×M, R is M×N.
155 Complete,
156}
157
158/// LAPACK backend.
159///
160/// Implements the decomposition and solver traits from [`mdarray_linalg`] by
161/// delegating to LAPACK routines.
162#[derive(Debug, Default, Clone)]
163pub struct Lapack {
164 svd_config: SVDConfig,
165 qr_config: QRConfig,
166}
167
168impl Lapack {
169 /// Creates a new `Lapack` backend.
170 pub fn new() -> Self {
171 Self {
172 svd_config: SVDConfig::default(),
173 qr_config: QRConfig::default(),
174 }
175 }
176
177 /// Selects the SVD algorithm.
178 #[doc(hidden)]
179 #[must_use]
180 pub fn config_svd(mut self, config: SVDConfig) -> Self {
181 self.svd_config = config;
182 self
183 }
184
185 /// Selects the QR algorithm variant.
186 #[doc(hidden)]
187 #[must_use]
188 pub fn config_qr(mut self, config: QRConfig) -> Self {
189 self.qr_config = config;
190 self
191 }
192}