DPLL算法和访问节点数

时间:2017-03-13 19:53:15

标签: algorithm haskell recursion artificial-intelligence

我正在实施DPLL算法,该算法计算访问节点的数量。我设法实现了不计算访问节点的DPLL,但我无法想到计算问题的任何解决方案。主要问题是,当算法找到满意的估值并返回True时,递归卷起并从递归开始的那一刻开始返回计数器。在任何命令式语言中,我只需使用全局变量并在调用函数时立即递增它,但在Haskell中则不是这样。

我粘贴的代码并不代表我解决计数问题的尝试,只是没有它的解决方案。我试图使用诸如(True,Int)之类的元组,但它总是从递归开始的那一刻起返回整数值。

这是我的实现,其中(Node - > Variable)是一个启发式函数,Sentence是要满足的CNF中的子句列表,[Variable]是未分配的文字列表,而Model只是一个真值估值。 / p>

dpll' :: (Node -> Variable) -> Sentence -> [Variable] -> Model -> Bool
dpll' heurFun sentence vars model
  | satisfiesSentence model sentence  = True
  | falsifiesSentence model sentence  = False
  | otherwise         = applyRecursion
    where
      applyRecursion
        | pureSymbol /= Nothing = recurOnPureSymbol
        | unitSymbol /= Nothing = recurOnUnitSymbol
        | otherwise             = recurUsingHeuristicFunction
          where
            pureSymbol  = findPureSymbol vars sentence model
            unitSymbol  = findUnitClause sentence model
            heurVar = heurFun (sentence,(vars,model))
            recurOnPureSymbol =
              dpll' heurFun sentence (vars \\ [getVar pureSymbol]) ((formAssignment pureSymbol):model)
            recurOnUnitSymbol =
              dpll' heurFun sentence (vars \\ [getVar unitSymbol]) ((formAssignment unitSymbol):model)
            recurUsingHeuristicFunction = case vars of
              (v:vs) ->     (dpll' heurFun sentence (vars \\ [heurVar]) ((AS (heurVar,True)):model)
                        ||   dpll' heurFun sentence (vars \\ [heurVar]) ((AS (heurVar,False)):model))
              []     ->     False

我真的很感激有关如何计算受访节点的任何建议。谢谢。

编辑:

我唯一允许使用的库是System.Random,Data.Maybe和Data.List。

编辑:

我试图实现的一个可能的解决方案是使用元组(Bool,Int)作为DPPL函数的返回值。代码如下:

dpll'' :: (Node -> Variable) -> Sentence -> [Variable] -> Model -> Int -> (Bool,Int)
dpll'' heurFun sentence vars model counter
  | satisfiesSentence model sentence  = (True,counter)
  | falsifiesSentence model sentence  = (False,counter)
  | otherwise         = applyRecursion
  where
    applyRecursion
      | pureSymbol /= Nothing = recurOnPureSymbol
      | unitSymbol /= Nothing = recurOnUnitSymbol
      | otherwise             = recurUsingHeuristicFunction
      where
        pureSymbol  = findPureSymbol vars sentence model
        unitSymbol  = findUnitClause sentence model
        heurVar = heurFun (sentence,(vars,model))
        recurOnPureSymbol =
          dpll'' heurFun sentence (vars \\ [getVar pureSymbol]) ((formAssignment pureSymbol):model) (counter + 1)
        recurOnUnitSymbol =
          dpll'' heurFun sentence (vars \\ [getVar unitSymbol]) ((formAssignment unitSymbol):model) (counter + 1)
        recurUsingHeuristicFunction = case vars of
          (v:vs)    ->    ((fst $ dpll'' heurFun sentence (vars \\ [heurVar]) ((AS (heurVar,True)):model) (counter + 1))
                      ||  (fst $ dpll'' heurFun sentence (vars \\ [heurVar]) ((AS (heurVar,False)):model) (counter + 1)),counter)
          []        -> (False,counter)

这种方法的基本思想是在每次递归调用时递增计数器。但是,这种方法的问题是我不知道如何从OR语句中的递归调用中检索计数器。我甚至不确定这是否可以在Haskell中使用。

2 个答案:

答案 0 :(得分:1)

您可以使用case或类似内容从递归调用中检索计数器。

recurUsingHeuristicFunction = case vars of
    v:vs -> case dpll'' heurFun sentence (vars \\ [heurVar]) (AS (heurVar,True):model) (counter + 1) of
        (result, counter') -> case dpll'' heurFun sentence (vars \\ [heurVar]) (AS (heurVar,False):model) counter' of
            (result', counter'') -> (result || result', counter'')
    []   -> (False,counter)

这是State monad的手动实现。但是,我不清楚你为什么要通过一个柜台。回来吧。然后它是更简单的Writer monad。这个助手的代码看起来像这样:

recurUsingHeuristicFunction = case vars of
    v:vs -> case dpll'' heurFun sentence (vars \\ [heurVar]) (AS (heurVar,True):model) of
        (result, counter) -> case dpll'' heurFun sentence (vars \\ [heurVar]) (AS (heurVar,False):model) of
            (result', counter') -> (result || result', counter + counter' + 1)
    []   -> (False,0)

其他结果相似 - 返回0而不是counter1而不是counter+1 - 并且对函数的调用会更简单,只需一个担心设置正确的争论较少。

答案 1 :(得分:0)

基本上你所描述的命令式语言解决方案可以通过传递一个计数变量来建模,在你返回它时将变量添加到结果中(递归达到可满足的赋值的底部),即对于一个函数a -> b您将创建一个新函数a -> Int -> (b, Int)Int参数是计数器的当前状态,结果通过计数器的更新状态得以丰富。

使用state monad可以进一步优雅地重新表达。关于haskell和状态monad的一个非常好的教程是here。基本上,只需为函数a -> b提供更好的名称,a -> Int -> (b, Int)a -> b的转换就可以看作是a -> State Int b转换为Int -> (b, Int)。有一个非常好的blog以一种非常容易理解的方式解释这些好的抽象来自何处。

import Control.Monad.Trans.StateT

type Count = Int

dpllM :: (Node -> Variable) -> Sentence -> [Variable] -> Model -> State Count Bool
dpllM heurFun sentence vars model | ... = do
    -- do your thing
    modify (+1)
    -- do your thing

dpll' :: (Node -> Variable) -> Sentence -> [Variable] -> Model -> Bool
dpll' heurFun sentence vars model = runState (dpllM heurFun sentence vars model) 0

也许你想要像

这样的东西
f :: A -> Int -> (Bool, Int)
f a c =
    let a' = ...
        a'' = ...
        (b', c') = f a' c in f a'' c'