use cubecl::prelude::*;
use cubecl::server::Handle;
use dspk_core::compute::LaunchGeometry;
use super::kernels::center_rows_kernel;
use super::matmul::{matmul, MatrixView};
use crate::core::{buffer, cast_f32, DspFloat, Scratch};
#[derive(Debug, Clone)]
pub struct DeviceProjection {
weights: Handle,
mean: Handle,
channels: usize,
components: usize,
centred: Scratch,
}
impl DeviceProjection {
pub fn upload<F: DspFloat>(client: &Client, weights: &[f32], mean: &[f32], channels: usize, components: usize) -> Self {
assert_eq!(weights.len(), channels * components, "weights size mismatch");
assert_eq!(mean.len(), channels, "mean size mismatch");
Self {
weights: buffer::upload(client, &cast_f32::<F>(weights)),
mean: buffer::upload(client, &cast_f32::<F>(mean)),
channels,
components,
centred: Scratch::new(),
}
}
pub fn channels(&self) -> usize {
self.channels
}
pub fn components(&self) -> usize {
self.components
}
pub fn project<F: DspFloat>(&mut self, client: &Client, input: &Handle, output: &Handle, samples: usize) {
let total = self.channels * samples;
if total == 0 || self.components == 0 {
return;
}
let centred = self.centred.get::<F>(client, total);
let geom = LaunchGeometry::elementwise(client, total);
unsafe {
center_rows_kernel::launch::<F>(
client,
geom.cube_count,
geom.cube_dim,
BufferArg::from_raw_parts(input.clone(), total),
BufferArg::from_raw_parts(self.mean.clone(), self.channels),
BufferArg::from_raw_parts(centred.clone(), total),
0,
samples as u32,
samples as u32,
total as u32,
);
}
let weights = MatrixView::row_major(&self.weights, self.channels * self.components, self.channels, self.components);
let x = MatrixView::row_major(¢red, total, self.channels, samples);
matmul::<F>(client, &weights.transposed(), &x, output, self.components * samples);
}
}