def tile_tensor(tensor, n, dim):
    """Replicate tensor n times along dim, without allocating memory (using torch.expand)"""

    assert 0 <= dim < len(tensor.shape), "dim must be a dimension of the given tensor"

    # this function works by unsqueezing tensor at dim (which will have size 1 and can therefore be expanded),
    # expanding dim by n, and reshaping it to the final shape, which is the original shape multiplied by n at dim.
    number_of_dimensions_after_unsqueezing = len(tensor.shape) + 1
    expand_at_dim_arg = [-1] * number_of_dimensions_after_unsqueezing
    expand_at_dim_arg[dim] = n
    final_shape = list(tensor.shape)
    final_shape[dim] *= n
    return tensor.unsqueeze(dim).expand(*expand_at_dim_arg).reshape(*final_shape)