cubek-interpolate 0.3.0

CubeK: Interpolation
use cubecl::zspace::Shape;
use cubek_test_utils::{HostData, HostDataVec, Progress};

use super::super::{contiguous_strides, for_each_output_coord};

pub fn reference_bilinear(
    input: &HostData,
    output_shape: &[usize],
    align_corners: bool,
    progress: Option<&Progress>,
) -> HostData {
    let mut data = vec![0.0f32; output_shape.iter().product()];

    for_each_output_coord(output_shape, |linear, out_coord| {
        let b = out_coord[0];
        let y_out = out_coord[1];
        let x_out = out_coord[2];
        let c = out_coord[3];

        let fy = if align_corners {
            let numerator = (input.shape[1] - 1) as f32;
            let denominator = (output_shape[1] - 1).max(1) as f32;
            y_out as f32 * (numerator / denominator)
        } else {
            let in_size = input.shape[1] as f32;
            let out_size = output_shape[1] as f32;
            ((y_out as f32 + 0.5) * (in_size / out_size) - 0.5).clamp(0.0, in_size - 1.0)
        };

        let fx = if align_corners {
            let numerator = (input.shape[2] - 1) as f32;
            let denominator = (output_shape[2] - 1).max(1) as f32;
            x_out as f32 * (numerator / denominator)
        } else {
            let in_size = input.shape[2] as f32;
            let out_size = output_shape[2] as f32;
            ((x_out as f32 + 0.5) * (in_size / out_size) - 0.5).clamp(0.0, in_size - 1.0)
        };

        let y0 = fy.floor() as usize;
        let x0 = fx.floor() as usize;
        let y1 = (y0 + 1).min(input.shape[1] - 1);
        let x1 = (x0 + 1).min(input.shape[2] - 1);

        let dy = fy - y0 as f32;
        let dx = fx - x0 as f32;

        let v00 = input.get_f32(&[b, y0, x0, c]);
        let v01 = input.get_f32(&[b, y0, x1, c]);
        let v10 = input.get_f32(&[b, y1, x0, c]);
        let v11 = input.get_f32(&[b, y1, x1, c]);

        let v0 = v00 * (1.0 - dx) + v01 * dx;
        let v1 = v10 * (1.0 - dx) + v11 * dx;
        let value = v0 * (1.0 - dy) + v1 * dy;

        data[linear] = value;

        if let Some(p) = progress {
            p.bump();
        }
    });

    HostData {
        data: HostDataVec::F32(data),
        shape: Shape::from(output_shape.to_vec()),
        strides: contiguous_strides(output_shape),
    }
}