use cubecl::prelude::*;
use super::monoid::{Carrier, Monoid, comptime_only};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct Semiring {
add: Monoid,
mul: Monoid,
}
impl Semiring {
pub const SUM_PROD: Self = Self {
add: Monoid::Sum,
mul: Monoid::Prod,
};
pub const MIN_SUM: Self = Self {
add: Monoid::Min,
mul: Monoid::Sum,
};
pub const MAX_SUM: Self = Self {
add: Monoid::Max,
mul: Monoid::Sum,
};
pub const fn add(self) -> Monoid {
self.add
}
pub const fn mul(self) -> Monoid {
self.mul
}
}
#[cube]
impl Semiring {
fn step_of<T: Carrier + CubePrimitive>(
lhs: T,
rhs: T,
acc: T,
#[comptime] semiring: Semiring,
) -> T {
if comptime!(semiring == Semiring::SUM_PROD) {
fma(lhs, rhs, acc)
} else {
let product = semiring.mul().combine::<T>(lhs, rhs);
semiring.add().combine::<T>(product, acc)
}
}
}
impl Semiring {
pub fn step<T: Carrier + CubePrimitive>(self, lhs: T, rhs: T, acc: T) -> T {
Semiring::step_of::<T>(lhs, rhs, acc, self)
}
pub fn __expand_step_method<T: Carrier + CubePrimitive>(
self,
scope: &Scope,
lhs: T::ExpandType,
rhs: T::ExpandType,
acc: T::ExpandType,
) -> T::ExpandType {
Semiring::__expand_step_of::<T>(scope, lhs, rhs, acc, self)
}
}
comptime_only!(Semiring);