mdarray_linalg_blas/lib.rs
1//! # mdarray_linalg_blas
2//!
3//! BLAS backend for [`mdarray_linalg`].
4//!
5//! This crate provides the [`Blas`] struct that implements the linear algebra traits
6//! defined by [`mdarray_linalg`], delegating computations to a BLAS implementation
7//! (e.g. OpenBLAS) via the `cblas-sys` crate.
8//!
9//! ## Scope
10//!
11//! The BLAS backend covers:
12//!
13//! - **Level 1** — vector operations: `dot`, `dotc`, `norm2`, `norm1`, `add_to_scaled`
14//! - **Level 2** — matrix-vector & outer product: `matvec`, `outer`
15//! - **Level 3** — matrix multiplication: `matmul`
16//! - **Tensor contraction** — `contract_all`, `contract_n`, `contract_pairs`, `contract`
17//! - **Argmax** — `argmax`, `argmax_abs`
18//!
19//! For decompositions (Eig, SVD, LU, QR, Cholesky, Schur) and solving linear systems,
20//! use the [`mdarray_linalg_lapack`] or [`mdarray_linalg_faer`] backends instead.
21//!
22//! ## Setup
23//!
24//! This crate binds to the CBLAS ABI but does not choose a native BLAS library to link against.
25//! This is left to the user. For example, to use a system OpenBLAS installation:
26//!
27//! ```bash
28//! cargo add mdarray mdarray-linalg mdarray-linalg-blas
29//! cargo add openblas-src --features system
30//! ```
31//!
32//! In one of your Rust crates, reference the CBLAS provider so its link directives are included:
33//!
34//! ```rust
35//! extern crate openblas_src as _;
36//! ```
37//!
38//! Other BLAS providers may be used if they expose the CBLAS symbols required by
39//! `cblas-sys`.
40//!
41//! ## Example
42//!
43//! All operations are accessed through the [`Blas`] backend via the traits from
44//! `mdarray_linalg::prelude::*`:
45//!
46//! ```rust
47//! # extern crate openblas_src as _;
48//! use mdarray::array;
49//! use mdarray_linalg::prelude::*;
50//! use mdarray_linalg_blas::Blas;
51//!
52//! // ----- Vector operations (Level 1) -----
53//! let x = array![1., 2., 3.];
54//! let y = array![4., 5., 6.];
55//!
56//! let d = Blas.dot(&x, &y);
57//! assert_eq!(d, 32.0); // 1·4 + 2·5 + 3·6
58//!
59//! // ----- Matrix-vector multiplication (Level 2) -----
60//! let a = array![[1., 2., 3.], [4., 5., 6.]];
61//! let v = array![1., 1., 1.];
62//!
63//! let av = Blas.matvec(&a, &v).eval();
64//! assert_eq!(av, array![6., 15.]); // A·v
65//!
66//! // ----- Matrix multiplication (Level 3) -----
67//! let b = array![[1., 2.], [3., 4.], [5., 6.]];
68//!
69//! let c = Blas.matmul(&a, &b).eval();
70//! assert_eq!(c, array![[22., 28.], [49., 64.]]); // (2×3)·(3×2) = (2×2)
71//!
72//! // Scaled addition: C = α·A·B + β·C
73//! let mut c = array![[1., 1.], [1., 1.]];
74//! Blas.matmul(&a, &b).add_to_scaled(&mut c, 2.0);
75//!
76//! // ----- Tensor contraction -----
77//! let t1 = array![[1., 2.], [3., 4.]].into_dyn();
78//! let t2 = array![[5., 6.], [7., 8.]].into_dyn();
79//!
80//! // Full contraction over all axes
81//! let scalar = Blas.contract_all(&t1, &t2);
82//! assert_eq!(scalar, 70.0); // 1·5 + 2·6 + 3·7 + 4·8
83//!
84//! // Contract last n axes (n=1 → standard matmul)
85//! let contracted = Blas.contract_n(&t1, &t2, 1).eval();
86//! assert_eq!(contracted, array![[19., 22.], [43., 50.]].into_dyn());
87//! ```
88//!
89//! ## Supported types
90//!
91//! `f32`, `f64`, `Complex<f32>`, `Complex<f64>`.
92//!
93//! ## Troubleshooting
94//!
95//! Linking errors usually mean that no BLAS library was linked into the final
96//! binary, or that the selected library is not in the linker/runtime search
97//! path. Add a source crate such as `openblas-src`, reference it from Rust code,
98//! or provide equivalent link flags from your application `build.rs`.
99//!
100// Keep the doc-comment blank line above: these reference definitions must start
101// a separate Markdown block from the preceding paragraph.
102#![cfg_attr(docsrs, doc = concat!(
103 "[`mdarray_linalg`]: https://docs.rs/mdarray-linalg/", env!("CARGO_PKG_VERSION"), "/mdarray_linalg/\n",
104 "[`mdarray_linalg_lapack`]: https://docs.rs/mdarray-linalg-lapack/", env!("CARGO_PKG_VERSION"), "/mdarray_linalg_lapack/\n",
105 "[`mdarray_linalg_faer`]: https://docs.rs/mdarray-linalg-faer/", env!("CARGO_PKG_VERSION"), "/mdarray_linalg_faer/",
106))]
107#![cfg_attr(not(docsrs), doc = "\
108[`mdarray_linalg`]: ../mdarray_linalg/index.html
109[`mdarray_linalg_lapack`]: ../mdarray_linalg_lapack/index.html
110[`mdarray_linalg_faer`]: ../mdarray_linalg_faer/index.html
111")]
112
113#[cfg(test)]
114extern crate openblas_src as _;
115
116mod contract;
117mod matvec;
118
119/// BLAS backend.
120///
121/// Implements the linear algebra traits from [`mdarray_linalg`] by delegating
122/// to BLAS routines. The struct is a zero-sized marker — all state is managed
123/// by the underlying BLAS library.
124#[derive(Default)]
125pub struct Blas;
126
127pub(crate) fn trans_stride<T, D0, D1, L>(
128 x: &mdarray::Slice<T, (D0, D1), L>,
129 same_order: cblas_sys::CBLAS_TRANSPOSE,
130 other_order: cblas_sys::CBLAS_TRANSPOSE,
131) -> (cblas_sys::CBLAS_TRANSPOSE, i32)
132where
133 D0: mdarray::Dim,
134 D1: mdarray::Dim,
135 L: mdarray::Layout,
136{
137 if x.stride(1) == 1 {
138 (same_order, mdarray_linalg::utils::into_i32(x.stride(0)))
139 } else {
140 assert!(
141 x.stride(0) == 1,
142 "matrix must be contiguous in one dimension"
143 );
144 (other_order, mdarray_linalg::utils::into_i32(x.stride(1)))
145 }
146}