pub fn is_dense(shape: &[usize], strides: &[usize]) -> bool {
let mut expected = 1;
for (axis, dim) in shape.iter().enumerate().rev() {
if *dim != 1 && strides[axis] != expected {
return false;
}
expected *= *dim;
}
true
}
pub fn is_nonoverlapping(shape: &[usize], strides: &[usize]) -> bool {
if shape
.iter()
.zip(strides)
.any(|(&extent, &stride)| stride == 0 && extent > 1)
{
return false;
}
let mut dims = shape.iter().zip(strides.iter()).collect::<Vec<_>>();
dims.sort_by_key(|(_, stride)| **stride);
let mut max_offset = 0;
for (shape, stride) in dims.into_iter() {
if *stride <= max_offset && *shape != 1 {
return false;
}
max_offset += (*shape - 1) * *stride;
}
true
}
#[cfg(test)]
mod tests {
use super::{is_dense, is_nonoverlapping};
#[test]
fn only_a_broadcast_or_a_fold_overlaps() {
assert!(is_nonoverlapping(&[48, 40], &[1, 48]));
assert!(is_nonoverlapping(&[33, 48], &[56, 1]));
assert!(is_nonoverlapping(&[1, 48, 40], &[0, 40, 1]));
assert!(!is_nonoverlapping(&[3, 48, 40], &[0, 40, 1]));
assert!(!is_nonoverlapping(&[48, 40], &[20, 1]));
}
#[test]
fn compact_strides_are_dense() {
assert!(is_dense(&[2, 4, 8, 96], &[3072, 768, 96, 1]));
}
#[test]
fn an_extent_one_axis_may_carry_any_stride() {
let (heads, head_dim) = (4, 96);
let (hd, seq_stride) = (heads * head_dim, heads * head_dim);
assert!(is_dense(
&[2, heads, 1, head_dim],
&[hd, head_dim, seq_stride, 1],
));
assert!(!cubecl::std::tensor::is_contiguous(
&[2, heads, 1, head_dim],
&[hd, head_dim, seq_stride, 1],
));
}
#[test]
fn a_permutation_of_addressable_axes_is_not_dense() {
assert!(!is_dense(&[2, 4, 7, 96], &[2688, 96, 384, 1]));
}
#[test]
fn a_padded_row_is_not_dense() {
assert!(!is_dense(&[1, 2, 8, 96], &[2048, 1024, 128, 1]));
}
#[test]
fn only_the_addressable_axis_has_to_line_up() {
assert!(is_dense(&[1, 1, 1, 64], &[999, 64, 777, 1]));
assert!(!is_dense(&[1, 1, 1, 64], &[999, 64, 777, 2]));
}
}