burn_backend/backend/ops/int_tensor.rs
1use super::cat::cat_with_slice_assign;
2use super::repeat_dim::repeat_with_slice_assign;
3use super::sort::{argsort, sort, sort_with_indices};
4use crate::tensor::{BoolTensor, Device, FloatTensor, IntTensor};
5use crate::{Backend, Distribution, TensorData, TensorMetadata};
6use crate::{ExecutionError, Scalar, get_device_settings};
7use alloc::vec::Vec;
8use burn_std::reader::try_read_sync;
9use burn_std::{BoolDType, FloatDType, IntDType, Shape, Slice};
10use core::ops::Range;
11
12/// Int Tensor API for basic and numeric operations, see
13#[cfg_attr(doc, doc = crate::doc_tensor!())]
14#[cfg_attr(not(doc), doc = "`Tensor`")]
15/// for documentation on each function.
16pub trait IntTensorOps<B: Backend> {
17 /// Creates a new int tensor.
18 ///
19 /// # Arguments
20 ///
21 /// * `shape` - The shape of the tensor.
22 /// * `device` - The device to create the tensor on.
23 /// * `dtype` - The target data type.
24 ///
25 /// # Returns
26 ///
27 /// The integer tensor with the given shape.
28 fn int_empty(shape: Shape, device: &Device<B>, dtype: IntDType) -> IntTensor<B>;
29
30 /// Converts the tensor to a data structure.
31 ///
32 /// # Arguments
33 ///
34 /// * `tensor` - The tensor.
35 ///
36 /// # Returns
37 ///
38 /// The data structure with the tensor's data.
39 fn int_into_data(
40 tensor: IntTensor<B>,
41 ) -> impl Future<Output = Result<TensorData, ExecutionError>> + Send;
42
43 /// Creates a tensor from the data structure.
44 ///
45 /// # Arguments
46 ///
47 /// * `data` - The data structure.
48 /// * `device` - The device to create the tensor on.
49 ///
50 /// # Returns
51 ///
52 /// The tensor with the data.
53 fn int_from_data(data: TensorData, device: &Device<B>) -> IntTensor<B>;
54
55 /// Moves the tensor to the given device.
56 fn int_to_device(tensor: IntTensor<B>, device: &Device<B>) -> IntTensor<B>;
57
58 /// Reshapes the tensor.
59 ///
60 /// # Arguments
61 ///
62 /// * `tensor` - The tensor.
63 /// * `shape` - The new shape.
64 ///
65 /// # Returns
66 ///
67 /// The tensor with the new shape.
68 fn int_reshape(tensor: IntTensor<B>, shape: Shape) -> IntTensor<B>;
69
70 /// Gets the element at the given indices.
71 ///
72 /// # Arguments
73 ///
74 /// * `tensor` - The tensor.
75 /// * `slices` - The slices specifying ranges and steps for each dimension.
76 ///
77 /// # Returns
78 ///
79 /// The elements at the given indices.
80 ///
81 /// # Note
82 ///
83 /// Empty slices (where start >= end) are handled at the high-level tensor API and will not
84 /// be passed to this method. Backend implementations do not need to handle empty slices.
85 fn int_slice(tensor: IntTensor<B>, slices: &[Slice]) -> IntTensor<B>;
86
87 /// Sets the values in the tensor for the given ranges.
88 ///
89 /// # Arguments
90 ///
91 /// * `tensor` - The tensor.
92 /// * `ranges` - The ranges to set the values for.
93 ///
94 /// # Returns
95 ///
96 /// The tensor with the values set for the given ranges.
97 ///
98 /// # Note
99 ///
100 /// Empty slice assignments (where any slice range produces 0 elements) are handled at the
101 /// high-level tensor API and will not be passed to this method. Backend implementations do
102 /// not need to handle empty slice assignments.
103 fn int_slice_assign(
104 tensor: IntTensor<B>,
105 slices: &[Slice],
106 value: IntTensor<B>,
107 ) -> IntTensor<B>;
108
109 /// Converts int tensor to float tensor.
110 ///
111 /// # Arguments
112 ///
113 /// * `tensor` - The tensor.
114 /// * `out_dtype` - The output tensor dtype.
115 ///
116 /// # Returns
117 ///
118 /// The int tensor with the same data as the float tensor.
119 fn int_into_float(tensor: IntTensor<B>, out_dtype: FloatDType) -> FloatTensor<B>;
120
121 /// Fills the tensor with values from the value tensor if the mask is true at the given
122 /// indices.
123 ///
124 /// # Arguments
125 ///
126 /// * `tensor` - The tensor.
127 /// * `mask` - The mask.
128 /// * `value` - The value tensor.
129 ///
130 /// # Returns
131 ///
132 /// The tensor with the values filled.
133 fn int_mask_where(
134 tensor: IntTensor<B>,
135 mask: BoolTensor<B>,
136 value: IntTensor<B>,
137 ) -> IntTensor<B>;
138
139 /// Fills the tensor with the given value if the mask is true at the given indices.
140 ///
141 /// # Arguments
142 ///
143 /// * `tensor` - The tensor.
144 /// * `mask` - The mask.
145 /// * `value` - The value.
146 ///
147 /// # Returns
148 ///
149 /// The tensor with the values filled.
150 fn int_mask_fill(tensor: IntTensor<B>, mask: BoolTensor<B>, value: Scalar) -> IntTensor<B>;
151
152 /// Gather elements from the tensor at the given indices.
153 ///
154 /// # Arguments
155 ///
156 /// * `dim` - The dimension to gather from.
157 /// * `tensor` - The tensor.
158 /// * `indices` - The indices.
159 fn int_gather(dim: usize, tensor: IntTensor<B>, indices: IntTensor<B>) -> IntTensor<B>;
160
161 /// Scatter a given value to the tensor at the given indices using sum reduction.
162 ///
163 /// # Arguments
164 ///
165 /// * `dim` - The dimension to scatter to.
166 /// * `tensor` - The tensor.
167 /// * `indices` - The indices.
168 /// * `value` - The value.
169 ///
170 /// # Returns
171 ///
172 /// The tensor with the values scattered.
173 fn int_scatter_add(
174 dim: usize,
175 tensor: IntTensor<B>,
176 indices: IntTensor<B>,
177 value: IntTensor<B>,
178 ) -> IntTensor<B>;
179
180 /// Multi-dimensional scatter for int tensors.
181 fn int_scatter_nd(
182 _data: IntTensor<B>,
183 _indices: IntTensor<B>,
184 _values: IntTensor<B>,
185 _reduction: crate::tensor::IndexingUpdateOp,
186 ) -> IntTensor<B> {
187 unimplemented!("int_scatter_nd is not implemented for this backend")
188 }
189
190 /// Multi-dimensional gather for int tensors.
191 fn int_gather_nd(_data: IntTensor<B>, _indices: IntTensor<B>) -> IntTensor<B> {
192 unimplemented!("int_gather_nd is not implemented for this backend")
193 }
194
195 /// Select tensor elements along the given dimension corresponding to the given indices.
196 ///
197 /// # Arguments
198 ///
199 /// * `tensor` - The tensor.
200 /// * `dim` - The dimension to select from.
201 /// * `indices` - The indices.
202 ///
203 /// # Returns
204 ///
205 /// The tensor with the selected elements.
206 fn int_select(tensor: IntTensor<B>, dim: usize, indices: IntTensor<B>) -> IntTensor<B>;
207
208 /// Assign the selected elements along the given dimension corresponding to the given indices
209 /// to the given value using sum reduction.
210 ///
211 /// # Arguments
212 ///
213 /// * `tensor` - The tensor.
214 /// * `dim` - The dimension to select from.
215 /// * `indices` - The indices.
216 /// * `value` - The value.
217 ///
218 /// # Returns
219 ///
220 /// The tensor with the selected elements assigned to the given value.
221 fn int_select_add(
222 tensor: IntTensor<B>,
223 dim: usize,
224 indices: IntTensor<B>,
225 value: IntTensor<B>,
226 ) -> IntTensor<B>;
227
228 /// Repeats the tensor along the given dimension the given number of times.
229 ///
230 /// # Arguments
231 ///
232 /// * `tensor` - The tensor.
233 /// * `dim` - The dimension to repeat.
234 /// * `times` - The number of times to repeat.
235 ///
236 /// # Returns
237 ///
238 /// The tensor with the given dimension repeated the given number of times.
239 fn int_repeat_dim(tensor: IntTensor<B>, dim: usize, times: usize) -> IntTensor<B> {
240 let device = tensor.device();
241 repeat_with_slice_assign::<B, _, _, _>(
242 tensor,
243 dim,
244 times,
245 device,
246 |shape, device, dtype| B::int_empty(shape, device, dtype.into()),
247 B::int_slice_assign,
248 )
249 }
250
251 /// Concatenates the given tensors along the given dimension.
252 ///
253 /// # Arguments
254 ///
255 /// * `tensors` - The tensors.
256 /// * `dim` - The dimension to concatenate along.
257 ///
258 /// # Returns
259 ///
260 /// The concatenated tensor.
261 ///
262 /// # Note
263 ///
264 /// Empty tensors (where the concatenation dimension has size 0) are filtered out at the
265 /// high-level tensor API and will not be passed to this method. Backend implementations do
266 /// not need to handle empty tensors.
267 fn int_cat(tensors: Vec<IntTensor<B>>, dim: usize) -> IntTensor<B> {
268 let first_tensor = tensors.first().expect("Tensors should not be empty");
269 let device = first_tensor.device();
270 cat_with_slice_assign::<B, _, _, _>(
271 tensors,
272 dim,
273 device,
274 |shape, device, dtype| B::int_empty(shape, device, dtype.into()),
275 B::int_slice_assign,
276 )
277 }
278
279 /// Element-wise equality comparison.
280 ///
281 /// # Arguments
282 ///
283 /// * `lhs` - The left-hand side tensor.
284 /// * `rhs` - The right-hand side tensor.
285 /// * `out_dtype` - The output tensor dtype.
286 ///
287 /// # Returns
288 ///
289 /// The boolean tensor with the result of the comparison.
290 fn int_equal(lhs: IntTensor<B>, rhs: IntTensor<B>, out_dtype: BoolDType) -> BoolTensor<B>;
291
292 /// Element-wise non-equality comparison.
293 ///
294 /// # Arguments
295 ///
296 /// * `lhs` - The left-hand side tensor.
297 /// * `rhs` - The right-hand side tensor.
298 /// * `out_dtype` - The output tensor dtype.
299 ///
300 /// # Returns
301 ///
302 /// The boolean tensor with the result of the comparison.
303 fn int_not_equal(lhs: IntTensor<B>, rhs: IntTensor<B>, out_dtype: BoolDType) -> BoolTensor<B> {
304 let equal_tensor = B::int_equal(lhs, rhs, out_dtype);
305 B::bool_not(equal_tensor)
306 }
307
308 /// Element-wise equality comparison with a scalar.
309 ///
310 /// # Arguments
311 ///
312 /// * `lhs` - The left-hand side tensor.
313 /// * `rhs` - The right-hand side scalar.
314 /// * `out_dtype` - The output tensor dtype.
315 ///
316 /// # Returns
317 ///
318 /// The boolean tensor with the result of the comparison.
319 fn int_equal_elem(lhs: IntTensor<B>, rhs: Scalar, out_dtype: BoolDType) -> BoolTensor<B>;
320
321 /// Element-wise non-equality comparison with a scalar.
322 ///
323 /// # Arguments
324 ///
325 /// * `lhs` - The left-hand side tensor.
326 /// * `rhs` - The right-hand side scalar.
327 /// * `out_dtype` - The output tensor dtype.
328 ///
329 /// # Returns
330 ///
331 /// The boolean tensor with the result of the comparison.
332 fn int_not_equal_elem(lhs: IntTensor<B>, rhs: Scalar, out_dtype: BoolDType) -> BoolTensor<B> {
333 let equal_tensor = B::int_equal_elem(lhs, rhs, out_dtype);
334 B::bool_not(equal_tensor)
335 }
336
337 /// Element-wise greater than comparison.
338 ///
339 /// # Arguments
340 ///
341 /// * `lhs` - The left-hand side tensor.
342 /// * `rhs` - The right-hand side tensor.
343 /// * `out_dtype` - The output tensor dtype.
344 ///
345 /// # Returns
346 ///
347 /// The boolean tensor with the result of the comparison.
348 fn int_greater(lhs: IntTensor<B>, rhs: IntTensor<B>, out_dtype: BoolDType) -> BoolTensor<B>;
349
350 /// Element-wise greater than comparison with a scalar.
351 ///
352 /// # Arguments
353 ///
354 /// * `lhs` - The left-hand side tensor.
355 /// * `rhs` - The right-hand side scalar.
356 /// * `out_dtype` - The output tensor dtype.
357 ///
358 /// # Returns
359 ///
360 /// The boolean tensor with the result of the comparison.
361 fn int_greater_elem(lhs: IntTensor<B>, rhs: Scalar, out_dtype: BoolDType) -> BoolTensor<B>;
362
363 /// Element-wise greater than or equal comparison.
364 ///
365 /// # Arguments
366 ///
367 /// * `lhs` - The left-hand side tensor.
368 /// * `rhs` - The right-hand side tensor.
369 /// * `out_dtype` - The output tensor dtype.
370 ///
371 /// # Returns
372 ///
373 /// The boolean tensor with the result of the comparison.
374 fn int_greater_equal(
375 lhs: IntTensor<B>,
376 rhs: IntTensor<B>,
377 out_dtype: BoolDType,
378 ) -> BoolTensor<B>;
379
380 /// Element-wise greater than or equal comparison with a scalar.
381 ///
382 /// # Arguments
383 ///
384 /// * `lhs` - The left-hand side tensor.
385 /// * `rhs` - The right-hand side scalar.
386 /// * `out_dtype` - The output tensor dtype.
387 ///
388 /// # Returns
389 ///
390 /// The boolean tensor with the result of the comparison.
391 fn int_greater_equal_elem(
392 lhs: IntTensor<B>,
393 rhs: Scalar,
394 out_dtype: BoolDType,
395 ) -> BoolTensor<B>;
396
397 /// Element-wise less than comparison.
398 ///
399 /// # Arguments
400 ///
401 /// * `lhs` - The left-hand side tensor.
402 /// * `rhs` - The right-hand side tensor.
403 /// * `out_dtype` - The output tensor dtype.
404 ///
405 /// # Returns
406 ///
407 /// The boolean tensor with the result of the comparison.
408 fn int_lower(lhs: IntTensor<B>, rhs: IntTensor<B>, out_dtype: BoolDType) -> BoolTensor<B>;
409
410 /// Element-wise less than comparison with a scalar.
411 ///
412 /// # Arguments
413 ///
414 /// * `lhs` - The left-hand side tensor.
415 /// * `rhs` - The right-hand side scalar.
416 /// * `out_dtype` - The output tensor dtype.
417 ///
418 /// # Returns
419 ///
420 /// The boolean tensor with the result of the comparison.
421 fn int_lower_elem(lhs: IntTensor<B>, rhs: Scalar, out_dtype: BoolDType) -> BoolTensor<B>;
422
423 /// Element-wise less than or equal comparison.
424 ///
425 /// # Arguments
426 ///
427 /// * `lhs` - The left-hand side tensor.
428 /// * `rhs` - The right-hand side tensor.
429 /// * `out_dtype` - The output tensor dtype.
430 ///
431 /// # Returns
432 ///
433 /// The boolean tensor with the result of the comparison.
434 fn int_lower_equal(lhs: IntTensor<B>, rhs: IntTensor<B>, out_dtype: BoolDType)
435 -> BoolTensor<B>;
436
437 /// Element-wise less than or equal comparison with a scalar.
438 ///
439 /// # Arguments
440 ///
441 /// * `lhs` - The left-hand side tensor.
442 /// * `rhs` - The right-hand side scalar.
443 /// * `out_dtype` - The output tensor dtype.
444 ///
445 /// # Returns
446 ///
447 /// The boolean tensor with the result of the comparison.
448 fn int_lower_equal_elem(lhs: IntTensor<B>, rhs: Scalar, out_dtype: BoolDType) -> BoolTensor<B>;
449
450 // ==== NUMERIC ==== //
451
452 /// Element-wise addition.
453 ///
454 /// # Arguments
455 ///
456 /// * `lhs` - The left-hand side tensor.
457 /// * `rhs` - The right-hand side tensor.
458 ///
459 /// # Returns
460 ///
461 /// The result of the addition.
462 fn int_add(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
463
464 /// Element-wise addition with a scalar.
465 ///
466 /// # Arguments
467 ///
468 /// * `lhs` - The left-hand side tensor.
469 /// * `rhs` - The right-hand side scalar.
470 ///
471 /// # Returns
472 ///
473 /// The result of the addition.
474 fn int_add_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
475
476 /// Element-wise square with a IntTensor.
477 ///
478 /// # Arguments
479 ///
480 /// * `tensor` - The IntTensor.
481 ///
482 /// # Returns
483 ///
484 /// The element-wise square of `tensor`.
485 fn int_square(tensor: IntTensor<B>) -> IntTensor<B> {
486 Self::int_powi_scalar(tensor, Scalar::from(2))
487 }
488
489 /// Element-wise power with a IntTensor.
490 ///
491 /// # Arguments
492 ///
493 /// * `lhs` - The left-hand side IntTensor.
494 /// * `rhs` - The right-hand side IntTensor.
495 ///
496 /// # Returns
497 ///
498 /// The elements of `lhs` raised to the power of the elements of `rhs`.
499 fn int_powi(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B> {
500 let dtype = lhs.dtype();
501 let float_dtype = get_device_settings::<B>(&lhs.device()).float_dtype;
502 B::float_into_int(
503 B::float_powi(B::int_into_float(lhs, float_dtype), rhs),
504 dtype.into(),
505 )
506 }
507
508 /// Element-wise power with a scalar.
509 ///
510 /// # Backend Implementors Note
511 ///
512 /// A number of common exponent cases can be implemented with operations
513 /// which are much cheaper than generic exponentiation.
514 ///
515 /// This (`Backend` impl overridable) operation handles generic optimizations
516 /// for several common integer exponent cases; and then dispatches to
517 /// the (`Backend` impl overridable) [`Self::int_powi_scalar_impl`]
518 /// operation to handle the generic case.
519 ///
520 /// # Arguments
521 ///
522 /// * `lhs` - The left-hand side tensor.
523 /// * `rhs` - The right-hand side scalar.
524 ///
525 /// # Returns
526 ///
527 /// The elements of `lhs` raised to the value of `rhs`.
528 fn int_powi_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B> {
529 let exp = rhs.elem::<i32>();
530 match exp {
531 0 => Self::int_ones(lhs.shape(), &lhs.device(), lhs.dtype().into()),
532 1 => lhs,
533 2 => Self::int_mul(lhs.clone(), lhs),
534 _ => Self::int_powi_scalar_impl(lhs, rhs),
535 }
536 }
537
538 /// Element-wise power with a scalar.
539 ///
540 /// # Backend Implementors Note
541 ///
542 /// This is the generic implementation of integer exponentiation
543 /// called by [`Self::int_powi_scalar`] in the fallback case.
544 ///
545 /// By default, this performs a relatively expensive conversion to float,
546 /// exponentiation in float, and conversion back to int.
547 /// This reduces the minimal operation set for `Backend`s,
548 /// at the cost of performance.
549 ///
550 /// This is a good target for specialized optimizations in `Backend` implementations.
551 ///
552 /// As a general rule, this should not be called directly.
553 ///
554 /// # Arguments
555 ///
556 /// * `lhs` - The left-hand side tensor.
557 /// * `rhs` - The right-hand side scalar.
558 ///
559 /// # Returns
560 ///
561 /// The elements of `lhs` raised to the value of `rhs`.
562 fn int_powi_scalar_impl(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B> {
563 let dtype = lhs.dtype();
564 let float_dtype = get_device_settings::<B>(&lhs.device()).float_dtype;
565 B::float_into_int(
566 B::float_powi_scalar_impl(B::int_into_float(lhs, float_dtype), rhs),
567 dtype.into(),
568 )
569 }
570
571 /// Clamps a tensor under a minimum value.
572 ///
573 /// # Arguments
574 ///
575 /// * `tensor` - The tensor to clamp.
576 /// * `min` - The minimum value.
577 ///
578 /// # Returns
579 ///
580 /// The clamped tensor.
581 fn int_clamp_min(tensor: IntTensor<B>, min: Scalar) -> IntTensor<B> {
582 let dtype = get_device_settings::<B>(&tensor.device()).bool_dtype;
583 let mask = Self::int_lower_elem(tensor.clone(), min, dtype);
584 Self::int_mask_fill(tensor, mask, min)
585 }
586
587 /// Clamps a tensor over a maximum value.
588 ///
589 /// # Arguments
590 ///
591 /// * `tensor` - The tensor to clamp.
592 /// * `max` - The maximum value.
593 ///
594 /// # Returns
595 ///
596 /// The clamped tensor.
597 fn int_clamp_max(tensor: IntTensor<B>, max: Scalar) -> IntTensor<B> {
598 let dtype = get_device_settings::<B>(&tensor.device()).bool_dtype;
599 let mask = Self::int_greater_elem(tensor.clone(), max, dtype);
600 Self::int_mask_fill(tensor, mask, max)
601 }
602
603 /// Clamps a tensor between a minimum and maximum value.
604 ///
605 /// # Arguments
606 ///
607 /// * `tensor` - The tensor to clamp.
608 /// * `min` - The minimum value.
609 /// * `max` - The maximum value.
610 ///
611 /// # Returns
612 ///
613 /// The clamped tensor.
614 fn int_clamp(tensor: IntTensor<B>, min: Scalar, max: Scalar) -> IntTensor<B> {
615 Self::int_clamp_min(Self::int_clamp_max(tensor, max), min)
616 }
617
618 /// Element-wise subtraction.
619 ///
620 /// # Arguments
621 ///
622 /// * `lhs` - The left-hand side tensor.
623 /// * `rhs` - The right-hand side tensor.
624 ///
625 /// # Returns
626 ///
627 /// The result of the subtraction.
628 fn int_sub(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
629
630 /// Element-wise subtraction with a scalar.
631 ///
632 /// # Arguments
633 ///
634 /// * `lhs` - The left-hand side tensor.
635 /// * `rhs` - The right-hand side scalar.
636 ///
637 /// # Returns
638 ///
639 /// The result of the subtraction.
640 fn int_sub_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
641
642 /// Element-wise multiplication.
643 ///
644 /// # Arguments
645 ///
646 /// * `lhs` - The left-hand side tensor.
647 /// * `rhs` - The right-hand side tensor.
648 ///
649 /// # Returns
650 ///
651 /// The result of the multiplication.
652 fn int_mul(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
653
654 /// Element-wise multiplication with a scalar.
655 ///
656 /// # Arguments
657 ///
658 /// * `lhs` - The left-hand side tensor.
659 /// * `rhs` - The right-hand side scalar.
660 ///
661 /// # Returns
662 ///
663 /// The result of the multiplication.
664 fn int_mul_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
665
666 /// Element-wise division.
667 ///
668 /// # Arguments
669 ///
670 /// * `lhs` - The left-hand side tensor.
671 /// * `rhs` - The right-hand side tensor.
672 ///
673 /// # Returns
674 ///
675 /// The result of the division.
676 fn int_div(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
677
678 /// Element-wise division with a scalar.
679 ///
680 /// # Arguments
681 ///
682 /// * `lhs` - The left-hand side tensor.
683 /// * `rhs` - The right-hand side scalar.
684 ///
685 /// # Returns
686 ///
687 /// The result of the division.
688 fn int_div_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
689
690 /// Element-wise modulus.
691 ///
692 /// # Arguments
693 /// * `lhs` - The left-hand side tensor.
694 /// * `rhs` - The right-hand side scalar.
695 ///
696 /// # Returns
697 ///
698 /// The result of applying the modulus of the scalar to the tensor.
699 fn int_remainder(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
700
701 /// Element-wise modulus with a scalar.
702 ///
703 /// # Arguments
704 /// * `lhs` - The left-hand side tensor.
705 /// * `rhs` - The right-hand side scalar.
706 ///
707 /// # Returns
708 ///
709 /// The result of applying the modulus of the scalar to the tensor.
710 fn int_remainder_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
711
712 /// Multiplies two tensors together using matrix multiplication.
713 ///
714 /// # Arguments
715 ///
716 /// * `lhs` - The left-hand side tensor.
717 /// * `rhs` - The right-hand side tensor.
718 ///
719 /// # Returns
720 ///
721 /// The result of multiplying the two tensors together using matrix multiplication.
722 fn int_matmul(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
723
724 /// Element-wise negation.
725 ///
726 /// # Arguments
727 ///
728 /// * `tensor` - The tensor to negate.
729 ///
730 /// # Returns
731 ///
732 /// The negated tensor.
733 fn int_neg(tensor: IntTensor<B>) -> IntTensor<B> {
734 Self::int_mul_scalar(tensor, (-1).into())
735 }
736
737 /// Creates a tensor of zeros.
738 ///
739 /// # Arguments
740 ///
741 /// * `shape` - The shape of the tensor.
742 /// * `device` - The device to create the tensor on.
743 /// * `dtype` - The target data type.
744 ///
745 /// # Returns
746 ///
747 /// The tensor of zeros.
748 fn int_zeros(shape: Shape, device: &Device<B>, dtype: IntDType) -> IntTensor<B> {
749 Self::int_from_data(TensorData::full_dtype(shape, 0, dtype.into()), device)
750 }
751
752 /// Creates a tensor of ones.
753 ///
754 /// # Arguments
755 ///
756 /// * `shape` - The shape of the tensor.
757 /// * `device` - The device to create the tensor on.
758 /// * `dtype` - The target data type.
759 ///
760 /// # Returns
761 ///
762 /// The tensor of ones.
763 fn int_ones(shape: Shape, device: &Device<B>, dtype: IntDType) -> IntTensor<B> {
764 Self::int_from_data(TensorData::full_dtype(shape, 1, dtype.into()), device)
765 }
766
767 /// Creates a tensor filled with given value.
768 ///
769 /// # Arguments
770 ///
771 /// * `shape` - The shape of the tensor.
772 /// * `fill_value` - The value with which to fill the tensor.
773 /// * `device` - The device to create the tensor on.
774 /// * `dtype` - The target data type.
775 ///
776 /// # Returns
777 ///
778 /// The tensor filled with given value
779 fn int_full(
780 shape: Shape,
781 fill_value: Scalar,
782 device: &Device<B>,
783 dtype: IntDType,
784 ) -> IntTensor<B> {
785 Self::int_from_data(
786 TensorData::full_dtype(shape, fill_value, dtype.into()),
787 device,
788 )
789 }
790
791 /// Sums all elements in the tensor.
792 ///
793 /// # Arguments
794 ///
795 /// * `tensor` - The tensor to sum.
796 ///
797 /// # Returns
798 ///
799 /// The sum of all elements in the tensor.
800 fn int_sum(tensor: IntTensor<B>) -> IntTensor<B>;
801
802 /// Sums all elements in the tensor along a dimension.
803 ///
804 /// # Arguments
805 ///
806 /// * `tensor` - The tensor to sum.
807 /// * `dim` - The dimension to sum along.
808 ///
809 /// # Returns
810 ///
811 /// The sum of all elements in the tensor along the dimension.
812 fn int_sum_dim(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
813
814 /// Computes the product of all elements in the tensor.
815 ///
816 /// # Arguments
817 ///
818 /// * `tensor` - The tensor to compute the product of.
819 ///
820 /// # Returns
821 ///
822 /// The product of all elements in the tensor.
823 fn int_prod(tensor: IntTensor<B>) -> IntTensor<B>;
824
825 /// Computes the product of all elements in the tensor along a dimension.
826 ///
827 /// # Arguments
828 ///
829 /// * `tensor` - The tensor to compute the product of.
830 /// * `dim` - The dimension to compute the product along.
831 ///
832 /// # Returns
833 ///
834 /// The product of all elements in the tensor along the dimension.
835 fn int_prod_dim(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
836
837 /// Computes the mean of all elements in the tensor.
838 ///
839 /// # Arguments
840 ///
841 /// * `tensor` - The tensor to compute the mean of.
842 ///
843 /// # Returns
844 ///
845 /// The mean of all elements in the tensor.
846 fn int_mean(tensor: IntTensor<B>) -> IntTensor<B> {
847 let num_elems = tensor.shape().num_elements() as i64;
848 B::int_div_scalar(B::int_sum(tensor), num_elems.into())
849 }
850
851 /// Computes the mean of all elements in the tensor along a dimension.
852 ///
853 /// # Arguments
854 ///
855 /// * `tensor` - The tensor to compute the mean of.
856 ///
857 /// # Returns
858 ///
859 /// The mean of all elements in the tensor along the dimension.
860 fn int_mean_dim(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
861
862 /// Computes the cumulative sum of elements along a dimension.
863 ///
864 /// # Arguments
865 ///
866 /// * `tensor` - The tensor to compute the cumulative sum of.
867 /// * `dim` - The dimension along which to compute the cumulative sum.
868 ///
869 /// # Returns
870 ///
871 /// A tensor with the same shape where each element is the cumulative sum
872 /// of all elements up to and including that position along the dimension.
873 fn int_cumsum(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
874
875 /// Computes the cumulative product of elements along a dimension.
876 ///
877 /// # Arguments
878 ///
879 /// * `tensor` - The tensor to compute the cumulative product of.
880 /// * `dim` - The dimension along which to compute the cumulative product.
881 ///
882 /// # Returns
883 ///
884 /// A tensor with the same shape where each element is the cumulative product
885 /// of all elements up to and including that position along the dimension.
886 fn int_cumprod(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
887
888 /// Computes the cumulative minimum of elements along a dimension.
889 ///
890 /// # Arguments
891 ///
892 /// * `tensor` - The tensor to compute the cumulative minimum of.
893 /// * `dim` - The dimension along which to compute the cumulative minimum.
894 ///
895 /// # Returns
896 ///
897 /// A tensor with the same shape where each element is the minimum
898 /// of all elements up to and including that position along the dimension.
899 fn int_cummin(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
900
901 /// Computes the cumulative maximum of elements along a dimension.
902 ///
903 /// # Arguments
904 ///
905 /// * `tensor` - The tensor to compute the cumulative maximum of.
906 /// * `dim` - The dimension along which to compute the cumulative maximum.
907 ///
908 /// # Returns
909 ///
910 /// A tensor with the same shape where each element is the maximum
911 /// of all elements up to and including that position along the dimension.
912 fn int_cummax(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
913
914 /// Gets the indices of the maximum elements along a dimension.
915 ///
916 /// # Arguments
917 ///
918 /// * `tensor` - The tensor to get the maximum indices of.
919 /// * `dim` - The dimension to get the maximum indices along.
920 ///
921 /// # Returns
922 ///
923 /// The indices of the maximum elements along the dimension.
924 fn int_argmax(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
925
926 /// Gets the indices of the k maximum elements along a dimension.
927 /// If two elements share the same value, it will be ordered by the lowest
928 /// coordinate
929 ///
930 /// # Arguments
931 ///
932 /// * `tensor` - The tensor to get the maximum indices of.
933 /// * `dim` - The dimension to get the maximum indices along.
934 /// * `k` - number of maximum elements.
935 ///
936 /// # Returns
937 ///
938 /// The indices of the maximum elements along the dimension.
939 fn int_argtopk(tensor: IntTensor<B>, dim: usize, k: usize) -> IntTensor<B> {
940 let device = &tensor.device();
941 let dtype = get_device_settings::<B>(device).int_dtype;
942 let k_indices = B::int_arange(0..k as i64, device, dtype);
943 Self::int_select(Self::int_argsort(tensor, dim, true), dim, k_indices)
944 }
945
946 /// Gets the values of the k maximum elements along a dimension.
947 /// # Arguments
948 ///
949 /// * `tensor` - The tensor to get the maximum values of.
950 /// * `dim` - The dimension to get the maximum values along.
951 /// * `k` - number of maximum elements.
952 ///
953 /// # Returns
954 ///
955 /// The values of the maximum elements along the dimension.
956 fn int_topk(tensor: IntTensor<B>, dim: usize, k: usize) -> IntTensor<B> {
957 let device = &tensor.device();
958 let dtype = get_device_settings::<B>(device).int_dtype;
959 let k_indices = Self::int_arange(0..k as i64, device, dtype);
960 Self::int_select(Self::int_sort(tensor, dim, true), dim, k_indices)
961 }
962
963 /// Gets the values of the k maximum elements along a dimension, and their indices.
964 ///
965 /// # Arguments
966 ///
967 /// * `tensor` - The tensor to get the maximum values of.
968 /// * `dim` - The dimension to get the maximum values along.
969 /// * `k` - number of maximum elements.
970 ///
971 /// # Returns
972 ///
973 /// A tuple with the values of the k maximum elements along the dimension, and their indices.
974 ///
975 /// The default sorts once and keeps the first `k` of each half. It deliberately does not
976 /// compose `int_topk` with `int_argtopk`: those default to a sort each, so that would sort
977 /// twice, and `int_argtopk` has no default at all, so backends that only sort could not
978 /// serve this. Backends whose top-k already carries both results should override this and
979 /// produce them in a single pass.
980 fn int_topk_with_indices(
981 tensor: IntTensor<B>,
982 dim: usize,
983 k: usize,
984 ) -> (IntTensor<B>, IntTensor<B>) {
985 let device = tensor.device();
986 let dtype = get_device_settings::<B>(&device).int_dtype;
987 let k_indices = Self::int_arange(0..k as i64, &device, dtype);
988 let (values, indices) = Self::int_sort_with_indices(tensor, dim, true);
989
990 (
991 Self::int_select(values, dim, k_indices.clone()),
992 Self::int_select(indices, dim, k_indices),
993 )
994 }
995
996 /// Gets the indices of the minimum elements along a dimension.
997 ///
998 /// # Arguments
999 ///
1000 /// * `tensor` - The tensor to get the minimum indices of.
1001 /// * `dim` - The dimension to get the minimum indices along.
1002 ///
1003 /// # Returns
1004 ///
1005 /// The indices of the minimum elements along the dimension.
1006 fn int_argmin(tensor: IntTensor<B>, dim: usize) -> IntTensor<B>;
1007
1008 /// Gets the maximum element in the tensor.
1009 ///
1010 /// # Arguments
1011 ///
1012 /// * `tensor` - The tensor to get the maximum element of.
1013 ///
1014 /// # Returns
1015 ///
1016 /// The maximum element in the tensor.
1017 fn int_max(tensor: IntTensor<B>) -> IntTensor<B> {
1018 let shape = tensor.shape();
1019 let tensor = B::int_reshape(tensor, Shape::new([shape.num_elements()]));
1020
1021 B::int_max_dim(tensor, 0)
1022 }
1023
1024 /// Gets the maximum element in the tensor along a dimension.
1025 ///
1026 /// # Arguments
1027 ///
1028 /// * `tensor` - The tensor to get the maximum element of.
1029 /// * `dim` - The dimension to get the maximum element along.
1030 ///
1031 /// # Returns
1032 ///
1033 /// The maximum element in the tensor along the dimension.
1034 fn int_max_dim(tensor: IntTensor<B>, dim: usize) -> IntTensor<B> {
1035 let index = B::int_argmax(tensor.clone(), dim);
1036 B::int_gather(dim, tensor, index)
1037 }
1038
1039 /// Gets the maximum elements and corresponding indices along a dimension.
1040 ///
1041 /// # Arguments
1042 ///
1043 /// * `tensor` - The tensor to get the maximum elements and indices of.
1044 /// * `dim` - The dimension to get the maximum elements and indices along.
1045 ///
1046 /// # Returns
1047 ///
1048 /// The maximum elements and corresponding indices along the dimension.
1049 fn int_max_dim_with_indices(tensor: IntTensor<B>, dim: usize) -> (IntTensor<B>, IntTensor<B>) {
1050 let index = B::int_argmax(tensor.clone(), dim);
1051 let values = B::int_gather(dim, tensor, index.clone());
1052
1053 (values, index)
1054 }
1055
1056 /// Gets the maximum absolute element in the tensor.
1057 ///
1058 /// # Arguments
1059 ///
1060 /// * `tensor` - The tensor to get the maximum element of.
1061 ///
1062 /// # Returns
1063 ///
1064 /// The maximum element in the tensor.
1065 fn int_max_abs(tensor: IntTensor<B>) -> IntTensor<B> {
1066 let shape = tensor.shape();
1067 let tensor = B::int_reshape(tensor, Shape::new([shape.num_elements()]));
1068
1069 B::int_max_abs_dim(tensor, 0)
1070 }
1071
1072 /// Gets the maximum absolute element in the tensor along a dimension.
1073 ///
1074 /// # Arguments
1075 ///
1076 /// * `tensor` - The tensor to get the maximum element of.
1077 /// * `dim` - The dimension to get the maximum element along.
1078 ///
1079 /// # Returns
1080 ///
1081 /// The maximum element in the tensor along the dimension.
1082 fn int_max_abs_dim(tensor: IntTensor<B>, dim: usize) -> IntTensor<B> {
1083 B::int_max_dim(B::int_abs(tensor), dim)
1084 }
1085
1086 /// Gets the minimum element in the tensor.
1087 ///
1088 /// # Arguments
1089 ///
1090 /// * `tensor` - The tensor to get the minimum element of.
1091 ///
1092 /// # Returns
1093 ///
1094 /// The minimum element in the tensor.
1095 fn int_min(tensor: IntTensor<B>) -> IntTensor<B> {
1096 let shape = tensor.shape();
1097 let tensor = B::int_reshape(tensor, Shape::new([shape.num_elements()]));
1098
1099 B::int_min_dim(tensor, 0)
1100 }
1101
1102 /// Gets the minimum elements in the tensor along a dimension.
1103 ///
1104 /// # Arguments
1105 ///
1106 /// * `tensor` - The tensor to get the minimum element of.
1107 /// * `dim` - The dimension to get the minimum element along.
1108 ///
1109 /// # Returns
1110 ///
1111 /// The minimum element in the tensor along the dimension.
1112 fn int_min_dim(tensor: IntTensor<B>, dim: usize) -> IntTensor<B> {
1113 let index = B::int_argmin(tensor.clone(), dim);
1114 B::int_gather(dim, tensor, index)
1115 }
1116
1117 /// Gets the minimum elements and corresponding indices along a dimension.
1118 ///
1119 /// # Arguments
1120 ///
1121 /// * `tensor` - The tensor to get the minimum elements and indices of.
1122 /// * `dim` - The dimension to get the minimum elements and indices along.
1123 ///
1124 /// # Returns
1125 ///
1126 /// The minimum elements and corresponding indices along the dimension.
1127 fn int_min_dim_with_indices(tensor: IntTensor<B>, dim: usize) -> (IntTensor<B>, IntTensor<B>) {
1128 let indices = B::int_argmin(tensor.clone(), dim);
1129 let values = B::int_gather(dim, tensor, indices.clone());
1130
1131 (values, indices)
1132 }
1133
1134 /// Returns a new tensor with absolute values.
1135 ///
1136 /// # Arguments
1137 ///
1138 /// * `tensor` - The tensor to take absolute value of.
1139 ///
1140 /// # Returns
1141 ///
1142 /// A tensor with the same shape as `tensor` with absolute values.
1143 fn int_abs(tensor: IntTensor<B>) -> IntTensor<B>;
1144
1145 /// Transposes an int tensor.
1146 ///
1147 /// # Arguments
1148 ///
1149 /// * `tensor` - The tensor to transpose.
1150 ///
1151 /// # Returns
1152 ///
1153 /// The transposed tensor.
1154 fn int_transpose(tensor: IntTensor<B>) -> IntTensor<B> {
1155 let ndims = tensor.shape().num_dims();
1156 Self::int_swap_dims(tensor, ndims - 2, ndims - 1)
1157 }
1158
1159 /// Swaps two dimensions of an int tensor.
1160 ///
1161 /// # Arguments
1162 ///
1163 /// * `tensor` - The tensor to swap the dimensions of.
1164 /// * `dim1` - The first dimension to swap.
1165 /// * `dim2` - The second dimension to swap.
1166 ///
1167 /// # Returns
1168 ///
1169 /// The tensor with the dimensions swapped.
1170 fn int_swap_dims(tensor: IntTensor<B>, dim1: usize, dim2: usize) -> IntTensor<B>;
1171
1172 /// Permutes the dimensions of a tensor.
1173 ///
1174 /// # Arguments
1175 ///
1176 /// * `tensor` - The tensor to permute the dimensions of.
1177 /// * `axes` - The new order of the dimensions.
1178 /// # Returns
1179 ///
1180 /// The tensor with the dimensions permuted.
1181 fn int_permute(tensor: IntTensor<B>, axes: &[usize]) -> IntTensor<B>;
1182
1183 /// Reverse the order of elements in a tensor along the given axes.
1184 ///
1185 /// # Arguments
1186 ///
1187 /// * `tensor` - The tensor to reverse.
1188 /// * `axes` - The axes to reverse.
1189 ///
1190 /// The tensor with the elements reversed.
1191 fn int_flip(tensor: IntTensor<B>, axes: &[usize]) -> IntTensor<B>;
1192
1193 /// Creates a new int tensor with random values.
1194 ///
1195 /// # Arguments
1196 /// * `shape` - The shape of the tensor.
1197 /// * `distribution` - The distribution to sample from.
1198 /// * `device` - The device to create the tensor on.
1199 /// * `dtype` - The target data type.
1200 ///
1201 /// # Returns
1202 ///
1203 /// The tensor with the given shape and random values.
1204 fn int_random(
1205 shape: Shape,
1206 distribution: Distribution,
1207 device: &Device<B>,
1208 dtype: IntDType,
1209 ) -> IntTensor<B>;
1210
1211 /// Creates a new tensor with values from the given range with the given step size.
1212 ///
1213 /// # Arguments
1214 ///
1215 /// * `range` - The range of values.
1216 /// * `step` - The step size.
1217 /// * `device` - The device to create the tensor on.
1218 /// * `dtype` - The target data type.
1219 ///
1220 /// # Returns
1221 ///
1222 /// The tensor with the given values.
1223 fn int_arange_step(
1224 range: Range<i64>,
1225 step: usize,
1226 device: &Device<B>,
1227 dtype: IntDType,
1228 ) -> IntTensor<B> {
1229 let value = range.step_by(step).collect::<Vec<_>>();
1230 let shape = Shape::new([value.len()]);
1231 let data = TensorData::new(value, shape).convert_dtype(dtype.into());
1232 B::int_from_data(data, device)
1233 }
1234
1235 /// Creates a new tensor with values from the given range.
1236 ///
1237 /// # Arguments
1238 ///
1239 /// * `range` - The range of values.
1240 /// * `device` - The device to create the tensor on.
1241 ///
1242 /// # Returns
1243 ///
1244 /// The tensor with the given values.
1245 ///
1246 /// # Remarks
1247 ///
1248 /// Uses `arange_step` with a step size of 1 under the hood.
1249 fn int_arange(range: Range<i64>, device: &Device<B>, dtype: IntDType) -> IntTensor<B> {
1250 Self::int_arange_step(range, 1, device, dtype)
1251 }
1252
1253 /// Tests if any element in the int `tensor` evaluates to True.
1254 ///
1255 /// # Arguments
1256 ///
1257 /// * `tensor` - The tensor to test.
1258 ///
1259 /// # Returns
1260 ///
1261 /// A boolean tensor with a single element, True if any element in the tensor is True, False otherwise.
1262 fn int_any(tensor: IntTensor<B>, out_dtype: BoolDType) -> BoolTensor<B> {
1263 let int_dtype = tensor.dtype();
1264 let bool_tensor = B::int_equal_elem(tensor, 0.into(), out_dtype);
1265 let bool_tensor = B::bool_not(bool_tensor);
1266 let sum = B::int_sum(B::bool_into_int(bool_tensor, int_dtype.into()));
1267 B::int_greater_elem(sum, 0.into(), out_dtype)
1268 }
1269
1270 /// Tests if any element in the int `tensor` evaluates to True along a given dimension `dim`.
1271 ///
1272 /// # Arguments
1273 ///
1274 /// * `tensor` - The tensor to test.
1275 /// * `dim` - The axis along which to test.
1276 ///
1277 /// # Returns
1278 ///
1279 /// A boolean tensor `Tensor<B, D, Bool>` with the same size as input `tensor`, except in the `dim` axis
1280 /// where the size is 1. The elem in the `dim` axis is True if any element along this dim in the input
1281 /// evaluates to True, False otherwise.
1282 fn int_any_dim(tensor: IntTensor<B>, dim: usize, out_dtype: BoolDType) -> BoolTensor<B> {
1283 let int_dtype = tensor.dtype();
1284 let bool_tensor = B::int_equal_elem(tensor, 0.into(), out_dtype);
1285 let bool_tensor = B::bool_not(bool_tensor);
1286 let sum = B::int_sum_dim(B::bool_into_int(bool_tensor, int_dtype.into()), dim);
1287 B::int_greater_elem(sum, 0.into(), out_dtype)
1288 }
1289
1290 /// Tests if all elements in the int `tensor` evaluate to True.
1291 ///
1292 /// # Arguments
1293 ///
1294 /// * `tensor` - The tensor to test.
1295 /// * `out_dtype` - The output tensor dtype.
1296 ///
1297 /// # Returns
1298 ///
1299 /// A boolean tensor `Tensor<B, 1, Bool>` with a single element, True if all elements in the input tensor
1300 /// evaluate to True, False otherwise.
1301 fn int_all(tensor: IntTensor<B>, out_dtype: BoolDType) -> BoolTensor<B> {
1302 let int_dtype = tensor.dtype();
1303 let num_elems = tensor.shape().num_elements() as i64;
1304 let bool_tensor = B::int_equal_elem(tensor, 0.into(), out_dtype);
1305 let bool_tensor = B::bool_not(bool_tensor);
1306 let sum = B::int_sum(B::bool_into_int(bool_tensor, int_dtype.into()));
1307 B::int_equal_elem(sum, num_elems.into(), out_dtype)
1308 }
1309
1310 /// Tests if all elements in the int `tensor` evaluate to True along a given dimension `dim`.
1311 ///
1312 /// # Arguments
1313 ///
1314 /// * `tensor` - The tensor to test.
1315 /// * `dim` - The axis along which to test.
1316 /// * `out_dtype` - The output tensor dtype.
1317 ///
1318 /// # Returns
1319 ///
1320 /// A boolean tensor `Tensor<B, D, Bool>` with the same size as input `tensor`, except in the `dim` axis
1321 /// where the size is 1. The elem in the `dim` axis is True if all elements along this dim in the input
1322 /// evaluates to True, False otherwise.
1323 fn int_all_dim(tensor: IntTensor<B>, dim: usize, out_dtype: BoolDType) -> BoolTensor<B> {
1324 let int_dtype = tensor.dtype();
1325 let num_elems = tensor.shape()[dim] as i64;
1326 let bool_tensor = B::int_equal_elem(tensor, 0.into(), out_dtype);
1327 let bool_tensor = B::bool_not(bool_tensor);
1328 let sum = B::int_sum_dim(B::bool_into_int(bool_tensor, int_dtype.into()), dim);
1329 B::int_equal_elem(sum, num_elems.into(), out_dtype)
1330 }
1331
1332 /// Returns the signs of the int `tensor`.
1333 ///
1334 /// # Arguments
1335 ///
1336 /// * `tensor` - The tensor to extract the signs from.
1337 ///
1338 /// # Returns
1339 ///
1340 /// A tensor with the same shape as `tensor` containing the signs of the elements of `tensor`.
1341 fn int_sign(tensor: IntTensor<B>) -> IntTensor<B> {
1342 let dtype = tensor.dtype();
1343 let device = &tensor.device();
1344 let bool_dtype = get_device_settings::<B>(&tensor.device()).bool_dtype;
1345 let zeros = B::int_zeros(tensor.shape(), device, dtype.into());
1346 let less_than_zero = B::int_lower_elem(tensor.clone(), 0.into(), bool_dtype);
1347 let greater_than_zero = B::int_greater_elem(tensor, 0.into(), bool_dtype);
1348
1349 let mut result = B::int_mask_fill(zeros, less_than_zero, (-1).into());
1350 result = B::int_mask_fill(result, greater_than_zero, 1.into());
1351 result
1352 }
1353
1354 /// Broadcasts the int `tensor` to the given `shape`.
1355 fn int_expand(tensor: IntTensor<B>, shape: Shape) -> IntTensor<B>;
1356
1357 /// Sort the elements of the input `tensor` by value along a given dimension.
1358 ///
1359 /// This sort is unstable (i.e., may reorder equal elements).
1360 ///
1361 /// # Arguments
1362 ///
1363 /// * `tensor` - The input tensor.
1364 /// * `dim` - The axis along which to sort.
1365 /// * `descending` - The sorting order.
1366 ///
1367 /// # Returns
1368 ///
1369 /// A tensor with the same shape as the input tensor, where the elements are sorted by value.
1370 fn int_sort(tensor: IntTensor<B>, dim: usize, descending: bool) -> IntTensor<B> {
1371 let device = tensor.device();
1372 sort::<B, _, _, _>(
1373 tensor,
1374 dim,
1375 descending,
1376 device,
1377 |tensor| {
1378 let msg = "Failed to synchronously read tensor data. This operation is not supported until this backend has a GPU sorting implementation.";
1379 try_read_sync(B::int_into_data(tensor))
1380 .expect(msg)
1381 .expect(msg)
1382 },
1383 |data, device, _dtype| B::int_from_data(data, device),
1384 )
1385 }
1386
1387 /// Sort the elements of the input `tensor` by value along a given dimension.
1388 ///
1389 /// This sort is unstable (i.e., may reorder equal elements).
1390 ///
1391 /// # Arguments
1392 ///
1393 /// * `tensor` - The input tensor.
1394 /// * `dim` - The axis along which to sort.
1395 ///
1396 /// # Returns
1397 ///
1398 /// A tensor with the same shape as the input tensor and corresponding indices, where
1399 /// the elements are sorted by value and the indices map back to the original input tensor.
1400 fn int_sort_with_indices(
1401 tensor: IntTensor<B>,
1402 dim: usize,
1403 descending: bool,
1404 ) -> (IntTensor<B>, IntTensor<B>) {
1405 let dtype = tensor.dtype();
1406 let device = tensor.device();
1407 sort_with_indices::<B, _, _, _>(
1408 tensor,
1409 dim,
1410 descending,
1411 dtype.into(),
1412 device,
1413 |tensor| {
1414 let msg = "Failed to synchronously read tensor data. This operation is not supported until this backend has a GPU sorting implementation.";
1415 try_read_sync(B::int_into_data(tensor))
1416 .expect(msg)
1417 .expect(msg)
1418 },
1419 |data, device, _dtype| B::int_from_data(data, device),
1420 )
1421 }
1422
1423 /// Returns the indices that sort the elements of the input `tensor` by value
1424 /// along a given dimension.
1425 ///
1426 /// This sort is unstable (i.e., may reorder equal elements).
1427 ///
1428 /// # Arguments
1429 ///
1430 /// * `tensor` - The input tensor.
1431 /// * `dim` - The axis along which to sort.
1432 /// * `descending` - The sorting order.
1433 ///
1434 /// # Returns
1435 ///
1436 /// A tensor with the same shape as the input tensor the indices map back to the original input tensor.
1437 fn int_argsort(tensor: IntTensor<B>, dim: usize, descending: bool) -> IntTensor<B> {
1438 let dtype = tensor.dtype();
1439 let device = tensor.device();
1440 argsort::<B, _, _>(tensor, dim, descending, dtype.into(), device, |tensor| {
1441 let msg = "Failed to synchronously read tensor data. This operation is not supported until this backend has a GPU sorting implementation.";
1442 try_read_sync(B::int_into_data(tensor))
1443 .expect(msg)
1444 .expect(msg)
1445 })
1446 }
1447
1448 /// Bitwise AND operation for Int Tensors
1449 fn bitwise_and(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
1450
1451 /// Bitwise AND operation for Int Tensors with a scalar
1452 fn bitwise_and_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
1453
1454 /// Bitwise OR operation for Int Tensors
1455 fn bitwise_or(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
1456
1457 /// Bitwise OR operation for Int Tensors with a scalar
1458 fn bitwise_or_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
1459
1460 /// Bitwise XOR operation for Int Tensors
1461 fn bitwise_xor(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
1462
1463 /// Bitwise XOR operation for Int Tensors with a scalar
1464 fn bitwise_xor_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
1465
1466 /// Bitwise NOT operation for Int Tensors
1467 fn bitwise_not(tensor: IntTensor<B>) -> IntTensor<B>;
1468
1469 /// Bitwise left shift operation for Int Tensors
1470 fn bitwise_left_shift(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
1471
1472 /// Bitwise left shift operation for Int Tensors with a scalar
1473 fn bitwise_left_shift_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
1474
1475 /// Bitwise right shift operation for Int Tensors
1476 fn bitwise_right_shift(lhs: IntTensor<B>, rhs: IntTensor<B>) -> IntTensor<B>;
1477
1478 /// Bitwise right shift operation for Int Tensors with a scalar
1479 fn bitwise_right_shift_scalar(lhs: IntTensor<B>, rhs: Scalar) -> IntTensor<B>;
1480
1481 /// Converts a tensor to another integer data type.
1482 ///
1483 /// # Arguments
1484 ///
1485 /// * `tensor` - The tensor to convert.
1486 /// * `dtype` - The target data type.
1487 ///
1488 /// # Returns
1489 ///
1490 /// A tensor with the same values as `tensor` but in the target integer data type.
1491 fn int_cast(tensor: IntTensor<B>, dtype: IntDType) -> IntTensor<B>;
1492
1493 /// Unfold windows along a dimension.
1494 ///
1495 /// Returns a view of the tensor with all complete windows of size `size` in dimension `dim`;
1496 /// where windows are advanced by `step` at each index.
1497 ///
1498 /// The number of windows is `max(0, (shape[dim] - size).ceil_div(step))`.
1499 ///
1500 /// # Arguments
1501 ///
1502 /// * `tensor` - The input tensor to unfold; of shape ``[pre=..., dim shape, post=...]``
1503 /// * `dim` - the selected dim.
1504 /// * `size` - the size of each unfolded window.
1505 /// * `step` - the step between each window.
1506 ///
1507 /// # Returns
1508 ///
1509 /// A tensor view with shape ``[pre=..., windows, size, post=...]``.
1510 fn int_unfold(tensor: IntTensor<B>, dim: usize, size: usize, step: usize) -> IntTensor<B>;
1511}