libmir-cuda 0.3.0

CUDA inference backend for libmir
pub(super) fn round_rows_from_pending(pending: &[bool], cursor: usize) -> Vec<usize> {
    (0..pending.len())
        .map(|offset| (cursor + offset) % pending.len())
        .filter(|row| pending[*row])
        .collect()
}

pub(super) const fn valid_chunk(count: usize, remaining: usize, budget: usize) -> bool {
    count > 0 && count <= remaining && count <= budget
}

pub(super) const fn fair_chunk_budget(remaining_budget: usize, rows_left: usize) -> usize {
    remaining_budget.div_ceil(if rows_left == 0 {
        1
    } else {
        rows_left
    })
}

pub(super) const fn row_chunk_budget(
    remaining_budget: usize,
    rows_left: usize,
    completion_first: bool,
) -> usize {
    if completion_first {
        remaining_budget
    } else {
        fair_chunk_budget(remaining_budget, rows_left)
    }
}

pub(super) const fn context_chunk_budget(
    consumed_tokens: usize,
    rows: usize,
    token_budget: usize,
    interleaved_decode: bool,
    reused_prefix: bool,
    completion_first: bool,
) -> usize {
    if completion_first || consumed_tokens < 2_048 || (reused_prefix && !interleaved_decode) {
        usize::MAX
    } else if !interleaved_decode && rows.saturating_mul(2_048) <= token_budget {
        2_048
    } else {
        1_024
    }
}

pub(super) fn reusable_prefix_tokens(
    cached_tokens: usize,
    prompt_tokens: usize,
    block_size: Option<usize>,
    replay_tokens: usize,
) -> usize {
    let cached_tokens = cached_tokens.min(prompt_tokens);
    if replay_tokens > 0 {
        return cached_tokens.saturating_sub(replay_tokens);
    }
    if cached_tokens < prompt_tokens {
        return cached_tokens;
    }
    block_size
        .filter(|size| *size > 0)
        .map_or(0, |size| cached_tokens.saturating_sub(size))
}