#[cfg(test)]
pub fn fuse_dims(dims: &[usize], all_strides: &[&[isize]]) -> Vec<usize> {
let n = dims.len();
if n <= 1 || all_strides.is_empty() {
return dims.to_vec();
}
let mut result = dims.to_vec();
for i in (1..n).rev() {
let mut can_merge = true;
for strides in all_strides {
let expected = result[i - 1] as isize * strides[i - 1];
if strides[i] != expected {
can_merge = false;
break;
}
}
if can_merge {
result[i - 1] *= result[i];
result[i] = 1;
}
}
result
}
#[cfg(test)]
pub fn compress_dims(dims: &[usize], all_strides: &[Vec<isize>]) -> (Vec<usize>, Vec<Vec<isize>>) {
let kept: Vec<usize> = (0..dims.len()).filter(|&i| dims[i] != 1).collect();
if kept.is_empty() {
if dims.is_empty() {
return (vec![], all_strides.to_vec());
}
let new_strides = all_strides.iter().map(|s| vec![s[0]]).collect();
return (vec![1], new_strides);
}
let new_dims: Vec<usize> = kept.iter().map(|&i| dims[i]).collect();
let new_strides: Vec<Vec<isize>> = all_strides
.iter()
.map(|s| kept.iter().map(|&i| s[i]).collect())
.collect();
(new_dims, new_strides)
}
#[cfg(test)]
pub fn compute_importance(
dims: &[usize],
all_strides: &[&[isize]],
index_orders: &[Vec<usize>],
) -> Vec<u64> {
let n = dims.len();
let m = all_strides.len();
if n == 0 || m == 0 {
return vec![];
}
let g = (64 - (m as u64 + 1).leading_zeros()) as u64;
let mut importance = vec![0u64; n];
for i in 0..n {
let shift = g * (n - index_orders[0][i]) as u64;
importance[i] = 2 * (1u64 << shift);
}
#[allow(clippy::needless_range_loop)]
for k in 1..m {
for i in 0..n {
let shift = g * (n - index_orders[k][i]) as u64;
importance[i] += 1u64 << shift;
}
}
for i in 0..n {
if dims[i] <= 1 {
importance[i] = 0;
}
}
importance
}
#[cfg(test)]
pub fn sort_by_importance(importance: &[u64]) -> Vec<usize> {
let mut indices: Vec<usize> = (0..importance.len()).collect();
indices.sort_by(|&a, &b| importance[b].cmp(&importance[a]));
indices
}
#[cfg(test)]
pub fn compute_costs<S: AsRef<[isize]>>(all_strides: &[S]) -> Vec<isize> {
if all_strides.is_empty() {
return vec![];
}
let n = all_strides[0].as_ref().len();
let mut costs = vec![isize::MAX; n];
for strides in all_strides {
let strides = strides.as_ref();
for i in 0..n {
costs[i] = costs[i].min(strides[i].abs());
}
}
for cost in &mut costs {
if *cost == 0 {
*cost = 1;
} else {
*cost *= 2;
}
}
costs
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BilateralFusionPlan {
pub dims: Vec<usize>,
pub src_strides: Vec<isize>,
pub dst_strides: Vec<isize>,
}
#[derive(Clone, Debug, thiserror::Error, PartialEq, Eq)]
pub enum FusionPlanError {
#[error(
"metadata lengths differ: dims={dims}, src_strides={src_strides}, \
dst_strides={dst_strides}"
)]
LengthMismatch {
dims: usize,
src_strides: usize,
dst_strides: usize,
},
#[error("fused dimension product overflows usize")]
DimensionOverflow,
}
pub fn plan_bilateral_fusion(
dims: &[usize],
src_strides: &[isize],
dst_strides: &[isize],
) -> Result<BilateralFusionPlan, FusionPlanError> {
if dims.len() != src_strides.len() || dims.len() != dst_strides.len() {
return Err(FusionPlanError::LengthMismatch {
dims: dims.len(),
src_strides: src_strides.len(),
dst_strides: dst_strides.len(),
});
}
let mut plan = BilateralFusionPlan {
dims: Vec::with_capacity(dims.len()),
src_strides: Vec::with_capacity(dims.len()),
dst_strides: Vec::with_capacity(dims.len()),
};
for ((&dim, &src_stride), &dst_stride) in dims.iter().zip(src_strides).zip(dst_strides) {
if dim == 1 {
continue;
}
isize::try_from(dim).map_err(|_| FusionPlanError::DimensionOverflow)?;
if let Some(last) = plan.dims.len().checked_sub(1) {
let current_dim =
isize::try_from(plan.dims[last]).map_err(|_| FusionPlanError::DimensionOverflow)?;
let src_contiguous = plan.src_strides[last]
.checked_mul(current_dim)
.is_some_and(|expected| src_stride == expected);
let dst_contiguous = plan.dst_strides[last]
.checked_mul(current_dim)
.is_some_and(|expected| dst_stride == expected);
if src_contiguous && dst_contiguous {
plan.dims[last] = plan.dims[last]
.checked_mul(dim)
.ok_or(FusionPlanError::DimensionOverflow)?;
continue;
}
}
plan.dims.push(dim);
plan.src_strides.push(src_stride);
plan.dst_strides.push(dst_stride);
}
Ok(plan)
}
#[cfg(test)]
fn fuse_dims_bilateral(
dims: &[usize],
src_strides: &[isize],
dst_strides: &[isize],
) -> (Vec<usize>, Vec<isize>, Vec<isize>) {
let plan = plan_bilateral_fusion(dims, src_strides, dst_strides).unwrap();
(plan.dims, plan.src_strides, plan.dst_strides)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fuse_dims_contiguous() {
let dims = [3, 4];
let strides1 = [1isize, 3];
let strides2 = [1isize, 3];
let all_strides: Vec<&[isize]> = vec![&strides1, &strides2];
let fused = fuse_dims(&dims, &all_strides);
assert_eq!(fused, vec![12, 1]);
}
#[test]
fn test_fuse_dims_non_contiguous() {
let dims = [3, 4];
let strides1 = [1isize, 10];
let all_strides: Vec<&[isize]> = vec![&strides1];
let fused = fuse_dims(&dims, &all_strides);
assert_eq!(fused, vec![3, 4]);
}
#[test]
fn test_fuse_dims_bilateral_all_contiguous() {
let dims = vec![2, 2, 2, 2];
let src_strides = vec![1, 2, 4, 8];
let dst_strides = vec![1, 2, 4, 8];
let (fd, fs, fds) = fuse_dims_bilateral(&dims, &src_strides, &dst_strides);
assert_eq!(fd, vec![16]);
assert_eq!(fs, vec![1]);
assert_eq!(fds, vec![1]);
}
#[test]
fn test_fuse_dims_bilateral_partial() {
let dims = vec![2, 3, 4];
let src_strides = vec![1, 2, 100]; let dst_strides = vec![1, 2, 6]; let (fd, fs, fds) = fuse_dims_bilateral(&dims, &src_strides, &dst_strides);
assert_eq!(fd, vec![6, 4]); assert_eq!(fs, vec![1, 100]);
assert_eq!(fds, vec![1, 6]);
}
#[test]
fn test_fuse_dims_bilateral_scattered() {
let dims = vec![2, 2, 2];
let src_strides = vec![1, 4194304, 2]; let dst_strides = vec![1, 2, 4]; let (fd, fs, fds) = fuse_dims_bilateral(&dims, &src_strides, &dst_strides);
assert_eq!(fd, vec![2, 2, 2]); assert_eq!(fs, vec![1, 4194304, 2]);
assert_eq!(fds, vec![1, 2, 4]);
}
#[test]
fn test_compress_dims_removes_fused() {
let dims = vec![12usize, 1];
let strides = vec![vec![1isize, 3]];
let (cd, cs) = compress_dims(&dims, &strides);
assert_eq!(cd, vec![12]);
assert_eq!(cs, vec![vec![1]]);
}
#[test]
fn test_compute_costs() {
let strides1 = [1isize, 4, 0];
let strides2 = [2isize, 1, 0];
let all_strides: Vec<&[isize]> = vec![&strides1, &strides2];
let costs = compute_costs(&all_strides);
assert_eq!(costs, vec![2, 2, 1]);
}
}