use crate::scirs2_compat::{DefaultRng, LinalgOps, SimdOps, StatisticalOps, Tensor as SciTensor};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use trustformers_core::errors::{runtime_error, Result};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimdAnalyticsConfig {
pub enable_simd: bool,
pub vector_width: Option<usize>,
pub num_threads: usize,
pub chunk_size: usize,
pub enable_advanced_stats: bool,
pub enable_ml_predictions: bool,
pub cache_size: usize,
}
impl Default for SimdAnalyticsConfig {
fn default() -> Self {
Self {
enable_simd: true,
vector_width: None, num_threads: num_cpus::get(),
chunk_size: 1024,
enable_advanced_stats: true,
enable_ml_predictions: true,
cache_size: 64 * 1024 * 1024, }
}
}
pub struct SimdPerformanceAnalytics {
config: SimdAnalyticsConfig,
simd_ops: Arc<SimdOps>,
linalg_ops: Arc<LinalgOps>,
stats_ops: Arc<StatisticalOps>,
cache: Arc<std::sync::RwLock<HashMap<String, SciTensor<f32>>>>,
rng: DefaultRng,
}
impl SimdPerformanceAnalytics {
pub fn new(config: SimdAnalyticsConfig) -> Result<Self> {
let vector_width = config.vector_width.unwrap_or_else(|| {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx512f") {
16
}
else if is_x86_feature_detected!("avx2") {
8
}
else if is_x86_feature_detected!("sse4.1") {
4
}
else {
1
} }
#[cfg(target_arch = "aarch64")]
{
if std::arch::is_aarch64_feature_detected!("neon") {
4
}
else {
1
} }
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
1
}
});
let simd_ops = Arc::new(SimdOps::new_with_width(vector_width)?);
let linalg_ops = Arc::new(LinalgOps::new());
let stats_ops = Arc::new(StatisticalOps::new());
Ok(Self {
config,
simd_ops,
linalg_ops,
stats_ops,
cache: Arc::new(std::sync::RwLock::new(HashMap::new())),
rng: DefaultRng::new(),
})
}
pub fn compute_performance_statistics(
&self,
metrics: &[PerformanceMetric],
) -> Result<SimdPerformanceStats> {
if metrics.is_empty() {
return Err(runtime_error("Empty metrics data"));
}
let cpu_usage: Vec<f32> = metrics.iter().map(|m| m.cpu_usage).collect();
let memory_usage: Vec<f32> = metrics.iter().map(|m| m.memory_usage_mb as f32).collect();
let inference_time: Vec<f32> = metrics.iter().map(|m| m.inference_time_ms).collect();
let throughput: Vec<f32> = metrics.iter().map(|m| m.throughput_ops_per_sec).collect();
let cpu_tensor = SciTensor::from_slice(&cpu_usage, &[cpu_usage.len()])?;
let memory_tensor = SciTensor::from_slice(&memory_usage, &[memory_usage.len()])?;
let inference_tensor = SciTensor::from_slice(&inference_time, &[inference_time.len()])?;
let throughput_tensor = SciTensor::from_slice(&throughput, &[throughput.len()])?;
let stats = SimdPerformanceStats {
cpu_stats: self.compute_tensor_stats(&cpu_tensor)?,
memory_stats: self.compute_tensor_stats(&memory_tensor)?,
inference_stats: self.compute_tensor_stats(&inference_tensor)?,
throughput_stats: self.compute_tensor_stats(&throughput_tensor)?,
correlation_matrix: self.compute_correlation_matrix(&[
&cpu_tensor,
&memory_tensor,
&inference_tensor,
&throughput_tensor,
])?,
cross_metric_analysis: self.analyze_cross_metric_relationships(&[
(&cpu_tensor, "cpu"),
(&memory_tensor, "memory"),
(&inference_tensor, "inference"),
(&throughput_tensor, "throughput"),
])?,
anomaly_scores: self.detect_simd_anomalies(&[
&cpu_tensor,
&memory_tensor,
&inference_tensor,
&throughput_tensor,
])?,
};
Ok(stats)
}
fn compute_tensor_stats(&self, tensor: &SciTensor<f32>) -> Result<TensorStats> {
let mean = self.stats_ops.simd_mean(tensor)?;
let variance = self.stats_ops.simd_variance(tensor)?;
let std_dev = variance.sqrt();
let (min, max) = self.stats_ops.simd_minmax(tensor)?;
let median = self.stats_ops.simd_quantile(tensor, 0.5)?;
let q25 = self.stats_ops.simd_quantile(tensor, 0.25)?;
let q75 = self.stats_ops.simd_quantile(tensor, 0.75)?;
let skewness = self.compute_simd_skewness(tensor, mean, std_dev)?;
let kurtosis = self.compute_simd_kurtosis(tensor, mean, std_dev)?;
Ok(TensorStats {
mean,
std_dev,
min,
max,
median,
q25,
q75,
skewness,
kurtosis,
count: tensor.len(),
})
}
fn compute_correlation_matrix(&self, tensors: &[&SciTensor<f32>]) -> Result<Vec<Vec<f32>>> {
let n = tensors.len();
let mut correlation_matrix = vec![vec![0.0; n]; n];
for i in 0..n {
for j in i..n {
let correlation =
if i == j { 1.0 } else { self.simd_ops.correlation(tensors[i], tensors[j])? };
correlation_matrix[i][j] = correlation;
correlation_matrix[j][i] = correlation; }
}
Ok(correlation_matrix)
}
fn analyze_cross_metric_relationships(
&self,
labeled_tensors: &[(&SciTensor<f32>, &str)],
) -> Result<Vec<CrossMetricRelationship>> {
let mut relationships = Vec::new();
for i in 0..labeled_tensors.len() {
for j in (i + 1)..labeled_tensors.len() {
let (tensor_a, label_a) = labeled_tensors[i];
let (tensor_b, label_b) = labeled_tensors[j];
let correlation = self.simd_ops.correlation(tensor_a, tensor_b)?;
let mutual_info = self.compute_mutual_information(tensor_a, tensor_b)?;
let (slope, intercept, r_squared) =
self.simd_linear_regression(tensor_a, tensor_b)?;
relationships.push(CrossMetricRelationship {
metric_a: label_a.to_string(),
metric_b: label_b.to_string(),
correlation,
mutual_information: mutual_info,
linear_regression: RegressionStats {
slope,
intercept,
r_squared,
},
relationship_strength: self.classify_relationship_strength(correlation),
});
}
}
Ok(relationships)
}
fn detect_simd_anomalies(&self, tensors: &[&SciTensor<f32>]) -> Result<Vec<AnomalyScore>> {
let mut anomaly_scores = Vec::new();
for (idx, tensor) in tensors.iter().enumerate() {
let z_scores = self.compute_simd_z_scores(tensor)?;
let z_anomalies = self.simd_ops.abs(&z_scores)?.gt_scalar(3.0)?;
let isolation_scores = self.compute_simd_isolation_scores(tensor)?;
let lof_scores = self.compute_simd_lof_scores(tensor)?;
let combined_scores = self.simd_ops.add(
&self.simd_ops.add(&z_scores, &isolation_scores)?,
&lof_scores,
)?;
anomaly_scores.push(AnomalyScore {
metric_index: idx,
z_score_anomalies: z_anomalies.gt_scalar_bool(3.0),
isolation_scores: isolation_scores.to_vec().clone(),
lof_scores: lof_scores.to_vec().clone(),
combined_scores: combined_scores.to_vec().clone(),
anomaly_threshold: 0.95, });
}
Ok(anomaly_scores)
}
fn compute_simd_skewness(
&self,
tensor: &SciTensor<f32>,
mean: f32,
std_dev: f32,
) -> Result<f32> {
let centered = self.simd_ops.sub_scalar(tensor, mean)?;
let cubed = self.simd_ops.pow_scalar(¢ered, 3.0)?;
let mean_cubed = self.stats_ops.simd_mean(&cubed)?;
Ok(mean_cubed / (std_dev.powi(3)))
}
fn compute_simd_kurtosis(
&self,
tensor: &SciTensor<f32>,
mean: f32,
std_dev: f32,
) -> Result<f32> {
let centered = self.simd_ops.sub_scalar(tensor, mean)?;
let fourth_power = self.simd_ops.pow_scalar(¢ered, 4.0)?;
let mean_fourth = self.stats_ops.simd_mean(&fourth_power)?;
Ok(mean_fourth / (std_dev.powi(4)) - 3.0) }
fn compute_simd_z_scores(&self, tensor: &SciTensor<f32>) -> Result<SciTensor<f32>> {
let mean = self.stats_ops.simd_mean(tensor)?;
let std_dev = self.stats_ops.simd_std(tensor)?;
let centered = self.simd_ops.sub_scalar(tensor, mean)?;
self.simd_ops.div_scalar(¢ered, std_dev)
}
fn simd_linear_regression(
&self,
x: &SciTensor<f32>,
y: &SciTensor<f32>,
) -> Result<(f32, f32, f32)> {
let x_mean = self.stats_ops.simd_mean(x)?;
let y_mean = self.stats_ops.simd_mean(y)?;
let x_centered = self.simd_ops.sub_scalar(x, x_mean)?;
let y_centered = self.simd_ops.sub_scalar(y, y_mean)?;
let xy_product = self.simd_ops.mul(&x_centered, &y_centered)?;
let x_squared = self.simd_ops.mul(&x_centered, &x_centered)?;
let numerator = self.stats_ops.simd_sum(&xy_product)?;
let denominator = self.stats_ops.simd_sum(&x_squared)?;
let slope = if denominator.abs() < f32::EPSILON { 0.0 } else { numerator / denominator };
let intercept = y_mean - slope * x_mean;
let y_pred = self.simd_ops.add_scalar(&self.simd_ops.mul_scalar(x, slope)?, intercept)?;
let residuals = self.simd_ops.sub(y, &y_pred)?;
let ss_res = self.stats_ops.simd_sum(&self.simd_ops.mul(&residuals, &residuals)?)?;
let y_var = self.stats_ops.simd_variance(y)?;
let ss_tot = y_var * (y.len() as f32 - 1.0);
let r_squared = if ss_tot.abs() < f32::EPSILON { 0.0 } else { 1.0 - (ss_res / ss_tot) };
Ok((slope, intercept, r_squared))
}
fn compute_mutual_information(&self, x: &SciTensor<f32>, y: &SciTensor<f32>) -> Result<f32> {
let correlation = self.simd_ops.correlation(x, y)?;
Ok(-0.5 * (1.0 - correlation.powi(2)).ln())
}
fn compute_simd_isolation_scores(&self, tensor: &SciTensor<f32>) -> Result<SciTensor<f32>> {
let mean = self.stats_ops.simd_mean(tensor)?;
let std_dev = self.stats_ops.simd_std(tensor)?;
let z_scores = self.compute_simd_z_scores(tensor)?;
let abs_z = self.simd_ops.abs(&z_scores)?;
self.simd_ops.div_scalar(&abs_z, std_dev)
}
fn compute_simd_lof_scores(&self, tensor: &SciTensor<f32>) -> Result<SciTensor<f32>> {
let sorted_indices = self.get_sorted_indices(tensor)?;
let mut lof_scores = vec![1.0; tensor.len()];
let k = (tensor.len() / 20).max(5).min(50);
for (i, &idx) in sorted_indices.iter().enumerate() {
let start = i.saturating_sub(k / 2);
let end = (i + k / 2 + 1).min(tensor.len());
let local_density = self.compute_local_density(tensor, idx, start, end)?;
lof_scores[idx] = if local_density > 0.0 { 1.0 / local_density } else { 10.0 };
}
SciTensor::from_slice(&lof_scores, &[lof_scores.len()])
}
fn get_sorted_indices(&self, tensor: &SciTensor<f32>) -> Result<Vec<usize>> {
let values = tensor.to_vec();
let mut indices: Vec<usize> = (0..values.len()).collect();
indices.sort_by(|&i, &j| {
values[i].partial_cmp(&values[j]).unwrap_or(std::cmp::Ordering::Equal)
});
Ok(indices)
}
fn compute_local_density(
&self,
tensor: &SciTensor<f32>,
idx: usize,
start: usize,
end: usize,
) -> Result<f32> {
let values = tensor.to_vec();
let target_value = values[idx];
let mut density = 0.0;
let mut count = 0;
for i in start..end {
if i != idx {
let distance = (values[i] - target_value).abs();
if distance > 0.0 {
density += 1.0 / distance;
count += 1;
}
}
}
Ok(if count > 0 { density / count as f32 } else { 0.0 })
}
fn classify_relationship_strength(&self, correlation: f32) -> RelationshipStrength {
let abs_corr = correlation.abs();
if abs_corr >= 0.8 {
RelationshipStrength::Strong
} else if abs_corr >= 0.5 {
RelationshipStrength::Moderate
} else if abs_corr >= 0.3 {
RelationshipStrength::Weak
} else {
RelationshipStrength::VeryWeak
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SimdPerformanceStats {
pub cpu_stats: TensorStats,
pub memory_stats: TensorStats,
pub inference_stats: TensorStats,
pub throughput_stats: TensorStats,
pub correlation_matrix: Vec<Vec<f32>>,
pub cross_metric_analysis: Vec<CrossMetricRelationship>,
pub anomaly_scores: Vec<AnomalyScore>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TensorStats {
pub mean: f32,
pub std_dev: f32,
pub min: f32,
pub max: f32,
pub median: f32,
pub q25: f32,
pub q75: f32,
pub skewness: f32,
pub kurtosis: f32,
pub count: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CrossMetricRelationship {
pub metric_a: String,
pub metric_b: String,
pub correlation: f32,
pub mutual_information: f32,
pub linear_regression: RegressionStats,
pub relationship_strength: RelationshipStrength,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegressionStats {
pub slope: f32,
pub intercept: f32,
pub r_squared: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum RelationshipStrength {
VeryWeak,
Weak,
Moderate,
Strong,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyScore {
pub metric_index: usize,
pub z_score_anomalies: Vec<bool>,
pub isolation_scores: Vec<f32>,
pub lof_scores: Vec<f32>,
pub combined_scores: Vec<f32>,
pub anomaly_threshold: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceMetric {
pub timestamp: f64,
pub cpu_usage: f32,
pub memory_usage_mb: u64,
pub inference_time_ms: f32,
pub throughput_ops_per_sec: f32,
pub gpu_utilization: f32,
pub thermal_state: f32,
pub battery_level: f32,
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_simd_analytics_creation() -> Result<()> {
let config = SimdAnalyticsConfig::default();
let _analytics = SimdPerformanceAnalytics::new(config)?;
Ok(())
}
#[test]
fn test_performance_statistics_computation() -> Result<()> {
let config = SimdAnalyticsConfig::default();
let analytics = SimdPerformanceAnalytics::new(config)?;
let metrics = vec![
PerformanceMetric {
timestamp: 0.0,
cpu_usage: 0.5,
memory_usage_mb: 1000,
inference_time_ms: 10.0,
throughput_ops_per_sec: 100.0,
gpu_utilization: 0.8,
thermal_state: 0.3,
battery_level: 0.9,
},
PerformanceMetric {
timestamp: 1.0,
cpu_usage: 0.6,
memory_usage_mb: 1100,
inference_time_ms: 12.0,
throughput_ops_per_sec: 90.0,
gpu_utilization: 0.85,
thermal_state: 0.35,
battery_level: 0.85,
},
];
let stats = analytics.compute_performance_statistics(&metrics)?;
assert_relative_eq!(stats.cpu_stats.mean, 0.55, epsilon = 1e-6);
assert_relative_eq!(stats.memory_stats.mean, 1050.0, epsilon = 1e-6);
Ok(())
}
#[test]
fn test_correlation_matrix() -> Result<()> {
let config = SimdAnalyticsConfig::default();
let analytics = SimdPerformanceAnalytics::new(config)?;
let tensor1 = SciTensor::from_slice(&[1.0, 2.0, 3.0, 4.0], &[4])?;
let tensor2 = SciTensor::from_slice(&[2.0, 4.0, 6.0, 8.0], &[4])?;
let tensors = vec![&tensor1, &tensor2];
let correlation_matrix = analytics.compute_correlation_matrix(&tensors)?;
assert_eq!(correlation_matrix.len(), 2);
assert_eq!(correlation_matrix[0].len(), 2);
assert_relative_eq!(correlation_matrix[0][0], 1.0, epsilon = 1e-6);
assert_relative_eq!(correlation_matrix[1][1], 1.0, epsilon = 1e-6);
assert_relative_eq!(
correlation_matrix[0][1],
correlation_matrix[1][0],
epsilon = 1e-6
);
Ok(())
}
}