use crate::prelude::{Scalar, TensorExpr, TensorResult};
use crate::shape::{ShapeError, Stride};
use crate::tensor::{from_vec_with_op, TensorBase};
pub(crate) fn coordinates_to_index<Idx>(coords: Idx, strides: &Stride) -> usize
where
Idx: AsRef<[usize]>,
{
coords
.as_ref()
.iter()
.zip(strides.iter())
.fold(0, |acc, (&i, &s)| acc + i * s)
}
pub fn matmul<T>(lhs: &TensorBase<T>, rhs: &TensorBase<T>) -> TensorResult<TensorBase<T>>
where
T: Scalar,
{
if lhs.shape().rank() != rhs.shape().rank() {
return Err(ShapeError::DimensionMismatch.into());
}
let shape = lhs.shape().matmul_shape(rhs.shape()).unwrap();
let mut result = vec![T::zero(); shape.size()];
for i in 0..lhs.shape().nrows() {
for j in 0..rhs.shape().ncols() {
for k in 0..lhs.shape().ncols() {
let pos = i * rhs.shape().ncols() + j;
let left = i * lhs.shape().ncols() + k;
let right = k * rhs.shape().ncols() + j;
result[pos] += lhs.data[left] * rhs.data[right];
}
}
}
let op = TensorExpr::matmul(lhs.clone(), rhs.clone());
let tensor = from_vec_with_op(false, op, shape, result);
Ok(tensor)
}
macro_rules! i {
($($x:expr),*) => {
vec![$($x),*]
};
}
macro_rules! impl_partial_eq {
($s:ident -> $cmp:tt: [$($t:ty),*]) => {
$(
impl_partial_eq!($s -> $cmp, $t);
)*
};
($s:ident -> $cmp:tt, $t:ty) => {
impl PartialEq<$t> for $s {
fn eq(&self, other: &$t) -> bool {
self.$cmp == *other
}
}
impl PartialEq<$s> for $t {
fn eq(&self, other: &$s) -> bool {
*self == other.$cmp
}
}
};
}
macro_rules! izip {
( @closure $p:pat => $tup:expr ) => {
|$p| $tup
};
( @closure $p:pat => ( $($tup:tt)* ) , $_iter:expr $( , $tail:expr )* ) => {
izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*)
};
($first:expr $(,)*) => {
IntoIterator::into_iter($first)
};
($first:expr, $second:expr $(,)*) => {
izip!($first)
.zip($second)
};
( $first:expr $( , $rest:expr )* $(,)* ) => {
izip!($first)
$(
.zip($rest)
)*
.map(
izip!(@closure a => (a) $( , $rest )*)
)
};
}