在my last question中,我问我如何解析命题表达式,然后在SBV库的帮助下找到公式的所有模型。我使用hatt库来解析布尔表达式。
不幸的是,SBV似乎不适合合理快速的SAT解决,或者“allSat”功能找不到所有模型的速度。毕竟SBV的目标是SMT解决。
我使用证明器Z3和CVC4测试了haskell SBV封装的性能,与picosat相比。我使用了36个变量和840个有效模型的命题公式。 picosat的结果是耗时0.5秒,而Z3耗时3分钟,CVC4耗时6分钟。 SBV和“allSat”函数都有一些性能技巧可以根据命题公式进行修剪。或者其他一些证明者可能比Z3更快。
但我现在假设我可能需要使用更快的选项进行SAT解决,我想使用PicoSAT或MiniSAT,因为我在过去有很好的成绩,SAT比赛的结果似乎很好。
问题:
是否有适合查找所有模型(即C / C ++级别的快速结果)的Picosat或MiniSAT的绑定?例如,python绑定到picosat的功能就是“itersolve”,就是这样。但我找不到haskell picosat或miniSAT绑定的这个功能(也许我忽略了它们)。
我应该如何从使用hatt包解析的String转到适用于picosat / miniSat的“int list”。因此,从hatt库中的类型Expr
的表达式到表示适合于例如picosat的样式的CNF公式。 Picosat使用整数列表的常见SAT格式。请注意,我从String解析的公式最初已经在CNF中。我可以直接从hatt Expr转到int列表。或者,我使用my last question中的代码到适合SBV的allSat
函数的格式,并重新实现SBV的allSAT
函数的变体以使用picosat / miniSAT的hasekll绑定。
链接:
答案 0 :(得分:1)
正如我在评论中所说,一个非常常见的解决方案是强制SAT求解器通过显式添加一个允许以前发现的解决方案的子句来寻找其他解决方案。例如:
solveAll :: [[Int]] -> IO [[Int]]
solveAll e =
do s <- solve e
case s of
Solution x -> (x :) `fmap` solveAll (map negate x : e)
_ -> return []
在上面我们有solveAll
的CNF输入。当发现解决方案时,我们通过将当前解决方案的否定添加为新子句来返回该解决方案和所有剩余解决方案。解算器最终将返回不饱和状态,这表明我们找到了所有解决方案,或者未知,这意味着可能存在未被发现的解决方案,但解算器已放弃。
完整的程序如下
import Data.Logic.Propositional hiding (interpret)
import Picosat
import Control.Monad ((<=<))
main :: IO ()
main = do
let expr = [ [1, -2] , [3, -2] ]
putStrLn $ "Solving expr: " ++ show expr
(print <=< solve) expr
(print <=< solveAll) expr
solveAll :: [[Int]] -> IO [[Int]]
solveAll e =
do s <- solve e
case s of
Solution x -> (x :) `fmap` solveAll (map negate x : e)
_ -> return []