繁体   English   中英

递归函数中的Python参数

[英]Python parameters in recursive functions

我正在尝试实现一个递归函数来解决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中的布尔子句/谓语进行回溯编程,其中当分支失败时,变量会自动设置为上一步。

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

每个对象都通过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(...)构造函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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