我想将一阶理论放入微软开发的 SMT 求解器 Z3 中。该理论包含两个对象obj1和obj2,一个函数move接受一个对象并返回一个动作,以及一个单一的谓词发生,它将一个动作作为参数。该理论包含公式发生(move(obj1)),我想确保这是发生谓词为真的唯一方式。我通过给出发生的定义来做到这一点:
forall (A) (occurs(A) <-> (A = move(obj1)))
这意味着从理论上可以推断出发生(move(obj1)) ,但发生(move(obj2))不能。为了证明这一点,我把它翻译成 Z3 如下:
(declare-datatypes () (( Obj obj1 obj2 )))
(declare-sort Action 0)
(declare-fun occurs (Action) Bool)
(declare-fun move (Obj) Action)
(assert (forall ((A Action)) (
= (occurs A) (= A (move obj1))
)))
(check-sat)
(get-value ((occurs (move obj1))))
(get-value ((occurs (move obj2))))
问题是这给出了以下输出:
sat
(((occurs (move obj1)) true))
(((occurs (move obj2)) true))
我不明白,因为发生的定义为谓词为真提供了所有必要和充分条件,所以我认为发生(move(obj2))在任何模型中都不能为真。我究竟做错了什么?
更新
感谢 de Moura,我已经能够找到解决问题的方法。我需要做的是为动作提供唯一的名称公理,在我的例子中就是move
函数。我需要声明,当它有两个不同的参数时,它move
永远不会返回相同的排序元素。Action
这可以通过多种方式完成,但我发现这是最简洁的版本:
(assert (forall ((o1 Obj) (o2 Obj))
(=> (not (= o1 o2)) (not (= (move o1) (move o2))))))