Returning recursive function vs. returning variable that stores value of recursive function

Question:

These two functions are returning different results. They look identical to me. What is going on here?

def DFS(r, c, grid):
   if (r<0 or r>=len(grid) or c<0 or c>=len(grid[0])):
      return False
   if (grid[r][c] == 1):
      return True
      
      grid[r][c]=1
      return DFS(r+1, c, grid) and DFS(r-1, c, grid) and DFS(r, c+1, grid) and DFS(r, c-1, grid)

and

def DFS(r, c, grid):
   if (r<0 or r>=len(grid) or c<0 or c>=len(grid[0])):
      return False
   if (grid[r][c] == 1):
      return True
   grid[r][c] = 1

   down = DFS(r+1, c, grid)
   up = DFS(r-1, c, grid)
   right = DFS(r, c+1, grid)
   left = DFS(r, c-1, grid)
   return down and up and right and left

For example in this code block,

for r in range(len(grid)):
            for c in range(len(grid[0])):
                if (grid[r][c] == 0):
                    #print("searching", r, c)
                    if (DFS(r, c, grid) == True):
                        print([r,c])
                        result+=1
        return result

The two DFS functions will return different values when given this input:

[[0,0,1,1,0,1,0,0,1,0],[1,1,0,1,1,0,1,1,1,0],[1,0,1,1,1,0,0,1,1,0],[0,1,1,0,0,0,0,1,0,1],[0,0,0,0,0,0,1,1,1,0],[0,1,0,1,0,1,0,1,1,1],[1,0,1,0,1,1,0,0,0,1],[1,1,1,1,1,1,0,0,0,0],[1,1,1,0,0,1,0,1,0,1],[1,1,1,0,1,1,0,1,1,0]]

Thank you for your help!

Asked By: ML_201721

||

Answers:

The first version evaluates the last 4 calls to DFS using short-circuit evaluation: i.e., if the first DFS call in the return statement returns a falsey value, the and operator won’t even bother evaluating the next 3 DFS calls.

The last version explicitly evaluates all 4 DFS calls first, and only then evaluates the 4-way and.

I’m guessing that has an impact on how often and when the grid[r][c] = 1 line is executed, which would explain why they behave differently.

Answered By: Artie Vandelay

In the other answer there is a statement:

I’m guessing that has an impact on how often and
when the grid[r][c]=1 line is executed, which would explain why they behave differently.

This guess is right as proven by the code below where the second function is made equivalent to the first. The assert result_1 == result_2 not raising an assertion error shows that both functions work the same way now:

# These two functions are returning different results. 
# They look identical to me. What is going on here?
def DFS1(r, c, grid):
   if (r<0 or r>=len(grid) or c<0 or c>=len(grid[0])):
      return False
   if (grid[r][c] == 1):
      return True
      
   grid[r][c]=1

   return DFS1(r+1, c, grid) and DFS1(r-1, c, grid) and DFS1(r, c+1, grid) and DFS1(r, c-1, grid)
# The functions in your question were not equivalent. 
# The equivalent function to this above will be: 
def DFS2(r, c, grid):
    if (r<0 or r>=len(grid) or c<0 or c>=len(grid[0])):
       return False
    if (grid[r][c] == 1):
       return True

    grid[r][c] = 1

    if down:= DFS2(r+1, c, grid):
        if up:= DFS2(r-1, c, grid):
            if right:= DFS2(r, c+1, grid):
                if left:= DFS2(r, c-1, grid):
                    return True                    
                      # ^-- as (down and up and right and left) == True
    return False    
    #   ^-- as (down and up and right and left) == False
# For example in this code block,
result_1 = 0
grid = [[0,0,1,1,0,1,0,0,1,0],[1,1,0,1,1,0,1,1,1,0],[1,0,1,1,1,0,0,1,1,0],[0,1,1,0,0,0,0,1,0,1],[0,0,0,0,0,0,1,1,1,0],[0,1,0,1,0,1,0,1,1,1],[1,0,1,0,1,1,0,0,0,1],[1,1,1,1,1,1,0,0,0,0],[1,1,1,0,0,1,0,1,0,1],[1,1,1,0,1,1,0,1,1,0]]
for r in range(len(grid)):
    for c in range(len(grid[0])):
        if (grid[r][c] == 0):
            #print("searching", r, c)
            if (DFS1(r, c, grid) == True):
                print([r,c])
                result_1+=1

result_2 = 0
print(' --- ' )
grid = [[0,0,1,1,0,1,0,0,1,0],[1,1,0,1,1,0,1,1,1,0],[1,0,1,1,1,0,0,1,1,0],[0,1,1,0,0,0,0,1,0,1],[0,0,0,0,0,0,1,1,1,0],[0,1,0,1,0,1,0,1,1,1],[1,0,1,0,1,1,0,0,0,1],[1,1,1,1,1,1,0,0,0,0],[1,1,1,0,0,1,0,1,0,1],[1,1,1,0,1,1,0,1,1,0]]
for r in range(len(grid)):
    for c in range(len(grid[0])):
        if (grid[r][c] == 0):
            #print("searching", r, c)
            if (DFS2(r, c, grid) == True):
                print([r,c])
                result_2+=1

# These two DFS functions above will return the same values. 
assert result_1 == result_2
Answered By: Claudio
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.