scirs2_core/ndarray_ext/elementwise/
functions_4.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::numeric::Float;
6use crate::simd_ops::{AutoOptimizer, SimdUnifiedOps};
7use ::ndarray::{Array1, ArrayView1};
8
9/// Apply ELU (Exponential Linear Unit) activation using SIMD operations
10///
11/// ELU is defined as:
12/// - f(x) = x, if x >= 0
13/// - f(x) = α * (exp(x) - 1), if x < 0
14///
15/// ELU is used in deep neural networks to:
16/// - Push mean activations closer to zero (faster learning)
17/// - Have negative values (unlike ReLU) for better gradient flow
18/// - Have a smooth curve everywhere (unlike Leaky ReLU)
19///
20/// # Arguments
21/// * `x` - Input array
22/// * `alpha` - Scaling factor for negative inputs (commonly 1.0)
23///
24/// # Returns
25/// * Array with ELU applied elementwise
26///
27/// # Example
28/// ```
29/// use scirs2_core::ndarray_ext::elementwise::elu_simd;
30/// use ndarray::{array, ArrayView1};
31///
32/// let x = array![1.0_f32, 0.0, -1.0, -2.0];
33/// let result = elu_simd(&x.view(), 1.0);
34/// assert!((result[0] - 1.0).abs() < 1e-6);  // Positive: unchanged
35/// assert!((result[1] - 0.0).abs() < 1e-6);  // Zero: unchanged
36/// assert!(result[2] < 0.0);  // Negative: α * (exp(x) - 1) < 0
37/// ```
38pub fn elu_simd<F>(x: &ArrayView1<F>, alpha: F) -> Array1<F>
39where
40    F: Float + SimdUnifiedOps,
41{
42    if x.is_empty() {
43        return Array1::zeros(0);
44    }
45    let optimizer = AutoOptimizer::new();
46    if optimizer.should_use_simd(x.len()) {
47        return F::simd_elu(x, alpha);
48    }
49    F::simd_elu(x, alpha)
50}
51/// Apply Leaky ReLU / PReLU activation using SIMD operations
52///
53/// Leaky ReLU (Parametric ReLU when alpha is learned) is defined as:
54/// - f(x) = x, if x >= 0
55/// - f(x) = alpha * x, if x < 0
56///
57/// Leaky ReLU addresses the "dying ReLU" problem by allowing
58/// a small gradient for negative inputs, preventing neurons from
59/// becoming permanently inactive.
60///
61/// # Arguments
62/// * `x` - Input array
63/// * `alpha` - Slope for negative inputs (commonly 0.01 for Leaky ReLU, learned for PReLU)
64///
65/// # Returns
66/// * Array with Leaky ReLU applied elementwise
67///
68/// # Example
69/// ```
70/// use scirs2_core::ndarray_ext::elementwise::leaky_relu_simd;
71/// use ndarray::{array, ArrayView1};
72///
73/// let x = array![1.0_f32, 0.0, -1.0, -2.0];
74/// let result = leaky_relu_simd(&x.view(), 0.01);
75/// assert!((result[0] - 1.0).abs() < 1e-6);    // Positive: unchanged
76/// assert!((result[1] - 0.0).abs() < 1e-6);    // Zero: unchanged
77/// assert!((result[2] - (-0.01)).abs() < 1e-6); // Negative: alpha * x
78/// ```
79pub fn leaky_relu_simd<F>(x: &ArrayView1<F>, alpha: F) -> Array1<F>
80where
81    F: Float + SimdUnifiedOps,
82{
83    if x.is_empty() {
84        return Array1::zeros(0);
85    }
86    let optimizer = AutoOptimizer::new();
87    if optimizer.should_use_simd(x.len()) {
88        return F::simd_leaky_relu(x, alpha);
89    }
90    F::simd_leaky_relu(x, alpha)
91}
92/// Alias for leaky_relu_simd - PReLU (Parametric ReLU)
93///
94/// PReLU is mathematically identical to Leaky ReLU, but the alpha
95/// parameter is learned during training rather than being fixed.
96/// This function provides a convenience alias for neural network code
97/// that uses PReLU terminology.
98#[inline]
99pub fn prelu_simd<F>(x: &ArrayView1<F>, alpha: F) -> Array1<F>
100where
101    F: Float + SimdUnifiedOps,
102{
103    leaky_relu_simd(x, alpha)
104}
105/// Apply SELU (Scaled Exponential Linear Unit) activation using SIMD operations
106///
107/// SELU is defined as:
108/// - f(x) = λ * x, if x > 0
109/// - f(x) = λ * α * (exp(x) - 1), if x <= 0
110///
111/// where λ ≈ 1.0507 and α ≈ 1.6733 are fixed constants.
112///
113/// SELU is the key activation for Self-Normalizing Neural Networks (SNNs):
114/// - Automatically maintains mean ≈ 0 and variance ≈ 1 through layers
115/// - Eliminates the need for Batch Normalization
116/// - Requires LeCun Normal initialization for weights
117/// - Works best with fully-connected networks
118///
119/// # Arguments
120/// * `x` - Input array
121///
122/// # Returns
123/// * Array with SELU applied elementwise
124///
125/// # Example
126/// ```
127/// use scirs2_core::ndarray_ext::elementwise::selu_simd;
128/// use ndarray::{array, ArrayView1};
129///
130/// let x = array![1.0_f32, 0.0, -1.0, -2.0];
131/// let result = selu_simd(&x.view());
132/// assert!(result[0] > 1.0);  // Positive: scaled by λ ≈ 1.0507
133/// assert!((result[1] - 0.0).abs() < 1e-6);  // Zero: unchanged
134/// assert!(result[2] < 0.0);  // Negative: λ * α * (exp(x) - 1) < 0
135/// ```
136pub fn selu_simd<F>(x: &ArrayView1<F>) -> Array1<F>
137where
138    F: Float + SimdUnifiedOps,
139{
140    if x.is_empty() {
141        return Array1::zeros(0);
142    }
143    let optimizer = AutoOptimizer::new();
144    if optimizer.should_use_simd(x.len()) {
145        return F::simd_selu(x);
146    }
147    F::simd_selu(x)
148}
149/// Apply Hardsigmoid activation using SIMD operations
150///
151/// Hardsigmoid is defined as:
152/// - f(x) = 0, if x <= -3
153/// - f(x) = 1, if x >= 3
154/// - f(x) = (x + 3) / 6, otherwise
155///
156/// Hardsigmoid is a piecewise linear approximation of sigmoid:
157/// - Used in MobileNetV3 for efficient mobile inference
158/// - Avoids expensive exp() computation
159/// - Output always in range [0, 1]
160///
161/// # Arguments
162/// * `x` - Input array
163///
164/// # Returns
165/// * Array with Hardsigmoid applied elementwise
166///
167/// # Example
168/// ```
169/// use scirs2_core::ndarray_ext::elementwise::hardsigmoid_simd;
170/// use ndarray::{array, ArrayView1};
171///
172/// let x = array![-4.0_f32, -3.0, 0.0, 3.0, 4.0];
173/// let result = hardsigmoid_simd(&x.view());
174/// assert!((result[0] - 0.0).abs() < 1e-6);   // Saturated at 0
175/// assert!((result[1] - 0.0).abs() < 1e-6);   // Boundary
176/// assert!((result[2] - 0.5).abs() < 1e-6);   // Linear region: (0+3)/6 = 0.5
177/// assert!((result[3] - 1.0).abs() < 1e-6);   // Boundary
178/// assert!((result[4] - 1.0).abs() < 1e-6);   // Saturated at 1
179/// ```
180pub fn hardsigmoid_simd<F>(x: &ArrayView1<F>) -> Array1<F>
181where
182    F: Float + SimdUnifiedOps,
183{
184    if x.is_empty() {
185        return Array1::zeros(0);
186    }
187    let optimizer = AutoOptimizer::new();
188    if optimizer.should_use_simd(x.len()) {
189        return F::simd_hardsigmoid(x);
190    }
191    F::simd_hardsigmoid(x)
192}
193/// Apply Hardswish activation using SIMD operations
194///
195/// Hardswish is defined as:
196/// - f(x) = 0, if x <= -3
197/// - f(x) = x, if x >= 3
198/// - f(x) = x * (x + 3) / 6, otherwise
199///
200/// Hardswish is a piecewise linear approximation of Swish:
201/// - Used in MobileNetV3 for efficient mobile inference
202/// - Self-gating like Swish but without exp() computation
203/// - Smooth at boundaries despite being piecewise
204///
205/// # Arguments
206/// * `x` - Input array
207///
208/// # Returns
209/// * Array with Hardswish applied elementwise
210///
211/// # Example
212/// ```
213/// use scirs2_core::ndarray_ext::elementwise::hardswish_simd;
214/// use ndarray::{array, ArrayView1};
215///
216/// let x = array![-4.0_f32, -3.0, 0.0, 3.0, 4.0];
217/// let result = hardswish_simd(&x.view());
218/// assert!((result[0] - 0.0).abs() < 1e-6);   // Saturated at 0
219/// assert!((result[1] - 0.0).abs() < 1e-6);   // Boundary: -3 * 0 / 6 = 0
220/// assert!((result[2] - 0.0).abs() < 1e-6);   // Linear: 0 * 3 / 6 = 0
221/// assert!((result[3] - 3.0).abs() < 1e-6);   // Boundary: identity
222/// assert!((result[4] - 4.0).abs() < 1e-6);   // Identity region
223/// ```
224pub fn hardswish_simd<F>(x: &ArrayView1<F>) -> Array1<F>
225where
226    F: Float + SimdUnifiedOps,
227{
228    if x.is_empty() {
229        return Array1::zeros(0);
230    }
231    let optimizer = AutoOptimizer::new();
232    if optimizer.should_use_simd(x.len()) {
233        return F::simd_hardswish(x);
234    }
235    F::simd_hardswish(x)
236}
237/// Apply Sinc function using SIMD operations
238///
239/// The normalized sinc function is defined as:
240/// - sinc(x) = sin(πx) / (πx) for x ≠ 0
241/// - sinc(0) = 1 (by L'Hôpital's rule)
242///
243/// The sinc function is fundamental in signal processing:
244/// - Ideal low-pass filter impulse response
245/// - Whittaker-Shannon interpolation formula
246/// - Windowing functions (Lanczos kernel)
247/// - Sampling theory and Nyquist theorem
248///
249/// # Arguments
250/// * `x` - Input array
251///
252/// # Returns
253/// * Array with sinc applied elementwise
254///
255/// # Example
256/// ```
257/// use scirs2_core::ndarray_ext::elementwise::sinc_simd;
258/// use ndarray::{array, ArrayView1};
259///
260/// let x = array![0.0_f64, 0.5, 1.0, 2.0];
261/// let result = sinc_simd(&x.view());
262/// assert!((result[0] - 1.0).abs() < 1e-10);   // sinc(0) = 1
263/// assert!((result[2] - 0.0).abs() < 1e-10);   // sinc(1) = 0
264/// assert!((result[3] - 0.0).abs() < 1e-10);   // sinc(2) = 0
265/// ```
266pub fn sinc_simd<F>(x: &ArrayView1<F>) -> Array1<F>
267where
268    F: Float + SimdUnifiedOps,
269{
270    if x.is_empty() {
271        return Array1::zeros(0);
272    }
273    let optimizer = AutoOptimizer::new();
274    if optimizer.should_use_simd(x.len()) {
275        return F::simd_sinc(x);
276    }
277    F::simd_sinc(x)
278}
279/// Apply Log-Softmax function using SIMD operations
280///
281/// The log-softmax function is defined as:
282/// log_softmax(x_i) = x_i - log(Σ_j exp(x_j))
283///
284/// This is more numerically stable than computing log(softmax(x)) directly,
285/// and is critical for neural network training:
286/// - Cross-entropy loss computation
287/// - Classification networks (output layer)
288/// - Transformer language models
289/// - Large language models (LLMs)
290///
291/// # Mathematical Properties
292///
293/// - log_softmax(x) = x - logsumexp(x)
294/// - Σ exp(log_softmax(x)) = 1 (outputs are log-probabilities)
295/// - log_softmax(x + c) = log_softmax(x) (invariant to constant shift)
296/// - Maximum output element approaches 0 for peaked distributions
297///
298/// # Arguments
299/// * `x` - Input array of logits (unnormalized log-probabilities)
300///
301/// # Returns
302/// * Array with log-softmax applied elementwise (log-probabilities that sum to 0)
303///
304/// # Example
305/// ```
306/// use scirs2_core::ndarray_ext::elementwise::log_softmax_simd;
307/// use ndarray::{array, ArrayView1};
308///
309/// let logits = array![1.0_f64, 2.0, 3.0];
310/// let log_probs = log_softmax_simd(&logits.view());
311///
312/// // Verify: exp(log_probs) sums to 1
313/// let probs: f64 = log_probs.mapv(|lp| lp.exp()).sum();
314/// assert!((probs - 1.0).abs() < 1e-10);
315///
316/// // log_softmax values are always <= 0
317/// for &lp in log_probs.iter() {
318///     assert!(lp <= 0.0);
319/// }
320/// ```
321///
322/// # Applications
323///
324/// - **Cross-Entropy Loss**: -Σ target * log_softmax(logits)
325/// - **Classification**: Converting logits to log-probabilities
326/// - **Transformers**: Final output layer for token prediction
327/// - **Language Models**: Computing perplexity and token probabilities
328/// - **Numerical Stability**: Avoiding underflow in softmax computation
329pub fn log_softmax_simd<F>(x: &ArrayView1<F>) -> Array1<F>
330where
331    F: Float + SimdUnifiedOps,
332{
333    if x.is_empty() {
334        return Array1::zeros(0);
335    }
336    let optimizer = AutoOptimizer::new();
337    if optimizer.should_use_simd(x.len()) {
338        return F::simd_log_softmax(x);
339    }
340    F::simd_log_softmax(x)
341}
342/// Apply inverse hyperbolic sine (asinh) using SIMD operations
343///
344/// The inverse hyperbolic sine is defined as:
345/// asinh(x) = ln(x + √(x² + 1))
346///
347/// Domain: (-∞, +∞), Range: (-∞, +∞)
348/// This is the inverse function of sinh.
349///
350/// # Mathematical Properties
351///
352/// - asinh(0) = 0
353/// - asinh(-x) = -asinh(x) (odd function)
354/// - asinh'(x) = 1/√(x² + 1)
355/// - For large x: asinh(x) ≈ ln(2x)
356///
357/// # Arguments
358/// * `x` - Input array
359///
360/// # Returns
361/// * Array with asinh applied elementwise
362///
363/// # Example
364/// ```
365/// use scirs2_core::ndarray_ext::elementwise::asinh_simd;
366/// use ndarray::{array, ArrayView1};
367///
368/// let x = array![0.0_f64, 1.0, -1.0, 10.0];
369/// let result = asinh_simd(&x.view());
370/// assert!((result[0] - 0.0).abs() < 1e-10);
371/// assert!((result[1] - 0.881373587).abs() < 1e-6);  // asinh(1)
372/// assert!((result[1] + result[2]).abs() < 1e-10);  // odd function
373/// ```
374///
375/// # Applications
376///
377/// - **Hyperbolic Geometry**: Distance calculations in hyperbolic space
378/// - **Special Relativity**: Rapidity in Lorentz transformations
379/// - **Signal Processing**: Parametric representation of signals
380/// - **Statistics**: Transformations for variance stabilization
381pub fn asinh_simd<F>(x: &ArrayView1<F>) -> Array1<F>
382where
383    F: Float + SimdUnifiedOps,
384{
385    if x.is_empty() {
386        return Array1::zeros(0);
387    }
388    let optimizer = AutoOptimizer::new();
389    if optimizer.should_use_simd(x.len()) {
390        return F::simd_asinh(x);
391    }
392    F::simd_asinh(x)
393}
394/// Apply inverse hyperbolic cosine (acosh) using SIMD operations
395///
396/// The inverse hyperbolic cosine is defined as:
397/// acosh(x) = ln(x + √(x² - 1))
398///
399/// Domain: [1, +∞), Range: [0, +∞)
400/// Returns NaN for x < 1.
401/// This is the inverse function of cosh.
402///
403/// # Mathematical Properties
404///
405/// - acosh(1) = 0
406/// - acosh(x) is monotonically increasing for x ≥ 1
407/// - acosh'(x) = 1/√(x² - 1)
408/// - For large x: acosh(x) ≈ ln(2x)
409///
410/// # Arguments
411/// * `x` - Input array (values should be ≥ 1 for valid results)
412///
413/// # Returns
414/// * Array with acosh applied elementwise (NaN for values < 1)
415///
416/// # Example
417/// ```
418/// use scirs2_core::ndarray_ext::elementwise::acosh_simd;
419/// use ndarray::{array, ArrayView1};
420///
421/// let x = array![1.0_f64, 2.0, 10.0];
422/// let result = acosh_simd(&x.view());
423/// assert!((result[0] - 0.0).abs() < 1e-10);         // acosh(1) = 0
424/// assert!((result[1] - 1.316957897).abs() < 1e-6);  // acosh(2)
425///
426/// // Out of domain returns NaN
427/// let x_invalid = array![0.5_f64];
428/// let result_invalid = acosh_simd(&x_invalid.view());
429/// assert!(result_invalid[0].is_nan());
430/// ```
431///
432/// # Applications
433///
434/// - **Hyperbolic Geometry**: Distance in Poincaré disk model
435/// - **Physics**: Catenary curves, suspension bridges
436/// - **Electronics**: Transmission line analysis
437/// - **Computer Graphics**: Hyperbolic tessellations
438pub fn acosh_simd<F>(x: &ArrayView1<F>) -> Array1<F>
439where
440    F: Float + SimdUnifiedOps,
441{
442    if x.is_empty() {
443        return Array1::zeros(0);
444    }
445    let optimizer = AutoOptimizer::new();
446    if optimizer.should_use_simd(x.len()) {
447        return F::simd_acosh(x);
448    }
449    F::simd_acosh(x)
450}
451/// Apply inverse hyperbolic tangent (atanh) using SIMD operations
452///
453/// The inverse hyperbolic tangent is defined as:
454/// atanh(x) = 0.5 * ln((1+x)/(1-x))
455///
456/// Domain: (-1, 1), Range: (-∞, +∞)
457/// Returns ±∞ at x = ±1, NaN for |x| > 1.
458/// This is the inverse function of tanh.
459///
460/// # Mathematical Properties
461///
462/// - atanh(0) = 0
463/// - atanh(-x) = -atanh(x) (odd function)
464/// - atanh(±1) = ±∞
465/// - atanh'(x) = 1/(1 - x²)
466///
467/// # Arguments
468/// * `x` - Input array (values should be in (-1, 1) for finite results)
469///
470/// # Returns
471/// * Array with atanh applied elementwise
472///
473/// # Example
474/// ```
475/// use scirs2_core::ndarray_ext::elementwise::atanh_simd;
476/// use ndarray::{array, ArrayView1};
477///
478/// let x = array![0.0_f64, 0.5, -0.5, 0.99];
479/// let result = atanh_simd(&x.view());
480/// assert!((result[0] - 0.0).abs() < 1e-10);          // atanh(0) = 0
481/// assert!((result[1] - 0.5493061).abs() < 1e-6);     // atanh(0.5)
482/// assert!((result[1] + result[2]).abs() < 1e-10);   // odd function
483///
484/// // Boundaries
485/// let x_boundary = array![1.0_f64, -1.0];
486/// let result_boundary = atanh_simd(&x_boundary.view());
487/// assert!(result_boundary[0].is_infinite() && result_boundary[0] > 0.0);
488/// assert!(result_boundary[1].is_infinite() && result_boundary[1] < 0.0);
489/// ```
490///
491/// # Applications
492///
493/// - **Statistics**: Fisher's z-transformation for correlation coefficients
494/// - **Signal Processing**: Parametric signal representation
495/// - **Probability**: Logit function relationship (atanh(x) = 0.5*logit((1+x)/2))
496/// - **Machine Learning**: Activation function transformations
497pub fn atanh_simd<F>(x: &ArrayView1<F>) -> Array1<F>
498where
499    F: Float + SimdUnifiedOps,
500{
501    if x.is_empty() {
502        return Array1::zeros(0);
503    }
504    let optimizer = AutoOptimizer::new();
505    if optimizer.should_use_simd(x.len()) {
506        return F::simd_atanh(x);
507    }
508    F::simd_atanh(x)
509}
510/// Compute the Beta function B(a, b) using SIMD operations
511///
512/// The Beta function is defined as:
513/// B(a, b) = Γ(a)Γ(b) / Γ(a+b)
514///
515/// This function computes `B(a[i], b[i])` for each pair of elements.
516/// The Beta function is fundamental in:
517/// - Beta distribution (Bayesian priors for probabilities)
518/// - Binomial coefficients: C(n,k) = 1/((n+1)·B(n-k+1, k+1))
519/// - Statistical hypothesis testing
520/// - Machine learning (Dirichlet processes)
521///
522/// # Mathematical Properties
523///
524/// - B(a, b) = B(b, a) (symmetric)
525/// - B(1, 1) = 1
526/// - B(a, 1) = 1/a
527/// - B(1, b) = 1/b
528/// - B(a, b) = B(a+1, b) + B(a, b+1)
529///
530/// # Arguments
531/// * `a` - First parameter array (must be > 0)
532/// * `b` - Second parameter array (must be > 0, same length as `a`)
533///
534/// # Returns
535/// * Array with `B(a[i], b[i])` for each pair
536///
537/// # Example
538/// ```
539/// use scirs2_core::ndarray_ext::elementwise::beta_simd;
540/// use ndarray::{array, ArrayView1};
541///
542/// let a = array![1.0_f64, 2.0, 0.5];
543/// let b = array![1.0_f64, 2.0, 0.5];
544/// let result = beta_simd(&a.view(), &b.view());
545/// assert!((result[0] - 1.0).abs() < 1e-10);       // B(1,1) = 1
546/// assert!((result[1] - 1.0/6.0).abs() < 1e-10);  // B(2,2) = 1/6
547/// assert!((result[2] - std::f64::consts::PI).abs() < 1e-8);  // B(0.5,0.5) = π
548/// ```
549///
550/// # Applications
551///
552/// - **Beta Distribution**: PDF = x^(a-1)(1-x)^(b-1) / B(a,b)
553/// - **Bayesian Statistics**: Prior/posterior for probability parameters
554/// - **A/B Testing**: Conversion rate analysis
555/// - **Machine Learning**: Dirichlet processes, topic modeling
556pub fn beta_simd<F>(a: &ArrayView1<F>, b: &ArrayView1<F>) -> Array1<F>
557where
558    F: Float + SimdUnifiedOps,
559{
560    if a.is_empty() || b.is_empty() {
561        return Array1::zeros(0);
562    }
563    let optimizer = AutoOptimizer::new();
564    if optimizer.should_use_simd(a.len()) {
565        return F::simd_beta(a, b);
566    }
567    F::simd_beta(a, b)
568}
569/// Compute the Log-Beta function ln(B(a, b)) using SIMD operations
570///
571/// The Log-Beta function is defined as:
572/// ln(B(a, b)) = ln(Γ(a)) + ln(Γ(b)) - ln(Γ(a+b))
573///
574/// This is more numerically stable than computing B(a,b) directly,
575/// especially for large arguments where Γ would overflow.
576///
577/// # Mathematical Properties
578///
579/// - ln(B(a, b)) = ln(B(b, a)) (symmetric)
580/// - ln(B(1, 1)) = 0
581/// - ln(B(a, 1)) = -ln(a)
582/// - For large a,b: ln(B(a,b)) ≈ 0.5*ln(2π) - (a+b-0.5)*ln(a+b) + (a-0.5)*ln(a) + (b-0.5)*ln(b)
583///
584/// # Arguments
585/// * `a` - First parameter array (must be > 0)
586/// * `b` - Second parameter array (must be > 0, same length as `a`)
587///
588/// # Returns
589/// * Array with `ln(B(a[i], b[i]))` for each pair
590///
591/// # Example
592/// ```ignore
593/// use scirs2_core::ndarray_ext::elementwise::ln_beta_simd;
594/// use scirs2_core::ndarray::{array, ArrayView1};
595///
596/// let a = array![1.0_f64, 2.0, 10.0];
597/// let b = array![1.0_f64, 2.0, 10.0];
598/// let result = ln_beta_simd(&a.view(), &b.view());
599/// assert!((result[0] - 0.0_f64).abs() < 1e-10);  // ln(B(1,1)) = ln(1) = 0
600/// assert!((result[1] - (-6.0_f64).ln()).abs() < 1e-10);  // ln(B(2,2)) = ln(1/6)
601/// ```
602///
603/// # Applications
604///
605/// - **Numerical Stability**: Avoiding overflow in Beta distribution computations
606/// - **Log-likelihood**: Direct computation of log-probabilities
607/// - **Monte Carlo Methods**: Log-probability computations
608/// - **Variational Inference**: KL divergence between Beta distributions
609pub fn ln_beta_simd<F>(a: &ArrayView1<F>, b: &ArrayView1<F>) -> Array1<F>
610where
611    F: Float + SimdUnifiedOps,
612{
613    if a.is_empty() || b.is_empty() {
614        return Array1::zeros(0);
615    }
616    let optimizer = AutoOptimizer::new();
617    if optimizer.should_use_simd(a.len()) {
618        return F::simd_ln_beta(a, b);
619    }
620    F::simd_ln_beta(a, b)
621}
622/// SIMD-accelerated linear interpolation
623///
624/// Computes element-wise linear interpolation: lerp(a, b, t) = a + t * (b - a)
625/// When t=0, returns a; when t=1, returns b.
626///
627/// # Arguments
628/// * `a` - Start values
629/// * `b` - End values
630/// * `t` - Interpolation parameter (typically in [0, 1])
631///
632/// # Returns
633/// Array of interpolated values
634///
635/// # Examples
636/// ```
637/// use scirs2_core::ndarray::{array, Array1};
638/// use scirs2_core::ndarray_ext::elementwise::lerp_simd;
639///
640/// let a = array![0.0_f32, 0.0, 0.0];
641/// let b = array![10.0_f32, 20.0, 30.0];
642///
643/// // t = 0: returns a
644/// let result = lerp_simd::<f32>(&a.view(), &b.view(), 0.0);
645/// assert!((result[0] - 0.0).abs() < 1e-6);
646///
647/// // t = 1: returns b
648/// let result = lerp_simd::<f32>(&a.view(), &b.view(), 1.0);
649/// assert!((result[0] - 10.0).abs() < 1e-6);
650///
651/// // t = 0.5: midpoint
652/// let result = lerp_simd::<f32>(&a.view(), &b.view(), 0.5);
653/// assert!((result[0] - 5.0).abs() < 1e-6);
654/// ```
655///
656/// # Use Cases
657/// - Animation blending
658/// - Color interpolation
659/// - Smooth parameter transitions
660/// - Gradient computation in neural networks
661pub fn lerp_simd<F>(a: &ArrayView1<F>, b: &ArrayView1<F>, t: F) -> Array1<F>
662where
663    F: Float + SimdUnifiedOps,
664{
665    if a.is_empty() || b.is_empty() {
666        return Array1::zeros(0);
667    }
668    let optimizer = AutoOptimizer::new();
669    if optimizer.should_use_simd(a.len()) {
670        return F::simd_lerp(a, b, t);
671    }
672    F::simd_lerp(a, b, t)
673}
674/// SIMD-accelerated smoothstep interpolation
675///
676/// Returns smooth Hermite interpolation between 0 and 1 when edge0 < x < edge1:
677/// - Returns 0 if x <= edge0
678/// - Returns 1 if x >= edge1
679/// - Returns smooth curve: 3t² - 2t³ where t = (x - edge0) / (edge1 - edge0)
680///
681/// # Arguments
682/// * `edge0` - Lower edge of the transition
683/// * `edge1` - Upper edge of the transition
684/// * `x` - Input values
685///
686/// # Returns
687/// Array of smoothstep values in [0, 1]
688///
689/// # Examples
690/// ```
691/// use scirs2_core::ndarray::{array, Array1};
692/// use scirs2_core::ndarray_ext::elementwise::smoothstep_simd;
693///
694/// let x = array![0.0_f32, 0.25, 0.5, 0.75, 1.0];
695///
696/// let result = smoothstep_simd::<f32>(0.0, 1.0, &x.view());
697/// assert!((result[0] - 0.0).abs() < 1e-6);  // x=0 -> 0
698/// assert!((result[2] - 0.5).abs() < 1e-6);  // x=0.5 -> 0.5
699/// assert!((result[4] - 1.0).abs() < 1e-6);  // x=1 -> 1
700/// ```
701///
702/// # Use Cases
703/// - Shader programming (smooth transitions)
704/// - Activation function variants
705/// - Anti-aliasing
706/// - Soft thresholding
707pub fn smoothstep_simd<F>(edge0: F, edge1: F, x: &ArrayView1<F>) -> Array1<F>
708where
709    F: Float + SimdUnifiedOps,
710{
711    if x.is_empty() {
712        return Array1::zeros(0);
713    }
714    let optimizer = AutoOptimizer::new();
715    if optimizer.should_use_simd(x.len()) {
716        return F::simd_smoothstep(edge0, edge1, x);
717    }
718    F::simd_smoothstep(edge0, edge1, x)
719}
720/// SIMD-accelerated hypotenuse calculation
721///
722/// Computes element-wise hypotenuse: hypot(x, y) = sqrt(x² + y²)
723/// Uses the standard library implementation which handles overflow/underflow correctly.
724///
725/// # Arguments
726/// * `x` - First coordinate values
727/// * `y` - Second coordinate values
728///
729/// # Returns
730/// Array of hypotenuse values
731///
732/// # Examples
733/// ```
734/// use scirs2_core::ndarray::{array, Array1};
735/// use scirs2_core::ndarray_ext::elementwise::hypot_simd;
736///
737/// let x = array![3.0_f64, 5.0, 8.0];
738/// let y = array![4.0_f64, 12.0, 15.0];
739///
740/// let result = hypot_simd::<f64>(&x.view(), &y.view());
741/// assert!((result[0] - 5.0).abs() < 1e-14);   // 3-4-5 triangle
742/// assert!((result[1] - 13.0).abs() < 1e-14);  // 5-12-13 triangle
743/// assert!((result[2] - 17.0).abs() < 1e-14);  // 8-15-17 triangle
744/// ```
745///
746/// # Use Cases
747/// - Distance calculations in 2D
748/// - Computing vector magnitudes
749/// - Complex number modulus: |a+bi| = hypot(a, b)
750/// - Graphics and physics simulations
751pub fn hypot_simd<F>(x: &ArrayView1<F>, y: &ArrayView1<F>) -> Array1<F>
752where
753    F: Float + SimdUnifiedOps,
754{
755    if x.is_empty() || y.is_empty() {
756        return Array1::zeros(0);
757    }
758    let optimizer = AutoOptimizer::new();
759    if optimizer.should_use_simd(x.len()) {
760        return F::simd_hypot(x, y);
761    }
762    F::simd_hypot(x, y)
763}
764/// SIMD-accelerated copysign operation
765///
766/// Returns element-wise magnitude of x with the sign of y.
767///
768/// # Arguments
769/// * `x` - Magnitude source values
770/// * `y` - Sign source values
771///
772/// # Returns
773/// Array where each element has the magnitude of x and sign of y
774///
775/// # Examples
776/// ```
777/// use scirs2_core::ndarray::{array, Array1};
778/// use scirs2_core::ndarray_ext::elementwise::copysign_simd;
779///
780/// let x = array![1.0_f64, -2.0, 3.0, -4.0];
781/// let y = array![-1.0_f64, 1.0, 1.0, -1.0];
782///
783/// let result = copysign_simd::<f64>(&x.view(), &y.view());
784/// assert!((result[0] - (-1.0)).abs() < 1e-14);  // 1 with sign of -1 = -1
785/// assert!((result[1] - 2.0).abs() < 1e-14);     // -2 with sign of 1 = 2
786/// assert!((result[2] - 3.0).abs() < 1e-14);     // 3 with sign of 1 = 3
787/// assert!((result[3] - (-4.0)).abs() < 1e-14); // -4 with sign of -1 = -4
788/// ```
789///
790/// # Use Cases
791/// - Sign manipulation in numerical algorithms
792/// - Implementing special functions (reflection formula)
793/// - Gradient sign propagation
794pub fn copysign_simd<F>(x: &ArrayView1<F>, y: &ArrayView1<F>) -> Array1<F>
795where
796    F: Float + SimdUnifiedOps,
797{
798    if x.is_empty() || y.is_empty() {
799        return Array1::zeros(0);
800    }
801    let optimizer = AutoOptimizer::new();
802    if optimizer.should_use_simd(x.len()) {
803        return F::simd_copysign(x, y);
804    }
805    F::simd_copysign(x, y)
806}
807/// SIMD-accelerated smootherstep interpolation (Ken Perlin's improved version)
808///
809/// Returns smooth Hermite interpolation with second-order continuity.
810/// Formula: 6t⁵ - 15t⁴ + 10t³ where t = (x - edge0) / (edge1 - edge0)
811///
812/// Unlike smoothstep, both the first AND second derivatives are zero at the boundaries,
813/// making it ideal for procedural generation and high-quality animations.
814///
815/// # Arguments
816/// * `edge0` - Lower edge of the transition
817/// * `edge1` - Upper edge of the transition
818/// * `x` - Input values
819///
820/// # Returns
821/// Array of smootherstep values in [0, 1]
822///
823/// # Examples
824/// ```
825/// use scirs2_core::ndarray::{array, Array1};
826/// use scirs2_core::ndarray_ext::elementwise::smootherstep_simd;
827///
828/// let x = array![0.0_f64, 0.25, 0.5, 0.75, 1.0];
829///
830/// let result = smootherstep_simd::<f64>(0.0, 1.0, &x.view());
831/// assert!((result[0] - 0.0).abs() < 1e-14);  // x=0 -> 0
832/// assert!((result[2] - 0.5).abs() < 1e-14);  // x=0.5 -> 0.5
833/// assert!((result[4] - 1.0).abs() < 1e-14);  // x=1 -> 1
834/// ```
835///
836/// # Use Cases
837/// - Perlin noise and procedural generation
838/// - High-quality animation easing
839/// - Shader programming (smooth lighting transitions)
840/// - Gradient-based optimization (smoother loss landscapes)
841pub fn smootherstep_simd<F>(edge0: F, edge1: F, x: &ArrayView1<F>) -> Array1<F>
842where
843    F: Float + SimdUnifiedOps,
844{
845    if x.is_empty() {
846        return Array1::zeros(0);
847    }
848    let optimizer = AutoOptimizer::new();
849    if optimizer.should_use_simd(x.len()) {
850        return F::simd_smootherstep(edge0, edge1, x);
851    }
852    F::simd_smootherstep(edge0, edge1, x)
853}
854/// SIMD-accelerated logaddexp: log(exp(a) + exp(b))
855///
856/// Computes the logarithm of the sum of exponentials in a numerically stable way.
857/// Uses the identity: log(exp(a) + exp(b)) = max(a,b) + log(1 + exp(-|a-b|))
858///
859/// # Arguments
860/// * `a` - First input values
861/// * `b` - Second input values
862///
863/// # Returns
864/// Array of log(exp(a) + exp(b)) values
865///
866/// # Examples
867/// ```
868/// use scirs2_core::ndarray::{array, Array1};
869/// use scirs2_core::ndarray_ext::elementwise::logaddexp_simd;
870///
871/// let a = array![0.0_f64, 1.0, 2.0];
872/// let b = array![0.0_f64, 1.0, 2.0];
873///
874/// let result = logaddexp_simd::<f64>(&a.view(), &b.view());
875/// // log(exp(0) + exp(0)) = log(2) ≈ 0.693
876/// assert!((result[0] - 2.0_f64.ln()).abs() < 1e-14);
877/// ```
878///
879/// # Use Cases
880/// - Log-probability computations (Bayesian inference)
881/// - Log-likelihood calculations in ML
882/// - Hidden Markov Model algorithms
883/// - Cross-entropy loss functions
884pub fn logaddexp_simd<F>(a: &ArrayView1<F>, b: &ArrayView1<F>) -> Array1<F>
885where
886    F: Float + SimdUnifiedOps,
887{
888    if a.is_empty() || b.is_empty() {
889        return Array1::zeros(0);
890    }
891    let optimizer = AutoOptimizer::new();
892    if optimizer.should_use_simd(a.len()) {
893        return F::simd_logaddexp(a, b);
894    }
895    F::simd_logaddexp(a, b)
896}
897/// SIMD-accelerated logit function: log(p / (1-p))
898///
899/// The logit function maps probabilities in (0, 1) to log-odds in (-∞, +∞).
900/// It is the inverse of the sigmoid (logistic) function.
901///
902/// # Arguments
903/// * `a` - Probability values in (0, 1)
904///
905/// # Returns
906/// Array of log-odds values
907///
908/// # Examples
909/// ```
910/// use scirs2_core::ndarray::{array, Array1};
911/// use scirs2_core::ndarray_ext::elementwise::logit_simd;
912///
913/// let p = array![0.5_f64, 0.1, 0.9];
914///
915/// let result = logit_simd::<f64>(&p.view());
916/// // logit(0.5) = log(1) = 0
917/// assert!((result[0] - 0.0).abs() < 1e-14);
918/// // logit(0.1) = log(0.1/0.9) ≈ -2.197
919/// assert!((result[1] - (0.1_f64 / 0.9).ln()).abs() < 1e-14);
920/// ```
921///
922/// # Use Cases
923/// - Logistic regression
924/// - Probability calibration
925/// - Converting probabilities to unbounded space
926/// - Statistical modeling (link functions)
927pub fn logit_simd<F>(a: &ArrayView1<F>) -> Array1<F>
928where
929    F: Float + SimdUnifiedOps,
930{
931    if a.is_empty() {
932        return Array1::zeros(0);
933    }
934    let optimizer = AutoOptimizer::new();
935    if optimizer.should_use_simd(a.len()) {
936        return F::simd_logit(a);
937    }
938    F::simd_logit(a)
939}
940/// SIMD-accelerated element-wise square: x²
941///
942/// Computes the square of each element. This is more efficient than `pow(x, 2)`
943/// since it avoids the overhead of general exponentiation.
944///
945/// # Arguments
946/// * `a` - Input values
947///
948/// # Returns
949/// Array of squared values
950///
951/// # Examples
952/// ```
953/// use scirs2_core::ndarray::{array, Array1};
954/// use scirs2_core::ndarray_ext::elementwise::square_simd;
955///
956/// let x = array![1.0_f64, 2.0, 3.0, -4.0];
957///
958/// let result = square_simd::<f64>(&x.view());
959/// assert!((result[0] - 1.0).abs() < 1e-14);   // 1² = 1
960/// assert!((result[1] - 4.0).abs() < 1e-14);   // 2² = 4
961/// assert!((result[2] - 9.0).abs() < 1e-14);   // 3² = 9
962/// assert!((result[3] - 16.0).abs() < 1e-14);  // (-4)² = 16
963/// ```
964///
965/// # Use Cases
966/// - Computing squared distances
967/// - Variance calculations (sum of squared deviations)
968/// - Loss functions (MSE, L2 regularization)
969/// - Polynomial evaluation
970pub fn square_simd<F>(a: &ArrayView1<F>) -> Array1<F>
971where
972    F: Float + SimdUnifiedOps,
973{
974    if a.is_empty() {
975        return Array1::zeros(0);
976    }
977    let optimizer = AutoOptimizer::new();
978    if optimizer.should_use_simd(a.len()) {
979        return F::simd_square(a);
980    }
981    F::simd_square(a)
982}