I've implemented backtracking algorithm in python to solve a sudoku. During the steps of the algorithm I check, if the sudoku is already solved and when it is, I want to return it. But my function just returns None. Can someone explain me the reason for this and give me a hint for the solution?
#Test-Sudoku
grid = [[1,0,7,0,0,5,4,0,0],
[9,0,0,3,7,0,0,0,0],
[0,2,3,0,8,0,0,0,0],
[0,9,2,0,0,0,0,7,0],
[0,7,0,0,6,0,0,1,0],
[0,6,0,0,0,0,8,9,0],
[0,0,0,0,4,0,3,6,0],
[0,0,0,0,3,7,0,0,1],
[0,0,8,2,0,0,5,0,7]]
def possible(row,col,num,grid):
""" Check if num can be passed to grid[row][col]"""
if grid[row][col] != 0:
return False
for i in range(9):
if grid[row][i] == num or grid[i][col] == num:
return False
row0 = (row//3)*3
col0 = (col//3)*3
for i in range(3):
for j in range(3):
if grid[row0+i][col0+j] == num:
return False
return True
def is_solved(grid):
""" Check if Sudoku is already solved/full"""
for i in range(9):
for j in range(9):
if grid[i][j] == 0:
return False
return True
def solve(grid):
""" Backtracking algorithm to solve Sudoku"""
for r in range(9):
for c in range(9):
if grid[r][c] == 0:
for i in range(1,10):
if possible(r, c, i, grid):
grid[r][c] = i
if is_solved(grid):
# Print grid for test
print("Show Solved Sudoku:")
print(grid)
return(grid)
solve(grid)
grid[r][c] = 0
return
return
solved_sudoku = solve(grid)
print(solved_sudoku)
because you use return which returns none
you store the result in grid and grid changes in every turn
try this:
def solve(grid):
""" Backtracking algorithm to solve Sudoku"""
for r in range(9):
for c in range(9):
if grid[r][c] == 0:
for i in range(1,10):
if possible(r, c, i, grid):
grid[r][c] = i
solve(grid)
if is_solved(grid):
return
grid[r][c] = 0
return
solve(grid)
print(grid)
Related
I'm a beginner in Leetcode & Python and I tried to solve the N-Queen Problem. Below is the solution in Python which passed submission
class Solution:
def solveNQueens(self, n: int) -> List[List[str]]:
def isSafe(row, x_col):
# check row
for x in range(n):
if placed[row][x] is True and x != x_col:
return False
# check column
for x in range(n):
if placed[x][x_col] is True and x != row:
return False
# check diagnol
i, j = row, x_col
while i > 0 and j < n - 1:
if placed[i - 1][j + 1] is True:
return False
i -= 1
j += 1
i, j = row, x_col
while i < n - 1 and j < 0:
if placed[i + 1][j - 1] is True:
return False
i -= 1
j += 1
# #check offdiagnol
i, j = row, x_col
while i > 0 and j > 0:
if placed[i - 1][j - 1] is True:
return False
i -= 1
j -= 1
i, j = row, x_col
while i < n-1 and j < n-1:
if placed[i][j] is True:
return False
i += 1
j += 1
return True
def process(currconfig, matrix, n, row):
#base condition
if row == n:
curr = []
for x in range(n):
curr.append(currconfig[x])
totalconfig.append(currconfig)
return
for x_col in range(n):
if isSafe(row, x_col):
path = x_col * '.' + 'Q' + (n - x_col - 1) * '.'
currconfig.append(path)
matrix[row][x_col] = True
#process recursively called
process(currconfig, matrix, n, row + 1)
currconfig.pop()
matrix[row][x_col] = False
configuration = []
totalconfig = []
placed = [[False for _ in range(n)] for _ in range(n)]
process(configuration, placed, n, 0)
return totalconfig
a = Solution()
print(a.solveNQueens(4))
I only have a doubt about the base condition of the process function. In the process function's base condition I initially did this and got empty Lists appended to totalconfig no matter what, CASE I:
def process(currconfig, matrix, n, row):
if row == n:
totalconfig.append(currconfig)
return
so spent a few hours trying to get around the problem and weirdly enough for me this worked, CASE II :
def process(currconfig, matrix, n, row):
if row == n:
curr = []
for x in range(n):
curr.append(currconfig[x])
totalconfig.append(currconfig)
return
I don't get why the CASE I did not work but CASE II worked. What am I missing...How is "currconfig" in CASE I different from "curr" in CASE II
it looks like you are not using functions (methods) in classes correctly.
Basically, the first argument is the self which refers to itself. In your case, currconfig is self.
So presumably the function should have looked like this:
def process(self, currconfig, matrix, n, row): # <---added self
if row == n:
totalconfig.append(currconfig)
return
I'm working on algos in python and tried to implement python sudoku solver. After many tries I've decided to look for the solution and decided to use the one listed here
I've tried to play with the code and modify it to accept a local variable sudoku instead of the global one, however it seems like my code solves the sudoku and then replaces the solved sudoku with the unsolved one probably due to the recursion modification.
Here is my modified code:
#Forming the Puzzle Grid
def form_grid(puzzle_string):
global grid
print('The Sudoku Problem')
for i in range(0, len(puzzle_string), 9):
row = puzzle_string[i:i+9]
temp = []
for block in row:
temp.append(int(block))
grid.append(temp)
printGrid()
Function to print the Grid
#Function to print the grid
def printGrid():
global grid
for row in grid:
print(row)
#Function to check if a digit can be placed in the given block
def possible(grid,row,col,digit):
for i in range(0,9):
if grid[row][i] == digit:
return False
for i in range(0,9):
if grid[i][col] == digit:
return False
square_row = (row//3)*3
square_col = (col//3)*3
for i in range(0,3):
for j in range(0,3):
if grid[square_row+i][square_col+j] == digit:
return False
return True
def solve(grid):
for row in range(9):
for col in range(9):
if grid[row][col] == 0:
for digit in range(1,10):
if possible(grid, row,col,digit):
grid[row][col] = digit
solve(grid)
grid[row][col] = 0 #Backtrack step
return grid
puzzle_string = "004300209005009001070060043006002087190007400050083000600000105003508690042910300"
solve(form_grid(puzzle_string))
Can't figure out how to modify the code to accept the sudoku as a parameter while returning the correct result, I've also tried to check for validity in every cal such as:
if 0 not in grid.flatten():
return grid
but that yielded the same result
The main problem is that you were assigning the current cell always back to 0 and checked all possible digits regardless of the result of the recursive solve. you should check if the recursive solve is valid and decide what would be the next step.
The following is a small fix to your code. First, solve should return bool (i.e., True or False) as the pointer to grid remains the same, so you ddon't really need to return it. Then you should use the recursive call to check if a valid solution was found. If not, continue to the next digit, and if you checked all digits, assign 0 back to the current cell and return False. Otherwise (if a valid solution was found) return True.
def solve(grid):
for row in range(9):
for col in range(9):
if grid[row][col] == 0:
valid = False
for digit in range(1, 10):
if possible(grid, row,col,digit):
grid[row][col] = digit
if solve(grid):
return True
grid[row][col] = 0 # Backtrack step
return False
return True
puzzle_string = "004300209005009001070060043006002087190007400050083000600000105003508690042910300"
grid = form_grid(puzzle_string)
printGrid()
solve(grid)
print()
printGrid()
BTW, there were few bugs in your code, such as relating to a global grid but not initializing it anywhere.
Also, solve is not very efficient as in each recursive call you are searching for the next empty cell. Currently is just a 9X9 grid, so it would be fast anyway, but for generalization, or just as a principal, a better way to use the recursive call is that solve would receive the row and col of the next position to check.
Finally, it might be better to remove the global grid and just return it from the form_grid function. the same for printGrid that should get the grid to print. The following is a version with the mentioned modifications:
#Forming the Puzzle Grid
def form_grid(puzzle_string):
grid = []
print('The Sudoku Problem')
for i in range(0, len(puzzle_string), 9):
row = puzzle_string[i:i+9]
temp = []
for block in row:
temp.append(int(block))
grid.append(temp)
return grid
#Function to print the grid
def printGrid(grid):
for row in grid:
print(row)
print()
#Function to check if a digit can be placed in the given block
def possible(grid, row, col, digit):
for i in range(0, 9):
if grid[row][i] == digit:
return False
for i in range(0, 9):
if grid[i][col] == digit:
return False
square_row = (row // 3) * 3
square_col = (col // 3) * 3
for i in range(0, 3):
for j in range(0, 3):
if grid[square_row + i][square_col + j] == digit:
return False
return True
def get_next_position(current_row, current_col):
if current_col == 8:
if current_row == 8:
return None, None
return current_row + 1, 0
return current_row, current_col + 1
def solve(grid, row, col):
if row is None:
return True
next_row, next_col = get_next_position(row, col)
if grid[row][col] != 0:
return solve(grid, next_row, next_col)
for digit in range(1, 10):
if possible(grid, row, col, digit):
grid[row][col] = digit
if solve(grid, next_row, next_col):
return True
grid[row][col] = 0
return False
puzzle_string = "004300209005009001070060043006002087190007400050083000600000105003508690042910300"
grid = form_grid(puzzle_string)
print("Initial grid")
printGrid(grid)
is_solved = solve(grid, 0, 0)
print(f"Solved: {is_solved}")
print("Solved grid")
printGrid(grid)
You could take the following steps:
Remove the global variable and all global statements
Turn your functions into methods of a new Sudoku class
Make from_grid the constructor of that class, i.e. name it __init__
Define self.grid = [] in this constructor. This way grid is an instance member, so it is separate for each instance you create of Sudoku
Remove all grid function parameters, but add self as the first parameter of all these methods, and make sure to reference self.grid where ever you need access to the grid
solve has an algorithmic problem: it returns grid when it has already backtracked a working "move". Instead make solve such that it returns a boolean: True when the solution is found, and False if not, and make sure it does not clear any moves when a solution is found, and does not try any alternatives. That way self.grid will have the solution.
Here are those things implemented, with a few other cosmetic changes:
class Sudoku:
def __init__(self, puzzle_string):
self.grid = [
list(map(int, puzzle_string[i:i+9]))
for i in range(0, len(puzzle_string), 9)
]
#Function to print the grid
def printGrid(self):
for row in self.grid:
print(row)
#Function to check if a digit can be placed in the given block
def possible(self, row, col, digit):
if digit in self.grid[row]:
return False
for i in range(0,9):
if self.grid[i][col] == digit:
return False
square_row = (row//3)*3
square_col = (col//3)*3
for i in range(0,3):
for j in range(0,3):
if self.grid[square_row+i][square_col+j] == digit:
return False
return True
def solve(self):
for row in range(9):
for col in range(9):
if self.grid[row][col] == 0:
for digit in range(1,10):
if self.possible(row, col, digit):
self.grid[row][col] = digit
if self.solve():
return True
self.grid[row][col] = 0 #Backtrack step
return False
return True
puzzle_string = "004300209005009001070060043006002087190007400050083000600000105003508690042910300"
puzzle = Sudoku(puzzle_string)
print('The Sudoku Problem:')
puzzle.printGrid()
puzzle.solve()
if puzzle.solve():
print("Solved:")
puzzle.printGrid()
else:
print("Sorry, no solution found")
I'm writing a sudoku solver in Python that takes in a partially filled in board and uses backtracking and forward checking to fill in the rest and solve the puzzle. Forward checking is where every time you assign a value to a blank cell you check whether its row, col, and box unassigned "neighbors" still have nonempty domains after the assignment.
To represent my board (dimenstions: N x N board with P x Q boxes), I'm using a 2D list in which each entry is of the form [value, [domain]], where value is the assigned number of the cell (0 if unassigned) and domain is the possible values for the cell that would keep the sudoku puzzle consistent.
I believe I am doing something wrong with my recursion but can't figure out what. The function always fails and returns False. Below is a portion of my recursive solver function with the preprocessing code taken out. If necessary, I can post the entire function and its helper functions.
def fc_recursive_solve(board, N, P, Q, row, col, outputFile, timeout):
###some preprocessing here to check if puzzle is solved and find next empty cell if not
vals = board[row][col][1] #domain/possible values for the empty cell
for num in vals:
#if num doesn't violate the row, col, and box sudoku constraints
if constraintCheck(row, col, num, P, N, Q, board):
#make copy of cell's domain for backtracking
tempDomain = copy.deepcopy(board[row][col][1])
board[row][col][0] = num #assign num to the cell
#remove num from domains of neighbors,
#if an empty domain results after removing num,
#return False and the original board,
#else return True and the updated board
noEmptyDomains, board = propagate_fc(board, N, P, Q, row, col, num)
if noEmptyDomains:
board[row][col][1] = [num] #update domain to be num and then recurse
if fc_recursive_solve(board, N, P, Q, row, col, outputFile, timeout):
return True
#backtrack -- reset value and domain of assigned cell
board[row][col][1] = tempDomain
board[row][col][0] = 0
else:
board[row][col][0] = 0
return False
EDIT: more code and trying out Blckknght's solution
def fc_recursive_solve(board, N, P, Q, row, col, outputFile, timeout):
if time.clock() >= timeout:
return "timeout"
while row < N and board[row][col][0] != 0: #find next blank
if col == N-1:
row = row + 1
col = 0
else:
col = col + 1
if row == N: #solved
return True
for num in vals:
if constraintCheck(row, col, num, P, N, Q, board):
board[row][col][0] = num
noEmptyDomains, new_board = propagate_fc(board, N, P, Q, row, col, num) # new var
if noEmptyDomains:
new_board[row][col][1] = [num] # this doesn't modify board, only new_board
if fc_recursive_solve(new_board, N, P, Q, row, col, outputFile, timeout):
return True
board[row][col][0] = 0 # the only thing that's required to backtrack
return False
def propagate_fc(board, N, P, Q, row, col, num):
origBoard = copy.deepcopy(board)
#row propagate
for x in range(N):
if board[x][col][0] == 0:
if num in board[x][col][1]:
board[x][col][1].remove(num)
if len(board[x][col][1]) == 0:
return False, origBoard #domain is empty; return original board
#col propagate
for y in range(N):
if board[row][y][0] == 0:
if num in board[row][y][1]:
board[row][y][1].remove(num)
if len(board[row][y][1]) == 0:
return False, origBoard #domain is empty
#box propagate
rDiv = row/P
cDiv = col/P
for i in range((rDiv * P), ((rDiv + 1) * P)):
for j in range((cDiv * Q), ((cDiv + 1) * Q)):
if board[i][j][0] == 0:
if num in board[i][j][1]:
board[i][j][1].remove(num)
if len(board[i][j][1]) == 0:
return False, origBoard #domain is empty
return True, board #success; return board with updated domains
If you're doing backtracking you need to be able to return the state of your board to how it was before. Your current code is not doing that. The propagate_fc function modifies board in a way that is not easy to undo.
Since I don't see an easy way to reverse the logic of propagate_fc, I suggest changing the design of the solver so that it makes copies of the board and only modifies the copies before passing them on to further recursive steps. If the copy doesn't lead to a solution, it can be thrown away, rather than trying to write backtracking code to fix it back up.
(I'm sure it is possible to backtrack, it's just not obvious what a good way to keep track of the changes, and figuring it out is too much work for this answer.)
Anyway, here's what I suggest for the modified version of the solver:
def fc_recursive_solve(board, N, P, Q, row, col, outputFile, timeout):
if time.clock() >= timeout:
return "timeout"
while row < N and board[row][col][0] != 0: #find next blank
if col == N-1:
row = row + 1
col = 0
else:
col = col + 1
if row == N: #solved
return board
for num in vals:
if constraintCheck(row, col, num, P, N, Q, board):
new_board = copy.deepcopy(board)
new_board[row][col][0] = num
if propagate_fc(new_board, N, P, Q, row, col, num):
new_board[row][col][1] = [num]
result = fc_recursive_solve(new_board, N, P, Q, row, col, outputFile, timeout)
if result is not None and result != "timeout":
return result
return None
I've changed it to return the solved board, if it's successful. Otherwise, you'd get a True response, but not be able to see the result (since the top-level code's board won't be modified).
Here's the changed version of propagate_fc to go with it:
def propagate_fc(board, N, P, Q, row, col, num):
# no copying any more here
#row propagate
for x in range(N):
if board[x][col][0] == 0:
if num in board[x][col][1]:
board[x][col][1].remove(num)
if len(board[x][col][1]) == 0:
return False
#col propagate
for y in range(N):
if board[row][y][0] == 0:
if num in board[row][y][1]:
board[row][y][1].remove(num)
if len(board[row][y][1]) == 0:
return False
#box propagate
rDiv = row/P
cDiv = col/P
for i in range((rDiv * P), ((rDiv + 1) * P)):
for j in range((cDiv * Q), ((cDiv + 1) * Q)):
if board[i][j][0] == 0:
if num in board[i][j][1]:
board[i][j][1].remove(num)
if len(board[i][j][1]) == 0:
return False
return board #success; return new board
The only real change here is that I don't bother returning the board, since we're always modifying it in place. Only the bool result is needed (to say if the board is valid or not).
(I'd initially thought there was another issue, with the if len(...) == 0 checks in each block, but it turned out not to be a problem after all. You might get slightly better performance doing those checks only when you've just removed a value from the current board[x][y][1] list (by indenting those blocks by two levels), but it's not likely to be a big performance gain.)
Based on a quick glance, I think you mixed up your row/col propagate:
#row propagate
for x in range(row): <== should this be range(col) ?
if board[row][x][0] == 0: <== row is fixed, but cols (x) changes
if num in board[row][x][1]:
board[row][x][1].remove(num)
if len(board[row][x][1]) == 0:
return False, origBoard #domain is empty; return original board
I am running into trouble trying to get this piece of code to run for all cases:
def symmetric(p):
""" returns true if list is symmetric"""
if p==[]:return True
n=len(p)
m=len(p[0])
if m !=n:
return False
i=0
j=0
t=False
while i < n:
while j < n:
if not p[i][j]==p[j][i]:
return False
j=j+1
i=i+1
return True
When I run this, it passes for some cases.
I can't seem to see what I am doing wrong.
I'd expect [['algebra', 'combinatorics', 'graphs'], ['combinatorics', 'topology', 'sets'], ['graphs', 'topology', 'sets']] to return False but it doesn't.
The break statement only ends the inner while loop.
Since you already found an asymmetry, just use return:
i, j = 0
while i < n:
while j < n:
if not p[i][j] == p[j][i]:
return False
j += 1
i += 1
return True
However, you are not comparing each row with each column at the same index here; because you never reset j back to 0, after the first while j < n loop you'll have j == n and you skip all the remaining loops.
Set j = 0 inside the first while:
i = 0
while i < n:
j = 0
while j < n:
if not p[i][j] == p[j][i]:
return False
j += 1
i += 1
return True
Better still, use for loops over range():
for i in range(n):
for j in range(n):
if not p[i][j] == p[j][i]:
return False
return True
This program tests if a matrix is an identity matrix or not.
I have pasted my code beneath, and would like to know ways in which I can optimize the efficiency of this code. Also I am new to python programming, are there some built in functions that can solve the purpose too?
def is_identity_matrix(test):
if (test == []):
return False
i = 0
while (i < len(test)):
if (len(test[i]) == len(test)):
j = 0
while(j < len(test[i])):
if (j != i):
if(test[i][j] != 0):
return False
else:
if(test[i][j] != 1):
return False
if(j == (len(test[i]) - 1)):
break
j += 1
if(i == (len(test) - 1)):
break
i += 1
else:
return False
if(i == j and i == (len(test) - 1)):
return True
# Test Cases:
matrix1 = [[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1]]
print is_identity_matrix(matrix1)
#>>>True
matrix2 = [[1,0,0],
[0,1,0],
[0,0,0]]
print is_identity_matrix(matrix2)
#>>>False
matrix3 = [[2,0,0],
[0,2,0],
[0,0,2]]
print is_identity_matrix(matrix3)
#>>>False
matrix4 = [[1,0,0,0],
[0,1,1,0],
[0,0,0,1]]
print is_identity_matrix(matrix4)
#>>>False
matrix5 = [[1,0,0,0,0,0,0,0,0]]
print is_identity_matrix(matrix5)
#>>>False
matrix6 = [[1,0,0,0],
[0,1,0,2],
[0,0,1,0],
[0,0,0,1]]
print is_identity_matrix(matrix6)
#>>>False
def is_identity_matrix(listoflist):
return all(val == (x == y)
for y, row in enumerate(listoflist)
for x, val in enumerate(row))
(though, this does not check if the matrix is square, and it returns True for an empty list)
Explanation: Inside all we have a generator expression with nested loops where val loops over each value in the matrix. x == y evaluates to True on the diagonal and False elsewhere. In Python, True == 1 and False == 0, so you can compare val == (x == y). The parentheses are important:
val == x == y would be a chained comparison equivalent to val == x and x == y
I'd use numpy:
(np.array(matrix1) == np.identity(len(matrix1))).all()
Of course, it'd be better if you were storing matrix1 as a numpy array in the first place to avoid the conversion.
Multiply by the all ones vector and check that the result is the same
Check the size of your matrix, make sure it is n x n, then create an actual identity matrix using np.identity(n), then compare your matrix with the new one you created.
def is_identity_matrix(test):
if not test : return False
le = len(test[0])
for i,x in enumerate(test):
if len(x) == le:
if any(y!=1 if j==i else y!=0 for j,y in enumerate(x)):
return False
else:
return False
return True if len(test) == le else False
If speed is important you should probably look at Numpy, but in a situation where you can't use it or perhaps it isn't worth it to have the matrix as a Numpy array you could also use the following:
def is_identity(mat):
for i, row in enumerate(mat):
if any(row[:i]) or row[i]!=1 or any(row[i+1:]):
return False
return True
About 12x faster than the code of the currently accepted answer! For a matrix of 2000x2000 at least...
The above does not check the matrix dimensions, but you can easily add something like:
n = len(matrix)
if not all(len(row) == n for row in matrix):
return False