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