首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在SBV中编码扩展自然元

在SBV中编码扩展自然元
EN

Stack Overflow用户
提问于 2018-11-23 10:00:20
回答 1查看 139关注 0票数 2

我正在试验以下在SMT中编码扩展自然元素的方法(我定义了一个类似于Maybe Integer的数据类型):

代码语言:javascript
复制
; extended integers -- if first field is true, then the value is infinity
(declare-datatypes () ((IntX (mk-int-x (is-infty Bool) (not-infty Int)))))

; addition
(define-fun plus ((x IntX) (y IntX)) IntX
  (ite (or (is-infty x) (is-infty y))
           (mk-int-x true 0)
           (mk-int-x false (+ (not-infty x) (not-infty y)))))

(declare-fun x () IntX)
(assert (= x (plus x (mk-int-x false 1))))
; x = x+1 when x |-> infty
(get-model)
(exit)

我将如何在SBV中编码这个呢?我试了下,但那只是崩溃了SBV。此外,我怀疑这是否会做我想做的事,但我对SBV的工作方式还不太熟悉。

代码语言:javascript
复制
!/usr/bin/env stack
{- stack script
  --resolver nightly-2018-11-23
  --package sbv
  --package syb
-}

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}

import Data.Generics
import Data.SBV

data IntX = IntX (Maybe Integer) deriving (Eq, Ord, Data, Read, Show, SymWord, HasKind)

pretty :: IntX -> String
pretty = \case
  IntX Nothing -> "∞"
  IntX n -> show n

instance Num IntX where
  (+) (IntX x) (IntX y) = IntX $ (+) <$> x <*> y
  (*) (IntX x) (IntX y) = IntX $ (*) <$> x <*> y
  fromInteger = IntX . Just

ex1 = sat $ do
  x :: SBV IntX <- free "x"
  return $ x .== x + 1

main :: IO ()
main = print =<< ex1
代码语言:javascript
复制
~/temp ✘ ./sbv.hs
sbv.hs: SBV.SMT.SMTLib2.cvtExp.sh: impossible happened; can't translate: s0 + s1
CallStack (from HasCallStack):

  error, called at ./Data/SBV/SMT/SMTLib2.hs:681:13 in sbv-7.12-9AiNAYtrUhB8YA6mr6BTn4:Data.SBV.SMT.SMTLib2
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-11-23 16:01:52

这里的基本问题是,您的代码正在混合Haskell的具体Maybe类型,并试图将其视为一个符号对象。但是,在SMT-Lib2中如何实现这一点是正确的:您实际上需要在SBV中编写相应的代码。

我首先要说的是:

代码语言:javascript
复制
{-# LANGUAGE DeriveAnyClass  #-}
{-# LANGUAGE DeriveGeneric   #-}
{-# LANGUAGE NamedFieldPuns  #-}

import Data.SBV
import Data.SBV.Control
import GHC.Generics (Generic)

这只是样板;除非您想使用查询模式,否则不需要Data.SBV.Control导入,但正如我们将要看到的那样,它确实很有用。

首先要做的是象征性地编码IntX类型;就像在SMTLib中所做的那样:

代码语言:javascript
复制
data SIntX = SIntX { isInf :: SBool
                   , xVal  :: SInteger
                   }
                   deriving (Generic, Mergeable)

instance Show SIntX where
  show (SIntX inf val) = case (unliteral inf, unliteral val) of
                           (Just True,  _)      -> "oo"
                           (Just False, Just n) -> show n
                           _                    -> "<symbolic>"

上面没有什么是令人惊讶的,除了GenericMergeable的派生。它简单地使SBV能够在扩展的自然状态上使用ite。还请注意Show实例在使用unliteral区分具体值和符号值时是如何小心的。

接下来,我们添加了一些方便函数,也没有什么奇怪的:

代码语言:javascript
复制
inf :: SIntX
inf = SIntX { isInf = true, xVal = 0 }

nat :: SInteger -> SIntX
nat v = SIntX { isInf = false, xVal = v }

liftU :: (SInteger -> SInteger) -> SIntX -> SIntX
liftU op a = ite (isInf a) inf (nat (op (xVal a)))

liftB :: (SInteger -> SInteger -> SInteger) -> SIntX -> SIntX -> SIntX
liftB op a b = ite (isInf a ||| isInf b) inf (nat (xVal a `op` xVal b))

现在我们可以让IntX成为一个数字:

代码语言:javascript
复制
instance Num SIntX where
  (+)         = liftB (+)
  (*)         = liftB (*)
  negate      = liftU negate
  abs         = liftU abs
  signum      = liftU signum
  fromInteger = nat . literal

(请注意,它的语义意味着oo - oo = oo,这充其量是有问题的。但这不是重点。您可能必须显式地定义-并按您的意愿处理它。类似的评论适用于signum。)

因为您想测试是否相等,所以我们还必须定义它的符号版本:

代码语言:javascript
复制
instance EqSymbolic SIntX where
  a .== b = ite (isInf a &&& isInf b) true
          $ ite (isInf a ||| isInf b) false
          $ xVal a .== xVal b

类似地,如果您想进行比较,您必须定义一个OrdSymbolic实例;但是想法是一样的。

我们需要一种方法来创造象征性的延伸自然。下面的函数很好地实现了这个功能:

代码语言:javascript
复制
freeSIntX :: String -> Symbolic SIntX
freeSIntX nm = do i <- sBool    $ nm ++ "_isInf"
                  v <- sInteger $ nm ++ "_xVal"
                  return $ SIntX { isInf = i, xVal = v }

严格地说,您不需要命名变量。(也就是说,不需要nm参数。)但我发现,出于明显的原因,总是给我的变量取名字是有帮助的。

现在,我们可以对您的示例进行编码:

代码语言:javascript
复制
ex1 :: IO SatResult
ex1 = sat $ do x <- freeSIntX "x"
               return $ x .== x+1

当我运行这个时,我得到:

代码语言:javascript
复制
*Main> ex1
Satisfiable. Model:
  x_isInf = True :: Bool
  x_xVal  =    0 :: Integer

我想这就是你要找的。

当您处理较大的程序时,能够更直接地提取IntX值并对它们进行进一步编程是有益的。这是查询模式派上用场的时候。首先是帮手:

代码语言:javascript
复制
data IntX = IntX (Maybe Integer) deriving Show

queryX :: SIntX -> Query IntX
queryX (SIntX {isInf, xVal}) = do
          b <- getValue isInf
          v <- getValue xVal
          return $ IntX $ if b then Nothing
                               else Just v

现在我们可以编码:

代码语言:javascript
复制
ex2 :: IO ()
ex2 = runSMT $ do x <- freeSIntX "x"
                  constrain $ x .== x+1

                  query $ do cs <- checkSat
                             case cs of
                               Unk   -> error "Solver said Unknown!"
                               Unsat -> error "Solver said Unsatisfiable!"
                               Sat   -> do v <- queryX x
                                           io $ print v

我们得到:

代码语言:javascript
复制
*Main> ex2
IntX Nothing

我希望这能帮到你。我把所有这些代码放在一个gist中:https://gist.github.com/LeventErkok/facfd067b813028390c89803b3a0e887

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53444430

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档