cubek-interpolate 0.3.0

CubeK: Interpolation
mod nearest;

pub(crate) use nearest::reference_nearest_backward;

use super::{f32_elem_type, make_random_f32_host, make_zero_handle};
use crate::definition::{InterpolateBackwardProblem, InterpolateMode, InterpolateOptions};
use cubecl::client::Client;
use cubek_test_utils::{
    ExecutionOutcome, HostData, HostDataType, Progress, launch_and_capture_outcome,
};

use crate::interpolate_backward;

pub fn kernel_result(
    client: Client,
    problem: InterpolateBackwardProblem,
    seed: u64,
) -> Result<HostData, String> {
    let dtype = f32_elem_type();

    let out_grad_shape = problem.out_grad_shape.to_vec();

    let input_shape = vec![
        out_grad_shape[0],
        problem.input_size[0],
        problem.input_size[1],
        out_grad_shape[3],
    ];
    let (input_handle, _input_host) = make_random_f32_host(&client, input_shape.clone(), seed);

    let (out_grad_handle, _out_grad_host) =
        make_random_f32_host(&client, out_grad_shape.clone(), seed);

    let input_grad_shape = input_shape;
    let input_grad_handle = make_zero_handle(&client, input_grad_shape, dtype);

    let outcome = launch_and_capture_outcome(&client, &[&input_grad_handle.handle], |c| {
        interpolate_backward(
            c,
            input_handle.clone().binding(),
            out_grad_handle.clone().binding(),
            input_grad_handle.clone().binding(),
            problem.options,
            dtype,
        )
        .into()
    });

    match outcome {
        ExecutionOutcome::CompileError(e) => Err(format!("compile error: {e}")),
        ExecutionOutcome::Executed => Ok(HostData::from_tensor_handle(
            &client,
            input_grad_handle,
            HostDataType::F32,
        )),
    }
}

pub fn cpu_reference_result(
    client: Client,
    problem: InterpolateBackwardProblem,
    seed: u64,
    progress: Option<&Progress>,
) -> Result<HostData, String> {
    let out_grad_shape = problem.out_grad_shape.to_vec();

    if let Some(p) = progress {
        let total: usize = out_grad_shape.iter().product();
        p.set_total(total as u64);
    }

    let (_out_grad_handle, out_grad_host) = make_random_f32_host(&client, out_grad_shape, seed);

    let input_grad_shape = vec![
        problem.out_grad_shape[0],
        problem.input_size[0],
        problem.input_size[1],
        problem.out_grad_shape[3],
    ];

    Ok(reference_for_backward_interpolation_mode(
        &out_grad_host,
        &input_grad_shape,
        &problem.options,
        progress,
    ))
}

pub fn reference_for_backward_interpolation_mode(
    out_grad: &HostData,
    output_shape: &[usize],
    options: &InterpolateOptions,
    progress: Option<&Progress>,
) -> HostData {
    match options.mode {
        InterpolateMode::Nearest(nearest_mode) => {
            reference_nearest_backward(out_grad, output_shape, nearest_mode, progress)
        }
        InterpolateMode::Bilinear => {
            panic!("Bilinear interpolation backward is not supported by CPU reference")
        }
        InterpolateMode::Bicubic => {
            panic!("Bicubic interpolation backward is not supported by CPU reference")
        }
        InterpolateMode::Lanczos3 => {
            panic!("Lanczos3 interpolation backward is not supported by CPU reference")
        }
    }
}