Z3的C API中的“Z3_mk_forall”和“Z3_mk_forall_const”之间的区别?

时间:2016-07-23 04:34:59

标签: api z3 smt quantifiers

我对2个功能感到困惑。它们似乎采用相同的一组参数(一个可以直接转换为另一个)并且每个都返回一个AST。功能是否做同样的事情?如果没有,我什么时候需要每个?

2的签名:

Z3_ast Z3_mk_forall (Z3_context c,
                     unsigned weight,
                     unsigned num_patterns,
                     Z3_pattern const patterns[],
                     unsigned num_decls,
                     Z3_sort const sorts[],
                     Z3_symbol const decl_names[],
                     Z3_ast body)

Z3_ast Z3_mk_forall_const (Z3_context c,
                           unsigned weight,
                           unsigned num_bound,
                           Z3_app const bound[],
                           unsigned num_patterns,
                           Z3_pattern const patterns[],
                           Z3_ast body)

1 个答案:

答案 0 :(得分:3)

是的,Z3团队提供了多种方法来做同样的事情。主要区别在于Z3_mk_forall_const采用已使用常规机制定义的常量列表,而Z3_mk_forall需要使用Z3_mk_bound创建的绑定变量列表。

哪种机制更易于使用取决于您的具体应用。特别是,在我看来,Z3_mk_forall_const当你想要构建量词的符号数量很少时,Z3_mk_forall会更自然。相反,Z3_mk_forall_const在量词符号的数量可能变化的情况下可能会更自然,在这种情况下,生成一个您将使用索引处理的绑定变量数组是很自然的。

还有其他优点和缺点。例如,请看这个问题: "How to declare constants to use as bound variables in Z3_mk_forall_const?" 在那个问题中,提问者希望避免在其全局上下文中引入大量变量,这对于使用Z3_mk_forall是必要的。回答者(Christoph)建议使用Z3_mk_forall_const代替,但这也不理想,因为对于嵌套量词,这将导致每个量词被不同地索引。克里斯托夫还在答案中透露,在内部,基于Z3_mk_forall的方法被转化为等同于// g++ --std=c++11 z3-quantifier-support.cpp -I../src/api/ -I../src/api/c++/ libz3.so #include <stdio.h> #include "z3.h" #include <iostream> #include "z3++.h" using namespace z3; /** * This is by far the most concise and easiest to use if the C++ API is available to you. */ void example_cpp_forall() { context c; expr a = c.int_const("a"); expr b = c.int_const("b"); expr x = c.int_const("x"); expr axiom = forall(x, implies(x <= a, x < b)); std::cout << "Result obtained using the C++ API with forall:\n" << axiom << "\n\n"; } /** * Example using Z3_mk_forall_const. Not as clean as the C++ example, but this was still * significantly easier for me to get working than the example using Z3_mk_forall(). */ void example_c_Z3_mk_forall_const() { // Get the context Z3_config cfg; Z3_context ctx; cfg = Z3_mk_config(); ctx = Z3_mk_context(cfg); // Declare integers a, b, and x Z3_sort I = Z3_mk_int_sort(ctx); Z3_symbol a_S = Z3_mk_string_symbol(ctx, "a"); Z3_symbol b_S = Z3_mk_string_symbol(ctx, "b"); Z3_symbol x_S = Z3_mk_string_symbol(ctx, "x"); Z3_ast a_A = Z3_mk_const(ctx, a_S, I); Z3_ast b_A = Z3_mk_const(ctx, b_S, I); Z3_ast x_A = Z3_mk_const(ctx, x_S, I); // Build the AST (x <= a) --> (x < b) Z3_ast x_le_a = Z3_mk_le(ctx, x_A, a_A); Z3_ast x_lt_b = Z3_mk_lt(ctx, x_A, b_A); Z3_ast f = Z3_mk_implies(ctx, x_le_a, x_lt_b); Z3_app vars[] = {(Z3_app) x_A}; Z3_ast axiom = Z3_mk_forall_const(ctx, 0, 1, vars, 0, 0, f); printf("Result obtained using the C API with Z3_mk_forall_const:\n"); printf("%s\n\n", Z3_ast_to_string(ctx, axiom)); } /** * Example using Z3_mk_forall. For the example, this is the most cumbersome. */ void example_c_Z3_mk_forall() { // Get the context Z3_config cfg; Z3_context ctx; cfg = Z3_mk_config(); ctx = Z3_mk_context(cfg); // Declare integers a and b Z3_sort I = Z3_mk_int_sort(ctx); Z3_symbol a_S = Z3_mk_string_symbol(ctx, "a"); Z3_symbol b_S = Z3_mk_string_symbol(ctx, "b"); Z3_ast a_A = Z3_mk_const(ctx, a_S, I); Z3_ast b_A = Z3_mk_const(ctx, b_S, I); // Declare bound variables, in this case, just x Z3_symbol x_S = Z3_mk_string_symbol(ctx, "x"); Z3_ast x_A = Z3_mk_bound(ctx, 0, I); // Z3_mk_forall requires all names, types, and bound variables to be provided in // arrays. In this example, where there is only one quantified variable, this seems a // bit cumbersome. If we were dealing with an varying number of quantified variables, // then this would seem more reasonable. const unsigned sz = 1; const Z3_sort types[] = {I}; const Z3_symbol names[] = {x_S}; const Z3_ast xs[] = {x_A}; // Build the AST (x <= a) --> (x < b) Z3_ast x_le_a = Z3_mk_le(ctx, x_A, a_A); Z3_ast x_lt_b = Z3_mk_lt(ctx, x_A, b_A); Z3_ast f = Z3_mk_implies(ctx, x_le_a, x_lt_b); // In the Z3 docs for Z3_mk_pattern, the following sentence appears: "If a pattern is // not provided for a quantifier, then Z3 will automatically compute a set of // patterns for it." So I tried supplying '0' for the number of patterns, and 'NULL' // for the list of patterns, and Z3_mk_forall still seems to function. Z3_ast axiom = Z3_mk_forall(ctx, 0, 0, NULL, sz, types, names, f); printf("Result obtained using the C API with Z3_mk_forall:\n"); printf("%s\n", Z3_ast_to_string(ctx, axiom)); } int main() { example_cpp_forall(); example_c_Z3_mk_forall_const(); example_c_Z3_mk_forall(); } 的方法,所以在引擎盖下确实没有区别。但是,API差异会给程序员带来很大的不同。

如果你能够使用它,那么在C ++ API中还为程序员提供了一种(更简单的)机制。以下是使用三种不同方法的示例:

{{1}}

我也发现这些问题很有用:

Z3源中提供的示例和注释也很有帮助,特别是在examples/c/test_capi.cexamples/c++/example.cppsrc/api/z3_api.h中。