Skip to main content

trueno/vector/ops/transforms/
math.rs

1//! Mathematical transformation operations (sqrt, recip, pow)
2
3#[allow(unused_imports)]
4use crate::backends::VectorBackend;
5use crate::dispatch_unary_op;
6use crate::{Result, Vector};
7
8impl Vector<f32> {
9    /// Element-wise square root: result\[i\] = sqrt(self\[i\])
10    ///
11    /// Computes the square root of each element. For negative values, returns NaN
12    /// following IEEE 754 floating-point semantics.
13    ///
14    /// # Returns
15    ///
16    /// A new vector where each element is the square root of the corresponding input element
17    ///
18    /// # Examples
19    ///
20    /// ```
21    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
22    /// use trueno::Vector;
23    ///
24    /// let a = Vector::from_slice(&[4.0, 9.0, 16.0, 25.0]);
25    /// let result = a.sqrt()?;
26    /// assert_eq!(result.as_slice(), &[2.0, 3.0, 4.0, 5.0]);
27    /// # Ok(())
28    /// # }
29    /// ```
30    ///
31    /// Negative values produce NaN:
32    /// ```
33    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
34    /// use trueno::Vector;
35    ///
36    /// let a = Vector::from_slice(&[-1.0, 4.0]);
37    /// let result = a.sqrt()?;
38    /// assert!(result.as_slice()[0].is_nan());
39    /// assert_eq!(result.as_slice()[1], 2.0);
40    /// # Ok(())
41    /// # }
42    /// ```
43    ///
44    /// # Use Cases
45    ///
46    /// - Distance calculations: Euclidean distance computation
47    /// - Statistics: Standard deviation, RMS (root mean square)
48    /// - Machine learning: Normalization, gradient descent with adaptive learning rates
49    /// - Signal processing: Amplitude calculations, power spectrum analysis
50    /// - Physics simulations: Velocity from kinetic energy, wave propagation
51    pub fn sqrt(&self) -> Result<Vector<f32>> {
52        // Uninit allocation: dispatch_unary_op!(sqrt) writes every element.
53        let n = self.len();
54        let mut result_data: Vec<f32> = Vec::with_capacity(n);
55        // SAFETY: dispatch_unary_op writes result_data[i] = sqrt(input[i]) for all i.
56        unsafe {
57            result_data.set_len(n);
58        }
59
60        if !self.as_slice().is_empty() {
61            // Use parallel processing for large arrays
62            #[cfg(feature = "parallel")]
63            {
64                const PARALLEL_THRESHOLD: usize = 100_000;
65                const CHUNK_SIZE: usize = 65536;
66
67                if self.len() >= PARALLEL_THRESHOLD {
68                    use rayon::prelude::*;
69
70                    self.as_slice()
71                        .par_chunks(CHUNK_SIZE)
72                        .zip(result_data.par_chunks_mut(CHUNK_SIZE))
73                        .for_each(|(chunk_in, chunk_out)| {
74                            dispatch_unary_op!(self.backend(), sqrt, chunk_in, chunk_out);
75                        });
76
77                    return Ok(Vector { data: result_data, backend: self.backend() });
78                }
79            }
80
81            dispatch_unary_op!(self.backend(), sqrt, self.as_slice(), &mut result_data);
82        }
83
84        Ok(Vector { data: result_data, backend: self.backend() })
85    }
86
87    /// Element-wise reciprocal: result\[i\] = 1 / self\[i\]
88    ///
89    /// Computes the reciprocal (multiplicative inverse) of each element.
90    /// For zero values, returns infinity following IEEE 754 floating-point semantics.
91    ///
92    /// # Returns
93    ///
94    /// A new vector where each element is the reciprocal of the corresponding input element
95    ///
96    /// # Examples
97    ///
98    /// ```
99    /// use trueno::Vector;
100    ///
101    /// let a = Vector::from_slice(&[2.0, 4.0, 5.0, 10.0]);
102    /// let result = a.recip().unwrap();
103    /// assert_eq!(result.as_slice(), &[0.5, 0.25, 0.2, 0.1]);
104    /// ```
105    ///
106    /// Zero values produce infinity:
107    /// ```
108    /// use trueno::Vector;
109    ///
110    /// let a = Vector::from_slice(&[0.0, 2.0]);
111    /// let result = a.recip().unwrap();
112    /// assert!(result.as_slice()[0].is_infinite());
113    /// assert_eq!(result.as_slice()[1], 0.5);
114    /// ```
115    ///
116    /// # Use Cases
117    ///
118    /// - Division optimization: `a / b` -> `a * recip(b)` (multiplication is faster)
119    /// - Neural networks: Learning rate schedules, weight normalization
120    /// - Statistics: Harmonic mean calculations, inverse transformations
121    /// - Physics: Resistance (R = 1/G), optical power (P = 1/f)
122    /// - Signal processing: Frequency to period conversion, filter design
123    pub fn recip(&self) -> Result<Vector<f32>> {
124        // Uninit allocation: dispatch_unary_op!(recip) writes every element.
125        let n = self.len();
126        let mut result_data: Vec<f32> = Vec::with_capacity(n);
127        // SAFETY: dispatch_unary_op writes result_data[i] = 1/input[i] for all i.
128        unsafe {
129            result_data.set_len(n);
130        }
131
132        if !self.as_slice().is_empty() {
133            dispatch_unary_op!(self.backend(), recip, self.as_slice(), &mut result_data);
134        }
135
136        Ok(Vector { data: result_data, backend: self.backend() })
137    }
138
139    /// Element-wise power: result\[i\] = base\[i\]^n
140    ///
141    /// Raises each element to the given power `n`.
142    /// Uses Rust's optimized f32::powf() method.
143    ///
144    /// # Examples
145    ///
146    /// ```
147    /// use trueno::Vector;
148    ///
149    /// let v = Vector::from_slice(&[2.0, 3.0, 4.0]);
150    /// let squared = v.pow(2.0).unwrap();
151    /// assert_eq!(squared.as_slice(), &[4.0, 9.0, 16.0]);
152    ///
153    /// let sqrt = v.pow(0.5).unwrap();  // Fractional power = root
154    /// ```
155    ///
156    /// # Special Cases
157    ///
158    /// - `x.pow(0.0)` returns 1.0 for all x (even x=0)
159    /// - `x.pow(1.0)` returns x (identity)
160    /// - `x.pow(-1.0)` returns 1/x (reciprocal)
161    /// - `x.pow(0.5)` returns sqrt(x) (square root)
162    ///
163    /// # Applications
164    ///
165    /// - Statistics: Power transformations (Box-Cox, Yeo-Johnson)
166    /// - Machine learning: Polynomial features, activation functions
167    /// - Physics: Inverse square law (1/r^2), power laws
168    /// - Signal processing: Power spectral density, root mean square
169    pub fn pow(&self, n: f32) -> Result<Vector<f32>> {
170        let pow_data: Vec<f32> = self.as_slice().iter().map(|x| x.powf(n)).collect();
171        Ok(Vector::from_vec(pow_data))
172    }
173}