Skip to main content

tensor4all_tcicore/matrixluci/
source.rs

1//! Candidate matrix sources for pivot-kernel factorization.
2//!
3//! Provides the [`CandidateMatrixSource`] trait and two built-in
4//! implementations: [`DenseMatrixSource`] (borrowed column-major data) and
5//! [`LazyMatrixSource`] (callback-backed block evaluation).
6
7use crate::matrixluci::scalar::Scalar;
8use crate::matrixluci::types::DenseOwnedMatrix;
9use std::marker::PhantomData;
10
11/// Abstraction for accessing a matrix that will be cross-interpolated.
12///
13/// Implementors provide block-level access (filling column-major sub-blocks)
14/// so that kernels can select pivots without materializing the full matrix.
15pub trait CandidateMatrixSource<T: Scalar> {
16    /// Number of rows.
17    fn nrows(&self) -> usize;
18
19    /// Number of columns.
20    fn ncols(&self) -> usize;
21
22    /// Fill `out` with the cross-product A[rows, cols] in column-major order.
23    fn get_block(&self, rows: &[usize], cols: &[usize], out: &mut [T]);
24
25    /// Borrow the whole matrix in column-major layout when available.
26    fn dense_column_major_slice(&self) -> Option<&[T]> {
27        None
28    }
29
30    /// Read a single matrix entry.
31    fn get(&self, row: usize, col: usize) -> T {
32        let mut out = [T::zero(); 1];
33        self.get_block(&[row], &[col], &mut out);
34        out[0]
35    }
36}
37
38/// Borrowed dense matrix source with column-major layout.
39///
40/// Wraps a column-major data slice for use with pivot kernels.
41pub struct DenseMatrixSource<'a, T: Scalar> {
42    data: &'a [T],
43    nrows: usize,
44    ncols: usize,
45}
46
47/// Callback-backed lazy matrix source.
48///
49/// Evaluates matrix blocks on demand via a user-supplied closure,
50/// avoiding full materialization. The closure fills a column-major
51/// output buffer for a given set of rows and columns.
52pub struct LazyMatrixSource<T: Scalar, F> {
53    nrows: usize,
54    ncols: usize,
55    fill_block: F,
56    _marker: PhantomData<T>,
57}
58
59impl<'a, T: Scalar> DenseMatrixSource<'a, T> {
60    /// Create a dense source from a column-major slice.
61    pub fn from_column_major(data: &'a [T], nrows: usize, ncols: usize) -> Self {
62        assert_eq!(data.len(), nrows * ncols);
63        Self { data, nrows, ncols }
64    }
65}
66
67impl<T: Scalar, F> LazyMatrixSource<T, F>
68where
69    F: Fn(&[usize], &[usize], &mut [T]),
70{
71    /// Create a lazy source from a block-fill callback.
72    pub fn new(nrows: usize, ncols: usize, fill_block: F) -> Self {
73        Self {
74            nrows,
75            ncols,
76            fill_block,
77            _marker: PhantomData,
78        }
79    }
80}
81
82impl<T: Scalar> CandidateMatrixSource<T> for DenseMatrixSource<'_, T> {
83    fn nrows(&self) -> usize {
84        self.nrows
85    }
86
87    fn ncols(&self) -> usize {
88        self.ncols
89    }
90
91    fn get_block(&self, rows: &[usize], cols: &[usize], out: &mut [T]) {
92        assert_eq!(out.len(), rows.len() * cols.len());
93        for (j, &col) in cols.iter().enumerate() {
94            for (i, &row) in rows.iter().enumerate() {
95                out[i + rows.len() * j] = self.data[row + self.nrows * col];
96            }
97        }
98    }
99
100    fn dense_column_major_slice(&self) -> Option<&[T]> {
101        Some(self.data)
102    }
103}
104
105impl<T: Scalar, F> CandidateMatrixSource<T> for LazyMatrixSource<T, F>
106where
107    F: Fn(&[usize], &[usize], &mut [T]),
108{
109    fn nrows(&self) -> usize {
110        self.nrows
111    }
112
113    fn ncols(&self) -> usize {
114        self.ncols
115    }
116
117    fn get_block(&self, rows: &[usize], cols: &[usize], out: &mut [T]) {
118        assert_eq!(out.len(), rows.len() * cols.len());
119        (self.fill_block)(rows, cols, out);
120    }
121}
122
123pub(crate) fn materialize_source<T: Scalar, S: CandidateMatrixSource<T>>(
124    source: &S,
125) -> DenseOwnedMatrix<T> {
126    let nrows = source.nrows();
127    let ncols = source.ncols();
128    let rows: Vec<usize> = (0..nrows).collect();
129    let cols: Vec<usize> = (0..ncols).collect();
130    let mut out = vec![T::zero(); nrows * ncols];
131    source.get_block(&rows, &cols, &mut out);
132    DenseOwnedMatrix::from_column_major(out, nrows, ncols)
133}
134
135#[cfg(test)]
136mod tests;