我有一个有状态的进程,被建模为i -> RWS r w s a
。我想给它一个输入cmds :: [i]
;目前我做的是批发:
let play = runGame theGame . go
where
go [] = finished
go ((v, n):cmds) = do
end1 <- stepWorld
end2 <- ite (SBV.isJust end1) (return end1) $ stepPlayer (v, n)
ite (SBV.isJust end2) (return end2) $ go cmds
我可以尝试搜索预定大小的输入,如下所示:
result <- satWith z3{ verbose = True } $ do
cmds <- mapM sCmd [1..inputLength]
return $ SBV.fromMaybe sFalse $ fst $ play cmds
然而,这给了我 SBV 本身可怕的性能,即在调用 Z3 之前(我可以看到情况是这样,因为verbose
输出显示了之前花费的所有时间(check-sat)
称呼)。这甚至与inputLength
设置为较小的值,例如 4。
然而,随着inputLength
设置为1或2,整个过程非常敏捷。所以这让我希望有一种方法可以运行SBV来获得单步行为的模型i -> s -> (s, a)
,然后告诉 SMT 求解器继续迭代该模型n
不同的i
s.
这就是我的问题:在这样的有状态计算中,我想要将 SMT 变量作为输入提供给状态计算,有没有办法让SMT求解器转动曲柄以避免SBV的不良性能?
我想一个简化的“模型问题”如果我有一个函数f :: St -> St
,和一个谓词p :: St -> SBool
,我想解决n :: SInt
这样p (iterateN n f x0)
,假设使用 SBV 执行此操作的推荐方法是什么Mergeable St
?
EDIT: 我已经上传了完整的代码到Github https://github.com/gergoerdi/scottcheck/tree/8ceaa0a7cb21681de12de79f1d9e2ed14d0b3d99但请记住,这不是一个最小化的例子;事实上,它还不是非常好的 Haskell 代码。