use systile::prelude::*;
fn ramp(rows: usize, cols: usize) -> PaddedTileLattice<f32> {
let data: Vec<f32> = (0..rows * cols).map(|i| i as f32).collect();
PaddedTileLattice::from_dense(rows, cols, &data, Geometry::TPU_V).unwrap()
}
#[test]
fn dense_roundtrip_through_geometry_relayout() {
let l = ramp(5, 7);
let original = l.to_dense();
let back = l
.relayout(Geometry::TINY)
.unwrap()
.relayout(Geometry::TPU_V)
.unwrap();
assert_eq!(back.to_dense(), original);
}
#[test]
fn transpose_then_matmul_is_gram_matrix() {
let a = ramp(2, 3);
let g = a.transpose().matmul(&a).unwrap();
assert_eq!(g.rows(), 3);
assert_eq!(g.cols(), 3);
}
#[test]
fn gram_matrix_is_symmetric() {
let a = ramp(2, 3);
let g = a.transpose().matmul(&a).unwrap();
for i in 0..3 {
for j in 0..3 {
assert_eq!(g.get(i, j), g.get(j, i));
}
}
}
#[test]
fn quantize_roundtrip_preserves_sign_pattern() {
let data: Vec<f32> = (0..16).map(|i| i as f32 - 8.0).collect();
let l = PaddedTileLattice::from_dense(4, 4, &data, Geometry::TPU_V).unwrap();
let params = QuantParams::symmetric(l.abs_max());
let back = l.quantize(params).unwrap().dequantize(params).unwrap();
for (orig, got) in l.to_dense().iter().zip(back.to_dense().iter()) {
assert_eq!(
orig.signum() as i32,
got.signum() as i32,
"orig={orig} got={got}"
);
}
}
#[test]
fn sparsity_survives_relayout() {
let mut l = PaddedTileLattice::<f32>::zeroed(16, 16, Geometry::TPU_V).unwrap();
l.set(0, 0, 1.0).unwrap();
let dense_nonzero = l.to_dense().iter().filter(|x| **x != 0.0).count();
let r = l.relayout(Geometry::TINY).unwrap();
let dense_nonzero_after = r.to_dense().iter().filter(|x| **x != 0.0).count();
assert_eq!(dense_nonzero, dense_nonzero_after);
}
#[test]
fn map_then_reduce_composes() {
let l = ramp(2, 3);
let squared = l.map(|x| x * x);
assert_eq!(squared.sum(), (0..6).map(|i| (i * i) as f32).sum());
}
#[test]
fn zip_add_matches_elementwise_sum() {
let a = ramp(3, 3);
let b = ramp(3, 3);
let c = a.zip_with(&b, |x, y| x + y).unwrap();
for (got, base) in c.to_dense().iter().zip(a.to_dense().iter()) {
assert_eq!(*got, base * 2.0);
}
}
#[test]
fn bf16_lattice_roundtrips_through_dense() {
let data: Vec<Bf16> = (0..6).map(|i| Bf16::from_f32(i as f32)).collect();
let l = PaddedTileLattice::from_dense(2, 3, &data, Geometry::TPU_V).unwrap();
assert_eq!(l.to_dense(), data);
}
#[test]
fn f32_to_bf16_lattice_via_map() {
let l = ramp(2, 3);
let b: PaddedTileLattice<Bf16> = l.map(|x| Bf16::from_f32(*x));
assert_eq!(b.get(1, 2).unwrap().to_f32(), 5.0);
}
#[test]
fn matmul_associativity_holds_on_small_f32() {
let a = ramp(2, 2);
let b = ramp(2, 2);
let c = ramp(2, 2);
let left = a.matmul(&b).unwrap().matmul(&c).unwrap();
let right = a.matmul(&b.matmul(&c).unwrap()).unwrap();
assert_eq!(left.to_dense(), right.to_dense());
}
#[test]
fn padding_fill_does_not_affect_matmul() {
let mut a = ramp(2, 3);
let b = ramp(3, 2);
let clean = a.matmul(&b).unwrap().to_dense();
a.fill_padding(999.0);
let filled = a.matmul(&b).unwrap().to_dense();
assert_eq!(clean, filled);
}
#[test]
fn storage_slice_length_is_stable_across_set() {
let mut l = ramp(3, 5);
let before = l.as_storage_slice().len();
l.set(0, 0, 42.0).unwrap();
assert_eq!(l.as_storage_slice().len(), before);
}
#[test]
fn num_tiles_matches_iter_count_for_many_shapes() {
for &(r, c) in &[(1, 1), (8, 128), (9, 129), (130, 257)] {
let l = PaddedTileLattice::<f32>::zeroed(r, c, Geometry::TPU_V).unwrap();
assert_eq!(l.num_tiles(), l.iter_tiles().count());
}
}
#[test]
fn identity_matmul_via_quantized_path_is_close() {
let mut id = PaddedTileLattice::<f32>::zeroed(4, 4, Geometry::TPU_V).unwrap();
for i in 0..4 {
id.set(i, i, 1.0).unwrap();
}
let m = ramp(4, 4);
let params = QuantParams::symmetric(m.abs_max());
let mq = m.quantize(params).unwrap().dequantize(params).unwrap();
let out = mq.matmul(&id).unwrap();
for (got, want) in out.to_dense().iter().zip(m.to_dense().iter()) {
assert!(
(got - want).abs() <= params.scale + 1e-3,
"got={got} want={want}"
);
}
}
#[test]
fn row_sums_equal_matmul_with_ones() {
let a = ramp(3, 4);
let ones = PaddedTileLattice::from_dense(4, 1, &[1.0; 4], Geometry::TPU_V).unwrap();
let prod = a.matmul(&ones).unwrap();
for (i, sum) in a.row_sums().iter().enumerate() {
assert_eq!(prod.get(i, 0).unwrap(), sum);
}
}
#[test]
fn tile_density_plus_sparsity_is_one_after_quantize() {
let mut l = PaddedTileLattice::<f32>::zeroed(16, 16, Geometry::TPU_V).unwrap();
l.set(3, 3, 5.0).unwrap();
let q = l.quantize(QuantParams::symmetric(5.0)).unwrap();
assert!((q.tile_density() + q.tile_sparsity() - 1.0).abs() < 1e-9);
}
#[test]
fn empty_lattice_to_dense_is_empty() {
let l = PaddedTileLattice::<f32>::zeroed(0, 0, Geometry::TPU_V).unwrap();
assert!(l.to_dense().is_empty());
}
#[test]
fn single_element_matmul() {
let a = PaddedTileLattice::from_dense(1, 1, &[3.0], Geometry::TPU_V).unwrap();
let b = PaddedTileLattice::from_dense(1, 1, &[4.0], Geometry::TPU_V).unwrap();
assert_eq!(a.matmul(&b).unwrap().to_dense(), vec![12.0]);
}
#[test]
fn mean_matches_sum_over_len() {
let l = ramp(4, 4);
assert_eq!(l.mean().unwrap(), l.sum() / l.len() as f32);
}
#[test]
fn map_in_place_and_map_agree() {
let l = ramp(3, 3);
let mapped = l.map(|x| x + 1.0);
let mut in_place = l.clone();
in_place.map_in_place(|x| x + 1.0);
assert_eq!(mapped.to_dense(), in_place.to_dense());
}
#[test]
fn transpose_of_quantized_matches_quantized_transpose() {
let l = ramp(3, 4);
let params = QuantParams::symmetric(l.abs_max());
let a = l
.quantize(params)
.unwrap()
.dequantize(params)
.unwrap()
.transpose();
let b = l
.transpose()
.quantize(params)
.unwrap()
.dequantize(params)
.unwrap();
assert_eq!(a.to_dense(), b.to_dense());
}
#[test]
fn full_tiles_beat_padded_tiles_on_utilisation() {
let (_, small) = ramp(1, 1).matmul_with_stats(&ramp(1, 1)).unwrap();
let (_, full) = ramp(128, 128).matmul_with_stats(&ramp(128, 128)).unwrap();
assert!(full.utilisation() > small.utilisation());
assert_eq!(full.utilisation(), 1.0);
}