torsh_tensor/
math_ops_trig.rs1use super::*;
13
14impl<T: TensorElement + Copy> Tensor<T>
16where
17 T: scirs2_core::numeric::Float + torsh_core::dtype::FloatElement,
18{
19 pub fn sqrt(&self) -> Result<Self> {
21 self.map(|x| x.sqrt())
22 }
23
24 pub fn square(&self) -> Result<Self> {
26 self.map(|x| x * x)
27 }
28
29 pub fn rsqrt(&self) -> Result<Self> {
31 self.map(|x| T::from(1.0).expect("numeric conversion should succeed") / x.sqrt())
32 }
33
34 pub fn reciprocal(&self) -> Result<Self> {
36 self.map(|x| T::from(1.0).expect("numeric conversion should succeed") / x)
37 }
38
39 pub fn exp(&self) -> Result<Self> {
41 self.map(|x| x.exp())
42 }
43
44 pub fn ln(&self) -> Result<Self> {
46 self.map(|x| x.ln())
47 }
48
49 pub fn log10(&self) -> Result<Self> {
51 self.map(|x| x.log10())
52 }
53
54 pub fn log2(&self) -> Result<Self> {
56 self.map(|x| x.log2())
57 }
58
59 pub fn log(&self) -> Result<Self> {
61 self.map(|x| x.ln())
62 }
63
64 pub fn sin(&self) -> Result<Self> {
66 self.map(|x| x.sin())
67 }
68
69 pub fn cos(&self) -> Result<Self> {
71 self.map(|x| x.cos())
72 }
73
74 pub fn tan(&self) -> Result<Self> {
76 self.map(|x| x.tan())
77 }
78
79 pub fn gelu(&self) -> Result<Self> {
81 #[cfg(feature = "simd")]
89 {
90 if std::any::TypeId::of::<T>() == std::any::TypeId::of::<f32>() && self.numel() > 1000 {
91 return self.simd_gelu_f32();
92 }
93 }
94
95 #[cfg(feature = "parallel")]
97 {
98 if self.numel() > 100 {
99 return self.parallel_map(|x| self.compute_gelu_scalar(x));
100 }
101 }
102
103 self.map(|x| self.compute_gelu_scalar(x))
106 }
107
108 fn compute_gelu_scalar(&self, x: T) -> T {
110 let pi = T::from(std::f64::consts::PI).expect("numeric conversion should succeed");
111 let two = T::from(2.0).expect("numeric conversion should succeed");
112 let sqrt_2_over_pi = (two / pi).sqrt();
113 let point_044715 = T::from(0.044715).expect("numeric conversion should succeed");
114 let one = <T as scirs2_core::numeric::One>::one();
115 let half = T::from(0.5).expect("numeric conversion should succeed");
116
117 let x_cubed = x * x * x;
118 let tanh_input = sqrt_2_over_pi * (x + point_044715 * x_cubed);
119 half * x * (one + tanh_input.tanh())
120 }
121
122 #[cfg(feature = "simd")]
124 fn simd_gelu_f32(&self) -> Result<Self> {
125 use scirs2_core::ndarray::ArrayView1;
126
127 let data = self.data()?;
128
129 let data_f32: &[f32] =
131 unsafe { std::slice::from_raw_parts(data.as_ptr() as *const f32, data.len()) };
132
133 let data_view = ArrayView1::from(data_f32);
135
136 let result_array = adaptive_simd::adaptive_simd_gelu_f32(&data_view);
138
139 let result_vec: Vec<T> = result_array
141 .to_vec()
142 .into_iter()
143 .map(|f| unsafe { std::mem::transmute_copy::<f32, T>(&f) })
144 .collect();
145
146 Self::from_data(
147 result_vec,
148 self.shape().dims().to_vec(),
149 self.device.clone(),
150 )
151 }
152
153 pub fn leaky_relu(&self, negative_slope: T) -> Result<Self> {
155 self.map(|x| {
160 if x > scirs2_core::numeric::Zero::zero() {
161 x
162 } else {
163 negative_slope * x
164 }
165 })
166 }
167
168 pub fn asin(&self) -> Result<Self> {
170 self.map(|x| x.asin())
171 }
172
173 pub fn acos(&self) -> Result<Self> {
175 self.map(|x| x.acos())
176 }
177
178 pub fn atan(&self) -> Result<Self> {
180 self.map(|x| x.atan())
181 }
182
183 pub fn sinh(&self) -> Result<Self> {
185 self.map(|x| x.sinh())
186 }
187
188 pub fn cosh(&self) -> Result<Self> {
190 self.map(|x| x.cosh())
191 }
192
193 pub fn tanh(&self) -> Result<Self> {
195 #[cfg(feature = "gpu")]
198 if let Some(result) =
199 crate::gpu_dispatch::try_unary_f32(self, crate::gpu_dispatch::UnaryOp::Tanh)
200 {
201 return Ok(result);
202 }
203
204 self.map(|x| x.tanh())
205 }
206
207 pub fn pow(&self, exponent: T) -> Result<Self>
209 where
210 T: TensorElement + Into<f32>,
211 {
212 let exponent_f32: f32 = exponent.into();
214
215 let mut result = self.map(|x| x.powf(exponent))?;
216
217 if self.requires_grad {
219 result.requires_grad = true;
220 result.operation = Operation::Power {
221 input: Arc::new(self.clone()),
222 exponent: exponent_f32,
223 };
224 }
225
226 Ok(result)
227 }
228
229 pub fn pow_scalar(&self, exponent: T) -> Result<Self>
231 where
232 T: TensorElement + Into<f32>,
233 {
234 self.pow(exponent)
235 }
236
237 pub fn pow_tensor(&self, exponent: &Self) -> Result<Self> {
239 self.elementwise_operation(exponent, |base, exp| base.powf(exp))
240 }
241
242 pub fn floor(&self) -> Result<Self> {
244 self.map(|x| x.floor())
245 }
246
247 pub fn ceil(&self) -> Result<Self> {
249 self.map(|x| x.ceil())
250 }
251
252 pub fn round(&self) -> Result<Self> {
254 self.map(|x| x.round())
255 }
256
257 pub fn trunc(&self) -> Result<Self> {
259 self.map(|x| x.trunc())
260 }
261
262 pub fn fract(&self) -> Result<Self> {
264 self.map(|x| x.fract())
265 }
266
267 pub fn neg(&self) -> Result<Self>
269 where
270 T: std::ops::Neg<Output = T>,
271 {
272 self.map(|x| -x)
273 }
274
275 pub fn sign(&self) -> Result<Self> {
277 self.map(|x| {
278 if x > <T as scirs2_core::numeric::Zero>::zero() {
279 <T as scirs2_core::numeric::One>::one()
280 } else if x < <T as scirs2_core::numeric::Zero>::zero() {
281 -<T as scirs2_core::numeric::One>::one()
282 } else {
283 <T as scirs2_core::numeric::Zero>::zero()
284 }
285 })
286 }
287}