use std::{cmp::max, sync::Arc};
use openvm_cuda_common::{d_buffer::DeviceBuffer, stream::GpuDeviceCtx};
use openvm_stark_backend::prover::MatrixDimensions;
use super::errors::FoldPleError;
use crate::{
base::DeviceMatrix,
cuda::{batch_ntt_small::validate_gpu_l_skip, logup_zerocheck::fold_ple_from_evals},
prelude::{EF, F},
};
pub fn fold_ple_evals_rotate(
l_skip: usize,
d_omega_skip_pows: &DeviceBuffer<F>,
trace_evals: &DeviceMatrix<F>,
d_inv_lagrange_denoms_r0: &DeviceBuffer<EF>,
need_rot: bool,
device_ctx: &GpuDeviceCtx,
) -> Result<DeviceMatrix<EF>, FoldPleError> {
validate_gpu_l_skip(l_skip)?;
let width = trace_evals.width();
let height = trace_evals.height();
let num_x = max(height >> l_skip, 1);
let out_width = width * if need_rot { 2 } else { 1 };
let folded_buf = DeviceBuffer::<EF>::with_capacity_on(num_x * out_width, device_ctx);
unsafe {
fold_ple_evals_gpu(
l_skip,
d_omega_skip_pows,
trace_evals,
folded_buf.as_mut_ptr(),
d_inv_lagrange_denoms_r0,
false,
device_ctx,
)?;
if need_rot {
fold_ple_evals_gpu(
l_skip,
d_omega_skip_pows,
trace_evals,
folded_buf.as_mut_ptr().add(num_x * width),
d_inv_lagrange_denoms_r0,
true,
device_ctx,
)?;
}
}
let folded = DeviceMatrix::new(Arc::new(folded_buf), num_x, out_width);
Ok(folded)
}
pub unsafe fn fold_ple_evals_gpu(
l_skip: usize,
d_omega_skip_pows: &DeviceBuffer<F>,
mat: &DeviceMatrix<F>,
output: *mut EF,
d_inv_lagrange_denoms_r0: &DeviceBuffer<EF>,
rotate: bool,
device_ctx: &GpuDeviceCtx,
) -> Result<(), FoldPleError> {
validate_gpu_l_skip(l_skip)?;
let height = mat.height();
let width = mat.width();
if height == 0 || width == 0 {
return Ok(());
}
let skip_domain = d_omega_skip_pows.len();
debug_assert_eq!(skip_domain, 1 << l_skip);
let lifted_height = max(skip_domain, height);
let num_x = lifted_height / skip_domain;
unsafe {
fold_ple_from_evals(
mat.buffer(),
output,
d_omega_skip_pows,
d_inv_lagrange_denoms_r0,
height as u32,
width as u32,
l_skip as u32,
num_x as u32,
rotate,
device_ctx.stream.as_raw(),
)?;
}
Ok(())
}