3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-17 11:26:17 +00:00

Merge remote-tracking branch 'upstream/master' into develop

This commit is contained in:
Murphy Berzish 2017-11-07 13:37:33 -05:00
commit 975368e16a
117 changed files with 2722 additions and 1892 deletions

View file

@ -124,7 +124,7 @@ utility is used to install ``Microsoft.Z3.dll`` into the
[pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/) file [pkg-config](http://www.freedesktop.org/wiki/Software/pkg-config/) file
(``Microsoft.Z3.Sharp.pc``) is also installed which allows the (``Microsoft.Z3.Sharp.pc``) is also installed which allows the
[MonoDevelop](http://www.monodevelop.com/) IDE to find the bindings. Running [MonoDevelop](http://www.monodevelop.com/) IDE to find the bindings. Running
``make uninstall`` will remove the dll from the GAC and the pkg-config file. ``make uninstall`` will remove the dll from the GAC and the ``pkg-config`` file.
See [``examples/dotnet``](examples/dotnet) for examples. See [``examples/dotnet``](examples/dotnet) for examples.
@ -170,8 +170,8 @@ If you do need to install to a non standard prefix a better approach is to use
a [Python virtual environment](https://virtualenv.readthedocs.org/en/latest/) a [Python virtual environment](https://virtualenv.readthedocs.org/en/latest/)
and install Z3 there. Python packages also work for Python3. and install Z3 there. Python packages also work for Python3.
Under Windows, recall to build inside the Visual C++ native command build environment. Under Windows, recall to build inside the Visual C++ native command build environment.
Note that the buit/python/z3 directory should be accessible from where python is used with Z3 Note that the ``build/python/z3`` directory should be accessible from where python is used with Z3
and it depends on libz3.dll to be in the path. and it depends on ``libz3.dll`` to be in the path.
```bash ```bash
virtualenv venv virtualenv venv

View file

@ -7,6 +7,19 @@
# the C++ standard library in resulting in a link failure. # the C++ standard library in resulting in a link failure.
project(Z3_C_EXAMPLE C CXX) project(Z3_C_EXAMPLE C CXX)
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 2.8.12)
# Set C version required to C99
if ("${CMAKE_VERSION}" VERSION_LESS "3.1")
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR
("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 ")
endif()
else()
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_EXTENSIONS OFF)
endif()
find_package(Z3 find_package(Z3
REQUIRED REQUIRED
CONFIG CONFIG

View file

@ -2769,80 +2769,279 @@ void fpa_example() {
double_sort = Z3_mk_fpa_sort(ctx, 11, 53); double_sort = Z3_mk_fpa_sort(ctx, 11, 53);
rm_sort = Z3_mk_fpa_rounding_mode_sort(ctx); 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"); s_rm = Z3_mk_string_symbol(ctx, "rm");
rm = Z3_mk_const(ctx, s_rm, rm_sort); rm = Z3_mk_const(ctx, s_rm, rm_sort);
s_x = Z3_mk_string_symbol(ctx, "x"); s_x = Z3_mk_string_symbol(ctx, "x");
s_y = Z3_mk_string_symbol(ctx, "y"); s_y = Z3_mk_string_symbol(ctx, "y");
x = Z3_mk_const(ctx, s_x, double_sort); x = Z3_mk_const(ctx, s_x, double_sort);
y = Z3_mk_const(ctx, s_y, double_sort); y = Z3_mk_const(ctx, s_y, double_sort);
n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort); n = Z3_mk_fpa_numeral_double(ctx, 42.0, double_sort);
s_x_plus_y = Z3_mk_string_symbol(ctx, "x_plus_y"); s_x_plus_y = Z3_mk_string_symbol(ctx, "x_plus_y");
x_plus_y = Z3_mk_const(ctx, s_x_plus_y, double_sort); x_plus_y = Z3_mk_const(ctx, s_x_plus_y, double_sort);
c1 = Z3_mk_eq(ctx, x_plus_y, Z3_mk_fpa_add(ctx, rm, x, y)); c1 = Z3_mk_eq(ctx, x_plus_y, Z3_mk_fpa_add(ctx, rm, x, y));
args[0] = c1; args[0] = c1;
args[1] = Z3_mk_eq(ctx, x_plus_y, n); args[1] = Z3_mk_eq(ctx, x_plus_y, n);
c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args); c2 = Z3_mk_and(ctx, 2, (Z3_ast*)&args);
args2[0] = c2; args2[0] = c2;
args2[1] = Z3_mk_not(ctx, Z3_mk_eq(ctx, rm, Z3_mk_fpa_rtz(ctx))); args2[1] = Z3_mk_not(ctx, Z3_mk_eq(ctx, rm, Z3_mk_fpa_rtz(ctx)));
c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2); c3 = Z3_mk_and(ctx, 2, (Z3_ast*)&args2);
and_args[0] = Z3_mk_not(ctx, Z3_mk_fpa_is_zero(ctx, y)); and_args[0] = Z3_mk_not(ctx, Z3_mk_fpa_is_zero(ctx, y));
and_args[1] = Z3_mk_not(ctx, Z3_mk_fpa_is_nan(ctx, y)); and_args[1] = Z3_mk_not(ctx, Z3_mk_fpa_is_nan(ctx, y));
and_args[2] = Z3_mk_not(ctx, Z3_mk_fpa_is_infinite(ctx, y)); and_args[2] = Z3_mk_not(ctx, Z3_mk_fpa_is_infinite(ctx, y));
args3[0] = c3; args3[0] = c3;
args3[1] = Z3_mk_and(ctx, 3, and_args); args3[1] = Z3_mk_and(ctx, 3, and_args);
c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3); c4 = Z3_mk_and(ctx, 2, (Z3_ast*)&args3);
printf("c4: %s\n", Z3_ast_to_string(ctx, c4)); 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); Z3_solver_assert(ctx, s, c4);
check(ctx, s, Z3_L_TRUE); check(ctx, s, Z3_L_TRUE);
Z3_solver_pop(ctx, s, 1); Z3_solver_pop(ctx, s, 1);
// Show that the following are equal: // Show that the following are equal:
// (fp #b0 #b10000000001 #xc000000000000) // (fp #b0 #b10000000001 #xc000000000000)
// ((_ to_fp 11 53) #x401c000000000000)) // ((_ to_fp 11 53) #x401c000000000000))
// ((_ to_fp 11 53) RTZ 1.75 2))) // ((_ to_fp 11 53) RTZ 1.75 2)))
// ((_ to_fp 11 53) RTZ 7.0))) // ((_ to_fp 11 53) RTZ 7.0)))
Z3_solver_push(ctx, s); 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, "0", Z3_mk_bv_sort(ctx, 1)),
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))); Z3_mk_numeral(ctx, "3377699720527872", Z3_mk_bv_sort(ctx, 52)));
c2 = Z3_mk_fpa_to_fp_bv(ctx, c2 = Z3_mk_fpa_to_fp_bv(ctx,
Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)), Z3_mk_numeral(ctx, "4619567317775286272", Z3_mk_bv_sort(ctx, 64)),
Z3_mk_fpa_sort(ctx, 11, 53)); 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_fpa_rtz(ctx),
Z3_mk_numeral(ctx, "2", Z3_mk_int_sort(ctx)), /* exponent */ 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_numeral(ctx, "1.75", Z3_mk_real_sort(ctx)), /* significand */
Z3_mk_fpa_sort(ctx, 11, 53)); 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_fpa_rtz(ctx),
Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)), Z3_mk_numeral(ctx, "7.0", Z3_mk_real_sort(ctx)),
Z3_mk_fpa_sort(ctx, 11, 53)); Z3_mk_fpa_sort(ctx, 11, 53));
args3[0] = Z3_mk_eq(ctx, c1, c2); args3[0] = Z3_mk_eq(ctx, c1, c2);
args3[1] = Z3_mk_eq(ctx, c1, c3); args3[1] = Z3_mk_eq(ctx, c1, c3);
args3[2] = Z3_mk_eq(ctx, c1, c4); args3[2] = Z3_mk_eq(ctx, c1, c4);
c5 = Z3_mk_and(ctx, 3, args3); c5 = Z3_mk_and(ctx, 3, args3);
printf("c5: %s\n", Z3_ast_to_string(ctx, c5)); printf("c5: %s\n", Z3_ast_to_string(ctx, c5));
Z3_solver_assert(ctx, s, c5); Z3_solver_assert(ctx, s, c5);
check(ctx, s, Z3_L_TRUE); check(ctx, s, Z3_L_TRUE);
Z3_solver_pop(ctx, s, 1); Z3_solver_pop(ctx, s, 1);
del_solver(ctx, s); del_solver(ctx, s);
Z3_del_context(ctx); Z3_del_context(ctx);
} }
/**
\brief Demonstrates some basic features of model construction
*/
void mk_model_example() {
Z3_context ctx;
Z3_model m;
Z3_sort intSort;
Z3_symbol aSymbol, bSymbol, cSymbol;
Z3_func_decl aFuncDecl, bFuncDecl, cFuncDecl;
Z3_ast aApp, bApp, cApp;
Z3_sort int2intArraySort;
Z3_ast zeroNumeral, oneNumeral, twoNumeral, threeNumeral, fourNumeral;
Z3_sort arrayDomain[1];
Z3_func_decl cAsFuncDecl;
Z3_func_interp cAsFuncInterp;
Z3_ast_vector zeroArgs;
Z3_ast_vector oneArgs;
Z3_ast cFuncDeclAsArray;
Z3_string modelAsString;
printf("\nmk_model_example\n");
ctx = mk_context();
// Construct empty model
m = Z3_mk_model(ctx);
Z3_model_inc_ref(ctx, m);
// Create constants "a" and "b"
intSort = Z3_mk_int_sort(ctx);
aSymbol = Z3_mk_string_symbol(ctx, "a");
aFuncDecl = Z3_mk_func_decl(ctx, aSymbol,
/*domain_size=*/0,
/*domain=*/NULL,
/*range=*/intSort);
aApp = Z3_mk_app(ctx, aFuncDecl,
/*num_args=*/0,
/*args=*/NULL);
bSymbol = Z3_mk_string_symbol(ctx, "b");
bFuncDecl = Z3_mk_func_decl(ctx, bSymbol,
/*domain_size=*/0,
/*domain=*/NULL,
/*range=*/intSort);
bApp = Z3_mk_app(ctx, bFuncDecl,
/*num_args=*/0,
/*args=*/NULL);
// Create array "c" that maps int to int.
cSymbol = Z3_mk_string_symbol(ctx, "c");
int2intArraySort = Z3_mk_array_sort(ctx,
/*domain=*/intSort,
/*range=*/intSort);
cFuncDecl = Z3_mk_func_decl(ctx, cSymbol,
/*domain_size=*/0,
/*domain=*/NULL,
/*range=*/int2intArraySort);
cApp = Z3_mk_app(ctx, cFuncDecl,
/*num_args=*/0,
/*args=*/NULL);
// Create numerals to be used in model
zeroNumeral = Z3_mk_int(ctx, 0, intSort);
oneNumeral = Z3_mk_int(ctx, 1, intSort);
twoNumeral = Z3_mk_int(ctx, 2, intSort);
threeNumeral = Z3_mk_int(ctx, 3, intSort);
fourNumeral = Z3_mk_int(ctx, 4, intSort);
// Add assignments to model
// a == 1
Z3_add_const_interp(ctx, m, aFuncDecl, oneNumeral);
// b == 2
Z3_add_const_interp(ctx, m, bFuncDecl, twoNumeral);
// Create a fresh function that represents
// reading from array.
arrayDomain[0] = intSort;
cAsFuncDecl = Z3_mk_fresh_func_decl(ctx,
/*prefix=*/"",
/*domain_size*/ 1,
/*domain=*/arrayDomain,
/*sort=*/intSort);
// Create function interpretation with default
// value of "0".
cAsFuncInterp =
Z3_add_func_interp(ctx, m, cAsFuncDecl,
/*default_value=*/zeroNumeral);
Z3_func_interp_inc_ref(ctx, cAsFuncInterp);
// Add [0] = 3
zeroArgs = Z3_mk_ast_vector(ctx);
Z3_ast_vector_inc_ref(ctx, zeroArgs);
Z3_ast_vector_push(ctx, zeroArgs, zeroNumeral);
Z3_func_interp_add_entry(ctx, cAsFuncInterp, zeroArgs, threeNumeral);
// Add [1] = 4
oneArgs = Z3_mk_ast_vector(ctx);
Z3_ast_vector_inc_ref(ctx, oneArgs);
Z3_ast_vector_push(ctx, oneArgs, oneNumeral);
Z3_func_interp_add_entry(ctx, cAsFuncInterp, oneArgs, fourNumeral);
// Now use the `(_ as_array)` to associate
// the `cAsFuncInterp` with the `cFuncDecl`
// in the model
cFuncDeclAsArray = Z3_mk_as_array(ctx, cAsFuncDecl);
Z3_add_const_interp(ctx, m, cFuncDecl, cFuncDeclAsArray);
// Print the model
modelAsString = Z3_model_to_string(ctx, m);
printf("Model:\n%s\n", modelAsString);
// Check the interpretations we expect to be present
// are.
{
Z3_func_decl expectedInterpretations[3] = {aFuncDecl, bFuncDecl, cFuncDecl};
int index;
for (index = 0;
index < sizeof(expectedInterpretations) / sizeof(Z3_func_decl);
++index) {
Z3_func_decl d = expectedInterpretations[index];
if (Z3_model_has_interp(ctx, m, d)) {
printf("Found interpretation for \"%s\"\n",
Z3_ast_to_string(ctx, Z3_func_decl_to_ast(ctx, d)));
} else {
printf("Missing interpretation");
exit(1);
}
}
}
{
// Evaluate a + b under model
Z3_ast addArgs[] = {aApp, bApp};
Z3_ast aPlusB = Z3_mk_add(ctx,
/*num_args=*/2,
/*args=*/addArgs);
Z3_ast aPlusBEval = NULL;
Z3_bool aPlusBEvalSuccess =
Z3_model_eval(ctx, m, aPlusB,
/*model_completion=*/Z3_FALSE, &aPlusBEval);
if (aPlusBEvalSuccess != Z3_TRUE) {
printf("Failed to evaluate model\n");
exit(1);
}
{
int aPlusBValue = 0;
Z3_bool getAPlusBValueSuccess =
Z3_get_numeral_int(ctx, aPlusBEval, &aPlusBValue);
if (getAPlusBValueSuccess != Z3_TRUE) {
printf("Failed to get integer value for a+b\n");
exit(1);
}
printf("Evaluated a + b = %d\n", aPlusBValue);
if (aPlusBValue != 3) {
printf("a+b did not evaluate to expected value\n");
exit(1);
}
}
}
{
// Evaluate c[0] + c[1] + c[2] under model
Z3_ast c0 = Z3_mk_select(ctx, cApp, zeroNumeral);
Z3_ast c1 = Z3_mk_select(ctx, cApp, oneNumeral);
Z3_ast c2 = Z3_mk_select(ctx, cApp, twoNumeral);
Z3_ast arrayAddArgs[] = {c0, c1, c2};
Z3_ast arrayAdd = Z3_mk_add(ctx,
/*num_args=*/3,
/*args=*/arrayAddArgs);
Z3_ast arrayAddEval = NULL;
Z3_bool arrayAddEvalSuccess =
Z3_model_eval(ctx, m, arrayAdd,
/*model_completion=*/Z3_FALSE, &arrayAddEval);
if (arrayAddEvalSuccess != Z3_TRUE) {
printf("Failed to evaluate model\n");
exit(1);
}
{
int arrayAddValue = 0;
Z3_bool getArrayAddValueSuccess =
Z3_get_numeral_int(ctx, arrayAddEval, &arrayAddValue);
if (getArrayAddValueSuccess != Z3_TRUE) {
printf("Failed to get integer value for c[0] + c[1] + c[2]\n");
exit(1);
}
printf("Evaluated c[0] + c[1] + c[2] = %d\n", arrayAddValue);
if (arrayAddValue != 7) {
printf("c[0] + c[1] + c[2] did not evaluate to expected value\n");
exit(1);
}
}
}
Z3_ast_vector_dec_ref(ctx, oneArgs);
Z3_ast_vector_dec_ref(ctx, zeroArgs);
Z3_func_interp_dec_ref(ctx, cAsFuncInterp);
Z3_model_dec_ref(ctx, m);
Z3_del_context(ctx);
}
/*@}*/ /*@}*/
/*@}*/ /*@}*/
int main() { int main() {
#ifdef LOG_Z3_CALLS #ifdef LOG_Z3_CALLS
Z3_open_log("z3.log"); Z3_open_log("z3.log");
@ -2886,5 +3085,6 @@ int main() {
substitute_example(); substitute_example();
substitute_vars_example(); substitute_vars_example();
fpa_example(); fpa_example();
mk_model_example();
return 0; return 0;
} }

View file

@ -37,20 +37,20 @@ def init_project_def():
add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic')
add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic')
add_lib('aig_tactic', ['tactic'], 'tactic/aig') add_lib('aig_tactic', ['tactic'], 'tactic/aig')
add_lib('solver', ['model', 'tactic']) add_lib('proofs', ['rewriter', 'util'], 'ast/proofs')
add_lib('solver', ['model', 'tactic', 'proofs'])
add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization')
add_lib('interp', ['solver']) add_lib('interp', ['solver'])
add_lib('cmd_context', ['solver', 'rewriter', 'interp']) add_lib('cmd_context', ['solver', 'rewriter', 'interp'])
add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds') add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds')
add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2')
add_lib('proof_checker', ['rewriter'], 'ast/proof_checker')
add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa')
add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern') add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern')
add_lib('bit_blaster', ['rewriter', 'rewriter'], 'ast/rewriter/bit_blaster') add_lib('bit_blaster', ['rewriter', 'rewriter'], 'ast/rewriter/bit_blaster')
add_lib('smt_params', ['ast', 'rewriter', 'pattern', 'bit_blaster'], 'smt/params') add_lib('smt_params', ['ast', 'rewriter', 'pattern', 'bit_blaster'], 'smt/params')
add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model') add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model')
add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model', add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model',
'substitution', 'grobner', 'euclid', 'simplex', 'proof_checker', 'pattern', 'parser_util', 'fpa', 'lp']) 'substitution', 'grobner', 'euclid', 'simplex', 'proofs', 'pattern', 'parser_util', 'fpa', 'lp'])
add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv') add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv')
add_lib('fuzzing', ['ast'], 'test/fuzzing') add_lib('fuzzing', ['ast'], 'test/fuzzing')
add_lib('smt_tactic', ['smt'], 'smt/tactic') add_lib('smt_tactic', ['smt'], 'smt/tactic')

View file

@ -72,6 +72,7 @@ IS_FREEBSD=False
IS_OPENBSD=False IS_OPENBSD=False
IS_CYGWIN=False IS_CYGWIN=False
IS_CYGWIN_MINGW=False IS_CYGWIN_MINGW=False
IS_MSYS2=False
VERBOSE=True VERBOSE=True
DEBUG_MODE=False DEBUG_MODE=False
SHOW_CPPS = True SHOW_CPPS = True
@ -152,6 +153,9 @@ def is_cygwin():
def is_cygwin_mingw(): def is_cygwin_mingw():
return IS_CYGWIN_MINGW return IS_CYGWIN_MINGW
def is_msys2():
return IS_MSYS2
def norm_path(p): def norm_path(p):
return os.path.expanduser(os.path.normpath(p)) return os.path.expanduser(os.path.normpath(p))
@ -227,7 +231,7 @@ def rmf(fname):
def exec_compiler_cmd(cmd): def exec_compiler_cmd(cmd):
r = exec_cmd(cmd) r = exec_cmd(cmd)
if is_windows() or is_cygwin_mingw(): if is_windows() or is_cygwin_mingw() or is_cygwin() or is_msys2():
rmf('a.exe') rmf('a.exe')
else: else:
rmf('a.out') rmf('a.out')
@ -606,6 +610,13 @@ elif os.name == 'posix':
IS_CYGWIN=True IS_CYGWIN=True
if (CC != None and "mingw" in CC): if (CC != None and "mingw" in CC):
IS_CYGWIN_MINGW=True IS_CYGWIN_MINGW=True
elif os.uname()[0].startswith('MSYS_NT') or os.uname()[0].startswith('MINGW'):
IS_MSYS2=True
if os.uname()[4] == 'x86_64':
LINUX_X64=True
else:
LINUX_X64=False
def display_help(exit_code): def display_help(exit_code):
print("mk_make.py: Z3 Makefile generator\n") print("mk_make.py: Z3 Makefile generator\n")
@ -1229,7 +1240,7 @@ def get_so_ext():
sysname = os.uname()[0] sysname = os.uname()[0]
if sysname == 'Darwin': if sysname == 'Darwin':
return 'dylib' return 'dylib'
elif sysname == 'Linux' or sysname == 'FreeBSD' or sysname == 'OpenBSD': elif sysname == 'Linux' or sysname == 'FreeBSD' or sysname == 'OpenBSD' or sysname.startswith('MSYS_NT') or sysname.startswith('MINGW'):
return 'so' return 'so'
elif sysname == 'CYGWIN': elif sysname == 'CYGWIN':
return 'dll' return 'dll'
@ -1783,6 +1794,8 @@ class JavaDLLComponent(Component):
t = t.replace('PLATFORM', 'openbsd') t = t.replace('PLATFORM', 'openbsd')
elif IS_CYGWIN: elif IS_CYGWIN:
t = t.replace('PLATFORM', 'cygwin') t = t.replace('PLATFORM', 'cygwin')
elif IS_MSYS2:
t = t.replace('PLATFORM', 'win32')
else: else:
t = t.replace('PLATFORM', 'win32') t = t.replace('PLATFORM', 'win32')
out.write(t) out.write(t)
@ -1875,7 +1888,6 @@ class MLComponent(Component):
def _init_ocamlfind_paths(self): def _init_ocamlfind_paths(self):
""" """
Initialises self.destdir and self.ldconf Initialises self.destdir and self.ldconf
Do not call this from the MLComponent constructor because OCAMLFIND Do not call this from the MLComponent constructor because OCAMLFIND
has not been checked at that point has not been checked at that point
""" """
@ -2446,7 +2458,7 @@ def mk_config():
if sysname == 'Darwin': if sysname == 'Darwin':
SO_EXT = '.dylib' SO_EXT = '.dylib'
SLIBFLAGS = '-dynamiclib' SLIBFLAGS = '-dynamiclib'
elif sysname == 'Linux': elif sysname == 'Linux' or sysname.startswith('MSYS_NT') or sysname.startswith('MINGW'):
CXXFLAGS = '%s -D_LINUX_' % CXXFLAGS CXXFLAGS = '%s -D_LINUX_' % CXXFLAGS
OS_DEFINES = '-D_LINUX_' OS_DEFINES = '-D_LINUX_'
SO_EXT = '.so' SO_EXT = '.so'
@ -2466,10 +2478,10 @@ def mk_config():
SO_EXT = '.so' SO_EXT = '.so'
SLIBFLAGS = '-shared' SLIBFLAGS = '-shared'
elif sysname[:6] == 'CYGWIN': elif sysname[:6] == 'CYGWIN':
CXXFLAGS = '%s -D_CYGWIN' % CXXFLAGS CXXFLAGS = '%s -D_CYGWIN' % CXXFLAGS
OS_DEFINES = '-D_CYGWIN' OS_DEFINES = '-D_CYGWIN'
SO_EXT = '.dll' SO_EXT = '.dll'
SLIBFLAGS = '-shared' SLIBFLAGS = '-shared'
else: else:
raise MKException('Unsupported platform: %s' % sysname) raise MKException('Unsupported platform: %s' % sysname)
if is64(): if is64():
@ -3160,7 +3172,6 @@ class MakeRuleCmd(object):
""" """
These class methods provide a convenient way to emit frequently These class methods provide a convenient way to emit frequently
needed commands used in Makefile rules needed commands used in Makefile rules
Note that several of the method are meant for use during ``make Note that several of the method are meant for use during ``make
install`` and ``make uninstall``. These methods correctly use install`` and ``make uninstall``. These methods correctly use
``$(PREFIX)`` and ``$(DESTDIR)`` and therefore are preferrable ``$(PREFIX)`` and ``$(DESTDIR)`` and therefore are preferrable
@ -3336,10 +3347,8 @@ def configure_file(template_file_path, output_file_path, substitutions):
Read a template file ``template_file_path``, perform substitutions Read a template file ``template_file_path``, perform substitutions
found in the ``substitutions`` dictionary and write the result to found in the ``substitutions`` dictionary and write the result to
the output file ``output_file_path``. the output file ``output_file_path``.
The template file should contain zero or more template strings of the The template file should contain zero or more template strings of the
form ``@NAME@``. form ``@NAME@``.
The substitutions dictionary maps old strings (without the ``@`` The substitutions dictionary maps old strings (without the ``@``
symbols) to their replacements. symbols) to their replacements.
""" """

View file

@ -67,7 +67,7 @@ add_subdirectory(interp)
add_subdirectory(cmd_context) add_subdirectory(cmd_context)
add_subdirectory(cmd_context/extra_cmds) add_subdirectory(cmd_context/extra_cmds)
add_subdirectory(parsers/smt2) add_subdirectory(parsers/smt2)
add_subdirectory(ast/proof_checker) add_subdirectory(ast/proofs)
add_subdirectory(ast/fpa) add_subdirectory(ast/fpa)
add_subdirectory(ast/macros) add_subdirectory(ast/macros)
add_subdirectory(ast/pattern) add_subdirectory(ast/pattern)

View file

@ -34,6 +34,19 @@ extern "C" {
Z3_CATCH_RETURN(0); Z3_CATCH_RETURN(0);
} }
Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const* domain, Z3_sort range) {
Z3_TRY;
LOG_Z3_mk_array_sort_n(c, n, domain, range);
RESET_ERROR_CODE();
vector<parameter> params;
for (unsigned i = 0; i < n; ++i) params.push_back(parameter(to_sort(domain[i])));
params.push_back(parameter(to_sort(range)));
sort * ty = mk_c(c)->m().mk_sort(mk_c(c)->get_array_fid(), ARRAY_SORT, params.size(), params.c_ptr());
mk_c(c)->save_ast_trail(ty);
RETURN_Z3(of_sort(ty));
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i) { Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i) {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_select(c, a, i); LOG_Z3_mk_select(c, a, i);
@ -57,6 +70,35 @@ extern "C" {
Z3_CATCH_RETURN(0); Z3_CATCH_RETURN(0);
} }
Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs) {
Z3_TRY;
LOG_Z3_mk_select_n(c, a, n, idxs);
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
expr * _a = to_expr(a);
// expr * _i = to_expr(i);
sort * a_ty = m.get_sort(_a);
// sort * i_ty = m.get_sort(_i);
if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) {
SET_ERROR_CODE(Z3_SORT_ERROR);
RETURN_Z3(0);
}
ptr_vector<sort> domain;
ptr_vector<expr> args;
args.push_back(_a);
domain.push_back(a_ty);
for (unsigned i = 0; i < n; ++i) {
args.push_back(to_expr(idxs[i]));
domain.push_back(m.get_sort(to_expr(idxs[i])));
}
func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_SELECT, 2, a_ty->get_parameters(), domain.size(), domain.c_ptr());
app * r = m.mk_app(d, args.size(), args.c_ptr());
mk_c(c)->save_ast_trail(r);
check_sorts(c, r);
RETURN_Z3(of_ast(r));
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) { Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v) {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_store(c, a, i, v); LOG_Z3_mk_store(c, a, i, v);
@ -82,6 +124,37 @@ extern "C" {
Z3_CATCH_RETURN(0); Z3_CATCH_RETURN(0);
} }
Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v) {
Z3_TRY;
LOG_Z3_mk_store_n(c, a, n, idxs, v);
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
expr * _a = to_expr(a);
expr * _v = to_expr(v);
sort * a_ty = m.get_sort(_a);
sort * v_ty = m.get_sort(_v);
if (a_ty->get_family_id() != mk_c(c)->get_array_fid()) {
SET_ERROR_CODE(Z3_SORT_ERROR);
RETURN_Z3(0);
}
ptr_vector<sort> domain;
ptr_vector<expr> args;
args.push_back(_a);
domain.push_back(a_ty);
for (unsigned i = 0; i < n; ++i) {
args.push_back(to_expr(idxs[i]));
domain.push_back(m.get_sort(to_expr(idxs[i])));
}
args.push_back(_v);
domain.push_back(v_ty);
func_decl * d = m.mk_func_decl(mk_c(c)->get_array_fid(), OP_STORE, 2, a_ty->get_parameters(), domain.size(), domain.c_ptr());
app * r = m.mk_app(d, args.size(), args.c_ptr());
mk_c(c)->save_ast_trail(r);
check_sorts(c, r);
RETURN_Z3(of_ast(r));
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) { Z3_ast Z3_API Z3_mk_map(Z3_context c, Z3_func_decl f, unsigned n, Z3_ast const* args) {
Z3_TRY; Z3_TRY;
LOG_Z3_mk_map(c, f, n, args); LOG_Z3_mk_map(c, f, n, args);
@ -188,6 +261,18 @@ extern "C" {
MK_BINARY(Z3_mk_set_subset, mk_c(c)->get_array_fid(), OP_SET_SUBSET, SKIP); MK_BINARY(Z3_mk_set_subset, mk_c(c)->get_array_fid(), OP_SET_SUBSET, SKIP);
MK_BINARY(Z3_mk_array_ext, mk_c(c)->get_array_fid(), OP_ARRAY_EXT, SKIP); MK_BINARY(Z3_mk_array_ext, mk_c(c)->get_array_fid(), OP_ARRAY_EXT, SKIP);
Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f) {
Z3_TRY;
LOG_Z3_mk_as_array(c, f);
RESET_ERROR_CODE();
ast_manager & m = mk_c(c)->m();
array_util a(m);
app * r = a.mk_as_array(to_func_decl(f));
mk_c(c)->save_ast_trail(r);
return of_ast(r);
Z3_CATCH_RETURN(0);
}
Z3_ast Z3_mk_set_member(Z3_context c, Z3_ast elem, Z3_ast set) { Z3_ast Z3_mk_set_member(Z3_context c, Z3_ast elem, Z3_ast set) {
return Z3_mk_select(c, set, elem); return Z3_mk_select(c, set, elem);
} }
@ -222,7 +307,8 @@ extern "C" {
CHECK_VALID_AST(t, 0); CHECK_VALID_AST(t, 0);
if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() && if (to_sort(t)->get_family_id() == mk_c(c)->get_array_fid() &&
to_sort(t)->get_decl_kind() == ARRAY_SORT) { to_sort(t)->get_decl_kind() == ARRAY_SORT) {
Z3_sort r = reinterpret_cast<Z3_sort>(to_sort(t)->get_parameter(1).get_ast()); unsigned n = to_sort(t)->get_num_parameters();
Z3_sort r = reinterpret_cast<Z3_sort>(to_sort(t)->get_parameter(n-1).get_ast());
RETURN_Z3(r); RETURN_Z3(r);
} }
SET_ERROR_CODE(Z3_INVALID_ARG); SET_ERROR_CODE(Z3_INVALID_ARG);

View file

@ -249,7 +249,7 @@ extern "C" {
params_ref _p; params_ref _p;
_p.set_bool("proof", true); // this is currently useless _p.set_bool("proof", true); // this is currently useless
scoped_proof_mode spm(mk_c(c)->m(), PGM_FINE); scoped_proof_mode spm(mk_c(c)->m(), PGM_ENABLED);
scoped_ptr<solver_factory> sf = mk_smt_solver_factory(); scoped_ptr<solver_factory> sf = mk_smt_solver_factory();
scoped_ptr<solver> m_solver((*sf)(mk_c(c)->m(), _p, true, true, true, ::symbol::null)); scoped_ptr<solver> m_solver((*sf)(mk_c(c)->m(), _p, true, true, true, ::symbol::null));
m_solver.get()->updt_params(_p); // why do we have to do this? m_solver.get()->updt_params(_p); // why do we have to do this?

View file

@ -255,8 +255,13 @@ extern "C" {
LOG_Z3_add_const_interp(c, m, f, a); LOG_Z3_add_const_interp(c, m, f, a);
RESET_ERROR_CODE(); RESET_ERROR_CODE();
func_decl* d = to_func_decl(f); func_decl* d = to_func_decl(f);
model* mdl = to_model_ref(m); if (d->get_arity() != 0) {
mdl->register_decl(d, to_expr(a)); SET_ERROR_CODE(Z3_INVALID_ARG);
}
else {
model* mdl = to_model_ref(m);
mdl->register_decl(d, to_expr(a));
}
Z3_CATCH; Z3_CATCH;
} }

View file

@ -250,6 +250,8 @@ namespace z3 {
Example: Given a context \c c, <tt>c.array_sort(c.int_sort(), c.bool_sort())</tt> is an array sort from integer to Boolean. Example: Given a context \c c, <tt>c.array_sort(c.int_sort(), c.bool_sort())</tt> is an array sort from integer to Boolean.
*/ */
sort array_sort(sort d, sort r); sort array_sort(sort d, sort r);
sort array_sort(sort_vector const& d, sort r);
/** /**
\brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1]. \brief Return an enumeration sort: enum_names[0], ..., enum_names[n-1].
\c cs and \c ts are output parameters. The method stores in \c cs the constants corresponding to the enumerated elements, \c cs and \c ts are output parameters. The method stores in \c cs the constants corresponding to the enumerated elements,
@ -2327,6 +2329,11 @@ namespace z3 {
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::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::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::array_sort(sort_vector const& d, sort r) {
array<Z3_sort> dom(d);
Z3_sort s = Z3_mk_array_sort_n(m_ctx, dom.size(), dom.ptr(), 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) { inline sort context::enumeration_sort(char const * name, unsigned n, char const * const * enum_names, func_decl_vector & cs, func_decl_vector & ts) {
array<Z3_symbol> _enum_names(n); array<Z3_symbol> _enum_names(n);
for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); } for (unsigned i = 0; i < n; i++) { _enum_names[i] = Z3_mk_string_symbol(*this, enum_names[i]); }
@ -2573,11 +2580,32 @@ namespace z3 {
a.check_error(); a.check_error();
return expr(a.ctx(), r); return expr(a.ctx(), r);
} }
inline expr select(expr const & a, expr_vector const & i) {
check_context(a, i);
array<Z3_ast> idxs(i);
Z3_ast r = Z3_mk_select_n(a.ctx(), a, idxs.size(), idxs.ptr());
a.check_error();
return expr(a.ctx(), r);
}
inline expr store(expr const & a, int i, expr const & v) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), v); } inline expr store(expr const & a, int i, expr const & v) { return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), v); }
inline expr store(expr const & a, expr i, int v) { return store(a, i, a.ctx().num_val(v, a.get_sort().array_range())); } inline expr store(expr const & a, expr i, int v) { return store(a, i, a.ctx().num_val(v, a.get_sort().array_range())); }
inline expr store(expr const & a, int i, int v) { inline expr store(expr const & a, int i, int v) {
return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), a.ctx().num_val(v, a.get_sort().array_range())); return store(a, a.ctx().num_val(i, a.get_sort().array_domain()), a.ctx().num_val(v, a.get_sort().array_range()));
} }
inline expr store(expr const & a, expr_vector const & i, expr const & v) {
check_context(a, i); check_context(a, v);
array<Z3_ast> idxs(i);
Z3_ast r = Z3_mk_store_n(a.ctx(), a, idxs.size(), idxs.ptr(), v);
a.check_error();
return expr(a.ctx(), r);
}
inline expr as_array(func_decl & f) {
Z3_ast r = Z3_mk_as_array(f.ctx(), f);
f.check_error();
return expr(f.ctx(), r);
}
#define MK_EXPR1(_fn, _arg) \ #define MK_EXPR1(_fn, _arg) \
Z3_ast r = _fn(_arg.ctx(), _arg); \ Z3_ast r = _fn(_arg.ctx(), _arg); \

View file

@ -63,6 +63,13 @@ namespace Microsoft.Z3
Contract.Requires(domain != null); Contract.Requires(domain != null);
Contract.Requires(range != null); Contract.Requires(range != null);
} }
internal ArraySort(Context ctx, Sort[] domain, Sort range)
: base(ctx, Native.Z3_mk_array_sort_n(ctx.nCtx, (uint)domain.Length, AST.ArrayToNative(domain), range.NativeObject))
{
Contract.Requires(ctx != null);
Contract.Requires(domain != null);
Contract.Requires(range != null);
}
#endregion #endregion
}; };

View file

@ -274,6 +274,20 @@ namespace Microsoft.Z3
return new ArraySort(this, domain, range); return new ArraySort(this, domain, range);
} }
/// <summary>
/// Create a new n-ary array sort.
/// </summary>
public ArraySort MkArraySort(Sort[] domain, Sort range)
{
Contract.Requires(domain != null);
Contract.Requires(range != null);
Contract.Ensures(Contract.Result<ArraySort>() != null);
CheckContextMatch<Sort>(domain);
CheckContextMatch(range);
return new ArraySort(this, domain, range);
}
/// <summary> /// <summary>
/// Create a new tuple sort. /// Create a new tuple sort.
/// </summary> /// </summary>
@ -2113,6 +2127,7 @@ namespace Microsoft.Z3
return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range)); return (ArrayExpr)MkConst(MkSymbol(name), MkArraySort(domain, range));
} }
/// <summary> /// <summary>
/// Array read. /// Array read.
/// </summary> /// </summary>
@ -2123,8 +2138,8 @@ namespace Microsoft.Z3
/// The node <c>a</c> must have an array sort <c>[domain -> range]</c>, /// The node <c>a</c> must have an array sort <c>[domain -> range]</c>,
/// and <c>i</c> must have the sort <c>domain</c>. /// and <c>i</c> must have the sort <c>domain</c>.
/// The sort of the result is <c>range</c>. /// The sort of the result is <c>range</c>.
/// <seealso cref="MkArraySort"/> /// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkStore"/> /// <seealso cref="MkStore(ArrayExpr, Expr, Expr)"/>
/// </remarks> /// </remarks>
public Expr MkSelect(ArrayExpr a, Expr i) public Expr MkSelect(ArrayExpr a, Expr i)
{ {
@ -2137,6 +2152,30 @@ namespace Microsoft.Z3
return Expr.Create(this, Native.Z3_mk_select(nCtx, a.NativeObject, i.NativeObject)); return Expr.Create(this, Native.Z3_mk_select(nCtx, a.NativeObject, i.NativeObject));
} }
/// <summary>
/// Array read.
/// </summary>
/// <remarks>
/// The argument <c>a</c> is the array and <c>args</c> are the indices
/// of the array that gets read.
///
/// The node <c>a</c> must have an array sort <c>[domain1,..,domaink -> range]</c>,
/// and <c>args</c> must have the sort <c>domain1,..,domaink</c>.
/// The sort of the result is <c>range</c>.
/// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkStore(ArrayExpr, Expr, Expr)"/>
/// </remarks>
public Expr MkSelect(ArrayExpr a, params Expr[] args)
{
Contract.Requires(a != null);
Contract.Requires(args != null && Contract.ForAll(args, n => n != null));
Contract.Ensures(Contract.Result<Expr>() != null);
CheckContextMatch(a);
CheckContextMatch<Expr>(args);
return Expr.Create(this, Native.Z3_mk_select_n(nCtx, a.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args)));
}
/// <summary> /// <summary>
/// Array update. /// Array update.
/// </summary> /// </summary>
@ -2151,8 +2190,9 @@ namespace Microsoft.Z3
/// on all indices except for <c>i</c>, where it maps to <c>v</c> /// on all indices except for <c>i</c>, where it maps to <c>v</c>
/// (and the <c>select</c> of <c>a</c> with /// (and the <c>select</c> of <c>a</c> with
/// respect to <c>i</c> may be a different value). /// respect to <c>i</c> may be a different value).
/// <seealso cref="MkArraySort"/> /// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect"/> /// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr[])"/>
/// </remarks> /// </remarks>
public ArrayExpr MkStore(ArrayExpr a, Expr i, Expr v) public ArrayExpr MkStore(ArrayExpr a, Expr i, Expr v)
{ {
@ -2167,14 +2207,45 @@ namespace Microsoft.Z3
return new ArrayExpr(this, Native.Z3_mk_store(nCtx, a.NativeObject, i.NativeObject, v.NativeObject)); return new ArrayExpr(this, Native.Z3_mk_store(nCtx, a.NativeObject, i.NativeObject, v.NativeObject));
} }
/// <summary>
/// Array update.
/// </summary>
/// <remarks>
/// The node <c>a</c> must have an array sort <c>[domain1,..,domaink -> range]</c>,
/// <c>args</c> must have sort <c>domain1,..,domaink</c>,
/// <c>v</c> must have sort range. The sort of the result is <c>[domain -> range]</c>.
/// The semantics of this function is given by the theory of arrays described in the SMT-LIB
/// standard. See http://smtlib.org for more details.
/// The result of this function is an array that is equal to <c>a</c>
/// (with respect to <c>select</c>)
/// on all indices except for <c>args</c>, where it maps to <c>v</c>
/// (and the <c>select</c> of <c>a</c> with
/// respect to <c>args</c> may be a different value).
/// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// <seealso cref="MkSelect(ArrayExpr, Expr[])"/>
/// </remarks>
public ArrayExpr MkStore(ArrayExpr a, Expr[] args, Expr v)
{
Contract.Requires(a != null);
Contract.Requires(args != null);
Contract.Requires(v != null);
Contract.Ensures(Contract.Result<ArrayExpr>() != null);
CheckContextMatch<Expr>(args);
CheckContextMatch(a);
CheckContextMatch(v);
return new ArrayExpr(this, Native.Z3_mk_store_n(nCtx, a.NativeObject, AST.ArrayLength(args), AST.ArrayToNative(args), v.NativeObject));
}
/// <summary> /// <summary>
/// Create a constant array. /// Create a constant array.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// The resulting term is an array, such that a <c>select</c>on an arbitrary index /// The resulting term is an array, such that a <c>select</c>on an arbitrary index
/// produces the value <c>v</c>. /// produces the value <c>v</c>.
/// <seealso cref="MkArraySort"/> /// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect"/> /// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// </remarks> /// </remarks>
public ArrayExpr MkConstArray(Sort domain, Expr v) public ArrayExpr MkConstArray(Sort domain, Expr v)
{ {
@ -2194,9 +2265,9 @@ namespace Microsoft.Z3
/// Eeach element of <c>args</c> must be of an array sort <c>[domain_i -> range_i]</c>. /// Eeach element of <c>args</c> must be of an array sort <c>[domain_i -> range_i]</c>.
/// The function declaration <c>f</c> must have type <c> range_1 .. range_n -> range</c>. /// The function declaration <c>f</c> must have type <c> range_1 .. range_n -> range</c>.
/// <c>v</c> must have sort range. The sort of the result is <c>[domain_i -> range]</c>. /// <c>v</c> must have sort range. The sort of the result is <c>[domain_i -> range]</c>.
/// <seealso cref="MkArraySort"/> /// <seealso cref="MkArraySort(Sort, Sort)"/>
/// <seealso cref="MkSelect"/> /// <seealso cref="MkSelect(ArrayExpr, Expr)"/>
/// <seealso cref="MkStore"/> /// <seealso cref="MkStore(ArrayExpr, Expr, Expr)"/>
/// </remarks> /// </remarks>
public ArrayExpr MkMap(FuncDecl f, params ArrayExpr[] args) public ArrayExpr MkMap(FuncDecl f, params ArrayExpr[] args)
{ {

View file

@ -56,4 +56,10 @@ public class ArraySort extends Sort
super(ctx, Native.mkArraySort(ctx.nCtx(), domain.getNativeObject(), super(ctx, Native.mkArraySort(ctx.nCtx(), domain.getNativeObject(),
range.getNativeObject())); range.getNativeObject()));
} }
ArraySort(Context ctx, Sort[] domains, Sort range)
{
super(ctx, Native.mkArraySortN(ctx.nCtx(), domains.length, AST.arrayToNative(domains),
range.getNativeObject()));
}
}; };

View file

@ -224,6 +224,17 @@ public class Context implements AutoCloseable {
return new ArraySort(this, domain, range); return new ArraySort(this, domain, range);
} }
/**
* Create a new array sort.
**/
public ArraySort mkArraySort(Sort[] domains, Sort range)
{
checkContextMatch(domains);
checkContextMatch(range);
return new ArraySort(this, domains, range);
}
/** /**
* Create a new string sort * Create a new string sort
**/ **/
@ -414,7 +425,7 @@ public class Context implements AutoCloseable {
* that is passed in as argument is updated with value v, * that is passed in as argument is updated with value v,
* the remaining fields of t are unchanged. * the remaining fields of t are unchanged.
**/ **/
public Expr MkUpdateField(FuncDecl field, Expr t, Expr v) public Expr mkUpdateField(FuncDecl field, Expr t, Expr v)
throws Z3Exception throws Z3Exception
{ {
return Expr.create (this, return Expr.create (this,
@ -706,7 +717,7 @@ public class Context implements AutoCloseable {
} }
/** /**
* Mk an expression representing {@code not(a)}. * Create an expression representing {@code not(a)}.
**/ **/
public BoolExpr mkNot(BoolExpr a) public BoolExpr mkNot(BoolExpr a)
{ {
@ -1679,6 +1690,28 @@ public class Context implements AutoCloseable {
i.getNativeObject())); i.getNativeObject()));
} }
/**
* Array read.
* Remarks: The argument {@code a} is the array and
* {@code args} are the indices of the array that gets read.
*
* The node {@code a} must have an array sort
* {@code [domains -> range]}, and {@code args} must have the sorts
* {@code domains}. The sort of the result is {@code range}.
*
* @see #mkArraySort
* @see #mkStore
**/
public Expr mkSelect(ArrayExpr a, Expr[] args)
{
checkContextMatch(a);
checkContextMatch(args);
return Expr.create(
this,
Native.mkSelectN(nCtx(), a.getNativeObject(), args.length, AST.arrayToNative(args)));
}
/** /**
* Array update. * Array update.
* Remarks: The node {@code a} must have an array sort * Remarks: The node {@code a} must have an array sort
@ -1704,6 +1737,31 @@ public class Context implements AutoCloseable {
i.getNativeObject(), v.getNativeObject())); i.getNativeObject(), v.getNativeObject()));
} }
/**
* Array update.
* Remarks: The node {@code a} must have an array sort
* {@code [domains -> range]}, {@code i} must have sort
* {@code domain}, {@code v} must have sort range. The sort of the
* result is {@code [domains -> range]}. The semantics of this function
* is given by the theory of arrays described in the SMT-LIB standard. See
* http://smtlib.org for more details. The result of this function is an
* array that is equal to {@code a} (with respect to
* {@code select}) on all indices except for {@code args}, where it
* maps to {@code v} (and the {@code select} of {@code a}
* with respect to {@code args} may be a different value).
* @see #mkArraySort
* @see #mkSelect
**/
public ArrayExpr mkStore(ArrayExpr a, Expr[] args, Expr v)
{
checkContextMatch(a);
checkContextMatch(args);
checkContextMatch(v);
return new ArrayExpr(this, Native.mkStoreN(nCtx(), a.getNativeObject(),
args.length, AST.arrayToNative(args), v.getNativeObject()));
}
/** /**
* Create a constant array. * Create a constant array.
* Remarks: The resulting term is an array, such * Remarks: The resulting term is an array, such
@ -2104,7 +2162,7 @@ public class Context implements AutoCloseable {
/** /**
* Create a range expression. * Create a range expression.
*/ */
public ReExpr MkRange(SeqExpr lo, SeqExpr hi) public ReExpr mkRange(SeqExpr lo, SeqExpr hi)
{ {
checkContextMatch(lo, hi); checkContextMatch(lo, hi);
return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject())); return (ReExpr) Expr.create(this, Native.mkReRange(nCtx(), lo.getNativeObject(), hi.getNativeObject()));

View file

@ -1881,6 +1881,17 @@ extern "C" {
*/ */
Z3_sort Z3_API Z3_mk_array_sort(Z3_context c, Z3_sort domain, Z3_sort range); Z3_sort Z3_API Z3_mk_array_sort(Z3_context c, Z3_sort domain, Z3_sort range);
/**
\brief Create an array type with N arguments
\sa Z3_mk_select_n
\sa Z3_mk_store_n
def_API('Z3_mk_array_sort_n', SORT, (_in(CONTEXT), _in(UINT), _in_array(1, SORT), _in(SORT)))
*/
Z3_sort Z3_API Z3_mk_array_sort_n(Z3_context c, unsigned n, Z3_sort const * domain, Z3_sort range);
/** /**
\brief Create a tuple type. \brief Create a tuple type.
@ -2973,6 +2984,15 @@ extern "C" {
*/ */
Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i); Z3_ast Z3_API Z3_mk_select(Z3_context c, Z3_ast a, Z3_ast i);
/**
\brief n-ary Array read.
The argument \c a is the array and \c idxs are the indices of the array that gets read.
def_API('Z3_mk_select_n', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST)))
*/
Z3_ast Z3_API Z3_mk_select_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs);
/** /**
\brief Array update. \brief Array update.
@ -2991,6 +3011,14 @@ extern "C" {
*/ */
Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v); Z3_ast Z3_API Z3_mk_store(Z3_context c, Z3_ast a, Z3_ast i, Z3_ast v);
/**
\brief n-ary Array update.
def_API('Z3_mk_store_n', AST, (_in(CONTEXT), _in(AST), _in(UINT), _in_array(2, AST), _in(AST)))
*/
Z3_ast Z3_API Z3_mk_store_n(Z3_context c, Z3_ast a, unsigned n, Z3_ast const* idxs, Z3_ast v);
/** /**
\brief Create the constant array. \brief Create the constant array.
@ -3031,6 +3059,15 @@ extern "C" {
def_API('Z3_mk_array_default', AST, (_in(CONTEXT), _in(AST))) def_API('Z3_mk_array_default', AST, (_in(CONTEXT), _in(AST)))
*/ */
Z3_ast Z3_API Z3_mk_array_default(Z3_context c, Z3_ast array); Z3_ast Z3_API Z3_mk_array_default(Z3_context c, Z3_ast array);
/**
\brief Create array with the same interpretation as a function.
The array satisfies the property (f x) = (select (_ as-array f) x)
for every argument x.
def_API('Z3_mk_as_array', AST, (_in(CONTEXT), _in(FUNC_DECL)))
*/
Z3_ast Z3_API Z3_mk_as_array(Z3_context c, Z3_func_decl f);
/*@}*/ /*@}*/
/** @name Sets */ /** @name Sets */
@ -3854,6 +3891,7 @@ extern "C" {
/** /**
\brief Return the domain of the given array sort. \brief Return the domain of the given array sort.
In the case of a multi-dimensional array, this function returns the sort of the first dimension.
\pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT \pre Z3_get_sort_kind(c, t) == Z3_ARRAY_SORT

View file

@ -10,6 +10,7 @@ z3_add_component(ast
ast_printer.cpp ast_printer.cpp
ast_smt2_pp.cpp ast_smt2_pp.cpp
ast_smt_pp.cpp ast_smt_pp.cpp
ast_pp_dot.cpp
ast_translation.cpp ast_translation.cpp
ast_util.cpp ast_util.cpp
bv_decl_plugin.cpp bv_decl_plugin.cpp

View file

@ -242,7 +242,9 @@ func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) {
parameter const* parameters = s->get_parameters(); parameter const* parameters = s->get_parameters();
if (num_parameters != arity) { if (num_parameters != arity) {
m_manager->raise_exception("select requires as many arguments as the size of the domain"); std::stringstream strm;
strm << "select requires " << num_parameters << " arguments, but was provided with " << arity << " arguments";
m_manager->raise_exception(strm.str().c_str());
return 0; return 0;
} }
ptr_buffer<sort> new_domain; // we need this because of coercions. ptr_buffer<sort> new_domain; // we need this because of coercions.
@ -314,7 +316,7 @@ func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domai
return 0; return 0;
} }
sort * r = to_sort(s->get_parameter(i).get_ast()); sort * r = to_sort(s->get_parameter(i).get_ast());
parameter param(s); parameter param(i);
return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT, 1, &param)); return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, func_decl_info(m_family_id, OP_ARRAY_EXT, 1, &param));
} }
@ -592,3 +594,9 @@ sort * array_util::mk_array_sort(unsigned arity, sort* const* domain, sort* rang
params.push_back(parameter(range)); params.push_back(parameter(range));
return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.c_ptr()); return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.c_ptr());
} }
func_decl* array_util::mk_array_ext(sort *domain, unsigned i) {
sort * domains[2] = { domain, domain };
parameter p(i);
return m_manager.mk_func_decl(m_fid, OP_ARRAY_EXT, 1, &p, 2, domains);
}

View file

@ -143,6 +143,7 @@ public:
bool is_const(expr* n) const { return is_app_of(n, m_fid, OP_CONST_ARRAY); } bool is_const(expr* n) const { return is_app_of(n, m_fid, OP_CONST_ARRAY); }
bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); } bool is_map(expr* n) const { return is_app_of(n, m_fid, OP_ARRAY_MAP); }
bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); } bool is_as_array(expr * n) const { return is_app_of(n, m_fid, OP_AS_ARRAY); }
bool is_as_array(expr * n, func_decl*& f) const { return is_as_array(n) && (f = get_as_array_func_decl(n), true); }
bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); } bool is_select(func_decl* f) const { return is_decl_of(f, m_fid, OP_SELECT); }
bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); } bool is_store(func_decl* f) const { return is_decl_of(f, m_fid, OP_STORE); }
bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); } bool is_const(func_decl* f) const { return is_decl_of(f, m_fid, OP_CONST_ARRAY); }
@ -182,13 +183,15 @@ public:
return mk_const_array(s, m_manager.mk_true()); return mk_const_array(s, m_manager.mk_true());
} }
func_decl * mk_array_ext(sort* domain, unsigned i);
sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); } sort * mk_array_sort(sort* dom, sort* range) { return mk_array_sort(1, &dom, range); }
sort * mk_array_sort(unsigned arity, sort* const* domain, sort* range); sort * mk_array_sort(unsigned arity, sort* const* domain, sort* range);
app * mk_as_array(sort * s, func_decl * f) { app * mk_as_array(func_decl * f) {
parameter param(f); parameter param(f);
return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, &param, 0, 0, s); return m_manager.mk_app(m_fid, OP_AS_ARRAY, 1, &param, 0, 0, 0);
} }
}; };

View file

@ -805,7 +805,6 @@ func_decl * basic_decl_plugin::mk_proof_decl(char const* name, basic_op_kind k,
} }
func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_parents) { func_decl * basic_decl_plugin::mk_proof_decl(basic_op_kind k, unsigned num_parents) {
SASSERT(k == PR_UNDEF || m_manager->proofs_enabled());
switch (static_cast<basic_op_kind>(k)) { switch (static_cast<basic_op_kind>(k)) {
// //
// A description of the semantics of the proof // A description of the semantics of the proof
@ -1684,7 +1683,7 @@ ast * ast_manager::register_node_core(ast * n) {
bool contains = m_ast_table.contains(n); bool contains = m_ast_table.contains(n);
CASSERT("nondet_bug", contains || slow_not_contains(n)); CASSERT("nondet_bug", contains || slow_not_contains(n));
#endif #endif
#if 0 #if 0
static unsigned counter = 0; static unsigned counter = 0;
counter++; counter++;
@ -1720,12 +1719,6 @@ ast * ast_manager::register_node_core(ast * n) {
n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk(); n->m_id = is_decl(n) ? m_decl_id_gen.mk() : m_expr_id_gen.mk();
static unsigned count = 0;
if (n->m_id == 404) {
++count;
//if (count == 2) SASSERT(false);
}
TRACE("ast", tout << "Object " << n->m_id << " was created.\n";); TRACE("ast", tout << "Object " << n->m_id << " was created.\n";);
TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";); TRACE("mk_var_bug", tout << "mk_ast: " << n->m_id << "\n";);
// increment reference counters // increment reference counters
@ -2626,8 +2619,8 @@ bool ast_manager::is_fully_interp(sort * s) const {
// ----------------------------------- // -----------------------------------
proof * ast_manager::mk_proof(family_id fid, decl_kind k, unsigned num_args, expr * const * args) { proof * ast_manager::mk_proof(family_id fid, decl_kind k, unsigned num_args, expr * const * args) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(fid, k, num_args, args); return mk_app(fid, k, num_args, args);
} }
@ -2662,8 +2655,7 @@ proof * ast_manager::mk_goal(expr * f) {
} }
proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) { proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) {
if (m_proof_mode == PGM_DISABLED) if (!p1 || !p2) return nullptr;
return m_undef_proof;
SASSERT(has_fact(p1)); SASSERT(has_fact(p1));
SASSERT(has_fact(p2)); SASSERT(has_fact(p2));
CTRACE("mk_modus_ponens", !(is_implies(get_fact(p2)) || is_iff(get_fact(p2)) || is_oeq(get_fact(p2))), CTRACE("mk_modus_ponens", !(is_implies(get_fact(p2)) || is_iff(get_fact(p2)) || is_oeq(get_fact(p2))),
@ -2684,14 +2676,10 @@ proof * ast_manager::mk_modus_ponens(proof * p1, proof * p2) {
} }
proof * ast_manager::mk_reflexivity(expr * e) { proof * ast_manager::mk_reflexivity(expr * e) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_eq(e, e)); return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_eq(e, e));
} }
proof * ast_manager::mk_oeq_reflexivity(expr * e) { proof * ast_manager::mk_oeq_reflexivity(expr * e) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_oeq(e, e)); return mk_app(m_basic_family_id, PR_REFLEXIVITY, mk_oeq(e, e));
} }
@ -2705,8 +2693,7 @@ proof * ast_manager::mk_commutativity(app * f) {
\brief Given a proof of p, return a proof of (p <=> true) \brief Given a proof of p, return a proof of (p <=> true)
*/ */
proof * ast_manager::mk_iff_true(proof * pr) { proof * ast_manager::mk_iff_true(proof * pr) {
if (m_proof_mode == PGM_DISABLED) if (!pr) return pr;
return m_undef_proof;
SASSERT(has_fact(pr)); SASSERT(has_fact(pr));
SASSERT(is_bool(get_fact(pr))); SASSERT(is_bool(get_fact(pr)));
return mk_app(m_basic_family_id, PR_IFF_TRUE, pr, mk_iff(get_fact(pr), mk_true())); return mk_app(m_basic_family_id, PR_IFF_TRUE, pr, mk_iff(get_fact(pr), mk_true()));
@ -2716,8 +2703,7 @@ proof * ast_manager::mk_iff_true(proof * pr) {
\brief Given a proof of (not p), return a proof of (p <=> false) \brief Given a proof of (not p), return a proof of (p <=> false)
*/ */
proof * ast_manager::mk_iff_false(proof * pr) { proof * ast_manager::mk_iff_false(proof * pr) {
if (m_proof_mode == PGM_DISABLED) if (!pr) return pr;
return m_undef_proof;
SASSERT(has_fact(pr)); SASSERT(has_fact(pr));
SASSERT(is_not(get_fact(pr))); SASSERT(is_not(get_fact(pr)));
expr * p = to_app(get_fact(pr))->get_arg(0); expr * p = to_app(get_fact(pr))->get_arg(0);
@ -2725,10 +2711,7 @@ proof * ast_manager::mk_iff_false(proof * pr) {
} }
proof * ast_manager::mk_symmetry(proof * p) { proof * ast_manager::mk_symmetry(proof * p) {
if (m_proof_mode == PGM_DISABLED) if (!p) return p;
return m_undef_proof;
if (!p)
return p;
if (is_reflexivity(p)) if (is_reflexivity(p))
return p; return p;
if (is_symmetry(p)) if (is_symmetry(p))
@ -2741,8 +2724,6 @@ proof * ast_manager::mk_symmetry(proof * p) {
} }
proof * ast_manager::mk_transitivity(proof * p1, proof * p2) { proof * ast_manager::mk_transitivity(proof * p1, proof * p2) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
if (!p1) if (!p1)
return p2; return p2;
if (!p2) if (!p2)
@ -2787,8 +2768,6 @@ proof * ast_manager::mk_transitivity(proof * p1, proof * p2, proof * p3, proof *
} }
proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
SASSERT(num_proofs > 0); SASSERT(num_proofs > 0);
proof * r = proofs[0]; proof * r = proofs[0];
for (unsigned i = 1; i < num_proofs; i++) for (unsigned i = 1; i < num_proofs; i++)
@ -2797,11 +2776,8 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs
} }
proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs, expr * n1, expr * n2) { proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs, expr * n1, expr * n2) {
if (m_proof_mode == PGM_DISABLED) if (num_proofs == 0)
return m_undef_proof; return nullptr;
if (fine_grain_proofs())
return mk_transitivity(num_proofs, proofs);
SASSERT(num_proofs > 0);
if (num_proofs == 1) if (num_proofs == 1)
return proofs[0]; return proofs[0];
DEBUG_CODE({ DEBUG_CODE({
@ -2817,8 +2793,6 @@ proof * ast_manager::mk_transitivity(unsigned num_proofs, proof * const * proofs
} }
proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
SASSERT(f1->get_num_args() == f2->get_num_args()); SASSERT(f1->get_num_args() == f2->get_num_args());
SASSERT(f1->get_decl() == f2->get_decl()); SASSERT(f1->get_decl() == f2->get_decl());
ptr_buffer<expr> args; ptr_buffer<expr> args;
@ -2828,8 +2802,6 @@ proof * ast_manager::mk_monotonicity(func_decl * R, app * f1, app * f2, unsigned
} }
proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
SASSERT(get_sort(f1) == get_sort(f2)); SASSERT(get_sort(f1) == get_sort(f2));
sort * s = get_sort(f1); sort * s = get_sort(f1);
sort * d[2] = { s, s }; sort * d[2] = { s, s };
@ -2837,8 +2809,6 @@ proof * ast_manager::mk_congruence(app * f1, app * f2, unsigned num_proofs, proo
} }
proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
SASSERT(get_sort(f1) == get_sort(f2)); SASSERT(get_sort(f1) == get_sort(f2));
sort * s = get_sort(f1); sort * s = get_sort(f1);
sort * d[2] = { s, s }; sort * d[2] = { s, s };
@ -2846,11 +2816,7 @@ proof * ast_manager::mk_oeq_congruence(app * f1, app * f2, unsigned num_proofs,
} }
proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) { proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p) {
if (m_proof_mode == PGM_DISABLED) if (!p) return nullptr;
return m_undef_proof;
if (!p) {
return 0;
}
SASSERT(q1->get_num_decls() == q2->get_num_decls()); SASSERT(q1->get_num_decls() == q2->get_num_decls());
SASSERT(has_fact(p)); SASSERT(has_fact(p));
SASSERT(is_iff(get_fact(p))); SASSERT(is_iff(get_fact(p)));
@ -2858,8 +2824,7 @@ proof * ast_manager::mk_quant_intro(quantifier * q1, quantifier * q2, proof * p)
} }
proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof * p) { proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof * p) {
if (m_proof_mode == PGM_DISABLED) if (!p) return nullptr;
return m_undef_proof;
SASSERT(q1->get_num_decls() == q2->get_num_decls()); SASSERT(q1->get_num_decls() == q2->get_num_decls());
SASSERT(has_fact(p)); SASSERT(has_fact(p));
SASSERT(is_oeq(get_fact(p))); SASSERT(is_oeq(get_fact(p)));
@ -2867,26 +2832,24 @@ proof * ast_manager::mk_oeq_quant_intro(quantifier * q1, quantifier * q2, proof
} }
proof * ast_manager::mk_distributivity(expr * s, expr * r) { proof * ast_manager::mk_distributivity(expr * s, expr * r) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
return mk_app(m_basic_family_id, PR_DISTRIBUTIVITY, mk_eq(s, r)); return mk_app(m_basic_family_id, PR_DISTRIBUTIVITY, mk_eq(s, r));
} }
proof * ast_manager::mk_rewrite(expr * s, expr * t) { proof * ast_manager::mk_rewrite(expr * s, expr * t) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(m_basic_family_id, PR_REWRITE, mk_eq(s, t)); return mk_app(m_basic_family_id, PR_REWRITE, mk_eq(s, t));
} }
proof * ast_manager::mk_oeq_rewrite(expr * s, expr * t) { proof * ast_manager::mk_oeq_rewrite(expr * s, expr * t) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(m_basic_family_id, PR_REWRITE, mk_oeq(s, t)); return mk_app(m_basic_family_id, PR_REWRITE, mk_oeq(s, t));
} }
proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
ptr_buffer<expr> args; ptr_buffer<expr> args;
args.append(num_proofs, (expr**) proofs); args.append(num_proofs, (expr**) proofs);
args.push_back(mk_eq(s, t)); args.push_back(mk_eq(s, t));
@ -2894,38 +2857,38 @@ proof * ast_manager::mk_rewrite_star(expr * s, expr * t, unsigned num_proofs, pr
} }
proof * ast_manager::mk_pull_quant(expr * e, quantifier * q) { proof * ast_manager::mk_pull_quant(expr * e, quantifier * q) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(m_basic_family_id, PR_PULL_QUANT, mk_iff(e, q)); return mk_app(m_basic_family_id, PR_PULL_QUANT, mk_iff(e, q));
} }
proof * ast_manager::mk_pull_quant_star(expr * e, quantifier * q) { proof * ast_manager::mk_pull_quant_star(expr * e, quantifier * q) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(m_basic_family_id, PR_PULL_QUANT_STAR, mk_iff(e, q)); return mk_app(m_basic_family_id, PR_PULL_QUANT_STAR, mk_iff(e, q));
} }
proof * ast_manager::mk_push_quant(quantifier * q, expr * e) { proof * ast_manager::mk_push_quant(quantifier * q, expr * e) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(m_basic_family_id, PR_PUSH_QUANT, mk_iff(q, e)); return mk_app(m_basic_family_id, PR_PUSH_QUANT, mk_iff(q, e));
} }
proof * ast_manager::mk_elim_unused_vars(quantifier * q, expr * e) { proof * ast_manager::mk_elim_unused_vars(quantifier * q, expr * e) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(m_basic_family_id, PR_ELIM_UNUSED_VARS, mk_iff(q, e)); return mk_app(m_basic_family_id, PR_ELIM_UNUSED_VARS, mk_iff(q, e));
} }
proof * ast_manager::mk_der(quantifier * q, expr * e) { proof * ast_manager::mk_der(quantifier * q, expr * e) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(m_basic_family_id, PR_DER, mk_iff(q, e)); return mk_app(m_basic_family_id, PR_DER, mk_iff(q, e));
} }
proof * ast_manager::mk_quant_inst(expr * not_q_or_i, unsigned num_bind, expr* const* binding) { proof * ast_manager::mk_quant_inst(expr * not_q_or_i, unsigned num_bind, expr* const* binding) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
vector<parameter> params; vector<parameter> params;
for (unsigned i = 0; i < num_bind; ++i) { for (unsigned i = 0; i < num_bind; ++i) {
params.push_back(parameter(binding[i])); params.push_back(parameter(binding[i]));
@ -2959,8 +2922,8 @@ bool ast_manager::is_rewrite(expr const* e, expr*& r1, expr*& r2) const {
} }
proof * ast_manager::mk_def_axiom(expr * ax) { proof * ast_manager::mk_def_axiom(expr * ax) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
return mk_app(m_basic_family_id, PR_DEF_AXIOM, ax); return mk_app(m_basic_family_id, PR_DEF_AXIOM, ax);
} }
@ -3001,7 +2964,7 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro
new_lits.push_back(lit); new_lits.push_back(lit);
} }
DEBUG_CODE({ DEBUG_CODE({
for (unsigned i = 1; m_proof_mode == PGM_FINE && i < num_proofs; i++) { for (unsigned i = 1; proofs_enabled() && i < num_proofs; i++) {
CTRACE("mk_unit_resolution_bug", !found.get(i, false), CTRACE("mk_unit_resolution_bug", !found.get(i, false),
for (unsigned j = 0; j < num_proofs; j++) { for (unsigned j = 0; j < num_proofs; j++) {
if (j == i) tout << "Index " << i << " was not found:\n"; if (j == i) tout << "Index " << i << " was not found:\n";
@ -3080,14 +3043,11 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro
} }
proof * ast_manager::mk_hypothesis(expr * h) { proof * ast_manager::mk_hypothesis(expr * h) {
if (m_proof_mode == PGM_DISABLED)
return m_undef_proof;
return mk_app(m_basic_family_id, PR_HYPOTHESIS, h); return mk_app(m_basic_family_id, PR_HYPOTHESIS, h);
} }
proof * ast_manager::mk_lemma(proof * p, expr * lemma) { proof * ast_manager::mk_lemma(proof * p, expr * lemma) {
if (m_proof_mode == PGM_DISABLED) if (!p) return p;
return m_undef_proof;
SASSERT(has_fact(p)); SASSERT(has_fact(p));
CTRACE("mk_lemma", !is_false(get_fact(p)), tout << mk_ll_pp(p, *this) << "\n";); CTRACE("mk_lemma", !is_false(get_fact(p)), tout << mk_ll_pp(p, *this) << "\n";);
SASSERT(is_false(get_fact(p))); SASSERT(is_false(get_fact(p)));
@ -3100,8 +3060,8 @@ proof * ast_manager::mk_def_intro(expr * new_def) {
} }
proof * ast_manager::mk_apply_defs(expr * n, expr * def, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_apply_defs(expr * n, expr * def, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
ptr_buffer<expr> args; ptr_buffer<expr> args;
args.append(num_proofs, (expr**) proofs); args.append(num_proofs, (expr**) proofs);
args.push_back(mk_oeq(n, def)); args.push_back(mk_oeq(n, def));
@ -3109,10 +3069,7 @@ proof * ast_manager::mk_apply_defs(expr * n, expr * def, unsigned num_proofs, pr
} }
proof * ast_manager::mk_iff_oeq(proof * p) { proof * ast_manager::mk_iff_oeq(proof * p) {
if (m_proof_mode == PGM_DISABLED) if (!p) return p;
return m_undef_proof;
if (!p)
return p;
SASSERT(has_fact(p)); SASSERT(has_fact(p));
SASSERT(is_iff(get_fact(p)) || is_oeq(get_fact(p))); SASSERT(is_iff(get_fact(p)) || is_oeq(get_fact(p)));
@ -3136,8 +3093,8 @@ bool ast_manager::check_nnf_proof_parents(unsigned num_proofs, proof * const * p
} }
proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
check_nnf_proof_parents(num_proofs, proofs); check_nnf_proof_parents(num_proofs, proofs);
ptr_buffer<expr> args; ptr_buffer<expr> args;
args.append(num_proofs, (expr**) proofs); args.append(num_proofs, (expr**) proofs);
@ -3146,8 +3103,8 @@ proof * ast_manager::mk_nnf_pos(expr * s, expr * t, unsigned num_proofs, proof *
} }
proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
check_nnf_proof_parents(num_proofs, proofs); check_nnf_proof_parents(num_proofs, proofs);
ptr_buffer<expr> args; ptr_buffer<expr> args;
args.append(num_proofs, (expr**) proofs); args.append(num_proofs, (expr**) proofs);
@ -3156,8 +3113,8 @@ proof * ast_manager::mk_nnf_neg(expr * s, expr * t, unsigned num_proofs, proof *
} }
proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
ptr_buffer<expr> args; ptr_buffer<expr> args;
args.append(num_proofs, (expr**) proofs); args.append(num_proofs, (expr**) proofs);
args.push_back(mk_oeq(s, t)); args.push_back(mk_oeq(s, t));
@ -3165,16 +3122,16 @@ proof * ast_manager::mk_nnf_star(expr * s, expr * t, unsigned num_proofs, proof
} }
proof * ast_manager::mk_skolemization(expr * q, expr * e) { proof * ast_manager::mk_skolemization(expr * q, expr * e) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
SASSERT(is_bool(q)); SASSERT(is_bool(q));
SASSERT(is_bool(e)); SASSERT(is_bool(e));
return mk_app(m_basic_family_id, PR_SKOLEMIZE, mk_oeq(q, e)); return mk_app(m_basic_family_id, PR_SKOLEMIZE, mk_oeq(q, e));
} }
proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) { proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof * const * proofs) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
ptr_buffer<expr> args; ptr_buffer<expr> args;
args.append(num_proofs, (expr**) proofs); args.append(num_proofs, (expr**) proofs);
args.push_back(mk_oeq(s, t)); args.push_back(mk_oeq(s, t));
@ -3182,8 +3139,8 @@ proof * ast_manager::mk_cnf_star(expr * s, expr * t, unsigned num_proofs, proof
} }
proof * ast_manager::mk_and_elim(proof * p, unsigned i) { proof * ast_manager::mk_and_elim(proof * p, unsigned i) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
SASSERT(has_fact(p)); SASSERT(has_fact(p));
SASSERT(is_and(get_fact(p))); SASSERT(is_and(get_fact(p)));
CTRACE("mk_and_elim", i >= to_app(get_fact(p))->get_num_args(), tout << "i: " << i << "\n" << mk_pp(get_fact(p), *this) << "\n";); CTRACE("mk_and_elim", i >= to_app(get_fact(p))->get_num_args(), tout << "i: " << i << "\n" << mk_pp(get_fact(p), *this) << "\n";);
@ -3193,8 +3150,8 @@ proof * ast_manager::mk_and_elim(proof * p, unsigned i) {
} }
proof * ast_manager::mk_not_or_elim(proof * p, unsigned i) { proof * ast_manager::mk_not_or_elim(proof * p, unsigned i) {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
SASSERT(has_fact(p)); SASSERT(has_fact(p));
SASSERT(is_not(get_fact(p))); SASSERT(is_not(get_fact(p)));
SASSERT(is_or(to_app(get_fact(p))->get_arg(0))); SASSERT(is_or(to_app(get_fact(p))->get_arg(0)));
@ -3216,8 +3173,8 @@ proof * ast_manager::mk_th_lemma(
unsigned num_params, parameter const* params unsigned num_params, parameter const* params
) )
{ {
if (m_proof_mode == PGM_DISABLED) if (proofs_disabled())
return m_undef_proof; return nullptr;
ptr_buffer<expr> args; ptr_buffer<expr> args;
vector<parameter> parameters; vector<parameter> parameters;

View file

@ -1396,8 +1396,7 @@ public:
enum proof_gen_mode { enum proof_gen_mode {
PGM_DISABLED, PGM_DISABLED,
PGM_COARSE, PGM_ENABLED
PGM_FINE
}; };
// ----------------------------------- // -----------------------------------
@ -2088,15 +2087,14 @@ protected:
proof * mk_proof(family_id fid, decl_kind k, expr * arg1, expr * arg2); proof * mk_proof(family_id fid, decl_kind k, expr * arg1, expr * arg2);
proof * mk_proof(family_id fid, decl_kind k, expr * arg1, expr * arg2, expr * arg3); proof * mk_proof(family_id fid, decl_kind k, expr * arg1, expr * arg2, expr * arg3);
proof * mk_undef_proof() const { return m_undef_proof; }
public: public:
bool proofs_enabled() const { return m_proof_mode != PGM_DISABLED; } bool proofs_enabled() const { return m_proof_mode != PGM_DISABLED; }
bool proofs_disabled() const { return m_proof_mode == PGM_DISABLED; } bool proofs_disabled() const { return m_proof_mode == PGM_DISABLED; }
bool coarse_grain_proofs() const { return m_proof_mode == PGM_COARSE; }
bool fine_grain_proofs() const { return m_proof_mode == PGM_FINE; }
proof_gen_mode proof_mode() const { return m_proof_mode; } proof_gen_mode proof_mode() const { return m_proof_mode; }
void toggle_proof_mode(proof_gen_mode m) { m_proof_mode = m; } // APIs for creating proof objects return [undef] void toggle_proof_mode(proof_gen_mode m) { m_proof_mode = m; } // APIs for creating proof objects return [undef]
proof * mk_undef_proof() const { return m_undef_proof; }
bool is_proof(expr const * n) const { return is_app(n) && to_app(n)->get_decl()->get_range() == m_proof_sort; } bool is_proof(expr const * n) const { return is_app(n) && to_app(n)->get_decl()->get_range() == m_proof_sort; }

133
src/ast/ast_pp_dot.cpp Normal file
View file

@ -0,0 +1,133 @@
/*++
Abstract: Pretty-printer for proofs in Graphviz format
--*/
#include "util/util.h"
#include "util/map.h"
#include "ast/ast_pp_dot.h"
// string escaping for DOT
std::string escape_dot(std::string const & s) {
std::string res;
res.reserve(s.size()); // preallocate
for (auto c : s) {
if (c == '\n')
res.append("\\l");
else
res.push_back(c);
}
return res;
}
// map from proofs to unique IDs
typedef obj_map<const expr, unsigned> expr2id;
// temporary structure for traversing the proof and printing it
struct ast_pp_dot_st {
ast_manager & m_manager;
std::ostream & m_out;
const ast_pp_dot * m_pp;
unsigned m_next_id;
expr2id m_id_map;
obj_hashtable<const expr> m_printed;
svector<const expr *> m_to_print;
bool m_first;
ast_pp_dot_st(const ast_pp_dot * pp, std::ostream & out) :
m_manager(pp->get_manager()),
m_out(out),
m_pp(pp),
m_next_id(0),
m_id_map(),
m_printed(),
m_to_print(),
m_first(true) {}
~ast_pp_dot_st() {};
void push_term(const expr * a) { m_to_print.push_back(a); }
void pp_loop() {
// DFS traversal
while (!m_to_print.empty()) {
const expr * a = m_to_print.back();
m_to_print.pop_back();
if (!m_printed.contains(a)) {
m_printed.insert(a);
if (m().is_proof(a))
pp_step(to_app(a));
else
pp_atomic_step(a);
}
}
}
private:
inline ast_manager & m() const { return m_manager; }
// label for an expression
std::string label_of_expr(const expr * e) const {
expr_ref er((expr*)e, m());
std::ostringstream out;
out << er << std::flush;
return escape_dot(out.str());
}
void pp_atomic_step(const expr * e) {
unsigned id = get_id(e);
m_out << "node_" << id << " [shape=box,color=\"yellow\",style=\"filled\",label=\"" << label_of_expr(e) << "\"] ;" << std::endl;
}
void pp_step(const proof * p) {
TRACE("pp_ast_dot_step", tout << " :kind " << p->get_kind() << " :num-args " << p->get_num_args() << "\n";);
if (m().has_fact(p)) {
// print result
expr* p_res = m().get_fact(p); // result of proof step
unsigned id = get_id(p);
unsigned num_parents = m().get_num_parents(p);
const char* color =
m_first ? (m_first=false,"color=\"red\"") : num_parents==0 ? "color=\"yellow\"": "";
m_out << "node_" << id <<
" [shape=box,style=\"filled\",label=\"" << label_of_expr(p_res) << "\""
<< color << "]" << std::endl;
// now print edges to parents (except last one, which is the result)
std::string label = p->get_decl()->get_name().str();
for (unsigned i = 0 ; i < num_parents; ++i) {
expr* parent = m().get_parent(p, i);
// explore parent, also print a link to it
push_term(to_app(parent));
m_out << "node_" << id << " -> " << "node_" << get_id((expr*)parent)
<< "[label=\"" << label << "\"];" << std::endl;;
}
} else {
pp_atomic_step(p);
}
}
// find a unique ID for this proof
unsigned get_id(const expr * e) {
unsigned id = 0;
if (!m_id_map.find(e, id)) {
id = m_next_id++;
m_id_map.insert(e, id);
}
return id;
}
};
// main printer
std::ostream & ast_pp_dot::pp(std::ostream & out) const {
out << "digraph proof { " << std::endl;
ast_pp_dot_st pp_st(this, out);
pp_st.push_term(m_pr);
pp_st.pp_loop();
out << std::endl << " } " << std::endl << std::flush;
return out;
}
std::ostream &operator<<(std::ostream &out, const ast_pp_dot & p) { return p.pp(out); }

24
src/ast/ast_pp_dot.h Normal file
View file

@ -0,0 +1,24 @@
/*++
Abstract: Pretty-printer for proofs in Graphviz format
--*/
#pragma once
#include <iostream>
#include "ast_pp.h"
class ast_pp_dot {
ast_manager & m_manager;
proof * const m_pr;
public:
ast_pp_dot(proof *pr, ast_manager &m) : m_manager(m), m_pr(pr) {}
ast_pp_dot(proof_ref &e) : m_manager(e.m()), m_pr(e.get()) {}
std::ostream & pp(std::ostream & out) const;
ast_manager & get_manager() const { return m_manager; }
};
std::ostream &operator<<(std::ostream &out, const ast_pp_dot & p);

View file

@ -44,6 +44,7 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len) co
return mk_string(m, str.c_str()); return mk_string(m, str.c_str());
} }
else if (!s.bare_str()) { else if (!s.bare_str()) {
len = 4;
return mk_string(m, "null"); return mk_string(m, "null");
} }
else { else {

View file

@ -250,7 +250,7 @@ bv2fpa_converter::array_model bv2fpa_converter::convert_array_func_interp(model_
am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng); am.new_float_fd = m.mk_fresh_func_decl(arity, array_domain.c_ptr(), rng);
am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f); am.new_float_fi = convert_func_interp(mc, am.new_float_fd, bv_f);
am.bv_fd = bv_f; am.bv_fd = bv_f;
am.result = arr_util.mk_as_array(f->get_range(), am.new_float_fd); am.result = arr_util.mk_as_array(am.new_float_fd);
return am; return am;
} }

View file

@ -3076,8 +3076,6 @@ void fpa2bv_converter::mk_to_ieee_bv(func_decl * f, unsigned num, expr * const *
split_fp(x, sgn, e, s); split_fp(x, sgn, e, s);
mk_is_nan(x, x_is_nan); mk_is_nan(x, x_is_nan);
sort * fp_srt = m.get_sort(x);
expr_ref unspec(m); expr_ref unspec(m);
mk_to_ieee_bv_unspecified(f, num, args, unspec); mk_to_ieee_bv_unspecified(f, num, args, unspec);

View file

@ -229,7 +229,7 @@ struct pull_quant::imp {
proofs.push_back(m_manager.mk_pull_quant(arg, to_quantifier(new_arg))); proofs.push_back(m_manager.mk_pull_quant(arg, to_quantifier(new_arg)));
} }
pull_quant1(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr(), r); pull_quant1(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr(), r);
if (m_manager.fine_grain_proofs()) { if (m_manager.proofs_enabled()) {
app * r1 = m_manager.mk_app(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr()); app * r1 = m_manager.mk_app(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr());
proof * p1 = proofs.empty() ? 0 : m_manager.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr()); proof * p1 = proofs.empty() ? 0 : m_manager.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr());
proof * p2 = r1 == r ? 0 : m_manager.mk_pull_quant(r1, to_quantifier(r)); proof * p2 = r1 == r ? 0 : m_manager.mk_pull_quant(r1, to_quantifier(r));
@ -240,7 +240,7 @@ struct pull_quant::imp {
expr_ref new_expr(m_manager); expr_ref new_expr(m_manager);
pull_quant1(to_quantifier(n)->get_expr(), new_expr); pull_quant1(to_quantifier(n)->get_expr(), new_expr);
pull_quant1(to_quantifier(n), new_expr, r); pull_quant1(to_quantifier(n), new_expr, r);
if (m_manager.fine_grain_proofs()) { if (m_manager.proofs_enabled()) {
quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr); quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr);
proof * p1 = 0; proof * p1 = 0;
if (n != q1) { if (n != q1) {

View file

@ -606,7 +606,7 @@ bool pattern_inference_cfg::reduce_quantifier(
result = m.update_quantifier_weight(tmp, new_weight); result = m.update_quantifier_weight(tmp, new_weight);
TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";); TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";);
} }
if (m.fine_grain_proofs()) if (m.proofs_enabled())
result_pr = m.mk_rewrite(q, new_q); result_pr = m.mk_rewrite(q, new_q);
return true; return true;
} }
@ -671,7 +671,7 @@ bool pattern_inference_cfg::reduce_quantifier(
quantifier_ref new_q(m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body), m); quantifier_ref new_q(m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body), m);
if (weight != q->get_weight()) if (weight != q->get_weight())
new_q = m.update_quantifier_weight(new_q, weight); new_q = m.update_quantifier_weight(new_q, weight);
if (m.fine_grain_proofs()) { if (m.proofs_enabled()) {
proof* new_body_pr = m.mk_reflexivity(new_body); proof* new_body_pr = m.mk_reflexivity(new_body);
result_pr = m.mk_quant_intro(q, new_q, new_body_pr); result_pr = m.mk_quant_intro(q, new_q, new_body_pr);
} }
@ -689,7 +689,7 @@ bool pattern_inference_cfg::reduce_quantifier(
warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str()); warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str());
} }
new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr()); new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr());
if (m.fine_grain_proofs()) { if (m.proofs_enabled()) {
result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_reflexivity(new_q->get_expr()))); result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_reflexivity(new_q->get_expr())));
} }
TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";); TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";);

View file

@ -1,6 +1,7 @@
z3_add_component(proof_checker z3_add_component(proofs
SOURCES SOURCES
proof_checker.cpp proof_checker.cpp
proof_utils.cpp
COMPONENT_DEPENDENCIES COMPONENT_DEPENDENCIES
rewriter rewriter
) )

View file

@ -4,10 +4,9 @@ Copyright (c) 2015 Microsoft Corporation
--*/ --*/
#include "ast/proof_checker/proof_checker.h" #include "ast/proofs/proof_checker.h"
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h" #include "ast/ast_pp.h"
// include "spc_decl_plugin.h"
#include "ast/ast_smt_pp.h" #include "ast/ast_smt_pp.h"
#include "ast/arith_decl_plugin.h" #include "ast/arith_decl_plugin.h"
#include "ast/rewriter/th_rewriter.h" #include "ast/rewriter/th_rewriter.h"

View file

@ -1,15 +1,343 @@
/*++ /*++
Copyright (c) 2015 Microsoft Corporation Copyright (c) 2017 Arie Gurfinkel
Module Name:
proof_utils.cpp
Abstract:
Utilities to traverse and manipulate proofs
Author:
Bernhard Gleiss
Arie Gurfinkel
Revision History:
--*/ --*/
#include "muz/base/dl_util.h" #include "ast/ast_util.h"
#include "muz/base/proof_utils.h" #include "ast/ast_pp.h"
#include "ast/ast_smt2_pp.h" #include "ast/proofs/proof_utils.h"
#include "ast/proofs/proof_checker.h"
#include "ast/rewriter/var_subst.h" #include "ast/rewriter/var_subst.h"
#include "util/container_util.h"
proof_post_order::proof_post_order(proof* root, ast_manager& manager) : m(manager)
{m_todo.push_back(root);}
bool proof_post_order::hasNext()
{return !m_todo.empty();}
/*
* iterative post-order depth-first search (DFS) through the proof DAG
*/
proof* proof_post_order::next()
{
while (!m_todo.empty()) {
proof* currentNode = m_todo.back();
// if we haven't already visited the current unit
if (!m_visited.is_marked(currentNode)) {
bool existsUnvisitedParent = false;
// add unprocessed premises to stack for DFS.
// If there is at least one unprocessed premise, don't compute the result
// for currentProof now, but wait until those unprocessed premises are processed.
for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) {
SASSERT(m.is_proof(currentNode->get_arg(i)));
proof* premise = to_app(currentNode->get_arg(i));
// if we haven't visited the current premise yet
if (!m_visited.is_marked(premise)) {
// add it to the stack
m_todo.push_back(premise);
existsUnvisitedParent = true;
}
}
// if we already visited all parent-inferences, we can visit the inference too
if (!existsUnvisitedParent) {
m_visited.mark(currentNode, true);
m_todo.pop_back();
return currentNode;
}
} else {
m_todo.pop_back();
}
}
// we have already iterated through all inferences
return nullptr;
}
class reduce_hypotheses { class reduce_hypotheses {
ast_manager &m;
// tracking all created expressions
expr_ref_vector m_pinned;
// cache for the transformation
obj_map<proof, proof*> m_cache;
// map from unit literals to their hypotheses-free derivations
obj_map<expr, proof*> m_units;
// -- all hypotheses in the the proof
obj_hashtable<expr> m_hyps;
// marks hypothetical proofs
ast_mark m_hypmark;
// stack
ptr_vector<proof> m_todo;
void reset()
{
m_cache.reset();
m_units.reset();
m_hyps.reset();
m_hypmark.reset();
m_pinned.reset();
}
bool compute_mark1(proof *pr)
{
bool hyp_mark = false;
// lemmas clear all hypotheses
if (!m.is_lemma(pr)) {
for (unsigned i = 0, sz = m.get_num_parents(pr); i < sz; ++i) {
if (m_hypmark.is_marked(m.get_parent(pr, i))) {
hyp_mark = true;
break;
}
}
}
m_hypmark.mark(pr, hyp_mark);
return hyp_mark;
}
void compute_marks(proof* pr) {
proof *p;
proof_post_order pit(pr, m);
while (pit.hasNext()) {
p = pit.next();
if (m.is_hypothesis(p)) {
m_hypmark.mark(p, true);
m_hyps.insert(m.get_fact(p));
}
else {
bool hyp_mark = compute_mark1(p);
// collect units that are hyp-free and are used as hypotheses somewhere
if (!hyp_mark && m.has_fact(p) && m_hyps.contains(m.get_fact(p))) {
m_units.insert(m.get_fact(p), p);
}
}
}
}
void find_units(proof *pr)
{
// optional. not implemented yet.
}
void reduce(proof* pf, proof_ref &out)
{
proof *res = NULL;
m_todo.reset();
m_todo.push_back(pf);
ptr_buffer<proof> args;
bool dirty = false;
while (!m_todo.empty()) {
proof *p, *tmp, *pp;
unsigned todo_sz;
p = m_todo.back();
if (m_cache.find(p, tmp)) {
res = tmp;
m_todo.pop_back();
continue;
}
dirty = false;
args.reset();
todo_sz = m_todo.size();
for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) {
pp = m.get_parent(p, i);
if (m_cache.find(pp, tmp)) {
args.push_back(tmp);
dirty = dirty || pp != tmp;
} else {
m_todo.push_back(pp);
}
}
if (todo_sz < m_todo.size()) { continue; }
else { m_todo.pop_back(); }
if (m.is_hypothesis(p)) {
// hyp: replace by a corresponding unit
if (m_units.find(m.get_fact(p), tmp)) {
res = tmp;
} else { res = p; }
}
else if (!dirty) { res = p; }
else if (m.is_lemma(p)) {
//lemma: reduce the premise; remove reduced consequences from conclusion
SASSERT(args.size() == 1);
res = mk_lemma_core(args.get(0), m.get_fact(p));
compute_mark1(res);
} else if (m.is_unit_resolution(p)) {
// unit: reduce untis; reduce the first premise; rebuild unit resolution
res = mk_unit_resolution_core(args.size(), args.c_ptr());
compute_mark1(res);
} else {
// other: reduce all premises; reapply
if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); }
SASSERT(p->get_decl()->get_arity() == args.size());
res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr());
m_pinned.push_back(res);
compute_mark1(res);
}
SASSERT(res);
m_cache.insert(p, res);
if (m.has_fact(res) && m.is_false(m.get_fact(res))) { break; }
}
out = res;
}
// returns true if (hypothesis (not a)) would be reduced
bool is_reduced(expr *a)
{
expr_ref e(m);
if (m.is_not(a)) { e = to_app(a)->get_arg(0); }
else { e = m.mk_not(a); }
return m_units.contains(e);
}
proof *mk_lemma_core(proof *pf, expr *fact)
{
ptr_buffer<expr> args;
expr_ref lemma(m);
if (m.is_or(fact)) {
for (unsigned i = 0, sz = to_app(fact)->get_num_args(); i < sz; ++i) {
expr *a = to_app(fact)->get_arg(i);
if (!is_reduced(a))
{ args.push_back(a); }
}
} else if (!is_reduced(fact))
{ args.push_back(fact); }
if (args.size() == 0) { return pf; }
else if (args.size() == 1) {
lemma = args.get(0);
} else {
lemma = m.mk_or(args.size(), args.c_ptr());
}
proof* res = m.mk_lemma(pf, lemma);
m_pinned.push_back(res);
if (m_hyps.contains(lemma))
{ m_units.insert(lemma, res); }
return res;
}
proof *mk_unit_resolution_core(unsigned num_args, proof* const *args)
{
ptr_buffer<proof> pf_args;
pf_args.push_back(args [0]);
app *cls_fact = to_app(m.get_fact(args[0]));
ptr_buffer<expr> cls;
if (m.is_or(cls_fact)) {
for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i)
{ cls.push_back(cls_fact->get_arg(i)); }
} else { cls.push_back(cls_fact); }
// construct new resovent
ptr_buffer<expr> new_fact_cls;
bool found;
// XXX quadratic
for (unsigned i = 0, sz = cls.size(); i < sz; ++i) {
found = false;
for (unsigned j = 1; j < num_args; ++j) {
if (m.is_complement(cls.get(i), m.get_fact(args [j]))) {
found = true;
pf_args.push_back(args [j]);
break;
}
}
if (!found) {
new_fact_cls.push_back(cls.get(i));
}
}
SASSERT(new_fact_cls.size() + pf_args.size() - 1 == cls.size());
expr_ref new_fact(m);
new_fact = mk_or(m, new_fact_cls.size(), new_fact_cls.c_ptr());
// create new proof step
proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact);
m_pinned.push_back(res);
return res;
}
// reduce all units, if any unit reduces to false return true and put its proof into out
bool reduce_units(proof_ref &out)
{
proof_ref res(m);
for (auto entry : m_units) {
reduce(entry.get_value(), res);
if (m.is_false(m.get_fact(res))) {
out = res;
return true;
}
res.reset();
}
return false;
}
public:
reduce_hypotheses(ast_manager &m) : m(m), m_pinned(m) {}
void operator()(proof_ref &pr)
{
compute_marks(pr);
if (!reduce_units(pr)) {
reduce(pr.get(), pr);
}
reset();
}
};
void reduce_hypotheses(proof_ref &pr) {
ast_manager &m = pr.get_manager();
class reduce_hypotheses hypred(m);
hypred(pr);
DEBUG_CODE(proof_checker pc(m);
expr_ref_vector side(m);
SASSERT(pc.check(pr, side));
);
}
#include "ast/ast_smt2_pp.h"
class reduce_hypotheses0 {
typedef obj_hashtable<expr> expr_set; typedef obj_hashtable<expr> expr_set;
ast_manager& m; ast_manager& m;
// reference for any expression created by the tranformation // reference for any expression created by the tranformation
@ -85,7 +413,7 @@ class reduce_hypotheses {
m_hyprefs.push_back(hyps); m_hyprefs.push_back(hyps);
inherited = false; inherited = false;
} }
datalog::set_union(*hyps, *hyps1); set_union(*hyps, *hyps1);
} }
} }
} }
@ -137,7 +465,7 @@ class reduce_hypotheses {
} }
public: public:
reduce_hypotheses(ast_manager& m): m(m), m_refs(m) {} reduce_hypotheses0(ast_manager& m): m(m), m_refs(m) {}
void operator()(proof_ref& pr) { void operator()(proof_ref& pr) {
proof_ref tmp(m); proof_ref tmp(m);
@ -416,7 +744,7 @@ public:
void proof_utils::reduce_hypotheses(proof_ref& pr) { void proof_utils::reduce_hypotheses(proof_ref& pr) {
ast_manager& m = pr.get_manager(); ast_manager& m = pr.get_manager();
class reduce_hypotheses reduce(m); class reduce_hypotheses0 reduce(m);
reduce(pr); reduce(pr);
CTRACE("proof_utils", !is_closed(m, pr), tout << mk_pp(pr, m) << "\n";); CTRACE("proof_utils", !is_closed(m, pr), tout << mk_pp(pr, m) << "\n";);
} }

View file

@ -0,0 +1,238 @@
/*++
Copyright (c) 2017 Microsoft Corporation
Module Name:
proof_utils.h
Abstract:
Utilities to traverse and manipulate proofs
Author:
Bernhard Gleiss
Arie Gurfinkel
Nikolaj Bjorner
Revision History:
--*/
#ifndef PROOF_UTILS_H_
#define PROOF_UTILS_H_
#include "ast/ast.h"
#include "ast/ast_pp.h"
#include "ast/rewriter/bool_rewriter.h"
#include "ast/proofs/proof_checker.h"
/*
* iterator, which traverses the proof in depth-first post-order.
*/
class proof_post_order {
public:
proof_post_order(proof* refutation, ast_manager& manager);
bool hasNext();
proof* next();
private:
ptr_vector<proof> m_todo;
ast_mark m_visited; // the proof nodes we have already visited
ast_manager& m;
};
void reduce_hypotheses(proof_ref &pr);
class proof_utils {
public:
/**
\brief reduce the set of hypotheses used in the proof.
*/
static void reduce_hypotheses(proof_ref& pr);
/**
\brief Check that a proof does not contain open hypotheses.
*/
static bool is_closed(ast_manager& m, proof* p);
/**
\brief Permute unit resolution rule with th-lemma
*/
static void permute_unit_resolution(proof_ref& pr);
/**
\brief Push instantiations created in hyper-resolutions up to leaves.
This produces a "ground" proof where leaves are annotated by instantiations.
*/
static void push_instantiations_up(proof_ref& pr);
};
class elim_aux_assertions {
static bool matches_fact(expr_ref_vector &args, expr* &match) {
ast_manager &m = args.get_manager();
expr *fact = args.back();
for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i) {
expr *arg = args.get(i);
if (m.is_proof(arg) &&
m.has_fact(to_app(arg)) &&
m.get_fact(to_app(arg)) == fact) {
match = arg;
return true;
}
}
return false;
}
app_ref m_aux;
public:
elim_aux_assertions(app_ref aux) : m_aux(aux) {}
void mk_or_core(expr_ref_vector &args, expr_ref &res)
{
ast_manager &m = args.get_manager();
unsigned j = 0;
for (unsigned i = 0, sz = args.size(); i < sz; ++i) {
if (m.is_false(args.get(i))) { continue; }
if (i != j) { args [j] = args.get(i); }
++j;
}
SASSERT(j >= 1);
res = j > 1 ? m.mk_or(j, args.c_ptr()) : args.get(0);
}
void mk_app(func_decl *decl, expr_ref_vector &args, expr_ref &res)
{
ast_manager &m = args.get_manager();
bool_rewriter brwr(m);
if (m.is_or(decl))
{ mk_or_core(args, res); }
else if (m.is_iff(decl) && args.size() == 2)
// avoiding simplifying equalities. In particular,
// we don't want (= (not a) (not b)) to be reduced to (= a b)
{ res = m.mk_iff(args.get(0), args.get(1)); }
else
{ brwr.mk_app(decl, args.size(), args.c_ptr(), res); }
}
void operator()(ast_manager &m, proof *pr, proof_ref &res)
{
DEBUG_CODE(proof_checker pc(m);
expr_ref_vector side(m);
SASSERT(pc.check(pr, side));
);
obj_map<app, app*> cache;
bool_rewriter brwr(m);
// for reference counting of new proofs
app_ref_vector pinned(m);
ptr_vector<app> todo;
todo.push_back(pr);
expr_ref not_aux(m);
not_aux = m.mk_not(m_aux);
expr_ref_vector args(m);
while (!todo.empty()) {
app *p, *r;
expr *a;
p = todo.back();
if (cache.find(pr, r)) {
todo.pop_back();
continue;
}
SASSERT(!todo.empty() || pr == p);
bool dirty = false;
unsigned todo_sz = todo.size();
args.reset();
for (unsigned i = 0, sz = p->get_num_args(); i < sz; ++i) {
expr* arg = p->get_arg(i);
if (arg == m_aux.get()) {
dirty = true;
args.push_back(m.mk_true());
} else if (arg == not_aux.get()) {
dirty = true;
args.push_back(m.mk_false());
}
// skip (asserted m_aux)
else if (m.is_asserted(arg, a) && a == m_aux.get()) {
dirty = true;
}
// skip (hypothesis m_aux)
else if (m.is_hypothesis(arg, a) && a == m_aux.get()) {
dirty = true;
} else if (is_app(arg) && cache.find(to_app(arg), r)) {
dirty |= (arg != r);
args.push_back(r);
} else if (is_app(arg))
{ todo.push_back(to_app(arg)); }
else
// -- not an app
{ args.push_back(arg); }
}
if (todo_sz < todo.size()) {
// -- process parents
args.reset();
continue;
}
// ready to re-create
app_ref newp(m);
if (!dirty) { newp = p; }
else if (m.is_unit_resolution(p)) {
if (args.size() == 2)
// unit resolution with m_aux that got collapsed to nothing
{ newp = to_app(args.get(0)); }
else {
ptr_vector<proof> parents;
for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i)
{ parents.push_back(to_app(args.get(i))); }
SASSERT(parents.size() == args.size() - 1);
newp = m.mk_unit_resolution(parents.size(), parents.c_ptr());
// XXX the old and new facts should be
// equivalent. The test here is much
// stronger. It might need to be relaxed.
SASSERT(m.get_fact(newp) == args.back());
pinned.push_back(newp);
}
} else if (matches_fact(args, a)) {
newp = to_app(a);
} else {
expr_ref papp(m);
mk_app(p->get_decl(), args, papp);
newp = to_app(papp.get());
pinned.push_back(newp);
}
cache.insert(p, newp);
todo.pop_back();
CTRACE("virtual",
p->get_decl_kind() == PR_TH_LEMMA &&
p->get_decl()->get_parameter(0).get_symbol() == "arith" &&
p->get_decl()->get_num_parameters() > 1 &&
p->get_decl()->get_parameter(1).get_symbol() == "farkas",
tout << "Old pf: " << mk_pp(p, m) << "\n"
<< "New pf: " << mk_pp(newp, m) << "\n";);
}
proof *r;
VERIFY(cache.find(pr, r));
DEBUG_CODE(
proof_checker pc(m);
expr_ref_vector side(m);
SASSERT(pc.check(r, side));
);
res = r ;
}
};
#endif

View file

@ -119,7 +119,6 @@ br_status fpa_rewriter::mk_to_fp(func_decl * f, unsigned num_args, expr * const
// BV -> float // BV -> float
SASSERT(bvs1 == sbits + ebits); SASSERT(bvs1 == sbits + ebits);
unsynch_mpz_manager & mpzm = m_fm.mpz_manager(); unsynch_mpz_manager & mpzm = m_fm.mpz_manager();
unsynch_mpq_manager & mpqm = m_fm.mpq_manager();
scoped_mpz sig(mpzm), exp(mpzm); scoped_mpz sig(mpzm), exp(mpzm);
const mpz & sm1 = m_fm.m_powers2(sbits - 1); const mpz & sm1 = m_fm.m_powers2(sbits - 1);

View file

@ -351,7 +351,6 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
if (is_ground(def)) { if (is_ground(def)) {
m_r = def; m_r = def;
if (ProofGen) { if (ProofGen) {
SASSERT(def_pr);
m_pr = m().mk_transitivity(m_pr, def_pr); m_pr = m().mk_transitivity(m_pr, def_pr);
} }
} }
@ -510,7 +509,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
new_no_pats = q->get_no_patterns(); new_no_pats = q->get_no_patterns();
} }
if (ProofGen) { if (ProofGen) {
quantifier * new_q = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body); quantifier_ref new_q(m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body), m());
m_pr = q == new_q ? 0 : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos)); m_pr = q == new_q ? 0 : m().mk_quant_intro(q, new_q, result_pr_stack().get(fr.m_spos));
m_r = new_q; m_r = new_q;
proof_ref pr2(m()); proof_ref pr2(m());

View file

@ -37,7 +37,7 @@ public:
class scoped_proof : public scoped_proof_mode { class scoped_proof : public scoped_proof_mode {
public: public:
scoped_proof(ast_manager& m): scoped_proof_mode(m, PGM_FINE) {} scoped_proof(ast_manager& m): scoped_proof_mode(m, PGM_ENABLED) {}
}; };
class scoped_no_proof : public scoped_proof_mode { class scoped_no_proof : public scoped_proof_mode {

View file

@ -20,6 +20,7 @@ Notes:
#include "util/version.h" #include "util/version.h"
#include "ast/ast_smt_pp.h" #include "ast/ast_smt_pp.h"
#include "ast/ast_smt2_pp.h" #include "ast/ast_smt2_pp.h"
#include "ast/ast_pp_dot.h"
#include "ast/ast_pp.h" #include "ast/ast_pp.h"
#include "ast/array_decl_plugin.h" #include "ast/array_decl_plugin.h"
#include "ast/pp.h" #include "ast/pp.h"
@ -202,6 +203,26 @@ ATOMIC_CMD(get_proof_cmd, "get-proof", "retrieve proof", {
} }
}); });
ATOMIC_CMD(get_proof_graph_cmd, "get-proof-graph", "retrieve proof and print it in graphviz", {
if (!ctx.produce_proofs())
throw cmd_exception("proof construction is not enabled, use command (set-option :produce-proofs true)");
if (!ctx.has_manager() ||
ctx.cs_state() != cmd_context::css_unsat)
throw cmd_exception("proof is not available");
proof_ref pr(ctx.m());
pr = ctx.get_check_sat_result()->get_proof();
if (pr == 0)
throw cmd_exception("proof is not available");
if (ctx.well_sorted_check_enabled() && !is_well_sorted(ctx.m(), pr)) {
throw cmd_exception("proof is not well sorted");
}
context_params& params = ctx.params();
const std::string& file = params.m_dot_proof_file;
std::ofstream out(file);
out << ast_pp_dot(pr) << std::endl;
});
static void print_core(cmd_context& ctx) { static void print_core(cmd_context& ctx) {
ptr_vector<expr> core; ptr_vector<expr> core;
ctx.get_check_sat_result()->get_unsat_core(core); ctx.get_check_sat_result()->get_unsat_core(core);
@ -840,6 +861,7 @@ void install_basic_cmds(cmd_context & ctx) {
ctx.insert(alloc(get_assignment_cmd)); ctx.insert(alloc(get_assignment_cmd));
ctx.insert(alloc(get_assertions_cmd)); ctx.insert(alloc(get_assertions_cmd));
ctx.insert(alloc(get_proof_cmd)); ctx.insert(alloc(get_proof_cmd));
ctx.insert(alloc(get_proof_graph_cmd));
ctx.insert(alloc(get_unsat_core_cmd)); ctx.insert(alloc(get_unsat_core_cmd));
ctx.insert(alloc(set_option_cmd)); ctx.insert(alloc(set_option_cmd));
ctx.insert(alloc(get_option_cmd)); ctx.insert(alloc(get_option_cmd));

View file

@ -774,7 +774,6 @@ bool cmd_context::is_func_decl(symbol const & s) const {
} }
void cmd_context::insert(symbol const & s, func_decl * f) { void cmd_context::insert(symbol const & s, func_decl * f) {
m_check_sat_result = 0;
if (!m_check_logic(f)) { if (!m_check_logic(f)) {
throw cmd_exception(m_check_logic.get_last_error()); throw cmd_exception(m_check_logic.get_last_error());
} }
@ -805,7 +804,6 @@ void cmd_context::insert(symbol const & s, func_decl * f) {
} }
void cmd_context::insert(symbol const & s, psort_decl * p) { void cmd_context::insert(symbol const & s, psort_decl * p) {
m_check_sat_result = 0;
if (m_psort_decls.contains(s)) { if (m_psort_decls.contains(s)) {
throw cmd_exception("sort already defined ", s); throw cmd_exception("sort already defined ", s);
} }
@ -819,7 +817,6 @@ void cmd_context::insert(symbol const & s, psort_decl * p) {
void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) { void cmd_context::insert(symbol const & s, unsigned arity, sort *const* domain, expr * t) {
expr_ref _t(t, m()); expr_ref _t(t, m());
m_check_sat_result = 0;
if (m_builtin_decls.contains(s)) { if (m_builtin_decls.contains(s)) {
throw cmd_exception("invalid macro/named expression, builtin symbol ", s); throw cmd_exception("invalid macro/named expression, builtin symbol ", s);
} }
@ -1066,16 +1063,31 @@ void cmd_context::mk_app(symbol const & s, unsigned num_args, expr * const * arg
if (fs.more_than_one()) if (fs.more_than_one())
throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as <symbol> <sort>) to disumbiguate ", s); throw cmd_exception("ambiguous constant reference, more than one constant with the same sort, use a qualified expression (as <symbol> <sort>) to disumbiguate ", s);
func_decl * f = fs.first(); func_decl * f = fs.first();
if (f == 0) if (f == 0) {
throw cmd_exception("unknown constant ", s); throw cmd_exception("unknown constant ", s);
}
if (f->get_arity() != 0) if (f->get_arity() != 0)
throw cmd_exception("invalid function application, missing arguments ", s); throw cmd_exception("invalid function application, missing arguments ", s);
result = m().mk_const(f); result = m().mk_const(f);
} }
else { else {
func_decl * f = fs.find(m(), num_args, args, range); func_decl * f = fs.find(m(), num_args, args, range);
if (f == 0) if (f == 0) {
throw cmd_exception("unknown constant ", s); std::ostringstream buffer;
buffer << "unknown constant " << s << " ";
buffer << " (";
bool first = true;
for (unsigned i = 0; i < num_args; ++i, first = false) {
if (!first) buffer << " ";
buffer << mk_pp(m().get_sort(args[i]), m());
}
buffer << ") ";
if (range) buffer << mk_pp(range, m()) << " ";
for (unsigned i = 0; i < fs.get_num_entries(); ++i) {
buffer << "\ndeclared: " << mk_pp(fs.get_entry(i), m()) << " ";
}
throw cmd_exception(buffer.str().c_str());
}
if (well_sorted_check_enabled()) if (well_sorted_check_enabled())
m().check_sort(f, num_args, args); m().check_sort(f, num_args, args);
result = m().mk_app(f, num_args, args); result = m().mk_app(f, num_args, args);

View file

@ -111,6 +111,9 @@ void context_params::set(char const * param, char const * value) {
else if (p == "trace_file_name") { else if (p == "trace_file_name") {
m_trace_file_name = value; m_trace_file_name = value;
} }
else if (p == "dot_proof_file") {
m_dot_proof_file = value;
}
else if (p == "unsat_core") { else if (p == "unsat_core") {
set_bool(m_unsat_core, param, value); set_bool(m_unsat_core, param, value);
} }
@ -146,6 +149,7 @@ void context_params::updt_params(params_ref const & p) {
m_dump_models = p.get_bool("dump_models", m_dump_models); m_dump_models = p.get_bool("dump_models", m_dump_models);
m_trace = p.get_bool("trace", m_trace); m_trace = p.get_bool("trace", m_trace);
m_trace_file_name = p.get_str("trace_file_name", "z3.log"); m_trace_file_name = p.get_str("trace_file_name", "z3.log");
m_dot_proof_file = p.get_str("dot_proof_file", "proof.dot");
m_unsat_core = p.get_bool("unsat_core", m_unsat_core); m_unsat_core = p.get_bool("unsat_core", m_unsat_core);
m_debug_ref_count = p.get_bool("debug_ref_count", m_debug_ref_count); m_debug_ref_count = p.get_bool("debug_ref_count", m_debug_ref_count);
m_smtlib2_compliant = p.get_bool("smtlib2_compliant", m_smtlib2_compliant); m_smtlib2_compliant = p.get_bool("smtlib2_compliant", m_smtlib2_compliant);
@ -161,6 +165,7 @@ void context_params::collect_param_descrs(param_descrs & d) {
d.insert("dump_models", CPK_BOOL, "dump models whenever check-sat returns sat", "false"); d.insert("dump_models", CPK_BOOL, "dump models whenever check-sat returns sat", "false");
d.insert("trace", CPK_BOOL, "trace generation for VCC", "false"); d.insert("trace", CPK_BOOL, "trace generation for VCC", "false");
d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log"); d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log");
d.insert("dot_proof_file", CPK_STRING, "file in which to output graphical proofs", "proof.dot");
d.insert("debug_ref_count", CPK_BOOL, "debug support for AST reference counting", "false"); d.insert("debug_ref_count", CPK_BOOL, "debug support for AST reference counting", "false");
d.insert("smtlib2_compliant", CPK_BOOL, "enable/disable SMT-LIB 2.0 compliance", "false"); d.insert("smtlib2_compliant", CPK_BOOL, "enable/disable SMT-LIB 2.0 compliance", "false");
collect_solver_param_descrs(d); collect_solver_param_descrs(d);
@ -192,7 +197,7 @@ void context_params::get_solver_params(ast_manager const & m, params_ref & p, bo
ast_manager * context_params::mk_ast_manager() { ast_manager * context_params::mk_ast_manager() {
ast_manager * r = alloc(ast_manager, ast_manager * r = alloc(ast_manager,
m_proof ? PGM_FINE : PGM_DISABLED, m_proof ? PGM_ENABLED : PGM_DISABLED,
m_trace ? m_trace_file_name.c_str() : 0); m_trace ? m_trace_file_name.c_str() : 0);
if (m_smtlib2_compliant) if (m_smtlib2_compliant)
r->enable_int_real_coercions(false); r->enable_int_real_coercions(false);

View file

@ -30,6 +30,7 @@ class context_params {
public: public:
bool m_auto_config; bool m_auto_config;
bool m_proof; bool m_proof;
std::string m_dot_proof_file;
bool m_interpolants; bool m_interpolants;
bool m_debug_ref_count; bool m_debug_ref_count;
bool m_trace; bool m_trace;

View file

@ -147,7 +147,7 @@ static void compute_interpolant_and_maybe_check(cmd_context & ctx, expr * t, par
ast_manager &_m = ctx.m(); ast_manager &_m = ctx.m();
// TODO: the following is a HACK to enable proofs in the old smt solver // TODO: the following is a HACK to enable proofs in the old smt solver
// When we stop using that solver, this hack can be removed // When we stop using that solver, this hack can be removed
scoped_proof_mode spm(_m,PGM_FINE); scoped_proof_mode spm(_m,PGM_ENABLED);
ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled); ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled);
p.set_bool("proof", true); p.set_bool("proof", true);
scoped_ptr<solver> sp = (ctx.get_interpolating_solver_factory())(_m, p, true, models_enabled, false, ctx.get_logic()); scoped_ptr<solver> sp = (ctx.get_interpolating_solver_factory())(_m, p, true, models_enabled, false, ctx.get_logic());

View file

@ -1575,6 +1575,7 @@ namespace Duality {
*/ */
int RPFP::SubtermTruth(hash_map<ast, int> &memo, const Term &f) { int RPFP::SubtermTruth(hash_map<ast, int> &memo, const Term &f) {
TRACE("duality", tout << f << "\n";);
if (memo.find(f) != memo.end()) { if (memo.find(f) != memo.end()) {
return memo[f]; return memo[f];
} }
@ -1657,83 +1658,6 @@ namespace Duality {
ands and, or, not. Returns result in memo. ands and, or, not. Returns result in memo.
*/ */
#if 0
int RPFP::GetLabelsRec(hash_map<ast,int> *memo, const Term &f, std::vector<symbol> &labels, bool labpos){
if(memo[labpos].find(f) != memo[labpos].end()){
return memo[labpos][f];
}
int res;
if(f.is_app()){
int nargs = f.num_args();
decl_kind k = f.decl().get_decl_kind();
if(k == Implies){
res = GetLabelsRec(memo,f.arg(1) || !f.arg(0), labels, labpos);
goto done;
}
if(k == And) {
res = 1;
for(int i = 0; i < nargs; i++){
int ar = GetLabelsRec(memo,f.arg(i), labels, labpos);
if(ar == 0){
res = 0;
goto done;
}
if(ar == 2)res = 2;
}
goto done;
}
else if(k == Or) {
res = 0;
for(int i = 0; i < nargs; i++){
int ar = GetLabelsRec(memo,f.arg(i), labels, labpos);
if(ar == 1){
res = 1;
goto done;
}
if(ar == 2)res = 2;
}
goto done;
}
else if(k == Not) {
int ar = GetLabelsRec(memo,f.arg(0), labels, !labpos);
res = (ar == 0) ? 1 : ((ar == 1) ? 0 : 2);
goto done;
}
}
{
bool pos; std::vector<symbol> names;
if(f.is_label(pos,names)){
res = GetLabelsRec(memo,f.arg(0), labels, labpos);
if(pos == labpos && res == (pos ? 1 : 0))
for(unsigned i = 0; i < names.size(); i++)
labels.push_back(names[i]);
goto done;
}
}
{
expr bv = dualModel.eval(f);
if(bv.is_app() && bv.decl().get_decl_kind() == Equal &&
bv.arg(0).is_array()){
bv = EvalArrayEquality(bv);
}
// Hack!!!! array equalities can occur negatively!
if(bv.is_app() && bv.decl().get_decl_kind() == Not &&
bv.arg(0).decl().get_decl_kind() == Equal &&
bv.arg(0).arg(0).is_array()){
bv = dualModel.eval(!EvalArrayEquality(bv.arg(0)));
}
if(eq(bv,ctx.bool_val(true)))
res = 1;
else if(eq(bv,ctx.bool_val(false)))
res = 0;
else
res = 2;
}
done:
memo[labpos][f] = res;
return res;
}
#endif
void RPFP::GetLabelsRec(hash_map<ast, int> &memo, const Term &f, std::vector<symbol> &labels, void RPFP::GetLabelsRec(hash_map<ast, int> &memo, const Term &f, std::vector<symbol> &labels,
hash_set<ast> *done, bool truth) { hash_set<ast> *done, bool truth) {
@ -1748,8 +1672,13 @@ namespace Duality {
} }
if (k == Iff) { if (k == Iff) {
int b = SubtermTruth(memo, f.arg(0)); int b = SubtermTruth(memo, f.arg(0));
if (b == 2) if (b == 2) {
throw "disaster in GetLabelsRec"; goto done;
// bypass error
std::ostringstream os;
os << "disaster in SubtermTruth processing " << f;
throw default_exception(os.str());
}
GetLabelsRec(memo, f.arg(1), labels, done, truth ? b : !b); GetLabelsRec(memo, f.arg(1), labels, done, truth ? b : !b);
goto done; goto done;
} }
@ -1825,8 +1754,11 @@ namespace Duality {
} }
if (k == Iff) { if (k == Iff) {
int b = SubtermTruth(memo, f.arg(0)); int b = SubtermTruth(memo, f.arg(0));
if (b == 2) if (b == 2) {
throw "disaster in ImplicantRed"; std::ostringstream os;
os << "disaster in SubtermTruth processing " << f;
throw default_exception(os.str());
}
ImplicantRed(memo, f.arg(1), lits, done, truth ? b : !b, dont_cares); ImplicantRed(memo, f.arg(1), lits, done, truth ? b : !b, dont_cares);
goto done; goto done;
} }

View file

@ -57,12 +57,12 @@ typedef ast raw_ast;
/** Wrapper around an ast pointer */ /** Wrapper around an ast pointer */
class ast_i { class ast_i {
protected: protected:
raw_ast *_ast; raw_ast *_ast;
public: public:
raw_ast * const &raw() const {return _ast;} raw_ast * const &raw() const {return _ast;}
ast_i(raw_ast *a){_ast = a;} ast_i(raw_ast *a){_ast = a;}
ast_i(){_ast = 0;} ast_i(){_ast = 0;}
bool eq(const ast_i &other) const { bool eq(const ast_i &other) const {
return _ast == other._ast; return _ast == other._ast;
@ -86,19 +86,19 @@ class ast_i {
/** Reference counting verison of above */ /** Reference counting verison of above */
class ast_r : public ast_i { class ast_r : public ast_i {
ast_manager *_m; ast_manager *_m;
public: public:
ast_r(ast_manager *m, raw_ast *a) : ast_i(a) { ast_r(ast_manager *m, raw_ast *a) : ast_i(a) {
_m = m; _m = m;
m->inc_ref(a); m->inc_ref(a);
} }
ast_r() {_m = 0;} ast_r() {_m = 0;}
ast_r(const ast_r &other) : ast_i(other) { ast_r(const ast_r &other) : ast_i(other) {
_m = other._m; _m = other._m;
if (_m) _m->inc_ref(_ast); if (_m) _m->inc_ref(_ast);
} }
ast_r &operator=(const ast_r &other) { ast_r &operator=(const ast_r &other) {
if(_ast) if(_ast)
_m->dec_ref(_ast); _m->dec_ref(_ast);
@ -107,12 +107,12 @@ class ast_r : public ast_i {
if (_m) _m->inc_ref(_ast); if (_m) _m->inc_ref(_ast);
return *this; return *this;
} }
~ast_r(){ ~ast_r() {
if(_ast) if(_ast)
_m->dec_ref(_ast); _m->dec_ref(_ast);
} }
ast_manager *mgr() const {return _m;} ast_manager *mgr() const {return _m;}
}; };

View file

@ -29,6 +29,7 @@
#include "interp/iz3profiling.h" #include "interp/iz3profiling.h"
#include "interp/iz3interp.h" #include "interp/iz3interp.h"
#include "interp/iz3proof_itp.h" #include "interp/iz3proof_itp.h"
#include "ast/ast_pp.h"
#include <assert.h> #include <assert.h>
#include <algorithm> #include <algorithm>
@ -1851,6 +1852,21 @@ public:
} }
break; break;
} }
case PR_TRANSITIVITY_STAR: {
// assume the premises are x = y, y = z, z = u, u = v, ..
ast x = arg(conc(prem(proof,0)),0);
ast y = arg(conc(prem(proof,0)),1);
ast z = arg(conc(prem(proof,1)),1);
res = iproof->make_transitivity(x,y,z,args[0],args[1]);
for (unsigned i = 2; i < nprems; ++i) {
y = z;
z = arg(conc(prem(proof,i)),1);
res = iproof->make_transitivity(x,y,z,res,args[i]);
}
break;
}
case PR_QUANT_INTRO: case PR_QUANT_INTRO:
case PR_MONOTONICITY: case PR_MONOTONICITY:
{ {
@ -2029,6 +2045,7 @@ public:
break; break;
} }
default: default:
IF_VERBOSE(0, verbose_stream() << "Unsupported proof rule: " << expr_ref((expr*)proof.raw(), *proof.mgr()) << "\n";);
// pfgoto(proof); // pfgoto(proof);
// SASSERT(0 && "translate_main: unsupported proof rule"); // SASSERT(0 && "translate_main: unsupported proof rule");
throw unsupported(); throw unsupported();

View file

@ -36,7 +36,7 @@ class iz3translation : public iz3base {
/** This is thrown when the proof cannot be translated. */ /** This is thrown when the proof cannot be translated. */
struct unsupported: public iz3_exception { struct unsupported: public iz3_exception {
unsupported(): iz3_exception("unsupported") {} unsupported(): iz3_exception("unsupported") { }
}; };
static iz3translation *create(iz3mgr &mgr, static iz3translation *create(iz3mgr &mgr,

View file

@ -10,7 +10,6 @@ z3_add_component(muz
dl_rule_transformer.cpp dl_rule_transformer.cpp
dl_util.cpp dl_util.cpp
hnf.cpp hnf.cpp
proof_utils.cpp
rule_properties.cpp rule_properties.cpp
COMPONENT_DEPENDENCIES COMPONENT_DEPENDENCIES
aig_tactic aig_tactic

View file

@ -53,7 +53,7 @@ Example from Boogie:
#include "muz/base/dl_boogie_proof.h" #include "muz/base/dl_boogie_proof.h"
#include "model/model_pp.h" #include "model/model_pp.h"
#include "muz/base/proof_utils.h" #include "ast/proofs/proof_utils.h"
#include "ast/ast_pp.h" #include "ast/ast_pp.h"
#include "ast/ast_util.h" #include "ast/ast_util.h"

View file

@ -453,7 +453,8 @@ namespace datalog {
return new_pred; return new_pred;
} }
void context::add_rule(expr* rl, symbol const& name, unsigned bound) { void context::add_rule(expr* rl, symbol const& name, unsigned bound) {
SASSERT(rl);
m_rule_fmls.push_back(rl); m_rule_fmls.push_back(rl);
m_rule_names.push_back(name); m_rule_names.push_back(name);
m_rule_bounds.push_back(bound); m_rule_bounds.push_back(bound);
@ -461,7 +462,7 @@ namespace datalog {
void context::flush_add_rules() { void context::flush_add_rules() {
datalog::rule_manager& rm = get_rule_manager(); datalog::rule_manager& rm = get_rule_manager();
scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED); scoped_proof_mode _scp(m, generate_proof_trace()?PGM_ENABLED:PGM_DISABLED);
while (m_rule_fmls_head < m_rule_fmls.size()) { while (m_rule_fmls_head < m_rule_fmls.size()) {
expr* fml = m_rule_fmls[m_rule_fmls_head].get(); expr* fml = m_rule_fmls[m_rule_fmls_head].get();
proof* p = generate_proof_trace()?m.mk_asserted(fml):0; proof* p = generate_proof_trace()?m.mk_asserted(fml):0;

View file

@ -141,7 +141,7 @@ namespace datalog {
void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) { void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_ENABLED:PGM_DISABLED);
proof_ref pr(p, m); proof_ref pr(p, m);
expr_ref fml1(m); expr_ref fml1(m);
bind_variables(fml, true, fml1); bind_variables(fml, true, fml1);
@ -343,7 +343,7 @@ namespace datalog {
} }
TRACE("dl", tout << rule_expr << "\n";); TRACE("dl", tout << rule_expr << "\n";);
scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_ENABLED:PGM_DISABLED);
proof_ref pr(m); proof_ref pr(m);
if (m_ctx.generate_proof_trace()) { if (m_ctx.generate_proof_trace()) {
pr = m.mk_asserted(rule_expr); pr = m.mk_asserted(rule_expr);

View file

@ -11,7 +11,7 @@ Abstract:
Author: Author:
Leonardo de Moura (leonardo) 2010-05-20. Krystof Hoder 2010
Revision History: Revision History:
@ -31,6 +31,7 @@ Revision History:
#include "util/statistics.h" #include "util/statistics.h"
#include "util/stopwatch.h" #include "util/stopwatch.h"
#include "util/lbool.h" #include "util/lbool.h"
#include "util/container_util.h"
namespace datalog { namespace datalog {
@ -381,129 +382,6 @@ namespace datalog {
*/ */
void apply_subst(expr_ref_vector& tgt, expr_ref_vector const& sub); void apply_subst(expr_ref_vector& tgt, expr_ref_vector const& sub);
// -----------------------------------
//
// container functions
//
// -----------------------------------
template<class Set1, class Set2>
void set_intersection(Set1 & tgt, const Set2 & src) {
svector<typename Set1::data> to_remove;
typename Set1::iterator vit = tgt.begin();
typename Set1::iterator vend = tgt.end();
for(;vit!=vend;++vit) {
typename Set1::data itm=*vit;
if(!src.contains(itm)) {
to_remove.push_back(itm);
}
}
while(!to_remove.empty()) {
tgt.remove(to_remove.back());
to_remove.pop_back();
}
}
template<class Set>
void set_difference(Set & tgt, const Set & to_remove) {
typename Set::iterator vit = to_remove.begin();
typename Set::iterator vend = to_remove.end();
for(;vit!=vend;++vit) {
typename Set::data itm=*vit;
tgt.remove(itm);
}
}
template<class Set1, class Set2>
void set_union(Set1 & tgt, const Set2 & to_add) {
typename Set2::iterator vit = to_add.begin();
typename Set2::iterator vend = to_add.end();
for(;vit!=vend;++vit) {
typename Set1::data itm=*vit;
tgt.insert(itm);
}
}
void idx_set_union(idx_set & tgt, const idx_set & src);
template<class T>
void unite_disjoint_maps(T & tgt, const T & src) {
typename T::iterator it = src.begin();
typename T::iterator end = src.end();
for(; it!=end; ++it) {
SASSERT(!tgt.contains(it->m_key));
tgt.insert(it->m_key, it->m_value);
}
}
template<class T, class U>
void collect_map_range(T & acc, const U & map) {
typename U::iterator it = map.begin();
typename U::iterator end = map.end();
for(; it!=end; ++it) {
acc.push_back(it->m_value);
}
}
template<class T>
void print_container(const T & begin, const T & end, std::ostream & out) {
T it = begin;
out << "(";
bool first = true;
for(; it!=end; ++it) {
if(first) { first = false; } else { out << ","; }
out << (*it);
}
out << ")";
}
template<class T>
void print_container(const T & cont, std::ostream & out) {
print_container(cont.begin(), cont.end(), out);
}
template<class T, class M>
void print_container(const ref_vector<T,M> & cont, std::ostream & out) {
print_container(cont.c_ptr(), cont.c_ptr() + cont.size(), out);
}
template<class T>
void print_map(const T & cont, std::ostream & out) {
typename T::iterator it = cont.begin();
typename T::iterator end = cont.end();
out << "(";
bool first = true;
for(; it!=end; ++it) {
if(first) { first = false; } else { out << ","; }
out << it->m_key << "->" << it->m_value;
}
out << ")";
}
template<class It, class V>
unsigned find_index(const It & begin, const It & end, const V & val) {
unsigned idx = 0;
It it = begin;
for(; it!=end; it++, idx++) {
if(*it==val) {
return idx;
}
}
return UINT_MAX;
}
template<class T, class U>
bool containers_equal(const T & begin1, const T & end1, const U & begin2, const U & end2) {
T it1 = begin1;
U it2 = begin2;
for(; it1!=end1 && it2!=end2; ++it1, ++it2) {
if(*it1!=*it2) {
return false;
}
}
return it1==end1 && it2==end2;
}
template<class T, class U> template<class T, class U>
bool vectors_equal(const T & c1, const U & c2) { bool vectors_equal(const T & c1, const U & c2) {
@ -521,6 +399,8 @@ namespace datalog {
return true; return true;
} }
void idx_set_union(idx_set & tgt, const idx_set & src);
template<class T> template<class T>
struct default_obj_chash { struct default_obj_chash {
unsigned operator()(T const& cont, unsigned i) const { unsigned operator()(T const& cont, unsigned i) const {

View file

@ -1,48 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
proof_utils.h
Abstract:
Utilities for transforming proofs.
Author:
Nikolaj Bjorner (nbjorner) 2012-10-12.
Revision History:
--*/
#ifndef PROOF_UTILS_H_
#define PROOF_UTILS_H_
class proof_utils {
public:
/**
\brief reduce the set of hypotheses used in the proof.
*/
static void reduce_hypotheses(proof_ref& pr);
/**
\brief Check that a proof does not contain open hypotheses.
*/
static bool is_closed(ast_manager& m, proof* p);
/**
\brief Permute unit resolution rule with th-lemma
*/
static void permute_unit_resolution(proof_ref& pr);
/**
\brief Push instantiations created in hyper-resolutions up to leaves.
This produces a "ground" proof where leaves are annotated by instantiations.
*/
static void push_instantiations_up(proof_ref& pr);
};
#endif

View file

@ -62,8 +62,7 @@ namespace datalog {
rule_set::decl2rules m_body2rules; rule_set::decl2rules m_body2rules;
void init_bottom_up() { void init_bottom_up() {
for (rule_set::iterator it = m_rules.begin(); it != m_rules.end(); ++it) { for (rule* cur : m_rules) {
rule* cur = *it;
for (unsigned i = 0; i < cur->get_uninterpreted_tail_size(); ++i) { for (unsigned i = 0; i < cur->get_uninterpreted_tail_size(); ++i) {
func_decl *d = cur->get_decl(i); func_decl *d = cur->get_decl(i);
rule_set::decl2rules::obj_map_entry *e = m_body2rules.insert_if_not_there2(d, 0); rule_set::decl2rules::obj_map_entry *e = m_body2rules.insert_if_not_there2(d, 0);
@ -83,31 +82,25 @@ namespace datalog {
} }
void init_top_down() { void init_top_down() {
const func_decl_set& output_preds = m_rules.get_output_predicates(); for (func_decl* sym : m_rules.get_output_predicates()) {
for (func_decl_set::iterator I = output_preds.begin(),
E = output_preds.end(); I != E; ++I) {
func_decl* sym = *I;
TRACE("dl", tout << sym->get_name() << "\n";); TRACE("dl", tout << sym->get_name() << "\n";);
const rule_vector& output_rules = m_rules.get_predicate_rules(sym); const rule_vector& output_rules = m_rules.get_predicate_rules(sym);
for (unsigned i = 0; i < output_rules.size(); ++i) { for (rule* r : output_rules) {
m_facts.insert_if_not_there2(sym, Fact())->get_data().m_value.init_down(m_context, output_rules[i]); m_facts.insert_if_not_there2(sym, Fact())->get_data().m_value.init_down(m_context, r);
m_todo[m_todo_idx].insert(sym); m_todo[m_todo_idx].insert(sym);
} }
} }
} }
void step_bottom_up() { void step_bottom_up() {
for(todo_set::iterator I = m_todo[m_todo_idx].begin(), for (func_decl* f : m_todo[m_todo_idx]) {
E = m_todo[m_todo_idx].end(); I!=E; ++I) {
ptr_vector<rule> * rules; ptr_vector<rule> * rules;
if (!m_body2rules.find(*I, rules)) if (!m_body2rules.find(f, rules))
continue; continue;
for (rule* r : *rules) {
for (ptr_vector<rule>::iterator I2 = rules->begin(), func_decl* head_sym = r->get_head()->get_decl();
E2 = rules->end(); I2 != E2; ++I2) { fact_reader<Fact> tail_facts(m_facts, r);
func_decl* head_sym = (*I2)->get_head()->get_decl(); bool new_info = m_facts.insert_if_not_there2(head_sym, Fact())->get_data().m_value.propagate_up(m_context, r, tail_facts);
fact_reader<Fact> tail_facts(m_facts, *I2);
bool new_info = m_facts.insert_if_not_there2(head_sym, Fact())->get_data().m_value.propagate_up(m_context, *I2, tail_facts);
if (new_info) { if (new_info) {
m_todo[!m_todo_idx].insert(head_sym); m_todo[!m_todo_idx].insert(head_sym);
} }
@ -119,15 +112,11 @@ namespace datalog {
} }
void step_top_down() { void step_top_down() {
for(todo_set::iterator I = m_todo[m_todo_idx].begin(), for (func_decl* head_sym : m_todo[m_todo_idx]) {
E = m_todo[m_todo_idx].end(); I!=E; ++I) {
func_decl* head_sym = *I;
// We can't use a reference here because we are changing the map while using the reference // We can't use a reference here because we are changing the map while using the reference
const Fact head_fact = m_facts.get(head_sym, Fact::null_fact); const Fact head_fact = m_facts.get(head_sym, Fact::null_fact);
const rule_vector& deps = m_rules.get_predicate_rules(head_sym); const rule_vector& deps = m_rules.get_predicate_rules(head_sym);
const unsigned deps_size = deps.size(); for (rule* trg_rule : deps) {
for (unsigned i = 0; i < deps_size; ++i) {
rule *trg_rule = deps[i];
fact_writer<Fact> writer(m_facts, trg_rule, m_todo[!m_todo_idx]); fact_writer<Fact> writer(m_facts, trg_rule, m_todo[!m_todo_idx]);
// Generate new facts // Generate new facts
head_fact.propagate_down(m_context, trg_rule, writer); head_fact.propagate_down(m_context, trg_rule, writer);
@ -146,16 +135,13 @@ namespace datalog {
dataflow_engine(typename Fact::ctx_t& ctx, const rule_set& rules) : m_rules(rules), m_todo_idx(0), m_context(ctx) {} dataflow_engine(typename Fact::ctx_t& ctx, const rule_set& rules) : m_rules(rules), m_todo_idx(0), m_context(ctx) {}
~dataflow_engine() { ~dataflow_engine() {
for (rule_set::decl2rules::iterator it = m_body2rules.begin(); it != m_body2rules.end(); ++it) { for (auto & kv : m_body2rules)
dealloc(it->m_value); dealloc(kv.m_value);
}
} }
void dump(std::ostream& outp) { void dump(std::ostream& outp) {
obj_hashtable<func_decl> visited; obj_hashtable<func_decl> visited;
for (rule_set::iterator I = m_rules.begin(), for (rule const* r : m_rules) {
E = m_rules.end(); I != E; ++I) {
const rule* r = *I;
func_decl* head_decl = r->get_decl(); func_decl* head_decl = r->get_decl();
obj_hashtable<func_decl>::entry *dummy; obj_hashtable<func_decl>::entry *dummy;
if (visited.insert_if_not_there_core(head_decl, dummy)) { if (visited.insert_if_not_there_core(head_decl, dummy)) {
@ -194,30 +180,30 @@ namespace datalog {
iterator end() const { return m_facts.end(); } iterator end() const { return m_facts.end(); }
void join(const dataflow_engine<Fact>& oth) { void join(const dataflow_engine<Fact>& oth) {
for (typename fact_db::iterator I = oth.m_facts.begin(), for (auto const& kv : oth.m_facts) {
E = oth.m_facts.end(); I != E; ++I) {
typename fact_db::entry* entry; typename fact_db::entry* entry;
if (m_facts.insert_if_not_there_core(I->m_key, entry)) { if (m_facts.insert_if_not_there_core(kv.m_key, entry)) {
entry->get_data().m_value = I->m_value; entry->get_data().m_value = kv.m_value;
} else { }
entry->get_data().m_value.join(m_context, I->m_value); else {
entry->get_data().m_value.join(m_context, kv.m_value);
} }
} }
} }
void intersect(const dataflow_engine<Fact>& oth) { void intersect(const dataflow_engine<Fact>& oth) {
vector<func_decl*> to_delete; ptr_vector<func_decl> to_delete;
for (typename fact_db::iterator I = m_facts.begin(), for (auto const& kv : m_facts) {
E = m_facts.end(); I != E; ++I) {
if (typename fact_db::entry *entry = oth.m_facts.find_core(I->m_key)) { if (typename fact_db::entry *entry = oth.m_facts.find_core(kv.m_key)) {
I->m_value.intersect(m_context, entry->get_data().m_value); kv.m_value.intersect(m_context, entry->get_data().m_value);
} else { }
to_delete.push_back(I->m_key); else {
to_delete.push_back(kv.m_key);
} }
} }
for (unsigned i = 0; i < to_delete.size(); ++i) { for (func_decl* f : to_delete) {
m_facts.erase(to_delete[i]); m_facts.erase(f);
} }
} }
}; };

View file

@ -189,11 +189,12 @@ public:
m_bound = bound; m_bound = bound;
m_arg_idx++; m_arg_idx++;
} }
virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); } virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); m_t = nullptr; }
virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; } virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; }
virtual void finalize(cmd_context & ctx) { virtual void finalize(cmd_context & ctx) {
} }
virtual void execute(cmd_context & ctx) { virtual void execute(cmd_context & ctx) {
if (!m_t) throw cmd_exception("invalid rule, expected formula");
m_dl_ctx->add_rule(m_t, m_name, m_bound); m_dl_ctx->add_rule(m_t, m_name, m_bound);
} }
}; };

View file

@ -41,9 +41,8 @@ Notes:
#include "ast/ast_smt2_pp.h" #include "ast/ast_smt2_pp.h"
#include "qe/qe_lite.h" #include "qe/qe_lite.h"
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "ast/proof_checker/proof_checker.h" #include "ast/proofs/proof_checker.h"
#include "smt/smt_value_sort.h" #include "smt/smt_value_sort.h"
#include "muz/base/proof_utils.h"
#include "muz/base/dl_boogie_proof.h" #include "muz/base/dl_boogie_proof.h"
#include "ast/scoped_proof.h" #include "ast/scoped_proof.h"
#include "tactic/core/blast_term_ite_tactic.h" #include "tactic/core/blast_term_ite_tactic.h"
@ -1825,7 +1824,7 @@ namespace pdr {
m_core_generalizers.push_back(alloc(core_multi_generalizer, *this, 0)); m_core_generalizers.push_back(alloc(core_multi_generalizer, *this, 0));
} }
if (!classify.is_bool()) { if (!classify.is_bool()) {
m.toggle_proof_mode(PGM_FINE); m.toggle_proof_mode(PGM_ENABLED);
m_fparams.m_arith_bound_prop = BP_NONE; m_fparams.m_arith_bound_prop = BP_NONE;
m_fparams.m_arith_auto_config_simplex = true; m_fparams.m_arith_auto_config_simplex = true;
m_fparams.m_arith_propagate_eqs = false; m_fparams.m_arith_propagate_eqs = false;

View file

@ -31,7 +31,7 @@ Revision History:
#include "ast/rewriter/th_rewriter.h" #include "ast/rewriter/th_rewriter.h"
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "tactic/arith/arith_bounds_tactic.h" #include "tactic/arith/arith_bounds_tactic.h"
#include "muz/base/proof_utils.h" #include "ast/proofs/proof_utils.h"
#include "ast/reg_decl_plugins.h" #include "ast/reg_decl_plugins.h"
@ -372,7 +372,7 @@ namespace pdr {
farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr) farkas_learner::farkas_learner(smt_params& params, ast_manager& outer_mgr)
: m_proof_params(get_proof_params(params)), : m_proof_params(get_proof_params(params)),
m_pr(PGM_FINE), m_pr(PGM_ENABLED),
m_constr(0), m_constr(0),
m_combine_farkas_coefficients(true), m_combine_farkas_coefficients(true),
p2o(m_pr, outer_mgr), p2o(m_pr, outer_mgr),
@ -733,8 +733,8 @@ namespace pdr {
} }
else { else {
expr_set* hyps3 = alloc(expr_set); expr_set* hyps3 = alloc(expr_set);
datalog::set_union(*hyps3, *hyps); set_union(*hyps3, *hyps);
datalog::set_union(*hyps3, *hyps2); set_union(*hyps3, *hyps2);
hyps = hyps3; hyps = hyps3;
hyprefs.push_back(hyps); hyprefs.push_back(hyps);
} }
@ -795,7 +795,7 @@ namespace pdr {
case PR_LEMMA: { case PR_LEMMA: {
expr_set* hyps2 = alloc(expr_set); expr_set* hyps2 = alloc(expr_set);
hyprefs.push_back(hyps2); hyprefs.push_back(hyps2);
datalog::set_union(*hyps2, *hyps); set_union(*hyps2, *hyps);
hyps = hyps2; hyps = hyps2;
expr* fml = m.get_fact(p); expr* fml = m.get_fact(p);
hyps->remove(fml); hyps->remove(fml);

View file

@ -81,7 +81,7 @@ namespace pdr {
m_gen(n, core0, uses_level1); m_gen(n, core0, uses_level1);
new_cores.push_back(std::make_pair(core0, uses_level1)); new_cores.push_back(std::make_pair(core0, uses_level1));
obj_hashtable<expr> core_exprs, core1_exprs; obj_hashtable<expr> core_exprs, core1_exprs;
datalog::set_union(core_exprs, core0); set_union(core_exprs, core0);
for (unsigned i = 0; i < old_core.size(); ++i) { for (unsigned i = 0; i < old_core.size(); ++i) {
expr* lit = old_core[i].get(); expr* lit = old_core[i].get();
if (core_exprs.contains(lit)) { if (core_exprs.contains(lit)) {
@ -94,8 +94,8 @@ namespace pdr {
if (core1.size() < old_core.size()) { if (core1.size() < old_core.size()) {
new_cores.push_back(std::make_pair(core1, uses_level1)); new_cores.push_back(std::make_pair(core1, uses_level1));
core1_exprs.reset(); core1_exprs.reset();
datalog::set_union(core1_exprs, core1); set_union(core1_exprs, core1);
datalog::set_intersection(core_exprs, core1_exprs); set_intersection(core_exprs, core1_exprs);
} }
} }
} }

View file

@ -7,7 +7,6 @@ z3_add_component(spacer
spacer_farkas_learner.cpp spacer_farkas_learner.cpp
spacer_generalizers.cpp spacer_generalizers.cpp
spacer_manager.cpp spacer_manager.cpp
spacer_marshal.cpp
spacer_prop_solver.cpp spacer_prop_solver.cpp
spacer_smt_context_manager.cpp spacer_smt_context_manager.cpp
spacer_sym_mux.cpp spacer_sym_mux.cpp
@ -15,11 +14,9 @@ z3_add_component(spacer
spacer_itp_solver.cpp spacer_itp_solver.cpp
spacer_virtual_solver.cpp spacer_virtual_solver.cpp
spacer_legacy_mbp.cpp spacer_legacy_mbp.cpp
spacer_proof_utils.cpp
spacer_unsat_core_learner.cpp spacer_unsat_core_learner.cpp
spacer_unsat_core_plugin.cpp spacer_unsat_core_plugin.cpp
spacer_matrix.cpp spacer_matrix.cpp
spacer_min_cut.cpp
spacer_antiunify.cpp spacer_antiunify.cpp
spacer_mev_array.cpp spacer_mev_array.cpp
spacer_qe_project.cpp spacer_qe_project.cpp

View file

@ -40,7 +40,7 @@ Notes:
#include "ast/ast_smt2_pp.h" #include "ast/ast_smt2_pp.h"
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "ast/ast_util.h" #include "ast/ast_util.h"
#include "ast/proof_checker/proof_checker.h" #include "ast/proofs/proof_checker.h"
#include "smt/smt_value_sort.h" #include "smt/smt_value_sort.h"
#include "ast/scoped_proof.h" #include "ast/scoped_proof.h"
#include "muz/spacer/spacer_qe_project.h" #include "muz/spacer/spacer_qe_project.h"
@ -2139,7 +2139,7 @@ void context::reset_lemma_generalizers()
void context::init_lemma_generalizers(datalog::rule_set& rules) void context::init_lemma_generalizers(datalog::rule_set& rules)
{ {
reset_lemma_generalizers(); reset_lemma_generalizers();
m.toggle_proof_mode(PGM_FINE); m.toggle_proof_mode(PGM_ENABLED);
smt_params &fparams = m_pm.fparams (); smt_params &fparams = m_pm.fparams ();
if (!m_params.spacer_eq_prop ()) { if (!m_params.spacer_eq_prop ()) {
fparams.m_arith_bound_prop = BP_NONE; fparams.m_arith_bound_prop = BP_NONE;

View file

@ -31,7 +31,7 @@ Revision History:
#include "muz/spacer/spacer_farkas_learner.h" #include "muz/spacer/spacer_farkas_learner.h"
#include "ast/rewriter/th_rewriter.h" #include "ast/rewriter/th_rewriter.h"
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "muz/base/proof_utils.h" #include "ast/proofs/proof_utils.h"
#include "ast/reg_decl_plugins.h" #include "ast/reg_decl_plugins.h"
#include "smt/smt_farkas_util.h" #include "smt/smt_farkas_util.h"
@ -231,8 +231,8 @@ void farkas_learner::get_lemmas(proof* root, expr_set const& bs, expr_ref_vector
hyps = hyps2; hyps = hyps2;
} else { } else {
expr_set* hyps3 = alloc(expr_set); expr_set* hyps3 = alloc(expr_set);
datalog::set_union(*hyps3, *hyps); set_union(*hyps3, *hyps);
datalog::set_union(*hyps3, *hyps2); set_union(*hyps3, *hyps2);
hyps = hyps3; hyps = hyps3;
hyprefs.push_back(hyps); hyprefs.push_back(hyps);
} }
@ -291,7 +291,7 @@ void farkas_learner::get_lemmas(proof* root, expr_set const& bs, expr_ref_vector
case PR_LEMMA: { case PR_LEMMA: {
expr_set* hyps2 = alloc(expr_set); expr_set* hyps2 = alloc(expr_set);
hyprefs.push_back(hyps2); hyprefs.push_back(hyps2);
datalog::set_union(*hyps2, *hyps); set_union(*hyps2, *hyps);
hyps = hyps2; hyps = hyps2;
expr* fml = m.get_fact(p); expr* fml = m.get_fact(p);
hyps->remove(fml); hyps->remove(fml);

View file

@ -134,8 +134,8 @@ public:
{return m_solver.get_num_assumptions();} {return m_solver.get_num_assumptions();}
virtual expr * get_assumption(unsigned idx) const virtual expr * get_assumption(unsigned idx) const
{return m_solver.get_assumption(idx);} {return m_solver.get_assumption(idx);}
virtual std::ostream &display(std::ostream &out) const virtual std::ostream &display(std::ostream &out, unsigned n, expr* const* es) const
{m_solver.display(out); return out;} { return m_solver.display(out, n, es); }
/* check_sat_result interface */ /* check_sat_result interface */
@ -170,7 +170,7 @@ public:
public: public:
scoped_bg(itp_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {} scoped_bg(itp_solver &s) : m_s(s), m_bg_sz(m_s.get_num_bg()) {}
~scoped_bg() ~scoped_bg()
{if(m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }} {if (m_s.get_num_bg() > m_bg_sz) { m_s.pop_bg(m_s.get_num_bg() - m_bg_sz); }}
}; };
}; };
} }

View file

@ -23,9 +23,9 @@
#include "ast/ast_smt2_pp.h" #include "ast/ast_smt2_pp.h"
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "ast/ast_util.h" #include "ast/ast_util.h"
#include "ast/proof_checker/proof_checker.h" #include "ast/proofs/proof_checker.h"
#include "smt/smt_value_sort.h" #include "smt/smt_value_sort.h"
#include "muz/base/proof_utils.h" #include "ast/proofs/proof_utils.h"
#include "ast/scoped_proof.h" #include "ast/scoped_proof.h"
#include "muz/spacer/spacer_qe_project.h" #include "muz/spacer/spacer_qe_project.h"
#include "tactic/core/blast_term_ite_tactic.h" #include "tactic/core/blast_term_ite_tactic.h"

View file

@ -1,289 +0,0 @@
/*++
Copyright (c) 2017 Arie Gurfinkel
Module Name:
spacer_min_cut.cpp
Abstract:
min cut solver
Author:
Bernhard Gleiss
Revision History:
--*/
#include "muz/spacer/spacer_min_cut.h"
namespace spacer {
spacer_min_cut::spacer_min_cut()
{
m_n = 2;
// push back two empty vectors for source and sink
m_edges.push_back(vector<std::pair<unsigned, unsigned>>());
m_edges.push_back(vector<std::pair<unsigned, unsigned>>());
}
unsigned spacer_min_cut::new_node()
{
return m_n++;
}
void spacer_min_cut::add_edge(unsigned int i, unsigned int j, unsigned int capacity)
{
if (i >= m_edges.size())
{
m_edges.resize(i + 1);
}
m_edges[i].insert(std::make_pair(j, 1));
STRACE("spacer.mincut",
verbose_stream() << "adding edge (" << i << "," << j << ")\n";
);
}
void spacer_min_cut::compute_min_cut(vector<unsigned>& cut_nodes)
{
if (m_n == 2)
{
return;
}
m_d.resize(m_n);
m_pred.resize(m_n);
// compute initial distances and number of nodes
compute_initial_distances();
unsigned i = 0;
while (m_d[0] < m_n)
{
unsigned j = get_admissible_edge(i);
if (j < m_n)
{
// advance(i)
m_pred[j] = i;
i = j;
// if i is the sink, augment path
if (i == 1)
{
augment_path();
i = 0;
}
}
else
{
// retreat
compute_distance(i);
if (i != 0)
{
i = m_pred[i];
}
}
}
// split nodes into reachable and unreachable ones
vector<bool> reachable(m_n);
compute_reachable_nodes(reachable);
// find all edges between reachable and unreachable nodes and for each such edge, add corresponding lemma to unsat-core
compute_cut_and_add_lemmas(reachable, cut_nodes);
}
void spacer_min_cut::compute_initial_distances()
{
vector<unsigned> todo;
vector<bool> visited(m_n);
todo.push_back(0); // start at the source, since we do postorder traversel
while (!todo.empty())
{
unsigned current = todo.back();
// if we haven't already visited current
if (!visited[current]) {
bool existsUnvisitedParent = false;
// add unprocessed parents to stack for DFS. If there is at least one unprocessed parent, don't compute the result
// for current now, but wait until those unprocessed parents are processed.
for (unsigned i = 0, sz = m_edges[current].size(); i < sz; ++i)
{
unsigned parent = m_edges[current][i].first;
// if we haven't visited the current parent yet
if(!visited[parent])
{
// add it to the stack
todo.push_back(parent);
existsUnvisitedParent = true;
}
}
// if we already visited all parents, we can visit current too
if (!existsUnvisitedParent) {
visited[current] = true;
todo.pop_back();
compute_distance(current); // I.H. all parent distances are already computed
}
}
else {
todo.pop_back();
}
}
}
unsigned spacer_min_cut::get_admissible_edge(unsigned i)
{
for (const auto& pair : m_edges[i])
{
if (pair.second > 0 && m_d[i] == m_d[pair.first] + 1)
{
return pair.first;
}
}
return m_n; // no element found
}
void spacer_min_cut::augment_path()
{
// find bottleneck capacity
unsigned max = std::numeric_limits<unsigned int>::max();
unsigned k = 1;
while (k != 0)
{
unsigned l = m_pred[k];
for (const auto& pair : m_edges[l])
{
if (pair.first == k)
{
if (max > pair.second)
{
max = pair.second;
}
}
}
k = l;
}
k = 1;
while (k != 0)
{
unsigned l = m_pred[k];
// decrease capacity
for (auto& pair : m_edges[l])
{
if (pair.first == k)
{
pair.second -= max;
}
}
// increase reverse flow
bool already_exists = false;
for (auto& pair : m_edges[k])
{
if (pair.first == l)
{
already_exists = true;
pair.second += max;
}
}
if (!already_exists)
{
m_edges[k].insert(std::make_pair(l, max));
}
k = l;
}
}
void spacer_min_cut::compute_distance(unsigned i)
{
if (i == 1) // sink node
{
m_d[1] = 0;
}
else
{
unsigned min = std::numeric_limits<unsigned int>::max();
// find edge (i,j) with positive residual capacity and smallest distance
for (const auto& pair : m_edges[i])
{
if (pair.second > 0)
{
unsigned tmp = m_d[pair.first] + 1;
if (tmp < min)
{
min = tmp;
}
}
}
m_d[i] = min;
}
}
void spacer_min_cut::compute_reachable_nodes(vector<bool>& reachable)
{
vector<unsigned> todo;
todo.push_back(0);
while (!todo.empty())
{
unsigned current = todo.back();
todo.pop_back();
if (!reachable[current])
{
reachable[current] = true;
for (const auto& pair : m_edges[current])
{
if (pair.second > 0)
{
todo.push_back(pair.first);
}
}
}
}
}
void spacer_min_cut::compute_cut_and_add_lemmas(vector<bool>& reachable, vector<unsigned>& cut_nodes)
{
vector<unsigned> todo;
vector<bool> visited(m_n);
todo.push_back(0);
while (!todo.empty())
{
unsigned current = todo.back();
todo.pop_back();
if (!visited[current])
{
visited[current] = true;
for (const auto& pair : m_edges[current])
{
unsigned successor = pair.first;
if (reachable[successor])
{
todo.push_back(successor);
}
else
{
cut_nodes.push_back(successor);
}
}
}
}
}
}

View file

@ -1,53 +0,0 @@
/*++
Copyright (c) 2017 Arie Gurfinkel
Module Name:
spacer_min_cut.h
Abstract:
min cut solver
Author:
Bernhard Gleiss
Revision History:
--*/
#ifndef _SPACER_MIN_CUT_H_
#define _SPACER_MIN_CUT_H_
#include "ast/ast.h"
#include "util/vector.h"
namespace spacer {
class spacer_min_cut {
public:
spacer_min_cut();
unsigned new_node();
void add_edge(unsigned i, unsigned j, unsigned capacity);
void compute_min_cut(vector<unsigned>& cut_nodes);
private:
unsigned m_n; // number of vertices in the graph
vector<vector<std::pair<unsigned, unsigned> > > m_edges; // map from node to all outgoing edges together with their weights (also contains "reverse edges")
vector<unsigned> m_d; // approximation of distance from node to sink in residual graph
vector<unsigned> m_pred; // predecessor-information for reconstruction of augmenting path
vector<expr*> m_node_to_formula; // maps each node to the corresponding formula in the original proof
void compute_initial_distances();
unsigned get_admissible_edge(unsigned i);
void augment_path();
void compute_distance(unsigned i);
void compute_reachable_nodes(vector<bool>& reachable);
void compute_cut_and_add_lemmas(vector<bool>& reachable, vector<unsigned>& cut_nodes);
};
}
#endif

View file

@ -1,332 +0,0 @@
/*++
Copyright (c) 2017 Arie Gurfinkel
Module Name:
spacer_proof_utils.cpp
Abstract:
Utilities to traverse and manipulate proofs
Author:
Bernhard Gleiss
Arie Gurfinkel
Revision History:
--*/
#include "muz/spacer/spacer_proof_utils.h"
#include "ast/ast_util.h"
#include "ast/ast_pp.h"
#include "ast/proof_checker/proof_checker.h"
namespace spacer {
ProofIteratorPostOrder::ProofIteratorPostOrder(proof* root, ast_manager& manager) : m(manager)
{m_todo.push_back(root);}
bool ProofIteratorPostOrder::hasNext()
{return !m_todo.empty();}
/*
* iterative post-order depth-first search (DFS) through the proof DAG
*/
proof* ProofIteratorPostOrder::next()
{
while (!m_todo.empty()) {
proof* currentNode = m_todo.back();
// if we haven't already visited the current unit
if (!m_visited.is_marked(currentNode)) {
bool existsUnvisitedParent = false;
// add unprocessed premises to stack for DFS. If there is at least one unprocessed premise, don't compute the result
// for currentProof now, but wait until those unprocessed premises are processed.
for (unsigned i = 0; i < m.get_num_parents(currentNode); ++i) {
SASSERT(m.is_proof(currentNode->get_arg(i)));
proof* premise = to_app(currentNode->get_arg(i));
// if we haven't visited the current premise yet
if (!m_visited.is_marked(premise)) {
// add it to the stack
m_todo.push_back(premise);
existsUnvisitedParent = true;
}
}
// if we already visited all parent-inferences, we can visit the inference too
if (!existsUnvisitedParent) {
m_visited.mark(currentNode, true);
m_todo.pop_back();
return currentNode;
}
} else {
m_todo.pop_back();
}
}
// we have already iterated through all inferences
return NULL;
}
class reduce_hypotheses {
ast_manager &m;
// tracking all created expressions
expr_ref_vector m_pinned;
// cache for the transformation
obj_map<proof, proof*> m_cache;
// map from unit literals to their hypotheses-free derivations
obj_map<expr, proof*> m_units;
// -- all hypotheses in the the proof
obj_hashtable<expr> m_hyps;
// marks hypothetical proofs
ast_mark m_hypmark;
// stack
ptr_vector<proof> m_todo;
void reset()
{
m_cache.reset();
m_units.reset();
m_hyps.reset();
m_hypmark.reset();
m_pinned.reset();
}
bool compute_mark1(proof *pr)
{
bool hyp_mark = false;
// lemmas clear all hypotheses
if (!m.is_lemma(pr)) {
for (unsigned i = 0, sz = m.get_num_parents(pr); i < sz; ++i) {
if (m_hypmark.is_marked(m.get_parent(pr, i))) {
hyp_mark = true;
break;
}
}
}
m_hypmark.mark(pr, hyp_mark);
return hyp_mark;
}
void compute_marks(proof* pr)
{
proof *p;
ProofIteratorPostOrder pit(pr, m);
while (pit.hasNext()) {
p = pit.next();
if (m.is_hypothesis(p)) {
m_hypmark.mark(p, true);
m_hyps.insert(m.get_fact(p));
} else {
bool hyp_mark = compute_mark1(p);
// collect units that are hyp-free and are used as hypotheses somewhere
if (!hyp_mark && m.has_fact(p) && m_hyps.contains(m.get_fact(p)))
{ m_units.insert(m.get_fact(p), p); }
}
}
}
void find_units(proof *pr)
{
// optional. not implemented yet.
}
void reduce(proof* pf, proof_ref &out)
{
proof *res = NULL;
m_todo.reset();
m_todo.push_back(pf);
ptr_buffer<proof> args;
bool dirty = false;
while (!m_todo.empty()) {
proof *p, *tmp, *pp;
unsigned todo_sz;
p = m_todo.back();
if (m_cache.find(p, tmp)) {
res = tmp;
m_todo.pop_back();
continue;
}
dirty = false;
args.reset();
todo_sz = m_todo.size();
for (unsigned i = 0, sz = m.get_num_parents(p); i < sz; ++i) {
pp = m.get_parent(p, i);
if (m_cache.find(pp, tmp)) {
args.push_back(tmp);
dirty = dirty || pp != tmp;
} else {
m_todo.push_back(pp);
}
}
if (todo_sz < m_todo.size()) { continue; }
else { m_todo.pop_back(); }
if (m.is_hypothesis(p)) {
// hyp: replace by a corresponding unit
if (m_units.find(m.get_fact(p), tmp)) {
res = tmp;
} else { res = p; }
}
else if (!dirty) { res = p; }
else if (m.is_lemma(p)) {
//lemma: reduce the premise; remove reduced consequences from conclusion
SASSERT(args.size() == 1);
res = mk_lemma_core(args.get(0), m.get_fact(p));
compute_mark1(res);
} else if (m.is_unit_resolution(p)) {
// unit: reduce untis; reduce the first premise; rebuild unit resolution
res = mk_unit_resolution_core(args.size(), args.c_ptr());
compute_mark1(res);
} else {
// other: reduce all premises; reapply
if (m.has_fact(p)) { args.push_back(to_app(m.get_fact(p))); }
SASSERT(p->get_decl()->get_arity() == args.size());
res = m.mk_app(p->get_decl(), args.size(), (expr * const*)args.c_ptr());
m_pinned.push_back(res);
compute_mark1(res);
}
SASSERT(res);
m_cache.insert(p, res);
if (m.has_fact(res) && m.is_false(m.get_fact(res))) { break; }
}
out = res;
}
// returns true if (hypothesis (not a)) would be reduced
bool is_reduced(expr *a)
{
expr_ref e(m);
if (m.is_not(a)) { e = to_app(a)->get_arg(0); }
else { e = m.mk_not(a); }
return m_units.contains(e);
}
proof *mk_lemma_core(proof *pf, expr *fact)
{
ptr_buffer<expr> args;
expr_ref lemma(m);
if (m.is_or(fact)) {
for (unsigned i = 0, sz = to_app(fact)->get_num_args(); i < sz; ++i) {
expr *a = to_app(fact)->get_arg(i);
if (!is_reduced(a))
{ args.push_back(a); }
}
} else if (!is_reduced(fact))
{ args.push_back(fact); }
if (args.size() == 0) { return pf; }
else if (args.size() == 1) {
lemma = args.get(0);
} else {
lemma = m.mk_or(args.size(), args.c_ptr());
}
proof* res = m.mk_lemma(pf, lemma);
m_pinned.push_back(res);
if (m_hyps.contains(lemma))
{ m_units.insert(lemma, res); }
return res;
}
proof *mk_unit_resolution_core(unsigned num_args, proof* const *args)
{
ptr_buffer<proof> pf_args;
pf_args.push_back(args [0]);
app *cls_fact = to_app(m.get_fact(args[0]));
ptr_buffer<expr> cls;
if (m.is_or(cls_fact)) {
for (unsigned i = 0, sz = cls_fact->get_num_args(); i < sz; ++i)
{ cls.push_back(cls_fact->get_arg(i)); }
} else { cls.push_back(cls_fact); }
// construct new resovent
ptr_buffer<expr> new_fact_cls;
bool found;
// XXX quadratic
for (unsigned i = 0, sz = cls.size(); i < sz; ++i) {
found = false;
for (unsigned j = 1; j < num_args; ++j) {
if (m.is_complement(cls.get(i), m.get_fact(args [j]))) {
found = true;
pf_args.push_back(args [j]);
break;
}
}
if (!found) {
new_fact_cls.push_back(cls.get(i));
}
}
SASSERT(new_fact_cls.size() + pf_args.size() - 1 == cls.size());
expr_ref new_fact(m);
new_fact = mk_or(m, new_fact_cls.size(), new_fact_cls.c_ptr());
// create new proof step
proof *res = m.mk_unit_resolution(pf_args.size(), pf_args.c_ptr(), new_fact);
m_pinned.push_back(res);
return res;
}
// reduce all units, if any unit reduces to false return true and put its proof into out
bool reduce_units(proof_ref &out)
{
proof_ref res(m);
for (auto entry : m_units) {
reduce(entry.get_value(), res);
if (m.is_false(m.get_fact(res))) {
out = res;
return true;
}
res.reset();
}
return false;
}
public:
reduce_hypotheses(ast_manager &m) : m(m), m_pinned(m) {}
void operator()(proof_ref &pr)
{
compute_marks(pr);
if (!reduce_units(pr)) {
reduce(pr.get(), pr);
}
reset();
}
};
void reduce_hypotheses(proof_ref &pr)
{
ast_manager &m = pr.get_manager();
class reduce_hypotheses hypred(m);
hypred(pr);
DEBUG_CODE(proof_checker pc(m);
expr_ref_vector side(m);
SASSERT(pc.check(pr, side));
);
}
}

View file

@ -1,43 +0,0 @@
/*++
Copyright (c) 2017 Arie Gurfinkel
Module Name:
spacer_proof_utils.cpp
Abstract:
Utilities to traverse and manipulate proofs
Author:
Bernhard Gleiss
Arie Gurfinkel
Revision History:
--*/
#ifndef _SPACER_PROOF_UTILS_H_
#define _SPACER_PROOF_UTILS_H_
#include "ast/ast.h"
namespace spacer {
/*
* iterator, which traverses the proof in depth-first post-order.
*/
class ProofIteratorPostOrder {
public:
ProofIteratorPostOrder(proof* refutation, ast_manager& manager);
bool hasNext();
proof* next();
private:
ptr_vector<proof> m_todo;
ast_mark m_visited; // the proof nodes we have already visited
ast_manager& m;
};
void reduce_hypotheses(proof_ref &pr);
}
#endif

View file

@ -41,7 +41,7 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e
// transform proof in order to get a proof which is better suited for unsat-core-extraction // transform proof in order to get a proof which is better suited for unsat-core-extraction
proof_ref pr(root, m); proof_ref pr(root, m);
spacer::reduce_hypotheses(pr); reduce_hypotheses(pr);
STRACE("spacer.unsat_core_learner", STRACE("spacer.unsat_core_learner",
verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n"; verbose_stream() << "Reduced proof:\n" << mk_ismt2_pp(pr, m) << "\n";
); );
@ -50,7 +50,7 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e
collect_symbols_b(asserted_b); collect_symbols_b(asserted_b);
// traverse proof // traverse proof
ProofIteratorPostOrder it(root, m); proof_post_order it(root, m);
while (it.hasNext()) while (it.hasNext())
{ {
proof* currentNode = it.next(); proof* currentNode = it.next();
@ -138,7 +138,7 @@ void unsat_core_learner::compute_unsat_core(proof *root, expr_set& asserted_b, e
std::unordered_map<unsigned, unsigned> id_to_small_id; std::unordered_map<unsigned, unsigned> id_to_small_id;
unsigned counter = 0; unsigned counter = 0;
ProofIteratorPostOrder it2(root, m); proof_post_order it2(root, m);
while (it2.hasNext()) while (it2.hasNext())
{ {
proof* currentNode = it2.next(); proof* currentNode = it2.next();

View file

@ -20,7 +20,7 @@ Revision History:
#include "ast/ast.h" #include "ast/ast.h"
#include "muz/spacer/spacer_util.h" #include "muz/spacer/spacer_util.h"
#include "muz/spacer/spacer_proof_utils.h" #include "ast/proofs/proof_utils.h"
namespace spacer { namespace spacer {

View file

@ -20,13 +20,13 @@ Revision History:
#include "ast/rewriter/bool_rewriter.h" #include "ast/rewriter/bool_rewriter.h"
#include "ast/arith_decl_plugin.h" #include "ast/arith_decl_plugin.h"
#include "ast/proofs/proof_utils.h"
#include "solver/solver.h" #include "solver/solver.h"
#include "smt/smt_farkas_util.h" #include "smt/smt_farkas_util.h"
#include "smt/smt_solver.h" #include "smt/smt_solver.h"
#include "muz/spacer/spacer_proof_utils.h"
#include "muz/spacer/spacer_matrix.h" #include "muz/spacer/spacer_matrix.h"
#include "muz/spacer/spacer_unsat_core_plugin.h" #include "muz/spacer/spacer_unsat_core_plugin.h"
#include "muz/spacer/spacer_unsat_core_learner.h" #include "muz/spacer/spacer_unsat_core_learner.h"
@ -735,7 +735,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
m_node_to_formula[node_other] = m.get_fact(i); m_node_to_formula[node_other] = m.get_fact(i);
m_node_to_formula[node_i] = m.get_fact(i); m_node_to_formula[node_i] = m.get_fact(i);
m_min_cut.add_edge(node_other, node_i, 1); m_min_cut.add_edge(node_other, node_i);
} }
} }
@ -765,12 +765,12 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
m_node_to_formula[node_j] = m.get_fact(j); m_node_to_formula[node_j] = m.get_fact(j);
m_node_to_formula[node_other] = m.get_fact(j); m_node_to_formula[node_other] = m.get_fact(j);
m_min_cut.add_edge(node_j, node_other, 1); m_min_cut.add_edge(node_j, node_other);
} }
} }
// finally connect nodes // finally connect nodes
m_min_cut.add_edge(node_i, node_j, 1); m_min_cut.add_edge(node_i, node_j);
} }
/* /*
@ -779,7 +779,7 @@ void unsat_core_plugin_farkas_lemma::compute_linear_combination(const vector<rat
*/ */
void unsat_core_plugin_min_cut::finalize() void unsat_core_plugin_min_cut::finalize()
{ {
vector<unsigned int> cut_nodes; unsigned_vector cut_nodes;
m_min_cut.compute_min_cut(cut_nodes); m_min_cut.compute_min_cut(cut_nodes);
for (unsigned cut_node : cut_nodes) for (unsigned cut_node : cut_nodes)

View file

@ -19,7 +19,7 @@ Revision History:
#define _SPACER_UNSAT_CORE_PLUGIN_H_ #define _SPACER_UNSAT_CORE_PLUGIN_H_
#include "ast/ast.h" #include "ast/ast.h"
#include "muz/spacer/spacer_min_cut.h" #include "util/min_cut.h"
namespace spacer { namespace spacer {
@ -109,7 +109,7 @@ private:
vector<expr*> m_node_to_formula; // maps each node to the corresponding formula in the original proof vector<expr*> m_node_to_formula; // maps each node to the corresponding formula in the original proof
spacer_min_cut m_min_cut; min_cut m_min_cut;
}; };
} }
#endif #endif

View file

@ -72,73 +72,67 @@ namespace spacer {
// //
model_evaluator_util::model_evaluator_util(ast_manager& m) : model_evaluator_util::model_evaluator_util(ast_manager& m) :
m(m), m_mev(NULL) m(m), m_mev(nullptr) {
{ reset (NULL); } reset (nullptr);
}
model_evaluator_util::~model_evaluator_util() {reset (NULL);} model_evaluator_util::~model_evaluator_util() {reset (NULL);}
void model_evaluator_util::reset(model* model) void model_evaluator_util::reset(model* model) {
{
if (m_mev) { if (m_mev) {
dealloc(m_mev); dealloc(m_mev);
m_mev = NULL; m_mev = NULL;
} }
m_model = model; m_model = model;
if (!m_model) { return; } if (!m_model) { return; }
m_mev = alloc(model_evaluator, *m_model); m_mev = alloc(model_evaluator, *m_model);
} }
bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) bool model_evaluator_util::eval(expr *e, expr_ref &result, bool model_completion) {
{
m_mev->set_model_completion (model_completion); m_mev->set_model_completion (model_completion);
try { try {
m_mev->operator() (e, result); m_mev->operator() (e, result);
return true; return true;
} catch (model_evaluator_exception &ex) { }
catch (model_evaluator_exception &ex) {
(void)ex; (void)ex;
TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";); TRACE("spacer_model_evaluator", tout << ex.msg () << "\n";);
return false; return false;
} }
} }
bool model_evaluator_util::eval(const expr_ref_vector &v, bool model_evaluator_util::eval(const expr_ref_vector &v,
expr_ref& res, bool model_completion) expr_ref& res, bool model_completion) {
{
expr_ref e(m); expr_ref e(m);
e = mk_and (v); e = mk_and (v);
return eval(e, res, model_completion); return eval(e, res, model_completion);
} }
bool model_evaluator_util::is_true(const expr_ref_vector &v) bool model_evaluator_util::is_true(const expr_ref_vector &v) {
{
expr_ref res(m); expr_ref res(m);
return eval (v, res, false) && m.is_true (res); return eval (v, res, false) && m.is_true (res);
} }
bool model_evaluator_util::is_false(expr *x) bool model_evaluator_util::is_false(expr *x) {
{
expr_ref res(m); expr_ref res(m);
return eval(x, res, false) && m.is_false (res); return eval(x, res, false) && m.is_false (res);
} }
bool model_evaluator_util::is_true(expr *x)
{ bool model_evaluator_util::is_true(expr *x) {
expr_ref res(m); expr_ref res(m);
return eval(x, res, false) && m.is_true (res); return eval(x, res, false) && m.is_true (res);
} }
void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml) {
void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml)
{
ast_manager& m = fml.get_manager(); ast_manager& m = fml.get_manager();
expr_ref_vector conjs(m); expr_ref_vector conjs(m);
flatten_and(fml, conjs); flatten_and(fml, conjs);
obj_map<expr, unsigned> diseqs; obj_map<expr, unsigned> diseqs;
expr* n, *lhs, *rhs; expr* n, *lhs, *rhs;
for (unsigned i = 0; i < conjs.size(); ++i) { for (unsigned i = 0; i < conjs.size(); ++i) {
if (m.is_not(conjs[i].get(), n) && if (m.is_not(conjs[i].get(), n) && m.is_eq(n, lhs, rhs)) {
m.is_eq(n, lhs, rhs)) {
if (!m.is_value(rhs)) { if (!m.is_value(rhs)) {
std::swap(lhs, rhs); std::swap(lhs, rhs);
} }
@ -155,14 +149,12 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml)
expr_ref val(m), tmp(m); expr_ref val(m), tmp(m);
proof_ref pr(m); proof_ref pr(m);
pr = m.mk_asserted(m.mk_true()); pr = m.mk_asserted(m.mk_true());
obj_map<expr, unsigned>::iterator it = diseqs.begin(); for (auto const& kv : diseqs) {
obj_map<expr, unsigned>::iterator end = diseqs.end(); if (kv.m_value >= threshold) {
for (; it != end; ++it) { model.eval(kv.m_key, val);
if (it->m_value >= threshold) { sub.insert(kv.m_key, val, pr);
model.eval(it->m_key, val); conjs.push_back(m.mk_eq(kv.m_key, val));
sub.insert(it->m_key, val, pr); num_deleted += kv.m_value;
conjs.push_back(m.mk_eq(it->m_key, val));
num_deleted += it->m_value;
} }
} }
if (orig_size < conjs.size()) { if (orig_size < conjs.size()) {
@ -178,14 +170,17 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml)
SASSERT(orig_size <= 1 + conjs.size()); SASSERT(orig_size <= 1 + conjs.size());
if (i + 1 == orig_size) { if (i + 1 == orig_size) {
// no-op. // no-op.
} else if (orig_size <= conjs.size()) { }
else if (orig_size <= conjs.size()) {
// no-op // no-op
} else { }
else {
SASSERT(orig_size == 1 + conjs.size()); SASSERT(orig_size == 1 + conjs.size());
--orig_size; --orig_size;
--i; --i;
} }
} else { }
else {
conjs[i] = tmp; conjs[i] = tmp;
} }
} }
@ -202,9 +197,8 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml)
ast_manager& m; ast_manager& m;
public: public:
ite_hoister(ast_manager& m): m(m) {} ite_hoister(ast_manager& m): m(m) {}
br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) br_status mk_app_core(func_decl* f, unsigned num_args, expr* const* args, expr_ref& result) {
{
if (m.is_ite(f)) { if (m.is_ite(f)) {
return BR_FAILED; return BR_FAILED;
} }
@ -233,13 +227,12 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml)
struct ite_hoister_cfg: public default_rewriter_cfg { struct ite_hoister_cfg: public default_rewriter_cfg {
ite_hoister m_r; ite_hoister m_r;
bool rewrite_patterns() const { return false; } bool rewrite_patterns() const { return false; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
{
return m_r.mk_app_core(f, num, args, result); return m_r.mk_app_core(f, num, args, result);
} }
ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {} ite_hoister_cfg(ast_manager & m, params_ref const & p):m_r(m) {}
}; };
class ite_hoister_star : public rewriter_tpl<ite_hoister_cfg> { class ite_hoister_star : public rewriter_tpl<ite_hoister_cfg> {
ite_hoister_cfg m_cfg; ite_hoister_cfg m_cfg;
public: public:
@ -247,9 +240,8 @@ void reduce_disequalities(model& model, unsigned threshold, expr_ref& fml)
rewriter_tpl<ite_hoister_cfg>(m, false, m_cfg), rewriter_tpl<ite_hoister_cfg>(m, false, m_cfg),
m_cfg(m, p) {} m_cfg(m, p) {}
}; };
void hoist_non_bool_if(expr_ref& fml) void hoist_non_bool_if(expr_ref& fml) {
{
ast_manager& m = fml.get_manager(); ast_manager& m = fml.get_manager();
scoped_no_proof _sp(m); scoped_no_proof _sp(m);
params_ref p; params_ref p;
@ -266,8 +258,7 @@ void hoist_non_bool_if(expr_ref& fml)
bool m_is_dl; bool m_is_dl;
bool m_test_for_utvpi; bool m_test_for_utvpi;
bool is_numeric(expr* e) const bool is_numeric(expr* e) const {
{
if (a.is_numeral(e)) { if (a.is_numeral(e)) {
return true; return true;
} }
@ -278,13 +269,11 @@ void hoist_non_bool_if(expr_ref& fml)
return false; return false;
} }
bool is_arith_expr(expr *e) const bool is_arith_expr(expr *e) const {
{
return is_app(e) && a.get_family_id() == to_app(e)->get_family_id(); return is_app(e) && a.get_family_id() == to_app(e)->get_family_id();
} }
bool is_offset(expr* e) const bool is_offset(expr* e) const {
{
if (a.is_numeral(e)) { if (a.is_numeral(e)) {
return true; return true;
} }
@ -315,47 +304,44 @@ void hoist_non_bool_if(expr_ref& fml)
return !is_arith_expr(e); return !is_arith_expr(e);
} }
bool is_minus_one(expr const * e) const bool is_minus_one(expr const * e) const {
{ rational r;
rational r; return a.is_numeral(e, r) && r.is_minus_one();
return a.is_numeral(e, r) && r.is_minus_one();
} }
bool test_ineq(expr* e) const bool test_ineq(expr* e) const {
{
SASSERT(a.is_le(e) || a.is_ge(e) || m.is_eq(e)); SASSERT(a.is_le(e) || a.is_ge(e) || m.is_eq(e));
SASSERT(to_app(e)->get_num_args() == 2); SASSERT(to_app(e)->get_num_args() == 2);
expr * lhs = to_app(e)->get_arg(0); expr * lhs = to_app(e)->get_arg(0);
expr * rhs = to_app(e)->get_arg(1); expr * rhs = to_app(e)->get_arg(1);
if (is_offset(lhs) && is_offset(rhs)) if (is_offset(lhs) && is_offset(rhs))
{ return true; } { return true; }
if (!is_numeric(rhs)) if (!is_numeric(rhs))
{ std::swap(lhs, rhs); } { std::swap(lhs, rhs); }
if (!is_numeric(rhs)) if (!is_numeric(rhs))
{ return false; } { return false; }
// lhs can be 'x' or '(+ x (* -1 y))' // lhs can be 'x' or '(+ x (* -1 y))'
if (is_offset(lhs)) if (is_offset(lhs))
{ return true; } { return true; }
expr* arg1, *arg2; expr* arg1, *arg2;
if (!a.is_add(lhs, arg1, arg2)) if (!a.is_add(lhs, arg1, arg2))
{ return false; } { return false; }
// x // x
if (m_test_for_utvpi) { if (m_test_for_utvpi) {
return is_offset(arg1) && is_offset(arg2); return is_offset(arg1) && is_offset(arg2);
} }
if (is_arith_expr(arg1)) if (is_arith_expr(arg1))
{ std::swap(arg1, arg2); } { std::swap(arg1, arg2); }
if (is_arith_expr(arg1)) if (is_arith_expr(arg1))
{ return false; } { return false; }
// arg2: (* -1 y) // arg2: (* -1 y)
expr* m1, *m2; expr* m1, *m2;
if (!a.is_mul(arg2, m1, m2)) if (!a.is_mul(arg2, m1, m2))
{ return false; } { return false; }
return is_minus_one(m1) && is_offset(m2); return is_minus_one(m1) && is_offset(m2);
} }
bool test_eq(expr* e) const bool test_eq(expr* e) const {
{
expr* lhs, *rhs; expr* lhs, *rhs;
VERIFY(m.is_eq(e, lhs, rhs)); VERIFY(m.is_eq(e, lhs, rhs));
if (!a.is_int_real(lhs)) { if (!a.is_int_real(lhs)) {
@ -370,9 +356,8 @@ void hoist_non_bool_if(expr_ref& fml)
!a.is_mul(lhs) && !a.is_mul(lhs) &&
!a.is_mul(rhs); !a.is_mul(rhs);
} }
bool test_term(expr* e) const bool test_term(expr* e) const {
{
if (m.is_bool(e)) { if (m.is_bool(e)) {
return true; return true;
} }
@ -490,7 +475,7 @@ bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls)
* eliminate simple equalities using qe_lite * eliminate simple equalities using qe_lite
* then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays * then, MBP for Booleans (substitute), reals (based on LW), ints (based on Cooper), and arrays
*/ */
void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml, void qe_project (ast_manager& m, app_ref_vector& vars, expr_ref& fml,
const model_ref& M, bool reduce_all_selects, bool use_native_mbp, const model_ref& M, bool reduce_all_selects, bool use_native_mbp,
bool dont_sub) bool dont_sub)
{ {

View file

@ -74,15 +74,6 @@ inline std::ostream& operator<<(std::ostream& out, pp_level const& p)
} }
struct scoped_watch {
stopwatch &m_sw;
scoped_watch (stopwatch &sw, bool reset=false): m_sw(sw)
{
if(reset) { m_sw.reset(); }
m_sw.start ();
}
~scoped_watch () {m_sw.stop ();}
};
typedef ptr_vector<app> app_vector; typedef ptr_vector<app> app_vector;

View file

@ -23,7 +23,8 @@ Notes:
#include "muz/spacer/spacer_util.h" #include "muz/spacer/spacer_util.h"
#include "ast/rewriter/bool_rewriter.h" #include "ast/rewriter/bool_rewriter.h"
#include "ast/proof_checker/proof_checker.h" #include "ast/proofs/proof_checker.h"
#include "ast/proofs/proof_utils.h"
#include "ast/scoped_proof.h" #include "ast/scoped_proof.h"
@ -64,172 +65,11 @@ virtual_solver::~virtual_solver()
} }
namespace { namespace {
static bool matches_fact(expr_ref_vector &args, expr* &match)
{
ast_manager &m = args.get_manager();
expr *fact = args.back();
for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i) {
expr *arg = args.get(i);
if (m.is_proof(arg) &&
m.has_fact(to_app(arg)) &&
m.get_fact(to_app(arg)) == fact) {
match = arg;
return true;
}
}
return false;
}
class elim_aux_assertions { // TBD: move to ast/proofs/elim_aux_assertions
app_ref m_aux;
public:
elim_aux_assertions(app_ref aux) : m_aux(aux) {}
void mk_or_core(expr_ref_vector &args, expr_ref &res)
{
ast_manager &m = args.get_manager();
unsigned j = 0;
for (unsigned i = 0, sz = args.size(); i < sz; ++i) {
if (m.is_false(args.get(i))) { continue; }
if (i != j) { args [j] = args.get(i); }
++j;
}
SASSERT(j >= 1);
res = j > 1 ? m.mk_or(j, args.c_ptr()) : args.get(0);
}
void mk_app(func_decl *decl, expr_ref_vector &args, expr_ref &res)
{
ast_manager &m = args.get_manager();
bool_rewriter brwr(m);
if (m.is_or(decl))
{ mk_or_core(args, res); }
else if (m.is_iff(decl) && args.size() == 2)
// avoiding simplifying equalities. In particular,
// we don't want (= (not a) (not b)) to be reduced to (= a b)
{ res = m.mk_iff(args.get(0), args.get(1)); }
else
{ brwr.mk_app(decl, args.size(), args.c_ptr(), res); }
}
void operator()(ast_manager &m, proof *pr, proof_ref &res)
{
DEBUG_CODE(proof_checker pc(m);
expr_ref_vector side(m);
SASSERT(pc.check(pr, side));
);
obj_map<app, app*> cache;
bool_rewriter brwr(m);
// for reference counting of new proofs
app_ref_vector pinned(m);
ptr_vector<app> todo;
todo.push_back(pr);
expr_ref not_aux(m);
not_aux = m.mk_not(m_aux);
expr_ref_vector args(m);
while (!todo.empty()) {
app *p, *r;
expr *a;
p = todo.back();
if (cache.find(pr, r)) {
todo.pop_back();
continue;
}
SASSERT(!todo.empty() || pr == p);
bool dirty = false;
unsigned todo_sz = todo.size();
args.reset();
for (unsigned i = 0, sz = p->get_num_args(); i < sz; ++i) {
expr* arg = p->get_arg(i);
if (arg == m_aux.get()) {
dirty = true;
args.push_back(m.mk_true());
} else if (arg == not_aux.get()) {
dirty = true;
args.push_back(m.mk_false());
}
// skip (asserted m_aux)
else if (m.is_asserted(arg, a) && a == m_aux.get()) {
dirty = true;
}
// skip (hypothesis m_aux)
else if (m.is_hypothesis(arg, a) && a == m_aux.get()) {
dirty = true;
} else if (is_app(arg) && cache.find(to_app(arg), r)) {
dirty |= (arg != r);
args.push_back(r);
} else if (is_app(arg))
{ todo.push_back(to_app(arg)); }
else
// -- not an app
{ args.push_back(arg); }
}
if (todo_sz < todo.size()) {
// -- process parents
args.reset();
continue;
}
// ready to re-create
app_ref newp(m);
if (!dirty) { newp = p; }
else if (m.is_unit_resolution(p)) {
if (args.size() == 2)
// unit resolution with m_aux that got collapsed to nothing
{ newp = to_app(args.get(0)); }
else {
ptr_vector<proof> parents;
for (unsigned i = 0, sz = args.size() - 1; i < sz; ++i)
{ parents.push_back(to_app(args.get(i))); }
SASSERT(parents.size() == args.size() - 1);
newp = m.mk_unit_resolution(parents.size(), parents.c_ptr());
// XXX the old and new facts should be
// equivalent. The test here is much
// stronger. It might need to be relaxed.
SASSERT(m.get_fact(newp) == args.back());
pinned.push_back(newp);
}
} else if (matches_fact(args, a)) {
newp = to_app(a);
} else {
expr_ref papp(m);
mk_app(p->get_decl(), args, papp);
newp = to_app(papp.get());
pinned.push_back(newp);
}
cache.insert(p, newp);
todo.pop_back();
CTRACE("virtual",
p->get_decl_kind() == PR_TH_LEMMA &&
p->get_decl()->get_parameter(0).get_symbol() == "arith" &&
p->get_decl()->get_num_parameters() > 1 &&
p->get_decl()->get_parameter(1).get_symbol() == "farkas",
tout << "Old pf: " << mk_pp(p, m) << "\n"
<< "New pf: " << mk_pp(newp, m) << "\n";);
}
proof *r;
VERIFY(cache.find(pr, r));
DEBUG_CODE(
proof_checker pc(m);
expr_ref_vector side(m);
SASSERT(pc.check(r, side));
);
res = r ;
}
};
} }
proof *virtual_solver::get_proof() proof *virtual_solver::get_proof()
@ -349,15 +189,16 @@ void virtual_solver::push_core()
m_context.push(); m_context.push();
} }
} }
void virtual_solver::pop_core(unsigned n) void virtual_solver::pop_core(unsigned n) {
{
SASSERT(!m_pushed || get_scope_level() > 0); SASSERT(!m_pushed || get_scope_level() > 0);
if (m_pushed) { if (m_pushed) {
SASSERT(!m_in_delay_scope); SASSERT(!m_in_delay_scope);
m_context.pop(n); m_context.pop(n);
m_pushed = get_scope_level() - n > 0; m_pushed = get_scope_level() - n > 0;
} else }
{ m_in_delay_scope = get_scope_level() - n > 0; } else {
m_in_delay_scope = get_scope_level() - n > 0;
}
} }
void virtual_solver::get_unsat_core(ptr_vector<expr> &r) void virtual_solver::get_unsat_core(ptr_vector<expr> &r)

View file

@ -92,7 +92,6 @@ public:
virtual bool get_produce_models(); virtual bool get_produce_models();
virtual smt_params &fparams(); virtual smt_params &fparams();
virtual void reset(); virtual void reset();
virtual void set_progress_callback(progress_callback *callback) virtual void set_progress_callback(progress_callback *callback)
{UNREACHABLE();} {UNREACHABLE();}
@ -134,6 +133,9 @@ private:
void refresh(); void refresh();
smt_params &fparams() { return m_fparams; }
public: public:
virtual_solver_factory(ast_manager &mgr, smt_params &fparams); virtual_solver_factory(ast_manager &mgr, smt_params &fparams);
virtual ~virtual_solver_factory(); virtual ~virtual_solver_factory();
@ -144,7 +146,6 @@ public:
void collect_param_descrs(param_descrs &r) { /* empty */ } void collect_param_descrs(param_descrs &r) { /* empty */ }
void set_produce_models(bool f) { m_fparams.m_model = f; } void set_produce_models(bool f) { m_fparams.m_model = f; }
bool get_produce_models() { return m_fparams.m_model; } bool get_produce_models() { return m_fparams.m_model; }
smt_params &fparams() { return m_fparams; }
}; };
} }

View file

@ -21,6 +21,7 @@ Author:
#include "muz/dataflow/dataflow.h" #include "muz/dataflow/dataflow.h"
#include "muz/dataflow/reachability.h" #include "muz/dataflow/reachability.h"
#include "ast/ast_pp.h" #include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "tactic/extension_model_converter.h" #include "tactic/extension_model_converter.h"
namespace datalog { namespace datalog {
@ -33,20 +34,28 @@ namespace datalog {
rule_set * mk_coi_filter::bottom_up(rule_set const & source) { rule_set * mk_coi_filter::bottom_up(rule_set const & source) {
dataflow_engine<reachability_info> engine(source.get_manager(), source); dataflow_engine<reachability_info> engine(source.get_manager(), source);
engine.run_bottom_up(); engine.run_bottom_up();
func_decl_set unreachable;
scoped_ptr<rule_set> res = alloc(rule_set, m_context); scoped_ptr<rule_set> res = alloc(rule_set, m_context);
res->inherit_predicates(source); res->inherit_predicates(source);
for (rule_set::iterator it = source.begin(); it != source.end(); ++it) { for (rule* r : source) {
rule * r = *it;
bool new_tail = false; bool new_tail = false;
bool contained = true; bool contained = true;
m_new_tail.reset();
m_new_tail_neg.reset();
for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) { for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) {
if (m_context.has_facts(r->get_decl(i))) { func_decl* decl_i = r->get_decl(i);
if (m_context.has_facts(decl_i)) {
return 0; return 0;
} }
bool reachable = engine.get_fact(decl_i).is_reachable();
if (!reachable) {
unreachable.insert(decl_i);
}
if (r->is_neg_tail(i)) { if (r->is_neg_tail(i)) {
if (!engine.get_fact(r->get_decl(i)).is_reachable()) { if (!reachable) {
if (!new_tail) { if (!new_tail) {
for (unsigned j = 0; j < i; ++j) { for (unsigned j = 0; j < i; ++j) {
m_new_tail.push_back(r->get_tail(j)); m_new_tail.push_back(r->get_tail(j));
@ -60,10 +69,9 @@ namespace datalog {
m_new_tail_neg.push_back(true); m_new_tail_neg.push_back(true);
} }
} }
else { else {
SASSERT(!new_tail); SASSERT(!new_tail);
if (!engine.get_fact(r->get_decl(i)).is_reachable()) { if (!reachable) {
contained = false; contained = false;
break; break;
} }
@ -78,24 +86,26 @@ namespace datalog {
res->add_rule(r); res->add_rule(r);
} }
} }
m_new_tail.reset();
m_new_tail_neg.reset();
} }
if (res->get_num_rules() == source.get_num_rules()) { if (res->get_num_rules() == source.get_num_rules()) {
TRACE("dl", tout << "No transformation\n";); TRACE("dl", tout << "No transformation\n";);
res = 0; res = 0;
} else { }
else {
res->close(); res->close();
} }
// set to false each unreached predicate // set to false each unreached predicate
if (m_context.get_model_converter()) { if (res && m_context.get_model_converter()) {
extension_model_converter* mc0 = alloc(extension_model_converter, m); extension_model_converter* mc0 = alloc(extension_model_converter, m);
for (dataflow_engine<reachability_info>::iterator it = engine.begin(); it != engine.end(); it++) { for (auto const& kv : engine) {
if (!it->m_value.is_reachable()) { if (!kv.m_value.is_reachable()) {
mc0->insert(it->m_key, m.mk_false()); mc0->insert(kv.m_key, m.mk_false());
} }
} }
for (func_decl* f : unreachable) {
mc0->insert(f, m.mk_false());
}
m_context.add_model_converter(mc0); m_context.add_model_converter(mc0);
} }
CTRACE("dl", 0 != res, res->display(tout);); CTRACE("dl", 0 != res, res->display(tout););
@ -109,9 +119,7 @@ namespace datalog {
scoped_ptr<rule_set> res = alloc(rule_set, m_context); scoped_ptr<rule_set> res = alloc(rule_set, m_context);
res->inherit_predicates(source); res->inherit_predicates(source);
rule_set::iterator rend = source.end(); for (rule * r : source) {
for (rule_set::iterator rit = source.begin(); rit != rend; ++rit) {
rule * r = *rit;
func_decl * pred = r->get_decl(); func_decl * pred = r->get_decl();
if (engine.get_fact(pred).is_reachable()) { if (engine.get_fact(pred).is_reachable()) {
res->add_rule(r); res->add_rule(r);
@ -125,14 +133,12 @@ namespace datalog {
res = 0; res = 0;
} }
if (res && m_context.get_model_converter()) { if (res && m_context.get_model_converter()) {
func_decl_set::iterator end = pruned_preds.end();
func_decl_set::iterator it = pruned_preds.begin();
extension_model_converter* mc0 = alloc(extension_model_converter, m); extension_model_converter* mc0 = alloc(extension_model_converter, m);
for (; it != end; ++it) { for (func_decl* f : pruned_preds) {
const rule_vector& rules = source.get_predicate_rules(*it); const rule_vector& rules = source.get_predicate_rules(f);
expr_ref_vector fmls(m); expr_ref_vector fmls(m);
for (unsigned i = 0; i < rules.size(); ++i) { for (rule * r : rules) {
app* head = rules[i]->get_head(); app* head = r->get_head();
expr_ref_vector conj(m); expr_ref_vector conj(m);
for (unsigned j = 0; j < head->get_num_args(); ++j) { for (unsigned j = 0; j < head->get_num_args(); ++j) {
expr* arg = head->get_arg(j); expr* arg = head->get_arg(j);
@ -140,11 +146,9 @@ namespace datalog {
conj.push_back(m.mk_eq(m.mk_var(j, m.get_sort(arg)), arg)); conj.push_back(m.mk_eq(m.mk_var(j, m.get_sort(arg)), arg));
} }
} }
fmls.push_back(m.mk_and(conj.size(), conj.c_ptr())); fmls.push_back(mk_and(conj));
} }
expr_ref fml(m); mc0->insert(f, mk_or(fmls));
fml = m.mk_or(fmls.size(), fmls.c_ptr());
mc0->insert(*it, fml);
} }
m_context.add_model_converter(mc0); m_context.add_model_converter(mc0);
} }

View file

@ -315,14 +315,13 @@ public:
void found_optimum() { void found_optimum() {
IF_VERBOSE(1, verbose_stream() << "found optimum\n";); IF_VERBOSE(1, verbose_stream() << "found optimum\n";);
rational upper(0); m_lower.reset();
for (unsigned i = 0; i < m_soft.size(); ++i) { for (unsigned i = 0; i < m_soft.size(); ++i) {
m_assignment[i] = is_true(m_soft[i]); m_assignment[i] = is_true(m_soft[i]);
if (!m_assignment[i]) { if (!m_assignment[i]) {
upper += m_weights[i]; m_lower += m_weights[i];
} }
} }
SASSERT(upper == m_lower);
m_upper = m_lower; m_upper = m_lower;
m_found_feasible_optimum = true; m_found_feasible_optimum = true;
} }
@ -397,10 +396,11 @@ public:
void get_current_correction_set(model* mdl, exprs& cs) { void get_current_correction_set(model* mdl, exprs& cs) {
cs.reset(); cs.reset();
if (!mdl) return; if (!mdl) return;
for (unsigned i = 0; i < m_asms.size(); ++i) { for (expr* a : m_asms) {
if (is_false(mdl, m_asms[i].get())) { if (is_false(mdl, a)) {
cs.push_back(m_asms[i].get()); cs.push_back(a);
} }
TRACE("opt", expr_ref tmp(m); mdl->eval(a, tmp, true); tout << mk_pp(a, m) << ": " << tmp << "\n";);
} }
TRACE("opt", display_vec(tout << "new correction set: ", cs);); TRACE("opt", display_vec(tout << "new correction set: ", cs););
} }
@ -509,6 +509,7 @@ public:
trace(); trace();
if (m_c.num_objectives() == 1 && m_pivot_on_cs && m_csmodel.get() && m_correction_set_size < core.size()) { if (m_c.num_objectives() == 1 && m_pivot_on_cs && m_csmodel.get() && m_correction_set_size < core.size()) {
exprs cs; exprs cs;
TRACE("opt", tout << "cs " << m_correction_set_size << " " << core.size() << "\n";);
get_current_correction_set(m_csmodel.get(), cs); get_current_correction_set(m_csmodel.get(), cs);
m_correction_set_size = cs.size(); m_correction_set_size = cs.size();
if (m_correction_set_size < core.size()) { if (m_correction_set_size < core.size()) {

View file

@ -819,7 +819,7 @@ namespace opt {
bool is_max = is_maximize(fml, term, orig_term, index); bool is_max = is_maximize(fml, term, orig_term, index);
bool is_min = !is_max && is_minimize(fml, term, orig_term, index); bool is_min = !is_max && is_minimize(fml, term, orig_term, index);
if (is_min && get_pb_sum(term, terms, weights, offset)) { if (is_min && get_pb_sum(term, terms, weights, offset)) {
TRACE("opt", tout << "try to convert minimization" << mk_pp(term, m) << "\n";); TRACE("opt", tout << "try to convert minimization\n" << mk_pp(term, m) << "\n";);
// minimize 2*x + 3*y // minimize 2*x + 3*y
// <=> // <=>
// (assert-soft (not x) 2) // (assert-soft (not x) 2)

View file

@ -47,8 +47,9 @@ namespace opt {
m_dump_benchmarks(false), m_dump_benchmarks(false),
m_first(true), m_first(true),
m_was_unknown(false) { m_was_unknown(false) {
solver::updt_params(p);
m_params.updt_params(p); m_params.updt_params(p);
if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) { if (m_params.m_case_split_strategy == CS_ACTIVITY_DELAY_NEW) {
m_params.m_relevancy_lvl = 0; m_params.m_relevancy_lvl = 0;
} }
// m_params.m_auto_config = false; // m_params.m_auto_config = false;

View file

@ -34,7 +34,7 @@ Revision History:
namespace smtlib { namespace smtlib {
solver::solver(): solver::solver():
m_ast_manager(m_params.m_proof ? PGM_FINE : PGM_DISABLED, m_ast_manager(m_params.m_proof ? PGM_ENABLED : PGM_DISABLED,
m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0), m_params.m_trace ? m_params.m_trace_file_name.c_str() : 0),
m_ctx(0), m_ctx(0),
m_error_code(0) { m_error_code(0) {

View file

@ -1,5 +1,6 @@
z3_add_component(smt2parser z3_add_component(smt2parser
SOURCES SOURCES
marshal.cpp
smt2parser.cpp smt2parser.cpp
smt2scanner.cpp smt2scanner.cpp
COMPONENT_DEPENDENCIES COMPONENT_DEPENDENCIES

View file

@ -2,14 +2,14 @@
Copyright (c) 2017 Arie Gurfinkel Copyright (c) 2017 Arie Gurfinkel
Module Name: Module Name:
spacer_marshal.cpp marshal.cpp
Abstract: Abstract:
marshaling and unmarshaling of expressions marshaling and unmarshaling of expressions
--*/ --*/
#include "muz/spacer/spacer_marshal.h" #include "parsers/smt2/marshal.h"
#include <sstream> #include <sstream>
@ -18,39 +18,33 @@ Abstract:
#include "util/vector.h" #include "util/vector.h"
#include "ast/ast_smt_pp.h" #include "ast/ast_smt_pp.h"
#include "ast/ast_pp.h" #include "ast/ast_pp.h"
#include "ast/ast_util.h"
namespace spacer { std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m) {
std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m)
{
ast_smt_pp pp(m); ast_smt_pp pp(m);
pp.display_smt2(os, e); pp.display_smt2(os, e);
return os; return os;
} }
std::string marshal(expr_ref e, ast_manager &m) std::string marshal(expr_ref e, ast_manager &m) {
{
std::stringstream ss; std::stringstream ss;
marshal(ss, e, m); marshal(ss, e, m);
return ss.str(); return ss.str();
} }
expr_ref unmarshal(std::istream &is, ast_manager &m) expr_ref unmarshal(std::istream &is, ast_manager &m) {
{
cmd_context ctx(false, &m); cmd_context ctx(false, &m);
ctx.set_ignore_check(true); ctx.set_ignore_check(true);
if (!parse_smt2_commands(ctx, is)) { return expr_ref(0, m); } if (!parse_smt2_commands(ctx, is)) { return expr_ref(0, m); }
ptr_vector<expr>::const_iterator it = ctx.begin_assertions(); ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
ptr_vector<expr>::const_iterator end = ctx.end_assertions(); ptr_vector<expr>::const_iterator end = ctx.end_assertions();
if (it == end) { return expr_ref(m.mk_true(), m); }
unsigned size = static_cast<unsigned>(end - it); unsigned size = static_cast<unsigned>(end - it);
return expr_ref(m.mk_and(size, it), m); return expr_ref(mk_and(m, size, it), m);
} }
expr_ref unmarshal(std::string s, ast_manager &m) expr_ref unmarshal(std::string s, ast_manager &m) {
{
std::istringstream is(s); std::istringstream is(s);
return unmarshal(is, m); return unmarshal(is, m);
} }
}

View file

@ -2,7 +2,7 @@
Copyright (c) 2017 Arie Gurfinkel Copyright (c) 2017 Arie Gurfinkel
Module Name: Module Name:
spacer_marshal.h marshal.h
Abstract: Abstract:
@ -17,14 +17,11 @@ Abstract:
#include "ast/ast.h" #include "ast/ast.h"
namespace spacer {
std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m); std::ostream &marshal(std::ostream &os, expr_ref e, ast_manager &m);
std::string marshal(expr_ref e, ast_manager &m); std::string marshal(expr_ref e, ast_manager &m);
expr_ref unmarshal(std::string s, ast_manager &m); expr_ref unmarshal(std::string s, ast_manager &m);
expr_ref unmarshal(std::istream &is, ast_manager &m); expr_ref unmarshal(std::istream &is, ast_manager &m);
}
#endif #endif

View file

@ -1881,6 +1881,8 @@ namespace smt2 {
// the resultant expression is on the top of the stack // the resultant expression is on the top of the stack
TRACE("let_frame", tout << "let result expr: " << mk_pp(expr_stack().back(), m()) << "\n";); TRACE("let_frame", tout << "let result expr: " << mk_pp(expr_stack().back(), m()) << "\n";);
expr_ref r(m()); expr_ref r(m());
if (expr_stack().empty())
throw parser_exception("invalid let expression");
r = expr_stack().back(); r = expr_stack().back();
expr_stack().pop_back(); expr_stack().pop_back();
// remove local declarations from the stack // remove local declarations from the stack

View file

@ -69,7 +69,7 @@ class inc_sat_solver : public solver {
public: public:
inc_sat_solver(ast_manager& m, params_ref const& p): inc_sat_solver(ast_manager& m, params_ref const& p):
m(m), m_solver(p, m.limit(), 0), m(m), m_solver(p, m.limit(), 0),
m_params(p), m_optimize_model(false), m_optimize_model(false),
m_fmls(m), m_fmls(m),
m_asmsf(m), m_asmsf(m),
m_fmls_head(0), m_fmls_head(0),
@ -79,7 +79,7 @@ public:
m_dep_core(m), m_dep_core(m),
m_unknown("no reason given") { m_unknown("no reason given") {
m_params.set_bool("elim_vars", false); m_params.set_bool("elim_vars", false);
m_solver.updt_params(m_params); updt_params(p);
init_preprocess(); init_preprocess();
} }
@ -237,7 +237,7 @@ public:
sat::solver::collect_param_descrs(r); sat::solver::collect_param_descrs(r);
} }
virtual void updt_params(params_ref const & p) { virtual void updt_params(params_ref const & p) {
m_params = p; solver::updt_params(p);
m_params.set_bool("elim_vars", false); m_params.set_bool("elim_vars", false);
m_solver.updt_params(m_params); m_solver.updt_params(m_params);
m_optimize_model = m_params.get_bool("optimize_model", false); m_optimize_model = m_params.get_bool("optimize_model", false);

View file

@ -75,7 +75,7 @@ z3_add_component(smt
normal_forms normal_forms
parser_util parser_util
pattern pattern
proof_checker proofs
proto_model proto_model
simplex simplex
substitution substitution

View file

@ -101,14 +101,14 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vector<justified_ex
else if (m.is_and(e)) { else if (m.is_and(e)) {
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
expr* arg = to_app(e)->get_arg(i); expr* arg = to_app(e)->get_arg(i);
proof_ref _pr(m.mk_and_elim(pr, i), m); proof_ref _pr(m.proofs_enabled() ? m.mk_and_elim(pr, i) : 0, m);
push_assertion(arg, _pr, result); push_assertion(arg, _pr, result);
} }
} }
else if (m.is_not(e, e1) && m.is_or(e1)) { else if (m.is_not(e, e1) && m.is_or(e1)) {
for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) {
expr* arg = to_app(e1)->get_arg(i); expr* arg = to_app(e1)->get_arg(i);
proof_ref _pr(m.mk_not_or_elim(pr, i), m); proof_ref _pr(m.proofs_enabled() ? m.mk_not_or_elim(pr, i) : 0, m);
expr_ref narg(mk_not(m, arg), m); expr_ref narg(mk_not(m, arg), m);
push_assertion(narg, _pr, result); push_assertion(narg, _pr, result);
} }
@ -163,7 +163,7 @@ void asserted_formulas::assert_expr(expr * e, proof * _in_pr) {
} }
void asserted_formulas::assert_expr(expr * e) { void asserted_formulas::assert_expr(expr * e) {
assert_expr(e, m.mk_asserted(e)); assert_expr(e, m.proofs_enabled() ? m.mk_asserted(e) : nullptr);
} }
void asserted_formulas::get_assertions(ptr_vector<expr> & result) const { void asserted_formulas::get_assertions(ptr_vector<expr> & result) const {
@ -365,7 +365,7 @@ void asserted_formulas::nnf_cnf() {
CASSERT("well_sorted", is_well_sorted(m, n)); CASSERT("well_sorted", is_well_sorted(m, n));
apply_nnf(n, push_todo, push_todo_prs, r1, pr1); apply_nnf(n, push_todo, push_todo_prs, r1, pr1);
CASSERT("well_sorted",is_well_sorted(m, r1)); CASSERT("well_sorted",is_well_sorted(m, r1));
pr = m.mk_modus_ponens(pr, pr1); pr = m.proofs_enabled() ? m.mk_modus_ponens(pr, pr1) : nullptr;
push_todo.push_back(r1); push_todo.push_back(r1);
push_todo_prs.push_back(pr); push_todo_prs.push_back(pr);
@ -506,16 +506,19 @@ void asserted_formulas::update_substitution(expr* n, proof* pr) {
} }
if (is_gt(rhs, lhs)) { if (is_gt(rhs, lhs)) {
TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";);
m_scoped_substitution.insert(rhs, lhs, m.mk_symmetry(pr)); m_scoped_substitution.insert(rhs, lhs, m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr);
return; return;
} }
TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";);
} }
if (m.is_not(n, n1)) { proof_ref pr1(m);
m_scoped_substitution.insert(n1, m.mk_false(), m.mk_iff_false(pr)); if (m.is_not(n, n1)) {
pr1 = m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr;
m_scoped_substitution.insert(n1, m.mk_false(), pr1);
} }
else { else {
m_scoped_substitution.insert(n, m.mk_true(), m.mk_iff_true(pr)); pr1 = m.proofs_enabled() ? m.mk_iff_true(pr) : nullptr;
m_scoped_substitution.insert(n, m.mk_true(), pr1);
} }
} }

View file

@ -810,8 +810,6 @@ namespace smt {
m_new_proofs.push_back(pr); m_new_proofs.push_back(pr);
return pr; return pr;
} }
if (m_manager.coarse_grain_proofs())
return pr;
TRACE("norm_eq_proof", TRACE("norm_eq_proof",
tout << "#" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n"; tout << "#" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";
tout << mk_ll_pp(pr, m_manager, true, false);); tout << mk_ll_pp(pr, m_manager, true, false););
@ -1217,7 +1215,7 @@ namespace smt {
mk_proof(rhs, c, prs2); mk_proof(rhs, c, prs2);
while (!prs2.empty()) { while (!prs2.empty()) {
proof * pr = prs2.back(); proof * pr = prs2.back();
if (m_manager.fine_grain_proofs()) { if (m_manager.proofs_enabled()) {
pr = m_manager.mk_symmetry(pr); pr = m_manager.mk_symmetry(pr);
m_new_proofs.push_back(pr); m_new_proofs.push_back(pr);
prs1.push_back(pr); prs1.push_back(pr);

View file

@ -23,7 +23,7 @@ Revision History:
#include "ast/ast_ll_pp.h" #include "ast/ast_ll_pp.h"
#include "util/warning.h" #include "util/warning.h"
#include "smt/smt_quick_checker.h" #include "smt/smt_quick_checker.h"
#include "ast/proof_checker/proof_checker.h" #include "ast/proofs/proof_checker.h"
#include "ast/ast_util.h" #include "ast/ast_util.h"
#include "smt/uses_theory.h" #include "smt/uses_theory.h"
#include "model/model.h" #include "model/model.h"
@ -4389,7 +4389,8 @@ namespace smt {
subst.push_back(arg); subst.push_back(arg);
} }
expr_ref bodyr(m); expr_ref bodyr(m);
var_subst sub(m, false); var_subst sub(m, true);
TRACE("context", tout << expr_ref(q, m) << " " << subst << "\n";);
sub(body, subst.size(), subst.c_ptr(), bodyr); sub(body, subst.size(), subst.c_ptr(), bodyr);
func_decl* f = to_app(fn)->get_decl(); func_decl* f = to_app(fn)->get_decl();
func_interp* fi = alloc(func_interp, m, f->get_arity()); func_interp* fi = alloc(func_interp, m, f->get_arity());

View file

@ -129,7 +129,7 @@ namespace smt {
if (m_node1 != m_node1->get_root()) { if (m_node1 != m_node1->get_root()) {
proof * pr = cr.get_proof(m_node1, m_node1->get_root()); proof * pr = cr.get_proof(m_node1, m_node1->get_root());
if (pr && m.fine_grain_proofs()) if (pr && m.proofs_enabled())
pr = m.mk_symmetry(pr); pr = m.mk_symmetry(pr);
prs.push_back(pr); prs.push_back(pr);
if (!pr) if (!pr)

View file

@ -29,9 +29,8 @@ Notes:
namespace smt { namespace smt {
class solver : public solver_na2as { class smt_solver : public solver_na2as {
smt_params m_smt_params; smt_params m_smt_params;
params_ref m_params;
smt::kernel m_context; smt::kernel m_context;
progress_callback * m_callback; progress_callback * m_callback;
symbol m_logic; symbol m_logic;
@ -42,28 +41,24 @@ namespace smt {
obj_map<expr, expr*> m_name2assertion; obj_map<expr, expr*> m_name2assertion;
public: public:
solver(ast_manager & m, params_ref const & p, symbol const & l) : smt_solver(ast_manager & m, params_ref const & p, symbol const & l) :
solver_na2as(m), solver_na2as(m),
m_smt_params(p), m_smt_params(p),
m_params(p),
m_context(m, m_smt_params), m_context(m, m_smt_params),
m_minimizing_core(false), m_minimizing_core(false),
m_core_extend_patterns(false), m_core_extend_patterns(false),
m_core_extend_patterns_max_distance(UINT_MAX), m_core_extend_patterns_max_distance(UINT_MAX),
m_core_extend_nonlocal_patterns(false) { m_core_extend_nonlocal_patterns(false) {
m_logic = l; m_logic = l;
if (m_logic != symbol::null) if (m_logic != symbol::null)
m_context.set_logic(m_logic); m_context.set_logic(m_logic);
smt_params_helper smth(p); updt_params(p);
m_core_extend_patterns = smth.core_extend_patterns();
m_core_extend_patterns_max_distance = smth.core_extend_patterns_max_distance();
m_core_extend_nonlocal_patterns = smth.core_extend_nonlocal_patterns();
} }
virtual solver * translate(ast_manager & m, params_ref const & p) { virtual solver * translate(ast_manager & m, params_ref const & p) {
ast_translation translator(get_manager(), m); ast_translation translator(get_manager(), m);
solver * result = alloc(solver, m, p, m_logic); smt_solver * result = alloc(smt_solver, m, p, m_logic);
smt::kernel::copy(m_context, result->m_context); smt::kernel::copy(m_context, result->m_context);
for (auto & kv : m_name2assertion) for (auto & kv : m_name2assertion)
@ -73,13 +68,13 @@ namespace smt {
return result; return result;
} }
virtual ~solver() { virtual ~smt_solver() {
dec_ref_values(get_manager(), m_name2assertion); dec_ref_values(get_manager(), m_name2assertion);
} }
virtual void updt_params(params_ref const & p) { virtual void updt_params(params_ref const & p) {
solver::updt_params(p);
m_smt_params.updt_params(p); m_smt_params.updt_params(p);
m_params.copy(p);
m_context.updt_params(p); m_context.updt_params(p);
smt_params_helper smth(p); smt_params_helper smth(p);
m_core_extend_patterns = smth.core_extend_patterns(); m_core_extend_patterns = smth.core_extend_patterns();
@ -146,9 +141,9 @@ namespace smt {
} }
struct scoped_minimize_core { struct scoped_minimize_core {
solver& s; smt_solver& s;
expr_ref_vector m_assumptions; expr_ref_vector m_assumptions;
scoped_minimize_core(solver& s) : s(s), m_assumptions(s.m_assumptions) { scoped_minimize_core(smt_solver& s) : s(s), m_assumptions(s.m_assumptions) {
s.m_minimizing_core = true; s.m_minimizing_core = true;
s.m_assumptions.reset(); s.m_assumptions.reset();
} }
@ -165,7 +160,7 @@ namespace smt {
r.push_back(m_context.get_unsat_core_expr(i)); r.push_back(m_context.get_unsat_core_expr(i));
} }
if (m_minimizing_core && smt_params_helper(m_params).core_minimize()) { if (m_minimizing_core && smt_params_helper(get_params()).core_minimize()) {
scoped_minimize_core scm(*this); scoped_minimize_core scm(*this);
mus mus(*this); mus mus(*this);
mus.add_soft(r.size(), r.c_ptr()); mus.add_soft(r.size(), r.c_ptr());
@ -346,22 +341,16 @@ namespace smt {
void add_nonlocal_pattern_literals_to_core(ptr_vector<expr> & core) { void add_nonlocal_pattern_literals_to_core(ptr_vector<expr> & core) {
ast_manager & m = get_manager(); ast_manager & m = get_manager();
for (auto const& kv : m_name2assertion) {
obj_map<expr, expr*>::iterator it = m_name2assertion.begin(); expr_ref name(kv.m_key, m);
obj_map<expr, expr*>::iterator end = m_name2assertion.end(); expr_ref assrtn(kv.m_value, m);
for (unsigned i = 0; it != end; it++, i++) {
expr_ref name(it->m_key, m);
expr_ref assrtn(it->m_value, m);
if (!core.contains(name)) { if (!core.contains(name)) {
func_decl_set pattern_fds, body_fds; func_decl_set pattern_fds, body_fds;
collect_pattern_fds(assrtn, pattern_fds); collect_pattern_fds(assrtn, pattern_fds);
collect_body_func_decls(assrtn, body_fds); collect_body_func_decls(assrtn, body_fds);
func_decl_set::iterator pit = pattern_fds.begin(); for (func_decl *fd : pattern_fds) {
func_decl_set::iterator pend= pattern_fds.end();
for (; pit != pend; pit++) {
func_decl * fd = *pit;
if (!body_fds.contains(fd)) { if (!body_fds.contains(fd)) {
core.insert(name); core.insert(name);
break; break;
@ -374,7 +363,7 @@ namespace smt {
}; };
solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & logic) { solver * mk_smt_solver(ast_manager & m, params_ref const & p, symbol const & logic) {
return alloc(smt::solver, m, p, logic); return alloc(smt::smt_solver, m, p, logic);
} }
class smt_solver_factory : public solver_factory { class smt_solver_factory : public solver_factory {

View file

@ -53,18 +53,12 @@ namespace smt {
var_data * d2 = m_var_data[v2]; var_data * d2 = m_var_data[v2];
if (!d1->m_prop_upward && d2->m_prop_upward) if (!d1->m_prop_upward && d2->m_prop_upward)
set_prop_upward(v1); set_prop_upward(v1);
ptr_vector<enode>::iterator it = d2->m_stores.begin(); for (enode* n : d2->m_stores)
ptr_vector<enode>::iterator end = d2->m_stores.end(); add_store(v1, n);
for (; it != end; ++it) for (enode* n : d2->m_parent_stores)
add_store(v1, *it); add_parent_store(v1, n);
it = d2->m_parent_stores.begin(); for (enode* n : d2->m_parent_selects)
end = d2->m_parent_stores.end(); add_parent_select(v1, n);
for (; it != end; ++it)
add_parent_store(v1, *it);
it = d2->m_parent_selects.begin();
end = d2->m_parent_selects.end();
for (; it != end; ++it)
add_parent_select(v1, *it);
TRACE("array", tout << "after merge\n"; display_var(tout, v1);); TRACE("array", tout << "after merge\n"; display_var(tout, v1););
} }
@ -103,16 +97,11 @@ namespace smt {
d->m_parent_selects.push_back(s); d->m_parent_selects.push_back(s);
TRACE("array", tout << mk_pp(s->get_owner(), get_manager()) << " " << mk_pp(get_enode(v)->get_owner(), get_manager()) << "\n";); TRACE("array", tout << mk_pp(s->get_owner(), get_manager()) << " " << mk_pp(get_enode(v)->get_owner(), get_manager()) << "\n";);
m_trail_stack.push(push_back_trail<theory_array, enode *, false>(d->m_parent_selects)); m_trail_stack.push(push_back_trail<theory_array, enode *, false>(d->m_parent_selects));
ptr_vector<enode>::iterator it = d->m_stores.begin(); for (enode* n : d->m_stores) {
ptr_vector<enode>::iterator end = d->m_stores.end(); instantiate_axiom2a(s, n);
for (; it != end; ++it) {
instantiate_axiom2a(s, *it);
} }
if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) { if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) {
it = d->m_parent_stores.begin(); for (enode* store : d->m_parent_stores) {
end = d->m_parent_stores.end();
for (; it != end; ++it) {
enode * store = *it;
SASSERT(is_store(store)); SASSERT(is_store(store));
if (!m_params.m_array_cg || store->is_cgr()) { if (!m_params.m_array_cg || store->is_cgr()) {
instantiate_axiom2b(s, store); instantiate_axiom2b(s, store);
@ -129,27 +118,19 @@ namespace smt {
var_data * d = m_var_data[v]; var_data * d = m_var_data[v];
d->m_parent_stores.push_back(s); d->m_parent_stores.push_back(s);
m_trail_stack.push(push_back_trail<theory_array, enode *, false>(d->m_parent_stores)); m_trail_stack.push(push_back_trail<theory_array, enode *, false>(d->m_parent_stores));
if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward) { if (!m_params.m_array_weak && !m_params.m_array_delay_exp_axiom && d->m_prop_upward)
ptr_vector<enode>::iterator it = d->m_parent_selects.begin(); for (enode* n : d->m_parent_selects)
ptr_vector<enode>::iterator end = d->m_parent_selects.end(); if (!m_params.m_array_cg || n->is_cgr())
for (; it != end; ++it) instantiate_axiom2b(n, s);
if (!m_params.m_array_cg || (*it)->is_cgr())
instantiate_axiom2b(*it, s);
}
} }
bool theory_array::instantiate_axiom2b_for(theory_var v) { bool theory_array::instantiate_axiom2b_for(theory_var v) {
bool result = false; bool result = false;
var_data * d = m_var_data[v]; var_data * d = m_var_data[v];
ptr_vector<enode>::iterator it = d->m_parent_stores.begin(); for (enode* n1 : d->m_parent_stores)
ptr_vector<enode>::iterator end = d->m_parent_stores.end(); for (enode * n2 : d->m_parent_selects)
for (; it != end; ++it) { if (instantiate_axiom2b(n2, n1))
ptr_vector<enode>::iterator it2 = d->m_parent_selects.begin();
ptr_vector<enode>::iterator end2 = d->m_parent_selects.end();
for (; it2 != end2; ++it2)
if (instantiate_axiom2b(*it2, *it))
result = true; result = true;
}
return result; return result;
} }
@ -167,10 +148,8 @@ namespace smt {
d->m_prop_upward = true; d->m_prop_upward = true;
if (!m_params.m_array_delay_exp_axiom) if (!m_params.m_array_delay_exp_axiom)
instantiate_axiom2b_for(v); instantiate_axiom2b_for(v);
ptr_vector<enode>::iterator it = d->m_stores.begin(); for (enode * n : d->m_stores)
ptr_vector<enode>::iterator end = d->m_stores.end(); set_prop_upward(n);
for (; it != end; ++it)
set_prop_upward(*it);
} }
} }
@ -209,11 +188,9 @@ namespace smt {
} }
d->m_stores.push_back(s); d->m_stores.push_back(s);
m_trail_stack.push(push_back_trail<theory_array, enode *, false>(d->m_stores)); m_trail_stack.push(push_back_trail<theory_array, enode *, false>(d->m_stores));
ptr_vector<enode>::iterator it = d->m_parent_selects.begin(); for (enode * n : d->m_parent_selects) {
ptr_vector<enode>::iterator end = d->m_parent_selects.end(); SASSERT(is_select(n));
for (; it != end; ++it) { instantiate_axiom2a(n, s);
SASSERT(is_select(*it));
instantiate_axiom2a(*it, s);
} }
if (m_params.m_array_always_prop_upward || lambda_equiv_class_size >= 1) if (m_params.m_array_always_prop_upward || lambda_equiv_class_size >= 1)
set_prop_upward(s); set_prop_upward(s);
@ -374,7 +351,7 @@ namespace smt {
final_check_status theory_array::final_check_eh() { final_check_status theory_array::final_check_eh() {
m_final_check_idx++; m_final_check_idx++;
final_check_status r; final_check_status r = FC_DONE;
if (m_params.m_array_lazy_ieq) { if (m_params.m_array_lazy_ieq) {
// Delay the creation of interface equalities... The // Delay the creation of interface equalities... The
// motivation is too give other theories and quantifier // motivation is too give other theories and quantifier

View file

@ -210,17 +210,15 @@ namespace smt {
func_decl_ref_vector * theory_array_base::register_sort(sort * s_array) { func_decl_ref_vector * theory_array_base::register_sort(sort * s_array) {
unsigned dimension = get_dimension(s_array); unsigned dimension = get_dimension(s_array);
func_decl_ref_vector * ext_skolems = 0; func_decl_ref_vector * ext_skolems = 0;
if (!m_sort2skolem.find(s_array, ext_skolems)) { if (!m_sort2skolem.find(s_array, ext_skolems)) {
array_util util(get_manager());
ast_manager & m = get_manager(); ast_manager & m = get_manager();
ext_skolems = alloc(func_decl_ref_vector, m); ext_skolems = alloc(func_decl_ref_vector, m);
for (unsigned i = 0; i < dimension; ++i) { for (unsigned i = 0; i < dimension; ++i) {
sort * ext_sk_domain[2] = { s_array, s_array }; func_decl * ext_sk_decl = util.mk_array_ext(s_array, i);
parameter p(i);
func_decl * ext_sk_decl = m.mk_func_decl(get_id(), OP_ARRAY_EXT, 1, &p, 2, ext_sk_domain);
ext_skolems->push_back(ext_sk_decl); ext_skolems->push_back(ext_sk_decl);
} }
m_sort2skolem.insert(s_array, ext_skolems); m_sort2skolem.insert(s_array, ext_skolems);

View file

@ -683,7 +683,9 @@ void theory_diff_logic<Ext>::set_neg_cycle_conflict() {
vector<parameter> params; vector<parameter> params;
if (get_manager().proofs_enabled()) { if (get_manager().proofs_enabled()) {
params.push_back(parameter(symbol("farkas"))); params.push_back(parameter(symbol("farkas")));
params.resize(lits.size()+1, parameter(rational(1))); for (unsigned i = 0; i <= lits.size(); ++i) {
params.push_back(parameter(rational(1)));
}
} }
ctx.set_conflict( ctx.set_conflict(

View file

@ -3466,6 +3466,8 @@ static bool get_arith_value(context& ctx, theory_id afid, expr* e, expr_ref& v)
bool theory_seq::get_num_value(expr* e, rational& val) const { bool theory_seq::get_num_value(expr* e, rational& val) const {
context& ctx = get_context(); context& ctx = get_context();
expr_ref _val(m); expr_ref _val(m);
if (!ctx.e_internalized(e))
return false;
enode* next = ctx.get_enode(e), *n = next; enode* next = ctx.get_enode(e), *n = next;
do { do {
if (get_arith_value(ctx, m_autil.get_family_id(), next->get_owner(), _val) && m_autil.is_numeral(_val, val) && val.is_int()) { if (get_arith_value(ctx, m_autil.get_family_id(), next->get_owner(), _val) && m_autil.is_numeral(_val, val) && val.is_int()) {

View file

@ -166,14 +166,18 @@ namespace smt {
} }
} }
void theory_str::assert_axiom(expr * e) { void theory_str::assert_axiom(expr * _e) {
if (opt_VerifyFinalCheckProgress) { if (opt_VerifyFinalCheckProgress) {
finalCheckProgressIndicator = true; finalCheckProgressIndicator = true;
} }
if (get_manager().is_true(e)) return; if (get_manager().is_true(_e)) return;
TRACE("str", tout << "asserting " << mk_ismt2_pp(e, get_manager()) << std::endl;);
context & ctx = get_context(); context & ctx = get_context();
ast_manager& m = get_manager();
TRACE("str", tout << "asserting " << mk_ismt2_pp(_e, m) << std::endl;);
expr_ref e(_e, m);
//th_rewriter rw(m);
//rw(e);
if (!ctx.b_internalized(e)) { if (!ctx.b_internalized(e)) {
ctx.internalize(e, false); ctx.internalize(e, false);
} }
@ -190,13 +194,13 @@ namespace smt {
expr * theory_str::rewrite_implication(expr * premise, expr * conclusion) { expr * theory_str::rewrite_implication(expr * premise, expr * conclusion) {
ast_manager & m = get_manager(); ast_manager & m = get_manager();
return m.mk_or(m.mk_not(premise), conclusion); return m.mk_or(mk_not(m, premise), conclusion);
} }
void theory_str::assert_implication(expr * premise, expr * conclusion) { void theory_str::assert_implication(expr * premise, expr * conclusion) {
ast_manager & m = get_manager(); ast_manager & m = get_manager();
TRACE("str", tout << "asserting implication " << mk_ismt2_pp(premise, m) << " -> " << mk_ismt2_pp(conclusion, m) << std::endl;); TRACE("str", tout << "asserting implication " << mk_ismt2_pp(premise, m) << " -> " << mk_ismt2_pp(conclusion, m) << std::endl;);
expr_ref axiom(m.mk_or(m.mk_not(premise), conclusion), m); expr_ref axiom(m.mk_or(mk_not(m, premise), conclusion), m);
assert_axiom(axiom); assert_axiom(axiom);
} }
@ -545,7 +549,7 @@ namespace smt {
context & ctx = get_context(); context & ctx = get_context();
ast_manager & m = get_manager(); ast_manager & m = get_manager();
expr_ref ax1(m.mk_not(ctx.mk_eq_atom(s, mk_string(""))), m); expr_ref ax1(mk_not(m, ctx.mk_eq_atom(s, mk_string(""))), m);
assert_axiom(ax1); assert_axiom(ax1);
{ {
@ -557,7 +561,7 @@ namespace smt {
SASSERT(zero); SASSERT(zero);
// build LHS > RHS and assert // build LHS > RHS and assert
// we have to build !(LHS <= RHS) instead // we have to build !(LHS <= RHS) instead
expr_ref lhs_gt_rhs(m.mk_not(m_autil.mk_le(len_str, zero)), m); expr_ref lhs_gt_rhs(mk_not(m, m_autil.mk_le(len_str, zero)), m);
SASSERT(lhs_gt_rhs); SASSERT(lhs_gt_rhs);
assert_axiom(lhs_gt_rhs); assert_axiom(lhs_gt_rhs);
} }
@ -592,7 +596,7 @@ namespace smt {
SASSERT(zero); SASSERT(zero);
// build LHS > RHS and assert // build LHS > RHS and assert
// we have to build !(LHS <= RHS) instead // we have to build !(LHS <= RHS) instead
expr_ref lhs_gt_rhs(m.mk_not(m_autil.mk_le(len_str, zero)), m); expr_ref lhs_gt_rhs(mk_not(m, m_autil.mk_le(len_str, zero)), m);
SASSERT(lhs_gt_rhs); SASSERT(lhs_gt_rhs);
assert_axiom(lhs_gt_rhs); assert_axiom(lhs_gt_rhs);
} }
@ -1089,7 +1093,7 @@ namespace smt {
m_autil.mk_ge(expr->get_arg(1), mk_int(0)), m_autil.mk_ge(expr->get_arg(1), mk_int(0)),
// REWRITE for arithmetic theory: // REWRITE for arithmetic theory:
// m_autil.mk_lt(expr->get_arg(1), mk_strlen(expr->get_arg(0))) // m_autil.mk_lt(expr->get_arg(1), mk_strlen(expr->get_arg(0)))
m.mk_not(m_autil.mk_ge(m_autil.mk_add(expr->get_arg(1), m_autil.mk_mul(mk_int(-1), mk_strlen(expr->get_arg(0)))), mk_int(0))) mk_not(m, m_autil.mk_ge(m_autil.mk_add(expr->get_arg(1), m_autil.mk_mul(mk_int(-1), mk_strlen(expr->get_arg(0)))), mk_int(0)))
), m); ), m);
expr_ref_vector and_item(m); expr_ref_vector and_item(m);
@ -1130,7 +1134,7 @@ namespace smt {
expr_ref_vector innerItems(m); expr_ref_vector innerItems(m);
innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1))); innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1)));
innerItems.push_back(ctx.mk_eq_atom(mk_strlen(ts0), mk_strlen(expr->get_arg(0)))); innerItems.push_back(ctx.mk_eq_atom(mk_strlen(ts0), mk_strlen(expr->get_arg(0))));
innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts0, expr->get_arg(0)), expr, m.mk_not(expr))); innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts0, expr->get_arg(0)), expr, mk_not(m, expr)));
expr_ref then1(m.mk_and(innerItems.size(), innerItems.c_ptr()), m); expr_ref then1(m.mk_and(innerItems.size(), innerItems.c_ptr()), m);
SASSERT(then1); SASSERT(then1);
@ -1143,7 +1147,7 @@ namespace smt {
, m); , m);
SASSERT(topLevelCond); SASSERT(topLevelCond);
expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, m.mk_not(expr)), m); expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, mk_not(m, expr)), m);
SASSERT(finalAxiom); SASSERT(finalAxiom);
assert_axiom(finalAxiom); assert_axiom(finalAxiom);
} }
@ -1167,7 +1171,7 @@ namespace smt {
expr_ref_vector innerItems(m); expr_ref_vector innerItems(m);
innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1))); innerItems.push_back(ctx.mk_eq_atom(expr->get_arg(1), mk_concat(ts0, ts1)));
innerItems.push_back(ctx.mk_eq_atom(mk_strlen(ts1), mk_strlen(expr->get_arg(0)))); innerItems.push_back(ctx.mk_eq_atom(mk_strlen(ts1), mk_strlen(expr->get_arg(0))));
innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts1, expr->get_arg(0)), expr, m.mk_not(expr))); innerItems.push_back(m.mk_ite(ctx.mk_eq_atom(ts1, expr->get_arg(0)), expr, mk_not(m, expr)));
expr_ref then1(m.mk_and(innerItems.size(), innerItems.c_ptr()), m); expr_ref then1(m.mk_and(innerItems.size(), innerItems.c_ptr()), m);
SASSERT(then1); SASSERT(then1);
@ -1180,7 +1184,7 @@ namespace smt {
, m); , m);
SASSERT(topLevelCond); SASSERT(topLevelCond);
expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, m.mk_not(expr)), m); expr_ref finalAxiom(m.mk_ite(topLevelCond, then1, mk_not(m, expr)), m);
SASSERT(finalAxiom); SASSERT(finalAxiom);
assert_axiom(finalAxiom); assert_axiom(finalAxiom);
} }
@ -1204,7 +1208,7 @@ namespace smt {
if (haystackStr.contains(needleStr)) { if (haystackStr.contains(needleStr)) {
assert_axiom(ex); assert_axiom(ex);
} else { } else {
assert_axiom(m.mk_not(ex)); assert_axiom(mk_not(m, ex));
} }
return; return;
} }
@ -1265,7 +1269,7 @@ namespace smt {
SASSERT(tmpLen); SASSERT(tmpLen);
thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4)));
thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen));
thenItems.push_back(m.mk_not(mk_contains(x3, expr->get_arg(1)))); thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1))));
expr_ref thenBranch(m.mk_and(thenItems.size(), thenItems.c_ptr()), m); expr_ref thenBranch(m.mk_and(thenItems.size(), thenItems.c_ptr()), m);
SASSERT(thenBranch); SASSERT(thenBranch);
@ -1341,7 +1345,7 @@ namespace smt {
expr_ref ite1(m.mk_ite( expr_ref ite1(m.mk_ite(
//m_autil.mk_lt(expr->get_arg(2), zeroAst), //m_autil.mk_lt(expr->get_arg(2), zeroAst),
m.mk_not(m_autil.mk_ge(expr->get_arg(2), zeroAst)), mk_not(m, m_autil.mk_ge(expr->get_arg(2), zeroAst)),
ctx.mk_eq_atom(resAst, mk_indexof(expr->get_arg(0), expr->get_arg(1))), ctx.mk_eq_atom(resAst, mk_indexof(expr->get_arg(0), expr->get_arg(1))),
ite2 ite2
), m); ), m);
@ -1384,7 +1388,7 @@ namespace smt {
thenItems.push_back(m_autil.mk_ge(indexAst, mk_int(0))); thenItems.push_back(m_autil.mk_ge(indexAst, mk_int(0)));
// args[0] = x1 . args[1] . x2 // args[0] = x1 . args[1] . x2
// x1 doesn't contain args[1] // x1 doesn't contain args[1]
thenItems.push_back(m.mk_not(mk_contains(x2, expr->get_arg(1)))); thenItems.push_back(mk_not(m, mk_contains(x2, expr->get_arg(1))));
thenItems.push_back(ctx.mk_eq_atom(indexAst, mk_strlen(x1))); thenItems.push_back(ctx.mk_eq_atom(indexAst, mk_strlen(x1)));
bool canSkip = false; bool canSkip = false;
@ -1402,7 +1406,7 @@ namespace smt {
expr_ref tmpLen(m_autil.mk_add(indexAst, mk_int(1)), m); expr_ref tmpLen(m_autil.mk_add(indexAst, mk_int(1)), m);
thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4)));
thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen));
thenItems.push_back(m.mk_not(mk_contains(x4, expr->get_arg(1)))); thenItems.push_back(mk_not(m, mk_contains(x4, expr->get_arg(1))));
} }
//---------------------------- //----------------------------
// else branch // else branch
@ -1422,104 +1426,6 @@ namespace smt {
assert_axiom(finalAxiom); assert_axiom(finalAxiom);
} }
void theory_str::instantiate_axiom_Substr(enode * e) {
context & ctx = get_context();
ast_manager & m = get_manager();
app * expr = e->get_owner();
if (axiomatized_terms.contains(expr)) {
TRACE("str", tout << "already set up Substr axiom for " << mk_pp(expr, m) << std::endl;);
return;
}
axiomatized_terms.insert(expr);
TRACE("str", tout << "instantiate Substr axiom for " << mk_pp(expr, m) << std::endl;);
expr_ref substrBase(expr->get_arg(0), m);
expr_ref substrPos(expr->get_arg(1), m);
expr_ref substrLen(expr->get_arg(2), m);
SASSERT(substrBase);
SASSERT(substrPos);
SASSERT(substrLen);
expr_ref zero(m_autil.mk_numeral(rational::zero(), true), m);
expr_ref minusOne(m_autil.mk_numeral(rational::minus_one(), true), m);
SASSERT(zero);
SASSERT(minusOne);
expr_ref_vector argumentsValid_terms(m);
// pos >= 0
argumentsValid_terms.push_back(m_autil.mk_ge(substrPos, zero));
// pos < strlen(base)
// --> pos + -1*strlen(base) < 0
argumentsValid_terms.push_back(m.mk_not(m_autil.mk_ge(
m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, substrLen)),
zero)));
// len >= 0
argumentsValid_terms.push_back(m_autil.mk_ge(substrLen, zero));
expr_ref argumentsValid(mk_and(argumentsValid_terms), m);
SASSERT(argumentsValid);
ctx.internalize(argumentsValid, false);
// (pos+len) >= strlen(base)
// --> pos + len + -1*strlen(base) >= 0
expr_ref lenOutOfBounds(m_autil.mk_ge(
m_autil.mk_add(substrPos, substrLen, m_autil.mk_mul(minusOne, mk_strlen(substrBase))),
zero), m);
SASSERT(lenOutOfBounds);
ctx.internalize(argumentsValid, false);
// Case 1: pos < 0 or pos >= strlen(base) or len < 0
// ==> (Substr ...) = ""
expr_ref case1_premise(m.mk_not(argumentsValid), m);
SASSERT(case1_premise);
ctx.internalize(case1_premise, false);
expr_ref case1_conclusion(ctx.mk_eq_atom(expr, mk_string("")), m);
SASSERT(case1_conclusion);
ctx.internalize(case1_conclusion, false);
expr_ref case1(rewrite_implication(case1_premise, case1_conclusion), m);
SASSERT(case1);
// Case 2: (pos >= 0 and pos < strlen(base) and len >= 0) and (pos+len) >= strlen(base)
// ==> base = t0.t1 AND len(t0) = pos AND (Substr ...) = t1
expr_ref t0(mk_str_var("t0"), m);
expr_ref t1(mk_str_var("t1"), m);
expr_ref case2_conclusion(m.mk_and(
ctx.mk_eq_atom(substrBase, mk_concat(t0,t1)),
ctx.mk_eq_atom(mk_strlen(t0), substrPos),
ctx.mk_eq_atom(expr, t1)), m);
expr_ref case2(rewrite_implication(m.mk_and(argumentsValid, lenOutOfBounds), case2_conclusion), m);
SASSERT(case2);
// Case 3: (pos >= 0 and pos < strlen(base) and len >= 0) and (pos+len) < strlen(base)
// ==> base = t2.t3.t4 AND len(t2) = pos AND len(t3) = len AND (Substr ...) = t3
expr_ref t2(mk_str_var("t2"), m);
expr_ref t3(mk_str_var("t3"), m);
expr_ref t4(mk_str_var("t4"), m);
expr_ref_vector case3_conclusion_terms(m);
case3_conclusion_terms.push_back(ctx.mk_eq_atom(substrBase, mk_concat(t2, mk_concat(t3, t4))));
case3_conclusion_terms.push_back(ctx.mk_eq_atom(mk_strlen(t2), substrPos));
case3_conclusion_terms.push_back(ctx.mk_eq_atom(mk_strlen(t3), substrLen));
case3_conclusion_terms.push_back(ctx.mk_eq_atom(expr, t3));
expr_ref case3_conclusion(mk_and(case3_conclusion_terms), m);
expr_ref case3(rewrite_implication(m.mk_and(argumentsValid, m.mk_not(lenOutOfBounds)), case3_conclusion), m);
SASSERT(case3);
ctx.internalize(case1, false);
ctx.internalize(case2, false);
ctx.internalize(case3, false);
expr_ref finalAxiom(m.mk_and(case1, case2, case3), m);
SASSERT(finalAxiom);
assert_axiom(finalAxiom);
}
#if 0
// rewrite
// requires to add th_rewriter to assert_axiom to enforce normal form.
void theory_str::instantiate_axiom_Substr(enode * e) { void theory_str::instantiate_axiom_Substr(enode * e) {
context & ctx = get_context(); context & ctx = get_context();
ast_manager & m = get_manager(); ast_manager & m = get_manager();
@ -1548,9 +1454,10 @@ namespace smt {
argumentsValid_terms.push_back(m_autil.mk_ge(substrPos, zero)); argumentsValid_terms.push_back(m_autil.mk_ge(substrPos, zero));
// pos < strlen(base) // pos < strlen(base)
// --> pos + -1*strlen(base) < 0 // --> pos + -1*strlen(base) < 0
argumentsValid_terms.push_back(m.mk_not(m_autil.mk_ge( argumentsValid_terms.push_back(mk_not(m, m_autil.mk_ge(
m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, substrLen)), m_autil.mk_add(substrPos, m_autil.mk_mul(minusOne, substrLen)),
zero))); zero)));
// len >= 0 // len >= 0
argumentsValid_terms.push_back(m_autil.mk_ge(substrLen, zero)); argumentsValid_terms.push_back(m_autil.mk_ge(substrLen, zero));
@ -1580,6 +1487,7 @@ namespace smt {
// Case 3: (pos >= 0 and pos < strlen(base) and len >= 0) and (pos+len) < strlen(base) // Case 3: (pos >= 0 and pos < strlen(base) and len >= 0) and (pos+len) < strlen(base)
// ==> base = t2.t3.t4 AND len(t2) = pos AND len(t3) = len AND (Substr ...) = t3 // ==> base = t2.t3.t4 AND len(t2) = pos AND len(t3) = len AND (Substr ...) = t3
expr_ref t2(mk_str_var("t2"), m); expr_ref t2(mk_str_var("t2"), m);
expr_ref t3(mk_str_var("t3"), m); expr_ref t3(mk_str_var("t3"), m);
expr_ref t4(mk_str_var("t4"), m); expr_ref t4(mk_str_var("t4"), m);
@ -1591,11 +1499,22 @@ namespace smt {
expr_ref case3_conclusion(mk_and(case3_conclusion_terms), m); expr_ref case3_conclusion(mk_and(case3_conclusion_terms), m);
expr_ref case3(m.mk_implies(m.mk_and(argumentsValid, m.mk_not(lenOutOfBounds)), case3_conclusion), m); expr_ref case3(m.mk_implies(m.mk_and(argumentsValid, m.mk_not(lenOutOfBounds)), case3_conclusion), m);
assert_axiom(case1); {
assert_axiom(case2); th_rewriter rw(m);
assert_axiom(case3);
expr_ref case1_rw(case1, m);
rw(case1_rw);
assert_axiom(case1_rw);
expr_ref case2_rw(case2, m);
rw(case2_rw);
assert_axiom(case2_rw);
expr_ref case3_rw(case3, m);
rw(case3_rw);
assert_axiom(case3_rw);
}
} }
#endif
void theory_str::instantiate_axiom_Replace(enode * e) { void theory_str::instantiate_axiom_Replace(enode * e) {
context & ctx = get_context(); context & ctx = get_context();
@ -1630,19 +1549,23 @@ namespace smt {
expr_ref tmpLen(m_autil.mk_add(i1, mk_strlen(expr->get_arg(1)), mk_int(-1)), m); expr_ref tmpLen(m_autil.mk_add(i1, mk_strlen(expr->get_arg(1)), mk_int(-1)), m);
thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4))); thenItems.push_back(ctx.mk_eq_atom(expr->get_arg(0), mk_concat(x3, x4)));
thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen)); thenItems.push_back(ctx.mk_eq_atom(mk_strlen(x3), tmpLen));
thenItems.push_back(m.mk_not(mk_contains(x3, expr->get_arg(1)))); thenItems.push_back(mk_not(m, mk_contains(x3, expr->get_arg(1))));
thenItems.push_back(ctx.mk_eq_atom(result, mk_concat(x1, mk_concat(expr->get_arg(2), x2)))); thenItems.push_back(ctx.mk_eq_atom(result, mk_concat(x1, mk_concat(expr->get_arg(2), x2))));
// ----------------------- // -----------------------
// false branch // false branch
expr_ref elseBranch(ctx.mk_eq_atom(result, expr->get_arg(0)), m); expr_ref elseBranch(ctx.mk_eq_atom(result, expr->get_arg(0)), m);
th_rewriter rw(m);
expr_ref breakdownAssert(m.mk_ite(condAst, m.mk_and(thenItems.size(), thenItems.c_ptr()), elseBranch), m); expr_ref breakdownAssert(m.mk_ite(condAst, m.mk_and(thenItems.size(), thenItems.c_ptr()), elseBranch), m);
assert_axiom(breakdownAssert); expr_ref breakdownAssert_rw(breakdownAssert, m);
rw(breakdownAssert_rw);
SASSERT(breakdownAssert); assert_axiom(breakdownAssert_rw);
expr_ref reduceToResult(ctx.mk_eq_atom(expr, result), m); expr_ref reduceToResult(ctx.mk_eq_atom(expr, result), m);
assert_axiom(reduceToResult); expr_ref reduceToResult_rw(reduceToResult, m);
rw(reduceToResult_rw);
assert_axiom(reduceToResult_rw);
} }
void theory_str::instantiate_axiom_str_to_int(enode * e) { void theory_str::instantiate_axiom_str_to_int(enode * e) {
@ -1684,7 +1607,7 @@ namespace smt {
expr_ref tl(mk_str_var("tl"), m); expr_ref tl(mk_str_var("tl"), m);
expr_ref conclusion1(ctx.mk_eq_atom(S, mk_concat(hd, tl)), m); expr_ref conclusion1(ctx.mk_eq_atom(S, mk_concat(hd, tl)), m);
expr_ref conclusion2(ctx.mk_eq_atom(mk_strlen(hd), m_autil.mk_numeral(rational::one(), true)), m); expr_ref conclusion2(ctx.mk_eq_atom(mk_strlen(hd), m_autil.mk_numeral(rational::one(), true)), m);
expr_ref conclusion3(m.mk_not(ctx.mk_eq_atom(hd, mk_string("0"))), m); expr_ref conclusion3(mk_not(m, ctx.mk_eq_atom(hd, mk_string("0"))), m);
expr_ref conclusion(m.mk_and(conclusion1, conclusion2, conclusion3), m); expr_ref conclusion(m.mk_and(conclusion1, conclusion2, conclusion3), m);
SASSERT(premise); SASSERT(premise);
SASSERT(conclusion); SASSERT(conclusion);
@ -1708,7 +1631,7 @@ namespace smt {
// axiom 1: N < 0 <==> (str.from-int N) = "" // axiom 1: N < 0 <==> (str.from-int N) = ""
expr * N = ex->get_arg(0); expr * N = ex->get_arg(0);
{ {
expr_ref axiom1_lhs(m.mk_not(m_autil.mk_ge(N, m_autil.mk_numeral(rational::zero(), true))), m); expr_ref axiom1_lhs(mk_not(m, m_autil.mk_ge(N, m_autil.mk_numeral(rational::zero(), true))), m);
expr_ref axiom1_rhs(ctx.mk_eq_atom(ex, mk_string("")), m); expr_ref axiom1_rhs(ctx.mk_eq_atom(ex, mk_string("")), m);
expr_ref axiom1(ctx.mk_eq_atom(axiom1_lhs, axiom1_rhs), m); expr_ref axiom1(ctx.mk_eq_atom(axiom1_lhs, axiom1_rhs), m);
SASSERT(axiom1); SASSERT(axiom1);
@ -1947,7 +1870,7 @@ namespace smt {
// inconsistency check: value // inconsistency check: value
if (!can_two_nodes_eq(eqc_nn1, eqc_nn2)) { if (!can_two_nodes_eq(eqc_nn1, eqc_nn2)) {
TRACE("str", tout << "inconsistency detected: " << mk_pp(eqc_nn1, m) << " cannot be equal to " << mk_pp(eqc_nn2, m) << std::endl;); TRACE("str", tout << "inconsistency detected: " << mk_pp(eqc_nn1, m) << " cannot be equal to " << mk_pp(eqc_nn2, m) << std::endl;);
expr_ref to_assert(m.mk_not(ctx.mk_eq_atom(eqc_nn1, eqc_nn2)), m); expr_ref to_assert(mk_not(m, ctx.mk_eq_atom(eqc_nn1, eqc_nn2)), m);
assert_axiom(to_assert); assert_axiom(to_assert);
// this shouldn't use the integer theory at all, so we don't allow the option of quick-return // this shouldn't use the integer theory at all, so we don't allow the option of quick-return
return false; return false;
@ -2160,7 +2083,7 @@ namespace smt {
expr_ref implyR11(ctx.mk_eq_atom(mk_strlen(arg1), mk_int(makeUpLenArg1)), m); expr_ref implyR11(ctx.mk_eq_atom(mk_strlen(arg1), mk_int(makeUpLenArg1)), m);
assert_implication(implyL11, implyR11); assert_implication(implyL11, implyR11);
} else { } else {
expr_ref neg(m.mk_not(implyL11), m); expr_ref neg(mk_not(m, implyL11), m);
assert_axiom(neg); assert_axiom(neg);
} }
} }
@ -2231,7 +2154,7 @@ namespace smt {
expr_ref implyR11(ctx.mk_eq_atom(mk_strlen(arg0), mk_int(makeUpLenArg0)), m); expr_ref implyR11(ctx.mk_eq_atom(mk_strlen(arg0), mk_int(makeUpLenArg0)), m);
assert_implication(implyL11, implyR11); assert_implication(implyL11, implyR11);
} else { } else {
expr_ref neg(m.mk_not(implyL11), m); expr_ref neg(mk_not(m, implyL11), m);
assert_axiom(neg); assert_axiom(neg);
} }
} }
@ -2762,7 +2685,7 @@ namespace smt {
} }
if (!can_two_nodes_eq(new_nn1, new_nn2)) { if (!can_two_nodes_eq(new_nn1, new_nn2)) {
expr_ref detected(m.mk_not(ctx.mk_eq_atom(new_nn1, new_nn2)), m); expr_ref detected(mk_not(m, ctx.mk_eq_atom(new_nn1, new_nn2)), m);
TRACE("str", tout << "inconsistency detected: " << mk_ismt2_pp(detected, m) << std::endl;); TRACE("str", tout << "inconsistency detected: " << mk_ismt2_pp(detected, m) << std::endl;);
assert_axiom(detected); assert_axiom(detected);
return; return;
@ -4752,12 +4675,10 @@ namespace smt {
bool theory_str::get_arith_value(expr* e, rational& val) const { bool theory_str::get_arith_value(expr* e, rational& val) const {
context& ctx = get_context(); context& ctx = get_context();
ast_manager & m = get_manager(); ast_manager & m = get_manager();
// safety
// safety if (!ctx.e_internalized(e)) {
if (!ctx.e_internalized(e)) {
return false; return false;
} }
// if an integer constant exists in the eqc, it should be the root // if an integer constant exists in the eqc, it should be the root
enode * en_e = ctx.get_enode(e); enode * en_e = ctx.get_enode(e);
enode * root_e = en_e->get_root(); enode * root_e = en_e->get_root();
@ -5008,7 +4929,7 @@ namespace smt {
implyR = boolVar; implyR = boolVar;
} else { } else {
//implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); //implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx));
implyR = m.mk_not(boolVar); implyR = mk_not(m, boolVar);
} }
} else { } else {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -5037,7 +4958,7 @@ namespace smt {
litems.push_back(ctx.mk_eq_atom(substrAst, aConcat)); litems.push_back(ctx.mk_eq_atom(substrAst, aConcat));
} }
//implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); //implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx));
implyR = m.mk_not(boolVar); implyR = mk_not(m, boolVar);
break; break;
} }
} }
@ -5076,7 +4997,7 @@ namespace smt {
implyR = boolVar; implyR = boolVar;
} else { } else {
// implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx)); // implyR = Z3_mk_eq(ctx, boolVar, Z3_mk_false(ctx));
implyR = m.mk_not(boolVar); implyR = mk_not(m, boolVar);
} }
} }
@ -5146,7 +5067,7 @@ namespace smt {
litems.push_back(ctx.mk_eq_atom(substrAst, aConcat)); litems.push_back(ctx.mk_eq_atom(substrAst, aConcat));
} }
expr_ref implyLHS(mk_and(litems), m); expr_ref implyLHS(mk_and(litems), m);
expr_ref implyR(m.mk_not(boolVar), m); expr_ref implyR(mk_not(m, boolVar), m);
assert_implication(implyLHS, implyR); assert_implication(implyLHS, implyR);
break; break;
} }
@ -6515,7 +6436,7 @@ namespace smt {
if (matchRes) { if (matchRes) {
assert_implication(implyL, boolVar); assert_implication(implyL, boolVar);
} else { } else {
assert_implication(implyL, m.mk_not(boolVar)); assert_implication(implyL, mk_not(m, boolVar));
} }
} }
} }
@ -6603,7 +6524,7 @@ namespace smt {
<< arg1_str << "\" + \"" << arg2_str << << arg1_str << "\" + \"" << arg2_str <<
"\" != \"" << const_str << "\"" << "\n";); "\" != \"" << const_str << "\"" << "\n";);
expr_ref equality(ctx.mk_eq_atom(concat, str), m); expr_ref equality(ctx.mk_eq_atom(concat, str), m);
expr_ref diseq(m.mk_not(equality), m); expr_ref diseq(mk_not(m, equality), m);
assert_axiom(diseq); assert_axiom(diseq);
return; return;
} }
@ -6621,7 +6542,7 @@ namespace smt {
"\" is longer than \"" << const_str << "\"," "\" is longer than \"" << const_str << "\","
<< " so cannot be concatenated with anything to form it" << "\n";); << " so cannot be concatenated with anything to form it" << "\n";);
expr_ref equality(ctx.mk_eq_atom(newConcat, str), m); expr_ref equality(ctx.mk_eq_atom(newConcat, str), m);
expr_ref diseq(m.mk_not(equality), m); expr_ref diseq(mk_not(m, equality), m);
assert_axiom(diseq); assert_axiom(diseq);
return; return;
} else { } else {
@ -6635,7 +6556,7 @@ namespace smt {
<< "actually \"" << arg2_str << "\"" << "actually \"" << arg2_str << "\""
<< "\n";); << "\n";);
expr_ref equality(ctx.mk_eq_atom(newConcat, str), m); expr_ref equality(ctx.mk_eq_atom(newConcat, str), m);
expr_ref diseq(m.mk_not(equality), m); expr_ref diseq(mk_not(m, equality), m);
assert_axiom(diseq); assert_axiom(diseq);
return; return;
} else { } else {
@ -10509,6 +10430,9 @@ namespace smt {
// iterate parents // iterate parents
if (standAlone) { if (standAlone) {
// I hope this works! // I hope this works!
if (!ctx.e_internalized(freeVar)) {
ctx.internalize(freeVar, false);
}
enode * e_freeVar = ctx.get_enode(freeVar); enode * e_freeVar = ctx.get_enode(freeVar);
enode_vector::iterator it = e_freeVar->begin_parents(); enode_vector::iterator it = e_freeVar->begin_parents();
for (; it != e_freeVar->end_parents(); ++it) { for (; it != e_freeVar->end_parents(); ++it) {

View file

@ -6,6 +6,7 @@ z3_add_component(solver
smt_logics.cpp smt_logics.cpp
solver.cpp solver.cpp
solver_na2as.cpp solver_na2as.cpp
solver_pool.cpp
solver2tactic.cpp solver2tactic.cpp
tactic2solver.cpp tactic2solver.cpp
COMPONENT_DEPENDENCIES COMPONENT_DEPENDENCIES

View file

@ -147,6 +147,7 @@ public:
} }
virtual void updt_params(params_ref const & p) { virtual void updt_params(params_ref const & p) {
solver::updt_params(p);
m_solver1->updt_params(p); m_solver1->updt_params(p);
m_solver2->updt_params(p); m_solver2->updt_params(p);
updt_local_params(p); updt_local_params(p);
@ -280,8 +281,8 @@ public:
return m_solver2->get_assumption(idx - c1); return m_solver2->get_assumption(idx - c1);
} }
virtual std::ostream& display(std::ostream & out) const { virtual std::ostream& display(std::ostream & out, unsigned n, expr* const* es) const {
return m_solver1->display(out); return m_solver1->display(out, n, es);
} }
virtual void collect_statistics(statistics & st) const { virtual void collect_statistics(statistics & st) const {

View file

@ -34,11 +34,12 @@ expr * solver::get_assertion(unsigned idx) const {
return 0; return 0;
} }
std::ostream& solver::display(std::ostream & out) const { std::ostream& solver::display(std::ostream & out, unsigned n, expr* const* assumptions) const {
expr_ref_vector fmls(get_manager()); expr_ref_vector fmls(get_manager());
get_assertions(fmls); get_assertions(fmls);
ast_pp_util visitor(get_manager()); ast_pp_util visitor(get_manager());
visitor.collect(fmls); visitor.collect(fmls);
visitor.collect(n, assumptions);
visitor.display_decls(out); visitor.display_decls(out);
visitor.display_asserts(out, fmls, true); visitor.display_asserts(out, fmls, true);
return out; return out;

View file

@ -43,6 +43,7 @@ public:
- results based on check_sat_result API - results based on check_sat_result API
*/ */
class solver : public check_sat_result { class solver : public check_sat_result {
params_ref m_params;
public: public:
virtual ~solver() {} virtual ~solver() {}
@ -54,7 +55,12 @@ public:
/** /**
\brief Update the solver internal settings. \brief Update the solver internal settings.
*/ */
virtual void updt_params(params_ref const & p) { } virtual void updt_params(params_ref const & p) { m_params.copy(p); }
/**
\brief Retrieve set of parameters set on solver.
*/
virtual params_ref const& get_params() { return m_params; }
/** /**
\brief Store in \c r a description of the configuration \brief Store in \c r a description of the configuration
@ -175,7 +181,7 @@ public:
/** /**
\brief Display the content of this solver. \brief Display the content of this solver.
*/ */
virtual std::ostream& display(std::ostream & out) const; virtual std::ostream& display(std::ostream & out, unsigned n = 0, expr* const* assumptions = nullptr) const;
class scoped_push { class scoped_push {
solver& s; solver& s;

320
src/solver/solver_pool.cpp Normal file
View file

@ -0,0 +1,320 @@
/**
Copyright (c) 2017 Microsoft Corporation
Module Name:
solver_pool.cpp
Abstract:
Maintain a pool of solvers
Author:
Nikolaj Bjorner
Notes:
--*/
#include "solver/solver_pool.h"
#include "solver/solver_na2as.h"
#include "ast/proofs/proof_utils.h"
#include "ast/ast_util.h"
class pool_solver : public solver_na2as {
solver_pool& m_pool;
app_ref m_pred;
proof_ref m_proof;
ref<solver> m_base;
expr_ref_vector m_assertions;
unsigned m_head;
expr_ref_vector m_flat;
bool m_pushed;
bool m_in_delayed_scope;
unsigned m_dump_counter;
bool is_virtual() const { return !m.is_true(m_pred); }
public:
pool_solver(solver* b, solver_pool& pool, app_ref& pred):
solver_na2as(pred.get_manager()),
m_pool(pool),
m_pred(pred),
m_proof(m),
m_base(b),
m_assertions(m),
m_head(0),
m_flat(m),
m_pushed(false),
m_in_delayed_scope(false),
m_dump_counter(0) {
if (is_virtual()) {
solver_na2as::assert_expr(m.mk_true(), pred);
}
}
virtual ~pool_solver() {
if (m_pushed) pop(get_scope_level());
if (is_virtual()) {
m_pred = m.mk_not(m_pred);
m_base->assert_expr(m_pred);
}
}
solver* base_solver() { return m_base.get(); }
virtual solver* translate(ast_manager& m, params_ref const& p) { UNREACHABLE(); return nullptr; }
virtual void updt_params(params_ref const& p) { solver::updt_params(p); m_base->updt_params(p); }
virtual void collect_param_descrs(param_descrs & r) { m_base->collect_param_descrs(r); }
virtual void collect_statistics(statistics & st) const { m_base->collect_statistics(st); }
virtual void get_unsat_core(ptr_vector<expr> & r) {
m_base->get_unsat_core(r);
unsigned j = 0;
for (unsigned i = 0; i < r.size(); ++i)
if (m_pred != r[i])
r[j++] = r[i];
r.shrink(j);
}
virtual unsigned get_num_assumptions() const {
unsigned sz = solver_na2as::get_num_assumptions();
return is_virtual() ? sz - 1 : sz;
}
virtual proof * get_proof() {
scoped_watch _t_(m_pool.m_proof_watch);
if (!m_proof.get()) {
elim_aux_assertions pc(m_pred);
m_proof = m_base->get_proof();
pc(m, m_proof, m_proof);
}
return m_proof;
}
void internalize_assertions() {
SASSERT(!m_pushed || m_head == m_assertions.size());
for (unsigned sz = m_assertions.size(); m_head < sz; ++m_head) {
expr_ref f(m);
f = m.mk_implies(m_pred, (m_assertions.get(m_head)));
m_base->assert_expr(f);
}
}
virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
SASSERT(!m_pushed || get_scope_level() > 0);
m_proof.reset();
scoped_watch _t_(m_pool.m_check_watch);
m_pool.m_stats.m_num_checks++;
stopwatch sw;
sw.start();
internalize_assertions();
lbool res = m_base->check_sat(num_assumptions, assumptions);
sw.stop();
switch (res) {
case l_true:
m_pool.m_check_sat_watch.add(sw);
m_pool.m_stats.m_num_sat_checks++;
break;
case l_undef:
m_pool.m_check_undef_watch.add(sw);
m_pool.m_stats.m_num_undef_checks++;
break;
default:
break;
}
set_status(res);
if (false /*m_dump_benchmarks && sw.get_seconds() >= m_pool.fparams().m_dump_min_time*/) {
std::stringstream file_name;
file_name << "virt_solver";
if (is_virtual()) { file_name << "_" << m_pred->get_decl()->get_name(); }
file_name << "_" << (m_dump_counter++) << ".smt2";
std::ofstream out(file_name.str().c_str());
if (!out) { verbose_stream() << "could not open file " << file_name.str() << " for output\n"; }
out << "(set-info :status ";
switch (res) {
case l_true: out << "sat"; break;
case l_false: out << "unsat"; break;
case l_undef: out << "unknown"; break;
}
out << ")\n";
m_base->display(out, num_assumptions, assumptions);
bool first = true;
out << "(check-sat";
for (unsigned i = 0; i < num_assumptions; ++i) {
out << " " << mk_pp(assumptions[i], m);
}
out << ")";
out << "(exit)\n";
::statistics st;
m_base->collect_statistics(st);
st.update("time", sw.get_seconds());
st.display_smt2(out);
out.close();
}
return res;
}
virtual void push_core() {
SASSERT(!m_pushed || get_scope_level() > 0);
if (m_in_delayed_scope) {
// second push
internalize_assertions();
m_base->push();
m_pushed = true;
m_in_delayed_scope = false;
}
if (!m_pushed) {
m_in_delayed_scope = true;
}
else {
SASSERT(m_pushed);
SASSERT(!m_in_delayed_scope);
m_base->push();
}
}
virtual void pop_core(unsigned n) {
SASSERT(!m_pushed || get_scope_level() > 0);
if (m_pushed) {
SASSERT(!m_in_delayed_scope);
m_base->pop(n);
m_pushed = get_scope_level() - n > 0;
}
else {
m_in_delayed_scope = get_scope_level() - n > 0;
}
}
virtual void assert_expr(expr * e) {
SASSERT(!m_pushed || get_scope_level() > 0);
if (m.is_true(e)) return;
if (m_in_delayed_scope) {
internalize_assertions();
m_base->push();
m_pushed = true;
m_in_delayed_scope = false;
}
if (m_pushed) {
m_base->assert_expr(e);
}
else {
m_flat.push_back(e);
flatten_and(m_flat);
m_assertions.append(m_flat);
m_flat.reset();
}
}
virtual void get_model(model_ref & _m) { m_base->get_model(_m); }
virtual expr * get_assumption(unsigned idx) const {
return solver_na2as::get_assumption(idx + is_virtual());
}
virtual std::string reason_unknown() const { return m_base->reason_unknown(); }
virtual void set_reason_unknown(char const* msg) { return m_base->set_reason_unknown(msg); }
virtual void get_labels(svector<symbol> & r) { return m_base->get_labels(r); }
virtual void set_progress_callback(progress_callback * callback) { m_base->set_progress_callback(callback); }
virtual ast_manager& get_manager() const { return m_base->get_manager(); }
void refresh(solver* new_base) {
SASSERT(!m_pushed);
m_head = 0;
m_base = new_base;
}
void reset() {
SASSERT(!m_pushed);
m_head = 0;
m_assertions.reset();
m_pool.refresh(m_base.get());
}
};
solver_pool::solver_pool(solver* base_solver, unsigned num_solvers_per_pool):
m_base_solver(base_solver),
m_num_solvers_per_pool(num_solvers_per_pool),
m_num_solvers_in_last_pool(0)
{}
ptr_vector<solver> solver_pool::get_base_solvers() const {
ptr_vector<solver> solvers;
for (solver* s0 : m_solvers) {
pool_solver* s = dynamic_cast<pool_solver*>(s0);
if (!solvers.contains(s->base_solver())) {
solvers.push_back(s->base_solver());
}
}
return solvers;
}
void solver_pool::collect_statistics(statistics &st) const {
ptr_vector<solver> solvers = get_base_solvers();
for (solver* s : solvers) s->collect_statistics(st);
st.update("time.pool_solver.smt.total", m_check_watch.get_seconds());
st.update("time.pool_solver.smt.total.sat", m_check_sat_watch.get_seconds());
st.update("time.pool_solver.smt.total.undef", m_check_undef_watch.get_seconds());
st.update("time.pool_solver.proof", m_proof_watch.get_seconds());
st.update("pool_solver.checks", m_stats.m_num_checks);
st.update("pool_solver.checks.sat", m_stats.m_num_sat_checks);
st.update("pool_solver.checks.undef", m_stats.m_num_undef_checks);
}
void solver_pool::reset_statistics() {
#if 0
ptr_vector<solver> solvers = get_base_solvers();
for (solver* s : solvers) {
s->reset_statistics();
}
#endif
m_stats.reset();
m_check_sat_watch.reset();
m_check_undef_watch.reset();
m_check_watch.reset();
m_proof_watch.reset();
}
solver* solver_pool::mk_solver() {
ref<solver> base_solver;
ast_manager& m = m_base_solver->get_manager();
if (m_solvers.empty() || m_num_solvers_in_last_pool == m_num_solvers_per_pool) {
base_solver = m_base_solver->translate(m, m_base_solver->get_params());
m_num_solvers_in_last_pool = 0;
}
else {
base_solver = dynamic_cast<pool_solver*>(m_solvers.back())->base_solver();
}
m_num_solvers_in_last_pool++;
std::stringstream name;
name << "vsolver#" << m_solvers.size();
app_ref pred(m.mk_const(symbol(name.str().c_str()), m.mk_bool_sort()), m);
pool_solver* solver = alloc(pool_solver, base_solver.get(), *this, pred);
m_solvers.push_back(solver);
return solver;
}
void solver_pool::reset_solver(solver* s) {
pool_solver* ps = dynamic_cast<pool_solver*>(s);
SASSERT(ps);
if (ps) ps->reset();
}
void solver_pool::refresh(solver* base_solver) {
ast_manager& m = m_base_solver->get_manager();
ref<solver> new_base = m_base_solver->translate(m, m_base_solver->get_params());
for (solver* s0 : m_solvers) {
pool_solver* s = dynamic_cast<pool_solver*>(s0);
if (base_solver == s->base_solver()) {
s->refresh(new_base.get());
}
}
}

69
src/solver/solver_pool.h Normal file
View file

@ -0,0 +1,69 @@
/**
Copyright (c) 2017 Microsoft Corporation
Module Name:
solver_pool.h
Abstract:
Maintain a pool of solvers
Author:
Nikolaj Bjorner
Arie Gurfinkel
Notes:
This is a revision of spacer_virtual_solver by Arie Gurfinkel
--*/
#ifndef SOLVER_POOL_H_
#define SOLVER_POOL_H_
#include "solver/solver.h"
#include "util/stopwatch.h"
class pool_solver;
class solver_pool {
friend class pool_solver;
struct stats {
unsigned m_num_checks;
unsigned m_num_sat_checks;
unsigned m_num_undef_checks;
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};
ref<solver> m_base_solver;
unsigned m_num_solvers_per_pool;
unsigned m_num_solvers_in_last_pool;
sref_vector<solver> m_solvers;
stats m_stats;
stopwatch m_check_watch;
stopwatch m_check_sat_watch;
stopwatch m_check_undef_watch;
stopwatch m_proof_watch;
void refresh(solver* s);
ptr_vector<solver> get_base_solvers() const;
public:
solver_pool(solver* base_solver, unsigned num_solvers_per_pool);
void collect_statistics(statistics &st) const;
void reset_statistics();
solver* mk_solver();
void reset_solver(solver* s);
};
#endif

View file

@ -37,7 +37,6 @@ class tactic2solver : public solver_na2as {
ref<simple_check_sat_result> m_result; ref<simple_check_sat_result> m_result;
tactic_ref m_tactic; tactic_ref m_tactic;
symbol m_logic; symbol m_logic;
params_ref m_params;
bool m_produce_models; bool m_produce_models;
bool m_produce_proofs; bool m_produce_proofs;
bool m_produce_unsat_cores; bool m_produce_unsat_cores;
@ -85,7 +84,7 @@ tactic2solver::tactic2solver(ast_manager & m, tactic * t, params_ref const & p,
m_tactic = t; m_tactic = t;
m_logic = logic; m_logic = logic;
m_params = p; solver::updt_params(p);
m_produce_models = produce_models; m_produce_models = produce_models;
m_produce_proofs = produce_proofs; m_produce_proofs = produce_proofs;
@ -96,7 +95,7 @@ tactic2solver::~tactic2solver() {
} }
void tactic2solver::updt_params(params_ref const & p) { void tactic2solver::updt_params(params_ref const & p) {
m_params.append(p); solver::updt_params(p);
} }
void tactic2solver::collect_param_descrs(param_descrs & r) { void tactic2solver::collect_param_descrs(param_descrs & r) {
@ -129,7 +128,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass
m_result = alloc(simple_check_sat_result, m); m_result = alloc(simple_check_sat_result, m);
m_tactic->cleanup(); m_tactic->cleanup();
m_tactic->set_logic(m_logic); m_tactic->set_logic(m_logic);
m_tactic->updt_params(m_params); // parameters are allowed to overwrite logic. m_tactic->updt_params(get_params()); // parameters are allowed to overwrite logic.
goal_ref g = alloc(goal, m, m_produce_proofs, m_produce_models, m_produce_unsat_cores); goal_ref g = alloc(goal, m, m_produce_proofs, m_produce_models, m_produce_unsat_cores);
unsigned sz = m_assertions.size(); unsigned sz = m_assertions.size();

Some files were not shown because too many files have changed in this diff Show more