Skip to content

← Memory, Copies and In-Place step 3 of 6

Easy Primitives

Fill the caller's buffer

Jump to the task

Assigning to a function parameter changes what its local name refers to. It does not replace or modify the caller's tensor:

import torch

def rebind(buf, values):
    buf = values

buf = torch.zeros(3)
values = torch.tensor([1.0, 2.0, 3.0])
rebind(buf, values)
print(buf.tolist())  # [0.0, 0.0, 0.0]

To change the caller's tensor, write into its existing storage. PyTorch's copy_() method does this; the trailing underscore indicates an in-place operation.

buf.copy_(values)
print(buf.tolist())  # [1.0, 2.0, 3.0]

The destination determines the result

copy_() keeps the destination's shape, dtype and device. It converts source values to the destination dtype and transfers them between devices if needed. Dtype conversion can lose precision.

The source must have a shape that can broadcast to the destination. For example, one value can fill a longer buffer:

buf = torch.zeros(3)
buf.copy_(torch.tensor([7.0]))
print(buf.tolist())  # [7.0, 7.0, 7.0]

For the one-dimensional tensors in this exercise, buf[:] = values also writes into the existing storage. That slice syntax is not a universal replacement for copy_(): a zero-dimensional tensor cannot be sliced with [:].

Where this is useful

Use in-place copying when other code holds a reference to the destination and needs to see the update, such as a preallocated output buffer. A custom optimizer can also update an existing parameter under torch.no_grad(). Rebinding a local parameter name would leave the model's parameter unchanged. In-place writes must still respect autograd's rules; this exercise uses buffers that do not require gradients.

Your task

def fill(buf: torch.Tensor, values: torch.Tensor) -> None

Write values into buf without replacing its storage. Return None. The test inputs are one-dimensional float32 tensors with matching shapes, and neither tensor requires gradients. The caller checks buf after the function returns.