use crate::{CooTensor, CscTensor, CsrTensor, SparseTensor, TorshResult};
fn unzip_triplets(triplets: Vec<(usize, usize, f32)>) -> (Vec<usize>, Vec<usize>, Vec<f32>) {
let mut rows = Vec::with_capacity(triplets.len());
let mut cols = Vec::with_capacity(triplets.len());
let mut values = Vec::with_capacity(triplets.len());
for (row, col, value) in triplets {
rows.push(row);
cols.push(col);
values.push(value);
}
(rows, cols, values)
}
pub struct SparseReLU {
#[allow(dead_code)]
inplace: bool,
}
impl SparseReLU {
pub fn new(inplace: bool) -> Self {
Self { inplace }
}
pub fn forward(&self, input: &dyn SparseTensor) -> TorshResult<Box<dyn SparseTensor>> {
let coo = input.to_coo()?;
let triplets = coo.triplets();
let shape = input.shape().clone();
let activated_triplets: Vec<(usize, usize, f32)> = triplets
.into_iter()
.filter_map(|(row, col, val)| {
if val > 0.0 {
Some((row, col, val))
} else {
None }
})
.collect();
let (rows, cols, values) = unzip_triplets(activated_triplets);
let activated_coo = CooTensor::new(rows, cols, values, shape)?;
match input.format() {
crate::SparseFormat::Coo => Ok(Box::new(activated_coo)),
crate::SparseFormat::Csr => Ok(Box::new(CsrTensor::from_coo(&activated_coo)?)),
crate::SparseFormat::Csc => Ok(Box::new(CscTensor::from_coo(&activated_coo)?)),
_ => Ok(Box::new(activated_coo)), }
}
}
pub struct SparseSigmoid;
impl Default for SparseSigmoid {
fn default() -> Self {
Self::new()
}
}
impl SparseSigmoid {
pub fn new() -> Self {
Self
}
pub fn forward(&self, input: &dyn SparseTensor) -> TorshResult<Box<dyn SparseTensor>> {
let coo = input.to_coo()?;
let triplets = coo.triplets();
let shape = input.shape().clone();
let activated_triplets: Vec<(usize, usize, f32)> = triplets
.into_iter()
.map(|(row, col, val)| {
let sigmoid_val = 1.0 / (1.0 + (-val).exp());
(row, col, sigmoid_val)
})
.collect();
let (rows, cols, values) = unzip_triplets(activated_triplets);
let activated_coo = CooTensor::new(rows, cols, values, shape)?;
match input.format() {
crate::SparseFormat::Coo => Ok(Box::new(activated_coo)),
crate::SparseFormat::Csr => Ok(Box::new(CsrTensor::from_coo(&activated_coo)?)),
crate::SparseFormat::Csc => Ok(Box::new(CscTensor::from_coo(&activated_coo)?)),
_ => Ok(Box::new(activated_coo)), }
}
}
pub struct SparseTanh;
impl Default for SparseTanh {
fn default() -> Self {
Self::new()
}
}
impl SparseTanh {
pub fn new() -> Self {
Self
}
pub fn forward(&self, input: &dyn SparseTensor) -> TorshResult<Box<dyn SparseTensor>> {
let coo = input.to_coo()?;
let triplets = coo.triplets();
let shape = input.shape().clone();
let activated_triplets: Vec<(usize, usize, f32)> = triplets
.into_iter()
.map(|(row, col, val)| {
let tanh_val = val.tanh();
(row, col, tanh_val)
})
.collect();
let (rows, cols, values) = unzip_triplets(activated_triplets);
let activated_coo = CooTensor::new(rows, cols, values, shape)?;
match input.format() {
crate::SparseFormat::Coo => Ok(Box::new(activated_coo)),
crate::SparseFormat::Csr => Ok(Box::new(CsrTensor::from_coo(&activated_coo)?)),
crate::SparseFormat::Csc => Ok(Box::new(CscTensor::from_coo(&activated_coo)?)),
_ => Ok(Box::new(activated_coo)), }
}
}
pub struct SparseGELU;
impl Default for SparseGELU {
fn default() -> Self {
Self::new()
}
}
impl SparseGELU {
pub fn new() -> Self {
Self
}
pub fn forward(&self, input: &dyn SparseTensor) -> TorshResult<Box<dyn SparseTensor>> {
let coo = input.to_coo()?;
let triplets = coo.triplets();
let shape = input.shape().clone();
let activated_triplets: Vec<(usize, usize, f32)> = triplets
.into_iter()
.map(|(row, col, val)| {
let sigmoid_val = 1.0 / (1.0 + (-1.702 * val).exp());
let gelu_val = val * sigmoid_val;
(row, col, gelu_val)
})
.collect();
let (rows, cols, values) = unzip_triplets(activated_triplets);
let activated_coo = CooTensor::new(rows, cols, values, shape)?;
match input.format() {
crate::SparseFormat::Coo => Ok(Box::new(activated_coo)),
crate::SparseFormat::Csr => Ok(Box::new(CsrTensor::from_coo(&activated_coo)?)),
crate::SparseFormat::Csc => Ok(Box::new(CscTensor::from_coo(&activated_coo)?)),
_ => Ok(Box::new(activated_coo)), }
}
}
pub struct SparseLeakyReLU {
negative_slope: f32,
}
impl SparseLeakyReLU {
pub fn new(negative_slope: f32) -> Self {
Self { negative_slope }
}
pub fn forward(&self, input: &dyn SparseTensor) -> TorshResult<Box<dyn SparseTensor>> {
let coo = input.to_coo()?;
let triplets = coo.triplets();
let shape = input.shape().clone();
let activated_triplets: Vec<(usize, usize, f32)> = triplets
.into_iter()
.map(|(row, col, val)| {
let leaky_relu_val = if val > 0.0 {
val
} else {
self.negative_slope * val
};
(row, col, leaky_relu_val)
})
.collect();
let (rows, cols, values) = unzip_triplets(activated_triplets);
let activated_coo = CooTensor::new(rows, cols, values, shape)?;
match input.format() {
crate::SparseFormat::Coo => Ok(Box::new(activated_coo)),
crate::SparseFormat::Csr => Ok(Box::new(CsrTensor::from_coo(&activated_coo)?)),
crate::SparseFormat::Csc => Ok(Box::new(CscTensor::from_coo(&activated_coo)?)),
_ => Ok(Box::new(activated_coo)), }
}
}