我见过一些用于定义代数数据类型的在线资料,如Z3中的IntList。我想知道如何定义具有逻辑约束的代数数据类型。例如,如何定义代表正整数的PosSort。
答案 0 :(得分:0)
SMT中的总功能
SMT中的函数总是完全的,这引发了如何编码部分函数的问题,例如PosSort
的数据类型构造函数。因此,如果Z3的/ SMT对代数数据类型的内置支持支持部分数据类型构造函数(并且SMT-LIB 2.6 standard似乎同意),我会感到惊讶。
编码部分功能:理论
然而,并非所有希望都失去了,但您可能必须自己编码ADT。假设一个总函数f: A -> B
,它应该对其域f': A ~> B
满足a
的部分数据类型构造函数p(a)
进行建模。在此处,A
可以是Int
,B
可以是List[A]
,p(a)
可以是0 < a
,f(a)
可以定义为f(a) := a :: Nil
(我在这里使用伪代码,但你应该明白这一点。)
一种方法是确保永远不会将f
应用于非正数的a
。根据SMT代码的来源,可能会在每次f
申请之前检查该约束(并提出f
的错误不适用)。
另一种方法是低估f
并有条件地定义它,例如沿着0 < a ==> f(a) := a :: Nil
的路线。这样,f
仍为总数(如前所述,您很可能不得不忍受),但a <= 0
的值未定义。因此,当您尝试证明有关f(a)
的内容时,例如那个head(f(a)) == a
,那么这应该失败(假设head(a :: _)
被定义为a
)。
编码部分功能:一个实际的例子
我太懒了,无法在SMT中编写示例代码,但是this encoding of an integer list(在一种名为Viper的验证语言中)应该让您对如何编码整数列表有一个非常具体的想法使用未解释的函数和公理。该示例基本上可以一对一的方式转换为SMT-LIB。
更改该示例以使其成为正整数列表的公理化是直截了当的:只需将约束head < 0
添加到每个讨论列表头的公理中。即使用以下替代公理:
axiom destruct_over_construct_Cons {
forall head: Int, tail: list :: {Cons(head, tail)}
0 < head ==>
head_Cons(Cons(head, tail)) == head
&& tail_Cons(Cons(head, tail)) == tail
}
...
axiom type_of_Cons {
forall head: Int, tail: list ::
0 < head ==> type(Cons(head, tail)) == type_Cons()
}
如果您使用这些更改在线运行示例,则测试method test_quantifiers()
应立即失败。在列表元素上添加必要的约束,即将其更改为
method test_quantifiers() {
/* The elements of a deconstructed Cons are equivalent to the corresponding arguments of Cons */
assert forall head: Int, tail: list, xs: list ::
0 < head ==>
is_Cons(xs) ==> (head == head_Cons(xs) && tail == tail_Cons(xs) <==> Cons(head, tail) == xs)
/* Two Cons are equal iff their constructors' arguments are equal */
assert forall head1: Int, head2: Int, tail1: list, tail2: list ::
(0 < head1 && 0 < head2) ==>
(Cons(head1, tail1) == Cons(head2, tail2)
<==>
head1 == head2 && tail1 == tail2)
}
应该使验证再次成功。
答案 1 :(得分:0)
您正在寻找的是谓词 - 子类型;据我所知,Yices是唯一支持开箱即用的SMT求解器:http://yices.csl.sri.com/old/language.shtml
请特别参阅此处的示例:http://yices.csl.sri.com/old/language.shtml#language_dependent_types
不幸的是,这是&#34; old&#34; Yices,我不认为这种特定的输入语言会受到支持。正如Malte所说,SMTLib也不支持谓词子类型。
假设您的输出SMTLib已生成,&#34;你可以插入&#34;检查&#34;确保所有元素都保留在域中。但这是相当麻烦的,并不清楚如何处理偏袒。取消规范是一个很好的技巧,但它可能变得非常毛茸茸,导致规范很难调试。
如果您确实需要谓词子类型,那么SMT求解器可能不是您的问题域的最佳选择。定理证明,依赖类型语言等可能更合适。例如,一个实际的例子是用于Haskell程序的LiquidHaskell系统,它允许将谓词附加到类型上以准确地执行您正在尝试的内容;并使用SMT求解器排除相关条件:https://ucsd-progsys.github.io/liquidhaskell-blog/
如果你想坚持SMT求解器并且不介意使用较旧的系统,我建议Yices支持谓词子类型来模拟这些问题。在SMT求解的背景下,这是(并且仍然是)这个想法中最好的实现之一。