AI笔记 The SAT problem

来源:互联网 发布:网址导航程序源码 编辑:程序博客网 时间:2024/06/06 02:29

The problems

Suppose you have a wedding to plan, and want to arrange the wedding seating for a certain number of guests in a hall. The hall has a certian number of tables for seating. Some pairs of guests are couples or close Friends(F) and want to sit together at the same table. Some other pairs of guestes are Enemies(E) and want to sit together at the same table. The rest of the pairs are Indifferent(I) to each other and do not mind sitting together or not. However, each pair of guests can have ONLY one relationship, (E), (F) or (I). Find a seating arrangement that satisfies the constrains.


SAT问题即满足问题。给定一个规则(约束条件)和dataset(数据集),求证这个数据集能否满足这个规则,如果满足,给出可能的解。历史上有很多经典SAT问题,例如地图涂色问题,婚礼问题,理事会问题。


DPLL是解此类问题的一个经典算法,DPLL是4个算法发明人名字的首字母。这四个人是Martin Davis, Hilary Putnam, George Logemann, and Donald Loveland (1962)。算法思想即把dataset和规则转换成clauses,再把clauses转换成Conjunctive normal form,一个完整的CNF是由若干个conjunction clause组成,每个conjunction clause由由若干个disjunction clause组成,每个disjunction clause是由一个symbol和其条件组成。这里conjunction即and,disjunction即or。如下是一个CNF:

CNF


如何判断CNF的正确性?

DPLL算法给出了一个简单的判定方法,如果经过合理的假设检验之后,某个CNF为空(即这个CNF中所有的子clause都为true),则说明这个CNF satisfiable。如果这个CNF中存在空的子clause,则说明这个子clause是矛盾的,那么这个CNF就是contradiction,即unsatisfiable。


针对一个dataset中的所有数据,如果存在一个确定的model,能够满足CNF中的所有clauses,那么就说这个CNF是satisfiable,否则就是unsatisfiable。那么如何确定model?经典算法使用假设检验(hypothesis),随机的将某个symbol假设为true或false,则包含这个symbol的所有clause将为true,如果发现CNF unstatisfiable则丢弃这个假设,直到这个CNF达到判定条件。

引用AIMA Berkeley的算法:

def dpll(clauses, symbols, model):    "See if the clauses are true in a partial model."    unknown_clauses = [] ## clauses with an unknown truth value    for c in clauses:        val =  pl_true(c, model)        if val == False:            return False        if val != True:            unknown_clauses.append(c)    if not unknown_clauses:        return model    P, value = find_pure_symbol(symbols, unknown_clauses)    if P:        return dpll(clauses, removeall(P, symbols), extend(model, P, value))    P, value = find_unit_clause(clauses, model)    if P:        return dpll(clauses, removeall(P, symbols), extend(model, P, value))    P = symbols.pop()    return (dpll(clauses, symbols, extend(model, P, True)) or            dpll(clauses, symbols, extend(model, P, False)))


需要说的是这里使用到了离散数学的一些经典方法来简化经过假设检验的CNF。


但是此类算法的问题是效率太低,需要遍历所有的symbol进行假设检验,最坏情况下算法的时间复杂度是O(m*n)。

0 0
原创粉丝点击