tenferro-cpu 0.4.0

CPU backend, kernels, provider selection, and CPU resource pools for tenferro.
use tenferro_core_ops::PrimitiveOpKind;
use tenferro_tensor::{
    BackendId, CapabilityAxis, CapabilityQuery, DType, SupportLevel, TensorBackendCapability,
};

use crate::CpuBackend;

#[test]
fn cpu_capability_table_reports_core_elementwise_reduction_and_dot_support() {
    let backend = CpuBackend::new();

    assert_eq!(backend.backend_id(), BackendId::Cpu);

    let add_i64 = backend
        .capability(CapabilityQuery::new(PrimitiveOpKind::Add, DType::I64))
        .expect("CPU add/i64 should be described");
    assert_eq!(add_i64.result, SupportLevel::Native);
    assert_eq!(add_i64.read_inputs, SupportLevel::Native);
    assert_eq!(add_i64.write_output, SupportLevel::FallbackCopy);
    assert_eq!(add_i64.output_dtype, DType::I64);

    let reduce_prod_c64 = backend
        .capability(CapabilityQuery::new(
            PrimitiveOpKind::ReduceProd,
            DType::C64,
        ))
        .expect("CPU reduce_prod/c64 should be described");
    assert_eq!(reduce_prod_c64.result, SupportLevel::Native);

    let dot_f64 = backend
        .capability(CapabilityQuery::new(
            PrimitiveOpKind::DotGeneral,
            DType::F64,
        ))
        .expect("CPU dot_general/f64 should be described");
    assert_eq!(
        dot_f64.axis(CapabilityAxis::OwnedResult),
        SupportLevel::Native
    );
    assert_eq!(
        dot_f64.axis(CapabilityAxis::ReadInputs),
        SupportLevel::Native
    );
    assert_eq!(
        dot_f64.axis(CapabilityAxis::WriteOutput),
        SupportLevel::Native
    );
    assert_eq!(
        dot_f64.axis(CapabilityAxis::Accumulation),
        SupportLevel::Native
    );

    let neg_i32 = backend
        .capability(CapabilityQuery::new(PrimitiveOpKind::Neg, DType::I32))
        .expect("CPU neg/i32 should be described");
    assert_eq!(neg_i32.result, SupportLevel::Native);
    assert_eq!(neg_i32.write_output, SupportLevel::FallbackCopy);

    let sign_c64 = backend
        .capability(CapabilityQuery::new(PrimitiveOpKind::Sign, DType::C64))
        .expect("CPU sign/c64 should be described");
    assert_eq!(sign_c64.result, SupportLevel::Native);

    let neg_i32 = backend
        .require_capability(
            CapabilityQuery::new(PrimitiveOpKind::Neg, DType::I32),
            CapabilityAxis::OwnedResult,
        )
        .unwrap();
    assert_eq!(neg_i32.result, SupportLevel::Native);

    let div_i32 = backend
        .capability(CapabilityQuery::new(PrimitiveOpKind::Div, DType::I32))
        .expect("CPU div/i32 should be described after #1320");
    assert_eq!(div_i32.result, SupportLevel::Native);
    assert_eq!(div_i32.write_output, SupportLevel::FallbackCopy);

    let rem_i64 = backend
        .capability(CapabilityQuery::new(PrimitiveOpKind::Rem, DType::I64))
        .expect("CPU rem/i64 should be described after #1320");
    assert_eq!(rem_i64.result, SupportLevel::Native);
    assert_eq!(rem_i64.write_output, SupportLevel::Unsupported);
}