scirs2_core/ndarray_ext/elementwise/functions_3.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/// Compute the base-2 logarithm of each element (SIMD-accelerated).
10///
11/// Computes log₂(x) for each element, where log₂(x) = ln(x) / ln(2).
12///
13/// # Arguments
14///
15/// * `x` - Input 1D array with positive values
16///
17/// # Returns
18///
19/// `Array1<F>` with the same length as input, where each element is the base-2
20/// logarithm. Returns NaN for x ≤ 0, and -∞ for x = 0.
21///
22/// # Performance
23///
24/// - **SIMD**: Automatically used for large arrays (1000+ elements)
25/// - **Scalar**: Used for small arrays or when SIMD is unavailable
26///
27/// # Mathematical Properties
28///
29/// - Domain: (0, ∞)
30/// - Range: (-∞, ∞)
31/// - log₂(1) = 0
32/// - log₂(2) = 1
33/// - log₂(2ⁿ) = n
34/// - log₂(x * y) = log₂(x) + log₂(y)
35/// - log₂(x / y) = log₂(x) - log₂(y)
36/// - log₂(xⁿ) = n * log₂(x)
37/// - Returns NaN for x ≤ 0
38/// - Returns -∞ for x = 0
39///
40/// # Examples
41///
42/// ```
43/// use scirs2_core::ndarray::array;
44/// use scirs2_core::ndarray_ext::elementwise::log2_simd;
45///
46/// let x = array![1.0_f64, 2.0, 4.0, 8.0, 16.0];
47/// let result = log2_simd(&x.view());
48/// // Result: [0.0, 1.0, 2.0, 3.0, 4.0]
49/// ```
50///
51/// # Applications
52///
53/// - **Information Theory**: Shannon entropy (bits), channel capacity
54/// - **Computer Science**: Binary tree depth, algorithm complexity analysis
55/// - **Machine Learning**: Decision trees, information gain
56/// - **Signal Processing**: Octave scales, frequency resolution
57/// - **Data Compression**: Optimal coding, Huffman coding
58/// - **Cryptography**: Key size representation, security levels
59/// - **Scientific Computing**: Binary logarithmic plots
60/// - **Digital Systems**: Bit depth calculations
61///
62/// # See Also
63///
64/// - `ln_simd`: Natural logarithm (base e)
65/// - `log10_simd`: Base-10 logarithm
66/// - `exp_simd`: Exponential function (inverse of ln)
67pub fn log2_simd<F>(x: &ArrayView1<F>) -> Array1<F>
68where
69 F: Float + SimdUnifiedOps,
70{
71 if x.is_empty() {
72 return Array1::zeros(0);
73 }
74 let optimizer = AutoOptimizer::new();
75 if optimizer.should_use_simd(x.len()) {
76 return F::simd_log2(x);
77 }
78 x.mapv(|val| val.log2())
79}
80/// Clamp each element to a specified range [min, max] (SIMD-accelerated).
81///
82/// Constrains each element x to satisfy min ≤ x ≤ max. Values below min are set
83/// to min, values above max are set to max, and values within range are unchanged.
84///
85/// # Arguments
86///
87/// * `x` - Input 1D array
88/// * `min` - Minimum value (lower bound)
89/// * `max` - Maximum value (upper bound)
90///
91/// # Returns
92///
93/// `Array1<F>` with the same length as input, where each element is clamped to [min, max].
94///
95/// # Panics
96///
97/// Panics if min > max (invalid range).
98///
99/// # Performance
100///
101/// - **SIMD**: Automatically used for large arrays (1000+ elements)
102/// - **Scalar**: Used for small arrays or when SIMD is unavailable
103///
104/// # Mathematical Properties
105///
106/// - clamp(x, min, max) = max(min, min(x, max))
107/// - clamp(x, min, max) ∈ [min, max] for all x
108/// - clamp(min, min, max) = min
109/// - clamp(max, min, max) = max
110/// - clamp is idempotent: clamp(clamp(x, a, b), a, b) = clamp(x, a, b)
111/// - clamp preserves monotonicity: if x₁ ≤ x₂, then clamp(x₁) ≤ clamp(x₂)
112///
113/// # Examples
114///
115/// ```
116/// use scirs2_core::ndarray::array;
117/// use scirs2_core::ndarray_ext::elementwise::clamp_simd;
118///
119/// let x = array![-1.0_f64, 0.5, 1.5, 2.5, 3.5];
120/// let result = clamp_simd(&x.view(), 0.0, 2.0);
121/// // Result: [0.0, 0.5, 1.5, 2.0, 2.0]
122/// ```
123///
124/// # Applications
125///
126/// - **Image Processing**: Pixel value normalization (0-255, 0.0-1.0)
127/// - **Neural Networks**: Gradient clipping, activation bounding
128/// - **Computer Vision**: Color space conversions, contrast limiting
129/// - **Signal Processing**: Dynamic range compression, amplitude limiting
130/// - **Data Normalization**: Feature scaling, outlier handling
131/// - **Numerical Stability**: Preventing overflow/underflow in computations
132/// - **Game Development**: Velocity limiting, position constraints
133/// - **Robotics**: Joint angle limits, actuator bounds
134/// - **Audio Processing**: Volume limiting, signal clipping prevention
135/// - **Machine Learning**: Learning rate bounds, weight constraints
136///
137/// # See Also
138///
139/// - `abs_simd`: Absolute value (clamping negative values to positive)
140/// - `floor_simd`: Lower bound only (ceiling at integers)
141/// - `ceil_simd`: Upper bound only (floor at integers)
142pub fn clamp_simd<F>(x: &ArrayView1<F>, min: F, max: F) -> Array1<F>
143where
144 F: Float + SimdUnifiedOps + std::fmt::Debug,
145{
146 assert!(
147 min <= max,
148 "clamp_simd: min ({:?}) must be <= max ({:?})",
149 min,
150 max
151 );
152 if x.is_empty() {
153 return Array1::zeros(0);
154 }
155 let optimizer = AutoOptimizer::new();
156 if optimizer.should_use_simd(x.len()) {
157 return F::simd_clamp(x, min, max);
158 }
159 x.mapv(|val| val.clamp(min, max))
160}
161/// Compute 2^x for each element (SIMD-accelerated).
162///
163/// Computes the base-2 exponential function 2^x for each element.
164///
165/// # Arguments
166///
167/// * `x` - Input 1D array
168///
169/// # Returns
170///
171/// `Array1<F>` with the same length as input, where each element is 2 raised to the
172/// corresponding input power.
173///
174/// # Performance
175///
176/// Uses the identity 2^x = exp(x * ln(2)) with SIMD-accelerated exp and scalar multiply.
177///
178/// # Mathematical Properties
179///
180/// - 2^0 = 1
181/// - 2^1 = 2
182/// - 2^(-1) = 0.5
183/// - 2^n for integer n is exact for small n
184///
185/// # Examples
186///
187/// ```
188/// use scirs2_core::ndarray::array;
189/// use scirs2_core::ndarray_ext::elementwise::exp2_simd;
190///
191/// let x = array![0.0_f64, 1.0, 2.0, 3.0, -1.0];
192/// let result = exp2_simd(&x.view());
193/// // Result: [1.0, 2.0, 4.0, 8.0, 0.5]
194/// ```
195///
196/// # Applications
197///
198/// - **Audio Processing**: Octave/semitone calculations
199/// - **Computer Graphics**: Level of detail (LOD) calculations
200/// - **Floating-Point**: Exponent manipulation
201pub fn exp2_simd<F>(x: &ArrayView1<F>) -> Array1<F>
202where
203 F: Float + SimdUnifiedOps,
204{
205 if x.is_empty() {
206 return Array1::zeros(0);
207 }
208 let optimizer = AutoOptimizer::new();
209 if optimizer.should_use_simd(x.len()) {
210 return F::simd_exp2(x);
211 }
212 F::simd_exp2(x)
213}
214/// Compute the cube root of each element (SIMD-accelerated).
215///
216/// Computes cbrt(x) = x^(1/3) for each element, correctly handling negative values.
217///
218/// # Arguments
219///
220/// * `x` - Input 1D array
221///
222/// # Returns
223///
224/// `Array1<F>` with the same length as input, where each element is the cube root.
225///
226/// # Mathematical Properties
227///
228/// - cbrt(x^3) = x (exact inverse of cubing)
229/// - cbrt(-x) = -cbrt(x) (handles negative numbers)
230/// - cbrt(0) = 0
231/// - cbrt(1) = 1, cbrt(8) = 2, cbrt(27) = 3
232///
233/// # Examples
234///
235/// ```
236/// use scirs2_core::ndarray::array;
237/// use scirs2_core::ndarray_ext::elementwise::cbrt_simd;
238///
239/// let x = array![0.0_f64, 1.0, 8.0, 27.0, -8.0];
240/// let result = cbrt_simd(&x.view());
241/// // Result: [0.0, 1.0, 2.0, 3.0, -2.0]
242/// ```
243///
244/// # Applications
245///
246/// - **Statistics**: Transforming skewed data
247/// - **Physics**: Volume calculations from cubic dimensions
248/// - **Numerical Analysis**: Root-finding algorithms
249pub fn cbrt_simd<F>(x: &ArrayView1<F>) -> Array1<F>
250where
251 F: Float + SimdUnifiedOps,
252{
253 if x.is_empty() {
254 return Array1::zeros(0);
255 }
256 let optimizer = AutoOptimizer::new();
257 if optimizer.should_use_simd(x.len()) {
258 return F::simd_cbrt(x);
259 }
260 x.mapv(|val| val.cbrt())
261}
262/// Compute ln(1+x) for each element (SIMD-accelerated, numerically stable).
263///
264/// Computes the natural logarithm of (1+x) with improved accuracy for small x values
265/// where direct computation of ln(1+x) would lose precision.
266///
267/// # Arguments
268///
269/// * `x` - Input 1D array with values > -1
270///
271/// # Returns
272///
273/// `Array1<F>` with the same length as input, where each element is ln(1+x).
274///
275/// # Mathematical Properties
276///
277/// - ln_1p(0) = 0
278/// - ln_1p(x) ≈ x for |x| << 1 (Taylor series first term)
279/// - More accurate than ln(1+x) when |x| is small
280///
281/// # Examples
282///
283/// ```
284/// use scirs2_core::ndarray::array;
285/// use scirs2_core::ndarray_ext::elementwise::ln_1p_simd;
286///
287/// let x = array![0.0_f64, 1.0, 1e-15, -0.5];
288/// let result = ln_1p_simd(&x.view());
289/// // Result: [0.0, ln(2), ≈1e-15, -ln(2)]
290/// ```
291///
292/// # Applications
293///
294/// - **Finance**: Continuous compound interest rates
295/// - **Statistics**: Log-likelihood computations
296/// - **Numerical Analysis**: Avoiding catastrophic cancellation
297pub fn ln_1p_simd<F>(x: &ArrayView1<F>) -> Array1<F>
298where
299 F: Float + SimdUnifiedOps,
300{
301 if x.is_empty() {
302 return Array1::zeros(0);
303 }
304 let optimizer = AutoOptimizer::new();
305 if optimizer.should_use_simd(x.len()) {
306 return F::simd_ln_1p(x);
307 }
308 x.mapv(|val| val.ln_1p())
309}
310/// Compute exp(x)-1 for each element (SIMD-accelerated, numerically stable).
311///
312/// Computes e^x - 1 with improved accuracy for small x values where direct
313/// computation would lose precision.
314///
315/// # Arguments
316///
317/// * `x` - Input 1D array
318///
319/// # Returns
320///
321/// `Array1<F>` with the same length as input, where each element is exp(x)-1.
322///
323/// # Mathematical Properties
324///
325/// - exp_m1(0) = 0
326/// - exp_m1(x) ≈ x for |x| << 1 (Taylor series first term)
327/// - exp_m1(-x) = -exp_m1(x) / (1 + exp_m1(x))
328/// - More accurate than exp(x)-1 when |x| is small
329///
330/// # Examples
331///
332/// ```
333/// use scirs2_core::ndarray::array;
334/// use scirs2_core::ndarray_ext::elementwise::exp_m1_simd;
335///
336/// let x = array![0.0_f64, 1.0, 1e-15, -1.0];
337/// let result = exp_m1_simd(&x.view());
338/// // Result: [0.0, e-1, ≈1e-15, 1/e - 1]
339/// ```
340///
341/// # Applications
342///
343/// - **Finance**: Continuous compounding calculations
344/// - **Physics**: Small perturbation calculations
345/// - **Numerical Analysis**: Avoiding catastrophic cancellation
346pub fn exp_m1_simd<F>(x: &ArrayView1<F>) -> Array1<F>
347where
348 F: Float + SimdUnifiedOps,
349{
350 if x.is_empty() {
351 return Array1::zeros(0);
352 }
353 let optimizer = AutoOptimizer::new();
354 if optimizer.should_use_simd(x.len()) {
355 return F::simd_exp_m1(x);
356 }
357 x.mapv(|val| val.exp_m1())
358}
359/// Convert degrees to radians for each element (SIMD-accelerated).
360///
361/// Computes x * π / 180 for each element, converting angle measurements
362/// from degrees to radians.
363///
364/// # Arguments
365///
366/// * `x` - Input 1D array of angles in degrees
367///
368/// # Returns
369///
370/// `Array1<F>` with the same length as input, where each element is the
371/// corresponding angle in radians.
372///
373/// # Performance
374///
375/// Uses SIMD scalar multiplication for optimal performance.
376///
377/// # Mathematical Properties
378///
379/// - to_radians(0) = 0
380/// - to_radians(90) = π/2
381/// - to_radians(180) = π
382/// - to_radians(360) = 2π
383///
384/// # Examples
385///
386/// ```
387/// use scirs2_core::ndarray::array;
388/// use scirs2_core::ndarray_ext::elementwise::to_radians_simd;
389///
390/// let degrees = array![0.0, 90.0, 180.0, 360.0];
391/// let radians = to_radians_simd(°rees.view());
392/// // Result: [0.0, π/2, π, 2π]
393/// ```
394///
395/// # Applications
396///
397/// - **Trigonometry**: Converting human-readable angles to radian form
398/// - **Graphics**: Rotation transformations
399/// - **Physics**: Angular velocity and position calculations
400/// - **Navigation**: Bearing and heading conversions
401pub fn to_radians_simd<F>(x: &ArrayView1<F>) -> Array1<F>
402where
403 F: Float + SimdUnifiedOps,
404{
405 if x.is_empty() {
406 return Array1::zeros(0);
407 }
408 let optimizer = AutoOptimizer::new();
409 if optimizer.should_use_simd(x.len()) {
410 return F::simd_to_radians(x);
411 }
412 F::simd_to_radians(x)
413}
414/// Convert radians to degrees for each element (SIMD-accelerated).
415///
416/// Computes x * 180 / π for each element, converting angle measurements
417/// from radians to degrees.
418///
419/// # Arguments
420///
421/// * `x` - Input 1D array of angles in radians
422///
423/// # Returns
424///
425/// `Array1<F>` with the same length as input, where each element is the
426/// corresponding angle in degrees.
427///
428/// # Performance
429///
430/// Uses SIMD scalar multiplication for optimal performance.
431///
432/// # Mathematical Properties
433///
434/// - to_degrees(0) = 0
435/// - to_degrees(π/2) = 90
436/// - to_degrees(π) = 180
437/// - to_degrees(2π) = 360
438///
439/// # Examples
440///
441/// ```
442/// use scirs2_core::ndarray::array;
443/// use scirs2_core::ndarray_ext::elementwise::to_degrees_simd;
444/// use std::f64::consts::PI;
445///
446/// let radians = array![0.0, PI/2.0, PI, 2.0*PI];
447/// let degrees = to_degrees_simd(&radians.view());
448/// // Result: [0.0, 90.0, 180.0, 360.0]
449/// ```
450///
451/// # Applications
452///
453/// - **Trigonometry**: Converting calculation results to human-readable form
454/// - **Graphics**: Displaying rotation angles
455/// - **Physics**: Reporting angular measurements
456/// - **Navigation**: Displaying compass headings
457pub fn to_degrees_simd<F>(x: &ArrayView1<F>) -> Array1<F>
458where
459 F: Float + SimdUnifiedOps,
460{
461 if x.is_empty() {
462 return Array1::zeros(0);
463 }
464 let optimizer = AutoOptimizer::new();
465 if optimizer.should_use_simd(x.len()) {
466 return F::simd_to_degrees(x);
467 }
468 F::simd_to_degrees(x)
469}
470/// Computes the element-wise digamma function ψ(x) = d/dx ln(Γ(x)) using SIMD acceleration.
471///
472/// The digamma function is the logarithmic derivative of the gamma function.
473/// It is essential for:
474/// - Bayesian variational inference (Dirichlet, Beta priors)
475/// - Maximum likelihood estimation for gamma distributions
476/// - Statistical special function computations
477///
478/// # Implementation Details
479///
480/// The implementation uses three techniques for high accuracy:
481/// 1. **Reflection formula**: For x < 0.5, uses ψ(1-x) - π/tan(πx)
482/// 2. **Recurrence relation**: For small x, uses ψ(x+1) = ψ(x) + 1/x
483/// 3. **Asymptotic expansion**: For large x, uses Bernoulli number series
484///
485/// # Arguments
486///
487/// * `x` - Input array of values. Should avoid non-positive integers where digamma has poles.
488///
489/// # Returns
490///
491/// Array of ψ(x) values, same shape as input.
492///
493/// # Mathematical Properties
494///
495/// - ψ(1) = -γ (Euler-Mascheroni constant ≈ -0.5772)
496/// - ψ(n) = -γ + Σ(k=1 to n-1) 1/k for positive integers
497/// - ψ(x+1) = ψ(x) + 1/x
498/// - ψ(1-x) - ψ(x) = π·cot(πx)
499///
500/// # Example
501///
502/// ```ignore
503/// use scirs2_core::ndarray_ext::elementwise::digamma_simd;
504/// use scirs2_core::ndarray::array;
505///
506/// let x = array![1.0f64, 2.0, 3.0, 4.0];
507/// let result = digamma_simd(&x.view());
508/// // ψ(1) ≈ -0.5772, ψ(2) ≈ 0.4228, ψ(3) ≈ 0.9228, ψ(4) ≈ 1.2561
509/// ```
510pub fn digamma_simd<F>(x: &ArrayView1<F>) -> Array1<F>
511where
512 F: Float + SimdUnifiedOps,
513{
514 if x.is_empty() {
515 return Array1::zeros(0);
516 }
517 let optimizer = AutoOptimizer::new();
518 if optimizer.should_use_simd(x.len()) {
519 return F::simd_digamma(x);
520 }
521 F::simd_digamma(x)
522}
523/// Computes the element-wise trigamma function ψ'(x) = d²/dx² ln(Γ(x)) using SIMD acceleration.
524///
525/// The trigamma function is the second derivative of the log-gamma function (first derivative
526/// of digamma). It is critical for:
527/// - Fisher information computation in Bayesian inference
528/// - Variance of gamma and beta distribution parameters
529/// - Maximum likelihood estimation for gamma distributions
530/// - Sensitivity analysis in Bayesian variational inference
531///
532/// # Implementation Details
533///
534/// The implementation uses three techniques for high accuracy:
535/// 1. **Reflection formula**: For x < 0, uses ψ'(1-x) + ψ'(x) = π²/sin²(πx)
536/// 2. **Recurrence relation**: For small x, uses ψ'(x+1) = ψ'(x) - 1/x²
537/// 3. **Asymptotic expansion**: For large x, uses ψ'(x) ≈ 1/x + 1/(2x²) + B₂/x³ - B₄/x⁵ + ...
538///
539/// # Arguments
540///
541/// * `x` - Input array of values. Should avoid non-positive integers where trigamma has poles.
542///
543/// # Returns
544///
545/// Array of ψ'(x) values, same shape as input.
546///
547/// # Mathematical Properties
548///
549/// - ψ'(1) = π²/6 ≈ 1.6449340668 (Basel problem)
550/// - ψ'(n) = π²/6 - Σ(k=1 to n-1) 1/k² for positive integers
551/// - ψ'(x+1) = ψ'(x) - 1/x²
552/// - For large x: ψ'(x) → 1/x
553///
554/// # Example
555///
556/// ```ignore
557/// use scirs2_core::ndarray_ext::elementwise::trigamma_simd;
558/// use scirs2_core::ndarray::array;
559///
560/// let x = array![1.0f64, 2.0, 3.0, 4.0];
561/// let result = trigamma_simd(&x.view());
562/// // ψ'(1) ≈ 1.6449, ψ'(2) ≈ 0.6449, ψ'(3) ≈ 0.3949, ψ'(4) ≈ 0.2838
563/// ```
564pub fn trigamma_simd<F>(x: &ArrayView1<F>) -> Array1<F>
565where
566 F: Float + SimdUnifiedOps,
567{
568 if x.is_empty() {
569 return Array1::zeros(0);
570 }
571 let optimizer = AutoOptimizer::new();
572 if optimizer.should_use_simd(x.len()) {
573 return F::simd_trigamma(x);
574 }
575 F::simd_trigamma(x)
576}
577/// Computes the element-wise log-gamma function ln(Γ(x)) using SIMD acceleration.
578///
579/// The log-gamma function is more numerically stable than computing `gamma(x).ln()`
580/// since it avoids overflow for large arguments and handles the full range of inputs.
581/// This function is extensively used in:
582/// - Statistical distributions (gamma, beta, binomial, Poisson)
583/// - Bayesian inference (prior/posterior computations)
584/// - Maximum likelihood estimation
585/// - Combinatorics (log of binomial coefficients)
586///
587/// # Implementation Details
588///
589/// Uses the Lanczos approximation with reflection formula:
590/// - For x >= 0.5: ln(Γ(z)) = ln(√(2π)) + (z-0.5)·ln(t) - t + ln(sum) where t = z + g - 0.5
591/// - For x < 0.5: ln(Γ(z)) = ln(π) - ln(|sin(πz)|) - ln(Γ(1-z))
592///
593/// # Arguments
594///
595/// * `x` - Input array of values. Poles at non-positive integers (returns +∞).
596///
597/// # Returns
598///
599/// Array of ln(Γ(x)) values, same shape as input.
600///
601/// # Mathematical Properties
602///
603/// - ln(Γ(1)) = ln(Γ(2)) = 0
604/// - ln(Γ(n)) = ln((n-1)!) for positive integers
605/// - ln(Γ(1/2)) = ln(√π) ≈ 0.5724
606/// - For large x: ln(Γ(x)) ≈ (x-0.5)·ln(x) - x + ln(√(2π))
607///
608/// # Example
609///
610/// ```ignore
611/// use scirs2_core::ndarray_ext::elementwise::ln_gamma_simd;
612/// use scirs2_core::ndarray::array;
613///
614/// let x = array![1.0f64, 2.0, 3.0, 4.0, 5.0];
615/// let result = ln_gamma_simd(&x.view());
616/// // ln(Γ(1)) = 0, ln(Γ(2)) = 0, ln(Γ(3)) = ln(2!) ≈ 0.693
617/// // ln(Γ(4)) = ln(3!) ≈ 1.792, ln(Γ(5)) = ln(4!) ≈ 3.178
618/// ```
619pub fn ln_gamma_simd<F>(x: &ArrayView1<F>) -> Array1<F>
620where
621 F: Float + SimdUnifiedOps,
622{
623 if x.is_empty() {
624 return Array1::zeros(0);
625 }
626 let optimizer = AutoOptimizer::new();
627 if optimizer.should_use_simd(x.len()) {
628 return F::simd_ln_gamma(x);
629 }
630 F::simd_ln_gamma(x)
631}
632/// Element-wise error function erf(x) = (2/√π) ∫₀ˣ e^(-t²) dt
633///
634/// Uses SIMD acceleration when available for optimal performance.
635/// Critical for normal distribution CDF: Φ(x) = 0.5 * (1 + erf(x/√2))
636///
637/// # Properties
638/// - erf(0) = 0
639/// - erf(∞) = 1, erf(-∞) = -1
640/// - erf(-x) = -erf(x) (odd function)
641/// - erf(1) ≈ 0.8427007929497148
642///
643/// # Examples
644///
645/// ```
646/// use scirs2_core::ndarray_ext::elementwise::erf_simd;
647/// use scirs2_core::ndarray::array;
648///
649/// let x = array![0.0_f64, 1.0, 2.0, -1.0];
650/// let result = erf_simd(&x.view());
651/// assert!((result[0] - 0.0_f64).abs() < 1e-10); // erf(0) = 0
652/// assert!((result[1] - 0.8427007929497148_f64).abs() < 1e-6); // erf(1)
653/// assert!((result[3] + 0.8427007929497148_f64).abs() < 1e-6); // erf(-1) = -erf(1)
654/// ```
655pub fn erf_simd<F>(x: &ArrayView1<F>) -> Array1<F>
656where
657 F: Float + SimdUnifiedOps,
658{
659 if x.is_empty() {
660 return Array1::zeros(0);
661 }
662 let optimizer = AutoOptimizer::new();
663 if optimizer.should_use_simd(x.len()) {
664 return F::simd_erf(x);
665 }
666 F::simd_erf(x)
667}
668/// Element-wise complementary error function erfc(x) = 1 - erf(x)
669///
670/// More numerically stable than computing 1 - erf(x) directly for large x.
671/// Uses SIMD acceleration when available for optimal performance.
672///
673/// # Properties
674/// - erfc(0) = 1
675/// - erfc(∞) = 0, erfc(-∞) = 2
676/// - erfc(x) = 1 - erf(x)
677/// - erfc(-x) = 2 - erfc(x)
678///
679/// # Examples
680///
681/// ```
682/// use scirs2_core::ndarray_ext::elementwise::erfc_simd;
683/// use scirs2_core::ndarray::array;
684///
685/// let x = array![0.0f64, 1.0, 2.0, 3.0];
686/// let result = erfc_simd(&x.view());
687/// assert!((result[0] - 1.0).abs() < 1e-10); // erfc(0) = 1
688/// assert!((result[1] - 0.1572992070502852).abs() < 1e-6); // erfc(1)
689/// ```
690pub fn erfc_simd<F>(x: &ArrayView1<F>) -> Array1<F>
691where
692 F: Float + SimdUnifiedOps,
693{
694 if x.is_empty() {
695 return Array1::zeros(0);
696 }
697 let optimizer = AutoOptimizer::new();
698 if optimizer.should_use_simd(x.len()) {
699 return F::simd_erfc(x);
700 }
701 F::simd_erfc(x)
702}
703/// Element-wise inverse error function erfinv(y) = x such that erf(x) = y
704///
705/// Uses SIMD acceleration when available for optimal performance.
706/// Critical for inverse normal CDF (probit function): Φ⁻¹(p) = √2 * erfinv(2p - 1)
707///
708/// # Domain and Range
709/// - Domain: (-1, 1)
710/// - Range: (-∞, ∞)
711/// - erfinv(-1) = -∞, erfinv(1) = ∞
712///
713/// # Properties
714/// - erfinv(0) = 0
715/// - erfinv(-y) = -erfinv(y) (odd function)
716/// - erf(erfinv(y)) = y
717///
718/// # Examples
719///
720/// ```
721/// use scirs2_core::ndarray_ext::elementwise::erfinv_simd;
722/// use scirs2_core::ndarray::array;
723///
724/// let y = array![0.0f64, 0.5, -0.5, 0.9];
725/// let result = erfinv_simd(&y.view());
726/// assert!((result[0] - 0.0).abs() < 1e-10); // erfinv(0) = 0
727/// ```
728pub fn erfinv_simd<F>(x: &ArrayView1<F>) -> Array1<F>
729where
730 F: Float + SimdUnifiedOps,
731{
732 if x.is_empty() {
733 return Array1::zeros(0);
734 }
735 let optimizer = AutoOptimizer::new();
736 if optimizer.should_use_simd(x.len()) {
737 return F::simd_erfinv(x);
738 }
739 F::simd_erfinv(x)
740}
741/// Element-wise inverse complementary error function erfcinv(y) = x such that erfc(x) = y
742///
743/// More numerically stable than erfinv(1 - y) for y close to 0.
744/// Uses SIMD acceleration when available for optimal performance.
745///
746/// # Domain and Range
747/// - Domain: (0, 2)
748/// - Range: (-∞, ∞)
749/// - erfcinv(0) = ∞, erfcinv(2) = -∞
750///
751/// # Properties
752/// - erfcinv(1) = 0
753/// - erfcinv(y) = erfinv(1 - y)
754/// - erfc(erfcinv(y)) = y
755///
756/// # Examples
757///
758/// ```
759/// use scirs2_core::ndarray_ext::elementwise::erfcinv_simd;
760/// use scirs2_core::ndarray::array;
761///
762/// let y = array![1.0f64, 0.5, 1.5];
763/// let result = erfcinv_simd(&y.view());
764/// assert!((result[0] - 0.0).abs() < 1e-10); // erfcinv(1) = 0
765/// ```
766pub fn erfcinv_simd<F>(x: &ArrayView1<F>) -> Array1<F>
767where
768 F: Float + SimdUnifiedOps,
769{
770 if x.is_empty() {
771 return Array1::zeros(0);
772 }
773 let optimizer = AutoOptimizer::new();
774 if optimizer.should_use_simd(x.len()) {
775 return F::simd_erfcinv(x);
776 }
777 F::simd_erfcinv(x)
778}
779/// Compute the element-wise sigmoid (logistic) function of an array.
780///
781/// The sigmoid function is defined as:
782/// σ(x) = 1 / (1 + exp(-x))
783///
784/// This is critical for neural networks, logistic regression, and probability modeling.
785/// The implementation is numerically stable, avoiding overflow for large |x|.
786///
787/// # Properties
788///
789/// - Range: (0, 1)
790/// - σ(0) = 0.5
791/// - σ(-x) = 1 - σ(x)
792/// - Derivative: σ'(x) = σ(x)(1 - σ(x))
793///
794/// # Examples
795///
796/// ```
797/// use scirs2_core::ndarray_ext::elementwise::sigmoid_simd;
798/// use scirs2_core::ndarray::array;
799///
800/// let x = array![0.0f64, 1.0, -1.0];
801/// let result = sigmoid_simd(&x.view());
802/// assert!((result[0] - 0.5).abs() < 1e-10); // sigmoid(0) = 0.5
803/// ```
804pub fn sigmoid_simd<F>(x: &ArrayView1<F>) -> Array1<F>
805where
806 F: Float + SimdUnifiedOps,
807{
808 if x.is_empty() {
809 return Array1::zeros(0);
810 }
811 let optimizer = AutoOptimizer::new();
812 if optimizer.should_use_simd(x.len()) {
813 return F::simd_sigmoid(x);
814 }
815 F::simd_sigmoid(x)
816}
817/// Compute the element-wise GELU (Gaussian Error Linear Unit) of an array.
818///
819/// The GELU function is defined as:
820/// GELU(x) = x * Φ(x) = x * 0.5 * (1 + erf(x / √2))
821///
822/// Where Φ(x) is the cumulative distribution function of the standard normal distribution.
823/// GELU is critical for Transformer models (BERT, GPT, etc.) and provides a smooth
824/// approximation of ReLU.
825///
826/// # Properties
827///
828/// - GELU(0) = 0
829/// - GELU(x) ≈ x for large positive x
830/// - GELU(x) ≈ 0 for large negative x
831/// - Smooth and differentiable everywhere
832///
833/// # Examples
834///
835/// ```
836/// use scirs2_core::ndarray_ext::elementwise::gelu_simd;
837/// use scirs2_core::ndarray::array;
838///
839/// let x = array![0.0f64, 1.0, -1.0];
840/// let result = gelu_simd(&x.view());
841/// assert!(result[0].abs() < 1e-10); // GELU(0) = 0
842/// ```
843pub fn gelu_simd<F>(x: &ArrayView1<F>) -> Array1<F>
844where
845 F: Float + SimdUnifiedOps,
846{
847 if x.is_empty() {
848 return Array1::zeros(0);
849 }
850 let optimizer = AutoOptimizer::new();
851 if optimizer.should_use_simd(x.len()) {
852 return F::simd_gelu(x);
853 }
854 F::simd_gelu(x)
855}
856/// SIMD-accelerated Swish (SiLU - Sigmoid Linear Unit) activation function
857///
858/// Computes the Swish activation function element-wise:
859/// `Swish(x) = x * sigmoid(x) = x / (1 + exp(-x))`
860///
861/// Swish is a self-gated activation function discovered through neural architecture
862/// search that has become a popular choice for modern neural networks.
863///
864/// # Key Properties
865///
866/// - Swish(0) = 0
867/// - Swish is smooth and non-monotonic
868/// - Has a small negative region (unlike ReLU)
869/// - Self-gating: x modulates its own activation via sigmoid
870/// - Unbounded above, bounded below (minimum ≈ -0.278 at x ≈ -1.278)
871///
872/// # Usage in Deep Learning
873///
874/// Swish is used in:
875/// - EfficientNet and EfficientNetV2
876/// - GPT-NeoX and other large language models
877/// - MobileNetV3
878/// - Many modern vision and NLP architectures
879///
880/// # Examples
881///
882/// ```
883/// use scirs2_core::ndarray_ext::elementwise::swish_simd;
884/// use scirs2_core::ndarray::array;
885///
886/// let x = array![0.0f64, 1.0, -1.0];
887/// let result = swish_simd(&x.view());
888/// assert!(result[0].abs() < 1e-10); // Swish(0) = 0
889/// // Swish(1) ≈ 0.7311
890/// assert!((result[1] - 0.7310585786).abs() < 1e-6);
891/// // Swish(-1) ≈ -0.2689
892/// assert!((result[2] - (-0.2689414214)).abs() < 1e-6);
893/// ```
894pub fn swish_simd<F>(x: &ArrayView1<F>) -> Array1<F>
895where
896 F: Float + SimdUnifiedOps,
897{
898 if x.is_empty() {
899 return Array1::zeros(0);
900 }
901 let optimizer = AutoOptimizer::new();
902 if optimizer.should_use_simd(x.len()) {
903 return F::simd_swish(x);
904 }
905 F::simd_swish(x)
906}
907/// SIMD-accelerated Softplus activation function
908///
909/// Computes the Softplus activation function element-wise:
910/// `Softplus(x) = ln(1 + exp(x))`
911///
912/// Softplus is a smooth approximation of ReLU and is commonly used in
913/// probabilistic models, Bayesian deep learning, and smooth counting.
914///
915/// # Key Properties
916///
917/// - Softplus(0) = ln(2) ≈ 0.693
918/// - Always positive (> 0 for all x)
919/// - Derivative: softplus'(x) = sigmoid(x)
920/// - Approaches ReLU for x → +∞: softplus(x) ≈ x
921/// - Approaches 0 for x → -∞: softplus(x) ≈ exp(x) ≈ 0
922///
923/// # Usage
924///
925/// Softplus is used in:
926/// - Probabilistic models (output layer for positive quantities)
927/// - Bayesian deep learning
928/// - Smooth counting applications
929/// - As a smooth ReLU replacement
930///
931/// # Examples
932///
933/// ```
934/// use scirs2_core::ndarray_ext::elementwise::softplus_simd;
935/// use scirs2_core::ndarray::array;
936///
937/// let x = array![0.0f64, 1.0, -1.0];
938/// let result = softplus_simd(&x.view());
939/// // Softplus(0) = ln(2) ≈ 0.693
940/// assert!((result[0] - 0.6931471805599453).abs() < 1e-10);
941/// // Softplus(1) = ln(1 + e) ≈ 1.3133
942/// assert!((result[1] - 1.3132616875182228).abs() < 1e-10);
943/// // Softplus(-1) = ln(1 + 1/e) ≈ 0.3133
944/// assert!((result[2] - 0.31326168751822286).abs() < 1e-10);
945/// ```
946pub fn softplus_simd<F>(x: &ArrayView1<F>) -> Array1<F>
947where
948 F: Float + SimdUnifiedOps,
949{
950 if x.is_empty() {
951 return Array1::zeros(0);
952 }
953 let optimizer = AutoOptimizer::new();
954 if optimizer.should_use_simd(x.len()) {
955 return F::simd_softplus(x);
956 }
957 F::simd_softplus(x)
958}
959/// SIMD-accelerated Mish activation function
960///
961/// Computes the Mish activation function element-wise:
962/// `Mish(x) = x * tanh(softplus(x)) = x * tanh(ln(1 + exp(x)))`
963///
964/// Mish is a self-regularized non-monotonic activation function that combines
965/// the benefits of ReLU, Swish, and other modern activations.
966///
967/// # Key Properties
968///
969/// - Mish(0) = 0
970/// - Smooth and non-monotonic
971/// - Self-regularizing (bounded negative region)
972/// - Unbounded above, bounded below (minimum ≈ -0.31 at x ≈ -1.2)
973/// - Derivative: complex but well-behaved
974///
975/// # Usage in Deep Learning
976///
977/// Mish is used in:
978/// - YOLOv4 and YOLOv5 object detection
979/// - Modern convolutional neural networks
980/// - Image classification and segmentation tasks
981///
982/// # Examples
983///
984/// ```
985/// use scirs2_core::ndarray_ext::elementwise::mish_simd;
986/// use scirs2_core::ndarray::array;
987///
988/// let x = array![0.0f64, 1.0, -1.0];
989/// let result = mish_simd(&x.view());
990/// // Mish(0) = 0
991/// assert!(result[0].abs() < 1e-10);
992/// // Mish(1) = 1 * tanh(ln(1 + e)) ≈ 0.8651
993/// assert!((result[1] - 0.8650983882673103).abs() < 1e-10);
994/// ```
995pub fn mish_simd<F>(x: &ArrayView1<F>) -> Array1<F>
996where
997 F: Float + SimdUnifiedOps,
998{
999 if x.is_empty() {
1000 return Array1::zeros(0);
1001 }
1002 let optimizer = AutoOptimizer::new();
1003 if optimizer.should_use_simd(x.len()) {
1004 return F::simd_mish(x);
1005 }
1006 F::simd_mish(x)
1007}