[英]Python parameters in recursive functions
I am trying to implement a recursive function to solve a 3-SAT problem as described in the this great Udacity course https://www.udacity.com/course/cs313 I am new of Python programming and I have noticed a behavior I find strange. 我正在尝试实现一个递归函数来解决3-SAT问题,如本本很棒的Udacity课程中所述:https: //www.udacity.com/course/cs313我是Python编程的新手,并且注意到我发现了一个行为奇怪。
The fact is that when the recursive3SatSolver ends returning None and the algorithm backtracks to a new branch the solution variable (passed as parameter at each iteration) is not set to the previous state but remains with the latest value (the one modified within the ended function) 事实是,当recursive3SatSolver结束时返回None且该算法回溯到新分支时,解决方案变量(在每次迭代中作为参数传递)未设置为先前状态,而是保留为最新值(在结束函数中修改的值) )
it behaves as if the parameter was passed by reference and not by value 它的行为就像参数是通过引用而不是通过值传递的
def solve_3SAT(num_variables, clauses):
solution = [-1]*(num_variables+1)
satisfiedClauses = [0]*len(clauses)
for i in range(0, num_variables+1):
positive = False
negative = False
for idClause,clause in enumerate(clauses):
positive = positive or (i in clause)
negative = negative or (-i in clause)
candidate = positive ^ negative
for idClause,clause in enumerate(clauses):
if i in clause:
if candidate:
satisfiedClauses[idClause]=1
if candidate:
if positive:
solution[i]=1
else:
solution[i]=0
solution[0]=0
print 'preprocessing: ',solution
solution = recursive3SatSolver(num_variables,solution,clauses)
if solution != None:
for idS,s in enumerate(solution):
if solution[idS]<0:
solution[idS]=0
return solution
def recursive3SatSolver(num_variables, solution, clauses):
if is_satisfiable(clauses,solution)==False:
return None
satisfiedClauses = satisfied_clauses(clauses,solution)
for idC,sat in enumerate(satisfiedClauses):
if sat == 0:
chosenClause=idC
clause = clauses[chosenClause]
for idVar,var in enumerate(clause):
absVar = abs(var)
if solution[absVar]<0:
value=-1
if var>0:
value=1
else:
value=0
solution[absVar]=value
if is_satisfied(num_variables,clauses,solution):
return solution
else:
finalSolution = recursive3SatSolver(num_variables,solution,clauses)
if finalSolution!=None:
#print 'returning ...'
return finalSolution
else:
print 'changing branch: ',solution,'=>'
solution[absVar]=1-solution[absVar]
continue
print 'finished possibilities for this clause'
return None
if is_satisfied(num_variables,clauses,solution):
return solution
else:
print 'no more clauses'
return None
def satisfied_clauses(clauses,assignment):
satisfiedClauses= [0]*len(clauses)
for idClause,clause in enumerate(clauses):
if is_clause_satisfied(clause,assignment):
satisfiedClauses[idClause]=1
return satisfiedClauses
def is_satisfiable(clauses, assignment):
for clause in clauses:
if is_clause_satisfiable(clause,assignment):
continue
else:
return False
return True
def is_clause_satisfiable(clause,assignment):
sat = is_clause_satisfied(clause,assignment)
if sat :
return True
else:
for idVar, var in enumerate(clause):
absVar = abs(var)
if assignment[absVar]==-1:
return True
return False
def is_clause_satisfied(clause,assignment):
for idVar,var in enumerate(clause):
absVar = abs(var)
if assignment[absVar]<0:
continue
if var>0:
if assignment[absVar]==1:
return True
else:
if assignment[absVar]==0:
return True
return False
def is_satisfied(num_variables, clauses, assignment):
if assignment==None:
return False
check=True
for clause in clauses:
clauseVal = False;
for var in clause:
val=False;
if var<0:
val = not assignment[abs(var)]
else:
val = assignment[var]
clauseVal = clauseVal or val
check = check and clauseVal
return check
def test():
clauses = [[-2, -3, -1], [3, -2, 1], [-3, 2, 1],
[2, -3, -1], [3, -2, 1], [3, -2, 1]]
solutions = [[0, 0, 0, 0],
[0, 0, 1, 1],
[0, 1, 0, 0],
[0, 1, 1, 0],
[1, 0, 0, 0],
[1, 0, 1, 1],
[1, 1, 0, 0],
[1, 1, 1, 0]]
assert solve_3SAT(3,clauses) in solutions
clauses = [[2, 1, 3], [-2, -1, 3], [-2, 3, -1], [-2, -1, 3],
[2, 3, 1], [-1, 3, -2], [-3, 2, 1], [1, -3, -2],
[-2, -1, 3], [1, -2, -3], [-2, -1, 3], [-1, -2, -3],
[3, -2, 1], [2, 1, 3], [-3, -1, 2], [-3, -2, 1],
[-1, 3, -2], [1, 2, -3], [-3, -1, 2], [2, -1, 3]]
assert solve_3SAT(3,clauses) == None
print 'Tests passed'
clauses = [[2, 1, 3], [-2, -1, 3], [-2, 3, -1], [-2, -1, 3],
[2, 3, 1], [-1, 3, -2], [-3, 2, 1], [1, -3, -2],
[-2, -1, 3], [1, -2, -3], [-2, -1, 3], [-1, -2, -3],
[3, -2, 1], [2, 1, 3], [-3, -1, 2], [-3, -2, 1],
[-1, 3, -2], [1, 2, -3], [-3, -1, 2], [2, -1, 3]]
assert solve_3SAT(3,clauses) == None
print 'Tests passed'
UPDATE I have been wondering why I have needed some time to get this. 更新我一直在想为什么我需要一些时间才能做到这一点。 And I have understood the reason is that I was used to program back tracking on boolean clauses/predicates in Prolog where the variables are automatically set to the previous step when a branch fail.
而且我已经知道原因是我习惯于对Prolog中的布尔子句/谓语进行回溯编程,其中当分支失败时,变量会自动设置为上一步。
it behaves as if the parameter was passed by reference and not by value
它的行为就像参数是通过引用而不是通过值传递的
Every object is passed by reference in Python. 每个对象都通过Python中的引用传递。 In your case if
solution
is a list you should probably make a copy of it. 在您的情况下,如果
solution
是一个列表,则可能应复制它。
Some methods you can use: 您可以使用一些方法:
>>> l = [0,1,2]
>>> list(l) # creates a new list from the old one
[0, 1, 2]
>>> l[:] # slices also create a new object
[0, 1, 2]
>>> import copy
>>> copy.deepcopy(l) # create a deep copy of the object
[0, 1, 2]
>>> [i for i in l] # manually copy an object
[0, 1, 2]
My preferred way is to use the list(...)
constructor. 我的首选方法是使用
list(...)
构造函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.