Skip to main content

burn_dispatch/ops/
tensor.rs

1use alloc::vec::Vec;
2use burn_backend::{
3    BoolDType, ExecutionError, FloatDType, IntDType, Scalar, Shape, Slice, TensorData,
4    ops::{FloatTensorOps, PadMode},
5    tensor::{BoolTensor, FloatTensor, IndexingUpdateOp, IntTensor},
6};
7use burn_backend_extension::backend_dispatch;
8
9use crate::{Dispatch, DispatchDevice};
10
11#[backend_dispatch]
12impl FloatTensorOps<Self> for Dispatch {
13    fn float_pad(
14        tensor: FloatTensor<Self>,
15        padding: &[(usize, usize)],
16        mode: PadMode,
17    ) -> FloatTensor<Self> {
18        B::float_pad(tensor, padding, mode)
19    }
20
21    fn float_from_data(
22        data: burn_backend::TensorData,
23        device: &DispatchDevice,
24    ) -> FloatTensor<Self> {
25        B::float_from_data(data, device)
26    }
27
28    fn float_random(
29        shape: Shape,
30        distribution: burn_backend::Distribution,
31        device: &DispatchDevice,
32        dtype: FloatDType,
33    ) -> FloatTensor<Self> {
34        B::float_random(shape, distribution, device, dtype)
35    }
36
37    async fn float_into_data(tensor: FloatTensor<Self>) -> Result<TensorData, ExecutionError> {
38        B::float_into_data(tensor).await
39    }
40
41    #[backend_dispatch(skip)]
42    fn float_to_device(tensor: FloatTensor<Self>, device: &DispatchDevice) -> FloatTensor<Self> {
43        // `Tensor::to_device` aligns the target's autodiff context with the source tensor before
44        // reaching this low-level operation. Direct callers must likewise provide compatible
45        // contexts; this layer only routes the transfer between compute resources.
46        float_to_device!(
47            Float,
48            float,
49            tensor,
50            device,
51            float_to_device,
52            |inner, device| { super::transfer::float_transfer::<B1, B2>(inner, device) }
53        )
54    }
55
56    fn float_into_int(tensor: FloatTensor<Self>, dtype: burn_backend::IntDType) -> IntTensor<Self> {
57        B::float_into_int(tensor, dtype)
58    }
59
60    fn float_empty(shape: Shape, device: &DispatchDevice, dtype: FloatDType) -> FloatTensor<Self> {
61        B::float_empty(shape, device, dtype)
62    }
63
64    fn float_add(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
65        B::float_add(lhs, rhs)
66    }
67
68    fn float_add_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
69        B::float_add_scalar(lhs, rhs)
70    }
71
72    fn float_sub(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
73        B::float_sub(lhs, rhs)
74    }
75
76    fn float_sub_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
77        B::float_sub_scalar(lhs, rhs)
78    }
79
80    fn float_mul(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
81        B::float_mul(lhs, rhs)
82    }
83
84    fn float_mul_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
85        B::float_mul_scalar(lhs, rhs)
86    }
87
88    fn float_div(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
89        B::float_div(lhs, rhs)
90    }
91
92    fn float_div_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
93        B::float_div_scalar(lhs, rhs)
94    }
95
96    fn float_remainder(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
97        B::float_remainder(lhs, rhs)
98    }
99
100    fn float_remainder_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
101        B::float_remainder_scalar(lhs, rhs)
102    }
103
104    fn float_fmod(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
105        B::float_fmod(lhs, rhs)
106    }
107
108    fn float_fmod_scalar(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
109        B::float_fmod_scalar(lhs, rhs)
110    }
111
112    fn float_matmul(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
113        B::float_matmul(lhs, rhs)
114    }
115
116    fn float_cross(
117        lhs: FloatTensor<Self>,
118        rhs: FloatTensor<Self>,
119        dim: usize,
120    ) -> FloatTensor<Self> {
121        B::float_cross(lhs, rhs, dim)
122    }
123
124    fn float_recip(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
125        B::float_recip(tensor)
126    }
127
128    fn float_swap_dims(tensor: FloatTensor<Self>, dim1: usize, dim2: usize) -> FloatTensor<Self> {
129        B::float_swap_dims(tensor, dim1, dim2)
130    }
131
132    fn float_permute(tensor: FloatTensor<Self>, axes: &[usize]) -> FloatTensor<Self> {
133        B::float_permute(tensor, axes)
134    }
135
136    fn float_flip(tensor: FloatTensor<Self>, axes: &[usize]) -> FloatTensor<Self> {
137        B::float_flip(tensor, axes)
138    }
139
140    fn float_reshape(tensor: FloatTensor<Self>, shape: Shape) -> FloatTensor<Self> {
141        B::float_reshape(tensor, shape)
142    }
143
144    fn float_gather(
145        dim: usize,
146        tensor: FloatTensor<Self>,
147        indices: IntTensor<Self>,
148    ) -> FloatTensor<Self> {
149        B::float_gather(dim, tensor, indices)
150    }
151
152    fn float_scatter(
153        dim: usize,
154        tensor: FloatTensor<Self>,
155        indices: IntTensor<Self>,
156        value: FloatTensor<Self>,
157        update: IndexingUpdateOp,
158    ) -> FloatTensor<Self> {
159        B::float_scatter(dim, tensor, indices, value, update)
160    }
161
162    fn float_scatter_nd(
163        data: FloatTensor<Self>,
164        indices: IntTensor<Self>,
165        values: FloatTensor<Self>,
166        reduction: burn_backend::tensor::IndexingUpdateOp,
167    ) -> FloatTensor<Self> {
168        B::float_scatter_nd(data, indices, values, reduction)
169    }
170
171    fn float_gather_nd(data: FloatTensor<Self>, indices: IntTensor<Self>) -> FloatTensor<Self> {
172        B::float_gather_nd(data, indices)
173    }
174
175    fn float_select(
176        tensor: FloatTensor<Self>,
177        dim: usize,
178        indices: IntTensor<Self>,
179    ) -> FloatTensor<Self> {
180        B::float_select(tensor, dim, indices)
181    }
182
183    fn float_select_assign(
184        tensor: FloatTensor<Self>,
185        dim: usize,
186        indices: IntTensor<Self>,
187        value: FloatTensor<Self>,
188        update: IndexingUpdateOp,
189    ) -> FloatTensor<Self> {
190        B::float_select_assign(tensor, dim, indices, value, update)
191    }
192
193    fn float_slice(tensor: FloatTensor<Self>, slices: &[Slice]) -> FloatTensor<Self> {
194        B::float_slice(tensor, slices)
195    }
196
197    fn float_slice_assign(
198        tensor: FloatTensor<Self>,
199        slices: &[Slice],
200        value: FloatTensor<Self>,
201    ) -> FloatTensor<Self> {
202        B::float_slice_assign(tensor, slices, value)
203    }
204
205    fn float_mask_where(
206        tensor: FloatTensor<Self>,
207        mask: BoolTensor<Self>,
208        value: FloatTensor<Self>,
209    ) -> FloatTensor<Self> {
210        B::float_mask_where(tensor, mask, value)
211    }
212
213    fn float_mask_fill(
214        tensor: FloatTensor<Self>,
215        mask: BoolTensor<Self>,
216        value: Scalar,
217    ) -> FloatTensor<Self> {
218        B::float_mask_fill(tensor, mask, value)
219    }
220
221    async fn float_mask_select(
222        tensor: FloatTensor<Self>,
223        mask: BoolTensor<Self>,
224    ) -> FloatTensor<Self> {
225        B::float_mask_select(tensor, mask).await
226    }
227
228    fn float_equal(
229        lhs: FloatTensor<Self>,
230        rhs: FloatTensor<Self>,
231        out_dtype: BoolDType,
232    ) -> BoolTensor<Self> {
233        B::float_equal(lhs, rhs, out_dtype)
234    }
235
236    fn float_equal_elem(
237        lhs: FloatTensor<Self>,
238        rhs: Scalar,
239        out_dtype: BoolDType,
240    ) -> BoolTensor<Self> {
241        B::float_equal_elem(lhs, rhs, out_dtype)
242    }
243
244    fn float_greater(
245        lhs: FloatTensor<Self>,
246        rhs: FloatTensor<Self>,
247        out_dtype: BoolDType,
248    ) -> BoolTensor<Self> {
249        B::float_greater(lhs, rhs, out_dtype)
250    }
251
252    fn float_greater_elem(
253        lhs: FloatTensor<Self>,
254        rhs: Scalar,
255        out_dtype: BoolDType,
256    ) -> BoolTensor<Self> {
257        B::float_greater_elem(lhs, rhs, out_dtype)
258    }
259
260    fn float_greater_equal(
261        lhs: FloatTensor<Self>,
262        rhs: FloatTensor<Self>,
263        out_dtype: BoolDType,
264    ) -> BoolTensor<Self> {
265        B::float_greater_equal(lhs, rhs, out_dtype)
266    }
267
268    fn float_greater_equal_elem(
269        lhs: FloatTensor<Self>,
270        rhs: Scalar,
271        out_dtype: BoolDType,
272    ) -> BoolTensor<Self> {
273        B::float_greater_equal_elem(lhs, rhs, out_dtype)
274    }
275
276    fn float_lower(
277        lhs: FloatTensor<Self>,
278        rhs: FloatTensor<Self>,
279        out_dtype: BoolDType,
280    ) -> BoolTensor<Self> {
281        B::float_lower(lhs, rhs, out_dtype)
282    }
283
284    fn float_lower_elem(
285        lhs: FloatTensor<Self>,
286        rhs: Scalar,
287        out_dtype: BoolDType,
288    ) -> BoolTensor<Self> {
289        B::float_lower_elem(lhs, rhs, out_dtype)
290    }
291
292    fn float_lower_equal(
293        lhs: FloatTensor<Self>,
294        rhs: FloatTensor<Self>,
295        out_dtype: BoolDType,
296    ) -> BoolTensor<Self> {
297        B::float_lower_equal(lhs, rhs, out_dtype)
298    }
299
300    fn float_lower_equal_elem(
301        lhs: FloatTensor<Self>,
302        rhs: Scalar,
303        out_dtype: BoolDType,
304    ) -> BoolTensor<Self> {
305        B::float_lower_equal_elem(lhs, rhs, out_dtype)
306    }
307
308    fn float_sum(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
309        B::float_sum(tensor)
310    }
311
312    fn float_sum_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
313        B::float_sum_dim(tensor, dim)
314    }
315
316    fn float_sum_dims(tensor: FloatTensor<Self>, dims: &[usize]) -> FloatTensor<Self> {
317        B::float_sum_dims(tensor, dims)
318    }
319
320    fn float_mean_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
321        B::float_mean_dim(tensor, dim)
322    }
323
324    fn float_cumsum(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
325        B::float_cumsum(tensor, dim)
326    }
327
328    fn float_cumprod(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
329        B::float_cumprod(tensor, dim)
330    }
331
332    fn float_cummin(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
333        B::float_cummin(tensor, dim)
334    }
335
336    fn float_cummax(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
337        B::float_cummax(tensor, dim)
338    }
339
340    fn float_cast(tensor: FloatTensor<Self>, dtype: FloatDType) -> FloatTensor<Self> {
341        B::float_cast(tensor, dtype)
342    }
343
344    fn float_exp(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
345        B::float_exp(tensor)
346    }
347
348    fn float_log(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
349        B::float_log(tensor)
350    }
351
352    fn float_log1p(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
353        B::float_log1p(tensor)
354    }
355
356    fn float_powf(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
357        B::float_powf(lhs, rhs)
358    }
359
360    fn float_powf_scalar_impl(tensor: FloatTensor<Self>, value: Scalar) -> FloatTensor<Self> {
361        B::float_powf_scalar_impl(tensor, value)
362    }
363
364    fn float_sqrt(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
365        B::float_sqrt(tensor)
366    }
367
368    fn float_abs(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
369        B::float_abs(tensor)
370    }
371
372    fn float_cos(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
373        B::float_cos(tensor)
374    }
375
376    fn float_sin(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
377        B::float_sin(tensor)
378    }
379
380    fn float_tan(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
381        B::float_tan(tensor)
382    }
383
384    fn float_cosh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
385        B::float_cosh(tensor)
386    }
387
388    fn float_sinh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
389        B::float_sinh(tensor)
390    }
391
392    fn float_tanh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
393        B::float_tanh(tensor)
394    }
395
396    fn float_acos(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
397        B::float_acos(tensor)
398    }
399
400    fn float_acosh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
401        B::float_acosh(tensor)
402    }
403
404    fn float_asin(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
405        B::float_asin(tensor)
406    }
407
408    fn float_asinh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
409        B::float_asinh(tensor)
410    }
411
412    fn float_atan(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
413        B::float_atan(tensor)
414    }
415
416    fn float_atanh(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
417        B::float_atanh(tensor)
418    }
419
420    fn float_atan2(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
421        B::float_atan2(lhs, rhs)
422    }
423
424    fn float_round(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
425        B::float_round(tensor)
426    }
427
428    fn float_floor(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
429        B::float_floor(tensor)
430    }
431
432    fn float_ceil(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
433        B::float_ceil(tensor)
434    }
435
436    fn float_trunc(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
437        B::float_trunc(tensor)
438    }
439
440    fn float_erf(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
441        B::float_erf(tensor)
442    }
443
444    fn float_argmax(tensor: FloatTensor<Self>, dim: usize, out_dtype: IntDType) -> IntTensor<Self> {
445        B::float_argmax(tensor, dim, out_dtype)
446    }
447
448    fn float_argtopk(
449        tensor: FloatTensor<Self>,
450        dim: usize,
451        k: usize,
452        out_dtype: IntDType,
453    ) -> IntTensor<Self> {
454        B::float_argtopk(tensor, dim, k, out_dtype)
455    }
456
457    fn float_topk(tensor: FloatTensor<Self>, dim: usize, k: usize) -> FloatTensor<Self> {
458        B::float_topk(tensor, dim, k)
459    }
460
461    fn float_topk_with_indices(
462        tensor: FloatTensor<Self>,
463        dim: usize,
464        k: usize,
465        out_dtype: IntDType,
466    ) -> (FloatTensor<Self>, IntTensor<Self>) {
467        B::float_topk_with_indices(tensor, dim, k, out_dtype)
468    }
469
470    fn float_argmin(tensor: FloatTensor<Self>, dim: usize, out_dtype: IntDType) -> IntTensor<Self> {
471        B::float_argmin(tensor, dim, out_dtype)
472    }
473
474    fn float_expand(tensor: FloatTensor<Self>, shape: Shape) -> FloatTensor<Self> {
475        B::float_expand(tensor, shape)
476    }
477
478    fn float_unfold(
479        tensor: FloatTensor<Self>,
480        dim: usize,
481        size: usize,
482        step: usize,
483    ) -> FloatTensor<Self> {
484        B::float_unfold(tensor, dim, size, step)
485    }
486
487    fn float_detach(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
488        B::float_detach(tensor)
489    }
490
491    fn float_set_require_grad(tensor: FloatTensor<Self>, require_grad: bool) -> FloatTensor<Self> {
492        B::float_set_require_grad(tensor, require_grad)
493    }
494
495    fn float_is_require_grad(tensor: &FloatTensor<Self>) -> bool {
496        B::float_is_require_grad(tensor)
497    }
498
499    // Default implementation
500    fn float_zeros(shape: Shape, device: &DispatchDevice, dtype: FloatDType) -> FloatTensor<Self> {
501        B::float_zeros(shape, device, dtype)
502    }
503
504    fn float_ones(shape: Shape, device: &DispatchDevice, dtype: FloatDType) -> FloatTensor<Self> {
505        B::float_ones(shape, device, dtype)
506    }
507
508    fn float_full(
509        shape: Shape,
510        fill_value: Scalar,
511        device: &DispatchDevice,
512        dtype: FloatDType,
513    ) -> FloatTensor<Self> {
514        B::float_full(shape, fill_value, device, dtype)
515    }
516
517    fn float_repeat_dim(tensor: FloatTensor<Self>, dim: usize, times: usize) -> FloatTensor<Self> {
518        B::float_repeat_dim(tensor, dim, times)
519    }
520
521    fn float_clamp_min(tensor: FloatTensor<Self>, min: Scalar) -> FloatTensor<Self> {
522        B::float_clamp_min(tensor, min)
523    }
524
525    fn float_clamp_max(tensor: FloatTensor<Self>, max: Scalar) -> FloatTensor<Self> {
526        B::float_clamp_max(tensor, max)
527    }
528
529    fn float_clamp(tensor: FloatTensor<Self>, min: Scalar, max: Scalar) -> FloatTensor<Self> {
530        B::float_clamp(tensor, min, max)
531    }
532
533    fn float_neg(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
534        B::float_neg(tensor)
535    }
536
537    fn float_transpose(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
538        B::float_transpose(tensor)
539    }
540
541    fn float_not_equal(
542        lhs: FloatTensor<Self>,
543        rhs: FloatTensor<Self>,
544        out_dtype: BoolDType,
545    ) -> BoolTensor<Self> {
546        B::float_not_equal(lhs, rhs, out_dtype)
547    }
548
549    fn float_not_equal_elem(
550        lhs: FloatTensor<Self>,
551        rhs: Scalar,
552        out_dtype: BoolDType,
553    ) -> BoolTensor<Self> {
554        B::float_not_equal_elem(lhs, rhs, out_dtype)
555    }
556
557    fn float_prod(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
558        B::float_prod(tensor)
559    }
560
561    fn float_prod_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
562        B::float_prod_dim(tensor, dim)
563    }
564
565    fn float_mean(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
566        B::float_mean(tensor)
567    }
568
569    fn float_powi(lhs: FloatTensor<Self>, rhs: IntTensor<Self>) -> FloatTensor<Self> {
570        B::float_powi(lhs, rhs)
571    }
572
573    fn float_powi_scalar_impl(lhs: FloatTensor<Self>, rhs: Scalar) -> FloatTensor<Self> {
574        B::float_powi_scalar_impl(lhs, rhs)
575    }
576
577    fn float_powf_scalar(tensor: FloatTensor<Self>, value: Scalar) -> FloatTensor<Self> {
578        B::float_powf_scalar(tensor, value)
579    }
580
581    fn float_cat(tensors: Vec<FloatTensor<Self>>, dim: usize) -> FloatTensor<Self> {
582        B::float_cat(tensors, dim)
583    }
584
585    fn float_max(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
586        B::float_max(tensor)
587    }
588
589    fn float_max_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
590        B::float_max_dim(tensor, dim)
591    }
592
593    fn float_max_dim_with_indices(
594        tensor: FloatTensor<Self>,
595        dim: usize,
596        indices_dtype: IntDType,
597    ) -> (FloatTensor<Self>, IntTensor<Self>) {
598        B::float_max_dim_with_indices(tensor, dim, indices_dtype)
599    }
600
601    fn float_min(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
602        B::float_min(tensor)
603    }
604
605    fn float_min_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
606        B::float_min_dim(tensor, dim)
607    }
608
609    fn float_min_dim_with_indices(
610        tensor: FloatTensor<Self>,
611        dim: usize,
612        indices_dtype: IntDType,
613    ) -> (FloatTensor<Self>, IntTensor<Self>) {
614        B::float_min_dim_with_indices(tensor, dim, indices_dtype)
615    }
616
617    fn float_max_abs(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
618        B::float_max_abs(tensor)
619    }
620
621    fn float_max_abs_dim(tensor: FloatTensor<Self>, dim: usize) -> FloatTensor<Self> {
622        B::float_max_abs_dim(tensor, dim)
623    }
624
625    fn float_any(tensor: FloatTensor<Self>, out_dtype: BoolDType) -> BoolTensor<Self> {
626        B::float_any(tensor, out_dtype)
627    }
628
629    fn float_any_dim(
630        tensor: FloatTensor<Self>,
631        dim: usize,
632        out_dtype: BoolDType,
633    ) -> BoolTensor<Self> {
634        B::float_any_dim(tensor, dim, out_dtype)
635    }
636
637    fn float_all(tensor: FloatTensor<Self>, out_dtype: BoolDType) -> BoolTensor<Self> {
638        B::float_all(tensor, out_dtype)
639    }
640
641    fn float_all_dim(
642        tensor: FloatTensor<Self>,
643        dim: usize,
644        out_dtype: BoolDType,
645    ) -> BoolTensor<Self> {
646        B::float_all_dim(tensor, dim, out_dtype)
647    }
648
649    fn float_sign(tensor: FloatTensor<Self>) -> FloatTensor<Self> {
650        B::float_sign(tensor)
651    }
652
653    fn float_sort(tensor: FloatTensor<Self>, dim: usize, descending: bool) -> FloatTensor<Self> {
654        B::float_sort(tensor, dim, descending)
655    }
656
657    fn float_sort_with_indices(
658        tensor: FloatTensor<Self>,
659        dim: usize,
660        descending: bool,
661        indices_dtype: IntDType,
662    ) -> (FloatTensor<Self>, IntTensor<Self>) {
663        B::float_sort_with_indices(tensor, dim, descending, indices_dtype)
664    }
665
666    fn float_argsort(
667        tensor: FloatTensor<Self>,
668        dim: usize,
669        descending: bool,
670        out_dtype: IntDType,
671    ) -> IntTensor<Self> {
672        B::float_argsort(tensor, dim, descending, out_dtype)
673    }
674
675    fn float_grid_sample_2d(
676        tensor: FloatTensor<Self>,
677        grid: FloatTensor<Self>,
678        options: burn_backend::ops::GridSampleOptions,
679    ) -> FloatTensor<Self> {
680        B::float_grid_sample_2d(tensor, grid, options)
681    }
682
683    fn float_is_nan(tensor: FloatTensor<Self>, out_dtype: BoolDType) -> BoolTensor<Self> {
684        B::float_is_nan(tensor, out_dtype)
685    }
686
687    fn float_is_inf(tensor: FloatTensor<Self>, out_dtype: BoolDType) -> BoolTensor<Self> {
688        B::float_is_inf(tensor, out_dtype)
689    }
690
691    fn float_hypot(lhs: FloatTensor<Self>, rhs: FloatTensor<Self>) -> FloatTensor<Self> {
692        B::float_hypot(lhs, rhs)
693    }
694}
695
696#[cfg(all(test, feature = "capture", feature = "flex"))]
697mod tests {
698    use super::*;
699    use burn_backend::ops::{BoolTensorOps, IntTensorOps};
700    use burn_capture::CaptureDevice;
701
702    #[test]
703    fn capture_tensor_movement_is_one_way() {
704        let source_device = DispatchDevice::Flex(Default::default());
705        let concrete_capture_device = CaptureDevice::default();
706        let capture_device = DispatchDevice::Capture(concrete_capture_device);
707        let float = Dispatch::float_from_data(TensorData::from([1.0f32, 2.0]), &source_device);
708        let int = Dispatch::int_from_data(TensorData::from([1i64, 2]), &source_device);
709
710        let graph = concrete_capture_device
711            .capture_scope(|scope| {
712                let captured_float = Dispatch::float_to_device(float, &capture_device);
713                let captured_float = Dispatch::float_to_device(captured_float, &capture_device);
714                let captured_int = Dispatch::int_to_device(int, &capture_device);
715                let captured_int = Dispatch::int_to_device(captured_int, &capture_device);
716                let float_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
717                    Dispatch::float_to_device(captured_float, &source_device)
718                }));
719                let int_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
720                    Dispatch::int_to_device(captured_int, &source_device)
721                }));
722
723                assert!(float_result.is_err());
724                assert!(int_result.is_err());
725                scope.complete([], [])
726            })
727            .unwrap();
728        assert_eq!(graph.values.len(), 2);
729    }
730
731    #[test]
732    fn initialized_tensors_can_move_between_capture_devices() {
733        let source_device = DispatchDevice::Flex(Default::default());
734        let first = CaptureDevice::default();
735        let second = CaptureDevice::default();
736        let first_dispatch = DispatchDevice::Capture(first);
737        let second_dispatch = DispatchDevice::Capture(second);
738        let float = Dispatch::float_from_data(TensorData::from([1.0f32]), &source_device);
739        let int = Dispatch::int_from_data(TensorData::from([1i64]), &source_device);
740        let bool = Dispatch::bool_from_data(TensorData::from([true]), &source_device);
741
742        let first_graph = first
743            .capture_scope(|first_scope| {
744                let float = Dispatch::float_to_device(float, &first_dispatch);
745                let int = Dispatch::int_to_device(int, &first_dispatch);
746                let bool = Dispatch::bool_to_device(bool, &first_dispatch);
747
748                let second_graph = second
749                    .capture_scope(|second_scope| {
750                        Dispatch::float_to_device(float, &second_dispatch);
751                        Dispatch::int_to_device(int, &second_dispatch);
752                        Dispatch::bool_to_device(bool, &second_dispatch);
753                        second_scope.complete([], [])
754                    })
755                    .unwrap();
756                assert_eq!(second_graph.values.len(), 3);
757
758                first_scope.complete([], [])
759            })
760            .unwrap();
761
762        assert_eq!(first_graph.values.len(), 3);
763    }
764
765    #[test]
766    fn computed_tensors_cannot_move_between_capture_devices() {
767        let source_device = DispatchDevice::Flex(Default::default());
768        let first = CaptureDevice::default();
769        let second = CaptureDevice::default();
770        let first_dispatch = DispatchDevice::Capture(first);
771        let second_dispatch = DispatchDevice::Capture(second);
772        let float = Dispatch::float_from_data(TensorData::from([1.0f32]), &source_device);
773        let int = Dispatch::int_from_data(TensorData::from([1i64]), &source_device);
774        let bool = Dispatch::bool_from_data(TensorData::from([true]), &source_device);
775
776        let first_graph = first
777            .capture_scope(|first_scope| {
778                let float = Dispatch::float_neg(Dispatch::float_to_device(float, &first_dispatch));
779                let int = Dispatch::int_neg(Dispatch::int_to_device(int, &first_dispatch));
780                let bool = Dispatch::bool_not(Dispatch::bool_to_device(bool, &first_dispatch));
781
782                let second_graph = second
783                    .capture_scope(|second_scope| {
784                        let float_result =
785                            std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
786                                Dispatch::float_to_device(float, &second_dispatch)
787                            }));
788                        let int_result =
789                            std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
790                                Dispatch::int_to_device(int, &second_dispatch)
791                            }));
792                        let bool_result =
793                            std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
794                                Dispatch::bool_to_device(bool, &second_dispatch)
795                            }));
796
797                        assert!(float_result.is_err());
798                        assert!(int_result.is_err());
799                        assert!(bool_result.is_err());
800                        second_scope.complete([], [])
801                    })
802                    .unwrap();
803                assert!(second_graph.values.is_empty());
804
805                first_scope.complete([], [])
806            })
807            .unwrap();
808
809        assert_eq!(first_graph.values.len(), 3);
810    }
811}