Skip to main content

trueno/vector/ops/transcendental/
trigonometric.rs

1//! Trigonometric and inverse trigonometric functions: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`
2
3use crate::backends::VectorBackend;
4use crate::vector::Vector;
5use crate::{dispatch_unary_op, Result};
6
7impl Vector<f32> {
8    /// Element-wise sine: result\[i\] = sin(x\[i\])
9    ///
10    /// Computes the sine for each element (input in radians).
11    /// Uses Rust's optimized f32::sin() method.
12    ///
13    /// # Examples
14    ///
15    /// ```
16    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
17    /// use trueno::Vector;
18    /// use std::f32::consts::PI;
19    ///
20    /// let v = Vector::from_slice(&[0.0, PI / 2.0, PI]);
21    /// let result = v.sin()?;
22    /// // result ≈ [0.0, 1.0, 0.0]
23    /// # Ok(())
24    /// # }
25    /// ```
26    ///
27    /// # Special Cases
28    ///
29    /// - `sin(0)` returns 0.0
30    /// - `sin(π/2)` returns 1.0
31    /// - `sin(π)` returns 0.0 (approximately)
32    /// - `sin(-x)` returns -sin(x) (odd function)
33    /// - Periodic with period 2π: sin(x + 2π) = sin(x)
34    ///
35    /// # Applications
36    ///
37    /// - Signal processing: Waveform generation, oscillators, modulation
38    /// - Physics: Harmonic motion, wave propagation, pendulums
39    /// - Audio: Synthesizers, tone generation, effects processing
40    /// - Graphics: Animation, rotation transformations, procedural generation
41    /// - Fourier analysis: Frequency decomposition, spectral analysis
42    pub fn sin(&self) -> Result<Vector<f32>> {
43        // Uninit: backend writes every element before any read.
44        let n = self.len();
45        let mut result_data: Vec<f32> = Vec::with_capacity(n);
46        // SAFETY: Backend writes all elements before any read.
47        unsafe {
48            result_data.set_len(n);
49        }
50
51        if !self.data.is_empty() {
52            dispatch_unary_op!(self.backend, sin, &self.data, &mut result_data);
53        }
54
55        Ok(Vector { data: result_data, backend: self.backend })
56    }
57
58    /// Element-wise cosine: result\[i\] = cos(x\[i\])
59    ///
60    /// Computes the cosine for each element (input in radians).
61    /// Uses Rust's optimized f32::cos() method.
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
67    /// use trueno::Vector;
68    /// use std::f32::consts::PI;
69    ///
70    /// let v = Vector::from_slice(&[0.0, PI / 2.0, PI]);
71    /// let result = v.cos()?;
72    /// // result ≈ [1.0, 0.0, -1.0]
73    /// # Ok(())
74    /// # }
75    /// ```
76    ///
77    /// # Special Cases
78    ///
79    /// - `cos(0)` returns 1.0
80    /// - `cos(π/2)` returns 0.0 (approximately)
81    /// - `cos(π)` returns -1.0
82    /// - `cos(-x)` returns cos(x) (even function)
83    /// - Periodic with period 2π: cos(x + 2π) = cos(x)
84    /// - Relation to sine: cos(x) = sin(x + π/2)
85    ///
86    /// # Applications
87    ///
88    /// - Signal processing: Phase-shifted waveforms, I/Q modulation, quadrature signals
89    /// - Physics: Projectile motion, wave interference, damped oscillations
90    /// - Graphics: Rotation matrices, camera transforms, circular motion
91    /// - Audio: Stereo panning, spatial audio, frequency synthesis
92    /// - Engineering: Control systems, frequency response, AC circuits
93    pub fn cos(&self) -> Result<Vector<f32>> {
94        // Uninit: backend writes every element before any read.
95        let n = self.len();
96        let mut result_data: Vec<f32> = Vec::with_capacity(n);
97        // SAFETY: Backend writes all elements before any read.
98        unsafe {
99            result_data.set_len(n);
100        }
101
102        if !self.data.is_empty() {
103            dispatch_unary_op!(self.backend, cos, &self.data, &mut result_data);
104        }
105
106        Ok(Vector { data: result_data, backend: self.backend })
107    }
108
109    /// Computes element-wise tangent (tan) of the vector.
110    ///
111    /// Returns a new vector where each element is the tangent of the corresponding input element.
112    /// tan(x) = sin(x) / cos(x)
113    ///
114    /// # Returns
115    /// - `Ok(Vector<f32>)`: New vector with tan(x) for each element
116    ///
117    /// # Properties
118    /// - Odd function: tan(-x) = -tan(x)
119    /// - Period: 2π (not π, despite common misconception)
120    /// - Undefined at x = π/2 + nπ (where n is any integer)
121    /// - tan(x) = sin(x) / cos(x)
122    /// - Range: (-∞, +∞)
123    ///
124    /// # Performance
125    /// - Iterator map pattern for cache efficiency
126    /// - Leverages Rust's optimized f32::tan()
127    /// - Auto-vectorized by LLVM on supporting platforms
128    ///
129    /// # Examples
130    /// ```
131    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
132    /// use trueno::Vector;
133    /// use std::f32::consts::PI;
134    ///
135    /// let angles = Vector::from_slice(&[0.0, PI / 4.0, -PI / 4.0]);
136    /// let result = angles.tan()?;
137    /// // Result: [0.0, 1.0, -1.0] (approximately)
138    /// # Ok(())
139    /// # }
140    /// ```
141    ///
142    /// # Use Cases
143    /// - Trigonometry: Slope calculations, angle relationships
144    /// - Signal processing: Phase analysis, modulation
145    /// - Physics: Projectile trajectories, optics (Snell's law angles)
146    /// - Graphics: Perspective projection, field of view calculations
147    /// - Engineering: Slope gradients, tangent lines to curves
148    pub fn tan(&self) -> Result<Vector<f32>> {
149        // Uninit: backend writes every element before any read.
150        let n = self.len();
151        let mut result_data: Vec<f32> = Vec::with_capacity(n);
152        // SAFETY: Backend writes all elements before any read.
153        unsafe {
154            result_data.set_len(n);
155        }
156
157        if !self.data.is_empty() {
158            dispatch_unary_op!(self.backend, tan, &self.data, &mut result_data);
159        }
160
161        Ok(Vector { data: result_data, backend: self.backend })
162    }
163
164    /// Computes element-wise arcsine (asin/sin⁻¹) of the vector.
165    ///
166    /// Returns a new vector where each element is the inverse sine of the corresponding input element.
167    /// This is the inverse function of sin: if y = sin(x), then x = asin(y).
168    ///
169    /// # Returns
170    /// - `Ok(Vector<f32>)`: New vector with asin(x) for each element
171    ///
172    /// # Properties
173    /// - Domain: [-1, 1] (inputs outside this range produce NaN)
174    /// - Range: [-π/2, π/2]
175    /// - Odd function: asin(-x) = -asin(x)
176    /// - Inverse relation: asin(sin(x)) = x for x ∈ [-π/2, π/2]
177    /// - asin(0) = 0
178    /// - asin(1) = π/2
179    /// - asin(-1) = -π/2
180    ///
181    /// # Performance
182    /// - Iterator map pattern for cache efficiency
183    /// - Leverages Rust's optimized f32::asin()
184    /// - Auto-vectorized by LLVM on supporting platforms
185    ///
186    /// # Examples
187    /// ```
188    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
189    /// use trueno::Vector;
190    /// use std::f32::consts::PI;
191    ///
192    /// let values = Vector::from_slice(&[0.0, 0.5, 1.0]);
193    /// let result = values.asin()?;
194    /// // Result: [0.0, π/6, π/2] (approximately)
195    /// # Ok(())
196    /// # }
197    /// ```
198    ///
199    /// # Use Cases
200    /// - Physics: Calculating angles from sine values in mechanics, optics
201    /// - Signal processing: Phase recovery, demodulation
202    /// - Graphics: Inverse transformations, angle calculations
203    /// - Navigation: GPS calculations, spherical trigonometry
204    /// - Control systems: Inverse kinematics, servo positioning
205    pub fn asin(&self) -> Result<Vector<f32>> {
206        let asin_data: Vec<f32> = self.data.iter().map(|x| x.asin()).collect();
207        Ok(Vector { data: asin_data, backend: self.backend })
208    }
209
210    /// Computes element-wise arccosine (acos/cos⁻¹) of the vector.
211    ///
212    /// Returns a new vector where each element is the inverse cosine of the corresponding input element.
213    /// This is the inverse function of cos: if y = cos(x), then x = acos(y).
214    ///
215    /// # Returns
216    /// - `Ok(Vector<f32>)`: New vector with acos(x) for each element
217    ///
218    /// # Properties
219    /// - Domain: [-1, 1] (inputs outside this range produce NaN)
220    /// - Range: [0, π]
221    /// - Symmetry: acos(-x) = π - acos(x)
222    /// - Inverse relation: acos(cos(x)) = x for x ∈ [0, π]
223    /// - acos(0) = π/2
224    /// - acos(1) = 0
225    /// - acos(-1) = π
226    ///
227    /// # Performance
228    /// - Iterator map pattern for cache efficiency
229    /// - Leverages Rust's optimized f32::acos()
230    /// - Auto-vectorized by LLVM on supporting platforms
231    ///
232    /// # Examples
233    /// ```
234    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
235    /// use trueno::Vector;
236    /// use std::f32::consts::PI;
237    ///
238    /// let values = Vector::from_slice(&[0.0, 0.5, 1.0]);
239    /// let result = values.acos()?;
240    /// // Result: [π/2, π/3, 0.0] (approximately)
241    /// # Ok(())
242    /// # }
243    /// ```
244    ///
245    /// # Use Cases
246    /// - Physics: Angle calculations in mechanics, optics, reflections
247    /// - Signal processing: Phase analysis, correlation functions
248    /// - Graphics: View angle calculations, lighting models
249    /// - Navigation: Bearing calculations, great circle distances
250    /// - Robotics: Joint angle solving, orientation calculations
251    pub fn acos(&self) -> Result<Vector<f32>> {
252        let acos_data: Vec<f32> = self.data.iter().map(|x| x.acos()).collect();
253        Ok(Vector { data: acos_data, backend: self.backend })
254    }
255
256    /// Computes element-wise arctangent (atan/tan⁻¹) of the vector.
257    ///
258    /// Returns a new vector where each element is the inverse tangent of the corresponding input element.
259    /// This is the inverse function of tan: if y = tan(x), then x = atan(y).
260    ///
261    /// # Returns
262    /// - `Ok(Vector<f32>)`: New vector with atan(x) for each element
263    ///
264    /// # Properties
265    /// - Domain: All real numbers (-∞, +∞)
266    /// - Range: (-π/2, π/2)
267    /// - Odd function: atan(-x) = -atan(x)
268    /// - Inverse relation: atan(tan(x)) = x for x ∈ (-π/2, π/2)
269    /// - atan(0) = 0
270    /// - atan(1) = π/4
271    /// - atan(-1) = -π/4
272    /// - lim(x→∞) atan(x) = π/2
273    /// - lim(x→-∞) atan(x) = -π/2
274    ///
275    /// # Performance
276    /// - Iterator map pattern for cache efficiency
277    /// - Leverages Rust's optimized f32::atan()
278    /// - Auto-vectorized by LLVM on supporting platforms
279    ///
280    /// # Examples
281    /// ```
282    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
283    /// use trueno::Vector;
284    /// use std::f32::consts::PI;
285    ///
286    /// let values = Vector::from_slice(&[0.0, 1.0, -1.0]);
287    /// let result = values.atan()?;
288    /// // Result: [0.0, π/4, -π/4] (approximately)
289    /// # Ok(())
290    /// # }
291    /// ```
292    ///
293    /// # Use Cases
294    /// - Physics: Angle calculations from slopes, velocity components
295    /// - Signal processing: Phase unwrapping, FM demodulation
296    /// - Graphics: Rotation calculations, camera orientation
297    /// - Robotics: Inverse kinematics, steering angles
298    /// - Navigation: Heading calculations from coordinates
299    pub fn atan(&self) -> Result<Vector<f32>> {
300        let atan_data: Vec<f32> = self.data.iter().map(|x| x.atan()).collect();
301        Ok(Vector { data: atan_data, backend: self.backend })
302    }
303}