使用SBV和Haskell证明的符号理论

时间:2015-07-08 14:49:28

标签: haskell z3 sbv

我在Haskell中使用SBV(使用Z3后端)来创建一些理论证明。我想检查具有给定约束的forall xy(例如x + y = y + x,其中+是“加号运算符”,而不是添加)其他一些术语是有效的。我想定义关于+表达式的公理(如关联性,身份等),然后检查是否有进一步的等式,例如检查a + (b + c) == (a + c) + b是否有效正式abc

我试图使用类似的东西来实现它:

main = do
    let x = forall "x"
    let y = forall "y"
    out <- prove $ (x .== x)
    print "end"

但似乎我们不能在符号值上使用.==运算符。这是缺少功能还是错误使用?我们能够以某种方式使用SBV吗?

2 个答案:

答案 0 :(得分:11)

通过使用未解释的排序和功能,这种推理确实是可能的。然而,需要注意的是,对这种结构的推理通常需要量化的公理,而SMT求解器通常不能很好地推理量词。

话虽如此,这里是我如何使用SBV进行的。

首先,使用一些样板代码来获取未解释的类型T

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Generics
import Data.SBV

-- Uninterpreted type T
data T = TBase () deriving (Eq, Ord, Data, Typeable, Read, Show)
instance SymWord T
instance HasKind T
type ST = SBV T

执行此操作后,您将可以访问未解释的类型T及其符号对应ST。让我们声明pluszero,再次使用正确类型的未解释的常量:

-- Uninterpreted addition
plus :: ST -> ST -> ST
plus = uninterpret "plus"

-- Uninterpreted zero
zero :: ST
zero = uninterpret "zero"

到目前为止,我们告诉SBV的是,存在类型T,函数plus和常量zero;明确地被解释。也就是说,除了具有给定类型的事实之外,SMT求解器不做任何假设。

让我们首先尝试证明0+x = x

bad = prove $ \x -> zero `plus` x .== x

如果您尝试这样做,您将收到以下回复:

*Main> bad
Falsifiable. Counter-example:
  s0 = T!val!0 :: T

SMT解决方案告诉您的是该属性不存在,并且这是一个它不能保持的值。值T!val!0Z3特定响应;其他解算器可以返回其他东西。它本质上是T类型居民的内部标识符;除此之外我们对此一无所知。当然,这并不是非常有用,因为您并不真正了解它为pluszero建立的关联,但这是可以预期的。

为了证明财产,让我们告诉SMT解决者另外两件事。首先,plus是可交换的。第二,右侧添加zero并没有做任何事情。这些是通过addAxiom电话完成的。不幸的是,你必须用SMTLib语法编写公理,因为SBV(至少还没有)支持使用Haskell编写的公理。另请注意,我们在此处切换到使用Symbolic monad:

good = prove $ do
         addAxiom "plus-zero-axioms"
                  [ "(assert (forall ((x T) (y T)) (= (plus x y) (plus y x))))"
                  , "(assert (forall ((x T)) (= (plus x zero) x)))"
                  ]
         x <- free "x"
         return $ zero `plus` x .== x

请注意我们如何告诉求解器x+y = y+xx+0 = x,并要求它证明0+x = x。以这种方式编写公理看起来非常难看,因为你必须使用SMTLib语法,但这是当前的事态。现在我们有:

*Main> good
Q.E.D.

量化公理和未解释类型/函数不是通过SBV接口使用的最简单的东西,但是你可以通过这种方式获得一些里程数。如果你在公理中大量使用量词,解算器就不太可能回答你的问题;并且可能会回复unknown。这一切都取决于你使用的求解器,以及要证明的属性有多难。

答案 1 :(得分:4)

您对API的使用并不是很正确。证明数学等式的最简单方法是使用简单的函数。例如,关于无界整数的关联性可以用这种方式表示:

prove $ \x y z -> x + (y + z) .== (x + y) + (z :: SInteger)

如果你需要一个更具编程性的界面(有时你会),那么你可以使用Symbolic monad,因此:

plusAssoc = prove $ do x <- sInteger "x"
                       y <- sInteger "y"
                       z <- sInteger "z"
                       return $ x + (y + z) .== (x + y) + z

我建议浏览hackage网站中提供的许多示例,以熟悉API:https://hackage.haskell.org/package/sbv