ruda-solver 0.1.101

Explicit scientific solvers: real/complex/sparse host algebra and opt-in small batched device kernels
Documentation
use super::{
    DeviceSolverError, complex::{Matrix, empty, grid, shape}, general_eig_kernel as kernels,
    large::{HostFloat, alloc},
};
use ruda_core::tensor::DType;
use ruda_kernel::dsl::prelude::*;
use ruda_kernel::tensor::RudaTensor;

pub struct Eigen<R: Runtime> {
    pub values: Matrix<R>,
    pub vectors: Matrix<R>,
    pub info: RudaTensor<R>,
    pub submitted_kernels: usize,
}

pub fn eig<R: Runtime>(a: &Matrix<R>, vectors: bool) -> Result<Eigen<R>, DeviceSolverError> {
    let (batch, n, cols) = shape(a)?;
    if n != cols { return Err(DeviceSolverError::InvalidInput("general eigen decomposition requires square matrices")); }
    super::elements(&[batch, 2])?;
    let work = empty(a, &[batch, n, n])?;
    let z = empty(a, &if vectors { [batch, n, n] } else { [0, 0, 0] })?;
    let scratch = empty(a, &[batch, 1, n])?;
    let values = empty(a, &[batch, 1, n])?;
    let balance = alloc(&a.real, [batch, n], a.real.dtype);
    let scaling = alloc(&a.real, [batch, 2], a.real.dtype);
    let info = alloc(&a.real, [batch], DType::I32);
    let mut submitted = 0;
    if batch != 0 {
        submitted += match a.real.dtype {
            DType::F32 => submit::<f32, R>(a, &work, &z, &scratch, &values, &balance, &scaling, &info, vectors, false),
            DType::F64 => submit::<f64, R>(a, &work, &z, &scratch, &values, &balance, &scaling, &info, vectors, true),
            _ => unreachable!(),
        };
    }
    let vectors = if vectors { work } else { z };
    Ok(Eigen { values, vectors, info, submitted_kernels: submitted })
}

fn submit<F: HostFloat, R: Runtime>(
    a: &Matrix<R>, h: &Matrix<R>, z: &Matrix<R>, scratch: &Matrix<R>, values: &Matrix<R>,
    balance: &RudaTensor<R>, scaling: &RudaTensor<R>, info: &RudaTensor<R>, vectors: bool, wide: bool,
) -> usize {
    let batch = a.real.meta.shape()[0]; let n = a.real.meta.shape()[1];
    let client = &a.real.client; let blocks = grid(batch); let dim = RudaDim::new_1d(256);
    kernels::prepare::launch::<F, R>(client, blocks, dim,
        a.real.clone().into_tensor_arg(), a.imag.clone().into_tensor_arg(),
        h.real.clone().into_array_arg(), h.imag.clone().into_array_arg(),
        z.real.clone().into_array_arg(), z.imag.clone().into_array_arg(),
        balance.clone().into_array_arg(), scaling.clone().into_array_arg(), info.clone().into_array_arg(), n as u32, vectors, wide);
    if n == 0 { return 1; }
    kernels::balance::launch::<F, R>(client, grid(batch), dim,
        h.real.clone().into_array_arg(), h.imag.clone().into_array_arg(), balance.clone().into_array_arg(),
        info.clone().into_array_arg(), n as u32, wide);
    kernels::hessenberg::launch::<F, R>(client, grid(batch), dim,
        h.real.clone().into_array_arg(), h.imag.clone().into_array_arg(),
        z.real.clone().into_array_arg(), z.imag.clone().into_array_arg(),
        scratch.real.clone().into_array_arg(), scratch.imag.clone().into_array_arg(),
        info.clone().into_array_arg(), n as u32, vectors, wide);
    kernels::schur::launch::<F, R>(client, grid(batch), dim,
        h.real.clone().into_array_arg(), h.imag.clone().into_array_arg(),
        z.real.clone().into_array_arg(), z.imag.clone().into_array_arg(),
        values.real.clone().into_array_arg(), values.imag.clone().into_array_arg(),
        scaling.clone().into_array_arg(), info.clone().into_array_arg(), n as u32, vectors, wide);
    if !vectors { return 4; }
    let x = empty(a, &[batch, n, n]).expect("eigenvector workspace size already checked");
    kernels::triangular_vectors::launch::<F, R>(client, grid(batch * n), dim,
        h.real.clone().into_array_arg(), h.imag.clone().into_array_arg(),
        x.real.clone().into_array_arg(), x.imag.clone().into_array_arg(),
        info.clone().into_array_arg(), n as u32, wide);
    kernels::backtransform::launch::<F, R>(client, grid(batch * n), dim,
        z.real.clone().into_array_arg(), z.imag.clone().into_array_arg(),
        x.real.clone().into_array_arg(), x.imag.clone().into_array_arg(),
        h.real.clone().into_array_arg(), h.imag.clone().into_array_arg(),
        balance.clone().into_array_arg(), info.clone().into_array_arg(), n as u32);
    kernels::check_vectors::launch::<F, R>(client, grid(batch), dim,
        h.real.clone().into_array_arg(), h.imag.clone().into_array_arg(), info.clone().into_array_arg(), n as u32);
    7
}