I am trying to understand solving Sudoku in Python from this website. I couldn't understand the "Search" Function in particular the application of "some" function in the "search".
def search(values):
"Using depth-first search and propagation, try all possible values."
if values is False:
return False ## Failed earlier
if all(len(values[s]) == 1 for s in squares):
return values ## Solved!
## Chose the unfilled square s with the fewest possibilities
n,s = min((len(values[s]), s) for s in squares if len(values[s]) > 1)
return some(search(assign(values.copy(), s, d))
for d in values[s])
def some(seq):
"Return some element of seq that is true."
for e in seq:
if e: return e
return False
values which is the input of the search is a dictionary (key: name of each square, value: string of possible values for that square). In the search we try to find one square( a square is a place holder of one number in Sudoku) which has the least number of possible values to fill. Then, the assign function is called for each of that values. the output of assign can be false or can be the new dictionary values. I am wondering what is the purpose of "some" function here?
This part:
search(assign(values.copy(), s, d))
for d in values[s]
is a generator expression that will recursively call search for each possible value that is valid for values[s]. It will give us a bunch of results - one for each d in values[s]. Each result will either be a dictionary (yay success) or False (boo, failure).
What some does is just pick the first success case in the group - otherwise return False.
A logically equivalent approach would be:
for d in values[s]:
e = search(assign(values.copy(), s, d))
if e: return e
return False
Related
I'm creating a python program that given any angles/sides of a triangle will solve for all other applicable sides. to do this I have a dictionary of lists with lengths a,b,c and sides aa,ba,ca. the dictionary is structured so the first item in the list is the value of the key and the second item is a 0 or a 1, depending on if it is answered or not.
The program takes the second value of the list and puts it into another dictionary i called eqdict. for eqdict the value is either a 1 or a 0, depending if the value is known or not. With this we can do Pythagorean theorem, so if a+b+c=2, then we know 1 value is missing so it starts a function to find the missing side. After this function the answer gets saved with the saveanswer function, and the equation finder function is called again. However when the program goes back through equation finder, the eqdict for whichever character it found is not set to 0, so it has a continuous loop.
import math
def main():
#creating terms in strings because I cant find an answer on how
#to make floats with a non zero no value
global terms
terms={"a":[0,0],"b":[0,0],"c":[0,0],"aa":[0,0],"ba":[0,0],"ca":[0,0]}
selectterms()
def selectterms():
"""takes user input for terms"""
doneterm=False
while not doneterm:
print("Please select the variable and then write it's value")
print("When done, please press enter with command prompt empty")
term1=input("Variable: ")
#to start program need to enter no command
if term1=="":
doneterm=True
appender()
#to end program after its finished
if doneterm ==False:
term2=float(input("Number: "))
terms[term1]=[term2]
terms[term1].append(1)
return
def addtoeqdict(term):
eqdict[term]=1
return
def saveanswer(term,num):
"""saves answer to answers dict, makes second term 1 and sends back the number"""
answers={}
print("saveanswer")
answers[term]=num
#print("answers",answers)
terms[term][1]=1
terms[term][0]=num
eqdict[term]=1
print(answers)
print(eqdict)
eqfinder(**eqdict)
def appender():
"""Append a 0 on to terms that have only 1 item in list"""
global eqdict
eqdict={}
keys=terms.keys()
for i in keys:
i = str(i)
eqdict[i]=int(terms[i][1])
eqfinder(**eqdict)
return
def eqfinder(a,b,c,aa,ba,ca):
"""runs through given terms to find any possible equations.
looks for possible equations by adding appended values"""
nomoreterms=False
while nomoreterms == False:
print(terms)
if terms["aa"][0]!=0 or terms["ba"][0]!=0 or terms["ca"][0]!=0:
if terms["aa"][0]<0 or terms["ba"][0]<0 or terms["ca"][0]<0:
posangles(terms["aa"][0],terms["ba"][0],terms["ca"][0])
print(a,b,c,aa,ba,ca)
if c+a+b==2:
cab(terms["c"][0],terms["a"][0],terms["b"][0])
else:
nomoreterms=True
def posangles(aa,ba,ca):
print("Posangles")
if aa<0:
aa=aa*(-1)
saveanswer("aa",aa)
elif ba<0:
ba=ba*(-1)
saveanswer("ba",ba)
elif ca<0:
ca=ca*(-1)
saveanswer("ca",ca)
def cab(c,a,b):
print("cab")
if c==0:
c=math.sqrt(a**2+b**2)
saveanswer("c",c)
elif a==0:
a=math.sqrt(c**2-b**2)
saveanswer("a", a)
elif b==0:
b=math.sqrt(c**2-a**2)
saveanswer("b",b)
main()
So the issue is your eqfinder function. You pass in a, b, c find the missing value using cab, and save the answer. It then gets back to eqfinder and checks if a + b + c == 2 which it does since you never updated the a, b, c variables. There are number of fixes you could do to make this break out of the for loop. Here's one (added line marked with >>>):
def eqfinder(a,b,c,aa,ba,ca):
"""runs through given terms to find any possible equations.
looks for possible equations by adding appended values"""
nomoreterms=False
while nomoreterms == False:
print(terms)
if terms["aa"][0]!=0 or terms["ba"][0]!=0 or terms["ca"][0]!=0:
if terms["aa"][0]<0 or terms["ba"][0]<0 or terms["ca"][0]<0:
posangles(terms["aa"][0],terms["ba"][0],terms["ca"][0])
print(a,b,c,aa,ba,ca)
if c+a+b==2:
cab(terms["c"][0],terms["a"][0],terms["b"][0])
>>> c, a, b = terms["c"][1],terms["a"][1],terms["b"][1]
else:
nomoreterms=True
Hi I am currently going through Peter Norvig's sudoku solution (http://norvig.com/sudoku.html).
However, I have a bit of confusion with the block code below:
def assign(values, s, d):
"""Eliminate all the other values (except d) from values[s] and propagate.
Return values, except return False if a contradiction is detected."""
other_values = values[s].replace(d, '')
if all(eliminate(values, s, d2) for d2 in other_values):
return values
else:
return False
def eliminate(values, s, d):
"""Eliminate d from values[s]; propagate when values or places <= 2.
Return values, except return False if a contradiction is detected."""
if d not in values[s]:
return values ## Already eliminated
values[s] = values[s].replace(d,'')
## (1) If a square s is reduced to one value d2, then eliminate d2 from the peers.
if len(values[s]) == 0:
return False ## Contradiction: removed last value
elif len(values[s]) == 1:
d2 = values[s]
if not all(eliminate(values, s2, d2) for s2 in peers[s]):
return False
## (2) If a unit u is reduced to only one place for a value d, then put it there.
for u in units[s]:
dplaces = [s for s in u if d in values[s]]
if len(dplaces) == 0:
return False ## Contradiction: no place for this value
elif len(dplaces) == 1:
# d can only be in one place in unit; assign it there
if not assign(values, dplaces[0], d):
return False
return values
The function assign receive an input of a dictionary values and will return values as well if there is no contradiction. However, in the assign function, I did not see any update on the dictionary values. My understanding is that dict values is updated with the eliminate function (and after running the code, I believe this is the case). However, this is done outside of the assign function and should not affect the values in the assign function, as it is not updated directly in the function.
Maybe you guys can give me a shed of light?
Python dicts are mutable, meaning that their value can be changed.
This example is showing an anti-pattern: You shouldn't both mutate an argument and return it. An example is all the methods that change a list (append, pop, etc.) don't return the original list.
The eliminate function gets the same dict as in the assign function, and any changes in the assign function are reflected in the elimate function.
Here is an example:
def update(dict_, key, value):
dict_[key] = value
d = {
1: 2,
3: 4
}
update(d, 1, 100)
update(d, 3, 100)
print(d[1] + d[3]) # 200
I need to make a SAT-solver for a homework assignment. my input gives me n variables x1,x2...xn, and M clauses which are disjuntions of literals , represented by a list of lists ex. [[-1,2,3],[2,-3],[1,-3]] where [-1,3],[2,-3] means (~X1 or X3) and (X2 or ~X3).
My plan is to implement a backtracking solution, where I first choose X1 = False, then recursively check the equation for each other variable.
My problems is how to set up the recursion. I have 2 functions, one which checks for contradictions in my program, and one which simplifies the expression based on the truth value selected for a variable.
def contradiction(clauses):
for clause in clauses:
if clause == ['F']: #checks if any clause evaluates to False
return True
for other in clauses:
if len(clause)==1 and len(other)==1:
if clause[0] == -other[0]: #checks if clauses Xi and ~Xi exist
return True
return False
def simplification(clauses, value):
new_clauses = [i for i in clauses]
for i in range(len(new_clauses)):
if -(value) in new_clauses[i]: #for assignment Xi, removes ~Xi from each clause, + vice versa
del new_clauses[i][new_clauses[i].index(-value)]
if new_clauses[i] == []:
new_clauses[i] = ['F']
if value in new_clauses[i]: #for value Xi, removes clauses satisfied by Xi
new_clauses [i] = []
return new_clauses
I wish to start at X1 and go through recursively down to Xn, stopping the process if a contradiction is found. A non recursive solution is fine as well.
EDIT: this is what I have so far:
def isSat(clauses,variable,n):
if variable > n:
if not contradiction(clauses):
return 'satisfiable'
if contradiction(clauses):
return 'unsatisifable'
clauses1 = simplification(clauses,variable)
clauses2 = simplification(clauses,-variable)
if not contradiction(clauses1):
return isSat(clauses1,variable+1,n)
if not contradiction(clauses2):
return isSat(clauses2,variable+1,n)
return 'unsatisfiable'
essentially I need to, starting from the first variable, set it to true and false, and check both cases for contradictions. Then, for each case that has no contradictions, recursively test both cases for the next variable. It will return satisfiable if it reached the last variable with no contradictions. (It only needs to return yes or no)
Turns out the problem was in a rare edge case where the same variable appeared twice in a clauses I.E. [9,-5,10,3,9]. In this case my simplification function would only remove one instance of the variable. Should not have assumed only 1 instance of a variable per clause
I am trying to write a function which is supposed to compare list structures (the values are indifferent). The problem is that I have two lists which are unequal but the function still returns True even though it actually goes into the else part. I don't understand why and what I did wrong. Here is my code:
def islist(p): #is p a list
return type(p)==type(list())
def ListeIsomorf(a,b):
if len(a)==len(b):
for i,j in zip(a,b):
if islist(i) and islist(j):
ListeIsomorf(i,j)
elif islist(i) or islist(j):
return(False)
return(True)
else:
print(a,"length from the list isn't equal",b)
return(False)
#example lists
ListeE = [[],[],[[]]]
ListeD = [[],[],[[]]]
ListeF = [[[],[],[[]]]]
ListeG = [[],[[]],[[]]]
ListeH = [1,[3]]
ListeI = [1,3]
#tests
print(ListeIsomorf(ListeD,ListeE)) # True
print(ListeIsomorf(ListeD,ListeF)) # False
print(ListeIsomorf(ListeD,ListeG)) # False
print(ListeIsomorf(ListeH,ListeI)) # False
So the problem only occurs with the third print(ListeIsomorf(ListeD,ListeG)) # False. It actually goes into the else part and does print the "length from the list isn't equal" but it doesn't stop and it doesn't give out the return(False). Am I missing something?
The problem is that when your function calls itself recursively:
ListeIsomorf(i,j)
it ignores the returned value.
Thus the comparisons that take place at the second level of recursion have no effect on what the top level returns.
Changing the above to:
if not ListeIsomorf(i,j):
return(False)
fixes the problem.
Write a recursive function search(l,key) that returns a boolean: True if key is in the list l; False if it isn’t. Describe the base case(s) and how the smaller problem relates to the bigger one. You may not use the in operator or the index() list method.
Can anyone explain what i need to do here for the description? I dont know anything about recurrsion to know where to start. Its for a exam review lab assignment.
Here is the code i have been provided.
def search(l,key):
"""
locates key in list l. if present, returns True; else returns False.
PRE: l is a list.
POST: l is unchanged; returns True if key in l; False otherwise.
"""
Sample Main:
l1 = [1, '2', 'x', 5, -2]
print search(l1, 'x') # should output: "True"
print search(l1, 2) # should output: "False"
All recursion tends to follow the same rules:
Have one or more terminating cases.
Every other case is a slightly simpler form of the current case.
So, for example, a (very inefficient) way to add two positive numbers a and b:
if b is zero, return a.
otherwise add the two numbers a+1 and b-1.
Something like:
def addtwo (a, b):
if b == 0:
return a
return addtwo (a+1, b-1)
Now let's think about the cases for your assignment:
if the list is empty, you didn't find it: return false.
if the first element of the list is equal to your key, you found it: return true.
otherwise look in the list made by removing the first element.
In pseudo-code (which is very similar to Python but different enough that you'll have to do some work):
def search (list, key):
if list is empty:
return false
if key == first item in list:
return true
return search (list with first element removed, key)
Every question regarding recursion should be dealt with the same way (usually)...Ask yourself what is the base case and then build on that for higher cases...
So in this question, ask yourself, when can i be certain there is no key in the list...
It's obviously when the list is empty, you're certain it's not present.
For a bigger list, you compare the first element, if it's the same as the key, you return True right away, but incase it's not, you perform all the checks for the rest of the list....
So studying all these aspects,
Here's your Algorithm.
function locate(lst,key)
if lst == emptylist then return False
if lst[0] == key then return True
else return locate(lst[1..],key) //i use the notation lst[1...] to indicate list starting from 1 index.