1use std::{fmt::Display, ops::Deref};
2use crate::{AutogradMetaT, Dim, Error, IntTensor, NumDType, Result, WithDType, D};
3use crate::Tensor;
4
5impl<T: WithDType> Tensor<T> {
6 pub fn indexes(&self, indexers: &[Indexer]) -> Result<Self> {
7 let mut x = self.clone();
8 let mut current_dim = 0;
9 for indexer in indexers.iter() {
10 x = match indexer {
11 Indexer::Select(n) => x.narrow(current_dim, *n, 1)?.squeeze(current_dim)?,
12 Indexer::SelectD(d) => {
13 let dim_size = x.dim(current_dim)?;
14 let n = d.to_real_index(dim_size, "index")?;
15 x.narrow(current_dim, n, 1)?.squeeze(current_dim)?
16 }
17 Indexer::Slice(range) => {
18 let out = x.slice(current_dim, range)?;
19 current_dim += 1;
20 out
21 }
22 Indexer::Boolean(index) => {
23 if index.dims1()? != x.dims()[current_dim] {
24 return Err(Error::BooleanIndexShouldLikeVector(index.shape().clone()))
25 }
26
27 let index = index.to_vec()?
30 .into_iter()
31 .enumerate()
32 .filter(|(_, v)| *v)
33 .map(|(i, _)| i as u32)
34 .collect::<Vec<_>>();
35 let index = Tensor::new(index)?;
36 let out = x.index_select(index, current_dim)?;
37 current_dim += 1;
38 out
39 }
40 };
41 }
42 Ok(x)
43 }
44
45 pub fn get(&self, i: usize) -> Result<Self> {
56 let dims = self.dims();
57 if dims.is_empty() {
58 Ok(self.clone())
59 } else {
60 self.narrow(0, i, 1)?.reshape(&dims[1..])
61 }
62 }
63
64 pub fn index_select<D: Dim>(&self, indexes: impl Into<IntTensor>, dim: D) -> Result<Self> {
65 let indexes: IntTensor = indexes.into();
66 let dim = dim.to_index(self.shape(), "index-select")?;
67 let indexes_len = indexes.shape().dims1()?;
68 let mut dims = self.dims().to_vec();
69 dims[dim] = indexes_len;
70 let meta = T::AutogradMeta::on_index_select_op(self, &indexes, dim);
71 let storage = match indexes {
72 IntTensor::I32(indexes) => self.storage_read()?.index_select(
73 self.layout(),
74 indexes.storage_read()?.deref(),
75 indexes.layout(),
76 dim,
77 )?,
78 IntTensor::U32(indexes) => self.storage_read()?.index_select(
79 self.layout(),
80 indexes.storage_read()?.deref(),
81 indexes.layout(),
82 dim,
83 )?,
84 IntTensor::U8(indexes) => self.storage_read()?.index_select(
85 self.layout(),
86 indexes.storage_read()?.deref(),
87 indexes.layout(),
88 dim,
89 )?,
90 };
91
92 Ok(Self::from_storage(storage, dims, meta))
93 }
94
95 pub fn gather<D: Dim>(&self, indexes: impl Into<IntTensor>, dim: D) -> Result<Self> {
107 let indexes = indexes.into();
108 let dim = dim.to_index(self.shape(), "gather")?;
109 let self_dims = self.dims();
110 let indexes_dims = indexes.dims();
111 let mismatch = if indexes_dims.len() != self_dims.len() {
112 true
113 } else {
114 let mut mismatch = false;
115 for (i, (&d1, &d2)) in self_dims.iter().zip(indexes_dims.iter()).enumerate() {
116 if i != dim && d1 < d2 {
117 mismatch = true;
118 break;
119 }
120 }
121 mismatch
122 };
123 if mismatch {
124 Err(Error::ShapeMismatchBinaryOp {
125 op: "gather",
126 lhs: self.shape().clone(),
127 rhs: indexes.shape().clone(),
128 })?
129 }
130
131 let storage = match &indexes {
132 IntTensor::I32(idx) => self.storage_read()?.gather(self.layout(), idx.storage_read()?.deref(), idx.layout(), dim)?,
133 IntTensor::U32(idx) => self.storage_read()?.gather(self.layout(), idx.storage_read()?.deref(), idx.layout(), dim)?,
134 IntTensor::U8(idx) => self.storage_read()?.gather(self.layout(), idx.storage_read()?.deref(), idx.layout(), dim)?,
135 };
136
137 let meta = T::AutogradMeta::on_gather_op(self, &indexes, dim);
138 Ok(Self::from_storage(storage, indexes.shape(), meta))
139 }
140}
141
142impl<T: NumDType> Tensor<T> {
143 pub fn index_add<D: Dim>(&self, indexes: impl Into<IntTensor>, source: &Tensor<T>, dim: D) -> Result<Self> {
144 let indexes: IntTensor = indexes.into();
145 let dim = dim.to_index(self.shape(), "index-add")?;
146
147 let source_dims = source.dims();
148 let self_dims = self.dims();
149 if source_dims.len() != self_dims.len() {
150 return Err(Error::ShapeMismatchBinaryOp {
151 op: "index-add",
152 lhs: self.shape().clone(),
153 rhs: source.shape().clone()
154 }.into());
155 }
156
157 let indexes_len = indexes.shape().dims1()?;
158 for (i, (&d_self, &d_src)) in self_dims.iter().zip(source_dims.iter()).enumerate() {
159 if i == dim {
160 if d_src != indexes_len {
161 return Err(Error::ShapeMismatchBinaryOp { op: "index-add (dim mismatch)", lhs: self.shape().clone(), rhs: source.shape().clone() }.into());
162 }
163 } else if d_self != d_src {
164 return Err(Error::ShapeMismatchBinaryOp { op: "index-add", lhs: self.shape().clone(), rhs: source.shape().clone() }.into());
165 }
166 }
167
168 let storage = match &indexes {
169 IntTensor::I32(idx) => self.storage_read()?.index_add(
170 self.layout(),
171 idx.storage_read()?.deref(),
172 idx.layout(),
173 source.storage_read()?.deref(),
174 source.layout(),
175 dim,
176 )?,
177 IntTensor::U32(idx) => self.storage_read()?.index_add(
178 self.layout(),
179 idx.storage_read()?.deref(),
180 idx.layout(),
181 source.storage_read()?.deref(),
182 source.layout(),
183 dim,
184 )?,
185 IntTensor::U8(idx) => self.storage_read()?.index_add(
186 self.layout(),
187 idx.storage_read()?.deref(),
188 idx.layout(),
189 source.storage_read()?.deref(),
190 source.layout(),
191 dim,
192 )?,
193 };
194
195 let meta = T::AutogradMeta::on_index_add_op(self, &indexes, source, dim);
196 Ok(Self::from_storage(storage, self_dims.to_vec(), meta))
197 }
198
199 pub fn scatter_add<D: Dim>(&self, indexes: impl Into<IntTensor>, source: &Self, dim: D) -> Result<Self> {
200 let indexes = indexes.into();
201 let dim = dim.to_index(self.shape(), "scatter-add")?;
202 self.scatter_checks(&indexes, source, dim)?;
203
204 let storage = match &indexes {
205 IntTensor::I32(idx) => self.storage_read()?.scatter_add(
206 self.layout(),
207 idx.storage_read()?.deref(),
208 idx.layout(),
209 source.storage_read()?.deref(),
210 source.layout(),
211 dim,
212 )?,
213 IntTensor::U32(idx) => self.storage_read()?.scatter_add(
214 self.layout(),
215 idx.storage_read()?.deref(),
216 idx.layout(),
217 source.storage_read()?.deref(),
218 source.layout(),
219 dim,
220 )?,
221 IntTensor::U8(idx) => self.storage_read()?.scatter_add(
222 self.layout(),
223 idx.storage_read()?.deref(),
224 idx.layout(),
225 source.storage_read()?.deref(),
226 source.layout(),
227 dim,
228 )?,
229 };
230
231 let meta = T::AutogradMeta::on_scatter_add_op(self, &indexes, source, dim);
232 Ok(Self::from_storage(storage, self.shape(), meta))
233 }
234
235 fn scatter_checks(&self, indexes: &IntTensor, source: &Self, dim: usize) -> Result<()> {
236 let source_dims = source.dims();
237 let self_dims = self.dims();
238 let mismatch = if source_dims.len() != self_dims.len() {
239 true
240 } else {
241 let mut mismatch = false;
242 for (i, (&d1, &d2)) in self_dims.iter().zip(source_dims.iter()).enumerate() {
243 if i != dim && d1 != d2 {
244 mismatch = true;
245 break;
246 }
247 }
248 mismatch
249 };
250 if mismatch {
251 Err(Error::ShapeMismatchBinaryOp {
252 op: "scatter (self, src)",
253 lhs: self.shape().clone(),
254 rhs: source.shape().clone(),
255 })?
256 }
257 if indexes.dims() != source.dims() {
258 Err(Error::ShapeMismatchBinaryOp {
259 op: "scatter (indexes, src)",
260 lhs: indexes.shape().clone(),
261 rhs: source.shape().clone(),
262 })?
263 }
264 Ok(())
265 }
266}
267
268impl<T: WithDType> Tensor<T> {
269 pub fn matrix_get(&self, row: usize, col: usize) -> Result<T> {
270 self.index((row, col))?.to_scalar()
271 }
272
273 pub fn matrix_set(&self, row: usize, col: usize, val: T) -> Result<()> {
274 self.index((row, col))?.set_scalar(val)
275 }
276
277 pub fn vector_get(&self, n: usize) -> Result<T> {
278 self.index(n)?.to_scalar()
279 }
280}
281
282#[derive(Debug, Clone, PartialEq, Eq)]
283pub enum Indexer {
284 Select(usize),
285 SelectD(D),
286 Slice(Slice),
287 Boolean(Tensor<bool>),
288}
289
290#[derive(Debug, Clone, PartialEq, Eq)]
291pub struct Slice {
292 pub start: usize,
293 pub end: Option<isize>,
294 pub step: usize
295}
296
297impl Slice {
298 pub fn new(start: usize, end: Option<isize>, step: usize) -> Self {
299 Self { start, end, step }
300 }
301
302 pub fn len(&self) -> usize {
303 self.clone().count()
304 }
305}
306
307impl Iterator for Slice {
308 type Item = usize;
309 fn next(&mut self) -> Option<Self::Item> {
310 match self.end {
311 Some(end) if end < 0 => {
312 let value = self.start;
313 self.start += self.step;
314 Some(value)
315 }
316 Some(end) => {
317 if self.start < end as usize {
318 let value = self.start;
319 self.start += self.step;
320 Some(value)
321 } else {
322 None
323 }
324 }
325 None => {
326 let value = self.start;
327 self.start += self.step;
328 Some(value)
329 }
330 }
331 }
332}
333
334impl Display for Slice {
335 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
336 let step_part = match self.step {
337 1 => format!(""),
338 _ => format!(":{}", self.step),
339 };
340 match self.end {
341 Some(end) => write!(f, "{}:{}{}", self.start, end, step_part),
342 None => write!(f, "{}:{}", self.start, step_part),
343 }
344 }
345}
346
347impl From<usize> for Indexer {
348 fn from(index: usize) -> Self {
349 Indexer::Select(index)
350 }
351}
352
353impl From<D> for Indexer {
354 fn from(index: D) -> Self {
355 Indexer::SelectD(index)
356 }
357}
358
359impl From<Slice> for Indexer {
360 fn from(value: Slice) -> Self {
361 Indexer::Slice(value)
362 }
363}
364
365impl From<&Tensor<bool>> for Indexer {
366 fn from(value: &Tensor<bool>) -> Self {
367 Indexer::Boolean(value.clone())
368 }
369}
370
371impl From<Tensor<bool>> for Indexer {
372 fn from(value: Tensor<bool>) -> Self {
373 Indexer::Boolean(value)
374 }
375}
376
377impl From<std::ops::Range<usize>> for Indexer {
378 fn from(value: std::ops::Range<usize>) -> Self {
379 let range = Slice::new(value.start, Some(value.end as isize), 1);
380 range.into()
381 }
382}
383
384impl From<std::ops::RangeFrom<usize>> for Indexer {
385 fn from(value: std::ops::RangeFrom<usize>) -> Self {
386 let range = Slice::new(value.start, None, 1);
387 range.into()
388 }
389}
390
391impl From<std::ops::RangeTo<usize>> for Indexer {
392 fn from(value: std::ops::RangeTo<usize>) -> Self {
393 let range = Slice::new(0, Some(value.end as isize), 1);
394 range.into()
395 }
396}
397
398
399impl From<std::ops::RangeFull> for Indexer {
400 fn from(_: std::ops::RangeFull) -> Self {
401 let range = Slice::new(0, None, 1);
402 range.into()
403 }
404}
405
406pub trait IndexOp<T, D: WithDType> {
407 fn index(&self, index: T) -> Result<Tensor<D>>;
408}
409
410impl<I: Into<Indexer>, D: WithDType> IndexOp<I, D> for Tensor<D> {
411 fn index(&self, index: I) -> Result<Tensor<D>> {
412 self.indexes(&[index.into()])
413 }
414}
415
416impl<I: Into<Indexer>, D: WithDType> IndexOp<(I,), D> for Tensor<D> {
417 fn index(&self, (index,): (I,)) -> Result<Tensor<D>> {
418 self.indexes(&[index.into()])
419 }
420}
421
422macro_rules! index_op_tuple {
423 ($($t:ident),+) => {
424 #[allow(non_snake_case)]
425 impl<$($t),*, D: WithDType> IndexOp<($($t,)*), D> for Tensor<D>
426 where
427 $($t: Into<Indexer>,)*
428 {
429 fn index(&self, ($($t,)*): ($($t,)*)) -> Result<Tensor<D>> {
430 self.indexes(&[$($t.into(),)*])
431 }
432 }
433 };
434}
435
436index_op_tuple!(I1, I2);
437index_op_tuple!(I1, I2, I3);
438index_op_tuple!(I1, I2, I3, I4);
439index_op_tuple!(I1, I2, I3, I4, I5);
440
441impl<I: Into<Indexer>, D: WithDType> IndexOp<Vec<I>, D> for Tensor<D> {
442 fn index(&self, index: Vec<I>) -> Result<Tensor<D>> {
443 let indexs = index.into_iter().map(|i| i.into()).collect::<Vec<Indexer>>();
444 self.indexes(&indexs)
445 }
446}
447
448#[macro_export]
449macro_rules! s {
450 ($start:tt : $end:expr) => {
452 Slice::new($start as usize, Some($end as isize), 1)
453 };
454 ($start:tt : $end:tt : $step:expr) => {
456 Slice::new($start as usize, Some($end as isize), $step as usize)
457 };
458 ($start:tt :) => {
460 Slice::new($start as usize, None, 1)
461 };
462 ($start:tt :: $step:expr) => {
464 Slice::new($start as usize, None, $step as usize)
465 };
466 (: $end:tt) => {
468 Slice::new(0, Some($end as isize), 1)
469 };
470 (: $end:tt : $step:expr) => {
472 Slice::new(0, Some($end as isize), $step as usize)
473 };
474 (:: $step:expr) => {
476 Slice::new(0, None, $step as usize)
477 };
478 (:) => {
480 Slice::new(0, None, 1)
481 };
482}
483
484#[cfg(test)]
485#[allow(unused)]
486mod test {
487 use crate::DType;
488 use super::*;
489
490 #[test]
491 fn test_index_select_basic() {
492 let arr = Tensor::arange(0, 12).unwrap().reshape((3, 4)).unwrap();
496
497 let indices = Tensor::new(&[0, 2]).unwrap();
498 let selected = arr.index_select(indices, 0).unwrap();
499
500 assert_eq!(selected.shape().dims(), &[2, 4]);
501 let data = selected.to_vec().unwrap();
502 assert_eq!(data, vec![0, 1, 2, 3, 8, 9, 10, 11]);
503
504 let indices_col = Tensor::new(&[1]).unwrap();
505 let selected_col = arr.index_select(indices_col, 1).unwrap();
506
507 assert_eq!(selected_col.shape().dims(), &[3, 1]);
508 let data_col = selected_col.to_vec().unwrap();
509 assert_eq!(data_col, vec![1, 5, 9]);
510 }
511
512 #[test]
513 fn test_boolean_index() {
514 let arr = Tensor::arange(0, 12).unwrap().reshape((3, 4)).unwrap();
518 let index = Tensor::new([true, false, true]).unwrap();
519
520 let selected = arr.index(index).unwrap();
521 println!("{}", selected);
522 }
523
524 #[test]
525 fn test_index_select_1d() {
526 let scores = Tensor::<f64>::arange(0.0, 100.0).unwrap();
527 let indices = Tensor::new(&[25, 34, 12, 90]).unwrap();
528
529 let selected = scores.index_select(indices, 0).unwrap();
530 println!("{}", selected);
531 }
532
533 #[test]
534 fn test_index_select_duplicates_and_reorder() {
535 let arr = Tensor::arange(0, 5).unwrap(); let indices = Tensor::new(&[4, 0, 0, 1]).unwrap();
538 let selected = arr.index_select(indices, 0).unwrap();
539
540 assert_eq!(selected.shape().dims(), &[4]);
541 let data = selected.to_vec().unwrap();
542 assert_eq!(data, vec![4, 0, 0, 1]);
543 }
544
545 #[test]
546 fn test_index_select_out_of_bounds() {
547 let arr = Tensor::arange(0, 10).unwrap();
548 let indices = Tensor::new(&[0, 10]).unwrap();
549
550 let result = arr.index_select(indices, 0);
551 assert!(result.is_err());
552 }
553
554 #[test]
555 fn test_index_add_basic() {
556 let dst = Tensor::<i32>::zeros((3, 3)).unwrap();
557 let src = Tensor::<i32>::ones((2, 3)).unwrap();
558 let indices = Tensor::new(&[0, 2]).unwrap();
559
560 let result = dst.index_add(indices, &src, 0).unwrap();
561
562 let data = result.to_vec().unwrap();
566 assert_eq!(data, vec![
567 1, 1, 1,
568 0, 0, 0,
569 1, 1, 1
570 ]);
571 }
572
573 #[test]
574 fn test_index_add_accumulate() {
575 let dst = Tensor::<i32>::zeros((5,)).unwrap(); let src = Tensor::new(&[10, 20, 30]).unwrap();
577 let indices = Tensor::new(&[1, 1, 3]).unwrap();
578
579 let result = dst.index_add(indices, &src, 0).unwrap();
580
581 let data = result.to_vec().unwrap();
587 assert_eq!(data, vec![0, 30, 0, 30, 0]);
588 }
589
590 #[test]
591 fn test_index_add_dim_mismatch() {
592 let dst = Tensor::<i32>::zeros((3, 3)).unwrap();
593 let src = Tensor::<i32>::ones((2, 3)).unwrap();
594 let indices = Tensor::new(&[0, 1, 2]).unwrap();
595
596 let result = dst.index_add(indices, &src, 0);
597 assert!(result.is_err());
598 }
599
600 #[test]
601 fn test_index_add_inner_dim() {
602 let dst = Tensor::<i32>::zeros((2, 3)).unwrap();
606 let src = Tensor::new(&[
608 [5],
609 [5]
610 ]).unwrap(); let indices = Tensor::new(&[1]).unwrap();
612 let result = dst.index_add(indices, &src, 1).unwrap();
613
614 let data = result.to_vec().unwrap();
618 assert_eq!(data, vec![0, 5, 0, 0, 5, 0]);
619 }
620
621
622 #[test]
623 fn test_gather_dim_1() {
624 let src = Tensor::new(&[
628 [1, 2],
629 [3, 4]
630 ]).unwrap();
631
632 let indices = Tensor::new(&[
637 [0, 0],
638 [1, 0]
639 ]).unwrap();
640
641 let result = src.gather(&indices, 1).unwrap();
642
643 let data = result.to_vec().unwrap();
647 assert_eq!(data, vec![1, 1, 4, 3]);
648 }
649
650 #[test]
651 fn test_gather_dim_0() {
652 let src = Tensor::new(&[
657 [10, 20],
658 [30, 40],
659 [50, 60]
660 ]).unwrap();
661
662 let indices = Tensor::new(&[
666 [1, 2],
667 [0, 1]
668 ]).unwrap();
669
670 let result = src.gather(&indices, 0).unwrap();
671
672 let data = result.to_vec().unwrap();
676 assert_eq!(data, vec![30, 60, 10, 40]);
677 }
678
679 #[test]
680 fn test_gather_3d() {
681 let src = Tensor::new(&[0, 1, 2, 3, 4, 5, 6, 7]).unwrap().reshape((2, 2, 2)).unwrap();
685
686 let indices = Tensor::<u32>::zeros((2, 1, 2)).unwrap(); let result = src.gather(&indices, 1).unwrap();
698
699 assert_eq!(result.dims(), &[2, 1, 2]);
700 let data = result.to_vec().unwrap();
701 assert_eq!(data, vec![0, 1, 4, 5]);
702 }
703
704
705 #[test]
706 fn test_scatter_add_1d_accumulate() {
707 let dst = Tensor::<i32>::zeros((5,)).unwrap();
709
710 let src = Tensor::new(&[1, 1, 1, 1]).unwrap();
712 let indices = Tensor::new(&[0, 2, 0, 4]).unwrap();
713
714 let result = dst.scatter_add(indices, &src, 0).unwrap();
720
721 let data = result.to_vec().unwrap();
723 assert_eq!(data, vec![2, 0, 1, 0, 1]);
724 }
725
726 #[test]
727 fn test_scatter_add_2d_dim1() {
728 let dst = Tensor::<i32>::zeros((2, 3)).unwrap();
730
731 let src = Tensor::new(&[
735 [10, 20],
736 [30, 40]
737 ]).unwrap();
738
739 let indices = Tensor::new(&[
743 [0, 2],
744 [1, 1]
745 ]).unwrap();
746
747 let result = dst.scatter_add(indices, &src, 1).unwrap();
748
749 let data = result.to_vec().unwrap();
753 assert_eq!(data, vec![10, 0, 20, 0, 70, 0]);
754 }
755
756 #[test]
757 fn test_scatter_add_3d() {
758 let dst = Tensor::<i32>::zeros((2, 2, 2)).unwrap();
760
761 let src = Tensor::ones((2, 1, 2)).unwrap(); let indices = Tensor::new(&[1, 0, 0, 0]).unwrap().reshape((2, 1, 2)).unwrap();
768
769 let result = dst.scatter_add(indices, &src, 1).unwrap();
770
771 let res_vec = result.to_vec().unwrap();
778 assert_eq!(res_vec, vec![0, 1, 1, 0, 1, 1, 0, 0]);
787 }
788
789 #[test]
790 fn test_scatter_add_shape_mismatch() {
791 let dst = Tensor::<i32>::zeros((2, 2)).unwrap();
792 let src = Tensor::<i32>::ones((2, 2)).unwrap();
793 let indices = Tensor::new(&[0]).unwrap();
795
796 let result = dst.scatter_add(indices, &src, 0);
797 assert!(result.is_err());
798 }
799
800 #[test]
801 fn test_index_scalar_dim_reduction() {
802 let arr = Tensor::arange(0, 125).unwrap().reshape((5, 5, 5)).unwrap();
803 let sub = arr.index(1).unwrap();
804 assert_eq!(sub.shape().dims(), &[5, 5]);
805
806 let sub = arr.index((2, 3)).unwrap();
807 assert_eq!(sub.shape().dims(), &[5]);
808 }
809
810 #[test]
811 fn test_index_range_basic() {
812 let arr = Tensor::arange(0, 125).unwrap().reshape((5, 5, 5)).unwrap();
813
814 let sub = arr.index(s!(1:3)).unwrap();
815 assert_eq!(sub.shape().dims(), &[2, 5, 5]);
816
817 let sub = arr.index((s!(1:3), s!(3:4), 1)).unwrap();
818 assert_eq!(sub.shape().dims(), &[2, 1]);
819 }
820
821 #[test]
822 fn test_index_full_and_mixed() {
823 let arr = Tensor::<i32>::zeros((5, 5, 5)).unwrap();
824
825 let sub = arr.index((s!(1:3), .., 1..2)).unwrap();
826 assert_eq!(sub.shape().dims(), &[2, 5, 1]);
827
828 let sub = arr.index((2, .., s!(0:2))).unwrap();
829 assert_eq!(sub.shape().dims(), &[5, 2]);
830
831 let sub = arr.index((s!(0:2), s!(2:5), s!(1:3))).unwrap();
832 assert_eq!(sub.shape().dims(), &[2, 3, 2]);
833 }
834
835 #[test]
836 fn test_index_out_of_bounds() {
837 let arr = Tensor::<i32>::zeros((5, 5, 5)).unwrap();
838 let result = arr.index(10);
839 assert!(result.is_err());
840
841 let result = arr.index(s!(3:10));
842 assert!(result.is_err());
843 }
844
845 #[test]
846 fn test_index_scalar_and_values() {
847 let arr = Tensor::arange(0, 125).unwrap().reshape((5, 5, 5)).unwrap();
848
849 let sub = arr.index(1).unwrap();
850 let expected = Tensor::arange(25, 50).unwrap().reshape((5, 5)).unwrap();
851 assert!(sub.allclose(&expected, 0.0, 0.0).unwrap());
852 }
853
854 #[test]
855 fn test_index_range_values() {
856 let arr = Tensor::arange(0, 125).unwrap().reshape((5, 5, 5)).unwrap();
857
858 let sub = arr.index(s!(1:3)).unwrap();
859 let expected = Tensor::arange(25, 75).unwrap().reshape((2, 5, 5)).unwrap();
860 assert!(sub.allclose(&expected, 0.0, 0.0).unwrap());
861 }
862
863 #[test]
864 fn test_index_mixed_values() {
865 let arr = Tensor::arange(0, 125).unwrap().reshape((5, 5, 5)).unwrap();
866 let sub = arr.index((2, 3)).unwrap();
867 let expected = Tensor::arange(65, 70).unwrap();
868 assert!(sub.allclose(&expected, 0.0, 0.0).unwrap());
869
870 let sub = arr.index((s!(1:3), s!(3:5), 2)).unwrap();
871 let mut vals = Vec::new();
872 for i in 1..3 {
873 for j in 3..5 {
874 vals.push(i * 25 + j * 5 + 2);
875 }
876 }
877 let expected = Tensor::from_vec(vals, (2, 2)).unwrap();
878 assert!(sub.allclose(&expected, 0.0, 0.0).unwrap());
879 }
880
881 #[test]
882 fn test_index_with_full_dim() {
883 let arr = Tensor::arange(0, 125).unwrap().reshape((5, 5, 5)).unwrap();
884 let sub = arr.index((s!(1:3), .., 1..2)).unwrap();
885
886 let expected = arr.index((s!(1:3), s!(0:5), s!(1:2))).unwrap();
887 assert!(sub.allclose(&expected, 0.0, 0.0).unwrap());
888 }
889
890 #[test]
891 fn test_index_dim() {
892 let arr = Tensor::<f32>::zeros((3, 3)).unwrap();
893 let sub = arr.index((.., D::Minus1)).unwrap();
895 sub.copy_(5.2).unwrap();
896 println!("{}", arr);
897 }
898
899 #[test]
900 fn test_macro() {
901 let t = (0..12usize);
902 let t = (2usize..);
903 assert_eq!(s!(1:10), Slice {start:1, end: Some(10), step:1});
904
905 assert!(
906 s!(1:20).zip((1..20))
907 .all(|(a, b)| a == b)
908 );
909
910 assert!(
911 s!(1:13:3).zip((1..13).step_by(3))
912 .all(|(a, b)| a == b)
913 );
914
915 assert!(
916 s!(1:).zip((1..).take(100))
917 .all(|(a, b)| a == b)
918 );
919
920 assert!(
921 s!(1::2).zip((1..).step_by(2).take(100))
922 .all(|(a, b)| a == b)
923 );
924
925 assert!(
926 s!(:20).zip((0..20usize))
927 .all(|(a, b)| a == b)
928 );
929
930 assert!(
931 s!(:20:5).zip((0..20usize).step_by(5))
932 .all(|(a, b)| a == b)
933 );
934
935 assert!(
936 s!(::2).zip((0..).step_by(2).take(100))
937 .all(|(a, b)| a == b)
938 );
939
940 assert!(
941 s!(:).zip((0..).take(100))
942 .all(|(a, b)| a == b)
943 );
944 }
945}
946