Skip to content

← Broadcasting step 1 of 6

Easy Primitives

A stride of zero

Jump to the task

To reuse one row across a matrix, you can expand a view or repeat the data into a new buffer:

import torch

v = torch.arange(4).reshape(1, 4)
a = v.expand(3, 4)
b = v.repeat(3, 1)
print(a.tolist())  # [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
print(torch.equal(a, b))  # True
print(a.stride())  # (0, 1)
print(b.stride())  # (4, 1)
print(a.untyped_storage().data_ptr() == v.untyped_storage().data_ptr())  # True
print(b.untyped_storage().data_ptr() == v.untyped_storage().data_ptr())  # False

How a zero stride repeats values

Moving along an axis with stride zero does not advance through storage. Every row of a therefore reads the same four integers. The expanded view needs metadata, but no repeated data buffer.

An existing axis can grow through expand only if its size is one. Other axes must keep their size. expand can also add leading axes. Use -1 to keep an existing axis's size, as in v.expand(3, -1).

If the requested row count is one, that axis is not enlarged and its original stride is retained. This boundary case appears in the tests.

Broadcasting often needs no explicit expansion

For elementwise arithmetic, you can usually let broadcasting reuse values implicitly. Adding a (1, cols) bias to a (rows, cols) tensor does not require calling repeat first. Zero strides help explain value reuse, but do not imply that every backend implements broadcasting identically. The arithmetic operation may still allocate its result.

Expanded views are not independent writable rows

Expanded entries can refer to the same location. Assigning a single entry can therefore change the original row and every expanded entry that refers to it. Some bulk in-place operations, such as adding to an overlapping expanded view, raise an error. Do not assume all writes are rejected.

If you need independent writable values, create a copy with repeat or clone the expanded view. Choose based on whether storage sharing is wanted, not on a rule that one operation is always better.

Your task

def broadcast_row(v: torch.Tensor, rows: int) -> torch.Tensor

The harness supplies a contiguous tensor v of shape (1, cols) with cols > 0 and rows >= 1. Return shape (rows, cols) with every row equal to v, sharing its storage. The row stride must be zero when rows > 1; when rows == 1, retain the original row stride. The starter repeats the data into a separate buffer.