cubek-pool 0.3.0

CubeK: Pool
use crate::{
    definition::MaxPoolOptions,
    eval::cpu_reference::{decode_index, decode_index_simple, forward::get_window_coords},
};
use cubek_test_utils::HostData;

pub fn run_max_pool<const N: usize>(
    input: &HostData,
    opts: &MaxPoolOptions<N>,
    out_dims: &[usize],
    in_dims: &[usize],
    out_strides: &[usize],
) -> Vec<f32> {
    let total: usize = out_dims.iter().product();
    let mut out = vec![0.0; total];
    let kernel_dims = opts.window.kernel_size;
    let total_k_elems: usize = kernel_dims.iter().product();

    for (i, out_val) in out.iter_mut().enumerate().take(total) {
        let coords = decode_index(i, out_dims, out_strides);
        let (batch, channel, spatial_out) = (coords[0], coords[N + 1], &coords[1..N + 1]);
        let mut max_val = f32::NEG_INFINITY;

        for k_idx in 0..total_k_elems {
            let k_coords = decode_index_simple(k_idx, &kernel_dims);
            let mut in_coords = vec![0; N + 2];
            in_coords[0] = batch;
            in_coords[N + 1] = channel;

            if let Some(valid_coords) = get_window_coords(
                spatial_out,
                &k_coords,
                opts.window.stride,
                opts.window.padding,
                opts.dilation,
                in_dims,
                in_coords,
            ) {
                max_val = f32::max(max_val, input.get_f32(&valid_coords));
            }
        }
        *out_val = if max_val == f32::NEG_INFINITY {
            0.0
        } else {
            max_val
        };
    }
    out
}

pub fn run_max_pool_with_indices<const N: usize>(
    input: &HostData,
    opts: &MaxPoolOptions<N>,
    out_dims: &[usize],
    in_dims: &[usize],
    out_strides: &[usize],
) -> (Vec<f32>, Vec<i32>) {
    let total: usize = out_dims.iter().product();
    let mut out = vec![0.0; total];
    let mut indices = vec![0i32; total];
    let kernel_dims = opts.window.kernel_size;
    let total_k_elems: usize = kernel_dims.iter().product();

    for i in 0..total {
        let coords = decode_index(i, out_dims, out_strides);
        let (batch, channel, spatial_out) = (coords[0], coords[N + 1], &coords[1..N + 1]);
        let mut max_val = f32::NEG_INFINITY;
        let mut max_idx = 0i32;

        for k_idx in 0..total_k_elems {
            let k_coords = decode_index_simple(k_idx, &kernel_dims);
            let mut in_coords = vec![0; N + 2];
            in_coords[0] = batch;
            in_coords[N + 1] = channel;

            if let Some(valid_coords) = get_window_coords(
                spatial_out,
                &k_coords,
                opts.window.stride,
                opts.window.padding,
                opts.dilation,
                in_dims,
                in_coords,
            ) {
                let val = input.get_f32(&valid_coords);
                if val > max_val {
                    max_val = val;

                    let spatial_in = &valid_coords[1..N + 1];
                    let mut current_spatial_idx = 0usize;
                    let mut multiplier = 1usize;
                    for d in (0..N).rev() {
                        current_spatial_idx += spatial_in[d] * multiplier;
                        multiplier *= in_dims[d + 1];
                    }

                    max_idx = current_spatial_idx as i32;
                }
            }
        }

        out[i] = if max_val == f32::NEG_INFINITY {
            0.0
        } else {
            max_val
        };
        indices[i] = max_idx;
    }

    (out, indices)
}