pub mod op;
pub use op::{AddOp, BinaryScalarOp, MulOp, SubOp};
use strided_kernel::{reduce, zip_map2_into, Exec, StridedView, StridedViewMut};
use tenferro_tensor::col_major_strides;
use tenferro_tensor::{DynRank, Host, StrideVec, TypedTensor};
fn strides_for(shape: &[usize]) -> crate::Result<StrideVec> {
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 TypedTensor<T, DynRank, Host>,
lhs: &TypedTensor<T, DynRank, Host>,
rhs: &TypedTensor<T, DynRank, Host>,
exec: Exec<'_>,
) -> 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 mut destination_view: StridedViewMut<'_, T> =
StridedViewMut::new(destination.host_data_mut(), lhs.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),
exec,
)
.map_err(|err| crate::Error::backend_source(op, err))
}
pub fn scalar_fold<T, Op>(
op: &'static str,
source: &TypedTensor<T, DynRank, Host>,
init: T,
exec: Exec<'_>,
) -> 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, exec)
.map_err(|err| crate::Error::backend_source(op, err))
}
#[cfg(test)]
mod tests;