ruCCL 0.21.1

Ruda collective communication algorithms and orchestration.
Documentation
use super::*;

#[test]
fn host_integer_reductions_cover_numeric_bitwise_and_wrapping_semantics() {
    let payload = i64::encode(&[2, 6, 3, 4]);
    for (operation, expected) in [
        (ReductionOperation::Sum, vec![5, 10]),
        (ReductionOperation::Product, vec![6, 24]),
        (ReductionOperation::Minimum, vec![2, 4]),
        (ReductionOperation::Maximum, vec![3, 6]),
        (ReductionOperation::BitAnd, vec![2, 4]),
        (ReductionOperation::BitOr, vec![3, 6]),
        (ReductionOperation::BitXor, vec![1, 2]),
    ] {
        let reduced = reduce_host_values::<i64>(&payload, 2, 2, operation).unwrap();
        assert_eq!(i64::decode(&reduced).unwrap(), expected);
    }

    let overflow = u8::encode(&[250, 10]);
    let reduced = reduce_host_values::<u8>(&overflow, 1, 2, ReductionOperation::Sum).unwrap();
    assert_eq!(u8::decode(&reduced).unwrap(), vec![4]);
}

#[test]
fn host_boolean_reductions_match_gloo_logical_semantics() {
    let payload = bool::encode(&[false, true, true, true]);
    for (operation, expected) in [
        (ReductionOperation::Sum, vec![true, true]),
        (ReductionOperation::Product, vec![false, true]),
        (ReductionOperation::Minimum, vec![false, true]),
        (ReductionOperation::Maximum, vec![true, true]),
        (ReductionOperation::BitAnd, vec![false, true]),
        (ReductionOperation::BitOr, vec![true, true]),
        (ReductionOperation::BitXor, vec![true, false]),
    ] {
        let reduced = reduce_host_values::<bool>(&payload, 2, 2, operation).unwrap();
        assert_eq!(bool::decode(&reduced).unwrap(), expected);
    }
    assert!(bool::decode(&[2]).is_err());
}

#[test]
fn host_f64_reductions_reject_bitwise_operations() {
    let payload = f64::encode(&[2.0, 6.0, 3.0, 4.0]);
    for (operation, expected) in [
        (ReductionOperation::Sum, vec![5.0, 10.0]),
        (ReductionOperation::Product, vec![6.0, 24.0]),
        (ReductionOperation::Minimum, vec![2.0, 4.0]),
        (ReductionOperation::Maximum, vec![3.0, 6.0]),
    ] {
        let reduced = reduce_host_values::<f64>(&payload, 2, 2, operation).unwrap();
        assert_eq!(f64::decode(&reduced).unwrap(), expected);
    }
    assert!(
        validate_host_reduction_operation(ElementType::F64, ReductionOperation::BitAnd).is_err()
    );
}

#[test]
fn host_complex_reductions_cover_sum_product_and_reject_unordered_operations() {
    let values32 = [
        Complex32 {
            real: 1.0,
            imaginary: 2.0,
        },
        Complex32 {
            real: 3.0,
            imaginary: -1.0,
        },
        Complex32 {
            real: 4.0,
            imaginary: -3.0,
        },
        Complex32 {
            real: -2.0,
            imaginary: 5.0,
        },
    ];
    let encoded32 = Complex32::encode(&values32);
    assert_eq!(Complex32::decode(&encoded32).unwrap(), values32);
    let sum32 = reduce_host_values::<Complex32>(&encoded32, 2, 2, ReductionOperation::Sum).unwrap();
    assert_eq!(
        Complex32::decode(&sum32).unwrap(),
        [
            Complex32 {
                real: 5.0,
                imaginary: -1.0,
            },
            Complex32 {
                real: 1.0,
                imaginary: 4.0,
            },
        ]
    );
    let product32 =
        reduce_host_values::<Complex32>(&encoded32, 2, 2, ReductionOperation::Product).unwrap();
    assert_eq!(
        Complex32::decode(&product32).unwrap(),
        [
            Complex32 {
                real: 10.0,
                imaginary: 5.0,
            },
            Complex32 {
                real: -1.0,
                imaginary: 17.0,
            },
        ]
    );

    let values64 = [
        Complex64 {
            real: 1.25,
            imaginary: -2.5,
        },
        Complex64 {
            real: 3.75,
            imaginary: 4.5,
        },
    ];
    let encoded64 = Complex64::encode(&values64);
    assert_eq!(Complex64::decode(&encoded64).unwrap(), values64);
    let sum64 = reduce_host_values::<Complex64>(&encoded64, 1, 2, ReductionOperation::Sum).unwrap();
    assert_eq!(
        Complex64::decode(&sum64).unwrap(),
        [Complex64 {
            real: 5.0,
            imaginary: 2.0,
        }]
    );

    for element_type in [ElementType::Complex64, ElementType::Complex128] {
        for operation in [
            ReductionOperation::Minimum,
            ReductionOperation::Maximum,
            ReductionOperation::BitAnd,
            ReductionOperation::BitOr,
            ReductionOperation::BitXor,
        ] {
            assert!(validate_host_reduction_operation(element_type, operation).is_err());
        }
    }
}

#[test]
fn f64_reductions_preserve_nan_zero_and_rank_order() {
    let nan = f64::from_bits(0x7ff8_0000_0000_0123);
    let payload = f64::encode(&[
        nan,
        -0.0,
        f64::INFINITY,
        5.0,
        2.0,
        0.0,
        f64::NEG_INFINITY,
        nan,
    ]);
    for (operation, third) in [
        (ReductionOperation::Minimum, f64::NEG_INFINITY),
        (ReductionOperation::Maximum, f64::INFINITY),
    ] {
        let output = reduce_host_values::<f64>(&payload, 4, 2, operation).unwrap();
        assert_eq!(output, f64::encode(&[nan, -0.0, third, 5.0]));
    }
    let payload = f64::encode(&[1.0e16, -1.0e16, 1.0]);
    let output = reduce_host_values::<f64>(&payload, 1, 3, ReductionOperation::Sum).unwrap();
    assert_eq!(output, f64::encode(&[1.0]));
}