trueno/vector/ops/transcendental/exp_log.rs
1//! Exponential and logarithmic functions: `exp`, `ln`, `log2`, `log10`
2
3use crate::backends::VectorBackend;
4use crate::vector::Vector;
5use crate::{dispatch_unary_op, Result};
6
7impl Vector<f32> {
8 /// Element-wise exponential: result\[i\] = e^x\[i\]
9 ///
10 /// Computes the natural exponential (e^x) for each element.
11 /// Uses Rust's optimized f32::exp() method.
12 ///
13 /// # Examples
14 ///
15 /// ```
16 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
17 /// use trueno::Vector;
18 ///
19 /// let v = Vector::from_slice(&[0.0, 1.0, 2.0]);
20 /// let result = v.exp()?;
21 /// // result ≈ [1.0, 2.718, 7.389]
22 /// # Ok(())
23 /// # }
24 /// ```
25 ///
26 /// # Special Cases
27 ///
28 /// - `exp(0.0)` returns 1.0
29 /// - `exp(1.0)` returns e ≈ 2.71828
30 /// - `exp(-∞)` returns 0.0
31 /// - `exp(+∞)` returns +∞
32 ///
33 /// # Applications
34 ///
35 /// - Machine learning: Softmax activation, sigmoid, exponential loss
36 /// - Statistics: Exponential distribution, log-normal distribution
37 /// - Physics: Radioactive decay, population growth models
38 /// - Signal processing: Exponential smoothing, envelope detection
39 /// - Numerical methods: Solving differential equations
40 pub fn exp(&self) -> Result<Vector<f32>> {
41 // Uninit: backend writes every element before any read.
42 let n = self.len();
43 let mut result_data: Vec<f32> = Vec::with_capacity(n);
44 // SAFETY: Backend writes all elements before any read.
45 unsafe {
46 result_data.set_len(n);
47 }
48
49 if !self.data.is_empty() {
50 // Use parallel processing for large arrays
51 #[cfg(feature = "parallel")]
52 {
53 const PARALLEL_THRESHOLD: usize = 100_000;
54 const CHUNK_SIZE: usize = 65536;
55
56 if self.len() >= PARALLEL_THRESHOLD {
57 use rayon::prelude::*;
58
59 self.data
60 .par_chunks(CHUNK_SIZE)
61 .zip(result_data.par_chunks_mut(CHUNK_SIZE))
62 .for_each(|(chunk_in, chunk_out)| {
63 dispatch_unary_op!(self.backend, exp, chunk_in, chunk_out);
64 });
65
66 return Ok(Vector { data: result_data, backend: self.backend });
67 }
68 }
69
70 dispatch_unary_op!(self.backend, exp, &self.data, &mut result_data);
71 }
72
73 Ok(Vector { data: result_data, backend: self.backend })
74 }
75
76 /// Element-wise natural logarithm: result\[i\] = ln(x\[i\])
77 ///
78 /// Computes the natural logarithm (base e) for each element.
79 /// Uses Rust's optimized f32::ln() method.
80 ///
81 /// # Examples
82 ///
83 /// ```
84 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
85 /// use trueno::Vector;
86 ///
87 /// let v = Vector::from_slice(&[1.0, std::f32::consts::E, std::f32::consts::E.powi(2)]);
88 /// let result = v.ln()?;
89 /// // result ≈ [0.0, 1.0, 2.0]
90 /// # Ok(())
91 /// # }
92 /// ```
93 ///
94 /// # Special Cases
95 ///
96 /// - `ln(1.0)` returns 0.0
97 /// - `ln(e)` returns 1.0
98 /// - `ln(x)` for x ≤ 0 returns NaN
99 /// - `ln(0.0)` returns -∞
100 /// - `ln(+∞)` returns +∞
101 ///
102 /// # Applications
103 ///
104 /// - Machine learning: Log loss, log-likelihood, softmax normalization
105 /// - Statistics: Log-normal distribution, log transformation for skewed data
106 /// - Information theory: Entropy calculation, mutual information
107 /// - Economics: Log returns, elasticity calculations
108 /// - Signal processing: Decibel conversion, log-frequency analysis
109 pub fn ln(&self) -> Result<Vector<f32>> {
110 // Uninit: backend writes every element before any read.
111 let n = self.len();
112 let mut result_data: Vec<f32> = Vec::with_capacity(n);
113 // SAFETY: Backend writes all elements before any read.
114 unsafe {
115 result_data.set_len(n);
116 }
117
118 if !self.data.is_empty() {
119 dispatch_unary_op!(self.backend, ln, &self.data, &mut result_data);
120 }
121
122 Ok(Vector { data: result_data, backend: self.backend })
123 }
124
125 /// Element-wise base-2 logarithm: result\[i\] = log₂(x\[i\])
126 ///
127 /// Computes the base-2 logarithm for each element.
128 /// Uses Rust's optimized f32::log2() method.
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
134 /// use trueno::Vector;
135 ///
136 /// let v = Vector::from_slice(&[1.0, 2.0, 4.0, 8.0]);
137 /// let result = v.log2()?;
138 /// // result ≈ [0.0, 1.0, 2.0, 3.0]
139 /// # Ok(())
140 /// # }
141 /// ```
142 ///
143 /// # Special Cases
144 ///
145 /// - `log2(1.0)` returns 0.0
146 /// - `log2(2.0)` returns 1.0
147 /// - `log2(x)` for x ≤ 0 returns NaN
148 /// - `log2(0.0)` returns -∞
149 /// - `log2(+∞)` returns +∞
150 ///
151 /// # Applications
152 ///
153 /// - Information theory: Entropy in bits, mutual information
154 /// - Computer science: Bit manipulation, binary search complexity
155 /// - Audio: Octave calculations, pitch detection
156 /// - Data compression: Huffman coding, arithmetic coding
157 pub fn log2(&self) -> Result<Vector<f32>> {
158 // Uninit: backend writes every element before any read.
159 let n = self.len();
160 let mut result_data: Vec<f32> = Vec::with_capacity(n);
161 // SAFETY: Backend writes all elements before any read.
162 unsafe {
163 result_data.set_len(n);
164 }
165
166 if !self.data.is_empty() {
167 dispatch_unary_op!(self.backend, log2, &self.data, &mut result_data);
168 }
169
170 Ok(Vector { data: result_data, backend: self.backend })
171 }
172
173 /// Element-wise base-10 logarithm: result\[i\] = log₁₀(x\[i\])
174 ///
175 /// Computes the base-10 (common) logarithm for each element.
176 /// Uses Rust's optimized f32::log10() method.
177 ///
178 /// # Examples
179 ///
180 /// ```
181 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
182 /// use trueno::Vector;
183 ///
184 /// let v = Vector::from_slice(&[1.0, 10.0, 100.0, 1000.0]);
185 /// let result = v.log10()?;
186 /// // result ≈ [0.0, 1.0, 2.0, 3.0]
187 /// # Ok(())
188 /// # }
189 /// ```
190 ///
191 /// # Special Cases
192 ///
193 /// - `log10(1.0)` returns 0.0
194 /// - `log10(10.0)` returns 1.0
195 /// - `log10(x)` for x ≤ 0 returns NaN
196 /// - `log10(0.0)` returns -∞
197 /// - `log10(+∞)` returns +∞
198 ///
199 /// # Applications
200 ///
201 /// - Audio: Decibel calculations (dB = 20 * log10(amplitude))
202 /// - Chemistry: pH calculations (-log10(H+ concentration))
203 /// - Seismology: Richter scale
204 /// - Scientific notation: Order of magnitude calculations
205 pub fn log10(&self) -> Result<Vector<f32>> {
206 // Uninit: backend writes every element before any read.
207 let n = self.len();
208 let mut result_data: Vec<f32> = Vec::with_capacity(n);
209 // SAFETY: Backend writes all elements before any read.
210 unsafe {
211 result_data.set_len(n);
212 }
213
214 if !self.data.is_empty() {
215 dispatch_unary_op!(self.backend, log10, &self.data, &mut result_data);
216 }
217
218 Ok(Vector { data: result_data, backend: self.backend })
219 }
220}