use super::*;
#[test]
fn test_find_stride1_dim_basic() {
assert_eq!(find_stride1_dim(&[4, 5], &[1, 4]), 0);
assert_eq!(find_stride1_dim(&[4, 5], &[5, 1]), 1);
}
#[test]
fn test_find_stride1_dim_skips_size1() {
assert_eq!(find_stride1_dim(&[1, 5], &[1, 2]), 1);
}
#[test]
fn test_build_plan_identity() {
let plan = build_permute_plan(&[2, 3, 4], &[1, 2, 6], &[1, 2, 6], 8).unwrap();
assert_eq!(&plan.fused_dims[..], &[24]);
assert!(matches!(plan.mode, ExecMode::ConstStride1 { .. }));
}
#[test]
fn test_build_plan_transpose_2d() {
let plan = build_permute_plan(&[4, 5], &[1, 4], &[5, 1], 8).unwrap();
assert_eq!(&plan.fused_dims[..], &[4, 5]);
match plan.mode {
ExecMode::Transpose { dim_a, dim_b } => {
assert_eq!(dim_a, 0); assert_eq!(dim_b, 1); }
_ => panic!("expected Transpose mode"),
}
assert_eq!(plan.block, 16); assert_eq!(plan.lda_inner, 4); assert_eq!(plan.ldb_inner, 5); assert!(plan.levels.is_empty());
}
#[test]
fn test_build_plan_3d_permute() {
let plan = build_permute_plan(&[4, 2, 3], &[6, 1, 2], &[1, 4, 8], 8).unwrap();
assert_eq!(&plan.fused_dims[..], &[4, 6]);
match plan.mode {
ExecMode::Transpose { dim_a, dim_b } => {
assert_eq!(dim_a, 1);
assert_eq!(dim_b, 0);
}
_ => panic!("expected Transpose mode"),
}
assert!(plan.levels.is_empty());
}
#[test]
fn test_build_plan_scattered_strides() {
let dims = vec![2, 2, 2, 2];
let src_strides = vec![1, 8, 2, 4]; let dst_strides = vec![1, 2, 4, 8];
let plan = build_permute_plan(&dims, &src_strides, &dst_strides, 8).unwrap();
assert_eq!(plan.fused_dims.len(), 3);
match plan.mode {
ExecMode::Transpose { .. } | ExecMode::ConstStride1 { .. } => {
}
_ => panic!("unexpected mode"),
}
}
#[test]
fn test_build_plan_step408_uses_grouped_tile() {
let dims = vec![2usize; 24];
let src_strides = vec![
16, 1024, 8388608, 4096, 1048576, 1, 8, 131072, 2, 4, 64, 128, 256, 512, 2048, 8192, 16384,
32768, 262144, 2097152, 4194304, 32, 65536, 524288,
];
let dst_strides = (0..24).map(|i| 1isize << i).collect::<Vec<_>>();
let plan = build_permute_plan(&dims, &src_strides, &dst_strides, 8).unwrap();
assert!(matches!(plan.mode, ExecMode::GroupedTranspose));
let grouped = plan.grouped_tile.as_ref().expect("grouped tile plan");
assert!(grouped.group_a.total_len() >= 16);
assert!(grouped.group_b.total_len() >= 16);
assert!(grouped.group_a.total_len() * grouped.group_b.total_len() >= 256);
}
#[test]
fn test_build_plan_rank8_scattered_uses_inline_grouped_tile() {
let dims = vec![2usize; 8];
let src_strides = [16isize, 1024, 8388608, 4096, 1048576, 1, 8, 131072];
let dst_strides = [1isize, 2, 4, 8, 16, 32, 64, 128];
let plan = build_permute_plan(&dims, &src_strides, &dst_strides, 8).unwrap();
assert!(matches!(plan.mode, ExecMode::GroupedTranspose));
let grouped = plan.grouped_tile.as_ref().expect("grouped tile plan");
assert!(grouped.group_a.outer.is_empty() && grouped.group_b.outer.is_empty());
assert!(grouped.group_a.len >= 4 && grouped.group_b.len >= 4);
assert!(!plan.levels.is_empty());
}
#[test]
fn test_build_plan_splits_groups_above_the_table_bound() {
let cases: [([usize; 8], [isize; 8], [isize; 8]); 3] = [
(
[101, 2, 2, 2, 2, 2, 2, 2],
[1, 102, 1000, 1001, 1002, 1003, 1004, 1005],
[128, 1, 2, 4, 8, 16, 32, 64],
),
(
[100, 2, 2, 2, 2, 2, 2, 2],
[1, 101, 1000, 1001, 1002, 1003, 1004, 1005],
[128, 1, 2, 4, 8, 16, 32, 64],
),
(
[2, 3, 4, 5, 6, 7, 8, 9],
[40320, 2, 6, 24, 120, 720, 5040, 1],
[1, 2, 6, 24, 120, 720, 5040, 40320],
),
];
for (dims, src_strides, dst_strides) in cases {
let plan = build_permute_plan(&dims, &src_strides, &dst_strides, 8).unwrap();
assert!(matches!(plan.mode, ExecMode::GroupedTranspose), "{dims:?}");
let grouped = plan.grouped_tile.as_ref().expect("grouped tile plan");
let groups = [&grouped.group_a, &grouped.group_b];
assert!(groups.iter().any(|g| !g.outer.is_empty()), "{dims:?}");
for group in groups {
assert!(group.len <= GROUP_OFFSETS_INLINE);
assert_eq!(group.src_offsets.len(), group.len);
}
}
let group_a = |case: usize| {
let (dims, src, dst) = &cases[case];
let plan = build_permute_plan(dims, src, dst, 8).unwrap();
plan.grouped_tile.unwrap().group_a
};
let prime = group_a(0);
assert_eq!(
(prime.len, prime.outer.as_slice()),
(1, &[(101, 1, 128)][..])
);
let split = group_a(1);
assert_eq!(
(split.len, split.outer.as_slice()),
(50, &[(2, 50, 6400)][..])
);
}
#[test]
fn test_build_plan_large_3d_transpose_uses_legacy_tile() {
let dims = vec![256usize, 256, 256];
let src_strides = vec![256isize, 1, 65536];
let dst_strides = vec![1isize, 256, 65536];
let plan = build_permute_plan(&dims, &src_strides, &dst_strides, 8).unwrap();
assert!(matches!(plan.mode, ExecMode::Transpose { .. }));
assert!(plan.grouped_tile.is_none());
}
#[test]
fn test_build_plan_rank0() {
let plan = build_permute_plan(&[], &[], &[], 8).unwrap();
assert!(matches!(plan.mode, ExecMode::Scalar));
assert!(plan.levels.is_empty());
}
#[test]
fn test_compute_loop_order_transpose() {
let dims = [4, 5, 3, 7];
let src_s = [1isize, 4, 100, 300];
let dst_s = [35isize, 1, 7, 21];
let order = compute_loop_order_transpose(&dims, &src_s, &dst_s, 0, 1);
assert_eq!(&order[..], &[3, 2]);
}
#[test]
fn test_build_loop_levels_chain() {
let dims = [10, 5, 3];
let src_s = [1isize, 10, 50];
let dst_s = [15isize, 1, 5];
let loop_order = vec![2];
let levels = build_loop_levels(&dims, &src_s, &dst_s, &loop_order);
assert_eq!(levels.len(), 1);
assert_eq!(levels[0].end, 3);
assert_eq!(levels[0].lda, 50);
assert_eq!(levels[0].ldb, 5);
assert!(build_loop_levels(&dims, &src_s, &dst_s, &[]).is_empty());
}