1use alloc::vec::Vec;
3use burn_backend::backend::ExecutionError;
4use burn_backend::ops::GridSampleOptions;
5use burn_backend::tensor::FloatTensor;
6use burn_backend::{TensorMetadata, element::cast::ToElement};
7use burn_std::{BoolDType, IntDType};
8
9use super::{
11 NdArrayMathOps, NdArrayOps,
12 matmul::{cross, matmul},
13};
14use crate::{
15 NdArray, cast_to_dtype, cat_with_dtype, execute_with_int_dtype, tensor::NdArrayTensor,
16};
17use crate::{NdArrayDevice, SEED, execute_with_float_out_dtype, execute_with_int_out_dtype, slice};
18use crate::{SharedArray, element::ExpElement};
19use crate::{execute_with_float_dtype, ops::grid_sample::grid_sample_2d};
20
21use crate::rand::get_seeded_rng;
23use burn_backend::{Distribution, FloatDType, Scalar};
24use burn_backend::{ElementConversion, Shape, TensorData, ops::FloatTensorOps};
25
26#[cfg(not(feature = "std"))]
27#[allow(unused_imports)]
28use num_traits::Float;
29
30use libm::erf;
31
32#[cfg(feature = "std")]
33#[allow(dead_code)]
34fn round_ties_even_wrapper(x: f64) -> f64 {
35 x.round_ties_even()
36}
37
38#[cfg(not(feature = "std"))]
39#[allow(dead_code)]
40fn round_ties_even_wrapper(x: f64) -> f64 {
41 if (x - x.floor()) == 0.5 {
42 (x * 0.5).round() * 2.0
43 } else {
44 x.round()
45 }
46}
47
48impl FloatTensorOps<Self> for NdArray {
49 fn float_from_data(data: TensorData, _device: &NdArrayDevice) -> FloatTensor<Self> {
50 NdArrayTensor::from_data(data)
51 }
52
53 fn float_random(
54 shape: Shape,
55 distribution: Distribution,
56 device: &NdArrayDevice,
57 dtype: FloatDType,
58 ) -> FloatTensor<Self> {
59 let mut seed = SEED.lock().unwrap();
60 let mut rng = seed.take().unwrap_or_else(get_seeded_rng);
61 let tensor = execute_with_float_out_dtype!(
62 dtype,
63 E,
64 Self::float_from_data(
65 TensorData::random::<E, _, _>(shape, distribution, &mut rng),
66 device,
67 )
68 );
69
70 *seed = Some(rng);
71 tensor
72 }
73
74 async fn float_into_data(tensor: FloatTensor<Self>) -> Result<TensorData, ExecutionError> {
75 Ok(tensor.into_data())
76 }
77
78 fn float_to_device(tensor: FloatTensor<Self>, _device: &NdArrayDevice) -> FloatTensor<Self> {
79 tensor
80 }
81
82 fn float_empty(shape: Shape, device: &NdArrayDevice, dtype: FloatDType) -> FloatTensor<Self> {
83 Self::float_zeros(shape, device, dtype)
84 }
85
86 fn float_add(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
87 execute_with_float_dtype!((lhs, rhs), NdArrayMathOps::add)
88 }
89
90 fn float_add_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
91 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
92 NdArrayMathOps::add_scalar(array, rhs.elem())
93 })
94 }
95
96 fn float_sub(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
97 execute_with_float_dtype!((lhs, rhs), NdArrayMathOps::sub)
98 }
99
100 fn float_sub_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
101 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
102 NdArrayMathOps::sub_scalar(array, rhs.elem())
103 })
104 }
105
106 fn float_mul(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
107 execute_with_float_dtype!((lhs, rhs), NdArrayMathOps::mul)
108 }
109
110 fn float_mul_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
111 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
112 NdArrayMathOps::mul_scalar(array, rhs.elem())
113 })
114 }
115
116 fn float_div(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
117 execute_with_float_dtype!((lhs, rhs), NdArrayMathOps::div)
118 }
119
120 fn float_div_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
121 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
122 NdArrayMathOps::div_scalar(array, rhs.elem())
123 })
124 }
125
126 fn float_remainder(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
127 execute_with_float_dtype!((lhs, rhs), NdArrayMathOps::remainder)
128 }
129
130 fn float_remainder_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
131 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
132 NdArrayMathOps::remainder_scalar(array, rhs.elem())
133 })
134 }
135
136 fn float_matmul(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
137 execute_with_float_dtype!((lhs, rhs), matmul)
138 }
139
140 fn float_cross(
141 lhs: FloatTensor<Self>,
142 rhs: FloatTensor<Self>,
143 dim: usize,
144 ) -> FloatTensor<Self> {
145 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| cross(lhs, rhs, dim))
146 }
147
148 fn float_recip(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
149 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
150 NdArrayMathOps::recip(array)
151 })
152 }
153
154 fn float_swap_dims(tensor: FloatTensor<Self>, dim1: usize, dim2: usize) -> FloatTensor<Self> {
155 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
156 NdArrayOps::swap_dims(array, dim1, dim2)
157 })
158 }
159
160 fn float_reshape(tensor: FloatTensor<Self>, shape: Shape) -> FloatTensor<Self> {
161 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
162 NdArrayOps::reshape(array, shape)
163 })
164 }
165
166 fn float_gather(
167 dim: usize,
168 tensor: FloatTensor<Self>,
169 indices: NdArrayTensor,
170 ) -> FloatTensor<Self> {
171 execute_with_int_dtype!(
172 indices,
173 IntElem,
174 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
175 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
176 NdArrayOps::gather(dim, array, idx_array)
177 })
178 }
179 )
180 }
181
182 fn float_scatter_add(
183 dim: usize,
184 tensor: FloatTensor<Self>,
185 indices: NdArrayTensor,
186 value: FloatTensor<Self>,
187 ) -> FloatTensor<Self> {
188 execute_with_int_dtype!(
189 indices,
190 IntElem,
191 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
192 execute_with_float_dtype!((tensor, value), |tensor, value| NdArrayOps::scatter(
193 dim, tensor, idx_array, value
194 ))
195 }
196 )
197 }
198
199 fn float_scatter_nd(
200 data: FloatTensor<Self>,
201 indices: NdArrayTensor,
202 values: FloatTensor<Self>,
203 reduction: burn_backend::tensor::IndexingUpdateOp,
204 ) -> FloatTensor<Self> {
205 execute_with_int_dtype!(
206 indices,
207 IntElem,
208 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
209 execute_with_float_dtype!((data, values), |data, values| NdArrayOps::scatter_nd(
210 data, idx_array, values, reduction
211 ))
212 }
213 )
214 }
215
216 fn float_gather_nd(data: FloatTensor<Self>, indices: NdArrayTensor) -> FloatTensor<Self> {
217 execute_with_int_dtype!(
218 indices,
219 IntElem,
220 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
221 execute_with_float_dtype!(data, FloatElem, |array: SharedArray<FloatElem>| {
222 NdArrayOps::gather_nd(array, idx_array)
223 })
224 }
225 )
226 }
227
228 fn float_select(
229 tensor: FloatTensor<Self>,
230 dim: usize,
231 indices: NdArrayTensor,
232 ) -> FloatTensor<Self> {
233 execute_with_int_dtype!(
234 indices,
235 IntElem,
236 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
237 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
238 NdArrayMathOps::select(array, dim, idx_array)
239 })
240 }
241 )
242 }
243
244 fn float_select_add(
245 tensor: FloatTensor<Self>,
246 dim: usize,
247 indices: NdArrayTensor,
248 value: FloatTensor<Self>,
249 ) -> FloatTensor<Self> {
250 execute_with_int_dtype!(
251 indices,
252 IntElem,
253 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
254 execute_with_float_dtype!((tensor, value), |tensor, value| {
255 NdArrayMathOps::select_assign(tensor, dim, idx_array, value)
256 })
257 }
258 )
259 }
260
261 fn float_slice(tensor: FloatTensor<Self>, slices: &[burn_backend::Slice]) -> FloatTensor<Self> {
262 slice!(tensor, slices)
263 }
264
265 fn float_slice_assign(
266 tensor: FloatTensor<Self>,
267 slices: &[burn_backend::Slice],
268 value: FloatTensor<Self>,
269 ) -> FloatTensor<Self> {
270 execute_with_float_dtype!((tensor, value), |tensor, value| {
271 NdArrayOps::slice_assign(tensor, slices, value)
272 })
273 }
274
275 fn float_mask_where(
276 tensor: FloatTensor<Self>,
277 mask: NdArrayTensor,
278 value: FloatTensor<Self>,
279 ) -> FloatTensor<Self> {
280 execute_with_float_dtype!((tensor, value), |tensor, value| {
281 NdArrayOps::mask_where(tensor, mask.bool(), value)
282 })
283 }
284
285 fn float_mask_fill(
286 tensor: FloatTensor<Self>,
287 mask: NdArrayTensor,
288 value: Scalar,
289 ) -> FloatTensor<Self> {
290 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
291 NdArrayOps::mask_fill(array, mask.bool(), value.elem())
292 })
293 }
294
295 fn float_equal(
296 lhs: FloatTensor<Self>,
297 rhs: FloatTensor<Self>,
298 _out_dtype: BoolDType,
299 ) -> NdArrayTensor {
300 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| { NdArrayMathOps::equal(lhs, rhs) })
301 }
302
303 fn float_equal_elem(
304 lhs: FloatTensor<Self>,
305 rhs: Scalar,
306 _out_dtype: BoolDType,
307 ) -> NdArrayTensor {
308 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
309 NdArrayMathOps::equal_elem(array, rhs.elem())
310 })
311 }
312
313 fn float_greater(
314 lhs: FloatTensor<Self>,
315 rhs: FloatTensor<Self>,
316 _out_dtype: BoolDType,
317 ) -> NdArrayTensor {
318 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| { NdArrayMathOps::greater(lhs, rhs) })
319 }
320
321 fn float_greater_elem(
322 lhs: FloatTensor<Self>,
323 rhs: Scalar,
324 _out_dtype: BoolDType,
325 ) -> NdArrayTensor {
326 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
327 NdArrayMathOps::greater_elem(array, rhs.elem())
328 })
329 }
330
331 fn float_greater_equal(
332 lhs: FloatTensor<Self>,
333 rhs: FloatTensor<Self>,
334 _out_dtype: BoolDType,
335 ) -> NdArrayTensor {
336 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| {
337 NdArrayMathOps::greater_equal(lhs, rhs)
338 })
339 }
340
341 fn float_greater_equal_elem(
342 lhs: FloatTensor<Self>,
343 rhs: Scalar,
344 _out_dtype: BoolDType,
345 ) -> NdArrayTensor {
346 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
347 NdArrayMathOps::greater_equal_elem(array, rhs.elem())
348 })
349 }
350
351 fn float_lower(
352 lhs: FloatTensor<Self>,
353 rhs: FloatTensor<Self>,
354 _out_dtype: BoolDType,
355 ) -> NdArrayTensor {
356 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| { NdArrayMathOps::lower(lhs, rhs) })
357 }
358
359 fn float_lower_elem(
360 lhs: FloatTensor<Self>,
361 rhs: Scalar,
362 _out_dtype: BoolDType,
363 ) -> NdArrayTensor {
364 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
365 NdArrayMathOps::lower_elem(array, rhs.elem())
366 })
367 }
368
369 fn float_lower_equal(
370 lhs: FloatTensor<Self>,
371 rhs: FloatTensor<Self>,
372 _out_dtype: BoolDType,
373 ) -> NdArrayTensor {
374 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| {
375 NdArrayMathOps::lower_equal(lhs, rhs)
376 })
377 }
378
379 fn float_lower_equal_elem(
380 lhs: FloatTensor<Self>,
381 rhs: Scalar,
382 _out_dtype: BoolDType,
383 ) -> NdArrayTensor {
384 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
385 NdArrayMathOps::lower_equal_elem(array, rhs.elem())
386 })
387 }
388
389 fn float_detach(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
390 tensor
391 }
392
393 fn float_mean(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
394 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
396 NdArrayMathOps::mean_view(array.view())
397 })
398 }
399
400 fn float_sum(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
401 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
403 NdArrayMathOps::sum_view(array.view())
404 })
405 }
406
407 fn float_mean_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
408 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
409 NdArrayMathOps::mean_dim(array, dim)
410 })
411 }
412
413 fn float_cumsum(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
414 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
415 NdArrayMathOps::cumsum(array, dim)
416 })
417 }
418
419 fn float_cumprod(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
420 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
421 NdArrayMathOps::cumprod(array, dim)
422 })
423 }
424
425 fn float_cummin(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
426 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
427 NdArrayMathOps::cummin(array, dim)
428 })
429 }
430
431 fn float_cummax(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
432 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
433 NdArrayMathOps::cummax(array, dim)
434 })
435 }
436
437 fn float_sum_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
438 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
439 NdArrayMathOps::sum_dim(array, dim)
440 })
441 }
442
443 fn float_argmax(tensor: FloatTensor<Self>, dim: usize, out_dtype: IntDType) -> NdArrayTensor {
444 execute_with_int_out_dtype!(out_dtype, I, {
446 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
447 NdArrayMathOps::argmax_view::<I>(array.view(), dim)
448 })
449 })
450 }
451
452 fn float_argmin(tensor: FloatTensor<Self>, dim: usize, out_dtype: IntDType) -> NdArrayTensor {
453 execute_with_int_out_dtype!(out_dtype, I, {
455 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
456 NdArrayMathOps::argmin_view::<I>(array.view(), dim)
457 })
458 })
459 }
460
461 fn float_exp(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
462 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
463 array.mapv_into(|a: FloatElem| a.exp_elem()).into_shared()
464 })
465 }
466
467 fn float_log(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
468 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
469 array.mapv_into(|a: FloatElem| a.log_elem()).into_shared()
470 })
471 }
472
473 fn float_prod(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
474 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
476 NdArrayMathOps::prod_view(array.view())
477 })
478 }
479
480 fn float_prod_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
481 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
482 NdArrayMathOps::prod_dim(array, dim)
483 })
484 }
485
486 fn float_max(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
487 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
489 NdArrayMathOps::max_view(array.view())
490 })
491 }
492
493 fn float_min(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
494 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
496 NdArrayMathOps::min_view(array.view())
497 })
498 }
499
500 fn float_log1p(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
501 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
502 array.mapv_into(|a: FloatElem| a.log1p_elem()).into_shared()
503 })
504 }
505
506 fn float_powf_scalar_impl(tensor: FloatTensor<Self>, value: Scalar) -> FloatTensor<Self> {
507 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
508 array
509 .mapv_into(|a: FloatElem| a.powf_elem(value.elem()))
510 .into_shared()
511 })
512 }
513
514 fn float_sqrt(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
515 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
516 array.mapv_into(|a: FloatElem| a.sqrt_elem()).into_shared()
517 })
518 }
519
520 fn float_abs(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
521 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
522 NdArrayMathOps::abs(array)
523 })
524 }
525
526 fn float_cos(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
527 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
528 array
529 .mapv_into(|a: FloatElem| (a.to_f64()).cos().elem())
530 .into_shared()
531 })
532 }
533
534 fn float_cosh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
535 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
536 array
537 .mapv_into(|a: FloatElem| (a.to_f64()).cosh().elem())
538 .into_shared()
539 })
540 }
541
542 fn float_sin(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
543 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
544 array
545 .mapv_into(|a: FloatElem| (a.to_f64()).sin().elem())
546 .into_shared()
547 })
548 }
549
550 fn float_sinh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
551 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
552 array
553 .mapv_into(|a: FloatElem| (a.to_f64()).sinh().elem())
554 .into_shared()
555 })
556 }
557
558 fn float_tan(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
559 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
560 array
561 .mapv_into(|a: FloatElem| (a.to_f64()).tan().elem())
562 .into_shared()
563 })
564 }
565
566 fn float_tanh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
567 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
568 array
569 .mapv_into(|a: FloatElem| (a.to_f64()).tanh().elem())
570 .into_shared()
571 })
572 }
573
574 fn float_acos(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
575 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
576 array
577 .mapv_into(|a: FloatElem| (a.to_f64()).acos().elem())
578 .into_shared()
579 })
580 }
581
582 fn float_acosh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
583 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
584 array
585 .mapv_into(|a: FloatElem| (a.to_f64()).acosh().elem())
586 .into_shared()
587 })
588 }
589
590 fn float_asin(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
591 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
592 array
593 .mapv_into(|a: FloatElem| (a.to_f64()).asin().elem())
594 .into_shared()
595 })
596 }
597
598 fn float_asinh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
599 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
600 array
601 .mapv_into(|a: FloatElem| (a.to_f64()).asinh().elem())
602 .into_shared()
603 })
604 }
605
606 fn float_atan(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
607 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
608 array
609 .mapv_into(|a: FloatElem| (a.to_f64()).atan().elem())
610 .into_shared()
611 })
612 }
613
614 fn float_atanh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
615 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
616 array
617 .mapv_into(|a: FloatElem| (a.to_f64()).atanh().elem())
618 .into_shared()
619 })
620 }
621
622 fn float_atan2(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
623 execute_with_float_dtype!((lhs, rhs), FloatElem, |lhs, rhs| {
624 NdArrayMathOps::elementwise_op(lhs, rhs, |a: &FloatElem, b: &FloatElem| a.atan2(*b))
625 })
626 }
627
628 fn float_round(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
629 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
630 array
631 .mapv_into(|a: FloatElem| round_ties_even_wrapper(a.to_f64()).elem())
632 .into_shared()
633 })
634 }
635
636 fn float_floor(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
637 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
638 array
639 .mapv_into(|a: FloatElem| (a.to_f64()).floor().elem())
640 .into_shared()
641 })
642 }
643
644 fn float_ceil(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
645 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
646 array
647 .mapv_into(|a: FloatElem| (a.to_f64()).ceil().elem())
648 .into_shared()
649 })
650 }
651
652 fn float_trunc(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
653 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
654 array
655 .mapv_into(|a: FloatElem| (a.to_f64()).trunc().elem())
656 .into_shared()
657 })
658 }
659
660 fn float_erf(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
661 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
662 array
663 .mapv_into(|a: FloatElem| erf(a.to_f64()).elem())
664 .into_shared()
665 })
666 }
667
668 fn float_cat(tensors: Vec<FloatTensor<Self>>, dim: usize) -> FloatTensor<Self> {
669 cat_with_dtype!(tensors, dim, [F64, F32])
670 }
671
672 fn float_clamp_min(tensor: FloatTensor<Self>, min: Scalar) -> FloatTensor<Self> {
673 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
674 NdArrayMathOps::clamp_min(array, min.elem())
675 })
676 }
677
678 fn float_clamp_max(tensor: FloatTensor<Self>, max: Scalar) -> FloatTensor<Self> {
679 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
680 NdArrayMathOps::clamp_max(array, max.elem())
681 })
682 }
683
684 fn float_clamp(tensor: FloatTensor<Self>, min: Scalar, max: Scalar) -> FloatTensor<Self> {
685 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
686 NdArrayMathOps::clamp(array, min.elem(), max.elem())
687 })
688 }
689
690 fn float_into_int(tensor: FloatTensor<Self>, out_dtype: IntDType) -> NdArrayTensor {
691 execute_with_int_out_dtype!(out_dtype, I, {
692 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
693 array.mapv(|a: FloatElem| a.elem::<I>()).into_shared()
694 })
695 })
696 }
697
698 fn float_powf(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
699 execute_with_float_dtype!((lhs, rhs), FloatElem, |lhs, rhs| {
700 NdArrayMathOps::elementwise_op(lhs, rhs, |a: &FloatElem, b: &FloatElem| a.powf(*b))
701 })
702 }
703
704 fn float_permute(tensor: FloatTensor<Self>, axes: &[usize]) -> FloatTensor<Self> {
705 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
706 NdArrayOps::permute(array, axes)
707 })
708 }
709
710 fn float_flip(tensor: FloatTensor<Self>, axes: &[usize]) -> FloatTensor<Self> {
711 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
712 NdArrayOps::flip(array, axes)
713 })
714 }
715
716 fn float_sign(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
717 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
718 NdArrayMathOps::sign_op(array)
719 })
720 }
721
722 fn float_expand(tensor: FloatTensor<Self>, shape: Shape) -> FloatTensor<Self> {
723 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
724 NdArrayOps::expand(array, shape)
725 })
726 }
727
728 fn float_cast(tensor: FloatTensor<Self>, dtype: FloatDType) -> FloatTensor<Self> {
729 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
730 cast_to_dtype(array, dtype.into())
731 })
732 }
733
734 fn float_grid_sample_2d(
735 tensor: FloatTensor<Self>,
736 grid: FloatTensor<Self>,
737 options: GridSampleOptions,
738 ) -> FloatTensor<Self> {
739 execute_with_float_dtype!((tensor, grid), |tensor, grid| grid_sample_2d(
740 tensor, grid, options
741 ))
742 }
743
744 fn float_unfold(
745 tensor: FloatTensor<Self>,
746 dim: usize,
747 size: usize,
748 step: usize,
749 ) -> FloatTensor<Self> {
750 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
751 NdArrayOps::unfold(array, dim, size, step)
752 })
753 }
754
755 fn float_hypot(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
756 execute_with_float_dtype!((lhs, rhs), FloatElem, |lhs, rhs| {
757 NdArrayMathOps::elementwise_op(lhs, rhs, |a: &FloatElem, b: &FloatElem| a.hypot(*b))
758 })
759 }
760}