use std::cell::RefCell;
use himada_dispatch::*;
use ndarray::{Array1, Array2};
pub trait HimadaArray1 {
fn himada_dot(&self, other: &Self) -> f64;
fn himada_reduce_sum(&self) -> f64;
fn himada_reduce_max(&self) -> f64;
fn himada_abs_max(&self) -> f64;
fn himada_argmax(&self) -> usize;
fn himada_softmax(&self) -> Array1<f64>;
fn himada_euclidean(&self, other: &Self) -> f64;
fn himada_cosine_similarity(&self, other: &Self) -> f64;
fn himada_negate(&self) -> Array1<f64>;
fn himada_clamp(&self, lo: f64, hi: f64) -> Array1<f64>;
}
pub trait HimadaArray2 {
fn himada_matmul(&self, other: &Self) -> Array2<f64>;
}
thread_local! {
static DOT: RefCell<Dispatch<DotKernel>> = RefCell::new(Dispatch::new("ndarray_dot", vec![]));
static REDUCE_SUM: RefCell<Dispatch<ReduceKernel>> = RefCell::new(Dispatch::new("ndarray_reduce_sum", vec![]));
static REDUCE_MAX: RefCell<Dispatch<ReduceKernel>> = RefCell::new(Dispatch::new("ndarray_reduce_max", vec![]));
static ABS_MAX: RefCell<Dispatch<ReduceKernel>> = RefCell::new(Dispatch::new("ndarray_abs_max", vec![]));
static ARGMAX: RefCell<Dispatch<ArgmaxKernel>> = RefCell::new(Dispatch::new("ndarray_argmax", vec![]));
static SOFTMAX: RefCell<Dispatch<SoftmaxKernel>> = RefCell::new(Dispatch::new("ndarray_softmax", vec![]));
static EUCLIDEAN: RefCell<Dispatch<DotKernel>> = RefCell::new(Dispatch::new("ndarray_euclidean", vec![]));
static COSINE: RefCell<Dispatch<DotKernel>> = RefCell::new(Dispatch::new("ndarray_cosine", vec![]));
static NEGATE: RefCell<Dispatch<SoftmaxKernel>> = RefCell::new(Dispatch::new("ndarray_negate", vec![]));
static CLAMP: RefCell<Dispatch<ClampKernel>> = RefCell::new(Dispatch::new("ndarray_clamp", vec![]));
static MATMUL: RefCell<Dispatch<MatMulKernel>> = RefCell::new(Dispatch::new("ndarray_matmul", vec![]));
}
impl HimadaArray1 for Array1<f64> {
fn himada_dot(&self, other: &Self) -> f64 {
DOT.with(|d| d.borrow_mut().compute(self.as_slice().unwrap(), other.as_slice().unwrap()))
}
fn himada_reduce_sum(&self) -> f64 {
REDUCE_SUM.with(|d| d.borrow_mut().compute(self.as_slice().unwrap()))
}
fn himada_reduce_max(&self) -> f64 {
REDUCE_MAX.with(|d| d.borrow_mut().compute(self.as_slice().unwrap()))
}
fn himada_abs_max(&self) -> f64 {
ABS_MAX.with(|d| d.borrow_mut().compute(self.as_slice().unwrap()))
}
fn himada_argmax(&self) -> usize {
ARGMAX.with(|d| d.borrow_mut().compute(self.as_slice().unwrap()))
}
fn himada_softmax(&self) -> Array1<f64> {
let mut out = vec![0.0; self.len()];
SOFTMAX.with(|d| d.borrow_mut().compute(self.as_slice().unwrap(), &mut out));
Array1::from_vec(out)
}
fn himada_euclidean(&self, other: &Self) -> f64 {
EUCLIDEAN.with(|d| d.borrow_mut().compute(self.as_slice().unwrap(), other.as_slice().unwrap()))
}
fn himada_cosine_similarity(&self, other: &Self) -> f64 {
COSINE.with(|d| d.borrow_mut().compute(self.as_slice().unwrap(), other.as_slice().unwrap()))
}
fn himada_negate(&self) -> Array1<f64> {
let mut out = vec![0.0; self.len()];
NEGATE.with(|d| d.borrow_mut().compute(self.as_slice().unwrap(), &mut out));
Array1::from_vec(out)
}
fn himada_clamp(&self, lo: f64, hi: f64) -> Array1<f64> {
let mut out = vec![0.0; self.len()];
CLAMP.with(|d| d.borrow_mut().compute(self.as_slice().unwrap(), lo, hi, &mut out));
Array1::from_vec(out)
}
}
impl HimadaArray2 for Array2<f64> {
fn himada_matmul(&self, other: &Self) -> Array2<f64> {
let n = self.nrows();
assert_eq!(n, self.ncols());
assert_eq!(n, other.nrows());
assert_eq!(n, other.ncols());
let mut c = vec![0.0; n * n];
MATMUL.with(|d| {
d.borrow_mut().compute(
self.as_slice().unwrap(),
other.as_slice().unwrap(),
&mut c,
n,
)
});
Array2::from_shape_vec((n, n), c).unwrap()
}
}