tenferro-einsum 0.8.0

Subscripts, contraction planning, concrete/traced/eager einsum APIs, extension runtime, and AD rule for tenferro.
Documentation
use tenferro_tensor::DotGeneralConfig;

use super::{try_build_exact_output_binary_dot_plan, BinaryDotOperandOrder};

#[test]
fn compact_configs_inline_four_axes_and_spill_larger_lists() {
    for (lhs, rhs, output, contracting, batch) in [
        ("abcde", "dcbaq", "eq", 4, 0),
        ("abcdef", "edcbaq", "fq", 5, 0),
        ("abcdefg", "abcdegh", "fhabcde", 1, 5),
    ] {
        let (_, config) = super::try_build_exact_output_binary_dot_config(
            lhs.as_bytes(),
            rhs.as_bytes(),
            output.as_bytes(),
        )
        .unwrap();
        assert_eq!(config.lhs_contracting_dims.len(), contracting);
        assert_eq!(config.rhs_contracting_dims.len(), contracting);
        assert_eq!(config.lhs_batch_dims.len(), batch);
        assert_eq!(config.rhs_batch_dims.len(), batch);
        assert_eq!(config.lhs_contracting_dims.is_heap(), contracting > 4);
        assert_eq!(config.rhs_contracting_dims.is_heap(), contracting > 4);
        assert_eq!(config.lhs_batch_dims.is_heap(), batch > 4);
        assert_eq!(config.rhs_batch_dims.is_heap(), batch > 4);
        let labels = [lhs, rhs, output].map(|s| s.bytes().map(u32::from).collect::<Vec<_>>());
        let full =
            try_build_exact_output_binary_dot_plan(&labels[0], &labels[1], &labels[2]).unwrap();
        assert_eq!(config, full.config);
    }
}

#[test]
fn compact_configs_match_full_plans_for_byte_and_integer_labels() {
    let terms = ["ij", "ji", "ijk", "kj", "j", "ii", "", "ipj", "jk"];
    let outputs = [
        "ip", "pi", "ij", "ji", "ikj", "kij", "", "i", "j", "ii", "z", "ipj", "pij",
    ];
    for lhs in terms {
        for rhs in terms {
            for output in outputs {
                let labels =
                    [lhs, rhs, output].map(|s| s.bytes().map(u32::from).collect::<Vec<_>>());
                let expected =
                    try_build_exact_output_binary_dot_plan(&labels[0], &labels[1], &labels[2])
                        .map(|plan| (plan.operand_order, plan.config));
                let bytes = super::try_build_exact_output_binary_dot_config(
                    lhs.as_bytes(),
                    rhs.as_bytes(),
                    output.as_bytes(),
                );
                let integers = super::try_build_exact_output_binary_dot_config(
                    &labels[0], &labels[1], &labels[2],
                );
                assert_eq!(bytes, expected, "{lhs},{rhs}->{output}");
                assert_eq!(integers, expected, "{lhs},{rhs}->{output}");
            }
        }
    }
}

#[test]
fn exact_binary_dot_plan_accepts_original_output_order() {
    let plan = try_build_exact_output_binary_dot_plan(
        &[b'i' as u32, b'j' as u32],
        &[b'j' as u32, b'k' as u32],
        &[b'i' as u32, b'k' as u32],
    )
    .expect("matmul should lower exactly");

    assert_eq!(plan.operand_order, BinaryDotOperandOrder::Original);
    assert_eq!(
        plan.config,
        DotGeneralConfig {
            lhs_contracting_dims: [1].as_slice().into(),
            rhs_contracting_dims: [0].as_slice().into(),
            lhs_batch_dims: [].as_slice().into(),
            rhs_batch_dims: [].as_slice().into(),
        }
    );
}

#[test]
fn exact_binary_dot_plan_accepts_swapped_col_major_matmul() {
    let plan = try_build_exact_output_binary_dot_plan(
        &[b'j' as u32, b'i' as u32],
        &[b'k' as u32, b'j' as u32],
        &[b'k' as u32, b'i' as u32],
    )
    .expect("col-major matmul should lower exactly after swapping operands");

    assert_eq!(plan.operand_order, BinaryDotOperandOrder::Swapped);
    assert_eq!(
        plan.config,
        DotGeneralConfig {
            lhs_contracting_dims: [1].as_slice().into(),
            rhs_contracting_dims: [0].as_slice().into(),
            lhs_batch_dims: [].as_slice().into(),
            rhs_batch_dims: [].as_slice().into(),
        }
    );
}

#[test]
fn exact_binary_dot_plan_accepts_swapped_col_major_batched_matmul() {
    let plan = try_build_exact_output_binary_dot_plan(
        &[b'j' as u32, b'i' as u32, b'b' as u32],
        &[b'k' as u32, b'j' as u32, b'b' as u32],
        &[b'k' as u32, b'i' as u32, b'b' as u32],
    )
    .expect("col-major batched matmul should lower exactly after swapping operands");

    assert_eq!(plan.operand_order, BinaryDotOperandOrder::Swapped);
    assert_eq!(
        plan.config,
        DotGeneralConfig {
            lhs_contracting_dims: [1].as_slice().into(),
            rhs_contracting_dims: [0].as_slice().into(),
            lhs_batch_dims: [2].as_slice().into(),
            rhs_batch_dims: [2].as_slice().into(),
        }
    );
}

#[test]
fn exact_binary_dot_plan_rejects_repeated_labels() {
    assert!(try_build_exact_output_binary_dot_plan(
        &[b'i' as u32, b'i' as u32],
        &[b'j' as u32],
        &[b'j' as u32],
    )
    .is_none());
}