使用Z3解决偏序理论时,哪些编码更可取?

使用Z3解决偏序理论时,哪些编码更可取?,z3,smt,partial-ordering,Z3,Smt,Partial Ordering,我正在考虑编码偏序关系的各种方法,以将其提供给Z3 该问题已经以各种方式受到约束,并使用QF_uu逻辑变体(主要是LIA或LRA) 如果变量ei>0=>a0先于ai,则我可以用偏序来表示其他约束条件,其中ei是我问题的一个变量,并且ai变量是新的,表示“先于”偏序约束条件 因此,这个偏序将以不同的方式限制根据ei得到的解 解决方案可以是使用以下示例中未解释的函数: 这正好表达了我想要的,但这也引入了一个新的带有量词的逻辑 另一种选择是将我的元素插入一个具体的域,如Real或Int: ;编码偏

我正在考虑编码偏序关系的各种方法,以将其提供给Z3

该问题已经以各种方式受到约束,并使用QF_uu逻辑变体(主要是LIA或LRA)

如果变量
ei>0=>a0先于ai
,则我可以用偏序来表示其他约束条件,其中
ei
是我问题的一个变量,并且
ai
变量是新的,表示“先于”偏序约束条件

因此,这个偏序将以不同的方式限制根据ei得到的解

解决方案可以是使用以下示例中未解释的函数:

这正好表达了我想要的,但这也引入了一个新的带有量词的逻辑

另一种选择是将我的元素插入一个具体的域,如Real或Int:

;编码偏序优先于与实数的关系
; 一个不成功的例子
(声明常数a0真实)
(声明常数a1真实)
(宣布常数a2为真)
(断言(
代码更简单,不使用量词,但它迫使(可能?)解算器过度思考,因为在第一个版本中,Real比抽象域A具有更多的属性

那么,通常应该首选哪种编码来编码偏序?
我是否应该考虑其他参数,或者我是否可以配置策略来帮助解决此类问题?

如果可以,请避免使用量词。SMT解算器对它们并不擅长,尤其是在理论组合方面。如果你能坚持使用
Int
Real
,那就太好了。如果你能使用位向量,那就更好了,因为即使存在非线性函数,逻辑仍然是可判定的


如果你的模型真的需要量词,我认为SMT解决方案根本不是一个很好的匹配。在这种情况下,看看半自动化系统,如Isabelle、Coq、HOL等。

尽可能避免使用量词。SMT解算器对它们并不擅长,尤其是在理论组合方面。如果你能坚持使用
Int
Real
,那就太好了。如果你能使用位向量,那就更好了,因为即使存在非线性函数,逻辑仍然是可判定的


如果你的模型真的需要量词,我认为SMT解决方案根本不是一个很好的匹配。在这种情况下,看看半自动化系统,如Isabelle、Coq、HOL等。

您还可以尝试特殊关系的内置功能。 至少它们改善了实例化的二次开销 偏序公理。内置的偏序关系是自反的, 因此,如果您想要一个不可伸缩的版本,那么请定义一个排除 反身情况。(uu偏序0)是一种关系,它接受两个相同排序的参数并返回布尔值。(u偏序1)将是不同的关系,因此您可以使用参数索引不同的偏序

(declare-sort A)
(define-fun pre ((x A) (y A)) Bool (and (not (= x y)) ((_ partial-order 0) x y)))
; an UNSAT example
(declare-const a0 A)
(declare-const a1 A)
(declare-const a2 A)
(assert (pre a0 a1))
(assert (pre a1 a2))
(assert (pre a2 a0))
(check-sat)

您还可以尝试特殊关系的内置功能。 至少它们改善了实例化的二次开销 偏序公理。内置的偏序关系是自反的, 因此,如果您想要一个不可伸缩的版本,那么请定义一个排除 反身情况。(uu偏序0)是一种关系,它接受两个相同排序的参数并返回布尔值。(u偏序1)将是不同的关系,因此您可以使用参数索引不同的偏序

(declare-sort A)
(define-fun pre ((x A) (y A)) Bool (and (not (= x y)) ((_ partial-order 0) x y)))
; an UNSAT example
(declare-const a0 A)
(declare-const a1 A)
(declare-const a2 A)
(assert (pre a0 a1))
(assert (pre a1 a2))
(assert (pre a2 a0))
(check-sat)

感谢您给出的答案,哪种类型符合我的直觉,但在理论之间相互作用的有限情况下,解算器是否应该看到它可以在我的抽象类型A上使用Tarjan,而不是用reals实例化?不尝试就无法判断。问题在于,解算器的内部或多或少是一个黑匣子:即使对输入进行很小的更改,也会导致它发散,并且很难调试。如果可以避免,请远离量词。在对这两种解决方案进行试验后,对于我的用例,不使用量词存在巨大的性能差距(秒或“未知”到毫秒),即我们应该更喜欢使用“插入Nat或真实”方法。所以我会接受这个答案。感谢你给出的答案,哪种类型符合我的直觉,但在理论之间的有限互动情况下,解算器是否应该看到它可以使用例如Tarjan在我的抽象类型A上,而不是用reals实例化?不尝试就无法判断。问题在于,解算器的内部或多或少是一个黑匣子:即使对输入进行很小的更改,也会导致它发散,并且很难调试。如果可以避免,请远离量词。在对这两种解决方案进行试验后,对于我的用例,不使用量词存在巨大的性能差距(秒或“未知”到毫秒),即我们应该更喜欢使用“插入Nat或真实”方法。所以我会接受这个答案。雷亚尔的问题是,他们是完全有序的。。。如果这是可以接受的,那肯定是更简单的方法。我会考虑是否有一个很好的嵌入到数据类型中的方法,它不需要太多的量词;但这是强制组合的附加约束,例如,两个完全独立的因果链最终在实数中“完全”有序,或者至少解算器必须考虑它。实数的问题是它们是完全有序的。。。如果这是可以接受的,那肯定是更简单的方法。我会想一想是否有一个很好的嵌入到数据类型中的方法,它对量词的要求不太高。好吧,因为我的约束没有提到相等,所以我最终得到了一个偏序,即使我陷入了实数,二
(declare-sort A)
(define-fun pre ((x A) (y A)) Bool (and (not (= x y)) ((_ partial-order 0) x y)))
; an UNSAT example
(declare-const a0 A)
(declare-const a1 A)
(declare-const a2 A)
(assert (pre a0 a1))
(assert (pre a1 a2))
(assert (pre a2 a0))
(check-sat)