use crate::geometry::Geometry;
use crate::lattice::PaddedTileLattice;
#[derive(Clone, Copy, Debug)]
pub struct TensorSort {
geom: Geometry,
}
impl Default for TensorSort {
fn default() -> Self {
TensorSort {
geom: Geometry::TPU_V,
}
}
}
impl TensorSort {
pub fn new() -> Self {
TensorSort::default()
}
pub fn comparison_matrix(&self, x: &[f32]) -> PaddedTileLattice<f32> {
let n = x.len();
let mut dense = vec![0.0f32; n * n];
for i in 0..n {
for j in 0..n {
let after = x[i] > x[j] || (x[i] == x[j] && i > j);
dense[i * n + j] = if after { 1.0 } else { 0.0 };
}
}
PaddedTileLattice::from_dense(n, n, &dense, self.geom).unwrap()
}
pub fn ranks(&self, x: &[f32]) -> Vec<usize> {
let n = x.len();
if n == 0 {
return Vec::new();
}
let c = self.comparison_matrix(x);
let ones = PaddedTileLattice::from_dense(n, 1, &vec![1.0f32; n], self.geom).unwrap();
let r = c.matmul(&ones).unwrap().to_dense();
r.into_iter().map(|v| v.round() as usize).collect()
}
pub fn argsort(&self, x: &[f32]) -> Vec<usize> {
let ranks = self.ranks(x);
let mut out = vec![0usize; x.len()];
for (i, &r) in ranks.iter().enumerate() {
out[r] = i;
}
out
}
pub fn permutation_matrix(&self, x: &[f32]) -> PaddedTileLattice<f32> {
let n = x.len();
let ranks = self.ranks(x);
let mut dense = vec![0.0f32; n * n];
for (i, &r) in ranks.iter().enumerate() {
dense[r * n + i] = 1.0;
}
PaddedTileLattice::from_dense(n, n, &dense, self.geom).unwrap()
}
pub fn sort(&self, x: &[f32]) -> Vec<f32> {
let ranks = self.ranks(x);
let mut out = vec![0.0f32; x.len()];
for (i, &r) in ranks.iter().enumerate() {
out[r] = x[i];
}
out
}
pub fn sort_via_matmul(&self, x: &[f32]) -> Vec<f32> {
let n = x.len();
if n == 0 {
return Vec::new();
}
let p = self.permutation_matrix(x);
let xv = PaddedTileLattice::from_dense(n, 1, x, self.geom).unwrap();
p.matmul(&xv).unwrap().to_dense()
}
}