【问题标题】:fresh variables are not shown in found models新变量未显示在找到的模型中
【发布时间】:2019-02-18 12:58:23
【问题描述】:

我正在使用 z3 编写一个静态检查器。我有以下问题:

>>> from z3 import *
>>> s = Solver()
>>> s.add(FreshInt() + FreshInt() > 0)
>>> s.check()
sat
>>> s.model()
[]

如您所见,模型中未显示新变量。我也无法获得它们的价值:

>>> a = FreshInt()
>>> s.add(a > 3)
>>> s.check()
sat
>>> s.model()
[]
>>> s.model()[a]

我查看了文档,但找不到改变这种行为的方法。我可以自己生成唯一的变量,但如果 z3 可以为我处理这个问题,那就太好了。有人可以指出我正确的方向吗?还是不能在 z3py 中更改?

【问题讨论】:

  • 我认为这是由于FreshInt;这些可以被认为是“内部的”。使用a = Int('a'),该示例按预期工作。

标签: z3 smt z3py


【解决方案1】:

FreshInt/FreshReal 等用于创建用户不可见的内部变量。您应该改用Int('name')Real('name') 创建将在模型中显示的用户级变量。

如果你真的想看值,你可以添加一个observer函数并像这样使用它:

from z3 import *

def observeInt(s, a):
    obs = Int('observer')
    s.add(obs == a)
    # might want to check the following really returns sat!
    s.check()
    print s.model()[obs]

s = Solver()
a = FreshInt()
s.add(a + FreshInt() > 0)
s.add(a > 12)
print s.check()
observeInt(s, a)

打印出来:

sat
13

这显然并不便宜(因为它涉及到对check 的调用),但它是安全的,只要它用于调试情况下的强臂 z3 就像你所说的那样,它应该可以解决问题。

【讨论】:

  • 我明白了。所以没有办法告诉求解器/模型“我知道这些不应该是用户可见的,但你能告诉我吗?”,即使这不是预期的行为?
  • 我没有关注。如果你想看到它们,为什么不直接使用Int/Real?这是唯一的区别。 (换句话说,如果你想让 z3 向你展示它们,只需使用 Int/Real,如果你不想自己创建名称,可以使用 Axel 的技巧。)
  • Axel 的技巧并不能保证变量是唯一的。当然,你可以有一个计数器,但如果你在某个地方有错误,你可能会因为字符串匹配而意外重用名称。通过使用 z3 的工具,只有在 z3 中存在错误或者我传递对该变量的引用时,才有可能重用名称。我想在我的检查器中使用这个额外的保证。
  • 我明白你的意思,并在我的回答中添加了一个“强力武装”z3 技巧。希望它对你有用!
【解决方案2】:

您可以通过以下方式规避此限制:

freshIntIdx = 0

def myFreshInt():
    global freshIntIdx
    freshIntIdx += 1;
    return Int('fi' + str(freshIntIdx))

a = myFreshInt()
b = myFreshInt()
s = Solver()
s.add(a + b > 5, a > 0, b > 0, a + b < 10)
print(s.check())
m = s.model()
print("a = %s" % m[a])
print("b = %s" % m[b])

【讨论】:

  • 这确实是我现在拥有的需要唯一变量结果的代码的某些部分。但我更愿意让 z3 也能告诉我新变量的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-02
  • 1970-01-01
  • 2014-05-10
  • 1970-01-01
  • 2019-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多