cubek-pool 0.3.0

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

pub fn run_adaptive_avg_pool<const N: usize>(
    input: &HostData,
    _opts: &AdaptiveAvgPoolOptions<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];

    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 starts = [0; N];
        let mut ends = [0; N];
        for d in 0..N {
            starts[d] = (spatial_out[d] * in_dims[d + 1]) / out_dims[d + 1];
            ends[d] = ((spatial_out[d] + 1) * in_dims[d + 1])
                .div_ceil(out_dims[d + 1])
                .min(in_dims[d + 1]);
        }

        let k_dims: Vec<usize> = (0..N).map(|d| ends[d] - starts[d]).collect();
        let total_k: usize = k_dims.iter().product();
        let (mut sum, mut count) = (0.0, 0);

        for k_idx in 0..total_k {
            let k_coords = decode_index_simple(k_idx, &k_dims);
            let mut in_coords = vec![0; N + 2];
            in_coords[0] = batch;
            in_coords[N + 1] = channel;
            for d in 0..N {
                in_coords[d + 1] = starts[d] + k_coords[d];
            }

            sum += input.get_f32(&in_coords);
            count += 1;
        }
        *out_val = if count > 0 { sum / count as f32 } else { 0.0 };
    }
    out
}