libmir-cuda 0.1.0

CUDA inference backend for libmir
use mircuda::{
    DeviceBuffer, PairedVariableGroupedFp4Launch, PairedVariableGroupedFp4Plan,
    VariableGroupedFp4Metadata, VariableGroupedFp4Operands, bf16,
};

use super::{super::bucketed_moe::ExpertBuckets, BucketedNvFp4Projection, validate_output};
use crate::{CudaBackend, NvFp4ExpertBank, Result, kernels::NvFp4BucketPreparation};

#[derive(Debug)]
pub(in crate::backend::linear::nvfp4::selected) struct BucketedNvFp4PairBf16 {
    plan: PairedVariableGroupedFp4Plan,
    left: BucketedNvFp4Projection,
    right: BucketedNvFp4Projection,
}

impl BucketedNvFp4PairBf16 {
    pub(in crate::backend::linear::nvfp4::selected) fn new(
        backend: &CudaBackend,
        tokens: usize,
        selected: usize,
        left_bank: NvFp4ExpertBank,
        right_bank: NvFp4ExpertBank,
    ) -> Result<Self> {
        let left = BucketedNvFp4Projection::new(backend, tokens, selected, left_bank)?;
        let right = BucketedNvFp4Projection::new(backend, tokens, selected, right_bank)?;
        let plan = PairedVariableGroupedFp4Plan::new(
            &backend.inner.context,
            &backend.inner.stream,
            left.plan_spec()?,
        )?;
        Ok(Self { plan, left, right })
    }

    #[allow(clippy::too_many_arguments)]
    pub(in crate::backend::linear::nvfp4::selected) fn execute(
        &mut self,
        preparation: &NvFp4BucketPreparation,
        buckets: &ExpertBuckets,
        input: &DeviceBuffer<bf16>,
        selected: &DeviceBuffer<u32>,
        left_output: &mut DeviceBuffer<bf16>,
        right_output: &mut DeviceBuffer<bf16>,
    ) -> Result<()> {
        BucketedNvFp4Projection::quantize_pair(
            preparation, buckets, input, selected, &mut self.left, &mut self.right,
        )?;
        validate_output(&self.left, left_output)?;
        validate_output(&self.right, right_output)?;
        let Self { plan, left, right } = self;
        let mut launch = PairedVariableGroupedFp4Launch {
            left: operands(left, left_output),
            right: operands(right, right_output),
            metadata: VariableGroupedFp4Metadata {
                indices: &buckets.indices,
                rows: &buckets.counts,
                offsets: &buckets.offsets,
            },
        };
        Ok(plan.execute(&left.stream, &mut launch)?)
    }

    pub(in crate::backend::linear::nvfp4::selected) fn output_elements(&self) -> Result<usize> {
        self.left.output_elements()
    }

    pub(in crate::backend::linear::nvfp4::selected) const fn output_features(&self) -> usize {
        self.left.output_features()
    }
}

fn operands<'a>(
    projection: &'a BucketedNvFp4Projection,
    output: &'a mut DeviceBuffer<bf16>,
) -> VariableGroupedFp4Operands<'a> {
    VariableGroupedFp4Operands {
        a: &projection.packed,
        a_scales: &projection.scales,
        b: &projection.bank.weight,
        b_scales: &projection.bank.cutlass_scales,
        alphas: &projection.bank.combined_scales,
        output,
    }
}