use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use crate::common::error::AicError;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum ProvenanceTier {
Silicon = 0,
Empirical = 1,
XShape = 2,
XQuant = 3,
XProfile = 4,
XOp = 5,
}
impl ProvenanceTier {
pub fn as_str(self) -> &'static str {
match self {
ProvenanceTier::Silicon => "silicon",
ProvenanceTier::Empirical => "empirical",
ProvenanceTier::XShape => "xshape",
ProvenanceTier::XQuant => "xquant",
ProvenanceTier::XProfile => "xprofile",
ProvenanceTier::XOp => "xop",
}
}
pub fn from_tag(tag: &str) -> Option<ProvenanceTier> {
match tag {
"silicon" => Some(ProvenanceTier::Silicon),
"empirical" => Some(ProvenanceTier::Empirical),
"xshape" => Some(ProvenanceTier::XShape),
"xquant" => Some(ProvenanceTier::XQuant),
"xprofile" => Some(ProvenanceTier::XProfile),
"xop" => Some(ProvenanceTier::XOp),
_ => None,
}
}
pub fn from_rank(rank: u8) -> ProvenanceTier {
match rank {
0 => ProvenanceTier::Silicon,
1 => ProvenanceTier::Empirical,
2 => ProvenanceTier::XShape,
3 => ProvenanceTier::XQuant,
4 => ProvenanceTier::XProfile,
_ => ProvenanceTier::XOp,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct UtilSample {
pub coords: Vec<f64>,
pub util: f64,
}
impl UtilSample {
pub fn new(coords: Vec<f64>, util: f64) -> Self {
Self { coords, util }
}
}
pub fn build_samples<I, F>(points: I, sol_fn: F) -> Vec<UtilSample>
where
I: IntoIterator<Item = (Vec<f64>, f64)>,
F: Fn(&[f64]) -> f64,
{
let mut samples = Vec::new();
for (coords, latency_ms) in points {
if latency_ms > 0.0 {
let sol = sol_fn(&coords);
if sol > 0.0 {
samples.push(UtilSample::new(coords, sol / latency_ms));
}
}
}
samples
}
#[derive(Debug, Clone)]
pub struct UtilGrid {
norm: Vec<Vec<f64>>,
utils: Vec<f64>,
mins: Vec<f64>,
spans: Vec<f64>,
pub reference_provenance: Option<&'static str>,
}
fn log_floor(value: f64) -> f64 {
value.max(1e-9).ln()
}
impl UtilGrid {
pub fn new(samples: Vec<UtilSample>) -> Self {
if samples.is_empty() {
return Self {
norm: Vec::new(),
utils: Vec::new(),
mins: Vec::new(),
spans: Vec::new(),
reference_provenance: None,
};
}
let dims = samples[0].coords.len();
let logc: Vec<Vec<f64>> = samples
.iter()
.map(|s| s.coords.iter().map(|&c| log_floor(c)).collect())
.collect();
let mut mins = vec![f64::INFINITY; dims];
let mut maxs = vec![f64::NEG_INFINITY; dims];
for row in &logc {
for (a, &v) in row.iter().enumerate() {
mins[a] = mins[a].min(v);
maxs[a] = maxs[a].max(v);
}
}
let spans: Vec<f64> = mins
.iter()
.zip(&maxs)
.map(|(&lo, &hi)| if hi - lo > 0.0 { hi - lo } else { 1.0 })
.collect();
let norm: Vec<Vec<f64>> = logc
.iter()
.map(|row| {
row.iter()
.enumerate()
.map(|(a, &v)| (v - mins[a]) / spans[a])
.collect()
})
.collect();
let utils = samples.iter().map(|s| s.util).collect();
Self {
norm,
utils,
mins,
spans,
reference_provenance: None,
}
}
pub fn is_empty(&self) -> bool {
self.utils.is_empty()
}
pub fn util(&self, query: &[f64]) -> Option<f64> {
if self.utils.is_empty() {
return None;
}
let q: Vec<f64> = query
.iter()
.enumerate()
.map(|(a, &v)| ((log_floor(v) - self.mins[a]) / self.spans[a]).clamp(0.0, 1.0))
.collect();
let distances: Vec<f64> = self
.norm
.iter()
.map(|row| {
row.iter()
.zip(&q)
.map(|(&x, &y)| (x - y) * (x - y))
.sum::<f64>()
.sqrt()
})
.collect();
let mut order: Vec<usize> = (0..distances.len()).collect();
order.sort_by(|&i, &j| {
distances[i]
.partial_cmp(&distances[j])
.expect("finite distances")
});
if distances[order[0]] == 0.0 {
return Some(self.utils[order[0]]);
}
let nearest = &order[..order.len().min(2)];
let mut weighted = 0.0;
let mut weight_sum = 0.0;
for &i in nearest {
let w = 1.0 / distances[i];
weighted += self.utils[i] * w;
weight_sum += w;
}
Some(weighted / weight_sum)
}
}
pub fn estimate(
sol_query: f64,
query: &[f64],
grid: Option<&UtilGrid>,
util_scale: f64,
) -> Result<(f64, f64), AicError> {
if let Some(util) = grid.and_then(|g| g.util(query)) {
if util > 0.0 {
return Ok((sol_query / (util * util_scale), util));
}
}
Err(AicError::EmpiricalNotImplemented(format!(
"No empirical utilisation data to estimate this op at query={query:?}: \
no own-shape, cross-shape, or sibling transfer reference available."
)))
}
pub fn nearest_candidate_index(query_features: &[f64], candidates: &[Vec<f64>]) -> Option<usize> {
if candidates.is_empty() {
return None;
}
let dims = query_features.len();
let feats: Vec<Vec<f64>> = candidates
.iter()
.map(|c| c.iter().map(|&v| log_floor(v)).collect())
.collect();
let mut mins = vec![f64::INFINITY; dims];
let mut maxs = vec![f64::NEG_INFINITY; dims];
for row in &feats {
for (a, &v) in row.iter().enumerate() {
mins[a] = mins[a].min(v);
maxs[a] = maxs[a].max(v);
}
}
let spans: Vec<f64> = mins
.iter()
.zip(&maxs)
.map(|(&lo, &hi)| if hi - lo > 0.0 { hi - lo } else { 1.0 })
.collect();
let q: Vec<f64> = query_features
.iter()
.enumerate()
.map(|(a, &v)| (log_floor(v) - mins[a]) / spans[a])
.collect();
let mut best = 0;
let mut best_dist2 = f64::INFINITY;
for (i, row) in feats.iter().enumerate() {
let dist2: f64 = row
.iter()
.enumerate()
.map(|(a, &v)| {
let n = (v - mins[a]) / spans[a];
(n - q[a]) * (n - q[a])
})
.sum();
if dist2 < best_dist2 {
best_dist2 = dist2;
best = i;
}
}
Some(best)
}
#[derive(Debug, Default)]
pub struct UtilGridCache {
grids: Mutex<HashMap<String, Option<Arc<UtilGrid>>>>,
}
impl UtilGridCache {
pub fn new() -> Self {
Self::default()
}
pub fn get_or_try_build<F>(
&self,
key: &str,
builder: F,
) -> Result<Option<Arc<UtilGrid>>, AicError>
where
F: FnOnce() -> Result<Option<UtilGrid>, AicError>,
{
let mut grids = self.grids.lock().expect("util grid cache poisoned");
if let Some(cached) = grids.get(key) {
return Ok(cached.clone());
}
let built = builder()?.map(Arc::new);
grids.insert(key.to_string(), built.clone());
Ok(built)
}
}
#[derive(Debug)]
pub struct ZeroAwareDeltaLookup {
coords: Vec<Vec<f64>>,
latencies: Vec<f64>,
mins: Vec<f64>,
spans: Vec<f64>,
norm: Vec<Vec<f64>>,
}
impl ZeroAwareDeltaLookup {
pub fn new(points: Vec<(Vec<f64>, f64)>) -> Self {
let kept: Vec<(Vec<f64>, f64)> =
points.into_iter().filter(|(_, lat)| *lat >= 0.0).collect();
if kept.is_empty() {
return Self {
coords: Vec::new(),
latencies: Vec::new(),
mins: Vec::new(),
spans: Vec::new(),
norm: Vec::new(),
};
}
let dims = kept[0].0.len();
let logc: Vec<Vec<f64>> = kept
.iter()
.map(|(c, _)| c.iter().map(|&v| log_floor(v)).collect())
.collect();
let mut mins = vec![f64::INFINITY; dims];
let mut maxs = vec![f64::NEG_INFINITY; dims];
for row in &logc {
for (a, &v) in row.iter().enumerate() {
mins[a] = mins[a].min(v);
maxs[a] = maxs[a].max(v);
}
}
let spans: Vec<f64> = mins
.iter()
.zip(&maxs)
.map(|(&lo, &hi)| if hi - lo > 0.0 { hi - lo } else { 1.0 })
.collect();
let norm: Vec<Vec<f64>> = logc
.iter()
.map(|row| {
row.iter()
.enumerate()
.map(|(a, &v)| (v - mins[a]) / spans[a])
.collect()
})
.collect();
Self {
latencies: kept.iter().map(|(_, lat)| *lat).collect(),
coords: kept.into_iter().map(|(c, _)| c).collect(),
mins,
spans,
norm,
}
}
pub fn estimate<F>(&self, query: &[f64], sol_fn: F) -> Result<f64, AicError>
where
F: Fn(&[f64]) -> f64,
{
if self.latencies.is_empty() {
return Err(AicError::EmpiricalNotImplemented(format!(
"No empirical compute_scale delta data is available at query={query:?}."
)));
}
let q: Vec<f64> = query
.iter()
.enumerate()
.map(|(a, &v)| (log_floor(v) - self.mins[a]) / self.spans[a])
.collect();
let mut best = 0;
let mut best_dist2 = f64::INFINITY;
for (i, row) in self.norm.iter().enumerate() {
let dist2: f64 = row.iter().zip(&q).map(|(&x, &y)| (x - y) * (x - y)).sum();
if dist2 < best_dist2 {
best_dist2 = dist2;
best = i;
}
}
let reference_latency = self.latencies[best];
if reference_latency == 0.0 {
return Ok(0.0);
}
let reference_sol = sol_fn(&self.coords[best]);
let query_sol = sol_fn(query);
if reference_sol <= 0.0 || query_sol <= 0.0 {
return Err(AicError::EmpiricalNotImplemented(format!(
"No positive SOL reference is available for compute_scale at query={query:?}."
)));
}
Ok(query_sol / (reference_sol / reference_latency))
}
}
#[derive(Debug, Default)]
pub struct DeltaLookupCache {
lookups: Mutex<HashMap<String, Arc<ZeroAwareDeltaLookup>>>,
}
impl DeltaLookupCache {
pub fn new() -> Self {
Self::default()
}
pub fn get_or_try_build<F>(
&self,
key: &str,
builder: F,
) -> Result<Arc<ZeroAwareDeltaLookup>, AicError>
where
F: FnOnce() -> Result<ZeroAwareDeltaLookup, AicError>,
{
let mut lookups = self.lookups.lock().expect("delta lookup cache poisoned");
if let Some(cached) = lookups.get(key) {
return Ok(cached.clone());
}
let built = Arc::new(builder()?);
lookups.insert(key.to_string(), built.clone());
Ok(built)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn approx(a: f64, b: f64) {
assert!((a - b).abs() < 1e-12, "expected {b}, got {a}");
}
#[test]
fn exact_singleton_duplicate_and_empty_grid_contracts() {
let exact = UtilGrid::new(vec![
UtilSample::new(vec![16.0], 0.8),
UtilSample::new(vec![8.0], 0.2),
UtilSample::new(vec![9.0], 0.4),
]);
let duplicate = UtilGrid::new(vec![
UtilSample::new(vec![4.0], 0.6),
UtilSample::new(vec![4.0], 0.7),
]);
approx(exact.util(&[9.0]).unwrap(), 0.4);
approx(
UtilGrid::new(vec![UtilSample::new(vec![0.0], 0.3)])
.util(&[100.0])
.unwrap(),
0.3,
);
approx(duplicate.util(&[4.0]).unwrap(), 0.6);
assert!(UtilGrid::new(vec![]).util(&[1.0, 2.0]).is_none());
}
#[test]
fn one_dim_k2_idw_uses_nearest_samples_in_normalized_log_space() {
let grid = UtilGrid::new(vec![
UtilSample::new(vec![16.0], 0.8),
UtilSample::new(vec![8.0], 0.2),
UtilSample::new(vec![9.0], 0.4),
]);
let distance_9 = 11.0_f64.ln() - 9.0_f64.ln();
let distance_8 = 11.0_f64.ln() - 8.0_f64.ln();
let expected =
(0.4 / distance_9 + 0.2 / distance_8) / (1.0 / distance_9 + 1.0 / distance_8);
approx(grid.util(&[11.0]).unwrap(), expected);
}
#[test]
fn multidimensional_k2_idw_uses_nearest_samples() {
let grid = UtilGrid::new(vec![
UtilSample::new(vec![1.0, 1.0], 0.2),
UtilSample::new(vec![100.0, 1.0], 0.6),
UtilSample::new(vec![100.0, 100.0], 1.0),
]);
approx(grid.util(&[10.0, 1.0]).unwrap(), 0.4);
}
#[test]
fn one_dim_extrapolation_clamps_to_measured_bounds() {
let grid = UtilGrid::new(vec![
UtilSample::new(vec![8.0], 0.2),
UtilSample::new(vec![16.0], 0.8),
]);
approx(grid.util(&[1.0]).unwrap(), 0.2);
approx(grid.util(&[128.0]).unwrap(), 0.8);
}
#[test]
fn multidimensional_extrapolation_clamps_each_axis() {
let grid = UtilGrid::new(vec![
UtilSample::new(vec![1.0, 1.0], 0.2),
UtilSample::new(vec![1.0, 10.0], 0.4),
UtilSample::new(vec![10.0, 1.0], 0.8),
]);
approx(grid.util(&[0.1, 100.0]).unwrap(), 0.4);
}
#[test]
fn build_samples_filters_non_positive_latency_and_sol() {
let samples = build_samples(
vec![
(vec![2.0], 4.0), (vec![3.0], 0.0), (vec![4.0], -1.0), (vec![0.5], 1.0), ],
|coords| if coords[0] >= 1.0 { coords[0] } else { 0.0 },
);
assert_eq!(samples.len(), 1);
approx(samples[0].util, 0.5);
}
#[test]
fn estimate_returns_latency_and_util_or_typed_miss() {
let grid = UtilGrid::new(vec![UtilSample::new(vec![1.0], 0.5)]);
let (latency, util) = estimate(1.0, &[1.0], Some(&grid), 1.0).unwrap();
approx(latency, 2.0);
approx(util, 0.5);
let (latency, _) = estimate(1.0, &[1.0], Some(&grid), 2.0).unwrap();
approx(latency, 1.0);
let missing = estimate(1.0, &[1.0], None, 1.0);
assert!(matches!(missing, Err(AicError::EmpiricalNotImplemented(_))));
let empty = UtilGrid::new(vec![]);
let empty_res = estimate(1.0, &[1.0], Some(&empty), 1.0);
assert!(matches!(
empty_res,
Err(AicError::EmpiricalNotImplemented(_))
));
}
#[test]
fn nearest_candidate_matches_python_normalised_log_selection() {
let idx = nearest_candidate_index(&[90.0], &[vec![1.0], vec![100.0]]);
assert_eq!(idx, Some(1));
assert_eq!(nearest_candidate_index(&[5.0], &[vec![1.0]]), Some(0));
assert_eq!(nearest_candidate_index(&[5.0], &[]), None);
}
#[test]
fn util_grid_cache_memoises_hits_and_misses_but_not_errors() {
let cache = UtilGridCache::new();
let mut builds = 0;
let grid = cache.get_or_try_build("k", || {
builds += 1;
Ok(Some(UtilGrid::new(vec![UtilSample::new(vec![1.0], 0.5)])))
});
assert!(grid.unwrap().is_some());
let again = cache.get_or_try_build("k", || {
builds += 1;
Ok(None)
});
assert!(again.unwrap().is_some());
assert_eq!(builds, 1);
let miss = cache.get_or_try_build("missing", || Ok(None));
assert!(miss.unwrap().is_none());
let miss_again =
cache.get_or_try_build("missing", || panic!("memoised miss must not rebuild"));
assert!(miss_again.unwrap().is_none());
let err = cache.get_or_try_build("broken", || {
Err(AicError::PerfDatabase("schema".to_string()))
});
assert!(err.is_err());
let recovered = cache.get_or_try_build("broken", || Ok(None));
assert!(recovered.unwrap().is_none());
}
#[test]
fn provenance_tier_mirrors_python_provenance_order() {
let tiers = [
(ProvenanceTier::Silicon, 0u8, "silicon"),
(ProvenanceTier::Empirical, 1, "empirical"),
(ProvenanceTier::XShape, 2, "xshape"),
(ProvenanceTier::XQuant, 3, "xquant"),
(ProvenanceTier::XProfile, 4, "xprofile"),
(ProvenanceTier::XOp, 5, "xop"),
];
for (tier, rank, tag) in tiers {
assert_eq!(tier as u8, rank);
assert_eq!(tier.as_str(), tag);
assert_eq!(ProvenanceTier::from_rank(rank), tier);
assert_eq!(ProvenanceTier::from_tag(tag), Some(tier));
}
assert_eq!(ProvenanceTier::from_tag("unknown"), None);
assert!(ProvenanceTier::XOp > ProvenanceTier::Empirical);
assert_eq!(ProvenanceTier::from_rank(200), ProvenanceTier::XOp);
}
#[test]
fn zero_aware_delta_keeps_zeroes_and_freezes_utilization() {
let lookup =
ZeroAwareDeltaLookup::new(vec![(vec![16.0, 16.0], 0.0), (vec![1024.0, 1024.0], 2.0)]);
let sol = |c: &[f64]| c[0] * c[1];
assert_eq!(lookup.estimate(&[8.0, 8.0], sol).unwrap(), 0.0);
let expected = (2048.0 * 2048.0) / ((1024.0 * 1024.0) / 2.0);
assert!((lookup.estimate(&[2048.0, 2048.0], sol).unwrap() - expected).abs() < 1e-12);
let empty = ZeroAwareDeltaLookup::new(vec![]);
assert!(matches!(
empty.estimate(&[1.0, 1.0], sol),
Err(AicError::EmpiricalNotImplemented(_))
));
}
}