1. Tensor 索引简介¶

y = paddle.slice(x, [0,1], [0,2], [1,4], decrease_axes=[1])
· x[0, 2:3] = Tensor(1.0)

· x[[0,1], [2,3]] = Tensor(1.0)

· x[0, [0,2], ..., 2:5:2, None] = 1.0

```x[(index_1, index_2, ..., index_n)] == x[index_1, index_2, ..., index_n] != x[[index_1, index_2, ..., index_n]]
```

2. 基础索引(Basic Index)¶

2.1 简介¶

• 单个整形或整形的 0-D `Tensor/Ndarray`

• Python `slice`对象，即 `start:end``start:end:step`，如果取所有元素，可以简写为`:``::`

• Python `Ellipsis`对象，即`...`

• Python `None`类型

```# In Paddle dynamic mode
>>> a
[[1., 1., 1.],
[1., 1., 1.]])
>>> b = a[0]   # b is a view of a
>>> b
[1., 1., 1.])
>>> b[1] = 10  # modifacation of b will affect a
>>> b
[1. , 10., 1. ])
>>> a
[[1. , 10., 1. ],
[1. , 1. , 1. ]])
```

2.2 单个整形或整形的 0-D Tensor/Ndarray¶

```>>> a = paddle.arange(6).reshape((2,3))
>>> a
[[0, 1, 2],
[3, 4, 5]])
>>> b = a[1]  # select the second row in first axis
>>> b
[3, 4, 5])
>>> c = a[-1] # select the last row in first axis
>>> c
[3, 4, 5])
```

```>>> d = a[1, 0]
>>> d
3)
```

```>>> b = a[1]
>>> b
[3, 4, 5])

>>> index = paddle.full([], 1, dtype='int32')
>>> c = a[index]
>>> c
[3, 4, 5])
```

2.3 Python `slice`对象¶

`slice`对象由 start/end/step 定义，这个场景与 Python 原生类型的索引规则类似，表示在对应轴上的起始-结束区间`[start, end)`内，根据指定的步长`step`进行切片选取。对于 start/end/step 同样可以是对应的 0-D Tensor/Ndarray，也可以是负数。当为负数时，start/end 表示从对应轴的最后开始计数，step 为负数时，表示逆序选取。在取值场景中，该轴对应的维度将被保留，大小为选取到的元素数量。

```>>> a = paddle.arange(8).reshape((4,2))
>>> a
[[0, 1],
[2, 3],
[4, 5],
[6, 7]])
>>> b = a[0:2]  # select elements [0, 2) with step 1 in first axis
>>> b
[[0, 1],
[2, 3]])
>>> c = a[::2]  # select elements [0, 4) with step 2 in first axis
>>> c
[[0, 1],
[4, 5]])
>>> d = a[::-1] # reversed selection in first axis
>>> d
[[6, 7],
[4, 5],
[2, 3],
[0, 1]])
```

2.4 Python `Ellipsis`对象¶

```>>> a = paddle.arange(8).reshape((2,2,2))
>>> a
Tensor(shape=[2, 2, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[0, 1],
[2, 3]],

[[4, 5],
[6, 7]]])
>>> b = a[...] # ... covers axes 0,1,2, equals a[:,:,:], which means select all elements
>>> b
Tensor(shape=[2, 2, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[0, 1],
[2, 3]],

[[4, 5],
[6, 7]]])
>>> c = a[1, ...]  # ... covers axes 1,2, equals a[1,:,:]
>>> c
[[4, 5],
[6, 7]])
>>> d = a[1, ..., 0] # ... covers axis 1, equals a[1,:,0]
>>> d
[4, 6])
```

2.5 Python `None`类型¶

`None`（或`np.newaxis`类型，两者实质是相同的），通常在取值场景中使用，表示取值的结果在对应位置扩展大小为 1 的维度。

```>>> a = paddle.arange(8).reshape((2,4))
>>> a
[[0, 1, 2, 3],
[4, 5, 6, 7]])
>>> b = a[:, None]
>>> b
Tensor(shape=[2, 1, 4], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[0, 1, 2, 3]],

[[4, 5, 6, 7]]])
```

3.1 简介¶

• 整形数组：即非 0-D 的`Tensor/Ndarray`或 Python `List`

• bool 类型的`Tensor/Ndarray`或 Python `List`

• Python `bool`

• 至少包含一个上述类型的 Python `Tuple`

```>>> a = paddle.ones((2,3))
>>> a
[[1., 1., 1.],
[1., 1., 1.]])
>>> b = a[[0]] # b is not a view of a
>>> b
[[1., 1., 1.]])
>>> b[0] = 10  # modify b will not affect a
>>> b
[[10., 10., 10.]])
>>> a
[[1., 1., 1.],
[1., 1., 1.]])
```

3.2 整形数组索引¶

```>>> a = paddle.arange(8).reshape((4,2))
>>> a
[[0, 1],
[2, 3],
[4, 5],
[6, 7]])
>>> b = a[[0,2,1]]  # select rows 0,2 and 1 in first axis
>>> b
[[0, 1],
[4, 5],
[2, 3]])

>>> c = a[np.array([0,1,0])]  # row 0 was selected twice
>>> c
[[0, 1],
[2, 3],
[0, 1]])

>>> d = a[index]  # select rows 1 and 2 in first axis, and combine them according `index`
>>> d
Tensor(shape=[2, 1, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[2, 3]],

[[4, 5]]])

>>> e = a[[2,0,3],[1,0,0]] # select a[2,1], a[0,0] and a[3,0]
>>> e
[5, 0, 6])
```

```output[i_1, ..., i_m] == x[index_1[i_1, ..., i_m], index_2[i_1, ..., i_m],
..., index_n[i_1, ..., i_m]]
```

```>>> f = a[[0,2,1], [0]]
>>> f
[0, 4, 2])
```

```>>> g = a[[0,2,1], [0,1]]  # shape (3,) and (2,) cannot be broadcast together
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/dist-packages/paddle/base/dygraph/tensor_patch_methods.py", line 992, in __getitem__
return self._getitem_dygraph(item)
ValueError: (InvalidArgument) Broadcast dimension mismatch. Operands could not be broadcast together with the shape of X = [2] and the shape of Y = [3]. Received [2] in X is not equal to [3] in Y at i:0.
[Hint: Expected x_dims_array[i] == y_dims_array[i] || x_dims_array[i] <= 1 || y_dims_array[i] <= 1 == true, but received x_dims_array[i] == y_dims_array[i] || x_dims_array[i] <= 1 || y_dims_array[i] <= 1:0 != true:1.] (at /workspace/workspace2/Paddle/paddle/fluid/operators/common_infer_shape_functions.cc:80)
```

3.3 布尔索引¶

3.3.1 index 为 bool 的 Tensor/Ndarray/List 等类型¶

`index``bool`类型的 Tensor/Ndarray/List 等类型时，要求在形状上满足下列条件：

• `index`的 rank 小于或等于被索引的 Tensor 的 rank

• `index`的所有轴均与被索引的 Tensor 在对应维度上大小一致

```# nonzero() returns the index of the non-zero elements on each axis

>>> a
[[0, 1],
[2, 3],
[4, 5],
[6, 7]])
>>> bool_mask = a > 4  # nonzero results are [2,1], [3,0] and [3,1]
[5, 6, 7])

>>> a[[True, False,True,False]]  # select row 0 and 2 in first axis
[[0, 1],
[4, 5]])
```

3.3.2 index 为 Python bool 类型¶

`index`是一个单独的 Python `bool`类型时，等价于额外添加一个维度，再根据`index`进行选择，即满足：

```x[py_bool_index] == x.unsqueeze(0)[[py_bool_index]]

>>> a
[[0, 1],
[2, 3],
[4, 5],
[6, 7]])
>>> a[True]
Tensor(shape=[1, 4, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[0, 1],
[2, 3],
[4, 5],
[6, 7]]])
>>> a[False]   # output is 0-Size Tensor
Tensor(shape=[0, 4, 2], dtype=int64, place=Place(cpu), stop_gradient=True,
[])
```

4. 联合索引（Combined Indexing）¶

4.1 联合索引的基本计算逻辑¶

```>>> a = paddle.arange(24).reshape((2,3,4))
>>> a
Tensor(shape=[2, 3, 4], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[0 , 1 , 2 , 3 ],
[4 , 5 , 6 , 7 ],
[8 , 9 , 10, 11]],

[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]])
>>> b = a[0,[1,2],2]   # This is same with (1) tmp = a[0,:,2] (2) b = tmp[[1,2]]
>>> b
[6 , 10])
```

4.2 多个高级索引时的计算逻辑¶

`index`中同时存在多个高级索引类型时，同样会通过 3.2 节介绍的广播规则确定最终的输出的大小。此外，在取值场景下，还需要额外考虑这些高级索引类型是否相邻，来确定最后输出所处的维度位置。

场景 1-高级索引位置相邻¶

```>>> a = paddle.arange(24).reshape((1,2,3,4))
>>> a
Tensor(shape=[1, 2, 3, 4], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[[0 , 1 , 2 , 3 ],
[4 , 5 , 6 , 7 ],
[8 , 9 , 10, 11]],

[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]]])

>>> b = a[:, [0,0,1], [1,2,0],:] # the new dimention is at axis 1
>>> b
Tensor(shape=[1, 3, 4], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[4 , 5 , 6 , 7 ],
[8 , 9 , 10, 11],
[12, 13, 14, 15]]])

>>> c = a[:,[0,0,1], [1,2,0], [2,1,0]]
>>> c
[[6 , 9 , 12]])
```

场景 2-高级索引位置不相邻¶

```>>> d = a[:, [1], :, [2,1,0]] # advanced indexes are not adjacent, the new dimention is at axis 0
>>> d
Tensor(shape=[3, 1, 3], dtype=int64, place=Place(cpu), stop_gradient=True,
[[[14, 18, 22]],

[[13, 17, 21]],

[[12, 16, 20]]])
```

5. 针对赋值的额外说明¶

5.1 赋值操作的规则¶

• Python Scalar (如 float / int / complex 等)

• 0-D Tensor/Ndarray，表示 Scalar 语义

• 非 0-D 的 Tensor/Ndarray，要求`value`的形状可广播到`x[index]`取值结果的形状

```>>> a = paddle.ones((2,3,4))
>>> a[:,:,2] = 10  # value is Python Scalar
>>> a
Tensor(shape=[2, 3, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
[[[1. , 1. , 10., 1. ],
[1. , 1. , 10., 1. ],
[1. , 1. , 10., 1. ]],

[[1. , 1. , 10., 1. ],
[1. , 1. , 10., 1. ],
[1. , 1. , 10., 1. ]]])

>>> a[:,:,1] = paddle.full([], 2) # value is 0-D Scalar Tensor
>>> a
Tensor(shape=[2, 3, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
[[[1. , 2. , 10., 1. ],
[1. , 2. , 10., 1. ],
[1. , 2. , 10., 1. ]],

[[1. , 2. , 10., 1. ],
[1. , 2. , 10., 1. ],
[1. , 2. , 10., 1. ]]])

>>> a[:,:,3] = paddle.full([2,1], 5) # value is a Tensor with shape [2,1], which can be broadcast to [2,3]
>>> a
Tensor(shape=[2, 3, 4], dtype=float32, place=Place(cpu), stop_gradient=True,
[[[1. , 2. , 10., 5. ],
[1. , 2. , 10., 5. ],
[1. , 2. , 10., 5. ]],

[[1. , 2. , 10., 5. ],
[1. , 2. , 10., 5. ],
[1. , 2. , 10., 5. ]]])

>>> a[:,:,3] = paddle.full([2,4], 5) # value is a Tensor with shape [2,4], which cannot be broadcast to [2,3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/dist-packages/paddle/base/dygraph/tensor_patch_methods.py", line 996, in __setitem__
return self._setitem_dygraph(item, value)
ValueError: (InvalidArgument) The shape of tensor assigned value must match the shape of target shape: [2, 4], but now shape is [2, 3].
```

```>>> paddle.enable_static()
>>> a[0] = 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/dist-packages/paddle/base/framework.py", line 2585, in __setitem__
raise RuntimeError(
RuntimeError: In static mode, the __setitem__ (looks like: x[indices] = values) should not be used. Please use x = paddle.static.setitem(x, indices, values)

>>> b
var set_value_0.tmp_0 : LOD_TENSOR.shape(2, 3, 4).dtype(float32).stop_gradient(True)
```

5.3 不同数据类型时的行为¶

```>>> a = paddle.ones((2,3,4), dtype='int32')
>>> a[0] = 2.5  # the value is truncated since float is casted to int
>>> a
Tensor(shape=[2, 3, 4], dtype=int32, place=Place(cpu), stop_gradient=True,
[[[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]],

[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]])