Skip to main content

burn_ndarray/ops/
tensor.rs

1// Language
2use 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
9// Current crate
10use 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
21// Workspace crates
22use 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        // Use view() for zero-copy on borrowed storage
395        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        // Use view() for zero-copy on borrowed storage
402        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        // Use view() for zero-copy on borrowed storage
445        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        // Use view() for zero-copy on borrowed storage
454        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        // Use view() for zero-copy on borrowed storage
475        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        // Use view() for zero-copy on borrowed storage
488        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        // Use view() for zero-copy on borrowed storage
495        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}