sklears_compose/execution/
simd_utils.rs

1//! SIMD utility functions for execution engine
2//!
3//! This module provides fallback implementations for SIMD operations
4//! used in the execution engine for high-performance metrics calculations.
5
6/// Compute mean of a vector of f32 values
7#[must_use]
8pub fn mean_vec(vec: &[f32]) -> f32 {
9    if vec.is_empty() {
10        0.0
11    } else {
12        vec.iter().sum::<f32>() / vec.len() as f32
13    }
14}
15
16/// Compute variance of a vector of f32 values
17#[must_use]
18pub fn variance_vec(vec: &[f32]) -> f32 {
19    if vec.len() <= 1 {
20        return 0.0;
21    }
22    let mean = mean_vec(vec);
23    vec.iter().map(|x| (x - mean).powi(2)).sum::<f32>() / vec.len() as f32
24}
25
26/// Compute sum of a vector of f32 values
27#[must_use]
28pub fn sum_vec(vec: &[f32]) -> f32 {
29    vec.iter().sum()
30}
31
32/// Add two vectors element-wise
33pub fn add_vec(a: &[f32], b: &[f32], result: &mut [f32]) {
34    assert_eq!(a.len(), b.len());
35    assert_eq!(a.len(), result.len());
36
37    for i in 0..a.len() {
38        result[i] = a[i] + b[i];
39    }
40}
41
42/// Multiply two vectors element-wise
43pub fn multiply_vec(a: &[f32], b: &[f32], result: &mut [f32]) {
44    assert_eq!(a.len(), b.len());
45    assert_eq!(a.len(), result.len());
46
47    for i in 0..a.len() {
48        result[i] = a[i] * b[i];
49    }
50}
51
52/// Divide two vectors element-wise
53pub fn divide_vec(a: &[f32], b: &[f32], result: &mut [f32]) {
54    assert_eq!(a.len(), b.len());
55    assert_eq!(a.len(), result.len());
56
57    for i in 0..a.len() {
58        result[i] = a[i] / b[i];
59    }
60}
61
62/// Compute dot product of two vectors
63#[must_use]
64pub fn dot_product(a: &[f32], b: &[f32]) -> f32 {
65    assert_eq!(a.len(), b.len());
66    a.iter().zip(b.iter()).map(|(&x, &y)| x * y).sum()
67}
68
69/// Find minimum and maximum values in a vector
70#[must_use]
71pub fn min_max_vec(vec: &[f32]) -> (f32, f32) {
72    if vec.is_empty() {
73        return (0.0, 0.0);
74    }
75
76    let mut min_val = vec[0];
77    let mut max_val = vec[0];
78
79    for &val in vec.iter().skip(1) {
80        if val < min_val {
81            min_val = val;
82        }
83        if val > max_val {
84            max_val = val;
85        }
86    }
87
88    (min_val, max_val)
89}
90
91/// In-place division of target vector by divisor vector
92pub fn divide_vec_inplace(target: &mut [f32], divisor: &[f32]) {
93    assert_eq!(target.len(), divisor.len());
94
95    for i in 0..target.len() {
96        target[i] /= divisor[i];
97    }
98}
99
100/// In-place multiplication of target vector by multiplier vector
101pub fn multiply_vec_inplace(target: &mut [f32], multiplier: &[f32]) {
102    assert_eq!(target.len(), multiplier.len());
103
104    for i in 0..target.len() {
105        target[i] *= multiplier[i];
106    }
107}
108
109/// Scale a vector by a scalar value
110pub fn scale_vec(vec: &[f32], scale: f32, result: &mut [f32]) {
111    assert_eq!(vec.len(), result.len());
112
113    for i in 0..vec.len() {
114        result[i] = vec[i] * scale;
115    }
116}
117
118/// Normalize a vector to unit length
119pub fn normalize_vec(vec: &mut [f32]) {
120    let norm = dot_product(vec, vec).sqrt();
121    if norm > 0.0 {
122        for val in vec {
123            *val /= norm;
124        }
125    }
126}
127
128/// Compute L2 norm (Euclidean norm) of a vector
129#[must_use]
130pub fn l2_norm(vec: &[f32]) -> f32 {
131    dot_product(vec, vec).sqrt()
132}
133
134/// Compute L1 norm (Manhattan norm) of a vector
135#[must_use]
136pub fn l1_norm(vec: &[f32]) -> f32 {
137    vec.iter().map(|&x| x.abs()).sum()
138}
139
140/// Element-wise absolute value
141pub fn abs_vec(vec: &[f32], result: &mut [f32]) {
142    assert_eq!(vec.len(), result.len());
143
144    for i in 0..vec.len() {
145        result[i] = vec[i].abs();
146    }
147}
148
149/// Element-wise square root
150pub fn sqrt_vec(vec: &[f32], result: &mut [f32]) {
151    assert_eq!(vec.len(), result.len());
152
153    for i in 0..vec.len() {
154        result[i] = vec[i].sqrt();
155    }
156}
157
158/// Element-wise exponential
159pub fn exp_vec(vec: &[f32], result: &mut [f32]) {
160    assert_eq!(vec.len(), result.len());
161
162    for i in 0..vec.len() {
163        result[i] = vec[i].exp();
164    }
165}
166
167/// Element-wise natural logarithm
168pub fn log_vec(vec: &[f32], result: &mut [f32]) {
169    assert_eq!(vec.len(), result.len());
170
171    for i in 0..vec.len() {
172        result[i] = vec[i].ln();
173    }
174}
175
176/// Compute Euclidean distance between two vectors
177#[must_use]
178pub fn euclidean_distance(a: &[f32], b: &[f32]) -> f32 {
179    assert_eq!(a.len(), b.len());
180
181    a.iter()
182        .zip(b.iter())
183        .map(|(&x, &y)| (x - y).powi(2))
184        .sum::<f32>()
185        .sqrt()
186}
187
188/// Compute cosine similarity between two vectors
189#[must_use]
190pub fn cosine_similarity(a: &[f32], b: &[f32]) -> f32 {
191    assert_eq!(a.len(), b.len());
192
193    let dot = dot_product(a, b);
194    let norm_a = l2_norm(a);
195    let norm_b = l2_norm(b);
196
197    if norm_a > 0.0 && norm_b > 0.0 {
198        dot / (norm_a * norm_b)
199    } else {
200        0.0
201    }
202}