oxiblas_matrix/
lib.rs

1//! OxiBLAS Matrix - Matrix types and views for OxiBLAS.
2//!
3//! This crate provides the core matrix types for OxiBLAS:
4//!
5//! - [`Mat<T>`]: Owned, heap-allocated matrix with column-major storage
6//! - [`CowMat<T>`]: Copy-on-Write matrix for efficient sharing
7//! - [`MatRef<'a, T>`]: Immutable view into a matrix
8//! - [`MatMut<'a, T>`]: Mutable view with reborrow semantics
9//!
10//! # Specialized Matrix Types
11//!
12//! - [`packed::PackedMat<T>`]: Packed triangular/symmetric storage
13//! - [`banded::BandedMat<T>`]: Banded matrix storage
14//! - [`triangular::TriangularMat<T>`]: Triangular matrix with packed storage
15//! - [`symmetric::SymmetricMat<T>`]: Symmetric matrix with packed storage
16//! - [`symmetric::HermitianMat<T>`]: Hermitian matrix with packed storage
17//!
18//! # Memory Layout
19//!
20//! All matrices use column-major (Fortran) storage order. This means elements
21//! within a column are contiguous in memory. The storage is aligned for
22//! efficient SIMD operations.
23//!
24//! # Views and Reborrows
25//!
26//! The view types (`MatRef`, `MatMut`) do not own their data. They can
27//! represent submatrices, transposed views, or any strided data.
28//!
29//! `MatMut` uses the reborrow pattern to prevent aliasing:
30//! - `rb()` creates an immutable reborrow
31//! - `rb_mut()` creates a mutable reborrow with a shorter lifetime
32//!
33//! # Example
34//!
35//! ```
36//! use oxiblas_matrix::{Mat, MatRef, MatMut};
37//!
38//! // Create a matrix
39//! let mut m: Mat<f64> = Mat::zeros(4, 4);
40//!
41//! // Modify through a mutable view
42//! {
43//!     let mut view = m.as_mut();
44//!     view[(0, 0)] = 1.0;
45//!     view[(1, 1)] = 2.0;
46//!     view[(2, 2)] = 3.0;
47//!     view[(3, 3)] = 4.0;
48//! }
49//!
50//! // Read through an immutable view
51//! let view = m.as_ref();
52//! assert_eq!(view.diagonal()[2], 3.0);
53//! ```
54
55#![warn(missing_docs)]
56#![warn(clippy::all)]
57#![allow(clippy::module_name_repetitions)]
58#![allow(clippy::similar_names)]
59#![allow(clippy::too_many_lines)]
60#![allow(clippy::must_use_candidate)]
61// Prefetch functions use raw pointer arithmetic but don't dereference
62#![allow(clippy::not_unsafe_ptr_arg_deref)]
63// Loop index variables are common in matrix operations
64#![allow(clippy::needless_range_loop)]
65
66// Core matrix types
67pub mod mat;
68pub mod mat_mut;
69pub mod mat_ref;
70
71// Specialized storage formats
72pub mod banded;
73pub mod cow;
74pub mod lazy;
75pub mod ops;
76pub mod packed;
77pub mod prefetch;
78pub mod symmetric;
79pub mod triangular;
80
81// Memory-mapped matrices (requires mmap feature)
82#[cfg(feature = "mmap")]
83pub mod mmap;
84
85// nalgebra interoperability (requires nalgebra feature)
86#[cfg(feature = "nalgebra")]
87pub mod nalgebra_compat;
88
89// Re-exports - allocator support
90pub use oxiblas_core::memory::{Alloc, Global};
91
92// Re-exports - core types
93pub use cow::CowMat;
94pub use mat::Mat;
95pub use mat_mut::MatMut;
96pub use mat_ref::{DiagRef, MatRef, TransposeRef};
97
98// Re-exports - specialized types
99pub use banded::{BandedMat, BandedMut, BandedRef, SymmetricBandedMat};
100pub use packed::{PackedMat, PackedMut, PackedRef, TriangularKind};
101pub use prefetch::{
102    CACHE_LINE_SIZE, MatrixPrefetcher, PREFETCH_DISTANCE_BYTES, PREFETCH_DISTANCE_LINES,
103    PrefetchLocality, prefetch_block, prefetch_column, prefetch_range_read, prefetch_range_write,
104    prefetch_read, prefetch_write,
105};
106pub use symmetric::{
107    HermitianMat, SymmetricMat, SymmetricMut, SymmetricRef, SymmetricView, SymmetricViewMut,
108};
109pub use triangular::{
110    DiagonalKind, TriangularMat, TriangularMut, TriangularRef, TriangularView, TriangularViewMut,
111};
112
113// Re-exports - lazy evaluation
114pub use lazy::{
115    ComplexExpr, ComplexScalar, Expr, ExprAdd, ExprConj, ExprFma, ExprGemm, ExprHermitian,
116    ExprLeaf, ExprMul, ExprNeg, ExprScale, ExprSub, ExprTranspose, LazyExt, fma, gemm,
117};
118
119// Re-exports - memory-mapped matrices
120#[cfg(feature = "mmap")]
121pub use mmap::{
122    MmapBuilder, MmapError, MmapMat, MmapMatMut, read_dimensions, write_mat as write_mmap,
123};
124
125// Re-exports - nalgebra conversions
126#[cfg(feature = "nalgebra")]
127pub use nalgebra_compat::{
128    DMatrixOxiblasExt, MatNalgebraExt, dmatrix_to_mat, dmatrix_view_to_mat, dvector_to_mat,
129    mat_ref_to_dmatrix, mat_to_dmatrix, mat_to_dvector,
130};
131
132/// Prelude module for convenient imports.
133pub mod prelude {
134    // Allocator support
135    pub use crate::{Alloc, Global};
136
137    // Core types
138    pub use crate::cow::CowMat;
139    pub use crate::mat::Mat;
140    pub use crate::mat_mut::MatMut;
141    pub use crate::mat_ref::{DiagRef, MatRef, TransposeRef};
142
143    // Specialized storage
144    pub use crate::banded::{BandedMat, SymmetricBandedMat};
145    pub use crate::packed::{PackedMat, TriangularKind};
146    pub use crate::symmetric::{HermitianMat, SymmetricMat};
147    pub use crate::triangular::{DiagonalKind, TriangularMat};
148
149    // Lazy evaluation
150    pub use crate::lazy::{ComplexExpr, Expr, LazyExt, fma as lazy_fma, gemm as lazy_gemm};
151
152    // Operations
153    pub use crate::ops;
154
155    // Performance utilities (only MatrixPrefetcher is unique to oxiblas-matrix)
156    // PrefetchLocality and prefetch_* are in oxiblas-core
157    pub use crate::prefetch::MatrixPrefetcher;
158}
159
160#[cfg(test)]
161mod tests {
162    use super::*;
163
164    #[test]
165    fn test_matrix_workflow() {
166        // Create a 3x3 matrix
167        let mut m: Mat<f64> = Mat::zeros(3, 3);
168
169        // Fill diagonal
170        for i in 0..3 {
171            m[(i, i)] = (i + 1) as f64;
172        }
173
174        // Check via view
175        let view = m.as_ref();
176        assert_eq!(view[(0, 0)], 1.0);
177        assert_eq!(view[(1, 1)], 2.0);
178        assert_eq!(view[(2, 2)], 3.0);
179
180        // Modify via mutable view
181        {
182            let mut view = m.as_mut();
183            view[(0, 1)] = 10.0;
184        }
185
186        assert_eq!(m[(0, 1)], 10.0);
187    }
188
189    #[test]
190    fn test_submatrix_views() {
191        let m: Mat<f64> = Mat::from_rows(&[
192            &[1.0, 2.0, 3.0, 4.0],
193            &[5.0, 6.0, 7.0, 8.0],
194            &[9.0, 10.0, 11.0, 12.0],
195            &[13.0, 14.0, 15.0, 16.0],
196        ]);
197
198        // Get a 2x2 submatrix from the center
199        let sub = m.as_ref().submatrix(1, 1, 2, 2);
200        assert_eq!(sub[(0, 0)], 6.0);
201        assert_eq!(sub[(0, 1)], 7.0);
202        assert_eq!(sub[(1, 0)], 10.0);
203        assert_eq!(sub[(1, 1)], 11.0);
204    }
205
206    #[test]
207    fn test_complex_matrix() {
208        use num_complex::Complex64;
209
210        // Use filled() instead of zeros() since Complex64 doesn't implement bytemuck::Zeroable
211        let mut m: Mat<Complex64> = Mat::filled(2, 2, Complex64::new(0.0, 0.0));
212        m[(0, 0)] = Complex64::new(1.0, 2.0);
213        m[(1, 1)] = Complex64::new(3.0, 4.0);
214
215        assert_eq!(m[(0, 0)].re, 1.0);
216        assert_eq!(m[(0, 0)].im, 2.0);
217        assert_eq!(m[(1, 1)].re, 3.0);
218        assert_eq!(m[(1, 1)].im, 4.0);
219    }
220}