递归函数中的Python参数

时间:2014-01-04 21:30:33

标签: python algorithm

我正在尝试实现一个递归函数来解决3-SAT问题,正如这个伟大的Udacity课程https://www.udacity.com/course/cs313中所描述的那样 我是Python编程的新手,我注意到了一个我觉得奇怪的行为。

事实是,当recursive3SatSolver结束返回None并且算法回溯到新分支时,解决方案变量(在每次迭代时作为参数传递)未设置为先前状态但保留最新值(在内部修改的值)结束的功能)

它的行为就好像参数是通过引用传递而不是通过值传递

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'

更新 我一直想知道为什么我需要一些时间才能得到这个。我理解的原因是我习惯于在Prolog中对布尔子句/谓词进行反向编程,其中变量在分支失败时自动设置为上一步。

1 个答案:

答案 0 :(得分:1)

  

它的行为就好像参数是通过引用传递而不是通过值传递

每个对象都通过Python中的引用传递。在您的情况下,如果solution是一个列表,您应该复制它。

您可以使用的一些方法:

>>> 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]

我首选的方法是使用list(...)构造函数。