use crate::dtype::DType;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum SparseFormat {
Coo,
Csr,
Csc,
}
impl SparseFormat {
#[inline]
pub fn is_row_major(&self) -> bool {
matches!(self, SparseFormat::Csr)
}
#[inline]
pub fn is_col_major(&self) -> bool {
matches!(self, SparseFormat::Csc)
}
pub fn name(&self) -> &'static str {
match self {
SparseFormat::Coo => "COO",
SparseFormat::Csr => "CSR",
SparseFormat::Csc => "CSC",
}
}
}
impl std::fmt::Display for SparseFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name())
}
}
pub trait SparseStorage: Sized {
fn format(&self) -> SparseFormat;
fn shape(&self) -> [usize; 2];
#[inline]
fn nrows(&self) -> usize {
self.shape()[0]
}
#[inline]
fn ncols(&self) -> usize {
self.shape()[1]
}
fn nnz(&self) -> usize;
fn dtype(&self) -> DType;
#[inline]
fn sparsity(&self) -> f64 {
let total = (self.nrows() * self.ncols()) as f64;
if total == 0.0 {
0.0
} else {
1.0 - (self.nnz() as f64 / total)
}
}
#[inline]
fn density(&self) -> f64 {
1.0 - self.sparsity()
}
#[inline]
fn is_empty(&self) -> bool {
self.nnz() == 0
}
fn memory_usage(&self) -> usize;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sparse_format_display() {
assert_eq!(SparseFormat::Coo.to_string(), "COO");
assert_eq!(SparseFormat::Csr.to_string(), "CSR");
assert_eq!(SparseFormat::Csc.to_string(), "CSC");
}
#[test]
fn test_format_properties() {
assert!(!SparseFormat::Coo.is_row_major());
assert!(SparseFormat::Csr.is_row_major());
assert!(!SparseFormat::Csc.is_row_major());
assert!(!SparseFormat::Coo.is_col_major());
assert!(!SparseFormat::Csr.is_col_major());
assert!(SparseFormat::Csc.is_col_major());
}
}