Z3 为什么0=0.5?

Z3 为什么0=0.5?,z3,Z3,在处理.smt2文件时,我注意到Z3 4.3.1有一些奇怪的行为 如果我做了(断言(=0.5)),它将是可以满足的。但是,如果我切换顺序并执行(assert(=0.50)),这是不可满足的 我猜测,如果第一个参数是整数,它将两个参数都转换为整数(将0.5舍入为0),然后进行比较。如果我将“0”更改为“0.0”,它将按预期工作。这与我使用过的大多数编程语言不同,在这些语言中,如果任何一个参数是浮点数,它们都转换为浮点数并进行比较。这真的是Z3中的预期行为吗?我们的一位实习生在研究SMT2的保守扩展

在处理.smt2文件时,我注意到Z3 4.3.1有一些奇怪的行为

如果我做了
(断言(=0.5))
,它将是可以满足的。但是,如果我切换顺序并执行
(assert(=0.50))
,这是不可满足的


我猜测,如果第一个参数是整数,它将两个参数都转换为整数(将0.5舍入为0),然后进行比较。如果我将“0”更改为“0.0”,它将按预期工作。这与我使用过的大多数编程语言不同,在这些语言中,如果任何一个参数是浮点数,它们都转换为浮点数并进行比较。这真的是Z3中的预期行为吗?

我们的一位实习生在研究SMT2的保守扩展和多态性时注意到了同样的奇怪行为,他试图理解混合整数和实数的公式是如何进行类型检查的:

z3()表示下面的示例是SAT,并找到一个模型x=1

(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x 1.5))
(check-sat)
(get-model)
(exit)
但是,它说,UNSAT中的以下“等效”示例

(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 x))
(check-sat)
(exit)

因此,这不符合等式谓词的对称性。因此,我认为这是一个bug。

我认为这是缺乏类型检查的结果;z3太宽大了。它应该简单地拒绝这些查询,因为它们的格式不好

根据SMT Lib标准,v2();第30页;核心理论的定义如下:

(theory Core
:sorts ((Bool 0))
:funs ((true Bool) (false Bool) (not Bool Bool)
      (=> Bool Bool Bool :right-assoc) (and Bool Bool Bool :left-assoc)
      (or Bool Bool Bool :left-assoc) (xor Bool Bool Bool :left-assoc)
      (par (A) (= A A Bool :chainable))
      (par (A) (distinct A A Bool :pairwise))
      (par (A) (ite Bool A A A))
      )
:definition
"For every expanded signature Sigma, the instance of Core with that signature
is the theory consisting of all Sigma-models in which:
  - the sort Bool denotes the set {true, false} of Boolean values;
  - for all sorts s in Sigma,
       - (= s s Bool) denotes the function that
         returns true iff its two arguments are identical;
       - (distinct s s Bool) denotes the function that
         returns true iff its two arguments are not identical;
       - (ite Bool s s) denotes the function that
         returns its second argument or its third depending on whether
         its first argument is true or not;
       - the other function symbols of Core denote the standard Boolean operators
         as expected.
       "
  :values "The set of values for the sort Bool is {true, false}."
)
因此,根据定义,相等要求输入排序相同;因此,上述查询应被视为无效而拒绝


可能会切换到z3或其他一些设置,强制执行比默认情况下更严格的类型检查;但是,即使使用最轻松的实现,我也会预料到这种情况

一个可能的解决方案是

(declare-fun x () Real)
(declare-fun y () Real)
(assert (= x 0))
(assert (= y 0.5))
(check-sat)
(push)
(assert (= x y) )
(check-sat)
(pop)
输出是

sat
unsat

Z3不是唯一的SMT解算器类型检查这些示例:

  • CVC4也接受它们(即使使用选项--smtlib strict),并在上述公式的两种情况下都回答UNSAT

  • Yices接受它们并回答UNSAT(将逻辑更改为QF_LIA后,因为它不支持AUFLIRA)

  • 对于(set logic QF_LIA),Z3发出一个错误:(错误“第3行第17列:逻辑不支持reals”)

  • Alt Ergo说在这两种情况下“键入错误:Int和Real不能统一”。但是Alt Ergo的SMT2解析器非常有限,并且没有经过严格测试,因为我们主要关注它的本地多态语言。因此,不应将其作为参考


我认为开发人员通常假定Int和Real之间存在“隐式”子类型关系。这就是为什么Z3、CVC4和Yices(可能还有其他人)成功地检查了这些示例的类型。

不依赖任何解算器的隐式类型转换。相反 使用
到_real
到_int
进行显式类型转换。只发送 向解算器发送类型良好的公式。然后穆罕默德·伊格内拉拉的例子如下

(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_real x) 1.5))
(check-sat)
(exit)

(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 (to_real x)))
(check-sat)
(exit)
(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_int 1.5) x))
(check-sat)
(get-model)
(exit)

(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x (to_int 1.5)))
(check-sat)
(get-model)
(exit)
这两个都返回Z3和CVC4中的UNSAT。如果相反,你真的 想要找到
x=1
的模型,您应该使用一个 下面是一个例子

(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_real x) 1.5))
(check-sat)
(exit)

(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= 1.5 (to_real x)))
(check-sat)
(exit)
(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= (to_int 1.5) x))
(check-sat)
(get-model)
(exit)

(set-option :produce-models true)
(set-logic AUFLIRA)
(declare-fun x () Int)
(assert (= x (to_int 1.5)))
(check-sat)
(get-model)
(exit)
这两个返回值在Z3和CVC4中均为
x=1


一旦你将所有类型转换都显式化,并且只处理类型良好的公式,等式的参数顺序就不再重要(为了正确)。

Jochen Hoenicke给出了关于“混合实数和整数”的答案(在SMT-LIB邮件列表上)。这是:

我只是想指出,语法可能是正式正确的。 AUFLIRA和AUFNIRA有一个扩展

“对于每个运算符,对于某些 排序s,以及排序Int的每个项t1,t2和排序实的每个项t 表达 -(op t1 t)是(op(to_real t1)t)的语法糖 -(opt t1)是(opt(to_real t1))的语法糖 -(/t1 t2)是(/(to_real t1)(to_real t2))的语法糖。“


严格地说,Z3在默认情况下不符合SMT2.0,这就是其中之一。我们可以加上

(set-option :smtlib2-compliant true) 

然后这个查询确实被正确地拒绝了。

声明:“……与大多数编程语言不同,Z3不会自动将整数转换为实数,反之亦然……”Oki,因此如果没有隐式转换,类型检查时应拒绝断言。@PetrVepřek想知道当您断言
0.5等于0
时,哪些语言会自动将0.5转换为0……它们都违反了SMT库规范。据我所知,该标准不允许存在“子类型”关系;也不清楚这种关系在总体上意味着什么。我建议您在SMT Lib邮件列表中提出这一点,并在那里寻求澄清:“不要依赖于隐含的任何东西”,说起来容易做起来难。这是含蓄的,没有被要求就发生了。我同意!但讨论的是“工具”,而不是“使用工具的人”和“他们应该如何使用工具”。我们开发工具来帮助我们。在这里,SMT求解者应该说示例类型不好。否则,这是一个错误。是的,这是一个错误。工具有漏洞。防御性的。为你拥有的工具而不是你想要的工具编写代码;平等是逻辑学中一个更为基本的概念。我希望标准在这一点上是明确的。在任何一种情况下,原始问题都是开放的:在任何一种情况下,Z3的行为似乎都有一个bug:它要么拒绝查询为无效,要么正确地处理“=”,并像您之前观察到的那样相应地回答这两个问题。