diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c
index 07fc05b21..0c6e2fae4 100644
--- a/examples/c/test_capi.c
+++ b/examples/c/test_capi.c
@@ -19,7 +19,7 @@ Copyright (c) 2015 Microsoft Corporation
#define LOG_MSG(msg) ((void)0)
#endif
-/**
+/**
\defgroup capi_ex C API examples
*/
/*@{*/
@@ -31,7 +31,7 @@ Copyright (c) 2015 Microsoft Corporation
/**
\brief exit gracefully in case of error.
*/
-void exitf(const char* message)
+void exitf(const char* message)
{
fprintf(stderr,"BUG: %s.\n", message);
exit(1);
@@ -40,7 +40,7 @@ void exitf(const char* message)
/**
\brief exit if unreachable code was reached.
*/
-void unreachable()
+void unreachable()
{
exitf("unreachable code was reached");
}
@@ -48,7 +48,7 @@ void unreachable()
/**
\brief Simpler error handler.
*/
-void error_handler(Z3_context c, Z3_error_code e)
+void error_handler(Z3_context c, Z3_error_code e)
{
printf("Error code: %d\n", e);
exitf("incorrect use of Z3");
@@ -56,34 +56,34 @@ void error_handler(Z3_context c, Z3_error_code e)
static jmp_buf g_catch_buffer;
/**
- \brief Low tech exceptions.
-
+ \brief Low tech exceptions.
+
In high-level programming languages, an error handler can throw an exception.
*/
-void throw_z3_error(Z3_context c, Z3_error_code e)
+void throw_z3_error(Z3_context c, Z3_error_code e)
{
longjmp(g_catch_buffer, e);
}
/**
- \brief Create a logical context.
+ \brief Create a logical context.
Enable model construction. Other configuration parameters can be passed in the cfg variable.
Also enable tracing to stderr and register custom error handler.
*/
-Z3_context mk_context_custom(Z3_config cfg, Z3_error_handler err)
+Z3_context mk_context_custom(Z3_config cfg, Z3_error_handler err)
{
Z3_context ctx;
-
+
Z3_set_param_value(cfg, "model", "true");
ctx = Z3_mk_context(cfg);
Z3_set_error_handler(ctx, err);
-
+
return ctx;
}
-Z3_solver mk_solver(Z3_context ctx)
+Z3_solver mk_solver(Z3_context ctx)
{
Z3_solver s = Z3_mk_solver(ctx);
Z3_solver_inc_ref(ctx, s);
@@ -102,7 +102,7 @@ void del_solver(Z3_context ctx, Z3_solver s)
Also enable tracing to stderr and register standard error handler.
*/
-Z3_context mk_context()
+Z3_context mk_context()
{
Z3_config cfg;
Z3_context ctx;
@@ -132,7 +132,7 @@ Z3_context mk_proof_context() {
/**
\brief Create a variable using the given name and type.
*/
-Z3_ast mk_var(Z3_context ctx, const char * name, Z3_sort ty)
+Z3_ast mk_var(Z3_context ctx, const char * name, Z3_sort ty)
{
Z3_symbol s = Z3_mk_string_symbol(ctx, name);
return Z3_mk_const(ctx, s, ty);
@@ -141,7 +141,7 @@ Z3_ast mk_var(Z3_context ctx, const char * name, Z3_sort ty)
/**
\brief Create a boolean variable using the given name.
*/
-Z3_ast mk_bool_var(Z3_context ctx, const char * name)
+Z3_ast mk_bool_var(Z3_context ctx, const char * name)
{
Z3_sort ty = Z3_mk_bool_sort(ctx);
return mk_var(ctx, name, ty);
@@ -150,16 +150,16 @@ Z3_ast mk_bool_var(Z3_context ctx, const char * name)
/**
\brief Create an integer variable using the given name.
*/
-Z3_ast mk_int_var(Z3_context ctx, const char * name)
+Z3_ast mk_int_var(Z3_context ctx, const char * name)
{
Z3_sort ty = Z3_mk_int_sort(ctx);
return mk_var(ctx, name, ty);
}
/**
- \brief Create a Z3 integer node using a C int.
+ \brief Create a Z3 integer node using a C int.
*/
-Z3_ast mk_int(Z3_context ctx, int v)
+Z3_ast mk_int(Z3_context ctx, int v)
{
Z3_sort ty = Z3_mk_int_sort(ctx);
return Z3_mk_int(ctx, v, ty);
@@ -168,7 +168,7 @@ Z3_ast mk_int(Z3_context ctx, int v)
/**
\brief Create a real variable using the given name.
*/
-Z3_ast mk_real_var(Z3_context ctx, const char * name)
+Z3_ast mk_real_var(Z3_context ctx, const char * name)
{
Z3_sort ty = Z3_mk_real_sort(ctx);
return mk_var(ctx, name, ty);
@@ -177,7 +177,7 @@ Z3_ast mk_real_var(Z3_context ctx, const char * name)
/**
\brief Create the unary function application: (f x).
*/
-Z3_ast mk_unary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x)
+Z3_ast mk_unary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x)
{
Z3_ast args[1] = {x};
return Z3_mk_app(ctx, f, 1, args);
@@ -186,7 +186,7 @@ Z3_ast mk_unary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x)
/**
\brief Create the binary function application: (f x y).
*/
-Z3_ast mk_binary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x, Z3_ast y)
+Z3_ast mk_binary_app(Z3_context ctx, Z3_func_decl f, Z3_ast x, Z3_ast y)
{
Z3_ast args[2] = {x, y};
return Z3_mk_app(ctx, f, 2, args);
@@ -205,7 +205,7 @@ void check(Z3_context ctx, Z3_solver s, Z3_lbool expected_result)
printf("unsat\n");
break;
case Z3_L_UNDEF:
- printf("unknown\n");
+ printf("unknown\n");
m = Z3_solver_get_model(ctx, s);
if (m) Z3_model_inc_ref(ctx, m);
printf("potential model:\n%s\n", Z3_model_to_string(ctx, m));
@@ -226,7 +226,7 @@ void check(Z3_context ctx, Z3_solver s, Z3_lbool expected_result)
\brief Prove that the constraints already asserted into the logical
context implies the given formula. The result of the proof is
displayed.
-
+
Z3 is a satisfiability checker. So, one can prove \c f by showing
that (not f) is unsatisfiable.
@@ -242,7 +242,7 @@ void prove(Z3_context ctx, Z3_solver s, Z3_ast f, Z3_bool is_valid)
not_f = Z3_mk_not(ctx, f);
Z3_solver_assert(ctx, s, not_f);
-
+
switch (Z3_solver_check(ctx, s)) {
case Z3_L_FALSE:
/* proved */
@@ -286,7 +286,7 @@ void prove(Z3_context ctx, Z3_solver s, Z3_ast f, Z3_bool is_valid)
/**
\brief Assert the axiom: function f is injective in the i-th argument.
-
+
The following axiom is asserted into the logical context:
\code
forall (x_0, ..., x_n) finv(f(x_0, ..., x_i, ..., x_{n-1})) = x_i
@@ -294,7 +294,7 @@ void prove(Z3_context ctx, Z3_solver s, Z3_ast f, Z3_bool is_valid)
Where, \c finv is a fresh function declaration.
*/
-void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i)
+void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i)
{
unsigned sz, j;
Z3_sort finv_domain, finv_range;
@@ -310,7 +310,7 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i)
if (i >= sz) {
exitf("failed to create inj axiom");
}
-
+
/* declare the i-th inverse of f: finv */
finv_domain = Z3_get_range(ctx, f);
finv_range = Z3_get_domain(ctx, f, i);
@@ -320,7 +320,7 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i)
types = (Z3_sort *) malloc(sizeof(Z3_sort) * sz);
names = (Z3_symbol *) malloc(sizeof(Z3_symbol) * sz);
xs = (Z3_ast *) malloc(sizeof(Z3_ast) * sz);
-
+
/* fill types, names and xs */
for (j = 0; j < sz; j++) { types[j] = Z3_get_domain(ctx, f, j); };
for (j = 0; j < sz; j++) { names[j] = Z3_mk_int_symbol(ctx, j); };
@@ -328,7 +328,7 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i)
x_i = xs[i];
- /* create f(x_0, ..., x_i, ..., x_{n-1}) */
+ /* create f(x_0, ..., x_i, ..., x_{n-1}) */
fxs = Z3_mk_app(ctx, f, sz, xs);
/* create f_inv(f(x_0, ..., x_i, ..., x_{n-1})) */
@@ -343,12 +343,12 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i)
printf("\n");
/* create & assert quantifier */
- q = Z3_mk_forall(ctx,
+ q = Z3_mk_forall(ctx,
0, /* using default weight */
1, /* number of patterns */
&p, /* address of the "array" of patterns */
sz, /* number of quantified variables */
- types,
+ types,
names,
eq);
printf("assert axiom:\n%s\n", Z3_ast_to_string(ctx, q));
@@ -361,11 +361,11 @@ void assert_inj_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f, unsigned i)
}
/**
- \brief Assert the axiom: function f is commutative.
-
+ \brief Assert the axiom: function f is commutative.
+
This example uses the SMT-LIB parser to simplify the axiom construction.
*/
-void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f)
+void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f)
{
Z3_sort t;
Z3_symbol f_name, t_name;
@@ -377,16 +377,16 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f)
Z3_get_domain(ctx, f, 0) != t ||
Z3_get_domain(ctx, f, 1) != t) {
exitf("function must be binary, and argument types must be equal to return type");
- }
-
+ }
+
/* Inside the parser, function f will be referenced using the symbol 'f'. */
f_name = Z3_mk_string_symbol(ctx, "f");
-
+
/* Inside the parser, type t will be referenced using the symbol 'T'. */
t_name = Z3_mk_string_symbol(ctx, "T");
-
- Z3_parse_smtlib_string(ctx,
+
+ Z3_parse_smtlib_string(ctx,
"(benchmark comm :formula (forall (x T) (y T) (= (f x y) (f y x))))",
1, &t_name, &t,
1, &f_name, &f);
@@ -396,15 +396,15 @@ void assert_comm_axiom(Z3_context ctx, Z3_solver s, Z3_func_decl f)
}
/**
- \brief Z3 does not support explicitly tuple updates. They can be easily implemented
- as macros. The argument \c t must have tuple type.
+ \brief Z3 does not support explicitly tuple updates. They can be easily implemented
+ as macros. The argument \c t must have tuple type.
A tuple update is a new tuple where field \c i has value \c new_val, and all
other fields have the value of the respective field of \c t.
update(t, i, new_val) is equivalent to
- mk_tuple(proj_0(t), ..., new_val, ..., proj_n(t))
+ mk_tuple(proj_0(t), ..., new_val, ..., proj_n(t))
*/
-Z3_ast mk_tuple_update(Z3_context c, Z3_ast t, unsigned i, Z3_ast new_val)
+Z3_ast mk_tuple_update(Z3_context c, Z3_ast t, unsigned i, Z3_ast new_val)
{
Z3_sort ty;
Z3_func_decl mk_tuple_decl;
@@ -419,11 +419,11 @@ Z3_ast mk_tuple_update(Z3_context c, Z3_ast t, unsigned i, Z3_ast new_val)
}
num_fields = Z3_get_tuple_sort_num_fields(c, ty);
-
+
if (i >= num_fields) {
exitf("invalid tuple update, index is too big");
}
-
+
new_fields = (Z3_ast*) malloc(sizeof(Z3_ast) * num_fields);
for (j = 0; j < num_fields; j++) {
if (i == j) {
@@ -445,7 +445,7 @@ Z3_ast mk_tuple_update(Z3_context c, Z3_ast t, unsigned i, Z3_ast new_val)
/**
\brief Display a symbol in the given output stream.
*/
-void display_symbol(Z3_context c, FILE * out, Z3_symbol s)
+void display_symbol(Z3_context c, FILE * out, Z3_symbol s)
{
switch (Z3_get_symbol_kind(c, s)) {
case Z3_INT_SYMBOL:
@@ -462,7 +462,7 @@ void display_symbol(Z3_context c, FILE * out, Z3_symbol s)
/**
\brief Display the given type.
*/
-void display_sort(Z3_context c, FILE * out, Z3_sort ty)
+void display_sort(Z3_context c, FILE * out, Z3_sort ty)
{
switch (Z3_get_sort_kind(c, ty)) {
case Z3_UNINTERPRETED_SORT:
@@ -480,7 +480,7 @@ void display_sort(Z3_context c, FILE * out, Z3_sort ty)
case Z3_BV_SORT:
fprintf(out, "bv%d", Z3_get_bv_sort_size(c, ty));
break;
- case Z3_ARRAY_SORT:
+ case Z3_ARRAY_SORT:
fprintf(out, "[");
display_sort(c, out, Z3_get_array_sort_domain(c, ty));
fprintf(out, "->");
@@ -488,7 +488,7 @@ void display_sort(Z3_context c, FILE * out, Z3_sort ty)
fprintf(out, "]");
break;
case Z3_DATATYPE_SORT:
- if (Z3_get_datatype_sort_num_constructors(c, ty) != 1)
+ if (Z3_get_datatype_sort_num_constructors(c, ty) != 1)
{
fprintf(out, "%s", Z3_sort_to_string(c,ty));
break;
@@ -516,11 +516,11 @@ void display_sort(Z3_context c, FILE * out, Z3_sort ty)
}
/**
- \brief Custom ast pretty printer.
+ \brief Custom ast pretty printer.
This function demonstrates how to use the API to navigate terms.
*/
-void display_ast(Z3_context c, FILE * out, Z3_ast v)
+void display_ast(Z3_context c, FILE * out, Z3_ast v)
{
switch (Z3_get_ast_kind(c, v)) {
case Z3_NUMERAL_AST: {
@@ -551,7 +551,7 @@ void display_ast(Z3_context c, FILE * out, Z3_ast v)
}
case Z3_QUANTIFIER_AST: {
fprintf(out, "quantifier");
- ;
+ ;
}
default:
fprintf(out, "#unknown");
@@ -561,7 +561,7 @@ void display_ast(Z3_context c, FILE * out, Z3_ast v)
/**
\brief Custom function interpretations pretty printer.
*/
-void display_function_interpretations(Z3_context c, FILE * out, Z3_model m)
+void display_function_interpretations(Z3_context c, FILE * out, Z3_model m)
{
unsigned num_functions, i;
@@ -574,14 +574,14 @@ void display_function_interpretations(Z3_context c, FILE * out, Z3_model m)
Z3_ast func_else;
unsigned num_entries = 0, j;
Z3_func_interp_opt finterp;
-
+
fdecl = Z3_model_get_func_decl(c, m, i);
finterp = Z3_model_get_func_interp(c, m, fdecl);
Z3_func_interp_inc_ref(c, finterp);
name = Z3_get_decl_name(c, fdecl);
display_symbol(c, out, name);
fprintf(out, " = {");
- if (finterp)
+ if (finterp)
num_entries = Z3_func_interp_get_num_entries(c, finterp);
for (j = 0; j < num_entries; j++) {
unsigned num_args, k;
@@ -617,7 +617,7 @@ void display_function_interpretations(Z3_context c, FILE * out, Z3_model m)
/**
\brief Custom model pretty printer.
*/
-void display_model(Z3_context c, FILE * out, Z3_model m)
+void display_model(Z3_context c, FILE * out, Z3_model m)
{
unsigned num_constants;
unsigned i;
@@ -677,7 +677,7 @@ void check2(Z3_context ctx, Z3_solver s, Z3_lbool expected_result)
/**
\brief Display Z3 version in the standard output.
*/
-void display_version()
+void display_version()
{
unsigned major, minor, build, revision;
Z3_get_version(&major, &minor, &build, &revision);
@@ -692,12 +692,12 @@ void display_version()
/**
\brief "Hello world" example: create a Z3 logical context, and delete it.
*/
-void simple_example()
+void simple_example()
{
Z3_context ctx;
LOG_MSG("simple_example");
printf("\nsimple_example\n");
-
+
ctx = mk_context();
/* delete logical context */
@@ -708,7 +708,7 @@ void simple_example()
Demonstration of how Z3 can be used to prove validity of
De Morgan's Duality Law: {e not(x and y) <-> (not x) or ( not y) }
*/
-void demorgan()
+void demorgan()
{
Z3_config cfg;
Z3_context ctx;
@@ -720,7 +720,7 @@ void demorgan()
printf("\nDeMorgan\n");
LOG_MSG("DeMorgan");
-
+
cfg = Z3_mk_config();
ctx = Z3_mk_context(cfg);
Z3_del_config(cfg);
@@ -729,7 +729,7 @@ void demorgan()
symbol_y = Z3_mk_int_symbol(ctx, 1);
x = Z3_mk_const(ctx, symbol_x, bool_sort);
y = Z3_mk_const(ctx, symbol_y, bool_sort);
-
+
/* De Morgan - with a negation around */
/* !(!(x && y) <-> (!x || !y)) */
not_x = Z3_mk_not(ctx, x);
@@ -743,8 +743,8 @@ void demorgan()
rs = Z3_mk_or(ctx, 2, args);
conjecture = Z3_mk_iff(ctx, ls, rs);
negated_conjecture = Z3_mk_not(ctx, conjecture);
-
- s = mk_solver(ctx);
+
+ s = mk_solver(ctx);
Z3_solver_assert(ctx, s, negated_conjecture);
switch (Z3_solver_check(ctx, s)) {
case Z3_L_FALSE:
@@ -767,7 +767,7 @@ void demorgan()
/**
\brief Find a model for x xor y.
*/
-void find_model_example1()
+void find_model_example1()
{
Z3_context ctx;
Z3_ast x, y, x_xor_y;
@@ -782,7 +782,7 @@ void find_model_example1()
x = mk_bool_var(ctx, "x");
y = mk_bool_var(ctx, "y");
x_xor_y = Z3_mk_xor(ctx, x, y);
-
+
Z3_solver_assert(ctx, s, x_xor_y);
printf("model for: x xor y\n");
@@ -796,7 +796,7 @@ void find_model_example1()
\brief Find a model for x < y + 1, x > 2.
Then, assert not(x = y), and find another model.
*/
-void find_model_example2()
+void find_model_example2()
{
Z3_context ctx;
Z3_ast x, y, one, two, y_plus_one;
@@ -807,7 +807,7 @@ void find_model_example2()
printf("\nfind_model_example2\n");
LOG_MSG("find_model_example2");
-
+
ctx = mk_context();
s = mk_solver(ctx);
x = mk_int_var(ctx, "x");
@@ -821,7 +821,7 @@ void find_model_example2()
c1 = Z3_mk_lt(ctx, x, y_plus_one);
c2 = Z3_mk_gt(ctx, x, two);
-
+
Z3_solver_assert(ctx, s, c1);
Z3_solver_assert(ctx, s, c2);
@@ -847,7 +847,7 @@ void find_model_example2()
This function demonstrates how to create uninterpreted types and
functions.
*/
-void prove_example1()
+void prove_example1()
{
Z3_context ctx;
Z3_solver s;
@@ -860,14 +860,14 @@ void prove_example1()
printf("\nprove_example1\n");
LOG_MSG("prove_example1");
-
+
ctx = mk_context();
s = mk_solver(ctx);
/* create uninterpreted type. */
U_name = Z3_mk_string_symbol(ctx, "U");
U = Z3_mk_uninterpreted_sort(ctx, U_name);
-
+
/* declare function g */
g_name = Z3_mk_string_symbol(ctx, "g");
g_domain[0] = U;
@@ -881,7 +881,7 @@ void prove_example1()
/* create g(x), g(y) */
gx = mk_unary_app(ctx, g, x);
gy = mk_unary_app(ctx, g, y);
-
+
/* assert x = y */
eq = Z3_mk_eq(ctx, x, y);
Z3_solver_assert(ctx, s, eq);
@@ -893,7 +893,7 @@ void prove_example1()
/* create g(g(x)) */
ggx = mk_unary_app(ctx, g, gx);
-
+
/* disprove g(g(x)) = g(y) */
f = Z3_mk_eq(ctx, ggx, gy);
printf("disprove: x = y implies g(g(x)) = g(y)\n");
@@ -909,7 +909,7 @@ void prove_example1()
This example demonstrates how to combine uninterpreted functions and arithmetic.
*/
-void prove_example2()
+void prove_example2()
{
Z3_context ctx;
Z3_solver s;
@@ -923,7 +923,7 @@ void prove_example2()
printf("\nprove_example2\n");
LOG_MSG("prove_example2");
-
+
ctx = mk_context();
s = mk_solver(ctx);
@@ -932,7 +932,7 @@ void prove_example2()
g_name = Z3_mk_string_symbol(ctx, "g");
g_domain[0] = int_sort;
g = Z3_mk_func_decl(ctx, g_name, 1, g_domain, int_sort);
-
+
/* create x, y, and z */
x = mk_int_var(ctx, "x");
y = mk_int_var(ctx, "y");
@@ -942,7 +942,7 @@ void prove_example2()
gx = mk_unary_app(ctx, g, x);
gy = mk_unary_app(ctx, g, y);
gz = mk_unary_app(ctx, g, z);
-
+
/* create zero */
zero = mk_int(ctx, 0);
@@ -987,7 +987,7 @@ void prove_example2()
This example also demonstrates how big numbers can be created in Z3.
*/
-void push_pop_example1()
+void push_pop_example1()
{
Z3_context ctx;
Z3_solver s;
@@ -1005,7 +1005,7 @@ void push_pop_example1()
/* create a big number */
int_sort = Z3_mk_int_sort(ctx);
big_number = Z3_mk_numeral(ctx, "1000000000000000000000000000000000000000000000000000000", int_sort);
-
+
/* create number 3 */
three = Z3_mk_numeral(ctx, "3", int_sort);
@@ -1044,7 +1044,7 @@ void push_pop_example1()
check2(ctx, s, Z3_L_TRUE);
/* new constraints can be asserted... */
-
+
/* create y */
y_sym = Z3_mk_string_symbol(ctx, "y");
y = Z3_mk_const(ctx, y_sym, int_sort);
@@ -1056,18 +1056,18 @@ void push_pop_example1()
/* the context is still consistent. */
check2(ctx, s, Z3_L_TRUE);
-
+
del_solver(ctx, s);
Z3_del_context(ctx);
}
/**
- \brief Prove that f(x, y) = f(w, v) implies y = v when
+ \brief Prove that f(x, y) = f(w, v) implies y = v when
\c f is injective in the second argument.
\sa assert_inj_axiom.
*/
-void quantifier_example1()
+void quantifier_example1()
{
Z3_config cfg;
Z3_context ctx;
@@ -1102,10 +1102,10 @@ void quantifier_example1()
f_domain[0] = int_sort;
f_domain[1] = int_sort;
f = Z3_mk_func_decl(ctx, f_name, 2, f_domain, int_sort);
-
+
/* assert that f is injective in the second argument. */
assert_inj_axiom(ctx, s, f, 1);
-
+
/* create x, y, v, w, fxy, fwv */
x = mk_int_var(ctx, "x");
y = mk_int_var(ctx, "y");
@@ -1113,7 +1113,7 @@ void quantifier_example1()
w = mk_int_var(ctx, "w");
fxy = mk_binary_app(ctx, f, x, y);
fwv = mk_binary_app(ctx, f, w, v);
-
+
/* assert f(x, y) = f(w, v) */
p1 = Z3_mk_eq(ctx, fxy, fwv);
Z3_solver_assert(ctx, s, p1);
@@ -1135,15 +1135,15 @@ void quantifier_example1()
del_solver(ctx, s);
Z3_del_context(ctx);
/* reset global parameters set by this function */
- Z3_global_param_reset_all();
+ Z3_global_param_reset_all();
}
/**
\brief Prove store(a1, i1, v1) = store(a2, i2, v2) implies (i1 = i3 or i2 = i3 or select(a1, i3) = select(a2, i3)).
-
+
This example demonstrates how to use the array theory.
*/
-void array_example1()
+void array_example1()
{
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
@@ -1168,10 +1168,10 @@ void array_example1()
i3 = mk_var(ctx, "i3", int_sort);
v1 = mk_var(ctx, "v1", int_sort);
v2 = mk_var(ctx, "v2", int_sort);
-
+
st1 = Z3_mk_store(ctx, a1, i1, v1);
st2 = Z3_mk_store(ctx, a2, i2, v2);
-
+
sel1 = Z3_mk_select(ctx, a1, i3);
sel2 = Z3_mk_select(ctx, a2, i3);
@@ -1201,7 +1201,7 @@ void array_example1()
This example also shows how to use the \c distinct construct.
*/
-void array_example2()
+void array_example2()
{
Z3_context ctx;
Z3_solver s;
@@ -1217,16 +1217,16 @@ void array_example2()
printf("n = %d\n", n);
ctx = mk_context();
s = mk_solver(ctx);
-
+
bool_sort = Z3_mk_bool_sort(ctx);
array_sort = Z3_mk_array_sort(ctx, bool_sort, bool_sort);
-
+
/* create arrays */
for (i = 0; i < n; i++) {
Z3_symbol s = Z3_mk_int_symbol(ctx, i);
a[i] = Z3_mk_const(ctx, s, array_sort);
}
-
+
/* assert distinct(a[0], ..., a[n]) */
d = Z3_mk_distinct(ctx, n, a);
printf("%s\n", Z3_ast_to_string(ctx, d));
@@ -1234,7 +1234,7 @@ void array_example2()
/* context is satisfiable if n < 5 */
check2(ctx, s, n < 5 ? Z3_L_TRUE : Z3_L_FALSE);
-
+
del_solver(ctx, s);
Z3_del_context(ctx);
}
@@ -1243,7 +1243,7 @@ void array_example2()
/**
\brief Simple array type construction/deconstruction example.
*/
-void array_example3()
+void array_example3()
{
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
@@ -1254,13 +1254,13 @@ void array_example3()
bool_sort = Z3_mk_bool_sort(ctx);
- int_sort = Z3_mk_int_sort(ctx);
+ int_sort = Z3_mk_int_sort(ctx);
array_sort = Z3_mk_array_sort(ctx, int_sort, bool_sort);
if (Z3_get_sort_kind(ctx, array_sort) != Z3_ARRAY_SORT) {
exitf("type must be an array type");
}
-
+
domain = Z3_get_array_sort_domain(ctx, array_sort);
range = Z3_get_array_sort_range(ctx, array_sort);
@@ -1282,21 +1282,21 @@ void array_example3()
/**
\brief Simple tuple type example. It creates a tuple that is a pair of real numbers.
*/
-void tuple_example1()
+void tuple_example1()
{
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
Z3_sort real_sort, pair_sort;
Z3_symbol mk_tuple_name;
Z3_func_decl mk_tuple_decl;
- Z3_symbol proj_names[2];
- Z3_sort proj_sorts[2];
+ Z3_symbol proj_names[2];
+ Z3_sort proj_sorts[2];
Z3_func_decl proj_decls[2];
Z3_func_decl get_x_decl, get_y_decl;
printf("\ntuple_example1\n");
LOG_MSG("tuple_example1");
-
+
real_sort = Z3_mk_real_sort(ctx);
@@ -1310,7 +1310,7 @@ void tuple_example1()
pair_sort = Z3_mk_tuple_sort(ctx, mk_tuple_name, 2, proj_names, proj_sorts, &mk_tuple_decl, proj_decls);
get_x_decl = proj_decls[0]; /* function that extracts the first element of a tuple. */
get_y_decl = proj_decls[1]; /* function that extracts the second element of a tuple. */
-
+
printf("tuple_sort: ");
display_sort(ctx, stdout, pair_sort);
printf("\n");
@@ -1319,11 +1319,11 @@ void tuple_example1()
/* prove that get_x(mk_pair(x,y)) == 1 implies x = 1*/
Z3_ast app1, app2, x, y, one;
Z3_ast eq1, eq2, eq3, thm;
-
+
x = mk_real_var(ctx, "x");
y = mk_real_var(ctx, "y");
app1 = mk_binary_app(ctx, mk_tuple_decl, x, y);
- app2 = mk_unary_app(ctx, get_x_decl, app1);
+ app2 = mk_unary_app(ctx, get_x_decl, app1);
one = Z3_mk_numeral(ctx, "1", real_sort);
eq1 = Z3_mk_eq(ctx, app2, one);
eq2 = Z3_mk_eq(ctx, x, one);
@@ -1343,7 +1343,7 @@ void tuple_example1()
Z3_ast p1, p2, x1, x2, y1, y2;
Z3_ast antecedents[2];
Z3_ast antecedent, consequent, thm;
-
+
p1 = mk_var(ctx, "p1", pair_sort);
p2 = mk_var(ctx, "p2", pair_sort);
x1 = mk_unary_app(ctx, get_x_decl, p1);
@@ -1397,7 +1397,7 @@ void tuple_example1()
/**
\brief Simple bit-vector example. This example disproves that x - 10 <= 0 IFF x <= 10 for (32-bit) machine integers
*/
-void bitvector_example1()
+void bitvector_example1()
{
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
@@ -1406,10 +1406,10 @@ void bitvector_example1()
printf("\nbitvector_example1\n");
LOG_MSG("bitvector_example1");
-
-
+
+
bv_sort = Z3_mk_bv_sort(ctx, 32);
-
+
x = mk_var(ctx, "x", bv_sort);
zero = Z3_mk_numeral(ctx, "0", bv_sort);
ten = Z3_mk_numeral(ctx, "10", bv_sort);
@@ -1420,7 +1420,7 @@ void bitvector_example1()
thm = Z3_mk_iff(ctx, c1, c2);
printf("disprove: x - 10 <= 0 IFF x <= 10 for (32-bit) machine integers\n");
prove(ctx, s, thm, Z3_FALSE);
-
+
del_solver(ctx, s);
Z3_del_context(ctx);
}
@@ -1432,7 +1432,7 @@ void bitvector_example2()
{
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
-
+
/* construct x ^ y - 103 == x * y */
Z3_sort bv_sort = Z3_mk_bv_sort(ctx, 32);
Z3_ast x = mk_var(ctx, "x", bv_sort);
@@ -1446,13 +1446,13 @@ void bitvector_example2()
printf("\nbitvector_example2\n");
LOG_MSG("bitvector_example2");
printf("find values of x and y, such that x ^ y - 103 == x * y\n");
-
+
/* add the constraint x ^ y - 103 == x * y<\tt> to the logical context */
Z3_solver_assert(ctx, s, ctr);
-
+
/* find a model (i.e., values for x an y that satisfy the constraint */
check(ctx, s, Z3_L_TRUE);
-
+
del_solver(ctx, s);
Z3_del_context(ctx);
}
@@ -1460,7 +1460,7 @@ void bitvector_example2()
/**
\brief Demonstrate how to use #Z3_eval.
*/
-void eval_example1()
+void eval_example1()
{
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
@@ -1470,11 +1470,11 @@ void eval_example1()
printf("\neval_example1\n");
LOG_MSG("eval_example1");
-
+
x = mk_int_var(ctx, "x");
y = mk_int_var(ctx, "y");
two = mk_int(ctx, 2);
-
+
/* assert x < y */
c1 = Z3_mk_lt(ctx, x, y);
Z3_solver_assert(ctx, s, c1);
@@ -1514,7 +1514,7 @@ void eval_example1()
/**
\brief Several logical context can be used simultaneously.
*/
-void two_contexts_example1()
+void two_contexts_example1()
{
Z3_context ctx1, ctx2;
Z3_ast x1, x2;
@@ -1525,22 +1525,22 @@ void two_contexts_example1()
/* using the same (default) configuration to initialized both logical contexts. */
ctx1 = mk_context();
ctx2 = mk_context();
-
+
x1 = Z3_mk_const(ctx1, Z3_mk_int_symbol(ctx1,0), Z3_mk_bool_sort(ctx1));
x2 = Z3_mk_const(ctx2, Z3_mk_int_symbol(ctx2,0), Z3_mk_bool_sort(ctx2));
Z3_del_context(ctx1);
-
+
/* ctx2 can still be used. */
printf("%s\n", Z3_ast_to_string(ctx2, x2));
-
+
Z3_del_context(ctx2);
}
/**
\brief Demonstrates how error codes can be read insted of registering an error handler.
*/
-void error_code_example1()
+void error_code_example1()
{
Z3_config cfg;
Z3_context ctx;
@@ -1563,7 +1563,7 @@ void error_code_example1()
x = mk_bool_var(ctx, "x");
x_decl = Z3_get_app_decl(ctx, Z3_to_app(ctx, x));
Z3_solver_assert(ctx, s, x);
-
+
if (Z3_solver_check(ctx, s) != Z3_L_TRUE) {
exitf("unexpected result");
}
@@ -1596,19 +1596,19 @@ void error_code_example2() {
printf("\nerror_code_example2\n");
LOG_MSG("error_code_example2");
-
+
/* low tech try&catch */
r = setjmp(g_catch_buffer);
if (r == 0) {
Z3_ast x, y, app;
-
+
cfg = Z3_mk_config();
ctx = mk_context_custom(cfg, throw_z3_error);
Z3_del_config(cfg);
-
+
x = mk_int_var(ctx, "x");
y = mk_bool_var(ctx, "y");
- printf("before Z3_mk_iff\n");
+ printf("before Z3_mk_iff\n");
/* the next call will produce an error */
app = Z3_mk_iff(ctx, x, y);
unreachable();
@@ -1625,7 +1625,7 @@ void error_code_example2() {
/**
\brief Demonstrates how to use the SMTLIB parser.
*/
-void parser_example1()
+void parser_example1()
{
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
@@ -1633,9 +1633,9 @@ void parser_example1()
printf("\nparser_example1\n");
LOG_MSG("parser_example1");
-
-
- Z3_parse_smtlib_string(ctx,
+
+
+ Z3_parse_smtlib_string(ctx,
"(benchmark tst :extrafuns ((x Int) (y Int)) :formula (> x y) :formula (> x 0))",
0, 0, 0,
0, 0, 0);
@@ -1645,7 +1645,7 @@ void parser_example1()
printf("formula %d: %s\n", i, Z3_ast_to_string(ctx, f));
Z3_solver_assert(ctx, s, f);
}
-
+
check(ctx, s, Z3_L_TRUE);
del_solver(ctx, s);
@@ -1655,7 +1655,7 @@ void parser_example1()
/**
\brief Demonstrates how to initialize the parser symbol table.
*/
-void parser_example2()
+void parser_example2()
{
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
@@ -1671,16 +1671,16 @@ void parser_example2()
/* Z3_enable_arithmetic doesn't need to be invoked in this example
because it will be implicitly invoked by mk_int_var.
*/
-
+
x = mk_int_var(ctx, "x");
decls[0] = Z3_get_app_decl(ctx, Z3_to_app(ctx, x));
y = mk_int_var(ctx, "y");
decls[1] = Z3_get_app_decl(ctx, Z3_to_app(ctx, y));
-
+
names[0] = Z3_mk_string_symbol(ctx, "a");
names[1] = Z3_mk_string_symbol(ctx, "b");
-
- Z3_parse_smtlib_string(ctx,
+
+ Z3_parse_smtlib_string(ctx,
"(benchmark tst :formula (> a b))",
0, 0, 0,
/* 'x' and 'y' declarations are inserted as 'a' and 'b' into the parser symbol table. */
@@ -1697,7 +1697,7 @@ void parser_example2()
/**
\brief Demonstrates how to initialize the parser symbol table.
*/
-void parser_example3()
+void parser_example3()
{
Z3_config cfg;
Z3_context ctx;
@@ -1724,10 +1724,10 @@ void parser_example3()
g_domain[0] = int_sort;
g_domain[1] = int_sort;
g = Z3_mk_func_decl(ctx, g_name, 2, g_domain, int_sort);
-
+
assert_comm_axiom(ctx, s, g);
- Z3_parse_smtlib_string(ctx,
+ Z3_parse_smtlib_string(ctx,
"(benchmark tst :formula (forall (x Int) (y Int) (implies (= x y) (= (g x 0) (g 0 y)))))",
0, 0, 0,
1, &g_name, &g);
@@ -1742,17 +1742,17 @@ void parser_example3()
/**
\brief Display the declarations, assumptions and formulas in a SMT-LIB string.
*/
-void parser_example4()
+void parser_example4()
{
Z3_context ctx;
unsigned i, num_decls, num_assumptions, num_formulas;
printf("\nparser_example4\n");
LOG_MSG("parser_example4");
-
+
ctx = mk_context();
-
- Z3_parse_smtlib_string(ctx,
+
+ Z3_parse_smtlib_string(ctx,
"(benchmark tst :extrafuns ((x Int) (y Int)) :assumption (= x 20) :formula (> x y) :formula (> x 0))",
0, 0, 0,
0, 0, 0);
@@ -1792,8 +1792,8 @@ void parser_example5() {
ctx = mk_context_custom(cfg, throw_z3_error);
s = mk_solver(ctx);
Z3_del_config(cfg);
-
- Z3_parse_smtlib_string(ctx,
+
+ Z3_parse_smtlib_string(ctx,
/* the following string has a parsing error: missing parenthesis */
"(benchmark tst :extrafuns ((x Int (y Int)) :formula (> x y) :formula (> x 0))",
0, 0, 0,
@@ -1822,7 +1822,7 @@ void numeral_example() {
Z3_sort real_ty;
printf("\nnumeral_example\n");
LOG_MSG("numeral_example");
-
+
ctx = mk_context();
s = mk_solver(ctx);
@@ -1841,25 +1841,25 @@ void numeral_example() {
del_solver(ctx, s);
Z3_del_context(ctx);
}
-
+
/**
\brief Test ite-term (if-then-else terms).
*/
-void ite_example()
+void ite_example()
{
Z3_context ctx;
Z3_ast f, one, zero, ite;
-
+
printf("\nite_example\n");
LOG_MSG("ite_example");
ctx = mk_context();
-
+
f = Z3_mk_false(ctx);
one = mk_int(ctx, 1);
zero = mk_int(ctx, 0);
ite = Z3_mk_ite(ctx, f, one, zero);
-
+
printf("term: %s\n", Z3_ast_to_string(ctx, ite));
/* delete logical context */
@@ -1879,7 +1879,7 @@ void enum_example() {
Z3_func_decl enum_testers[3];
Z3_ast apple, orange, banana, fruity;
Z3_ast ors[3];
-
+
printf("\nenum_example\n");
LOG_MSG("enum_example");
@@ -1888,7 +1888,7 @@ void enum_example() {
enum_names[2] = Z3_mk_string_symbol(ctx,"orange");
fruit = Z3_mk_enumeration_sort(ctx, name, 3, enum_names, enum_consts, enum_testers);
-
+
printf("%s\n", Z3_func_decl_to_string(ctx, enum_consts[0]));
printf("%s\n", Z3_func_decl_to_string(ctx, enum_consts[1]));
printf("%s\n", Z3_func_decl_to_string(ctx, enum_consts[2]));
@@ -1935,7 +1935,7 @@ void list_example() {
Z3_func_decl nil_decl, is_nil_decl, cons_decl, is_cons_decl, head_decl, tail_decl;
Z3_ast nil, l1, l2, x, y, u, v, fml, fml1;
Z3_ast ors[2];
-
+
printf("\nlist_example\n");
LOG_MSG("list_example");
@@ -1944,7 +1944,7 @@ void list_example() {
int_list = Z3_mk_list_sort(ctx, Z3_mk_string_symbol(ctx, "int_list"), int_ty,
&nil_decl, &is_nil_decl, &cons_decl, &is_cons_decl, &head_decl, &tail_decl);
-
+
nil = Z3_mk_app(ctx, nil_decl, 0, 0);
l1 = mk_binary_app(ctx, cons_decl, mk_int(ctx, 1), nil);
l2 = mk_binary_app(ctx, cons_decl, mk_int(ctx, 2), nil);
@@ -1957,14 +1957,14 @@ void list_example() {
/* cons(x,nil) = cons(y, nil) => x = y */
x = mk_var(ctx, "x", int_ty);
- y = mk_var(ctx, "y", int_ty);
+ y = mk_var(ctx, "y", int_ty);
l1 = mk_binary_app(ctx, cons_decl, x, nil);
l2 = mk_binary_app(ctx, cons_decl, y, nil);
prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, x, y)), Z3_TRUE);
/* cons(x,u) = cons(x, v) => u = v */
u = mk_var(ctx, "u", int_list);
- v = mk_var(ctx, "v", int_list);
+ v = mk_var(ctx, "v", int_list);
l1 = mk_binary_app(ctx, cons_decl, x, u);
l2 = mk_binary_app(ctx, cons_decl, y, v);
prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), Z3_TRUE);
@@ -1975,7 +1975,7 @@ void list_example() {
ors[1] = Z3_mk_app(ctx, is_cons_decl, 1, &u);
prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE);
- /* occurs check u != cons(x,u) */
+ /* occurs check u != cons(x,u) */
prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE);
/* destructors: is_cons(u) => u = cons(head(u),tail(u)) */
@@ -1993,7 +1993,7 @@ void list_example() {
/**
\brief Create a binary tree datatype.
-*/
+*/
void tree_example() {
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
@@ -2015,7 +2015,7 @@ void tree_example() {
cons_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "cons"), Z3_mk_string_symbol(ctx, "is_cons"), 2, head_tail, sorts, sort_refs);
constructors[0] = nil_con;
constructors[1] = cons_con;
-
+
cell = Z3_mk_datatype(ctx, Z3_mk_string_symbol(ctx, "cell"), 2, constructors);
Z3_query_constructor(ctx, nil_con, 0, &nil_decl, &is_nil_decl, 0);
@@ -2036,9 +2036,9 @@ void tree_example() {
/* cons(x,u) = cons(x, v) => u = v */
u = mk_var(ctx, "u", cell);
- v = mk_var(ctx, "v", cell);
+ v = mk_var(ctx, "v", cell);
x = mk_var(ctx, "x", cell);
- y = mk_var(ctx, "y", cell);
+ y = mk_var(ctx, "y", cell);
l1 = mk_binary_app(ctx, cons_decl, x, u);
l2 = mk_binary_app(ctx, cons_decl, y, v);
prove(ctx, s, Z3_mk_implies(ctx, Z3_mk_eq(ctx,l1,l2), Z3_mk_eq(ctx, u, v)), Z3_TRUE);
@@ -2049,7 +2049,7 @@ void tree_example() {
ors[1] = Z3_mk_app(ctx, is_cons_decl, 1, &u);
prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE);
- /* occurs check u != cons(x,u) */
+ /* occurs check u != cons(x,u) */
prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE);
/* destructors: is_cons(u) => u = cons(car(u),cdr(u)) */
@@ -2072,7 +2072,7 @@ void tree_example() {
forest ::= nil | cons(tree, forest)
tree ::= nil | cons(forest, forest)
-*/
+*/
void forest_example() {
Z3_context ctx = mk_context();
@@ -2110,7 +2110,7 @@ void forest_example() {
cons2_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "cons2"), Z3_mk_string_symbol(ctx, "is_cons2"),2, head_tail, sorts, sort_refs);
constructors2[0] = nil2_con;
constructors2[1] = cons2_con;
-
+
clist1 = Z3_mk_constructor_list(ctx, 2, constructors1);
clist2 = Z3_mk_constructor_list(ctx, 2, constructors2);
@@ -2130,7 +2130,7 @@ void forest_example() {
Z3_query_constructor(ctx, cons2_con, 2, &cons2_decl, &is_cons2_decl, cons_accessors);
car2_decl = cons_accessors[0];
cdr2_decl = cons_accessors[1];
-
+
Z3_del_constructor_list(ctx, clist1);
Z3_del_constructor_list(ctx, clist2);
Z3_del_constructor(ctx,nil1_con);
@@ -2156,7 +2156,7 @@ void forest_example() {
/* cons(x,u) = cons(x, v) => u = v */
u = mk_var(ctx, "u", forest);
- v = mk_var(ctx, "v", forest);
+ v = mk_var(ctx, "v", forest);
x = mk_var(ctx, "x", tree);
y = mk_var(ctx, "y", tree);
l1 = mk_binary_app(ctx, cons1_decl, x, u);
@@ -2169,7 +2169,7 @@ void forest_example() {
ors[1] = Z3_mk_app(ctx, is_cons1_decl, 1, &u);
prove(ctx, s, Z3_mk_or(ctx, 2, ors), Z3_TRUE);
- /* occurs check u != cons(x,u) */
+ /* occurs check u != cons(x,u) */
prove(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, u, l1)), Z3_TRUE);
/* delete logical context */
@@ -2181,14 +2181,14 @@ void forest_example() {
/**
\brief Create a binary tree datatype of the form
- BinTree ::= nil
+ BinTree ::= nil
| node(value : Int, left : BinTree, right : BinTree)
-*/
+*/
void binary_tree_example() {
Z3_context ctx = mk_context();
Z3_solver s = mk_solver(ctx);
Z3_sort cell;
- Z3_func_decl
+ Z3_func_decl
nil_decl, /* nil : BinTree (constructor) */
is_nil_decl, /* is_nil : BinTree -> Bool (tester, return true if the given BinTree is a nil) */
node_decl, /* node : Int, BinTree, BinTree -> BinTree (constructor) */
@@ -2208,15 +2208,15 @@ void binary_tree_example() {
/* nil_con and node_con are auxiliary datastructures used to create the new recursive datatype BinTree */
nil_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "nil"), Z3_mk_string_symbol(ctx, "is-nil"), 0, 0, 0, 0);
- node_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "node"), Z3_mk_string_symbol(ctx, "is-cons"),
+ node_con = Z3_mk_constructor(ctx, Z3_mk_string_symbol(ctx, "node"), Z3_mk_string_symbol(ctx, "is-cons"),
3, node_accessor_names, node_accessor_sorts, node_accessor_sort_refs);
constructors[0] = nil_con;
constructors[1] = node_con;
-
+
/* create the new recursive datatype */
cell = Z3_mk_datatype(ctx, Z3_mk_string_symbol(ctx, "BinTree"), 2, constructors);
- /* retrieve the new declarations: constructors (nil_decl, node_decl), testers (is_nil_decl, is_cons_del), and
+ /* retrieve the new declarations: constructors (nil_decl, node_decl), testers (is_nil_decl, is_cons_del), and
accessors (value_decl, left_decl, right_decl */
Z3_query_constructor(ctx, nil_con, 0, &nil_decl, &is_nil_decl, 0);
Z3_query_constructor(ctx, node_con, 3, &node_decl, &is_node_decl, node_accessors);
@@ -2267,7 +2267,7 @@ void binary_tree_example() {
\brief Prove a theorem and extract, and print the proof.
This example illustrates the use of #Z3_check_assumptions.
-*/
+*/
void unsat_core_and_proof_example() {
Z3_context ctx = mk_proof_context();
Z3_solver s = mk_solver(ctx);
@@ -2290,7 +2290,7 @@ void unsat_core_and_proof_example() {
Z3_ast g1[2] = { f1, p1 };
Z3_ast g2[2] = { f2, p2 };
Z3_ast g3[2] = { f3, p3 };
- Z3_ast g4[2] = { f4, p4 };
+ Z3_ast g4[2] = { f4, p4 };
Z3_lbool result;
Z3_ast proof;
Z3_model m = 0;
@@ -2299,7 +2299,7 @@ void unsat_core_and_proof_example() {
printf("\nunsat_core_and_proof_example\n");
LOG_MSG("unsat_core_and_proof_example");
-
+
Z3_solver_assert(ctx, s, Z3_mk_or(ctx, 2, g1));
Z3_solver_assert(ctx, s, Z3_mk_or(ctx, 2, g2));
Z3_solver_assert(ctx, s, Z3_mk_or(ctx, 2, g3));
@@ -2381,7 +2381,7 @@ void del_ext_context(Z3_ext_context ctx) {
/**
\brief Create a retractable constraint.
-
+
\return An id that can be used to retract/reassert the constraint.
*/
unsigned assert_retractable_cnstr(Z3_ext_context ctx, Z3_ast c) {
@@ -2488,7 +2488,7 @@ void incremental_example1() {
z = mk_int_var(ctx, "z");
two = mk_int(ctx, 2);
one = mk_int(ctx, 1);
-
+
/* assert x < y */
c1 = assert_retractable_cnstr(ext_ctx, Z3_mk_lt(ctx, x, y));
/* assert x = z */
@@ -2497,8 +2497,8 @@ void incremental_example1() {
c3 = assert_retractable_cnstr(ext_ctx, Z3_mk_gt(ctx, x, two));
/* assert y < 1 */
c4 = assert_retractable_cnstr(ext_ctx, Z3_mk_lt(ctx, y, one));
-
- result = ext_check(ext_ctx);
+
+ result = ext_check(ext_ctx);
if (result != Z3_L_FALSE)
exitf("bug in Z3");
printf("unsat\n");
@@ -2550,7 +2550,7 @@ void reference_counter_example() {
// Create a Z3 context where the user is reponsible for managing
// Z3_ast reference counters.
ctx = Z3_mk_context_rc(cfg);
- Z3_del_config(cfg);
+ Z3_del_config(cfg);
s = mk_solver(ctx);
Z3_solver_inc_ref(ctx, s);
@@ -2564,16 +2564,16 @@ void reference_counter_example() {
y = Z3_mk_const(ctx, sy, ty);
Z3_inc_ref(ctx, y);
// ty is not needed anymore.
- Z3_dec_ref(ctx, Z3_sort_to_ast(ctx, ty));
+ Z3_dec_ref(ctx, Z3_sort_to_ast(ctx, ty));
x_xor_y = Z3_mk_xor(ctx, x, y);
Z3_inc_ref(ctx, x_xor_y);
// x and y are not needed anymore.
- Z3_dec_ref(ctx, x);
+ Z3_dec_ref(ctx, x);
Z3_dec_ref(ctx, y);
Z3_solver_assert(ctx, s, x_xor_y);
// x_or_y is not needed anymore.
- Z3_dec_ref(ctx, x_xor_y);
-
+ Z3_dec_ref(ctx, x_xor_y);
+
printf("model for: x xor y\n");
check(ctx, s, Z3_L_TRUE);
@@ -2619,12 +2619,12 @@ void substitute_example() {
int_ty = Z3_mk_int_sort(ctx);
a = mk_int_var(ctx,"a");
b = mk_int_var(ctx,"b");
- {
+ {
Z3_sort f_domain[2] = { int_ty, int_ty };
f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 2, f_domain, int_ty);
}
g = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "g"), 1, &int_ty, int_ty);
- {
+ {
Z3_ast args[2] = { a, b };
fab = Z3_mk_app(ctx, f, 2, args);
}
@@ -2665,12 +2665,12 @@ void substitute_vars_example() {
int_ty = Z3_mk_int_sort(ctx);
x0 = Z3_mk_bound(ctx, 0, int_ty);
x1 = Z3_mk_bound(ctx, 1, int_ty);
- {
+ {
Z3_sort f_domain[2] = { int_ty, int_ty };
f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 2, f_domain, int_ty);
}
g = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "g"), 1, &int_ty, int_ty);
- {
+ {
Z3_ast args[2] = { x0, x1 };
f01 = Z3_mk_app(ctx, f, 2, args);
}
@@ -2706,7 +2706,7 @@ void fpa_example() {
printf("\nFPA-example\n");
LOG_MSG("FPA-example");
-
+
cfg = Z3_mk_config();
ctx = Z3_mk_context(cfg);
s = mk_solver(ctx);
@@ -2715,7 +2715,7 @@ void fpa_example() {
double_sort = Z3_mk_fpa_sort(ctx, 11, 53);
rm_sort = Z3_mk_fpa_rounding_mode_sort(ctx);
- // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode).
+ // Show that there are x, y s.t. (x + y) = 42.0 (with rounding mode).
s_rm = Z3_mk_string_symbol(ctx, "rm");
rm = Z3_mk_const(ctx, s_rm, rm_sort);
s_x = Z3_mk_string_symbol(ctx, "x");
@@ -2742,33 +2742,33 @@ void fpa_example() {
args3[0] = c3;
args3[1] = Z3_mk_and(ctx, 3, and_args);
c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3);
-
+
printf("c4: %s\n", Z3_ast_to_string(ctx, c4));
- Z3_solver_push(ctx, s);
+ Z3_solver_push(ctx, s);
Z3_solver_assert(ctx, s, c4);
check(ctx, s, Z3_L_TRUE);
Z3_solver_pop(ctx, s, 1);
// Show that the following are equal:
- // (fp #b0 #b10000000001 #xc000000000000)
+ // (fp #b0 #b10000000001 #xc000000000000)
// ((_ to_fp 11 53) #x401c000000000000))
// ((_ to_fp 11 53) RTZ 1.75 2)))
// ((_ to_fp 11 53) RTZ 7.0)))
-
+
Z3_solver_push(ctx, s);
- c1 = Z3_mk_fpa_fp(ctx,
+ c1 = Z3_mk_fpa_fp(ctx,
Z3_mk_numeral(ctx, "0", Z3_mk_bv_sort(ctx, 1)),
- Z3_mk_numeral(ctx, "3377699720527872", Z3_mk_bv_sort(ctx, 52)),
- Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11)));
+ Z3_mk_numeral(ctx, "1025", Z3_mk_bv_sort(ctx, 11)),
+ Z3_mk_numeral(ctx, "3377699720527872", Z3_mk_bv_sort(ctx, 52)));
c2 = Z3_mk_fpa_to_fp_bv(ctx,
Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)),
Z3_mk_fpa_sort(ctx, 11, 53));
- c3 = Z3_mk_fpa_to_fp_int_real(ctx,
+ c3 = Z3_mk_fpa_to_fp_int_real(ctx,
Z3_mk_fpa_rtz(ctx),
- Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)),
- Z3_mk_numeral(ctx, "1.75", Z3_mk_real_sort(ctx)),
+ Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)), /* exponent */
+ Z3_mk_numeral(ctx, "1.75", Z3_mk_real_sort(ctx)), /* significand */
Z3_mk_fpa_sort(ctx, 11, 53));
- c4 = Z3_mk_fpa_to_fp_real(ctx,
+ c4 = Z3_mk_fpa_to_fp_real(ctx,
Z3_mk_fpa_rtz(ctx),
Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)),
Z3_mk_fpa_sort(ctx, 11, 53));
diff --git a/scripts/mk_copyright.py b/scripts/mk_copyright.py
index 730020a38..3651e3819 100644
--- a/scripts/mk_copyright.py
+++ b/scripts/mk_copyright.py
@@ -19,15 +19,15 @@ def has_cr(file):
lines = 0
line = ins.readline()
while line and lines < 20:
- m = cr.search(line)
- if m:
- ins.close()
- return True
- m = aut.search(line)
- if m:
- ins.close()
- return True
- line = ins.readline()
+ m = cr.search(line)
+ if m:
+ ins.close()
+ return True
+ m = aut.search(line)
+ if m:
+ ins.close()
+ return True
+ line = ins.readline()
ins.close()
return False
@@ -38,20 +38,20 @@ def add_cr(file):
ous.write(cr_notice)
line = ins.readline()
while line:
- ous.write(line)
- line = ins.readline()
+ ous.write(line)
+ line = ins.readline()
ins.close()
ous.close()
os.system("move %s %s" % (tmp, file))
-
+
def add_missing_cr(dir):
for root, dirs, files in os.walk(dir):
- for f in files:
- if f.endswith('.cpp') or f.endswith('.h') or f.endswith('.c') or f.endswith('.cs'):
- path = "%s\\%s" % (root, f)
- if not has_cr(path):
- print("Missing CR for %s" % path)
- add_cr(path)
+ for f in files:
+ if f.endswith('.cpp') or f.endswith('.h') or f.endswith('.c') or f.endswith('.cs'):
+ path = "%s\\%s" % (root, f)
+ if not has_cr(path):
+ print("Missing CR for %s" % path)
+ add_cr(path)
add_missing_cr('src')
add_missing_cr('examples')
diff --git a/scripts/mk_make.py b/scripts/mk_make.py
index ecf70a8c5..813cd3a66 100644
--- a/scripts/mk_make.py
+++ b/scripts/mk_make.py
@@ -1,7 +1,7 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
-#
-# Scripts for generating Makefiles and Visual
+#
+# Scripts for generating Makefiles and Visual
# Studio project files.
#
# Author: Leonardo de Moura (leonardo)
@@ -17,6 +17,7 @@ update_version()
mk_auto_src()
mk_bindings(API_files)
mk_vs_proj('z3', ['shell'])
+mk_vs_proj_dll('libz3', ['api_dll'])
mk_makefile()
diff --git a/scripts/mk_project.py b/scripts/mk_project.py
index 12e8fea3c..b1b3fdef8 100644
--- a/scripts/mk_project.py
+++ b/scripts/mk_project.py
@@ -16,11 +16,12 @@ def init_project_def():
add_lib('nlsat', ['polynomial', 'sat'])
add_lib('hilbert', ['util'], 'math/hilbert')
add_lib('simplex', ['util'], 'math/simplex')
+ add_lib('automata', ['util'], 'math/automata')
add_lib('interval', ['util'], 'math/interval')
add_lib('realclosure', ['interval'], 'math/realclosure')
add_lib('subpaving', ['interval'], 'math/subpaving')
add_lib('ast', ['util', 'polynomial'])
- add_lib('rewriter', ['ast', 'polynomial'], 'ast/rewriter')
+ add_lib('rewriter', ['ast', 'polynomial', 'automata'], 'ast/rewriter')
add_lib('normal_forms', ['rewriter'], 'ast/normal_forms')
add_lib('model', ['rewriter'])
add_lib('tactic', ['ast', 'model'])
diff --git a/scripts/mk_util.py b/scripts/mk_util.py
index df8cae237..6a070fe93 100644
--- a/scripts/mk_util.py
+++ b/scripts/mk_util.py
@@ -559,7 +559,7 @@ def dos2unix_tree():
for root, dirs, files in os.walk('src'):
for f in files:
dos2unix(os.path.join(root, f))
-
+
def check_eol():
if not IS_WINDOWS:
@@ -643,7 +643,7 @@ def display_help(exit_code):
def parse_options():
global VERBOSE, DEBUG_MODE, IS_WINDOWS, VS_X64, ONLY_MAKEFILES, SHOW_CPPS, VS_PROJ, TRACE, VS_PAR, VS_PAR_NUM
global DOTNET_ENABLED, JAVA_ENABLED, ML_ENABLED, STATIC_LIB, PREFIX, GMP, FOCI2, FOCI2LIB, PYTHON_PACKAGE_DIR, GPROF, GIT_HASH
- global LINUX_X64, SLOW_OPTIMIZE, USE_OMP, PYTHON_INSTALL_ENABLED
+ global LINUX_X64, SLOW_OPTIMIZE, USE_OMP
try:
options, remainder = getopt.gnu_getopt(sys.argv[1:],
'b:df:sxhmcvtnp:gj',
@@ -711,26 +711,7 @@ def parse_options():
else:
print("ERROR: Invalid command line option '%s'" % opt)
display_help(1)
- # Handle the Python package directory
- if IS_WINDOWS:
- # Installing under Windows doesn't make sense as the install prefix is used
- # but that doesn't make sense under Windows
- PYTHON_INSTALL_ENABLED = False
- else:
- if not PYTHON_PACKAGE_DIR.startswith(PREFIX):
- print(("Warning: The detected Python package directory (%s)"
- " does not live under the installation prefix (%s)"
- ". This would lead to a broken Python installation."
- "Use --pypkgdir= to change the Python package directory") %
- (PYTHON_PACKAGE_DIR, PREFIX))
- if IS_OSX and PYTHON_PACKAGE_DIR.startswith('/Library/'):
- print("Using hack to install Python bindings, this might lead to a broken system")
- PYTHON_INSTALL_ENABLED = True
- else:
- print("Disabling install of Python bindings")
- PYTHON_INSTALL_ENABLED = False
- else:
- PYTHON_INSTALL_ENABLED = True
+
# Return a list containing a file names included using '#include' in
# the given C/C++ file named fname.
@@ -1036,6 +1017,11 @@ class Component:
def mk_unix_dist(self, build_path, dist_path):
return
+ # Used to print warnings or errors after mk_make.py is done, so that they
+ # are not quite as easy to miss.
+ def final_info(self):
+ pass
+
class LibComponent(Component):
def __init__(self, name, path, deps, includes2install):
Component.__init__(self, name, path, deps)
@@ -1062,8 +1048,8 @@ class LibComponent(Component):
out.write('\n')
out.write('%s: %s\n\n' % (self.name, libfile))
- def mk_install_dep(self, out):
- out.write('%s' % libfile)
+ def mk_install_deps(self, out):
+ return
def mk_install(self, out):
for include in self.includes2install:
@@ -1151,8 +1137,10 @@ class ExeComponent(Component):
def main_component(self):
return self.install
- def mk_install_dep(self, out):
- out.write('%s' % exefile)
+ def mk_install_deps(self, out):
+ if self.install:
+ exefile = '%s$(EXE_EXT)' % self.exe_name
+ out.write('%s' % exefile)
def mk_install(self, out):
if self.install:
@@ -1308,7 +1296,7 @@ class DLLComponent(Component):
def require_def_file(self):
return IS_WINDOWS and self.export_files
- def mk_install_dep(self, out):
+ def mk_install_deps(self, out):
out.write('%s$(SO_EXT)' % self.dll_name)
if self.static:
out.write(' %s$(LIB_EXT)' % self.dll_name)
@@ -1345,38 +1333,54 @@ class DLLComponent(Component):
class PythonInstallComponent(Component):
def __init__(self, name, libz3Component):
assert isinstance(libz3Component, DLLComponent)
+ global PYTHON_INSTALL_ENABLED
Component.__init__(self, name, None, [])
self.pythonPkgDir = None
self.in_prefix_install = True
self.libz3Component = libz3Component
- if not PYTHON_INSTALL_ENABLED:
- return
- if self.is_osx_hack():
- # Use full path that is outside of install prefix
- self.pythonPkgDir = PYTHON_PACKAGE_DIR
- self.in_prefix_install = False
- assert os.path.isabs(self.pythonPkgDir)
+ if IS_WINDOWS:
+ # Installing under Windows doesn't make sense as the install prefix is used
+ # but that doesn't make sense under Windows
+ # CMW: It makes perfectly good sense; the prefix is Python's sys.prefix,
+ # i.e., something along the lines of C:\Python\... At the moment we are not
+ # sure whether we would want to install libz3.dll into that directory though.
+ PYTHON_INSTALL_ENABLED = False
+ return
else:
- # Use path inside the prefix (should be the normal case)
+ PYTHON_INSTALL_ENABLED = True
+
+ if IS_WINDOWS or IS_OSX:
+ # Use full path that is possibly outside of install prefix
+ self.in_prefix_install = PYTHON_PACKAGE_DIR.startswith(PREFIX)
+ self.pythonPkgDir = strip_path_prefix(PYTHON_PACKAGE_DIR, PREFIX)
+ else:
+ # Use path inside the prefix (should be the normal case on Linux)
+ # CMW: Also normal on *BSD?
assert PYTHON_PACKAGE_DIR.startswith(PREFIX)
self.pythonPkgDir = strip_path_prefix(PYTHON_PACKAGE_DIR, PREFIX)
- assert not os.path.isabs(self.pythonPkgDir)
- assert self.in_prefix_install
+ self.in_prefix_install = True
- def is_osx_hack(self):
- return IS_OSX and not PYTHON_PACKAGE_DIR.startswith(PREFIX)
+ if self.in_prefix_install:
+ assert not os.path.isabs(self.pythonPkgDir)
+
+ def final_info(self):
+ if not PYTHON_PACKAGE_DIR.startswith(PREFIX):
+ print("Warning: The detected Python package directory (%s) is not "
+ "in the installation prefix (%s). This can lead to a broken "
+ "Python API installation. Use --pypkgdir= to change the "
+ "Python package directory." % (PYTHON_PACKAGE_DIR, PREFIX))
def main_component(self):
- return False
-
+ return False
+
def mk_install(self, out):
if not is_python_install_enabled():
return
MakeRuleCmd.make_install_directory(out, self.pythonPkgDir, in_prefix=self.in_prefix_install)
# Sym-link or copy libz3 into python package directory
- if IS_WINDOWS or self.is_osx_hack():
+ if IS_WINDOWS or IS_OSX:
MakeRuleCmd.install_files(out,
self.libz3Component.dll_file(),
os.path.join(self.pythonPkgDir,
@@ -1568,7 +1572,6 @@ class DotNetDLLComponent(Component):
def mk_win_dist(self, build_path, dist_path):
if is_dotnet_enabled():
- # Assuming all .NET dlls should be in the distribution
mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name),
'%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
@@ -1578,11 +1581,13 @@ class DotNetDLLComponent(Component):
shutil.copy('%s.pdb' % os.path.join(build_path, self.dll_name),
'%s.pdb' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
-
-
def mk_unix_dist(self, build_path, dist_path):
- # Do nothing
- return
+ if is_dotnet_enabled():
+ mk_dir(os.path.join(dist_path, INSTALL_BIN_DIR))
+ shutil.copy('%s.dll' % os.path.join(build_path, self.dll_name),
+ '%s.dll' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
+ shutil.copy('%s.xml' % os.path.join(build_path, self.dll_name),
+ '%s.xml' % os.path.join(dist_path, INSTALL_BIN_DIR, self.dll_name))
def mk_install_deps(self, out):
if not is_dotnet_enabled():
@@ -1724,7 +1729,7 @@ class JavaDLLComponent(Component):
MakeRuleCmd.remove_installed_files(out, os.path.join(INSTALL_LIB_DIR, jarfile))
class MLComponent(Component):
-
+
def __init__(self, name, lib_name, path, deps):
Component.__init__(self, name, path, deps)
if lib_name is None:
@@ -1742,14 +1747,14 @@ class MLComponent(Component):
out.write('CXXFLAGS_OCAML=$(CXXFLAGS:/GL=)\n') # remove /GL; the ocaml tools don't like it.
if IS_WINDOWS:
- prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\')
+ prefix_lib = '-L' + os.path.abspath(BUILD_DIR).replace('\\', '\\\\')
else:
prefix_lib = '-L' + PREFIX + '/lib'
substitutions = { 'LEXTRA': prefix_lib,
'VERSION': "{}.{}.{}.{}".format(VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION) }
-
+
configure_file(os.path.join(self.src_dir, 'META.in'),
- os.path.join(BUILD_DIR, self.sub_dir, 'META'),
+ os.path.join(BUILD_DIR, self.sub_dir, 'META'),
substitutions)
mlis = ''
@@ -1761,7 +1766,7 @@ class MLComponent(Component):
z3dllso = get_component(Z3_DLL_COMPONENT).dll_name + '$(SO_EXT)'
out.write('%s: %s %s\n' % (stubso, stubsc, z3dllso))
out.write('\t%s -ccopt "$(CXXFLAGS_OCAML) -I %s -I %s -I %s $(CXX_OUT_FLAG)%s" -c %s\n' %
- (OCAMLC, OCAML_LIB, api_src, src_dir, stubso, stubsc))
+ (OCAMLC, OCAML_LIB, api_src, src_dir, stubso, stubsc))
cmis = ''
for m in self.modules:
@@ -1771,7 +1776,7 @@ class MLComponent(Component):
out.write('\t%s -I %s -o %s -c %s\n' % (OCAMLC, self.sub_dir, ft, ff))
cmis = cmis + ' ' + ft
- cmos = ''
+ cmos = ''
for m in self.modules:
ff = os.path.join(src_dir, m + '.ml')
ft = os.path.join(self.sub_dir, m + '.cmo')
@@ -1797,7 +1802,7 @@ class MLComponent(Component):
out.write('\tocamlmklib -o %s -I %s %s %s -L. -lz3\n' % (z3mls, self.sub_dir, stubso, cmxs))
out.write('%s.cmxs: %s.cmxa\n' % (z3mls, z3mls))
out.write('\t%s -shared -o %s.cmxs -I %s %s.cmxa\n' % (OCAMLOPT, z3mls, self.sub_dir, z3mls))
-
+
out.write('\n')
out.write('ml: %s.cma %s.cmxa %s.cmxs\n' % (z3mls, z3mls, z3mls))
out.write('\n')
@@ -1811,7 +1816,7 @@ class MLComponent(Component):
out.write('ocamlfind_uninstall:\n')
self.mk_uninstall(out)
out.write('\n')
-
+
def mk_install_deps(self, out):
if is_ml_enabled() and OCAMLFIND != '':
out.write(get_component(Z3_DLL_COMPONENT).dll_name + '$(SO_EXT) ')
@@ -1880,8 +1885,8 @@ class CppExampleComponent(ExampleComponent):
out.write(' -I%s' % get_component(API_COMPONENT).to_src_dir)
out.write(' -I%s' % get_component(CPP_COMPONENT).to_src_dir)
out.write(' %s' % os.path.join(self.to_ex_dir, cppfile))
- out.write('\n')
-
+ out.write('\n')
+
exefile = '%s$(EXE_EXT)' % self.name
out.write('%s: %s %s\n' % (exefile, dll, objfiles))
out.write('\t$(LINK) $(LINK_OUT_FLAG)%s $(LINK_FLAGS) %s ' % (exefile, objfiles))
@@ -2336,12 +2341,12 @@ def mk_makefile():
out.write(' %s' % c.name)
out.write('\n\t@echo Z3 was successfully built.\n')
out.write("\t@echo \"Z3Py scripts can already be executed in the \'%s\' directory.\"\n" % BUILD_DIR)
- out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be also executed if \'%s\' directory is added to the PYTHONPATH environment variable.\"\n" % BUILD_DIR)
+ out.write("\t@echo \"Z3Py scripts stored in arbitrary directories can be executed if the \'%s\' directory is added to the PYTHONPATH environment variable.\"\n" % BUILD_DIR)
if not IS_WINDOWS:
out.write("\t@echo Use the following command to install Z3 at prefix $(PREFIX).\n")
out.write('\t@echo " sudo make install"\n\n')
- out.write("\t@echo If you are doing a staged install you can use DESTDIR.\n")
- out.write('\t@echo " make DESTDIR=/some/temp/directory install"\n')
+ # out.write("\t@echo If you are doing a staged install you can use DESTDIR.\n")
+ # out.write('\t@echo " make DESTDIR=/some/temp/directory install"\n')
# Generate :examples rule
out.write('examples:')
for c in get_components():
@@ -2355,6 +2360,8 @@ def mk_makefile():
if not IS_WINDOWS:
mk_install(out)
mk_uninstall(out)
+ for c in get_components():
+ c.final_info()
out.close()
# Finalize
if VERBOSE:
@@ -3298,15 +3305,18 @@ def mk_z3consts_ml(api_files):
def mk_gui_str(id):
return '4D2F40D8-E5F9-473B-B548-%012d' % id
-def mk_vs_proj(name, components):
- if not VS_PROJ:
- return
- proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name)
- modes=['Debug', 'Release']
- PLATFORMS=['Win32']
- f = open(proj_name, 'w')
- f.write('\n')
- f.write('\n')
+def get_platform_toolset_str():
+ default = 'v110';
+ vstr = check_output(['msbuild', '/ver'])
+ lines = vstr.split('\n')
+ lline = lines[-1]
+ tokens = lline.split('.')
+ if len(tokens) < 2:
+ return default
+ else:
+ return 'v' + tokens[0] + tokens[1]
+
+def mk_vs_proj_property_groups(f, name, target_ext, type):
f.write(' \n')
f.write(' \n')
f.write(' Debug\n')
@@ -3317,35 +3327,46 @@ def mk_vs_proj(name, components):
f.write(' Win32\n')
f.write(' \n')
f.write(' \n')
- f.write(' \n')
+ f.write(' \n')
f.write(' {%s}\n' % mk_gui_str(0))
f.write(' %s\n' % name)
f.write(' Win32Proj\n')
+ f.write(' %s\n' % get_platform_toolset_str())
f.write(' \n')
f.write(' \n')
f.write(' \n')
- f.write(' Application\n')
+ f.write(' %s\n' % type)
f.write(' Unicode\n')
f.write(' false\n')
f.write(' \n')
f.write(' \n')
- f.write(' \n')
- f.write(' \n')
+ f.write(' \n')
f.write(' \n')
f.write(' \n')
f.write(' \n')
f.write(' \n')
- f.write(' $(SolutionDir)$(Configuration)\\n')
+ f.write(' $(SolutionDir)\$(ProjectName)\$(Configuration)\\n')
f.write(' %s\n' % name)
- f.write(' .exe\n')
- f.write(' $(SolutionDir)$(Configuration)\\n')
+ f.write(' .%s\n' % target_ext)
+ f.write(' $(SolutionDir)\$(ProjectName)\$(Configuration)\\n')
f.write(' %s\n' % name)
- f.write(' .exe\n')
+ f.write(' .%s\n' % target_ext)
f.write(' \n')
- f.write(' \n')
+ f.write(' \n')
+ f.write(' $(ProjectName)\$(Configuration)\\n')
+ f.write(' \n')
+ f.write(' \n')
+ f.write(' $(ProjectName)\$(Configuration)\\n')
+ f.write(' \n')
+
+
+def mk_vs_proj_cl_compile(f, name, components, debug):
f.write(' \n')
f.write(' Disabled\n')
- f.write(' WIN32;_DEBUG;Z3DEBUG;_TRACE;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)\n')
+ if debug:
+ f.write(' WIN32;_DEBUG;Z3DEBUG;_TRACE;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)\n')
+ else:
+ f.write(' WIN32;_NDEBUG;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)\n')
if VS_PAR:
f.write(' false\n')
f.write(' true\n')
@@ -3353,8 +3374,14 @@ def mk_vs_proj(name, components):
f.write(' true\n')
f.write(' EnableFastChecks\n')
f.write(' Level3\n')
- f.write(' MultiThreadedDebugDLL\n')
- f.write(' true\n')
+ if debug:
+ f.write(' MultiThreadedDebugDLL\n')
+ else:
+ f.write(' MultiThreadedDLL\n')
+ if USE_OMP:
+ f.write(' true\n')
+ else:
+ f.write(' false\n')
f.write(' ProgramDatabase\n')
f.write(' ')
deps = find_all_deps(name, components)
@@ -3367,63 +3394,89 @@ def mk_vs_proj(name, components):
f.write(get_component(dep).to_src_dir)
f.write('\n')
f.write(' \n')
- f.write(' \n')
- f.write(' $(OutDir)%s.exe\n' % name)
- f.write(' true\n')
- f.write(' Console\n')
- f.write(' 8388608\n')
- f.write(' false\n')
- f.write(' \n')
- f.write(' \n')
- f.write(' MachineX86\n')
- f.write(' %(AdditionalLibraryDirectories)\n')
- f.write('psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)\n')
- f.write(' \n')
- f.write(' \n')
- f.write(' \n')
- f.write(' \n')
- f.write(' Disabled\n')
- f.write(' WIN32;_NDEBUG;_MP_INTERNAL;_WINDOWS;%(PreprocessorDefinitions)\n')
- if VS_PAR:
- f.write(' false\n')
- f.write(' true\n')
- else:
- f.write(' true\n')
- f.write(' EnableFastChecks\n')
- f.write(' Level3\n')
- f.write(' MultiThreadedDLL\n')
- f.write(' true\n')
- f.write(' ProgramDatabase\n')
- f.write(' ')
- deps = find_all_deps(name, components)
- first = True
- for dep in deps:
- if first:
- first = False
- else:
- f.write(';')
- f.write(get_component(dep).to_src_dir)
- f.write('\n')
- f.write(' \n')
- f.write(' \n')
- f.write(' $(OutDir)%s.exe\n' % name)
- f.write(' true\n')
- f.write(' Console\n')
- f.write(' 8388608\n')
- f.write(' false\n')
- f.write(' \n')
- f.write(' \n')
- f.write(' MachineX86\n')
- f.write(' %(AdditionalLibraryDirectories)\n')
- f.write('psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)\n')
- f.write(' \n')
- f.write(' \n')
+
+def mk_vs_proj_dep_groups(f, name, components):
f.write(' \n')
+ deps = find_all_deps(name, components)
for dep in deps:
dep = get_component(dep)
for cpp in filter(lambda f: f.endswith('.cpp'), os.listdir(dep.src_dir)):
f.write(' \n' % os.path.join(dep.to_src_dir, cpp))
f.write(' \n')
+
+def mk_vs_proj_link_exe(f, name, debug):
+ f.write(' \n')
+ f.write(' $(OutDir)%s.exe\n' % name)
+ f.write(' true\n')
+ f.write(' Console\n')
+ f.write(' 8388608\n')
+ f.write(' false\n')
+ f.write(' \n')
+ f.write(' MachineX86\n')
+ f.write(' %(AdditionalLibraryDirectories)\n')
+ f.write(' psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)\n')
+ f.write(' \n')
+
+def mk_vs_proj(name, components):
+ if not VS_PROJ:
+ return
+ proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name)
+ modes=['Debug', 'Release']
+ PLATFORMS=['Win32']
+ f = open(proj_name, 'w')
+ f.write('\n')
+ f.write('\n')
+ mk_vs_proj_property_groups(f, name, 'exe', 'Application')
+ f.write(' \n')
+ mk_vs_proj_cl_compile(f, name, components, debug=True)
+ mk_vs_proj_link_exe(f, name, debug=True)
+ f.write(' \n')
+ f.write(' \n')
+ mk_vs_proj_cl_compile(f, name, components, debug=False)
+ mk_vs_proj_link_exe(f, name, debug=False)
+ f.write(' \n')
+ mk_vs_proj_dep_groups(f, name, components)
+ f.write(' \n')
+ f.write(' \n')
+ f.write(' \n')
+ f.write('\n')
+ f.close()
+ if is_verbose():
+ print("Generated '%s'" % proj_name)
+
+def mk_vs_proj_link_dll(f, name, debug):
+ f.write(' \n')
+ f.write(' $(OutDir)%s.dll\n' % name)
+ f.write(' true\n')
+ f.write(' Console\n')
+ f.write(' 8388608\n')
+ f.write(' false\n')
+ f.write(' \n')
+ f.write(' MachineX86\n')
+ f.write(' %(AdditionalLibraryDirectories)\n')
+ f.write(' psapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)\n')
+ f.write(' %s' % os.path.join(get_component('api_dll').to_src_dir, 'api_dll.def'))
+ f.write(' \n')
+
+def mk_vs_proj_dll(name, components):
+ if not VS_PROJ:
+ return
+ proj_name = '%s.vcxproj' % os.path.join(BUILD_DIR, name)
+ modes=['Debug', 'Release']
+ PLATFORMS=['Win32']
+ f = open(proj_name, 'w')
+ f.write('\n')
+ f.write('\n')
+ mk_vs_proj_property_groups(f, name, 'dll', 'DynamicLibrary')
+ f.write(' \n')
+ mk_vs_proj_cl_compile(f, name, components, debug=True)
+ mk_vs_proj_link_dll(f, name, debug=True)
+ f.write(' \n')
+ f.write(' \n')
+ mk_vs_proj_cl_compile(f, name, components, debug=False)
+ mk_vs_proj_link_dll(f, name, debug=False)
+ f.write(' \n')
+ mk_vs_proj_dep_groups(f, name, components)
f.write(' \n')
f.write(' \n')
f.write(' \n')
@@ -3470,22 +3523,17 @@ class MakeRuleCmd(object):
@classmethod
def _install_root(cls, path, in_prefix, out, is_install=True):
- if in_prefix:
- assert not os.path.isabs(path)
- install_root = cls.install_root()
- else:
- # This hack only exists for the Python bindings on OSX
- # which are sometimes not installed inside the prefix.
- # In all other cases installing outside the prefix is
- # misleading and dangerous!
- assert IS_OSX
- assert os.path.isabs(path)
+ if not in_prefix:
+ # The Python bindings on OSX are sometimes not installed inside the prefix.
install_root = "$(DESTDIR)"
action_string = 'install' if is_install else 'uninstall'
cls.write_cmd(out, 'echo "WARNING: {}ing files/directories ({}) that are not in the install prefix ($(PREFIX))."'.format(
- action_string, path))
- print("WARNING: Generating makefile rule that {}s {} '{}' which is outside the installation prefix '{}'.".format(
- action_string, 'to' if is_install else 'from', path, PREFIX))
+ action_string, path))
+ #print("WARNING: Generating makefile rule that {}s {} '{}' which is outside the installation prefix '{}'.".format(
+ # action_string, 'to' if is_install else 'from', path, PREFIX))
+ else:
+ assert not os.path.isabs(path)
+ install_root = cls.install_root()
return install_root
@classmethod
@@ -3605,14 +3653,15 @@ class MakeRuleCmd(object):
out.write("\t@{}\n".format(line))
def strip_path_prefix(path, prefix):
- assert path.startswith(prefix)
- stripped_path = path[len(prefix):]
- stripped_path.replace('//','/')
- if stripped_path[0] == '/':
- stripped_path = stripped_path[1:]
-
- assert not os.path.isabs(stripped_path)
- return stripped_path
+ if path.startswith(prefix):
+ stripped_path = path[len(prefix):]
+ stripped_path.replace('//','/')
+ if stripped_path[0] == '/':
+ stripped_path = stripped_path[1:]
+ assert not os.path.isabs(stripped_path)
+ return stripped_path
+ else:
+ return path
def configure_file(template_file_path, output_file_path, substitutions):
"""
diff --git a/scripts/update_api.py b/scripts/update_api.py
index febbf3eb2..fc0f1c939 100644
--- a/scripts/update_api.py
+++ b/scripts/update_api.py
@@ -1079,7 +1079,7 @@ def def_API(name, result, params):
def mk_bindings():
exe_c.write("void register_z3_replayer_cmds(z3_replayer & in) {\n")
for key, val in API2Id.items():
- exe_c.write(" in.register_cmd(%s, exec_%s);\n" % (key, val))
+ exe_c.write(" in.register_cmd(%s, exec_%s, \"%s\");\n" % (key, val, val))
exe_c.write("}\n")
def ml_method_name(name):
diff --git a/scripts/update_header_guards.py b/scripts/update_header_guards.py
index 1010f1899..815196ef3 100644
--- a/scripts/update_header_guards.py
+++ b/scripts/update_header_guards.py
@@ -17,55 +17,55 @@ def fix_hdr(file):
line = ins.readline()
found = False
while line:
- m = doubleu.search(line)
- if m:
- ous.write("#")
- ous.write(m.group(1))
- ous.write(" ")
- ous.write(m.group(2))
- ous.write("_H_\n")
- line = ins.readline()
- found = True
- continue
- m = ifndef.search(line)
- if m:
- print(m.group(1))
- ous.write("#ifndef ")
- ous.write(m.group(1))
- ous.write("_H_\n")
- line = ins.readline()
- found = True
- continue
- m = defn.search(line)
- if m:
- ous.write("#define ")
- ous.write(m.group(1))
- ous.write("_H_\n")
- line = ins.readline()
- found = True
- continue
- m = endif.search(line)
- if m:
- ous.write("#endif /* ")
- ous.write(m.group(1))
- ous.write("_H_ */\n")
- line = ins.readline()
- found = True
- continue
- ous.write(line)
- line = ins.readline()
+ m = doubleu.search(line)
+ if m:
+ ous.write("#")
+ ous.write(m.group(1))
+ ous.write(" ")
+ ous.write(m.group(2))
+ ous.write("_H_\n")
+ line = ins.readline()
+ found = True
+ continue
+ m = ifndef.search(line)
+ if m:
+ print(m.group(1))
+ ous.write("#ifndef ")
+ ous.write(m.group(1))
+ ous.write("_H_\n")
+ line = ins.readline()
+ found = True
+ continue
+ m = defn.search(line)
+ if m:
+ ous.write("#define ")
+ ous.write(m.group(1))
+ ous.write("_H_\n")
+ line = ins.readline()
+ found = True
+ continue
+ m = endif.search(line)
+ if m:
+ ous.write("#endif /* ")
+ ous.write(m.group(1))
+ ous.write("_H_ */\n")
+ line = ins.readline()
+ found = True
+ continue
+ ous.write(line)
+ line = ins.readline()
ins.close()
ous.close()
if found:
- os.system("move %s %s" % (tmp, file))
+ os.system("move %s %s" % (tmp, file))
else:
- os.system("del %s" % tmp)
-
+ os.system("del %s" % tmp)
+
def fixup(dir):
for root, dirs, files in os.walk(dir):
- for f in files:
- if f.endswith('.h'):
- path = "%s\\%s" % (root, f)
- fix_hdr(path)
+ for f in files:
+ if f.endswith('.h'):
+ path = "%s\\%s" % (root, f)
+ fix_hdr(path)
fixup('src')
diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp
index 9f0ddbaa8..db10c8bb3 100644
--- a/src/api/api_ast.cpp
+++ b/src/api/api_ast.cpp
@@ -641,6 +641,12 @@ extern "C" {
else if (fid == mk_c(c)->get_fpa_fid() && k == ROUNDING_MODE_SORT) {
return Z3_ROUNDING_MODE_SORT;
}
+ else if (fid == mk_c(c)->get_seq_fid() && k == SEQ_SORT) {
+ return Z3_SEQ_SORT;
+ }
+ else if (fid == mk_c(c)->get_seq_fid() && k == RE_SORT) {
+ return Z3_RE_SORT;
+ }
else {
return Z3_UNKNOWN_SORT;
}
@@ -776,6 +782,8 @@ extern "C" {
SET_ERROR_CODE(Z3_SORT_ERROR);
RETURN_Z3(of_expr(0));
}
+ SASSERT(from[i]->get_ref_count() > 0);
+ SASSERT(to[i]->get_ref_count() > 0);
}
expr_safe_replace subst(m);
for (unsigned i = 0; i < num_exprs; i++) {
@@ -1106,6 +1114,32 @@ extern "C" {
}
}
+ if (mk_c(c)->get_seq_fid() == _d->get_family_id()) {
+ switch (_d->get_decl_kind()) {
+ case Z3_OP_SEQ_UNIT: return Z3_OP_SEQ_UNIT;
+ case Z3_OP_SEQ_EMPTY: return Z3_OP_SEQ_EMPTY;
+ case Z3_OP_SEQ_CONCAT: return Z3_OP_SEQ_CONCAT;
+ case Z3_OP_SEQ_PREFIX: return Z3_OP_SEQ_PREFIX;
+ case Z3_OP_SEQ_SUFFIX: return Z3_OP_SEQ_SUFFIX;
+ case Z3_OP_SEQ_CONTAINS: return Z3_OP_SEQ_CONTAINS;
+ case Z3_OP_SEQ_EXTRACT: return Z3_OP_SEQ_EXTRACT;
+ case Z3_OP_SEQ_REPLACE: return Z3_OP_SEQ_REPLACE;
+ case Z3_OP_SEQ_AT: return Z3_OP_SEQ_AT;
+ case Z3_OP_SEQ_LENGTH: return Z3_OP_SEQ_LENGTH;
+ case Z3_OP_SEQ_INDEX: return Z3_OP_SEQ_INDEX;
+ case Z3_OP_SEQ_TO_RE: return Z3_OP_SEQ_TO_RE;
+ case Z3_OP_SEQ_IN_RE: return Z3_OP_SEQ_IN_RE;
+
+ case Z3_OP_RE_PLUS: return Z3_OP_RE_PLUS;
+ case Z3_OP_RE_STAR: return Z3_OP_RE_STAR;
+ case Z3_OP_RE_OPTION: return Z3_OP_RE_OPTION;
+ case Z3_OP_RE_CONCAT: return Z3_OP_RE_CONCAT;
+ case Z3_OP_RE_UNION: return Z3_OP_RE_UNION;
+ default:
+ return Z3_OP_UNINTERPRETED;
+ }
+ }
+
if (mk_c(c)->get_fpa_fid() == _d->get_family_id()) {
switch (_d->get_decl_kind()) {
case OP_FPA_RM_NEAREST_TIES_TO_EVEN: return Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN;
diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp
index 9d0abe3a7..75782a28d 100644
--- a/src/api/api_context.cpp
+++ b/src/api/api_context.cpp
@@ -73,6 +73,7 @@ namespace api {
m_datalog_util(m()),
m_fpa_util(m()),
m_dtutil(m()),
+ m_sutil(m()),
m_last_result(m()),
m_ast_trail(m()),
m_replay_stack(),
@@ -97,6 +98,7 @@ namespace api {
m_dt_fid = m().mk_family_id("datatype");
m_datalog_fid = m().mk_family_id("datalog_relation");
m_fpa_fid = m().mk_family_id("fpa");
+ m_seq_fid = m().mk_family_id("seq");
m_dt_plugin = static_cast(m().get_plugin(m_dt_fid));
if (!m_user_ref_count) {
diff --git a/src/api/api_context.h b/src/api/api_context.h
index 40b59d1b2..23c8d3fd2 100644
--- a/src/api/api_context.h
+++ b/src/api/api_context.h
@@ -25,6 +25,7 @@ Revision History:
#include"api_util.h"
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
+#include"seq_decl_plugin.h"
#include"datatype_decl_plugin.h"
#include"dl_decl_plugin.h"
#include"fpa_decl_plugin.h"
@@ -58,6 +59,7 @@ namespace api {
datalog::dl_decl_util m_datalog_util;
fpa_util m_fpa_util;
datatype_util m_dtutil;
+ seq_util m_sutil;
// Support for old solver API
smt_params m_fparams;
@@ -78,6 +80,7 @@ namespace api {
family_id m_datalog_fid;
family_id m_pb_fid;
family_id m_fpa_fid;
+ family_id m_seq_fid;
datatype_decl_plugin * m_dt_plugin;
std::string m_string_buffer; // temporary buffer used to cache strings sent to the "external" world.
@@ -121,6 +124,7 @@ namespace api {
datalog::dl_decl_util & datalog_util() { return m_datalog_util; }
fpa_util & fpautil() { return m_fpa_util; }
datatype_util& dtutil() { return m_dtutil; }
+ seq_util& sutil() { return m_sutil; }
family_id get_basic_fid() const { return m_basic_fid; }
family_id get_array_fid() const { return m_array_fid; }
family_id get_arith_fid() const { return m_arith_fid; }
@@ -129,6 +133,7 @@ namespace api {
family_id get_datalog_fid() const { return m_datalog_fid; }
family_id get_pb_fid() const { return m_pb_fid; }
family_id get_fpa_fid() const { return m_fpa_fid; }
+ family_id get_seq_fid() const { return m_seq_fid; }
datatype_decl_plugin * get_dt_plugin() const { return m_dt_plugin; }
Z3_error_code get_error_code() const { return m_error_code; }
diff --git a/src/api/api_fpa.cpp b/src/api/api_fpa.cpp
index daef12d20..90b818b4b 100644
--- a/src/api/api_fpa.cpp
+++ b/src/api/api_fpa.cpp
@@ -268,14 +268,14 @@ extern "C" {
Z3_ast Z3_API Z3_mk_fpa_fp(Z3_context c, Z3_ast sgn, Z3_ast exp, Z3_ast sig) {
Z3_TRY;
- LOG_Z3_mk_fpa_fp(c, sgn, sig, exp);
+ LOG_Z3_mk_fpa_fp(c, sgn, exp, sig);
RESET_ERROR_CODE();
if (!is_bv(c, sgn) || !is_bv(c, exp) || !is_bv(c, sig)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
api::context * ctx = mk_c(c);
- expr * a = ctx->fpautil().mk_fp(to_expr(sgn), to_expr(sig), to_expr(exp));
+ expr * a = ctx->fpautil().mk_fp(to_expr(sgn), to_expr(exp), to_expr(sig));
ctx->save_ast_trail(a);
RETURN_Z3(of_expr(a));
Z3_CATCH_RETURN(0);
@@ -351,7 +351,7 @@ extern "C" {
ctx->fpautil().fm().set(tmp,
ctx->fpautil().get_ebits(to_sort(ty)),
ctx->fpautil().get_sbits(to_sort(ty)),
- sgn != 0, sig, exp);
+ sgn != 0, exp, sig);
expr * a = ctx->fpautil().mk_value(tmp);
ctx->save_ast_trail(a);
RETURN_Z3(of_expr(a));
@@ -371,7 +371,7 @@ extern "C" {
ctx->fpautil().fm().set(tmp,
ctx->fpautil().get_ebits(to_sort(ty)),
ctx->fpautil().get_sbits(to_sort(ty)),
- sgn != 0, sig, exp);
+ sgn != 0, exp, sig);
expr * a = ctx->fpautil().mk_value(tmp);
ctx->save_ast_trail(a);
RETURN_Z3(of_expr(a));
@@ -931,15 +931,23 @@ extern "C" {
mpf_manager & mpfm = mk_c(c)->fpautil().fm();
unsynch_mpz_manager & mpzm = mpfm.mpz_manager();
unsynch_mpq_manager & mpqm = mpfm.mpq_manager();
- fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid());
- scoped_mpf val(mpfm);
- if (!plugin->is_numeral(to_expr(t), val)) {
+ family_id fid = mk_c(c)->get_fpa_fid();
+ fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid);
+ SASSERT(plugin != 0);
+ expr * e = to_expr(t);
+ if (!is_app(e) ||
+ is_app_of(e, fid, OP_FPA_NAN) ||
+ is_app_of(e, fid, OP_FPA_PLUS_INF) ||
+ is_app_of(e, fid, OP_FPA_MINUS_INF)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return "";
}
- else if (!mpfm.is_regular(val)) {
+ scoped_mpf val(mpfm);
+ app * a = to_app(e);
+ bool r = plugin->is_numeral(e, val);
+ if (!r || !mpfm.is_regular(val)) {
SET_ERROR_CODE(Z3_INVALID_ARG)
- return "";
+ return "";
}
unsigned sbits = val.get().get_sbits();
scoped_mpq q(mpqm);
@@ -960,16 +968,25 @@ extern "C" {
ast_manager & m = mk_c(c)->m();
mpf_manager & mpfm = mk_c(c)->fpautil().fm();
unsynch_mpz_manager & mpzm = mpfm.mpz_manager();
- fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid());
- scoped_mpf val(mpfm);
- bool r = plugin->is_numeral(to_expr(t), val);
- if (!r) {
+ family_id fid = mk_c(c)->get_fpa_fid();
+ fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(fid);
+ SASSERT(plugin != 0);
+ expr * e = to_expr(t);
+ if (!is_app(e) ||
+ is_app_of(e, fid, OP_FPA_NAN) ||
+ is_app_of(e, fid, OP_FPA_PLUS_INF) ||
+ is_app_of(e, fid, OP_FPA_MINUS_INF)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
+ *n = 0;
return 0;
}
+ scoped_mpf val(mpfm);
+ app * a = to_app(e);
+ bool r = plugin->is_numeral(e, val);
const mpz & z = mpfm.sig(val);
- if (!mpzm.is_uint64(z)) {
+ if (!r || mpfm.is_regular(val)|| !mpzm.is_uint64(z)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
+ *n = 0;
return 0;
}
*n = mpzm.get_uint64(z);
@@ -983,16 +1000,23 @@ extern "C" {
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
mpf_manager & mpfm = mk_c(c)->fpautil().fm();
+ family_id fid = mk_c(c)->get_fpa_fid();
fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid());
- scoped_mpf val(mpfm);
- bool r = plugin->is_numeral(to_expr(t), val);
- if (!r) {
+ SASSERT(plugin != 0);
+ expr * e = to_expr(t);
+ if (!is_app(e) ||
+ is_app_of(e, fid, OP_FPA_NAN) ||
+ is_app_of(e, fid, OP_FPA_PLUS_INF) ||
+ is_app_of(e, fid, OP_FPA_MINUS_INF)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return "";
}
- else if (!mpfm.is_normal(val) && !mpfm.is_denormal(val)) {
- SET_ERROR_CODE(Z3_INVALID_ARG)
- return "";
+ scoped_mpf val(mpfm);
+ app * a = to_app(e);
+ bool r = plugin->is_numeral(e, val);
+ if (!r || !mpfm.is_regular(val)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return "";
}
mpf_exp_t exp = mpfm.exp_normalized(val);
std::stringstream ss;
@@ -1007,11 +1031,24 @@ extern "C" {
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
mpf_manager & mpfm = mk_c(c)->fpautil().fm();
+ family_id fid = mk_c(c)->get_fpa_fid();
fpa_decl_plugin * plugin = (fpa_decl_plugin*)m.get_plugin(mk_c(c)->get_fpa_fid());
- scoped_mpf val(mpfm);
- bool r = plugin->is_numeral(to_expr(t), val);
- if (!r) {
+ SASSERT(plugin != 0);
+ expr * e = to_expr(t);
+ if (!is_app(e) ||
+ is_app_of(e, fid, OP_FPA_NAN) ||
+ is_app_of(e, fid, OP_FPA_PLUS_INF) ||
+ is_app_of(e, fid, OP_FPA_MINUS_INF)) {
SET_ERROR_CODE(Z3_INVALID_ARG);
+ *n = 0;
+ return 0;
+ }
+ scoped_mpf val(mpfm);
+ app * a = to_app(e);
+ bool r = plugin->is_numeral(e, val);
+ if (!r || !mpfm.is_regular(val)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ *n = 0;
return 0;
}
*n = mpfm.exp(val);
@@ -1035,18 +1072,18 @@ extern "C" {
Z3_ast Z3_API Z3_mk_fpa_to_fp_int_real(Z3_context c, Z3_ast rm, Z3_ast exp, Z3_ast sig, Z3_sort s) {
Z3_TRY;
- LOG_Z3_mk_fpa_to_fp_int_real(c, rm, sig, exp, s);
+ LOG_Z3_mk_fpa_to_fp_int_real(c, rm, exp, sig, s);
RESET_ERROR_CODE();
api::context * ctx = mk_c(c);
fpa_util & fu = ctx->fpautil();
if (!fu.is_rm(to_expr(rm)) ||
- !ctx->autil().is_real(to_expr(sig)) ||
!ctx->autil().is_int(to_expr(exp)) ||
+ !ctx->autil().is_real(to_expr(sig)) ||
!fu.is_float(to_sort(s))) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
- expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(sig), to_expr(exp));
+ expr * a = fu.mk_to_fp(to_sort(s), to_expr(rm), to_expr(exp), to_expr(sig));
ctx->save_ast_trail(a);
RETURN_Z3(of_expr(a));
Z3_CATCH_RETURN(0);
diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp
index 370e639b9..63092b2cf 100644
--- a/src/api/api_model.cpp
+++ b/src/api/api_model.cpp
@@ -277,7 +277,9 @@ extern "C" {
RESET_ERROR_CODE();
CHECK_NON_NULL(f, 0);
expr * e = to_func_interp_ref(f)->get_else();
- mk_c(c)->save_ast_trail(e);
+ if (e) {
+ mk_c(c)->save_ast_trail(e);
+ }
RETURN_Z3(of_expr(e));
Z3_CATCH_RETURN(0);
}
diff --git a/src/api/api_seq.cpp b/src/api/api_seq.cpp
new file mode 100644
index 000000000..5704ffdb0
--- /dev/null
+++ b/src/api/api_seq.cpp
@@ -0,0 +1,151 @@
+/*++
+Copyright (c) 2016 Microsoft Corporation
+
+Module Name:
+
+ api_seq.cpp
+
+Abstract:
+
+ API for sequences and regular expressions.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2016-01-02.
+
+Revision History:
+
+--*/
+#include
+#include"z3.h"
+#include"api_log_macros.h"
+#include"api_context.h"
+#include"api_util.h"
+#include"ast_pp.h"
+
+extern "C" {
+
+ Z3_sort Z3_API Z3_mk_seq_sort(Z3_context c, Z3_sort domain) {
+ Z3_TRY;
+ LOG_Z3_mk_seq_sort(c, domain);
+ RESET_ERROR_CODE();
+ sort * ty = mk_c(c)->sutil().str.mk_seq(to_sort(domain));
+ mk_c(c)->save_ast_trail(ty);
+ RETURN_Z3(of_sort(ty));
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_sort Z3_API Z3_mk_re_sort(Z3_context c, Z3_sort domain) {
+ Z3_TRY;
+ LOG_Z3_mk_re_sort(c, domain);
+ RESET_ERROR_CODE();
+ sort * ty = mk_c(c)->sutil().re.mk_re(to_sort(domain));
+ mk_c(c)->save_ast_trail(ty);
+ RETURN_Z3(of_sort(ty));
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_ast Z3_API Z3_mk_string(Z3_context c, Z3_string str) {
+ Z3_TRY;
+ LOG_Z3_mk_string(c, str);
+ RESET_ERROR_CODE();
+ zstring s(str, zstring::ascii);
+ app* a = mk_c(c)->sutil().str.mk_string(s);
+ mk_c(c)->save_ast_trail(a);
+ RETURN_Z3(of_ast(a));
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_sort Z3_API Z3_mk_string_sort(Z3_context c) {
+ Z3_TRY;
+ LOG_Z3_mk_string_sort(c);
+ RESET_ERROR_CODE();
+ sort* ty = mk_c(c)->sutil().str.mk_string_sort();
+ mk_c(c)->save_ast_trail(ty);
+ RETURN_Z3(of_sort(ty));
+ Z3_CATCH_RETURN(0);
+ }
+
+ Z3_bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_is_seq_sort(c, s);
+ RESET_ERROR_CODE();
+ bool result = mk_c(c)->sutil().is_seq(to_sort(s));
+ return result?Z3_TRUE:Z3_FALSE;
+ Z3_CATCH_RETURN(Z3_FALSE);
+ }
+
+ Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_is_re_sort(c, s);
+ RESET_ERROR_CODE();
+ bool result = mk_c(c)->sutil().is_re(to_sort(s));
+ return result?Z3_TRUE:Z3_FALSE;
+ Z3_CATCH_RETURN(Z3_FALSE);
+ }
+
+ Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s) {
+ Z3_TRY;
+ LOG_Z3_is_string_sort(c, s);
+ RESET_ERROR_CODE();
+ bool result = mk_c(c)->sutil().is_string(to_sort(s));
+ return result?Z3_TRUE:Z3_FALSE;
+ Z3_CATCH_RETURN(Z3_FALSE);
+ }
+
+ Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s) {
+ Z3_TRY;
+ LOG_Z3_is_string(c, s);
+ RESET_ERROR_CODE();
+ bool result = mk_c(c)->sutil().str.is_string(to_expr(s));
+ return result?Z3_TRUE:Z3_FALSE;
+ Z3_CATCH_RETURN(Z3_FALSE);
+ }
+
+ Z3_string Z3_API Z3_get_string(Z3_context c, Z3_ast s) {
+ Z3_TRY;
+ LOG_Z3_get_string(c, s);
+ RESET_ERROR_CODE();
+ zstring str;
+ if (!mk_c(c)->sutil().str.is_string(to_expr(s), str)) {
+ SET_ERROR_CODE(Z3_INVALID_ARG);
+ return "";
+ }
+ std::string result = str.encode();
+ return mk_c(c)->mk_external_string(result);
+ Z3_CATCH_RETURN("");
+ }
+
+ Z3_ast Z3_API Z3_mk_seq_empty(Z3_context c, Z3_sort seq) {
+ Z3_TRY;
+ LOG_Z3_mk_seq_empty(c, seq);
+ RESET_ERROR_CODE();
+ app* a = mk_c(c)->sutil().str.mk_empty(to_sort(seq));
+ mk_c(c)->save_ast_trail(a);
+ RETURN_Z3(of_ast(a));
+ Z3_CATCH_RETURN(0);
+ }
+
+ MK_UNARY(Z3_mk_seq_unit, mk_c(c)->get_seq_fid(), OP_SEQ_UNIT, SKIP);
+ MK_NARY(Z3_mk_seq_concat, mk_c(c)->get_seq_fid(), OP_SEQ_CONCAT, SKIP);
+ MK_BINARY(Z3_mk_seq_prefix, mk_c(c)->get_seq_fid(), OP_SEQ_PREFIX, SKIP);
+ MK_BINARY(Z3_mk_seq_suffix, mk_c(c)->get_seq_fid(), OP_SEQ_SUFFIX, SKIP);
+ MK_BINARY(Z3_mk_seq_contains, mk_c(c)->get_seq_fid(), OP_SEQ_CONTAINS, SKIP);
+ MK_TERNARY(Z3_mk_seq_extract, mk_c(c)->get_seq_fid(), OP_SEQ_EXTRACT, SKIP);
+ MK_TERNARY(Z3_mk_seq_replace, mk_c(c)->get_seq_fid(), OP_SEQ_REPLACE, SKIP);
+ MK_BINARY(Z3_mk_seq_at, mk_c(c)->get_seq_fid(), OP_SEQ_AT, SKIP);
+ MK_UNARY(Z3_mk_seq_length, mk_c(c)->get_seq_fid(), OP_SEQ_LENGTH, SKIP);
+ MK_TERNARY(Z3_mk_seq_index, mk_c(c)->get_seq_fid(), OP_SEQ_INDEX, SKIP);
+ MK_UNARY(Z3_mk_seq_to_re, mk_c(c)->get_seq_fid(), OP_SEQ_TO_RE, SKIP);
+ MK_BINARY(Z3_mk_seq_in_re, mk_c(c)->get_seq_fid(), OP_SEQ_IN_RE, SKIP);
+
+
+ MK_UNARY(Z3_mk_re_plus, mk_c(c)->get_seq_fid(), OP_RE_PLUS, SKIP);
+ MK_UNARY(Z3_mk_re_star, mk_c(c)->get_seq_fid(), OP_RE_STAR, SKIP);
+ MK_UNARY(Z3_mk_re_option, mk_c(c)->get_seq_fid(), OP_RE_OPTION, SKIP);
+ MK_NARY(Z3_mk_re_union, mk_c(c)->get_seq_fid(), OP_RE_UNION, SKIP);
+ MK_NARY(Z3_mk_re_concat, mk_c(c)->get_seq_fid(), OP_RE_CONCAT, SKIP);
+
+
+
+};
diff --git a/src/api/api_util.h b/src/api/api_util.h
index 9befd8849..3b7baeac0 100644
--- a/src/api/api_util.h
+++ b/src/api/api_util.h
@@ -135,6 +135,23 @@ Z3_ast Z3_API NAME(Z3_context c, Z3_ast n1, Z3_ast n2) { \
MK_BINARY_BODY(NAME, FID, OP, EXTRA_CODE); \
}
+#define MK_TERNARY_BODY(NAME, FID, OP, EXTRA_CODE) \
+ Z3_TRY; \
+ RESET_ERROR_CODE(); \
+ EXTRA_CODE; \
+ expr * args[3] = { to_expr(n1), to_expr(n2), to_expr(n3) }; \
+ ast* a = mk_c(c)->m().mk_app(FID, OP, 0, 0, 3, args); \
+ mk_c(c)->save_ast_trail(a); \
+ check_sorts(c, a); \
+ RETURN_Z3(of_ast(a)); \
+ Z3_CATCH_RETURN(0);
+
+#define MK_TERNARY(NAME, FID, OP, EXTRA_CODE) \
+ Z3_ast Z3_API NAME(Z3_context c, Z3_ast n1, Z3_ast n2, Z3_ast n3) { \
+ LOG_ ## NAME(c, n1, n2, n3); \
+ MK_TERNARY_BODY(NAME, FID, OP, EXTRA_CODE); \
+}
+
#define MK_NARY(NAME, FID, OP, EXTRA_CODE) \
Z3_ast Z3_API NAME(Z3_context c, unsigned num_args, Z3_ast const* args) { \
Z3_TRY; \
diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h
index 1635ea7bb..b353499ad 100644
--- a/src/api/c++/z3++.h
+++ b/src/api/c++/z3++.h
@@ -205,6 +205,18 @@ namespace z3 {
\brief Return the Bit-vector sort of size \c sz. That is, the sort for bit-vectors of size \c sz.
*/
sort bv_sort(unsigned sz);
+ /**
+ \brief Return the sort for ASCII strings.
+ */
+ sort string_sort();
+ /**
+ \brief Return a sequence sort over base sort \c s.
+ */
+ sort seq_sort(sort& s);
+ /**
+ \brief Return a regular expression sort over sequences \c seq_sort.
+ */
+ sort re_sort(sort& seq_sort);
/**
\brief Return an array sort for arrays from \c d to \c r.
@@ -261,6 +273,9 @@ namespace z3 {
expr bv_val(__uint64 n, unsigned sz);
expr bv_val(char const * n, unsigned sz);
+ expr string_val(char const* s);
+ expr string_val(std::string const& s);
+
expr num_val(int n, sort const & s);
/**
@@ -425,6 +440,14 @@ namespace z3 {
\brief Return true if this sort is a Relation sort.
*/
bool is_relation() const { return sort_kind() == Z3_RELATION_SORT; }
+ /**
+ \brief Return true if this sort is a Sequence sort.
+ */
+ bool is_seq() const { return sort_kind() == Z3_SEQ_SORT; }
+ /**
+ \brief Return true if this sort is a regular expression sort.
+ */
+ bool is_re() const { return sort_kind() == Z3_RE_SORT; }
/**
\brief Return true if this sort is a Finite domain sort.
*/
@@ -532,6 +555,15 @@ namespace z3 {
\brief Return true if this is a Relation expression.
*/
bool is_relation() const { return get_sort().is_relation(); }
+ /**
+ \brief Return true if this is a sequence expression.
+ */
+ bool is_seq() const { return get_sort().is_seq(); }
+ /**
+ \brief Return true if this is a regular expression.
+ */
+ bool is_re() const { return get_sort().is_re(); }
+
/**
\brief Return true if this is a Finite-domain expression.
@@ -663,6 +695,7 @@ namespace z3 {
friend expr distinct(expr_vector const& args);
friend expr concat(expr const& a, expr const& b);
+ friend expr concat(expr_vector const& args);
friend expr operator==(expr const & a, expr const & b);
friend expr operator==(expr const & a, int b);
@@ -728,10 +761,50 @@ namespace z3 {
friend expr operator|(int a, expr const & b);
friend expr operator~(expr const & a);
- expr extract(unsigned hi, unsigned lo) const { Z3_ast r = Z3_mk_extract(ctx(), hi, lo, *this); return expr(ctx(), r); }
+ expr extract(unsigned hi, unsigned lo) const { Z3_ast r = Z3_mk_extract(ctx(), hi, lo, *this); ctx().check_error(); return expr(ctx(), r); }
unsigned lo() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 1)); }
unsigned hi() const { assert (is_app() && Z3_get_decl_num_parameters(ctx(), decl()) == 2); return static_cast(Z3_get_decl_int_parameter(ctx(), decl(), 0)); }
+ /**
+ \brief sequence and regular expression operations.
+ + is overloaeded as sequence concatenation and regular expression union.
+ concat is overloaded to handle sequences and regular expressions
+ */
+ expr extract(expr const& offset, expr const& length) const {
+ check_context(*this, offset); check_context(offset, length);
+ Z3_ast r = Z3_mk_seq_extract(ctx(), *this, offset, length); check_error(); return expr(ctx(), r);
+ }
+ expr replace(expr const& src, expr const& dst) const {
+ check_context(*this, src); check_context(src, dst);
+ Z3_ast r = Z3_mk_seq_replace(ctx(), *this, src, dst);
+ check_error();
+ return expr(ctx(), r);
+ }
+ expr unit() const {
+ Z3_ast r = Z3_mk_seq_unit(ctx(), *this);
+ check_error();
+ return expr(ctx(), r);
+ }
+ expr contains(expr const& s) {
+ check_context(*this, s);
+ Z3_ast r = Z3_mk_seq_contains(ctx(), *this, s);
+ check_error();
+ return expr(ctx(), r);
+ }
+ expr at(expr const& index) const {
+ check_context(*this, index);
+ Z3_ast r = Z3_mk_seq_at(ctx(), *this, index);
+ check_error();
+ return expr(ctx(), r);
+ }
+ expr length() const {
+ Z3_ast r = Z3_mk_seq_length(ctx(), *this);
+ check_error();
+ return expr(ctx(), r);
+ }
+
+
+
/**
\brief Return a simplified version of this expression.
*/
@@ -835,6 +908,13 @@ namespace z3 {
else if (a.is_bv() && b.is_bv()) {
r = Z3_mk_bvadd(a.ctx(), a, b);
}
+ else if (a.is_seq() && b.is_seq()) {
+ return concat(a, b);
+ }
+ else if (a.is_re() && b.is_re()) {
+ Z3_ast _args[2] = { a, b };
+ r = Z3_mk_re_union(a.ctx(), 2, _args);
+ }
else {
// operator is not supported by given arguments.
assert(false);
@@ -1219,11 +1299,48 @@ namespace z3 {
inline expr concat(expr const& a, expr const& b) {
check_context(a, b);
- Z3_ast r = Z3_mk_concat(a.ctx(), a, b);
+ Z3_ast r;
+ if (Z3_is_seq_sort(a.ctx(), a.get_sort())) {
+ Z3_ast _args[2] = { a, b };
+ r = Z3_mk_seq_concat(a.ctx(), 2, _args);
+ }
+ else if (Z3_is_re_sort(a.ctx(), a.get_sort())) {
+ Z3_ast _args[2] = { a, b };
+ r = Z3_mk_re_concat(a.ctx(), 2, _args);
+ }
+ else {
+ r = Z3_mk_concat(a.ctx(), a, b);
+ }
a.ctx().check_error();
return expr(a.ctx(), r);
}
+ inline expr concat(expr_vector const& args) {
+ Z3_ast r;
+ assert(args.size() > 0);
+ if (args.size() == 1) {
+ return args[0];
+ }
+ context& ctx = args[0].ctx();
+ array _args(args);
+ if (Z3_is_seq_sort(ctx, args[0].get_sort())) {
+ r = Z3_mk_seq_concat(ctx, _args.size(), _args.ptr());
+ }
+ else if (Z3_is_re_sort(ctx, args[0].get_sort())) {
+ r = Z3_mk_re_concat(ctx, _args.size(), _args.ptr());
+ }
+ else {
+ r = _args[args.size()-1];
+ for (unsigned i = args.size()-1; i > 0; ) {
+ --i;
+ r = Z3_mk_concat(ctx, _args[i], r);
+ ctx.check_error();
+ }
+ }
+ ctx.check_error();
+ return expr(ctx, r);
+ }
+
class func_entry : public object {
Z3_func_entry m_entry;
void init(Z3_func_entry e) {
@@ -1762,6 +1879,10 @@ namespace z3 {
inline sort context::int_sort() { Z3_sort s = Z3_mk_int_sort(m_ctx); check_error(); return sort(*this, s); }
inline sort context::real_sort() { Z3_sort s = Z3_mk_real_sort(m_ctx); check_error(); return sort(*this, s); }
inline sort context::bv_sort(unsigned sz) { Z3_sort s = Z3_mk_bv_sort(m_ctx, sz); check_error(); return sort(*this, s); }
+ inline sort context::string_sort() { Z3_sort s = Z3_mk_string_sort(m_ctx); check_error(); return sort(*this, s); }
+ inline sort context::seq_sort(sort& s) { Z3_sort r = Z3_mk_seq_sort(m_ctx, s); check_error(); return sort(*this, r); }
+ inline sort context::re_sort(sort& s) { Z3_sort r = Z3_mk_re_sort(m_ctx, s); check_error(); return sort(*this, r); }
+
inline sort context::array_sort(sort d, sort r) { Z3_sort s = Z3_mk_array_sort(m_ctx, d, r); check_error(); return sort(*this, s); }
inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) {
array _enum_names(n);
@@ -1885,6 +2006,9 @@ namespace z3 {
inline expr context::bv_val(__uint64 n, unsigned sz) { Z3_ast r = Z3_mk_unsigned_int64(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); }
inline expr context::bv_val(char const * n, unsigned sz) { Z3_ast r = Z3_mk_numeral(m_ctx, n, bv_sort(sz)); check_error(); return expr(*this, r); }
+ inline expr context::string_val(char const* s) { Z3_ast r = Z3_mk_string(m_ctx, s); check_error(); return expr(*this, r); }
+ inline expr context::string_val(std::string const& s) { Z3_ast r = Z3_mk_string(m_ctx, s.c_str()); check_error(); return expr(*this, r); }
+
inline expr context::num_val(int n, sort const & s) { Z3_ast r = Z3_mk_int(m_ctx, n, s); check_error(); return expr(*this, r); }
inline expr func_decl::operator()(unsigned n, expr const * args) const {
@@ -2017,6 +2141,62 @@ namespace z3 {
d.check_error();
return expr(d.ctx(), r);
}
+
+ // sequence and regular expression operations.
+ // union is +
+ // concat is overloaded to handle sequences and regular expressions
+
+ inline expr empty(sort const& s) {
+ Z3_ast r = Z3_mk_seq_empty(s.ctx(), s);
+ s.check_error();
+ return expr(s.ctx(), r);
+ }
+ inline expr suffixof(expr const& a, expr const& b) {
+ check_context(a, b);
+ Z3_ast r = Z3_mk_seq_suffix(a.ctx(), a, b);
+ a.check_error();
+ return expr(a.ctx(), r);
+ }
+ inline expr prefixof(expr const& a, expr const& b) {
+ check_context(a, b);
+ Z3_ast r = Z3_mk_seq_prefix(a.ctx(), a, b);
+ a.check_error();
+ return expr(a.ctx(), r);
+ }
+ inline expr indexof(expr const& s, expr const& substr, expr const& offset) {
+ check_context(s, substr); check_context(s, offset);
+ Z3_ast r = Z3_mk_seq_index(s.ctx(), s, substr, offset);
+ s.check_error();
+ return expr(s.ctx(), r);
+ }
+ inline expr to_re(expr const& s) {
+ Z3_ast r = Z3_mk_seq_to_re(s.ctx(), s);
+ s.check_error();
+ return expr(s.ctx(), r);
+ }
+ inline expr in_re(expr const& s, expr const& re) {
+ check_context(s, re);
+ Z3_ast r = Z3_mk_seq_in_re(s.ctx(), s, re);
+ s.check_error();
+ return expr(s.ctx(), r);
+ }
+ inline expr plus(expr const& re) {
+ Z3_ast r = Z3_mk_re_plus(re.ctx(), re);
+ re.check_error();
+ return expr(re.ctx(), r);
+ }
+ inline expr option(expr const& re) {
+ Z3_ast r = Z3_mk_re_option(re.ctx(), re);
+ re.check_error();
+ return expr(re.ctx(), r);
+ }
+ inline expr star(expr const& re) {
+ Z3_ast r = Z3_mk_re_star(re.ctx(), re);
+ re.check_error();
+ return expr(re.ctx(), r);
+ }
+
+
inline expr interpolant(expr const& a) {
return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a));
}
diff --git a/src/api/dotnet/Context.cs b/src/api/dotnet/Context.cs
index 2e08d3dab..a97036897 100644
--- a/src/api/dotnet/Context.cs
+++ b/src/api/dotnet/Context.cs
@@ -125,6 +125,7 @@ namespace Microsoft.Z3
private BoolSort m_boolSort = null;
private IntSort m_intSort = null;
private RealSort m_realSort = null;
+ private SeqSort m_stringSort = null;
///
/// Retrieves the Boolean sort of the context.
@@ -163,6 +164,20 @@ namespace Microsoft.Z3
}
}
+ ///
+ /// Retrieves the String sort of the context.
+ ///
+ public SeqSort StringSort
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result() != null);
+ if (m_stringSort == null) m_stringSort = new SeqSort(this, Native.Z3_mk_string_sort(nCtx));
+ return m_stringSort;
+ }
+ }
+
+
///
/// Create a new Boolean sort.
///
@@ -223,6 +238,27 @@ namespace Microsoft.Z3
return new BitVecSort(this, Native.Z3_mk_bv_sort(nCtx, size));
}
+
+ ///
+ /// Create a new sequence sort.
+ ///
+ public SeqSort MkSeqSort(Sort s)
+ {
+ Contract.Requires(s != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new SeqSort(this, Native.Z3_mk_seq_sort(nCtx, s.NativeObject));
+ }
+
+ ///
+ /// Create a new regular expression sort.
+ ///
+ public ReSort MkReSort(SeqSort s)
+ {
+ Contract.Requires(s != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new ReSort(this, Native.Z3_mk_re_sort(nCtx, s.NativeObject));
+ }
+
///
/// Create a new array sort.
///
@@ -2286,6 +2322,230 @@ namespace Microsoft.Z3
#endregion
+ #region Sequence, string and regular expresions
+
+ ///
+ /// Create the empty sequence.
+ ///
+ public SeqExpr MkEmptySeq(Sort s)
+ {
+ Contract.Requires(s != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new SeqExpr(this, Native.Z3_mk_seq_empty(nCtx, s.NativeObject));
+ }
+
+ ///
+ /// Create the singleton sequence.
+ ///
+ public SeqExpr MkUnit(Expr elem)
+ {
+ Contract.Requires(elem != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new SeqExpr(this, Native.Z3_mk_seq_unit(nCtx, elem.NativeObject));
+ }
+
+ ///
+ /// Create a string constant.
+ ///
+ public SeqExpr MkString(string s)
+ {
+ Contract.Requires(s != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new SeqExpr(this, Native.Z3_mk_string(nCtx, s));
+ }
+
+ ///
+ /// Concatentate sequences.
+ ///
+ public SeqExpr MkConcat(params SeqExpr[] t)
+ {
+ Contract.Requires(t != null);
+ Contract.Requires(Contract.ForAll(t, a => a != null));
+ Contract.Ensures(Contract.Result() != null);
+
+ CheckContextMatch(t);
+ return new SeqExpr(this, Native.Z3_mk_seq_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t)));
+ }
+
+
+ ///
+ /// Retrieve the length of a given sequence.
+ ///
+ public IntExpr MkLength(SeqExpr s)
+ {
+ Contract.Requires(s != null);
+ Contract.Ensures(Contract.Result() != null);
+ return (IntExpr) Expr.Create(this, Native.Z3_mk_seq_length(nCtx, s.NativeObject));
+ }
+
+ ///
+ /// Check for sequence prefix.
+ ///
+ public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2)
+ {
+ Contract.Requires(s1 != null);
+ Contract.Requires(s2 != null);
+ Contract.Ensures(Contract.Result() != null);
+ CheckContextMatch(s1, s2);
+ return new BoolExpr(this, Native.Z3_mk_seq_prefix(nCtx, s1.NativeObject, s2.NativeObject));
+ }
+
+ ///
+ /// Check for sequence suffix.
+ ///
+ public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2)
+ {
+ Contract.Requires(s1 != null);
+ Contract.Requires(s2 != null);
+ Contract.Ensures(Contract.Result() != null);
+ CheckContextMatch(s1, s2);
+ return new BoolExpr(this, Native.Z3_mk_seq_suffix(nCtx, s1.NativeObject, s2.NativeObject));
+ }
+
+ ///
+ /// Check for sequence containment of s2 in s1.
+ ///
+ public BoolExpr MkContains(SeqExpr s1, SeqExpr s2)
+ {
+ Contract.Requires(s1 != null);
+ Contract.Requires(s2 != null);
+ Contract.Ensures(Contract.Result() != null);
+ CheckContextMatch(s1, s2);
+ return new BoolExpr(this, Native.Z3_mk_seq_contains(nCtx, s1.NativeObject, s2.NativeObject));
+ }
+
+ ///
+ /// Retrieve sequence of length one at index.
+ ///
+ public SeqExpr MkAt(SeqExpr s, IntExpr index)
+ {
+ Contract.Requires(s != null);
+ Contract.Requires(index != null);
+ Contract.Ensures(Contract.Result() != null);
+ CheckContextMatch(s, index);
+ return new SeqExpr(this, Native.Z3_mk_seq_at(nCtx, s.NativeObject, index.NativeObject));
+ }
+
+ ///
+ /// Extract subsequence.
+ ///
+ public SeqExpr MkExtract(SeqExpr s, IntExpr offset, IntExpr length)
+ {
+ Contract.Requires(s != null);
+ Contract.Requires(offset != null);
+ Contract.Requires(length != null);
+ Contract.Ensures(Contract.Result() != null);
+ CheckContextMatch(s, offset, length);
+ return new SeqExpr(this, Native.Z3_mk_seq_extract(nCtx, s.NativeObject, offset.NativeObject, length.NativeObject));
+ }
+
+ ///
+ /// Extract index of sub-string starting at offset.
+ ///
+ public IntExpr MkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset)
+ {
+ Contract.Requires(s != null);
+ Contract.Requires(offset != null);
+ Contract.Requires(substr != null);
+ Contract.Ensures(Contract.Result() != null);
+ CheckContextMatch(s, substr, offset);
+ return new IntExpr(this, Native.Z3_mk_seq_index(nCtx, s.NativeObject, substr.NativeObject, offset.NativeObject));
+ }
+
+ ///
+ /// Replace the first occurrence of src by dst in s.
+ ///
+ public SeqExpr MkReplace(SeqExpr s, SeqExpr src, SeqExpr dst)
+ {
+ Contract.Requires(s != null);
+ Contract.Requires(src != null);
+ Contract.Requires(dst != null);
+ Contract.Ensures(Contract.Result() != null);
+ CheckContextMatch(s, src, dst);
+ return new SeqExpr(this, Native.Z3_mk_seq_replace(nCtx, s.NativeObject, src.NativeObject, dst.NativeObject));
+ }
+
+ ///
+ /// Convert a regular expression that accepts sequence s.
+ ///
+ public ReExpr MkToRe(SeqExpr s)
+ {
+ Contract.Requires(s != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new ReExpr(this, Native.Z3_mk_seq_to_re(nCtx, s.NativeObject));
+ }
+
+
+ ///
+ /// Check for regular expression membership.
+ ///
+ public BoolExpr MkInRe(SeqExpr s, ReExpr re)
+ {
+ Contract.Requires(s != null);
+ Contract.Requires(re != null);
+ Contract.Ensures(Contract.Result() != null);
+ CheckContextMatch(s, re);
+ return new BoolExpr(this, Native.Z3_mk_seq_in_re(nCtx, s.NativeObject, re.NativeObject));
+ }
+
+ ///
+ /// Take the Kleene star of a regular expression.
+ ///
+ public ReExpr MkStar(ReExpr re)
+ {
+ Contract.Requires(re != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new ReExpr(this, Native.Z3_mk_re_star(nCtx, re.NativeObject));
+ }
+
+ ///
+ /// Take the Kleene plus of a regular expression.
+ ///
+ public ReExpr MPlus(ReExpr re)
+ {
+ Contract.Requires(re != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new ReExpr(this, Native.Z3_mk_re_plus(nCtx, re.NativeObject));
+ }
+
+ ///
+ /// Create the optional regular expression.
+ ///
+ public ReExpr MOption(ReExpr re)
+ {
+ Contract.Requires(re != null);
+ Contract.Ensures(Contract.Result() != null);
+ return new ReExpr(this, Native.Z3_mk_re_option(nCtx, re.NativeObject));
+ }
+
+ ///
+ /// Create the concatenation of regular languages.
+ ///
+ public ReExpr MkConcat(params ReExpr[] t)
+ {
+ Contract.Requires(t != null);
+ Contract.Requires(Contract.ForAll(t, a => a != null));
+ Contract.Ensures(Contract.Result() != null);
+
+ CheckContextMatch(t);
+ return new ReExpr(this, Native.Z3_mk_re_concat(nCtx, (uint)t.Length, AST.ArrayToNative(t)));
+ }
+
+ ///
+ /// Create the union of regular languages.
+ ///
+ public ReExpr MkUnion(params ReExpr[] t)
+ {
+ Contract.Requires(t != null);
+ Contract.Requires(Contract.ForAll(t, a => a != null));
+ Contract.Ensures(Contract.Result() != null);
+
+ CheckContextMatch(t);
+ return new ReExpr(this, Native.Z3_mk_re_union(nCtx, (uint)t.Length, AST.ArrayToNative(t)));
+ }
+
+ #endregion
+
#region Pseudo-Boolean constraints
///
@@ -4448,6 +4708,26 @@ namespace Microsoft.Z3
throw new Z3Exception("Context mismatch");
}
+ [Pure]
+ internal void CheckContextMatch(Z3Object other1, Z3Object other2)
+ {
+ Contract.Requires(other1 != null);
+ Contract.Requires(other2 != null);
+ CheckContextMatch(other1);
+ CheckContextMatch(other2);
+ }
+
+ [Pure]
+ internal void CheckContextMatch(Z3Object other1, Z3Object other2, Z3Object other3)
+ {
+ Contract.Requires(other1 != null);
+ Contract.Requires(other2 != null);
+ Contract.Requires(other3 != null);
+ CheckContextMatch(other1);
+ CheckContextMatch(other2);
+ CheckContextMatch(other3);
+ }
+
[Pure]
internal void CheckContextMatch(Z3Object[] arr)
{
@@ -4628,6 +4908,7 @@ namespace Microsoft.Z3
m_boolSort = null;
m_intSort = null;
m_realSort = null;
+ m_stringSort = null;
}
#endregion
}
diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs
index 599cbf756..c995a12bd 100644
--- a/src/api/dotnet/Expr.cs
+++ b/src/api/dotnet/Expr.cs
@@ -1826,6 +1826,8 @@ namespace Microsoft.Z3
case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPExpr(ctx, obj);
case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMExpr(ctx, obj);
case Z3_sort_kind.Z3_FINITE_DOMAIN_SORT: return new FiniteDomainExpr(ctx, obj);
+ case Z3_sort_kind.Z3_RE_SORT: return new ReExpr(ctx, obj);
+ case Z3_sort_kind.Z3_SEQ_SORT: return new SeqExpr(ctx, obj);
}
return new Expr(ctx, obj);
diff --git a/src/api/dotnet/Microsoft.Z3.csproj b/src/api/dotnet/Microsoft.Z3.csproj
index a753e0193..cde8b78c9 100644
--- a/src/api/dotnet/Microsoft.Z3.csproj
+++ b/src/api/dotnet/Microsoft.Z3.csproj
@@ -374,7 +374,11 @@
+
+
+
+
diff --git a/src/api/dotnet/ReExpr.cs b/src/api/dotnet/ReExpr.cs
new file mode 100644
index 000000000..6a10d535f
--- /dev/null
+++ b/src/api/dotnet/ReExpr.cs
@@ -0,0 +1,42 @@
+/*++
+Copyright () 2016 Microsoft Corporation
+
+Module Name:
+
+ ReExpr.cs
+
+Abstract:
+
+ Z3 Managed API: Regular Expressions
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2012-11-23
+
+Notes:
+
+--*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// Regular expression expressions
+ ///
+ public class ReExpr : Expr
+ {
+ #region Internal
+ /// Constructor for ReExpr
+ internal ReExpr(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
diff --git a/src/api/dotnet/ReSort.cs b/src/api/dotnet/ReSort.cs
new file mode 100644
index 000000000..bc420603d
--- /dev/null
+++ b/src/api/dotnet/ReSort.cs
@@ -0,0 +1,43 @@
+/*++
+Copyright (c) 2016 Microsoft Corporation
+
+Module Name:
+
+ ReSort.cs
+
+Abstract:
+
+ Z3 Managed API: Regular expression Sorts
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2012-11-23
+
+Notes:
+
+--*/
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// A regular expression sort
+ ///
+ public class ReSort : Sort
+ {
+ #region Internal
+ internal ReSort(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ internal ReSort(Context ctx)
+ : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx))
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
diff --git a/src/api/dotnet/SeqExpr.cs b/src/api/dotnet/SeqExpr.cs
new file mode 100644
index 000000000..c9fdd03a8
--- /dev/null
+++ b/src/api/dotnet/SeqExpr.cs
@@ -0,0 +1,42 @@
+/*++
+Copyright () 2016 Microsoft Corporation
+
+Module Name:
+
+ SeqExpr.cs
+
+Abstract:
+
+ Z3 Managed API: Sequence Expressions
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2012-11-23
+
+Notes:
+
+--*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// Sequence expressions
+ ///
+ public class SeqExpr : Expr
+ {
+ #region Internal
+ /// Constructor for SeqExpr
+ internal SeqExpr(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
diff --git a/src/api/dotnet/SeqSort.cs b/src/api/dotnet/SeqSort.cs
new file mode 100644
index 000000000..b2be11291
--- /dev/null
+++ b/src/api/dotnet/SeqSort.cs
@@ -0,0 +1,43 @@
+/*++
+Copyright (c) 2016 Microsoft Corporation
+
+Module Name:
+
+ SeqSort.cs
+
+Abstract:
+
+ Z3 Managed API: Sequence Sorts
+
+Author:
+
+ Christoph Wintersteiger (cwinter) 2012-11-23
+
+Notes:
+
+--*/
+
+using System;
+using System.Diagnostics.Contracts;
+
+namespace Microsoft.Z3
+{
+ ///
+ /// A Sequence sort
+ ///
+ public class SeqSort : Sort
+ {
+ #region Internal
+ internal SeqSort(Context ctx, IntPtr obj)
+ : base(ctx, obj)
+ {
+ Contract.Requires(ctx != null);
+ }
+ internal SeqSort(Context ctx)
+ : base(ctx, Native.Z3_mk_int_sort(ctx.nCtx))
+ {
+ Contract.Requires(ctx != null);
+ }
+ #endregion
+ }
+}
diff --git a/src/api/dotnet/Sort.cs b/src/api/dotnet/Sort.cs
index 412398ddd..e1b8ca1b7 100644
--- a/src/api/dotnet/Sort.cs
+++ b/src/api/dotnet/Sort.cs
@@ -147,6 +147,8 @@ namespace Microsoft.Z3
case Z3_sort_kind.Z3_RELATION_SORT: return new RelationSort(ctx, obj);
case Z3_sort_kind.Z3_FLOATING_POINT_SORT: return new FPSort(ctx, obj);
case Z3_sort_kind.Z3_ROUNDING_MODE_SORT: return new FPRMSort(ctx, obj);
+ case Z3_sort_kind.Z3_SEQ_SORT: return new SeqSort(ctx, obj);
+ case Z3_sort_kind.Z3_RE_SORT: return new ReSort(ctx, obj);
default:
throw new Z3Exception("Unknown sort kind");
}
diff --git a/src/api/java/Context.java b/src/api/java/Context.java
index 4d8484ced..40b597be4 100644
--- a/src/api/java/Context.java
+++ b/src/api/java/Context.java
@@ -103,6 +103,7 @@ public class Context extends IDisposable
private BoolSort m_boolSort = null;
private IntSort m_intSort = null;
private RealSort m_realSort = null;
+ private SeqSort m_stringSort = null;
/**
* Retrieves the Boolean sort of the context.
@@ -142,6 +143,16 @@ public class Context extends IDisposable
return new BoolSort(this);
}
+ /**
+ * Retrieves the Integer sort of the context.
+ **/
+ public SeqSort getStringSort()
+ {
+ if (m_stringSort == null)
+ m_stringSort = mkStringSort();
+ return m_stringSort;
+ }
+
/**
* Create a new uninterpreted sort.
**/
@@ -193,6 +204,31 @@ public class Context extends IDisposable
return new ArraySort(this, domain, range);
}
+ /**
+ * Create a new string sort
+ **/
+ public SeqSort mkStringSort()
+ {
+ return new SeqSort(this, Native.mkStringSort(nCtx()));
+ }
+
+ /**
+ * Create a new sequence sort
+ **/
+ public SeqSort mkSeqSort(Sort s)
+ {
+ return new SeqSort(this, Native.mkSeqSort(nCtx(), s.getNativeObject()));
+ }
+
+ /**
+ * Create a new regular expression sort
+ **/
+ public ReSort mkReSort(Sort s)
+ {
+ return new ReSort(this, Native.mkReSort(nCtx(), s.getNativeObject()));
+ }
+
+
/**
* Create a new tuple sort.
**/
@@ -1849,6 +1885,184 @@ public class Context extends IDisposable
arg2.getNativeObject()));
}
+
+ /**
+ * Sequences, Strings and regular expressions.
+ */
+
+ /**
+ * Create the empty sequence.
+ */
+ public SeqExpr MkEmptySeq(Sort s)
+ {
+ checkContextMatch(s);
+ return new SeqExpr(this, Native.mkSeqEmpty(nCtx(), s.getNativeObject()));
+ }
+
+ /**
+ * Create the singleton sequence.
+ */
+ public SeqExpr MkUnit(Expr elem)
+ {
+ checkContextMatch(elem);
+ return new SeqExpr(this, Native.mkSeqUnit(nCtx(), elem.getNativeObject()));
+ }
+
+ /**
+ * Create a string constant.
+ */
+ public SeqExpr MkString(String s)
+ {
+ return new SeqExpr(this, Native.mkString(nCtx(), s));
+ }
+
+ /**
+ * Concatentate sequences.
+ */
+ public SeqExpr MkConcat(SeqExpr... t)
+ {
+ checkContextMatch(t);
+ return new SeqExpr(this, Native.mkSeqConcat(nCtx(), (int)t.length, AST.arrayToNative(t)));
+ }
+
+
+ /**
+ * Retrieve the length of a given sequence.
+ */
+ public IntExpr MkLength(SeqExpr s)
+ {
+ checkContextMatch(s);
+ return (IntExpr) Expr.create(this, Native.mkSeqLength(nCtx(), s.getNativeObject()));
+ }
+
+ /**
+ * Check for sequence prefix.
+ */
+ public BoolExpr MkPrefixOf(SeqExpr s1, SeqExpr s2)
+ {
+ checkContextMatch(s1, s2);
+ return new BoolExpr(this, Native.mkSeqPrefix(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
+ }
+
+ /**
+ * Check for sequence suffix.
+ */
+ public BoolExpr MkSuffixOf(SeqExpr s1, SeqExpr s2)
+ {
+ checkContextMatch(s1, s2);
+ return new BoolExpr(this, Native.mkSeqSuffix(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
+ }
+
+ /**
+ * Check for sequence containment of s2 in s1.
+ */
+ public BoolExpr MkContains(SeqExpr s1, SeqExpr s2)
+ {
+ checkContextMatch(s1, s2);
+ return new BoolExpr(this, Native.mkSeqContains(nCtx(), s1.getNativeObject(), s2.getNativeObject()));
+ }
+
+ /**
+ * Retrieve sequence of length one at index.
+ */
+ public SeqExpr MkAt(SeqExpr s, IntExpr index)
+ {
+ checkContextMatch(s, index);
+ return new SeqExpr(this, Native.mkSeqAt(nCtx(), s.getNativeObject(), index.getNativeObject()));
+ }
+
+ /**
+ * Extract subsequence.
+ */
+ public SeqExpr MkExtract(SeqExpr s, IntExpr offset, IntExpr length)
+ {
+ checkContextMatch(s, offset, length);
+ return new SeqExpr(this, Native.mkSeqExtract(nCtx(), s.getNativeObject(), offset.getNativeObject(), length.getNativeObject()));
+ }
+
+ /**
+ * Extract index of sub-string starting at offset.
+ */
+ public IntExpr MkIndexOf(SeqExpr s, SeqExpr substr, ArithExpr offset)
+ {
+ checkContextMatch(s, substr, offset);
+ return new IntExpr(this, Native.mkSeqIndex(nCtx(), s.getNativeObject(), substr.getNativeObject(), offset.getNativeObject()));
+ }
+
+ /**
+ * Replace the first occurrence of src by dst in s.
+ */
+ public SeqExpr MkReplace(SeqExpr s, SeqExpr src, SeqExpr dst)
+ {
+ checkContextMatch(s, src, dst);
+ return new SeqExpr(this, Native.mkSeqReplace(nCtx(), s.getNativeObject(), src.getNativeObject(), dst.getNativeObject()));
+ }
+
+ /**
+ * Convert a regular expression that accepts sequence s.
+ */
+ public ReExpr MkToRe(SeqExpr s)
+ {
+ checkContextMatch(s);
+ return new ReExpr(this, Native.mkSeqToRe(nCtx(), s.getNativeObject()));
+ }
+
+
+ /**
+ * Check for regular expression membership.
+ */
+ public BoolExpr MkInRe(SeqExpr s, ReExpr re)
+ {
+ checkContextMatch(s, re);
+ return new BoolExpr(this, Native.mkSeqInRe(nCtx(), s.getNativeObject(), re.getNativeObject()));
+ }
+
+ /**
+ * Take the Kleene star of a regular expression.
+ */
+ public ReExpr MkStar(ReExpr re)
+ {
+ checkContextMatch(re);
+ return new ReExpr(this, Native.mkReStar(nCtx(), re.getNativeObject()));
+ }
+
+ /**
+ * Take the Kleene plus of a regular expression.
+ */
+ public ReExpr MPlus(ReExpr re)
+ {
+ checkContextMatch(re);
+ return new ReExpr(this, Native.mkRePlus(nCtx(), re.getNativeObject()));
+ }
+
+ /**
+ * Create the optional regular expression.
+ */
+ public ReExpr MOption(ReExpr re)
+ {
+ checkContextMatch(re);
+ return new ReExpr(this, Native.mkReOption(nCtx(), re.getNativeObject()));
+ }
+
+ /**
+ * Create the concatenation of regular languages.
+ */
+ public ReExpr MkConcat(ReExpr... t)
+ {
+ checkContextMatch(t);
+ return new ReExpr(this, Native.mkReConcat(nCtx(), (int)t.length, AST.arrayToNative(t)));
+ }
+
+ /**
+ * Create the union of regular languages.
+ */
+ public ReExpr MkUnion(ReExpr... t)
+ {
+ checkContextMatch(t);
+ return new ReExpr(this, Native.mkReUnion(nCtx(), (int)t.length, AST.arrayToNative(t)));
+ }
+
+
/**
* Create a Term of a given sort.
* @param v A string representing the term value in decimal notation. If the given sort is a real, then the
@@ -3683,6 +3897,19 @@ public class Context extends IDisposable
throw new Z3Exception("Context mismatch");
}
+ void checkContextMatch(Z3Object other1, Z3Object other2)
+ {
+ checkContextMatch(other1);
+ checkContextMatch(other2);
+ }
+
+ void checkContextMatch(Z3Object other1, Z3Object other2, Z3Object other3)
+ {
+ checkContextMatch(other1);
+ checkContextMatch(other2);
+ checkContextMatch(other3);
+ }
+
void checkContextMatch(Z3Object[] arr)
{
if (arr != null)
@@ -3822,6 +4049,7 @@ public class Context extends IDisposable
m_Params_DRQ.clear(this);
m_Probe_DRQ.clear(this);
m_Solver_DRQ.clear(this);
+ m_Optimize_DRQ.clear(this);
m_Statistics_DRQ.clear(this);
m_Tactic_DRQ.clear(this);
m_Fixedpoint_DRQ.clear(this);
@@ -3829,6 +4057,7 @@ public class Context extends IDisposable
m_boolSort = null;
m_intSort = null;
m_realSort = null;
+ m_stringSort = null;
synchronized (creation_lock) {
if (m_refCount.get() == 0 && m_ctx != 0) {
diff --git a/src/api/java/Expr.java b/src/api/java/Expr.java
index b0b95d4b7..e03d5b1c9 100644
--- a/src/api/java/Expr.java
+++ b/src/api/java/Expr.java
@@ -2186,6 +2186,10 @@ public class Expr extends AST
return new FPRMExpr(ctx, obj);
case Z3_FINITE_DOMAIN_SORT:
return new FiniteDomainExpr(ctx, obj);
+ case Z3_SEQ_SORT:
+ return new SeqExpr(ctx, obj);
+ case Z3_RE_SORT:
+ return new ReExpr(ctx, obj);
default: ;
}
diff --git a/src/api/java/ReExpr.java b/src/api/java/ReExpr.java
new file mode 100644
index 000000000..60dc2bf96
--- /dev/null
+++ b/src/api/java/ReExpr.java
@@ -0,0 +1,33 @@
+/**
+Copyright (c) 2012-2016 Microsoft Corporation
+
+Module Name:
+
+ ReExpr.java
+
+Abstract:
+
+Author:
+
+ @author Christoph Wintersteiger (cwinter) 2012-03-15
+
+Notes:
+
+**/
+
+package com.microsoft.z3;
+
+/**
+ * Re expressions
+ **/
+public class ReExpr extends Expr
+{
+ /**
+ * Constructor for ReExpr
+ * @throws Z3Exception on error
+ **/
+ ReExpr(Context ctx, long obj)
+ {
+ super(ctx, obj);
+ }
+}
diff --git a/src/api/java/ReSort.java b/src/api/java/ReSort.java
new file mode 100644
index 000000000..74e7c5c5f
--- /dev/null
+++ b/src/api/java/ReSort.java
@@ -0,0 +1,29 @@
+/**
+Copyright (c) 2012-2014 Microsoft Corporation
+
+Module Name:
+
+ ReSort.java
+
+Abstract:
+
+Author:
+
+ @author Christoph Wintersteiger (cwinter) 2012-03-15
+
+Notes:
+
+**/
+
+package com.microsoft.z3;
+
+/**
+ * A Regular expression sort
+ **/
+public class ReSort extends Sort
+{
+ ReSort(Context ctx, long obj)
+ {
+ super(ctx, obj);
+ }
+}
diff --git a/src/api/java/SeqExpr.java b/src/api/java/SeqExpr.java
new file mode 100644
index 000000000..47976dd5e
--- /dev/null
+++ b/src/api/java/SeqExpr.java
@@ -0,0 +1,33 @@
+/**
+Copyright (c) 2012-2016 Microsoft Corporation
+
+Module Name:
+
+ SeqExpr.java
+
+Abstract:
+
+Author:
+
+ @author Christoph Wintersteiger (cwinter) 2012-03-15
+
+Notes:
+
+**/
+
+package com.microsoft.z3;
+
+/**
+ * Seq expressions
+ **/
+public class SeqExpr extends Expr
+{
+ /**
+ * Constructor for SeqExpr
+ * @throws Z3Exception on error
+ **/
+ SeqExpr(Context ctx, long obj)
+ {
+ super(ctx, obj);
+ }
+}
diff --git a/src/api/java/SeqSort.java b/src/api/java/SeqSort.java
new file mode 100644
index 000000000..5c7a549c9
--- /dev/null
+++ b/src/api/java/SeqSort.java
@@ -0,0 +1,29 @@
+/**
+Copyright (c) 2012-2014 Microsoft Corporation
+
+Module Name:
+
+ SeqSort.java
+
+Abstract:
+
+Author:
+
+ @author Christoph Wintersteiger (cwinter) 2012-03-15
+
+Notes:
+
+**/
+
+package com.microsoft.z3;
+
+/**
+ * A Sequence sort
+ **/
+public class SeqSort extends Sort
+{
+ SeqSort(Context ctx, long obj)
+ {
+ super(ctx, obj);
+ }
+}
diff --git a/src/api/java/Sort.java b/src/api/java/Sort.java
index db6bee80e..1481a44e2 100644
--- a/src/api/java/Sort.java
+++ b/src/api/java/Sort.java
@@ -141,6 +141,10 @@ public class Sort extends AST
return new FPSort(ctx, obj);
case Z3_ROUNDING_MODE_SORT:
return new FPRMSort(ctx, obj);
+ case Z3_SEQ_SORT:
+ return new SeqSort(ctx, obj);
+ case Z3_RE_SORT:
+ return new ReSort(ctx, obj);
default:
throw new Z3Exception("Unknown sort kind");
}
diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml
index 84c70001e..54b9c3932 100644
--- a/src/api/ml/z3.ml
+++ b/src/api/ml/z3.ml
@@ -60,7 +60,7 @@ struct
o.inc_ref (context_gno ctx) no ;
(
if not (is_null o.m_n_obj) then
- o.dec_ref (context_gno ctx) o.m_n_obj ;
+ o.dec_ref (context_gno ctx) o.m_n_obj ;
(context_sub1 ctx)
) ;
o.m_n_obj <- no
@@ -68,8 +68,8 @@ struct
let z3obj_dispose o =
if not (is_null o.m_n_obj) then
(
- o.dec_ref (z3obj_gnc o) o.m_n_obj ;
- (context_sub1 (z3obj_gc o))
+ o.dec_ref (z3obj_gnc o) o.m_n_obj ;
+ (context_sub1 (z3obj_gc o))
) ;
o.m_n_obj <- null
@@ -81,12 +81,14 @@ struct
let z3_native_object_of_ast_ptr : context -> Z3native.ptr -> z3_native_object = fun ctx no ->
let res : z3_native_object = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.inc_ref ;
- dec_ref = Z3native.dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.inc_ref ;
+ dec_ref = Z3native.dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
- res
+ res
+
+
end
open Internal
@@ -137,18 +139,18 @@ struct
let create_i ( ctx : context ) ( no : Z3native.ptr ) =
let res : symbol = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = z3obj_nil_ref ;
- dec_ref = z3obj_nil_ref } in
+ m_n_obj = null ;
+ inc_ref = z3obj_nil_ref ;
+ dec_ref = z3obj_nil_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
let create_s ( ctx : context ) ( no : Z3native.ptr ) =
let res : symbol = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = z3obj_nil_ref ;
- dec_ref = z3obj_nil_ref } in
+ m_n_obj = null ;
+ inc_ref = z3obj_nil_ref ;
+ dec_ref = z3obj_nil_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
@@ -156,7 +158,7 @@ struct
let create ( ctx : context ) ( no : Z3native.ptr ) =
match (symbol_kind_of_int (Z3native.get_symbol_kind (context_gno ctx) no)) with
| INT_SYMBOL -> (create_i ctx no)
- | STRING_SYMBOL -> (create_s ctx no)
+ | STRING_SYMBOL -> (create_s ctx no)
let gc ( x : symbol ) = (z3obj_gc x)
let gnc ( x : symbol ) = (z3obj_gnc x)
@@ -264,16 +266,16 @@ end = struct
module ASTVector =
struct
type ast_vector = z3_native_object
-
+
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : ast_vector = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.ast_vector_inc_ref ;
- dec_ref = Z3native.ast_vector_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.ast_vector_inc_ref ;
+ dec_ref = Z3native.ast_vector_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
-
+
let mk_ast_vector ( ctx : context ) = (create ctx (Z3native.mk_ast_vector (context_gno ctx)))
let get_size ( x : ast_vector ) =
@@ -287,69 +289,69 @@ end = struct
let resize ( x : ast_vector ) ( new_size : int ) =
Z3native.ast_vector_resize (z3obj_gnc x) (z3obj_gno x) new_size
-
+
let push ( x : ast_vector ) ( a : ast ) =
Z3native.ast_vector_push (z3obj_gnc x) (z3obj_gno x) (z3obj_gno a)
-
+
let translate ( x : ast_vector ) ( to_ctx : context ) =
create to_ctx (Z3native.ast_vector_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx))
let to_list ( x : ast_vector ) =
- let xs = (get_size x) in
+ let xs = (get_size x) in
let f i = (get x i) in
mk_list f xs
let to_expr_list ( x : ast_vector ) =
- let xs = (get_size x) in
+ let xs = (get_size x) in
let f i = (Expr.expr_of_ptr (z3obj_gc x) (z3obj_gno (get x i))) in
mk_list f xs
-
+
let to_string ( x : ast_vector ) =
Z3native.ast_vector_to_string (z3obj_gnc x) (z3obj_gno x)
end
module ASTMap =
- struct
+ struct
type ast_map = z3_native_object
-
+
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : ast_map = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.ast_map_inc_ref ;
- dec_ref = Z3native.ast_map_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.ast_map_inc_ref ;
+ dec_ref = Z3native.ast_map_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
- res
-
+ res
+
let mk_ast_map ( ctx : context ) = (create ctx (Z3native.mk_ast_map (context_gno ctx)))
let astmap_of_ptr ( ctx : context ) ( no : Z3native.ptr ) =
let res : ast_map = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.ast_map_inc_ref ;
- dec_ref = Z3native.ast_map_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.ast_map_inc_ref ;
+ dec_ref = Z3native.ast_map_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
-
+
let contains ( x : ast_map ) ( key : ast ) =
Z3native.ast_map_contains (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key)
-
+
let find ( x : ast_map ) ( key : ast ) =
ast_of_ptr (z3obj_gc x) (Z3native.ast_map_find (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key))
-
+
let insert ( x : ast_map ) ( key : ast ) ( value : ast ) =
Z3native.ast_map_insert (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key) (z3obj_gno value)
let erase ( x : ast_map ) ( key : ast ) =
Z3native.ast_map_erase (z3obj_gnc x) (z3obj_gno x) (z3obj_gno key)
-
+
let reset ( x : ast_map ) =
Z3native.ast_map_reset (z3obj_gnc x) (z3obj_gno x)
let get_size ( x : ast_map ) =
Z3native.ast_map_size (z3obj_gnc x) (z3obj_gno x)
-
+
let get_keys ( x : ast_map ) =
let av = ASTVector.create (z3obj_gc x) (Z3native.ast_map_keys (z3obj_gnc x) (z3obj_gno x)) in
(ASTVector.to_list av)
@@ -369,7 +371,7 @@ end = struct
| QUANTIFIER_AST
| VAR_AST -> true
| _ -> false
-
+
let is_app ( x : ast ) = (get_ast_kind x) == APP_AST
let is_var ( x : ast ) = (get_ast_kind x) == VAR_AST
let is_quantifier ( x : ast ) = (get_ast_kind x) == QUANTIFIER_AST
@@ -385,12 +387,12 @@ end = struct
false
else
Z3native.is_eq_ast (z3obj_gnc a) (z3obj_gno a) (z3obj_gno b)
-
+
let compare a b =
if (get_id a) < (get_id b) then -1 else
if (get_id a) > (get_id b) then 1 else
- 0
-
+ 0
+
let translate ( x : ast ) ( to_ctx : context ) =
if (z3obj_gnc x) == (context_gno to_ctx) then
x
@@ -456,24 +458,19 @@ end = struct
let equal : sort -> sort -> bool = fun a b ->
(a == b) ||
if (gnc a) != (gnc b) then
- false
+ false
else
- (Z3native.is_eq_sort (gnc a) (gno a) (gno b))
+ (Z3native.is_eq_sort (gnc a) (gno a) (gno b))
-
+
let get_id ( x : sort ) = Z3native.get_sort_id (gnc x) (gno x)
let get_sort_kind ( x : sort ) = (sort_kind_of_int (Z3native.get_sort_kind (gnc x) (gno x)))
let get_name ( x : sort ) = (Symbol.create (gc x) (Z3native.get_sort_name (gnc x) (gno x)))
let to_string ( x : sort ) = Z3native.sort_to_string (gnc x) (gno x)
let mk_uninterpreted ( ctx : context ) ( s : Symbol.symbol ) =
- let res = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.inc_ref ;
- dec_ref = Z3native.dec_ref } in
- (z3obj_sno res ctx (Z3native.mk_uninterpreted_sort (context_gno ctx) (Symbol.gno s))) ;
- (z3obj_create res) ;
- Sort(res)
+ let n = (Z3native.mk_uninterpreted_sort (context_gno ctx) (Symbol.gno s)) in
+ Sort(z3_native_object_of_ast_ptr ctx n)
let mk_uninterpreted_s ( ctx : context ) ( s : string ) =
mk_uninterpreted ctx (Symbol.mk_string ( ctx : context ) s)
@@ -490,14 +487,14 @@ sig
module Parameter :
sig
type parameter =
- P_Int of int
+ P_Int of int
| P_Dbl of float
| P_Sym of Symbol.symbol
| P_Srt of Sort.sort
| P_Ast of AST.ast
| P_Fdl of func_decl
| P_Rat of string
-
+
val get_kind : parameter -> Z3enums.parameter_kind
val get_int : parameter -> int
val get_float : parameter -> float
@@ -537,22 +534,10 @@ end = struct
let ast_of_func_decl f = match f with FuncDecl(x) -> x
let create_ndr ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) =
- let res = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.inc_ref ;
- dec_ref = Z3native.dec_ref } in
- (z3obj_sno res ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ;
- (z3obj_create res) ;
- FuncDecl(res)
+ func_decl_of_ptr ctx (Z3native.mk_func_decl (context_gno ctx) (Symbol.gno name) (List.length domain) (Sort.sort_lton domain) (Sort.gno range))
let create_pdr ( ctx : context) ( prefix : string ) ( domain : Sort.sort list ) ( range : Sort.sort ) =
- let res = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.inc_ref ;
- dec_ref = Z3native.dec_ref } in
- (z3obj_sno res ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (Sort.sort_lton domain) (Sort.gno range))) ;
- (z3obj_create res) ;
- FuncDecl(res)
+ func_decl_of_ptr ctx (Z3native.mk_fresh_func_decl (context_gno ctx) prefix (List.length domain) (Sort.sort_lton domain) (Sort.gno range))
let gc ( x : func_decl ) = match x with FuncDecl(a) -> (z3obj_gc a)
let gnc ( x : func_decl ) = match x with FuncDecl(a) -> (z3obj_gnc a)
@@ -568,51 +553,51 @@ end = struct
| P_Ast of AST.ast
| P_Fdl of func_decl
| P_Rat of string
-
+
let get_kind ( x : parameter ) =
(match x with
- | P_Int(_) -> PARAMETER_INT
- | P_Dbl(_) -> PARAMETER_DOUBLE
- | P_Sym(_) -> PARAMETER_SYMBOL
- | P_Srt(_) -> PARAMETER_SORT
- | P_Ast(_) -> PARAMETER_AST
- | P_Fdl(_) -> PARAMETER_FUNC_DECL
- | P_Rat(_) -> PARAMETER_RATIONAL)
-
+ | P_Int(_) -> PARAMETER_INT
+ | P_Dbl(_) -> PARAMETER_DOUBLE
+ | P_Sym(_) -> PARAMETER_SYMBOL
+ | P_Srt(_) -> PARAMETER_SORT
+ | P_Ast(_) -> PARAMETER_AST
+ | P_Fdl(_) -> PARAMETER_FUNC_DECL
+ | P_Rat(_) -> PARAMETER_RATIONAL)
+
let get_int ( x : parameter ) =
match x with
- | P_Int(x) -> x
- | _ -> raise (Z3native.Exception "parameter is not an int")
-
+ | P_Int(x) -> x
+ | _ -> raise (Z3native.Exception "parameter is not an int")
+
let get_float ( x : parameter ) =
match x with
- | P_Dbl(x) -> x
- | _ -> raise (Z3native.Exception "parameter is not a float")
+ | P_Dbl(x) -> x
+ | _ -> raise (Z3native.Exception "parameter is not a float")
let get_symbol ( x : parameter ) =
match x with
- | P_Sym(x) -> x
- | _ -> raise (Z3native.Exception "parameter is not a symbol")
-
+ | P_Sym(x) -> x
+ | _ -> raise (Z3native.Exception "parameter is not a symbol")
+
let get_sort ( x : parameter ) =
match x with
- | P_Srt(x) -> x
- | _ -> raise (Z3native.Exception "parameter is not a sort")
+ | P_Srt(x) -> x
+ | _ -> raise (Z3native.Exception "parameter is not a sort")
let get_ast ( x : parameter ) =
match x with
- | P_Ast(x) -> x
- | _ -> raise (Z3native.Exception "parameter is not an ast")
+ | P_Ast(x) -> x
+ | _ -> raise (Z3native.Exception "parameter is not an ast")
let get_func_decl ( x : parameter ) =
match x with
- | P_Fdl(x) -> x
- | _ -> raise (Z3native.Exception "parameter is not a func_decl")
+ | P_Fdl(x) -> x
+ | _ -> raise (Z3native.Exception "parameter is not a func_decl")
let get_rational ( x : parameter ) =
match x with
- | P_Rat(x) -> x
- | _ -> raise (Z3native.Exception "parameter is not a rational string")
+ | P_Rat(x) -> x
+ | _ -> raise (Z3native.Exception "parameter is not a rational string")
end
let mk_func_decl ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort list ) ( range : Sort.sort ) =
@@ -710,19 +695,19 @@ end = struct
let param_descrs_of_ptr ( ctx : context ) ( no : Z3native.ptr ) =
let res : param_descrs = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.param_descrs_inc_ref ;
- dec_ref = Z3native.param_descrs_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.param_descrs_inc_ref ;
+ dec_ref = Z3native.param_descrs_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
-
+
let validate ( x : param_descrs ) ( p : params ) =
Z3native.params_validate (z3obj_gnc x) (z3obj_gno p) (z3obj_gno x)
-
+
let get_kind ( x : param_descrs ) ( name : Symbol.symbol ) =
(param_kind_of_int (Z3native.param_descrs_get_kind (z3obj_gnc x) (z3obj_gno x) (Symbol.gno name)))
-
+
let get_names ( x : param_descrs ) =
let n = Z3native.param_descrs_size (z3obj_gnc x) (z3obj_gno x) in
let f i = Symbol.create (z3obj_gc x) (Z3native.param_descrs_get_name (z3obj_gnc x) (z3obj_gno x) i) in
@@ -746,9 +731,9 @@ end = struct
let mk_params ( ctx : context ) =
let res : params = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.params_inc_ref ;
- dec_ref = Z3native.params_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.params_inc_ref ;
+ dec_ref = Z3native.params_dec_ref } in
(z3obj_sno res ctx (Z3native.mk_params (context_gno ctx))) ;
(z3obj_create res) ;
res
@@ -807,32 +792,30 @@ end = struct
let gno e = match e with Expr(a) -> (z3obj_gno a)
let expr_of_ptr : context -> Z3native.ptr -> expr = fun ctx no ->
+ let e = z3_native_object_of_ast_ptr ctx no in
if ast_kind_of_int (Z3native.get_ast_kind (context_gno ctx) no) == QUANTIFIER_AST then
- Expr(z3_native_object_of_ast_ptr ctx no)
+ Expr(e)
else
let s = Z3native.get_sort (context_gno ctx) no in
let sk = (sort_kind_of_int (Z3native.get_sort_kind (context_gno ctx) s)) in
if (Z3native.is_algebraic_number (context_gno ctx) no) then
- Expr(z3_native_object_of_ast_ptr ctx no)
- else
- if (Z3native.is_numeral_ast (context_gno ctx) no) then
- match sk with
- | REAL_SORT
- | BOOL_SORT
- | ARRAY_SORT
- | BV_SORT
- | ROUNDING_MODE_SORT
- | RELATION_SORT
- | UNINTERPRETED_SORT
- | FLOATING_POINT_SORT
- | INT_SORT
- | DATATYPE_SORT
- | FINITE_DOMAIN_SORT ->
- Expr(z3_native_object_of_ast_ptr ctx no)
- | _ ->
- raise (Z3native.Exception "Unsupported numeral object")
- else
- Expr(z3_native_object_of_ast_ptr ctx no)
+ Expr(e)
+ else if (Z3native.is_numeral_ast (context_gno ctx) no) then
+ match sk with
+ | REAL_SORT
+ | BOOL_SORT
+ | ARRAY_SORT
+ | BV_SORT
+ | ROUNDING_MODE_SORT
+ | RELATION_SORT
+ | UNINTERPRETED_SORT
+ | FLOATING_POINT_SORT
+ | INT_SORT
+ | DATATYPE_SORT
+ | FINITE_DOMAIN_SORT -> Expr(e)
+ | _ -> raise (Z3native.Exception "Unsupported numeral object")
+ else
+ Expr(e)
let expr_of_ast a =
let q = (Z3enums.ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc a) (z3obj_gno a))) in
@@ -852,6 +835,13 @@ end = struct
let o = Z3native.mk_app (context_gno ctx) (AST.ptr_of_ast fa) (List.length args) (expr_lton args) in
expr_of_ptr ctx o
+ let apply1 ctx f t = expr_of_ptr ctx (f (context_gno ctx) (gno t)) in
+
+ let apply2 ctx f t1 t2 = expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2)) in
+
+ let apply3 ctx f t1 t2 t3 = expr_of_ptr ctx (f (context_gno ctx) (gno t1) (gno t2) (gno t3)) in
+
+
let simplify ( x : expr ) ( p : Params.params option ) = match p with
| None -> expr_of_ptr (Expr.gc x) (Z3native.simplify (gnc x) (gno x))
| Some pp -> expr_of_ptr (Expr.gc x) (Z3native.simplify_ex (gnc x) (gno x) (z3obj_gno pp))
@@ -866,21 +856,21 @@ end = struct
let get_num_args ( x : expr ) = Z3native.get_app_num_args (gnc x) (gno x)
let get_args ( x : expr ) = let n = (get_num_args x) in
- let f i = expr_of_ptr (Expr.gc x) (Z3native.get_app_arg (gnc x) (gno x) i) in
- mk_list f n
-
+ let f i = expr_of_ptr (Expr.gc x) (Z3native.get_app_arg (gnc x) (gno x) i) in
+ mk_list f n
+
let update ( x : expr ) ( args : expr list ) =
if ((AST.is_app (ast_of_expr x)) && (List.length args <> (get_num_args x))) then
raise (Z3native.Exception "Number of arguments does not match")
else
- expr_of_ptr (Expr.gc x) (Z3native.update_term (gnc x) (gno x) (List.length args) (expr_lton args))
-
+ expr_of_ptr (Expr.gc x) (Z3native.update_term (gnc x) (gno x) (List.length args) (expr_lton args))
+
let substitute ( x : expr ) from to_ =
if (List.length from) <> (List.length to_) then
raise (Z3native.Exception "Argument sizes do not match")
else
- expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_))
-
+ expr_of_ptr (Expr.gc x) (Z3native.substitute (gnc x) (gno x) (List.length from) (expr_lton from) (expr_lton to_))
+
let substitute_one ( x : expr ) from to_ =
substitute ( x : expr ) [ from ] [ to_ ]
@@ -891,7 +881,7 @@ end = struct
if (Expr.gc x) == to_ctx then
x
else
- expr_of_ptr to_ctx (Z3native.translate (gnc x) (gno x) (context_gno to_ctx))
+ expr_of_ptr to_ctx (Z3native.translate (gnc x) (gno x) (context_gno to_ctx))
let to_string ( x : expr ) = Z3native.ast_to_string (gnc x) (gno x)
@@ -952,34 +942,33 @@ struct
let mk_val ( ctx : context ) ( value : bool ) =
if value then mk_true ctx else mk_false ctx
- let mk_not ( ctx : context ) ( a : expr ) =
- expr_of_ptr ctx (Z3native.mk_not (context_gno ctx) (gno a))
+ let mk_not ( ctx : context ) ( a : expr ) = apply1 ctx Z3native.mk_not a
- let mk_ite ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( t3 : expr ) =
- expr_of_ptr ctx (Z3native.mk_ite (context_gno ctx) (gno t1) (gno t2) (gno t3))
+ let mk_ite ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( t3 : expr ) =
+ apply3 ctx Z3native.mk_ite t1 t2 t3
let mk_iff ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- expr_of_ptr ctx (Z3native.mk_iff (context_gno ctx) (gno t1) (gno t2))
+ apply2 ctx Z3native.mk_iff t1 t2
let mk_implies ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- expr_of_ptr ctx (Z3native.mk_implies (context_gno ctx) (gno t1) (gno t2))
+ apply2 ctx Z3native.mk_implies t1 t2
let mk_xor ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- expr_of_ptr ctx (Z3native.mk_xor (context_gno ctx) (gno t1) (gno t2))
+ apply2 ctx Z3native.mk_xor t1 t2
let mk_and ( ctx : context ) ( args : expr list ) =
let f x = (Expr.gno (x)) in
- expr_of_ptr ctx (Z3native.mk_and (context_gno ctx) (List.length args) (Array.of_list (List.map f args)))
+ expr_of_ptr ctx (Z3native.mk_and (context_gno ctx) (List.length args) (Array.of_list (List.map f args)))
let mk_or ( ctx : context ) ( args : expr list ) =
let f x = (Expr.gno (x)) in
- expr_of_ptr ctx (Z3native.mk_or (context_gno ctx) (List.length args) (Array.of_list(List.map f args)))
+ expr_of_ptr ctx (Z3native.mk_or (context_gno ctx) (List.length args) (Array.of_list(List.map f args)))
let mk_eq ( ctx : context ) ( x : expr ) ( y : expr ) =
- expr_of_ptr ctx (Z3native.mk_eq (context_gno ctx) (Expr.gno x) (Expr.gno y))
+ apply2 ctx Z3native.mk_eq x y
let mk_distinct ( ctx : context ) ( args : expr list ) =
- expr_of_ptr ctx (Z3native.mk_distinct (context_gno ctx) (List.length args) (expr_lton args))
+ expr_of_ptr ctx (Z3native.mk_distinct (context_gno ctx) (List.length args) (expr_lton args))
let get_bool_value ( x : expr ) = lbool_of_int (Z3native.get_bool_value (gnc x) (gno x))
@@ -1012,10 +1001,10 @@ struct
match e with Expr.Expr(a) ->
let q = (Z3enums.ast_kind_of_int (Z3native.get_ast_kind (z3obj_gnc a) (z3obj_gno a))) in
if (q != Z3enums.QUANTIFIER_AST) then
- raise (Z3native.Exception "Invalid coercion")
+ raise (Z3native.Exception "Invalid coercion")
else
- Quantifier(e)
-
+ Quantifier(e)
+
let gc ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gc e)
let gnc ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gnc e)
let gno ( x : quantifier ) = match (x) with Quantifier(e) -> (Expr.gno e)
@@ -1023,25 +1012,25 @@ struct
module Pattern =
struct
type pattern = Pattern of AST.ast
-
+
let ast_of_pattern e = match e with Pattern(x) -> x
let pattern_of_ast a =
(* CMW: Unchecked ok? *)
Pattern(a)
-
+
let gc ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gc a)
let gnc ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gnc a)
let gno ( x : pattern ) = match (x) with Pattern(a) -> (z3obj_gno a)
let get_num_terms ( x : pattern ) =
- Z3native.get_pattern_num_terms (gnc x) (gno x)
+ Z3native.get_pattern_num_terms (gnc x) (gno x)
let get_terms ( x : pattern ) =
let n = (get_num_terms x) in
let f i = (expr_of_ptr (gc x) (Z3native.get_pattern (gnc x) (gno x) i)) in
mk_list f n
-
+
let to_string ( x : pattern ) = Z3native.pattern_to_string (gnc x) (gno x)
end
@@ -1085,10 +1074,10 @@ struct
mk_list f n
let get_body ( x : quantifier ) =
- expr_of_ptr (gc x) (Z3native.get_quantifier_body (gnc x) (gno x))
+ apply1 (gc x) Z3native.get_quantifier_body x
let mk_bound ( ctx : context ) ( index : int ) ( ty : Sort.sort ) =
- expr_of_ptr ctx (Z3native.mk_bound (context_gno ctx) index (Sort.gno ty))
+ expr_of_ptr ctx (Z3native.mk_bound (context_gno ctx) index (Sort.gno ty))
let mk_pattern ( ctx : context ) ( terms : expr list ) =
if (List.length terms) == 0 then
@@ -1101,76 +1090,76 @@ struct
raise (Z3native.Exception "Number of sorts does not match number of names")
else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then
Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) true
- (match weight with | None -> 1 | Some(x) -> x)
- (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
- (List.length sorts) (Sort.sort_lton sorts)
- (Symbol.symbol_lton names)
- (Expr.gno body)))
+ (match weight with | None -> 1 | Some(x) -> x)
+ (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
+ (List.length sorts) (Sort.sort_lton sorts)
+ (Symbol.symbol_lton names)
+ (Expr.gno body)))
else
Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_ex (context_gno ctx) true
- (match weight with | None -> 1 | Some(x) -> x)
- (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
- (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
- (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
- (List.length nopatterns) (expr_lton nopatterns)
- (List.length sorts) (Sort.sort_lton sorts)
- (Symbol.symbol_lton names)
- (Expr.gno body)))
-
+ (match weight with | None -> 1 | Some(x) -> x)
+ (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
+ (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
+ (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
+ (List.length nopatterns) (expr_lton nopatterns)
+ (List.length sorts) (Sort.sort_lton sorts)
+ (Symbol.symbol_lton names)
+ (Expr.gno body)))
+
let mk_forall_const ( ctx : context ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then
Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const (context_gno ctx) true
- (match weight with | None -> 1 | Some(x) -> x)
- (List.length bound_constants) (expr_lton bound_constants)
- (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
- (Expr.gno body)))
+ (match weight with | None -> 1 | Some(x) -> x)
+ (List.length bound_constants) (expr_lton bound_constants)
+ (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
+ (Expr.gno body)))
else
Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const_ex (context_gno ctx) true
- (match weight with | None -> 1 | Some(x) -> x)
- (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
- (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
- (List.length bound_constants) (expr_lton bound_constants)
- (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
- (List.length nopatterns) (expr_lton nopatterns)
- (Expr.gno body)))
+ (match weight with | None -> 1 | Some(x) -> x)
+ (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
+ (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
+ (List.length bound_constants) (expr_lton bound_constants)
+ (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
+ (List.length nopatterns) (expr_lton nopatterns)
+ (Expr.gno body)))
let mk_exists ( ctx : context ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
if (List.length sorts) != (List.length names) then
raise (Z3native.Exception "Number of sorts does not match number of names")
else if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then
Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier (context_gno ctx) false
- (match weight with | None -> 1 | Some(x) -> x)
- (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
- (List.length sorts) (Sort.sort_lton sorts)
- (Symbol.symbol_lton names)
- (Expr.gno body)))
+ (match weight with | None -> 1 | Some(x) -> x)
+ (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
+ (List.length sorts) (Sort.sort_lton sorts)
+ (Symbol.symbol_lton names)
+ (Expr.gno body)))
else
Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_ex (context_gno ctx) false
- (match weight with | None -> 1 | Some(x) -> x)
- (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
- (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
- (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
- (List.length nopatterns) (expr_lton nopatterns)
- (List.length sorts) (Sort.sort_lton sorts)
- (Symbol.symbol_lton names)
- (Expr.gno body)))
-
+ (match weight with | None -> 1 | Some(x) -> x)
+ (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
+ (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
+ (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
+ (List.length nopatterns) (expr_lton nopatterns)
+ (List.length sorts) (Sort.sort_lton sorts)
+ (Symbol.symbol_lton names)
+ (Expr.gno body)))
+
let mk_exists_const ( ctx : context ) ( bound_constants : expr list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
if ((List.length nopatterns) == 0 && quantifier_id == None && skolem_id == None) then
Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const (context_gno ctx) false
- (match weight with | None -> 1 | Some(x) -> x)
- (List.length bound_constants) (expr_lton bound_constants)
- (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
- (Expr.gno body)))
+ (match weight with | None -> 1 | Some(x) -> x)
+ (List.length bound_constants) (expr_lton bound_constants)
+ (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
+ (Expr.gno body)))
else
Quantifier(expr_of_ptr ctx (Z3native.mk_quantifier_const_ex (context_gno ctx) false
- (match weight with | None -> 1 | Some(x) -> x)
- (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
- (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
- (List.length bound_constants) (expr_lton bound_constants)
- (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
- (List.length nopatterns) (expr_lton nopatterns)
- (Expr.gno body)))
+ (match weight with | None -> 1 | Some(x) -> x)
+ (match quantifier_id with | None -> null | Some(x) -> (Symbol.gno x))
+ (match skolem_id with | None -> null | Some(x) -> (Symbol.gno x))
+ (List.length bound_constants) (expr_lton bound_constants)
+ (List.length patterns) (let f x = (AST.ptr_of_ast (Pattern.ast_of_pattern x)) in (Array.of_list (List.map f patterns)))
+ (List.length nopatterns) (expr_lton nopatterns)
+ (Expr.gno body)))
let mk_quantifier ( ctx : context ) ( universal : bool ) ( sorts : Sort.sort list ) ( names : Symbol.symbol list ) ( body : expr ) ( weight : int option ) ( patterns : Pattern.pattern list ) ( nopatterns : expr list ) ( quantifier_id : Symbol.symbol option ) ( skolem_id : Symbol.symbol option ) =
if (universal) then
@@ -1209,27 +1198,27 @@ struct
let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( domain : Sort.sort ) ( range : Sort.sort ) =
(Expr.mk_const ctx name (mk_sort ctx domain range))
- let mk_const_s ( ctx : context ) ( name : string ) ( domain : Sort.sort ) ( range : Sort.sort ) =
+ let mk_const_s ( ctx : context ) ( name : string ) ( domain : Sort.sort ) ( range : Sort.sort ) =
mk_const ctx (Symbol.mk_string ctx name) domain range
let mk_select ( ctx : context ) ( a : expr ) ( i : expr ) =
- expr_of_ptr ctx (Z3native.mk_select (context_gno ctx) (Expr.gno a) (Expr.gno i))
+ apply2 ctx Z3native.mk_select a i
let mk_store ( ctx : context ) ( a : expr ) ( i : expr ) ( v : expr ) =
- expr_of_ptr ctx (Z3native.mk_store (context_gno ctx) (Expr.gno a) (Expr.gno i) (Expr.gno v))
+ apply3 ctx Z3native.mk_store a i v
let mk_const_array ( ctx : context ) ( domain : Sort.sort ) ( v : expr ) =
- expr_of_ptr ctx (Z3native.mk_const_array (context_gno ctx) (Sort.gno domain) (Expr.gno v))
+ expr_of_ptr ctx (Z3native.mk_const_array (context_gno ctx) (Sort.gno domain) (Expr.gno v))
let mk_map ( ctx : context ) ( f : func_decl ) ( args : expr list ) =
let m x = (Expr.gno x) in
expr_of_ptr ctx (Z3native.mk_map (context_gno ctx) (FuncDecl.gno f) (List.length args) (Array.of_list (List.map m args)))
let mk_term_array ( ctx : context ) ( arg : expr ) =
- expr_of_ptr ctx (Z3native.mk_array_default (context_gno ctx) (Expr.gno arg))
+ apply1 ctx Z3native.mk_array_default arg
let mk_array_ext ( ctx : context) ( arg1 : expr ) ( arg2 : expr ) =
- expr_of_ptr ctx (Z3native.mk_array_ext (context_gno ctx) (Expr.gno arg1) (Expr.gno arg2))
+ apply2 ctx Z3native.mk_array_ext arg1 arg2
end
@@ -1252,13 +1241,14 @@ struct
expr_of_ptr ctx (Z3native.mk_full_set (context_gno ctx) (Sort.gno domain))
let mk_set_add ( ctx : context ) ( set : expr ) ( element : expr ) =
- expr_of_ptr ctx (Z3native.mk_set_add (context_gno ctx) (Expr.gno set) (Expr.gno element))
+ apply2 ctx Z3native.mk_set_add set element
let mk_del ( ctx : context ) ( set : expr ) ( element : expr ) =
- expr_of_ptr ctx (Z3native.mk_set_del (context_gno ctx) (Expr.gno set) (Expr.gno element))
+ apply2 Z3native.mk_set_del set element
let mk_union ( ctx : context ) ( args : expr list ) =
- expr_of_ptr ctx (Z3native.mk_set_union (context_gno ctx) (List.length args) (expr_lton args))
+ let r = expr_of_ptr ctx (Z3native.mk_set_union (context_gno ctx) (List.length args) (expr_lton args)) in
+ r
let mk_intersection ( ctx : context ) ( args : expr list ) =
expr_of_ptr ctx (Z3native.mk_set_intersect (context_gno ctx) (List.length args) (expr_lton args))
@@ -1305,7 +1295,7 @@ struct
let is_relation ( x : expr ) =
let nc = (Expr.gnc x) in
((Z3native.is_app (Expr.gnc x) (Expr.gno x)) &&
- (sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc (Expr.gno x))) == RELATION_SORT))
+ (sort_kind_of_int (Z3native.get_sort_kind nc (Z3native.get_sort nc (Expr.gno x))) == RELATION_SORT))
let is_store ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_STORE)
let is_empty ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_RA_EMPTY)
@@ -1335,7 +1325,7 @@ struct
module Constructor =
struct
type constructor = z3_native_object
-
+
module FieldNumTable = Hashtbl.Make(struct
type t = AST.ast
let equal x y = AST.compare x y = 0
@@ -1347,28 +1337,28 @@ struct
let create ( ctx : context ) ( name : Symbol.symbol ) ( recognizer : Symbol.symbol ) ( field_names : Symbol.symbol list ) ( sorts : Sort.sort option list ) ( sort_refs : int list ) =
let n = (List.length field_names) in
if n != (List.length sorts) then
- raise (Z3native.Exception "Number of field names does not match number of sorts")
+ raise (Z3native.Exception "Number of field names does not match number of sorts")
else
- if n != (List.length sort_refs) then
- raise (Z3native.Exception "Number of field names does not match number of sort refs")
- else
+ if n != (List.length sort_refs) then
+ raise (Z3native.Exception "Number of field names does not match number of sort refs")
+ else
let ptr = (Z3native.mk_constructor (context_gno ctx) (Symbol.gno name)
- (Symbol.gno recognizer)
- n
- (Symbol.symbol_lton field_names)
- (Sort.sort_option_lton sorts)
- (Array.of_list sort_refs)) in
- let no : constructor = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = z3obj_nil_ref ;
- dec_ref = z3obj_nil_ref} in
- (z3obj_sno no ctx ptr) ;
- (z3obj_create no) ;
- let f = fun o -> Z3native.del_constructor (z3obj_gnc o) (z3obj_gno o) in
- Gc.finalise f no ;
- FieldNumTable.add _field_nums no n ;
- no
-
+ (Symbol.gno recognizer)
+ n
+ (Symbol.symbol_lton field_names)
+ (Sort.sort_option_lton sorts)
+ (Array.of_list sort_refs)) in
+ let no : constructor = { m_ctx = ctx ;
+ m_n_obj = null ;
+ inc_ref = z3obj_nil_ref ;
+ dec_ref = z3obj_nil_ref} in
+ (z3obj_sno no ctx ptr) ;
+ (z3obj_create no) ;
+ let f = fun o -> Z3native.del_constructor (z3obj_gnc o) (z3obj_gno o) in
+ Gc.finalise f no ;
+ FieldNumTable.add _field_nums no n ;
+ no
+
let get_num_fields ( x : constructor ) = FieldNumTable.find _field_nums x
let get_constructor_decl ( x : constructor ) =
@@ -1377,13 +1367,13 @@ struct
let get_tester_decl ( x : constructor ) =
let (_, b, _) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in
- func_decl_of_ptr (z3obj_gc x) b
+ func_decl_of_ptr (z3obj_gc x) b
let get_accessor_decls ( x : constructor ) =
let (_, _, c) = (Z3native.query_constructor (z3obj_gnc x) (z3obj_gno x) (get_num_fields x)) in
let f i = func_decl_of_ptr (z3obj_gc x) (Array.get c i) in
mk_list f (Array.length c)
-
+
end
module ConstructorList =
@@ -1392,9 +1382,9 @@ struct
let create ( ctx : context ) ( c : Constructor.constructor list ) =
let res : constructor_list = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = z3obj_nil_ref ;
- dec_ref = z3obj_nil_ref} in
+ m_n_obj = null ;
+ inc_ref = z3obj_nil_ref ;
+ dec_ref = z3obj_nil_ref} in
let f x =(z3obj_gno x) in
(z3obj_sno res ctx (Z3native.mk_constructor_list (context_gno ctx) (List.length c) (Array.of_list (List.map f c)))) ;
(z3obj_create res) ;
@@ -1429,8 +1419,8 @@ struct
let mk_sorts_s ( ctx : context ) ( names : string list ) ( c : Constructor.constructor list list ) =
mk_sorts ctx
(
- let f e = (Symbol.mk_string ctx e) in
- List.map f names
+ let f e = (Symbol.mk_string ctx e) in
+ List.map f names
)
c
@@ -1600,27 +1590,27 @@ struct
let get_big_int ( x : expr ) =
if (is_int_numeral x) then
- let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in
- (Big_int.big_int_of_string s)
+ let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in
+ (Big_int.big_int_of_string s)
else raise (Z3native.Exception "Conversion failed.")
-
+
let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
let mk_const ( ctx : context ) ( name : Symbol.symbol ) =
Expr.mk_const ctx name (mk_sort ctx)
-
+
let mk_const_s ( ctx : context ) ( name : string ) =
mk_const ctx (Symbol.mk_string ctx name)
-
+
let mk_mod ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
expr_of_ptr ctx (Z3native.mk_mod (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
-
+
let mk_rem ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
expr_of_ptr ctx (Z3native.mk_rem (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
let mk_numeral_s ( ctx : context ) ( v : string ) =
expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx)))
-
+
let mk_numeral_i ( ctx : context ) ( v : int ) =
expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno (mk_sort ctx)))
@@ -1634,60 +1624,60 @@ struct
module Real =
struct
let mk_sort ( ctx : context ) =
- Sort.sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx))
+ Sort.sort_of_ptr ctx (Z3native.mk_real_sort (context_gno ctx))
let get_numerator ( x : expr ) =
expr_of_ptr (Expr.gc x) (Z3native.get_numerator (Expr.gnc x) (Expr.gno x))
-
+
let get_denominator ( x : expr ) =
expr_of_ptr (Expr.gc x) (Z3native.get_denominator (Expr.gnc x) (Expr.gno x))
-
+
let get_ratio ( x : expr ) =
if (is_rat_numeral x) then
- let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in
- (Ratio.ratio_of_string s)
+ let s = (Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)) in
+ (Ratio.ratio_of_string s)
else raise (Z3native.Exception "Conversion failed.")
let to_decimal_string ( x : expr ) ( precision : int ) =
Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision
-
+
let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
let mk_const ( ctx : context ) ( name : Symbol.symbol ) =
Expr.mk_const ctx name (mk_sort ctx)
-
+
let mk_const_s ( ctx : context ) ( name : string ) =
mk_const ctx (Symbol.mk_string ctx name)
let mk_numeral_nd ( ctx : context ) ( num : int ) ( den : int ) =
if (den == 0) then
- raise (Z3native.Exception "Denominator is zero")
+ raise (Z3native.Exception "Denominator is zero")
else
- expr_of_ptr ctx (Z3native.mk_real (context_gno ctx) num den)
-
+ expr_of_ptr ctx (Z3native.mk_real (context_gno ctx) num den)
+
let mk_numeral_s ( ctx : context ) ( v : string ) =
expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx)))
-
+
let mk_numeral_i ( ctx : context ) ( v : int ) =
expr_of_ptr ctx (Z3native.mk_int (context_gno ctx) v (Sort.gno (mk_sort ctx)))
-
+
let mk_is_integer ( ctx : context ) ( t : expr ) =
(expr_of_ptr ctx (Z3native.mk_is_int (context_gno ctx) (Expr.gno t)))
-
+
let mk_real2int ( ctx : context ) ( t : expr ) =
(expr_of_ptr ctx (Z3native.mk_real2int (context_gno ctx) (Expr.gno t)))
module AlgebraicNumber =
struct
let to_upper ( x : expr ) ( precision : int ) =
- expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision)
-
+ expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_upper (Expr.gnc x) (Expr.gno x) precision)
+
let to_lower ( x : expr ) precision =
- expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision)
-
+ expr_of_ptr (Expr.gc x) (Z3native.get_algebraic_number_lower (Expr.gnc x) (Expr.gno x) precision)
+
let to_decimal_string ( x : expr ) ( precision : int ) =
- Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision
-
+ Z3native.get_numeral_decimal_string (Expr.gnc x) (Expr.gno x) precision
+
let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
end
end
@@ -1843,9 +1833,9 @@ struct
let mk_sge ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
(expr_of_ptr ctx (Z3native.mk_bvsge (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
let mk_ugt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- (expr_of_ptr ctx (Z3native.mk_bvugt (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
+ (expr_of_ptr ctx (Z3native.mk_bvugt (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
let mk_sgt ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- (expr_of_ptr ctx (Z3native.mk_bvsgt (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
+ (expr_of_ptr ctx (Z3native.mk_bvsgt (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
let mk_concat ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
expr_of_ptr ctx (Z3native.mk_concat (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
let mk_extract ( ctx : context ) ( high : int ) ( low : int ) ( t : expr ) =
@@ -1857,7 +1847,7 @@ struct
let mk_repeat ( ctx : context ) ( i : int ) ( t : expr ) =
expr_of_ptr ctx (Z3native.mk_repeat (context_gno ctx) i (Expr.gno t))
let mk_shl ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- expr_of_ptr ctx (Z3native.mk_bvshl (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
+ expr_of_ptr ctx (Z3native.mk_bvshl (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
let mk_lshr ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
expr_of_ptr ctx (Z3native.mk_bvlshr (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
let mk_ashr ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
@@ -1869,15 +1859,15 @@ struct
let mk_ext_rotate_left ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
expr_of_ptr ctx (Z3native.mk_ext_rotate_left (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
let mk_ext_rotate_right ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- expr_of_ptr ctx (Z3native.mk_ext_rotate_right (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
+ expr_of_ptr ctx (Z3native.mk_ext_rotate_right (context_gno ctx) (Expr.gno t1) (Expr.gno t2))
let mk_bv2int ( ctx : context ) ( t : expr ) ( signed : bool ) =
expr_of_ptr ctx (Z3native.mk_bv2int (context_gno ctx) (Expr.gno t) signed)
let mk_add_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) =
(expr_of_ptr ctx (Z3native.mk_bvadd_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed))
let mk_add_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- (expr_of_ptr ctx (Z3native.mk_bvadd_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
+ (expr_of_ptr ctx (Z3native.mk_bvadd_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
let mk_sub_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- (expr_of_ptr ctx (Z3native.mk_bvsub_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
+ (expr_of_ptr ctx (Z3native.mk_bvsub_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
let mk_sub_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) =
(expr_of_ptr ctx (Z3native.mk_bvsub_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed))
let mk_sdiv_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
@@ -1887,7 +1877,7 @@ struct
let mk_mul_no_overflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) ( signed : bool) =
(expr_of_ptr ctx (Z3native.mk_bvmul_no_overflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2) signed))
let mk_mul_no_underflow ( ctx : context ) ( t1 : expr ) ( t2 : expr ) =
- (expr_of_ptr ctx (Z3native.mk_bvmul_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
+ (expr_of_ptr ctx (Z3native.mk_bvmul_no_underflow (context_gno ctx) (Expr.gno t1) (Expr.gno t2)))
let mk_numeral ( ctx : context ) ( v : string ) ( size : int ) =
expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno (mk_sort ctx size)))
end
@@ -1897,66 +1887,66 @@ module FloatingPoint =
struct
module RoundingMode =
struct
- let mk_sort ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx)))
- let is_fprm ( x : expr ) =
- (Sort.get_sort_kind (Expr.get_sort(x))) == ROUNDING_MODE_SORT
- let mk_round_nearest_ties_to_even ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_even (context_gno ctx)))
- let mk_rne ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_rne (context_gno ctx)))
- let mk_round_nearest_ties_to_away ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_away (context_gno ctx)))
- let mk_rna ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_rna (context_gno ctx)))
- let mk_round_toward_positive ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_positive (context_gno ctx)))
- let mk_rtp ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_rtp (context_gno ctx)))
- let mk_round_toward_negative ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_negative (context_gno ctx)))
- let mk_rtn ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_rtn (context_gno ctx)))
- let mk_round_toward_zero ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_zero (context_gno ctx)))
- let mk_rtz ( ctx : context ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_rtz (context_gno ctx)))
+ let mk_sort ( ctx : context ) =
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_rounding_mode_sort (context_gno ctx)))
+ let is_fprm ( x : expr ) =
+ (Sort.get_sort_kind (Expr.get_sort(x))) == ROUNDING_MODE_SORT
+ let mk_round_nearest_ties_to_even ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_even (context_gno ctx)))
+ let mk_rne ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_rne (context_gno ctx)))
+ let mk_round_nearest_ties_to_away ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_round_nearest_ties_to_away (context_gno ctx)))
+ let mk_rna ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_rna (context_gno ctx)))
+ let mk_round_toward_positive ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_positive (context_gno ctx)))
+ let mk_rtp ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_rtp (context_gno ctx)))
+ let mk_round_toward_negative ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_negative (context_gno ctx)))
+ let mk_rtn ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_rtn (context_gno ctx)))
+ let mk_round_toward_zero ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_round_toward_zero (context_gno ctx)))
+ let mk_rtz ( ctx : context ) =
+ (expr_of_ptr ctx (Z3native.mk_fpa_rtz (context_gno ctx)))
end
-
+
let mk_sort ( ctx : context ) ( ebits : int ) ( sbits : int ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort (context_gno ctx) ebits sbits))
let mk_sort_half ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx)))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_half (context_gno ctx)))
let mk_sort_16 ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx)))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_16 (context_gno ctx)))
let mk_sort_single ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx)))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_single (context_gno ctx)))
let mk_sort_32 ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx)))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_32 (context_gno ctx)))
let mk_sort_double ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx)))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_double (context_gno ctx)))
let mk_sort_64 ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx)))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_64 (context_gno ctx)))
let mk_sort_quadruple ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx)))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_quadruple (context_gno ctx)))
let mk_sort_128 ( ctx : context ) =
- (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx)))
+ (Sort.sort_of_ptr ctx (Z3native.mk_fpa_sort_128 (context_gno ctx)))
let mk_nan ( ctx : context ) ( s : Sort.sort ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_nan (context_gno ctx) (Sort.gno s)))
+ (expr_of_ptr ctx (Z3native.mk_fpa_nan (context_gno ctx) (Sort.gno s)))
let mk_inf ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_inf (context_gno ctx) (Sort.gno s) negative))
+ (expr_of_ptr ctx (Z3native.mk_fpa_inf (context_gno ctx) (Sort.gno s) negative))
let mk_zero ( ctx : context ) ( s : Sort.sort ) ( negative : bool ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_zero (context_gno ctx) (Sort.gno s) negative))
+ (expr_of_ptr ctx (Z3native.mk_fpa_zero (context_gno ctx) (Sort.gno s) negative))
let mk_fp ( ctx : context ) ( sign : expr ) ( exponent : expr ) ( significand : expr ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_fp (context_gno ctx) (Expr.gno sign) (Expr.gno exponent) (Expr.gno significand)))
+ (expr_of_ptr ctx (Z3native.mk_fpa_fp (context_gno ctx) (Expr.gno sign) (Expr.gno exponent) (Expr.gno significand)))
let mk_numeral_f ( ctx : context ) ( value : float ) ( s : Sort.sort ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_numeral_double (context_gno ctx) value (Sort.gno s)))
+ (expr_of_ptr ctx (Z3native.mk_fpa_numeral_double (context_gno ctx) value (Sort.gno s)))
let mk_numeral_i ( ctx : context ) ( value : int ) ( s : Sort.sort ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int (context_gno ctx) value (Sort.gno s)))
+ (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int (context_gno ctx) value (Sort.gno s)))
let mk_numeral_i_u ( ctx : context ) ( sign : bool ) ( exponent : int ) ( significand : int ) ( s : Sort.sort ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int64_uint64 (context_gno ctx) sign exponent significand (Sort.gno s)))
+ (expr_of_ptr ctx (Z3native.mk_fpa_numeral_int64_uint64 (context_gno ctx) sign exponent significand (Sort.gno s)))
let mk_numeral_s ( ctx : context ) ( v : string ) ( s : Sort.sort ) =
(expr_of_ptr ctx (Z3native.mk_numeral (context_gno ctx) v (Sort.gno s)))
@@ -1991,7 +1981,7 @@ struct
let is_to_sbv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_SBV)
let is_to_real ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_REAL)
let is_to_ieee_bv ( x : expr ) = (AST.is_app (Expr.ast_of_expr x)) && (FuncDecl.get_decl_kind (Expr.get_func_decl x) == OP_FPA_TO_IEEE_BV)
-
+
let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
let mk_const ( ctx : context ) ( name : Symbol.symbol ) ( s : Sort.sort ) =
Expr.mk_const ctx name s
@@ -2064,24 +2054,24 @@ struct
expr_of_ptr ctx (Z3native.mk_fpa_to_real (context_gno ctx) (Expr.gno t))
let get_ebits ( ctx : context ) ( s : Sort.sort ) =
- (Z3native.fpa_get_ebits (context_gno ctx) (Sort.gno s))
+ (Z3native.fpa_get_ebits (context_gno ctx) (Sort.gno s))
let get_sbits ( ctx : context ) ( s : Sort.sort ) =
- (Z3native.fpa_get_sbits (context_gno ctx) (Sort.gno s))
+ (Z3native.fpa_get_sbits (context_gno ctx) (Sort.gno s))
let get_numeral_sign ( ctx : context ) ( t : expr ) =
- (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t))
+ (Z3native.fpa_get_numeral_sign (context_gno ctx) (Expr.gno t))
let get_numeral_significand_string ( ctx : context ) ( t : expr ) =
- (Z3native.fpa_get_numeral_significand_string (context_gno ctx) (Expr.gno t))
+ (Z3native.fpa_get_numeral_significand_string (context_gno ctx) (Expr.gno t))
let get_numeral_significand_uint ( ctx : context ) ( t : expr ) =
- (Z3native.fpa_get_numeral_significand_uint64 (context_gno ctx) (Expr.gno t))
+ (Z3native.fpa_get_numeral_significand_uint64 (context_gno ctx) (Expr.gno t))
let get_numeral_exponent_string ( ctx : context ) ( t : expr ) =
- (Z3native.fpa_get_numeral_exponent_string (context_gno ctx) (Expr.gno t))
+ (Z3native.fpa_get_numeral_exponent_string (context_gno ctx) (Expr.gno t))
let get_numeral_exponent_int ( ctx : context ) ( t : expr ) =
- (Z3native.fpa_get_numeral_exponent_int64 (context_gno ctx) (Expr.gno t))
+ (Z3native.fpa_get_numeral_exponent_int64 (context_gno ctx) (Expr.gno t))
let mk_to_ieee_bv ( ctx : context ) ( t : expr ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_to_ieee_bv (context_gno ctx) (Expr.gno t)))
+ (expr_of_ptr ctx (Z3native.mk_fpa_to_ieee_bv (context_gno ctx) (Expr.gno t)))
let mk_to_fp_int_real ( ctx : context ) ( rm : expr ) ( exponent : expr ) ( significand : expr ) ( s : Sort.sort ) =
- (expr_of_ptr ctx (Z3native.mk_fpa_to_fp_int_real (context_gno ctx) (Expr.gno rm) (Expr.gno exponent) (Expr.gno significand) (Sort.gno s)))
+ (expr_of_ptr ctx (Z3native.mk_fpa_to_fp_int_real (context_gno ctx) (Expr.gno rm) (Expr.gno exponent) (Expr.gno significand) (Sort.gno s)))
let numeral_to_string ( x : expr ) = Z3native.get_numeral_string (Expr.gnc x) (Expr.gno x)
end
@@ -2137,9 +2127,9 @@ struct
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : goal = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.goal_inc_ref ;
- dec_ref = Z3native.goal_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.goal_inc_ref ;
+ dec_ref = Z3native.goal_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
@@ -2176,7 +2166,7 @@ struct
let get_formulas ( x : goal ) =
let n = get_size x in
let f i = ((expr_of_ptr (z3obj_gc x)
- (Z3native.goal_formula (z3obj_gnc x) (z3obj_gno x) i))) in
+ (Z3native.goal_formula (z3obj_gnc x) (z3obj_gno x) i))) in
mk_list f n
let get_num_exprs ( x : goal ) = Z3native.goal_num_exprs (z3obj_gnc x) (z3obj_gno x)
@@ -2200,9 +2190,9 @@ struct
Z3native.apply_result_inc_ref (z3obj_gnc x) arn ;
let sg = Z3native.apply_result_get_num_subgoals (z3obj_gnc x) arn in
let res = if sg == 0 then
- raise (Z3native.Exception "No subgoals")
+ raise (Z3native.Exception "No subgoals")
else
- Z3native.apply_result_get_subgoal (z3obj_gnc x) arn 0 in
+ Z3native.apply_result_get_subgoal (z3obj_gnc x) arn 0 in
Z3native.apply_result_dec_ref (z3obj_gnc x) arn ;
Z3native.tactic_dec_ref (z3obj_gnc x) tn ;
create (z3obj_gc x) res
@@ -2213,13 +2203,13 @@ struct
let to_string ( x : goal ) = Z3native.goal_to_string (z3obj_gnc x) (z3obj_gno x)
let as_expr ( x : goal ) =
- let n = get_size x in
- if n = 0 then
- (Boolean.mk_true (z3obj_gc x))
- else if n = 1 then
- (List.hd (get_formulas x))
- else
- (Boolean.mk_and (z3obj_gc x) (get_formulas x))
+ let n = get_size x in
+ if n = 0 then
+ (Boolean.mk_true (z3obj_gc x))
+ else if n = 1 then
+ (List.hd (get_formulas x))
+ else
+ (Boolean.mk_and (z3obj_gc x) (get_formulas x))
end
@@ -2229,9 +2219,9 @@ struct
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : model = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.model_inc_ref ;
- dec_ref = Z3native.model_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.model_inc_ref ;
+ dec_ref = Z3native.model_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
@@ -2242,40 +2232,40 @@ struct
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : func_interp = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.func_interp_inc_ref ;
- dec_ref = Z3native.func_interp_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.func_interp_inc_ref ;
+ dec_ref = Z3native.func_interp_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
-
+
module FuncEntry =
- struct
+ struct
type func_entry = z3_native_object
-
+
let create ( ctx : context ) ( no : Z3native.ptr ) =
- let res : func_entry = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.func_entry_inc_ref ;
- dec_ref = Z3native.func_entry_dec_ref } in
- (z3obj_sno res ctx no) ;
- (z3obj_create res) ;
- res
-
+ let res : func_entry = { m_ctx = ctx ;
+ m_n_obj = null ;
+ inc_ref = Z3native.func_entry_inc_ref ;
+ dec_ref = Z3native.func_entry_dec_ref } in
+ (z3obj_sno res ctx no) ;
+ (z3obj_create res) ;
+ res
+
let get_value ( x : func_entry ) =
- expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_value (z3obj_gnc x) (z3obj_gno x))
+ expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_value (z3obj_gnc x) (z3obj_gno x))
let get_num_args ( x : func_entry ) = Z3native.func_entry_get_num_args (z3obj_gnc x) (z3obj_gno x)
-
+
let get_args ( x : func_entry ) =
- let n = (get_num_args x) in
- let f i = (expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_arg (z3obj_gnc x) (z3obj_gno x) i)) in
- mk_list f n
-
+ let n = (get_num_args x) in
+ let f i = (expr_of_ptr (z3obj_gc x) (Z3native.func_entry_get_arg (z3obj_gnc x) (z3obj_gno x) i)) in
+ mk_list f n
+
let to_string ( x : func_entry ) =
- let a = (get_args x) in
- let f c p = (p ^ (Expr.to_string c) ^ ", ") in
- "[" ^ List.fold_right f a ((Expr.to_string (get_value x)) ^ "]")
+ let a = (get_args x) in
+ let f c p = (p ^ (Expr.to_string c) ^ ", ") in
+ "[" ^ List.fold_right f a ((Expr.to_string (get_value x)) ^ "]")
end
let get_num_entries ( x: func_interp ) = Z3native.func_interp_get_num_entries (z3obj_gnc x) (z3obj_gno x)
@@ -2291,14 +2281,14 @@ struct
let to_string ( x : func_interp ) =
let f c p = (
- let n = (FuncEntry.get_num_args c) in
- p ^
- let g c p = (p ^ (Expr.to_string c) ^ ", ") in
- (if n > 1 then "[" else "") ^
- (List.fold_right
- g
- (FuncEntry.get_args c)
- ((if n > 1 then "]" else "") ^ " -> " ^ (Expr.to_string (FuncEntry.get_value c)) ^ ", "))
+ let n = (FuncEntry.get_num_args c) in
+ p ^
+ let g c p = (p ^ (Expr.to_string c) ^ ", ") in
+ (if n > 1 then "[" else "") ^
+ (List.fold_right
+ g
+ (FuncEntry.get_args c)
+ ((if n > 1 then "]" else "") ^ " -> " ^ (Expr.to_string (FuncEntry.get_value c)) ^ ", "))
) in
List.fold_right f (get_entries x) ("else -> " ^ (Expr.to_string (get_else x)) ^ "]")
end
@@ -2310,9 +2300,9 @@ struct
else
let np = Z3native.model_get_const_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) in
if (Z3native.is_null np) then
- None
+ None
else
- Some (expr_of_ptr (z3obj_gc x) np)
+ Some (expr_of_ptr (z3obj_gc x) np)
let get_const_interp_e ( x : model ) ( a : expr ) = get_const_interp x (Expr.get_func_decl a)
@@ -2322,20 +2312,20 @@ struct
if (FuncDecl.get_arity f) == 0 then
let n = Z3native.model_get_const_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f) in
if (Z3native.is_null n) then
- None
+ None
else
- match sk with
- | ARRAY_SORT ->
- if not (Z3native.is_as_array (z3obj_gnc x) n) then
- raise (Z3native.Exception "Argument was not an array constant")
- else
- let fd = Z3native.get_as_array_func_decl (z3obj_gnc x) n in
+ match sk with
+ | ARRAY_SORT ->
+ if not (Z3native.is_as_array (z3obj_gnc x) n) then
+ raise (Z3native.Exception "Argument was not an array constant")
+ else
+ let fd = Z3native.get_as_array_func_decl (z3obj_gnc x) n in
get_func_interp x (func_decl_of_ptr (z3obj_gc x) fd)
- | _ -> raise (Z3native.Exception "Constant functions do not have a function interpretation; use ConstInterp");
+ | _ -> raise (Z3native.Exception "Constant functions do not have a function interpretation; use ConstInterp");
else
let n = (Z3native.model_get_func_interp (z3obj_gnc x) (z3obj_gno x) (FuncDecl.gno f)) in
if (Z3native.is_null n) then None else Some (FuncInterp.create (z3obj_gc x) n)
-
+
(** The number of constants that have an interpretation in the model. *)
let get_num_consts ( x : model ) = Z3native.model_get_num_consts (z3obj_gnc x) (z3obj_gno x)
@@ -2389,9 +2379,9 @@ struct
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : probe = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.probe_inc_ref ;
- dec_ref = Z3native.probe_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.probe_inc_ref ;
+ dec_ref = Z3native.probe_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
@@ -2449,9 +2439,9 @@ struct
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : tactic = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.tactic_inc_ref ;
- dec_ref = Z3native.tactic_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.tactic_inc_ref ;
+ dec_ref = Z3native.tactic_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
@@ -2459,30 +2449,30 @@ struct
module ApplyResult =
struct
type apply_result = z3_native_object
-
+
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : apply_result = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.apply_result_inc_ref ;
- dec_ref = Z3native.apply_result_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.apply_result_inc_ref ;
+ dec_ref = Z3native.apply_result_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
-
+
let get_num_subgoals ( x : apply_result ) =
Z3native.apply_result_get_num_subgoals (z3obj_gnc x) (z3obj_gno x)
-
+
let get_subgoals ( x : apply_result ) =
let n = (get_num_subgoals x) in
let f i = Goal.create (z3obj_gc x) (Z3native.apply_result_get_subgoal (z3obj_gnc x) (z3obj_gno x) i) in
mk_list f n
-
+
let get_subgoal ( x : apply_result ) ( i : int ) =
Goal.create (z3obj_gc x) (Z3native.apply_result_get_subgoal (z3obj_gnc x) (z3obj_gno x) i)
-
+
let convert_model ( x : apply_result ) ( i : int ) ( m : Model.model ) =
Model.create (z3obj_gc x) (Z3native.apply_result_convert_model (z3obj_gnc x) (z3obj_gno x) i (z3obj_gno m))
-
+
let to_string ( x : apply_result ) = Z3native.apply_result_to_string (z3obj_gnc x) (z3obj_gno x)
end
@@ -2515,10 +2505,10 @@ struct
| Some(x) -> (Some (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno c) x))) in
match (List.fold_left f None ts) with
| None ->
- create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2))
+ create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2))
| Some(x) ->
- let o = (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t2) x) in
- create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) o)
+ let o = (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t2) x) in
+ create ctx (Z3native.tactic_and_then (context_gno ctx) (z3obj_gno t1) o)
let or_else ( ctx : context ) ( t1 : tactic ) ( t2 : tactic ) =
create ctx (Z3native.tactic_or_else (context_gno ctx) (z3obj_gno t1) (z3obj_gno t2))
@@ -2566,14 +2556,14 @@ end
module Statistics =
-struct
+struct
type statistics = z3_native_object
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : statistics = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.stats_inc_ref ;
- dec_ref = Z3native.stats_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.stats_inc_ref ;
+ dec_ref = Z3native.stats_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
@@ -2582,44 +2572,44 @@ struct
module Entry =
struct
type statistics_entry = {
- mutable m_key : string;
- mutable m_is_int : bool ;
- mutable m_is_float : bool ;
- mutable m_int : int ;
- mutable m_float : float }
-
+ mutable m_key : string;
+ mutable m_is_int : bool ;
+ mutable m_is_float : bool ;
+ mutable m_int : int ;
+ mutable m_float : float }
+
let create_si k v =
- let res : statistics_entry = {
- m_key = k ;
- m_is_int = true ;
- m_is_float = false ;
- m_int = v ;
- m_float = 0.0
- } in
- res
+ let res : statistics_entry = {
+ m_key = k ;
+ m_is_int = true ;
+ m_is_float = false ;
+ m_int = v ;
+ m_float = 0.0
+ } in
+ res
let create_sd k v =
- let res : statistics_entry = {
- m_key = k ;
- m_is_int = false ;
- m_is_float = true ;
- m_int = 0 ;
- m_float = v
- } in
- res
-
+ let res : statistics_entry = {
+ m_key = k ;
+ m_is_int = false ;
+ m_is_float = true ;
+ m_int = 0 ;
+ m_float = v
+ } in
+ res
+
let get_key (x : statistics_entry) = x.m_key
- let get_int (x : statistics_entry) = x.m_int
+ let get_int (x : statistics_entry) = x.m_int
let get_float (x : statistics_entry) = x.m_float
let is_int (x : statistics_entry) = x.m_is_int
let is_float (x : statistics_entry) = x.m_is_float
let to_string_value (x : statistics_entry) =
- if (is_int x) then
- string_of_int (get_int x)
- else if (is_float x) then
- string_of_float (get_float x)
- else
+ if (is_int x) then
+ string_of_int (get_int x)
+ else if (is_float x) then
+ string_of_float (get_float x)
+ else
raise (Z3native.Exception "Unknown statistical entry type")
let to_string ( x : statistics_entry ) = (get_key x) ^ ": " ^ (to_string_value x)
end
@@ -2631,11 +2621,11 @@ struct
let get_entries ( x : statistics ) =
let n = (get_size x ) in
let f i = (
- let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in
- if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then
- (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i))
- else
- (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i))
+ let k = Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i in
+ if (Z3native.stats_is_uint (z3obj_gnc x) (z3obj_gno x) i) then
+ (Entry.create_si k (Z3native.stats_get_uint_value (z3obj_gnc x) (z3obj_gno x) i))
+ else
+ (Entry.create_sd k (Z3native.stats_get_double_value (z3obj_gnc x) (z3obj_gno x) i))
) in
mk_list f n
@@ -2643,7 +2633,7 @@ struct
let n = (get_size x) in
let f i = (Z3native.stats_get_key (z3obj_gnc x) (z3obj_gno x) i) in
mk_list f n
-
+
let get ( x : statistics ) ( key : string ) =
let f p c = (if ((Entry.get_key c) == key) then (Some c) else p) in
List.fold_left f None (get_entries x)
@@ -2657,9 +2647,9 @@ struct
let create ( ctx : context ) ( no : Z3native.ptr ) =
let res : solver = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.solver_inc_ref ;
- dec_ref = Z3native.solver_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.solver_inc_ref ;
+ dec_ref = Z3native.solver_dec_ref } in
(z3obj_sno res ctx no) ;
(z3obj_create res) ;
res
@@ -2695,7 +2685,7 @@ struct
else
let f a b = (Z3native.solver_assert_and_track (z3obj_gnc x) (z3obj_gno x) (Expr.gno a) (Expr.gno b)) in
ignore (List.iter2 f cs ps)
-
+
let assert_and_track ( x : solver ) ( c : expr ) ( p : expr ) =
Z3native.solver_assert_and_track (z3obj_gnc x) (z3obj_gno x) (Expr.gno c) (Expr.gno p)
@@ -2710,30 +2700,30 @@ struct
let check ( x : solver ) ( assumptions : expr list ) =
let r =
if ((List.length assumptions) == 0) then
- lbool_of_int (Z3native.solver_check (z3obj_gnc x) (z3obj_gno x))
+ lbool_of_int (Z3native.solver_check (z3obj_gnc x) (z3obj_gno x))
else
- let f x = (Expr.gno x) in
- lbool_of_int (Z3native.solver_check_assumptions (z3obj_gnc x) (z3obj_gno x) (List.length assumptions) (Array.of_list (List.map f assumptions)))
+ let f x = (Expr.gno x) in
+ lbool_of_int (Z3native.solver_check_assumptions (z3obj_gnc x) (z3obj_gno x) (List.length assumptions) (Array.of_list (List.map f assumptions)))
in
match r with
| L_TRUE -> SATISFIABLE
| L_FALSE -> UNSATISFIABLE
| _ -> UNKNOWN
-
+
let get_model ( x : solver ) =
let q = Z3native.solver_get_model (z3obj_gnc x) (z3obj_gno x) in
if (Z3native.is_null q) then
None
else
Some (Model.create (z3obj_gc x) q)
-
+
let get_proof ( x : solver ) =
let q = Z3native.solver_get_proof (z3obj_gnc x) (z3obj_gno x) in
if (Z3native.is_null q) then
None
else
Some (expr_of_ptr (z3obj_gc x) q)
-
+
let get_unsat_core ( x : solver ) =
let av = AST.ASTVector.create (z3obj_gc x) (Z3native.solver_get_unsat_core (z3obj_gnc x) (z3obj_gno x)) in
(AST.ASTVector.to_expr_list av)
@@ -2758,7 +2748,7 @@ struct
create ctx (Z3native.mk_solver_from_tactic (context_gno ctx) (z3obj_gno t))
let translate ( x : solver ) ( to_ctx : context ) =
- create to_ctx (Z3native.solver_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx))
+ create to_ctx (Z3native.solver_translate (z3obj_gnc x) (z3obj_gno x) (context_gno to_ctx))
let to_string ( x : solver ) = Z3native.solver_to_string (z3obj_gnc x) (z3obj_gno x)
end
@@ -2770,9 +2760,9 @@ struct
let create ( ctx : context ) =
let res : fixedpoint = { m_ctx = ctx ;
- m_n_obj = null ;
- inc_ref = Z3native.fixedpoint_inc_ref ;
- dec_ref = Z3native.fixedpoint_dec_ref } in
+ m_n_obj = null ;
+ inc_ref = Z3native.fixedpoint_inc_ref ;
+ dec_ref = Z3native.fixedpoint_dec_ref } in
(z3obj_sno res ctx (Z3native.mk_fixedpoint (context_gno ctx))) ;
(z3obj_create res) ;
res
@@ -2815,7 +2805,7 @@ struct
| L_TRUE -> Solver.SATISFIABLE
| L_FALSE -> Solver.UNSATISFIABLE
| _ -> Solver.UNKNOWN
-
+
let push ( x : fixedpoint ) =
Z3native.fixedpoint_push (z3obj_gnc x) (z3obj_gno x)
@@ -2844,7 +2834,7 @@ struct
None
else
Some (expr_of_ptr (z3obj_gc x) q)
-
+
let add_cover ( x : fixedpoint ) ( level : int ) ( predicate : func_decl ) ( property : expr ) =
Z3native.fixedpoint_add_cover (z3obj_gnc x) (z3obj_gno x) level (FuncDecl.gno predicate) (Expr.gno property)
@@ -2980,13 +2970,13 @@ struct
raise (Z3native.Exception "Argument size mismatch")
else
Z3native.parse_smtlib_string (context_gno ctx) str
- cs
- (Symbol.symbol_lton sort_names)
- (Sort.sort_lton sorts)
- cd
- (Symbol.symbol_lton decl_names)
- (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))
-
+ cs
+ (Symbol.symbol_lton sort_names)
+ (Sort.sort_lton sorts)
+ cd
+ (Symbol.symbol_lton decl_names)
+ (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))
+
let parse_smtlib_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) =
let csn = (List.length sort_names) in
let cs = (List.length sorts) in
@@ -2996,12 +2986,12 @@ struct
raise (Z3native.Exception "Argument size mismatch")
else
Z3native.parse_smtlib_file (context_gno ctx) file_name
- cs
- (Symbol.symbol_lton sort_names)
- (Sort.sort_lton sorts)
- cd
- (Symbol.symbol_lton decl_names)
- (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))
+ cs
+ (Symbol.symbol_lton sort_names)
+ (Sort.sort_lton sorts)
+ cd
+ (Symbol.symbol_lton decl_names)
+ (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))
let get_num_smtlib_formulas ( ctx : context ) = Z3native.get_smtlib_num_formulas (context_gno ctx)
@@ -3040,13 +3030,13 @@ struct
raise (Z3native.Exception "Argument size mismatch")
else
(expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) str
- cs
- (Symbol.symbol_lton sort_names)
- (Sort.sort_lton sorts)
- cd
- (Symbol.symbol_lton decl_names)
- (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))))
-
+ cs
+ (Symbol.symbol_lton sort_names)
+ (Sort.sort_lton sorts)
+ cd
+ (Symbol.symbol_lton decl_names)
+ (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))))
+
let parse_smtlib2_file ( ctx : context ) ( file_name : string ) ( sort_names : Symbol.symbol list ) ( sorts : Sort.sort list ) ( decl_names : Symbol.symbol list ) ( decls : func_decl list ) =
let csn = (List.length sort_names) in
let cs = (List.length sorts) in
@@ -3056,12 +3046,12 @@ struct
raise (Z3native.Exception "Argument size mismatch")
else
(expr_of_ptr ctx (Z3native.parse_smtlib2_string (context_gno ctx) file_name
- cs
- (Symbol.symbol_lton sort_names)
- (Sort.sort_lton sorts)
- cd
- (Symbol.symbol_lton decl_names)
- (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))))
+ cs
+ (Symbol.symbol_lton sort_names)
+ (Sort.sort_lton sorts)
+ cd
+ (Symbol.symbol_lton decl_names)
+ (let f x = FuncDecl.gno x in (Array.of_list (List.map f decls)))))
end
module Interpolation =
@@ -3102,21 +3092,21 @@ struct
match r with
| 0 -> raise (Z3native.Exception "Interpolation problem could not be read.")
| _ ->
- let f1 i = (expr_of_ptr ctx (Array.get cnsts i)) in
- let f2 i = (Array.get parents i) in
- let f3 i = (expr_of_ptr ctx (Array.get theory i)) in
- ((mk_list f1 num),
- (mk_list f2 num),
- (mk_list f3 num_theory))
+ let f1 i = (expr_of_ptr ctx (Array.get cnsts i)) in
+ let f2 i = (Array.get parents i) in
+ let f3 i = (expr_of_ptr ctx (Array.get theory i)) in
+ ((mk_list f1 num),
+ (mk_list f2 num),
+ (mk_list f3 num_theory))
let check_interpolant ( ctx : context ) ( num : int ) ( cnsts : Expr.expr list ) ( parents : int list ) ( interps : Expr.expr list ) ( num_theory : int ) ( theory : Expr.expr list ) =
let (r, str) = (Z3native.check_interpolant (context_gno ctx)
- num
- (let f x = Expr.gno x in (Array.of_list (List.map f cnsts)))
- (Array.of_list parents)
- (let f x = Expr.gno x in (Array.of_list (List.map f interps)))
- num_theory
- (let f x = Expr.gno x in (Array.of_list (List.map f theory)))) in
+ num
+ (let f x = Expr.gno x in (Array.of_list (List.map f cnsts)))
+ (Array.of_list parents)
+ (let f x = Expr.gno x in (Array.of_list (List.map f interps)))
+ num_theory
+ (let f x = Expr.gno x in (Array.of_list (List.map f theory)))) in
match (lbool_of_int r) with
| L_UNDEF -> raise (Z3native.Exception "Interpolant could not be verified.")
| L_FALSE -> raise (Z3native.Exception "Interpolant could not be verified.")
diff --git a/src/api/python/z3.py b/src/api/python/z3.py
index 864a92846..77af10463 100644
--- a/src/api/python/z3.py
+++ b/src/api/python/z3.py
@@ -1,7 +1,7 @@
############################################
# Copyright (c) 2012 Microsoft Corporation
-#
+#
# Z3 Python interface
#
# Author: Leonardo de Moura (leonardo)
@@ -123,7 +123,7 @@ def _Z3python_error_handler_core(c, e):
# Do nothing error handler, just avoid exit(0)
# The wrappers in z3core.py will raise a Z3Exception if an error is detected
return
-
+
_Z3Python_error_handler = _error_handler_fptr(_Z3python_error_handler_core)
def _to_param_value(val):
@@ -137,12 +137,12 @@ def _to_param_value(val):
class Context:
"""A Context manages all other Z3 objects, global configuration options, etc.
-
+
Z3Py uses a default global context. For most applications this is sufficient.
An application may use multiple Z3 contexts. Objects created in one context
cannot be used in another one. However, several objects may be "translated" from
one context to another. It is not safe to access Z3 objects from multiple threads.
- The only exception is the method `interrupt()` that can be used to interrupt() a long
+ The only exception is the method `interrupt()` that can be used to interrupt() a long
computation.
The initialization method receives global configuration options for the new context.
"""
@@ -176,19 +176,19 @@ class Context:
return self.ctx
def interrupt(self):
- """Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions.
+ """Interrupt a solver performing a satisfiability test, a tactic processing a goal, or simplify functions.
This method can be invoked from a thread different from the one executing the
interruptable procedure.
"""
Z3_interrupt(self.ref())
-
+
# Global Z3 context
_main_ctx = None
def main_ctx():
- """Return a reference to the global Z3 context.
-
+ """Return a reference to the global Z3 context.
+
>>> x = Real('x')
>>> x.ctx == main_ctx()
True
@@ -204,7 +204,7 @@ def main_ctx():
global _main_ctx
if _main_ctx == None:
_main_ctx = Context()
- return _main_ctx
+ return _main_ctx
def _get_ctx(ctx):
if ctx == None:
@@ -293,7 +293,7 @@ class AstRef(Z3PPObject):
def sexpr(self):
"""Return an string representing the AST node in s-expression notation.
-
+
>>> x = Int('x')
>>> ((x + 1)*x).sexpr()
'(* (+ x 1) x)'
@@ -311,10 +311,10 @@ class AstRef(Z3PPObject):
def ctx_ref(self):
"""Return a reference to the C context where this AST node is stored."""
return self.ctx.ref()
-
+
def eq(self, other):
"""Return `True` if `self` and `other` are structurally identical.
-
+
>>> x = Int('x')
>>> n1 = x + 1
>>> n2 = 1 + x
@@ -328,10 +328,10 @@ class AstRef(Z3PPObject):
if __debug__:
_z3_assert(is_ast(other), "Z3 AST expected")
return Z3_is_eq_ast(self.ctx_ref(), self.as_ast(), other.as_ast())
-
+
def translate(self, target):
- """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`.
-
+ """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`.
+
>>> c1 = Context()
>>> c2 = Context()
>>> x = Int('x', c1)
@@ -347,7 +347,7 @@ class AstRef(Z3PPObject):
def hash(self):
"""Return a hashcode for the `self`.
-
+
>>> n1 = simplify(Int('x') + 1)
>>> n2 = simplify(2 + Int('x') - 1)
>>> n1.hash() == n2.hash()
@@ -357,7 +357,7 @@ class AstRef(Z3PPObject):
def is_ast(a):
"""Return `True` if `a` is an AST node.
-
+
>>> is_ast(10)
False
>>> is_ast(IntVal(10))
@@ -377,7 +377,7 @@ def is_ast(a):
def eq(a, b):
"""Return `True` if `a` and `b` are structurally identical AST nodes.
-
+
>>> x = Int('x')
>>> y = Int('y')
>>> eq(x, y)
@@ -463,7 +463,7 @@ class SortRef(AstRef):
def kind(self):
"""Return the Z3 internal kind of a sort. This method can be used to test if `self` is one of the Z3 builtin sorts.
-
+
>>> b = BoolSort()
>>> b.kind() == Z3_BOOL_SORT
True
@@ -478,15 +478,15 @@ class SortRef(AstRef):
return _sort_kind(self.ctx, self.ast)
def subsort(self, other):
- """Return `True` if `self` is a subsort of `other`.
-
+ """Return `True` if `self` is a subsort of `other`.
+
>>> IntSort().subsort(RealSort())
True
"""
return False
def cast(self, val):
- """Try to cast `val` as an element of sort `self`.
+ """Try to cast `val` as an element of sort `self`.
This method is used in Z3Py to convert Python objects such as integers,
floats, longs and strings into Z3 expressions.
@@ -494,7 +494,7 @@ class SortRef(AstRef):
>>> x = Int('x')
>>> RealSort().cast(x)
ToReal(x)
- """
+ """
if __debug__:
_z3_assert(is_expr(val), "Z3 expression expected")
_z3_assert(self.eq(val.sort()), "Sort mismatch")
@@ -502,7 +502,7 @@ class SortRef(AstRef):
def name(self):
"""Return the name (string) of sort `self`.
-
+
>>> BoolSort().name()
'Bool'
>>> ArraySort(IntSort(), IntSort()).name()
@@ -512,7 +512,7 @@ class SortRef(AstRef):
def __eq__(self, other):
"""Return `True` if `self` and `other` are the same Z3 sort.
-
+
>>> p = Bool('p')
>>> p.sort() == BoolSort()
True
@@ -525,7 +525,7 @@ class SortRef(AstRef):
def __ne__(self, other):
"""Return `True` if `self` and `other` are not the same Z3 sort.
-
+
>>> p = Bool('p')
>>> p.sort() != BoolSort()
False
@@ -540,7 +540,7 @@ class SortRef(AstRef):
def is_sort(s):
"""Return `True` if `s` is a Z3 sort.
-
+
>>> is_sort(IntSort())
True
>>> is_sort(Int('x'))
@@ -601,9 +601,9 @@ def DeclareSort(name, ctx=None):
class FuncDeclRef(AstRef):
"""Function declaration. Every constant and function have an associated declaration.
-
+
The declaration assigns a name, a sort (i.e., type), and for function
- the sort (i.e., type) of each of its arguments. Note that, in Z3,
+ the sort (i.e., type) of each of its arguments. Note that, in Z3,
a constant is a function with 0 arguments.
"""
def as_ast(self):
@@ -617,7 +617,7 @@ class FuncDeclRef(AstRef):
def name(self):
"""Return the name of the function declaration `self`.
-
+
>>> f = Function('f', IntSort(), IntSort())
>>> f.name()
'f'
@@ -628,7 +628,7 @@ class FuncDeclRef(AstRef):
def arity(self):
"""Return the number of arguments of a function declaration. If `self` is a constant, then `self.arity()` is 0.
-
+
>>> f = Function('f', IntSort(), RealSort(), BoolSort())
>>> f.arity()
2
@@ -637,7 +637,7 @@ class FuncDeclRef(AstRef):
def domain(self, i):
"""Return the sort of the argument `i` of a function declaration. This method assumes that `0 <= i < self.arity()`.
-
+
>>> f = Function('f', IntSort(), RealSort(), BoolSort())
>>> f.domain(0)
Int
@@ -650,7 +650,7 @@ class FuncDeclRef(AstRef):
def range(self):
"""Return the sort of the range of a function declaration. For constants, this is the sort of the constant.
-
+
>>> f = Function('f', IntSort(), RealSort(), BoolSort())
>>> f.range()
Bool
@@ -659,7 +659,7 @@ class FuncDeclRef(AstRef):
def kind(self):
"""Return the internal kind of a function declaration. It can be used to identify Z3 built-in functions such as addition, multiplication, etc.
-
+
>>> x = Int('x')
>>> d = (x + 1).decl()
>>> d.kind() == Z3_OP_ADD
@@ -670,7 +670,7 @@ class FuncDeclRef(AstRef):
return Z3_get_decl_kind(self.ctx_ref(), self.ast)
def __call__(self, *args):
- """Create a Z3 application expression using the function `self`, and the given arguments.
+ """Create a Z3 application expression using the function `self`, and the given arguments.
The arguments must be Z3 expressions. This method assumes that
the sorts of the elements in `args` match the sorts of the
@@ -703,7 +703,7 @@ class FuncDeclRef(AstRef):
def is_func_decl(a):
"""Return `True` if `a` is a Z3 function declaration.
-
+
>>> f = Function('f', IntSort(), IntSort())
>>> is_func_decl(f)
True
@@ -714,8 +714,8 @@ def is_func_decl(a):
return isinstance(a, FuncDeclRef)
def Function(name, *sig):
- """Create a new Z3 uninterpreted function with the given sorts.
-
+ """Create a new Z3 uninterpreted function with the given sorts.
+
>>> f = Function('f', IntSort(), IntSort())
>>> f(f(0))
f(f(0))
@@ -748,10 +748,10 @@ class ExprRef(AstRef):
"""Constraints, formulas and terms are expressions in Z3.
Expressions are ASTs. Every expression has a sort.
- There are three main kinds of expressions:
+ There are three main kinds of expressions:
function applications, quantifiers and bounded variables.
A constant is a function application with 0 arguments.
- For quantifier free problems, all expressions are
+ For quantifier free problems, all expressions are
function applications.
"""
def as_ast(self):
@@ -762,7 +762,7 @@ class ExprRef(AstRef):
def sort(self):
"""Return the sort of expression `self`.
-
+
>>> x = Int('x')
>>> (x + 1).sort()
Int
@@ -774,7 +774,7 @@ class ExprRef(AstRef):
def sort_kind(self):
"""Shorthand for `self.sort().kind()`.
-
+
>>> a = Array('a', IntSort(), IntSort())
>>> a.sort_kind() == Z3_ARRAY_SORT
True
@@ -786,7 +786,7 @@ class ExprRef(AstRef):
def __eq__(self, other):
"""Return a Z3 expression that represents the constraint `self == other`.
- If `other` is `None`, then this method simply returns `False`.
+ If `other` is `None`, then this method simply returns `False`.
>>> a = Int('a')
>>> b = Int('b')
@@ -806,8 +806,8 @@ class ExprRef(AstRef):
def __ne__(self, other):
"""Return a Z3 expression that represents the constraint `self != other`.
-
- If `other` is `None`, then this method simply returns `True`.
+
+ If `other` is `None`, then this method simply returns `True`.
>>> a = Int('a')
>>> b = Int('b')
@@ -824,7 +824,7 @@ class ExprRef(AstRef):
def decl(self):
"""Return the Z3 function declaration associated with a Z3 application.
-
+
>>> f = Function('f', IntSort(), IntSort())
>>> a = Int('a')
>>> t = f(a)
@@ -836,7 +836,7 @@ class ExprRef(AstRef):
if __debug__:
_z3_assert(is_app(self), "Z3 application expected")
return FuncDeclRef(Z3_get_app_decl(self.ctx_ref(), self.as_ast()), self.ctx)
-
+
def num_args(self):
"""Return the number of arguments of a Z3 application.
@@ -854,7 +854,7 @@ class ExprRef(AstRef):
return int(Z3_get_app_num_args(self.ctx_ref(), self.as_ast()))
def arg(self, idx):
- """Return argument `idx` of the application `self`.
+ """Return argument `idx` of the application `self`.
This method assumes that `self` is a function application with at least `idx+1` arguments.
@@ -893,7 +893,7 @@ def _to_expr_ref(a, ctx):
if isinstance(a, Pattern):
return PatternRef(a, ctx)
ctx_ref = ctx.ref()
- k = Z3_get_ast_kind(ctx_ref, a)
+ k = Z3_get_ast_kind(ctx_ref, a)
if k == Z3_QUANTIFIER_AST:
return QuantifierRef(a, ctx)
sk = Z3_get_sort_kind(ctx_ref, Z3_get_sort(ctx_ref, a))
@@ -918,7 +918,7 @@ def _to_expr_ref(a, ctx):
return ArrayRef(a, ctx)
if sk == Z3_DATATYPE_SORT:
return DatatypeRef(a, ctx)
- if sk == Z3_FLOATING_POINT_SORT:
+ if sk == Z3_FLOATING_POINT_SORT:
if k == Z3_APP_AST and _is_numeral(ctx, a):
return FPNumRef(a, ctx)
else:
@@ -930,6 +930,10 @@ def _to_expr_ref(a, ctx):
return FiniteDomainRef(a, ctx)
if sk == Z3_ROUNDING_MODE_SORT:
return FPRMRef(a, ctx)
+ if sk == Z3_SEQ_SORT:
+ return SeqRef(a, ctx)
+ if sk == Z3_RE_SORT:
+ return ReRef(a, ctx)
return ExprRef(a, ctx)
def _coerce_expr_merge(s, a):
@@ -960,7 +964,7 @@ def _coerce_exprs(a, b, ctx=None):
a = s.cast(a)
b = s.cast(b)
return (a, b)
-
+
def _reduce(f, l, a):
r = a
for e in l:
@@ -980,7 +984,7 @@ def _coerce_expr_list(alist, ctx=None):
def is_expr(a):
"""Return `True` if `a` is a Z3 expression.
-
+
>>> a = Int('a')
>>> is_expr(a)
True
@@ -995,13 +999,15 @@ def is_expr(a):
>>> x = Int('x')
>>> is_expr(ForAll(x, x >= 0))
True
+ >>> is_expr(FPVal(1.0))
+ True
"""
return isinstance(a, ExprRef)
def is_app(a):
- """Return `True` if `a` is a Z3 function application.
-
- Note that, constants are function applications with 0 arguments.
+ """Return `True` if `a` is a Z3 function application.
+
+ Note that, constants are function applications with 0 arguments.
>>> a = Int('a')
>>> is_app(a)
@@ -1024,8 +1030,8 @@ def is_app(a):
return k == Z3_NUMERAL_AST or k == Z3_APP_AST
def is_const(a):
- """Return `True` if `a` is Z3 constant/variable expression.
-
+ """Return `True` if `a` is Z3 constant/variable expression.
+
>>> a = Int('a')
>>> is_const(a)
True
@@ -1042,8 +1048,8 @@ def is_const(a):
return is_app(a) and a.num_args() == 0
def is_var(a):
- """Return `True` if `a` is variable.
-
+ """Return `True` if `a` is variable.
+
Z3 uses de-Bruijn indices for representing bound variables in
quantifiers.
@@ -1067,7 +1073,7 @@ def is_var(a):
def get_var_index(a):
"""Return the de-Bruijn index of the Z3 bounded variable `a`.
-
+
>>> x = Int('x')
>>> y = Int('y')
>>> is_var(x)
@@ -1098,8 +1104,8 @@ def get_var_index(a):
return int(Z3_get_index_value(a.ctx.ref(), a.as_ast()))
def is_app_of(a, k):
- """Return `True` if `a` is an application of the given kind `k`.
-
+ """Return `True` if `a` is an application of the given kind `k`.
+
>>> x = Int('x')
>>> n = x + 1
>>> is_app_of(n, Z3_OP_ADD)
@@ -1110,8 +1116,8 @@ def is_app_of(a, k):
return is_app(a) and a.decl().kind() == k
def If(a, b, c, ctx=None):
- """Create a Z3 if-then-else expression.
-
+ """Create a Z3 if-then-else expression.
+
>>> x = Int('x')
>>> y = Int('y')
>>> max = If(x > y, x, y)
@@ -1132,8 +1138,8 @@ def If(a, b, c, ctx=None):
return _to_expr_ref(Z3_mk_ite(ctx.ref(), a.as_ast(), b.as_ast(), c.as_ast()), ctx)
def Distinct(*args):
- """Create a Z3 distinct expression.
-
+ """Create a Z3 distinct expression.
+
>>> x = Int('x')
>>> y = Int('y')
>>> Distinct(x, y)
@@ -1174,11 +1180,11 @@ def Const(name, sort):
return _to_expr_ref(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), sort.ast), ctx)
def Consts(names, sort):
- """Create a several constants of the given sort.
-
- `names` is a string containing the names of all constants to be created.
+ """Create a several constants of the given sort.
+
+ `names` is a string containing the names of all constants to be created.
Blank spaces separate the names of different constants.
-
+
>>> x, y, z = Consts('x y z', IntSort())
>>> x + y + z
x + y + z
@@ -1189,7 +1195,7 @@ def Consts(names, sort):
def Var(idx, s):
"""Create a Z3 free variable. Free variables are used to create quantified formulas.
-
+
>>> Var(0, IntSort())
Var(0)
>>> eq(Var(0, IntSort()), Var(0, BoolSort()))
@@ -1203,7 +1209,7 @@ def RealVar(idx, ctx=None):
"""
Create a real free variable. Free variables are used to create quantified formulas.
They are also used to create polynomials.
-
+
>>> RealVar(0)
Var(0)
"""
@@ -1213,7 +1219,7 @@ def RealVarVector(n, ctx=None):
"""
Create a list of Real free variables.
The variables have ids: 0, 1, ..., n-1
-
+
>>> x0, x1, x2, x3 = RealVarVector(4)
>>> x2
Var(2)
@@ -1230,7 +1236,7 @@ class BoolSortRef(SortRef):
"""Boolean sort."""
def cast(self, val):
"""Try to cast `val` as a Boolean.
-
+
>>> x = BoolSort().cast(True)
>>> x
True
@@ -1282,7 +1288,7 @@ def is_bool(a):
def is_true(a):
"""Return `True` if `a` is the Z3 true expression.
-
+
>>> p = Bool('p')
>>> is_true(p)
False
@@ -1312,7 +1318,7 @@ def is_false(a):
def is_and(a):
"""Return `True` if `a` is a Z3 and expression.
-
+
>>> p, q = Bools('p q')
>>> is_and(And(p, q))
True
@@ -1334,7 +1340,7 @@ def is_or(a):
def is_not(a):
"""Return `True` if `a` is a Z3 not expression.
-
+
>>> p = Bool('p')
>>> is_not(p)
False
@@ -1345,7 +1351,7 @@ def is_not(a):
def is_eq(a):
"""Return `True` if `a` is a Z3 equality expression.
-
+
>>> x, y = Ints('x y')
>>> is_eq(x == y)
True
@@ -1354,7 +1360,7 @@ def is_eq(a):
def is_distinct(a):
"""Return `True` if `a` is a Z3 distinct expression.
-
+
>>> x, y, z = Ints('x y z')
>>> is_distinct(x == y)
False
@@ -1365,7 +1371,7 @@ def is_distinct(a):
def BoolSort(ctx=None):
"""Return the Boolean Z3 sort. If `ctx=None`, then the global context is used.
-
+
>>> BoolSort()
Bool
>>> p = Const('p', BoolSort())
@@ -1382,7 +1388,7 @@ def BoolSort(ctx=None):
def BoolVal(val, ctx=None):
"""Return the Boolean value `True` or `False`. If `ctx=None`, then the global context is used.
-
+
>>> BoolVal(True)
True
>>> is_true(BoolVal(True))
@@ -1400,7 +1406,7 @@ def BoolVal(val, ctx=None):
def Bool(name, ctx=None):
"""Return a Boolean constant named `name`. If `ctx=None`, then the global context is used.
-
+
>>> p = Bool('p')
>>> q = Bool('q')
>>> And(p, q)
@@ -1410,9 +1416,9 @@ def Bool(name, ctx=None):
return BoolRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), BoolSort(ctx).ast), ctx)
def Bools(names, ctx=None):
- """Return a tuple of Boolean constants.
-
- `names` is a single string containing all names separated by blank spaces.
+ """Return a tuple of Boolean constants.
+
+ `names` is a single string containing all names separated by blank spaces.
If `ctx=None`, then the global context is used.
>>> p, q, r = Bools('p q r')
@@ -1429,7 +1435,7 @@ def BoolVector(prefix, sz, ctx=None):
The constants are named using the given prefix.
If `ctx=None`, then the global context is used.
-
+
>>> P = BoolVector('p', 3)
>>> P
[p__0, p__1, p__2]
@@ -1440,8 +1446,8 @@ def BoolVector(prefix, sz, ctx=None):
def FreshBool(prefix='b', ctx=None):
"""Return a fresh Boolean constant in the given context using the given prefix.
-
- If `ctx=None`, then the global context is used.
+
+ If `ctx=None`, then the global context is used.
>>> b1 = FreshBool()
>>> b2 = FreshBool()
@@ -1452,8 +1458,8 @@ def FreshBool(prefix='b', ctx=None):
return BoolRef(Z3_mk_fresh_const(ctx.ref(), prefix, BoolSort(ctx).ast), ctx)
def Implies(a, b, ctx=None):
- """Create a Z3 implies expression.
-
+ """Create a Z3 implies expression.
+
>>> p, q = Bools('p q')
>>> Implies(p, q)
Implies(p, q)
@@ -1482,8 +1488,8 @@ def Xor(a, b, ctx=None):
return BoolRef(Z3_mk_xor(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
def Not(a, ctx=None):
- """Create a Z3 not expression or probe.
-
+ """Create a Z3 not expression or probe.
+
>>> p = Bool('p')
>>> Not(Not(p))
Not(Not(p))
@@ -1507,8 +1513,8 @@ def _has_probe(args):
return False
def And(*args):
- """Create a Z3 and-expression or and-probe.
-
+ """Create a Z3 and-expression or and-probe.
+
>>> p, q, r = Bools('p q r')
>>> And(p, q, r)
And(p, q, r)
@@ -1537,8 +1543,8 @@ def And(*args):
return BoolRef(Z3_mk_and(ctx.ref(), sz, _args), ctx)
def Or(*args):
- """Create a Z3 or-expression or or-probe.
-
+ """Create a Z3 or-expression or or-probe.
+
>>> p, q, r = Bools('p q r')
>>> Or(p, q, r)
Or(p, q, r)
@@ -1573,8 +1579,8 @@ def Or(*args):
#########################################
class PatternRef(ExprRef):
- """Patterns are hints for quantifier instantiation.
-
+ """Patterns are hints for quantifier instantiation.
+
See http://rise4fun.com/Z3Py/tutorial/advanced for more details.
"""
def as_ast(self):
@@ -1587,7 +1593,7 @@ def is_pattern(a):
"""Return `True` if `a` is a Z3 pattern (hint for quantifier instantiation.
See http://rise4fun.com/Z3Py/tutorial/advanced for more details.
-
+
>>> f = Function('f', IntSort(), IntSort())
>>> x = Int('x')
>>> q = ForAll(x, f(x) == 0, patterns = [ f(x) ])
@@ -1606,7 +1612,7 @@ def MultiPattern(*args):
"""Create a Z3 multi-pattern using the given expressions `*args`
See http://rise4fun.com/Z3Py/tutorial/advanced for more details.
-
+
>>> f = Function('f', IntSort(), IntSort())
>>> g = Function('g', IntSort(), IntSort())
>>> x = Int('x')
@@ -1654,7 +1660,7 @@ class QuantifierRef(BoolRef):
def is_forall(self):
"""Return `True` if `self` is a universal quantifier.
-
+
>>> f = Function('f', IntSort(), IntSort())
>>> x = Int('x')
>>> q = ForAll(x, f(x) == 0)
@@ -1730,22 +1736,22 @@ class QuantifierRef(BoolRef):
f(Var(0)) == 0
"""
return _to_expr_ref(Z3_get_quantifier_body(self.ctx_ref(), self.ast), self.ctx)
-
+
def num_vars(self):
- """Return the number of variables bounded by this quantifier.
-
+ """Return the number of variables bounded by this quantifier.
+
>>> f = Function('f', IntSort(), IntSort(), IntSort())
>>> x = Int('x')
>>> y = Int('y')
>>> q = ForAll([x, y], f(x, y) >= x)
- >>> q.num_vars()
+ >>> q.num_vars()
2
"""
return int(Z3_get_quantifier_num_bound(self.ctx_ref(), self.ast))
def var_name(self, idx):
- """Return a string representing a name used when displaying the quantifier.
-
+ """Return a string representing a name used when displaying the quantifier.
+
>>> f = Function('f', IntSort(), IntSort(), IntSort())
>>> x = Int('x')
>>> y = Int('y')
@@ -1788,7 +1794,7 @@ class QuantifierRef(BoolRef):
def is_quantifier(a):
"""Return `True` if `a` is a Z3 quantifier.
-
+
>>> f = Function('f', IntSort(), IntSort())
>>> x = Int('x')
>>> q = ForAll(x, f(x) == 0)
@@ -1821,15 +1827,15 @@ def _mk_quantifier(is_forall, vs, body, weight=1, qid="", skid="", patterns=[],
_no_pats, num_no_pats = _to_ast_array(no_patterns)
qid = to_symbol(qid, ctx)
skid = to_symbol(skid, ctx)
- return QuantifierRef(Z3_mk_quantifier_const_ex(ctx.ref(), is_forall, weight, qid, skid,
- num_vars, _vs,
- num_pats, _pats,
- num_no_pats, _no_pats,
+ return QuantifierRef(Z3_mk_quantifier_const_ex(ctx.ref(), is_forall, weight, qid, skid,
+ num_vars, _vs,
+ num_pats, _pats,
+ num_no_pats, _no_pats,
body.as_ast()), ctx)
def ForAll(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
"""Create a Z3 forall formula.
-
+
The parameters `weight`, `qif`, `skid`, `patterns` and `no_patterns` are optional annotations.
See http://rise4fun.com/Z3Py/tutorial/advanced for more details.
@@ -1848,7 +1854,7 @@ def ForAll(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
def Exists(vs, body, weight=1, qid="", skid="", patterns=[], no_patterns=[]):
"""Create a Z3 exists formula.
-
+
The parameters `weight`, `qif`, `skid`, `patterns` and `no_patterns` are optional annotations.
See http://rise4fun.com/Z3Py/tutorial/advanced for more details.
@@ -1878,7 +1884,7 @@ class ArithSortRef(SortRef):
def is_real(self):
"""Return `True` if `self` is of the sort Real.
-
+
>>> x = Real('x')
>>> x.is_real()
True
@@ -1892,7 +1898,7 @@ class ArithSortRef(SortRef):
def is_int(self):
"""Return `True` if `self` is of the sort Integer.
-
+
>>> x = Int('x')
>>> x.is_int()
True
@@ -1910,7 +1916,7 @@ class ArithSortRef(SortRef):
def cast(self, val):
"""Try to cast `val` as an Integer or Real.
-
+
>>> IntSort().cast(10)
10
>>> is_int(IntSort().cast(10))
@@ -1946,7 +1952,7 @@ class ArithSortRef(SortRef):
def is_arith_sort(s):
"""Return `True` if s is an arithmetical sort (type).
-
+
>>> is_arith_sort(IntSort())
True
>>> is_arith_sort(RealSort())
@@ -1958,13 +1964,13 @@ def is_arith_sort(s):
True
"""
return isinstance(s, ArithSortRef)
-
+
class ArithRef(ExprRef):
"""Integer and Real expressions."""
def sort(self):
"""Return the sort (type) of the arithmetical expression `self`.
-
+
>>> Int('x').sort()
Int
>>> (Real('x') + 1).sort()
@@ -1974,7 +1980,7 @@ class ArithRef(ExprRef):
def is_int(self):
"""Return `True` if `self` is an integer expression.
-
+
>>> x = Int('x')
>>> x.is_int()
True
@@ -1988,7 +1994,7 @@ class ArithRef(ExprRef):
def is_real(self):
"""Return `True` if `self` is an real expression.
-
+
>>> x = Real('x')
>>> x.is_real()
True
@@ -1999,7 +2005,7 @@ class ArithRef(ExprRef):
def __add__(self, other):
"""Create the Z3 expression `self + other`.
-
+
>>> x = Int('x')
>>> y = Int('y')
>>> x + y
@@ -2012,7 +2018,7 @@ class ArithRef(ExprRef):
def __radd__(self, other):
"""Create the Z3 expression `other + self`.
-
+
>>> x = Int('x')
>>> 10 + x
10 + x
@@ -2022,7 +2028,7 @@ class ArithRef(ExprRef):
def __mul__(self, other):
"""Create the Z3 expression `self * other`.
-
+
>>> x = Real('x')
>>> y = Real('y')
>>> x * y
@@ -2035,7 +2041,7 @@ class ArithRef(ExprRef):
def __rmul__(self, other):
"""Create the Z3 expression `other * self`.
-
+
>>> x = Real('x')
>>> 10 * x
10*x
@@ -2058,7 +2064,7 @@ class ArithRef(ExprRef):
def __rsub__(self, other):
"""Create the Z3 expression `other - self`.
-
+
>>> x = Int('x')
>>> 10 - x
10 - x
@@ -2068,7 +2074,7 @@ class ArithRef(ExprRef):
def __pow__(self, other):
"""Create the Z3 expression `self**other` (** is the power operator).
-
+
>>> x = Real('x')
>>> x**3
x**3
@@ -2082,7 +2088,7 @@ class ArithRef(ExprRef):
def __rpow__(self, other):
"""Create the Z3 expression `other**self` (** is the power operator).
-
+
>>> x = Real('x')
>>> 2**x
2**x
@@ -2096,7 +2102,7 @@ class ArithRef(ExprRef):
def __div__(self, other):
"""Create the Z3 expression `other/self`.
-
+
>>> x = Int('x')
>>> y = Int('y')
>>> x/y
@@ -2123,7 +2129,7 @@ class ArithRef(ExprRef):
def __rdiv__(self, other):
"""Create the Z3 expression `other/self`.
-
+
>>> x = Int('x')
>>> 10/x
10/x
@@ -2144,7 +2150,7 @@ class ArithRef(ExprRef):
def __mod__(self, other):
"""Create the Z3 expression `other%self`.
-
+
>>> x = Int('x')
>>> y = Int('y')
>>> x % y
@@ -2159,7 +2165,7 @@ class ArithRef(ExprRef):
def __rmod__(self, other):
"""Create the Z3 expression `other%self`.
-
+
>>> x = Int('x')
>>> 10 % x
10%x
@@ -2179,10 +2185,10 @@ class ArithRef(ExprRef):
x
"""
return ArithRef(Z3_mk_unary_minus(self.ctx_ref(), self.as_ast()), self.ctx)
-
+
def __pos__(self):
"""Return `self`.
-
+
>>> x = Int('x')
>>> +x
x
@@ -2191,7 +2197,7 @@ class ArithRef(ExprRef):
def __le__(self, other):
"""Create the Z3 expression `other <= self`.
-
+
>>> x, y = Ints('x y')
>>> x <= y
x <= y
@@ -2204,7 +2210,7 @@ class ArithRef(ExprRef):
def __lt__(self, other):
"""Create the Z3 expression `other < self`.
-
+
>>> x, y = Ints('x y')
>>> x < y
x < y
@@ -2217,7 +2223,7 @@ class ArithRef(ExprRef):
def __gt__(self, other):
"""Create the Z3 expression `other > self`.
-
+
>>> x, y = Ints('x y')
>>> x > y
x > y
@@ -2227,10 +2233,10 @@ class ArithRef(ExprRef):
"""
a, b = _coerce_exprs(self, other)
return BoolRef(Z3_mk_gt(self.ctx_ref(), a.as_ast(), b.as_ast()), self.ctx)
-
+
def __ge__(self, other):
"""Create the Z3 expression `other >= self`.
-
+
>>> x, y = Ints('x y')
>>> x >= y
x >= y
@@ -2243,7 +2249,7 @@ class ArithRef(ExprRef):
def is_arith(a):
"""Return `True` if `a` is an arithmetical expression.
-
+
>>> x = Int('x')
>>> is_arith(x)
True
@@ -2263,7 +2269,7 @@ def is_arith(a):
def is_int(a):
"""Return `True` if `a` is an integer expression.
-
+
>>> x = Int('x')
>>> is_int(x + 1)
True
@@ -2281,7 +2287,7 @@ def is_int(a):
def is_real(a):
"""Return `True` if `a` is a real expression.
-
+
>>> x = Int('x')
>>> is_real(x + 1)
False
@@ -2305,7 +2311,7 @@ def _is_algebraic(ctx, a):
def is_int_value(a):
"""Return `True` if `a` is an integer value of sort Int.
-
+
>>> is_int_value(IntVal(1))
True
>>> is_int_value(1)
@@ -2328,7 +2334,7 @@ def is_int_value(a):
def is_rational_value(a):
"""Return `True` if `a` is rational value of sort Real.
-
+
>>> is_rational_value(RealVal(1))
True
>>> is_rational_value(RealVal("3/5"))
@@ -2349,7 +2355,7 @@ def is_rational_value(a):
def is_algebraic_value(a):
"""Return `True` if `a` is an algerbraic value of sort Real.
-
+
>>> is_algebraic_value(RealVal("3/5"))
False
>>> n = simplify(Sqrt(2))
@@ -2362,7 +2368,7 @@ def is_algebraic_value(a):
def is_add(a):
"""Return `True` if `a` is an expression of the form b + c.
-
+
>>> x, y = Ints('x y')
>>> is_add(x + y)
True
@@ -2373,7 +2379,7 @@ def is_add(a):
def is_mul(a):
"""Return `True` if `a` is an expression of the form b * c.
-
+
>>> x, y = Ints('x y')
>>> is_mul(x * y)
True
@@ -2384,7 +2390,7 @@ def is_mul(a):
def is_sub(a):
"""Return `True` if `a` is an expression of the form b - c.
-
+
>>> x, y = Ints('x y')
>>> is_sub(x - y)
True
@@ -2395,7 +2401,7 @@ def is_sub(a):
def is_div(a):
"""Return `True` if `a` is an expression of the form b / c.
-
+
>>> x, y = Reals('x y')
>>> is_div(x / y)
True
@@ -2411,7 +2417,7 @@ def is_div(a):
def is_idiv(a):
"""Return `True` if `a` is an expression of the form b div c.
-
+
>>> x, y = Ints('x y')
>>> is_idiv(x / y)
True
@@ -2433,7 +2439,7 @@ def is_mod(a):
def is_le(a):
"""Return `True` if `a` is an expression of the form b <= c.
-
+
>>> x, y = Ints('x y')
>>> is_le(x <= y)
True
@@ -2444,7 +2450,7 @@ def is_le(a):
def is_lt(a):
"""Return `True` if `a` is an expression of the form b < c.
-
+
>>> x, y = Ints('x y')
>>> is_lt(x < y)
True
@@ -2455,7 +2461,7 @@ def is_lt(a):
def is_ge(a):
"""Return `True` if `a` is an expression of the form b >= c.
-
+
>>> x, y = Ints('x y')
>>> is_ge(x >= y)
True
@@ -2466,7 +2472,7 @@ def is_ge(a):
def is_gt(a):
"""Return `True` if `a` is an expression of the form b > c.
-
+
>>> x, y = Ints('x y')
>>> is_gt(x > y)
True
@@ -2477,7 +2483,7 @@ def is_gt(a):
def is_is_int(a):
"""Return `True` if `a` is an expression of the form IsInt(b).
-
+
>>> x = Real('x')
>>> is_is_int(IsInt(x))
True
@@ -2488,7 +2494,7 @@ def is_is_int(a):
def is_to_real(a):
"""Return `True` if `a` is an expression of the form ToReal(b).
-
+
>>> x = Int('x')
>>> n = ToReal(x)
>>> n
@@ -2502,7 +2508,7 @@ def is_to_real(a):
def is_to_int(a):
"""Return `True` if `a` is an expression of the form ToInt(b).
-
+
>>> x = Real('x')
>>> n = ToInt(x)
>>> n
@@ -2518,8 +2524,8 @@ class IntNumRef(ArithRef):
"""Integer values."""
def as_long(self):
- """Return a Z3 integer numeral as a Python long (bignum) numeral.
-
+ """Return a Z3 integer numeral as a Python long (bignum) numeral.
+
>>> v = IntVal(1)
>>> v + 1
1 + 1
@@ -2542,7 +2548,7 @@ class RatNumRef(ArithRef):
"""Rational values."""
def numerator(self):
- """ Return the numerator of a Z3 rational numeral.
+ """ Return the numerator of a Z3 rational numeral.
>>> is_rational_value(RealVal("3/5"))
True
@@ -2557,8 +2563,8 @@ class RatNumRef(ArithRef):
return IntNumRef(Z3_get_numerator(self.ctx_ref(), self.as_ast()), self.ctx)
def denominator(self):
- """ Return the denominator of a Z3 rational numeral.
-
+ """ Return the denominator of a Z3 rational numeral.
+
>>> is_rational_value(Q(3,5))
True
>>> n = Q(3,5)
@@ -2569,7 +2575,7 @@ class RatNumRef(ArithRef):
def numerator_as_long(self):
""" Return the numerator as a Python long.
-
+
>>> v = RealVal(10000000000)
>>> v
10000000000
@@ -2579,7 +2585,7 @@ class RatNumRef(ArithRef):
True
"""
return self.numerator().as_long()
-
+
def denominator_as_long(self):
""" Return the denominator as a Python long.
@@ -2593,7 +2599,7 @@ class RatNumRef(ArithRef):
def as_decimal(self, prec):
""" Return a Z3 rational value as a string in decimal notation using at most `prec` decimal places.
-
+
>>> v = RealVal("1/5")
>>> v.as_decimal(3)
'0.2'
@@ -2614,7 +2620,7 @@ class RatNumRef(ArithRef):
def as_fraction(self):
"""Return a Z3 rational as a Python Fraction object.
-
+
>>> v = RealVal("1/5")
>>> v.as_fraction()
Fraction(1, 5)
@@ -2625,9 +2631,9 @@ class AlgebraicNumRef(ArithRef):
"""Algebraic irrational values."""
def approx(self, precision=10):
- """Return a Z3 rational number that approximates the algebraic number `self`.
- The result `r` is such that |r - self| <= 1/10^precision
-
+ """Return a Z3 rational number that approximates the algebraic number `self`.
+ The result `r` is such that |r - self| <= 1/10^precision
+
>>> x = simplify(Sqrt(2))
>>> x.approx(20)
6838717160008073720548335/4835703278458516698824704
@@ -2658,7 +2664,7 @@ def _py2expr(a, ctx=None):
def IntSort(ctx=None):
"""Return the integer sort in the given context. If `ctx=None`, then the global context is used.
-
+
>>> IntSort()
Int
>>> x = Const('x', IntSort())
@@ -2674,7 +2680,7 @@ def IntSort(ctx=None):
def RealSort(ctx=None):
"""Return the real sort in the given context. If `ctx=None`, then the global context is used.
-
+
>>> RealSort()
Real
>>> x = Const('x', RealSort())
@@ -2705,7 +2711,7 @@ def _to_int_str(val):
def IntVal(val, ctx=None):
"""Return a Z3 integer value. If `ctx=None`, then the global context is used.
-
+
>>> IntVal(1)
1
>>> IntVal("100")
@@ -2715,11 +2721,11 @@ def IntVal(val, ctx=None):
return IntNumRef(Z3_mk_numeral(ctx.ref(), _to_int_str(val), IntSort(ctx).ast), ctx)
def RealVal(val, ctx=None):
- """Return a Z3 real value.
-
+ """Return a Z3 real value.
+
`val` may be a Python int, long, float or string representing a number in decimal or rational notation.
If `ctx=None`, then the global context is used.
-
+
>>> RealVal(1)
1
>>> RealVal(1).sort()
@@ -2736,7 +2742,7 @@ def RatVal(a, b, ctx=None):
"""Return a Z3 rational a/b.
If `ctx=None`, then the global context is used.
-
+
>>> RatVal(3,5)
3/5
>>> RatVal(3,5).sort()
@@ -2749,7 +2755,7 @@ def RatVal(a, b, ctx=None):
def Q(a, b, ctx=None):
"""Return a Z3 rational a/b.
-
+
If `ctx=None`, then the global context is used.
>>> Q(3,5)
@@ -2772,8 +2778,8 @@ def Int(name, ctx=None):
return ArithRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), IntSort(ctx).ast), ctx)
def Ints(names, ctx=None):
- """Return a tuple of Integer constants.
-
+ """Return a tuple of Integer constants.
+
>>> x, y, z = Ints('x y z')
>>> Sum(x, y, z)
x + y + z
@@ -2785,7 +2791,7 @@ def Ints(names, ctx=None):
def IntVector(prefix, sz, ctx=None):
"""Return a list of integer constants of size `sz`.
-
+
>>> X = IntVector('x', 3)
>>> X
[x__0, x__1, x__2]
@@ -2820,8 +2826,8 @@ def Real(name, ctx=None):
return ArithRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), RealSort(ctx).ast), ctx)
def Reals(names, ctx=None):
- """Return a tuple of real constants.
-
+ """Return a tuple of real constants.
+
>>> x, y, z = Reals('x y z')
>>> Sum(x, y, z)
x + y + z
@@ -2835,7 +2841,7 @@ def Reals(names, ctx=None):
def RealVector(prefix, sz, ctx=None):
"""Return a list of real constants of size `sz`.
-
+
>>> X = RealVector('x', 3)
>>> X
[x__0, x__1, x__2]
@@ -2860,8 +2866,8 @@ def FreshReal(prefix='b', ctx=None):
return ArithRef(Z3_mk_fresh_const(ctx.ref(), prefix, RealSort(ctx).ast), ctx)
def ToReal(a):
- """ Return the Z3 expression ToReal(a).
-
+ """ Return the Z3 expression ToReal(a).
+
>>> x = Int('x')
>>> x.sort()
Int
@@ -2877,8 +2883,8 @@ def ToReal(a):
return ArithRef(Z3_mk_int2real(ctx.ref(), a.as_ast()), ctx)
def ToInt(a):
- """ Return the Z3 expression ToInt(a).
-
+ """ Return the Z3 expression ToInt(a).
+
>>> x = Real('x')
>>> x.sort()
Real
@@ -2894,8 +2900,8 @@ def ToInt(a):
return ArithRef(Z3_mk_real2int(ctx.ref(), a.as_ast()), ctx)
def IsInt(a):
- """ Return the Z3 predicate IsInt(a).
-
+ """ Return the Z3 predicate IsInt(a).
+
>>> x = Real('x')
>>> IsInt(x + "1/2")
IsInt(x + 1/2)
@@ -2908,10 +2914,10 @@ def IsInt(a):
_z3_assert(a.is_real(), "Z3 real expression expected.")
ctx = a.ctx
return BoolRef(Z3_mk_is_int(ctx.ref(), a.as_ast()), ctx)
-
+
def Sqrt(a, ctx=None):
- """ Return a Z3 expression which represents the square root of a.
-
+ """ Return a Z3 expression which represents the square root of a.
+
>>> x = Real('x')
>>> Sqrt(x)
x**(1/2)
@@ -2922,8 +2928,8 @@ def Sqrt(a, ctx=None):
return a ** "1/2"
def Cbrt(a, ctx=None):
- """ Return a Z3 expression which represents the cubic root of a.
-
+ """ Return a Z3 expression which represents the cubic root of a.
+
>>> x = Real('x')
>>> Cbrt(x)
x**(1/3)
@@ -2944,7 +2950,7 @@ class BitVecSortRef(SortRef):
def size(self):
"""Return the size (number of bits) of the bit-vector sort `self`.
-
+
>>> b = BitVecSort(32)
>>> b.size()
32
@@ -2997,7 +3003,7 @@ class BitVecRef(ExprRef):
def size(self):
"""Return the number of bits of the bit-vector expression `self`.
-
+
>>> x = BitVec('x', 32)
>>> (x + 1).size()
32
@@ -3005,10 +3011,10 @@ class BitVecRef(ExprRef):
64
"""
return self.sort().size()
-
+
def __add__(self, other):
"""Create the Z3 expression `self + other`.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> x + y
@@ -3021,7 +3027,7 @@ class BitVecRef(ExprRef):
def __radd__(self, other):
"""Create the Z3 expression `other + self`.
-
+
>>> x = BitVec('x', 32)
>>> 10 + x
10 + x
@@ -3031,7 +3037,7 @@ class BitVecRef(ExprRef):
def __mul__(self, other):
"""Create the Z3 expression `self * other`.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> x * y
@@ -3044,7 +3050,7 @@ class BitVecRef(ExprRef):
def __rmul__(self, other):
"""Create the Z3 expression `other * self`.
-
+
>>> x = BitVec('x', 32)
>>> 10 * x
10*x
@@ -3054,7 +3060,7 @@ class BitVecRef(ExprRef):
def __sub__(self, other):
"""Create the Z3 expression `self - other`.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> x - y
@@ -3067,7 +3073,7 @@ class BitVecRef(ExprRef):
def __rsub__(self, other):
"""Create the Z3 expression `other - self`.
-
+
>>> x = BitVec('x', 32)
>>> 10 - x
10 - x
@@ -3077,7 +3083,7 @@ class BitVecRef(ExprRef):
def __or__(self, other):
"""Create the Z3 expression bitwise-or `self | other`.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> x | y
@@ -3090,7 +3096,7 @@ class BitVecRef(ExprRef):
def __ror__(self, other):
"""Create the Z3 expression bitwise-or `other | self`.
-
+
>>> x = BitVec('x', 32)
>>> 10 | x
10 | x
@@ -3100,7 +3106,7 @@ class BitVecRef(ExprRef):
def __and__(self, other):
"""Create the Z3 expression bitwise-and `self & other`.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> x & y
@@ -3113,7 +3119,7 @@ class BitVecRef(ExprRef):
def __rand__(self, other):
"""Create the Z3 expression bitwise-or `other & self`.
-
+
>>> x = BitVec('x', 32)
>>> 10 & x
10 & x
@@ -3123,7 +3129,7 @@ class BitVecRef(ExprRef):
def __xor__(self, other):
"""Create the Z3 expression bitwise-xor `self ^ other`.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> x ^ y
@@ -3136,7 +3142,7 @@ class BitVecRef(ExprRef):
def __rxor__(self, other):
"""Create the Z3 expression bitwise-xor `other ^ self`.
-
+
>>> x = BitVec('x', 32)
>>> 10 ^ x
10 ^ x
@@ -3259,7 +3265,7 @@ class BitVecRef(ExprRef):
def __le__(self, other):
"""Create the Z3 expression (signed) `other <= self`.
-
+
Use the function ULE() for unsigned less than or equal to.
>>> x, y = BitVecs('x y', 32)
@@ -3275,7 +3281,7 @@ class BitVecRef(ExprRef):
def __lt__(self, other):
"""Create the Z3 expression (signed) `other < self`.
-
+
Use the function ULT() for unsigned less than.
>>> x, y = BitVecs('x y', 32)
@@ -3291,7 +3297,7 @@ class BitVecRef(ExprRef):
def __gt__(self, other):
"""Create the Z3 expression (signed) `other > self`.
-
+
Use the function UGT() for unsigned greater than.
>>> x, y = BitVecs('x y', 32)
@@ -3304,10 +3310,10 @@ class BitVecRef(ExprRef):
"""
a, b = _coerce_exprs(self, other)
return BoolRef(Z3_mk_bvsgt(self.ctx_ref(), a.as_ast(), b.as_ast()), self.ctx)
-
+
def __ge__(self, other):
"""Create the Z3 expression (signed) `other >= self`.
-
+
Use the function UGE() for unsigned greater than or equal to.
>>> x, y = BitVecs('x y', 32)
@@ -3397,8 +3403,8 @@ class BitVecNumRef(BitVecRef):
"""Bit-vector values."""
def as_long(self):
- """Return a Z3 bit-vector numeral as a Python long (bignum) numeral.
-
+ """Return a Z3 bit-vector numeral as a Python long (bignum) numeral.
+
>>> v = BitVecVal(0xbadc0de, 32)
>>> v
195936478
@@ -3409,7 +3415,7 @@ class BitVecNumRef(BitVecRef):
def as_signed_long(self):
"""Return a Z3 bit-vector numeral as a Python long (bignum) numeral. The most significant bit is assumed to be the sign.
-
+
>>> BitVecVal(4, 3).as_signed_long()
-4
>>> BitVecVal(7, 3).as_signed_long()
@@ -3434,7 +3440,7 @@ class BitVecNumRef(BitVecRef):
def is_bv(a):
"""Return `True` if `a` is a Z3 bit-vector expression.
-
+
>>> b = BitVec('b', 32)
>>> is_bv(b)
True
@@ -3460,8 +3466,8 @@ def is_bv_value(a):
return is_bv(a) and _is_numeral(a.ctx, a.as_ast())
def BV2Int(a):
- """Return the Z3 expression BV2Int(a).
-
+ """Return the Z3 expression BV2Int(a).
+
>>> b = BitVec('b', 3)
>>> BV2Int(b).sort()
Int
@@ -3493,7 +3499,7 @@ def BitVecSort(sz, ctx=None):
def BitVecVal(val, bv, ctx=None):
"""Return a bit-vector value with the given number of bits. If `ctx=None`, then the global context is used.
-
+
>>> v = BitVecVal(10, 32)
>>> v
10
@@ -3531,8 +3537,8 @@ def BitVec(name, bv, ctx=None):
return BitVecRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), bv.ast), ctx)
def BitVecs(names, bv, ctx=None):
- """Return a tuple of bit-vector constants of size bv.
-
+ """Return a tuple of bit-vector constants of size bv.
+
>>> x, y, z = BitVecs('x y z', 16)
>>> x.size()
16
@@ -3551,8 +3557,8 @@ def BitVecs(names, bv, ctx=None):
return [BitVec(name, bv, ctx) for name in names]
def Concat(*args):
- """Create a Z3 bit-vector concatenation expression.
-
+ """Create a Z3 bit-vector concatenation expression.
+
>>> v = BitVecVal(1, 4)
>>> Concat(v, v+1, v)
Concat(Concat(1, 1 + 1), 1)
@@ -3562,24 +3568,56 @@ def Concat(*args):
121
"""
args = _get_args(args)
+ sz = len(args)
+ if __debug__:
+ _z3_assert(sz >= 2, "At least two arguments expected.")
+
+ ctx = args[0].ctx
+
+ if is_seq(args[0]):
+ if __debug__:
+ _z3_assert(all([is_seq(a) for a in args]), "All arguments must be sequence expressions.")
+ v = (Ast * sz)()
+ for i in range(sz):
+ v[i] = args[i].as_ast()
+ return SeqRef(Z3_mk_seq_concat(ctx.ref(), sz, v), ctx)
+
+ if is_re(args[0]):
+ if __debug__:
+ _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.")
+ v = (Ast * sz)()
+ for i in range(sz):
+ v[i] = args[i].as_ast()
+ return ReRef(Z3_mk_re_concat(ctx.ref(), sz, v), ctx)
+
if __debug__:
_z3_assert(all([is_bv(a) for a in args]), "All arguments must be Z3 bit-vector expressions.")
- _z3_assert(len(args) >= 2, "At least two arguments expected.")
- ctx = args[0].ctx
r = args[0]
- for i in range(len(args) - 1):
+ for i in range(sz - 1):
r = BitVecRef(Z3_mk_concat(ctx.ref(), r.as_ast(), args[i+1].as_ast()), ctx)
return r
def Extract(high, low, a):
- """Create a Z3 bit-vector extraction expression.
+ """Create a Z3 bit-vector extraction expression, or create a string extraction expression.
>>> x = BitVec('x', 8)
>>> Extract(6, 2, x)
Extract(6, 2, x)
>>> Extract(6, 2, x).sort()
BitVec(5)
+ >>> simplify(Extract(StringVal("abcd"),2,1))
+ "c"
"""
+ if isinstance(high, str):
+ high = StringVal(high)
+ if is_seq(high):
+ s = high
+ offset = _py2expr(low, high.ctx)
+ length = _py2expr(a, high.ctx)
+
+ if __debug__:
+ _z3_assert(is_int(offset) and is_int(length), "Second and third arguments must be integers")
+ return SeqRef(Z3_mk_seq_extract(s.ctx_ref(), s.as_ast(), offset.as_ast(), length.as_ast()), s.ctx)
if __debug__:
_z3_assert(low <= high, "First argument must be greater than or equal to second argument")
_z3_assert(isinstance(high, int) and high >= 0 and isinstance(low, int) and low >= 0, "First and second arguments must be non negative integers")
@@ -3592,9 +3630,9 @@ def _check_bv_args(a, b):
def ULE(a, b):
"""Create the Z3 expression (unsigned) `other <= self`.
-
+
Use the operator <= for signed less than or equal to.
-
+
>>> x, y = BitVecs('x y', 32)
>>> ULE(x, y)
ULE(x, y)
@@ -3609,9 +3647,9 @@ def ULE(a, b):
def ULT(a, b):
"""Create the Z3 expression (unsigned) `other < self`.
-
+
Use the operator < for signed less than.
-
+
>>> x, y = BitVecs('x y', 32)
>>> ULT(x, y)
ULT(x, y)
@@ -3626,9 +3664,9 @@ def ULT(a, b):
def UGE(a, b):
"""Create the Z3 expression (unsigned) `other >= self`.
-
+
Use the operator >= for signed greater than or equal to.
-
+
>>> x, y = BitVecs('x y', 32)
>>> UGE(x, y)
UGE(x, y)
@@ -3643,9 +3681,9 @@ def UGE(a, b):
def UGT(a, b):
"""Create the Z3 expression (unsigned) `other > self`.
-
+
Use the operator > for signed greater than.
-
+
>>> x, y = BitVecs('x y', 32)
>>> UGT(x, y)
UGT(x, y)
@@ -3660,9 +3698,9 @@ def UGT(a, b):
def UDiv(a, b):
"""Create the Z3 expression (unsigned) division `self / other`.
-
+
Use the operator / for signed division.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> UDiv(x, y)
@@ -3680,9 +3718,9 @@ def UDiv(a, b):
def URem(a, b):
"""Create the Z3 expression (unsigned) remainder `self % other`.
-
+
Use the operator % for signed modulus, and SRem() for signed remainder.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> URem(x, y)
@@ -3700,9 +3738,9 @@ def URem(a, b):
def SRem(a, b):
"""Create the Z3 expression signed remainder.
-
+
Use the operator % for signed modulus, and URem() for unsigned remainder.
-
+
>>> x = BitVec('x', 32)
>>> y = BitVec('y', 32)
>>> SRem(x, y)
@@ -3881,16 +3919,16 @@ class ArraySortRef(SortRef):
def domain(self):
"""Return the domain of the array sort `self`.
-
+
>>> A = ArraySort(IntSort(), BoolSort())
>>> A.domain()
Int
"""
return _to_sort_ref(Z3_get_array_sort_domain(self.ctx_ref(), self.ast), self.ctx)
-
+
def range(self):
"""Return the range of the array sort `self`.
-
+
>>> A = ArraySort(IntSort(), BoolSort())
>>> A.range()
Bool
@@ -3908,7 +3946,7 @@ class ArrayRef(ExprRef):
Array(Int, Bool)
"""
return ArraySortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
-
+
def domain(self):
"""Shorthand for `self.sort().domain()`.
@@ -3917,7 +3955,7 @@ class ArrayRef(ExprRef):
Int
"""
return self.sort().domain()
-
+
def range(self):
"""Shorthand for `self.sort().range()`.
@@ -3946,7 +3984,7 @@ class ArrayRef(ExprRef):
def is_array(a):
"""Return `True` if `a` is a Z3 array expression.
-
+
>>> a = Array('a', IntSort(), IntSort())
>>> is_array(a)
True
@@ -3982,7 +4020,7 @@ def is_K(a):
return is_app_of(a, Z3_OP_CONST_ARRAY)
def is_map(a):
- """Return `True` if `a` is a Z3 map array expression.
+ """Return `True` if `a` is a Z3 map array expression.
>>> f = Function('f', IntSort(), IntSort())
>>> b = Array('b', IntSort(), IntSort())
@@ -4023,7 +4061,7 @@ def get_map_func(a):
def ArraySort(d, r):
"""Return the Z3 array sort with the given domain and range sorts.
-
+
>>> A = ArraySort(IntSort(), BoolSort())
>>> A
Array(Int, Bool)
@@ -4076,15 +4114,15 @@ def Update(a, i, v):
ctx = a.ctx
return _to_expr_ref(Z3_mk_store(ctx.ref(), a.as_ast(), i.as_ast(), v.as_ast()), ctx)
-def Default(a):
- """ Return a default value for array expression.
- >>> b = K(IntSort(), 1)
- >>> prove(Default(b) == 1)
+def Default(a):
+ """ Return a default value for array expression.
+ >>> b = K(IntSort(), 1)
+ >>> prove(Default(b) == 1)
proved
- """
- if __debug__:
- _z3_assert(is_array(a), "First argument must be a Z3 array expression")
- return a.default()
+ """
+ if __debug__:
+ _z3_assert(is_array(a), "First argument must be a Z3 array expression")
+ return a.default()
def Store(a, i, v):
@@ -4118,7 +4156,7 @@ def Select(a, i):
return a[i]
def Map(f, *args):
- """Return a Z3 map array expression.
+ """Return a Z3 map array expression.
>>> f = Function('f', IntSort(), IntSort(), IntSort())
>>> a1 = Array('a1', IntSort(), IntSort())
@@ -4140,8 +4178,8 @@ def Map(f, *args):
return ArrayRef(Z3_mk_map(ctx.ref(), f.ast, sz, _args), ctx)
def K(dom, v):
- """Return a Z3 constant array expression.
-
+ """Return a Z3 constant array expression.
+
>>> a = K(IntSort(), 10)
>>> a
K(Int, 10)
@@ -4169,7 +4207,7 @@ def Ext(a, b):
def is_select(a):
"""Return `True` if `a` is a Z3 array select application.
-
+
>>> a = Array('a', IntSort(), IntSort())
>>> is_select(a)
False
@@ -4181,7 +4219,7 @@ def is_select(a):
def is_store(a):
"""Return `True` if `a` is a Z3 array store application.
-
+
>>> a = Array('a', IntSort(), IntSort())
>>> is_store(a)
False
@@ -4201,7 +4239,7 @@ def _valid_accessor(acc):
return isinstance(acc, tuple) and len(acc) == 2 and isinstance(acc[0], str) and (isinstance(acc[1], Datatype) or is_sort(acc[1]))
class Datatype:
- """Helper class for declaring Z3 datatypes.
+ """Helper class for declaring Z3 datatypes.
>>> List = Datatype('List')
>>> List.declare('cons', ('car', IntSort()), ('cdr', List))
@@ -4239,15 +4277,15 @@ class Datatype:
self.constructors.append((name, rec_name, args))
def declare(self, name, *args):
- """Declare constructor named `name` with the given accessors `args`.
- Each accessor is a pair `(name, sort)`, where `name` is a string and `sort` a Z3 sort or a reference to the datatypes being declared.
+ """Declare constructor named `name` with the given accessors `args`.
+ Each accessor is a pair `(name, sort)`, where `name` is a string and `sort` a Z3 sort or a reference to the datatypes being declared.
- In the followin example `List.declare('cons', ('car', IntSort()), ('cdr', List))`
- declares the constructor named `cons` that builds a new List using an integer and a List.
- It also declares the accessors `car` and `cdr`. The accessor `car` extracts the integer of a `cons` cell,
- and `cdr` the list of a `cons` cell. After all constructors were declared, we use the method create() to create
+ In the followin example `List.declare('cons', ('car', IntSort()), ('cdr', List))`
+ declares the constructor named `cons` that builds a new List using an integer and a List.
+ It also declares the accessors `car` and `cdr`. The accessor `car` extracts the integer of a `cons` cell,
+ and `cdr` the list of a `cons` cell. After all constructors were declared, we use the method create() to create
the actual datatype in Z3.
-
+
>>> List = Datatype('List')
>>> List.declare('cons', ('car', IntSort()), ('cdr', List))
>>> List.declare('nil')
@@ -4263,7 +4301,7 @@ class Datatype:
def create(self):
"""Create a Z3 datatype based on the constructors declared using the mehtod `declare()`.
-
+
The function `CreateDatatypes()` must be used to define mutually recursive datatypes.
>>> List = Datatype('List')
@@ -4295,7 +4333,7 @@ class ScopedConstructorList:
def CreateDatatypes(*ds):
"""Create mutually recursive Z3 datatypes using 1 or more Datatype helper objects.
-
+
In the following example we define a Tree-List using two mutually recursive datatypes.
>>> TreeList = Datatype('TreeList')
@@ -4388,8 +4426,8 @@ def CreateDatatypes(*ds):
class DatatypeSortRef(SortRef):
"""Datatype sorts."""
def num_constructors(self):
- """Return the number of constructors in the given Z3 datatype.
-
+ """Return the number of constructors in the given Z3 datatype.
+
>>> List = Datatype('List')
>>> List.declare('cons', ('car', IntSort()), ('cdr', List))
>>> List.declare('nil')
@@ -4418,12 +4456,12 @@ class DatatypeSortRef(SortRef):
if __debug__:
_z3_assert(idx < self.num_constructors(), "Invalid constructor index")
return FuncDeclRef(Z3_get_datatype_sort_constructor(self.ctx_ref(), self.ast, idx), self.ctx)
-
+
def recognizer(self, idx):
- """In Z3, each constructor has an associated recognizer predicate.
+ """In Z3, each constructor has an associated recognizer predicate.
If the constructor is named `name`, then the recognizer `is_name`.
-
+
>>> List = Datatype('List')
>>> List.declare('cons', ('car', IntSort()), ('cdr', List))
>>> List.declare('nil')
@@ -4449,7 +4487,7 @@ class DatatypeSortRef(SortRef):
def accessor(self, i, j):
"""In Z3, each constructor has 0 or more accessor. The number of accessors is equal to the arity of the constructor.
-
+
>>> List = Datatype('List')
>>> List.declare('cons', ('car', IntSort()), ('cdr', List))
>>> List.declare('nil')
@@ -4499,7 +4537,7 @@ def EnumSort(name, values, ctx=None):
for i in range(num):
_val_names[i] = to_symbol(values[i])
_values = (FuncDecl * num)()
- _testers = (FuncDecl * num)()
+ _testers = (FuncDecl * num)()
name = to_symbol(name)
S = DatatypeSortRef(Z3_mk_enumeration_sort(ctx.ref(), name, num, _val_names, _values, _testers), ctx)
V = []
@@ -4516,7 +4554,7 @@ def EnumSort(name, values, ctx=None):
class ParamsRef:
"""Set of parameters used to configure Solvers, Tactics and Simplifiers in Z3.
-
+
Consider using the function `args2params` to create instances of this object.
"""
def __init__(self, ctx=None):
@@ -4599,12 +4637,12 @@ class ParamDescrsRef:
"""Return the i-th parameter name in the parameter description `self`.
"""
return _symbol2py(self.ctx, Z3_param_descrs_get_name(self.ctx.ref(), self.descr, i))
-
+
def get_kind(self, n):
"""Return the kind of the parameter named `n`.
"""
return Z3_param_descrs_get_kind(self.ctx.ref(), self.descr, to_symbol(n, self.ctx))
-
+
def __getitem__(self, arg):
if _is_int(arg):
return self.get_name(arg)
@@ -4622,7 +4660,7 @@ class ParamDescrsRef:
class Goal(Z3PPObject):
"""Goal is a collection of constraints we want to find a solution or show to be unsatisfiable (infeasible).
-
+
Goals are processed using Tactics. A Tactic transforms a goal into a set of subgoals.
A goal has a solution if one of its subgoals has a solution.
A goal is unsatisfiable if all subgoals are unsatisfiable.
@@ -4660,13 +4698,13 @@ class Goal(Z3PPObject):
def inconsistent(self):
"""Return `True` if `self` contains the `False` constraints.
-
+
>>> x, y = Ints('x y')
>>> g = Goal()
>>> g.inconsistent()
False
>>> g.add(x == 0, x == 1)
- >>> g
+ >>> g
[x == 0, x == 1]
>>> g.inconsistent()
False
@@ -4678,7 +4716,7 @@ class Goal(Z3PPObject):
def prec(self):
"""Return the precision (under-approximation, over-approximation, or precise) of the goal `self`.
-
+
>>> g = Goal()
>>> g.prec() == Z3_GOAL_PRECISE
True
@@ -4708,7 +4746,7 @@ class Goal(Z3PPObject):
def size(self):
"""Return the number of constraints in the goal `self`.
-
+
>>> g = Goal()
>>> g.size()
0
@@ -4734,7 +4772,7 @@ class Goal(Z3PPObject):
def get(self, i):
"""Return a constraint in the goal `self`.
-
+
>>> g = Goal()
>>> x, y = Ints('x y')
>>> g.add(x == 0, y > x)
@@ -4747,7 +4785,7 @@ class Goal(Z3PPObject):
def __getitem__(self, arg):
"""Return a constraint in the goal `self`.
-
+
>>> g = Goal()
>>> x, y = Ints('x y')
>>> g.add(x == 0, y > x)
@@ -4762,7 +4800,7 @@ class Goal(Z3PPObject):
def assert_exprs(self, *args):
"""Assert constraints into the goal.
-
+
>>> x = Int('x')
>>> g = Goal()
>>> g.assert_exprs(x > 0, x < 2)
@@ -4777,7 +4815,7 @@ class Goal(Z3PPObject):
def append(self, *args):
"""Add constraints.
-
+
>>> x = Int('x')
>>> g = Goal()
>>> g.append(x > 0, x < 2)
@@ -4785,10 +4823,10 @@ class Goal(Z3PPObject):
[x > 0, x < 2]
"""
self.assert_exprs(*args)
-
+
def insert(self, *args):
"""Add constraints.
-
+
>>> x = Int('x')
>>> g = Goal()
>>> g.insert(x > 0, x < 2)
@@ -4799,7 +4837,7 @@ class Goal(Z3PPObject):
def add(self, *args):
"""Add constraints.
-
+
>>> x = Int('x')
>>> g = Goal()
>>> g.add(x > 0, x < 2)
@@ -4817,7 +4855,7 @@ class Goal(Z3PPObject):
def translate(self, target):
"""Copy goal `self` to context `target`.
-
+
>>> x = Int('x')
>>> g = Goal()
>>> g.add(x > 10)
@@ -4840,9 +4878,9 @@ class Goal(Z3PPObject):
def simplify(self, *arguments, **keywords):
"""Return a new simplified goal.
-
+
This method is essentially invoking the simplify tactic.
-
+
>>> g = Goal()
>>> x = Int('x')
>>> g.add(x + 1 >= 2)
@@ -4860,7 +4898,7 @@ class Goal(Z3PPObject):
def as_expr(self):
"""Return goal `self` as a single Z3 expression.
-
+
>>> x = Int('x')
>>> g = Goal()
>>> g.as_expr()
@@ -4902,7 +4940,7 @@ class AstVector(Z3PPObject):
def __del__(self):
if self.vector != None:
Z3_ast_vector_dec_ref(self.ctx.ref(), self.vector)
-
+
def __len__(self):
"""Return the size of the vector `self`.
@@ -4933,7 +4971,7 @@ class AstVector(Z3PPObject):
def __setitem__(self, i, v):
"""Update AST at position `i`.
-
+
>>> A = AstVector()
>>> A.push(Int('x') + 1)
>>> A.push(Int('y'))
@@ -4946,7 +4984,7 @@ class AstVector(Z3PPObject):
if i >= self.__len__():
raise IndexError
Z3_ast_vector_set(self.ctx.ref(), self.vector, i, v.as_ast())
-
+
def push(self, v):
"""Add `v` in the end of the vector.
@@ -4994,7 +5032,7 @@ class AstVector(Z3PPObject):
if elem.eq(item):
return True
return False
-
+
def translate(self, other_ctx):
"""Copy vector `self` to context `other_ctx`.
@@ -5039,7 +5077,7 @@ class AstMap:
Z3_ast_map_dec_ref(self.ctx.ref(), self.map)
def __len__(self):
- """Return the size of the map.
+ """Return the size of the map.
>>> M = AstMap()
>>> len(M)
@@ -5063,7 +5101,7 @@ class AstMap:
False
"""
return Z3_ast_map_contains(self.ctx.ref(), self.map, key.as_ast())
-
+
def __getitem__(self, key):
"""Retrieve the value associated with key `key`.
@@ -5154,7 +5192,7 @@ class FuncEntry:
def num_args(self):
"""Return the number of arguments in the given entry.
-
+
>>> f = Function('f', IntSort(), IntSort(), IntSort())
>>> s = Solver()
>>> s.add(f(0, 1) == 10, f(1, 2) == 20, f(1, 0) == 10)
@@ -5172,7 +5210,7 @@ class FuncEntry:
def arg_value(self, idx):
"""Return the value of argument `idx`.
-
+
>>> f = Function('f', IntSort(), IntSort(), IntSort())
>>> s = Solver()
>>> s.add(f(0, 1) == 10, f(1, 2) == 20, f(1, 0) == 10)
@@ -5203,7 +5241,7 @@ class FuncEntry:
def value(self):
"""Return the value of the function at point `self`.
-
+
>>> f = Function('f', IntSort(), IntSort(), IntSort())
>>> s = Solver()
>>> s.add(f(0, 1) == 10, f(1, 2) == 20, f(1, 0) == 10)
@@ -5222,7 +5260,7 @@ class FuncEntry:
10
"""
return _to_expr_ref(Z3_func_entry_get_value(self.ctx.ref(), self.entry), self.ctx)
-
+
def as_list(self):
"""Return entry `self` as a Python list.
>>> f = Function('f', IntSort(), IntSort(), IntSort())
@@ -5244,7 +5282,7 @@ class FuncEntry:
def __repr__(self):
return repr(self.as_list())
-
+
class FuncInterp(Z3PPObject):
"""Stores the interpretation of a function in a Z3 model."""
@@ -5310,7 +5348,7 @@ class FuncInterp(Z3PPObject):
1
"""
return int(Z3_func_interp_get_arity(self.ctx.ref(), self.f))
-
+
def entry(self, idx):
"""Return an entry at position `idx < self.num_entries()` in the function interpretation `self`.
@@ -5334,7 +5372,7 @@ class FuncInterp(Z3PPObject):
if idx >= self.num_entries():
raise IndexError
return FuncEntry(Z3_func_interp_get_entry(self.ctx.ref(), self.f, idx), self.ctx)
-
+
def as_list(self):
"""Return the function interpretation as a Python list.
>>> f = Function('f', IntSort(), IntSort())
@@ -5405,7 +5443,7 @@ class ModelRef(Z3PPObject):
def evaluate(self, t, model_completion=False):
"""Alias for `eval`.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.add(x > 0, x < 2)
@@ -5477,7 +5515,7 @@ class ModelRef(Z3PPObject):
def num_sorts(self):
"""Return the number of unintepreted sorts that contain an interpretation in the model `self`.
-
+
>>> A = DeclareSort('A')
>>> a, b = Consts('a b', A)
>>> s = Solver()
@@ -5492,7 +5530,7 @@ class ModelRef(Z3PPObject):
def get_sort(self, idx):
"""Return the unintepreted sort at position `idx` < self.num_sorts().
-
+
>>> A = DeclareSort('A')
>>> B = DeclareSort('B')
>>> a1, a2 = Consts('a1 a2', A)
@@ -5512,7 +5550,7 @@ class ModelRef(Z3PPObject):
if idx >= self.num_sorts():
raise IndexError
return _to_sort_ref(Z3_model_get_sort(self.ctx.ref(), self.model, idx), self.ctx)
-
+
def sorts(self):
"""Return all uninterpreted sorts that have an interpretation in the model `self`.
@@ -5552,7 +5590,7 @@ class ModelRef(Z3PPObject):
def __getitem__(self, idx):
"""If `idx` is an integer, then the declaration at position `idx` in the model `self` is returned. If `idx` is a declaration, then the actual interpreation is returned.
-
+
The elements can be retrieved using position or the actual declaration.
>>> f = Function('f', IntSort(), IntSort())
@@ -5658,9 +5696,9 @@ class Statistics:
return Z3_stats_to_string(self.ctx.ref(), self.stats)
def __len__(self):
- """Return the number of statistical counters.
+ """Return the number of statistical counters.
- >>> x = Int('x')
+ >>> x = Int('x')
>>> s = Then('simplify', 'nlsat').solver()
>>> s.add(x > 0)
>>> s.check()
@@ -5674,7 +5712,7 @@ class Statistics:
def __getitem__(self, idx):
"""Return the value of statistical counter at position `idx`. The result is a pair (key, value).
- >>> x = Int('x')
+ >>> x = Int('x')
>>> s = Then('simplify', 'nlsat').solver()
>>> s.add(x > 0)
>>> s.check()
@@ -5694,11 +5732,11 @@ class Statistics:
else:
val = Z3_stats_get_double_value(self.ctx.ref(), self.stats, idx)
return (Z3_stats_get_key(self.ctx.ref(), self.stats, idx), val)
-
+
def keys(self):
"""Return the list of statistical counters.
-
- >>> x = Int('x')
+
+ >>> x = Int('x')
>>> s = Then('simplify', 'nlsat').solver()
>>> s.add(x > 0)
>>> s.check()
@@ -5710,7 +5748,7 @@ class Statistics:
def get_key_value(self, key):
"""Return the value of a particular statistical counter.
- >>> x = Int('x')
+ >>> x = Int('x')
>>> s = Then('simplify', 'nlsat').solver()
>>> s.add(x > 0)
>>> s.check()
@@ -5726,19 +5764,19 @@ class Statistics:
else:
return Z3_stats_get_double_value(self.ctx.ref(), self.stats, idx)
raise Z3Exception("unknown key")
-
+
def __getattr__(self, name):
"""Access the value of statistical using attributes.
-
+
Remark: to access a counter containing blank spaces (e.g., 'nlsat propagations'),
we should use '_' (e.g., 'nlsat_propagations').
- >>> x = Int('x')
+ >>> x = Int('x')
>>> s = Then('simplify', 'nlsat').solver()
>>> s.add(x > 0)
>>> s.check()
sat
- >>> st = s.statistics()
+ >>> st = s.statistics()
>>> st.nlsat_propagations
2
>>> st.nlsat_stages
@@ -5749,7 +5787,7 @@ class Statistics:
return self.get_key_value(key)
except Z3Exception:
raise AttributeError
-
+
#########################################
#
# Solver
@@ -5757,7 +5795,7 @@ class Statistics:
#########################################
class CheckSatResult:
"""Represents the result of a satisfiability check: sat, unsat, unknown.
-
+
>>> s = Solver()
>>> s.check()
sat
@@ -5793,7 +5831,7 @@ class CheckSatResult:
sat = CheckSatResult(Z3_L_TRUE)
unsat = CheckSatResult(Z3_L_FALSE)
-unknown = CheckSatResult(Z3_L_UNDEF)
+unknown = CheckSatResult(Z3_L_UNDEF)
class Solver(Z3PPObject):
"""Solver API provides methods for implementing the main SMT 2.0 commands: push, pop, check, get-model, etc."""
@@ -5814,7 +5852,7 @@ class Solver(Z3PPObject):
def set(self, *args, **keys):
"""Set a configuration option. The method `help()` return a string containing all available options.
-
+
>>> s = Solver()
>>> # The option MBQI can be set using three different approaches.
>>> s.set(mbqi=True)
@@ -5848,7 +5886,7 @@ class Solver(Z3PPObject):
def pop(self, num=1):
"""Backtrack \c num backtracking points.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.add(x > 0)
@@ -5870,7 +5908,7 @@ class Solver(Z3PPObject):
def reset(self):
"""Remove all asserted constraints and backtracking points created using `push()`.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.add(x > 0)
@@ -5881,10 +5919,10 @@ class Solver(Z3PPObject):
[]
"""
Z3_solver_reset(self.ctx.ref(), self.solver)
-
+
def assert_exprs(self, *args):
"""Assert constraints into the solver.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.assert_exprs(x > 0, x < 2)
@@ -5903,7 +5941,7 @@ class Solver(Z3PPObject):
def add(self, *args):
"""Assert constraints into the solver.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.add(x > 0, x < 2)
@@ -5914,7 +5952,7 @@ class Solver(Z3PPObject):
def append(self, *args):
"""Assert constraints into the solver.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.append(x > 0, x < 2)
@@ -5925,7 +5963,7 @@ class Solver(Z3PPObject):
def insert(self, *args):
"""Assert constraints into the solver.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.insert(x > 0, x < 2)
@@ -5936,9 +5974,9 @@ class Solver(Z3PPObject):
def assert_and_track(self, a, p):
"""Assert constraint `a` and track it in the unsat core using the Boolean constant `p`.
-
+
If `p` is a string, it will be automatically converted into a Boolean constant.
-
+
>>> x = Int('x')
>>> p3 = Bool('p3')
>>> s = Solver()
@@ -5966,7 +6004,7 @@ class Solver(Z3PPObject):
def check(self, *assumptions):
"""Check whether the assertions in the given solver plus the optional assumptions are consistent or not.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.check()
@@ -5993,9 +6031,9 @@ class Solver(Z3PPObject):
return CheckSatResult(r)
def model(self):
- """Return a model for the last `check()`.
-
- This function raises an exception if
+ """Return a model for the last `check()`.
+
+ This function raises an exception if
a model is not available (e.g., last `check()` returned unsat).
>>> s = Solver()
@@ -6013,11 +6051,11 @@ class Solver(Z3PPObject):
def unsat_core(self):
"""Return a subset (as an AST vector) of the assumptions provided to the last check().
-
+
These are the assumptions Z3 used in the unsatisfiability proof.
- Assumptions are available in Z3. They are used to extract unsatisfiable cores.
- They may be also used to "retract" assumptions. Note that, assumptions are not really
- "soft constraints", but they can be used to implement them.
+ Assumptions are available in Z3. They are used to extract unsatisfiable cores.
+ They may be also used to "retract" assumptions. Note that, assumptions are not really
+ "soft constraints", but they can be used to implement them.
>>> p1, p2, p3 = Bools('p1 p2 p3')
>>> x, y = Ints('x y')
@@ -6049,7 +6087,7 @@ class Solver(Z3PPObject):
def assertions(self):
"""Return an AST vector containing all added constraints.
-
+
>>> s = Solver()
>>> s.assertions()
[]
@@ -6063,7 +6101,7 @@ class Solver(Z3PPObject):
def statistics(self):
"""Return statistics for the last `check()`.
-
+
>>> s = SimpleSolver()
>>> x = Int('x')
>>> s.add(x > 0)
@@ -6081,7 +6119,7 @@ class Solver(Z3PPObject):
def reason_unknown(self):
"""Return a string describing why the last `check()` returned `unknown`.
-
+
>>> x = Int('x')
>>> s = SimpleSolver()
>>> s.add(2**x == 4)
@@ -6091,7 +6129,7 @@ class Solver(Z3PPObject):
'(incomplete (theory arithmetic))'
"""
return Z3_solver_get_reason_unknown(self.ctx.ref(), self.solver)
-
+
def help(self):
"""Display a string describing all available options."""
print(Z3_solver_get_help(self.ctx.ref(), self.solver))
@@ -6105,8 +6143,8 @@ class Solver(Z3PPObject):
return obj_to_string(self)
def translate(self, target):
- """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`.
-
+ """Translate `self` to the context `target`. That is, return a copy of `self` in the context `target`.
+
>>> c1 = Context()
>>> c2 = Context()
>>> s1 = Solver(ctx=c1)
@@ -6116,10 +6154,10 @@ class Solver(Z3PPObject):
_z3_assert(isinstance(target, Context), "argument must be a Z3 context")
solver = Z3_solver_translate(self.ctx.ref(), self.solver, target.ref())
return Solver(solver, target)
-
+
def sexpr(self):
"""Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
-
+
>>> x = Int('x')
>>> s = Solver()
>>> s.add(x > 0)
@@ -6145,7 +6183,7 @@ class Solver(Z3PPObject):
return Z3_benchmark_to_smtlib_string(self.ctx.ref(), "benchmark generated from python API", "", "unknown", "", sz1, v, e)
def SolverFor(logic, ctx=None):
- """Create a solver customized for the given logic.
+ """Create a solver customized for the given logic.
The parameter `logic` is a string. It should be contains
the name of a SMT-LIB logic.
@@ -6166,7 +6204,7 @@ def SolverFor(logic, ctx=None):
def SimpleSolver(ctx=None):
"""Return a simple general purpose solver with limited amount of preprocessing.
-
+
>>> s = SimpleSolver()
>>> x = Int('x')
>>> s.add(x > 0)
@@ -6184,7 +6222,7 @@ def SimpleSolver(ctx=None):
class Fixedpoint(Z3PPObject):
"""Fixedpoint API provides methods for solving with recursive predicates"""
-
+
def __init__(self, fixedpoint=None, ctx=None):
assert fixedpoint == None or ctx != None
self.ctx = _get_ctx(ctx)
@@ -6201,7 +6239,7 @@ class Fixedpoint(Z3PPObject):
Z3_fixedpoint_dec_ref(self.ctx.ref(), self.fixedpoint)
def set(self, *args, **keys):
- """Set a configuration option. The method `help()` return a string containing all available options.
+ """Set a configuration option. The method `help()` return a string containing all available options.
"""
p = args2params(args, keys, self.ctx)
Z3_fixedpoint_set_params(self.ctx.ref(), self.fixedpoint, p.params)
@@ -6209,11 +6247,11 @@ class Fixedpoint(Z3PPObject):
def help(self):
"""Display a string describing all available options."""
print(Z3_fixedpoint_get_help(self.ctx.ref(), self.fixedpoint))
-
+
def param_descrs(self):
"""Return the parameter description set."""
return ParamDescrsRef(Z3_fixedpoint_get_param_descrs(self.ctx.ref(), self.fixedpoint), self.ctx)
-
+
def assert_exprs(self, *args):
"""Assert constraints as background axioms for the fixedpoint solver."""
args = _get_args(args)
@@ -6257,16 +6295,16 @@ class Fixedpoint(Z3PPObject):
name = to_symbol(name, self.ctx)
if body == None:
head = self.abstract(head)
- Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name)
+ Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, head.as_ast(), name)
else:
body = _get_args(body)
f = self.abstract(Implies(And(body, self.ctx),head))
Z3_fixedpoint_add_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
-
+
def rule(self, head, body = None, name = None):
"""Assert rules defining recursive predicates to the fixedpoint solver. Alias for add_rule."""
self.add_rule(head, body, name)
-
+
def fact(self, head, name = None):
"""Assert facts defining recursive predicates to the fixedpoint solver. Alias for add_rule."""
self.add_rule(head, None, name)
@@ -6277,7 +6315,7 @@ class Fixedpoint(Z3PPObject):
"""
query = _get_args(query)
sz = len(query)
- if sz >= 1 and isinstance(query[0], FuncDeclRef):
+ if sz >= 1 and isinstance(query[0], FuncDeclRef):
_decls = (FuncDecl * sz)()
i = 0
for q in query:
@@ -6310,7 +6348,7 @@ class Fixedpoint(Z3PPObject):
f = self.abstract(Implies(And(body, self.ctx),head))
Z3_fixedpoint_update_rule(self.ctx.ref(), self.fixedpoint, f.as_ast(), name)
- def get_answer(self):
+ def get_answer(self):
"""Retrieve answer from last query call."""
r = Z3_fixedpoint_get_answer(self.ctx.ref(), self.fixedpoint)
return _to_expr_ref(r, self.ctx)
@@ -6323,7 +6361,7 @@ class Fixedpoint(Z3PPObject):
"""Retrieve properties known about predicate for the level'th unfolding. -1 is treated as the limit (infinity)"""
r = Z3_fixedpoint_get_cover_delta(self.ctx.ref(), self.fixedpoint, level, predicate.ast)
return _to_expr_ref(r, self.ctx)
-
+
def add_cover(self, level, predicate, property):
"""Add property to predicate for the level'th unfolding. -1 is treated as infinity (infinity)"""
Z3_fixedpoint_add_cover(self.ctx.ref(), self.fixedpoint, level, predicate.ast, property.ast)
@@ -6347,7 +6385,7 @@ class Fixedpoint(Z3PPObject):
def parse_string(self, s):
"""Parse rules and queries from a string"""
return AstVector(Z3_fixedpoint_from_string(self.ctx.ref(), self.fixedpoint, s), self.ctx)
-
+
def parse_file(self, f):
"""Parse rules and queries from a file"""
return AstVector(Z3_fixedpoint_from_file(self.ctx.ref(), self.fixedpoint, f), self.ctx)
@@ -6365,7 +6403,7 @@ class Fixedpoint(Z3PPObject):
return self.sexpr()
def sexpr(self):
- """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
+ """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
"""
return Z3_fixedpoint_to_string(self.ctx.ref(), self.fixedpoint, 0, (Ast * 0)())
@@ -6376,7 +6414,7 @@ class Fixedpoint(Z3PPObject):
"""
args, len = _to_ast_array(queries)
return Z3_fixedpoint_to_string(self.ctx.ref(), self.fixedpoint, len, args)
-
+
def statistics(self):
"""Return statistics for the last `query()`.
"""
@@ -6395,7 +6433,7 @@ class Fixedpoint(Z3PPObject):
vars = _get_args(vars)
for v in vars:
self.vars += [v]
-
+
def abstract(self, fml, is_forall=True):
if self.vars == []:
return fml
@@ -6442,18 +6480,18 @@ def is_finite_domain_sort(s):
class FiniteDomainRef(ExprRef):
"""Finite-domain expressions."""
-
+
def sort(self):
"""Return the sort of the finite-domain expression `self`."""
return FiniteDomainSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
def as_string(self):
"""Return a Z3 floating point expression as a Python string."""
- return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
+ return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
def is_finite_domain(a):
"""Return `True` if `a` is a Z3 finite-domain expression.
-
+
>>> s = FiniteDomainSort('S', 100)
>>> b = Const('b', s)
>>> is_finite_domain(b)
@@ -6463,13 +6501,13 @@ def is_finite_domain(a):
"""
return isinstance(a, FiniteDomainRef)
-
+
class FiniteDomainNumRef(FiniteDomainRef):
"""Integer values."""
def as_long(self):
- """Return a Z3 finite-domain numeral as a Python long (bignum) numeral.
-
+ """Return a Z3 finite-domain numeral as a Python long (bignum) numeral.
+
>>> s = FiniteDomainSort('S', 100)
>>> v = FiniteDomainVal(3, s)
>>> v
@@ -6489,10 +6527,10 @@ class FiniteDomainNumRef(FiniteDomainRef):
"""
return Z3_get_numeral_string(self.ctx_ref(), self.as_ast())
-
+
def FiniteDomainVal(val, sort, ctx=None):
"""Return a Z3 finite-domain value. If `ctx=None`, then the global context is used.
-
+
>>> s = FiniteDomainSort('S', 256)
>>> FiniteDomainVal(255, s)
255
@@ -6503,7 +6541,7 @@ def FiniteDomainVal(val, sort, ctx=None):
_z3_assert(is_finite_domain_sort(sort), "Expected finite-domain sort" )
ctx = sort.ctx
return FiniteDomainNumRef(Z3_mk_numeral(ctx.ref(), _to_int_str(val), sort.ast), ctx)
-
+
def is_finite_domain_value(a):
"""Return `True` if `a` is a Z3 finite-domain value.
@@ -6535,7 +6573,7 @@ class OptimizeObjective:
def lower(self):
opt = self._opt
return _to_expr_ref(Z3_optimize_get_lower(opt.ctx.ref(), opt.optimize, self._value), opt.ctx)
-
+
def upper(self):
opt = self._opt
return _to_expr_ref(Z3_optimize_get_upper(opt.ctx.ref(), opt.optimize, self._value), opt.ctx)
@@ -6548,7 +6586,7 @@ class OptimizeObjective:
class Optimize(Z3PPObject):
"""Optimize API provides methods for solving using objective functions and weighted soft constraints"""
-
+
def __init__(self, ctx=None):
self.ctx = _get_ctx(ctx)
self.optimize = Z3_mk_optimize(self.ctx.ref())
@@ -6559,7 +6597,7 @@ class Optimize(Z3PPObject):
Z3_optimize_dec_ref(self.ctx.ref(), self.optimize)
def set(self, *args, **keys):
- """Set a configuration option. The method `help()` return a string containing all available options.
+ """Set a configuration option. The method `help()` return a string containing all available options.
"""
p = args2params(args, keys, self.ctx)
Z3_optimize_set_params(self.ctx.ref(), self.optimize, p.params)
@@ -6567,11 +6605,11 @@ class Optimize(Z3PPObject):
def help(self):
"""Display a string describing all available options."""
print(Z3_optimize_get_help(self.ctx.ref(), self.optimize))
-
+
def param_descrs(self):
"""Return the parameter description set."""
return ParamDescrsRef(Z3_optimize_get_param_descrs(self.ctx.ref(), self.optimize), self.ctx)
-
+
def assert_exprs(self, *args):
"""Assert constraints as background axioms for the optimize solver."""
args = _get_args(args)
@@ -6643,23 +6681,23 @@ class Optimize(Z3PPObject):
if not isinstance(obj, OptimizeObjective):
raise Z3Exception("Expecting objective handle returned by maximize/minimize")
return obj.upper()
-
+
def __repr__(self):
"""Return a formatted string with all added rules and constraints."""
return self.sexpr()
def sexpr(self):
- """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
+ """Return a formatted string (in Lisp-like format) with all added constraints. We say the string is in s-expression format.
"""
return Z3_optimize_to_string(self.ctx.ref(), self.optimize)
-
+
def statistics(self):
"""Return statistics for the last `query()`.
"""
return Statistics(Z3_optimize_get_statistics(self.ctx.ref(), self.optimize), self.ctx)
-
+
#########################################
#
@@ -6668,7 +6706,7 @@ class Optimize(Z3PPObject):
#########################################
class ApplyResult(Z3PPObject):
"""An ApplyResult object contains the subgoals produced by a tactic when applied to a goal. It also contains model and proof converters."""
-
+
def __init__(self, result, ctx):
self.result = result
self.ctx = ctx
@@ -6679,7 +6717,7 @@ class ApplyResult(Z3PPObject):
def __len__(self):
"""Return the number of subgoals in `self`.
-
+
>>> a, b = Ints('a b')
>>> g = Goal()
>>> g.add(Or(a == 0, a == 1), Or(b == 0, b == 1), a > b)
@@ -6704,7 +6742,7 @@ class ApplyResult(Z3PPObject):
>>> g.add(Or(a == 0, a == 1), Or(b == 0, b == 1), a > b)
>>> t = Tactic('split-clause')
>>> r = t(g)
- >>> r[0]
+ >>> r[0]
[a == 0, Or(b == 0, b == 1), a > b]
>>> r[1]
[a == 1, Or(b == 0, b == 1), a > b]
@@ -6728,7 +6766,7 @@ class ApplyResult(Z3PPObject):
>>> g.add(Or(a == 0, a == 1), Or(b == 0, b == 1), a > b)
>>> t = Then(Tactic('split-clause'), Tactic('solve-eqs'))
>>> r = t(g)
- >>> r[0]
+ >>> r[0]
[Or(b == 0, b == 1), Not(0 <= b)]
>>> r[1]
[Or(b == 0, b == 1), Not(1 <= b)]
@@ -6753,7 +6791,7 @@ class ApplyResult(Z3PPObject):
def as_expr(self):
"""Return a Z3 expression consisting of all subgoals.
-
+
>>> x = Int('x')
>>> g = Goal()
>>> g.add(x > 1)
@@ -6776,7 +6814,7 @@ class ApplyResult(Z3PPObject):
return self[0].as_expr()
else:
return Or([ self[i].as_expr() for i in range(len(self)) ])
-
+
#########################################
#
# Tactics
@@ -6810,7 +6848,7 @@ class Tactic:
The solver supports the methods `push()` and `pop()`, but it
will always solve each `check()` from scratch.
-
+
>>> t = Then('simplify', 'nlsat')
>>> s = t.solver()
>>> x = Real('x')
@@ -6824,7 +6862,7 @@ class Tactic:
def apply(self, goal, *arguments, **keywords):
"""Apply tactic `self` to the given goal or Z3 Boolean expression using the given options.
-
+
>>> x, y = Ints('x y')
>>> t = Tactic('solve-eqs')
>>> t.apply(And(x == 0, y >= x + 1))
@@ -6841,7 +6879,7 @@ class Tactic:
def __call__(self, goal, *arguments, **keywords):
"""Apply tactic `self` to the given goal or Z3 Boolean expression using the given options.
-
+
>>> x, y = Ints('x y')
>>> t = Tactic('solve-eqs')
>>> t(And(x == 0, y >= x + 1))
@@ -6887,7 +6925,7 @@ def _or_else(t1, t2, ctx=None):
def AndThen(*ts, **ks):
"""Return a tactic that applies the tactics in `*ts` in sequence.
-
+
>>> x, y = Ints('x y')
>>> t = AndThen(Tactic('simplify'), Tactic('solve-eqs'))
>>> t(And(x == 0, y > x + 1))
@@ -6906,7 +6944,7 @@ def AndThen(*ts, **ks):
def Then(*ts, **ks):
"""Return a tactic that applies the tactics in `*ts` in sequence. Shorthand for AndThen(*ts, **ks).
-
+
>>> x, y = Ints('x y')
>>> t = Then(Tactic('simplify'), Tactic('solve-eqs'))
>>> t(And(x == 0, y > x + 1))
@@ -6915,7 +6953,7 @@ def Then(*ts, **ks):
Not(y <= 1)
"""
return AndThen(*ts, **ks)
-
+
def OrElse(*ts, **ks):
"""Return a tactic that applies the tactics in `*ts` until one of them succeeds (it doesn't fail).
@@ -6956,7 +6994,7 @@ def ParOr(*ts, **ks):
def ParThen(t1, t2, ctx=None):
"""Return a tactic that applies t1 and then t2 to every subgoal produced by t1. The subgoals are processed in parallel.
-
+
>>> x, y = Ints('x y')
>>> t = ParThen(Tactic('split-clause'), Tactic('propagate-values'))
>>> t(And(Or(x == 1, x == 2), y == x + 1))
@@ -6974,7 +7012,7 @@ def ParAndThen(t1, t2, ctx=None):
def With(t, *args, **keys):
"""Return a tactic that applies tactic `t` using the given configuration options.
-
+
>>> x, y = Ints('x y')
>>> t = With(Tactic('simplify'), som=True)
>>> t((x + 1)*(y + 2) == 0)
@@ -7006,7 +7044,7 @@ def Repeat(t, max=4294967295, ctx=None):
def TryFor(t, ms, ctx=None):
"""Return a tactic that applies `t` to a given goal for `ms` milliseconds.
-
+
If `t` does not terminate in `ms` milliseconds, then it fails.
"""
t = _to_tactic(t, ctx)
@@ -7014,7 +7052,7 @@ def TryFor(t, ms, ctx=None):
def tactics(ctx=None):
"""Return a list of all available tactics in Z3.
-
+
>>> l = tactics()
>>> l.count('simplify') == 1
True
@@ -7158,7 +7196,7 @@ class Probe:
def __call__(self, goal):
"""Evaluate the probe `self` in the given goal.
-
+
>>> p = Probe('size')
>>> x = Int('x')
>>> g = Goal()
@@ -7180,13 +7218,13 @@ class Probe:
1.0
"""
if __debug__:
- _z3_assert(isinstance(goal, Goal) or isinstance(goal, BoolRef), "Z3 Goal or Boolean expression expected")
+ _z3_assert(isinstance(goal, Goal) or isinstance(goal, BoolRef), "Z3 Goal or Boolean expression expected")
goal = _to_goal(goal)
return Z3_probe_apply(self.ctx.ref(), self.probe, goal.goal)
def is_probe(p):
"""Return `True` if `p` is a Z3 probe.
-
+
>>> is_probe(Int('x'))
False
>>> is_probe(Probe('memory'))
@@ -7202,7 +7240,7 @@ def _to_probe(p, ctx=None):
def probes(ctx=None):
"""Return a list of all available probes in Z3.
-
+
>>> l = probes()
>>> l.count('memory') == 1
True
@@ -7212,7 +7250,7 @@ def probes(ctx=None):
def probe_description(name, ctx=None):
"""Return a short description for the probe named `name`.
-
+
>>> d = probe_description('memory')
"""
ctx = _get_ctx(ctx)
@@ -7272,7 +7310,7 @@ def FailIf(p, ctx=None):
def When(p, t, ctx=None):
"""Return a tactic that applies tactic `t` only if probe `p` evaluates to true. Otherwise, it returns the input goal unmodified.
-
+
>>> t = When(Probe('size') > 2, Tactic('simplify'))
>>> x, y = Ints('x y')
>>> g = Goal()
@@ -7290,7 +7328,7 @@ def When(p, t, ctx=None):
def Cond(p, t1, t2, ctx=None):
"""Return a tactic that applies tactic `t1` to a goal if probe `p` evaluates to true, and `t2` otherwise.
-
+
>>> t = Cond(Probe('is-qfnra'), Tactic('qfnra'), Tactic('smt'))
"""
p = _to_probe(p, ctx)
@@ -7308,7 +7346,7 @@ def simplify(a, *arguments, **keywords):
"""Simplify the expression `a` using the given options.
This function has many options. Use `help_simplify` to obtain the complete list.
-
+
>>> x = Int('x')
>>> y = Int('y')
>>> simplify(x + 1 + y + x + 1)
@@ -7338,7 +7376,7 @@ def simplify_param_descrs():
def substitute(t, *m):
"""Apply substitution m on t, m is a list of pairs of the form (from, to). Every occurrence in t of from is replaced with to.
-
+
>>> x = Int('x')
>>> y = Int('y')
>>> substitute(x + 1, (x, y + 1))
@@ -7364,7 +7402,7 @@ def substitute(t, *m):
def substitute_vars(t, *m):
"""Substitute the free variables in t with the expression in m.
-
+
>>> v0 = Var(0, IntSort())
>>> v1 = Var(1, IntSort())
>>> x = Int('x')
@@ -7383,8 +7421,8 @@ def substitute_vars(t, *m):
return _to_expr_ref(Z3_substitute_vars(t.ctx.ref(), t.as_ast(), num, _to), t.ctx)
def Sum(*args):
- """Create the sum of the Z3 expressions.
-
+ """Create the sum of the Z3 expressions.
+
>>> a, b, c = Ints('a b c')
>>> Sum(a, b, c)
a + b + c
@@ -7408,8 +7446,8 @@ def Sum(*args):
return ArithRef(Z3_mk_add(ctx.ref(), sz, _args), ctx)
def Product(*args):
- """Create the product of the Z3 expressions.
-
+ """Create the product of the Z3 expressions.
+
>>> a, b, c = Ints('a b c')
>>> Product(a, b, c)
a*b*c
@@ -7472,11 +7510,11 @@ def PbLe(args, k):
def solve(*args, **keywords):
"""Solve the constraints `*args`.
-
+
This is a simple function for creating demonstrations. It creates a solver,
configure it using the options in `keywords`, adds the constraints
in `args`, and invokes check.
-
+
>>> a = Int('a')
>>> solve(a > 0, a < 2)
[a = 1]
@@ -7500,7 +7538,7 @@ def solve(*args, **keywords):
def solve_using(s, *args, **keywords):
"""Solve the constraints `*args` using solver `s`.
-
+
This is a simple function for creating demonstrations. It is similar to `solve`,
but it uses the given solver `s`.
It configures solver `s` using the options in `keywords`, adds the constraints
@@ -7653,7 +7691,7 @@ def _dict2darray(decls, ctx):
def parse_smt2_string(s, sorts={}, decls={}, ctx=None):
"""Parse a string in SMT 2.0 format using the given sorts and decls.
-
+
The arguments sorts and decls are Python dictionaries used to initialize
the symbol table used for the SMT 2.0 parser.
@@ -7673,18 +7711,18 @@ def parse_smt2_string(s, sorts={}, decls={}, ctx=None):
def parse_smt2_file(f, sorts={}, decls={}, ctx=None):
"""Parse a file in SMT 2.0 format using the given sorts and decls.
-
+
This function is similar to parse_smt2_string().
"""
ctx = _get_ctx(ctx)
ssz, snames, ssorts = _dict2sarray(sorts, ctx)
dsz, dnames, ddecls = _dict2darray(decls, ctx)
return _to_expr_ref(Z3_parse_smtlib2_file(ctx.ref(), f, ssz, snames, ssorts, dsz, dnames, ddecls), ctx)
-
+
def Interpolant(a,ctx=None):
"""Create an interpolation operator.
-
- The argument is an interpolation pattern (see tree_interpolant).
+
+ The argument is an interpolation pattern (see tree_interpolant).
>>> x = Int('x')
>>> print(Interpolant(x>0))
@@ -7716,7 +7754,7 @@ def tree_interpolant(pat,p=None,ctx=None):
and moreover pat sigma implies false. In the simplest case
an interpolant for the pattern "(and (interp A) B)" maps A
- to an interpolant for A /\ B.
+ to an interpolant for A /\ B.
The return value is a vector of formulas representing sigma. This
vector contains sigma(phi) for each marked subformula of pat, in
@@ -7781,7 +7819,7 @@ def binary_interpolant(a,b,p=None,ctx=None):
solver that determines satisfiability.
x = Int('x')
- print binary_interpolant(x<0,x>2)
+ print(binary_interpolant(x<0,x>2))
Not(x >= 0)
"""
f = And(Interpolant(a),b)
@@ -7798,8 +7836,8 @@ def sequence_interpolant(v,p=None,ctx=None):
1) w[i] & v[i+1] implies w[i+1] (or false if i+1 = N)
2) All uninterpreted symbols in w[i] occur in both v[0]..v[i]
and v[i+1]..v[n]
-
- Requires len(v) >= 1.
+
+ Requires len(v) >= 1.
If a & b is satisfiable, raises an object of class ModelRef
that represents a model of a & b.
@@ -7821,13 +7859,14 @@ def sequence_interpolant(v,p=None,ctx=None):
f = And(Interpolant(f),v[i])
return tree_interpolant(f,p,ctx)
+
#########################################
#
# Floating-Point Arithmetic
#
#########################################
-
+
# Global default rounding mode
_dflt_rounding_mode = Z3_OP_FPA_RM_TOWARD_ZERO
_dflt_fpsort_ebits = 11
@@ -7875,8 +7914,32 @@ def _dflt_rm(ctx=None):
def _dflt_fps(ctx=None):
return get_default_fp_sort(ctx)
+def _coerce_fp_expr_list(alist, ctx):
+ first_fp_sort = None
+ for a in alist:
+ if is_fp(a):
+ if first_fp_sort == None:
+ first_fp_sort = a.sort()
+ elif first_fp_sort == a.sort():
+ pass # OK, same as before
+ else:
+ # we saw at least 2 different float sorts; something will
+ # throw a sort mismatch later, for now assume None.
+ first_fp_sort = None
+ break
+
+ r = []
+ for i in range(len(alist)):
+ a = alist[i]
+ if (isinstance(a, str) and a.contains('2**(') and a.endswith(')')) or _is_int(a) or isinstance(a, float) or isinstance(a, bool):
+ r.append(FPVal(a, None, first_fp_sort, ctx))
+ else:
+ r.append(a)
+ return _coerce_expr_list(r, ctx)
+
+
### FP Sorts
-
+
class FPSortRef(SortRef):
"""Floating-point sort."""
@@ -7978,10 +8041,10 @@ def is_fprm_sort(s):
return isinstance(s, FPRMSortRef)
### FP Expressions
-
+
class FPRef(ExprRef):
"""Floating-point expressions."""
-
+
def sort(self):
"""Return the sort of the floating-point expression `self`.
@@ -8014,24 +8077,24 @@ class FPRef(ExprRef):
return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
def __le__(self, other):
- return fpLEQ(self, other)
+ return fpLEQ(self, other, self.ctx)
def __lt__(self, other):
- return fpLT(self, other)
+ return fpLT(self, other, self.ctx)
def __ge__(self, other):
- return fpGEQ(self, other)
-
+ return fpGEQ(self, other, self.ctx)
+
def __gt__(self, other):
- return fpGT(self, other)
+ return fpGT(self, other, self.ctx)
def __ne__(self, other):
- return fpNEQ(self, other)
+ return fpNEQ(self, other, self.ctx)
def __add__(self, other):
"""Create the Z3 expression `self + other`.
-
+
>>> x = FP('x', FPSort(8, 24))
>>> y = FP('y', FPSort(8, 24))
>>> x + y
@@ -8039,22 +8102,22 @@ class FPRef(ExprRef):
>>> (x + y).sort()
FPSort(8, 24)
"""
- a, b = z3._coerce_exprs(self, other)
- return fpAdd(_dflt_rm(), self, other)
+ [a, b] = _coerce_fp_expr_list([self, other], self.ctx)
+ return fpAdd(_dflt_rm(), a, b, self.ctx)
def __radd__(self, other):
"""Create the Z3 expression `other + self`.
-
+
>>> x = FP('x', FPSort(8, 24))
>>> 10 + x
1.25*(2**3) + x
"""
- a, b = _coerce_exprs(self, other)
- return fpAdd(_dflt_rm(), other, self)
+ [a, b] = _coerce_fp_expr_list([other, self], self.ctx)
+ return fpAdd(_dflt_rm(), a, b, self.ctx)
def __sub__(self, other):
"""Create the Z3 expression `self - other`.
-
+
>>> x = FP('x', FPSort(8, 24))
>>> y = FP('y', FPSort(8, 24))
>>> x - y
@@ -8062,22 +8125,22 @@ class FPRef(ExprRef):
>>> (x - y).sort()
FPSort(8, 24)
"""
- a, b = z3._coerce_exprs(self, other)
- return fpSub(_dflt_rm(), self, other)
+ [a, b] = _coerce_fp_expr_list([self, other], self.ctx)
+ return fpSub(_dflt_rm(), a, b, self.ctx)
def __rsub__(self, other):
"""Create the Z3 expression `other - self`.
-
+
>>> x = FP('x', FPSort(8, 24))
>>> 10 - x
1.25*(2**3) - x
"""
- a, b = _coerce_exprs(self, other)
- return fpSub(_dflt_rm(), other, self)
+ [a, b] = _coerce_fp_expr_list([other, self], self.ctx)
+ return fpSub(_dflt_rm(), a, b, self.ctx)
def __mul__(self, other):
"""Create the Z3 expression `self * other`.
-
+
>>> x = FP('x', FPSort(8, 24))
>>> y = FP('y', FPSort(8, 24))
>>> x * y
@@ -8087,12 +8150,12 @@ class FPRef(ExprRef):
>>> 10 * y
1.25*(2**3) * y
"""
- a, b = z3._coerce_exprs(self, other)
- return fpMul(_dflt_rm(), self, other)
+ [a, b] = _coerce_fp_expr_list([self, other], self.ctx)
+ return fpMul(_dflt_rm(), a, b, self.ctx)
def __rmul__(self, other):
"""Create the Z3 expression `other * self`.
-
+
>>> x = FP('x', FPSort(8, 24))
>>> y = FP('y', FPSort(8, 24))
>>> x * y
@@ -8100,24 +8163,53 @@ class FPRef(ExprRef):
>>> x * 10
x * 1.25*(2**3)
"""
- a, b = _coerce_exprs(self, other)
- return fpMul(_dflt_rm(), other, self)
+ [a, b] = _coerce_fp_expr_list([other, self], self.ctx)
+ return fpMul(_dflt_rm(), a, b, self.ctx)
def __pos__(self):
"""Create the Z3 expression `+self`."""
return self
-
+
def __neg__(self):
"""Create the Z3 expression `-self`."""
return FPRef(fpNeg(self))
- def __truediv__(self, other):
- """Create the Z3 expression division `self / other`."""
- return self.__div__(other)
+ def __div__(self, other):
+ """Create the Z3 expression `self / other`.
- def __rtruediv__(self, other):
- """Create the Z3 expression division `other / self`."""
- return self.__rdiv__(other)
+ >>> x = FP('x', FPSort(8, 24))
+ >>> y = FP('y', FPSort(8, 24))
+ >>> x / y
+ x / y
+ >>> (x / y).sort()
+ FPSort(8, 24)
+ >>> 10 / y
+ 1.25*(2**3) / y
+ """
+ [a, b] = _coerce_fp_expr_list([self, other], self.ctx)
+ return fpDiv(_dflt_rm(), a, b, self.ctx)
+
+ def __rdiv__(self, other):
+ """Create the Z3 expression `other / self`.
+
+ >>> x = FP('x', FPSort(8, 24))
+ >>> y = FP('y', FPSort(8, 24))
+ >>> x / y
+ x / y
+ >>> x / 10
+ x / 1.25*(2**3)
+ """
+ [a, b] = _coerce_fp_expr_list([other, self], self.ctx)
+ return fpDiv(_dflt_rm(), a, b, self.ctx)
+
+ if not sys.version < '3':
+ def __truediv__(self, other):
+ """Create the Z3 expression division `self / other`."""
+ return self.__div__(other)
+
+ def __rtruediv__(self, other):
+ """Create the Z3 expression division `other / self`."""
+ return self.__rdiv__(other)
def __mod__(self, other):
"""Create the Z3 expression mod `self % other`."""
@@ -8134,7 +8226,7 @@ class FPRMRef(ExprRef):
"""Return a Z3 floating point expression as a Python string."""
return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
-
+
def RoundNearestTiesToEven(ctx=None):
ctx = _get_ctx(ctx)
return FPRMRef(Z3_mk_fpa_round_nearest_ties_to_even(ctx.ref()), ctx)
@@ -8190,7 +8282,7 @@ def is_fprm(a):
def is_fprm_value(a):
"""Return `True` if `a` is a Z3 floating-point rounding mode numeral value."""
return is_fprm(a) and _is_numeral(a.ctx, a.ast)
-
+
### FP Numerals
class FPNumRef(FPRef):
@@ -8253,7 +8345,7 @@ class FPNumRef(FPRef):
def exponent_as_long(self):
ptr = (ctypes.c_longlong * 1)()
if not Z3_fpa_get_numeral_exponent_int64(self.ctx.ref(), self.as_ast(), ptr):
- raise Z3Exception("error retrieving the exponent of a numeral.")
+ raise Z3Exception("error retrieving the exponent of a numeral.")
return ptr[0]
"""
@@ -8267,16 +8359,9 @@ class FPNumRef(FPRef):
s = Z3_fpa_get_numeral_string(self.ctx.ref(), self.as_ast())
return ("FPVal(%s, %s)" % (s, FPSortRef(self.sort()).as_string()))
-
-def _to_fpnum(num, ctx=None):
- if isinstance(num, FPNum):
- return num
- else:
- return FPNum(num, ctx)
-
def is_fp(a):
"""Return `True` if `a` is a Z3 floating-point expression.
-
+
>>> b = FP('b', FPSort(8, 24))
>>> is_fp(b)
True
@@ -8315,54 +8400,99 @@ def FPSort(ebits, sbits, ctx=None):
ctx = z3._get_ctx(ctx)
return FPSortRef(Z3_mk_fpa_sort(ctx.ref(), ebits, sbits), ctx)
-def _to_float_str(val):
+def _to_float_str(val, exp=0):
if isinstance(val, float):
- return str(val)
+ v = val.as_integer_ratio()
+ num = v[0]
+ den = v[1]
+ rvs = str(num) + '/' + str(den)
+ res = rvs + 'p' + _to_int_str(exp)
elif isinstance(val, bool):
if val:
- return "1.0"
+ res = "1.0"
else:
- return "0.0"
+ res = "0.0"
elif _is_int(val):
- return str(val)
+ res = str(val)
elif isinstance(val, str):
- return val
- if __debug__:
- _z3_assert(False, "Python value cannot be used as a double")
+ inx = val.find('*(2**')
+ if inx == -1:
+ res = val
+ elif val[-1] == ')':
+ res = val[0:inx]
+ exp = str(int(val[inx+5:-1]) + int(exp))
+ else:
+ _z3_assert(False, "String does not have floating-point numeral form.")
+ elif __debug__:
+ _z3_assert(False, "Python value cannot be used to create floating-point numerals.")
+ if exp == 0:
+ return res
+ else:
+ return res + 'p' + exp
+
def fpNaN(s):
+ """Create a Z3 floating-point NaN term.
+
+ >>> s = FPSort(8, 24)
+ >>> set_fpa_pretty(True)
+ >>> fpNaN(s)
+ NaN
+ >>> pb = get_fpa_pretty()
+ >>> set_fpa_pretty(False)
+ >>> fpNaN(s)
+ fpNaN(FPSort(8, 24))
+ >>> set_fpa_pretty(pb)
+ """
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_nan(s.ctx_ref(), s.ast), s.ctx)
def fpPlusInfinity(s):
+ """Create a Z3 floating-point +oo term.
+
+ >>> s = FPSort(8, 24)
+ >>> pb = get_fpa_pretty()
+ >>> set_fpa_pretty(True)
+ >>> fpPlusInfinity(s)
+ +oo
+ >>> set_fpa_pretty(False)
+ >>> fpPlusInfinity(s)
+ fpPlusInfinity(FPSort(8, 24))
+ >>> set_fpa_pretty(pb)
+ """
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, False), s.ctx)
def fpMinusInfinity(s):
+ """Create a Z3 floating-point -oo term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, True), s.ctx)
def fpInfinity(s, negative):
+ """Create a Z3 floating-point +oo or -oo term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
_z3_assert(isinstance(negative, bool), "expected Boolean flag")
return FPNumRef(Z3_mk_fpa_inf(s.ctx_ref(), s.ast, negative), s.ctx)
def fpPlusZero(s):
+ """Create a Z3 floating-point +0.0 term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, False), s.ctx)
def fpMinusZero(s):
+ """Create a Z3 floating-point -0.0 term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, True), s.ctx)
def fpZero(s, negative):
+ """Create a Z3 floating-point +0.0 or -0.0 term."""
_z3_assert(isinstance(s, FPSortRef), "sort mismatch")
_z3_assert(isinstance(negative, bool), "expected Boolean flag")
return FPNumRef(Z3_mk_fpa_zero(s.ctx_ref(), s.ast, negative), s.ctx)
def FPVal(sig, exp=None, fps=None, ctx=None):
"""Return a floating-point value of value `val` and sort `fps`. If `ctx=None`, then the global context is used.
-
+
>>> v = FPVal(20.0, FPSort(8, 24))
>>> v
1.25*(2**4)
@@ -8383,14 +8513,12 @@ def FPVal(sig, exp=None, fps=None, ctx=None):
fps = _dflt_fps(ctx)
_z3_assert(is_fp_sort(fps), "sort mismatch")
if exp == None:
- exp = 0
+ exp = 0
val = _to_float_str(sig)
- val = val + 'p'
- val = val + _to_int_str(exp)
return FPNumRef(Z3_mk_numeral(ctx.ref(), val, fps.ast), ctx)
def FP(name, fpsort, ctx=None):
- """Return a floating-point constant named `name`.
+ """Return a floating-point constant named `name`.
`fpsort` is the floating-point sort.
If `ctx=None`, then the global context is used.
@@ -8405,8 +8533,8 @@ def FP(name, fpsort, ctx=None):
>>> x2 = FP('x', word)
>>> eq(x, x2)
True
- """
- if isinstance(fpsort, FPSortRef):
+ """
+ if isinstance(fpsort, FPSortRef) and ctx is None:
ctx = fpsort.ctx
else:
ctx = _get_ctx(ctx)
@@ -8414,7 +8542,7 @@ def FP(name, fpsort, ctx=None):
def FPs(names, fpsort, ctx=None):
"""Return an array of floating-point constants.
-
+
>>> x, y, z = FPs('x y z', FPSort(8, 24))
>>> x.sort()
FPSort(8, 24)
@@ -8430,7 +8558,7 @@ def FPs(names, fpsort, ctx=None):
names = names.split(" ")
return [FP(name, fpsort, ctx) for name in names]
-def fpAbs(a):
+def fpAbs(a, ctx=None):
"""Create a Z3 floating-point absolute value expression.
>>> s = FPSort(8, 24)
@@ -8448,18 +8576,11 @@ def fpAbs(a):
>>> fpAbs(x).sort()
FPSort(8, 24)
"""
- ctx = None
- if not is_expr(a):
- ctx =_get_ctx(ctx)
- s = get_default_fp_sort(ctx)
- a = FPVal(a, s)
- else:
- ctx = a.ctx
- if __debug__:
- _z3_assert(is_fp(a), "First argument must be Z3 floating-point expression")
- return FPRef(Z3_mk_fpa_abs(a.ctx_ref(), a.as_ast()), a.ctx)
+ ctx = _get_ctx(ctx)
+ [a] = _coerce_fp_expr_list([a], ctx)
+ return FPRef(Z3_mk_fpa_abs(ctx.ref(), a.as_ast()), ctx)
-def fpNeg(a):
+def fpNeg(a, ctx=None):
"""Create a Z3 floating-point addition expression.
>>> s = FPSort(8, 24)
@@ -8470,18 +8591,63 @@ def fpNeg(a):
>>> fpNeg(x).sort()
FPSort(8, 24)
"""
- ctx = None
- if not is_expr(a):
- ctx =_get_ctx(ctx)
- s = get_default_fp_sort(ctx)
- a = FPVal(a, s)
- else:
- ctx = a.ctx
- if __debug__:
- _z3_assert(is_fp(a), "First argument must be Z3 floating-point expression")
- return FPRef(Z3_mk_fpa_neg(a.ctx_ref(), a.as_ast()), a.ctx)
+ ctx = _get_ctx(ctx)
+ [a] = _coerce_fp_expr_list([a], ctx)
+ return FPRef(Z3_mk_fpa_neg(ctx.ref(), a.as_ast()), ctx)
-def fpAdd(rm, a, b):
+def _mk_fp_unary(f, rm, a, ctx):
+ ctx = _get_ctx(ctx)
+ [a] = _coerce_fp_expr_list([a], ctx)
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a), "Second argument must be a Z3 floating-point expression")
+ return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast()), ctx)
+
+def _mk_fp_unary_norm(f, a, ctx):
+ ctx = _get_ctx(ctx)
+ [a] = _coerce_fp_expr_list([a], ctx)
+ if __debug__:
+ _z3_assert(is_fp(a), "First argument must be a Z3 floating-point expression")
+ return FPRef(f(ctx.ref(), a.as_ast()), ctx)
+
+def _mk_fp_unary_pred(f, a, ctx):
+ ctx = _get_ctx(ctx)
+ [a] = _coerce_fp_expr_list([a], ctx)
+ if __debug__:
+ _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
+ return BoolRef(f(ctx.ref(), a.as_ast()), ctx)
+
+def _mk_fp_bin(f, rm, a, b, ctx):
+ ctx = _get_ctx(ctx)
+ [a, b] = _coerce_fp_expr_list([a, b], ctx)
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
+ return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast(), b.as_ast()), ctx)
+
+def _mk_fp_bin_norm(f, a, b, ctx):
+ ctx = _get_ctx(ctx)
+ [a, b] = _coerce_fp_expr_list([a, b], ctx)
+ if __debug__:
+ _z3_assert(is_fp(a) or is_fp(b), "First or second argument must be a Z3 floating-point expression")
+ return FPRef(f(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
+
+def _mk_fp_bin_pred(f, a, b, ctx):
+ ctx = _get_ctx(ctx)
+ [a, b] = _coerce_fp_expr_list([a, b], ctx)
+ if __debug__:
+ _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
+ return BoolRef(f(ctx.ref(), a.as_ast(), b.as_ast()), ctx)
+
+def _mk_fp_tern(f, rm, a, b, c, ctx):
+ ctx = _get_ctx(ctx)
+ [a, b, c] = _coerce_fp_expr_list([a, b, c], ctx)
+ if __debug__:
+ _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
+ _z3_assert(is_fp(a) or is_fp(b) or is_fp(c), "At least one of the arguments must be a Z3 floating-point expression")
+ return FPRef(f(ctx.ref(), rm.as_ast(), a.as_ast(), b.as_ast(), c.as_ast()), ctx)
+
+def fpAdd(rm, a, b, ctx=None):
"""Create a Z3 floating-point addition expression.
>>> s = FPSort(8, 24)
@@ -8490,16 +8656,14 @@ def fpAdd(rm, a, b):
>>> y = FP('y', s)
>>> fpAdd(rm, x, y)
fpAdd(RNE(), x, y)
+ >>> fpAdd(RTZ(), x, y) # default rounding mode is RTZ
+ x + y
>>> fpAdd(rm, x, y).sort()
FPSort(8, 24)
"""
- if __debug__:
- _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
- _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
- a, b = _coerce_exprs(a, b)
- return FPRef(Z3_mk_fpa_add(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx)
+ return _mk_fp_bin(Z3_mk_fpa_add, rm, a, b, ctx)
-def fpSub(rm, a, b):
+def fpSub(rm, a, b, ctx=None):
"""Create a Z3 floating-point subtraction expression.
>>> s = FPSort(8, 24)
@@ -8511,13 +8675,9 @@ def fpSub(rm, a, b):
>>> fpSub(rm, x, y).sort()
FPSort(8, 24)
"""
- if __debug__:
- _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
- _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
- a, b = _coerce_exprs(a, b)
- return FPRef(Z3_mk_fpa_sub(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx)
+ return _mk_fp_bin(Z3_mk_fpa_sub, rm, a, b, ctx)
-def fpMul(rm, a, b):
+def fpMul(rm, a, b, ctx=None):
"""Create a Z3 floating-point multiplication expression.
>>> s = FPSort(8, 24)
@@ -8529,13 +8689,9 @@ def fpMul(rm, a, b):
>>> fpMul(rm, x, y).sort()
FPSort(8, 24)
"""
- if __debug__:
- _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
- _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
- a, b = _coerce_exprs(a, b)
- return FPRef(Z3_mk_fpa_mul(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx)
+ return _mk_fp_bin(Z3_mk_fpa_mul, rm, a, b, ctx)
-def fpDiv(rm, a, b):
+def fpDiv(rm, a, b, ctx=None):
"""Create a Z3 floating-point divison expression.
>>> s = FPSort(8, 24)
@@ -8547,13 +8703,9 @@ def fpDiv(rm, a, b):
>>> fpDiv(rm, x, y).sort()
FPSort(8, 24)
"""
- if __debug__:
- _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
- _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
- a, b = _coerce_exprs(a, b)
- return FPRef(Z3_mk_fpa_div(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast()), rm.ctx)
+ return _mk_fp_bin(Z3_mk_fpa_div, rm, a, b, ctx)
-def fpRem(a, b):
+def fpRem(a, b, ctx=None):
"""Create a Z3 floating-point remainder expression.
>>> s = FPSort(8, 24)
@@ -8564,12 +8716,9 @@ def fpRem(a, b):
>>> fpRem(x, y).sort()
FPSort(8, 24)
"""
- if __debug__:
- _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
- a, b = _coerce_exprs(a, b)
- return FPRef(Z3_mk_fpa_rem(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+ return _mk_fp_bin_norm(Z3_mk_fpa_rem, a, b, ctx)
-def fpMin(a, b):
+def fpMin(a, b, ctx=None):
"""Create a Z3 floating-point minimium expression.
>>> s = FPSort(8, 24)
@@ -8581,12 +8730,9 @@ def fpMin(a, b):
>>> fpMin(x, y).sort()
FPSort(8, 24)
"""
- if __debug__:
- _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
- a, b = _coerce_exprs(a, b)
- return FPRef(Z3_mk_fpa_min(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+ return _mk_fp_bin_norm(Z3_mk_fpa_min, a, b, ctx)
-def fpMax(a, b):
+def fpMax(a, b, ctx=None):
"""Create a Z3 floating-point maximum expression.
>>> s = FPSort(8, 24)
@@ -8598,146 +8744,110 @@ def fpMax(a, b):
>>> fpMax(x, y).sort()
FPSort(8, 24)
"""
- if __debug__:
- _z3_assert(is_fp(a) or is_fp(b), "Second or third argument must be a Z3 floating-point expression")
- a, b = _coerce_exprs(a, b)
- return FPRef(Z3_mk_fpa_max(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+ return _mk_fp_bin_norm(Z3_mk_fpa_max, a, b, ctx)
-def fpFMA(rm, a, b, c):
+def fpFMA(rm, a, b, c, ctx=None):
"""Create a Z3 floating-point fused multiply-add expression.
"""
- if __debug__:
- _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
- _z3_assert(is_fp(a) or is_fp(b) or is_fp(c), "Second, third, or fourth argument must be a Z3 floating-point expression")
- a, b, c = _coerce_expr_list([a, b, c])
- return FPRef(Z3_mk_fpa_fma(rm.ctx_ref(), rm.as_ast(), a.as_ast(), b.as_ast(), c.as_ast()), rm.ctx)
+ return _mk_fp_tern(Z3_mk_fpa_fma, rm, a, b, c, ctx)
-def fpSqrt(rm, a):
+def fpSqrt(rm, a, ctx=None):
"""Create a Z3 floating-point square root expression.
"""
- ctx = None
- if not is_expr(a):
- ctx =_get_ctx(ctx)
- s = get_default_fp_sort(ctx)
- a = FPVal(a, s)
- else:
- ctx = a.ctx
- if __debug__:
- _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
- _z3_assert(is_fp(a), "Second argument must be a Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_sqrt(rm.ctx_ref(), rm.as_ast(), a.as_ast()), rm.ctx)
+ return _mk_fp_unary(Z3_mk_fpa_sqrt, rm, a, ctx)
-def fpRoundToIntegral(rm, a):
+def fpRoundToIntegral(rm, a, ctx=None):
"""Create a Z3 floating-point roundToIntegral expression.
"""
- ctx = None
- if not is_expr(a):
- ctx =_get_ctx(ctx)
- s = get_default_fp_sort(ctx)
- a = FPVal(a, s)
- else:
- ctx = a.ctx
- if __debug__:
- _z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
- _z3_assert(is_fp(a), "Second argument must be a Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_round_to_integral(rm.ctx_ref(), rm.as_ast(), a.as_ast()), rm.ctx)
+ return _mk_fp_unary(Z3_mk_fpa_round_to_integral, rm, a, ctx)
-def fpIsNaN(a):
+def fpIsNaN(a, ctx=None):
"""Create a Z3 floating-point isNaN expression.
- """
- if __debug__:
- _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_is_nan(a.ctx_ref(), a.as_ast()), a.ctx)
-def fpIsInfinite(a):
+ >>> s = FPSort(8, 24)
+ >>> x = FP('x', s)
+ >>> y = FP('y', s)
+ >>> fpIsNaN(x)
+ fpIsNaN(x)
+ """
+ return _mk_fp_unary_norm(Z3_mk_fpa_is_nan, a, ctx)
+
+def fpIsInf(a, ctx=None):
"""Create a Z3 floating-point isInfinite expression.
- """
- if __debug__:
- _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_is_infinite(a.ctx_ref(), a.as_ast()), a.ctx)
-def fpIsZero(a):
+ >>> s = FPSort(8, 24)
+ >>> x = FP('x', s)
+ >>> fpIsInf(x)
+ fpIsInf(x)
+ """
+ return _mk_fp_unary_norm(Z3_mk_fpa_is_infinite, a, ctx)
+
+def fpIsZero(a, ctx=None):
"""Create a Z3 floating-point isZero expression.
"""
- if __debug__:
- _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_is_zero(a.ctx_ref(), a.as_ast()), a.ctx)
+ return _mk_fp_unary_norm(Z3_mk_fpa_is_zero, a, ctx)
-def fpIsNormal(a):
+def fpIsNormal(a, ctx=None):
"""Create a Z3 floating-point isNormal expression.
"""
- if __debug__:
- _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_is_normal(a.ctx_ref(), a.as_ast()), a.ctx)
+ return _mk_fp_unary_norm(Z3_mk_fpa_is_normal, a, ctx)
-def fpIsSubnormal(a):
+def fpIsSubnormal(a, ctx=None):
"""Create a Z3 floating-point isSubnormal expression.
"""
- if __debug__:
- _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_is_subnormal(a.ctx_ref(), a.as_ast()), a.ctx)
+ return _mk_fp_unary_norm(Z3_mk_fpa_is_subnormal, a, ctx)
-def fpIsNegative(a):
+def fpIsNegative(a, ctx=None):
"""Create a Z3 floating-point isNegative expression.
"""
- if __debug__:
- _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_is_negative(a.ctx_ref(), a.as_ast()), a.ctx)
+ return _mk_fp_unary_norm(Z3_mk_fpa_is_negative, a, ctx)
-def fpIsPositive(a):
+def fpIsPositive(a, ctx=None):
"""Create a Z3 floating-point isPositive expression.
"""
- if __debug__:
- _z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
- return FPRef(Z3_mk_fpa_is_positive(a.ctx_ref(), a.as_ast()), a.ctx)
+ return _mk_fp_unary_norm(Z3_mk_fpa_is_positive, a, ctx)
+ return FPRef(Z3_mk_fpa_is_positive(a.ctx_ref(), a.as_ast()), a.ctx)
def _check_fp_args(a, b):
if __debug__:
_z3_assert(is_fp(a) or is_fp(b), "At least one of the arguments must be a Z3 floating-point expression")
-def fpLT(a, b):
+def fpLT(a, b, ctx=None):
"""Create the Z3 floating-point expression `other <= self`.
-
+
>>> x, y = FPs('x y', FPSort(8, 24))
>>> fpLT(x, y)
x < y
>>> (x <= y).sexpr()
'(fp.leq x y)'
"""
- _check_fp_args(a, b)
- a, b = _coerce_exprs(a, b)
- return BoolRef(Z3_mk_fpa_lt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+ return _mk_fp_bin_pred(Z3_mk_fpa_lt, a, b, ctx)
-def fpLEQ(a, b):
+def fpLEQ(a, b, ctx=None):
"""Create the Z3 floating-point expression `other <= self`.
-
+
>>> x, y = FPs('x y', FPSort(8, 24))
>>> fpLEQ(x, y)
x <= y
>>> (x <= y).sexpr()
'(fp.leq x y)'
"""
- _check_fp_args(a, b)
- a, b = _coerce_exprs(a, b)
- return BoolRef(Z3_mk_fpa_leq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+ return _mk_fp_bin_pred(Z3_mk_fpa_leq, a, b, ctx)
-def fpGT(a, b):
+def fpGT(a, b, ctx=None):
"""Create the Z3 floating-point expression `other <= self`.
-
+
>>> x, y = FPs('x y', FPSort(8, 24))
>>> fpGT(x, y)
x > y
>>> (x > y).sexpr()
'(fp.gt x y)'
"""
- _check_fp_args(a, b)
- a, b = _coerce_exprs(a, b)
- return BoolRef(Z3_mk_fpa_gt(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+ return _mk_fp_bin_pred(Z3_mk_fpa_gt, a, b, ctx)
-
-def fpGEQ(a, b):
+def fpGEQ(a, b, ctx=None):
"""Create the Z3 floating-point expression `other <= self`.
-
+
>>> x, y = FPs('x y', FPSort(8, 24))
>>> x + y
x + y
@@ -8746,67 +8856,82 @@ def fpGEQ(a, b):
>>> (x >= y).sexpr()
'(fp.geq x y)'
"""
- _check_fp_args(a, b)
- a, b = _coerce_exprs(a, b)
- return BoolRef(Z3_mk_fpa_geq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+ return _mk_fp_bin_pred(Z3_mk_fpa_geq, a, b, ctx)
-def fpEQ(a, b):
+def fpEQ(a, b, ctx=None):
"""Create the Z3 floating-point expression `other <= self`.
-
+
>>> x, y = FPs('x y', FPSort(8, 24))
>>> fpEQ(x, y)
fpEQ(x, y)
>>> fpEQ(x, y).sexpr()
'(fp.eq x y)'
"""
- _check_fp_args(a, b)
- a, b = _coerce_exprs(a, b)
- return BoolRef(Z3_mk_fpa_eq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+ return _mk_fp_bin_pred(Z3_mk_fpa_eq, a, b, ctx)
-def fpNEQ(a, b):
+def fpNEQ(a, b, ctx=None):
"""Create the Z3 floating-point expression `other <= self`.
-
+
>>> x, y = FPs('x y', FPSort(8, 24))
>>> fpNEQ(x, y)
Not(fpEQ(x, y))
>>> (x != y).sexpr()
'(not (fp.eq x y))'
"""
- _check_fp_args(a, b)
- a, b = _coerce_exprs(a, b)
- return Not(BoolRef(Z3_mk_fpa_eq(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx), a.ctx)
+ return Not(fpEQ(a, b, ctx))
+def fpFP(sgn, exp, sig, ctx=None):
+ """Create the Z3 floating-point value `fpFP(sgn, sig, exp)` from the three bit-vectors sgn, sig, and exp.
-
-def fpFP(sgn, exp, sig):
- """Create the Z3 floating-point value `fpFP(sgn, sig, exp)` from the three bit-vectorssgn, sig, and exp."""
+ >>> s = FPSort(8, 24)
+ >>> x = fpFP(BitVecVal(1, 1), BitVecVal(2**7-1, 8), BitVecVal(2**22, 23))
+ >>> print(x)
+ fpFP(1, 127, 4194304)
+ >>> xv = FPVal(-1.5, s)
+ >>> print(xv)
+ -1.5
+ >>> slvr = Solver()
+ >>> slvr.add(fpEQ(x, xv))
+ >>> slvr.check()
+ sat
+ >>> xv = FPVal(+1.5, s)
+ >>> print(xv)
+ 1.5
+ >>> slvr = Solver()
+ >>> slvr.add(fpEQ(x, xv))
+ >>> slvr.check()
+ unsat
+ """
_z3_assert(is_bv(sgn) and is_bv(exp) and is_bv(sig), "sort mismatch")
_z3_assert(sgn.sort().size() == 1, "sort mismatch")
- return FPRef(Z3_mk_fpa_fp(sgn.ctx_ref(), sgn.ast, exp.ast, sig.ast), sgn.ctx)
-
+ ctx = _get_ctx(ctx)
+ _z3_assert(ctx == sgn.ctx == exp.ctx == sig.ctx, "context mismatch")
+ return FPRef(Z3_mk_fpa_fp(ctx.ref(), sgn.ast, exp.ast, sig.ast), ctx)
-def fpToFP(a1, a2=None, a3=None):
+def fpToFP(a1, a2=None, a3=None, ctx=None):
"""Create a Z3 floating-point conversion expression from other terms."""
+ ctx = _get_ctx(ctx)
if is_bv(a1) and is_fp_sort(a2):
- return FPRef(Z3_mk_fpa_to_fp_bv(a1.ctx_ref(), a1.ast, a2.ast), a1.ctx)
+ return FPRef(Z3_mk_fpa_to_fp_bv(ctx.ref(), a1.ast, a2.ast), ctx)
elif is_fprm(a1) and is_fp(a2) and is_fp_sort(a3):
- return FPRef(Z3_mk_fpa_to_fp_float(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx)
+ return FPRef(Z3_mk_fpa_to_fp_float(ctx.ref(), a1.ast, a2.ast, a3.ast), ctx)
elif is_fprm(a1) and is_real(a2) and is_fp_sort(a3):
- return FPRef(Z3_mk_fpa_to_fp_real(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx)
+ return FPRef(Z3_mk_fpa_to_fp_real(ctx.ref(), a1.ast, a2.ast, a3.ast), ctx)
elif is_fprm(a1) and is_bv(a2) and is_fp_sort(a3):
- return FPRef(Z3_mk_fpa_to_fp_signed(a1.ctx_ref(), a1.ast, a2.ast, a3.ast), a1.ctx)
+ return FPRef(Z3_mk_fpa_to_fp_signed(ctx.ref(), a1.ast, a2.ast, a3.ast), ctx)
else:
raise Z3Exception("Unsupported combination of arguments for conversion to floating-point term.")
-def fpToFPUnsigned(rm, x, s):
+def fpToFPUnsigned(rm, x, s, ctx=None):
"""Create a Z3 floating-point conversion expression, from unsigned bit-vector to floating-point expression."""
if __debug__:
_z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
_z3_assert(is_bv(x), "Second argument must be a Z3 bit-vector expression")
_z3_assert(is_fp_sort(s), "Third argument must be Z3 floating-point sort")
- return FPRef(Z3_mk_fpa_to_fp_unsigned(rm.ctx_ref(), rm.ast, x.ast, s.ast), rm.ctx)
+ ctx = _get_ctx(ctx)
+ return FPRef(Z3_mk_fpa_to_fp_unsigned(ctx.ref(), rm.ast, x.ast, s.ast), ctx)
-def fpToSBV(rm, x, s):
+def fpToSBV(rm, x, s, ctx=None):
"""Create a Z3 floating-point conversion expression, from floating-point expression to signed bit-vector.
>>> x = FP('x', FPSort(8, 24))
@@ -8824,9 +8949,10 @@ def fpToSBV(rm, x, s):
_z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
_z3_assert(is_fp(x), "Second argument must be a Z3 floating-point expression")
_z3_assert(is_bv_sort(s), "Third argument must be Z3 bit-vector sort")
- return BitVecRef(Z3_mk_fpa_to_sbv(rm.ctx_ref(), rm.ast, x.ast, s.size()), rm.ctx)
+ ctx = _get_ctx(ctx)
+ return BitVecRef(Z3_mk_fpa_to_sbv(ctx.ref(), rm.ast, x.ast, s.size()), ctx)
-def fpToUBV(rm, x, s):
+def fpToUBV(rm, x, s, ctx=None):
"""Create a Z3 floating-point conversion expression, from floating-point expression to unsigned bit-vector.
>>> x = FP('x', FPSort(8, 24))
@@ -8844,9 +8970,10 @@ def fpToUBV(rm, x, s):
_z3_assert(is_fprm(rm), "First argument must be a Z3 floating-point rounding mode expression")
_z3_assert(is_fp(x), "Second argument must be a Z3 floating-point expression")
_z3_assert(is_bv_sort(s), "Third argument must be Z3 bit-vector sort")
- return BitVecRef(Z3_mk_fpa_to_ubv(rm.ctx_ref(), rm.ast, x.ast, s.size()), rm.ctx)
+ ctx = _get_ctx(ctx)
+ return BitVecRef(Z3_mk_fpa_to_ubv(ctx.ref(), rm.ast, x.ast, s.size()), ctx)
-def fpToReal(x):
+def fpToReal(x, ctx=None):
"""Create a Z3 floating-point conversion expression, from floating-point expression to real.
>>> x = FP('x', FPSort(8, 24))
@@ -8862,15 +8989,16 @@ def fpToReal(x):
"""
if __debug__:
_z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression")
- return ArithRef(Z3_mk_fpa_to_real(x.ctx_ref(), x.ast), x.ctx)
+ ctx = _get_ctx(ctx)
+ return ArithRef(Z3_mk_fpa_to_real(ctx.ref(), x.ast), ctx)
-def fpToIEEEBV(x):
+def fpToIEEEBV(x, ctx=None):
"""\brief Conversion of a floating-point term into a bit-vector term in IEEE 754-2008 format.
-
- The size of the resulting bit-vector is automatically determined.
-
- Note that IEEE 754-2008 allows multiple different representations of NaN. This conversion
- knows only one NaN and it will always produce the same bit-vector represenatation of
+
+ The size of the resulting bit-vector is automatically determined.
+
+ Note that IEEE 754-2008 allows multiple different representations of NaN. This conversion
+ knows only one NaN and it will always produce the same bit-vector represenatation of
that NaN.
>>> x = FP('x', FPSort(8, 24))
@@ -8886,4 +9014,341 @@ def fpToIEEEBV(x):
"""
if __debug__:
_z3_assert(is_fp(x), "First argument must be a Z3 floating-point expression")
- return BitVecRef(Z3_mk_fpa_to_ieee_bv(x.ctx_ref(), x.ast), x.ctx)
+ ctx = _get_ctx(ctx)
+ return BitVecRef(Z3_mk_fpa_to_ieee_bv(ctx.ref(), x.ast), ctx)
+
+
+
+#########################################
+#
+# Strings, Sequences and Regular expressions
+#
+#########################################
+
+class SeqSortRef(SortRef):
+ """Sequence sort."""
+
+ def is_string(self):
+ """Determine if sort is a string
+ >>> s = StringSort()
+ >>> s.is_string()
+ True
+ >>> s = SeqSort(IntSort())
+ >>> s.is_string()
+ False
+ """
+ return Z3_is_string_sort(self.ctx_ref(), self.ast)
+
+def StringSort(ctx=None):
+ """Create a string sort
+ >>> s = StringSort()
+ >>> print(s)
+ String
+ """
+ ctx = _get_ctx(ctx)
+ return SeqSortRef(Z3_mk_string_sort(ctx.ref()), ctx)
+
+
+def SeqSort(s):
+ """Create a sequence sort over elements provided in the argument
+ >>> s = SeqSort(IntSort())
+ >>> s == Unit(IntVal(1)).sort()
+ True
+ """
+ return SeqSortRef(Z3_mk_seq_sort(s.ctx_ref(), s.ast), s.ctx)
+
+class SeqRef(ExprRef):
+ """Sequence expression."""
+
+ def sort(self):
+ return SeqSortRef(Z3_get_sort(self.ctx_ref(), self.as_ast()), self.ctx)
+
+ def __add__(self, other):
+ return Concat(self, other)
+
+ def __getitem__(self, i):
+ return SeqRef(Z3_mk_seq_at(self.ctx_ref(), self.as_ast(), i.as_ast()), self.ctx)
+
+ def is_string(self):
+ return Z3_is_string_sort(self.ctx_ref(), Z3_get_sort(self.ctx_ref(), self.as_ast()))
+
+ def is_string_value(self):
+ return Z3_is_string(self.ctx_ref(), self.as_ast())
+
+ def as_string(self):
+ """Return a string representation of sequence expression."""
+ return Z3_ast_to_string(self.ctx_ref(), self.as_ast())
+
+
+def _coerce_seq(s, ctx=None):
+ if isinstance(s, str):
+ ctx = _get_ctx(ctx)
+ s = StringVal(s, ctx)
+ return s
+
+def _get_ctx2(a, b, ctx=None):
+ if is_expr(a):
+ return a.ctx
+ if is_expr(b):
+ return b.ctx
+ if ctx is None:
+ ctx = main_ctx()
+ return ctx
+
+def is_seq(a):
+ """Return `True` if `a` is a Z3 sequence expression.
+ >>> print (is_seq(Unit(IntVal(0))))
+ True
+ >>> print (is_seq(StringVal("abc")))
+ True
+ """
+ return isinstance(a, SeqRef)
+
+def is_string(a):
+ """Return `True` if `a` is a Z3 string expression.
+ >>> print (is_string(StringVal("ab")))
+ True
+ """
+ return isinstance(a, SeqRef) and a.is_string()
+
+def is_string_value(a):
+ """return 'True' if 'a' is a Z3 string constant expression.
+ >>> print (is_string_value(StringVal("a")))
+ True
+ >>> print (is_string_value(StringVal("a") + StringVal("b")))
+ False
+ """
+ return isinstance(a, SeqRef) and a.is_string_value()
+
+
+def StringVal(s, ctx=None):
+ """create a string expression"""
+ ctx = _get_ctx(ctx)
+ return SeqRef(Z3_mk_string(ctx.ref(), s), ctx)
+
+def String(name, ctx=None):
+ """Return a string constant named `name`. If `ctx=None`, then the global context is used.
+
+ >>> x = String('x')
+ """
+ ctx = _get_ctx(ctx)
+ return SeqRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), StringSort(ctx).ast), ctx)
+
+def Strings(names, ctx=None):
+ """Return a tuple of String constants. """
+ ctx = _get_ctx(ctx)
+ if isinstance(names, str):
+ names = names.split(" ")
+ return [String(name, ctx) for name in names]
+
+def Empty(s):
+ """Create the empty sequence of the given sort
+ >>> e = Empty(StringSort())
+ >>> print(e)
+ ""
+ >>> e2 = StringVal("")
+ >>> print(e.eq(e2))
+ True
+ >>> e3 = Empty(SeqSort(IntSort()))
+ >>> print(e3)
+ seq.empty
+ """
+ return SeqRef(Z3_mk_seq_empty(s.ctx_ref(), s.ast), s.ctx)
+
+def Unit(a):
+ """Create a singleton sequence"""
+ return SeqRef(Z3_mk_seq_unit(a.ctx_ref(), a.as_ast()), a.ctx)
+
+def PrefixOf(a, b):
+ """Check if 'a' is a prefix of 'b'
+ >>> s1 = PrefixOf("ab", "abc")
+ >>> simplify(s1)
+ True
+ >>> s2 = PrefixOf("bc", "abc")
+ >>> simplify(s2)
+ False
+ """
+ ctx = _get_ctx2(a, b)
+ a = _coerce_seq(a, ctx)
+ b = _coerce_seq(b, ctx)
+ return BoolRef(Z3_mk_seq_prefix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def SuffixOf(a, b):
+ """Check if 'a' is a suffix of 'b'
+ >>> s1 = SuffixOf("ab", "abc")
+ >>> simplify(s1)
+ False
+ >>> s2 = SuffixOf("bc", "abc")
+ >>> simplify(s2)
+ True
+ """
+ ctx = _get_ctx2(a, b)
+ a = _coerce_seq(a, ctx)
+ b = _coerce_seq(b, ctx)
+ return BoolRef(Z3_mk_seq_suffix(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+def Contains(a, b):
+ """Check if 'a' contains 'b'
+ >>> s1 = Contains("abc", "ab")
+ >>> simplify(s1)
+ True
+ >>> s2 = Contains("abc", "bc")
+ >>> simplify(s2)
+ True
+ >>> x, y, z = Strings('x y z')
+ >>> s3 = Contains(Concat(x,y,z), y)
+ >>> simplify(s3)
+ True
+ """
+ ctx = _get_ctx2(a, b)
+ a = _coerce_seq(a, ctx)
+ b = _coerce_seq(b, ctx)
+ return BoolRef(Z3_mk_seq_contains(a.ctx_ref(), a.as_ast(), b.as_ast()), a.ctx)
+
+
+def Replace(s, src, dst):
+ """Replace the first occurrence of 'src' by 'dst' in 's'
+ >>> r = Replace("aaa", "a", "b")
+ >>> simplify(r)
+ "baa"
+ """
+ ctx = _get_ctx2(dst, s)
+ if ctx is None and is_expr(src):
+ ctx = src.ctx
+ src = _coerce_seq(src, ctx)
+ dst = _coerce_seq(dst, ctx)
+ s = _coerce_seq(s, ctx)
+ return SeqRef(Z3_mk_seq_replace(src.ctx_ref(), s.as_ast(), src.as_ast(), dst.as_ast()), s.ctx)
+
+def IndexOf(s, substr):
+ return IndexOf(s, substr, IntVal(0))
+
+def IndexOf(s, substr, offset):
+ """Retrieve the index of substring within a string starting at a specified offset.
+ >>> simplify(IndexOf("abcabc", "bc", 0))
+ 1
+ >>> simplify(IndexOf("abcabc", "bc", 2))
+ 4
+ """
+ ctx = None
+ if is_expr(offset):
+ ctx = offset.ctx
+ ctx = _get_ctx2(s, substr, ctx)
+ s = _coerce_seq(s, ctx)
+ substr = _coerce_seq(substr, ctx)
+ if isinstance(offset, int):
+ offset = IntVal(offset, ctx)
+ return SeqRef(Z3_mk_seq_index(s.ctx_ref(), s.as_ast(), substr.as_ast(), offset.as_ast()), s.ctx)
+
+def Length(s):
+ """Obtain the length of a sequence 's'
+ >>> l = Length(StringVal("abc"))
+ >>> simplify(l)
+ 3
+ """
+ s = _coerce_seq(s)
+ return ArithRef(Z3_mk_seq_length(s.ctx_ref(), s.as_ast()), s.ctx)
+
+def Re(s, ctx=None):
+ """The regular expression that accepts sequence 's'
+ >>> s1 = Re("ab")
+ >>> s2 = Re(StringVal("ab"))
+ >>> s3 = Re(Unit(BoolVal(True)))
+ """
+ s = _coerce_seq(s, ctx)
+ return ReRef(Z3_mk_seq_to_re(s.ctx_ref(), s.as_ast()), s.ctx)
+
+
+
+
+## Regular expressions
+
+class ReSortRef(SortRef):
+ """Regular expression sort."""
+
+
+def ReSort(s):
+ if is_ast(s):
+ return ReSortRef(Z3_mk_re_sort(s.ctx.ref(), s.as_ast()), ctx)
+ if s is None or isinstance(s, Context):
+ ctx = _get_ctx(s)
+ return ReSortRef(Z3_mk_re_sort(ctx.ref(), Z3_mk_string_sort(ctx.ref())), ctx)
+ raise Z3Exception("Regular expression sort constructor expects either a string or a context or no argument")
+
+
+class ReRef(ExprRef):
+ """Regular expressions."""
+
+ def __add__(self, other):
+ return Union(self, other)
+
+
+def is_re(s):
+ return isinstance(s, ReRef)
+
+
+def InRe(s, re):
+ """Create regular expression membership test
+ >>> re = Union(Re("a"),Re("b"))
+ >>> print (simplify(InRe("a", re)))
+ True
+ >>> print (simplify(InRe("b", re)))
+ True
+ >>> print (simplify(InRe("c", re)))
+ False
+ """
+ s = _coerce_seq(s, re.ctx)
+ return BoolRef(Z3_mk_seq_in_re(s.ctx_ref(), s.as_ast(), re.as_ast()), s.ctx)
+
+def Union(*args):
+ """Create union of regular expressions.
+ >>> re = Union(Re("a"), Re("b"), Re("c"))
+ >>> print (simplify(InRe("d", re)))
+ False
+ """
+ args = _get_args(args)
+ sz = len(args)
+ if __debug__:
+ _z3_assert(sz >= 2, "At least two arguments expected.")
+ _z3_assert(all([is_re(a) for a in args]), "All arguments must be regular expressions.")
+ ctx = args[0].ctx
+ v = (Ast * sz)()
+ for i in range(sz):
+ v[i] = args[i].as_ast()
+ return ReRef(Z3_mk_re_union(ctx.ref(), sz, v), ctx)
+
+def Plus(re):
+ """Create the regular expression accepting one or more repetitions of argument.
+ >>> re = Plus(Re("a"))
+ >>> print(simplify(InRe("aa", re)))
+ True
+ >>> print(simplify(InRe("ab", re)))
+ False
+ >>> print(simplify(InRe("", re)))
+ False
+ """
+ return ReRef(Z3_mk_re_plus(re.ctx_ref(), re.as_ast()), re.ctx)
+
+def Option(re):
+ """Create the regular expression that optionally accepts the argument.
+ >>> re = Option(Re("a"))
+ >>> print(simplify(InRe("a", re)))
+ True
+ >>> print(simplify(InRe("", re)))
+ True
+ >>> print(simplify(InRe("aa", re)))
+ False
+ """
+ return ReRef(Z3_mk_re_option(re.ctx_ref(), re.as_ast()), re.ctx)
+
+def Star(re):
+ """Create the regular expression accepting zero or more repetitions of argument.
+ >>> re = Star(Re("a"))
+ >>> print(simplify(InRe("aa", re)))
+ True
+ >>> print(simplify(InRe("ab", re)))
+ False
+ >>> print(simplify(InRe("", re)))
+ True
+ """
+ return ReRef(Z3_mk_re_star(re.ctx_ref(), re.as_ast()), re.ctx)
diff --git a/src/api/python/z3printer.py b/src/api/python/z3printer.py
index adc203436..c8d69900a 100644
--- a/src/api/python/z3printer.py
+++ b/src/api/python/z3printer.py
@@ -68,8 +68,8 @@ _z3_op_to_fpa_normal_str = {
Z3_OP_FPA_RM_NEAREST_TIES_TO_EVEN : 'RoundNearestTiesToEven()', Z3_OP_FPA_RM_NEAREST_TIES_TO_AWAY : 'RoundNearestTiesToAway()',
Z3_OP_FPA_RM_TOWARD_POSITIVE : 'RoundTowardPositive()', Z3_OP_FPA_RM_TOWARD_NEGATIVE : 'RoundTowardNegative()',
Z3_OP_FPA_RM_TOWARD_ZERO : 'RoundTowardZero()',
- Z3_OP_FPA_PLUS_INF : '+oo', Z3_OP_FPA_MINUS_INF : '-oo',
- Z3_OP_FPA_NAN : 'NaN', Z3_OP_FPA_PLUS_ZERO : 'PZero', Z3_OP_FPA_MINUS_ZERO : 'NZero',
+ Z3_OP_FPA_PLUS_INF : 'fpPlusInfinity', Z3_OP_FPA_MINUS_INF : 'fpMinusInfinity',
+ Z3_OP_FPA_NAN : 'fpNaN', Z3_OP_FPA_PLUS_ZERO : 'fpPZero', Z3_OP_FPA_MINUS_ZERO : 'fpNZero',
Z3_OP_FPA_ADD : 'fpAdd', Z3_OP_FPA_SUB : 'fpSub', Z3_OP_FPA_NEG : 'fpNeg', Z3_OP_FPA_MUL : 'fpMul',
Z3_OP_FPA_DIV : 'fpDiv', Z3_OP_FPA_REM : 'fpRem', Z3_OP_FPA_ABS : 'fpAbs',
Z3_OP_FPA_MIN : 'fpMin', Z3_OP_FPA_MAX : 'fpMax',
@@ -570,6 +570,9 @@ class Formatter:
def pp_algebraic(self, a):
return to_format(a.as_decimal(self.precision))
+ def pp_string(self, a):
+ return to_format(a.as_string())
+
def pp_bv(self, a):
return to_format(a.as_string())
@@ -585,14 +588,24 @@ class Formatter:
def pp_fp_value(self, a):
z3._z3_assert(isinstance(a, z3.FPNumRef), 'type mismatch')
- if not self.fpa_pretty:
+ if not self.fpa_pretty:
+ r = []
if (a.isNaN()):
- return to_format('NaN')
+ r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_NAN]))
+ r.append(to_format('('))
+ r.append(to_format(a.sort()))
+ r.append(to_format(')'))
+ return compose(r)
elif (a.isInf()):
if (a.isNegative()):
- return to_format('-oo')
+ r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_MINUS_INF]))
else:
- return to_format('+oo')
+ r.append(to_format(_z3_op_to_fpa_normal_str[Z3_OP_FPA_PLUS_INF]))
+ r.append(to_format('('))
+ r.append(to_format(a.sort()))
+ r.append(to_format(')'))
+ return compose(r)
+
elif (a.isZero()):
if (a.isNegative()):
return to_format('-zero')
@@ -875,6 +888,8 @@ class Formatter:
return self.pp_fp_value(a)
elif z3.is_fp(a):
return self.pp_fp(a, d, xs)
+ elif z3.is_string_value(a):
+ return self.pp_string(a)
elif z3.is_const(a):
return self.pp_const(a)
else:
@@ -1190,6 +1205,10 @@ def set_fpa_pretty(flag=True):
set_fpa_pretty(True)
+def get_fpa_pretty():
+ global Formatter
+ return _Formatter.fpa_pretty
+
def in_html_mode():
return isinstance(_Formatter, HTMLFormatter)
diff --git a/src/api/z3_api.h b/src/api/z3_api.h
index a4a10bb85..528399394 100644
--- a/src/api/z3_api.h
+++ b/src/api/z3_api.h
@@ -161,6 +161,8 @@ typedef enum
Z3_FINITE_DOMAIN_SORT,
Z3_FLOATING_POINT_SORT,
Z3_ROUNDING_MODE_SORT,
+ Z3_SEQ_SORT,
+ Z3_RE_SORT,
Z3_UNKNOWN_SORT = 1000
} Z3_sort_kind;
@@ -1098,7 +1100,7 @@ typedef enum {
Z3_OP_PR_TH_LEMMA,
Z3_OP_PR_HYPER_RESOLVE,
- // Sequences
+ // Relational algebra
Z3_OP_RA_STORE = 0x600,
Z3_OP_RA_EMPTY,
Z3_OP_RA_IS_EMPTY,
@@ -1115,6 +1117,28 @@ typedef enum {
Z3_OP_FD_CONSTANT,
Z3_OP_FD_LT,
+ // Sequences
+ Z3_OP_SEQ_UNIT,
+ Z3_OP_SEQ_EMPTY,
+ Z3_OP_SEQ_CONCAT,
+ Z3_OP_SEQ_PREFIX,
+ Z3_OP_SEQ_SUFFIX,
+ Z3_OP_SEQ_CONTAINS,
+ Z3_OP_SEQ_EXTRACT,
+ Z3_OP_SEQ_REPLACE,
+ Z3_OP_SEQ_AT,
+ Z3_OP_SEQ_LENGTH,
+ Z3_OP_SEQ_INDEX,
+ Z3_OP_SEQ_TO_RE,
+ Z3_OP_SEQ_IN_RE,
+
+ // regular expressions
+ Z3_OP_RE_PLUS,
+ Z3_OP_RE_STAR,
+ Z3_OP_RE_OPTION,
+ Z3_OP_RE_CONCAT,
+ Z3_OP_RE_UNION,
+
// Auxiliary
Z3_OP_LABEL = 0x700,
Z3_OP_LABEL_LIT,
@@ -3093,6 +3117,222 @@ extern "C" {
/*@}*/
+ /** @name Sequences and regular expressions */
+ /*@{*/
+
+ /**
+ \brief Create a sequence sort out of the sort for the elements.
+
+ def_API('Z3_mk_seq_sort', SORT, (_in(CONTEXT), _in(SORT)))
+ */
+ Z3_sort Z3_API Z3_mk_seq_sort(Z3_context c, Z3_sort s);
+
+ /**
+ \brief Check if \c s is a sequence sort.
+
+ def_API('Z3_is_seq_sort', BOOL, (_in(CONTEXT), _in(SORT)))
+ */
+ Z3_bool Z3_API Z3_is_seq_sort(Z3_context c, Z3_sort s);
+
+ /**
+ \brief Create a regular expression sort out of a sequence sort.
+
+ def_API('Z3_mk_re_sort', SORT, (_in(CONTEXT), _in(SORT)))
+ */
+ Z3_sort Z3_API Z3_mk_re_sort(Z3_context c, Z3_sort seq);
+
+ /**
+ \brief Check if \c s is a regular expression sort.
+
+ def_API('Z3_is_re_sort', BOOL, (_in(CONTEXT), _in(SORT)))
+ */
+ Z3_bool Z3_API Z3_is_re_sort(Z3_context c, Z3_sort s);
+
+ /**
+ \brief Create a sort for 8 bit strings.
+
+ This function creates a sort for ASCII strings.
+ Each character is 8 bits.
+
+ def_API('Z3_mk_string_sort', SORT ,(_in(CONTEXT), ))
+ */
+ Z3_sort Z3_API Z3_mk_string_sort(Z3_context c);
+
+ /**
+ \brief Check if \c s is a string sort.
+
+ def_API('Z3_is_string_sort', BOOL, (_in(CONTEXT), _in(SORT)))
+ */
+ Z3_bool Z3_API Z3_is_string_sort(Z3_context c, Z3_sort s);
+
+ /**
+ \brief Create a string constant out of the string that is passed in
+ def_API('Z3_mk_string' ,AST ,(_in(CONTEXT), _in(STRING)))
+ */
+ Z3_ast Z3_API Z3_mk_string(Z3_context c, Z3_string s);
+
+ /**
+ \brief Determine if \c s is a string constant.
+
+ def_API('Z3_is_string', BOOL, (_in(CONTEXT), _in(AST)))
+ */
+ Z3_bool Z3_API Z3_is_string(Z3_context c, Z3_ast s);
+
+ /**
+ \brief Retrieve the string constant stored in \c s.
+
+ \pre Z3_is_string(c, s)
+
+ def_API('Z3_get_string' ,STRING ,(_in(CONTEXT), _in(AST)))
+ */
+ Z3_string Z3_API Z3_get_string(Z3_context c, Z3_ast s);
+
+ /**
+ \brief Create an empty sequence of the sequence sort \c seq.
+
+ \pre s is a sequence sort.
+
+ def_API('Z3_mk_seq_empty' ,AST ,(_in(CONTEXT), _in(SORT)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_empty(Z3_context c, Z3_sort seq);
+
+ /**
+ \brief Create a unit sequence of \c a.
+
+ def_API('Z3_mk_seq_unit' ,AST ,(_in(CONTEXT), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_unit(Z3_context c, Z3_ast a);
+
+ /**
+ \brief Concatenate sequences.
+
+ \pre n > 0
+
+ def_API('Z3_mk_seq_concat' ,AST ,(_in(CONTEXT), _in(UINT), _in_array(1, AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_concat(Z3_context c, unsigned n, Z3_ast const args[]);
+
+ /**
+ \brief Check if \c prefix is a prefix of \c s.
+
+ \pre prefix and s are the same sequence sorts.
+
+ def_API('Z3_mk_seq_prefix' ,AST ,(_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_prefix(Z3_context c, Z3_ast prefix, Z3_ast s);
+
+ /**
+ \brief Check if \c suffix is a suffix of \c s.
+
+ \pre \c suffix and \c s are the same sequence sorts.
+
+ def_API('Z3_mk_seq_suffix' ,AST ,(_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_suffix(Z3_context c, Z3_ast suffix, Z3_ast s);
+
+ /**
+ \brief Check if \c container contains \c containee.
+
+ \pre \c container and \c containee are the same sequence sorts.
+
+ def_API('Z3_mk_seq_contains' ,AST ,(_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_contains(Z3_context c, Z3_ast container, Z3_ast containee);
+
+ /**
+ \brief Extract subsequence starting at \c offset of \c length.
+
+ def_API('Z3_mk_seq_extract' ,AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_extract(Z3_context c, Z3_ast s, Z3_ast offset, Z3_ast length);
+
+ /**
+ \brief Replace the first occurrence of \c src with \c dst in \c s.
+
+ def_API('Z3_mk_seq_replace' ,AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_replace(Z3_context c, Z3_ast s, Z3_ast src, Z3_ast dst);
+
+ /**
+ \brief Retrieve from \s the unit sequence positioned at position \c index.
+
+ def_API('Z3_mk_seq_at' ,AST ,(_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_at(Z3_context c, Z3_ast s, Z3_ast index);
+
+ /**
+ \brief Return the length of the sequence \c s.
+
+ def_API('Z3_mk_seq_length' ,AST ,(_in(CONTEXT), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_length(Z3_context c, Z3_ast s);
+
+
+ /**
+ \brief Return index of first occurrence of \c substr in \c s starting from offset \c offset.
+ If \c s does not contain \c substr, then the value is -1, if \c offset is the length of \c s, then the value is -1 as well.
+ The function is under-specified if \c offset is negative or larger than the length of \c s.
+
+ def_API('Z3_mk_seq_index' ,AST ,(_in(CONTEXT), _in(AST), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_index(Z3_context c, Z3_ast s, Z3_ast substr, Z3_ast offset);
+
+ /**
+ \brief Create a regular expression that accepts the sequence \c seq.
+
+ def_API('Z3_mk_seq_to_re' ,AST ,(_in(CONTEXT), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_to_re(Z3_context c, Z3_ast seq);
+
+ /**
+ \brief Check if \c seq is in the language generated by the regular expression \c re.
+
+ def_API('Z3_mk_seq_in_re' ,AST ,(_in(CONTEXT), _in(AST), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_seq_in_re(Z3_context c, Z3_ast seq, Z3_ast re);
+
+ /**
+ \brief Create the regular language \c re+.
+
+ def_API('Z3_mk_re_plus' ,AST ,(_in(CONTEXT), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_re_plus(Z3_context c, Z3_ast re);
+
+ /**
+ \brief Create the regular language \c re*.
+
+ def_API('Z3_mk_re_star' ,AST ,(_in(CONTEXT), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_re_star(Z3_context c, Z3_ast re);
+
+ /**
+ \brief Create the regular language \c [re].
+
+ def_API('Z3_mk_re_option' ,AST ,(_in(CONTEXT), _in(AST)))
+ */
+ Z3_ast Z3_API Z3_mk_re_option(Z3_context c, Z3_ast re);
+
+ /**
+ \brief Create the union of the regular languages.
+
+ \pre n > 0
+
+ def_API('Z3_mk_re_union' ,AST ,(_in(CONTEXT), _in(UINT), _in_array(1, AST)))
+ */
+ Z3_ast Z3_API Z3_mk_re_union(Z3_context c, unsigned n, Z3_ast const args[]);
+
+ /**
+ \brief Create the concatenation of the regular languages.
+
+ \pre n > 0
+
+ def_API('Z3_mk_re_concat' ,AST ,(_in(CONTEXT), _in(UINT), _in_array(1, AST)))
+ */
+ Z3_ast Z3_API Z3_mk_re_concat(Z3_context c, unsigned n, Z3_ast const args[]);
+
+ /*@}*/
+
+
/** @name Quantifiers */
/*@{*/
/**
diff --git a/src/api/z3_replayer.cpp b/src/api/z3_replayer.cpp
index 927521b65..8ce81ec31 100644
--- a/src/api/z3_replayer.cpp
+++ b/src/api/z3_replayer.cpp
@@ -46,6 +46,7 @@ struct z3_replayer::imp {
size_t m_ptr;
size_t_map m_heap;
svector m_cmds;
+ vector m_cmds_names;
enum value_kind { INT64, UINT64, DOUBLE, STRING, SYMBOL, OBJECT, UINT_ARRAY, INT_ARRAY, SYMBOL_ARRAY, OBJECT_ARRAY, FLOAT };
@@ -509,6 +510,7 @@ struct z3_replayer::imp {
if (idx >= m_cmds.size())
throw z3_replayer_exception("invalid command");
try {
+ TRACE("z3_replayer_cmd", tout << m_cmds_names[idx] << "\n";);
m_cmds[idx](m_owner);
}
catch (z3_error & ex) {
@@ -672,9 +674,11 @@ struct z3_replayer::imp {
m_result = obj;
}
- void register_cmd(unsigned id, z3_replayer_cmd cmd) {
+ void register_cmd(unsigned id, z3_replayer_cmd cmd, char const* name) {
m_cmds.reserve(id+1, 0);
+ m_cmds_names.reserve(id+1, "");
m_cmds[id] = cmd;
+ m_cmds_names[id] = name;
}
void reset() {
@@ -786,8 +790,8 @@ void z3_replayer::store_result(void * obj) {
return m_imp->store_result(obj);
}
-void z3_replayer::register_cmd(unsigned id, z3_replayer_cmd cmd) {
- return m_imp->register_cmd(id, cmd);
+void z3_replayer::register_cmd(unsigned id, z3_replayer_cmd cmd, char const* name) {
+ return m_imp->register_cmd(id, cmd, name);
}
void z3_replayer::parse() {
diff --git a/src/api/z3_replayer.h b/src/api/z3_replayer.h
index 6c566d553..88654363d 100644
--- a/src/api/z3_replayer.h
+++ b/src/api/z3_replayer.h
@@ -62,7 +62,7 @@ public:
void ** get_obj_addr(unsigned pos);
void store_result(void * obj);
- void register_cmd(unsigned id, z3_replayer_cmd cmd);
+ void register_cmd(unsigned id, z3_replayer_cmd cmd, char const* name);
};
#endif
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 2ee6c7556..ab1a5a5af 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -1656,6 +1656,7 @@ ast * ast_manager::register_node_core(ast * n) {
n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk();
+
TRACE("ast", tout << "Object " << n->m_id << " was created.\n";);
TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";);
// increment reference counters
diff --git a/src/ast/expr_abstract.cpp b/src/ast/expr_abstract.cpp
index 0569eb360..949168cad 100644
--- a/src/ast/expr_abstract.cpp
+++ b/src/ast/expr_abstract.cpp
@@ -49,6 +49,7 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const*
case AST_APP: {
app* a = to_app(curr);
bool all_visited = true;
+ bool changed = false;
m_args.reset();
for (unsigned i = 0; i < a->get_num_args(); ++i) {
if (!m_map.find(a->get_arg(i), b)) {
@@ -56,12 +57,17 @@ void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const*
all_visited = false;
}
else {
+ changed |= b != a->get_arg(i);
m_args.push_back(b);
}
}
if (all_visited) {
- b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr());
- m_pinned.push_back(b);
+ if (changed) {
+ b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr());
+ m_pinned.push_back(b);
+ } else {
+ b = curr;
+ }
m_map.insert(curr, b);
m_stack.pop_back();
}
diff --git a/src/ast/fpa/fpa2bv_converter.cpp b/src/ast/fpa/fpa2bv_converter.cpp
index c4ca4c03d..863d1d8db 100644
--- a/src/ast/fpa/fpa2bv_converter.cpp
+++ b/src/ast/fpa/fpa2bv_converter.cpp
@@ -2490,12 +2490,12 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
expr * bv_rm = to_app(args[0])->get_arg(0);
- rational q;
- if (!m_arith_util.is_numeral(args[1], q))
+ rational e;
+ if (!m_arith_util.is_numeral(args[1], e))
UNREACHABLE();
- rational e;
- if (!m_arith_util.is_numeral(args[2], e))
+ rational q;
+ if (!m_arith_util.is_numeral(args[2], q))
UNREACHABLE();
SASSERT(e.is_int64());
@@ -2505,11 +2505,11 @@ void fpa2bv_converter::mk_to_fp_real_int(func_decl * f, unsigned num, expr * con
return mk_pzero(f, result);
else {
scoped_mpf nte(m_mpf_manager), nta(m_mpf_manager), tp(m_mpf_manager), tn(m_mpf_manager), tz(m_mpf_manager);
- m_mpf_manager.set(nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, q.to_mpq(), e.to_mpq().numerator());
- m_mpf_manager.set(nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, q.to_mpq(), e.to_mpq().numerator());
- m_mpf_manager.set(tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, q.to_mpq(), e.to_mpq().numerator());
- m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, q.to_mpq(), e.to_mpq().numerator());
- m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, q.to_mpq(), e.to_mpq().numerator());
+ m_mpf_manager.set(nte, ebits, sbits, MPF_ROUND_NEAREST_TEVEN, e.to_mpq().numerator(), q.to_mpq());
+ m_mpf_manager.set(nta, ebits, sbits, MPF_ROUND_NEAREST_TAWAY, e.to_mpq().numerator(), q.to_mpq());
+ m_mpf_manager.set(tp, ebits, sbits, MPF_ROUND_TOWARD_POSITIVE, e.to_mpq().numerator(), q.to_mpq());
+ m_mpf_manager.set(tn, ebits, sbits, MPF_ROUND_TOWARD_NEGATIVE, e.to_mpq().numerator(), q.to_mpq());
+ m_mpf_manager.set(tz, ebits, sbits, MPF_ROUND_TOWARD_ZERO, e.to_mpq().numerator(), q.to_mpq());
app_ref a_nte(m), a_nta(m), a_tp(m), a_tn(m), a_tz(m);
a_nte = m_plugin->mk_numeral(nte);
diff --git a/src/ast/fpa_decl_plugin.cpp b/src/ast/fpa_decl_plugin.cpp
index d32aa5e6d..317112cae 100644
--- a/src/ast/fpa_decl_plugin.cpp
+++ b/src/ast/fpa_decl_plugin.cpp
@@ -39,7 +39,7 @@ void fpa_decl_plugin::set_manager(ast_manager * m, family_id id) {
m_int_sort = m_manager->mk_sort(m_arith_fid, INT_SORT);
SASSERT(m_int_sort != 0); // arith_decl_plugin must be installed before fpa_decl_plugin.
m_manager->inc_ref(m_int_sort);
-
+
// BV is not optional anymore.
SASSERT(m_manager->has_plugin(symbol("bv")));
m_bv_fid = m_manager->mk_family_id("bv");
@@ -69,28 +69,30 @@ void fpa_decl_plugin::recycled_id(unsigned id) {
}
func_decl * fpa_decl_plugin::mk_numeral_decl(mpf const & v) {
- parameter p(mk_id(v), true);
- SASSERT(p.is_external());
sort * s = mk_float_sort(v.get_ebits(), v.get_sbits());
- return m_manager->mk_const_decl(symbol("fp.numeral"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p));
+ func_decl * r = 0;
+ if (m_fm.is_nan(v))
+ r = m_manager->mk_const_decl(symbol("NaN"), s, func_decl_info(m_family_id, OP_FPA_NAN));
+ else if (m_fm.is_pinf(v))
+ r = m_manager->mk_const_decl(symbol("+oo"), s, func_decl_info(m_family_id, OP_FPA_PLUS_INF));
+ else if (m_fm.is_ninf(v))
+ r = m_manager->mk_const_decl(symbol("-oo"), s, func_decl_info(m_family_id, OP_FPA_MINUS_INF));
+ else if (m_fm.is_pzero(v))
+ r = m_manager->mk_const_decl(symbol("+zero"), s, func_decl_info(m_family_id, OP_FPA_PLUS_ZERO));
+ else if (m_fm.is_nzero(v))
+ r = m_manager->mk_const_decl(symbol("-zero"), s, func_decl_info(m_family_id, OP_FPA_MINUS_ZERO));
+ else {
+ SASSERT(m_fm.is_regular(v));
+ parameter p(mk_id(v), true);
+ SASSERT(p.is_external());
+ sort * s = mk_float_sort(v.get_ebits(), v.get_sbits());
+ r = m_manager->mk_const_decl(symbol("fp.numeral"), s, func_decl_info(m_family_id, OP_FPA_NUM, 1, &p));
+ }
+ return r;
}
app * fpa_decl_plugin::mk_numeral(mpf const & v) {
- sort * s = mk_float_sort(v.get_ebits(), v.get_sbits());
- func_decl * d;
- if (m_fm.is_nan(v))
- d = m_manager->mk_const_decl(symbol("NaN"), s, func_decl_info(m_family_id, OP_FPA_NAN));
- else if (m_fm.is_pinf(v))
- d = m_manager->mk_const_decl(symbol("+oo"), s, func_decl_info(m_family_id, OP_FPA_PLUS_INF));
- else if (m_fm.is_ninf(v))
- d = m_manager->mk_const_decl(symbol("-oo"), s, func_decl_info(m_family_id, OP_FPA_MINUS_INF));
- else if (m_fm.is_pzero(v))
- d = m_manager->mk_const_decl(symbol("+zero"), s, func_decl_info(m_family_id, OP_FPA_PLUS_ZERO));
- else if (m_fm.is_nzero(v))
- d = m_manager->mk_const_decl(symbol("-zero"), s, func_decl_info(m_family_id, OP_FPA_MINUS_ZERO));
- else
- d = mk_numeral_decl(v);
- return m_manager->mk_const(d);
+ return m_manager->mk_const(mk_numeral_decl(v));
}
bool fpa_decl_plugin::is_numeral(expr * n, mpf & val) {
@@ -161,9 +163,9 @@ bool fpa_decl_plugin::is_rm_numeral(expr * n, mpf_rounding_mode & val) {
return 0;
}
-bool fpa_decl_plugin::is_rm_numeral(expr * n) {
- mpf_rounding_mode t;
- return is_rm_numeral(n, t);
+bool fpa_decl_plugin::is_rm_numeral(expr * n) {
+ mpf_rounding_mode t;
+ return is_rm_numeral(n, t);
}
void fpa_decl_plugin::del(parameter const & p) {
@@ -182,8 +184,8 @@ void fpa_decl_plugin::finalize() {
if (m_int_sort) { m_manager->dec_ref(m_int_sort); }
}
-decl_plugin * fpa_decl_plugin::mk_fresh() {
- return alloc(fpa_decl_plugin);
+decl_plugin * fpa_decl_plugin::mk_fresh() {
+ return alloc(fpa_decl_plugin);
}
sort * fpa_decl_plugin::mk_float_sort(unsigned ebits, unsigned sbits) {
@@ -268,7 +270,7 @@ func_decl * fpa_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_param
}
SASSERT(is_sort_of(s, m_family_id, FLOATING_POINT_SORT));
-
+
unsigned ebits = s->get_parameter(0).get_int();
unsigned sbits = s->get_parameter(1).get_int();
scoped_mpf val(m_fm);
@@ -297,9 +299,9 @@ func_decl * fpa_decl_plugin::mk_bin_rel_decl(decl_kind k, unsigned num_parameter
switch (k) {
case OP_FPA_EQ: name = "fp.eq"; break;
case OP_FPA_LT: name = "fp.lt"; break;
- case OP_FPA_GT: name = "fp.gt"; break;
- case OP_FPA_LE: name = "fp.leq"; break;
- case OP_FPA_GE: name = "fp.geq"; break;
+ case OP_FPA_GT: name = "fp.gt"; break;
+ case OP_FPA_LE: name = "fp.leq"; break;
+ case OP_FPA_GE: name = "fp.geq"; break;
default:
UNREACHABLE();
break;
@@ -336,7 +338,7 @@ func_decl * fpa_decl_plugin::mk_unary_decl(decl_kind k, unsigned num_parameters,
if (arity != 1)
m_manager->raise_exception("invalid number of arguments to floating point operator");
if (!is_float_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
+ m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
symbol name;
switch (k) {
case OP_FPA_ABS: name = "fp.abs"; break;
@@ -353,7 +355,7 @@ func_decl * fpa_decl_plugin::mk_binary_decl(decl_kind k, unsigned num_parameters
if (arity != 2)
m_manager->raise_exception("invalid number of arguments to floating point operator");
if (domain[0] != domain[1] || !is_float_sort(domain[0]))
- m_manager->raise_exception("sort mismatch, expected arguments of equal FloatingPoint sorts");
+ m_manager->raise_exception("sort mismatch, expected arguments of equal FloatingPoint sorts");
symbol name;
switch (k) {
case OP_FPA_REM: name = "fp.rem"; break;
@@ -377,7 +379,7 @@ func_decl * fpa_decl_plugin::mk_rm_binary_decl(decl_kind k, unsigned num_paramet
if (!is_rm_sort(domain[0]))
m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
if (domain[1] != domain[2] || !is_float_sort(domain[1]))
- m_manager->raise_exception("sort mismatch, expected arguments 1 and 2 of equal FloatingPoint sorts");
+ m_manager->raise_exception("sort mismatch, expected arguments 1 and 2 of equal FloatingPoint sorts");
symbol name;
switch (k) {
case OP_FPA_ADD: name = "fp.add"; break;
@@ -398,7 +400,7 @@ func_decl * fpa_decl_plugin::mk_rm_unary_decl(decl_kind k, unsigned num_paramete
if (!is_rm_sort(domain[0]))
m_manager->raise_exception("sort mismatch, expected RoundingMode as first argument");
if (!is_float_sort(domain[1]))
- m_manager->raise_exception("sort mismatch, expected FloatingPoint as second argument");
+ m_manager->raise_exception("sort mismatch, expected FloatingPoint as second argument");
symbol name;
switch (k) {
case OP_FPA_SQRT: name = "fp.sqrt"; break;
@@ -423,8 +425,8 @@ func_decl * fpa_decl_plugin::mk_fma(decl_kind k, unsigned num_parameters, parame
}
func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
- if (m_bv_plugin && arity == 3 &&
+ unsigned arity, sort * const * domain, sort * range) {
+ if (m_bv_plugin && arity == 3 &&
is_sort_of(domain[0], m_bv_fid, BV_SORT) &&
is_sort_of(domain[1], m_bv_fid, BV_SORT) &&
is_sort_of(domain[2], m_bv_fid, BV_SORT)) {
@@ -445,7 +447,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para
int ebits = parameters[0].get_int();
int sbits = parameters[1].get_int();
-
+
if (domain[0]->get_parameter(0).get_int() != (ebits + sbits))
m_manager->raise_exception("sort mismatch; invalid bit-vector size, expected bitvector of size (ebits+sbits)");
@@ -453,7 +455,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para
symbol name("to_fp");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
}
- else if (m_bv_plugin && arity == 2 &&
+ else if (m_bv_plugin && arity == 2 &&
is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
is_sort_of(domain[1], m_bv_fid, BV_SORT)) {
// RoundingMode + 1 BV -> 1 FP
@@ -477,24 +479,37 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para
if (!parameters[0].is_int() || !parameters[1].is_int())
m_manager->raise_exception("invalid parameter type to to_fp");
int ebits = parameters[0].get_int();
- int sbits = parameters[1].get_int();
+ int sbits = parameters[1].get_int();
if (!is_rm_sort(domain[0]))
m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
if (!is_sort_of(domain[1], m_family_id, FLOATING_POINT_SORT))
m_manager->raise_exception("sort mismatch, expected second argument of FloatingPoint sort");
-
+
sort * fp = mk_float_sort(ebits, sbits);
symbol name("to_fp");
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
- }
+ }
+ else if (arity == 3 &&
+ is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
+ is_sort_of(domain[1], m_arith_fid, REAL_SORT) &&
+ is_sort_of(domain[2], m_arith_fid, INT_SORT))
+ {
+ // Rounding + 1 Real + 1 Int -> 1 FP
+ if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
+ m_manager->raise_exception("expecting two integer parameters to to_fp");
+
+ sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
+ symbol name("to_fp");
+ return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k, num_parameters, parameters));
+ }
else if (arity == 3 &&
is_sort_of(domain[0], m_family_id, ROUNDING_MODE_SORT) &&
- is_sort_of(domain[1], m_arith_fid, REAL_SORT) &&
- is_sort_of(domain[2], m_arith_fid, INT_SORT))
+ is_sort_of(domain[1], m_arith_fid, INT_SORT) &&
+ is_sort_of(domain[2], m_arith_fid, REAL_SORT))
{
- // Rounding + 1 Real + 1 Int -> 1 FP
+ // Rounding + 1 Int + 1 Real -> 1 FP
if (!(num_parameters == 2 && parameters[0].is_int() && parameters[1].is_int()))
- m_manager->raise_exception("expecting two integer parameters to to_fp");
+ m_manager->raise_exception("expecting two integer parameters to to_fp");
sort * fp = mk_float_sort(parameters[0].get_int(), parameters[1].get_int());
symbol name("to_fp");
@@ -543,6 +558,7 @@ func_decl * fpa_decl_plugin::mk_to_fp(decl_kind k, unsigned num_parameters, para
"(Real), "
"(RoundingMode (_ BitVec (eb+sb))), "
"(RoundingMode (_ FloatingPoint eb' sb')), "
+ "(RoundingMode Int Real), "
"(RoundingMode Real Int), "
"(RoundingMode Int), and "
"(RoundingMode Real)."
@@ -561,13 +577,13 @@ func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_paramet
m_manager->raise_exception("sort mismatch, expected first argument of RoundingMode sort");
if (!is_sort_of(domain[1], m_bv_fid, BV_SORT))
m_manager->raise_exception("sort mismatch, expected second argument of bit-vector sort");
-
+
// RoundingMode + 1 BV -> 1 FP
if (num_parameters != 2)
m_manager->raise_exception("invalid number of parameters to to_fp_unsigned");
if (!parameters[0].is_int() || !parameters[1].is_int())
m_manager->raise_exception("invalid parameter type to to_fp_unsigned");
-
+
int ebits = parameters[0].get_int();
int sbits = parameters[1].get_int();
@@ -579,16 +595,16 @@ func_decl * fpa_decl_plugin::mk_to_fp_unsigned(decl_kind k, unsigned num_paramet
func_decl * fpa_decl_plugin::mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 3)
- m_manager->raise_exception("invalid number of arguments to fp");
- if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) ||
+ m_manager->raise_exception("invalid number of arguments to fp");
+ if (!is_sort_of(domain[0], m_bv_fid, BV_SORT) ||
(domain[0]->get_parameter(0).get_int() != 1) ||
!is_sort_of(domain[1], m_bv_fid, BV_SORT) ||
!is_sort_of(domain[2], m_bv_fid, BV_SORT))
m_manager->raise_exception("sort mismatch, expected three bit-vectors, the first one of size 1.");
-
+
int eb = (domain[1])->get_parameter(0).get_int();
int sb = (domain[2])->get_parameter(0).get_int() + 1;
- symbol name("fp");
+ symbol name("fp");
sort * fp = mk_float_sort(eb, sb);
return m_manager->mk_func_decl(name, arity, domain, fp, func_decl_info(m_family_id, k));
}
@@ -636,12 +652,12 @@ func_decl * fpa_decl_plugin::mk_to_sbv(decl_kind k, unsigned num_parameters, par
}
func_decl * fpa_decl_plugin::mk_to_real(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range) {
+ unsigned arity, sort * const * domain, sort * range) {
if (arity != 1)
m_manager->raise_exception("invalid number of arguments to fp.to_real");
if (!is_float_sort(domain[0]))
m_manager->raise_exception("sort mismatch, expected argument of FloatingPoint sort");
-
+
symbol name("fp.to_real");
return m_manager->mk_func_decl(name, 1, domain, m_real_sort, func_decl_info(m_family_id, k));
}
@@ -668,7 +684,7 @@ func_decl * fpa_decl_plugin::mk_internal_rm(decl_kind k, unsigned num_parameters
m_manager->raise_exception("sort mismatch, expected argument of sort bitvector, size 3");
if (!is_rm_sort(range))
m_manager->raise_exception("sort mismatch, expected range of RoundingMode sort");
-
+
parameter ps[] = { parameter(3) };
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
return m_manager->mk_func_decl(symbol("rm"), 1, &bv_srt, range, func_decl_info(m_family_id, k, num_parameters, parameters));
@@ -688,7 +704,7 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
return m_manager->mk_func_decl(symbol("bv_wrap"), 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
- else {
+ else {
parameter ps[] = { parameter(3) };
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, ps);
return m_manager->mk_func_decl(symbol("bv_wrap"), 1, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
@@ -698,12 +714,12 @@ func_decl * fpa_decl_plugin::mk_internal_bv_wrap(decl_kind k, unsigned num_param
func_decl * fpa_decl_plugin::mk_internal_bv_unwrap(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
if (arity != 1)
- m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap");
+ m_manager->raise_exception("invalid number of arguments to internal_bv_unwrap");
if (!is_sort_of(domain[0], m_bv_fid, BV_SORT))
m_manager->raise_exception("sort mismatch, expected argument of bitvector sort");
if (!is_float_sort(range) && !is_rm_sort(range))
m_manager->raise_exception("sort mismatch, expected range of FloatingPoint or RoundingMode sort");
-
+
return m_manager->mk_func_decl(symbol("bv_unwrap"), 1, domain, range, func_decl_info(m_family_id, k, num_parameters, parameters));
}
@@ -716,7 +732,7 @@ func_decl * fpa_decl_plugin::mk_internal_to_ubv_unspecified(
m_manager->raise_exception("invalid number of parameters to fp.to_ubv_unspecified; expecting 1");
if (!parameters[0].is_int())
m_manager->raise_exception("invalid parameters type provided to fp.to_ubv_unspecified; expecting an integer");
-
+
sort * bv_srt = m_bv_plugin->mk_sort(m_bv_fid, 1, parameters);
return m_manager->mk_func_decl(symbol("fp.to_ubv_unspecified"), 0, domain, bv_srt, func_decl_info(m_family_id, k, num_parameters, parameters));
}
@@ -748,7 +764,7 @@ func_decl * fpa_decl_plugin::mk_internal_to_real_unspecified(
func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
- switch (k) {
+ switch (k) {
case OP_FPA_MINUS_INF:
case OP_FPA_PLUS_INF:
case OP_FPA_NAN:
@@ -768,14 +784,14 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case OP_FPA_GE:
return mk_bin_rel_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_IS_ZERO:
- case OP_FPA_IS_NEGATIVE:
+ case OP_FPA_IS_NEGATIVE:
case OP_FPA_IS_POSITIVE:
case OP_FPA_IS_NAN:
case OP_FPA_IS_INF:
case OP_FPA_IS_NORMAL:
case OP_FPA_IS_SUBNORMAL:
return mk_unary_rel_decl(k, num_parameters, parameters, arity, domain, range);
- case OP_FPA_ABS:
+ case OP_FPA_ABS:
case OP_FPA_NEG:
return mk_unary_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_REM:
@@ -787,7 +803,7 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case OP_FPA_DIV:
return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_SUB:
- if (arity == 1)
+ if (arity == 1)
return mk_unary_decl(OP_FPA_NEG, num_parameters, parameters, arity, domain, range);
else
return mk_rm_binary_decl(k, num_parameters, parameters, arity, domain, range);
@@ -797,7 +813,7 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
case OP_FPA_FMA:
return mk_fma(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_FP:
- return mk_fp(k, num_parameters, parameters, arity, domain, range);
+ return mk_fp(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_TO_UBV:
return mk_to_ubv(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_TO_SBV:
@@ -817,13 +833,13 @@ func_decl * fpa_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
return mk_internal_bv_wrap(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_BVUNWRAP:
return mk_internal_bv_unwrap(k, num_parameters, parameters, arity, domain, range);
-
+
case OP_FPA_INTERNAL_MIN_I:
case OP_FPA_INTERNAL_MAX_I:
case OP_FPA_INTERNAL_MIN_UNSPECIFIED:
case OP_FPA_INTERNAL_MAX_UNSPECIFIED:
return mk_binary_decl(k, num_parameters, parameters, arity, domain, range);
-
+
case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED:
return mk_internal_to_ubv_unspecified(k, num_parameters, parameters, arity, domain, range);
case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED:
@@ -857,19 +873,19 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons
op_names.push_back(builtin_name("RTZ", OP_FPA_RM_TOWARD_ZERO));
op_names.push_back(builtin_name("fp.abs", OP_FPA_ABS));
- op_names.push_back(builtin_name("fp.neg", OP_FPA_NEG));
- op_names.push_back(builtin_name("fp.add", OP_FPA_ADD));
- op_names.push_back(builtin_name("fp.sub", OP_FPA_SUB));
- op_names.push_back(builtin_name("fp.mul", OP_FPA_MUL));
+ op_names.push_back(builtin_name("fp.neg", OP_FPA_NEG));
+ op_names.push_back(builtin_name("fp.add", OP_FPA_ADD));
+ op_names.push_back(builtin_name("fp.sub", OP_FPA_SUB));
+ op_names.push_back(builtin_name("fp.mul", OP_FPA_MUL));
op_names.push_back(builtin_name("fp.div", OP_FPA_DIV));
- op_names.push_back(builtin_name("fp.fma", OP_FPA_FMA));
- op_names.push_back(builtin_name("fp.sqrt", OP_FPA_SQRT));
+ op_names.push_back(builtin_name("fp.fma", OP_FPA_FMA));
+ op_names.push_back(builtin_name("fp.sqrt", OP_FPA_SQRT));
op_names.push_back(builtin_name("fp.rem", OP_FPA_REM));
op_names.push_back(builtin_name("fp.roundToIntegral", OP_FPA_ROUND_TO_INTEGRAL));
op_names.push_back(builtin_name("fp.min", OP_FPA_MIN));
- op_names.push_back(builtin_name("fp.max", OP_FPA_MAX));
+ op_names.push_back(builtin_name("fp.max", OP_FPA_MAX));
op_names.push_back(builtin_name("fp.leq", OP_FPA_LE));
- op_names.push_back(builtin_name("fp.lt", OP_FPA_LT));
+ op_names.push_back(builtin_name("fp.lt", OP_FPA_LT));
op_names.push_back(builtin_name("fp.geq", OP_FPA_GE));
op_names.push_back(builtin_name("fp.gt", OP_FPA_GT));
op_names.push_back(builtin_name("fp.eq", OP_FPA_EQ));
@@ -880,13 +896,13 @@ void fpa_decl_plugin::get_op_names(svector & op_names, symbol cons
op_names.push_back(builtin_name("fp.isInfinite", OP_FPA_IS_INF));
op_names.push_back(builtin_name("fp.isNaN", OP_FPA_IS_NAN));
op_names.push_back(builtin_name("fp.isNegative", OP_FPA_IS_NEGATIVE));
- op_names.push_back(builtin_name("fp.isPositive", OP_FPA_IS_POSITIVE));
+ op_names.push_back(builtin_name("fp.isPositive", OP_FPA_IS_POSITIVE));
op_names.push_back(builtin_name("fp", OP_FPA_FP));
op_names.push_back(builtin_name("fp.to_ubv", OP_FPA_TO_UBV));
op_names.push_back(builtin_name("fp.to_sbv", OP_FPA_TO_SBV));
op_names.push_back(builtin_name("fp.to_real", OP_FPA_TO_REAL));
-
+
op_names.push_back(builtin_name("to_fp", OP_FPA_TO_FP));
op_names.push_back(builtin_name("to_fp_unsigned", OP_FPA_TO_FP_UNSIGNED));
@@ -917,13 +933,13 @@ expr * fpa_decl_plugin::get_some_value(sort * s) {
func_decl * f = mk_rm_const_decl(OP_FPA_RM_TOWARD_ZERO, 0, 0, 0, 0, s);
return m_manager->mk_const(f);
}
-
+
UNREACHABLE();
return 0;
}
bool fpa_decl_plugin::is_value(app * e) const {
- if (e->get_family_id() != m_family_id)
+ if (e->get_family_id() != m_family_id)
return false;
switch (e->get_decl_kind()) {
case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
@@ -956,7 +972,7 @@ bool fpa_decl_plugin::is_unique_value(app* e) const {
case OP_FPA_RM_TOWARD_POSITIVE:
case OP_FPA_RM_TOWARD_NEGATIVE:
case OP_FPA_RM_TOWARD_ZERO:
- return true;
+ return true;
case OP_FPA_PLUS_INF: /* No; +oo == fp(#b0 #b11 #b00) */
case OP_FPA_MINUS_INF: /* No; -oo == fp #b1 #b11 #b00) */
case OP_FPA_PLUS_ZERO: /* No; +zero == fp #b0 #b00 #b000) */
@@ -1029,7 +1045,7 @@ app * fpa_util::mk_nzero(unsigned ebits, unsigned sbits) {
return mk_value(v);
}
-app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) {
+app * fpa_util::mk_internal_to_ubv_unspecified(unsigned width) {
parameter ps[] = { parameter(width) };
sort * range = m_bv_util.mk_sort(width);
return m().mk_app(get_family_id(), OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED, 1, ps, 0, 0, range);
diff --git a/src/ast/fpa_decl_plugin.h b/src/ast/fpa_decl_plugin.h
index bf82aa487..a667bc6f8 100644
--- a/src/ast/fpa_decl_plugin.h
+++ b/src/ast/fpa_decl_plugin.h
@@ -24,7 +24,7 @@ Revision History:
#include"arith_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"mpf.h"
-
+
enum fpa_sort_kind {
FLOATING_POINT_SORT,
ROUNDING_MODE_SORT,
@@ -89,16 +89,16 @@ enum fpa_op_kind {
/* Internal use only */
OP_FPA_INTERNAL_RM, // Internal conversion from (_ BitVec 3) to RoundingMode
OP_FPA_INTERNAL_BVWRAP,
- OP_FPA_INTERNAL_BVUNWRAP,
-
+ OP_FPA_INTERNAL_BVUNWRAP,
+
OP_FPA_INTERNAL_MIN_I,
OP_FPA_INTERNAL_MAX_I,
OP_FPA_INTERNAL_MIN_UNSPECIFIED,
OP_FPA_INTERNAL_MAX_UNSPECIFIED,
OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED,
- OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED,
+ OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED,
OP_FPA_INTERNAL_TO_IEEE_BV_UNSPECIFIED,
- OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED,
+ OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED,
LAST_FLOAT_OP
};
@@ -115,7 +115,7 @@ class fpa_decl_plugin : public decl_plugin {
mpf_eq_proc(scoped_mpf_vector const & values):m_values(values) {}
bool operator()(unsigned id1, unsigned id2) const { return m_values.m().eq_core(m_values[id1], m_values[id2]); }
};
-
+
typedef chashtable value_table;
@@ -149,7 +149,7 @@ class fpa_decl_plugin : public decl_plugin {
func_decl * mk_rm_unary_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_fma(decl_kind k, unsigned num_parameters, parameter const * parameters,
- unsigned arity, sort * const * domain, sort * range);
+ unsigned arity, sort * const * domain, sort * range);
func_decl * mk_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_to_fp(decl_kind k, unsigned num_parameters, parameter const * parameters,
@@ -184,23 +184,23 @@ class fpa_decl_plugin : public decl_plugin {
public:
fpa_decl_plugin();
-
+
bool is_float_sort(sort * s) const { return is_sort_of(s, m_family_id, FLOATING_POINT_SORT); }
bool is_rm_sort(sort * s) const { return is_sort_of(s, m_family_id, ROUNDING_MODE_SORT); }
virtual ~fpa_decl_plugin();
virtual void finalize();
-
+
virtual decl_plugin * mk_fresh();
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
- virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
+ virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual void get_op_names(svector & op_names, symbol const & logic);
virtual void get_sort_names(svector & sort_names, symbol const & logic);
virtual expr * get_some_value(sort * s);
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app* e) const;
-
+
mpf_manager & fm() { return m_fm; }
func_decl * mk_numeral_decl(mpf const & v);
app * mk_numeral(mpf const & v);
@@ -209,7 +209,7 @@ public:
bool is_rm_numeral(expr * n, mpf_rounding_mode & val);
bool is_rm_numeral(expr * n);
- mpf const & get_value(unsigned id) const {
+ mpf const & get_value(unsigned id) const {
SASSERT(m_value_table.contains(id));
return m_values[id];
}
@@ -222,7 +222,7 @@ class fpa_util {
ast_manager & m_manager;
fpa_decl_plugin * m_plugin;
family_id m_fid;
- arith_util m_a_util;
+ arith_util m_a_util;
bv_util m_bv_util;
public:
@@ -269,29 +269,29 @@ public:
app * mk_pzero(sort * s) { return mk_pzero(get_ebits(s), get_sbits(s)); }
app * mk_nzero(sort * s) { return mk_nzero(get_ebits(s), get_sbits(s)); }
- bool is_nan(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nan(v); }
+ bool is_nan(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nan(v); }
bool is_pinf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pinf(v); }
bool is_ninf(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_ninf(v); }
bool is_zero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_zero(v); }
bool is_pzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_pzero(v); }
bool is_nzero(expr * n) { scoped_mpf v(fm()); return is_numeral(n, v) && fm().is_nzero(v); }
-
- app * mk_fp(expr * arg1, expr * arg2, expr * arg3) { return m().mk_app(m_fid, OP_FPA_FP, arg1, arg2, arg3); }
+
+ app * mk_fp(expr * sgn, expr * exp, expr * sig) { return m().mk_app(m_fid, OP_FPA_FP, sgn, exp, sig); }
app * mk_to_fp(sort * s, expr * bv_t) {
SASSERT(is_float(s) && s->get_num_parameters() == 2);
- return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t);
+ return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 1, &bv_t);
}
- app * mk_to_fp(sort * s, expr * rm, expr * t) {
+ app * mk_to_fp(sort * s, expr * rm, expr * t) {
SASSERT(is_float(s) && s->get_num_parameters() == 2);
expr * args[] = { rm, t };
return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 2, args);
}
- app * mk_to_fp(sort * s, expr * rm, expr * sig, expr * exp) {
+ app * mk_to_fp(sort * s, expr * rm, expr * exp, expr * sig) {
SASSERT(is_float(s) && s->get_num_parameters() == 2);
- expr * args[] = { rm, sig, exp };
+ expr * args[] = { rm, exp, sig};
return m().mk_app(m_fid, OP_FPA_TO_FP, 2, s->get_parameters(), 3, args);
}
- app * mk_to_fp_unsigned(sort * s, expr * rm, expr * t) {
+ app * mk_to_fp_unsigned(sort * s, expr * rm, expr * t) {
SASSERT(is_float(s) && s->get_num_parameters() == 2);
expr * args[] = { rm, t };
return m().mk_app(m_fid, OP_FPA_TO_FP_UNSIGNED, 2, s->get_parameters(), 2, args);
@@ -299,11 +299,11 @@ public:
bool is_to_fp(expr * n) { return is_app_of(n, m_fid, OP_FPA_TO_FP); }
- app * mk_to_ubv(expr * rm, expr * t, unsigned sz) {
+ app * mk_to_ubv(expr * rm, expr * t, unsigned sz) {
parameter ps[] = { parameter(sz) };
expr * args[] = { rm, t };
return m().mk_app(m_fid, OP_FPA_TO_UBV, 1, ps, 2, args); }
- app * mk_to_sbv(expr * rm, expr * t, unsigned sz) {
+ app * mk_to_sbv(expr * rm, expr * t, unsigned sz) {
parameter ps[] = { parameter(sz) };
expr * args[] = { rm, t };
return m().mk_app(m_fid, OP_FPA_TO_SBV, 1, ps, 2, args);
@@ -336,7 +336,7 @@ public:
app * mk_is_inf(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_INF, arg1); }
app * mk_is_zero(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_ZERO, arg1); }
app * mk_is_normal(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NORMAL, arg1); }
- app * mk_is_subnormal(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_SUBNORMAL, arg1); }
+ app * mk_is_subnormal(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_SUBNORMAL, arg1); }
app * mk_is_positive(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_POSITIVE, arg1); }
app * mk_is_negative(expr * arg1) { return m().mk_app(m_fid, OP_FPA_IS_NEGATIVE, arg1); }
diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h
index ea8209c61..b812de941 100644
--- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h
+++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl.h
@@ -121,8 +121,11 @@ public:
void mk_comp(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
void mk_carry_save_adder(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr * const * c_bits, expr_ref_vector & sum_bits, expr_ref_vector & carry_bits);
- void mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
+ bool mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
+ bool mk_const_case_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits);
+ void mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer& a_bits, ptr_buffer& b_bits, expr_ref_vector & out_bits);
+ bool is_bool_const(expr* e) const { return m().is_true(e) || m().is_false(e); }
void mk_abs(unsigned sz, expr * const * a_bits, expr_ref_vector & out_bits);
};
diff --git a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
index 38a608f5f..102082cd5 100644
--- a/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
+++ b/src/ast/rewriter/bit_blaster/bit_blaster_tpl_def.h
@@ -38,7 +38,7 @@ void bit_blaster_tpl::checkpoint() {
template
bool bit_blaster_tpl::is_numeral(unsigned sz, expr * const * bits) const {
for (unsigned i = 0; i < sz; i++)
- if (!m().is_true(bits[i]) && !m().is_false(bits[i]))
+ if (!is_bool_const(bits[i]))
return false;
return true;
}
@@ -158,32 +158,31 @@ void bit_blaster_tpl::mk_subtracter(unsigned sz, expr * const * a_bits, exp
template
void bit_blaster_tpl::mk_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
SASSERT(sz > 0);
+ numeral n_a, n_b;
+ out_bits.reset();
+ if (is_numeral(sz, a_bits, n_b))
+ std::swap(a_bits, b_bits);
+ if (is_minus_one(sz, b_bits)) {
+ mk_neg(sz, a_bits, out_bits);
+ SASSERT(sz == out_bits.size());
+ return;
+ }
+ if (is_numeral(sz, a_bits, n_a)) {
+ n_a *= n_b;
+ num2bits(n_a, sz, out_bits);
+ SASSERT(sz == out_bits.size());
+ return;
+ }
- if (!m_use_bcm) {
- numeral n_a, n_b;
- if (is_numeral(sz, a_bits, n_b))
- std::swap(a_bits, b_bits);
- if (is_minus_one(sz, b_bits)) {
- mk_neg(sz, a_bits, out_bits);
- return;
- }
- if (is_numeral(sz, a_bits, n_a)) {
- n_a *= n_b;
- num2bits(n_a, sz, out_bits);
- return;
- }
+ if (mk_const_multiplier(sz, a_bits, b_bits, out_bits)) {
+ SASSERT(sz == out_bits.size());
+ return;
}
- else {
- numeral n_a, n_b;
- if (is_numeral(sz, a_bits, n_a)) {
- mk_const_multiplier(sz, a_bits, b_bits, out_bits);
- return;
- } else if (is_numeral(sz, b_bits, n_b)) {
- mk_const_multiplier(sz, b_bits, a_bits, out_bits);
- return;
- }
+ if (mk_const_multiplier(sz, b_bits, a_bits, out_bits)) {
+ SASSERT(sz == out_bits.size());
+ return;
}
-
+ out_bits.reset();
if (!m_use_wtm) {
#if 0
static unsigned counter = 0;
@@ -1171,20 +1170,84 @@ void bit_blaster_tpl::mk_carry_save_adder(unsigned sz, expr * const * a_bit
}
template
-void bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
- DEBUG_CODE({
- numeral x;
- SASSERT(is_numeral(sz, a_bits, x));
- SASSERT(out_bits.empty());
- });
+bool bit_blaster_tpl::mk_const_case_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
+ unsigned nb = 0;
+ unsigned case_size = 1;
+ unsigned circuit_size = sz*sz*5;
+ for (unsigned i = 0; case_size < circuit_size && i < sz; ++i) {
+ if (!is_bool_const(a_bits[i])) {
+ case_size *= 2;
+ }
+ if (!is_bool_const(b_bits[i])) {
+ case_size *= 2;
+ }
+ }
+ if (case_size >= circuit_size) {
+ return false;
+ }
+ SASSERT(out_bits.empty());
+ ptr_buffer na_bits;
+ na_bits.append(sz, a_bits);
+ ptr_buffer nb_bits;
+ nb_bits.append(sz, b_bits);
+ mk_const_case_multiplier(true, 0, sz, na_bits, nb_bits, out_bits);
+ return false;
+}
+
+template
+void bit_blaster_tpl::mk_const_case_multiplier(bool is_a, unsigned i, unsigned sz, ptr_buffer& a_bits, ptr_buffer& b_bits, expr_ref_vector & out_bits) {
+ while (is_a && i < sz && is_bool_const(a_bits[i])) ++i;
+ if (is_a && i == sz) { is_a = false; i = 0; }
+ while (!is_a && i < sz && is_bool_const(b_bits[i])) ++i;
+ if (i < sz) {
+ expr_ref_vector out1(m()), out2(m());
+ expr_ref x(m());
+ x = is_a?a_bits[i]:b_bits[i];
+ if (is_a) a_bits[i] = m().mk_true(); else b_bits[i] = m().mk_true();
+ mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out1);
+ if (is_a) a_bits[i] = m().mk_false(); else b_bits[i] = m().mk_false();
+ mk_const_case_multiplier(is_a, i+1, sz, a_bits, b_bits, out2);
+ if (is_a) a_bits[i] = x; else b_bits[i] = x;
+ SASSERT(out_bits.empty());
+ for (unsigned j = 0; j < sz; ++j) {
+ out_bits.push_back(m().mk_ite(x, out1[j].get(), out2[j].get()));
+ }
+ }
+ else {
+ numeral n_a, n_b;
+ SASSERT(i == sz && !is_a);
+ VERIFY(is_numeral(sz, a_bits.c_ptr(), n_a));
+ VERIFY(is_numeral(sz, b_bits.c_ptr(), n_b));
+ n_a *= n_b;
+ num2bits(n_a, sz, out_bits);
+ }
+ SASSERT(out_bits.size() == sz);
+}
+
+template
+bool bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bits, expr * const * b_bits, expr_ref_vector & out_bits) {
+ numeral n_a;
+ if (!is_numeral(sz, a_bits, n_a)) {
+ return false;
+ }
+ SASSERT(out_bits.empty());
+
+ if (mk_const_case_multiplier(sz, a_bits, b_bits, out_bits)) {
+ SASSERT(sz == out_bits.size());
+ return true;
+ }
+ out_bits.reset();
+ if (!m_use_bcm) {
+ return false;
+ }
expr_ref_vector minus_b_bits(m()), tmp(m());
mk_neg(sz, b_bits, minus_b_bits);
out_bits.resize(sz, m().mk_false());
#if 1
- bool last=false, now;
+ bool last = false, now;
for (unsigned i = 0; i < sz; i++) {
now = m().is_true(a_bits[i]);
SASSERT(now || m().is_false(a_bits[i]));
@@ -1255,4 +1318,7 @@ void bit_blaster_tpl::mk_const_multiplier(unsigned sz, expr * const * a_bit
TRACE("bit_blaster_tpl_booth", for (unsigned i=0; iget_num_args();
+ expr_ref t1(m()), t2(m());
+ t1 = to_app(rhs)->get_arg(0);
+ if (sz > 2) {
+ t2 = m().mk_app(get_fid(), OP_BADD, sz-1, to_app(rhs)->get_args()+1);
+ }
+ else {
+ SASSERT(sz == 2);
+ t2 = to_app(rhs)->get_arg(1);
+ }
+ mk_t1_add_t2_eq_c(t1, t2, lhs, result);
+ return true;
+}
+
+bool bv_rewriter::is_add_mul_const(expr* e) const {
+ if (!m_util.is_bv_add(e)) {
+ return false;
+ }
+ unsigned num = to_app(e)->get_num_args();
+ for (unsigned i = 0; i < num; i++) {
+ expr * arg = to_app(e)->get_arg(i);
+ expr * c2, * x2;
+ if (m_util.is_numeral(arg))
+ continue;
+ if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2))
+ continue;
+ return false;
+ }
+ return true;
+}
+
+bool bv_rewriter::is_concat_target(expr* lhs, expr* rhs) const {
+ return
+ (m_util.is_concat(lhs) && (is_concat_split_target(rhs) || has_numeral(to_app(lhs)))) ||
+ (m_util.is_concat(rhs) && (is_concat_split_target(lhs) || has_numeral(to_app(rhs))));
+}
+
+bool bv_rewriter::has_numeral(app* a) const {
+ for (unsigned i = 0; i < a->get_num_args(); ++i) {
+ if (is_numeral(a->get_arg(i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) {
+
expr * c, * x;
numeral c_val, c_inv_val;
unsigned sz;
@@ -2001,24 +2057,30 @@ br_status bv_rewriter::mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result) {
// c * x = t_1 + ... + t_n
// and t_i's have non-unary coefficients (this condition is used to make sure we are actually reducing the number of multipliers).
- if (m_util.is_bv_add(rhs)) {
+ if (is_add_mul_const(rhs)) {
// Potential problem: this simplification may increase the number of adders by reducing the amount of sharing.
- unsigned num = to_app(rhs)->get_num_args();
- unsigned i;
- for (i = 0; i < num; i++) {
- expr * arg = to_app(rhs)->get_arg(i);
- expr * c2, * x2;
- if (m_util.is_numeral(arg))
- continue;
- if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2))
- continue;
- break;
- }
- if (i == num) {
- result = m().mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val, sz), rhs));
- return BR_REWRITE2;
+ result = m().mk_eq(x, m_util.mk_bv_mul(m_util.mk_numeral(c_inv_val, sz), rhs));
+ return BR_REWRITE2;
+ }
+ }
+ if (m_util.is_numeral(lhs, c_val, sz) && is_add_mul_const(rhs)) {
+ unsigned num_args = to_app(rhs)->get_num_args();
+ unsigned i = 0;
+ expr* c2, *x2;
+ numeral c2_val, c2_inv_val;
+ bool found = false;
+ for (; !found && i < num_args; ++i) {
+ expr* arg = to_app(rhs)->get_arg(i);
+ if (m_util.is_bv_mul(arg, c2, x2) && m_util.is_numeral(c2, c2_val, sz) &&
+ m_util.mult_inverse(c2_val, sz, c2_inv_val)) {
+ found = true;
}
}
+ if (found) {
+ result = m().mk_eq(m_util.mk_numeral(c2_inv_val*c_val, sz),
+ m_util.mk_bv_mul(m_util.mk_numeral(c2_inv_val, sz), rhs));
+ return BR_REWRITE3;
+ }
}
return BR_FAILED;
}
@@ -2065,9 +2127,10 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
return st;
}
+ expr_ref new_lhs(m());
+ expr_ref new_rhs(m());
+
if (m_util.is_bv_add(lhs) || m_util.is_bv_mul(lhs) || m_util.is_bv_add(rhs) || m_util.is_bv_mul(rhs)) {
- expr_ref new_lhs(m());
- expr_ref new_rhs(m());
st = cancel_monomials(lhs, rhs, false, new_lhs, new_rhs);
if (st != BR_FAILED) {
if (is_numeral(new_lhs) && is_numeral(new_rhs)) {
@@ -2080,28 +2143,27 @@ br_status bv_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
new_rhs = rhs;
}
+ lhs = new_lhs;
+ rhs = new_rhs;
// Try to rewrite t1 + t2 = c --> t1 = c - t2
// Reason: it is much cheaper to bit-blast.
- expr * t1, * t2;
- if (m_util.is_bv_add(new_lhs, t1, t2) && is_numeral(new_rhs)) {
- mk_t1_add_t2_eq_c(t1, t2, new_rhs, result);
+ if (isolate_term(lhs, rhs, result)) {
return BR_REWRITE2;
}
- if (m_util.is_bv_add(new_rhs, t1, t2) && is_numeral(new_lhs)) {
- mk_t1_add_t2_eq_c(t1, t2, new_lhs, result);
- return BR_REWRITE2;
+ if (is_concat_target(lhs, rhs)) {
+ return mk_eq_concat(lhs, rhs, result);
}
-
+
if (st != BR_FAILED) {
- result = m().mk_eq(new_lhs, new_rhs);
+ result = m().mk_eq(lhs, rhs);
return BR_DONE;
}
}
- if ((m_util.is_concat(lhs) && is_concat_split_target(rhs)) ||
- (m_util.is_concat(rhs) && is_concat_split_target(lhs)))
+ if (is_concat_target(lhs, rhs)) {
return mk_eq_concat(lhs, rhs, result);
-
+ }
+
if (swapped) {
result = m().mk_eq(lhs, rhs);
return BR_DONE;
diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h
index 1c9b44b52..78d3fb4f1 100644
--- a/src/ast/rewriter/bv_rewriter.h
+++ b/src/ast/rewriter/bv_rewriter.h
@@ -137,6 +137,10 @@ class bv_rewriter : public poly_rewriter {
bool is_concat_split_target(expr * t) const;
br_status mk_mul_eq(expr * lhs, expr * rhs, expr_ref & result);
+ bool is_add_mul_const(expr* e) const;
+ bool isolate_term(expr* lhs, expr* rhs, expr_ref & result);
+ bool has_numeral(app* e) const;
+ bool is_concat_target(expr* lhs, expr* rhs) const;
void updt_local_params(params_ref const & p);
diff --git a/src/ast/rewriter/expr_safe_replace.cpp b/src/ast/rewriter/expr_safe_replace.cpp
index b43577960..25a8fd657 100644
--- a/src/ast/rewriter/expr_safe_replace.cpp
+++ b/src/ast/rewriter/expr_safe_replace.cpp
@@ -20,9 +20,11 @@ Revision History:
#include "expr_safe_replace.h"
#include "rewriter.h"
+#include "ast_pp.h"
void expr_safe_replace::insert(expr* src, expr* dst) {
+ SASSERT(m.get_sort(src) == m.get_sort(dst));
m_src.push_back(src);
m_dst.push_back(dst);
m_subst.insert(src, dst);
@@ -30,7 +32,7 @@ void expr_safe_replace::insert(expr* src, expr* dst) {
void expr_safe_replace::operator()(expr* e, expr_ref& res) {
m_todo.push_back(e);
- expr* a, *b, *d;
+ expr* a, *b;
while (!m_todo.empty()) {
a = m_todo.back();
@@ -39,7 +41,7 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) {
}
else if (m_subst.find(a, b)) {
m_cache.insert(a, b);
- m_todo.pop_back();
+ m_todo.pop_back();
}
else if (is_var(a)) {
m_cache.insert(a, a);
@@ -51,18 +53,21 @@ void expr_safe_replace::operator()(expr* e, expr_ref& res) {
m_args.reset();
bool arg_differs = false;
for (unsigned i = 0; i < n; ++i) {
- if (m_cache.find(c->get_arg(i), d)) {
+ expr* d = 0, *arg = c->get_arg(i);
+ if (m_cache.find(arg, d)) {
m_args.push_back(d);
- arg_differs |= c->get_arg(i) != d;
+ arg_differs |= arg != d;
+ SASSERT(m.get_sort(arg) == m.get_sort(d));
}
else {
- m_todo.push_back(c->get_arg(i));
+ m_todo.push_back(arg);
}
}
if (m_args.size() == n) {
if (arg_differs) {
b = m.mk_app(c->get_decl(), m_args.size(), m_args.c_ptr());
m_refs.push_back(b);
+ SASSERT(m.get_sort(a) == m.get_sort(b));
} else {
b = a;
}
diff --git a/src/ast/rewriter/fpa_rewriter.cpp b/src/ast/rewriter/fpa_rewriter.cpp
index 63af356c8..bc3f8c25e 100644
--- a/src/ast/rewriter/fpa_rewriter.cpp
+++ b/src/ast/rewriter/fpa_rewriter.cpp
@@ -213,7 +213,7 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const
mpf_exp_t mpf_exp = mpzm.get_int64(exp);
mpf_exp = m_fm.unbias_exp(ebits, mpf_exp);
- m_fm.set(v, ebits, sbits, !mpzm.is_zero(z), sig, mpf_exp);
+ m_fm.set(v, ebits, sbits, !mpzm.is_zero(z), mpf_exp, sig);
TRACE("fp_rewriter",
tout << "sgn: " << !mpzm.is_zero(z) << std::endl;
tout << "sig: " << mpzm.to_string(sig) << std::endl;
@@ -267,7 +267,21 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const
return BR_FAILED;
TRACE("fp_rewriter", tout << "r1: " << r1 << ", r2: " << r2 << "\n";);
- m_fm.set(v, ebits, sbits, rmv, r1.to_mpq(), r2.to_mpq().numerator());
+ m_fm.set(v, ebits, sbits, rmv, r2.to_mpq().numerator(), r1.to_mpq());
+ result = m_util.mk_value(v);
+ return BR_DONE;
+ }
+ else if (m_util.is_rm_numeral(args[0], rmv) &&
+ m_util.au().is_int(args[1]) &&
+ m_util.au().is_real(args[2])) {
+ // rm + int + real -> float
+ if (!m_util.is_rm_numeral(args[0], rmv) ||
+ !m_util.au().is_numeral(args[1], r1) ||
+ !m_util.au().is_numeral(args[2], r2))
+ return BR_FAILED;
+
+ TRACE("fp_rewriter", tout << "r1: " << r1 << ", r2: " << r2 << "\n";);
+ m_fm.set(v, ebits, sbits, rmv, r1.to_mpq().numerator(), r2.to_mpq());
result = m_util.mk_value(v);
return BR_DONE;
}
@@ -281,8 +295,8 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const
mpf_exp_t biased_exp = m_fm.mpz_manager().get_int64(r2.to_mpq().numerator());
m_fm.set(v, bvs2, bvs3 + 1,
r1.is_one(),
- r3.to_mpq().numerator(),
- m_fm.unbias_exp(bvs2, biased_exp));
+ m_fm.unbias_exp(bvs2, biased_exp),
+ r3.to_mpq().numerator());
TRACE("fp_rewriter", tout << "v = " << m_fm.to_string(v) << std::endl;);
result = m_util.mk_value(v);
return BR_DONE;
@@ -753,24 +767,23 @@ br_status fpa_rewriter::mk_rm(expr * arg, expr_ref & result) {
return BR_FAILED;
}
-br_status fpa_rewriter::mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) {
+br_status fpa_rewriter::mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result) {
unsynch_mpz_manager & mpzm = m_fm.mpz_manager();
bv_util bu(m());
- rational r1, r2, r3;
- unsigned bvs1, bvs2, bvs3;
+ rational rsgn, rexp, rsig;
+ unsigned bvsz_sgn, bvsz_exp, bvsz_sig;
- if (bu.is_numeral(arg1, r1, bvs1) &&
- bu.is_numeral(arg2, r2, bvs2) &&
- bu.is_numeral(arg3, r3, bvs3)) {
- SASSERT(mpzm.is_one(r2.to_mpq().denominator()));
- SASSERT(mpzm.is_one(r3.to_mpq().denominator()));
- SASSERT(mpzm.is_int64(r3.to_mpq().numerator()));
+ if (bu.is_numeral(sgn, rsgn, bvsz_sgn) &&
+ bu.is_numeral(sig, rsig, bvsz_sig) &&
+ bu.is_numeral(exp, rexp, bvsz_exp)) {
+ SASSERT(mpzm.is_one(rexp.to_mpq().denominator()));
+ SASSERT(mpzm.is_one(rsig.to_mpq().denominator()));
scoped_mpf v(m_fm);
- mpf_exp_t biased_exp = mpzm.get_int64(r2.to_mpq().numerator());
- m_fm.set(v, bvs2, bvs3 + 1,
- r1.is_one(),
- r3.to_mpq().numerator(),
- m_fm.unbias_exp(bvs2, biased_exp));
+ mpf_exp_t biased_exp = mpzm.get_int64(rexp.to_mpq().numerator());
+ m_fm.set(v, bvsz_exp, bvsz_sig + 1,
+ rsgn.is_one(),
+ m_fm.unbias_exp(bvsz_exp, biased_exp),
+ rsig.to_mpq().numerator());
TRACE("fp_rewriter", tout << "simplified (fp ...) to " << m_fm.to_string(v) << std::endl;);
result = m_util.mk_value(v);
return BR_DONE;
diff --git a/src/ast/rewriter/fpa_rewriter.h b/src/ast/rewriter/fpa_rewriter.h
index 43d138cad..0889bba72 100644
--- a/src/ast/rewriter/fpa_rewriter.h
+++ b/src/ast/rewriter/fpa_rewriter.h
@@ -79,7 +79,7 @@ public:
br_status mk_to_fp_unsigned(func_decl * f, expr * arg1, expr * arg2, expr_ref & result);
br_status mk_rm(expr * arg, expr_ref & result);
- br_status mk_fp(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
+ br_status mk_fp(expr * sgn, expr * exp, expr * sig, expr_ref & result);
br_status mk_to_fp_unsigned(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_to_ubv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result);
br_status mk_to_sbv(func_decl * f, expr * arg1, expr * arg2, expr_ref & result);
diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp
index 8a9ede35f..3ee8675d8 100644
--- a/src/ast/rewriter/seq_rewriter.cpp
+++ b/src/ast/rewriter/seq_rewriter.cpp
@@ -22,30 +22,144 @@ Notes:
#include"ast_pp.h"
#include"ast_util.h"
#include"uint_set.h"
+#include"automaton.h"
+#include"well_sorted.h"
+struct display_expr1 {
+ ast_manager& m;
+ display_expr1(ast_manager& m): m(m) {}
+ std::ostream& display(std::ostream& out, expr* e) const {
+ return out << mk_pp(e, m);
+ }
+};
+
+
+re2automaton::re2automaton(ast_manager& m): m(m), u(m) {}
+
+eautomaton* re2automaton::operator()(expr* e) {
+ eautomaton* r = re2aut(e);
+ if (r) {
+ //display_expr1 disp(m);
+ //r->display(std::cout, disp);
+ r->compress();
+ //r->display(std::cout, disp);
+ }
+ return r;
+}
+
+
+eautomaton* re2automaton::re2aut(expr* e) {
+ SASSERT(u.is_re(e));
+ expr* e1, *e2;
+ scoped_ptr a, b;
+ if (u.re.is_to_re(e, e1)) {
+ return seq2aut(e1);
+ }
+ else if (u.re.is_concat(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) {
+ return eautomaton::mk_concat(*a, *b);
+ }
+ else if (u.re.is_union(e, e1, e2) && (a = re2aut(e1)) && (b = re2aut(e2))) {
+ return eautomaton::mk_union(*a, *b);
+ }
+ else if (u.re.is_star(e, e1) && (a = re2aut(e1))) {
+ a->add_final_to_init_moves();
+ a->add_init_to_final_states();
+
+ return a.detach();
+ }
+ else if (u.re.is_plus(e, e1) && (a = re2aut(e1))) {
+ a->add_final_to_init_moves();
+ return a.detach();
+ }
+ else if (u.re.is_opt(e, e1) && (a = re2aut(e1))) {
+ a = eautomaton::mk_opt(*a);
+ return a.detach();
+ }
+ else if (u.re.is_range(e)) {
+
+ }
+ else if (u.re.is_loop(e)) {
+
+ }
+#if 0
+ else if (u.re.is_intersect(e, e1, e2)) {
+
+ }
+ else if (u.re.is_empty(e)) {
+
+ }
+#endif
+
+ return 0;
+}
+
+eautomaton* re2automaton::seq2aut(expr* e) {
+ SASSERT(u.is_seq(e));
+ zstring s;
+ expr* e1, *e2;
+ scoped_ptr a, b;
+ if (u.str.is_concat(e, e1, e2) && (a = seq2aut(e1)) && (b = seq2aut(e2))) {
+ return eautomaton::mk_concat(*a, *b);
+ }
+ else if (u.str.is_unit(e, e1)) {
+ return alloc(eautomaton, m, e1);
+ }
+ else if (u.str.is_empty(e)) {
+ return eautomaton::mk_epsilon(m);
+ }
+ else if (u.str.is_string(e, s)) {
+ unsigned init = 0;
+ eautomaton::moves mvs;
+ unsigned_vector final;
+ final.push_back(s.length());
+ for (unsigned k = 0; k < s.length(); ++k) {
+ // reference count?
+ mvs.push_back(eautomaton::move(m, k, k+1, u.str.mk_char(s, k)));
+ }
+ return alloc(eautomaton, m, init, final, mvs);
+ }
+ return 0;
+}
+
br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == get_fid());
switch(f->get_decl_kind()) {
case OP_SEQ_UNIT:
- case OP_SEQ_EMPTY:
-
- case OP_RE_PLUS:
- case OP_RE_STAR:
- case OP_RE_OPTION:
- case OP_RE_RANGE:
- case OP_RE_CONCAT:
- case OP_RE_UNION:
- case OP_RE_INTERSECT:
- case OP_RE_LOOP:
- case OP_RE_EMPTY_SET:
- case OP_RE_FULL_SET:
- case OP_RE_OF_PRED:
- case _OP_SEQ_SKOLEM:
return BR_FAILED;
-
+ case OP_SEQ_EMPTY:
+ return BR_FAILED;
+ case OP_RE_PLUS:
+ SASSERT(num_args == 1);
+ return mk_re_plus(args[0], result);
+ case OP_RE_STAR:
+ SASSERT(num_args == 1);
+ return mk_re_star(args[0], result);
+ case OP_RE_OPTION:
+ SASSERT(num_args == 1);
+ return mk_re_opt(args[0], result);
+ case OP_RE_CONCAT:
+ SASSERT(num_args == 2);
+ return mk_re_concat(args[0], args[1], result);
+ case OP_RE_UNION:
+ SASSERT(num_args == 2);
+ return mk_re_union(args[0], args[1], result);
+ case OP_RE_RANGE:
+ return BR_FAILED;
+ case OP_RE_INTERSECT:
+ return BR_FAILED;
+ case OP_RE_LOOP:
+ return BR_FAILED;
+ case OP_RE_EMPTY_SET:
+ return BR_FAILED;
+ case OP_RE_FULL_SET:
+ return BR_FAILED;
+ case OP_RE_OF_PRED:
+ return BR_FAILED;
+ case _OP_SEQ_SKOLEM:
+ return BR_FAILED;
case OP_SEQ_CONCAT:
if (num_args == 1) {
result = args[0];
@@ -83,10 +197,11 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
SASSERT(num_args == 3);
return mk_seq_replace(args[0], args[1], args[2], result);
case OP_SEQ_TO_RE:
- return BR_FAILED;
+ SASSERT(num_args == 1);
+ return mk_str_to_regexp(args[0], result);
case OP_SEQ_IN_RE:
- return BR_FAILED;
-
+ SASSERT(num_args == 2);
+ return mk_str_in_regexp(args[0], args[1], result);
case OP_STRING_CONST:
return BR_FAILED;
case OP_STRING_ITOS:
@@ -129,8 +244,8 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
result = m_util.str.mk_string(s1 + s2);
return BR_DONE;
}
- if (m_util.str.is_concat(b, c, d)) {
- result = m_util.str.mk_concat(m_util.str.mk_concat(a, c), d);
+ if (m_util.str.is_concat(a, c, d)) {
+ result = m_util.str.mk_concat(c, m_util.str.mk_concat(d, b));
return BR_REWRITE2;
}
if (m_util.str.is_empty(a)) {
@@ -141,11 +256,15 @@ br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
result = a;
return BR_DONE;
}
- if (m_util.str.is_concat(a, c, d) &&
- m_util.str.is_string(d, s1) && isc2) {
+ // TBD concatenation is right-associative
+ if (isc2 && m_util.str.is_concat(a, c, d) && m_util.str.is_string(d, s1)) {
result = m_util.str.mk_concat(c, m_util.str.mk_string(s1 + s2));
return BR_DONE;
}
+ if (isc1 && m_util.str.is_concat(b, c, d) && m_util.str.is_string(c, s2)) {
+ result = m_util.str.mk_concat(m_util.str.mk_string(s1 + s2), d);
+ return BR_DONE;
+ }
return BR_FAILED;
}
@@ -156,17 +275,17 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
unsigned len = 0;
unsigned j = 0;
for (unsigned i = 0; i < m_es.size(); ++i) {
- if (m_util.str.is_string(m_es[i], b)) {
+ if (m_util.str.is_string(m_es[i].get(), b)) {
len += b.length();
}
- else if (m_util.str.is_unit(m_es[i])) {
+ else if (m_util.str.is_unit(m_es[i].get())) {
len += 1;
}
- else if (m_util.str.is_empty(m_es[i])) {
+ else if (m_util.str.is_empty(m_es[i].get())) {
// skip
}
else {
- m_es[j] = m_es[i];
+ m_es[j] = m_es[i].get();
++j;
}
}
@@ -177,7 +296,7 @@ br_status seq_rewriter::mk_seq_length(expr* a, expr_ref& result) {
if (j != m_es.size() || j != 1) {
expr_ref_vector es(m());
for (unsigned i = 0; i < j; ++i) {
- es.push_back(m_util.str.mk_length(m_es[i]));
+ es.push_back(m_util.str.mk_length(m_es[i].get()));
}
if (len != 0) {
es.push_back(m_autil.mk_numeral(rational(len, rational::ui64()), true));
@@ -207,20 +326,31 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
return BR_DONE;
}
// check if subsequence of b is in a.
- ptr_vector as, bs;
+ expr_ref_vector as(m()), bs(m());
m_util.str.get_concat(a, as);
m_util.str.get_concat(b, bs);
+ bool all_values = true;
+
+ for (unsigned i = 0; all_values && i < bs.size(); ++i) {
+ all_values = m().is_value(bs[i].get());
+ }
+
bool found = false;
for (unsigned i = 0; !found && i < as.size(); ++i) {
if (bs.size() > as.size() - i) break;
+ all_values &= m().is_value(as[i].get());
unsigned j = 0;
- for (; j < bs.size() && as[j+i] == bs[j]; ++j) {};
+ for (; j < bs.size() && as[j+i].get() == bs[j].get(); ++j) {};
found = j == bs.size();
}
if (found) {
result = m().mk_true();
return BR_DONE;
}
+ if (all_values) {
+ result = m().mk_false();
+ return BR_DONE;
+ }
return BR_FAILED;
}
@@ -292,7 +422,7 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
expr* b1 = m_util.str.get_leftmost_concat(b);
isc1 = m_util.str.is_string(a1, s1);
isc2 = m_util.str.is_string(b1, s2);
- ptr_vector as, bs;
+ expr_ref_vector as(m()), bs(m());
if (a1 != b1 && isc1 && isc2) {
if (s1.length() <= s2.length()) {
@@ -342,15 +472,26 @@ br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
m_util.str.get_concat(a, as);
m_util.str.get_concat(b, bs);
unsigned i = 0;
- for (; i < as.size() && i < bs.size() && as[i] == bs[i]; ++i) {};
+ bool all_values = true;
+ for (; i < as.size() && i < bs.size(); ++i) {
+ all_values &= m().is_value(as[i].get()) && m().is_value(bs[i].get());
+ if (as[i].get() != bs[i].get()) {
+ if (all_values) {
+ result = m().mk_false();
+ return BR_DONE;
+ }
+ break;
+ }
+ };
if (i == as.size()) {
result = m().mk_true();
return BR_DONE;
}
+ SASSERT(i < as.size());
if (i == bs.size()) {
expr_ref_vector es(m());
for (unsigned j = i; j < as.size(); ++j) {
- es.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j]));
+ es.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get()));
}
result = mk_and(es);
return BR_REWRITE3;
@@ -380,20 +521,10 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
result = m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), a);
return BR_REWRITE3;
}
- // concatenation is left-associative, so a2, b2 are not concatenations
- expr* a1, *a2, *b1, *b2;
- if (m_util.str.is_concat(a, a1, a2) &&
- m_util.str.is_concat(b, b1, b2) && a2 == b2) {
- result = m_util.str.mk_suffix(a1, b1);
- return BR_REWRITE1;
- }
- if (m_util.str.is_concat(b, b1, b2) && b2 == a) {
- result = m().mk_true();
- return BR_DONE;
- }
+
bool isc1 = false;
bool isc2 = false;
-
+ expr* a1, *a2, *b1, *b2;
if (m_util.str.is_concat(a, a1, a2) && m_util.str.is_string(a2, s1)) {
isc1 = true;
}
@@ -453,6 +584,37 @@ br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
}
}
}
+ expr_ref_vector as(m()), bs(m());
+ m_util.str.get_concat(a, as);
+ m_util.str.get_concat(b, bs);
+ bool change = false;
+ while (as.size() > 0 && bs.size() > 0 && as.back() == bs.back()) {
+ as.pop_back();
+ bs.pop_back();
+ change = true;
+ }
+ if (as.size() > 0 && bs.size() > 0 && m().is_value(as.back()) && m().is_value(bs.back())) {
+ result = m().mk_false();
+ return BR_DONE;
+ }
+ if (change) {
+ // suffix("", bs) <- true
+ if (as.empty()) {
+ result = m().mk_true();
+ return BR_DONE;
+ }
+ // suffix(as, "") iff as = ""
+ if (bs.empty()) {
+ for (unsigned j = 0; j < as.size(); ++j) {
+ bs.push_back(m().mk_eq(m_util.str.mk_empty(m().get_sort(a)), as[j].get()));
+ }
+ result = mk_and(bs);
+ return BR_REWRITE3;
+ }
+ result = m_util.str.mk_suffix(m_util.str.mk_concat(as.size(), as.c_ptr()),
+ m_util.str.mk_concat(bs.size(), bs.c_ptr()));
+ return BR_DONE;
+ }
return BR_FAILED;
}
@@ -480,26 +642,190 @@ br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
}
return BR_FAILED;
}
+
+void seq_rewriter::add_next(u_map& next, unsigned idx, expr* cond) {
+ expr* acc;
+ if (m().is_true(cond) || !next.find(idx, acc)) {
+ next.insert(idx, cond);
+ }
+ else {
+ next.insert(idx, m().mk_or(cond, acc));
+ }
+}
+
+bool seq_rewriter::is_sequence(expr* e, expr_ref_vector& seq) {
+ zstring s;
+ ptr_vector todo;
+ expr *e1, *e2;
+ todo.push_back(e);
+ while (!todo.empty()) {
+ e = todo.back();
+ todo.pop_back();
+ if (m_util.str.is_string(e, s)) {
+ for (unsigned i = s.length(); i > 0; ) {
+ --i;
+ seq.push_back(m_util.str.mk_char(s, i));
+ }
+ }
+ else if (m_util.str.is_empty(e)) {
+ continue;
+ }
+ else if (m_util.str.is_unit(e)) {
+ seq.push_back(e);
+ }
+ else if (m_util.str.is_concat(e, e1, e2)) {
+ todo.push_back(e1);
+ todo.push_back(e2);
+ }
+ else {
+ return false;
+ }
+ }
+ seq.reverse();
+ return true;
+}
+
br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
+ scoped_ptr aut;
+ expr_ref_vector seq(m());
+ if (is_sequence(a, seq) && (aut = re2automaton(m())(b))) {
+ expr_ref_vector trail(m());
+ u_map maps[2];
+ bool select_map = false;
+ expr_ref ch(m()), cond(m());
+ eautomaton::moves mvs;
+ maps[0].insert(aut->init(), m().mk_true());
+ // is_accepted(a, aut) & some state in frontier is final.
+
+ for (unsigned i = 0; i < seq.size(); ++i) {
+ u_map& frontier = maps[select_map];
+ u_map& next = maps[!select_map];
+ select_map = !select_map;
+ ch = seq[i].get();
+ next.reset();
+ u_map::iterator it = frontier.begin(), end = frontier.end();
+ for (; it != end; ++it) {
+ mvs.reset();
+ unsigned state = it->m_key;
+ expr* acc = it->m_value;
+ aut->get_moves_from(state, mvs, false);
+ for (unsigned j = 0; j < mvs.size(); ++j) {
+ eautomaton::move const& mv = mvs[j];
+ if (m().is_value(mv.t()) && m().is_value(ch)) {
+ if (mv.t() == ch) {
+ add_next(next, mv.dst(), acc);
+ }
+ else {
+ continue;
+ }
+ }
+ else {
+ cond = m().mk_eq(mv.t(), ch);
+ if (!m().is_true(acc)) cond = m().mk_and(acc, cond);
+ add_next(next, mv.dst(), cond);
+ }
+ }
+ }
+ }
+ u_map const& frontier = maps[select_map];
+ u_map::iterator it = frontier.begin(), end = frontier.end();
+ expr_ref_vector ors(m());
+ for (; it != end; ++it) {
+ unsigned_vector states;
+ bool has_final = false;
+ aut->get_epsilon_closure(it->m_key, states);
+ for (unsigned i = 0; i < states.size() && !has_final; ++i) {
+ has_final = aut->is_final_state(states[i]);
+ }
+ if (has_final) {
+ ors.push_back(it->m_value);
+ }
+ }
+ result = mk_or(ors);
+ return BR_REWRITE_FULL;
+ }
return BR_FAILED;
}
br_status seq_rewriter::mk_str_to_regexp(expr* a, expr_ref& result) {
return BR_FAILED;
}
br_status seq_rewriter::mk_re_concat(expr* a, expr* b, expr_ref& result) {
+ if (is_epsilon(a)) {
+ result = b;
+ return BR_DONE;
+ }
+ if (is_epsilon(b)) {
+ result = a;
+ return BR_DONE;
+ }
return BR_FAILED;
}
+/*
+ (a + a) = a
+ (a + eps) = a
+ (eps + a) = a
+*/
br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) {
+ if (a == b) {
+ result = a;
+ return BR_DONE;
+ }
+ if (m_util.re.is_star(a) && is_epsilon(b)) {
+ result = a;
+ return BR_DONE;
+ }
+ if (m_util.re.is_star(b) && is_epsilon(a)) {
+ result = b;
+ return BR_DONE;
+ }
return BR_FAILED;
}
+/*
+ a** = a*
+ (a* + b)* = (a + b)*
+ (a + b*)* = (a + b)*
+ (a*b*)* = (a + b)*
+*/
br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
+ expr* b, *c, *b1, *c1;
+ if (m_util.re.is_star(a)) {
+ result = a;
+ return BR_DONE;
+ }
+ if (m_util.re.is_union(a, b, c)) {
+ if (m_util.re.is_star(b, b1)) {
+ result = m_util.re.mk_star(m_util.re.mk_union(b1, c));
+ return BR_REWRITE2;
+ }
+ if (m_util.re.is_star(c, c1)) {
+ result = m_util.re.mk_star(m_util.re.mk_union(b, c1));
+ return BR_REWRITE2;
+ }
+ }
+ if (m_util.re.is_concat(a, b, c) &&
+ m_util.re.is_star(b, b1) && m_util.re.is_star(c, c1)) {
+ result = m_util.re.mk_star(m_util.re.mk_union(b1, c1));
+ return BR_REWRITE2;
+ }
+
return BR_FAILED;
}
+
+/*
+ a+ = aa*
+*/
br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) {
return BR_FAILED;
+// result = m_util.re.mk_concat(a, m_util.re.mk_star(a));
+// return BR_REWRITE2;
}
+
br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) {
- return BR_FAILED;
+ sort* s;
+ VERIFY(m_util.is_re(a, s));
+ sort_ref seq(m_util.str.mk_seq(s), m());
+ result = m_util.re.mk_union(m_util.re.mk_to_re(m_util.str.mk_empty(seq)), a);
+ return BR_REWRITE1;
}
br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
@@ -518,38 +844,33 @@ br_status seq_rewriter::mk_eq_core(expr * l, expr * r, expr_ref & result) {
return BR_REWRITE3;
}
-bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) {
+bool seq_rewriter::reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs) {
expr* a, *b;
zstring s;
bool change = false;
- expr_ref_vector trail(m());
- m_lhs.reset();
- m_rhs.reset();
- m_util.str.get_concat(l, m_lhs);
- m_util.str.get_concat(r, m_rhs);
// solve from back
while (true) {
- while (!m_rhs.empty() && m_util.str.is_empty(m_rhs.back())) {
- m_rhs.pop_back();
+ while (!rs.empty() && m_util.str.is_empty(rs.back())) {
+ rs.pop_back();
change = true;
}
- while (!m_lhs.empty() && m_util.str.is_empty(m_lhs.back())) {
- m_lhs.pop_back();
+ while (!ls.empty() && m_util.str.is_empty(ls.back())) {
+ ls.pop_back();
change = true;
}
- if (m_lhs.empty() || m_rhs.empty()) {
+ if (ls.empty() || rs.empty()) {
break;
}
- expr* l = m_lhs.back();
- expr* r = m_rhs.back();
+ expr* l = ls.back();
+ expr* r = rs.back();
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
std::swap(l, r);
- std::swap(m_lhs, m_rhs);
+ ls.swap(rs);
}
if (l == r) {
- m_lhs.pop_back();
- m_rhs.pop_back();
+ ls.pop_back();
+ rs.pop_back();
}
else if(m_util.str.is_unit(l, a) &&
m_util.str.is_unit(r, b)) {
@@ -558,8 +879,8 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
}
lhs.push_back(a);
rhs.push_back(b);
- m_lhs.pop_back();
- m_rhs.pop_back();
+ ls.pop_back();
+ rs.pop_back();
}
else if (m_util.str.is_unit(l, a) && m_util.str.is_string(r, s)) {
SASSERT(s.length() > 0);
@@ -568,14 +889,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
SASSERT(m().get_sort(ch) == m().get_sort(a));
lhs.push_back(ch);
rhs.push_back(a);
- m_lhs.pop_back();
+ ls.pop_back();
if (s.length() == 1) {
- m_rhs.pop_back();
+ rs.pop_back();
}
else {
expr_ref s2(m_util.str.mk_string(s.extract(0, s.length()-2)), m());
- m_rhs[m_rhs.size()-1] = s2;
- trail.push_back(s2);
+ rs[rs.size()-1] = s2;
}
}
else {
@@ -587,22 +907,22 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
// solve from front
unsigned head1 = 0, head2 = 0;
while (true) {
- while (head1 < m_lhs.size() && m_util.str.is_empty(m_lhs[head1])) {
+ while (head1 < ls.size() && m_util.str.is_empty(ls[head1].get())) {
++head1;
}
- while (head2 < m_rhs.size() && m_util.str.is_empty(m_rhs[head2])) {
+ while (head2 < rs.size() && m_util.str.is_empty(rs[head2].get())) {
++head2;
}
- if (head1 == m_lhs.size() || head2 == m_rhs.size()) {
+ if (head1 == ls.size() || head2 == rs.size()) {
break;
}
- SASSERT(head1 < m_lhs.size() && head2 < m_rhs.size());
+ SASSERT(head1 < ls.size() && head2 < rs.size());
- expr* l = m_lhs[head1];
- expr* r = m_rhs[head2];
+ expr* l = ls[head1].get();
+ expr* r = rs[head2].get();
if (m_util.str.is_unit(r) && m_util.str.is_string(l)) {
std::swap(l, r);
- std::swap(m_lhs, m_rhs);
+ ls.swap(rs);
}
if (l == r) {
++head1;
@@ -624,14 +944,13 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
SASSERT(m().get_sort(ch) == m().get_sort(a));
lhs.push_back(ch);
rhs.push_back(a);
- m_lhs.pop_back();
+ ls.pop_back();
if (s.length() == 1) {
- m_rhs.pop_back();
+ rs.pop_back();
}
else {
expr_ref s2(m_util.str.mk_string(s.extract(1, s.length()-1)), m());
- m_rhs[m_rhs.size()-1] = s2;
- trail.push_back(s2);
+ rs[rs.size()-1] = s2;
}
}
else {
@@ -641,10 +960,10 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
}
// reduce strings
zstring s1, s2;
- while (head1 < m_lhs.size() &&
- head2 < m_rhs.size() &&
- m_util.str.is_string(m_lhs[head1], s1) &&
- m_util.str.is_string(m_rhs[head2], s2)) {
+ while (head1 < ls.size() &&
+ head2 < rs.size() &&
+ m_util.str.is_string(ls[head1].get(), s1) &&
+ m_util.str.is_string(rs[head2].get(), s2)) {
unsigned l = std::min(s1.length(), s2.length());
for (unsigned i = 0; i < l; ++i) {
if (s1[i] != s2[i]) {
@@ -655,68 +974,88 @@ bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_ve
++head1;
}
else {
- m_lhs[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
- trail.push_back(m_lhs[head1]);
+ ls[head1] = m_util.str.mk_string(s1.extract(l, s1.length()-l));
}
if (l == s2.length()) {
++head2;
}
else {
- m_rhs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
- trail.push_back(m_rhs[head2]);
+ rs[head2] = m_util.str.mk_string(s2.extract(l, s2.length()-l));
}
change = true;
}
- while (head1 < m_lhs.size() &&
- head2 < m_rhs.size() &&
- m_util.str.is_string(m_lhs.back(), s1) &&
- m_util.str.is_string(m_rhs.back(), s2)) {
+ while (head1 < ls.size() &&
+ head2 < rs.size() &&
+ m_util.str.is_string(ls.back(), s1) &&
+ m_util.str.is_string(rs.back(), s2)) {
unsigned l = std::min(s1.length(), s2.length());
for (unsigned i = 0; i < l; ++i) {
if (s1[s1.length()-i-1] != s2[s2.length()-i-1]) {
return false;
}
}
- m_lhs.pop_back();
- m_rhs.pop_back();
+ ls.pop_back();
+ rs.pop_back();
if (l < s1.length()) {
- m_lhs.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
- trail.push_back(m_lhs.back());
+ ls.push_back(m_util.str.mk_string(s1.extract(0, s1.length()-l)));
}
if (l < s2.length()) {
- m_rhs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
- trail.push_back(m_rhs.back());
- }
+ rs.push_back(m_util.str.mk_string(s2.extract(0, s2.length()-l)));
+ }
change = true;
}
bool is_sat;
- unsigned szl = m_lhs.size() - head1, szr = m_rhs.size() - head2;
- expr* const* ls = m_lhs.c_ptr() + head1, * const*rs = m_rhs.c_ptr() + head2;
- if (length_constrained(szl, ls, szr, rs, lhs, rhs, is_sat)) {
+ unsigned szl = ls.size() - head1, szr = rs.size() - head2;
+ expr* const* _ls = ls.c_ptr() + head1, * const* _rs = rs.c_ptr() + head2;
+ if (length_constrained(szl, _ls, szr, _rs, lhs, rhs, is_sat)) {
+ ls.reset(); rs.reset();
return is_sat;
}
- if (is_subsequence(szl, ls, szr, rs, lhs, rhs, is_sat)) {
+ if (is_subsequence(szl, _ls, szr, _rs, lhs, rhs, is_sat)) {
+ ls.reset(); rs.reset();
return is_sat;
}
- if (szl == 0 && szr == 0) {
- return true;
- }
+ if (szl == 0 && szr == 0) {
+ ls.reset(); rs.reset();
+ return true;
+ }
else if (!change) {
- lhs.push_back(l);
- rhs.push_back(r);
+ // skip
+ SASSERT(lhs.empty());
}
else {
// could solve if either side is fixed size.
SASSERT(szl > 0 && szr > 0);
-
- lhs.push_back(m_util.str.mk_concat(szl, ls));
- rhs.push_back(m_util.str.mk_concat(szr, rs));
+ lhs.push_back(m_util.str.mk_concat(szl, ls.c_ptr() + head1));
+ rhs.push_back(m_util.str.mk_concat(szr, rs.c_ptr() + head2));
+ ls.reset();
+ rs.reset();
}
+ SASSERT(lhs.empty() || ls.empty());
return true;
}
+bool seq_rewriter::reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs) {
+ m_lhs.reset();
+ m_rhs.reset();
+ m_util.str.get_concat(l, m_lhs);
+ m_util.str.get_concat(r, m_rhs);
+ if (reduce_eq(m_lhs, m_rhs, lhs, rhs)) {
+ SASSERT(lhs.size() == rhs.size());
+ if (lhs.empty()) {
+ lhs.push_back(l);
+ rhs.push_back(r);
+ }
+ return true;
+ }
+ else {
+ TRACE("seq", tout << mk_pp(l, m()) << " != " << mk_pp(r, m()) << "\n";);
+ return false;
+ }
+}
+
expr* seq_rewriter::concat_non_empty(unsigned n, expr* const* as) {
SASSERT(n > 0);
ptr_vector bs;
@@ -812,6 +1151,11 @@ bool seq_rewriter::length_constrained(unsigned szl, expr* const* l, unsigned szr
return false;
}
+bool seq_rewriter::is_epsilon(expr* e) const {
+ expr* e1;
+ return m_util.re.is_to_re(e, e1) && m_util.str.is_empty(e1);
+}
+
bool seq_rewriter::is_subsequence(unsigned szl, expr* const* l, unsigned szr, expr* const* r,
expr_ref_vector& lhs, expr_ref_vector& rhs, bool& is_sat) {
is_sat = true;
diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h
index de3634a51..9d4dbb14f 100644
--- a/src/ast/rewriter/seq_rewriter.h
+++ b/src/ast/rewriter/seq_rewriter.h
@@ -24,15 +24,27 @@ Notes:
#include"rewriter_types.h"
#include"params.h"
#include"lbool.h"
+#include"automaton.h"
+typedef automaton eautomaton;
+class re2automaton {
+ ast_manager& m;
+ seq_util u;
+ eautomaton* re2aut(expr* e);
+ eautomaton* seq2aut(expr* e);
+ public:
+ re2automaton(ast_manager& m);
+ eautomaton* operator()(expr* e);
+};
+
/**
\brief Cheap rewrite rules for seq constraints
*/
class seq_rewriter {
seq_util m_util;
arith_util m_autil;
- ptr_vector m_es, m_lhs, m_rhs;
+ expr_ref_vector m_es, m_lhs, m_rhs;
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
br_status mk_seq_length(expr* a, expr_ref& result);
@@ -61,9 +73,13 @@ class seq_rewriter {
bool min_length(unsigned n, expr* const* es, unsigned& len);
expr* concat_non_empty(unsigned n, expr* const* es);
+ void add_next(u_map& next, unsigned idx, expr* cond);
+ bool is_sequence(expr* e, expr_ref_vector& seq);
+ bool is_epsilon(expr* e) const;
+
public:
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
- m_util(m), m_autil(m) {
+ m_util(m), m_autil(m), m_es(m), m_lhs(m), m_rhs(m) {
}
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
@@ -76,6 +92,8 @@ public:
bool reduce_eq(expr* l, expr* r, expr_ref_vector& lhs, expr_ref_vector& rhs);
+ bool reduce_eq(expr_ref_vector& ls, expr_ref_vector& rs, expr_ref_vector& lhs, expr_ref_vector& rhs);
+
};
#endif
diff --git a/src/ast/seq_decl_plugin.cpp b/src/ast/seq_decl_plugin.cpp
index cda154050..9c8a085e8 100644
--- a/src/ast/seq_decl_plugin.cpp
+++ b/src/ast/seq_decl_plugin.cpp
@@ -25,7 +25,6 @@ Revision History:
zstring::zstring(encoding enc): m_encoding(enc) {}
zstring::zstring(char const* s, encoding enc): m_encoding(enc) {
- // TBD: epply decoding
while (*s) {
m_buffer.push_back(*s);
++s;
@@ -42,7 +41,7 @@ zstring::zstring(unsigned num_bits, bool const* ch) {
m_encoding = (num_bits == 8)?ascii:unicode;
unsigned n = 0;
for (unsigned i = 0; i < num_bits; ++i) {
- n |= (((unsigned)ch[i]) << num_bits);
+ n |= (((unsigned)ch[i]) << i);
}
m_buffer.push_back(n);
}
@@ -81,12 +80,24 @@ zstring zstring::replace(zstring const& src, zstring const& dst) const {
return result;
}
+static const char esc_table[32][3] =
+ { "\\0", "^A", "^B", "^C", "^D", "^E", "^F", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "^N",
+ "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V","^W","^X","^Y","^Z","\\e","^\\","^]","^^","^_"};
+
std::string zstring::encode() const {
- // TBD apply encodings.
SASSERT(m_encoding == ascii);
std::ostringstream strm;
for (unsigned i = 0; i < m_buffer.size(); ++i) {
- strm << (char)(m_buffer[i]);
+ unsigned char ch = m_buffer[i];
+ if (0 <= ch && ch < 32) {
+ strm << esc_table[ch];
+ }
+ else if (ch == 127) {
+ strm << "^?";
+ }
+ else {
+ strm << (char)(ch);
+ }
}
return strm.str();
}
@@ -163,6 +174,7 @@ std::ostream& zstring::operator<<(std::ostream& out) const {
seq_decl_plugin::seq_decl_plugin(): m_init(false),
m_stringc_sym("String"),
+ m_charc_sym("Char"),
m_string(0),
m_char(0) {}
@@ -211,9 +223,9 @@ bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) {
}
/*
- \brief match left associative operator.
+ \brief match right associative operator.
*/
-void seq_decl_plugin::match_left_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
+void seq_decl_plugin::match_right_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
ptr_vector binding;
ast_manager& m = *m_manager;
TRACE("seq_verbose",
@@ -369,7 +381,8 @@ void seq_decl_plugin::init() {
void seq_decl_plugin::set_manager(ast_manager* m, family_id id) {
decl_plugin::set_manager(m, id);
- m_char = m->mk_sort(symbol("Char"), sort_info(m_family_id, _CHAR_SORT, 0, (parameter const*)0));
+ bv_util bv(*m);
+ m_char = bv.mk_sort(8);
m->inc_ref(m_char);
parameter param(m_char);
m_string = m->mk_sort(symbol("String"), sort_info(m_family_id, SEQ_SORT, 1, ¶m));
@@ -391,18 +404,18 @@ sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter
return m_string;
}
return m.mk_sort(symbol("Seq"), sort_info(m_family_id, SEQ_SORT, num_parameters, parameters));
- case RE_SORT:
+ case RE_SORT: {
if (num_parameters != 1) {
m.raise_exception("Invalid regex sort, expecting one parameter");
}
if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
m.raise_exception("invalid regex sort, parameter is not a sort");
}
+ sort * s = to_sort(parameters[0].get_ast());
return m.mk_sort(symbol("RegEx"), sort_info(m_family_id, RE_SORT, num_parameters, parameters));
+ }
case _STRING_SORT:
return m_string;
- case _CHAR_SORT:
- return m_char;
default:
UNREACHABLE();
return 0;
@@ -430,9 +443,9 @@ func_decl* seq_decl_plugin::mk_assoc_fun(decl_kind k, unsigned arity, sort* cons
if (arity == 0) {
m.raise_exception("Invalid function application. At least one argument expected");
}
- match_left_assoc(*m_sigs[k], arity, domain, range, rng);
+ match_right_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k_seq);
- info.set_left_associative();
+ info.set_right_associative();
return m.mk_func_decl(m_sigs[(rng == m_string)?k_string:k_seq]->m_name, rng, rng, rng, info);
}
@@ -470,6 +483,8 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
}
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters));
+
+
case OP_STRING_CONST:
if (!(num_parameters == 1 && arity == 0 && parameters[0].is_symbol())) {
m.raise_exception("invalid string declaration");
@@ -583,7 +598,7 @@ void seq_decl_plugin::get_sort_names(svector & sort_names, symbol
app* seq_decl_plugin::mk_string(symbol const& s) {
parameter param(s);
func_decl* f = m_manager->mk_const_decl(m_stringc_sym, m_string,
- func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
+ func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
return m_manager->mk_const(f);
}
@@ -591,12 +606,16 @@ app* seq_decl_plugin::mk_string(zstring const& s) {
symbol sym(s.encode().c_str());
parameter param(sym);
func_decl* f = m_manager->mk_const_decl(m_stringc_sym, m_string,
- func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
+ func_decl_info(m_family_id, OP_STRING_CONST, 1, ¶m));
return m_manager->mk_const(f);
}
+
bool seq_decl_plugin::is_value(app* e) const {
- return is_app_of(e, m_family_id, OP_STRING_CONST);
+ return
+ is_app_of(e, m_family_id, OP_SEQ_EMPTY) ||
+ (is_app_of(e, m_family_id, OP_SEQ_UNIT) &&
+ m_manager->is_value(e->get_arg(0)));
}
app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range) {
@@ -609,11 +628,26 @@ app* seq_util::mk_skolem(symbol const& name, unsigned n, expr* const* args, sort
app* seq_util::str::mk_string(zstring const& s) { return u.seq.mk_string(s); }
+
app* seq_util::str::mk_char(zstring const& s, unsigned idx) {
bv_util bvu(m);
return bvu.mk_numeral(s[idx], s.num_bits());
}
+app* seq_util::str::mk_char(char ch) {
+ zstring s(ch, zstring::ascii);
+ return mk_char(s, 0);
+}
+
+bool seq_util::str::is_char(expr* n, zstring& c) const {
+ if (u.is_char(n)) {
+ c = zstring(to_app(n)->get_decl()->get_parameter(0).get_symbol().bare_str());
+ return true;
+ }
+ else {
+ return false;
+ }
+}
bool seq_util::str::is_string(expr const* n, zstring& s) const {
if (is_string(n)) {
@@ -626,7 +660,7 @@ bool seq_util::str::is_string(expr const* n, zstring& s) const {
}
-void seq_util::str::get_concat(expr* e, ptr_vector& es) const {
+void seq_util::str::get_concat(expr* e, expr_ref_vector& es) const {
expr* e1, *e2;
while (is_concat(e, e1, e2)) {
get_concat(e1, es);
diff --git a/src/ast/seq_decl_plugin.h b/src/ast/seq_decl_plugin.h
index 04161b08d..8cd67a406 100644
--- a/src/ast/seq_decl_plugin.h
+++ b/src/ast/seq_decl_plugin.h
@@ -22,13 +22,13 @@ Revision History:
#define SEQ_DECL_PLUGIN_H_
#include "ast.h"
+#include "bv_decl_plugin.h"
enum seq_sort_kind {
SEQ_SORT,
RE_SORT,
- _STRING_SORT, // internal only
- _CHAR_SORT // internal only
+ _STRING_SORT // internal only
};
enum seq_op_kind {
@@ -131,12 +131,13 @@ class seq_decl_plugin : public decl_plugin {
ptr_vector m_sigs;
bool m_init;
symbol m_stringc_sym;
+ symbol m_charc_sym;
sort* m_string;
sort* m_char;
void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
- void match_left_assoc(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
+ void match_right_assoc(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
bool match(ptr_vector& binding, sort* s, sort* sP);
@@ -187,6 +188,7 @@ public:
ast_manager& get_manager() const { return m; }
+ bool is_char(sort* s) const { return seq.is_char(s); }
bool is_string(sort* s) const { return is_seq(s) && seq.is_char(s->get_parameter(0).get_ast()); }
bool is_seq(sort* s) const { return is_sort_of(s, m_fid, SEQ_SORT); }
bool is_re(sort* s) const { return is_sort_of(s, m_fid, RE_SORT); }
@@ -195,6 +197,7 @@ public:
bool is_seq(sort* s, sort*& seq) { return is_seq(s) && (seq = to_sort(s->get_parameter(0).get_ast()), true); }
bool is_re(expr* e) const { return is_re(m.get_sort(e)); }
bool is_re(expr* e, sort*& seq) const { return is_re(m.get_sort(e), seq); }
+ bool is_char(expr* e) const { return is_char(m.get_sort(e)); }
app* mk_skolem(symbol const& name, unsigned n, expr* const* args, sort* range);
bool is_skolem(expr const* e) const { return is_app_of(e, m_fid, _OP_SEQ_SKOLEM); }
@@ -212,13 +215,13 @@ public:
str(seq_util& u): u(u), m(u.m), m_fid(u.m_fid) {}
sort* mk_seq(sort* s) { parameter param(s); return m.mk_sort(m_fid, SEQ_SORT, 1, ¶m); }
+ sort* mk_string_sort() { return m.mk_sort(m_fid, _STRING_SORT, 0, 0); }
app* mk_empty(sort* s) { return m.mk_const(m.mk_func_decl(m_fid, OP_SEQ_EMPTY, 0, 0, 0, (expr*const*)0, s)); }
app* mk_string(zstring const& s);
app* mk_string(symbol const& s) { return u.seq.mk_string(s); }
+ app* mk_char(char ch);
app* mk_concat(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); }
- app* mk_concat(expr* a, expr* b, expr* c) {
- return mk_concat(mk_concat(a, b), c);
- }
+ app* mk_concat(expr* a, expr* b, expr* c) { return mk_concat(a, mk_concat(b, c)); }
expr* mk_concat(unsigned n, expr* const* es) { if (n == 1) return es[0]; SASSERT(n > 1); return m.mk_app(m_fid, OP_SEQ_CONCAT, n, es); }
app* mk_length(expr* a) { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); }
app* mk_substr(expr* a, expr* b, expr* c) { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); }
@@ -229,8 +232,6 @@ public:
app* mk_unit(expr* u) { return m.mk_app(m_fid, OP_SEQ_UNIT, 1, &u); }
app* mk_char(zstring const& s, unsigned idx);
-
-
bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); }
bool is_string(expr const* n, symbol& s) const {
@@ -238,6 +239,7 @@ public:
}
bool is_string(expr const* n, zstring& s) const;
+ bool is_char(expr* n, zstring& s) const;
bool is_empty(expr const* n) const { symbol s;
return is_app_of(n, m_fid, OP_SEQ_EMPTY) || (is_string(n, s) && !s.is_numerical() && *s.bare_str() == 0);
@@ -271,8 +273,9 @@ public:
MATCH_BINARY(is_in_re);
MATCH_UNARY(is_unit);
- void get_concat(expr* e, ptr_vector& es) const;
+ void get_concat(expr* e, expr_ref_vector& es) const;
expr* get_leftmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e1; return e; }
+ expr* get_rightmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e2; return e; }
};
class re {
@@ -281,6 +284,8 @@ public:
public:
re(seq_util& u): m(u.m), m_fid(u.m_fid) {}
+ sort* mk_re(sort* seq) { parameter param(seq); return m.mk_sort(m_fid, RE_SORT, 1, ¶m); }
+
app* mk_to_re(expr* s) { return m.mk_app(m_fid, OP_SEQ_TO_RE, 1, &s); }
app* mk_in_re(expr* s, expr* r) { return m.mk_app(m_fid, OP_SEQ_IN_RE, s, r); }
app* mk_concat(expr* r1, expr* r2) { return m.mk_app(m_fid, OP_RE_CONCAT, r1, r2); }
diff --git a/src/ast/simplifier/elim_bounds.cpp b/src/ast/simplifier/elim_bounds.cpp
index 41ce18549..a4e145e0a 100644
--- a/src/ast/simplifier/elim_bounds.cpp
+++ b/src/ast/simplifier/elim_bounds.cpp
@@ -110,6 +110,7 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) {
return;
}
expr * n = q->get_expr();
+ unsigned num_vars = q->get_num_decls();
ptr_buffer atoms;
if (m_manager.is_or(n))
atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args());
@@ -138,11 +139,11 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) {
var * lower = 0;
var * upper = 0;
if (is_bound(a, lower, upper)) {
- if (lower != 0 && !m_used_vars.contains(lower->get_idx())) {
+ if (lower != 0 && !m_used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) {
ADD_CANDIDATE(lower);
m_lowers.insert(lower);
}
- if (upper != 0 && !m_used_vars.contains(upper->get_idx())) {
+ if (upper != 0 && !m_used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) {
ADD_CANDIDATE(upper);
m_uppers.insert(upper);
}
@@ -176,6 +177,7 @@ void elim_bounds::operator()(quantifier * q, expr_ref & r) {
switch (atoms.size()) {
case 0:
r = m_manager.mk_false();
+ TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";);
return;
case 1:
new_body = atoms[0];
diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp
index 58db2c3b5..87f782160 100755
--- a/src/interp/iz3interp.cpp
+++ b/src/interp/iz3interp.cpp
@@ -26,7 +26,6 @@
#pragma warning(disable:4101)
#endif
-#include
#include
#include
#include
diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp
index cc3fe70ac..ebb5e00c8 100755
--- a/src/interp/iz3translate.cpp
+++ b/src/interp/iz3translate.cpp
@@ -2023,8 +2023,8 @@ public:
break;
}
default:
- pfgoto(proof);
- assert(0 && "translate_main: unsupported proof rule");
+ // pfgoto(proof);
+ // SASSERT(0 && "translate_main: unsupported proof rule");
throw unsupported();
}
}
diff --git a/src/math/automata/automaton.cpp b/src/math/automata/automaton.cpp
new file mode 100644
index 000000000..ab908525e
--- /dev/null
+++ b/src/math/automata/automaton.cpp
@@ -0,0 +1,23 @@
+/*++
+Copyright (c) 2015 Microsoft Corporation
+
+Module Name:
+
+ automaton.cpp
+
+Abstract:
+
+ Symbolic Automaton, a la Margus Veanes Automata library.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2015-12-23.
+
+Revision History:
+
+
+--*/
+
+#include "automaton.h"
+
+template class automaton;
diff --git a/src/math/automata/automaton.h b/src/math/automata/automaton.h
new file mode 100644
index 000000000..e7d7c8bfb
--- /dev/null
+++ b/src/math/automata/automaton.h
@@ -0,0 +1,608 @@
+/*++
+Copyright (c) 2015 Microsoft Corporation
+
+Module Name:
+
+ automaton.h
+
+Abstract:
+
+ Symbolic Automaton, a la Margus Veanes Automata library.
+
+Author:
+
+ Nikolaj Bjorner (nbjorner) 2015-12-23.
+
+Revision History:
+
+
+--*/
+
+#ifndef AUTOMATON_H_
+#define AUTOMATON_H_
+
+
+#include "util.h"
+#include "vector.h"
+#include "uint_set.h"
+
+template
+class default_value_manager {
+public:
+ void inc_ref(T* t) {}
+ void dec_ref(T* t) {}
+};
+
+template >
+class automaton {
+public:
+ class move {
+ M& m;
+ T* m_t;
+ unsigned m_src;
+ unsigned m_dst;
+ public:
+ move(M& m, unsigned s, unsigned d, T* t = 0): m(m), m_t(t), m_src(s), m_dst(d) {
+ if (t) m.inc_ref(t);
+ }
+ ~move() {
+ if (m_t) m.dec_ref(m_t);
+ }
+
+ move(move const& other): m(other.m), m_t(other.m_t), m_src(other.m_src), m_dst(other.m_dst) {
+ if (m_t) m.inc_ref(m_t);
+ }
+
+ move& operator=(move const& other) {
+ SASSERT(&m == &other.m);
+ T* t = other.m_t;
+ if (t) m.inc_ref(t);
+ if (m_t) m.dec_ref(m_t);
+ m_t = t;
+ m_src = other.m_src;
+ m_dst = other.m_dst;
+ return *this;
+ }
+
+ unsigned dst() const { return m_dst; }
+ unsigned src() const { return m_src; }
+ T* t() const { return m_t; }
+
+ bool is_epsilon() const { return m_t == 0; }
+ };
+ typedef vector moves;
+private:
+ M& m;
+ vector m_delta;
+ vector m_delta_inv;
+ unsigned m_init;
+ uint_set m_final_set;
+ unsigned_vector m_final_states;
+
+
+ // local data-structures
+ mutable uint_set m_visited;
+ mutable unsigned_vector m_todo;
+
+ struct default_display {
+ std::ostream& display(std::ostream& out, T* t) {
+ return out << t;
+ }
+ };
+
+public:
+
+ // The empty automaton:
+ automaton(M& m):
+ m(m),
+ m_init(0)
+ {
+ m_delta.push_back(moves());
+ m_delta_inv.push_back(moves());
+ }
+
+
+ // create an automaton from initial state, final states, and moves
+ automaton(M& m, unsigned init, unsigned_vector const& final, moves const& mvs): m(m) {
+ m_init = init;
+ for (unsigned i = 0; i < final.size(); ++i) {
+ add_to_final_states(final[i]);
+ }
+ for (unsigned i = 0; i < mvs.size(); ++i) {
+ move const& mv = mvs[i];
+ unsigned n = std::max(mv.src(), mv.dst());
+ if (n >= m_delta.size()) {
+ m_delta.resize(n+1, moves());
+ m_delta_inv.resize(n+1, moves());
+ }
+ add(mv);
+ }
+ }
+
+ // create an automaton that accepts a sequence.
+ automaton(M& m, ptr_vector const& seq):
+ m(m),
+ m_init(0) {
+ m_delta.resize(seq.size()+1, moves());
+ m_delta_inv.resize(seq.size()+1, moves());
+ for (unsigned i = 0; i < seq.size(); ++i) {
+ m_delta[i].push_back(move(m, i, i + 1, seq[i]));
+ m_delta[i + 1].push_back(move(m, i, i + 1, seq[i]));
+ }
+ add_to_final_states(seq.size());
+ }
+
+ // The automaton that accepts t
+ automaton(M& m, T* t):
+ m(m),
+ m_init(0) {
+ m_delta.resize(2, moves());
+ m_delta_inv.resize(2, moves());
+ add_to_final_states(1);
+ add(move(m, 0, 1, t));
+ }
+
+ automaton(automaton const& other):
+ m(other.m),
+ m_delta(other.m_delta),
+ m_delta_inv(other.m_delta_inv),
+ m_init(other.m_init),
+ m_final_set(other.m_final_set),
+ m_final_states(other.m_final_states)
+ {}
+
+ // create the automaton that accepts the empty string only.
+ static automaton* mk_epsilon(M& m) {
+ moves mvs;
+ unsigned_vector final;
+ final.push_back(0);
+ return alloc(automaton, m, 0, final, mvs);
+ }
+
+ // create the automaton with a single state on condition t.
+ static automaton* mk_loop(M& m, T* t) {
+ moves mvs;
+ unsigned_vector final;
+ final.push_back(0);
+ mvs.push_back(move(m, 0, 0, t));
+ return alloc(automaton, m, 0, final, mvs);
+ }
+
+ // create the sum of disjoint automata
+ static automaton* mk_union(automaton const& a, automaton const& b) {
+ SASSERT(&a.m == &b.m);
+ M& m = a.m;
+ moves mvs;
+ unsigned_vector final;
+ unsigned offset1 = 1;
+ unsigned offset2 = a.num_states() + 1;
+ mvs.push_back(move(m, 0, a.init() + offset1));
+ mvs.push_back(move(m, 0, b.init() + offset2));
+ append_moves(offset1, a, mvs);
+ append_moves(offset2, b, mvs);
+ append_final(offset1, a, final);
+ append_final(offset2, b, final);
+ return alloc(automaton, m, 0, final, mvs);
+ }
+
+ static automaton* mk_opt(automaton const& a) {
+ M& m = a.m;
+ moves mvs;
+ unsigned_vector final;
+ unsigned offset = 0;
+ unsigned init = a.init();
+ if (!a.initial_state_is_source()) {
+ offset = 1;
+ init = 0;
+ mvs.push_back(move(m, 0, a.init() + offset));
+ }
+ mvs.push_back(move(m, init, a.final_state() + offset));
+ append_moves(offset, a, mvs);
+ append_final(offset, a, final);
+ return alloc(automaton, m, init, final, mvs);
+ }
+
+ // concatenate accepting languages
+ static automaton* mk_concat(automaton const& a, automaton const& b) {
+ SASSERT(&a.m == &b.m);
+ M& m = a.m;
+ moves mvs;
+ unsigned_vector final;
+ unsigned init = 0;
+ unsigned offset1 = 1;
+ unsigned offset2 = a.num_states() + offset1;
+ mvs.push_back(move(m, 0, a.init() + offset1));
+ append_moves(offset1, a, mvs);
+ for (unsigned i = 0; i < a.m_final_states.size(); ++i) {
+ mvs.push_back(move(m, a.m_final_states[i] + offset1, b.init() + offset2));
+ }
+ append_moves(offset2, b, mvs);
+ append_final(offset2, b, final);
+
+ return alloc(automaton, m, init, final, mvs);
+ }
+
+ static automaton* mk_reverse(automaton const& a) {
+ M& m = a.m;
+ if (a.is_empty()) {
+ return alloc(automaton, m);
+ }
+ moves mvs;
+ for (unsigned i = 0; i < a.m_delta.size(); ++i) {
+ moves const& mvs1 = a.m_delta[i];
+ for (unsigned j = 0; j < mvs1.size(); ++j) {
+ move const& mv = mvs1[j];
+ mvs.push_back(move(m, mv.dst(), mv.src(), mv.t()));
+ }
+ }
+ unsigned_vector final;
+ unsigned init;
+ final.push_back(a.init());
+ if (a.m_final_states.size() == 1) {
+ init = a.m_final_states[0];
+ }
+ else {
+ init = a.num_states();
+ for (unsigned i = 0; i < a.m_final_states.size(); ++i) {
+ mvs.push_back(move(m, init, a.m_final_states[i]));
+ }
+ }
+ return alloc(automaton, m, init, final, mvs);
+ }
+
+ void add_to_final_states(unsigned s) {
+ if (!is_final_state(s)) {
+ m_final_set.insert(s);
+ m_final_states.push_back(s);
+ }
+ }
+
+ void remove_from_final_states(unsigned s) {
+ if (is_final_state(s)) {
+ m_final_set.remove(s);
+ m_final_states.erase(s);
+ }
+ }
+
+ void add_init_to_final_states() {
+ add_to_final_states(init());
+ }
+
+ void add_final_to_init_moves() {
+ for (unsigned i = 0; i < m_final_states.size(); ++i) {
+ unsigned state = m_final_states[i];
+ bool found = false;
+ moves const& mvs = m_delta[state];
+ for (unsigned j = 0; found && j < mvs.size(); ++j) {
+ found = (mvs[j].dst() == m_init) && mvs[j].is_epsilon();
+ }
+ if (!found && state != m_init) {
+ add(move(m, state, m_init));
+ }
+ }
+ }
+
+ // remove epsilon transitions
+ // src - e -> dst
+ // in_degree(src) = 1, final(src) => final(dst), src0 != src
+ // src0 - t -> src - e -> dst => src0 - t -> dst
+ // out_degree(dst) = 1, final(dst) => final(src), dst != dst1
+ // src - e -> dst - t -> dst1 => src - t -> dst1
+
+ // Generalized:
+ // Src - E -> dst - t -> dst1 => Src - t -> dst1 if dst is final => each Src is final
+ //
+ // src - e -> dst - ET -> Dst1 => src - ET -> Dst1 if in_degree(dst) = 1, src != dst
+ // Src - E -> dst - et -> dst1 => Src - et -> dst1 if out_degree(dst) = 1, src != dst
+ //
+ void compress() {
+ for (unsigned i = 0; i < m_delta.size(); ++i) {
+ for (unsigned j = 0; j < m_delta[i].size(); ++j) {
+ move const& mv = m_delta[i][j];
+ unsigned src = mv.src();
+ unsigned dst = mv.dst();
+ SASSERT(src == i);
+ if (mv.is_epsilon()) {
+ if (src == dst) {
+ // just remove this edge.
+ }
+ else if (1 == in_degree(src) && 1 == out_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) {
+ move const& mv0 = m_delta_inv[src][0];
+ unsigned src0 = mv0.src();
+ T* t = mv0.t();
+ SASSERT(mv0.dst() == src);
+ if (src0 == src) {
+ continue;
+ }
+ add(move(m, src0, dst, t));
+ remove(src0, src, t);
+
+ }
+ else if (1 == out_degree(dst) && 1 == in_degree(dst) && init() != dst && (!is_final_state(dst) || is_final_state(src))) {
+ move const& mv1 = m_delta[dst][0];
+ unsigned dst1 = mv1.dst();
+ T* t = mv1.t();
+ SASSERT(mv1.src() == dst);
+ if (dst1 == dst) {
+ continue;
+ }
+ add(move(m, src, dst1, t));
+ remove(dst, dst1, t);
+ }
+ else if (1 == in_degree(dst) && (!is_final_state(dst) || is_final_state(src)) && init() != dst) {
+ moves const& mvs = m_delta[dst];
+ moves mvs1;
+ for (unsigned k = 0; k < mvs.size(); ++k) {
+ mvs1.push_back(move(m, src, mvs[k].dst(), mvs[k].t()));
+ }
+ for (unsigned k = 0; k < mvs1.size(); ++k) {
+ remove(dst, mvs1[k].dst(), mvs1[k].t());
+ add(mvs1[k]);
+ }
+ }
+ //
+ // Src - E -> dst - et -> dst1 => Src - et -> dst1 if out_degree(dst) = 1, src != dst
+ //
+ else if (1 == out_degree(dst) && all_epsilon_in(dst) && init() != dst && !is_final_state(dst)) {
+ move const& mv = m_delta[dst][0];
+ unsigned dst1 = mv.dst();
+ T* t = mv.t();
+ unsigned_vector src0s;
+ moves const& mvs = m_delta_inv[dst];
+ moves mvs1;
+ for (unsigned k = 0; k < mvs.size(); ++k) {
+ SASSERT(mvs[k].is_epsilon());
+ mvs1.push_back(move(m, mvs[k].src(), dst1, t));
+ }
+ for (unsigned k = 0; k < mvs1.size(); ++k) {
+ remove(mvs1[k].src(), dst, 0);
+ add(mvs1[k]);
+ }
+ remove(dst, dst1, t);
+ --j;
+ continue;
+ }
+ //
+ // Src1 - ET -> src - e -> dst => Src1 - ET -> dst if out_degree(src) = 1, src != init()
+ //
+ else if (1 == out_degree(src) && init() != src && (!is_final_state(src) || is_final_state(dst))) {
+ moves const& mvs = m_delta_inv[src];
+ moves mvs1;
+ for (unsigned k = 0; k < mvs.size(); ++k) {
+ mvs1.push_back(move(m, mvs[k].src(), dst, mvs[k].t()));
+ }
+ for (unsigned k = 0; k < mvs1.size(); ++k) {
+ remove(mvs1[k].src(), src, mvs1[k].t());
+ add(mvs1[k]);
+ }
+ }
+ else {
+ continue;
+ }
+ remove(src, dst, 0);
+ --j;
+ }
+ }
+ }
+ while (true) {
+ SASSERT(!m_delta.empty());
+ unsigned src = m_delta.size() - 1;
+ if (in_degree(src) == 0 && init() != src) {
+ remove_from_final_states(src);
+ m_delta.pop_back();
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ bool is_sequence(unsigned& length) const {
+ if (is_final_state(m_init) && (out_degree(m_init) == 0 || (out_degree(m_init) == 1 && is_loop_state(m_init)))) {
+ length = 0;
+ return true;
+ }
+ if (is_empty() || in_degree(m_init) != 0 || out_degree(m_init) != 1) {
+ return false;
+ }
+
+ length = 1;
+ unsigned s = get_move_from(m_init).dst();
+ while (!is_final_state(s)) {
+ if (out_degree(s) != 1 || in_degree(s) != 1) {
+ return false;
+ }
+ s = get_move_from(s).dst();
+ ++length;
+ }
+ return out_degree(s) == 0 || (out_degree(s) == 1 && is_loop_state(s));
+ }
+
+ unsigned init() const { return m_init; }
+ unsigned in_degree(unsigned state) const { return m_delta_inv[state].size(); }
+ unsigned out_degree(unsigned state) const { return m_delta[state].size(); }
+ move const& get_move_from(unsigned state) const { SASSERT(m_delta[state].size() == 1); return m_delta[state][0]; }
+ move const& get_move_to(unsigned state) const { SASSERT(m_delta_inv[state].size() == 1); return m_delta_inv[state][0]; }
+ moves const& get_moves_from(unsigned state) const { return m_delta[state]; }
+ moves const& get_moves_to(unsigned state) const { return m_delta_inv[state]; }
+ bool initial_state_is_source() const { return m_delta_inv[m_init].empty(); }
+ bool is_final_state(unsigned s) const { return m_final_set.contains(s); }
+ bool is_epsilon_free() const {
+ for (unsigned i = 0; i < m_delta.size(); ++i) {
+ moves const& mvs = m_delta[i];
+ for (unsigned j = 0; j < mvs.size(); ++j) {
+ if (!mvs[j].t()) return false;
+ }
+ }
+ return true;
+ }
+
+ bool all_epsilon_in(unsigned s) {
+ moves const& mvs = m_delta_inv[s];
+ for (unsigned j = 0; j < mvs.size(); ++j) {
+ if (mvs[j].t()) return false;
+ }
+ return true;
+ }
+
+ bool is_empty() const { return m_final_states.empty(); }
+ unsigned final_state() const { return m_final_states[0]; }
+ bool has_single_final_sink() const { return m_final_states.size() == 1 && m_delta[final_state()].empty(); }
+ unsigned num_states() const { return m_delta.size(); }
+ bool is_loop_state(unsigned s) const {
+ moves mvs;
+ get_moves_from(s, mvs);
+ for (unsigned i = 0; i < mvs.size(); ++i) {
+ if (s == mvs[i].dst()) return true;
+ }
+ return false;
+ }
+
+ unsigned move_count() const {
+ unsigned result = 0;
+ for (unsigned i = 0; i < m_delta.size(); result += m_delta[i].size(), ++i) {}
+ return result;
+ }
+ void get_epsilon_closure(unsigned state, unsigned_vector& states) {
+ get_epsilon_closure(state, m_delta, states);
+ }
+ void get_inv_epsilon_closure(unsigned state, unsigned_vector& states) {
+ get_epsilon_closure(state, m_delta_inv, states);
+ }
+ void get_moves_from(unsigned state, moves& mvs, bool epsilon_closure = true) const {
+ get_moves(state, m_delta, mvs, epsilon_closure);
+ }
+ void get_moves_to(unsigned state, moves& mvs, bool epsilon_closure = true) {
+ get_moves(state, m_delta_inv, mvs, epsilon_closure);
+ }
+
+ template
+ std::ostream& display(std::ostream& out, D& displayer = D()) const {
+ out << "init: " << init() << "\n";
+ out << "final: ";
+ for (unsigned i = 0; i < m_final_states.size(); ++i) out << m_final_states[i] << " ";
+ out << "\n";
+ for (unsigned i = 0; i < m_delta.size(); ++i) {
+ moves const& mvs = m_delta[i];
+ for (unsigned j = 0; j < mvs.size(); ++j) {
+ move const& mv = mvs[j];
+ out << i << " -> " << mv.dst() << " ";
+ if (mv.t()) {
+ out << "if ";
+ displayer.display(out, mv.t());
+ }
+ out << "\n";
+ }
+ }
+ return out;
+ }
+private:
+
+ void remove_dead_states() {
+ unsigned_vector remap;
+ for (unsigned i = 0; i < m_delta.size(); ++i) {
+
+ }
+ }
+
+
+ void add(move const& mv) {
+ m_delta[mv.src()].push_back(mv);
+ m_delta_inv[mv.dst()].push_back(mv);
+ }
+
+
+ unsigned find_move(unsigned src, unsigned dst, T* t, moves const& mvs) {
+ for (unsigned i = 0; i < mvs.size(); ++i) {
+ move const& mv = mvs[i];
+ if (mv.src() == src && mv.dst() == dst && t == mv.t()) {
+ return i;
+ }
+ }
+ UNREACHABLE();
+ return UINT_MAX;
+ }
+
+ void remove(unsigned src, unsigned dst, T* t, moves& mvs) {
+ remove(find_move(src, dst, t, mvs), mvs);
+ }
+
+ void remove(unsigned src, unsigned dst, T* t) {
+ remove(src, dst, t, m_delta[src]);
+ remove(src, dst, t, m_delta_inv[dst]);
+ }
+
+ void remove(unsigned index, moves& mvs) {
+ mvs[index] = mvs.back();
+ mvs.pop_back();
+ }
+
+ mutable unsigned_vector m_states1, m_states2;
+
+ void get_moves(unsigned state, vector const& delta, moves& mvs, bool epsilon_closure) const {
+ m_states1.reset();
+ m_states2.reset();
+ get_epsilon_closure(state, delta, m_states1);
+ for (unsigned i = 0; i < m_states1.size(); ++i) {
+ state = m_states1[i];
+ moves const& mv1 = delta[state];
+ for (unsigned j = 0; j < mv1.size(); ++j) {
+ move const& mv = mv1[j];
+ if (!mv.is_epsilon()) {
+ if (epsilon_closure) {
+ m_states2.reset();
+ get_epsilon_closure(mv.dst(), delta, m_states2);
+ for (unsigned k = 0; k < m_states2.size(); ++k) {
+ mvs.push_back(move(m, state, m_states2[k], mv.t()));
+ }
+ }
+ else {
+ mvs.push_back(move(m, state, mv.dst(), mv.t()));
+ }
+ }
+ }
+ }
+ }
+
+ void get_epsilon_closure(unsigned state, vector const& delta, unsigned_vector& states) const {
+ m_todo.push_back(state);
+ m_visited.insert(state);
+ while (!m_todo.empty()) {
+ state = m_todo.back();
+ states.push_back(state);
+ m_todo.pop_back();
+ moves const& mvs = delta[state];
+ for (unsigned i = 0; i < mvs.size(); ++i) {
+ unsigned tgt = mvs[i].dst();
+ if (mvs[i].is_epsilon() && !m_visited.contains(tgt)) {
+ m_visited.insert(tgt);
+ m_todo.push_back(tgt);
+ }
+ }
+ }
+ m_visited.reset();
+ SASSERT(m_todo.empty());
+ }
+
+ static void append_moves(unsigned offset, automaton const& a, moves& mvs) {
+ for (unsigned i = 0; i < a.num_states(); ++i) {
+ moves const& mvs1 = a.m_delta[i];
+ for (unsigned j = 0; j < mvs1.size(); ++j) {
+ move const& mv = mvs1[j];
+ mvs.push_back(move(a.m, mv.src() + offset, mv.dst() + offset, mv.t()));
+ }
+ }
+ }
+
+ static void append_final(unsigned offset, automaton const& a, unsigned_vector& final) {
+ for (unsigned i = 0; i < a.m_final_states.size(); ++i) {
+ final.push_back(a.m_final_states[i]+offset);
+ }
+ }
+
+};
+
+typedef automaton uautomaton;
+
+
+#endif
diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp
index ded7c14c2..b3648f38d 100644
--- a/src/muz/pdr/pdr_context.cpp
+++ b/src/muz/pdr/pdr_context.cpp
@@ -1158,7 +1158,6 @@ namespace pdr {
while (!todo.empty()) {
model_node* n = todo.back();
model* md = 0;
- ast_manager& m = n->pt().get_manager();
if (!n->get_model_ptr()) {
if (models.find(n->state(), md)) {
TRACE("pdr", tout << n->state() << "\n";);
diff --git a/src/muz/rel/dl_mk_simple_joins.cpp b/src/muz/rel/dl_mk_simple_joins.cpp
index e76b3a25b..b9febe53e 100644
--- a/src/muz/rel/dl_mk_simple_joins.cpp
+++ b/src/muz/rel/dl_mk_simple_joins.cpp
@@ -11,7 +11,7 @@ Abstract:
Author:
- Leonardo de Moura (leonardo) 2010-05-20.
+ Krystof Hoder 2010-05-20.
Revision History:
@@ -301,13 +301,10 @@ namespace datalog {
}
- pair_info & get_pair(app_pair key) const {
- return *m_costs.find(key);
- }
-
void remove_rule_from_pair(app_pair key, rule * r, unsigned original_len) {
- pair_info * ptr = &get_pair(key);
- if (ptr->remove_rule(r, original_len)) {
+ pair_info * ptr = 0;
+ if (m_costs.find(key, ptr) && ptr &&
+ ptr->remove_rule(r, original_len)) {
SASSERT(ptr->m_rules.empty());
m_costs.remove(key);
dealloc(ptr);
@@ -362,7 +359,12 @@ namespace datalog {
void join_pair(app_pair pair_key) {
app * t1 = pair_key.first;
app * t2 = pair_key.second;
- pair_info & inf = get_pair(pair_key);
+ pair_info* infp = 0;
+ if (!m_costs.find(pair_key, infp) || !infp) {
+ UNREACHABLE();
+ return;
+ }
+ pair_info & inf = *infp;
SASSERT(!inf.m_rules.empty());
var_idx_set & output_vars = inf.m_all_nonlocal_vars;
expr_ref_vector args(m);
diff --git a/src/parsers/smt2/smt2scanner.cpp b/src/parsers/smt2/smt2scanner.cpp
index ed16003c2..3664ed903 100644
--- a/src/parsers/smt2/smt2scanner.cpp
+++ b/src/parsers/smt2/smt2scanner.cpp
@@ -169,24 +169,16 @@ namespace smt2 {
char c = curr();
if (c == EOF)
throw scanner_exception("unexpected end of string", m_line, m_spos);
- if (c == '\"') {
+ if (c == '\n') {
+ new_line();
+ }
+ else if (c == '\"') {
next();
if (curr() != '\"') {
m_string.push_back(0);
return STRING_TOKEN;
}
}
- else if (c == '\n') {
- new_line();
- }
- else if (c == '\\') {
- next();
- c = curr();
- if (c == EOF)
- throw scanner_exception("unexpected end of string", m_line, m_spos);
- if (c != '\\' && c != '\"')
- throw scanner_exception("invalid escape sequence", m_line, m_spos);
- }
m_string.push_back(c);
next();
}
diff --git a/src/sat/sat_asymm_branch.cpp b/src/sat/sat_asymm_branch.cpp
index 193bf59f2..8a761ea3a 100644
--- a/src/sat/sat_asymm_branch.cpp
+++ b/src/sat/sat_asymm_branch.cpp
@@ -78,8 +78,12 @@ namespace sat {
clause_vector::iterator end = s.m_clauses.end();
try {
for (; it != end; ++it) {
- if (s.inconsistent())
+ if (s.inconsistent()) {
+ for (; it != end; ++it, ++it2) {
+ *it2 = *it;
+ }
break;
+ }
SASSERT(s.m_qhead == s.m_trail.size());
if (m_counter < limit || s.inconsistent()) {
*it2 = *it;
diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp
index 6314d6fad..fe4822406 100644
--- a/src/sat/sat_clause.cpp
+++ b/src/sat/sat_clause.cpp
@@ -169,6 +169,7 @@ namespace sat {
#endif
void * mem = m_allocator.allocate(size);
clause * cls = new (mem) clause(m_id_gen.mk(), num_lits, lits, learned);
+ TRACE("sat", tout << "alloc: " << cls->id() << " " << cls << " " << *cls << " " << (learned?"l":"a") << "\n";);
SASSERT(!learned || cls->is_learned());
return cls;
}
diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp
index 834fe4429..6c4c01ab0 100644
--- a/src/shell/smtlib_frontend.cpp
+++ b/src/shell/smtlib_frontend.cpp
@@ -33,7 +33,6 @@ Revision History:
#include"smt_solver.h"
extern bool g_display_statistics;
-extern void display_config();
static clock_t g_start_time;
static smtlib::solver* g_solver = 0;
static cmd_context * g_cmd_context = 0;
diff --git a/src/smt/mam.cpp b/src/smt/mam.cpp
index d22ca88db..764176ea0 100644
--- a/src/smt/mam.cpp
+++ b/src/smt/mam.cpp
@@ -3936,7 +3936,7 @@ namespace smt {
}
virtual bool is_shared(enode * n) const {
- return m_shared_enodes.contains(n);
+ return !m_shared_enodes.empty() && m_shared_enodes.contains(n);
}
// This method is invoked when n becomes relevant.
diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp
index 26ca2e68a..04b7ce234 100644
--- a/src/smt/smt_context.cpp
+++ b/src/smt/smt_context.cpp
@@ -1382,7 +1382,8 @@ namespace smt {
bool_var v = l.var();
bool_var_data & d = get_bdata(v);
lbool val = get_assignment(v);
- TRACE("propagate_atoms", tout << "propagating atom, #" << bool_var2expr(v)->get_id() << ", is_enode(): " << d.is_enode() << " " << l << "\n";);
+ TRACE("propagate_atoms", tout << "propagating atom, #" << bool_var2expr(v)->get_id() << ", is_enode(): " << d.is_enode()
+ << " tag: " << (d.is_eq()?"eq":"") << (d.is_theory_atom()?"th":"") << (d.is_quantifier()?"q":"") << " " << l << "\n";);
SASSERT(val != l_undef);
if (d.is_enode())
propagate_bool_var_enode(v);
@@ -4024,8 +4025,9 @@ namespace smt {
return false;
}
case 1: {
- if (m_qmanager->is_shared(n))
+ if (m_qmanager->is_shared(n)) {
return true;
+ }
// the variabe is shared if the equivalence class of n
// contains a parent application.
diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h
index 7c3224882..69a882c99 100644
--- a/src/smt/smt_enode.h
+++ b/src/smt/smt_enode.h
@@ -113,6 +113,7 @@ namespace smt {
friend class context;
friend class euf_manager;
friend class conflict_resolution;
+
theory_var_list * get_th_var_list() {
return m_th_var_list.get_th_var() == null_theory_var ? 0 : &m_th_var_list;
@@ -170,6 +171,7 @@ namespace smt {
m_interpreted = true;
}
+
void del_eh(ast_manager & m, bool update_children_parent = true);
app * get_owner() const {
@@ -192,6 +194,7 @@ namespace smt {
return m_owner->hash();
}
+
enode * get_root() const {
return m_root;
}
diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp
index 98d982b7a..88e9761b4 100644
--- a/src/smt/smt_model_generator.cpp
+++ b/src/smt/smt_model_generator.cpp
@@ -90,7 +90,9 @@ namespace smt {
sort * s = m_manager.get_sort(r->get_owner());
model_value_proc * proc = 0;
if (m_manager.is_bool(s)) {
- SASSERT(m_context->get_assignment(r) == l_true || m_context->get_assignment(r) == l_false);
+ CTRACE("func_interp_bug", m_context->get_assignment(r) == l_undef,
+ tout << mk_pp(r->get_owner(), m_manager) << "\n";);
+ SASSERT(m_context->get_assignment(r) != l_undef);
if (m_context->get_assignment(r) == l_true)
proc = alloc(expr_wrapper_proc, m_manager.mk_true());
else
@@ -359,6 +361,7 @@ namespace smt {
}
else {
enode * child = d.get_enode();
+ TRACE("mg_top_sort", tout << "#" << n->get_owner_id() << " (" << mk_pp(n->get_owner(), m_manager) << "): " << mk_pp(child->get_owner(), m_manager) << " " << mk_pp(child->get_root()->get_owner(), m_manager) << "\n";);
child = child->get_root();
app * val = 0;
m_root2value.find(child, val);
diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp
index 69bf0b72f..e06480bc5 100644
--- a/src/smt/smt_quantifier.cpp
+++ b/src/smt/smt_quantifier.cpp
@@ -396,12 +396,14 @@ namespace smt {
scoped_ptr m_model_checker;
unsigned m_new_enode_qhead;
unsigned m_lazy_matching_idx;
+ bool m_active;
public:
default_qm_plugin():
m_qm(0),
m_context(0),
m_new_enode_qhead(0),
- m_lazy_matching_idx(0) {
+ m_lazy_matching_idx(0),
+ m_active(false) {
}
virtual ~default_qm_plugin() {
@@ -427,7 +429,7 @@ namespace smt {
virtual bool model_based() const { return m_fparams->m_mbqi; }
- virtual bool mbqi_enabled(quantifier *q) const {
+ virtual bool mbqi_enabled(quantifier *q) const {
if(!m_fparams->m_mbqi_id) return true;
const symbol &s = q->get_qid();
size_t len = strlen(m_fparams->m_mbqi_id);
@@ -443,6 +445,7 @@ namespace smt {
*/
virtual void add(quantifier * q) {
if (m_fparams->m_mbqi && mbqi_enabled(q)) {
+ m_active = true;
m_model_finder->register_quantifier(q);
}
}
@@ -475,6 +478,7 @@ namespace smt {
}
virtual void assign_eh(quantifier * q) {
+ m_active = true;
if (m_fparams->m_ematching) {
bool has_unary_pattern = false;
unsigned num_patterns = q->get_num_patterns();
@@ -537,7 +541,7 @@ namespace smt {
}
virtual bool is_shared(enode * n) const {
- return (m_mam->is_shared(n) || m_lazy_mam->is_shared(n));
+ return m_active && (m_mam->is_shared(n) || m_lazy_mam->is_shared(n));
}
virtual void adjust_model(proto_model * m) {
diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp
index 8ebfa2d71..8a40f9d7a 100644
--- a/src/smt/smt_setup.cpp
+++ b/src/smt/smt_setup.cpp
@@ -815,7 +815,7 @@ namespace smt {
}
void setup::setup_seq() {
- m_context.register_plugin(alloc(theory_seq_empty, m_manager));
+ m_context.register_plugin(alloc(theory_seq, m_manager));
}
void setup::setup_card() {
diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h
index 1e0c7c5f4..7b56f19e5 100644
--- a/src/smt/theory_arith.h
+++ b/src/smt/theory_arith.h
@@ -429,6 +429,7 @@ namespace smt {
arith_util m_util;
arith_eq_solver m_arith_eq_solver;
bool m_found_unsupported_op;
+ bool m_found_underspecified_op;
arith_eq_adapter m_arith_eq_adapter;
vector m_rows;
svector m_dead_rows;
@@ -510,6 +511,7 @@ namespace smt {
virtual theory_var mk_var(enode * n);
void found_unsupported_op(app * n);
+ void found_underspecified_op(app * n);
bool has_var(expr * v) const { return get_context().e_internalized(v) && get_context().get_enode(v)->get_th_var(get_id()) != null_theory_var; }
theory_var expr2var(expr * v) const { SASSERT(get_context().e_internalized(v)); return get_context().get_enode(v)->get_th_var(get_id()); }
@@ -1056,6 +1058,10 @@ namespace smt {
// -----------------------------------
virtual bool get_value(enode * n, expr_ref & r);
+ bool get_lower(enode* n, expr_ref& r);
+ bool get_upper(enode* n, expr_ref& r);
+ bool to_expr(inf_numeral const& val, bool is_int, expr_ref& r);
+
// -----------------------------------
//
@@ -1071,6 +1077,8 @@ namespace smt {
unsigned num_eqs, enode_pair const * eqs,
unsigned num_params, parameter* params);
inf_eps_rational conflict_minimize();
+
+
private:
virtual expr_ref mk_gt(theory_var v);
diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h
index e2a2d48a6..4291590c6 100644
--- a/src/smt/theory_arith_aux.h
+++ b/src/smt/theory_arith_aux.h
@@ -2153,10 +2153,14 @@ namespace smt {
*/
template
bool theory_arith::is_shared(theory_var v) const {
+ if (!m_found_underspecified_op) {
+ return false;
+ }
enode * n = get_enode(v);
enode * r = n->get_root();
enode_vector::const_iterator it = r->begin_parents();
enode_vector::const_iterator end = r->end_parents();
+ TRACE("shared", tout << get_context().get_scope_level() << " " << v << " " << r->get_num_parents() << "\n";);
for (; it != end; ++it) {
enode * parent = *it;
app * o = parent->get_owner();
diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h
index 96fe2d1f8..4561e1ced 100644
--- a/src/smt/theory_arith_core.h
+++ b/src/smt/theory_arith_core.h
@@ -37,6 +37,15 @@ namespace smt {
}
}
+ template
+ void theory_arith::found_underspecified_op(app * n) {
+ if (!m_found_underspecified_op) {
+ TRACE("arith", tout << "found non underspecificed expression:\n" << mk_pp(n, get_manager()) << "\n";);
+ get_context().push_trail(value_trail(m_found_underspecified_op));
+ m_found_underspecified_op = true;
+ }
+ }
+
template
bool theory_arith::process_atoms() const {
if (!adaptive())
@@ -308,6 +317,7 @@ namespace smt {
template
theory_var theory_arith::internalize_div(app * n) {
+ found_underspecified_op(n);
theory_var s = mk_binary_op(n);
context & ctx = get_context();
if (!ctx.relevancy())
@@ -317,6 +327,7 @@ namespace smt {
template
theory_var theory_arith::internalize_idiv(app * n) {
+ found_underspecified_op(n);
theory_var s = mk_binary_op(n);
context & ctx = get_context();
app * mod = m_util.mk_mod(n->get_arg(0), n->get_arg(1));
@@ -329,6 +340,7 @@ namespace smt {
template
theory_var theory_arith::internalize_mod(app * n) {
TRACE("arith_mod", tout << "internalizing...\n" << mk_pp(n, get_manager()) << "\n";);
+ found_underspecified_op(n);
theory_var s = mk_binary_op(n);
context & ctx = get_context();
if (!ctx.relevancy())
@@ -338,6 +350,7 @@ namespace smt {
template
theory_var theory_arith::internalize_rem(app * n) {
+ found_underspecified_op(n);
theory_var s = mk_binary_op(n);
context & ctx = get_context();
if (!ctx.relevancy()) {
@@ -1514,6 +1527,7 @@ namespace smt {
m_util(m),
m_arith_eq_solver(m),
m_found_unsupported_op(false),
+ m_found_underspecified_op(false),
m_arith_eq_adapter(*this, params, m_util),
m_asserted_qhead(0),
m_to_patch(1024),
@@ -3089,20 +3103,35 @@ namespace smt {
// -----------------------------------
template
- bool theory_arith::get_value(enode * n, expr_ref & r) {
- theory_var v = n->get_th_var(get_id());
- if (v == null_theory_var) {
- // TODO: generate fresh value different from other get_value(v) for all v.
- return false;
+ bool theory_arith::to_expr(inf_numeral const& val, bool is_int, expr_ref & r) {
+ if (val.get_infinitesimal().is_zero()) {
+ numeral _val = val.get_rational();
+ r = m_util.mk_numeral(_val.to_rational(), is_int);
+ return true;
}
- inf_numeral const & val = get_value(v);
- if (!val.get_infinitesimal().is_zero()) {
- // TODO: add support for infinitesimals
+ else {
return false;
}
- numeral _val = val.get_rational();
- r = m_util.mk_numeral(_val.to_rational(), is_int(v));
- return true;
+ }
+
+ template
+ bool theory_arith::get_value(enode * n, expr_ref & r) {
+ theory_var v = n->get_th_var(get_id());
+ return v != null_theory_var && to_expr(get_value(v), is_int(v), r);
+ }
+
+ template
+ bool theory_arith::get_lower(enode * n, expr_ref & r) {
+ theory_var v = n->get_th_var(get_id());
+ bound* b = (v == null_theory_var) ? 0 : lower(v);
+ return b && to_expr(b->get_value(), is_int(v), r);
+ }
+
+ template
+ bool theory_arith::get_upper(enode * n, expr_ref & r) {
+ theory_var v = n->get_th_var(get_id());
+ bound* b = (v == null_theory_var) ? 0 : upper(v);
+ return b && to_expr(b->get_value(), is_int(v), r);
}
// -----------------------------------
diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp
index 51b2c1b59..cef8d5fc7 100644
--- a/src/smt/theory_bv.cpp
+++ b/src/smt/theory_bv.cpp
@@ -424,6 +424,39 @@ namespace smt {
};
+ void theory_bv::add_fixed_eq(theory_var v1, theory_var v2) {
+ ++m_stats.m_num_eq_dynamic;
+ if (v1 > v2) {
+ std::swap(v1, v2);
+ }
+ unsigned sz = get_bv_size(v1);
+ ast_manager& m = get_manager();
+ context & ctx = get_context();
+ app* o1 = get_enode(v1)->get_owner();
+ app* o2 = get_enode(v2)->get_owner();
+ literal oeq = mk_eq(o1, o2, true);
+ TRACE("bv",
+ tout << mk_pp(o1, m) << " = " << mk_pp(o2, m) << " "
+ << ctx.get_scope_level() << "\n";);
+ literal_vector eqs;
+ for (unsigned i = 0; i < sz; ++i) {
+ literal l1 = m_bits[v1][i];
+ literal l2 = m_bits[v2][i];
+ expr_ref e1(m), e2(m);
+ e1 = mk_bit2bool(o1, i);
+ e2 = mk_bit2bool(o2, i);
+ literal eq = mk_eq(e1, e2, true);
+ ctx.mk_th_axiom(get_id(), l1, ~l2, ~eq);
+ ctx.mk_th_axiom(get_id(), ~l1, l2, ~eq);
+ ctx.mk_th_axiom(get_id(), l1, l2, eq);
+ ctx.mk_th_axiom(get_id(), ~l1, ~l2, eq);
+ ctx.mk_th_axiom(get_id(), eq, ~oeq);
+ eqs.push_back(~eq);
+ }
+ eqs.push_back(oeq);
+ ctx.mk_th_axiom(get_id(), eqs.size(), eqs.c_ptr());
+ }
+
void theory_bv::fixed_var_eh(theory_var v) {
numeral val;
bool r = get_fixed_value(v, val);
@@ -443,7 +476,9 @@ namespace smt {
display_var(tout, v);
display_var(tout, v2););
m_stats.m_num_th2core_eq++;
- ctx.assign_eq(get_enode(v), get_enode(v2), eq_justification(js));
+ add_fixed_eq(v, v2);
+ ctx.assign_eq(get_enode(v), get_enode(v2), eq_justification(js));
+ m_fixed_var_table.insert(key, v2);
}
}
else {
@@ -1177,6 +1212,7 @@ namespace smt {
}
void theory_bv::assign_bit(literal consequent, theory_var v1, theory_var v2, unsigned idx, literal antecedent, bool propagate_eqc) {
+
m_stats.m_num_bit2core++;
context & ctx = get_context();
SASSERT(ctx.get_assignment(antecedent) == l_true);
@@ -1192,6 +1228,12 @@ namespace smt {
}
else {
ctx.assign(consequent, mk_bit_eq_justification(v1, v2, consequent, antecedent));
+ literal_vector lits;
+ lits.push_back(~consequent);
+ lits.push_back(antecedent);
+ lits.push_back(~mk_eq(get_enode(v1)->get_owner(), get_enode(v2)->get_owner(), false));
+ ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
+
if (m_wpos[v2] == idx)
find_wpos(v2);
// REMARK: bit_eq_justification is marked as a theory_bv justification.
@@ -1601,6 +1643,7 @@ namespace smt {
st.update("bv dynamic diseqs", m_stats.m_num_diseq_dynamic);
st.update("bv bit2core", m_stats.m_num_bit2core);
st.update("bv->core eq", m_stats.m_num_th2core_eq);
+ st.update("bv dynamic eqs", m_stats.m_num_eq_dynamic);
}
#ifdef Z3DEBUG
diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h
index bb0dcc907..17d03b412 100644
--- a/src/smt/theory_bv.h
+++ b/src/smt/theory_bv.h
@@ -34,6 +34,7 @@ namespace smt {
struct theory_bv_stats {
unsigned m_num_diseq_static, m_num_diseq_dynamic, m_num_bit2core, m_num_th2core_eq, m_num_conflicts;
+ unsigned m_num_eq_dynamic;
void reset() { memset(this, 0, sizeof(theory_bv_stats)); }
theory_bv_stats() { reset(); }
};
@@ -124,8 +125,9 @@ namespace smt {
typedef std::pair value_sort_pair;
typedef pair_hash, unsigned_hash> value_sort_pair_hash;
typedef map > value2var;
- value2var m_fixed_var_table;
+ value2var m_fixed_var_table;
+
literal_vector m_tmp_literals;
svector m_prop_queue;
bool m_approximates_large_bvs;
@@ -166,6 +168,7 @@ namespace smt {
void find_wpos(theory_var v);
friend class fixed_eq_justification;
void fixed_var_eh(theory_var v);
+ void add_fixed_eq(theory_var v1, theory_var v2);
bool get_fixed_value(theory_var v, numeral & result) const;
void internalize_num(app * n);
void internalize_add(app * n);
diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp
index 3e43cc4ce..a06ee723c 100644
--- a/src/smt/theory_fpa.cpp
+++ b/src/smt/theory_fpa.cpp
@@ -235,7 +235,7 @@ namespace smt {
SASSERT(mpzm.is_int64(exp_u));
scoped_mpf f(mpfm);
- mpfm.set(f, m_ebits, m_sbits, mpzm.is_one(sgn_z), sig_z, mpzm.get_int64(exp_u));
+ mpfm.set(f, m_ebits, m_sbits, mpzm.is_one(sgn_z), mpzm.get_int64(exp_u), sig_z);
result = m_fu.mk_value(f);
TRACE("t_fpa", tout << "fpa_value_proc::mk_value [" <<
diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp
index 63ac0fbe8..f5353e8d0 100644
--- a/src/smt/theory_seq.cpp
+++ b/src/smt/theory_seq.cpp
@@ -15,20 +15,35 @@ Author:
Revision History:
+ // Use instead reference counts for dependencies to GC?
+
--*/
#include "value_factory.h"
#include "smt_context.h"
#include "smt_model_generator.h"
#include "theory_seq.h"
-#include "seq_rewriter.h"
#include "ast_trail.h"
+#include "theory_arith.h"
using namespace smt;
-void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d) {
+struct display_expr {
+ ast_manager& m;
+ display_expr(ast_manager& m): m(m) {}
+ std::ostream& display(std::ostream& out, expr* e) const {
+ return out << mk_pp(e, m);
+ }
+};
+
+
+
+void theory_seq::solution_map::update(expr* e, expr* r, dependency* d) {
+ if (e == r) {
+ return;
+ }
m_cache.reset();
- std::pair value;
+ std::pair value;
if (m_map.find(e, value)) {
add_trail(DEL, e, value.first, value.second);
}
@@ -38,24 +53,39 @@ void theory_seq::solution_map::update(expr* e, expr* r, enode_pair_dependency* d
add_trail(INS, e, r, d);
}
-void theory_seq::solution_map::add_trail(map_update op, expr* l, expr* r, enode_pair_dependency* d) {
+void theory_seq::solution_map::add_trail(map_update op, expr* l, expr* r, dependency* d) {
m_updates.push_back(op);
m_lhs.push_back(l);
m_rhs.push_back(r);
m_deps.push_back(d);
}
-expr* theory_seq::solution_map::find(expr* e, enode_pair_dependency*& d) {
- std::pair value;
+bool theory_seq::solution_map::is_root(expr* e) const {
+ return !m_map.contains(e);
+}
+
+expr* theory_seq::solution_map::find(expr* e, dependency*& d) {
+ std::pair value;
d = 0;
expr* result = e;
while (m_map.find(result, value)) {
d = m_dm.mk_join(d, value.second);
+ TRACE("seq", tout << mk_pp(result, m) << " -> " << mk_pp(value.first, m) << "\n";);
+ SASSERT(result != value.first);
+ SASSERT(e != value.first);
result = value.first;
}
return result;
}
+expr* theory_seq::solution_map::find(expr* e) {
+ std::pair value;
+ while (m_map.find(e, value)) {
+ e = value.first;
+ }
+ return e;
+}
+
void theory_seq::solution_map::pop_scope(unsigned num_scopes) {
if (num_scopes == 0) return;
m_cache.reset();
@@ -119,246 +149,397 @@ void theory_seq::exclusion_table::display(std::ostream& out) const {
}
}
+
theory_seq::theory_seq(ast_manager& m):
theory(m.mk_family_id("seq")),
m(m),
m_rep(m, m_dm),
+ m_eq_id(0),
m_factory(0),
- m_ineqs(m),
m_exclude(m),
m_axioms(m),
m_axioms_head(0),
- m_branch_variable_head(0),
- m_incomplete(false),
- m_has_length(false),
- m_model_completion(false),
- m_rewrite(m),
+ m_mg(0),
+ m_rewrite(m),
+ m_seq_rewrite(m),
m_util(m),
m_autil(m),
- m_trail_stack(*this) {
- m_prefix_sym = "seq.prefix.suffix";
- m_suffix_sym = "seq.suffix.prefix";
- m_left_sym = "seq.left";
- m_right_sym = "seq.right";
- m_contains_left_sym = "seq.contains.left";
- m_contains_right_sym = "seq.contains.right";
+ m_trail_stack(*this),
+ m_atoms_qhead(0),
+ m_ls(m), m_rs(m),
+ m_lhs(m), m_rhs(m),
+ m_new_solution(false),
+ m_new_propagation(false) {
+ m_prefix = "seq.prefix.suffix";
+ m_suffix = "seq.suffix.prefix";
+ m_contains_left = "seq.contains.left";
+ m_contains_right = "seq.contains.right";
+ m_accept = "aut.accept";
+ m_reject = "aut.reject";
+ m_tail = "seq.tail";
+ m_nth = "seq.nth";
+ m_seq_first = "seq.first";
+ m_seq_last = "seq.last";
+ m_indexof_left = "seq.indexof.left";
+ m_indexof_right = "seq.indexof.right";
+ m_aut_step = "aut.step";
+ m_extract_prefix = "seq.extract.prefix";
+ m_at_left = "seq.at.left";
+ m_at_right = "seq.at.right";
}
theory_seq::~theory_seq() {
+ m_trail_stack.reset();
}
final_check_status theory_seq::final_check_eh() {
context & ctx = get_context();
TRACE("seq", display(tout););
- if (!check_ineqs()) {
- return FC_CONTINUE;
- }
if (simplify_and_solve_eqs()) {
+ ++m_stats.m_solve_eqs;
+ TRACE("seq", tout << ">>solve_eqs\n";);
return FC_CONTINUE;
}
- if (ctx.inconsistent()) {
+ if (solve_nqs(0)) {
+ ++m_stats.m_solve_nqs;
+ TRACE("seq", tout << ">>solve_nqs\n";);
return FC_CONTINUE;
}
if (branch_variable()) {
- TRACE("seq", tout << "branch\n";);
+ ++m_stats.m_branch_variable;
+ TRACE("seq", tout << ">>branch_variable\n";);
return FC_CONTINUE;
}
- if (split_variable()) {
- TRACE("seq", tout << "split_variable\n";);
+ if (check_length_coherence()) {
+ ++m_stats.m_check_length_coherence;
+ TRACE("seq", tout << ">>check_length_coherence\n";);
return FC_CONTINUE;
}
- if (ctx.inconsistent()) {
+ if (propagate_automata()) {
+ ++m_stats.m_propagate_automata;
+ TRACE("seq", tout << ">>propagate_automata\n";);
return FC_CONTINUE;
}
- if (!check_length_coherence()) {
- TRACE("seq", tout << "check_length_coherence\n";);
- return FC_CONTINUE;
- }
- if (!check_length_coherence_tbd()) {
- TRACE("seq", tout << "check_length_coherence\n";);
- return FC_GIVEUP;
- }
if (is_solved()) {
- TRACE("seq", tout << "is_solved\n";);
+ TRACE("seq", tout << ">>is_solved\n";);
return FC_DONE;
}
return FC_GIVEUP;
}
-bool theory_seq::check_ineqs() {
- context & ctx = get_context();
- for (unsigned i = 0; i < m_ineqs.size(); ++i) {
- expr* a = m_ineqs[i].get();
- enode_pair_dependency* eqs = 0;
- expr_ref b = canonize(a, eqs);
- if (m.is_true(b)) {
- TRACE("seq", tout << "Evaluates to false: " << mk_pp(a,m) << "\n";);
- ctx.internalize(a, false);
- propagate_lit(eqs, ctx.get_literal(a));
- return false;
- }
- else if (!m.is_false(b)) {
- TRACE("seq", tout << "Disequality is undetermined: " << mk_pp(a, m) << " " << b << "\n";);
- }
- }
- return true;
-}
bool theory_seq::branch_variable() {
context& ctx = get_context();
unsigned sz = m_eqs.size();
- ptr_vector ls, rs;
+ int start = ctx.get_random_value();
+ unsigned s = 0;
for (unsigned i = 0; i < sz; ++i) {
- unsigned k = (i + m_branch_variable_head) % sz;
- eq e = m_eqs[k];
- TRACE("seq", tout << e.m_lhs << " = " << e.m_rhs << "\n";);
- ls.reset(); rs.reset();
- m_util.str.get_concat(e.m_lhs, ls);
- m_util.str.get_concat(e.m_rhs, rs);
-
- if (!ls.empty() && find_branch_candidate(ls[0], rs)) {
- m_branch_variable_head = k;
+ unsigned k = (i + start) % sz;
+ eq const& e = m_eqs[k];
+ unsigned id = e.id();
+ TRACE("seq", tout << e.ls() << " = " << e.rs() << "\n";);
+
+ s = find_branch_start(2*id);
+ bool found = find_branch_candidate(s, e.dep(), e.ls(), e.rs());
+ insert_branch_start(2*id, s);
+ if (found) {
return true;
}
- if (!rs.empty() && find_branch_candidate(rs[0], ls)) {
- m_branch_variable_head = k;
+ s = find_branch_start(2*id + 1);
+ found = find_branch_candidate(s, e.dep(), e.rs(), e.ls());
+ insert_branch_start(2*id + 1, s);
+ if (found) {
return true;
}
+
+#if 0
+ if (!has_length(e.ls())) {
+ enforce_length(ensure_enode(e.ls()));
+ }
+ if (!has_length(e.rs())) {
+ enforce_length(ensure_enode(e.rs()));
+ }
+#endif
}
- return false;
+ return ctx.inconsistent();
}
-bool theory_seq::find_branch_candidate(expr* l, ptr_vector const& rs) {
+void theory_seq::insert_branch_start(unsigned k, unsigned s) {
+ m_branch_start.insert(k, s);
+ m_trail_stack.push(pop_branch(k));
+}
- TRACE("seq", tout << mk_pp(l, m) << " "
- << (is_var(l)?"var":"not var") << "\n";);
+unsigned theory_seq::find_branch_start(unsigned k) {
+ unsigned s = 0;
+ if (m_branch_start.find(k, s)) {
+ return s;
+ }
+ return 0;
+}
+
+bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs) {
+
+ if (ls.empty()) {
+ return false;
+ }
+ expr* l = ls[0];
if (!is_var(l)) {
return false;
}
- expr_ref v0(m), v(m);
+ expr_ref v0(m);
v0 = m_util.str.mk_empty(m.get_sort(l));
- if (assume_equality(l, v0)) {
+ if (can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size(), rs.c_ptr()) && l_false != assume_equality(l, v0)) {
+ TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";);
return true;
}
- for (unsigned j = 0; j < rs.size(); ++j) {
- if (occurs(l, rs[j])) {
+// start = 0;
+ for (; start < rs.size(); ++start) {
+ unsigned j = start;
+ SASSERT(!m_util.str.is_concat(rs[j]));
+ SASSERT(!m_util.str.is_string(rs[j]));
+ if (l == rs[j]) {
return false;
}
- zstring s;
- if (m_util.str.is_string(rs[j], s)) {
- for (size_t k = 1; k < s.length(); ++k) {
- v = m_util.str.mk_string(s.extract(0, k));
- if (v0) v = m_util.str.mk_concat(v0, v);
- if (assume_equality(l, v)) {
- return true;
- }
- }
+ if (!can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size() - j - 1, rs.c_ptr() + j + 1)) {
+ continue;
}
- v0 = (j == 0)? rs[0] : m_util.str.mk_concat(v0, rs[j]);
- if (assume_equality(l, v0)) {
+ v0 = mk_concat(j + 1, rs.c_ptr());
+ if (l_false != assume_equality(l, v0)) {
+ TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";);
+ ++start;
return true;
}
}
+
+ bool all_units = true;
+ for (unsigned j = 0; all_units && j < rs.size(); ++j) {
+ all_units &= m_util.str.is_unit(rs[j]);
+ }
+ if (all_units) {
+ literal_vector lits;
+ lits.push_back(~mk_eq_empty(l));
+ for (unsigned i = 0; i < rs.size(); ++i) {
+ v0 = mk_concat(i + 1, rs.c_ptr());
+ lits.push_back(~mk_eq(l, v0, false));
+ }
+ set_conflict(dep, lits);
+ TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";);
+ return true;
+ }
return false;
}
-bool theory_seq::assume_equality(expr* l, expr* r) {
- context& ctx = get_context();
- if (m_exclude.contains(l, r)) {
- return false;
+bool theory_seq::can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const {
+ unsigned i = 0;
+ for (; i < szl && i < szr; ++i) {
+ if (m.are_distinct(ls[i], rs[i])) {
+ return false;
+ }
+ if (!m.are_equal(ls[i], rs[i])) {
+ break;
+ }
}
- else {
- TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << "\n";);
- enode* n1 = ensure_enode(l);
- enode* n2 = ensure_enode(r);
- ctx.mark_as_relevant(n1);
- ctx.mark_as_relevant(n2);
- ctx.assume_eq(n1, n2);
- return true;
+ if (i == szr) {
+ std::swap(ls, rs);
+ std::swap(szl, szr);
}
+ if (i == szl && i < szr) {
+ for (; i < szr; ++i) {
+ if (m_util.str.is_unit(rs[i])) {
+ return false;
+ }
+ }
+ }
+ return true;
}
-bool theory_seq::split_variable() {
+lbool theory_seq::assume_equality(expr* l, expr* r) {
+ context& ctx = get_context();
+ if (m_exclude.contains(l, r)) {
+ return l_false;
+ }
+
+ expr_ref eq(m.mk_eq(l, r), m);
+ m_rewrite(eq);
+ if (m.is_true(eq)) {
+ return l_true;
+ }
+ if (m.is_false(eq)) {
+ return l_false;
+ }
+
+ TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << "\n";);
+ enode* n1 = ensure_enode(l);
+ enode* n2 = ensure_enode(r);
+ if (n1->get_root() == n2->get_root()) {
+ return l_true;
+ }
+ ctx.mark_as_relevant(n1);
+ ctx.mark_as_relevant(n2);
+ ctx.assume_eq(n1, n2);
+ return l_undef;
+}
+
+bool theory_seq::propagate_length_coherence(expr* e) {
+ expr_ref head(m), tail(m);
+ rational lo, hi;
+
+ if (!is_var(e) || !m_rep.is_root(e)) {
+ return false;
+ }
+ if (!lower_bound(e, lo) || !lo.is_pos() || lo >= rational(2048)) {
+ return false;
+ }
+ TRACE("seq", tout << "Unsolved " << mk_pp(e, m);
+ if (!lower_bound(e, lo)) lo = -rational::one();
+ if (!upper_bound(e, hi)) hi = -rational::one();
+ tout << " lo: " << lo << " hi: " << hi << "\n";
+ );
+
+ expr_ref seq(e, m);
+ expr_ref_vector elems(m);
+ unsigned _lo = lo.get_unsigned();
+ for (unsigned j = 0; j < _lo; ++j) {
+ mk_decompose(seq, head, tail);
+ elems.push_back(head);
+ seq = tail;
+ }
+ expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m);
+ elems.push_back(seq);
+ tail = mk_concat(elems.size(), elems.c_ptr());
+ // len(e) >= low => e = tail;
+ literal low(mk_literal(m_autil.mk_ge(m_util.str.mk_length(e), m_autil.mk_numeral(lo, true))));
+ add_axiom(~low, mk_eq(e, tail, false));
+ if (upper_bound(e, hi)) {
+ // len(e) <= hi => len(tail) <= hi - lo
+ expr_ref high1(m_autil.mk_le(m_util.str.mk_length(e), m_autil.mk_numeral(hi, true)), m);
+ if (hi == lo) {
+ add_axiom(~mk_literal(high1), mk_eq(seq, emp, false));
+ }
+ else {
+ expr_ref high2(m_autil.mk_le(m_util.str.mk_length(seq), m_autil.mk_numeral(hi-lo, true)), m);
+ add_axiom(~mk_literal(high1), mk_literal(high2));
+ }
+ }
+ else {
+ assume_equality(seq, emp);
+ }
+ return true;
+}
+
+bool theory_seq::check_length_coherence(expr* e) {
+ if (is_var(e) && m_rep.is_root(e)) {
+ expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m);
+ expr_ref head(m), tail(m);
+ if (!propagate_length_coherence(e) &&
+ l_false == assume_equality(e, emp)) {
+ // e = emp \/ e = unit(head.elem(e))*tail(e)
+ mk_decompose(e, head, tail);
+ expr_ref conc = mk_concat(head, tail);
+ propagate_is_conc(e, conc);
+ assume_equality(tail, emp);
+ }
+ m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e)));
+ return true;
+ }
return false;
}
bool theory_seq::check_length_coherence() {
- if (!m_has_length) return true;
- context& ctx = get_context();
- bool coherent = true;
- for (unsigned i = 0; i < m_eqs.size(); ++i) {
- m_eqs[i].m_dep;
- expr_ref v1(m), v2(m), l(m_eqs[i].m_lhs), r(m_eqs[i].m_rhs);
- expr_ref len1(m_util.str.mk_length(l), m);
- expr_ref len2(m_util.str.mk_length(r), m);
- enode* n1 = ensure_enode(len1);
- enode* n2 = ensure_enode(len2);
- if (n1->get_root() != n2->get_root()) {
- TRACE("seq", tout << len1 << " = " << len2 << "\n";);
- propagate_eq(m_eqs[i].m_dep, n1, n2);
- coherent = false;
+ obj_hashtable::iterator it = m_length.begin(), end = m_length.end();
+ for (; it != end; ++it) {
+ expr* e = *it;
+ if (check_length_coherence(e)) {
+ return true;
}
}
- return coherent;
-}
-
-bool theory_seq::check_length_coherence_tbd() {
- if (!m_has_length) return true;
- context& ctx = get_context();
- bool coherent = true;
- // each variable that canonizes to itself can have length 0.
- unsigned sz = get_num_vars();
- for (unsigned i = 0; i < sz; ++i) {
- enode* n = get_enode(i);
- expr* e = n->get_owner();
- if (m_util.is_re(e)) {
- continue;
- }
- SASSERT(m_util.is_seq(e));
- // extend length of variables.
- enode_pair_dependency* dep = 0;
- expr* f = m_rep.find(e, dep);
- if (is_var(f) && f == e) {
- expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m);
- TRACE("seq", tout << "Unsolved " << mk_pp(e, m) << "\n";);
-#if 0
- if (!assume_equality(e, emp)) {
- // e = emp \/ e = head*tail & head = unit(v)
- sort* char_sort = 0;
- VERIFY(m_util.is_seq(m.get_sort(e), char_sort));
- expr_ref tail(mk_skolem(symbol("seq.tail"), e), m);
- expr_ref v(mk_skolem(symbol("seq.head.elem"), e, 0, 0, char_sort), m);
- expr_ref head(m_util.str.mk_unit(v), m);
- expr_ref conc(m_util.str.mk_concat(head, tail), m);
- literal e_eq_emp(mk_eq(e, emp, false));
- add_axiom(e_eq_emp, mk_eq(e, conc, false));
- }
-#endif
- coherent = false;
- }
- }
- return coherent;
+ return false;
}
-bool theory_seq::check_ineq_coherence() {
- bool all_false = true;
- for (unsigned i = 0; all_false && i < m_ineqs.size(); ++i) {
- expr* a = m_ineqs[i].get();
- enode_pair_dependency* eqs = 0;
- expr_ref b = canonize(a, eqs);
- all_false = m.is_false(b);
- if (all_false) {
- TRACE("seq", tout << "equality is undetermined: " << mk_pp(a, m) << " " << b << "\n";);
- }
- }
- return all_false;
+/*
+ lit => s != ""
+*/
+void theory_seq::propagate_non_empty(literal lit, expr* s) {
+ SASSERT(get_context().get_assignment(lit) == l_true);
+ propagate_lit(0, 1, &lit, ~mk_eq_empty(s));
}
+void theory_seq::propagate_is_conc(expr* e, expr* conc) {
+ TRACE("seq", tout << mk_pp(conc, m) << " is non-empty\n";);
+ context& ctx = get_context();
+ literal lit = ~mk_eq_empty(e);
+ SASSERT(ctx.get_assignment(lit) == l_true);
+ propagate_lit(0, 1, &lit, mk_eq(e, conc, false));
+ expr_ref e1(e, m), e2(conc, m);
+ new_eq_eh(m_dm.mk_leaf(assumption(lit)), ctx.get_enode(e1), ctx.get_enode(e2));
+}
+
+bool theory_seq::is_nth(expr* e) const {
+ return is_skolem(m_nth, e);
+}
+
+bool theory_seq::is_tail(expr* e, expr*& s, unsigned& idx) const {
+ rational r;
+ return
+ is_skolem(m_tail, e) &&
+ m_autil.is_numeral(to_app(e)->get_arg(1), r) &&
+ (idx = r.get_unsigned(), s = to_app(e)->get_arg(0), true);
+}
+
+
+expr_ref theory_seq::mk_nth(expr* s, expr* idx) {
+ sort* char_sort = 0;
+ VERIFY(m_util.is_seq(m.get_sort(s), char_sort));
+ return mk_skolem(m_nth, s, idx, 0, char_sort);
+}
+
+expr_ref theory_seq::mk_last(expr* s) {
+ sort* char_sort = 0;
+ VERIFY(m_util.is_seq(m.get_sort(s), char_sort));
+ return mk_skolem(m_seq_last, s, 0, 0, char_sort);
+}
+
+
+void theory_seq::mk_decompose(expr* e, expr_ref& head, expr_ref& tail) {
+ expr* e1, *e2;
+ zstring s;
+ if (m_util.str.is_empty(e)) {
+ head = m_util.str.mk_unit(mk_nth(e, m_autil.mk_int(0)));
+ tail = e;
+ }
+ else if (m_util.str.is_string(e, s)) {
+ head = m_util.str.mk_unit(m_util.str.mk_char(s, 0));
+ tail = m_util.str.mk_string(s.extract(1, s.length()-1));
+ }
+ else if (m_util.str.is_unit(e)) {
+ head = e;
+ tail = m_util.str.mk_empty(m.get_sort(e));
+ }
+ else if (m_util.str.is_concat(e, e1, e2) && m_util.str.is_unit(e1)) {
+ head = e1;
+ tail = e2;
+ }
+ else if (is_skolem(m_tail, e)) {
+ rational r;
+ app* a = to_app(e);
+ expr* s = a->get_arg(0);
+ VERIFY (m_autil.is_numeral(a->get_arg(1), r));
+ expr* idx = m_autil.mk_int(r.get_unsigned() + 1);
+ head = m_util.str.mk_unit(mk_nth(s, idx));
+ tail = mk_skolem(m_tail, s, idx);
+ }
+ else {
+ head = m_util.str.mk_unit(mk_nth(e, m_autil.mk_int(0)));
+ tail = mk_skolem(m_tail, e, m_autil.mk_int(0));
+ }
+}
+
+
/*
- Eqs = 0
- Diseqs evaluate to false
@@ -367,48 +548,72 @@ bool theory_seq::check_ineq_coherence() {
bool theory_seq::is_solved() {
if (!m_eqs.empty()) {
+ IF_VERBOSE(10, verbose_stream() << "(seq.giveup " << m_eqs[0].ls() << " = " << m_eqs[0].rs() << " is unsolved)\n";);
return false;
}
- if (!check_ineq_coherence()) {
- return false;
- }
-
- SASSERT(check_length_coherence());
-
+ for (unsigned i = 0; i < m_automata.size(); ++i) {
+ if (!m_automata[i]) {
+ IF_VERBOSE(10, verbose_stream() << "(seq.giveup regular expression did not compile to automaton)\n";);
+ return false;
+ }
+ }
return true;
-
}
-void theory_seq::propagate_lit(enode_pair_dependency* dep, literal lit) {
+void theory_seq::linearize(dependency* dep, enode_pair_vector& eqs, literal_vector& lits) const {
+ svector assumptions;
+ const_cast(m_dm).linearize(dep, assumptions);
+ for (unsigned i = 0; i < assumptions.size(); ++i) {
+ assumption const& a = assumptions[i];
+ if (a.lit != null_literal) {
+ lits.push_back(a.lit);
+ }
+ if (a.n1 != 0) {
+ eqs.push_back(enode_pair(a.n1, a.n2));
+ }
+ }
+}
+
+
+
+void theory_seq::propagate_lit(dependency* dep, unsigned n, literal const* _lits, literal lit) {
context& ctx = get_context();
ctx.mark_as_relevant(lit);
- vector _eqs;
- m_dm.linearize(dep, _eqs);
+ literal_vector lits(n, _lits);
+ enode_pair_vector eqs;
+ linearize(dep, eqs, lits);
TRACE("seq", ctx.display_detailed_literal(tout, lit);
- tout << " <- "; display_deps(tout, dep););
+ tout << " <- "; ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); display_deps(tout, dep););
justification* js =
ctx.mk_justification(
ext_theory_propagation_justification(
- get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), lit));
+ get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), lit));
+ m_new_propagation = true;
ctx.assign(lit, js);
}
-void theory_seq::set_conflict(enode_pair_dependency* dep) {
+void theory_seq::set_conflict(dependency* dep, literal_vector const& _lits) {
context& ctx = get_context();
- vector _eqs;
- m_dm.linearize(dep, _eqs);
- TRACE("seq", display_deps(tout, dep););
+ enode_pair_vector eqs;
+ literal_vector lits(_lits);
+ linearize(dep, eqs, lits);
+ TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); display_deps(tout, dep); ;);
+ m_new_propagation = true;
ctx.set_conflict(
ctx.mk_justification(
ext_theory_conflict_justification(
- get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), 0, 0)));
+ get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), 0, 0)));
}
-void theory_seq::propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2) {
+void theory_seq::propagate_eq(dependency* dep, enode* n1, enode* n2) {
+ if (n1->get_root() == n2->get_root()) {
+ return;
+ }
context& ctx = get_context();
- vector _eqs;
- m_dm.linearize(dep, _eqs);
+ literal_vector lits;
+ enode_pair_vector eqs;
+ linearize(dep, eqs, lits);
TRACE("seq",
tout << mk_pp(n1->get_owner(), m) << " = " << mk_pp(n2->get_owner(), m) << " <- ";
display_deps(tout, dep);
@@ -416,90 +621,127 @@ void theory_seq::propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2)
justification* js = ctx.mk_justification(
ext_theory_eq_propagation_justification(
- get_id(), ctx.get_region(), 0, 0, _eqs.size(), _eqs.c_ptr(), n1, n2));
+ get_id(), ctx.get_region(), lits.size(), lits.c_ptr(), eqs.size(), eqs.c_ptr(), n1, n2));
ctx.assign_eq(n1, n2, eq_justification(js));
+ m_new_propagation = true;
+
+ enforce_length_coherence(n1, n2);
+}
+
+void theory_seq::enforce_length_coherence(enode* n1, enode* n2) {
+ expr* o1 = n1->get_owner();
+ expr* o2 = n2->get_owner();
+ if (m_util.str.is_concat(o1) && m_util.str.is_concat(o2)) {
+ //std::cout << "concats:\n" << mk_pp(o1,m) << "\n" << mk_pp(o2,m) << "\n";
+ return;
+ }
+ if (has_length(o1) && !has_length(o2)) {
+ //std::cout << "enforce length: " << mk_pp(o1,m) << " -> " << mk_pp(o2,m) << "\n";
+ enforce_length(n2);
+ }
+ else if (has_length(o2) && !has_length(o1)) {
+ //std::cout << "enforce length: " << mk_pp(o2,m) << " -> " << mk_pp(o1,m) << "\n";
+ enforce_length(n1);
+ }
}
-bool theory_seq::simplify_eq(expr* l, expr* r, enode_pair_dependency* deps) {
+bool theory_seq::simplify_eq(expr_ref_vector& ls, expr_ref_vector& rs, dependency* deps) {
context& ctx = get_context();
- seq_rewriter rw(m);
expr_ref_vector lhs(m), rhs(m);
- expr_ref lh = canonize(l, deps);
- expr_ref rh = canonize(r, deps);
- if (!rw.reduce_eq(lh, rh, lhs, rhs)) {
- // equality is inconsistent.
- TRACE("seq", tout << lh << " != " << rh << "\n";);
+ if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs)) {
+ // equality is inconsistent.x2
+ TRACE("seq", tout << ls << " != " << rs << "\n";);
set_conflict(deps);
return true;
}
- if (lhs.size() == 1 && l == lhs[0].get() &&
- rhs.size() == 1 && r == rhs[0].get()) {
+ if (lhs.empty()) {
return false;
}
SASSERT(lhs.size() == rhs.size());
- for (unsigned i = 0; i < lhs.size(); ++i) {
- expr_ref l(lhs[i].get(), m);
- expr_ref r(rhs[i].get(), m);
- if (m_util.is_seq(l) || m_util.is_re(l)) {
- m_eqs.push_back(eq(l, r, deps));
+ SASSERT(ls.empty() && rs.empty());
+ for (unsigned i = 0; !ctx.inconsistent() && i < lhs.size(); ++i) {
+ expr_ref li(lhs[i].get(), m);
+ expr_ref ri(rhs[i].get(), m);
+ if (solve_unit_eq(li, ri, deps)) {
+ // skip
+ }
+ else if (m_util.is_seq(li) || m_util.is_re(li)) {
+ m_eqs.push_back(mk_eqdep(li, ri, deps));
}
else {
- propagate_eq(deps, ensure_enode(l), ensure_enode(r));
+ propagate_eq(deps, ensure_enode(li), ensure_enode(ri));
}
- }
+ }
TRACE("seq",
- tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " => ";
- for (unsigned i = 0; i < m_eqs.size(); ++i) {
- tout << m_eqs[i].m_lhs << " = " << m_eqs[i].m_rhs << "; ";
+ tout << ls << " = " << rs << " => \n";
+ for (unsigned i = 0; i < lhs.size(); ++i) {
+ tout << mk_pp(lhs[i].get(), m) << "\n = \n" << mk_pp(rhs[i].get(), m) << "; \n";
}
- tout << "\n";
- );
+ tout << "\n";);
+
+
return true;
}
-bool theory_seq::solve_unit_eq(expr* l, expr* r, enode_pair_dependency* deps) {
- expr_ref lh = canonize(l, deps);
- expr_ref rh = canonize(r, deps);
- if (lh == rh) {
+bool theory_seq::solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* deps) {
+ if (l.size() == 1 && is_var(l[0]) && !occurs(l[0], r) && add_solution(l[0], mk_concat(r), deps)) {
return true;
}
- if (is_var(lh) && !occurs(lh, rh)) {
- add_solution(lh, rh, deps);
+ if (r.size() == 1 && is_var(r[0]) && !occurs(r[0], l) && add_solution(r[0], mk_concat(l), deps)) {
return true;
}
- if (is_var(rh) && !occurs(rh, lh)) {
- add_solution(rh, lh, deps);
- return true;
- }
- // Use instead reference counts for dependencies to GC?
- // TBD: Solutions to units are not necessarily variables, but
- // they may induce new equations.
+ return false;
+}
+bool theory_seq::solve_unit_eq(expr* l, expr* r, dependency* deps) {
+ SASSERT(l != r);
+ if (l == r) {
+ return true;
+ }
+
+ if (is_var(l) && !occurs(l, r) && add_solution(l, r, deps)) {
+ return true;
+ }
+ if (is_var(r) && !occurs(r, l) && add_solution(r, l, deps)) {
+ return true;
+ }
+
+ return false;
+}
+
+
+bool theory_seq::occurs(expr* a, expr_ref_vector const& b) {
+ for (unsigned i = 0; i < b.size(); ++i) {
+ if (a == b[i]) return true;
+ }
return false;
}
bool theory_seq::occurs(expr* a, expr* b) {
- // true if a occurs under an interpreted function or under left/right selector.
+ // true if a occurs under an interpreted function or under left/right selector.
SASSERT(is_var(a));
+ SASSERT(m_todo.empty());
expr* e1, *e2;
- while (is_left_select(a, e1) || is_right_select(a, e1)) {
- a = e1;
+ m_todo.push_back(b);
+ while (!m_todo.empty()) {
+ b = m_todo.back();
+ if (a == b) {
+ m_todo.reset();
+ return true;
+ }
+ m_todo.pop_back();
+ if (m_util.str.is_concat(b, e1, e2)) {
+ m_todo.push_back(e1);
+ m_todo.push_back(e2);
+ }
}
- if (m_util.str.is_concat(b, e1, e2)) {
- return occurs(a, e1) || occurs(a, e2);
- }
- while (is_left_select(b, e1) || is_right_select(b, e1)) {
- b = e1;
- }
- if (a == b) {
- return true;
- }
- return false;
+ return false;
}
+
bool theory_seq::is_var(expr* a) {
return
m_util.is_seq(a) &&
@@ -509,42 +751,30 @@ bool theory_seq::is_var(expr* a) {
!m_util.str.is_unit(a);
}
-bool theory_seq::is_left_select(expr* a, expr*& b) {
- return m_util.is_skolem(a) &&
- to_app(a)->get_decl()->get_parameter(0).get_symbol() == m_left_sym && (b = to_app(a)->get_arg(0), true);
-}
-bool theory_seq::is_right_select(expr* a, expr*& b) {
- return m_util.is_skolem(a) &&
- to_app(a)->get_decl()->get_parameter(0).get_symbol() == m_right_sym && (b = to_app(a)->get_arg(0), true);
-}
-void theory_seq::add_solution(expr* l, expr* r, enode_pair_dependency* deps) {
- context& ctx = get_context();
- m_rep.update(l, r, deps);
- // TBD: skip new equalities for non-internalized terms.
- if (ctx.e_internalized(l) && ctx.e_internalized(r)) {
- propagate_eq(deps, ctx.get_enode(l), ctx.get_enode(r));
+bool theory_seq::add_solution(expr* l, expr* r, dependency* deps) {
+ if (l == r) {
+ return false;
}
+ context& ctx = get_context();
+ TRACE("seq", tout << mk_pp(l, m) << " ==> " << mk_pp(r, m) << "\n";);
+ m_new_solution = true;
+ m_rep.update(l, r, deps);
+ enode* n1 = ensure_enode(l);
+ enode* n2 = ensure_enode(r);
+ if (n1->get_root() != n2->get_root()) {
+ propagate_eq(deps, n1, n2);
+ }
+ return true;
}
-bool theory_seq::simplify_eqs() {
- return pre_process_eqs(true);
-}
-
-bool theory_seq::solve_basic_eqs() {
- return pre_process_eqs(false);
-}
-
-bool theory_seq::pre_process_eqs(bool simplify_or_solve) {
+bool theory_seq::solve_eqs(unsigned i) {
context& ctx = get_context();
bool change = false;
- for (unsigned i = 0; !ctx.inconsistent() && i < m_eqs.size(); ++i) {
+ for (; !ctx.inconsistent() && i < m_eqs.size(); ++i) {
eq e = m_eqs[i];
-
- if (simplify_or_solve?
- simplify_eq(e.m_lhs, e.m_rhs, e.m_dep):
- solve_unit_eq(e.m_lhs, e.m_rhs, e.m_dep)) {
+ if (solve_eq(e.ls(), e.rs(), e.dep())) {
if (i + 1 != m_eqs.size()) {
eq e1 = m_eqs[m_eqs.size()-1];
m_eqs.set(i, e1);
@@ -555,72 +785,487 @@ bool theory_seq::pre_process_eqs(bool simplify_or_solve) {
change = true;
}
}
- return change;
+ return change || ctx.inconsistent();
}
-bool theory_seq::simplify_and_solve_eqs() {
- context & ctx = get_context();
- bool change = simplify_eqs();
- while (!ctx.inconsistent() && solve_basic_eqs()) {
- simplify_eqs();
- change = true;
+bool theory_seq::solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* deps) {
+ context& ctx = get_context();
+ expr_ref_vector& ls = m_ls;
+ expr_ref_vector& rs = m_rs;
+ rs.reset(); ls.reset();
+ dependency* dep2 = 0;
+ bool change = canonize(l, ls, dep2);
+ change = canonize(r, rs, dep2) || change;
+ TRACE("seq", tout << ls << " = " << rs << "\n";);
+ deps = m_dm.mk_join(dep2, deps);
+ if (!ctx.inconsistent() && simplify_eq(ls, rs, deps)) {
+ return true;
+ }
+ TRACE("seq", tout << ls << " = " << rs << "\n";);
+ SASSERT(rs.empty() == ls.empty());
+ if (ls.empty()) {
+ return true;
+ }
+ if (!ctx.inconsistent() && solve_unit_eq(ls, rs, deps)) {
+ return true;
+ }
+ if (!ctx.inconsistent() && solve_binary_eq(ls, rs, deps)) {
+ return true;
+ }
+ if (!ctx.inconsistent() && change) {
+ m_eqs.push_back(eq(m_eq_id++, ls, rs, deps));
+ return true;
+ }
+ return false;
+}
+
+bool theory_seq::propagate_max_length(expr* l, expr* r, dependency* deps) {
+ unsigned idx;
+ expr* s;
+ if (m_util.str.is_empty(l)) {
+ std::swap(l, r);
+ }
+ rational hi;
+ if (is_tail(l, s, idx) && has_length(s) && m_util.str.is_empty(r) && !upper_bound(s, hi)) {
+ //std::cout << "max length " << mk_pp(s, m) << " " << idx << "\n";
+ propagate_lit(deps, 0, 0, mk_literal(m_autil.mk_le(m_util.str.mk_length(s), m_autil.mk_int(idx+1))));
+ return true;
+ }
+ return false;
+}
+
+bool theory_seq::is_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, expr*& x, ptr_vector& xs, ptr_vector& ys, expr*& y) {
+ if (ls.size() > 1 && is_var(ls[0]) &&
+ rs.size() > 1 && is_var(rs.back())) {
+ xs.reset();
+ ys.reset();
+ x = ls[0];
+ y = rs.back();
+ for (unsigned i = 1; i < ls.size(); ++i) {
+ if (!m_util.str.is_unit(ls[i])) return false;
+ }
+ for (unsigned i = 0; i < rs.size()-1; ++i) {
+ if (!m_util.str.is_unit(rs[i])) return false;
+ }
+ xs.append(ls.size()-1, ls.c_ptr() + 1);
+ ys.append(rs.size()-1, rs.c_ptr());
+ return true;
+ }
+ return false;
+}
+
+bool theory_seq::solve_binary_eq(expr_ref_vector const& ls, expr_ref_vector const& rs, dependency* dep) {
+ context& ctx = get_context();
+ ptr_vector xs, ys;
+ expr* x, *y;
+ bool is_binary = is_binary_eq(ls, rs, x, xs, ys, y);
+ if (!is_binary) {
+ is_binary = is_binary_eq(rs, ls, x, xs, ys, y);
+ }
+ if (!is_binary) {
+ return false;
+ }
+ // Equation is of the form x ++ xs = ys ++ y
+ // where xs, ys are units.
+ if (x != y) {
+ return false;
+ }
+ if (xs.size() != ys.size()) {
+ set_conflict(dep);
+ return false;
+ }
+ if (xs.empty()) {
+ // this should have been solved already
+ UNREACHABLE();
+ return false;
+ }
+ unsigned sz = xs.size();
+ literal_vector conflict;
+ for (unsigned offset = 0; offset < sz; ++offset) {
+ bool has_conflict = false;
+ for (unsigned j = 0; !has_conflict && j < sz; ++j) {
+ unsigned j1 = (offset + j) % sz;
+ literal eq = mk_eq(xs[j], ys[j1], false);
+ switch (ctx.get_assignment(eq)) {
+ case l_false:
+ conflict.push_back(~eq);
+ has_conflict = true;
+ break;
+ case l_undef: {
+ enode* n1 = ensure_enode(xs[j]);
+ enode* n2 = ensure_enode(ys[j1]);
+ if (n1->get_root() == n2->get_root()) {
+ break;
+ }
+ ctx.mark_as_relevant(eq);
+ if (sz == 1) {
+ propagate_lit(dep, 0, 0, eq);
+ return true;
+ }
+ m_new_propagation = true;
+ break;
+ }
+ case l_true:
+ break;
+ }
+ }
+ if (!has_conflict) {
+ TRACE("seq", tout << "offset: " << offset << " equality ";
+ for (unsigned j = 0; j < sz; ++j) {
+ tout << mk_pp(xs[j], m) << " = " << mk_pp(ys[(offset+j) % sz], m) << "; ";
+ }
+ tout << "\n";);
+ // current equalities can work when solving x ++ xs = ys ++ y
+ return false;
+ }
+ }
+ TRACE("seq", tout << conflict << "\n";);
+ set_conflict(dep, conflict);
+ return false;
+}
+
+bool theory_seq::solve_nqs(unsigned i) {
+ bool change = false;
+ context & ctx = get_context();
+ for (; !ctx.inconsistent() && i < m_nqs.size(); ++i) {
+ if (!m_nqs[i].is_solved()) {
+ solve_ne(i);
+ }
+ }
+ return m_new_propagation || ctx.inconsistent();
+}
+
+void theory_seq::solve_ne(unsigned idx) {
+ context& ctx = get_context();
+ ne const& n = m_nqs[idx];
+ TRACE("seq", display_disequation(tout, n););
+
+ SASSERT(!n.is_solved());
+ unsigned num_undef_lits = 0;
+ for (unsigned i = 0; i < n.m_lits.size(); ++i) {
+ switch (ctx.get_assignment(n.m_lits[i])) {
+ case l_false:
+ // mark as solved in
+ mark_solved(idx);
+ return;
+ case l_true:
+ break;
+ case l_undef:
+ ++num_undef_lits;
+ break;
+ }
+ }
+ for (unsigned i = 0; i < n.m_lhs.size(); ++i) {
+ expr_ref_vector& ls = m_ls;
+ expr_ref_vector& rs = m_rs;
+ expr_ref_vector& lhs = m_lhs;
+ expr_ref_vector& rhs = m_rhs;
+ ls.reset(); rs.reset(); lhs.reset(); rhs.reset();
+ dependency* deps = 0;
+ expr* l = n.m_lhs[i];
+ expr* r = n.m_rhs[i];
+ canonize(l, ls, deps);
+ canonize(r, rs, deps);
+ if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs)) {
+ mark_solved(idx);
+ return;
+ }
+ else if (lhs.empty() || (lhs.size() == 1 && lhs[0].get() == l)) {
+ // continue
+ }
+ else {
+ TRACE("seq",
+ for (unsigned j = 0; j < lhs.size(); ++j) {
+ tout << mk_pp(lhs[j].get(), m) << " ";
+ }
+ tout << "\n";
+ tout << mk_pp(l, m) << " != " << mk_pp(r, m) << "\n";);
+
+ for (unsigned j = 0; j < lhs.size(); ++j) {
+ expr_ref nl(lhs[j].get(), m);
+ expr_ref nr(rhs[j].get(), m);
+ if (m_util.is_seq(nl) || m_util.is_re(nl)) {
+ m_trail_stack.push(push_ne(*this, idx, nl, nr));
+ }
+ else {
+ literal lit(mk_eq(nl, nr, false));
+ m_trail_stack.push(push_lit(*this, idx, lit));
+ ctx.mark_as_relevant(lit);
+ switch (ctx.get_assignment(lit)) {
+ case l_false:
+ mark_solved(idx);
+ return;
+ case l_true:
+ break;
+ case l_undef:
+ ++num_undef_lits;
+ m_new_propagation = true;
+ break;
+ }
+ }
+ }
+ m_trail_stack.push(push_dep(*this, idx, deps));
+ erase_index(idx, i);
+ --i;
+ }
+ }
+ if (num_undef_lits == 1 && n.m_lhs.empty()) {
+ literal_vector lits;
+ literal undef_lit = null_literal;
+ for (unsigned i = 0; i < n.m_lits.size(); ++i) {
+ literal lit = n.m_lits[i];
+ switch (ctx.get_assignment(lit)) {
+ case l_true:
+ lits.push_back(lit);
+ break;
+ case l_false:
+ UNREACHABLE();
+ break;
+ case l_undef:
+ SASSERT(undef_lit == null_literal);
+ undef_lit = lit;
+ break;
+ }
+ }
+ TRACE("seq", tout << "propagate: " << undef_lit << "\n";);
+ SASSERT(undef_lit != null_literal);
+ propagate_lit(n.m_dep, lits.size(), lits.c_ptr(), ~undef_lit);
+ }
+ else if (num_undef_lits == 0 && n.m_lhs.empty()) {
+ literal_vector lits(n.m_lits);
+ lits.push_back(~mk_eq(n.m_l, n.m_r, false));
+ set_conflict(n.m_dep, lits);
+ SASSERT(m_new_propagation);
+ }
+ else if (false && num_undef_lits == 0 && n.m_lhs.size() == 1) {
+ expr* l = n.m_lhs[0];
+ expr* r = n.m_rhs[0];
+ if (m_util.str.is_empty(r)) {
+ std::swap(l, r);
+ }
+ if (m_util.str.is_empty(l) && is_var(r)) {
+ literal lit = ~mk_eq_empty(r);
+ switch (ctx.get_assignment(lit)) {
+ case l_true: {
+ expr_ref head(m), tail(m);
+ mk_decompose(r, head, tail);
+ expr_ref conc = mk_concat(head, tail);
+ propagate_is_conc(r, conc);
+ m_new_propagation = true;
+ break;
+ }
+ case l_undef:
+ m_new_propagation = true;
+ break;
+ case l_false:
+ break;
+ }
+ }
+ }
+}
+
+
+#if 0
+bool theory_seq::solve_ne2(unsigned idx) {
+ context& ctx = get_context();
+ ne2 const& n = m_nqs[idx];
+ TRACE("seq", display_disequation(tout, n););
+
+ unsigned num_undef_lits = 0;
+ for (unsigned i = 0; i < n.lits().size(); ++i) {
+ switch (ctx.get_assignment(n.lits(i))) {
+ case l_false:
+ return true;
+ case l_true:
+ break;
+ case l_undef:
+ ++num_undef_lits;
+ break;
+ }
+ }
+ unsigned_vector unchanged;
+ dependency* new_deps = 0;
+ vector new_ls, new_rs;
+ literal_vector new_lits = n.lits();
+ bool updated = false;
+ for (unsigned i = 0; i < n.ls().size(); ++i) {
+ expr_ref_vector& ls = m_ls;
+ expr_ref_vector& rs = m_rs;
+ expr_ref_vector& lhs = m_lhs;
+ expr_ref_vector& rhs = m_rhs;
+ ls.reset(); rs.reset(); lhs.reset(); rhs.reset();
+ dependency* deps = 0;
+ expr_ref_vector const& l = n.ls(i);
+ expr_ref_vector const& r = n.rs(i);
+ change = canonize(l, ls, deps) || change;
+ change = canonize(r, rs, deps) || change;
+ if (!m_seq_rewrite.reduce_eq(ls, rs, lhs, rhs)) {
+ return true;
+ }
+ else if (!change && lhs.empty()) {
+ unchanged.push_back(i);
+ }
+ else if (change && lhs.empty()) {
+
+ }
+ else {
+ updated = true;
+ TRACE("seq",
+ for (unsigned j = 0; j < lhs.size(); ++j) {
+ tout << mk_pp(lhs[j].get(), m) << " ";
+ }
+ tout << "\n";
+ tout << l << " != " << r << "\n";);
+
+ for (unsigned j = 0; j < lhs.size(); ++j) {
+ expr_ref nl(lhs[j].get(), m);
+ expr_ref nr(rhs[j].get(), m);
+ if (m_util.is_seq(nl) || m_util.is_re(nl)) {
+ new_ls.push_back(nl);
+ new_rs.push_back(nr);
+ }
+ else {
+ literal lit(mk_eq(nl, nr, false));
+ ctx.mark_as_relevant(lit);
+ new_lits.push_back(lit);
+ switch (ctx.get_assignment(lit)) {
+ case l_false:
+ return true;
+ case l_true:
+ break;
+ case l_undef:
+ ++num_undef_lits;
+ m_new_propagation = true;
+ break;
+ }
+ }
+ }
+ new_deps = deps;
+ }
+ }
+ if (num_undef_lits == 1 && new_ls.empty()) {
+ literal_vector lits;
+ literal undef_lit = null_literal;
+ for (unsigned i = 0; i < new_lits.size(); ++i) {
+ literal lit = new_lits[i];
+ switch (ctx.get_assignment(lit)) {
+ case l_true:
+ lits.push_back(lit);
+ break;
+ case l_false:
+ UNREACHABLE();
+ break;
+ case l_undef:
+ SASSERT(undef_lit == null_literal);
+ undef_lit = lit;
+ break;
+ }
+ }
+ TRACE("seq", tout << "propagate: " << undef_lit << "\n";);
+ SASSERT(undef_lit != null_literal);
+ propagate_lit(new_deps, lits.size(), lits.c_ptr(), ~undef_lit);
+ return true;
+ }
+ else if (num_undef_lits == 0 && new_ls.empty()) {
+ set_conflict(new_deps, new_lits);
+ SASSERT(m_new_propagation);
+ return true;
+ }
+ else if (change) {
+
}
return change;
}
-void theory_seq::internalize_eq_eh(app * atom, bool_var v) {
+#endif
+
+void theory_seq::mark_solved(unsigned idx) {
+ m_trail_stack.push(solved_ne(*this, idx));
}
-bool theory_seq::internalize_atom(app* a, bool) {
- return internalize_term(a);
+void theory_seq::erase_index(unsigned idx, unsigned i) {
+ ne const& n = m_nqs[idx];
+ unsigned sz = n.m_lhs.size();
+ if (i + 1 != sz) {
+ m_trail_stack.push(set_ne(*this, idx, i, n.m_lhs[sz-1], n.m_rhs[sz-1]));
+ }
+ m_trail_stack.push(pop_ne(*this, idx));
}
+bool theory_seq::simplify_and_solve_eqs() {
+ context & ctx = get_context();
+ m_new_propagation = false;
+ m_new_solution = true;
+ while (m_new_solution && !ctx.inconsistent()) {
+ m_new_solution = false;
+ solve_eqs(0);
+ }
+ return m_new_propagation || ctx.inconsistent();
+}
+
+
bool theory_seq::internalize_term(app* term) {
- TRACE("seq", tout << mk_pp(term, m) << "\n";);
context & ctx = get_context();
+ if (ctx.e_internalized(term)) {
+ enode* e = ctx.get_enode(term);
+ mk_var(e);
+ return true;
+ }
+ TRACE("seq", tout << mk_pp(term, m) << "\n";);
unsigned num_args = term->get_num_args();
+ expr* arg;
for (unsigned i = 0; i < num_args; i++) {
- expr* arg = term->get_arg(i);
+ arg = term->get_arg(i);
mk_var(ensure_enode(arg));
}
if (m.is_bool(term)) {
bool_var bv = ctx.mk_bool_var(term);
ctx.set_var_theory(bv, get_id());
+ ctx.mark_as_relevant(bv);
+ }
+
+ enode* e = 0;
+ if (ctx.e_internalized(term)) {
+ e = ctx.get_enode(term);
}
else {
- enode* e = 0;
- if (ctx.e_internalized(term)) {
- e = ctx.get_enode(term);
- }
- else {
- e = ctx.mk_enode(term, false, m.is_bool(term), true);
- }
- mk_var(e);
- }
- if (m_util.str.is_length(term) && !m_has_length) {
- m_trail_stack.push(value_trail(m_has_length));
- m_has_length = true;
- }
- if (!m_util.str.is_concat(term) &&
- !m_util.str.is_string(term) &&
- !m_util.str.is_empty(term) &&
- !m_util.str.is_unit(term) &&
- !m_util.str.is_suffix(term) &&
- !m_util.str.is_prefix(term) &&
- !m_util.str.is_contains(term) &&
- !m_util.is_skolem(term)) {
- set_incomplete(term);
- }
+ e = ctx.mk_enode(term, false, m.is_bool(term), true);
+ }
+ mk_var(e);
+
return true;
}
+void theory_seq::add_length(expr* e) {
+ SASSERT(!has_length(e));
+ m_length.insert(e);
+ m_trail_stack.push(insert_obj_trail(m_length, e));
+}
+
+/*
+ ensure that all elements in equivalence class occur under an applicatin of 'length'
+*/
+void theory_seq::enforce_length(enode* n) {
+ enode* n1 = n;
+ do {
+ expr* o = n->get_owner();
+ if (!has_length(o)) {
+ expr_ref len(m_util.str.mk_length(o), m);
+ enque_axiom(len);
+ add_length(o);
+ }
+ n = n->get_next();
+ }
+ while (n1 != n);
+}
+
void theory_seq::apply_sort_cnstr(enode* n, sort* s) {
mk_var(n);
}
void theory_seq::display(std::ostream & out) const {
if (m_eqs.size() == 0 &&
- m_ineqs.empty() &&
+ m_nqs.size() == 0 &&
m_rep.empty() &&
m_exclude.empty()) {
return;
@@ -630,10 +1275,16 @@ void theory_seq::display(std::ostream & out) const {
out << "Equations:\n";
display_equations(out);
}
- if (!m_ineqs.empty()) {
- out << "Negative constraints:\n";
- for (unsigned i = 0; i < m_ineqs.size(); ++i) {
- out << mk_pp(m_ineqs[i], m) << "\n";
+ if (m_nqs.size() > 0) {
+ display_disequations(out);
+ }
+ if (!m_re2aut.empty()) {
+ out << "Regex\n";
+ obj_map::iterator it = m_re2aut.begin(), end = m_re2aut.end();
+ for (; it != end; ++it) {
+ out << mk_pp(it->m_key, m) << "\n";
+ display_expr disp(m);
+ it->m_value->display(out, disp);
}
}
if (!m_rep.empty()) {
@@ -649,23 +1300,60 @@ void theory_seq::display(std::ostream & out) const {
void theory_seq::display_equations(std::ostream& out) const {
for (unsigned i = 0; i < m_eqs.size(); ++i) {
eq const& e = m_eqs[i];
- out << e.m_lhs << " = " << e.m_rhs << " <- ";
- display_deps(out, e.m_dep);
+ out << e.ls() << " = " << e.rs() << " <- ";
+ display_deps(out, e.dep());
}
}
-void theory_seq::display_deps(std::ostream& out, enode_pair_dependency* dep) const {
- vector _eqs;
- const_cast(m_dm).linearize(dep, _eqs);
- for (unsigned i = 0; i < _eqs.size(); ++i) {
- out << " " << mk_pp(_eqs[i].first->get_owner(), m) << " = " << mk_pp(_eqs[i].second->get_owner(), m);
+void theory_seq::display_disequations(std::ostream& out) const {
+ bool first = true;
+ for (unsigned i = 0; i < m_nqs.size(); ++i) {
+ if (!m_nqs[i].is_solved()) {
+ if (first) out << "Disequations:\n";
+ first = false;
+ display_disequation(out, m_nqs[i]);
+ }
+ }
+}
+
+void theory_seq::display_disequation(std::ostream& out, ne const& e) const {
+ for (unsigned j = 0; j < e.m_lits.size(); ++j) {
+ out << e.m_lits[j] << " ";
}
- out << "\n";
+ if (e.m_lits.size() > 0) {
+ out << "\n";
+ }
+ for (unsigned j = 0; j < e.m_lhs.size(); ++j) {
+ out << mk_pp(e.m_lhs[j], m) << " != " << mk_pp(e.m_rhs[j], m) << "\n";
+ }
+ if (e.m_dep) {
+ display_deps(out, e.m_dep);
+ }
+}
+
+void theory_seq::display_deps(std::ostream& out, dependency* dep) const {
+ literal_vector lits;
+ enode_pair_vector eqs;
+ linearize(dep, eqs, lits);
+ for (unsigned i = 0; i < eqs.size(); ++i) {
+ out << "\n " << mk_pp(eqs[i].first->get_owner(), m) << " = " << mk_pp(eqs[i].second->get_owner(), m);
+ }
+ for (unsigned i = 0; i < lits.size(); ++i) {
+ literal lit = lits[i];
+ get_context().display_literals_verbose(out << "\n ", 1, &lit);
+ }
+ out << "\n";
}
void theory_seq::collect_statistics(::statistics & st) const {
st.update("seq num splits", m_stats.m_num_splits);
st.update("seq num reductions", m_stats.m_num_reductions);
+ st.update("seq unfold def", m_stats.m_propagate_automata);
+ st.update("seq length coherence", m_stats.m_check_length_coherence);
+ st.update("seq branch", m_stats.m_branch_variable);
+ st.update("seq solve !=", m_stats.m_solve_nqs);
+ st.update("seq solve =", m_stats.m_solve_eqs);
+ st.update("seq add axiom", m_stats.m_add_axiom);
}
void theory_seq::init_model(model_generator & mg) {
@@ -673,26 +1361,148 @@ void theory_seq::init_model(model_generator & mg) {
mg.register_factory(m_factory);
}
+
+class seq_value_proc : public model_value_proc {
+ theory_seq& th;
+ app* n;
+ svector m_dependencies;
+public:
+ seq_value_proc(theory_seq& th, app* n): th(th), n(n) {
+ }
+ virtual ~seq_value_proc() {}
+ void add_dependency(enode* n) { m_dependencies.push_back(model_value_dependency(n)); }
+ virtual void get_dependencies(buffer & result) {
+ result.append(m_dependencies.size(), m_dependencies.c_ptr());
+ }
+ virtual app * mk_value(model_generator & mg, ptr_vector & values) {
+ SASSERT(values.size() == m_dependencies.size());
+ ast_manager& m = mg.get_manager();
+ if (values.empty()) {
+ return th.mk_value(n);
+ }
+ return th.mk_value(mg.get_manager().mk_app(n->get_decl(), values.size(), values.c_ptr()));
+ }
+};
+
+
model_value_proc * theory_seq::mk_value(enode * n, model_generator & mg) {
- enode_pair_dependency* deps = 0;
- expr_ref e(n->get_owner(), m);
- flet _model_completion(m_model_completion, true);
- e = canonize(e, deps);
- SASSERT(is_app(e));
- m_factory->add_trail(e);
- return alloc(expr_wrapper_proc, to_app(e));
+ context& ctx = get_context();
+ expr_ref e(m);
+ expr* e1;
+ ptr_vector concats;
+ get_concat(n->get_owner(), concats);
+ switch (concats.size()) {
+ case 0:
+ e = m_util.str.mk_empty(m.get_sort(n->get_owner()));
+ break;
+ case 1:
+ e = concats[0];
+ SASSERT(!m_util.str.is_concat(e));
+ break;
+ default:
+ e = m_rep.find(n->get_owner());
+ SASSERT(m_util.str.is_concat(e));
+ break;
+ }
+ seq_value_proc* sv = alloc(seq_value_proc, *this, to_app(e));
+ TRACE("seq", tout << mk_pp(n->get_owner(), m) << " ";
+ for (unsigned i = 0; i < concats.size(); ++i) {
+ tout << mk_pp(concats[i], m) << " ";
+ }
+ tout << "\n";
+ );
+
+ if (concats.size() > 1) {
+ for (unsigned i = 0; i < concats.size(); ++i) {
+ sv->add_dependency(ctx.get_enode(concats[i]));
+ }
+ }
+ else if (m_util.str.is_unit(e, e1)) {
+ sv->add_dependency(ctx.get_enode(e1));
+ }
+ return sv;
}
-
-
-void theory_seq::set_incomplete(app* term) {
- if (!m_incomplete) {
- TRACE("seq", tout << "Incomplete operator: " << mk_pp(term, m) << "\n";);
- m_trail_stack.push(value_trail(m_incomplete));
- m_incomplete = true;
- }
+void theory_seq::get_concat(expr* e, ptr_vector& concats) {
+ expr* e1, *e2;
+ while (true) {
+ e = m_rep.find(e);
+ if (m_util.str.is_concat(e, e1, e2)) {
+ get_concat(e1, concats);
+ e = e2;
+ continue;
+ }
+ if (!m_util.str.is_empty(e)) {
+ concats.push_back(e);
+ }
+ return;
+ }
}
+app* theory_seq::mk_value(app* e) {
+ expr* e1;
+ expr_ref result(e, m);
+ if (m_util.str.is_unit(e, e1)) {
+ dependency* deps = 0;
+ result = expand(e1, deps);
+ bv_util bv(m);
+ rational val;
+ unsigned sz;
+ if (bv.is_numeral(result, val, sz) && sz == zstring().num_bits()) {
+ unsigned v = val.get_unsigned();
+ if ((0 <= v && v < 7) || (14 <= v && v < 32) || v == 127) {
+ result = m_util.str.mk_unit(result);
+ }
+ else {
+ svector val_as_bits;
+ for (unsigned i = 0; i < sz; ++i) {
+ val_as_bits.push_back(1 == v % 2);
+ v = v / 2;
+ }
+ result = m_util.str.mk_string(zstring(sz, val_as_bits.c_ptr()));
+ }
+ }
+ else {
+ result = m_util.str.mk_unit(result);
+ }
+ }
+ else if (is_var(e)) {
+ SASSERT(m_factory);
+ expr_ref val(m);
+ val = m_factory->get_some_value(m.get_sort(e));
+ if (val) {
+ result = val;
+ }
+ else {
+ result = e;
+ }
+ }
+ else if (is_nth(e)) {
+ enode* n = get_context().get_enode(e)->get_root();
+ enode* n0 = n;
+ bool found_value = false;
+ do {
+ result = n->get_owner();
+ found_value = m.is_model_value(result);
+ }
+ while (n0 != n && !found_value);
+
+ if (!found_value) {
+ if (m_util.is_char(result)) {
+ result = m_util.str.mk_char('#');
+ }
+ else {
+ result = m_mg->get_some_value(m.get_sort(result));
+ }
+ }
+ }
+ m_rewrite(result);
+ m_factory->add_trail(result);
+ TRACE("seq", tout << mk_pp(e, m) << " -> " << result << "\n";);
+ return to_app(result);
+}
+
+
theory_var theory_seq::mk_var(enode* n) {
if (!m_util.is_seq(n->get_owner()) &&
!m_util.is_re(n->get_owner())) {
@@ -710,34 +1520,75 @@ theory_var theory_seq::mk_var(enode* n) {
}
bool theory_seq::can_propagate() {
- return m_axioms_head < m_axioms.size();
+ return m_axioms_head < m_axioms.size() || !m_replay.empty() || m_new_solution;
}
-expr_ref theory_seq::canonize(expr* e, enode_pair_dependency*& eqs) {
+expr_ref theory_seq::canonize(expr* e, dependency*& eqs) {
expr_ref result = expand(e, eqs);
m_rewrite(result);
return result;
}
-expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) {
- enode_pair_dependency* deps = 0;
- expr_dep ed;
- if (m_rep.find_cache(e, ed)) {
- eqs = m_dm.mk_join(eqs, ed.second);
- return expr_ref(ed.first, m);
- }
- e = m_rep.find(e, deps);
- expr_ref result(m);
+bool theory_seq::canonize(expr* e0, expr_ref_vector& es, dependency*& eqs) {
+ dependency* dep = 0;
+ expr* e = m_rep.find(e0, dep);
+ bool change = e != e0;
expr* e1, *e2;
if (m_util.str.is_concat(e, e1, e2)) {
- result = m_util.str.mk_concat(expand(e1, deps), expand(e2, deps));
+ change = canonize(e1, es, eqs) || change;
+ change = canonize(e2, es, eqs) || change;
+ }
+ else if (m_util.str.is_empty(e)) {
+ // skip
+ }
+ else {
+ expr_ref e3 = expand(e, eqs);
+ if (m_util.str.is_concat(e3) || m_util.str.is_empty(e3)) {
+ change = canonize(e3, es, eqs) || change;
+ }
+ else {
+ change = e3 != e || change;
+ es.push_back(e3);
+ }
+ }
+ eqs = m_dm.mk_join(eqs, dep);
+ return change;
+}
+
+bool theory_seq::canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs) {
+ dependency* dep = 0;
+ bool change = false;
+ for (unsigned i = 0; i < es.size(); ++i) {
+ expr_ref r = expand(es[i], eqs);
+ change |= r != es[i];
+ if (m_util.str.is_concat(r)) {
+ canonize(r, result, eqs);
+ }
+ else if (!m_util.str.is_empty(r)) {
+ result.push_back(r);
+ }
+ }
+ return change;
+}
+
+
+expr_ref theory_seq::expand(expr* e0, dependency*& eqs) {
+ expr_ref result(m);
+ dependency* deps = 0;
+ expr_dep ed;
+ if (m_rep.find_cache(e0, ed)) {
+ eqs = m_dm.mk_join(eqs, ed.second);
+ result = ed.first;
+ return result;
+ }
+ expr* e = m_rep.find(e0, deps);
+ expr* e1, *e2;
+ if (m_util.str.is_concat(e, e1, e2)) {
+ result = mk_concat(expand(e1, deps), expand(e2, deps));
}
else if (m_util.str.is_empty(e) || m_util.str.is_string(e)) {
result = e;
}
- else if (m.is_eq(e, e1, e2)) {
- result = m.mk_eq(expand(e1, deps), expand(e2, deps));
- }
else if (m_util.str.is_prefix(e, e1, e2)) {
result = m_util.str.mk_prefix(expand(e1, deps), expand(e2, deps));
}
@@ -747,30 +1598,23 @@ expr_ref theory_seq::expand(expr* e, enode_pair_dependency*& eqs) {
else if (m_util.str.is_contains(e, e1, e2)) {
result = m_util.str.mk_contains(expand(e1, deps), expand(e2, deps));
}
- else if (m_model_completion && is_var(e)) {
- SASSERT(m_factory);
- expr_ref val(m);
- val = m_factory->get_some_value(m.get_sort(e));
- if (val) {
- m_rep.update(e, val, 0);
- result = val;
- }
- else {
- result = e;
- }
- }
else {
result = e;
}
+ if (result == e0) {
+ deps = 0;
+ }
expr_dep edr(result, deps);
- m_rep.add_cache(e, edr);
+ m_rep.add_cache(e0, edr);
eqs = m_dm.mk_join(eqs, deps);
+ TRACE("seq_verbose", tout << mk_pp(e0, m) << " |--> " << result << "\n";
+ if (eqs) display_deps(tout, eqs););
return result;
}
-void theory_seq::add_dependency(enode_pair_dependency*& dep, enode* a, enode* b) {
+void theory_seq::add_dependency(dependency*& dep, enode* a, enode* b) {
if (a != b) {
- dep = m_dm.mk_join(dep, m_dm.mk_leaf(std::make_pair(a, b)));
+ dep = m_dm.mk_join(dep, m_dm.mk_leaf(assumption(a, b)));
}
}
@@ -783,18 +1627,34 @@ void theory_seq::propagate() {
deque_axiom(e);
++m_axioms_head;
}
+ while (!m_replay.empty() && !ctx.inconsistent()) {
+ (*m_replay[m_replay.size()-1])(*this);
+ TRACE("seq", tout << "replay: " << ctx.get_scope_level() << "\n";);
+ m_replay.pop_back();
+ }
+ if (m_new_solution) {
+ simplify_and_solve_eqs();
+ m_new_solution = false;
+ }
}
void theory_seq::enque_axiom(expr* e) {
TRACE("seq", tout << "add axioms for: " << mk_pp(e, m) << "\n";);
- m_trail_stack.push(push_back_vector(m_axioms));
- m_axioms.push_back(e);
+ if (!m_axiom_set.contains(e)) {
+ m_axioms.push_back(e);
+ m_axiom_set.insert(e);
+ m_trail_stack.push(push_back_vector(m_axioms));
+ m_trail_stack.push(insert_obj_trail(m_axiom_set, e));;
+ }
}
void theory_seq::deque_axiom(expr* n) {
if (m_util.str.is_length(n)) {
add_length_axiom(n);
}
+ else if (m_util.str.is_empty(n) && !has_length(n) && !m_length.empty()) {
+ enforce_length(get_context().get_enode(n));
+ }
else if (m_util.str.is_index(n)) {
add_indexof_axiom(n);
}
@@ -807,18 +1667,8 @@ void theory_seq::deque_axiom(expr* n) {
else if (m_util.str.is_at(n)) {
add_at_axiom(n);
}
- else if (m_util.str.is_unit(n)) {
- add_length_unit_axiom(n);
- }
- else if (m_util.str.is_empty(n)) {
- add_length_empty_axiom(n);
- }
- else if (m_util.str.is_concat(n)) {
- add_length_concat_axiom(n);
- }
else if (m_util.str.is_string(n)) {
add_elim_string_axiom(n);
- // add_length_string_axiom(n);
}
}
@@ -827,96 +1677,90 @@ void theory_seq::deque_axiom(expr* n) {
encode that s is not a proper prefix of xs1
where s1 is all of s, except the last element.
- lit or s = "" or s = s1*c
- lit or s = "" or len(c) = 1
+ lit or s = "" or s = s1*(unit c)
lit or s = "" or !prefix(s, x*s1)
*/
void theory_seq::tightest_prefix(expr* s, expr* x, literal lit1, literal lit2) {
- expr_ref s1 = mk_skolem(symbol("seq.first"), s);
- expr_ref c = mk_skolem(symbol("seq.last"), s);
- expr_ref s1c(m_util.str.mk_concat(s1, c), m);
- expr_ref lc(m_util.str.mk_length(c), m);
- expr_ref one(m_autil.mk_int(1), m);
- expr_ref emp(m_util.str.mk_empty(m.get_sort(s)), m);
- literal s_eq_emp = mk_eq(s, emp, false);
+ expr_ref s1 = mk_skolem(m_seq_first, s);
+ expr_ref c = mk_last(s);
+ expr_ref s1c = mk_concat(s1, m_util.str.mk_unit(c));
+ literal s_eq_emp = mk_eq_empty(s);
add_axiom(lit1, lit2, s_eq_emp, mk_eq(s, s1c, false));
- add_axiom(lit1, lit2, s_eq_emp, mk_eq(lc, one, false));
- add_axiom(lit1, lit2, s_eq_emp, ~mk_literal(m_util.str.mk_contains(s, m_util.str.mk_concat(x, s1))));
+ add_axiom(lit1, lit2, s_eq_emp, ~mk_literal(m_util.str.mk_prefix(s, mk_concat(x, s1))));
}
/*
// index of s in t starting at offset.
- let i = Index(t, s, 0):
+ let i = Index(t, s, offset):
- len(t) = 0 => i = -1
+ offset >= len(t) => i = -1
+
+ offset fixed to 0:
+
len(t) != 0 & !contains(t, s) => i = -1
len(t) != 0 & contains(t, s) => t = xsy & i = len(x)
len(t) != 0 & contains(t, s) & s != emp => tightest_prefix(x, s)
- let i = Index(t, s, offset)
+ offset not fixed:
-
- 0 <= offset < len(t) => xy = t & len(x) = offset & (-1 = indexof(t, s, 0) => -1 = i)
- & (indexof(t, s, 0) >= 0 => indexof(t, s, 0) + offset = i)
-
-
- offset = len(t) => i = -1
-
- if offset < 0 or offset >= len(t)
+ 0 <= offset < len(t) => xy = t &
+ len(x) = offset &
+ (-1 = indexof(y, s, 0) => -1 = i) &
+ (indexof(y, s, 0) >= 0 => indexof(t, s, 0) + offset = i)
+
+ if offset < 0
under specified
optional lemmas:
- (len(s) > len(t) -> i = -1)
- (len(s) <= len(t) -> i <= len(t)-len(s))
+ (len(s) > len(t) -> i = -1)
+ (len(s) <= len(t) -> i <= len(t)-len(s))
*/
void theory_seq::add_indexof_axiom(expr* i) {
expr* s, *t, *offset;
rational r;
VERIFY(m_util.str.is_index(i, t, s, offset));
- expr_ref emp(m), minus_one(m), zero(m), xsy(m);
- minus_one = m_autil.mk_int(-1);
- zero = m_autil.mk_int(0);
- emp = m_util.str.mk_empty(m.get_sort(s));
- literal offset_ne_zero = null_literal;
- bool is_num = m_autil.is_numeral(offset, r);
- if (is_num && r.is_zero()) {
- offset_ne_zero = null_literal;
- }
- else {
- offset_ne_zero = ~mk_eq(offset, zero, false);
- }
- if (!is_num || r.is_zero()) {
- expr_ref x = mk_skolem(m_contains_left_sym, t, s);
- expr_ref y = mk_skolem(m_contains_right_sym, t, s);
- xsy = m_util.str.mk_concat(x,s,y);
- literal cnt = mk_literal(m_util.str.mk_contains(t, s));
- literal eq_empty = mk_eq(s, emp, false);
- add_axiom(offset_ne_zero, cnt, mk_eq(i, minus_one, false));
- add_axiom(offset_ne_zero, ~eq_empty, mk_eq(i, zero, false));
- add_axiom(offset_ne_zero, ~cnt, eq_empty, mk_eq(t, xsy, false));
- tightest_prefix(s, x, ~cnt, offset_ne_zero);
- }
- if (is_num && r.is_zero()) {
- return;
- }
+ expr_ref minus_one(m_autil.mk_int(-1), m);
+ expr_ref zero(m_autil.mk_int(0), m);
+ expr_ref xsy(m);
+
// offset >= len(t) => indexof(s, t, offset) = -1
expr_ref len_t(m_util.str.mk_length(t), m);
literal offset_ge_len = mk_literal(m_autil.mk_ge(mk_sub(offset, len_t), zero));
add_axiom(offset_ge_len, mk_eq(i, minus_one, false));
- // 0 <= offset & offset < len(t) => t = xy
- // 0 <= offset & offset < len(t) => len(x) = offset
- // 0 <= offset & offset < len(t) & ~contains(s, y) => indexof(t, s, offset) = -1
- // 0 <= offset & offset < len(t) & contains(s, y) => index(t, s, offset) = indexof(y, s, 0) + len(t)
- expr_ref x = mk_skolem(symbol("seq.indexof.left"), t, s, offset);
- expr_ref y = mk_skolem(symbol("seq.indexof.right"), t, s, offset);
- expr_ref indexof(m_util.str.mk_index(y, s, zero), m);
- // TBD:
- //literal offset_ge_0 = mk_literal(m_autil.mk_ge(offset, zero));
- //add_axiom(~offset_ge_0, offset_ge_len, mk_eq(indexof, i, false));
- //add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false));
- //add_axiom(~offset_ge_0, offset_ge_len, mk_eq(t, m_util.str.mk_concat(x, y), false));
+ if (m_autil.is_numeral(offset, r) && r.is_zero()) {
+ expr_ref x = mk_skolem(m_contains_left, t, s);
+ expr_ref y = mk_skolem(m_contains_right, t, s);
+ xsy = mk_concat(x,s,y);
+ literal cnt = mk_literal(m_util.str.mk_contains(t, s));
+ literal eq_empty = mk_eq_empty(s);
+ add_axiom(cnt, mk_eq(i, minus_one, false));
+ add_axiom(~eq_empty, mk_eq(i, zero, false));
+ add_axiom(~cnt, eq_empty, mk_eq(t, xsy, false));
+ tightest_prefix(s, x, ~cnt);
+ }
+ else {
+ expr_ref x = mk_skolem(m_indexof_left, t, s, offset);
+ expr_ref y = mk_skolem(m_indexof_right, t, s, offset);
+ expr_ref indexof0(m_util.str.mk_index(y, s, zero), m);
+ expr_ref offset_p_indexof0(m_autil.mk_add(offset, indexof0), m);
+ literal offset_ge_0 = mk_literal(m_autil.mk_ge(offset, zero));
+
+ // 0 <= offset & offset < len(t) => t = xy
+ // 0 <= offset & offset < len(t) => len(x) = offset
+ // 0 <= offset & offset < len(t) & -1 = indexof(y,s,0) = -1 => -1 = i
+ // 0 <= offset & offset < len(t) & indexof(y,s,0) >= 0 = -1 =>
+ // -1 = indexof(y,s,0) + offset = indexof(t, s, offset)
+
+ add_axiom(~offset_ge_0, offset_ge_len, mk_eq(t, mk_concat(x, y), false));
+ add_axiom(~offset_ge_0, offset_ge_len, mk_eq(m_util.str.mk_length(x), offset, false));
+ add_axiom(~offset_ge_0, offset_ge_len,
+ ~mk_eq(indexof0, minus_one, false), mk_eq(i, minus_one, false));
+ add_axiom(~offset_ge_0, offset_ge_len,
+ ~mk_literal(m_autil.mk_ge(indexof0, zero)),
+ mk_eq(offset_p_indexof0, i, false));
+ }
}
/*
@@ -930,10 +1774,10 @@ void theory_seq::add_indexof_axiom(expr* i) {
void theory_seq::add_replace_axiom(expr* r) {
expr* a, *s, *t;
VERIFY(m_util.str.is_replace(r, a, s, t));
- expr_ref x = mk_skolem(m_contains_left_sym, a, s);
- expr_ref y = mk_skolem(m_contains_right_sym, a, s);
- expr_ref xty(m_util.str.mk_concat(x, t, y), m);
- expr_ref xsy(m_util.str.mk_concat(x, s, y), m);
+ expr_ref x = mk_skolem(m_contains_left, a, s);
+ expr_ref y = mk_skolem(m_contains_right, a, s);
+ expr_ref xty = mk_concat(x, t, y);
+ expr_ref xsy = mk_concat(x, s, y);
literal cnt = mk_literal(m_util.str.mk_contains(a ,s));
add_axiom(cnt, mk_eq(r, a, false));
add_axiom(~cnt, mk_eq(a, xsy, false));
@@ -941,87 +1785,207 @@ void theory_seq::add_replace_axiom(expr* r) {
tightest_prefix(s, x, ~cnt);
}
-void theory_seq::add_length_unit_axiom(expr* n) {
- if (!m_has_length) return;
- SASSERT(m_util.str.is_unit(n));
- expr_ref one(m_autil.mk_int(1), m), len(m_util.str.mk_length(n), m);
- add_axiom(mk_eq(len, one, false));
-}
-
-void theory_seq::add_length_empty_axiom(expr* n) {
- if (!m_has_length) return;
- SASSERT(m_util.str.is_empty(n));
- expr_ref zero(m_autil.mk_int(0), m), len(m_util.str.mk_length(n), m);
- add_axiom(mk_eq(len, zero, false));
-}
-
void theory_seq::add_elim_string_axiom(expr* n) {
zstring s;
VERIFY(m_util.str.is_string(n, s));
- SASSERT(s.length() > 0);
- expr_ref result(m_util.str.mk_unit(m_util.str.mk_char(s, 0)), m);
- for (unsigned i = 1; i < s.length(); ++i) {
- result = m_util.str.mk_concat(result, m_util.str.mk_unit(m_util.str.mk_char(s, i)));
+ if (s.length() == 0) {
+ return;
+ }
+ expr_ref result(m_util.str.mk_unit(m_util.str.mk_char(s, s.length()-1)), m);
+ for (unsigned i = s.length()-1; i > 0; ) {
+ --i;
+ result = mk_concat(m_util.str.mk_unit(m_util.str.mk_char(s, i)), result);
}
add_axiom(mk_eq(n, result, false));
m_rep.update(n, result, 0);
+ m_new_solution = true;
}
-void theory_seq::add_length_string_axiom(expr* n) {
- if (!m_has_length) return;
- zstring s;
- VERIFY(m_util.str.is_string(n, s));
- expr_ref len(m_util.str.mk_length(n), m);
- expr_ref ls(m_autil.mk_numeral(rational(s.length(), rational::ui64()), true), m);
- add_axiom(mk_eq(len, ls, false));
-}
-
-void theory_seq::add_length_concat_axiom(expr* n) {
- if (!m_has_length) return;
- expr* a, *b;
- VERIFY(m_util.str.is_concat(n, a, b));
- expr_ref len(m_util.str.mk_length(n), m);
- expr_ref _a(m_util.str.mk_length(a), m);
- expr_ref _b(m_util.str.mk_length(b), m);
- expr_ref a_p_b(m_autil.mk_add(_a, _b), m);
- add_axiom(mk_eq(len, a_p_b, false));
-}
/*
let n = len(x)
-
- len(x) >= 0
- len(x) = 0 => x = ""
- x = "" => len(x) = 0
+ - len(a ++ b) = len(a) + len(b) if x = a ++ b
+ - len(unit(u)) = 1 if x = unit(u)
+ - len(str) = str.length() if x = str
+ - len(empty) = 0 if x = empty
+ - len(x) >= 0 otherwise
*/
void theory_seq::add_length_axiom(expr* n) {
expr* x;
VERIFY(m_util.str.is_length(n, x));
- if (!m_util.str.is_unit(x) &&
- !m_util.str.is_empty(x) &&
- !m_util.str.is_string(x) &&
- !m_util.str.is_concat(x)) {
- expr_ref zero(m_autil.mk_int(0), m);
- expr_ref emp(m_util.str.mk_empty(m.get_sort(x)), m);
- literal eq1(mk_eq(zero, n, false));
- literal eq2(mk_eq(x, emp, false));
- add_axiom(mk_literal(m_autil.mk_ge(n, zero)));
- add_axiom(~eq1, eq2);
- add_axiom(~eq2, eq1);
+ if (m_util.str.is_concat(x) ||
+ m_util.str.is_unit(x) ||
+ m_util.str.is_empty(x) ||
+ m_util.str.is_string(x)) {
+ expr_ref len(n, m);
+ m_rewrite(len);
+ SASSERT(n != len);
+ add_axiom(mk_eq(len, n, false));
+
+ m_trail_stack.push(push_replay(alloc(replay_axiom, m, n)));
+ }
+ else {
+ add_axiom(mk_literal(m_autil.mk_ge(n, m_autil.mk_int(0))));
+ m_trail_stack.push(push_replay(alloc(replay_axiom, m, n)));
}
}
-expr* theory_seq::mk_sub(expr* a, expr* b) {
- return m_autil.mk_add(a, m_autil.mk_mul(m_autil.mk_int(-1), b));
+
+
+void theory_seq::propagate_in_re(expr* n, bool is_true) {
+ TRACE("seq", tout << mk_pp(n, m) << " <- " << (is_true?"true":"false") << "\n";);
+ expr* e1, *e2;
+ VERIFY(m_util.str.is_in_re(n, e1, e2));
+
+ expr_ref tmp(n, m);
+ m_rewrite(tmp);
+ if (m.is_true(tmp)) {
+ if (!is_true) {
+ literal_vector lits;
+ lits.push_back(mk_literal(n));
+ set_conflict(0, lits);
+ }
+ return;
+ }
+ else if (m.is_false(tmp)) {
+ if (is_true) {
+ literal_vector lits;
+ lits.push_back(~mk_literal(n));
+ set_conflict(0, lits);
+ }
+ return;
+ }
+
+ eautomaton* a = get_automaton(e2);
+ if (!a) return;
+
+ context& ctx = get_context();
+
+ expr_ref len(m_util.str.mk_length(e1), m);
+ for (unsigned i = 0; i < a->num_states(); ++i) {
+ literal acc = mk_accept(e1, len, e2, i);
+ literal rej = mk_reject(e1, len, e2, i);
+ add_axiom(a->is_final_state(i)?acc:~acc);
+ add_axiom(a->is_final_state(i)?~rej:rej);
+ }
+
+ expr_ref zero(m_autil.mk_int(0), m);
+ unsigned_vector states;
+ a->get_epsilon_closure(a->init(), states);
+ literal_vector lits;
+ literal lit = ctx.get_literal(n);
+ if (is_true) {
+ lits.push_back(~lit);
+ }
+ for (unsigned i = 0; i < states.size(); ++i) {
+ if (is_true) {
+ lits.push_back(mk_accept(e1, zero, e2, states[i]));
+ }
+ else {
+ literal nlit = ~lit;
+ propagate_lit(0, 1, &nlit, mk_reject(e1, zero, e2, states[i]));
+ }
+ }
+ if (is_true) {
+ if (lits.size() == 2) {
+ propagate_lit(0, 1, &lit, lits[1]);
+ }
+ else {
+ TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";);
+ ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
+ }
+ }
+}
+
+
+expr_ref theory_seq::mk_sub(expr* a, expr* b) {
+ expr_ref result(m_autil.mk_sub(a, b), m);
+ m_rewrite(result);
+ return result;
}
enode* theory_seq::ensure_enode(expr* e) {
context& ctx = get_context();
if (!ctx.e_internalized(e)) {
ctx.internalize(e, false);
- ctx.mark_as_relevant(ctx.get_enode(e));
}
- return ctx.get_enode(e);
+ enode* n = ctx.get_enode(e);
+ ctx.mark_as_relevant(n);
+ return n;
+}
+
+static theory_mi_arith* get_th_arith(context& ctx, theory_id afid, expr* e) {
+ ast_manager& m = ctx.get_manager();
+ theory* th = ctx.get_theory(afid);
+ if (th && ctx.e_internalized(e)) {
+ return dynamic_cast(th);
+ }
+ else {
+ return 0;
+ }
+}
+
+bool theory_seq::lower_bound(expr* _e, rational& lo) {
+ context& ctx = get_context();
+ expr_ref e(m_util.str.mk_length(_e), m);
+ theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e);
+ expr_ref _lo(m);
+ if (!tha || !tha->get_lower(ctx.get_enode(e), _lo)) return false;
+ return m_autil.is_numeral(_lo, lo) && lo.is_int();
+}
+
+bool theory_seq::upper_bound(expr* _e, rational& hi) {
+ context& ctx = get_context();
+ expr_ref e(m_util.str.mk_length(_e), m);
+ theory_mi_arith* tha = get_th_arith(ctx, m_autil.get_family_id(), e);
+ expr_ref _hi(m);
+ if (!tha || !tha->get_upper(ctx.get_enode(e), _hi)) return false;
+ return m_autil.is_numeral(_hi, hi) && hi.is_int();
+}
+
+bool theory_seq::get_length(expr* e, rational& val) {
+ context& ctx = get_context();
+ theory* th = ctx.get_theory(m_autil.get_family_id());
+ if (!th) return false;
+ theory_mi_arith* tha = dynamic_cast(th);
+ if (!tha) return false;
+ rational val1;
+ expr_ref len(m), len_val(m);
+ expr* e1, *e2;
+ ptr_vector todo;
+ todo.push_back(e);
+ val.reset();
+ zstring s;
+ while (!todo.empty()) {
+ expr* c = todo.back();
+ todo.pop_back();
+ if (m_util.str.is_concat(c, e1, e2)) {
+ todo.push_back(e1);
+ todo.push_back(e2);
+ }
+ else if (m_util.str.is_unit(c)) {
+ val += rational(1);
+ }
+ else if (m_util.str.is_empty(c)) {
+ continue;
+ }
+ else if (m_util.str.is_string(c, s)) {
+ val += rational(s.length());
+ }
+ else {
+ len = m_util.str.mk_length(c);
+ if (ctx.e_internalized(len) &&
+ tha->get_value(ctx.get_enode(len), len_val) &&
+ m_autil.is_numeral(len_val, val1)) {
+ val += val1;
+ }
+ else {
+ TRACE("seq", tout << "No length provided for " << len << "\n";);
+ return false;
+ }
+ }
+ }
+ return val.is_int();
}
/*
@@ -1040,12 +2004,12 @@ enode* theory_seq::ensure_enode(expr* e) {
void theory_seq::add_extract_axiom(expr* e) {
expr* s, *i, *l;
VERIFY(m_util.str.is_extract(e, s, i, l));
- expr_ref x(mk_skolem(symbol("seq.extract.prefix"), s, e), m);
+ expr_ref x(mk_skolem(m_extract_prefix, s, e), m);
expr_ref ls(m_util.str.mk_length(s), m);
expr_ref lx(m_util.str.mk_length(x), m);
expr_ref le(m_util.str.mk_length(e), m);
expr_ref ls_minus_i(mk_sub(ls, i), m);
- expr_ref xe(m_util.str.mk_concat(x, e), m);
+ expr_ref xe = mk_concat(x, e);
expr_ref zero(m_autil.mk_int(0), m);
literal i_ge_0 = mk_literal(m_autil.mk_ge(i, zero));
@@ -1069,9 +2033,9 @@ void theory_seq::add_at_axiom(expr* e) {
expr* s, *i;
VERIFY(m_util.str.is_at(e, s, i));
expr_ref x(m), y(m), lx(m), le(m), xey(m), zero(m), one(m), len_e(m), len_x(m);
- x = mk_skolem(symbol("seq.at.left"), s);
- y = mk_skolem(symbol("seq.at.right"), s);
- xey = m_util.str.mk_concat(x, e, y);
+ x = mk_skolem(m_at_left, s);
+ y = mk_skolem(m_at_right, s);
+ xey = mk_concat(x, e, y);
zero = m_autil.mk_int(0);
one = m_autil.mk_int(1);
len_e = m_util.str.mk_length(e);
@@ -1085,6 +2049,53 @@ void theory_seq::add_at_axiom(expr* e) {
add_axiom(~i_ge_0, i_ge_len_s, mk_eq(i, len_x, false));
}
+/**
+ step(s, idx, re, i, j, t) -> nth(s, idx) == t & len(s) > idx
+*/
+void theory_seq::propagate_step(literal lit, expr* step) {
+ context& ctx = get_context();
+ SASSERT(ctx.get_assignment(lit) == l_true);
+ expr* re, *t, *s, *idx, *i, *j;
+ VERIFY(is_step(step, s, idx, re, i, j, t));
+ expr_ref nth = mk_nth(s, idx);
+ TRACE("seq", tout << mk_pp(step, m) << " -> " << mk_pp(t, m) << " = " << nth << "\n";);
+ propagate_eq(lit, t, nth);
+ rational lo;
+ rational _idx;
+ if (lower_bound(s, lo) && lo.is_unsigned() && m_autil.is_numeral(idx, _idx) && lo >= _idx) {
+ // skip
+ }
+ else {
+ propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx)));
+ }
+ ensure_nth(lit, s, idx);
+}
+
+/*
+ lit => s = (nth s 0) ++ (nth s 1) ++ ... ++ (nth s idx) ++ (tail s idx)
+*/
+void theory_seq::ensure_nth(literal lit, expr* s, expr* idx) {
+ context& ctx = get_context();
+ rational r;
+ SASSERT(ctx.get_assignment(lit) == l_true);
+ VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned());
+ unsigned _idx = r.get_unsigned();
+ expr_ref head(m), tail(m), conc(m), len1(m), len2(m);
+ expr_ref_vector elems(m);
+
+ expr* s2 = s;
+ for (unsigned j = 0; j <= _idx; ++j) {
+ mk_decompose(s2, head, tail);
+ elems.push_back(head);
+ len1 = m_util.str.mk_length(s2);
+ len2 = m_autil.mk_add(m_autil.mk_int(1), m_util.str.mk_length(tail));
+ propagate_eq(lit, len1, len2, false);
+ s2 = tail;
+ }
+ elems.push_back(s2);
+ conc = mk_concat(elems);
+ propagate_eq(lit, s, conc, true);
+}
literal theory_seq::mk_literal(expr* _e) {
expr_ref e(_e, m);
@@ -1093,6 +2104,20 @@ literal theory_seq::mk_literal(expr* _e) {
return ctx.get_literal(e);
}
+literal theory_seq::mk_equals(expr* a, expr* b) {
+ literal lit = mk_eq(a, b, false);
+ get_context().force_phase(lit);
+ return lit;
+}
+
+literal theory_seq::mk_eq_empty(expr* _e) {
+ expr_ref e(_e, m);
+ SASSERT(m_util.is_seq(e));
+ expr_ref emp(m);
+ emp = m_util.str.mk_empty(m.get_sort(e));
+ return mk_equals(e, emp);
+}
+
void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4) {
context& ctx = get_context();
literal_vector lits;
@@ -1100,7 +2125,9 @@ void theory_seq::add_axiom(literal l1, literal l2, literal l3, literal l4) {
if (l2 != null_literal) { ctx.mark_as_relevant(l2); lits.push_back(l2); }
if (l3 != null_literal) { ctx.mark_as_relevant(l3); lits.push_back(l3); }
if (l4 != null_literal) { ctx.mark_as_relevant(l4); lits.push_back(l4); }
- TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";);
+ TRACE("seq", ctx.display_literals_verbose(tout << "axiom: ", lits.size(), lits.c_ptr()); tout << "\n";);
+ m_new_propagation = true;
+ ++m_stats.m_add_axiom;
ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
}
@@ -1115,81 +2142,166 @@ expr_ref theory_seq::mk_skolem(symbol const& name, expr* e1,
return expr_ref(m_util.mk_skolem(name, len, es, range), m);
}
-void theory_seq::propagate_eq(bool_var v, expr* e1, expr* e2) {
- context& ctx = get_context();
- TRACE("seq",
- tout << mk_pp(ctx.bool_var2enode(v)->get_owner(), m) << " => "
- << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";);
+bool theory_seq::is_skolem(symbol const& s, expr* e) const {
+ return m_util.is_skolem(e) && to_app(e)->get_decl()->get_parameter(0).get_symbol() == s;
+}
+
+
+void theory_seq::propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs) {
+ context& ctx = get_context();
- SASSERT(ctx.e_internalized(e2));
enode* n1 = ensure_enode(e1);
enode* n2 = ensure_enode(e2);
- literal lit(v);
+ if (n1->get_root() == n2->get_root()) {
+ return;
+ }
+ ctx.mark_as_relevant(n1);
+ ctx.mark_as_relevant(n2);
+ if (add_to_eqs) {
+ SASSERT(l_true == ctx.get_assignment(lit));
+ dependency* deps = m_dm.mk_leaf(assumption(lit));
+ new_eq_eh(deps, n1, n2);
+
+ }
+ TRACE("seq",
+ tout << mk_pp(ctx.bool_var2expr(lit.var()), m) << " => "
+ << mk_pp(e1, m) << " = " << mk_pp(e2, m) << "\n";);
justification* js =
ctx.mk_justification(
ext_theory_eq_propagation_justification(
get_id(), ctx.get_region(), 1, &lit, 0, 0, n1, n2));
+ m_new_propagation = true;
ctx.assign_eq(n1, n2, eq_justification(js));
}
-void theory_seq::assign_eq(bool_var v, bool is_true) {
+
+void theory_seq::assign_eh(bool_var v, bool is_true) {
context & ctx = get_context();
- enode* n = ctx.bool_var2enode(v);
- app* e = n->get_owner();
- if (is_true) {
- expr* e1, *e2;
- expr_ref f(m);
- if (m_util.str.is_prefix(e, e1, e2)) {
- f = mk_skolem(m_prefix_sym, e1, e2);
- f = m_util.str.mk_concat(e1, f);
- propagate_eq(v, f, e2);
- }
- else if (m_util.str.is_suffix(e, e1, e2)) {
- f = mk_skolem(m_suffix_sym, e1, e2);
- f = m_util.str.mk_concat(f, e1);
- propagate_eq(v, f, e2);
- }
- else if (m_util.str.is_contains(e, e1, e2)) {
- expr_ref f1 = mk_skolem(m_contains_left_sym, e1, e2);
- expr_ref f2 = mk_skolem(m_contains_right_sym, e1, e2);
- f = m_util.str.mk_concat(m_util.str.mk_concat(f1, e2), f2);
- propagate_eq(v, f, e1);
- }
- else if (m_util.str.is_in_re(e, e1, e2)) {
- // TBD
+ expr* e = ctx.bool_var2expr(v);
+ expr* e1, *e2;
+ expr_ref f(m);
+ literal lit(v, !is_true);
+
+ if (m_util.str.is_prefix(e, e1, e2)) {
+ if (is_true) {
+ f = mk_skolem(m_prefix, e1, e2);
+ f = mk_concat(e1, f);
+ propagate_eq(lit, f, e2, true);
}
else {
- UNREACHABLE();
+ // !prefix(e1,e2) => e1 != ""
+ propagate_non_empty(lit, e1);
+ if (add_prefix2prefix(e)) {
+ add_atom(e);
+ }
}
}
- else {
- m_trail_stack.push(push_back_vector(m_ineqs));
- m_ineqs.push_back(e);
+ else if (m_util.str.is_suffix(e, e1, e2)) {
+ if (is_true) {
+ f = mk_skolem(m_suffix, e1, e2);
+ f = mk_concat(f, e1);
+ propagate_eq(lit, f, e2, true);
+ }
+ else {
+ // lit => e1 != empty
+ propagate_non_empty(lit, e1);
+
+ // lit => e1 = first ++ (unit last)
+ expr_ref f1 = mk_skolem(m_seq_first, e1);
+ expr_ref f2 = mk_last(e1);
+ f = mk_concat(f1, m_util.str.mk_unit(f2));
+ propagate_eq(lit, e1, f, true);
+
+ if (add_suffix2suffix(e)) {
+ add_atom(e);
+ }
+ }
}
+ else if (m_util.str.is_contains(e, e1, e2)) {
+ if (is_true) {
+ expr_ref f1 = mk_skolem(m_contains_left, e1, e2);
+ expr_ref f2 = mk_skolem(m_contains_right, e1, e2);
+ f = mk_concat(f1, e2, f2);
+ propagate_eq(lit, f, e1, true);
+ }
+ else if (!canonizes(false, e)) {
+ propagate_non_empty(lit, e2);
+ propagate_lit(0, 1, &lit, ~mk_literal(m_util.str.mk_prefix(e2, e1)));
+ if (add_contains2contains(e)) {
+ add_atom(e);
+ }
+ }
+ }
+ else if (is_accept(e)) {
+ if (is_true) {
+ propagate_acc_rej_length(lit, e);
+ if (add_accept2step(e)) {
+ add_atom(e);
+ }
+ }
+ }
+ else if (is_reject(e)) {
+ if (is_true) {
+ propagate_acc_rej_length(lit, e);
+ add_atom(e);
+ }
+ }
+ else if (is_step(e)) {
+ if (is_true) {
+ propagate_step(lit, e);
+ if (add_step2accept(e)) {
+ add_atom(e);
+ }
+ }
+ }
+ else if (m_util.str.is_in_re(e)) {
+ propagate_in_re(e, is_true);
+ }
+ else {
+ UNREACHABLE();
+ }
+}
+
+void theory_seq::add_atom(expr* e) {
+ m_trail_stack.push(push_back_vector >(m_atoms));
+ m_atoms.push_back(e);
}
void theory_seq::new_eq_eh(theory_var v1, theory_var v2) {
enode* n1 = get_enode(v1);
enode* n2 = get_enode(v2);
- if (n1 != n2) {
+ dependency* deps = m_dm.mk_leaf(assumption(n1, n2));
+ new_eq_eh(deps, n1, n2);
+}
+
+void theory_seq::new_eq_eh(dependency* deps, enode* n1, enode* n2) {
+ if (n1 != n2 && m_util.is_seq(n1->get_owner())) {
expr_ref o1(n1->get_owner(), m);
expr_ref o2(n2->get_owner(), m);
TRACE("seq", tout << o1 << " = " << o2 << "\n";);
- m_eqs.push_back(eq(o1, o2, m_dm.mk_leaf(enode_pair(n1, n2))));
+ m_eqs.push_back(mk_eqdep(o1, o2, deps));
+ solve_eqs(m_eqs.size()-1);
+ enforce_length_coherence(n1, n2);
}
}
void theory_seq::new_diseq_eh(theory_var v1, theory_var v2) {
- expr* e1 = get_enode(v1)->get_owner();
- expr* e2 = get_enode(v2)->get_owner();
- m_trail_stack.push(push_back_vector(m_ineqs));
- m_ineqs.push_back(mk_eq_atom(e1, e2));
+ enode* n1 = get_enode(v1);
+ enode* n2 = get_enode(v2);
+ expr_ref e1(n1->get_owner(), m);
+ expr_ref e2(n2->get_owner(), m);
m_exclude.update(e1, e2);
+ expr_ref eq(m.mk_eq(e1, e2), m);
+ m_rewrite(eq);
+ if (!m.is_false(eq)) {
+ m_nqs.push_back(ne(e1, e2));
+ solve_nqs(m_nqs.size() - 1);
+ }
+ // add solution for variable that is non-empty?
}
void theory_seq::push_scope_eh() {
- TRACE("seq", tout << "push " << m_eqs.size() << "\n";);
theory::push_scope_eh();
m_rep.push_scope();
m_exclude.push_scope();
@@ -1197,31 +2309,504 @@ void theory_seq::push_scope_eh() {
m_trail_stack.push_scope();
m_trail_stack.push(value_trail(m_axioms_head));
m_eqs.push_scope();
+ m_nqs.push_scope();
+ m_atoms_lim.push_back(m_atoms.size());
}
void theory_seq::pop_scope_eh(unsigned num_scopes) {
- TRACE("seq", tout << "pop " << m_eqs.size() << "\n";);
m_trail_stack.pop_scope(num_scopes);
theory::pop_scope_eh(num_scopes);
m_dm.pop_scope(num_scopes);
m_rep.pop_scope(num_scopes);
m_exclude.pop_scope(num_scopes);
- m_eqs.pop_scopes(num_scopes);
+ m_eqs.pop_scope(num_scopes);
+ m_nqs.pop_scope(num_scopes);
+ m_atoms.resize(m_atoms_lim[m_atoms_lim.size()-num_scopes]);
+ m_atoms_lim.shrink(m_atoms_lim.size()-num_scopes);
}
void theory_seq::restart_eh() {
}
void theory_seq::relevant_eh(app* n) {
- if (m_util.str.is_length(n) ||
- m_util.str.is_index(n) ||
+ if (m_util.str.is_index(n) ||
m_util.str.is_replace(n) ||
m_util.str.is_extract(n) ||
m_util.str.is_at(n) ||
- m_util.str.is_concat(n) ||
m_util.str.is_empty(n) ||
- m_util.str.is_unit(n) ||
m_util.str.is_string(n)) {
enque_axiom(n);
}
+
+ expr* arg;
+ if (m_util.str.is_length(n, arg) && !has_length(arg)) {
+ enforce_length(get_context().get_enode(arg));
+ }
+}
+
+
+eautomaton* theory_seq::get_automaton(expr* re) {
+ eautomaton* result = 0;
+ if (m_re2aut.find(re, result)) {
+ return result;
+ }
+ result = re2automaton(m)(re);
+ if (result) {
+ display_expr disp(m);
+ TRACE("seq", result->display(tout, disp););
+ }
+ if (result) {
+ m_automata.push_back(result);
+ m_trail_stack.push(push_back_vector >(m_automata));
+ }
+ m_re2aut.insert(re, result);
+ m_trail_stack.push(insert_obj_map(m_re2aut, re));
+ return result;
+}
+
+literal theory_seq::mk_accept(expr* s, expr* idx, expr* re, expr* state) {
+ expr_ref_vector args(m);
+ args.push_back(s).push_back(idx).push_back(re).push_back(state);
+ return mk_literal(m_util.mk_skolem(m_accept, args.size(), args.c_ptr(), m.mk_bool_sort()));
+}
+literal theory_seq::mk_reject(expr* s, expr* idx, expr* re, expr* state) {
+ expr_ref_vector args(m);
+ args.push_back(s).push_back(idx).push_back(re).push_back(state);
+ return mk_literal(m_util.mk_skolem(m_reject, args.size(), args.c_ptr(), m.mk_bool_sort()));
+}
+
+bool theory_seq::is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) {
+ if (is_skolem(ar, e)) {
+ rational r;
+ s = to_app(e)->get_arg(0);
+ idx = to_app(e)->get_arg(1);
+ re = to_app(e)->get_arg(2);
+ VERIFY(m_autil.is_numeral(to_app(e)->get_arg(3), r));
+ SASSERT(r.is_unsigned());
+ i = r.get_unsigned();
+ aut = m_re2aut[re];
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool theory_seq::is_step(expr* e) const {
+ return is_skolem(m_aut_step, e);
+}
+
+bool theory_seq::is_step(expr* e, expr*& s, expr*& idx, expr*& re, expr*& i, expr*& j, expr*& t) const {
+ if (is_step(e)) {
+ s = to_app(e)->get_arg(0);
+ idx = to_app(e)->get_arg(1);
+ re = to_app(e)->get_arg(2);
+ i = to_app(e)->get_arg(3);
+ j = to_app(e)->get_arg(4);
+ t = to_app(e)->get_arg(5);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+expr_ref theory_seq::mk_step(expr* s, expr* idx, expr* re, unsigned i, unsigned j, expr* t) {
+ expr_ref_vector args(m);
+ args.push_back(s).push_back(idx).push_back(re);
+ args.push_back(m_autil.mk_int(i));
+ args.push_back(m_autil.mk_int(j));
+ args.push_back(t);
+ return expr_ref(m_util.mk_skolem(m_aut_step, args.size(), args.c_ptr(), m.mk_bool_sort()), m);
+}
+
+/*
+ acc(s, idx, re, i) -> len(s) >= idx if i is final
+ rej(s, idx, re, i) -> len(s) >= idx if i is non-final
+
+ acc(s, idx, re, i) -> len(s) > idx if i is non-final
+ rej(s, idx, re, i) -> len(s) > idx if i is final
+*/
+void theory_seq::propagate_acc_rej_length(literal lit, expr* e) {
+ context& ctx = get_context();
+ expr *s, * idx, *re;
+ unsigned src;
+ eautomaton* aut = 0;
+ bool is_acc;
+ is_acc = is_accept(e, s, idx, re, src, aut);
+ if (!is_acc) {
+ VERIFY(is_reject(e, s, idx, re, src, aut));
+ }
+ if (m_util.str.is_length(idx)) return;
+ SASSERT(m_autil.is_numeral(idx));
+ SASSERT(ctx.get_assignment(lit) == l_true);
+ bool is_final = aut->is_final_state(src);
+ if (is_final == is_acc) {
+ propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx)));
+ }
+ else {
+ propagate_lit(0, 1, &lit, ~mk_literal(m_autil.mk_le(m_util.str.mk_length(s), idx)));
+ }
+}
+
+/**
+ acc(s, idx, re, i) -> \/ step(s, idx, re, i, j, t) if i is non-final
+ acc(s, idx, re, i) -> len(s) <= idx \/ step(s, idx, re, i, j, t) if i is final
+*/
+bool theory_seq::add_accept2step(expr* acc) {
+ context& ctx = get_context();
+
+ TRACE("seq", tout << mk_pp(acc, m) << "\n";);
+ SASSERT(ctx.get_assignment(acc) == l_true);
+ expr *e, * idx, *re;
+ expr_ref step(m);
+ unsigned src;
+ eautomaton* aut = 0;
+ VERIFY(is_accept(acc, e, idx, re, src, aut));
+ if (!aut || m_util.str.is_length(idx)) {
+ return false;
+ }
+ SASSERT(m_autil.is_numeral(idx));
+ eautomaton::moves mvs;
+ aut->get_moves_from(src, mvs);
+
+ expr_ref len(m_util.str.mk_length(e), m);
+ literal_vector lits;
+ lits.push_back(~ctx.get_literal(acc));
+ if (aut->is_final_state(src)) {
+ lits.push_back(mk_literal(m_autil.mk_le(len, idx)));
+ switch (ctx.get_assignment(lits.back())) {
+ case l_true:
+ return false;
+ case l_undef:
+ ctx.force_phase(lits.back());
+ return true;
+ default:
+ break;
+ }
+ }
+ bool has_undef = false;
+ int start = ctx.get_random_value();
+ for (unsigned i = 0; i < mvs.size(); ++i) {
+ unsigned j = (i + start) % mvs.size();
+ eautomaton::move mv = mvs[j];
+ step = mk_step(e, idx, re, src, mv.dst(), mv.t());
+ lits.push_back(mk_literal(step));
+ switch (ctx.get_assignment(lits.back())) {
+ case l_true:
+ return false;
+ case l_undef:
+ //ctx.force_phase(lits.back());
+ //return true;
+ has_undef = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (has_undef && mvs.size() == 1) {
+ literal lit = lits.back();
+ lits.pop_back();
+ for (unsigned i = 0; i < lits.size(); ++i) {
+ lits[i].neg();
+ }
+ propagate_lit(0, lits.size(), lits.c_ptr(), lit);
+ return false;
+ }
+ if (has_undef) {
+ return true;
+ }
+ TRACE("seq", ctx.display_literals_verbose(tout, lits.size(), lits.c_ptr()); tout << "\n";);
+ for (unsigned i = 0; i < lits.size(); ++i) {
+ SASSERT(ctx.get_assignment(lits[i]) == l_false);
+ lits[i].neg();
+ }
+ set_conflict(0, lits);
+ return false;
+}
+
+
+/**
+ acc(s, idx, re, i) & step(s, idx, re, i, j, t) => acc(s, idx + 1, re, j)
+*/
+
+bool theory_seq::add_step2accept(expr* step) {
+ context& ctx = get_context();
+ SASSERT(ctx.get_assignment(step) == l_true);
+ expr* re, *t, *s, *idx, *i, *j;
+ VERIFY(is_step(step, s, idx, re, i, j, t));
+ literal acc1 = mk_accept(s, idx, re, i);
+ switch (ctx.get_assignment(acc1)) {
+ case l_false:
+ break;
+ case l_undef:
+ return true;
+ case l_true: {
+ rational r;
+ VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned());
+ expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m);
+ literal acc2 = mk_accept(s, idx1, re, j);
+ literal_vector lits;
+ lits.push_back(acc1);
+ lits.push_back(ctx.get_literal(step));
+ lits.push_back(~acc2);
+ switch (ctx.get_assignment(acc2)) {
+ case l_undef:
+ propagate_lit(0, 2, lits.c_ptr(), acc2);
+ break;
+ case l_true:
+ break;
+ case l_false:
+ set_conflict(0, lits);
+ break;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
+/*
+ rej(s, idx, re, i) & nth(s, idx) = t & idx < len(s) => rej(s, idx + 1, re, j)
+
+ len(s) > idx -> s = (nth 0 s) ++ .. ++ (nth idx s) ++ (tail idx s)
+
+Recall we also have:
+ rej(s, idx, re, i) -> len(s) >= idx if i is non-final
+ rej(s, idx, re, i) -> len(s) > idx if i is final
+
+*/
+bool theory_seq::add_reject2reject(expr* rej) {
+ context& ctx = get_context();
+ SASSERT(ctx.get_assignment(rej) == l_true);
+ expr* s, *idx, *re;
+ unsigned src;
+ rational r;
+ eautomaton* aut = 0;
+ VERIFY(is_reject(rej, s, idx, re, src, aut));
+ if (!aut || m_util.str.is_length(idx)) return false;
+ VERIFY(m_autil.is_numeral(idx, r) && r.is_unsigned());
+ expr_ref idx1(m_autil.mk_int(r.get_unsigned() + 1), m);
+ eautomaton::moves mvs;
+ aut->get_moves_from(src, mvs);
+ literal rej1 = ctx.get_literal(rej);
+ expr_ref len(m_util.str.mk_length(s), m);
+ literal len_le_idx = mk_literal(m_autil.mk_le(len, idx));
+ switch (ctx.get_assignment(len_le_idx)) {
+ case l_true:
+ return false;
+ case l_undef:
+ ctx.force_phase(len_le_idx);
+ return true;
+ default:
+ break;
+ }
+ expr_ref nth = mk_nth(s, idx);
+ ensure_nth(~len_le_idx, s, idx);
+ literal_vector eqs;
+ bool has_undef = false;
+ for (unsigned i = 0; i < mvs.size(); ++i) {
+ eautomaton::move const& mv = mvs[i];
+ literal eq = mk_eq(nth, mv.t(), false);
+ switch (ctx.get_assignment(eq)) {
+ case l_false:
+ case l_true:
+ break;
+ case l_undef:
+ ctx.force_phase(~eq);
+ has_undef = true;
+ break;
+ }
+ eqs.push_back(eq);
+ }
+ if (has_undef) {
+ return true;
+ }
+ for (unsigned i = 0; i < mvs.size(); ++i) {
+ eautomaton::move const& mv = mvs[i];
+ literal eq = eqs[i];
+ if (ctx.get_assignment(eq) == l_true) {
+ literal rej2 = mk_reject(s, idx1, re, m_autil.mk_int(mv.dst()));
+ add_axiom(~rej1, ~eq, len_le_idx, rej2);
+ }
+ }
+ return false;
+}
+
+/*
+ !prefix -> e2 = emp \/ nth(e1,0) != nth(e2,0) \/ !prefix(tail(e1),tail(e2))
+*/
+bool theory_seq::add_prefix2prefix(expr* e) {
+ context& ctx = get_context();
+ expr* e1, *e2;
+ VERIFY(m_util.str.is_prefix(e, e1, e2));
+ SASSERT(ctx.get_assignment(e) == l_false);
+ if (canonizes(false, e)) {
+ return false;
+ }
+ expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m);
+ switch (assume_equality(e2, emp)) {
+ case l_true:
+ return false; // done
+ case l_undef:
+ return true; // retry
+ default:
+ break;
+ }
+ expr_ref head1(m), tail1(m), head2(m), tail2(m);
+ mk_decompose(e1, head1, tail1);
+ mk_decompose(e2, head2, tail2);
+
+ literal lit = mk_eq(head1, head2, false);
+ switch (ctx.get_assignment(lit)) {
+ case l_true: {
+ literal_vector lits;
+ lits.push_back(~ctx.get_literal(e));
+ lits.push_back(~mk_eq(e2, emp, false));
+ lits.push_back(lit);
+ propagate_lit(0, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_prefix(tail1, tail2)));
+ return false;
+ }
+ case l_false:
+ return false;
+ case l_undef:
+ ctx.force_phase(~lit);
+ return true;
+ }
+ return true;
+}
+
+/*
+ !suffix(e1, e2) -> e2 = emp \/ last(e1) != last(e2) \/ !suffix(first(e1), first(e2))
+ */
+bool theory_seq::add_suffix2suffix(expr* e) {
+ context& ctx = get_context();
+ expr* e1, *e2;
+ VERIFY(m_util.str.is_suffix(e, e1, e2));
+ SASSERT(ctx.get_assignment(e) == l_false);
+ if (canonizes(false, e)) {
+ return false;
+ }
+
+ expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m);
+
+ switch (assume_equality(e2, emp)) {
+ case l_true:
+ return false; // done
+ case l_undef:
+ ctx.force_phase(mk_eq(e2, emp, false));
+ return true; // retry
+ case l_false:
+ break;
+ }
+ expr_ref first2 = mk_skolem(m_seq_first, e2);
+ expr_ref last2 = mk_last(e2);
+ expr_ref first1 = mk_skolem(m_seq_first, e1);
+ expr_ref last1 = mk_last(e1);
+ expr_ref conc = mk_concat(first2, m_util.str.mk_unit(last2));
+ propagate_eq(~mk_eq(e2, emp, false), e2, conc);
+
+ literal last_eq = mk_eq(last1, last2, false);
+ switch (ctx.get_assignment(last_eq)) {
+ case l_false:
+ return false; // done
+ case l_undef:
+ ctx.force_phase(~last_eq);
+ return true;
+ case l_true:
+ break;
+ }
+
+ literal_vector lits;
+ lits.push_back(~ctx.get_literal(e));
+ lits.push_back(~mk_eq(e2, emp, false));
+ lits.push_back(last_eq);
+ propagate_lit(0, lits.size(), lits.c_ptr(), ~mk_literal(m_util.str.mk_suffix(first1, first2)));
+ return false;
+}
+
+bool theory_seq::canonizes(bool sign, expr* e) {
+ context& ctx = get_context();
+ dependency* deps = 0;
+ expr_ref cont = canonize(e, deps);
+ TRACE("seq", tout << mk_pp(e, m) << " -> " << cont << "\n";);
+ if ((m.is_true(cont) && !sign) ||
+ (m.is_false(cont) && sign)) {
+ propagate_lit(deps, 0, 0, ctx.get_literal(e));
+ return true;
+ }
+ if ((m.is_false(cont) && !sign) ||
+ (m.is_true(cont) && sign)) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ !contains(e1, e2) -> !prefix(e2, e1)
+ !contains(e1, e2) -> e1 = emp \/ !contains(tail(e1), e2)
+ */
+
+bool theory_seq::add_contains2contains(expr* e) {
+ context& ctx = get_context();
+ expr* e1, *e2;
+ VERIFY(m_util.str.is_contains(e, e1, e2));
+ SASSERT(ctx.get_assignment(e) == l_false);
+ if (canonizes(false, e)) {
+ return false;
+ }
+ expr_ref emp(m_util.str.mk_empty(m.get_sort(e1)), m);
+
+ switch (assume_equality(e1, emp)) {
+ case l_true:
+ return false; // done
+ case l_undef:
+ return true; // retry
+ default:
+ break;
+ }
+ expr_ref head(m), tail(m);
+ mk_decompose(e1, head, tail);
+ literal lits[2] = { ~ctx.get_literal(e), ~mk_eq(e1, emp, false) };
+ propagate_lit(0, 2, lits, ~mk_literal(m_util.str.mk_contains(tail, e2)));
+ return false;
+}
+
+bool theory_seq::propagate_automata() {
+ context& ctx = get_context();
+ if (m_atoms_qhead == m_atoms.size()) {
+ return false;
+ }
+ m_trail_stack.push(value_trail(m_atoms_qhead));
+ ptr_vector re_add;
+ while (m_atoms_qhead < m_atoms.size() && !ctx.inconsistent()) {
+ expr* e = m_atoms[m_atoms_qhead];
+ TRACE("seq", tout << mk_pp(e, m) << "\n";);
+ bool reQ = false;
+ if (is_accept(e)) {
+ reQ = add_accept2step(e);
+ }
+ else if (is_reject(e)) {
+ reQ = add_reject2reject(e);
+ }
+ else if (is_step(e)) {
+ reQ = add_step2accept(e);
+ }
+ else if (m_util.str.is_prefix(e)) {
+ reQ = add_prefix2prefix(e);
+ }
+ else if (m_util.str.is_suffix(e)) {
+ reQ = add_suffix2suffix(e);
+ }
+ else if (m_util.str.is_contains(e)) {
+ reQ = add_contains2contains(e);
+ }
+ if (reQ) {
+ re_add.push_back(e);
+ }
+ ++m_atoms_qhead;
+ }
+ m_atoms.append(re_add);
+ return true;
}
diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h
index b2b45e77e..1e19bcddb 100644
--- a/src/smt/theory_seq.h
+++ b/src/smt/theory_seq.h
@@ -25,15 +25,24 @@ Revision History:
#include "th_rewriter.h"
#include "ast_trail.h"
#include "scoped_vector.h"
+#include "scoped_ptr_vector.h"
+#include "automaton.h"
+#include "seq_rewriter.h"
namespace smt {
class theory_seq : public theory {
- typedef scoped_dependency_manager enode_pair_dependency_manager;
- typedef enode_pair_dependency_manager::dependency enode_pair_dependency;
-
+ struct assumption {
+ enode* n1, *n2;
+ literal lit;
+ assumption(enode* n1, enode* n2): n1(n1), n2(n2), lit(null_literal) {}
+ assumption(literal lit): n1(0), n2(0), lit(lit) {}
+ };
+ typedef scoped_dependency_manager dependency_manager;
+ typedef dependency_manager::dependency dependency;
+
typedef trail_stack th_trail_stack;
- typedef std::pair expr_dep;
+ typedef std::pair expr_dep;
typedef obj_map eqdep_map_t;
// cache to track evaluations under equalities
@@ -52,27 +61,30 @@ namespace smt {
class solution_map {
enum map_update { INS, DEL };
ast_manager& m;
- enode_pair_dependency_manager& m_dm;
+ dependency_manager& m_dm;
eqdep_map_t m_map;
eval_cache m_cache;
expr_ref_vector m_lhs, m_rhs;
- ptr_vector m_deps;
+ ptr_vector m_deps;
svector m_updates;
unsigned_vector m_limit;
- void add_trail(map_update op, expr* l, expr* r, enode_pair_dependency* d);
+ void add_trail(map_update op, expr* l, expr* r, dependency* d);
public:
- solution_map(ast_manager& m, enode_pair_dependency_manager& dm):
+ solution_map(ast_manager& m, dependency_manager& dm):
m(m), m_dm(dm), m_cache(m), m_lhs(m), m_rhs(m) {}
- bool empty() const { return m_map.empty(); }
- void update(expr* e, expr* r, enode_pair_dependency* d);
+ bool empty() const { return m_map.empty(); }
+ void update(expr* e, expr* r, dependency* d);
void add_cache(expr* v, expr_dep& r) { m_cache.insert(v, r); }
bool find_cache(expr* v, expr_dep& r) { return m_cache.find(v, r); }
- expr* find(expr* e, enode_pair_dependency*& d);
- void cache(expr* e, expr* r, enode_pair_dependency* d);
- void push_scope() { m_limit.push_back(m_updates.size()); }
- void pop_scope(unsigned num_scopes);
- void display(std::ostream& out) const;
+ expr* find(expr* e, dependency*& d);
+ expr* find(expr* e);
+ bool is_root(expr* e) const;
+ void cache(expr* e, expr* r, dependency* d);
+ void reset_cache() { m_cache.reset(); }
+ void push_scope() { m_limit.push_back(m_updates.size()); }
+ void pop_scope(unsigned num_scopes);
+ void display(std::ostream& out) const;
};
// Table of current disequalities
@@ -94,55 +106,308 @@ namespace smt {
};
// Asserted or derived equality with dependencies
- struct eq {
- expr_ref m_lhs;
- expr_ref m_rhs;
- enode_pair_dependency* m_dep;
- eq(expr_ref& l, expr_ref& r, enode_pair_dependency* d):
- m_lhs(l), m_rhs(r), m_dep(d) {}
- eq(eq const& other): m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_dep(other.m_dep) {}
- eq& operator=(eq const& other) { m_lhs = other.m_lhs; m_rhs = other.m_rhs; m_dep = other.m_dep; return *this; }
+ class eq {
+ unsigned m_id;
+ expr_ref_vector m_lhs;
+ expr_ref_vector m_rhs;
+ dependency* m_dep;
+ public:
+
+ eq(unsigned id, expr_ref_vector& l, expr_ref_vector& r, dependency* d):
+ m_id(id), m_lhs(l), m_rhs(r), m_dep(d) {}
+ eq(eq const& other): m_id(other.m_id), m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_dep(other.m_dep) {}
+ eq& operator=(eq const& other) {
+ if (this != &other) {
+ m_lhs.reset();
+ m_rhs.reset();
+ m_lhs.append(other.m_lhs);
+ m_rhs.append(other.m_rhs);
+ m_dep = other.m_dep;
+ m_id = other.m_id;
+ }
+ return *this;
+ }
+ expr_ref_vector const& ls() const { return m_lhs; }
+ expr_ref_vector const& rs() const { return m_rhs; }
+ dependency* dep() const { return m_dep; }
+ unsigned id() const { return m_id; }
};
+ eq mk_eqdep(expr* l, expr* r, dependency* dep) {
+ expr_ref_vector ls(m), rs(m);
+ m_util.str.get_concat(l, ls);
+ m_util.str.get_concat(r, rs);
+ return eq(m_eq_id++, ls, rs, dep);
+ }
+
+
+ class ne2 {
+ vector m_lhs;
+ vector m_rhs;
+ literal_vector m_lits;
+ dependency* m_dep;
+ public:
+ ne2(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep):
+ m_dep(dep) {
+ m_lhs.push_back(l);
+ m_rhs.push_back(r);
+ }
+
+ ne2(ne2 const& other):
+ m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_lits(other.m_lits), m_dep(other.m_dep) {}
+
+ ne2& operator=(ne2 const& other) {
+ if (this != &other) {
+ m_lhs.reset(); m_lhs.append(other.m_lhs);
+ m_rhs.reset(); m_rhs.append(other.m_rhs);
+ m_lits.reset(); m_lits.append(other.m_lits);
+ m_dep = other.m_dep;
+ }
+ return *this;
+ }
+ vector const& ls() const { return m_lhs; }
+ vector const& rs() const { return m_rhs; }
+ expr_ref_vector const& ls(unsigned i) const { return m_lhs[i]; }
+ expr_ref_vector const& rs(unsigned i) const { return m_rhs[i]; }
+ literal_vector const& lits() const { return m_lits; }
+ literal lits(unsigned i) const { return m_lits[i]; }
+ dependency* dep() const { return m_dep; }
+ };
+
+
+ // asserted or derived disqequality with dependencies
+ struct ne {
+ bool m_solved;
+ expr_ref m_l, m_r;
+ expr_ref_vector m_lhs;
+ expr_ref_vector m_rhs;
+ literal_vector m_lits;
+ dependency* m_dep;
+ ne(expr_ref& l, expr_ref& r):
+ m_solved(false), m_l(l), m_r(r), m_lhs(l.get_manager()), m_rhs(r.get_manager()), m_dep(0) {
+ m_lhs.push_back(l);
+ m_rhs.push_back(r);
+ }
+ ne(ne const& other):
+ m_solved(other.m_solved), m_l(other.m_l), m_r(other.m_r), m_lhs(other.m_lhs), m_rhs(other.m_rhs), m_lits(other.m_lits), m_dep(other.m_dep) {}
+ ne& operator=(ne const& other) {
+ m_solved = other.m_solved;
+ m_l = other.m_l;
+ m_r = other.m_r;
+ m_lhs.reset(); m_lhs.append(other.m_lhs);
+ m_rhs.reset(); m_rhs.append(other.m_rhs);
+ m_lits.reset(); m_lits.append(other.m_lits);
+ m_dep = other.m_dep;
+ return *this;
+ }
+ bool is_solved() const { return m_solved; }
+ };
+
+ class pop_lit : public trail {
+ unsigned m_idx;
+ literal m_lit;
+ public:
+ pop_lit(theory_seq& th, unsigned idx): m_idx(idx), m_lit(th.m_nqs[idx].m_lits.back()) {
+ th.m_nqs.ref(m_idx).m_lits.pop_back();
+ }
+ virtual void undo(theory_seq & th) { th.m_nqs.ref(m_idx).m_lits.push_back(m_lit); }
+ };
+ class push_lit : public trail {
+ unsigned m_idx;
+ public:
+ push_lit(theory_seq& th, unsigned idx, literal lit): m_idx(idx) {
+ th.m_nqs.ref(m_idx).m_lits.push_back(lit);
+ }
+ virtual void undo(theory_seq & th) { th.m_nqs.ref(m_idx).m_lits.pop_back(); }
+ };
+ class set_lit : public trail {
+ unsigned m_idx;
+ unsigned m_i;
+ literal m_lit;
+ public:
+ set_lit(theory_seq& th, unsigned idx, unsigned i, literal lit):
+ m_idx(idx), m_i(i), m_lit(th.m_nqs[idx].m_lits[i]) {
+ th.m_nqs.ref(m_idx).m_lits[i] = lit;
+ }
+ virtual void undo(theory_seq & th) { th.m_nqs.ref(m_idx).m_lits[m_i] = m_lit; }
+ };
+
+ class solved_ne : public trail {
+ unsigned m_idx;
+ public:
+ solved_ne(theory_seq& th, unsigned idx) : m_idx(idx) { th.m_nqs.ref(idx).m_solved = true; }
+ virtual void undo(theory_seq& th) { th.m_nqs.ref(m_idx).m_solved = false; }
+ };
+ void mark_solved(unsigned idx);
+
+ class push_ne : public trail {
+ unsigned m_idx;
+ public:
+ push_ne(theory_seq& th, unsigned idx, expr* l, expr* r) : m_idx(idx) {
+ th.m_nqs.ref(m_idx).m_lhs.push_back(l);
+ th.m_nqs.ref(m_idx).m_rhs.push_back(r);
+ }
+ virtual void undo(theory_seq& th) { th.m_nqs.ref(m_idx).m_lhs.pop_back(); th.m_nqs.ref(m_idx).m_rhs.pop_back(); }
+ };
+
+ class pop_ne : public trail {
+ expr_ref m_lhs;
+ expr_ref m_rhs;
+ unsigned m_idx;
+ public:
+ pop_ne(theory_seq& th, unsigned idx):
+ m_lhs(th.m_nqs[idx].m_lhs.back(), th.m),
+ m_rhs(th.m_nqs[idx].m_rhs.back(), th.m),
+ m_idx(idx) {
+ th.m_nqs.ref(idx).m_lhs.pop_back();
+ th.m_nqs.ref(idx).m_rhs.pop_back();
+ }
+ virtual void undo(theory_seq& th) {
+ th.m_nqs.ref(m_idx).m_lhs.push_back(m_lhs);
+ th.m_nqs.ref(m_idx).m_rhs.push_back(m_rhs);
+ m_lhs.reset();
+ m_rhs.reset();
+ }
+ };
+
+ class set_ne : public trail {
+ expr_ref m_lhs;
+ expr_ref m_rhs;
+ unsigned m_idx;
+ unsigned m_i;
+ public:
+ set_ne(theory_seq& th, unsigned idx, unsigned i, expr* l, expr* r):
+ m_lhs(th.m_nqs[idx].m_lhs[i], th.m),
+ m_rhs(th.m_nqs[idx].m_rhs[i], th.m),
+ m_idx(idx),
+ m_i(i) {
+ th.m_nqs.ref(idx).m_lhs[i] = l;
+ th.m_nqs.ref(idx).m_rhs[i] = r;
+ }
+ virtual void undo(theory_seq& th) {
+ th.m_nqs.ref(m_idx).m_lhs[m_i] = m_lhs;
+ th.m_nqs.ref(m_idx).m_rhs[m_i] = m_rhs;
+ m_lhs.reset();
+ m_rhs.reset();
+ }
+ };
+
+ class push_dep : public trail {
+ dependency* m_dep;
+ unsigned m_idx;
+ public:
+ push_dep(theory_seq& th, unsigned idx, dependency* d): m_dep(th.m_nqs[idx].m_dep), m_idx(idx) {
+ th.m_nqs.ref(idx).m_dep = d;
+ }
+ virtual void undo(theory_seq& th) {
+ th.m_nqs.ref(m_idx).m_dep = m_dep;
+ }
+ };
+
+ class apply {
+ public:
+ virtual ~apply() {}
+ virtual void operator()(theory_seq& th) = 0;
+ };
+
+ class replay_length_coherence : public apply {
+ expr_ref m_e;
+ public:
+ replay_length_coherence(ast_manager& m, expr* e) : m_e(e, m) {}
+ virtual void operator()(theory_seq& th) {
+ th.check_length_coherence(m_e);
+ m_e.reset();
+ }
+ };
+
+ class replay_axiom : public apply {
+ expr_ref m_e;
+ public:
+ replay_axiom(ast_manager& m, expr* e) : m_e(e, m) {}
+ virtual void operator()(theory_seq& th) {
+ th.enque_axiom(m_e);
+ m_e.reset();
+ }
+ };
+
+ class push_replay : public trail {
+ apply* m_apply;
+ public:
+ push_replay(apply* app): m_apply(app) {}
+ virtual void undo(theory_seq& th) {
+ th.m_replay.push_back(m_apply);
+ }
+ };
+
+ class pop_branch : public trail {
+ unsigned k;
+ public:
+ pop_branch(unsigned k): k(k) {}
+ virtual void undo(theory_seq& th) {
+ th.m_branch_start.erase(k);
+ }
+ };
+
+ void erase_index(unsigned idx, unsigned i);
+
struct stats {
stats() { reset(); }
void reset() { memset(this, 0, sizeof(stats)); }
unsigned m_num_splits;
unsigned m_num_reductions;
+ unsigned m_propagate_automata;
+ unsigned m_check_length_coherence;
+ unsigned m_branch_variable;
+ unsigned m_solve_nqs;
+ unsigned m_solve_eqs;
+ unsigned m_add_axiom;
};
- ast_manager& m;
- enode_pair_dependency_manager m_dm;
- solution_map m_rep; // unification representative.
- scoped_vector m_eqs; // set of current equations.
+ ast_manager& m;
+ dependency_manager m_dm;
+ solution_map m_rep; // unification representative.
+ scoped_vector m_eqs; // set of current equations.
+ scoped_vector m_nqs; // set of current disequalities.
+ unsigned m_eq_id;
- seq_factory* m_factory; // value factory
- expr_ref_vector m_ineqs; // inequalities to check solution against
- exclusion_table m_exclude; // set of asserted disequalities.
- expr_ref_vector m_axioms; // list of axioms to add.
- unsigned m_axioms_head; // index of first axiom to add.
- unsigned m_branch_variable_head; // index of first equation to examine.
- bool m_incomplete; // is the solver (clearly) incomplete for the fragment.
- bool m_has_length; // is length applied
- bool m_model_completion; // during model construction, invent values in canonizer
- th_rewriter m_rewrite;
- seq_util m_util;
- arith_util m_autil;
- th_trail_stack m_trail_stack;
- stats m_stats;
- symbol m_prefix_sym;
- symbol m_suffix_sym;
- symbol m_contains_left_sym;
- symbol m_contains_right_sym;
- symbol m_left_sym; // split variable left part
- symbol m_right_sym; // split variable right part
+ seq_factory* m_factory; // value factory
+ exclusion_table m_exclude; // set of asserted disequalities.
+ expr_ref_vector m_axioms; // list of axioms to add.
+ obj_hashtable m_axiom_set;
+ unsigned m_axioms_head; // index of first axiom to add.
+ bool m_incomplete; // is the solver (clearly) incomplete for the fragment.
+ obj_hashtable m_length; // is length applied
+ scoped_ptr_vector m_replay; // set of actions to replay
+ model_generator* m_mg;
+ th_rewriter m_rewrite;
+ seq_rewriter m_seq_rewrite;
+ seq_util m_util;
+ arith_util m_autil;
+ th_trail_stack m_trail_stack;
+ stats m_stats;
+ symbol m_prefix, m_suffix, m_contains_left, m_contains_right, m_accept, m_reject;
+ symbol m_tail, m_nth, m_seq_first, m_seq_last, m_indexof_left, m_indexof_right, m_aut_step;
+ symbol m_extract_prefix, m_at_left, m_at_right;
+ ptr_vector m_todo;
+ expr_ref_vector m_ls, m_rs, m_lhs, m_rhs;
+
+ // maintain automata with regular expressions.
+ scoped_ptr_vector m_automata;
+ obj_map m_re2aut;
+
+ // queue of asserted atoms
+ ptr_vector m_atoms;
+ unsigned_vector m_atoms_lim;
+ unsigned m_atoms_qhead;
+ bool m_new_solution; // new solution added
+ bool m_new_propagation; // new propagation to core
virtual final_check_status final_check_eh();
- virtual bool internalize_atom(app*, bool);
+ virtual bool internalize_atom(app* atom, bool) { return internalize_term(atom); }
virtual bool internalize_term(app*);
- virtual void internalize_eq_eh(app * atom, bool_var v);
+ virtual void internalize_eq_eh(app * atom, bool_var v) {}
virtual void new_eq_eh(theory_var, theory_var);
virtual void new_diseq_eh(theory_var, theory_var);
- virtual void assign_eq(bool_var v, bool is_true);
+ virtual void assign_eh(bool_var v, bool is_true);
virtual bool can_propagate();
virtual void propagate();
virtual void push_scope_eh();
@@ -159,40 +424,61 @@ namespace smt {
virtual void init_model(model_generator & mg);
// final check
- bool check_ineqs(); // check if inequalities are violated.
bool simplify_and_solve_eqs(); // solve unitary equalities
bool branch_variable(); // branch on a variable
bool split_variable(); // split a variable
bool is_solved();
- bool check_length_coherence();
- bool check_length_coherence_tbd();
- bool check_ineq_coherence();
+ bool check_length_coherence();
+ bool check_length_coherence(expr* e);
+ bool propagate_length_coherence(expr* e);
- bool pre_process_eqs(bool simplify_or_solve);
- bool simplify_eqs();
- bool simplify_eq(expr* l, expr* r, enode_pair_dependency* dep);
- bool solve_unit_eq(expr* l, expr* r, enode_pair_dependency* dep);
- bool solve_basic_eqs();
+ bool solve_eqs(unsigned start);
+ bool solve_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep);
+ bool simplify_eq(expr_ref_vector& l, expr_ref_vector& r, dependency* dep);
+ bool solve_unit_eq(expr* l, expr* r, dependency* dep);
+ bool solve_unit_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep);
+ bool is_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, expr*& x, ptr_vector& xunits, ptr_vector& yunits, expr*& y);
+ bool solve_binary_eq(expr_ref_vector const& l, expr_ref_vector const& r, dependency* dep);
+ bool propagate_max_length(expr* l, expr* r, dependency* dep);
+
+ expr_ref mk_concat(unsigned n, expr*const* es) { return expr_ref(m_util.str.mk_concat(n, es), m); }
+ expr_ref mk_concat(expr_ref_vector const& es) { return mk_concat(es.size(), es.c_ptr()); }
+ expr_ref mk_concat(expr* e1, expr* e2) { return expr_ref(m_util.str.mk_concat(e1, e2), m); }
+ expr_ref mk_concat(expr* e1, expr* e2, expr* e3) { return expr_ref(m_util.str.mk_concat(e1, e2, e3), m); }
+ bool solve_nqs(unsigned i);
+ void solve_ne(unsigned i);
// asserting consequences
- void propagate_lit(enode_pair_dependency* dep, literal lit);
- void propagate_eq(enode_pair_dependency* dep, enode* n1, enode* n2);
- void propagate_eq(bool_var v, expr* e1, expr* e2);
- void set_conflict(enode_pair_dependency* dep);
+ void linearize(dependency* dep, enode_pair_vector& eqs, literal_vector& lits) const;
+ void propagate_lit(dependency* dep, literal lit) { propagate_lit(dep, 0, 0, lit); }
+ void propagate_lit(dependency* dep, unsigned n, literal const* lits, literal lit);
+ void propagate_eq(dependency* dep, enode* n1, enode* n2);
+ void propagate_eq(literal lit, expr* e1, expr* e2, bool add_to_eqs = false);
+ void set_conflict(dependency* dep, literal_vector const& lits = literal_vector());
- bool find_branch_candidate(expr* l, ptr_vector const& rs);
- bool assume_equality(expr* l, expr* r);
+ u_map m_branch_start;
+ void insert_branch_start(unsigned k, unsigned s);
+ unsigned find_branch_start(unsigned k);
+ bool find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs);
+ bool can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const;
+ lbool assume_equality(expr* l, expr* r);
// variable solving utilities
bool occurs(expr* a, expr* b);
+ bool occurs(expr* a, expr_ref_vector const& b);
bool is_var(expr* b);
- void add_solution(expr* l, expr* r, enode_pair_dependency* dep);
- bool is_left_select(expr* a, expr*& b);
- bool is_right_select(expr* a, expr*& b);
- expr_ref canonize(expr* e, enode_pair_dependency*& eqs);
- expr_ref expand(expr* e, enode_pair_dependency*& eqs);
- void add_dependency(enode_pair_dependency*& dep, enode* a, enode* b);
+ bool add_solution(expr* l, expr* r, dependency* dep);
+ bool is_nth(expr* a) const;
+ bool is_tail(expr* a, expr*& s, unsigned& idx) const;
+ expr_ref mk_nth(expr* s, expr* idx);
+ expr_ref mk_last(expr* e);
+ expr_ref canonize(expr* e, dependency*& eqs);
+ bool canonize(expr* e, expr_ref_vector& es, dependency*& eqs);
+ bool canonize(expr_ref_vector const& es, expr_ref_vector& result, dependency*& eqs);
+ expr_ref expand(expr* e, dependency*& eqs);
+ void add_dependency(dependency*& dep, enode* a, enode* b);
+ void get_concat(expr* e, ptr_vector& concats);
// terms whose meaning are encoded using axioms.
void enque_axiom(expr* e);
@@ -202,28 +488,80 @@ namespace smt {
void add_replace_axiom(expr* e);
void add_extract_axiom(expr* e);
void add_length_axiom(expr* n);
- void add_length_unit_axiom(expr* n);
- void add_length_empty_axiom(expr* n);
- void add_length_concat_axiom(expr* n);
- void add_length_string_axiom(expr* n);
+
+ bool has_length(expr *e) const { return m_length.contains(e); }
+ void add_length(expr* e);
+ void enforce_length(enode* n);
+ void enforce_length_coherence(enode* n1, enode* n2);
+
void add_elim_string_axiom(expr* n);
void add_at_axiom(expr* n);
+ void add_in_re_axiom(expr* n);
literal mk_literal(expr* n);
+ literal mk_eq_empty(expr* n);
+ literal mk_equals(expr* a, expr* b);
void tightest_prefix(expr* s, expr* x, literal lit, literal lit2 = null_literal);
- expr* mk_sub(expr* a, expr* b);
+ expr_ref mk_sub(expr* a, expr* b);
enode* ensure_enode(expr* a);
+ // arithmetic integration
+ bool lower_bound(expr* s, rational& lo);
+ bool upper_bound(expr* s, rational& hi);
+ bool get_length(expr* s, rational& val);
+
+ void mk_decompose(expr* e, expr_ref& head, expr_ref& tail);
expr_ref mk_skolem(symbol const& s, expr* e1, expr* e2 = 0, expr* e3 = 0, sort* range = 0);
+ bool is_skolem(symbol const& s, expr* e) const;
void set_incomplete(app* term);
+ // automata utilities
+ void propagate_in_re(expr* n, bool is_true);
+ eautomaton* get_automaton(expr* e);
+ literal mk_accept(expr* s, expr* idx, expr* re, expr* state);
+ literal mk_accept(expr* s, expr* idx, expr* re, unsigned i) { return mk_accept(s, idx, re, m_autil.mk_int(i)); }
+ bool is_accept(expr* acc) const { return is_skolem(m_accept, acc); }
+ bool is_accept(expr* acc, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) {
+ return is_acc_rej(m_accept, acc, s, idx, re, i, aut);
+ }
+ literal mk_reject(expr* s, expr* idx, expr* re, expr* state);
+ literal mk_reject(expr* s, expr* idx, expr* re, unsigned i) { return mk_reject(s, idx, re, m_autil.mk_int(i)); }
+ bool is_reject(expr* rej) const { return is_skolem(m_reject, rej); }
+ bool is_reject(expr* rej, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut) {
+ return is_acc_rej(m_reject, rej, s, idx, re, i, aut);
+ }
+ bool is_acc_rej(symbol const& ar, expr* e, expr*& s, expr*& idx, expr*& re, unsigned& i, eautomaton*& aut);
+ expr_ref mk_step(expr* s, expr* tail, expr* re, unsigned i, unsigned j, expr* t);
+ bool is_step(expr* e, expr*& s, expr*& tail, expr*& re, expr*& i, expr*& j, expr*& t) const;
+ bool is_step(expr* e) const;
+ void propagate_step(literal lit, expr* n);
+ bool add_reject2reject(expr* rej);
+ bool add_accept2step(expr* acc);
+ bool add_step2accept(expr* step);
+ bool add_prefix2prefix(expr* e);
+ bool add_suffix2suffix(expr* e);
+ bool add_contains2contains(expr* e);
+ void ensure_nth(literal lit, expr* s, expr* idx);
+ bool canonizes(bool sign, expr* e);
+ void propagate_non_empty(literal lit, expr* s);
+ void propagate_is_conc(expr* e, expr* conc);
+ void propagate_acc_rej_length(literal lit, expr* acc_rej);
+ bool propagate_automata();
+ void add_atom(expr* e);
+ void new_eq_eh(dependency* dep, enode* n1, enode* n2);
+
// diagnostics
void display_equations(std::ostream& out) const;
- void display_deps(std::ostream& out, enode_pair_dependency* deps) const;
+ void display_disequations(std::ostream& out) const;
+ void display_disequation(std::ostream& out, ne const& e) const;
+ void display_deps(std::ostream& out, dependency* deps) const;
public:
theory_seq(ast_manager& m);
virtual ~theory_seq();
+ // model building
+ app* mk_value(app* a);
+
};
};
diff --git a/src/smt/theory_seq_empty.h b/src/smt/theory_seq_empty.h
index 04f38020c..5065c733d 100644
--- a/src/smt/theory_seq_empty.h
+++ b/src/smt/theory_seq_empty.h
@@ -30,6 +30,7 @@ namespace smt {
seq_util u;
symbol_set m_strings;
unsigned m_next;
+ char m_char;
std::string m_unique_prefix;
obj_map m_unique_sequences;
expr_ref_vector m_trail;
@@ -41,6 +42,7 @@ namespace smt {
m_model(md),
u(m),
m_next(0),
+ m_char(0),
m_unique_prefix("#B"),
m_trail(m)
{
@@ -99,6 +101,11 @@ namespace smt {
expr* v0 = get_fresh_value(seq);
return u.re.mk_to_re(v0);
}
+ if (u.is_char(s)) {
+ //char s[2] = { ++m_char, 0 };
+ //return u.str.mk_char(zstring(s), 0);
+ return u.str.mk_char(zstring("a"), 0);
+ }
NOT_IMPLEMENTED_YET();
return 0;
}
diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp
index 47f7a5576..a41c6939e 100644
--- a/src/tactic/arith/purify_arith_tactic.cpp
+++ b/src/tactic/arith/purify_arith_tactic.cpp
@@ -366,7 +366,7 @@ struct purify_arith_proc {
push_cnstr(EQ(x, u().mk_power(k, u().mk_numeral(n, false))));
push_cnstr_pr(result_pr);
}
- else if (complete()) {
+ else {
SASSERT(n.is_even());
// (^ x (/ 1 n)) --> k | x >= 0 implies (x = k^n and k >= 0), x < 0 implies k = neg-root(x, n)
// when n is even
@@ -379,9 +379,9 @@ struct purify_arith_proc {
EQ(k, u().mk_neg_root(x, u().mk_numeral(n, false)))));
push_cnstr_pr(result_pr);
}
- else {
- return BR_FAILED;
- }
+// else {
+// return BR_FAILED;
+// }
}
else {
// root not supported for integers.
diff --git a/src/tactic/bv/bit_blaster_tactic.h b/src/tactic/bv/bit_blaster_tactic.h
index cb7f6f7a9..d840154b9 100644
--- a/src/tactic/bv/bit_blaster_tactic.h
+++ b/src/tactic/bv/bit_blaster_tactic.h
@@ -1,32 +1,33 @@
-/*++
+ /*++
Copyright (c) 2011 Microsoft Corporation
-
-Module Name:
-
+
+ Module Name:
+
bit_blaster_tactic.h
-
-Abstract:
-
+
+ Abstract:
+
Apply bit-blasting to a given goal.
-
-Author:
-
+
+ Author:
+
Leonardo (leonardo) 2011-10-25
-
-Notes:
-
---*/
+
+ Notes:
+
+ --*/
#ifndef BIT_BLASTER_TACTIC_H_
#define BIT_BLASTER_TACTIC_H_
-
-#include"params.h"
-#include"bit_blaster_rewriter.h"
-class ast_manager;
-class tactic;
-
+
+ #include"params.h"
+ #include"bit_blaster_rewriter.h"
+ class ast_manager;
+ class tactic;
+
tactic * mk_bit_blaster_tactic(ast_manager & m, params_ref const & p = params_ref());
tactic * mk_bit_blaster_tactic(ast_manager & m, bit_blaster_rewriter* rw, params_ref const & p = params_ref());
-/*
+ /*
ADD_TACTIC("bit-blast", "reduce bit-vector expressions into SAT.", "mk_bit_blaster_tactic(m, p)")
-*/
-#endif
+ */
+ #endif
+
diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp
index f1ffe4b53..e436d19c4 100644
--- a/src/tactic/core/solve_eqs_tactic.cpp
+++ b/src/tactic/core/solve_eqs_tactic.cpp
@@ -22,7 +22,7 @@ Revision History:
#include"occurs.h"
#include"cooperate.h"
#include"goal_shared_occs.h"
-#include"ast_smt2_pp.h"
+#include"ast_pp.h"
class solve_eqs_tactic : public tactic {
struct imp {
@@ -92,21 +92,23 @@ class solve_eqs_tactic : public tactic {
}
// Use: (= x def) and (= def x)
- bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) {
+
+ bool trivial_solve1(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) {
+
if (is_uninterp_const(lhs) && !m_candidate_vars.is_marked(lhs) && !occurs(lhs, rhs) && check_occs(lhs)) {
var = to_app(lhs);
def = rhs;
pr = 0;
return true;
}
- else if (is_uninterp_const(rhs) && !m_candidate_vars.is_marked(rhs) && !occurs(rhs, lhs) && check_occs(rhs)) {
- var = to_app(rhs);
- def = lhs;
- if (m_produce_proofs)
- pr = m().mk_commutativity(m().mk_eq(lhs, rhs));
- return true;
+ else {
+ return false;
}
- return false;
+ }
+ bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) {
+ return
+ trivial_solve1(lhs, rhs, var, def, pr) ||
+ trivial_solve1(rhs, lhs, var, def, pr);
}
// (ite c (= x t1) (= x t2)) --> (= x (ite c t1 t2))
diff --git a/src/tactic/fpa/fpa2bv_model_converter.cpp b/src/tactic/fpa/fpa2bv_model_converter.cpp
index fdbe54c4d..799083a5f 100644
--- a/src/tactic/fpa/fpa2bv_model_converter.cpp
+++ b/src/tactic/fpa/fpa2bv_model_converter.cpp
@@ -132,7 +132,7 @@ expr_ref fpa2bv_model_converter::convert_bv2fp(sort * s, expr * sgn, expr * exp,
mpzm.set(sig_z, sig_q.to_mpq().numerator());
exp_z = mpzm.get_int64(exp_unbiased_q.to_mpq().numerator());
- fu.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), sig_z, exp_z);
+ fu.fm().set(fp_val, ebits, sbits, !mpqm.is_zero(sgn_q.to_mpq()), exp_z, sig_z);
mpzm.del(sig_z);
diff --git a/src/tactic/smtlogics/quant_tactics.cpp b/src/tactic/smtlogics/quant_tactics.cpp
index 937b0229e..8714b055f 100644
--- a/src/tactic/smtlogics/quant_tactics.cpp
+++ b/src/tactic/smtlogics/quant_tactics.cpp
@@ -102,7 +102,8 @@ tactic * mk_lra_tactic(ast_manager & m, params_ref const & p) {
or_else(try_for(mk_smt_tactic(), 100),
try_for(qe::mk_sat_tactic(m), 1000),
try_for(mk_smt_tactic(), 1000),
- and_then(mk_qe_tactic(m), mk_smt_tactic())));
+ and_then(mk_qe_tactic(m), mk_smt_tactic())
+ ));
st->updt_params(p);
return st;
diff --git a/src/test/algebraic.cpp b/src/test/algebraic.cpp
index 7c0fb4a95..af7270825 100644
--- a/src/test/algebraic.cpp
+++ b/src/test/algebraic.cpp
@@ -19,35 +19,37 @@ Notes:
#include"algebraic_numbers.h"
#include"polynomial_var2value.h"
#include"mpbq.h"
+#include"rlimit.h"
static void display_anums(std::ostream & out, scoped_anum_vector const & rs) {
out << "numbers in decimal:\n";
algebraic_numbers::manager & m = rs.m();
for (unsigned i = 0; i < rs.size(); i++) {
- m.display_decimal(out, rs[i], 10);
+ m.display_decimal(out, rs[i], 10);
out << "\n";
}
out << "numbers as root objects\n";
for (unsigned i = 0; i < rs.size(); i++) {
- m.display_root(out, rs[i]);
+ m.display_root(out, rs[i]);
out << "\n";
- }
+ }
out << "numbers as intervals\n";
for (unsigned i = 0; i < rs.size(); i++) {
- m.display_interval(out, rs[i]);
+ m.display_interval(out, rs[i]);
out << "\n";
- }
+ }
}
static void tst1() {
+ reslimit rl;
unsynch_mpq_manager nm;
- polynomial::manager m(nm);
+ polynomial::manager m(rl, nm);
polynomial_ref x(m);
x = m.mk_polynomial(m.mk_var());
polynomial_ref p(m);
p = 3*x - 2;
- algebraic_numbers::manager am(nm);
+ algebraic_numbers::manager am(rl, nm);
scoped_anum_vector rs1(am);
std::cout << "p: " << p << "\n";
am.isolate_roots(p, rs1);
@@ -69,16 +71,16 @@ static void tst1() {
nm.set(q, 1, 3);
scoped_anum aq(am);
am.set(aq, q); // create algebraic number representing 1/3
-
+
am.add(sqrt2, aq, aq);
- std::cout << "sqrt(2) + 1/3: ";
- am.display_decimal(std::cout, aq, 10); std::cout << " "; am.display_interval(std::cout, aq);
+ std::cout << "sqrt(2) + 1/3: ";
+ am.display_decimal(std::cout, aq, 10); std::cout << " "; am.display_interval(std::cout, aq);
std::cout << " "; am.display_root(std::cout, aq); std::cout << "\n";
- am.set(aq, q);
+ am.set(aq, q);
am.add(rs1[0], aq, aq);
- std::cout << "-sqrt(2) + 1/3: ";
- am.display_decimal(std::cout, aq, 10); std::cout << " "; am.display_interval(std::cout, aq);
+ std::cout << "-sqrt(2) + 1/3: ";
+ am.display_decimal(std::cout, aq, 10); std::cout << " "; am.display_interval(std::cout, aq);
std::cout << " "; am.display_root(std::cout, aq); std::cout << "\n";
p = ((x^5) - x - 1)*(x-1)*(x-2);
@@ -92,7 +94,7 @@ static void tst1() {
am.set(gauss, rs1[1]);
std::cout << "compare(" << sqrt2 << ", " << gauss << "): " << am.compare(sqrt2, gauss) << "\n";
-
+
statistics st;
am.collect_statistics(st);
st.display_smt2(std::cout);
@@ -103,7 +105,7 @@ static void tst1() {
am.isolate_roots(p, rs1);
display_anums(std::cout, rs1);
SASSERT(rs1.size() == 4);
-
+
scoped_anum hidden_sqrt2(am);
am.set(hidden_sqrt2, rs1[2]);
@@ -116,7 +118,7 @@ static void tst1() {
SASSERT(is_int(power(sqrt2, 4)));
SASSERT(power(sqrt2, 4) == 4);
-
+
scoped_anum sqrt2_gauss(am);
am.add(sqrt2, gauss, sqrt2_gauss);
std::cout << "sqrt2 + gauss: " << sqrt2_gauss << " "; am.display_root(std::cout, sqrt2_gauss); std::cout << "\n";
@@ -151,22 +153,22 @@ static void tst1() {
am.mul(tmp, sqrt2, tmp);
std::cout << "sqrt(2)*4*(1/sqrt2): " << tmp << " " << root_obj_pp(tmp) << "\n";
std::cout << "is_int(sqrt(2)*4*(1/sqrt2)): " << am.is_int(tmp) << ", after is-int: " << tmp << "\n";
-
+
p = (998*x - 1414)*((x^2) - 15);
std::cout << "p: " << p << "\n";
rs1.reset();
am.isolate_roots(p, rs1);
-
+
std::cout << "is-rational(sqrt2): " << am.is_rational(sqrt2) << "\n";
-
+
scoped_anum qr(am);
am.set(qr, rs1[1]);
-
+
std::cout << "qr: " << root_obj_pp(qr);
std::cout << ", is-rational: " << am.is_rational(qr) << ", val: " << root_obj_pp(qr) << "\n";
return;
-
+
std::cout << "compare(" << sqrt2 << ", " << gauss << "): " << am.compare(sqrt2, gauss) << "\n";
p = (x^16) - 136*(x^14) + 6476*(x^12) - 141912*(x^10) + 1513334*(x^8) - 7453176*(x^6) + 13950764*(x^4) - 5596840*(x^2) + 46225;
@@ -216,25 +218,26 @@ void tst_mpbq_root() {
mpbq_manager bqm(qm);
// scoped_mpbq q(bqm);
// q.set(q1, 1.4142135 , 7);
-
+
}
static void tst_wilkinson() {
// Test Wilkinson Polynomial
+ reslimit rl;
unsynch_mpq_manager nm;
- polynomial::manager m(nm);
+ polynomial::manager m(rl, nm);
polynomial_ref x(m);
x = m.mk_polynomial(m.mk_var());
polynomial_ref p(m);
for (int i = 1; i <= 20; i++) {
- if (i > 1)
+ if (i > 1)
p = p*(x - i);
- else
+ else
p = (x - i);
}
std::cout << "Wilkinson's polynomial: " << p << "\n";
- algebraic_numbers::manager am(nm);
+ algebraic_numbers::manager am(rl, nm);
scoped_anum_vector rs1(am);
std::cout << "p: " << p << "\n";
am.isolate_roots(p, rs1);
@@ -246,9 +249,10 @@ static void tst_wilkinson() {
}
static void tst_dejan() {
+ reslimit rl;
unsynch_mpq_manager qm;
- algebraic_numbers::manager am(qm);
-
+ algebraic_numbers::manager am(rl, qm);
+
scoped_anum two101(am);
am.set(two101, 2);
am.root(two101, 11, two101);
@@ -256,7 +260,7 @@ static void tst_dejan() {
scoped_anum two103(am);
am.set(two103, 2);
am.root(two103, 7, two103);
-
+
std::cout << "two101: " << two101 << " " << root_obj_pp(two101) << std::endl;
std::cout << "two103: " << two103 << " " << root_obj_pp(two103) << std::endl;
@@ -332,9 +336,10 @@ static void tst_eval_sign(polynomial_ref const & p, anum_manager & am,
static void tst_eval_sign() {
enable_trace("anum_eval_sign");
+ reslimit rl;
unsynch_mpq_manager qm;
- polynomial::manager pm(qm);
- algebraic_numbers::manager am(qm);
+ polynomial::manager pm(rl, qm);
+ algebraic_numbers::manager am(rl, qm);
polynomial_ref x0(pm);
polynomial_ref x1(pm);
polynomial_ref x2(pm);
@@ -351,7 +356,7 @@ static void tst_eval_sign() {
am.set(v1, 1);
am.set(v0, -3);
tst_eval_sign(p, am, 0, v0, 1, v1, 2, v2, -1);
-
+
am.set(v0, 2);
am.root(v0, 2, v0);
am.set(v1, 0);
@@ -412,9 +417,10 @@ static void tst_isolate_roots(polynomial_ref const & p, anum_manager & am,
static void tst_isolate_roots() {
enable_trace("isolate_roots");
+ reslimit rl;
unsynch_mpq_manager qm;
- polynomial::manager pm(qm);
- algebraic_numbers::manager am(qm);
+ polynomial::manager pm(rl, qm);
+ algebraic_numbers::manager am(rl, qm);
polynomial_ref x0(pm);
polynomial_ref x1(pm);
polynomial_ref x2(pm);
@@ -423,7 +429,7 @@ static void tst_isolate_roots() {
x1 = pm.mk_polynomial(pm.mk_var());
x2 = pm.mk_polynomial(pm.mk_var());
x3 = pm.mk_polynomial(pm.mk_var());
-
+
polynomial_ref p(pm);
p = x3*x1 + 1;
@@ -432,44 +438,44 @@ static void tst_isolate_roots() {
tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
am.set(v1, 1);
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
am.set(v1, 2);
am.root(v1, 2, v1);
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
-
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+
p = (x1 + x2)*x3 + 1;
am.set(v2, v1);
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
-
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+
p = (x1 + x2)*x3 + x1*x2 + 2;
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
p = (x1 + x2)*(x3^3) + x1*x2 + 2;
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
p = (x1 + x2)*(x3^2) - x1*x2 - 2;
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
-
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+
p = x0*(x1 + x2)*(x3^2) - x0*x1*x2 - 2;
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
p = (x1 - x2)*x3 + x1*x2 - 2;
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
p = (x1 - x2)*(x3^3) + x1*x2 - 2;
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
-
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+
p = (x3 - x0)*(x3 - x0 - x1);
am.set(v0, 2);
am.root(v0, 2, v0); // x2 -> sqrt(2)
am.set(v1, 3);
am.root(v1, 2, v1); // x1 -> sqrt(3)
am.reset(v2);
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
-
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+
p = (x3 - x0)*((x3 - x0 - x1)^2);
- tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
+ tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
p = (x3 - x0)*(x3 - 2)*((x3 - 1)^2)*(x3 - x1);
tst_isolate_roots(p, am, 0, v0, 1, v1, 2, v2);
@@ -485,7 +491,8 @@ static void pp(polynomial_ref const & p, polynomial::var x) {
static void ex1() {
unsynch_mpq_manager qm;
- polynomial::manager pm(qm);
+ reslimit rl;
+ polynomial::manager pm(rl, qm);
polynomial_ref x(pm);
polynomial_ref a(pm);
polynomial_ref b(pm);
@@ -508,7 +515,7 @@ static void ex1() {
std::cout << "d: " << d << "\n";
std::cout << "h3: "; pp(h3, 0); std::cout << "\n";
- algebraic_numbers::manager am(qm);
+ algebraic_numbers::manager am(rl, qm);
scoped_anum v1(am), v2(am);
am.set(v1, 2);
am.root(v1, 3, v1);
@@ -542,8 +549,9 @@ static void ex1() {
}
static void tst_root() {
+ reslimit rl;
unsynch_mpq_manager qm;
- algebraic_numbers::manager am(qm);
+ algebraic_numbers::manager am(rl, qm);
scoped_anum v1(am), v2(am);
am.set(v1, 4);
am.root(v1, 2, v2);
@@ -551,7 +559,7 @@ static void tst_root() {
am.set(v1, 4);
am.root(v1, 4, v2);
std::cout << "root: " << root_obj_pp(v2) << "\n";
-
+
}
void tst_algebraic() {
diff --git a/src/test/hilbert_basis.cpp b/src/test/hilbert_basis.cpp
index 57c8c5050..b46ede849 100644
--- a/src/test/hilbert_basis.cpp
+++ b/src/test/hilbert_basis.cpp
@@ -12,6 +12,7 @@ Copyright (c) 2015 Microsoft Corporation
#include "tactic.h"
#include "tactic2solver.h"
#include "solver.h"
+#include "rlimit.h"
#include
#include
#include
@@ -38,7 +39,7 @@ class hilbert_basis_validate {
}
public:
-
+
hilbert_basis_validate(ast_manager& m);
expr_ref mk_validate(hilbert_basis& hb);
@@ -46,7 +47,7 @@ public:
};
-hilbert_basis_validate::hilbert_basis_validate(ast_manager& m):
+hilbert_basis_validate::hilbert_basis_validate(ast_manager& m):
m(m) {
}
@@ -86,7 +87,7 @@ void hilbert_basis_validate::validate_solution(hilbert_basis& hb, vector v;
- // check that claimed solution really satisfies inequalities:
+ // check that claimed solution really satisfies inequalities:
for (unsigned i = 0; i < sz; ++i) {
bool is_initial;
hb.get_basis_solution(i, v, is_initial);
@@ -111,7 +112,7 @@ expr_ref hilbert_basis_validate::mk_validate(hilbert_basis& hb) {
sort_ref_vector sorts(m);
#define mk_mul(_r,_x) (_r.is_one()?((expr*)_x):((expr*)a.mk_mul(a.mk_numeral(_r,true),_x)))
-
+
for (unsigned i = 0; i < sz; ++i) {
bool is_initial;
@@ -169,7 +170,7 @@ expr_ref hilbert_basis_validate::mk_validate(hilbert_basis& hb) {
}
fml1 = m.mk_or(fmls.size(), fmls.c_ptr());
fmls.reset();
-
+
sz = hb.get_num_ineqs();
for (unsigned i = 0; i < sz; ++i) {
bool is_eq;
@@ -194,7 +195,7 @@ expr_ref hilbert_basis_validate::mk_validate(hilbert_basis& hb) {
}
fml2 = m.mk_and(fmls.size(), fmls.c_ptr());
fml = m.mk_eq(fml1, fml2);
-
+
bounds.reset();
for (unsigned i = 0; i < xs.size(); ++i) {
if (!hb.get_is_int(i)) {
@@ -221,7 +222,7 @@ static void display_statistics(hilbert_basis& hb) {
}
static void on_ctrl_c(int) {
- signal (SIGINT, SIG_DFL);
+ signal (SIGINT, SIG_DFL);
display_statistics(*g_hb);
raise(SIGINT);
}
@@ -258,17 +259,17 @@ static void saturate_basis(hilbert_basis& hb) {
lbool is_sat = hb.saturate();
switch(is_sat) {
- case l_true:
- std::cout << "sat\n";
+ case l_true:
+ std::cout << "sat\n";
hb.display(std::cout);
//validate_sat(hb);
break;
- case l_false:
- std::cout << "unsat\n";
+ case l_false:
+ std::cout << "unsat\n";
+ break;
+ case l_undef:
+ std::cout << "undef\n";
break;
- case l_undef:
- std::cout << "undef\n";
- break;
}
display_statistics(hb);
}
@@ -283,7 +284,8 @@ static void saturate_basis(hilbert_basis& hb) {
static void gorrila_test(unsigned seed, unsigned n, unsigned k, unsigned bound, unsigned num_ineqs) {
std::cout << "Gorrila test\n";
random_gen rand(seed);
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
SASSERT(0 < bound);
SASSERT(k <= n);
int ibound = static_cast(bound);
@@ -303,7 +305,7 @@ static void gorrila_test(unsigned seed, unsigned n, unsigned k, unsigned bound,
}
a0 = rational(ibound - static_cast(rand(2*bound+1)));
hb.add_ge(nv, a0);
- }
+ }
hb.display(std::cout << "Saturate\n");
saturate_basis(hb);
}
@@ -368,7 +370,8 @@ static vector vec(int i, int j, int k, int l, int x, int y, int z) {
// -y + z <= 0
static void tst1() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_eq(vec(1,1,-2));
hb.add_eq(vec(1,0,-1));
hb.add_le(vec(0,1,-1));
@@ -380,7 +383,8 @@ static void tst1() {
// 23x - 12y - 9z <= 0
// x - 8y - 8z <= 0
void tst2() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_eq(vec(-23,12,9));
hb.add_eq(vec(-1,8,8));
@@ -391,7 +395,8 @@ void tst2() {
// example 6, Ajili, Contenjean
// 3x + 2y - z - 2u <= 0
static void tst3() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec(3,2,-1,-2));
saturate_basis(hb);
}
@@ -400,7 +405,8 @@ static void tst3() {
// Sigma_1, table 1, Ajili, Contejean
static void tst4() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec( 0,-2, 1, 3, 2,-2, 3), R(3));
hb.add_le(vec(-1, 7, 0, 1, 3, 5,-4), R(2));
hb.add_le(vec( 0,-1, 1,-1,-1, 0, 0), R(2));
@@ -416,7 +422,8 @@ static void tst4() {
// Sigma_2 table 1, Ajili, Contejean
static void tst5() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec( 1, 2,-1, 1), R(3));
hb.add_le(vec( 2, 4, 1, 2), R(12));
hb.add_le(vec( 1, 4, 2, 1), R(9));
@@ -429,7 +436,8 @@ static void tst5() {
// Sigma_3 table 1, Ajili, Contejean
static void tst6() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec( 4, 3, 0), R(6));
hb.add_le(vec(-3,-4, 0), R(-1));
hb.add_le(vec( 4, 0,-3), R(3));
@@ -441,7 +449,8 @@ static void tst6() {
// Sigma_4 table 1, Ajili, Contejean
static void tst7() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_eq(vec( 1, 1, 1, 0), R(5));
hb.add_le(vec( 2, 1, 0, 1), R(6));
hb.add_le(vec( 1, 2, 1, 1), R(7));
@@ -454,7 +463,8 @@ static void tst7() {
// Sigma_5 table 1, Ajili, Contejean
static void tst8() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec( 2, 1, 1), R(2));
hb.add_le(vec( 1, 2, 3), R(5));
hb.add_le(vec( 2, 2, 3), R(6));
@@ -464,7 +474,8 @@ static void tst8() {
// Sigma_6 table 1, Ajili, Contejean
static void tst9() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec( 1, 2, 3), R(11));
hb.add_le(vec( 2, 2, 5), R(13));
hb.add_le(vec( 1,-1,-11), R(3));
@@ -473,7 +484,8 @@ static void tst9() {
// Sigma_7 table 1, Ajili, Contejean
static void tst10() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec( 1,-1,-1,-3), R(2));
hb.add_le(vec(-2, 3, 3,-5), R(3));
saturate_basis(hb);
@@ -481,14 +493,16 @@ static void tst10() {
// Sigma_8 table 1, Ajili, Contejean
static void tst11() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec( 7,-2,11, 3, -5), R(5));
saturate_basis(hb);
}
// Sigma_9 table 1, Ajili, Contejean
static void tst12() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_eq(vec( 1,-2,-3,4), R(0));
hb.add_le(vec(100,45,-78,-67), R(0));
saturate_basis(hb);
@@ -496,34 +510,39 @@ static void tst12() {
// Sigma_10 table 1, Ajili, Contejean
static void tst13() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec( 23, -56, -34, 12, 11), R(0));
saturate_basis(hb);
}
// Sigma_11 table 1, Ajili, Contejean
static void tst14() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_eq(vec(1, 0, -4, 8), R(2));
hb.add_le(vec(12,19,-11,-7), R(-7));
saturate_basis(hb);
}
static void tst15() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec(1, 0), R(1));
hb.add_le(vec(0, 1), R(1));
saturate_basis(hb);
}
static void tst16() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_le(vec(1, 0), R(100));
saturate_basis(hb);
}
static void tst17() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_eq(vec(1, 0), R(0));
hb.add_eq(vec(-1, 0), R(0));
hb.add_eq(vec(0, 2), R(0));
@@ -533,26 +552,29 @@ static void tst17() {
}
static void tst18() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_eq(vec(0, 1), R(0));
hb.add_eq(vec(1, -1), R(2));
- saturate_basis(hb);
+ saturate_basis(hb);
}
static void tst19() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
hb.add_eq(vec(0, 1, 0), R(0));
hb.add_eq(vec(1, -1, 0), R(2));
- saturate_basis(hb);
+ saturate_basis(hb);
}
static void test_A_5_5_3() {
- hilbert_basis hb;
+ reslimit rl;
+ hilbert_basis hb(rl);
for (unsigned i = 0; i < 15; ++i) {
vector v;
for (unsigned j = 0; j < 5; ++j) {
for (unsigned k = 0; k < 15; ++k) {
- v.push_back(rational(k == i));
+ v.push_back(rational(k == i));
}
}
hb.add_ge(v, R(0));
diff --git a/src/test/interval.cpp b/src/test/interval.cpp
index ef733394b..ac242cc60 100644
--- a/src/test/interval.cpp
+++ b/src/test/interval.cpp
@@ -22,6 +22,7 @@ Revision History:
#include"mpq.h"
#include"ast.h"
#include"debug.h"
+#include"rlimit.h"
template class interval_manager;
typedef im_default_config::interval interval;
@@ -61,7 +62,7 @@ static void display_smt2_numeral(std::ostream & out, unsynch_mpq_manager & m, mp
}
}
-static void display_constraint(std::ostream & out, unsynch_mpq_manager & m, char const * a, interval const & i,
+static void display_constraint(std::ostream & out, unsynch_mpq_manager & m, char const * a, interval const & i,
bool include_lower = true, bool include_upper = true) {
out << "(and true";
if (!i.m_lower_inf && include_lower) {
@@ -77,7 +78,7 @@ static void display_constraint(std::ostream & out, unsynch_mpq_manager & m, char
out << ")";
}
-static void assert_hyp(std::ostream & out, unsynch_mpq_manager & m, char const * a, interval const & i,
+static void assert_hyp(std::ostream & out, unsynch_mpq_manager & m, char const * a, interval const & i,
bool include_lower = true, bool include_upper = true) {
out << "(assert ";
display_constraint(out, m, a, i, include_lower, include_upper);
@@ -99,7 +100,7 @@ static bool mk_interval(im_default_config & cfg, interval & a, bool l_inf, bool
if (l_val == u_val && (l_open || u_open))
return false;
}
-
+
if (l_inf) {
a.m_lower_open = true;
a.m_lower_inf = true;
@@ -119,7 +120,7 @@ static bool mk_interval(im_default_config & cfg, interval & a, bool l_inf, bool
a.m_upper_inf = false;
cfg.m().set(a.m_upper, u_val);
}
-
+
return true;
}
#endif
@@ -131,7 +132,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m
if (rand()%4 == 0) {
a.m_lower_open = true;
a.m_lower_inf = true;
-
+
a.m_upper_open = (rand()%2 == 0);
a.m_upper_inf = false;
cfg.m().set(a.m_upper, -static_cast((rand()%magnitude)));
@@ -141,7 +142,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m
a.m_upper_inf = false;
int upper = -static_cast((rand()%magnitude));
cfg.m().set(a.m_upper, upper);
-
+
a.m_lower_open = (rand()%2 == 0);
a.m_lower_inf = false;
cfg.m().set(a.m_lower, upper - static_cast(rand()%magnitude) - (a.m_lower_open || a.m_upper_open ? 1 : 0));
@@ -149,7 +150,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m
break;
case 1:
// Neg, Pos
-
+
if (rand()%4 == 0) {
a.m_lower_open = true;
a.m_lower_inf = true;
@@ -159,7 +160,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m
a.m_lower_inf = false;
cfg.m().set(a.m_lower, -static_cast((rand()%magnitude)) - 1);
}
-
+
if (rand()%4 == 0) {
a.m_upper_open = true;
a.m_upper_inf = true;
@@ -175,7 +176,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m
if (rand()%4 == 0) {
a.m_upper_open = true;
a.m_upper_inf = true;
-
+
a.m_lower_open = (rand()%2 == 0);
a.m_lower_inf = false;
cfg.m().set(a.m_lower, (rand()%magnitude));
@@ -185,7 +186,7 @@ static void mk_random_interval(im_default_config & cfg, interval & a, unsigned m
a.m_lower_inf = false;
int lower = (rand()%magnitude);
cfg.m().set(a.m_lower, lower);
-
+
a.m_upper_open = (rand()%2 == 0);
a.m_upper_inf = false;
cfg.m().set(a.m_upper, lower + rand()%magnitude + (a.m_lower_open || a.m_upper_open ? 1 : 0));
@@ -235,9 +236,10 @@ static void display_lemmas(unsynch_mpq_manager & nm, char const * result_term,
#define MK_BINARY(NAME, RES_TERM) \
static void tst_ ## NAME(unsigned N, unsigned magnitude) { \
+ reslimit rl; \
unsynch_mpq_manager nm; \
im_default_config imc(nm); \
- interval_manager im(imc); \
+ interval_manager im(rl, imc); \
interval a, b, r; \
\
for (unsigned i = 0; i < N; i++) { \
@@ -255,130 +257,137 @@ MK_BINARY(mul, "(* a b)");
MK_BINARY(add, "(+ a b)");
MK_BINARY(sub, "(- a b)");
-static void tst_neg(unsigned N, unsigned magnitude) {
- unsynch_mpq_manager nm;
+static void tst_neg(unsigned N, unsigned magnitude) {
+ reslimit rl;
+ unsynch_mpq_manager nm;
im_default_config imc(nm);
- interval_manager im(imc);
- interval a, b, r;
-
- for (unsigned i = 0; i < N; i++) {
- mk_random_interval(imc, a, magnitude);
- interval_deps deps;
- im.neg(a, r, deps);
- display_lemmas(nm, "(- a)", a, b, r, deps);
- }
- del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
-}
+ interval_manager im(rl, imc);
+ interval a, b, r;
-static void tst_pw_2(unsigned N, unsigned magnitude) {
- unsynch_mpq_manager nm;
- im_default_config imc(nm);
- interval_manager im(imc);
- interval a, b, r;
-
- for (unsigned i = 0; i < N; i++) {
- mk_random_interval(imc, a, magnitude);
- interval_deps deps;
- im.power(a, 2, r, deps);
- display_lemmas(nm, "(* a a)", a, b, r, deps);
- }
- del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
-}
-
-static void tst_pw_3(unsigned N, unsigned magnitude) {
- unsynch_mpq_manager nm;
- im_default_config imc(nm);
- interval_manager im(imc);
- interval a, b, r;
-
- for (unsigned i = 0; i < N; i++) {
- mk_random_interval(imc, a, magnitude);
- interval_deps deps;
- im.power(a, 3, r, deps);
- display_lemmas(nm, "(* a a a)", a, b, r, deps);
+ for (unsigned i = 0; i < N; i++) {
+ mk_random_interval(imc, a, magnitude);
+ interval_deps deps;
+ im.neg(a, r, deps);
+ display_lemmas(nm, "(- a)", a, b, r, deps);
}
- del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
+ del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
}
-static void tst_root_2(unsigned N, unsigned magnitude, unsigned precision) {
- unsynch_mpq_manager nm;
+static void tst_pw_2(unsigned N, unsigned magnitude) {
+ reslimit rl;
+ unsynch_mpq_manager nm;
im_default_config imc(nm);
- interval_manager im(imc);
- interval a, b, r;
+ interval_manager im(rl, imc);
+ interval a, b, r;
+
+ for (unsigned i = 0; i < N; i++) {
+ mk_random_interval(imc, a, magnitude);
+ interval_deps deps;
+ im.power(a, 2, r, deps);
+ display_lemmas(nm, "(* a a)", a, b, r, deps);
+ }
+ del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
+}
+
+static void tst_pw_3(unsigned N, unsigned magnitude) {
+ reslimit rl;
+ unsynch_mpq_manager nm;
+ im_default_config imc(nm);
+ interval_manager im(rl, imc);
+ interval a, b, r;
+
+ for (unsigned i = 0; i < N; i++) {
+ mk_random_interval(imc, a, magnitude);
+ interval_deps deps;
+ im.power(a, 3, r, deps);
+ display_lemmas(nm, "(* a a a)", a, b, r, deps);
+ }
+ del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
+}
+
+static void tst_root_2(unsigned N, unsigned magnitude, unsigned precision) {
+ reslimit rl;
+ unsynch_mpq_manager nm;
+ im_default_config imc(nm);
+ interval_manager im(rl, imc);
+ interval a, b, r;
scoped_mpq p(nm);
p = precision;
nm.inv(p);
unsigned i = 0;
while (i < N) {
- mk_random_interval(imc, a, magnitude);
+ mk_random_interval(imc, a, magnitude);
if (!im.lower_is_neg(a)) {
i++;
- interval_deps deps;
- im.nth_root(a, 2, p, r, deps);
- display_lemmas(nm, "(^ a (/ 1.0 2.0))", a, b, r, deps);
- }
- }
- del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
+ interval_deps deps;
+ im.nth_root(a, 2, p, r, deps);
+ display_lemmas(nm, "(^ a (/ 1.0 2.0))", a, b, r, deps);
+ }
+ }
+ del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
}
-static void tst_root_3(unsigned N, unsigned magnitude, unsigned precision) {
- unsynch_mpq_manager nm;
+static void tst_root_3(unsigned N, unsigned magnitude, unsigned precision) {
+ reslimit rl;
+ unsynch_mpq_manager nm;
im_default_config imc(nm);
- interval_manager im(imc);
- interval a, b, r;
+ interval_manager im(rl, imc);
+ interval a, b, r;
scoped_mpq p(nm);
p = precision;
nm.inv(p);
unsigned i = 0;
while (i < N) {
- mk_random_interval(imc, a, magnitude);
+ mk_random_interval(imc, a, magnitude);
i++;
- interval_deps deps;
- im.nth_root(a, 3, p, r, deps);
- display_lemmas(nm, "(^ a (/ 1.0 3.0))", a, b, r, deps);
- }
- del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
+ interval_deps deps;
+ im.nth_root(a, 3, p, r, deps);
+ display_lemmas(nm, "(^ a (/ 1.0 3.0))", a, b, r, deps);
+ }
+ del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
}
-static void tst_inv(unsigned N, unsigned magnitude) {
- unsynch_mpq_manager nm;
+static void tst_inv(unsigned N, unsigned magnitude) {
+ reslimit rl;
+ unsynch_mpq_manager nm;
im_default_config imc(nm);
- interval_manager im(imc);
- interval a, b, r;
-
- for (unsigned i = 0; i < N; i++) {
+ interval_manager im(rl, imc);
+ interval a, b, r;
+
+ for (unsigned i = 0; i < N; i++) {
while (true) {
- mk_random_interval(imc, a, magnitude);
+ mk_random_interval(imc, a, magnitude);
if (!im.contains_zero(a))
break;
}
- interval_deps deps;
- im.inv(a, r, deps);
- display_lemmas(nm, "(/ 1 a)", a, b, r, deps);
- }
- del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
+ interval_deps deps;
+ im.inv(a, r, deps);
+ display_lemmas(nm, "(/ 1 a)", a, b, r, deps);
+ }
+ del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
}
-static void tst_div(unsigned N, unsigned magnitude) {
- unsynch_mpq_manager nm;
- im_default_config imc(nm);
- interval_manager im(imc);
- interval a, b, r;
+static void tst_div(unsigned N, unsigned magnitude) {
+ reslimit rl;
+ unsynch_mpq_manager nm;
+ im_default_config imc(nm);
+ interval_manager im(rl, imc);
+ interval a, b, r;
- for (unsigned i = 0; i < N; i++) {
- mk_random_interval(imc, a, magnitude);
+ for (unsigned i = 0; i < N; i++) {
+ mk_random_interval(imc, a, magnitude);
while (true) {
- mk_random_interval(imc, b, magnitude);
+ mk_random_interval(imc, b, magnitude);
if (!im.contains_zero(b))
break;
}
- interval_deps deps;
- im.div(a, b, r, deps);
- display_lemmas(nm, "(/ a b)", a, b, r, deps);
- }
- del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
+ interval_deps deps;
+ im.div(a, b, r, deps);
+ display_lemmas(nm, "(/ a b)", a, b, r, deps);
+ }
+ del_interval(imc, a); del_interval(imc, b); del_interval(imc, r);
}
#include"im_float_config.h"
@@ -395,7 +404,7 @@ static void tst_float() {
qm.set(one_third, 1, 3);
qm.set(two_third, 2, 3);
qm.set(minus_two_third, -2, 3);
-
+
ifc.round_to_minus_inf();
ifc.m().set(a.m_lower, minus_one_third);
ifc.round_to_plus_inf();
@@ -405,7 +414,7 @@ static void tst_float() {
ifc.m().set(b.m_lower, minus_two_third);
ifc.round_to_plus_inf();
ifc.m().set(b.m_upper, one_third);
-
+
im.display(std::cout, a);
std::cout << "\n";
im.display(std::cout, b);
@@ -420,13 +429,14 @@ static void tst_float() {
#endif
void tst_pi() {
- unsynch_mpq_manager nm;
+ reslimit rl;
+ unsynch_mpq_manager nm;
im_default_config imc(nm);
- interval_manager im(imc);
+ interval_manager im(rl, imc);
interval r;
for (unsigned i = 0; i < 8; i++) {
im.pi(i, r);
- nm.display_decimal(std::cout, im.lower(r), 32); std::cout << " ";
+ nm.display_decimal(std::cout, im.lower(r), 32); std::cout << " ";
nm.display_decimal(std::cout, im.upper(r), 32); std::cout << "\n";
SASSERT(nm.lt(im.lower(r), im.upper(r)));
}
@@ -436,10 +446,11 @@ void tst_pi() {
#if 0
static void tst_pi_float() {
std::cout << "pi float...\n";
+ reslimit rl;
unsynch_mpq_manager qm;
mpf_manager fm;
im_float_config ifc(fm, 22, 106);
- interval_manager