use cubecl::prelude::*;
use cubecl::terminate;
#[cube(launch_unchecked)]
pub fn nlm_mc_chain_compose(
pair_ring: &Array<i32>,
mv_field: &mut Array<i32>,
start_pair_slot: u32,
#[comptime] forward: bool,
#[comptime] steps: u32,
#[comptime] pair_ring_slots: u32,
#[comptime] dir_len: u32,
#[comptime] slot_len: u32,
#[comptime] step: u32,
#[comptime] width: u32,
#[comptime] height: u32,
#[comptime] blocks_x: u32,
#[comptime] blocks_y: u32,
) {
let bx = ABSOLUTE_POS_X;
let by = ABSOLUTE_POS_Y;
if bx >= blocks_x || by >= blocks_y {
terminate!();
}
let direction = comptime!(if forward { 0u32 } else { 1u32 });
let mut pos_x = (bx * step + step / 2) as i32;
let mut pos_y = (by * step + step / 2) as i32;
let mut acc_x = 0i32;
let mut acc_y = 0i32;
for i in 0..steps {
let slot = if forward {
(start_pair_slot + i) % pair_ring_slots
} else {
(start_pair_slot + pair_ring_slots - i) % pair_ring_slots
};
let cx = clamp_i32(pos_x, width as i32) as u32;
let cy = clamp_i32(pos_y, height as i32) as u32;
let bxi = (cx / step).min(blocks_x - 1);
let byi = (cy / step).min(blocks_y - 1);
let base = slot * slot_len + direction * dir_len + (byi * blocks_x + bxi) * 2;
let fx = pair_ring[base as usize];
let fy = pair_ring[(base + 1) as usize];
acc_x += fx;
acc_y += fy;
pos_x += fx;
pos_y += fy;
}
let out_idx = ((by * blocks_x + bx) * 2) as usize;
mv_field[out_idx] = acc_x;
mv_field[out_idx + 1] = acc_y;
}
#[cube(launch_unchecked)]
pub fn nlm_mc_pair_zero(dst: &mut Array<i32>, #[comptime] length: u32, #[comptime] total_threads: u32) {
let mut idx = ABSOLUTE_POS_X;
while idx < length {
dst[idx as usize] = 0i32;
idx += total_threads;
}
}
#[cube]
fn clamp_i32(value: i32, limit: i32) -> i32 {
let mut result = value;
if value < 0 {
result = 0;
} else if value >= limit {
result = limit - 1;
}
result
}