Skip to content

← Indexing and Selection step 2 of 9

Medium Primitives

Pick columns for each row

Jump to the task

Each row of a matrix can request its own list of columns. gather reads those positions without a Python loop over the elements.

import torch

src = torch.tensor([[0.0, 1.0, 2.0, 3.0], [4.0, 5.0, 6.0, 7.0]])
idx = torch.tensor([[3, 0], [1, 2]], dtype=torch.long)
print(torch.gather(src, 1, idx).tolist())  # [[3.0, 0.0], [5.0, 6.0]]

The first row selects columns 3 and 0; the second selects columns 1 and 2. The order and any repeated indices are preserved.

Read the shape rule

For dim=1, the output satisfies:

out[r, c] = src[r, idx[r, c]]

src and idx must have the same rank. In this exercise they have the same number of rows, while the number of requested columns can differ from the source width. The output shape equals idx.shape. Each index must name a valid source column.

A slice selects a shared interval or stride pattern. Gather is useful when rows need different choices, including repeated or reordered columns. For these matching row dimensions, take_along_dim can produce the same values, but its broadcasting and dispatch behavior need not be identical.

Why replace the loop

The starter computes the requested values on the CPU inputs, but repeated indexing and assignment dispatch many tensor operations. Gather expresses the selection as one tensor operation. This reduces Python-level overhead; it does not imply that every dispatch launches a GPU kernel or synchronizes a device. Those costs depend on the backend and operation.

Your task

def pick(src: torch.Tensor, idx: torch.Tensor) -> torch.Tensor

src is a two-dimensional CPU float32 tensor. idx is a two-dimensional int64 tensor with the same number of rows and valid nonnegative column indices. Return src[r, idx[r, c]] at every output position.

Use at most two operations counted by the harness's TorchDispatchMode. This checks dispatched tensor operations inside your function, not runtime or GPU kernel count.