use crate::{element::JitElement, ops::numeric::empty_device, tensor::JitTensor, JitRuntime};
use cubecl::frontend::{Numeric, Tensor, ABSOLUTE_POS};
use cubecl::linalg::tensor::index_offset_with_layout;
use cubecl::CubeDim;
use cubecl::{calculate_cube_count_elemwise, prelude::*};
#[cube(launch_unchecked)]
fn gather_kernel<T: Numeric, I: Numeric>(
input: &Tensor<Line<T>>,
indices: &Tensor<Line<I>>,
output: &mut Tensor<Line<T>>,
dim: &u32,
) {
if ABSOLUTE_POS >= indices.len() {
return;
}
let index = indices[ABSOLUTE_POS];
let stride = input.stride(*dim);
let mut offset = u32::cast_from(index);
offset *= stride;
if *dim > 0 {
let offset_before = index_offset_with_layout(input, output, ABSOLUTE_POS, 0, *dim, false);
offset += offset_before;
}
let offset_after =
index_offset_with_layout(input, output, ABSOLUTE_POS, *dim + 1, input.rank(), false);
offset += offset_after;
output[ABSOLUTE_POS] = input[offset];
}
pub(crate) fn gather<R: JitRuntime, E: JitElement, I: JitElement>(
dim: usize,
tensor: JitTensor<R>,
indices: JitTensor<R>,
) -> JitTensor<R> {
let shape_output = indices.shape.clone();
let total_elem = shape_output.num_elements();
let output = empty_device::<R, E>(tensor.client.clone(), tensor.device.clone(), shape_output);
let cube_dim = CubeDim::default();
let cube_count = calculate_cube_count_elemwise(total_elem, cube_dim);
unsafe {
gather_kernel::launch_unchecked::<E, I, R>(
&tensor.client,
cube_count,
cube_dim,
tensor.as_tensor_arg::<E>(1),
indices.as_tensor_arg::<I>(1),
output.as_tensor_arg::<E>(1),
ScalarArg::new(dim as u32),
)
}
output
}