1use self::unary_basic_int::BasicIntUnaryKind;
2use burn_backend::cubecl::dtype_to_storage_type;
3
4use super::{expand, numeric, permute, unfold};
5use crate::kernel::prng::{random_bernoulli, random_normal, random_uniform};
6use crate::kernel::{
7 BitwiseShlOp, BitwiseShrOp, NumericUnaryOp, NumericUnaryOpFamily, launch_binop_int,
8 launch_scalar_binop_int, launch_unary_numeric, reduce, unary_basic_int,
9};
10use crate::{
11 CubeBackend,
12 kernel::{
13 self,
14 matmul::{MatmulStrategy, matmul},
15 },
16};
17use burn_backend::tensor::{BoolTensor, Device, FloatTensor, IntTensor};
18use burn_backend::{DType, IntDType, Slice, ops::IntTensorOps};
19use burn_backend::{
20 Distribution, ElementConversion, Shape, TensorData, get_or_init_device_settings,
21};
22use burn_backend::{ExecutionError, Scalar};
23use burn_std::{BoolDType, FloatDType};
24use cubecl::frontend::Numeric;
25use cubecl::prelude::*;
26use cubek::reduce::components::instructions::ReduceOperationConfig;
27use std::ops::Range;
28
29impl IntTensorOps<Self> for CubeBackend {
30 fn int_empty(shape: Shape, device: &Device<Self>, dtype: IntDType) -> IntTensor<Self> {
31 let dtype = dtype.into();
32 super::empty(shape, device, dtype)
33 }
34
35 async fn int_into_data(tensor: IntTensor<Self>) -> Result<TensorData, ExecutionError> {
36 super::into_data(tensor).await
37 }
38
39 fn int_from_data(data: TensorData, device: &Device<Self>) -> IntTensor<Self> {
40 match data.dtype() {
41 DType::I64
42 | DType::I32
43 | DType::I16
44 | DType::I8
45 | DType::U64
46 | DType::U32
47 | DType::U16
48 | DType::U8 => super::from_data(data, device),
49 _ => unimplemented!("Unsupported dtype for `int_from_data`"),
50 }
51 }
52
53 fn int_to_device(tensor: IntTensor<Self>, device: &Device<Self>) -> IntTensor<Self> {
54 super::to_device(tensor, device)
55 }
56
57 fn int_reshape(tensor: IntTensor<Self>, shape: Shape) -> IntTensor<Self> {
58 super::reshape(tensor, shape)
59 }
60
61 fn int_slice(tensor: IntTensor<Self>, slices: &[Slice]) -> IntTensor<Self> {
62 let all_steps_one = slices.iter().all(|info| info.step == 1);
64
65 if all_steps_one {
66 let simple_ranges: Vec<Range<usize>> = slices
68 .iter()
69 .enumerate()
70 .map(|(i, slice)| slice.to_range(tensor.meta.shape()[i]))
71 .collect();
72
73 kernel::slice(tensor, &simple_ranges)
74 } else {
75 kernel::slice_with_steps(tensor, slices)
77 }
78 }
79
80 fn int_slice_assign(
81 tensor: IntTensor<Self>,
82 ranges: &[Slice],
83 value: IntTensor<Self>,
84 ) -> IntTensor<Self> {
85 kernel::slice_assign(tensor, ranges, value)
86 }
87
88 fn int_matmul(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
89 let dtype = lhs.dtype;
90 matmul(lhs, rhs, None, MatmulStrategy::default(), dtype).unwrap()
91 }
92
93 fn int_mask_where(
94 tensor: IntTensor<Self>,
95 mask: BoolTensor<Self>,
96 value: IntTensor<Self>,
97 ) -> IntTensor<Self> {
98 let bool_dtype = mask.dtype;
99 kernel::mask_where_auto(tensor, mask, value, bool_dtype)
100 }
101
102 fn int_mask_fill(
103 tensor: IntTensor<Self>,
104 mask: BoolTensor<Self>,
105 value: Scalar,
106 ) -> IntTensor<Self> {
107 let dtype = tensor.dtype;
108 let bool_dtype = mask.dtype;
109 kernel::mask_fill_auto(
110 tensor,
111 mask,
112 InputScalar::new(value, dtype_to_storage_type(dtype)),
113 bool_dtype,
114 )
115 }
116
117 fn int_gather(
118 dim: usize,
119 tensor: IntTensor<Self>,
120 indices: IntTensor<Self>,
121 ) -> IntTensor<Self> {
122 kernel::gather(dim, tensor, indices)
123 }
124
125 fn int_scatter(
126 dim: usize,
127 tensor: IntTensor<Self>,
128 indices: IntTensor<Self>,
129 value: IntTensor<Self>,
130 update: burn_backend::tensor::IndexingUpdateOp,
131 ) -> IntTensor<Self> {
132 match update {
133 burn_backend::tensor::IndexingUpdateOp::Assign => {
134 kernel::scatter_assign(dim, tensor, indices, value)
135 }
136 burn_backend::tensor::IndexingUpdateOp::Add => {
137 kernel::scatter(dim, tensor, indices, value, false)
138 }
139 burn_backend::tensor::IndexingUpdateOp::Mul => {
140 kernel::scatter_mul(dim, tensor, indices, value)
141 }
142 burn_backend::tensor::IndexingUpdateOp::Min => {
143 kernel::scatter_min(dim, tensor, indices, value)
144 }
145 burn_backend::tensor::IndexingUpdateOp::Max => {
146 kernel::scatter_max(dim, tensor, indices, value)
147 }
148 }
149 }
150
151 fn int_scatter_nd(
152 data: IntTensor<Self>,
153 indices: IntTensor<Self>,
154 values: IntTensor<Self>,
155 reduction: burn_backend::tensor::IndexingUpdateOp,
156 ) -> IntTensor<Self> {
157 kernel::scatter_nd(data, indices, values, reduction)
158 }
159
160 fn int_gather_nd(data: IntTensor<Self>, indices: IntTensor<Self>) -> IntTensor<Self> {
161 kernel::gather_nd(data, indices)
162 }
163
164 fn int_select(
165 tensor: IntTensor<Self>,
166 dim: usize,
167 indices: IntTensor<Self>,
168 ) -> IntTensor<Self> {
169 kernel::select(tensor, dim, indices)
170 }
171
172 fn int_select_assign(
173 tensor: IntTensor<Self>,
174 dim: usize,
175 indices: IntTensor<Self>,
176 value: IntTensor<Self>,
177 update: burn_backend::tensor::IndexingUpdateOp,
178 ) -> IntTensor<Self> {
179 match update {
180 burn_backend::tensor::IndexingUpdateOp::Assign => {
181 kernel::select_assign_replace(tensor, dim, indices, value)
182 }
183 burn_backend::tensor::IndexingUpdateOp::Add => {
184 kernel::select_assign(tensor, dim, indices, value, false)
185 }
186 burn_backend::tensor::IndexingUpdateOp::Mul => {
187 kernel::select_assign_mul(tensor, dim, indices, value)
188 }
189 burn_backend::tensor::IndexingUpdateOp::Min => {
190 kernel::select_assign_min(tensor, dim, indices, value)
191 }
192 burn_backend::tensor::IndexingUpdateOp::Max => {
193 kernel::select_assign_max(tensor, dim, indices, value)
194 }
195 }
196 }
197
198 fn int_equal(
199 lhs: IntTensor<Self>,
200 rhs: IntTensor<Self>,
201 out_dtype: BoolDType,
202 ) -> BoolTensor<Self> {
203 kernel::equal(lhs, rhs, out_dtype.into())
204 }
205
206 fn int_not_equal(
207 lhs: IntTensor<Self>,
208 rhs: IntTensor<Self>,
209 out_dtype: BoolDType,
210 ) -> BoolTensor<Self> {
211 kernel::not_equal(lhs, rhs, out_dtype.into())
212 }
213
214 fn int_equal_elem(lhs: IntTensor<Self>, rhs: Scalar, out_dtype: BoolDType) -> BoolTensor<Self> {
215 let dtype = lhs.dtype;
216 kernel::equal_elem(
217 lhs,
218 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
219 out_dtype.into(),
220 )
221 }
222
223 fn int_not_equal_elem(
224 lhs: IntTensor<Self>,
225 rhs: Scalar,
226 out_dtype: BoolDType,
227 ) -> BoolTensor<Self> {
228 let dtype = lhs.dtype;
229 kernel::not_equal_elem(
230 lhs,
231 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
232 out_dtype.into(),
233 )
234 }
235
236 fn int_greater(
237 lhs: IntTensor<Self>,
238 rhs: IntTensor<Self>,
239 out_dtype: BoolDType,
240 ) -> BoolTensor<Self> {
241 kernel::greater(lhs, rhs, out_dtype.into())
242 }
243
244 fn int_greater_elem(
245 lhs: IntTensor<Self>,
246 rhs: Scalar,
247 out_dtype: BoolDType,
248 ) -> BoolTensor<Self> {
249 let dtype = lhs.dtype;
250 kernel::greater_elem(
251 lhs,
252 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
253 out_dtype.into(),
254 )
255 }
256
257 fn int_greater_equal(
258 lhs: IntTensor<Self>,
259 rhs: IntTensor<Self>,
260 out_dtype: BoolDType,
261 ) -> BoolTensor<Self> {
262 kernel::greater_equal(lhs, rhs, out_dtype.into())
263 }
264
265 fn int_greater_equal_elem(
266 lhs: IntTensor<Self>,
267 rhs: Scalar,
268 out_dtype: BoolDType,
269 ) -> BoolTensor<Self> {
270 let dtype = lhs.dtype;
271 kernel::greater_equal_elem(
272 lhs,
273 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
274 out_dtype.into(),
275 )
276 }
277
278 fn int_lower(
279 lhs: IntTensor<Self>,
280 rhs: IntTensor<Self>,
281 out_dtype: BoolDType,
282 ) -> BoolTensor<Self> {
283 kernel::lower(lhs, rhs, out_dtype.into())
284 }
285
286 fn int_lower_elem(lhs: IntTensor<Self>, rhs: Scalar, out_dtype: BoolDType) -> BoolTensor<Self> {
287 let dtype = lhs.dtype;
288 kernel::lower_elem(
289 lhs,
290 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
291 out_dtype.into(),
292 )
293 }
294
295 fn int_lower_equal(
296 lhs: IntTensor<Self>,
297 rhs: IntTensor<Self>,
298 out_dtype: BoolDType,
299 ) -> BoolTensor<Self> {
300 kernel::lower_equal(lhs, rhs, out_dtype.into())
301 }
302
303 fn int_lower_equal_elem(
304 lhs: IntTensor<Self>,
305 rhs: Scalar,
306 out_dtype: BoolDType,
307 ) -> BoolTensor<Self> {
308 let dtype = lhs.dtype;
309 kernel::lower_equal_elem(
310 lhs,
311 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
312 out_dtype.into(),
313 )
314 }
315
316 fn int_add(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
317 numeric::add(lhs, rhs)
318 }
319
320 fn int_add_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
321 let dtype = lhs.dtype;
322 numeric::add_scalar(lhs, InputScalar::new(rhs, dtype_to_storage_type(dtype)))
323 }
324
325 fn int_sub(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
326 numeric::sub(lhs, rhs)
327 }
328
329 fn int_sub_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
330 let dtype = lhs.dtype;
331 numeric::sub_scalar(lhs, InputScalar::new(rhs, dtype_to_storage_type(dtype)))
332 }
333
334 fn int_mul(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
335 numeric::mul(lhs, rhs)
336 }
337
338 fn int_mul_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
339 let dtype = lhs.dtype;
340 numeric::mul_scalar(lhs, InputScalar::new(rhs, dtype_to_storage_type(dtype)))
341 }
342
343 fn int_div(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
344 numeric::div(lhs, rhs)
345 }
346
347 fn int_div_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
348 let dtype = lhs.dtype;
349 numeric::div_scalar(lhs, InputScalar::new(rhs, dtype_to_storage_type(dtype)))
350 }
351
352 fn int_remainder(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
353 numeric::remainder(lhs, rhs)
354 }
355
356 fn int_remainder_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
357 let dtype = lhs.dtype;
358 numeric::remainder_scalar(lhs, InputScalar::new(rhs, dtype_to_storage_type(dtype)))
359 }
360
361 fn int_zeros(shape: Shape, device: &Device<Self>, dtype: IntDType) -> IntTensor<Self> {
362 let dtype = dtype.into();
363 numeric::zeros(device.clone(), shape, dtype)
364 }
365
366 fn int_ones(shape: Shape, device: &Device<Self>, dtype: IntDType) -> IntTensor<Self> {
367 let dtype = dtype.into();
368 numeric::ones(device.clone(), shape, dtype)
369 }
370
371 fn int_full(
372 shape: Shape,
373 fill_value: Scalar,
374 device: &Device<Self>,
375 dtype: IntDType,
376 ) -> IntTensor<Self> {
377 let dtype: DType = dtype.into();
378 let client = device.client();
379 numeric::full_device_dtype(
380 client,
381 shape,
382 device.clone(),
383 InputScalar::new(fill_value, dtype_to_storage_type(dtype)),
384 dtype,
385 )
386 }
387
388 fn int_sum(tensor: IntTensor<Self>) -> IntTensor<Self> {
389 reduce::sum_fallback(tensor, Default::default()).unwrap()
390 }
391
392 fn int_sum_dim(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
393 reduce::reduce_dim(
394 tensor,
395 None,
396 dim,
397 Default::default(),
398 ReduceOperationConfig::Sum,
399 )
400 .unwrap()
401 }
402
403 fn int_any(tensor: IntTensor<Self>, out_dtype: BoolDType) -> BoolTensor<Self> {
404 reduce::reduce_logical(tensor, None, ReduceOperationConfig::Any, out_dtype)
405 }
406
407 fn int_any_dim(tensor: IntTensor<Self>, dim: usize, out_dtype: BoolDType) -> BoolTensor<Self> {
408 reduce::reduce_logical(tensor, Some(dim), ReduceOperationConfig::Any, out_dtype)
409 }
410
411 fn int_all(tensor: IntTensor<Self>, out_dtype: BoolDType) -> BoolTensor<Self> {
412 reduce::reduce_logical(tensor, None, ReduceOperationConfig::All, out_dtype)
413 }
414
415 fn int_all_dim(tensor: IntTensor<Self>, dim: usize, out_dtype: BoolDType) -> BoolTensor<Self> {
416 reduce::reduce_logical(tensor, Some(dim), ReduceOperationConfig::All, out_dtype)
417 }
418
419 fn int_prod(tensor: IntTensor<Self>) -> IntTensor<Self> {
420 reduce::reduce(
421 tensor,
422 None,
423 Default::default(),
424 ReduceOperationConfig::Prod,
425 )
426 .unwrap()
427 }
428
429 fn int_prod_dim(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
430 reduce::reduce_dim(
431 tensor,
432 None,
433 dim,
434 Default::default(),
435 ReduceOperationConfig::Prod,
436 )
437 .unwrap()
438 }
439
440 fn int_max(tensor: IntTensor<Self>) -> IntTensor<Self> {
441 reduce::reduce(tensor, None, Default::default(), ReduceOperationConfig::Max).unwrap()
442 }
443
444 fn int_max_dim(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
445 reduce::reduce_dim(
446 tensor,
447 None,
448 dim,
449 Default::default(),
450 ReduceOperationConfig::Max,
451 )
452 .unwrap()
453 }
454
455 fn int_topk(tensor: IntTensor<Self>, dim: usize, k: usize) -> IntTensor<Self> {
456 reduce::reduce_dim(
457 tensor,
458 None,
459 dim,
460 Default::default(),
461 ReduceOperationConfig::TopK(k),
462 )
463 .unwrap()
464 }
465
466 fn int_topk_with_indices(
467 tensor: IntTensor<Self>,
468 dim: usize,
469 k: usize,
470 ) -> (IntTensor<Self>, IntTensor<Self>) {
471 let dtype = tensor.dtype;
475 reduce::reduce_dim_with_indices(
476 tensor,
477 dtype,
478 dim,
479 Default::default(),
480 ReduceOperationConfig::TopK(k),
481 )
482 .unwrap()
483 }
484
485 fn int_max_dim_with_indices(
486 tensor: IntTensor<Self>,
487 dim: usize,
488 ) -> (IntTensor<Self>, IntTensor<Self>) {
489 let dtype = tensor.dtype;
491 reduce::reduce_dim_with_indices(
492 tensor,
493 dtype,
494 dim,
495 Default::default(),
496 ReduceOperationConfig::Max,
497 )
498 .unwrap()
499 }
500
501 fn int_min_dim_with_indices(
502 tensor: IntTensor<Self>,
503 dim: usize,
504 ) -> (IntTensor<Self>, IntTensor<Self>) {
505 let dtype = tensor.dtype;
507 reduce::reduce_dim_with_indices(
508 tensor,
509 dtype,
510 dim,
511 Default::default(),
512 ReduceOperationConfig::Min,
513 )
514 .unwrap()
515 }
516
517 fn int_max_abs(tensor: IntTensor<Self>) -> IntTensor<Self> {
518 reduce::reduce(
519 tensor,
520 None,
521 Default::default(),
522 ReduceOperationConfig::MaxAbs,
523 )
524 .unwrap()
525 }
526
527 fn int_max_abs_dim(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
528 reduce::reduce_dim(
529 tensor,
530 None,
531 dim,
532 Default::default(),
533 ReduceOperationConfig::MaxAbs,
534 )
535 .unwrap()
536 }
537
538 fn int_min(tensor: IntTensor<Self>) -> IntTensor<Self> {
539 reduce::reduce(tensor, None, Default::default(), ReduceOperationConfig::Min).unwrap()
540 }
541
542 fn int_min_dim(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
543 reduce::reduce_dim(
544 tensor,
545 None,
546 dim,
547 Default::default(),
548 ReduceOperationConfig::Min,
549 )
550 .unwrap()
551 }
552
553 fn int_mean_dim(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
554 reduce::reduce_dim(
555 tensor,
556 None,
557 dim,
558 Default::default(),
559 ReduceOperationConfig::Mean,
560 )
561 .unwrap()
562 }
563
564 fn int_cumsum(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
565 numeric::cumsum(tensor, dim)
566 }
567
568 fn int_cumprod(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
569 numeric::cumprod(tensor, dim)
570 }
571
572 fn int_cummin(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
573 numeric::cummin(tensor, dim)
574 }
575
576 fn int_cummax(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
577 numeric::cummax(tensor, dim)
578 }
579
580 fn int_argmax(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
581 let dtype = tensor.dtype;
582 reduce::reduce_dim(
583 tensor,
584 Some(dtype),
585 dim,
586 Default::default(),
587 ReduceOperationConfig::ArgMax,
588 )
589 .unwrap()
590 }
591
592 fn int_argtopk(tensor: IntTensor<Self>, dim: usize, k: usize) -> IntTensor<Self> {
593 let dtype = tensor.dtype;
594 reduce::reduce_dim(
595 tensor,
596 Some(dtype),
597 dim,
598 Default::default(),
599 ReduceOperationConfig::ArgTopK(k),
600 )
601 .unwrap()
602 }
603
604 fn int_argmin(tensor: IntTensor<Self>, dim: usize) -> IntTensor<Self> {
605 let dtype = tensor.dtype;
606 reduce::reduce_dim(
607 tensor,
608 Some(dtype),
609 dim,
610 Default::default(),
611 ReduceOperationConfig::ArgMin,
612 )
613 .unwrap()
614 }
615
616 fn int_clamp(tensor: IntTensor<Self>, min: Scalar, max: Scalar) -> IntTensor<Self> {
617 let dtype = tensor.dtype;
618 kernel::clamp_int(
619 tensor,
620 InputScalar::new(min, dtype_to_storage_type(dtype)),
621 InputScalar::new(max, dtype_to_storage_type(dtype)),
622 )
623 }
624
625 fn int_abs(tensor: IntTensor<Self>) -> IntTensor<Self> {
626 struct Abs;
627
628 #[cube]
629 impl<T: Numeric, N: Size> NumericUnaryOp<T, N> for Abs {
630 type Options = ();
631
632 fn execute(input: Vector<T, N>, _options: &Self::Options) -> Vector<T, N> {
633 Vector::abs(input)
634 }
635 }
636
637 impl NumericUnaryOpFamily for Abs {
638 type Options = ();
639 type Unary<T: Numeric, N: Size> = Self;
640 }
641
642 launch_unary_numeric::<Abs, _>(tensor, |_| ())
643 }
644
645 fn int_sign(tensor: IntTensor<Self>) -> IntTensor<Self> {
646 unary_basic_int::launch::<_>(tensor, |_| BasicIntUnaryKind::Sign)
647 }
648
649 fn int_into_float(tensor: IntTensor<Self>, out_dtype: FloatDType) -> FloatTensor<Self> {
650 kernel::cast(tensor, out_dtype.into())
651 }
652
653 fn int_swap_dims(mut tensor: IntTensor<Self>, dim1: usize, dim2: usize) -> IntTensor<Self> {
654 tensor.meta.swap(dim1, dim2);
655
656 tensor
657 }
658
659 fn int_repeat_dim(tensor: IntTensor<Self>, dim: usize, times: usize) -> IntTensor<Self> {
660 kernel::repeat_dim(tensor, dim, times)
661 }
662
663 fn int_random(
664 shape: Shape,
665 distribution: Distribution,
666 device: &Device<Self>,
667 dtype: IntDType,
668 ) -> IntTensor<Self> {
669 let dtype = dtype.into();
670 match distribution {
671 Distribution::Default => random_uniform(shape, device, 0., 255., dtype),
672 Distribution::Uniform(low, high) => {
673 random_uniform(shape, device, low.elem(), high.elem(), dtype)
674 }
675 Distribution::Bernoulli(prob) => random_bernoulli(shape, device, prob as f32, dtype),
676 Distribution::Normal(mean, std) => {
677 random_normal(shape, device, mean.elem(), std.elem(), dtype)
678 }
679 }
680 }
681
682 fn int_permute(tensor: IntTensor<Self>, axes: &[usize]) -> IntTensor<Self> {
683 permute(tensor, axes)
684 }
685
686 fn int_expand(tensor: IntTensor<Self>, shape: Shape) -> IntTensor<Self> {
687 expand(tensor, shape)
688 }
689
690 fn int_flip(tensor: IntTensor<Self>, axes: &[usize]) -> IntTensor<Self> {
691 let bool_dtype = get_or_init_device_settings::<Self>(&tensor.device).bool_dtype;
692 kernel::flip(tensor, axes, bool_dtype.into())
693 }
694
695 fn bitwise_and(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
696 numeric::bitwise_and(lhs, rhs)
697 }
698
699 fn bitwise_and_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
700 let dtype = lhs.dtype;
701 numeric::bitwise_and_scalar(lhs, InputScalar::new(rhs, dtype_to_storage_type(dtype)))
702 }
703
704 fn bitwise_or(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
705 numeric::bitwise_or(lhs, rhs)
706 }
707
708 fn bitwise_or_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
709 let dtype = lhs.dtype;
710 numeric::bitwise_or_scalar(lhs, InputScalar::new(rhs, dtype_to_storage_type(dtype)))
711 }
712
713 fn bitwise_xor(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
714 numeric::bitwise_xor(lhs, rhs)
715 }
716
717 fn bitwise_xor_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
718 let dtype = lhs.dtype;
719 numeric::bitwise_xor_scalar(lhs, InputScalar::new(rhs, dtype_to_storage_type(dtype)))
720 }
721
722 fn bitwise_not(tensor: IntTensor<Self>) -> IntTensor<Self> {
723 unary_basic_int::launch::<_>(tensor, |_| BasicIntUnaryKind::BitwiseNot)
724 }
725
726 fn bitwise_left_shift(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
727 launch_binop_int::<kernel::BitwiseShlOp>(lhs, rhs)
728 }
729
730 fn bitwise_left_shift_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
731 let dtype = lhs.dtype;
732 launch_scalar_binop_int::<BitwiseShlOp>(
733 lhs,
734 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
735 )
736 }
737
738 fn bitwise_right_shift(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
739 launch_binop_int::<BitwiseShrOp>(lhs, rhs)
740 }
741
742 fn bitwise_right_shift_scalar(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
743 let dtype = lhs.dtype;
744 launch_scalar_binop_int::<BitwiseShrOp>(
745 lhs,
746 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
747 )
748 }
749
750 fn int_cast(tensor: IntTensor<Self>, dtype: IntDType) -> IntTensor<Self> {
751 kernel::cast(tensor, dtype.into())
752 }
753
754 fn int_unfold(
755 tensor: FloatTensor<Self>,
756 dim: usize,
757 size: usize,
758 step: usize,
759 ) -> FloatTensor<Self> {
760 unfold(tensor, dim, size, step)
761 }
762
763 fn int_powi(lhs: IntTensor<Self>, rhs: IntTensor<Self>) -> IntTensor<Self> {
764 launch_binop_int::<kernel::PowiOp>(lhs, rhs)
765 }
766
767 fn int_powi_scalar_impl(lhs: IntTensor<Self>, rhs: Scalar) -> IntTensor<Self> {
768 let dtype = lhs.dtype;
769 launch_scalar_binop_int::<kernel::PowiOp>(
770 lhs,
771 InputScalar::new(rhs, dtype_to_storage_type(dtype)),
772 )
773 }
774}