use scirs2_core::ndarray::{Array1, Array2};
pub fn simd_l2_norm(data: &[f64]) -> f64 {
let mut sum_of_squares = 0.0;
for &val in data {
sum_of_squares += val * val;
}
sum_of_squares.sqrt()
}
pub fn simd_l1_norm(data: &[f64]) -> f64 {
let mut sum_abs = 0.0;
for &val in data {
sum_abs += val.abs();
}
sum_abs
}
pub fn simd_soft_threshold(input: &[f64], threshold: f64, output: &mut [f64]) {
for i in 0..input.len() {
let val = input[i];
output[i] = if val > threshold {
val - threshold
} else if val < -threshold {
val + threshold
} else {
0.0
};
}
}
pub fn simd_group_norm(coefficients: &Array2<f64>, groups: &[Vec<usize>]) -> Vec<f64> {
let mut group_norms = Vec::with_capacity(groups.len());
for group in groups {
let mut group_sum = 0.0;
for &feature_idx in group {
if feature_idx < coefficients.nrows() {
let feature_coefs = coefficients.row(feature_idx);
let coef_slice = feature_coefs
.as_slice()
.expect("slice operation should succeed");
let norm_squared = simd_dot_product(coef_slice, coef_slice);
group_sum += norm_squared;
}
}
group_norms.push(group_sum.sqrt());
}
group_norms
}
pub fn simd_dot_product(a: &[f64], b: &[f64]) -> f64 {
let min_len = a.len().min(b.len());
let mut dot_product = 0.0;
for i in 0..min_len {
dot_product += a[i] * b[i];
}
dot_product
}
pub fn simd_residuals(predictions: &[f64], targets: &[f64], residuals: &mut [f64]) {
let min_len = predictions.len().min(targets.len()).min(residuals.len());
for i in 0..min_len {
residuals[i] = predictions[i] - targets[i];
}
}
pub fn simd_coefficient_update(coefficients: &mut [f64], gradients: &[f64], learning_rate: f64) {
let min_len = coefficients.len().min(gradients.len());
for i in 0..min_len {
coefficients[i] -= learning_rate * gradients[i];
}
}
pub fn simd_nuclear_norm_penalty(matrix: &Array2<f64>, lambda: f64) -> f64 {
let trace = simd_trace(matrix);
let frobenius = simd_frobenius_norm(matrix);
lambda * (trace * frobenius).sqrt()
}
pub fn simd_trace(matrix: &Array2<f64>) -> f64 {
let mut trace = 0.0;
let min_dim = matrix.nrows().min(matrix.ncols());
for i in 0..min_dim {
trace += matrix[(i, i)];
}
trace
}
pub fn simd_frobenius_norm(matrix: &Array2<f64>) -> f64 {
let mut sum_squares = 0.0;
for row in matrix.rows() {
let row_slice = row.as_slice().expect("matrix indexing should be valid");
sum_squares += simd_dot_product(row_slice, row_slice);
}
sum_squares.sqrt()
}
pub fn simd_task_similarity(task1_coefs: &Array1<f64>, task2_coefs: &Array1<f64>) -> f64 {
let coef1_slice = task1_coefs
.as_slice()
.expect("slice operation should succeed");
let coef2_slice = task2_coefs
.as_slice()
.expect("slice operation should succeed");
let dot_product = simd_dot_product(coef1_slice, coef2_slice);
let norm1 = simd_l2_norm(coef1_slice);
let norm2 = simd_l2_norm(coef2_slice);
if norm1 == 0.0 || norm2 == 0.0 {
0.0
} else {
dot_product / (norm1 * norm2)
}
}
pub fn simd_max_change(old_coefs: &[f64], new_coefs: &[f64]) -> f64 {
let min_len = old_coefs.len().min(new_coefs.len());
let mut max_change: f64 = 0.0;
for i in 0..min_len {
let change = (new_coefs[i] - old_coefs[i]).abs();
max_change = max_change.max(change);
}
max_change
}