# Set min value of each row of a tensor to zero without using explicit loops

Here's the problem.

Return a copy of x, where the minimum value along each row has been set to 0.

For example, if x is:

x = torch.tensor([[
[10, 20, 30],
[ 2,  5,  1]
]])


Then y = zero_row_min(x) should be:

torch.tensor([
[0, 20, 30],
[2,  5,  0]
])


Your implementation should use reduction and indexing operations; you should not use any explicit loops. The input tensor should not be modified.

Inputs:

• x: Tensor of shape (M, N)

Returns:

• y: Tensor of shape (M, N) that is a copy of x, except the minimum value along each row is replaced with 0.

It has been hinted at that clone and argmin should be used.

I'm having trouble understanding how to do this without a loop and my current code below (although it gets the problem right) is crude. I'm looking for a better way to solve this problem.

  x0 = torch.tensor([[10, 20, 30], [2, 5, 1]])
x1 = torch.tensor([[2, 5, 10, -1], [1, 3, 2, 4], [5, 6, 2, 10]])

func(x0)
func(x1)

def func(x):

y = None

# g = x.argmin(dim=1)

g = x.min(dim=1)

if x.shape == 2:
x[0,:][g] = 0
x[1,:][g] = 0
elif x.shape == 3:
x[0,:][g] = 0
x[1,:][g] = 0
x[2,:][g] = 0

y = x

return y

• The idea should be copy_of_array[argmin_indices] = 0. Sep 1 at 16:21
• Can you provide expected shape for each of your variables? e.g. (1000, 2, 12) or whatever. Sep 1 at 17:33
• @Reinderien Sure, x0 = torch.tensor([[10, 20, 30], [2, 5, 1]]) and x1 = torch.tensor([[2, 5, 10, -1], [1, 3, 2, 4], [5, 6, 2, 10]]). I've added them to the original post for clarification as well.
– Ryan
Sep 1 at 17:44
• @Andrew I believe that's similar to the way I went about solving it. It works, but I have to manually iterate over each row to mutate the min() value.
– Ryan
Sep 1 at 17:55

Not much of a code review, but this should work:

def zero_min(x):
y = x.clone()
y[torch.arange(x.shape), torch.argmin(x, dim=1)] = 0
return y


In each row, if the minimum is not unique, then only the occurrence with the smallest index will be zeroed out.

To zero out all the occurrences, you could do something like the following:

def zero_em_all_min(x):
y = x.clone()
y[x == x.min(dim=1, keepdims=True).values] = 0
return y

• Thanks, didn't think to use torch.arange to iterate through the rows. I'll ask on regular SE in the future.
– Ryan
Sep 1 at 18:24
• @Ryan I'm happy it could be answered, but perhaps that is indeed the better platform for a similar question! Sep 1 at 18:26