简体   繁体   English

递归函数中的Python参数

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM