为字符串约束设置求解器

时间:2019-08-31 16:37:45

标签: python z3 z3py

我正在尝试使用python中的z3实现问题的求解器(需要字符串操作)。 我尝试阅读documentation,但信息不足。我也尝试阅读z3str documentation,但找不到使示例工作的方法。

我想设置:

len(string) = 8
string[6] = 'a'
string_possible_characters = '3456789a'
string.count("6") = 2

在这种情况下,最好使用itertools(排列+组合)之类的东西吗?

1 个答案:

答案 0 :(得分:1)

z3可以相对轻松地解决此类问题。关于API的使用,有一些学习上的曲线,但是值得投资。话虽如此,如果您的约束相对简单且字符串较短,则枚举它们并使用常规编程检查约束可以很快并且有效的替代方案。但是对于更长的字符串和更复杂的约束,z3将是解决此类问题的理想选择。

这是我用Python编写示例的方式:

# Bring z3 to scope
from z3 import *

# Grab a solver
s = Solver ()

# Create a symbolic string
string = String('string')

# len(string) = 8
s.add(Length(string) == 8)

# string[6] = 'a'
s.add(SubSeq(string, 6, 1) == StringVal('a'))

# string_possible_characters = '3456789a'
chars    = Union([Re(StringVal(c)) for c in '345789a'])   # Note I left 6 out on purpose!
six      = Re(StringVal('6'))

# string.count("6") = 2
# Create a regular expression that matches exactly two occurences
# of 6's and any other allowed character in other positions
template = Concat(Star(chars), six, Star(chars), six, Star(chars))

# Assert our string matches the template
s.add(InRe(string, template))

# Get a model
res = s.check()
if res == sat:
    print s.model()
else:
    print "Solver said:",
    print res

运行它,我得到:

[string = "634436a9"]

满足您的所有约束。您可以在此模板上构建模型来建模其他约束。 API的相关部分在这里:https://z3prover.github.io/api/html/z3py_8py_source.html#l10190

请注意,Python并不是唯一提供对Z3正则表达式和字符串的访问的API。几乎所有其他对z3的高级绑定都提供一定程度的支持,包括C / C ++ / Java / Haskell等。而且,根据这些绑定提供的抽象,这些约束甚至可能更易于编程。例如,这是使用SBV Haskell软件包编码的相同问题,该软件包使用z3作为基础求解器:

{-# LANGUAGE OverloadedStrings #-}

import Data.SBV

import qualified Data.SBV.String as S
import           Data.SBV.RegExp

p :: IO SatResult
p = sat $ do s <- sString "string"

             let others   = KStar $ oneOf "345789a"
                 template = others * "6" * others * "6" * others

             constrain $ S.length s        .== 8
             constrain $ S.strToCharAt s 6 .== literal 'a'
             constrain $ s `match` template

运行时,此程序将产生:

*Main> p
Satisfiable. Model:
  string = "649576a8" :: String

如您所见,Haskell编码相当简洁且易于阅读,而其他语言(例如C,Java等)的编码可能更冗长。当然,您应该选择一种最适合您的宿主语言,但是如果您有这样做的自由,我建议您使用Haskell绑定以便于使用。详细信息在这里:http://hackage.haskell.org/package/sbv