use cubecl::prelude::*;
use super::{FactorReads, Reads, Recipe, RecipeCoords, RecipeExpand, Separable, SeparableExpand};
#[derive(CubeType, Clone)]
pub struct Factors<R: CubeType> {
pub factors: Sequence<R>,
}
impl<R: CubeType> FactorReads for FactorsExpand<R>
where
R::ExpandType: Reads,
{
fn factor_reads(&self, scope: &Scope, factor: usize, axis: crate::Axis) -> bool {
let factor = NativeExpand::from_lit(scope, factor);
self.factors
.__expand_index_method(scope, factor)
.reads(scope, axis)
}
}
#[cube]
impl<R: CubeType> Factors<R> {
pub fn new(factors: Sequence<R>) -> Factors<R> {
Factors::<R> { factors }
}
pub(crate) fn rank(&self) -> comptime_type!(usize) {
let rank = self.factors.len();
comptime!(assert!(
rank > 0,
"Factors: a separable recipe needs at least one factor"
));
rank
}
}
#[cube]
impl<T: Numeric, R: Recipe<T>> Recipe<T> for Factors<R> {
fn evaluate(&self, coordinates: &RecipeCoords) -> T {
let rank = self.rank();
let mut value = self.factors.index(0usize).evaluate(coordinates);
#[unroll]
for f in 1..rank {
value *= self.factors.index(f).evaluate(coordinates);
}
value
}
}
#[cube]
impl<T: Numeric, R: Recipe<T>> Separable<T> for Factors<R> {
fn factors(&self) -> comptime_type!(usize) {
self.rank()
}
fn factor(&self, coordinates: &RecipeCoords, #[comptime] factor: usize) -> T {
self.factors.index(factor).evaluate(coordinates)
}
}