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();
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(
183 dim: usize,
184 tensor: FloatTensor<Self>,
185 indices: NdArrayTensor,
186 value: FloatTensor<Self>,
187 update: burn_backend::tensor::IndexingUpdateOp,
188 ) -> FloatTensor<Self> {
189 match update {
190 burn_backend::tensor::IndexingUpdateOp::Add => {
191 execute_with_int_dtype!(
192 indices,
193 IntElem,
194 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
195 execute_with_float_dtype!((tensor, value), |tensor, value| {
196 NdArrayOps::scatter(dim, tensor, idx_array, value)
197 })
198 }
199 )
200 }
201 burn_backend::tensor::IndexingUpdateOp::Assign => {
202 execute_with_int_dtype!(
203 indices,
204 IntElem,
205 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
206 execute_with_float_dtype!((tensor, value), |tensor, value| {
207 NdArrayOps::scatter_assign(dim, tensor, idx_array, value)
208 })
209 }
210 )
211 }
212 burn_backend::tensor::IndexingUpdateOp::Mul => {
213 execute_with_int_dtype!(
214 indices,
215 IntElem,
216 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
217 execute_with_float_dtype!((tensor, value), |tensor, value| {
218 NdArrayOps::scatter_mul(dim, tensor, idx_array, value)
219 })
220 }
221 )
222 }
223 burn_backend::tensor::IndexingUpdateOp::Min => {
224 execute_with_int_dtype!(
225 indices,
226 IntElem,
227 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
228 execute_with_float_dtype!((tensor, value), |tensor, value| {
229 NdArrayOps::scatter_min(dim, tensor, idx_array, value)
230 })
231 }
232 )
233 }
234 burn_backend::tensor::IndexingUpdateOp::Max => {
235 execute_with_int_dtype!(
236 indices,
237 IntElem,
238 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
239 execute_with_float_dtype!((tensor, value), |tensor, value| {
240 NdArrayOps::scatter_max(dim, tensor, idx_array, value)
241 })
242 }
243 )
244 }
245 }
246 }
247
248 fn float_scatter_nd(
249 data: FloatTensor<Self>,
250 indices: NdArrayTensor,
251 values: FloatTensor<Self>,
252 reduction: burn_backend::tensor::IndexingUpdateOp,
253 ) -> FloatTensor<Self> {
254 execute_with_int_dtype!(
255 indices,
256 IntElem,
257 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
258 execute_with_float_dtype!((data, values), |data, values| NdArrayOps::scatter_nd(
259 data, idx_array, values, reduction
260 ))
261 }
262 )
263 }
264
265 fn float_gather_nd(data: FloatTensor<Self>, indices: NdArrayTensor) -> FloatTensor<Self> {
266 execute_with_int_dtype!(
267 indices,
268 IntElem,
269 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
270 execute_with_float_dtype!(data, FloatElem, |array: SharedArray<FloatElem>| {
271 NdArrayOps::gather_nd(array, idx_array)
272 })
273 }
274 )
275 }
276
277 fn float_select(
278 tensor: FloatTensor<Self>,
279 dim: usize,
280 indices: NdArrayTensor,
281 ) -> FloatTensor<Self> {
282 execute_with_int_dtype!(
283 indices,
284 IntElem,
285 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
286 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
287 NdArrayMathOps::select(array, dim, idx_array)
288 })
289 }
290 )
291 }
292
293 fn float_select_assign(
294 tensor: FloatTensor<Self>,
295 dim: usize,
296 indices: NdArrayTensor,
297 value: FloatTensor<Self>,
298 update: burn_backend::tensor::IndexingUpdateOp,
299 ) -> FloatTensor<Self> {
300 match update {
301 burn_backend::tensor::IndexingUpdateOp::Add => {
302 execute_with_int_dtype!(
303 indices,
304 IntElem,
305 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
306 execute_with_float_dtype!((tensor, value), |tensor, value| {
307 NdArrayMathOps::select_assign(tensor, dim, idx_array, value)
308 })
309 }
310 )
311 }
312 burn_backend::tensor::IndexingUpdateOp::Assign => {
313 execute_with_int_dtype!(
314 indices,
315 IntElem,
316 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
317 execute_with_float_dtype!((tensor, value), |tensor, value| {
318 NdArrayMathOps::select_assign_replace(tensor, dim, idx_array, value)
319 })
320 }
321 )
322 }
323 burn_backend::tensor::IndexingUpdateOp::Mul => {
324 execute_with_int_dtype!(
325 indices,
326 IntElem,
327 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
328 execute_with_float_dtype!((tensor, value), |tensor, value| {
329 NdArrayMathOps::select_assign_mul(tensor, dim, idx_array, value)
330 })
331 }
332 )
333 }
334 burn_backend::tensor::IndexingUpdateOp::Min => {
335 execute_with_int_dtype!(
336 indices,
337 IntElem,
338 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
339 execute_with_float_dtype!((tensor, value), |tensor, value| {
340 NdArrayMathOps::select_assign_min(tensor, dim, idx_array, value)
341 })
342 }
343 )
344 }
345 burn_backend::tensor::IndexingUpdateOp::Max => {
346 execute_with_int_dtype!(
347 indices,
348 IntElem,
349 |idx_array: SharedArray<IntElem>| -> NdArrayTensor {
350 execute_with_float_dtype!((tensor, value), |tensor, value| {
351 NdArrayMathOps::select_assign_max(tensor, dim, idx_array, value)
352 })
353 }
354 )
355 }
356 }
357 }
358
359 fn float_slice(tensor: FloatTensor<Self>, slices: &[burn_backend::Slice]) -> FloatTensor<Self> {
360 slice!(tensor, slices)
361 }
362
363 fn float_slice_assign(
364 tensor: FloatTensor<Self>,
365 slices: &[burn_backend::Slice],
366 value: FloatTensor<Self>,
367 ) -> FloatTensor<Self> {
368 execute_with_float_dtype!((tensor, value), |tensor, value| {
369 NdArrayOps::slice_assign(tensor, slices, value)
370 })
371 }
372
373 fn float_mask_where(
374 tensor: FloatTensor<Self>,
375 mask: NdArrayTensor,
376 value: FloatTensor<Self>,
377 ) -> FloatTensor<Self> {
378 execute_with_float_dtype!((tensor, value), |tensor, value| {
379 NdArrayOps::mask_where(tensor, mask.bool(), value)
380 })
381 }
382
383 fn float_mask_fill(
384 tensor: FloatTensor<Self>,
385 mask: NdArrayTensor,
386 value: Scalar,
387 ) -> FloatTensor<Self> {
388 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
389 NdArrayOps::mask_fill(array, mask.bool(), value.elem())
390 })
391 }
392
393 fn float_equal(
394 lhs: FloatTensor<Self>,
395 rhs: FloatTensor<Self>,
396 _out_dtype: BoolDType,
397 ) -> NdArrayTensor {
398 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| { NdArrayMathOps::equal(lhs, rhs) })
399 }
400
401 fn float_equal_elem(
402 lhs: FloatTensor<Self>,
403 rhs: Scalar,
404 _out_dtype: BoolDType,
405 ) -> NdArrayTensor {
406 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
407 NdArrayMathOps::equal_elem(array, rhs.elem())
408 })
409 }
410
411 fn float_greater(
412 lhs: FloatTensor<Self>,
413 rhs: FloatTensor<Self>,
414 _out_dtype: BoolDType,
415 ) -> NdArrayTensor {
416 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| { NdArrayMathOps::greater(lhs, rhs) })
417 }
418
419 fn float_greater_elem(
420 lhs: FloatTensor<Self>,
421 rhs: Scalar,
422 _out_dtype: BoolDType,
423 ) -> NdArrayTensor {
424 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
425 NdArrayMathOps::greater_elem(array, rhs.elem())
426 })
427 }
428
429 fn float_greater_equal(
430 lhs: FloatTensor<Self>,
431 rhs: FloatTensor<Self>,
432 _out_dtype: BoolDType,
433 ) -> NdArrayTensor {
434 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| {
435 NdArrayMathOps::greater_equal(lhs, rhs)
436 })
437 }
438
439 fn float_greater_equal_elem(
440 lhs: FloatTensor<Self>,
441 rhs: Scalar,
442 _out_dtype: BoolDType,
443 ) -> NdArrayTensor {
444 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
445 NdArrayMathOps::greater_equal_elem(array, rhs.elem())
446 })
447 }
448
449 fn float_lower(
450 lhs: FloatTensor<Self>,
451 rhs: FloatTensor<Self>,
452 _out_dtype: BoolDType,
453 ) -> NdArrayTensor {
454 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| { NdArrayMathOps::lower(lhs, rhs) })
455 }
456
457 fn float_lower_elem(
458 lhs: FloatTensor<Self>,
459 rhs: Scalar,
460 _out_dtype: BoolDType,
461 ) -> NdArrayTensor {
462 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
463 NdArrayMathOps::lower_elem(array, rhs.elem())
464 })
465 }
466
467 fn float_lower_equal(
468 lhs: FloatTensor<Self>,
469 rhs: FloatTensor<Self>,
470 _out_dtype: BoolDType,
471 ) -> NdArrayTensor {
472 execute_with_float_dtype!((lhs, rhs), |lhs, rhs| {
473 NdArrayMathOps::lower_equal(lhs, rhs)
474 })
475 }
476
477 fn float_lower_equal_elem(
478 lhs: FloatTensor<Self>,
479 rhs: Scalar,
480 _out_dtype: BoolDType,
481 ) -> NdArrayTensor {
482 execute_with_float_dtype!(lhs, FloatElem, |array: SharedArray<FloatElem>| {
483 NdArrayMathOps::lower_equal_elem(array, rhs.elem())
484 })
485 }
486
487 fn float_detach(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
488 tensor
489 }
490
491 fn float_mean(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
492 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
494 NdArrayMathOps::mean_view(array.view())
495 })
496 }
497
498 fn float_sum(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
499 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
501 NdArrayMathOps::sum_view(array.view())
502 })
503 }
504
505 fn float_mean_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
506 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
507 NdArrayMathOps::mean_dim(array, dim)
508 })
509 }
510
511 fn float_cumsum(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
512 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
513 NdArrayMathOps::cumsum(array, dim)
514 })
515 }
516
517 fn float_cumprod(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
518 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
519 NdArrayMathOps::cumprod(array, dim)
520 })
521 }
522
523 fn float_cummin(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
524 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
525 NdArrayMathOps::cummin(array, dim)
526 })
527 }
528
529 fn float_cummax(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
530 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
531 NdArrayMathOps::cummax(array, dim)
532 })
533 }
534
535 fn float_sum_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
536 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
537 NdArrayMathOps::sum_dim(array, dim)
538 })
539 }
540
541 fn float_argmax(tensor: FloatTensor<Self>, dim: usize, out_dtype: IntDType) -> NdArrayTensor {
542 execute_with_int_out_dtype!(out_dtype, I, {
544 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
545 NdArrayMathOps::argmax_view::<I>(array.view(), dim)
546 })
547 })
548 }
549
550 fn float_argmin(tensor: FloatTensor<Self>, dim: usize, out_dtype: IntDType) -> NdArrayTensor {
551 execute_with_int_out_dtype!(out_dtype, I, {
553 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
554 NdArrayMathOps::argmin_view::<I>(array.view(), dim)
555 })
556 })
557 }
558
559 fn float_exp(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
560 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
561 array.mapv_into(|a: FloatElem| a.exp_elem()).into_shared()
562 })
563 }
564
565 fn float_log(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
566 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
567 array.mapv_into(|a: FloatElem| a.log_elem()).into_shared()
568 })
569 }
570
571 fn float_prod(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
572 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
574 NdArrayMathOps::prod_view(array.view())
575 })
576 }
577
578 fn float_prod_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
579 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
580 NdArrayMathOps::prod_dim(array, dim)
581 })
582 }
583
584 fn float_max(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
585 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
587 NdArrayMathOps::max_float_view(array.view())
588 })
589 }
590
591 fn float_min(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
592 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
594 NdArrayMathOps::min_float_view(array.view())
595 })
596 }
597
598 fn float_log1p(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
599 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
600 array.mapv_into(|a: FloatElem| a.log1p_elem()).into_shared()
601 })
602 }
603
604 fn float_powf_scalar_impl(tensor: FloatTensor<Self>, value: Scalar) -> FloatTensor<Self> {
605 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
606 array
607 .mapv_into(|a: FloatElem| a.powf_elem(value.elem()))
608 .into_shared()
609 })
610 }
611
612 fn float_sqrt(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
613 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
614 array.mapv_into(|a: FloatElem| a.sqrt_elem()).into_shared()
615 })
616 }
617
618 fn float_abs(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
619 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
620 NdArrayMathOps::abs(array)
621 })
622 }
623
624 fn float_cos(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
625 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
626 array
627 .mapv_into(|a: FloatElem| (a.to_f64()).cos().elem())
628 .into_shared()
629 })
630 }
631
632 fn float_cosh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
633 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
634 array
635 .mapv_into(|a: FloatElem| (a.to_f64()).cosh().elem())
636 .into_shared()
637 })
638 }
639
640 fn float_sin(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
641 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
642 array
643 .mapv_into(|a: FloatElem| (a.to_f64()).sin().elem())
644 .into_shared()
645 })
646 }
647
648 fn float_sinh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
649 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
650 array
651 .mapv_into(|a: FloatElem| (a.to_f64()).sinh().elem())
652 .into_shared()
653 })
654 }
655
656 fn float_tan(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
657 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
658 array
659 .mapv_into(|a: FloatElem| (a.to_f64()).tan().elem())
660 .into_shared()
661 })
662 }
663
664 fn float_tanh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
665 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
666 array
667 .mapv_into(|a: FloatElem| (a.to_f64()).tanh().elem())
668 .into_shared()
669 })
670 }
671
672 fn float_acos(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
673 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
674 array
675 .mapv_into(|a: FloatElem| (a.to_f64()).acos().elem())
676 .into_shared()
677 })
678 }
679
680 fn float_acosh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
681 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
682 array
683 .mapv_into(|a: FloatElem| (a.to_f64()).acosh().elem())
684 .into_shared()
685 })
686 }
687
688 fn float_asin(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
689 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
690 array
691 .mapv_into(|a: FloatElem| (a.to_f64()).asin().elem())
692 .into_shared()
693 })
694 }
695
696 fn float_asinh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
697 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
698 array
699 .mapv_into(|a: FloatElem| (a.to_f64()).asinh().elem())
700 .into_shared()
701 })
702 }
703
704 fn float_atan(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
705 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
706 array
707 .mapv_into(|a: FloatElem| (a.to_f64()).atan().elem())
708 .into_shared()
709 })
710 }
711
712 fn float_atanh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
713 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
714 array
715 .mapv_into(|a: FloatElem| (a.to_f64()).atanh().elem())
716 .into_shared()
717 })
718 }
719
720 fn float_atan2(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
721 execute_with_float_dtype!((lhs, rhs), FloatElem, |lhs, rhs| {
722 NdArrayMathOps::elementwise_op(lhs, rhs, |a: &FloatElem, b: &FloatElem| a.atan2(*b))
723 })
724 }
725
726 fn float_round(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
727 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
728 array
729 .mapv_into(|a: FloatElem| round_ties_even_wrapper(a.to_f64()).elem())
730 .into_shared()
731 })
732 }
733
734 fn float_floor(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
735 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
736 array
737 .mapv_into(|a: FloatElem| (a.to_f64()).floor().elem())
738 .into_shared()
739 })
740 }
741
742 fn float_ceil(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
743 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
744 array
745 .mapv_into(|a: FloatElem| (a.to_f64()).ceil().elem())
746 .into_shared()
747 })
748 }
749
750 fn float_trunc(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
751 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
752 array
753 .mapv_into(|a: FloatElem| (a.to_f64()).trunc().elem())
754 .into_shared()
755 })
756 }
757
758 fn float_erf(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
759 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
760 array
761 .mapv_into(|a: FloatElem| erf(a.to_f64()).elem())
762 .into_shared()
763 })
764 }
765
766 fn float_cat(tensors: Vec<FloatTensor<Self>>, dim: usize) -> FloatTensor<Self> {
767 cat_with_dtype!(tensors, dim, [F64, F32])
768 }
769
770 fn float_clamp_min(tensor: FloatTensor<Self>, min: Scalar) -> FloatTensor<Self> {
771 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
772 NdArrayMathOps::clamp_min(array, min.elem())
773 })
774 }
775
776 fn float_clamp_max(tensor: FloatTensor<Self>, max: Scalar) -> FloatTensor<Self> {
777 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
778 NdArrayMathOps::clamp_max(array, max.elem())
779 })
780 }
781
782 fn float_clamp(tensor: FloatTensor<Self>, min: Scalar, max: Scalar) -> FloatTensor<Self> {
783 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
784 NdArrayMathOps::clamp(array, min.elem(), max.elem())
785 })
786 }
787
788 fn float_into_int(tensor: FloatTensor<Self>, out_dtype: IntDType) -> NdArrayTensor {
789 execute_with_int_out_dtype!(out_dtype, I, {
790 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
791 array.mapv(|a: FloatElem| a.elem::<I>()).into_shared()
792 })
793 })
794 }
795
796 fn float_powf(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
797 execute_with_float_dtype!((lhs, rhs), FloatElem, |lhs, rhs| {
798 NdArrayMathOps::elementwise_op(lhs, rhs, |a: &FloatElem, b: &FloatElem| a.powf(*b))
799 })
800 }
801
802 fn float_permute(tensor: FloatTensor<Self>, axes: &[usize]) -> FloatTensor<Self> {
803 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
804 NdArrayOps::permute(array, axes)
805 })
806 }
807
808 fn float_flip(tensor: FloatTensor<Self>, axes: &[usize]) -> FloatTensor<Self> {
809 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
810 NdArrayOps::flip(array, axes)
811 })
812 }
813
814 fn float_sign(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
815 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
816 NdArrayMathOps::sign_op(array)
817 })
818 }
819
820 fn float_expand(tensor: FloatTensor<Self>, shape: Shape) -> FloatTensor<Self> {
821 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
822 NdArrayOps::expand(array, shape)
823 })
824 }
825
826 fn float_cast(tensor: FloatTensor<Self>, dtype: FloatDType) -> FloatTensor<Self> {
827 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
828 cast_to_dtype(array, dtype.into())
829 })
830 }
831
832 fn float_grid_sample_2d(
833 tensor: FloatTensor<Self>,
834 grid: FloatTensor<Self>,
835 options: GridSampleOptions,
836 ) -> FloatTensor<Self> {
837 execute_with_float_dtype!((tensor, grid), |tensor, grid| grid_sample_2d(
838 tensor, grid, options
839 ))
840 }
841
842 fn float_unfold(
843 tensor: FloatTensor<Self>,
844 dim: usize,
845 size: usize,
846 step: usize,
847 ) -> FloatTensor<Self> {
848 execute_with_float_dtype!(tensor, FloatElem, |array: SharedArray<FloatElem>| {
849 NdArrayOps::unfold(array, dim, size, step)
850 })
851 }
852
853 fn float_hypot(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
854 execute_with_float_dtype!((lhs, rhs), FloatElem, |lhs, rhs| {
855 NdArrayMathOps::elementwise_op(lhs, rhs, |a: &FloatElem, b: &FloatElem| a.hypot(*b))
856 })
857 }
858}