pub mod op;
pub use op::{AddOp, BinaryScalarOp, MulOp, SubOp};
use strided_kernel::{reduce, zip_map2_into, StridedView, StridedViewMut};
use tenferro_tensor::col_major_strides;
use tenferro_tensor_core::HostTensor;
fn strides_for(shape: &[usize]) -> crate::Result<Vec<isize>> {
col_major_strides(shape)
}
fn require_same_shape(op: &'static str, lhs: &[usize], rhs: &[usize]) -> crate::Result<()> {
if lhs == rhs {
Ok(())
} else {
Err(crate::Error::shape_mismatch(op, lhs.to_vec(), rhs.to_vec()))
}
}
pub fn scalar_binary_into<T, Op>(
op: &'static str,
destination: &mut HostTensor<T>,
lhs: &HostTensor<T>,
rhs: &HostTensor<T>,
) -> crate::Result<()>
where
T: Copy + Send + Sync,
Op: BinaryScalarOp<T>,
{
require_same_shape(op, destination.shape(), lhs.shape())?;
require_same_shape(op, lhs.shape(), rhs.shape())?;
let strides = strides_for(lhs.shape())?;
let destination_shape = destination.shape().to_vec();
let mut destination_view: StridedViewMut<'_, T> =
StridedViewMut::new(destination.as_mut_slice(), &destination_shape, &strides, 0)
.map_err(|err| crate::Error::backend_source(op, err))?;
let lhs_view: StridedView<'_, T> = StridedView::new(lhs.as_slice(), lhs.shape(), &strides, 0)
.map_err(|err| crate::Error::backend_source(op, err))?;
let rhs_view: StridedView<'_, T> = StridedView::new(rhs.as_slice(), rhs.shape(), &strides, 0)
.map_err(|err| crate::Error::backend_source(op, err))?;
zip_map2_into(&mut destination_view, &lhs_view, &rhs_view, |a, b| {
Op::apply(a, b)
})
.map_err(|err| crate::Error::backend_source(op, err))
}
pub fn scalar_fold<T, Op>(op: &'static str, source: &HostTensor<T>, init: T) -> crate::Result<T>
where
T: Copy + Send + Sync,
Op: BinaryScalarOp<T>,
{
let strides = strides_for(source.shape())?;
let view: StridedView<'_, T> = StridedView::new(source.as_slice(), source.shape(), &strides, 0)
.map_err(|err| crate::Error::backend_source(op, err))?;
reduce(&view, |element| element, |a, b| Op::apply(a, b), init)
.map_err(|err| crate::Error::backend_source(op, err))
}
#[cfg(test)]
mod tests;