tenferro-linalg 0.2.0

Linear algebra traced APIs, eager helpers, extension runtime, and optional AD rules for tenferro.
Documentation
use std::sync::Arc;

use tenferro_runtime::extension::ExtensionOp;
use tenferro_tensor::{
    Buffer, BufferHandle, DType, DeviceId, DeviceKind, Error, GpuBackendKind, MemoryKind,
    Placement, Tensor, TypedTensor,
};

use super::{promote_dtypes, LinalgExtensionOp, LinalgOp};

#[test]
fn eager_linalg_rejects_cuda_tensor_when_cuda_feature_is_disabled() {
    let tensor = Tensor::F64(
        TypedTensor::from_buffer_col_major(
            vec![2, 2],
            Buffer::Backend(Arc::new(BufferHandle::<f64>::new_with_len(7, 4))),
            Placement {
                memory_kind: MemoryKind::Device,
                device: Some(DeviceId {
                    kind: DeviceKind::Gpu(GpuBackendKind::Cuda),
                    ordinal: 0,
                }),
            },
        )
        .unwrap(),
    );
    let op = LinalgExtensionOp::new(LinalgOp::Cholesky);

    let err = op.eager_execute(&[&tensor]).unwrap_err();

    match err {
        Error::BackendFailure { op, message } => {
            assert_eq!(op, "linalg_eager_execute");
            assert!(message.contains("cuda feature"));
            assert!(message.contains("download"));
        }
        other => panic!("expected BackendFailure, got {other:?}"),
    }
}

#[test]
fn infer_output_meta_returns_error_on_input_count_mismatch() {
    let op = LinalgExtensionOp::new(LinalgOp::Cholesky);

    let err = op.infer_output_meta(&[], &[]).unwrap_err();

    assert!(matches!(
        err,
        Error::InvalidConfig {
            op: "tenferro-linalg",
            ..
        }
    ));
}

#[test]
fn extension_dtype_promotion_delegates_to_canonical_tensor_rules() {
    let source = include_str!("../extension.rs");
    assert!(
        !source.contains("fn promote_dtype("),
        "linalg extension metadata must not duplicate the canonical dtype promotion lattice"
    );

    let dtypes = [
        DType::Bool,
        DType::I32,
        DType::I64,
        DType::F32,
        DType::F64,
        DType::C32,
        DType::C64,
    ];
    for lhs in dtypes {
        for rhs in dtypes {
            assert_eq!(
                promote_dtypes(&[lhs, rhs]),
                tenferro_tensor::validate::promote_dtype(lhs, rhs),
                "promotion mismatch for {lhs:?}, {rhs:?}"
            );
        }
    }
}