use crate::{CausalTensor, Tensor};
use deep_causality_haft::{Applicative, BoundedComonad, Foldable, Functor, HKT, Monad};
use deep_causality_num::Zero;
pub struct CausalTensorWitness;
impl HKT for CausalTensorWitness {
type Type<T> = CausalTensor<T>;
}
impl Applicative<CausalTensorWitness> for CausalTensorWitness {
fn pure<T>(value: T) -> CausalTensor<T> {
CausalTensor::from_vec(vec![value], &[])
}
fn apply<A, B, Func>(f_ab: CausalTensor<Func>, f_a: CausalTensor<A>) -> CausalTensor<B>
where
Func: FnMut(A) -> B,
{
let shape_a = f_a.shape().to_vec();
let mut funcs = f_ab.into_vec();
let args = f_a.into_vec();
let result_data = if funcs.len() == 1 {
let f = funcs.pop().unwrap();
args.into_iter().map(f).collect()
} else if funcs.len() != args.len() {
return CausalTensor::from_vec(vec![], &[0]);
} else {
let mut data = Vec::with_capacity(args.len());
for (mut f, a) in funcs.into_iter().zip(args.into_iter()) {
data.push(f(a));
}
data
};
CausalTensor::from_vec(result_data, &shape_a)
}
}
impl Foldable<CausalTensorWitness> for CausalTensorWitness {
fn fold<A, B, Func>(fa: CausalTensor<A>, init: B, f: Func) -> B
where
Func: FnMut(B, A) -> B,
{
fa.into_vec().into_iter().fold(init, f)
}
}
impl Functor<CausalTensorWitness> for CausalTensorWitness {
fn fmap<A, B, Func>(m_a: CausalTensor<A>, f: Func) -> CausalTensor<B>
where
Func: FnMut(A) -> B,
{
let shape = m_a.shape().to_vec(); let new_data = m_a.into_vec().into_iter().map(f).collect();
CausalTensor::from_vec(new_data, &shape)
}
}
impl Monad<CausalTensorWitness> for CausalTensorWitness {
fn bind<A, B, Func>(m_a: CausalTensor<A>, mut f: Func) -> CausalTensor<B>
where
Func: FnMut(A) -> CausalTensor<B>,
{
let mut result_data = Vec::new();
for a in m_a.into_vec() {
let mb = f(a);
result_data.extend(mb.into_vec());
}
let len = result_data.len();
CausalTensor::from_vec(result_data, &[len])
}
}
impl BoundedComonad<CausalTensorWitness> for CausalTensorWitness {
fn extract<A>(fa: &CausalTensor<A>) -> A
where
A: Clone,
{
if fa.ndim() == 0 && !fa.is_empty() {
let v = fa.to_vec();
v.into_iter().next().unwrap()
} else if fa.is_empty() {
panic!("CoMonad::extract cannot be called on an empty CausalTensor.");
} else {
let v = fa.to_vec();
v.into_iter().next().unwrap()
}
}
fn extend<A, B, Func>(fa: &CausalTensor<A>, mut f: Func) -> CausalTensor<B>
where
Func: FnMut(&CausalTensor<A>) -> B,
A: Zero + Copy + Clone,
B: Zero + Copy + Clone,
{
let len = fa.len();
let new_data: Vec<B> = (0..len)
.map(|i| {
let focused_view = fa.shifted_view(i);
f(&focused_view)
})
.collect();
CausalTensor::from_slice(&new_data, fa.shape())
}
}
use deep_causality_haft::BoundedAdjunction;
use std::ops::{Add, Mul};
impl BoundedAdjunction<CausalTensorWitness, CausalTensorWitness, Vec<usize>>
for CausalTensorWitness
{
fn left_adjunct<A, B, F>(ctx: &Vec<usize>, a: A, f: F) -> CausalTensor<B>
where
F: Fn(CausalTensor<A>) -> B,
A: Clone + Zero + Copy + PartialEq,
B: Clone,
{
let t_t_a = Self::unit(ctx, a);
<Self as Functor<Self>>::fmap(t_t_a, f)
}
fn right_adjunct<A, B, F>(ctx: &Vec<usize>, la: CausalTensor<A>, f: F) -> B
where
F: FnMut(A) -> CausalTensor<B>,
A: Clone + Zero,
B: Clone + Zero + Add<Output = B> + Mul<Output = B>,
{
let mapped = <Self as Functor<Self>>::fmap(la, f);
Self::counit(ctx, mapped)
}
fn unit<A>(ctx: &Vec<usize>, a: A) -> CausalTensor<CausalTensor<A>>
where
A: Clone + Zero + Copy + PartialEq,
{
if !ctx.is_empty() {
panic!(
"BoundedAdjunction::unit for CausalTensor requires an empty shape vector (Scalar). Provided shape: {:?}",
ctx
);
}
let inner = CausalTensor::from_vec(vec![a], ctx);
CausalTensor::from_vec(vec![inner], &[])
}
fn counit<B>(_ctx: &Vec<usize>, lrb: CausalTensor<CausalTensor<B>>) -> B
where
B: Clone + Zero + Add<Output = B> + Mul<Output = B>,
{
let flattened = <Self as Monad<Self>>::bind(lrb, |x| x);
<Self as BoundedComonad<Self>>::extract(&flattened)
}
}