为了学习 Z3,我尝试使用 Haskell 绑定解决我最喜欢的代码出现问题之一(一个特别困难的问题, 2018 年第 23 天,第 2 部分sbv
) 。前面代码中的剧透...
module Lib
( solve
) where
import Data.SBV
puzzle :: [((SInteger, SInteger, SInteger), SInteger)]
puzzle = (\((x, y, z), r) -> ((literal x, literal y, literal z), literal r)) <$> [
((60118729,58965711,8716524), 71245377),
{- 999 more values that are large like the first one... -}
]
manhattan (a1, a2, a3) (b1, b2, b3) =
abs (a1 - b1) + abs (a2 - b2) + abs (a3 - b3)
countInRange pos =
foldr (\(nb, r) -> (+) $ oneIf (manhattan nb pos .<= r)) (0 :: SInteger) puzzle
answer = optimize Lexicographic $ do
x <- sInteger "x"
y <- sInteger "y"
z <- sInteger "z"
maximize "in-range" $ countInRange (x, y, z)
minimize "distance-from-origin" $ abs x + abs y + abs z
solve =
answer >>= print
现在,这个问题不是一个真正的sbv
问题,也不是一个 Haskell 问题,上面的代码并没有什么问题(它解决了 1000 个值puzzle
列表,在我的机器上在一分钟多一点的时间内具有巨大的 X、Y 和 Z 坐标,即对我来说已经足够好了)。这个问题是关于(0 :: SInteger)
在countInRange
.
如果我更改(0 :: SInteger)
它(0 :: SInt32)
会导致解决方案需要很长时间(当我开始输入这个问题时我开始了它,那是 16 分钟前并且还在计数)。
那么,什么给了?为什么SInt32
在这种情况下慢得多?是因为我在混合域(SInteger
在其他地方使用)吗?我会认为 unboundedSInteger
表示会比 bounded 慢Int32
。
请注意,所讨论的符号类型仅用于计算匹配值puzzle
(因此它总是 <= 1000,即 的长度puzzle
)。
更新
我Int32
在运行 40 分钟后终止了解决方案。