--- myst: html_meta: description: Tensor indexing in PyTorch C++ — Slice, None, Ellipsis, boolean masks, and advanced indexing with index() and index_put_(). keywords: PyTorch, C++, tensor indexing, Slice, index, index_put_, boolean mask, fancy indexing --- # Tensor Indexing The PyTorch C++ API provides tensor indexing similar to Python. Use `torch::indexing` namespace for index types: ```cpp using namespace torch::indexing; ``` The main difference from Python is that instead of using the `[]` operator, the C++ API uses the `index` and `index_put_` methods: - `torch::Tensor::index` — read elements - `torch::Tensor::index_put_` — write elements ## Index Types The `TensorIndex` class accepts six types of indices via implicit constructors: ```{list-table} :widths: 25 35 40 :header-rows: 1 * - Type - C++ - Python equivalent * - None (unsqueeze) - `None` - `None` * - Ellipsis - `Ellipsis` or `"..."` - `...` * - Integer - `0`, `1`, `-1` - `0`, `1`, `-1` * - Boolean - `true`, `false` - `True`, `False` * - Slice - `Slice(start, stop, step)` - `start:stop:step` * - Tensor - `torch::tensor({0, 2})` - `torch.tensor([0, 2])` ``` ## Getter Operations ```{list-table} :widths: 40 60 :header-rows: 1 * - Python - C++ * - `tensor[0]` - `tensor.index({0})` * - `tensor[-1]` - `tensor.index({-1})` * - `tensor[1, 2]` - `tensor.index({1, 2})` * - `tensor[1, :, 3]` - `tensor.index({1, Slice(), 3})` * - `tensor[None]` - `tensor.index({None})` * - `tensor[:, None]` - `tensor.index({Slice(), None})` * - `tensor[...]` - `tensor.index({Ellipsis})` or `tensor.index({"..."})` * - `tensor[..., 0]` - `tensor.index({Ellipsis, 0})` * - `tensor[1::2]` - `tensor.index({Slice(1, None, 2)})` * - `tensor[True]` - `tensor.index({true})` * - `tensor[torch.tensor([1, 2])]` - `tensor.index({torch::tensor({1, 2})})` * - `tensor[bool_mask]` - `tensor.index({bool_mask})` * - `tensor[:, torch.tensor([[0,1],[4,3]])]` - `tensor.index({Slice(), torch::tensor({{0,1},{4,3}})})` * - `tensor[cond > 0]` - `tensor.index({cond > 0})` ``` ## Setter Operations ```{list-table} :widths: 40 60 :header-rows: 1 * - Python - C++ * - `tensor[0] = 1` - `tensor.index_put_({0}, 1)` * - `tensor[1, 2] = 1` - `tensor.index_put_({1, 2}, 1)` * - `tensor[1] = torch.arange(5)` - `tensor.index_put_({1}, torch::arange(5))` * - `tensor[1::2] = 1` - `tensor.index_put_({Slice(1, None, 2)}, 1)` * - `tensor[0, 1::2] = torch.tensor([3., 4.])` - `tensor.index_put_({0, Slice(1, None, 2)}, torch::tensor({3., 4.}))` * - `tensor[...] = 0` - `tensor.index_put_({Ellipsis}, 0)` * - `tensor[None] = value` - `tensor.index_put_({None}, value)` * - `tensor[bool_mask] = 0` - `tensor.index_put_({bool_mask}, 0)` * - `tensor[torch.tensor([0, 2])] = value` - `tensor.index_put_({torch::tensor({0, 2})}, value)` * - `tensor[1:2, torch.tensor([1,2])] = 0` - `tensor.index_put_({Slice(1, 2), torch::tensor({1, 2})}, 0)` ``` The `index_put_` method also accepts an optional `accumulate` parameter. When `true`, values are added to existing values instead of replacing them: ```cpp tensor.index_put_({mask}, values, /*accumulate=*/true); ``` ## Slice Syntax The `Slice` constructor signature is: ```cpp Slice( std::optional start = std::nullopt, std::optional stop = std::nullopt, std::optional step = std::nullopt); ``` Pass `None` for open-ended bounds: ```{list-table} :widths: 30 70 :header-rows: 1 * - Python - C++ * - `:` or `::` - `Slice()` or `Slice(None, None)` * - `1:` - `Slice(1, None)` * - `:3` - `Slice(None, 3)` * - `1:3` - `Slice(1, 3)` * - `1:3:2` - `Slice(1, 3, 2)` * - `::2` - `Slice(None, None, 2)` ``` ## Full Example ```cpp #include using namespace torch::indexing; auto tensor = torch::arange(2 * 3 * 4).reshape({2, 3, 4}); // Basic indexing auto row = tensor.index({0}); // tensor[0] auto elem = tensor.index({1, 2, 3}); // tensor[1, 2, 3] // Slicing auto sliced = tensor.index({Slice(), Slice(0, 2)}); // tensor[:, 0:2] // None (unsqueeze) and Ellipsis auto unsqueezed = tensor.index({None}); // tensor[None] auto last_dim = tensor.index({Ellipsis, -1}); // tensor[..., -1] // Boolean mask indexing auto mask = tensor > 10; auto selected = tensor.index({mask}); // tensor[tensor > 10] // Integer tensor (fancy) indexing auto idx = torch::tensor({0, 2}); auto gathered = tensor.index({Slice(), idx}); // tensor[:, [0, 2]] // Setting values tensor.index_put_({0, Slice(), 0}, 99); // tensor[0, :, 0] = 99 tensor.index_put_({mask}, 0); // tensor[tensor > 10] = 0 ```