use core::fmt::Debug;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DType {
F32,
F64,
I32,
I64,
Bool,
}
impl DType {
pub fn size_bytes(&self) -> usize {
match self {
DType::F32 => 4,
DType::F64 => 8,
DType::I32 => 4,
DType::I64 => 8,
DType::Bool => 1,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Device {
Cpu,
Cuda(usize),
Wgpu,
}
impl Default for Device {
#[inline]
fn default() -> Self {
Device::Cpu
}
}
pub trait TensorBase: Clone + Send + Sync + Debug {
fn shape(&self) -> &[usize];
fn dtype(&self) -> DType;
fn device(&self) -> Device;
fn ndim(&self) -> usize {
self.shape().len()
}
fn numel(&self) -> usize {
self.shape().iter().product()
}
fn is_scalar(&self) -> bool {
self.ndim() == 0
}
fn is_vector(&self) -> bool {
self.ndim() == 1
}
fn is_matrix(&self) -> bool {
self.ndim() == 2
}
fn to_dense(&self) -> crate::tensor::dense::DenseTensor;
#[cfg(feature = "tensor")]
fn to_sparse(&self) -> Option<crate::tensor::sparse::SparseTensor>;
}
pub trait TensorOps: TensorBase {
fn add(&self, other: &Self) -> Self;
fn sub(&self, other: &Self) -> Self;
fn mul(&self, other: &Self) -> Self;
fn div(&self, other: &Self) -> Self;
fn matmul(&self, other: &Self) -> Self;
fn transpose(&self, axes: Option<&[usize]>) -> Self;
fn sum(&self, axes: Option<&[usize]>) -> Self;
fn mean(&self, axes: Option<&[usize]>) -> Self;
fn mul_scalar(&self, scalar: f64) -> Self;
fn add_scalar(&self, scalar: f64) -> Self;
fn map<F>(&self, f: F) -> Self
where
F: Fn(f64) -> f64 + Send + Sync;
fn reshape(&self, new_shape: &[usize]) -> Self;
fn slice(&self, axes: &[usize], ranges: &[core::ops::Range<usize>]) -> Self;
fn concat(&self, other: &Self, axis: usize) -> Self;
fn max(&self) -> f64;
fn min(&self) -> f64;
fn norm(&self) -> f64;
fn normalize(&self) -> Self;
}
pub trait SparseTensorOps: Clone + Send + Sync + TensorBase {
fn nnz(&self) -> usize;
fn sparsity(&self) -> f64 {
let total = self.numel();
if total == 0 {
0.0
} else {
1.0 - (self.nnz() as f64 / total as f64)
}
}
fn coo(&self) -> COOView<'_>;
fn row_indices(&self) -> &[usize];
fn col_indices(&self) -> &[usize];
fn values(&self) -> &crate::tensor::dense::DenseTensor;
}
#[derive(Debug, Clone)]
pub struct COOView<'a> {
pub row_indices: &'a [usize],
pub col_indices: &'a [usize],
pub values: &'a [f64],
pub shape: [usize; 2],
}
impl<'a> COOView<'a> {
pub fn new(
row_indices: &'a [usize],
col_indices: &'a [usize],
values: &'a [f64],
shape: [usize; 2],
) -> Self {
Self {
row_indices,
col_indices,
values,
shape,
}
}
pub fn nnz(&self) -> usize {
self.values.len()
}
pub fn iter(&self) -> impl Iterator<Item = (usize, usize, f64)> + '_ {
self.row_indices
.iter()
.zip(self.col_indices.iter())
.zip(self.values.iter())
.map(|((&r, &c), &v)| (r, c, v))
}
}