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