I'm doing a sudoku solver and found this code online, which used a snimilar method to what I was doing, but I don't understand how grid[y][x] = 0 is able to be reached in this code since it calls solve(grid)in the line before.
I've noticed I get the same output if I put a else statement before it (and as well if it has on less indent)
def solve(grid):
for y in range(9):
for x in range(9):
if grid[y][x] == 0:
for n in range(1, 10):
if possible(y, x, n, grid):
grid[y][x] = n
solve(grid)
grid[y][x] = 0 # How is the program able to reach this code if it calls solve(grid) before it's able to be reached?
return
print(np.matrix(grid))
It is a recursive solution. Recursive means that the solve function calls itself. It continues it's code when the program returns from calling.
grid[y][x] = n # current solve changes grid
solve(grid) # call recursively solve
# the function solve has now returned
# and can have changed grid
grid[y][x] = 0 # now the current solve continues
This works because a list like grid is a mutable object which means that the called function can change grid and the caller continues with the changed grid.
There is one condition: there must be some condition inside solve so that after calling itself multiple times the last called solve returns.
Compare it with the well known Fibonacci function:
def F(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return F(n - 1) + F(n - 2)
print(F(6))
It stops calling itself when n==0 or n==1. Before that it keeps calling itself with n-1 and n-2.
I don't understand what bugs you - it's just a plain ordinary function call. Obviously a function can call another function, else we couldn't do much.
NB : what the name solve points to is resolved at runtime - the only thing happening at compile time here is that the generated byte-code knows it has to resolve the name solve and apply the call op to whatever this name resolves to.
Related
I found a basic code in python to find the numbers of paths you can take in a (m,n) grid if you can only go either down or right.
def gridtraveller(m,n):
if m == 0 or n == 0:
return 0
elif m == 1 or n == 1:
return 1
return gridtraveller(m-1,n) + gridtraveller(m,n-1)
But I dont understand why is this working for two thing:
What does def something (m,n) do ?
And why does here we return the definition ? ( I do understand why we return
m-1 and n-1 , but I don't understant the concepte of a def returning a def)
Thanks to you and sorry english is not my first language.
In Python the def keyword is simply used to define a function, in this case it's the function gridtraveller(m,n). What you're seeing with that last return statement is actually a function returning the value of another function. In this case it's returning the value of another call to gridtraveller, but with different parameter values; this is called recursion. An important part of recursion is having appropriate base cases, or return values that won't end in another recursive call(i.e. the return 0 or return 1 you see).
It can be easier to understand by simply stepping through a few iterations of the recursive calls. If your first function call starts with m = 2 and n = 1, the first call will end with return gridtraveller(1,1) + gridtraveller(2,0). The first call in that statement will then return 1 since either m or n are 1 and the second returns 0 since n = 0 here giving a total result of 1. If larger values of m and n are used it will obviously result in a higher number since more calls to gridtraver(m,n) will happen.
I'm so confused by backtracking because when the recursive call returns, won't you replace the solution found by replacing the grid back to zero. So even if you find the solution would it not be erased because after calling the solve function you are canceling what you did by replacing the value back to zero. I get the fact that you are backtracking but on the final recursive call that contains all the correct values are you not just replacing everything to 0?
# grid = ..... # defined as a global value,
# a list of 9 lists, 9-long each
def solve():
global grid
for y in range (0, 9):
for x in range (0, 9):
if grid[y][x] == 0:
for n in range(1,10):
if possible(y, x, n):
grid[y][x] = n
solve()
grid[y][x] = 0
return
# edit: missed this final line:
print (np.matrix(grid))
This was the code on Computerphile video by Prof. Thorsten Altenkirch.
This is weird code, but should work with some adaptations:
def solve():
global grid
for y in range(0, 9):
for x in range(0, 9):
if grid[y][x] == 0:
for n in range(1,10):
if possible(y, x, n):
grid[y][x] = n
if solve():
return True # return without reset
grid[y][x] = 0
return False # exhausted all options
return True # this is the deepest and last call with no more zeroes
Here is part of my code:
vlist = PossibleValueAtPosition(row,col) # find possible value at location (row, col)
for v in vlist: # try each possible value
puzzle[row][col] = v
if SolvePuzzle(n+1)==True: # n=81 means all filled then end loop
return True # if get a solution, you return True
puzzle[row][col] = 0 # if above return true, this line will never run
return False # return False for each fail attemp
Main program should like this
if SolvePuzzle(0)==True:
print(puzzle)
else:
print('No solution!')
It's not the final recursive call that contains all the correct values, but (each of) the deepest. Yes, this code enumerates all the solutions to the puzzle with the given board grid, not just the first solution.
For each (y,x) place, if it's empty, we try to place there each of the numbers from 1 through 9 in turn. If the placement was possible on the board as it is so far, we recurse with the changed grid board.
At the deepest level of recursion there were no empty (y,x) places on the board. Therefore we slide through to the print statement. (It could also be replaced by yield True for example, to turn it into a generator. On each next value we'd get from that generator, we'd have a complete solution -- in the changed grid. And when the generator would get exhausted, the grid would be again in its original state.)
When all the numbers from 1 through 9 have been tried, the current invocation has run its course. But the one above it in the recursion chain is waiting to continue its work trying to fill its (y,x) position. We must let it work on the same board it had before it invoked this invocation of solve(). And the only change on the board this invocation did was to change its (y,x) position's value from 0 to 1 through 9. So we must change it back to 0.
This means that the code could be restructured a little bit too, as
def solve():
global grid
for y in range (0, 9):
for x in range (0, 9): # for the first
if grid[y][x] == 0: # empty slot found:
for n in range(1,10): # try 1..9
if possible(y, x, n):
grid[y][x] = n
solve() # and recurse
# (move it here)
grid[y][x] = 0 # restore
return # and return
# no empty slots were found:
# we're at the deepest level of recursion and
# there are no more slots to fill:
yield True # was: print (np.matrix(grid))
Each invocation works only on one (y,x) location, the first empty position that it found by searching anew from the start on the changed board. This search is done by the first two nested loops on y and on x. That is a bit redundant; we know all the positions before this (y,x) are already filled. The code would be better restructured to pass the starting position (y,x) as a parameter to solve.
The paradigm of recursive backtracking is beautiful. Prolog is full of mystique, Haskell will dazzle you with cryptic monads talk (monads are actually just interpretable nestable data), but all it takes here are some nested loops, recursively created!
The paradigm is beautiful, but this code, not so much. A code's visual structure should reflect its true computational structure, but this code gives you an impression that the y-x- loops are the nested loops at work to create the backtracking structure, and they are not (they just implement a one-off linear search for the next empty space in the top-down left-to-right order).
That role is fulfilled by the n in range(1,10) loops. The y-x- loops should be stopped and exited explicitly when the empty space is found, to truly reflect in the code structure what is going on computationally, to make it apparent that the n in range(1,10) loop is not nested inside the y-x- loops, but comes in play after they finish their job.
Another problem is that it just assumes the validity of the numbers given to us in the grid before the very first call to solve(). That validity is never actually checked, only the validity of the numbers which we are placing in the empty cells is checked.
(note: previous versions of this answer were based on an erroneous reading of the code. there were some valid parts in them too. you can find them on the revisions list here).
I'm doing a quiz from "Automate the Boring Stuff with Python", and after tinkering with the problem for a bit, I finally found a solution that worked (with a little help from a comp-sci buddy of mine). The quiz asks me to make program that executes a Collatz-sequence.
I understand the logic behind all of the code, EXCEPT for the final line.
Here's my code with a few comments:
def collatz(number):
if number % 2 == 0:
print(number // 2)
return number // 2
elif number % 2 == 1:
print(3 * number + 1)
return 3 * number + 1
guess = input("Your guess please ")
while guess != 1:
guess = collatz(int(guess))
The output of the program is a sequence of numbers, as the while-loop somehow re-iterates over the returned value of the function, and uses that for another computation.
My problem is with the last line. Here's how I understand it:
Once I enter the while-loop, my function "collatz" is called, using my input-value
The function is run, and my input is computed, and based on the input, I get either the even or odd calculation in return
Here's where my brain hurts!
Is the line "guess = collatz(...)" now constantly updating "guess" to be equal to the retuned value from the function? If this is the case, then I completely understand the flow. If it's not the case, then I don't understand how the returned value is constantly being used for new calculations.
Also, is this what is called "recursion"?
Short answer:
Yes.
Longer answer: (still short)
The collatz function is returning a value which is assigned to guess.
Also, this is not called recursion, recursion is a function which calls itself.
First, no, this is not a recursion. Recursion is a function that calls itself.
For instance this is a recursion:
def fibonacci(n):
if n == 0:
return 0
if n == 1:
return 1
return fibonacci(n-1) + fibonacci(n-2)
As you can see here fibonacci function will call fibonacci function ... But it also has an exit condition (n == 0, and n == 1). Without that, this would cause runtime error with message that maximum recursion depth exceeded. But if I am not mistaken, you can check what is the maximum depth of recursion with following command:
import sys
print(sys.getrecursionlimit())
On my computer, this number is 1000. If this number is to small for you, you can also set it with this command:
sys.setrecursionlimit(n)
About other thing. Your function is returning some calculated value and in your main loop, this is assigned to variable guess. So everytime, that main loop will go through, value of guess will also update
This question regarding exercise 5.5 from Think Python 2 has been asked and answered already, but I still don't understand how this function works. Here's the function in question:
def draw(t, length, n):
if n == 0:
return
angle = 50
t.fd(length*n)
t.lt(angle)
draw(t, length, n-1)
t.rt(2*angle)
draw(t, length, n-1)
t.lt(angle)
t.bk(length*n)
I see a recursive loop here:
def draw(t, length, n):
if n == 0:
return
angle = 50
t.fd(length*n)
t.lt(angle)
draw(t, length, n-1)
After the function calls itself a sufficient number of times to cause n == 0, how does it move on to the next step, namely t.rt(2*angle)? Once n == 0, shouldn't the function return None and simply end? If not, where is returning to? The same thing happens again the next time it calls itself, and then the function continues to perform work long after the state n == 0 has been satisfied (twice!). I'm obviously missing a key concept here and would appreciate any light anyone can shed on this topic. Thanks in advance~
The return statement returns execution of the program back to the line where the function that returned was called.
If you're not familiar with what a call stack is, think of it as a stack of functions - whenever something gets called, it's placed on top of the stack and that's what's running. When that returns, it's removed from the stack and so the function that called it (one below in the stack) is now the top, so that's where execution picks up again.
That particular function will return when n == 0 (so that's your base case), so once its recursive call draw(t, length, n-1) - and, by consequence, its subsequent recursive calls, since it won't finish execution until they do - reach that point, it'll move over to the next line.
Take a simpler function foo(sum, n) instead:
def foo(sum, n):
if (n == 0):
return sum
sum += foo(sum, n-1)
sum /= 2
return foo(sum, n-1)
Whenever you call that, it won't move from sum += foo(sum, n-1) until that call and all of the recursive calls made return. This function is structurally comparable to the one you showed and it might help you visualize a little better what's going on.
I've posted a picture explaining this in the following question , for a fast navigation here's my picture :
I'm trying to halt the for loop below once values (x,y) or (z,2) have been returned so that the value i doesn't keep increasing, and simply halts when the if or elif condition is first
def maxPalindrome(theList):
# students need to put some logic here
maxcomplist = theList[:]
maxcomplist.reverse()
control = len(theList) - 1
# exit if maxPalindrome is True
for i in range(control):
if maxcomplist[:] == theList[:]:
x = 0
y = len(theList)
return (x, y)
break
elif maxcomplist[i:control] == theList[i:control]:
successList = theList[i:control]
z = i
w = len(theList) - z - 1
return (z, w)
How can I accomplish this?
As I wrote in a comment already: that function isn't a recursive one at all.
Recursion means, that a function calls itself to complete it's purpose. This call can be indirect, meaning that the function uses helper function that will call the first function again.
But your code doesn't cover both cases.
A recursive function always have a certain architecture:
the first thing after being called should be to test, if the primitive case (or one primitive case among options) has been reached. if so, it returns.
If not it will compute whatever is needed and pass this results to itself again,
untill the primitive case is reached, and the nested function calls will finish in one after the other.
One well-known usage of recursion is the quicksort algorithm:
def quicksort(alist):
if len(alist) < 2:
return alist # primitive case: a list of size one is ordered
pivotelement = alist.pop()
# compute the 2 lists for the next recursive call
left = [element for element in alist if element < pivotelement]#left = smaller than pivotelemet
right = [element for element in alist if element >= pivotelement]#left = greater than pivotelemet
# call function recursively
return quicksort(left) + [pivotelement] + quicksort(right)
So the "stop" must be the return of a primitive case. This is vital for recursion. You cannot just break out somehow.
I don't understand the question - if I get it right, that what you want already happens. If you return, the function stops running.
Some comments in addition to this answer:
As well, I cannot see where the function is called recursively, nor what
exit if maxPalindrome is True
means. (Is this a comment, maybe?)
Besides, the maxcomplist[:]==theList[:] does not make much sense to me, and seem to be a waste of time and memory, and to have this comparison in each iteration loop doesn't make it faster as well.