ruPRIM 0.1.7

Parallel primitives, reductions, scans, and indexing for Ruda.
Documentation
use ruda_core::tensor::{DType, TensorMetadata, element::Scalar as TensorScalar};
use ruda_kernel::dsl as kernel_dsl;
use ruda_kernel::dsl::{calculate_ruda_count_elemwise, prelude::*};
use ruda_kernel::library::tensor::layout::linear::LinearView;
use ruda_kernel::tensor::{
    RudaTensor,
    allocation::empty_device_dtype,
    layout::{address_type, broadcast_shape, max_vector_size},
};

#[ruda(launch_unchecked, address_type = "dynamic")]
fn tensor_kernel<F: Float, I: Int, N: Size>(
    lhs: &LinearView<Vector<F, N>>,
    rhs: &LinearView<Vector<I, N>>,
    out: &mut LinearView<Vector<F, N>, ReadWrite>,
    #[define(F, I)] _dtypes: [StorageType; 2],
) where F: Powi<I> {
    if !out.is_in_bounds(ABSOLUTE_POS) {
        terminate!();
    }
    out[ABSOLUTE_POS] = Vector::powi(lhs[ABSOLUTE_POS], rhs[ABSOLUTE_POS]);
}

#[ruda(launch_unchecked, address_type = "dynamic")]
fn scalar_kernel<F: Float, I: Int, N: Size>(
    input: &LinearView<Vector<F, N>>,
    exponent: InputScalar,
    out: &mut LinearView<Vector<F, N>, ReadWrite>,
    #[define(F, I)] _dtypes: [StorageType; 2],
) where F: Powi<I> {
    if !out.is_in_bounds(ABSOLUTE_POS) {
        terminate!();
    }
    out[ABSOLUTE_POS] = Vector::powi(input[ABSOLUTE_POS], Vector::new(exponent.get::<I>()));
}

pub fn tensor<R: Runtime>(lhs: RudaTensor<R>, rhs: RudaTensor<R>) -> RudaTensor<R> {
    let vector_size = max_vector_size(&lhs).min(max_vector_size(&rhs));
    let shape = broadcast_shape(&[&lhs, &rhs]);
    let dtype = lhs.dtype;
    let dtypes = [dtype.into(), rhs.dtype.into()];
    let client = lhs.client.clone();
    let working_units = shape.num_elements() / vector_size as usize;
    let ruda_dim = RudaDim::new(client.properties(), working_units);
    let ruda_count = calculate_ruda_count_elemwise(&client, working_units, ruda_dim);

    unsafe {
        if lhs.can_mut_broadcast(&rhs) {
            tensor_kernel::launch_unchecked::<R>(
                &client,
                ruda_count,
                ruda_dim,
                address_type!(lhs, rhs),
                vector_size,
                lhs.clone().into_linear_view(),
                rhs.into_linear_view_like(&lhs),
                lhs.as_linear_view_alias(0),
                dtypes,
            );
            lhs
        } else {
            let output = empty_device_dtype(client.clone(), lhs.device.clone(), shape, dtype);
            tensor_kernel::launch_unchecked::<R>(
                &client,
                ruda_count,
                ruda_dim,
                address_type!(lhs, rhs, output),
                vector_size,
                lhs.into_linear_view_like(&output),
                rhs.into_linear_view_like(&output),
                output.clone().into_linear_view(),
                dtypes,
            );
            output
        }
    }
}

pub fn scalar<R: Runtime>(input: RudaTensor<R>, exponent: TensorScalar) -> RudaTensor<R> {
    let (exponent, exponent_dtype) = match exponent {
        TensorScalar::UInt(value) => {
            let dtype = if u32::try_from(value).is_ok() { DType::U32 } else { DType::U64 };
            (TensorScalar::UInt(value), dtype)
        }
        value => {
            let value = value.elem::<i64>();
            let dtype = if i32::try_from(value).is_ok() { DType::I32 } else { DType::I64 };
            (TensorScalar::Int(value), dtype)
        }
    };
    let exponent = InputScalar::new(exponent, exponent_dtype);
    let vector_size = max_vector_size(&input);
    let client = input.client.clone();
    let working_units = input.meta.num_elements() / vector_size as usize;
    let ruda_dim = RudaDim::new(client.properties(), working_units);
    let ruda_count = calculate_ruda_count_elemwise(&client, working_units, ruda_dim);
    let dtypes = [input.dtype.into(), exponent_dtype.into()];

    unsafe {
        if input.can_mut() && input.is_nonoverlapping() {
            scalar_kernel::launch_unchecked::<R>(
                &client,
                ruda_count,
                ruda_dim,
                address_type!(input),
                vector_size,
                input.clone().into_linear_view(),
                exponent,
                input.as_linear_view_alias(0),
                dtypes,
            );
            input
        } else {
            let output = empty_device_dtype(
                client.clone(), input.device.clone(), input.shape(), input.dtype,
            );
            scalar_kernel::launch_unchecked::<R>(
                &client,
                ruda_count,
                ruda_dim,
                address_type!(input, output),
                vector_size,
                input.into_linear_view(),
                exponent,
                output.clone().into_linear_view(),
                dtypes,
            );
            output
        }
    }
}