use crate::error::LinalgResult;
use crate::matrixfree::LinearOperator;
use scirs2_core::ndarray::ScalarOperand;
use scirs2_core::ndarray::{Array1, Array2, ArrayView1};
use scirs2_core::numeric::{Float, NumAssign, One, Zero};
use std::{fmt::Debug, iter::Sum};
mod circulant;
mod hankel;
mod toeplitz;
mod utils;
pub use circulant::CirculantMatrix;
pub use hankel::HankelMatrix;
pub use toeplitz::ToeplitzMatrix;
pub use utils::{
circulant_determinant, circulant_eigenvalues, circulant_inverse_fft, circulant_matvec_direct,
circulant_matvec_fft, dftmatrix_multiply, fast_toeplitz_inverse, gohberg_semencul_inverse,
hadamard_transform, hankel_determinant, hankel_matvec, hankel_matvec_fft, hankel_svd,
levinson_durbin, solve_circulant, solve_circulant_fft, solve_toeplitz, solve_tridiagonal_lu,
solve_tridiagonal_thomas, tridiagonal_determinant, tridiagonal_eigenvalues,
tridiagonal_eigenvectors, tridiagonal_matvec, yule_walker,
};
pub trait StructuredMatrix<A>
where
A: Float + NumAssign + Zero + Sum + One + ScalarOperand + Send + Sync + Debug,
{
fn nrows(&self) -> usize;
fn ncols(&self) -> usize;
fn shape(&self) -> (usize, usize) {
(self.nrows(), self.ncols())
}
fn get(&self, i: usize, j: usize) -> LinalgResult<A>;
fn matvec(&self, x: &ArrayView1<A>) -> LinalgResult<Array1<A>>;
fn matvec_transpose(&self, x: &ArrayView1<A>) -> LinalgResult<Array1<A>>;
fn to_dense(&self) -> LinalgResult<Array2<A>> {
let (rows, cols) = self.shape();
let mut result = Array2::zeros((rows, cols));
for i in 0..rows {
for j in 0..cols {
result[[i, j]] = self.get(i, j)?;
}
}
Ok(result)
}
fn to_operator(&self) -> LinearOperator<A>
where
Self: Clone + Send + Sync + 'static,
{
let matrix = self.clone();
let (rows, cols) = self.shape();
LinearOperator::new_rectangular(rows, cols, move |x: &ArrayView1<A>| {
matrix.matvec(x).expect("Operation failed")
})
}
}
#[allow(dead_code)]
pub fn structured_to_operator<A, M>(matrix: &M) -> LinearOperator<A>
where
A: Float + NumAssign + Zero + Sum + One + ScalarOperand + Send + Sync + Debug + 'static,
M: StructuredMatrix<A> + Clone + Send + Sync + 'static,
{
let matrix_clone = matrix.clone();
let (rows, cols) = matrix.shape();
LinearOperator::new_rectangular(rows, cols, move |x: &ArrayView1<A>| {
matrix_clone.matvec(x).expect("Operation failed")
})
}
#[cfg(test)]
mod tests {
}