tenferro-internal-cpu-kernels 0.8.0

Internal ordinary CPU kernel implementations for tenferro-cpu.
Documentation
use super::*;
use tenferro_tensor::StridedSliceSpec;

#[test]
fn static_replay_preserves_scalar_side_and_negative_strides() {
    let mut pool = BufferPool::new();
    let scalar = Tensor::from_vec_col_major([], vec![12.0_f64]).unwrap();
    let input = TypedTensor::<f64>::from_vec_col_major([3usize], vec![2.0, 3.0, 4.0]).unwrap();
    let reverse = input
        .as_view()
        .slice_view(&[StridedSliceSpec::new(0, Some(3), -1)])
        .unwrap();
    for (left_scalar, expected_sub, expected_div) in [
        (true, vec![8.0, 9.0, 10.0], vec![3.0, 4.0, 6.0]),
        (
            false,
            vec![-8.0, -9.0, -10.0],
            vec![4.0 / 12.0, 0.25, 2.0 / 12.0],
        ),
    ] {
        let operands = || {
            let scalar = TensorRead::from_tensor(&scalar);
            let view = TensorRead::from_view(TensorView::F64(reverse.clone()));
            if left_scalar {
                (scalar, view)
            } else {
                (view, scalar)
            }
        };
        let (lhs, rhs) = operands();
        let sub = sub_read_with_pool(&mut pool, lhs, rhs, Exec::serial()).unwrap();
        assert_eq!(sub.as_slice::<f64>().unwrap(), expected_sub);
        let (lhs, rhs) = operands();
        let div = div_read_with_pool(&mut pool, lhs, rhs, Exec::serial()).unwrap();
        assert_eq!(div.as_slice::<f64>().unwrap(), expected_div);
    }
}

#[test]
fn static_replay_keeps_complex_abs_real_and_conjugation_exact() {
    let mut pool = BufferPool::new();
    let input = TypedTensor::<_>::from_vec_col_major(
        [2usize],
        vec![Complex::new(3.0_f64, 4.0), Complex::new(-5.0, 12.0)],
    )
    .unwrap();
    let read = || TensorRead::from_view(TensorView::C64(input.as_view()));
    let abs = abs_read_with_pool(&mut pool, read(), Exec::serial()).unwrap();
    assert_eq!(abs.dtype(), DType::F64);
    assert_eq!(abs.as_slice::<f64>().unwrap(), &[5.0, 13.0]);
    let conj = conj_read_with_pool(&mut pool, read(), Exec::serial()).unwrap();
    assert_eq!(
        conj.as_slice::<Complex<f64>>().unwrap(),
        &[Complex::new(3.0, -4.0), Complex::new(-5.0, -12.0)]
    );
}

#[test]
fn static_replay_preserves_wrapping_neg_and_abs() {
    let mut pool = BufferPool::new();
    macro_rules! check {
        ($ty:ty, $variant:ident) => {{
            let input =
                TypedTensor::<$ty>::from_vec_col_major([2usize], vec![<$ty>::MIN, -7]).unwrap();
            let read = || TensorRead::from_view(TensorView::$variant(input.as_view()));
            let neg = neg_read_with_pool(&mut pool, read(), Exec::serial()).unwrap();
            let abs = abs_read_with_pool(&mut pool, read(), Exec::serial()).unwrap();
            assert_eq!(neg.as_slice::<$ty>().unwrap(), &[<$ty>::MIN, 7]);
            assert_eq!(abs.as_slice::<$ty>().unwrap(), &[<$ty>::MIN, 7]);
        }};
    }
    check!(i32, I32);
    check!(i64, I64);
}

#[test]
fn static_ternary_replay_preserves_selection_and_nan_policy() {
    let mut pool = BufferPool::new();
    let input =
        TypedTensor::<_>::from_vec_col_major([3usize], vec![-2.0_f64, f64::NAN, 3.0]).unwrap();
    let lower = TypedTensor::<_>::from_vec_col_major([3usize], vec![-1.0_f64; 3]).unwrap();
    let upper = TypedTensor::<_>::from_vec_col_major([3usize], vec![1.0_f64; 3]).unwrap();
    let pred = TypedTensor::<_>::from_vec_col_major([3usize], vec![true, false, true]).unwrap();
    let clamp = typed_clamp_with_pool(
        &mut pool,
        &input.as_view(),
        &lower.as_view(),
        &upper.as_view(),
        Exec::serial(),
    )
    .unwrap();
    let values = clamp.host_data().unwrap();
    assert_eq!(values[0], -1.0);
    assert!(values[1].is_nan());
    assert_eq!(values[2usize], 1.0);
    let select = typed_select_with_pool(
        &mut pool,
        &pred.as_view(),
        &input.as_view(),
        &upper.as_view(),
        Exec::serial(),
    )
    .unwrap();
    assert_eq!(select.host_data().unwrap(), &[-2.0, 1.0, 3.0]);
    let wrong = TypedTensor::<_>::from_vec_col_major([1usize], vec![false]).unwrap();
    assert!(typed_select_with_pool(
        &mut pool,
        &wrong.as_view(),
        &input.as_view(),
        &upper.as_view(),
        Exec::serial(),
    )
    .is_err());
}